add choice mechanic

This commit is contained in:
Stanislaw Dzioba
2026-03-23 19:44:41 +01:00
parent 1373e1e128
commit 86edc3bf88
8 changed files with 300 additions and 136 deletions

View File

@@ -22,12 +22,23 @@ define_sprite Player shock "https://placehold.co/400x600/4d79ff/ffffff?text=Play
sprite Agnieszka happy at pos2
sprite Player normal at pos7
say Agnieszka "To jest najprostszy tekst w tekstboxie!"
say Agnieszka "Chcesz zobaczyć specjalny efekt?"
choice "Tak, pokaż mi!" jump:special_effect
choice "Nie, przejdźmy dalej" jump:continue_scene
label special_effect
sprite Agnieszka wave at pos3
say Agnieszka "Oto on! Pogrubiony tekst: " b"BUM!"
say Agnieszka "I teraz wracamy do głównej sceny."
label continue_scene
say Agnieszka "Kontynuujemy naszą rozmowę."
say Agnieszka "To jest najprostszy tekst w tekstboxie!" "Tu jest dużo tekstu."
say "To by było trochę niekomfortowe trzymać w jednej linii." "Ale wszyscy wiedzą."
say "Że to nadal Agnieszka."
say "To jest tekst bez osoby podanej!"
sprite Agnieszka wave at pos3
say Agnieszka "Look, I defined this 'wave' sprite right in the script!"
say Agnieszka b"To jest pogrubione" "A to nie!" b"P""ierwsza litera tylko"
say Agnieszka i"Hello! This is italicized" "And this isn't"
say Agnieszka u"This is underlined" "And this isn't."
@@ -67,8 +78,13 @@ export interface Segment {
modifiers: Modifier;
}
export interface ChoiceOption {
text: string;
jumpLabel: string;
}
export interface Statement {
type: 'say' | 'wait' | 'sprite' | 'set' | 'fire' | 'nextfile' | 'comment';
type: 'say' | 'wait' | 'sprite' | 'set' | 'fire' | 'nextfile' | 'comment' | 'choice' | 'label';
character?: string | null;
segments?: Segment[];
continuations?: Segment[];
@@ -82,6 +98,8 @@ export interface Statement {
filename?: string;
text?: string;
lineNumber: number;
label?: string;
choices?: ChoiceOption[];
}
// --- PARSER ---
@@ -95,7 +113,23 @@ export function parseScript(text: string): Statement[] {
const segments: Segment[] = [];
const segmentRegex = /([biuswcftn]|click|clicknoskip)?"([^"]*)"(\(([^)]+)\))?/g;
let match;
let lastIndex = 0;
while ((match = segmentRegex.exec(lineText)) !== null) {
// Add any text between matches (like spaces) as a plain segment
const gap = lineText.substring(lastIndex, match.index);
if (gap) {
segments.push({
text: gap,
modifiers: {
bold: false, italic: false, underline: false, strikethrough: false,
wait: false, waitDuration: null, color: null, font: null,
speed: null, clickLock: null, click: false, clicknoskip: false,
inlineBranch: []
}
});
}
const [full, mod, textValue, fullParens, params] = match;
const modifiers: Modifier = {
bold: mod === 'b',
@@ -113,7 +147,23 @@ export function parseScript(text: string): Statement[] {
inlineBranch: []
};
segments.push({ text: textValue, modifiers });
lastIndex = segmentRegex.lastIndex;
}
// Add remaining text after the last match
const remaining = lineText.substring(lastIndex);
if (remaining) {
segments.push({
text: remaining,
modifiers: {
bold: false, italic: false, underline: false, strikethrough: false,
wait: false, waitDuration: null, color: null, font: null,
speed: null, clickLock: null, click: false, clicknoskip: false,
inlineBranch: []
}
});
}
return segments;
};
@@ -135,10 +185,12 @@ export function parseScript(text: string): Statement[] {
if (afterSay.startsWith('"')) {
character = null;
} else {
const firstQuoteIndex = afterSay.indexOf('"');
if (firstQuoteIndex !== -1) {
character = afterSay.substring(0, firstQuoteIndex).trim();
segmentPart = afterSay.substring(firstQuoteIndex);
// Find the start of the first segment.
// A segment starts with a quote, or a modifier followed by a quote.
const segmentMatch = afterSay.match(/([biuswcftn]|click|clicknoskip)?"/);
if (segmentMatch && segmentMatch.index !== undefined) {
character = afterSay.substring(0, segmentMatch.index).trim();
segmentPart = afterSay.substring(segmentMatch.index);
} else {
character = afterSay;
segmentPart = "";
@@ -159,10 +211,31 @@ export function parseScript(text: string): Statement[] {
continue;
}
const words = line.split(/\s+/);
const words = line.match(/(?:[^\s"]+|"[^"]*")+/g) || [];
let cmd = words[0];
if (cmd === 'wait') {
if (cmd === 'label') {
statements.push({
type: 'label',
label: words[1],
lineNumber: originalLineNumber
});
} else if (cmd === 'choice') {
const text = words[1]?.replace(/^"(.*)"$/, '$1');
const jumpPart = words[2];
const jumpLabel = jumpPart?.startsWith('jump:') ? jumpPart.slice(5) : '';
const lastStatement = statements[statements.length - 1];
if (lastStatement?.type === 'choice') {
lastStatement.choices?.push({ text, jumpLabel });
} else {
statements.push({
type: 'choice',
choices: [{ text, jumpLabel }],
lineNumber: originalLineNumber
});
}
} else if (cmd === 'wait') {
statements.push({
type: 'wait',
duration: words[1],