]> 4ch.mooo.com Git - 16.git/blob - src/lib/hb/kd_keen.c
[16_ca needs huge amounts of work and I should remember what needs to be done soon...
[16.git] / src / lib / hb / kd_keen.c
1 /* Keen Dreams Source Code\r
2  * Copyright (C) 2014 Javier M. Chavez\r
3  *\r
4  * This program is free software; you can redistribute it and/or modify\r
5  * it under the terms of the GNU General Public License as published by\r
6  * the Free Software Foundation; either version 2 of the License, or\r
7  * (at your option) any later version.\r
8  *\r
9  * This program is distributed in the hope that it will be useful,\r
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
12  * GNU General Public License for more details.\r
13  *\r
14  * You should have received a copy of the GNU General Public License along\r
15  * with this program; if not, write to the Free Software Foundation, Inc.,\r
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
17  */\r
18 \r
19 // KD_KEEN.C\r
20 \r
21 #include "KD_DEF.H"\r
22 #pragma hdrstop\r
23 \r
24 /*\r
25 \r
26 player->temp1 = pausetime / pointer to zees when sleeping\r
27 player->temp2 = pausecount / stagecount\r
28 player->temp3 =\r
29 player->temp4 =\r
30 \r
31 \r
32 */\r
33 \r
34 \r
35 /*\r
36 =============================================================================\r
37 \r
38                                                  LOCAL CONSTANTS\r
39 \r
40 =============================================================================\r
41 */\r
42 \r
43 #define KEENPRIORITY    1\r
44 \r
45 #define PLACESPRITE RF_PlaceSprite (&ob->sprite,ob->x,ob->y,ob->shapenum, \\r
46         spritedraw,KEENPRIORITY);\r
47 \r
48 #define MINPOLEJUMPTICS 19      // wait tics before allowing a pole regram\r
49 \r
50 #define SPDRUNJUMP              16\r
51 #define SPDPOLESIDEJUMP 8\r
52 #define WALKAIRSPEED    8\r
53 #define DIVESPEED               32\r
54 #define JUMPTIME                16\r
55 #define POLEJUMPTIME    10\r
56 #define SPDJUMP                 40\r
57 #define SPDDIVEUP               16\r
58 #define SPDPOLEJUMP             20\r
59 \r
60 #define SPDPOWERUP              -64\r
61 #define SPDPOWER                64\r
62 #define SPDPOWERY               -20\r
63 #define POWERCOUNT              50\r
64 \r
65 #define MAXXSPEED   24\r
66 \r
67 /*\r
68 =============================================================================\r
69 \r
70                                                  GLOBAL VARIABLES\r
71 \r
72 =============================================================================\r
73 */\r
74 \r
75 int     singlegravity;\r
76 unsigned        bounceangle[8][8] =\r
77 {\r
78 {0,0,0,0,0,0,0,0},\r
79 {7,6,5,4,3,2,1,0},\r
80 {5,4,3,2,1,0,15,14},\r
81 {5,4,3,2,1,0,15,14},\r
82 {3,2,1,0,15,14,13,12},\r
83 {9,8,7,6,5,4,3,2},\r
84 {9,8,7,6,5,4,3,2},\r
85 {11,10,9,8,7,6,5,4}\r
86 };\r
87 \r
88 \r
89 /*\r
90 =============================================================================\r
91 \r
92                                                  LOCAL VARIABLES\r
93 \r
94 =============================================================================\r
95 */\r
96 \r
97 int     jumptime;\r
98 long    leavepoletime;          // TimeCount when jumped off pole\r
99 \r
100 /*\r
101 =============================================================================\r
102 \r
103                                                  SCORE BOX ROUTINES\r
104 \r
105 =============================================================================\r
106 */\r
107 \r
108 void    SpawnScore (void);\r
109 void ScoreThink (objtype *ob);\r
110 void ScoreReact (objtype *ob);\r
111 \r
112 void MemDrawChar (int char8,byte far *dest,unsigned width,unsigned planesize);\r
113 \r
114 statetype s_score       = {NULL,NULL,think,false,\r
115         false,0, 0,0, ScoreThink , NULL, ScoreReact, NULL};\r
116 \r
117 \r
118 /*\r
119 ======================\r
120 =\r
121 = SpawnScore\r
122 =\r
123 ======================\r
124 */\r
125 \r
126 void    SpawnScore (void)\r
127 {\r
128         scoreobj->obclass = inertobj;\r
129         scoreobj->active = allways;\r
130         scoreobj->needtoclip = false;\r
131         *((long *)&(scoreobj->temp1)) = -1;             // force score to be updated\r
132         scoreobj->temp3 = -1;                   // and flower power\r
133         scoreobj->temp4 = -1;                   // and lives\r
134         NewState (scoreobj,&s_score);\r
135 }\r
136 \r
137 \r
138 void    FixScoreBox (void)\r
139 {\r
140         unsigned        width, planesize;\r
141         unsigned smallplane,bigplane;\r
142         spritetype      _seg    *block;\r
143         byte    far     *dest;\r
144 \r
145 // draw boobus bomb if on level 15, else flower power\r
146         block = (spritetype _seg *)grsegs[SCOREBOXSPR];\r
147         width = block->width[0];\r
148         planesize = block->planesize[0];\r
149         dest = (byte far *)grsegs[SCOREBOXSPR]+block->sourceoffset[0]\r
150                 + planesize + width*16 + 4*CHARWIDTH;\r
151         if (mapon == 15)\r
152         {\r
153                 MemDrawChar (20,dest,width,planesize);\r
154                 MemDrawChar (21,dest+CHARWIDTH,width,planesize);\r
155                 MemDrawChar (22,dest+width*8,width,planesize);\r
156                 MemDrawChar (23,dest+width*8+CHARWIDTH,width,planesize);\r
157         }\r
158         else\r
159         {\r
160                 MemDrawChar (28,dest,width,planesize);\r
161                 MemDrawChar (29,dest+CHARWIDTH,width,planesize);\r
162                 MemDrawChar (30,dest+width*8,width,planesize);\r
163                 MemDrawChar (31,dest+width*8+CHARWIDTH,width,planesize);\r
164         }\r
165 \r
166 }\r
167 \r
168 \r
169 /*\r
170 ======================\r
171 =\r
172 = MemDrawChar\r
173 =\r
174 ======================\r
175 */\r
176 \r
177 #if GRMODE == EGAGR\r
178 \r
179 void MemDrawChar (int char8,byte far *dest,unsigned width,unsigned planesize)\r
180 {\r
181 asm     mov     si,[char8]\r
182 asm     shl     si,1\r
183 asm     shl     si,1\r
184 asm     shl     si,1\r
185 asm     shl     si,1\r
186 asm     shl     si,1            // index into char 8 segment\r
187 \r
188 asm     mov     ds,[WORD PTR grsegs+STARTTILE8*2]\r
189 asm     mov     es,[WORD PTR dest+2]\r
190 \r
191 asm     mov     cx,4            // draw four planes\r
192 asm     mov     bx,[width]\r
193 asm     dec     bx\r
194 \r
195 planeloop:\r
196 \r
197 asm     mov     di,[WORD PTR dest]\r
198 \r
199 asm     movsb\r
200 asm     add     di,bx\r
201 asm     movsb\r
202 asm     add     di,bx\r
203 asm     movsb\r
204 asm     add     di,bx\r
205 asm     movsb\r
206 asm     add     di,bx\r
207 asm     movsb\r
208 asm     add     di,bx\r
209 asm     movsb\r
210 asm     add     di,bx\r
211 asm     movsb\r
212 asm     add     di,bx\r
213 asm     movsb\r
214 \r
215 asm     mov     ax,[planesize]\r
216 asm     add     [WORD PTR dest],ax\r
217 \r
218 asm     loop    planeloop\r
219 \r
220 asm     mov     ax,ss\r
221 asm     mov     ds,ax\r
222 \r
223 }\r
224 #endif\r
225 \r
226 #if GRMODE == CGAGR\r
227 void MemDrawChar (int char8,byte far *dest,unsigned width,unsigned planesize)\r
228 {\r
229 asm     mov     si,[char8]\r
230 asm     shl     si,1\r
231 asm     shl     si,1\r
232 asm     shl     si,1\r
233 asm     shl     si,1            // index into char 8 segment\r
234 \r
235 asm     mov     ds,[WORD PTR grsegs+STARTTILE8*2]\r
236 asm     mov     es,[WORD PTR dest+2]\r
237 \r
238 asm     mov     bx,[width]\r
239 asm     sub     bx,2\r
240 \r
241 asm     mov     di,[WORD PTR dest]\r
242 \r
243 asm     movsw\r
244 asm     add     di,bx\r
245 asm     movsw\r
246 asm     add     di,bx\r
247 asm     movsw\r
248 asm     add     di,bx\r
249 asm     movsw\r
250 asm     add     di,bx\r
251 asm     movsw\r
252 asm     add     di,bx\r
253 asm     movsw\r
254 asm     add     di,bx\r
255 asm     movsw\r
256 asm     add     di,bx\r
257 asm     movsw\r
258 \r
259 asm     mov     ax,ss\r
260 asm     mov     ds,ax\r
261 \r
262         planesize++;            // shut the compiler up\r
263 }\r
264 #endif\r
265 \r
266 \r
267 /*\r
268 ====================\r
269 =\r
270 = ShiftScore\r
271 =\r
272 ====================\r
273 */\r
274 #if GRMODE == EGAGR\r
275 void ShiftScore (void)\r
276 {\r
277         spritetabletype far *spr;\r
278         spritetype _seg *dest;\r
279 \r
280         spr = &spritetable[SCOREBOXSPR-STARTSPRITES];\r
281         dest = (spritetype _seg *)grsegs[SCOREBOXSPR];\r
282 \r
283         CAL_ShiftSprite (FP_SEG(dest),dest->sourceoffset[0],\r
284                 dest->sourceoffset[1],spr->width,spr->height,2);\r
285 \r
286         CAL_ShiftSprite (FP_SEG(dest),dest->sourceoffset[0],\r
287                 dest->sourceoffset[2],spr->width,spr->height,4);\r
288 \r
289         CAL_ShiftSprite (FP_SEG(dest),dest->sourceoffset[0],\r
290                 dest->sourceoffset[3],spr->width,spr->height,6);\r
291 }\r
292 #endif\r
293 \r
294 /*\r
295 ===============\r
296 =\r
297 = ScoreThink\r
298 =\r
299 ===============\r
300 */\r
301 \r
302 void ScoreThink (objtype *ob)\r
303 {\r
304         char            str[10],*ch;\r
305         spritetype      _seg    *block;\r
306         byte            far *dest;\r
307         unsigned        i, length, width, planesize, number;\r
308 \r
309 //\r
310 // score changed\r
311 //\r
312         if ((gamestate.score>>16) != ob->temp1\r
313                 || (unsigned)gamestate.score != ob->temp2 )\r
314         {\r
315                 block = (spritetype _seg *)grsegs[SCOREBOXSPR];\r
316                 width = block->width[0];\r
317                 planesize = block->planesize[0];\r
318                 dest = (byte far *)grsegs[SCOREBOXSPR]+block->sourceoffset[0]\r
319                         + planesize + width*4 + 1*CHARWIDTH;\r
320 \r
321                 ltoa (gamestate.score,str,10);\r
322 \r
323                 // erase leading spaces\r
324                 length = strlen(str);\r
325                 for (i=6;i>length;i--)\r
326                         MemDrawChar (0,dest+=CHARWIDTH,width,planesize);\r
327 \r
328                 // draw digits\r
329                 ch = str;\r
330                 while (*ch)\r
331                         MemDrawChar (*ch++ - '0'+1,dest+=CHARWIDTH,width,planesize);\r
332 \r
333 #if GRMODE == EGAGR\r
334                 ShiftScore ();\r
335 #endif\r
336                 ob->needtoreact = true;\r
337                 ob->temp1 = gamestate.score>>16;\r
338                 ob->temp2 = gamestate.score;\r
339         }\r
340 \r
341 //\r
342 // flower power changed\r
343 //\r
344         if (mapon == 15)\r
345                 number = gamestate.boobusbombs;\r
346         else\r
347                 number = gamestate.flowerpowers;\r
348         if (number != ob->temp3)\r
349         {\r
350                 block = (spritetype _seg *)grsegs[SCOREBOXSPR];\r
351                 width = block->width[0];\r
352                 planesize = block->planesize[0];\r
353                 dest = (byte far *)grsegs[SCOREBOXSPR]+block->sourceoffset[0]\r
354                         + planesize + width*20 + 5*CHARWIDTH;\r
355 \r
356                 if (number > 99)\r
357                         strcpy (str,"99");\r
358                 else\r
359                         ltoa (number,str,10);\r
360 \r
361                 // erase leading spaces\r
362                 length = strlen(str);\r
363                 for (i=2;i>length;i--)\r
364                         MemDrawChar (0,dest+=CHARWIDTH,width,planesize);\r
365 \r
366                 // draw digits\r
367                 ch = str;\r
368                 while (*ch)\r
369                         MemDrawChar (*ch++ - '0'+1,dest+=CHARWIDTH,width,planesize);\r
370 \r
371 #if GRMODE == EGAGR\r
372                 ShiftScore ();\r
373 #endif\r
374                 ob->needtoreact = true;\r
375                 ob->temp3 = gamestate.flowerpowers;\r
376         }\r
377 \r
378 //\r
379 // lives changed\r
380 //\r
381         if (gamestate.lives != ob->temp4)\r
382         {\r
383                 block = (spritetype _seg *)grsegs[SCOREBOXSPR];\r
384                 width = block->width[0];\r
385                 planesize = block->planesize[0];\r
386                 dest = (byte far *)grsegs[SCOREBOXSPR]+block->sourceoffset[0]\r
387                         + planesize + width*20 + 2*CHARWIDTH;\r
388 \r
389                 if (gamestate.lives>9)\r
390                         MemDrawChar ('9' - '0'+1,dest,width,planesize);\r
391                 else\r
392                         MemDrawChar (gamestate.lives +1,dest,width,planesize);\r
393 \r
394 #if GRMODE == EGAGR\r
395                 ShiftScore ();\r
396 #endif\r
397                 ob->needtoreact = true;\r
398                 ob->temp4 = gamestate.lives;\r
399         }\r
400 \r
401         if (originxglobal != ob->x || originyglobal != ob->y)\r
402                 ob->needtoreact = true;\r
403 }\r
404 \r
405 \r
406 /*\r
407 ===============\r
408 =\r
409 = ScoreReact\r
410 =\r
411 ===============\r
412 */\r
413 \r
414 void ScoreReact (objtype *ob)\r
415 {\r
416         ob->x = originxglobal;\r
417         ob->y = originyglobal;\r
418 \r
419 #if GRMODE == EGAGR\r
420         RF_PlaceSprite (&ob->sprite\r
421                 ,ob->x+4*PIXGLOBAL\r
422                 ,ob->y+4*PIXGLOBAL\r
423                 ,SCOREBOXSPR\r
424                 ,spritedraw\r
425                 ,PRIORITIES-1);\r
426 #endif\r
427 #if GRMODE == CGAGR\r
428         RF_PlaceSprite (&ob->sprite\r
429                 ,ob->x+8*PIXGLOBAL\r
430                 ,ob->y+8*PIXGLOBAL\r
431                 ,SCOREBOXSPR\r
432                 ,spritedraw\r
433                 ,PRIORITIES-1);\r
434 #endif\r
435 }\r
436 \r
437 \r
438 /*\r
439 =============================================================================\r
440 \r
441                                                 FLOWER POWER ROUTINES\r
442 \r
443 temp1 = 8, same as power bonus\r
444 temp2 = initial direction\r
445 \r
446 =============================================================================\r
447 */\r
448 \r
449 void    PowerCount                      (objtype *ob);\r
450 void    PowerContact            (objtype *ob, objtype *hit);\r
451 void    PowerReact                      (objtype *ob);\r
452 \r
453 extern  statetype s_flowerpower1;\r
454 extern  statetype s_flowerpower2;\r
455 \r
456 extern  statetype s_boobusbomb1;\r
457 extern  statetype s_boobusbomb2;\r
458 \r
459 extern  statetype s_bombexplode;\r
460 extern  statetype s_bombexplode2;\r
461 extern  statetype s_bombexplode3;\r
462 extern  statetype s_bombexplode4;\r
463 extern  statetype s_bombexplode5;\r
464 extern  statetype s_bombexplode6;\r
465 \r
466 extern  statetype s_powerblink1;\r
467 extern  statetype s_powerblink2;\r
468 \r
469 statetype s_flowerpower1        = {FLOWERPOWER1SPR,FLOWERPOWER1SPR,stepthink,false,\r
470         false,10, 0,0, ProjectileThink, PowerContact, PowerReact, &s_flowerpower2};\r
471 statetype s_flowerpower2        = {FLOWERPOWER2SPR,FLOWERPOWER2SPR,stepthink,false,\r
472         false,10, 0,0, ProjectileThink, PowerContact, PowerReact, &s_flowerpower1};\r
473 \r
474 statetype s_boobusbomb1 = {BOOBUSBOMB1SPR,BOOBUSBOMB1SPR,stepthink,false,\r
475         false,5, 0,0, ProjectileThink, PowerContact, PowerReact, &s_boobusbomb2};\r
476 statetype s_boobusbomb2 = {BOOBUSBOMB3SPR,BOOBUSBOMB3SPR,stepthink,false,\r
477         false,5, 0,0, ProjectileThink, PowerContact, PowerReact, &s_boobusbomb1};\r
478 \r
479 statetype s_bombexplode = {BOOBUSBOOM1SPR,BOOBUSBOOM1SPR,step,false,\r
480         false,5, 0,0, NULL, NULL, DrawReact, &s_bombexplode2};\r
481 statetype s_bombexplode2= {BOOBUSBOOM2SPR,BOOBUSBOOM2SPR,step,false,\r
482         false,5, 0,0, NULL, NULL, DrawReact, &s_bombexplode3};\r
483 statetype s_bombexplode3= {BOOBUSBOOM1SPR,BOOBUSBOOM1SPR,step,false,\r
484         false,5, 0,0, NULL, NULL, DrawReact, &s_bombexplode4};\r
485 statetype s_bombexplode4= {BOOBUSBOOM2SPR,BOOBUSBOOM2SPR,step,false,\r
486         false,5, 0,0, NULL, NULL, DrawReact, &s_bombexplode5};\r
487 statetype s_bombexplode5= {BOOBUSBOOM1SPR,BOOBUSBOOM1SPR,step,false,\r
488         false,5, 0,0, NULL, NULL, DrawReact, &s_bombexplode6};\r
489 statetype s_bombexplode6= {BOOBUSBOOM2SPR,BOOBUSBOOM2SPR,step,false,\r
490         false,5, 0,0, NULL, NULL, DrawReact, NULL};\r
491 \r
492 statetype s_powerblink1 = {FLOWERPOWER1SPR,FLOWERPOWER1SPR,step,false,\r
493         false,5, 0,0, PowerCount, NULL, DrawReact, &s_powerblink2};\r
494 statetype s_powerblink2 = {-1,-1,step,false,\r
495         false,5, 0,0, PowerCount, NULL, DrawReact, &s_powerblink1};\r
496 \r
497 \r
498 /*\r
499 ===============\r
500 =\r
501 = ThrowPower\r
502 =\r
503 ===============\r
504 */\r
505 \r
506 void ThrowPower (unsigned x, unsigned y, int dir)\r
507 {\r
508         statetype *startstate;\r
509 \r
510         if (mapon == 15)\r
511         {\r
512                 if (!gamestate.boobusbombs)\r
513                 {\r
514                         SD_PlaySound (NOWAYSND);\r
515                         return;                                         // no bombs to throw\r
516                 }\r
517                 SD_PlaySound (THROWBOMBSND);\r
518                 gamestate.bombsthislevel--;\r
519                 gamestate.boobusbombs--;\r
520         }\r
521         else\r
522         {\r
523                 if (!gamestate.flowerpowers)\r
524                 {\r
525                         SD_PlaySound (NOWAYSND);\r
526                         return;                                         // no flower power to throw\r
527                 }\r
528                 SD_PlaySound (THROWSND);\r
529                 gamestate.flowerpowers--;\r
530         }\r
531 \r
532 \r
533 \r
534         GetNewObj (true);\r
535         new->obclass = powerobj;\r
536         new->temp2 = dir;\r
537         new->x = x;\r
538         new->y = y;\r
539         new->tileleft = new->tileright = x>>G_T_SHIFT;\r
540         new->tiletop = new->tilebottom = y>>G_T_SHIFT;\r
541         new->ydir = -1;\r
542 \r
543         switch (dir)\r
544         {\r
545         case dir_North:\r
546                 new->xspeed = 0;\r
547                 new->yspeed = SPDPOWERUP;\r
548                 break;\r
549         case dir_East:\r
550                 new->xspeed = SPDPOWER;\r
551                 new->yspeed = SPDPOWERY;\r
552                 break;\r
553         case dir_South:\r
554                 new->xspeed = 0;\r
555                 new->yspeed = SPDPOWER;\r
556                 break;\r
557         case dir_West:\r
558                 new->xspeed = -SPDPOWER;\r
559                 new->yspeed = SPDPOWERY;\r
560                 break;\r
561         default:\r
562                 Quit ("ThrowPower: Bad dir!");\r
563         }\r
564 \r
565         if (mapon != 15)\r
566         {\r
567                 new->temp1 = 8;                                 // flower power bonus\r
568                 startstate = &s_flowerpower1;\r
569         }\r
570         else\r
571         {\r
572                 new->temp1 = 10;                                // boobus bomb bonus\r
573                 startstate = &s_boobusbomb1;\r
574         }\r
575         new->active = removable;\r
576 \r
577 #if 0\r
578         new->x -= 5*new->xspeed;                // make sure they hit nearby walls\r
579         new->y -= 5*new->yspeed;\r
580 #endif\r
581         NewState (new,startstate);\r
582 #if 0\r
583         new->xmove = 5*new->xspeed;\r
584         new->ymove = 5*new->yspeed;\r
585         ClipToWalls (new);\r
586 #endif\r
587 }\r
588 \r
589 /*\r
590 ============================\r
591 =\r
592 = PowerCount\r
593 =\r
594 ============================\r
595 */\r
596 \r
597 void    PowerCount (objtype *ob)\r
598 {\r
599         ob->temp2+=tics;\r
600 \r
601         ob->shapenum = 0;\r
602 \r
603         if (ob->temp2 > POWERCOUNT)\r
604                 RemoveObj(ob);\r
605 }\r
606 \r
607 \r
608 /*\r
609 ============================\r
610 =\r
611 = CalcSingleGravity\r
612 =\r
613 ============================\r
614 */\r
615 \r
616 void    CalcSingleGravity (void)\r
617 {\r
618         unsigned        speed;\r
619         long    i;\r
620 //\r
621 // only accelerate on odd tics, because of limited precision\r
622 //\r
623         speed = 0;\r
624         singlegravity = 0;\r
625         for (i=lasttimecount-tics;i<lasttimecount;i++)\r
626         {\r
627                 if (i&1)\r
628                 {\r
629                         speed+=ACCGRAVITY;\r
630                         if (speed>SPDMAXY)\r
631                           speed=SPDMAXY;\r
632                 }\r
633                 singlegravity+=speed;\r
634         }\r
635 \r
636         singlegravity/=2;\r
637 }\r
638 \r
639 \r
640 /*\r
641 ============================\r
642 =\r
643 = PowerContact\r
644 =\r
645 ============================\r
646 */\r
647 \r
648 void    PowerContact (objtype *ob, objtype *hit)\r
649 {\r
650         unsigned        x,y,yspot,xspot;\r
651 \r
652         switch (hit->obclass)\r
653         {\r
654         case    broccoobj:\r
655         case    tomatobj:\r
656         case    carrotobj:\r
657         case    celeryobj:\r
658         case    asparobj:\r
659         case    taterobj:\r
660         case    frenchyobj:\r
661         case    squashobj:\r
662         case    apelobj:\r
663         case    peapodobj:\r
664         case    peabrainobj:\r
665                 ChangeToFlower (hit);\r
666                 RemoveObj (ob);\r
667                 break;\r
668         case    boobusobj:\r
669                 if (!--hit->temp4)\r
670                 {\r
671                 // killed boobus\r
672                         GivePoints (50000);\r
673                         GivePoints (50000);\r
674                         hit->obclass = inertobj;\r
675                         ChangeState (hit,&s_boobusdie);\r
676                         hit->temp1 = 0;         // death count\r
677                 }\r
678                 SD_PlaySound (BOMBBOOMSND);\r
679                 ChangeState (ob,&s_bombexplode);\r
680                 break;\r
681         }\r
682 }\r
683 \r
684 \r
685 /*\r
686 ============================\r
687 =\r
688 = PowerReact\r
689 =\r
690 ============================\r
691 */\r
692 \r
693 void    PowerReact (objtype *ob)\r
694 {\r
695         unsigned wall,absx,absy,angle,newangle;\r
696         unsigned long speed;\r
697 \r
698         PLACESPRITE;\r
699         if (ob->hiteast || ob->hitwest)\r
700         {\r
701                 ob->xspeed= -ob->xspeed/2;\r
702                 ob->obclass = bonusobj;\r
703         }\r
704 \r
705         if (ob->hitsouth)\r
706         {\r
707                 if ( ob->hitsouth == 17)        // go through pole holes\r
708                 {\r
709                         if (ob->temp2 != dir_North)\r
710                                 ob->obclass = bonusobj;\r
711                         ob->top-=32;\r
712                         ob->y-=32;\r
713                         ob->xspeed = 0;\r
714                         ob->x = ob->tilemidx*TILEGLOBAL + 4*PIXGLOBAL;\r
715                 }\r
716                 else\r
717                 {\r
718                         ob->yspeed= -ob->yspeed/2;\r
719                 }\r
720                 return;\r
721         }\r
722 \r
723         wall = ob->hitnorth;\r
724         if ( wall == 17)        // go through pole holes\r
725         {\r
726                 if (ob->temp2 != dir_South)\r
727                         ob->obclass = bonusobj;\r
728                 ob->bottom+=32;\r
729                 ob->y+=32;\r
730                 ob->xspeed = 0;\r
731                 ob->x = ob->tilemidx*TILEGLOBAL + 4*PIXGLOBAL;\r
732         }\r
733         else if (wall)\r
734         {\r
735                 ob->obclass = bonusobj;\r
736                 if (ob->yspeed < 0)\r
737                         ob->yspeed = 0;\r
738 \r
739                 absx = abs(ob->xspeed);\r
740                 absy = ob->yspeed;\r
741                 if (absx>absy)\r
742                 {\r
743                         if (absx>absy*2)        // 22 degrees\r
744                         {\r
745                                 angle = 0;\r
746                                 speed = absx*286;       // x*sqrt(5)/2\r
747                         }\r
748                         else                            // 45 degrees\r
749                         {\r
750                                 angle = 1;\r
751                                 speed = absx*362;       // x*sqrt(2)\r
752                         }\r
753                 }\r
754                 else\r
755                 {\r
756                         if (absy>absx*2)        // 90 degrees\r
757                         {\r
758                                 angle = 3;\r
759                                 speed = absy*256;\r
760                         }\r
761                         else\r
762                         {\r
763                                 angle = 2;              // 67 degrees\r
764                                 speed = absy*286;       // y*sqrt(5)/2\r
765                         }\r
766                 }\r
767                 if (ob->xspeed > 0)\r
768                         angle = 7-angle;\r
769 \r
770                 speed >>= 1;\r
771                 newangle = bounceangle[ob->hitnorth][angle];\r
772                 switch (newangle)\r
773                 {\r
774                 case 0:\r
775                         ob->xspeed = speed / 286;\r
776                         ob->yspeed = -ob->xspeed / 2;\r
777                         break;\r
778                 case 1:\r
779                         ob->xspeed = speed / 362;\r
780                         ob->yspeed = -ob->xspeed;\r
781                         break;\r
782                 case 2:\r
783                         ob->yspeed = -(speed / 286);\r
784                         ob->xspeed = -ob->yspeed / 2;\r
785                         break;\r
786                 case 3:\r
787 \r
788                 case 4:\r
789                         ob->xspeed = 0;\r
790                         ob->yspeed = -(speed / 256);\r
791                         break;\r
792                 case 5:\r
793                         ob->yspeed = -(speed / 286);\r
794                         ob->xspeed = ob->yspeed / 2;\r
795                         break;\r
796                 case 6:\r
797                         ob->xspeed = ob->yspeed = -(speed / 362);\r
798                         break;\r
799                 case 7:\r
800                         ob->xspeed = -(speed / 286);\r
801                         ob->yspeed = ob->xspeed / 2;\r
802                         break;\r
803 \r
804                 case 8:\r
805                         ob->xspeed = -(speed / 286);\r
806                         ob->yspeed = -ob->xspeed / 2;\r
807                         break;\r
808                 case 9:\r
809                         ob->xspeed = -(speed / 362);\r
810                         ob->yspeed = -ob->xspeed;\r
811                         break;\r
812                 case 10:\r
813                         ob->yspeed = speed / 286;\r
814                         ob->xspeed = -ob->yspeed / 2;\r
815                         break;\r
816                 case 11:\r
817 \r
818                 case 12:\r
819                         ob->xspeed = 0;\r
820                         ob->yspeed = -(speed / 256);\r
821                         break;\r
822                 case 13:\r
823                         ob->yspeed = speed / 286;\r
824                         ob->xspeed = ob->yspeed / 2;\r
825                         break;\r
826                 case 14:\r
827                         ob->xspeed = speed / 362;\r
828                         ob->yspeed = speed / 362;\r
829                         break;\r
830                 case 15:\r
831                         ob->xspeed = speed / 286;\r
832                         ob->yspeed = ob->xspeed / 2;\r
833                         break;\r
834                 }\r
835 \r
836                 if (speed < 256*16)\r
837                 {\r
838                         if (mapon == 15)\r
839                         {\r
840                                 ob->ydir = -1;                  // bonus stuff flies up when touched\r
841                                 ob->temp2 = ob->shapenum = BOOBUSBOMB1SPR;\r
842                                 ob->temp3 = ob->temp2 + 2;\r
843                                 ob->needtoclip = 0;\r
844                                 ChangeState (ob,&s_bonus);\r
845                         }\r
846                         else\r
847                         {\r
848                                 ChangeState (ob,&s_powerblink1);\r
849                                 ob->needtoclip = 0;\r
850                                 ob->temp2 = 0;          // blink time\r
851                         }\r
852                 }\r
853         }\r
854 }\r
855 \r
856 \r
857 /*\r
858 =============================================================================\r
859 \r
860                                                            MINI KEEN\r
861 \r
862 player->temp1 = dir\r
863 player->temp2 = animation stage\r
864 \r
865 #define WORLDKEENSLEEP1SPR              238\r
866 #define WORLDKEENSLEEP2SPR              239\r
867 #define WORLDKEENWAVE1SPR               240\r
868 #define WORLDKEENWAVE2SPR               241\r
869 =============================================================================\r
870 */\r
871 \r
872 void    SpawnWorldKeen (int tilex, int tiley);\r
873 void    KeenWorldThink          (objtype *ob);\r
874 void    KeenWorldWalk           (objtype *ob);\r
875 \r
876 extern  statetype s_worldkeen;\r
877 \r
878 extern  statetype s_worldkeenwave1;\r
879 extern  statetype s_worldkeenwave2;\r
880 extern  statetype s_worldkeenwave3;\r
881 extern  statetype s_worldkeenwave4;\r
882 extern  statetype s_worldkeenwave5;\r
883 \r
884 extern  statetype s_worldkeenwait;\r
885 \r
886 extern  statetype s_worldkeensleep1;\r
887 extern  statetype s_worldkeensleep2;\r
888 \r
889 extern  statetype s_worldwalk;\r
890 \r
891 #pragma warn -sus\r
892 \r
893 statetype s_worldkeen   = {NULL,NULL,stepthink,false,\r
894         false,360, 0,0, KeenWorldThink, NULL, DrawReact, &s_worldkeenwave1};\r
895 \r
896 statetype s_worldkeenwave1= {WORLDKEENWAVE1SPR,WORLDKEENWAVE1SPR,stepthink,false,\r
897         false,20, 0,0, KeenWorldThink, NULL, DrawReact, &s_worldkeenwave2};\r
898 statetype s_worldkeenwave2= {WORLDKEENWAVE2SPR,WORLDKEENWAVE2SPR,stepthink,false,\r
899         false,20, 0,0, KeenWorldThink, NULL, DrawReact, &s_worldkeenwave3};\r
900 statetype s_worldkeenwave3= {WORLDKEENWAVE1SPR,WORLDKEENWAVE1SPR,stepthink,false,\r
901         false,20, 0,0, KeenWorldThink, NULL, DrawReact, &s_worldkeenwave4};\r
902 statetype s_worldkeenwave4= {WORLDKEENWAVE2SPR,WORLDKEENWAVE2SPR,stepthink,false,\r
903         false,20, 0,0, KeenWorldThink, NULL, DrawReact, &s_worldkeenwave5};\r
904 statetype s_worldkeenwave5= {WORLDKEENWAVE1SPR,WORLDKEENWAVE1SPR,stepthink,false,\r
905         false,20, 0,0, KeenWorldThink, NULL, DrawReact, &s_worldkeenwait};\r
906 \r
907 statetype s_worldkeenwait       = {WORLDKEEND3SPR,WORLDKEEND3SPR,stepthink,false,\r
908         false,400, 0,0, KeenWorldThink, NULL, DrawReact, &s_worldkeensleep1};\r
909 \r
910 statetype s_worldkeensleep1     = {WORLDKEENSLEEP1SPR,WORLDKEENSLEEP1SPR,stepthink,false,\r
911         false,30, 0,0, KeenWorldThink, NULL, DrawReact, &s_worldkeensleep2};\r
912 statetype s_worldkeensleep2     = {WORLDKEENSLEEP2SPR,WORLDKEENSLEEP2SPR,stepthink,false,\r
913         false,90, 0,0, KeenWorldThink, NULL, DrawReact, &s_worldkeensleep2};\r
914 \r
915 statetype s_worldwalk   = {NULL,NULL,slide,false,\r
916         false,4, 16,16, KeenWorldWalk, NULL, DrawReact, &s_worldwalk};\r
917 \r
918 #pragma warn +sus\r
919 \r
920 /*\r
921 ======================\r
922 =\r
923 = SpawnWorldKeen\r
924 =\r
925 ======================\r
926 */\r
927 \r
928 void    SpawnWorldKeen (int tilex, int tiley)\r
929 {\r
930         player->obclass = keenobj;\r
931         if (!gamestate.worldx)\r
932         {\r
933                 player->x = tilex<<G_T_SHIFT;\r
934                 player->y = tiley<<G_T_SHIFT;\r
935         }\r
936         else\r
937         {\r
938                 player->x = gamestate.worldx;\r
939                 player->y = gamestate.worldy;\r
940         }\r
941 \r
942         player->active = yes;\r
943         player->needtoclip = true;\r
944         player->xdir = 0;\r
945         player->ydir = 0;\r
946         player->temp1 = dir_West;\r
947         player->temp2 = 3;\r
948         player->shapenum = 3+WORLDKEENL1SPR-1;                          // feet together\r
949         NewState (player,&s_worldkeen);\r
950 }\r
951 \r
952 \r
953 /*\r
954 ======================\r
955 =\r
956 = CheckEnterLevel\r
957 =\r
958 ======================\r
959 */\r
960 \r
961 void    CheckEnterLevel (objtype *ob)\r
962 {\r
963         int     x,y,tile;\r
964 \r
965         for (y=ob->tiletop;y<=ob->tilebottom;y++)\r
966                 for (x=ob->tileleft;x<=ob->tileright;x++)\r
967                 {\r
968                         tile = *((unsigned _seg *)mapsegs[2]+mapbwidthtable[y]/2+x);\r
969                         if (tile >= 3 && tile <=18)\r
970                         {\r
971                         //\r
972                         // enter level!\r
973                         //\r
974                                 if (tile == 17)\r
975                                 {\r
976                                         if (gamestate.boobusbombs < 12)\r
977                                         {\r
978                                                 VW_FixRefreshBuffer ();\r
979                                                 US_CenterWindow (26,6);\r
980                                                 PrintY+= 8;\r
981                                                 US_CPrint ("You can't possibly\n"\r
982                                                                    "defeat King Boobus Tuber\n"\r
983                                                                    "with less than 12 bombs!");\r
984                                                 VW_UpdateScreen ();\r
985                                                 IN_Ack ();\r
986                                                 RF_ForceRefresh ();\r
987                                                 return;\r
988                                         }\r
989                                 }\r
990                                 gamestate.worldx = ob->x;\r
991                                 gamestate.worldy = ob->y;\r
992                                 gamestate.mapon = tile-2;\r
993                                 playstate = levelcomplete;\r
994                                 SD_PlaySound (ENTERLEVELSND);\r
995                         }\r
996                 }\r
997 }\r
998 \r
999 \r
1000 /*\r
1001 ======================\r
1002 =\r
1003 = KeenWorldThink\r
1004 =\r
1005 ======================\r
1006 */\r
1007 \r
1008 void    KeenWorldThink (objtype *ob)\r
1009 {\r
1010         if (c.dir!=dir_None)\r
1011         {\r
1012                 ob->state = &s_worldwalk;\r
1013                 ob->temp2 = 0;\r
1014                 KeenWorldWalk (ob);\r
1015         }\r
1016 \r
1017         if (c.button0 || c.button1)\r
1018                 CheckEnterLevel(ob);\r
1019 }\r
1020 \r
1021 \r
1022 /*\r
1023 ======================\r
1024 =\r
1025 = KeenWorldWalk\r
1026 =\r
1027 ======================\r
1028 */\r
1029 \r
1030 int worldshapes[8] = {WORLDKEENU1SPR-1,WORLDKEENUR1SPR-1,WORLDKEENR1SPR-1,\r
1031         WORLDKEENDR1SPR-1,WORLDKEEND1SPR-1,WORLDKEENDL1SPR-1,WORLDKEENL1SPR-1,\r
1032         WORLDKEENUL1SPR-1};\r
1033 \r
1034 int worldanims[4] ={2,3,1,3};\r
1035 \r
1036 void    KeenWorldWalk (objtype *ob)\r
1037 {\r
1038         ob->xdir = c.xaxis;\r
1039         ob->ydir = c.yaxis;\r
1040 \r
1041         if (++ob->temp2==4)\r
1042                 ob->temp2 = 0;\r
1043 \r
1044         if (c.button0 || c.button1)\r
1045                 CheckEnterLevel(ob);\r
1046 \r
1047         if (c.dir == dir_None)\r
1048         {\r
1049                 ob->state = &s_worldkeen;\r
1050                 ob->shapenum = worldshapes[ob->temp1]+3;\r
1051                 return;\r
1052         }\r
1053 \r
1054         ob->temp1 = c.dir;\r
1055         ob->shapenum = worldshapes[ob->temp1]+worldanims[ob->temp2];\r
1056 }\r
1057 \r
1058 \r
1059 /*\r
1060 =============================================================================\r
1061 \r
1062                                                                 KEEN\r
1063 \r
1064 player->temp1 = pausetime / pointer to zees when sleeping\r
1065 player->temp2 = pausecount / stagecount\r
1066 player->temp3 =\r
1067 player->temp4 = pole x location\r
1068 \r
1069 =============================================================================\r
1070 */\r
1071 \r
1072 void    KeenStandThink          (objtype *ob);\r
1073 void    KeenPauseThink          (objtype *ob);\r
1074 void    KeenGoSleepThink        (objtype *ob);\r
1075 void    KeenSleepThink          (objtype *ob);\r
1076 void    KeenDieThink            (objtype *ob);\r
1077 void    KeenDuckThink           (objtype *ob);\r
1078 void    KeenDropDownThink       (objtype *ob);\r
1079 void    KeenWalkThink           (objtype *ob);\r
1080 void    KeenAirThink            (objtype *ob);\r
1081 void    KeenPoleThink           (objtype *ob);\r
1082 void    KeenClimbThink          (objtype *ob);\r
1083 void    KeenDropThink           (objtype *ob);\r
1084 void    KeenDive                        (objtype *ob);\r
1085 void    KeenThrow                       (objtype *ob);\r
1086 \r
1087 void    KeenContact             (objtype *ob, objtype *hit);\r
1088 void    KeenSimpleReact         (objtype *ob);\r
1089 void    KeenStandReact          (objtype *ob);\r
1090 void    KeenWalkReact           (objtype *ob);\r
1091 void    KeenPoleReact           (objtype *ob);\r
1092 void    KeenAirReact            (objtype *ob);\r
1093 void    KeenDiveReact           (objtype *ob);\r
1094 void    KeenSlideReact          (objtype *ob);\r
1095 \r
1096 //-------------------\r
1097 \r
1098 extern  statetype s_keenzee1;\r
1099 extern  statetype s_keenzee2;\r
1100 extern  statetype s_keenzee3;\r
1101 extern  statetype s_keenzee4;\r
1102 extern  statetype s_keenzee5;\r
1103 \r
1104 //-------------------\r
1105 \r
1106 extern  statetype       s_keenstand;\r
1107 extern  statetype s_keenpauselook;\r
1108 extern  statetype s_keenyawn1;\r
1109 extern  statetype s_keenyawn2;\r
1110 extern  statetype s_keenyawn3;\r
1111 extern  statetype s_keenyawn4;\r
1112 \r
1113 extern  statetype s_keenwait1;\r
1114 extern  statetype s_keenwait2;\r
1115 extern  statetype s_keenwait3;\r
1116 extern  statetype s_keenwait4;\r
1117 extern  statetype s_keenwait5;\r
1118 extern  statetype s_keenwait6;\r
1119 \r
1120 extern  statetype s_keenmoon1;\r
1121 extern  statetype s_keenmoon2;\r
1122 extern  statetype s_keenmoon3;\r
1123 \r
1124 extern  statetype s_keengosleep1;\r
1125 extern  statetype s_keengosleep2;\r
1126 extern  statetype s_keensleep1;\r
1127 extern  statetype s_keensleep2;\r
1128 \r
1129 extern  statetype s_keendie1;\r
1130 extern  statetype s_keendie2;\r
1131 extern  statetype s_keendie3;\r
1132 extern  statetype s_keendie4;\r
1133 \r
1134 extern  statetype       s_keenlookup;\r
1135 extern  statetype       s_keenduck;\r
1136 extern  statetype       s_keendrop;\r
1137 \r
1138 //-------------------\r
1139 \r
1140 extern  statetype s_keenreach;\r
1141 \r
1142 extern  statetype s_keenpole;\r
1143 \r
1144 extern  statetype s_keenclimb1;\r
1145 extern  statetype s_keenclimb2;\r
1146 extern  statetype s_keenclimb3;\r
1147 \r
1148 extern  statetype s_keenslide1;\r
1149 extern  statetype s_keenslide2;\r
1150 extern  statetype s_keenslide3;\r
1151 extern  statetype s_keenslide4;\r
1152 \r
1153 extern  statetype s_keenpolethrow1;\r
1154 extern  statetype s_keenpolethrow2;\r
1155 extern  statetype s_keenpolethrow3;\r
1156 \r
1157 extern  statetype s_keenpolethrowup1;\r
1158 extern  statetype s_keenpolethrowup2;\r
1159 extern  statetype s_keenpolethrowup3;\r
1160 \r
1161 extern  statetype s_keenpolethrowdown1;\r
1162 extern  statetype s_keenpolethrowdown2;\r
1163 extern  statetype s_keenpolethrowdown3;\r
1164 \r
1165 //-------------------\r
1166 \r
1167 extern  statetype       s_keenwalk1;\r
1168 extern  statetype       s_keenwalk2;\r
1169 extern  statetype       s_keenwalk3;\r
1170 extern  statetype       s_keenwalk4;\r
1171 \r
1172 extern  statetype       s_keenthrow1;\r
1173 extern  statetype       s_keenthrow2;\r
1174 extern  statetype       s_keenthrow3;\r
1175 extern  statetype       s_keenthrow4;\r
1176 \r
1177 extern  statetype       s_keenthrowup1;\r
1178 extern  statetype       s_keenthrowup2;\r
1179 extern  statetype       s_keenthrowup3;\r
1180 \r
1181 extern  statetype       s_keendive1;\r
1182 extern  statetype       s_keendive2;\r
1183 extern  statetype       s_keendive3;\r
1184 \r
1185 //-------------------\r
1186 \r
1187 extern  statetype s_keenjumpup1;\r
1188 extern  statetype s_keenjumpup2;\r
1189 extern  statetype s_keenjumpup3;\r
1190 \r
1191 extern  statetype s_keenjump1;\r
1192 extern  statetype s_keenjump2;\r
1193 extern  statetype s_keenjump3;\r
1194 \r
1195 extern  statetype s_keenairthrow1;\r
1196 extern  statetype s_keenairthrow2;\r
1197 extern  statetype s_keenairthrow3;\r
1198 \r
1199 extern  statetype s_keenairthrowup1;\r
1200 extern  statetype s_keenairthrowup2;\r
1201 extern  statetype s_keenairthrowup3;\r
1202 \r
1203 extern  statetype s_keenairthrowdown1;\r
1204 extern  statetype s_keenairthrowdown2;\r
1205 extern  statetype s_keenairthrowdown3;\r
1206 \r
1207 #pragma warn -sus\r
1208 \r
1209 //-------------------\r
1210 \r
1211 statetype s_keenzee1    = {KEENZEES1SPR,KEENZEES1SPR,step,false,\r
1212         false,30, 0,0, NULL, NULL, DrawReact, &s_keenzee2};\r
1213 statetype s_keenzee2    = {KEENZEES2SPR,KEENZEES2SPR,step,false,\r
1214         false,30, 0,0, NULL, NULL, DrawReact, &s_keenzee3};\r
1215 statetype s_keenzee3    = {KEENZEES3SPR,KEENZEES3SPR,step,false,\r
1216         false,30, 0,0, NULL, NULL, DrawReact, &s_keenzee1};\r
1217 \r
1218 //-------------------\r
1219 \r
1220 statetype s_keenstand   = {KEENSTANDLSPR,KEENSTANDRSPR,stepthink,false,\r
1221         true,4, 0,16, KeenPauseThink, KeenContact, KeenStandReact, &s_keenstand};\r
1222 statetype s_keenpauselook= {KEENLOOKULSPR,KEENLOOKURSPR,stepthink,false,\r
1223         true,60, 0,0, KeenPauseThink, KeenContact, KeenStandReact, &s_keenstand};\r
1224 statetype s_keenyawn1   = {KEENYAWN1SPR,KEENYAWN1SPR,stepthink,false,\r
1225         true,40, 0,0, KeenPauseThink, KeenContact, KeenStandReact, &s_keenyawn2};\r
1226 statetype s_keenyawn2   = {KEENYAWN2SPR,KEENYAWN2SPR,stepthink,false,\r
1227         true,40, 0,0, KeenPauseThink, KeenContact, KeenStandReact, &s_keenyawn3};\r
1228 statetype s_keenyawn3   = {KEENYAWN3SPR,KEENYAWN3SPR,stepthink,false,\r
1229         true,40, 0,0, KeenPauseThink, KeenContact, KeenStandReact, &s_keenyawn4};\r
1230 statetype s_keenyawn4   = {KEENYAWN4SPR,KEENYAWN4SPR,stepthink,false,\r
1231         true,40, 0,0, KeenPauseThink, KeenContact, KeenStandReact, &s_keenstand};\r
1232 \r
1233 statetype s_keenwait1   = {KEENWAITL2SPR,KEENWAITR2SPR,stepthink,false,\r
1234         true,90, 0,0, KeenPauseThink, KeenContact, KeenStandReact, &s_keenwait2};\r
1235 statetype s_keenwait2   = {KEENWAITL1SPR,KEENWAITR1SPR,stepthink,false,\r
1236         true,10, 0,0, KeenPauseThink, KeenContact, KeenStandReact, &s_keenwait3};\r
1237 statetype s_keenwait3   = {KEENWAITL2SPR,KEENWAITR2SPR,stepthink,false,\r
1238         true,90, 0,0, KeenPauseThink, KeenContact, KeenStandReact, &s_keenwait4};\r
1239 statetype s_keenwait4   = {KEENWAITL1SPR,KEENWAITR1SPR,stepthink,false,\r
1240         true,10, 0,0, KeenPauseThink, KeenContact, KeenStandReact, &s_keenwait5};\r
1241 statetype s_keenwait5   = {KEENWAITL2SPR,KEENWAITR2SPR,stepthink,false,\r
1242         true,90, 0,0, KeenPauseThink, KeenContact, KeenStandReact, &s_keenwait6};\r
1243 statetype s_keenwait6   = {KEENWAITL3SPR,KEENWAITR3SPR,stepthink,false,\r
1244         true,70, 0,0, KeenPauseThink, KeenContact, KeenStandReact, &s_keenstand};\r
1245 \r
1246 statetype s_keengosleep1= {KEENSLEEP1SPR,KEENSLEEP1SPR,stepthink,false,\r
1247         true,20, 0,0, KeenPauseThink, KeenContact, KeenStandReact, &s_keengosleep2};\r
1248 statetype s_keengosleep2= {KEENSLEEP2SPR,KEENSLEEP2SPR,step,false,\r
1249         true,20, 0,0, KeenGoSleepThink, KeenContact, KeenStandReact, &s_keensleep1};\r
1250 statetype s_keensleep1= {KEENSLEEP3SPR,KEENSLEEP3SPR,stepthink,false,\r
1251         true,120, 0,0, KeenSleepThink, KeenContact, KeenStandReact, &s_keensleep2};\r
1252 statetype s_keensleep2= {KEENSLEEP4SPR,KEENSLEEP4SPR,stepthink,false,\r
1253         true,120, 0,0, KeenSleepThink, KeenContact, KeenStandReact, &s_keensleep1};\r
1254 \r
1255 statetype s_keengetup   = {KEENGETUPLSPR,KEENGETUPRSPR,step,false,\r
1256         true,15, 0,0, NULL, KeenContact, KeenSimpleReact, &s_keenstand};\r
1257 \r
1258 statetype s_keendie1            = {KEENDREAM1SPR,KEENDREAM1SPR,step,false,\r
1259         false,20, 0,0, NULL, NULL, KeenSimpleReact, &s_keendie2};\r
1260 statetype s_keendie2            = {KEENDREAM2SPR,KEENDREAM2SPR,step,false,\r
1261         false,20, 0,0, NULL, NULL, KeenSimpleReact, &s_keendie3};\r
1262 statetype s_keendie3            = {KEENDREAM3SPR,KEENDREAM3SPR,step,false,\r
1263         false,120, 0,0, KeenDieThink, NULL, KeenSimpleReact, &s_keendie3};\r
1264 \r
1265 statetype s_keenlookup  = {KEENLOOKULSPR,KEENLOOKURSPR,think,false,\r
1266         true,0, 0,0, KeenStandThink, KeenContact, KeenStandReact, &s_keenlookup};\r
1267 \r
1268 statetype s_keenduck    = {KEENDUCKLSPR,KEENDUCKRSPR,think,false,\r
1269         true,0, 0,0, KeenDuckThink, KeenContact, KeenStandReact, &s_keenduck};\r
1270 \r
1271 statetype s_keendrop    = {KEENDUCKLSPR,KEENDUCKRSPR,step,false,\r
1272         false,0, 0,0, KeenDropDownThink, KeenContact, KeenSimpleReact, &s_keenjumpup3};\r
1273 \r
1274 //-------------------\r
1275 \r
1276 statetype s_keenpole    = {KEENSHINNYL1SPR,KEENSHINNYR1SPR,think,false,\r
1277         false,0, 0,0, KeenPoleThink, KeenContact, KeenSimpleReact, &s_keenpole};\r
1278 \r
1279 statetype s_keenclimb1  = {KEENSHINNYL1SPR,KEENSHINNYR1SPR,slidethink,false,\r
1280         false,8, 0,8, KeenClimbThink, KeenContact, KeenSimpleReact, &s_keenclimb2};\r
1281 statetype s_keenclimb2  = {KEENSHINNYL2SPR,KEENSHINNYR2SPR,slidethink,false,\r
1282         false,8, 0,8, KeenClimbThink, KeenContact, KeenSimpleReact, &s_keenclimb3};\r
1283 statetype s_keenclimb3  = {KEENSHINNYL3SPR,KEENSHINNYR3SPR,slidethink,false,\r
1284         false,8, 0,8, KeenClimbThink, KeenContact, KeenSimpleReact, &s_keenclimb1};\r
1285 \r
1286 statetype s_keenslide1  = {KEENSLIDED1SPR,KEENSLIDED1SPR,slide,false,\r
1287         false,8, 0,24, KeenDropThink, KeenContact, KeenSimpleReact, &s_keenslide2};\r
1288 statetype s_keenslide2  = {KEENSLIDED2SPR,KEENSLIDED2SPR,slide,false,\r
1289         false,8, 0,24, KeenDropThink, KeenContact, KeenSimpleReact, &s_keenslide3};\r
1290 statetype s_keenslide3  = {KEENSLIDED3SPR,KEENSLIDED3SPR,slide,false,\r
1291         false,8, 0,24, KeenDropThink, KeenContact, KeenSimpleReact, &s_keenslide4};\r
1292 statetype s_keenslide4  = {KEENSLIDED4SPR,KEENSLIDED4SPR,slide,false,\r
1293         false,8, 0,24, KeenDropThink, KeenContact, KeenSimpleReact, &s_keenslide1};\r
1294 \r
1295 statetype s_keenpolethrow1      = {KEENPTHROWL1SPR,KEENPTHROWR1SPR,step,false,\r
1296         false,8, 0,0, NULL, KeenContact, KeenSimpleReact, &s_keenpolethrow2};\r
1297 statetype s_keenpolethrow2      = {KEENPTHROWL2SPR,KEENPTHROWR2SPR,step,true,\r
1298         false,1, 0,0, KeenThrow, KeenContact, KeenSimpleReact, &s_keenpolethrow3};\r
1299 statetype s_keenpolethrow3      = {KEENPTHROWL2SPR,KEENPTHROWR2SPR,step,false,\r
1300         false,10, 0,0, NULL, KeenContact, KeenSimpleReact, &s_keenpole};\r
1301 \r
1302 statetype s_keenpolethrowup1 = {KEENPLTHROWU1SPR,KEENPRTHROWU1SPR,step,false,\r
1303         false,8, 0,0, NULL, KeenContact, KeenSimpleReact, &s_keenpolethrowup2};\r
1304 statetype s_keenpolethrowup2 = {KEENPLTHROWU2SPR,KEENPRTHROWU2SPR,step,true,\r
1305         false,1, 0,0, KeenThrow, KeenContact, KeenSimpleReact, &s_keenpolethrowup3};\r
1306 statetype s_keenpolethrowup3 = {KEENPLTHROWU2SPR,KEENPRTHROWU2SPR,step,false,\r
1307         false,10, 0,0, NULL, KeenContact, KeenSimpleReact, &s_keenpole};\r
1308 \r
1309 statetype s_keenpolethrowdown1 = {KEENPLTHROWD1SPR,KEENPRTHROWD1SPR,step,false,\r
1310         false,8, 0,0, NULL, KeenContact, KeenSimpleReact, &s_keenpolethrowdown2};\r
1311 statetype s_keenpolethrowdown2 = {KEENPLTHROWD2SPR,KEENPRTHROWD2SPR,step,true,\r
1312         false,1, 0,0, KeenThrow, KeenContact, KeenSimpleReact, &s_keenpolethrowdown3};\r
1313 statetype s_keenpolethrowdown3 = {KEENPLTHROWD2SPR,KEENPRTHROWD2SPR,step,false,\r
1314         false,10, 0,0, NULL, KeenContact, KeenSimpleReact, &s_keenpole};\r
1315 \r
1316 \r
1317 //-------------------\r
1318 \r
1319 statetype s_keenwalk1   = {KEENRUNL1SPR,KEENRUNR1SPR,slidethink,true,\r
1320         true,6, 24,0, KeenWalkThink, KeenContact, KeenWalkReact, &s_keenwalk2};\r
1321 statetype s_keenwalk2   = {KEENRUNL2SPR,KEENRUNR2SPR,slidethink,true,\r
1322         true,6, 24,0, KeenWalkThink, KeenContact, KeenWalkReact, &s_keenwalk3};\r
1323 statetype s_keenwalk3   = {KEENRUNL3SPR,KEENRUNR3SPR,slidethink,true,\r
1324         true,6, 24,0, KeenWalkThink, KeenContact, KeenWalkReact, &s_keenwalk4};\r
1325 statetype s_keenwalk4   = {KEENRUNL4SPR,KEENRUNR4SPR,slidethink,true,\r
1326         true,6, 24,0, KeenWalkThink, KeenContact, KeenWalkReact, &s_keenwalk1};\r
1327 \r
1328 statetype s_keenthrow1  = {KEENTHROWL1SPR,KEENTHROWR1SPR,step,true,\r
1329         true,4, 0,0, NULL, KeenContact, KeenStandReact, &s_keenthrow2};\r
1330 statetype s_keenthrow2  = {KEENTHROWL2SPR,KEENTHROWR2SPR,step,false,\r
1331         true,4, 0,0, NULL, KeenContact, KeenStandReact, &s_keenthrow3};\r
1332 statetype s_keenthrow3  = {KEENTHROWL3SPR,KEENTHROWR3SPR,step,true,\r
1333         true,1, 0,0, KeenThrow, KeenContact, KeenStandReact, &s_keenthrow4};\r
1334 statetype s_keenthrow4  = {KEENTHROWL3SPR,KEENTHROWR3SPR,step,false,\r
1335         true,10, 0,0, NULL, KeenContact, KeenStandReact, &s_keenstand};\r
1336 \r
1337 statetype s_keenthrowup1        = {KEENTHROWU1SPR,KEENTHROWU1SPR,step,false,\r
1338         true,8, 0,0, NULL, KeenContact, KeenStandReact, &s_keenthrowup2};\r
1339 statetype s_keenthrowup2        = {KEENTHROWU2SPR,KEENTHROWU2SPR,step,true,\r
1340         true,1, 0,0, KeenThrow, KeenContact, KeenStandReact, &s_keenthrowup3};\r
1341 statetype s_keenthrowup3        = {KEENTHROWU2SPR,KEENTHROWU2SPR,step,false,\r
1342         true,10, 0,0, NULL, KeenContact, KeenStandReact, &s_keenstand};\r
1343 \r
1344 //-------------------\r
1345 \r
1346 statetype s_keenjumpup1 = {KEENJUMPUL1SPR,KEENJUMPUR1SPR,think,false,\r
1347         false,0, 0,0, KeenAirThink, KeenContact, KeenAirReact, &s_keenjumpup2};\r
1348 statetype s_keenjumpup2 = {KEENJUMPUL2SPR,KEENJUMPUR2SPR,think,false,\r
1349         false,0, 0,0, KeenAirThink, KeenContact, KeenAirReact, &s_keenjumpup3};\r
1350 statetype s_keenjumpup3 = {KEENJUMPUL1SPR,KEENJUMPUR1SPR,think,false,\r
1351         false,0, 0,0, KeenAirThink, KeenContact, KeenAirReact, &s_keenstand};\r
1352 \r
1353 statetype s_keenjump1   = {KEENJUMPL1SPR,KEENJUMPR1SPR,think,false,\r
1354         false,0, 0,0, KeenAirThink, KeenContact, KeenAirReact, &s_keenjump2};\r
1355 statetype s_keenjump2   = {KEENJUMPL2SPR,KEENJUMPR2SPR,think,false,\r
1356         false,0, 0,0, KeenAirThink, KeenContact, KeenAirReact, &s_keenjump3};\r
1357 statetype s_keenjump3   = {KEENJUMPL3SPR,KEENJUMPR3SPR,think,false,\r
1358         false,0, 0,0, KeenAirThink, KeenContact, KeenAirReact, &s_keenstand};\r
1359 \r
1360 statetype s_keenairthrow1= {KEENJLTHROWL1SPR,KEENJRTHROWR1SPR,stepthink,false,\r
1361         false,8, 0,0, ProjectileThink, KeenContact, KeenAirReact, &s_keenairthrow2};\r
1362 statetype s_keenairthrow2= {KEENJLTHROWL2SPR,KEENJRTHROWR2SPR,step,true,\r
1363         false,1, 0,0, KeenThrow, KeenContact, KeenAirReact, &s_keenairthrow3};\r
1364 statetype s_keenairthrow3= {KEENJLTHROWL2SPR,KEENJRTHROWR2SPR,stepthink,false,\r
1365         false,10, 0,0, ProjectileThink, KeenContact, KeenAirReact, &s_keenjumpup3};\r
1366 \r
1367 statetype s_keenairthrowup1= {KEENJLTHROWU1SPR,KEENJRTHROWU1SPR,stepthink,false,\r
1368         false,8, 0,0, ProjectileThink, KeenContact, KeenAirReact, &s_keenairthrowup2};\r
1369 statetype s_keenairthrowup2= {KEENJLTHROWU2SPR,KEENJRTHROWU2SPR,step,true,\r
1370         false,1, 0,0, KeenThrow, KeenContact, KeenAirReact, &s_keenairthrowup3};\r
1371 statetype s_keenairthrowup3= {KEENJLTHROWU2SPR,KEENJRTHROWU2SPR,stepthink,false,\r
1372         false,10, 0,0, ProjectileThink, KeenContact, KeenAirReact, &s_keenjumpup3};\r
1373 \r
1374 statetype s_keenairthrowdown1= {KEENJLTHROWD1SPR,KEENJRTHROWD1SPR,stepthink,false,\r
1375         false,8, 0,0, ProjectileThink, KeenContact, KeenAirReact, &s_keenairthrowdown2};\r
1376 statetype s_keenairthrowdown2= {KEENJLTHROWD2SPR,KEENJRTHROWD2SPR,step,true,\r
1377         false,1, 0,0, KeenThrow, KeenContact, KeenAirReact, &s_keenairthrowdown3};\r
1378 statetype s_keenairthrowdown3= {KEENJLTHROWD2SPR,KEENJRTHROWD2SPR,stepthink,false,\r
1379         false,10, 0,0, ProjectileThink, KeenContact, KeenAirReact, &s_keenjumpup3};\r
1380 \r
1381 \r
1382 //===========================================================================\r
1383 \r
1384 #pragma warn +sus\r
1385 \r
1386 \r
1387 /*\r
1388 ===============\r
1389 =\r
1390 = SpawnKeen\r
1391 =\r
1392 ===============\r
1393 */\r
1394 \r
1395 void SpawnKeen (int tilex, int tiley, int dir)\r
1396 {\r
1397         player->obclass = keenobj;\r
1398         player->active = yes;\r
1399         player->needtoclip = true;\r
1400         player->x = tilex<<G_T_SHIFT;\r
1401         player->y = (tiley<<G_T_SHIFT) - BLOCKSIZE*2;\r
1402 \r
1403         player->xdir = dir;\r
1404         player->ydir = 1;\r
1405         NewState (player,&s_keenstand);\r
1406 }\r
1407 \r
1408 //==========================================================================\r
1409 \r
1410 /*\r
1411 ======================\r
1412 =\r
1413 = CheckGrabPole\r
1414 =\r
1415 ======================\r
1416 */\r
1417 \r
1418 boolean CheckGrabPole (objtype *ob)\r
1419 {\r
1420         int     x;\r
1421         unsigned far *map;\r
1422 \r
1423 //\r
1424 // kludgy bit to not let you grab a pole the instant you jump off it\r
1425 //\r
1426         if (TimeCount < leavepoletime)\r
1427                 leavepoletime = 0;\r
1428         else if (TimeCount - leavepoletime < MINPOLEJUMPTICS)\r
1429                 return false;\r
1430 \r
1431         if (c.yaxis == -1)\r
1432                 map = (unsigned _seg *)mapsegs[1]+\r
1433                         mapbwidthtable[(ob->top+6*PIXGLOBAL)/TILEGLOBAL]/2;\r
1434         else\r
1435                 map = (unsigned _seg *)mapsegs[1]+\r
1436                         mapbwidthtable[ob->tilebottom]/2;\r
1437 \r
1438         x = (ob->left + (ob->right - ob->left)/2) >>G_T_SHIFT;\r
1439 \r
1440         map += x;\r
1441 \r
1442         if ((tinf[INTILE+*map]&0x7f) == 1)\r
1443         {\r
1444                 ob->xmove = ((x<<G_T_SHIFT)-8*PIXGLOBAL) - ob->x;\r
1445                 ob->ymove = c.yaxis*32;\r
1446                 ob->temp4 = x;                          // for future reference\r
1447                 ob->needtoclip = false;         // can climb through pole holes\r
1448                 ob->state = &s_keenpole;\r
1449                 return true;\r
1450         }\r
1451 \r
1452         return false;\r
1453 }\r
1454 \r
1455 //==========================================================================\r
1456 \r
1457 \r
1458 /*\r
1459 ============================\r
1460 =\r
1461 = KeenStandThink\r
1462 =\r
1463 ============================\r
1464 */\r
1465 \r
1466 void KeenStandThink (objtype *ob)\r
1467 {\r
1468         if (c.xaxis)\r
1469         {\r
1470         // started walking\r
1471                 ob->xdir = c.xaxis;\r
1472                 ob->state = &s_keenwalk1;\r
1473                 ob->xmove = ob->xdir*s_keenwalk1.xmove*tics;\r
1474                 KeenWalkThink(ob);\r
1475                 return;\r
1476         }\r
1477 \r
1478         if (c.button0 && !button0held)\r
1479         {\r
1480         // jump straight up\r
1481                 SD_PlaySound (JUMPSND);\r
1482                 ob->xspeed = 0;\r
1483                 ob->yspeed = -SPDJUMP;\r
1484                 ob->xmove = 0;\r
1485                 ob->ymove = 0;          // ob->yspeed*tics;                     // DEBUG\r
1486                 jumptime = JUMPTIME;    // -tics;\r
1487                 ob->state = &s_keenjumpup1;\r
1488                 button0held = true;\r
1489                 return;\r
1490         }\r
1491 \r
1492         if (c.button1 && !button1held)\r
1493         {\r
1494         // throw current xdir\r
1495                 if (c.yaxis == -1)\r
1496                         ob->state = &s_keenthrowup1;\r
1497                 else\r
1498                         ob->state = &s_keenthrow1;\r
1499                 button1held = true;\r
1500                 return;\r
1501         }\r
1502 \r
1503         switch (c.yaxis)\r
1504         {\r
1505         case -1:\r
1506                 if (!CheckGrabPole(ob))                 // try to go up/down pole first\r
1507                         ob->state = &s_keenlookup;\r
1508                 return;\r
1509         case 0:\r
1510                 ob->state = &s_keenstand;\r
1511                 return;\r
1512         case 1:\r
1513                 if (!CheckGrabPole(ob))                 // try to go up/down pole first\r
1514                         ob->state = &s_keenduck;\r
1515                 return;\r
1516         }\r
1517 }\r
1518 \r
1519 //===========================================================================\r
1520 \r
1521 /*\r
1522 =======================\r
1523 =\r
1524 = KeenPauseThink\r
1525 =\r
1526 = Do special animations in time\r
1527 =\r
1528 =======================\r
1529 */\r
1530 \r
1531 void KeenPauseThink (objtype *ob)\r
1532 {\r
1533         if (c.dir != dir_None || c.button0 || c.button1)\r
1534         {\r
1535                 ob->temp1 = ob->temp2 = 0;                      // not paused any more\r
1536                 ob->state = &s_keenstand;\r
1537                 KeenStandThink(ob);\r
1538                 return;\r
1539         }\r
1540 \r
1541         if ((ob->hitnorth & ~7) != 24)  // if it is 0 now, keen is standing on a sprite\r
1542                 ob->temp1 += tics;\r
1543 \r
1544         switch (ob->temp2)\r
1545         {\r
1546         case 0:\r
1547                 if (ob->temp1 > 200)\r
1548                 {\r
1549                         ob->temp2++;\r
1550                         ob->state = &s_keenpauselook;\r
1551                         ob->temp1 = 0;\r
1552                 }\r
1553                 break;\r
1554         case 1:\r
1555                 if (ob->temp1 > 300)\r
1556                 {\r
1557                         ob->temp2++;\r
1558                         ob->state = &s_keenwait1;\r
1559                         ob->temp1 = 0;\r
1560                 }\r
1561                 break;\r
1562         case 2:\r
1563                 if (ob->temp1 > 700)\r
1564                 {\r
1565                         ob->temp2++;\r
1566                         ob->state = &s_keenyawn1;\r
1567                         ob->temp1 = 0;\r
1568                 }\r
1569                 break;\r
1570         case 3:\r
1571                 if (ob->temp1 > 400)\r
1572                 {\r
1573                         ob->temp2++;\r
1574                         ob->state = &s_keenpauselook;\r
1575                         ob->temp1 = 0;\r
1576                 }\r
1577                 break;\r
1578         case 4:\r
1579                 if (ob->temp1 > 700)\r
1580                 {\r
1581                         ob->temp2++;\r
1582                         ob->state = &s_keenyawn1;\r
1583                         ob->temp1 = 0;\r
1584                 }\r
1585                 break;\r
1586         case 5:\r
1587                 if (ob->temp1 > 400)\r
1588                 {\r
1589                         ob->temp2++;\r
1590                         ob->state = &s_keengosleep1;\r
1591                 }\r
1592                 break;\r
1593         }\r
1594 }\r
1595 \r
1596 \r
1597 //===========================================================================\r
1598 \r
1599 /*\r
1600 =======================\r
1601 =\r
1602 = KeenGoSleepThink\r
1603 =\r
1604 =======================\r
1605 */\r
1606 \r
1607 void KeenGoSleepThink (objtype *ob)\r
1608 {\r
1609 //\r
1610 // spawn the zees above keens head\r
1611 //\r
1612         GetNewObj (true);\r
1613 \r
1614         new->obclass = inertobj;\r
1615         new->x = player->x;\r
1616         new->y = player->y-4*PIXGLOBAL;\r
1617         new->xdir = 1;\r
1618         new->ydir = -1;\r
1619         NewState (new,&s_keenzee1);\r
1620 \r
1621         ob->temp1 = (int)new;                           // so they can be removed later\r
1622 }\r
1623 \r
1624 \r
1625 //===========================================================================\r
1626 \r
1627 /*\r
1628 =======================\r
1629 =\r
1630 = KeenSleepThink\r
1631 =\r
1632 =======================\r
1633 */\r
1634 \r
1635 void KeenSleepThink (objtype *ob)\r
1636 {\r
1637         if (c.dir != dir_None || c.button0 || c.button1)\r
1638         {\r
1639                 if (ob->temp1 != (unsigned)&dummyobj)\r
1640                         RemoveObj ((objtype *)ob->temp1);       // remove the zees\r
1641                 ob->temp1 = ob->temp2 = 0;                      // not paused any more\r
1642                 ob->state = &s_keengetup;\r
1643         }\r
1644 }\r
1645 \r
1646 \r
1647 //===========================================================================\r
1648 \r
1649 /*\r
1650 =======================\r
1651 =\r
1652 = KeenDieThink\r
1653 =\r
1654 =======================\r
1655 */\r
1656 \r
1657 void KeenDieThink (objtype *ob)\r
1658 {\r
1659         ob++;                   // shut up compiler\r
1660         playstate = died;\r
1661 }\r
1662 \r
1663 \r
1664 //===========================================================================\r
1665 \r
1666 /*\r
1667 =======================\r
1668 =\r
1669 = KeenDuckThink\r
1670 =\r
1671 =======================\r
1672 */\r
1673 \r
1674 void KeenDuckThink (objtype *ob)\r
1675 {\r
1676         unsigned far *map, tile;\r
1677         int midtile,bottomtile,move;\r
1678 \r
1679         if (c.yaxis != 1)\r
1680         {\r
1681                 ob->state = &s_keenstand;\r
1682                 KeenStandThink(ob);\r
1683                 return;\r
1684         }\r
1685 \r
1686         if (c.xaxis)\r
1687                 ob->xdir = c.xaxis;\r
1688 \r
1689         if (c.button0 && !button0held)\r
1690         {\r
1691         //\r
1692         // drop down a level\r
1693         //\r
1694                 button0held = true;\r
1695 \r
1696                 midtile = (ob->tileleft + ob->tileright) >> 1;\r
1697                 bottomtile = ob->tilebottom;\r
1698                 map = (unsigned far *)mapsegs[1] + mapbwidthtable[bottomtile]/2\r
1699                         + midtile;\r
1700                 tile = *map;\r
1701                 if (tinf[WESTWALL+tile] || tinf[EASTWALL+tile]\r
1702                         || tinf[SOUTHWALL+tile])\r
1703                         return;                         // wall prevents drop down\r
1704 \r
1705                 map += mapwidth;\r
1706                 tile = *map;\r
1707                 if (tinf[WESTWALL+tile] || tinf[EASTWALL+tile]\r
1708                         || tinf[SOUTHWALL+tile])\r
1709                         return;                         // wall prevents drop down\r
1710 \r
1711                 move = PIXGLOBAL*(tics<4 ? 4: tics);\r
1712                 ob->bottom += move;\r
1713                 ob->y += move;\r
1714                 ob->xmove = ob->ymove = 0;\r
1715                 ob->state = &s_keenjumpup3;\r
1716                 ob->temp2 = 1;          // allready in last stage\r
1717                 ob->xspeed = ob->yspeed = 0;\r
1718                 SD_PlaySound (PLUMMETSND);\r
1719         }\r
1720 }\r
1721 \r
1722 \r
1723 //===========================================================================\r
1724 \r
1725 /*\r
1726 =======================\r
1727 =\r
1728 = KeenDropDownThink\r
1729 =\r
1730 =======================\r
1731 */\r
1732 \r
1733 void KeenDropDownThink (objtype *ob)\r
1734 {\r
1735         ob->needtoclip = true;\r
1736 }\r
1737 \r
1738 \r
1739 //===========================================================================\r
1740 \r
1741 /*\r
1742 =======================\r
1743 =\r
1744 = KeenWalkThink\r
1745 =\r
1746 =======================\r
1747 */\r
1748 \r
1749 unsigned slopespeed[8] = {0,0,4,4,8,-4,-4,-8};\r
1750 \r
1751 void KeenWalkThink (objtype *ob)\r
1752 {\r
1753         int move;\r
1754 \r
1755         if (!c.xaxis)\r
1756         {\r
1757         //\r
1758         // stopped running\r
1759         //\r
1760                 KeenStandThink (ob);\r
1761                 return;\r
1762         }\r
1763 \r
1764         ob->xdir = c.xaxis;\r
1765 \r
1766         if (c.yaxis && CheckGrabPole(ob))               // try to go up/down pole\r
1767                 return;\r
1768 \r
1769         if (c.button0 && !button0held)\r
1770         {\r
1771         //\r
1772         // running jump\r
1773         //\r
1774                 SD_PlaySound (JUMPSND);\r
1775                 ob->xspeed = ob->xdir * SPDRUNJUMP;\r
1776                 ob->yspeed = -SPDJUMP;\r
1777                 ob->xmove = 0;\r
1778                 ob->ymove = 0;                                  // ob->yspeed*tics;\r
1779                 button0held = true;\r
1780                 jumptime = JUMPTIME; //-tics;           // DEBUG\r
1781                 ob->state = &s_keenjump1;\r
1782         }\r
1783 \r
1784         if (c.button1 && !button1held)\r
1785         {\r
1786         //\r
1787         // throw\r
1788         //\r
1789                 ob->state = &s_keenthrow1;\r
1790                 button1held = true;\r
1791                 return;\r
1792         }\r
1793 \r
1794         //\r
1795         // give speed for slopes\r
1796         //\r
1797         move = tics*slopespeed[ob->hitnorth&7];\r
1798 \r
1799         ob->xmove += move;\r
1800 }\r
1801 \r
1802 //===========================================================================\r
1803 \r
1804 /*\r
1805 =======================\r
1806 =\r
1807 = KeenAirThink\r
1808 =\r
1809 =======================\r
1810 */\r
1811 \r
1812 void    KeenAirThink            (objtype *ob)\r
1813 {\r
1814         if (jumptime)\r
1815         {\r
1816                 if (jumptime<tics)\r
1817                 {\r
1818                         ob->ymove = ob->yspeed*jumptime;\r
1819                         jumptime = 0;\r
1820                 }\r
1821                 else\r
1822                 {\r
1823                         ob->ymove = ob->yspeed*tics;\r
1824                         if (!jumpcheat)\r
1825                                 jumptime-=tics;\r
1826                 }\r
1827                 if (!c.button0)\r
1828                         jumptime = 0;\r
1829 \r
1830                 if (!jumptime)\r
1831                 {\r
1832                         ob->temp2 = 0;\r
1833                         ob->state = ob->state->nextstate;       // switch to second jump stage\r
1834                 }\r
1835         }\r
1836         else\r
1837         {\r
1838                 DoGravity(ob);\r
1839 \r
1840                 if (ob->yspeed>0 && !ob->temp2)\r
1841                 {\r
1842                         ob->state = ob->state->nextstate;       // switch to third jump stage\r
1843                         ob->temp2 = 1;\r
1844                 }\r
1845         }\r
1846 \r
1847 //-------------\r
1848 \r
1849         if (c.xaxis)\r
1850         {\r
1851                 ob->xdir = c.xaxis;\r
1852                 AccelerateX(ob,c.xaxis*2,MAXXSPEED);\r
1853         }\r
1854         else\r
1855                 FrictionX(ob);\r
1856 \r
1857         if (c.button1 && !button1held)\r
1858         {\r
1859                 button1held = true;\r
1860         //\r
1861         // throw\r
1862         //\r
1863                 switch (c.yaxis)\r
1864                 {\r
1865                 case -1:\r
1866                         ob->state = &s_keenairthrowup1;\r
1867                         return;\r
1868                 case 0:\r
1869                         ob->state = &s_keenairthrow1;\r
1870                         return;\r
1871                 case 1:\r
1872                         ob->state = &s_keenairthrowdown1;\r
1873                         return;\r
1874                 }\r
1875         }\r
1876 \r
1877         if (ob->hitsouth==17)           // going through a pole hole\r
1878         {\r
1879                 ob->xspeed = ob->xmove = 0;\r
1880         }\r
1881 \r
1882 \r
1883         if (c.yaxis == -1)\r
1884                 CheckGrabPole (ob);\r
1885 \r
1886 }\r
1887 \r
1888 //===========================================================================\r
1889 \r
1890 /*\r
1891 =======================\r
1892 =\r
1893 = KeenPoleThink\r
1894 =\r
1895 =======================\r
1896 */\r
1897 \r
1898 int     polexspeed[3] = {-SPDPOLESIDEJUMP,0,SPDPOLESIDEJUMP};\r
1899 \r
1900 void    PoleActions (objtype *ob)\r
1901 {\r
1902         if (c.xaxis)\r
1903                 ob->xdir = c.xaxis;\r
1904 \r
1905         if (c.button0 && !button0held)          // jump off the pole\r
1906         {\r
1907                 SD_PlaySound (JUMPSND);\r
1908                 ob->xspeed = polexspeed[c.xaxis+1];\r
1909                 ob->yspeed = -SPDPOLEJUMP;\r
1910                 ob->needtoclip = true;\r
1911                 jumptime = POLEJUMPTIME;\r
1912                 ob->state = &s_keenjump1;\r
1913                 ob->ydir = 1;\r
1914                 button0held = true;\r
1915                 leavepoletime = TimeCount;\r
1916                 return;\r
1917         }\r
1918 \r
1919         if (c.button1 && !button1held)\r
1920         {\r
1921                 button1held = true;\r
1922 \r
1923                 switch (c.yaxis)\r
1924                 {\r
1925                 case -1:\r
1926                         ob->state = &s_keenpolethrowup1;\r
1927                         break;\r
1928                 case 0:\r
1929                         ob->state = &s_keenpolethrow1;\r
1930                         break;\r
1931                 case 1:\r
1932                         ob->state = &s_keenpolethrowdown1;\r
1933                         break;\r
1934                 }\r
1935         }\r
1936 }\r
1937 \r
1938 \r
1939 void    KeenPoleThink           (objtype *ob)\r
1940 {\r
1941         unsigned far *map, tile;\r
1942 \r
1943         switch (c.yaxis)\r
1944         {\r
1945         case -1:\r
1946                 ob->state = &s_keenclimb1;\r
1947                 ob->ydir = -1;\r
1948                 return;\r
1949 \r
1950         case 1:\r
1951                 ob->state = &s_keenslide1;\r
1952                 ob->ydir = 1;\r
1953                 KeenDropThink (ob);\r
1954                 return;\r
1955         }\r
1956 \r
1957         if (c.xaxis)\r
1958         {\r
1959         //\r
1960         // walk off pole if right next to ground\r
1961         //\r
1962                 map = mapsegs[1] + (mapbwidthtable[ob->tilebottom+1]/2 + ob->tilemidx);\r
1963                 tile = *map;\r
1964                 if (tinf[NORTHWALL+tile])\r
1965                 {\r
1966                         ob->xspeed = 0;\r
1967                         ob->yspeed = 0;\r
1968                         ob->needtoclip = true;\r
1969                         jumptime = 0;\r
1970                         ob->state = &s_keenjump3;\r
1971                         ob->ydir = 1;\r
1972                         SD_PlaySound (PLUMMETSND);\r
1973                         return;\r
1974                 }\r
1975         }\r
1976 \r
1977         PoleActions (ob);\r
1978 }\r
1979 \r
1980 \r
1981 /*\r
1982 =======================\r
1983 =\r
1984 = KeenClimbThink\r
1985 =\r
1986 =======================\r
1987 */\r
1988 \r
1989 void    KeenClimbThink          (objtype *ob)\r
1990 {\r
1991         unsigned far *map;\r
1992 \r
1993         map = (unsigned _seg *)mapsegs[1]+mapbwidthtable[ob->tiletop]/2+ob->temp4;\r
1994 \r
1995         if ((tinf[INTILE+*map]&0x7f) != 1)\r
1996         {\r
1997                 ob->ymove=0;\r
1998                 ob->state = &s_keenpole;                // ran out of pole\r
1999                 return;\r
2000         }\r
2001 \r
2002         switch (c.yaxis)\r
2003         {\r
2004         case 0:\r
2005                 ob->state = &s_keenpole;\r
2006                 ob->ydir = 0;\r
2007                 break;\r
2008 \r
2009         case 1:\r
2010                 ob->state = &s_keenslide1;\r
2011                 ob->ydir = 1;\r
2012                 KeenDropThink (ob);\r
2013                 break;\r
2014         }\r
2015 \r
2016         PoleActions (ob);\r
2017 }\r
2018 \r
2019 \r
2020 /*\r
2021 =======================\r
2022 =\r
2023 = KeenDropThink\r
2024 =\r
2025 =======================\r
2026 */\r
2027 \r
2028 void    KeenDropThink           (objtype *ob)\r
2029 {\r
2030         unsigned far *map;\r
2031 \r
2032         map = (unsigned _seg *)mapsegs[1]+mapbwidthtable[ob->tilebottom]/2+ob->temp4;\r
2033 \r
2034         if ((tinf[INTILE+*map]&0x7f) != 1)\r
2035         {\r
2036                 SD_PlaySound (PLUMMETSND);\r
2037                 ob->state = &s_keenjump3;               // ran out of pole\r
2038                 jumptime = 0;\r
2039                 ob->temp2 = 1;\r
2040                 ob->xspeed = polexspeed[c.xaxis+1];\r
2041                 ob->yspeed = 0;\r
2042                 ob->needtoclip = true;\r
2043                 ob->tilebottom--;\r
2044                 return;\r
2045         }\r
2046 \r
2047         switch (c.yaxis)\r
2048         {\r
2049         case -1:\r
2050                 ob->state = &s_keenclimb1;\r
2051                 ob->ydir = -1;\r
2052                 break;\r
2053 \r
2054         case 0:\r
2055                 ob->state = &s_keenpole;\r
2056                 ob->ydir = 0;\r
2057                 break;\r
2058         }\r
2059 \r
2060         PoleActions (ob);\r
2061 }\r
2062 \r
2063 //===========================================================================\r
2064 \r
2065 /*\r
2066 =======================\r
2067 =\r
2068 = KeenThrow\r
2069 =\r
2070 =======================\r
2071 */\r
2072 \r
2073 void    KeenThrow       (objtype *ob)\r
2074 {\r
2075 // can't use &<var> in a switch statement...\r
2076 \r
2077         if (ob->state == &s_keenthrow3)\r
2078         {\r
2079                 if (ob->xdir > 0)\r
2080                         ThrowPower (ob->midx-4*PIXGLOBAL,ob->y+8*PIXGLOBAL,dir_East);\r
2081                 else\r
2082                         ThrowPower (ob->midx-4*PIXGLOBAL,ob->y+8*PIXGLOBAL,dir_West);\r
2083                 return;\r
2084         }\r
2085 \r
2086         if (ob->state == &s_keenpolethrow2)\r
2087         {\r
2088                 if (ob->xdir > 0)\r
2089                         ThrowPower (ob->x+24*PIXGLOBAL,ob->y,dir_East);\r
2090                 else\r
2091                         ThrowPower (ob->x-8*PIXGLOBAL,ob->y,dir_West);\r
2092                 return;\r
2093         }\r
2094 \r
2095         if (ob->state == &s_keenthrowup2)\r
2096         {\r
2097                 ThrowPower (ob->x+4*PIXGLOBAL,ob->y-8*PIXGLOBAL,dir_North);\r
2098                 return;\r
2099         }\r
2100 \r
2101         if (ob->state == &s_keenpolethrowup2)\r
2102         {\r
2103                 ThrowPower (ob->x+8*PIXGLOBAL,ob->y-8*PIXGLOBAL,dir_North);\r
2104                 return;\r
2105         }\r
2106 \r
2107         if (ob->state == &s_keenpolethrowdown2)\r
2108         {\r
2109                 ThrowPower (ob->x+8*PIXGLOBAL,ob->y+8*PIXGLOBAL,dir_South);\r
2110                 return;\r
2111         }\r
2112 \r
2113         if (ob->state == &s_keenairthrow2)\r
2114         {\r
2115                 if (ob->xdir > 0)\r
2116                         ThrowPower (ob->midx-4*PIXGLOBAL,ob->y+8*PIXGLOBAL,dir_East);\r
2117                 else\r
2118                         ThrowPower (ob->midx-4*PIXGLOBAL,ob->y+8*PIXGLOBAL,dir_West);\r
2119 #if 0\r
2120                 if (ob->xdir > 0)\r
2121                         ThrowPower (ob->x+32*PIXGLOBAL,ob->y+8*PIXGLOBAL,dir_East);\r
2122                 else\r
2123                         ThrowPower (ob->x-16*PIXGLOBAL,ob->y+8*PIXGLOBAL,dir_West);\r
2124 #endif\r
2125 \r
2126                 new->xspeed += ob->xspeed/2;\r
2127                 new->yspeed += ob->yspeed/2;\r
2128                 return;\r
2129         }\r
2130 \r
2131         if (ob->state == &s_keenairthrowup2)\r
2132         {\r
2133                 if (ob->xdir > 0)\r
2134                         ThrowPower (ob->x+16*PIXGLOBAL,ob->y,dir_North);\r
2135                 else\r
2136                         ThrowPower (ob->x+4*PIXGLOBAL,ob->y,dir_North);\r
2137                 new->xspeed += ob->xspeed/2;\r
2138                 new->yspeed += ob->yspeed/2;\r
2139                 return;\r
2140         }\r
2141 \r
2142         if (ob->state == &s_keenairthrowdown2)\r
2143         {\r
2144                 if (ob->xdir > 0)\r
2145                         ThrowPower (ob->x+3*PIXGLOBAL,ob->y+16*PIXGLOBAL,dir_South);\r
2146                 else\r
2147                         ThrowPower (ob->x+12*PIXGLOBAL,ob->y+16*PIXGLOBAL,dir_South);\r
2148                 new->xspeed += ob->xspeed/2;\r
2149                 new->yspeed += ob->yspeed/2;\r
2150                 return;\r
2151         }\r
2152 \r
2153         Quit ("KeenThrow: Bad state!");\r
2154 }\r
2155 \r
2156 \r
2157 /*\r
2158 =============================================================================\r
2159 \r
2160                                                 CONTACT ROUTINES\r
2161 \r
2162 =============================================================================\r
2163 */\r
2164 \r
2165 /*\r
2166 ============================\r
2167 =\r
2168 = KillKeen\r
2169 =\r
2170 ============================\r
2171 */\r
2172 \r
2173 void KillKeen (void)\r
2174 {\r
2175         if (!godmode)\r
2176         {\r
2177                 SD_PlaySound (WAKEUPSND);\r
2178                 player->needtoclip = false;\r
2179                 ChangeState (player,&s_keendie1);\r
2180         }\r
2181 }\r
2182 \r
2183 \r
2184 \r
2185 /*\r
2186 ============================\r
2187 =\r
2188 = KeenContact\r
2189 =\r
2190 ============================\r
2191 */\r
2192 \r
2193 unsigned bonuspoints[6] = {100,200,500,1000,2000,5000};\r
2194 \r
2195 void    KeenContact (objtype *ob, objtype *hit)\r
2196 {\r
2197         switch (hit->obclass)\r
2198         {\r
2199         case    bonusobj:\r
2200                 hit->obclass = inertobj;\r
2201                 switch (hit->temp1)\r
2202                 {\r
2203                 case 0:\r
2204                 case 1:\r
2205                 case 2:\r
2206                 case 3:\r
2207                 case 4:\r
2208                 case 5:\r
2209                         SD_PlaySound (GETPOINTSSND);\r
2210                         hit->shapenum = BONUS100SPR+hit->temp1;\r
2211                         GivePoints (bonuspoints[hit->temp1]);\r
2212                         ChangeState (hit,&s_bonusrise);\r
2213                         break;\r
2214                 case 6:\r
2215                         SD_PlaySound (EXTRAKEENSND);\r
2216                         hit->shapenum = BONUS1UPSPR;\r
2217                         gamestate.lives++;\r
2218                         ChangeState (hit,&s_bonusrise);\r
2219                         break;\r
2220                 case 7:\r
2221                         SD_PlaySound (EXTRAKEENSND);\r
2222                         hit->shapenum = BONUSSUPERSPR;\r
2223                         gamestate.lives+=3;\r
2224                         gamestate.flowerpowers+=8;\r
2225                         GivePoints (10000);\r
2226                         ChangeState (hit,&s_bonusrise);\r
2227                         break;\r
2228                 case 8:\r
2229                         SD_PlaySound (GETPOWERSND);\r
2230                         hit->shapenum = BONUSFLOWERSPR;\r
2231                         gamestate.flowerpowers++;\r
2232                         ChangeState (hit,&s_bonusrise);\r
2233                         break;\r
2234                 case 9:\r
2235                         SD_PlaySound (GETPOWERSND);\r
2236                         hit->shapenum = BONUSFLOWERUPSPR;\r
2237                         gamestate.flowerpowers+=5;\r
2238                         ChangeState (hit,&s_bonusrise);\r
2239                         break;\r
2240                 case 10:\r
2241                         SD_PlaySound (GETBOMBSND);\r
2242                         hit->shapenum = BONUSBOMBSPR;\r
2243                         gamestate.boobusbombs++;\r
2244                         gamestate.bombsthislevel++;\r
2245                         ChangeState (hit,&s_bonusrise);\r
2246                         break;\r
2247                 case 11:\r
2248                         SD_PlaySound (GETKEYSND);\r
2249                         hit->shapenum = BONUSKEYSPR;\r
2250                         gamestate.keys++;\r
2251                         ChangeState (hit,&s_bonusrise);\r
2252                         break;\r
2253                 }\r
2254                 break;\r
2255 \r
2256         case    doorobj:\r
2257                 if (gamestate.keys)\r
2258                 {\r
2259                         if (hit->state != &s_doorraise)\r
2260                         {\r
2261                                 SD_PlaySound (OPENDOORSND);\r
2262                                 gamestate.keys--;\r
2263                                 ChangeState (hit,&s_doorraise);\r
2264                         }\r
2265                 }\r
2266                 else\r
2267                 {\r
2268                         SD_PlaySound (NOWAYSND);\r
2269                         ClipToSpriteSide (ob,hit);\r
2270                 }\r
2271                 break;\r
2272         case    taterobj:\r
2273                 if (hit->state == &s_taterattack2)\r
2274                         KillKeen ();\r
2275                 break;\r
2276         case    carrotobj:\r
2277                 ClipToSpriteSide (ob,hit);\r
2278                 if (!ob->needtoclip)            // got pushed off a pole\r
2279                 {\r
2280                         SD_PlaySound (PLUMMETSND);\r
2281                         ob->needtoclip = true;\r
2282                         ob->xspeed = ob->yspeed = 0;\r
2283                         ChangeState(ob,&s_keenjump3);\r
2284                         ob->temp2 = 1;\r
2285                         jumptime = 0;\r
2286                 }\r
2287                 break;\r
2288         case    cartobj:\r
2289                 ClipToSprite (ob,hit,true);\r
2290                 break;\r
2291         case    broccoobj:\r
2292                 if (hit->state == &s_broccosmash3 || hit->state == &s_broccosmash4)\r
2293                         KillKeen ();\r
2294                 break;\r
2295         case    squashobj:\r
2296                 if (hit->state == &s_squasherjump2)\r
2297                         KillKeen ();\r
2298                 else\r
2299                 {\r
2300                         ClipToSpriteSide (ob,hit);\r
2301                         if (!ob->needtoclip)            // got pushed off a pole\r
2302                         {\r
2303                                 SD_PlaySound (PLUMMETSND);\r
2304                                 ob->needtoclip = true;\r
2305                                 ob->xspeed = ob->yspeed = 0;\r
2306                                 ChangeState(ob,&s_keenjump3);\r
2307                                 ob->temp2 = 1;\r
2308                                 jumptime = 0;\r
2309                         }\r
2310                 }\r
2311                 break;\r
2312         case    grapeobj:\r
2313                 if (hit->state == &s_grapefall)\r
2314                         KillKeen ();\r
2315                 break;\r
2316         case    tomatobj:\r
2317         case    celeryobj:\r
2318         case    asparobj:\r
2319         case    turnipobj:\r
2320         case    cauliobj:\r
2321         case    brusselobj:\r
2322         case    mushroomobj:\r
2323         case    apelobj:\r
2324         case    peabrainobj:\r
2325         case    boobusobj:\r
2326         case    shotobj:\r
2327                         KillKeen ();\r
2328                 break;\r
2329 \r
2330         }\r
2331 }\r
2332 \r
2333 \r
2334 /*\r
2335 =============================================================================\r
2336 \r
2337                                                  REACTION ROUTINES\r
2338 \r
2339 =============================================================================\r
2340 */\r
2341 \r
2342 \r
2343 /*\r
2344 ============================\r
2345 =\r
2346 = KeenSimpleReact\r
2347 =\r
2348 ============================\r
2349 */\r
2350 \r
2351 void    KeenSimpleReact (objtype *ob)\r
2352 {\r
2353         PLACESPRITE;\r
2354 }\r
2355 \r
2356 \r
2357 /*\r
2358 ============================\r
2359 =\r
2360 = KeenStandReact\r
2361 =\r
2362 ============================\r
2363 */\r
2364 \r
2365 void    KeenStandReact (objtype *ob)\r
2366 {\r
2367         if (!ob->hitnorth)\r
2368         {\r
2369         //\r
2370         // walked off an edge\r
2371         //\r
2372                 SD_PlaySound (PLUMMETSND);\r
2373                 ob->xspeed = ob->xdir*WALKAIRSPEED;\r
2374                 ChangeState (ob,&s_keenjump3);\r
2375                 ob->temp2 = 1;\r
2376                 jumptime = 0;\r
2377         }\r
2378         else if ( (ob->hitnorth & ~7) == 8)     // deadly floor!\r
2379         {\r
2380                 KillKeen ();\r
2381         }\r
2382 \r
2383         PLACESPRITE;\r
2384 }\r
2385 \r
2386 /*\r
2387 ============================\r
2388 =\r
2389 = KeenWalkReact\r
2390 =\r
2391 ============================\r
2392 */\r
2393 \r
2394 void    KeenWalkReact (objtype *ob)\r
2395 {\r
2396         if (!ob->hitnorth)\r
2397         {\r
2398         //\r
2399         // walked off an edge\r
2400         //\r
2401                 ob->xspeed = ob->xdir*WALKAIRSPEED;\r
2402                 ob->yspeed = 0;\r
2403                 ChangeState (ob,&s_keenjump3);\r
2404                 ob->temp2 = 1;\r
2405                 jumptime = 0;\r
2406         }\r
2407         else if ( (ob->hitnorth & ~7) == 8)     // deadly floor!\r
2408         {\r
2409                 KillKeen ();\r
2410                 goto placeit;\r
2411         }\r
2412 \r
2413         if (ob->hiteast == 2)                   // doors\r
2414         {\r
2415 \r
2416         }\r
2417         else if (ob->hitwest == 2)              // doors\r
2418         {\r
2419 \r
2420         }\r
2421         else if (ob->hiteast || ob->hitwest)\r
2422         {\r
2423         //\r
2424         // ran into a wall\r
2425         //\r
2426                 ob->ticcount = 0;\r
2427                 ob->state = &s_keenstand;\r
2428                 ob->shapenum = ob->xdir == 1 ? s_keenstand.rightshapenum :\r
2429                         s_keenstand.leftshapenum;\r
2430         }\r
2431 placeit:\r
2432 \r
2433         PLACESPRITE;\r
2434 }\r
2435 \r
2436 \r
2437 /*\r
2438 ============================\r
2439 =\r
2440 = KeenAirReact\r
2441 =\r
2442 ============================\r
2443 */\r
2444 \r
2445 void    KeenAirReact (objtype *ob)\r
2446 {\r
2447         int x,y;\r
2448         unsigned far *map,mapextra;\r
2449 \r
2450         if (ob->hiteast || ob->hitwest)\r
2451                 ob->xspeed = 0;\r
2452 \r
2453         map = mapsegs[1] + (mapbwidthtable[ob->tiletop]/2) + ob->tileleft;\r
2454         mapextra = mapwidth - (ob->tileright - ob->tileleft+1);\r
2455         for (y=ob->tiletop;y<=ob->tilebottom;y++,map+=mapextra)\r
2456                 for (x=ob->tileleft;x<=ob->tileright;x++,map++)\r
2457                         if (tinf[SOUTHWALL+*map] == 17) // jumping up through a pole hole\r
2458                         {\r
2459                                 ob->xspeed = 0;\r
2460                                 ob->x = ob->tilemidx*TILEGLOBAL - 2*PIXGLOBAL;\r
2461                                 goto checknorth;\r
2462                         }\r
2463 \r
2464         if (ob->hitsouth)\r
2465         {\r
2466                 if (ob->hitsouth == 17) // jumping up through a pole hole\r
2467                 {\r
2468                         ob->y -= 32;\r
2469                         ob->top -= 32;\r
2470                         ob->xspeed = 0;\r
2471                         ob->x = ob->tilemidx*TILEGLOBAL - 2*PIXGLOBAL;\r
2472                 }\r
2473                 else\r
2474                 {\r
2475                         SD_PlaySound (HITHEADSND);\r
2476 \r
2477                         if (ob->hitsouth > 1)\r
2478                         {\r
2479                                 ob->yspeed += 16;\r
2480                                 if (ob->yspeed<0)       // push away from slopes\r
2481                                         ob->yspeed = 0;\r
2482                         }\r
2483                         else\r
2484                                 ob->yspeed = 0;\r
2485                         jumptime = 0;\r
2486                 }\r
2487         }\r
2488 \r
2489 checknorth:\r
2490         if (ob->hitnorth)\r
2491         {\r
2492                 if (!(ob->hitnorth == 25 && jumptime))  // KLUDGE to allow jumping off\r
2493                 {                                                                               // sprites\r
2494                         ob->temp1 = ob->temp2 = 0;\r
2495                         ChangeState (ob,&s_keenstand);\r
2496                         SD_PlaySound (LANDSND);\r
2497                 }\r
2498         }\r
2499 \r
2500         PLACESPRITE;\r
2501 }\r
2502 \r
2503 /*\r
2504 ============================\r
2505 =\r
2506 = KeenSlideReact\r
2507 =\r
2508 ============================\r
2509 */\r
2510 \r
2511 void    KeenSlideReact (objtype *ob)\r
2512 {\r
2513         unsigned far *map;\r
2514 \r
2515         if (ob->hitnorth)                       // friction slow down\r
2516         {\r
2517                 map = mapsegs[2] + (mapbwidthtable[ob->tiletop]/2 + ob->tileleft);\r
2518                 if (!tinf[SOUTHWALL+*map] && !tinf[SOUTHWALL+*(map+1)])\r
2519                         FrictionX(ob);\r
2520         }\r
2521 \r
2522 \r
2523         if (ob->hitwest || ob->hiteast || !ob->xspeed)\r
2524                 ChangeState (ob,&s_keengetup);\r
2525 \r
2526         PLACESPRITE;\r
2527 }\r
2528 \r