]> 4ch.mooo.com Git - 16.git/blob - 16/keen456/KEEN4-6/KEEN4/K4_ACT3.C
extrcted keen code remake
[16.git] / 16 / keen456 / KEEN4-6 / KEEN4 / K4_ACT3.C
1 /* Reconstructed Commander Keen 4-6 Source Code\r
2  * Copyright (C) 2021 K1n9_Duk3\r
3  *\r
4  * This file is loosely based on:\r
5  * Keen Dreams Source Code\r
6  * Copyright (C) 2014 Javier M. Chavez\r
7  *\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
12  *\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
17  *\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
21  */\r
22 \r
23 /*\r
24 K4_ACT3.C\r
25 =========\r
26 \r
27 Contains the following actor types (in this order):\r
28 \r
29 - Treasure Eater\r
30 - Mimrock\r
31 - Dopefish\r
32 - Schoolfish\r
33 - Sprite\r
34 - Mine\r
35 - Lindsey\r
36 - Dart Shooter & Dart\r
37 - Wetsuit\r
38 \r
39 */\r
40 \r
41 #include "CK_DEF.H"\r
42 \r
43 /*\r
44 =============================================================================\r
45 \r
46                                                   TREASURE EATER\r
47 \r
48 temp1 = turn counter\r
49 \r
50 =============================================================================\r
51 */\r
52 \r
53 statetype s_eaterstand1 = {EATERSTAND1SPR, EATERSTAND1SPR, step, false, false, 20, 0, 0, NULL, C_Eater, R_Draw, &s_eaterstand2};\r
54 statetype s_eaterstand2 = {EATERSTAND2SPR, EATERSTAND2SPR, step, false, false, 20, 0, 0, T_EaterJump, C_Eater, R_Draw, NULL};\r
55 statetype s_eatertport1 = {SMOKE1SPR, SMOKE1SPR, step, false, false, 20, 0, 0, NULL, C_Eater, R_Draw, &s_eatertport2};\r
56 statetype s_eatertport2 = {SMOKE2SPR, SMOKE2SPR, step, false, false, 20, 0, 0, NULL, C_Eater, R_Draw, &s_eatertport3};\r
57 statetype s_eatertport3 = {SMOKE3SPR, SMOKE3SPR, step, false, false, 20, 0, 0, NULL, C_Eater, R_Draw, &s_eatertport4};\r
58 statetype s_eatertport4 = {SMOKE4SPR, SMOKE4SPR, step, false, false, 20, 0, 0, T_EaterTeleport, C_Eater, R_Draw, &s_eatertport5};\r
59 statetype s_eatertport5 = {SMOKE4SPR, SMOKE4SPR, step, false, false, 20, 0, 0, NULL, C_Eater, R_Draw, &s_eatertport6};\r
60 statetype s_eatertport6 = {SMOKE3SPR, SMOKE3SPR, step, false, false, 20, 0, 0, NULL, C_Eater, R_Draw, &s_eatertport7};\r
61 statetype s_eatertport7 = {SMOKE2SPR, SMOKE2SPR, step, false, false, 20, 0, 0, NULL, C_Eater, R_Draw, &s_eatertport8};\r
62 statetype s_eatertport8 = {SMOKE1SPR, SMOKE1SPR, step, false, false, 20, 0, 0, NULL, C_Eater, R_Draw, &s_eaterjump1};\r
63 statetype s_eaterjump1  = {EATERJUMPL1SPR, EATERJUMPR1SPR, stepthink, false, false, 6, 0, 0, T_WeakProjectile, C_Eater, R_EaterAir, &s_eaterjump2};\r
64 statetype s_eaterjump2  = {EATERJUMPL2SPR, EATERJUMPR2SPR, stepthink, false, false, 6, 0, 0, T_WeakProjectile, C_Eater, R_EaterAir, &s_eaterjump3};\r
65 statetype s_eaterjump3  = {EATERJUMPL3SPR, EATERJUMPR3SPR, stepthink, false, false, 6, 0, 0, T_WeakProjectile, C_Eater, R_EaterAir, &s_eaterjump4};\r
66 statetype s_eaterjump4  = {EATERJUMPL2SPR, EATERJUMPR2SPR, stepthink, false, false, 6, 0, 0, T_WeakProjectile, C_Eater, R_EaterAir, &s_eaterjump1};\r
67 statetype s_eaterstun   = {EATERJUMPL1SPR, EATERJUMPL1SPR, think, false, false, 0, 0, 0, T_Projectile, 0, R_Stunned, &s_eaterstun2};\r
68 statetype s_eaterstun2  = {EATERSTUNSPR, EATERSTUNSPR, think, false, false, 0, 0, 0, T_Projectile, 0, R_Stunned, NULL};\r
69 \r
70 statetype s_eatenbonus1 = {EATENBONUS1SPR, EATENBONUS1SPR, slide, false, false, 10, 0, 8, NULL, NULL, R_Draw, &s_eatenbonus2};\r
71 statetype s_eatenbonus2 = {EATENBONUS2SPR, EATENBONUS2SPR, slide, false, false, 10, 0, 8, NULL, NULL, R_Draw, &s_eatenbonus3};\r
72 statetype s_eatenbonus3 = {EATENBONUS3SPR, EATENBONUS3SPR, slide, false, false, 10, 0, 8, NULL, NULL, R_Draw, &s_eatenbonus4};\r
73 statetype s_eatenbonus4 = {EATENBONUS4SPR, EATENBONUS4SPR, slide, false, false, 10, 0, 8, NULL, NULL, R_Draw, NULL};\r
74 \r
75 /*\r
76 ===========================\r
77 =\r
78 = SpawnEater\r
79 =\r
80 ===========================\r
81 */\r
82 \r
83 void SpawnEater(Sint16 x, Sint16 y)\r
84 {\r
85         GetNewObj(false);\r
86         new->obclass = treasureeaterobj;\r
87         new->active = ac_yes;\r
88         new->priority = 3;\r
89         new->x = CONVERT_TILE_TO_GLOBAL(x);\r
90         new->y = CONVERT_TILE_TO_GLOBAL(y) - 24*PIXGLOBAL;\r
91         if (US_RndT() < 0x80)\r
92         {\r
93                 new->xdir = 1;\r
94         }\r
95         else\r
96         {\r
97                 new->xdir = -1;\r
98         }\r
99         new->ydir = 1;\r
100         NewState(new, &s_eaterstand1);\r
101 }\r
102 \r
103 /*\r
104 ===========================\r
105 =\r
106 = T_EaterJump\r
107 =\r
108 ===========================\r
109 */\r
110 \r
111 void T_EaterJump(objtype *ob)\r
112 {\r
113         objtype *ob2;\r
114         Uint16 x;\r
115         Sint16 y;\r
116         Uint16 far *map;\r
117         Uint16 intile, rowdiff, width;\r
118 \r
119         ob->state = &s_eaterjump1;\r
120 \r
121         //jump straight up if below bonus object:\r
122         for (ob2 = player->next; ob2; ob2 = ob2->next)\r
123         {\r
124                 if (ob2->obclass == bonusobj && ob2->active == ac_yes\r
125                         && ob2->right > ob->left && ob2->left < ob->right\r
126                         && ob2->bottom < ob->top && ob2->bottom + 3*TILEGLOBAL > ob->top)\r
127                 {\r
128                         ob->xspeed = 0;\r
129                         ob->yspeed = -48;\r
130                         return;\r
131                 }\r
132         }\r
133 \r
134         //jump straight up if below bonus tile:\r
135         map = mapsegs[1] + mapbwidthtable[ob->tiletop-3]/2 + ob->tileleft;\r
136         width = ob->tileright-ob->tileleft+1;\r
137         rowdiff = mapwidth-width;\r
138         for (y=0; y<3; y++, map+=rowdiff)\r
139         {\r
140                 for (x=0; x<width; x++, map++)\r
141                 {\r
142                         intile = tinf[INTILE+*map];\r
143                         if (intile == INTILE_DROP || intile >= INTILE_BONUS100 && intile <= INTILE_AMMO)\r
144                         {\r
145                                 ob->xspeed = 0;\r
146                                 ob->yspeed = -48;\r
147                                 return;\r
148                         }\r
149                 }\r
150         }\r
151 \r
152         //vanish after having checked both directions:\r
153         if (ob->temp1 >= 2)\r
154         {\r
155                 // BUG? this doesn't play a sound\r
156                 ob->state = &s_eatertport1;\r
157                 return;\r
158         }\r
159 \r
160         //jump in current direction if there is a floor in that direction:\r
161         map = mapsegs[1] + mapbwidthtable[ob->tilebottom-2]/2 + ob->tilemidx;\r
162         map += ob->xdir * 4;\r
163         for (y=0; y<4; y++, map+=mapwidth)\r
164         {\r
165                 if (tinf[NORTHWALL+*map])\r
166                 {\r
167                         ob->xspeed = ob->xdir * 20;\r
168                         ob->yspeed = -24;\r
169                         return;\r
170                 }\r
171         }\r
172 \r
173         //couldn't jump in current direction, so turn around:\r
174         if (++ob->temp1 == 2)\r
175         {\r
176                 SD_PlaySound(SND_TREASUREEATERVANISH);\r
177                 ob->state = &s_eatertport1;\r
178                 return;\r
179         }\r
180 \r
181         //jump in opposite direction:\r
182         ob->xdir = -ob->xdir;\r
183         ob->xspeed = ob->xdir * 20;\r
184         ob->yspeed = -24;\r
185 }\r
186 \r
187 /*\r
188 ===========================\r
189 =\r
190 = T_EaterTeleport\r
191 =\r
192 ===========================\r
193 */\r
194 \r
195 void T_EaterTeleport(objtype *ob)\r
196 {\r
197         objtype *ob2;\r
198 \r
199         ob->temp1 = 0;\r
200         for (ob2=player->next; ob2; ob2=ob2->next)\r
201         {\r
202                 if (ob2->obclass == bonusobj)\r
203                 {\r
204                         ob->x = ob2->x - 8*PIXGLOBAL;\r
205                         ob->y = ob2->y;\r
206                         NewState(ob, &s_eatertport5);\r
207                         return;\r
208                 }\r
209         }\r
210         RemoveObj(ob);\r
211 }\r
212 \r
213 /*\r
214 ===========================\r
215 =\r
216 = C_Eater\r
217 =\r
218 ===========================\r
219 */\r
220 \r
221 void C_Eater(objtype *ob, objtype *hit)\r
222 {\r
223         if (hit->obclass == bonusobj)\r
224         {\r
225                 //BUG? bonus object might be a key, and eating a key makes a level unwinnable\r
226                 hit->obclass = inertobj;\r
227                 hit->priority = 3;\r
228                 ChangeState(hit, &s_eatenbonus1);\r
229                 SD_PlaySound(SND_EATBONUS);\r
230         }\r
231         else if (hit->obclass == stunshotobj)\r
232         {\r
233                 //basically StunObj(), but in different order:\r
234                 ob->temp1 = 0;\r
235                 ob->temp2 = 0;\r
236                 ob->temp3 = 0;\r
237                 ob->temp4 = ob->obclass;\r
238                 ob->obclass = stunnedobj;\r
239                 ExplodeShot(hit);\r
240                 ChangeState(ob, &s_eaterstun);\r
241 \r
242                 ob->yspeed -= 16;\r
243         }\r
244 }\r
245 \r
246 /*\r
247 ===========================\r
248 =\r
249 = EaterInTile\r
250 =\r
251 ===========================\r
252 */\r
253 \r
254 void EaterInTile(objtype *ob)\r
255 {\r
256         Uint16 x, y;\r
257         Uint16 far *map;\r
258         Uint16 rowdiff, intile;\r
259 \r
260         map = mapsegs[1] + mapbwidthtable[ob->tiletop]/2 + ob->tileleft;\r
261         rowdiff = mapwidth-(ob->tileright-ob->tileleft+1);\r
262         for (y=ob->tiletop; y<=ob->tilebottom; y++, map+=rowdiff)\r
263         {\r
264                 for (x=ob->tileleft; x<=ob->tileright; x++, map++)\r
265                 {\r
266                         intile = tinf[INTILE + *map] & INTILE_TYPEMASK;\r
267                         if (intile == INTILE_DROP || intile >= INTILE_BONUS100 && intile <= INTILE_AMMO)\r
268                         {\r
269                                 RF_MemToMap(&zeromap, 1, x, y, 1, 1);\r
270                                 GetNewObj(true);\r
271                                 new->obclass = inertobj;\r
272                                 new->priority = 3;\r
273                                 new->needtoclip = cl_noclip;\r
274                                 new->x = CONVERT_TILE_TO_GLOBAL(x);\r
275                                 new->y = CONVERT_TILE_TO_GLOBAL(y);\r
276                                 new->active = ac_removable;\r
277                                 ChangeState(new, &s_eatenbonus1);       //using ChangeState and not NewState is fine for noclipping objects\r
278                                 //BUG? this doesn't play a sound\r
279                                 break;\r
280                         }\r
281                 }\r
282         }\r
283 }\r
284 \r
285 /*\r
286 ===========================\r
287 =\r
288 = R_EaterAir\r
289 =\r
290 ===========================\r
291 */\r
292 \r
293 void R_EaterAir(objtype *ob)\r
294 {\r
295         EaterInTile(ob);\r
296 \r
297         if (ob->hitnorth)\r
298                 ChangeState(ob, &s_eaterstand1);\r
299 \r
300         if (ob->hiteast || ob->hitwest)\r
301         {\r
302                 ob->temp1++;\r
303                 ob->xdir = -ob->xdir;\r
304                 ob->xspeed = 0;\r
305         }\r
306 \r
307         if (ob->hitnorth)       //BUG? maybe this was supposed to check hitsouth as well?\r
308                 ob->yspeed = 0;\r
309 \r
310         RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
311 }\r
312 \r
313 /*\r
314 =============================================================================\r
315 \r
316                                                   MIMROCK\r
317 \r
318 =============================================================================\r
319 */\r
320 \r
321 statetype s_mimrock   = {MIMROCKSPR, MIMROCKSPR, step, false, true, 20, 0, 0, T_MimrockWait, NULL, R_Walk, &s_mimrock};\r
322 statetype s_mimsneak1 = {MIMROCKWALKR1SPR, MIMROCKWALKL1SPR, step, false, true, 6, 64, 0, T_MimrockSneak, C_Mimrock, R_Walk, &s_mimsneak2};\r
323 statetype s_mimsneak2 = {MIMROCKWALKR2SPR, MIMROCKWALKL2SPR, step, false, true, 6, 64, 0, T_MimrockSneak, C_Mimrock, R_Walk, &s_mimsneak3};\r
324 statetype s_mimsneak3 = {MIMROCKWALKR3SPR, MIMROCKWALKL3SPR, step, false, true, 6, 64, 0, T_MimrockSneak, C_Mimrock, R_Walk, &s_mimsneak4};\r
325 statetype s_mimsneak4 = {MIMROCKWALKR4SPR, MIMROCKWALKL4SPR, step, false, true, 6, 64, 0, T_MimrockSneak, C_Mimrock, R_Walk, &s_mimsneak5};\r
326 statetype s_mimsneak5 = {MIMROCKWALKR1SPR, MIMROCKWALKL1SPR, step, false, true, 6, 64, 0, T_MimrockSneak, C_Mimrock, R_Walk, &s_mimsneak6};\r
327 statetype s_mimsneak6 = {MIMROCKWALKR2SPR, MIMROCKWALKL2SPR, step, false, true, 6, 64, 0, T_MimrockSneak, C_Mimrock, R_Walk, &s_mimrock};\r
328 statetype s_mimbonk1  = {MIMROCKJUMPL1SPR, MIMROCKJUMPR1SPR, stepthink, false, false, 24, 0, 0, T_WeakProjectile, C_MimLethal, R_MimAir, &s_mimbonk2};\r
329 statetype s_mimbonk2  = {MIMROCKJUMPL2SPR, MIMROCKJUMPR2SPR, stepthink, false, false, 10, 0, 0, T_WeakProjectile, C_MimLethal, R_MimAir, &s_mimbonk3};\r
330 statetype s_mimbonk3  = {MIMROCKJUMPL3SPR, MIMROCKJUMPR3SPR, think, false, false, 10, 0, 0, T_WeakProjectile, C_MimLethal, R_MimAir, &s_mimbonk2};\r
331 statetype s_mimbounce = {MIMROCKJUMPL3SPR, MIMROCKJUMPR3SPR, think, false, false, 10, 0, 0, T_Projectile, C_Mimrock, R_MimBounce, NULL};\r
332 statetype s_mimstun   = {MIMROCKJUMPL3SPR, MIMROCKJUMPL3SPR, think, false, false, 12, 0, 0, T_Projectile, NULL, R_Stunned, &s_mimstun2};\r
333 statetype s_mimstun2  = {MINROCKSTUNSPR, MINROCKSTUNSPR, think, false, false, 12, 0, 0, T_Projectile, NULL, R_Stunned, NULL};\r
334 \r
335 /*\r
336 ===========================\r
337 =\r
338 = SpawnMimrock\r
339 =\r
340 ===========================\r
341 */\r
342 \r
343 void SpawnMimrock(Sint16 x, Sint16 y)\r
344 {\r
345         GetNewObj(false);\r
346         new->obclass = mimrockobj;\r
347         new->active = ac_yes;\r
348         new->priority = 3;\r
349         new->x = CONVERT_TILE_TO_GLOBAL(x);\r
350         new->y = CONVERT_TILE_TO_GLOBAL(y)+ -13*PIXGLOBAL;\r
351         new->ydir = new->xdir = 1;\r
352         NewState(new, &s_mimrock);\r
353 }\r
354 \r
355 /*\r
356 ===========================\r
357 =\r
358 = T_MimrockWait\r
359 =\r
360 ===========================\r
361 */\r
362 \r
363 void T_MimrockWait(objtype *ob)\r
364 {\r
365         if (abs(ob->bottom - player->bottom) > 5*TILEGLOBAL)\r
366                 return;\r
367 \r
368         if (abs(ob->x - player->x) > 3*TILEGLOBAL)\r
369         {\r
370                 if (player->x < ob->x)\r
371                 {\r
372                         if (player->xdir == -1)\r
373                         {\r
374                                 ob->xdir = -1;\r
375                                 ob->state = &s_mimsneak1;\r
376                         }\r
377                 }\r
378                 else\r
379                 {\r
380                         if (player->xdir == 1)\r
381                         {\r
382                                 ob->xdir = 1;\r
383                                 ob->state = &s_mimsneak1;\r
384                         }\r
385                 }\r
386         }\r
387 }\r
388 \r
389 /*\r
390 ===========================\r
391 =\r
392 = T_MimrockSneak\r
393 =\r
394 ===========================\r
395 */\r
396 \r
397 void T_MimrockSneak(objtype *ob)\r
398 {\r
399         if (abs(ob->bottom - player->bottom) > 5*TILEGLOBAL\r
400                 || ob->xdir != player->xdir)\r
401         {\r
402                 ob->state = &s_mimrock;\r
403         }\r
404         else if (abs(ob->x - player->x) < 4*TILEGLOBAL)\r
405         {\r
406                 ob->xspeed = ob->xdir * 20;\r
407                 ob->yspeed = -40;\r
408                 ytry = ob->yspeed * tics;\r
409                 ob->state = &s_mimbonk1;\r
410         }\r
411 }\r
412 \r
413 /*\r
414 ===========================\r
415 =\r
416 = C_Mimrock\r
417 =\r
418 ===========================\r
419 */\r
420 \r
421 void C_Mimrock(objtype *ob, objtype *hit)\r
422 {\r
423         if (hit->obclass == stunshotobj)\r
424         {\r
425                 //basically StunObj(), but in different order:\r
426                 ob->temp1 = 0;\r
427                 ob->temp2 = 0;\r
428                 ob->temp3 = 0;\r
429                 ob->temp4 = ob->obclass;\r
430                 ob->obclass = stunnedobj;\r
431                 ExplodeShot(hit);\r
432                 ChangeState(ob, &s_mimstun);\r
433 \r
434                 ob->yspeed -= 16;\r
435         }\r
436 }\r
437 \r
438 /*\r
439 ===========================\r
440 =\r
441 = C_MimLethal\r
442 =\r
443 ===========================\r
444 */\r
445 \r
446 void C_MimLethal(objtype *ob, objtype *hit)\r
447 {\r
448         if (hit->obclass == keenobj)\r
449         {\r
450                 KillKeen();\r
451         }\r
452         else\r
453         {\r
454                 C_Mimrock(ob, hit);\r
455         }\r
456 }\r
457 \r
458 /*\r
459 ===========================\r
460 =\r
461 = R_MimAir\r
462 =\r
463 ===========================\r
464 */\r
465 \r
466 void R_MimAir(objtype *ob)\r
467 {\r
468         if (ob->hitnorth)\r
469         {\r
470                 SD_PlaySound(SND_HELMETHIT);\r
471                 ob->yspeed = -20;\r
472                 ChangeState(ob, &s_mimbounce);\r
473         }\r
474 \r
475         if (ob->hiteast || ob->hitwest)\r
476                 ob->xspeed = 0;\r
477 \r
478         if (ob->hitnorth || ob->hitsouth)\r
479                 ob->yspeed = 0;\r
480 \r
481         RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
482 }\r
483 \r
484 /*\r
485 ===========================\r
486 =\r
487 = R_MimBounce\r
488 =\r
489 ===========================\r
490 */\r
491 \r
492 void R_MimBounce(objtype *ob)\r
493 {\r
494         if (ob->hitnorth)\r
495         {\r
496                 SD_PlaySound(SND_HELMETHIT);\r
497                 ChangeState(ob, &s_mimrock);\r
498         }\r
499 \r
500         if (ob->hiteast || ob->hitwest)\r
501                 ob->xspeed = 0;\r
502 \r
503         if (ob->hitnorth)\r
504                 ob->yspeed = 0;\r
505 \r
506         RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
507 }\r
508 \r
509 /*\r
510 =============================================================================\r
511 \r
512                                                   DOPEFISH\r
513 \r
514 temp1 = blocked (cannot change xdir to chase Keen while this is non-zero)\r
515 temp2 = old x position\r
516 temp3 = old y position\r
517 temp4 = pointer to object being eaten\r
518         (BUG: pointer may be invalid after loading a saved game!)\r
519 \r
520 =============================================================================\r
521 */\r
522 \r
523 statetype s_dopefish1  = {DOPEFISHSWIML1SPR, DOPEFISHSWIMR1SPR, stepthink, false, false, 20, 0, 0, T_Dope, C_Dope, R_Fish, &s_dopefish2};\r
524 statetype s_dopefish2  = {DOPEFISHSWIML2SPR, DOPEFISHSWIMR2SPR, stepthink, false, false, 20, 0, 0, T_Dope, C_Dope, R_Fish, &s_dopefish1};\r
525 statetype s_dopeattack = {DOPEFISHHUNGRYLSPR, DOPEFISHHUNGRYRSPR, think, false, false, 0, 0, 0, T_DopeHunt, NULL, R_Draw, NULL};\r
526 statetype s_dopeeat    = {DOPEFISHSWIML1SPR, DOPEFISHSWIMR1SPR, step, false, false, 60, 0, 0, NULL, NULL, R_Draw, &s_dopeburp1};\r
527 statetype s_dopeburp1  = {DOPEFISHBURP1SPR, DOPEFISHBURP1SPR, step, false, false, 60, 0, 0, T_Burp, NULL, R_Draw, &s_dopeburp2};\r
528 statetype s_dopeburp2  = {DOPEFISHBURP2SPR, DOPEFISHBURP2SPR, step, false, false, 60, 0, 0, NULL, NULL, R_Draw, &s_dopereturn};\r
529 statetype s_dopereturn = {DOPEFISHSWIML1SPR, DOPEFISHSWIMR1SPR, think, false, false, 0, 0, 0, T_DopeReturn, NULL, R_Draw, &s_dopefish1};\r
530 \r
531 statetype s_dopefood     = {SCHOOLFISHL1SPR, SCHOOLFISHR1SPR, think, false, false, 0, 0, 0, NULL, NULL, R_Draw, NULL};\r
532 statetype s_keendopefood = {SCUBAKEENDEAD1SPR, SCUBAKEENDEAD1SPR, think, false, false, 0, 0, 0, NULL, NULL, R_Draw, &s_keendieslow};\r
533 statetype s_keendieslow  = {-1, -1, step, false, false, 180, 0, 0, T_EatenKeen, NULL, R_Draw, &s_keendieslow};\r
534 \r
535 statetype s_bubble1 = {BIGBUBBLE1SPR, BIGBUBBLE1SPR, think, false, false, 20, 0, 20, T_Bubble, NULL, R_Draw, &s_bubble2};\r
536 statetype s_bubble2 = {BIGBUBBLE2SPR, BIGBUBBLE2SPR, think, false, false, 20, 0, 20, T_Bubble, NULL, R_Draw, &s_bubble3};\r
537 statetype s_bubble3 = {BIGBUBBLE3SPR, BIGBUBBLE3SPR, think, false, false, 20, 0, 20, T_Bubble, NULL, R_Draw, &s_bubble4};\r
538 statetype s_bubble4 = {BIGBUBBLE4SPR, BIGBUBBLE4SPR, think, false, false, 20, 0, 20, T_Bubble, NULL, R_Draw, &s_bubble1};\r
539 \r
540 /*\r
541 ===========================\r
542 =\r
543 = SpawnDopefish\r
544 =\r
545 ===========================\r
546 */\r
547 \r
548 void SpawnDopefish(Sint16 x, Sint16 y)\r
549 {\r
550         GetNewObj(false);\r
551         new->obclass = dopefishobj;\r
552         new->active = ac_yes;\r
553         new->priority = 2;\r
554         new->needtoclip = cl_fullclip;\r
555         new->x = CONVERT_TILE_TO_GLOBAL(x);\r
556         new->y = CONVERT_TILE_TO_GLOBAL(y) + -3*TILEGLOBAL;\r
557         if (US_RndT() < 0x80)\r
558         {\r
559                 new->xdir = 1;\r
560         }\r
561         else\r
562         {\r
563                 new->xdir = -1;\r
564         }\r
565         new->ydir = 1;\r
566         NewState(new, &s_dopefish1);\r
567 }\r
568 \r
569 /*\r
570 ===========================\r
571 =\r
572 = T_EatenKeen\r
573 =\r
574 ===========================\r
575 */\r
576 \r
577 void T_EatenKeen(objtype *ob)\r
578 {\r
579         ob++;                   // shut up compiler\r
580         playstate = ex_died;\r
581 }\r
582 \r
583 /*\r
584 ===========================\r
585 =\r
586 = T_Dope\r
587 =\r
588 ===========================\r
589 */\r
590 \r
591 void T_Dope(objtype *ob)\r
592 {\r
593         if (ob->temp1 == 0)\r
594         {\r
595                 if (ob->x < player->x)\r
596                 {\r
597                         ob->xdir = 1;\r
598                 }\r
599                 else\r
600                 {\r
601                         ob->xdir = -1;\r
602                 }\r
603         }\r
604         AccelerateXv(ob, ob->xdir, 10);\r
605 \r
606         if (ob->y < player->y)\r
607         {\r
608                 AccelerateY(ob, 1, 10);\r
609         }\r
610         else\r
611         {\r
612                 AccelerateY(ob, -1, 10);\r
613         }\r
614 }\r
615 \r
616 /*\r
617 ===========================\r
618 =\r
619 = T_DopeHunt\r
620 =\r
621 ===========================\r
622 */\r
623 \r
624 void T_DopeHunt(objtype *ob)\r
625 {\r
626         objtype *target;\r
627         Sint16 xdist, ydist;\r
628 \r
629         target = (objtype *)(ob->temp4);\r
630         ydist = target->y - TILEGLOBAL - ob->y;\r
631         if (ob->xdir == 1)\r
632         {\r
633                 xdist = target->right + 2*PIXGLOBAL - ob->right;\r
634         }\r
635         else\r
636         {\r
637                 xdist = target->left - 2*PIXGLOBAL - ob->left;\r
638         }\r
639 \r
640         if (xdist < 0)\r
641         {\r
642                 xtry = tics * -32;\r
643                 if (xtry < xdist)\r
644                         xtry = xdist;\r
645         }\r
646         else\r
647         {\r
648                 xtry = tics * 32;\r
649                 if (xtry > xdist)\r
650                         xtry = xdist;\r
651         }\r
652 \r
653         if (ydist < 0)\r
654         {\r
655                 ytry = tics * -32;\r
656                 if (ytry < ydist)\r
657                         ytry = ydist;\r
658         }\r
659         else\r
660         {\r
661                 ytry = tics * 32;\r
662                 if (ytry > ydist)\r
663                         ytry = ydist;\r
664         }\r
665 \r
666         if (xtry == xdist && ytry == ydist)\r
667         {\r
668                 if (target == player)\r
669                 {\r
670                         ChangeState(target, &s_keendieslow);\r
671                 }\r
672                 else if (target->state->nextstate)\r
673                 {\r
674                         ChangeState(target, target->state->nextstate);\r
675                 }\r
676                 else\r
677                 {\r
678                         RemoveObj(target);\r
679                 }\r
680                 ob->state = &s_dopeeat;\r
681         }\r
682 }\r
683 \r
684 /*\r
685 ===========================\r
686 =\r
687 = T_DopeReturn\r
688 =\r
689 ===========================\r
690 */\r
691 \r
692 void T_DopeReturn(objtype *ob)\r
693 {\r
694         Sint16 xdist, ydist;\r
695 \r
696         ydist = ob->temp3 - ob->y;\r
697         xdist = ob->temp2 - ob->x;\r
698 \r
699         if (xdist < 0)\r
700         {\r
701                 xtry = tics * -32;\r
702                 if (xtry < xdist)\r
703                         xtry = xdist;\r
704         }\r
705         else\r
706         {\r
707                 xtry = tics * 32;\r
708                 if (xtry > xdist)\r
709                         xtry = xdist;\r
710         }\r
711 \r
712         if (ydist < 0)\r
713         {\r
714                 ytry = tics * -32;\r
715                 if (ytry < ydist)\r
716                         ytry = ydist;\r
717         }\r
718         else\r
719         {\r
720                 ytry = tics * 32;\r
721                 if (ytry > ydist)\r
722                         ytry = ydist;\r
723         }\r
724 \r
725         if (xtry == xdist && ytry == ydist)\r
726         {\r
727                 ob->state = ob->state->nextstate;\r
728                 ob->needtoclip = cl_fullclip;\r
729         }\r
730 }\r
731 \r
732 /*\r
733 ===========================\r
734 =\r
735 = T_Burp\r
736 =\r
737 ===========================\r
738 */\r
739 \r
740 void T_Burp(objtype *ob)\r
741 {\r
742         GetNewObj(true);\r
743         new->x = ob->x + 56*PIXGLOBAL;\r
744         new->y = ob->y + 32*PIXGLOBAL;\r
745         new->obclass = inertobj;\r
746         new->priority = 3;\r
747         new->active = ac_removable;\r
748         new->needtoclip = cl_noclip;\r
749         new->yspeed = -20;\r
750         new->xspeed = 4;\r
751         NewState(new, &s_bubble1);\r
752         SD_PlaySound(SND_BURP);\r
753 }\r
754 \r
755 /*\r
756 ===========================\r
757 =\r
758 = T_Bubble\r
759 =\r
760 ===========================\r
761 */\r
762 \r
763 void T_Bubble(objtype *ob)\r
764 {\r
765         T_Velocity(ob);\r
766         if (US_RndT() < tics * 16)\r
767                 ob->xspeed = -ob->xspeed;\r
768 \r
769         if (ob->y < 3*TILEGLOBAL)\r
770                 RemoveObj(ob);\r
771 }\r
772 \r
773 /*\r
774 ===========================\r
775 =\r
776 = C_Dope\r
777 =\r
778 ===========================\r
779 */\r
780 \r
781 void C_Dope(objtype *ob, objtype *hit)\r
782 {\r
783         if (hit->obclass == schoolfishobj)\r
784         {\r
785                 ChangeState(hit, &s_dopefood);\r
786         }\r
787         else if (hit->obclass == keenobj && !godmode)\r
788         {\r
789                 hit->obclass = inertobj;        //prevents other objects from killing Keen before he is fully swallowed\r
790                 hit->needtoclip = cl_noclip;\r
791                 SD_PlaySound(SND_KEENDEAD);\r
792                 ChangeState(hit, &s_keendopefood);\r
793         }\r
794         else\r
795         {\r
796                 return;\r
797         }\r
798 \r
799         ob->temp2 = ob->x;\r
800         ob->temp3 = ob->y;\r
801         ob->temp4 = (Sint16)hit;\r
802         if (hit->midx < ob->midx)\r
803         {\r
804                 ob->xdir = -1;\r
805         }\r
806         else\r
807         {\r
808                 ob->xdir = 1;\r
809         }\r
810         ChangeState(ob, &s_dopeattack);\r
811         ob->needtoclip = cl_noclip;\r
812 }\r
813 \r
814 /*\r
815 ===========================\r
816 =\r
817 = R_Fish\r
818 =\r
819 ===========================\r
820 */\r
821 \r
822 void R_Fish(objtype *ob)        //for Dopefish and Schoolfish\r
823 {\r
824         if ((ob->hitsouth || ob->hitnorth) && ob->temp1 == 0)\r
825                 ob->temp1++;\r
826 \r
827         if (ob->hiteast || ob->hitwest)\r
828         {\r
829                 ob->xspeed = 0;\r
830                 ob->xdir = -ob->xdir;\r
831                 ob->temp1 = 1;\r
832         }\r
833 \r
834         if (!ob->hitsouth && !ob->hitnorth)\r
835                 ob->temp1 = 0;\r
836 \r
837         RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
838 }\r
839 \r
840 /*\r
841 =============================================================================\r
842 \r
843                                                   SCHOOLFISH\r
844 \r
845 temp1 = blocked (cannot change xdir to chase Keen while this is non-zero)\r
846 \r
847 =============================================================================\r
848 */\r
849 \r
850 statetype s_schoolfish1 = {SCHOOLFISHL1SPR, SCHOOLFISHR1SPR, stepthink, false, false, 20, 0, 0, T_SchoolFish, NULL, R_Fish, &s_schoolfish2};\r
851 statetype s_schoolfish2 = {SCHOOLFISHL2SPR, SCHOOLFISHR2SPR, stepthink, false, false, 20, 0, 0, T_SchoolFish, NULL, R_Fish, &s_schoolfish1};\r
852 \r
853 /*\r
854 ===========================\r
855 =\r
856 = SpawnSchoolfish\r
857 =\r
858 ===========================\r
859 */\r
860 \r
861 void SpawnSchoolfish(Sint16 x, Sint16 y)\r
862 {\r
863         GetNewObj(false);\r
864         new->obclass = schoolfishobj;\r
865         new->active = ac_yes;\r
866         new->needtoclip = cl_fullclip;\r
867         new->priority = 0;\r
868         new->x = CONVERT_TILE_TO_GLOBAL(x);\r
869         new->y = CONVERT_TILE_TO_GLOBAL(y);\r
870         new->ydir = new->xdir = 1;\r
871         NewState(new, &s_schoolfish1);\r
872 }\r
873 \r
874 /*\r
875 ===========================\r
876 =\r
877 = T_SchoolFish\r
878 =\r
879 ===========================\r
880 */\r
881 \r
882 void T_SchoolFish(objtype *ob)\r
883 {\r
884         if (ob->temp1 == 0)\r
885         {\r
886                 if (ob->x < player->x)\r
887                 {\r
888                         ob->xdir = 1;\r
889                 }\r
890                 else\r
891                 {\r
892                         ob->xdir = -1;\r
893                 }\r
894         }\r
895         AccelerateXv(ob, ob->xdir, 10);\r
896 \r
897         if (ob->y < player->y)\r
898         {\r
899                 AccelerateY(ob, 1, 10);\r
900         }\r
901         else\r
902         {\r
903                 AccelerateY(ob, -1, 10);\r
904         }\r
905 }\r
906 \r
907 /*\r
908 =============================================================================\r
909 \r
910                                                   PIXIE (a.k.a. SPRITE)\r
911 \r
912 =============================================================================\r
913 */\r
914 \r
915 statetype s_pixie       = {SPRITEFLOATSPR,  SPRITEFLOATSPR,  think, false, false, 10, 0, 0, T_Pixie, C_Lethal, R_Draw, &s_pixie};\r
916 statetype s_pixielook   = {SPRITEAIMLSPR,   SPRITEAIMRSPR,   step, false, false, 40, 0, 0, T_PixieCheck, C_Lethal, R_Draw, &s_pixie};\r
917 statetype s_pixieshoot  = {SPRITESHOOTLSPR, SPRITESHOOTRSPR, step, false, false, 40, 0, 0, T_PixieShoot, C_Lethal, R_Draw, &s_pixieshoot2};\r
918 statetype s_pixieshoot2 = {SPRITESHOOTLSPR, SPRITESHOOTRSPR, step, false, false, 30, 0, 0, NULL, C_Lethal, R_Draw, &s_pixie};\r
919 statetype s_pixiefire1  = {SPRITESHOT1SPR,  SPRITESHOT1SPR,  slide, false, false, 10, 64, 0, NULL, C_Lethal, R_Mshot, &s_pixiefire2};\r
920 statetype s_pixiefire2  = {SPRITESHOT2SPR,  SPRITESHOT2SPR,  slide, false, false, 10, 64, 0, NULL, C_Lethal, R_Mshot, &s_pixiefire3};\r
921 statetype s_pixiefire3  = {SPRITESHOT3SPR,  SPRITESHOT3SPR,  slide, false, false, 10, 64, 0, NULL, C_Lethal, R_Mshot, &s_pixiefire4};\r
922 statetype s_pixiefire4  = {SPRITESHOT4SPR,  SPRITESHOT4SPR,  slide, false, false, 10, 64, 0, NULL, C_Lethal, R_Mshot, &s_pixiefire1};\r
923 \r
924 /*\r
925 ===========================\r
926 =\r
927 = SpawnPixie\r
928 =\r
929 ===========================\r
930 */\r
931 \r
932 void SpawnPixie(Sint16 x, Sint16 y)\r
933 {\r
934         GetNewObj(false);\r
935         new->obclass = pixieobj;\r
936         new->active = ac_yes;\r
937         new->priority = 0;\r
938         new->needtoclip = cl_noclip;\r
939         new->x = CONVERT_TILE_TO_GLOBAL(x);\r
940         new->y = new->temp1 = CONVERT_TILE_TO_GLOBAL(y);\r
941         new->ydir = new->xdir = 1;\r
942         NewState(new, &s_pixie);\r
943 }\r
944 \r
945 /*\r
946 ===========================\r
947 =\r
948 = T_Pixie\r
949 =\r
950 ===========================\r
951 */\r
952 \r
953 void T_Pixie(objtype *ob)\r
954 {\r
955         AccelerateY(ob, ob->ydir, 8);\r
956         if ((Sint16)(ob->temp1 - ob->y) > 2*PIXGLOBAL)\r
957         {\r
958                 ob->ydir = 1;\r
959         }\r
960         if ((Sint16)(ob->y - ob->temp1) > 2*PIXGLOBAL)\r
961         {\r
962                 ob->ydir = -1;\r
963         }\r
964 \r
965         if (player->top < ob->bottom && player->bottom > ob->top)\r
966         {\r
967                 if (player->x < ob->x)\r
968                 {\r
969                         ob->xdir = -1;\r
970                 }\r
971                 else\r
972                 {\r
973                         ob->xdir = 1;\r
974                 }\r
975                 ob->state = &s_pixielook;\r
976         }\r
977 }\r
978 \r
979 /*\r
980 ===========================\r
981 =\r
982 = T_PixieCheck\r
983 =\r
984 ===========================\r
985 */\r
986 \r
987 void T_PixieCheck(objtype *ob)\r
988 {\r
989         if (player->top < ob->bottom && player->bottom > ob->top)\r
990                 ob->state = &s_pixieshoot;\r
991 }\r
992 \r
993 /*\r
994 ===========================\r
995 =\r
996 = T_PixieShoot\r
997 =\r
998 ===========================\r
999 */\r
1000 \r
1001 void T_PixieShoot(objtype *ob)\r
1002 {\r
1003         GetNewObj(true);\r
1004         new->x = ob->x;\r
1005         new->y = ob->y + 8*PIXGLOBAL;\r
1006         new->priority = 0;\r
1007         new->obclass = mshotobj;\r
1008         new->active = ac_removable;\r
1009         SD_PlaySound(SND_KEENFIRE);     //BUG?\r
1010         new->xdir = ob->xdir;\r
1011         NewState(new, &s_pixiefire1);\r
1012         SD_PlaySound(SND_SPRITEFIRE);\r
1013 }\r
1014 \r
1015 /*\r
1016 ===========================\r
1017 =\r
1018 = R_Mshot\r
1019 =\r
1020 ===========================\r
1021 */\r
1022 \r
1023 void R_Mshot(objtype *ob)\r
1024 {\r
1025         if (ob->hitnorth || ob->hiteast || ob->hitsouth || ob->hitwest)\r
1026         {\r
1027                 RemoveObj(ob);\r
1028         }\r
1029         else\r
1030         {\r
1031                 RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
1032         }\r
1033 }\r
1034 \r
1035 /*\r
1036 =============================================================================\r
1037 \r
1038                                                   MINE\r
1039 \r
1040 =============================================================================\r
1041 */\r
1042 statetype s_mine      = {MINESPR,         MINESPR,         think, false, false, 10, 0, 0, T_Platform, C_Mine, R_Draw, &s_mine};\r
1043 statetype s_mineboom1 = {MINEEXPLODE1SPR, MINEEXPLODE1SPR, step, false, false, 30, 0, 0, NULL, NULL, R_Draw, &s_mineboom2};\r
1044 statetype s_mineboom2 = {MINEEXPLODE2SPR, MINEEXPLODE2SPR, step, false, false, 30, 0, 0, NULL, NULL, R_Draw, NULL};\r
1045 \r
1046 /*\r
1047 ===========================\r
1048 =\r
1049 = SpawnMine\r
1050 =\r
1051 ===========================\r
1052 */\r
1053 \r
1054 void SpawnMine(Sint16 x, Sint16 y, Sint16 dir)\r
1055 {\r
1056         GetNewObj(false);\r
1057         new->obclass = mineobj;\r
1058         new->active = ac_allways;\r
1059         new->priority = 0;\r
1060         new->x = CONVERT_TILE_TO_GLOBAL(x);\r
1061         new->y = CONVERT_TILE_TO_GLOBAL(y);\r
1062         switch (dir)\r
1063         {\r
1064         case 0:\r
1065                 new->xdir = 0;\r
1066                 new->ydir = -1;\r
1067                 break;\r
1068         case 1:\r
1069                 new->xdir = 1;\r
1070                 new->ydir = 0;\r
1071                 break;\r
1072         case 2:\r
1073                 new->xdir = 0;\r
1074                 new->ydir = 1;\r
1075                 break;\r
1076         case 3:\r
1077                 new->xdir = -1;\r
1078                 new->ydir = 0;\r
1079                 break;\r
1080         }\r
1081         NewState(new, &s_mine);\r
1082 }\r
1083 \r
1084 /*\r
1085 ===========================\r
1086 =\r
1087 = C_Mine\r
1088 =\r
1089 ===========================\r
1090 */\r
1091 \r
1092 void C_Mine(objtype *ob, objtype *hit)\r
1093 {\r
1094         if (hit->obclass == keenobj)\r
1095         {\r
1096                 ChangeState(ob, &s_mineboom1);\r
1097                 SD_PlaySound(SND_MINEEXPLODE);\r
1098                 KillKeen();\r
1099         }\r
1100 }\r
1101 \r
1102 /*\r
1103 =============================================================================\r
1104 \r
1105                                                   PRINCESS LINDSEY\r
1106 \r
1107 temp1 = initial y position\r
1108 \r
1109 =============================================================================\r
1110 */\r
1111 statetype s_lindsey1 = {LINDSEY1SPR, LINDSEY1SPR, stepthink, false, false, 20, 0, 0, T_Lindsey, NULL, R_Draw, &s_lindsey2};\r
1112 statetype s_lindsey2 = {LINDSEY2SPR, LINDSEY2SPR, stepthink, false, false, 20, 0, 0, T_Lindsey, NULL, R_Draw, &s_lindsey3};\r
1113 statetype s_lindsey3 = {LINDSEY3SPR, LINDSEY3SPR, stepthink, false, false, 20, 0, 0, T_Lindsey, NULL, R_Draw, &s_lindsey4};\r
1114 statetype s_lindsey4 = {LINDSEY4SPR, LINDSEY4SPR, stepthink, false, false, 20, 0, 0, T_Lindsey, NULL, R_Draw, &s_lindsey1};\r
1115 \r
1116 /*\r
1117 ===========================\r
1118 =\r
1119 = SpawnLindsey\r
1120 =\r
1121 ===========================\r
1122 */\r
1123 \r
1124 void SpawnLindsey(Sint16 x, Sint16 y)\r
1125 {\r
1126         GetNewObj(false);\r
1127         new->obclass = lindseyobj;\r
1128         new->active = ac_yes;\r
1129         new->priority = 0;\r
1130         new->x = CONVERT_TILE_TO_GLOBAL(x);\r
1131         new->y = new->temp1 = CONVERT_TILE_TO_GLOBAL(y) - TILEGLOBAL;\r
1132         new->ydir = 1;\r
1133         NewState(new, &s_lindsey1);\r
1134 }\r
1135 \r
1136 /*\r
1137 ===========================\r
1138 =\r
1139 = T_Lindsey\r
1140 =\r
1141 ===========================\r
1142 */\r
1143 \r
1144 void T_Lindsey(objtype *ob)\r
1145 {\r
1146         AccelerateY(ob, ob->ydir, 8);\r
1147         if (ob->temp1 - (Sint16)ob->y > 2*PIXGLOBAL)\r
1148         {\r
1149                 ob->ydir = 1;\r
1150         }\r
1151         if ((Sint16)ob->y - ob->temp1 > 2*PIXGLOBAL)\r
1152         {\r
1153                 ob->ydir = -1;\r
1154         }\r
1155 }\r
1156 \r
1157 /*\r
1158 =============================================================================\r
1159 \r
1160                                                   DARTS\r
1161 \r
1162 temp1 = direction\r
1163 \r
1164 =============================================================================\r
1165 */\r
1166 \r
1167 statetype s_dartthrower = {0, 0, step, false, false, 150, 0, 0, T_DartShoot, NULL, NULL, &s_dartthrower};\r
1168 statetype s_dart1       = {DARTL1SPR, DARTR1SPR, slide, false, false, 6, 64, 0, NULL, C_Lethal, R_Mshot, &s_dart2};\r
1169 statetype s_dart2       = {DARTL2SPR, DARTR2SPR, slide, false, false, 6, 64, 0, NULL, C_Lethal, R_Mshot, &s_dart1};\r
1170 statetype s_dartup1     = {DARTU1SPR, DARTU1SPR, slide, false, false, 6, 0, 64, NULL, C_Lethal, R_Mshot, &s_dartup2};\r
1171 statetype s_dartup2     = {DARTU2SPR, DARTU2SPR, slide, false, false, 6, 0, 64, NULL, C_Lethal, R_Mshot, &s_dartup1};\r
1172 statetype s_dartdown1   = {DARTD1SPR, DARTD1SPR, slide, false, false, 6, 0, 64, NULL, C_Lethal, R_Mshot, &s_dartdown2};\r
1173 statetype s_dartdown2   = {DARTD2SPR, DARTD2SPR, slide, false, false, 6, 0, 64, NULL, C_Lethal, R_Mshot, &s_dartdown1};\r
1174 \r
1175 /*\r
1176 ===========================\r
1177 =\r
1178 = SpawnDartShooter\r
1179 =\r
1180 ===========================\r
1181 */\r
1182 \r
1183 void SpawnDartShooter(Sint16 x, Sint16 y, Sint16 dir)\r
1184 {\r
1185         GetNewObj(false);\r
1186         new->obclass = inertobj;\r
1187         new->active = ac_yes;\r
1188         new->x = CONVERT_TILE_TO_GLOBAL(x);\r
1189         new->needtoclip = cl_noclip;\r
1190         new->y = CONVERT_TILE_TO_GLOBAL(y);\r
1191         new->temp1 = dir;\r
1192         switch (dir)\r
1193         {\r
1194         case 0:\r
1195                 new->y -= 3*PIXGLOBAL;\r
1196                 new->x += 9*PIXGLOBAL;\r
1197                 new->shapenum = DARTU1SPR;\r
1198                 break;\r
1199         case 1:\r
1200                 new->x += 8*PIXGLOBAL;\r
1201                 new->y += 5*PIXGLOBAL;\r
1202                 new->shapenum = DARTR1SPR;\r
1203                 break;\r
1204         case 2:\r
1205                 new->x += 9*PIXGLOBAL;\r
1206                 new->shapenum = DARTD1SPR;\r
1207                 break;\r
1208         case 3:\r
1209                 new->y += 7*PIXGLOBAL;\r
1210                 new->x -= 3*PIXGLOBAL;\r
1211                 new->shapenum = DARTL1SPR;\r
1212                 break;\r
1213         }\r
1214         NewState(new, &s_dartthrower);\r
1215 }\r
1216 \r
1217 /*\r
1218 ===========================\r
1219 =\r
1220 = T_DartShoot\r
1221 =\r
1222 ===========================\r
1223 */\r
1224 \r
1225 void T_DartShoot(objtype *ob)\r
1226 {\r
1227         GetNewObj(true);\r
1228         new->x = ob->x;\r
1229         new->y = ob->y;\r
1230         new->obclass = mshotobj;\r
1231         new->active = ac_removable;\r
1232         switch (ob->temp1)\r
1233         {\r
1234         case 0:\r
1235                 new->xdir = 0;\r
1236                 new->ydir = -1;\r
1237                 NewState(new, &s_dartup1);\r
1238                 break;\r
1239         case 1:\r
1240                 new->xdir = 1;\r
1241                 new->ydir = 0;\r
1242                 NewState(new, &s_dart1);\r
1243                 break;\r
1244         case 2:\r
1245                 new->xdir = 0;\r
1246                 new->ydir = 1;\r
1247                 NewState(new, &s_dartdown1);\r
1248                 break;\r
1249         case 3:\r
1250                 new->xdir = -1;\r
1251                 new->ydir = 0;\r
1252                 NewState(new, &s_dart1);\r
1253                 break;\r
1254         }\r
1255         SD_PlaySound(SND_SHOOTDART);\r
1256 }\r
1257 \r
1258 /*\r
1259 ===========================\r
1260 =\r
1261 = R_DartThrower\r
1262 =\r
1263 ===========================\r
1264 */\r
1265 \r
1266 void R_DartThrower(objtype *ob) //never used\r
1267 {\r
1268         RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
1269 }\r
1270 \r
1271 /*\r
1272 =============================================================================\r
1273 \r
1274                                                   SCUBA GEAR\r
1275 \r
1276 =============================================================================\r
1277 */\r
1278 statetype s_scuba = {SCUBASPR, SCUBASPR, step, false, false, 30000, 0, 0, NULL, C_Scuba, R_Draw, &s_scuba};\r
1279 \r
1280 /*\r
1281 ===========================\r
1282 =\r
1283 = SpawnScuba\r
1284 =\r
1285 ===========================\r
1286 */\r
1287 \r
1288 void SpawnScuba(Sint16 x, Sint16 y)\r
1289 {\r
1290         GetNewObj(false);\r
1291         new->obclass = scubaobj;\r
1292         new->active = ac_yes;\r
1293         new->x = CONVERT_TILE_TO_GLOBAL(x);\r
1294         new->y = CONVERT_TILE_TO_GLOBAL(y) + -TILEGLOBAL;\r
1295         NewState(new, &s_scuba);\r
1296 }\r
1297 \r
1298 /*\r
1299 ===========================\r
1300 =\r
1301 = C_Scuba\r
1302 =\r
1303 ===========================\r
1304 */\r
1305 \r
1306 void C_Scuba(objtype *ob, objtype *hit)\r
1307 {\r
1308         if (hit->obclass == keenobj && hit->hitnorth)\r
1309         {\r
1310                 gamestate.wetsuit = true;\r
1311                 SD_PlaySound(SND_MAKEFOOT);\r
1312                 GotScuba();\r
1313                 RF_ForceRefresh();\r
1314                 playstate = ex_completed;\r
1315                 ob++;                   // shut up compiler\r
1316         }\r
1317 }