Chris Dick
/
Gameduino_Manic_Miner_game
Manic miner game for the Gameduino
main.cpp@1:e047847f1cda, 2012-12-21 (annotated)
- Committer:
- TheChrisyd
- Date:
- Fri Dec 21 14:00:03 2012 +0000
- Revision:
- 1:e047847f1cda
- Parent:
- 0:a2d36977aec3
sound on title screen not working, otherwise ok
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
TheChrisyd | 0:a2d36977aec3 | 1 | #include "mbed.h" |
TheChrisyd | 0:a2d36977aec3 | 2 | #include "GD.h" |
TheChrisyd | 0:a2d36977aec3 | 3 | #include "arduino.h" |
TheChrisyd | 1:e047847f1cda | 4 | #include "shield.h" |
TheChrisyd | 0:a2d36977aec3 | 5 | |
TheChrisyd | 1:e047847f1cda | 6 | GDClass GD(ARD_MOSI, ARD_MISO, ARD_SCK, ARD_D9, USBTX, USBRX) ; |
TheChrisyd | 0:a2d36977aec3 | 7 | SPI spi(ARD_MOSI, ARD_MISO, ARD_SCK);// mosi, miso, sclk |
TheChrisyd | 0:a2d36977aec3 | 8 | DigitalOut cs(ARD_D9); |
TheChrisyd | 0:a2d36977aec3 | 9 | Serial pc(USBTX, USBRX); |
TheChrisyd | 0:a2d36977aec3 | 10 | |
TheChrisyd | 0:a2d36977aec3 | 11 | #define CHEAT_INVINCIBLE 0 // means Willy unaffected by nasties |
TheChrisyd | 0:a2d36977aec3 | 12 | #define START_LEVEL 0 // level to start on, 0-18 |
TheChrisyd | 0:a2d36977aec3 | 13 | #define CHEAT_OPEN_PORTAL 0 // Portal always open |
TheChrisyd | 0:a2d36977aec3 | 14 | |
TheChrisyd | 0:a2d36977aec3 | 15 | // Game has three controls: LEFT, RIGHT, JUMP. You can map them |
TheChrisyd | 0:a2d36977aec3 | 16 | // to any pins by changing the definitions of PIN_L, PIN_R, PIN_J |
TheChrisyd | 0:a2d36977aec3 | 17 | // below. |
TheChrisyd | 0:a2d36977aec3 | 18 | |
TheChrisyd | 0:a2d36977aec3 | 19 | #if 1 // SPARKFUN_JOYSTICK |
TheChrisyd | 1:e047847f1cda | 20 | #define PIN_L ARD_A0 |
TheChrisyd | 1:e047847f1cda | 21 | #define PIN_R ARD_A1 |
TheChrisyd | 1:e047847f1cda | 22 | #define PIN_J ARD_D6 |
TheChrisyd | 0:a2d36977aec3 | 23 | #else |
TheChrisyd | 0:a2d36977aec3 | 24 | #define PIN_L ARD_A2 |
TheChrisyd | 0:a2d36977aec3 | 25 | #define PIN_R ARD_A3 |
TheChrisyd | 0:a2d36977aec3 | 26 | #define PIN_J ARD_A5 |
TheChrisyd | 0:a2d36977aec3 | 27 | #endif |
TheChrisyd | 0:a2d36977aec3 | 28 | |
TheChrisyd | 0:a2d36977aec3 | 29 | #define CONTROL_LEFT 1 |
TheChrisyd | 0:a2d36977aec3 | 30 | #define CONTROL_RIGHT 2 |
TheChrisyd | 0:a2d36977aec3 | 31 | #define CONTROL_JUMP 4 |
TheChrisyd | 0:a2d36977aec3 | 32 | |
TheChrisyd | 1:e047847f1cda | 33 | DigitalIn jump(ARD_D4); |
TheChrisyd | 1:e047847f1cda | 34 | DigitalIn jumpa(ARD_D5); |
TheChrisyd | 1:e047847f1cda | 35 | DigitalIn jumpb(ARD_D6); |
TheChrisyd | 1:e047847f1cda | 36 | DigitalIn jumpc(ARD_D7); |
TheChrisyd | 1:e047847f1cda | 37 | DigitalIn jumpd(ARD_A4); |
TheChrisyd | 1:e047847f1cda | 38 | DigitalIn left(ARD_A1); |
TheChrisyd | 1:e047847f1cda | 39 | DigitalIn right(ARD_A0); |
TheChrisyd | 0:a2d36977aec3 | 40 | |
TheChrisyd | 0:a2d36977aec3 | 41 | static byte setup_control() |
TheChrisyd | 0:a2d36977aec3 | 42 | { |
TheChrisyd | 1:e047847f1cda | 43 | jump.mode(PullUp); |
TheChrisyd | 1:e047847f1cda | 44 | jumpa.mode(PullUp); |
TheChrisyd | 1:e047847f1cda | 45 | jumpb.mode(PullUp); |
TheChrisyd | 1:e047847f1cda | 46 | jumpc.mode(PullUp); |
TheChrisyd | 1:e047847f1cda | 47 | jumpd.mode(PullUp); |
TheChrisyd | 1:e047847f1cda | 48 | left.mode(PullUp); |
TheChrisyd | 1:e047847f1cda | 49 | right.mode(PullUp); |
TheChrisyd | 0:a2d36977aec3 | 50 | } |
TheChrisyd | 0:a2d36977aec3 | 51 | |
TheChrisyd | 0:a2d36977aec3 | 52 | static byte control() |
TheChrisyd | 0:a2d36977aec3 | 53 | { |
TheChrisyd | 0:a2d36977aec3 | 54 | byte r = 0; |
TheChrisyd | 1:e047847f1cda | 55 | //if (jump) |
TheChrisyd | 1:e047847f1cda | 56 | // r |= CONTROL_JUMP; |
TheChrisyd | 1:e047847f1cda | 57 | if (!jumpa) |
TheChrisyd | 1:e047847f1cda | 58 | r |= CONTROL_JUMP; |
TheChrisyd | 1:e047847f1cda | 59 | if (!jumpb) |
TheChrisyd | 0:a2d36977aec3 | 60 | r |= CONTROL_JUMP; |
TheChrisyd | 1:e047847f1cda | 61 | if (!jumpc) |
TheChrisyd | 1:e047847f1cda | 62 | r |= CONTROL_JUMP; |
TheChrisyd | 1:e047847f1cda | 63 | if (!jumpd) |
TheChrisyd | 1:e047847f1cda | 64 | r |= CONTROL_JUMP; |
TheChrisyd | 1:e047847f1cda | 65 | if (!left) |
TheChrisyd | 0:a2d36977aec3 | 66 | r |= CONTROL_LEFT; |
TheChrisyd | 1:e047847f1cda | 67 | if (!right) |
TheChrisyd | 0:a2d36977aec3 | 68 | r |= CONTROL_RIGHT; |
TheChrisyd | 0:a2d36977aec3 | 69 | return r; |
TheChrisyd | 0:a2d36977aec3 | 70 | } |
TheChrisyd | 0:a2d36977aec3 | 71 | |
TheChrisyd | 0:a2d36977aec3 | 72 | #define BLACK RGB(0,0,0) |
TheChrisyd | 0:a2d36977aec3 | 73 | #define RED RGB(255,0,0) |
TheChrisyd | 0:a2d36977aec3 | 74 | #define YELLOW RGB(255,255,0) |
TheChrisyd | 0:a2d36977aec3 | 75 | #define CYAN RGB(0,255,255) |
TheChrisyd | 0:a2d36977aec3 | 76 | #define GREEN RGB(0,255,0) |
TheChrisyd | 0:a2d36977aec3 | 77 | #define MAGENTA RGB(255,0,255) |
TheChrisyd | 0:a2d36977aec3 | 78 | #define WHITE RGB(255,255,255) |
TheChrisyd | 0:a2d36977aec3 | 79 | |
TheChrisyd | 0:a2d36977aec3 | 80 | #define CHR_BORDER 31 // hw char used for all of the border |
TheChrisyd | 0:a2d36977aec3 | 81 | #define CHR_AIR 128 // AIR line |
TheChrisyd | 0:a2d36977aec3 | 82 | |
TheChrisyd | 0:a2d36977aec3 | 83 | // assigned sprite images and sprite numbers |
TheChrisyd | 0:a2d36977aec3 | 84 | #define IMG_ITEM 0 // items 0-4 |
TheChrisyd | 0:a2d36977aec3 | 85 | #define IMG_PORTAL 5 // room exit |
TheChrisyd | 0:a2d36977aec3 | 86 | #define IMG_SWITCH1 6 // the switches for the Kong Beast levels |
TheChrisyd | 0:a2d36977aec3 | 87 | #define IMG_SWITCH2 7 |
TheChrisyd | 0:a2d36977aec3 | 88 | #define IMG_GUARD 8 // All guardians, 8 max |
TheChrisyd | 0:a2d36977aec3 | 89 | #define IMG_NASTY1 16 // Nasty blocks |
TheChrisyd | 0:a2d36977aec3 | 90 | #define IMG_NASTY2 17 |
TheChrisyd | 0:a2d36977aec3 | 91 | #define IMG_WILLYC 56 |
TheChrisyd | 0:a2d36977aec3 | 92 | #define IMG_WILLY 63 |
TheChrisyd | 0:a2d36977aec3 | 93 | |
TheChrisyd | 0:a2d36977aec3 | 94 | #define ELEM_AIR 0 |
TheChrisyd | 0:a2d36977aec3 | 95 | #define ELEM_FLOOR 1 |
TheChrisyd | 0:a2d36977aec3 | 96 | #define ELEM_CRUMBLE 2 |
TheChrisyd | 0:a2d36977aec3 | 97 | #define ELEM_WALL 3 |
TheChrisyd | 0:a2d36977aec3 | 98 | #define ELEM_CONVEYOR 4 |
TheChrisyd | 0:a2d36977aec3 | 99 | #define ELEM_NASTY1 5 |
TheChrisyd | 0:a2d36977aec3 | 100 | #define ELEM_NASTY2 6 |
TheChrisyd | 0:a2d36977aec3 | 101 | |
TheChrisyd | 0:a2d36977aec3 | 102 | struct level { |
TheChrisyd | 0:a2d36977aec3 | 103 | byte name[32]; |
TheChrisyd | 0:a2d36977aec3 | 104 | prog_uchar *background; |
TheChrisyd | 0:a2d36977aec3 | 105 | byte border; |
TheChrisyd | 0:a2d36977aec3 | 106 | prog_uchar bgchars[64]; |
TheChrisyd | 0:a2d36977aec3 | 107 | byte bgattr[8]; |
TheChrisyd | 0:a2d36977aec3 | 108 | byte item[8]; |
TheChrisyd | 0:a2d36977aec3 | 109 | struct { byte x, y; } items[5]; |
TheChrisyd | 0:a2d36977aec3 | 110 | byte portal[32]; |
TheChrisyd | 0:a2d36977aec3 | 111 | byte air; |
TheChrisyd | 0:a2d36977aec3 | 112 | byte conveyordir; |
TheChrisyd | 0:a2d36977aec3 | 113 | byte portalattr, portalx, portaly; |
TheChrisyd | 0:a2d36977aec3 | 114 | byte guardian[8 * 32]; |
TheChrisyd | 0:a2d36977aec3 | 115 | struct { byte a, x, y, d, x0, x1; } hguard[8]; |
TheChrisyd | 0:a2d36977aec3 | 116 | byte wx, wy, wd, wf; |
TheChrisyd | 0:a2d36977aec3 | 117 | byte bidir; |
TheChrisyd | 0:a2d36977aec3 | 118 | }; |
TheChrisyd | 0:a2d36977aec3 | 119 | #include "manicminer.h" |
TheChrisyd | 0:a2d36977aec3 | 120 | #include "spectrum.h" |
TheChrisyd | 0:a2d36977aec3 | 121 | #include "spectrum_data.h" // title screen |
TheChrisyd | 0:a2d36977aec3 | 122 | |
TheChrisyd | 0:a2d36977aec3 | 123 | #define COLOR(i) (pgm_read_word_near(specpal + (2 * (i)))) |
TheChrisyd | 0:a2d36977aec3 | 124 | #define BRIGHT(x) (((x) & 64) >> 3) |
TheChrisyd | 0:a2d36977aec3 | 125 | #define PAPER(a) ((((a) >> 3) & 7) | BRIGHT(a)) |
TheChrisyd | 0:a2d36977aec3 | 126 | #define INK(a) (((a) & 7) | BRIGHT(a)) |
TheChrisyd | 0:a2d36977aec3 | 127 | |
TheChrisyd | 0:a2d36977aec3 | 128 | // screen coordinate - Spectrum 256x192 screen is centered in Gameduino screen |
TheChrisyd | 0:a2d36977aec3 | 129 | static uint16_t atxy(byte x, byte y) |
TheChrisyd | 0:a2d36977aec3 | 130 | { |
TheChrisyd | 0:a2d36977aec3 | 131 | return RAM_PIC + 64 * (y + 6) + (x + 9); |
TheChrisyd | 0:a2d36977aec3 | 132 | } |
TheChrisyd | 0:a2d36977aec3 | 133 | |
TheChrisyd | 0:a2d36977aec3 | 134 | // unpack 8 monochrome pixels into Gameduino character RAM |
TheChrisyd | 0:a2d36977aec3 | 135 | void unpack8(byte b) |
TheChrisyd | 0:a2d36977aec3 | 136 | { |
TheChrisyd | 0:a2d36977aec3 | 137 | static byte stretch[16] = { |
TheChrisyd | 0:a2d36977aec3 | 138 | 0x00, 0x03, 0x0c, 0x0f, |
TheChrisyd | 0:a2d36977aec3 | 139 | 0x30, 0x33, 0x3c, 0x3f, |
TheChrisyd | 0:a2d36977aec3 | 140 | 0xc0, 0xc3, 0xcc, 0xcf, |
TheChrisyd | 0:a2d36977aec3 | 141 | 0xf0, 0xf3, 0xfc, 0xff |
TheChrisyd | 0:a2d36977aec3 | 142 | }; |
TheChrisyd | 0:a2d36977aec3 | 143 | spi.write(stretch[b >> 4]); |
TheChrisyd | 0:a2d36977aec3 | 144 | spi.write(stretch[b & 15]); |
TheChrisyd | 0:a2d36977aec3 | 145 | } |
TheChrisyd | 0:a2d36977aec3 | 146 | |
TheChrisyd | 0:a2d36977aec3 | 147 | // unpack monochrome bitmap from flash to Gameduino character RAM at dst |
TheChrisyd | 0:a2d36977aec3 | 148 | void unpack8xn(uint16_t dst, PROGMEM prog_uchar *src, uint16_t size) |
TheChrisyd | 0:a2d36977aec3 | 149 | { |
TheChrisyd | 0:a2d36977aec3 | 150 | GD.__wstart(dst); |
TheChrisyd | 0:a2d36977aec3 | 151 | while (size--) |
TheChrisyd | 0:a2d36977aec3 | 152 | unpack8(pgm_read_byte_near(src++)); |
TheChrisyd | 0:a2d36977aec3 | 153 | GD.__end(); |
TheChrisyd | 0:a2d36977aec3 | 154 | } |
TheChrisyd | 0:a2d36977aec3 | 155 | |
TheChrisyd | 0:a2d36977aec3 | 156 | // Load 8x8 1-bit sprite from src into slot (0-63) |
TheChrisyd | 0:a2d36977aec3 | 157 | // zero and one are the two colors |
TheChrisyd | 0:a2d36977aec3 | 158 | |
TheChrisyd | 0:a2d36977aec3 | 159 | void send8(byte b, byte zero, byte one) |
TheChrisyd | 0:a2d36977aec3 | 160 | { |
TheChrisyd | 0:a2d36977aec3 | 161 | for (byte j = 8; j; j--) { |
TheChrisyd | 0:a2d36977aec3 | 162 | spi.write((b & 0x80) ? one : zero); |
TheChrisyd | 0:a2d36977aec3 | 163 | b <<= 1; |
TheChrisyd | 0:a2d36977aec3 | 164 | } |
TheChrisyd | 0:a2d36977aec3 | 165 | } |
TheChrisyd | 0:a2d36977aec3 | 166 | |
TheChrisyd | 0:a2d36977aec3 | 167 | // load an 8x8 into a hw 256-color sprite, padding with transparent (color 255) |
TheChrisyd | 0:a2d36977aec3 | 168 | void loadspr8(byte slot, PROGMEM prog_uchar *src, byte zero, byte one) |
TheChrisyd | 0:a2d36977aec3 | 169 | { |
TheChrisyd | 0:a2d36977aec3 | 170 | GD.__wstart(RAM_SPRIMG + (slot << 8)); |
TheChrisyd | 0:a2d36977aec3 | 171 | for (byte i = 8; i; i--) { |
TheChrisyd | 0:a2d36977aec3 | 172 | send8(pgm_read_byte_near(src++), zero, one); |
TheChrisyd | 0:a2d36977aec3 | 173 | send8(0, 255, 255); |
TheChrisyd | 0:a2d36977aec3 | 174 | } |
TheChrisyd | 0:a2d36977aec3 | 175 | for (byte i = 128; i; i--) |
TheChrisyd | 0:a2d36977aec3 | 176 | spi.write(255); |
TheChrisyd | 0:a2d36977aec3 | 177 | GD.__end(); |
TheChrisyd | 0:a2d36977aec3 | 178 | } |
TheChrisyd | 0:a2d36977aec3 | 179 | |
TheChrisyd | 0:a2d36977aec3 | 180 | // load an 16x16 into a hw 256-color sprite |
TheChrisyd | 0:a2d36977aec3 | 181 | void loadspr16(byte slot, PROGMEM prog_uchar *src, byte zero, byte one) |
TheChrisyd | 0:a2d36977aec3 | 182 | { |
TheChrisyd | 0:a2d36977aec3 | 183 | GD.__wstart(RAM_SPRIMG + (slot << 8)); |
TheChrisyd | 0:a2d36977aec3 | 184 | for (byte i = 32; i; i--) |
TheChrisyd | 0:a2d36977aec3 | 185 | send8(pgm_read_byte_near(src++), zero, one); |
TheChrisyd | 0:a2d36977aec3 | 186 | GD.__end(); |
TheChrisyd | 0:a2d36977aec3 | 187 | } |
TheChrisyd | 0:a2d36977aec3 | 188 | |
TheChrisyd | 0:a2d36977aec3 | 189 | |
TheChrisyd | 0:a2d36977aec3 | 190 | static void sprite(byte spr, byte x, byte y, byte img, byte rot = 0) |
TheChrisyd | 0:a2d36977aec3 | 191 | { |
TheChrisyd | 0:a2d36977aec3 | 192 | GD.sprite(spr, x + 9*8, y + 6*8, img, 0, rot); |
TheChrisyd | 0:a2d36977aec3 | 193 | } |
TheChrisyd | 0:a2d36977aec3 | 194 | |
TheChrisyd | 0:a2d36977aec3 | 195 | static void hide(byte spr) |
TheChrisyd | 0:a2d36977aec3 | 196 | { |
TheChrisyd | 0:a2d36977aec3 | 197 | GD.sprite(spr, 400, 400, 0, 0, 0); |
TheChrisyd | 0:a2d36977aec3 | 198 | } |
TheChrisyd | 0:a2d36977aec3 | 199 | |
TheChrisyd | 0:a2d36977aec3 | 200 | struct guardian { |
TheChrisyd | 0:a2d36977aec3 | 201 | byte a; |
TheChrisyd | 0:a2d36977aec3 | 202 | byte x, y; |
TheChrisyd | 0:a2d36977aec3 | 203 | signed char d; |
TheChrisyd | 0:a2d36977aec3 | 204 | byte x0, x1; |
TheChrisyd | 0:a2d36977aec3 | 205 | byte f; |
TheChrisyd | 0:a2d36977aec3 | 206 | } guards[8]; |
TheChrisyd | 0:a2d36977aec3 | 207 | |
TheChrisyd | 0:a2d36977aec3 | 208 | #define MAXRAY 40 |
TheChrisyd | 0:a2d36977aec3 | 209 | |
TheChrisyd | 0:a2d36977aec3 | 210 | struct state_t { |
TheChrisyd | 0:a2d36977aec3 | 211 | byte level; |
TheChrisyd | 0:a2d36977aec3 | 212 | byte lives; |
TheChrisyd | 0:a2d36977aec3 | 213 | uint32_t score; |
TheChrisyd | 0:a2d36977aec3 | 214 | uint32_t hiscore; |
TheChrisyd | 0:a2d36977aec3 | 215 | |
TheChrisyd | 0:a2d36977aec3 | 216 | byte bidir; |
TheChrisyd | 0:a2d36977aec3 | 217 | byte air; |
TheChrisyd | 0:a2d36977aec3 | 218 | byte conveyordir; |
TheChrisyd | 0:a2d36977aec3 | 219 | byte portalattr; |
TheChrisyd | 0:a2d36977aec3 | 220 | byte nitems; |
TheChrisyd | 0:a2d36977aec3 | 221 | byte wx, wy; // Willy x,y |
TheChrisyd | 0:a2d36977aec3 | 222 | byte wd, wf; // Willy dir and frame |
TheChrisyd | 0:a2d36977aec3 | 223 | byte lastdx; // Willy last x movement |
TheChrisyd | 0:a2d36977aec3 | 224 | byte convey; // Willy caught on conveyor |
TheChrisyd | 0:a2d36977aec3 | 225 | byte jumping; |
TheChrisyd | 0:a2d36977aec3 | 226 | signed char wyv; |
TheChrisyd | 0:a2d36977aec3 | 227 | byte conveyor[2]; |
TheChrisyd | 0:a2d36977aec3 | 228 | PROGMEM prog_uchar *guardian; |
TheChrisyd | 0:a2d36977aec3 | 229 | uint16_t prevray[MAXRAY]; |
TheChrisyd | 0:a2d36977aec3 | 230 | byte switch1, switch2; |
TheChrisyd | 0:a2d36977aec3 | 231 | } state; |
TheChrisyd | 0:a2d36977aec3 | 232 | |
TheChrisyd | 0:a2d36977aec3 | 233 | // All this is taken from |
TheChrisyd | 0:a2d36977aec3 | 234 | // http://jswremakes.emuunlim.com/Mmt/Manic%20Miner%20Room%20Format.htm |
TheChrisyd | 0:a2d36977aec3 | 235 | |
TheChrisyd | 0:a2d36977aec3 | 236 | static void plot_air() |
TheChrisyd | 0:a2d36977aec3 | 237 | { |
TheChrisyd | 0:a2d36977aec3 | 238 | // Starting at CHR_AIR+4, draw a line of n/8 solid, n%8, then 27-(n/8) |
TheChrisyd | 0:a2d36977aec3 | 239 | uint16_t addr = RAM_CHR + (16 * (CHR_AIR + 4)); // line 2 of (CHR_AIR+4) |
TheChrisyd | 0:a2d36977aec3 | 240 | for (byte i = 0; i < 28; i++) { |
TheChrisyd | 0:a2d36977aec3 | 241 | byte v; |
TheChrisyd | 0:a2d36977aec3 | 242 | if (i < (state.air >> 3)) |
TheChrisyd | 0:a2d36977aec3 | 243 | v = 8; |
TheChrisyd | 0:a2d36977aec3 | 244 | else if (i == (state.air >> 3)) |
TheChrisyd | 0:a2d36977aec3 | 245 | v = state.air & 7; |
TheChrisyd | 0:a2d36977aec3 | 246 | else |
TheChrisyd | 0:a2d36977aec3 | 247 | v = 0; |
TheChrisyd | 0:a2d36977aec3 | 248 | unpack8xn(addr + i * 16, airs + (v << 3), 8); |
TheChrisyd | 0:a2d36977aec3 | 249 | } |
TheChrisyd | 0:a2d36977aec3 | 250 | } |
TheChrisyd | 0:a2d36977aec3 | 251 | |
TheChrisyd | 0:a2d36977aec3 | 252 | static void plot_score() |
TheChrisyd | 0:a2d36977aec3 | 253 | { |
TheChrisyd | 0:a2d36977aec3 | 254 | uint32_t n = state.score; |
TheChrisyd | 0:a2d36977aec3 | 255 | |
TheChrisyd | 0:a2d36977aec3 | 256 | GD.__wstart(atxy(26, 19)); |
TheChrisyd | 0:a2d36977aec3 | 257 | spi.write('0' + (n / 100000) % 10); |
TheChrisyd | 0:a2d36977aec3 | 258 | spi.write('0' + (n / 10000) % 10); |
TheChrisyd | 0:a2d36977aec3 | 259 | spi.write('0' + (n / 1000) % 10); |
TheChrisyd | 0:a2d36977aec3 | 260 | spi.write('0' + (n / 100) % 10); |
TheChrisyd | 0:a2d36977aec3 | 261 | spi.write('0' + (n / 10) % 10); |
TheChrisyd | 0:a2d36977aec3 | 262 | spi.write('0' + n % 10); |
TheChrisyd | 0:a2d36977aec3 | 263 | GD.__end(); |
TheChrisyd | 0:a2d36977aec3 | 264 | } |
TheChrisyd | 0:a2d36977aec3 | 265 | |
TheChrisyd | 0:a2d36977aec3 | 266 | static void bump_score(byte n) |
TheChrisyd | 0:a2d36977aec3 | 267 | { |
TheChrisyd | 0:a2d36977aec3 | 268 | if ((state.score < 10000) && (10000 <= (state.score + n ))) |
TheChrisyd | 0:a2d36977aec3 | 269 | state.lives++; |
TheChrisyd | 0:a2d36977aec3 | 270 | state.score += n; |
TheChrisyd | 0:a2d36977aec3 | 271 | plot_score(); |
TheChrisyd | 0:a2d36977aec3 | 272 | } |
TheChrisyd | 0:a2d36977aec3 | 273 | |
TheChrisyd | 0:a2d36977aec3 | 274 | static void pause(byte n) |
TheChrisyd | 0:a2d36977aec3 | 275 | { |
TheChrisyd | 0:a2d36977aec3 | 276 | while (n--) |
TheChrisyd | 0:a2d36977aec3 | 277 | GD.waitvblank(); |
TheChrisyd | 0:a2d36977aec3 | 278 | } |
TheChrisyd | 0:a2d36977aec3 | 279 | |
TheChrisyd | 0:a2d36977aec3 | 280 | static void clear_screen(byte yclear = 16) |
TheChrisyd | 0:a2d36977aec3 | 281 | { |
TheChrisyd | 0:a2d36977aec3 | 282 | // blank out top 16 lines |
TheChrisyd | 0:a2d36977aec3 | 283 | GD.fill(RAM_CHR, 0, 16); |
TheChrisyd | 0:a2d36977aec3 | 284 | GD.wr16(RAM_PAL, BLACK); |
TheChrisyd | 0:a2d36977aec3 | 285 | for (byte y = 0; y < yclear; y++) |
TheChrisyd | 0:a2d36977aec3 | 286 | GD.fill(atxy(0, y), 0, 32); |
TheChrisyd | 0:a2d36977aec3 | 287 | for (int i = 0; i < 256; i++) |
TheChrisyd | 0:a2d36977aec3 | 288 | hide(i); |
TheChrisyd | 0:a2d36977aec3 | 289 | for (int i = 0; i < 64; i++) |
TheChrisyd | 0:a2d36977aec3 | 290 | GD.voice(i, 0, 0, 0, 0); |
TheChrisyd | 0:a2d36977aec3 | 291 | pause(6); |
TheChrisyd | 0:a2d36977aec3 | 292 | } |
TheChrisyd | 0:a2d36977aec3 | 293 | |
TheChrisyd | 0:a2d36977aec3 | 294 | static void loadlevel(struct level *l) |
TheChrisyd | 0:a2d36977aec3 | 295 | { |
TheChrisyd | 0:a2d36977aec3 | 296 | clear_screen(); |
TheChrisyd | 0:a2d36977aec3 | 297 | |
TheChrisyd | 0:a2d36977aec3 | 298 | // border |
TheChrisyd | 0:a2d36977aec3 | 299 | GD.wr16(RAM_PAL + 8 * CHR_BORDER, COLOR(pgm_read_byte_near(&l->border))); |
TheChrisyd | 0:a2d36977aec3 | 300 | |
TheChrisyd | 0:a2d36977aec3 | 301 | // background picture: uncompress into scratch then copy to screen |
TheChrisyd | 0:a2d36977aec3 | 302 | prog_uchar *background = (prog_uchar*)pgm_read_word_near(&l->background); |
TheChrisyd | 0:a2d36977aec3 | 303 | uint16_t scratch = 4096 - 512; // offscreen scratch |
TheChrisyd | 0:a2d36977aec3 | 304 | GD.uncompress(scratch, background); |
TheChrisyd | 0:a2d36977aec3 | 305 | for (byte y = 0; y < 16; y++) |
TheChrisyd | 0:a2d36977aec3 | 306 | for (byte x = 0; x < 32; x++) |
TheChrisyd | 0:a2d36977aec3 | 307 | GD.wr(atxy(x, y), GD.rd(scratch + (y << 5) + x)); |
TheChrisyd | 0:a2d36977aec3 | 308 | for (byte y = 16; y < 24; y++) |
TheChrisyd | 0:a2d36977aec3 | 309 | GD.fill(atxy(0, y), ' ', 32); |
TheChrisyd | 0:a2d36977aec3 | 310 | |
TheChrisyd | 0:a2d36977aec3 | 311 | // bg characters |
TheChrisyd | 0:a2d36977aec3 | 312 | unpack8xn(RAM_CHR, l->bgchars, sizeof(l->bgchars)); |
TheChrisyd | 0:a2d36977aec3 | 313 | state.conveyor[0] = pgm_read_byte_near(&l->bgchars[8 * 4 + 0]); |
TheChrisyd | 0:a2d36977aec3 | 314 | state.conveyor[1] = pgm_read_byte_near(&l->bgchars[8 * 4 + 3]); |
TheChrisyd | 0:a2d36977aec3 | 315 | |
TheChrisyd | 0:a2d36977aec3 | 316 | // bg character palettes |
TheChrisyd | 0:a2d36977aec3 | 317 | for (byte c = 0; c < 8; c++) { |
TheChrisyd | 0:a2d36977aec3 | 318 | byte attr = pgm_read_byte_near(l->bgattr + c); |
TheChrisyd | 0:a2d36977aec3 | 319 | GD.wr16(RAM_PAL + 8 * c, COLOR(PAPER(attr))); |
TheChrisyd | 0:a2d36977aec3 | 320 | GD.wr16(RAM_PAL + 8 * c + 6, COLOR(INK(attr))); |
TheChrisyd | 0:a2d36977aec3 | 321 | } |
TheChrisyd | 0:a2d36977aec3 | 322 | |
TheChrisyd | 0:a2d36977aec3 | 323 | // block 2 is the crumbling floor |
TheChrisyd | 0:a2d36977aec3 | 324 | // put the 7 anims of crumbling floor in chars 8-14 |
TheChrisyd | 0:a2d36977aec3 | 325 | GD.fill(RAM_CHR + 16 * 8, 0, 16 * 7); |
TheChrisyd | 0:a2d36977aec3 | 326 | prog_uchar *src = l->bgchars + 2 * 8; |
TheChrisyd | 0:a2d36977aec3 | 327 | for (byte i = 0; i < 7; i++) { |
TheChrisyd | 0:a2d36977aec3 | 328 | byte ch = 8 + i; |
TheChrisyd | 0:a2d36977aec3 | 329 | unpack8xn(RAM_CHR + 16 * ch + 2 * (i + 1), src, 7 - i); |
TheChrisyd | 0:a2d36977aec3 | 330 | byte attr = pgm_read_byte_near(l->bgattr + 2); |
TheChrisyd | 0:a2d36977aec3 | 331 | GD.wr16(RAM_PAL + 8 * ch, COLOR(PAPER(attr))); |
TheChrisyd | 0:a2d36977aec3 | 332 | GD.wr16(RAM_PAL + 8 * ch + 6, COLOR(INK(attr))); |
TheChrisyd | 0:a2d36977aec3 | 333 | } |
TheChrisyd | 0:a2d36977aec3 | 334 | |
TheChrisyd | 0:a2d36977aec3 | 335 | // level name and score line |
TheChrisyd | 0:a2d36977aec3 | 336 | for (byte x = 0; x < 32; x++) { |
TheChrisyd | 0:a2d36977aec3 | 337 | char scoreline[] = "High Score 000000 Score 000000"; |
TheChrisyd | 0:a2d36977aec3 | 338 | GD.wr(atxy(x, 16), 0x80 + pgm_read_byte_near(l->name + x)); |
TheChrisyd | 0:a2d36977aec3 | 339 | GD.wr(atxy(x, 19), scoreline[x]); |
TheChrisyd | 0:a2d36977aec3 | 340 | } |
TheChrisyd | 0:a2d36977aec3 | 341 | plot_score(); |
TheChrisyd | 0:a2d36977aec3 | 342 | |
TheChrisyd | 0:a2d36977aec3 | 343 | // AIR line characters |
TheChrisyd | 0:a2d36977aec3 | 344 | for (byte i = 0; i < 32; i++) |
TheChrisyd | 0:a2d36977aec3 | 345 | GD.wr(atxy(i, 17), CHR_AIR + i); |
TheChrisyd | 0:a2d36977aec3 | 346 | |
TheChrisyd | 0:a2d36977aec3 | 347 | // the items are 5 sprites, using colors 16 up |
TheChrisyd | 0:a2d36977aec3 | 348 | state.nitems = 0; |
TheChrisyd | 0:a2d36977aec3 | 349 | for (byte i = 0; i < 5; i++) { |
TheChrisyd | 0:a2d36977aec3 | 350 | byte x = pgm_read_byte_near(&l->items[i].x); |
TheChrisyd | 0:a2d36977aec3 | 351 | byte y = pgm_read_byte_near(&l->items[i].y); |
TheChrisyd | 0:a2d36977aec3 | 352 | if (x || y) { |
TheChrisyd | 0:a2d36977aec3 | 353 | loadspr8(IMG_ITEM + i, l->item, 255, 16 + i); // items have color 16 up |
TheChrisyd | 0:a2d36977aec3 | 354 | sprite(IMG_ITEM + i, x, y, IMG_ITEM + i); |
TheChrisyd | 0:a2d36977aec3 | 355 | state.nitems++; |
TheChrisyd | 0:a2d36977aec3 | 356 | } else |
TheChrisyd | 0:a2d36977aec3 | 357 | hide(IMG_ITEM + i); |
TheChrisyd | 0:a2d36977aec3 | 358 | } |
TheChrisyd | 0:a2d36977aec3 | 359 | |
TheChrisyd | 0:a2d36977aec3 | 360 | // the portal is a sprite, using colors 32,33 |
TheChrisyd | 0:a2d36977aec3 | 361 | state.portalattr = pgm_read_byte_near(&l->portalattr); |
TheChrisyd | 0:a2d36977aec3 | 362 | loadspr16(IMG_PORTAL, l->portal, 32, 33); |
TheChrisyd | 0:a2d36977aec3 | 363 | byte portalx = pgm_read_byte_near(&l->portalx); |
TheChrisyd | 0:a2d36977aec3 | 364 | byte portaly = pgm_read_byte_near(&l->portaly); |
TheChrisyd | 0:a2d36977aec3 | 365 | sprite(IMG_PORTAL, portalx, portaly, IMG_PORTAL); |
TheChrisyd | 0:a2d36977aec3 | 366 | |
TheChrisyd | 0:a2d36977aec3 | 367 | // use sprites for blocks NASTY1 and NASTY2 |
TheChrisyd | 0:a2d36977aec3 | 368 | byte nc1 = pgm_read_byte_near(l->bgattr + ELEM_NASTY1); |
TheChrisyd | 0:a2d36977aec3 | 369 | byte nc2 = pgm_read_byte_near(l->bgattr + ELEM_NASTY2); |
TheChrisyd | 0:a2d36977aec3 | 370 | loadspr8(IMG_NASTY1, l->bgchars + ELEM_NASTY1 * 8, 255, INK(nc1)); |
TheChrisyd | 0:a2d36977aec3 | 371 | loadspr8(IMG_NASTY2, l->bgchars + ELEM_NASTY2 * 8, 255, INK(nc2)); |
TheChrisyd | 0:a2d36977aec3 | 372 | // now paint sprites over all the NASTY blocks |
TheChrisyd | 0:a2d36977aec3 | 373 | { |
TheChrisyd | 0:a2d36977aec3 | 374 | byte spr = IMG_NASTY1; |
TheChrisyd | 0:a2d36977aec3 | 375 | for (byte y = 0; y < 16; y++) |
TheChrisyd | 0:a2d36977aec3 | 376 | for (byte x = 0; x < 32; x++) { |
TheChrisyd | 0:a2d36977aec3 | 377 | byte blk = GD.rd(atxy(x, y)); |
TheChrisyd | 0:a2d36977aec3 | 378 | if (blk == ELEM_NASTY1) |
TheChrisyd | 0:a2d36977aec3 | 379 | sprite(spr++, x << 3, y << 3, IMG_NASTY1); |
TheChrisyd | 0:a2d36977aec3 | 380 | if (blk == ELEM_NASTY2) |
TheChrisyd | 0:a2d36977aec3 | 381 | sprite(spr++, x << 3, y << 3, IMG_NASTY2); |
TheChrisyd | 0:a2d36977aec3 | 382 | } |
TheChrisyd | 0:a2d36977aec3 | 383 | } |
TheChrisyd | 0:a2d36977aec3 | 384 | |
TheChrisyd | 0:a2d36977aec3 | 385 | // air |
TheChrisyd | 0:a2d36977aec3 | 386 | state.air = pgm_read_byte_near(&l->air); |
TheChrisyd | 0:a2d36977aec3 | 387 | plot_air(); |
TheChrisyd | 0:a2d36977aec3 | 388 | |
TheChrisyd | 0:a2d36977aec3 | 389 | // Conveyor direction |
TheChrisyd | 0:a2d36977aec3 | 390 | state.conveyordir = pgm_read_byte_near(&l->conveyordir); |
TheChrisyd | 0:a2d36977aec3 | 391 | |
TheChrisyd | 0:a2d36977aec3 | 392 | // the hguardians |
TheChrisyd | 0:a2d36977aec3 | 393 | state.bidir = pgm_read_byte_near(&l->bidir); |
TheChrisyd | 0:a2d36977aec3 | 394 | state.guardian = l->guardian; |
TheChrisyd | 0:a2d36977aec3 | 395 | guardian *pg; |
TheChrisyd | 0:a2d36977aec3 | 396 | for (byte i = 0; i < 8; i++) { |
TheChrisyd | 0:a2d36977aec3 | 397 | byte a = pgm_read_byte_near(&l->hguard[i].a); |
TheChrisyd | 0:a2d36977aec3 | 398 | guards[i].a = a; |
TheChrisyd | 0:a2d36977aec3 | 399 | if (a) { |
TheChrisyd | 0:a2d36977aec3 | 400 | byte x = pgm_read_byte_near(&l->hguard[i].x); |
TheChrisyd | 0:a2d36977aec3 | 401 | byte y = pgm_read_byte_near(&l->hguard[i].y); |
TheChrisyd | 0:a2d36977aec3 | 402 | guards[i].x = x; |
TheChrisyd | 0:a2d36977aec3 | 403 | guards[i].y = y; |
TheChrisyd | 0:a2d36977aec3 | 404 | guards[i].d = pgm_read_byte_near(&l->hguard[i].d); |
TheChrisyd | 0:a2d36977aec3 | 405 | guards[i].x0 = pgm_read_byte_near(&l->hguard[i].x0); |
TheChrisyd | 0:a2d36977aec3 | 406 | guards[i].x1 = pgm_read_byte_near(&l->hguard[i].x1); |
TheChrisyd | 0:a2d36977aec3 | 407 | guards[i].f = 0; |
TheChrisyd | 0:a2d36977aec3 | 408 | } else { |
TheChrisyd | 0:a2d36977aec3 | 409 | hide(6 + i); |
TheChrisyd | 0:a2d36977aec3 | 410 | } |
TheChrisyd | 0:a2d36977aec3 | 411 | } |
TheChrisyd | 0:a2d36977aec3 | 412 | |
TheChrisyd | 0:a2d36977aec3 | 413 | pg = &guards[4]; // Use slot 4 for special guardians |
TheChrisyd | 0:a2d36977aec3 | 414 | switch (state.level) { // Special level handling |
TheChrisyd | 0:a2d36977aec3 | 415 | case 4: // Eugene's lair |
TheChrisyd | 0:a2d36977aec3 | 416 | pg->a = 0; // prevent normal guardian logic |
TheChrisyd | 0:a2d36977aec3 | 417 | pg->x = 120; |
TheChrisyd | 0:a2d36977aec3 | 418 | pg->y = 0; |
TheChrisyd | 0:a2d36977aec3 | 419 | pg->d = -1; |
TheChrisyd | 0:a2d36977aec3 | 420 | pg->x0 = 0; |
TheChrisyd | 0:a2d36977aec3 | 421 | pg->x1 = 88; |
TheChrisyd | 0:a2d36977aec3 | 422 | loadspr16(IMG_GUARD + 4, eugene, 255, 15); |
TheChrisyd | 0:a2d36977aec3 | 423 | break; |
TheChrisyd | 0:a2d36977aec3 | 424 | case 7: // Miner Willy meets the Kong Beast |
TheChrisyd | 0:a2d36977aec3 | 425 | case 11: // Return of the Alien Kong Beast |
TheChrisyd | 0:a2d36977aec3 | 426 | pg->a = 0; |
TheChrisyd | 0:a2d36977aec3 | 427 | pg->x = 120; |
TheChrisyd | 0:a2d36977aec3 | 428 | pg->y = 0; |
TheChrisyd | 0:a2d36977aec3 | 429 | state.switch1 = 0; |
TheChrisyd | 0:a2d36977aec3 | 430 | loadspr8(IMG_SWITCH1, lightswitch, 0, 6); |
TheChrisyd | 0:a2d36977aec3 | 431 | sprite(IMG_SWITCH1, 48, 0, IMG_SWITCH1); |
TheChrisyd | 0:a2d36977aec3 | 432 | state.switch2 = 0; |
TheChrisyd | 0:a2d36977aec3 | 433 | loadspr8(IMG_SWITCH2, lightswitch, 0, 6); |
TheChrisyd | 0:a2d36977aec3 | 434 | sprite(IMG_SWITCH2, 144, 0, IMG_SWITCH2); |
TheChrisyd | 0:a2d36977aec3 | 435 | break; |
TheChrisyd | 0:a2d36977aec3 | 436 | } |
TheChrisyd | 0:a2d36977aec3 | 437 | |
TheChrisyd | 0:a2d36977aec3 | 438 | for (byte i = 0; i < MAXRAY; i++) |
TheChrisyd | 0:a2d36977aec3 | 439 | state.prevray[i] = 4095; |
TheChrisyd | 0:a2d36977aec3 | 440 | |
TheChrisyd | 0:a2d36977aec3 | 441 | // Willy |
TheChrisyd | 0:a2d36977aec3 | 442 | state.wx = pgm_read_byte_near(&l->wx); |
TheChrisyd | 0:a2d36977aec3 | 443 | state.wy = pgm_read_byte_near(&l->wy); |
TheChrisyd | 0:a2d36977aec3 | 444 | state.wf = pgm_read_byte_near(&l->wf); |
TheChrisyd | 0:a2d36977aec3 | 445 | state.wd = pgm_read_byte_near(&l->wd); |
TheChrisyd | 0:a2d36977aec3 | 446 | state.jumping = 0; |
TheChrisyd | 0:a2d36977aec3 | 447 | state.convey = 0; |
TheChrisyd | 0:a2d36977aec3 | 448 | state.wyv = 0; |
TheChrisyd | 0:a2d36977aec3 | 449 | } |
TheChrisyd | 0:a2d36977aec3 | 450 | |
TheChrisyd | 0:a2d36977aec3 | 451 | static byte rol8(byte b, byte d) // 8-bit byte rotate left |
TheChrisyd | 0:a2d36977aec3 | 452 | { |
TheChrisyd | 0:a2d36977aec3 | 453 | d &= 7; |
TheChrisyd | 0:a2d36977aec3 | 454 | return ((b << d) | (b >> (8 - d))) & 0xff; |
TheChrisyd | 0:a2d36977aec3 | 455 | } |
TheChrisyd | 0:a2d36977aec3 | 456 | |
TheChrisyd | 0:a2d36977aec3 | 457 | |
TheChrisyd | 0:a2d36977aec3 | 458 | void setup() |
TheChrisyd | 0:a2d36977aec3 | 459 | { |
TheChrisyd | 0:a2d36977aec3 | 460 | GD.begin(); |
TheChrisyd | 0:a2d36977aec3 | 461 | setup_control(); |
TheChrisyd | 0:a2d36977aec3 | 462 | } |
TheChrisyd | 0:a2d36977aec3 | 463 | |
TheChrisyd | 0:a2d36977aec3 | 464 | void game_graphics() |
TheChrisyd | 0:a2d36977aec3 | 465 | { |
TheChrisyd | 0:a2d36977aec3 | 466 | // Load the Spectrum font: regular in 32-127 reverse in 160-255 |
TheChrisyd | 0:a2d36977aec3 | 467 | unpack8xn(RAM_CHR + 16 * ' ', specfont, sizeof(specfont)); |
TheChrisyd | 0:a2d36977aec3 | 468 | unpack8xn(RAM_CHR + 16 * (128 + ' '), specfont, sizeof(specfont)); |
TheChrisyd | 0:a2d36977aec3 | 469 | for (byte i = 32; i < 128; i++) { |
TheChrisyd | 0:a2d36977aec3 | 470 | GD.setpal(4 * i, BLACK); |
TheChrisyd | 0:a2d36977aec3 | 471 | GD.setpal(4 * i + 3, YELLOW); |
TheChrisyd | 0:a2d36977aec3 | 472 | GD.setpal(4 * (128 + i), COLOR(6)); // dark yellow |
TheChrisyd | 0:a2d36977aec3 | 473 | GD.setpal(4 * (128 + i) + 3, BLACK); |
TheChrisyd | 0:a2d36977aec3 | 474 | } |
TheChrisyd | 0:a2d36977aec3 | 475 | |
TheChrisyd | 0:a2d36977aec3 | 476 | // AIR display in 32 chars starting at CHR_AIR |
TheChrisyd | 0:a2d36977aec3 | 477 | unpack8xn(RAM_CHR + 16 * CHR_AIR, specfont + 8 * ('A' - ' '), 8); |
TheChrisyd | 0:a2d36977aec3 | 478 | unpack8xn(RAM_CHR + 16 * (CHR_AIR+1), specfont + 8 * ('I' - ' '), 8); |
TheChrisyd | 0:a2d36977aec3 | 479 | unpack8xn(RAM_CHR + 16 * (CHR_AIR+2), specfont + 8 * ('R' - ' '), 8); |
TheChrisyd | 0:a2d36977aec3 | 480 | for (byte i = 0; i < 32; i++) { |
TheChrisyd | 0:a2d36977aec3 | 481 | uint16_t color = (i < 10) ? RED : GREEN; |
TheChrisyd | 0:a2d36977aec3 | 482 | GD.setpal(4 * (CHR_AIR + i), color); |
TheChrisyd | 0:a2d36977aec3 | 483 | GD.setpal(4 * (CHR_AIR + i) + 3, WHITE); |
TheChrisyd | 0:a2d36977aec3 | 484 | } |
TheChrisyd | 0:a2d36977aec3 | 485 | |
TheChrisyd | 0:a2d36977aec3 | 486 | // Load the Spectrum's palette into PALETTE256A |
TheChrisyd | 0:a2d36977aec3 | 487 | GD.copy(RAM_SPRPAL, specpal, sizeof(specpal)); |
TheChrisyd | 0:a2d36977aec3 | 488 | GD.wr16(RAM_SPRPAL + 2 * 255, TRANSPARENT); // color 255 is transparent |
TheChrisyd | 0:a2d36977aec3 | 489 | |
TheChrisyd | 0:a2d36977aec3 | 490 | // fill screen with char CHR_BORDER |
TheChrisyd | 0:a2d36977aec3 | 491 | GD.fill(RAM_CHR + 16 * CHR_BORDER, 0, 16); |
TheChrisyd | 0:a2d36977aec3 | 492 | GD.fill(RAM_PIC, CHR_BORDER, 64 * 64); |
TheChrisyd | 0:a2d36977aec3 | 493 | |
TheChrisyd | 0:a2d36977aec3 | 494 | // Load Willy in bright cyan and white |
TheChrisyd | 0:a2d36977aec3 | 495 | for (byte i = 0; i < 4; i++) { |
TheChrisyd | 0:a2d36977aec3 | 496 | loadspr16(IMG_WILLYC + i, willy + (i << 5), 255, 8 + 5); |
TheChrisyd | 0:a2d36977aec3 | 497 | } |
TheChrisyd | 0:a2d36977aec3 | 498 | } |
TheChrisyd | 0:a2d36977aec3 | 499 | |
TheChrisyd | 0:a2d36977aec3 | 500 | // midi frequency table |
TheChrisyd | 0:a2d36977aec3 | 501 | static PROGMEM prog_uint16_t midifreq[128] = { |
TheChrisyd | 0:a2d36977aec3 | 502 | 32,34,36,38,41,43,46,48,51,55,58,61,65,69,73,77,82,87,92,97,103,110,116,123,130,138,146,155,164,174,184,195,207,220,233,246,261,277,293,311,329,349,369,391,415,440,466,493,523,554,587,622,659,698,739,783,830,880,932,987,1046,1108,1174,1244,1318,1396,1479,1567,1661,1760,1864,1975,2093,2217,2349,2489,2637,2793,2959,3135,3322,3520,3729,3951,4186,4434,4698,4978,5274,5587,5919,6271,6644,7040,7458,7902,8372,8869,9397,9956,10548,11175,11839,12543,13289,14080,14917,15804,16744,17739,18794,19912,21096,22350,23679,25087,26579,28160,29834,31608,33488,35479,37589,39824,42192,44701,47359,50175 |
TheChrisyd | 0:a2d36977aec3 | 503 | }; |
TheChrisyd | 0:a2d36977aec3 | 504 | #define MIDI(n) pgm_read_word(midifreq + (n)) |
TheChrisyd | 0:a2d36977aec3 | 505 | |
TheChrisyd | 0:a2d36977aec3 | 506 | static void squarewave(byte voice, uint16_t f0, byte amp) |
TheChrisyd | 0:a2d36977aec3 | 507 | { |
TheChrisyd | 0:a2d36977aec3 | 508 | GD.voice(8*voice + 0, 0, f0, amp, amp); |
TheChrisyd | 0:a2d36977aec3 | 509 | GD.voice(8*voice + 1, 0, 3 * f0, amp/3, amp/3); |
TheChrisyd | 0:a2d36977aec3 | 510 | GD.voice(8*voice + 2, 0, 5 * f0, amp/5, amp/5); |
TheChrisyd | 0:a2d36977aec3 | 511 | GD.voice(8*voice + 3, 0, 7 * f0, amp/7, amp/7); |
TheChrisyd | 0:a2d36977aec3 | 512 | GD.voice(8*voice + 4, 0, 9 * f0, amp/9, amp/9); |
TheChrisyd | 0:a2d36977aec3 | 513 | GD.voice(8*voice + 5, 0, 11 * f0, amp/11, amp/11); |
TheChrisyd | 0:a2d36977aec3 | 514 | } |
TheChrisyd | 0:a2d36977aec3 | 515 | |
TheChrisyd | 0:a2d36977aec3 | 516 | static void drive_level(byte t); |
TheChrisyd | 0:a2d36977aec3 | 517 | |
TheChrisyd | 0:a2d36977aec3 | 518 | static int title_screen() // returns 1 if player pressed something |
TheChrisyd | 0:a2d36977aec3 | 519 | { |
TheChrisyd | 0:a2d36977aec3 | 520 | for (;;) { |
TheChrisyd | 0:a2d36977aec3 | 521 | display: |
TheChrisyd | 0:a2d36977aec3 | 522 | clear_screen(); |
TheChrisyd | 0:a2d36977aec3 | 523 | GD.fill(0x4000, 0, 6144); // clear emulated Spectrum video RAM |
TheChrisyd | 0:a2d36977aec3 | 524 | GD.uncompress(0x7000, spectrum_tables); |
TheChrisyd | 0:a2d36977aec3 | 525 | |
TheChrisyd | 0:a2d36977aec3 | 526 | // fill screen with char 0x80 for border |
TheChrisyd | 0:a2d36977aec3 | 527 | GD.setpal(4 * 0x80, COLOR(2)); |
TheChrisyd | 0:a2d36977aec3 | 528 | GD.fill(RAM_CHR, 0, 4096); |
TheChrisyd | 0:a2d36977aec3 | 529 | GD.fill(RAM_PIC, 0x80, 4096); |
TheChrisyd | 0:a2d36977aec3 | 530 | |
TheChrisyd | 0:a2d36977aec3 | 531 | // paint the 256x192 window as alternating lines of |
TheChrisyd | 0:a2d36977aec3 | 532 | // chars 0-31 and 32-63 |
TheChrisyd | 0:a2d36977aec3 | 533 | for (byte y = 0; y < 24; y += 2) { |
TheChrisyd | 0:a2d36977aec3 | 534 | for (byte x = 0; x < 32; x++) { |
TheChrisyd | 0:a2d36977aec3 | 535 | GD.wr(atxy(x, y), x); |
TheChrisyd | 0:a2d36977aec3 | 536 | GD.wr(atxy(x, y + 1), 32 + x); |
TheChrisyd | 0:a2d36977aec3 | 537 | } |
TheChrisyd | 0:a2d36977aec3 | 538 | } |
TheChrisyd | 0:a2d36977aec3 | 539 | GD.microcode(spectrum_code, sizeof(spectrum_code)); |
TheChrisyd | 0:a2d36977aec3 | 540 | GD.uncompress(0x4000, screen_mm1); |
TheChrisyd | 0:a2d36977aec3 | 541 | |
TheChrisyd | 0:a2d36977aec3 | 542 | for (prog_uint32_t *tune = blue_danube; |
TheChrisyd | 0:a2d36977aec3 | 543 | (size_t)tune < ((size_t)blue_danube + sizeof(blue_danube)); |
TheChrisyd | 0:a2d36977aec3 | 544 | tune++) { |
TheChrisyd | 0:a2d36977aec3 | 545 | uint32_t cmd = pgm_read_dword_near(tune); |
TheChrisyd | 0:a2d36977aec3 | 546 | for (int t = 60 * (cmd >> 28); t; t--) { |
TheChrisyd | 0:a2d36977aec3 | 547 | delay(1); |
TheChrisyd | 0:a2d36977aec3 | 548 | if (control()) |
TheChrisyd | 0:a2d36977aec3 | 549 | goto escape; |
TheChrisyd | 0:a2d36977aec3 | 550 | } |
TheChrisyd | 0:a2d36977aec3 | 551 | byte n0 = 127 & (cmd >> 21); |
TheChrisyd | 0:a2d36977aec3 | 552 | byte a0 = 127 & (cmd >> 14); |
TheChrisyd | 0:a2d36977aec3 | 553 | byte n1 = 127 & (cmd >> 7); |
TheChrisyd | 0:a2d36977aec3 | 554 | byte a1 = 127 & cmd; |
TheChrisyd | 0:a2d36977aec3 | 555 | squarewave(0, MIDI(n0), a0 >> 1); |
TheChrisyd | 0:a2d36977aec3 | 556 | squarewave(1, MIDI(n1), a1 >> 1); |
TheChrisyd | 0:a2d36977aec3 | 557 | GD.setpal(4 * 0x80, COLOR((n1 ^ n0) & 7)); |
TheChrisyd | 0:a2d36977aec3 | 558 | } |
TheChrisyd | 0:a2d36977aec3 | 559 | GD.setpal(4 * 0x80, COLOR(7)); |
TheChrisyd | 0:a2d36977aec3 | 560 | |
TheChrisyd | 0:a2d36977aec3 | 561 | for (byte i = 0; i < ((sizeof(message) - 1) - 32); i++) { |
TheChrisyd | 0:a2d36977aec3 | 562 | prog_uchar *src = message + i; |
TheChrisyd | 0:a2d36977aec3 | 563 | for (byte j = 0; j < 32; j++) { |
TheChrisyd | 0:a2d36977aec3 | 564 | byte ch = pgm_read_byte_near(src + j); |
TheChrisyd | 0:a2d36977aec3 | 565 | prog_uchar *glyph = specfont + ((ch - ' ') << 3); |
TheChrisyd | 0:a2d36977aec3 | 566 | for (byte k = 0; k < 8; k++) |
TheChrisyd | 0:a2d36977aec3 | 567 | GD.wr(0x5060 + j + (k << 8), pgm_read_byte_near(glyph++)); |
TheChrisyd | 0:a2d36977aec3 | 568 | } |
TheChrisyd | 0:a2d36977aec3 | 569 | for (byte t = 80; t; t--) { |
TheChrisyd | 0:a2d36977aec3 | 570 | delay(1); |
TheChrisyd | 0:a2d36977aec3 | 571 | if (control()) |
TheChrisyd | 0:a2d36977aec3 | 572 | goto escape; |
TheChrisyd | 0:a2d36977aec3 | 573 | } |
TheChrisyd | 0:a2d36977aec3 | 574 | } |
TheChrisyd | 0:a2d36977aec3 | 575 | |
TheChrisyd | 0:a2d36977aec3 | 576 | GD.wr(J1_RESET, 1); // stop coprocessor |
TheChrisyd | 0:a2d36977aec3 | 577 | clear_screen(24); |
TheChrisyd | 0:a2d36977aec3 | 578 | game_graphics(); |
TheChrisyd | 0:a2d36977aec3 | 579 | |
TheChrisyd | 0:a2d36977aec3 | 580 | for (state.level = 0; state.level < 19; state.level++) { |
TheChrisyd | 0:a2d36977aec3 | 581 | loadlevel(&levels[state.level]); |
TheChrisyd | 0:a2d36977aec3 | 582 | for (byte t = 0; t < 128; t++) { |
TheChrisyd | 0:a2d36977aec3 | 583 | drive_level(t); |
TheChrisyd | 0:a2d36977aec3 | 584 | GD.waitvblank(); |
TheChrisyd | 0:a2d36977aec3 | 585 | if (control()) |
TheChrisyd | 0:a2d36977aec3 | 586 | goto display; |
TheChrisyd | 0:a2d36977aec3 | 587 | } |
TheChrisyd | 0:a2d36977aec3 | 588 | } |
TheChrisyd | 0:a2d36977aec3 | 589 | } |
TheChrisyd | 0:a2d36977aec3 | 590 | |
TheChrisyd | 0:a2d36977aec3 | 591 | escape: |
TheChrisyd | 0:a2d36977aec3 | 592 | GD.wr(J1_RESET, 1); // stop coprocessor |
TheChrisyd | 0:a2d36977aec3 | 593 | clear_screen(24); |
TheChrisyd | 0:a2d36977aec3 | 594 | game_graphics(); |
TheChrisyd | 0:a2d36977aec3 | 595 | } |
TheChrisyd | 0:a2d36977aec3 | 596 | |
TheChrisyd | 0:a2d36977aec3 | 597 | static void game_over() |
TheChrisyd | 0:a2d36977aec3 | 598 | { |
TheChrisyd | 0:a2d36977aec3 | 599 | clear_screen(); |
TheChrisyd | 0:a2d36977aec3 | 600 | // Willy |
TheChrisyd | 0:a2d36977aec3 | 601 | loadspr16(0, willy, 255, 8 + 7); |
TheChrisyd | 0:a2d36977aec3 | 602 | sprite(0, 124, 128 - 32, 0); |
TheChrisyd | 0:a2d36977aec3 | 603 | |
TheChrisyd | 0:a2d36977aec3 | 604 | // plinth |
TheChrisyd | 0:a2d36977aec3 | 605 | loadspr16(2, plinth, 255, 8 + 7); |
TheChrisyd | 0:a2d36977aec3 | 606 | sprite(2, 120, 128 - 16, 2); |
TheChrisyd | 0:a2d36977aec3 | 607 | |
TheChrisyd | 0:a2d36977aec3 | 608 | // Boot |
TheChrisyd | 0:a2d36977aec3 | 609 | loadspr16(1, boot, 255, 8 + 7); |
TheChrisyd | 0:a2d36977aec3 | 610 | loadspr16(3, boot, 255, 8 + 7); // sprite 3 is top 2 lines of boot |
TheChrisyd | 0:a2d36977aec3 | 611 | // erase the bottom 14 lines of boot |
TheChrisyd | 0:a2d36977aec3 | 612 | GD.fill(RAM_SPRIMG + 3 * 256 + 2 * 16, 255, 14 * 16); |
TheChrisyd | 0:a2d36977aec3 | 613 | |
TheChrisyd | 0:a2d36977aec3 | 614 | for (byte i = 0; i <= 48; i++) { |
TheChrisyd | 0:a2d36977aec3 | 615 | sprite(1, 120, 2 * i, 1); // boot in sprite 1 |
TheChrisyd | 0:a2d36977aec3 | 616 | sprite(3 + i, 120, 2 * i, 3); // leg in sprites 3,4, etc |
TheChrisyd | 0:a2d36977aec3 | 617 | if (41 <= i) // erase Willy as boot covers him |
TheChrisyd | 0:a2d36977aec3 | 618 | GD.fill(RAM_SPRIMG + 32 * (i - 41), 255, 32); |
TheChrisyd | 0:a2d36977aec3 | 619 | if ((i & 1) == 0) |
TheChrisyd | 0:a2d36977aec3 | 620 | GD.wr16(RAM_PAL, COLOR(random(7))); |
TheChrisyd | 0:a2d36977aec3 | 621 | squarewave(0, 400 + 4 * i, 150); |
TheChrisyd | 0:a2d36977aec3 | 622 | pause(2); |
TheChrisyd | 0:a2d36977aec3 | 623 | } |
TheChrisyd | 0:a2d36977aec3 | 624 | GD.wr16(RAM_PAL, BLACK); |
TheChrisyd | 0:a2d36977aec3 | 625 | squarewave(0, 0, 0); |
TheChrisyd | 0:a2d36977aec3 | 626 | |
TheChrisyd | 0:a2d36977aec3 | 627 | // "Game Over" text in sprite images 16-23, color 16-23 |
TheChrisyd | 0:a2d36977aec3 | 628 | char msg[] = "GameOver"; |
TheChrisyd | 0:a2d36977aec3 | 629 | for (byte i = 0; i < 8; i++) |
TheChrisyd | 0:a2d36977aec3 | 630 | loadspr8(16 + i, specfont + (msg[i] - 32) * 8, 255, 16 + i); |
TheChrisyd | 0:a2d36977aec3 | 631 | for (byte i = 0; i < 4; i++) { |
TheChrisyd | 0:a2d36977aec3 | 632 | sprite(100 + i, 80 + i * 8, 48, 16 + i); |
TheChrisyd | 0:a2d36977aec3 | 633 | sprite(104 + i, 140 + i * 8, 48, 20 + i); |
TheChrisyd | 0:a2d36977aec3 | 634 | } |
TheChrisyd | 0:a2d36977aec3 | 635 | for (byte t = 120; t; t--) { |
TheChrisyd | 0:a2d36977aec3 | 636 | for (byte i = 0; i < 8; i++) |
TheChrisyd | 0:a2d36977aec3 | 637 | GD.wr16(RAM_SPRPAL + (16 + i) * 2, COLOR(9 + random(7))); |
TheChrisyd | 0:a2d36977aec3 | 638 | pause(2); |
TheChrisyd | 0:a2d36977aec3 | 639 | } |
TheChrisyd | 0:a2d36977aec3 | 640 | clear_screen(); |
TheChrisyd | 0:a2d36977aec3 | 641 | } |
TheChrisyd | 0:a2d36977aec3 | 642 | |
TheChrisyd | 0:a2d36977aec3 | 643 | // crumble block at s, which is the sequence |
TheChrisyd | 0:a2d36977aec3 | 644 | // 2->8->9->10->11->12->13->14->0 |
TheChrisyd | 0:a2d36977aec3 | 645 | |
TheChrisyd | 0:a2d36977aec3 | 646 | static void crumble(uint16_t s) |
TheChrisyd | 0:a2d36977aec3 | 647 | { |
TheChrisyd | 0:a2d36977aec3 | 648 | byte r = GD.rd(s); |
TheChrisyd | 0:a2d36977aec3 | 649 | signed char nexts[] = { |
TheChrisyd | 0:a2d36977aec3 | 650 | -1, -1, 8, -1, -1, -1, -1, -1, |
TheChrisyd | 0:a2d36977aec3 | 651 | 9, 10, 11, 12, 13, 14, 0 }; |
TheChrisyd | 0:a2d36977aec3 | 652 | if (r < sizeof(nexts) && nexts[r] != -1) |
TheChrisyd | 0:a2d36977aec3 | 653 | GD.wr(s, nexts[r]); |
TheChrisyd | 0:a2d36977aec3 | 654 | } |
TheChrisyd | 0:a2d36977aec3 | 655 | |
TheChrisyd | 0:a2d36977aec3 | 656 | // is it legal for willy to be at (x,y) |
TheChrisyd | 0:a2d36977aec3 | 657 | static int canbe(byte x, byte y) |
TheChrisyd | 0:a2d36977aec3 | 658 | { |
TheChrisyd | 0:a2d36977aec3 | 659 | uint16_t addr = atxy(x / 8, y / 8); |
TheChrisyd | 0:a2d36977aec3 | 660 | return |
TheChrisyd | 0:a2d36977aec3 | 661 | (GD.rd(addr) != ELEM_WALL) && |
TheChrisyd | 0:a2d36977aec3 | 662 | (GD.rd(addr+1) != ELEM_WALL) && |
TheChrisyd | 0:a2d36977aec3 | 663 | (GD.rd(addr+64) != ELEM_WALL) && |
TheChrisyd | 0:a2d36977aec3 | 664 | (GD.rd(addr+65) != ELEM_WALL); |
TheChrisyd | 0:a2d36977aec3 | 665 | } |
TheChrisyd | 0:a2d36977aec3 | 666 | |
TheChrisyd | 0:a2d36977aec3 | 667 | // is Willy standing in a solar ray? |
TheChrisyd | 0:a2d36977aec3 | 668 | static int inray(byte x, byte y) |
TheChrisyd | 0:a2d36977aec3 | 669 | { |
TheChrisyd | 0:a2d36977aec3 | 670 | uint16_t addr = atxy(x / 8, y / 8); |
TheChrisyd | 0:a2d36977aec3 | 671 | return |
TheChrisyd | 0:a2d36977aec3 | 672 | (GD.rd(addr) > 0x80 ) || |
TheChrisyd | 0:a2d36977aec3 | 673 | (GD.rd(addr+1) > 0x80) || |
TheChrisyd | 0:a2d36977aec3 | 674 | (GD.rd(addr+64) > 0x80) || |
TheChrisyd | 0:a2d36977aec3 | 675 | (GD.rd(addr+65) > 0x80); |
TheChrisyd | 0:a2d36977aec3 | 676 | } |
TheChrisyd | 0:a2d36977aec3 | 677 | |
TheChrisyd | 0:a2d36977aec3 | 678 | static void drive_level(byte t) |
TheChrisyd | 0:a2d36977aec3 | 679 | { |
TheChrisyd | 0:a2d36977aec3 | 680 | uint16_t freq = 133955L / pgm_read_byte_near(music1 + ((t >> 1) & 63)); |
TheChrisyd | 0:a2d36977aec3 | 681 | GD.waitvblank(); |
TheChrisyd | 0:a2d36977aec3 | 682 | squarewave(0, freq, 128); |
TheChrisyd | 0:a2d36977aec3 | 683 | GD.waitvblank(); |
TheChrisyd | 0:a2d36977aec3 | 684 | squarewave(0, freq, 0); |
TheChrisyd | 0:a2d36977aec3 | 685 | GD.waitvblank(); |
TheChrisyd | 0:a2d36977aec3 | 686 | GD.waitvblank(); |
TheChrisyd | 0:a2d36977aec3 | 687 | |
TheChrisyd | 0:a2d36977aec3 | 688 | guardian *pg; |
TheChrisyd | 0:a2d36977aec3 | 689 | byte lt; // local time, for slow hguardians |
TheChrisyd | 0:a2d36977aec3 | 690 | for (byte i = 0; i < 8; i++) { |
TheChrisyd | 0:a2d36977aec3 | 691 | pg = &guards[i]; |
TheChrisyd | 0:a2d36977aec3 | 692 | if (pg->a) { |
TheChrisyd | 0:a2d36977aec3 | 693 | byte vertical = (i >= 4); |
TheChrisyd | 0:a2d36977aec3 | 694 | byte frame; |
TheChrisyd | 0:a2d36977aec3 | 695 | switch (state.level) { |
TheChrisyd | 0:a2d36977aec3 | 696 | case 13: // Skylabs |
TheChrisyd | 0:a2d36977aec3 | 697 | if (pg->y != pg->x1) { |
TheChrisyd | 0:a2d36977aec3 | 698 | pg->f = 0; |
TheChrisyd | 0:a2d36977aec3 | 699 | pg->y += pg->d; |
TheChrisyd | 0:a2d36977aec3 | 700 | } else { |
TheChrisyd | 0:a2d36977aec3 | 701 | pg->f++; |
TheChrisyd | 0:a2d36977aec3 | 702 | } |
TheChrisyd | 0:a2d36977aec3 | 703 | if (pg->f == 8) { |
TheChrisyd | 0:a2d36977aec3 | 704 | pg->f = 0; |
TheChrisyd | 0:a2d36977aec3 | 705 | pg->x += 64; |
TheChrisyd | 0:a2d36977aec3 | 706 | pg->y = pg->x0; |
TheChrisyd | 0:a2d36977aec3 | 707 | } |
TheChrisyd | 0:a2d36977aec3 | 708 | loadspr16(IMG_GUARD + i, state.guardian + (pg->f << 5), 255, INK(pg->a)); |
TheChrisyd | 0:a2d36977aec3 | 709 | sprite(IMG_GUARD + i, pg->x, pg->y, IMG_GUARD + i); |
TheChrisyd | 0:a2d36977aec3 | 710 | break; |
TheChrisyd | 0:a2d36977aec3 | 711 | default: |
TheChrisyd | 0:a2d36977aec3 | 712 | lt = t; |
TheChrisyd | 0:a2d36977aec3 | 713 | if (!vertical && (pg->a & 0x80)) { |
TheChrisyd | 0:a2d36977aec3 | 714 | if (t & 1) |
TheChrisyd | 0:a2d36977aec3 | 715 | lt = t >> 1; |
TheChrisyd | 0:a2d36977aec3 | 716 | else |
TheChrisyd | 0:a2d36977aec3 | 717 | break; |
TheChrisyd | 0:a2d36977aec3 | 718 | } |
TheChrisyd | 0:a2d36977aec3 | 719 | if (state.bidir) |
TheChrisyd | 0:a2d36977aec3 | 720 | frame = (lt & 3) ^ (pg->d ? 7 : 0); |
TheChrisyd | 0:a2d36977aec3 | 721 | else |
TheChrisyd | 0:a2d36977aec3 | 722 | if (vertical) |
TheChrisyd | 0:a2d36977aec3 | 723 | frame = lt & 3; |
TheChrisyd | 0:a2d36977aec3 | 724 | else |
TheChrisyd | 0:a2d36977aec3 | 725 | frame = 4 + (lt & 3) ^ (pg->d ? 3 : 0); |
TheChrisyd | 0:a2d36977aec3 | 726 | loadspr16(IMG_GUARD + i, state.guardian + (frame << 5), 255, INK(pg->a)); |
TheChrisyd | 0:a2d36977aec3 | 727 | sprite(IMG_GUARD + i, pg->x, pg->y, IMG_GUARD + i); |
TheChrisyd | 0:a2d36977aec3 | 728 | if (!vertical) { |
TheChrisyd | 0:a2d36977aec3 | 729 | if ((lt & 3) == 3) { |
TheChrisyd | 0:a2d36977aec3 | 730 | if (pg->x == pg->x0 && pg->d) |
TheChrisyd | 0:a2d36977aec3 | 731 | pg->d = 0; |
TheChrisyd | 0:a2d36977aec3 | 732 | else if (pg->x == pg->x1 && !pg->d) |
TheChrisyd | 0:a2d36977aec3 | 733 | pg->d = 1; |
TheChrisyd | 0:a2d36977aec3 | 734 | else |
TheChrisyd | 0:a2d36977aec3 | 735 | pg->x += pg->d ? -8 : 8; |
TheChrisyd | 0:a2d36977aec3 | 736 | } |
TheChrisyd | 0:a2d36977aec3 | 737 | } else { |
TheChrisyd | 0:a2d36977aec3 | 738 | if (pg->y <= pg->x0 && pg->d < 0) |
TheChrisyd | 0:a2d36977aec3 | 739 | pg->d = -pg->d; |
TheChrisyd | 0:a2d36977aec3 | 740 | else if (pg->y >= pg->x1 && pg->d > 0) |
TheChrisyd | 0:a2d36977aec3 | 741 | pg->d = -pg->d; |
TheChrisyd | 0:a2d36977aec3 | 742 | else |
TheChrisyd | 0:a2d36977aec3 | 743 | pg->y += pg->d; |
TheChrisyd | 0:a2d36977aec3 | 744 | } |
TheChrisyd | 0:a2d36977aec3 | 745 | } |
TheChrisyd | 0:a2d36977aec3 | 746 | } |
TheChrisyd | 0:a2d36977aec3 | 747 | } |
TheChrisyd | 0:a2d36977aec3 | 748 | pg = &guards[4]; |
TheChrisyd | 0:a2d36977aec3 | 749 | switch (state.level) { // Special level handling |
TheChrisyd | 0:a2d36977aec3 | 750 | case 4: // Eugene's lair |
TheChrisyd | 0:a2d36977aec3 | 751 | sprite(IMG_GUARD + 4, pg->x, pg->y, IMG_GUARD + 4); |
TheChrisyd | 0:a2d36977aec3 | 752 | if (pg->y == pg->x0 && pg->d < 0) |
TheChrisyd | 0:a2d36977aec3 | 753 | pg->d = 1; |
TheChrisyd | 0:a2d36977aec3 | 754 | if (pg->y == pg->x1 && pg->d > 0) |
TheChrisyd | 0:a2d36977aec3 | 755 | pg->d = -1; |
TheChrisyd | 0:a2d36977aec3 | 756 | if (state.nitems == 0) { // all collected -> descend and camp |
TheChrisyd | 0:a2d36977aec3 | 757 | if (pg->d == -1) |
TheChrisyd | 0:a2d36977aec3 | 758 | pg->d = 1; |
TheChrisyd | 0:a2d36977aec3 | 759 | if (pg->y == pg->x1) |
TheChrisyd | 0:a2d36977aec3 | 760 | pg->d = 0; |
TheChrisyd | 0:a2d36977aec3 | 761 | } |
TheChrisyd | 0:a2d36977aec3 | 762 | pg->y += pg->d; |
TheChrisyd | 0:a2d36977aec3 | 763 | break; |
TheChrisyd | 0:a2d36977aec3 | 764 | case 7: // Miner Willy meets the Kong Beast |
TheChrisyd | 0:a2d36977aec3 | 765 | case 11: // Return of the Alien Kong Beast |
TheChrisyd | 0:a2d36977aec3 | 766 | byte frame, color; |
TheChrisyd | 0:a2d36977aec3 | 767 | if (!state.switch2) { |
TheChrisyd | 0:a2d36977aec3 | 768 | frame = (t >> 3) & 1; |
TheChrisyd | 0:a2d36977aec3 | 769 | color = 8 + 4; |
TheChrisyd | 0:a2d36977aec3 | 770 | } else { |
TheChrisyd | 0:a2d36977aec3 | 771 | frame = 2 + ((t >> 1) & 1); |
TheChrisyd | 0:a2d36977aec3 | 772 | color = 8 + 6; |
TheChrisyd | 0:a2d36977aec3 | 773 | if (pg->y < 104) { |
TheChrisyd | 0:a2d36977aec3 | 774 | pg->y += 4; |
TheChrisyd | 0:a2d36977aec3 | 775 | bump_score(100); |
TheChrisyd | 0:a2d36977aec3 | 776 | } |
TheChrisyd | 0:a2d36977aec3 | 777 | } |
TheChrisyd | 0:a2d36977aec3 | 778 | if (pg->y != 104) { |
TheChrisyd | 0:a2d36977aec3 | 779 | loadspr16(IMG_GUARD + 4, state.guardian + (frame << 5), 255, color); |
TheChrisyd | 0:a2d36977aec3 | 780 | sprite(IMG_GUARD + 4, pg->x, pg->y, IMG_GUARD + 4); |
TheChrisyd | 0:a2d36977aec3 | 781 | } else { |
TheChrisyd | 0:a2d36977aec3 | 782 | hide(IMG_GUARD + 4); |
TheChrisyd | 0:a2d36977aec3 | 783 | } |
TheChrisyd | 0:a2d36977aec3 | 784 | } |
TheChrisyd | 0:a2d36977aec3 | 785 | |
TheChrisyd | 0:a2d36977aec3 | 786 | // Animate conveyors: |
TheChrisyd | 0:a2d36977aec3 | 787 | signed char convt = state.conveyordir ? t : -t; |
TheChrisyd | 0:a2d36977aec3 | 788 | GD.__wstart(RAM_CHR + 4 * 16 + 2 * 0); // character 4 line 0 |
TheChrisyd | 0:a2d36977aec3 | 789 | unpack8(rol8(state.conveyor[0], convt)); |
TheChrisyd | 0:a2d36977aec3 | 790 | GD.__end(); |
TheChrisyd | 0:a2d36977aec3 | 791 | GD.__wstart(RAM_CHR + 4 * 16 + 2 * 3); // character 4 line 3 |
TheChrisyd | 0:a2d36977aec3 | 792 | unpack8(rol8(state.conveyor[0], -convt)); |
TheChrisyd | 0:a2d36977aec3 | 793 | GD.__end(); |
TheChrisyd | 0:a2d36977aec3 | 794 | |
TheChrisyd | 0:a2d36977aec3 | 795 | // Solar rays |
TheChrisyd | 0:a2d36977aec3 | 796 | if (state.level == 18) { |
TheChrisyd | 0:a2d36977aec3 | 797 | // Draw new ray, turning 0x00 to 0x80 |
TheChrisyd | 0:a2d36977aec3 | 798 | byte sx = 23; |
TheChrisyd | 0:a2d36977aec3 | 799 | byte sy = 0; |
TheChrisyd | 0:a2d36977aec3 | 800 | byte sd = 0; // down |
TheChrisyd | 0:a2d36977aec3 | 801 | byte ri; // ray index |
TheChrisyd | 0:a2d36977aec3 | 802 | for (ri = 0; ri < MAXRAY; ri++) { |
TheChrisyd | 0:a2d36977aec3 | 803 | uint16_t a = atxy(sx, sy); |
TheChrisyd | 0:a2d36977aec3 | 804 | if (state.prevray[ri] != a) { |
TheChrisyd | 0:a2d36977aec3 | 805 | GD.wr(state.prevray[ri], 0); |
TheChrisyd | 0:a2d36977aec3 | 806 | if (GD.rd(a) != 0) |
TheChrisyd | 0:a2d36977aec3 | 807 | break; // absorbed |
TheChrisyd | 0:a2d36977aec3 | 808 | GD.wr(a, 0x80 + ' '); |
TheChrisyd | 0:a2d36977aec3 | 809 | state.prevray[ri] = a; |
TheChrisyd | 0:a2d36977aec3 | 810 | } |
TheChrisyd | 0:a2d36977aec3 | 811 | for (byte i = 0; i < 8; i++) |
TheChrisyd | 0:a2d36977aec3 | 812 | if (guards[i].a && (guards[i].x >> 3) == sx && (guards[i].y >> 3) == sy) |
TheChrisyd | 0:a2d36977aec3 | 813 | sd ^= 1; |
TheChrisyd | 0:a2d36977aec3 | 814 | if (sd == 0) |
TheChrisyd | 0:a2d36977aec3 | 815 | sy++; |
TheChrisyd | 0:a2d36977aec3 | 816 | else |
TheChrisyd | 0:a2d36977aec3 | 817 | sx--; |
TheChrisyd | 0:a2d36977aec3 | 818 | } |
TheChrisyd | 0:a2d36977aec3 | 819 | while (ri < MAXRAY) { |
TheChrisyd | 0:a2d36977aec3 | 820 | GD.wr(state.prevray[ri], 0); |
TheChrisyd | 0:a2d36977aec3 | 821 | state.prevray[ri++] = 4095; |
TheChrisyd | 0:a2d36977aec3 | 822 | } |
TheChrisyd | 0:a2d36977aec3 | 823 | } |
TheChrisyd | 0:a2d36977aec3 | 824 | |
TheChrisyd | 0:a2d36977aec3 | 825 | // animate item colors starting at 16 |
TheChrisyd | 0:a2d36977aec3 | 826 | uint16_t colors[4] = { MAGENTA, YELLOW, CYAN, GREEN }; |
TheChrisyd | 0:a2d36977aec3 | 827 | for (byte i = 0; i < 5; i++) |
TheChrisyd | 0:a2d36977aec3 | 828 | GD.wr16(RAM_SPRPAL + 2 * (i + 16), colors[(i + t) & 3]); |
TheChrisyd | 0:a2d36977aec3 | 829 | |
TheChrisyd | 0:a2d36977aec3 | 830 | // when all items collected, |
TheChrisyd | 0:a2d36977aec3 | 831 | // flash portal in colors 32,33 - the thing the Spectrum *can* do in hardware |
TheChrisyd | 0:a2d36977aec3 | 832 | byte flip = (t >> 3) & (CHEAT_OPEN_PORTAL || state.nitems == 0); |
TheChrisyd | 0:a2d36977aec3 | 833 | GD.wr16(RAM_SPRPAL + 2 * (32 ^ flip), COLOR(PAPER(state.portalattr))); |
TheChrisyd | 0:a2d36977aec3 | 834 | GD.wr16(RAM_SPRPAL + 2 * (33 ^ flip), COLOR(INK(state.portalattr))); |
TheChrisyd | 0:a2d36977aec3 | 835 | |
TheChrisyd | 0:a2d36977aec3 | 836 | // animated lives count, draw up to seven |
TheChrisyd | 0:a2d36977aec3 | 837 | for (byte i = 0; i < 7; i++) |
TheChrisyd | 0:a2d36977aec3 | 838 | if (i < (state.lives - 1)) |
TheChrisyd | 0:a2d36977aec3 | 839 | sprite(IMG_WILLYC + i, i << 4, 168, IMG_WILLYC + ((t >> 2) & 3)); |
TheChrisyd | 0:a2d36977aec3 | 840 | else |
TheChrisyd | 0:a2d36977aec3 | 841 | hide(IMG_WILLYC + i); |
TheChrisyd | 0:a2d36977aec3 | 842 | |
TheChrisyd | 0:a2d36977aec3 | 843 | GD.waitvblank(); |
TheChrisyd | 0:a2d36977aec3 | 844 | } |
TheChrisyd | 0:a2d36977aec3 | 845 | |
TheChrisyd | 0:a2d36977aec3 | 846 | // play a complete game |
TheChrisyd | 0:a2d36977aec3 | 847 | void loop() |
TheChrisyd | 0:a2d36977aec3 | 848 | { |
TheChrisyd | 0:a2d36977aec3 | 849 | title_screen(); |
TheChrisyd | 0:a2d36977aec3 | 850 | game_graphics(); |
TheChrisyd | 0:a2d36977aec3 | 851 | |
TheChrisyd | 0:a2d36977aec3 | 852 | state.level = START_LEVEL; |
TheChrisyd | 0:a2d36977aec3 | 853 | state.score = 0; |
TheChrisyd | 0:a2d36977aec3 | 854 | for (state.lives = 3; state.lives; state.lives--) { |
TheChrisyd | 0:a2d36977aec3 | 855 | loadlevel(&levels[state.level]); |
TheChrisyd | 0:a2d36977aec3 | 856 | // state.wy = 16; |
TheChrisyd | 0:a2d36977aec3 | 857 | byte alive = 1; |
TheChrisyd | 0:a2d36977aec3 | 858 | byte t = 0; |
TheChrisyd | 0:a2d36977aec3 | 859 | while (alive) { |
TheChrisyd | 0:a2d36977aec3 | 860 | drive_level(t); |
TheChrisyd | 0:a2d36977aec3 | 861 | |
TheChrisyd | 0:a2d36977aec3 | 862 | // Willy draw |
TheChrisyd | 0:a2d36977aec3 | 863 | byte frame = state.wf ^ (state.wd ? 7 : 0); |
TheChrisyd | 0:a2d36977aec3 | 864 | loadspr16(IMG_WILLY, willy + (frame << 5), 255, 8 + 7); |
TheChrisyd | 0:a2d36977aec3 | 865 | sprite(IMG_WILLY, state.wx, state.wy, IMG_WILLY); |
TheChrisyd | 0:a2d36977aec3 | 866 | |
TheChrisyd | 0:a2d36977aec3 | 867 | // Willy movement |
TheChrisyd | 0:a2d36977aec3 | 868 | // See http://www.seasip.demon.co.uk/Jsw/manic.mac |
TheChrisyd | 0:a2d36977aec3 | 869 | // and http://jetsetwilly.jodi.org/poke.html |
TheChrisyd | 0:a2d36977aec3 | 870 | |
TheChrisyd | 0:a2d36977aec3 | 871 | byte con = control(); |
TheChrisyd | 0:a2d36977aec3 | 872 | byte ychanged = 0; // if Y block changes must check for landing later |
TheChrisyd | 0:a2d36977aec3 | 873 | if (state.jumping) { |
TheChrisyd | 0:a2d36977aec3 | 874 | #define JUMP_APEX 9 |
TheChrisyd | 0:a2d36977aec3 | 875 | #define JUMP_FALL 11 // 1 2 3 4 5 6 7 8 9 10 11 |
TheChrisyd | 0:a2d36977aec3 | 876 | signed char moves[] = { -4, -4, -3, -3, -2, -2, -1, -1, 0, 0, 1, 1, 2, 2, 3, 3, 4 }; |
TheChrisyd | 0:a2d36977aec3 | 877 | byte index = min(sizeof(moves) - 1, state.jumping - 1); |
TheChrisyd | 0:a2d36977aec3 | 878 | byte newy = state.wy + moves[index]; |
TheChrisyd | 0:a2d36977aec3 | 879 | state.jumping++; |
TheChrisyd | 0:a2d36977aec3 | 880 | if (canbe(state.wx, newy)) { |
TheChrisyd | 0:a2d36977aec3 | 881 | ychanged = (state.wy >> 3) != (newy >> 3); |
TheChrisyd | 0:a2d36977aec3 | 882 | state.wy = newy; |
TheChrisyd | 0:a2d36977aec3 | 883 | } else { |
TheChrisyd | 0:a2d36977aec3 | 884 | state.jumping = max(state.jumping, JUMP_FALL); // halt ascent |
TheChrisyd | 0:a2d36977aec3 | 885 | ychanged = 1; |
TheChrisyd | 0:a2d36977aec3 | 886 | } |
TheChrisyd | 0:a2d36977aec3 | 887 | } |
TheChrisyd | 0:a2d36977aec3 | 888 | uint16_t feet_addr = atxy(state.wx >> 3, (state.wy + 16) >> 3); |
TheChrisyd | 0:a2d36977aec3 | 889 | byte elem0 = GD.rd(feet_addr); |
TheChrisyd | 0:a2d36977aec3 | 890 | byte elem1 = GD.rd(feet_addr + 1); |
TheChrisyd | 0:a2d36977aec3 | 891 | byte elem = ((1 <= elem0) && (elem0 <= 31)) ? elem0 : elem1; |
TheChrisyd | 0:a2d36977aec3 | 892 | |
TheChrisyd | 0:a2d36977aec3 | 893 | byte dx = 0xff; |
TheChrisyd | 0:a2d36977aec3 | 894 | byte first_jump = (con & CONTROL_JUMP) && state.lastdx == 0xff; |
TheChrisyd | 0:a2d36977aec3 | 895 | if (state.jumping) { |
TheChrisyd | 0:a2d36977aec3 | 896 | dx = state.lastdx; |
TheChrisyd | 0:a2d36977aec3 | 897 | } else if (!first_jump && (elem == ELEM_CONVEYOR) && (state.wd == state.conveyordir)) { |
TheChrisyd | 0:a2d36977aec3 | 898 | dx = state.conveyordir; |
TheChrisyd | 0:a2d36977aec3 | 899 | } else { |
TheChrisyd | 0:a2d36977aec3 | 900 | if (con & CONTROL_RIGHT) { |
TheChrisyd | 0:a2d36977aec3 | 901 | if (state.wd != 0) { |
TheChrisyd | 0:a2d36977aec3 | 902 | state.wf ^= 3; |
TheChrisyd | 0:a2d36977aec3 | 903 | state.wd = 0; |
TheChrisyd | 0:a2d36977aec3 | 904 | } else { |
TheChrisyd | 0:a2d36977aec3 | 905 | dx = 0; |
TheChrisyd | 0:a2d36977aec3 | 906 | } |
TheChrisyd | 0:a2d36977aec3 | 907 | } else if (con & CONTROL_LEFT) { |
TheChrisyd | 0:a2d36977aec3 | 908 | if (state.wd == 0) { |
TheChrisyd | 0:a2d36977aec3 | 909 | state.wf ^= 3; |
TheChrisyd | 0:a2d36977aec3 | 910 | state.wd = 1; |
TheChrisyd | 0:a2d36977aec3 | 911 | } else { |
TheChrisyd | 0:a2d36977aec3 | 912 | dx = 1; |
TheChrisyd | 0:a2d36977aec3 | 913 | } |
TheChrisyd | 0:a2d36977aec3 | 914 | } |
TheChrisyd | 0:a2d36977aec3 | 915 | } |
TheChrisyd | 0:a2d36977aec3 | 916 | if (dx != 0xff) { |
TheChrisyd | 0:a2d36977aec3 | 917 | if (state.wf != 3) |
TheChrisyd | 0:a2d36977aec3 | 918 | state.wf++; |
TheChrisyd | 0:a2d36977aec3 | 919 | else { |
TheChrisyd | 0:a2d36977aec3 | 920 | byte newx = state.wx + (dx ? -8 : 8); |
TheChrisyd | 0:a2d36977aec3 | 921 | if (canbe(newx, state.wy)) { |
TheChrisyd | 0:a2d36977aec3 | 922 | state.wf = 0; |
TheChrisyd | 0:a2d36977aec3 | 923 | state.wx = newx; |
TheChrisyd | 0:a2d36977aec3 | 924 | } |
TheChrisyd | 0:a2d36977aec3 | 925 | } |
TheChrisyd | 0:a2d36977aec3 | 926 | } |
TheChrisyd | 0:a2d36977aec3 | 927 | state.lastdx = dx; |
TheChrisyd | 0:a2d36977aec3 | 928 | |
TheChrisyd | 0:a2d36977aec3 | 929 | if ((elem == ELEM_CONVEYOR) && (dx == 0xff) && !state.jumping) |
TheChrisyd | 0:a2d36977aec3 | 930 | state.wd = state.conveyordir; |
TheChrisyd | 0:a2d36977aec3 | 931 | |
TheChrisyd | 0:a2d36977aec3 | 932 | if (!state.jumping && (con & CONTROL_JUMP)) { |
TheChrisyd | 0:a2d36977aec3 | 933 | if (canbe(state.wx, state.wy - 3)) { |
TheChrisyd | 0:a2d36977aec3 | 934 | state.jumping = 1; |
TheChrisyd | 0:a2d36977aec3 | 935 | state.wy -= 0; |
TheChrisyd | 0:a2d36977aec3 | 936 | } |
TheChrisyd | 0:a2d36977aec3 | 937 | } |
TheChrisyd | 0:a2d36977aec3 | 938 | |
TheChrisyd | 0:a2d36977aec3 | 939 | byte onground = ((1 <= elem) && (elem <= 4)) || ((7 <= elem) && (elem <= 16)); |
TheChrisyd | 0:a2d36977aec3 | 940 | if (state.jumping) { |
TheChrisyd | 0:a2d36977aec3 | 941 | if ((JUMP_APEX <= state.jumping) && ychanged && onground) { |
TheChrisyd | 0:a2d36977aec3 | 942 | state.jumping = 0; |
TheChrisyd | 0:a2d36977aec3 | 943 | state.wy &= ~7; |
TheChrisyd | 0:a2d36977aec3 | 944 | } |
TheChrisyd | 0:a2d36977aec3 | 945 | if (state.jumping >= 19) // stop x movement late in the jump |
TheChrisyd | 0:a2d36977aec3 | 946 | state.lastdx = 0xff; |
TheChrisyd | 0:a2d36977aec3 | 947 | } else { |
TheChrisyd | 0:a2d36977aec3 | 948 | if (!onground) { // nothing to stand on, start falling |
TheChrisyd | 0:a2d36977aec3 | 949 | state.jumping = JUMP_FALL; |
TheChrisyd | 0:a2d36977aec3 | 950 | state.lastdx = 0xff; |
TheChrisyd | 0:a2d36977aec3 | 951 | } |
TheChrisyd | 0:a2d36977aec3 | 952 | } |
TheChrisyd | 0:a2d36977aec3 | 953 | if (!state.jumping) { |
TheChrisyd | 0:a2d36977aec3 | 954 | crumble(feet_addr); |
TheChrisyd | 0:a2d36977aec3 | 955 | crumble(feet_addr + 1); |
TheChrisyd | 0:a2d36977aec3 | 956 | } |
TheChrisyd | 0:a2d36977aec3 | 957 | |
TheChrisyd | 0:a2d36977aec3 | 958 | if (((t & 7) == 0) || |
TheChrisyd | 0:a2d36977aec3 | 959 | ((state.level == 18) && inray(state.wx, state.wy))) { |
TheChrisyd | 0:a2d36977aec3 | 960 | state.air--; |
TheChrisyd | 0:a2d36977aec3 | 961 | plot_air(); |
TheChrisyd | 0:a2d36977aec3 | 962 | if (state.air == 0) { |
TheChrisyd | 0:a2d36977aec3 | 963 | alive = 0; |
TheChrisyd | 0:a2d36977aec3 | 964 | } |
TheChrisyd | 0:a2d36977aec3 | 965 | } |
TheChrisyd | 0:a2d36977aec3 | 966 | GD.waitvblank(); // let the screen display, then check for collisions |
TheChrisyd | 0:a2d36977aec3 | 967 | byte coll = GD.rd(COLLISION + IMG_WILLY); |
TheChrisyd | 0:a2d36977aec3 | 968 | if (coll <= (IMG_ITEM + 4)) { |
TheChrisyd | 0:a2d36977aec3 | 969 | bump_score(100); |
TheChrisyd | 0:a2d36977aec3 | 970 | hide(coll - IMG_ITEM); |
TheChrisyd | 0:a2d36977aec3 | 971 | --state.nitems; |
TheChrisyd | 0:a2d36977aec3 | 972 | } else if (coll == IMG_PORTAL) { |
TheChrisyd | 0:a2d36977aec3 | 973 | if (CHEAT_OPEN_PORTAL || state.nitems == 0) { |
TheChrisyd | 0:a2d36977aec3 | 974 | while (state.air) { |
TheChrisyd | 0:a2d36977aec3 | 975 | squarewave(0, 800 + 2 * state.air, 100); |
TheChrisyd | 0:a2d36977aec3 | 976 | state.air--; |
TheChrisyd | 0:a2d36977aec3 | 977 | plot_air(); |
TheChrisyd | 0:a2d36977aec3 | 978 | bump_score(7); |
TheChrisyd | 0:a2d36977aec3 | 979 | GD.waitvblank(); |
TheChrisyd | 0:a2d36977aec3 | 980 | } |
TheChrisyd | 0:a2d36977aec3 | 981 | state.level = (state.level + 1) % 18; |
TheChrisyd | 0:a2d36977aec3 | 982 | loadlevel(&levels[state.level]); |
TheChrisyd | 0:a2d36977aec3 | 983 | } |
TheChrisyd | 0:a2d36977aec3 | 984 | } else if (coll == IMG_SWITCH1) { |
TheChrisyd | 0:a2d36977aec3 | 985 | if (!state.switch1) { |
TheChrisyd | 0:a2d36977aec3 | 986 | state.switch1 = 1; |
TheChrisyd | 0:a2d36977aec3 | 987 | sprite(IMG_SWITCH1, 48 - 8, 0, IMG_SWITCH1, 2); |
TheChrisyd | 0:a2d36977aec3 | 988 | GD.wr(atxy(17, 11), 0); |
TheChrisyd | 0:a2d36977aec3 | 989 | GD.wr(atxy(17, 12), 0); |
TheChrisyd | 0:a2d36977aec3 | 990 | } |
TheChrisyd | 0:a2d36977aec3 | 991 | } else if (coll == IMG_SWITCH2) { |
TheChrisyd | 0:a2d36977aec3 | 992 | if (coll == IMG_SWITCH2) { |
TheChrisyd | 0:a2d36977aec3 | 993 | state.switch2 = 1; |
TheChrisyd | 0:a2d36977aec3 | 994 | sprite(IMG_SWITCH2, 144 - 8, 0, IMG_SWITCH2, 2); |
TheChrisyd | 0:a2d36977aec3 | 995 | GD.wr(atxy(15, 2), 0); |
TheChrisyd | 0:a2d36977aec3 | 996 | GD.wr(atxy(16, 2), 0); |
TheChrisyd | 0:a2d36977aec3 | 997 | } |
TheChrisyd | 0:a2d36977aec3 | 998 | } else if (coll != 0xff && !CHEAT_INVINCIBLE) { |
TheChrisyd | 0:a2d36977aec3 | 999 | alive = 0; |
TheChrisyd | 0:a2d36977aec3 | 1000 | } |
TheChrisyd | 0:a2d36977aec3 | 1001 | t++; |
TheChrisyd | 0:a2d36977aec3 | 1002 | } |
TheChrisyd | 0:a2d36977aec3 | 1003 | // player died |
TheChrisyd | 0:a2d36977aec3 | 1004 | clear_screen(); |
TheChrisyd | 0:a2d36977aec3 | 1005 | } |
TheChrisyd | 0:a2d36977aec3 | 1006 | game_over(); |
TheChrisyd | 0:a2d36977aec3 | 1007 | } |
TheChrisyd | 0:a2d36977aec3 | 1008 | |
TheChrisyd | 0:a2d36977aec3 | 1009 | |
TheChrisyd | 0:a2d36977aec3 | 1010 | |
TheChrisyd | 0:a2d36977aec3 | 1011 | |
TheChrisyd | 0:a2d36977aec3 | 1012 | |
TheChrisyd | 0:a2d36977aec3 | 1013 | |
TheChrisyd | 0:a2d36977aec3 | 1014 | |
TheChrisyd | 0:a2d36977aec3 | 1015 | int main(){ |
TheChrisyd | 0:a2d36977aec3 | 1016 | setup(); |
TheChrisyd | 0:a2d36977aec3 | 1017 | while(1){ |
TheChrisyd | 0:a2d36977aec3 | 1018 | loop(); |
TheChrisyd | 0:a2d36977aec3 | 1019 | } |
TheChrisyd | 0:a2d36977aec3 | 1020 | } |