4 Placed in the public domain.
6 This code is designed for use with Perlenspiel, by Brian Moriarty,
7 which is released under the terms of the GNU LGPL version 3 or
21 var SELECTED
= 0x222222;
23 var DISABLE_PROMPT
= 3;
30 var AUDIO_QUIET
= 0.4;
32 var selecting
= false;
45 var level_modifier
= [FIRE
, VOID
];
47 function couldFinishWorldSound(score
, size
) {
48 score
= PS
.Random(score
) + score
;
49 if (score
+ 18 > AUDIO_MAX
)
50 score
= AUDIO_MAX
- 18;
51 PS
.AudioPlay(PS
.Harpsichord(score
, false), AUDIO_QUIET
);
52 PS
.AudioPlay(PS
.Harpsichord(score
+ 6, false), AUDIO_QUIET
);
53 PS
.AudioPlay(PS
.Harpsichord(score
+ 18, false), AUDIO_QUIET
);
56 function finishWorldSound(score
, size
) {
57 score
= PS
.Random(score
) + score
;
58 if (score
+ 18 > AUDIO_MAX
)
59 score
= AUDIO_MAX
- 18;
60 PS
.AudioPlay(PS
.Harpsichord(score
, true), AUDIO_LOUD
);
61 PS
.AudioPlay(PS
.Harpsichord(score
+ 6, true), AUDIO_LOUD
);
62 PS
.AudioPlay(PS
.Harpsichord(score
+ 18, true), AUDIO_LOUD
);
65 function levelUpSound(level
) {
66 if (level
+ 44 > AUDIO_MAX
)
67 level
= AUDIO_MAX
- 44;
68 PS
.AudioPlay(PS
.Harpsichord(20 + level
, true), AUDIO_LOUD
);
69 PS
.AudioPlay(PS
.Harpsichord(28 + level
, true), AUDIO_LOUD
);
70 PS
.AudioPlay(PS
.Harpsichord(44 + level
, true), AUDIO_LOUD
);
73 function select(x
, y
) {
74 if (PS
.BeadBorderColor(x
, y
) != SELECTED
) {
75 var invalid
= checkInvalidReason();
76 PS
.BeadBorderColor(x
, y
, SELECTED
);
77 PS
.BeadBorderWidth(x
, y
, 4);
78 if (invalid
&& !checkInvalidReason())
79 couldFinishWorldSound(score
, 0);
83 function deselect(x
, y
) {
84 PS
.BeadBorderColor(x
, y
, PS
.DEFAULT
);
85 PS
.BeadBorderWidth(x
, y
, PS
.DEFAULT
);
89 for (var i
= a
.length
- 1; i
>= 1; --i
) {
90 var j
= PS
.Random(i
) - 1;
98 function countBoard(evenUnselected
) {
99 var b
= { fire
: 0, earth
: 0, water
: 0, wind
: 0, nothing
: 0, total
: 0 };
100 for (var x
= 0; x
< X_SIZE
; ++x
) {
101 for (var y
= 0; y
< Y_SIZE
; ++y
) {
102 if (evenUnselected
|| isSelected(x
, y
)) {
103 var color
= PS
.BeadColor(x
, y
);
104 if (color
== FIRE
) b
.fire
++;
105 if (color
== EARTH
) b
.earth
++;
106 if (color
== WATER
) b
.water
++;
107 if (color
== WIND
) b
.wind
++;
108 if (color
== VOID
) b
.nothing
++;
116 function isSelected(x
, y
) {
117 return (x
>= 0 && x
< X_SIZE
118 && y
>= 0 && y
< Y_SIZE
119 && PS
.BeadBorderColor(x
, y
) == SELECTED
);
122 function onlySelected(x
, y
) {
123 return isSelected(x
, y
) && countBoard().total
== 1;
126 function checkAdjacent(x
, y
) {
127 return (isSelected(x
, y
)
128 || isSelected(x
- 1, y
)
129 || isSelected(x
+ 1, y
)
130 || isSelected(x
, y
- 1)
131 || isSelected(x
, y
+ 1));
134 function createBoard() {
135 var nothing
= countBoard(true).nothing
;
137 for (var y
= 0; y
< nothing
; ++y
) {
138 b
.push(proportions
[y
% proportions
.length
]);
142 for (var x
= 0; x
< X_SIZE
; ++x
)
143 for (var y
= 0; y
< Y_SIZE
; ++y
)
144 if (PS
.BeadColor(x
, y
) == VOID
)
145 PS
.BeadColor(x
, y
, b
[j
++]);
148 function checkInvalidReason() {
149 var b
= countBoard();
150 if (b
.total
== 1 && b
.fire
) {
151 return ["[Fire] Counter its heat with water", 0xFF9999];
152 } else if (b
.total
== 1 && b
.earth
) {
153 return ["[Life] Lifeless worlds are pointless", 0x99FF99];
154 } else if (b
.total
== 1 && b
.water
) {
155 return ["[Water] Quench both thirst and fire", 0x9999FF];
156 } else if (b
.total
== 1 && b
.wind
) {
157 return ["[Air] Habitable worlds need air", 0xFFFF99];
158 } else if (b
.total
== 1 && b
.nothing
) {
159 return ["[Void] Don't use too much...", 0xFF99FF];
160 } else if (b
.total
== 0 && score
== 0) {
161 return ["Click and drag to make a world", 0xFFFFFF];
162 } else if (b
.total
&& b
.total
< 3 && score
< DISABLE_PROMPT
) {
163 return ["Select more elements to make a world", 0xFFFFFF];
164 } else if (b
.total
< 3) {
165 var s
= "Worlds created: " + score
;
167 s
= "Plane " + level
+ " / " + s
;
168 return [s
, 0xFFFFFF];
172 return ["This world wouldn't have any life!", 0x99FF99];
175 return ["Life needs water to drink!", 0x9999FF];
178 return ["Life needs air to breathe!", 0xFFFF99];
180 if (b
.nothing
>= (b
.water
+ b
.fire
* 2 + b
.earth
+ b
.wind
))
181 return ["Your world has too much nothing!", 0xFF99FF];
183 if (b
.water
< b
.fire
)
184 return ["Your world is burning!", 0xFF9999];
189 function statusUpdate() {
190 var res
= checkInvalidReason();
192 res
= ["Click to create a world", 0xFFFFFF];
193 PS
.StatusText(res
[0]);
194 PS
.StatusColor(res
[1]);
197 PS
.Init = function () {
198 var path
= window
.location
.href
;
199 PS
.AudioPath(path
.substr(0, path
.lastIndexOf("/")) + "/audio/");
201 PS
.GridSize(X_SIZE
, Y_SIZE
);
202 PS
.GridBGColor(VOID
);
203 PS
.BeadShow(PS
.ALL
, PS
.ALL
, true);
204 PS
.BeadColor(PS
.ALL
, PS
.ALL
, VOID
);
209 PS
.Click = function (x
, y
, data
) {
210 if (onlySelected(x
, y
)) {
212 } else if (isSelected(x
, y
) && !checkInvalidReason()) {
214 for (var x
= 0; x
< X_SIZE
; ++x
) {
215 for (var y
= 0; y
< Y_SIZE
; ++y
) {
216 if (isSelected(x
, y
)) {
217 PS
.BeadColor(x
, y
, VOID
);
222 deselect(PS
.ALL
, PS
.ALL
);
223 finishWorldSound(++score
, size
);
224 } else if (checkAdjacent(x
, y
) && !isSelected(x
, y
)) {
228 deselect(PS
.ALL
, PS
.ALL
);
233 var b
= countBoard(true);
235 proportions
.push
.apply(proportions
, level_modifier
);
237 levelUpSound(++level
);
239 var b
= countBoard(true);
241 PS
.StatusText("All life thanks you! Final score: " + score
);
243 PS
.StatusText("Now try a more dangerous universe!");
245 PS
.StatusColor(0xFFFFFF);
249 PS
.Release = function (x
, y
, data
) {
253 PS
.Enter = function (x
, y
, data
) {
254 if (selecting
&& checkAdjacent(x
, y
)) {
262 PS
.Leave = function (x
, y
, data
) {
265 PS
.KeyDown = function (key
, shift
, ctrl
) {
268 PS
.KeyUp = function (key
, shift
, ctrl
) {
271 PS
.Wheel = function (dir
) {
274 // Chrome and Firefox bug out when asked to preload 114 files at once.
276 PS
.Tick = function () {
277 if (++loaded
<= AUDIO_MAX
) {
278 PS
.AudioLoad(PS
.Harpsichord(loaded
));
279 PS
.AudioLoad(PS
.Harpsichord(loaded
, true));