aboutsummaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
authorJuan J. Martinez <jjm@usebox.net>2021-05-03 08:21:10 +0100
committerJuan J. Martinez <jjm@usebox.net>2021-05-03 10:00:00 +0100
commitc3b0fa04a663fe233765b83d3be41a42aa08c25d (patch)
tree0befda349001ef6ce306b39378f9c70ad917363e /main.c
downloadreturn-of-traxtor-cpc-c3b0fa04a663fe233765b83d3be41a42aa08c25d.tar.gz
return-of-traxtor-cpc-c3b0fa04a663fe233765b83d3be41a42aa08c25d.zip
Initial import for public releaseHEADmain
Diffstat (limited to 'main.c')
-rw-r--r--main.c1794
1 files changed, 1794 insertions, 0 deletions
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..bb32475
--- /dev/null
+++ b/main.c
@@ -0,0 +1,1794 @@
+/*
+ The Return of Traxtor (Amstrad CPC)
+ Copyright (C) 2015 Juan J. Martinez <jjm@usebox.net>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ucl.h"
+#include "cpcrslib/cpcrslib.h"
+#include "cpcrslib/cpcwyzlib.h"
+#include "splib.h"
+
+#define WFRAMES 12 // ~ 25 FPS
+#include "int.h"
+#include "sound.h"
+
+// generated
+#include "font.h"
+#include "menubg.h"
+#include "playbg.h"
+#include "tiles.h"
+#include "tiles_alt.h"
+#include "ship.h"
+#include "return_mus.h"
+#include "board_mus.h"
+#include "gameover_mus.h"
+
+#define KEY_RIGHT 0
+#define KEY_LEFT 1
+#define KEY_BEAM 2
+#define KEY_FIRE 3
+#define KEY_PAUSE 4
+#define KEY_ALT_BEAM 5
+#define KEY_QUIT 14
+
+#define BW 7
+#define BH 10
+
+#define BLOCK_WILD 7
+
+#define BLOCK(x) (x & 0x0f)
+#define EFFECT(x) (x >> 4)
+#define UPDATE_EFFECT(x, y) ((x & 0x0f) | (y << 4))
+
+#define LOCK_GRAVITY 8
+#define TILE_ERASE 16
+#define TILE_MARKER 17
+#define TILE_EXPLO 18
+#define TILE_GRAVITY 14
+
+#define K_DELAY 3
+
+#define DIRTY_NONE 0
+#define DIRTY_SCORE 1
+#define DIRTY_LEVEL 2
+#define DIRTY_BAY 4
+#define DIRTY_ALL 255
+
+#define ENDGAME 25
+
+// encrypted endgame text; like anyobe is going to read it from the binary! :D
+const uint8_t endgame[] = {
+ 0xf3, 0x45, 0xfe, 0x20, 0x89, 0x36, 0x9a, 0x44, 0xf3, 0x5e, 0x80, 0x31,
+ 0x99, 0x22, 0x8e, 0x50, 0xef, 0x5f, 0xe5, 0x11, 0xb8, 0x03, 0xdd, 0x73,
+ 0xdf, 0x64, 0xcc, 0x73, 0xc4, 0x76, 0xcd, 0x77, 0xa7, 0x53, 0xa7, 0x1f,
+ 0xae, 0x02, 0xdc, 0x6c, 0xdd, 0x74, 0xa4, 0x74, 0xa4, 0x50, 0xa4, 0x03,
+ 0xb2, 0x19, 0xc7, 0x78, 0xd4, 0x6f, 0xb1, 0x0e, 0xd0, 0x62, 0xd9, 0x60,
+ 0xdb, 0x6b, 0xd1, 0x0e, 0xfa, 0x0e, 0xa4, 0x12, 0xad, 0x1d, 0xa8, 0x05,
+ 0xdb, 0x63, 0xd2, 0x7e, 0xa0, 0x0e, 0xbc, 0x03, 0xa4, 0x13, 0xa3, 0x1a,
+ 0xee, 0x44, 0xf2, 0x49, 0x97, 0x2e, 0x91, 0x22, 0x99, 0x49, 0xb7
+};
+
+/*
+"THE WAR IS OVER AND\n"
+"WE PREVAILED.\n\n"
+"FOR NOW...\n\n"
+"YOU ARE A LEGEND!\n\n"
+"THANKS FOR PLAYING\n"
+"THE GAME."
+*/
+
+// conf
+uint8_t conf_mode = 0; // normal, 1: easy
+uint8_t conf_tiles = 0; // classic, 1: alternative
+uint8_t conf_music = 1; // on, 0: off
+uint8_t (*tiles_blocks)[54] = tiles;
+
+uint8_t dirty_hud;
+uint8_t last_wild;
+uint8_t dirty_marker;
+
+#define EFFECTS_DELAY 3
+uint8_t has_effects;
+uint8_t effects_delay;
+uint8_t combo_delay;
+
+#define GRAVITY_DELAY 2
+uint8_t gravity[BW * BH * 2];
+uint8_t has_gravity;
+uint8_t gravity_delay;
+
+uint8_t empty_board;
+uint8_t gameover;
+uint8_t paused;
+uint16_t score;
+uint16_t hiscore = 0;
+uint8_t level;
+
+int16_t next_level;
+int16_t next_line;
+int16_t next_line_level;
+
+uint8_t px;
+uint8_t py;
+uint8_t old_px;
+
+int8_t board[BW * BH];
+
+uint8_t bay[3];
+int8_t bay_top;
+
+const uint8_t pal_hw[] = {
+ 0x54, 0x44, 0x55, 0x5c, 0x58, 0x4c, 0x4d, 0x46,
+ 0x57, 0x40, 0x5f, 0x4e, 0x5a, 0x5b, 0x4a, 0x4b
+};
+
+uint8_t joystick;
+const uint16_t key_map[2][6] = {
+ // right, left, beam, fire, pause, extra beam
+ { 0x4002, 0x4101, 0x4004, 0x4580, 0x4510, 0x0000 }, // keyboard
+ { 0x4908, 0x4904, 0x4580, 0x4910, 0x4510, 0x4920 } // joystick
+};
+const char redefine[5][6] = {
+ "RIGHT", "LEFT ", "BEAM ", "FIRE ", "PAUSE"
+};
+
+void
+map_keys()
+{
+ uint8_t i;
+
+ for (i = 0; i < 6; i++)
+ cpc_AssignKey(i, key_map[joystick][i]);
+}
+
+void
+draw_controls()
+{
+ if (joystick)
+ {
+ cpc_SetInkGphStr(2, 170);
+ cpc_SetInkGphStr(3, 42);
+ }
+ else
+ {
+ cpc_SetInkGphStr(2, 160);
+ cpc_SetInkGphStr(3, 138);
+ }
+ cpc_PrintGphStrXY("1:JOYSTICK", 30, 80);
+
+ if (joystick)
+ {
+ cpc_SetInkGphStr(2, 160);
+ cpc_SetInkGphStr(3, 138);
+ }
+ else
+ {
+ cpc_SetInkGphStr(2, 170);
+ cpc_SetInkGphStr(3, 42);
+ }
+ cpc_PrintGphStrXY("2:KEYBOARD", 30, 90);
+
+ cpc_SetInkGphStr(2, 160);
+ cpc_SetInkGphStr(3, 138);
+ cpc_PrintGphStrXY("3:REDEFINE", 30, 100);
+
+ cpc_PrintGphStrXY("4:OPTIONS", 30, 110);
+
+ cpc_SetInkGphStr(2, 128);
+ cpc_SetInkGphStr(3, 128);
+ cpc_PrintGphStrXY("BEAM OR FIRE TO PLAY", 20, 135);
+}
+
+void
+draw_menu()
+{
+ uint8_t buffer[11] = "HI: ";
+
+ // colors: 0 bg, 1 unused, 2 top/bottom, 3 center
+ //
+ // 8: blue
+ // 42: yellow
+ // 138: orange
+ // 160: red
+ // 32: dark purple
+ // 40: light purple
+ // 170: white
+ // 162: light blue
+ //
+
+ ucl_uncompress(menubg, (uint8_t *)BUFF_ADDR);
+
+ wait_vsync();
+ cpc_PutSp((char *)BUFF_ADDR, 56, 80, (int)0xf050);
+ draw_controls();
+
+ if (hiscore > 0)
+ {
+ cpc_SetInkGphStr(2, 162);
+ cpc_SetInkGphStr(3, 170);
+ pad_numbers(buffer + 4, 6, hiscore);
+ cpc_PrintGphStrXY(buffer, 30, 0);
+ }
+
+ cpc_SetInkGphStr(2, 160);
+ cpc_SetInkGphStr(3, 40);
+ cpc_PrintGphStrXY("CODE, GRAPHICS & SOUND", 18, 160);
+
+ cpc_SetInkGphStr(2, 32);
+ cpc_SetInkGphStr(3, 32);
+ cpc_PrintGphStrXY("JUAN J. MARTINEZ", 24, 170);
+
+ cpc_SetInkGphStr(2, 8);
+ cpc_SetInkGphStr(3, 8);
+ cpc_PrintGphStrXY("\x1f""2015 USEBOX.NET", 24, 190);
+}
+
+void
+run_redefine()
+{
+ uint8_t i;
+
+ memset((uint8_t *)BUFF_ADDR, 0, 65 * 80);
+ cpc_PutSp((char *)BUFF_ADDR, 65, 80, (int)0xc320);
+
+ // be sure the keyboard is free
+ while (cpc_AnyKeyPressed())
+ wait();
+
+ cpc_SetInkGphStr(2, 160);
+ cpc_SetInkGphStr(3, 138);
+ cpc_PrintGphStrXY("PRESS KEY FOR:", 20, 110);
+
+ cpc_SetInkGphStr(2, 42);
+ cpc_SetInkGphStr(3, 42);
+
+ // clean exiting keys
+ for (i = 0; i < 6; i++)
+ cpc_AssignKey(i, (int)0xffff);
+
+ for (i = 0; i < 5; i++)
+ {
+ wait_vsync();
+ cpc_PrintGphStrXY(redefine[i], 50, 110);
+ cpc_RedefineKey(i);
+ }
+
+ // alt beam
+ cpc_AssignKey(i, (int)0x0000);
+
+ // be sure the keyboard is free
+ while (cpc_AnyKeyPressed())
+ wait();
+
+ cpc_PutSp((char *)BUFF_ADDR, 65, 80, (int)0xc320);
+}
+
+uint8_t song_names[5][11] =
+{
+ { "THE RETURN" },
+ { "THE LEGEND" },
+ { "I REMEMBER" },
+ { "FULL BOARD" },
+ { "GAME OVER " }
+};
+
+const uint8_t *juke_songs[] = { return_mus, 0, 0, board_mus, gameover_mus };
+
+void
+draw_options(uint8_t song)
+{
+ cpc_SetInkGphStr(2, 160);
+ cpc_SetInkGphStr(3, 138);
+
+ wait_vsync();
+ cpc_PrintGphStrXY("ESC:MAIN MENU", 22, 125);
+
+ if (conf_mode)
+ cpc_PrintGphStrXY("1:EASY MODE ", 26, 80);
+ else
+ cpc_PrintGphStrXY("1:NORMAL MODE", 26, 80);
+
+ if (conf_tiles)
+ cpc_PrintGphStrXY("2:ALT TILES ", 26, 90);
+ else
+ cpc_PrintGphStrXY("2:CLASSIC TILES", 26, 90);
+
+ if (conf_music)
+ cpc_PrintGphStrXY("3:MUSIC ON ", 26, 100);
+ else
+ cpc_PrintGphStrXY("3:MUSIC OFF", 26, 100);
+
+ cpc_PrintGphStrXY("4:JUKEBOX [", 26, 110);
+ cpc_PrintGphStrXY("]", 68, 110);
+
+ cpc_SetInkGphStr(2, 162);
+ cpc_SetInkGphStr(3, 170);
+ cpc_PrintGphStrXY(song_names[song], 48, 110);
+}
+
+void
+run_options()
+{
+ uint8_t song = 0, k_delay = 0;
+
+ memset((uint8_t *)BUFF_ADDR, 0, 65 * 80);
+ cpc_PutSp((char *)BUFF_ADDR, 65, 80, (int)0xc320);
+
+ // be sure the keyboard is free
+ while (cpc_AnyKeyPressed())
+ wait();
+
+ draw_options(song);
+
+ while (1)
+ {
+ cpc_ScanKeyboard();
+
+ if (k_delay)
+ {
+ k_delay--;
+ continue;
+ }
+
+ if (cpc_TestKeyF(KEY_QUIT))
+ break;
+
+ if (cpc_TestKeyF(8)) // key: 1
+ {
+ conf_mode = !conf_mode;
+
+ draw_options(song);
+ k_delay = 8;
+ continue;
+ }
+
+ if (cpc_TestKeyF(9)) // key: 2
+ {
+ conf_tiles = !conf_tiles;
+
+ if (conf_tiles)
+ tiles_blocks = (uint8_t *[])tiles_alt;
+ else
+ tiles_blocks = (uint8_t *[])tiles;
+
+ draw_options(song);
+ k_delay = 8;
+ continue;
+ }
+
+ if (cpc_TestKeyF(10)) // key: 3
+ {
+ conf_music = !conf_music;
+
+ draw_options(song);
+ k_delay = 8;
+ continue;
+ }
+
+ if (cpc_TestKeyF(11)) // key: 4
+ {
+ song++;
+ if (song > 4)
+ song = 0;
+
+ WyzPlayerOff();
+ switch (song)
+ {
+ default:
+ ucl_uncompress(juke_songs[song], (uint8_t *)7000);
+ cpc_WyzLoadSong(0);
+ break;
+ case 1:
+ case 2:
+ cpc_WyzLoadSong(song);
+ break;
+ }
+ WyzPlayerOn();
+
+ draw_options(song);
+ k_delay = 8;
+ continue;
+ }
+ }
+
+ // be sure the keyboard is free
+ while (cpc_AnyKeyPressed())
+ wait();
+
+ if (song)
+ {
+ WyzPlayerOff();
+ ucl_uncompress(return_mus, (uint8_t *)7000);
+ cpc_WyzLoadSong(0);
+ WyzPlayerOn();
+ }
+
+ cpc_PutSp((char *)BUFF_ADDR, 65, 80, (int)0xc320);
+}
+
+void
+do_text_fadeout(char * text, uint8_t x, uint8_t y)
+{
+ cpc_SetInkGphStr(2, 170);
+ cpc_SetInkGphStr(3, 170);
+ wait();
+ cpc_PrintGphStrXY2X(text, x, y);
+
+ cpc_SetInkGphStr(2, 32);
+ cpc_SetInkGphStr(3, 32);
+ wait();
+ wait();
+ cpc_PrintGphStrXY2X(text, x, y);
+
+ cpc_SetInkGphStr(2, 128);
+ cpc_SetInkGphStr(3, 128);
+ wait();
+ wait();
+ cpc_PrintGphStrXY2X(text, x, y);
+
+ cpc_SetInkGphStr(2, 0);
+ cpc_SetInkGphStr(3, 0);
+ wait();
+ wait();
+ cpc_PrintGphStrXY2X(text, x, y);
+}
+
+void
+screen_black()
+{
+ uint8_t i;
+
+ wait_vsync();
+
+ // all black
+ for (i = 0; i < 16; i++)
+ set_hw_ink(i, 0x54);
+}
+
+void
+screen_fadein()
+{
+ uint8_t i;
+
+ // all blue
+ wait_vsync();
+ for (i = 1; i < 16; i++)
+ set_hw_ink(i, 0x44);
+
+ for (i = 0; i < 4; i++)
+ wait();
+
+ // all white
+ wait_vsync();
+ for (i = 1; i < 16; i++)
+ set_hw_ink(i, 0x4b);
+
+ for (i = 0; i < 3; i++)
+ wait();
+
+ // final colours
+ wait_vsync();
+ for (i = 1; i < 16; i++)
+ set_hw_ink(i, pal_hw[i]);
+}
+
+const uint8_t text_intro[] =
+ "1000 YEARS HAVE PASSED SINCE THE\n"
+ "LAST WAR, WHEN TRAXTOR SAVED US.\n\n"
+ "WITH THE LEGEND NOW LONG GONE,\n"
+ "THIS IS A STORY OF ITS LEGACY...";
+
+const uint8_t intro_pos[3] = { 0, 3, 6 };
+
+void
+run_intro()
+{
+ const uint8_t *pt = text_intro;
+ uint8_t buffer[2] = { 0, 0 };
+ uint8_t i, j, k;
+
+ init_tiles();
+
+ cpc_WyzLoadSong(2);
+ WyzPlayerOn();
+
+ for (k = 0; k < 48; k++)
+ wait();
+
+ for (k = 0; k < 3; k++)
+ {
+ i = intro_pos[k];
+ put_tile(tiles[k * 2], i, 1);
+ put_tile(tiles[1 + k * 2], i, 2);
+
+ put_tile(tiles[6 + k * 2], i, 14);
+ put_tile(tiles[7 + k * 2], i, 15);
+ }
+
+ update_screen();
+ screen_fadein();
+
+ for (k = 0; k < 32; k++)
+ wait();
+
+ cpc_SetInkGphStr(2, 162);
+ cpc_SetInkGphStr(3, 170);
+
+ i = 8;
+ j = 60;
+ while (*pt)
+ {
+ switch (*pt)
+ {
+ default:
+ buffer[0] = *pt;
+ cpc_PrintGphStrXY(buffer, i, j);
+ i += 2;
+ break;
+ case '\n':
+ i = 8;
+ j += 10;
+ break;
+ }
+ for (k = 0; *pt != ' ' && k < 3; k++)
+ wait();
+ pt++;
+
+ if (cpc_AnyKeyPressed())
+ goto exit_intro;
+ }
+
+ for (k = 0; k < 42; k++)
+ wait();
+
+ WyzPlayerOff();
+ cpc_WyzConfigurePlayer(0);
+ WyzPlayerOn();
+ cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_EXPLO);
+
+ for (j = 0; j < 4; j++)
+ {
+ for (k = 0; k < 3; k++)
+ {
+ i = intro_pos[k];
+ put_tile(tiles[TILE_EXPLO + 1 + j * 2], i, 1);
+ put_tile(tiles[TILE_EXPLO + j * 2], i, 2);
+ }
+
+ for (k = 0; k < 3; k++)
+ {
+ i = intro_pos[k];
+ put_tile(tiles[TILE_EXPLO + 1 + j * 2], i, 14);
+ put_tile(tiles[TILE_EXPLO + j * 2], i, 15);
+ }
+
+ wait();
+ update_screen();
+ for (i = 0; i < 6; i++)
+ wait();
+ }
+
+ for (k = 0; k < 3; k++)
+ {
+ i = intro_pos[k];
+ put_tile(tiles[TILE_ERASE], i, 1);
+ put_tile(tiles[TILE_ERASE], i, 2);
+
+ put_tile(tiles[TILE_ERASE], i, 14);
+ put_tile(tiles[TILE_ERASE], i, 15);
+ }
+ update_screen();
+
+ for (k = 0; k < 42; k++)
+ wait();
+
+exit_intro:
+ WyzPlayerOff();
+}
+
+const uint16_t bay_addr[] = { 0xc360, 0xcbb0, 0xd400, 0xdc50, 0xe4a0, 0xecf0 };
+
+void
+draw_hud()
+{
+ int8_t i;
+ uint8_t buffer[6];
+
+ cpc_SetInkGphStr(2, 170);
+ cpc_SetInkGphStr(3, 170);
+
+ if (dirty_hud & DIRTY_SCORE)
+ {
+ pad_numbers(buffer, 5, score);
+ cpc_PrintGphStrXY(buffer, 7, 32);
+ }
+
+ if (dirty_hud & DIRTY_LEVEL)
+ {
+ pad_numbers(buffer, 2, level);
+ cpc_PrintGphStrXY(buffer, 67, 32);
+ }
+
+ if (dirty_hud & DIRTY_BAY)
+ {
+ for (i = 2; i >= 0; i--)
+ if (bay[i] == 0)
+ {
+ cpc_PutSp(tiles[TILE_ERASE], 9, 6, bay_addr[i * 2]);
+ cpc_PutSp(tiles[TILE_ERASE], 9, 6, bay_addr[1 + i * 2]);
+ }
+ else
+ {
+ cpc_PutSp(tiles_blocks[(bay[i] - 1) * 2], 9, 6, bay_addr[i * 2]);
+ cpc_PutSp(tiles_blocks[1 + (bay[i] - 1) * 2], 9, 6, bay_addr[1 + i * 2]);
+ }
+
+ }
+
+ dirty_hud = DIRTY_NONE;
+}
+
+const uint16_t ship_addr[] = { 0xdef4, 0xdefa, 0xdf00, 0xdf06, 0xdf0c, 0xdf12, 0xdf18 };
+const uint16_t engine_addr[] = { 0xef94, 0xef9a, 0xefa0, 0xefa6, 0xefac, 0xefb2, 0xefb8 };
+const uint8_t engine_cycle[] = { 3, 2, 3, 2, 1, 2, 1, 0, 1 };
+
+uint8_t engine;
+
+void
+draw_ship()
+{
+ cpc_PutSp(ship[0], 18, 6, ship_addr[px]);
+ if (engine_cycle[engine])
+ cpc_PutSp(&ship[0][126 - (engine_cycle[engine] * 6)], engine_cycle[engine], 6, engine_addr[px]);
+
+ engine++;
+ if (engine > 8)
+ engine = 0;
+
+ old_px = px;
+}
+
+void
+erase_ship()
+{
+ if (old_px != px)
+ cpc_PutSp(ship[1], 21, 6, ship_addr[old_px]);
+ else
+ cpc_PutSp(&ship[1][126 - 18], 3, 6, engine_addr[px]);
+}
+
+void
+draw_board()
+{
+ uint8_t i, j;
+ int8_t c;
+
+ for (j = 0; j < BH; j++)
+ {
+ for (i = 0; i < BW; i++)
+ {
+ if (EFFECT(board[i + j & BW]))
+ continue;
+
+ c = BLOCK(board[i + j * BW]) - 1;
+
+ if (c >= 0)
+ {
+ put_tile(tiles_blocks[c * 2], i, j * 2);
+ put_tile(tiles_blocks[1 + c * 2], i, 1 + j * 2);
+ continue;
+ }
+ }
+ }
+}
+
+int8_t
+update_py()
+{
+ int8_t i;
+
+ for (i = BH - 1; i >= 0; i--)
+ if (board[px + i * BW])
+ break;
+
+ return i;
+}
+
+void
+add_board_line()
+{
+ uint8_t i;
+
+ memmove(board + BW, board, (BW * BH) - BW);
+ for (i = 0; i < BW; ++i)
+ {
+ board[i] = 1 + (rand() % 6);
+ if (!conf_mode && i > 0 && board[i] == board[i - 1])
+ board[i] = 1 + (rand() % 6);
+ }
+
+ if (!last_wild && (rand() % 4) < 2)
+ board[rand() % (BW - 1)] = BLOCK_WILD;
+
+ last_wild = last_wild ? 0 : 1;
+}
+
+// used to calculate the matches
+uint8_t matches;
+int8_t sc_buffer[BW * BH];
+
+void
+process_matches(uint8_t x, uint8_t y, uint8_t tile, uint8_t *matches)
+{
+ int8_t i;
+
+ for (i = x - 1; i >= 0; i--)
+ {
+ if (!BLOCK(board[i + y * BW]))
+ break;
+ if (sc_buffer[i + y * BW] && BLOCK(board[i + y * BW]) == tile)
+ {
+ (*matches)++;
+ sc_buffer[i + y * BW] = 0;
+ process_matches(i, y, tile, matches);
+ }
+ else
+ break;
+ }
+
+ for (i = x + 1; i < BW; i++)
+ {
+ if (!BLOCK(board[i + y * BW]))
+ break;
+ if (sc_buffer[i + y * BW] && BLOCK(board[i + y * BW]) == tile)
+ {
+ (*matches)++;
+ sc_buffer[i + y * BW] = 0;
+ process_matches(i, y, tile, matches);
+ }
+ else
+ break;
+ }
+
+ for (i = y - 1; i >= 0; i--)
+ {
+ if (!BLOCK(board[x + i * BW]))
+ break;
+ if (sc_buffer[x + i * BW] && BLOCK(board[x + i * BW]) == tile)
+ {
+ (*matches)++;
+ sc_buffer[x + i * BW] = 0;
+ process_matches(x, i, tile, matches);
+ }
+ else
+ break;
+ }
+
+ for (i = y + 1; i < BH; i++)
+ {
+ if (!BLOCK(board[x + i * BW]))
+ break;
+ if (sc_buffer[x + i * BW] && BLOCK(board[x + i * BW]) == tile)
+ {
+ (*matches)++;
+ sc_buffer[x + i * BW] = 0;
+ process_matches(x, i, tile, matches);
+ }
+ else
+ break;
+ }
+}
+
+uint16_t
+has_matches()
+{
+ uint8_t i;
+
+ memset(sc_buffer, 0, BLOCK_WILD + 1);
+
+ for (i = 0; i < BW * BH; i++)
+ sc_buffer[BLOCK(board[i])]++;
+
+ for (i = 0; i < 3; i++)
+ sc_buffer[bay[i]]++;
+
+ for (i = 1; i < 7; i++)
+ // 3 matches or 2 + wildcard
+ if (sc_buffer[i] >= 3 || (sc_buffer[i] == 2 && sc_buffer[BLOCK_WILD]))
+ return 1;
+
+ return 0;
+}
+
+void
+draw_effects()
+{
+ uint8_t i, j, e;
+
+ for (j = 0; j < BH; j++)
+ for (i = 0; i < BW; i++)
+ {
+ e = EFFECT(board[i + j * BW]);
+ if (e)
+ {
+ e--;
+ put_tile(tiles[TILE_EXPLO + e * 2], i, 1 + j * 2);
+ put_tile(tiles[TILE_EXPLO + 1 + e * 2], i, j * 2);
+ }
+ }
+}
+
+void
+add_gravity()
+{
+ uint8_t i, j;
+
+ for (j = 1; j < BH; j++)
+ for (i = 0; i < BW; i++)
+ if (BLOCK(board[i + j * BW]) && !BLOCK(board[i + (j - 1) * BW]))
+ {
+ gravity[i + j * 2 * BW] = TILE_GRAVITY;
+ gravity[i + (1 + (j * 2)) * BW] = TILE_GRAVITY + 1;
+ board[i + j * BW] = 0;
+ has_gravity = 1;
+ }
+}
+
+void
+update_effects()
+{
+ uint8_t i, j, e;
+
+ effects_delay++;
+ if (effects_delay < EFFECTS_DELAY)
+ return;
+
+ effects_delay = 0;
+
+ for (j = 0; j < BH; j++)
+ for (i = 0; i < BW; i++)
+ {
+ e = EFFECT(board[i + j * BW]);
+ if (!e)
+ continue;
+
+ if (e < 4)
+ board[i + j * BW] = UPDATE_EFFECT(board[i + j * BW], e + 1);
+ else
+ {
+ board[i + j * BW] = 0;
+ put_tile(tiles[TILE_ERASE], i, j * 2);
+ put_tile(tiles[TILE_ERASE], i, 1 + j * 2);
+
+ has_effects--;
+ if (!has_effects && !gameover)
+ {
+ add_gravity();
+
+ if (!dirty_marker)
+ {
+ put_tile(tiles[TILE_ERASE], px, py * 2);
+ dirty_marker = 1;
+ }
+
+ // check for empty board
+ if (!gameover && bay_top == 2)
+ {
+ empty_board = 1;
+ for (i = 0; i < BW * BH; i++)
+ if (BLOCK(board[i]))
+ {
+ empty_board = 0;
+ break;
+ }
+ }
+ return;
+ }
+ }
+ }
+}
+
+void
+erase_gravity()
+{
+ uint8_t i, j;
+
+ for (j = 0; j < BH * 2; j++)
+ for (i = 0; i < BW; i++)
+ if (gravity[i + j * BW] && j < BH * 2 - 1)
+ put_tile(tiles[TILE_ERASE], i, j);
+}
+
+void
+draw_gravity()
+{
+ uint8_t i, j, c;
+
+ for (j = 0; j < BH * 2; j++)
+ for (i = 0; i < BW; i++)
+ {
+ c = gravity[i + j * BW];
+ if (c)
+ {
+ if (j < BH * 2 - 1)
+ put_tile(tiles[c], i, j);
+ if (j && !BLOCK(board[i + (j >> 1) * BW]) && !gravity[i + (j - 1) * BW])
+ put_tile(tiles[TILE_ERASE], i, j - 1);
+ }
+ }
+}
+
+void
+update_gravity()
+{
+ uint8_t i;
+
+ gravity_delay++;
+ if (gravity_delay < GRAVITY_DELAY)
+ return;
+
+ gravity_delay = 0;
+ has_gravity = 0;
+
+ memmove(gravity + BW, gravity, (BW * BH * 2) - BW);
+ memset(gravity, 0, BW);
+
+ for (i = BW; i < BW * BH * 2; i++)
+ if (gravity[i])
+ {
+ has_gravity = 1;
+ return;
+ }
+}
+
+void
+level_up()
+{
+ level++;
+ next_level = 24 + 3 * (int16_t)level;
+
+ if (conf_mode) // easy
+ next_line_level -= 16;
+ else
+ next_line_level -= 32;
+
+ if (level % 5 == 0)
+ next_line_level += 84;
+ if (next_line_level < 64)
+ next_line_level = 64;
+
+ dirty_hud |= DIRTY_LEVEL;
+}
+
+void
+dec_engame()
+{
+ uint8_t i = 21, j = 70, k;
+ uint8_t p = 0x59, key = 0xfe, c;
+ const uint8_t *pt = endgame;
+ uint8_t buffer[2] = { 0, 0};
+
+ while (1)
+ {
+ c = (*pt ^ key) ^ p;
+ if (!c)
+ break;
+
+ switch (c)
+ {
+ default:
+ buffer[0] = c;
+ cpc_PrintGphStrXY(buffer, i, j);
+ for (k = 0; c != ' ' && k < 3; k++)
+ {
+ wait();
+ erase_ship();
+ draw_ship();
+ }
+ i += 2;
+ break;
+ case '\n':
+ i = 21;
+ j += 10;
+ break;
+ }
+ p = *pt;
+ pt++;
+ }
+}
+
+void
+run_play()
+{
+ uint8_t i, j, c, k_delay = 0;
+ int8_t h;
+
+ srand(tick);
+ cpc_WyzConfigurePlayer(0);
+ WyzPlayerOn();
+
+ init_tiles();
+
+ memset(board, 0, BW * BH);
+
+ // frequency of the wildcards
+ last_wild = 0;
+
+ has_effects = 0;
+ effects_delay = 0;
+ combo_delay = 0;
+
+ has_gravity = 0;
+ gravity_delay = 0;
+
+ empty_board = 0;
+ gameover = 0;
+ paused = 0;
+ score = 0;
+ level = 1;
+ next_level = 15;
+ next_line = 0;
+ next_line_level = 336;
+
+ px = 3;
+ old_px = 3;
+ py = 0;
+ engine = 0;
+
+ bay_top = 2;
+ memset(bay, 0, 3);
+
+ add_board_line();
+ add_board_line();
+ draw_board();
+
+ py = 1 + update_py();
+ put_tile(tiles[TILE_MARKER], px, py * 2);
+ dirty_marker = 0;
+
+ screen_black();
+
+ wait_vsync();
+ ucl_uncompress(playbg, (uint8_t *)0xc000);
+ update_screen();
+
+ if (conf_mode) // easy
+ {
+ cpc_SetInkGphStr(2, 8);
+ cpc_SetInkGphStr(3, 8);
+ cpc_PrintGphStrXY("EASY", 0, 190);
+ }
+
+ dirty_hud = DIRTY_ALL;
+ draw_hud();
+
+ draw_ship();
+
+ cpc_SetInkGphStr(2, 138);
+ cpc_SetInkGphStr(3, 42);
+ cpc_PrintGphStrXY2X("READY?", 35, 90);
+
+ screen_fadein();
+
+ cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_READY);
+ for (i = 0; i < 58; i++)
+ {
+ wait();
+ erase_ship();
+ draw_ship();
+ }
+
+ do_text_fadeout("READY?", 35, 90);
+
+ if (conf_music)
+ {
+ WyzPlayerOff();
+ cpc_WyzLoadSong(1);
+ WyzPlayerOn();
+ }
+
+ while (1)
+ {
+ cpc_ScanKeyboard();
+
+ if (cpc_TestKeyF(KEY_QUIT))
+ break;
+
+ if (!k_delay)
+ {
+ if (cpc_TestKeyF(KEY_PAUSE))
+ {
+ if (!paused)
+ {
+ memset((uint8_t *)BUFF_ADDR, 0, TMW * TMH * TH * TW / 2);
+ for (j = 0; j < TMH - 1; j++)
+ for (i = 0; i < TMW; i++)
+ invalidate_tile_xy(i, j);
+
+ wait();
+ update_screen();
+
+ cpc_SetInkGphStr(2, 138);
+ cpc_SetInkGphStr(3, 42);
+ cpc_PrintGphStrXY2X("PAUSED", 35, 80);
+
+ if (conf_music)
+ {
+ WyzPlayerOff();
+ cpc_WyzConfigurePlayer(0);
+ WyzPlayerOn();
+ }
+
+ cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_ERROR);
+ paused = 1;
+
+ }
+ else
+ {
+ do_text_fadeout("PAUSED", 35, 80);
+
+ draw_board();
+ if (has_effects)
+ draw_effects();
+ if (has_gravity)
+ draw_gravity();
+
+ put_tile(tiles[TILE_MARKER], px, py * 2);
+ dirty_marker = 0;
+
+ wait();
+ update_screen();
+
+ paused = 0;
+
+ if (conf_music)
+ {
+ WyzPlayerOff();
+ cpc_WyzLoadSong(1);
+ WyzPlayerOn();
+ }
+ }
+
+ k_delay = K_DELAY;
+ continue;
+ }
+
+ if (paused)
+ goto skip_controls;
+
+ if (cpc_TestKeyF(KEY_RIGHT) && !cpc_TestKeyF(KEY_LEFT))
+ {
+ if (px < BW - 1)
+ {
+ put_tile(tiles[TILE_ERASE], px, py * 2);
+ px++;
+ dirty_marker = 1;
+ }
+
+ k_delay = K_DELAY;
+ }
+
+ if (cpc_TestKeyF(KEY_LEFT) && !cpc_TestKeyF(KEY_RIGHT))
+ {
+ if (px > 0)
+ {
+ put_tile(tiles[TILE_ERASE], px, py * 2);
+ px--;
+ dirty_marker = 1;
+ }
+
+ k_delay = K_DELAY;
+ }
+
+ if ((cpc_TestKeyF(KEY_BEAM) || cpc_TestKeyF(KEY_ALT_BEAM))
+ && !cpc_TestKeyF(KEY_FIRE))
+ {
+ if (bay_top >= 0)
+ {
+ h = update_py();
+
+ if (h >= 0 && !EFFECT(board[px + h * BW]))
+ {
+ bay[bay_top--] = board[px + h * BW];
+ board[px + h * BW] = 0;
+
+ put_tile(tiles[TILE_ERASE], px, h * 2);
+ put_tile(tiles[TILE_ERASE], px, 1 + h * 2);
+
+ if (!dirty_marker)
+ {
+ put_tile(tiles[TILE_ERASE], px, py * 2);
+ dirty_marker = 1;
+ }
+
+ dirty_hud |= DIRTY_BAY;
+ }
+ else
+ cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_ERROR);
+ }
+ else
+ cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_ERROR);
+
+ k_delay = K_DELAY;
+ }
+
+ if (cpc_TestKeyF(KEY_FIRE) && !cpc_TestKeyF(KEY_BEAM)
+ && !cpc_TestKeyF(KEY_ALT_BEAM))
+ {
+ if (bay_top < 2)
+ {
+ h = update_py();
+
+ if (h == BH - 2)
+ {
+ k_delay = K_DELAY;
+ cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_ERROR);
+ continue;
+ }
+
+ // change wildcard to target block
+ if (BLOCK(bay[bay_top + 1]) == BLOCK_WILD
+ && h >= 0 && BLOCK(board[px + h * BW]))
+ bay[bay_top + 1] = BLOCK(board[px + h * BW]);
+
+ h++;
+ bay_top++;
+ board[px + h * BW] = bay[bay_top];
+ c = bay[bay_top];
+ bay[bay_top] = 0;
+ dirty_hud |= DIRTY_BAY;
+
+ matches = 0;
+ memset(sc_buffer, 1, BW * BH);
+ process_matches(px, h, c, &matches);
+
+ // 3 matches and not targeting a wildcard!
+ if (matches >= 3 && BLOCK(board[px + h * BW]) != BLOCK_WILD)
+ {
+ next_level -= matches;
+
+ for (j = 0; j < BH; j++)
+ for (i = 0; i < BW; i++)
+ {
+ if (!sc_buffer[i + j * BW])
+ {
+ if (EFFECT(board[i + j * BW]))
+ {
+ cpc_SetInkGphStr(2, 138);
+ cpc_SetInkGphStr(3, 42);
+
+ cpc_PrintGphStrXY("COMBO!", 6, 52);
+ combo_delay = 32;
+ }
+ else
+ has_effects++;
+ board[i + j * BW] = UPDATE_EFFECT(board[i + j * BW], 1);
+ cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_EXPLO);
+ }
+ }
+
+ score += matches * 5;
+ if (matches > 3)
+ score += (matches - 3) * 10;
+
+ dirty_hud |= DIRTY_SCORE;
+
+ if (score > hiscore)
+ hiscore = score;
+ }
+ else
+ {
+ c--;
+ // draw only the changed tile
+ put_tile(tiles_blocks[c * 2], px, h * 2);
+ put_tile(tiles_blocks[1 + c * 2], px, 1 + h * 2);
+ }
+
+ // will update marker
+ dirty_marker = 1;
+ }
+ else
+ cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_ERROR);
+
+ k_delay = K_DELAY;
+ }
+ }
+ else
+ k_delay--;
+
+skip_controls:
+ if (!paused && has_effects)
+ {
+ update_effects();
+ draw_effects();
+ }
+
+ if (!paused && has_gravity)
+ {
+ update_gravity();
+ draw_gravity();
+ }
+
+ if (dirty_marker)
+ {
+ py = 1 + update_py();
+ put_tile(tiles[TILE_MARKER], px, py * 2);
+ dirty_marker = 0;
+ }
+
+ wait();
+ update_screen();
+ erase_ship();
+ draw_ship();
+ draw_hud();
+
+ if (paused)
+ continue;
+
+ if (combo_delay)
+ {
+ combo_delay--;
+ if (!combo_delay)
+ cpc_PrintGphStrXY(" ", 6, 52);
+ }
+
+ if (empty_board)
+ {
+ if (conf_music)
+ {
+ WyzPlayerOff();
+ cpc_WyzConfigurePlayer(0);
+ WyzPlayerOn();
+ }
+
+ while (has_gravity)
+ {
+ update_gravity();
+ draw_gravity();
+ wait();
+ update_screen();
+ erase_ship();
+ draw_ship();
+ }
+
+ if (combo_delay)
+ {
+ combo_delay = 0;
+ cpc_PrintGphStrXY(" ", 6, 52);
+ }
+
+ dirty_hud = DIRTY_ALL;
+ draw_hud();
+
+ memset((uint8_t *)BUFF_ADDR, 0, TMW * TMH * TH * TW / 2);
+ for (j = 0; j < TMH - 1; j++)
+ for (i = 0; i < TMW; i++)
+ invalidate_tile_xy(i, j);
+
+ wait();
+ update_screen();
+
+ px = 3;
+
+ WyzPlayerOff();
+ ucl_uncompress(board_mus, (uint8_t *)7000);
+ cpc_WyzLoadSong(0);
+ WyzPlayerOn();
+
+ cpc_SetInkGphStr(2, 138);
+ cpc_SetInkGphStr(3, 42);
+ cpc_PrintGphStrXY2X("FULL BOARD", 31, 60);
+ for (i = 0; i < 72; i++)
+ {
+ wait();
+ erase_ship();
+ draw_ship();
+ }
+
+ WyzPlayerOff();
+ WyzPlayerOn();
+
+ cpc_SetInkGphStr(2, 160);
+ cpc_SetInkGphStr(3, 40);
+ cpc_PrintGphStrXY("LINES", 31, 85);
+ i = 0;
+ if (next_level > 0)
+ i += next_level * 10;
+ score += i;
+ pad_numbers((uint8_t *)BUFF_ADDR, 4, i);
+ cpc_PrintGphStrXY((char *)BUFF_ADDR, 31 + 12, 85);
+
+ dirty_hud = DIRTY_SCORE;
+ draw_hud();
+
+ if (i == 0)
+ cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_ERROR);
+ else
+ cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_LEVEL);
+
+ for (i = 0; i < 46; i++)
+ {
+ wait();
+ erase_ship();
+ draw_ship();
+ }
+
+ score += 2500;
+ cpc_SetInkGphStr(2, 160);
+ cpc_SetInkGphStr(3, 40);
+ cpc_PrintGphStrXY("EXTRA 2500", 31, 95);
+
+ dirty_hud = DIRTY_SCORE;
+ draw_hud();
+
+ cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_LEVEL);
+ for (i = 0; i < 46; i++)
+ {
+ wait();
+ erase_ship();
+ draw_ship();
+ }
+
+ cpc_SetInkGphStr(2, 42);
+ cpc_SetInkGphStr(3, 170);
+ cpc_PrintGphStrXY("LEVEL UP!", 31, 115);
+
+ level_up();
+ draw_hud();
+
+ cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_LEVEL);
+ for (i = 0; i < 46; i++)
+ {
+ wait();
+ erase_ship();
+ draw_ship();
+ }
+
+ memset((uint8_t *)BUFF_ADDR, 0, TMW * TMH * TH * TW / 2);
+ for (j = 0; j < TMH - 1; j++)
+ for (i = 0; i < TMW; i++)
+ invalidate_tile_xy(i, j);
+
+ wait();
+ update_screen();
+
+ next_line = 0;
+ add_board_line();
+ add_board_line();
+ draw_board();
+
+ py = 1 + update_py();
+ put_tile(tiles[TILE_MARKER], px, py * 2);
+ dirty_marker = 0;
+
+ wait();
+ update_screen();
+
+ cpc_SetInkGphStr(2, 138);
+ cpc_SetInkGphStr(3, 42);
+ cpc_PrintGphStrXY2X("READY?", 35, 90);
+
+ cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_READY);
+ for (i = 0; i < 58; i++)
+ {
+ wait();
+ erase_ship();
+ draw_ship();
+ }
+
+ do_text_fadeout("READY?", 35, 90);
+
+ if (conf_music)
+ {
+ WyzPlayerOff();
+ cpc_WyzLoadSong(1);
+ WyzPlayerOn();
+ }
+
+ if (score > hiscore)
+ hiscore = score;
+
+ empty_board = 0;
+ continue;
+ }
+
+ if (++next_line > next_line_level || !has_matches())
+ {
+ next_line = 0;
+ add_board_line();
+ cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_LINE);
+
+ if (has_gravity)
+ {
+ update_gravity();
+ update_gravity();
+ draw_gravity();
+ }
+
+ draw_board();
+
+ for (i = 0; i < BW; i++)
+ if (board[i + (BH - 1) * BW] != 0)
+ {
+ if (conf_music)
+ {
+ WyzPlayerOff();
+ cpc_WyzConfigurePlayer(0);
+ WyzPlayerOn();
+ }
+
+ update_screen();
+ gameover = 1;
+
+ bay_top = 2;
+ memset(bay, 0, 3);
+ dirty_hud |= DIRTY_BAY;
+ draw_hud();
+
+ // hacky!
+ memset((uint8_t *)BUFF_ADDR, 0, TMW * TMH * TH * TW / 2);
+ for (i = 0; i < BW; i++)
+ invalidate_tile_xy(i, TMH - 1);
+
+ wait();
+ cpc_PutSp(ship[1], 21, 6, ship_addr[px]);
+ update_screen();
+
+ erase_gravity();
+ put_tile(tiles[TILE_ERASE], px, py * 2);
+ draw_board();
+ wait();
+ update_screen();
+
+ for (j = 0; j < BH; j++)
+ {
+ for (i = 0; i < BW; i++)
+ if (BLOCK(board[i + (BH - 1 - j) * BW])
+ && !EFFECT(board[i + (BH - 1 - j) * BW]))
+ {
+ board[i + (BH - 1 - j) * BW] = UPDATE_EFFECT(1, 1);
+ has_effects++;
+ }
+
+ cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_EXPLO);
+ while (has_effects)
+ {
+ update_effects();
+ draw_effects();
+ update_screen();
+ }
+ }
+
+ cpc_SetInkGphStr(2, 138);
+ cpc_SetInkGphStr(3, 42);
+ cpc_PrintGphStrXY2X("GAME OVER", 31, 80);
+
+ WyzPlayerOff();
+ ucl_uncompress(gameover_mus, (uint8_t *)7000);
+ cpc_WyzLoadSong(0);
+ WyzPlayerOn();
+
+ for (i = 0; i < 118; i++)
+ wait();
+
+ WyzPlayerOff();
+
+ for (i = 0; i < 24; i++)
+ wait();
+
+ do_text_fadeout("GAME OVER", 31, 80);
+ break;
+ }
+
+ if (gameover)
+ break;
+
+ py = 1 + update_py();
+ put_tile(tiles[TILE_MARKER], px, py * 2);
+ dirty_marker = 0;
+
+ wait();
+ update_screen();
+ }
+
+ if (!has_effects && next_level <= 0)
+ {
+ cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_LEVEL);
+ level_up();
+
+ if (level > ENDGAME)
+ {
+ gameover = 1;
+ bay_top = 2;
+ memset(bay, 0, 3);
+ dirty_hud |= DIRTY_BAY;
+ draw_hud();
+
+ erase_gravity();
+ put_tile(tiles[TILE_ERASE], px, py * 2);
+ draw_board();
+ wait();
+ update_screen();
+
+ px = 3;
+
+ for (j = 0; j < BH; j++)
+ {
+ for (i = 0; i < BW; i++)
+ if (BLOCK(board[i + (BH - 1 - j) * BW])
+ && !EFFECT(board[i + (BH - 1 - j) * BW]))
+ {
+ board[i + (BH - 1 - j) * BW] = UPDATE_EFFECT(1, 1);
+ has_effects++;
+ }
+
+ cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_EXPLO);
+ while (has_effects)
+ {
+ update_effects();
+ draw_effects();
+ update_screen();
+ erase_ship();
+ draw_ship();
+ }
+ }
+
+ cpc_SetInkGphStr(2, 138);
+ cpc_SetInkGphStr(3, 42);
+ cpc_PrintGphStrXY2X("WELL DONE!", 31, 35);
+
+ WyzPlayerOff();
+ ucl_uncompress(return_mus, (uint8_t *)7000);
+ cpc_WyzLoadSong(0);
+ WyzPlayerOn();
+
+ cpc_SetInkGphStr(2, 162);
+ cpc_SetInkGphStr(3, 170);
+ dec_engame();
+
+ // be sure the keyboard is free
+ while (cpc_AnyKeyPressed())
+ wait();
+
+ while (!cpc_AnyKeyPressed())
+ {
+ wait();
+ erase_ship();
+ draw_ship();
+ }
+
+ wait_vsync();
+ cpc_ClrScr();
+
+ break;
+ }
+ }
+ }
+
+ WyzPlayerOff();
+
+ wait_vsync();
+ cpc_ClrScr();
+}
+
+const uint8_t text_cycle[] = { 0x4b, 0x4a, 0x47, 0x4e, 0x4c, 0x4e, 0x47, 0x4a };
+
+int
+main()
+{
+ uint8_t cycle = 0;
+
+ setup_int();
+
+ // black
+ set_hw_border(0x54);
+ set_hw_ink(0, 0x54);
+
+ cpc_WyzInitPlayer(wyz_sound_table, wyz_ins_table, wyz_effect_table, wyz_song_table);
+ cpc_WyzConfigurePlayer(0);
+
+ cpc_SetFont(31, font);
+
+ joystick = 1;
+ map_keys();
+ cpc_AssignKey(KEY_QUIT, 0x4804); // ESC
+ cpc_AssignKey(8, 0x4801); // 1
+ cpc_AssignKey(9, 0x4802); // 2
+ cpc_AssignKey(10, 0x4702); // 3
+ cpc_AssignKey(11, 0x4701); // 4
+
+ cpc_SetInkGphStr(0, 0);
+
+ screen_black();
+ cpc_ClrScr();
+ run_intro();
+
+ screen_black();
+ cpc_ClrScr();
+ draw_menu();
+ screen_fadein();
+
+ ucl_uncompress(return_mus, (uint8_t *)7000);
+ cpc_WyzLoadSong(0);
+ WyzPlayerOn();
+
+ while (1)
+ {
+ cpc_ScanKeyboard();
+
+ if (cpc_TestKeyF(8) && !cpc_TestKeyF(9) && !joystick) // key: 1
+ {
+ joystick = 1;
+ wait_vsync();
+ draw_controls();
+
+ map_keys();
+ continue;
+ }
+
+ if (cpc_TestKeyF(9) && !cpc_TestKeyF(8) && joystick) // key: 2
+ {
+ joystick = 0;
+ wait_vsync();
+ draw_controls();
+
+ map_keys();
+ continue;
+ }
+
+ if (cpc_TestKeyF(10)) // key: 3
+ {
+ run_redefine();
+
+ joystick = 0;
+ draw_controls();
+ continue;
+ }
+
+ if (cpc_TestKeyF(11)) // key: 4
+ {
+ run_options();
+
+ draw_controls();
+ continue;
+ }
+
+ if (cpc_TestKey(KEY_FIRE) || cpc_TestKey(KEY_BEAM)) // fire
+ {
+ // clean the cycle
+ set_hw_ink(1, 0x44);
+ WyzPlayerOff();
+
+ run_play();
+
+ screen_black();
+ draw_menu();
+ screen_fadein();
+
+ ucl_uncompress(return_mus, (uint8_t *)7000);
+ cpc_WyzLoadSong(0);
+ WyzPlayerOn();
+ }
+
+ wait();
+ if (++cycle > 7)
+ cycle = 0;
+ set_hw_ink(1, text_cycle[cycle]);
+ }
+}