// C Header File // Created 12/2/2002; 7:03:15 AM #define MAX_ACTING_DISTANCE (5<<6) static void InitSpriteData(short idx); static short life(short which); static void SetSprite(short idx); static inline void InitSprite(char type, short x, short y, short idx); static inline short SpriteLife(short idx, short adjust); static void PlayerLife(short a); static inline void KillSprite(short idx); static inline void SpawnSprites(void); static inline void SpawnExplosion(short x, short y); #ifndef __SPRITES_H__ #define __SPRITES_H__ static void InitSpriteData(short idx) { register GameGlobals *ggg asm("a4") = gg; (ggg->sprites + idx)->clientdata = (unsigned char*)(&ggg->sprites_extra[idx]); memset(ggg->sprites_extra + idx,0x00,sizeof(SpriteStruct)); } static short life(short which) { switch(which) { case skeleton: return 40; case spider: return 25; case ceilingSentry: return 30; case redDemon: return 50; case whiteSeeker: return 70; case fatty: return 800; case boss: return 5000; default: return 0; } } static void SetSprite(short idx) { register GameGlobals *ggg asm("a4") = gg; FATSPRITE *cursprite = ggg->sprites + idx; SpriteStruct *curextra = ggg->sprites_extra + idx; switch(curextra->type) { case flamingShip: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_flamingShipA; cursprite->drawmode = SPRITEMODE_SIZE64; curextra->animated = TRUE; curextra->lastframe = 2; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = INVINCIBLE; break; case generator: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_generatorA; cursprite->drawmode = SPRITEMODE_SIZE64; curextra->animated = TRUE; curextra->lastframe = 1; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = 300; curextra->deathsprite = TEXIDX_generatorDead; curextra->deathsize = SPRITEMODE_LOWER32; break; case terminal: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_terminal; cursprite->drawmode = SPRITEMODE_SIZE64; //curextra->animated = FALSE; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = INVINCIBLE; break; case satellite: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_satellite; cursprite->drawmode = SPRITEMODE_SIZE64; //curextra->animated = FALSE; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = INVINCIBLE; break; case deathAnim: curextra->src = ggg->projectilemodels; curextra->first_idx = SPRIDX_death1; cursprite->drawmode = SPRITEMODE_SIZE64; curextra->animated = TRUE; curextra->lastframe = 4; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = 5; curextra->noexplode = TRUE; break; /*case instantHitShow: curextra->src = enemyggg->sprites; curextra->first_idx = TEXIDX_rexA; cursprite->drawmode = SPRITEMODE_SIZE64; curextra->animated = TRUE; curextra->lastframe = 0; curextra->becomesHealth = FALSE; curextra->desire = ENEMY_NONE; curextra->life = 2; curextra->noexplode = TRUE; break;*/ case mushroom: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_mushroom; //curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_LOWER32; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = 1; curextra->noexplode = TRUE; curextra->passthrough = TRUE; break; case grass: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_grass; curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_LOWER32; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = 1; curextra->noexplode = TRUE; curextra->passthrough = TRUE; break; case plantA: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_plantA; //curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_LOWER32; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = 1; curextra->noexplode = TRUE; curextra->passthrough = TRUE; break; case treeA: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_treeA; //curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_SIZE64; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = INVINCIBLE; break; case tableA: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_tableA; //curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_LOWER32; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = INVINCIBLE; break; case tableB: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_tableB; //curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_LOWER32; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = INVINCIBLE; break; case healthLarge: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_healthLarge; //curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_LOWER32; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = INVINCIBLE; curextra->pickup = TRUE; break; case healthSmall: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_healthSmall; //curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_LOWER32; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = INVINCIBLE; curextra->pickup = TRUE; break; case healthPlant: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_healthPlant; //curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_LOWER32; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = INVINCIBLE; curextra->pickup = TRUE; break; case armorLight: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_armorLight; //curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_LOWER32; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = INVINCIBLE; curextra->pickup = TRUE; break; case armorHeavy: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_armorHeavy; //curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_LOWER32; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = INVINCIBLE; curextra->pickup = TRUE; break; case keycardTrigger: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_keycard; //curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_LOWER32; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = INVINCIBLE; curextra->pickup = TRUE; break; case keycard: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_keycard; //curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_LOWER32; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = INVINCIBLE; curextra->pickup = TRUE; break; case pistolAmmo: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_pistolAmmo; //curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_LOWER32; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = INVINCIBLE; curextra->pickup = TRUE; break; case machinegunAmmo: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_machinegunAmmo; //curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_LOWER32; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = INVINCIBLE; curextra->pickup = TRUE; break; case rocketlauncherAmmo: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_rocketlauncherAmmo; //curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_LOWER32; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = INVINCIBLE; curextra->pickup = TRUE; break; case plasmagunAmmo: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_plasmagunAmmo; //curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_LOWER32; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = INVINCIBLE; curextra->pickup = TRUE; break; case railgunAmmo: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_railgunAmmo; //curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_LOWER32; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = INVINCIBLE; curextra->pickup = TRUE; break; case pistol: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_pistol; //curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_LOWER32; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = INVINCIBLE; curextra->pickup = TRUE; break; case machinegun: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_machinegun; //curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_LOWER32; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = INVINCIBLE; curextra->pickup = TRUE; break; case rocketlauncher: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_rocketlauncher; //curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_LOWER32; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = INVINCIBLE; curextra->pickup = TRUE; break; case plasmagun: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_plasmagun; //curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_LOWER32; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = INVINCIBLE; curextra->pickup = TRUE; break; case railgun: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_railgun; //curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_LOWER32; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = INVINCIBLE; curextra->pickup = TRUE; break; case skeleton: curextra->src = ggg->enemysprites; curextra->first_idx = TEXIDX_skeleton05; cursprite->drawmode = SPRITEMODE_SIZE64; curextra->life = life(skeleton); //curextra->pickup = FALSE; curextra->desire = ENEMY_SHOOTER | ENEMY_CHASER; curextra->speed = 2; curextra->weapon = WIset(Pistol); curextra->becomesHealth = becomesSmallHealth; curextra->animated = TRUE; curextra->lastframe = 3; curextra->pattern = &walkingAnimation[0]; curextra->delaycycles = 3; curextra->nr_textures = 2; break; case spider: curextra->src = ggg->enemysprites; curextra->first_idx = TEXIDX_spider05; cursprite->drawmode = SPRITEMODE_LOWER32; curextra->life = life(spider); //curextra->pickup = FALSE; curextra->desire = ENEMY_SHOOTER | ENEMY_CHASER; curextra->speed = 4; curextra->weapon = WIset(SpiderGun); curextra->becomesHealth = becomesSmallHealth; curextra->animated = TRUE; curextra->lastframe = 3; curextra->pattern = &walkingAnimation[0]; curextra->delaycycles = 3; curextra->nr_textures = 2; break; case redDemon: curextra->src = ggg->enemysprites; curextra->first_idx = TEXIDX_redDemon05; cursprite->drawmode = SPRITEMODE_LOWER32; curextra->life = life(redDemon); //curextra->pickup = FALSE; curextra->desire = ENEMY_SHOOTER | ENEMY_CHASER; curextra->speed = 2; curextra->weapon = WIset(RocketLauncher); curextra->becomesHealth = becomesLargeHealth; curextra->animated = TRUE; curextra->lastframe = 3; curextra->pattern = &walkingAnimation[0]; curextra->delaycycles = 3; curextra->nr_textures = 2; break; case whiteSeeker: curextra->src = ggg->enemysprites; curextra->first_idx = TEXIDX_whiteSeeker05; cursprite->drawmode = SPRITEMODE_SIZE64; curextra->life = life(whiteSeeker); //curextra->pickup = FALSE; curextra->desire = ENEMY_SHOOTER | ENEMY_CHASER; curextra->speed = 3; curextra->weapon = WIset(RocketLauncher); curextra->becomesHealth = becomesLargeHealth; curextra->animated = TRUE; curextra->lastframe = 3; curextra->pattern = &walkingAnimation[0]; curextra->delaycycles = 3; curextra->nr_textures = 2; break; case fatty: curextra->src = ggg->enemysprites; curextra->first_idx = TEXIDX_fatty05; curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_SIZE64; curextra->life = life(fatty); //curextra->pickup = FALSE; curextra->desire = ENEMY_SHOOTER | ENEMY_CHASER; curextra->speed = 1; curextra->weapon = WIset(SuperSlowRocketLauncher); curextra->becomesHealth = becomesLargeHealth; curextra->nr_textures = 2; break; case boss: curextra->src = ggg->enemysprites; curextra->first_idx = TEXIDX_boss05; curextra->animated = TRUE; curextra->lastframe = 3; curextra->pattern = &walkingAnimation[0]; cursprite->drawmode = SPRITEMODE_SIZE64; curextra->life = life(boss); curextra->delaycycles = 3; //curextra->pickup = FALSE; curextra->desire = ENEMY_BOSS; curextra->speed = 1; curextra->weapon = WIset(SuperSlowRocketLauncher); curextra->deathsprite = TEXIDX_bossDead; curextra->deathsize = SPRITEMODE_LOWER32; curextra->curinc = 1; break; case ceilingSentry: curextra->src = ggg->enemysprites; curextra->first_idx = TEXIDX_roofsentry; curextra->firesprite = TEXIDX_roofsentryFiring; //curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_UPPER32; curextra->life = life(ceilingSentry); //curextra->pickup = FALSE; curextra->desire = ENEMY_SHOOTER; curextra->weapon = WIset(MachineGun); curextra->becomesHealth = FALSE; curextra->passthrough = TRUE; break; case deathBox: curextra->src = ggg->sprites_s; curextra->first_idx = TEXIDX_mine; cursprite->nr_textures = 1; //curextra->animated = FALSE; cursprite->drawmode = SPRITEMODE_SIZE64; //curextra->becomesHealth = FALSE; //curextra->desire = ENEMY_NONE; curextra->life = 1; //curextra->pickup = FALSE; curextra->passthrough = TRUE; break; } } static inline void InitSprite(char type, short x, short y, short idx) { register GameGlobals *ggg asm("a4") = gg; FATSPRITE *cursprite = ggg->sprites + idx; SpriteStruct *curextra = ggg->sprites_extra + idx; //Set general info FAT_InitSprite (cursprite); InitSpriteData (idx); cursprite->xpos = x; cursprite->ypos = y; curextra->type = type; curextra->speed = 1; cursprite->nr_textures = 1; curextra->nr_textures = 1; //Set specific info SetSprite(idx); /* if(cursprite->drawmode == SPRITEMODE_SIZE64) cursprite->drawmode = SPRITEMODE_UPPER32; else cursprite->drawmode = SPRITEMODE_UNUSED;//Water fakeness*/ cursprite->textures = curextra->src+curextra->first_idx; if(curextra->weapon.cur) { curextra->weapon.ammo = curextra->weapon.cur->start_ammo; curextra->weapon.curdelay = curextra->weapon.cur->repeatdelay; curextra->weapon.cur_persistence = 0; } curextra->drawmode = cursprite->drawmode; if(!(curextra->passthrough||curextra->pickup)) { curextra->tile = fc->map_data[(y>>6)*fc->map_width+(x>>6)]; fc->map_data[(y>>6)*fc->map_width+(x>>6)]=solidSprite; } } static inline short SpriteLife(short idx, short adjust) { register GameGlobals *ggg asm("a4") = gg; SpriteStruct *extra = ggg->sprites_extra + idx; if(extra->life == INVINCIBLE) return 0; extra->life += adjust; if(extra->life <= 0) { extra->life = 0; KillSprite(idx); return 1; } return 0; } static void PlayerLife(short a) { register GameGlobals *ggg asm("a4") = gg; short b = a; if(a<0) { if(ggg->player.armor) { a = (a*(MAX_ARMOR-ggg->player.armor))/((MAX_ARMOR*3)/2); ggg->player.armor -= (abs(b-a)); if(ggg->player.armor<0) ggg->player.armor = 0; } ggg->invert++; } ggg->player.life += a; if(ggg->player.life<=0) { ggg->player.life = 0; ggg->quitting = PLAYER_DIED; } } static inline void KillSprite(short idx) { register GameGlobals *ggg asm("a4") = gg; FATSPRITE *f = ggg->sprites + idx; SpriteStruct *s = ggg->sprites_extra+idx; char h = s->becomesHealth; char db = s->type==deathBox; short x = f->xpos; short y = f->ypos; if(h && (ggg->sprite_count < MAX_SPRITES)) { if(h == becomesLargeHealth) InitSprite(healthLarge,x,y,/*(x&~63)|32,(y&~63)|32,*/ggg->sprite_count); else InitSprite(healthSmall,(x&~63)|32,(y&~63)|32,ggg->sprite_count); ggg->sprite_count++; } if(fc->map_data[(y>>6)*fc->map_width + (x>>6)]==solidSprite) fc->map_data[(y>>6)*fc->map_width + (x>>6)] = s->tile; if((ggg->sprite_count < MAX_SPRITES) && !s->life && !s->noexplode) { InitSprite(deathAnim,x,y,ggg->sprite_count); ggg->sprite_count++; } if(s->deathsprite) { f->textures = s->src+s->deathsprite; s->desire = ENEMY_NONE; s->life = INVINCIBLE; f->drawmode = s->deathsize; s->drawmode = f->drawmode; s->animated = FALSE; s->passthrough = TRUE; s->pickup = FALSE; } else { ggg->sprite_count--; FATSPRITE *tosprite = ggg->sprites + ggg->sprite_count; FATSPRITE *fromsprite = ggg->sprites + idx; SpriteStruct *toextra = ggg->sprites_extra + ggg->sprite_count; SpriteStruct *fromextra = ggg->sprites_extra + idx; FATSPRITE s; SpriteStruct e; memcpy(&s,tosprite,sizeof(FATSPRITE)); memcpy(&e,toextra,sizeof(SpriteStruct)); memcpy(tosprite,fromsprite,sizeof(FATSPRITE)); memcpy(toextra,fromextra,sizeof(SpriteStruct)); memcpy(fromsprite,&s,sizeof(FATSPRITE)); memcpy(fromextra,&e,sizeof(SpriteStruct)); } //If this is first, it causes an infinite loop/ stack overflow //when two mines are within range of each other if(db) SpawnExplosion(x,y); } static inline void SpawnSprites(void) { register GameGlobals *ggg asm("a4") = gg; short a; char Xvalue; for(a=0;amap_width*fc->map_height;a++) { if(ggg->sprite_count == MAX_SPRITES) return; //Can't handle any more Xvalue = fc->map_data[a]; if(Xvalue>=0) continue; if(Xvalue <= SPRITE_CODE_MIN && Xvalue >= SPRITE_CODE_MAX) { fc->map_data[a] = 0; InitSprite(Xvalue,(a%fc->map_width)*64+32, (a/fc->map_width)*64+32,ggg->sprite_count); ggg->sprite_count++; } } } #endif