diff --git a/.gitignore b/.gitignore
index 6eb629f..d8692a1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
-playground/
\ No newline at end of file
+playground/
+rascript-upstream.js
\ No newline at end of file
diff --git a/Makefile b/Makefile
index f9dd660..33b6ad9 100644
--- a/Makefile
+++ b/Makefile
@@ -1,13 +1,20 @@
SHELL := /bin/bash
.PHONY: test
-run:
- echo "Starting at http://localhost:8000"
- python -m SimpleHTTPServer # Python2.7
- # python -m http.server 8000 # Python 3
-
test:
bash ./scripts/test.sh
gen:
- bash ./scripts/gen.sh
\ No newline at end of file
+ bash ./scripts/gen.sh
+
+upgrade:
+ bash ./scripts/upgrade.sh
+
+clean:
+ rm -rf plyground
+ rm rascript-upstream.js
+
+run: gen
+ echo "Starting at http://localhost:8000"
+ python -m SimpleHTTPServer # Python2.7
+ # python -m http.server 8000 # Python 3
\ No newline at end of file
diff --git a/README.md b/README.md
index 176ec57..fc56738 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,17 @@
-# highlightjs-rascript
\ No newline at end of file
+# highlightjs-rascript
+
+[highlight.js](https://highlightjs.org/) syntax definition for [RATools](https://github.com/Jamiras/RATools) DSL, RAScript
+
+[](https://github.com/joshraphael/highlightjs-rascript/blob/main/LICENSE)
+[](https://github.com/joshraphael/highlightjs-rascript/actions/workflows/test.yaml)
+[](https://github.com/joshraphael/highlightjs-rascript/tags)
+[](https://github.com/joshraphael/highlightjs-rascript/archive/main.zip)
+
+## Commands:
+
+|Title|Command|Parameters|Description|
+|-|-|-|-|
+|Test|`make test`|None|Test the rascript highlightjs module|
+|Generate|`make gen`|None|Generate the distribution Javascript of the rascript highlightjs pacakge|
+|Upgrade rascript-syntax|`make upgrade`|None|Upgrade the rascript-syntax version|
+|Run|`make run`|None|Build and start simple http webserver with example RAScript syntax (using auto-detection)|
\ No newline at end of file
diff --git a/dist/rascript.es.min.js b/dist/rascript.es.min.js
index f075d90..3e334da 100644
--- a/dist/rascript.es.min.js
+++ b/dist/rascript.es.min.js
@@ -1,13 +1,16 @@
/*! `rascript` grammar compiled for Highlight.js 11.11.1 */
-var hljsGrammar=(()=>{"use strict";return e=>({case_insensitive:!1,
-contains:[e.C_LINE_COMMENT_MODE,e.QUOTE_STRING_MODE,e.C_NUMBER_MODE,e.COMMENT("/\\*","\\*/"),{
-className:"variable.language",begin:/\b(this)\b/},{className:"keyword",
-begin:/\b(function|class|else|for|if|in|return)\b/},{className:"literal",
-begin:/\b(true|false)\b/},{className:"operator",
-begin:/(\|\||\&\&|\=\=|\!\=|\>\=|\<\=|\=\>)/},{scope:"operator",
+var hljsGrammar=(()=>{"use strict";return e=>({case_insensitive:!1,contains:[{
+begin:[/\b(byte|word|tbyte|dword|bit0|bit1|bit2|bit3|bit4|bit5|bit6|bit7|bit|low4|high4|bitcount|word_be|tbyte_be|dword_be|float|float_be|mbf32|mbf32_le|double32|double32_be|prev|prior|bcd|identity_transform|ascii_string_equals|unicode_string_equals|repeated|once|tally|deduct|never|unless|measured|trigger_when|disable_when|always_true|always_false|format|substring|length|range|array_push|array_pop|array_map|array_contains|array_reduce|array_filter|dictionary_contains_key|any_of|all_of|none_of|sum_of|tally_of|max_of|assert|achievement|rich_presence_display|rich_presence_value|rich_presence_lookup|rich_presence_ascii_string_lookup|rich_presence_macro|rich_presence_conditional_display|leaderboard|__ornext)\b/,/\(/],
+beginScope:{1:"title.function.invoke"},relevance:10
+},e.C_LINE_COMMENT_MODE,e.QUOTE_STRING_MODE,e.C_NUMBER_MODE,e.COMMENT("/\\*","\\*/"),{
+scope:"variable.language",begin:/\b(this)\b/,relevance:0},{scope:"keyword",
+begin:/\b(else|for|if|in|return)\b/,relevance:0},{scope:"literal",
+begin:/\b(true|false)\b/,relevance:0},{scope:"operator",
+begin:/(\|\||\&\&|\=\=|\!\=|\>\=|\<\=|\=\>)/,relevance:0},{scope:"operator",
match:/[\+\-\*\/\%\^\&\^\~\>\<\!\|]/,relevance:0},{
-begin:[/function[\t ]+/,/[a-zA-Z_][\w]*/,/\(/],beginScope:{2:"title.function"}
-},{begin:[/class[\t ]+/,/[a-zA-Z_][\w]*/],beginScope:{2:"title.class"}},{
-begin:[/[a-zA-Z_][\w]*/,/\(/],beginScope:{1:"title.function.invoke"}},{
-className:"variable",begin:/[a-zA-Z_][\w]*/,relevance:0}]})})()
-;export default hljsGrammar;
\ No newline at end of file
+begin:[/\b(function)\b/,/[\t ]+/,/[a-zA-Z_][\w]*/,/\(/],beginScope:{1:"keyword",
+3:"title.function"},relevance:0},{
+begin:[/\b(class)\b/,/[\t ]+/,/[a-zA-Z_][\w]*/],beginScope:{1:"keyword",
+3:"title.class"},relevance:0},{begin:[/[a-zA-Z_][\w]*/,/\(/],beginScope:{
+1:"title.function.invoke"},relevance:0},{scope:"variable",
+begin:/[a-zA-Z_][\w]*/,relevance:0}]})})();export default hljsGrammar;
\ No newline at end of file
diff --git a/dist/rascript.min.js b/dist/rascript.min.js
index 1007607..c765225 100644
--- a/dist/rascript.min.js
+++ b/dist/rascript.min.js
@@ -1,13 +1,17 @@
/*! `rascript` grammar compiled for Highlight.js 11.11.1 */
-(()=>{var e=(()=>{"use strict";return e=>({case_insensitive:!1,
-contains:[e.C_LINE_COMMENT_MODE,e.QUOTE_STRING_MODE,e.C_NUMBER_MODE,e.COMMENT("/\\*","\\*/"),{
-className:"variable.language",begin:/\b(this)\b/},{className:"keyword",
-begin:/\b(function|class|else|for|if|in|return)\b/},{className:"literal",
-begin:/\b(true|false)\b/},{className:"operator",
-begin:/(\|\||\&\&|\=\=|\!\=|\>\=|\<\=|\=\>)/},{scope:"operator",
+(()=>{var e=(()=>{"use strict";return e=>({case_insensitive:!1,contains:[{
+begin:[/\b(byte|word|tbyte|dword|bit0|bit1|bit2|bit3|bit4|bit5|bit6|bit7|bit|low4|high4|bitcount|word_be|tbyte_be|dword_be|float|float_be|mbf32|mbf32_le|double32|double32_be|prev|prior|bcd|identity_transform|ascii_string_equals|unicode_string_equals|repeated|once|tally|deduct|never|unless|measured|trigger_when|disable_when|always_true|always_false|format|substring|length|range|array_push|array_pop|array_map|array_contains|array_reduce|array_filter|dictionary_contains_key|any_of|all_of|none_of|sum_of|tally_of|max_of|assert|achievement|rich_presence_display|rich_presence_value|rich_presence_lookup|rich_presence_ascii_string_lookup|rich_presence_macro|rich_presence_conditional_display|leaderboard|__ornext)\b/,/\(/],
+beginScope:{1:"title.function.invoke"},relevance:10
+},e.C_LINE_COMMENT_MODE,e.QUOTE_STRING_MODE,e.C_NUMBER_MODE,e.COMMENT("/\\*","\\*/"),{
+scope:"variable.language",begin:/\b(this)\b/,relevance:0},{scope:"keyword",
+begin:/\b(else|for|if|in|return)\b/,relevance:0},{scope:"literal",
+begin:/\b(true|false)\b/,relevance:0},{scope:"operator",
+begin:/(\|\||\&\&|\=\=|\!\=|\>\=|\<\=|\=\>)/,relevance:0},{scope:"operator",
match:/[\+\-\*\/\%\^\&\^\~\>\<\!\|]/,relevance:0},{
-begin:[/function[\t ]+/,/[a-zA-Z_][\w]*/,/\(/],beginScope:{2:"title.function"}
-},{begin:[/class[\t ]+/,/[a-zA-Z_][\w]*/],beginScope:{2:"title.class"}},{
-begin:[/[a-zA-Z_][\w]*/,/\(/],beginScope:{1:"title.function.invoke"}},{
-className:"variable",begin:/[a-zA-Z_][\w]*/,relevance:0}]})})()
-;hljs.registerLanguage("rascript",e)})();
\ No newline at end of file
+begin:[/\b(function)\b/,/[\t ]+/,/[a-zA-Z_][\w]*/,/\(/],beginScope:{1:"keyword",
+3:"title.function"},relevance:0},{
+begin:[/\b(class)\b/,/[\t ]+/,/[a-zA-Z_][\w]*/],beginScope:{1:"keyword",
+3:"title.class"},relevance:0},{begin:[/[a-zA-Z_][\w]*/,/\(/],beginScope:{
+1:"title.function.invoke"},relevance:0},{scope:"variable",
+begin:/[a-zA-Z_][\w]*/,relevance:0}]})})();hljs.registerLanguage("rascript",e)
+})();
\ No newline at end of file
diff --git a/package.json b/package.json
index 4a0c4a1..60e1000 100644
--- a/package.json
+++ b/package.json
@@ -2,16 +2,17 @@
"name": "highlightjs-rascript",
"version": "0.0.0",
"description": "highlight.js syntax definition for RATools DSL, RAScript",
- "main": "src/rascript.js",
+ "main": "src/languages/rascript.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
- "url": "https://github.com/joshraphael/highlightjs-rascript.git"
+ "url": "git+https://github.com/joshraphael/highlightjs-rascript.git"
},
"keywords": [
"rascript",
+ "hljs",
"highlight.js",
"highlightjs",
"syntax"
diff --git a/scripts/gen.sh b/scripts/gen.sh
index 94d90b5..6630251 100644
--- a/scripts/gen.sh
+++ b/scripts/gen.sh
@@ -5,8 +5,6 @@ bash ./scripts/setup.sh
export PLAYGROUND="playground"
export HIGHLIGHTJS_RASCRIPT="${PLAYGROUND}/extra/highlightjs-rascript"
-cp ${PLAYGROUND}/rascript.js src/languages
-
rm -rf dist
mkdir -p dist
cd ${PLAYGROUND}
diff --git a/scripts/setup.sh b/scripts/setup.sh
index a2b7414..9ad35cc 100644
--- a/scripts/setup.sh
+++ b/scripts/setup.sh
@@ -2,14 +2,19 @@
export PLAYGROUND="playground"
export HIGHLIGHTJS_RASCRIPT="${PLAYGROUND}/extra/highlightjs-rascript"
-export RASCRIPT_SYNTAX_VERSION="v0.2.0"
+export RASCRIPT_SYNTAX_VERSION="v0.3.0"
+export HIGHLIGHTJS_VERSION="11.11.1"
rm -rf ${PLAYGROUND}
mkdir -p ${PLAYGROUND}
git clone https://github.com/highlightjs/highlight.js ${PLAYGROUND}
-wget -O ${PLAYGROUND}/rascript.js "https://github.com/joshraphael/rascript-syntax/releases/download/${RASCRIPT_SYNTAX_VERSION}/rascript.js"
+cd ${PLAYGROUND}
+git checkout tags/${HIGHLIGHTJS_VERSION}
+cd ..
+wget -O rascript-upstream.js "https://github.com/joshraphael/rascript-syntax/releases/download/${RASCRIPT_SYNTAX_VERSION}/rascript.js"
mkdir -p ${HIGHLIGHTJS_RASCRIPT}
cp -r src ${HIGHLIGHTJS_RASCRIPT}
cp -r test ${HIGHLIGHTJS_RASCRIPT}
cd ${PLAYGROUND}
-npm ci
\ No newline at end of file
+npm ci
+node ./tools/build.js -t cdn
\ No newline at end of file
diff --git a/scripts/test.sh b/scripts/test.sh
index e082d6a..4c46a61 100755
--- a/scripts/test.sh
+++ b/scripts/test.sh
@@ -5,13 +5,12 @@ bash ./scripts/setup.sh
export PLAYGROUND="playground"
export HIGHLIGHTJS_RASCRIPT="${PLAYGROUND}/extra/highlightjs-rascript"
-diff -q "src/languages/rascript.js" "${PLAYGROUND}/rascript.js"
+diff -q "src/languages/rascript.js" "rascript-upstream.js"
if [ $? -ne 0 ]; then
exit 1
fi
cd ${PLAYGROUND}
-node ./tools/build.js -t cdn
npm run build_and_test
if [ $? -ne 0 ]; then
exit 1
diff --git a/scripts/upgrade.sh b/scripts/upgrade.sh
new file mode 100644
index 0000000..4971632
--- /dev/null
+++ b/scripts/upgrade.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+bash ./scripts/setup.sh
+
+cp rascript-upstream.js src/languages/rascript.js
\ No newline at end of file
diff --git a/src/languages/rascript.js b/src/languages/rascript.js
index 1da4e99..8969d65 100644
--- a/src/languages/rascript.js
+++ b/src/languages/rascript.js
@@ -3,12 +3,99 @@ Language: RAScript
Author: Joshua Raphael
Description: Syntax grammar for RAScript, a RetroAchievements.org DSL
Category: syntax
-Version: v0.2.0
+Version: v0.3.0
*/
+
+function ImportantWordRegex() {
+ let words = [
+ "byte",
+ "word",
+ "tbyte",
+ "dword",
+ "bit0",
+ "bit1",
+ "bit2",
+ "bit3",
+ "bit4",
+ "bit5",
+ "bit6",
+ "bit7",
+ "bit",
+ "low4",
+ "high4",
+ "bitcount",
+ "word_be",
+ "tbyte_be",
+ "dword_be",
+ "float",
+ "float_be",
+ "mbf32",
+ "mbf32_le",
+ "double32",
+ "double32_be",
+ "prev",
+ "prior",
+ "bcd",
+ "identity_transform",
+ "ascii_string_equals",
+ "unicode_string_equals",
+ "repeated",
+ "once",
+ "tally",
+ "deduct",
+ "never",
+ "unless",
+ "measured",
+ "trigger_when",
+ "disable_when",
+ "always_true",
+ "always_false",
+ "format",
+ "substring",
+ "length",
+ "range",
+ "array_push",
+ "array_pop",
+ "array_map",
+ "array_contains",
+ "array_reduce",
+ "array_filter",
+ "dictionary_contains_key",
+ "any_of",
+ "all_of",
+ "none_of",
+ "sum_of",
+ "tally_of",
+ "max_of",
+ "assert",
+ "achievement",
+ "rich_presence_display",
+ "rich_presence_value",
+ "rich_presence_lookup",
+ "rich_presence_ascii_string_lookup",
+ "rich_presence_macro",
+ "rich_presence_conditional_display",
+ "leaderboard",
+ "__ornext",
+ ]
+ return "\\b(" + words.join("|") + ")\\b";
+}
+
export default function(hljs) {
return {
case_insensitive: false,
contains: [
+ // This block helps highlight.js auto detect RAScript syntax
+ {
+ begin: [
+ new RegExp(ImportantWordRegex()),
+ /\(/
+ ],
+ beginScope: {
+ 1: "title.function.invoke"
+ },
+ relevance: 10
+ },
hljs.C_LINE_COMMENT_MODE,
hljs.QUOTE_STRING_MODE,
hljs.C_NUMBER_MODE,
@@ -17,20 +104,24 @@ export default function(hljs) {
'\\*/',
),
{
- className: 'variable.language',
- begin: /\b(this)\b/
+ scope: 'variable.language',
+ begin: /\b(this)\b/,
+ relevance: 0
},
{
- className: 'keyword',
- begin: /\b(function|class|else|for|if|in|return)\b/
+ scope: 'keyword',
+ begin: /\b(else|for|if|in|return)\b/,
+ relevance: 0
},
{
- className: 'literal',
- begin: /\b(true|false)\b/
+ scope: 'literal',
+ begin: /\b(true|false)\b/,
+ relevance: 0
},
{
- className: 'operator',
- begin: /(\|\||\&\&|\=\=|\!\=|\>\=|\<\=|\=\>)/
+ scope: 'operator',
+ begin: /(\|\||\&\&|\=\=|\!\=|\>\=|\<\=|\=\>)/,
+ relevance: 0
},
{
scope: 'operator',
@@ -39,22 +130,28 @@ export default function(hljs) {
},
{
begin: [
- /function[\t ]+/,
+ /\b(function)\b/,
+ /[\t ]+/,
/[a-zA-Z_][\w]*/,
/\(/
],
beginScope: {
- 2: "title.function"
- }
+ 1: "keyword",
+ 3: "title.function"
+ },
+ relevance: 0
},
{
begin: [
- /class[\t ]+/,
+ /\b(class)\b/,
+ /[\t ]+/,
/[a-zA-Z_][\w]*/
],
beginScope: {
- 2: "title.class"
- }
+ 1: "keyword",
+ 3: "title.class"
+ },
+ relevance: 0
},
{
begin: [
@@ -63,10 +160,11 @@ export default function(hljs) {
],
beginScope: {
1: "title.function.invoke"
- }
+ },
+ relevance: 0
},
{
- className: 'variable',
+ scope: 'variable',
begin: /[a-zA-Z_][\w]*/,
relevance: 0
}
diff --git a/test/detect/rascript/default.txt b/test/detect/rascript/default.txt
deleted file mode 100644
index 634187f..0000000
--- a/test/detect/rascript/default.txt
+++ /dev/null
@@ -1,1721 +0,0 @@
-// Monster Max
-// #ID = 4111
-
-// $C006 - Start Menu
-function StartMenu() => word( 0xc006 )
-
-// $C009 - Select Menu
-function SelectMenu() => high4( 0xc009 )
-
-// $CFBF - Current mission
-function CurrentMission() => byte( 0xcfbf )
-
-// $D00A: Mission Flags for marking completed missions
-function MissionFlags() => dword( 0xd00a )
-
-// $D120: Lucky Star Count
-function LuckyStars() => byte( 0xd120 )
-
-// $D122: Health
-function Health() => byte( 0xd122 )
-
-// $D123: Speed Boost
-function SpeedBoost() => byte( 0xd123 )
-
-// $D124: Power Ring
-function PowerRing() => byte( 0xd124 )
-
-// $D125: PowerSpring
-function PowerSpring() => byte( 0xd125 )
-
-// $D128: Lift Pass Level
-function LiftPassLevel() => byte( 0xd128 )
-
-// $D129: Number of credits earned
-function Credits() => word( 0xd129 )
-
-// $D190: Start Menu Map Group 1
-function StartMenuMapGroup1() => bitcount( 0xd190 )
-
-// $D191: Start Menu Map Group 2
-function StartMenuMapGroup2() => bitcount( 0xd191 )
-
-class Test {
- t_var = 0
- t_newvar = "213"
-
- function DoSomething(v5, v56) {
- this.t_var = v5
- }
-}
-
-// $D192: Start Menu Map Group 3
-function StartMenuMapGroup3() => bitcount( 0xd192 )
-
-// $D193: Start Menu Map Group 4
-function StartMenuMapGroup4() => bitcount( 0xd193 )
-
-// $D194: Start Menu Map Group 5
-function StartMenuMapGroup5() => bitcount( 0xd194 )
-
-// $D195: Start Menu Map Group 6
-function StartMenuMapGroup6() => bitcount( 0xd195 )
-
-// $D196: Start Menu Map Group 7
-function StartMenuMapGroup7() => bitcount( 0xd196 )
-
-// $D3F0 - Password first four chars
-function PasswordCharGroup1() => dword( 0xd3f0 )
-
-// $D3F4 - Password last four chars
-function PasswordCharGroup2() => dword( 0xd3f4 )
-
-// $D3E5 - Current Select Menu Option Selection
-function SelectMenuOption() => byte( 0xd3e5 )
-
-// $D402 - Mission Bonus
-function Bonus() => word( 0xd402 )
-
-// Doors
-CLOSED = 0x00
-
-// Life
-DEAD = 0xFF
-
-// Mission Masks
-PLAYPENMASK = 0x00000001
-LEVEL1MISSION1MASK = 0x00000002
-LEVEL1MISSION2MASK = 0x00000004
-LEVEL1MISSION3MASK = 0x00000008
-LEVEL2MISSION1MASK = 0x00000010
-LEVEL2MISSION2MASK = 0x00000020
-LEVEL2MISSION3MASK = 0x00000040
-LEVEL3MISSION1MASK = 0x00000080
-LEVEL3MISSION2MASK = 0x00000100
-LEVEL3MISSION3MASK = 0x00000200
-LEVEL4MISSION1MASK = 0x00000400
-LEVEL4MISSION2MASK = 0x00000800
-LEVEL4MISSION3MASK = 0x00001000
-LEVEL5MISSION1MASK = 0x00002000
-LEVEL5MISSION2MASK = 0x00004000
-LEVEL5MISSION3MASK = 0x00008000
-LEVEL6MISSION1MASK = 0x00010000
-LEVEL6MISSION2MASK = 0x00020000
-LEVEL6MISSION3MASK = 0x00040000
-LEVEL7MISSION1MASK = 0x00080000
-LEVEL7MISSION2MASK = 0x00100000
-LEVEL7MISSION3MASK = 0x00200000
-LEVEL8MISSION1MASK = 0x00400000
-LEVEL8MISSION2MASK = 0x00800000
-LEVEL8MISSION3MASK = 0x01000000
-LEVEL9MISSION1MASK = 0x02000000
-LEVEL9MISSION2MASK = 0x04000000
-LEVEL9MISSION3MASK = 0x08000000
-LEVEL10MISSION1MASK = 0x10000000
-
-// Mission IDs
-MAINROOMID = 0x00
-PLAYPENID = 0x01
-LEVEL1MISSION1ID = 0x02
-LEVEL1MISSION2ID = 0x03
-LEVEL1MISSION3ID = 0x04
-LEVEL2MISSION1ID = 0x05
-LEVEL2MISSION2ID = 0x06
-LEVEL2MISSION3ID = 0x07
-LEVEL3MISSION1ID = 0x08
-LEVEL3MISSION2ID = 0x09
-LEVEL3MISSION3ID = 0x0A
-LEVEL4MISSION1ID = 0x0B
-LEVEL4MISSION2ID = 0x0C
-LEVEL4MISSION3ID = 0x0D
-LEVEL5MISSION1ID = 0x0E
-LEVEL5MISSION2ID = 0x0F
-LEVEL5MISSION3ID = 0x10
-LEVEL6MISSION1ID = 0x11
-LEVEL6MISSION2ID = 0x12
-LEVEL6MISSION3ID = 0x13
-LEVEL7MISSION1ID = 0x14
-LEVEL7MISSION2ID = 0x15
-LEVEL7MISSION3ID = 0x16
-LEVEL8MISSION1ID = 0x17
-LEVEL8MISSION2ID = 0x18
-LEVEL8MISSION3ID = 0x19
-LEVEL9MISSION1ID = 0x1A
-LEVEL9MISSION2ID = 0x1B
-LEVEL9MISSION3ID = 0x1C
-LEVEL10MISSION1ID = 0x1D
-TITLESCREENID = 0x1E
-CONCERTSCREENID = 0x1F
-
-LEVEL1 = 0x00
-LEVEL2 = 0x01
-LEVEL3 = 0x02
-LEVEL4 = 0x03
-LEVEL5 = 0x04
-LEVEL6 = 0x05
-LEVEL7 = 0x06
-LEVEL8 = 0x07
-LEVEL9 = 0x08
-LEVEL10 = 0x09
-
-levelLookup = {
- 1: {
- "id": LEVEL1,
- "titleOverride": "The Journey Begins",
- "cost": 0
- },
- 2: {
- "id": LEVEL2,
- "titleOverride": "Double the Trouble",
- "cost": 70,
- "raID": 459891,
- "raBadge": "549135"
- },
- 3: {
- "id": LEVEL3,
- "titleOverride": "It's a Long Way to the Top",
- "cost": 130,
- "raID": 459898,
- "raBadge": "520623"
- },
- 4: {
- "id": LEVEL4,
- "titleOverride": "Don't Stop Believin'",
- "cost": 200,
- "raID": 459905,
- "raBadge": "520630"
- },
- 5: {
- "id": LEVEL5,
- "titleOverride": "Just Move On Up",
- "cost": 300,
- "raID": 459912,
- "raBadge": "520637"
- },
- 6: {
- "id": LEVEL6,
- "titleOverride": "Takin' Care of Business",
- "cost": 450,
- "raID": 459919,
- "raBadge": "520644"
- },
- 7: {
- "id": LEVEL7,
- "titleOverride": "Stairway to Heaven",
- "cost": 650,
- "raID": 459926,
- "raBadge": "520651"
- },
- 8: {
- "id": LEVEL8,
- "titleOverride": "A Rising Star",
- "cost": 1000,
- "raID": 459933,
- "raBadge": "520658"
- },
- 9: {
- "id": LEVEL9,
- "titleOverride": "School's Out!",
- "cost": 1500,
- "raID": 459940,
- "raBadge": "520665"
- },
- 10: {
- "id": LEVEL10,
- "cost": 2500,
- "raID": 459947,
- "raBadge": "520672"
- },
-}
-
-achievements = {}
-
-// private functions
-
-function missionMarkedComplete( config )
-{
- // Mission is marked complete and it was previously closed
- return (
- ( ( MissionFlags() & config["missionMask"] ) == config["missionMask"] ) &&
- ( ( prev( MissionFlags() ) & config["missionMask"] ) == CLOSED )
- )
-}
-
-function onlyMissionUnlocked( config )
-{
- return (
- CurrentMission() == config["missionId"] &&
- MissionFlags() == ( prev( MissionFlags() ) + config["missionMask"] ) &&
- prior( bit( config["itemBit"], config["itemAddr"] ) ) == 0 &&
- bit( config["itemBit"], config["itemAddr"] ) == 1
- )
-}
-
-function PlayerHurt()
-{
- // Player loses a heart
- return (
- !inTitleScreen() && !inConcertScreen() && !inMainLobby() && // check that they are in a mission
- ( Health() == ( prev( Health() ) - 1 ) )
- )
-}
-
-function inMainLobby()
-{
- return (
- CurrentMission() == MAINROOMID
- )
-}
-
-function inSelectMenu()
-{
- return (
- SelectMenu() == 0
- )
-}
-
-function inStartMenu()
-{
- return (
- StartMenu() == 0x3836
- )
-}
-
-function inTitleScreen()
-{
- return (
- CurrentMission() == TITLESCREENID
- )
-}
-
-function inConcertScreen()
-{
- return (
- CurrentMission() == CONCERTSCREENID
- )
-}
-
-function upgradeLiftPassLevel( prevLevel, newLevel, cost )
-{
- return (
- prev( LiftPassLevel() ) == prevLevel &&
- LiftPassLevel() == newLevel &&
- prev( Credits() ) == ( Credits() + cost )
- )
-}
-
-function countRoomsSeen()
-{
- return (
- StartMenuMapGroup1() +
- StartMenuMapGroup2() +
- StartMenuMapGroup3() +
- StartMenuMapGroup4() +
- StartMenuMapGroup5() +
- StartMenuMapGroup6() +
- StartMenuMapGroup7()
- )
-}
-
-// public functions
-
-function OpenPasswordMenu()
-{
- return (
- inSelectMenu() &&
- SelectMenuOption() == 0x01 && // enter password menu
- prev( PasswordCharGroup1() ) != 0xFFFFFFFF && PasswordCharGroup1() == 0xFFFFFFFF &&
- prev( PasswordCharGroup2() ) != 0xFFFFFFFF && PasswordCharGroup2() == 0xFFFFFFFF
- )
-}
-
-function PlayerDies( missionIds )
-{
- conditions = (
- prev( Health() ) != DEAD &&
- Health() == DEAD
- )
- if length( missionIds ) > 0 {
- return any_of(
- missionIds,
- mid => CurrentMission() == mid && conditions
- )
- }
- return conditions
-}
-
-function PlayerQuitsMission( config )
-{
- return (
- prev( CurrentMission() ) == config["missionId"] &&
- CurrentMission() != config["missionId"] &&
- !missionMarkedComplete( config )
- )
-}
-
-function PlayerEntersMission( config )
-{
- return (
- prev( CurrentMission() ) == MAINROOMID &&
- CurrentMission() == config["missionId"]
- )
-}
-
-function MissionCompletePerfectCondition( config )
-{
- conditions = []
- if config["inGameHearts"] > 0 {
- array_push( conditions, repeated( config["inGameHearts"], CurrentMission() == config["missionId"] && Health() == prev( Health() ) + 1 ))
- }
- if config["stars"] > 0 {
- array_push( conditions, repeated( config["stars"], CurrentMission() == config["missionId"] && LuckyStars() == prev( LuckyStars() ) + 1 ) )
- }
- if config["gold"] > 0 {
- array_push( conditions, repeated( config["gold"], CurrentMission() == config["missionId"] && Bonus() == prev( Bonus() ) + config["bonus"] ) )
- }
- return tally(
- config["inGameHearts"] + config["stars"] + config["gold"],
- conditions
- )
-}
-
-function GameStarts()
-{
- return (
- LiftPassLevel() == 0x00 &&
- Credits() == 0x00 &&
- MissionFlags() == 0x00000000 &&
- (
- prev( CurrentMission() ) == TITLESCREENID ||
- prev( CurrentMission() ) == CONCERTSCREENID
- ) &&
- CurrentMission() == MAINROOMID
- )
-}
-
-function GameEnds()
-{
- return (
- LiftPassLevel() == 0x09 &&
- prev( CurrentMission() ) == LEVEL10MISSION1ID &&
- CurrentMission() == CONCERTSCREENID
- )
-}
-
-// Achievement Configs
-
-MissionConfigs = [
- {
- "index": 1,
- "level": 1,
- "mission": 0,
- "title": "Play Pen",
- "description": "Beat the play pen tutorial",
- "itemBit": 7,
- "itemAddr": 0xd002,
- "reward": 1,
- "startingHearts": 0,
- "bonus": 0,
- "inGameHearts": 0,
- "gold": 0,
- "stars": 0,
- "lightning": 0,
- "powerSpring": 1,
- "powerRing": 0,
- "map": 0,
- "points": 2,
- "type": "",
- "missionId": PLAYPENID,
- "missionMask": PLAYPENMASK,
- "hasChallenge": false,
- "raID": 459884,
- "raBadge": "520616",
- "leaderboardID": 114800
- },
- {
- "index": 2,
- "level": 1,
- "mission": 1,
- "title": "Big Brain",
- "description": "Destroy the mind",
- "itemBit": 1,
- "itemAddr": 0xd004,
- "reward": 30,
- "startingHearts": 4,
- "bonus": 3,
- "inGameHearts": 1,
- "gold": 1,
- "stars": 1,
- "lightning": 1,
- "powerSpring": 0,
- "powerRing": 0,
- "map": 0,
- "missionId": LEVEL1MISSION1ID,
- "missionMask": LEVEL1MISSION1MASK,
- "points": 5,
- "type": "",
- "raID": 459885,
- "raBadge": "520617",
- "hasChallenge": true,
- "challengeTitle": "Street Smarts",
- "challengePoints": 10,
- "challengeRAID": 459886,
- "challengeRABadge": "520618",
- "leaderboardID": 114801
- },
- {
- "index": 4,
- "level": 1,
- "mission": 2,
- "title": "Ice Queen",
- "description": "Steal the Ice Queen's crown",
- "itemBit": 1,
- "itemAddr": 0xd004,
- "reward": 30,
- "startingHearts": 4,
- "bonus": 3,
- "inGameHearts": 1,
- "gold": 0,
- "stars": 1,
- "lightning": 0,
- "powerSpring": 1,
- "powerRing": 0,
- "map": 0,
- "missionId": LEVEL1MISSION2ID,
- "missionMask": LEVEL1MISSION2MASK,
- "points": 5,
- "type": "",
- "raID": 459887,
- "raBadge": "520619",
- "hasChallenge": true,
- "challengeTitle": "Cold as Ice",
- "challengePoints": 10,
- "challengeRAID": 459888,
- "challengeRABadge": "520620",
- "leaderboardID": 114802
- },
- {
- "index": 6,
- "level": 1,
- "mission": 3,
- "title": "Erase the Alchemist",
- "description": "Destroy the alchemist",
- "itemBit": 2,
- "itemAddr": 0xd004,
- "reward": 45,
- "startingHearts": 4,
- "bonus": 3,
- "inGameHearts": 1,
- "gold": 1,
- "stars": 2,
- "lightning": 2,
- "powerSpring": 0,
- "powerRing": 1,
- "map": 1,
- "missionId": LEVEL1MISSION3ID,
- "missionMask": LEVEL1MISSION3MASK,
- "points": 5,
- "type": "",
- "raID": 459889,
- "raBadge": "520621",
- "hasChallenge": true,
- "challengeTitle": "The Scientist",
- "challengePoints": 10,
- "challengeRAID": 459890,
- "challengeRABadge": "520622",
- "leaderboardID": 114803
- },
- {
- "index": 9,
- "level": 2,
- "mission": 1,
- "title": "Blind the Enemy",
- "description": "Destroy the all seeing eye",
- "itemBit": 4,
- "itemAddr": 0xd004,
- "reward": 45,
- "startingHearts": 4,
- "bonus": 7,
- "inGameHearts": 1,
- "gold": 0,
- "stars": 2,
- "lightning": 1,
- "powerSpring": 0,
- "powerRing": 0,
- "map": 1,
- "missionId": LEVEL2MISSION1ID,
- "missionMask": LEVEL2MISSION1MASK,
- "points": 5,
- "type": "",
- "raID": 459892,
- "raBadge": "520624",
- "hasChallenge": true,
- "challengeTitle": "Eye of the Tiger",
- "challengePoints": 10,
- "challengeRAID": 459893,
- "challengeRABadge": "520625",
- "leaderboardID": 114804
- },
- {
- "index": 11,
- "level": 2,
- "mission": 2,
- "title": "Secret Codex",
- "description": "Read the secret code",
- "itemBit": 0,
- "itemAddr": 0xd004,
- "reward": 40,
- "startingHearts": 4,
- "bonus": 7,
- "inGameHearts": 1,
- "gold": 1,
- "stars": 3,
- "lightning": 0,
- "powerSpring": 0,
- "powerRing": 0,
- "map": 0,
- "missionId": LEVEL2MISSION2ID,
- "missionMask": LEVEL2MISSION2MASK,
- "points": 5,
- "type": "",
- "raID": 459894,
- "raBadge": "520626",
- "hasChallenge": true,
- "challengeTitle": "Lyrical Analysis",
- "challengePoints": 10,
- "challengeRAID": 459895,
- "challengeRABadge": "520627",
- "leaderboardID": 114805
- },
- {
- "index": 13,
- "level": 2,
- "mission": 3,
- "title": "Liftoff",
- "description": "Launch the self destructing rocket",
- "itemBit": 2,
- "itemAddr": 0xd004,
- "reward": 65,
- "startingHearts": 4,
- "bonus": 7,
- "inGameHearts": 1,
- "gold": 0,
- "stars": 0,
- "lightning": 0,
- "powerSpring": 1,
- "powerRing": 0,
- "map": 0,
- "missionId": LEVEL2MISSION3ID,
- "missionMask": LEVEL2MISSION3MASK,
- "points": 5,
- "type": "",
- "raID": 459896,
- "raBadge": "520628",
- "hasChallenge": true,
- "challengeTitle": "Soar to the Top of the Charts",
- "challengePoints": 10,
- "challengeRAID": 459897,
- "challengeRABadge": "520629",
- "leaderboardID": 114806
- },
- {
- "index": 16,
- "level": 3,
- "mission": 1,
- "title": "Illuminate the Way",
- "description": "Find the flashlight",
- "itemBit": 2,
- "itemAddr": 0xd004,
- "reward": 70,
- "startingHearts": 4,
- "bonus": 10,
- "inGameHearts": 1,
- "gold": 0,
- "stars": 2,
- "lightning": 1,
- "powerSpring": 0,
- "powerRing": 0,
- "map": 1,
- "missionId": LEVEL3MISSION1ID,
- "missionMask": LEVEL3MISSION1MASK,
- "points": 5,
- "type": "",
- "raID": 459899,
- "raBadge": "520631",
- "hasChallenge": true,
- "challengeTitle": "Kick Out the Stage Lights",
- "challengePoints": 10,
- "challengeRAID": 459900,
- "challengeRABadge": "520632",
- "leaderboardID": 114807
- },
- {
- "index": 18,
- "level": 3,
- "mission": 2,
- "title": "Circuit Breaker",
- "description": "Find the electrical control box",
- "itemBit": 7,
- "itemAddr": 0xd003,
- "reward": 60,
- "startingHearts": 4,
- "bonus": 10,
- "inGameHearts": 1,
- "gold": 2,
- "stars": 3,
- "lightning": 0,
- "powerSpring": 0,
- "powerRing": 0,
- "map": 0,
- "missionId": LEVEL3MISSION2ID,
- "missionMask": LEVEL3MISSION2MASK,
- "points": 5,
- "type": "",
- "raID": 459901,
- "raBadge": "520633",
- "hasChallenge": true,
- "challengeTitle": "Overdrive",
- "challengePoints": 10,
- "challengeRAID": 459902,
- "challengeRABadge": "520634",
- "leaderboardID": 114808
- },
- {
- "index": 20,
- "level": 3,
- "mission": 3,
- "title": "Startup Funds",
- "description": "Search for the piggy bank",
- "itemBit": 1,
- "itemAddr": 0xd004,
- "reward": 100,
- "startingHearts": 4,
- "bonus": 10,
- "inGameHearts": 1,
- "gold": 1,
- "stars": 2,
- "lightning": 1,
- "powerSpring": 1,
- "powerRing": 0,
- "map": 0,
- "missionId": LEVEL3MISSION3ID,
- "missionMask": LEVEL3MISSION3MASK,
- "points": 5,
- "type": "",
- "raID": 459903,
- "raBadge": "520635",
- "hasChallenge": true,
- "challengeTitle": "Sold Out Concert",
- "challengePoints": 10,
- "challengeRAID": 459904,
- "challengeRABadge": "520636",
- "leaderboardID": 114809
- },
- {
- "index": 23,
- "level": 4,
- "mission": 1,
- "title": "Time Keeper",
- "description": "Collect the pocketwatch",
- "itemBit": 1,
- "itemAddr": 0xd004,
- "reward": 100,
- "startingHearts": 4,
- "bonus": 15,
- "inGameHearts": 1,
- "gold": 1,
- "stars": 0,
- "lightning": 0,
- "powerSpring": 0,
- "powerRing": 0,
- "map": 0,
- "missionId": LEVEL4MISSION1ID,
- "missionMask": LEVEL4MISSION1MASK,
- "points": 5,
- "type": "",
- "raID": 459906,
- "raBadge": "520638",
- "hasChallenge": true,
- "challengeTitle": "It's Show Time!",
- "challengePoints": 10,
- "challengeRAID": 459907,
- "challengeRABadge": "520639",
- "leaderboardID": 114810
- },
- {
- "index": 25,
- "level": 4,
- "mission": 2,
- "title": "Food Poisoning",
- "description": "Get rid of the poisoned food",
- "itemBit": 0,
- "itemAddr": 0xd004,
- "reward": 100,
- "startingHearts": 4,
- "bonus": 15,
- "inGameHearts": 1,
- "gold": 1,
- "stars": 1,
- "lightning": 1,
- "powerSpring": 0,
- "powerRing": 0,
- "map": 0,
- "missionId": LEVEL4MISSION2ID,
- "missionMask": LEVEL4MISSION2MASK,
- "points": 5,
- "type": "",
- "raID": 459908,
- "raBadge": "520640",
- "hasChallenge": true,
- "challengeTitle": "Rock and McRoll",
- "challengePoints": 10,
- "challengeRAID": 459909,
- "challengeRABadge": "520641",
- "leaderboardID": 114811
- },
- {
- "index": 27,
- "level": 4,
- "mission": 3,
- "title": "Command an Army",
- "description": "Earn the crown of attack",
- "itemBit": 5,
- "itemAddr": 0xd002,
- "reward": 150,
- "startingHearts": 3,
- "bonus": 15,
- "inGameHearts": 1,
- "gold": 1,
- "stars": 1,
- "lightning": 0,
- "powerSpring": 0,
- "powerRing": 0,
- "map": 1,
- "missionId": LEVEL4MISSION3ID,
- "missionMask": LEVEL4MISSION3MASK,
- "points": 5,
- "type": "",
- "raID": 459910,
- "raBadge": "520642",
- "hasChallenge": true,
- "challengeTitle": "The King of Rock",
- "challengePoints": 10,
- "challengeRAID": 459911,
- "challengeRABadge": "520643",
- "leaderboardID": 114812
- },
- {
- "index": 30,
- "level": 5,
- "mission": 1,
- "title": "Ghost Ship",
- "description": "Take the ghost ship wood log",
- "itemBit": 1,
- "itemAddr": 0xd003,
- "reward": 150,
- "startingHearts": 4,
- "bonus": 20,
- "inGameHearts": 1,
- "gold": 2,
- "stars": 1,
- "lightning": 1,
- "powerSpring": 0,
- "powerRing": 0,
- "map": 0,
- "missionId": LEVEL5MISSION1ID,
- "missionMask": LEVEL5MISSION1MASK,
- "points": 5,
- "type": "",
- "raID": 459913,
- "raBadge": "520645",
- "hasChallenge": true,
- "challengeTitle": "Rock the Boat",
- "challengePoints": 10,
- "challengeRAID": 459914,
- "challengeRABadge": "520646",
- "leaderboardID": 114813
- },
- {
- "index": 32,
- "level": 5,
- "mission": 2,
- "title": "Talk to the Dead",
- "description": "Collect the crystal ball",
- "itemBit": 0,
- "itemAddr": 0xd004,
- "reward": 200,
- "startingHearts": 3,
- "bonus": 20,
- "inGameHearts": 1,
- "gold": 0,
- "stars": 1,
- "lightning": 0,
- "powerSpring": 1,
- "powerRing": 0,
- "map": 0,
- "missionId": LEVEL5MISSION2ID,
- "missionMask": LEVEL5MISSION2MASK,
- "points": 5,
- "type": "",
- "raID": 459915,
- "raBadge": "520647",
- "hasChallenge": true,
- "challengeTitle": "Fortune Teller", // Roling Stones
- "challengePoints": 10,
- "challengeRAID": 459916,
- "challengeRABadge": "520648",
- "leaderboardID": 114814
- },
- {
- "index": 34,
- "level": 5,
- "mission": 3,
- "title": "Keeping Warm",
- "description": "Use the wood stove",
- "itemBit": 1,
- "itemAddr": 0xd004,
- "reward": 300,
- "startingHearts": 3,
- "bonus": 20,
- "inGameHearts": 1,
- "gold": 0,
- "stars": 1,
- "lightning": 0,
- "powerSpring": 0,
- "powerRing": 0,
- "map": 0,
- "missionId": LEVEL5MISSION3ID,
- "missionMask": LEVEL5MISSION3MASK,
- "points": 5,
- "type": "",
- "raID": 459917,
- "raBadge": "520649",
- "hasChallenge": true,
- "challengeTitle": "Through the Fire and Flames",
- "challengePoints": 10,
- "challengeRAID": 459918,
- "challengeRABadge": "520650",
- "leaderboardID": 114815
- },
- {
- "index": 37,
- "level": 6,
- "mission": 1,
- "title": "In Safe Hands",
- "description": "Return the safe",
- "itemBit": 4,
- "itemAddr": 0xd005,
- "reward": 275,
- "startingHearts": 3,
- "bonus": 30,
- "inGameHearts": 0,
- "gold": 1,
- "stars": 0,
- "lightning": 5,
- "powerSpring": 0,
- "powerRing": 0,
- "map": 0,
- "missionId": LEVEL6MISSION1ID,
- "missionMask": LEVEL6MISSION1MASK,
- "points": 5,
- "type": "",
- "raID": 459920,
- "raBadge": "520652",
- "hasChallenge": true,
- "challengeTitle": "The Unreleased Album",
- "challengePoints": 10,
- "challengeRAID": 459921,
- "challengeRABadge": "520653",
- "leaderboardID": 114816
- },
- {
- "index": 39,
- "level": 6,
- "mission": 2,
- "title": "Enchantment",
- "description": "Smash the potion vial",
- "itemBit": 5,
- "itemAddr": 0xd005,
- "reward": 300,
- "startingHearts": 3,
- "bonus": 30,
- "inGameHearts": 1,
- "gold": 0,
- "stars": 0,
- "lightning": 3,
- "powerSpring": 0,
- "powerRing": 1,
- "map": 1,
- "missionId": LEVEL6MISSION2ID,
- "missionMask": LEVEL6MISSION2MASK,
- "points": 5,
- "type": "",
- "raID": 459922,
- "raBadge": "520654",
- "hasChallenge": true,
- "challengeTitle": "THE CONCOCTION",
- "challengePoints": 10,
- "challengeRAID": 459923,
- "challengeRABadge": "520655",
- "leaderboardID": 114817
- },
- {
- "index": 41,
- "level": 6,
- "mission": 3,
- "title": "Cursed Gem",
- "description": "Destroy the dark jewel",
- "itemBit": 0,
- "itemAddr": 0xd004,
- "reward": 450,
- "startingHearts": 3,
- "bonus": 30,
- "inGameHearts": 1,
- "gold": 0,
- "stars": 1,
- "lightning": 0,
- "powerSpring": 1,
- "powerRing": 0,
- "map": 0,
- "missionId": LEVEL6MISSION3ID,
- "missionMask": LEVEL6MISSION3MASK,
- "points": 5,
- "type": "",
- "raID": 459924,
- "raBadge": "520656",
- "hasChallenge": true,
- "challengeTitle": "Bejeweled",
- "challengePoints": 10,
- "challengeRAID": 459925,
- "challengeRABadge": "520657",
- "leaderboardID": 114818
- },
- {
- "index": 44,
- "level": 7,
- "mission": 1,
- "title": "POP!",
- "description": "Earn the fizzy soda prize",
- "itemBit": 1,
- "itemAddr": 0xd004,
- "reward": 450,
- "startingHearts": 3,
- "bonus": 42,
- "inGameHearts": 1,
- "gold": 1,
- "stars": 4,
- "lightning": 0,
- "powerSpring": 0,
- "powerRing": 0,
- "map": 0,
- "missionId": LEVEL7MISSION1ID,
- "missionMask": LEVEL7MISSION1MASK,
- "points": 5,
- "type": "",
- "raID": 459927,
- "raBadge": "520659",
- "hasChallenge": true,
- "challengeTitle": "Have a Drink on Me", // AC/DC
- "challengePoints": 10,
- "challengeRAID": 459928,
- "challengeRABadge": "520660",
- "leaderboardID": 114819
- },
- {
- "index": 46,
- "level": 7,
- "mission": 2,
- "title": "Waiting for a Call",
- "description": "Collect the phone",
- "itemBit": 2,
- "itemAddr": 0xd004,
- "reward": 450,
- "startingHearts": 3,
- "bonus": 42,
- "inGameHearts": 1,
- "gold": 1,
- "stars": 3,
- "lightning": 1,
- "powerSpring": 0,
- "powerRing": 0,
- "map": 0,
- "missionId": LEVEL7MISSION2ID,
- "missionMask": LEVEL7MISSION2MASK,
- "points": 5,
- "type": "",
- "raID": 459929,
- "raBadge": "520661",
- "hasChallenge": true,
- "challengeTitle": "Off the Hook",
- "challengePoints": 10,
- "challengeRAID": 459930,
- "challengeRABadge": "520662",
- "leaderboardID": 114820
- },
- {
- "index": 48,
- "level": 7,
- "mission": 3,
- "title": "S.O.S",
- "description": "Release the captive voyager",
- "itemBit": 3,
- "itemAddr": 0xd003,
- "reward": 600,
- "startingHearts": 2,
- "bonus": 42,
- "inGameHearts": 1,
- "gold": 0,
- "stars": 3,
- "lightning": 0,
- "powerSpring": 1,
- "powerRing": 1,
- "map": 0,
- "missionId": LEVEL7MISSION3ID,
- "missionMask": LEVEL7MISSION3MASK,
- "points": 5,
- "type": "",
- "raID": 459931,
- "raBadge": "520663",
- "hasChallenge": true,
- "challengeTitle": "Message in a Bottle", // The Police
- "challengePoints": 10,
- "challengeRAID": 459932,
- "challengeRABadge": "520664",
- "leaderboardID": 114821
- },
- {
- "index": 51,
- "level": 8,
- "mission": 1,
- "title": "K9 Companion",
- "description": "Rescue the dog",
- "itemBit": 1,
- "itemAddr": 0xd004,
- "reward": 650,
- "startingHearts": 3,
- "bonus": 60,
- "inGameHearts": 1,
- "gold": 0,
- "stars": 1,
- "lightning": 16,
- "powerSpring": 0,
- "powerRing": 0,
- "map": 0,
- "missionId": LEVEL8MISSION1ID,
- "missionMask": LEVEL8MISSION1MASK,
- "points": 5,
- "type": "",
- "raID": 459934,
- "raBadge": "520666",
- "hasChallenge": true,
- "challengeTitle": "Who Let the Dogs Out?",
- "challengePoints": 10,
- "challengeRAID": 459935,
- "challengeRABadge": "520667",
- "leaderboardID": 114822
- },
- {
- "index": 53,
- "level": 8,
- "mission": 2,
- "title": "Fast Getaway",
- "description": "Find and flee with the amphora jar",
- "itemBit": 0,
- "itemAddr": 0xd004,
- "reward": 650,
- "startingHearts": 2,
- "bonus": 60,
- "inGameHearts": 1,
- "gold": 0,
- "stars": 3,
- "lightning": 1,
- "powerSpring": 0,
- "powerRing": 0,
- "map": 0,
- "missionId": LEVEL8MISSION2ID,
- "missionMask": LEVEL8MISSION2MASK,
- "points": 5,
- "type": "",
- "raID": 459936,
- "raBadge": "520668",
- "hasChallenge": true,
- "challengeTitle": "Rock You like a Hurricane",
- "challengePoints": 10,
- "challengeRAID": 459937,
- "challengeRABadge": "520669",
- "leaderboardID": 114823
- },
- {
- "index": 55,
- "level": 8,
- "mission": 3,
- "title": "Piece of Cake",
- "description": "Eat the triple decker cake",
- "itemBit": 1,
- "itemAddr": 0xd004,
- "reward": 850,
- "startingHearts": 2,
- "bonus": 60,
- "inGameHearts": 1,
- "gold": 1,
- "stars": 5,
- "lightning": 0,
- "powerSpring": 0,
- "powerRing": 0,
- "map": 0,
- "missionId": LEVEL8MISSION3ID,
- "missionMask": LEVEL8MISSION3MASK,
- "points": 5,
- "type": "",
- "raID": 459938,
- "raBadge": "520670",
- "hasChallenge": true,
- "challengeTitle": "Fight for Your Right to Party",
- "challengePoints": 10,
- "challengeRAID": 459939,
- "challengeRABadge": "520671",
- "leaderboardID": 114824
- },
- {
- "index": 58,
- "level": 9,
- "mission": 1,
- "title": "Hacking the Mainframe",
- "description": "Destroy the computer system",
- "itemBit": 0,
- "itemAddr": 0xd004,
- "reward": 900,
- "startingHearts": 2,
- "bonus": 90,
- "inGameHearts": 1,
- "gold": 0,
- "stars": 5,
- "lightning": 0,
- "powerSpring": 0,
- "powerRing": 0,
- "map": 0,
- "missionId": LEVEL9MISSION1ID,
- "missionMask": LEVEL9MISSION1MASK,
- "points": 5,
- "type": "",
- "raID": 459941,
- "raBadge": "520673",
- "hasChallenge": true,
- "challengeTitle": "Technologic",
- "challengePoints": 10,
- "challengeRAID": 459942,
- "challengeRABadge": "520674",
- "leaderboardID": 114825
- },
- {
- "index": 60,
- "level": 9,
- "mission": 2,
- "title": "Infestation",
- "description": "Smash open the jar of insects",
- "itemBit": 0,
- "itemAddr": 0xd004,
- "reward": 800,
- "startingHearts": 2,
- "bonus": 90,
- "inGameHearts": 1,
- "gold": 2,
- "stars": 3,
- "lightning": 1,
- "powerSpring": 0,
- "powerRing": 1,
- "map": 0,
- "missionId": LEVEL9MISSION2ID,
- "missionMask": LEVEL9MISSION2MASK,
- "points": 5,
- "type": "",
- "raID": 459943,
- "raBadge": "520675",
- "hasChallenge": true,
- "challengeTitle": "Squash Those Beetles",
- "challengePoints": 10,
- "challengeRAID": 459944,
- "challengeRABadge": "520676",
- "leaderboardID": 114826
- },
- {
- "index": 62,
- "level": 9,
- "mission": 3,
- "title": "Home Sweet Home",
- "description": "Find a new home",
- "itemBit": 7,
- "itemAddr": 0xd003,
- "reward": 1100,
- "startingHearts": 2,
- "bonus": 90,
- "inGameHearts": 1,
- "gold": 0,
- "stars": 1,
- "lightning": 0,
- "powerSpring": 0,
- "powerRing": 0,
- "map": 1,
- "missionId": LEVEL9MISSION3ID,
- "missionMask": LEVEL9MISSION3MASK,
- "points": 5,
- "type": "",
- "raID": 459945,
- "raBadge": "520677",
- "hasChallenge": true,
- "challengeTitle": "Mansion Tour",
- "challengePoints": 10,
- "challengeRAID": 459946,
- "challengeRABadge": "520678",
- "leaderboardID": 114827
- },
- {
- "index": 65,
- "level": 10,
- "mission": 1,
- "title": "King Krond",
- "description": "Defeat Krond and save the Mega Hero Academy!",
- "itemBit": 5,
- "itemAddr": 0xd008,
- "reward": 3500,
- "startingHearts": 3,
- "bonus": 120,
- "inGameHearts": 4,
- "gold": 0,
- "stars": 1,
- "lightning": 2,
- "powerSpring": 1,
- "powerRing": 1,
- "map": 0,
- "missionId": LEVEL10MISSION1ID,
- "missionMask": LEVEL10MISSION1MASK,
- "points": 25,
- "type": "win_condition",
- "raID": 459948,
- "raBadge": "520680",
- "hasChallenge": false,
- "leaderboardID": 114828
- }
-]
-
-currentLevel = 1
-count = 0
-lightningMissions = []
-powerSpringMissions = []
-powerRingMissions = []
-mapMissions = []
-leaderboards = []
-
-for config in MissionConfigs
-{
- // Progression level achievements
- if currentLevel + 1 == config["level"] {
- levelIndex = config["index"] - 1
- levelMissionConfigs = []
- levelMissionIds = []
- for missionConfig in MissionConfigs {
- if missionConfig["level"] == currentLevel && missionConfig["mission"] != 0 {
- array_push( levelMissionConfigs, missionConfig )
- array_push( levelMissionIds, missionConfig["missionId"] )
- }
- }
- conditions = [
- once( GameStarts() ),
- once( GameStarts() )
- ]
- for levelMissionConfig in levelMissionConfigs {
- array_push( conditions, once(
- onlyMissionUnlocked( levelMissionConfig )
- ) )
- }
- title = format("Complete Level {0}", currentLevel)
- if dictionary_contains_key( levelLookup[currentLevel], "titleOverride" ) {
- title = levelLookup[currentLevel]["titleOverride"]
- }
- levelAchievement = {
- "title": title,
- "description": format("Buy the lift pass for level {0} without using passwords, or if using passwords complete any two missions on level {1} before buying the lift pass for level {0}", config["level"], currentLevel),
- "points": 10,
- "trigger": tally(
- 2,
- conditions
- ) &&
- upgradeLiftPassLevel( levelLookup[currentLevel]["id"], levelLookup[config["level"]]["id"], levelLookup[config["level"]]["cost"] ) &&
- never( OpenPasswordMenu() ),
- "type": "progression",
- "id": levelLookup[config["level"]]["raID"],
- "badge": levelLookup[config["level"]]["raBadge"],
- }
- count = count + 1
- achievements[levelIndex] = levelAchievement
- currentLevel = config["level"]
- }
-
- // Standard mission completion achievements
- currIndex = config["index"]
- desc = format( "{0} and complete Level {1} Mission {2}", config["description"], config["level"], config["mission"])
- leaderboardTitle = format( "Speedrun Level {0} Mission {1}", config["level"], config["mission"] )
- leaderboardDescription = format( "Complete Level {0} Mission {1} from start to finish as fast as possible without using passwords", config["level"], config["mission"] )
- if ( ( config["level"] == 1 && config["mission"] == 0 ) || ( config["level"] == 10 && config["mission"] == 1 ) ) { // Play pen & king krond
- desc = config["description"]
- if ( config["level"] == 1 && config["mission"] == 0 ) {
- leaderboardTitle = format("Speedrun {0}", config["title"])
- leaderboardDescription = format("Complete {0} from start to finish as fast as possible without using passwords", config["title"] )
- }
- }
- a = {
- "title": config["title"],
- "description": desc,
- "points": config["points"],
- "trigger": onlyMissionUnlocked( config ),
- "type": config["type"],
- "id": config["raID"],
- "badge": config["raBadge"],
- }
- achievements[currIndex] = a
- count = count + 1
-
- // Missable challenge mission achievements
- if config["hasChallenge"] {
- currIndex = currIndex + 1
- items = ""
- if config["inGameHearts"] > 0 || config["gold"] > 0 || config["stars"] > 0 {
- items = ", collect "
- heartLabel = "heart"
- if config["inGameHearts"] > 1 {
- heartLabel = "hearts"
- }
- goldLabel = "gold bullion"
- if config["gold"] > 1 {
- goldLabel = "gold bullions"
- }
- starLabel = "star"
- if config["stars"] > 1 {
- starLabel = "stars"
- }
- args = []
- if config["inGameHearts"] > 0 {
- array_push( args, config["inGameHearts"] )
- array_push( args, heartLabel )
- }
- if config["gold"] > 0 {
- array_push( args, config["gold"] )
- array_push( args, goldLabel )
- }
- if config["stars"] > 0 {
- array_push( args, config["stars"] )
- array_push( args, starLabel )
- }
- for index in range( 0, length( args ) - 1, 2) {
- atEnd = true
- if length( args ) > 2 {
- if index == length( args ) - 2 {
- items = items + " and "
- } else {
- if index != 0 {
- items = items + ", "
- }
- }
- }
- items = items + args[index] + " " + args[index + 1]
- }
- }
- title = format("Perfect {0}", config["title"])
- if dictionary_contains_key( config, "challengeTitle" ) {
- title = config["challengeTitle"]
- }
- a1 = {
- "title": title,
- "description": format("Without taking damage{0} and complete Level {1} Mission {2}", items, config["level"], config["mission"]),
- "points": config["challengePoints"],
- "trigger": once( PlayerEntersMission( config ) ) &&
- measured(
- MissionCompletePerfectCondition( config )
- ) &&
- onlyMissionUnlocked( config ) &&
- never( PlayerHurt() ) &&
- never( OpenPasswordMenu() ) &&
- never( PlayerDies( [] ) ) &&
- never( PlayerQuitsMission( config ) ),
- "type": "missable",
- "id": config["challengeRAID"],
- "badge": config["challengeRABadge"]
- }
- count = count + 1
- achievements[currIndex] = a1
- }
-
- // Build lists for "fun" achievements
-
- // lightnings
- if config["lightning"] > 0 {
- array_push( lightningMissions, config["missionId"] )
- }
-
- // power springs
- if config["powerSpring"] > 0 && config["missionId"] != PLAYPENID { // gather all power spring missions that are not the playpen
- array_push( powerSpringMissions, config["missionId"] )
- }
-
- // power rings
- if config["powerRing"] > 0 {
- array_push( powerRingMissions, config["missionId"] )
- }
-
- // maps
- if config["map"] > 0 {
- array_push( mapMissions, config["missionId"] )
- }
-
- // Create leaderboard structures
- l = {
- "title": leaderboardTitle,
- "description": leaderboardDescription,
- "start": PlayerEntersMission( config ),
- "cancel": (
- OpenPasswordMenu() ||
- PlayerDies( [] ) ||
- PlayerQuitsMission( config )
- ),
- "submit": onlyMissionUnlocked( config ),
- "value": measured( always_true() ) &&
- unless( inSelectMenu() ) &&
- unless( inStartMenu() ),
- "format": "FRAMES",
- "lower_is_better": true,
- "id": config["leaderboardID"]
- }
- array_push( leaderboards, l )
-}
-
-// Lightning achievement
-currIndex = count + 1
-a = {
- "index": 66,
- "title": "Speedy",
- "description": "Pick up a lightning in any mission",
- "points": 2,
- "trigger": any_of(
- lightningMissions,
- mid => CurrentMission() == mid &&
- prev( SpeedBoost() ) == 0 &&
- SpeedBoost() > 0
- ),
- "type": "",
- "id": 459950,
- "badge": "520682",
-}
-count = count + 1
-achievements[currIndex] = a
-
-// Power Spring achievement
-currIndex = count + 1
-a = {
- "title": "Jump to the Rescue",
- "description": "Pick up a power spring in any mission except the Play Pen",
- "points": 2,
- "trigger": any_of(
- powerSpringMissions,
- mid => CurrentMission() == mid &&
- prev( PowerSpring() ) + 0x0a == PowerSpring()
- ),
- "type": "",
- "id": 459951,
- "badge": "520683",
-}
-count = count + 1
-achievements[currIndex] = a
-
-// Power Ring achievement
-currIndex = count + 1
-a = {
- "title": "Invincible",
- "description": "Pick up a power ring in any mission",
- "points": 2,
- "trigger": any_of(
- powerRingMissions,
- mid => CurrentMission() == mid &&
- prev( PowerRing() ) == 0 &&
- PowerRing() > 0
- ),
- "type": "",
- "id": 459952,
- "badge": "520684",
-}
-count = count + 1
-achievements[currIndex] = a
-
-// Map achievement
-currIndex = count + 1
-a = {
- "title": "I'm the Map",
- "description": "If there's a place you got to get, a map can get you there, I bet. Find a map to reveal the mission layout",
- "points": 2,
- "trigger": any_of(
- mapMissions,
- mid => CurrentMission() == mid &&
- prev( countRoomsSeen() ) <= countRoomsSeen() &&
- countRoomsSeen() == 56 // 8 bits * 7 groups = 56 rooms max to play with
- ),
- "type": "",
- "id": 459953,
- "badge": "520685",
-}
-count = count + 1
-achievements[currIndex] = a
-
-// VOIDED Win condition achievement
-currIndex = count + 1
-a = {
- "title": "[VOID] Beat the Game",
- "description": "Beat every level of the game without using passwords",
- "points": 0,
- "trigger": always_false(),
- "type": "",
- "id": 459949,
- "badge": "520681",
-}
-count = count + 1
-achievements[currIndex] = a
-
-if length( achievements ) == count { // This check is to ensure the amount of achievements I expect when building the order of them
- for index in range( 1, count ) {
- a = achievements[index]
- achievement(
- title = a["title"],
- description = a["description"],
- points = a["points"],
- trigger = a["trigger"],
- type = a["type"],
- id = a["id"],
- badge = a["badge"]
- )
- }
-}
-
-// Rich Presence
-
-levelPass = {
- 0: "Level 1",
- 1: "Level 2",
- 2: "Level 3",
- 3: "Level 4",
- 4: "Level 5",
- 5: "Level 6",
- 6: "Level 7",
- 7: "Level 8",
- 8: "Level 9",
- 9: "Level 10"
-}
-
-currentMission = {
- 1: "Play Pen",
- 2: "Level 1 Mission 1",
- 3: "Level 1 Mission 2",
- 4: "Level 1 Mission 3",
- 5: "Level 2 Mission 1",
- 6: "Level 2 Mission 2",
- 7: "Level 2 Mission 3",
- 8: "Level 3 Mission 1",
- 9: "Level 3 Mission 2",
- 10: "Level 3 Mission 3",
- 11: "Level 4 Mission 1",
- 12: "Level 4 Mission 2",
- 13: "Level 4 Mission 3",
- 14: "Level 5 Mission 1",
- 15: "Level 5 Mission 2",
- 16: "Level 5 Mission 3",
- 17: "Level 6 Mission 1",
- 18: "Level 6 Mission 2",
- 19: "Level 6 Mission 3",
- 20: "Level 7 Mission 1",
- 21: "Level 7 Mission 2",
- 22: "Level 7 Mission 3",
- 23: "Level 8 Mission 1",
- 24: "Level 8 Mission 2",
- 25: "Level 8 Mission 3",
- 26: "Level 9 Mission 1",
- 27: "Level 9 Mission 2",
- 28: "Level 9 Mission 3",
- 29: "Level 10 Mission 1"
-}
-
-singular_lookup = {
- 1: ""
-}
-
-rich_presence_conditional_display(
- inTitleScreen(),
- "Title Screen"
-)
-
-rich_presence_conditional_display(
- inConcertScreen(),
- "Playing in the Hero Academy Concert"
-)
-
-rich_presence_conditional_display(
- inMainLobby(),
- "Main Lobby • {0} Star{1} • {2} Lift Pass • #{3} Credit{4}",
- rich_presence_value( "valueFormat", LuckyStars(), "VALUE" ),
- rich_presence_lookup( "singularLookup", LuckyStars(), singular_lookup, "s" ),
- rich_presence_lookup( "liftPassLevel", LiftPassLevel(), levelPass ),
- rich_presence_value( "credits", Credits(), "POINTS" ),
- rich_presence_lookup( "singularLookup", Credits(), singular_lookup, "s" )
-)
-
-rich_presence_display(
- "{0} • {1} Heart{2} • {3} Star{4}",
- rich_presence_lookup( "mission", CurrentMission(), currentMission ),
- rich_presence_value( "valueFormat", Health(), "VALUE" ),
- rich_presence_lookup( "singularLookup", Health(), singular_lookup, "s" ),
- rich_presence_value( "valueFormat", LuckyStars(), "VALUE" ),
- rich_presence_lookup( "singularLookup", LuckyStars(), singular_lookup, "s" )
-)
-
-// Leaderboards
-
-speedrun = {
- "title": "Speedrun Monster Max",
- "description": "Complete the game from start to finish as fast as possible without using passwords",
- "start": GameStarts(),
- "cancel": OpenPasswordMenu(),
- "submit": GameEnds(),
- "value": tally( 37, deduct( always_true() ) ) && // 60 * 0.61 = ~36.6 frames unavoidable in the start, remove them to start at 0 seconds
- measured( always_true() ) &&
- unless( inTitleScreen() ) &&
- unless( inSelectMenu() ) &&
- unless( inStartMenu() ),
- "format": "FRAMES",
- "lower_is_better": true,
- "id": 114798
-}
-array_push( leaderboards, speedrun )
-
-highScore = {
- "title": "High Score",
- "description": "Complete the game from start to finish with the most credits and stars without using passwords",
- "start": GameStarts(),
- "cancel": OpenPasswordMenu(),
- "submit": GameEnds(),
- "value": Credits() + LuckyStars(),
- "format": "VALUE",
- "lower_is_better": false,
- "id": 114799
-}
-array_push( leaderboards, highScore )
-
-for l in leaderboards
-{
- leaderboard(
- title = l["title"],
- description = l["description"],
- start = l["start"],
- cancel = l["cancel"],
- submit = l["submit"],
- value = l["value"],
- format = l["format"],
- lower_is_better = l["lower_is_better"],
- id = l["id"]
- )
-}
\ No newline at end of file
diff --git a/test/markup/rascript/class.expect.txt b/test/markup/rascript/class.expect.txt
new file mode 100644
index 0000000..e408dd3
--- /dev/null
+++ b/test/markup/rascript/class.expect.txt
@@ -0,0 +1,12 @@
+class Test
+{
+ t_test = 0
+
+ function DoSomething(arg1, arg2) {
+ this.t_test = arg1 + arg2
+ }
+
+ function GetSomething() {
+ return this.t_test
+ }
+}
\ No newline at end of file
diff --git a/test/markup/rascript/class.txt b/test/markup/rascript/class.txt
new file mode 100644
index 0000000..50768e7
--- /dev/null
+++ b/test/markup/rascript/class.txt
@@ -0,0 +1,12 @@
+class Test
+{
+ t_test = 0
+
+ function DoSomething(arg1, arg2) {
+ this.t_test = arg1 + arg2
+ }
+
+ function GetSomething() {
+ return this.t_test
+ }
+}
\ No newline at end of file
diff --git a/test/markup/rascript/comments.expect.txt b/test/markup/rascript/comments.expect.txt
new file mode 100644
index 0000000..6c7cf29
--- /dev/null
+++ b/test/markup/rascript/comments.expect.txt
@@ -0,0 +1,9 @@
+
+
+
+
+non_comment = "this is not part of the comment"
\ No newline at end of file
diff --git a/test/markup/rascript/comments.txt b/test/markup/rascript/comments.txt
new file mode 100644
index 0000000..345421a
--- /dev/null
+++ b/test/markup/rascript/comments.txt
@@ -0,0 +1,9 @@
+/**
+ * This is a test comment
+ * It crosses multiple lines
+ * RAScript supports multiple types of comments
+ **/
+
+// This is the second form, a single line comment
+
+non_comment = "this is not part of the comment"
\ No newline at end of file
diff --git a/test/markup/rascript/function.expect.txt b/test/markup/rascript/function.expect.txt
new file mode 100644
index 0000000..c0db0cf
--- /dev/null
+++ b/test/markup/rascript/function.expect.txt
@@ -0,0 +1,3 @@
+function Test(var1) {
+ return var1 + 2
+}
\ No newline at end of file
diff --git a/test/markup/rascript/function.txt b/test/markup/rascript/function.txt
new file mode 100644
index 0000000..6ae027d
--- /dev/null
+++ b/test/markup/rascript/function.txt
@@ -0,0 +1,3 @@
+function Test(var1) {
+ return var1 + 2
+}
\ No newline at end of file