summaryrefslogtreecommitdiffstats
path: root/static/games/stallman-shooter/main.js
diff options
context:
space:
mode:
Diffstat (limited to 'static/games/stallman-shooter/main.js')
-rw-r--r--static/games/stallman-shooter/main.js173
1 files changed, 173 insertions, 0 deletions
diff --git a/static/games/stallman-shooter/main.js b/static/games/stallman-shooter/main.js
new file mode 100644
index 0000000..d3a3581
--- /dev/null
+++ b/static/games/stallman-shooter/main.js
@@ -0,0 +1,173 @@
+import * as state from '/static/games/stallman-shooter/state.js';
+import * as constants from '/static/games/stallman-shooter/constants.js';
+
+let events = [];
+
+window.addEventListener('keydown', (e) => events.push(['keydown', e.key]));
+window.addEventListener('keyup', (e) => events.push(['keyup', e.key]));
+
+const duration = 1000 / 60;
+
+function frame(ctx, st, events, textures) {
+ const new_bullets = [];
+ const count = st.count;
+ for (const enemy of st.enemies) {
+ new_bullets.push(...enemy.act(count));
+ }
+ for (const bullet of st.bullets) {
+ state.straight_bullet_act(bullet);
+ }
+ for (const bullet of st.player_bullets) {
+ state.straight_bullet_act(bullet);
+ }
+ st.player.act(events);
+ if (count % st.player.fire_rate === 0) {
+ st.player_bullets.push(new state.PBullet(st.player.x, 0, st.player.y, -3.5));
+ }
+ for (const bullet of st.bullets) {
+ if (state.overlaps(st.player, bullet)) {
+ return 'loss';
+ }
+ }
+ for (const bullet of new_bullets) {
+ if (state.overlaps(st.player, bullet)) {
+ return 'loss';
+ }
+ }
+ for (const enemy of st.enemies) {
+ for (const bullet of st.player_bullets) {
+ if (state.overlaps(enemy, bullet)) {
+ enemy.injure(bullet.damage());
+ state.straight_bullet_delete(bullet);
+ }
+ }
+ }
+ st.enemies = st.enemies.filter((enemy) => enemy.health > 0);
+ if (st.enemies.length === 0) {
+ return 'win';
+ }
+ st.bullets = st.bullets.filter((bullet) => !state.outside(bullet));
+ st.bullets.push(...new_bullets);
+ st.player_bullets = st.player_bullets.filter((bullet) => !state.outside(bullet));
+
+ for (const bullet of st.player_bullets) {
+ state.draw(bullet, ctx, textures.pbullet);
+ }
+ for (const enemy of st.enemies) {
+ state.draw(enemy, ctx, textures.enemy);
+ }
+ state.draw(st.player, ctx, textures.player);
+ for (const bullet of st.bullets) {
+ state.draw(bullet, ctx, textures.ebullet);
+ }
+ ctx.strokeStyle = "red";
+ ctx.strokeRect(0, 0, Math.round(st.enemies[0].health * constants.x_dim), 20);
+ st.count++;
+ return 'nothing';
+}
+
+async function get_bitmap(id) {
+ const image = document.getElementById(id);
+ await image.decode();
+ return await window.createImageBitmap(image);
+}
+
+async function get_player_bitmap() {
+ return get_bitmap('stallman');
+}
+
+async function get_enemy_bitmap() {
+ return get_bitmap('gates');
+}
+
+async function get_ebullet_bitmap() {
+ return get_bitmap('binary-blob');
+}
+
+async function get_pbullet_surface() {
+ return get_bitmap('player-pepp');
+}
+
+async function generic_message(ctx, image, okay) {
+ const bitmap = await get_bitmap(image);
+ while (true) {
+ await new Promise(window.requestAnimationFrame);
+ const ev = events;
+ events = [];
+ for (const event of ev) {
+ const [type, keycode] = event;
+ if (type === 'keydown' && keycode === okay) {
+ return;
+ }
+ }
+ ctx.drawImage(bitmap, 0, 0);
+ }
+}
+
+async function introduction(ctx) {
+ await generic_message(ctx, 'introduction', 'Enter');
+}
+
+async function loss(ctx) {
+ await generic_message(ctx, 'loss', 'r');
+}
+
+async function victory(ctx) {
+ await generic_message(ctx, 'victory', 'r');
+}
+
+async function main() {
+ const canvas = document.getElementById('canvas');
+ const ctx = canvas.getContext('2d');
+
+ await introduction(ctx);
+
+ while (true) {
+ const st = new state.State();
+ const [
+ player_bitmap,
+ enemy_bitmap,
+ ebullet_bitmap,
+ pbullet_bitmap,
+ ] = await Promise.all([
+ get_bitmap('stallman'),
+ get_bitmap('gates'),
+ get_bitmap('binary-blob'),
+ get_bitmap('player-pepp'),
+ ]);
+ const textures = {
+ player: player_bitmap,
+ enemy: enemy_bitmap,
+ ebullet: ebullet_bitmap,
+ pbullet: pbullet_bitmap,
+ };
+ let last_frame_time = null;
+ let accumulator = 0;
+ game: while (true) {
+ const now = await new Promise(requestAnimationFrame);
+ if (last_frame_time !== null) {
+ accumulator += now - last_frame_time;
+ }
+ last_frame_time = now;
+
+ while (accumulator >= duration) {
+ accumulator -= duration;
+
+ ctx.fillStyle = "white";
+ ctx.fillRect(0, 0, constants.x_dim, constants.y_dim);
+ const result = frame(ctx, st, events, textures);
+ events = [];
+ if (result === 'loss') {
+ await loss(ctx);
+ break game;
+ }
+ if (result === 'win') {
+ await victory(ctx);
+ break game;
+ }
+ }
+ }
+ }
+}
+
+main()