Asteroids game using a Gameduino

Dependencies:   Gameduino mbed

A version of the classic asteroids game for the mbed using gameduino. The game currently runs far too fast and is unplayable.

Please see http://mbed.org/users/TheChrisyd/code/Gameduino/ for more information

Committer:
TheChrisyd
Date:
Fri Dec 21 13:45:01 2012 +0000
Revision:
2:6c07ac67dbb2
Parent:
1:3907d67048f1
updated Gameduino library

Who changed what in which revision?

UserRevisionLine numberNew contents of line
TheChrisyd 0:2175bf475f30 1 #include "mbed.h"
TheChrisyd 0:2175bf475f30 2 #include "GD.h"
TheChrisyd 0:2175bf475f30 3 #include "shield.h"
TheChrisyd 0:2175bf475f30 4
TheChrisyd 0:2175bf475f30 5 GDClass GD(ARD_MOSI, ARD_MISO, ARD_SCK, ARD_D9, USBTX, USBRX) ;
TheChrisyd 0:2175bf475f30 6 SPI spimain(ARD_MOSI, ARD_MISO, ARD_SCK); // mosi, miso, sclk
TheChrisyd 0:2175bf475f30 7 DigitalIn down(ARD_A2);//0
TheChrisyd 0:2175bf475f30 8 DigitalIn up(ARD_A3);//1
TheChrisyd 0:2175bf475f30 9 DigitalIn left(ARD_A1);//2
TheChrisyd 0:2175bf475f30 10 DigitalIn right(ARD_A0);//3
TheChrisyd 0:2175bf475f30 11
TheChrisyd 0:2175bf475f30 12 // ----------------------------------------------------------------------
TheChrisyd 0:2175bf475f30 13 // qrand: quick random numbers
TheChrisyd 0:2175bf475f30 14 // ----------------------------------------------------------------------
TheChrisyd 0:2175bf475f30 15
TheChrisyd 0:2175bf475f30 16 static uint16_t lfsr = 1;
TheChrisyd 0:2175bf475f30 17
TheChrisyd 0:2175bf475f30 18 static void qrandSeed(int seed) {
TheChrisyd 0:2175bf475f30 19 if (seed) {
TheChrisyd 0:2175bf475f30 20 lfsr = seed;
TheChrisyd 0:2175bf475f30 21 } else {
TheChrisyd 0:2175bf475f30 22 lfsr = 0x947;
TheChrisyd 0:2175bf475f30 23 }
TheChrisyd 0:2175bf475f30 24 }
TheChrisyd 0:2175bf475f30 25
TheChrisyd 0:2175bf475f30 26 static byte qrand1() { // a random bit
TheChrisyd 0:2175bf475f30 27 lfsr = (lfsr >> 1) ^ (-(lfsr & 1) & 0xb400);
TheChrisyd 0:2175bf475f30 28 return lfsr & 1;
TheChrisyd 0:2175bf475f30 29 }
TheChrisyd 0:2175bf475f30 30
TheChrisyd 0:2175bf475f30 31 static byte qrand(byte n) { // n random bits
TheChrisyd 0:2175bf475f30 32 byte r = 0;
TheChrisyd 0:2175bf475f30 33 while (n--)
TheChrisyd 0:2175bf475f30 34 r = (r << 1) | qrand1();
TheChrisyd 0:2175bf475f30 35 return r;
TheChrisyd 0:2175bf475f30 36 }
TheChrisyd 0:2175bf475f30 37
TheChrisyd 0:2175bf475f30 38 // ----------------------------------------------------------------------
TheChrisyd 0:2175bf475f30 39 // controller: buttons on Arduino pins 3,4,5,6
TheChrisyd 0:2175bf475f30 40 // ----------------------------------------------------------------------
TheChrisyd 0:2175bf475f30 41
TheChrisyd 0:2175bf475f30 42 static void controller_init() {
TheChrisyd 0:2175bf475f30 43 // Configure input pins with internal pullups
TheChrisyd 0:2175bf475f30 44
TheChrisyd 1:3907d67048f1 45 down.mode(PullUp);
TheChrisyd 1:3907d67048f1 46 up.mode(PullUp);
TheChrisyd 1:3907d67048f1 47 left.mode(PullUp);
TheChrisyd 1:3907d67048f1 48 right.mode(PullUp);
TheChrisyd 0:2175bf475f30 49
TheChrisyd 0:2175bf475f30 50 }
TheChrisyd 0:2175bf475f30 51
TheChrisyd 0:2175bf475f30 52 #define CONTROL_LEFT 1
TheChrisyd 0:2175bf475f30 53 #define CONTROL_RIGHT 2
TheChrisyd 0:2175bf475f30 54 #define CONTROL_UP 4
TheChrisyd 0:2175bf475f30 55 #define CONTROL_DOWN 8
TheChrisyd 0:2175bf475f30 56
TheChrisyd 0:2175bf475f30 57
TheChrisyd 0:2175bf475f30 58 static byte controller_sense(uint16_t clock) {
TheChrisyd 0:2175bf475f30 59 byte r = 0;
TheChrisyd 0:2175bf475f30 60
TheChrisyd 0:2175bf475f30 61
TheChrisyd 1:3907d67048f1 62 if (!down)
TheChrisyd 0:2175bf475f30 63 r |= CONTROL_DOWN;
TheChrisyd 1:3907d67048f1 64 if (!up)
TheChrisyd 0:2175bf475f30 65 r |= CONTROL_UP;
TheChrisyd 1:3907d67048f1 66 if (!left)
TheChrisyd 0:2175bf475f30 67 r |= CONTROL_LEFT;
TheChrisyd 1:3907d67048f1 68 if (!right)
TheChrisyd 0:2175bf475f30 69 r |= CONTROL_RIGHT;
TheChrisyd 0:2175bf475f30 70
TheChrisyd 0:2175bf475f30 71 return r;
TheChrisyd 0:2175bf475f30 72 }
TheChrisyd 0:2175bf475f30 73
TheChrisyd 0:2175bf475f30 74 // Swap color's red and blue channels
TheChrisyd 0:2175bf475f30 75 uint16_t swapRB(uint16_t color) {
TheChrisyd 0:2175bf475f30 76 byte r = 31 & (color >> 10);
TheChrisyd 0:2175bf475f30 77 byte g = 31 & (color >> 5);
TheChrisyd 0:2175bf475f30 78 byte b = 31 & color;
TheChrisyd 0:2175bf475f30 79 return (color & 0x8000) | (b << 10) | (g << 5) | r;
TheChrisyd 0:2175bf475f30 80 }
TheChrisyd 0:2175bf475f30 81
TheChrisyd 0:2175bf475f30 82 // Swap color's red and green channels
TheChrisyd 0:2175bf475f30 83 uint16_t swapRG(uint16_t color) {
TheChrisyd 0:2175bf475f30 84 byte r = 31 & (color >> 10);
TheChrisyd 0:2175bf475f30 85 byte g = 31 & (color >> 5);
TheChrisyd 0:2175bf475f30 86 byte b = 31 & color;
TheChrisyd 0:2175bf475f30 87 return (color & 0x8000) | (g << 10) | (r << 5) | b;
TheChrisyd 0:2175bf475f30 88 }
TheChrisyd 0:2175bf475f30 89
TheChrisyd 0:2175bf475f30 90 #include "asteroidgraphics.h"
TheChrisyd 0:2175bf475f30 91 #include "splitscreen.h"
TheChrisyd 0:2175bf475f30 92
TheChrisyd 0:2175bf475f30 93 static void update_score();
TheChrisyd 0:2175bf475f30 94
TheChrisyd 0:2175bf475f30 95 // [int(127 * math.sin(math.pi * 2 * i / 16)) for i in range(16)]
TheChrisyd 0:2175bf475f30 96 static PROGMEM signed char charsin[16] = {0, 48, 89, 117, 127, 117, 89, 48, 0, -48, -89, -117, -127, -117, -89, -48};
TheChrisyd 0:2175bf475f30 97 char qsin(int a) {
TheChrisyd 0:2175bf475f30 98 //har)pgm_read_byte_near(charsin + ((a) & 15))
TheChrisyd 0:2175bf475f30 99 return charsin[(a & 15)];
TheChrisyd 0:2175bf475f30 100 }
TheChrisyd 0:2175bf475f30 101 #define qcos(a) qsin((a) + 4)
TheChrisyd 0:2175bf475f30 102
TheChrisyd 0:2175bf475f30 103 static char spr2obj[256]; // Maps sprites to owning objects
TheChrisyd 0:2175bf475f30 104
TheChrisyd 0:2175bf475f30 105 /*
TheChrisyd 0:2175bf475f30 106
TheChrisyd 0:2175bf475f30 107 The general idea is that an object table ``objects`` has an entry for
TheChrisyd 0:2175bf475f30 108 each drawn thing on screen (e.g. player, missile, rock, explosion).
TheChrisyd 0:2175bf475f30 109 Each class of object has a ``handler`` function that does the necessary
TheChrisyd 0:2175bf475f30 110 housekeeping and draws the actual sprites.
TheChrisyd 0:2175bf475f30 111
TheChrisyd 0:2175bf475f30 112 As part of the behavior, some classes need to know if they have collided
TheChrisyd 0:2175bf475f30 113 with anything. In particular the rocks need to know if they have collided
TheChrisyd 0:2175bf475f30 114 with the player or a missile. The `collide` member points to the
TheChrisyd 0:2175bf475f30 115 colliding sprite.
TheChrisyd 0:2175bf475f30 116
TheChrisyd 0:2175bf475f30 117 */
TheChrisyd 0:2175bf475f30 118
TheChrisyd 0:2175bf475f30 119 struct object {
TheChrisyd 0:2175bf475f30 120 int x, y;
TheChrisyd 0:2175bf475f30 121 byte handler, state;
TheChrisyd 0:2175bf475f30 122 byte collide;
TheChrisyd 0:2175bf475f30 123 } objects[128];
TheChrisyd 0:2175bf475f30 124 #define COORD(c) ((c) << 4)
TheChrisyd 0:2175bf475f30 125
TheChrisyd 0:2175bf475f30 126 static signed char explosions = -1;
TheChrisyd 0:2175bf475f30 127 static signed char enemies = -1;
TheChrisyd 0:2175bf475f30 128 static signed char missiles = -1;
TheChrisyd 0:2175bf475f30 129
TheChrisyd 0:2175bf475f30 130 static void push(signed char *stk, byte i) {
TheChrisyd 0:2175bf475f30 131 objects[i].state = *stk;
TheChrisyd 0:2175bf475f30 132 *stk = i;
TheChrisyd 0:2175bf475f30 133 }
TheChrisyd 0:2175bf475f30 134
TheChrisyd 0:2175bf475f30 135 static char pop(signed char *stk) {
TheChrisyd 0:2175bf475f30 136 signed char r = *stk;
TheChrisyd 0:2175bf475f30 137 if (0 <= r) {
TheChrisyd 0:2175bf475f30 138 *stk = objects[r].state;
TheChrisyd 0:2175bf475f30 139 }
TheChrisyd 0:2175bf475f30 140 return r;
TheChrisyd 0:2175bf475f30 141 }
TheChrisyd 0:2175bf475f30 142
TheChrisyd 0:2175bf475f30 143 byte rr[4] = { 0,3,6,5 };
TheChrisyd 0:2175bf475f30 144
TheChrisyd 0:2175bf475f30 145 static struct {
TheChrisyd 0:2175bf475f30 146 byte boing, boom, pop;
TheChrisyd 0:2175bf475f30 147 byte thrust;
TheChrisyd 0:2175bf475f30 148 byte bass;
TheChrisyd 0:2175bf475f30 149 } sounds;
TheChrisyd 0:2175bf475f30 150
TheChrisyd 0:2175bf475f30 151 static int player_vx, player_vy; // Player velocity
TheChrisyd 0:2175bf475f30 152 static int player_invincible, player_dying;
TheChrisyd 0:2175bf475f30 153 static byte lives;
TheChrisyd 0:2175bf475f30 154 static long score;
TheChrisyd 0:2175bf475f30 155 static byte level;
TheChrisyd 0:2175bf475f30 156
TheChrisyd 0:2175bf475f30 157 // Move object po by velocity (vx, vy), optionally keeping in
TheChrisyd 0:2175bf475f30 158 // player's frame.
TheChrisyd 0:2175bf475f30 159 // Returns true if the object wrapped screen edge
TheChrisyd 0:2175bf475f30 160 static bool move(struct object *po, char vx, char vy, byte playerframe = 1) {
TheChrisyd 0:2175bf475f30 161 bool r = 0;
TheChrisyd 0:2175bf475f30 162 if (playerframe) {
TheChrisyd 0:2175bf475f30 163 po->x += (vx - player_vx);
TheChrisyd 0:2175bf475f30 164 po->y += (vy - player_vy);
TheChrisyd 0:2175bf475f30 165 } else {
TheChrisyd 0:2175bf475f30 166 po->x += vx;
TheChrisyd 0:2175bf475f30 167 po->y += vy;
TheChrisyd 0:2175bf475f30 168 }
TheChrisyd 0:2175bf475f30 169
TheChrisyd 0:2175bf475f30 170 if (po->x > COORD(416))
TheChrisyd 0:2175bf475f30 171 r = 1, po->x -= COORD(432);
TheChrisyd 0:2175bf475f30 172 else if (po->x < COORD(-16))
TheChrisyd 0:2175bf475f30 173 r = 1, po->x += COORD(432);
TheChrisyd 0:2175bf475f30 174
TheChrisyd 0:2175bf475f30 175 if (po->y > COORD(316))
TheChrisyd 0:2175bf475f30 176 r = 1, po->y -= COORD(332);
TheChrisyd 0:2175bf475f30 177 else if (po->y < COORD(-16))
TheChrisyd 0:2175bf475f30 178 r = 1, po->y += COORD(332);
TheChrisyd 0:2175bf475f30 179 return r;
TheChrisyd 0:2175bf475f30 180 }
TheChrisyd 0:2175bf475f30 181
TheChrisyd 0:2175bf475f30 182
TheChrisyd 0:2175bf475f30 183 #define HANDLE_NULL 0
TheChrisyd 0:2175bf475f30 184 #define HANDLE_ROCK0 1
TheChrisyd 0:2175bf475f30 185 #define HANDLE_ROCK1 2
TheChrisyd 0:2175bf475f30 186 #define HANDLE_BANG0 3
TheChrisyd 0:2175bf475f30 187 #define HANDLE_BANG1 4
TheChrisyd 0:2175bf475f30 188 #define HANDLE_PLAYER 5
TheChrisyd 0:2175bf475f30 189 #define HANDLE_MISSILE 6
TheChrisyd 0:2175bf475f30 190
TheChrisyd 0:2175bf475f30 191 // Expire object i, and return it to the free stk
TheChrisyd 0:2175bf475f30 192 static void expire(signed char *stk, byte i) {
TheChrisyd 0:2175bf475f30 193 objects[i].handler = HANDLE_NULL;
TheChrisyd 0:2175bf475f30 194 push(stk, i);
TheChrisyd 0:2175bf475f30 195 }
TheChrisyd 0:2175bf475f30 196
TheChrisyd 0:2175bf475f30 197 static void handle_null(byte i, byte state, uint16_t clock) {
TheChrisyd 0:2175bf475f30 198 }
TheChrisyd 0:2175bf475f30 199
TheChrisyd 0:2175bf475f30 200 static void handle_player(byte i, byte state, uint16_t clock) {
TheChrisyd 0:2175bf475f30 201 struct object *po = &objects[i];
TheChrisyd 0:2175bf475f30 202 byte angle = (po->state & 15);
TheChrisyd 0:2175bf475f30 203 byte rot1 = (angle & 3);
TheChrisyd 0:2175bf475f30 204 byte rot2 = rr[3 & (angle >> 2)];
TheChrisyd 0:2175bf475f30 205 if (!player_dying && (player_invincible & 1) == 0)
TheChrisyd 0:2175bf475f30 206 draw_player(200, 150, rot1, rot2);
TheChrisyd 0:2175bf475f30 207
TheChrisyd 0:2175bf475f30 208 static byte prev_control;
TheChrisyd 0:2175bf475f30 209 byte control = controller_sense(clock);
TheChrisyd 0:2175bf475f30 210
TheChrisyd 0:2175bf475f30 211 char thrust_x, thrust_y;
TheChrisyd 0:2175bf475f30 212 if (!player_dying && control & CONTROL_DOWN) { // thrust
TheChrisyd 0:2175bf475f30 213 byte flame_angle = angle ^ 8;
TheChrisyd 0:2175bf475f30 214 byte d;
TheChrisyd 0:2175bf475f30 215 for (d = 9; d > 5; d--) {
TheChrisyd 0:2175bf475f30 216 int flamex = 201 - (((d + (clock&3)) * qsin(flame_angle)) >> 5);
TheChrisyd 0:2175bf475f30 217 int flamey = 150 - (((d + (clock&3)) * qcos(flame_angle)) >> 5);
TheChrisyd 0:2175bf475f30 218 if ((player_invincible & 1) == 0)
TheChrisyd 0:2175bf475f30 219 draw_sparkr(flamex, flamey, rot1, rot2, 1); // collision class K
TheChrisyd 0:2175bf475f30 220 }
TheChrisyd 0:2175bf475f30 221 thrust_x = -qsin(angle);
TheChrisyd 0:2175bf475f30 222 thrust_y = -qcos(angle);
TheChrisyd 0:2175bf475f30 223 sounds.thrust = 1;
TheChrisyd 0:2175bf475f30 224 } else {
TheChrisyd 0:2175bf475f30 225 thrust_x = thrust_y = 0;
TheChrisyd 0:2175bf475f30 226 sounds.thrust = 0;
TheChrisyd 0:2175bf475f30 227 }
TheChrisyd 0:2175bf475f30 228
TheChrisyd 0:2175bf475f30 229 player_vx = ((31 * player_vx) + thrust_x) / 32;
TheChrisyd 0:2175bf475f30 230 player_vy = ((31 * player_vy) + thrust_y) / 32;
TheChrisyd 0:2175bf475f30 231
TheChrisyd 0:2175bf475f30 232 po->x += player_vx;
TheChrisyd 0:2175bf475f30 233 po->y += player_vy;
TheChrisyd 0:2175bf475f30 234
TheChrisyd 0:2175bf475f30 235 if (clock & 1) {
TheChrisyd 0:2175bf475f30 236 char rotate = (512) / 400;
TheChrisyd 0:2175bf475f30 237 if (control & CONTROL_LEFT)
TheChrisyd 0:2175bf475f30 238 rotate++;
TheChrisyd 0:2175bf475f30 239 if (control & CONTROL_RIGHT)
TheChrisyd 0:2175bf475f30 240 rotate--;
TheChrisyd 0:2175bf475f30 241 po->state = ((angle + rotate) & 15);
TheChrisyd 0:2175bf475f30 242 }
TheChrisyd 0:2175bf475f30 243
TheChrisyd 0:2175bf475f30 244 if (!player_dying &&
TheChrisyd 0:2175bf475f30 245 !(prev_control & CONTROL_UP) &&
TheChrisyd 0:2175bf475f30 246 (control & CONTROL_UP)) { // shoot!
TheChrisyd 0:2175bf475f30 247 signed char e = pop(&missiles);
TheChrisyd 0:2175bf475f30 248 if (0 <= e) {
TheChrisyd 0:2175bf475f30 249 objects[e].x = COORD(200);
TheChrisyd 0:2175bf475f30 250 objects[e].y = COORD(150);
TheChrisyd 0:2175bf475f30 251 objects[e].state = po->state;
TheChrisyd 0:2175bf475f30 252 objects[e].handler = HANDLE_MISSILE;
TheChrisyd 0:2175bf475f30 253 }
TheChrisyd 0:2175bf475f30 254 sounds.boing = 1;
TheChrisyd 0:2175bf475f30 255 }
TheChrisyd 0:2175bf475f30 256 prev_control = control;
TheChrisyd 0:2175bf475f30 257 if (player_invincible)
TheChrisyd 0:2175bf475f30 258 --player_invincible;
TheChrisyd 0:2175bf475f30 259 if (player_dying) {
TheChrisyd 0:2175bf475f30 260 if (--player_dying == 0) {
TheChrisyd 0:2175bf475f30 261 --lives;
TheChrisyd 0:2175bf475f30 262 update_score();
TheChrisyd 0:2175bf475f30 263 if (lives != 0) {
TheChrisyd 0:2175bf475f30 264 player_invincible = 48;
TheChrisyd 0:2175bf475f30 265 }
TheChrisyd 0:2175bf475f30 266 }
TheChrisyd 0:2175bf475f30 267 }
TheChrisyd 0:2175bf475f30 268 }
TheChrisyd 0:2175bf475f30 269
TheChrisyd 0:2175bf475f30 270 static void handle_missile(byte i, byte state, uint16_t clock) {
TheChrisyd 0:2175bf475f30 271 struct object *po = &objects[i];
TheChrisyd 0:2175bf475f30 272 byte angle = (po->state & 15);
TheChrisyd 0:2175bf475f30 273 byte rot1 = (angle & 3);
TheChrisyd 0:2175bf475f30 274 byte rot2 = rr[3 & (angle >> 2)];
TheChrisyd 0:2175bf475f30 275 draw_sparkr(po->x >> 4, po->y >> 4, rot1, rot2);
TheChrisyd 0:2175bf475f30 276 char vx = -qsin(po->state), vy = -qcos(po->state);
TheChrisyd 0:2175bf475f30 277 if (move(po, vx, vy, 0)) {
TheChrisyd 0:2175bf475f30 278 expire(&missiles, i);
TheChrisyd 0:2175bf475f30 279 }
TheChrisyd 0:2175bf475f30 280 }
TheChrisyd 0:2175bf475f30 281
TheChrisyd 0:2175bf475f30 282 static void explodehere(struct object *po, byte handler, uint16_t clock) {
TheChrisyd 0:2175bf475f30 283 signed char e = pop(&explosions);
TheChrisyd 0:2175bf475f30 284 if (0 <= e) {
TheChrisyd 0:2175bf475f30 285 objects[e].x = po->x;
TheChrisyd 0:2175bf475f30 286 objects[e].y = po->y;
TheChrisyd 0:2175bf475f30 287 objects[e].handler = handler;
TheChrisyd 0:2175bf475f30 288 objects[e].state = clock;
TheChrisyd 0:2175bf475f30 289 }
TheChrisyd 0:2175bf475f30 290 }
TheChrisyd 0:2175bf475f30 291
TheChrisyd 0:2175bf475f30 292 static void killplayer(uint16_t clock) {
TheChrisyd 0:2175bf475f30 293 if (!player_invincible && !player_dying) {
TheChrisyd 0:2175bf475f30 294 signed char e = pop(&explosions);
TheChrisyd 0:2175bf475f30 295 if (0 <= e) {
TheChrisyd 0:2175bf475f30 296 objects[e].x = COORD(200);
TheChrisyd 0:2175bf475f30 297 objects[e].y = COORD(150);
TheChrisyd 0:2175bf475f30 298 objects[e].handler = HANDLE_BANG1;
TheChrisyd 0:2175bf475f30 299 objects[e].state = clock;
TheChrisyd 0:2175bf475f30 300 }
TheChrisyd 0:2175bf475f30 301 player_dying = 2 * 36;
TheChrisyd 0:2175bf475f30 302 sounds.boom = 1;
TheChrisyd 0:2175bf475f30 303 sounds.pop = 1;
TheChrisyd 0:2175bf475f30 304 }
TheChrisyd 0:2175bf475f30 305 }
TheChrisyd 0:2175bf475f30 306
TheChrisyd 0:2175bf475f30 307 static byte commonrock(uint16_t clock, byte i, byte speed, void df(int x, int y, byte anim, byte rot, byte jk)) {
TheChrisyd 0:2175bf475f30 308 struct object *po = &objects[i];
TheChrisyd 0:2175bf475f30 309
TheChrisyd 0:2175bf475f30 310 byte move_angle = po->state >> 4;
TheChrisyd 0:2175bf475f30 311 char vx = (speed * -qsin(move_angle)) >> 6, vy = (speed * -qcos(move_angle)) >> 6;
TheChrisyd 0:2175bf475f30 312 move(po, vx, vy);
TheChrisyd 0:2175bf475f30 313
TheChrisyd 0:2175bf475f30 314 byte angle = (clock * speed) >> 4;
TheChrisyd 0:2175bf475f30 315 if (po->state & 1)
TheChrisyd 0:2175bf475f30 316 angle = ~angle;
TheChrisyd 0:2175bf475f30 317 byte rot1 = (angle & 3);
TheChrisyd 0:2175bf475f30 318 byte rot2 = rr[3 & (angle >> 2)];
TheChrisyd 0:2175bf475f30 319 df(po->x >> 4, po->y >> 4, rot1, rot2, 1);
TheChrisyd 0:2175bf475f30 320 if (po->collide != 0xff) {
TheChrisyd 0:2175bf475f30 321 struct object *other = &objects[po->collide];
TheChrisyd 0:2175bf475f30 322 switch (other->handler) {
TheChrisyd 0:2175bf475f30 323 case HANDLE_PLAYER:
TheChrisyd 0:2175bf475f30 324 killplayer(clock);
TheChrisyd 0:2175bf475f30 325 break;
TheChrisyd 0:2175bf475f30 326 case HANDLE_MISSILE:
TheChrisyd 0:2175bf475f30 327 expire(&missiles, po->collide); // missile is dead
TheChrisyd 0:2175bf475f30 328 expire(&enemies, i);
TheChrisyd 0:2175bf475f30 329 return 1;
TheChrisyd 0:2175bf475f30 330 }
TheChrisyd 0:2175bf475f30 331 }
TheChrisyd 0:2175bf475f30 332 return 0;
TheChrisyd 0:2175bf475f30 333 }
TheChrisyd 0:2175bf475f30 334
TheChrisyd 0:2175bf475f30 335 static void handle_rock0(byte i, byte state, uint16_t clock) {
TheChrisyd 0:2175bf475f30 336 struct object *po = &objects[i];
TheChrisyd 0:2175bf475f30 337 byte speed = 12 + (po->state & 7);
TheChrisyd 0:2175bf475f30 338 if (commonrock(clock, i, speed, draw_rock0r)) {
TheChrisyd 0:2175bf475f30 339 explodehere(po, HANDLE_BANG0, clock);
TheChrisyd 0:2175bf475f30 340 score += 10;
TheChrisyd 0:2175bf475f30 341 sounds.pop = 1;
TheChrisyd 0:2175bf475f30 342 }
TheChrisyd 0:2175bf475f30 343 }
TheChrisyd 0:2175bf475f30 344
TheChrisyd 0:2175bf475f30 345 static void handle_rock1(byte i, byte state, uint16_t clock) {
TheChrisyd 0:2175bf475f30 346 struct object *po = &objects[i];
TheChrisyd 0:2175bf475f30 347 byte speed = 6 + (po->state & 3);
TheChrisyd 0:2175bf475f30 348 if (commonrock(clock, i, speed, draw_rock1r)) {
TheChrisyd 0:2175bf475f30 349 int j;
TheChrisyd 0:2175bf475f30 350 for (j = 0; j < 4; j++) {
TheChrisyd 0:2175bf475f30 351 char e = pop(&enemies);
TheChrisyd 0:2175bf475f30 352 if (0 < e) {
TheChrisyd 0:2175bf475f30 353 objects[e].x = po->x;
TheChrisyd 0:2175bf475f30 354 objects[e].y = po->y;
TheChrisyd 0:2175bf475f30 355 objects[e].handler = HANDLE_ROCK0;
TheChrisyd 0:2175bf475f30 356 objects[e].state = (j << 6) + qrand(6); // spread fragments across 4 quadrants
TheChrisyd 0:2175bf475f30 357 }
TheChrisyd 0:2175bf475f30 358 }
TheChrisyd 0:2175bf475f30 359 explodehere(po, HANDLE_BANG1, clock);
TheChrisyd 0:2175bf475f30 360 score += 30;
TheChrisyd 0:2175bf475f30 361 sounds.boom = 1;
TheChrisyd 0:2175bf475f30 362 }
TheChrisyd 0:2175bf475f30 363 }
TheChrisyd 0:2175bf475f30 364
TheChrisyd 0:2175bf475f30 365 static void handle_bang0(byte i, byte state, uint16_t clock) {
TheChrisyd 0:2175bf475f30 366 struct object *po = &objects[i];
TheChrisyd 0:2175bf475f30 367 move(po, 0, 0);
TheChrisyd 0:2175bf475f30 368 byte anim = ((0xff & clock) - state) >> 1;
TheChrisyd 0:2175bf475f30 369 if (anim < EXPLODE16_FRAMES)
TheChrisyd 0:2175bf475f30 370 draw_explode16(po->x >> 4, po->y >> 4, anim, 0);
TheChrisyd 0:2175bf475f30 371 else
TheChrisyd 0:2175bf475f30 372 expire(&explosions, i);
TheChrisyd 0:2175bf475f30 373 }
TheChrisyd 0:2175bf475f30 374
TheChrisyd 0:2175bf475f30 375 static void handle_bang1(byte i, byte state, uint16_t clock) {
TheChrisyd 0:2175bf475f30 376 struct object *po = &objects[i];
TheChrisyd 0:2175bf475f30 377 move(po, 0, 0);
TheChrisyd 0:2175bf475f30 378 byte anim = ((0xff & clock) - state) >> 1;
TheChrisyd 0:2175bf475f30 379 byte rot = 7 & i;
TheChrisyd 0:2175bf475f30 380 if (anim < EXPLODE32_FRAMES)
TheChrisyd 0:2175bf475f30 381 draw_explode32(po->x >> 4, po->y >> 4, anim, rot);
TheChrisyd 0:2175bf475f30 382 else
TheChrisyd 0:2175bf475f30 383 expire(&explosions, i);
TheChrisyd 0:2175bf475f30 384 }
TheChrisyd 0:2175bf475f30 385
TheChrisyd 0:2175bf475f30 386 typedef void (*handler)(byte, byte, uint16_t);
TheChrisyd 0:2175bf475f30 387 static handler handlers[] = {
TheChrisyd 0:2175bf475f30 388 handle_null,
TheChrisyd 0:2175bf475f30 389 handle_rock0,
TheChrisyd 0:2175bf475f30 390 handle_rock1,
TheChrisyd 0:2175bf475f30 391 handle_bang0,
TheChrisyd 0:2175bf475f30 392 handle_bang1,
TheChrisyd 0:2175bf475f30 393 handle_player,
TheChrisyd 0:2175bf475f30 394 handle_missile
TheChrisyd 0:2175bf475f30 395 };
TheChrisyd 0:2175bf475f30 396
TheChrisyd 0:2175bf475f30 397
TheChrisyd 0:2175bf475f30 398 // uncompress one line of the title banner into buffer dst
TheChrisyd 0:2175bf475f30 399 // title banner lines are run-length encoded
TheChrisyd 0:2175bf475f30 400 static void titlepaint(char *dst, byte src, byte mask) {
TheChrisyd 0:2175bf475f30 401 if (src != 0xff) {
TheChrisyd 0:2175bf475f30 402 PROGMEM prog_uchar *psrc = title_runs + 2 * src;
TheChrisyd 0:2175bf475f30 403 byte a, b;
TheChrisyd 0:2175bf475f30 404 do {
TheChrisyd 0:2175bf475f30 405 a = *psrc++;
TheChrisyd 0:2175bf475f30 406 b = *psrc++;
TheChrisyd 0:2175bf475f30 407 while (a < (b & 0x7f))
TheChrisyd 0:2175bf475f30 408 dst[a++] |= mask;
TheChrisyd 0:2175bf475f30 409 } while (!(b & 0x80));
TheChrisyd 0:2175bf475f30 410 }
TheChrisyd 0:2175bf475f30 411 }
TheChrisyd 0:2175bf475f30 412
TheChrisyd 0:2175bf475f30 413 // draw a title banner column src (0-511) to screen column dst (0-63).
TheChrisyd 0:2175bf475f30 414 static void column(byte dst, byte src) {
TheChrisyd 0:2175bf475f30 415 static char scratch[76];
TheChrisyd 0:2175bf475f30 416 memset(scratch, 0, sizeof(scratch));
TheChrisyd 0:2175bf475f30 417 //PROGMEM prog_uchar* titleadd = title + 2 * src;
TheChrisyd 0:2175bf475f30 418 prog_uchar line = title[2 * src];//*titleadd++;//pgm_read_byte_near(title + 2 * src);
TheChrisyd 0:2175bf475f30 419 titlepaint(scratch, line, 1);
TheChrisyd 0:2175bf475f30 420 line = title[2 * src+1];//*titleadd;//pgm_read_byte_near(title + 2 * src + 1);
TheChrisyd 0:2175bf475f30 421 titlepaint(scratch, line, 2);
TheChrisyd 0:2175bf475f30 422
TheChrisyd 0:2175bf475f30 423 byte j;
TheChrisyd 0:2175bf475f30 424 for (j = 0; j < 38; j++) {
TheChrisyd 0:2175bf475f30 425 GD.wr(dst + (j << 6),
TheChrisyd 0:2175bf475f30 426 (((dst + j) & 15) << 4) +
TheChrisyd 0:2175bf475f30 427 scratch[2 * j] +
TheChrisyd 0:2175bf475f30 428 (scratch[2 * j + 1] << 2));
TheChrisyd 0:2175bf475f30 429 }
TheChrisyd 0:2175bf475f30 430 }
TheChrisyd 0:2175bf475f30 431
TheChrisyd 0:2175bf475f30 432 static void setup_sprites() {
TheChrisyd 0:2175bf475f30 433 GD.copy(PALETTE16A, palette16a, sizeof(palette16a));
TheChrisyd 0:2175bf475f30 434 GD.copy(PALETTE4A, palette4a, sizeof(palette4a));
TheChrisyd 0:2175bf475f30 435 GD.copy(PALETTE16B, palette16b, sizeof(palette16b));
TheChrisyd 0:2175bf475f30 436
TheChrisyd 0:2175bf475f30 437 // Use the first two 256-color palettes as pseudo-16 color palettes
TheChrisyd 0:2175bf475f30 438 int i;
TheChrisyd 0:2175bf475f30 439 for (i = 0; i < 256; i++) {
TheChrisyd 0:2175bf475f30 440
TheChrisyd 0:2175bf475f30 441 // palette 0 decodes low nibble, hence (i & 15)
TheChrisyd 0:2175bf475f30 442 //PROGMEM prog_uchar* pallow = palette256a + ((i & 15) << 1);
TheChrisyd 0:2175bf475f30 443 uint16_t rgb = palette256a[((i & 15) << 1)];
TheChrisyd 0:2175bf475f30 444 GD.wr16(RAM_SPRPAL + (i << 1), rgb);
TheChrisyd 0:2175bf475f30 445
TheChrisyd 0:2175bf475f30 446 // palette 1 decodes nigh nibble, hence (i >> 4)
TheChrisyd 0:2175bf475f30 447 //PROGMEM prog_uchar* palhigh = palette256a + ((i >> 4) << 1);
TheChrisyd 0:2175bf475f30 448 rgb = palette256a[((i >> 4) << 1)];
TheChrisyd 0:2175bf475f30 449 GD.wr16(RAM_SPRPAL + 512 + (i << 1), rgb);
TheChrisyd 0:2175bf475f30 450 }
TheChrisyd 0:2175bf475f30 451
TheChrisyd 0:2175bf475f30 452 GD.uncompress(RAM_SPRIMG, asteroid_images_compressed);
TheChrisyd 0:2175bf475f30 453 GD.wr(JK_MODE, 1);
TheChrisyd 0:2175bf475f30 454 }
TheChrisyd 0:2175bf475f30 455
TheChrisyd 0:2175bf475f30 456 // Run the object handlers, keeping track of sprite ownership in spr2obj
TheChrisyd 0:2175bf475f30 457 static void runobjects(uint16_t r) {
TheChrisyd 0:2175bf475f30 458 int i;
TheChrisyd 0:2175bf475f30 459 GD.__wstartspr(((r & 1) ? 256 : 0)); // write sprites to other frame
TheChrisyd 0:2175bf475f30 460 for (i = 0; i < 128; i++) {
TheChrisyd 0:2175bf475f30 461 struct object *po = &objects[i];
TheChrisyd 0:2175bf475f30 462 handler h = (handler)handlers[po->handler];
TheChrisyd 0:2175bf475f30 463 byte loSpr = GD.spr;
TheChrisyd 0:2175bf475f30 464 (*h)(i, po->state, r);
TheChrisyd 0:2175bf475f30 465 while (loSpr < GD.spr) {
TheChrisyd 0:2175bf475f30 466 spr2obj[loSpr++] = i;
TheChrisyd 0:2175bf475f30 467 }
TheChrisyd 0:2175bf475f30 468 }
TheChrisyd 0:2175bf475f30 469 // Hide all the remaining sprites
TheChrisyd 0:2175bf475f30 470 do
TheChrisyd 0:2175bf475f30 471 GD.xhide();
TheChrisyd 0:2175bf475f30 472 while (GD.spr);
TheChrisyd 0:2175bf475f30 473 GD.__end();
TheChrisyd 0:2175bf475f30 474 }
TheChrisyd 0:2175bf475f30 475
TheChrisyd 0:2175bf475f30 476 // ----------------------------------------------------------------------
TheChrisyd 0:2175bf475f30 477 // map
TheChrisyd 0:2175bf475f30 478 // ----------------------------------------------------------------------
TheChrisyd 0:2175bf475f30 479
TheChrisyd 0:2175bf475f30 480 static byte loaded[8];
TheChrisyd 0:2175bf475f30 481 static byte scrap;
TheChrisyd 0:2175bf475f30 482
TheChrisyd 0:2175bf475f30 483 // copy a (w,h) rectangle from the source image (x,y) into picture RAM
TheChrisyd 0:2175bf475f30 484 static void rect(unsigned int dst, byte x, byte y, byte w, byte h) {
TheChrisyd 0:2175bf475f30 485 PROGMEM prog_uchar *src = bg_pic + (16 * y) + x;
TheChrisyd 0:2175bf475f30 486 while (h--) {
TheChrisyd 0:2175bf475f30 487 GD.copy(dst, src, w);
TheChrisyd 0:2175bf475f30 488 dst += 64;
TheChrisyd 0:2175bf475f30 489 src += 16;
TheChrisyd 0:2175bf475f30 490 }
TheChrisyd 0:2175bf475f30 491 }
TheChrisyd 0:2175bf475f30 492
TheChrisyd 0:2175bf475f30 493 static void map_draw(byte strip) {
TheChrisyd 0:2175bf475f30 494 strip &= 63; // Universe is finite but unbounded: 64 strips
TheChrisyd 0:2175bf475f30 495 byte s8 = (strip & 7); // Destination slot for this strip (0-7)
TheChrisyd 0:2175bf475f30 496 if (loaded[s8] != strip) {
TheChrisyd 0:2175bf475f30 497 qrandSeed(level ^ (strip * 77)); // strip number is the hash...
TheChrisyd 0:2175bf475f30 498
TheChrisyd 0:2175bf475f30 499 // Random star pattern is made from characters 1-15
TheChrisyd 0:2175bf475f30 500 GD.__wstart(s8 * (8 * 64));
TheChrisyd 0:2175bf475f30 501 int i;
TheChrisyd 0:2175bf475f30 502 for (i = 0; i < (8 * 64); i++) {
TheChrisyd 0:2175bf475f30 503 byte r;
TheChrisyd 0:2175bf475f30 504 if (qrand(3) == 0)
TheChrisyd 0:2175bf475f30 505 r = qrand(4);
TheChrisyd 0:2175bf475f30 506 else
TheChrisyd 0:2175bf475f30 507 r = 0;
TheChrisyd 0:2175bf475f30 508 spimain.write(r);
TheChrisyd 0:2175bf475f30 509 }
TheChrisyd 0:2175bf475f30 510 GD.__end();
TheChrisyd 0:2175bf475f30 511
TheChrisyd 0:2175bf475f30 512 // Occasional planet, copied from the background char map
TheChrisyd 0:2175bf475f30 513 if (qrand(2) == 0) {
TheChrisyd 0:2175bf475f30 514 uint16_t dst = (qrand(3) * 8) + (s8 * (8 * 64));
TheChrisyd 0:2175bf475f30 515 switch (qrand(2)) {
TheChrisyd 0:2175bf475f30 516 case 0:
TheChrisyd 0:2175bf475f30 517 rect(dst, 0, 1, 6, 6);
TheChrisyd 0:2175bf475f30 518 break;
TheChrisyd 0:2175bf475f30 519 case 1:
TheChrisyd 0:2175bf475f30 520 rect(dst, 7, 1, 6, 6);
TheChrisyd 0:2175bf475f30 521 break;
TheChrisyd 0:2175bf475f30 522 case 2:
TheChrisyd 0:2175bf475f30 523 rect(dst, 0, 7, 8, 4);
TheChrisyd 0:2175bf475f30 524 break;
TheChrisyd 0:2175bf475f30 525 case 3:
TheChrisyd 0:2175bf475f30 526 rect(dst, 8, 7, 5, 5);
TheChrisyd 0:2175bf475f30 527 break;
TheChrisyd 0:2175bf475f30 528 }
TheChrisyd 0:2175bf475f30 529 }
TheChrisyd 0:2175bf475f30 530 loaded[s8] = strip;
TheChrisyd 0:2175bf475f30 531 }
TheChrisyd 0:2175bf475f30 532 }
TheChrisyd 0:2175bf475f30 533
TheChrisyd 0:2175bf475f30 534 static void map_coldstart() {
TheChrisyd 0:2175bf475f30 535 memset(loaded, 0xff, sizeof(loaded));
TheChrisyd 0:2175bf475f30 536 scrap = 0xff;
TheChrisyd 0:2175bf475f30 537 byte i;
TheChrisyd 0:2175bf475f30 538 for (i = 0; i < 8; i++)
TheChrisyd 0:2175bf475f30 539 map_draw(i);
TheChrisyd 0:2175bf475f30 540 }
TheChrisyd 0:2175bf475f30 541
TheChrisyd 0:2175bf475f30 542 static int atxy(int x, int y) {
TheChrisyd 0:2175bf475f30 543 return (y << 6) + x;
TheChrisyd 0:2175bf475f30 544 }
TheChrisyd 0:2175bf475f30 545
TheChrisyd 0:2175bf475f30 546 static void update_score() {
TheChrisyd 0:2175bf475f30 547 unsigned long s = score;
TheChrisyd 0:2175bf475f30 548 uint16_t a = atxy(49, scrap << 3);
TheChrisyd 0:2175bf475f30 549 byte i;
TheChrisyd 0:2175bf475f30 550 //void* code;
TheChrisyd 0:2175bf475f30 551 for (i = 0; i < 6; i++) {
TheChrisyd 0:2175bf475f30 552 PROGMEM prog_uchar* digitcodes = (bg_pic + (16 * 30))+(s % 10);
TheChrisyd 0:2175bf475f30 553
TheChrisyd 0:2175bf475f30 554 //code = &digitcodes + (s % 10);
TheChrisyd 0:2175bf475f30 555 GD.wr(a--, *digitcodes);//pgm_read_byte_near(digitcodes + (s % 10)) ;
TheChrisyd 0:2175bf475f30 556 s /= 10;
TheChrisyd 0:2175bf475f30 557 }
TheChrisyd 0:2175bf475f30 558 PROGMEM prog_uchar* digitcodes = bg_pic + (16 * 30) + lives;
TheChrisyd 0:2175bf475f30 559 //code = &digitcodes + lives;
TheChrisyd 0:2175bf475f30 560 GD.wr(atxy(0, scrap << 3), *digitcodes);// pgm_read_byte_near(digitcodes + lives));
TheChrisyd 0:2175bf475f30 561 }
TheChrisyd 0:2175bf475f30 562
TheChrisyd 0:2175bf475f30 563 static void map_refresh(byte strip) {
TheChrisyd 0:2175bf475f30 564 byte i;
TheChrisyd 0:2175bf475f30 565 byte newscrap = 7 & (strip + 7);
TheChrisyd 0:2175bf475f30 566 if (scrap != newscrap) {
TheChrisyd 0:2175bf475f30 567 scrap = newscrap;
TheChrisyd 0:2175bf475f30 568
TheChrisyd 0:2175bf475f30 569 uint16_t scrapline = scrap << 6;
TheChrisyd 0:2175bf475f30 570 GD.wr16(COMM+2, 0x8000 | scrapline); // show scrapline at line 0
TheChrisyd 0:2175bf475f30 571 GD.wr16(COMM+14, 0x8000 | (0x1ff & ((scrapline + 8) - 291))); // show scrapline+8 at line 291
TheChrisyd 0:2175bf475f30 572
TheChrisyd 0:2175bf475f30 573 GD.fill(atxy(0, scrap << 3), 0, 50);
TheChrisyd 0:2175bf475f30 574 update_score();
TheChrisyd 0:2175bf475f30 575
TheChrisyd 0:2175bf475f30 576 GD.fill(atxy(0, 1 + (scrap << 3)), 0, 64);
TheChrisyd 0:2175bf475f30 577 rect(atxy(0, 1 + (scrap << 3)), 0, 31, 16, 1);
TheChrisyd 0:2175bf475f30 578 rect(atxy(32, 1 + (scrap << 3)), 0, 31, 16, 1);
TheChrisyd 0:2175bf475f30 579
TheChrisyd 0:2175bf475f30 580 loaded[scrap] = 0xff;
TheChrisyd 0:2175bf475f30 581 }
TheChrisyd 0:2175bf475f30 582 wait_ms(1); // wait for raster to pass the top line before overwriting it
TheChrisyd 0:2175bf475f30 583 for (i = 0; i < 6; i++)
TheChrisyd 0:2175bf475f30 584 map_draw(strip + i);
TheChrisyd 0:2175bf475f30 585 }
TheChrisyd 0:2175bf475f30 586
TheChrisyd 0:2175bf475f30 587 static void start_level() {
TheChrisyd 0:2175bf475f30 588 int i;
TheChrisyd 0:2175bf475f30 589
TheChrisyd 0:2175bf475f30 590 for (i = 0; i < 128; i++)
TheChrisyd 0:2175bf475f30 591 objects[i].handler = 0;
TheChrisyd 0:2175bf475f30 592
TheChrisyd 0:2175bf475f30 593 player_vx = 0;
TheChrisyd 0:2175bf475f30 594 player_vy = 0;
TheChrisyd 0:2175bf475f30 595 player_invincible = 0;
TheChrisyd 0:2175bf475f30 596 player_dying = 0;
TheChrisyd 0:2175bf475f30 597
TheChrisyd 0:2175bf475f30 598 objects[0].x = 0;
TheChrisyd 0:2175bf475f30 599 objects[0].y = 0;
TheChrisyd 0:2175bf475f30 600 objects[0].state = 0;
TheChrisyd 0:2175bf475f30 601 objects[0].handler = HANDLE_PLAYER;
TheChrisyd 0:2175bf475f30 602
TheChrisyd 0:2175bf475f30 603 // Set up the pools of objects for missiles, enemies, explosions
TheChrisyd 0:2175bf475f30 604 missiles = 0;
TheChrisyd 0:2175bf475f30 605 enemies = 0;
TheChrisyd 0:2175bf475f30 606 explosions = 0;
TheChrisyd 0:2175bf475f30 607 for (i = 1; i < 16; i++)
TheChrisyd 0:2175bf475f30 608 push(&missiles, i);
TheChrisyd 0:2175bf475f30 609 for (i = 16; i < 80; i++)
TheChrisyd 0:2175bf475f30 610 push(&enemies, i);
TheChrisyd 0:2175bf475f30 611 for (i = 80; i < 128; i++)
TheChrisyd 0:2175bf475f30 612 push(&explosions, i);
TheChrisyd 0:2175bf475f30 613
TheChrisyd 0:2175bf475f30 614 // Place asteroids in a ring around the edges of the screen
TheChrisyd 0:2175bf475f30 615 int x;
TheChrisyd 0:2175bf475f30 616 if ((level + 3) < 32) {
TheChrisyd 0:2175bf475f30 617 x = level + 3;
TheChrisyd 0:2175bf475f30 618 } else {
TheChrisyd 0:2175bf475f30 619 x = 32;
TheChrisyd 0:2175bf475f30 620 }
TheChrisyd 0:2175bf475f30 621 for (i = 0; i < x; i++) {
TheChrisyd 0:2175bf475f30 622 char e = pop(&enemies);
TheChrisyd 0:2175bf475f30 623 if (rand()%2 == 0) {
TheChrisyd 0:2175bf475f30 624 objects[e].x = rand()%2 ? COORD(32) : COORD(400-32);
TheChrisyd 0:2175bf475f30 625 objects[e].y = rand()%COORD(300);
TheChrisyd 0:2175bf475f30 626 } else {
TheChrisyd 0:2175bf475f30 627 objects[e].x = rand()%COORD(400);
TheChrisyd 0:2175bf475f30 628 objects[e].y = rand()%2 ? COORD(32) : COORD(300-32);
TheChrisyd 0:2175bf475f30 629 }
TheChrisyd 0:2175bf475f30 630 objects[e].handler = HANDLE_ROCK1;
TheChrisyd 0:2175bf475f30 631 objects[e].state = qrand(8);
TheChrisyd 0:2175bf475f30 632 }
TheChrisyd 0:2175bf475f30 633
TheChrisyd 0:2175bf475f30 634 GD.copy(PALETTE16B, palette16b, sizeof(palette16b));
TheChrisyd 0:2175bf475f30 635 for (i = 0; i < 16; i++) {
TheChrisyd 0:2175bf475f30 636 uint16_t a = PALETTE16B + 2 * i;
TheChrisyd 0:2175bf475f30 637 uint16_t c = GD.rd16(a);
TheChrisyd 0:2175bf475f30 638 if (level & 1)
TheChrisyd 0:2175bf475f30 639 c = swapRB(c);
TheChrisyd 0:2175bf475f30 640 if (level & 2)
TheChrisyd 0:2175bf475f30 641 c = swapRG(c);
TheChrisyd 0:2175bf475f30 642 if (level & 4)
TheChrisyd 0:2175bf475f30 643 c = swapRB(c);
TheChrisyd 0:2175bf475f30 644 GD.wr16(a, c);
TheChrisyd 0:2175bf475f30 645 }
TheChrisyd 0:2175bf475f30 646
TheChrisyd 0:2175bf475f30 647 map_coldstart();
TheChrisyd 0:2175bf475f30 648 }
TheChrisyd 0:2175bf475f30 649
TheChrisyd 0:2175bf475f30 650 void setup() {
TheChrisyd 0:2175bf475f30 651
TheChrisyd 0:2175bf475f30 652 GD.begin();
TheChrisyd 0:2175bf475f30 653 controller_init();
TheChrisyd 0:2175bf475f30 654
TheChrisyd 0:2175bf475f30 655 }
TheChrisyd 0:2175bf475f30 656
TheChrisyd 0:2175bf475f30 657 static void title_banner() {
TheChrisyd 0:2175bf475f30 658 GD.fill(VOICES, 0, 64 * 4);
TheChrisyd 0:2175bf475f30 659 GD.wr(J1_RESET, 1);
TheChrisyd 0:2175bf475f30 660 GD.wr(SPR_DISABLE, 1);
TheChrisyd 0:2175bf475f30 661 GD.wr16(SCROLL_X, 0);
TheChrisyd 0:2175bf475f30 662 GD.wr16(SCROLL_Y, 0);
TheChrisyd 0:2175bf475f30 663 GD.fill(RAM_PIC, 0, 4096);
TheChrisyd 0:2175bf475f30 664 setup_sprites();
TheChrisyd 0:2175bf475f30 665
TheChrisyd 0:2175bf475f30 666 uint16_t i;
TheChrisyd 0:2175bf475f30 667 uint16_t j;
TheChrisyd 0:2175bf475f30 668
TheChrisyd 0:2175bf475f30 669 GD.__wstart(RAM_CHR);
TheChrisyd 0:2175bf475f30 670 for (i = 0; i < 256; i++) {
TheChrisyd 0:2175bf475f30 671 // bits control lit segments like this:
TheChrisyd 0:2175bf475f30 672 // 0 1
TheChrisyd 0:2175bf475f30 673 // 2 3
TheChrisyd 0:2175bf475f30 674 byte a = (i & 1) ? 0x3f : 0;
TheChrisyd 0:2175bf475f30 675 byte b = (i & 2) ? 0x3f : 0;
TheChrisyd 0:2175bf475f30 676 byte c = (i & 4) ? 0x3f : 0;
TheChrisyd 0:2175bf475f30 677 byte d = (i & 8) ? 0x3f : 0;
TheChrisyd 0:2175bf475f30 678 for (j = 0; j < 3; j++) {
TheChrisyd 0:2175bf475f30 679 spimain.write(a);
TheChrisyd 0:2175bf475f30 680 spimain.write(b);
TheChrisyd 0:2175bf475f30 681 }
TheChrisyd 0:2175bf475f30 682 spimain.write(0);
TheChrisyd 0:2175bf475f30 683 spimain.write(0);
TheChrisyd 0:2175bf475f30 684 for (j = 0; j < 3; j++) {
TheChrisyd 0:2175bf475f30 685 spimain.write(c);
TheChrisyd 0:2175bf475f30 686 spimain.write(d);
TheChrisyd 0:2175bf475f30 687 }
TheChrisyd 0:2175bf475f30 688 spimain.write(0);
TheChrisyd 0:2175bf475f30 689 spimain.write(0);
TheChrisyd 0:2175bf475f30 690 }
TheChrisyd 0:2175bf475f30 691
TheChrisyd 0:2175bf475f30 692 GD.__end();
TheChrisyd 0:2175bf475f30 693
TheChrisyd 0:2175bf475f30 694 for (i = 0; i < 256; i++) {
TheChrisyd 0:2175bf475f30 695 GD.setpal(4 * i + 0, RGB(0,0,0));
TheChrisyd 0:2175bf475f30 696 //prog_uchar* colptr = title_ramp + 2 * (i >> 4);
TheChrisyd 0:2175bf475f30 697 prog_uchar color = title_ramp[(i >> 4)];//pgm_read_word_near(title_ramp + 2 * (i >> 4));
TheChrisyd 0:2175bf475f30 698 GD.setpal(4 * i + 3, color);
TheChrisyd 0:2175bf475f30 699 }
TheChrisyd 0:2175bf475f30 700
TheChrisyd 0:2175bf475f30 701 for (i = 0; i < 64; i++) {
TheChrisyd 0:2175bf475f30 702 column(i, i);
TheChrisyd 0:2175bf475f30 703 }
TheChrisyd 0:2175bf475f30 704
TheChrisyd 0:2175bf475f30 705 for (i = 0; i < 128; i++) {
TheChrisyd 0:2175bf475f30 706 objects[i].handler = 0;
TheChrisyd 0:2175bf475f30 707 objects[i].collide = 0xff;
TheChrisyd 0:2175bf475f30 708 }
TheChrisyd 0:2175bf475f30 709
TheChrisyd 0:2175bf475f30 710 for (i = 0; i < 128; i++)
TheChrisyd 0:2175bf475f30 711 push(&enemies, i);
TheChrisyd 0:2175bf475f30 712
TheChrisyd 0:2175bf475f30 713 for (i = 0; i < 40; i++) {
TheChrisyd 0:2175bf475f30 714 char e = pop(&enemies);
TheChrisyd 0:2175bf475f30 715 objects[e].x = COORD(rand()%400);
TheChrisyd 0:2175bf475f30 716 objects[e].y = COORD(rand()%300);
TheChrisyd 0:2175bf475f30 717 objects[e].handler = qrand1() ? HANDLE_ROCK1 : HANDLE_ROCK0;
TheChrisyd 0:2175bf475f30 718 objects[e].state = qrand(8);
TheChrisyd 0:2175bf475f30 719 }
TheChrisyd 0:2175bf475f30 720
TheChrisyd 0:2175bf475f30 721 byte startgame = 0;
TheChrisyd 0:2175bf475f30 722 for (i = 0; startgame < 50; i++) {
TheChrisyd 0:2175bf475f30 723 for (j = 0; j < 256; j++) {
TheChrisyd 0:2175bf475f30 724 byte index = 15 & ((-i >> 2) + (j >> 4));
TheChrisyd 0:2175bf475f30 725 prog_uchar* colour = title_ramp + 2 * index;
TheChrisyd 0:2175bf475f30 726 prog_uchar color = *colour;// pgm_read_word_near(title_ramp + 2 * index);
TheChrisyd 0:2175bf475f30 727 GD.setpal(4 * j + 3, color);
TheChrisyd 0:2175bf475f30 728 }
TheChrisyd 0:2175bf475f30 729
TheChrisyd 0:2175bf475f30 730 if (!startgame &&
TheChrisyd 0:2175bf475f30 731 (controller_sense(i) || (i == (2048 - 400)))) {
TheChrisyd 0:2175bf475f30 732 // explode all rocks!
TheChrisyd 0:2175bf475f30 733 for (j = 0; j < 128; j++) {
TheChrisyd 0:2175bf475f30 734 byte h = objects[j].handler;
TheChrisyd 0:2175bf475f30 735 if ((h == HANDLE_ROCK0) || (h == HANDLE_ROCK1))
TheChrisyd 0:2175bf475f30 736 objects[j].handler = HANDLE_BANG1;
TheChrisyd 0:2175bf475f30 737 objects[j].state = i;
TheChrisyd 0:2175bf475f30 738 }
TheChrisyd 0:2175bf475f30 739 startgame = 1;
TheChrisyd 0:2175bf475f30 740 }
TheChrisyd 0:2175bf475f30 741
TheChrisyd 0:2175bf475f30 742 if (startgame){
TheChrisyd 0:2175bf475f30 743 startgame++;
TheChrisyd 0:2175bf475f30 744 }
TheChrisyd 0:2175bf475f30 745
TheChrisyd 0:2175bf475f30 746 //runobjects(i);
TheChrisyd 0:2175bf475f30 747
TheChrisyd 0:2175bf475f30 748 GD.waitvblank();
TheChrisyd 0:2175bf475f30 749 GD.wr(SPR_PAGE, (i & 1));
TheChrisyd 0:2175bf475f30 750 GD.wr(SPR_DISABLE, 0);
TheChrisyd 0:2175bf475f30 751 GD.wr16(SCROLL_X, i);
TheChrisyd 0:2175bf475f30 752 if ((i & 7) == 0) {
TheChrisyd 0:2175bf475f30 753 byte x = ((i >> 3) + 56);
TheChrisyd 0:2175bf475f30 754 column(63 & x, 255 & x);
TheChrisyd 0:2175bf475f30 755 }
TheChrisyd 0:2175bf475f30 756 }
TheChrisyd 0:2175bf475f30 757
TheChrisyd 0:2175bf475f30 758 for (i = 0; i < 32; i++) {
TheChrisyd 0:2175bf475f30 759 for (j = 0; j < 256; j++) {
TheChrisyd 0:2175bf475f30 760 uint16_t a = RAM_PAL + (8 * j) + 6;
TheChrisyd 0:2175bf475f30 761 uint16_t pal = GD.rd16(a);
TheChrisyd 0:2175bf475f30 762 byte r = 31 & (pal >> 10);
TheChrisyd 0:2175bf475f30 763 byte g = 31 & (pal >> 5);
TheChrisyd 0:2175bf475f30 764 byte b = 31 & pal;
TheChrisyd 0:2175bf475f30 765 if (r) r--;
TheChrisyd 0:2175bf475f30 766 if (g) g--;
TheChrisyd 0:2175bf475f30 767 if (b) b--;
TheChrisyd 0:2175bf475f30 768 pal = (r << 10) | (g << 5) | b;
TheChrisyd 0:2175bf475f30 769 GD.wr16(a, pal);
TheChrisyd 0:2175bf475f30 770 }
TheChrisyd 0:2175bf475f30 771 GD.waitvblank();
TheChrisyd 0:2175bf475f30 772 GD.waitvblank();
TheChrisyd 0:2175bf475f30 773
TheChrisyd 0:2175bf475f30 774 }
TheChrisyd 0:2175bf475f30 775
TheChrisyd 0:2175bf475f30 776 GD.fill(RAM_PIC, 0, 4096);
TheChrisyd 0:2175bf475f30 777
TheChrisyd 0:2175bf475f30 778 }
TheChrisyd 0:2175bf475f30 779
TheChrisyd 0:2175bf475f30 780 #define SOUNDCYCLE(state) ((state) = v ? ((state) + 1) : 0)
TheChrisyd 0:2175bf475f30 781
TheChrisyd 0:2175bf475f30 782 int main() {
TheChrisyd 0:2175bf475f30 783
TheChrisyd 0:2175bf475f30 784 setup();
TheChrisyd 0:2175bf475f30 785 while (1) {
TheChrisyd 0:2175bf475f30 786
TheChrisyd 0:2175bf475f30 787 title_banner();
TheChrisyd 0:2175bf475f30 788
TheChrisyd 0:2175bf475f30 789 GD.uncompress(RAM_CHR, bg_chr_compressed);
TheChrisyd 0:2175bf475f30 790 GD.uncompress(RAM_PAL, bg_pal_compressed);
TheChrisyd 0:2175bf475f30 791
TheChrisyd 0:2175bf475f30 792 GD.wr16(COMM+0, 0);
TheChrisyd 0:2175bf475f30 793 GD.wr16(COMM+2, 0x8000);
TheChrisyd 0:2175bf475f30 794 GD.wr16(COMM+4, 8); // split at line 8
TheChrisyd 0:2175bf475f30 795 GD.wr16(COMM+6, 177);
TheChrisyd 0:2175bf475f30 796 GD.wr16(COMM+8, 166);
TheChrisyd 0:2175bf475f30 797 GD.wr16(COMM+10, 291); // split at line 291
TheChrisyd 0:2175bf475f30 798 GD.wr16(COMM+12, 0);
TheChrisyd 0:2175bf475f30 799 GD.wr16(COMM+14, 0x8000 | (0x1ff & (8 - 291))); // show line 8 at line 292
TheChrisyd 0:2175bf475f30 800 GD.microcode(splitscreen_code, sizeof(splitscreen_code));
TheChrisyd 0:2175bf475f30 801
TheChrisyd 0:2175bf475f30 802 setup_sprites();
TheChrisyd 0:2175bf475f30 803
TheChrisyd 0:2175bf475f30 804
TheChrisyd 0:2175bf475f30 805 memset(&sounds, 0, sizeof(sounds));
TheChrisyd 0:2175bf475f30 806 level = 0;
TheChrisyd 0:2175bf475f30 807 score = 0;
TheChrisyd 0:2175bf475f30 808 lives = 3;
TheChrisyd 0:2175bf475f30 809 unsigned int r = 0;
TheChrisyd 0:2175bf475f30 810 start_level();
TheChrisyd 0:2175bf475f30 811
TheChrisyd 0:2175bf475f30 812 while (lives) {
TheChrisyd 0:2175bf475f30 813 int i;//, j;
TheChrisyd 0:2175bf475f30 814
TheChrisyd 0:2175bf475f30 815 runobjects(r);
TheChrisyd 0:2175bf475f30 816
TheChrisyd 0:2175bf475f30 817 for (i = 0; i < 128; i++)
TheChrisyd 0:2175bf475f30 818 objects[i].collide = 0xff;
TheChrisyd 0:2175bf475f30 819
TheChrisyd 0:2175bf475f30 820 GD.waitvblank();
TheChrisyd 0:2175bf475f30 821 // swap frames
TheChrisyd 0:2175bf475f30 822 GD.wr(SPR_PAGE, (r & 1));
TheChrisyd 0:2175bf475f30 823 int scrollx = objects[0].x >> 4;
TheChrisyd 0:2175bf475f30 824 int scrolly = objects[0].y >> 4;
TheChrisyd 0:2175bf475f30 825 GD.wr16(COMM+6, scrollx & 0x1ff);
TheChrisyd 0:2175bf475f30 826 GD.wr16(COMM+8, scrolly & 0x1ff);
TheChrisyd 0:2175bf475f30 827 map_refresh(scrolly >> 6);
TheChrisyd 0:2175bf475f30 828 update_score();
TheChrisyd 0:2175bf475f30 829 GD.wr16(COMM+12, r); // horizontal scroll the bottom banner
TheChrisyd 0:2175bf475f30 830
TheChrisyd 0:2175bf475f30 831 GD.waitvblank();
TheChrisyd 0:2175bf475f30 832
TheChrisyd 0:2175bf475f30 833 GD.__start(COLLISION);
TheChrisyd 0:2175bf475f30 834 for (i = 0; i < 256; i++) {
TheChrisyd 0:2175bf475f30 835 byte c = spimain.write(0); // c is the colliding sprite number
TheChrisyd 0:2175bf475f30 836 if (c != 0xff) {
TheChrisyd 0:2175bf475f30 837 objects[spr2obj[i]].collide = spr2obj[c];
TheChrisyd 0:2175bf475f30 838 }
TheChrisyd 0:2175bf475f30 839 }
TheChrisyd 0:2175bf475f30 840 GD.__end();
TheChrisyd 0:2175bf475f30 841
TheChrisyd 0:2175bf475f30 842 if (sounds.boing) {
TheChrisyd 0:2175bf475f30 843 byte x;
TheChrisyd 0:2175bf475f30 844 if ((16 - (sounds.boing - 1) * 2) <0) {
TheChrisyd 0:2175bf475f30 845 x = 0;
TheChrisyd 0:2175bf475f30 846 } else {
TheChrisyd 0:2175bf475f30 847 x = 16 - (sounds.boing - 1) * 2;
TheChrisyd 0:2175bf475f30 848 }
TheChrisyd 0:2175bf475f30 849 byte v = x; //max(0, 16 - (sounds.boing - 1) * 2);
TheChrisyd 0:2175bf475f30 850 GD.voice(0, 0, 4 * 4000 - 700 * sounds.boing, v/2, v/2);
TheChrisyd 0:2175bf475f30 851 GD.voice(1, 1, 1000 - 100 * sounds.boing, v, v);
TheChrisyd 0:2175bf475f30 852 SOUNDCYCLE(sounds.boing);
TheChrisyd 0:2175bf475f30 853 }
TheChrisyd 0:2175bf475f30 854 if (sounds.boom) {
TheChrisyd 0:2175bf475f30 855 byte x;
TheChrisyd 0:2175bf475f30 856 if ((96 - (sounds.boom - 1) * 6) <0) {
TheChrisyd 0:2175bf475f30 857 x = 0;
TheChrisyd 0:2175bf475f30 858 } else {
TheChrisyd 0:2175bf475f30 859 x = 96 - (sounds.boom - 1) * 6;
TheChrisyd 0:2175bf475f30 860 }
TheChrisyd 0:2175bf475f30 861 byte v = x;//max(0, 96 - (sounds.boom - 1) * 6);
TheChrisyd 0:2175bf475f30 862 GD.voice(2, 0, 220, v, v);
TheChrisyd 0:2175bf475f30 863 GD.voice(3, 1, 220/8, v/2, v/2);
TheChrisyd 0:2175bf475f30 864 SOUNDCYCLE(sounds.boom);
TheChrisyd 0:2175bf475f30 865 }
TheChrisyd 0:2175bf475f30 866 if (sounds.pop) {
TheChrisyd 0:2175bf475f30 867 byte x;
TheChrisyd 0:2175bf475f30 868 if ((32 - (sounds.pop - 1) * 3) <0) {
TheChrisyd 0:2175bf475f30 869 x = 0;
TheChrisyd 0:2175bf475f30 870 } else {
TheChrisyd 0:2175bf475f30 871 x = 32 - (sounds.pop - 1) * 3;
TheChrisyd 0:2175bf475f30 872 }
TheChrisyd 0:2175bf475f30 873 byte v = x;//max(0, 32 - (sounds.pop - 1) * 3);
TheChrisyd 0:2175bf475f30 874 GD.voice(4, 0, 440, v, v);
TheChrisyd 0:2175bf475f30 875 GD.voice(5, 1, 440/8, v/2, v/2);
TheChrisyd 0:2175bf475f30 876 SOUNDCYCLE(sounds.pop);
TheChrisyd 0:2175bf475f30 877 }
TheChrisyd 0:2175bf475f30 878 GD.voice(6, 1, 40, sounds.thrust ? 10 : 0, sounds.thrust ? 10 : 0);
TheChrisyd 0:2175bf475f30 879
TheChrisyd 0:2175bf475f30 880 static byte tune;
TheChrisyd 0:2175bf475f30 881 if (sounds.bass) {
TheChrisyd 0:2175bf475f30 882 byte v = sounds.bass < 9 ? 63 : 0;
TheChrisyd 0:2175bf475f30 883 int f0 = tune ? 130: 163 ;
TheChrisyd 0:2175bf475f30 884 byte partials[] = { 71, 32, 14, 75, 20, 40 };
TheChrisyd 0:2175bf475f30 885 byte i;
TheChrisyd 0:2175bf475f30 886 for (i = 0; i < 6; i++) {
TheChrisyd 0:2175bf475f30 887 byte a = (v * partials[i]) >> 8;
TheChrisyd 0:2175bf475f30 888 GD.voice(7 + i, 0, f0 * (i + 1), a, a);
TheChrisyd 0:2175bf475f30 889 }
TheChrisyd 0:2175bf475f30 890 SOUNDCYCLE(sounds.bass);
TheChrisyd 0:2175bf475f30 891 }
TheChrisyd 0:2175bf475f30 892 static byte rhythm;
TheChrisyd 0:2175bf475f30 893 byte x;
TheChrisyd 0:2175bf475f30 894 if ((24 - level) <10) {
TheChrisyd 0:2175bf475f30 895 x = 10;
TheChrisyd 0:2175bf475f30 896 } else {
TheChrisyd 0:2175bf475f30 897 x = 24 - level;
TheChrisyd 0:2175bf475f30 898 }
TheChrisyd 0:2175bf475f30 899 if (++rhythm >= x) {
TheChrisyd 0:2175bf475f30 900 sounds.bass = 1;
TheChrisyd 0:2175bf475f30 901 rhythm = 0;
TheChrisyd 0:2175bf475f30 902 tune = !tune;
TheChrisyd 0:2175bf475f30 903 }
TheChrisyd 0:2175bf475f30 904
TheChrisyd 0:2175bf475f30 905 byte nenemies = 64;
TheChrisyd 0:2175bf475f30 906 byte pe = enemies;
TheChrisyd 0:2175bf475f30 907 while (pe) {
TheChrisyd 0:2175bf475f30 908 pe = objects[pe].state;
TheChrisyd 0:2175bf475f30 909 nenemies--;
TheChrisyd 0:2175bf475f30 910 }
TheChrisyd 0:2175bf475f30 911 if (nenemies == 0) {
TheChrisyd 0:2175bf475f30 912 level++;
TheChrisyd 0:2175bf475f30 913 start_level();
TheChrisyd 0:2175bf475f30 914 }
TheChrisyd 0:2175bf475f30 915
TheChrisyd 0:2175bf475f30 916 r++;
TheChrisyd 0:2175bf475f30 917 }
TheChrisyd 0:2175bf475f30 918 }
TheChrisyd 0:2175bf475f30 919 }