]> 4ch.mooo.com Git - 16.git/blob - 16/keen456/KEEN4-6/KEEN5/K5_ACT2.C
extrcted keen code remake
[16.git] / 16 / keen456 / KEEN4-6 / KEEN5 / K5_ACT2.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 K5_ACT2.C\r
25 =========\r
26 \r
27 Contains the following actor types (in this order):\r
28 \r
29 - Sparky\r
30 - Little Ampton\r
31 - Slicestar\r
32 - Shelley\r
33 \r
34 */\r
35 \r
36 #include "CK_DEF.H"\r
37 \r
38 /*\r
39 =============================================================================\r
40 \r
41                                                   SPARKY\r
42 \r
43 temp1 = charge countdown\r
44 \r
45 =============================================================================\r
46 */\r
47 \r
48 statetype s_sparkywalk1   = {SPARKYWALKL1SPR, SPARKYWALKR1SPR, step,  false, true,  8, 128, 0, T_Sparky, C_Sparky, R_Sparky, &s_sparkywalk2};\r
49 statetype s_sparkywalk2   = {SPARKYWALKL2SPR, SPARKYWALKR2SPR, step,  false, true,  8, 128, 0, NULL, C_Sparky, R_Sparky, &s_sparkywalk3};\r
50 statetype s_sparkywalk3   = {SPARKYWALKL3SPR, SPARKYWALKR3SPR, step,  false, true,  8, 128, 0, NULL, C_Sparky, R_Sparky, &s_sparkywalk4};\r
51 statetype s_sparkywalk4   = {SPARKYWALKL4SPR, SPARKYWALKR4SPR, step,  false, true,  8, 128, 0, NULL, C_Sparky, R_Sparky, &s_sparkywalk1};\r
52 statetype s_sparkylook1   = {SPARKYTURN1SPR,  SPARKYTURN1SPR,  step,  false, true,  6,   0, 0, NULL, C_Sparky, R_Draw, &s_sparkylook2};\r
53 statetype s_sparkylook2   = {SPARKYTURN2SPR,  SPARKYTURN2SPR,  step,  false, true,  6,   0, 0, NULL, C_Sparky, R_Draw, &s_sparkylook3};\r
54 statetype s_sparkylook3   = {SPARKYTURN3SPR,  SPARKYTURN3SPR,  step,  false, true,  6,   0, 0, NULL, C_Sparky, R_Draw, &s_sparkylook4};\r
55 statetype s_sparkylook4   = {SPARKYWALKR1SPR, SPARKYWALKR1SPR, step,  false, true,  6,   0, 0, T_SparkyLookL, C_Sparky, R_Sparky, &s_sparkylook5};\r
56 statetype s_sparkylook5   = {SPARKYTURN3SPR,  SPARKYTURN3SPR,  step,  false, true,  6,   0, 0, NULL, C_Sparky, R_Draw, &s_sparkylook6};\r
57 statetype s_sparkylook6   = {SPARKYTURN2SPR,  SPARKYTURN3SPR,  step,  false, true,  6,   0, 0, NULL, C_Sparky, R_Draw, &s_sparkylook7};\r
58 statetype s_sparkylook7   = {SPARKYTURN1SPR,  SPARKYTURN3SPR,  step,  false, true,  6,   0, 0, NULL, C_Sparky, R_Draw, &s_sparkylook8};\r
59 statetype s_sparkylook8   = {SPARKYWALKL1SPR, SPARKYWALKR1SPR, step,  false, true,  6,   0, 0, T_SparkyLookR, C_Sparky, R_Sparky, &s_sparkywalk2};\r
60 statetype s_sparkyspeed1  = {SPARKYWALKL1SPR, SPARKYWALKR1SPR, step,  true,  true,  4,   0, 0, NULL, C_Sparky, R_Sparky, &s_sparkyspeed2};\r
61 statetype s_sparkyspeed2  = {SPARKYWALKL2SPR, SPARKYWALKR2SPR, step,  true,  true,  4,   0, 0, NULL, C_Sparky, R_Sparky, &s_sparkyspeed3};\r
62 statetype s_sparkyspeed3  = {SPARKYWALKL3SPR, SPARKYWALKR3SPR, step,  true,  true,  4,   0, 0, NULL, C_Sparky, R_Sparky, &s_sparkyspeed4};\r
63 statetype s_sparkyspeed4  = {SPARKYWALKL4SPR, SPARKYWALKR4SPR, step,  true,  true,  4,   0, 0, T_ChargeCount, C_Sparky, R_Sparky, &s_sparkyspeed1};\r
64 statetype s_sparkycharge1 = {SPARKYWALKL1SPR, SPARKYWALKR1SPR, step,  true,  true,  4, 128, 0, NULL, C_Sparky, R_Sparky, &s_sparkycharge2};\r
65 statetype s_sparkycharge2 = {SPARKYWALKL2SPR, SPARKYWALKR2SPR, step,  true,  true,  4, 128, 0, T_RunSnd1, C_Sparky, R_Sparky, &s_sparkycharge3};\r
66 statetype s_sparkycharge3 = {SPARKYWALKL3SPR, SPARKYWALKR3SPR, step,  true,  true,  4, 128, 0, NULL, C_Sparky, R_Sparky, &s_sparkycharge4};\r
67 statetype s_sparkycharge4 = {SPARKYWALKL4SPR, SPARKYWALKR4SPR, step,  true,  true,  4, 128, 0, T_RunSnd2, C_Sparky, R_Sparky, &s_sparkycharge1};\r
68 statetype s_sparkyturn1   = {SPARKYTURN3SPR,  SPARKYTURN1SPR,  step,  false, true,  8,   0, 0, NULL, C_Sparky, R_Draw, &s_sparkyturn2};\r
69 statetype s_sparkyturn2   = {SPARKYTURN2SPR,  SPARKYTURN2SPR,  step,  false, true,  8,   0, 0, NULL, C_Sparky, R_Draw, &s_sparkyturn3};\r
70 statetype s_sparkyturn3   = {SPARKYTURN1SPR,  SPARKYTURN3SPR,  step,  false, true,  8,   0, 0, NULL, C_Sparky, R_Draw, &s_sparkywalk1};\r
71 statetype s_sparkystun    = {SPARKYSTUNSPR,   SPARKYSTUNSPR,   think, false, false, 0,   0, 0, T_Projectile, NULL, R_Stunned, NULL};\r
72 \r
73 /*\r
74 ===========================\r
75 =\r
76 = SpawnSparky\r
77 =\r
78 ===========================\r
79 */\r
80 \r
81 void SpawnSparky(Uint16 tileX, Uint16 tileY)\r
82 {\r
83         GetNewObj(false);\r
84         new->obclass = sparkyobj;\r
85         new->active = ac_yes;\r
86         new->priority = 0;\r
87         new->x = CONVERT_TILE_TO_GLOBAL(tileX);\r
88         new->y = CONVERT_TILE_TO_GLOBAL(tileY) + -1*TILEGLOBAL;\r
89         if (US_RndT() < 0x80)\r
90         {\r
91                 new->xdir = 1;\r
92         }\r
93         else\r
94         {\r
95                 new->xdir = -1;\r
96         }\r
97         new->ydir = 1;\r
98         NewState(new, &s_sparkywalk1);\r
99 }\r
100 \r
101 /*\r
102 ===========================\r
103 =\r
104 = T_Sparky\r
105 =\r
106 ===========================\r
107 */\r
108 \r
109 void T_Sparky(objtype *ob)\r
110 {\r
111         if (US_RndT() < 0x40)\r
112         {\r
113                 ob->state = &s_sparkylook1;\r
114                 xtry = 0;\r
115         }\r
116 }\r
117 \r
118 /*\r
119 ===========================\r
120 =\r
121 = T_ChargeCount\r
122 =\r
123 ===========================\r
124 */\r
125 \r
126 void T_ChargeCount(objtype *ob)\r
127 {\r
128         if (--ob->temp1 == 0)\r
129                 ob->state = &s_sparkycharge1;\r
130 }\r
131 \r
132 /*\r
133 ===========================\r
134 =\r
135 = T_SparkyLookL\r
136 =\r
137 ===========================\r
138 */\r
139 \r
140 void T_SparkyLookL(objtype *ob)\r
141 {\r
142         Uint16 dist = player->bottom + TILEGLOBAL - ob->bottom;\r
143         if (dist > 2*TILEGLOBAL)\r
144                 return;\r
145 \r
146         if (player->x < ob->x)\r
147         {       \r
148                 ob->xdir = -1;\r
149                 SD_PlaySound(SND_SPARKYCHARGE);\r
150                 ob->state = &s_sparkyspeed1;\r
151                 ob->temp1 = 3;\r
152         }\r
153 }\r
154 \r
155 /*\r
156 ===========================\r
157 =\r
158 = T_SparkyLookR\r
159 =\r
160 ===========================\r
161 */\r
162 \r
163 void T_SparkyLookR(objtype *ob)\r
164 {\r
165         Uint16 dist = player->bottom + TILEGLOBAL - ob->bottom;\r
166         if (dist > 2*TILEGLOBAL)\r
167                 return;\r
168 \r
169         if (player->x > ob->x)\r
170         {\r
171                 ob->xdir = 1;\r
172                 SD_PlaySound(SND_SPARKYCHARGE);\r
173                 ob->state = &s_sparkyspeed1;\r
174                 ob->temp1 = 3;\r
175         }\r
176 }\r
177 \r
178 /*\r
179 ===========================\r
180 =\r
181 = T_RunSnd1\r
182 =\r
183 ===========================\r
184 */\r
185 \r
186 #pragma argsused\r
187 void T_RunSnd1(objtype *ob)\r
188 {\r
189         SD_PlaySound(SND_WORLDWALK1);\r
190 }\r
191 \r
192 /*\r
193 ===========================\r
194 =\r
195 = T_RunSnd2\r
196 =\r
197 ===========================\r
198 */\r
199 \r
200 #pragma argsused\r
201 void T_RunSnd2(objtype *ob)\r
202 {\r
203         SD_PlaySound(SND_WORLDWALK1);\r
204 }\r
205 \r
206 /*\r
207 ===========================\r
208 =\r
209 = C_Sparky\r
210 =\r
211 ===========================\r
212 */\r
213 \r
214 void C_Sparky(objtype *ob, objtype *hit)\r
215 {\r
216         if (hit->obclass == keenobj)\r
217         {\r
218                 KillKeen();\r
219         }\r
220         else if (hit->obclass == stunshotobj)\r
221         {\r
222                 StunObj(ob, hit, &s_sparkystun);\r
223         }\r
224 }\r
225 \r
226 /*\r
227 ===========================\r
228 =\r
229 = R_Sparky\r
230 =\r
231 ===========================\r
232 */\r
233 \r
234 void R_Sparky(objtype *ob)\r
235 {\r
236         if (ob->xdir == 1 && ob->hitwest)\r
237         {\r
238                 ob->x -= ob->xmove;\r
239                 ob->xdir = -1;\r
240                 ob->nothink = US_RndT() >> 5;\r
241                 ChangeState(ob, &s_sparkyturn1);\r
242         }\r
243         else if (ob->xdir == -1 && ob->hiteast)\r
244         {\r
245                 ob->x -= ob->xmove;\r
246                 ob->xdir = 1;\r
247                 ob->nothink = US_RndT() >> 5;\r
248                 ChangeState(ob, &s_sparkyturn1);\r
249         }\r
250         else if (!ob->hitnorth)\r
251         {\r
252                 ob->x -= ob->xmove;\r
253                 ob->xdir = -ob->xdir;\r
254                 ob->nothink = US_RndT() >> 5;\r
255                 ChangeState(ob, &s_sparkyturn1);\r
256         }\r
257         RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
258 }\r
259 \r
260 /*\r
261 =============================================================================\r
262 \r
263                                                   LITTLE AMPTON\r
264 \r
265 =============================================================================\r
266 */\r
267 \r
268 statetype s_amptonwalk1    = {AMTONWALKL1SPR, AMPTONWALKR1SPR, step,       false, true,  8, 128,  0, T_Ampton, C_Ampton, R_Ampton, &s_amptonwalk2};\r
269 statetype s_amptonwalk2    = {AMTONWALKL2SPR, AMPTONWALKR2SPR, step,       false, true,  8, 128,  0, T_Ampton, C_Ampton, R_Ampton, &s_amptonwalk3};\r
270 statetype s_amptonwalk3    = {AMTONWALKL3SPR, AMPTONWALKR3SPR, step,       false, true,  8, 128,  0, T_Ampton, C_Ampton, R_Ampton, &s_amptonwalk4};\r
271 statetype s_amptonwalk4    = {AMTONWALKL4SPR, AMPTONWALKR4SPR, step,       false, true,  8, 128,  0, T_Ampton, C_Ampton, R_Ampton, &s_amptonwalk1};\r
272 statetype s_amptonturn     = {AMPTONFACESPR,  AMPTONFACESPR,   step,       false, true,  8,   0,  0, NULL, C_Ampton, R_Draw, &s_amptonwalk1};\r
273 statetype s_amptongrab1    = {AMPTONGRAB1SPR, AMPTONGRAB1SPR,  step,       false, true,  8,   0,  0, NULL, C_Ampton, R_Draw, &s_amptongrab2};\r
274 statetype s_amptongrab2    = {AMPTONGRAB2SPR, AMPTONGRAB2SPR,  step,       false, true,  8,   0,  0, NULL, C_Ampton, R_Draw, &s_amptonclimb};\r
275 statetype s_amptonclimb    = {AMPTONGRAB2SPR, AMPTONGRAB2SPR,  slidethink, false, false, 0,   0, 32, T_AmptonClimb, C_Ampton, R_Draw, NULL};\r
276 statetype s_amptonrelease1 = {AMPTONGRAB2SPR, AMPTONGRAB2SPR,  step,       false, false, 8,   0,  0, NULL, C_Ampton, R_Draw, &s_amptonrelease2};\r
277 statetype s_amptonrelease2 = {AMPTONGRAB1SPR, AMPTONGRAB1SPR,  step,       false, false, 8,   0,  0, T_SetNoThink, C_Ampton, R_Draw, &s_amptonwalk1};\r
278 statetype s_amptonfiddle1  = {AMPTONGRAB1SPR, AMPTONGRAB1SPR,  step,       false, true, 12,   0,  0, NULL, C_Ampton, R_Draw, &s_amptonfiddle2};\r
279 statetype s_amptonfiddle2  = {AMPTONGRAB2SPR, AMPTONGRAB2SPR,  step,       false, true, 12,   0,  0, NULL, C_Ampton, R_Draw, &s_amptonfiddle3};\r
280 statetype s_amptonfiddle3  = {AMPTONGRAB1SPR, AMPTONGRAB1SPR,  step,       false, true, 12,   0,  0, NULL, C_Ampton, R_Draw, &s_amptonfiddle4};\r
281 statetype s_amptonfiddle4  = {AMPTONGRAB2SPR, AMPTONGRAB2SPR,  step,       false, true, 12,   0,  0, NULL, C_Ampton, R_Draw, &s_amptonfiddle5};\r
282 statetype s_amptonfiddle5  = {AMPTONGRAB1SPR, AMPTONGRAB1SPR,  step,       false, true, 12,   0,  0, T_SetNoThink, C_Ampton, R_Draw, &s_amptonwalk1};\r
283 statetype s_amptonstun     = {AMPTONSTUNSPR,  AMPTONSTUNSPR,   think,      false, false, 0,   0,  0, T_Projectile, NULL, R_Stunned, NULL};\r
284 \r
285 /*\r
286 ===========================\r
287 =\r
288 = SpawnAmpton\r
289 =\r
290 ===========================\r
291 */\r
292 \r
293 void SpawnAmpton(Uint16 tileX, Uint16 tileY)\r
294 {\r
295         GetNewObj(false);\r
296         new->obclass = amptonobj;\r
297         new->active = ac_yes;\r
298         new->priority = 0;\r
299         new->x = CONVERT_TILE_TO_GLOBAL(tileX);\r
300         new->y = CONVERT_TILE_TO_GLOBAL(tileY) + -8*PIXGLOBAL;\r
301         if (US_RndT() < 0x80)\r
302         {\r
303                 new->xdir = 1;\r
304         }\r
305         else\r
306         {\r
307                 new->xdir = -1;\r
308         }\r
309         new->ydir = 1;\r
310         NewState(new, &s_amptonwalk1);\r
311 }\r
312 \r
313 /*\r
314 ===========================\r
315 =\r
316 = T_Ampton\r
317 =\r
318 ===========================\r
319 */\r
320 \r
321 void T_Ampton(objtype *ob)\r
322 {\r
323         Uint16 far *map;\r
324         Uint16 intile, var8;\r
325         boolean poleup, poledown;\r
326 \r
327         if (ob->state == &s_amptonwalk1)\r
328         {\r
329                 SD_PlaySound(SND_AMPTONWALK1);\r
330         }\r
331         else if (ob->state == &s_amptonwalk3)\r
332         {\r
333                 SD_PlaySound(SND_AMPTONWALK2);\r
334         }\r
335         if (ob->x & 0xFF)\r
336         {\r
337                 map = mapsegs[1] + mapbwidthtable[ob->tiletop]/2 + ob->tileleft + 1;\r
338                 intile = tinf[*map + INTILE] & INTILE_TYPEMASK;\r
339                 if (intile == INTILE_AMPTONCOMPUTER)\r
340                 {\r
341                         ob->state = &s_amptonfiddle1;\r
342                 }\r
343                 else if (intile == INTILE_POLE && US_RndT() < 196)\r
344                 {\r
345                         if ((tinf[*(map + mapwidth*2) + INTILE] & INTILE_TYPEMASK) == INTILE_POLE)\r
346                         {\r
347                                 poledown = true;\r
348                         }\r
349                         else\r
350                         {\r
351                                 poledown = false;\r
352                         }\r
353                         if ((tinf[*(map - mapwidth*2) + INTILE] & INTILE_TYPEMASK) == INTILE_POLE)\r
354                         {\r
355                                 poleup = true;\r
356                         }\r
357                         else\r
358                         {\r
359                                 poleup = false;\r
360                         }\r
361                         if (poleup && poledown)\r
362                         {\r
363                                 if (US_RndT() < 0x80)\r
364                                         poleup = false;\r
365                                 else\r
366                                         poledown = false;\r
367                         }\r
368 \r
369                         if (poleup)\r
370                         {\r
371                                 ob->ydir = -1;\r
372                                 ob->state = &s_amptongrab1;\r
373                                 ob->needtoclip = cl_noclip;\r
374                                 ob->nothink = 6;\r
375                                 xtry = 0;\r
376                         }\r
377                         else if (poledown)\r
378                         {\r
379                                 ob->ydir = 1;\r
380                                 ob->state = &s_amptongrab1;\r
381                                 ob->needtoclip = cl_noclip;\r
382                                 ob->nothink = 6;\r
383                                 xtry = 0;\r
384                         }\r
385                 }\r
386         }\r
387 }\r
388 \r
389 /*\r
390 ===========================\r
391 =\r
392 = T_AmptonClimb\r
393 =\r
394 ===========================\r
395 */\r
396 \r
397 void T_AmptonClimb(objtype *ob)\r
398 {\r
399         Uint16 newtile;\r
400         Uint16 far *map;\r
401         Uint16 move;\r
402 \r
403         newtile = CONVERT_GLOBAL_TO_TILE(ob->bottom + ytry);\r
404         if (ob->tilebottom != newtile)\r
405         {\r
406                 if (ob->ydir == -1)\r
407                 {\r
408                         map = mapsegs[1] + mapbwidthtable[newtile]/2 + ob->tileleft + 1;\r
409                         if (!tinf[map[0] + NORTHWALL] && tinf[map[mapwidth]+NORTHWALL])\r
410                         {\r
411                                 if ((tinf[*(map-4*mapwidth)+INTILE] & INTILE_TYPEMASK) == INTILE_POLE && US_RndT() < 0x80)\r
412                                         return;\r
413 \r
414                                 move = (ob->bottom & 0xFF) + 1;\r
415                                 ob->y -= move;\r
416                                 ob->bottom -= move;\r
417                                 ob->needtoclip = cl_midclip;\r
418                                 ob->state = &s_amptonrelease1;\r
419                                 ytry = PIXGLOBAL;\r
420                                 ob->ydir = 1;\r
421                                 ClipToWalls(ob);\r
422                                 ob->nothink = 4;\r
423                                 return;\r
424                         }\r
425                         if ((tinf[*(map-mapwidth)+INTILE] & INTILE_TYPEMASK) != INTILE_POLE)\r
426                         {\r
427                                 ytry = 0;\r
428                                 ob->ydir = 1;\r
429                         }\r
430                 }\r
431                 else\r
432                 {\r
433                         map = mapsegs[1] + mapbwidthtable[newtile]/2 + ob->tileleft + 1;\r
434                         if (tinf[map[0] + NORTHWALL] && !tinf[*(map-mapwidth)+NORTHWALL])\r
435                         {\r
436                                 if ((tinf[map[2*mapwidth] + INTILE] & INTILE_TYPEMASK) == INTILE_POLE && US_RndT() < 0x80)\r
437                                         return;\r
438 \r
439                                 move = 0xFF - (ob->bottom & 0xFF);\r
440                                 ob->y += move;\r
441                                 ob->bottom += move;\r
442                                 ob->needtoclip = cl_midclip;\r
443                                 ob->state = &s_amptonrelease1;\r
444                                 ytry = PIXGLOBAL;\r
445                                 ClipToWalls(ob);\r
446                                 ob->nothink = 4;\r
447                                 return;\r
448                         }\r
449                         if ((tinf[map[0] + INTILE] & INTILE_TYPEMASK) != INTILE_POLE)\r
450                         {\r
451                                 ytry = 0;\r
452                                 ob->ydir = -1;\r
453                         }\r
454                 }\r
455         }\r
456 }\r
457 \r
458 /*\r
459 ===========================\r
460 =\r
461 = T_SetNoThink\r
462 =\r
463 ===========================\r
464 */\r
465 \r
466 void T_SetNoThink(objtype *ob)\r
467 {\r
468         ob->nothink = 4;\r
469 }\r
470 \r
471 /*\r
472 ===========================\r
473 =\r
474 = C_Ampton\r
475 =\r
476 ===========================\r
477 */\r
478 \r
479 void C_Ampton(objtype *ob, objtype *hit)\r
480 {\r
481         if (hit->obclass == keenobj)\r
482         {\r
483                 if (ob->state == &s_amptonclimb)\r
484                 {\r
485                         KillKeen();\r
486                 }\r
487                 else\r
488                 {\r
489                         ClipToSpriteSide(hit, ob);\r
490                 }\r
491         }\r
492         else if (hit->obclass == stunshotobj)\r
493         {\r
494                 ob->needtoclip = cl_midclip;\r
495                 ob->ydir = 1;\r
496                 ob->yspeed = 0;\r
497                 SD_PlaySound(SND_AMPTONDIE);\r
498                 StunObj(ob, hit, &s_amptonstun);\r
499         }\r
500 }\r
501 \r
502 /*\r
503 ===========================\r
504 =\r
505 = R_Ampton\r
506 =\r
507 ===========================\r
508 */\r
509 \r
510 void R_Ampton(objtype *ob)\r
511 {\r
512         if (ob->xdir == 1 && ob->hitwest)\r
513         {\r
514                 ob->x -= ob->xmove;\r
515                 ob->xdir = -1;\r
516                 ChangeState(ob, &s_amptonturn);\r
517         }\r
518         else if (ob->xdir == -1 && ob->hiteast)\r
519         {\r
520                 ob->x -= ob->xmove;\r
521                 ob->xdir = 1;\r
522                 ChangeState(ob, &s_amptonturn);\r
523         }\r
524         else if (!ob->hitnorth)\r
525         {\r
526                 ob->x -= ob->xmove;\r
527                 ob->xdir = -ob->xdir;\r
528                 ChangeState(ob, &s_amptonturn);\r
529         }\r
530         RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
531 }\r
532 \r
533 /*\r
534 =============================================================================\r
535 \r
536                                                   SLICESTAR\r
537 \r
538 temp4 = health\r
539 \r
540 =============================================================================\r
541 */\r
542 \r
543 statetype s_slicestarslide  = {SLICESTARSPR,     SLICESTARSPR,     think, false, false,  0,  0,  0, T_Platform, C_Slicestar, R_Draw, NULL};\r
544 statetype s_slicestarbounce = {SLICESTARSPR,     SLICESTARSPR,     slide, false, false,  0, 24, 24, NULL, C_Slicestar, R_Slicestar, &s_slicestarbounce};\r
545 statetype s_slicestarboom   = {SLICESTARBOOMSPR, SLICESTARBOOMSPR, step,  false, false, 20,  0,  0, NULL, NULL, R_Draw, NULL};\r
546 \r
547 /*\r
548 ===========================\r
549 =\r
550 = SpawnSlicestarSlide\r
551 =\r
552 ===========================\r
553 */\r
554 \r
555 void SpawnSlicestarSlide(Uint16 tileX, Uint16 tileY, Sint16 dir)\r
556 {\r
557         GetNewObj(false);\r
558         new->obclass = slicestarobj;\r
559         new->active = ac_yes;\r
560         new->priority = 2;\r
561         new->x = CONVERT_TILE_TO_GLOBAL(tileX);\r
562         new->y = CONVERT_TILE_TO_GLOBAL(tileY);\r
563         new->temp4 = 20;        // health!\r
564         switch (dir)\r
565         {\r
566         case 0:\r
567                 new->xdir = 0;\r
568                 new->ydir = -1;\r
569                 break;\r
570         case 1:\r
571                 new->xdir = 1;\r
572                 new->ydir = 0;\r
573                 break;\r
574         case 2:\r
575                 new->xdir = 0;\r
576                 new->ydir = 1;\r
577                 break;\r
578         case 3:\r
579                 new->xdir = -1;\r
580                 new->ydir = 0;\r
581         }\r
582         NewState(new, &s_slicestarslide);\r
583 }\r
584 \r
585 /*\r
586 ===========================\r
587 =\r
588 = SpawnSlicestarBounce\r
589 =\r
590 ===========================\r
591 */\r
592 \r
593 void SpawnSlicestarBounce(Uint16 tileX, Uint16 tileY)\r
594 {\r
595         GetNewObj(false);\r
596         new->obclass = slicestarobj;\r
597         new->active = ac_yes;\r
598         new->priority = 2;\r
599         new->needtoclip = cl_fullclip;\r
600         new->x = CONVERT_TILE_TO_GLOBAL(tileX);\r
601         new->y = CONVERT_TILE_TO_GLOBAL(tileY);\r
602         new->temp4 = 50;        // health!\r
603         switch (US_RndT() / 0x40)\r
604         {\r
605         case 0:\r
606                 new->xdir = -1;\r
607                 new->ydir = -1;\r
608                 break;\r
609         case 1:\r
610                 new->xdir = 1;\r
611                 new->ydir = 1;\r
612                 break;\r
613         case 2:\r
614                 new->xdir = -1;\r
615                 new->ydir = 1;\r
616                 break;\r
617         case 3:\r
618                 new->xdir = 1;\r
619                 new->ydir = -1;\r
620         }\r
621         NewState(new, &s_slicestarbounce);\r
622 }\r
623 \r
624 /*\r
625 ===========================\r
626 =\r
627 = C_Slicestar\r
628 =\r
629 ===========================\r
630 */\r
631 \r
632 void C_Slicestar(objtype *ob, objtype *hit)\r
633 {\r
634         if (hit->obclass == keenobj)\r
635         {\r
636                 KillKeen();\r
637         }\r
638         else if (hit->obclass == stunshotobj)\r
639         {\r
640                 ExplodeShot(hit);\r
641                 if (--ob->temp4 == 0)\r
642                 {\r
643                         ChangeState(ob, &s_slicestarboom);\r
644                 }\r
645         }\r
646 }\r
647 \r
648 /*\r
649 ===========================\r
650 =\r
651 = R_Slicestar\r
652 =\r
653 ===========================\r
654 */\r
655 \r
656 void R_Slicestar(objtype *ob)\r
657 {\r
658         if (ob->hitnorth)\r
659         {\r
660                 ob->ydir = -1;\r
661                 SD_PlaySound(SND_SLICESTARBOUNCE);\r
662         }\r
663         else if (ob->hitsouth)\r
664         {\r
665                 ob->ydir = 1;\r
666                 SD_PlaySound(SND_SLICESTARBOUNCE);\r
667         }\r
668         if (ob->hitwest)\r
669         {\r
670                 ob->xdir = -1;\r
671                 SD_PlaySound(SND_SLICESTARBOUNCE);\r
672         }\r
673         else if (ob->hiteast)\r
674         {\r
675                 ob->xdir = 1;\r
676                 SD_PlaySound(SND_SLICESTARBOUNCE);\r
677         }\r
678         RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
679 }\r
680 \r
681 /*\r
682 =============================================================================\r
683 \r
684                                                   SHELLEY\r
685 \r
686 =============================================================================\r
687 */\r
688 \r
689 statetype s_shellywalk1  = {SHELLEYL1SPR,     SHELLEYR1SPR,     step,      false, true,    8, 128, 0, NULL, C_Shelly, R_Shelly, &s_shellywalk2};\r
690 statetype s_shellywalk2  = {SHELLEYL2SPR,     SHELLEYR2SPR,     step,      false, true,    8, 128, 0, NULL, C_Shelly, R_Shelly, &s_shellywalk3};\r
691 statetype s_shellywalk3  = {SHELLEYL3SPR,     SHELLEYR3SPR,     step,      false, true,    8, 128, 0, NULL, C_Shelly, R_Shelly, &s_shellywalk4};\r
692 statetype s_shellywalk4  = {SHELLEYL4SPR,     SHELLEYR4SPR,     step,      false, true,    8, 128, 0, NULL, C_Shelly, R_Shelly, &s_shellywalk1};\r
693 statetype s_shellylook   = {SHELLEYL2SPR,     SHELLEYR2SPR,     stepthink, false, true,  100,   0, 0, T_ShellyLook, C_Shelly, R_Draw, &s_shellylook2};\r
694 statetype s_shellylook2  = {SHELLEYL2SPR,     SHELLEYR2SPR,     step,      true,  true,    1,   0, 0, T_Turn, C_Shelly, R_Draw, &s_shellywalk1};\r
695 statetype s_shellyjump1  = {SHELLEYJUMPLSPR,  SHELLEYJUMPRSPR,  stepthink, false, false,   8,   0, 0, T_Projectile, C_Shelly, R_Shell, &s_shellyjump2};\r
696 statetype s_shellyjump2  = {SHELLEYFALLLSPR,  SHELLEYFALLRSPR,  think,     false, false,   8,   0, 0, T_Projectile, C_Shelly, R_Shell, NULL};\r
697 statetype s_shellydie    = {SHELLEYFALLLSPR,  SHELLEYFALLRSPR,  step,      false, false,   8,   0, 0, T_ShellyFrag, NULL, R_Shell, NULL};\r
698 statetype s_shellydieup  = {SHELLEYL2SPR,     SHELLEYR2SPR,     step,      false, false,   8,   0, 0, T_ShellyFrag, NULL, R_Shell, NULL};\r
699 statetype s_shellyboom1  = {SHELLEYBOOM1SPR,  SHELLEYBOOM1SPR,  step,      false, false,  20,   0, 0, NULL, C_Lethal, R_Draw, &s_shellyboom2};\r
700 statetype s_shellyboom2  = {SHELLEYBOOM2SPR,  SHELLEYBOOM2SPR,  step,      false, false,  20,   0, 0, NULL, C_Lethal, R_Draw, &s_shellyboom3};\r
701 statetype s_shellyboom3  = {SHELLEYBOOM3SPR,  SHELLEYBOOM3SPR,  step,      false, false,  20,   0, 0, NULL, C_Lethal, R_Draw, &s_shellyboom4};\r
702 statetype s_shellyboom4  = {SHELLEYBOOM4SPR,  SHELLEYBOOM4SPR,  step,      false, false,  20,   0, 0, NULL, C_Lethal, R_Draw, NULL};\r
703 statetype s_shellypiece1 = {SHELLEYPIECE1SPR, SHELLEYPIECE1SPR, think,     false, false,   8,   0, 0, T_Projectile, C_Lethal, R_Bounce, NULL};\r
704 statetype s_shellypiece2 = {SHELLEYPIECE2SPR, SHELLEYPIECE2SPR, think,     false, false,   8,   0, 0, T_Projectile, C_Lethal, R_Bounce, NULL};\r
705 \r
706 /*\r
707 ===========================\r
708 =\r
709 = SpawnShelly\r
710 =\r
711 ===========================\r
712 */\r
713 \r
714 void SpawnShelly(Uint16 tileX, Uint16 tileY)\r
715 {\r
716         GetNewObj(false);\r
717         new->obclass = sparkyobj;       // BUG: should use shelleyobj\r
718         new->active = ac_yes;\r
719         new->priority = 0;\r
720         new->x = CONVERT_TILE_TO_GLOBAL(tileX);\r
721         new->y = CONVERT_TILE_TO_GLOBAL(tileY);\r
722         if (US_RndT() < 0x80)\r
723         {\r
724                 new->xdir = 1;\r
725         }\r
726         else\r
727         {\r
728                 new->xdir = -1;\r
729         }\r
730         new->ydir = 1;\r
731         NewState(new, &s_shellywalk1);\r
732 }\r
733 \r
734 /*\r
735 ===========================\r
736 =\r
737 = T_ShellyLook\r
738 =\r
739 ===========================\r
740 */\r
741 \r
742 void T_ShellyLook(objtype *ob)\r
743 {\r
744         Sint16 xdist;\r
745 \r
746         if (player->top < ob->bottom)\r
747                 return;\r
748 \r
749         xdist = player->midx - ob->midx;\r
750         if (ob->xdir == 1)\r
751         {\r
752                 if (xdist > 1*TILEGLOBAL && xdist < 3*TILEGLOBAL)\r
753                 {\r
754                         ob->xspeed = 16;\r
755                         ob->yspeed = -24;\r
756                         ob->state = &s_shellyjump1;\r
757                         xtry = ytry = 0;\r
758                 }\r
759         }\r
760         else\r
761         {\r
762                 if (xdist < -1*TILEGLOBAL && xdist > -3*TILEGLOBAL)\r
763                 {\r
764                         ob->xspeed = -16;\r
765                         ob->yspeed = -24;\r
766                         ob->state = &s_shellyjump1;\r
767                         xtry = ytry = 0;\r
768                 }\r
769         }\r
770 }\r
771 \r
772 /*\r
773 ===========================\r
774 =\r
775 = T_Turn\r
776 =\r
777 ===========================\r
778 */\r
779 \r
780 void T_Turn(objtype *ob)\r
781 {\r
782         ob->xdir = -ob->xdir;\r
783 }\r
784 \r
785 /*\r
786 ===========================\r
787 =\r
788 = T_ShellyFrag\r
789 =\r
790 ===========================\r
791 */\r
792 \r
793 void T_ShellyFrag(objtype *ob)\r
794 {\r
795         GetNewObj(true);\r
796         new->x = ob->x;\r
797         new->y = ob->y;\r
798         new->xspeed = 32;\r
799         new->yspeed = -24;\r
800         NewState(new, &s_shellypiece1);\r
801 \r
802         GetNewObj(true);\r
803         new->x = ob->x;\r
804         new->y = ob->y;\r
805         new->xspeed = -32;\r
806         new->yspeed = -24;\r
807         NewState(new, &s_shellypiece2);\r
808 }\r
809 \r
810 /*\r
811 ===========================\r
812 =\r
813 = C_Shelly\r
814 =\r
815 ===========================\r
816 */\r
817 \r
818 void C_Shelly(objtype *ob, objtype *hit)\r
819 {\r
820         if (hit->obclass == keenobj)\r
821         {\r
822                 ClipToSpriteSide(hit, ob);\r
823                 if (player->midx < ob->left || player->midx > ob->right)\r
824                         return;\r
825         }\r
826         else if (hit->obclass == stunshotobj)\r
827         {\r
828                 ExplodeShot(hit);\r
829         }\r
830         else if (hit->obclass == mshotobj)\r
831         {\r
832                 RemoveObj(hit);\r
833         }\r
834         else\r
835                 return;\r
836 \r
837 explode:\r
838         SD_PlaySound(SND_SHELLEYEXPLODE);\r
839         if (ob->hitnorth)\r
840         {\r
841                 ChangeState(ob, &s_shellydieup);\r
842         }\r
843         else\r
844         {\r
845                 ChangeState(ob, &s_shellydie);\r
846         }\r
847         GetNewObj(true);\r
848         new->x = ob->x;\r
849         new->y = ob->y;\r
850         NewState(new, &s_shellyboom1);\r
851 }\r
852 \r
853 /*\r
854 ===========================\r
855 =\r
856 = R_Shelly\r
857 =\r
858 ===========================\r
859 */\r
860 \r
861 void R_Shelly(objtype *ob)\r
862 {\r
863         if (ob->xdir == 1 && ob->hitwest)\r
864         {\r
865                 ob->x -= ob->xmove;\r
866                 ob->xdir = -1;\r
867         }\r
868         else if (ob->xdir == -1 && ob->hiteast)\r
869         {\r
870                 ob->x -= ob->xmove;\r
871                 ob->xdir = 1;\r
872         }\r
873         else if (!ob->hitnorth)\r
874         {\r
875                 ob->x -= ob->xmove;\r
876                 ChangeState(ob, &s_shellylook);\r
877         }\r
878         RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
879 }\r
880 \r
881 /*\r
882 ===========================\r
883 =\r
884 = R_Shell\r
885 =\r
886 ===========================\r
887 */\r
888 \r
889 void R_Shell(objtype *ob)\r
890 {\r
891         if (ob->hiteast || ob->hitwest)\r
892         {\r
893                 ob->xspeed = 0;\r
894         }\r
895         if (ob->hitnorth)\r
896         {\r
897                 SD_PlaySound(SND_SHELLEYEXPLODE);\r
898                 ChangeState(ob, &s_shellydie);\r
899 \r
900                 GetNewObj(true);\r
901                 new->x = ob->x;\r
902                 new->y = ob->y;\r
903                 NewState(new, &s_shellyboom1);\r
904         }\r
905         RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
906 }