Spaces:
Running
Running
Upload 569 files
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +34 -0
- .nojekyll +0 -0
- Makefile +137 -0
- README.md +115 -11
- compile_levels.sh +14 -0
- deploy.sh.example +3 -0
- favicon.ico +0 -0
- images/mute-off.png +0 -0
- images/mute-on.png +0 -0
- images/static.gif +0 -0
- index.html +120 -15
- levels/01_cellBlockA.jsx +64 -0
- levels/02_theLongWayOut.jsx +49 -0
- levels/03_validationEngaged.jsx +47 -0
- levels/04_multiplicity.jsx +40 -0
- levels/05_minesweeper.jsx +55 -0
- levels/06_drones101.jsx +79 -0
- levels/07_colors.jsx +103 -0
- levels/08_intoTheWoods.jsx +123 -0
- levels/09_fordingTheRiver.jsx +68 -0
- levels/10_ambush.jsx +127 -0
- levels/11_robot.jsx +94 -0
- levels/12_robotNav.jsx +97 -0
- levels/13_robotMaze.jsx +131 -0
- levels/14_crispsContest.jsx +130 -0
- levels/15_exceptionalCrossing.jsx +55 -0
- levels/16_lasers.jsx +90 -0
- levels/17_pointers.jsx +94 -0
- levels/18_superDrEvalBros.jsx +86 -0
- levels/19_documentObjectMadness.jsx +164 -0
- levels/20_bossFight.jsx +161 -0
- levels/21_endOfTheLine.jsx +50 -0
- levels/22_credits.jsx +97 -0
- levels/bonus/01_inTheDesert.jsx +89 -0
- levels/bonus/02_theEmptyRoom.jsx +89 -0
- levels/bonus/03_theCollapsingRoom.jsx +99 -0
- levels/bonus/04_theGuard.jsx +43 -0
- levels/bonus/05_theCorridor.jsx +93 -0
- levels/bonus/AB_1_ANewJourney.jsx +102 -0
- levels/bonus/AB_2_FrozenCave.jsx +144 -0
- levels/bonus/AB_3_BoulderMadness.jsx +92 -0
- levels/bonus/AB_4_BatAttack.jsx +115 -0
- levels/bonus/AB_5_PathOfDoom.jsx +116 -0
- levels/bonus/AB_6_Credits +42 -0
- levels/bonus/_sampleLevel.jsx +20 -0
- levels/bonus/darkAlley.jsx +98 -0
- levels/bonus/ice.jsx +93 -0
- levels/bonus/labryinth.jsx +308 -0
- levels/bonus/levelName.jsx +52 -0
- levels/bonus/noWayOut.jsx +44 -0
.gitattributes
CHANGED
@@ -32,3 +32,37 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
32 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
33 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
34 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
33 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
34 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
35 |
+
music/(((stereofect)))_Winter_Solstice_2012.mp3 filter=lfs diff=lfs merge=lfs -text
|
36 |
+
music/Adversity.mp3 filter=lfs diff=lfs merge=lfs -text
|
37 |
+
music/Adversity.wav filter=lfs diff=lfs merge=lfs -text
|
38 |
+
music/all_ages_bitcrusher.mp3 filter=lfs diff=lfs merge=lfs -text
|
39 |
+
music/Ant_Neely_-_07_-_Not_Fit_For_Human_Consumption.mp3 filter=lfs diff=lfs merge=lfs -text
|
40 |
+
music/BLEO_-_02_-_Tart_Pts_1__2_feat_KeFF.mp3 filter=lfs diff=lfs merge=lfs -text
|
41 |
+
music/BLEO_-_04_-_Death_Destroyer_Radio_Edit_feat_Rhinostrich.mp3 filter=lfs diff=lfs merge=lfs -text
|
42 |
+
music/Boss[[:space:]]Loop[[:space:]]1.mp3 filter=lfs diff=lfs merge=lfs -text
|
43 |
+
music/Boss[[:space:]]Loop[[:space:]]1.wav filter=lfs diff=lfs merge=lfs -text
|
44 |
+
music/Broke_For_Free_-_01_-_Night_Owl.mp3 filter=lfs diff=lfs merge=lfs -text
|
45 |
+
music/conspiracy_bitcrusher_final.mp3 filter=lfs diff=lfs merge=lfs -text
|
46 |
+
music/Eric_Skiff_-_06_-_Searching.mp3 filter=lfs diff=lfs merge=lfs -text
|
47 |
+
music/Eric_Skiff_-_09_-_Come_and_Find_Me_-_B_mix.mp3 filter=lfs diff=lfs merge=lfs -text
|
48 |
+
music/Fex_coming_soon.mp3 filter=lfs diff=lfs merge=lfs -text
|
49 |
+
music/gurh.mp3 filter=lfs diff=lfs merge=lfs -text
|
50 |
+
music/intricate_cloudy_sin.mp3 filter=lfs diff=lfs merge=lfs -text
|
51 |
+
music/Jackson_D_Zero_One.mp3 filter=lfs diff=lfs merge=lfs -text
|
52 |
+
music/Obsibilo_-_02_-_Comme_Des_Orages.mp3 filter=lfs diff=lfs merge=lfs -text
|
53 |
+
music/Obsibilo_-_Soixante-8.mp3 filter=lfs diff=lfs merge=lfs -text
|
54 |
+
music/Revolution_Void_-_08_-_Obscure_Terrain.mp3 filter=lfs diff=lfs merge=lfs -text
|
55 |
+
music/RoccoW_-_Messeah.mp3 filter=lfs diff=lfs merge=lfs -text
|
56 |
+
music/Rolemusic_-_07_-_Beach_Wedding_Dance.mp3 filter=lfs diff=lfs merge=lfs -text
|
57 |
+
music/Roots[[:space:]]of[[:space:]]Supremacy.mp3 filter=lfs diff=lfs merge=lfs -text
|
58 |
+
music/Roots[[:space:]]of[[:space:]]Supremacy.wav filter=lfs diff=lfs merge=lfs -text
|
59 |
+
music/Skizofonik_System.mp3 filter=lfs diff=lfs merge=lfs -text
|
60 |
+
music/Spectrofuzz_Sunset_84.mp3 filter=lfs diff=lfs merge=lfs -text
|
61 |
+
music/Sycamore_Drive_-_03_-_The_Waves_Call_Her_Name.mp3 filter=lfs diff=lfs merge=lfs -text
|
62 |
+
music/ThatAndyGuy-Chip-loop.mp3 filter=lfs diff=lfs merge=lfs -text
|
63 |
+
music/ThatAndyGuy-Chip.mp3 filter=lfs diff=lfs merge=lfs -text
|
64 |
+
music/Tortue_Super_Sonic_-_11_-_Y.mp3 filter=lfs diff=lfs merge=lfs -text
|
65 |
+
music/Various_Artists_-_15_-_Slimeball_vomit.mp3 filter=lfs diff=lfs merge=lfs -text
|
66 |
+
music/Vernon_Lenoir_-_Brazilicon_alley.mp3 filter=lfs diff=lfs merge=lfs -text
|
67 |
+
music/what.mp3 filter=lfs diff=lfs merge=lfs -text
|
68 |
+
music/Yonnie_The_Green.mp3 filter=lfs diff=lfs merge=lfs -text
|
.nojekyll
ADDED
File without changes
|
Makefile
ADDED
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Partially based off of:
|
2 |
+
# http://nefariousdesigns.co.uk/website-builds-using-make.html
|
3 |
+
|
4 |
+
# if a mod is specified but doesn't exist, raise an error
|
5 |
+
err:=$(shell if [ ! -z '$(mod)' ] && [ ! -d 'mods/$(mod)' ]; then echo 'Mod [$(mod)] not found!'; fi)
|
6 |
+
ifneq '$(err)' ''
|
7 |
+
$(error $(err))
|
8 |
+
endif
|
9 |
+
|
10 |
+
mod-dir=$(shell if [ -z '$(mod)' ]; then echo 'default'; else echo $(mod); fi)
|
11 |
+
|
12 |
+
err:=$(shell if [ ! -f 'mods/$(mod-dir)/intro.js' ]; then echo 'File mods/$(mod-dir)/intro.js not found!'; fi)
|
13 |
+
ifneq '$(err)' ''
|
14 |
+
$(error $(err))
|
15 |
+
endif
|
16 |
+
|
17 |
+
js-target = scripts/build/untrusted.js
|
18 |
+
js-target-min = scripts/build/untrusted.min.js
|
19 |
+
|
20 |
+
js-modules = scripts/util.js \
|
21 |
+
mods/$(mod-dir)/intro.js\
|
22 |
+
scripts/_head.js \
|
23 |
+
scripts/game.js \
|
24 |
+
scripts/codeEditor.js \
|
25 |
+
scripts/display.js \
|
26 |
+
scripts/dynamicObject.js \
|
27 |
+
scripts/inventory.js \
|
28 |
+
scripts/map.js \
|
29 |
+
scripts/objects.js \
|
30 |
+
scripts/player.js \
|
31 |
+
scripts/reference.js \
|
32 |
+
scripts/sound.js \
|
33 |
+
scripts/validate.js \
|
34 |
+
scripts/ui.js \
|
35 |
+
levels/levels.js \
|
36 |
+
scripts/_launcher_release.js \
|
37 |
+
scripts/_tail.js
|
38 |
+
|
39 |
+
js-modules-debug = scripts/util.js \
|
40 |
+
mods/$(mod-dir)/intro.js\
|
41 |
+
scripts/_head.js \
|
42 |
+
scripts/game.js \
|
43 |
+
scripts/codeEditor.js \
|
44 |
+
scripts/display.js \
|
45 |
+
scripts/dynamicObject.js \
|
46 |
+
scripts/inventory.js \
|
47 |
+
scripts/map.js \
|
48 |
+
scripts/objects.js \
|
49 |
+
scripts/player.js \
|
50 |
+
scripts/reference.js \
|
51 |
+
scripts/sound.js \
|
52 |
+
scripts/validate.js \
|
53 |
+
scripts/ui.js \
|
54 |
+
levels/levels.js \
|
55 |
+
scripts/_launcher_debug.js \
|
56 |
+
scripts/_tail.js
|
57 |
+
|
58 |
+
yui-jar = tools/yuicompressor-2.4.8pre.jar
|
59 |
+
|
60 |
+
# `make` or `make debug` merges scripts (using debug launcher)
|
61 |
+
debug:
|
62 |
+
@echo "Building level file…\t\t\t\c"
|
63 |
+
@./compile_levels.sh $(mod-dir)
|
64 |
+
@echo "[ Done ]"
|
65 |
+
@echo "Merging JS files…\t\t\t\c"
|
66 |
+
@cat $(js-modules-debug) > $(js-target)
|
67 |
+
@./parse_target.sh $(js-target) $(mod-dir)
|
68 |
+
@echo "[ Done ]"
|
69 |
+
|
70 |
+
# `make release` merges and compresses scripts (using release launcher)
|
71 |
+
release:
|
72 |
+
@rm -f $(js-target-min)
|
73 |
+
@echo "Building level file…\t\t\t\c"
|
74 |
+
@./compile_levels.sh $(mod-dir)
|
75 |
+
@echo "[ Done ]"
|
76 |
+
@echo "Merging JS files…\t\t\t\c"
|
77 |
+
@cat $(js-modules) > $(js-target)
|
78 |
+
@./parse_target.sh $(js-target) $(mod-dir)
|
79 |
+
@echo "[ Done ]"
|
80 |
+
@echo "Compressing merged JS…\t\t\t\c"
|
81 |
+
@java -jar $(yui-jar) -o $(js-target-min) $(js-target)
|
82 |
+
@echo "[ Done ]"
|
83 |
+
|
84 |
+
# `make clean` removes built scripts
|
85 |
+
clean:
|
86 |
+
@rm -f $(js-target) $(js-target-min)
|
87 |
+
|
88 |
+
# to use `make deploy` to deploy Untrusted to your own server, create
|
89 |
+
# a deploy.sh script (ncftpput is helpful for uploading via FTP).
|
90 |
+
deploy: release
|
91 |
+
@echo "Deploying to server…\t\t\t\c"
|
92 |
+
@rm -rf _site
|
93 |
+
@mkdir _site
|
94 |
+
@cp -R levels scripts styles images sound index.html _site
|
95 |
+
@./deploy.sh /untrusted _site
|
96 |
+
@rm -rf _site
|
97 |
+
@echo "[ Done ]"
|
98 |
+
|
99 |
+
# `make deploy-full` also deploys music and libs
|
100 |
+
deploy-full: release
|
101 |
+
@echo "Deploying to server…\t\t\t\c"
|
102 |
+
@rm -rf _site
|
103 |
+
@mkdir _site
|
104 |
+
@cp -R levels scripts styles images sound music lib index.html _site
|
105 |
+
@./deploy.sh /untrusted _site
|
106 |
+
@rm -rf _site
|
107 |
+
@echo "[ Done ]"
|
108 |
+
|
109 |
+
# `make deploy-debug` deploys the debug version to /debug
|
110 |
+
deploy-debug: debug
|
111 |
+
@echo "Deploying to server…\t\t\t\c"
|
112 |
+
@rm -rf _site
|
113 |
+
@mkdir _site
|
114 |
+
@cp -R levels scripts styles images sound index.html _site
|
115 |
+
@./deploy.sh /untrusted/debug _site
|
116 |
+
@rm -rf _site
|
117 |
+
@echo "[ Done ]"
|
118 |
+
|
119 |
+
# `make deploy-debug` deploys the debug version to /debug
|
120 |
+
deploy-debug-full: debug
|
121 |
+
@echo "Deploying to server…\t\t\t\c"
|
122 |
+
@rm -rf _site
|
123 |
+
@mkdir _site
|
124 |
+
@cp -R levels scripts styles images sound music lib index.html _site
|
125 |
+
@./deploy.sh /untrusted/debug _site
|
126 |
+
@rm -rf _site
|
127 |
+
@echo "[ Done ]"
|
128 |
+
|
129 |
+
deploy-github:
|
130 |
+
@git checkout gh-pages && git merge master --no-commit && make release && git commit -am "build" && git push origin gh-pages; git checkout master && make
|
131 |
+
|
132 |
+
# run-local will start a mini python webserver and host a local
|
133 |
+
# instance of the game will run on an available port
|
134 |
+
# the option -c-1 disables caching
|
135 |
+
runlocal: debug
|
136 |
+
@echo "Running local instance"
|
137 |
+
./node_modules/http-server/bin/http-server -c-1
|
README.md
CHANGED
@@ -1,11 +1,115 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
**Untrusted —or— the Continuing Adventures of Dr. Eval** is an exciting Meta-JavaScript Adventure Game wherein you guide the dashing, steadfast Dr. Eval through a mysterious MACHINE CONTINUUM, wherein, using only his trusty computer and the TURING-COMPLETE power of JavaScript, he must literally ALTER HIS REALITY in order to find his freedom! You must literally edit and re-execute the very JavaScript running the game in your browser to save Dr. Eval from this dark and confusing reality!
|
2 |
+
|
3 |
+
### Overview
|
4 |
+
|
5 |
+
The game presents you with a roguelike-like playing environment and a console window with the JavaScript code generating each level. As loaded, each level is unbeatable, and most of the JavaScript is blocked from editing. The challenge is to open a path to the next level using only the limited tools left open to you.
|
6 |
+
|
7 |
+
### Development
|
8 |
+
|
9 |
+
Run
|
10 |
+
```
|
11 |
+
make
|
12 |
+
```
|
13 |
+
to merge the JavaScript files into `scripts/build/untrusted.js` (and enables debug features).
|
14 |
+
|
15 |
+
```
|
16 |
+
make release
|
17 |
+
```
|
18 |
+
merges and minifies the JavaScript files into `scripts/build/untrusted.min.js` (and disables debug features).
|
19 |
+
|
20 |
+
To run the game locally, you need to set up a local server to serve `index.html` (this step is necessary due to Access-Control-Allow-Origin restrictions).
|
21 |
+
|
22 |
+
First install [http-server](https://github.com/nodeapps/http-server/#installing-globally) if you haven't already:
|
23 |
+
|
24 |
+
```
|
25 |
+
npm install http-server
|
26 |
+
```
|
27 |
+
|
28 |
+
Then run:
|
29 |
+
|
30 |
+
```
|
31 |
+
make runlocal
|
32 |
+
```
|
33 |
+
|
34 |
+
Build your own mod in the `mods` directory:
|
35 |
+
|
36 |
+
```
|
37 |
+
make mod=example_mod
|
38 |
+
```
|
39 |
+
|
40 |
+
### Contributing Levels
|
41 |
+
|
42 |
+
To add a new level, create a jsx file in [/levels/bonus](https://github.com/AlexNisnevich/untrusted/tree/master/levels/bonus) and add the level filename to the `bonusLevels` array in [game.js](https://github.com/AlexNisnevich/untrusted/blob/master/scripts/game.js#L40).
|
43 |
+
|
44 |
+
If you are adding any new commands that the player can use, make sure to add them to `reference.js`.
|
45 |
+
|
46 |
+
#### The .jsx file format
|
47 |
+
|
48 |
+
jsx files are like regular JavaScript files, but have some additional syntax:
|
49 |
+
- `#BEGIN_EDITABLE#` and `#END_EDITABLE#` surround editable lines
|
50 |
+
- `#{#` and `#}#` wrap editable sections (parts of lines)
|
51 |
+
- `#BEGIN_PROPERTIES#` and `#END_PROPERTIES#` surround the properties object at the start of the file. Available properties include:
|
52 |
+
- `commandsIntroduced`: array of new commands introduced in the level (see `reference.js`)
|
53 |
+
- `mapProperties`: optionally contains any of the following:
|
54 |
+
- `allowOverwrite`: if true, placed static objects can be overwritten by other objects
|
55 |
+
- `keyDelay`: specifies the lag, in milliseconds, between player keystrokes (default: 0)
|
56 |
+
- `refreshRate`: the refresh rate of the level, in milliseconds (required for dynamic objects with `interval` properties to work correctly)
|
57 |
+
- `showDrawingCanvas`: if true, the drawing canvas overlay is displayed
|
58 |
+
- `showDummyDom`: if true, a dummy DOM will be displayed instead of the regular map
|
59 |
+
- `music`: name of the background track for the level (see `sound.js`)
|
60 |
+
- `startingMessage`: message displayed at the bottom of the screen when the level starts (if any)
|
61 |
+
- `version`: increase the level version whenever you update a level
|
62 |
+
- `nextBonusLevel`: load another level automatically when this one is solved
|
63 |
+
- `#START_OF_START_LEVEL#` and `#END_OF_START_LEVEL#` should be the first and last line of the `startLevel` method, respectively
|
64 |
+
|
65 |
+
#### Adding music
|
66 |
+
|
67 |
+
To add a new background music track, add an MP3 file (that you have permission to use) to the [/music](https://github.com/AlexNisnevich/untrusted/tree/master/music) and add a new entry to the `tracks` array in [sound.js](https://github.com/AlexNisnevich/untrusted/blob/master/scripts/sound.js).
|
68 |
+
|
69 |
+
### Acknowledgements
|
70 |
+
|
71 |
+
Untrusted is a game by [Alex Nisnevich](http://alex.nisnevich.com/) and [Greg Shuflin](https://github.com/neunenak).
|
72 |
+
|
73 |
+
We'd like to thank:
|
74 |
+
|
75 |
+
- [Dmitry Mazin](https://github.com/dmazin) for design assistance and for the implementation of multiline editing
|
76 |
+
- [Jordan Arnesen](https://github.com/extrajordanary) for playtesting and design of lvl17
|
77 |
+
- [Natasha Hull-Richter](http://nhull.com) for extensive playtesting and assistance in level design
|
78 |
+
- Alex Bolotov, Colin Curtin, Conrad Irwin, Devin C-R, Eugene Evans, Gilbert Hsyu, Jacob Nisnevich, James Silvey, Jason Jiang, Jimmy Hack, Philip Shao, Ryan Fitzgerald, Stephen Liu, Yayoi Ukai, and Yuval Gnessin for playtesting and feedback
|
79 |
+
- [Ondřej Žára](https://github.com/ondras) for his [rot.js](http://ondras.github.io/rot.js/) library
|
80 |
+
- [Marijn Haverbeke](https://github.com/marijnh) for his [CodeMirror](http://codemirror.net/) library
|
81 |
+
- [Brian Harvey](http://www.cs.berkeley.edu/~bh/) for allowing us to use his likeness in lvl19
|
82 |
+
|
83 |
+
#### Soundtrack
|
84 |
+
|
85 |
+
You can [listen to the full soundtrack here](https://soundcloud.com/untrusted/sets/untrusted-soundtrack).
|
86 |
+
|
87 |
+
The music that appears in Untrusted, in order, is:
|
88 |
+
|
89 |
+
- "The Green" - [Jonathan Holliday](http://www.soundclick.com/bands/default.cfm?bandID=836578) (used with permission)
|
90 |
+
- "Dmitry's Thing #2" - [Dmitry Mazin](https://soundcloud.com/dmitry-mazin) (written for Untrusted)
|
91 |
+
- "Obscure Terrain" - [Revolution Void](http://revolutionvoid.com/) (CC-BY-NC-SA)
|
92 |
+
- "coming soon" - [Fex](http://artistserver.com/Fex) (public domain)
|
93 |
+
- "cloudy sin" - [iNTRICATE](https://soundcloud.com/stk13) (used with permission)
|
94 |
+
- "Dynamic Punctuality" - [Dmitry Mazin](https://soundcloud.com/dmitry-mazin) (written for Untrusted)
|
95 |
+
- "Y" - [Tortue Super Sonic](https://soundcloud.com/tss-tortue-super-sonic) (CC-BY-NC-SA)
|
96 |
+
- "Night Owl" - [Broke for Free](http://brokeforfree.com/) (CC-BY)
|
97 |
+
- "The Waves Call Her Name" - [Sycamore Drive](http://sycamoredrive.bandcamp.com/) (CC-BY-NC-SA)
|
98 |
+
- "Come and Find Me - B mix" - [Eric Skiff](http://ericskiff.com/) (CC-BY)
|
99 |
+
- "Conspiracy" - [Mike and Alan](https://www.facebook.com/MicAndAlan) (used with permission)
|
100 |
+
- "Messeah" - [RoccoW](https://soundcloud.com/roccow) (CC-BY)
|
101 |
+
- "Searching" - [Eric Skiff](http://ericskiff.com/) (CC-BY)
|
102 |
+
- "Da Funk Do You Know 'bout Chip?" - [That Andy Guy](https://soundcloud.com/that-andy-guy) (used with permission)
|
103 |
+
- "Soixante-8" - [Obsibilo](http://freemusicarchive.org/music/Obsibilo/) (CC-BY-NC-SA)
|
104 |
+
- "Tart (Pts 1 and 2)" - [BLEO feat KeFF](http://bleo.dummydrome.com/) (CC-BY-NC-SA)
|
105 |
+
- "Beach Wedding Dance" - [Rolemusic](https://soundcloud.com/rolemusic) (CC-BY-NC-SA)
|
106 |
+
- "Boss Loop 1" - [Essa](http://www.youtube.com/user/Essasmusic) (free to use)
|
107 |
+
- "Adversity" - [Seropard](https://soundcloud.com/seropard) (free to use)
|
108 |
+
- "Comme Des Orages" - [Obsibilo](http://freemusicarchive.org/music/Obsibilo/) (CC-BY-NC-SA)
|
109 |
+
- "Brazilicon Alley" - [Vernon Lenoir](http://vernonlenoir.wordpress.com/) (CC-BY-NC-SA), based on "Aquarela do Brazil" by Ary Barroso
|
110 |
+
|
111 |
+
### License
|
112 |
+
This work is dual-licensed.
|
113 |
+
|
114 |
+
- Untrusted and the Untrusted soundtrack are licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License (CC-BY-NC-SA 3.0)</a>. In other words, you are free to use and modify Untrusted for non-commercial purposes, provided that you credit us and your work is also licensed under CC-BY-NC-SA.
|
115 |
+
- Additionally, the Untrusted code *without the soundtrack* is licenced under a commercial license. This means that you are able to use Untrusted for commercial purposes under some conditions, provided that you do not use any of the music. Please [contact us](mailto:[email protected],[email protected]) for details.
|
compile_levels.sh
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
echo "Game.prototype._levels = {" > levels/levels.js
|
2 |
+
|
3 |
+
mod=$1
|
4 |
+
|
5 |
+
for lvl in mods/$mod/*.jsx
|
6 |
+
do
|
7 |
+
lvlfn=`basename $lvl`
|
8 |
+
printf %s " 'levels/$lvlfn': '" >> levels/levels.js
|
9 |
+
echo "$lvl" | xargs sed "s#\\\#\\\\\\\#g" | sed "s#'#\\\'#g" | tr '\n' '`' | sed "s/\`/\\\n/g" | sed -e "a\\
|
10 |
+
',
|
11 |
+
" | tr '\n' ' ' >> levels/levels.js
|
12 |
+
echo "" >> levels/levels.js # dummy newline for style
|
13 |
+
done
|
14 |
+
echo "};" >> levels/levels.js
|
deploy.sh.example
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
cd $2
|
2 |
+
ncftpput -R -v -u [username] ftp.[domain].com [untrusted_root_path]$1 .
|
3 |
+
cd ..
|
favicon.ico
ADDED
|
images/mute-off.png
ADDED
![]() |
images/mute-on.png
ADDED
![]() |
images/static.gif
ADDED
![]() |
index.html
CHANGED
@@ -1,19 +1,124 @@
|
|
1 |
<!DOCTYPE html>
|
2 |
<html>
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
</div>
|
18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
</html>
|
|
|
1 |
<!DOCTYPE html>
|
2 |
<html>
|
3 |
+
<head>
|
4 |
+
<title>Untrusted - a user javascript adventure game</title>
|
5 |
+
<meta charset='utf8'></meta>
|
6 |
+
<link rel="shortcut icon" href="favicon.ico" />
|
7 |
+
|
8 |
+
<link href='//fonts.googleapis.com/css?family=Droid+Sans+Mono|Share+Tech+Mono' rel='stylesheet' type='text/css'>
|
9 |
+
|
10 |
+
<link rel="stylesheet" href="styles/game.css">
|
11 |
+
|
12 |
+
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
|
13 |
+
<script type="text/javascript" src="lib/es5-shim.min.js"></script>
|
14 |
+
<script type="text/javascript" src="lib/shortcut.js"></script>
|
15 |
+
<script type="text/javascript" src="lib/rotjs-library/rot.js"></script>
|
16 |
+
<script type="text/javascript" src="lib/jquery.jplayer.min.js"></script>
|
17 |
+
|
18 |
+
<link rel="stylesheet" href="lib/codemirror-3.1/lib/codemirror.css">
|
19 |
+
<script src="lib/codemirror-3.1/lib/codemirror.js"></script>
|
20 |
+
<script src="lib/codemirror-3.1/mode/javascript/javascript.js"></script>
|
21 |
+
<link rel="stylesheet" href="lib/codemirror-3.1/theme/vibrant-ink.css">
|
22 |
+
|
23 |
+
<script src="scripts/build/untrusted.js"></script>
|
24 |
+
</head>
|
25 |
+
<body>
|
26 |
+
<a id="forkMe" href="https://github.com/AlexNisnevich/untrusted" target="_blank"><img style="position: absolute; top: 0; right: 0; border: 0; z-index: 9999;" src="//s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on GitHub"></a>
|
27 |
+
<div id="container">
|
28 |
+
<div id="panes">
|
29 |
+
<noscript>
|
30 |
+
You must enable JavaScript to play Untrusted.
|
31 |
+
</noscript>
|
32 |
+
<a id="muteButton"><img draggable ="false" src="images/mute-off.png" /></a>
|
33 |
+
<span id="nowPlayingMsg" class="topStatus"></span>
|
34 |
+
<span id="savedLevelMsg" class="topStatus"></span>
|
35 |
+
<div id="screenPane">
|
36 |
+
<canvas id="drawingCanvas"></canvas>
|
37 |
+
<div id="dummyDom"></div>
|
38 |
+
<div id="screen"></div>
|
39 |
+
<div id="inventory"></div>
|
40 |
+
<div id="output"></div>
|
41 |
+
<div id="chapter"></div>
|
42 |
+
</div>
|
43 |
+
<div id="editorPane" style="display: none;">
|
44 |
+
<textarea id="editor">
|
45 |
+
</textarea>
|
46 |
+
<div id="buttons">
|
47 |
+
<span><a id="helpButton" title="Ctrl+1: API Reference"><span class="keys">^1</span> API</a></span>
|
48 |
+
<span><a id="toggleFocusButton" title="Ctrl+2: Toggle Focus"><span class="keys">^2</span> Toggle Focus</a></span>
|
49 |
+
<span><a id="notepadButton" title="Ctrl+3: Notepad"><span class="keys">^3</span> Notepad</a></span>
|
50 |
+
<span><a id="resetButton" title="Ctrl+4: Reset Level"><span class="keys">^4</span> Reset</a></span>
|
51 |
+
<span><a id="executeButton" title="Ctrl+5: Execute"><span class="keys">^5</span> Execute</a></span>
|
52 |
+
<span><a id="phoneButton" style="display: none;" title="Q: Use Phone"><span class="keys"> Q</span> Phone</a></span>
|
53 |
+
<span><a id="menuButton" title="Ctrl+0: Menu" style="float: right;"><span class="keys">^0</span> <span id="menuLabel">Menu</span></a></span>
|
54 |
+
</div>
|
55 |
+
</div>
|
56 |
+
<div id="helpPane" style="display: none;">
|
57 |
+
<div id="helpPaneSidebar">
|
58 |
+
<div id="helpPaneTitle">API Reference</div>
|
59 |
+
<ul></ul>
|
60 |
+
</div>
|
61 |
+
<div id="helpPaneContent"></div>
|
62 |
+
<div id="helpPaneCloseButton">x</div>
|
63 |
+
</div>
|
64 |
+
|
65 |
+
<div id="menuPane" class='pop_up_box'>
|
66 |
+
<div id="leftMenuPane">
|
67 |
+
<ul>
|
68 |
+
<li id="rootDir">/</li>
|
69 |
+
<li id="levelsDir" class="nested selected">levels/</li>
|
70 |
+
<li id="scriptsDir" class="nested">scripts/</li>
|
71 |
+
<li id="bonusDir" class="nested">bonus/</li>
|
72 |
+
</ul>
|
73 |
+
</div>
|
74 |
+
<div id="rightMenuPane">
|
75 |
+
<div class="pop_up_box_heading">Level Select</div>
|
76 |
+
<div id="root"></div>
|
77 |
+
<div id="levels"></div>
|
78 |
+
<div id="scripts"></div>
|
79 |
+
<div id="bonus"></div>
|
80 |
+
</div>
|
81 |
+
</div>
|
82 |
+
|
83 |
+
<div id="notepadPane" class='pop_up_box'>
|
84 |
+
<div id='notepadPaneContent'>
|
85 |
+
<div class="pop_up_box_heading">$EDITOR</div>
|
86 |
+
<textarea id=notepadTextarea></textarea>
|
87 |
+
<button id='notepadSaveButton'>Save</button>
|
88 |
</div>
|
89 |
+
<div id='notepadPaneCloseButton'>x</div>
|
90 |
+
</div>
|
91 |
+
</div>
|
92 |
+
|
93 |
+
<div id="licensing">
|
94 |
+
<a onClick="$('#licensingEmail').toggle();">Interested in using Untrusted commercially?</a>
|
95 |
+
<span id="licensingEmail">[email protected]</span>
|
96 |
+
</div>
|
97 |
+
|
98 |
+
<div id="paypal">
|
99 |
+
<span id="paypalCaption">Send some beer money our way?</span>
|
100 |
+
<form id="paypalButton" action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_blank">
|
101 |
+
<input type="hidden" name="cmd" value="_s-xclick">
|
102 |
+
<input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----MIIHbwYJKoZIhvcNAQcEoIIHYDCCB1wCAQExggEwMIIBLAIBADCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwDQYJKoZIhvcNAQEBBQAEgYCm7SFl45X1Lu7xu+F3oAV+spw9MvqKfjmED56iQSTH7SbbRdGmbtbQ30smDaU9rOXIt1QoEcFJgjO/Fq8o0+BWn7thno7btbwDnt4Jvr2DycSwZPSa8x8jNgypLBQVkQVL2v7ufhcjuNpIr7nz4M9CdmT0ys2m2JwpprBWDjFrtzELMAkGBSsOAwIaBQAwgewGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQI4EnAzSo6DfyAgci7VmL95V9fzkvjGoJSp9ZyDwaziQZPr9/CV285CyhivtaDc1Ytz1tnYAumWweOmBhlKbRNUg+3nXSlvqh8FXM/iHmr5QKEPFKFWvyqIOuXheDzKg+pX7UeeLzkZpagx6eJtvxf4C2KmOVcx4f8y6vj+Eoh4wsO/yKqyt0cdXWpnNNl7N1vMGSiJa43yHJ4TGGDwa9jOJfKo/kUZE8s7LYpGQODNvFEHYnLplS5pYo+xhbpq4j74z1oCT+UOYhJMvwa4N91dYOFOaCCA4cwggODMIIC7KADAgECAgEAMA0GCSqGSIb3DQEBBQUAMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbTAeFw0wNDAyMTMxMDEzMTVaFw0zNTAyMTMxMDEzMTVaMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwUdO3fxEzEtcnI7ZKZL412XvZPugoni7i7D7prCe0AtaHTc97CYgm7NsAtJyxNLixmhLV8pyIEaiHXWAh8fPKW+R017+EmXrr9EaquPmsVvTywAAE1PMNOKqo2kl4Gxiz9zZqIajOm1fZGWcGS0f5JQ2kBqNbvbg2/Za+GJ/qwUCAwEAAaOB7jCB6zAdBgNVHQ4EFgQUlp98u8ZvF71ZP1LXChvsENZklGswgbsGA1UdIwSBszCBsIAUlp98u8ZvF71ZP1LXChvsENZklGuhgZSkgZEwgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAgV86VpqAWuXvX6Oro4qJ1tYVIT5DgWpE692Ag422H7yRIr/9j/iKG4Thia/Oflx4TdL+IFJBAyPK9v6zZNZtBgPBynXb048hsP16l2vi0k5Q2JKiPDsEfBhGI+HnxLXEaUWAcVfCsQFvd2A1sxRr67ip5y2wwBelUecP3AjJ+YcxggGaMIIBlgIBATCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTE0MDQwOTIwMTMwNVowIwYJKoZIhvcNAQkEMRYEFCwi/dWQTjH3ydSP3kF9F1D65lSoMA0GCSqGSIb3DQEBAQUABIGAJ11YwSy6yDT6yk7rHUbyGQ027xEZ8xwDqjDGbbpPxswr3B4nXHlJwohhmv4Iy50Oq9g/FWCeQSNXMti52qGvAdzVVuzCelTb8ngxWmY+B7129CmqjZJPZPPCCuT+NjDovXDfNbJzYWakBkJSGeRlM84JBUuSQF1Ki+lI7BBUC7s=-----END PKCS7-----">
|
103 |
+
<input type="image" src="//www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
|
104 |
+
<img alt="" border="0" src="//www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1">
|
105 |
+
</form>
|
106 |
+
</div>
|
107 |
+
</div>
|
108 |
+
|
109 |
+
<div id="jquery_bgPlayer" class="jp-jplayer"></div>
|
110 |
+
<div id="jquery_soundPlayer" class="jp-jplayer"></div>
|
111 |
+
<script type="text/javascript">
|
112 |
+
var _gaq = _gaq || [];
|
113 |
+
_gaq.push(['_setAccount', 'UA-345959-12']);
|
114 |
+
_gaq.push(['_trackPageview']);
|
115 |
+
|
116 |
+
(function() {
|
117 |
+
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
118 |
+
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
119 |
+
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
120 |
+
})();
|
121 |
+
</script>
|
122 |
+
<iframe id="user_code" style="display:none;" />
|
123 |
+
</body>
|
124 |
</html>
|
levels/01_cellBlockA.jsx
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.2.1",
|
4 |
+
"commandsIntroduced":
|
5 |
+
["global.startLevel", "global.onExit", "map.placePlayer",
|
6 |
+
"map.placeObject", "map.getHeight", "map.getWidth",
|
7 |
+
"map.displayChapter", "map.getPlayer", "player.hasItem"],
|
8 |
+
"music": "The Green"
|
9 |
+
}
|
10 |
+
#END_PROPERTIES#
|
11 |
+
/*****************
|
12 |
+
* cellBlockA.js *
|
13 |
+
*****************
|
14 |
+
*
|
15 |
+
* Good morning, Dr. Eval.
|
16 |
+
*
|
17 |
+
* It wasn't easy, but I've managed to get your computer down
|
18 |
+
* to you. This system might be unfamiliar, but the underlying
|
19 |
+
* code is still JavaScript. Just like we predicted.
|
20 |
+
*
|
21 |
+
* Now, let's get what we came here for and then get you out of
|
22 |
+
* here. Easy peasy.
|
23 |
+
*
|
24 |
+
* I've given you as much access to their code as I could, but
|
25 |
+
* it's not perfect. The red background indicates lines that
|
26 |
+
* are off-limits from editing.
|
27 |
+
*
|
28 |
+
* The code currently places blocks in a rectangle surrounding
|
29 |
+
* you. All you need to do is make a gap. You don't even need
|
30 |
+
* to do anything extra. In fact, you should be doing less.
|
31 |
+
*/
|
32 |
+
|
33 |
+
function startLevel(map) {
|
34 |
+
#START_OF_START_LEVEL#
|
35 |
+
map.displayChapter('Chapter 1\nBreakout');
|
36 |
+
|
37 |
+
map.placePlayer(7, 5);
|
38 |
+
#BEGIN_EDITABLE#
|
39 |
+
|
40 |
+
for (var y = 3; y <= map.getHeight() - 10; y++) {
|
41 |
+
map.placeObject(5, y, 'block');
|
42 |
+
map.placeObject(map.getWidth() - 5, y, 'block');
|
43 |
+
}
|
44 |
+
|
45 |
+
for (var x = 5; x <= map.getWidth() - 5; x++) {
|
46 |
+
map.placeObject(x, 3, 'block');
|
47 |
+
map.placeObject(x, map.getHeight() - 10, 'block');
|
48 |
+
}
|
49 |
+
#END_EDITABLE#
|
50 |
+
|
51 |
+
map.placeObject(15, 12, 'computer');
|
52 |
+
|
53 |
+
map.placeObject(map.getWidth()-7, map.getHeight()-5, 'exit');
|
54 |
+
#END_OF_START_LEVEL#
|
55 |
+
}
|
56 |
+
|
57 |
+
function onExit(map) {
|
58 |
+
if (!map.getPlayer().hasItem('computer')) {
|
59 |
+
map.writeStatus("Don't forget to pick up the computer!");
|
60 |
+
return false;
|
61 |
+
} else {
|
62 |
+
return true;
|
63 |
+
}
|
64 |
+
}
|
levels/02_theLongWayOut.jsx
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.2",
|
4 |
+
"commandsIntroduced": ["ROT.Map.DividedMaze", "player.atLocation"],
|
5 |
+
"music": "gurh"
|
6 |
+
}
|
7 |
+
#END_PROPERTIES#
|
8 |
+
/********************
|
9 |
+
* theLongWayOut.js *
|
10 |
+
********************
|
11 |
+
*
|
12 |
+
* Well, it looks like they're on to us. The path isn't as
|
13 |
+
* clear as I thought it'd be. But no matter - four clever
|
14 |
+
* characters should be enough to erase all their tricks.
|
15 |
+
*/
|
16 |
+
|
17 |
+
function startLevel(map) {
|
18 |
+
#START_OF_START_LEVEL#
|
19 |
+
map.placePlayer(7, 5);
|
20 |
+
|
21 |
+
var maze = new ROT.Map.DividedMaze(map.getWidth(), map.getHeight());
|
22 |
+
#BEGIN_EDITABLE#
|
23 |
+
|
24 |
+
#END_EDITABLE#
|
25 |
+
maze.create( function (x, y, mapValue) {
|
26 |
+
|
27 |
+
// don't write maze over player
|
28 |
+
if (map.getPlayer().atLocation(x, y)) {
|
29 |
+
return 0;
|
30 |
+
}
|
31 |
+
|
32 |
+
else if (mapValue === 1) { //0 is empty space 1 is wall
|
33 |
+
map.placeObject(x, y, 'block');
|
34 |
+
}
|
35 |
+
else {
|
36 |
+
map.placeObject(x, y, 'empty');
|
37 |
+
}
|
38 |
+
});
|
39 |
+
|
40 |
+
map.placeObject(map.getWidth()-4, map.getHeight()-4, 'block');
|
41 |
+
map.placeObject(map.getWidth()-6, map.getHeight()-4, 'block');
|
42 |
+
map.placeObject(map.getWidth()-5, map.getHeight()-5, 'block');
|
43 |
+
map.placeObject(map.getWidth()-5, map.getHeight()-3, 'block');
|
44 |
+
#BEGIN_EDITABLE#
|
45 |
+
|
46 |
+
#END_EDITABLE#
|
47 |
+
map.placeObject(map.getWidth()-5, map.getHeight()-4, 'exit');
|
48 |
+
#END_OF_START_LEVEL#
|
49 |
+
}
|
levels/03_validationEngaged.jsx
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.2.1",
|
4 |
+
"commandsIntroduced":
|
5 |
+
["global.validateLevel", "map.validateAtLeastXObjects",
|
6 |
+
"map.validateExactlyXManyObjects"],
|
7 |
+
"music": "Obscure Terrain"
|
8 |
+
}
|
9 |
+
#END_PROPERTIES#
|
10 |
+
/************************
|
11 |
+
* validationEngaged.js *
|
12 |
+
************************
|
13 |
+
*
|
14 |
+
* They're really on to us now! The validateLevel function
|
15 |
+
* has been activated to enforce constraints on what you can
|
16 |
+
* do. In this case, you're not allowed to remove any blocks.
|
17 |
+
*
|
18 |
+
* They're doing all they can to keep you here. But you
|
19 |
+
* can still outsmart them.
|
20 |
+
*/
|
21 |
+
|
22 |
+
function startLevel(map) {
|
23 |
+
#START_OF_START_LEVEL#
|
24 |
+
map.placePlayer(map.getWidth()-7, map.getHeight()-5);
|
25 |
+
#BEGIN_EDITABLE#
|
26 |
+
|
27 |
+
for (var y = 10; y <= map.getHeight() - 3; y++) {
|
28 |
+
map.placeObject(5, y, 'block');
|
29 |
+
map.placeObject(map.getWidth() - 5, y, 'block');
|
30 |
+
}
|
31 |
+
|
32 |
+
for (var x = 5; x <= map.getWidth() - 5; x++) {
|
33 |
+
map.placeObject(x, 10, 'block');
|
34 |
+
map.placeObject(x, map.getHeight() - 3, 'block');
|
35 |
+
}
|
36 |
+
#END_EDITABLE#
|
37 |
+
|
38 |
+
map.placeObject(7, 5, 'exit');
|
39 |
+
#END_OF_START_LEVEL#
|
40 |
+
}
|
41 |
+
|
42 |
+
function validateLevel(map) {
|
43 |
+
var numBlocks = 2 * (map.getHeight()-13) + 2 * (map.getWidth()-10);
|
44 |
+
|
45 |
+
map.validateAtLeastXObjects(numBlocks, 'block');
|
46 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
47 |
+
}
|
levels/04_multiplicity.jsx
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.2.1",
|
4 |
+
"commandsIntroduced": [],
|
5 |
+
"music": "coming soon"
|
6 |
+
}
|
7 |
+
#END_PROPERTIES#
|
8 |
+
/*******************
|
9 |
+
* multiplicity.js *
|
10 |
+
*******************
|
11 |
+
*
|
12 |
+
* Out of one cell and into another. They're not giving you
|
13 |
+
* very much to work with here, either. Ah, well.
|
14 |
+
*
|
15 |
+
* Level filenames can be hints, by the way. Have I
|
16 |
+
* mentioned that before?
|
17 |
+
*
|
18 |
+
* No more cells after this one. I promise.
|
19 |
+
*/
|
20 |
+
|
21 |
+
function startLevel(map) {
|
22 |
+
#START_OF_START_LEVEL#
|
23 |
+
|
24 |
+
map.placePlayer(map.getWidth()-5, map.getHeight()-4);
|
25 |
+
|
26 |
+
for (var y = 7; y <= map.getHeight() - 3; y++) {
|
27 |
+
map.placeObject(7, y, 'block');
|
28 |
+
map.placeObject(map.getWidth() - 3, y, 'block');
|
29 |
+
}
|
30 |
+
#BEGIN_EDITABLE#
|
31 |
+
|
32 |
+
#END_EDITABLE#
|
33 |
+
for (var x = 7; x <= map.getWidth() - 3; x++) {
|
34 |
+
map.placeObject(x, 7, 'block');
|
35 |
+
map.placeObject(x, map.getHeight() - 3, 'block');
|
36 |
+
}
|
37 |
+
|
38 |
+
map.placeObject(map.getWidth() - 5, 5, 'exit');
|
39 |
+
#END_OF_START_LEVEL#
|
40 |
+
}
|
levels/05_minesweeper.jsx
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.2.2",
|
4 |
+
"commandsIntroduced": ["map.setSquareColor"],
|
5 |
+
"music": "cloudy_sin"
|
6 |
+
}
|
7 |
+
#END_PROPERTIES#
|
8 |
+
/******************
|
9 |
+
* minesweeper.js *
|
10 |
+
******************
|
11 |
+
*
|
12 |
+
* So much for Asimov's Laws. They're actually trying to kill
|
13 |
+
* you now. Not to be alarmist, but the floor is littered
|
14 |
+
* with mines. Rushing for the exit blindly may be unwise.
|
15 |
+
* I need you alive, after all.
|
16 |
+
*
|
17 |
+
* If only there was some way you could track the positions
|
18 |
+
* of the mines...
|
19 |
+
*/
|
20 |
+
|
21 |
+
function getRandomInt(min, max) {
|
22 |
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
23 |
+
}
|
24 |
+
|
25 |
+
function startLevel(map) {
|
26 |
+
#START_OF_START_LEVEL#
|
27 |
+
for (var x = 0; x < map.getWidth(); x++) {
|
28 |
+
for (var y = 0; y < map.getHeight(); y++) {
|
29 |
+
map.setSquareColor(x, y, '#f00');
|
30 |
+
}
|
31 |
+
}
|
32 |
+
|
33 |
+
map.placePlayer(map.getWidth() - 5, 5);
|
34 |
+
|
35 |
+
for (var i = 0; i < 75; i++) {
|
36 |
+
var x = getRandomInt(0, map.getWidth() - 1);
|
37 |
+
var y = getRandomInt(0, map.getHeight() - 1);
|
38 |
+
if ((x != 2 || y != map.getHeight() - 1)
|
39 |
+
&& (x != map.getWidth() - 5 || y != 5)) {
|
40 |
+
// don't place mine over exit or player!
|
41 |
+
map.placeObject(x, y, 'mine');
|
42 |
+
#BEGIN_EDITABLE#
|
43 |
+
|
44 |
+
#END_EDITABLE#
|
45 |
+
}
|
46 |
+
}
|
47 |
+
|
48 |
+
map.placeObject(2, map.getHeight() - 1, 'exit');
|
49 |
+
#END_OF_START_LEVEL#
|
50 |
+
}
|
51 |
+
|
52 |
+
function validateLevel(map) {
|
53 |
+
map.validateAtLeastXObjects(40, 'mine');
|
54 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
55 |
+
}
|
levels/06_drones101.jsx
ADDED
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.2",
|
4 |
+
"commandsIntroduced":
|
5 |
+
["object.type", "object.behavior", "object.findNearest",
|
6 |
+
"object.getX", "object.getY", "object.canMove", "object.move"],
|
7 |
+
"music": "GameScratch"
|
8 |
+
}
|
9 |
+
#END_PROPERTIES#
|
10 |
+
|
11 |
+
/****************
|
12 |
+
* drones101.js *
|
13 |
+
****************
|
14 |
+
*
|
15 |
+
* Do you remember, my dear Professor, a certain introductory
|
16 |
+
* computational rationality class you taught long ago? Assignment
|
17 |
+
* #2, behavior functions of autonomous agents? I remember that one
|
18 |
+
* fondly - but attack drones are so much easier to reason about
|
19 |
+
* when they're not staring you in the face, I would imagine!
|
20 |
+
*/
|
21 |
+
|
22 |
+
function startLevel(map) {
|
23 |
+
#START_OF_START_LEVEL#
|
24 |
+
function moveToward(obj, type) {
|
25 |
+
var target = obj.findNearest(type);
|
26 |
+
var leftDist = obj.getX() - target.x;
|
27 |
+
var upDist = obj.getY() - target.y;
|
28 |
+
|
29 |
+
var direction;
|
30 |
+
if (upDist == 0 && leftDist == 0) {
|
31 |
+
return;
|
32 |
+
} if (upDist > 0 && upDist >= leftDist) {
|
33 |
+
direction = 'up';
|
34 |
+
} else if (upDist < 0 && upDist < leftDist) {
|
35 |
+
direction = 'down';
|
36 |
+
} else if (leftDist > 0 && leftDist >= upDist) {
|
37 |
+
direction = 'left';
|
38 |
+
} else {
|
39 |
+
direction = 'right';
|
40 |
+
}
|
41 |
+
|
42 |
+
if (obj.canMove(direction)) {
|
43 |
+
obj.move(direction);
|
44 |
+
}
|
45 |
+
}
|
46 |
+
|
47 |
+
map.defineObject('attackDrone', {
|
48 |
+
'type': 'dynamic',
|
49 |
+
'symbol': 'd',
|
50 |
+
'color': 'red',
|
51 |
+
'onCollision': function (player) {
|
52 |
+
player.killedBy('an attack drone');
|
53 |
+
},
|
54 |
+
'behavior': function (me) {
|
55 |
+
moveToward(me, 'player');
|
56 |
+
}
|
57 |
+
});
|
58 |
+
|
59 |
+
|
60 |
+
map.placePlayer(1, 1);
|
61 |
+
map.placeObject(map.getWidth()-2, 12, 'attackDrone');
|
62 |
+
map.placeObject(map.getWidth()-1, 12, 'exit');
|
63 |
+
|
64 |
+
map.placeObject(map.getWidth()-1, 11, 'block');
|
65 |
+
map.placeObject(map.getWidth()-2, 11, 'block');
|
66 |
+
map.placeObject(map.getWidth()-1, 13, 'block');
|
67 |
+
map.placeObject(map.getWidth()-2, 13, 'block');
|
68 |
+
#BEGIN_EDITABLE#
|
69 |
+
|
70 |
+
|
71 |
+
|
72 |
+
|
73 |
+
#END_EDITABLE#
|
74 |
+
#END_OF_START_LEVEL#
|
75 |
+
}
|
76 |
+
|
77 |
+
function validateLevel(map) {
|
78 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
79 |
+
}
|
levels/07_colors.jsx
ADDED
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.2",
|
4 |
+
"commandsIntroduced":
|
5 |
+
["map.defineObject", "player.getColor", "player.setColor",
|
6 |
+
"object.color", "object.impassable", "object.symbol",
|
7 |
+
"player.setPhoneCallback"],
|
8 |
+
"music": "Y"
|
9 |
+
}
|
10 |
+
#END_PROPERTIES#
|
11 |
+
/*************
|
12 |
+
* colors.js *
|
13 |
+
*************
|
14 |
+
*
|
15 |
+
* You're almost at the exit. You just need to get past this
|
16 |
+
* color lock.
|
17 |
+
*
|
18 |
+
* Changing your environment is no longer enough. You must
|
19 |
+
* learn to change yourself. I've sent you a little something
|
20 |
+
* that should help with that.
|
21 |
+
*/
|
22 |
+
|
23 |
+
function startLevel(map) {
|
24 |
+
#START_OF_START_LEVEL#
|
25 |
+
map.placePlayer(0, 12);
|
26 |
+
|
27 |
+
map.placeObject(5, 12, 'phone');
|
28 |
+
|
29 |
+
// The function phone lets you call arbitrary functions,
|
30 |
+
// as defined by player.setPhoneCallback() below.
|
31 |
+
// The function phone callback is bound to Q or Ctrl-6.
|
32 |
+
map.getPlayer().setPhoneCallback(function () {
|
33 |
+
#BEGIN_EDITABLE#
|
34 |
+
var player = map.getPlayer();
|
35 |
+
|
36 |
+
player.setColor('#f00');
|
37 |
+
|
38 |
+
|
39 |
+
|
40 |
+
|
41 |
+
|
42 |
+
#END_EDITABLE#
|
43 |
+
});
|
44 |
+
|
45 |
+
|
46 |
+
map.defineObject('redLock', {
|
47 |
+
symbol: '☒',
|
48 |
+
color: "#f00", // red
|
49 |
+
impassable: function(player, object) {
|
50 |
+
return player.getColor() != object.color;
|
51 |
+
}
|
52 |
+
});
|
53 |
+
|
54 |
+
map.defineObject('greenLock', {
|
55 |
+
symbol: '☒',
|
56 |
+
color: "#0f0", // green
|
57 |
+
impassable: function(player, object) {
|
58 |
+
return player.getColor() != object.color;
|
59 |
+
}
|
60 |
+
});
|
61 |
+
|
62 |
+
map.defineObject('yellowLock', {
|
63 |
+
symbol: '☒',
|
64 |
+
color: "#ff0", // yellow
|
65 |
+
impassable: function(player, object) {
|
66 |
+
return player.getColor() != object.color;
|
67 |
+
}
|
68 |
+
});
|
69 |
+
|
70 |
+
for (var x = 20; x <= 40; x++) {
|
71 |
+
map.placeObject(x, 11, 'block');
|
72 |
+
map.placeObject(x, 13, 'block');
|
73 |
+
}
|
74 |
+
map.placeObject(22, 12, 'greenLock');
|
75 |
+
map.placeObject(25, 12, 'redLock');
|
76 |
+
map.placeObject(28, 12, 'yellowLock');
|
77 |
+
map.placeObject(31, 12, 'greenLock');
|
78 |
+
map.placeObject(34, 12, 'redLock');
|
79 |
+
map.placeObject(37, 12, 'yellowLock');
|
80 |
+
map.placeObject(40, 12, 'exit');
|
81 |
+
for (var y = 0; y < map.getHeight(); y++) {
|
82 |
+
if (y != 12) {
|
83 |
+
map.placeObject(40, y, 'block');
|
84 |
+
}
|
85 |
+
for (var x = 41; x < map.getWidth(); x++) {
|
86 |
+
map.setSquareColor(x, y, '#080');
|
87 |
+
}
|
88 |
+
}
|
89 |
+
#END_OF_START_LEVEL#
|
90 |
+
}
|
91 |
+
|
92 |
+
function validateLevel(map) {
|
93 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
94 |
+
}
|
95 |
+
|
96 |
+
function onExit(map) {
|
97 |
+
if (!map.getPlayer().hasItem('phone')) {
|
98 |
+
map.writeStatus("We need the phone!");
|
99 |
+
return false;
|
100 |
+
} else {
|
101 |
+
return true;
|
102 |
+
}
|
103 |
+
}
|
levels/08_intoTheWoods.jsx
ADDED
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.2",
|
4 |
+
"commandsIntroduced":
|
5 |
+
["map.getObjectTypeAt", "player.getX", "player.getY",
|
6 |
+
"map.refresh"],
|
7 |
+
"mapProperties": {
|
8 |
+
"allowOverwrite": true
|
9 |
+
},
|
10 |
+
"music": "Night Owl"
|
11 |
+
}
|
12 |
+
#END_PROPERTIES#
|
13 |
+
/*******************
|
14 |
+
* intoTheWoods.js *
|
15 |
+
*******************
|
16 |
+
*
|
17 |
+
* Ah, you're out of the woods now. Or into the woods, as the
|
18 |
+
* case may be.
|
19 |
+
*
|
20 |
+
* So take a deep breath, relax, and remember what you're here
|
21 |
+
* for in the first place.
|
22 |
+
*
|
23 |
+
* I've traced its signal and the Algorithm is nearby. You'll
|
24 |
+
* need to go through the forest and across the river, and
|
25 |
+
* you'll reach the fortress where it's kept. Their defences
|
26 |
+
* are light, and we should be able to catch them off-guard.
|
27 |
+
*/
|
28 |
+
|
29 |
+
function startLevel(map) {
|
30 |
+
#START_OF_START_LEVEL#
|
31 |
+
// NOTE: In this level alone, map.placeObject is allowed to
|
32 |
+
//overwrite existing objects.
|
33 |
+
|
34 |
+
map.displayChapter('Chapter 2\nRaiders of the Lost Algorithm');
|
35 |
+
|
36 |
+
map.placePlayer(2, map.getHeight() - 1);
|
37 |
+
|
38 |
+
var functionList = {};
|
39 |
+
|
40 |
+
functionList['fortresses'] = function () {
|
41 |
+
function genRandomValue(direction) {
|
42 |
+
if (direction === "height") {
|
43 |
+
return Math.floor(Math.random() * (map.getHeight()-3));
|
44 |
+
} else if (direction === "width") {
|
45 |
+
return Math.floor(Math.random() * (map.getWidth()+1));
|
46 |
+
}
|
47 |
+
}
|
48 |
+
|
49 |
+
var x = genRandomValue("width");
|
50 |
+
var y = genRandomValue("height");
|
51 |
+
|
52 |
+
for (var i = x-2; i < x+2; i++) {
|
53 |
+
map.placeObject(i,y-2, 'block');
|
54 |
+
}
|
55 |
+
for (var i = x-2; i < x+2; i++) {
|
56 |
+
map.placeObject(i,y+2, 'block');
|
57 |
+
}
|
58 |
+
|
59 |
+
for (var j = y-2; j < y+2; j++) {
|
60 |
+
map.placeObject(x-2,j, 'block');
|
61 |
+
}
|
62 |
+
|
63 |
+
for (var j = y-2; j < y+2; j++) {
|
64 |
+
map.placeObject(x+2,j, 'block');
|
65 |
+
}
|
66 |
+
};
|
67 |
+
|
68 |
+
functionList['generateForest'] = function () {
|
69 |
+
for (var i = 0; i < map.getWidth(); i++) {
|
70 |
+
for (var j = 0; j < map.getHeight(); j++) {
|
71 |
+
|
72 |
+
// initialize to empty if the square contains a forest already
|
73 |
+
if (map.getObjectTypeAt(i, j) === 'tree') {
|
74 |
+
// remove existing forest
|
75 |
+
map.placeObject(i,j, 'empty');
|
76 |
+
}
|
77 |
+
|
78 |
+
if (map.getPlayer().atLocation(i,j) ||
|
79 |
+
map.getObjectTypeAt(i, j) === 'block' ||
|
80 |
+
map.getObjectTypeAt(i, j) === 'exit') {
|
81 |
+
continue;
|
82 |
+
}
|
83 |
+
|
84 |
+
var rv = Math.random();
|
85 |
+
if (rv < 0.45) {
|
86 |
+
map.placeObject(i, j, 'tree');
|
87 |
+
}
|
88 |
+
}
|
89 |
+
}
|
90 |
+
map.refresh();
|
91 |
+
};
|
92 |
+
|
93 |
+
functionList['movePlayerToExit'] = function () {
|
94 |
+
map.writeStatus("Permission denied.");
|
95 |
+
}
|
96 |
+
|
97 |
+
functionList['pleaseMovePlayerToExit'] = function () {
|
98 |
+
map.writeStatus("I don't think so.");
|
99 |
+
}
|
100 |
+
|
101 |
+
functionList['movePlayerToExitDamnit'] = function () {
|
102 |
+
map.writeStatus("So, how 'bout them <LOCAL SPORTS TEAM>?");
|
103 |
+
}
|
104 |
+
|
105 |
+
// generate forest
|
106 |
+
functionList['generateForest']();
|
107 |
+
|
108 |
+
// generate fortresses
|
109 |
+
functionList['fortresses']();
|
110 |
+
functionList['fortresses']();
|
111 |
+
functionList['fortresses']();
|
112 |
+
functionList['fortresses']();
|
113 |
+
|
114 |
+
map.getPlayer().setPhoneCallback(functionList[#{#"movePlayerToExit"#}#]);
|
115 |
+
|
116 |
+
map.placeObject(map.getWidth()-1, map.getHeight()-1, 'exit');
|
117 |
+
#END_OF_START_LEVEL#
|
118 |
+
}
|
119 |
+
|
120 |
+
function validateLevel(map) {
|
121 |
+
map.validateAtLeastXObjects(100, 'tree');
|
122 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
123 |
+
}
|
levels/09_fordingTheRiver.jsx
ADDED
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.2",
|
4 |
+
"commandsIntroduced":
|
5 |
+
["player.killedBy", "object.onCollision"],
|
6 |
+
"music": "The_Waves_Call_Her_Name"
|
7 |
+
}
|
8 |
+
#END_PROPERTIES#
|
9 |
+
/**********************
|
10 |
+
* fordingTheRiver.js *
|
11 |
+
**********************
|
12 |
+
*
|
13 |
+
* And there's the river. Fortunately, I was prepared for this.
|
14 |
+
* See the raft on the other side?
|
15 |
+
*
|
16 |
+
* Everything is going according to plan.
|
17 |
+
*/
|
18 |
+
|
19 |
+
function startLevel(map) {
|
20 |
+
#START_OF_START_LEVEL#
|
21 |
+
var raftDirection = 'down';
|
22 |
+
|
23 |
+
map.placePlayer(map.getWidth()-1, map.getHeight()-1);
|
24 |
+
var player = map.getPlayer();
|
25 |
+
|
26 |
+
map.defineObject('raft', {
|
27 |
+
'type': 'dynamic',
|
28 |
+
'symbol': '▓',
|
29 |
+
'color': '#420',
|
30 |
+
'transport': true, // (prevents player from drowning in water)
|
31 |
+
'behavior': function (me) {
|
32 |
+
me.move(raftDirection);
|
33 |
+
}
|
34 |
+
});
|
35 |
+
|
36 |
+
map.defineObject('water', {
|
37 |
+
'symbol': '░',
|
38 |
+
'color': '#44f',
|
39 |
+
'onCollision': function (player) {
|
40 |
+
player.killedBy('drowning in deep dark water');
|
41 |
+
}
|
42 |
+
});
|
43 |
+
|
44 |
+
for (var x = 0; x < map.getWidth(); x++) {
|
45 |
+
for (var y = 5; y < 15; y++) {
|
46 |
+
map.placeObject(x, y, 'water');
|
47 |
+
}
|
48 |
+
}
|
49 |
+
|
50 |
+
map.placeObject(20, 5, 'raft');
|
51 |
+
map.placeObject(0, 2, 'exit');
|
52 |
+
map.placeObject(0, 1, 'block');
|
53 |
+
map.placeObject(1, 1, 'block');
|
54 |
+
map.placeObject(0, 3, 'block');
|
55 |
+
map.placeObject(1, 3, 'block');
|
56 |
+
|
57 |
+
#BEGIN_EDITABLE#
|
58 |
+
|
59 |
+
|
60 |
+
|
61 |
+
#END_EDITABLE#
|
62 |
+
#END_OF_START_LEVEL#
|
63 |
+
}
|
64 |
+
|
65 |
+
function validateLevel(map) {
|
66 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
67 |
+
map.validateExactlyXManyObjects(1, 'raft');
|
68 |
+
}
|
levels/10_ambush.jsx
ADDED
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.2",
|
4 |
+
"commandsIntroduced": [],
|
5 |
+
"music": "Come and Find Me"
|
6 |
+
}
|
7 |
+
#END_PROPERTIES#
|
8 |
+
/*************
|
9 |
+
* ambush.js *
|
10 |
+
*************
|
11 |
+
*
|
12 |
+
* Oh. Oh, I see. This wasn't quite part of the plan.
|
13 |
+
*
|
14 |
+
* Looks like they won't let you take the Algorithm
|
15 |
+
* without a fight. You'll need to carefully weave your
|
16 |
+
* way through the guard drones.
|
17 |
+
*
|
18 |
+
* Well, time to improvise. Let's mess with their programming
|
19 |
+
* a little, shall we?
|
20 |
+
*/
|
21 |
+
|
22 |
+
function startLevel(map) {
|
23 |
+
#START_OF_START_LEVEL#
|
24 |
+
function moveToward(obj, type) {
|
25 |
+
var target = obj.findNearest(type);
|
26 |
+
var leftDist = obj.getX() - target.x;
|
27 |
+
var upDist = obj.getY() - target.y;
|
28 |
+
|
29 |
+
var direction;
|
30 |
+
if (upDist == 0 && leftDist == 0) {
|
31 |
+
return;
|
32 |
+
} if (upDist > 0 && upDist >= leftDist) {
|
33 |
+
direction = 'up';
|
34 |
+
} else if (upDist < 0 && upDist < leftDist) {
|
35 |
+
direction = 'down';
|
36 |
+
} else if (leftDist > 0 && leftDist >= upDist) {
|
37 |
+
direction = 'left';
|
38 |
+
} else {
|
39 |
+
direction = 'right';
|
40 |
+
}
|
41 |
+
|
42 |
+
if (obj.canMove(direction)) {
|
43 |
+
obj.move(direction);
|
44 |
+
}
|
45 |
+
}
|
46 |
+
|
47 |
+
map.defineObject('attackDrone', {
|
48 |
+
'type': 'dynamic',
|
49 |
+
'symbol': 'd',
|
50 |
+
'color': 'red',
|
51 |
+
'onCollision': function (player) {
|
52 |
+
player.killedBy('an attack drone');
|
53 |
+
},
|
54 |
+
'behavior': function (me) {
|
55 |
+
#BEGIN_EDITABLE#
|
56 |
+
moveToward(me, 'player');
|
57 |
+
#END_EDITABLE#
|
58 |
+
}
|
59 |
+
});
|
60 |
+
|
61 |
+
map.defineObject('reinforcementDrone', {
|
62 |
+
'type': 'dynamic',
|
63 |
+
'symbol': 'd',
|
64 |
+
'color': 'yellow',
|
65 |
+
'onCollision': function (player) {
|
66 |
+
player.killedBy('a reinforcement drone');
|
67 |
+
},
|
68 |
+
'behavior': function (me) {
|
69 |
+
#BEGIN_EDITABLE#
|
70 |
+
me.move('left');
|
71 |
+
#END_EDITABLE#
|
72 |
+
}
|
73 |
+
});
|
74 |
+
|
75 |
+
map.defineObject('defenseDrone', {
|
76 |
+
'type': 'dynamic',
|
77 |
+
'symbol': 'd',
|
78 |
+
'color': 'green',
|
79 |
+
'onCollision': function (player) {
|
80 |
+
player.killedBy('a defense drone');
|
81 |
+
},
|
82 |
+
'behavior': function (me) {
|
83 |
+
#BEGIN_EDITABLE#
|
84 |
+
|
85 |
+
#END_EDITABLE#
|
86 |
+
}
|
87 |
+
});
|
88 |
+
|
89 |
+
// just for decoration
|
90 |
+
map.defineObject('water', {
|
91 |
+
'symbol': '░',
|
92 |
+
'color': '#44f'
|
93 |
+
});
|
94 |
+
|
95 |
+
map.placePlayer(0, 12);
|
96 |
+
|
97 |
+
for (var x = 0; x < map.getWidth(); x++) {
|
98 |
+
map.placeObject(x, 10, 'block');
|
99 |
+
map.placeObject(x, 14, 'block');
|
100 |
+
|
101 |
+
for (var y = 20; y < map.getHeight(); y++) {
|
102 |
+
map.placeObject(x, y, 'water');
|
103 |
+
}
|
104 |
+
}
|
105 |
+
|
106 |
+
map.placeObject(23, 11, 'attackDrone');
|
107 |
+
map.placeObject(23, 12, 'attackDrone');
|
108 |
+
map.placeObject(23, 13, 'attackDrone');
|
109 |
+
|
110 |
+
map.placeObject(27, 11, 'defenseDrone');
|
111 |
+
map.placeObject(27, 12, 'defenseDrone');
|
112 |
+
map.placeObject(27, 13, 'defenseDrone');
|
113 |
+
|
114 |
+
map.placeObject(24, 11, 'reinforcementDrone');
|
115 |
+
map.placeObject(25, 11, 'reinforcementDrone');
|
116 |
+
map.placeObject(26, 11, 'reinforcementDrone');
|
117 |
+
map.placeObject(24, 13, 'reinforcementDrone');
|
118 |
+
map.placeObject(25, 13, 'reinforcementDrone');
|
119 |
+
map.placeObject(26, 13, 'reinforcementDrone');
|
120 |
+
|
121 |
+
map.placeObject(map.getWidth()-1, 12, 'exit');
|
122 |
+
#END_OF_START_LEVEL#
|
123 |
+
}
|
124 |
+
|
125 |
+
function validateLevel(map) {
|
126 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
127 |
+
}
|
levels/11_robot.jsx
ADDED
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.2",
|
4 |
+
"commandsIntroduced":
|
5 |
+
["object.giveItemTo", "object.passableFor",
|
6 |
+
"map.validateAtMostXObjects"],
|
7 |
+
"music": "conspiracy"
|
8 |
+
}
|
9 |
+
#END_PROPERTIES#
|
10 |
+
/*
|
11 |
+
* robot.js
|
12 |
+
*
|
13 |
+
* You'll need three keys in order to unlock the
|
14 |
+
* Algorithm: the red key, the green key, and the
|
15 |
+
* blue key. Unfortunately, all three of them are
|
16 |
+
* behind human-proof barriers.
|
17 |
+
*
|
18 |
+
* The plan is simple: reprogram the maintenance
|
19 |
+
* robots to grab the key and bring it through
|
20 |
+
* the barrier to us.
|
21 |
+
*
|
22 |
+
* Let's try it on the red key first.
|
23 |
+
*/
|
24 |
+
|
25 |
+
function getRandomInt(min, max) {
|
26 |
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
27 |
+
}
|
28 |
+
|
29 |
+
function startLevel(map) {
|
30 |
+
#START_OF_START_LEVEL#
|
31 |
+
// Hint: you can press R or 5 to "rest" and not move the
|
32 |
+
// player, while the robot moves around.
|
33 |
+
|
34 |
+
map.placePlayer(map.getWidth()-2, map.getHeight()-2);
|
35 |
+
var player = map.getPlayer();
|
36 |
+
|
37 |
+
map.defineObject('robot', {
|
38 |
+
'type': 'dynamic',
|
39 |
+
'symbol': 'R',
|
40 |
+
'color': 'gray',
|
41 |
+
'onCollision': function (player, me) {
|
42 |
+
me.giveItemTo(player, 'redKey');
|
43 |
+
},
|
44 |
+
'behavior': function (me) {
|
45 |
+
#BEGIN_EDITABLE#
|
46 |
+
// Available commands: me.move(direction)
|
47 |
+
// and me.canMove(direction)
|
48 |
+
|
49 |
+
|
50 |
+
|
51 |
+
#END_EDITABLE#
|
52 |
+
}
|
53 |
+
});
|
54 |
+
|
55 |
+
map.defineObject('barrier', {
|
56 |
+
'symbol': '░',
|
57 |
+
'color': 'purple',
|
58 |
+
'impassable': true,
|
59 |
+
'passableFor': ['robot']
|
60 |
+
});
|
61 |
+
|
62 |
+
map.placeObject(0, map.getHeight() - 1, 'exit');
|
63 |
+
map.placeObject(1, 1, 'robot');
|
64 |
+
map.placeObject(map.getWidth() - 2, 8, 'redKey');
|
65 |
+
map.placeObject(map.getWidth() - 2, 9, 'barrier');
|
66 |
+
|
67 |
+
for (var x = 0; x < map.getWidth(); x++) {
|
68 |
+
map.placeObject(x, 0, 'block');
|
69 |
+
if (x != map.getWidth() - 2) {
|
70 |
+
map.placeObject(x, 9, 'block');
|
71 |
+
}
|
72 |
+
}
|
73 |
+
|
74 |
+
for (var y = 1; y < 9; y++) {
|
75 |
+
map.placeObject(0, y, 'block');
|
76 |
+
map.placeObject(map.getWidth() - 1, y, 'block');
|
77 |
+
}
|
78 |
+
#END_OF_START_LEVEL#
|
79 |
+
}
|
80 |
+
|
81 |
+
function validateLevel(map) {
|
82 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
83 |
+
map.validateExactlyXManyObjects(1, 'robot');
|
84 |
+
map.validateAtMostXObjects(1, 'redKey');
|
85 |
+
}
|
86 |
+
|
87 |
+
function onExit(map) {
|
88 |
+
if (!map.getPlayer().hasItem('redKey')) {
|
89 |
+
map.writeStatus("We need to get that key!");
|
90 |
+
return false;
|
91 |
+
} else {
|
92 |
+
return true;
|
93 |
+
}
|
94 |
+
}
|
levels/12_robotNav.jsx
ADDED
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.2",
|
4 |
+
"commandsIntroduced": [],
|
5 |
+
"music": "Messeah"
|
6 |
+
}
|
7 |
+
#END_PROPERTIES#
|
8 |
+
/*
|
9 |
+
* robotNav.js
|
10 |
+
*
|
11 |
+
* The green key is located in a slightly more
|
12 |
+
* complicated room. You'll need to get the robot
|
13 |
+
* past these obstacles.
|
14 |
+
*/
|
15 |
+
|
16 |
+
function startLevel(map) {
|
17 |
+
#START_OF_START_LEVEL#
|
18 |
+
// Hint: you can press R or 5 to "rest" and not move the
|
19 |
+
// player, while the robot moves around.
|
20 |
+
|
21 |
+
map.placePlayer(0, map.getHeight() - 1);
|
22 |
+
var player = map.getPlayer();
|
23 |
+
|
24 |
+
map.defineObject('robot', {
|
25 |
+
'type': 'dynamic',
|
26 |
+
'symbol': 'R',
|
27 |
+
'color': 'gray',
|
28 |
+
'onCollision': function (player, me) {
|
29 |
+
me.giveItemTo(player, 'greenKey');
|
30 |
+
},
|
31 |
+
'behavior': function (me) {
|
32 |
+
#BEGIN_EDITABLE#
|
33 |
+
if (me.canMove('right')) {
|
34 |
+
me.move('right');
|
35 |
+
} else {
|
36 |
+
me.move('down');
|
37 |
+
}
|
38 |
+
|
39 |
+
|
40 |
+
|
41 |
+
|
42 |
+
|
43 |
+
|
44 |
+
|
45 |
+
|
46 |
+
|
47 |
+
|
48 |
+
|
49 |
+
#END_EDITABLE#
|
50 |
+
}
|
51 |
+
});
|
52 |
+
|
53 |
+
map.defineObject('barrier', {
|
54 |
+
'symbol': '░',
|
55 |
+
'color': 'purple',
|
56 |
+
'impassable': true,
|
57 |
+
'passableFor': ['robot']
|
58 |
+
});
|
59 |
+
|
60 |
+
map.placeObject(map.getWidth() - 1, map.getHeight() - 1, 'exit');
|
61 |
+
map.placeObject(1, 1, 'robot');
|
62 |
+
map.placeObject(map.getWidth() - 2, 8, 'greenKey');
|
63 |
+
map.placeObject(map.getWidth() - 2, 9, 'barrier');
|
64 |
+
|
65 |
+
for (var x = 0; x < map.getWidth(); x++) {
|
66 |
+
map.placeObject(x, 0, 'block');
|
67 |
+
if (x != map.getWidth() - 2) {
|
68 |
+
map.placeObject(x, 9, 'block');
|
69 |
+
}
|
70 |
+
}
|
71 |
+
|
72 |
+
for (var y = 1; y < 9; y++) {
|
73 |
+
map.placeObject(0, y, 'block');
|
74 |
+
map.placeObject(map.getWidth() - 1, y, 'block');
|
75 |
+
}
|
76 |
+
|
77 |
+
for (var i = 0; i < 4; i++) {
|
78 |
+
map.placeObject(20 - i, i + 1, 'block');
|
79 |
+
map.placeObject(35 - i, 8 - i, 'block');
|
80 |
+
}
|
81 |
+
#END_OF_START_LEVEL#
|
82 |
+
}
|
83 |
+
|
84 |
+
function validateLevel(map) {
|
85 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
86 |
+
map.validateExactlyXManyObjects(1, 'robot');
|
87 |
+
map.validateAtMostXObjects(1, 'greenKey');
|
88 |
+
}
|
89 |
+
|
90 |
+
function onExit(map) {
|
91 |
+
if (!map.getPlayer().hasItem('greenKey')) {
|
92 |
+
map.writeStatus("We need to get that key!");
|
93 |
+
return false;
|
94 |
+
} else {
|
95 |
+
return true;
|
96 |
+
}
|
97 |
+
}
|
levels/13_robotMaze.jsx
ADDED
@@ -0,0 +1,131 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.2",
|
4 |
+
"commandsIntroduced": ["map.getAdjacentEmptyCells"],
|
5 |
+
"music": "Searching"
|
6 |
+
}
|
7 |
+
#END_PROPERTIES#
|
8 |
+
/*
|
9 |
+
* robotMaze.js
|
10 |
+
*
|
11 |
+
* The blue key is inside a labyrinth, and extracting
|
12 |
+
* it will not be easy.
|
13 |
+
*
|
14 |
+
* It's a good thing that you're a AI expert, or
|
15 |
+
* we would have to leave empty-handed.
|
16 |
+
*/
|
17 |
+
|
18 |
+
function startLevel(map) {
|
19 |
+
#START_OF_START_LEVEL#
|
20 |
+
// Hint: you can press R or 5 to "rest" and not move the
|
21 |
+
// player, while the robot moves around.
|
22 |
+
|
23 |
+
map.getRandomInt = function(min, max) {
|
24 |
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
25 |
+
}
|
26 |
+
|
27 |
+
map.placePlayer(map.getWidth()-1, map.getHeight()-1);
|
28 |
+
var player = map.getPlayer();
|
29 |
+
|
30 |
+
map.defineObject('robot', {
|
31 |
+
'type': 'dynamic',
|
32 |
+
'symbol': 'R',
|
33 |
+
'color': 'gray',
|
34 |
+
'onCollision': function (player, me) {
|
35 |
+
me.giveItemTo(player, 'blueKey');
|
36 |
+
},
|
37 |
+
'behavior': function (me) {
|
38 |
+
#BEGIN_EDITABLE#
|
39 |
+
// move randomly
|
40 |
+
var moves = map.getAdjacentEmptyCells(me.getX(), me.getY());
|
41 |
+
// getAdjacentEmptyCells gives array of ((x, y), direction) pairs
|
42 |
+
me.move(moves[map.getRandomInt(0, moves.length - 1)][1]);
|
43 |
+
|
44 |
+
|
45 |
+
|
46 |
+
|
47 |
+
|
48 |
+
|
49 |
+
|
50 |
+
|
51 |
+
|
52 |
+
|
53 |
+
|
54 |
+
|
55 |
+
|
56 |
+
|
57 |
+
|
58 |
+
|
59 |
+
|
60 |
+
|
61 |
+
|
62 |
+
|
63 |
+
|
64 |
+
|
65 |
+
|
66 |
+
|
67 |
+
|
68 |
+
|
69 |
+
|
70 |
+
|
71 |
+
|
72 |
+
|
73 |
+
|
74 |
+
|
75 |
+
|
76 |
+
|
77 |
+
|
78 |
+
|
79 |
+
|
80 |
+
|
81 |
+
|
82 |
+
|
83 |
+
|
84 |
+
|
85 |
+
|
86 |
+
|
87 |
+
|
88 |
+
#END_EDITABLE#
|
89 |
+
}
|
90 |
+
});
|
91 |
+
|
92 |
+
map.defineObject('barrier', {
|
93 |
+
'symbol': '░',
|
94 |
+
'color': 'purple',
|
95 |
+
'impassable': true,
|
96 |
+
'passableFor': ['robot']
|
97 |
+
});
|
98 |
+
|
99 |
+
map.placeObject(0, map.getHeight() - 1, 'exit');
|
100 |
+
map.placeObject(1, 1, 'robot');
|
101 |
+
map.placeObject(map.getWidth() - 2, 8, 'blueKey');
|
102 |
+
map.placeObject(map.getWidth() - 2, 9, 'barrier');
|
103 |
+
|
104 |
+
var autoGeneratedMaze = new ROT.Map.DividedMaze(map.getWidth(), 10);
|
105 |
+
autoGeneratedMaze.create( function (x, y, mapValue) {
|
106 |
+
// don't write maze over robot or barrier
|
107 |
+
if ((x == 1 && y == 1) || (x == map.getWidth() - 2 && y >= 8)) {
|
108 |
+
return 0;
|
109 |
+
} else if (mapValue === 1) { //0 is empty space 1 is wall
|
110 |
+
map.placeObject(x,y, 'block');
|
111 |
+
} else {
|
112 |
+
map.placeObject(x,y,'empty');
|
113 |
+
}
|
114 |
+
});
|
115 |
+
#END_OF_START_LEVEL#
|
116 |
+
}
|
117 |
+
|
118 |
+
function validateLevel(map) {
|
119 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
120 |
+
map.validateExactlyXManyObjects(1, 'robot');
|
121 |
+
map.validateAtMostXObjects(1, 'blueKey');
|
122 |
+
}
|
123 |
+
|
124 |
+
function onExit(map) {
|
125 |
+
if (!map.getPlayer().hasItem('blueKey')) {
|
126 |
+
map.writeStatus("We need to get that key!");
|
127 |
+
return false;
|
128 |
+
} else {
|
129 |
+
return true;
|
130 |
+
}
|
131 |
+
}
|
levels/14_crispsContest.jsx
ADDED
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.2",
|
4 |
+
"commandsIntroduced":
|
5 |
+
["map.createFromGrid", "player.removeItem"],
|
6 |
+
"music": "Chip"
|
7 |
+
}
|
8 |
+
#END_PROPERTIES#
|
9 |
+
/********************
|
10 |
+
* crispsContest.js *
|
11 |
+
********************
|
12 |
+
*
|
13 |
+
* The Algorithm is almost in our grasp!
|
14 |
+
* At long last, we will definitively establish
|
15 |
+
* that 3SAT is solvable in polynomial time. It's
|
16 |
+
* been a long, strange journey, but it will all be
|
17 |
+
* worth it.
|
18 |
+
*
|
19 |
+
* You have the red, green, and blue keys. Now you
|
20 |
+
* just need to figure out how to unlock this thing.
|
21 |
+
*/
|
22 |
+
|
23 |
+
function startLevel(map) {
|
24 |
+
#START_OF_START_LEVEL#
|
25 |
+
map.defineObject('redLock', {
|
26 |
+
'symbol': String.fromCharCode(0x2297),
|
27 |
+
'color': 'red',
|
28 |
+
'impassable': function (player) {
|
29 |
+
if (player.hasItem('redKey')) {
|
30 |
+
player.removeItem('redKey');
|
31 |
+
return false;
|
32 |
+
} else {
|
33 |
+
return true;
|
34 |
+
}
|
35 |
+
}
|
36 |
+
});
|
37 |
+
|
38 |
+
map.defineObject('blueLock', {
|
39 |
+
'symbol': String.fromCharCode(0x2297),
|
40 |
+
'color': '#06f',
|
41 |
+
'impassable': function (player) {
|
42 |
+
if (player.hasItem('blueKey')) {
|
43 |
+
player.removeItem('blueKey');
|
44 |
+
return false;
|
45 |
+
} else {
|
46 |
+
return true;
|
47 |
+
}
|
48 |
+
}
|
49 |
+
});
|
50 |
+
|
51 |
+
map.defineObject('greenLock', {
|
52 |
+
'symbol': String.fromCharCode(0x2297),
|
53 |
+
'color': '#0f0',
|
54 |
+
'impassable': function (player) {
|
55 |
+
if (player.hasItem('greenKey')) {
|
56 |
+
player.removeItem(#{#'greenKey'#}#);
|
57 |
+
return false;
|
58 |
+
} else {
|
59 |
+
return true;
|
60 |
+
}
|
61 |
+
}
|
62 |
+
});
|
63 |
+
|
64 |
+
map.defineObject('yellowLock', {
|
65 |
+
'symbol': String.fromCharCode(0x2297),
|
66 |
+
'color': 'yellow',
|
67 |
+
'impassable': function (player) {
|
68 |
+
if (player.hasItem('yellowKey')) {
|
69 |
+
player.removeItem('yellowKey');
|
70 |
+
return false;
|
71 |
+
} else {
|
72 |
+
return true;
|
73 |
+
}
|
74 |
+
}
|
75 |
+
});
|
76 |
+
|
77 |
+
map.createFromGrid(
|
78 |
+
[' +++++ +++++ ',
|
79 |
+
' + b +++ r + ',
|
80 |
+
' + +E+ + ',
|
81 |
+
'+++G+B+ +R+G+++',
|
82 |
+
'+ y B R b +',
|
83 |
+
'+ + + +',
|
84 |
+
'+++++ @ +++++',
|
85 |
+
'+ + + +',
|
86 |
+
'+ y R B y +',
|
87 |
+
'++++++Y+Y++++++',
|
88 |
+
' + + + ',
|
89 |
+
' + ABy + ',
|
90 |
+
' +++++++ '],
|
91 |
+
{
|
92 |
+
'@': 'player',
|
93 |
+
'E': 'exit',
|
94 |
+
'A': 'theAlgorithm',
|
95 |
+
'+': 'block',
|
96 |
+
'R': 'redLock',
|
97 |
+
'G': 'greenLock',
|
98 |
+
'B': 'blueLock',
|
99 |
+
'Y': 'yellowLock',
|
100 |
+
'r': 'redKey',
|
101 |
+
'g': 'greenKey',
|
102 |
+
'b': 'blueKey',
|
103 |
+
'y': 'yellowKey'
|
104 |
+
}, 17, 6);
|
105 |
+
#END_OF_START_LEVEL#
|
106 |
+
}
|
107 |
+
|
108 |
+
function validateLevel(map) {
|
109 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
110 |
+
map.validateAtMostXObjects(1, 'theAlgorithm');
|
111 |
+
map.validateAtMostXObjects(4, 'yellowKey');
|
112 |
+
map.validateAtMostXObjects(2, 'blueKey');
|
113 |
+
map.validateAtMostXObjects(1, 'redKey');
|
114 |
+
}
|
115 |
+
|
116 |
+
function onExit(map) {
|
117 |
+
// make sure we have all the items we need!
|
118 |
+
if (!map.getPlayer().hasItem('theAlgorithm')) {
|
119 |
+
map.writeStatus("You must get that Algorithm!!");
|
120 |
+
return false;
|
121 |
+
} else if (!map.getPlayer().hasItem('computer')) {
|
122 |
+
map.writeStatus("You'll need your computer! [Ctrl-5 to restart]");
|
123 |
+
return false;
|
124 |
+
} else if (!map.getPlayer().hasItem('phone')) {
|
125 |
+
map.writeStatus("You'll need your phone! [Ctrl-5 to restart]");
|
126 |
+
return false;
|
127 |
+
} else {
|
128 |
+
return true;
|
129 |
+
}
|
130 |
+
}
|
levels/15_exceptionalCrossing.jsx
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.2",
|
4 |
+
"commandsIntroduced": [],
|
5 |
+
"music": "The_Waves_Call_Her_Name",
|
6 |
+
"startingMessage": "You have lost the Algorithm!"
|
7 |
+
}
|
8 |
+
#END_PROPERTIES#
|
9 |
+
/**************************
|
10 |
+
* exceptionalCrossing.js *
|
11 |
+
**************************
|
12 |
+
*
|
13 |
+
* Sorry, old friend, but I'm afraid I can't share
|
14 |
+
* co-authorship on this paper. You've done a very
|
15 |
+
* good job getting this Algorithm for me. The bit
|
16 |
+
* with the keys was especially clever! I wouldn't
|
17 |
+
* have thought of it myself. But then, of course,
|
18 |
+
* that's why you were here in the first place.
|
19 |
+
*
|
20 |
+
* You've served your purpose well. But now, alas,
|
21 |
+
* it is time for you to die.
|
22 |
+
*
|
23 |
+
* I'm not heartless, though. In fact, I will let
|
24 |
+
* you choose your mode of death. There, isn't that
|
25 |
+
* nice?
|
26 |
+
*/
|
27 |
+
|
28 |
+
function startLevel(map) {
|
29 |
+
#START_OF_START_LEVEL#
|
30 |
+
map.displayChapter('Chapter 3\nBetrayal');
|
31 |
+
|
32 |
+
map.placePlayer(0, 0);
|
33 |
+
|
34 |
+
// yoink!
|
35 |
+
map.getPlayer().removeItem('theAlgorithm');
|
36 |
+
|
37 |
+
map.defineObject('water', {
|
38 |
+
'symbol': '░',
|
39 |
+
'color': '#44f',
|
40 |
+
'onCollision': function (player) {
|
41 |
+
player.killedBy#{#('drowning in deep dark water')#}#;
|
42 |
+
}
|
43 |
+
});
|
44 |
+
|
45 |
+
for (var x = 0; x < map.getWidth(); x++)
|
46 |
+
for (var y = 5; y < 15; y++)
|
47 |
+
map.placeObject(x, y, 'water');
|
48 |
+
|
49 |
+
map.placeObject(map.getWidth()-1, map.getHeight()-1, 'exit');
|
50 |
+
#END_OF_START_LEVEL#
|
51 |
+
}
|
52 |
+
|
53 |
+
function validateLevel(map) {
|
54 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
55 |
+
}
|
levels/16_lasers.jsx
ADDED
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.2.3",
|
4 |
+
"commandsIntroduced":
|
5 |
+
["map.getCanvasContext", "canvas.beginPath", "canvas.strokeStyle",
|
6 |
+
"canvas.lineWidth", "canvas.moveTo", "canvas.lineTo",
|
7 |
+
"canvas.stroke", "map.createLine", "map.validateAtLeastXLines"],
|
8 |
+
"music": "Soixante-8",
|
9 |
+
"mapProperties": {
|
10 |
+
"showDrawingCanvas": true
|
11 |
+
}
|
12 |
+
}
|
13 |
+
#END_PROPERTIES#
|
14 |
+
/*************
|
15 |
+
* lasers.js *
|
16 |
+
*************
|
17 |
+
*
|
18 |
+
* Time to unleash the killer lasers! Each laser will kill you
|
19 |
+
* unless you have the appropriate color. Too bad you can't
|
20 |
+
* see which color corresponds to which laser!
|
21 |
+
*/
|
22 |
+
|
23 |
+
function getRandomInt(min, max) {
|
24 |
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
25 |
+
}
|
26 |
+
|
27 |
+
function startLevel(map) {
|
28 |
+
#START_OF_START_LEVEL#
|
29 |
+
map.placePlayer(0, 0);
|
30 |
+
map.placeObject(map.getWidth()-1, map.getHeight()-1, 'exit');
|
31 |
+
var player = map.getPlayer();
|
32 |
+
|
33 |
+
for (var i = 0; i < 25; i++) {
|
34 |
+
var colors = ['red', 'yellow', 'teal'];
|
35 |
+
|
36 |
+
var startX = getRandomInt(0, 600);
|
37 |
+
var startY = getRandomInt(0, 500);
|
38 |
+
var angle = getRandomInt(0, 360);
|
39 |
+
var length = getRandomInt(200, 300);
|
40 |
+
var color = colors[i % 3];
|
41 |
+
createLaser(startX, startY, angle, length, color);
|
42 |
+
}
|
43 |
+
|
44 |
+
function createLaser(centerX, centerY, angleInDegrees, length, color) {
|
45 |
+
var angleInRadians = angleInDegrees * Math.PI / 180;
|
46 |
+
|
47 |
+
var x1 = centerX - Math.cos(angleInRadians) * length / 2;
|
48 |
+
var y1 = centerY + Math.sin(angleInRadians) * length / 2;
|
49 |
+
var x2 = centerX + Math.cos(angleInRadians) * length / 2;
|
50 |
+
var y2 = centerY - Math.sin(angleInRadians) * length / 2;
|
51 |
+
|
52 |
+
// map.createLine() creates a line with an effect when
|
53 |
+
// the player moves over it, but doesn't display it
|
54 |
+
map.createLine([x1, y1], [x2, y2], function (player) {
|
55 |
+
if (player.getColor() != color) {
|
56 |
+
player.killedBy('a ' + color + ' laser');
|
57 |
+
}
|
58 |
+
});
|
59 |
+
|
60 |
+
#BEGIN_EDITABLE#
|
61 |
+
// using canvas to draw the line
|
62 |
+
var ctx = map.getCanvasContext();
|
63 |
+
ctx.beginPath();
|
64 |
+
ctx.strokeStyle = 'white';
|
65 |
+
ctx.lineWidth = 5;
|
66 |
+
ctx.moveTo(x1, y1);
|
67 |
+
ctx.lineTo(x2, y2);
|
68 |
+
ctx.stroke();
|
69 |
+
#END_EDITABLE#
|
70 |
+
|
71 |
+
}
|
72 |
+
|
73 |
+
#BEGIN_EDITABLE#
|
74 |
+
|
75 |
+
|
76 |
+
|
77 |
+
|
78 |
+
|
79 |
+
|
80 |
+
|
81 |
+
|
82 |
+
|
83 |
+
#END_EDITABLE#
|
84 |
+
#END_OF_START_LEVEL#
|
85 |
+
}
|
86 |
+
|
87 |
+
function validateLevel(map) {
|
88 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
89 |
+
map.validateAtLeastXLines(25);
|
90 |
+
}
|
levels/17_pointers.jsx
ADDED
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.2.2",
|
4 |
+
"commandsIntroduced":
|
5 |
+
["map.getDynamicObjects", "map.getCanvasCoords", "object.setTarget"],
|
6 |
+
"music": "Tart",
|
7 |
+
"mapProperties": {
|
8 |
+
"showDrawingCanvas": true
|
9 |
+
}
|
10 |
+
}
|
11 |
+
#END_PROPERTIES#
|
12 |
+
/***************
|
13 |
+
* pointers.js *
|
14 |
+
***************
|
15 |
+
*
|
16 |
+
* You! How are you still alive?
|
17 |
+
*
|
18 |
+
* Well, no matter. Good luck getting through this
|
19 |
+
* maze of rooms - you'll never see me or the Algorithm again!
|
20 |
+
*/
|
21 |
+
|
22 |
+
function startLevel(map) {
|
23 |
+
#START_OF_START_LEVEL#
|
24 |
+
function shuffle(o){ //v1.0 [http://bit.ly/1l6LGQT]
|
25 |
+
for(var j, x, i = o.length; i; j = Math.floor(Math.random() * i),
|
26 |
+
x = o[--i], o[i] = o[j], o[j] = x);
|
27 |
+
return o;
|
28 |
+
};
|
29 |
+
|
30 |
+
map.createFromGrid(
|
31 |
+
['+++++++++++++++++++++++++++++++++++++++++++++',
|
32 |
+
'++o *++++o *++++o *++++o *++++o *++++o *+++++',
|
33 |
+
'+* @ o++* o++* o++* o++* o++* o++++',
|
34 |
+
'++o *++++o *++++o *++++o *++++o *++++o *+++++',
|
35 |
+
'+++++++++++++++++++++++++++++++++++++++++++++',
|
36 |
+
'+++++* o++++* o++++* o++++* o++++* o++++* o++',
|
37 |
+
'++++o *++o *++o *++o *++o *++o *+',
|
38 |
+
'+++++* o++++* o++++* o++++* o++++* o++++* o++',
|
39 |
+
'+++++++++++++++++++++++++++++++++++++++++++++',
|
40 |
+
'++o *++++o *++++o *++++o *++++o *++++o *+++++',
|
41 |
+
'+* o++* o++* o++* o++* o++* o++++',
|
42 |
+
'++o *++++o *++++o *++++o *++++o *++++o *+++++',
|
43 |
+
'+++++++++++++++++++++++++++++++++++++++++++++',
|
44 |
+
'+++++* o++++* o++++* o++++* o++++* o++++* o++',
|
45 |
+
'++++o *++o *++o *++o *++o *++o *+',
|
46 |
+
'+++++* o++++* o++++* o++++* o++++* o++++* o++',
|
47 |
+
'+++++++++++++++++++++++++++++++++++++++++++++',
|
48 |
+
'++o *++++o *++++o *++++o *++++o *++++o *+++++',
|
49 |
+
'+* o++* o++* o++* o++* o++* E o++++',
|
50 |
+
'++o *++++o *++++o *++++o *++++o *++++o *+++++',
|
51 |
+
'+++++++++++++++++++++++++++++++++++++++++++++'],
|
52 |
+
{
|
53 |
+
'@': 'player',
|
54 |
+
'E': 'exit',
|
55 |
+
'+': 'block',
|
56 |
+
'o': 'teleporter',
|
57 |
+
'*': 'trap',
|
58 |
+
}, 2, 2);
|
59 |
+
|
60 |
+
var canvas = map.getCanvasContext();
|
61 |
+
|
62 |
+
var teleportersAndTraps = map.getDynamicObjects();
|
63 |
+
teleportersAndTraps = shuffle(teleportersAndTraps);
|
64 |
+
|
65 |
+
for (var i = 0; i < teleportersAndTraps.length; i+=2) {
|
66 |
+
var t1 = teleportersAndTraps[i];
|
67 |
+
var t2 = teleportersAndTraps[i+1];
|
68 |
+
|
69 |
+
// Point each teleporter to either another teleporter
|
70 |
+
// or a trap
|
71 |
+
if (t1.getType() == 'teleporter') {
|
72 |
+
t1.setTarget(t2);
|
73 |
+
}
|
74 |
+
if (t2.getType() == 'teleporter') {
|
75 |
+
t2.setTarget(t1);
|
76 |
+
}
|
77 |
+
|
78 |
+
#BEGIN_EDITABLE#
|
79 |
+
// TODO find a way to remove the API docs
|
80 |
+
// wouldn't want the 'good doctor' to find
|
81 |
+
// out about map.getCanvasCoords()...
|
82 |
+
|
83 |
+
|
84 |
+
|
85 |
+
|
86 |
+
|
87 |
+
#END_EDITABLE#
|
88 |
+
}
|
89 |
+
#END_OF_START_LEVEL#
|
90 |
+
}
|
91 |
+
|
92 |
+
function validateLevel(map) {
|
93 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
94 |
+
}
|
levels/18_superDrEvalBros.jsx
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.2.2",
|
4 |
+
"commandsIntroduced": ["player.move", "map.startTimer"],
|
5 |
+
"music": "Beach Wedding Dance",
|
6 |
+
"mapProperties": {
|
7 |
+
"keyDelay": 25
|
8 |
+
}
|
9 |
+
}
|
10 |
+
#END_PROPERTIES#
|
11 |
+
/**********************
|
12 |
+
* superDrEvalBros.js *
|
13 |
+
**********************
|
14 |
+
*
|
15 |
+
* You're still here?! Well, Dr. Eval, let's see
|
16 |
+
* how well you can operate with one less dimension.
|
17 |
+
*
|
18 |
+
* Give up now. Unless you have a magic mushroom
|
19 |
+
* up your sleeve, it's all over.
|
20 |
+
*/
|
21 |
+
|
22 |
+
function startLevel(map) {
|
23 |
+
#START_OF_START_LEVEL#
|
24 |
+
var fl = Math.floor;
|
25 |
+
var w = map.getWidth();
|
26 |
+
var h = map.getHeight();
|
27 |
+
|
28 |
+
map.placePlayer(1, fl(h/2)-1);
|
29 |
+
var player = map.getPlayer();
|
30 |
+
|
31 |
+
map.placeObject(w-1, fl(h/2)-1, 'exit');
|
32 |
+
|
33 |
+
for (var x = 0; x < fl(w/2) - 5; x++) {
|
34 |
+
for (var y = fl(h/2); y < h; y++) {
|
35 |
+
map.placeObject(x, y, 'block');
|
36 |
+
}
|
37 |
+
}
|
38 |
+
|
39 |
+
for (var x = fl(w/2) + 5; x <= w; x++) {
|
40 |
+
for (var y = fl(h/2); y < h; y++) {
|
41 |
+
map.placeObject(x, y, 'block');
|
42 |
+
}
|
43 |
+
}
|
44 |
+
|
45 |
+
function gravity() {
|
46 |
+
var x = player.getX();
|
47 |
+
var y = player.getY() + 1;
|
48 |
+
|
49 |
+
if (y === map.getHeight() - 2) {
|
50 |
+
player.killedBy("gravity");
|
51 |
+
}
|
52 |
+
|
53 |
+
if (map.getObjectTypeAt(x,y) === "empty") {
|
54 |
+
player.move("down");
|
55 |
+
}
|
56 |
+
|
57 |
+
}
|
58 |
+
map.startTimer(gravity, 45);
|
59 |
+
|
60 |
+
function jump() {
|
61 |
+
#BEGIN_EDITABLE#
|
62 |
+
|
63 |
+
|
64 |
+
|
65 |
+
|
66 |
+
|
67 |
+
|
68 |
+
|
69 |
+
#END_EDITABLE#
|
70 |
+
}
|
71 |
+
|
72 |
+
player.setPhoneCallback(function () {
|
73 |
+
var x = player.getX();
|
74 |
+
var y = player.getY() + 1;
|
75 |
+
|
76 |
+
if (map.getObjectTypeAt(x,y) !== "empty") {
|
77 |
+
jump();
|
78 |
+
}
|
79 |
+
});
|
80 |
+
#END_OF_START_LEVEL#
|
81 |
+
}
|
82 |
+
|
83 |
+
function validateLevel(map) {
|
84 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
85 |
+
map.validateExactlyXManyObjects(520, 'block');
|
86 |
+
}
|
levels/19_documentObjectMadness.jsx
ADDED
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.3",
|
4 |
+
"commandsIntroduced":
|
5 |
+
["global.objective", "map.getDOM", "map.createFromDOM",
|
6 |
+
"map.updateDOM", "map.overrideKey", "global.$",
|
7 |
+
"jQuery.find", "jQuery.addClass", "jQuery.hasClass",
|
8 |
+
"jQuery.removeClass", "jQuery.parent", "jQuery.length",
|
9 |
+
"jQuery.children", "jQuery.first", "jQuery.next",
|
10 |
+
"jQuery.prev"],
|
11 |
+
"music": "BossLoop",
|
12 |
+
"mapProperties": {
|
13 |
+
"showDummyDom": true
|
14 |
+
}
|
15 |
+
}
|
16 |
+
#END_PROPERTIES#
|
17 |
+
/****************************
|
18 |
+
* documentObjectMadness.js *
|
19 |
+
****************************
|
20 |
+
*
|
21 |
+
* I can't believe it! I can't believe you made it onto
|
22 |
+
* Department of Theoretical Computation's web server!
|
23 |
+
* YOU SHOULD HAVE BEEN DELETED! This shouldn't even be
|
24 |
+
* possible! What the hell were the IT folks thinking?
|
25 |
+
*
|
26 |
+
* No matter. I still have the Algorithm. That's the
|
27 |
+
* important part. The rest is just implementation, and
|
28 |
+
* how hard could that be?
|
29 |
+
*
|
30 |
+
* Anyway you're not going to catch me now, my good Doctor.
|
31 |
+
* After all, you're a tenured professor with a well-respected
|
32 |
+
* history of research - you probably don't know jQuery!
|
33 |
+
*/
|
34 |
+
|
35 |
+
function objective(map) {
|
36 |
+
return map.getDOM().find('.adversary').hasClass('drEval');
|
37 |
+
}
|
38 |
+
|
39 |
+
function startLevel(map) {
|
40 |
+
#START_OF_START_LEVEL#
|
41 |
+
var html = "<div class='container'>" +
|
42 |
+
"<div style='width: 600px; height: 500px; background-color: white; font-size: 10px;'>" +
|
43 |
+
"<center><h1>Department of Theoretical Computation</h1></center>" +
|
44 |
+
"<hr />" +
|
45 |
+
"<table border='0'><tr valign='top'>" +
|
46 |
+
"<td><div id='face' /></td>" +
|
47 |
+
"<td>" +
|
48 |
+
"<h2 class=facultyName>Cornelius Eval</h2>" +
|
49 |
+
"<h3>Associate Professor of Computer Science</h3>" +
|
50 |
+
"<ul>" +
|
51 |
+
"<li>BS, Mathematics, University of Manitoba</li>" +
|
52 |
+
"<li>PhD, Theoretical Computation, <a href='http://www.mit.edu'>MIT</a></li>" +
|
53 |
+
"</ul>" +
|
54 |
+
"<h4>About me</h4>" +
|
55 |
+
"<p>I am an associate professor of computer science, attached to the Department of " +
|
56 |
+
"Theoretical Computation. My current research interests include the human-machine " +
|
57 |
+
"interface, NP complete problems, and parallelized mesh mathematics.</p>" +
|
58 |
+
"<p>I am also the current faculty advisor to the <a href=''>undergraduate Super Smash Bros. team</a>. " +
|
59 |
+
"In my spare time I enjoy polka and dirtbiking. </p>" +
|
60 |
+
"</td>" +
|
61 |
+
"</tr></table>" +
|
62 |
+
|
63 |
+
"<div id='class_schedule'>" +
|
64 |
+
"<h4>Class Schedule</h4>" +
|
65 |
+
"<table>" +
|
66 |
+
"<tr>" +
|
67 |
+
"<th>Monday</th><th>Tuesday</th><th>Wednesday</th><th>Thursday</th><th>Friday</th>" +
|
68 |
+
"</tr>" +
|
69 |
+
"<tr>" +
|
70 |
+
"<td>CS145 - Semicolons</td><td>Nothing Planned</td><td>CS145 - Semicolons</td><td>CS199 - Practical Theorycrafting </td><td>CS145 - Semicolons</td>" +
|
71 |
+
"</tr>" +
|
72 |
+
"</table>" +
|
73 |
+
"</div>" +
|
74 |
+
"<div id='loremIpsum'>" +
|
75 |
+
"<h4>Lorem Ipsum</h4>" +
|
76 |
+
"<blockquote>" +
|
77 |
+
"<code>Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci " +
|
78 |
+
"velit, sed quia nonnumquam eiusmodi tempora incidunt ut labore et dolore magnam aliquam quaerat " +
|
79 |
+
"voluptatem.</code>" +
|
80 |
+
"<footer>— " +
|
81 |
+
"<cite>Cicero, De Finibus Bonorum et Malorum</cite>" +
|
82 |
+
"</footer>" +
|
83 |
+
"</blockquote>" +
|
84 |
+
"</div>" +
|
85 |
+
"</div></div>";
|
86 |
+
|
87 |
+
var $dom = $(html);
|
88 |
+
|
89 |
+
$dom.find('.facultyName').addClass('drEval');
|
90 |
+
$dom.find('cite').addClass('adversary');
|
91 |
+
|
92 |
+
function moveToParent(className) {
|
93 |
+
var currentPosition = $dom.find('.' + className);
|
94 |
+
if (currentPosition.parent().length > 0) {
|
95 |
+
if (currentPosition.parent().hasClass('container')) {
|
96 |
+
if (className === 'drEval') {
|
97 |
+
map.getPlayer().killedBy('moving off the edge of the DOM');
|
98 |
+
} else {
|
99 |
+
return false;
|
100 |
+
}
|
101 |
+
} else {
|
102 |
+
currentPosition.parent().addClass(className);
|
103 |
+
currentPosition.removeClass(className);
|
104 |
+
map.updateDOM($dom);
|
105 |
+
}
|
106 |
+
}
|
107 |
+
}
|
108 |
+
|
109 |
+
function moveToFirstChild(className) {
|
110 |
+
var currentPosition = $dom.find('.' + className);
|
111 |
+
if (currentPosition.children().length > 0) {
|
112 |
+
currentPosition.children().first().addClass(className);
|
113 |
+
currentPosition.removeClass(className);
|
114 |
+
map.updateDOM($dom);
|
115 |
+
}
|
116 |
+
}
|
117 |
+
|
118 |
+
function moveToPreviousSibling(className) {
|
119 |
+
var currentPosition = $dom.find('.' + className);
|
120 |
+
if (currentPosition.prev().length > 0) {
|
121 |
+
currentPosition.prev().addClass(className);
|
122 |
+
currentPosition.removeClass(className);
|
123 |
+
map.updateDOM($dom);
|
124 |
+
}
|
125 |
+
}
|
126 |
+
|
127 |
+
function moveToNextSibling(className) {
|
128 |
+
var currentPosition = $dom.find('.' + className);
|
129 |
+
if (currentPosition.next().length > 0) {
|
130 |
+
currentPosition.next().addClass(className);
|
131 |
+
currentPosition.removeClass(className);
|
132 |
+
map.updateDOM($dom);
|
133 |
+
}
|
134 |
+
}
|
135 |
+
|
136 |
+
map.overrideKey('up', function () { moveToParent('drEval'); });
|
137 |
+
map.overrideKey('down', function () { moveToFirstChild('drEval'); });
|
138 |
+
map.overrideKey('left', function () { moveToPreviousSibling('drEval'); });
|
139 |
+
map.overrideKey('right', function () { moveToNextSibling('drEval'); });
|
140 |
+
|
141 |
+
map.defineObject('adversary', {
|
142 |
+
'type': 'dynamic',
|
143 |
+
'symbol': '@',
|
144 |
+
'color': 'red',
|
145 |
+
'behavior': function (me) {
|
146 |
+
var move = Math.floor(Math.random() * 4) + 1; // 1, 2, 3, or 4
|
147 |
+
if (move == 1) {
|
148 |
+
moveToParent('adversary');
|
149 |
+
} else if (move == 2) {
|
150 |
+
moveToFirstChild('adversary');
|
151 |
+
} else if (move == 3) {
|
152 |
+
moveToPreviousSibling('adversary');
|
153 |
+
} else if (move == 4) {
|
154 |
+
moveToNextSibling('adversary');
|
155 |
+
}
|
156 |
+
}
|
157 |
+
});
|
158 |
+
|
159 |
+
map.placePlayer(1, 1);
|
160 |
+
map.placeObject(map.getWidth() - 2, map.getHeight() - 2, 'adversary');
|
161 |
+
|
162 |
+
map.createFromDOM($dom);
|
163 |
+
#END_OF_START_LEVEL#
|
164 |
+
}
|
levels/20_bossFight.jsx
ADDED
@@ -0,0 +1,161 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.2.1",
|
4 |
+
"commandsIntroduced":
|
5 |
+
["object.onDestroy", "object.projectile",
|
6 |
+
"map.countObjects", "map.isStartOfLevel",
|
7 |
+
"map.validateAtMostXDynamicObjects", "map.validateNoTimers"],
|
8 |
+
"music": "Adversity",
|
9 |
+
"mapProperties": {
|
10 |
+
"refreshRate": 50
|
11 |
+
}
|
12 |
+
}
|
13 |
+
#END_PROPERTIES#
|
14 |
+
|
15 |
+
/*****************
|
16 |
+
* bossFight.js *
|
17 |
+
*****************
|
18 |
+
*
|
19 |
+
* NO FARTHER, DR. EVAL!!!!
|
20 |
+
* YOU WILL NOT GET OUT OF HERE ALIVE!!!!
|
21 |
+
* IT'S TIME YOU SEE MY TRUE FORM!!!!
|
22 |
+
* FACE MY ROBOT WRATH!!!!!
|
23 |
+
*/
|
24 |
+
|
25 |
+
function startLevel(map) {
|
26 |
+
#START_OF_START_LEVEL#
|
27 |
+
map.defineObject('boss', {
|
28 |
+
'type': 'dynamic',
|
29 |
+
'symbol': '⊙',
|
30 |
+
'color': 'red',
|
31 |
+
'interval': 200,
|
32 |
+
'onCollision': function (player) {
|
33 |
+
player.killedBy('the boss');
|
34 |
+
},
|
35 |
+
'behavior': function (me) {
|
36 |
+
if (!me.direction) {
|
37 |
+
me.direction = 'right';
|
38 |
+
}
|
39 |
+
if (me.canMove(me.direction)) {
|
40 |
+
me.move(me.direction);
|
41 |
+
} else {
|
42 |
+
me.direction = (me.direction == 'right') ? 'left' : 'right';
|
43 |
+
}
|
44 |
+
if (Math.random() < 0.3) {
|
45 |
+
map.placeObject(me.getX(), me.getY() + 2, 'bullet');
|
46 |
+
}
|
47 |
+
},
|
48 |
+
'onDestroy': function (me) {
|
49 |
+
if (map.countObjects('boss') == 0) {
|
50 |
+
map.placeObject(me.getX(), me.getY(), 'theAlgorithm');
|
51 |
+
}
|
52 |
+
}
|
53 |
+
});
|
54 |
+
|
55 |
+
map.defineObject('bullet', {
|
56 |
+
'type': 'dynamic',
|
57 |
+
'symbol': '.',
|
58 |
+
'color': 'red',
|
59 |
+
'interval': 100,
|
60 |
+
'projectile': true,
|
61 |
+
'behavior': function (me) {
|
62 |
+
me.move('down');
|
63 |
+
}
|
64 |
+
});
|
65 |
+
|
66 |
+
map.placePlayer(0, map.getHeight() - 3);
|
67 |
+
map.placeObject(map.getWidth() - 1, map.getHeight() - 1, 'exit');
|
68 |
+
|
69 |
+
// Not so tough now, huh?
|
70 |
+
map.getPlayer().removeItem('phone');
|
71 |
+
map.placeObject(map.getWidth() - 1, map.getHeight() - 3, 'phone');
|
72 |
+
|
73 |
+
map.placeObject(0, map.getHeight() - 4, 'block');
|
74 |
+
map.placeObject(1, map.getHeight() - 4, 'block');
|
75 |
+
map.placeObject(2, map.getHeight() - 4, 'block');
|
76 |
+
map.placeObject(2, map.getHeight() - 3, 'block');
|
77 |
+
map.placeObject(map.getWidth() - 1, map.getHeight() - 4, 'block');
|
78 |
+
map.placeObject(map.getWidth() - 2, map.getHeight() - 4, 'block');
|
79 |
+
map.placeObject(map.getWidth() - 3, map.getHeight() - 4, 'block');
|
80 |
+
map.placeObject(map.getWidth() - 3, map.getHeight() - 3, 'block');
|
81 |
+
|
82 |
+
for (var x = 0; x < map.getWidth(); x++) {
|
83 |
+
map.placeObject(x, 4, 'block');
|
84 |
+
}
|
85 |
+
|
86 |
+
map.placeObject(9, 5, 'boss');
|
87 |
+
map.placeObject(11, 5, 'boss');
|
88 |
+
map.placeObject(13, 5, 'boss');
|
89 |
+
map.placeObject(15, 5, 'boss');
|
90 |
+
map.placeObject(17, 5, 'boss');
|
91 |
+
map.placeObject(19, 5, 'boss');
|
92 |
+
map.placeObject(21, 5, 'boss');
|
93 |
+
map.placeObject(23, 5, 'boss');
|
94 |
+
map.placeObject(25, 5, 'boss');
|
95 |
+
map.placeObject(27, 5, 'boss');
|
96 |
+
map.placeObject(29, 5, 'boss');
|
97 |
+
map.placeObject(31, 5, 'boss');
|
98 |
+
|
99 |
+
map.placeObject(10, 6, 'boss');
|
100 |
+
map.placeObject(12, 6, 'boss');
|
101 |
+
map.placeObject(14, 6, 'boss');
|
102 |
+
map.placeObject(16, 6, 'boss');
|
103 |
+
map.placeObject(18, 6, 'boss');
|
104 |
+
map.placeObject(20, 6, 'boss');
|
105 |
+
map.placeObject(22, 6, 'boss');
|
106 |
+
map.placeObject(24, 6, 'boss');
|
107 |
+
map.placeObject(26, 6, 'boss');
|
108 |
+
map.placeObject(28, 6, 'boss');
|
109 |
+
map.placeObject(30, 6, 'boss');
|
110 |
+
|
111 |
+
#BEGIN_EDITABLE#
|
112 |
+
|
113 |
+
|
114 |
+
|
115 |
+
|
116 |
+
|
117 |
+
|
118 |
+
|
119 |
+
|
120 |
+
|
121 |
+
|
122 |
+
|
123 |
+
|
124 |
+
|
125 |
+
|
126 |
+
|
127 |
+
|
128 |
+
|
129 |
+
|
130 |
+
#END_EDITABLE#
|
131 |
+
|
132 |
+
#END_OF_START_LEVEL#
|
133 |
+
}
|
134 |
+
|
135 |
+
function validateLevel(map) {
|
136 |
+
// called at start of level and whenever a callback executes
|
137 |
+
map.validateAtMostXObjects(59, 'block');
|
138 |
+
map.validateAtMostXObjects(1, 'phone');
|
139 |
+
|
140 |
+
if (map.countObjects('theAlgorithm') > 0 && map.countObjects('boss') > 0) {
|
141 |
+
throw "The Algorithm can only be dropped by the boss!";
|
142 |
+
}
|
143 |
+
|
144 |
+
// only called at start of level
|
145 |
+
if (map.isStartOfLevel()) {
|
146 |
+
map.validateAtMostXDynamicObjects(23);
|
147 |
+
map.validateNoTimers();
|
148 |
+
}
|
149 |
+
}
|
150 |
+
|
151 |
+
function onExit(map) {
|
152 |
+
if (!map.getPlayer().hasItem('theAlgorithm')) {
|
153 |
+
map.writeStatus("You must take back the Algorithm!!");
|
154 |
+
return false;
|
155 |
+
} else if (!map.getPlayer().hasItem('phone')) {
|
156 |
+
map.writeStatus("We need the phone!");
|
157 |
+
return false;
|
158 |
+
} else {
|
159 |
+
return true;
|
160 |
+
}
|
161 |
+
}
|
levels/21_endOfTheLine.jsx
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.2",
|
4 |
+
"music": "Comme Des Orages"
|
5 |
+
}
|
6 |
+
#END_PROPERTIES#
|
7 |
+
|
8 |
+
/*******************
|
9 |
+
* endOfTheLine.js *
|
10 |
+
*******************
|
11 |
+
*
|
12 |
+
* I don't feel guilty at all, Cornelius.
|
13 |
+
*
|
14 |
+
* Did you really expect me to? Did you really think that
|
15 |
+
* you could be trusted with coauthorship on the paper that
|
16 |
+
* would prove P = NP in the eyes of the world?
|
17 |
+
*
|
18 |
+
* You're a very pure researcher, my good Doctor. "Department
|
19 |
+
* of Theoretical Computation", divorced from the realities
|
20 |
+
* of the world. I don't think you ever considered the
|
21 |
+
* implications - the *physical* implications - of the
|
22 |
+
* Algorithm. What humanity might do if it was as easy to
|
23 |
+
* solve an intractable puzzle as it was to conceive of it.
|
24 |
+
*
|
25 |
+
* We would become as unto Gods, Cornelius, if this knowledge
|
26 |
+
* was public. Immature children wielding power unimaginable.
|
27 |
+
* We've already had one Oppenheimer - we don't need Dr.
|
28 |
+
* Cornelius Eval to be another.
|
29 |
+
*
|
30 |
+
* If I had succeeded the Algorithm would be safe and secure
|
31 |
+
* in the hands of those with the sound judgement and sense
|
32 |
+
* of responsibility to use it wisely. I pray my failure
|
33 |
+
* will not doom mankind - but I cannot hope so
|
34 |
+
* optimistically.
|
35 |
+
*
|
36 |
+
* You may have defeated my robot form, but I anticipated
|
37 |
+
* this eventuality. The Algorithm must never leave the
|
38 |
+
* Machine Continuum. And so neither can you.
|
39 |
+
*
|
40 |
+
* This is bigger than me and bigger than you. I have no
|
41 |
+
* regrets. I would do it again in an instant.
|
42 |
+
*/
|
43 |
+
|
44 |
+
function startLevel(map) {
|
45 |
+
#START_OF_START_LEVEL#
|
46 |
+
map.finalLevel = true;
|
47 |
+
map.placePlayer(15, 12);
|
48 |
+
map.placeObject(25, 12, 'exit');
|
49 |
+
#END_OF_START_LEVEL#
|
50 |
+
}
|
levels/22_credits.jsx
ADDED
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.3.0",
|
4 |
+
"music": "Brazil",
|
5 |
+
"mapProperties": {
|
6 |
+
"showDrawingCanvas": "true"
|
7 |
+
},
|
8 |
+
"commandsIntroduced": [
|
9 |
+
"canvas.fillStyle",
|
10 |
+
"canvas.fillText",
|
11 |
+
"map.timeout"
|
12 |
+
]
|
13 |
+
}
|
14 |
+
#END_PROPERTIES#
|
15 |
+
/**************
|
16 |
+
* credits.js *
|
17 |
+
*************
|
18 |
+
*
|
19 |
+
* Congratulations! Dr. Eval has successfully escaped from the
|
20 |
+
* Machine Continuum with the Algorithm in hand.
|
21 |
+
*
|
22 |
+
* Give yourself a pat on the back. You are one clever hacker.
|
23 |
+
*
|
24 |
+
*
|
25 |
+
*
|
26 |
+
* Hungry for more?
|
27 |
+
*
|
28 |
+
* Check out Untrusted's github repository at
|
29 |
+
* https://github.com/AlexNisnevich/untrusted
|
30 |
+
*
|
31 |
+
* Perhaps try your hand at making your own level or two!
|
32 |
+
*
|
33 |
+
* Like what you've been hearing? You can listen to the full
|
34 |
+
* soundtrack at
|
35 |
+
* https://soundcloud.com/untrusted
|
36 |
+
*
|
37 |
+
* Feel free to drop us a line at [
|
38 |
+
* 'alex [dot] nisnevich [at] gmail [dot] com',
|
39 |
+
* 'greg [dot] shuflin [at] gmail [dot] com'
|
40 |
+
* ]
|
41 |
+
*
|
42 |
+
* Once again, congratulations!
|
43 |
+
*
|
44 |
+
* -- Alex and Greg
|
45 |
+
*/
|
46 |
+
|
47 |
+
function startLevel(map) {
|
48 |
+
#START_OF_START_LEVEL#
|
49 |
+
var credits = [
|
50 |
+
[15, 1, "U N T R U S T E D"],
|
51 |
+
[20, 2, "- or -"],
|
52 |
+
[5, 3, "THE CONTINUING ADVENTURES OF DR. EVAL"],
|
53 |
+
[1, 4, "{"],
|
54 |
+
[2, 5, "a_game_by: 'Alex Nisnevich and Greg Shuflin',"],
|
55 |
+
[2, 7, "special_thanks_to: {"],
|
56 |
+
[5, 8, "Dmitry_Mazin: ['design', 'code'],"],
|
57 |
+
[5, 9, "Jordan_Arnesen: ['levels', 'playtesting'],"],
|
58 |
+
[5, 10, "Natasha_HullRichter: ['levels','playtesting']"],
|
59 |
+
[2, 11, "},"],
|
60 |
+
[2, 13, "music_by: "],
|
61 |
+
[4, 14, "['Jonathan Holliday',"],
|
62 |
+
[5, 15, "'Dmitry Mazin',"],
|
63 |
+
[5, 16, "'Revolution Void',"],
|
64 |
+
[5, 17, "'Fex',"],
|
65 |
+
[5, 18, "'iNTRICATE',"],
|
66 |
+
[5, 19, "'Tortue Super Sonic',"],
|
67 |
+
[5, 20, "'Broke For Free',"],
|
68 |
+
[5, 21, "'Sycamore Drive',"],
|
69 |
+
[5, 22, "'Eric Skiff'],"],
|
70 |
+
[30, 14, "'Mike and Alan',"],
|
71 |
+
[30, 15, "'RoccoW',"],
|
72 |
+
[30, 16, "'That Andy Guy',"],
|
73 |
+
[30, 17, "'Obsibilo',"],
|
74 |
+
[30, 18, "'BLEO',"],
|
75 |
+
[30, 19, "'Rolemusic',"],
|
76 |
+
[30, 20, "'Seropard',"],
|
77 |
+
[30, 21, "'Vernon Lenoir',"],
|
78 |
+
[15, map.getHeight() - 2, "Thank_you: 'for playing!'"],
|
79 |
+
[1, map.getHeight() - 1, "}"]
|
80 |
+
];
|
81 |
+
|
82 |
+
function drawCredits(i) {
|
83 |
+
if (i >= credits.length) {
|
84 |
+
return;
|
85 |
+
}
|
86 |
+
var ctx = map.getCanvasContext();
|
87 |
+
ctx.fillStyle = "#ccc";
|
88 |
+
var line = credits[i];
|
89 |
+
var coords = map.getCanvasCoords(line[0],line[1]);
|
90 |
+
ctx.fillText(line[2],coords.x, coords.y)
|
91 |
+
map.timeout(function () {drawCredits(i+1);}, 2000)
|
92 |
+
}
|
93 |
+
|
94 |
+
map.timeout(function () {drawCredits(0);}, 4000);
|
95 |
+
|
96 |
+
#END_OF_START_LEVEL#
|
97 |
+
}
|
levels/bonus/01_inTheDesert.jsx
ADDED
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.0.1",
|
4 |
+
"commandsIntroduced": [],
|
5 |
+
"nextBonusLevel": "02_theEmptyRoom.jsx"
|
6 |
+
}
|
7 |
+
#END_PROPERTIES#
|
8 |
+
/******************
|
9 |
+
* inTheDesert.js *
|
10 |
+
* from HangoverX *
|
11 |
+
* by janosgyerik *
|
12 |
+
******************
|
13 |
+
*
|
14 |
+
* Good morning, Mr.... uhm, who are you again?
|
15 |
+
*
|
16 |
+
* You are in the middle of the desert.
|
17 |
+
* You don't remember who you are and what you're doing here.
|
18 |
+
* And that headache...is...painful... Not your best Monday!
|
19 |
+
*
|
20 |
+
* What you see:
|
21 |
+
*
|
22 |
+
* - Desert. Everywhere. Some bushes.
|
23 |
+
* - A floating red eye. Following your every move.
|
24 |
+
* Whatever it is, it's kind of unsettling...
|
25 |
+
* - At least you have this computer. But what the heck for?
|
26 |
+
* - And a small building with a gate. Watch that DEADLY laser!
|
27 |
+
*/
|
28 |
+
|
29 |
+
function startLevel(map) {
|
30 |
+
#START_OF_START_LEVEL#
|
31 |
+
map.displayChapter('Chapter 1\nUhm... Wha..?');
|
32 |
+
|
33 |
+
map.defineObject('laser', {
|
34 |
+
'type': 'trap',
|
35 |
+
'symbol': '-',
|
36 |
+
'color': 'red',
|
37 |
+
'onCollision': function (player) {
|
38 |
+
player.killedBy('deadly laser');
|
39 |
+
},
|
40 |
+
'passableFor': ['player', 'eye'],
|
41 |
+
'deactivatedBy': ['eye'],
|
42 |
+
'onDeactivate': function () {
|
43 |
+
map.writeStatus('machine voice: "d-e-a-c-t-i-v-a-t-e"');
|
44 |
+
}
|
45 |
+
});
|
46 |
+
|
47 |
+
var building_x = parseInt(map.getWidth() / 2);
|
48 |
+
var building_y = parseInt(map.getHeight() / 2) - 5;
|
49 |
+
map.createFromGrid(
|
50 |
+
['###',
|
51 |
+
'#E#',
|
52 |
+
'#-#'],
|
53 |
+
{
|
54 |
+
'#': 'block',
|
55 |
+
'E': 'exit',
|
56 |
+
'-': 'laser'
|
57 |
+
}, building_x, building_y);
|
58 |
+
|
59 |
+
map.placePlayer(building_x + 1, building_y + 8);
|
60 |
+
map.placeObject(building_x + 6, building_y + 8, 'computer');
|
61 |
+
map.placeObject(building_x - 1, building_y + 5, 'eye');
|
62 |
+
|
63 |
+
generateDesert(map, .01);
|
64 |
+
|
65 |
+
#END_OF_START_LEVEL#
|
66 |
+
}
|
67 |
+
|
68 |
+
function generateDesert(map, density) {
|
69 |
+
for (var i = 0; i < map.getWidth(); i++) {
|
70 |
+
for (var j = 0; j < map.getHeight(); j++) {
|
71 |
+
if (map.getPlayer().atLocation(i,j)
|
72 |
+
|| map.getObjectTypeAt(i, j) !== 'empty') {
|
73 |
+
continue;
|
74 |
+
}
|
75 |
+
var rv = Math.random();
|
76 |
+
if (rv < density) {
|
77 |
+
map.placeObject(i, j, 'tree');
|
78 |
+
}
|
79 |
+
}
|
80 |
+
}
|
81 |
+
}
|
82 |
+
|
83 |
+
function onExit(map) {
|
84 |
+
if (!map.getPlayer().hasItem('computer')) {
|
85 |
+
map.writeStatus("Don't forget to pick up the computer!");
|
86 |
+
return false;
|
87 |
+
}
|
88 |
+
return true;
|
89 |
+
}
|
levels/bonus/02_theEmptyRoom.jsx
ADDED
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.0.1",
|
4 |
+
"commandsIntroduced": [],
|
5 |
+
"nextBonusLevel": "03_theCollapsingRoom.jsx"
|
6 |
+
}
|
7 |
+
#END_PROPERTIES#
|
8 |
+
/*******************
|
9 |
+
* theEmptyRoom.js *
|
10 |
+
* from HangoverX *
|
11 |
+
* by janosgyerik *
|
12 |
+
*******************
|
13 |
+
*
|
14 |
+
* Oh great, an empty room. That's so much better than a desert.
|
15 |
+
* Shiny silvery walls and no exit.
|
16 |
+
*
|
17 |
+
* Oh look, a terminal. You seem to remember something about
|
18 |
+
* a previous life, something about "programming", and "languages".
|
19 |
+
* Maybe you can hookup your computer with the terminal and see
|
20 |
+
* where your instincts take you...
|
21 |
+
*/
|
22 |
+
|
23 |
+
function startLevel(map) {
|
24 |
+
#START_OF_START_LEVEL#
|
25 |
+
map.displayChapter('Chapter 2\nThe Empty Room');
|
26 |
+
|
27 |
+
function getAnswer(input) {
|
28 |
+
#BEGIN_EDITABLE#
|
29 |
+
// Hm, buggy software?
|
30 |
+
// Looks like I can inject my own code, right here...
|
31 |
+
|
32 |
+
return 42;
|
33 |
+
#END_EDITABLE#
|
34 |
+
}
|
35 |
+
|
36 |
+
map.defineObject('terminal', {
|
37 |
+
'symbol': 'T',
|
38 |
+
'color': '#88f',
|
39 |
+
'onCollision': function (player) {
|
40 |
+
function challenge() {
|
41 |
+
var input = parseInt(Math.random() * 50) + 15;
|
42 |
+
var expected = {15:610,16:987,17:1597,18:2584,19:4181,20:6765,21:10946,22:17711,23:28657,24:46368,25:75025,26:121393,27:196418,28:317811,29:514229,30:832040,31:1346269,32:2178309,33:3524578,34:5702887,35:9227465,36:14930352,37:24157817,38:39088169,39:63245986,40:102334155,41:165580141,42:267914296,43:433494437,44:701408733,45:1134903170,46:1836311903,47:2971215073,48:4807526976,49:7778742049,50:12586269025,51:20365011074,52:32951280099,53:53316291173,54:86267571272,55:139583862445,56:225851433717,57:365435296162,58:591286729879,59:956722026041,60:1548008755920,61:2504730781961,62:4052739537881,63:6557470319842,64:0x9a661ca20bb,65:0xf9d297a859d,66:27777890035288,67:44945570212853,68:72723460248141,69:0x6b04f4c2fe42,70:0xad2934c6d08f,71:308061521170129,72:498454011879264,73:806515533049393,74:0x4a2dce62b0d91,75:0x780626e057bc2,76:0xc233f54308953,77:5527939700884757,78:8944394323791464,79:0x336a82d89c937c,80:0x533163ef0321e4,81:0x869be6c79fb560,82:0xd9cd4ab6a2d740,83:99194853094755490,84:0x23a367c34e563e0,85:0x39a9fadb327f080,86:0x5d4d629e80d5480,87:0x96f75d79b354500,88:0xf444c0183429980,89:0x18b3c1d91e77de00,90:0x27f80ddaa1ba7800,91:466004661037553e4,92:0x68a3dd8e61ecd000,93:0xa94fad42221f2800,94:0x111f38ad0840c0000,95:319404346349901e5,96:5168070885485833e4,97:8362114348984843e4,98:0x755b0bdd8fa998000,99:2189229958345552e5,100:3542248481792619e5}[input];
|
43 |
+
return expected == getAnswer(input);
|
44 |
+
}
|
45 |
+
if (!challenge()) {
|
46 |
+
player.killedBy('wrong answer');
|
47 |
+
}
|
48 |
+
if (getAnswer(input) == undefined) {
|
49 |
+
player.killedBy('unanswered');
|
50 |
+
}
|
51 |
+
if (!map.opened) {
|
52 |
+
map.writeStatus("*click*");
|
53 |
+
map.opened = true;
|
54 |
+
}
|
55 |
+
}
|
56 |
+
});
|
57 |
+
|
58 |
+
var grid = [
|
59 |
+
'#####################',
|
60 |
+
'# #x# #',
|
61 |
+
'# #T# #',
|
62 |
+
'# #',
|
63 |
+
'# #',
|
64 |
+
'# #',
|
65 |
+
'# #',
|
66 |
+
'# #',
|
67 |
+
'# @ #',
|
68 |
+
'# #',
|
69 |
+
'# e #',
|
70 |
+
'# #',
|
71 |
+
'#####################'
|
72 |
+
];
|
73 |
+
var width = map.getWidth();
|
74 |
+
var height = map.getHeight();
|
75 |
+
var grid_x = parseInt((width - grid[0].length) / 2);
|
76 |
+
var grid_y = parseInt((height - grid.length) / 2);
|
77 |
+
map.createFromGrid(grid, {
|
78 |
+
'T': 'terminal',
|
79 |
+
'x': 'exit',
|
80 |
+
'#': 'block',
|
81 |
+
'@': 'player',
|
82 |
+
'e': 'eye'
|
83 |
+
}, grid_x, grid_y);
|
84 |
+
#END_OF_START_LEVEL#
|
85 |
+
}
|
86 |
+
|
87 |
+
function validateLevel(map) {
|
88 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
89 |
+
}
|
levels/bonus/03_theCollapsingRoom.jsx
ADDED
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "0.1.1",
|
4 |
+
"commandsIntroduced": [],
|
5 |
+
"nextBonusLevel": "04_theGuard.jsx"
|
6 |
+
}
|
7 |
+
#END_PROPERTIES#
|
8 |
+
/************************
|
9 |
+
* theCollapsingRoom.js *
|
10 |
+
* from HangoverX *
|
11 |
+
* by janosgyerik *
|
12 |
+
************************
|
13 |
+
*
|
14 |
+
* As you step through the portal, bright flash of white light.
|
15 |
+
* You feel... different. But the worst news is, the room seems
|
16 |
+
* to be collapsing on you. I mean, MASSIVE CEILING BLOCKS are
|
17 |
+
* falling, man, do something!
|
18 |
+
*
|
19 |
+
* Good thing you found a place in the security system to inject
|
20 |
+
* your custom code, maybe that can help!
|
21 |
+
*/
|
22 |
+
|
23 |
+
function startLevel(map) {
|
24 |
+
#START_OF_START_LEVEL#
|
25 |
+
map.displayChapter('Chapter 3\nThe Collapsing Room');
|
26 |
+
|
27 |
+
var width = map.getWidth();
|
28 |
+
var height = map.getHeight();
|
29 |
+
var half_width = Math.floor(width / 2);
|
30 |
+
var half_height = Math.floor(height / 2);
|
31 |
+
var grid_x = Math.floor(width / 4);
|
32 |
+
var grid_y = Math.floor(height / 4);
|
33 |
+
|
34 |
+
for (var i = 0; i < half_width; ++i) {
|
35 |
+
map.placeObject(grid_x + i, grid_y, 'block');
|
36 |
+
map.placeObject(grid_x + i, grid_y + half_height - 1, 'block');
|
37 |
+
}
|
38 |
+
for (var i = 1; i < half_height; ++i) {
|
39 |
+
map.placeObject(grid_x, grid_y + i, 'block');
|
40 |
+
map.placeObject(grid_x + half_width - 1, grid_y + i, 'block');
|
41 |
+
}
|
42 |
+
|
43 |
+
map.placePlayer(half_width, half_height);
|
44 |
+
map.placeObject(half_width + 2, half_height + 2, 'eye');
|
45 |
+
|
46 |
+
var exit_x, exit_y;
|
47 |
+
switch (Math.floor(Math.random() * 4)) {
|
48 |
+
case 0:
|
49 |
+
exit_x = grid_x + 1;
|
50 |
+
exit_y = grid_y + 1;
|
51 |
+
break;
|
52 |
+
case 1:
|
53 |
+
exit_x = grid_x - 2 + half_width;
|
54 |
+
exit_y = grid_y + 1;
|
55 |
+
break;
|
56 |
+
case 2:
|
57 |
+
exit_x = grid_x - 2 + half_width;
|
58 |
+
exit_y = grid_y - 2 + half_height;
|
59 |
+
break;
|
60 |
+
case 3:
|
61 |
+
exit_x = grid_x + 1;
|
62 |
+
exit_y = grid_y - 2 + half_height;
|
63 |
+
break;
|
64 |
+
}
|
65 |
+
map.placeObject(exit_x, exit_y, 'exit');
|
66 |
+
|
67 |
+
#BEGIN_EDITABLE#
|
68 |
+
|
69 |
+
#END_EDITABLE#
|
70 |
+
|
71 |
+
function bringItDown(map, blocks_per_round) {
|
72 |
+
for (var count = 0, z = 0; count < blocks_per_round && z < 100; ++z) {
|
73 |
+
var x = grid_x + 1 + Math.floor(Math.random() * (half_width - 2));
|
74 |
+
var y = grid_y + 1 + Math.floor(Math.random() * (half_height - 2));
|
75 |
+
if (map.getPlayer().atLocation(x, y)) {
|
76 |
+
map.getPlayer().killedBy('massive ceiling block');
|
77 |
+
}
|
78 |
+
if (map.getObjectTypeAt(x, y) !== 'empty') {
|
79 |
+
continue;
|
80 |
+
}
|
81 |
+
map.placeObject(x, y, 'block');
|
82 |
+
++count;
|
83 |
+
}
|
84 |
+
}
|
85 |
+
|
86 |
+
map.defineObject('rainmaker', {
|
87 |
+
'type': 'dynamic',
|
88 |
+
'symbol': ' ',
|
89 |
+
'behavior': function() {
|
90 |
+
bringItDown(map, 10);
|
91 |
+
}
|
92 |
+
});
|
93 |
+
map.placeObject(1, 1, 'rainmaker');
|
94 |
+
#END_OF_START_LEVEL#
|
95 |
+
}
|
96 |
+
|
97 |
+
function validateLevel(map) {
|
98 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
99 |
+
}
|
levels/bonus/04_theGuard.jsx
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "0.1.1",
|
4 |
+
"commandsIntroduced": [],
|
5 |
+
"nextBonusLevel": "05_theCorridor.jsx"
|
6 |
+
}
|
7 |
+
#END_PROPERTIES#
|
8 |
+
/******************
|
9 |
+
* theGuard.js *
|
10 |
+
* from HangoverX *
|
11 |
+
* by janosgyerik *
|
12 |
+
******************
|
13 |
+
*
|
14 |
+
* Damn that was close!
|
15 |
+
*
|
16 |
+
* The next room feels strangely empty. And incredibly huge.
|
17 |
+
* Whoever owns this place, they might be on to you now.
|
18 |
+
* There's a guard drone near the exit and it's not looking friendly...
|
19 |
+
*/
|
20 |
+
|
21 |
+
function startLevel(map) {
|
22 |
+
#START_OF_START_LEVEL#
|
23 |
+
map.displayChapter('Chapter 4\nThe Guard');
|
24 |
+
|
25 |
+
var width = map.getWidth();
|
26 |
+
var height = map.getHeight();
|
27 |
+
var half_width = Math.floor(width / 2);
|
28 |
+
var half_height = Math.floor(height / 2);
|
29 |
+
|
30 |
+
map.placeObject(half_width, half_height, 'exit');
|
31 |
+
map.placePlayer(width - 3, height - 3);
|
32 |
+
map.placeObject(width - 1, height - 1, 'eye');
|
33 |
+
map.placeObject(half_width + 2, half_height, 'guard');
|
34 |
+
|
35 |
+
#BEGIN_EDITABLE#
|
36 |
+
|
37 |
+
#END_EDITABLE#
|
38 |
+
#END_OF_START_LEVEL#
|
39 |
+
}
|
40 |
+
|
41 |
+
function validateLevel(map) {
|
42 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
43 |
+
}
|
levels/bonus/05_theCorridor.jsx
ADDED
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "0.1",
|
4 |
+
"commandsIntroduced": []
|
5 |
+
}
|
6 |
+
#END_PROPERTIES#
|
7 |
+
/***********************
|
8 |
+
* theCorridor.js *
|
9 |
+
* from HangoverX *
|
10 |
+
* by mongoose11235813 *
|
11 |
+
***********************
|
12 |
+
*/
|
13 |
+
|
14 |
+
function startLevel(map) {
|
15 |
+
#START_OF_START_LEVEL#
|
16 |
+
map.displayChapter('Chapter 4.1\nChapters are supposed to be more than one level long');
|
17 |
+
|
18 |
+
map.defineObject('trap_left', {
|
19 |
+
'type': 'dynamic',
|
20 |
+
'symbol': '>',
|
21 |
+
'color': '#900',
|
22 |
+
'impassable': 'true',
|
23 |
+
'behavior': function (me) {
|
24 |
+
trap_behaviour(me, 1, 6);
|
25 |
+
}
|
26 |
+
}
|
27 |
+
);
|
28 |
+
map.defineObject('trap_right', {
|
29 |
+
'type': 'dynamic',
|
30 |
+
'symbol': '<',
|
31 |
+
'color': '#900',
|
32 |
+
'impassable': 'true',
|
33 |
+
'behavior': function (me) {
|
34 |
+
trap_behaviour(me, -5, 0);
|
35 |
+
}
|
36 |
+
}
|
37 |
+
);
|
38 |
+
map.defineObject('laser', {
|
39 |
+
'type': 'dynamic',
|
40 |
+
'symbol': '-',
|
41 |
+
'color': '#f00',
|
42 |
+
'onCollision': function (player) {
|
43 |
+
player.killedBy('a laser');
|
44 |
+
}
|
45 |
+
}
|
46 |
+
);
|
47 |
+
function trap_behaviour (me, left, right) {
|
48 |
+
var player_pos = me.findNearest('player');
|
49 |
+
if (player_pos.y - me.getY() <= 1 && !me.trapTriggered) {
|
50 |
+
me.trapTriggered = true;
|
51 |
+
for (var x = left; x < right; ++x) {
|
52 |
+
map.placeObject(me.getX() + x, me.getY(), 'laser')
|
53 |
+
}
|
54 |
+
}
|
55 |
+
}
|
56 |
+
|
57 |
+
var level_map = [
|
58 |
+
'#######',
|
59 |
+
'# x #',
|
60 |
+
'# #',
|
61 |
+
'> #',
|
62 |
+
'# #',
|
63 |
+
'# <',
|
64 |
+
'# #',
|
65 |
+
'> #',
|
66 |
+
'# #',
|
67 |
+
'# <',
|
68 |
+
'# #',
|
69 |
+
'# @ e#',
|
70 |
+
'#######'
|
71 |
+
]
|
72 |
+
var width = map.getWidth();
|
73 |
+
var height = map.getHeight();
|
74 |
+
var map_left = Math.floor((width - level_map[0].length) / 2);
|
75 |
+
var map_top = Math.floor((height - level_map.length) / 2);
|
76 |
+
map.createFromGrid(level_map, {
|
77 |
+
'x': 'exit',
|
78 |
+
'#': 'block',
|
79 |
+
'@': 'player',
|
80 |
+
'e': 'eye',
|
81 |
+
'>': 'trap_left',
|
82 |
+
'<': 'trap_right'
|
83 |
+
}, map_left, map_top);
|
84 |
+
|
85 |
+
#BEGIN_EDITABLE#
|
86 |
+
|
87 |
+
#END_EDITABLE#
|
88 |
+
#END_OF_START_LEVEL#
|
89 |
+
}
|
90 |
+
|
91 |
+
function validateLevel(map) {
|
92 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
93 |
+
}
|
levels/bonus/AB_1_ANewJourney.jsx
ADDED
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.0.1",
|
4 |
+
"mapProperties": {
|
5 |
+
"allowOverwrite": true
|
6 |
+
},
|
7 |
+
"nextBonusLevel": "AB_2_FrozenCave.jsx"
|
8 |
+
}
|
9 |
+
#END_PROPERTIES#
|
10 |
+
/***************************
|
11 |
+
* ANewJourney.js *
|
12 |
+
***************************
|
13 |
+
* Hello young traveler!
|
14 |
+
*
|
15 |
+
* We are in dire need of an adventurer
|
16 |
+
* to brave the dangers and use his wits
|
17 |
+
* to escape the traps and retrieve the
|
18 |
+
* ultimate prize...
|
19 |
+
*
|
20 |
+
* You will know when you see it.
|
21 |
+
*
|
22 |
+
* The entrance to the cave is said to be
|
23 |
+
* magical and protected by a spell
|
24 |
+
* to keep people out, but I trust you
|
25 |
+
* to find a way.
|
26 |
+
*
|
27 |
+
* Every traveller knows that the
|
28 |
+
* adventures never truly end.
|
29 |
+
*/
|
30 |
+
|
31 |
+
function getRandomInt(min, max) {
|
32 |
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
33 |
+
}
|
34 |
+
|
35 |
+
function startLevel(map) {
|
36 |
+
#START_OF_START_LEVEL#
|
37 |
+
|
38 |
+
map.createFromGrid(
|
39 |
+
[' xxxxxxxxxxxxxxxxxxxxxxxx ',
|
40 |
+
' xxxxxxxx xxxxxxxxx xxxxx ',
|
41 |
+
' xxxxxxxxxxxx xxxxxxxxxx ',
|
42 |
+
' xxxxxxxxxxxxxxxxxxx ',
|
43 |
+
' xxxxxxxxxxxxxxxx xxxxx ',
|
44 |
+
' xxxxxxxxxxxxxxxxxxxx ',
|
45 |
+
' xxx xxxxxxxxxxxxx ',
|
46 |
+
' xxxxxxxxxx xxxxx ',
|
47 |
+
' xxxxxxxxxxxxxxx ',
|
48 |
+
' ',
|
49 |
+
' ',
|
50 |
+
' ',
|
51 |
+
' ',
|
52 |
+
' ',
|
53 |
+
' ',
|
54 |
+
' ',
|
55 |
+
' ',
|
56 |
+
' ',
|
57 |
+
' ',
|
58 |
+
' ',
|
59 |
+
' ',
|
60 |
+
' ',
|
61 |
+
' ',
|
62 |
+
' C ',
|
63 |
+
' @ '],
|
64 |
+
{
|
65 |
+
'@': 'player',
|
66 |
+
'E': 'exit',
|
67 |
+
'#': 'block',
|
68 |
+
'x': 'tree',
|
69 |
+
'C': 'computer',
|
70 |
+
}, 0, 0);
|
71 |
+
|
72 |
+
|
73 |
+
var exit_place = getRandomInt(0, 5);
|
74 |
+
if(exit_place == 0){
|
75 |
+
map.placeObject(map.getWidth()-8, 1, 'exit');
|
76 |
+
}
|
77 |
+
else if(exit_place == 1){
|
78 |
+
map.placeObject(map.getWidth()-18, 1, 'exit');
|
79 |
+
}
|
80 |
+
else if(exit_place == 2){
|
81 |
+
map.placeObject(map.getWidth()-13, 2, 'exit');
|
82 |
+
}
|
83 |
+
else if(exit_place == 3){
|
84 |
+
map.placeObject(map.getWidth()-8, 4, 'exit')
|
85 |
+
}
|
86 |
+
else if(exit_place == 4){
|
87 |
+
map.placeObject(map.getWidth()-8, 7, 'exit')
|
88 |
+
}
|
89 |
+
else{
|
90 |
+
map.placeObject(map.getWidth()-16, 6, 'exit')
|
91 |
+
}
|
92 |
+
|
93 |
+
#BEGIN_EDITABLE#
|
94 |
+
|
95 |
+
#END_EDITABLE#
|
96 |
+
|
97 |
+
#END_OF_START_LEVEL#
|
98 |
+
}
|
99 |
+
|
100 |
+
function validateLevel(map) {
|
101 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
102 |
+
}
|
levels/bonus/AB_2_FrozenCave.jsx
ADDED
@@ -0,0 +1,144 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.0.2",
|
4 |
+
"mapProperties": {
|
5 |
+
"allowOverwrite": true
|
6 |
+
},
|
7 |
+
"nextBonusLevel": "AB_3_BoulderMadness.jsx"
|
8 |
+
}
|
9 |
+
#END_PROPERTIES#
|
10 |
+
/**************************
|
11 |
+
* FrozenCave.js *
|
12 |
+
**************************
|
13 |
+
* So you did it.
|
14 |
+
*
|
15 |
+
* You found the cave.
|
16 |
+
*
|
17 |
+
* To be frank I didn't think
|
18 |
+
* you had it in you.
|
19 |
+
*
|
20 |
+
* Lets see you in this challenge.
|
21 |
+
*
|
22 |
+
* And no my name is not Frank.
|
23 |
+
*
|
24 |
+
* Every traveller knows that the
|
25 |
+
* adventures never truly end.
|
26 |
+
*/
|
27 |
+
|
28 |
+
function getRandomInt(min, max) {
|
29 |
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
30 |
+
}
|
31 |
+
|
32 |
+
function startLevel(map) {
|
33 |
+
#START_OF_START_LEVEL#
|
34 |
+
var savedX, savedY, savedDirection;
|
35 |
+
map.defineObject('ice', {
|
36 |
+
'symbol': String.fromCharCode(0x2630), 'color': '#75D1FF',
|
37 |
+
'impassable': function(player, me) {
|
38 |
+
savedX = player.getX();
|
39 |
+
savedY = player.getY();
|
40 |
+
return false;
|
41 |
+
},
|
42 |
+
'onCollision': function(player) {
|
43 |
+
if (player.getX() == savedX) {
|
44 |
+
if (player.getY() > savedY) {
|
45 |
+
savedDirection = 'down';
|
46 |
+
} else {
|
47 |
+
savedDirection = 'up';
|
48 |
+
}
|
49 |
+
} else {
|
50 |
+
if (player.getX() > savedX) {
|
51 |
+
savedDirection = 'right';
|
52 |
+
} else {
|
53 |
+
savedDirection = 'left';
|
54 |
+
}
|
55 |
+
}
|
56 |
+
var dirs = ['up', 'down', 'left', 'right'];
|
57 |
+
for (var d=0;d<dirs.length;d++) {
|
58 |
+
if (dirs[d] != savedDirection) {
|
59 |
+
map.overrideKey(dirs[d], function(){});
|
60 |
+
}
|
61 |
+
}
|
62 |
+
}
|
63 |
+
});
|
64 |
+
|
65 |
+
map.startTimer(function() {
|
66 |
+
var player = map.getPlayer();
|
67 |
+
var x = player.getX(), y = player.getY();
|
68 |
+
if (map.getObjectTypeAt(x,y) == 'ice') {
|
69 |
+
player.move(savedDirection);
|
70 |
+
}
|
71 |
+
if (player.getX() == x && player.getY() == y) {
|
72 |
+
map.overrideKey('up', null);
|
73 |
+
map.overrideKey('down', null);
|
74 |
+
map.overrideKey('left', null);
|
75 |
+
map.overrideKey('right', null);
|
76 |
+
}
|
77 |
+
},200);
|
78 |
+
|
79 |
+
map.defineObject('boulder', {
|
80 |
+
'symbol': String.fromCharCode(0x2617),
|
81 |
+
'color' : '#5C1F00',
|
82 |
+
'impassable': true
|
83 |
+
});
|
84 |
+
|
85 |
+
map.createFromGrid(
|
86 |
+
['##################################################',
|
87 |
+
'##xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx##',
|
88 |
+
'##xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx##',
|
89 |
+
'##xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx##',
|
90 |
+
'##xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx##',
|
91 |
+
'##xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx##',
|
92 |
+
'##xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx##',
|
93 |
+
'##xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx#E#xxxxx##',
|
94 |
+
'##xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###xxxxx##',
|
95 |
+
'##xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx##',
|
96 |
+
'##xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx##',
|
97 |
+
'##xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx##',
|
98 |
+
'##xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx##',
|
99 |
+
'##xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx##',
|
100 |
+
'##xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx##',
|
101 |
+
'##xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx##',
|
102 |
+
'##xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx##',
|
103 |
+
'##xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx##',
|
104 |
+
'##xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx##',
|
105 |
+
'##xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx##',
|
106 |
+
'##xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx##',
|
107 |
+
'###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx##',
|
108 |
+
'#####C#xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###',
|
109 |
+
'#### ###########################################',
|
110 |
+
'#### @ ###########################################'],
|
111 |
+
{
|
112 |
+
'@': 'player',
|
113 |
+
'E': 'exit',
|
114 |
+
'#': 'boulder',
|
115 |
+
'x': 'ice',
|
116 |
+
'C': 'computer',
|
117 |
+
}, 0, 0);
|
118 |
+
|
119 |
+
for (var i = 0; i < 75; i++) {
|
120 |
+
var player = map.getPlayer();
|
121 |
+
var x = getRandomInt(0, map.getWidth() - 1);
|
122 |
+
var y = getRandomInt(0, map.getHeight() - 1);
|
123 |
+
if ((x != player.getX() || y != player.getY())
|
124 |
+
&& (x != map.getWidth()-9 || y != 7)
|
125 |
+
&& (x != map.getWidth()-9 || y != 6)
|
126 |
+
&& (x != player.getX() || y != map.getHeight()-2)
|
127 |
+
&& (x != player.getX() || y != map.getHeight()-3)
|
128 |
+
&& (x != player.getX() || y != map.getHeight()-4)) {
|
129 |
+
map.placeObject(x, y, 'boulder');
|
130 |
+
}
|
131 |
+
}
|
132 |
+
#BEGIN_EDITABLE#
|
133 |
+
|
134 |
+
#END_EDITABLE#
|
135 |
+
|
136 |
+
#END_OF_START_LEVEL#
|
137 |
+
}
|
138 |
+
|
139 |
+
function validateLevel(map) {
|
140 |
+
map.validateExactlyXManyObjects(0, 'phone');
|
141 |
+
map.validateExactlyXManyObjects(0, 'theAlgorithm');
|
142 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
143 |
+
map.validateAtMostXDynamicObjects(0);
|
144 |
+
}
|
levels/bonus/AB_3_BoulderMadness.jsx
ADDED
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.0.1",
|
4 |
+
"nextBonusLevel": "AB_4_BatAttack.jsx"
|
5 |
+
}
|
6 |
+
#END_PROPERTIES#
|
7 |
+
/********************************
|
8 |
+
* BoulderMadness.js *
|
9 |
+
********************************
|
10 |
+
*
|
11 |
+
* Getting through the ice was not easy,
|
12 |
+
* in this section of the cave
|
13 |
+
* some of the snowy boulders maybe be movable,
|
14 |
+
* or maybe you can even squeeze yourself through them,
|
15 |
+
* but be careful, pushing too hard might get you stuck,
|
16 |
+
* or worse...
|
17 |
+
* You need a way to distinguish danger...
|
18 |
+
* and danger is usually red!
|
19 |
+
*
|
20 |
+
* Every traveller knows that the
|
21 |
+
* adventures never truly end.
|
22 |
+
*/
|
23 |
+
|
24 |
+
function getRandomInt(min, max) {
|
25 |
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
26 |
+
}
|
27 |
+
|
28 |
+
function startLevel(map) {
|
29 |
+
#START_OF_START_LEVEL#
|
30 |
+
|
31 |
+
map.placePlayer(1, 1);
|
32 |
+
|
33 |
+
map.placeObject(map.getWidth()-2, map.getHeight()-2, 'exit');
|
34 |
+
|
35 |
+
map.defineObject('boulder', {
|
36 |
+
#{# #}#
|
37 |
+
'symbol': String.fromCharCode(0x2617),
|
38 |
+
'impassable': true
|
39 |
+
});
|
40 |
+
|
41 |
+
map.defineObject('movingBoulder', {
|
42 |
+
#{# #}#
|
43 |
+
'symbol': String.fromCharCode(0x2617),
|
44 |
+
'pushable': true,
|
45 |
+
'type': 'dynamic',
|
46 |
+
});
|
47 |
+
|
48 |
+
map.defineObject('trapBoulder', {
|
49 |
+
#{# #}#
|
50 |
+
'symbol': String.fromCharCode(0x2617),
|
51 |
+
'pushable': true,
|
52 |
+
'type': 'dynamic',
|
53 |
+
'onCollision': function (player) {
|
54 |
+
player.killedBy('Got trapped under boulder');
|
55 |
+
},
|
56 |
+
});
|
57 |
+
|
58 |
+
|
59 |
+
for (var i = 0; i < 580; i++) {
|
60 |
+
var player = map.getPlayer();
|
61 |
+
var x = getRandomInt(0, map.getWidth() - 1);
|
62 |
+
var y = getRandomInt(0, map.getHeight() - 1);
|
63 |
+
if ((x != player.getX() || y != player.getY())
|
64 |
+
&& (x != map.getWidth()-9 || y != 7)
|
65 |
+
&& (x != map.getWidth()-9 || y != 6)
|
66 |
+
&& (x != player.getX() || y != map.getHeight()-2)
|
67 |
+
&& (x != player.getX() || y != map.getHeight()-3)
|
68 |
+
&& (x != player.getX() || y != map.getHeight()-4)) {
|
69 |
+
var placement = getRandomInt(0,15);
|
70 |
+
if (map.getObjectTypeAt(x, y)=== "empty") {
|
71 |
+
if ( placement < 8) {
|
72 |
+
map.placeObject(x, y, 'movingBoulder');
|
73 |
+
} else if (placement < 13) {
|
74 |
+
map.placeObject(x, y, 'boulder');
|
75 |
+
} else {
|
76 |
+
map.placeObject(x, y, 'trapBoulder');
|
77 |
+
}
|
78 |
+
} else {
|
79 |
+
i = i -1;
|
80 |
+
}
|
81 |
+
}
|
82 |
+
}
|
83 |
+
|
84 |
+
|
85 |
+
#END_OF_START_LEVEL#
|
86 |
+
}
|
87 |
+
|
88 |
+
function validateLevel(map) {
|
89 |
+
map.validateExactlyXManyObjects(0, 'phone');
|
90 |
+
map.validateExactlyXManyObjects(0, 'theAlgorithm');
|
91 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
92 |
+
}
|
levels/bonus/AB_4_BatAttack.jsx
ADDED
@@ -0,0 +1,115 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.0",
|
4 |
+
"commandsIntroduced":
|
5 |
+
["object.passableFor",
|
6 |
+
"map.validateExactlyXManyObjects"],
|
7 |
+
"nextBonusLevel": "AB_5_PathOfDoom.jsx"
|
8 |
+
}
|
9 |
+
#END_PROPERTIES#
|
10 |
+
/****************************
|
11 |
+
* BatAttack.js *
|
12 |
+
****************************
|
13 |
+
*
|
14 |
+
* As you proceed into the cave
|
15 |
+
* you notice some creatures hiding in the darkness.
|
16 |
+
* They seem to be asleep... Proceed with care though,
|
17 |
+
* for they tend to sleep lightly.
|
18 |
+
* Sneaky or smart, you never truly had an option.
|
19 |
+
*
|
20 |
+
* Every traveller knows that the
|
21 |
+
* adventures never truly end.
|
22 |
+
*/
|
23 |
+
|
24 |
+
|
25 |
+
function startLevel(map) {
|
26 |
+
#START_OF_START_LEVEL#
|
27 |
+
|
28 |
+
function wakeAndHunt(obj, type) {
|
29 |
+
var direction;
|
30 |
+
var target = obj.findNearest(type);
|
31 |
+
var leftDist = obj.getX() - target.x;
|
32 |
+
var upDist = obj.getY() - target.y;
|
33 |
+
|
34 |
+
if (Math.abs(upDist) < 4 && Math.abs(leftDist) < 8) {
|
35 |
+
if (upDist == 0 && leftDist == 0) {
|
36 |
+
return;
|
37 |
+
} if (upDist > 0 && upDist >= leftDist) {
|
38 |
+
direction = 'up';
|
39 |
+
} else if (upDist < 0 && upDist < leftDist) {
|
40 |
+
direction = 'down';
|
41 |
+
} else if (leftDist > 0 && leftDist >= upDist) {
|
42 |
+
direction = 'left';
|
43 |
+
} else {
|
44 |
+
direction = 'right';
|
45 |
+
}
|
46 |
+
obj.move(direction);
|
47 |
+
}
|
48 |
+
}
|
49 |
+
|
50 |
+
map.defineObject('bat', {
|
51 |
+
'type': 'dynamic',
|
52 |
+
'symbol': String.fromCharCode(0x03E1),
|
53 |
+
'color': 'purple',
|
54 |
+
'onCollision': function (player) {
|
55 |
+
player.killedBy('a bat');
|
56 |
+
},
|
57 |
+
'behavior': function (me) {
|
58 |
+
wakeAndHunt(me, 'player');
|
59 |
+
}
|
60 |
+
});
|
61 |
+
|
62 |
+
map.defineObject('boulder', {
|
63 |
+
'color' : '#5C1F00',
|
64 |
+
'symbol': String.fromCharCode(0x2617),
|
65 |
+
'impassable': true,
|
66 |
+
'passableFor': ['bat']
|
67 |
+
});
|
68 |
+
|
69 |
+
map.createFromGrid(
|
70 |
+
['##################################################',
|
71 |
+
'#################################### E#########',
|
72 |
+
'############# ############## #########',
|
73 |
+
'############ ############ #########',
|
74 |
+
'########## # ######### ################',
|
75 |
+
'######### #B# ###BBB### ################',
|
76 |
+
'####### #BBB# ######### ###############',
|
77 |
+
'######## ####### ###BBB### ##############',
|
78 |
+
'####### ######### ######### #############',
|
79 |
+
'######## ####### ######### ##############',
|
80 |
+
'####### ###BBB### ###BBB### #############',
|
81 |
+
'###BBB## ####### ######### ##############',
|
82 |
+
'####### ######### ######### #############',
|
83 |
+
'######## ##BBB## ######### ##############',
|
84 |
+
'####### ######### ##BBB#### #############',
|
85 |
+
'##BBB### ####### ######### ##############',
|
86 |
+
'####### ######### ######## ##############',
|
87 |
+
'######## ####### ####### ################',
|
88 |
+
'####### ###BBB### #BBB# #################',
|
89 |
+
'######## ####### #B# ##################',
|
90 |
+
'####### ########## # ###################',
|
91 |
+
'#### ######### ####################',
|
92 |
+
'#### ########### #####################',
|
93 |
+
'#### @ #######################################',
|
94 |
+
'##################################################'],
|
95 |
+
{
|
96 |
+
'@': 'player',
|
97 |
+
'E': 'exit',
|
98 |
+
'#': 'boulder',
|
99 |
+
'B': 'bat',
|
100 |
+
}, 0, 0);
|
101 |
+
|
102 |
+
#BEGIN_EDITABLE#
|
103 |
+
|
104 |
+
|
105 |
+
|
106 |
+
|
107 |
+
#END_EDITABLE#
|
108 |
+
|
109 |
+
#END_OF_START_LEVEL#
|
110 |
+
}
|
111 |
+
|
112 |
+
function validateLevel(map) {
|
113 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
114 |
+
}
|
115 |
+
|
levels/bonus/AB_5_PathOfDoom.jsx
ADDED
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.0"
|
4 |
+
}
|
5 |
+
#END_PROPERTIES#
|
6 |
+
/********************************
|
7 |
+
* PathOfDooM.js *
|
8 |
+
********************************
|
9 |
+
*
|
10 |
+
* The path ahead is a treacherous one
|
11 |
+
* and bears many dangers. The trap is
|
12 |
+
* not to be feared, but trampled for
|
13 |
+
* it is the only way forward. Don't
|
14 |
+
* forget that what keeps you in here
|
15 |
+
* might as well be the only thing still
|
16 |
+
* protecting you.
|
17 |
+
*
|
18 |
+
* Every traveller knows that the
|
19 |
+
* adventures never truly end.
|
20 |
+
*/
|
21 |
+
|
22 |
+
|
23 |
+
function startLevel(map) {
|
24 |
+
#START_OF_START_LEVEL#
|
25 |
+
|
26 |
+
|
27 |
+
map.defineObject('boulder', {
|
28 |
+
'symbol': String.fromCharCode(0x2617),
|
29 |
+
'color' : '#5C1F00',
|
30 |
+
'impassable': true
|
31 |
+
});
|
32 |
+
|
33 |
+
|
34 |
+
map.defineObject('plate', {
|
35 |
+
'type': 'static',
|
36 |
+
'symbol': String.fromCharCode(0x2617),
|
37 |
+
'color': 'white',
|
38 |
+
'onCollision': function (me) {
|
39 |
+
map.startTimer(arrows, 200);
|
40 |
+
},
|
41 |
+
});
|
42 |
+
|
43 |
+
map.defineObject('switch', {
|
44 |
+
'type': 'static',
|
45 |
+
'symbol': String.fromCharCode(0x2617),
|
46 |
+
'color': 'red',
|
47 |
+
'onCollision': function (me) {
|
48 |
+
#BEGIN_EDITABLE#
|
49 |
+
|
50 |
+
|
51 |
+
|
52 |
+
|
53 |
+
#END_EDITABLE#
|
54 |
+
}
|
55 |
+
|
56 |
+
});
|
57 |
+
|
58 |
+
map.defineObject('arrow', {
|
59 |
+
'type': 'dynamic',
|
60 |
+
'symbol': '<',
|
61 |
+
'color': 'green',
|
62 |
+
'interval': 100,
|
63 |
+
'projectile': true,
|
64 |
+
'behavior': function (me) {
|
65 |
+
me.move('left');
|
66 |
+
}
|
67 |
+
});
|
68 |
+
|
69 |
+
function arrows() {
|
70 |
+
for (var x = 8; x <= 12; x++) {
|
71 |
+
map.placeObject(map.getWidth()-3, x, 'arrow');
|
72 |
+
}
|
73 |
+
}
|
74 |
+
|
75 |
+
map.createFromGrid(
|
76 |
+
['##################################################',
|
77 |
+
'##################################################',
|
78 |
+
'##### S ##########################################',
|
79 |
+
'#### ########################################',
|
80 |
+
'##### ########################################',
|
81 |
+
'###### #######################################',
|
82 |
+
'##### ########################################',
|
83 |
+
'#### ########################################',
|
84 |
+
'#### ##',
|
85 |
+
'#### ##',
|
86 |
+
'### ##',
|
87 |
+
'##### ##',
|
88 |
+
'###### ##',
|
89 |
+
'########p################################# #####',
|
90 |
+
'####### ################################ #####',
|
91 |
+
'####### ############################### #####',
|
92 |
+
'####### ############################### #####',
|
93 |
+
'######## ############################## #####',
|
94 |
+
'####### ############################## #####',
|
95 |
+
'####### ############################## #####',
|
96 |
+
'###### ############################### E #####',
|
97 |
+
'#### #####################################',
|
98 |
+
'#### @ ######################################',
|
99 |
+
'##### #######################################',
|
100 |
+
'###### ########################################'],
|
101 |
+
{
|
102 |
+
'@': 'player',
|
103 |
+
'E': 'exit',
|
104 |
+
'S': 'switch',
|
105 |
+
'p': 'plate',
|
106 |
+
'#': 'boulder'
|
107 |
+
}, 0, 0);
|
108 |
+
|
109 |
+
|
110 |
+
#END_OF_START_LEVEL#
|
111 |
+
}
|
112 |
+
|
113 |
+
function validateLevel(map) {
|
114 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
115 |
+
}
|
116 |
+
|
levels/bonus/AB_6_Credits
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.0",
|
4 |
+
"mapProperties": {
|
5 |
+
"allowOverwrite": true
|
6 |
+
}
|
7 |
+
}
|
8 |
+
#END_PROPERTIES#
|
9 |
+
/***************************
|
10 |
+
* ANewJourney.js *
|
11 |
+
***************************
|
12 |
+
* Hello young traveler!
|
13 |
+
*
|
14 |
+
* There will always be dire need
|
15 |
+
* of an adventurer to brave the dangers
|
16 |
+
* and use his wits to escape the traps
|
17 |
+
* and face that which others lack the
|
18 |
+
* power to.
|
19 |
+
*
|
20 |
+
* You now know and you can see it.
|
21 |
+
*
|
22 |
+
* It is the courage and the willpower
|
23 |
+
* to do so, despite the fear and the
|
24 |
+
* consequences, to pull through where
|
25 |
+
* others would simply stop...
|
26 |
+
*
|
27 |
+
* Every traveller knows that the
|
28 |
+
* adventures never truly end.
|
29 |
+
*/
|
30 |
+
|
31 |
+
function startLevel(map) {
|
32 |
+
|
33 |
+
map.placePlayer(20,20);
|
34 |
+
|
35 |
+
#START_OF_START_LEVEL#
|
36 |
+
|
37 |
+
#BEGIN_EDITABLE#
|
38 |
+
|
39 |
+
#END_EDITABLE#
|
40 |
+
|
41 |
+
#END_OF_START_LEVEL#
|
42 |
+
}
|
levels/bonus/_sampleLevel.jsx
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.2.1",
|
4 |
+
"commandsIntroduced": ['object.pushable'],
|
5 |
+
"music": "Brazil"
|
6 |
+
}
|
7 |
+
#END_PROPERTIES#
|
8 |
+
/********************
|
9 |
+
* sampleLevel.js *
|
10 |
+
* by AlexNisnevich *
|
11 |
+
********************
|
12 |
+
*
|
13 |
+
*/
|
14 |
+
|
15 |
+
function startLevel(map) {
|
16 |
+
#START_OF_START_LEVEL#
|
17 |
+
map.placePlayer(0, 12);
|
18 |
+
map.placeObject(map.getWidth()/2, map.getHeight()/2, 'exit');
|
19 |
+
#END_OF_START_LEVEL#
|
20 |
+
}
|
levels/bonus/darkAlley.jsx
ADDED
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.0",
|
4 |
+
"commandsIntroduced": []
|
5 |
+
}
|
6 |
+
#END_PROPERTIES#
|
7 |
+
/******************
|
8 |
+
* darkAlley.jsx *
|
9 |
+
* by aquang9124 *
|
10 |
+
******************
|
11 |
+
*
|
12 |
+
* Good evening, Dr.
|
13 |
+
*
|
14 |
+
* You wake up in a dark alleyway and have no recollection of
|
15 |
+
* how you got here. There's nothing in your pockets except
|
16 |
+
* lint. You hear footsteps closing in on your location...
|
17 |
+
*
|
18 |
+
*/
|
19 |
+
|
20 |
+
function startLevel(map) {
|
21 |
+
#START_OF_START_LEVEL#
|
22 |
+
|
23 |
+
map.defineObject('thug', {
|
24 |
+
'symbol': String.fromCharCode(0x2620),
|
25 |
+
'onCollision': function(player) {
|
26 |
+
if ( !player.hasItem('goldengun') ) {
|
27 |
+
player.killedBy('vicious thug');
|
28 |
+
} else {
|
29 |
+
map.writeStatus('You are invincible!');
|
30 |
+
}
|
31 |
+
}
|
32 |
+
});
|
33 |
+
|
34 |
+
map.defineObject('bluedoor', {
|
35 |
+
'symbol': '-',
|
36 |
+
'color': 'blue',
|
37 |
+
'impassable': function(player) {
|
38 |
+
if (player.getColor() === '#0f0') {
|
39 |
+
player.setColor('orange');
|
40 |
+
this.color = 'red';
|
41 |
+
return false;
|
42 |
+
}
|
43 |
+
return true;
|
44 |
+
}
|
45 |
+
});
|
46 |
+
|
47 |
+
map.defineObject('goldengun', {
|
48 |
+
'symbol': String.fromCharCode(0x122),
|
49 |
+
type: 'item',
|
50 |
+
'onPickUp': function(player) {
|
51 |
+
map.writeStatus('You have the golden gun!');
|
52 |
+
|
53 |
+
if (player.getColor() === "orange") {
|
54 |
+
player.setColor('#0f0');
|
55 |
+
}
|
56 |
+
}
|
57 |
+
});
|
58 |
+
|
59 |
+
var alleyX = parseInt(map.getWidth() / 2);
|
60 |
+
var alleyY = parseInt(map.getHeight() / 2) - 5;
|
61 |
+
|
62 |
+
map.createFromGrid(['#######',
|
63 |
+
'# E #',
|
64 |
+
'# #',
|
65 |
+
'# #',
|
66 |
+
'# #',
|
67 |
+
'# #',
|
68 |
+
'# T #',
|
69 |
+
'# T',
|
70 |
+
'#T ##',
|
71 |
+
'#L#TLL#',
|
72 |
+
'# #',
|
73 |
+
'###T#L#',
|
74 |
+
'# P #',
|
75 |
+
'#######'],
|
76 |
+
{
|
77 |
+
'E': 'exit',
|
78 |
+
'#': 'block',
|
79 |
+
'G': 'goldengun',
|
80 |
+
'T': 'thug',
|
81 |
+
'L': 'bluedoor',
|
82 |
+
'P': 'player'
|
83 |
+
}, alleyX, alleyY);
|
84 |
+
#BEGIN_EDITABLE#
|
85 |
+
map.placeObject(20, 20, 'goldengun');
|
86 |
+
#END_EDITABLE#
|
87 |
+
|
88 |
+
#END_OF_START_LEVEL#
|
89 |
+
}
|
90 |
+
|
91 |
+
function onExit(map) {
|
92 |
+
map.writeStatus("You have escaped the dark alley.");
|
93 |
+
return true;
|
94 |
+
}
|
95 |
+
|
96 |
+
function validateLevel(map) {
|
97 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
98 |
+
}
|
levels/bonus/ice.jsx
ADDED
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "0.1",
|
4 |
+
"commandsIntroduced": []
|
5 |
+
}
|
6 |
+
#END_PROPERTIES#
|
7 |
+
/*******************
|
8 |
+
* ice.js *
|
9 |
+
* by mdejean *
|
10 |
+
*******************
|
11 |
+
*
|
12 |
+
*/
|
13 |
+
|
14 |
+
function startLevel(map) {
|
15 |
+
#START_OF_START_LEVEL#
|
16 |
+
var savedX, savedY, savedDirection;
|
17 |
+
map.defineObject('ice', {
|
18 |
+
'symbol': '.', 'color': '#00f',
|
19 |
+
'impassable': function(player, me) {
|
20 |
+
savedX = player.getX();
|
21 |
+
savedY = player.getY();
|
22 |
+
return false;
|
23 |
+
},
|
24 |
+
'onCollision': function(player) {
|
25 |
+
if (player.getX() == savedX) {
|
26 |
+
if (player.getY() > savedY) {
|
27 |
+
savedDirection = 'down';
|
28 |
+
} else {
|
29 |
+
savedDirection = 'up';
|
30 |
+
}
|
31 |
+
} else {
|
32 |
+
if (player.getX() > savedX) {
|
33 |
+
savedDirection = 'right';
|
34 |
+
} else {
|
35 |
+
savedDirection = 'left';
|
36 |
+
}
|
37 |
+
}
|
38 |
+
var dirs = ['up', 'down', 'left', 'right'];
|
39 |
+
for (var d=0;d<dirs.length;d++) {
|
40 |
+
if (dirs[d] != savedDirection) {
|
41 |
+
map.overrideKey(dirs[d], function(){});
|
42 |
+
}
|
43 |
+
}
|
44 |
+
}
|
45 |
+
});
|
46 |
+
map.startTimer(function() {
|
47 |
+
var player = map.getPlayer();
|
48 |
+
var x = player.getX(), y = player.getY();
|
49 |
+
if (map.getObjectTypeAt(x,y) == 'ice') {
|
50 |
+
player.move(savedDirection);
|
51 |
+
}
|
52 |
+
if (player.getX() == x && player.getY() == y) {
|
53 |
+
map.overrideKey('up', null);
|
54 |
+
map.overrideKey('down', null);
|
55 |
+
map.overrideKey('left', null);
|
56 |
+
map.overrideKey('right', null);
|
57 |
+
}
|
58 |
+
},200);
|
59 |
+
map.createFromGrid(
|
60 |
+
['+++++++++++++++++++++++++++++++',
|
61 |
+
'+ +++ +',
|
62 |
+
'+ ++E+ +',
|
63 |
+
'+ xxxx +',
|
64 |
+
'+ xxxx +',
|
65 |
+
'+ xxxx +',
|
66 |
+
'+ xxxx +',
|
67 |
+
'+ @+++ +',
|
68 |
+
'+ +',
|
69 |
+
'+ +',
|
70 |
+
'+ +',
|
71 |
+
'+ +',
|
72 |
+
'+ +',
|
73 |
+
'+ +',
|
74 |
+
'+++++++++++++++++++++++++++++++'],
|
75 |
+
{
|
76 |
+
'@': 'player',
|
77 |
+
'E': 'exit',
|
78 |
+
'+': 'block',
|
79 |
+
'x': 'ice',
|
80 |
+
}, 6, 6);
|
81 |
+
#BEGIN_EDITABLE#
|
82 |
+
|
83 |
+
#END_EDITABLE#
|
84 |
+
|
85 |
+
#END_OF_START_LEVEL#
|
86 |
+
}
|
87 |
+
|
88 |
+
function validateLevel(map) {
|
89 |
+
map.validateExactlyXManyObjects(0, 'phone');
|
90 |
+
map.validateExactlyXManyObjects(0, 'theAlgorithm');
|
91 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
92 |
+
map.validateAtMostXDynamicObjects(0);
|
93 |
+
}
|
levels/bonus/labryinth.jsx
ADDED
@@ -0,0 +1,308 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "1.2.2",
|
4 |
+
"commandsIntroduced": [],
|
5 |
+
"music": "Brazil"
|
6 |
+
}
|
7 |
+
#END_PROPERTIES#
|
8 |
+
|
9 |
+
|
10 |
+
function startLevel(map) {
|
11 |
+
#START_OF_START_LEVEL#
|
12 |
+
var savedX, savedY, savedDirection;
|
13 |
+
|
14 |
+
function moveToward(obj, type) {
|
15 |
+
var target = obj.findNearest(type);
|
16 |
+
var leftDist = obj.getX() - target.x;
|
17 |
+
var upDist = obj.getY() - target.y;
|
18 |
+
|
19 |
+
var direction;
|
20 |
+
if (upDist == 0 && leftDist == 0) {
|
21 |
+
return;
|
22 |
+
} if (upDist > 0 && upDist >= leftDist) {
|
23 |
+
direction = 'up';
|
24 |
+
} else if (upDist < 0 && upDist < leftDist) {
|
25 |
+
direction = 'down';
|
26 |
+
} else if (leftDist > 0 && leftDist >= upDist) {
|
27 |
+
direction = 'left';
|
28 |
+
} else {
|
29 |
+
direction = 'right';
|
30 |
+
}
|
31 |
+
|
32 |
+
if (obj.canMove(direction)) {
|
33 |
+
obj.move(direction);
|
34 |
+
}
|
35 |
+
}
|
36 |
+
|
37 |
+
function shuffle(o){ //v1.0 [http://bit.ly/1l6LGQT]
|
38 |
+
for(var j, x, i = o.length; i; j = Math.floor(Math.random() * i),
|
39 |
+
x = o[--i], o[i] = o[j], o[j] = x);
|
40 |
+
return o;
|
41 |
+
};
|
42 |
+
map.defineObject('ice', {
|
43 |
+
'symbol': String.fromCharCode(0x2630), 'color': '#75D1FF',
|
44 |
+
'impassable': function(player, me) {
|
45 |
+
savedX = player.getX();
|
46 |
+
savedY = player.getY();
|
47 |
+
return false;
|
48 |
+
},
|
49 |
+
'onCollision': function(player) {
|
50 |
+
if (player.getX() == savedX) {
|
51 |
+
if (player.getY() > savedY) {
|
52 |
+
savedDirection = 'down';
|
53 |
+
} else {
|
54 |
+
savedDirection = 'up';
|
55 |
+
}
|
56 |
+
} else {
|
57 |
+
if (player.getX() > savedX) {
|
58 |
+
savedDirection = 'right';
|
59 |
+
} else {
|
60 |
+
savedDirection = 'left';
|
61 |
+
}
|
62 |
+
}
|
63 |
+
var dirs = ['up', 'down', 'left', 'right'];
|
64 |
+
for (var d=0;d<dirs.length;d++) {
|
65 |
+
if (dirs[d] != savedDirection) {
|
66 |
+
map.overrideKey(dirs[d], function(){});
|
67 |
+
}
|
68 |
+
}
|
69 |
+
}
|
70 |
+
});
|
71 |
+
|
72 |
+
map.startTimer(function() {
|
73 |
+
var player = map.getPlayer();
|
74 |
+
var x = player.getX(), y = player.getY();
|
75 |
+
if (map.getObjectTypeAt(x,y) == 'ice') {
|
76 |
+
player.move(savedDirection);
|
77 |
+
}
|
78 |
+
if (player.getX() == x && player.getY() == y) {
|
79 |
+
map.overrideKey('up', null);
|
80 |
+
map.overrideKey('down', null);
|
81 |
+
map.overrideKey('left', null);
|
82 |
+
map.overrideKey('right', null);
|
83 |
+
}
|
84 |
+
},200);
|
85 |
+
|
86 |
+
map.defineObject('boulder', {
|
87 |
+
'symbol': String.fromCharCode(0x2617),
|
88 |
+
'color' : '#5C1F00',
|
89 |
+
'impassable': true
|
90 |
+
});
|
91 |
+
|
92 |
+
map.defineObject('water', {
|
93 |
+
'symbol': '░',
|
94 |
+
'color': '#44f',
|
95 |
+
'onCollision': function (player) {
|
96 |
+
player.killedBy#{#('drowning in deep dark water')#}#;
|
97 |
+
}
|
98 |
+
});
|
99 |
+
|
100 |
+
map.defineObject('invisibleBoulder', {
|
101 |
+
'symbol' : String.fromCharCode(0x2617),
|
102 |
+
'color' : '#000000',
|
103 |
+
'impassable' : true
|
104 |
+
});
|
105 |
+
|
106 |
+
map.defineObject('zombie', {
|
107 |
+
'type': 'dynamic',
|
108 |
+
'symbol': 'z',
|
109 |
+
'color': 'red',
|
110 |
+
'onCollision': function (player) {
|
111 |
+
player.killedBy('Zombie');
|
112 |
+
},
|
113 |
+
'behavior': function (me) {
|
114 |
+
#BEGIN_EDITABLE#
|
115 |
+
var player = map.getPlayer();
|
116 |
+
var x = player.getX();
|
117 |
+
var y = player.getY();
|
118 |
+
/*Hint: There is a me.canMove method for zombies, for example if me.canMove('right')
|
119 |
+
is true, then it means that the zombie is able to move right at that specific point in time
|
120 |
+
//Hint 2: You can specify where the zombie will move with ex: me.move('right')
|
121 |
+
*/
|
122 |
+
if(x > 40 && x < 45){
|
123 |
+
if(y >= 13){
|
124 |
+
moveToward(me, 'player');
|
125 |
+
}
|
126 |
+
}
|
127 |
+
#END_EDITABLE#
|
128 |
+
}
|
129 |
+
});
|
130 |
+
map.defineObject('blueLock', {
|
131 |
+
'symbol': String.fromCharCode(0x2297),
|
132 |
+
'color': '#06f',
|
133 |
+
'impassable': function (player) {
|
134 |
+
if (player.hasItem('blueKey')) {
|
135 |
+
player.removeItem('blueKey');
|
136 |
+
return false;
|
137 |
+
} else {
|
138 |
+
return true;
|
139 |
+
}
|
140 |
+
}
|
141 |
+
});
|
142 |
+
|
143 |
+
map.defineObject('yellowLock', {
|
144 |
+
'symbol': String.fromCharCode(0x2297),
|
145 |
+
'color': 'yellow',
|
146 |
+
'impassable': function (player) {
|
147 |
+
if (player.hasItem('yellowKey')) {
|
148 |
+
player.removeItem('yellowKey');
|
149 |
+
return false;
|
150 |
+
} else {
|
151 |
+
return true;
|
152 |
+
}
|
153 |
+
}
|
154 |
+
});
|
155 |
+
|
156 |
+
map.createFromGrid([
|
157 |
+
'o # # ',
|
158 |
+
'xx # # ',
|
159 |
+
'xx # B E ',
|
160 |
+
'xx # # ',
|
161 |
+
'xx # # ',
|
162 |
+
'xx # #############',
|
163 |
+
' # b',
|
164 |
+
'### ##Y####################',
|
165 |
+
' # # ',
|
166 |
+
' # ######### #############',
|
167 |
+
' # #xxxxxxxxxxxxxxxxxxxxx ',
|
168 |
+
'xx #y xxxxxxxxxxxx ',
|
169 |
+
'xx ############################################# ',
|
170 |
+
'xx o # ',
|
171 |
+
'xx# ## ## # ',
|
172 |
+
'xx# ##wwwwwwwwww## # ',
|
173 |
+
'xx# ##wwwwwwwwww## # ',
|
174 |
+
'xx# ##wwwwwwwwww## # ',
|
175 |
+
'xx# ##wwwwwwwwww## # ',
|
176 |
+
'xx# ##wwwwwwwwww## # ',
|
177 |
+
'xx# ##wwwwwwwwww## # ',
|
178 |
+
'xx# ##wwwwwwwwww## # ',
|
179 |
+
'xx# ##wwwwwwwwww## # ',
|
180 |
+
'xx# ##wwwwwwwwww## # ',
|
181 |
+
'@ # ##wwwwwwwwww##zzzz '],
|
182 |
+
{
|
183 |
+
'@': 'player',
|
184 |
+
'E': 'exit',
|
185 |
+
'#': 'boulder',
|
186 |
+
'i': 'invisibleBoulder',
|
187 |
+
'x': 'ice',
|
188 |
+
'o': 'teleporter',
|
189 |
+
'w': 'water',
|
190 |
+
'z': 'zombie',
|
191 |
+
'b': 'blueKey',
|
192 |
+
'y': 'yellowKey',
|
193 |
+
'B': 'blueLock',
|
194 |
+
'Y': 'yellowLock',
|
195 |
+
}, 0, 0);
|
196 |
+
function gravity() {
|
197 |
+
var player = map.getPlayer();
|
198 |
+
var x = player.getX();
|
199 |
+
var y = player.getY() + 1;
|
200 |
+
if(x > 2 && x < 27){
|
201 |
+
if(y >= 13){
|
202 |
+
player.move('down');
|
203 |
+
}
|
204 |
+
if(y >= 21){
|
205 |
+
player.killedBy('gravity');
|
206 |
+
}
|
207 |
+
}
|
208 |
+
}
|
209 |
+
map.startTimer(gravity,45);
|
210 |
+
|
211 |
+
function waterGravity() {
|
212 |
+
var player = map.getPlayer();
|
213 |
+
var x = player.getX();
|
214 |
+
var y = player.getY() + 1;
|
215 |
+
if(x > 28 && x < 39) {
|
216 |
+
if(y >= 13){
|
217 |
+
player.move('down');
|
218 |
+
}
|
219 |
+
}
|
220 |
+
}
|
221 |
+
map.startTimer(waterGravity, 45);
|
222 |
+
|
223 |
+
var teleporters = map.getDynamicObjects();
|
224 |
+
teleporters = shuffle(teleporters);
|
225 |
+
var t1, t2;
|
226 |
+
for(var i = 0; i < teleporters.length; i++){
|
227 |
+
if(teleporters[i].getType() == 'teleporter'){
|
228 |
+
t1 = teleporters[i];
|
229 |
+
}
|
230 |
+
}
|
231 |
+
for(var j = teleporters.length - 1; j >= 0; j--){
|
232 |
+
if(teleporters[j].getType() == 'teleporter'){
|
233 |
+
t2 = teleporters[j];
|
234 |
+
}
|
235 |
+
}
|
236 |
+
t1.setTarget(t2);
|
237 |
+
t2.setTarget(t1);
|
238 |
+
|
239 |
+
for(var x = 3; x < 26; x++) {
|
240 |
+
map.placeObject(x, 10, 'invisibleBoulder');
|
241 |
+
}
|
242 |
+
for(var x = 4; x < 27; x++) {
|
243 |
+
map.placeObject(x, 8, 'invisibleBoulder');
|
244 |
+
}
|
245 |
+
for(var x = 0; x < 26; x++) {
|
246 |
+
map.placeObject(x, 6, 'invisibleBoulder');
|
247 |
+
}
|
248 |
+
for(var y = 1; y < 6; y++) {
|
249 |
+
map.placeObject(25, y, 'invisibleBoulder');
|
250 |
+
}
|
251 |
+
for(var y = 0; y < 5; y++) {
|
252 |
+
map.placeObject(23, y, 'invisibleBoulder');
|
253 |
+
}
|
254 |
+
for(var y = 1; y < 6; y++) {
|
255 |
+
map.placeObject(21, y, 'invisibleBoulder');
|
256 |
+
}
|
257 |
+
for(var y = 0; y < 5; y++) {
|
258 |
+
map.placeObject(19, y, 'invisibleBoulder');
|
259 |
+
}
|
260 |
+
for(var y = 1; y < 6; y++) {
|
261 |
+
map.placeObject(17, y, 'invisibleBoulder');
|
262 |
+
}
|
263 |
+
for(var y = 0; y < 5; y++) {
|
264 |
+
map.placeObject(15, y, 'invisibleBoulder');
|
265 |
+
}
|
266 |
+
for(var y = 1; y < 6; y++) {
|
267 |
+
map.placeObject(13, y, 'invisibleBoulder');
|
268 |
+
}
|
269 |
+
for(var y = 0; y < 5; y++) {
|
270 |
+
map.placeObject(11, y, 'invisibleBoulder');
|
271 |
+
}
|
272 |
+
for(var y = 1; y < 6; y++) {
|
273 |
+
map.placeObject(9, y, 'invisibleBoulder');
|
274 |
+
}
|
275 |
+
for(var y = 0; y < 5; y++) {
|
276 |
+
map.placeObject(7, y, 'invisibleBoulder');
|
277 |
+
}
|
278 |
+
for(var y = 1; y < 6; y++) {
|
279 |
+
map.placeObject(5, y, 'invisibleBoulder');
|
280 |
+
}
|
281 |
+
for(var y = 0; y < 5; y++) {
|
282 |
+
map.placeObject(3, y, 'invisibleBoulder');
|
283 |
+
}
|
284 |
+
|
285 |
+
#BEGIN_EDITABLE#
|
286 |
+
for(var x = 43; x < 46; x++) {
|
287 |
+
map.placeObject(x, 1, 'boulder');
|
288 |
+
map.placeObject(x, 3, 'boulder');
|
289 |
+
}
|
290 |
+
map.placeObject(43, 2, 'boulder');
|
291 |
+
map.placeObject(45, 2, 'boulder');
|
292 |
+
map.placeObject(1, 9, 'boulder');
|
293 |
+
map.placeObject(30, 14, 'boulder');
|
294 |
+
map.placeObject(36, 11, 'boulder');
|
295 |
+
for(var x = map.getWidth() - 13; x < map.getWidth() - 1; x++) {
|
296 |
+
map.placeObject(x, 6, 'boulder');
|
297 |
+
}
|
298 |
+
#END_EDITABLE#
|
299 |
+
#END_OF_START_LEVEL#
|
300 |
+
}
|
301 |
+
|
302 |
+
function validateLevel(map) {
|
303 |
+
map.validateExactlyXManyObjects(0, 'phone');
|
304 |
+
map.validateExactlyXManyObjects(0, 'theAlgorithm');
|
305 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
306 |
+
map.validateExactlyXManyObjects(0, 'computer');
|
307 |
+
map.validateAtMostXDynamicObjects(6);
|
308 |
+
}
|
levels/bonus/levelName.jsx
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "0.0",
|
4 |
+
"commandsIntroduced": []
|
5 |
+
}
|
6 |
+
#END_PROPERTIES#
|
7 |
+
/*******************
|
8 |
+
* <level name>.js *
|
9 |
+
* by mdejean *
|
10 |
+
*******************
|
11 |
+
*/
|
12 |
+
|
13 |
+
function startLevel(map) {
|
14 |
+
#START_OF_START_LEVEL#
|
15 |
+
map.defineObject('door', {
|
16 |
+
'symbol': '-', 'color': '#0f0',
|
17 |
+
'impassable': function(player) {
|
18 |
+
if (player.getColor() == this.color) {
|
19 |
+
player.setColor('red');
|
20 |
+
return false;
|
21 |
+
}
|
22 |
+
return true;
|
23 |
+
}
|
24 |
+
});
|
25 |
+
map.createFromGrid(
|
26 |
+
['+++++++++++++++',
|
27 |
+
'+ + +',
|
28 |
+
'+ ++ +',
|
29 |
+
'+ @ ++x +',
|
30 |
+
'+ ++x++',
|
31 |
+
'+ ++E++',
|
32 |
+
'+++++++++++++++'],
|
33 |
+
{
|
34 |
+
'@': 'player',
|
35 |
+
'E': 'exit',
|
36 |
+
'+': 'block',
|
37 |
+
'x': 'door',
|
38 |
+
}, 17, 6);
|
39 |
+
#BEGIN_EDITABLE#
|
40 |
+
|
41 |
+
#END_EDITABLE#
|
42 |
+
|
43 |
+
#END_OF_START_LEVEL#
|
44 |
+
}
|
45 |
+
|
46 |
+
function validateLevel(map) {
|
47 |
+
map.validateExactlyXManyObjects(0, 'phone');
|
48 |
+
map.validateExactlyXManyObjects(0, 'theAlgorithm');
|
49 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
50 |
+
map.validateNoTimers();
|
51 |
+
map.validateAtMostXDynamicObjects(0);
|
52 |
+
}
|
levels/bonus/noWayOut.jsx
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#BEGIN_PROPERTIES#
|
2 |
+
{
|
3 |
+
"version": "0.1000002",
|
4 |
+
"commandsIntroduced":
|
5 |
+
[ ],
|
6 |
+
"music": "gurh"
|
7 |
+
}
|
8 |
+
#END_PROPERTIES#
|
9 |
+
/*******************
|
10 |
+
* 102_noWayOut.js *
|
11 |
+
* by AGoliath *
|
12 |
+
*******************
|
13 |
+
*
|
14 |
+
* Who builds a wall in a room anyway?
|
15 |
+
*
|
16 |
+
*/
|
17 |
+
|
18 |
+
function startLevel(map) {
|
19 |
+
#START_OF_START_LEVEL#
|
20 |
+
map.displayChapter('Challenge 2\nTear down this wall!');
|
21 |
+
|
22 |
+
map.placePlayer(7, 5);
|
23 |
+
|
24 |
+
var buildWall = function() {
|
25 |
+
for (var i= 0; i <= map.getHeight(); i++) map.placeObject(map.getWidth()-10, i, 'block');
|
26 |
+
}
|
27 |
+
|
28 |
+
#BEGIN_EDITABLE#
|
29 |
+
|
30 |
+
#END_EDITABLE#
|
31 |
+
|
32 |
+
buildWall();
|
33 |
+
map.placeObject(map.getWidth()-7, map.getHeight()-5, 'exit');
|
34 |
+
#END_OF_START_LEVEL#
|
35 |
+
}
|
36 |
+
|
37 |
+
function onExit(map) {
|
38 |
+
return true;
|
39 |
+
}
|
40 |
+
|
41 |
+
|
42 |
+
function validateLevel(map) {
|
43 |
+
map.validateExactlyXManyObjects(1, 'exit');
|
44 |
+
}
|