diff --git a/.gitignore b/.gitignore index 4d29575..4c62f55 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,9 @@ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. +# generated code +/src/grammar/grammar.ohm-bundle.d.ts +/src/grammar/grammar.ohm-bundle.js + # dependencies /node_modules /.pnp diff --git a/package-lock.json b/package-lock.json index c2a3d44..ac5a2e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "bootstrap": "^5.2.3", "csstype": "^3.1.2", "format-duration": "^3.0.2", + "ohm-js": "^17.1.0", "react": "^18.2.0", "react-bootstrap": "^2.7.2", "react-dom": "^18.2.0", @@ -30,6 +31,7 @@ "web-vitals": "^2.1.4" }, "devDependencies": { + "@ohm-js/cli": "^2.0.0", "@types/bootstrap": "^5.2.6" } }, @@ -3043,6 +3045,22 @@ "node": ">= 8" } }, + "node_modules/@ohm-js/cli": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@ohm-js/cli/-/cli-2.0.0.tgz", + "integrity": "sha512-yiO6QEqW4wQQe1l9c+jOIfmhGm2LlHEhjmaB5Qu9hhz6rEQvL/vhz44azgHegLb0m23D0S7a78orURbPClRtyA==", + "dev": true, + "dependencies": { + "commander": "^8.1.0", + "fast-glob": "^3.2.7" + }, + "bin": { + "ohm": "index.js" + }, + "peerDependencies": { + "ohm-js": "^17.0.0" + } + }, "node_modules/@pmmmwh/react-refresh-webpack-plugin": { "version": "0.5.10", "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.10.tgz", @@ -12963,6 +12981,14 @@ "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" }, + "node_modules/ohm-js": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/ohm-js/-/ohm-js-17.1.0.tgz", + "integrity": "sha512-xc3B5dgAjTBQGHaH7B58M2Pmv6WvzrJ/3/7LeUzXNg0/sY3jQPdSd/S2SstppaleO77rifR1tyhdfFGNIwxf2Q==", + "engines": { + "node": ">=0.12.1" + } + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", diff --git a/package.json b/package.json index 60e80a4..bfb8c4f 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "bootstrap": "^5.2.3", "csstype": "^3.1.2", "format-duration": "^3.0.2", + "ohm-js": "^17.1.0", "react": "^18.2.0", "react-bootstrap": "^2.7.2", "react-dom": "^18.2.0", @@ -26,6 +27,7 @@ }, "scripts": { "start": "react-scripts start", + "generate": "ohm generateBundles -et src/grammar/grammar.ohm", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" @@ -49,6 +51,7 @@ ] }, "devDependencies": { + "@ohm-js/cli": "^2.0.0", "@types/bootstrap": "^5.2.6" } } diff --git a/src/grammar/grammar.ohm b/src/grammar/grammar.ohm new file mode 100644 index 0000000..d63e4cc --- /dev/null +++ b/src/grammar/grammar.ohm @@ -0,0 +1,99 @@ +FabulaDSL { + CodeSegment = (Block | CompleteOperation | EmptyLines)* + + identifier (an identifier) = identifierStart identifierContinue+ + identifierStart = "_" | "$" | letter + identifierContinue = identifierStart | digit + + newline = "\n" + EmptyLines = operationTerminator+ + + nonNewlineSpace = ~newline space + spaces := (nonNewlineSpace|blockComment)* + + target = "@" + source = "&" + null = "-" + colon = ":" + + operand (an operand) = identifier | target | source + comma = "," + Operands (operands) = nonemptyListOf + + experienceResource = caseInsensitive<"XP">|caseInsensitive<"EXP"> + meteredResource (the name of a metered resource) = caseInsensitive<"HP">|caseInsensitive<"MP">|caseInsensitive<"IP">|caseInsensitive<"ZP">|caseInsensitive<"BP">|caseInsensitive<"Turns">|experienceResource + spResource = caseInsensitive<"FP">|caseInsensitive<"UP">|caseInsensitive<"SP"> + moneyResource = caseInsensitive<"Zenit">|caseInsensitive<"z"> + materialsResource = caseInsensitive<"materials">|caseInsensitive<"mats">|caseInsensitive<"m"> + levelResource = caseInsensitive<"Level">|caseInsensitive<"lv"> + unmeteredResource (the name of an unmetered resource) = spResource|moneyResource|materialsResource|levelResource|caseInsensitive<"order"> + resource (the name of a resource) = meteredResource|unmeteredResource + + deltaOperator = "+"|"-" + integer (an integer) = digit+ + Delta (a delta) = deltaOperator integer + + element = caseInsensitive<"fire">|caseInsensitive<"water">|caseInsensitive<"poison">|caseInsensitive<"lightning">|caseInsensitive<"earth">|caseInsensitive<"ice">|caseInsensitive<"wind">|caseInsensitive<"light">|caseInsensitive<"dark">|caseInsensitive<"physical"> + affinity = "??"|"..."|"."|"!!" + + meteredSeparator = ~lineCommentStart ~blockCommentStart "/" + MeteredValue = integer MaxValue + MaxValue = meteredSeparator integer + + DeltaOperation = Operands space resource colon Delta affinity? element? + DeltaOperationAlternate = Operands colon Delta affinity? resource? element? + DeltaOperationAlternate2 = Operands colon resource Delta affinity? element? + SetMeteredOperation = Operands space meteredResource colon MeteredValue + SetMeteredOperationAlternate = Operands colon MeteredValue meteredResource + SetMeteredOperationAlternate2 = Operands colon meteredResource MeteredValue + SetValueOperation = Operands space resource colon integer + SetValueOperationAlternate = Operands colon integer resource + SetValueOperationAlternate2 = Operands colon resource integer + SetMaxOperation = Operands space meteredResource colon MaxValue + SetMaxOperationAlternate = Operands colon MaxValue meteredResource + SetMaxOperationAlternate2 = Operands colon meteredResource MaxValue + ClearOperation = Operands space resource colon null + ClearOperationAlternate = Operands colon null resource + ClearOperationAlternate2 = Operands colon resource null + + StatusDeltaOperation = Operands colon deltaOperator identifier + + notNewlineOrComment = ~newline ~lineCommentStart ~blockCommentStart any + textToEndOfLine = notNewlineOrComment+ + + SetTargetOperation = target (Operands | null) + SetSourceOperation = source (Operands | null) + + PrintOperation = ">" textToEndOfLine + + Operation = DeltaOperation | DeltaOperationAlternate | DeltaOperationAlternate2 + | SetMeteredOperation | SetMeteredOperationAlternate | SetMeteredOperationAlternate2 + | SetValueOperation | SetValueOperationAlternate | SetValueOperationAlternate2 + | SetMaxOperation | SetMaxOperationAlternate | SetMaxOperationAlternate2 + | ClearOperation | ClearOperationAlternate | ClearOperationAlternate2 + | StatusDeltaOperation + | SetTargetOperation | SetSourceOperation | PrintOperation + + silentOperator = "~" + + lineCommentStart = "//" + lineComment = lineCommentStart textToEndOfLine (newline | end) + + blockCommentStart = "/*" + blockCommentEnd = "*/" + + blockCommentCharacter = ~blockCommentEnd any + blockCommentText = blockCommentCharacter* + blockComment = blockCommentStart blockCommentText blockCommentEnd + + operationTerminator = newline | lineComment + operationTerminatorOrEnd = operationTerminator | end + CompleteOperation = silentOperator? Operation operationTerminatorOrEnd + + beginKeyword = caseInsensitive<"begin"> + endKeyword = caseInsensitive<"end"> + BlockStart = silentOperator? beginKeyword SetSourceOperation? SetTargetOperation? textToEndOfLine + BlockEnd = endKeyword textToEndOfLine? + + Block = BlockStart operationTerminator CodeSegment BlockEnd operationTerminatorOrEnd +} \ No newline at end of file diff --git a/src/model/Character.ts b/src/model/Character.ts index 12e8199..217e080 100644 --- a/src/model/Character.ts +++ b/src/model/Character.ts @@ -197,6 +197,8 @@ export interface Character { readonly name?: string readonly altName?: string readonly level?: number + readonly xp?: number + readonly maxXp?: number readonly hp?: number readonly maxHp?: number readonly health?: CharacterHealth @@ -399,6 +401,8 @@ export function applyCharacterPrivacy(character: Character): Character|null { } if (!privacySettings.showLevel) { delete out.level + delete out.xp + delete out.maxXp } return out } \ No newline at end of file diff --git a/src/model/GameState.ts b/src/model/GameState.ts index 6d7302b..8556c82 100644 --- a/src/model/GameState.ts +++ b/src/model/GameState.ts @@ -1,8 +1,8 @@ import {Character, CharacterId, CharacterSide, SPType} from "./Character"; export enum ClockMode { - HEROES_FILL = "heroes fill", - HEROES_EMPTY = "heroes empty", + HEROES_FILL = "fill", + HEROES_EMPTY = "empty", } export interface Clock {