X-Git-Url: http://4ch.mooo.com/gitweb/?p=16.git;a=blobdiff_plain;f=16%2Fkeen456%2FKEEN4-6%2FKEEN4%2FK4_ACT1.C;fp=16%2Fkeen456%2FKEEN4-6%2FKEEN4%2FK4_ACT1.C;h=f26104b165f7fa4f0e5dcf2f1cc23b511aa4830e;hp=0000000000000000000000000000000000000000;hb=7d1948e210bb7b58af0a0412e71f2a0a0a2010af;hpb=ebc247a0a67daa69a027f31d9d7d9572db765e56 diff --git a/16/keen456/KEEN4-6/KEEN4/K4_ACT1.C b/16/keen456/KEEN4-6/KEEN4/K4_ACT1.C new file mode 100755 index 00000000..f26104b1 --- /dev/null +++ b/16/keen456/KEEN4-6/KEEN4/K4_ACT1.C @@ -0,0 +1,1221 @@ +/* Reconstructed Commander Keen 4-6 Source Code + * Copyright (C) 2021 K1n9_Duk3 + * + * This file is loosely based on: + * Keen Dreams Source Code + * Copyright (C) 2014 Javier M. Chavez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* +K4_ACT1.C +========= + +Contains the following actor types (in this order): + +- Miragia (world map) +- Bonus Items +- Council Member +- Poison Slug +- Mad Mushroom +- Egg & Eggbird +- Arachnut +- Skypest + +*/ + +#include "CK_DEF.H" + +/* +============================================================================= + + MIRAGIA + +============================================================================= +*/ + +statetype s_miragia0 = {0, 0, step, false, false, 300, 0, 0, T_Miragia0, NULL, NULL, &s_miragia1}; +statetype s_miragia1 = {0, 0, step, false, false, 30, 0, 0, T_Miragia1, NULL, NULL, &s_miragia2}; +statetype s_miragia2 = {0, 0, step, false, false, 30, 0, 0, T_Miragia2, NULL, NULL, &s_miragia3}; +statetype s_miragia3 = {0, 0, step, false, false, 30, 0, 0, T_Miragia3, NULL, NULL, &s_miragia4}; +statetype s_miragia4 = {0, 0, step, false, false, 300, 0, 0, T_Miragia4, NULL, NULL, &s_miragia5}; +statetype s_miragia5 = {0, 0, step, false, false, 30, 0, 0, T_Miragia5, NULL, NULL, &s_miragia6}; +statetype s_miragia6 = {0, 0, step, false, false, 30, 0, 0, T_Miragia6, NULL, NULL, &s_miragia7}; +statetype s_miragia7 = {0, 0, step, false, false, 30, 0, 0, T_Miragia7, NULL, NULL, &s_miragia0}; + +/* +=========================== += += SpawnMiragia += +=========================== +*/ + +void SpawnMiragia(Sint16 x, Sint16 y) +{ + GetNewObj(false); + new->obclass = inertobj; + new->active = ac_allways; + new->x = x; + new->y = y; + new->state = &s_miragia0; +} + +/* +=========================== += += T_Miragia0 += +=========================== +*/ + +void T_Miragia0(objtype *ob) +{ + if (player->tileright >= ob->x && player->tileleft <= ob->x+5 + && player->tiletop >= ob->y && player->tilebottom <= ob->y+4) + { + //don't let miragia appear if player is in the area, so player won't get stuck + ob->state = &s_miragia7; + } + else + { + RF_MapToMap(8, 60, ob->x, ob->y, 6, 4); + } +} + +/* +=========================== += += T_Miragia1 += +=========================== +*/ + +void T_Miragia1(objtype *ob) +{ + RF_MapToMap(14, 60, ob->x, ob->y, 6, 4); +} + +/* +=========================== += += T_Miragia2 += +=========================== +*/ + +void T_Miragia2(objtype *ob) +{ + RF_MapToMap(20, 60, ob->x, ob->y, 6, 4); +} + +/* +=========================== += += T_Miragia3 += +=========================== +*/ + +void T_Miragia3(objtype *ob) +{ + RF_MapToMap(26, 60, ob->x, ob->y, 6, 4); +} + +/* +=========================== += += T_Miragia4 += +=========================== +*/ + +void T_Miragia4(objtype *ob) +{ + RF_MapToMap(20, 60, ob->x, ob->y, 6, 4); +} + +/* +=========================== += += T_Miragia5 += +=========================== +*/ + +void T_Miragia5(objtype *ob) +{ + RF_MapToMap(14, 60, ob->x, ob->y, 6, 4); +} + +/* +=========================== += += T_Miragia6 += +=========================== +*/ + +void T_Miragia6(objtype *ob) +{ + RF_MapToMap(8, 60, ob->x, ob->y, 6, 4); +} + +/* +=========================== += += T_Miragia7 += +=========================== +*/ + +void T_Miragia7(objtype *ob) +{ + RF_MapToMap(2, 60, ob->x, ob->y, 6, 4); +} + +/* +============================================================================= + + BONUS ITEMS + +temp1 = bonus type +temp2 = base shape number +temp3 = last animated shape number +1 + +============================================================================= +*/ + +statetype s_bonus1 = {0, 0, step, false, false, 20, 0, 0, T_Bonus, NULL, R_Draw, &s_bonus2}; +statetype s_bonus2 = {0, 0, step, false, false, 20, 0, 0, T_Bonus, NULL, R_Draw, &s_bonus1}; +statetype s_bonusrise = {0, 0, slide, false, false, 40, 0, 8, NULL, NULL, R_Draw, NULL}; + +statetype s_splash1 = {DROPSPLASH1SPR, DROPSPLASH1SPR, step, false, false, 10, 0, 0, NULL, NULL, R_Draw, &s_splash2}; +statetype s_splash2 = {DROPSPLASH2SPR, DROPSPLASH2SPR, step, false, false, 10, 0, 0, NULL, NULL, R_Draw, &s_splash3}; +statetype s_splash3 = {DROPSPLASH3SPR, DROPSPLASH3SPR, step, false, false, 10, 0, 0, NULL, NULL, R_Draw, NULL}; + +Uint16 bonusshape[] = {REDGEM1SPR, YELLOWGEM1SPR, BLUEGEM1SPR, GREENGEM1SPR, SUGAR1ASPR, SUGAR2ASPR, SUGAR3ASPR, SUGAR4ASPR, SUGAR5ASPR, SUGAR6ASPR, ONEUPASPR, STUNCLIP1SPR}; + +/* +=========================== += += SpawnBonus += +=========================== +*/ + +void SpawnBonus(Sint16 x, Sint16 y, Sint16 type) +{ + GetNewObj(false); + new->needtoclip = cl_noclip; + new->priority = 2; + new->obclass = bonusobj; + new->x = CONVERT_TILE_TO_GLOBAL(x); + new->y = CONVERT_TILE_TO_GLOBAL(y); + new->ydir = -1; + new->temp1 = type; + new->temp2 = new->shapenum = bonusshape[type]; + new->temp3 = new->temp2 + 2; + NewState(new, &s_bonus1); +} + +/* +=========================== += += SpawnSplash += +=========================== +*/ + +void SpawnSplash(Sint16 x, Sint16 y) +{ + GetNewObj(true); + new->needtoclip = cl_noclip; + new->priority = 3; + new->obclass = inertobj; + new->x = CONVERT_TILE_TO_GLOBAL(x); + new->y = CONVERT_TILE_TO_GLOBAL(y); + NewState(new, &s_splash1); +} + +/* +=========================== += += T_Bonus += +=========================== +*/ + +void T_Bonus(objtype *ob) +{ + ob->shapenum++; + if (ob->shapenum == ob->temp3) + ob->shapenum = ob->temp2; +} + +/* +============================================================================= + + COUNCIL MEMBER + +============================================================================= +*/ + +statetype s_councilwalk1 = {COUNCILWALKL1SPR, COUNCILWALKR1SPR, step, false, true, 10, 64, 0, T_Council, NULL, R_Walk, &s_councilwalk2}; +statetype s_councilwalk2 = {COUNCILWALKL2SPR, COUNCILWALKR2SPR, step, false, true, 10, 64, 0, T_Council, NULL, R_Walk, &s_councilwalk1}; +statetype s_councilstand = {COUNCILTHINKLSPR, COUNCILTHINKRSPR, step, false, false, 120, 128, 0, NULL, NULL, R_Draw, &s_councilwalk1}; + +/* +=========================== += += SpawnCouncil += +=========================== +*/ + +void SpawnCouncil(Sint16 x, Sint16 y) +{ + GetNewObj(false); + new->obclass = oracleobj; + new->active = ac_yes; + new->priority = 0; + new->x = CONVERT_TILE_TO_GLOBAL(x); + new->y = CONVERT_TILE_TO_GLOBAL(y) -0x171; //TODO: wierd + if (US_RndT() < 0x80) + { + new->xdir = 1; + } + else + { + new->xdir = -1; + } + new->ydir = 1; + NewState(new, &s_councilwalk1); +} + +/* +=========================== += += T_Council += +=========================== +*/ + +void T_Council(objtype *ob) +{ + Uint16 randnum; + + randnum = US_RndT(); + if (tics*8 > randnum) + { + // BUG: might be about to move off a ledge, causing it to get stuck + // after standing (the stand state doesn't use R_Walk)! + // To avoid that, set xtry to 0 here. + ob->state = &s_councilstand; + } +} + +/* +============================================================================= + + POINSON SLUG + +============================================================================= +*/ + +statetype s_slugwalk1 = {SLUGWALKL1SPR, SLUGWALKR1SPR, step, false, true, 8, 64, 0, NULL, C_Slug, R_WalkNormal, &s_slugwalk2}; +statetype s_slugwalk2 = {SLUGWALKL2SPR, SLUGWALKR2SPR, step, false, true, 8, 64, 0, T_Slug, C_Slug, R_WalkNormal, &s_slugwalk1}; +statetype s_slugpiss1 = {SLUGPISSLSPR, SLUGPISSRSPR, step, false, true, 60, 64, 0, T_SlugPiss, C_Slug, R_WalkNormal, &s_slugwalk1}; +statetype s_slugstun = {SLUGSTUN1SPR, SLUGSTUN1SPR, think, false, false, 0, 0, 0, T_Projectile, NULL, R_Stunned, NULL}; +statetype s_slugstunalt = {SLUGSTUN2SPR, SLUGSTUN2SPR, think, false, false, 0, 0, 0, T_Projectile, NULL, R_Stunned, NULL}; +statetype s_slugslime = {SLUGSLIME1SPR, SLUGSLIME1SPR, step, false, false, 300, 0, 0, NULL, C_Lethal, R_Draw, &s_slugslime2}; +statetype s_slugslime2 = {SLUGSLIME2SPR, SLUGSLIME2SPR, step, false, false, 60, 0, 0, NULL, NULL, R_Draw, NULL}; + +/* +=========================== += += SpawnSlug += +=========================== +*/ + +void SpawnSlug(Sint16 x, Sint16 y) +{ + GetNewObj(false); + new->obclass = slugobj; + new->active = ac_yes; + new->priority = 2; + new->x = CONVERT_TILE_TO_GLOBAL(x); + new->y = CONVERT_TILE_TO_GLOBAL(y) - 0x71; + if (US_RndT() < 0x80) + { + new->xdir = 1; + } + else + { + new->xdir = -1; + } + new->ydir = 1; + NewState(new, &s_slugwalk1); +} + +/* +=========================== += += T_Slug += +=========================== +*/ + +void T_Slug(objtype *ob) +{ + if (US_RndT() < 16) + { + if (ob->x < player->x) + { + ob->xdir = 1; + } + else + { + ob->xdir = -1; + } + ob->state = &s_slugpiss1; + SD_PlaySound(SND_SLUGPOO); + // Note: might be a good idea to set xtry to 0 here + } +} + +/* +=========================== += += T_SlugPiss += +=========================== +*/ + +void T_SlugPiss(objtype *ob) +{ + GetNewObj(true); + new->obclass = inertobj; + new->active = ac_removable; + new->priority = 0; + new->x = ob->x; + new->y = ob->bottom - 8*PIXGLOBAL; + NewState(new, &s_slugslime); +} + +/* +=========================== += += C_Slug += +=========================== +*/ + +void C_Slug(objtype *ob, objtype *hit) +{ + if (hit->obclass == keenobj) + { + KillKeen(); + } + else if (hit->obclass == stunshotobj) + { + if (US_RndT() < 0x80) + { + StunObj(ob, hit, &s_slugstun); + } + else + { + StunObj(ob, hit, &s_slugstunalt); + } + ob->yspeed = -24; + ob->xspeed = ob->xdir*8; + } +} + +/* +============================================================================= + + MAD MUSHROOM + +temp1 = jump counter + +============================================================================= +*/ + +statetype s_mushroom1 = {MADMUSHROOML1SPR, MADMUSHROOMR1SPR, stepthink, false, false, 8, 0, 0, T_Mushroom, C_Mushroom, R_Mushroom, &s_mushroom2}; +statetype s_mushroom2 = {MADMUSHROOML2SPR, MADMUSHROOMR2SPR, stepthink, false, false, 8, 0, 0, T_Mushroom, C_Mushroom, R_Mushroom, &s_mushroom1}; + +/* +=========================== += += SpawnMadMushroom += +=========================== +*/ + +void SpawnMadMushroom(Sint16 x, Sint16 y) +{ + GetNewObj(false); + new->obclass = madmushroomobj; + new->active = ac_yes; + new->priority = 0; + new->x = CONVERT_TILE_TO_GLOBAL(x); + new->y = CONVERT_TILE_TO_GLOBAL(y) - 0xF1; + new->xdir = 1; + new->ydir = 1; + NewState(new, &s_mushroom1); +} + +/* +=========================== += += T_Mushroom += +=========================== +*/ + +void T_Mushroom(objtype *ob) +{ + if (player->x < ob->x) + { + ob->xdir = -1; + } + else + { + ob->xdir = 1; + } + + // BUG: this might be executed twice during the same frame if the + // object's animation/state changed during that frame, causing the + // object to move at twice the speed during that frame! + // To avoid that, return if ytry is not 0. + DoWeakGravity(ob); +} + +/* +=========================== += += C_Mushroom += +=========================== +*/ + +void C_Mushroom(objtype *ob, objtype *hit) +{ + ob++; // shut up compiler + if (hit->obclass == stunshotobj) + { + ExplodeShot(hit); + } + else if (hit->obclass == keenobj) + { + KillKeen(); + } +} + +/* +=========================== += += R_Mushroom += +=========================== +*/ + +void R_Mushroom(objtype *ob) +{ + if (ob->hitsouth) + ob->yspeed = 0; + + if (ob->hitnorth) + { + ob->yspeed = 0; + if (++ob->temp1 == 3) + { + ob->temp1 = 0; + ob->yspeed = -68; + SD_PlaySound(SND_BOUNCE2); + } + else + { + SD_PlaySound(SND_BOUNCE1); + ob->yspeed = -40; + } + } + RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority); +} + +/* +============================================================================= + + EGGBIRD + +temp1 = blocked flag for flying eggbird (cannot change xdir to chase Keen + while this is non-zero) + +============================================================================= +*/ + +statetype s_egg = {EGGSPR, EGGSPR, think, false, true, 8, 0, 0, NULL, C_Egg, R_Draw, NULL}; +statetype s_eggbroke = {EGGBROKESPR, EGGBROKESPR, step, false, false, 30000, 0, 0, NULL, NULL, R_Draw, NULL}; +statetype s_eggchip1 = {EGGCHIP1SPR, EGGCHIP1SPR, think, false, false, 0, 0, 0, T_Projectile, NULL, R_Chip, NULL}; +statetype s_eggchip2 = {EGGCHIP2SPR, EGGCHIP2SPR, think, false, false, 0, 0, 0, T_Projectile, NULL, R_Chip, NULL}; +statetype s_eggchip3 = {EGGCHIP3SPR, EGGCHIP3SPR, think, false, false, 0, 0, 0, T_Projectile, NULL, R_Chip, NULL}; + +statetype s_eggbirdpause = {BIRDWALKL1SPR, BIRDWALKR1SPR, step, false, true, 120, 128, 0, NULL, C_EggbirdStun, R_Eggbird, &s_eggbirdwalk2}; +statetype s_eggbirdwalk1 = {BIRDWALKL1SPR, BIRDWALKR1SPR, step, false, true, 7, 128, 0, NULL, C_Eggbird, R_Eggbird, &s_eggbirdwalk2}; +statetype s_eggbirdwalk2 = {BIRDWALKL2SPR, BIRDWALKR2SPR, step, false, true, 7, 128, 0, NULL, C_Eggbird, R_Eggbird, &s_eggbirdwalk3}; +statetype s_eggbirdwalk3 = {BIRDWALKL3SPR, BIRDWALKR3SPR, step, false, true, 7, 128, 0, NULL, C_Eggbird, R_Eggbird, &s_eggbirdwalk4}; +statetype s_eggbirdwalk4 = {BIRDWALKL4SPR, BIRDWALKR4SPR, step, false, true, 7, 128, 0, T_Eggbird, C_Eggbird, R_Eggbird, &s_eggbirdwalk1}; +statetype s_eggbirdfly1 = {BIRDFLY1SPR, BIRDFLY1SPR, slidethink, false, false, 8, 0, 0, T_EggbirdFly, C_Eggbird, R_Eggbirdfly, &s_eggbirdfly2}; +statetype s_eggbirdfly2 = {BIRDFLY2SPR, BIRDFLY2SPR, slidethink, false, false, 8, 0, 0, T_EggbirdFly, C_Eggbird, R_Eggbirdfly, &s_eggbirdfly3}; +statetype s_eggbirdfly3 = {BIRDFLY3SPR, BIRDFLY3SPR, slidethink, false, false, 8, 0, 0, T_EggbirdFly, C_Eggbird, R_Eggbirdfly, &s_eggbirdfly4}; +statetype s_eggbirdfly4 = {BIRDFLY4SPR, BIRDFLY4SPR, slidethink, false, false, 8, 0, 0, T_EggbirdFly, C_Eggbird, R_Eggbirdfly, &s_eggbirdfly1}; +statetype s_eggbirddrop = {BIRDFLY4SPR, BIRDFLY4SPR, think, false, false, 8, 128, 0, T_WeakProjectile, C_Eggbird, R_EggbirdDrop, NULL}; +statetype s_eggbirdstun = {BIRDSTUNSPR, BIRDSTUNSPR, stepthink, false, false, 240, 0, 0, T_Projectile, C_EggbirdStun, R_Draw, &s_eggbirdstun2}; +statetype s_eggbirdstun2 = {BIRDWALKL1SPR, BIRDWALKR1SPR, step, false, true, 20, 0, 0, NULL, C_EggbirdStun, R_Draw, &s_eggbirdstun3}; +statetype s_eggbirdstun3 = {BIRDSTUNSPR, BIRDSTUNSPR, step, false, true, 20, 0, 0, NULL, C_EggbirdStun, R_Draw, &s_eggbirdstun4}; +statetype s_eggbirdstun4 = {BIRDWALKL1SPR, BIRDWALKR1SPR, step, false, true, 20, 0, 0, NULL, C_EggbirdStun, R_Draw, &s_eggbirdstun5}; +statetype s_eggbirdstun5 = {BIRDSTUNSPR, BIRDSTUNSPR, step, false, true, 20, 0, 0, T_EggUnstun, C_EggbirdStun, R_Draw, &s_eggbirdwalk1}; + +/* +=========================== += += SpawnEggbird += +=========================== +*/ + +void SpawnEggbird(Sint16 x, Sint16 y) +{ + GetNewObj(false); + new->obclass = eggobj; + new->active = ac_yes; + new->priority = 2; + new->x = CONVERT_TILE_TO_GLOBAL(x); + new->y = CONVERT_TILE_TO_GLOBAL(y) - 0x71; + new->xdir = 1; + new->ydir = 1; + NewState(new, &s_egg); +} + +/* +=========================== += += T_EggUnstun += +=========================== +*/ + +void T_EggUnstun(objtype *ob) +{ + ob->obclass = eggbirdobj; +} + +/* +=========================== += += SpawnEggbirdOut += +=========================== +*/ + +void SpawnEggbirdOut(Sint16 x, Sint16 y) +{ + GetNewObj(true); + new->obclass = eggbirdobj; + new->active = ac_yes; + new->priority = 2; + new->x = CONVERT_TILE_TO_GLOBAL(x); + new->y = CONVERT_TILE_TO_GLOBAL(y) - 0xF1; + if (new->x < player->x) + { + new->xdir = 1; + } + else + { + new->xdir = -1; + } + new->ydir = 1; + NewState(new, &s_eggbirdpause); +} + +/* +=========================== += += C_Egg += +=========================== +*/ + +void C_Egg(objtype *ob, objtype *hit) +{ + if (hit->obclass == stunshotobj || hit->obclass == keenobj) + { + if (hit->obclass == stunshotobj) + ExplodeShot(hit); + + ob->obclass = inertobj; + ob->active = ac_removable; + ChangeState(ob, &s_eggbroke); + + GetNewObj(true); + new->obclass = eggbirdobj; + new->active = ac_yes; + new->x = ob->x; + new->y = ob->y - 8*PIXGLOBAL; + if (ob->x < player->x) + { + new->xdir = 1; + } + else + { + new->xdir = -1; + } + new->ydir = 1; + NewState(new, &s_eggbirdpause); + + GetNewObj(true); + new->obclass = inertobj; + new->active = ac_removable; + new->x = ob->x; + new->y = ob->y; + new->xspeed = -28; + new->yspeed = -40; + NewState(new, &s_eggchip1); + + GetNewObj(true); + new->obclass = inertobj; + new->active = ac_removable; + new->x = ob->x; + new->y = ob->y; + new->xspeed = 28; + new->yspeed = -40; + NewState(new, &s_eggchip2); + + GetNewObj(true); + new->obclass = inertobj; + new->active = ac_removable; + new->x = ob->x; + new->y = ob->y; + new->xspeed = 0; + new->yspeed = -56; + NewState(new, &s_eggchip3); + } +} + +/* +=========================== += += T_Eggbird += +=========================== +*/ + +void T_Eggbird(objtype *ob) +{ + if (ob->x < player->x) + { + ob->xdir = 1; + } + else + { + ob->xdir = -1; + } + if (ob->bottom >= player->bottom + 3*TILEGLOBAL && player->hitnorth + && StatePositionOk(ob, &s_eggbirdfly1)) // BUG: StatePositionOk() only works for normal clipping, not for full clipping + { + // Note: might be a good idea to set xtry to 0 here + ob->state = &s_eggbirdfly1; + ob->needtoclip = cl_fullclip; + ob->yspeed = -8; + ob->temp1 = 0; + } +} + +/* +=========================== += += T_EggbirdFly += +=========================== +*/ + +void T_EggbirdFly(objtype *ob) +{ + if (ob->temp1 == 0) + { + if (ob->x < player->x) + { + ob->xdir = 1; + } + else + { + ob->xdir = -1; + } + } + AccelerateXv(ob, ob->xdir, 16); + if (ob->y < player->y) + { + AccelerateY(ob, 1, 16); + } + else + { + AccelerateY(ob, -1, 16); + } +} + +/* +=========================== += += C_Eggbird += +=========================== +*/ + +void C_Eggbird(objtype *ob, objtype *hit) +{ + if (hit->obclass == keenobj) + { + KillKeen(); + } + else if (hit->obclass == stunshotobj) + { + ob->xspeed = 0; + ob->needtoclip = cl_midclip; + StunObj(ob, hit, &s_eggbirdstun); + } +} + +/* +=========================== += += C_EggbirdStun += +=========================== +*/ + +void C_EggbirdStun(objtype *ob, objtype *hit) +{ + if (hit->obclass == stunshotobj) + { + ob->xspeed = 0; + StunObj(ob, hit, &s_eggbirdstun); + } +} + +/* +=========================== += += R_Eggbird += +=========================== +*/ + +void R_Eggbird(objtype *ob) +{ + if (ob->xdir == 1 && ob->hitwest) + { + ob->x -= ob->xmove; + ob->xdir = -1; + ob->nothink = US_RndT() >> 5; + ChangeState(ob, ob->state); + } + else if (ob->xdir == -1 && ob->hiteast) + { + ob->x -= ob->xmove; + ob->xdir = 1; + ob->nothink = US_RndT() >> 5; + ChangeState(ob, ob->state); + } + if (!ob->hitnorth) + { + ob->yspeed = -16; + ob->needtoclip = cl_fullclip; + ChangeState(ob, &s_eggbirdfly1); + } + RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority); +} + +/* +=========================== += += R_EggbirdDrop += +=========================== +*/ + +void R_EggbirdDrop(objtype *ob) //never actually used +{ + if (ob->hitnorth) + { + ChangeState(ob, &s_eggbirdwalk1); + } + RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority); +} + +/* +=========================== += += R_Chip += +=========================== +*/ + +void R_Chip(objtype *ob) +{ + if (ob->hitnorth) + ob->xspeed = ob->yspeed = 0; + + RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority); +} + +/* +=========================== += += R_Eggbirdfly += +=========================== +*/ + +void R_Eggbirdfly(objtype *ob) +{ + statetype *oldstate; + + if ((ob->hitsouth || ob->hitnorth) && !ob->temp1) + ob->temp1++; + + if (ob->hiteast && ob->xspeed < 0 || ob->hitwest && ob->xspeed > 0) + { + ob->xspeed = 0; + ob->xdir = -ob->xdir; + } + if (ob->hitnorth == 1 && player->bottom - ob->bottom < 8*PIXGLOBAL) // BUG? unsigned comparison! + { + oldstate = ob->state; + ob->needtoclip = cl_midclip; + ChangeState(ob, &s_eggbirdwalk1); + xtry = 0; + ytry = 8*PIXGLOBAL; + PushObj(ob); + if (!ob->hitnorth) + { + ob->needtoclip = cl_fullclip; + ChangeState(ob, oldstate); + } + return; // BUG: sprite isn't updated + } + + if (!ob->hitsouth && !ob->hitnorth) + ob->temp1 = 0; + + RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority); +} + +/* +============================================================================= + + ARACHNUT + +============================================================================= +*/ + +statetype s_arach1 = {ARACHNUTWALK1SPR, ARACHNUTWALK4SPR, step, false, true, 6, 128, 0, NULL, C_Arach, R_Walk, &s_arach2}; +statetype s_arach2 = {ARACHNUTWALK2SPR, ARACHNUTWALK3SPR, step, false, true, 6, 128, 0, NULL, C_Arach, R_Walk, &s_arach3}; +statetype s_arach3 = {ARACHNUTWALK3SPR, ARACHNUTWALK2SPR, step, false, true, 6, 128, 0, NULL, C_Arach, R_Walk, &s_arach4}; +statetype s_arach4 = {ARACHNUTWALK4SPR, ARACHNUTWALK1SPR, step, false, true, 6, 128, 0, T_Arach, C_Arach, R_Walk, &s_arach1}; +statetype s_arachstun = {ARACHNUTSTUNSPR, ARACHNUTSTUNSPR, step, false, true, 240, 0, 0, NULL, C_ArachStun, R_Draw, &s_arachstun2}; +statetype s_arachstun2 = {ARACHNUTWALK1SPR, ARACHNUTWALK1SPR, step, false, true, 20, 0, 0, NULL, C_ArachStun, R_Draw, &s_arachstun3}; +statetype s_arachstun3 = {ARACHNUTSTUNSPR, ARACHNUTSTUNSPR, step, false, true, 20, 0, 0, NULL, C_ArachStun, R_Draw, &s_arachstun4}; +statetype s_arachstun4 = {ARACHNUTWALK1SPR, ARACHNUTWALK1SPR, step, false, true, 20, 0, 0, NULL, C_ArachStun, R_Draw, &s_arachstun5}; +statetype s_arachstun5 = {ARACHNUTSTUNSPR, ARACHNUTSTUNSPR, step, false, true, 20, 0, 0, NULL, C_ArachStun, R_Draw, &s_arach1}; + +/* +=========================== += += SpawnArachnut += +=========================== +*/ + +void SpawnArachnut(Sint16 x, Sint16 y) +{ + GetNewObj(false); + new->obclass = arachnutobj; + new->active = ac_yes; + new->priority = 0; + new->x = CONVERT_TILE_TO_GLOBAL(x); + new->y = CONVERT_TILE_TO_GLOBAL(y) - 0x171; + if (US_RndT() < 0x80) + { + new->xdir = 1; + } + else + { + new->xdir = -1; + } + new->ydir = 1; + NewState(new, &s_arach1); +} + +/* +=========================== += += T_Arach += +=========================== +*/ + +void T_Arach(objtype *ob) +{ + if (ob->x > player->x) + { + ob->xdir = -1; + } + else + { + ob->xdir = 1; + } +} + +/* +=========================== += += C_Arach += +=========================== +*/ + +void C_Arach(objtype *ob, objtype *hit) +{ + if (hit->obclass == stunshotobj) + { + StunObj(ob, hit, &s_arachstun); + } + else if (hit->obclass == keenobj) + { + KillKeen(); + } +} + +/* +=========================== += += C_ArachStun += +=========================== +*/ + +void C_ArachStun(objtype *ob, objtype *hit) +{ + if (hit->obclass == stunshotobj) + { + StunObj(ob, hit, &s_arachstun); + } +} + +/* +============================================================================= + + SKYPEST + +============================================================================= +*/ + +statetype s_pestfly1 = {SKYPESTFLYL1SPR, SKYPESTFLYR1SPR, stepthink, true, false, 5, 0, 0, T_PestFly, C_PestFly, R_Pest, &s_pestfly2}; +statetype s_pestfly2 = {SKYPESTFLYL2SPR, SKYPESTFLYR2SPR, stepthink, true, false, 5, 0, 0, T_PestFly, C_PestFly, R_Pest, &s_pestfly1}; +statetype s_squashedpest = {SKYPESTSQUASHEDSPR, SKYPESTSQUASHEDSPR, think, false, false, 0, 0, 0, NULL, NULL, R_Draw, &s_squashedpest}; +statetype s_pestrest1 = {SKYPESTSIT9SPR, SKYPESTSIT9SPR, step, false, false, 100, 0, 0, NULL, C_Squashable, R_Draw, &s_pestrest2}; +statetype s_pestrest2 = {SKYPESTSIT1SPR, SKYPESTSIT1SPR, step, false, false, 10, 0, 0, NULL, C_Squashable, R_Draw, &s_pestrest3}; +statetype s_pestrest3 = {SKYPESTSIT2SPR, SKYPESTSIT2SPR, step, false, false, 10, 0, 0, NULL, C_Squashable, R_Draw, &s_pestrest4}; +statetype s_pestrest4 = {SKYPESTSIT3SPR, SKYPESTSIT3SPR, step, false, false, 10, 0, 0, NULL, C_Squashable, R_Draw, &s_pestrest5}; +statetype s_pestrest5 = {SKYPESTSIT4SPR, SKYPESTSIT4SPR, step, false, false, 10, 0, 0, NULL, C_Squashable, R_Draw, &s_pestrest6}; +statetype s_pestrest6 = {SKYPESTSIT3SPR, SKYPESTSIT3SPR, step, false, false, 10, 0, 0, NULL, C_Squashable, R_Draw, &s_pestrest7}; +statetype s_pestrest7 = {SKYPESTSIT2SPR, SKYPESTSIT2SPR, step, false, false, 10, 0, 0, NULL, C_Squashable, R_Draw, &s_pestrest8}; +statetype s_pestrest8 = {SKYPESTSIT1SPR, SKYPESTSIT1SPR, step, false, false, 10, 0, 0, NULL, C_Squashable, R_Draw, &s_pestrest9}; +statetype s_pestrest9 = {SKYPESTSIT9SPR, SKYPESTSIT9SPR, step, false, false, 60, 0, 0, NULL, C_Squashable, R_Draw, &s_pestrest10}; +statetype s_pestrest10 = {SKYPESTSIT5SPR, SKYPESTSIT5SPR, step, false, false, 10, 0, 0, NULL, C_Squashable, R_Draw, &s_pestrest11}; +statetype s_pestrest11 = {SKYPESTSIT6SPR, SKYPESTSIT6SPR, step, false, false, 10, 0, 0, NULL, C_Squashable, R_Draw, &s_pestrest12}; +statetype s_pestrest12 = {SKYPESTSIT7SPR, SKYPESTSIT7SPR, step, false, false, 10, 0, 0, NULL, C_Squashable, R_Draw, &s_pestrest13}; +statetype s_pestrest13 = {SKYPESTSIT8SPR, SKYPESTSIT8SPR, step, false, false, 10, 0, 0, NULL, C_Squashable, R_Draw, &s_pestrest14}; +statetype s_pestrest14 = {SKYPESTSIT7SPR, SKYPESTSIT7SPR, step, false, false, 10, 0, 0, NULL, C_Squashable, R_Draw, &s_pestrest15}; +statetype s_pestrest15 = {SKYPESTSIT6SPR, SKYPESTSIT6SPR, step, false, false, 10, 0, 0, NULL, C_Squashable, R_Draw, &s_pestrest16}; +statetype s_pestrest16 = {SKYPESTSIT5SPR, SKYPESTSIT5SPR, step, false, false, 10, 0, 0, NULL, C_Squashable, R_Draw, &s_pestrest17}; +statetype s_pestrest17 = {SKYPESTSIT9SPR, SKYPESTSIT9SPR, step, false, false, 100, 0, 0, T_PestRest, C_Squashable, R_Draw, &s_pestfly1}; + +/* +=========================== += += SpawnSkypest += +=========================== +*/ + +void SpawnSkypest(Sint16 x, Sint16 y) +{ + GetNewObj(false); + new->obclass = skypestobj; + new->active = ac_yes; + new->priority = 0; + new->x = CONVERT_TILE_TO_GLOBAL(x); + new->y = CONVERT_TILE_TO_GLOBAL(y); + if (US_RndT() < 0x80) + { + new->xdir = 1; + } + else + { + new->xdir = -1; + } + if (US_RndT() < 0x80) + { + new->ydir = 1; + } + else + { + new->ydir = -1; + } + NewState(new, &s_pestfly1); +} + +/* +=========================== += += T_PestFly += +=========================== +*/ + +void T_PestFly(objtype *ob) +{ + // BUG: this might be executed twice during the same frame if the + // object's animation/state changed during that frame, causing the + // object to move at twice the speed during that frame! + // To avoid that, return if xtry is not 0 or ytry is not 0. + + if (US_RndT() < tics) + ob->xdir = -ob->xdir; + + if (ob->ydir == -1 && US_RndT() < tics) + ob->ydir = 1; + + if (ob->ydir == 1 && US_RndT() < tics*2) + ob->ydir = -ob->ydir; + + AccelerateX(ob, ob->xdir, 20); + AccelerateY(ob, ob->ydir, 20); +} + +/* +=========================== += += C_PestFly += +=========================== +*/ + +void C_PestFly(objtype *ob, objtype *hit) +{ + if (hit->obclass == keenobj) + KillKeen(); + + if (hit->obclass == stunshotobj) + { + if (hit->xdir == 1) + { + ob->xspeed = 20; + } + else if (hit->xdir == -1) + { + ob->xspeed = -20; + } + else if (hit->ydir == 1) + { + ob->yspeed = 20; + } + else if (hit->ydir == -1) + { + ob->yspeed = -20; + } + ExplodeShot(hit); + } +} + +/* +=========================== += += C_Squashable += +=========================== +*/ + +void C_Squashable(objtype *ob, objtype *hit) +{ + if (hit->state == &s_keenpogodown || hit->state == &s_keenpogo || hit->state == &s_keenpogo2) + { + ChangeState(ob, &s_squashedpest); + SD_PlaySound(SND_SQUISH); + ob->obclass = inertobj; + } +} + +/* +=========================== += += T_PestRest += +=========================== +*/ + +void T_PestRest(objtype *ob) +{ + ob->ydir = -1; + ob->yspeed = -16; + ytry = -144; +} + +/* +=========================== += += R_Pest += +=========================== +*/ + +void R_Pest(objtype *ob) +{ + if (ob->hitsouth) + { + ob->yspeed = 8; + ob->ydir = 1; + } + if (ob->hitnorth && !ob->hiteast && !ob->hitwest) + { + ob->y += 8*PIXGLOBAL; + ChangeState(ob, &s_pestrest1); + } + if (ob->hitwest) + { + ob->xspeed = 0; + ob->xdir = -1; + } + if (ob->hiteast) + { + ob->xspeed = 0; + ob->xdir = 1; + } + RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority); +}