1 /* Reconstructed Commander Keen 4-6 Source Code
\r
2 * Copyright (C) 2021 K1n9_Duk3
\r
4 * This file is loosely based on:
\r
5 * Keen Dreams Source Code
\r
6 * Copyright (C) 2014 Javier M. Chavez
\r
8 * This program is free software; you can redistribute it and/or modify
\r
9 * it under the terms of the GNU General Public License as published by
\r
10 * the Free Software Foundation; either version 2 of the License, or
\r
11 * (at your option) any later version.
\r
13 * This program is distributed in the hope that it will be useful,
\r
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
16 * GNU General Public License for more details.
\r
18 * You should have received a copy of the GNU General Public License along
\r
19 * with this program; if not, write to the Free Software Foundation, Inc.,
\r
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\r
27 Contains the following actor types (in this order):
\r
36 - Dart Shooter & Dart
\r
44 =============================================================================
\r
48 temp1 = turn counter
\r
50 =============================================================================
\r
53 statetype s_eaterstand1 = {EATERSTAND1SPR, EATERSTAND1SPR, step, false, false, 20, 0, 0, NULL, C_Eater, R_Draw, &s_eaterstand2};
\r
54 statetype s_eaterstand2 = {EATERSTAND2SPR, EATERSTAND2SPR, step, false, false, 20, 0, 0, T_EaterJump, C_Eater, R_Draw, NULL};
\r
55 statetype s_eatertport1 = {SMOKE1SPR, SMOKE1SPR, step, false, false, 20, 0, 0, NULL, C_Eater, R_Draw, &s_eatertport2};
\r
56 statetype s_eatertport2 = {SMOKE2SPR, SMOKE2SPR, step, false, false, 20, 0, 0, NULL, C_Eater, R_Draw, &s_eatertport3};
\r
57 statetype s_eatertport3 = {SMOKE3SPR, SMOKE3SPR, step, false, false, 20, 0, 0, NULL, C_Eater, R_Draw, &s_eatertport4};
\r
58 statetype s_eatertport4 = {SMOKE4SPR, SMOKE4SPR, step, false, false, 20, 0, 0, T_EaterTeleport, C_Eater, R_Draw, &s_eatertport5};
\r
59 statetype s_eatertport5 = {SMOKE4SPR, SMOKE4SPR, step, false, false, 20, 0, 0, NULL, C_Eater, R_Draw, &s_eatertport6};
\r
60 statetype s_eatertport6 = {SMOKE3SPR, SMOKE3SPR, step, false, false, 20, 0, 0, NULL, C_Eater, R_Draw, &s_eatertport7};
\r
61 statetype s_eatertport7 = {SMOKE2SPR, SMOKE2SPR, step, false, false, 20, 0, 0, NULL, C_Eater, R_Draw, &s_eatertport8};
\r
62 statetype s_eatertport8 = {SMOKE1SPR, SMOKE1SPR, step, false, false, 20, 0, 0, NULL, C_Eater, R_Draw, &s_eaterjump1};
\r
63 statetype s_eaterjump1 = {EATERJUMPL1SPR, EATERJUMPR1SPR, stepthink, false, false, 6, 0, 0, T_WeakProjectile, C_Eater, R_EaterAir, &s_eaterjump2};
\r
64 statetype s_eaterjump2 = {EATERJUMPL2SPR, EATERJUMPR2SPR, stepthink, false, false, 6, 0, 0, T_WeakProjectile, C_Eater, R_EaterAir, &s_eaterjump3};
\r
65 statetype s_eaterjump3 = {EATERJUMPL3SPR, EATERJUMPR3SPR, stepthink, false, false, 6, 0, 0, T_WeakProjectile, C_Eater, R_EaterAir, &s_eaterjump4};
\r
66 statetype s_eaterjump4 = {EATERJUMPL2SPR, EATERJUMPR2SPR, stepthink, false, false, 6, 0, 0, T_WeakProjectile, C_Eater, R_EaterAir, &s_eaterjump1};
\r
67 statetype s_eaterstun = {EATERJUMPL1SPR, EATERJUMPL1SPR, think, false, false, 0, 0, 0, T_Projectile, 0, R_Stunned, &s_eaterstun2};
\r
68 statetype s_eaterstun2 = {EATERSTUNSPR, EATERSTUNSPR, think, false, false, 0, 0, 0, T_Projectile, 0, R_Stunned, NULL};
\r
70 statetype s_eatenbonus1 = {EATENBONUS1SPR, EATENBONUS1SPR, slide, false, false, 10, 0, 8, NULL, NULL, R_Draw, &s_eatenbonus2};
\r
71 statetype s_eatenbonus2 = {EATENBONUS2SPR, EATENBONUS2SPR, slide, false, false, 10, 0, 8, NULL, NULL, R_Draw, &s_eatenbonus3};
\r
72 statetype s_eatenbonus3 = {EATENBONUS3SPR, EATENBONUS3SPR, slide, false, false, 10, 0, 8, NULL, NULL, R_Draw, &s_eatenbonus4};
\r
73 statetype s_eatenbonus4 = {EATENBONUS4SPR, EATENBONUS4SPR, slide, false, false, 10, 0, 8, NULL, NULL, R_Draw, NULL};
\r
76 ===========================
\r
80 ===========================
\r
83 void SpawnEater(Sint16 x, Sint16 y)
\r
86 new->obclass = treasureeaterobj;
\r
87 new->active = ac_yes;
\r
89 new->x = CONVERT_TILE_TO_GLOBAL(x);
\r
90 new->y = CONVERT_TILE_TO_GLOBAL(y) - 24*PIXGLOBAL;
\r
91 if (US_RndT() < 0x80)
\r
100 NewState(new, &s_eaterstand1);
\r
104 ===========================
\r
108 ===========================
\r
111 void T_EaterJump(objtype *ob)
\r
117 Uint16 intile, rowdiff, width;
\r
119 ob->state = &s_eaterjump1;
\r
121 //jump straight up if below bonus object:
\r
122 for (ob2 = player->next; ob2; ob2 = ob2->next)
\r
124 if (ob2->obclass == bonusobj && ob2->active == ac_yes
\r
125 && ob2->right > ob->left && ob2->left < ob->right
\r
126 && ob2->bottom < ob->top && ob2->bottom + 3*TILEGLOBAL > ob->top)
\r
134 //jump straight up if below bonus tile:
\r
135 map = mapsegs[1] + mapbwidthtable[ob->tiletop-3]/2 + ob->tileleft;
\r
136 width = ob->tileright-ob->tileleft+1;
\r
137 rowdiff = mapwidth-width;
\r
138 for (y=0; y<3; y++, map+=rowdiff)
\r
140 for (x=0; x<width; x++, map++)
\r
142 intile = tinf[INTILE+*map];
\r
143 if (intile == INTILE_DROP || intile >= INTILE_BONUS100 && intile <= INTILE_AMMO)
\r
152 //vanish after having checked both directions:
\r
153 if (ob->temp1 >= 2)
\r
155 // BUG? this doesn't play a sound
\r
156 ob->state = &s_eatertport1;
\r
160 //jump in current direction if there is a floor in that direction:
\r
161 map = mapsegs[1] + mapbwidthtable[ob->tilebottom-2]/2 + ob->tilemidx;
\r
162 map += ob->xdir * 4;
\r
163 for (y=0; y<4; y++, map+=mapwidth)
\r
165 if (tinf[NORTHWALL+*map])
\r
167 ob->xspeed = ob->xdir * 20;
\r
173 //couldn't jump in current direction, so turn around:
\r
174 if (++ob->temp1 == 2)
\r
176 SD_PlaySound(SND_TREASUREEATERVANISH);
\r
177 ob->state = &s_eatertport1;
\r
181 //jump in opposite direction:
\r
182 ob->xdir = -ob->xdir;
\r
183 ob->xspeed = ob->xdir * 20;
\r
188 ===========================
\r
192 ===========================
\r
195 void T_EaterTeleport(objtype *ob)
\r
200 for (ob2=player->next; ob2; ob2=ob2->next)
\r
202 if (ob2->obclass == bonusobj)
\r
204 ob->x = ob2->x - 8*PIXGLOBAL;
\r
206 NewState(ob, &s_eatertport5);
\r
214 ===========================
\r
218 ===========================
\r
221 void C_Eater(objtype *ob, objtype *hit)
\r
223 if (hit->obclass == bonusobj)
\r
225 //BUG? bonus object might be a key, and eating a key makes a level unwinnable
\r
226 hit->obclass = inertobj;
\r
228 ChangeState(hit, &s_eatenbonus1);
\r
229 SD_PlaySound(SND_EATBONUS);
\r
231 else if (hit->obclass == stunshotobj)
\r
233 //basically StunObj(), but in different order:
\r
237 ob->temp4 = ob->obclass;
\r
238 ob->obclass = stunnedobj;
\r
240 ChangeState(ob, &s_eaterstun);
\r
247 ===========================
\r
251 ===========================
\r
254 void EaterInTile(objtype *ob)
\r
258 Uint16 rowdiff, intile;
\r
260 map = mapsegs[1] + mapbwidthtable[ob->tiletop]/2 + ob->tileleft;
\r
261 rowdiff = mapwidth-(ob->tileright-ob->tileleft+1);
\r
262 for (y=ob->tiletop; y<=ob->tilebottom; y++, map+=rowdiff)
\r
264 for (x=ob->tileleft; x<=ob->tileright; x++, map++)
\r
266 intile = tinf[INTILE + *map] & INTILE_TYPEMASK;
\r
267 if (intile == INTILE_DROP || intile >= INTILE_BONUS100 && intile <= INTILE_AMMO)
\r
269 RF_MemToMap(&zeromap, 1, x, y, 1, 1);
\r
271 new->obclass = inertobj;
\r
273 new->needtoclip = cl_noclip;
\r
274 new->x = CONVERT_TILE_TO_GLOBAL(x);
\r
275 new->y = CONVERT_TILE_TO_GLOBAL(y);
\r
276 new->active = ac_removable;
\r
277 ChangeState(new, &s_eatenbonus1); //using ChangeState and not NewState is fine for noclipping objects
\r
278 //BUG? this doesn't play a sound
\r
286 ===========================
\r
290 ===========================
\r
293 void R_EaterAir(objtype *ob)
\r
298 ChangeState(ob, &s_eaterstand1);
\r
300 if (ob->hiteast || ob->hitwest)
\r
303 ob->xdir = -ob->xdir;
\r
307 if (ob->hitnorth) //BUG? maybe this was supposed to check hitsouth as well?
\r
310 RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);
\r
314 =============================================================================
\r
318 =============================================================================
\r
321 statetype s_mimrock = {MIMROCKSPR, MIMROCKSPR, step, false, true, 20, 0, 0, T_MimrockWait, NULL, R_Walk, &s_mimrock};
\r
322 statetype s_mimsneak1 = {MIMROCKWALKR1SPR, MIMROCKWALKL1SPR, step, false, true, 6, 64, 0, T_MimrockSneak, C_Mimrock, R_Walk, &s_mimsneak2};
\r
323 statetype s_mimsneak2 = {MIMROCKWALKR2SPR, MIMROCKWALKL2SPR, step, false, true, 6, 64, 0, T_MimrockSneak, C_Mimrock, R_Walk, &s_mimsneak3};
\r
324 statetype s_mimsneak3 = {MIMROCKWALKR3SPR, MIMROCKWALKL3SPR, step, false, true, 6, 64, 0, T_MimrockSneak, C_Mimrock, R_Walk, &s_mimsneak4};
\r
325 statetype s_mimsneak4 = {MIMROCKWALKR4SPR, MIMROCKWALKL4SPR, step, false, true, 6, 64, 0, T_MimrockSneak, C_Mimrock, R_Walk, &s_mimsneak5};
\r
326 statetype s_mimsneak5 = {MIMROCKWALKR1SPR, MIMROCKWALKL1SPR, step, false, true, 6, 64, 0, T_MimrockSneak, C_Mimrock, R_Walk, &s_mimsneak6};
\r
327 statetype s_mimsneak6 = {MIMROCKWALKR2SPR, MIMROCKWALKL2SPR, step, false, true, 6, 64, 0, T_MimrockSneak, C_Mimrock, R_Walk, &s_mimrock};
\r
328 statetype s_mimbonk1 = {MIMROCKJUMPL1SPR, MIMROCKJUMPR1SPR, stepthink, false, false, 24, 0, 0, T_WeakProjectile, C_MimLethal, R_MimAir, &s_mimbonk2};
\r
329 statetype s_mimbonk2 = {MIMROCKJUMPL2SPR, MIMROCKJUMPR2SPR, stepthink, false, false, 10, 0, 0, T_WeakProjectile, C_MimLethal, R_MimAir, &s_mimbonk3};
\r
330 statetype s_mimbonk3 = {MIMROCKJUMPL3SPR, MIMROCKJUMPR3SPR, think, false, false, 10, 0, 0, T_WeakProjectile, C_MimLethal, R_MimAir, &s_mimbonk2};
\r
331 statetype s_mimbounce = {MIMROCKJUMPL3SPR, MIMROCKJUMPR3SPR, think, false, false, 10, 0, 0, T_Projectile, C_Mimrock, R_MimBounce, NULL};
\r
332 statetype s_mimstun = {MIMROCKJUMPL3SPR, MIMROCKJUMPL3SPR, think, false, false, 12, 0, 0, T_Projectile, NULL, R_Stunned, &s_mimstun2};
\r
333 statetype s_mimstun2 = {MINROCKSTUNSPR, MINROCKSTUNSPR, think, false, false, 12, 0, 0, T_Projectile, NULL, R_Stunned, NULL};
\r
336 ===========================
\r
340 ===========================
\r
343 void SpawnMimrock(Sint16 x, Sint16 y)
\r
346 new->obclass = mimrockobj;
\r
347 new->active = ac_yes;
\r
349 new->x = CONVERT_TILE_TO_GLOBAL(x);
\r
350 new->y = CONVERT_TILE_TO_GLOBAL(y)+ -13*PIXGLOBAL;
\r
351 new->ydir = new->xdir = 1;
\r
352 NewState(new, &s_mimrock);
\r
356 ===========================
\r
360 ===========================
\r
363 void T_MimrockWait(objtype *ob)
\r
365 if (abs(ob->bottom - player->bottom) > 5*TILEGLOBAL)
\r
368 if (abs(ob->x - player->x) > 3*TILEGLOBAL)
\r
370 if (player->x < ob->x)
\r
372 if (player->xdir == -1)
\r
375 ob->state = &s_mimsneak1;
\r
380 if (player->xdir == 1)
\r
383 ob->state = &s_mimsneak1;
\r
390 ===========================
\r
394 ===========================
\r
397 void T_MimrockSneak(objtype *ob)
\r
399 if (abs(ob->bottom - player->bottom) > 5*TILEGLOBAL
\r
400 || ob->xdir != player->xdir)
\r
402 ob->state = &s_mimrock;
\r
404 else if (abs(ob->x - player->x) < 4*TILEGLOBAL)
\r
406 ob->xspeed = ob->xdir * 20;
\r
408 ytry = ob->yspeed * tics;
\r
409 ob->state = &s_mimbonk1;
\r
414 ===========================
\r
418 ===========================
\r
421 void C_Mimrock(objtype *ob, objtype *hit)
\r
423 if (hit->obclass == stunshotobj)
\r
425 //basically StunObj(), but in different order:
\r
429 ob->temp4 = ob->obclass;
\r
430 ob->obclass = stunnedobj;
\r
432 ChangeState(ob, &s_mimstun);
\r
439 ===========================
\r
443 ===========================
\r
446 void C_MimLethal(objtype *ob, objtype *hit)
\r
448 if (hit->obclass == keenobj)
\r
454 C_Mimrock(ob, hit);
\r
459 ===========================
\r
463 ===========================
\r
466 void R_MimAir(objtype *ob)
\r
470 SD_PlaySound(SND_HELMETHIT);
\r
472 ChangeState(ob, &s_mimbounce);
\r
475 if (ob->hiteast || ob->hitwest)
\r
478 if (ob->hitnorth || ob->hitsouth)
\r
481 RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);
\r
485 ===========================
\r
489 ===========================
\r
492 void R_MimBounce(objtype *ob)
\r
496 SD_PlaySound(SND_HELMETHIT);
\r
497 ChangeState(ob, &s_mimrock);
\r
500 if (ob->hiteast || ob->hitwest)
\r
506 RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);
\r
510 =============================================================================
\r
514 temp1 = blocked (cannot change xdir to chase Keen while this is non-zero)
\r
515 temp2 = old x position
\r
516 temp3 = old y position
\r
517 temp4 = pointer to object being eaten
\r
518 (BUG: pointer may be invalid after loading a saved game!)
\r
520 =============================================================================
\r
523 statetype s_dopefish1 = {DOPEFISHSWIML1SPR, DOPEFISHSWIMR1SPR, stepthink, false, false, 20, 0, 0, T_Dope, C_Dope, R_Fish, &s_dopefish2};
\r
524 statetype s_dopefish2 = {DOPEFISHSWIML2SPR, DOPEFISHSWIMR2SPR, stepthink, false, false, 20, 0, 0, T_Dope, C_Dope, R_Fish, &s_dopefish1};
\r
525 statetype s_dopeattack = {DOPEFISHHUNGRYLSPR, DOPEFISHHUNGRYRSPR, think, false, false, 0, 0, 0, T_DopeHunt, NULL, R_Draw, NULL};
\r
526 statetype s_dopeeat = {DOPEFISHSWIML1SPR, DOPEFISHSWIMR1SPR, step, false, false, 60, 0, 0, NULL, NULL, R_Draw, &s_dopeburp1};
\r
527 statetype s_dopeburp1 = {DOPEFISHBURP1SPR, DOPEFISHBURP1SPR, step, false, false, 60, 0, 0, T_Burp, NULL, R_Draw, &s_dopeburp2};
\r
528 statetype s_dopeburp2 = {DOPEFISHBURP2SPR, DOPEFISHBURP2SPR, step, false, false, 60, 0, 0, NULL, NULL, R_Draw, &s_dopereturn};
\r
529 statetype s_dopereturn = {DOPEFISHSWIML1SPR, DOPEFISHSWIMR1SPR, think, false, false, 0, 0, 0, T_DopeReturn, NULL, R_Draw, &s_dopefish1};
\r
531 statetype s_dopefood = {SCHOOLFISHL1SPR, SCHOOLFISHR1SPR, think, false, false, 0, 0, 0, NULL, NULL, R_Draw, NULL};
\r
532 statetype s_keendopefood = {SCUBAKEENDEAD1SPR, SCUBAKEENDEAD1SPR, think, false, false, 0, 0, 0, NULL, NULL, R_Draw, &s_keendieslow};
\r
533 statetype s_keendieslow = {-1, -1, step, false, false, 180, 0, 0, T_EatenKeen, NULL, R_Draw, &s_keendieslow};
\r
535 statetype s_bubble1 = {BIGBUBBLE1SPR, BIGBUBBLE1SPR, think, false, false, 20, 0, 20, T_Bubble, NULL, R_Draw, &s_bubble2};
\r
536 statetype s_bubble2 = {BIGBUBBLE2SPR, BIGBUBBLE2SPR, think, false, false, 20, 0, 20, T_Bubble, NULL, R_Draw, &s_bubble3};
\r
537 statetype s_bubble3 = {BIGBUBBLE3SPR, BIGBUBBLE3SPR, think, false, false, 20, 0, 20, T_Bubble, NULL, R_Draw, &s_bubble4};
\r
538 statetype s_bubble4 = {BIGBUBBLE4SPR, BIGBUBBLE4SPR, think, false, false, 20, 0, 20, T_Bubble, NULL, R_Draw, &s_bubble1};
\r
541 ===========================
\r
545 ===========================
\r
548 void SpawnDopefish(Sint16 x, Sint16 y)
\r
551 new->obclass = dopefishobj;
\r
552 new->active = ac_yes;
\r
554 new->needtoclip = cl_fullclip;
\r
555 new->x = CONVERT_TILE_TO_GLOBAL(x);
\r
556 new->y = CONVERT_TILE_TO_GLOBAL(y) + -3*TILEGLOBAL;
\r
557 if (US_RndT() < 0x80)
\r
566 NewState(new, &s_dopefish1);
\r
570 ===========================
\r
574 ===========================
\r
577 void T_EatenKeen(objtype *ob)
\r
579 ob++; // shut up compiler
\r
580 playstate = ex_died;
\r
584 ===========================
\r
588 ===========================
\r
591 void T_Dope(objtype *ob)
\r
593 if (ob->temp1 == 0)
\r
595 if (ob->x < player->x)
\r
604 AccelerateXv(ob, ob->xdir, 10);
\r
606 if (ob->y < player->y)
\r
608 AccelerateY(ob, 1, 10);
\r
612 AccelerateY(ob, -1, 10);
\r
617 ===========================
\r
621 ===========================
\r
624 void T_DopeHunt(objtype *ob)
\r
627 Sint16 xdist, ydist;
\r
629 target = (objtype *)(ob->temp4);
\r
630 ydist = target->y - TILEGLOBAL - ob->y;
\r
633 xdist = target->right + 2*PIXGLOBAL - ob->right;
\r
637 xdist = target->left - 2*PIXGLOBAL - ob->left;
\r
666 if (xtry == xdist && ytry == ydist)
\r
668 if (target == player)
\r
670 ChangeState(target, &s_keendieslow);
\r
672 else if (target->state->nextstate)
\r
674 ChangeState(target, target->state->nextstate);
\r
680 ob->state = &s_dopeeat;
\r
685 ===========================
\r
689 ===========================
\r
692 void T_DopeReturn(objtype *ob)
\r
694 Sint16 xdist, ydist;
\r
696 ydist = ob->temp3 - ob->y;
\r
697 xdist = ob->temp2 - ob->x;
\r
725 if (xtry == xdist && ytry == ydist)
\r
727 ob->state = ob->state->nextstate;
\r
728 ob->needtoclip = cl_fullclip;
\r
733 ===========================
\r
737 ===========================
\r
740 void T_Burp(objtype *ob)
\r
743 new->x = ob->x + 56*PIXGLOBAL;
\r
744 new->y = ob->y + 32*PIXGLOBAL;
\r
745 new->obclass = inertobj;
\r
747 new->active = ac_removable;
\r
748 new->needtoclip = cl_noclip;
\r
751 NewState(new, &s_bubble1);
\r
752 SD_PlaySound(SND_BURP);
\r
756 ===========================
\r
760 ===========================
\r
763 void T_Bubble(objtype *ob)
\r
766 if (US_RndT() < tics * 16)
\r
767 ob->xspeed = -ob->xspeed;
\r
769 if (ob->y < 3*TILEGLOBAL)
\r
774 ===========================
\r
778 ===========================
\r
781 void C_Dope(objtype *ob, objtype *hit)
\r
783 if (hit->obclass == schoolfishobj)
\r
785 ChangeState(hit, &s_dopefood);
\r
787 else if (hit->obclass == keenobj && !godmode)
\r
789 hit->obclass = inertobj; //prevents other objects from killing Keen before he is fully swallowed
\r
790 hit->needtoclip = cl_noclip;
\r
791 SD_PlaySound(SND_KEENDEAD);
\r
792 ChangeState(hit, &s_keendopefood);
\r
801 ob->temp4 = (Sint16)hit;
\r
802 if (hit->midx < ob->midx)
\r
810 ChangeState(ob, &s_dopeattack);
\r
811 ob->needtoclip = cl_noclip;
\r
815 ===========================
\r
819 ===========================
\r
822 void R_Fish(objtype *ob) //for Dopefish and Schoolfish
\r
824 if ((ob->hitsouth || ob->hitnorth) && ob->temp1 == 0)
\r
827 if (ob->hiteast || ob->hitwest)
\r
830 ob->xdir = -ob->xdir;
\r
834 if (!ob->hitsouth && !ob->hitnorth)
\r
837 RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);
\r
841 =============================================================================
\r
845 temp1 = blocked (cannot change xdir to chase Keen while this is non-zero)
\r
847 =============================================================================
\r
850 statetype s_schoolfish1 = {SCHOOLFISHL1SPR, SCHOOLFISHR1SPR, stepthink, false, false, 20, 0, 0, T_SchoolFish, NULL, R_Fish, &s_schoolfish2};
\r
851 statetype s_schoolfish2 = {SCHOOLFISHL2SPR, SCHOOLFISHR2SPR, stepthink, false, false, 20, 0, 0, T_SchoolFish, NULL, R_Fish, &s_schoolfish1};
\r
854 ===========================
\r
858 ===========================
\r
861 void SpawnSchoolfish(Sint16 x, Sint16 y)
\r
864 new->obclass = schoolfishobj;
\r
865 new->active = ac_yes;
\r
866 new->needtoclip = cl_fullclip;
\r
868 new->x = CONVERT_TILE_TO_GLOBAL(x);
\r
869 new->y = CONVERT_TILE_TO_GLOBAL(y);
\r
870 new->ydir = new->xdir = 1;
\r
871 NewState(new, &s_schoolfish1);
\r
875 ===========================
\r
879 ===========================
\r
882 void T_SchoolFish(objtype *ob)
\r
884 if (ob->temp1 == 0)
\r
886 if (ob->x < player->x)
\r
895 AccelerateXv(ob, ob->xdir, 10);
\r
897 if (ob->y < player->y)
\r
899 AccelerateY(ob, 1, 10);
\r
903 AccelerateY(ob, -1, 10);
\r
908 =============================================================================
\r
910 PIXIE (a.k.a. SPRITE)
\r
912 =============================================================================
\r
915 statetype s_pixie = {SPRITEFLOATSPR, SPRITEFLOATSPR, think, false, false, 10, 0, 0, T_Pixie, C_Lethal, R_Draw, &s_pixie};
\r
916 statetype s_pixielook = {SPRITEAIMLSPR, SPRITEAIMRSPR, step, false, false, 40, 0, 0, T_PixieCheck, C_Lethal, R_Draw, &s_pixie};
\r
917 statetype s_pixieshoot = {SPRITESHOOTLSPR, SPRITESHOOTRSPR, step, false, false, 40, 0, 0, T_PixieShoot, C_Lethal, R_Draw, &s_pixieshoot2};
\r
918 statetype s_pixieshoot2 = {SPRITESHOOTLSPR, SPRITESHOOTRSPR, step, false, false, 30, 0, 0, NULL, C_Lethal, R_Draw, &s_pixie};
\r
919 statetype s_pixiefire1 = {SPRITESHOT1SPR, SPRITESHOT1SPR, slide, false, false, 10, 64, 0, NULL, C_Lethal, R_Mshot, &s_pixiefire2};
\r
920 statetype s_pixiefire2 = {SPRITESHOT2SPR, SPRITESHOT2SPR, slide, false, false, 10, 64, 0, NULL, C_Lethal, R_Mshot, &s_pixiefire3};
\r
921 statetype s_pixiefire3 = {SPRITESHOT3SPR, SPRITESHOT3SPR, slide, false, false, 10, 64, 0, NULL, C_Lethal, R_Mshot, &s_pixiefire4};
\r
922 statetype s_pixiefire4 = {SPRITESHOT4SPR, SPRITESHOT4SPR, slide, false, false, 10, 64, 0, NULL, C_Lethal, R_Mshot, &s_pixiefire1};
\r
925 ===========================
\r
929 ===========================
\r
932 void SpawnPixie(Sint16 x, Sint16 y)
\r
935 new->obclass = pixieobj;
\r
936 new->active = ac_yes;
\r
938 new->needtoclip = cl_noclip;
\r
939 new->x = CONVERT_TILE_TO_GLOBAL(x);
\r
940 new->y = new->temp1 = CONVERT_TILE_TO_GLOBAL(y);
\r
941 new->ydir = new->xdir = 1;
\r
942 NewState(new, &s_pixie);
\r
946 ===========================
\r
950 ===========================
\r
953 void T_Pixie(objtype *ob)
\r
955 AccelerateY(ob, ob->ydir, 8);
\r
956 if ((Sint16)(ob->temp1 - ob->y) > 2*PIXGLOBAL)
\r
960 if ((Sint16)(ob->y - ob->temp1) > 2*PIXGLOBAL)
\r
965 if (player->top < ob->bottom && player->bottom > ob->top)
\r
967 if (player->x < ob->x)
\r
975 ob->state = &s_pixielook;
\r
980 ===========================
\r
984 ===========================
\r
987 void T_PixieCheck(objtype *ob)
\r
989 if (player->top < ob->bottom && player->bottom > ob->top)
\r
990 ob->state = &s_pixieshoot;
\r
994 ===========================
\r
998 ===========================
\r
1001 void T_PixieShoot(objtype *ob)
\r
1005 new->y = ob->y + 8*PIXGLOBAL;
\r
1006 new->priority = 0;
\r
1007 new->obclass = mshotobj;
\r
1008 new->active = ac_removable;
\r
1009 SD_PlaySound(SND_KEENFIRE); //BUG?
\r
1010 new->xdir = ob->xdir;
\r
1011 NewState(new, &s_pixiefire1);
\r
1012 SD_PlaySound(SND_SPRITEFIRE);
\r
1016 ===========================
\r
1020 ===========================
\r
1023 void R_Mshot(objtype *ob)
\r
1025 if (ob->hitnorth || ob->hiteast || ob->hitsouth || ob->hitwest)
\r
1031 RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);
\r
1036 =============================================================================
\r
1040 =============================================================================
\r
1042 statetype s_mine = {MINESPR, MINESPR, think, false, false, 10, 0, 0, T_Platform, C_Mine, R_Draw, &s_mine};
\r
1043 statetype s_mineboom1 = {MINEEXPLODE1SPR, MINEEXPLODE1SPR, step, false, false, 30, 0, 0, NULL, NULL, R_Draw, &s_mineboom2};
\r
1044 statetype s_mineboom2 = {MINEEXPLODE2SPR, MINEEXPLODE2SPR, step, false, false, 30, 0, 0, NULL, NULL, R_Draw, NULL};
\r
1047 ===========================
\r
1051 ===========================
\r
1054 void SpawnMine(Sint16 x, Sint16 y, Sint16 dir)
\r
1057 new->obclass = mineobj;
\r
1058 new->active = ac_allways;
\r
1059 new->priority = 0;
\r
1060 new->x = CONVERT_TILE_TO_GLOBAL(x);
\r
1061 new->y = CONVERT_TILE_TO_GLOBAL(y);
\r
1081 NewState(new, &s_mine);
\r
1085 ===========================
\r
1089 ===========================
\r
1092 void C_Mine(objtype *ob, objtype *hit)
\r
1094 if (hit->obclass == keenobj)
\r
1096 ChangeState(ob, &s_mineboom1);
\r
1097 SD_PlaySound(SND_MINEEXPLODE);
\r
1103 =============================================================================
\r
1107 temp1 = initial y position
\r
1109 =============================================================================
\r
1111 statetype s_lindsey1 = {LINDSEY1SPR, LINDSEY1SPR, stepthink, false, false, 20, 0, 0, T_Lindsey, NULL, R_Draw, &s_lindsey2};
\r
1112 statetype s_lindsey2 = {LINDSEY2SPR, LINDSEY2SPR, stepthink, false, false, 20, 0, 0, T_Lindsey, NULL, R_Draw, &s_lindsey3};
\r
1113 statetype s_lindsey3 = {LINDSEY3SPR, LINDSEY3SPR, stepthink, false, false, 20, 0, 0, T_Lindsey, NULL, R_Draw, &s_lindsey4};
\r
1114 statetype s_lindsey4 = {LINDSEY4SPR, LINDSEY4SPR, stepthink, false, false, 20, 0, 0, T_Lindsey, NULL, R_Draw, &s_lindsey1};
\r
1117 ===========================
\r
1121 ===========================
\r
1124 void SpawnLindsey(Sint16 x, Sint16 y)
\r
1127 new->obclass = lindseyobj;
\r
1128 new->active = ac_yes;
\r
1129 new->priority = 0;
\r
1130 new->x = CONVERT_TILE_TO_GLOBAL(x);
\r
1131 new->y = new->temp1 = CONVERT_TILE_TO_GLOBAL(y) - TILEGLOBAL;
\r
1133 NewState(new, &s_lindsey1);
\r
1137 ===========================
\r
1141 ===========================
\r
1144 void T_Lindsey(objtype *ob)
\r
1146 AccelerateY(ob, ob->ydir, 8);
\r
1147 if (ob->temp1 - (Sint16)ob->y > 2*PIXGLOBAL)
\r
1151 if ((Sint16)ob->y - ob->temp1 > 2*PIXGLOBAL)
\r
1158 =============================================================================
\r
1164 =============================================================================
\r
1167 statetype s_dartthrower = {0, 0, step, false, false, 150, 0, 0, T_DartShoot, NULL, NULL, &s_dartthrower};
\r
1168 statetype s_dart1 = {DARTL1SPR, DARTR1SPR, slide, false, false, 6, 64, 0, NULL, C_Lethal, R_Mshot, &s_dart2};
\r
1169 statetype s_dart2 = {DARTL2SPR, DARTR2SPR, slide, false, false, 6, 64, 0, NULL, C_Lethal, R_Mshot, &s_dart1};
\r
1170 statetype s_dartup1 = {DARTU1SPR, DARTU1SPR, slide, false, false, 6, 0, 64, NULL, C_Lethal, R_Mshot, &s_dartup2};
\r
1171 statetype s_dartup2 = {DARTU2SPR, DARTU2SPR, slide, false, false, 6, 0, 64, NULL, C_Lethal, R_Mshot, &s_dartup1};
\r
1172 statetype s_dartdown1 = {DARTD1SPR, DARTD1SPR, slide, false, false, 6, 0, 64, NULL, C_Lethal, R_Mshot, &s_dartdown2};
\r
1173 statetype s_dartdown2 = {DARTD2SPR, DARTD2SPR, slide, false, false, 6, 0, 64, NULL, C_Lethal, R_Mshot, &s_dartdown1};
\r
1176 ===========================
\r
1178 = SpawnDartShooter
\r
1180 ===========================
\r
1183 void SpawnDartShooter(Sint16 x, Sint16 y, Sint16 dir)
\r
1186 new->obclass = inertobj;
\r
1187 new->active = ac_yes;
\r
1188 new->x = CONVERT_TILE_TO_GLOBAL(x);
\r
1189 new->needtoclip = cl_noclip;
\r
1190 new->y = CONVERT_TILE_TO_GLOBAL(y);
\r
1195 new->y -= 3*PIXGLOBAL;
\r
1196 new->x += 9*PIXGLOBAL;
\r
1197 new->shapenum = DARTU1SPR;
\r
1200 new->x += 8*PIXGLOBAL;
\r
1201 new->y += 5*PIXGLOBAL;
\r
1202 new->shapenum = DARTR1SPR;
\r
1205 new->x += 9*PIXGLOBAL;
\r
1206 new->shapenum = DARTD1SPR;
\r
1209 new->y += 7*PIXGLOBAL;
\r
1210 new->x -= 3*PIXGLOBAL;
\r
1211 new->shapenum = DARTL1SPR;
\r
1214 NewState(new, &s_dartthrower);
\r
1218 ===========================
\r
1222 ===========================
\r
1225 void T_DartShoot(objtype *ob)
\r
1230 new->obclass = mshotobj;
\r
1231 new->active = ac_removable;
\r
1232 switch (ob->temp1)
\r
1237 NewState(new, &s_dartup1);
\r
1242 NewState(new, &s_dart1);
\r
1247 NewState(new, &s_dartdown1);
\r
1252 NewState(new, &s_dart1);
\r
1255 SD_PlaySound(SND_SHOOTDART);
\r
1259 ===========================
\r
1263 ===========================
\r
1266 void R_DartThrower(objtype *ob) //never used
\r
1268 RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);
\r
1272 =============================================================================
\r
1276 =============================================================================
\r
1278 statetype s_scuba = {SCUBASPR, SCUBASPR, step, false, false, 30000, 0, 0, NULL, C_Scuba, R_Draw, &s_scuba};
\r
1281 ===========================
\r
1285 ===========================
\r
1288 void SpawnScuba(Sint16 x, Sint16 y)
\r
1291 new->obclass = scubaobj;
\r
1292 new->active = ac_yes;
\r
1293 new->x = CONVERT_TILE_TO_GLOBAL(x);
\r
1294 new->y = CONVERT_TILE_TO_GLOBAL(y) + -TILEGLOBAL;
\r
1295 NewState(new, &s_scuba);
\r
1299 ===========================
\r
1303 ===========================
\r
1306 void C_Scuba(objtype *ob, objtype *hit)
\r
1308 if (hit->obclass == keenobj && hit->hitnorth)
\r
1310 gamestate.wetsuit = true;
\r
1311 SD_PlaySound(SND_MAKEFOOT);
\r
1313 RF_ForceRefresh();
\r
1314 playstate = ex_completed;
\r
1315 ob++; // shut up compiler
\r