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
45 =============================================================================
\r
49 temp2 = x position of the "eye", in global units (relative to the mine sprite)
\r
50 temp3 = y position of the "eye", in global units (relative to the mine sprite)
\r
51 temp4 = sprite pointer for the "eye"
\r
53 =============================================================================
\r
56 static Uint16 dopposite[] = {2, 3, 0, 1, 6, 7, 4, 5, 8};
\r
58 statetype s_mine = {SHIKADIMINESPR, SHIKADIMINESPR, think, false, false, 8, 0, 0, T_Mine, C_Solid, R_Mine, NULL};
\r
59 statetype s_minecenter = {SHIKADIMINESPR, SHIKADIMINESPR, think, false, false, 0, 0, 0, T_MineCenter, C_Solid, R_Mine, &s_mineshift};
\r
60 statetype s_mineshift = {SHIKADIMINESPR, SHIKADIMINESPR, think, false, false, 0, 0, 0, T_MineShift, C_Solid, R_Mine, &s_mine};
\r
61 statetype s_mineboom1 = {SHIKADIMINEPULSE1SPR, SHIKADIMINEPULSE1SPR, step, false, false, 10, 0, 0, NULL, C_Solid, R_Draw, &s_mineboom2};
\r
62 statetype s_mineboom2 = {SHIKADIMINEPULSE2SPR, SHIKADIMINEPULSE2SPR, step, false, false, 10, 0, 0, NULL, C_Solid, R_Draw, &s_mineboom3};
\r
63 statetype s_mineboom3 = {SHIKADIMINEPULSE1SPR, SHIKADIMINEPULSE1SPR, step, false, false, 10, 0, 0, NULL, C_Solid, R_Draw, &s_mineboom4};
\r
64 statetype s_mineboom4 = {SHIKADIMINEPULSE2SPR, SHIKADIMINEPULSE2SPR, step, false, false, 10, 0, 0, T_MineFrag, C_Solid, R_Draw, &s_mineboom5};
\r
65 statetype s_mineboom5 = {SHIKADIMINEBOOM1SPR, SHIKADIMINEBOOM1SPR, step, false, false, 20, 0, 0, NULL, C_Spindread, R_Draw, &s_mineboom6};
\r
66 statetype s_mineboom6 = {SHIKADIMINEBOOM2SPR, SHIKADIMINEBOOM2SPR, step, false, false, 20, 0, 0, NULL, C_Spindread, R_Draw, NULL};
\r
67 statetype s_minepiece = {SHIKADIMINEPIECESPR, SHIKADIMINEPIECESPR, think, false, false, 8, 0, 0, T_Projectile, C_MineFrag, R_Bounce, NULL};
\r
70 ===========================
\r
74 ===========================
\r
77 void SpawnMine(Uint16 tileX, Uint16 tileY)
\r
82 new->obclass = mineobj;
\r
83 new->active = ac_yes;
\r
84 new->needtoclip = cl_noclip;
\r
85 new->x = CONVERT_TILE_TO_GLOBAL(tileX);
\r
86 new->y = CONVERT_TILE_TO_GLOBAL(tileY) + -(31*PIXGLOBAL + 1);
\r
87 new->temp2 = 16*PIXGLOBAL;
\r
88 new->temp3 = 13*PIXGLOBAL;
\r
89 NewState(new, &s_mineshift);
\r
90 new->xspeed = TILEGLOBAL;
\r
92 for (i=0; i<=3; i++)
\r
100 ===========================
\r
104 ===========================
\r
107 boolean MinePosCheck(Uint16 tileX, Uint16 tileY)
\r
112 map = mapsegs[1] + mapbwidthtable[tileY]/2 + tileX;
\r
113 for (y=0; y<2; y++)
\r
115 for (x=0; x<3; x++)
\r
117 tile = *(map + y*mapwidth + x);
\r
118 if (tinf[tile+NORTHWALL] || tinf[tile+EASTWALL] || tinf[tile+SOUTHWALL] || tinf[tile+WESTWALL])
\r
126 ===========================
\r
130 ===========================
\r
133 boolean Walk(objtype *ob, Sint16 dir)
\r
135 Uint16 tileX, tileY;
\r
137 tileX = CONVERT_GLOBAL_TO_TILE(ob->x + xtry);
\r
138 tileY = CONVERT_GLOBAL_TO_TILE(ob->y + ytry);
\r
143 if (MinePosCheck(tileX, tileY-1))
\r
151 if (MinePosCheck(tileX+1, tileY))
\r
159 if (MinePosCheck(tileX, tileY+1))
\r
167 if (MinePosCheck(tileX-1, tileY))
\r
175 Quit("Walk: Bad dir");
\r
181 ===========================
\r
185 ===========================
\r
188 void ChaseThink(objtype *ob)
\r
191 Sint16 xdist, ydist, ydir, xdir;
\r
192 Sint16 olddir[2], oppdir;
\r
198 else if (ob->xdir == -1)
\r
202 else if (ob->ydir == -1)
\r
206 else if (ob->ydir == 1)
\r
210 oppdir = dopposite[olddir[0]];
\r
211 xdist = player->x - (ob->x + xtry);
\r
212 ydist = player->y - (ob->y + ytry);
\r
231 if (abs(ydist) > abs(xdist))
\r
237 if (xdir == oppdir)
\r
241 if (ydir == oppdir)
\r
245 if (ydir != 8 && Walk(ob, ydir))
\r
249 if (xdir != 8 && Walk(ob, xdir))
\r
253 if (Walk(ob, olddir[0]))
\r
257 if (US_RndT() > 0x80)
\r
259 for (temp=0; temp<=3; temp++)
\r
261 if (temp != oppdir && Walk(ob, temp))
\r
267 for (temp=3; temp>=0; temp--)
\r
269 if (temp != oppdir && Walk(ob, temp))
\r
277 ===========================
\r
281 ===========================
\r
284 void T_Mine(objtype *ob)
\r
286 Sint16 oldxdir, oldydir;
\r
287 Sint16 xdist, ydist;
\r
290 xdist = ob->x - player->x;
\r
291 ydist = ob->y - player->y;
\r
292 if (xdist <= 2*TILEGLOBAL && xdist >= -5*TILEGLOBAL && ydist <= 3*TILEGLOBAL && ydist >= -5*PIXGLOBAL)
\r
294 SD_PlaySound(SND_MINEEXPLODE);
\r
295 ob->state = &s_mineboom1;
\r
296 RF_RemoveSprite((void**)(&ob->temp4));
\r
301 if (ob->xspeed <= speed)
\r
303 xtry = ob->xdir * ob->xspeed;
\r
304 ytry = ob->ydir * ob->xspeed; // yes, this uses xspeed!
\r
305 speed -= ob->xspeed;
\r
306 oldxdir = ob->xdir;
\r
307 oldydir = ob->ydir;
\r
309 ob->xspeed = TILEGLOBAL;
\r
310 if (ob->xdir != oldxdir || ob->ydir != oldydir)
\r
312 ob->state = &s_minecenter;
\r
316 ob->xspeed -= speed;
\r
317 xtry += ob->xdir * speed;
\r
318 ytry += ob->ydir * speed;
\r
323 ===========================
\r
327 ===========================
\r
331 void C_Solid(objtype *ob, objtype *hit)
\r
333 if (hit->obclass == stunshotobj)
\r
340 ===========================
\r
344 ===========================
\r
348 void C_MineFrag(objtype *ob, objtype *hit)
\r
350 if (hit->obclass == stunshotobj)
\r
354 else if (hit->obclass == keenobj)
\r
358 else if (hit->obclass == qedobj)
\r
360 SpawnFuseFlash(hit->tileleft, hit->tiletop);
\r
361 SpawnFuseFlash(hit->tileright, hit->tiletop);
\r
362 SpawnFuseFlash(hit->tileleft, hit->tilebottom);
\r
363 SpawnFuseFlash(hit->tileright, hit->tilebottom);
\r
364 RF_MapToMap(0, 0, 16, 11, 4, 2);
\r
365 RF_MapToMap(4, 0, 16, 13, 4, 2);
\r
366 SpawnDeadMachine();
\r
372 ===========================
\r
376 ===========================
\r
379 void T_MineCenter(objtype *ob)
\r
381 Sint16 px, py, xdist, ydist;
\r
383 xdist = ob->x - player->x;
\r
384 ydist = ob->y - player->y;
\r
386 if (xdist <= 2*TILEGLOBAL && xdist >= -3*TILEGLOBAL && ydist <= 3*TILEGLOBAL && ydist >= -3*TILEGLOBAL)
\r
388 //BUG? this doesn't play a sound
\r
389 ob->state = &s_mineboom1;
\r
390 RF_RemoveSprite((void**)&ob->temp4);
\r
394 ob->needtoreact = true;
\r
399 if (ob->temp2 < px)
\r
401 ob->temp2 = ob->temp2 + tics*4;
\r
402 if (ob->temp2 >= px)
\r
405 ob->state = ob->state->nextstate;
\r
408 else if (ob->temp2 > px)
\r
410 ob->temp2 = ob->temp2 - tics*4;
\r
411 if (ob->temp2 <= px)
\r
414 ob->state = ob->state->nextstate;
\r
417 if (ob->temp3 < py)
\r
419 ob->temp3 = ob->temp3 + tics*4;
\r
420 if (ob->temp3 >= py)
\r
423 ob->state = ob->state->nextstate;
\r
426 else if (ob->temp3 > py)
\r
428 ob->temp3 = ob->temp3 - tics*4;
\r
429 if (ob->temp3 <= py)
\r
432 ob->state = ob->state->nextstate;
\r
439 ===========================
\r
443 ===========================
\r
446 void T_MineShift(objtype *ob)
\r
448 Sint16 px, py, xdist, ydist;
\r
450 xdist = ob->x - player->x;
\r
451 ydist = ob->y - player->y;
\r
453 if (xdist <= 2*TILEGLOBAL && xdist >= -3*TILEGLOBAL && ydist <= 3*TILEGLOBAL && ydist >= -3*TILEGLOBAL)
\r
455 //BUG? this doesn't play a sound
\r
456 ob->state = &s_mineboom1;
\r
457 RF_RemoveSprite((void**)&ob->temp4);
\r
461 ob->needtoreact = true;
\r
486 if (ob->temp2 < px)
\r
488 ob->temp2 = ob->temp2 + tics*4;
\r
489 if (ob->temp2 >= px)
\r
492 ob->state = ob->state->nextstate;
\r
495 else if (ob->temp2 > px)
\r
497 ob->temp2 = ob->temp2 - tics*4;
\r
498 if (ob->temp2 <= px)
\r
501 ob->state = ob->state->nextstate;
\r
504 if (ob->temp3 < py)
\r
506 ob->temp3 = ob->temp3 + tics*4;
\r
507 if (ob->temp3 >= py)
\r
510 ob->state = ob->state->nextstate;
\r
513 else if (ob->temp3 > py)
\r
515 ob->temp3 = ob->temp3 - tics*4;
\r
516 if (ob->temp3 <= py)
\r
519 ob->state = ob->state->nextstate;
\r
526 ===========================
\r
530 ===========================
\r
533 void T_MineFrag(objtype *ob)
\r
535 SD_PlaySound(SND_MINEEXPLODE);
\r
540 new->xspeed = -(US_RndT()>>3);
\r
542 NewState(new, &s_minepiece);
\r
545 new->x = ob->x + TILEGLOBAL;
\r
547 new->xspeed = (US_RndT()>>3);
\r
549 NewState(new, &s_minepiece);
\r
554 new->xspeed = (US_RndT()>>4) + 40;
\r
556 NewState(new, &s_minepiece);
\r
559 new->x = ob->x + TILEGLOBAL;
\r
561 new->xspeed = -40 - (US_RndT()>>4);
\r
563 NewState(new, &s_minepiece);
\r
570 NewState(new, &s_minepiece);
\r
573 new->x = ob->x + TILEGLOBAL;
\r
577 NewState(new, &s_minepiece);
\r
581 ===========================
\r
585 ===========================
\r
588 void R_Mine(objtype *ob)
\r
590 RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);
\r
591 RF_PlaceSprite((void**)&ob->temp4, ob->x+ob->temp2, ob->y+ob->temp3, SHIKADIMINEEYESPR, spritedraw, 2);
\r
595 =============================================================================
\r
599 temp1 = number of shots to fire
\r
601 =============================================================================
\r
604 statetype s_robored = {ROBOREDLSPR, ROBOREDRSPR, step, false, true, 6, 64, 0, T_RoboRed, C_RoboRed, R_Walk, &s_robored};
\r
605 statetype s_roboredfire0 = {ROBOREDLSPR, ROBOREDRSPR, step, true, true, 40, 0, 0, NULL, C_Spindread, R_Draw, &s_roboredfire1};
\r
606 statetype s_roboredfire1 = {ROBOREDLSPR, ROBOREDRSPR, step, true, true, 4, 64, 0, NULL, C_Spindread, R_Draw, &s_roboredfire2};
\r
607 statetype s_roboredfire2 = {ROBOREDLSPR, ROBOREDRSPR, step, false, true, 6, 0, 0, T_RoboShoot, C_Spindread, R_Draw, &s_roboredfire1};
\r
608 statetype s_rshot1 = {ROBOSHOT1SPR, ROBOSHOT1SPR, stepthink, false, false, 8, 0, 0, T_Velocity, C_RShot, R_RShot, &s_rshot2};
\r
609 statetype s_rshot2 = {ROBOSHOT2SPR, ROBOSHOT2SPR, stepthink, false, false, 8, 0, 0, T_Velocity, C_RShot, R_RShot, &s_rshot1};
\r
610 statetype s_rshothit1 = {ROBOSHOTHIT1SPR, ROBOSHOTHIT1SPR, step, false, false, 10, 0, 0, NULL, NULL, R_Draw, &s_rshothit2};
\r
611 statetype s_rshothit2 = {ROBOSHOTHIT2SPR, ROBOSHOTHIT2SPR, step, false, false, 10, 0, 0, NULL, NULL, R_Draw, NULL};
\r
614 ===========================
\r
618 ===========================
\r
621 void SpawnRoboRed(Uint16 tileX, Uint16 tileY)
\r
624 new->obclass = roboredobj;
\r
625 new->active = ac_yes;
\r
626 new->x = CONVERT_TILE_TO_GLOBAL(tileX);
\r
627 new->y = CONVERT_TILE_TO_GLOBAL(tileY) + -4*TILEGLOBAL;
\r
628 if (US_RndT() < 0x80)
\r
636 NewState(new, &s_robored);
\r
640 ===========================
\r
644 ===========================
\r
647 void T_RoboRed(objtype *ob)
\r
649 if (!(ob->x & (4*PIXGLOBAL)) && player->bottom > ob->top && player->top < ob->bottom && US_RndT() < 16)
\r
651 if (ob->x > player->x)
\r
659 ob->temp1 = 10; // shoot 10 times
\r
660 ob->state = &s_roboredfire0;
\r
665 ===========================
\r
669 ===========================
\r
672 void C_RoboRed(objtype *ob, objtype *hit)
\r
674 if (hit->obclass == stunshotobj)
\r
677 ob->xdir = (player->x > ob->x)? 1 : -1;
\r
678 ob->temp1 = 10; // shoot 10 times
\r
679 ChangeState(ob, &s_roboredfire0);
\r
681 else if (hit->obclass == keenobj)
\r
688 ===========================
\r
692 ===========================
\r
695 void T_RoboShoot(objtype *ob)
\r
699 if (--ob->temp1 == 0)
\r
701 ob->state = &s_robored;
\r
705 x = ob->x + 56*PIXGLOBAL;
\r
711 if (CheckSpawnShot(x, ob->y + 32*PIXGLOBAL, &s_rshot1) != -1)
\r
713 new->xspeed = ob->xdir * 60;
\r
722 SD_PlaySound(SND_ENEMYSHOT);
\r
723 xtry = (ob->xdir == 1)? -4*PIXGLOBAL : 4*PIXGLOBAL;
\r
728 ===========================
\r
732 ===========================
\r
735 void C_RShot(objtype *ob, objtype *hit)
\r
737 if (hit->obclass == keenobj)
\r
740 ChangeState(ob, &s_rshothit1);
\r
745 ===========================
\r
749 ===========================
\r
752 void R_RShot(objtype *ob)
\r
754 if (ob->hitnorth || ob->hiteast || ob->hitsouth || ob->hitwest)
\r
756 SD_PlaySound(SND_ENEMYSHOTEXPLODE);
\r
757 ChangeState(ob, &s_rshothit1);
\r
759 RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);
\r
763 =============================================================================
\r
767 =============================================================================
\r
770 statetype s_gripsitd = {SPIROSITDSPR, SPIROSITDSPR, step, false, false, 150, 0, 0, NULL, C_Spindread, R_Draw, &s_gripjumpd};
\r
771 statetype s_gripjumpd = {SPIROSITDSPR, SPIROSITDSPR, slide, false, false, 64, 0, -16, NULL, C_Spindread, R_Draw, &s_gripspin7};
\r
772 statetype s_gripsitl = {SPIROSITLSPR, SPIROSITLSPR, step, false, false, 150, 0, 0, NULL, C_Spindread, R_Draw, &s_gripjumpl};
\r
773 statetype s_gripjumpl = {SPIROSITLSPR, SPIROSITLSPR, slide, false, false, 64, 16, 0, NULL, C_Spindread, R_Draw, &s_gripspin1};
\r
774 statetype s_gripsitr = {SPIROSITRSPR, SPIROSITRSPR, step, false, false, 150, 0, 0, NULL, C_Spindread, R_Draw, &s_gripjumpr};
\r
775 statetype s_gripjumpr = {SPIROSITRSPR, SPIROSITRSPR, slide, false, false, 64, -16, 0, NULL, C_Spindread, R_Draw, &s_gripspin5};
\r
776 statetype s_gripsitu = {SPIROSITUSPR, SPIROSITUSPR, step, false, false, 150, 0, 0, NULL, C_Spindread, R_Draw, &s_gripjumpu};
\r
777 statetype s_gripjumpu = {SPIROSITUSPR, SPIROSITUSPR, slide, false, false, 64, 0, 16, NULL, C_Spindread, R_Draw, &s_gripspin3};
\r
778 statetype s_gripspin1 = {SPIROSPINULSPR, SPIROSPINULSPR, step, false, false, 8, 0, 0, NULL, C_Spindread, R_Draw, &s_gripspin2};
\r
779 statetype s_gripspin2 = {SPIROSPINUSPR, SPIROSPINUSPR, step, false, false, 8, 0, 0, T_SpiroLaunch, C_Spindread, R_Draw, &s_gripspin3};
\r
780 statetype s_gripspin3 = {SPIROSPINURSPR, SPIROSPINURSPR, step, false, false, 8, 0, 0, NULL, C_Spindread, R_Draw, &s_gripspin4};
\r
781 statetype s_gripspin4 = {SPIROSPINRSPR, SPIROSPINRSPR, step, false, false, 8, 0, 0, T_SpiroLaunch, C_Spindread, R_Draw, &s_gripspin5};
\r
782 statetype s_gripspin5 = {SPIROSPINDRSPR, SPIROSPINDRSPR, step, false, false, 8, 0, 0, NULL, C_Spindread, R_Draw, &s_gripspin6};
\r
783 statetype s_gripspin6 = {SPIROSPINDSPR, SPIROSPINDSPR, step, false, false, 8, 0, 0, T_SpiroLaunch, C_Spindread, R_Draw, &s_gripspin7};
\r
784 statetype s_gripspin7 = {SPIROSPINDLSPR, SPIROSPINDLSPR, step, false, false, 8, 0, 0, NULL, C_Spindread, R_Draw, &s_gripspin8};
\r
785 statetype s_gripspin8 = {SPIROSPINLSPR, SPIROSPINLSPR, step, false, false, 8, 0, 0, T_SpiroLaunch, C_Spindread, R_Draw, &s_gripspin1};
\r
786 statetype s_gripflyd = {SPIROSITDSPR, SPIROSITDSPR, slide, false, false, 0, 0, 48, NULL, C_Spindread, R_SpiroFly, &s_gripsitd};
\r
787 statetype s_gripflyl = {SPIROSITLSPR, SPIROSITLSPR, slide, false, false, 0, -48, 0, NULL, C_Spindread, R_SpiroFly, &s_gripsitl};
\r
788 statetype s_gripflyr = {SPIROSITRSPR, SPIROSITRSPR, slide, false, false, 0, 48, 0, NULL, C_Spindread, R_SpiroFly, &s_gripsitr};
\r
789 statetype s_gripflyu = {SPIROSITUSPR, SPIROSITUSPR, slide, false, false, 0, 0, -48, NULL, C_Spindread, R_SpiroFly, &s_gripsitu};
\r
792 ===========================
\r
796 ===========================
\r
799 void SpawnSpirogrip(Uint16 tileX, Uint16 tileY)
\r
802 new->obclass = spirogripobj;
\r
803 new->active = ac_yes;
\r
804 new->x = CONVERT_TILE_TO_GLOBAL(tileX);
\r
805 new->y = CONVERT_TILE_TO_GLOBAL(tileY) + -1*TILEGLOBAL;
\r
808 NewState(new, &s_gripsitd);
\r
812 ===========================
\r
816 ===========================
\r
819 void T_SpiroLaunch(objtype *ob)
\r
821 if (US_RndT() <= 20)
\r
823 SD_PlaySound(SND_SPIROFLY);
\r
824 if (ob->state == &s_gripspin2)
\r
826 ob->state = &s_gripflyu;
\r
828 else if (ob->state == &s_gripspin4)
\r
830 ob->state = &s_gripflyr;
\r
832 else if (ob->state == &s_gripspin6)
\r
834 ob->state = &s_gripflyd;
\r
836 else if (ob->state == &s_gripspin8)
\r
838 ob->state = &s_gripflyl;
\r
844 ===========================
\r
848 ===========================
\r
851 void R_SpiroFly(objtype *ob)
\r
853 RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);
\r
854 if (ob->hitnorth || ob->hiteast || ob->hitsouth || ob->hitwest)
\r
856 ChangeState(ob, ob->state->nextstate);
\r
857 SD_PlaySound(SND_SPIROGRAB);
\r
862 =============================================================================
\r
866 temp1 = bounce counter
\r
868 =============================================================================
\r
871 statetype s_spindred1 = {SPINDRED1SPR, SPINDRED1SPR, stepthink, false, false, 8, 0, 0, T_Spindread, C_Spindread, R_Spindread, &s_spindred2};
\r
872 statetype s_spindred2 = {SPINDRED2SPR, SPINDRED2SPR, stepthink, false, false, 8, 0, 0, T_Spindread, C_Spindread, R_Spindread, &s_spindred3};
\r
873 statetype s_spindred3 = {SPINDRED3SPR, SPINDRED3SPR, stepthink, false, false, 8, 0, 0, T_Spindread, C_Spindread, R_Spindread, &s_spindred4};
\r
874 statetype s_spindred4 = {SPINDRED4SPR, SPINDRED4SPR, stepthink, false, false, 8, 0, 0, T_Spindread, C_Spindread, R_Spindread, &s_spindred1};
\r
877 ===========================
\r
881 ===========================
\r
884 void SpawnSpindread(Uint16 tileX, Uint16 tileY)
\r
887 new->obclass = spindredobj;
\r
888 new->active = ac_yes;
\r
890 new->x = CONVERT_TILE_TO_GLOBAL(tileX);
\r
891 new->y = CONVERT_TILE_TO_GLOBAL(tileY) + -8*PIXGLOBAL;
\r
893 NewState(new, &s_spindred1);
\r
897 ===========================
\r
901 ===========================
\r
904 void T_Spindread(objtype *ob)
\r
908 // BUG: this might be executed twice during the same frame if the
\r
909 // object's animation/state changed during that frame, causing the
\r
910 // object to move at twice the speed during that frame!
\r
911 // To avoid that, return if ytry is not 0.
\r
913 for (i=lasttimecount-tics; i<lasttimecount; i++)
\r
919 if (ob->yspeed < 0 && ob->yspeed >= -3)
\r
921 ytry += ob->yspeed;
\r
928 if (ob->yspeed > 70)
\r
936 if (ob->yspeed > 0 && ob->yspeed <= 3)
\r
938 ytry += ob->yspeed;
\r
945 if (ob->yspeed < -70)
\r
952 ytry += ob->yspeed;
\r
957 ===========================
\r
961 ===========================
\r
965 void C_Spindread(objtype *ob, objtype *hit)
\r
967 if (hit->obclass == stunshotobj)
\r
971 else if (hit->obclass == keenobj)
\r
978 ===========================
\r
982 ===========================
\r
985 void R_Spindread(objtype *ob)
\r
990 if (ob->ydir == -1)
\r
992 if (++ob->temp1 == 3)
\r
996 ob->ydir = -ob->ydir;
\r
997 SD_PlaySound(SND_SPINDREDFLIP);
\r
1001 SD_PlaySound(SND_SPINDREDBOUNCE);
\r
1009 if (ob->ydir == 1)
\r
1011 if (++ob->temp1 == 3)
\r
1015 ob->ydir = -ob->ydir;
\r
1016 SD_PlaySound(SND_BOUNCE);
\r
1020 SD_PlaySound(SND_SPINDREDBOUNCE);
\r
1025 RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);
\r
1029 =============================================================================
\r
1033 temp1 = defines next action (0 = shoot, 1 = teleport)
\r
1035 =============================================================================
\r
1038 statetype s_master1 = {MASTER1SPR, MASTER1SPR, step, false, false, 8, 0, 0, NULL, C_Master, R_Draw, &s_master2};
\r
1039 statetype s_master2 = {MASTER2SPR, MASTER2SPR, step, false, false, 8, 0, 0, NULL, C_Master, R_Draw, &s_master3};
\r
1040 statetype s_master3 = {MASTER3SPR, MASTER3SPR, step, false, false, 8, 0, 0, NULL, C_Master, R_Draw, &s_master4};
\r
1041 statetype s_master4 = {MASTER4SPR, MASTER4SPR, step, false, false, 8, 0, 0, T_Master, C_Master, R_Draw, &s_master1};
\r
1042 statetype s_mastershoot1 = {SHIKMASTERCASTLSPR, SHIKMASTERCASTRSPR, step, false, false, 30, 0, 0, T_MasterShoot, C_Spindread, R_Draw, &s_mastershoot2};
\r
1043 statetype s_mastershoot2 = {SHIKMASTERCASTLSPR, SHIKMASTERCASTRSPR, step, false, false, 8, 0, 0, NULL, C_Spindread, R_Draw, &s_master1};
\r
1044 statetype s_mastertport1 = {MASTERTELEPORT1SPR, MASTERTELEPORT1SPR, step, false, true, 20, 0, 0, NULL, C_Spindread, R_Draw, &s_mastertport2};
\r
1045 statetype s_mastertport2 = {MASTERTELEPORT2SPR, MASTERTELEPORT2SPR, step, false, true, 20, 0, 0, T_MasterTPort, C_Spindread, R_Draw, &s_mastertport3};
\r
1046 statetype s_mastertport3 = {MASTERTELEPORT2SPR, MASTERTELEPORT2SPR, think, false, false, 0, 0, 0, T_Projectile, NULL, R_Land, &s_mastertport4};
\r
1047 statetype s_mastertport4 = {MASTERTELEPORT2SPR, MASTERTELEPORT2SPR, step, false, false, 60, 0, 0, NULL, C_Spindread, R_Draw, &s_master1};
\r
1048 statetype s_mshot1 = {MASTERSHOT4SPR, MASTERSHOT1SPR, stepthink, false, false, 8, 0, 0, T_WeakProjectile, C_MShot, R_MShot, &s_mshot2};
\r
1049 statetype s_mshot2 = {MASTERSHOT3SPR, MASTERSHOT2SPR, stepthink, false, false, 8, 0, 0, T_WeakProjectile, C_MShot, R_MShot, &s_mshot3};
\r
1050 statetype s_mshot3 = {MASTERSHOT2SPR, MASTERSHOT3SPR, stepthink, false, false, 8, 0, 0, T_WeakProjectile, C_MShot, R_MShot, &s_mshot4};
\r
1051 statetype s_mshot4 = {MASTERSHOT1SPR, MASTERSHOT4SPR, stepthink, false, false, 8, 0, 0, T_WeakProjectile, C_MShot, R_MShot, &s_mshot1};
\r
1052 statetype s_mspray1 = {MASTERFLOORSPARK1SPR, MASTERFLOORSPARK1SPR, stepthink, false, false, 6, 0, 0, T_Projectile, C_MShot, R_MSpray, &s_mspray2};
\r
1053 statetype s_mspray2 = {MASTERFLOORSPARK2SPR, MASTERFLOORSPARK2SPR, stepthink, false, false, 6, 0, 0, T_Projectile, C_MShot, R_MSpray, &s_mspray3};
\r
1054 statetype s_mspray3 = {MASTERFLOORSPARK3SPR, MASTERFLOORSPARK3SPR, stepthink, false, false, 6, 0, 0, T_Projectile, C_MShot, R_MSpray, &s_mspray4};
\r
1055 statetype s_mspray4 = {MASTERFLOORSPARK4SPR, MASTERFLOORSPARK4SPR, stepthink, false, false, 6, 0, 0, T_Projectile, C_MShot, R_MSpray, &s_mspray1};
\r
1058 ===========================
\r
1062 ===========================
\r
1065 void SpawnMaster(Uint16 tileX, Uint16 tileY)
\r
1068 new->obclass = shikadimasterobj;
\r
1069 new->active = ac_yes;
\r
1070 new->x = CONVERT_TILE_TO_GLOBAL(tileX);
\r
1071 new->y = CONVERT_TILE_TO_GLOBAL(tileY) + -24*PIXGLOBAL;
\r
1072 NewState(new, &s_master1);
\r
1076 ===========================
\r
1080 ===========================
\r
1083 void T_Master(objtype *ob)
\r
1087 randval = US_RndT();
\r
1088 if (randval < 0x40)
\r
1092 ob->state = &s_mastertport1;
\r
1098 if (player->x > ob->x)
\r
1106 ob->state = &s_mastershoot1;
\r
1112 ===========================
\r
1116 ===========================
\r
1119 void T_MasterShoot(objtype *ob)
\r
1123 if (ob->xdir == 1)
\r
1125 x = ob->x + 16*PIXGLOBAL;
\r
1131 if (CheckSpawnShot(x, ob->y+8*PIXGLOBAL, &s_mshot1) != -1)
\r
1133 new->xspeed = ob->xdir * 48;
\r
1134 new->yspeed = -16;
\r
1135 SD_PlaySound(SND_MASTERATTACK);
\r
1140 ===========================
\r
1144 ===========================
\r
1147 void C_Master(objtype *ob, objtype *hit)
\r
1149 if (hit->obclass == stunshotobj)
\r
1152 ob->xdir = (player->x > ob->x)? 1 : -1;
\r
1154 ChangeState(ob, &s_mastershoot1);
\r
1156 else if (hit->obclass == keenobj)
\r
1163 ===========================
\r
1167 ===========================
\r
1170 void T_MasterTPort(objtype *ob)
\r
1173 Sint16 tx, ty, redos, oldx, oldy;
\r
1182 NewState(new, &s_mspray1); // BUG? new object is not made removable
\r
1187 new->xspeed = -48;
\r
1188 NewState(new, &s_mspray1); // BUG? new object is not made removable
\r
1190 SD_PlaySound(SND_MASTERBLAST);
\r
1194 if (++redos == 10)
\r
1196 US_RndT(); // call it, but ignore the result
\r
1197 // probably to avoid repeatedly getting the same same "random" values
\r
1198 // due to having an even number of US_RndT() calls in this routine and
\r
1199 // an even number of elements in the random table.
\r
1201 ob->state = &s_master1;
\r
1209 tx = player->tilemidx - 16 + (US_RndT()>>3);
\r
1210 ty = player->tilebottom - 16 + (US_RndT()>>3);
\r
1211 if (tx < 2 || ty < 2 || tx > mapwidth-5 || ty > mapheight-5)
\r
1215 ob->x = CONVERT_TILE_TO_GLOBAL(tx);
\r
1216 ob->y = CONVERT_TILE_TO_GLOBAL(ty);
\r
1217 ob->tileleft = tx-1;
\r
1218 ob->tileright = tx+4;
\r
1219 ob->tiletop = ty-1;
\r
1220 ob->tilebottom = ty+4;
\r
1227 map = (Uint16 far *)mapsegs[1] + mapbwidthtable[ob->tiletop]/2 + ob->tileleft;
\r
1228 mapdelta = mapwidth - (ob->tileright - ob->tileleft + 1);
\r
1230 for (y = ob->tiletop; ob->tilebottom >= y; y++, map+=mapdelta)
\r
1232 for (x = ob->tileleft; ob->tileright >= x; x++)
\r
1235 if ((tinf[tile+INTILE] & INTILE_FOREGROUND) || tinf[tile+NORTHWALL] || tinf[tile+EASTWALL]
\r
1236 || tinf[tile+SOUTHWALL] || tinf[tile+WESTWALL])
\r
1248 ===========================
\r
1252 ===========================
\r
1255 void C_MShot(objtype *ob, objtype *hit)
\r
1257 if (hit->obclass == keenobj)
\r
1262 else if (hit->obclass == stunshotobj)
\r
1270 ===========================
\r
1274 ===========================
\r
1277 void R_MShot(objtype *ob)
\r
1279 if (ob->hiteast || ob->hitwest)
\r
1281 ob->xspeed = -ob->xspeed;
\r
1289 SD_PlaySound(SND_MASTERATTACK);
\r
1291 ChangeState(ob, &s_mspray1);
\r
1296 new->xspeed = -48;
\r
1297 NewState(new, &s_mspray1); // BUG? new object is not made removable
\r
1299 RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);
\r
1303 ===========================
\r
1307 ===========================
\r
1310 void R_MSpray(objtype *ob)
\r
1312 if (ob->hiteast || ob->hitwest)
\r
1318 RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);
\r
1323 =============================================================================
\r
1327 temp1 = x tile position of the pole being grabbed (is set but never used)
\r
1329 temp3 = flash countdown
\r
1331 =============================================================================
\r
1334 statetype s_shikadi1 = {SHIKADI1SPR, SHIKADI1SPR, step, false, true, 8, 0, 0, NULL, C_Shikadi, R_Shikadi, &s_shikadi2};
\r
1335 statetype s_shikadi2 = {SHIKADI2SPR, SHIKADI2SPR, step, false, true, 8, 0, 0, NULL, C_Shikadi, R_Shikadi, &s_shikadi3};
\r
1336 statetype s_shikadi3 = {SHIKADI3SPR, SHIKADI3SPR, step, false, true, 8, 0, 0, NULL, C_Shikadi, R_Shikadi, &s_shikadi4};
\r
1337 statetype s_shikadi4 = {SHIKADI4SPR, SHIKADI4SPR, step, false, true, 8, 0, 0, NULL, C_Shikadi, R_Shikadi, &s_shikadiwalk1};
\r
1338 statetype s_shikadiwalk1 = {SHIKADIWALKL1SPR, SHIKADIWALKR1SPR, step, false, true, 8, 128, 0, T_Shikadi, C_Shikadi, R_Shikadi, &s_shikadiwalk2};
\r
1339 statetype s_shikadiwalk2 = {SHIKADIWALKL2SPR, SHIKADIWALKR2SPR, step, false, true, 8, 128, 0, T_Shikadi, C_Shikadi, R_Shikadi, &s_shikadiwalk3};
\r
1340 statetype s_shikadiwalk3 = {SHIKADIWALKL3SPR, SHIKADIWALKR3SPR, step, false, true, 8, 128, 0, T_Shikadi, C_Shikadi, R_Shikadi, &s_shikadiwalk4};
\r
1341 statetype s_shikadiwalk4 = {SHIKADIWALKL4SPR, SHIKADIWALKR4SPR, step, false, true, 8, 128, 0, T_Shikadi, C_Shikadi, R_Shikadi, &s_shikadiwalk1};
\r
1342 statetype s_shikadigrab = {SHIKADIGRABLSPR, SHIKADIGRABRSPR, step, false, true, 20, 0, 0, T_PoleShock, C_Shikadi, R_Shikadi, &s_shikadigrab2};
\r
1343 statetype s_shikadigrab2 = {SHIKADIGRABLSPR, SHIKADIGRABRSPR, step, false, true, 20, 0, 0, NULL, C_Shikadi, R_Shikadi, &s_shikadiwalk1};
\r
1344 statetype s_shikadistun = {SHIKADISTUNSPR, SHIKADISTUNSPR, think, false, false, 0, 0, 0, T_Projectile, NULL, R_Stunned, NULL};
\r
1346 statetype s_polespark1 = {SHIKADIPOLESPARK1SPR, SHIKADIPOLESPARK1SPR, stepthink, false, false, 0, 0, 0, T_PoleSpark, C_Lethal, R_Draw, &s_polespark2};
\r
1347 statetype s_polespark2 = {SHIKADIPOLESPARK1SPR, SHIKADIPOLESPARK1SPR, stepthink, false, false, 0, 0, 0, T_PoleSpark, C_Lethal, R_Draw, &s_polespark1};
\r
1350 ===========================
\r
1354 ===========================
\r
1357 void SpawnShikadi(Uint16 tileX, Uint16 tileY)
\r
1360 new->obclass = shikadiobj;
\r
1361 new->active = ac_yes;
\r
1362 new->x = CONVERT_TILE_TO_GLOBAL(tileX);
\r
1363 new->y = CONVERT_TILE_TO_GLOBAL(tileY) + -1*TILEGLOBAL;
\r
1364 new->temp2 = 4; // health
\r
1365 if (US_RndT() < 0x80)
\r
1373 NewState(new, &s_shikadi1);
\r
1377 ===========================
\r
1381 ===========================
\r
1384 void T_Shikadi(objtype *ob)
\r
1388 if (player->state->contact == &KeenPosContact
\r
1389 || ob->bottom - player->bottom + TILEGLOBAL <= 2*TILEGLOBAL)
\r
1391 if (ob->x > player->x + TILEGLOBAL)
\r
1395 else if (ob->x < player->x - TILEGLOBAL)
\r
1399 if (ob->xdir == 1)
\r
1401 tx = ob->tileright;
\r
1405 tx = ob->tileleft;
\r
1408 if (player->tilemidx != tx)
\r
1413 if (US_RndT() < 0x10)
\r
1416 ob->state = &s_shikadi1;
\r
1419 if ((ob->x & 0xFF) || !OnScreen(ob))
\r
1422 if (ob->xdir == 1)
\r
1424 tx = ob->tileright;
\r
1428 tx = ob->tileleft;
\r
1432 tile = *(mapsegs[1]+mapbwidthtable[ob->tiletop]/2 + tx);
\r
1433 if (tinf[tile+INTILE] == INTILE_POLE)
\r
1436 ob->state = &s_shikadigrab;
\r
1438 SD_PlaySound(SND_SHIKADIATTACK);
\r
1443 ===========================
\r
1447 ===========================
\r
1450 void C_Shikadi(objtype *ob, objtype *hit)
\r
1452 if (hit->obclass == keenobj)
\r
1456 if (hit->obclass == stunshotobj)
\r
1458 if (--ob->temp2 == 0) // handle health
\r
1462 StunObj(ob, hit, &s_shikadistun);
\r
1466 ob->temp3 = 2; // draw white two times
\r
1467 ob->needtoreact = true;
\r
1474 ===========================
\r
1478 ===========================
\r
1481 void T_PoleShock(objtype *ob)
\r
1486 if (ob->xdir == 1)
\r
1488 x = CONVERT_TILE_TO_GLOBAL(ob->tileright);
\r
1492 x = CONVERT_TILE_TO_GLOBAL(ob->tileleft);
\r
1497 new->y = ob->y + 8*PIXGLOBAL;
\r
1498 new->obclass = mshotobj;
\r
1499 new->active = ac_removable;
\r
1500 new->needtoclip = cl_noclip;
\r
1501 NewState(new, &s_polespark1);
\r
1502 if (ob->y < player->y)
\r
1510 SD_PlaySound(SND_SHIKADIATTACK);
\r
1514 ===========================
\r
1518 ===========================
\r
1521 void T_PoleSpark(objtype *ob)
\r
1527 ytry = ob->ydir * 48;
\r
1528 tile = *(mapsegs[1]+mapbwidthtable[ob->tiletop]/2 + ob->tilemidx);
\r
1529 if (tinf[tile+INTILE] != INTILE_POLE)
\r
1537 ===========================
\r
1541 ===========================
\r
1544 void R_Shikadi(objtype *ob)
\r
1546 if (ob->xdir == 1 && ob->hitwest)
\r
1548 ob->x -= ob->xmove;
\r
1550 ob->nothink = US_RndT() >> 5;
\r
1551 ChangeState(ob, ob->state);
\r
1553 else if (ob->xdir == -1 && ob->hiteast)
\r
1555 ob->x -= ob->xmove;
\r
1557 ob->nothink = US_RndT() >> 5;
\r
1558 ChangeState(ob, ob->state);
\r
1560 else if (!ob->hitnorth)
\r
1562 ob->x -= ob->xmove;
\r
1563 ob->xdir = -ob->xdir;
\r
1564 ob->nothink = US_RndT() >> 5;
\r
1565 ChangeState(ob, ob->state);
\r
1570 RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, maskdraw, ob->priority);
\r
1574 RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);
\r
1579 =============================================================================
\r
1581 PET (a.k.a. SHOCKSHUND)
\r
1583 temp1 = countdown for sit animation
\r
1585 temp3 = flash countdown
\r
1587 =============================================================================
\r
1590 statetype s_petsit1 = {PETSIT1SPR, PETSIT1SPR, step, false, true, 8, 0, 0, NULL, C_Pet, R_Pet, &s_petsit2};
\r
1591 statetype s_petsit2 = {PETSIT2SPR, PETSIT2SPR, step, false, true, 8, 0, 0, T_PetSit, C_Pet, R_Pet, &s_petsit1};
\r
1592 statetype s_petbark1 = {PETBARKL1SPR, PETBARKR1SPR, step, false, true, 8, 0, 0, NULL, C_Pet, R_Pet, &s_petbark2};
\r
1593 statetype s_petbark2 = {PETBARKL2SPR, PETBARKR2SPR, step, false, true, 8, 0, 0, T_PetBark, C_Pet, R_Pet, &s_pet1};
\r
1594 statetype s_pet1 = {PETRUNL1SPR, PETRUNR1SPR, step, false, true, 8, 128, 0, NULL, C_Pet, R_Pet, &s_pet2};
\r
1595 statetype s_pet2 = {PETRUNL2SPR, PETRUNR2SPR, step, false, true, 8, 128, 0, NULL, C_Pet, R_Pet, &s_pet3};
\r
1596 statetype s_pet3 = {PETRUNL3SPR, PETRUNR3SPR, step, false, true, 8, 128, 0, NULL, C_Pet, R_Pet, &s_pet4};
\r
1597 statetype s_pet4 = {PETRUNL4SPR, PETRUNR4SPR, step, false, true, 8, 128, 0, T_Pet, C_Pet, R_Pet, &s_pet1};
\r
1598 statetype s_petjump = {PETJUMPLSPR, PETJUMPRSPR, think, false, false, 8, 128, 0, T_Projectile, C_Pet, R_PetJump, &s_pet2};
\r
1599 statetype s_pshot1 = {PETSPARK1SPR, PETSPARK1SPR, stepthink, false, false, 8, 0, 0, T_Velocity, C_PShot, R_PShot, &s_pshot2};
\r
1600 statetype s_pshot2 = {PETSPARK2SPR, PETSPARK2SPR, stepthink, false, false, 8, 0, 0, T_Velocity, C_PShot, R_PShot, &s_pshot1};
\r
1601 statetype s_pshothot1 = {PETSPARKHIT1SPR, PETSPARKHIT1SPR, step, false, false, 10, 0, 0, NULL, NULL, R_Draw, &s_pshothot2};
\r
1602 statetype s_pshothot2 = {PETSPARKHIT2SPR, PETSPARKHIT2SPR, step, false, false, 10, 0, 0, NULL, NULL, R_Draw, NULL};
\r
1603 statetype s_petstun = {PETSTUNSPR, PETSTUNSPR, think, false, false, 0, 0, 0, T_Projectile, NULL, R_Stunned, NULL};
\r
1606 ===========================
\r
1610 ===========================
\r
1613 void SpawnPet(Uint16 tileX, Uint16 tileY)
\r
1616 new->obclass = petobj;
\r
1617 new->active = ac_yes;
\r
1618 new->x = CONVERT_TILE_TO_GLOBAL(tileX);
\r
1619 new->y = CONVERT_TILE_TO_GLOBAL(tileY) + -8*PIXGLOBAL;
\r
1620 new->temp2 = 2; // health
\r
1621 new->xdir = new->ydir = 1;
\r
1622 NewState(new, &s_pet1);
\r
1626 ===========================
\r
1630 ===========================
\r
1633 void T_Pet(objtype *ob)
\r
1635 if (ob->x > player->x)
\r
1643 if (US_RndT() < 0x10)
\r
1646 ob->state = &s_petsit1;
\r
1647 ob->temp1 = 10; // repeat animation 10 times;
\r
1651 if (ob->bottom != player->bottom)
\r
1653 ob->state = &s_petjump;
\r
1654 if (ob->xdir == 1)
\r
1664 if (US_RndT() < 0x80)
\r
1667 ob->state = &s_petbark1;
\r
1673 ===========================
\r
1677 ===========================
\r
1680 void T_PetSit(objtype *ob)
\r
1682 if (--ob->temp1 == 0)
\r
1684 ob->state = &s_pet1;
\r
1689 ===========================
\r
1693 ===========================
\r
1696 void T_PetBark(objtype *ob)
\r
1700 if (ob->xdir == 1)
\r
1702 x = ob->x + 7*PIXGLOBAL;
\r
1708 if (CheckSpawnShot(x, ob->y+4*PIXGLOBAL, &s_pshot1) != -1)
\r
1710 new->xspeed = ob->xdir * 60;
\r
1711 new->xdir = ob->xdir;
\r
1712 SD_PlaySound(SND_SHOCKSHUNDBARK);
\r
1717 ===========================
\r
1721 ===========================
\r
1724 void C_Pet(objtype *ob, objtype *hit)
\r
1726 if (hit->obclass == keenobj)
\r
1730 if (hit->obclass == stunshotobj) // no 'else if' in the original code!
\r
1732 if (--ob->temp2 == 0) // handle health
\r
1736 StunObj(ob, hit, &s_petstun);
\r
1740 ob->temp3 = 2; // draw white two times
\r
1741 ob->needtoreact = true;
\r
1748 ===========================
\r
1752 ===========================
\r
1755 void R_Pet(objtype *ob)
\r
1757 if (ob->xdir == 1 && ob->hitwest)
\r
1759 ob->x -= ob->xmove;
\r
1761 ob->nothink = US_RndT() >> 5;
\r
1762 ChangeState(ob, ob->state);
\r
1764 else if (ob->xdir == -1 && ob->hiteast)
\r
1766 ob->x -= ob->xmove;
\r
1768 ob->nothink = US_RndT() >> 5;
\r
1769 ChangeState(ob, ob->state);
\r
1771 else if (!ob->hitnorth)
\r
1773 if ((ob->xdir == 1 && player->x > ob->x) || (ob->xdir == -1 && player->x < ob->x))
\r
1775 ChangeState(ob, &s_petjump);
\r
1776 if (ob->xdir == 1)
\r
1788 ob->x -= ob->xmove*2;
\r
1789 ob->xdir = -ob->xdir;
\r
1790 ob->nothink = US_RndT() >> 5;
\r
1791 ChangeState(ob, ob->state);
\r
1797 RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, maskdraw, ob->priority);
\r
1801 RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);
\r
1806 ===========================
\r
1810 ===========================
\r
1813 void R_PetJump(objtype *ob)
\r
1817 ob->nothink = US_RndT() >> 5;
\r
1818 ChangeState(ob, &s_pet1);
\r
1823 RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, maskdraw, ob->priority);
\r
1827 RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);
\r
1832 ===========================
\r
1836 ===========================
\r
1839 void C_PShot(objtype *ob, objtype *hit)
\r
1841 if (hit->obclass == keenobj)
\r
1844 ChangeState(ob, &s_pshothot1);
\r
1846 else if (hit->obclass == stunshotobj)
\r
1849 ChangeState(ob, &s_pshothot1);
\r
1854 ===========================
\r
1858 ===========================
\r
1861 void R_PShot(objtype *ob)
\r
1863 if (ob->hitnorth || ob->hiteast || ob->hitsouth || ob->hitwest)
\r
1865 SD_PlaySound(SND_SHOCKBALLEXPLODE);
\r
1866 ChangeState(ob, &s_pshothot1);
\r
1868 RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);
\r
1872 =============================================================================
\r
1876 temp1 ... temp4 = sprite pointers for the guards circling around the sphere
\r
1878 =============================================================================
\r
1881 statetype s_sphereful1 = {SPHEREFUL1SPR, SPHEREFUL1SPR, stepthink, false, false, 6, 0, 0, T_Sphereful, C_Spindread, R_Sphereful, &s_sphereful2};
\r
1882 statetype s_sphereful2 = {SPHEREFUL2SPR, SPHEREFUL2SPR, stepthink, false, false, 6, 0, 0, T_Sphereful, C_Spindread, R_Sphereful, &s_sphereful3};
\r
1883 statetype s_sphereful3 = {SPHEREFUL3SPR, SPHEREFUL3SPR, stepthink, false, false, 6, 0, 0, T_Sphereful, C_Spindread, R_Sphereful, &s_sphereful4};
\r
1884 statetype s_sphereful4 = {SPHEREFUL4SPR, SPHEREFUL4SPR, stepthink, false, false, 6, 0, 0, T_Sphereful, C_Spindread, R_Sphereful, &s_sphereful1};
\r
1887 ===========================
\r
1891 ===========================
\r
1894 void SpawnSphereful(Uint16 tileX, Uint16 tileY)
\r
1897 new->obclass = spherefulobj;
\r
1898 new->needtoclip = cl_fullclip;
\r
1899 new->active = ac_yes;
\r
1900 new->x = CONVERT_TILE_TO_GLOBAL(tileX);
\r
1901 new->y = CONVERT_TILE_TO_GLOBAL(tileY) + -1*TILEGLOBAL;
\r
1902 new->priority = 1;
\r
1903 NewState(new, &s_sphereful1);
\r
1907 ===========================
\r
1911 ===========================
\r
1914 void T_Sphereful(objtype *ob)
\r
1917 ob->needtoreact = true;
\r
1920 // this code could be executed twice during the same frame because the
\r
1921 // object's animation/state changed during that frame, so don't update
\r
1922 // anything if we already have movement for the current frame i.e. the
\r
1923 // update code has already been executed this frame
\r
1925 if (xtry == 0 && ytry == 0)
\r
1927 for (i=lasttimecount-tics; i<lasttimecount; i++)
\r
1931 if (ob->yspeed < 8)
\r
1934 if (ob->x < player->x && ob->xspeed < 8)
\r
1937 if (ob->x > player->x && ob->xspeed > -8)
\r
1940 ytry += ob->yspeed;
\r
1941 xtry += ob->xspeed;
\r
1947 ===========================
\r
1951 ===========================
\r
1954 void R_Sphereful(objtype *ob)
\r
1956 static Uint16 circle[16] = {
\r
1957 384, 369, 328, 265, 192, 119, 58, 15,
\r
1958 0, 15, 58, 119, 192, 265, 328, 369
\r
1961 Uint16 index, shapenum, priority;
\r
1963 if (ob->hitwest || ob->hiteast)
\r
1965 ob->xspeed = -ob->xspeed;
\r
1966 SD_PlaySound(SND_SPHEREFULBOUNCE);
\r
1970 ob->yspeed = -ob->yspeed;
\r
1971 SD_PlaySound(SND_SPHEREFULBOUNCE);
\r
1976 ob->yspeed = -ob->yspeed;
\r
1977 if (player->y < ob->y)
\r
1985 if (ob->yspeed > -4)
\r
1989 else if (ob->yspeed < -12)
\r
1993 SD_PlaySound(SND_BOUNCE);
\r
1995 RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);
\r
1997 index = ((Uint16)lasttimecount / 8) & 0xF;
\r
1998 shapenum = index / 4 + SPHEREGUARD1SPR;
\r
2007 RF_PlaceSprite((void**)&ob->temp1, ob->x+circle[index], ob->y+circle[index], shapenum, spritedraw, priority);
\r
2008 RF_PlaceSprite((void**)&ob->temp2, ob->x+24*PIXGLOBAL-circle[index], ob->y+circle[index], shapenum, spritedraw, priority);
\r
2020 RF_PlaceSprite((void**)&ob->temp3, ob->x+circle[index], ob->y+circle[index], shapenum, spritedraw, priority);
\r
2021 RF_PlaceSprite((void**)&ob->temp4, ob->x+24*PIXGLOBAL-circle[index], ob->y+circle[index], shapenum, spritedraw, priority);
\r
2025 =============================================================================
\r
2029 =============================================================================
\r
2032 statetype s_scottie1 = {SCOTTIEWALKL1SPR, SCOTTIEWALKR1SPR, step, false, true, 8, 128, 0, T_Scottie, C_Scottie, R_Walk, &s_scottie2};
\r
2033 statetype s_scottie2 = {SCOTTIEWALKL2SPR, SCOTTIEWALKR2SPR, step, false, true, 8, 128, 0, T_Scottie, C_Scottie, R_Walk, &s_scottie3};
\r
2034 statetype s_scottie3 = {SCOTTIEWALKL3SPR, SCOTTIEWALKR3SPR, step, false, true, 8, 128, 0, T_Scottie, C_Scottie, R_Walk, &s_scottie4};
\r
2035 statetype s_scottie4 = {SCOTTIEWALKL4SPR, SCOTTIEWALKR4SPR, step, false, true, 8, 128, 0, T_Scottie, C_Scottie, R_Walk, &s_scottie1};
\r
2036 statetype s_scottieface = {SCOTTIEFACESPR, SCOTTIEFACESPR, step, false, true, 30, 0, 0, NULL, C_Scottie, R_Walk, &s_scottie1};
\r
2037 statetype s_scottiestun = {SCOTTIESTUNSPR, SCOTTIESTUNSPR, think, false, false, 0, 0, 0, T_Projectile, NULL, R_Stunned, NULL};
\r
2040 ===========================
\r
2044 ===========================
\r
2047 void SpawnScottie(Uint16 tileX, Uint16 tileY)
\r
2050 new->obclass = scottieobj;
\r
2051 new->active = ac_yes;
\r
2052 new->x = CONVERT_TILE_TO_GLOBAL(tileX);
\r
2053 new->y = CONVERT_TILE_TO_GLOBAL(tileY) + -8*PIXGLOBAL;
\r
2054 if (US_RndT() < 0x80)
\r
2062 NewState(new, &s_scottie1);
\r
2066 ===========================
\r
2070 ===========================
\r
2073 void T_Scottie(objtype *ob)
\r
2075 if (US_RndT() < 0x10)
\r
2078 if (US_RndT() < 0x80)
\r
2086 ob->state = &s_scottieface;
\r
2091 ===========================
\r
2095 ===========================
\r
2098 void C_Scottie(objtype *ob, objtype *hit)
\r
2100 if (hit->obclass == keenobj && hit->state->contact)
\r
2102 ClipToSpriteSide(hit, ob);
\r
2104 else if (hit->obclass == stunshotobj)
\r
2106 StunObj(ob, hit, &s_scottiestun);
\r
2111 =============================================================================
\r
2115 =============================================================================
\r
2118 statetype s_qed = {-1, -1, step, false, true, 8, 128, 0, NULL, NULL, NULL, &s_qed};
\r
2121 ===========================
\r
2125 ===========================
\r
2128 void SpawnQed(Uint16 tileX, Uint16 tileY)
\r
2131 new->obclass = qedobj;
\r
2132 new->active = ac_yes;
\r
2133 new->tileleft = tileX;
\r
2134 new->tiletop = tileY;
\r
2135 new->tileright = new->tileleft + 1;
\r
2136 new->tilebottom = new->tiletop + 1;
\r
2137 new->x = new->left = CONVERT_TILE_TO_GLOBAL(tileX) + -1*PIXGLOBAL;
\r
2138 new->y = new->top = CONVERT_TILE_TO_GLOBAL(tileY) + -1*PIXGLOBAL;
\r
2139 new->right = new->left + 34*PIXGLOBAL;
\r
2140 new->bottom = new->top + 34*PIXGLOBAL;
\r
2141 NewState(new, &s_qed);
\r