forked from fabiosantoscode/js13k-2024
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgoal.js
386 lines (354 loc) · 12.1 KB
/
goal.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
/** There's a "turn" in the track */
let CURRENT_TURN = 0
let goal_nth_place = 13
let goal_target_turn = 0
let PLAYER_NO_COLLIDE = 0
/** 0..1 */
let DIFFICULTY = 0
let LEVEL = 1
let ENDING_CUTSCENE = 0
let APPROACHING_RACER
let this_level_ends_at = 0
let distance_till_next_level = () => this_level_ends_at - player_y_nowrap
let ordinal = place => {
if (ENDING_CUTSCENE) {
return ''
} else {
let nx = ['th','st','nd','rd']
return place+(nx[place] || nx[0])
}
}
let yield_time = function*(ms) {
ms += Date.now()
while (Date.now() < ms) yield;
}
let yield_space = function*(distance) {
distance += player_y_nowrap
while (player_y_nowrap < distance) yield;
}
// CHALLENGES
let challenge_hard_turn = function*() {
// Turn left and right, try not to hit walls
let turn_towards = random() > 0.5 ? 1 : -1
yield* warn(turn_towards < 0 ? 'HARD LEFT' : 'HARD RIGHT')
goal_target_turn = turn_towards
yield* yield_space(100)
goal_target_turn = 0
}
let challenge_jump = function*() {
// receive a wall in front of you to jump over
let start = Date.now()
yield* warn('JUMP')
let jump_wall_y = (player_y + RENDER_DIST + 2) | 0
for (let i = 0; i < map_len_x; i++) {
map[jump_wall_y][i] = true // create a wall
}
while (player_y < jump_wall_y && (Date.now() - start < 4_000)) {
yield;
}
for (let i = 0; i < map_len_x; i++) {
map[jump_wall_y][i] = false // tear down the wall
}
}
let challenge_some_guy_in_front_of_you = function*() {
if (goal_nth_place === 1) return; // no one is in front of us
APPROACHING_RACER = [player_x > 10 ? 7 : 13, player_y + RENDER_DIST + 2, 1]
// Another pilot comes, and you have to hit them in the back to make sure you remain in 13th place
yield* warn(`${ordinal(goal_nth_place - 1)} CONTESTANT`)
let cancel_at = Date.now() + 8_000
while (1) {
// CANCEL
if (player_y > 900 || (Date.now() > cancel_at)) {
// Cancel this (just to avoid infinite loop and math issues due to wrapping)
break
}
// SUCCEED
if (hasApproachingRacerBeenHit()) {
APPROACHING_RACER[2] = 2 // phase 2 - be kicked forward
yield* screen_message_success('SUCCESS')
yield* yield_space(45)
break
}
// FAIL
if (hasApproachingRacerBeenSurpassed()) {
goal_nth_place--
yield* screen_message_success('FAILURE')
break
}
yield;
}
APPROACHING_RACER = 0
}
let DEBUG_skip_to_level
if (self.env !== 'production') {
let l = +new URLSearchParams(location.search).get('level')
if (l) DEBUG_skip_to_level = l
}
let transition_level = function*(on_finish_cutscene) {
if (DEBUG_skip_to_level > LEVEL) {
COLOR_reset_all_colors()
on_finish_cutscene && on_finish_cutscene()
return
}
PLAYER_NO_COLLIDE++
let cutscene_fadeout = Date.now() + 2500
let cutscene_end = Date.now() + 4000
while (cutscene_end > Date.now()) {
let y = (player_y + RENDER_DIST + 10) | 0
let y_end = y + 50
while (y++ < y_end && y < map_len_y) {
map[y][0] = true
map[y][1] = true
map[y][2] = true
map[y][3] = true
map[y][4] = true
map[y][15] = true
map[y][16] = true
map[y][17] = true
map[y][18] = true
map[y][19] = true
}
let fadeout_point = abs(Date.now() - cutscene_fadeout);
let f_fadeout_point = round_n(fadeout_point, 250) / 1000
if (f_fadeout_point <= 1) {
if (on_finish_cutscene && f_fadeout_point == 0) {
COLOR_reset_all_colors()
on_finish_cutscene()
on_finish_cutscene = 0
}
c.style.opacity = f_fadeout_point
c.style.filter = `saturate(${lerp(100, 250, 1 - f_fadeout_point)}%)`
}
yield
}
PLAYER_NO_COLLIDE--
}
let level_generator = function*(no_jump) {
if (self.env !== 'production') {
if (DEBUG_skip_to_level > LEVEL) {
return
}
}
let challenges =
//[challenge_some_guy_in_front_of_you]
[challenge_some_guy_in_front_of_you, challenge_hard_turn]
if (!no_jump) challenges.push(challenge_jump)
// Yield at the start so we can appreciate the scenery
yield* yield_space(200);
while (1) {
if (
// make sure we have space to do the challenge before the wrap around
abs(player_y - map_len_y) > map_len_y - 600
// no challenges during the cutscene
&& !ENDING_CUTSCENE
) {
let chl = challenges[floor(random() * challenges.length)];
yield * chl();
}
yield * yield_space(90); // meters of track which are between challenges (decrease to increase difficulty)
if (distance_till_next_level() < 200) {
break
}
}
}
let game_generator = (function*() {
// yield; // Don't start yet (`game_generator` is called immediately)
// Make sure we are ready
if (self.env === 'production') {
yield* yield_space(100);
yield* screen_message_success('Press A/D to move', 4000);
yield* screen_message_success('Press space to jump', 4000);
yield* screen_message_success('Or tap buttons below', 4000);
yield* screen_message_success('Please Finish In 13th Place', 4000);
}
// DIFFICULTY = 0 - starts at zero
// transition_level(() => {}) // do nothing here because it's the first level.
this_level_ends_at = player_y_nowrap + 1500
yield* level_generator()
// Neon night
yield* transition_level(() => {
COLOR_stars = 'rgba(255,255,255,.6)'
COLOR_sky_gradient_start = '#37c'
COLOR_sky_gradient_end = '#600'
COLOR_road_gradient_start = '#133'
COLOR_road_gradient_end = 'brown'
COLOR_road_checkerboard = null
COLOR_tree_hue = 320
COLOR_wall_hue = 230
COLOR_abyss_color = 'rgba(180,50,150,.4)'
COLOR_player_brightness = 1.8
});
this_level_ends_at = player_y_nowrap + 1500
DIFFICULTY = 2 / 6
LEVEL = 2
yield* level_generator()
// Macintosh plus
yield* transition_level(() => {
COLOR_stars = null
COLOR_sky_gradient_start = '#ff899c'
COLOR_sky_gradient_end = '#ff899c'
COLOR_sky_shapes = 1
COLOR_road_gradient_start = null
COLOR_road_gradient_end = null
COLOR_road_checkerboard = ['#d79', '#122']
COLOR_road_grid = null
COLOR_tree_hue = 195.0
COLOR_wall_hue = 34.0
COLOR_tree_sat = .02
COLOR_wall_sat = .24
COLOR_tree_lum = .5
COLOR_wall_lum = .4
COLOR_abyss_color = '#e1a1fe'
COLOR_text_nth_place = '#87e7c0'
COLOR_player_brightness = 1.8
COLOR_wall_randomness_biome = 8
});
this_level_ends_at = player_y_nowrap + 2000
DIFFICULTY = 3 / 6
LEVEL = 3
yield* level_generator()
// Digital red
yield* transition_level(() => {
COLOR_stars = 'red'
COLOR_road_gradient_start = 0
COLOR_road_gradient_end = 0
COLOR_road_grid = 'green'
COLOR_road_checkerboard = null
COLOR_tree_hue = 0
COLOR_tree_lum = .3
COLOR_wall_hue = 145
COLOR_wall_lum = .1
COLOR_player_brightness = 0
});
this_level_ends_at = player_y_nowrap + 2000
DIFFICULTY = 4 / 6
LEVEL = 4
yield* level_generator()
// Rainbow road
yield* transition_level(() => {
COLOR_moon = '#ddd'
COLOR_road_rainbow = ['#c83898', '#c89058', '#c8c020', '#08c828', '#18c0d8', '#6060e8', '#b008e8']
COLOR_stars = 'white'
COLOR_sky_gradient_end = 'black'
COLOR_sky_gradient_start = 'black'
COLOR_wall_sat = 86
COLOR_wall_lum = .2
COLOR_wall_hue = 250
COLOR_tree_sat = 0
COLOR_tree_lum = .1
COLOR_player_brightness = 2
COLOR_wall_hidden = 1
COLOR_wall_randomness_biome = 9
});
this_level_ends_at = player_y_nowrap + 2500
DIFFICULTY = 5 / 6
LEVEL = 5
yield* level_generator(1 /* forbid jumps on rainbow road */)
// Trippy black void
yield* transition_level(() => {
ENDING_CUTSCENE++
// Full circle. Colors were set by COLOR_reset_all_colors
COLOR_void = 1 // Black void effect
})
this_level_ends_at = Infinity
DIFFICULTY = 6 / 6
LEVEL = 6
if (goal_nth_place === 13) {
yield* screen_message_success('Congratulations', 4000);
yield* yield_time(400);
yield* screen_message_success('You have Finish In 13th Place', 4000);
yield* yield_time(400);
yield* screen_message_success('You have failed Successfully', 4000);
yield* yield_time(400);
yield* screen_message_success('You have worked hard and', 4000);
yield* yield_time(400);
yield* screen_message_success('now the quadrillionaire', 4000);
yield* yield_time(400);
yield* screen_message_success('bought another space yacht', 4000);
} else if (goal_nth_place === 1) {
yield* screen_message_success("Congratulations", 4000);
yield* yield_time(400);
yield* screen_message_success("You have Finish In 1th Place", 4000);
yield* yield_time(400);
yield* screen_message_success("You have failed by Succeeding", 4000);
yield* yield_time(400);
yield* screen_message_success("You have worked hard and", 4000);
yield* yield_time(400);
yield* screen_message_success("You are in racing hall of fame", 4000);
yield* yield_time(400);
yield* screen_message_success("And also DEAD ...", 4000);
yield* yield_time(400);
yield* screen_message_success("Should have Finish In 13th Place", 4000);
} else {
yield* screen_message_failure('Unfortunately', 4000);
yield* yield_time(400);
yield* screen_message_failure('You have failed by succeeding', 4000);
yield* yield_time(400);
yield* screen_message_failure('Next time', 4000);
yield* yield_time(400);
yield* screen_message_failure('Please Finish In 13th Place', 4000);
}
yield* yield_time(2000);
yield* screen_message_success("SPECIAL THANKS TO", 4000);
yield* yield_time(400);
yield* screen_message_success("Gina Vasile", 4000);
yield* yield_time(400);
yield* screen_message_success("Antonio \"Toni\" Saraiva", 4000);
yield* yield_time(400);
yield* screen_message_success("IgorFIE & Dosaki", 4000);
yield* yield_time(400);
this_level_ends_at = 0 // just the cutscene pls
yield* level_generator()
yield* transition_level(() => {
// Full circle. Colors were set by COLOR_reset_all_colors
// Though first, we go into a trippy black void
// Black void effect
COLOR_void = 0
ENDING_CUTSCENE--
});
this_level_ends_at = Infinity
DIFFICULTY = 6 / 6
LEVEL = 6
// TODO yield* ending()
})()
let warn = function*(w, time) {
warning = w;
yield* yield_time(time||800);
warning = '';
}
let screen_message_success = function*(w, time) {
success = w;
yield* yield_time(time||800);
success = '';
}
let screen_message_failure = function*(w, time) {
failure = w;
yield* yield_time(time||800);
failure = '';
}
let updateGoal = () => {
game_generator.next();
// Maintain CURRENT_TURN
CURRENT_TURN = lerp(CURRENT_TURN, goal_target_turn, 0.05);
if (goal_target_turn == 0 && abs(CURRENT_TURN) < 0.05) CURRENT_TURN = 0;
};
let debug_info = () => {
if (self.env === 'production') return '';
return ` `;
};
let warning = '';
let success = '';
let failure = '';
let drawGoal = () => {
let text_y = 20
if (ENDING_CUTSCENE) {
warning = '';
text_y = 60
}
ctx.fillStyle =
warning ? (sin(GAME_TIME * 9) > 0 ? 'red' : 'yellow')
: failure ? (sin(GAME_TIME * 9) > 0 ? 'red' : 'purple')
: success ? (sin(GAME_TIME * 9) > 0 ? 'purple' : 'blue')
: COLOR_text_nth_place;
ctx.fillText(warning || success || failure || ordinal(goal_nth_place) + debug_info(), halfWidth, text_y);
};