/* *-------------------------------------- * Program Name: 20,000 LOONS UNDER THE SEA * Author: Rodger "Iambian" Weisman * License: BSD (See LICENSE file) * Description: Deliver the package in a submarine *-------------------------------------- */ #define VERSION_INFO "v0.1" #define TRANSPARENT_COLOR 0xF8 #define GREETINGS_DIALOG_TEXT_COLOR 0xDF #define BULLET_TABLE_SIZE 512 #define ENEMY_TABLE_SIZE 32 #define GM_TITLE 0 #define GM_OPENANIM 1 #define GM_GAMEMODE 2 #define GM_CLOSINGANIM 3 #define GM_DYING 4 #define GM_GAMEOVER 5 #define GM_OUTPOSTSHOP 6 #define GM_RETURNTOBASE 7 #define PB_BASICWEAPON 0 #define PB_SPREADSHOT 1 #define BT_TORPEDO 1 #define BT_BUBBLES 2 #define BT_EXPLOSION1 3 #define BT_EXPLOSION2 4 #define BT_WHITEBALL 5 #define BT_SPREADTORPEDO 6 #define GMBOX_X (LCD_WIDTH/4) #define GMBOX_Y (LCD_HEIGHT/2-LCD_HEIGHT/8) #define GMBOX_W (LCD_WIDTH/2) #define GMBOX_H (LCD_HEIGHT/4) #define ACCELFACTOR ((int)(0.07*256)) /* Standard headers (recommended) */ #include #include #include #include /* External library headers */ #include #include #include #include #include #include #include "main.h" #include "stage.h" #include "enemy.h" #include "gfx/loonsub_gfx.h" #include "gfx/propeller_gfx.h" #include "gfx/torpedo_gfx.h" #include "gfx/bubbles_gfx.h" #include "gfx/enemy_gfx.h" #include "gfx/explosion1_gfx.h" #include "gfx/explosion2_gfx.h" #include "gfx/bullets_gfx.h" #include "gfx/outpost_gfx.h" #include "gfx/shop_gfx.h" union fp16_8 { int fp; struct { uint8_t fpart; int16_t ipart; } p; } curx,cury,dx,dy,maxspeed; typedef struct bullet_t { uint8_t id; int x; int y; int dx; int dy; uint8_t power; int temp; } bullet_t; bullet_t emptybullet,newbullet,bullets[BULLET_TABLE_SIZE]; //enemy_t typedef in enemy.h enemy_t emptyenemy,testenemy; enemy_t enemies[ENEMY_TABLE_SIZE]; const char *gameoverdesc[] = {"Your loon drowned","Delivery failure","The sub sprung a leak","You had only one job"}; const char *gameovertext = "Game Over"; const char *gamestart1 = "Received package!"; const char *gamestart2 = "Get ready!"; const char *checkpoint1 = "Dropped off package!"; const char *checkpoint2 = "Got another package!"; const char *title1 = "Press [2nd] to start game"; const char *title2 = "Press [MODE] to quit"; const char *blankstr = " "; const char *getready = "Get ready!"; const char *goodluck = "Good luck!"; const char *arrival = "Arriving at outpost"; const char *shoptitle = "Outpost Shop"; const char *loontitle1 = "20,000 Loons"; const char *loontitle2 = "Under the Sea"; const char *loontitleA = "New Game"; const char *loontitleB = "Continue"; const char *loontitleC = "Quit"; const char *quitmode1 = "You returned to base"; const char *quitmode2 = "Game Saved"; const stage_t defaultstage[] = {S_ENDSTAGE}; const char *itemcost = "Cost: "; const int8_t floatmotion[32] = { 64, 49, 36, 25, 16, 9, 4, 1, -1, -4, -9,-16,-25,-36,-49,-64, -64,-49,-36,-25,-16, -9, -4, -1, 1 , 4, 9, 16, 25, 36, 49, 64 }; const int8_t costab_lofi[16] = { 127,118,91,48,0,-48,-91,-118, -127,-118,-91,-48,0,48,91,118}; //rawr. /* Put your function prototypes here */ void drawbg(); void drawloonsub(); void moveloonsub(); void movebullets(); void moveenemy(); void addbullet(bullet_t* bulletdata); void addenemy(enemy_t* enemydata); void drawbullets(); void drawenemy(); void collideenemy(bullet_t* bulletdata, int pierces); bool damageenemy(enemy_t* enemydata,bullet_t* bulletdata); void collideplayer(); void addbullethiteffect(bullet_t* bulletdata,int strikex,int strikey); void execstage(int reset); void drawoutpost(int xpos); //--- void mineexplode(enemy_t* enemydata); //--- void putaway(); void waitanykey(); void keywait(); void drawdebug(); void enemynullfunc(enemy_t *enemy_table); void centerxtext(char* strobj,int y); //--- void initgamestate(); void initgamevars(); bool buyitem(int cost); /* Put all your globals here */ int gamemode; int movefactor; int debugvalue; int maintimer; int playershotdelay; int playershotdelaymax; int playerweaponid; int curhp; int iframes; int shakecycles; int curstage; int gamerepeats; int weaponunlockflags; int weaponpower; int accelstat; int topspeedstat; int durabilitystat; int curmoney; int8_t menuoption; int8_t weaponselect; stage_t* curstagearr; gfx_sprite_t *loonsub_sprite; gfx_sprite_t *loonsubprops[14]; gfx_sprite_t *tmp_ptr; gfx_sprite_t *torpedo[2]; gfx_sprite_t *bubbles[4]; gfx_sprite_t *enemy1_sprite; gfx_sprite_t *enemy2_sprite; gfx_sprite_t *explosion1[5]; gfx_sprite_t *explosion2[5]; gfx_sprite_t *whiteball_sprite; gfx_sprite_t *outpost_sprite; gfx_sprite_t *chainlink_sprite; gfx_sprite_t *weapon1sym_sprite; gfx_sprite_t *weapon2sym_sprite; gfx_sprite_t *weapon3sym_sprite; gfx_sprite_t *weapon4sym_sprite; gfx_sprite_t *weaponhighlight_sprite; void main(void) { int x,y,i,j,subtimer; kb_key_t k; char* tmp_str; /* Initialize system */ gfx_Begin(gfx_8bpp); gfx_SetDrawBuffer(); gfx_SetTransparentColor(TRANSPARENT_COLOR); gfx_SetClipRegion(0,0,320,240); /* Initialize variables */ initgamestate(); initgamevars(); // for (i=0;i<32;i++) enemies[i] = emptyenemy; //NOT NEEDED ANYMORE BUT KEPT FOR REFERENCE // ti_CloseAll(); // slot = ti_Open("LLOONDAT","r"); // if (slot) ti_Read(&highscore,sizeof highscore, 1, slot); // ti_CloseAll(); loonsub_sprite = gfx_MallocSprite(32,32); dzx7_Turbo(loonsub_compressed,loonsub_sprite); enemy1_sprite = gfx_MallocSprite(32,27); dzx7_Turbo(enemy1_compressed,enemy1_sprite); enemy2_sprite = gfx_MallocSprite(24,24); dzx7_Turbo(enemy2_compressed,enemy2_sprite); whiteball_sprite = gfx_MallocSprite(8,8); dzx7_Turbo(whiteball_compressed,whiteball_sprite); weapon1sym_sprite = gfx_MallocSprite(16,16); dzx7_Turbo(weapon1sym_compressed,weapon1sym_sprite); weapon2sym_sprite = gfx_MallocSprite(16,16); dzx7_Turbo(weapon2sym_compressed,weapon2sym_sprite); weapon3sym_sprite = gfx_MallocSprite(16,16); dzx7_Turbo(weapon3sym_compressed,weapon3sym_sprite); weapon4sym_sprite = gfx_MallocSprite(16,16); dzx7_Turbo(weapon4sym_compressed,weapon4sym_sprite); weaponhighlight_sprite = gfx_MallocSprite(20,20); dzx7_Turbo(weaponhighlight_compressed,weaponhighlight_sprite); outpost_sprite = gfx_MallocSprite(32,48); dzx7_Turbo(outpost_compressed,outpost_sprite); chainlink_sprite = gfx_MallocSprite(8,16); dzx7_Turbo(chainlink_compressed,chainlink_sprite); for (i=0;i<14;i++) { tmp_ptr = gfx_MallocSprite(4,12); dzx7_Turbo(propeller_ts_tiles_compressed[i],tmp_ptr); loonsubprops[i] = tmp_ptr; } for (i=0;i<2;i++) { tmp_ptr = gfx_MallocSprite(16,8); dzx7_Turbo(torpedo_ts_tiles_compressed[i],tmp_ptr); torpedo[i] = tmp_ptr; } for (i=0;i<4;i++) { tmp_ptr = gfx_MallocSprite(8,8); dzx7_Turbo(bubbles_ts_tiles_compressed[i],tmp_ptr); bubbles[i] = tmp_ptr; } for (i=0;i<5;i++) { tmp_ptr = gfx_MallocSprite(24,24); dzx7_Turbo(explosion1_tiles_compressed[i],tmp_ptr); explosion1[i] = tmp_ptr; tmp_ptr = gfx_MallocSprite(32,32); dzx7_Turbo(explosion2_tiles_compressed[i],tmp_ptr); explosion2[i] = tmp_ptr; } // Start loop gamemode = GM_TITLE; maintimer = 0; menuoption = 0; while (1) { maintimer++; kb_Scan(); switch(gamemode) { case GM_TITLE: k = kb_Data[1]; if (k == kb_2nd) { keywait(); initgamestate(); maintimer = 0; if (menuoption == 2) putaway(); if (menuoption == 1) gamemode = GM_OPENANIM; if (menuoption == 0) initgamevars(); break; } if (k == kb_Mode) putaway(); k = kb_Data[7]; keywait(); if (k == kb_Up) { if ((--menuoption)<0) menuoption=2; } if (k == kb_Down) { if ((++menuoption)>2) menuoption=0; } drawbg(); gfx_SetTextFGColor(0x9F); gfx_SetTextScale(3,3); centerxtext(loontitle1,5); gfx_SetTextScale(3,2); centerxtext(loontitle2,34); gfx_SetTextScale(2,2); gfx_SetTextFGColor((menuoption==0) ? 0x08 : 0xBF); centerxtext(loontitleA,108); gfx_SetTextFGColor((menuoption==1) ? 0x08 : 0xBF); centerxtext(loontitleB,132); gfx_SetTextFGColor((menuoption==2) ? 0x08 : 0xBF); centerxtext(loontitleC,156); gfx_SetTextScale(1,1); gfx_SetTextFGColor(0xBF); gfx_SetTextXY(290,230); gfx_PrintString(VERSION_INFO); gfx_SwapDraw(); break; case GM_OPENANIM: //At given rate of outpost gtfo, maintimer maxes at 112 curx.fp = 24*256; cury.fp = 104*256; dy.fp = dx.fp = 0; maxspeed.fp = (2*256)+(topspeedstat*32); movefactor = ACCELFACTOR*accelstat; playershotdelay = 0; curhp = 10*durabilitystat; shakecycles = iframes = 0; drawbg(); drawoutpost(24-(maintimer>>1)); drawloonsub(); gfx_SetColor(0x08); //xlibc dark blue gfx_FillRectangle(GMBOX_X,GMBOX_Y,GMBOX_W,GMBOX_H); gfx_SetTextFGColor(GREETINGS_DIALOG_TEXT_COLOR); if (maintimer<75) { tmp_str = (maintimer & 0x08) ? getready : blankstr; } else { tmp_str = goodluck; } gfx_GetStringWidth(tmp_str); centerxtext(tmp_str,GMBOX_Y+25); gfx_SwapDraw(); if (maintimer>124) { gamemode = GM_GAMEMODE; curstagearr = stages[curstage]; //Loads curstage dbg_sprintf(dbgout,"Stage loading %i, game mode %i\n",curstage,gamemode); } break; case GM_GAMEMODE: if (kb_Data[1] == kb_Mode) gamemode = GM_RETURNTOBASE; execstage(0); moveloonsub(); moveenemy(); drawbg(); drawenemy(); drawloonsub(); movebullets(); drawbullets(); gfx_SwapDraw(); if (gamemode!=GM_GAMEMODE) maintimer = 0; break; case GM_CLOSINGANIM: //At given rate of outpost return, maintimer maxes at 112 drawbg(); drawoutpost(320-(maintimer>>1)); moveloonsub(); drawloonsub(); gfx_SetColor(0x08); //xlibc dark blue gfx_FillRectangle(GMBOX_X,GMBOX_Y,GMBOX_W,GMBOX_H); gfx_SetTextFGColor(GREETINGS_DIALOG_TEXT_COLOR); tmp_str = (maintimer & 0x08) ? arrival : blankstr; gfx_GetStringWidth(tmp_str); centerxtext(tmp_str,GMBOX_Y+25); gfx_SwapDraw(); if (maintimer>124) { gamemode = GM_OUTPOSTSHOP; menuoption = 0; menuoption = 0; } break; case GM_DYING: iframes = (iframes ^ 0x4) | 0x8; if (maintimer<2) shakecycles = 20; if (maintimer<20) { if (maintimer&1) { x = curx.fp+((randInt(0,32)-8)<<8); y = cury.fp+((randInt(0,32)-8)<<8); newbullet.id = BT_EXPLOSION1; newbullet.y = y; newbullet.x = x; newbullet.temp = 0; addbullet(&newbullet); } } else if (maintimer==20) { newbullet.id = BT_EXPLOSION2; newbullet.y = cury.fp; newbullet.x = curx.fp; newbullet.temp = 0; addbullet(&newbullet); } else if (maintimer==50) { gamemode = GM_GAMEOVER; } moveenemy(); drawbg(); drawenemy(); if (maintimer<22) drawloonsub(); movebullets(); drawbullets(); gfx_SwapDraw(); break; case GM_GAMEOVER: gfx_SetColor(0x08); //xlibc dark blue gfx_FillRectangle(GMBOX_X,GMBOX_Y,GMBOX_W,GMBOX_H); tmp_str = gameoverdesc[randInt(0,3)]; gfx_GetStringWidth(tmp_str); gfx_SetTextFGColor(GREETINGS_DIALOG_TEXT_COLOR); centerxtext(tmp_str,GMBOX_Y+15); centerxtext(gameovertext,GMBOX_Y+35); gfx_SwapDraw(); waitanykey(); gamemode = GM_TITLE; break; case GM_OUTPOSTSHOP: k = kb_Data[1]; if (k == kb_2nd) { keywait(); switch (menuoption) { case 0: if ((weaponunlockflags>>weaponselect) & 1) { playerweaponid = weaponselect; } else { if ((weaponselect == 1) && buyitem(1000)) weaponunlockflags |= 0x02; if ((weaponselect == 1) && buyitem(100000)) weaponunlockflags |= 0x04; if ((weaponselect == 1) && buyitem(100000)) weaponunlockflags |= 0x08; } break; case 1: if (weaponpower < 10 && buyitem(weaponpower*weaponpower*500)) weaponpower++; break; case 2: if (accelstat < 10 && buyitem(accelstat*accelstat*800)) accelstat++; break; case 3: if (topspeedstat < 10 && buyitem(topspeedstat*topspeedstat*500)) topspeedstat++; break; case 4: if (durabilitystat < 10 && buyitem(durabilitystat*durabilitystat*500)) durabilitystat++; break; default: break; } } if (k == kb_Mode) { keywait(); gamemode = GM_OPENANIM; initgamestate(); curstage++; if (curstage>7) { gamerepeats++; curstage = 0; //Put game ending animation someplace when final is done. } break; } k = kb_Data[7]; keywait(); if (k == kb_Up) { if ((--menuoption)<0) menuoption=4; } if (k == kb_Down) { if ((++menuoption)>4) menuoption=0; } if (k == kb_Left && !menuoption) { if ((--weaponselect)<0) weaponselect = 3; } if (k == kb_Right && !menuoption) { if ((++weaponselect)>3) weaponselect = 0; } gfx_FillScreen(0x4A); gfx_SetTextFGColor(0xDF); gfx_SetTextScale(3,3); centerxtext("Outpost Shop",5); gfx_SetTextScale(1,1); gfx_SetTextXY(32,56); gfx_PrintString("Current Funds: "); gfx_PrintUInt(curmoney,6); gfx_SetTextXY(192,56); gfx_PrintString("Equipped: "); x = gfx_GetTextX(); y = gfx_GetTextY()-4; switch (playerweaponid) { case 0: default: tmp_ptr = weapon1sym_sprite; break; case 1: tmp_ptr = weapon2sym_sprite; break; case 2: tmp_ptr = weapon3sym_sprite; break; case 3: tmp_ptr = weapon4sym_sprite; break; } gfx_Sprite(tmp_ptr,x,y); gfx_SetTextFGColor((menuoption==0) ? 0x08 : 0xBF); gfx_SetTextXY(32,94); gfx_PrintString("Weapon: "); gfx_SetTextFGColor(0xBF); x = gfx_GetTextX(); y = gfx_GetTextY()-4; gfx_Sprite(weapon1sym_sprite,x,y); if (weaponselect==0) gfx_TransparentSprite(weaponhighlight_sprite,x-2,y-2); x+=24; gfx_Sprite(weapon2sym_sprite,x,y); if (weaponselect==1) gfx_TransparentSprite(weaponhighlight_sprite,x-2,y-2); x+=24; gfx_Sprite(weapon3sym_sprite,x,y); if (weaponselect==2) gfx_TransparentSprite(weaponhighlight_sprite,x-2,y-2); x+=24; gfx_Sprite(weapon4sym_sprite,x,y); if (weaponselect==3) gfx_TransparentSprite(weaponhighlight_sprite,x-2,y-2); gfx_SetTextXY(192,94); gfx_PrintString(itemcost); if ((weaponunlockflags>>weaponselect) & 1) { gfx_PrintString("HAVE"); } else { if (weaponselect==1) gfx_PrintString("1000"); if (weaponselect==2) gfx_PrintString("N/A"); if (weaponselect==3) gfx_PrintString("N/A"); } gfx_SetTextFGColor((menuoption==1) ? 0x08 : 0xBF); gfx_SetTextXY(32,113); gfx_PrintString("Weapon power: "); gfx_SetTextFGColor(0xBF); gfx_PrintInt(weaponpower,2); gfx_SetTextXY(192,113); gfx_PrintString(itemcost); if (weaponpower>9) { gfx_PrintString("MAXED"); } else { gfx_PrintInt(weaponpower*weaponpower*500,7); } // Insert item cost calculator gfx_SetTextFGColor((menuoption==2) ? 0x08 : 0xBF); gfx_SetTextXY(32,132); gfx_PrintString("Acceleration: "); gfx_SetTextFGColor(0xBF); gfx_PrintInt(accelstat,2); gfx_SetTextXY(192,132); gfx_PrintString(itemcost); if (accelstat>9) { gfx_PrintString("MAXED"); } else { gfx_PrintInt(accelstat*accelstat*800,7); } gfx_SetTextFGColor((menuoption==3) ? 0x08 : 0xBF); gfx_SetTextXY(32,151); gfx_PrintString("Top speed: "); gfx_SetTextFGColor(0xBF); gfx_PrintInt(topspeedstat,2); gfx_SetTextXY(192,151); gfx_PrintString(itemcost); if (topspeedstat>9) { gfx_PrintString("MAXED"); } else { gfx_PrintInt(topspeedstat*topspeedstat*1000,7); } gfx_SetTextFGColor((menuoption==4) ? 0x08 : 0xBF); gfx_SetTextXY(32,170); gfx_PrintString("Durability: "); gfx_SetTextFGColor(0xBF); gfx_PrintInt(durabilitystat,2); gfx_SetTextXY(192,170); gfx_PrintString(itemcost); if (durabilitystat>9) { gfx_PrintString("MAXED"); } else { gfx_PrintInt(durabilitystat*durabilitystat*400,7); } centerxtext("Push 2nd to buy/equip selected item.",208); centerxtext("Push MODE to exit the shop.",208+19); gfx_SwapDraw(); break; case GM_RETURNTOBASE: gfx_SetColor(0x08); //xlibc dark blue gfx_FillRectangle(GMBOX_X,GMBOX_Y,GMBOX_W,GMBOX_H); gfx_SetTextFGColor(GREETINGS_DIALOG_TEXT_COLOR); centerxtext(quitmode1,GMBOX_Y+15); centerxtext(quitmode2,GMBOX_Y+35); gfx_SwapDraw(); waitanykey(); menuoption = 0; gamemode = GM_TITLE; break; default: gfx_SetDefaultPalette(gfx_8bpp); gfx_SetTextFGColor(gfx_red); gfx_SetTextBGColor(255); gfx_SetTextTransparentColor(255); gfx_ZeroScreen(); //gfx_FillScreen(0); gfx_SetTextXY(5,5); gfx_PrintString("An error has occurred!"); gfx_SwapDraw(); waitanykey(); putaway(); } } putaway(); } /* Put other functions here */ void drawbg() { gfx_FillScreen(0x12); } void drawloonsub() { static int prop_timer; int x,y; x = (int) curx.p.ipart; y = (int) cury.p.ipart; prop_timer++; if (prop_timer>13) prop_timer = 0; if (!(iframes&4)) { if (shakecycles) { x += randInt(0,4)-2; y += randInt(0,4)-2; } gfx_TransparentSprite(loonsubprops[prop_timer],x,y+11); gfx_TransparentSprite(loonsub_sprite,x,y); } } //Note: This function relies on kb_Scan() being executed outside in main. void moveloonsub() { kb_key_t k = kb_Data[7]; bullet_t pbdata; int tmf; tmf = 0; //Take care of maintenance tasks if (iframes) iframes--; if (shakecycles) shakecycles--; //Accelerate if moving in direction, else decelerate (less) if (k&kb_Left) dx.fp -= movefactor<<1; if (k&kb_Right) dx.fp += movefactor<<1; if (dx.fp<-maxspeed.fp) dx.fp = -maxspeed.fp; if (dx.fp>maxspeed.fp) dx.fp = maxspeed.fp; tmf = dx.fp-movefactor; if (dx.fp>0) dx.fp = (tmf>0)?tmf:0; tmf = dx.fp+movefactor; if (dx.fp<0) dx.fp = (tmf<0)?tmf:0; curx.fp = dx.fp + curx.fp; if (curx.p.ipart<0) dx.fp = curx.fp = 0; if (curx.p.ipart>LCD_WIDTH-32) { curx.p.ipart = LCD_WIDTH-32; dx.fp = 0; } if (k&kb_Up) dy.fp -= movefactor<<1; if (k&kb_Down) dy.fp += movefactor<<1; if (dy.fp<-maxspeed.fp) dy.fp = -maxspeed.fp; if (dy.fp>maxspeed.fp) dy.fp = maxspeed.fp; tmf = dy.fp-movefactor; if (dy.fp>0) dy.fp = (tmf>0)?tmf:0; tmf = dy.fp+movefactor; if (dy.fp<0) dy.fp = (tmf<0)?tmf:0; cury.fp = dy.fp + cury.fp; if (cury.p.ipart<0) dy.fp = cury.fp = 0; if (cury.p.ipart>LCD_HEIGHT-32) { cury.p.ipart = LCD_HEIGHT-32; dy.fp = 0; } // Process player shooting if (kb_Data[1] == kb_2nd) { if (playershotdelay) { playershotdelay--; } else { playershotdelay = playershotdelaymax; switch (playerweaponid) { case PB_BASICWEAPON: pbdata.id = BT_TORPEDO; pbdata.x = curx.fp+(16<<8); pbdata.y = cury.fp+(12<<8); pbdata.dx = pbdata.dy = 0; pbdata.power = weaponpower; pbdata.temp = 0; addbullet(&pbdata); break; case PB_SPREADSHOT: pbdata.id = BT_SPREADTORPEDO; pbdata.x = curx.fp+(16<<8); pbdata.y = cury.fp+(12<<8); pbdata.dx = pbdata.dy = 0; pbdata.power = weaponpower; pbdata.temp = 0; addbullet(&pbdata); pbdata.dy = -2*256; addbullet(&pbdata); pbdata.dy = 2*256; addbullet(&pbdata); break; default: break; } } } //Perform player collision check against enemies collideplayer(); } void movebullets() { int i,x,y,dx,dy,t; bullet_t newbullet; x = y = dx = dy = t = 0; memcpy(&newbullet,&emptybullet,sizeof emptybullet); for (i=0;i>8 > 4) dx = 4<<8; bullets[i].dx = dx; t = bullets[i].temp++; if (!(t & 0x03)) { newbullet.id = BT_BUBBLES; newbullet.y = bullets[i].y+(2*256); newbullet.dy = -256; newbullet.x = bullets[i].x-(256*4); newbullet.temp = 0; addbullet(&newbullet); } x = bullets[i].x += dx; if (x>(320+16)<<8){ bullets[i].id = 0; break; } collideenemy(&bullets[i],0); break; case BT_BUBBLES: bullets[i].y += bullets[i].dy; t = bullets[i].temp++; if (t>12) bullets[i].id = 0; break; case BT_EXPLOSION1: case BT_EXPLOSION2: t = (++bullets[i].temp)>>2; if (t>4) bullets[i].id = 0; break; case BT_WHITEBALL: x = (bullets[i].x += bullets[i].dx)>>8; y = (bullets[i].y += bullets[i].dy)>>8; if (x < -8 || x > (LCD_WIDTH+8) || y < -8 || y > (LCD_HEIGHT+8)) { bullets[i].id = 0; } break; case BT_SPREADTORPEDO: dx = bullets[i].dx + (int)(0.10*256); if (dx>>8 > 4) dx = 4<<8; bullets[i].dx = dx; t = bullets[i].temp++; x = bullets[i].x += dx; if (x>(320+16)<<8){ bullets[i].id = 0; break; } if (dy=bullets[i].dy) { //is supposed to be assignment here. dy += (t = (bullets[i].dy>0) ? (int)(-(0.04*256)) : (int)(0.04*256)); if ((bullets[i].dy ^ dy) < 0) dy = 0; } y = bullets[i].y += (bullets[i].dy=dy); if (y>0 && y<(238<<8)) { bullets[i].y = y; collideenemy(&bullets[i],0); } break; default: break; } } } void moveenemy() { int i,x,y,t; enemy_t newenemy; memcpy(&newenemy,&emptyenemy,sizeof emptyenemy); for (i=0;i<32;i++) { if (enemies[i].id) { (*enemies[i].movefuncptr) (&(enemies[i])); } } } //Keeping index as static helps prevent void addbullet(bullet_t* bulletdata) { static unsigned int index; unsigned int previndex = index; do { if (!bullets[index].id) { memcpy(&bullets[index],bulletdata,sizeof emptybullet); break; } index++; if (index>=BULLET_TABLE_SIZE) index = 0; } while ( index != previndex ); } void addenemy(enemy_t* enemydata) { static uint8_t index; uint8_t previndex = index; do { if (!enemies[index].id) { memcpy(&enemies[index],enemydata,sizeof emptyenemy); enemies[index].hp *= (1+gamerepeats); //make enemies tougher on each repeat break; } index++; if (index>=ENEMY_TABLE_SIZE) index = 0; } while (index != previndex); } void drawbullets() { int i,x,y,dx,dy,t; for (i=0;i>8,bullets[i].y>>8); break; case BT_BUBBLES: gfx_TransparentSprite(bubbles[bullets[i].temp>>2],bullets[i].x>>8,bullets[i].y>>8); break; case BT_EXPLOSION1: gfx_TransparentSprite(explosion1[bullets[i].temp>>2],bullets[i].x>>8,bullets[i].y>>8); break; case BT_EXPLOSION2: gfx_TransparentSprite(explosion2[bullets[i].temp>>2],bullets[i].x>>8,bullets[i].y>>8); break; case BT_WHITEBALL: gfx_TransparentSprite(whiteball_sprite,bullets[i].x>>8,bullets[i].y>>8); break; default: break; } } } void drawenemy() { int i,x,y,t; x = y = 0; for (i=0;i>8; y = enemies[i].y>>8; enemies[i].temp++; } switch (enemies[i].id){ case EN_REDTIGERSUB: if (enemies[i].temp>=14) enemies[i].temp = 0; gfx_TransparentSprite(enemy1_sprite,x,y); gfx_TransparentSprite(loonsubprops[enemies[i].temp],x+27,y+10); break; case EN_MINE: gfx_TransparentSprite(enemy2_sprite,x,y); default: break; } } } void collideenemy(bullet_t* bulletdata,int pierces) { int i,x,y,w,h,t,ex,ey; bullet_t newbullet; ex = ey = x = y = w = h = 0; switch (bulletdata->id) { case BT_TORPEDO: case BT_SPREADTORPEDO: x = bulletdata->x + 256*16; y = bulletdata->y + 256*2; w = 16; h = 4; break; default: break; } x = bulletdata->x; for(i=0;iey && yex && xid = 0; } } break; case EN_MINE: if (y>ey && yex && xid = 0; } } default: break; } } } } bool damageenemy(enemy_t* enemydata,bullet_t* bulletdata) { int hp; bullet_t newbullet; hp = enemydata->hp = enemydata->hp-bulletdata->power; if (hp<1) { switch (enemydata->id) { case EN_REDTIGERSUB: curmoney += 100 * (curstage+1) * (gamerepeats+1); break; case EN_MINE: curmoney += 50 * (curstage+1) * (gamerepeats+1); break; default: break; } enemydata->id = 0; memcpy(&newbullet,&emptybullet,sizeof emptybullet); newbullet.id = BT_EXPLOSION2; newbullet.y = enemydata->y; newbullet.x = enemydata->x; newbullet.temp = 0; addbullet(&newbullet); return 1; } return 0; } void collideplayer() { int i,x,y,t,ex,ey,w,h,damage; damage = h = w = 0; x = curx.fp; y = cury.fp; for(i=0;iex && y<(ey+h) && (y+(32<<8))>ey) { curhp -= bullets[i].power; iframes = 40; shakecycles = 20; } break; default: break; } } for(i=0;iex && y<(ey+h) && (y+(32<<8))>ey) { curhp -= damage; iframes = 40; shakecycles = 20; if (enemies[i].id == EN_MINE) mineexplode(&enemies[i]); } break; } } if (curhp<1) gamemode = GM_DYING; } void addbullethiteffect(bullet_t* bulletdata,int strikex,int strikey) { bullet_t newbullet; memcpy(&newbullet,&emptybullet,sizeof emptybullet); newbullet.temp = 0; switch (playerweaponid) { case PB_BASICWEAPON: case PB_SPREADSHOT: newbullet.id = BT_EXPLOSION1; newbullet.y = strikey-256*12; newbullet.x = strikex-256*12; addbullet(&newbullet); break; default: break; } } void execstage(int reset) { int x,y,cx,cy,j,state; intptr_t t; static enemy_t enemydata = {0,0,0,0,0,0}; static enemy_t cminedata = {EN_MINE, 320<<8, 0<<8,5,enemycrawl,0}; static int stagetimer = 0; static intptr_t rtn = 0; static int i = 0; if (reset) { i = 0; stagetimer = 0; rtn = 0; return; } while(1) { t = (int) curstagearr[i].val.ival; i++; stagetimer++; switch (t) { case S_NEWEN: memcpy(&enemydata,(enemy_t*) curstagearr[i].val.ptr,sizeof emptyenemy); addenemy(&enemydata); i++; break; case S_COPYEN: enemydata.x = curstagearr[i].val.ival; i++; enemydata.y = curstagearr[i].val.ival; i++; addenemy(&enemydata); break; case S_WAITUNTIL: if (stagetimer < curstagearr[i].val.ival) { i--; return; //break off the routine and come back next frame. } i++; break; case S_GOSUB: break; case S_RETURN: break; case S_ENDSTAGE: i = 0; stagetimer = -1; gamemode = GM_CLOSINGANIM; rtn = 0; return; case S_RANDMINE: cy = cminedata.y; y = 0; //to suppress warning about y possibly being unused before define for(j=0;j<12;j++){ y = randInt(0,215)<<8; if (y<(cy+(24<<8)) && (y+(24<<8))>cy) continue; break; } cminedata.y = y; addenemy(&cminedata); default: break; } } } void drawoutpost(int xpos) { int i,x,y; for (y=(LCD_HEIGHT-16);y>((LCD_HEIGHT+48)/2-16);y-=16) { gfx_TransparentSprite(chainlink_sprite,xpos+12,y); } y-=32; //overcome the last 40h to draw in the outpost gfx_TransparentSprite(outpost_sprite,xpos,y); } //--------------------------------------------------------------------------- void enemyslowcrawl(enemy_t *enemydata){ int x,y,t; x = enemydata->x -= 64; if (x>>8 < -32) enemydata->id = 0; } void enemycrawl(enemy_t *enemydata) { int x,y,t; x = enemydata->x -= 128; if (x>>8 < -32) enemydata->id = 0; } void enemyfloating(enemy_t *enemydata){ int x,y,t; x = enemydata->x -= 128; if (x>>8 < -32) enemydata->id = 0; enemydata->y += floatmotion[enemydata->temp & 0x1F]; } void enemycrawlwidetrishot(enemy_t *enemydata) { int i,x,y,t; bullet_t newbullet; enemycrawl(enemydata); x = (enemydata->x)>>8; if (x>250 && ((maintimer&0x1F)==0x1F)) { memcpy(&newbullet,&emptybullet,sizeof emptybullet); newbullet.id = BT_WHITEBALL; newbullet.x = (enemydata->x); newbullet.y = (enemydata->y)+(256*8); newbullet.power = 2; for (i=6;i<(6+3*2);i+=2) { newbullet.dx = costab_lofi[i]<<2; newbullet.dy = costab_lofi[i+4]<<2; addbullet(&newbullet); } } } void enemycrawsupershot(enemy_t *enemydata) { int i,x,y,t; bullet_t newbullet; enemycrawl(enemydata); x = (enemydata->x)>>8; if (x>200 && ((maintimer&0x1F)==0x1F)) { memcpy(&newbullet,&emptybullet,sizeof emptybullet); newbullet.id = BT_WHITEBALL; newbullet.x = (enemydata->x); newbullet.y = (enemydata->y)+(256*8); newbullet.power = 2; for (i=6;i<(6+3*2);i++) { newbullet.dx = costab_lofi[i]<<2; newbullet.dy = costab_lofi[i+4]<<2; addbullet(&newbullet); } } } void mineexplode(enemy_t* enemydata) { int i,x,y; bullet_t newbullet; memcpy(&newbullet,&emptybullet,sizeof emptybullet); newbullet.power = 1000000; //guarantee that mine explodes damageenemy(enemydata,&newbullet); newbullet.id = BT_WHITEBALL; newbullet.power = 2; newbullet.x = (enemydata->x)+(8*256); newbullet.y = (enemydata->y)+(8*256); newbullet.temp = 0; for(i=0;i<16;i++) { newbullet.dx = (int) costab_lofi[i]*5; newbullet.dy = (int) costab_lofi[(i+4)&0x0F]*5; addbullet(&newbullet); } } //--------------------------------------------------------------------------- void putaway() { // int_Reset(); gfx_End(); // slot = ti_Open("LLOONDAT","w"); // ti_Write(&highscore,sizeof highscore, 1, slot); ti_CloseAll(); exit(0); } void waitanykey() { keywait(); //wait until all keys are released while (!kb_AnyKey()); //wait until a key has been pressed. while (kb_AnyKey()); //make sure key is released before advancing } void keywait() { while (kb_AnyKey()); //wait until all keys are released } void drawdebug() { static int i=0; i++; gfx_SetTextXY(10,5); gfx_PrintInt(i,4); gfx_SetTextXY(50,5); gfx_PrintChar('X'); gfx_PrintChar(':'); gfx_PrintInt(curx.p.ipart,5); gfx_SetTextXY(120,5); gfx_PrintChar('Y'); gfx_PrintChar(':'); gfx_PrintInt(cury.p.ipart,4); gfx_SetTextXY(10,15); gfx_PrintInt(debugvalue,4); gfx_SetTextXY(50,15); gfx_PrintChar('D'); gfx_PrintChar('X'); gfx_PrintChar(':'); gfx_PrintInt(dx.p.ipart,5); gfx_SetTextXY(120,15); gfx_PrintChar('D'); gfx_PrintChar('Y'); gfx_PrintChar(':'); gfx_PrintInt(dy.p.ipart,4); gfx_SetTextXY(50,25); gfx_PrintChar('M'); gfx_PrintChar('F'); gfx_PrintChar(':'); gfx_PrintInt(movefactor,5); gfx_SetTextXY(120,25); gfx_PrintChar('M'); gfx_PrintChar('S'); gfx_PrintChar(':'); gfx_PrintInt(maxspeed.fp,4); } void centerxtext(char* strobj,int y) { gfx_PrintStringXY(strobj,(LCD_WIDTH-gfx_GetStringWidth(strobj))/2,y); } //---------------------------------------------------------------------------------- void initgamestate() { stage_t *ptr; int prevgamemode; execstage(1); //execute to reset stage state. memset(&emptybullet,0,sizeof emptybullet); memset(bullets,0,BULLET_TABLE_SIZE*sizeof(emptybullet)); memset(&emptyenemy,0,sizeof emptyenemy); memset(enemies,0,ENEMY_TABLE_SIZE*sizeof(emptyenemy)); maintimer = 0; } void initgamevars() { weaponunlockflags = 0x01; weaponpower = 1; accelstat = 1; topspeedstat = 1; maintimer = 0; playershotdelaymax = 10; playerweaponid = PB_BASICWEAPON; durabilitystat = 1; curstage = 0; gamerepeats = 0; //------ gamemode = GM_OPENANIM; curmoney = 0; //------ } bool buyitem(int cost) { if (curmoney < cost) return 0; curmoney -= cost; return 1; }