1 /*
2 Copyright (C) 1994-1995 Apogee Software, Ltd.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20
21
22 #include <string.h>
23 #include <stdlib.h>
24 #include "rt_def.h"
25 #include "rt_sound.h"
26 #include "rt_door.h"
27 #include "rt_ted.h"
28 #include "rt_draw.h"
29 #include "watcom.h"
30 #include "z_zone.h"
31 #include "w_wad.h"
32 #include "lumpy.h"
33 #include "gmove.h"
34 #include "states.h"
35 #include "rt_sqrt.h"
36 #include "rt_stat.h"
37 #include "sprites.h"
38 #include "rt_actor.h"
39 #include "rt_game.h"
40 #include "rt_main.h"
41 #include "rt_playr.h"
42 #include "rt_util.h"
43 #include "rt_rand.h"
44 #include "rt_menu.h"
45 #include "rt_swift.h"
46 #include "_rt_acto.h"
47 #include "rt_cfg.h"
48 #include "rt_floor.h"
49 #include "engine.h"
50 #include "develop.h"
51 #include "rt_view.h"
52 #include "isr.h"
53 #include "rt_com.h"
54 #include "rt_scale.h"
55 #include "modexlib.h"
56 #include "rt_net.h"
57 #include "rt_msg.h"
58 #include "fx_man.h"
59 //MED
60 #include "memcheck.h"
61
62
63
64
65 #define SGN(x) (((x) > 0)?(1):(-1))
66
67
68
69 #define WILEYBLITZCHANCE 20
70 #define GIBSOUND SD_GIBSPLASHSND
71 #define ACTORTHUDSND SD_BODYLANDSND
72 #define ACTORLANDSND SD_PLAYERLANDSND
73
74 //========================== Global Variables ===================================================
75
76 #define SHP(difficulty,ob) (starthitpoints[difficulty][ob->obclass])
77
78 #define CAP_OSCUROS_HITPOINTS(ob) \
79 { \
80 if (ob->hitpoints > (SHP(gamestate.difficulty,ob)<<1)) \
81 ob->hitpoints = (SHP(gamestate.difficulty,ob)<<1); \
82 }
83
84
85 boolean ludicrousgibs=false;
86
87 short colheight[15];
88
89 byte deathshapeoffset[8] = {0,7,7,8,8,9,8,7};
90
91 unsigned MAXFUNCTION,MINFUNCTION,MAXSTATE,MINSTATE;
92
93 objtype *PLAYER0MISSILE;
94 objtype *SCREENEYE;
95 objtype *FIRSTACTOR,*LASTACTOR;
96
97 objtype *FIRSTFREE,*LASTFREE;
98 objtype *lastactive,*firstactive,**objlist;
99 objtype *firstareaactor[NUMAREAS+1],*lastareaactor[NUMAREAS+1];
100 int objcount;
101
102 byte RANDOMACTORTYPE[10];
103
104 #if (SHAREWARE == 0)
105 _2Dpoint SNAKEPATH[512];
106 #endif
107 misc_stuff mstruct,*MISCVARS = &mstruct;
108 int angletodir[ANGLES];
109 objtype *new;
110
111 void *actorat[MAPSIZE][MAPSIZE];
112 #if (DEVELOPMENT == 1)
113 FILE * williamdebug;
114 #endif
115 exit_t playstate;
116
117 void T_SlideDownScreen(objtype*);
118
119 basic_actor_sounds BAS[NUMCLASSES+3] =
120 {{0,0,0,0,0},
121 {0,0,0,0,0},
122 {0,SD_LOWGUARD1SEESND,SD_LOWGUARDFIRESND,SD_LOWGUARDOUCHSND,SD_LOWGUARD1DIESND},
123 {0,SD_HIGHGUARD1SEESND,SD_HIGHGUARDFIRESND,SD_HIGHGUARDOUCHSND,SD_HIGHGUARDDIESND},
124 {0,SD_OVERP1SEESND,SD_OVERPFIRESND,SD_OVERPOUCHSND,SD_OVERPDIESND},
125 {0,SD_STRIKE1SEESND,SD_STRIKEFIRESND,SD_STRIKEOUCHSND,SD_STRIKEDIESND},
126 {0,SD_BLITZ1SEESND,SD_BLITZFIRESND,SD_BLITZOUCHSND,SD_BLITZDIESND},
127 {0,SD_ENFORCERSEESND,SD_ENFORCERFIRESND,SD_ENFORCEROUCHSND,SD_ENFORCERDIESND} ,
128 {0,SD_MONKSEESND,SD_MONKGRABSND,SD_MONKOUCHSND,SD_MONKDIESND},
129 {0,SD_FIREMONKSEESND,SD_FIREMONKFIRESND,SD_FIREMONKOUCHSND,SD_FIREMONKDIESND},
130 {0,SD_ROBOTSEESND,SD_ROBOTFIRESND,0,SD_ROBOTDIESND},
131
132 //bosses
133 {SD_DARIANSAY1,SD_DARIANSEESND,SD_DARIANFIRESND,0,SD_DARIANDIESND},
134 {SD_KRISTSAY1,SD_KRISTSEESND,SD_KRISTFIRESND,0,SD_KRISTDIESND},
135 {0,SD_NMESEESND,SD_NMEFIRE1SND,0,SD_NMEDIESND},
136 {SD_DARKMONKSAY1,SD_DARKMONKSEESND,SD_DARKMONKFIRE1SND,0,SD_DARKMONKDIESND},
137 {SD_SNAKESAY1,SD_SNAKESEESND,SD_SNAKESPITSND,0,SD_SNAKEDIESND},
138
139 //specials
140 {0,SD_EMPLACEMENTSEESND,SD_EMPLACEMENTFIRESND,0,0},
141 {0,SD_ROBOTSEESND,SD_ROBOTFIRESND,0,SD_ROBOTDIESND}, //wallop
142 {0,0,0,0,0}, //pillar
143 {SD_FIREJETSND,0,0,0,0}, //firejet
144 {SD_BLADESPINSND,0,0,0,0}, //blade
145 {SD_CYLINDERMOVESND,0,0,0,0}, //crushcol
146 {SD_BOULDERROLLSND,0,0,SD_BOULDERHITSND,0}, //boulder
147 {SD_SPEARSTABSND,0,0,0,0}, //spear
148 {0,0,0,0,0}, //gasgrate
149 {SD_SPRINGBOARDSND,0,0,0,0}, //spring
150 {0,0,0,0,0}, //shuriken
151 {SD_FIREBALLSND,0,0,SD_FIREBALLHITSND,0}, //wallfire
152 {0,0,0,0,0}, //net
153 {SD_KRISTMINEBEEPSND,0,0,0,0}, //h_mine
154 {0,0,0,0,0}, //grenade
155 {0,0,0,0,0}, //fireball
156 {0,0,0,0,0}, //dmfball
157 {0,0,0,0,0}, //bigshuriken
158 {0,0,0,0,0}, //missile
159 {0,0,0,0,0}, //NMEsaucer
160 {0,0,0,0,0}, //dm_weapon
161 {0,0,0,0,0}, //dm_heatseek
162 {0,0,0,0,0}, //dm_spit
163 {SD_MISSILEFLYSND,0,SD_BAZOOKAFIRESND,SD_MISSILEHITSND,0},
164 {SD_MISSILEFLYSND,0,SD_FIREBOMBFIRESND,SD_MISSILEHITSND,0},
165 {SD_MISSILEFLYSND,0,SD_HEATSEEKFIRESND,SD_MISSILEHITSND,0},
166 {SD_MISSILEFLYSND,0,SD_DRUNKFIRESND,SD_MISSILEHITSND,0},
167 {SD_FLAMEWALLSND,0,SD_FLAMEWALLFIRESND,SD_FIREHITSND,0},
168 {SD_MISSILEFLYSND,0,SD_SPLITFIRESND,SD_MISSILEHITSND,0},
169 {SD_GRAVSND,0,SD_GRAVFIRESND,SD_GRAVHITSND,0},
170 {SD_GRAVSND,0,SD_GODMODEFIRESND,SD_GRAVHITSND,0}
171
172 };
173
174
175 //========================== Local Variables ==================================================
176
177 extern boolean dopefish;
178
179
180 boolean Masterdisk;
181
182 static objtype *SNAKEHEAD,*SNAKEEND,*PARTICLE_GENERATOR,*EXPLOSIONS;
183 #if (SHAREWARE == 0)
184 static int OLDTILEX,OLDTILEY;
185 #endif
186
187
188 static char *debugstr[] = {
189
190 "inerttype",
191 "player",
192 "lowguard",
193 "highguard",
194 "overpatrol",
195 "strikeguard",
196 "blitzguard",
197 "triadenforcer",
198 "deathmonk",
199 "dfiremonk",
200 "roboguard",
201 "b_darian",
202 "b_heinrich",
203 "b_darkmonk",
204 "b_roboboss",
205 "b_darksnake",
206 "patrolgun",
207 "wallop",
208 "pillar",
209 "firejet",
210 "blade",
211 "crushcol",
212 "boulder",
213 "spear",
214 "gasgrate",
215 "spring",
216 "shuriken",
217 "wallfire",
218 "net",
219 "h_mine",
220 "grenade",
221 "fireball",
222 "dmfball",
223 "bigshuriken",
224 "missile",
225 "NMEsaucer",
226 "dm_weapon",
227 "dm_heatseek",
228 "dm_spit",
229 "p_bazooka",
230 "p_firebomb",
231 "p_heatseek",
232 "p_drunkmissile",
233 "p_firewall",
234 "p_splitmissile",
235 "p_kes",
236 "p_godball",
237 "collectorobj"
238 };
239
240
241
242
243
244
245
246 static int starthitpoints[4][NUMENEMIES+2] =
247
248 {{0,0,30,35,50,40,45,425,200,200,100,1500,2500,3000,3000,-1,200,2},
249 {0,0,40,50,55,50,50,475,250,250,125,2300,3400,4500,3600,-1,250,2},
250 {0,0,50,65,60,60,60,525,275,300,150,2400,3600,5000,4500,-1,300,2},
251 {0,0,60,80,70,70,75,525,300,350,175,2800,3800,5900,4800,-1,350,2}};
252
253
254 static statobj_t *touchsprite;
255
256
257 static const byte dirdiff[8][8] = {{0,1,2,3,4,3,2,1},{1,0,1,2,3,4,3,2},
258 {2,1,0,1,2,3,4,3},{3,2,1,0,1,2,3,4},
259 {4,3,2,1,0,1,2,3},{3,4,3,2,1,0,1,2},
260 {2,3,4,3,2,1,0,1},{1,2,3,4,3,2,1,0}};
261
262 static const byte dirorder[8][2] = {{southeast,northeast},{east,north},
263 {northeast,northwest},{north,west},
264 {northwest,southwest},{west,south},
265 {southwest,southeast},{south,east}};
266
267 #if (SHAREWARE == 0)
268
269 static const byte dirdiff16[16][16] = {
270 {0,1,2,3,4,5,6,7,8,7,6,5,4,3,2,1},
271 {1,0,1,2,3,4,5,6,7,8,7,6,5,4,3,2},
272 {2,1,0,1,2,3,4,5,6,7,8,7,6,5,4,3},
273 {3,2,1,0,1,2,3,4,5,6,7,8,7,6,5,4},
274 {4,3,2,1,0,1,2,3,4,5,6,7,8,7,6,5},
275 {5,4,3,2,1,0,1,2,3,4,5,6,7,8,7,6},
276 {6,5,4,3,2,1,0,1,2,3,4,5,6,7,8,7},
277 {7,6,5,4,3,2,1,0,1,2,3,4,5,6,7,8},
278 {8,7,6,5,4,3,2,1,0,1,2,3,4,5,6,7},
279 {7,8,7,6,5,4,3,2,1,0,1,2,3,4,5,6},
280 {6,7,8,7,6,5,4,3,2,1,0,1,2,3,4,5},
281 {5,6,7,8,7,6,5,4,3,2,1,0,1,2,3,4},
282 {4,5,6,7,8,7,6,5,4,3,2,1,0,1,2,3},
283 {3,4,5,6,7,8,7,6,5,4,3,2,1,0,1,2},
284 {2,3,4,5,6,7,8,7,6,5,4,3,2,1,0,1},
285 {1,2,3,4,5,6,7,8,7,6,5,4,3,2,1,0}};
286 #endif
287
288 static const byte dirorder16[16][2] = {
289 {15,1} , {0,2}, {1,3}, {2,4},
290 {3,5} , {4,6}, {5,7}, {6,8},
291 {7,9} , {8,10}, {9,11}, {10,12},
292 {11,13}, {12,14}, {13,15}, {14,0}};
293
294 //static byte opposite16[16] = {8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7};
295
296 #if (SHAREWARE == 0)
297
298 static statetype * UPDATE_STATES[NUMSTATES][NUMENEMIES] =
299
300 { {&s_lowgrdstand,&s_highgrdstand,&s_opstand,&s_strikestand,
301 &s_blitzstand,&s_enforcerstand,&s_dmonkstand,&s_firemonkstand,
302 &s_robogrdstand,&s_darianstand,&s_heinrichstand,NULL,
303 &s_darkmonkstand,NULL,&s_gunstand,&s_wallstand},
304
305 {&s_lowgrdpath1,&s_highgrdpath1,&s_oppath1,&s_strikepath1,
306 &s_blitzpath1,&s_enforcerpath1,&s_dmonkpath1,&s_firemonkpath1,
307 &s_robogrdpath1,NULL,NULL,NULL,
308 NULL,NULL,NULL,&s_wallpath},
309
310 {&s_lowgrdcollide,&s_highgrdcollide,&s_opcollide,&s_strikecollide,
311 &s_blitzcollide,&s_enforcercollide,&s_dmonkcollide,&s_firemonkcollide,
312 &s_robogrdcollide,&s_dariancollide,NULL,NULL,
313 NULL,NULL,NULL,&s_wallcollide},
314
315 {&s_lowgrdcollide2,&s_highgrdcollide2,&s_opcollide2,&s_strikecollide2,
316 &s_blitzcollide2,&s_enforcercollide2,&s_dmonkcollide2,&s_firemonkcollide2,
317 &s_robogrdcollide2,&s_dariancollide2,NULL,NULL,
318 NULL,NULL,NULL,&s_wallcollide},
319
320 {&s_lowgrdchase1,&s_highgrdchase1,&s_opchase1,&s_strikechase1,
321 &s_blitzchase1,&s_enforcerchase1,&s_dmonkchase1,&s_firemonkchase1,
322 NULL/*se1*/,&s_darianchase1,&s_heinrichchase,&s_NMEchase,
323 &s_darkmonkchase1,NULL,&s_gunstand,&s_wallpath},
324
325 /*
326 {&s_lowgrduse1,&s_highgrduse1,&s_opuse1,&s_strikeuse1,
327 &s_blitzuse,&s_enforceruse1,NULL,NULL,
328 NULL,&s_darianuse1,NULL,NULL,
329 NULL,NULL,NULL,NULL},*/
330 {0},
331
332 {&s_lowgrdshoot1,&s_highgrdshoot1,&s_opshoot1,&s_strikeshoot1,
333 &s_blitzshoot1,&s_enforcershoot1,NULL,&s_firemonkcast1,
334 &s_robogrdshoot1,&s_darianshoot1,&s_heinrichshoot1,NULL,
335 NULL,NULL,&s_gunfire1,&s_wallshoot},
336
337 {&s_lowgrddie1,&s_highgrddie1,&s_opdie1,&s_strikedie1,
338 &s_blitzdie1,&s_enforcerdie1,&s_dmonkdie1,&s_firemonkdie1,
339 &s_robogrddie1,&s_dariandie1,&s_heinrichdie1,&s_NMEdie,
340 &s_darkmonkdie1,NULL,&s_gundie1,NULL},
341
342 {0},
343
344 {NULL,NULL,NULL,&s_strikewait,
345 &s_blitzstand,&s_enforcerdie1,&s_dmonkdie1,&s_firemonkdie1,
346 &s_robogrddie1,&s_dariandie1,&s_heinrichdie1,NULL,
347 &s_darkmonkdie1,NULL,NULL,NULL},
348
349 {&s_lowgrdcrushed1,&s_highgrdcrushed1,&s_opcrushed1,&s_strikecrushed1,
350 &s_blitzcrushed1,&s_enforcercrushed1,&s_dmonkcrushed1,&s_firemonkcrushed1,
351 &s_robogrddie1,NULL,NULL,NULL,
352 NULL,NULL,NULL,NULL}
353
354 };
355
356 #else
357
358 static statetype * UPDATE_STATES[NUMSTATES][NUMENEMIES] =
359
360 { {&s_lowgrdstand,&s_highgrdstand,NULL,&s_strikestand,
361 &s_blitzstand,&s_enforcerstand,NULL,NULL,
362 &s_robogrdstand,NULL,NULL,NULL,
363 NULL,NULL,NULL,NULL},
364
365 {&s_lowgrdpath1,&s_highgrdpath1,NULL,&s_strikepath1,
366 &s_blitzpath1,&s_enforcerpath1,NULL,NULL,
367 &s_robogrdpath1,NULL,NULL,NULL,
368 NULL,NULL,NULL,NULL},
369
370 {&s_lowgrdcollide,&s_highgrdcollide,NULL,&s_strikecollide,
371 &s_blitzcollide,&s_enforcercollide,NULL,NULL,
372 NULL,NULL,NULL,NULL,
373 NULL,NULL,NULL,NULL},
374
375 {&s_lowgrdcollide2,&s_highgrdcollide2,NULL,&s_strikecollide2,
376 &s_blitzcollide2,&s_enforcercollide2,NULL,NULL,
377 &s_robogrdcollide2,NULL,NULL,NULL,
378 NULL,NULL,NULL,NULL},
379
380 {&s_lowgrdchase1,&s_highgrdchase1,NULL,&s_strikechase1,
381 &s_blitzchase1,&s_enforcerchase1,NULL,NULL,
382 NULL,NULL,NULL,NULL,
383 NULL,NULL,NULL,NULL},
384
385 /*
386 {&s_lowgrduse1,&s_highgrduse1,&s_opuse1,&s_strikeuse1,
387 &s_blitzuse,&s_enforceruse1,NULL,NULL,
388 NULL,&s_darianuse1,NULL,NULL,
389 NULL,NULL,NULL,NULL},*/
390 {0},
391
392 {&s_lowgrdshoot1,&s_highgrdshoot1,NULL,&s_strikeshoot1,
393 &s_blitzshoot1,&s_enforcershoot1,NULL,NULL,
394 &s_robogrdshoot1,NULL,NULL,NULL,
395 NULL,NULL,NULL,NULL},
396
397 {&s_lowgrddie1,&s_highgrddie1,NULL,&s_strikedie1,
398 &s_blitzdie1,&s_enforcerdie1,NULL,NULL,
399 &s_robogrddie1,NULL,NULL,NULL,
400 NULL,NULL,NULL,NULL},
401
402 {0},
403
404 {NULL,NULL,NULL,&s_strikewait,
405 &s_blitzstand,&s_enforcerdie1,NULL,NULL,
406 &s_robogrddie1,NULL,NULL,NULL,
407 NULL,NULL,NULL,NULL},
408
409 {&s_lowgrdcrushed1,&s_highgrdcrushed1,NULL,&s_strikecrushed1,
410 &s_blitzcrushed1,&s_enforcercrushed1,NULL,NULL,
411 &s_robogrddie1,NULL,NULL,NULL,
412 NULL,NULL,NULL,NULL}
413
414 };
415
416 #endif
417
418
419
420 #define TABLE_ACTOR(ob) ((ob->obclass >= lowguardobj) && (ob->obclass <= wallopobj))
421
422
423 void T_Reset(objtype*ob);
424 void ApplyGravity(objtype *ob);
425 void BeginEnemyHurt(objtype *ob);
426 void T_PlayDead(objtype *ob);
427 void SpawnFirewall(objtype*ob,int which,int newz);
428 void SelectKristChaseDir(objtype*ob);
429 void ExplodeStatic(statobj_t*tempstat);
430 void AvoidPlayerMissile(objtype*ob);
431 int EnvironmentDamage(objtype *ob);
432
433 int STOPSPEED = 0x200;
434 static int PLAYERFRICTION = 0xe000;
435 static int ACTORFRICTION = 0xf000;
436 static int DIAGADJUST = 0xb504;
437 static boolean MissileSound = true;
438
439
440
441
FirstExplosionState(statetype * state)442 boolean FirstExplosionState(statetype *state)
443 {
444 if (DoPanicMapping())
445 {
446 if (state == &s_altexplosion1)
447 return true;
448 else
449 return false;
450 }
451 else
452 {
453 if ((state == &s_explosion1) ||
454 (state == &s_grexplosion1) ||
455 (state == &s_staticexplosion1)
456 )
457 return true;
458 else
459 return false;
460 }
461
462 }
463
464
465
466
467
SetGibSpeed(int speed)468 void SetGibSpeed(int speed)
469 {
470 MISCVARS->gibspeed = speed;
471 }
472
ResetGibSpeed(void)473 void ResetGibSpeed(void)
474 {
475 MISCVARS->gibspeed = NORMALGIBSPEED;
476 }
477
ValidAreanumber(int areanumber)478 int ValidAreanumber (int areanumber)
479 { if ((areanumber >=0) && (areanumber <= NUMAREAS))
480 return 1;
481 return 0;
482 }
483
GetIndexForState(statetype * state)484 int GetIndexForState (statetype * state)
485 {
486 int i;
487
488 if (state == NULL)
489 return -1;
490
491 for (i=0;i<MAXSTATES;i++)
492 {
493 if (statetable[i]==state)
494 return i;
495 }
496 Error("Cannot find the state in 'GetIndexForState', state->shapenum = %d\n",state->shapenum);
497 return -1;
498 }
499
500
501
GetStateForIndex(int index)502 statetype * GetStateForIndex (int index)
503 {
504 if (index == -1)
505 return NULL;
506
507 return statetable[index];
508 }
509
510
GetStaticForIndex(int index)511 statobj_t* GetStaticForIndex(int index)
512 {statobj_t* temp;
513
514 for(temp=FIRSTSTAT;temp;temp=temp->statnext)
515 if (index == temp->whichstat)
516 return temp;
517
518 Error("Cannot find the static in 'GetStaticForIndex', statindex %d\n",index);
519 return NULL;
520
521 }
522
523
524
SaveActors(byte ** buffer,int * size)525 void SaveActors(byte **buffer,int*size)
526 {objtype*temp,*tact;
527 saved_actor_type dummy;
528 byte*tptr;
529 int actorcount;
530
531
532 for(actorcount=0,temp=FIRSTACTOR;temp;temp=temp->next)
533 temp->whichactor = actorcount++;
534
535
536
537 *size = sizeof(int) + sizeof(numplayers) + sizeof(misc_stuff) + objcount*sizeof(saved_actor_type);
538 *buffer = (byte*)SafeMalloc(*size);
539 tptr = *buffer;
540
541 memcpy(tptr,MISCVARS,sizeof(misc_stuff));
542 tptr += sizeof(misc_stuff);
543
544 memcpy(tptr,&numplayers,sizeof(numplayers));
545 tptr += sizeof(numplayers);
546
547 memcpy(tptr,&consoleplayer,sizeof(consoleplayer));
548 tptr += sizeof(consoleplayer);
549
550 for(temp=FIRSTACTOR;temp;temp=temp->next)
551 {dummy.x = temp->x;
552 dummy.y = temp->y;
553 dummy.z = temp->z;
554 dummy.flags = temp->flags;
555 dummy.areanumber = temp->areanumber;
556 //dummy.whichactor = temp->whichactor;
557 dummy.hitpoints = temp->hitpoints;
558 dummy.ticcount = temp->ticcount;
559 dummy.obclass = (byte)(temp->obclass);
560 dummy.stateindex = GetIndexForState(temp->state);
561 dummy.shapeoffset = temp->shapeoffset;
562 dummy.dirchoosetime = temp->dirchoosetime;
563 dummy.door_to_open = temp->door_to_open;
564 dummy.targetx = temp->targettilex;
565 dummy.targety = temp->targettiley;
566 dummy.dir = (signed char)temp->dir;
567 dummy.angle = temp->angle;
568 dummy.yzangle = temp->yzangle;
569 dummy.speed = temp->speed;
570 dummy.momentumx = temp->momentumx;
571 dummy.momentumy = temp->momentumy;
572 dummy.momentumz = temp->momentumz;
573
574 dummy.temp1 = temp->temp1;
575 dummy.temp2 = temp->temp2;
576 dummy.temp3 = temp->temp3;
577 if (temp->whatever)
578 {/*if ((temp->flags & FL_USE) && (temp!=player))
579 {dummy.whateverindex = (GetIndexForState((statetype*)(temp->whatever))|SG_PSTATE);
580 if ((dummy.whateverindex < 0) && (dummy.whateverindex != -1))
581 Error("Bad actor whatever save value of %d\n",dummy.whateverindex);
582 }
583 else*/
584 {tact = (objtype*)(temp->whatever);
585 if (tact->which == ACTOR)
586 dummy.whateverindex = tact->whichactor;
587 else
588 {statobj_t *tstat;
589
590 tstat = (statobj_t*)(temp->whatever);
591 dummy.whateverindex = (tstat->whichstat|SG_PSTAT);
592
593 }
594 }
595 }
596 else
597 dummy.whateverindex = -1;
598
599
600 if (temp->target)
601 {tact = (objtype*)(temp->target);
602 if (tact->which == ACTOR)
603 {dummy.targetindex = tact->whichactor;
604 Debug("\nsave actor %d, type %d has target %d",temp->whichactor,temp->obclass,tact->whichactor);
605 }
606 else if (tact->which == SPRITE)
607 {statobj_t *tstat;
608
609 tstat = (statobj_t*)(temp->target);
610 dummy.targetindex = (tstat->whichstat|SG_PSTAT);
611 }
612 else // It must be a push wall, and we don't save that
613 dummy.targetindex=-1;
614 }
615 else
616 dummy.targetindex = -1;
617
618
619 memcpy(tptr,&(dummy.x),sizeof(saved_actor_type));
620 tptr += sizeof(saved_actor_type);
621
622 }
623
624 }
625
626
627
LoadActors(byte * buffer,int size)628 void LoadActors(byte *buffer,int size)
629 {
630 int numactors,i,playerindex;
631 saved_actor_type dummy;
632 objtype *temp;
633 short *targetindices,*whateverindices;
634
635 InitActorList();
636
637 memcpy(MISCVARS,buffer,sizeof(misc_stuff));
638 buffer += sizeof(misc_stuff);
639
640 memcpy(&numplayers,buffer,sizeof(numplayers));
641 buffer += sizeof(numplayers);
642
643 memcpy(&playerindex,buffer,sizeof(playerindex));
644 buffer += sizeof(playerindex);
645
646 size -= (sizeof(misc_stuff)+sizeof(numplayers)+sizeof(playerindex));
647 numactors = size/sizeof(saved_actor_type);
648
649
650 objlist = (objtype**)SafeMalloc(numactors*sizeof(objtype*));
651 targetindices = (short*)SafeMalloc(numactors*sizeof(short));
652 whateverindices = (short*)SafeMalloc(numactors*sizeof(short));
653
654 for(i=0;i<numactors;i++)
655 {
656 targetindices[i] = 0;
657 whateverindices[i] = 0;
658 objlist[i] = NULL;
659 }
660
661
662 for(i=0;i<numactors;i++)
663 {
664 GetNewActor();
665 objlist[i] = new;
666 if (i < numplayers)
667 {
668 PLAYER[i]=new;
669 if (i==playerindex)
670 player=new;
671 }
672
673 memcpy(&(dummy.x),buffer,sizeof(saved_actor_type));
674
675 //new->x = dummy.x;
676 //new->y = dummy.y;
677 SetFinePosition(new,dummy.x,dummy.y);
678 SetVisiblePosition(new,dummy.x,dummy.y);
679 new->z = dummy.z;
680 new->flags = dummy.flags;
681 new->hitpoints = dummy.hitpoints;
682 new->ticcount = dummy.ticcount;
683 new->shapeoffset = dummy.shapeoffset;
684 new->obclass = (classtype)(dummy.obclass);
685
686
687 new->state = GetStateForIndex(dummy.stateindex);
688 if (new->state == &s_superparticles)
689 PARTICLE_GENERATOR = new;
690 else if
691 (new->state->think == T_SlideDownScreen)
692 SCREENEYE = new;
693 new->dirchoosetime = dummy.dirchoosetime;
694 new->door_to_open = dummy.door_to_open;
695 new->targettilex = dummy.targetx;
696 new->targettiley = dummy.targety;
697 new->dir = (dirtype)(dummy.dir);
698 new->angle = dummy.angle;
699 new->yzangle = dummy.yzangle;
700 new->speed = dummy.speed;
701 new->momentumx = dummy.momentumx;
702 new->momentumy = dummy.momentumy;
703 new->momentumz = dummy.momentumz;
704 new->temp1 = dummy.temp1;
705 new->temp2 = dummy.temp2;
706 new->temp3 = dummy.temp3;
707 if (dummy.whateverindex == -1)
708 new->whatever = NULL;
709
710 else if (dummy.whateverindex & SG_PSTAT)
711 new->whatever = GetStaticForIndex(dummy.whateverindex & ~SG_PSTAT);
712 else
713 whateverindices[i] = dummy.whateverindex+1;
714
715
716 if (dummy.targetindex == -1)
717 new->target = NULL;
718 else if (dummy.targetindex & SG_PSTAT)
719 new->target = GetStaticForIndex(dummy.targetindex & ~SG_PSTAT);
720 else
721 {
722 targetindices[i] = dummy.targetindex+1;
723 Debug("\nload actor %d, type %d has target %d",i,new->obclass,dummy.targetindex);
724 }
725
726
727 new->areanumber = dummy.areanumber;
728 new->shapenum = new->state->shapenum + new->shapeoffset;
729 new->which = ACTOR;
730 if (new->flags & FL_ABP)
731 MakeActive(new);
732 if (new->obclass != inertobj)
733 MakeLastInArea(new);
734
735 if (!(new->flags & (FL_NEVERMARK|FL_NONMARK)))
736 actorat[new->tilex][new->tiley] = new;
737
738 PreCacheActor(new->obclass,-1);
739 buffer += sizeof(saved_actor_type);
740 }
741
742
743 // find unique links between actors,
744 // searching list AFTER all have been spawned
745
746 for(i=0;i<numactors;i++)
747 {temp=objlist[i];
748 if (whateverindices[i])
749 temp->whatever = objlist[whateverindices[i]-1];
750 if (targetindices[i])
751 temp->target = objlist[targetindices[i]-1];
752 }
753
754
755 for(temp=FIRSTACTOR;temp;temp=temp->next)
756 {if (temp->obclass == b_darksnakeobj)
757 {if (!SNAKEHEAD)
758 SNAKEHEAD = temp;
759 else if (!temp->whatever)
760 SNAKEEND = temp;
761 }
762
763 }
764
765 if (SNAKEHEAD)
766 for(temp=FIRSTACTOR;temp;temp=temp->next)
767 {if (temp->state == &s_megaexplosions)
768 EXPLOSIONS = temp;
769 }
770
771 //SafeFree(objlist);
772 SafeFree(targetindices);
773 SafeFree(whateverindices);
774
775 }
776
777
778
RandomSign(void)779 int RandomSign(void)
780 {
781 if (GameRandomNumber("random sign",0) < 128)
782 return -1;
783 return 1;
784
785
786 }
787
788
AddToFreeList(objtype * ob)789 void AddToFreeList(objtype*ob)
790 { if (!FIRSTFREE)
791 FIRSTFREE = ob;
792 else
793 {ob->prev = LASTFREE;
794 LASTFREE->next = ob;
795 }
796 LASTFREE = ob;
797
798 }
799
RemoveFromFreeList(objtype * ob)800 void RemoveFromFreeList(objtype*ob)
801 {
802 if (ob == LASTFREE)
803 LASTFREE = ob->prev;
804 else
805 ob->next->prev = ob->prev;
806
807 if (ob == FIRSTFREE)
808 FIRSTFREE = ob->next;
809 else
810 ob->prev->next = ob->next;
811
812 ob->prev = NULL;
813 ob->next = NULL;
814
815 }
816
817
MakeActive(objtype * ob)818 void MakeActive(objtype *ob)
819 {if ((ob == firstactive) || (ob->prevactive) || (ob->nextactive))
820 {
821 SoftError("\ndouble make active try");
822 //AddEndGameCommand ();
823 return;
824 }
825
826 if (!firstactive)
827 firstactive = ob;
828 else
829 {ob->prevactive = lastactive;
830 lastactive->nextactive = ob;
831 }
832 lastactive = ob;
833
834 #if ((DEVELOPMENT == 1))
835 #if ((LOADSAVETEST == 1))
836 if (!lastactive)
837 Debug("\nlastactive = NULL !");
838 else
839 Debug("\nlastactive = %8x",lastactive);
840
841 #endif
842 #endif
843 }
844
845
846
MakeLastInArea(objtype * ob)847 void MakeLastInArea(objtype *ob)
848 {
849 if (!ValidAreanumber(ob->areanumber))
850 Error("\n ob type %s at %d,%d has illegal areanumber of %d",
851 debugstr[ob->obclass],ob->tilex,ob->tiley,ob->areanumber);
852
853
854 if ((ob == firstareaactor[ob->areanumber]) || (ob->previnarea) || (ob->nextinarea))
855 {
856 SoftError("\ndouble make last in area try");
857 //AddEndGameCommand ();
858 return;
859 }
860 if (!firstareaactor[ob->areanumber])
861 firstareaactor[ob->areanumber] = ob;
862 else
863 {ob->previnarea = lastareaactor[ob->areanumber];
864 lastareaactor[ob->areanumber]->nextinarea = ob;
865 }
866 lastareaactor[ob->areanumber] = ob;
867 }
868
869
870
RemoveFromArea(objtype * ob)871 void RemoveFromArea(objtype*ob)
872 {
873 if (!((ob == firstareaactor[ob->areanumber]) || (ob->previnarea) || (ob->nextinarea)))
874 {
875 SoftError("\ndouble remove from area try");
876 //AddEndGameCommand ();
877 return;
878 }
879
880 if (ob == lastareaactor[ob->areanumber]) // remove from master list
881 lastareaactor[ob->areanumber] = ob->previnarea;
882 else
883 ob->nextinarea->previnarea = ob->previnarea;
884
885 if (ob == firstareaactor[ob->areanumber])
886 firstareaactor[ob->areanumber] = ob->nextinarea;
887 else
888 ob->previnarea->nextinarea = ob->nextinarea;
889
890 ob->previnarea = NULL;
891 ob->nextinarea = NULL;
892 }
893
894
MakeInactive(objtype * ob)895 void MakeInactive(objtype*ob)
896 {
897 if (!ACTIVE(ob))
898 // if (!((ob == firstactive) || (ob->prevactive) || (ob->nextactive)))
899 {
900 SoftError("\n trying to remove inactive object");
901 //AddEndGameCommand ();
902 return;
903 }
904
905 //if (ob->flags & FL_ABP)
906 {
907
908 if (ob == lastactive) // remove from master list
909 lastactive = ob->prevactive;
910 else
911 ob->nextactive->prevactive = ob->prevactive;
912
913 if (ob == firstactive)
914 firstactive = ob->nextactive;
915 else
916 ob->prevactive->nextactive = ob->nextactive;
917
918
919 ob->prevactive = NULL;
920 ob->nextactive = NULL;
921 }
922
923 }
924
925
926
A_Steal(objtype * ob)927 void A_Steal(objtype*ob)
928 {
929 int dx,dy,dz;
930
931 ActorMovement(ob);
932
933 dx = abs(ob->x - PLAYER[0]->x);
934 dy = abs(ob->y - PLAYER[0]->y);
935 dz = abs(ob->z - PLAYER[0]->z);
936
937 if ((dx > TOUCHDIST) || (dy > TOUCHDIST) || (dz > (TOUCHDIST >> 10)))
938 {
939 NewState(ob,&s_blitzchase1);
940 return;
941 }
942
943 if (ob->ticcount)
944 return;
945
946 SD_PlaySoundRTP(SD_BLITZSTEALSND,ob->x,ob->y);
947 if (PLAYER[0]->flags & FL_GASMASK)
948 {
949 PLAYER[0]->flags &= ~FL_GASMASK;
950 PLAYERSTATE[0].protectiontime = 1;
951 ob->temp3 = stat_gasmask;
952 GM_UpdateBonus (PLAYERSTATE[0].poweruptime, true);
953
954 }
955 else if(PLAYER[0]->flags & FL_BPV)
956 {
957 PLAYER[0]->flags &= ~FL_BPV;
958 PLAYERSTATE[0].protectiontime = 1;
959 ob->temp3 = stat_bulletproof;
960 GM_UpdateBonus (PLAYERSTATE[0].poweruptime, true);
961
962 }
963 else if(PLAYER[0]->flags & FL_AV)
964 {
965 PLAYER[0]->flags &= ~FL_AV;
966 PLAYERSTATE[0].protectiontime = 1;
967 ob->temp3 = stat_asbesto;
968 GM_UpdateBonus (PLAYERSTATE[0].poweruptime, true);
969
970 }
971 else if (PLAYERSTATE[0].missileweapon != -1)
972 {
973 NewState(PLAYER[0],&s_player);
974 PLAYERSTATE[0].attackframe = PLAYERSTATE[0].weaponframe = 0;
975 PLAYERSTATE[0].new_weapon = PLAYERSTATE[0].bulletweapon;
976 ob->temp3 = GetItemForWeapon(PLAYERSTATE[0].missileweapon);
977 ob->temp2 = PLAYERSTATE[0].ammo;
978 //ob->temp1 = oldpolltime;
979 PLAYERSTATE[0].ammo = -1;
980
981 if (PLAYERSTATE[0].weapon == PLAYERSTATE[0].missileweapon)
982 PLAYERSTATE[0].weapondowntics = WEAPONS[PLAYERSTATE[0].weapon].screenheight/GMOVE;
983 PLAYERSTATE[0].missileweapon = -1;
984
985 if ( SHOW_BOTTOM_STATUS_BAR() )
986 DrawBarAmmo (false);
987
988 }
989 }
990
991
FindAddresses(void)992 void FindAddresses(void)
993 {
994 int i;
995 unsigned tstate,tfunct;
996
997 MINFUNCTION = 0xffffffff;
998 MAXFUNCTION = 0x00000000;
999 MINSTATE = 0xffffffff;
1000 MAXSTATE = 0x00000000;
1001
1002 for(i=0;i<MAXSTATES;i++)
1003 {
1004 tstate = (unsigned)(statetable[i]);
1005 if (tstate < MINSTATE)
1006 MINSTATE = tstate;
1007
1008 if (tstate > MAXSTATE)
1009 MAXSTATE = tstate;
1010 if (statetable[i]!=NULL)
1011 {
1012 tfunct = (unsigned)(statetable[i]->think);
1013 if (tfunct < MINFUNCTION)
1014 MINFUNCTION = tfunct;
1015
1016 if (tfunct > MAXFUNCTION)
1017 MAXFUNCTION = tfunct;
1018 }
1019 }
1020 }
1021
CheckBounds(objtype * ob)1022 void CheckBounds(objtype*ob)
1023 {
1024 unsigned tstate,tfunct;
1025
1026 tstate = (unsigned)(ob->state);
1027 tfunct = (unsigned)(ob->state->think);
1028
1029 if ((tfunct < MINFUNCTION) || (tfunct > MAXFUNCTION) ||
1030 (tstate < MINSTATE) || (tstate > MAXSTATE))
1031 {
1032 if (tfunct < MINFUNCTION)
1033 Error("%s has thinking function less than MINFUNCTION",debugstr[ob->obclass]);
1034
1035 else if (tfunct > MAXFUNCTION)
1036 Error("%s has thinking function greater than MAXFUNCTION",debugstr[ob->obclass]);
1037
1038 if (tstate < MINSTATE)
1039 Error("%s has state less than MINSTATE",debugstr[ob->obclass]);
1040
1041 else if (tstate > MAXSTATE)
1042 Error("%s has state greater than MAXSTATE",debugstr[ob->obclass]);
1043
1044 }
1045
1046
1047 }
1048
1049 /*************************************************************/
1050
1051
1052 /*
1053 =====================
1054 =
1055 = DoActor
1056 =
1057 =====================
1058 */
1059
DoActor(objtype * ob)1060 void DoActor (objtype *ob)
1061 {
1062 void (*think)(objtype *);
1063 int door;
1064
1065
1066 // for(i=0;i<tics;i++)
1067 // {
1068
1069
1070 ApplyGravity(ob);
1071 M_CheckDoor(ob);
1072 M_CheckBossSounds(ob);
1073 if ((ob->obclass >= b_darianobj) &&
1074 (ob->obclass < b_darksnakeobj) &&
1075 MISCVARS->REDTIME
1076 )
1077 {
1078 MISCVARS->REDTIME --;
1079 MISCVARS->redindex = (MISCVARS->REDTIME & 15);
1080 }
1081
1082 if (ob->obclass == playerobj)
1083 ControlPlayerObj(ob);
1084
1085 think = ob->state->think;
1086 if (think)
1087 {
1088 //CheckBounds(ob);
1089 think (ob);
1090
1091 if (!ob->state)
1092 {
1093 RemoveObj (ob);
1094 return;
1095 }
1096 }
1097
1098 if (ob->ticcount)
1099 ob->ticcount --;
1100
1101 else
1102 {
1103 if (!(ob->state->next))
1104 {
1105 RemoveObj (ob);
1106 return;
1107 }
1108 else
1109 NewState(ob,ob->state->next);
1110 }
1111
1112
1113 if (ob->flags&FL_NEVERMARK)
1114 return;
1115
1116 if ((ob->flags&FL_NONMARK) && actorat[ob->tilex][ob->tiley])
1117 return;
1118
1119 actorat[ob->tilex][ob->tiley] = ob;
1120 }
1121
1122
1123
1124
1125
ApplyGravity(objtype * ob)1126 void ApplyGravity(objtype *ob)
1127 {
1128 int oldmomentumz;
1129
1130 if (((ob->momentumz) || (ob->z != nominalheight)) &&
1131 (ob->obclass > playerobj) &&
1132 ((ob->obclass <= roboguardobj) || (ob->obclass == collectorobj) ||
1133 (ob->obclass == b_heinrichobj)) &&
1134 (ob->state->think != T_Stand)
1135 )
1136 {
1137 ob->z += (ob->momentumz>>16);
1138 ob->momentumz += GRAVITY;
1139 if (ob->z >= nominalheight)
1140 {
1141 ob->z = nominalheight;
1142 oldmomentumz = ob->momentumz;
1143 ob->momentumz = 0;
1144 if (oldmomentumz > 2*GRAVITY)
1145 {
1146 if (ob->flags & FL_DYING)
1147 SD_PlaySoundRTP(ACTORTHUDSND,ob->x,ob->y);
1148 else
1149 {
1150 int oldviolence = gamestate.violence;
1151
1152 SD_PlaySoundRTP(ACTORLANDSND,ob->x,ob->y);
1153 gamestate.violence = vl_low;
1154 BeginEnemyHurt(ob);
1155 gamestate.violence = oldviolence;
1156 }
1157 }
1158 if (ob->flags&FL_FALLINGOBJECT)
1159 {
1160 RemoveObj(ob);
1161 return;
1162 }
1163 }
1164 }
1165 }
1166
1167
1168
1169 /*
1170 ===================
1171 =
1172 = NewState
1173 =
1174 = Changes ob to a new state, setting ticcount to the max for that state
1175 =
1176 ===================
1177 */
1178
NewState(objtype * ob,statetype * newstate)1179 void NewState (objtype *ob, statetype *newstate)
1180 {
1181 if (DoPanicMapping() &&
1182 ((newstate == &s_explosion1) ||
1183 (newstate == &s_grexplosion1) ||
1184 (newstate == &s_staticexplosion1)
1185 )
1186 )
1187 ob->state = &s_altexplosion1;
1188 else
1189 ob->state = newstate;
1190
1191 SetVisiblePosition(ob,ob->x,ob->y);
1192 ob->ticcount = (ob->state->tictime>>1);
1193 ob->shapenum = ob->state->shapenum + ob->shapeoffset;
1194
1195 }
1196
1197
1198 /*
1199 =========================
1200 =
1201 = InitActorList
1202 =
1203 = Call to clear out the actor object lists returning them all to the free
1204 = list. Allocates a special spot for the player.
1205 =
1206 =========================
1207 */
1208
1209
1210
InitActorList(void)1211 void InitActorList (void)
1212 {
1213 //====== NETWORK STUFF =======================================
1214 memset(&DEADPLAYER[0],0,sizeof(DEADPLAYER));
1215 NUMDEAD = 0;
1216
1217
1218
1219 //======= NULLIFY GLOBAL POINTERS ============================
1220
1221 LASTACTOR=FIRSTACTOR=NULL;
1222 FIRSTFREE = LASTFREE = NULL;
1223 firstactive = lastactive = NULL;
1224 memset(firstareaactor,0,sizeof(firstareaactor));
1225 memset(lastareaactor,0,sizeof(lastareaactor));
1226 NUMSPAWNLOCATIONS = 0;
1227
1228
1229 PARTICLE_GENERATOR = NULL;
1230 EXPLOSIONS = NULL;
1231 SNAKEEND=SNAKEHEAD=NULL;
1232 SCREENEYE = NULL;
1233 PLAYER0MISSILE = NULL;
1234
1235 //============================================================
1236
1237 objcount = 0;
1238 memset(MISCVARS,0,sizeof(misc_stuff));
1239 MISCVARS->gibgravity = -1;
1240 MISCVARS->gibspeed = NORMALGIBSPEED;
1241
1242 memset(&RANDOMACTORTYPE[0],0,sizeof(RANDOMACTORTYPE));
1243 FindAddresses();
1244 MissileSound = true;
1245 Masterdisk = false;
1246
1247 }
1248
1249 //===========================================================================
1250
1251 /*
1252 =========================
1253 =
1254 = GetNewActor
1255 =
1256 = Sets the global variable new to point to a free spot in objlist.
1257 = The free spot is inserted at the end of the liked list
1258 =
1259 = When the object list is full, the caller can either have it bomb out ot
1260 = return a dummy object pointer that will never get used
1261 =
1262 =========================
1263 */
1264
GetNewActor(void)1265 void GetNewActor (void)
1266 {
1267 objtype *temp;
1268
1269 if (!FIRSTFREE)
1270 {
1271 temp = (objtype*)Z_LevelMalloc(sizeof(objtype),PU_LEVELSTRUCT,NULL);
1272 //SoftError("\nMalloc-ing actor");
1273 //if (insetupgame)
1274 // SoftError("in setup");
1275 }
1276
1277 else
1278 {
1279 temp = LASTFREE;
1280 //SoftError("\nfree actor available");
1281 RemoveFromFreeList(LASTFREE);
1282 }
1283
1284 if (temp)
1285 {
1286 new = temp;
1287 memset(new,0,sizeof(*new));
1288
1289 if (FIRSTACTOR)
1290 {
1291 new->prev = LASTACTOR;
1292 LASTACTOR->next = new;
1293 }
1294 else
1295 FIRSTACTOR = new;
1296 LASTACTOR = new;
1297
1298 new->door_to_open = -1;
1299 new->soundhandle = -1;
1300 objcount ++;
1301 }
1302 else
1303 Error("Z_LevelMalloc failed in GetNewActor");
1304 }
1305
1306
1307
1308
1309 //===========================================================================
1310
1311
1312
1313
1314 /*
1315 =========================
1316 =
1317 = RemoveObj
1318 =
1319 = Add the given object back into the free list, and unlink it from it's
1320 = neighbors
1321 =
1322 =========================
1323 */
1324
1325
RemoveObj(objtype * gone)1326 void RemoveObj (objtype *gone)
1327 {
1328 if (gone == PLAYER[0])
1329 Error ("RemoveObj: Tried to remove the player!");
1330
1331 gone->state=NULL;
1332
1333 MakeInactive(gone);
1334
1335 if (gone->obclass!=inertobj) {
1336 if (ValidAreanumber(gone->areanumber))
1337 RemoveFromArea(gone);
1338 else
1339 Error("tried to remove an instance of %s with invalid areanumber %d",debugstr[gone->obclass],gone->areanumber);
1340 }
1341
1342 if (gone == LASTACTOR)
1343 LASTACTOR = gone->prev;
1344 else
1345 gone->next->prev = gone->prev;
1346
1347 if (gone == FIRSTACTOR)
1348 FIRSTACTOR = gone->next;
1349 else
1350 gone->prev->next = gone->next;
1351
1352 if (gone == EXPLOSIONS)
1353 EXPLOSIONS = NULL;
1354 gone->next = NULL;
1355 gone->prev = NULL;
1356 // SoftError("\nremoving instance of %s",debugstr[gone->obclass]);
1357 if (actorat[gone->tilex][gone->tiley] == (void*)gone)
1358 actorat[gone->tilex][gone->tiley] = NULL;
1359
1360 gone->flags |= FL_NEVERMARK;
1361
1362 if (gone->flags & FL_TARGET)
1363 UnTargetActor(gone);
1364
1365 //Add_To_Delete_Array(gone);
1366 //Z_Free(gone);
1367 AddToFreeList(gone);
1368
1369 objcount--;
1370 }
1371
1372
1373 //============== World Physics Model Functions =========================
1374
1375
ParseMomentum(objtype * ob,int angle)1376 void ParseMomentum(objtype *ob,int angle)
1377 {
1378 ob->momentumx += FixedMul(ob->speed,costable[angle]);
1379 ob->momentumy -= FixedMul(ob->speed,sintable[angle]);
1380 }
1381
Set_3D_Momenta(objtype * ob,int speed,int theta,int phi)1382 void Set_3D_Momenta(objtype *ob, int speed, int theta, int phi)
1383 {
1384 int _2Ddiag;
1385
1386 ob->momentumz = -FixedMul(speed,sintable[phi]);
1387 _2Ddiag = FixedMul(speed,costable[phi]);
1388 ob->momentumx = FixedMul(_2Ddiag,costable[theta]);
1389 ob->momentumy = -FixedMul(_2Ddiag,sintable[theta]);
1390
1391
1392 }
1393
1394
AngleBetween(objtype * source,objtype * target)1395 int AngleBetween(objtype *source,objtype*target)
1396 {
1397 int dx,dy;
1398
1399 dx = target->x - source->x;
1400 dy = source->y - target->y;
1401 return (atan2_appx(dx,dy));
1402 }
1403
1404
GetMomenta(objtype * target,objtype * source,int * newmomx,int * newmomy,int * newmomz,int magnitude)1405 void GetMomenta(objtype *target, objtype *source, int *newmomx,
1406 int *newmomy, int *newmomz, int magnitude
1407 )
1408 {
1409 int angle,dx,dy,dz,yzangle,xydist,_2Ddiag;
1410
1411 dx = target->x - source->x;
1412 dy = source->y - target->y;
1413 dz = source->z - target->z;
1414 xydist = FindDistance(dx,dy);
1415 angle = atan2_appx(dx,dy);
1416 yzangle = atan2_appx(xydist,(dz<<10));
1417 _2Ddiag = FixedMul(magnitude,costable[yzangle]);
1418
1419 *newmomz = -FixedMul(magnitude,sintable[yzangle]);
1420 *newmomx = FixedMul(_2Ddiag,costable[angle]);
1421 *newmomy = -FixedMul(_2Ddiag,sintable[angle]);
1422 }
1423
1424 //=======================================================================
1425
1426
1427
1428
1429
SpawnNewObj(unsigned tilex,unsigned tiley,statetype * state,classtype which)1430 void SpawnNewObj (unsigned tilex, unsigned tiley, statetype *state, classtype which)
1431 {
1432 int newarea;
1433
1434 GetNewActor ();
1435 new->obclass = which;
1436 SetTilePosition(new,tilex,tiley);
1437 SetVisiblePosition(new,new->x,new->y);
1438 new->dir = nodir;
1439 new->which = ACTOR;
1440 if (FirstExplosionState(state))
1441 new->flags |= (FL_NEVERMARK|FL_NOFRICTION);
1442
1443 if ((which != inertobj) && (which != diskobj))
1444 actorat[tilex][tiley] = new;
1445
1446 newarea = AREANUMBER(tilex,tiley);
1447 if ((which <= springobj) && (which != inertobj))
1448 {
1449 if (ValidAreanumber(newarea))
1450 new->areanumber = newarea;
1451 else
1452 Error("illegal initial areanumber of %d for actor type %s"
1453 "trying to spawn at %d, %d",newarea,debugstr[which],tilex,tiley);
1454 }
1455 else
1456 new->areanumber = newarea;
1457
1458 if ((which != inertobj) && (!Masterdisk))
1459 MakeLastInArea(new);
1460 NewState(new,state);
1461 new->z = nominalheight;
1462 if (which==springobj)
1463 new->z+=2;
1464
1465 }
1466
1467
1468 //====================================================================
1469
ConsiderAlternateActor(objtype * ob,classtype which)1470 void ConsiderAlternateActor(objtype *ob,classtype which)
1471 {
1472 if (((which >= lowguardobj) && (which <= blitzguardobj)) ||
1473 (which == dfiremonkobj))
1474 {if (GameRandomNumber("SpawnStand",which) < 128)
1475 {switch(which)
1476 {case lowguardobj:
1477 ob->shapeoffset = W_GetNumForName("MARSHOO1") -
1478 W_GetNumForName("LWGSHOO1");
1479 break;
1480 case highguardobj:
1481 ob->shapeoffset = W_GetNumForName("HIGSHOO1") -
1482 W_GetNumForName("HG2SHOO1");
1483 break;
1484 case overpatrolobj:
1485 ob->shapeoffset = W_GetNumForName("PATSHOO1") -
1486 W_GetNumForName("OBPSHOO1");
1487 break;
1488 case strikeguardobj:
1489 ob->shapeoffset = W_GetNumForName("XYGSHOO1") -
1490 W_GetNumForName("ANGSHOO1");
1491 break;
1492 /*case blitzguardobj:
1493 altstartlabel = "WIGSHOO1";
1494 new->shapeoffset = 80;
1495 break;*/
1496 case dfiremonkobj:
1497 ob->shapeoffset = W_GetNumForName("MRKKSH1") -
1498 W_GetNumForName("ALLKSH1");
1499 break;
1500 default:
1501 ;
1502 }
1503 }
1504
1505 }
1506
1507 //if (new->shapeoffset)
1508 // {if (W_CheckNumForName(altstartlabel) == -1)
1509 // new->shapeoffset = 0;
1510 // }
1511
1512 }
1513
1514
1515
1516
1517
1518 /*
1519 ===================
1520 =
1521 = StandardEnemyInit
1522 =
1523 ===================
1524 */
1525
StandardEnemyInit(objtype * ob,int dir)1526 void StandardEnemyInit(objtype *ob,int dir)
1527 {
1528 int zoffset;
1529
1530 if ((ob->obclass == deathmonkobj) || (ob->obclass == dfiremonkobj))
1531 ob->temp2 = DRAINTIME;
1532
1533 else if ((ob->obclass == highguardobj) || (ob->obclass == triadenforcerobj))
1534 ob->flags |= FL_HASAUTO;
1535
1536 ob->hitpoints = starthitpoints[gamestate.difficulty][ob->obclass];
1537 ob->dir = dir*2;
1538 ob->flags |= (FL_SHOOTABLE|FL_BLOCK);
1539 ob->speed = ENEMYRUNSPEED;
1540 ob->dirchoosetime = 0;
1541 ob->door_to_open = -1;
1542
1543 zoffset = MAPSPOT(ob->tilex,ob->tiley,2);
1544 if ((zoffset&0xff00)==0xb000)
1545 Set_NewZ_to_MapValue(&(ob->z),zoffset,"standard enemy",ob->tilex,ob->tiley);
1546 else
1547 ob->z = PlatformHeight(ob->tilex,ob->tiley);
1548
1549 }
1550
1551
1552
1553
ConsiderOutfittingBlitzguard(objtype * ob)1554 void ConsiderOutfittingBlitzguard(objtype *ob)
1555 {
1556 if ((GameRandomNumber("wiley blitzguard",0) < WILEYBLITZCHANCE) &&
1557 (gamestate.difficulty >= gd_medium)
1558 )
1559 {
1560 ob->temp3 = stat_bazooka;
1561 ob->temp2 = 3;
1562 }
1563 }
1564
1565
1566
1567 /*
1568 ===============
1569 =
1570 = SpawnStand
1571 =
1572 ===============
1573 */
1574
1575
SpawnStand(classtype which,int tilex,int tiley,int dir,int ambush)1576 void SpawnStand (classtype which, int tilex, int tiley, int dir, int ambush)
1577 {statetype *temp;
1578
1579 #if (SHAREWARE == 1)
1580 switch(which)
1581 {
1582 case overpatrolobj:
1583 case wallopobj:
1584 case deathmonkobj:
1585 case dfiremonkobj:
1586 case b_darianobj:
1587 case b_heinrichobj:
1588 case b_darkmonkobj:
1589 Error("\n%s actor at %d,%d not allowed in shareware !",debugstr[which],tilex,tiley);
1590 break;
1591 default:
1592 ;
1593 }
1594
1595
1596
1597 #endif
1598
1599 if ((which == lowguardobj) && (GameRandomNumber("SpawnStand",which) < 128))
1600 which = blitzguardobj;
1601
1602
1603 if ((temp = UPDATE_STATES[STAND][which-lowguardobj]) != NULL)
1604 {
1605 SpawnNewObj(tilex,tiley,temp,which);
1606 if (!loadedgame)
1607 gamestate.killtotal++;
1608
1609
1610 if (ambush)
1611 new->flags |= FL_AMBUSH;
1612
1613
1614 #if 0
1615 #if (SUPERROTT == 1)
1616
1617 ConsiderAlternateActor(new,which);
1618
1619 #endif
1620 #endif
1621
1622 StandardEnemyInit(new,dir);
1623
1624 if (which == b_darkmonkobj)
1625 {
1626 new->flags |= (FL_NOFRICTION);//|FL_INVULNERABLE);
1627 new->speed = ENEMYRUNSPEED*2;
1628 }
1629
1630 if (which == blitzguardobj)
1631 ConsiderOutfittingBlitzguard(new);
1632
1633
1634 if ((new->obclass >= lowguardobj) && (new->obclass <= dfiremonkobj))
1635 RANDOMACTORTYPE[new->obclass]++;
1636
1637 if (MAPSPOT(tilex,tiley,2) == 0xdead)
1638 {
1639 new->flags |= FL_KEYACTOR;
1640 MISCVARS->KEYACTORSLEFT++;
1641 }
1642
1643 PreCacheActor(which,0);
1644 }
1645 //else
1646 //Error("NULL initialization error");
1647 }
1648
1649
1650
1651
1652
1653 /*
1654 ===============
1655 =
1656 = SpawnPatrol
1657 =
1658 ===============
1659 */
1660
SpawnPatrol(classtype which,int tilex,int tiley,int dir)1661 void SpawnPatrol (classtype which, int tilex, int tiley, int dir)
1662 {statetype *temp;
1663 int path=PATH;
1664 #if 0
1665 #if (SUPERROTT == 1)
1666 char *altstartlabel;
1667 #endif
1668 #endif
1669
1670
1671
1672 #if (SHAREWARE==1)
1673 switch(which)
1674 {
1675 case overpatrolobj:
1676 case wallopobj:
1677 case deathmonkobj:
1678 case dfiremonkobj:
1679 case b_darianobj:
1680 case b_heinrichobj:
1681 case b_darkmonkobj:
1682 Error("\n%s actor at %d,%d not allowed in shareware !",debugstr[which],tilex,tiley);
1683 break;
1684 default:
1685 ;
1686 }
1687
1688 #endif
1689
1690 if ((which == lowguardobj) && (GameRandomNumber("SpawnStand",which) < 128))
1691 which = blitzguardobj;
1692
1693
1694
1695
1696 if ((temp= UPDATE_STATES[path][(int)(which-lowguardobj)]) != NULL)
1697 {
1698 SpawnNewObj(tilex,tiley,temp,which);
1699
1700 if (!loadedgame)
1701 gamestate.killtotal++;
1702
1703
1704 #if 0
1705 #if (SUPERROTT == 1)
1706 ConsiderAlternateActor(new,which);
1707 #endif
1708 #endif
1709
1710 StandardEnemyInit(new,dir);
1711
1712 if ((which == wallopobj) || (which == roboguardobj))
1713 {new->flags |= FL_NOFRICTION;
1714 //new->flags &= ~FL_SHOOTABLE;
1715 new->dir <<= 1;
1716 ParseMomentum(new,dirangle16[new->dir]);
1717 }
1718 else
1719 ParseMomentum(new,dirangle8[new->dir]);
1720
1721
1722 if (which == blitzguardobj)
1723 ConsiderOutfittingBlitzguard(new);
1724
1725
1726 if (MAPSPOT(tilex,tiley,2) == 0xdead)
1727 {new->flags |= FL_KEYACTOR;
1728 MISCVARS->KEYACTORSLEFT++;
1729 }
1730
1731 PreCacheActor(which,0);
1732 }
1733
1734 }
1735
1736
1737
1738
1739 //==========================================================================
1740
1741
1742
SpawnDisk(int tilex,int tiley,int type,boolean master)1743 void SpawnDisk(int tilex, int tiley, int type, boolean master)
1744 {int zoffset;
1745
1746
1747
1748 if (master == true)
1749 {
1750 Masterdisk = true;
1751 SpawnNewObj(tilex,tiley,&s_diskmaster,diskobj);
1752 Masterdisk = false;
1753 new->flags |= FL_MASTER;
1754 new->momentumz = -(DISKMOMZ << 16);
1755 new->flags |= FL_SYNCED;
1756 new->flags |= FL_NEVERMARK;
1757 new->temp1 = 1;
1758 //RemoveFromArea(new);
1759
1760 }
1761
1762 else
1763 {
1764 if (!type)
1765 {
1766 SpawnNewObj(tilex,tiley,&s_elevdisk,diskobj);
1767 new->momentumz = -(DISKMOMZ << 16);
1768 //new->flags |= FL_SYNCED;
1769 zoffset = MAPSPOT(tilex,tiley,2);
1770 if ((zoffset&0xff00)==0xb000)
1771 Set_NewZ_to_MapValue((fixed*)(&(new->temp2)),zoffset,"elev disk",tilex,tiley);
1772 else
1773 new->temp2 = 32;
1774 new->temp1 = 1;
1775 }
1776 else
1777 {
1778 SpawnNewObj(tilex,tiley,&s_pathdisk,diskobj);
1779 zoffset = MAPSPOT(tilex,tiley,2);
1780 if ((zoffset&0xff00)==0xb000)
1781 Set_NewZ_to_MapValue((fixed*)(&(new->z)),zoffset,"path disk",tilex,tiley);
1782
1783 new->dir = (type-1) << 1;
1784 new->speed = 0x1000;
1785
1786 //ParseMomentum(new,dirangle8[new->dir]);
1787 }
1788 actorat[tilex][tiley] = NULL;
1789 new->flags |= FL_BLOCK;
1790 new->flags |= (FL_NOFRICTION|FL_ACTIVE|FL_NEVERMARK);
1791 }
1792 }
1793
1794
1795
1796
DiskAt(int tilex,int tiley)1797 objtype* DiskAt(int tilex,int tiley)
1798 {int area;
1799 objtype *temp;
1800 statobj_t *tstat;
1801
1802 area = AREANUMBER(tilex,tiley);
1803 for(temp = firstareaactor[area];temp;temp = temp->nextinarea)
1804 {if ((temp->tilex != tilex) || (temp->tiley != tiley) ||
1805 (temp->obclass != diskobj))
1806 continue;
1807 return temp;
1808
1809 }
1810
1811 for(tstat = firstactivestat;tstat;tstat = tstat->nextactive)
1812 {
1813 if ((tstat->tilex != tilex) || (tstat->tiley != tiley) ||
1814 (tstat->itemnumber != stat_disk))
1815 continue;
1816 return (objtype*)tstat;
1817 }
1818
1819
1820 return NULL;
1821
1822 }
1823
1824
SetElevatorDiskVariables(objtype * ob,int newz,int newmomentumz,int newtemp1,int newtemp3,int newdirchoose)1825 void SetElevatorDiskVariables(objtype *ob,int newz, int newmomentumz,
1826 int newtemp1,int newtemp3,int newdirchoose)
1827 {
1828 ob->z = newz;
1829 ob->momentumz = newmomentumz;
1830 ob->temp1 = newtemp1;
1831 ob->temp3 = newtemp3;
1832 ob->dirchoosetime = newdirchoose;
1833 }
1834
1835
T_ElevDisk(objtype * ob)1836 void T_ElevDisk(objtype*ob)
1837 {
1838 objtype *temp = (objtype*)(actorat[ob->tilex][ob->tiley]);
1839 objtype *master;
1840
1841 if (ob->flags & FL_MASTER)
1842 goto masterlabel;
1843
1844 master = (objtype*)(ob->target);
1845 if (!master)
1846 Error("disk without master !");
1847
1848
1849 //SoftError("\n ob->z:%d %s, master z:%d",ob->z,
1850 // (ob->flags & FL_SYNCED)?("SYNCED"):("UNSYNCED"),master->z);
1851
1852
1853 if (M_ISACTOR(temp) && (temp != ob) && (!(temp->flags & FL_DYING)))
1854 {
1855 int dz = abs(ob->z - temp->z),
1856 dx = abs(ob->x - temp->x),
1857 dy = abs(ob->y - temp->y);
1858
1859 if ((dx < 0x7000) && (dy < 0x7000) && (dz < 68) && (temp->z > ob->z))
1860 {
1861 ob->flags &= ~FL_SYNCED;
1862 return;
1863 }
1864 }
1865
1866 if (master && (!(ob->flags & FL_SYNCED)))
1867 {
1868 int dz;
1869
1870 dz = abs(master->z - ob->z);
1871 if ((dz > 0) && (dz < 8))
1872 {
1873 SetElevatorDiskVariables(ob,master->z,master->momentumz,master->temp1,
1874 master->temp3,master->dirchoosetime);
1875 ob->flags |= FL_SYNCED;
1876 //return;
1877 }
1878 return;
1879 }
1880
1881
1882 masterlabel:
1883
1884 if (ob->dirchoosetime)
1885 {
1886 ob->dirchoosetime --;
1887 return;
1888 }
1889
1890
1891 if (ob->temp1) // moving
1892 {
1893 ob->z += (ob->momentumz >> 16);
1894 if (ob->momentumz > 0) // down
1895 {
1896 if (ob->z >= nominalheight + 40 + DISKMOMZ)
1897 SetElevatorDiskVariables(ob,ob->z - (ob->momentumz>>16),0,0,0,35);
1898 }
1899 else
1900 {
1901 if (ob->z < ob->temp2) // temp2 has max height
1902 SetElevatorDiskVariables(ob,ob->z - (ob->momentumz>>16),0,0,1,35);
1903 }
1904 }
1905 else
1906 {
1907 if (ob->temp3)
1908 ob->momentumz = (DISKMOMZ << 16);
1909 else
1910 ob->momentumz = -(DISKMOMZ << 16);
1911 ob->temp1 = 1;
1912 }
1913 }
1914
1915
1916
1917
SpawnInertActor(int newx,int newy,int newz)1918 void SpawnInertActor(int newx,int newy, int newz)
1919 {
1920 GetNewActor ();
1921 MakeActive(new);
1922
1923 new->obclass = inertobj;
1924 new->which = ACTOR;
1925 SetFinePosition(new,newx,newy);
1926 SetVisiblePosition(new,new->x,new->y);
1927 new->z = newz;
1928 new->dir = 0;
1929 new->speed = 0;
1930 new->flags = (FL_NEVERMARK|FL_ABP);
1931
1932 }
1933
1934
1935
1936
1937 #if (SHAREWARE == 0)
SpawnGroundExplosion(int x,int y,int z)1938 void SpawnGroundExplosion(int x, int y, int z)
1939 {
1940 SpawnInertActor(x,y,z);
1941 NewState(new,&s_grexplosion1);
1942 new->temp2 = GameRandomNumber("SpawnGroundExplosion",0)>>2;
1943
1944 }
1945 #endif
1946
SpawnSlowParticles(int which,int numgibs,int x,int y,int z)1947 void SpawnSlowParticles(int which, int numgibs, int x,int y,int z)
1948 {objtype *prevlast,*temp;
1949 int tilex,tiley;
1950
1951 tilex = x>>16;
1952 tiley = y>>16;
1953
1954 SpawnNewObj(tilex,tiley,&s_gibs1,inertobj);
1955 SetFinePosition(new,x,y);
1956 SetVisiblePosition(new,x,y);
1957 prevlast = new;
1958 prevlast->flags |= FL_ABP;
1959 MakeActive(prevlast);
1960 SpawnParticles(new,which,numgibs);
1961
1962 for(temp = prevlast->next;temp;temp=temp->next)
1963 {temp->z = z;
1964 temp->momentumx >>= 1;
1965 temp->momentumy >>= 1;
1966 temp->momentumz >>= 1;
1967 }
1968 RemoveObj(prevlast);
1969
1970 }
1971
1972
ResolveDoorSpace(int tilex,int tiley)1973 void ResolveDoorSpace(int tilex,int tiley)
1974 {
1975 statobj_t* tstat,*temp;
1976
1977 for(tstat = firstactivestat;tstat;)
1978 {
1979 temp = tstat->nextactive;
1980
1981 if (tstat->flags & FL_DEADBODY)
1982 {
1983 if ((tstat->tilex == tilex) && (tstat->tiley == tiley))
1984 {
1985 if ((tstat->flags & FL_DEADBODY) && (tstat->linked_to != -1))
1986 DEADPLAYER[tstat->linked_to] = NULL;
1987 RemoveStatic(tstat);
1988 if (tstat->flags & FL_DEADBODY)
1989 SpawnSlowParticles(GUTS,8,tstat->x,tstat->y,tstat->z);
1990 else
1991 SpawnSlowParticles(gt_sparks,8,tstat->x,tstat->y,tstat->z);
1992 SD_PlaySoundRTP(SD_ACTORSQUISHSND,tstat->x,tstat->y);
1993 }
1994 }
1995 tstat = temp;
1996 }
1997 }
1998
1999
SpawnSpear(int tilex,int tiley,int up)2000 void SpawnSpear(int tilex,int tiley,int up)
2001 {
2002 int count,i;
2003 statetype *tstate;
2004
2005
2006 if (BATTLEMODE && (!gamestate.BattleOptions.SpawnDangers))
2007 return;
2008
2009 if (!up)
2010 {
2011 #if (SHAREWARE == 1)
2012 Error("\ndownspear at %d,%d in shareware!",tilex,tiley);
2013 #else
2014 SpawnNewObj(tilex,tiley,&s_speardown1,spearobj);
2015 new->z = 0;
2016 #endif
2017 }
2018 else
2019
2020 SpawnNewObj(tilex,tiley,&s_spearup1,spearobj);
2021
2022 count = (int)(GameRandomNumber("Spawn Spear",0) % 16);
2023 for(i=0,tstate = new->state;i<count;i++,tstate=tstate->next);
2024 NewState(new,tstate);
2025
2026 PreCacheActor(spearobj,up);
2027 new->flags |= (FL_ABP);//|FL_INVULNERABLE);
2028 MakeActive(new);
2029 }
2030
2031
2032
SpawnSpring(int tilex,int tiley)2033 void SpawnSpring(int tilex,int tiley)
2034 {
2035 int iconvalue;
2036
2037 iconvalue = MAPSPOT(tilex,tiley,2);
2038 if (iconvalue == 3)
2039 {
2040 SpawnNewObj(tilex,tiley,&s_autospring1,springobj);
2041 new->ticcount = (GameRandomNumber("Spawn Spring",0) % new->ticcount)+1;
2042 new->temp1 = iconvalue;
2043 }
2044 else
2045 {
2046 SpawnNewObj(tilex,tiley,&s_spring1,springobj);
2047 if (iconvalue == 2)
2048 new->temp1 = iconvalue;
2049 }
2050
2051 PreCacheActor(springobj,0);
2052 new->flags &= ~(FL_SHOOTABLE|FL_BLOCK);
2053 }
2054
2055
2056
2057
T_Spring(objtype * ob)2058 void T_Spring(objtype*ob)
2059 {
2060 objtype *temp;
2061 int op,dx,dy,dz;
2062
2063
2064 if ((ob->state->condition & SF_DOWN) && (ob->temp1))
2065 {
2066 if (ob->ticcount)
2067 return;
2068 ob->shapenum++;
2069 TurnActorIntoSprite(ob);
2070 return;
2071 }
2072
2073 for(temp=firstareaactor[ob->areanumber];temp;temp=temp->nextinarea)
2074 {
2075 if (temp == ob)
2076 continue;
2077
2078 if (temp->obclass >= roboguardobj)
2079 continue;
2080
2081 dx = abs(ob->x-temp->x);
2082 dy = abs(ob->y-temp->y);
2083 dz = abs(ob->z-temp->z);
2084 if ((dx > ACTORSIZE+0x2800) || (dy > ACTORSIZE+0x2800) || (dz > 40))
2085 continue;
2086 if (!temp->momentumz)
2087 {
2088 op = FixedMul(GRAVITY,(temp->z-5)<<16) << 1;
2089 temp->momentumz = -FixedSqrtHP(op);
2090 SD_PlaySoundRTP(SD_SPRINGBOARDSND,ob->x,ob->y);
2091 }
2092 }
2093 }
2094
2095
2096
T_Count(objtype * ob)2097 void T_Count(objtype*ob)
2098 {
2099 int index;
2100 wall_t* tswitch;
2101 touchplatetype *temp;
2102 objtype* tempactor;
2103
2104 if (ob->dirchoosetime)
2105 {
2106 ob->dirchoosetime --;
2107 if (ob->dirchoosetime>980)
2108 MISCVARS->gasindex=((1050-ob->dirchoosetime)<<4)/70;
2109 else if (ob->dirchoosetime<35)
2110 MISCVARS->gasindex=(ob->dirchoosetime<<4)/35;
2111 if (ob->temp3)
2112 {
2113 ob->temp3 --;
2114 if (ob->temp3 & 1)
2115 SD_PlaySoundRTP(SD_GASHISSSND,ob->x,ob->y);
2116 }
2117 else
2118 {
2119 ob->temp3 = 105;
2120 for(tempactor=firstareaactor[ob->areanumber];tempactor;tempactor=tempactor->nextinarea)
2121 {
2122 if (tempactor == ob)
2123 continue;
2124 if (!(tempactor->flags & FL_SHOOTABLE))
2125 continue;
2126 if (tempactor->obclass != playerobj)
2127 {
2128 if ((tempactor->obclass >= lowguardobj) &&
2129 (tempactor->obclass <= dfiremonkobj))
2130 {
2131 int oldviolence = gamestate.violence;
2132
2133 gamestate.violence = vl_low;
2134 DamageThing(tempactor,EnvironmentDamage(ob));
2135 Collision(tempactor,ob,-(tempactor->momentumx),-(tempactor->momentumy));
2136 gamestate.violence = oldviolence;
2137
2138 }
2139 }
2140 else if (!(tempactor->flags & FL_GASMASK))
2141 {
2142 DamageThing(tempactor,EnvironmentDamage(ob));
2143 Collision(tempactor,ob,0,0);
2144 M_CheckPlayerKilled(tempactor);
2145 }
2146 }
2147 }
2148 }
2149
2150 else
2151 {
2152 int i;
2153 playertype *pstate;
2154
2155 for(i=0;i<numplayers;i++)
2156 {
2157 M_LINKSTATE(PLAYER[i],pstate);
2158 PLAYER[i]->flags &= ~FL_GASMASK;
2159 pstate->protectiontime = 1;
2160 }
2161
2162 NewState(ob,&s_gas1);
2163 SD_PlaySoundRTP(SD_GASENDSND,ob->x,ob->y);
2164 ob->flags &= ~FL_ACTIVE;
2165 MISCVARS->gasindex=0;
2166 MU_StartSong(song_level);
2167 MU_RestoreSongPosition();
2168 MISCVARS->GASON = 0;
2169
2170 index = touchindices[ob->temp1][ob->temp2]-1;
2171 TRIGGER[index] = 0;
2172 for(temp = touchplate[index];temp;temp = temp->nextaction)
2173 if (temp->action == EnableObject)
2174 {
2175 tempactor = (objtype*)(temp->whichobj);
2176 tempactor->flags &= ~FL_ACTIVE;
2177 }
2178
2179 tswitch = (wall_t*)actorat[ob->temp1][ob->temp2];
2180 /*
2181 if (tswitch && (tswitch->which != ACTOR))
2182 {
2183 tilemap[ob->temp1][ob->temp2]--;
2184 tswitch->flags &= ~FL_ON;
2185 }
2186 */
2187
2188 }
2189 }
2190
2191
2192
2193
SpawnBlade(int tilex,int tiley,int dir,int upordown,int moving)2194 void SpawnBlade(int tilex, int tiley,int dir,int upordown,int moving)
2195 {int count,i;
2196 statetype *nstate;
2197
2198 #if (SHAREWARE == 1)
2199 if (!upordown)
2200 Error("\ndown spinblade at %d,%d not allowed in shareware !",tilex,tiley);
2201 if (moving)
2202 Error("\nupdown spinblade at %d,%d not allowed in shareware !",tilex,tiley);
2203
2204 #endif
2205
2206
2207 if (BATTLEMODE && (!gamestate.BattleOptions.SpawnDangers))
2208 return;
2209
2210 if (moving)
2211
2212 {
2213 #if (SHAREWARE == 0)
2214
2215 if (upordown)
2216 SpawnNewObj(tilex,tiley,&s_spinupblade1,bladeobj);
2217 else
2218 {SpawnNewObj(tilex,tiley,&s_spindownblade1,bladeobj);
2219 new->z = 0;
2220 }
2221 #endif
2222 }
2223 else
2224 {if (upordown)
2225 SpawnNewObj(tilex,tiley,&s_upblade1,bladeobj);
2226
2227 #if (SHAREWARE == 0)
2228
2229 else
2230 {SpawnNewObj(tilex,tiley,&s_downblade1,bladeobj);
2231 new->z = 0;
2232 }
2233 #endif
2234 }
2235
2236
2237 count = (int)(GameRandomNumber("SpawnBlade",0) % 16);
2238 for(nstate=new->state,i=0;i<count;nstate = nstate->next,i++);
2239 NewState(new,nstate);
2240
2241 new->flags |= (FL_BLOCK);
2242 new->flags &= ~FL_SHOOTABLE;
2243 new->dir = dir;
2244 if (dir != nodir)
2245 {new->flags |= FL_NOFRICTION;
2246 new->speed = ENEMYRUNSPEED;
2247
2248 }
2249 if (!MAPSPOT(tilex,tiley,2))
2250 {new->flags |= FL_ACTIVE;
2251 ParseMomentum(new,dirangle8[new->dir]);
2252 }
2253 PreCacheActor(bladeobj,(moving<<1)+upordown);
2254 }
2255
2256
SpawnCrushingColumn(int tilex,int tiley,int upordown)2257 void SpawnCrushingColumn(int tilex, int tiley, int upordown)
2258 {int i,count;
2259 statetype * nstate;
2260
2261
2262 #if (SHAREWARE == 1)
2263 if (!upordown)
2264 Error("\ncrush-up column at %d,%d not allowed in shareware!",tilex,tiley);
2265 #endif
2266
2267
2268 if (BATTLEMODE && (!gamestate.BattleOptions.SpawnDangers))
2269 return;
2270 #if (SHAREWARE == 0)
2271 if (!upordown)
2272 SpawnNewObj(tilex,tiley,&s_columnupup1,crushcolobj);
2273 else
2274 #endif
2275 {SpawnNewObj(tilex,tiley,&s_columndowndown1,crushcolobj);
2276 new->z = 0;
2277 }
2278
2279 count = (int)(GameRandomNumber("SpawnCrushingColumn",0) % 8);
2280 for(nstate=new->state,i=0;i<count;nstate = nstate->next,i++)
2281 {if ((!upordown) && (nstate->condition & SF_UP))
2282 new->temp1 += (((nstate->tictime>>1) + 1)<<2);
2283
2284 }
2285 NewState(new,nstate);
2286 new->flags |= (FL_BLOCK);
2287
2288 new->flags &= ~FL_SHOOTABLE;
2289 PreCacheActor(crushcolobj,upordown);
2290 }
2291
2292
2293
SpawnFirejet(int tilex,int tiley,int dir,int upordown)2294 void SpawnFirejet(int tilex, int tiley, int dir, int upordown)
2295 {
2296 int statecount,i;
2297 statetype *tstate;
2298
2299
2300 statecount = (int)(GameRandomNumber("SpawnFirejet",0) % 22);
2301
2302 if (upordown)
2303 {
2304 for(i=0,tstate=&s_firejetup1;i<statecount;i++,tstate=tstate->next);
2305 SpawnNewObj(tilex,tiley,tstate,firejetobj);
2306 }
2307 else
2308 {
2309 #if (SHAREWARE == 1)
2310 Error("\ndown firejet at %d,%d not allowed in shareware",tilex,tiley);
2311 #else
2312 for(i=0,tstate=&s_firejetdown1;i<statecount;i++,tstate=tstate->next);
2313 SpawnNewObj(tilex,tiley,tstate,firejetobj);
2314 new->z = 0;
2315 #endif
2316 }
2317
2318 PreCacheActor(firejetobj,upordown);
2319
2320 new->flags &= ~FL_SHOOTABLE;
2321
2322 if (dir != nodir)
2323 {
2324 new->dir = dir*2;
2325 new->flags |= FL_NOFRICTION;
2326 new->speed = ENEMYRUNSPEED;
2327 ParseMomentum(new,dirangle8[new->dir]);
2328 }
2329 else
2330 new->dir = dir;
2331 }
2332
2333
SpawnFirebomb(objtype * ob,int damage,int which)2334 void SpawnFirebomb(objtype*ob,int damage,int which)
2335 {
2336 int i,low,high,doorat;
2337 wall_t *tempwall;
2338 doorobj_t*tempdoor;
2339
2340 if (which == 0)
2341 {
2342 low = (ob->dir>>1);
2343 high = low;
2344 }
2345 else
2346 {
2347 low = 0;
2348 high = which-1;
2349
2350 if ((FindDistance((ob->x-player->x), (ob->y-player->y))<0x120000) &&
2351 (player->z==nominalheight)
2352 )
2353 SHAKETICS = 35;
2354 }
2355
2356 for (i=low;i<=high;i++)
2357 {
2358 MissileSound = false;
2359 /*
2360 if (((which == 0) && ((low == 5) || (low == 6))) ||
2361 ((which == 6) && ((i==4) || (i==5)))
2362 )
2363 {
2364
2365 if (((which == 0) && (low == 5)) ||
2366 ((which == 6) && (i == 4))
2367 )
2368 {
2369 newz = ob->z + 64;
2370 if (newz > maxheight)
2371 continue;
2372 SpawnMissile(ob,p_firebombobj,0,0,&s_grexplosion1,0);
2373 new->z = newz;
2374 new->dir = 10;
2375
2376
2377 }
2378 else
2379 {
2380 newz = ob->z - 64;
2381 if ((sky == 0) && (newz < 0))
2382 continue;
2383 SpawnMissile(ob,p_firebombobj,0,0,&s_grexplosion1,0);
2384 new->z = newz;
2385 new->dir = 12;
2386
2387 }
2388
2389
2390 }
2391 else */
2392 {
2393 SpawnMissile(ob,p_firebombobj,0,dirangle8[2*i],&s_grexplosion1,0x10000);
2394 new->z = ob->z;
2395 new->dir = (i<<1);
2396
2397 }
2398
2399 MissileSound = true;
2400
2401
2402 SD_PlaySoundRTP(SD_EXPLODEFLOORSND,ob->x,ob->y);
2403 new->temp2 = FixedMul(damage,DIAGADJUST);
2404
2405
2406 tempwall = (wall_t*)actorat[new->tilex][new->tiley];
2407 doorat= 0;
2408 if (M_ISDOOR(new->tilex,new->tiley))
2409 {
2410 tempdoor = doorobjlist[tilemap[new->tilex][new->tiley]&0x3ff];
2411 if (tempdoor->position<0x8000)
2412 doorat = 1;
2413 }
2414
2415 if ((tempwall && M_ISWALL(tempwall)) || doorat ||
2416 (new->tilex <=0) || (new->tilex > MAPSIZE-1) ||
2417 (new->tiley <=0) || (new->tiley > MAPSIZE-1)
2418 )
2419 {
2420 new->z = ob->z;
2421 SetFinePosition(new,ob->x,ob->y);
2422 SetVisiblePosition(new,ob->x,ob->y);
2423 }
2424 new->whatever = ob->whatever;
2425 new->temp3 = ob->temp3 - 1;
2426 }
2427 }
2428
2429
2430
2431
2432
2433
MissileHitActor(objtype * owner,objtype * missile,objtype * victim,int damage,int hitmomx,int hitmomy)2434 void MissileHitActor(objtype *owner, objtype *missile, objtype *victim,
2435 int damage, int hitmomx, int hitmomy
2436 )
2437 {
2438 int tcl = victim->obclass;
2439 int ocl = missile->obclass;
2440
2441 if (
2442 (victim->flags & FL_DYING) || // hey, they're dying already;
2443 (victim->flags & FL_HEAD) || // don't hurt overrobot's head, wheels
2444 (tcl == wallopobj) || // bcraft is invulnerable
2445 (tcl == b_darkmonkobj) || // darkmonk is invulnerable
2446 (!(victim->flags & FL_SHOOTABLE)) || // don't hurt environment dangers, dead guys
2447 ((tcl == b_darksnakeobj) &&
2448 ((SNAKELEVEL != 3) || (!victim->temp3))// return for non-red snake
2449 )
2450 )
2451 return;
2452
2453
2454 if ((tcl == playerobj) || (tcl == b_heinrichobj))
2455 victim->target = owner;
2456
2457
2458 if (tcl == NMEsaucerobj) // can shoot over's saucer
2459 {
2460 NewState(victim,&s_explosion1);
2461 victim->flags &= ~FL_SHOOTABLE;
2462 victim->temp2 = damage;
2463 return;
2464 }
2465
2466 else if (tcl == roboguardobj) // check roboguard
2467 {
2468 DamageThing(victim,damage);
2469 Collision(victim,owner,0,0);
2470 }
2471
2472 else if (tcl == collectorobj)
2473 {
2474 if (gamestate.SpawnEluder)
2475 return;
2476
2477 DamageThing(victim,damage);
2478 Collision(victim,owner,0,0);
2479 }
2480
2481 else if (tcl == patrolgunobj)
2482 {
2483 DamageThing(victim,damage);
2484 if (victim->hitpoints <= 0)
2485 {
2486 victim->momentumx = victim->momentumy = victim->momentumz = 0;
2487 victim->flags |= FL_DYING;
2488 if (victim->temp1 == -1) // this is 4-way gun
2489 NewState(victim,&s_robogrddie1);
2490 #if (SHAREWARE == 0)
2491 else // this is normal
2492 NewState(victim,&s_gundie1);
2493 #endif
2494 }
2495 }
2496
2497 // bosses are "special" ==========================
2498
2499 else if ((tcl >= b_darianobj) && (tcl < b_darkmonkobj))
2500
2501 {
2502 DamageThing(victim,damage);
2503 if (!(victim->flags & FL_ATTACKMODE))
2504 FirstSighting (victim); // put into combat mode
2505 if (victim->hitpoints <= 0)
2506 {
2507 victim->momentumx = victim->momentumy = victim->momentumz = 0;
2508 victim->flags |= FL_DYING;
2509 NewState(victim,UPDATE_STATES[DIE][victim->obclass-lowguardobj]);
2510 switch (victim->obclass)
2511 {
2512 case b_darianobj:
2513 AddMessage("Darian defeated!",MSG_CHEAT);
2514 break;
2515
2516 case b_heinrichobj:
2517 AddMessage("Krist defeated!",MSG_CHEAT);
2518 break;
2519
2520 case b_robobossobj:
2521 AddMessage("NME defeated!",MSG_CHEAT);
2522 break;
2523 default:
2524 ;
2525 }
2526 MU_StartSong(song_bossdie);
2527 }
2528 #if (SHAREWARE == 0)
2529 else
2530 {
2531 MISCVARS->REDTIME = (damage >> 1);
2532 if (victim->obclass == b_heinrichobj)
2533 {
2534 NewState(victim,&s_heinrichdefend);
2535 if (Near(victim,PLAYER[0],3))
2536 {
2537 MISCVARS->HRAMMING = 1;
2538 MISCVARS->HMINING = 0;
2539 victim->dirchoosetime = 0;
2540 }
2541 else
2542 {
2543 MISCVARS->HMINING = 1;
2544 MISCVARS->HRAMMING = 0;
2545 victim->dirchoosetime = 5;//10;
2546 }
2547 victim->targettilex = victim->targettiley = 0;
2548 victim->target = NULL;
2549 }
2550 }
2551 #endif
2552 }
2553
2554 #if (SHAREWARE == 0)
2555 else if ((tcl == b_darksnakeobj) && (victim->temp3)) // red snake
2556 {
2557 DamageThing(SNAKEEND,damage);
2558 if (victim->state->think == T_DarkSnakeChase)
2559 NewState(victim,&s_redheadhit);
2560 else
2561 NewState(victim,&s_redlinkhit);
2562 victim->temp3 = 0;
2563 }
2564 #endif
2565
2566 //===============================================
2567 else // all other actors
2568 {
2569
2570 if ((tcl == playerobj) &&
2571 (victim->flags & FL_AV) &&
2572 (ocl != p_godballobj)
2573 )
2574 {
2575 playertype *pstate;
2576
2577 M_LINKSTATE(victim,pstate);
2578 pstate->protectiontime -= ((damage<<1) + damage);
2579 if (pstate->protectiontime < 1)
2580 pstate->protectiontime = 1;
2581 if (victim==player)
2582 GM_UpdateBonus (pstate->protectiontime, false);
2583
2584 return; // asbestos vest prevents victim damage
2585 }
2586
2587 DamageThing(victim,damage);
2588
2589
2590
2591 if ((tcl < roboguardobj) && (victim->hitpoints <= 0))
2592 {
2593 if (ocl != p_godballobj)
2594 victim->flags |= FL_HBM;
2595 else
2596 victim->flags |= (FL_GODSTRUCK | FL_FULLLIGHT);
2597 }
2598
2599 if (tcl == playerobj)
2600 {
2601 playertype *pstate;
2602
2603 M_LINKSTATE(victim,pstate);
2604 if (pstate->health <= 0)
2605 {
2606 if (ocl != p_godballobj)
2607 victim->flags |= FL_HBM;
2608 else
2609 victim->flags |= (FL_GODSTRUCK | FL_FULLLIGHT);
2610
2611 if (M_ISACTOR(owner))
2612 {
2613 if (owner->obclass == playerobj)
2614 {
2615 if (!victim->momentumz)
2616 BATTLE_PlayerKilledPlayer(battle_kill_with_missile,owner->dirchoosetime,victim->dirchoosetime);
2617 else
2618 BATTLE_PlayerKilledPlayer(battle_kill_with_missile_in_air,owner->dirchoosetime,victim->dirchoosetime);
2619 }
2620 else
2621 BATTLE_CheckGameStatus(battle_player_killed,missile->dirchoosetime);
2622 }
2623 else
2624 BATTLE_CheckGameStatus(battle_player_killed,missile->dirchoosetime);
2625 }
2626 }
2627
2628
2629
2630 if ((owner->obclass == playerobj) && (victim->flags & FL_HBM))
2631 {
2632 MISCVARS->supergibflag = true;
2633 //GivePoints(starthitpoints[gamestate.difficulty][victim->obclass]*5);
2634 }
2635
2636 Collision(victim,owner,hitmomx,hitmomy);
2637 MISCVARS->supergibflag = false;
2638 if ((tcl == blitzguardobj) && (owner->obclass == playerobj))
2639 victim->flags |= FL_TARGET;
2640
2641 }
2642
2643 }
2644
2645
2646
MissileHit(objtype * ob,void * hitwhat)2647 void MissileHit (objtype *ob,void *hitwhat)
2648 {
2649 int damage=0, random,tcl=0,ocl,fireweapon=0,sound,hitmomx,hitmomy;
2650 objtype* tempactor=NULL,*owner;
2651
2652
2653
2654 if (ob==missobj)
2655 missobj=NULL;
2656
2657 if (ob == PLAYER0MISSILE)
2658 PLAYER0MISSILE = NULL;
2659
2660
2661 ob->momentumz = 0;
2662 hitmomx = ob->momentumx;
2663 hitmomy = ob->momentumy;
2664 if (ob->soundhandle != -1)
2665 SD_StopSound(ob->soundhandle);
2666
2667 ob->flags &= ~FL_SHOOTABLE;
2668 if (FirstExplosionState(ob->state))
2669 return;
2670
2671 /*
2672 if ((ob->z < -28) || (IsWindow(ob->tilex,ob->tiley)))
2673 {
2674 NewState(ob,&s_megaremove);
2675 return;
2676 }
2677 */
2678
2679 tempactor = (objtype*)hitwhat;
2680 owner = (objtype*)(ob->whatever);
2681
2682 random = GameRandomNumber("MissileHit",0);
2683 ocl = ob->obclass;
2684 if (tempactor)
2685 {
2686 if (tempactor->which == ACTOR)
2687 tcl = tempactor->obclass;
2688 else if (tempactor->which == SPRITE)
2689 tcl = -1;
2690 }
2691
2692 if ((!tcl) && (ob->z < -30))
2693 {
2694 if (ob->soundhandle != -1)
2695 SD_StopSound(ob->soundhandle);
2696
2697 NewState(ob,&s_megaremove);
2698 return;
2699
2700 }
2701
2702
2703 if (((ocl != p_kesobj) && (ocl != p_godballobj)) || (!tcl))
2704 ZEROMOM;
2705
2706 if (tcl == b_darianobj)
2707 MISCVARS->ESAU_SHOOTING = false;
2708
2709 switch(ocl)
2710 {
2711
2712
2713 case p_bazookaobj:
2714 NewState(ob,&s_explosion1);
2715 if (M_ISACTOR(owner) && (owner->obclass == blitzguardobj))
2716 damage = 30 + (random >> 4);
2717 else
2718 damage = 2*((random>>3)+80);
2719 break;
2720
2721 case p_heatseekobj:
2722 NewState(ob,&s_explosion1);
2723 damage = 2*((random>>3)+50);
2724 break;
2725
2726
2727 case p_drunkmissileobj:
2728 NewState(ob,&s_explosion1);
2729 damage = ((random>>3)+25);
2730 break;
2731
2732 case p_firebombobj:
2733 NewState(ob,&s_explosion1);
2734 damage = 2*((random>>3)+90);
2735 ob->temp3 = 4;
2736 SpawnFirebomb(ob,damage,4);
2737 break;
2738
2739 case p_firewallobj:
2740
2741 if (tcl == playerobj)
2742 gamestate.DOGROUNDZEROBONUS = true;
2743 NewState(ob,&s_explosion1);
2744 damage = 2*((random>>3)+50);
2745 break;
2746
2747
2748 case p_godballobj:
2749 if ((tcl >= pillarobj) || (!tcl) || ((tcl == -1) && (!(tempactor->flags & FL_SHOOTABLE))))
2750 NewState(ob,&s_explosion1);
2751 ob->target = NULL;
2752 damage = 500;
2753 break;
2754
2755
2756 case shurikenobj:
2757 NewState(ob,&s_explosion1);
2758 damage = ((random >>3) + 30)>>2;
2759 break;
2760
2761
2762 case grenadeobj:
2763 NewState(ob,&s_explosion1);
2764 damage = (random >>3) + 20;
2765 break;
2766
2767 case fireballobj:
2768 NewState(ob,&s_explosion1);
2769 damage = (random >> 3) + 10;
2770 fireweapon = 1;
2771 break;
2772
2773 case missileobj:
2774 NewState(ob,&s_explosion1);
2775 if (M_ISACTOR(owner) && (owner->obclass == wallopobj))
2776 damage = (random >> 5);
2777 else
2778 damage = (random >>3) + 30;
2779 if (tcl && (tcl != b_heinrichobj))
2780 damage = 3*damage>>3;
2781 break;
2782
2783 case wallfireobj:
2784 if ((!tempactor) ||
2785 (tempactor->which == ACTOR) ||
2786 (tempactor->which == SPRITE)
2787 )
2788 NewState(ob,&s_explosion1);
2789 else if (M_ISWALL(tempactor) || (tempactor->which == DOOR))
2790 NewState(ob,&s_crossdone1);
2791 damage = EnvironmentDamage(ob);
2792 fireweapon = 1;
2793 break;
2794
2795
2796
2797 case inertobj:
2798 ob->state = NULL;
2799 return;
2800 break;
2801
2802
2803 #if (SHAREWARE == 0)
2804
2805
2806 case p_splitmissileobj:
2807 NewState(ob,&s_explosion1);
2808 damage = 2*((random>>3)+50);
2809 break;
2810
2811
2812 case p_kesobj:
2813 if ((tcl >= pillarobj) ||
2814 (!tcl) ||
2815 ((tcl == -1) && (!(tempactor->flags & FL_SHOOTABLE)))
2816 )
2817 NewState(ob,&s_explosion1);
2818 damage = 2*((random>>3)+140);
2819 break;
2820
2821
2822 case netobj:
2823 ob->state=NULL;
2824 MISCVARS->NET_IN_FLIGHT = false;
2825 if (tempactor == PLAYER[0])
2826 {
2827 if ((tempactor->flags & FL_GODMODE) ||
2828 (tempactor->flags & FL_DOGMODE) ||
2829 godmode
2830 )
2831 damage = 0;
2832 else
2833 {
2834 damage = (random >>4) + 5;
2835 PLAYERSTATE[0].NETCAPTURED = -1;
2836 PLAYERSTATE[0].weapondowntics = WEAPONS[PLAYERSTATE[0].weapon].screenheight/GMOVE;
2837 NewState(PLAYER[0],&s_player);
2838 PLAYERSTATE[0].attackframe = PLAYERSTATE[0].weaponframe = 0;
2839 PLAYERSTATE[0].batblast = 0;
2840 if (PLAYERSTATE[0].HASKNIFE == false)
2841 AddMessage("Wiggle left and right to get out of net!",
2842 MSG_GAME);
2843 }
2844 }
2845 break;
2846
2847
2848 case bigshurikenobj:
2849 NewState(ob,&s_oshurikenhit1);
2850 if (owner->obclass == wallopobj)
2851 damage = (random >> 5);
2852 else
2853 damage = 4*((random >>3) + 30)/10;
2854
2855 break;
2856
2857
2858 case dm_spitobj:
2859 NewState(ob,&s_spithit1);
2860 damage = 30;
2861 if (gamestate.difficulty == gd_hard)
2862 damage += 15;
2863 break;
2864
2865 case dm_weaponobj:
2866 damage = 20;
2867 NewState(ob,&s_explosion1);
2868 break;
2869
2870 case dm_heatseekobj:
2871 damage = 20;
2872 NewState(ob,&s_explosion1);
2873 break;
2874
2875 case dmfballobj:
2876 NewState(ob,&s_explosion1);
2877 damage = (random >>3) + 20;
2878 fireweapon = 1;
2879 break;
2880
2881 case h_mineobj:
2882 NewState(ob,&s_explosion1);
2883 damage = (random >>3) + 20;
2884 break;
2885
2886 case NMEsaucerobj:
2887 NewState(ob,&s_explosion1);
2888 damage = 2*((random>>3)+30);
2889 break;
2890
2891
2892 #endif
2893
2894
2895 //default:
2896 //Error("Unknown ob %d called MissileHit",ob->obclass);
2897 }
2898
2899 //if (!ob->state)
2900 //return;
2901 if ((sound = BAS[ob->obclass].hit)!=0)
2902 SD_PlaySoundRTP(sound,ob->x,ob->y);
2903
2904
2905 if (FirstExplosionState(ob->state))
2906 SD_PlaySoundRTP(SD_EXPLODESND,ob->x,ob->y);
2907
2908
2909 if (tcl>0) // actors
2910 {
2911 MissileHitActor(owner,ob,tempactor,damage,hitmomx,hitmomy);
2912 if ((ocl == p_kesobj) && (tcl < roboguardobj))
2913 {
2914 tempactor->momentumx = hitmomx; // kes gives wus targets its momentum
2915 tempactor->momentumy = hitmomy;
2916 //missile->flags |= FL_NOFRICTION;
2917 }
2918 }
2919
2920 else if (tcl < 0) // static
2921 {
2922 DamageThing(hitwhat,damage);
2923 if (FirstExplosionState(new->state))
2924 new->whatever = ob->whatever;
2925 }
2926
2927
2928 }
2929
2930
2931
2932
T_Spears(objtype * ob)2933 void T_Spears(objtype*ob)
2934 {int dx,dy,dz,i;
2935
2936
2937 for(i=0;i<numplayers;i++)
2938 {if (PLAYER[i]->flags & FL_DYING)
2939 continue;
2940
2941 dx = abs(PLAYER[i]->x - ob->x);
2942 dy = abs(PLAYER[i]->y - ob->y);
2943 dz = abs(PLAYER[i]->z - ob->z);
2944
2945
2946 if ((!ob->ticcount)&&(ob->state->condition&SF_SOUND) &&
2947 areabyplayer[ob->areanumber])
2948 SD_PlaySoundRTP(BAS[ob->obclass].operate,ob->x,ob->y);
2949
2950 if ((dx < STANDDIST) && (dy < STANDDIST) && (dz < 20))
2951 {ob->flags &= ~FL_BLOCK;
2952 if ((!ob->ticcount) && (ob->state->condition & SF_CRUSH))
2953 {DamageThing(PLAYER[i],EnvironmentDamage(ob));
2954 Collision(PLAYER[i],ob,0,0);
2955 M_CheckPlayerKilled(PLAYER[i]);
2956 return;
2957 }
2958 }
2959 else
2960 {if (ob->state->condition & SF_DOWN)
2961 ob->flags &= ~FL_BLOCK;
2962 else
2963 ob->flags |= FL_BLOCK;
2964 }
2965 }
2966 }
2967
2968
2969
T_CrushUp(objtype * ob)2970 void T_CrushUp(objtype*ob)
2971 {int dx, dy,dist,dz,i,playeron;
2972
2973
2974 if ((!ob->ticcount) && (ob->state->condition & SF_SOUND) &&
2975 areabyplayer[ob->areanumber])
2976 SD_PlaySoundRTP(BAS[ob->obclass].operate,ob->x,ob->y);
2977 dist = ACTORSIZE+0x2000;
2978 if (ob->state->condition & SF_UP)
2979 {ob->temp1 += 4;
2980 // Debug("\ncol momz = 4");
2981 }
2982 else if (ob->state->condition & SF_DOWN)
2983 {ob->temp1 -= 4;
2984 // Debug("\ncol mom z = -4");
2985 }
2986 else
2987 {//ob->momentumz = 0;
2988 // Debug("\ncol mom z = 0");
2989 }
2990
2991 ob->temp2 = maxheight - ob->temp1 + 32;
2992
2993
2994 playeron = 0;
2995 for(i=0;i<numplayers;i++)
2996 {dx = abs(PLAYER[i]->x - ob->x);
2997 dy = abs(PLAYER[i]->y - ob->y);
2998 dz = abs(ob->temp2-PLAYER[i]->z);
2999
3000 if ((dx < dist) && (dy < dist) && (dz < 65))
3001 {ob->flags &= ~FL_BLOCK;
3002 //player->temp2 = 0;
3003 playeron = 1;
3004 if ((!ob->ticcount) && (ob->state->condition & SF_CRUSH) &&
3005 (levelheight<2) && (!(ob->flags & FL_DYING)))
3006 {DamageThing(PLAYER[i],EnvironmentDamage(ob));
3007 if (PLAYER[i]->hitpoints <= 0)
3008 PLAYER[i]->flags |= FL_HBM;
3009 Collision(PLAYER[i],ob,0,0);
3010 M_CheckPlayerKilled(PLAYER[i]);
3011 //NewState(ob,ob->state); //reset ticcount
3012 return;
3013 }
3014 if (ob->state->condition & SF_UP)
3015 {
3016 PLAYER[i]->momentumz = -(4<<16);
3017 if (PLAYER[i]->z < -30)
3018 PLAYER[i]->z = -30;
3019 }
3020 else if (ob->state->condition & SF_DOWN)
3021 {PLAYER[i]->momentumz = (4<<16);
3022 if (PLAYER[i]->z >= nominalheight)
3023 PLAYER[i]->z = nominalheight;
3024 }
3025 else
3026 PLAYER[i]->momentumz = 0;
3027 PLAYER[i]->whatever = ob;
3028 ob->whatever = PLAYER[i];
3029 //PLAYER[i]->flags |= FL_RIDING;
3030
3031 }
3032
3033 }
3034
3035 //if (!playeron)
3036 {if (ob->state->condition & SF_BLOCK)
3037 ob->flags |= FL_BLOCK;
3038 else
3039 ob->flags &= ~FL_BLOCK;
3040
3041 }
3042
3043
3044 }
3045
3046
T_CrushDown(objtype * ob)3047 void T_CrushDown(objtype*ob)
3048 {int dx,dy,dz,i,playeron;
3049
3050
3051 if ((!ob->ticcount) && (ob->state->condition & SF_SOUND)&&
3052 areabyplayer[ob->areanumber])
3053 SD_PlaySoundRTP(BAS[ob->obclass].operate,ob->x,ob->y);
3054
3055 ob->temp2 = ob->z;
3056 playeron = 0;
3057 for(i=0;i<numplayers;i++)
3058 {dx = abs(PLAYER[i]->x - ob->x);
3059 dy = abs(PLAYER[i]->y - ob->y);
3060 dz = abs(PLAYER[i]->z - ob->z);
3061
3062 if ((dx < STANDDIST) && (dy < STANDDIST) && (dz < 20))
3063 {//PLAYER[i]->temp2 = 0;
3064 playeron = 1;
3065 ob->flags &= ~FL_BLOCK;
3066 if ((!ob->ticcount) && (ob->state->condition & SF_CRUSH) &&
3067 (!(ob->flags & FL_DYING)))
3068 {DamageThing(PLAYER[i],EnvironmentDamage(ob));
3069 if (PLAYER[i]->hitpoints <= 0)
3070 PLAYER[i]->flags |= FL_HBM;
3071 Collision(PLAYER[i],ob,0,0);
3072 M_CheckPlayerKilled(PLAYER[i]);
3073 //NewState(ob,ob->state); //reset ticcount
3074 return;
3075 }
3076 if ((ob->state->condition & SF_DOWN) &&
3077 ((ob->state != &s_columndowndown1) &&
3078 (ob->state != s_columndowndown1.next)))
3079 {PLAYER[i]->temp2 = COLUMNCRUSH;
3080 PLAYER[i]->whatever = ob;
3081 }
3082 }
3083
3084 }
3085 //if (!playeron)
3086 {if (ob->state->condition & SF_BLOCK)
3087 ob->flags |= FL_BLOCK;
3088 else
3089 ob->flags &= ~FL_BLOCK;
3090 }
3091
3092
3093 }
3094
3095
T_Explosion(objtype * ob)3096 void T_Explosion(objtype* ob)
3097 {
3098 int momx,momy,momz;
3099 int dx,dy,dz;
3100 int pdamage,dist,blastradius=0x20000,
3101 fatalradius=0x9000,impulse,damage,
3102 scalefactor;
3103
3104
3105
3106 statobj_t* checkstat;
3107 objtype* check,*owner;
3108
3109 if (ob->ticcount)
3110 return;
3111
3112 damage = EXPLOSION_DAMAGE;
3113 owner = (objtype*)(ob->whatever);
3114 if ((ob->temp3) && (ob->obclass == p_firebombobj))
3115 {
3116 SpawnFirebomb(ob,damage,0);
3117 ob->temp3 = 0;
3118 }
3119 //================== check surrounding actors ============================//
3120
3121
3122 for(check = firstactive;check;check=check->nextactive)
3123 {
3124 if (check == ob)
3125 continue;
3126
3127 // if (check == owner)
3128 // continue;
3129
3130 dx = abs(check->x - ob->x);
3131 if (dx > blastradius)
3132 continue;
3133
3134 dy = abs(ob->y - check->y);
3135 if (dy > blastradius)
3136 continue;
3137
3138 dz = ((abs(ob->z - check->z))<<10);
3139 if (dz > blastradius)
3140 continue;
3141
3142
3143 if (check->flags & FL_HEAD)
3144 continue;
3145
3146 if (check->flags & FL_DYING)
3147 continue;
3148
3149 if (!(check->flags & FL_SHOOTABLE))
3150 continue;
3151
3152
3153
3154 if ((check->obclass >= roboguardobj) && (check->obclass != b_darkmonkobj))
3155 //(check->obclass <= wallopobj))
3156 continue;
3157
3158
3159 if (!CheckLine(ob,check,SIGHT))
3160 continue;
3161
3162
3163 if (check->obclass == NMEsaucerobj)
3164 {
3165 NewState(check,&s_explosion1);
3166 check->flags &= ~FL_SHOOTABLE;
3167 return;
3168 }
3169 #if 0
3170 dist = FindDistance(dx,dy);
3171 scalefactor = (blastradius-dist)>>4;
3172 if (scalefactor > 0xffff)
3173 scalefactor = 0xffff;
3174 pdamage = FixedMul(damage,scalefactor);
3175 #endif
3176 //#if 0
3177 //magdx = abs(dx);
3178 //magdy = abs(dy);
3179
3180 dist = Find_3D_Distance(dx,dy,dz);
3181 SoftError("\ndist: %x\n",dist);
3182
3183
3184 //if (dist < 0x10000)
3185 // dist = 0x10000;
3186
3187 scalefactor = FixedDiv2(1<<16,FixedMul(dist,dist));
3188 //scalefactor = FixedDiv2(1<<16,dist);
3189
3190 if (scalefactor > 0x12000)
3191 scalefactor = 0x12000;
3192 pdamage = FixedMul(damage,scalefactor);
3193 SoftError("\ndamage: %d, scalefactor: %x\n",pdamage,scalefactor);
3194 //#endif
3195 impulse = FixedMul(EXPLOSION_IMPULSE,scalefactor);
3196 if (check->obclass == playerobj)
3197 {
3198 check->target = owner;
3199 if (check->flags & FL_AV)
3200 pdamage = 0;
3201 }
3202
3203 if (check->obclass < roboguardobj)
3204 {
3205 SoftError("\nhitpoints before: %d",check->hitpoints);
3206 DamageThing(check,pdamage);
3207 SoftError("\nhitpoints after: %d",check->hitpoints);
3208 if ((check->hitpoints <= 0) && (gamestate.violence == vl_excessive) &&
3209 ((ob->obclass == p_firebombobj) ||
3210 ((dx < fatalradius) && (dy < fatalradius) && (dz < 20)))
3211 )
3212 check->flags |= FL_HBM;
3213
3214 GetMomenta(check,ob,&momx,&momy,&momz,impulse);
3215 //Debug("\nhitmomx = %d, hitmomy = %d",momx,momy);
3216
3217 /*if (M_ISACTOR(owner) &&
3218 (owner->obclass == playerobj) &&
3219 (check->hitpoints <=0)
3220 )
3221 GivePoints(starthitpoints[gamestate.difficulty][check->obclass]*5);
3222 */
3223 Collision(check,owner,momx,momy);
3224 check->momentumz += (momz<<6);
3225 if ((check->obclass == playerobj) && (check->flags & FL_DYING) &&
3226 M_ISACTOR(owner))
3227 {
3228 if (owner->obclass == playerobj)
3229 {
3230 if (check->z != nominalheight)
3231 BATTLE_PlayerKilledPlayer(battle_kill_with_missile_in_air,owner->dirchoosetime,check->dirchoosetime);
3232 else
3233 BATTLE_PlayerKilledPlayer(battle_kill_with_missile,owner->dirchoosetime,check->dirchoosetime);
3234 }
3235 else
3236 BATTLE_CheckGameStatus(battle_player_killed,check->dirchoosetime);
3237 }
3238
3239 }
3240 else
3241 {
3242 if (check->obclass != b_darkmonkobj) {
3243 SoftError("non-darkmonk actor %d being helped by explosion",check->obclass);
3244 }
3245 check->hitpoints += pdamage;
3246 }
3247 }
3248
3249 //======================== check surrounding statics ================
3250
3251
3252 for(checkstat = firstactivestat;checkstat;checkstat=checkstat->nextactive)
3253 {
3254
3255 if ((!(checkstat->flags & FL_SHOOTABLE)) && (checkstat->itemnumber != stat_priestporridge))
3256 continue;
3257
3258 if ((checkstat->itemnumber >= stat_lifeitem1) &&
3259 (checkstat->itemnumber <= stat_lifeitem4))
3260 continue;
3261
3262 dx = abs(checkstat->x - ob->x);
3263 dy = abs(checkstat->y - ob->y);
3264 dz = ((abs(checkstat->z - ob->z))<<10);
3265
3266 if ((dx < blastradius) && (dy < blastradius) && (dz < blastradius))
3267 {
3268 dist = Find_3D_Distance(dx,dy,dz)+0xc00;
3269
3270 if (dist < 0x10000)
3271 dist = 0x10000;
3272
3273 scalefactor = FixedDiv2(1<<16,FixedMul(dist,dist));
3274 pdamage = FixedMul(damage,scalefactor);
3275
3276 if (checkstat->itemnumber != stat_priestporridge)
3277 DamageThing(checkstat,pdamage);
3278 else if (!(checkstat->flags & FL_ACTIVE))
3279 {
3280 checkstat->flags |= FL_ACTIVE;
3281 checkstat->count = 1;
3282 //checkstat->numanims = 6;
3283 SD_PlaySoundRTP(SD_COOKHEALTHSND,ob->x,ob->y);
3284 }
3285 }
3286 }
3287
3288 //======================== check surrounding walls ================
3289 {
3290 int tilexlow,tilexhigh;
3291 int tileylow,tileyhigh;
3292 int radius =0x10000;
3293 int x,y;
3294
3295 tilexlow = (int)((ob->x-radius) >>TILESHIFT);
3296 tileylow = (int)((ob->y-radius) >>TILESHIFT);
3297
3298 tilexhigh = (int)((ob->x+radius) >>TILESHIFT);
3299 tileyhigh = (int)((ob->y+radius) >>TILESHIFT);
3300
3301 for (y=tileylow;y<=tileyhigh;y++)
3302 {
3303 for (x=tilexlow;x<=tilexhigh;x++)
3304 {
3305 if ((tilemap[x][y]&0x8000) && (tilemap[x][y]&0x4000) && (abs(ob->z - nominalheight) < 32))
3306 {
3307 maskedwallobj_t * mw;
3308
3309 mw=maskobjlist[tilemap[x][y]&0x3ff];
3310 if (mw->flags&MW_SHOOTABLE)
3311 UpdateMaskedWall(tilemap[x][y]&0x3ff);
3312 }
3313 }
3314 }
3315 }
3316
3317 }
3318
3319
3320
SpawnScreenEye(objtype * ob)3321 void SpawnScreenEye(objtype *ob)
3322 {
3323 SpawnNewObj(ob->tilex,ob->tiley,&s_eye1,inertobj);
3324 new->targettiley = 0;
3325 new->targettilex = GameRandomNumber("eye position",0) + 20;
3326 SCREENEYE = new;
3327 //RemoveFromArea(new);
3328 new->flags |= FL_ABP;
3329 MakeActive(new);
3330
3331 }
3332
3333
3334
3335
3336
3337
SpawnSuperFatalityGibs(objtype * ob,objtype * attacker)3338 void SpawnSuperFatalityGibs(objtype *ob,objtype *attacker)
3339 {
3340 int crazygibs = (GameRandomNumber("crazy gibs",0) % 6) + 4;
3341 int i;
3342
3343
3344 if ((MISCVARS->supergibflag == true) &&
3345 ((crazygibs == 9) || (ludicrousgibs == true))
3346 )
3347
3348 {
3349 int olddirect = MISCVARS->directgibs;
3350
3351 MISCVARS->directgibs = false;
3352 if (ludicrousgibs == false)
3353 {
3354 if (attacker == player)
3355 {
3356 AddMessage("Ludicrous Gibs!",MSG_GAME);
3357 if (!(attacker->flags&FL_DOGMODE))
3358 SD_Play(PlayerSnds[locplayerstate->player]);
3359 }
3360 }
3361 else
3362 {
3363 MISCVARS->randgibspeed = true;
3364 // SpawnParticles(ob,GUTS,75);
3365 //MED
3366 SpawnParticles(ob,GUTS,150);
3367 MISCVARS->randgibspeed = false;
3368 }
3369 SpawnParticles(ob,GUTS,40);
3370 MISCVARS->directgibs = olddirect;
3371
3372 }
3373
3374 for (i=gt_head;i<=crazygibs;i++)
3375 {
3376
3377 if (((ob->obclass == dfiremonkobj) || (ob->obclass == deathmonkobj)) &&
3378 (i == gt_leg)
3379 )
3380 SpawnParticles(ob,gt_arm,1);
3381 else
3382 SpawnParticles(ob,i,1);
3383 }
3384
3385
3386 }
3387
3388
3389
3390
3391
Vicious_Annihilation(objtype * ob,objtype * attacker)3392 boolean Vicious_Annihilation(objtype *ob, objtype *attacker)
3393 {
3394 if ((ob->flags & FL_HBM) && (gamestate.violence >= vl_high))
3395 {
3396 ob->shapeoffset = 0;
3397 ob->flags &= ~FL_FULLLIGHT;
3398 NewState(ob,(ob->obclass == playerobj)?(&s_remoteguts1):(&s_guts1));
3399 SD_PlaySoundRTP(SD_ACTORSQUISHSND,ob->x,ob->y);
3400 if (gamestate.violence == vl_excessive)
3401 {
3402 int numgibs;
3403 objtype *prevlast;
3404
3405 numgibs = (GameRandomNumber("excessive guts",0) & 7) + 4;
3406 //SoftError("\nnumgibs = %d,gamestate.difficulty = %d",numgibs,gamestate.difficulty);
3407 prevlast = LASTACTOR;
3408 MISCVARS->fulllightgibs = true;
3409 SpawnParticles(ob,GUTS,numgibs);
3410 MISCVARS->fulllightgibs = false;
3411 for(prevlast = prevlast->next;prevlast;prevlast = prevlast->next)
3412 prevlast->momentumz += (prevlast->momentumz >> 1);
3413
3414 if ((GameRandomNumber("super gib chance",0) < 100) ||
3415 (ludicrousgibs == true)
3416 )
3417 {
3418 MISCVARS->directgibs = true;
3419 //MED
3420 MISCVARS->gibgravity = GRAVITY/2;
3421 // MISCVARS->gibgravity = GRAVITY*2;
3422 MISCVARS->fulllightgibs = true;
3423 SpawnSuperFatalityGibs(ob,attacker);
3424 MISCVARS->fulllightgibs = false;
3425 MISCVARS->gibgravity = -1;
3426 MISCVARS->directgibs = false;
3427 }
3428 }
3429 return true;
3430
3431 }
3432
3433
3434 if (ob->flags & FL_GODSTRUCK)
3435 {
3436 ob->shapeoffset = 0;
3437 ob->flags |= (FL_FULLLIGHT);
3438 ob->flags &= ~FL_COLORED;
3439 ob->momentumx = ob->momentumy = ob->momentumz = 0;
3440 KillActor(ob);
3441 NewState(ob,&s_vaporized1);
3442 return true;
3443 }
3444
3445 if (ob->flags & FL_SKELETON)
3446 {
3447 KillActor(ob);
3448 ob->shapeoffset = 0;
3449 ob->flags &= ~FL_COLORED;
3450 ob->momentumx = ob->momentumy = ob->momentumz = 0;
3451 NewState(ob,&s_skeleton1);
3452 SD_PlaySoundRTP(SD_ACTORBURNEDSND,ob->x,ob->y);
3453 return true;
3454 }
3455
3456 return false;
3457
3458 }
3459
3460
3461 /*
3462 ========================
3463 =
3464 = BeginEnemyFatality
3465 =
3466 ========================
3467 */
3468
3469
3470
BeginEnemyFatality(objtype * ob,objtype * attacker)3471 void BeginEnemyFatality(objtype *ob,objtype *attacker)
3472 {
3473
3474
3475 if ((attacker == player) && (ob->obclass < (NUMENEMIES + 2)))
3476 {
3477 GivePoints(starthitpoints[gamestate.difficulty][ob->obclass]*5);
3478 if (timelimitenabled)
3479 timelimit+=VBLCOUNTER;
3480 }
3481
3482 ob->flags |= FL_DYING;
3483 ob->soundhandle = -1;
3484
3485 #if 0
3486 if ((ob->obclass == blitzguardobj) &&
3487 (ob->state->condition & SF_DOWN)
3488 )
3489
3490 SD_Play(PlayerSnds[locplayerstate->player]);
3491 #endif
3492
3493 if (Vicious_Annihilation(ob,attacker))
3494 return;
3495
3496 if ((ob->obclass == patrolgunobj) && (ob->temp1 == -1))
3497 NewState(ob,&s_robogrddie1);
3498 else if (ob->obclass == collectorobj)
3499 {
3500 if ((!M_ISACTOR(attacker)) || (attacker->obclass != playerobj))
3501 RespawnEluder();
3502 else
3503 BATTLE_CheckGameStatus(battle_shot_deluder,attacker->dirchoosetime);
3504
3505 NewState(ob,&s_explosion1);
3506 MISCVARS->gibgravity = GRAVITY/2;
3507 MISCVARS->fulllightgibs = true;
3508 SpawnParticles(ob,gt_sparks,100);
3509 MISCVARS->fulllightgibs = false;
3510 MISCVARS->gibgravity = -1;
3511 }
3512 else
3513 {
3514 statetype *temp;
3515
3516 if ((ob->obclass == blitzguardobj) &&
3517 (ob->state->condition & SF_FAKING)
3518 )
3519 {
3520 NewState(ob,&s_blitzstruggledie1);
3521 ob->flags &= ~FL_FULLLIGHT;
3522 }
3523 else if
3524 ((ob->obclass == blitzguardobj) &&
3525 (ob->state->condition & SF_DOWN)
3526 )
3527 {
3528 NewState(ob,&s_blitzplead7);
3529 ob->flags &= ~FL_FULLLIGHT;
3530 }
3531
3532 else if
3533 ((temp= M_S(DIE)) != NULL)
3534 {
3535 if (LOW_VIOLENCE_DEATH_SHOULD_BE_SET(ob))
3536 SET_DEATH_SHAPEOFFSET(ob);
3537 NewState(ob,temp);
3538 ob->flags &= ~FL_FULLLIGHT;
3539 }
3540 else
3541 Error("Null dead state called in Collision, obclass %d",ob->obclass);
3542 }
3543
3544
3545 }
3546
3547
3548
3549 /*
3550 ========================
3551 =
3552 = BeginPlayerFatality
3553 =
3554 ========================
3555 */
3556
3557
3558
3559
BeginPlayerFatality(objtype * ob,objtype * attacker)3560 void BeginPlayerFatality(objtype *ob,objtype *attacker)
3561 {
3562 playertype *pstate;
3563 M_LINKSTATE(ob,pstate);
3564
3565
3566 ob->flags &= ~(FL_ELASTO|FL_GODMODE|FL_DOGMODE|FL_NOFRICTION|FL_RIDING);
3567
3568 ob->flags |= FL_DYING;
3569 pstate->weapon = -1;
3570
3571
3572 if (BATTLEMODE)
3573 SD_PlaySoundRTP (SD_PLAYERTCDEATHSND+(pstate->player),ob->x,ob->y);
3574
3575 if (Vicious_Annihilation(ob,attacker) == false)
3576 {
3577 if (LOW_VIOLENCE_DEATH_SHOULD_BE_SET(ob))
3578 SET_DEATH_SHAPEOFFSET(ob);
3579
3580 NewState(ob,&s_remotedie1);
3581 ob->flags &= ~FL_FULLLIGHT;
3582 }
3583
3584
3585
3586 }
3587
3588
3589
3590 /*
3591 ========================
3592 =
3593 = BeginEnemyHurt
3594 =
3595 ========================
3596 */
3597
3598
BeginEnemyHurt(objtype * ob)3599 void BeginEnemyHurt(objtype *ob)
3600 {
3601 statetype *temp;
3602
3603 if ((temp= M_S(COLLIDE1)) != NULL)
3604 {
3605
3606
3607 if ((ob->obclass == blitzguardobj) &&
3608 (ob->state->condition & SF_FAKING)
3609 )
3610 {
3611 ob->temp1 = 1;
3612 ob->dirchoosetime = 0;
3613 T_PlayDead(ob);
3614
3615 }
3616
3617 else
3618 {
3619 if ((ob->obclass == triadenforcerobj) &&
3620 (GameRandomNumber("george pain chance",0) <
3621 (50 + (gamestate.difficulty<<6))
3622 )
3623 )
3624 {
3625 ob->flags &= ~FL_FULLLIGHT;
3626 return;
3627
3628 }
3629
3630
3631 if (LOW_VIOLENCE_PAIN_SHOULD_BE_SET(ob))
3632 SET_PAIN_SHAPEOFFSET(ob);
3633
3634 if (GameRandomNumber("Collision",0) < 128)
3635 NewState(ob,temp);
3636 else
3637 NewState(ob,M_S(COLLIDE2));
3638 }
3639
3640 ob->flags &= ~FL_FULLLIGHT;
3641 ob->ticcount = PAINTIME;
3642 if (ob->obclass == strikeguardobj)
3643 ob->ticcount >>= 1;
3644 }
3645 }
3646
3647
Collision(objtype * ob,objtype * attacker,int hitmomentumx,int hitmomentumy)3648 void Collision(objtype*ob,objtype *attacker,int hitmomentumx,int hitmomentumy)
3649 {
3650 int ocl;
3651
3652 if ((!(ob->flags & FL_SHOOTABLE)) || (ob->flags & FL_DYING))
3653 return;
3654
3655 ocl = ob->obclass;
3656
3657 ob->momentumx += hitmomentumx;
3658 ob->momentumy += hitmomentumy;
3659
3660 if ((ocl == playerobj) && (gamestate.battlemode == battle_Eluder))
3661 return;
3662
3663 //insertion 5
3664
3665 if (ocl != playerobj)
3666 {
3667 if ((!(ob->flags & FL_ATTACKMODE)) && (TABLE_ACTOR(ob)))
3668 ActivateEnemy(ob);
3669
3670
3671 if (ob->hitpoints <= 0)
3672 BeginEnemyFatality(ob,attacker);
3673
3674 else if (ocl != roboguardobj)// && (ob->state->think != T_Collide))
3675 BeginEnemyHurt(ob);
3676 }
3677 else
3678 {
3679 playertype *pstate;
3680
3681 if ((ob->flags & FL_GODMODE) || (ob->flags & FL_DOGMODE) || godmode)
3682 return;
3683
3684 M_LINKSTATE(ob,pstate);
3685 if (pstate->health<=0)
3686 BeginPlayerFatality(ob,attacker);
3687 else
3688 ob->flags |= FL_PAIN;
3689
3690 }
3691
3692 }
3693
3694
3695
3696
T_BossExplosions(objtype * ob)3697 void T_BossExplosions(objtype*ob)
3698 {
3699
3700 if (ob->temp1)
3701 {if (ob->dirchoosetime)
3702 ob->dirchoosetime --;
3703 else
3704 {int randtime,randangle,randdist,sound;
3705 statetype *nstate;
3706
3707 ob->temp1 --;
3708 randtime = GameRandomNumber("Boss Explosion Time",0);
3709 ob->dirchoosetime = 10;
3710 if (randtime < 128)
3711 ob->dirchoosetime >>= 1;
3712 randangle = (GameRandomNumber("Boss Explosion Angle",0) << 3);
3713 randdist = (GameRandomNumber("Boss Explosion Distance",0) << 7)+0x4000;
3714 sound = SD_EXPLODEFLOORSND;
3715 if (randtime < 128)
3716 {nstate = &s_explosion1;
3717 sound++;
3718 }
3719 #if (SHAREWARE == 0)
3720 else
3721 nstate = &s_grexplosion1;
3722 #endif
3723
3724
3725 SpawnMissile(ob,inertobj,0,randangle,nstate,randdist);
3726 SD_PlaySoundRTP(sound,new->x,new->y);
3727 }
3728 }
3729 }
3730
3731
3732
3733
RandomGutsType(void)3734 gib_t RandomGutsType(void)
3735 {
3736 int rand = GameRandomNumber("gut random",0);
3737
3738
3739 if (rand < 128)
3740 return gt_organ;
3741
3742 //if (rand < 160)
3743 return gt_rib;
3744
3745 //return gt_pinkorgan;
3746
3747
3748 }
3749
3750
3751 //MED
SpawnParticles(objtype * ob,int which,int numparticles)3752 void SpawnParticles(objtype*ob,int which,int numparticles)
3753 {
3754 int randphi,randtheta,i,nspeed;
3755 boolean eyespawned = false;
3756 int gibtype;
3757 int randadj;
3758
3759
3760 if ((ob->z <= -64) && (sky == 0)) //shouldn't happen
3761 return;
3762
3763
3764 if (((which == GUTS) || (which == RANDOM)) && (gamestate.violence < vl_high))
3765 which = gt_sparks;
3766
3767 gibtype = which;
3768
3769
3770 for(i=0;i<numparticles;i++)
3771 {
3772 int ordertemp; /* DDOI - Watcom evaluates the mult order diff */
3773 randphi = (GameRandomNumber("particle generate phi",0) << 3);
3774 // randadj = RandomSign() * (GameRandomNumber("rand gib adjust",0) >> 4);
3775 ordertemp = (GameRandomNumber("rand gib adjust",0) >> 4);
3776 randadj = RandomSign() * ordertemp;
3777
3778
3779
3780 if (ob->z > (nominalheight - 32))
3781 randphi &= ((ANGLES/2) - 1);
3782
3783 randtheta = (GameRandomNumber("particle generate theta",0) << 3);
3784 nspeed = MISCVARS->gibspeed;
3785
3786
3787 if (which == RANDOM)
3788 {
3789 if (GameRandomNumber("random gib",0) < 128)
3790 gibtype = RandomGutsType();
3791 else
3792 gibtype = gt_sparks;
3793
3794 }
3795
3796 if ((which == GUTS) || (which == DISEMBOWEL))
3797 {
3798
3799 gibtype = RandomGutsType();
3800 if (which == DISEMBOWEL)
3801 {
3802 randphi>>=2;
3803 randtheta=ob->temp1+(randtheta>>3)-(randtheta>>4);
3804 }
3805
3806 }
3807
3808 if (lowmemory && (gibtype >= gt_rib) && (gibtype <= gt_limb))
3809 gibtype = gt_organ;
3810
3811 if
3812 (
3813 // (gibtype >= gt_organ) && (gibtype <= gt_limb) &&
3814 (MISCVARS->numgibs >= MAXGIBS)
3815 )
3816 return;
3817
3818
3819
3820 if (gibtype == gt_lsoul)
3821 {
3822 SpawnNewObj(ob->tilex,ob->tiley,&s_littlesoul,inertobj);
3823 randphi = 0;
3824 }
3825
3826
3827 #if (SHAREWARE == 0)
3828 else if (gibtype == gt_spit)
3829
3830 SpawnNewObj(ob->tilex,ob->tiley,&s_slop1,inertobj);
3831 #endif
3832 else
3833 {
3834 SpawnNewObj(ob->tilex,ob->tiley,&s_gibs1,inertobj);
3835 new->shapeoffset = gibtype*12;
3836 NewState(new,new->state);
3837 }
3838
3839 if (MISCVARS->directgibs == true)
3840 {
3841 int dx,dy,dz;
3842
3843 dx = PLAYER[0]->x - ob->x;
3844 dy = ob->y - PLAYER[0]->y;
3845 randtheta = AngleBetween(ob,PLAYER[0]) +
3846 (randadj<<4);
3847 dz = 100 + (randadj<<3);
3848
3849 //MED
3850 // nspeed = 0x2800 + (randadj<<7);
3851 nspeed = 0x2800;
3852
3853 randphi = atan2_appx(FindDistance(dx,dy),dz<<10);
3854 }
3855
3856
3857 if ((eyespawned == false) && (which == GUTS) &&
3858 (ob->obclass != playerobj)
3859 )
3860 {
3861 eyespawned = true;
3862 new->flags |= FL_EYEBALL;
3863 }
3864
3865 if ((gibtype >= gt_organ) && (gibtype <= gt_limb))
3866 {
3867 new->dirchoosetime = GIBVALUE;
3868 MISCVARS->numgibs ++;
3869 }
3870 new->temp2 = gibtype;
3871 new->temp3 = (MISCVARS->gibgravity == -1)?(GRAVITY):(MISCVARS->gibgravity);
3872
3873 new->speed = nspeed>>1;
3874 //if (MISCVARS->randgibspeed == true)
3875 // new->speed += (randadj << 11);
3876
3877 // if (ob->state == &s_snakefireworks)
3878 new->z = ob->z;
3879
3880 Fix(randphi);
3881 Fix(randtheta);
3882
3883 Set_3D_Momenta(new,new->speed,randtheta,randphi);
3884 new->momentumz <<= 6;
3885 new->flags |= (FL_NOFRICTION|FL_CRAZY|FL_ABP|FL_NEVERMARK);
3886 if (MISCVARS->fulllightgibs == true)
3887 new->flags |= FL_FULLLIGHT;
3888 new->dir = west;
3889 new->whatever = ob;
3890 MakeActive(new);
3891 }
3892 }
3893
3894
3895
T_SlideDownScreen(objtype * ob)3896 void T_SlideDownScreen(objtype *ob)
3897 {
3898
3899 ob->targettiley += 12;
3900 if (ob->targettiley > 300)
3901 {
3902 NewState(ob,&s_megaremove);
3903 SCREENEYE = NULL;
3904 }
3905
3906 }
3907
T_SpawnSoul(objtype * ob)3908 void T_SpawnSoul(objtype*ob)
3909 {
3910 if (ob->ticcount)
3911 return;
3912
3913 SpawnNewObj(ob->tilex,ob->tiley,&s_bigsoul,inertobj);
3914 new->momentumz = -4000;
3915 new->flags |= (FL_NOFRICTION|FL_CRAZY|FL_ABP|FL_NEVERMARK);
3916 new->z = ob->z;
3917 new->dir = west;
3918 MakeActive(new);
3919
3920 SpawnParticles(ob,gt_lsoul,6);
3921
3922
3923 }
3924
3925
BloodDrip(objtype * ob,int tilex,int tiley)3926 void BloodDrip(objtype *ob,int tilex,int tiley)
3927 {int dx,dy,x,y,scale;
3928
3929 dx = ob->tilex - tilex;
3930 dy = ob->tiley - tiley;
3931
3932 if (!dy)
3933 {
3934 scale = (ob->momentumx)?(FixedDiv2(ob->momentumy,ob->momentumx)):(0);
3935 x = (dx < 0)?(tilex << 16):((tilex+1) << 16);
3936 y = FixedMul(x - ob->x,scale) + ob->y;
3937 }
3938
3939 else if (!dx)
3940 {
3941 scale = (ob->momentumy)?(FixedDiv2(ob->momentumx,ob->momentumy)):(0);
3942 y = (dy < 0)?(tiley << 16):((tiley+1) << 16);
3943 x = FixedMul(y - ob->y,scale) + ob->x;
3944 }
3945
3946 ob->temp2 = (GameRandomNumber("BloodDrip",0) << 9) + 0xc000;
3947 ob->temp1 = (ob->z<<16);
3948 SetFinePosition(ob,x,y);
3949 ob->shapeoffset = 0;
3950 NewState(ob,&s_blooddrip1);
3951
3952 }
3953
3954
3955
T_BloodFall(objtype * ob)3956 void T_BloodFall(objtype*ob)
3957 {
3958 ob->temp1 += ob->temp2;
3959 ob->z = (ob->temp1 >> 16);
3960 if (ob->z >= maxheight)
3961 {
3962 ob->shapeoffset = 12;
3963 MISCVARS->numgibs--;
3964 NewState(ob,&s_gibsdone1);
3965 ob->z = nominalheight;
3966 }
3967
3968 }
3969
3970
3971
3972
T_Xylophone(objtype * ob)3973 void T_Xylophone(objtype*ob)
3974 {
3975 if (!ob->ticcount)
3976 SD_PlaySoundRTP(SD_ACTORSKELETONSND,ob->x,ob->y);
3977 }
3978
3979
3980
T_ParticleGenerate(objtype * ob)3981 void T_ParticleGenerate(objtype*ob)
3982 {
3983
3984 if (ob->dirchoosetime)
3985 ob->dirchoosetime--;
3986 else
3987 {
3988 SetGibSpeed(0x3000);
3989 SpawnParticles(ob,gt_sparks,(GameRandomNumber("particle count",0) % 10) + 7);
3990 ResetGibSpeed();
3991 ob->dirchoosetime = 10;
3992 if (GameRandomNumber("particle generator choose time",0) < 128)
3993 ob->dirchoosetime >>= 1;
3994 }
3995
3996 }
3997
3998
3999
T_Particle(objtype * ob)4000 void T_Particle(objtype*ob)
4001 {int dx,dy,dz;
4002
4003 ob->z += (ob->momentumz>>16);
4004
4005 if ((ob->z >= nominalheight) || (!ob->momentumz))
4006
4007 {
4008 if (ob->z >= nominalheight)
4009 ob->z = nominalheight;
4010 //done:
4011 if (ob->temp2 == gt_spit)
4012 ob->state = NULL;
4013 else
4014 {
4015 if (ob->dirchoosetime == GIBVALUE)
4016 {
4017 MISCVARS->numgibs--;
4018 SD_PlaySoundRTP(GIBSOUND,ob->x,ob->y);
4019 }
4020 NewState(ob,&s_gibsdone1);
4021 }
4022 return;
4023 }
4024 else if ((ob->z < -64) && (sky == 0))
4025 {
4026 ob->momentumz = 1; //any positive value will do
4027 ob->z = -64;
4028
4029 }
4030
4031
4032 ob->momentumz += ob->temp3;
4033 ActorMovement(ob);
4034
4035
4036 if (!BATTLEMODE)
4037 {
4038 dx = abs(ob->x - PLAYER[0]->x);
4039 dy = abs(ob->y - PLAYER[0]->y);
4040 dz = abs(ob->z - PLAYER[0]->z);
4041
4042 #if (SHAREWARE==0)
4043 if ((ob->flags & FL_EYEBALL) && (dx < 0x20000) && (dy < 0x20000) &&
4044 (dz < 64) && (GameRandomNumber("eye chance",0) < 15) &&
4045 (SCREENEYE == NULL) && (locplayerstate->weapon != wp_dog)
4046 )
4047 #else
4048 if ((ob->flags & FL_EYEBALL) && (dx < 0x20000) && (dy < 0x20000) &&
4049 (dz < 64) && (GameRandomNumber("eye chance",0) < 15) &&
4050 (SCREENEYE == NULL)
4051 )
4052 #endif
4053 SpawnScreenEye(ob);
4054 }
4055
4056 //MoveActor(ob);
4057 //if ((!ob->momentumx) && (!ob->momentumy))
4058 //goto done;
4059
4060
4061 }
4062
4063
4064
DropItemInEmptyTile(int item,int tilex,int tiley)4065 void DropItemInEmptyTile(int item,int tilex,int tiley)
4066 {
4067 int stilex = tilex;
4068 int stiley = tiley;
4069
4070 FindEmptyTile(&stilex,&stiley);
4071 SpawnStatic(stilex,stiley,item,9);
4072 LASTSTAT->flags |= FL_ABP;
4073 MakeStatActive(LASTSTAT);
4074
4075 }
4076
4077
KillActor(objtype * ob)4078 void KillActor(objtype*ob)
4079 {int ocl;
4080
4081 ocl = ob->obclass;
4082
4083
4084 //GivePoints(starthitpoints[gamestate.difficulty][ob->obclass]*5);
4085 if ((ocl == highguardobj) &&
4086 (GameRandomNumber("Drop mp40 chance",0) < 25))
4087 {
4088 DropItemInEmptyTile(stat_mp40,ob->tilex,ob->tiley);
4089 }
4090
4091 else if ((ocl == blitzguardobj) && (ob->temp3))
4092 {
4093 DropItemInEmptyTile(ob->temp3,ob->tilex,ob->tiley);
4094 LASTSTAT->ammo = ob->temp2;
4095 }
4096
4097 if (actorat[ob->tilex][ob->tiley] == (void*)ob)
4098 actorat[ob->tilex][ob->tiley] = NULL;
4099
4100 gamestate.killcount++;
4101 ob->flags &= ~FL_SHOOTABLE;
4102 ob->flags &= ~FL_BLOCK;
4103 ob->flags |= FL_NEVERMARK;
4104 #if (SHAREWARE == 0)
4105 if (ocl == b_darksnakeobj)
4106 {if (ob == SNAKEHEAD)
4107 {SpawnNewObj(ob->tilex,ob->tiley,&s_megaexplosions,inertobj);
4108 new->temp1 = 7000;
4109 new->flags |= FL_ABP;
4110 EXPLOSIONS = new;
4111 NewState(ob,&s_darkmonkheaddie1);
4112 MakeActive(new);
4113 ob->dirchoosetime = 0;
4114
4115 }
4116 else
4117 {objtype *temp;
4118
4119 SNAKEEND = (objtype*)(ob->target);
4120 SNAKEEND->whatever = NULL;
4121 NewState(ob,&s_explosion1);
4122 for(temp=SNAKEHEAD;temp;temp = (objtype*)(temp->whatever))
4123 temp->speed += 0x500;
4124 }
4125 }
4126 else
4127 #endif
4128 {ob->whatever = NULL;
4129 if (ob->obclass!=playerobj)
4130 ob->target = NULL;
4131 }
4132
4133 if ((ob->flags & FL_KEYACTOR) && (ocl!=playerobj) && (ocl != blitzguardobj))
4134 {MISCVARS->KEYACTORSLEFT --;
4135 if (!MISCVARS->KEYACTORSLEFT)
4136 {SpawnNewObj(ob->tilex,ob->tiley,&s_timekeeper,inertobj);
4137 new->flags |= FL_ABP;
4138 MakeActive(new);
4139 }
4140 }
4141
4142 }
4143
4144
T_End(objtype * ob)4145 void T_End(objtype *ob)
4146 {
4147 if (ob->ticcount)
4148 return;
4149
4150 if (MAPSPOT(0,5,2) == LASTLEVELVALUE)
4151 playstate = ex_gameover;
4152 else
4153 playstate = ex_bossdied;
4154
4155 }
4156
4157
4158
T_Convert(objtype * ob)4159 void T_Convert(objtype*ob)
4160 {
4161 if (ob->ticcount)
4162 return;
4163
4164 if (ob->obclass == playerobj)
4165 {
4166 if (ob->state == &s_vaporized8)
4167 {
4168 T_SpawnSoul(ob);
4169 NewState(ob,&s_voidwait);
4170 }
4171 else if (ob->state == &s_skeleton48)
4172 {
4173 playertype *pstate;
4174
4175 M_LINKSTATE(ob,pstate);
4176 if ((pstate->falling == true) ||
4177 (!ob->momentumz)
4178 )
4179 NewState(ob,&s_ashwait);
4180 else
4181 CheckPlayerSpecials(ob);
4182
4183
4184 }
4185 }
4186 else
4187 {
4188 if (ob->state == &s_vaporized8)
4189 T_SpawnSoul(ob);
4190 else if (ob->state == &s_skeleton48)
4191 TurnActorIntoSprite(ob);
4192 }
4193 }
4194
TurnActorIntoSprite(objtype * ob)4195 void TurnActorIntoSprite(objtype *ob)
4196 {statobj_t*temp;
4197 objtype *tactor;
4198
4199
4200 if (!firstemptystat)
4201 temp = (statobj_t*)Z_LevelMalloc(sizeof(statobj_t),PU_LEVELSTRUCT,NULL);
4202
4203 else
4204 {temp = lastemptystat;
4205 //SoftError("\nfree actor available");
4206 RemoveFromFreeStaticList(lastemptystat);
4207 }
4208
4209
4210 if (temp)
4211 {
4212 if ((ob->obclass == blitzguardobj) &&
4213 ((ob->flags & FL_PLEADING) || (ob->flags & FL_UNDEAD))
4214 )
4215 MISCVARS->NUMBEGGINGKEVINS = 0;
4216
4217
4218 if (ob->obclass == roboguardobj)
4219 {for(tactor=firstareaactor[ob->areanumber];tactor;tactor=tactor->nextinarea)
4220 {if (tactor == ob)
4221 continue;
4222 if (tactor->obclass != ob->obclass)
4223 continue;
4224
4225 if (tactor->flags & FL_DYING)
4226 continue;
4227 if (!tactor->state->think)
4228 NewState(tactor,UPDATE_STATES[PATH][tactor->obclass-lowguardobj]);
4229
4230 }
4231 }
4232
4233 memset(temp,0,sizeof(*temp));
4234 temp->shapenum = ob->shapenum;
4235 temp->linked_to = -1;
4236 temp->whichstat = statcount ++;
4237 SetFinePosition(temp,ob->x,ob->y);
4238 temp->areanumber = MAPSPOT(temp->tilex,temp->tiley,0)-AREATILE;
4239 // if ((temp->areanumbers<=0) || (temp->areanumber>NUMAREAS))
4240 // Error ("Sprite at x=%ld y=%ld type=%ld has an illegal areanumber\n",tilex,tiley,mtype);
4241
4242 temp->visspot = &spotvis[temp->tilex][temp->tiley];
4243 temp->which = SPRITE;
4244 temp->itemnumber = -1;
4245 temp->flags = FL_DEADBODY;
4246 if (ob->flags & FL_COLORED)
4247 {playertype *pstate;
4248
4249 M_LINKSTATE(ob,pstate);
4250 temp->flags |= FL_COLORED;
4251 temp->hitpoints = pstate->uniformcolor;
4252 }
4253 temp->z = ob->z;
4254 AddStatic(temp);
4255 // sprites[temp->tilex][temp->tiley] = temp;
4256
4257 if (areabyplayer[temp->areanumber])
4258 {temp->flags |= FL_ABP;
4259 MakeStatActive(temp);
4260 }
4261 if (ob->state != &s_guts12)
4262 actorat[ob->tilex][ob->tiley] = temp;
4263 ob->state = NULL; // say goodbye actor
4264 }
4265 else
4266 Error("Z_LevelMalloc failed in TurnActorIntoSprite!");
4267
4268 }
4269
4270
T_Blood(objtype * ob)4271 void T_Blood(objtype*ob)
4272 {
4273 if (ob->dirchoosetime)
4274 {ob->dirchoosetime --;
4275 return;
4276 }
4277
4278 ob->dirchoosetime = 35 + (GameRandomNumber("blood time",0) % 20);
4279 NewState(ob,&s_deadblood1);
4280
4281 }
4282
4283
4284
4285
ActorDeath(objtype * ob)4286 void ActorDeath(objtype*ob)
4287 {
4288 #if (SHAREWARE == 0)
4289 if (ob->obclass == b_heinrichobj)
4290 {
4291 KillActor(ob);
4292 ob->temp1 = ob->dirchoosetime = 5;//10; // init. spin counter for heinrich
4293 ob->temp3 = 7; //number of times to stay at fast spin
4294 ob->temp2 = ob->dir; //temp2 holds orig. dir.
4295 }
4296
4297 else if (ob->obclass == b_robobossobj)
4298 {
4299 objtype *wheels,*head;
4300
4301
4302 head = (objtype*)(ob->whatever);
4303 wheels = (objtype*)(ob->target);
4304 head->flags &= ~(FL_HEAD|FL_SHOOTABLE|FL_BLOCK);
4305 head->temp2 = 5;
4306 head->flags |= (FL_NOFRICTION|FL_CRAZY);
4307 // head->obclass = inertobj;
4308 //RemoveObj(wheels); // remove wheels
4309 KillActor(ob);
4310 ob->whatever = head;
4311 ob->target = wheels;
4312 //ob->temp1 = 25;
4313 //ob->shapeoffset = 0;
4314 SpawnNewObj(ob->tilex,ob->tiley,&s_megaexplosions,inertobj);
4315 new->temp1 = 18;
4316 new->flags |= FL_ABP;
4317 MakeActive(new);
4318 //ob->state = NULL;
4319 NewState(ob,&s_NMEdeathbuildup);
4320 }
4321 else
4322 #endif
4323 if ((ob->state == ob->state->next) &&
4324 (ob->flags & FL_DYING)
4325 )
4326 {
4327 KillActor(ob);
4328 TurnActorIntoSprite(ob);
4329 if (LASTSTAT->z < nominalheight)
4330 {
4331 if ((!IsPlatform(LASTSTAT->tilex,LASTSTAT->tiley)) &&
4332 (DiskAt(LASTSTAT->tilex,LASTSTAT->tiley) == NULL)
4333 )
4334 {
4335 SpawnParticles(ob,GUTS,10 + gamestate.difficulty);
4336 RemoveStatic(LASTSTAT);
4337 }
4338 }
4339 /*
4340 else if ((GameRandomNumber("blood spray",0) < 300) && areabyplayer[ob->areanumber])
4341 {ob->shapeoffset = 0;
4342 ob->temp2 = ob->temp3 = 0;
4343 ob->temp1 = 10;
4344 NewState(ob,&s_deadblood1);
4345 return;
4346 }
4347 */
4348 }
4349 }
4350
4351
4352
4353
BeginPostPainAction(objtype * ob)4354 void BeginPostPainAction(objtype *ob)
4355 {
4356
4357 if ((ob->obclass == strikeguardobj) &&
4358 (ob->target == (void*)PLAYER[0])
4359 )
4360 {//ob->target = NULL;
4361 if (LOW_VIOLENCE_DEATH_IS_SET(ob))
4362 RESET_DEATH_SHAPEOFFSET(ob);
4363
4364 if (GameRandomNumber("T_Collide",0) < 128)
4365 NewState(ob,&s_strikerollright1);
4366 else
4367 NewState(ob,&s_strikerollleft1);
4368
4369 SelectRollDir(ob);
4370
4371 if (ob->dirchoosetime)
4372 {
4373 SD_PlaySoundRTP(SD_STRIKEROLLSND,ob->x,ob->y);
4374 return;
4375 }
4376
4377 }
4378
4379 if (LOW_VIOLENCE_PAIN_IS_SET(ob))
4380 RESET_PAIN_SHAPEOFFSET(ob);
4381
4382 if (ob->obclass < roboguardobj)
4383 ob->flags &= ~FL_NOFRICTION;
4384
4385 if (
4386 (ob->obclass == blitzguardobj) &&
4387 (gamestate.violence == vl_excessive) &&
4388 (GameRandomNumber("blitzplead",0) < 128) &&
4389 (MISCVARS->NUMBEGGINGKEVINS == 0) &&
4390 (ob->flags & FL_TARGET) &&
4391
4392 (ob->hitpoints < (starthitpoints[gamestate.difficulty][ob->obclass] >> 1)) &&
4393 (ob->momentumz == 0) &&
4394 (!(ob->flags & FL_UNDEAD))
4395 )
4396
4397 {
4398 NewState(ob,&s_blitzplead1);
4399 MISCVARS->NUMBEGGINGKEVINS = 1;
4400 ob->momentumx = ob->momentumy = 0;
4401 ob->flags |= FL_PLEADING;
4402 ob->flags &= ~FL_TARGET;
4403 ob->dirchoosetime = 165;
4404 ob->hitpoints = 1;
4405 }
4406
4407 else
4408 {
4409 NewState(ob,M_S(CHASE));
4410 ob->targettilex = ob->targettiley = 0;
4411 ob->dirchoosetime = 0;
4412 }
4413
4414 }
4415
4416
4417
T_Collide(objtype * ob)4418 void T_Collide(objtype*ob)
4419 {
4420 if (!(ob->flags & FL_SHOOTABLE))
4421 return;
4422
4423 ActorMovement(ob);
4424
4425 if (ob->state == NULL)
4426 return;
4427
4428 if (ob->ticcount)
4429 return;
4430
4431 if (ob->hitpoints <= 0)
4432 {
4433
4434 if ((ob->soundhandle == -1) &&
4435 (!ob->ticcount) &&
4436 (ob->state->next->tictime == 0)
4437 )
4438 {
4439 ob->soundhandle = SD_PlaySoundRTP(ACTORTHUDSND,ob->x,ob->y);
4440
4441 }
4442
4443 if (ob->momentumx || ob->momentumy || ob->momentumz)
4444 return;
4445
4446 ActorDeath(ob);
4447 return;
4448 }
4449
4450 BeginPostPainAction(ob);
4451
4452 }
4453
4454
4455
4456 /*
4457 =========================================================================
4458 =
4459 = Special Blitzguard Functions
4460 =
4461 =========================================================================
4462 */
4463
4464
4465 /*
4466 =================
4467 =
4468 = T_Plead
4469 =
4470 =================
4471 */
4472
4473
4474
T_Plead(objtype * ob)4475 void T_Plead(objtype*ob)
4476 {
4477 int handle;
4478
4479 ActorMovement(ob);
4480 if (ob->dirchoosetime)
4481 {
4482 if (!(ob->dirchoosetime & 31))
4483 {
4484 int random = GameRandomNumber("blitz plead sound",0);
4485 if (random < 80)
4486 SD_PlaySoundRTP(SD_BLITZPLEADSND,ob->x,ob->y);
4487 else if (random < 160)
4488 SD_PlaySoundRTP(SD_BLITZPLEAD1SND,ob->x,ob->y);
4489 else
4490 SD_PlaySoundRTP(SD_BLITZPLEAD2SND,ob->x,ob->y);
4491 }
4492 ob->dirchoosetime --;
4493 return;
4494 }
4495 ob->hitpoints = (starthitpoints[gamestate.difficulty][blitzguardobj]>>1);
4496 //ob->flags |= FL_DYING;
4497 ob->flags |= FL_UNDEAD;
4498 SET_DEATH_SHAPEOFFSET(ob);
4499 NewState(ob,&s_blitzfakedie1);
4500 ob->flags &= ~FL_PLEADING;
4501 ob->dirchoosetime = (GameRandomNumber("blitz fake time",0) >> 2) + 70;
4502 handle = SD_PlaySoundRTP(SD_BLITZOUCHSND,ob->x,ob->y);
4503 SD_SetSoundPitch (handle,-500);
4504 ob->temp1 = 0;
4505 ob->temp1 = (GameRandomNumber("blitz visible rise",0) < 60);
4506
4507 }
4508
4509
4510
4511 /*
4512 =================
4513 =
4514 = T_ReallyDead
4515 =
4516 =================
4517 */
4518
4519
T_ReallyDead(objtype * ob)4520 void T_ReallyDead(objtype *ob)
4521 {
4522 ActorMovement(ob);
4523 if ((!ob->ticcount) && (LOW_VIOLENCE_DEATH_SHOULD_BE_SET(ob)))
4524 SET_DEATH_SHAPEOFFSET(ob);
4525
4526
4527 }
4528
4529
4530
4531 /*
4532 =================
4533 =
4534 = T_PlayDead
4535 =
4536 =================
4537 */
4538
4539
4540
T_PlayDead(objtype * ob)4541 void T_PlayDead(objtype *ob)
4542 {
4543 int dangle;
4544
4545 ob->flags &= ~FL_DYING;
4546
4547 ActorMovement(ob);
4548 if (ob->dirchoosetime)
4549 {
4550 ob->dirchoosetime--;
4551 return;
4552 }
4553
4554 dangle = abs(player->angle - AngleBetween(player,ob));
4555 if (dangle > ANGLES/2)
4556 dangle = ANGLES - dangle;
4557
4558 if (ob->temp1 || (dangle > ANGLES/4))
4559 {
4560 if (LOW_VIOLENCE_DEATH_IS_SET(ob))
4561 RESET_DEATH_SHAPEOFFSET(ob);
4562 ob->temp1 = 0;
4563
4564 NewState(ob,&s_blitzrise2);
4565
4566 }
4567
4568 }
4569
4570
AdjustAngle(int maxadjust,short int * currangle,int targetangle)4571 void AdjustAngle(int maxadjust, short int *currangle,int targetangle)
4572 {
4573 int dangle,i,magangle;
4574
4575 for(i=0;i<maxadjust;i++)
4576 {
4577 dangle = *currangle - targetangle;
4578
4579 if (dangle)
4580 {
4581 magangle = abs(dangle);
4582 if (magangle > (ANGLES/2))
4583 {
4584 if (dangle > 0)
4585 (*currangle) ++;
4586 else
4587 (*currangle) --;
4588 }
4589 else
4590 {
4591 if (dangle > 0)
4592 (*currangle) --;
4593 else
4594 (*currangle) ++;
4595 }
4596 Fix(*currangle);
4597 }
4598 }
4599 }
4600
4601
ResolveMinimumDistance(objtype * heatseeker,objtype * potential_target,int * currmin)4602 void ResolveMinimumDistance(objtype *heatseeker, objtype *potential_target,
4603 int *currmin)
4604 {
4605 int currdist,angle,magangle;
4606
4607
4608 currdist = FindDistance((heatseeker->x-potential_target->x),
4609 (heatseeker->y-potential_target->y));
4610 angle = AngleBetween(heatseeker,potential_target);
4611
4612
4613 if (heatseeker->obclass != p_godballobj)
4614 {
4615 magangle = abs(heatseeker->angle - angle);
4616 if (magangle > VANG180)
4617 magangle = ANGLES - magangle;
4618 if (magangle > ANGLESDIV8)
4619 return;
4620 }
4621
4622 if (currdist > LOOKAHEAD)
4623 return;
4624
4625 if (currdist < (*currmin))
4626 {
4627 *currmin = currdist;
4628 heatseeker->target = potential_target;
4629 }
4630 }
4631
4632
4633
4634
HeatSeek(objtype * ob)4635 void HeatSeek(objtype*ob)
4636 {int xydist;
4637
4638 int mindist;
4639 objtype* tactor;
4640 objtype* owner;
4641 statobj_t* tstat;
4642 int angle,dz,yzangle,adjust;
4643 int dx,dy;
4644
4645
4646 owner=(objtype *)ob->whatever;
4647
4648 if (ob->dirchoosetime)
4649 ob->dirchoosetime --;
4650
4651 else
4652 {
4653 if (!ob->target)
4654 {mindist = 0x7fffffff;
4655
4656 for (tactor=firstactive;tactor;tactor=tactor->nextactive)
4657 {
4658 if (tactor == owner)
4659 continue;
4660
4661 if (tactor->flags & FL_HEAD)
4662 continue;
4663
4664 if ((tactor == ob) ||
4665 (!(tactor->flags & FL_SHOOTABLE)) ||
4666 (tactor->flags & FL_DYING))
4667 continue;
4668
4669 if (!CheckLine(ob,tactor,SIGHT))
4670 continue;
4671
4672 if ((tactor->obclass == bladeobj) || (tactor->obclass == NMEsaucerobj))
4673 continue;
4674
4675
4676 ResolveMinimumDistance(ob,tactor,&mindist);
4677
4678 }
4679
4680 if (ob->obclass != p_godballobj)
4681 {
4682 for(tstat=firstactivestat;tstat;tstat=tstat->nextactive)
4683 {
4684 if (!(tstat->flags & FL_HEAT))
4685 continue;
4686
4687 if (!CheckLine(ob,tstat,SHOOT))
4688 continue;
4689
4690 ResolveMinimumDistance(ob,(objtype*)tstat,&mindist);
4691 }
4692 }
4693
4694
4695 if (!ob->target)
4696 ob->dirchoosetime = 5;
4697 }
4698
4699 else //if (ob->target != owner)
4700 {
4701 tactor = (objtype*)ob->target;
4702
4703 if ((!tactor->nextactive) && (!tactor->prevactive))
4704 {
4705 ob->target = NULL;
4706 return;
4707 }
4708 dx = tactor->x - ob->x;
4709 dy = ob->y - tactor->y;
4710 dz = ob->z - tactor->z;
4711 //xydist = FixedSqrtHP((FixedMul(dx,dx) + FixedMul(dy,dy))>>16);
4712 xydist = FindDistance(dx,dy);
4713 angle = atan2_appx(dx,dy);
4714 adjust = (ob->obclass == p_godballobj)?(GODHAPT):(HAAPT);
4715 AdjustAngle(adjust,&(ob->angle),angle);
4716 ob->dir = angletodir[ob->angle];
4717 ob->momentumx = FixedMul(ob->speed,costable[ob->angle]);
4718 ob->momentumy = -FixedMul(ob->speed,sintable[ob->angle]);
4719
4720 yzangle = atan2_appx(xydist,(dz<<10));
4721 adjust = (ob->obclass == p_godballobj)?(GODVAPT):(VAAPT);
4722 AdjustAngle(adjust,&(ob->yzangle),yzangle);
4723 ob->momentumz = -(FixedMul(ob->speed,sintable[ob->yzangle]));
4724
4725 }
4726 }
4727
4728 }
4729
4730
Stagger(objtype * ob)4731 void Stagger(objtype*ob)
4732 {
4733 int randadj;
4734
4735
4736 randadj = (int)(GameRandomNumber("Stagger",1) >> 3);
4737
4738 if (!ob->dirchoosetime)
4739 {
4740 ob->momentumz = ob->temp1 + (RandomSign() << 12);
4741 ob->dirchoosetime = 6;
4742 }
4743 else
4744 ob->dirchoosetime --;
4745
4746 if ((ob->z + (ob->momentumz >> 10)) > (maxheight-12))
4747 ob->momentumz = -ob->momentumz;
4748 else if ((ob->z < 5) && (!sky))
4749 ob->z = 5;
4750
4751 ob->angle += (RandomSign()*randadj);
4752 Fix(ob->angle);
4753 ob->momentumx = FixedMul(ob->speed,costable[ob->angle]);
4754 ob->momentumy = -FixedMul(ob->speed,sintable[ob->angle]);
4755 ob->dir = angletodir[ob->angle];
4756
4757 }
4758
4759
4760
4761
SpawnSplit(objtype * ob,int angle)4762 void SpawnSplit(objtype *ob,int angle)
4763 {
4764 Fix(angle);
4765 SpawnMissile(ob,p_heatseekobj,ob->speed,angle,&s_p_bazooka1,0x4000);
4766 new->momentumz = ob->momentumz;
4767 new->whatever = ob->whatever;
4768
4769 }
4770
4771
4772
SplitMissile(objtype * ob)4773 void SplitMissile(objtype*ob)
4774 {
4775
4776 SD_PlaySoundRTP(SD_SPLITSND,ob->x,ob->y);
4777 if (ob->soundhandle != -1)
4778 SD_StopSound(ob->soundhandle);
4779
4780 SpawnSplit(ob,ob->angle + ANGLES/12);
4781 SpawnSplit(ob,ob->angle - ANGLES/12);
4782
4783 if (missobj == ob)
4784 {
4785 if (GameRandomNumber("split misscam",0)<128)
4786 missobj = LASTACTOR;
4787 else
4788 missobj = LASTACTOR->prev;
4789 }
4790
4791 ob->state=NULL; // get rid of current missile
4792
4793 }
4794
4795
4796
4797
SpawnMissileSmoke(objtype * ob)4798 void SpawnMissileSmoke(objtype *ob)
4799 {
4800 if (!ValidAreanumber(AREANUMBER(ob->tilex,ob->tiley)))
4801 return;
4802
4803 SpawnStatic(ob->tilex,ob->tiley,stat_missmoke,-1);
4804 LASTSTAT->flags |= FL_ABP;
4805 MakeStatActive(LASTSTAT);
4806 SetFinePosition(LASTSTAT,ob->x,ob->y);
4807 LASTSTAT->z = ob->z+3;
4808
4809 }
4810
4811
T_Projectile(objtype * ob)4812 void T_Projectile (objtype *ob)
4813 {
4814 objtype *owner;
4815 playertype * pstate;
4816
4817 owner = (objtype*)(ob->whatever);
4818
4819 if (owner->obclass == playerobj)
4820 M_LINKSTATE(owner,pstate);
4821
4822 if ((ob->soundhandle != -1) &&
4823 (!(oldpolltime & 7))
4824 )
4825 SD_PanRTP(ob->soundhandle,ob->x,ob->y);
4826 #if (SHAREWARE == 0)
4827 if (ob->obclass == h_mineobj)
4828 {
4829 if (!ob->dirchoosetime)
4830 {
4831 NewState(ob,&s_grexplosion1);
4832 SD_PlaySoundRTP(SD_KRISTMINEHITSND,ob->x,ob->y);
4833 }
4834 else
4835 ob->dirchoosetime --;
4836 if (
4837 (ob->state == &s_mine1) &&
4838 (!ob->ticcount)
4839 )
4840 SD_PlaySoundRTP(BAS[ob->obclass].operate,ob->x,ob->y);
4841
4842 }
4843 #endif
4844
4845
4846 if (!ob->ticcount)
4847 {
4848 if (ob->state == &s_p_grenade)
4849 ob->momentumz += (GRAVITY>>6);
4850 else if
4851 (ob->state == &s_grenade_fall6)
4852 {
4853 NewState(ob,&s_explosion1);
4854 return;
4855 }
4856 }
4857
4858
4859
4860
4861 if (ob->obclass == p_drunkmissileobj)
4862 {
4863 if (ob->temp3 > 0)
4864 {
4865 ob->temp3 --;
4866 Stagger(ob);
4867 }
4868 else
4869 {
4870 if (ob->target == NULL)
4871 Stagger(ob);
4872 HeatSeek(ob);
4873 }
4874
4875 }
4876
4877 else if (ob->temp1 == NME_DRUNKTYPE)
4878
4879 Stagger(ob);
4880
4881
4882 else if ((ob->obclass == p_heatseekobj) ||
4883 (ob->obclass == dm_heatseekobj) ||
4884 (ob->temp1 == NME_HEATSEEKINGTYPE) ||
4885 (ob->obclass == p_godballobj)
4886 )
4887 HeatSeek(ob);
4888
4889
4890 else if
4891 ((ob->obclass == p_splitmissileobj) &&
4892 (!pstate->buttonstate[bt_attack])
4893 )
4894 {
4895 SplitMissile(ob);
4896 return;
4897 }
4898
4899
4900
4901
4902 if ((!BATTLEMODE) &&
4903 (!(ob->ticcount & 7)) &&
4904 (ob->obclass != p_firewallobj) &&
4905 (ob->obclass != p_kesobj) &&
4906 (ob->obclass != p_godballobj) &&
4907 ((ob->obclass >= p_bazookaobj) || (ob->obclass == missileobj))
4908 )// &&
4909
4910 SpawnMissileSmoke(ob);
4911
4912 MissileMovement(ob);
4913
4914 if (ob->obclass == grenadeobj)
4915
4916 {
4917 if (ob->temp1 > 0)
4918 ob->temp1 -= ob->speed;
4919 else if (!(ob->flags & FL_DONE))
4920 {
4921 NewState(ob,&s_grenade_fall1);
4922 ob->flags |= FL_DONE;
4923 }
4924 }
4925 }
4926
4927
4928
StartFirewall(objtype * ob,int newz)4929 void StartFirewall(objtype*ob, int newz)
4930 {
4931 objtype *owner = (objtype*)(ob->whatever);
4932
4933 MISCVARS->firespawned = 0;
4934 owner->temp1 = 0;
4935 SpawnFirewall(ob,2,newz);
4936 if (missobj == ob)
4937 missobj = LASTACTOR;
4938 NewState(ob,&s_megaremove);
4939
4940 }
4941
4942
4943
MissileMovement(objtype * ob)4944 void MissileMovement(objtype*ob)
4945 {int tryx, tryy,tryz;
4946
4947 tryx = ob->x + ob->momentumx;
4948 tryy = ob->y + ob->momentumy;
4949 tryz = ob->z + (ob->momentumz >> 10);
4950 if (!MissileTryMove (ob, tryx, tryy, tryz))
4951 return;
4952 ob->z += (ob->momentumz >> 10);
4953 MoveActor(ob);
4954 }
4955
4956
4957
4958 #define DetonateMissile(x,y) \
4959 {MissileHit(x,y); \
4960 return false; \
4961 } \
4962
4963 #define QuietDetonate(ob) \
4964 { \
4965 if (ob->soundhandle != -1) \
4966 SD_StopSound(ob->soundhandle); \
4967 if (ob == missobj) \
4968 missobj = NULL; \
4969 NewState(ob,&s_megaremove); \
4970 return false; \
4971 }
4972
MissileTryMove(objtype * ob,int tryx,int tryy,int tryz)4973 boolean MissileTryMove(objtype*ob,int tryx,int tryy,int tryz)
4974 {
4975 int tilexlow,tileylow,tilexhigh,tileyhigh,x,y,
4976 trytilex,trytiley,dx,dy,dzt,dztp1,radius,
4977 sprrad,actrad,tcl,ocl,oldsrad,area,zdist,
4978 wall;
4979
4980 objtype *temp;
4981 wall_t *tempwall;
4982 doorobj_t *tempdoor;
4983 int doorn;
4984 statobj_t *tempstat;
4985 boolean areatried[NUMAREAS] = {0};
4986
4987 sprrad = 0x4500;
4988 actrad = ACTORSIZE+0x2800;
4989 ocl = ob->obclass;
4990 radius = PROJSIZE-0x2200;
4991 if (ocl==wallfireobj)
4992 radius-=0x3000;
4993 trytilex = (tryx >> TILESHIFT);
4994 trytiley = (tryy >> TILESHIFT);
4995
4996
4997 if (IsWindow(trytilex,trytiley) || (!InMapBounds((tryx>>16),(tryy>>16))))
4998 {
4999 QuietDetonate(ob);
5000 }
5001
5002
5003
5004 /*
5005 */
5006 //==== ceiling/floor clipping =================//
5007
5008 if (tryz < -30)
5009 {if ((sky==0) || (ocl == inertobj))
5010 {
5011 DetonateMissile(ob,NULL);
5012 }
5013 /*
5014 else
5015 return true;
5016 */
5017 /*
5018 else
5019 {
5020 NewState(ob,&s_megaremove);
5021 if (missobj == ob)
5022 missobj = NULL;
5023
5024 return false;
5025 }
5026 */
5027 }
5028
5029
5030 if (tryz > (maxheight-10))
5031 {
5032 if ((ocl == p_firewallobj) && (!(ob->flags & FL_ISFIRE)))
5033 StartFirewall(ob,nominalheight);
5034 else
5035 MissileHit(ob,NULL);
5036 return false;
5037 }
5038
5039 //=============================================//
5040
5041 sprrad = PROJSIZE+0x1000;
5042
5043
5044 tilexlow = (int)((tryx-radius) >>TILESHIFT);
5045 tileylow = (int)((tryy-radius) >>TILESHIFT);
5046
5047 tilexhigh = (int)((tryx+radius) >>TILESHIFT);
5048 tileyhigh = (int)((tryy+radius) >>TILESHIFT);
5049
5050 oldsrad = sprrad;
5051
5052
5053 if (ocl == inertobj)
5054 goto walls;
5055
5056 area = ob->areanumber;
5057 areatried[area] = true;
5058 actors:
5059 for(temp=firstareaactor[area];temp;temp=temp->nextinarea)
5060 {
5061 if (temp == ob)
5062 continue;
5063
5064 dx = abs(tryx - temp->x);
5065 dy = abs(tryy - temp->y);
5066 if ((dx > actrad) || (dy > actrad))
5067 continue;
5068
5069 if (temp->flags & FL_HEAD)
5070 continue;
5071
5072 if ((!(temp->flags & FL_BLOCK)) || (temp->flags & FL_DYING))
5073 continue;
5074
5075 tcl = temp->obclass;
5076
5077
5078 zdist = 32;
5079 dzt = abs(tryz - temp->z);
5080
5081 if ((tcl == playerobj) && (temp->flags & FL_DOGMODE))
5082 {
5083 dzt = abs(tryz - (temp->z + 30));
5084 zdist = 10;
5085 }
5086 else if (tcl == diskobj)
5087 {
5088 zdist = 50;
5089 }
5090
5091 if (dzt > zdist)
5092 continue;
5093
5094
5095
5096 //if ((ocl==wallfireobj) && (tcl==playerobj) && (temp->flags&FL_DOGMODE) && (dz>15))
5097 // continue;
5098
5099 //if ((ocl==playerobj) &&
5100 // (ob->whatever == (void*)temp))
5101 //continue;
5102
5103 if (ob->whatever && (ob->whatever == temp->whatever))// &&
5104 // (ocl == tcl))// missiles with same owner
5105 // go through each other
5106 continue;
5107
5108 if (!(ob->flags & FL_ISFIRE))
5109 {
5110
5111 int random;
5112
5113 if (tcl != b_darkmonkobj)
5114 {
5115 MissileHit(ob,temp);
5116 ob->target = NULL;
5117 if (tcl == wallfireobj)
5118 MissileHit(temp,NULL);
5119 if (((ocl == p_kesobj) || (ocl == p_godballobj)) && (tcl < pillarobj))
5120 continue;
5121 else
5122 return false;
5123 }
5124 random = GameRandomNumber("empower darkmonk",0);
5125 #if (SHAREWARE == 0)
5126
5127 if (ocl == p_kesobj)
5128 {
5129 NewState(ob,&s_megaremove);
5130 //ob->state = NULL;
5131 temp->hitpoints += (((random>>3)+140)<<1);
5132 CAP_OSCUROS_HITPOINTS(temp);
5133 }
5134 else if (ocl == p_firebombobj)
5135 {
5136 NewState(ob,&s_explosion1);
5137 temp->hitpoints += (((random>>3)+70)<<1);
5138 CAP_OSCUROS_HITPOINTS(temp);
5139
5140 ob->target = NULL;
5141 }
5142 else
5143 {
5144 NewState(ob,&s_explosion1);
5145 temp->hitpoints += (((random>>3)+50)<<1);
5146 CAP_OSCUROS_HITPOINTS(temp);
5147
5148 ob->target = NULL;
5149 }
5150 temp->temp3 = ocl;
5151 temp->speed = 5*SPDPATROL;
5152 NewState(temp,&s_darkmonkreact);
5153 #endif
5154 return false;
5155 }
5156
5157 else if (tcl < roboguardobj)
5158 {if ((temp->z == nominalheight) &&
5159 (!((tcl == playerobj) && ((temp->flags & FL_GODMODE) || (temp->flags & FL_DOGMODE) || godmode))))
5160 {
5161 if (tcl == playerobj)
5162 {
5163 playertype *pstate;
5164 objtype *owner = (objtype*)(ob->whatever);
5165
5166 M_LINKSTATE(temp,pstate);
5167 if (temp->flags & FL_AV)
5168 {pstate->protectiontime = 1;
5169 if (temp==player)
5170 GM_UpdateBonus (pstate->protectiontime, false);
5171 continue;
5172 }
5173
5174
5175 //temp->flags &= ~FL_COLORED;
5176 pstate->health = 0;
5177 pstate->weapon = -1;
5178 if (owner->obclass == playerobj)
5179 BATTLE_PlayerKilledPlayer(battle_kill_with_missile,owner->dirchoosetime,temp->dirchoosetime);
5180
5181
5182 }
5183
5184
5185 temp->flags |= FL_SKELETON;
5186 temp->hitpoints = 0;
5187 Collision(temp,ob->whatever,-temp->momentumx,-temp->momentumy);
5188 }
5189 continue;
5190 }
5191
5192
5193
5194 else
5195 {
5196 NewState(ob,&s_megaremove);
5197 ob->target = NULL;
5198 #if (SHAREWARE == 0)
5199 if (tcl == b_darkmonkobj)
5200 NewState(temp,&s_darkmonkfspark1);
5201 #endif
5202 }
5203
5204 return false;
5205
5206 }
5207
5208
5209 for (y=tileylow;y<=tileyhigh;y++)
5210 for (x=tilexlow;x<=tilexhigh;x++)
5211 {
5212 area = AREANUMBER(x,y);
5213 if (ValidAreanumber(area) && (areatried[area]==false))
5214 {
5215 areatried[area] = true;
5216 goto actors;
5217 }
5218 }
5219
5220
5221 /******************* WALLS/PWALLS *****************************************/
5222
5223 walls:
5224
5225 for (y=tileylow;y<=tileyhigh;y++)
5226 for (x=tilexlow;x<=tilexhigh;x++)
5227 {
5228
5229
5230 tempwall = (wall_t*)actorat[x][y];
5231 wall=tilemap[x][y];
5232
5233 if (tempwall && M_ISWALL(tempwall) && (tempwall->which!=MWALL))
5234 {if (ocl == h_mineobj)
5235 {
5236 if (WallCheck(ob->x-ob->momentumx, tryy))
5237 {ob->momentumx = -ob->momentumx;
5238 continue;
5239 }
5240 else if (WallCheck(tryx, ob->y-ob->momentumy))
5241 {ob->momentumy = -ob->momentumy;
5242 continue;
5243 }
5244 }
5245
5246 DetonateMissile(ob,tempwall);
5247 //MissileHit(ob,tempwall);
5248 //return false;
5249 }
5250
5251
5252 tempstat = sprites[x][y];
5253 sprrad = oldsrad;
5254
5255 if (tempstat &&
5256 ((tempstat->flags & FL_SHOOTABLE) || (tempstat->flags & FL_BLOCK)))
5257 {
5258
5259 if ((tempstat->itemnumber >= stat_bcolumn) &&
5260 (tempstat->itemnumber <= stat_icolumn))
5261 sprrad += 0x5000;
5262
5263 dx = tryx - tempstat->x;
5264 if ((dx < -sprrad) || (dx > sprrad))
5265 continue;
5266
5267 dy = tryy - tempstat->y;
5268 if ((dy < -sprrad) || (dy > sprrad))
5269 continue;
5270
5271 //#define MINSTATZDIFF 60
5272
5273 dzt = abs(ob->z - tempstat->z);
5274 dztp1 = abs(tryz - tempstat->z);
5275 /*
5276 if (ocl == p_firewallobj)// && (dztp1 <= MINSTATZDIFF))
5277 {
5278 if (ob->flags & FL_ISFIRE)
5279 {
5280 int cz = (ob->z - tempstat->z + MINSTATZDIFF);
5281
5282 if ((cz >= -MAXSTEPHEIGHT) && (cz <= 0))
5283 {
5284 ob->z = tempstat->z - MINSTATZDIFF;
5285 tryz = ob->z + (ob->momentumz >> 16);
5286 dzt = MINSTATZDIFF;
5287 }
5288 }
5289
5290 if ((dztp1 >= MINSTATZDIFF) || (dzt >= MINSTATZDIFF))
5291 continue;
5292
5293 if (!(ob->flags & FL_ISFIRE))
5294 {
5295 StartFirewall(ob,tempstat->z - MINSTATZDIFF);
5296 return false;
5297 }
5298 }
5299
5300
5301 else*/
5302 {
5303 if (dztp1 > 50)
5304 continue;
5305
5306 DetonateMissile(ob,tempstat);
5307 }
5308 //MissileHit(ob,tempstat);
5309 //return false;
5310 }
5311 }
5312
5313
5314 //mwalls:
5315
5316
5317
5318 if (M_ISMWALL(trytilex,trytiley))
5319 {
5320 maskedwallobj_t * mw;
5321
5322 wall=tilemap[trytilex][trytiley];
5323 //tempwall = (wall_t*)actorat[trytilex][trytiley];
5324
5325
5326 mw=maskobjlist[wall&0x3ff];
5327
5328 if (!(mw->flags&MW_BLOCKING))
5329 {
5330
5331 if ((levelheight > 1) &&
5332 (((!(mw->flags & MW_ABOVEPASSABLE)) && (tryz <= 32)) ||
5333 ((!(mw->flags & MW_MIDDLEPASSABLE)) && (tryz > 25) && (tryz < nominalheight-32)) ||
5334 ((!(mw->flags & MW_BOTTOMPASSABLE)) && (tryz > maxheight - 74))
5335 )
5336 )
5337 DetonateMissile(ob,NULL);
5338
5339 }
5340
5341 else if (mw->flags&MW_SHOOTABLE)
5342 {
5343 if (ob->z >= maxheight-64)
5344 {
5345 UpdateMaskedWall(tilemap[trytilex][trytiley]&0x3ff);
5346 }
5347 else
5348 DetonateMissile(ob,NULL);
5349
5350 }
5351
5352 else
5353 DetonateMissile(ob,NULL);
5354 //MissileHit(ob,tempwall);
5355 //return false;
5356 }
5357
5358
5359
5360 /******************* DOOR STUFF ******************************************/
5361
5362
5363 else if (M_ISDOOR(trytilex,trytiley))
5364 {
5365 doorn = tilemap[trytilex][trytiley];
5366 tempdoor = doorobjlist[doorn&0x3ff];
5367 if (tempdoor->position>=0x8000)
5368 {
5369 if (ob->z>maxheight-64)
5370 return true;
5371 }
5372 DetonateMissile(ob,tempdoor);
5373 }
5374
5375 return true;
5376
5377
5378 }
5379
5380
5381
SpawnFirewall(objtype * ob,int which,int newz)5382 void SpawnFirewall(objtype*ob,int which,int newz)
5383 {int i,j,count,newx,newy;
5384 objtype* owner;
5385 wall_t*tempwall;
5386 statetype* frame;
5387 int offset;
5388
5389 owner = (objtype*)(ob->whatever);
5390
5391 if ((owner->temp1 < 2) && (MISCVARS->firespawned < 14))
5392 {for(i=0;i<=which;i++)
5393 {
5394 GetNewActor ();
5395 MakeActive(new);
5396 MISCVARS->firespawned ++;
5397 new->obclass = p_firewallobj;
5398 new->which = ACTOR;
5399 new->areanumber = ob->areanumber;
5400 MakeLastInArea(new);
5401 offset = 0x6000;
5402 if (!which)
5403 new->temp1 = ob->temp1;
5404 else if (i==1)
5405 new->temp1 = ob->angle + ANGLES/4;
5406 else if (i==2)
5407 new->temp1 = ob->angle - ANGLES/4;
5408 else
5409 {
5410 new->temp1 = 0;
5411 offset = 0;
5412 new->flags |= FL_DONE;
5413 }
5414
5415 Fix(new->temp1);
5416
5417 new->speed = 0x8000;
5418 new->angle = ob->angle;
5419 ParseMomentum(new,new->angle);
5420 newx = ob->x + FixedMul(offset,costable[new->temp1]);
5421 newy = ob->y - FixedMul(offset,sintable[new->temp1]);
5422 SetFinePosition(new,newx,newy);
5423 SetVisiblePosition(new,newx,newy);
5424 new->whatever = ob->whatever;
5425 new->dirchoosetime = 2;
5426 new->flags |= (FL_NEVERMARK|FL_ABP|FL_NOFRICTION);
5427 count = (int)(GameRandomNumber("SpawFireWall",0) & 15);
5428
5429 for(frame = &s_fireunit1,j=0;j<count;frame = frame->next,j++);
5430
5431 NewState(new,frame);
5432 new->flags |= FL_ISFIRE;
5433 //SD_Play(SD_EXPL);
5434 tempwall = (wall_t*)actorat[new->tilex][new->tiley];
5435 new->z = newz;
5436 if (tempwall && M_ISWALL(tempwall))
5437 {
5438 SetFinePosition(new,ob->x,ob->y);
5439 SetVisiblePosition(new,ob->x,ob->y);
5440 owner->temp1++;
5441 }
5442 }
5443 }
5444
5445 }
5446
5447
T_Firethink(objtype * ob)5448 void T_Firethink(objtype*ob)
5449 {
5450
5451 if (ob->dirchoosetime)
5452 ob->dirchoosetime--;
5453 else if (!(ob->flags & FL_DONE))
5454 {
5455 SpawnFirewall(ob,0,ob->z);
5456 ob->flags |= FL_DONE;
5457 }
5458
5459 MissileMovement(ob);
5460
5461 }
5462
5463
5464
ResolveRide(objtype * ob)5465 void ResolveRide(objtype *ob)
5466 {
5467 objtype *ride = (objtype*)(ob->whatever);
5468
5469 if (M_ISACTOR(ride) && (ob->obclass != playerobj))
5470 {
5471 if (ob->flags & FL_RIDING)
5472 {
5473 int dx,dy;
5474
5475 dx = ob->x - ride->x;
5476 dy = ob->y - ride->y;
5477 if ((dx < -MINACTORDIST) || (dx > MINACTORDIST) ||
5478 (dy < -MINACTORDIST) || (dy > MINACTORDIST) )
5479 {
5480 ride->whatever = NULL;
5481 ob->whatever = NULL;
5482 ob->flags &= ~FL_RIDING;
5483 }
5484 }
5485 }
5486
5487 }
5488
5489
5490
5491
MoveActor(objtype * ob)5492 void MoveActor(objtype*ob)
5493 {
5494 int linked,oldarea,newarea,
5495 tilex,tiley,oldtilex,oldtiley;
5496
5497 linked = 0;
5498
5499 ResolveRide(ob);
5500
5501 oldtilex = ob->tilex;
5502 oldtiley = ob->tiley;
5503
5504 SetFinePosition(ob,ob->x+ob->momentumx,ob->y+ob->momentumy);
5505 /*
5506 if (ob->state == &s_explosion1)
5507 Error("moving explosion"); */
5508
5509 if ((ob->obclass == playerobj) || (ob->flags & FL_NOFRICTION) || (ob->state->think == T_Collide) ||
5510 (ob->obclass == b_heinrichobj) || (ob->obclass == h_mineobj))
5511
5512 SetVisiblePosition(ob,ob->x,ob->y);
5513
5514
5515
5516 if (ob->obclass == inertobj)
5517 return;
5518
5519 if ((ob->obclass == b_darksnakeobj) && (ob != SNAKEHEAD))
5520 {
5521 oldarea = ob->areanumber;
5522 newarea = SNAKEHEAD->areanumber;
5523 if (oldarea != newarea)
5524 {
5525 RemoveFromArea(ob);
5526 ob->areanumber = newarea;
5527 MakeLastInArea(ob);
5528 }
5529 return;
5530
5531 }
5532
5533
5534 oldarea = ob->areanumber;
5535 newarea = AREANUMBER(ob->tilex,ob->tiley);
5536 if (!(ob->flags & (FL_NONMARK|FL_NEVERMARK)))
5537 {
5538 if ((oldtilex != ob->tilex) || (oldtiley != ob->tiley))
5539 {
5540 if (actorat[oldtilex][oldtiley] == (void*)ob)
5541 actorat[oldtilex][oldtiley] = NULL;
5542 if (actorat[ob->tilex][ob->tiley])
5543 {
5544 objtype* temp;
5545
5546 temp = (objtype*)actorat[ob->tilex][ob->tiley];
5547 if (temp->which != SPRITE)
5548 actorat[ob->tilex][ob->tiley] = ob;
5549 }
5550 else
5551 actorat[ob->tilex][ob->tiley] = ob;
5552 }
5553 }
5554
5555
5556 #define CheckAdjacentArea(x,y) \
5557 { \
5558 if (InMapBounds(x,y)) \
5559 { \
5560 temparea = AREANUMBER(x,y); \
5561 if (ValidAreanumber(temparea)) \
5562 newarea = temparea; \
5563 } \
5564 }
5565
5566
5567 if (!ValidAreanumber(newarea)) //find empty tile
5568 {
5569 int temparea;
5570 tilex = ob->tilex;
5571 tiley = ob->tiley;
5572
5573 CheckAdjacentArea(tilex+1,tiley);
5574 CheckAdjacentArea(tilex-1,tiley);
5575 CheckAdjacentArea(tilex,tiley+1);
5576 CheckAdjacentArea(tilex,tiley-1);
5577
5578 }
5579 //Error("new area invalid for actor %d, class %d",
5580 // ob-&objlist[0],ob->obclass);
5581
5582
5583 //====================== swap in linked lists =====================
5584 if (oldarea != newarea)
5585 {
5586 RemoveFromArea(ob);
5587 ob->areanumber = newarea;
5588 MakeLastInArea(ob);
5589 }
5590 }
5591
5592
5593
SpawnPushColumn(int tilex,int tiley,int which,int dir,int linked)5594 void SpawnPushColumn(int tilex,int tiley,int which,int dir, int linked)
5595 {
5596 if (which==0)
5597 {
5598 SpawnNewObj(tilex,tiley,&s_pushcolumn1,pillarobj);
5599 // for (i=0;i<(levelheight-1);i++)
5600 // SpawnStatic(tilex,tiley,stat_bcolumn,-(i<<6));
5601 }
5602 else if (which==1)
5603 {
5604 SpawnNewObj(tilex,tiley,&s_pushcolumn2,pillarobj);
5605 // for (i=0;i<(levelheight-1);i++)
5606 // SpawnStatic(tilex,tiley,stat_gcolumn,-(i<<6));
5607 }
5608 else
5609 {
5610 SpawnNewObj(tilex,tiley,&s_pushcolumn3,pillarobj);
5611 // for (i=0;i<(levelheight-1);i++)
5612 // SpawnStatic(tilex,tiley,stat_icolumn,-(i<<6));
5613 }
5614 PreCacheActor(pillarobj,which);
5615
5616 gamestate.secrettotal++;
5617 new->speed = PILLARMOM;
5618 new->temp1 = 0x20000;
5619 new->temp2 = linked;
5620 new->flags |= (FL_BLOCK|FL_NOFRICTION);
5621 new->flags &= ~FL_SHOOTABLE;
5622 new->flags |= FL_HEIGHTFLIPPABLE;
5623 new->dir = dir;
5624 if (dir != nodir)
5625 ParseMomentum(new,dirangle8[new->dir]);
5626
5627
5628 }
5629
5630
5631
SpawnWallfire(int tilex,int tiley,int dir)5632 void SpawnWallfire(int tilex, int tiley, int dir)
5633 {int offx,offy;
5634
5635
5636 GetNewActor();
5637 new->speed = 0x2000;
5638 SetTilePosition(new,tilex,tiley);
5639 SetVisiblePosition(new,new->x,new->y);
5640 new->obclass = wallfireobj;
5641 new->dir = dir*2;
5642 new->flags |= (FL_BLOCK|FL_NOFRICTION|FL_NEVERMARK);
5643 new->flags &= ~FL_SHOOTABLE;
5644 new->which = ACTOR;
5645 new->angle = dirangle8[new->dir];
5646 offx = FixedMul(0x10000,costable[new->angle])>>TILESHIFT;
5647 offy = -(FixedMul(0x10000,sintable[new->angle])>>TILESHIFT);
5648
5649 new->areanumber = MAPSPOT(new->tilex+offx,new->tiley+offy,0)-AREATILE;
5650 MakeLastInArea(new);
5651
5652 NewState(new,&s_wallfireball);
5653
5654 }
5655
5656
5657
SpawnSneaky(int tilex,int tiley)5658 void SpawnSneaky(int tilex,int tiley)
5659 {
5660
5661 SpawnNewObj(tilex,tiley,&s_sneakydown,lowguardobj);
5662 new->temp3 = SNEAKY;
5663 if (!loadedgame)
5664 gamestate.killtotal++;
5665 StandardEnemyInit(new,north>>1);
5666
5667 PreCacheActor(lowguardobj,0);
5668 }
5669
5670
RespawnEluder(void)5671 void RespawnEluder(void)
5672 {
5673 int rand,count;
5674 int nx,ny;
5675
5676 rand = (GameRandomNumber("eluder respawn",0) % NUMSPAWNLOCATIONS);
5677
5678 for(count=0;count < NUMSPAWNLOCATIONS;count++)
5679 {
5680 if (!actorat[SPAWNLOC[rand].x][SPAWNLOC[rand].y])
5681 {
5682 SpawnCollector(SPAWNLOC[rand].x,SPAWNLOC[rand].y);
5683 return;
5684 }
5685 rand= ((rand + 1) % NUMSPAWNLOCATIONS);
5686
5687 }
5688
5689 //MED
5690 nx = SPAWNLOC[rand].x;
5691 ny = SPAWNLOC[rand].y;
5692 FindEmptyTile(&nx,&ny);
5693 SpawnCollector(nx,ny);
5694 }
5695
5696 //****************************************************************************
5697 //
5698 //
5699 //
5700 //****************************************************************************
5701
SpawnCollector(int tilex,int tiley)5702 void SpawnCollector(int tilex, int tiley)
5703 {
5704 #if (SHAREWARE == 0)
5705 if ( dopefish==true )
5706 {
5707 SpawnNewObj(tilex,tiley,&s_scottwander1,collectorobj);
5708 }
5709 else
5710 #endif
5711 {
5712 SpawnNewObj(tilex,tiley,&s_collectorwander1,collectorobj);
5713 }
5714
5715 new->flags |= (FL_SHOOTABLE|FL_BLOCK|FL_NOFRICTION|FL_FULLLIGHT);
5716 new->hitpoints = 500;
5717 new->speed = 0x3000;
5718 new->dir = north;
5719 new->dirchoosetime = 175;
5720 new->z = PlatformHeight(tilex,tiley);
5721 if (new->z == -10)
5722 new->z = 0;
5723 if (areabyplayer[new->areanumber])
5724 {new->flags |= FL_ABP;
5725 MakeActive(new);
5726 }
5727
5728 }
5729
5730
5731
SelectDoorDir(objtype * ob)5732 void SelectDoorDir(objtype*ob)
5733 {int dx,dy,actrad;
5734 dirtype dtry1,dtry2,tdir,olddir;
5735
5736 dx= ob->targettilex - ob->x;
5737 dy= ob->y - ob->targettiley;
5738 olddir = ob->dir;
5739 if ((abs(dx) < 0x4000) && (abs(dy) < 0x4000))
5740 {ZEROMOM;
5741 SetFinePosition(ob,ob->targettilex,ob->targettiley);
5742 SetVisiblePosition(ob,ob->x,ob->y);
5743 ParseMomentum(ob,dirangle8[ob->temp2]);
5744 ActorMovement(ob);
5745 ob->temp2 = 0;
5746 ob->temp1 = 20;
5747 #if (SHAREWARE == 0)
5748 if ( dopefish==true )
5749 {
5750 NewState(ob,&s_scottwander1);
5751 }
5752 else
5753 #endif
5754 {
5755 NewState(ob,&s_collectorwander1);
5756 }
5757 ob->targettilex = ob->targettiley = 0;
5758 ob->dirchoosetime = 165;
5759 return;
5760 }
5761
5762
5763 ZEROMOM;
5764
5765 ParseMomentum(ob,atan2_appx(dx,dy));
5766 ActorMovement(ob);
5767 if (ob->momentumx || ob->momentumy)
5768 return;
5769 actrad = ACTORSIZE;
5770 dtry1=nodir;
5771 dtry2=nodir;
5772
5773 if (dx> actrad)
5774 dtry1= east;
5775 else if (dx< -actrad)
5776 dtry1= west;
5777 if (dy> actrad)
5778 dtry2= north;
5779 else if (dy < -actrad)
5780 dtry2= south;
5781
5782
5783 if (abs(dy)>abs(dx))
5784 {tdir=dtry1;
5785 dtry1=dtry2;
5786 dtry2=tdir;
5787 }
5788
5789
5790 if (dtry1 != nodir)
5791 M_CHECKDIR(ob,dtry1);
5792
5793 if (dtry2 != nodir)
5794 M_CHECKDIR(ob,dtry2);
5795
5796 if (dtry1 != nodir)
5797 M_CHECKDIR(ob,dirorder[dtry1][NEXT]);
5798
5799 if (dtry2 != nodir)
5800 M_CHECKDIR(ob,dirorder[dtry2][NEXT]);
5801
5802 for(tdir = dirorder[olddir][NEXT];tdir != olddir;tdir = dirorder[tdir][NEXT])
5803 M_CHECKDIR(ob,tdir);
5804 ob->dir = olddir;
5805
5806 }
5807
5808
EluderCaught(objtype * ob)5809 boolean EluderCaught(objtype*ob)
5810 {
5811 objtype *temp;
5812 int dx,dy,dz;
5813 playertype *pstate;
5814 int dist = 0xc000;
5815
5816 for(temp = PLAYER[0];temp != PLAYER[numplayers-1]->next;temp=temp->next)
5817 {
5818 #if (SHAREWARE == 0)
5819 if (temp->state != &s_doguse)
5820 continue;
5821 #endif
5822
5823 dx = M_ABS(temp->x - ob->x);
5824 if (dx > dist)
5825 continue;
5826
5827 dy = M_ABS(temp->y - ob->y);
5828 if (dy > dist)
5829 continue;
5830
5831 dz = M_ABS(temp->z - ob->z);
5832 if (dz > (dist>>10))
5833 continue;
5834
5835 M_LINKSTATE(temp,pstate);
5836 //if (DOGSCRATCH.attackinfo[pstate->attackframe].attack == at_pulltrigger)
5837 {BATTLE_CheckGameStatus(battle_caught_eluder,temp->dirchoosetime);
5838 SpawnNewObj(ob->tilex,ob->tiley,&s_itemspawn1,inertobj);
5839 new->flags |= FL_ABP;
5840 SetFinePosition(new,ob->x,ob->y);
5841 SetVisiblePosition(new,ob->x,ob->y);
5842 new->z = ob->z;
5843 SD_PlaySoundRTP(SD_GETBONUSSND,ob->x,ob->y);
5844 MakeActive(new);
5845 NewState(ob,&s_megaremove);
5846 return true;
5847 }
5848
5849 }
5850
5851 return false;
5852 }
5853
5854
T_CollectorFindDoor(objtype * ob)5855 void T_CollectorFindDoor(objtype*ob)
5856 {
5857
5858 if (EluderCaught(ob))
5859 return;
5860
5861 if (!(gamestate.TimeCount % 17))
5862 SD_PlaySoundRTP(SD_MONKGRABSND,ob->x,ob->y);
5863
5864
5865 if ((ob->z != nominalheight) && (!IsPlatform(ob->tilex,ob->tiley)))
5866 ZEROMOM;
5867
5868
5869
5870 if (ob->dirchoosetime)
5871 ob->dirchoosetime --;
5872 else
5873 {
5874 #if (SHAREWARE == 0)
5875 if ( dopefish==true )
5876 {
5877 NewState(ob,&s_scottwander1);
5878 }
5879 else
5880 #endif
5881 {
5882 NewState(ob,&s_collectorwander1);
5883 }
5884 ob->dirchoosetime = 165;
5885 ob->targettilex = ob->targettiley = 0;
5886 return;
5887 }
5888
5889 if (ob->temp1)
5890 {int dx,dy;
5891
5892 ob->temp1 --;
5893 ActorMovement(ob);
5894 dx = ob->targettilex-ob->x;
5895 dy = ob->targettiley-ob->y;
5896 if ((abs(dx) < 0x4000) && (abs(dy) < 0x4000))
5897 {ZEROMOM;
5898 SetFinePosition(ob,ob->targettilex,ob->targettiley);
5899 SetVisiblePosition(ob,ob->x,ob->y);
5900
5901 ParseMomentum(ob,dirangle8[ob->temp2]);
5902 ActorMovement(ob);
5903 ob->temp2 = 0;
5904 ob->temp1 = 35;
5905 #if (SHAREWARE == 0)
5906 if ( dopefish==true )
5907 {
5908 NewState(ob,&s_scottwander1);
5909 }
5910 else
5911 #endif
5912 {
5913 NewState(ob,&s_collectorwander1);
5914 }
5915 ob->targettilex = ob->targettiley = 0;
5916 ob->dirchoosetime = 165;
5917 return;
5918 }
5919 if (NOMOM)
5920 ob->temp1 = 0;
5921 return;
5922 }
5923
5924
5925
5926 ob->temp1 = 5;
5927
5928 if (ob->targettilex || ob->targettiley)
5929 SelectDoorDir(ob);
5930
5931 else
5932 {int i;
5933 doorobj_t* dptr;
5934
5935 //==========================================================================
5936 #define SetCollectorTarget(xoffset,yoffset,newdir) \
5937 { \
5938 ob->targettilex = ((dptr->tilex + (xoffset)) << TILESHIFT) + HALFGLOBAL1; \
5939 ob->targettiley = ((dptr->tiley + (yoffset)) << TILESHIFT) + HALFGLOBAL1; \
5940 ob->temp2 = newdir; \
5941 if (GameRandomNumber("collector door search",0) < 100) \
5942 return; \
5943 }
5944 //==========================================================================
5945
5946 for(i=0;i<doornum;i++)
5947 {dptr = doorobjlist[i];
5948 if (dptr->vertical)
5949 {
5950 int area1 = AREANUMBER(dptr->tilex-1,dptr->tiley),
5951 area2 = AREANUMBER(dptr->tilex+1,dptr->tiley);
5952
5953 if (area1 == ob->areanumber)
5954 SetCollectorTarget(-1,0,east)
5955
5956 else if (area2 == ob->areanumber)
5957 SetCollectorTarget(1,0,west);
5958
5959 }
5960 else
5961 {
5962 int area1 = AREANUMBER(dptr->tilex,dptr->tiley-1),
5963 area2 = AREANUMBER(dptr->tilex,dptr->tiley+1);
5964
5965 if (area1 == ob->areanumber)
5966 SetCollectorTarget(0,-1,south)
5967
5968 else if (area2 == ob->areanumber)
5969 SetCollectorTarget(0,1,north);
5970
5971 }
5972 }
5973 }
5974
5975 }
5976
5977
T_CollectorWander(objtype * ob)5978 void T_CollectorWander(objtype*ob)
5979 {
5980
5981 int newtilex,newtiley;
5982
5983 if (EluderCaught(ob))
5984 return;
5985
5986 if ((ob->z != nominalheight) && (!IsPlatform(ob->tilex,ob->tiley)))
5987 ZEROMOM;
5988
5989 if (!(gamestate.TimeCount & 15))//%17
5990 SD_PlaySoundRTP(SD_MONKGRABSND,ob->x,ob->y);
5991
5992 if (ob->dirchoosetime)
5993 {
5994 if (doornum > 0)
5995 ob->dirchoosetime --;
5996 }
5997
5998 else
5999 {
6000 #if (SHAREWARE == 0)
6001 if ( dopefish==true )
6002 {
6003 NewState(ob,&s_scottwanderdoor1);
6004 }
6005 else
6006 #endif
6007 {
6008 NewState(ob,&s_collectorfdoor1);
6009 }
6010 ob->temp1 = 0;
6011 ob->dirchoosetime = 165;
6012 ob->targettilex = ob->targettiley = 0;
6013 return;
6014 }
6015
6016 if (ob->temp1) // temp1 holds direction time
6017 ob->temp1 --;
6018 else
6019 {
6020 dirtype bestdir,tempdir;
6021
6022 bestdir = angletodir[GameRandomNumber("collector theta",0) << 3];
6023
6024 for(tempdir = bestdir;tempdir != dirorder[bestdir][PREV];tempdir = dirorder[tempdir][NEXT])
6025 {
6026 ParseMomentum(ob,dirangle8[tempdir]);
6027 newtilex = ((ob->x + ob->momentumx)>>16);
6028 newtiley = ((ob->y + ob->momentumy)>>16);
6029 if (IsWindow(newtilex,newtiley))
6030 continue;
6031 ActorMovement(ob);
6032 if (ob->momentumx || ob->momentumy)
6033 {
6034 ob->temp1 = (GameRandomNumber("collector choose time",0) >> 2);
6035 return;
6036 }
6037 }
6038
6039 }
6040
6041 newtilex = ((ob->x + ob->momentumx)>>16);
6042 newtiley = ((ob->y + ob->momentumy)>>16);
6043
6044
6045 if (IsWindow(newtilex,newtiley))
6046 {
6047 ob->temp1 = 0;
6048 return;
6049 }
6050
6051
6052 ActorMovement(ob);
6053
6054 if (NOMOM)
6055 ob->temp1 = 0;
6056 }
6057
6058
6059
6060
6061
CheckDoor(objtype * ob,doorobj_t * door,int trytilex,int trytiley)6062 boolean CheckDoor(objtype *ob,doorobj_t * door,int trytilex,int trytiley)
6063 {boolean doorok=false;
6064
6065
6066 switch(ob->dir)
6067 {case north:
6068 if ((ob->tiley == (door->tiley + 1)) && (trytilex == ob->tilex))
6069 doorok = true;
6070 break;
6071
6072 case east:
6073 if ((ob->tilex == (door->tilex - 1)) && (trytiley == ob->tiley))
6074 doorok = true;
6075 break;
6076
6077 case south:
6078 if ((ob->tiley == (door->tiley - 1)) && (trytilex == ob->tilex))
6079 doorok = true;
6080 break;
6081
6082 case west:
6083 if ((ob->tilex == (door->tilex + 1)) && (trytiley == ob->tiley))
6084 doorok = true;
6085 break;
6086 default:
6087 ;
6088 }
6089
6090
6091 if (doorok)
6092 {SetTilePosition(ob,ob->tilex,ob->tiley);
6093 SetVisiblePosition(ob,ob->x,ob->y);
6094 return true;
6095 }
6096 return false;
6097 }
6098
6099
WallCheck(int tryx,int tryy)6100 boolean WallCheck(int tryx,int tryy)
6101 {int tilexlow,tilexhigh,tileylow,tileyhigh,y,x;
6102
6103 tilexlow = (int)((tryx -PLAYERSIZE) >>TILESHIFT);
6104 tileylow = (int)((tryy -PLAYERSIZE) >>TILESHIFT);
6105
6106 tilexhigh = (int)((tryx + PLAYERSIZE) >>TILESHIFT);
6107 tileyhigh = (int)((tryy + PLAYERSIZE) >>TILESHIFT);
6108
6109
6110 for (y=tileylow;y<=tileyhigh;y++)
6111 for (x=tilexlow;x<=tilexhigh;x++)
6112 {//tempwall = (wall_t*)actorat[x][y];
6113 //if (tempwall && M_ISWALL(tempwall))
6114 if (tilemap[x][y])
6115 return false;
6116 }
6117
6118 return true;
6119
6120 }
6121
6122
QuickSpaceCheck(objtype * ob,int tryx,int tryy)6123 boolean QuickSpaceCheck(objtype*ob,int tryx, int tryy)
6124 {int xlow,xhigh,ylow,yhigh,x,y,dx,dy;
6125 objtype* temp;
6126
6127 xlow = (int)((tryx-ACTORSIZE) >>TILESHIFT);
6128 ylow = (int)((tryy-ACTORSIZE) >>TILESHIFT);
6129
6130 xhigh = (int)((tryx+ACTORSIZE) >>TILESHIFT);
6131 yhigh = (int)((tryy+ACTORSIZE) >>TILESHIFT);
6132 /******************* WALLS/PWALLS *****************************************/
6133
6134 for (y=ylow;y<=yhigh;y++)
6135 for (x=xlow;x<=xhigh;x++)
6136 {temp = (objtype*)actorat[x][y];
6137 if ((temp && (temp->which != ACTOR)) ||
6138 (sprites[x][y] && (sprites[x][y]->flags & FL_BLOCK))
6139
6140 || tilemap[x][y])
6141 return false;
6142 }
6143
6144 for(temp=firstareaactor[ob->areanumber];temp;temp=temp->nextinarea)
6145 {if (temp == ob)
6146 continue;
6147 if ((temp->flags & FL_NONMARK) || (temp->flags & FL_NEVERMARK))
6148 continue;
6149 dx = tryx - temp->x;
6150 if ((dx < -MINACTORDIST) || (dx > MINACTORDIST))
6151 continue;
6152 dy = tryy - temp->y;
6153 if ((dy < -MINACTORDIST) || (dy > MINACTORDIST))
6154 continue;
6155 if (ob->whatever == (void*)temp)
6156 continue;
6157 if (temp->whatever == ob->whatever)
6158 continue;
6159 return false;
6160 }
6161
6162 return true;
6163
6164
6165 }
6166
6167
6168 //=========================================================================
6169 //
6170 // ACTOR TRY MOVE MADNESS
6171 //
6172 //=========================================================================
6173
6174 typedef enum
6175 {
6176 NO_MOVEMENT,
6177 Z_MOVEMENT_ONLY,
6178 OK_TO_CONTINUE
6179
6180 }movement_status;
6181
6182
6183
6184 //==================== Some ActorTryMove macros ==============================
6185
6186 #define CheckProximitySpecials(ob,temp) \
6187 { \
6188 if (ocl == b_heinrichobj) \
6189 { \
6190 if (tcl == playerobj) \
6191 { \
6192 playertype *pstate; \
6193 \
6194 M_LINKSTATE(temp,pstate); \
6195 DamageThing(temp,5); \
6196 temp->whatever = ob; \
6197 temp->temp2 = COLUMNCRUSH; \
6198 pstate->heightoffset += 4; \
6199 if (pstate->heightoffset >= 30) \
6200 pstate->heightoffset = 30; \
6201 pstate->oldheightoffset = pstate->heightoffset; \
6202 } \
6203 else \
6204 { \
6205 temp->momentumx = temp->momentumy = temp->momentumz = 0; \
6206 temp->hitpoints = 0; \
6207 } \
6208 if (temp->hitpoints <= 0) \
6209 temp->flags |= FL_HBM; \
6210 Collision(temp,ob,0,0); \
6211 continue; \
6212 } \
6213 \
6214 else if ((ocl == b_darksnakeobj) && (tcl == playerobj)) \
6215 { \
6216 DamageThing(temp,1); \
6217 Collision(temp,ob,0,0); \
6218 M_CheckPlayerKilled(temp); \
6219 } \
6220 \
6221 if ((ocl == boulderobj) && (tcl >= lowguardobj) && (tcl < roboguardobj))\
6222 {temp->momentumx = temp->momentumy = temp->momentumz = 0; \
6223 temp->hitpoints = 0; \
6224 temp->flags |= FL_HBM; \
6225 Collision(temp,ob,0,0); \
6226 SD_PlaySoundRTP(SD_ACTORSQUISHSND,temp->x,temp->y); \
6227 continue; \
6228 } \
6229 \
6230 if (pusher && (ocl != tcl) && (!(temp->flags & FL_DYING)) && \
6231 (tcl < roboguardobj) \
6232 ) \
6233 {if ((!ob->ticcount) && (ocl != collectorobj) && (ocl != diskobj))\
6234 DamageThing(temp,5); \
6235 \
6236 if (tcl == playerobj) \
6237 temp->flags |= FL_PUSHED; \
6238 Collision(temp,ob,ob->momentumx-temp->momentumx,ob->momentumy-temp->momentumy);\
6239 M_CheckPlayerKilled(temp); \
6240 continue; \
6241 } \
6242 \
6243 if (bouncer) \
6244 {ob->momentumx = -ob->momentumx; \
6245 continue; \
6246 } \
6247 }
6248
6249
6250
6251 #define CheckStepping(ob,step,minzdiff) \
6252 { \
6253 int cz = (ob->z - step->z + minzdiff); \
6254 \
6255 if ((cz >= -MAXSTEPHEIGHT) && (cz <= MAXSTEPHEIGHT)) \
6256 {if ((ob->obclass == playerobj) && (ob->temp2 == 0) && \
6257 (ob->z != (step->z - minzdiff)) \
6258 ) \
6259 { \
6260 playertype *pstate; \
6261 \
6262 M_LINKSTATE(ob,pstate); \
6263 \
6264 pstate->heightoffset = pstate->oldheightoffset + cz; \
6265 ob->temp2 = (cz >= 0)?(STEPUP):(STEPDOWN); \
6266 } \
6267 ob->z = step->z - minzdiff; \
6268 tryz = ob->z + (ob->momentumz >> 16); \
6269 dzt = minzdiff; \
6270 } \
6271 } \
6272
6273
6274
6275
6276 //============ Players crushing other players =====================
6277
BattleCrushCheck(objtype * ob,objtype * listrover)6278 void BattleCrushCheck(objtype *ob,objtype *listrover) \
6279 {
6280 if ((ob->obclass == playerobj) && (listrover->obclass == playerobj))
6281 {
6282 playertype * pstate;
6283
6284 M_LINKSTATE(listrover,pstate);
6285 if (pstate->health <= 0)
6286 BATTLE_PlayerKilledPlayer(battle_kill_by_crushing,ob->dirchoosetime,
6287 listrover->dirchoosetime);
6288 }
6289 }
6290
6291
6292 //=================================================================
6293
6294
6295
6296
6297
CheckOtherActors(objtype * ob,int tryx,int tryy,int tryz)6298 movement_status CheckOtherActors(objtype*ob,int tryx,int tryy,int tryz)
6299 {
6300 objtype *listrover;
6301 int area;
6302 int op;
6303 int areatried[NUMAREAS]={0};
6304 int tilexlow,tilexhigh,tileylow,tileyhigh;
6305 int radius,actrad,oldrad;
6306 boolean bouncer,pusher,thinkingactor,zstoppable,ACTORSTOP;
6307 int dzt,dztp1,checkz;
6308 int x,y,dx,dy;
6309 int ocl,tcl;
6310 int ISPLAYER = 0;
6311 int hoffset;
6312
6313 ocl = ob->obclass;
6314
6315 actrad = MINACTORDIST;//ACTORSIZE+0x2800;
6316 pusher = ((ocl == wallopobj) || (ocl == pillarobj) ||
6317 (ocl == roboguardobj) || (ocl == collectorobj) ||
6318 (ocl == boulderobj) || (ocl == diskobj)
6319 );
6320
6321 thinkingactor = ((ocl != playerobj) && (ob->state->think != T_Collide) &&
6322 (ocl < roboguardobj)
6323 );
6324
6325 zstoppable = (!(ob->flags & FL_DYING));
6326 bouncer = ((ocl == playerobj) && (ob->flags & FL_ELASTO));
6327 radius = ACTORSIZE;
6328
6329
6330 if (ocl != playerobj)
6331 {
6332 //actrad = MINACTORDIST;
6333 //if ((ob->dir == nodir) && (ocl != b_robobossobj) &&
6334 // (ocl != wallopobj) && (ocl != roboguardobj) && (ocl != diskobj)
6335 // )
6336 // Error("ob called with nodir");
6337 if (ocl == boulderobj)
6338 radius += (ACTORSIZE/4);
6339 else if (ocl == b_darksnakeobj)
6340 radius -= 6000;
6341 else if (ocl == inertobj)
6342 radius -= 0x2000;
6343 }
6344
6345 else
6346 {
6347 ISPLAYER = 1;
6348 if (ob->flags & FL_DOGMODE)
6349 hoffset = 10;
6350 }
6351
6352
6353
6354 tilexlow = (int)((tryx-radius) >>TILESHIFT);
6355 tileylow = (int)((tryy-radius) >>TILESHIFT);
6356
6357 tilexhigh = (int)((tryx+radius) >>TILESHIFT);
6358 tileyhigh = (int)((tryy+radius) >>TILESHIFT);
6359
6360 area = ob->areanumber;
6361 areatried[area] = 1;
6362 ACTORSTOP = false;
6363 oldrad = actrad;
6364
6365 actors:
6366 for(listrover=firstareaactor[area];listrover;listrover=listrover->nextinarea)
6367 {
6368 actrad = oldrad;
6369
6370 if (listrover == ob)
6371 continue;
6372
6373
6374 tcl = listrover->obclass;
6375
6376 if ((tcl == b_darksnakeobj) && (listrover != SNAKEHEAD))
6377 continue;
6378
6379 if (((tcl == bladeobj) || (tcl == firejetobj)) && thinkingactor)
6380
6381 actrad += 0x3000;
6382
6383
6384 dx = tryx - listrover->x;
6385 if ((dx < -actrad) || (dx > actrad))
6386 continue;
6387
6388 dy = tryy - listrover->y;
6389 if ((dy < -actrad) || (dy > actrad))
6390 continue;
6391
6392
6393 if ((ocl == b_darksnakeobj) && (tcl == ocl))
6394 continue;
6395
6396 if ((tcl == springobj) && (listrover->state->condition & SF_UP) &&
6397 (listrover->temp1!=3) && (levelheight > 1) &&
6398 (abs(listrover->z - ob->z) < 5) && (!ob->momentumz)
6399 )
6400 {
6401 {
6402 op = (FixedMul((int)GRAVITY,(int)((ob->z-10)<<16))<<1);
6403 ob->momentumz = -FixedSqrtHP(op);
6404 }
6405 SD_PlaySoundRTP(SD_SPRINGBOARDSND,listrover->x,listrover->y);
6406 NewState(listrover,&s_spring2);
6407
6408 }
6409
6410
6411
6412 if ((tcl == firejetobj) && (ob->z < listrover->z))
6413 continue;
6414
6415 if ((!(listrover->flags & FL_BLOCK)) && (actrad == oldrad)) // if not blocking
6416 // and actor not avoiding
6417 // env. danger
6418 continue;
6419
6420
6421
6422 if (tcl == crushcolobj)
6423 checkz = listrover->temp2;
6424 else
6425 checkz = listrover->z;
6426
6427 #define MINACTORZDIFF 58
6428
6429 dzt = abs(checkz - ob->z);
6430 dztp1 = abs(checkz - tryz);
6431
6432 if ((tcl == diskobj) && (dztp1 <= MINACTORZDIFF) && zstoppable &&
6433 (ocl != b_heinrichobj)
6434 )
6435 CheckStepping(ob,listrover,MINACTORZDIFF);
6436
6437 dztp1 = abs(checkz - tryz);
6438
6439
6440
6441 if ((dzt > (MINACTORZDIFF - 25)) && (dzt < MINACTORZDIFF) &&
6442 (dztp1 < MINACTORZDIFF) && (tcl < roboguardobj) &&
6443 (ocl < roboguardobj)
6444 )
6445 {
6446 int rdx,rdy;
6447
6448 rdx = abs(ob->x - listrover->x);
6449 rdy = abs(ob->y - listrover->y);
6450 if ((rdx < actrad) && (rdy < actrad))
6451 {
6452 if (ob->z > listrover->z)
6453 listrover->z = ob->z - MINACTORZDIFF;
6454 else
6455 ob->z = listrover->z - MINACTORZDIFF;
6456
6457 dzt = dztp1 = MINACTORZDIFF;
6458 }
6459
6460 }
6461
6462
6463 if ((dztp1 >= MINACTORZDIFF) || (dzt >= MINACTORZDIFF))
6464 {
6465 if ((dzt >= MINACTORZDIFF) && (dztp1 <= MINACTORZDIFF) &&
6466 zstoppable
6467 )
6468 {//ob->momentumz = 0;
6469 if (ob->z < listrover->z)
6470 {
6471 ob->z = listrover->z - MINACTORZDIFF;
6472 ob->momentumz = 0;
6473 }
6474 else
6475 ob->momentumz = 2*GRAVITY;
6476 if ((listrover->z > ob->z) && (tcl < roboguardobj) && (ocl < roboguardobj) &&
6477 (!(listrover->flags & FL_DYING))
6478 )
6479
6480 {
6481 DamageThing(listrover,5);
6482 BattleCrushCheck(ob,listrover);
6483 Collision(listrover,ob,listrover->momentumx,listrover->momentumy);
6484 /*
6485 if ((ocl == playerobj) && (listrover->flags & FL_DYING))
6486 GivePoints(starthitpoints[gamestate.difficulty][tcl]);
6487 */
6488 }
6489
6490 if (((tcl == bladeobj) || (tcl == diskobj)) && (ob->z < listrover->z))
6491 {
6492 ob->whatever = listrover;
6493 if (listrover->flags & FL_ACTIVE)
6494 ob->flags |= FL_RIDING;
6495 listrover->whatever = ob;
6496 }
6497
6498 //Debug("\nplayerz %d, tryz %d momz zeroed at %d, clearances %d and %d",
6499 // ob->z,tryz,listrover->z-64 + (listrover->momentumz >> 16),dzt,dztp1);
6500
6501 }
6502
6503 continue;
6504 }
6505
6506
6507 CheckProximitySpecials(ob,listrover);
6508
6509
6510 ACTORSTOP = true;
6511 if (!ob->momentumz)
6512 return NO_MOVEMENT;
6513
6514 }
6515
6516
6517 for (y=tileylow;y<=tileyhigh;y++)
6518 for (x=tilexlow;x<=tilexhigh;x++)
6519 {
6520 area = AREANUMBER(x,y);
6521 if (ValidAreanumber(area) && (areatried[area]==0))
6522 {
6523 areatried[area] = 1;
6524 goto actors;
6525 }
6526 }
6527
6528
6529
6530 if (ACTORSTOP==true)
6531 return Z_MOVEMENT_ONLY;
6532
6533 return OK_TO_CONTINUE;
6534 }
6535
6536
6537
CheckRegularWalls(objtype * ob,int tryx,int tryy,int tryz)6538 movement_status CheckRegularWalls(objtype *ob,int tryx,int tryy,int tryz)
6539 {
6540 int tilexlow,tilexhigh,tileylow,tileyhigh,x,y,radius;
6541 classtype ocl;
6542 boolean WALLSTOP,ISPLAYER=false;
6543
6544 ocl = ob->obclass;
6545 tryz=tryz;
6546
6547
6548 if (ocl != playerobj)
6549 {
6550 radius = ACTORSIZE - 0x1000;
6551 //actrad = MINACTORDIST;
6552 //if ((ob->dir == nodir) && (ocl != b_robobossobj) &&
6553 // (ocl != wallopobj) && (ocl != roboguardobj) && (ocl != diskobj)
6554 // )
6555 // Error("ob called with nodir");
6556 if (ocl == boulderobj)
6557 radius += (ACTORSIZE/4);
6558 else if (ocl == b_darksnakeobj)
6559 radius -= 6000;
6560 else if (ocl == inertobj)
6561 radius -= 0x2000;
6562 }
6563
6564 else
6565 {
6566 radius = PLAYERSIZE;
6567 ISPLAYER = true;
6568 }
6569
6570
6571 tilexlow = (int)((tryx-radius) >>TILESHIFT);
6572 tileylow = (int)((tryy-radius) >>TILESHIFT);
6573
6574 tilexhigh = (int)((tryx+radius) >>TILESHIFT);
6575 tileyhigh = (int)((tryy+radius) >>TILESHIFT);
6576
6577
6578 WALLSTOP = false;
6579
6580 for (y=tileylow;y<=tileyhigh;y++)
6581 for (x=tilexlow;x<=tilexhigh;x++)
6582 {
6583 wall_t *tempwall;
6584 int wall;
6585
6586 tempwall = (wall_t*)actorat[x][y];
6587 wall=tilemap[x][y];
6588 if (tempwall)
6589 {
6590 if (tempwall->which==WALL)// && IsWindow(x,y)==false)
6591 {
6592 if (ocl == boulderobj)
6593 {
6594 #if (SHAREWARE == 0)
6595 NewState(ob,&s_bouldersink1);
6596 #endif
6597 SD_PlaySoundRTP(SD_BOULDERHITSND,ob->x,ob->y);
6598 }
6599 else if (ISPLAYER && (!(ob->flags & FL_DYING)) &&
6600 (!(ob->flags & FL_AV)) &&
6601 (tempwall->flags & FL_W_DAMAGE))
6602 {
6603 DamageThing(ob,5);
6604 Collision(ob,(objtype*)tempwall,0,0);
6605 M_CheckPlayerKilled(ob);
6606 SD_PlaySoundRTP(SD_PLAYERBURNEDSND,ob->x,ob->y);
6607 }
6608
6609 //return false;
6610 WALLSTOP = true;
6611 if ((ocl == inertobj) &&
6612 (ob->dirchoosetime == GIBVALUE) &&
6613
6614 (((ob->tilex - x) == 0) != ((ob->tiley - y) == 0)) &&
6615 (ob->z > -28)
6616
6617 )
6618 {
6619 // SoftError ("Blood Dripping oldpolltime=%ld\n",oldpolltime);
6620 BloodDrip(ob,x,y);
6621 return NO_MOVEMENT;
6622 }
6623
6624 if (!ob->momentumz)
6625 return NO_MOVEMENT;
6626 else// if (ocl != inertobj)
6627 return Z_MOVEMENT_ONLY;
6628 //else
6629 //goto doors;
6630 }
6631
6632 else if (tempwall->which==PWALL)
6633 {
6634 pwallobj_t*pw;
6635 int dx,dy;
6636
6637 pw=(pwallobj_t *)tempwall;
6638 dx = abs(pw->x - tryx);
6639 if (dx > PWALLRAD+0x5000)
6640 continue;
6641
6642 dy = abs(pw->y - tryy);
6643 if (dy > PWALLRAD+0x5000)
6644 continue;
6645
6646 return NO_MOVEMENT;
6647 }
6648
6649 }
6650 }
6651
6652 return OK_TO_CONTINUE;
6653
6654 }
6655
6656
6657
CheckStaticObjects(objtype * ob,int tryx,int tryy,int tryz)6658 movement_status CheckStaticObjects(objtype *ob,int tryx,int tryy,int tryz)
6659 {
6660 int dx,dy,dzt,dztp1,x,y;
6661 statobj_t*tempstat;
6662 int sprrad,oldsrad,sprtrad;
6663 boolean specialstat=false,widestat=false,zstoppable;
6664 int sprxlow,sprxhigh,sprylow,spryhigh;
6665 boolean SPRSTOP;
6666 classtype ocl;
6667
6668 ocl = ob->obclass;
6669
6670 if (ocl != playerobj)
6671 sprtrad = ACTORSIZE - 0x1000;
6672 else
6673 sprtrad = ACTORSIZE - 0x1000 + 0x10000;
6674
6675
6676
6677 sprxlow = (int)((tryx-sprtrad) >>TILESHIFT);
6678 sprylow = (int)((tryy-sprtrad) >>TILESHIFT);
6679
6680 sprxhigh = (int)((tryx+sprtrad) >>TILESHIFT);
6681 spryhigh = (int)((tryy+sprtrad) >>TILESHIFT);
6682
6683 if (sprxlow < 0)
6684 sprxlow = 0;
6685
6686 if (sprxhigh > (MAPSIZE-1))
6687 sprxhigh = MAPSIZE-1;
6688
6689 if (sprylow < 0)
6690 sprylow = 0;
6691
6692 if (spryhigh > (MAPSIZE-1))
6693 spryhigh = MAPSIZE-1;
6694
6695 SPRSTOP = false;
6696 sprrad = 0x4500;
6697 zstoppable = (!(ob->flags & FL_DYING));
6698 oldsrad = sprrad;
6699
6700 for (y=sprylow;y<=spryhigh;y++)
6701 for (x=sprxlow;x<=sprxhigh;x++)
6702 {
6703 tempstat = sprites[x][y];
6704 sprrad = oldsrad;
6705
6706 if (tempstat)
6707 {
6708 specialstat = ((tempstat->itemnumber == stat_heatgrate) ||
6709 (tempstat->itemnumber == stat_pit)
6710 );
6711
6712 widestat = (((tempstat->itemnumber >= stat_bcolumn) &&
6713 (tempstat->itemnumber <= stat_icolumn)) ||
6714 (tempstat->itemnumber == stat_disk)
6715 );
6716
6717 if ((tempstat->flags & FL_BLOCK) || (specialstat==true))
6718 {
6719 if ((specialstat==true) && (ocl !=playerobj) &&
6720 (ob->state->think != T_Collide)
6721 )
6722 sprrad += 0x5000;
6723
6724 if (widestat==true)
6725 sprrad += 0x3b00;
6726
6727
6728 if ((tempstat->itemnumber == stat_ironbarrel) ||
6729 (tempstat->itemnumber == stat_bonusbarrel))
6730 sprrad += 0x5000;
6731
6732 dx = abs(tryx - tempstat->x);
6733 if (dx > sprrad)
6734 continue;
6735 dy = abs(tryy - tempstat->y);
6736 if (dy > sprrad)
6737 continue;
6738
6739 #define MINSTATZDIFF 58
6740
6741 dzt = abs(ob->z - tempstat->z);
6742 dztp1 = abs(tryz - tempstat->z);
6743
6744 if (widestat && (dztp1 <= MINSTATZDIFF) && zstoppable &&
6745 (ocl != b_heinrichobj)
6746 )
6747 CheckStepping(ob,tempstat,MINSTATZDIFF);
6748
6749
6750 dztp1 = abs(tryz - tempstat->z);
6751
6752 #if (SHAREWARE == 0)
6753 if ((ocl == b_darksnakeobj) && (tempstat->itemnumber == stat_heatgrate))
6754 {
6755 if (ob->state->think == T_DarkSnakeChase)
6756 NewState(ob,&s_darkmonkredhead);
6757 else
6758 NewState(ob,&s_darkmonkredlink);
6759 ob->temp3 ++; // make shootable
6760 }
6761 #endif
6762
6763 if (specialstat==true)
6764 continue;
6765
6766
6767 if ((dztp1 >= MINSTATZDIFF) || (dzt >= MINSTATZDIFF))
6768 {if ((dzt >= MINSTATZDIFF) && (dztp1 <= MINSTATZDIFF) && zstoppable)
6769 {//ob->momentumz = 0;
6770 if (ob->z <= tempstat->z)
6771 {
6772 ob->z = tempstat->z - MINSTATZDIFF;
6773 ob->momentumz = 0;
6774 }
6775 else
6776 ob->momentumz = 2*GRAVITY; // ((2*GRAVITY + GRAVITY) >> 16) = 1
6777 }
6778 continue;
6779 }
6780
6781
6782 if (ocl == boulderobj)
6783 {if ((tempstat->itemnumber < stat_bcolumn) ||
6784 (tempstat->itemnumber > stat_icolumn)
6785 )
6786 {
6787 tempstat->flags |= FL_SHOOTABLE;
6788 DamageThing(tempstat,tempstat->hitpoints);
6789 continue;
6790 }
6791 #if (SHAREWARE == 0)
6792 else
6793 NewState(ob,&s_bouldersink1);
6794 #endif
6795 }
6796 //ob->momentumz=0;
6797 //return false;
6798 SPRSTOP=true;
6799 if (!ob->momentumz)
6800 return NO_MOVEMENT;
6801 }
6802 }
6803 }
6804 if (SPRSTOP == true)
6805 return Z_MOVEMENT_ONLY;
6806
6807 return OK_TO_CONTINUE;
6808
6809 }
6810
6811
6812
6813
6814
6815 //============== Platform craziness ======================================
6816
6817
6818 #define ClipHeight(ob,clipz) \
6819 { ob->momentumz = 0; \
6820 \
6821 if (ISPLAYER && (ob->z != clipz) && (ob->temp2 == 0)) \
6822 {playertype *pstate; \
6823 int dz = ob->z - clipz; \
6824 \
6825 M_LINKSTATE(ob,pstate); \
6826 \
6827 pstate->heightoffset = pstate->oldheightoffset + dz; \
6828 ob->temp2 = (dz >= 0)?(STEPUP):(STEPDOWN); \
6829 } \
6830 \
6831 ob->z = clipz; \
6832 }
6833
6834 //======================
6835
6836 #define CheckSpecialGibMovement(blocker) \
6837 { \
6838 int centerx = ((trytilex<<16) + 0x8000); \
6839 int centery = ((trytiley<<16) + 0x8000); \
6840 \
6841 if (blocker->vertical==false) \
6842 { \
6843 int dyt = centery - ob->y; \
6844 int dytp1 = centery - tryy; \
6845 \
6846 if ((abs(dytp1) > abs(dyt)) && \
6847 (SGN(dyt) == SGN(dytp1)) \
6848 ) \
6849 return OK_TO_CONTINUE; \
6850 \
6851 } \
6852 else \
6853 { \
6854 int dxt = centerx - ob->x; \
6855 int dxtp1 = centerx - tryx; \
6856 \
6857 if ((abs(dxtp1) > abs(dxt)) && \
6858 (SGN(dxt) == SGN(dxtp1)) \
6859 ) \
6860 return OK_TO_CONTINUE; \
6861 \
6862 } \
6863 }
6864
6865
CheckMaskedWalls(objtype * ob,int tryx,int tryy,int tryz)6866 movement_status CheckMaskedWalls(objtype *ob,int tryx,int tryy,int tryz)
6867 {
6868 int trytilex,trytiley;
6869 boolean MWALLSTOP;
6870 int ISPLAYER = (ob->obclass == playerobj);
6871 classtype ocl = ob->obclass;
6872
6873 trytilex = (tryx >> TILESHIFT);
6874 trytiley = (tryy >> TILESHIFT);
6875 MWALLSTOP = false;
6876 //for (y=tileylow;y<=tileyhigh;y++)
6877 // for (x=tilexlow;x<=tilexhigh;x++)
6878
6879 if (M_ISMWALL(trytilex,trytiley))
6880 {
6881 int wall = tilemap[trytilex][trytiley];
6882 maskedwallobj_t * mw;
6883
6884 mw=maskobjlist[wall&0x3ff];
6885
6886 if (ocl == inertobj)
6887 CheckSpecialGibMovement(mw);
6888
6889 if (!(mw->flags&MW_BLOCKING))
6890 {
6891 if (mw->flags&MW_NONDOGBLOCKING)
6892 {
6893 if ((ocl==playerobj)&&(ob->flags&FL_DOGMODE))
6894 {
6895 if (ob->z < nominalheight)
6896 {
6897 MWALLSTOP = true;
6898 if (!ob->momentumz)
6899 return NO_MOVEMENT;
6900 }
6901 }
6902 else
6903 {
6904 MWALLSTOP = true;
6905 if (!ob->momentumz)
6906 return NO_MOVEMENT;
6907 }
6908 }
6909
6910
6911 else
6912 {
6913 if (mw->flags & MW_ABOVEPASSABLE)
6914 {if (mw->flags & MW_MIDDLEPASSABLE) // ==> not bottom
6915 {if (ob->z > LOWFALLCLIPZ+MAXSTEPHEIGHT)
6916 MWALLSTOP = true;
6917 else if (tryz >= LOWFALLCLIPZ)
6918 ClipHeight(ob,LOWFALLCLIPZ);
6919 }
6920 else if (mw->flags & MW_BOTTOMPASSABLE)
6921 {if ((ob->z > HIGHFALLCLIPZ+MAXSTEPHEIGHT) && (ob->z < LOWRISECLIPZ))
6922 MWALLSTOP = true;
6923 else if (ob->z <= HIGHFALLCLIPZ+MAXSTEPHEIGHT)
6924 {if (tryz >= HIGHFALLCLIPZ)
6925 ClipHeight(ob,HIGHFALLCLIPZ);
6926 }
6927 else if (tryz <= LOWRISECLIPZ)
6928 ob->momentumz = 0;
6929
6930 }
6931 else // ==> above only
6932 {if (ob->z > HIGHFALLCLIPZ+MAXSTEPHEIGHT)
6933 MWALLSTOP = true;
6934 else if (tryz >= HIGHFALLCLIPZ)
6935 ClipHeight(ob,HIGHFALLCLIPZ);
6936 }
6937
6938 }
6939 else if (mw->flags & MW_MIDDLEPASSABLE)
6940 {if (mw->flags & MW_BOTTOMPASSABLE) //==> not above passable
6941 {if (ob->z >= HIGHRISECLIPZ)
6942 {if (tryz <= HIGHRISECLIPZ)
6943 ob->momentumz = 0;
6944 }
6945 else if (tryz <= HIGHRISECLIPZ)
6946 MWALLSTOP = true;
6947 }
6948
6949 else //==> middle only
6950 {if (ob->z > LOWFALLCLIPZ+MAXSTEPHEIGHT)
6951 MWALLSTOP = true;
6952 else if (tryz >= LOWFALLCLIPZ)
6953 ClipHeight(ob,LOWFALLCLIPZ)
6954 else
6955 {if (ob->z >= HIGHRISECLIPZ)
6956 {if (tryz <= HIGHRISECLIPZ)
6957 ob->momentumz = 0;
6958 }
6959 else if (tryz <= HIGHRISECLIPZ)
6960 MWALLSTOP = true;
6961 }
6962 }
6963
6964 }
6965 else // ==> bottompassable only
6966 {if (ob->z < LOWRISECLIPZ)
6967 MWALLSTOP = true;
6968 else if (tryz < LOWRISECLIPZ)
6969 ob->momentumz = 0;
6970 }
6971
6972 }
6973 }
6974 else
6975 {
6976 if ( (mw->flags&MW_SHOOTABLE) &&
6977 (mw->flags&MW_BLOCKINGCHANGES) &&
6978 (ob->z >= nominalheight)
6979
6980 )
6981 {
6982 int speed=FindDistance(ob->momentumx,ob->momentumy);
6983 if ((speed>0x2800) && (!(ob->flags & FL_DYING)))
6984 {
6985 if (ob->obclass == playerobj)
6986 {
6987 DamageThing(ob,10);
6988 Collision(ob,(objtype*)mw,0,0);
6989 }
6990 UpdateMaskedWall(wall&0x3ff);
6991 if (tryz < nominalheight)
6992 ob->momentumz = 0;
6993 }
6994 else
6995 {
6996 MWALLSTOP = true;
6997 if (!ob->momentumz)
6998 return NO_MOVEMENT;
6999 }
7000 }
7001 else
7002 {
7003 MWALLSTOP = true;
7004 if (!ob->momentumz)
7005 return NO_MOVEMENT;
7006 }
7007 }
7008 }
7009
7010 if (MWALLSTOP == true)
7011 return Z_MOVEMENT_ONLY;
7012
7013 return OK_TO_CONTINUE;
7014
7015 }
7016
7017
7018
CheckDoors(objtype * ob,int tryx,int tryy,int tryz)7019 movement_status CheckDoors(objtype *ob,int tryx,int tryy,int tryz)
7020 {
7021 int trytilex,trytiley;
7022 int ocl;
7023
7024
7025 trytilex = (tryx >> TILESHIFT);
7026 trytiley = (tryy >> TILESHIFT);
7027 ocl = ob->obclass;
7028
7029
7030 if (M_ISDOOR(trytilex,trytiley))
7031 {
7032 doorobj_t*tempdoor;
7033 int doorn;
7034
7035 doorn = tilemap[trytilex][trytiley];
7036
7037 tempdoor = doorobjlist[doorn&0x3ff];
7038 if (tempdoor->action == dr_open)
7039 {
7040
7041 if (ob->z >= nominalheight)
7042 {
7043 if (tryz < nominalheight)
7044 ob->momentumz = 0;
7045 return OK_TO_CONTINUE;
7046 }
7047
7048 }
7049 if (ocl == inertobj)
7050 {
7051 CheckSpecialGibMovement(tempdoor);
7052 }
7053 else if ((ocl == playerobj) || (ocl > b_darksnakeobj))
7054 return NO_MOVEMENT;
7055 else if (ob->state->think != T_Collide)
7056 {
7057
7058 #define DOOR_LOCKED(door) \
7059 (((door->flags & DF_ELEVLOCKED) || (door->lock)) && \
7060 (ob->obclass != b_darianobj) \
7061 )
7062 #define GAS_DOOR(x,y) (MISCVARS->GASON && (MAPSPOT(x,y,1) == GASVALUE))
7063
7064 if ((!DOOR_LOCKED(tempdoor)) &&
7065 (!GAS_DOOR(trytilex,trytiley))
7066 )
7067
7068
7069 //)
7070 {
7071 ob->door_to_open = doorn&0x3ff;
7072 LinkedOpenDoor(ob->door_to_open);
7073 if (tempdoor->eindex != -1)
7074 OperateElevatorDoor(doorn&0x3ff);
7075 }
7076
7077 //if ((nstate = M_S(USE)) != NULL)
7078 //{ob->whatever = ob->state;
7079 // NewState(ob,nstate);
7080 // ob->flags |= FL_USE;
7081 // }
7082 return NO_MOVEMENT;
7083 }
7084 else
7085 return NO_MOVEMENT;
7086 }
7087
7088 return OK_TO_CONTINUE;
7089 }
7090
7091
7092
ActorTryMove(objtype * ob,int tryx,int tryy,int tryz)7093 boolean ActorTryMove(objtype*ob,int tryx, int tryy, int tryz)
7094 {
7095
7096 movement_status (*reduced_movement_check[3])(objtype*,int,int,int)=
7097 {
7098 CheckRegularWalls,
7099 CheckMaskedWalls,
7100 CheckDoors,
7101 };
7102
7103
7104 movement_status (*complete_movement_check[5])(objtype*,int,int,int)=
7105 {
7106 CheckOtherActors,
7107 CheckRegularWalls,
7108 CheckStaticObjects,
7109 CheckMaskedWalls,
7110 CheckDoors,
7111 };
7112
7113 movement_status (**movement_function)(objtype*,int,int,int);
7114 movement_status movement_check_result;
7115 int numcheckfunctions;
7116 int i;
7117 boolean xyblocked;
7118
7119
7120
7121
7122 if ((tryz < -30) && (sky==0) && (ob->obclass != inertobj))
7123 {
7124 ob->z = -28;
7125 ob->momentumz = 0;
7126 return false;
7127 }
7128
7129 if ((!InMapBounds(tryx>>16,tryy>>16)) ||
7130 ((ob->obclass != playerobj) && (IsWindow((tryx>>16),(tryy>>16))))
7131 )
7132 return false;
7133
7134 switch(ob->obclass)
7135 {
7136 case inertobj:
7137 case bladeobj:
7138 case firejetobj:
7139 movement_function = &reduced_movement_check[0];
7140 numcheckfunctions = 3;
7141 break;
7142
7143 default:
7144 movement_function = &complete_movement_check[0];
7145 numcheckfunctions = 5;
7146 break;
7147 }
7148
7149
7150 for(xyblocked=false,i=0;i<numcheckfunctions;i++)
7151 {
7152 movement_check_result = movement_function[i](ob,tryx,tryy,tryz);
7153 if (movement_check_result == Z_MOVEMENT_ONLY)
7154 xyblocked = true;
7155
7156 else if (movement_check_result == NO_MOVEMENT)
7157 return false;
7158 }
7159
7160 if (xyblocked == true)
7161 return false;
7162
7163
7164 return true;
7165
7166 }
7167
7168
PushWallMove(int num)7169 void PushWallMove(int num)
7170 {
7171 int tcl;
7172 pwallobj_t *pwall;
7173 int dx,dy;
7174 int actrad;
7175 objtype *temp;
7176 boolean pushem;
7177 int tryx,tryy,areanumber,trytilex,trytiley;
7178
7179
7180 pwall=pwallobjlist[num];
7181
7182 actrad = PWALLRAD + 0x5000;
7183 tryx = (pwall->x + pwall->momentumx);
7184 tryy = (pwall->y + pwall->momentumy);
7185 trytilex = (tryx >> 16);
7186 trytiley = (tryy >> 16);
7187
7188 areanumber = AREANUMBER(trytilex,trytiley);
7189
7190
7191 for(temp=firstareaactor[areanumber];temp;temp=temp->nextinarea)
7192 {
7193 tcl = temp->obclass;
7194
7195 if (temp->flags & FL_HEAD) //ignore NME's head and wheels
7196 continue;
7197
7198 if ((temp->flags & FL_DYING) || (!(temp->flags & FL_SHOOTABLE)))
7199 continue;
7200
7201 if (tcl > b_darianobj)
7202 continue;
7203
7204
7205 dx = abs(tryx - temp->x);
7206 if (dx > actrad)
7207 continue;
7208
7209 dy = abs(tryy - temp->y);
7210 if (dy > actrad)
7211 continue;
7212
7213 if (pwall->flags&PW_DAMAGE)
7214 {if (!((tcl == playerobj) && (temp->flags & FL_AV)))
7215 DamageThing(temp,5);
7216
7217 Collision(temp,(objtype*)pwall,0,0);
7218 M_CheckPlayerKilled(temp);
7219 if (temp->flags & FL_DYING)
7220 return;
7221
7222 }
7223
7224 pushem=false;
7225 switch (pwall->dir)
7226 {
7227
7228 #define PWALLTOL (0xc000)
7229
7230 case north:
7231 if ((temp->y<pwall->y) && (dx<PWALLTOL))
7232 pushem=true;
7233 break;
7234 case east:
7235 if ((temp->x>pwall->x) && (dy<PWALLTOL))
7236 pushem=true;
7237 break;
7238 case northeast:
7239 if ((temp->y<pwall->y) && (dx<PWALLTOL))
7240 pushem=true;
7241 else if ((temp->x>pwall->x) && (dy<PWALLTOL))
7242 pushem=true;
7243 break;
7244 case northwest:
7245 if ((temp->y<pwall->y) && (dx<PWALLTOL))
7246 pushem=true;
7247 else if ((temp->x<pwall->x) && (dy<PWALLTOL))
7248 pushem=true;
7249 break;
7250 case south:
7251 if ((temp->y>pwall->y) && (dx<PWALLTOL))
7252 pushem=true;
7253 break;
7254 case west:
7255 if ((temp->x<pwall->x) && (dy<PWALLTOL))
7256 pushem=true;
7257 break;
7258 case southeast:
7259 if ((temp->y>pwall->y) && (dx<PWALLTOL))
7260 pushem=true;
7261 else if ((temp->x>pwall->x) && (dy<PWALLTOL))
7262 pushem=true;
7263 break;
7264 case southwest:
7265 if ((temp->y>pwall->y) && (dx<PWALLTOL))
7266 pushem=true;
7267 else if ((temp->x<pwall->x) && (dy<PWALLTOL))
7268 pushem=true;
7269 break;
7270 default:
7271 //Error ("Pushwall #%d has an illegal direction %d \n",num,pwall->dir);
7272 break;
7273 }
7274
7275
7276 //if (!pushem)
7277 //continue;
7278
7279 //temp->momentumx = temp->momentumy = 0;
7280 if (temp->obclass==playerobj)
7281 temp->flags|=FL_PUSHED;
7282
7283 if (!pushem)
7284 {
7285 Collision(temp,(objtype*)pwall,-temp->momentumx,-temp->momentumy);
7286 continue;
7287 }
7288
7289 if ((temp->obclass >= lowguardobj) && (temp->obclass < roboguardobj))
7290 {
7291
7292 temp->momentumx = temp->momentumy = temp->momentumz = 0;
7293 temp->hitpoints = 0;
7294
7295 if (gamestate.violence >= vl_high)
7296 temp->flags |= FL_HBM;
7297 Collision(temp,(objtype*)pwall,0,0);
7298 /*
7299 if (gamestate.violence < vl_high)
7300 {if ((tstate = UPDATE_STATES[CRUSH][temp->obclass - lowguardobj])!=NULL)
7301 NewState(temp,tstate);
7302
7303 else
7304 Error("\n\Null low-violence crush state in push wall crush, instance of %s",debugstr[temp->obclass]);
7305 }
7306 else
7307 {temp->shapeoffset = 0;
7308 //tactor->flags|=FL_HBM;
7309 NewState(temp,&s_guts1);
7310 //KillActor(temp);
7311 }*/
7312
7313 SD_PlaySoundRTP(SD_ACTORSQUISHSND,temp->x,temp->y);
7314 }
7315 else
7316 {
7317 if (!ActorTryMove(temp,temp->x + temp->momentumx,temp->y + temp->momentumy,
7318 temp->z + (temp->momentumz >> 16))
7319 )
7320 {
7321 DamageThing(temp,30);
7322 if ((temp->obclass==playerobj) && (temp->hitpoints <= 0))
7323 temp->target = (objtype *)pwall;
7324 }
7325
7326 Collision(temp,(objtype*)pwall,pwall->momentumx-temp->momentumx,pwall->momentumy-temp->momentumy);
7327 M_CheckPlayerKilled(temp);
7328 }
7329
7330
7331
7332 }
7333 }
7334
ActorMovement(objtype * ob)7335 void ActorMovement (objtype *ob)
7336 {int tryx,tryy,tryz,limitok,max,friction,ocl;
7337
7338
7339
7340 if ((ob->obclass == strikeguardobj) && (!(ob->flags & FL_DYING)) &&
7341 (gamestate.difficulty > gd_easy)
7342 )
7343 {
7344 AvoidPlayerMissile(ob);
7345 ob->flags &= ~FL_FULLLIGHT;
7346 }
7347
7348
7349 if ((!ob->momentumx) && (!ob->momentumy) && (!ob->momentumz))
7350 {if (ob->flags & FL_RIDING)
7351 goto ride;
7352 else
7353 return;
7354 }
7355
7356
7357 limitok = 1;
7358
7359 friction = ACTORFRICTION;
7360 if (!(ob->flags & FL_DYING))
7361 friction >>= 1;
7362 ocl = ob->obclass;
7363 if (ocl == playerobj)
7364 {
7365 playertype *pstate;
7366
7367 M_LINKSTATE(ob,pstate);
7368 max = pstate->topspeed;
7369 friction = PLAYERFRICTION;
7370 if ((ob->temp2 == PITFALL) || (ob->temp2 == PITRISE))
7371 friction >>= 4;
7372 }
7373
7374
7375 else if (/*(ob->state->think != T_Collide) &&*/ (ocl != b_robobossobj) &&
7376 (ocl != boulderobj) && (ocl !=b_darkmonkobj) && (ocl != b_darksnakeobj) &&
7377 (ocl != inertobj) && (ocl != collectorobj))
7378 max = MAXMOVE;
7379
7380 else
7381 limitok = 0;
7382
7383 if (limitok)
7384 {if (ocl == playerobj)
7385 {int dist,scale;
7386
7387 dist = FindDistance(ob->momentumx,ob->momentumy);
7388 if (dist > max)
7389 {scale = FixedDiv2(max,dist);
7390 ob->momentumx = FixedMul(ob->momentumx,scale);
7391 ob->momentumy = FixedMul(ob->momentumy,scale);
7392 }
7393 }
7394 else
7395 {
7396 if (ob->momentumx > max)
7397 ob->momentumx = max;
7398 else if (ob->momentumx < -max)
7399 ob->momentumx = -max;
7400 if (ob->momentumy > max)
7401 ob->momentumy = max;
7402 else if (ob->momentumy < -max)
7403 ob->momentumy = -max;
7404 }
7405
7406 }
7407
7408 tryx = ob->x + ob->momentumx;
7409 tryy = ob->y + ob->momentumy;
7410 tryz = ob->z + (ob->momentumz >> 16);
7411
7412 if (ocl != playerobj)
7413 ob->flags &= ~FL_STUCK;
7414
7415
7416 if (!ActorTryMove (ob, tryx, tryy, tryz))
7417 {if (ocl == playerobj)
7418 {if (!(ob->flags & FL_ELASTO))
7419 PlayerSlideMove (ob);
7420 else
7421 {if (ActorTryMove(ob,tryx, ob->y-ob->momentumy,tryz))
7422 ob->momentumy = -(ob->momentumy);
7423 else if (ActorTryMove(ob,ob->x-ob->momentumx,tryy,tryz))
7424 ob->momentumx = -(ob->momentumx);
7425 else
7426 ZEROMOM;
7427 }
7428 }
7429
7430 else
7431 {ZEROMOM;
7432 ob->flags |= FL_STUCK;
7433 return;
7434 }
7435 }
7436
7437 MoveActor(ob);
7438
7439
7440 ride:
7441
7442 if (ob->flags & FL_RIDING)
7443 {
7444 objtype *ride = (objtype*)(ob->whatever);
7445
7446 ob->z += (ride->momentumz >> 16);
7447
7448 if ((ride->momentumx || ride->momentumy) &&
7449 ActorTryMove(ob,ob->x+ride->momentumx,ob->y+ride->momentumy,tryz)
7450 )
7451 SetFinePosition(ob,ob->x+ride->momentumx,ob->y+ride->momentumy);
7452 }
7453
7454
7455 #define SLIDER(ob) ((ob->flags & FL_NOFRICTION) && (ob->state->think != T_Collide))
7456 #define AIRBORNE(ob) ((ob->obclass != playerobj) && (ob->z != nominalheight) &&\
7457 (!IsPlatform(ob->tilex,ob->tiley)) && \
7458 (DiskAt(ob->tilex,ob->tiley) == NULL) \
7459 )
7460
7461 if (SLIDER(ob) || AIRBORNE(ob))
7462 return;
7463
7464 if ( (abs(ob->momentumx) < STOPSPEED) &&
7465 (abs(ob->momentumy) < STOPSPEED)
7466 )
7467 {
7468 ZEROMOM;
7469 }
7470
7471 else if ((ob->flags & FL_DYING) && (ob->state == ob->state->next))
7472 {ob->momentumx = FixedMul (ob->momentumx, DEADFRICTION);
7473 ob->momentumy = FixedMul (ob->momentumy, DEADFRICTION);
7474
7475 }
7476
7477 else
7478 {ob->momentumx = FixedMul (ob->momentumx, friction);
7479 ob->momentumy = FixedMul (ob->momentumy, friction);
7480
7481 }
7482
7483
7484
7485 }
7486
7487
7488
7489
T_Guts(objtype * ob)7490 void T_Guts(objtype*ob)
7491 {if (ob->ticcount)
7492 return;
7493 SpawnParticles(ob,GUTS,50);
7494
7495 }
7496
7497
T_Special(objtype * ob)7498 void T_Special(objtype*ob)
7499 {
7500 if (ob->ticcount)
7501 return;
7502
7503 #if (SHAREWARE == 0)
7504 if (ob->state == &s_NMEheadexplosion)
7505 {
7506 ob->z -= 42;
7507 SetGibSpeed(0x4000);
7508 SpawnParticles(ob,gt_sparks,100);
7509 ResetGibSpeed();
7510 SD_PlaySoundRTP(SD_EXPLODESND,ob->x,ob->y);
7511 return;
7512 }
7513 #endif
7514 if (ob->obclass != b_robobossobj)
7515 return;
7516
7517 NewState(ob,&s_bossdeath);
7518 }
7519
7520
7521
7522
SpawnBoulder(int tilex,int tiley,int dir)7523 void SpawnBoulder(int tilex,int tiley,int dir)
7524 {
7525 #if (SHAREWARE == 1)
7526 tilex = tilex;
7527 tiley = tiley;
7528 dir = dir;
7529 Error("Boulders aren't allowed in shareware!");
7530 #endif
7531 #if (SHAREWARE == 0)
7532 SpawnNewObj(tilex,tiley,&s_boulderspawn,inertobj);
7533 new->z = 0;
7534 PreCacheActor(boulderobj,0);
7535 new->dir = 2*dir;
7536 #endif
7537
7538 }
7539
7540
7541
7542 #define InitSprayPart(newflags) \
7543 { \
7544 new->hitpoints = starthitpoints[gamestate.difficulty][b_robobossobj]; \
7545 new->dir = dir*4; \
7546 new->speed = 7*SPDPATROL; \
7547 new->door_to_open = -1; \
7548 new->flags |= (newflags); \
7549 } \
7550
7551
SpawnMultiSpriteActor(classtype actorclass,int tilex,int tiley,int dir)7552 void SpawnMultiSpriteActor(classtype actorclass, int tilex,int tiley,int dir)
7553 {
7554
7555
7556
7557 #if (SHAREWARE==1)
7558
7559 actorclass = actorclass;
7560 tilex = tilex;
7561 tiley = tiley;
7562 dir = dir;
7563 Error("\nSPRAY not allowed in shareware !");
7564
7565 #else
7566
7567 {
7568 objtype *temp;
7569
7570 gamestate.killtotal++;
7571
7572 SpawnNewObj(tilex,tiley,&s_NMEstand,actorclass);
7573 InitSprayPart(FL_BLOCK|FL_NOFRICTION|FL_SHOOTABLE);
7574
7575 new->temp1 = -1; // temp1 used as one-event queue for directions when chasing
7576 // -1 when isn't waiting to try new dir, dirnumber when waiting
7577 temp = new;
7578
7579 SpawnNewObj(tilex,tiley,&s_NMEhead1,actorclass);
7580 InitSprayPart(FL_NOFRICTION|FL_SHOOTABLE|FL_HEAD|FL_NEVERMARK);
7581
7582 //new->whatever = temp; // head points to body
7583
7584 temp->whatever = new; // body points to head
7585
7586 SpawnNewObj(tilex,tiley,&s_NMEwheels2,actorclass);
7587 InitSprayPart(FL_NOFRICTION|FL_SHOOTABLE|FL_HEAD|FL_NEVERMARK);
7588
7589
7590 //new->whatever = temp; // head points to body
7591 temp->target = new; // body also points to wheels
7592 actorat[tilex][tiley] = NULL;
7593 PreCacheActor(b_robobossobj,0);
7594 }
7595 #endif
7596 }
7597
7598
SpawnSnake(int tilex,int tiley)7599 void SpawnSnake(int tilex,int tiley)
7600 {
7601
7602 #if (SHAREWARE == 1)
7603 tilex = tilex;
7604 tiley = tiley;
7605 Error("snake not allowed in shareware!");
7606 #else
7607
7608 GetNewActor();
7609 MakeActive(new);
7610 new->flags |= (FL_DONE|FL_ABP|FL_NEVERMARK);
7611 SetTilePosition(new,tilex,tiley);
7612 SetVisiblePosition(new,new->x,new->y);
7613 new->obclass = b_darkmonkobj;
7614 new->which = ACTOR;
7615 new->z = nominalheight;
7616 if (SNAKELEVEL == 2)
7617 NewState(new,&s_darkmonkfastspawn);
7618 else
7619 NewState(new,&s_darkmonkhspawn);
7620 #endif
7621
7622 }
7623
SpawnGunThingy(classtype which,int tilex,int tiley,int dir)7624 void SpawnGunThingy(classtype which, int tilex, int tiley, int dir)
7625 {
7626 #if (SHAREWARE == 1)
7627 which = which;
7628 tilex = tilex;
7629 tiley = tiley;
7630 dir = dir;
7631
7632 Error("no emplacements allowed in shareware!");
7633 #else
7634 SpawnNewObj(tilex,tiley,&s_gunstand,which);
7635
7636
7637 if (!loadedgame)
7638 gamestate.killtotal++;
7639
7640 PreCacheActor(patrolgunobj,0);
7641
7642 new->hitpoints = starthitpoints[gamestate.difficulty][which];
7643 new->dir = dir*2;
7644 // new->speed = 0x500;
7645 // ParseMomentum(new,dirangle8[new->dir]);
7646 new->flags |= (FL_BLOCK|FL_SHOOTABLE);
7647 #endif
7648 }
7649
7650
SpawnFourWayGun(int tilex,int tiley)7651 void SpawnFourWayGun(int tilex, int tiley)
7652 {
7653 #if (SHAREWARE == 1)
7654 tilex = tilex;
7655 tiley = tiley;
7656 Error("no 4-way emplacements allowed in shareware!");
7657 #else
7658
7659
7660 SpawnNewObj(tilex,tiley,&s_4waygun,patrolgunobj);
7661 if (!loadedgame)
7662 gamestate.killtotal++;
7663
7664 PreCacheActor(patrolgunobj,0);
7665 new->temp1 = -1;
7666 new->hitpoints = starthitpoints[gamestate.difficulty][patrolgunobj]*3;
7667 new->flags |= (FL_BLOCK|FL_SHOOTABLE);
7668 #endif
7669 }
7670
7671
7672
7673
7674 /*
7675 =======================================================================
7676 =
7677 = NON-SHAREWARE CODE
7678 =
7679 =======================================================================
7680 */
7681
7682 #if (SHAREWARE == 0)
7683
T_BoulderSpawn(objtype * ob)7684 void T_BoulderSpawn(objtype*ob)
7685 {objtype *tactor;
7686 int dx,dy,cl;
7687
7688 if (!(ob->flags & FL_ACTIVE))
7689 return;
7690
7691 else if (!ob->ticcount)
7692 {for(tactor = firstareaactor[ob->areanumber];tactor;tactor = tactor->nextinarea)
7693 {cl = tactor->obclass;
7694 if (tactor == ob)
7695 continue;
7696
7697 if (!(tactor->flags & FL_SHOOTABLE))
7698 continue;
7699 dx = abs(tactor->x - ob->x);
7700 if (dx > MINACTORDIST)
7701 continue;
7702 dy = abs(tactor->y - ob->y);
7703 if (dy > MINACTORDIST)
7704 continue;
7705 if ((cl == b_heinrichobj) || (cl== b_darkmonkobj) ||
7706 (cl == b_darianobj) || (cl == b_robobossobj) ||
7707 (cl == pillarobj) || (cl == wallopobj) ||
7708 (cl == boulderobj))
7709 return;
7710 else break;
7711 }
7712
7713
7714 SpawnNewObj(ob->tilex,ob->tiley,&s_boulderdrop1,boulderobj);
7715 new->z = 0;
7716 new->dir = ob->dir;
7717 //new->angle = dirangle8[new->dir];
7718 new->speed = 0x4000;
7719 ParseMomentum(new,dirangle8[new->dir]);
7720 new->flags |= (FL_BLOCK|FL_NOFRICTION);
7721 new->flags &= ~FL_SHOOTABLE;
7722 new->whatever = ob;
7723 if (tactor)
7724 new->target = tactor;
7725 MakeActive(new);
7726 new->flags |= FL_ABP;
7727
7728 }
7729
7730 }
7731
T_BoulderDrop(objtype * ob)7732 void T_BoulderDrop(objtype*ob)
7733 {int dx,dy,dz;
7734 objtype * tactor;
7735 statetype *tstate;
7736
7737
7738 if (ob->state == &s_boulderdrop12)
7739 {
7740
7741 if (ob->z == nominalheight)
7742 NewState(ob,&s_boulderroll1);
7743 else if (ob->momentumz)
7744 {ob->z += (ob->momentumz>>16);
7745 ob->momentumz += (GRAVITY<<1);
7746 if (ob->z > nominalheight)
7747 {ob->z = nominalheight;
7748 ob->momentumz = 0;
7749 //ob->flags &= ~FL_NOFRICTION;
7750 }
7751 }
7752 else if (!ob->temp1)
7753 {ob->momentumz = (GRAVITY<<6);
7754 ob->temp1 = 1;
7755 }
7756
7757 }
7758
7759 if (ob->ticcount)
7760 return;
7761 if (ob->state->condition & SF_SOUND)
7762
7763 SD_PlaySoundRTP(SD_BOULDERFALLSND,ob->x,ob->y);
7764 tactor = (objtype*)(ob->target);
7765 if (tactor && (!(tactor->flags & FL_DYING)))
7766 {dx = tactor->x - ob->x;
7767 dy = tactor->y - ob->y;
7768 dz = tactor->z - ob->z;
7769 if ((abs(dx) < MINACTORDIST) && (abs(dy) < MINACTORDIST) &&
7770 (abs(dz) < 50))
7771 {if (tactor->obclass != playerobj)
7772 {tactor->momentumx = tactor->momentumy = tactor->momentumz = 0;
7773 tactor->flags |= FL_DYING;
7774 tactor->hitpoints = 0;
7775 if (gamestate.violence < vl_high)
7776 {if ((tstate = UPDATE_STATES[CRUSH][tactor->obclass - lowguardobj])!=NULL)
7777 NewState(tactor,tstate);
7778
7779 //else
7780 //Error("\n\Null low-violence crush state in boulder drop, instance of %s",debugstr[tactor->obclass]);
7781 }
7782 else
7783 {tactor->shapeoffset = 0;
7784 //tactor->flags|=FL_HBM;
7785 NewState(tactor,&s_guts1);
7786 }
7787 }
7788 else
7789 {DamageThing(tactor,200);
7790 Collision(tactor,ob,0,0);
7791 M_CheckPlayerKilled(tactor);
7792 }
7793 SD_PlaySoundRTP(SD_ACTORSQUISHSND,tactor->x,tactor->y);
7794 ob->target = NULL;
7795 }
7796
7797 }
7798 }
7799
7800
CheckCrush(objtype * ob)7801 void CheckCrush(objtype*ob)
7802 {
7803 objtype *temp;
7804 int dx,dy,dz;
7805
7806 for(temp = PLAYER[0];temp != PLAYER[numplayers-1]->next;temp=temp->next)
7807 {
7808 if (ob->flags & FL_DYING)
7809 continue;
7810
7811 dx = abs(temp->x - ob->x);
7812 if (dx > MINACTORDIST)
7813 continue;
7814
7815 dy = abs(temp->y - ob->y);
7816 if (dy > MINACTORDIST)
7817 continue;
7818
7819 dz = abs(temp->z - ob->z);
7820 if (dz > (MINACTORDIST>>10))
7821 continue;
7822
7823 if (!ob->ticcount)
7824 DamageThing(temp,EnvironmentDamage(ob));
7825 Collision(temp,ob,ob->momentumx-temp->momentumx,ob->momentumy-temp->momentumy);
7826 M_CheckPlayerKilled(temp);
7827 }
7828 }
7829
7830
T_BoulderMove(objtype * ob)7831 void T_BoulderMove(objtype*ob)
7832 {
7833
7834
7835 if (MAPSPOT(ob->tilex,ob->tiley,1) == 395)
7836 {NewState(ob,&s_bouldersink1);
7837 return;
7838 }
7839 if (NOMOM)
7840 ParseMomentum(ob,dirangle8[ob->dir]);
7841 if ((!ob->ticcount) && (ob->state->condition & SF_SOUND) &&
7842 areabyplayer[ob->areanumber])
7843 SD_PlaySoundRTP(BAS[ob->obclass].operate,ob->x,ob->y);
7844 SelectPathDir(ob);
7845
7846 }
7847
7848
7849 /*
7850 =========================================================================
7851 =
7852 = Boss Functions
7853 =
7854 =========================================================================
7855 */
7856
7857 //***************************** Esau ************************************
7858
7859
7860 enum {
7861 ESAU_USING_HOLES=1,
7862 ESAU_LEAVING_CONTROL_ROOM,
7863 ESAU_USING_TOUCH_PEDASTALS,
7864 ESAU_CHASING_PLAYER
7865 };
7866
7867
7868
7869
T_EsauWait(objtype * ob)7870 void T_EsauWait(objtype*ob)
7871 {
7872 int dist;
7873
7874 dist = FindDistance(ob->tilex-PLAYER[0]->tilex,ob->tiley-PLAYER[0]->tiley);
7875 MISCVARS->ESAU_SHOOTING = false;
7876
7877 if (ob->dirchoosetime)
7878 ob->dirchoosetime --;
7879
7880 if ((dist>81) || (dist<36))
7881 {
7882 if (CheckLine(ob,PLAYER[0],MISSILE))
7883 {
7884 NewState(ob,&s_darianshoot1);
7885 ob->momentumx = ob->momentumy = 0;
7886 }
7887 return;
7888 }
7889 else if ((!ob->dirchoosetime) && (CheckLine(ob,PLAYER[0],SHOOT)))
7890 {
7891 NewState(ob,&s_dariandefend1);
7892 ob->dirchoosetime = (GameRandomNumber("T_EsauWait",0) % 35) + 17;//35;
7893 return;
7894 }
7895 }
7896
7897
T_EsauRise(objtype * ob)7898 void T_EsauRise(objtype*ob)
7899 {
7900 int newarea,oldarea;
7901
7902 // if (gamestate.victoryflag)
7903 // return;
7904
7905 if (!ob->ticcount)
7906 {//Debug("\n tx before: %d, ty before: %d",
7907 // ob->targettilex,ob->targettiley);
7908
7909 SelectTouchDir(ob);
7910 if (ob->targettilex || ob->targettiley)
7911 {//Debug("\n ob->tilex: %d, ob->tiley: %d, targettilex: %d, targettiley: %d",
7912 // ob->tilex, ob->tiley, ob->targettilex, ob->targettiley);
7913
7914 SetTilePosition(ob,ob->targettilex,ob->targettiley);
7915 SetVisiblePosition(ob,ob->x,ob->y);
7916 oldarea = ob->areanumber;
7917 newarea = AREANUMBER(ob->tilex,ob->tiley);
7918 if (oldarea != newarea)
7919 {
7920 RemoveFromArea(ob);
7921 ob->areanumber = newarea;
7922 MakeLastInArea(ob);
7923 }
7924 }
7925 else
7926 MISCVARS->EPOP[ob->temp3].x = MISCVARS->EPOP[ob->temp3].y = 0;
7927
7928 ob->dirchoosetime= (GameRandomNumber("T_EsauRise",0) % 35) + 17;
7929 MISCVARS->ESAU_HIDING = false;
7930 MISCVARS->ESAU_SHOOTING = true;
7931 ob->flags |= FL_SHOOTABLE;
7932 }
7933 }
7934
7935
7936
T_EsauChase(objtype * ob)7937 void T_EsauChase(objtype*ob)
7938 {
7939 int dx,dy,chance,dist;
7940 statetype *temp;
7941
7942
7943
7944 if ((ob->tilex == ob->targettilex) && (ob->tiley == ob->targettiley))
7945 {
7946 if (MISCVARS->DSTATE == ESAU_USING_HOLES)
7947 {
7948 MISCVARS->ESAU_HIDING = true;
7949 MISCVARS->ESAU_SHOOTING = false;
7950 SD_PlaySoundRTP(SD_DARIANHIDESND,ob->x,ob->y);
7951 NewState(ob,&s_dariansink1);
7952 ob->flags &= ~FL_SHOOTABLE;
7953 return;
7954 }
7955 else if (MISCVARS->DSTATE == ESAU_LEAVING_CONTROL_ROOM)
7956 {
7957 if (!MISCVARS->doorcount)
7958 {
7959 SetTilePosition(ob,ob->tilex,ob->tiley);
7960 SetVisiblePosition(ob,ob->x,ob->y);
7961 }
7962 MISCVARS->doorcount ++;
7963 if (MISCVARS->doorcount == 4)
7964 MISCVARS->DSTATE = ESAU_USING_HOLES;
7965 else // hack to FORCE esau to walk through door
7966 {
7967 switch (ob->temp1)
7968 {
7969 case east:
7970 ob->targettilex ++;
7971 break;
7972 case west:
7973 ob->targettilex --;
7974 break;
7975 case north:
7976 ob->targettiley --;
7977 break;
7978 case south:
7979 ob->targettiley ++;
7980 break;
7981 }
7982 }
7983 SelectTouchDir(ob);
7984 return;
7985 }
7986 }
7987
7988 if (touchsprite && (touchsprite->itemnumber == stats[stat_dariantouch].type))
7989 {
7990 dx = touchsprite->x - ob->x;
7991 dy = touchsprite->y - ob->y;
7992
7993 if (((dx > -0x5000) && (dx < 0x5000)) &&
7994 ((dy > -0x5000) && (dy < 0x5000)))
7995 {
7996 SD_PlaySoundRTP(SD_DARIANGONNAUSESND,ob->x,ob->y);
7997 NewState(ob,&s_darianuse1);
7998 return;
7999 }
8000 }
8001
8002 if (ob->dirchoosetime)
8003 ob->dirchoosetime --;
8004
8005 if (NOMOM || (!ob->dirchoosetime))
8006 {
8007 SelectTouchDir(ob);
8008 ob->dirchoosetime = M_CHOOSETIME(ob);
8009 }
8010 else
8011 ActorMovement(ob);
8012
8013
8014 if (!ob->ticcount)
8015 {
8016 if (CheckLine(ob,PLAYER[0],MISSILE)) // got a shot at player?
8017 {
8018 if (Near(ob,PLAYER[0],1))
8019 chance = 300;
8020 else
8021 {
8022 dx = abs(PLAYER[0]->tilex-ob->tilex);
8023 dy = abs(PLAYER[0]->tiley-ob->tiley);
8024 dist = (dx>dy)?dx:dy;
8025 chance = 400/dist;
8026 }
8027 if (GameRandomNumber("T_EsauChase",0) <chance)
8028 {
8029 if ((temp=M_S(AIM)) != NULL)
8030 {
8031 NewState(ob,temp);
8032 ob->dirchoosetime = 0;
8033 ob->momentumx = ob->momentumy = 0;
8034 SetVisiblePosition(ob,ob->x,ob->y);
8035 return;
8036 }
8037 }
8038 if (MISCVARS->ESAU_SHOOTING)
8039 {
8040 SetVisiblePosition(ob,ob->x,ob->y);
8041 return;
8042 }
8043 }
8044 }
8045 }
8046
8047
T_EsauSpears(objtype * ob)8048 void T_EsauSpears(objtype*ob)
8049 {
8050
8051 if (ob->ticcount == (ob->state->tictime>>1)-1)
8052 {
8053 OLDTILEX = PLAYER[0]->tilex;
8054 OLDTILEY = PLAYER[0]->tiley;
8055 }
8056
8057 else if (!ob->ticcount)
8058 {
8059 SpawnNewObj(OLDTILEX,OLDTILEY,&s_speardown1,spearobj);
8060 new->flags |= FL_ABP;
8061 MakeActive(new);
8062 }
8063 }
8064
8065
8066
FindDoor(objtype * ob)8067 void FindDoor(objtype*ob)
8068 {
8069 int i,area1,area2,min,curr,
8070 dest1x,dest1y,dest2x,dest2y,
8071 d1,d2;
8072
8073 dirtype tdir1,tdir2;
8074 doorobj_t*dr;
8075
8076 min = 0x7fffffff;
8077 for(i=0;i<doornum;i++)
8078 {
8079 dr = doorobjlist[i];
8080 if (dr->vertical)
8081 {
8082 area1 = MAPSPOT(dr->tilex-1,dr->tiley,0)-AREATILE;
8083 dest1x = dr->tilex-1;
8084 dest1y = dr->tiley;
8085 tdir1 = east;
8086 area2 = MAPSPOT(dr->tilex+1,dr->tiley,0)-AREATILE;
8087 dest2x = dr->tilex+1;
8088 dest2y = dr->tiley;
8089 tdir2 = west;
8090 }
8091 else
8092 {
8093 area1 = MAPSPOT(dr->tilex,dr->tiley-1,0)-AREATILE;
8094 dest1x = dr->tilex;
8095 dest1y = dr->tiley-1;
8096 tdir1 = south;
8097 area2 = MAPSPOT(dr->tilex,dr->tiley+1,0)-AREATILE;
8098 dest2x = dr->tilex;
8099 dest2y = dr->tiley+1;
8100 tdir2 = north;
8101 }
8102
8103 //============================================================
8104 #define CheckMinDist(destx,desty,dir) \
8105 { \
8106 curr = FindDistance(destx-ob->tilex,desty-ob->tiley); \
8107 if (curr < min) \
8108 { \
8109 min = curr; \
8110 ob->targettilex = destx; \
8111 ob->targettiley = desty; \
8112 ob->temp1 = dir; \
8113 } \
8114 }
8115 //============================================================
8116
8117 if (area1 == ob->areanumber)
8118 {
8119 if (area1 == area2)
8120 {
8121 d1 = FindDistance(dest1x-ob->tilex,dest1y-ob->tiley);
8122 d2 = FindDistance(dest2x-ob->tilex,dest2y-ob->tiley);
8123 if (d2 < d1) //swap areas
8124 {
8125 CheckMinDist(dest2x,dest2y,tdir2);
8126 continue;
8127 }
8128 }
8129
8130 CheckMinDist(dest1x,dest1y,tdir1);
8131
8132 }
8133 else if (area2 == ob->areanumber)
8134 CheckMinDist(dest2x,dest2y,tdir2);
8135
8136 }
8137 }
8138
8139
FindTouch(objtype * ob)8140 int FindTouch(objtype *ob)
8141 {
8142 int i,curr,min,tx,ty,noneleft;
8143 statobj_t* tempstat;
8144
8145
8146 min = 0x7fffffff;
8147 noneleft = 1;
8148 for(i=0;i<MISCVARS->nexttouch;i++)
8149 {
8150 if (MISCVARS->ETOUCH[i].x || MISCVARS->ETOUCH[i].y)
8151 {
8152 noneleft = 0;
8153 tx = MISCVARS->ETOUCH[i].x;
8154 ty = MISCVARS->ETOUCH[i].y;
8155 tempstat = sprites[tx][ty];
8156 curr = FindDistance(tx-ob->tilex,ty-ob->tiley);
8157
8158 if (curr < min)
8159 {
8160 min = curr;
8161 ob->targettilex = tx;
8162 ob->targettiley = ty;
8163 touchsprite = tempstat;
8164 }
8165 }
8166 }
8167 return (!noneleft);
8168 }
8169
8170
8171
8172
8173 typedef enum
8174 {
8175 down_in_a_hole=-1,
8176 no_holes_available=0,
8177 holes_unreachable=1,
8178 hole_targetted=2
8179
8180 }hiding_status;
8181
8182
8183
HoleStatus(objtype * ob)8184 hiding_status HoleStatus(objtype*ob)
8185 {
8186 int i,tx,ty,dist,noneleft,invisible,curr,min;
8187 tpoint dummy,*dptr = &dummy;
8188 objtype *tactor;
8189 _2Dpoint *tdptr;
8190
8191 min = 0x7fffffff;
8192 noneleft = 1;
8193
8194
8195
8196 for(i=0;i<MISCVARS->nextpop;i++)
8197 {
8198 tdptr = &(MISCVARS->EPOP[i]);
8199
8200 if (tdptr->x || tdptr->y)
8201 {
8202 tactor = (objtype*)actorat[tdptr->x][tdptr->y];
8203 if (tactor && (tactor->obclass == pillarobj))
8204 {
8205 tdptr->x = 0;
8206 tdptr->y = 0;
8207 MISCVARS->popsleft --;
8208 }
8209 }
8210 }
8211
8212
8213 if (MISCVARS->popsleft > 1)
8214 {
8215 for(i=0;i<MISCVARS->nextpop;i++)
8216 {
8217 tdptr = &(MISCVARS->EPOP[i]);
8218
8219 if (tdptr->x || tdptr->y)
8220 {
8221 tx = tdptr->x;
8222 ty = tdptr->y;
8223
8224 if ((PLAYER[0]->tilex == tx) || (PLAYER[0]->tiley == ty))
8225 continue;
8226
8227 if (MISCVARS->ESAU_HIDING)
8228 {
8229 dist = FindDistance(PLAYER[0]->tilex-tx,PLAYER[0]->tiley-ty);
8230 if ((ob->tilex == tx) && (ob->tiley == ty) && (MISCVARS->popsleft != 1))
8231 continue;
8232 noneleft = 0;
8233 if ((MAPSPOT(tx,ty,0)-AREATILE) == ob->areanumber)
8234 {
8235 ob->targettilex = tx;
8236 ob->targettiley = ty;
8237 ob->temp3 = i;
8238 if ((dist < 81) && (dist > 36))
8239 return down_in_a_hole;
8240 }
8241 }
8242
8243 else if (!MISCVARS->ESAU_SHOOTING)
8244 {
8245 curr = FindDistance(tx-ob->tilex,ty-ob->tiley);
8246 if (curr < min)
8247 {
8248 min = curr;
8249 noneleft = 0;
8250 dptr->which = ACTOR;
8251 SetTilePosition(dptr,tx,ty);
8252 //dptr->x = (tx << TILESHIFT) + TILEGLOBAL/2;
8253 //dptr->y = (ty << TILESHIFT) + TILEGLOBAL/2;
8254 dptr->z = ob->z;
8255 invisible = 0;
8256 if ((!CheckLine(ob,dptr,SHOOT)) && (MISCVARS->DSTATE != ESAU_USING_HOLES))
8257 {
8258 invisible = 1;
8259 MISCVARS->DSTATE = ESAU_LEAVING_CONTROL_ROOM;
8260 }
8261 else
8262 MISCVARS->DSTATE = ESAU_USING_HOLES;
8263 ob->targettilex = tx;
8264 ob->targettiley = ty;
8265 }
8266 }
8267 }
8268 }
8269 }
8270
8271 if (MISCVARS->ESAU_HIDING)
8272 return down_in_a_hole;
8273
8274 if (noneleft)
8275 {
8276 MISCVARS->DSTATE = ESAU_CHASING_PLAYER;
8277 return no_holes_available;
8278 }
8279
8280 if (invisible) //leave present room
8281 return holes_unreachable;
8282
8283 return hole_targetted;
8284 }
8285
8286
SelectTouchDir(objtype * ob)8287 void SelectTouchDir (objtype *ob)
8288 {
8289 int dx,dy,noneleft,invisible;
8290 hiding_status hole;
8291
8292
8293 dirtype d[3];
8294 dirtype tdir, olddir, turnaround;
8295
8296
8297 olddir=ob->dir;
8298 turnaround= opposite[olddir];
8299
8300
8301 invisible = 0;
8302 noneleft = 1;
8303
8304 if (!MISCVARS->notouch)
8305 {
8306 if (!FindTouch(ob))
8307 MISCVARS->notouch = 1;
8308 else
8309 MISCVARS->DSTATE = ESAU_USING_TOUCH_PEDASTALS;
8310 }
8311
8312 else if ((!MISCVARS->noholes) && (MISCVARS->DSTATE != ESAU_LEAVING_CONTROL_ROOM))
8313 {
8314 hole = HoleStatus(ob);
8315
8316 switch(hole)
8317 {
8318 case down_in_a_hole:
8319 return;
8320
8321 case no_holes_available:
8322 MISCVARS->noholes = 1;
8323 break;
8324
8325 case holes_unreachable:
8326 FindDoor(ob);
8327 break;
8328
8329 default:
8330 break;
8331 }
8332 }
8333
8334 else if (MISCVARS->DSTATE == ESAU_CHASING_PLAYER)
8335
8336 // only gets here if all gimmicks (touch tables,
8337 // holes) are inoperative
8338 {
8339 ob->flags |= FL_SHOOTABLE;
8340 ob->targettilex = PLAYER[0]->tilex;
8341 ob->targettiley = PLAYER[0]->tiley;
8342 }
8343 /*
8344 if (DSTATE == SDOOR)
8345 {dx = ((ob->targettilex<<16)+TILEGLOBAL/2) - ob->x;
8346 dy = ob->y - ((ob->targettiley<<16)+TILEGLOBAL/2);
8347 angle = atan2_appx(dx,dy);
8348 ZEROMOM;
8349 ParseMomentum(ob,angle);
8350 ActorMovement(ob);
8351 if (ob->momentumx || ob->momentumy)
8352 {ob->angle = angle;
8353 ob->dir = angletodir[ob->angle];
8354 return;
8355 }
8356 }
8357 else */
8358 dx = ob->targettilex - ob->tilex;
8359 dy = ob->tiley - ob->targettiley;
8360
8361
8362
8363
8364 d[1]=nodir;
8365 d[2]=nodir;
8366
8367
8368 if (dx>0)
8369 d[1]= east;
8370 else if (dx<0)
8371 d[1]= west;
8372 if (dy>0)
8373 d[2]=north;
8374 else if (dy<0)
8375 d[2]=south;
8376
8377
8378 if (GameRandomNumber("SelectTouchDir",0)<128)
8379 {
8380 tdir=d[1];
8381 d[1]=d[2];
8382 d[2]=tdir;
8383 }
8384
8385 ZEROMOM;
8386
8387
8388 if (d[1]!=nodir)
8389 M_CHECKDIR(ob,d[1]);
8390
8391
8392 if (d[2]!=nodir)
8393 M_CHECKDIR(ob,d[2]);
8394
8395
8396
8397 if (GameRandomNumber("SelectTouchDir",ob->obclass)>128) //randomly determine direction of search
8398 {
8399 for (tdir=north;tdir<=west;tdir++)
8400 {
8401 if (tdir!=turnaround)
8402 M_CHECKDIR(ob,tdir);
8403 }
8404 }
8405 else
8406 {
8407 for (tdir=west;tdir>=north;tdir--)
8408 {
8409 if (tdir!=turnaround)
8410 M_CHECKDIR(ob,tdir);
8411 }
8412 }
8413
8414 if (turnaround != nodir)
8415 M_CHECKDIR(ob,turnaround);
8416
8417
8418 if (olddir!=nodir)
8419 M_CHECKDIR(ob,olddir);
8420
8421 }
8422
8423
8424
8425
8426 //************** Krist ****************************************************
8427
8428
8429
CheckRunover(objtype * ob)8430 void CheckRunover(objtype*ob)
8431 {int dx,dy,dz;
8432
8433 dx = abs(PLAYER[0]->x - ob->x);
8434 if (dx > MINACTORDIST)
8435 return;
8436
8437 dy = abs(PLAYER[0]->y - ob->y);
8438 if (dy > MINACTORDIST)
8439 return;
8440
8441 dz = abs(PLAYER[0]->z - ob->z);
8442 if (dz > 10)
8443 return;
8444
8445 locplayerstate->heightoffset = 18 + locplayerstate->playerheight;
8446 locplayerstate->oldheightoffset = locplayerstate->heightoffset;
8447 PLAYER[0]->temp2 = RENORMALIZE;
8448 DamageThing(PLAYER[0],30);
8449 Collision(PLAYER[0],ob,0,0);
8450 M_CheckPlayerKilled(PLAYER[0]);
8451
8452 }
8453
8454
T_HeinrichChase(objtype * ob)8455 void T_HeinrichChase(objtype*ob)
8456 {
8457 int dx,dy,dist,chance,perpangle;
8458 // statetype *temp;
8459 boolean doorok;
8460
8461 CheckRunover(ob);
8462
8463 // ob->flags &= ~FL_DODGE;
8464 if (CheckLine(ob,PLAYER[0],SIGHT))
8465 {ob->targettilex = PLAYER[0]->x;
8466 ob->targettiley = PLAYER[0]->y;
8467 }
8468
8469 if (!ob->ticcount)
8470 {
8471
8472 // if (gamestate.victoryflag)
8473 // return;
8474
8475
8476 if (CheckLine(ob,PLAYER[0],SHOOT)) // got a shot at PLAYER[0]?
8477 {dx = abs(ob->tilex - PLAYER[0]->tilex);
8478 dy = abs(ob->tiley - PLAYER[0]->tiley);
8479 dist = dx>dy ? dx : dy;
8480 if (!dist || dist==1)
8481 chance = 300;
8482 else
8483 chance = 2400/dist;
8484
8485 if (GameRandomNumber("T_HeinrichChase",0) <chance)
8486 {tpoint dummy,*dptr=&dummy;
8487
8488 if (Near(ob,PLAYER[0],2))
8489 goto cdoor;
8490
8491
8492 perpangle = AngleBetween(ob,PLAYER[0]) + ANGLES/4;
8493 Fix(perpangle);
8494 dptr->which = ACTOR;
8495 dptr->x = ob->x + FixedMul(0x10000l,costable[perpangle]);
8496 dptr->y = ob->y - FixedMul(0x10000l,sintable[perpangle]);
8497
8498 dptr->z = ob->z;
8499 if (!CheckLine(dptr,PLAYER[0],SHOOT))
8500 goto cdoor;
8501
8502 ob->target = PLAYER[0];
8503 NewState(ob,M_S(AIM));
8504 ob->dirchoosetime = 0;
8505 return;
8506
8507
8508 }
8509 }
8510
8511 }
8512
8513 cdoor:
8514 doorok = NextToDoor(ob);
8515
8516
8517 if (ob->dirchoosetime)
8518 ob->dirchoosetime--;
8519
8520 if ((ob->flags & FL_STUCK) || (!ob->dirchoosetime) || doorok)
8521 {/*if ((ob->flags & FL_DODGE) && (!doorok))
8522 SelectKristDodgeDir (ob);
8523 else */
8524 SD_PlaySoundRTP(SD_KRISTMOTORSND,ob->x,ob->y);
8525 SelectKristChaseDir(ob);
8526
8527 ob->dirchoosetime = 4*M_CHOOSETIME(ob);
8528
8529 }
8530
8531 else
8532 {if (NOMOM)
8533 ParseMomentum(ob,dirangle8[ob->dir]);
8534 ActorMovement(ob);
8535
8536 }
8537
8538 }
8539
T_Heinrich_Defend(objtype * ob)8540 void T_Heinrich_Defend (objtype*ob)
8541 {
8542 CheckRunover(ob);
8543
8544 if (ob->dirchoosetime)
8545 ob->dirchoosetime--;
8546
8547
8548 if (MISCVARS->HRAMMING)
8549 ParseMomentum(ob,dirangle8[ob->dir]);
8550
8551
8552 if ((ob->flags & FL_STUCK) || (!ob->dirchoosetime))
8553 {if (MISCVARS->HRAMMING)
8554 {if (!Near(ob,PLAYER[0],3))
8555 {NewState(ob,M_S(CHASE));
8556 ob->dirchoosetime = 0;
8557 return;
8558 }
8559 SelectKristChaseDir(ob);
8560 }
8561 else if (MISCVARS->HMINING)
8562 {SelectMineDir(ob);
8563 if (!MISCVARS->HMINING)
8564 goto hchase;
8565 ob->dirchoosetime = 5;//10;
8566 return;
8567 }
8568 else
8569 hchase:
8570 NewState(ob,M_S(CHASE));
8571 ob->dirchoosetime = 0;
8572 }
8573 else
8574 {if (NOMOM)
8575 ParseMomentum(ob,dirangle8[ob->dir]);
8576 ActorMovement(ob);
8577 }
8578 }
8579
8580
T_Heinrich_Out_of_Control(objtype * ob)8581 void T_Heinrich_Out_of_Control(objtype*ob)
8582 {
8583 if (ob->dirchoosetime)
8584 ob->dirchoosetime --;
8585 else
8586 {
8587 if (!ob->temp1)
8588 {
8589 SetGibSpeed(0x4000);
8590 SpawnParticles(ob,RANDOM,120);
8591 ResetGibSpeed();
8592
8593 NewState(ob,&s_dexplosion1);
8594 SD_PlaySoundRTP(SD_EXPLODESND,ob->x,ob->y);
8595 }
8596 else
8597 {
8598 ob->dir = dirorder[ob->dir][PREV];
8599 ob->angle = dirangle8[ob->dir];
8600 if (ob->dir == (unsigned)ob->temp2)
8601 {
8602 if (ob->temp1 > 1)
8603 ob->temp1--;
8604 else
8605 {
8606 if (ob->temp3 == 7)
8607 {
8608 SpawnNewObj(ob->tilex,ob->tiley,&s_megaexplosions,inertobj);
8609 new->temp1 = 25;
8610 new->flags |= FL_ABP;
8611 MakeActive(new);
8612 SpawnNewObj(ob->tilex,ob->tiley,&s_superparticles,inertobj);
8613 new->flags |= FL_ABP;
8614 PARTICLE_GENERATOR = new;
8615 MakeActive(new);
8616 }
8617 if (ob->temp3)
8618 ob->temp3 --;
8619 else
8620 ob->temp1 --;
8621 }
8622 }
8623
8624 if (ob->temp1)
8625 ob->dirchoosetime = ob->temp1;
8626 else
8627 {
8628 ob->dirchoosetime = 70; // end of spin wait for megaexplosion
8629 if (PARTICLE_GENERATOR)
8630 {
8631 NewState(PARTICLE_GENERATOR,&s_megaremove);
8632 PARTICLE_GENERATOR = NULL;
8633 }
8634 }
8635 }
8636 }
8637 }
8638
8639
8640
8641
SelectKristChaseDir(objtype * ob)8642 void SelectKristChaseDir(objtype*ob)
8643 {int dx,dy,tx,ty,angle;
8644 dirtype dtry1,dtry2,tdir,olddir,next,prev,straight;
8645 //tpoint dummy,*dptr=&dummy;
8646
8647 olddir=ob->dir;
8648
8649
8650 //dptr->which = ACTOR;
8651 //dptr->z = ob->z;
8652 if (ob->targettilex || ob->targettiley)
8653 {tx = ob->targettilex;
8654 ty = ob->targettiley;
8655 dx= tx - ob->x;
8656 dy= ob->y - ty;
8657 // SetFinePosition(dptr,tx,ty);
8658 if ( ((dx < 0x20000) && (dx > -0x20000)) &&
8659 ((dy < 0x20000) && (dy > -0x20000)))
8660 {
8661 dx= PLAYER[0]->x-ob->x;
8662 dy= ob->y-PLAYER[0]->y;
8663 // SetFinePosition(dptr,PLAYER[0]->x,PLAYER[0]->y);
8664 }
8665 }
8666 else
8667 {
8668 dx= PLAYER[0]->x-ob->x;
8669 dy= ob->y-PLAYER[0]->y;
8670 //SetFinePosition(dptr,PLAYER[0]->x,PLAYER[0]->y);
8671
8672 }
8673
8674 angle = atan2_appx(dx,dy);
8675 straight = angletodir[angle];
8676 /*
8677 if (ob->areanumber == PLAYER[0]->areanumber)
8678 {//tpoint newpos1,newpos2;
8679 //dirtype leftdir;
8680 //int leftangle1,leftangle2;
8681
8682 if (CheckLine(ob,&dummy,DIRCHECK))
8683 {//Debug("\ntrying straight dir %d",straight);
8684 M_CHECKTURN(ob,straight);
8685 //Debug("\nstraight dir %d failed",straight);
8686 }
8687 //leftdir = dirorder[straight][PREV];
8688 //leftangle1 = dirangle8[leftdir];
8689 //newpos1.which = ACTOR;
8690 //rightangle = dirangle[dirorder[straight][NEXT]];
8691 //newpos1.x = ob->x + FixedMul(0x10000,costable[leftangle1]);
8692 //newpos1.y = ob->y - FixedMul(0x10000,sintable[leftangle1]);
8693 //newpos1.z = ob->z;
8694
8695 //leftangle2 = dirangle8[dirorder[leftdir][PREV]];
8696 //newpos2.which = ACTOR;
8697 //rightangle = dirangle[dirorder[straight][NEXT]];
8698 //newpos2.x = ob->x + FixedMul(0x10000,costable[leftangle2]);
8699 //newpos2.y = ob->y - FixedMul(0x10000,sintable[leftangle2]);
8700 //newpos2.z = ob->z;
8701 //if (CheckLine(&newpos1,&dummy,SHOOT))// || CheckLine(&newpos2,&dummy,SHOOT))
8702 {for(tdir = dirorder[straight][PREV];tdir != dirorder[straight][NEXT];tdir = dirorder[tdir][PREV])
8703 {//Debug("\ntried left-hand rule dir %d",tdir);
8704 M_CHECKTURN(ob,tdir);
8705 }
8706 }
8707 //else
8708 //{for(tdir = dirorder[straight][NEXT];tdir != dirorder[straight][PREV];tdir = dirorder[tdir][NEXT])
8709 // {//Debug("\ntrying right-hand rule dir %d",tdir);
8710 // M_CHECKTURN(ob,tdir);
8711 //Debug("\nright-hand rule dir %d failed\n",tdir);
8712 // }
8713 // }
8714 }
8715 else*/
8716 {dtry1=nodir;
8717 dtry2=nodir;
8718
8719 if (dx> ACTORSIZE)
8720 dtry1= east;
8721 else if (dx< -ACTORSIZE)
8722 dtry1= west;
8723 if (dy> ACTORSIZE)
8724 dtry2=north;
8725 else if (dy < -ACTORSIZE)
8726 dtry2= south;
8727
8728
8729 if (abs(dy)>abs(dx))
8730 {tdir=dtry1;
8731 dtry1=dtry2;
8732 dtry2=tdir;
8733 }
8734
8735 // ZEROMOM;
8736 ob->momentumx = FixedMul (ob->momentumx, DEADFRICTION>>gamestate.difficulty);
8737 ob->momentumy = FixedMul (ob->momentumy, DEADFRICTION>>gamestate.difficulty);
8738
8739
8740 M_CHECKTURN(ob,straight);
8741
8742 if (dtry1 != nodir)
8743 M_CHECKTURN(ob,dtry1);
8744
8745 if (dtry2 != nodir)
8746 M_CHECKTURN(ob,dtry2);
8747
8748 if (dtry1 != nodir)
8749 {M_CHECKTURN(ob,dirorder[dtry1][NEXT]);
8750 M_CHECKTURN(ob,dirorder[dtry1][PREV]);
8751 }
8752
8753 for(tdir = dirorder[olddir][NEXT];tdir != olddir;tdir = dirorder[tdir][NEXT])
8754 M_CHECKTURN(ob,tdir);
8755
8756 ob->dir = olddir;
8757 }
8758
8759
8760
8761 }
8762
8763
8764
T_KristLeft(objtype * ob)8765 void T_KristLeft(objtype*ob)
8766 {CheckRunover(ob);
8767 ActorMovement(ob);
8768 if (!ob->ticcount)
8769 {SD_PlaySoundRTP(SD_KRISTTURNSND,ob->x,ob->y);
8770 if (ob->dir != (unsigned)ob->temp1)
8771 ob->dir = dirorder[ob->dir][NEXT];
8772 else
8773 {ob->temp1 = 0;
8774 NewState(ob,&s_heinrichchase);
8775 }
8776 }
8777
8778 }
8779
T_KristRight(objtype * ob)8780 void T_KristRight(objtype*ob)
8781 {CheckRunover(ob);
8782 ActorMovement(ob);
8783 if (!ob->ticcount)
8784 {SD_PlaySoundRTP(SD_KRISTTURNSND,ob->x,ob->y);
8785 if (ob->dir != (unsigned)ob->temp1)
8786 ob->dir = dirorder[ob->dir][PREV];
8787 else
8788 {ob->temp1 = 0;
8789 NewState(ob,&s_heinrichchase);
8790 }
8791 }
8792 }
8793
8794
T_KristCheckFire(objtype * ob)8795 void T_KristCheckFire(objtype*ob)
8796 {int perpangle,angle;
8797 tpoint dummy;
8798
8799 if (!ob->ticcount)
8800 {angle = AngleBetween(ob,PLAYER[0]);
8801
8802 if (ob->state == &s_heinrichshoot1)
8803 perpangle = angle + ANGLES/4;
8804 else
8805 perpangle = angle - ANGLES/4;
8806
8807 Fix(perpangle);
8808
8809
8810 dummy.which = ACTOR;
8811 dummy.x = ob->x + FixedMul(0x4000,costable[angle]) + FixedMul(0x4000l,costable[perpangle]) +
8812 FixedMul(PROJSIZE,costable[perpangle]); // offset ahead plus
8813 // offset for left/right missile plus offset for missile
8814 // radius (will missile reach player without hitting wall,etc.)
8815
8816 dummy.y = ob->y - FixedMul(0x4000,sintable[angle]) - FixedMul(0x4000l,sintable[perpangle]) -
8817 FixedMul(PROJSIZE,sintable[perpangle]);
8818
8819 dummy.x -= (FixedMul(PROJSIZE,costable[perpangle])<<1);
8820
8821 dummy.y += (FixedMul(PROJSIZE,sintable[perpangle])<<1);
8822 dummy.z = ob->z;
8823
8824 if (!CheckLine(&dummy,PLAYER[0],SHOOT))
8825 {NewState(ob,&s_heinrichchase);
8826 return;
8827 }
8828
8829
8830 }
8831 }
8832
8833
8834
SelectMineDir(objtype * ob)8835 void SelectMineDir(objtype*ob)
8836 {int angle,missangle;
8837 dirtype olddir,tdir,next,prev,destdir;
8838 static int nummines=0;
8839
8840 if (!CheckLine(ob,PLAYER[0],SIGHT))
8841 {NewState(ob,M_S(CHASE));
8842 MISCVARS->HMINING = 0;
8843 return;
8844 }
8845
8846 olddir = ob->dir;
8847
8848 angle = AngleBetween(ob,PLAYER[0]);
8849 tdir = angletodir[angle];
8850 destdir = opposite[tdir];
8851
8852 if (destdir != olddir)
8853 {next = dirorder[olddir][NEXT];
8854 prev = dirorder[olddir][PREV];
8855 if (dirdiff[destdir][next] < dirdiff[destdir][prev])
8856 ob->dir = next;
8857 else
8858 ob->dir = prev;
8859 return;
8860 }
8861
8862 nummines ++;
8863 missangle = angle;
8864 if (nummines == 2)
8865 missangle -= (ANGLES/36);
8866 else if (nummines == 3)
8867 missangle += (ANGLES/36);
8868
8869 Fix(missangle);
8870 // if (missangle > (ANGLES - 1))
8871 // missangle -= ANGLES;
8872 // else if (missangle < 0)
8873 // missangle += ANGLES;
8874
8875
8876 SpawnMissile(ob,h_mineobj,0x2000,missangle,&s_mine1,0xa000);
8877 new->dirchoosetime = 140;
8878 SD_PlaySoundRTP(SD_KRISTDROPSND,ob->x,ob->y);
8879
8880 if (nummines == 3)
8881 {MISCVARS->HMINING = 0;
8882 nummines = 0;
8883 }
8884 }
8885
8886
8887
A_HeinrichShoot(objtype * ob)8888 void A_HeinrichShoot(objtype* ob)
8889 {int angle,perpangle;
8890
8891 if (!ob->ticcount)
8892 {angle = AngleBetween(ob,PLAYER[0]);
8893 if (ob->state == &s_heinrichshoot4)
8894 perpangle = angle + ANGLES/4;
8895 else
8896 perpangle = angle - ANGLES/4;
8897
8898 Fix(perpangle);
8899
8900 SpawnMissile(ob,missileobj,0x4000,angle,&s_missile1,0x8000);
8901 SD_PlaySoundRTP(BAS[ob->obclass].fire,ob->x,ob->y);
8902
8903 SetFinePosition(new,new->x + FixedMul(0x4000l,costable[perpangle]),
8904 new->y - FixedMul(0x4000l,sintable[perpangle]));
8905 SetVisiblePosition(new,new->x,new->y);
8906 }
8907
8908
8909 }
8910
8911
8912 //***************************///////**************************************
8913 //***************************/ NME /**************************************
8914 //***************************///////**************************************
8915
8916
8917
8918
8919
UpdateNMELinkedActors(objtype * ob)8920 void UpdateNMELinkedActors(objtype*ob)
8921 {
8922 objtype *head,*wheels;
8923 int oldarea;
8924
8925
8926 head = (objtype*)(ob->whatever);
8927 wheels = (objtype*)(ob->target);
8928
8929 oldarea = head->areanumber;
8930
8931 SetFinePosition(head,ob->x,ob->y);
8932 SetFinePosition(wheels,ob->x,ob->y);
8933 SetVisiblePosition(head,ob->x,ob->y);
8934 SetVisiblePosition(wheels,ob->x,ob->y);
8935
8936 if (oldarea != ob->areanumber)
8937 {
8938 RemoveFromArea(head);
8939 head->areanumber = ob->areanumber;
8940 MakeLastInArea(head);
8941 RemoveFromArea(wheels);
8942 wheels->areanumber = ob->areanumber;
8943 MakeLastInArea(wheels);
8944 }
8945
8946 }
8947
8948
T_OrobotChase(objtype * ob)8949 void T_OrobotChase(objtype*ob)
8950 {
8951 int dx,dy;
8952
8953
8954 if (CheckLine(ob,PLAYER[0],SIGHT))
8955 {
8956
8957 ob->targettilex = PLAYER[0]->tilex;
8958 ob->targettiley = PLAYER[0]->tiley;
8959 }
8960
8961
8962
8963 if (!ob->ticcount)
8964 {
8965 if (NMEspincheck(ob))
8966 return;
8967
8968 dx = PLAYER[0]->x - ob->x;
8969 dy = ob->y - PLAYER[0]->y;
8970 /*
8971 if ((dx > -0x18000) && (dx < 0x18000) && (dy > -0x18000) && (dy < 0x18000))
8972 {NewState(ob,&s_NMEavoid);
8973 return;
8974 }
8975 */
8976
8977 if (CheckLine(ob,PLAYER[0],SIGHT))
8978 {
8979 int inrange;
8980
8981 switch(gamestate.difficulty)
8982 {
8983 case gd_baby: inrange = Near(ob,PLAYER[0],6);break;
8984 case gd_easy: inrange = Near(ob,PLAYER[0],9);break;
8985 case gd_medium: inrange = Near(ob,PLAYER[0],12);break;
8986 case gd_hard: inrange = 1;break;
8987 }
8988
8989 if ((!Near(ob,PLAYER[0],3)) && inrange)
8990 {
8991 SD_PlaySoundRTP(SD_NMEREADYSND,ob->x,ob->y);
8992 if ((ob->hitpoints < 2000) && (GameRandomNumber("NME special attack",0) < 120))
8993 {
8994 int next,prev;
8995
8996 next = dirorder16[ob->dir][NEXT];
8997 prev = dirorder16[ob->dir][PREV];
8998 ob->targettilex = (angletodir[atan2_appx(dx,dy)]<<1);
8999
9000 if (dirdiff16[prev][ob->targettilex] < dirdiff16[next][ob->targettiley])
9001 ob->temp3 = PREV;
9002 else
9003 ob->temp3 = NEXT;
9004 NewState(ob,&s_NMEspinfire);
9005 }
9006 else
9007 {
9008 NewState(ob,&s_NMEwindup);
9009 ob->temp3 = 0;
9010 }
9011 //NewState((objtype*)(ob->target),&s_NMEwheelspin);
9012
9013 NewState((objtype*)(ob->target),&s_NMEwheels120);
9014 return;
9015 }
9016 }
9017 }
9018
9019 if (ob->dirchoosetime)
9020 ob->dirchoosetime --;
9021
9022 if ((ob->flags & FL_STUCK) || (!ob->dirchoosetime))
9023 {
9024 SelectOrobotChaseDir(ob);
9025 ob->dirchoosetime = 4;//8;
9026 }
9027
9028 else
9029 {
9030 ActorMovement(ob);
9031 UpdateNMELinkedActors(ob);
9032 }
9033 }
9034
9035
9036
T_Saucer(objtype * ob)9037 void T_Saucer(objtype*ob)
9038 {int angle,dangle;
9039
9040 if (!ob->ticcount) // if on track at end of each state, accelerate
9041 // towards PLAYER[0]
9042 {if (ob->state->condition & SF_SOUND)
9043 SD_PlaySoundRTP(SD_NMEREADYSND,ob->x,ob->y);
9044 angle = AngleBetween(ob,PLAYER[0]);
9045 dangle = ob->angle - angle;
9046 if ((dangle > -(ANGLES/72)) && (dangle < (ANGLES/72)))
9047 {if (ob->speed < 0x10000)
9048 {ob->speed += 0x200;
9049 ZEROMOM;
9050 ParseMomentum(ob,ob->angle);
9051 }
9052 }
9053 else // off track; zero mom. and select new dir.
9054 {ob->speed = 0x1000;
9055 ZEROMOM;
9056 ob->angle = angle;
9057 ParseMomentum(ob,ob->angle);
9058 }
9059 }
9060 MissileMovement(ob);
9061
9062
9063 }
9064
9065
T_NME_WindUp(objtype * ob)9066 void T_NME_WindUp(objtype*ob)
9067 {objtype *head,*wheels;
9068
9069 head = (objtype*)(ob->whatever);
9070 wheels = (objtype*)(ob->target);
9071
9072 if (ob->dirchoosetime)
9073 {ob->dirchoosetime--;
9074 return;
9075 }
9076
9077 ob->dirchoosetime = 0;//3;
9078
9079 if (MISCVARS->NMErotate < 3)
9080 {head->dir = dirorder16[head->dir][NEXT];
9081 MISCVARS->NMErotate ++;
9082 }
9083 else if (MISCVARS->NMErotate < 6)
9084 {head->dir = dirorder16[head->dir][PREV];
9085 MISCVARS->NMErotate ++;
9086 }
9087 else if (MISCVARS->NMErotate < 9)
9088 {ob->dir = dirorder16[ob->dir][NEXT];
9089 wheels->dir = ob->dir;
9090 MISCVARS->NMErotate++;
9091 }
9092 else if (MISCVARS->NMErotate < 12)
9093 {ob->dir = dirorder16[ob->dir][PREV];
9094 wheels->dir = ob->dir;
9095 MISCVARS->NMErotate ++;
9096 }
9097 else
9098 {MISCVARS->NMErotate = 0;
9099
9100 NewState(ob,&s_NMEattack);
9101 ob->dirchoosetime = 0;
9102 //ob->dirchoosetime = 50 - (ob->shapeoffset >> 2) - (gamestate.difficulty << 2);//70;
9103 if (!ob->temp2)
9104 NewState((objtype*)(ob->whatever),&s_NMEhead1rl);
9105 else
9106 NewState((objtype*)(ob->whatever),&s_NMEhead2rl);
9107 NewState(wheels,&s_NMEwheels2);
9108 }
9109
9110 }
9111
9112 #define SPRAYDIST 0x12000
9113
SelectOrobotChaseDir(objtype * ob)9114 void SelectOrobotChaseDir(objtype*ob) // this code is for head
9115 {
9116 int dx,dy,angle,tx,ty;
9117 int tdir,olddir,nextdir,prevdir;
9118 objtype* head,*wheels;
9119
9120
9121
9122 head = (objtype*)(ob->whatever);
9123 wheels = (objtype*)(ob->target);
9124 olddir=head->dir;
9125
9126 findplayer:
9127 if (ob->temp1 == -1)
9128 {
9129 if (ob->targettilex || ob->targettiley)
9130 {
9131 tx = (int)((ob->targettilex << TILESHIFT) + HALFGLOBAL1);
9132 ty = (int)((ob->targettiley << TILESHIFT) + HALFGLOBAL1);
9133 dx= tx - ob->x;
9134 dy= ob->y - ty;
9135 if (((dx <SPRAYDIST ) && (dx > -SPRAYDIST)) &&
9136 ((dy <SPRAYDIST ) && (dy > -SPRAYDIST)))
9137 {
9138 dx= PLAYER[0]->x-ob->x;
9139 dy= ob->y - PLAYER[0]->y;
9140 }
9141 }
9142 else
9143 {
9144 dx= PLAYER[0]->x - ob->x;
9145 dy= ob->y - PLAYER[0]->y;
9146 }
9147
9148 angle = atan2_appx(dx,dy);
9149
9150 tdir = (((angletodir[angle])<<1) & 0xf);
9151 }
9152 else
9153 {
9154 tdir = (ob->temp1 & 0xf);
9155
9156 if ((head->dir == (unsigned)tdir) && (ob->dir == (unsigned)tdir)) // increment
9157 // tried dir if robot will attempt to move at tdir =>
9158 // head and body are at move try dir
9159 {//Debug("\ntrying next queue dir %d",tdir);
9160 MISCVARS->NMEdirstried ++;
9161 if (MISCVARS->NMEdirstried == MISCVARS->NMEqueuesize) //gone through all queue entries
9162 {//Debug("\nqueue exhausted");
9163 ob->temp1 = -1;
9164 MISCVARS->NMEdirstried = 0;
9165 goto findplayer;
9166 }
9167 }
9168 }
9169
9170
9171 if (tdir != olddir) //rotate head to new chase direction
9172 {
9173 nextdir = dirorder16[olddir][NEXT];
9174 prevdir = dirorder16[olddir][PREV];
9175 if (dirdiff16[tdir][nextdir] < dirdiff16[tdir][prevdir])
9176 head->dir = nextdir;
9177 else
9178 head->dir = prevdir;
9179 return;
9180 }
9181 //Debug("\nhead aligned to dir %d",tdir);
9182
9183 //oddir = ob->dir;
9184 if (ob->dir != head->dir) // align body and wheels with head
9185 {
9186 ZEROMOM;
9187 NewState(wheels,&s_NMEwheels120); //rotate wheels for spinning
9188 nextdir = dirorder16[ob->dir][NEXT];
9189 prevdir = dirorder16[ob->dir][PREV];
9190 if (dirdiff16[head->dir][nextdir] < dirdiff16[head->dir][prevdir])
9191 ob->dir = nextdir;
9192 else
9193 ob->dir = prevdir;
9194 wheels->dir = ob->dir;
9195 return;
9196 }
9197
9198 // Debug("\nbody aligned to head at dir %d",ob->dir);
9199
9200 ZEROMOM;
9201 ParseMomentum(ob,dirangle16[head->dir]);
9202 // Debug("\ntrying to move at dir %d",head->dir);
9203 ActorMovement(ob);
9204 UpdateNMELinkedActors(ob);
9205
9206 if (ob->momentumx || ob->momentumy)
9207 {
9208 NewState(wheels,&s_NMEwheels2); // align wheels for movement
9209 //Debug("\nmove at dir %d succesful, resetting queue",head->dir);
9210 ob->temp1 = -1; //clear direction queue
9211 return;
9212 }
9213 else if (ob->temp1 == -1) // if queue is empty
9214 //make a queue of directions (byte packed)
9215 {
9216 //Debug("\nmove at dir %d failed and queue empty",head->dir);
9217 ob->temp1 = 0;
9218 MISCVARS->NMEdirstried = 0;
9219 MISCVARS->NMEqueuesize = 0;
9220
9221 nextdir = ((tdir + 6) & 0xf);
9222 prevdir = ((tdir - 6) & 0xf);
9223
9224 for(; MISCVARS->NMEqueuesize < 6;MISCVARS->NMEqueuesize += 2)
9225 {
9226 ob->temp1 <<= 4;
9227 ob->temp1 += nextdir;
9228 ob->temp1 <<= 4;
9229 ob->temp1 += prevdir;
9230 nextdir = ((nextdir-2) & 0xf);
9231 prevdir = ((prevdir+2) & 0xf);
9232
9233 }
9234 #if 0
9235 SoftError("\n straight dir: %d\n queue dirs ",tdir);
9236 for(count = 0;count < MISCVARS->NMEqueuesize;count++)
9237 {
9238 SoftError("\n dir %d: %d",MISCVARS->NMEqueuesize-count,
9239 ((ob->temp1 >> (4*count)) &0xf)
9240 );
9241
9242 }
9243 #endif
9244 }
9245 else // else goto next queue dir;
9246 {
9247 ob->temp1 >>= 4;
9248 }
9249
9250 }
9251
9252
9253
T_NME_Explode(objtype * ob)9254 void T_NME_Explode(objtype*ob)
9255 {
9256
9257 if (ob->ticcount == 35)
9258 {objtype*head;
9259 int op;
9260
9261 head = (objtype*)(ob->whatever);
9262
9263 op = FixedMul(GRAVITY,(head->z-25)<<16) << 1;
9264 head->momentumz = -FixedSqrtHP(op);
9265 head->momentumx = (GameRandomNumber("NME head momx",0) << 2);
9266 head->momentumy = (GameRandomNumber("NME head momy",0) << 2);
9267 head->hitpoints = 0;
9268 head->flags |= FL_DYING;
9269 NewState(head,&s_shootinghead);
9270
9271 //RemoveObj((objtype*)(ob->whatever)); // remove head
9272 }
9273 else if (!ob->ticcount)
9274 {ob->shapeoffset = 0;
9275 NewState(ob,&s_explosion1);
9276 SetGibSpeed(0x4000);
9277 SpawnParticles(ob,gt_sparks,200);
9278 ResetGibSpeed();
9279 RemoveObj((objtype*)(ob->target));
9280 }
9281
9282 }
9283
T_NME_HeadShoot(objtype * ob)9284 void T_NME_HeadShoot(objtype*ob)
9285 {//int randtheta,i,offx,offy;
9286
9287 ob->z += (ob->momentumz>>16);
9288
9289 /*if (ob->momentumz < 0)
9290 {for(i=0;i<3;i++)
9291 {randtheta = (GameRandomNumber("NME spark drop",0) << 3);
9292 SpawnNewObj(ob->tilex,ob->tiley,&s_particle1,inertobj);
9293 new->temp2 = 1;
9294 offx = FixedMul(0x400,costable[randtheta]);
9295 offy = -FixedMul(0x400,sintable[randtheta]);
9296 new->x = new->drawx = ob->x + offx;
9297 new->y = new->drawy = ob->y + offy;
9298 new->z = ob->z-15;
9299 new->flags |= (FL_NOFRICTION|FL_CRAZY|FL_ABP);
9300 new->dir = west;
9301 MakeActive(new);
9302 }
9303 }*/
9304
9305 ob->momentumz += GRAVITY;
9306 if (ob->z >= (nominalheight+45))
9307 {ob->z = nominalheight+45;
9308 if (ob->temp2)
9309 {ob->momentumz = -30000*ob->temp2;
9310 ob->temp2--;
9311 }
9312 else
9313 {ob->momentumx = ob->momentumy = ob->momentumz = 0;
9314 ob->shapeoffset = 0;
9315 NewState(ob,&s_NMEheadexplosion);
9316
9317 return;
9318 }
9319 }
9320 ActorMovement(ob);
9321
9322 }
9323
9324
NMEspincheck(objtype * ob)9325 boolean NMEspincheck(objtype*ob)
9326 {
9327 int dx,dy,dz;
9328
9329 dx = abs(PLAYER[0]->x - ob->x);
9330 dy = abs(PLAYER[0]->y - ob->y);
9331 dz = abs(PLAYER[0]->z - ob->z);
9332 if ((dx < 0x10000) && (dy < 0x10000) && (dz < 32))
9333 {
9334 NewState(ob,&s_NMEspinattack);
9335 NewState((objtype*)(ob->target),&s_NMEwheelspin);
9336 if (!ob->temp2)
9337 NewState((objtype*)(ob->whatever),&s_NMEhead1);
9338 else
9339 NewState((objtype*)(ob->whatever),&s_NMEhead2);
9340 ob->dirchoosetime = 1;
9341 return true;
9342 }
9343 return false;
9344 }
9345
9346
9347
9348
9349
T_NME_SpinAttack(objtype * ob)9350 void T_NME_SpinAttack(objtype* ob)
9351 {int mx,my,mz;
9352 objtype*head,*wheels;
9353
9354
9355
9356 if (ob->ticcount == 30) // knock player back
9357 {GetMomenta(PLAYER[0],ob,&mx,&my,&mz,0x4000);
9358 DamageThing(PLAYER[0],20);
9359 Collision(PLAYER[0],ob,mx,my);
9360 M_CheckPlayerKilled(PLAYER[0]);
9361 }
9362 if (ob->dirchoosetime)
9363 ob->dirchoosetime --;
9364 else
9365 {head = (objtype*)(ob->whatever);
9366 wheels = (objtype*)(ob->target);
9367 wheels->dir = head->dir = ob->dir = dirorder16[dirorder16[ob->dir][NEXT]][NEXT];
9368
9369 ob->dirchoosetime = 1;
9370 }
9371
9372
9373 }
9374
9375
T_NME_SpinFire(objtype * ob)9376 void T_NME_SpinFire(objtype*ob)
9377 {
9378 int randtheta,oldyzangle,dx,dy,xydist,dz;
9379 objtype *head,*wheels;
9380
9381
9382 head = (objtype*)(ob->whatever);
9383 wheels = (objtype*)(ob->target);
9384
9385 if (ob->dir != (unsigned)ob->targettilex)
9386 {ob->dir = head->dir = wheels->dir = dirorder16[ob->dir][ob->temp3];
9387 return;
9388 }
9389
9390 if (ob->dirchoosetime)
9391 {ob->dirchoosetime --;
9392 return;
9393 }
9394
9395 if (ob->temp3 < 20)
9396 {//randphi = (GameRandomNumber("NME generate phi",0) << 3) & ((ANGLES/2) -1);
9397 if (GameRandomNumber("NME generate theta",0) < 128)
9398 randtheta = (GameRandomNumber("NME generate theta",0)>>4);
9399 else
9400 randtheta = -(GameRandomNumber("NME generate theta",0)>>4);
9401 dx = PLAYER[0]->x-ob->x;
9402 dy = ob->y-PLAYER[0]->y;
9403 if (GameRandomNumber("bcraft shoot up/down",0) < 128)
9404 dz = 5;
9405 else
9406 dz = -5;
9407 xydist = FindDistance(dx,dy);
9408 randtheta += atan2_appx(dx,dy);
9409 Fix(randtheta);
9410 oldyzangle = ob->yzangle;
9411 ob->yzangle = atan2_appx(xydist,dz<<10);
9412 //ob->yzangle = randphi;
9413 SD_PlaySoundRTP(BAS[ob->obclass].fire+1,ob->x,ob->y);
9414 //wheels->dir = head->dir = ob->dir = dirorder16[dirorder16[ob->dir][NEXT]][NEXT];
9415 SpawnMissile(ob,fireballobj,0x6000,randtheta,&s_NMEminiball1,0x10000);
9416 ob->dirchoosetime = 1;
9417 ob->yzangle = oldyzangle;
9418 ob->temp3 ++;
9419 }
9420 else
9421 {ob->temp3 = 0;
9422 NewState(ob,&s_NMEchase);
9423 NewState((objtype*)(ob->target),&s_NMEwheels2);
9424 if (!ob->temp2)
9425 NewState((objtype*)(ob->whatever),&s_NMEhead1);
9426 else
9427 NewState((objtype*)(ob->whatever),&s_NMEhead2);
9428
9429
9430 }
9431
9432
9433 }
9434
T_NME_Attack(objtype * ob)9435 void T_NME_Attack(objtype*ob)
9436 {int angle,perpangle,i;
9437
9438
9439
9440 if (NMEspincheck(ob))
9441 {//ob->temp3 = 0;
9442 return;
9443 }
9444 if (ob->dirchoosetime)
9445 {ob->dirchoosetime --;
9446 return;
9447 }
9448
9449
9450 if (!CheckLine(ob,PLAYER[0],SIGHT))
9451 {//ob->temp3 = 0;
9452 //#if ((DEVELOPMENT == 1))
9453 //Debug("\nCheckLine failed in NME Attack");
9454 //#endif
9455 NewState(ob,&s_NMEchase);
9456 NewState((objtype*)(ob->target),&s_NMEwheels2);
9457 if (!ob->temp2)
9458 NewState((objtype*)(ob->whatever),&s_NMEhead1);
9459 else
9460 NewState((objtype*)(ob->whatever),&s_NMEhead2);
9461 return;
9462 }
9463 //sound = BAS[ob->obclass].fire;
9464 angle = AngleBetween(ob,PLAYER[0]);
9465
9466
9467
9468 if ((ob->temp3 == 0) || (ob->temp3 == 1)) //heatseek
9469
9470 {SD_PlaySoundRTP(BAS[ob->obclass].fire+2,ob->x,ob->y);
9471 angle = AngleBetween(ob,PLAYER[0]);
9472 SpawnMissile(ob,missileobj,0x6000,angle,&s_missile1,0x8000);
9473 if (ob->temp3 == 3)
9474 perpangle = angle + ANGLES/4;
9475 else
9476 perpangle = angle - ANGLES/4;
9477 Fix(perpangle);
9478
9479 new->temp1 = NME_HEATSEEKINGTYPE;
9480 SetFinePosition(new,new->x + FixedMul(0x8000l,costable[perpangle]),
9481 new->y - FixedMul(0x8000l,sintable[perpangle]));
9482 SetVisiblePosition(new,new->x,new->y);
9483 if (!ob->temp3)
9484 ob->dirchoosetime = 20;
9485 else
9486 {ob->dirchoosetime = 35 - (ob->shapeoffset >> 2) - (gamestate.difficulty << 2);//70;
9487 if (!ob->temp2)
9488 NewState((objtype*)(ob->whatever),&s_NMEhead1);
9489 else
9490 NewState((objtype*)(ob->whatever),&s_NMEhead2);
9491 }
9492 ob->temp3 ++;
9493
9494 }
9495
9496 else if (ob->temp3 == 2) // saucer
9497 { SpawnMissile(ob,NMEsaucerobj,0x1000,angle,&s_NMEsaucer1,0xc000);
9498 new->flags |= FL_SHOOTABLE;
9499 ob->temp3++;
9500 ob->dirchoosetime = 35 - (ob->shapeoffset >> 2) - (gamestate.difficulty << 2);//70;
9501 if (!ob->temp2)
9502 NewState((objtype*)(ob->whatever),&s_NMEhead1rl);
9503 else
9504 NewState((objtype*)(ob->whatever),&s_NMEhead2rl);
9505 }
9506
9507 else if ((ob->temp3 == 3) || (ob->temp3 == 4)) // drunk
9508 {SD_PlaySoundRTP(BAS[ob->obclass].fire+2,ob->x,ob->y);
9509 if (!ob->temp3)
9510 perpangle = angle + ANGLES/4;
9511 else
9512 perpangle = angle - ANGLES/4;
9513 Fix(perpangle);
9514 for(i=0;i<(2+gamestate.difficulty);i++)
9515 {
9516 SpawnMissile(ob,missileobj,0x6000,angle,&s_missile1,0x8000);
9517 new->temp1 = NME_DRUNKTYPE;
9518 SetFinePosition(new,new->x + FixedMul(0x8000l,costable[perpangle]),
9519 new->y - FixedMul(0x8000l,sintable[perpangle]));
9520 SetVisiblePosition(new,new->x,new->y);
9521 }
9522
9523 if (ob->temp3 == 3)
9524 ob->dirchoosetime = 20;
9525 else
9526 {ob->temp3 = 0;
9527 NewState(ob,&s_NMEchase);
9528 if (!ob->temp2)
9529 NewState((objtype*)(ob->whatever),&s_NMEhead1);
9530 else
9531 NewState((objtype*)(ob->whatever),&s_NMEhead2);
9532 }
9533
9534 ob->temp3 ++;
9535
9536 }
9537
9538
9539
9540 }
9541
9542
9543
9544 //================== Tom/Snake ============================================
9545
9546
9547
9548
9549
T_DarkSnakeSpawn(objtype * ob)9550 void T_DarkSnakeSpawn(objtype*ob)
9551 {
9552 objtype * linkinfront;
9553
9554 if (((ob->state == &s_darkmonkhspawn) && (!(ob->ticcount%8))) ||
9555 ((ob->state == &s_darkmonkfastspawn) && (!(ob->ticcount%4))))
9556 {
9557 GetNewActor();
9558 MakeActive(new);
9559 SetFinePosition(new,ob->x,ob->y);
9560 SetVisiblePosition(new,ob->x,ob->y);
9561 new->z = nominalheight;
9562 new->areanumber = MAPSPOT(new->tilex,new->tiley,0)-AREATILE;
9563 MakeLastInArea(new);
9564 new->obclass = b_darksnakeobj;
9565 new->which = ACTOR;
9566 new->angle = AngleBetween(ob,PLAYER[0]);
9567 new->dir = angletodir[new->angle];
9568 if (SNAKELEVEL == 1)
9569 new->speed = 0x5000;
9570 else if (SNAKELEVEL == 2)
9571 new->speed = 0x5800;
9572 else
9573 new->speed = 0x2000;
9574
9575
9576 new->hitpoints = 1000;
9577 new->dirchoosetime = 0;
9578 new->door_to_open = -1;
9579
9580 new->flags |= (FL_ABP|FL_NOFRICTION|FL_SHOOTABLE|FL_BLOCK);
9581
9582 if (ob->whatever)
9583 {
9584 linkinfront = (objtype*)(ob->whatever);
9585 linkinfront->whatever = new;
9586 new->target = linkinfront;
9587 new->targettilex = linkinfront->x;
9588 new->targettiley = linkinfront->y;
9589 new->angle = AngleBetween(new,linkinfront);
9590 new->dir = angletodir[new->angle];
9591 new->flags |= FL_NEVERMARK;
9592 ParseMomentum(new,new->angle);
9593 NewState(new,&s_darkmonksnakelink);
9594 }
9595
9596 else
9597 {
9598 SNAKEHEAD = new;
9599 if (SNAKELEVEL == 3)
9600 NewState(new,&s_darkmonkhead);
9601 else if (SNAKELEVEL == 1)
9602 {
9603 NewState(new,&s_snakefindpath);
9604 new->flags |= FL_ATTACKMODE;
9605 }
9606 else if (SNAKELEVEL == 2)
9607 {
9608 NewState(new,&s_snakepath);
9609 new->angle = 3*ANGLES/4;
9610 new->dir = angletodir[new->angle];
9611 new->flags |= FL_ATTACKMODE;
9612
9613 }
9614 ob->targettilex = ob->targettiley = 0;
9615 ParseMomentum(new,new->angle);
9616 }
9617
9618 if (!ob->ticcount)
9619 SNAKEEND = new;
9620
9621 ob->whatever = new;
9622
9623 }
9624 }
9625
9626
T_GenericMove(objtype * ob)9627 void T_GenericMove(objtype*ob)
9628 {int dx,dy;
9629
9630 if (ob->temp3 == -1)
9631 return;
9632
9633
9634 if (!(SNAKEHEAD->flags & FL_ATTACKMODE))
9635 return;
9636
9637 if (ob->hitpoints <= 0)
9638 {KillActor(ob);
9639 ob->temp3 = 0;
9640 return;
9641 }
9642
9643 if (!ob->ticcount)
9644 {if (ob->state == &s_darkmonkredlink)
9645 ob->temp3 = 0;
9646 else if ((ob!=SNAKEEND) && (ob->state == &s_redlinkhit))
9647 NewState((objtype*)(ob->whatever),&s_redlinkhit);
9648 }
9649
9650 dx = ob->targettilex-ob->x;
9651 dy = ob->y-ob->targettiley;
9652 if ((dx > -0xa000) && (dx < 0xa000) && (dy > -0xa000) && (dy < 0xa000))
9653 {if (ob->temp1 && ob->temp2)
9654 {dx = ob->temp1 - ob->x;
9655 dy = ob->y - ob->temp2;
9656 ZEROMOM;
9657 /*
9658 if ((ob->targettilex == ob->temp1) && (ob->targettiley == ob->temp2))
9659 return; */
9660 //ob->x = ob->drawx = ob->targettilex;
9661 //ob->y = ob->drawy = ob->targettiley;
9662 //ob->tilex = ob->x >> TILESHIFT;
9663 //ob->tiley = ob->y >> TILESHIFT;
9664 //#if ((DEVELOPMENT == 1))
9665 // Debug("\nfollower %d being moved to targetx %4x and targety %4x",
9666 // ob-SNAKEHEAD,ob->x,ob->y);
9667 // #endif
9668 ob->targettilex = ob->temp1;
9669 ob->targettiley = ob->temp2;
9670 #if (0)
9671 Debug("\nfollower %d's new targetx %4x, targety %4x",
9672 ob-SNAKEHEAD,ob->temp1,ob->temp2);
9673 #endif
9674 ob->angle = atan2_appx(dx,dy);
9675 ob->dir = angletodir[ob->angle];
9676 ParseMomentum(ob,ob->angle);
9677 }
9678 }
9679 else if (NOMOM)
9680 {//SNAKEHEAD->dirchoosetime = 0;
9681 ParseMomentum(ob,ob->angle);
9682 }
9683 if (ob->momentumx || ob->momentumy)
9684 MoveActor(ob);
9685
9686 // ActorMovement(ob);
9687
9688 }
9689
9690
9691 /*
9692 ===============
9693 =
9694 = SelectSnakeDir
9695 =
9696 ===============
9697 */
9698
9699
SelectSnakeDir(objtype * ob)9700 void SelectSnakeDir (objtype *ob)
9701 {
9702 int spot,centerx,centery,dx,dy;
9703
9704 spot = MAPSPOT(ob->tilex,ob->tiley,1)-ICONARROWS;
9705
9706 if ((spot >= 0) && (spot<= 7) && ((ob->dir!=(unsigned)spot)||(!(ob->flags & FL_DONE))))
9707 { centerx= (ob->tilex << 16) + HALFGLOBAL1;
9708 centery= (ob->tiley << 16) + HALFGLOBAL1;
9709 dx = abs(centerx - ob->x);
9710 dy = abs(centery - ob->y);
9711
9712 if ((dx < SNAKERAD) && (dy < SNAKERAD))
9713 // new direction
9714 {ZEROMOM;
9715 ob->dir = spot;
9716 ob->flags |= FL_DONE;
9717 ParseMomentum(ob,dirangle8[ob->dir]);
9718 SetFinePosition(ob,centerx,centery);
9719 SetVisiblePosition(ob,ob->x,ob->y);
9720
9721 if (ob==SNAKEHEAD) {
9722 SoftError("\n path changed at %d, %d",ob->tilex,ob->tiley);
9723 }
9724 }
9725 }
9726
9727 MoveActor(ob);
9728
9729 }
9730
9731
T_SnakePath(objtype * ob)9732 void T_SnakePath(objtype*ob)
9733 {objtype*temp,*follower;
9734
9735 if (SNAKEEND && (SNAKELEVEL == 2))
9736 {if (CheckLine(SNAKEEND,PLAYER[0],SIGHT))
9737 {if (ob->temp3 == -1) //if snake can see player
9738 //and he's presently stopped, restart
9739 {for(temp=ob;temp;temp=(objtype*)(temp->whatever))
9740 {temp->temp3 = 0;
9741 temp->momentumx = temp->temp1;
9742 temp->momentumy = temp->temp2;
9743 }
9744 ob->dirchoosetime = 0;
9745 }
9746 }
9747 else if (ob->temp3 != -1) //else if he hasn't been stopped, stop him
9748 {for(temp=ob;temp;temp = (objtype*)(temp->whatever))
9749 {temp->temp1 = temp->momentumx;
9750 temp->temp2 = temp->momentumy;
9751 temp->temp3 = -1;
9752 temp->momentumx = temp->momentumy = 0;
9753 }
9754 }
9755 else
9756 return;
9757 }
9758
9759
9760 if (ob->dirchoosetime)
9761 ob->dirchoosetime--;
9762
9763 else
9764 {int count = 0;
9765
9766 for(temp=ob;temp->whatever;temp=(objtype*)(temp->whatever))
9767 {follower = (objtype*)(temp->whatever);
9768 follower->temp1 = temp->x;
9769 follower->temp2 = temp->y;
9770
9771 SoftError("\n follower %d temp1 set to %4x, temp2 set to %4x",
9772 count,temp->x,temp->y);
9773 count ++;
9774 }
9775 ob->dirchoosetime = 2 ;//15
9776 }
9777
9778 if (ob->momentumx || ob->momentumy)
9779 SelectSnakeDir(ob);
9780 //else
9781 // {ParseMomentum(ob,ob->angle);
9782 // MoveActor(ob);
9783 // }
9784
9785
9786 }
9787
FindClosestPath(objtype * ob)9788 void FindClosestPath(objtype*ob)
9789 {int tx,ty,dx,dy,angle;
9790
9791
9792 tx = (ob->targettilex << 16) + TILEGLOBAL/2;
9793 ty = (ob->targettiley << 16) + TILEGLOBAL/2;
9794
9795 dx= tx - ob->x;
9796 dy= ob->y - ty;
9797 angle = atan2_appx(dx,dy);
9798
9799 ZEROMOM;
9800 ParseMomentum(ob,angle);
9801 MoveActor(ob);
9802
9803 }
9804
9805
T_SnakeFindPath(objtype * ob)9806 void T_SnakeFindPath(objtype*ob)
9807 {int i,dx,dy,currdist,mindist,map;
9808 tpoint dstruct,*dummy=&dstruct;
9809 objtype*temp,*follower;
9810
9811 if (ob->targettilex || ob->targettiley)
9812 {FindClosestPath(ob);
9813 dx = ob->targettilex - ob->tilex;
9814 dy = ob->targettiley - ob->tiley;
9815 if ((!dx) && (!dy))
9816 {SetTilePosition(ob,ob->tilex,ob->tiley);
9817 SetVisiblePosition(ob,ob->x,ob->y);
9818 ob->y = ob->drawy = (ob->tiley << TILESHIFT) + TILEGLOBAL/2;
9819 NewState(ob,&s_snakepath);
9820 return;
9821 }
9822 }
9823
9824 else
9825 {dummy->which = ACTOR;
9826 mindist = 0x7fffffff;
9827 for(i=0;i<whichpath;i++)
9828 {
9829 SetTilePosition(dummy,SNAKEPATH[i].x,SNAKEPATH[i].y);
9830 dummy->z = ob->z;
9831 if (CheckLine(ob,dummy,SIGHT))
9832 {currdist = FindDistance(ob->tilex-dummy->tilex,ob->tiley-dummy->tiley);
9833 map = MAPSPOT(ob->tilex,ob->tiley,0)-AREATILE;
9834 if ((currdist < mindist) && (map >= 0) && (map <= NUMAREAS))
9835 {ob->targettilex = dummy->tilex;
9836 ob->targettiley = dummy->tiley;
9837 mindist = currdist;
9838 }
9839 }
9840 }
9841 }
9842
9843 if (ob->dirchoosetime)
9844 ob->dirchoosetime--;
9845 else
9846 {for(temp=ob;temp->whatever;temp=(objtype*)(temp->whatever))
9847 {follower = (objtype*)(temp->whatever);
9848 follower->temp1 = temp->x;
9849 follower->temp2 = temp->y;
9850 }
9851 ob->dirchoosetime = 2 ;//15
9852 }
9853 }
9854
9855
9856
T_SnakeFinale(objtype * ob)9857 void T_SnakeFinale(objtype*ob)
9858 {
9859
9860 if ((ob->state == &s_snakefireworks1)||(ob->state == &s_snakefireworks2))
9861 {
9862 if (ob->z != (maxheight-200))
9863 {
9864 ob->z --;
9865 return;
9866 }
9867 SetGibSpeed(0x4500);
9868 SpawnParticles(ob,RANDOM,100);
9869
9870 SpawnParticles(ob,gt_spit,100);
9871 ResetGibSpeed();
9872 NewState(ob,&s_dexplosion1);
9873 }
9874
9875 else
9876 {
9877 if (!ob->ticcount)
9878 {
9879 NewState(EXPLOSIONS,&s_megaremove);
9880 // SpawnParticles(ob,RANDOM,100);
9881 // SpawnParticles(ob,SPIT,100);
9882 return;
9883 }
9884
9885 if (ob->dirchoosetime)
9886 ob->dirchoosetime --;
9887 else
9888 {
9889 ob->dirchoosetime = (GameRandomNumber("snake finale choose",0) % 7) + 15;
9890 SetGibSpeed(0x3000);
9891 SpawnParticles(ob,RANDOM,30);
9892 SpawnParticles(ob,gt_spit,20);
9893 ResetGibSpeed();
9894 }
9895 }
9896 }
9897
9898
9899
T_DarkSnakeChase(objtype * ob)9900 void T_DarkSnakeChase(objtype*ob)
9901 {
9902 objtype* temp,*follower;
9903 int tdir,angle;
9904
9905
9906 if (!(ob->flags & FL_ATTACKMODE))
9907 {
9908 if (!(CheckSight(ob,player) || Near(ob,player,4)))
9909 return;
9910 else
9911 {
9912 ob->flags |= FL_ATTACKMODE;
9913 MU_StartSong(song_bosssee);
9914 }
9915
9916 }
9917
9918
9919
9920 if (ob->hitpoints <= 0)
9921 {
9922 MU_StartSong(song_bossdie);
9923 KillActor(ob);
9924 AddMessage("Oscuro defeated!",MSG_CHEAT);
9925 return;
9926 }
9927
9928 angle = AngleBetween(ob,PLAYER[0]);
9929 tdir = angletodir[angle];
9930 if (Near(ob,PLAYER[0],6) && (ob->dir == (unsigned)tdir) && (!(ob->state->condition & SF_DOWN)))
9931 {
9932 NewState(ob,&s_snakefire1);
9933 SD_PlaySoundRTP(SD_SNAKEREADYSND,ob->x,ob->y);
9934 }
9935
9936 if (!ob->ticcount)
9937 {
9938 if (ob->state == &s_darkmonkredhead)
9939 ob->temp3 = 0; // no longer hitable
9940 else if ((ob->state == &s_redheadhit) && (ob != SNAKEEND))
9941 NewState((objtype*)(ob->whatever),&s_redlinkhit);
9942 else if (ob->state->condition & SF_UP)
9943 {
9944 SpawnMissile(ob,dm_spitobj,0x6000,angle,&s_spit1,0x6000);
9945 SD_PlaySoundRTP(BAS[ob->obclass].fire,ob->x,ob->y);
9946 //new->z -= 5;
9947 }
9948 //spawn spit;
9949 }
9950
9951 if (CheckLine(ob,PLAYER[0],SIGHT))
9952 {
9953 ob->targettilex = PLAYER[0]->x;
9954 ob->targettiley = PLAYER[0]->y;
9955 }
9956
9957 if (ob->dirchoosetime)
9958 {
9959 ob->dirchoosetime--;
9960 ActorMovement(ob);
9961 if (NOMOM)
9962 ob->dirchoosetime = 0;
9963 }
9964
9965 else
9966 {//if (ob)
9967 for(temp=ob;temp->whatever;temp=(objtype*)(temp->whatever))
9968 {
9969 follower = (objtype*)(temp->whatever);
9970 follower->temp1 = temp->x;
9971 follower->temp2 = temp->y;
9972 }
9973 SelectChaseDir(ob);
9974 ob->dirchoosetime = 7 ;//15
9975 }
9976 }
9977
9978
9979
T_DarkmonkReact(objtype * ob)9980 void T_DarkmonkReact(objtype*ob)
9981 {
9982 if (ob->z < nominalheight)
9983 {MISCVARS->monkz += MZADJUST;
9984 ob->z = nominalheight + (MISCVARS->monkz >> 16);
9985 //ob->z++;
9986 return;
9987 }
9988
9989 else
9990 {int ocl;
9991
9992 ocl = ob->temp3;
9993
9994 if (ocl == p_kesobj)
9995 NewState(ob,&s_darkmonkabsorb1);
9996 else if (ocl == p_heatseekobj)
9997 NewState(ob,&s_darkmonkhball1);
9998 else if (ocl == p_firebombobj)
9999 NewState(ob,&s_darkmonkbreathe1);
10000 else
10001 NewState(ob,&s_darkmonkchase1);
10002 ob->dirchoosetime = 0;
10003 }
10004
10005 }
10006
10007
10008
T_DarkmonkCharge(objtype * ob)10009 void T_DarkmonkCharge(objtype*ob)
10010 {int dx,dy;
10011
10012 dx = abs(PLAYER[0]->x - ob->x);
10013 dy = abs(PLAYER[0]->y - ob->y);
10014 if ((dx < 0xa000) && (dy < 0xa000))
10015 {DamageThing(PLAYER[0],10);
10016 Collision(PLAYER[0],ob,0,0);
10017 M_CheckPlayerKilled(PLAYER[0]);
10018 }
10019
10020 if (!ob->ticcount)
10021 ob->speed >>= 1;
10022
10023 if (ob->dirchoosetime)
10024 ob->dirchoosetime --;
10025
10026 if (NOMOM || (!ob->dirchoosetime))
10027 {ob->angle = AngleBetween(ob,PLAYER[0]);
10028 ob->dir = angletodir[ob->angle];
10029 ParseMomentum(ob,ob->angle);
10030 ob->dirchoosetime = 5;
10031 }
10032
10033 ActorMovement(ob);
10034
10035
10036 }
10037
10038
T_DarkmonkLandAndFire(objtype * ob)10039 void T_DarkmonkLandAndFire(objtype*ob)
10040 {
10041
10042 if (ob->z < nominalheight)
10043 {MISCVARS->monkz += MZADJUST;
10044 ob->z = nominalheight + (MISCVARS->monkz >> 16);
10045 //ob->z++;
10046 return;
10047 }
10048 if (Near(ob,PLAYER[0],3))
10049 {if (GameRandomNumber("darkmonkland",0)<128)
10050 NewState(ob,&s_darkmonkbball1);
10051 else
10052 {ob->angle = AngleBetween(ob,PLAYER[0]);
10053 ob->dir = angletodir[ob->angle];
10054 ob->speed <<= 1; // goes twice as fast
10055 ZEROMOM;
10056 ParseMomentum(ob,ob->angle);
10057 ob->dirchoosetime = 5; // change dir every 5 tics
10058 ob->hitpoints -= 200; // big penalty for charging
10059 if (ob->hitpoints <= 0)
10060 {objtype*column = (objtype*)(ob->whatever);
10061
10062 EnableObject((int)column);
10063 ob->whatever = NULL;
10064
10065 KillActor(ob);
10066 NewState(ob,&s_darkmonkfastspawn);
10067 AddMessage("Oscuro flees!",MSG_CHEAT);
10068 return;
10069 }
10070 NewState(ob,&s_darkmonkcharge1);
10071 }
10072
10073 }
10074 else if (ob->temp1)
10075 NewState(ob,&s_darkmonklightning1);
10076 else
10077 NewState(ob,&s_dmgreenthing1);
10078 ob->temp1 ^= 1;
10079 ob->dirchoosetime = 0;
10080
10081 }
10082
10083
T_DarkmonkChase(objtype * ob)10084 void T_DarkmonkChase(objtype*ob)
10085 {int chance,dx,dy,dist;
10086
10087
10088 if (!Near(ob,PLAYER[0],2))
10089 {if (ob->z > (maxheight - 100))
10090 {MISCVARS->monkz -= MZADJUST;
10091 ob->z = nominalheight + (MISCVARS->monkz >> 16);
10092 //ob->z--;
10093 return;
10094 }
10095 }
10096 else if (ob->z < nominalheight)
10097 {MISCVARS->monkz += MZADJUST;
10098 ob->z = nominalheight + (MISCVARS->monkz >> 16);
10099 //ob->z++;
10100 return;
10101 }
10102
10103
10104 if (CheckLine(ob,PLAYER[0],SIGHT))
10105 {ob->targettilex = PLAYER[0]->x;
10106 ob->targettiley = PLAYER[0]->y;
10107 }
10108
10109 if (!ob->ticcount)
10110 {
10111 if (CheckLine(ob,PLAYER[0],SHOOT)) // got a shot at player?
10112 {dx = abs(ob->tilex - PLAYER[0]->tilex);
10113 dy = abs(ob->tiley - PLAYER[0]->tiley);
10114 dist = dx>dy ? dx : dy;
10115 if (!dist || dist==1)
10116 chance = 300;//300;
10117 else
10118 chance = 400/dist;//300/dist;
10119
10120 if (GameRandomNumber("T_DarkMonkChase",0) < chance)
10121 {NewState(ob,&s_dmlandandfire);
10122 return;
10123 }
10124 }
10125 }
10126
10127 if (ob->dirchoosetime)
10128 ob->dirchoosetime--;
10129
10130 if ((ob->flags & FL_STUCK) || (!ob->dirchoosetime))
10131 {SelectChaseDir(ob);
10132 ob->dirchoosetime = M_CHOOSETIME(ob);
10133 }
10134
10135 else
10136 {if (NOMOM)
10137 ParseMomentum(ob,dirangle8[ob->dir]);
10138 ActorMovement(ob);
10139
10140 }
10141
10142 }
10143
10144
10145 //====================== End of Boss Functions ===========================//
10146
10147
10148
10149
10150
10151
T_GunStand(objtype * ob)10152 void T_GunStand(objtype*ob)
10153 {int dy,dx,infrontof,dz;
10154 objtype* temp;
10155
10156 // if (ob->target)
10157 // Error("gun reset with non-null target");
10158 for(temp = firstareaactor[ob->areanumber];temp;temp= temp->nextinarea)
10159 {if (temp == ob)
10160 continue;
10161 if (temp->obclass == ob->obclass)
10162 continue;
10163 if ((!(temp->flags & FL_SHOOTABLE)) || (temp->flags & FL_DYING))
10164 continue;
10165
10166 dy = ob->y - temp->y;
10167 dx = ob->x - temp->x;
10168 dz = ob->z - temp->z;
10169 if ((abs(dy)>0x40000) || (abs(dx)>0x40000) || (abs(dz) > 20))
10170 continue;
10171
10172
10173 infrontof = 0;
10174
10175 switch (ob->dir)
10176 {case north:
10177 if ((dy > 0) && (abs(dx)<0x8000))
10178 infrontof = 1;
10179 break;
10180
10181 case east:
10182 if ((dx < 0) && (abs(dy)<0x8000))
10183 infrontof = 1;
10184 break;
10185
10186 case south:
10187 if ((dy < 0) && (abs(dx)<0x8000))
10188 infrontof = 1;
10189 break;
10190
10191 case west:
10192 if ((dx > 0) && (abs(dy)<0x8000))
10193 infrontof = 1;
10194 break;
10195
10196 default:
10197 break;
10198 }
10199
10200 if (infrontof && CheckLine(ob,temp,SHOOT))
10201 {ob->target = temp;
10202 NewState(ob,&s_gunraise1);
10203 return;
10204 }
10205 }
10206
10207 }
10208
10209
T_4WayGunStand(objtype * ob)10210 void T_4WayGunStand(objtype*ob)
10211 {
10212 int dy,dx,dz;
10213 objtype* temp;
10214
10215 if (ob->target)
10216 Error("gun reset with non-null target");
10217 for(temp = firstareaactor[ob->areanumber];temp;temp= temp->nextinarea)
10218 {
10219 if (temp == ob)
10220 continue;
10221
10222 if (temp->obclass == ob->obclass)
10223 continue;
10224
10225 if ((!(temp->flags & FL_SHOOTABLE)) || (temp->flags & FL_DYING))
10226 continue;
10227
10228 dy = abs(ob->x-temp->x);
10229 dx = abs(ob->y-temp->y);
10230 dz = abs(ob->z-temp->z);
10231 if ((dx < 0x40000) && (dy < 0x40000) && (dz< 20) && CheckLine(ob,temp,SHOOT))
10232 {//if ((dx < 0x8000) || (dy <0x8000))
10233 ob->target = temp;
10234 NewState(ob,&s_4waygunfire1);
10235 return;
10236 }
10237 }
10238 }
10239
10240
A_GunShoot(objtype * ob)10241 void A_GunShoot(objtype*ob)
10242 { int dx,dy,dz,damage,infrontof,tnear,savedangle;
10243 objtype * target;
10244
10245 if (!ob->ticcount)
10246 {target = (objtype*)(ob->target);
10247 if (!target)
10248 Error("an instance of %s called gunshoot without a target\n",debugstr[ob->obclass]);
10249 if ((!(target->flags & FL_SHOOTABLE)) || (target->flags & FL_DYING))
10250 {NewState(ob,&s_gunlower1);
10251 ob->target = NULL;
10252 return;
10253 }
10254
10255 dx = target->x-ob->x;
10256 dy = ob->y-target->y;
10257 dz = ob->z-target->z;
10258
10259
10260 tnear = ((abs(dy)<0x40000) && (abs(dx)<0x40000) && (abs(dz) < 20));
10261 infrontof = 0;
10262
10263 switch (ob->dir)
10264 {case north:
10265 if ((dy > 0) && (abs(dx)<0x8000))
10266 infrontof = 1;
10267 break;
10268
10269 case east:
10270 if ((dx < 0) && (abs(dy)<0x8000))
10271 infrontof = 1;
10272 break;
10273
10274 case south:
10275 if ((dy < 0) && (abs(dx)<0x8000))
10276 infrontof = 1;
10277 break;
10278
10279 case west:
10280 if ((dx > 0) && (abs(dy)<0x8000))
10281 infrontof = 1;
10282 break;
10283
10284 default:
10285 break;
10286 }
10287
10288 if ((!infrontof) || (!CheckLine(ob,target,SHOOT)) ||
10289 (!tnear))
10290 {NewState(ob,&s_gunlower1);
10291 ob->target = NULL;
10292 return;
10293 }
10294
10295 //SD_PlaySoundRTP(SD_FIRE,PLAYER[0]->x,PLAYER[0]->y,ob->x,ob->y);
10296 //hitchance = 128;
10297
10298 // if (!target)
10299 // Error("object called shoot without a target\n");
10300
10301
10302 damage = DMG_AHGUN;
10303
10304
10305 if (target->obclass == playerobj)
10306 {target->target = ob;
10307 if (target->flags & FL_BPV)
10308 damage >>= 1;
10309
10310 }
10311 savedangle = ob->angle;
10312 ob->angle = atan2_appx(dx,dy);
10313 RayShoot(ob,damage,GameRandomNumber("A_GunShoot Accuracy",0) % 20);
10314 ob->angle = savedangle;
10315 SD_PlaySoundRTP(SD_BIGEMPLACEFIRESND,ob->x,ob->y);
10316 }
10317
10318 }
10319
10320
A_4WayGunShoot(objtype * ob)10321 void A_4WayGunShoot(objtype*ob)
10322 {
10323 int dx,dy,dz,damage,savedangle;
10324 objtype * target;
10325
10326 if (ob->ticcount == (ob->state->tictime >> 1))
10327 {
10328 target = (objtype*)(ob->target);
10329 if (!target)
10330 Error("an instance of %s called 4waygunshoot without a target\n",debugstr[ob->obclass]);
10331 dx = abs(target->x-ob->x);
10332 dy = abs(ob->y-target->y);
10333 dz = abs(ob->z-target->z);
10334 if ((dx > 0x40000) || (dy > 0x40000) || (dz > 20) ||
10335 (!CheckLine(ob,target,SHOOT)) ||
10336 (!(target->flags & FL_SHOOTABLE)) ||
10337 (target->flags & FL_DYING)
10338 )
10339 {
10340 ob->target = NULL;
10341 NewState(ob,&s_4waygun);
10342 return;
10343 }
10344
10345
10346 //SD_PlaySoundRTP(SD_FIRE,PLAYER[0]->x,PLAYER[0]->y,ob->x,ob->y);
10347 //hitchance = 128;
10348
10349 // if (!target)
10350 // Error("object called shoot without a target\n");
10351
10352
10353 damage = DMG_AHGUN;
10354 SD_PlaySoundRTP(BAS[ob->obclass].fire,ob->x,ob->y);
10355
10356 if (target->obclass == playerobj)
10357 {
10358 target->target = ob;
10359 if (target->flags & FL_BPV)
10360 damage >>= 1;
10361 }
10362
10363 savedangle = ob->angle;
10364 ob->angle = 0;
10365 RayShoot(ob,damage,GameRandomNumber("A_4WayGunShoot Accuracy",0) % 20);
10366 ob->angle = ANG90;
10367 RayShoot(ob,damage,GameRandomNumber("A_4WayGunShoot Accuracy",0) % 20);
10368 ob->angle = ANG180;
10369 RayShoot(ob,damage,GameRandomNumber("A_4WayGunShoot Accuracy",0) % 20);
10370 ob->angle = ANG270;
10371 RayShoot(ob,damage,GameRandomNumber("A_4WayGunShoot Accuracy",0) % 20);
10372 ob->angle = savedangle;
10373 }
10374 }
10375
10376
A_Drain(objtype * ob)10377 void A_Drain (objtype *ob)
10378 {
10379 int dx,dy,dz,damage;
10380
10381 dx = abs(PLAYER[0]->x - ob->x);
10382 dy = abs(PLAYER[0]->y - ob->y);
10383 dz = abs(PLAYER[0]->z - ob->z);
10384
10385 if ((dx > TOUCHDIST) || (dy > TOUCHDIST) || (dz > (TOUCHDIST>>10)))
10386 {
10387 NewState(ob,&s_dmonkshoot5);
10388 return;
10389 }
10390
10391 if (ob->ticcount)
10392 return;
10393
10394 else
10395 {
10396 damage = (GameRandomNumber("A_Drain",ob->obclass) >> 3);
10397 DamageThing (PLAYER[0],damage);
10398 ob->hitpoints += damage;
10399 if (ob->hitpoints > starthitpoints[gamestate.difficulty][ob->obclass])
10400 ob->hitpoints = starthitpoints[gamestate.difficulty][ob->obclass];
10401
10402 Collision(PLAYER[0],ob,0,0);
10403 if (PLAYER[0]->flags & FL_DYING)
10404 PLAYER[0]->target = ob;
10405 M_CheckPlayerKilled(PLAYER[0]);
10406 SD_PlaySoundRTP(SD_MONKGRABSND,ob->x,ob->y);
10407 }
10408 }
10409
10410
10411
10412
10413
10414
A_DmonkAttack(objtype * ob)10415 void A_DmonkAttack(objtype*ob)
10416 {int angle,nobclass,nspeed,altangle1=0,altangle2=0,zoff=0,sound;
10417 statetype *nstate;
10418
10419
10420 if (!ob->ticcount)
10421 {
10422 ob->hitpoints -= 120;//120;
10423 if (ob->hitpoints <= 0)
10424 {
10425 objtype*column = (objtype*)(ob->whatever);
10426
10427 EnableObject((int)column);
10428 ob->whatever = NULL;
10429
10430 KillActor(ob);
10431 NewState(ob,&s_darkmonkfastspawn);
10432 return;
10433 }
10434 }
10435
10436
10437 if (ob->dirchoosetime)
10438 ob->dirchoosetime --;
10439
10440 else
10441 {sound = BAS[ob->obclass].fire;
10442 angle = AngleBetween(ob,PLAYER[0]);
10443 nspeed = 0x6000;
10444
10445 if (ob->state == &s_darkmonksphere8)
10446 {nstate = &s_kessphere1;
10447 nobclass = p_kesobj;
10448 ob->dirchoosetime = 70;
10449 }
10450
10451 else if (ob->state == &s_darkmonkhball7)
10452 {nstate = &s_handball1;
10453 nobclass = dm_heatseekobj;
10454 nspeed = 0x3000;
10455 ob->dirchoosetime = 5;
10456 }
10457
10458 else if (ob->state == &s_darkmonkbball7)
10459 {nstate = &s_faceball1;
10460 nobclass = dm_weaponobj;
10461 nspeed = 0x3000;
10462 ob->dirchoosetime = 5;
10463 }
10464
10465 else if (ob->state == &s_darkmonklightning9)
10466 {nstate = &s_lightning;
10467 nobclass = dm_weaponobj;
10468 ob->dirchoosetime = 3;
10469 sound++;
10470 }
10471
10472 else if (ob->state == &s_dmgreenthing8)
10473 {nstate = &s_energysphere1;
10474 nobclass = dm_weaponobj;
10475 sound +=2;
10476 ob->dirchoosetime = 70;
10477 }
10478
10479 else if (ob->state == &s_darkmonkfspark5)
10480 {nstate = &s_floorspark1;
10481
10482 altangle1 = angle + ANGLES/24;
10483 altangle2 = angle - ANGLES/24;
10484 Fix(altangle1);
10485 Fix(altangle2);
10486 nobclass = dm_weaponobj;
10487 ob->dirchoosetime = 3;
10488 sound += 3;
10489 }
10490
10491 else if (ob->state == &s_darkmonkbreathe6)
10492 {nstate = &s_crossfire1;
10493 ob->dirchoosetime = 3;
10494 nobclass = dm_weaponobj;
10495 zoff = -15;
10496 sound += 3;
10497 }
10498
10499 SpawnMissile(ob,nobclass,nspeed,angle,nstate,0xb000);
10500 SD_PlaySoundRTP(sound,ob->x,ob->y);
10501
10502 new->z = ob->z+zoff;
10503 if (altangle1)
10504 {
10505 SpawnMissile(ob,nobclass,nspeed,altangle1,nstate,0xb000);
10506 SpawnMissile(ob,nobclass,nspeed,altangle2,nstate,0xb000);
10507 }
10508 }
10509
10510
10511
10512 }
10513
10514
10515
10516 #endif // SHAREWARE endif
10517
10518
10519
10520
10521 //=====================================================================//
10522
10523
10524
10525
10526 /*
10527 ===============
10528 =
10529 = T_Stand
10530 =
10531 ===============
10532 */
10533
T_Stand(objtype * ob)10534 void T_Stand (objtype *ob)
10535 {
10536 if (!ob->ticcount)
10537 SightPlayer (ob);
10538 else
10539 SoftError("\n ob type %s ticcount of %d in T_Stand",debugstr[ob->obclass],
10540 ob->ticcount);
10541 }
10542
10543
10544
10545
10546
DamagePlayerActor(objtype * ob,int damage)10547 void DamagePlayerActor(objtype *ob, int damage)
10548
10549 {
10550 playertype *pstate;
10551
10552 switch (gamestate.difficulty)
10553 {
10554 case 0: damage >>= 1;
10555 break;
10556 case 1: damage -= (damage >> 2);
10557 break;
10558 case 2: break;
10559 case 3: //damage += (damage>>2);
10560 break;
10561 //default: Error("Um, Gamestate.Difficulty, uh, has problems.\n");
10562 }
10563
10564 if (!damage) damage++;
10565
10566 M_LINKSTATE(ob,pstate);
10567
10568
10569 pstate->health -= damage;
10570 ob->hitpoints = pstate->health;
10571
10572 SD_PlaySoundRTP(SD_PLAYERTCHURTSND+(pstate->player),ob->x,ob->y);
10573 if (ob==player)
10574 {
10575 damagecount += damage;
10576 if (cybermanenabled)
10577 SWIFT_TactileFeedback (10*damage, 15, 15);
10578 if ( SHOW_BOTTOM_STATUS_BAR() )
10579 DrawBarHealth (false);
10580 }
10581
10582 if (pstate->health<=0)
10583 {
10584 pstate->health = 0;
10585 ob->hitpoints = 0;
10586 }
10587 }
10588
10589
10590
10591
DamageNonPlayerActor(objtype * ob,int damage)10592 void DamageNonPlayerActor(objtype *ob,int damage)
10593 {
10594 //if ((ob->obclass == b_darksnakeobj) && (!ob->temp3))
10595 // return;
10596
10597 if (!(ob->flags & FL_ATTACKMODE))
10598 damage <<= 1;
10599
10600 ob->hitpoints -= damage;
10601 if (ob->hitpoints <= 0)
10602 {
10603 int sound;
10604
10605 sound = BAS[ob->obclass].die;
10606 if (ob->obclass == lowguardobj)
10607 {
10608 if (ob->shapeoffset)
10609 sound ++;
10610 }
10611 SD_PlaySoundRTP(sound,ob->x,ob->y);
10612 }
10613 else
10614 SD_PlaySoundRTP(BAS[ob->obclass].hit,ob->x,ob->y);
10615
10616 #if (SHAREWARE == 0)
10617 if ((ob->obclass == b_robobossobj) && (ob->temp2 <= 2))
10618 {
10619 if (ob->hitpoints <
10620 ((3-ob->temp2)*starthitpoints[gamestate.difficulty][ob->obclass]>>2)
10621 )
10622 {
10623 SD_PlaySoundRTP(SD_NMEAPARTSND,ob->x,ob->y);
10624 ob->temp2++;
10625 ob->shapeoffset += 16;
10626 ob->speed += 0x500;
10627 SpawnNewObj(ob->tilex,ob->tiley,&s_megaexplosions,inertobj);
10628 new->temp1 = 3;
10629 new->flags |= FL_ABP;
10630 MakeActive(new);
10631 }
10632 if (ob->temp2 == 1)
10633 NewState((objtype*)(ob->whatever),&s_NMEhead2);
10634 }
10635 #endif
10636 MISCVARS->madenoise = true;
10637 }
10638
10639
10640
DamageStaticObject(statobj_t * tempstat,int damage)10641 void DamageStaticObject(statobj_t*tempstat,int damage)
10642 {
10643
10644
10645 tempstat->hitpoints -= damage;
10646 if (tempstat->hitpoints <= 0)
10647 {
10648 sprites[tempstat->tilex][tempstat->tiley]=NULL;
10649 tempstat->flags |= FL_NONMARK;
10650 if (tempstat->flags&FL_LIGHT)
10651 {
10652
10653 if (MAPSPOT(tempstat->tilex,tempstat->tiley,2))
10654 {touchplatetype *tplate;
10655
10656 for(tplate=touchplate[tempstat->linked_to];tplate;tplate = tplate->nextaction)
10657 if (tplate->whichobj == (int)(tempstat))
10658 RemoveTouchplateAction(tplate,tempstat->linked_to);
10659 }
10660
10661 if (tempstat->flags & FL_LIGHTON)
10662 TurnOffLight(tempstat->tilex,tempstat->tiley);
10663
10664
10665 if (tempstat->itemnumber<=stat_chandelier)
10666 //SpawnFallingDebris(tempstat->x,tempstat->y,tempstat->z-32);
10667 {
10668 objtype *prevlast = LASTACTOR;
10669
10670 SpawnSlowParticles(gt_sparks,4,tempstat->x,tempstat->y,tempstat->z-32);
10671 for(prevlast = prevlast->next;prevlast;prevlast= prevlast->next)
10672 {
10673 prevlast->momentumz = 1; // any positive value will do
10674 prevlast->momentumx >>= 1;
10675 prevlast->momentumy >>= 1;
10676 }
10677 }
10678 else
10679 {
10680
10681 SpawnStatic(tempstat->tilex,tempstat->tiley,stat_metalshards,-1);
10682 LASTSTAT->flags |= (FL_ABP|FL_NONMARK);
10683 sprites[tempstat->tilex][tempstat->tiley] = NULL;
10684 MakeStatActive(LASTSTAT);
10685 switch (tempstat->itemnumber)
10686 {
10687 case stat_lamp:
10688 case stat_altbrazier1:
10689 case stat_altbrazier2:
10690 case stat_torch:
10691 SpawnSlowParticles(gt_sparks,5,tempstat->x,tempstat->y,tempstat->z-32);
10692 break;
10693 case stat_floorfire:
10694 SpawnSlowParticles(gt_sparks,5,tempstat->x,tempstat->y,tempstat->z);
10695 break;
10696 default:
10697 ;
10698 }
10699 }
10700 SpawnSolidStatic(tempstat);
10701 SD_PlaySoundRTP(SD_ITEMBLOWSND,tempstat->x,tempstat->y);
10702 }
10703 else
10704 {
10705 switch (tempstat->itemnumber)
10706 {
10707 case stat_dariantouch:
10708 MISCVARS->ETOUCH[tempstat->linked_to].x = MISCVARS->ETOUCH[tempstat->linked_to].y = 0;
10709 case stat_tntcrate:
10710 case stat_bonusbarrel:
10711 SpawnNewObj(tempstat->tilex,tempstat->tiley,&s_staticexplosion1,inertobj);
10712 MakeActive(new);
10713 new->flags |= FL_ABP;
10714 new->whatever = tempstat;
10715 new->temp2 = damage;
10716
10717 if (tempstat->itemnumber == stat_bonusbarrel)
10718 {
10719 int rand = GameRandomNumber("DamageThing",0);
10720
10721 if (rand < 80)
10722 {
10723 if (rand & 1)
10724 SpawnStatic(tempstat->tilex,tempstat->tiley,stat_monkmeal,-1);
10725 else
10726 SpawnStatic(tempstat->tilex,tempstat->tiley,stat_priestporridge,-1);
10727 gamestate.healthtotal ++;
10728 }
10729 else if (rand < 160)
10730 {
10731 if (rand & 1)
10732 SpawnStatic(tempstat->tilex,tempstat->tiley,stat_lifeitem1,-1);
10733 else
10734 SpawnStatic(tempstat->tilex,tempstat->tiley,stat_lifeitem3,-1);
10735 }
10736 else
10737 {
10738 if (rand & 1)
10739 SpawnStatic(tempstat->tilex,tempstat->tiley,stat_mp40,-1);
10740 else
10741 {
10742 SpawnStatic(tempstat->tilex,tempstat->tiley,stat_heatseeker,-1);
10743 gamestate.missiletotal ++;
10744 }
10745 LASTSTAT->flags &= ~FL_RESPAWN;
10746 }
10747 //LASTSTAT->flags &= ~FL_SHOOTABLE;
10748 LASTSTAT->flags |= FL_ABP;
10749 MakeStatActive(LASTSTAT);
10750 SD_PlaySoundRTP(SD_BONUSBARRELSND,tempstat->x,tempstat->y);
10751 }
10752 else
10753 {
10754 ExplodeStatic(tempstat);
10755 if (tempstat == touchsprite)
10756 touchsprite = NULL;
10757 }
10758 SpawnSolidStatic(tempstat);
10759 //SD_Play(SD_EXPL);
10760 break;
10761 #if (SHAREWARE == 0)
10762 case stat_mine:
10763 SpawnNewObj(tempstat->tilex,tempstat->tiley,&s_grexplosion1,inertobj);
10764 MakeActive(new);
10765 new->flags |= FL_ABP;
10766 new->whatever = tempstat;
10767 new->temp2 = damage;
10768 RemoveStatic(tempstat);
10769 break;
10770
10771 case stat_tomlarva:
10772 SD_PlaySoundRTP(SD_ACTORSQUISHSND,tempstat->x,tempstat->y);
10773 SpawnGroundExplosion(tempstat->x,tempstat->y,tempstat->z);
10774 //MISCVARS->gibgravity = GRAVITY/2;
10775 MISCVARS->fulllightgibs = true;
10776 SetGibSpeed(0x4000);
10777 SpawnSlowParticles(GUTS,30,tempstat->x, tempstat->y,tempstat->z);
10778 ResetGibSpeed();
10779 MISCVARS->fulllightgibs = false;
10780 //MISCVARS->gibgravity = -1;
10781 RemoveStatic(tempstat);
10782 break;
10783 #endif
10784
10785 case stat_lifeitem1:
10786 case stat_lifeitem2:
10787 case stat_lifeitem3:
10788 case stat_lifeitem4:
10789 SD_PlaySoundRTP(SD_ITEMBLOWSND,tempstat->x,tempstat->y);
10790 gamestate.treasurecount ++;
10791 SpawnSlowParticles(gt_sparks,10,tempstat->x,tempstat->y,tempstat->z);
10792 SpawnSolidStatic(tempstat);
10793 break;
10794
10795 default:
10796
10797 if ((tempstat->itemnumber == stat_plant) ||
10798 (tempstat->itemnumber == stat_tree))
10799 gamestate.plantcount++;
10800
10801 //tempstat->shapenum = -1;
10802 //tempstat->flags &= ~FL_SHOOTABLE;
10803 ExplodeStatic(tempstat);
10804 SpawnSolidStatic(tempstat);
10805 break;
10806 }
10807 }
10808 }
10809 }
10810
10811
DamageThing(void * thing,int damage)10812 void DamageThing (void *thing, int damage)
10813 {
10814 objtype* tempactor;
10815 statobj_t* tempstat;
10816
10817
10818 tempactor = (objtype*)thing;
10819 if (!tempactor)
10820 return;
10821
10822 if ((tempactor->which == ACTOR) && (!(tempactor->flags & FL_SHOOTABLE)))
10823 return;
10824
10825 if ((tempactor->which == ACTOR) || (tempactor->which == SPRITE))
10826 {
10827 if (tempactor->which == ACTOR)
10828 {
10829 if (tempactor->obclass == playerobj)
10830 {
10831 if ((tempactor->flags & FL_GODMODE) ||
10832 (tempactor->flags & FL_DOGMODE) ||
10833 godmode ||
10834 (gamestate.battlemode == battle_Eluder)
10835 )
10836 return;
10837 DamagePlayerActor(tempactor,damage);
10838 }
10839
10840 else
10841 {
10842 if ((tempactor->obclass == collectorobj) && (gamestate.SpawnEluder))
10843 return;
10844 if (tempactor->hitpoints <= 0)
10845 return;
10846 DamageNonPlayerActor(tempactor,damage);
10847 }
10848 }
10849 else
10850 {
10851 tempstat = (statobj_t*)thing;
10852
10853 MISCVARS->madenoise = true;
10854 if (!(tempstat->flags & FL_SHOOTABLE))
10855 return;
10856 DamageStaticObject(tempstat,damage);
10857 }
10858 }
10859 }
10860
10861
ExplodeStatic(statobj_t * tempstat)10862 void ExplodeStatic(statobj_t*tempstat)
10863 {
10864 //SpawnSolidStatic(tempstat);
10865
10866 if (tempstat->flags & FL_WOODEN)
10867 {
10868 SpawnStatic(tempstat->tilex,tempstat->tiley,stat_woodfrag,-1);
10869 if ((gamestate.BattleOptions.RespawnItems) &&
10870 (tempstat->itemnumber == stat_tntcrate)
10871 )
10872 {
10873 tempstat->linked_to = (int)(LASTSTAT);
10874 tempstat->flags |= FL_RESPAWN;
10875 }
10876
10877 }
10878 else if (tempstat->flags & FL_METALLIC)
10879 SpawnStatic(tempstat->tilex,tempstat->tiley,stat_metalfrag,-1);
10880 else
10881 SpawnStatic(tempstat->tilex,tempstat->tiley,stat_rubble,-1);
10882 LASTSTAT->flags |= (FL_ABP|FL_NONMARK);
10883 sprites[tempstat->tilex][tempstat->tiley] = NULL;
10884 MakeStatActive(LASTSTAT);
10885 SD_PlaySoundRTP(SD_ITEMBLOWSND,tempstat->x,tempstat->y);
10886
10887
10888 }
10889
10890
10891
10892
10893
EnableObject(int object)10894 void EnableObject(int object)
10895 {
10896 objtype* ob;
10897 int i,gasicon;
10898 doorobj_t*tdoor;
10899
10900 ob = (objtype*)object;
10901 ob->flags |= FL_ACTIVE;
10902 if (ob->obclass == bladeobj)
10903 {
10904 ParseMomentum(ob,dirangle8[ob->dir]);
10905 if (ob->whatever)
10906 {
10907 objtype *passenger=(objtype*)(ob->whatever);
10908
10909 passenger->momentumx += ob->momentumx;
10910 passenger->momentumy += ob->momentumy;
10911 }
10912 }
10913
10914 if (ob->obclass == gasgrateobj)
10915 {
10916 NewState(ob,&s_gas2);
10917 SD_PlaySoundRTP(SD_GASSTARTSND,ob->x,ob->y);
10918 ob->dirchoosetime = GASTICS;
10919 for(i=0;i<doornum;i++)
10920 {
10921
10922 tdoor = doorobjlist[i];
10923 gasicon = MAPSPOT(tdoor->tilex,tdoor->tiley,1);
10924 if (gasicon == GASVALUE)
10925 LinkedCloseDoor(i);
10926 }
10927
10928 MU_StoreSongPosition();
10929 MU_StartSong(song_gason);
10930 MISCVARS->GASON = 1;
10931 ob->temp3 = 105;
10932 }
10933 else if (ob->obclass == pillarobj)
10934 {
10935 ob->flags |= FL_FLIPPED;
10936 gamestate.secretcount++;
10937 }
10938 if (!(ob->flags & FL_ABP))
10939 {
10940 ob->flags |= FL_ABP;
10941 MakeActive(ob);
10942 }
10943 }
10944
DisableObject(int object)10945 void DisableObject(int object)
10946 {objtype*ob;
10947
10948 ob = (objtype*)object;
10949 ob->flags &= ~FL_ACTIVE;
10950 }
10951
10952
T_MoveColumn(objtype * ob)10953 void T_MoveColumn(objtype* ob)
10954 {int spot,index;
10955
10956
10957 if (!(ob->flags & FL_ACTIVE))
10958 return;
10959 /*
10960 switch (ob->dir)
10961 {case north:
10962 ob->momentumy = -PILLARMOM;
10963 break;
10964 case south:
10965 ob->momentumy = PILLARMOM;
10966 break;
10967 case east:
10968 ob->momentumx = PILLARMOM;
10969 break;
10970 case west:
10971 ob->momentumx = -PILLARMOM;
10972 break;
10973 }
10974
10975 */
10976 ActorMovement(ob);
10977 index = touchindices[ob->tilex][ob->tiley];
10978 if (index)
10979 TRIGGER[index-1] = 1;
10980 ob->temp1 -= PILLARMOM;
10981
10982 if ((ob->temp1 <= 0) || NOMOM)
10983 {ZEROMOM;
10984 ob->temp1 = 0x20000;
10985 ob->flags &= ~FL_ACTIVE;
10986 spot = MAPSPOT(ob->tilex,ob->tiley,1)-ICONARROWS;
10987 if ((spot >= 0) && (spot <= 7))
10988 {ob->dir = spot;
10989 if (!ob->temp2)
10990 {
10991 gamestate.secrettotal++;
10992 }
10993 else
10994 {
10995 ob->flags |= FL_ACTIVE;
10996 }
10997 ParseMomentum(ob,dirangle8[ob->dir]);
10998 }
10999 else
11000 ob->flags |= FL_DONE;
11001
11002 }
11003 }
11004
11005
11006
NextToDoor(objtype * ob)11007 boolean NextToDoor(objtype*ob)
11008 {
11009 int tilex,tiley,centerx,centery,dx,dy;
11010
11011 tilex = ob->tilex;
11012 tiley = ob->tiley;
11013
11014
11015 if (M_ISDOOR(tilex+1,tiley) || M_ISDOOR(tilex-1,tiley))
11016 {centery = (tiley << TILESHIFT) + HALFGLOBAL1;
11017 dy = abs(ob->y - centery);
11018 if (dy < 0x2000)
11019 return true;
11020 }
11021
11022 if (M_ISDOOR(tilex,tiley+1) || M_ISDOOR(tilex,tiley-1))
11023 {centerx = (tilex << TILESHIFT) + HALFGLOBAL1;
11024 dx = abs(ob->x - centerx);
11025 if (dx < 0x2000)
11026 return true;
11027 }
11028
11029 return false;
11030 }
11031
11032
11033 /*
11034 =================
11035 =
11036 = T_Use
11037 =
11038 =================
11039 */
11040
11041
T_Use(objtype * ob)11042 void T_Use(objtype*ob)
11043 {if (ob->ticcount)
11044 return;
11045
11046 switch (ob->obclass)
11047 {
11048 #if (SHAREWARE == 0)
11049 case b_darianobj:
11050 if (!DoPanicMapping())
11051 touchsprite->flags |= FL_ACTIVE;
11052 if ((!sprites[PLAYER[0]->tilex][PLAYER[0]->tiley]) && (ob->areanumber == PLAYER[0]->areanumber))
11053 {SpawnNewObj(PLAYER[0]->tilex,PLAYER[0]->tiley,&s_dspear1,spearobj);
11054 new->flags |= (FL_ABP);//|FL_INVULNERABLE);
11055 new->z = 0;
11056 MakeActive(new);
11057 }
11058 ZEROMOM;
11059 ob->flags |= FL_STUCK;
11060 SD_PlaySoundRTP(SD_DARIANUSESND,ob->x,ob->y);
11061 //NewState(ob,&s_darianspears);
11062 break;
11063 #endif
11064 default:
11065 ;
11066 }
11067
11068
11069 }
11070
11071
11072
11073
11074
11075 #define RollStart(ob,state,angle) \
11076 { \
11077 int oldspeed = ob->speed; \
11078 \
11079 ob->speed = ROLLMOMENTUM+0x200; \
11080 NewState(ob,state); \
11081 ParseMomentum(ob,angle); \
11082 ob->speed = oldspeed; \
11083 } \
11084
11085
11086
11087
11088
AvoidPlayerMissile(objtype * ob)11089 void AvoidPlayerMissile(objtype*ob)
11090 {
11091 objtype *temp;
11092 int dx,dy,dz;
11093 int magangle,angle1,rollangle1,rollangle2,dangle1,dangle2;
11094
11095 if (PLAYER0MISSILE == NULL)
11096 return;
11097
11098 if (GameRandomNumber("scott missile avoid",0) > 160)
11099 return;
11100
11101 if (ob->momentumz)
11102 return;
11103
11104 if ((ob->state->think == T_Roll) || (ob->state->think == T_Reset))
11105 return;
11106
11107 temp = PLAYER0MISSILE;
11108
11109 dx = abs(temp->x - ob->x);
11110 dy = abs(ob->y - temp->y);
11111 dz = abs(ob->z - temp->z);
11112 angle1 = AngleBetween(temp,ob);
11113 magangle = abs(temp->angle - angle1);
11114
11115 if (magangle > VANG180)
11116 magangle = ANGLES - magangle;
11117
11118
11119 if ((magangle > ANGLES/48) || (dx > 0x50000) || (dy > 0x50000) ||
11120 (dz > 32))
11121 return;
11122
11123 rollangle1 = angle1 + ANGLES/4;
11124 Fix(rollangle1);
11125 dangle1 = abs(temp->angle - rollangle1);
11126 if (dangle1 > VANG180)
11127 dangle1 = ANGLES - dangle1;
11128
11129 rollangle2 = angle1 - ANGLES/4;
11130 Fix(rollangle2);
11131 dangle2 = abs(temp->angle - rollangle2);
11132 if (dangle2 > VANG180)
11133 dangle2 = ANGLES - dangle2;
11134
11135 ob->momentumx = ob->momentumy = 0;
11136
11137 if (dangle1 > dangle2)
11138 {
11139 RollStart(ob,&s_strikerollleft1,rollangle1);
11140 }
11141 else
11142 {
11143 RollStart(ob,&s_strikerollright1,rollangle2);
11144 }
11145 ob->flags |= FL_NOFRICTION;
11146
11147 ob->target = PLAYER[0];
11148 //SelectRollDir(ob);
11149
11150
11151 }
11152
11153
11154
11155
11156 /*
11157 =================
11158 =
11159 = T_Chase
11160 =
11161 =================
11162 */
11163
T_Chase(objtype * ob)11164 void T_Chase (objtype *ob)
11165 {
11166 int dx,dy,dz,dist,chance;
11167 classtype ocl;
11168 statetype *temp;
11169 boolean doorok;
11170
11171 ocl = ob->obclass;
11172
11173
11174 if ((ocl == deathmonkobj) || (ocl == blitzguardobj))
11175 {dx = abs(PLAYER[0]->x - ob->x);
11176 dy = abs(ob->y - PLAYER[0]->y);
11177 dz = abs(ob->z - PLAYER[0]->z);
11178
11179 if ((dx < TOUCHDIST) && (dy < TOUCHDIST) && (dz < (TOUCHDIST >> 10)))
11180 {
11181 #if (SHAREWARE == 0)
11182 if (ocl == deathmonkobj)
11183 {NewState(ob,&s_dmonkshoot1);
11184 STOPACTOR(ob);
11185 return;
11186
11187 }
11188 else
11189 #endif
11190 if ((!ob->temp3) && (PLAYERSTATE[0].missileweapon != -1) &&
11191 (PLAYERSTATE[0].missileweapon < wp_godhand))
11192 {NewState(ob,&s_blitzsteal1);
11193 STOPACTOR(ob);
11194 return;
11195 }
11196 }
11197 }
11198
11199 ob->flags &= ~FL_DODGE;
11200
11201 //if (CheckLine(ob,PLAYER[0],DIRCHECK) && (ocl != roboguardobj))
11202
11203 if (!ob->ticcount)
11204 {if (CheckLine(ob,PLAYER[0],SIGHT)) // got a shot at player?
11205 {if (ocl != roboguardobj)
11206 {ob->targettilex = PLAYER[0]->x;
11207 ob->targettiley = PLAYER[0]->y;
11208 }
11209 }
11210
11211 if (CheckLine(ob,PLAYER[0],SHOOT) && (!(player->flags&FL_DYING))) // got a shot at player?
11212 {
11213 dx = abs(ob->tilex - PLAYER[0]->tilex);
11214 dy = abs(ob->tiley - PLAYER[0]->tiley);
11215 dist = (dx>dy)?(dx):(dy);
11216 if ((!dist) || (dist==1))
11217 chance = 300;
11218 else if (ocl >= b_darianobj)
11219 chance = 400/dist;
11220 else
11221 chance = 300/dist;
11222
11223 if (GameRandomNumber("T_Chase",ocl) <chance)
11224 {if ((ocl == b_heinrichobj) && (Near(ob,PLAYER[0],4)))
11225 goto cdoor;
11226
11227 ob->dir = angletodir[AngleBetween(ob,PLAYER[0])];
11228 STOPACTOR(ob);
11229 #if (SHAREWARE == 0)
11230 if ((ocl == overpatrolobj) && (!Near(ob,PLAYER[0],3)) &&
11231 (!PLAYERSTATE[0].NETCAPTURED) && (!MISCVARS->NET_IN_FLIGHT))
11232 {NewState(ob,&s_opbolo1);
11233 MISCVARS->NET_IN_FLIGHT = true;
11234 return;
11235 }
11236 #endif
11237 if ((ocl == triadenforcerobj) && (!Near(ob,PLAYER[0],3)))
11238 {NewState(ob,&s_enforcerthrow1);
11239 return;
11240 }
11241
11242 if ((temp=M_S(AIM)) != NULL)
11243 {if ((ob->flags & FL_HASAUTO) && (!ob->temp3))
11244 ob->temp3 = (GameRandomNumber("T_Chase FL_HASAUTO",ocl) % 5) + 3;
11245 ob->target = PLAYER[0];
11246 NewState(ob,temp);
11247 return;
11248 }
11249
11250 }
11251 //if ((CheckSight(ob,PLAYER[0])) && (!ob->angle))// &&
11252 //(ocl != b_heinrichobj))
11253 //ob->flags |= FL_DODGE;
11254 }
11255
11256 }
11257 cdoor:
11258 doorok = NextToDoor(ob);
11259
11260
11261 if (ob->dirchoosetime)
11262 ob->dirchoosetime--;
11263
11264 if ((ob->flags & FL_STUCK) || (!ob->dirchoosetime) || doorok)
11265 {//if (ob->flags & FL_DODGE)
11266 // SelectDodgeDir(ob);
11267 //else
11268 SelectChaseDir(ob);
11269 ob->dirchoosetime = M_CHOOSETIME(ob);
11270 }
11271
11272 else
11273 {if (NOMOM)
11274 ParseMomentum(ob,dirangle8[ob->dir]);
11275 ActorMovement(ob);
11276 }
11277 }
11278
11279
11280
SpawnMissile(objtype * shooter,classtype nobclass,int nspeed,int nangle,statetype * nstate,int offset)11281 void SpawnMissile(objtype* shooter,classtype nobclass,int nspeed,int nangle,statetype*nstate,int offset)
11282 {
11283 GetNewActor();
11284 MakeActive(new);
11285 new->which = ACTOR;
11286 new->obclass = nobclass;
11287 new->angle = nangle;
11288 new->speed = nspeed;
11289 if (shooter->obclass == playerobj)
11290 offset += FindDistance(shooter->momentumx,shooter->momentumy);
11291
11292 SetFinePosition(new,shooter->x + FixedMul(offset,costable[nangle]),
11293 shooter->y - FixedMul(offset,sintable[nangle]));
11294 SetVisiblePosition(new,new->x,new->y);
11295 //SoftError("\n missx:%d, missy:%d, speed:%d, offset:%d, angle%d, drawx:%d, drawy:%d",
11296 // new->x,new->y,nspeed,offset,nangle,new->drawx,new->drawy);
11297
11298 new->z = shooter->z;
11299 new->areanumber = shooter->areanumber;
11300 new->soundhandle = -1;
11301 if (nobclass != inertobj)
11302 {
11303 MakeLastInArea(new);
11304 if (MissileSound == true)
11305 new->soundhandle = SD_PlaySoundRTP(BAS[new->obclass].operate,new->x,new->y);
11306 }
11307
11308 if ((shooter->obclass == playerobj) || (shooter->obclass == wallopobj) ||
11309 (shooter->obclass == b_robobossobj))
11310 {
11311 Set_3D_Momenta(new,new->speed,new->angle,shooter->yzangle);
11312
11313 if (nobclass == p_drunkmissileobj)
11314 new->temp1 = new->momentumz;
11315
11316 new->z -= FixedMulShift(offset,sintable[shooter->yzangle],26);
11317 if ((shooter->obclass == playerobj) && (shooter->flags & FL_GODMODE))
11318 new->z -= 10;
11319 }
11320 else
11321 ParseMomentum(new,new->angle);
11322
11323 if (nobclass == p_drunkmissileobj)
11324 new->temp3 = VBLCOUNTER/3;
11325
11326
11327 new->flags |= (FL_NEVERMARK|FL_ABP|FL_NOFRICTION|FL_FULLLIGHT);
11328 new->whatever = shooter; // keep track of missile possession
11329 NewState(new,nstate);
11330 }
11331
11332
11333
11334 /*
11335 =================
11336 =
11337 = T_Roll
11338 =
11339 =================
11340 */
11341
11342
T_Roll(objtype * ob)11343 void T_Roll (objtype *ob)
11344 {
11345 ActorMovement(ob);
11346
11347 }
11348
11349
11350
11351
11352 /*
11353 ===============
11354 =
11355 = T_Path
11356 =
11357 ===============
11358 */
11359
T_Path(objtype * ob)11360 void T_Path (objtype *ob)
11361 {int dx,dy,dz,ocl,damage=1;
11362 objtype*temp,*ttarg,*twhat;
11363
11364
11365 ocl = ob->obclass;
11366
11367 if (((ocl == firejetobj) || (ocl == bladeobj)) && (!ob->ticcount))
11368 {
11369 if (ocl == bladeobj)
11370 {
11371 if (ob->state->condition & SF_DOWN )
11372 ob->flags &= ~FL_BLOCK;
11373 else if (ob->state->condition & SF_UP)
11374 {
11375 ob->flags |= FL_BLOCK;
11376 damage = 0;
11377 }
11378 }
11379
11380 if ((ob->state->condition & SF_SOUND) && areabyplayer[ob->areanumber])
11381 SD_PlaySoundRTP(BAS[ob->obclass].operate,ob->x,ob->y);
11382
11383 if (damage)
11384 {
11385 for(temp=firstareaactor[ob->areanumber];temp;temp=temp->nextinarea)
11386 {
11387 if (temp == ob)
11388 continue;
11389
11390 if (temp->obclass >= roboguardobj)
11391 continue;
11392
11393 //WAS
11394 ttarg = (objtype*)(temp->target);
11395 twhat = (objtype*)(temp->whatever);
11396
11397 if ((M_ISACTOR(ttarg) && (ttarg->obclass == b_robobossobj)) ||
11398 (M_ISACTOR(twhat) && (twhat->obclass == b_robobossobj))
11399 )
11400 continue;
11401
11402 if ((!(temp->flags & FL_SHOOTABLE)) || (temp->flags & FL_DYING))
11403 continue;
11404
11405 if (temp->obclass == playerobj)
11406 {
11407 if ((temp->flags & FL_GODMODE) || (temp->flags & FL_DOGMODE))
11408 continue;
11409 if ((temp->flags & FL_AV) && (ocl == firejetobj))
11410 continue;
11411 }
11412 dx = temp->x - ob->x;
11413 if (abs(dx) > 0xa000)
11414 continue;
11415 dy = temp->y - ob->y;
11416 if (abs(dy) > 0xa000)
11417 continue;
11418
11419 //if (temp->obclass == playerobj)
11420 //Collision(temp,-temp->momentumx+ob->momentumx,-temp->momentumy + ob->momentumy);
11421 dz = temp->z - ob->z;
11422 if (abs(dz) > 32)
11423 continue;
11424
11425 DamageThing(temp,EnvironmentDamage(ob));
11426 if ((ocl == firejetobj) && (temp->obclass < roboguardobj))
11427 SD_PlaySoundRTP(SD_PLAYERBURNEDSND,temp->x,temp->y);
11428
11429 if ((gamestate.violence == vl_excessive) && (temp->obclass < roboguardobj))
11430 {
11431 if (ocl == bladeobj)
11432 {
11433 SpawnParticles(temp,GUTS,1);
11434 if (temp->hitpoints <= 0)
11435 temp->flags |= FL_HBM;
11436 }
11437 else if (ocl == firejetobj)
11438 {
11439 if ((temp->hitpoints <= 0) && (temp->z == nominalheight))
11440 {
11441
11442 temp->hitpoints = 0;
11443 temp->flags |= FL_SKELETON;
11444 if (temp->obclass == playerobj)
11445 {
11446 playertype *pstate;
11447
11448 temp->flags &= ~FL_COLORED;
11449 M_LINKSTATE(temp,pstate);
11450 pstate->health = 0;
11451 pstate->weapon = -1;
11452 }
11453
11454 Collision(temp,ob,-temp->momentumx,-temp->momentumy);
11455 M_CheckPlayerKilled(temp);
11456
11457 continue;
11458 }
11459 }
11460 }
11461 //SD_PlaySoundRTP(SD_ACTORBURNEDSND,temp->x,temp->y);
11462
11463 // if ((ocl == bladeobj) || (ob->state->condition == SF_CRUSH))
11464 Collision(temp,ob,-temp->momentumx,-temp->momentumy);
11465 M_CheckPlayerKilled(temp);
11466
11467 }
11468 }
11469 }
11470
11471
11472 if (ob->dir == nodir)
11473 return;
11474
11475 if ((ocl != firejetobj) && (ocl != bladeobj) && (ocl != diskobj))
11476 {
11477 if (!ob->ticcount)
11478 {
11479 if (SightPlayer (ob))
11480 return;
11481 }
11482 else
11483 SoftError("\n ob type %s with ticcount %d in T_Path",
11484 debugstr[ob->obclass],ob->ticcount);
11485 }
11486
11487 SelectPathDir (ob);
11488 if (NOMOM)
11489 ParseMomentum(ob,dirangle8[ob->dir]);
11490 }
11491
11492
11493
EnvironmentDamage(objtype * ob)11494 int EnvironmentDamage(objtype *ob)
11495 {
11496 if (BATTLEMODE && (gamestate.BattleOptions.DangerDamage != bo_danger_normal))
11497 {
11498 return(gamestate.BattleOptions.DangerDamage);
11499 }
11500 else
11501 {
11502 int damage = 1;
11503
11504 switch(ob->obclass)
11505 {
11506 case firejetobj:
11507 case bladeobj:
11508 damage = 6;
11509 break;
11510
11511 case boulderobj:
11512 damage = 50;
11513 break;
11514
11515 case spearobj:
11516 damage = 7;
11517 break;
11518
11519 case gasgrateobj:
11520 damage = 20;
11521 break;
11522
11523 case wallfireobj:
11524 damage = ((GameRandomNumber("wallfire damage",0) >>3) + 10);
11525 break;
11526
11527 case crushcolobj:
11528 damage = 10;
11529 break;
11530 default:
11531 ;
11532 }
11533
11534 if (gamestate.difficulty < gd_hard)
11535 damage >>= 1;
11536
11537 return damage;
11538 }
11539 //SoftError("unknown environment danger");
11540
11541 }
11542
11543
11544
11545
T_AutoShootAlign(objtype * ob)11546 void T_AutoShootAlign(objtype*ob)
11547 {
11548 if (ob->dir != (dirtype)ob->temp1)
11549 ob->dir = dirorder16[ob->dir][NEXT];
11550 else
11551 NewState(ob,M_S(AIM));
11552
11553 }
11554
11555
T_AutoRealign(objtype * ob)11556 void T_AutoRealign(objtype*ob)
11557 {
11558 if (ob->dir != (dirtype)ob->targettilex)
11559 ob->dir = dirorder16[ob->dir][NEXT];
11560 else
11561 {objtype *temp;
11562
11563 NewState(ob,M_S(PATH));
11564 for(temp=firstareaactor[ob->areanumber];temp;temp=temp->nextinarea)
11565 {if (temp == ob)
11566 continue;
11567 if (temp->obclass != ob->obclass)
11568 continue;
11569 if (!temp->state->think)
11570 NewState(temp,UPDATE_STATES[PATH][temp->obclass-lowguardobj]);
11571 }
11572 }
11573 }
11574
11575
11576 /*
11577 ===============
11578 =
11579 = T_AutoPath
11580 =
11581 ===============
11582 */
11583
T_AutoPath(objtype * ob)11584 void T_AutoPath (objtype *ob)
11585 {objtype *temp;
11586
11587 // ob->temp3 holds random number of shots before resuming path
11588
11589 if (CheckLine(ob,PLAYER[0],SIGHT) && (Near(ob,PLAYER[0],4) || MISCVARS->madenoise))
11590
11591 {int dx,dy,destdir,ocl;
11592 statetype *align,*wait;
11593
11594 ocl = ob->obclass;
11595 dx = player->x - ob->x;
11596 dy = ob->y - player->y;
11597 destdir = (angletodir[atan2_appx(dx,dy)] << 1);
11598 ob->temp1 = destdir;
11599 ob->targettilex = ob->dir; //save old dir
11600 #if (SHAREWARE == 0)
11601 if (ocl == wallopobj)
11602 {//if (ob->temp3)
11603 // Error("may be writing over temp3");
11604 ob->temp3 = (GameRandomNumber("T_WallPath",0)%4) + 1;
11605 align = &s_wallalign;
11606 wait = &s_wallwait;
11607 }
11608 else
11609 #endif
11610 {align = &s_roboalign;
11611 wait = &s_robowait;
11612 }
11613
11614 NewState(ob,align);
11615 for(temp=firstareaactor[ob->areanumber];temp;temp=temp->nextinarea)
11616 {if (temp == ob)
11617 continue;
11618
11619 if (temp->obclass != ob->obclass)
11620 continue;
11621
11622 if (temp->flags & FL_DYING)
11623 continue;
11624
11625 if (CheckLine(temp,PLAYER[0],SIGHT) && (Near(temp,PLAYER[0],4) || MISCVARS->madenoise))
11626 {dx = PLAYER[0]->x - temp->x;
11627 dy = temp->y - PLAYER[0]->y;
11628 destdir = (angletodir[atan2_appx(dx,dy)] << 1);
11629
11630 temp->temp1 = destdir;
11631 temp->targettilex = temp->dir;
11632 NewState(temp,align);
11633 temp->temp3 = ob->temp3;
11634 }
11635 else
11636 NewState(temp,wait);
11637 }
11638 return;
11639 }
11640
11641 SD_PlaySoundRTP(SD_ROBOTMOVESND,ob->x,ob->y);
11642
11643 SelectPathDir(ob);
11644
11645 }
11646
11647
11648
11649
11650 /*
11651 ===============
11652 =
11653 = A_Shoot
11654 =
11655 = Try to damage the player, based on skill level and player's speed
11656 =
11657 ===============
11658 */
11659
A_Shoot(objtype * ob)11660 void A_Shoot (objtype *ob)
11661 {
11662 int dx,dy,dz,dist;
11663 int accuracy,damage,sound;
11664 objtype * target;
11665 int num;
11666 int savedangle;
11667
11668 ActorMovement(ob);
11669
11670 ob->flags |= FL_FULLLIGHT;
11671 //if (!(ob->flags & FL_SHOOTABLE))
11672 //Error("\na dead instance of %s is shooting at you",debugstr[ob->obclass]);
11673
11674 if (!ob->ticcount)
11675 {if (ob->obclass == strikeguardobj)
11676 ob->flags &= ~FL_NOFRICTION;
11677
11678 target = (objtype*)(ob->target);
11679 if (!target)
11680 Error("an instance of %s called shoot without a target\n",debugstr[ob->obclass]);
11681
11682
11683 ob->flags &= ~FL_FULLLIGHT;
11684
11685
11686 dx = (target->x - ob->x);
11687 dy = (ob->y - target->y);
11688 dz = target->z-ob->z;
11689
11690
11691 if ((ob->obclass == blitzguardobj) && (ob->temp3) &&
11692 (ob->temp3 != stat_gasmask) && (ob->temp3 != stat_asbesto) &&
11693 (ob->temp3 != stat_bulletproof) &&
11694 (gamestate.difficulty >= gd_medium) &&
11695 ((abs(dx) > 0xc000) || (abs(dy) > 0xc000))
11696 )
11697 {
11698 int i;
11699 missile_stats* newmissiledata;
11700
11701 newmissiledata = &PlayerMissileData[GetWeaponForItem(ob->temp3)];
11702
11703 // ready to annihilate this poor bastard
11704
11705 SpawnMissile(ob,newmissiledata->obclass,newmissiledata->speed,
11706 AngleBetween(ob,player), newmissiledata->state,
11707 newmissiledata->offset);
11708
11709 if (newmissiledata->obclass == p_drunkmissileobj)
11710 {
11711 for(i=0;i<4;i++)
11712 {
11713 SpawnMissile(ob,newmissiledata->obclass,newmissiledata->speed,
11714 AngleBetween(ob,player), newmissiledata->state,
11715 newmissiledata->offset);
11716 }
11717 }
11718 ob->target = NULL;
11719 ob->temp2 --;
11720 if (ob->temp2 == 0)
11721 ob->temp3 = 0;
11722 return;
11723 }
11724
11725
11726 if ((!areabyplayer[ob->areanumber]) && (target->obclass == playerobj))
11727 return;
11728
11729 //if (!CheckLine(ob,target,SHOOT)) // player is behind a wall
11730 //return;
11731
11732
11733 savedangle=ob->angle;
11734 ob->angle = atan2_appx (dx,dy);
11735 dist = FindDistance(dx,dy);
11736 ob->yzangle = FINEANGLES-atan2_appx(dist, dz<<10);
11737
11738 if ((ob->yzangle>MAXYZANGLE) && (ob->yzangle<FINEANGLES-MAXYZANGLE))
11739 ob->yzangle=MAXYZANGLE;
11740
11741 dist>>=16;
11742
11743 accuracy=(WHICHACTOR<<4)+((gamestate.difficulty) << 6);
11744
11745 num = GameRandomNumber("A_Shoot3",ob->obclass);
11746
11747 if (num<128) num=128; // Don't let accuracy fall below 50% original
11748
11749 accuracy=FixedMulShift(num,accuracy,8); // scale accuracy based off randomness
11750
11751 // check for maximum accuracy;
11752
11753 if (accuracy>255) accuracy=255;
11754
11755 if (ob->obclass==highguardobj)
11756 damage=DMG_MP40;
11757 else if (ob->obclass == triadenforcerobj)
11758 damage=DMG_MP40;
11759 else
11760 damage=DMG_ENEMYBULLETWEAPON;
11761
11762
11763 RayShoot (ob, damage, 255-accuracy);
11764
11765 ob->angle=savedangle;
11766 sound = BAS[ob->obclass].fire;
11767 SD_PlaySoundRTP(sound,ob->x,ob->y);
11768 MISCVARS->madenoise = true;
11769 if ((!(ob->flags& FL_HASAUTO)) || (!ob->temp3))
11770 ob->target = NULL;
11771 }
11772 }
11773
11774
11775
11776
A_Repeat(objtype * ob)11777 void A_Repeat(objtype*ob)
11778 {
11779 ActorMovement(ob);
11780
11781 if (!ob->ticcount)
11782 {ob->temp3 --;
11783 if (ob->temp3 <= 0)
11784 NewState(ob,M_S(CHASE));
11785 }
11786
11787 }
11788
11789
A_MissileWeapon(objtype * ob)11790 void A_MissileWeapon(objtype *ob)
11791 {
11792 int sound,nspeed,noffset,zoffset;
11793
11794 #if (SHAREWARE == 0)
11795 int oldyzangle;
11796 #endif
11797 classtype nobclass;
11798 statetype*nstate;
11799
11800
11801 if ((ob->obclass == wallopobj) || (ob->obclass == roboguardobj));
11802 //SelectPathDir(ob);
11803 else
11804 ActorMovement(ob);
11805
11806 if (!ob->ticcount)
11807 {
11808 #if (SHAREWARE == 0)
11809 if ((ob->obclass == wallopobj) && (!ob->temp3))
11810 {
11811 NewState(ob,&s_wallrestore);
11812 return;
11813 }
11814 #endif
11815 if ((ob->obclass == b_darianobj) && (!CheckLine(ob,PLAYER[0],SHOOT)))
11816 {NewState(ob,M_S(CHASE));
11817 return;
11818 }
11819 // Move sounds, flags into switch cases
11820
11821 sound = BAS[ob->obclass].fire;
11822 nspeed = 0x4000;
11823 noffset = 0x8000;
11824 zoffset = 0;
11825 switch (ob->obclass)
11826 {
11827
11828 case triadenforcerobj:
11829 nobclass = grenadeobj;
11830 nstate= &s_grenade1;
11831 sound++;
11832 break;
11833
11834
11835 case roboguardobj:
11836 nobclass = shurikenobj;
11837 nspeed = 0x2000;
11838 noffset = 0x10000;
11839 nstate = &s_robogrdshuriken1;
11840 break;
11841
11842 /*
11843 case b_darkmonkobj:
11844 nobclass = dmfballobj;
11845 nstate = &s_dmfball1;
11846 break;
11847 */
11848 /*
11849 case b_robobossobj:
11850 nobclass = bigshurikenobj;
11851 nstate = &s_oshuriken1;
11852 break;
11853 */
11854 #if (SHAREWARE == 0)
11855 case b_darianobj:
11856 nobclass = missileobj;
11857 //nspeed = 0x100;
11858 //noffset = 0x18000;
11859 nstate = &s_missile1;
11860 zoffset = -20;
11861 break;
11862
11863
11864 case dfiremonkobj:
11865 nobclass = fireballobj;
11866 nstate = &s_monkfire1;
11867 break;
11868
11869
11870 case overpatrolobj:
11871 nobclass = netobj;
11872 nstate = &s_bolocast1;
11873 sound ++;
11874 break;
11875
11876
11877 case wallopobj:
11878 {int dx,dy,dz,xydist;
11879
11880 ob->temp2 ^= 1; // increment numfired
11881 ob->temp3 --; // decrement random fire no.
11882
11883
11884 dx = PLAYER[0]->x-ob->x;
11885 dy = ob->y-PLAYER[0]->y;
11886 if (GameRandomNumber("bcraft shoot up/down",0) < 128)
11887 dz = 10;
11888 else
11889 dz = -10;
11890 xydist = FindDistance(dx,dy);
11891 oldyzangle = ob->yzangle;
11892 ob->yzangle = atan2_appx(xydist,dz<<10);
11893 if (ob->temp2)
11894 {nobclass = missileobj;
11895 nstate = &s_missile1;
11896 }
11897 else
11898 {nobclass = bigshurikenobj;
11899 nstate = &s_bstar1;
11900 }
11901 }
11902 break;
11903 #endif
11904 default:
11905 ;
11906 }
11907
11908 SpawnMissile(ob,nobclass,nspeed,AngleBetween(ob,PLAYER[0]),nstate,noffset);
11909 new->z += zoffset;
11910 SD_PlaySoundRTP(sound,ob->x,ob->y);
11911 MISCVARS->madenoise = true;
11912 if (ob->obclass == triadenforcerobj)
11913 {//new->flags |= (FL_SHOOTABLE);
11914 new->temp1 = 0x50000;
11915 }
11916 #if (SHAREWARE == 0)
11917 else if (ob->obclass == wallopobj)
11918 ob->yzangle = oldyzangle;
11919 #endif
11920
11921
11922 }
11923 }
11924
11925
A_Wallfire(objtype * ob)11926 void A_Wallfire(objtype *ob)
11927 {
11928 if (!(ob->flags & FL_ACTIVE))
11929 return;
11930
11931 if (!ob->ticcount)
11932 {SpawnMissile(ob,wallfireobj,0x4000,ob->angle,&s_crossfire1,0xa000);
11933 if (areabyplayer[ob->areanumber])
11934 SD_PlaySoundRTP(SD_FIRECHUTESND,ob->x,ob->y);
11935 new->dir = angletodir[new->angle];
11936 new->z = nominalheight;
11937 }
11938
11939 }
11940
11941
T_Reset(objtype * ob)11942 void T_Reset(objtype *ob)
11943 {
11944 ActorMovement(ob);
11945
11946 if (ob->ticcount)
11947 return;
11948
11949 ob->momentumx = ob->momentumy = ob->dirchoosetime = 0;
11950 ob->flags &= ~FL_NOFRICTION;
11951
11952
11953
11954 }
11955
SelectRollDir(objtype * ob)11956 void SelectRollDir(objtype *ob)
11957 {int angle,tryx,tryy;
11958
11959
11960 if (ob->state == &s_strikerollright1)
11961 angle = AngleBetween(ob,PLAYER[0]) + ANGLES/4;
11962 else
11963 angle = AngleBetween(ob,PLAYER[0]) - ANGLES/4;
11964
11965 Fix(angle);
11966 tryx = ob->x + FixedMul(0x20000l,costable[angle]);
11967 tryy = ob->y - FixedMul(0x20000l,sintable[angle]);
11968 ZEROMOM;
11969 if (QuickSpaceCheck(ob,tryx,tryy))
11970 {int oldspeed;
11971
11972 oldspeed = ob->speed;
11973 ob->speed = ROLLMOMENTUM;
11974 ParseMomentum(ob,angle);
11975 ob->speed = oldspeed;
11976 ob->dirchoosetime = 5;
11977 ob->flags |= FL_NOFRICTION;
11978 }
11979 else
11980 ob->dirchoosetime = 0;
11981
11982
11983 }
11984
11985
SelectDodgeDir(objtype * ob)11986 void SelectDodgeDir (objtype *ob)
11987 {
11988 int dx,dy,i,tx,ty;
11989 unsigned absdx,absdy;
11990 dirtype dirtry[5];
11991 dirtype turnaround,tdir,olddir;
11992
11993
11994 olddir = ob->dir;
11995 if (ob->flags & FL_FIRSTATTACK)
11996 {
11997 //
11998 // turning around is only ok the very first time after noticing the
11999 // player
12000 //
12001 turnaround = nodir;
12002 ob->flags &= ~FL_FIRSTATTACK;
12003 }
12004 else
12005 turnaround=opposite[ob->dir];
12006
12007
12008 if (ob->targettilex || ob->targettiley)
12009 {tx = ob->targettilex;
12010 ty = ob->targettiley;
12011 dx= tx - ob->x;
12012 dy= ty - ob->y;
12013 if ( ((dx < MINACTORDIST) && (dx > -MINACTORDIST)) &&
12014 ((dy < MINACTORDIST) && (dy > -MINACTORDIST)))
12015 {dx= PLAYER[0]->x-ob->x;
12016 dy= PLAYER[0]->y-ob->y;
12017 }
12018 }
12019 else
12020 {dx= PLAYER[0]->x-ob->x;
12021 dy= PLAYER[0]->y-ob->y;
12022 }
12023
12024
12025
12026 //
12027 // arange 5 direction choices in order of preference
12028 // the four cardinal directions plus the diagonal straight towards
12029 // the player
12030 //
12031 if (dx>ACTORSIZE)
12032 {
12033 dirtry[1]= east;
12034 dirtry[3]= west;
12035 }
12036 else if (dx < -ACTORSIZE)
12037 {
12038 dirtry[1]= west;
12039 dirtry[3]= east;
12040 }
12041
12042 if (dy>ACTORSIZE)
12043 {
12044 dirtry[2]= south; // south
12045 dirtry[4]= north; // north
12046 }
12047 else if (dy <-ACTORSIZE)
12048 {
12049 dirtry[2]= north; // north
12050 dirtry[4]= south; // south
12051 }
12052
12053 //
12054 // randomize a bit for dodging
12055 //
12056 absdx = abs(dx);
12057 absdy = abs(dy);
12058
12059 if (absdx > absdy)
12060 {
12061 tdir = dirtry[1];
12062 dirtry[1] = dirtry[2];
12063 dirtry[2] = tdir;
12064 tdir = dirtry[3];
12065 dirtry[3] = dirtry[4];
12066 dirtry[4] = tdir;
12067 }
12068
12069 if (GameRandomNumber("SelectDogeDir",ob->obclass) < 128)
12070 {
12071 tdir = dirtry[1];
12072 dirtry[1] = dirtry[2];
12073 dirtry[2] = tdir;
12074 tdir = dirtry[3];
12075 dirtry[3] = dirtry[4];
12076 dirtry[4] = tdir;
12077 }
12078
12079 dirtry[0] = diagonal [dirtry[1]] [dirtry[2]];
12080
12081 ZEROMOM;
12082
12083 for (i=0;i<5;i++)
12084 {if ((dirtry[i] == nodir) || (dirdiff[dirtry[i]][olddir] > 1))
12085 continue;
12086
12087 M_CHECKDIR(ob,dirtry[i]);
12088 }
12089
12090 //
12091 // turn around only as a last resort
12092 //
12093 // for(tdir = east;tdir<=southeast;tdir++)
12094 //if (tdir != turnaround)
12095 // M_CHECKDIR(ob,tdir);
12096
12097 if (turnaround != nodir)
12098 M_CHECKDIR(ob,turnaround);
12099
12100 }
12101
12102
12103
12104
12105 #define TryAbruptProximalDirections(trydir) \
12106 { \
12107 next = dirorder[trydir][NEXT]; \
12108 prev = dirorder[trydir][PREV]; \
12109 if (GameRandomNumber("actor choose dir",0) < 128) \
12110 { \
12111 dirtype temp = next; \
12112 \
12113 next = prev; \
12114 prev = temp; \
12115 } \
12116 \
12117 if (!dirtried[next]) \
12118 { \
12119 M_CHECKDIR(ob,next); \
12120 dirtried[next]=1; \
12121 } \
12122 \
12123 if (!dirtried[prev]) \
12124 { \
12125 M_CHECKDIR(ob,prev); \
12126 dirtried[prev]=1; \
12127 } \
12128 \
12129 }
12130
12131
12132 #define TrySmoothProximalDirections(trydir) \
12133 { \
12134 \
12135 if (((trydir == olddir) || (dirdiff[trydir][olddir] < 2)) && \
12136 (!dirtried[trydir])) \
12137 { \
12138 M_CHECKDIR(ob,trydir); \
12139 dirtried[trydir] = 1; \
12140 } \
12141 next = dirorder[olddir][NEXT]; \
12142 prev = dirorder[olddir][PREV]; \
12143 \
12144 if (dirdiff[trydir][next] <= dirdiff[trydir][prev]) \
12145 { \
12146 start = next; \
12147 whichway = NEXT; \
12148 } \
12149 else \
12150 { \
12151 start = prev; \
12152 whichway = PREV; \
12153 } \
12154 \
12155 for (tdir= start; tdir != dirorder[trydir][whichway]; \
12156 tdir = dirorder[tdir][whichway] \
12157 ) \
12158 { \
12159 if (dirtried[tdir]) \
12160 continue; \
12161 M_CHECKDIR(ob,tdir); \
12162 dirtried[tdir]=1; \
12163 } \
12164 \
12165 }
12166
12167
12168
12169 #define ChasePlayer(ob) \
12170 { \
12171 dx= player->x-ob->x; \
12172 dy= ob->y-player->y; \
12173 if ((abs(dx) < 0xb000) && (abs(dy) < 0xb000)) \
12174 return; \
12175 dummy.x = player->x; \
12176 dummy.y = player->y; \
12177 }
12178
12179
SelectChaseDir(objtype * ob)12180 void SelectChaseDir (objtype *ob)
12181 {
12182 int dx,dy,whichway,tx,ty,actrad,visible,
12183 realdiff;
12184 dirtype dtry1,dtry2,tdir,olddir,next,prev,start,straight;
12185 tpoint dummy;
12186 byte dirtried[9] = {0};
12187
12188 olddir=ob->dir;
12189 visible = CheckLine(ob,PLAYER[0],SIGHT);
12190
12191 /*
12192 if (ob->flags & FL_FIRSTATTACK)
12193 {
12194 //
12195 // turning around is only ok the very first time after noticing the
12196 // player
12197 //
12198 turnaround = opposite[ob->dir];
12199 ob->flags &= ~FL_FIRSTATTACK;
12200 }
12201 else
12202 turnaround=nodir;
12203 */
12204 dummy.which = ACTOR;
12205 dummy.z = ob->z;
12206 if (ob->targettilex || ob->targettiley)
12207 {
12208 tx = ob->targettilex;
12209 ty = ob->targettiley;
12210 dx= tx - ob->x;
12211 dy= ob->y - ty;
12212 dummy.x = tx;
12213 dummy.y = ty;
12214 if ((abs(dx) < 0x2000) && (abs(dy) < 0x2000))
12215 ChasePlayer(ob);
12216 }
12217 else
12218 ChasePlayer(ob);
12219
12220 //if ((abs(dx) < 0x10000) && (abs(dy) < 0x10000))
12221 //return;
12222 straight = angletodir[atan2_appx(dx,dy)];
12223 realdiff = dirdiff[straight][ob->dir];
12224 ZEROMOM;
12225
12226 //insertion 20
12227
12228 actrad = ACTORSIZE;
12229 dtry1=nodir;
12230 dtry2=nodir;
12231
12232 if (dx> actrad)
12233 dtry1= east;
12234 else if (dx< -actrad)
12235 dtry1= west;
12236 if (dy> actrad)
12237 dtry2=north;
12238 else if (dy < -actrad)
12239 dtry2= south;
12240
12241
12242 if (abs(dy)>abs(dx))
12243 {
12244 tdir=dtry1;
12245 dtry1=dtry2;
12246 dtry2=tdir;
12247 }
12248
12249 if (GameRandomNumber("chase minor",0) < 80)
12250 {
12251 tdir=dtry1;
12252 dtry1=dtry2;
12253 dtry2=tdir;
12254 }
12255
12256 ZEROMOM;
12257
12258 if ((!visible) || (realdiff > 2)) // don't worry about abrupt or unrealistic turns if player
12259 // can't see guards
12260 {
12261 M_CHECKDIR(ob,straight);
12262 dirtried[straight]=1;
12263 next = dirorder[straight][NEXT];
12264 prev = dirorder[straight][PREV];
12265
12266 if ((dtry1 != nodir) && (dtry1 != straight))
12267 {
12268 M_CHECKDIR(ob,dtry1);
12269 dirtried[dtry1]=1;
12270 }
12271
12272
12273 if ((dtry2 != nodir) && (!dirtried[dtry2]))
12274 {
12275 M_CHECKDIR(ob,dtry2);
12276 dirtried[dtry2]=1;
12277 }
12278
12279 if (dtry1 != nodir)
12280 TryAbruptProximalDirections(dtry1);
12281
12282 if (dtry2 != nodir)
12283 TryAbruptProximalDirections(dtry2);
12284 }
12285
12286 else
12287 {
12288 if (realdiff < 2)
12289 {
12290 M_CHECKDIR(ob,straight);
12291 dirtried[straight]=1;
12292 }
12293
12294 if (dtry1 != nodir)
12295 TrySmoothProximalDirections(dtry1);
12296
12297 if (dtry2 != nodir)
12298 TrySmoothProximalDirections(dtry2);
12299
12300 }
12301
12302 if ((dtry1!=nodir) || (dtry2!=nodir))
12303 {
12304 if (GameRandomNumber("actor choose dir",0) < 128)
12305 whichway = NEXT;
12306 else
12307 whichway = PREV;
12308
12309 for(tdir = dirorder[olddir][whichway];tdir != olddir;tdir = dirorder[tdir][whichway])
12310 {
12311 if (dirtried[tdir])
12312 continue;
12313 M_CHECKDIR(ob,tdir);
12314 }
12315 }
12316
12317 ob->dir = olddir;
12318 }
12319
12320
12321
Near(objtype * ob,void * what,int distance)12322 int Near(objtype *ob,void* what,int distance)
12323
12324 {
12325 objtype *aw;
12326
12327 aw = (objtype*) what;
12328
12329 if (FindDistance((aw->x - ob->x),(aw->y - ob->y)) <= (distance<<16))
12330 return 1;
12331 return 0;
12332
12333 }
12334
12335
12336
12337 /*
12338 ===============
12339 =
12340 = SelectPathDir
12341 =
12342 ===============
12343 */
12344
SelectPathDir(objtype * ob)12345 void SelectPathDir (objtype *ob)
12346 {
12347 int spot,centerx,centery,dx,dy,set,done,radius,ocl;
12348
12349 ocl = ob->obclass;
12350
12351
12352 if ((ocl == bladeobj) && (!(ob->flags & FL_ACTIVE)))
12353 return;
12354
12355 spot = MAPSPOT(ob->tilex,ob->tiley,1)-ICONARROWS;
12356 set = ((ocl == wallopobj) || (ocl == roboguardobj));
12357 done = (((!set) && (ob->dir == (dirtype)spot)) ||
12358 (set && (ob->dir == (dirtype)(spot<<1))));
12359
12360 if ((spot >= 0) && (spot<= 7) && (!done))
12361 {
12362 centerx= (ob->tilex << 16) + HALFGLOBAL1;
12363 centery= (ob->tiley << 16) + HALFGLOBAL1;
12364 dx = abs(centerx - ob->x);
12365 dy = abs(centery - ob->y);
12366 //radius = (ob->speed > 0x4800)?(0xb000):(0x4000);
12367 radius = 0x4000;
12368
12369 if ((dx < radius) && (dy < radius))
12370 // new direction
12371 {
12372 ZEROMOM;
12373 if ((ocl == wallopobj) || (ocl == roboguardobj))
12374 {
12375 ob->dir = spot<<1;
12376 ParseMomentum(ob,dirangle16[ob->dir]);
12377 }
12378 else
12379 {
12380 ob->dir = spot;
12381 ParseMomentum(ob,dirangle8[ob->dir]);
12382 }
12383 dx = centerx - ob->x;
12384 dy = centery - ob->y;
12385 SetFinePosition(ob,centerx,centery);
12386 SetVisiblePosition(ob,centerx,centery);
12387 /*
12388 if (((ocl == bladeobj) || (ocl == diskobj)) && ob->whatever)
12389 {objtype*passenger = (objtype*)(ob->whatever);
12390
12391 passenger->x += dx;
12392 passenger->y += dy;
12393 passenger->drawx = passenger->x;
12394 passenger->drawy = passenger->y;
12395 passenger->tilex = passenger->x >> 16;
12396 passenger->tiley = passenger->y >> 16;
12397 }*/
12398 // if (ob==SNAKEHEAD)
12399 // Debug("\n path changed at %d, %d",
12400 // ob->tilex,ob->tiley);
12401 }
12402 }
12403 if (NOMOM)
12404 {
12405 if ((ocl == wallopobj) || (ocl == roboguardobj))
12406 ParseMomentum(ob,dirangle16[ob->dir]);
12407 else
12408 ParseMomentum(ob,dirangle8[ob->dir]);
12409 }
12410
12411 //if ((ob->obclass == firejetobj) || (ob->obclass == bladeobj))
12412 //MoveActor(ob);
12413 //else
12414 ActorMovement(ob);
12415
12416 }
12417
12418
12419
12420 /*
12421 ================
12422 =
12423 = CheckSight
12424 =
12425 = Checks a straight line between player and current object
12426 =
12427 = If the sight is ok, check alertness and angle to see if they notice
12428 =
12429 = returns true if the player has been spoted
12430 =
12431 ================
12432 */
12433
12434
CheckSight(objtype * ob,void * atwhat)12435 boolean CheckSight (objtype *ob,void *atwhat)
12436 {
12437 long deltax,deltay;
12438 objtype * what;
12439 //
12440 // don't bother tracing a line if the area isn't connected to the player's
12441 //
12442 if (!areabyplayer[ob->areanumber])
12443 return false;
12444
12445 //
12446 // if the player is real close, sight is automatic
12447 //
12448 what = (objtype*)atwhat;
12449 deltax = what->x - ob->x;
12450 deltay = what->y - ob->y;
12451
12452 if ((deltax > -MINSIGHT) && (deltax < MINSIGHT) &&
12453 (deltay > -MINSIGHT) && (deltay < MINSIGHT))
12454 return true;
12455
12456 //
12457 // see if they are looking in the right direction
12458 //
12459 switch (ob->dir)
12460 {
12461 case north:
12462 if (deltay > 0)
12463 return false;
12464 break;
12465
12466 case east:
12467 if (deltax < 0)
12468 return false;
12469 break;
12470
12471 case south:
12472 if (deltay < 0)
12473 return false;
12474 break;
12475
12476 case west:
12477 if (deltax > 0)
12478 return false;
12479 break;
12480 default:
12481 ;
12482 }
12483
12484 //
12485 // trace a line to check for blocking tiles (corners)
12486 //
12487 return CheckLine (ob,atwhat,SIGHT);
12488
12489 }
12490
12491
12492
ActivateEnemy(objtype * ob)12493 void ActivateEnemy(objtype*ob)
12494 {statetype *temp;
12495
12496
12497 ob->flags |= (FL_ATTACKMODE|FL_FIRSTATTACK);
12498 if (ob->obclass == roboguardobj)
12499 return;
12500
12501 if (ob->temp3 == SNEAKY)
12502 { NewState(ob,&s_sneakyrise1);
12503 ob->temp3=0;
12504 }
12505 else if ((temp = M_S(CHASE)) != NULL)
12506 NewState(ob,temp);
12507 /*
12508 ob->speed = ENEMYRUNSPEED;
12509 */
12510 if (ob->obclass == b_heinrichobj)
12511 ob->speed = 7*ob->speed/2;
12512 else if (ob->obclass == b_darianobj)
12513 ob->speed = 3*SPDPATROL;
12514 if (ob->door_to_open != -1)
12515 ob->door_to_open = -1; // ignore the door opening command
12516 ob->dirchoosetime = 0;
12517
12518
12519 }
12520
12521
12522 /*
12523 ===============
12524 =
12525 = FirstSighting
12526 =
12527 = Puts an actor into attack mode and possibly reverses the direction
12528 = if the player is behind it
12529 =
12530 ===============
12531 */
12532
FirstSighting(objtype * ob)12533 void FirstSighting (objtype *ob)
12534 {
12535 statetype *temp;
12536 int sound;
12537
12538 if (ob->temp3 == SNEAKY)
12539 {
12540 NewState(ob,&s_sneakyrise1);
12541 ob->temp3=0;
12542 if (ob->shapeoffset==0)
12543 SD_PlaySoundRTP(SD_SNEAKYSPRINGMSND,ob->x,ob->y);
12544 else
12545 SD_PlaySoundRTP(SD_SNEAKYSPRINGFSND,ob->x,ob->y);
12546 }
12547 else if ((temp = M_S(CHASE)) != NULL)
12548 {
12549 int rand;
12550
12551 NewState(ob,temp);
12552 sound = BAS[ob->obclass].see;
12553 rand = GameRandomNumber("FirstSighting low",0);
12554 if ((ob->obclass > lowguardobj) && (ob->obclass <= blitzguardobj) && (rand < 128)) //hack for alternate
12555 sound++;
12556 //if ((ob->obclass == lowguardobj) && (rand < 80))
12557 //sound ++;
12558 else if (ob->obclass == lowguardobj)
12559 {if (rand < 128)
12560 {if ((PLAYERSTATE[0].player == 1) || (PLAYERSTATE[0].player == 3))
12561 sound++;
12562 }
12563 else
12564 sound += 2;
12565
12566 if (ob->shapeoffset)
12567 sound += 4;
12568
12569 }
12570 SD_PlaySoundRTP(sound,ob->x,ob->y);
12571 if ((ob->obclass>=b_darianobj) && (ob->obclass<=b_darksnakeobj))
12572 {
12573 MU_StartSong(song_bosssee);
12574 }
12575 }
12576
12577 /*
12578 ob->speed = ENEMYRUNSPEED;*/
12579 if (ob->obclass == b_heinrichobj)
12580 ob->speed = 7*ob->speed/2;
12581 else if (ob->obclass == b_darianobj)
12582 ob->speed = 3*SPDPATROL;
12583 if (ob->door_to_open != -1)
12584 ob->door_to_open = -1; // ignore the door opening command
12585 ob->dirchoosetime = 0;
12586 ob->flags |= (FL_ATTACKMODE|FL_FIRSTATTACK);
12587
12588 }
12589
12590
12591 /*
12592 ===============
12593 =
12594 = SightPlayer
12595 =
12596 = Called by actors that ARE NOT chasing the player. If the player
12597 = is detected (by sight, noise, or proximity), the actor is put into
12598 = it's combat frame and true is returned.
12599 =
12600 = Incorporates a random reaction delay
12601 =
12602 ===============
12603 */
12604
SightPlayer(objtype * ob)12605 boolean SightPlayer (objtype *ob)
12606 {
12607 //if (ob->flags & FL_ATTACKMODE)
12608 //Error ("An instance of %s in ATTACKMODE called SightPlayer!",debugstr[ob->obclass]);
12609
12610 if (!areabyplayer[ob->areanumber])
12611 return false;
12612
12613 if (ob->obclass == b_robobossobj)
12614 {
12615 if (!(CheckSight(ob,player) || Near(ob,player,6)))
12616 return false;
12617
12618 }
12619
12620
12621 else if (ob->flags & FL_AMBUSH)
12622 {
12623 if (!CheckSight (ob,PLAYER[0]))
12624 {
12625 //SoftError("\n failed from ambush in SightPlayer");
12626 return false;
12627 }
12628 ob->flags &= ~FL_AMBUSH;
12629 }
12630 else
12631 {
12632 if (ob->temp3 == SNEAKY)
12633 {
12634 if (!Near(ob,PLAYER[0],2))
12635 return false;
12636 }
12637 else if (!((MISCVARS->madenoise) ||
12638 (CheckSight (ob,player)) ||
12639 (Near(ob,player,4))
12640 )
12641 )
12642 {
12643 //SoftError("\n failed from SightPlayer");
12644 return false;
12645 }
12646 }
12647
12648 FirstSighting (ob);
12649
12650 return true;
12651 }
12652
12653
12654 /*
12655 =====================
12656 =
12657 = CheckLine
12658 =
12659 = Returns true if a straight line between two obs is unobstructed
12660 =
12661 =====================
12662 */
12663
12664
12665
CheckLine(void * from,void * to,int condition)12666 boolean CheckLine (void *from, void *to, int condition)
12667 {
12668 objtype *tempactor,*ob,*orig;
12669 statobj_t *checksprite;
12670 int destx,desty,destz;
12671 int desttilex,desttiley;
12672 int snx,sny;
12673 int incr[2];
12674 int thedir[2];
12675 int cnt;
12676 int grid[2];
12677 int index;
12678 int vx,vy;
12679 int yzangle;
12680 int value;
12681 int dx,dy,dz;
12682 int xydist;
12683 int otx,oty,count=0;
12684
12685
12686
12687 ob = (objtype*)to;
12688 orig = (objtype*)from;
12689 if (ob->which == SPRITE)
12690 {
12691 destx = ((statobj_t*)to)->x;
12692 desty = ((statobj_t*)to)->y;
12693 destz = ((statobj_t*)to)->z;
12694 }
12695 else
12696 {
12697 destx = ob->x;
12698 desty = ob->y;
12699 destz = ob->z;
12700 }
12701
12702 desttilex=destx>>16;
12703 desttiley=desty>>16;
12704
12705 if ((desttilex == orig->tilex) && (desttiley == orig->tiley))
12706 return true;
12707
12708
12709 dx=destx-orig->x;
12710 dy=orig->y-desty;
12711 dz=orig->z-destz;
12712 xydist = FindDistance(dx,dy);
12713 yzangle = atan2_appx(xydist,dz<<10);
12714
12715 if ((yzangle>MAXYZANGLE) && (yzangle<FINEANGLES-MAXYZANGLE))
12716 {
12717 #if (0)
12718 Debug("\nfailed from yzangle");
12719 #endif
12720 return false;
12721 }
12722
12723 //angle = atan2_appx(dx,dy);
12724 otx = orig->x >> TILESHIFT;
12725 oty = orig->y >> TILESHIFT;
12726
12727 if (xydist==0)
12728 {
12729 /*
12730 SoftError("\nCheckLine:xydist=0");
12731 if (orig->which == ACTOR)
12732 SoftError("shooter: %s",debugstr[orig->obclass]);
12733 if (ob->which == ACTOR)
12734 SoftError("target: %s",debugstr[ob->obclass]);*/
12735 vy=-dy;
12736 vx=dx;
12737 }
12738 else
12739 {
12740 vy = -FixedDiv2(dy,xydist);
12741 vx = FixedDiv2(dx,xydist);
12742 }
12743 snx=orig->x&0xffff;
12744 sny=orig->y&0xffff;
12745
12746 grid[0]=otx;
12747 grid[1]=oty;
12748
12749 if (vx>0)
12750 {
12751 thedir[0]=1;
12752 snx^=0xffff;
12753 incr[1]=-vx;
12754 }
12755 else
12756 {
12757 thedir[0]=-1;
12758 incr[1]=vx;
12759 }
12760 if (vy>0)
12761 {
12762 thedir[1]=1;
12763 sny^=0xffff;
12764 incr[0]=vy;
12765 }
12766 else
12767 {
12768 thedir[1]=-1;
12769 incr[0]=-vy;
12770 }
12771 cnt=FixedMul(snx,incr[0])+FixedMul(sny,incr[1]);
12772
12773
12774 do
12775 {count ++;
12776 /*
12777 if (count > 1000)
12778 Error("possible infinite loop in CheckLine");
12779 if ((grid[0] < 0) || (grid[0] > (MAPSIZE-1)) ||
12780 (grid[1] < 0) || (grid[1] > (MAPSIZE-1)))
12781 Error("out of bounds in check line, grid[0] = %d, grid[1] = %d",grid[0],grid[1]);
12782 */
12783 if ((grid[0]==desttilex) && (grid[1]==desttiley))
12784 return true;
12785 tempactor = (objtype*)actorat[grid[0]][grid[1]];
12786 value = tilemap[grid[0]][grid[1]];
12787 checksprite = sprites[grid[0]][grid[1]];
12788 if (value)
12789 {
12790 if (value&0x8000)
12791 {
12792 if (!(value&0x4000))
12793 {
12794 doorobj_t*dptr = doorobjlist[value&0x3ff];
12795
12796 if (dptr->position < 0x8000)
12797 {
12798
12799 int x = (grid[0] << 16) + 0x8000;
12800 int y = (grid[1] << 16) + 0x8000;
12801
12802 if (dptr->vertical)
12803 {
12804 if (abs(dx) > abs(x-orig->x))
12805 return false;
12806 }
12807 else
12808 {
12809 if (abs(dy) > abs(orig->y-y))
12810 return false;
12811 }
12812 }
12813 }
12814 else
12815 {
12816 if (condition == SHOOT)
12817 {
12818 if ( maskobjlist[value&0x3ff]->flags & MW_SHOOTABLE )
12819 {
12820 #if (0)
12821 SoftError("\nfailed from shootable mask");
12822 #endif
12823 return false;
12824 }
12825 else if ( maskobjlist[value&0x3ff]->flags & MW_WEAPONBLOCKING )
12826 {
12827 #if (0)
12828 SoftError("\nfailed from block mask");
12829 #endif
12830 return false;
12831 }
12832 }
12833 else if ((condition == MISSILE) &&
12834 ( maskobjlist[value&0x3ff]->flags & MW_BLOCKING )
12835 )
12836 return false;
12837 }
12838 }
12839 else
12840 {
12841 #if (0)
12842 SoftError("\n obx %d, oby %d, origx %d, origy %d"
12843 "\n xydist %d, vx %d, vy %d",ob->x,ob->y,orig->x,
12844 orig->y,xydist,vx,vy);
12845
12846 SoftError("\nfailed from normal wall");
12847 #endif
12848 return false;
12849 }
12850 }
12851 if (condition == SHOOT)
12852 {
12853 if (tempactor && (tempactor->which == ACTOR) &&
12854 (tempactor->flags & FL_BLOCK) && (tempactor != orig) &&
12855 (tempactor != ob)) //&&
12856 // (InRange(orig,tempactor,
12857 // FindDistance(orig->x-tempactor->x,orig->y-tempactor->y) )
12858 // ==true) )
12859 {
12860 #if (0)
12861 SoftError("\nfailed from actor");
12862 #endif
12863 return false;
12864 }
12865 }
12866
12867 if (checksprite && (checksprite->flags & FL_BLOCK) && (condition == SHOOT) &&
12868 ((void *)checksprite != to) &&
12869 (checksprite->itemnumber!=stat_disk) &&
12870 (InRange(orig,(objtype *)checksprite,
12871 FindDistance(orig->x-checksprite->x,orig->y-checksprite->y) )
12872 ==true) )
12873
12874 {
12875 #if (0)
12876 SoftError("\nfailed from sprite");
12877 #endif
12878 return false;
12879 }
12880
12881 if (tempactor && (tempactor->which == PWALL))
12882 {
12883 #if (0)
12884 SoftError("\nfailed from pushwall");
12885 #endif
12886 return false;
12887 }
12888 index=(cnt>=0);
12889 cnt+=incr[index];
12890 grid[index]+=thedir[index];
12891 }
12892 while (1);
12893 }
12894
12895
12896
12897
12898
12899
12900
12901 /*
12902 =====================
12903 =
12904 = ShootActor
12905 =
12906 = Shoot an actor.
12907 =
12908 =====================
12909 */
ShootActor(objtype * shooter,objtype * target,int damage,int accuracy,int angle)12910 void ShootActor(objtype * shooter, objtype * target, int damage, int accuracy, int angle)
12911 {
12912 int dx,dy,dist;
12913 int newmomx, newmomy;
12914 int tcl;
12915
12916
12917 if (target->flags & FL_DYING)
12918 return;
12919
12920 dx = abs(shooter->x - target->x);
12921 dy = abs(shooter->y - target->y);
12922 dist = FindDistance(dx,dy)>>16;
12923
12924 tcl=target->obclass;
12925
12926 if (tcl==playerobj)
12927 {
12928 target->target=shooter;
12929 if (target->flags&FL_BPV)
12930 {
12931 playertype *pstate;
12932
12933 M_LINKSTATE(target,pstate);
12934 pstate->protectiontime -= (damage<<1);
12935 if (pstate->protectiontime < 1)
12936 pstate->protectiontime = 1;
12937 if (target==player)
12938 GM_UpdateBonus (pstate->protectiontime, false);
12939 return;
12940 }
12941 else if ((target->flags&FL_GODMODE) || (target->flags&FL_DOGMODE) || godmode)
12942 return;
12943 //damage=FixedMulShift((gamestate.difficulty+1),damage,2); // player object difficulty
12944 }
12945
12946 else if (tcl == NMEsaucerobj)
12947 {
12948 target->momentumx = target->momentumy = 0;
12949 NewState(target,&s_explosion1);
12950 target->flags &= ~FL_SHOOTABLE;
12951 return;
12952 }
12953 else if (tcl == b_darianobj)
12954 MISCVARS->ESAU_SHOOTING = false;
12955 else if ((tcl == strikeguardobj) || (tcl == b_heinrichobj))
12956 target->target = shooter;
12957
12958 if (( (!(target->flags & FL_SHOOTABLE)) ||
12959 (tcl == roboguardobj) || (tcl == wallopobj) ||
12960 (tcl == patrolgunobj) ) &&
12961 (tcl!=playerobj) )
12962 SpawnMetalSparks(target,angle);
12963
12964 else if ((tcl < b_darianobj) || (tcl > b_darksnakeobj))
12965 {
12966
12967 //target->flags &= ~FL_USE;
12968
12969 damage=FixedMulShift(511-accuracy,damage,9); // Min half damage
12970 if (dist<64)
12971 {
12972 if (dist>2)
12973 damage=FixedMulShift(63-dist,damage,6);
12974 if (damage<1)
12975 damage=1;
12976 }
12977 else
12978 damage=1;
12979
12980 if (damage>MAXDAMAGE) damage=MAXDAMAGE; // absolutely clip it
12981
12982 DamageThing(target,damage);
12983 if ((tcl == collectorobj) && gamestate.SpawnDeluder)
12984 {
12985 Collision(target,shooter,0,0);
12986 if (target->hitpoints <= 0)
12987 BATTLE_CheckGameStatus(battle_shot_deluder,shooter->dirchoosetime);
12988 }
12989
12990 else
12991 {newmomx = FixedMul(damage<<7,costable[angle]);
12992 newmomy = -FixedMul(damage<<7,sintable[angle]);
12993 Collision(target,shooter,-(target->momentumx)+newmomx,-(target->momentumy)+newmomy);
12994 if (tcl == playerobj)
12995 {
12996 playertype * pstate;
12997
12998 M_LINKSTATE(target,pstate);
12999 if (pstate->health <= 0)
13000 {
13001
13002 if (shooter->obclass == playerobj) {
13003 if (!target->momentumz)
13004 BATTLE_PlayerKilledPlayer(battle_kill_with_bullet,shooter->dirchoosetime,target->dirchoosetime);
13005 else
13006 BATTLE_PlayerKilledPlayer(battle_kill_with_bullet_in_air,shooter->dirchoosetime,target->dirchoosetime);
13007 }
13008 }
13009 }
13010 // SoftError("ShootActor: damage=%ld dist=%ld\n",damage,dist);
13011
13012 if ((GameRandomNumber("disembowel",0)<64) && (gamestate.violence == vl_excessive))
13013 {
13014 int temp;
13015 temp=target->temp1;
13016 target->temp1=angle;
13017
13018 SpawnParticles(target,DISEMBOWEL,damage>>3);
13019 target->temp1=temp;
13020 }
13021 else if (gamestate.violence > 0)
13022 SpawnBlood(target,angle);
13023 }
13024 }
13025 }
13026
13027
13028 /*
13029 =====================
13030 =
13031 = ShootSprite
13032 =
13033 = Shoot a sprite.
13034 =
13035 =====================
13036 */
ShootSprite(objtype * shooter,statobj_t * target,int damage,int accuracy,int angle)13037 void ShootSprite(objtype * shooter, statobj_t * target, int damage, int accuracy, int angle)
13038 {
13039 int dx,dy,dist;
13040
13041
13042 if (!(target->flags & FL_SHOOTABLE))
13043 // Watchout for sprite being passed in as actor WARNING
13044 SpawnMetalSparks((objtype *)target,angle);
13045
13046 else
13047 {
13048 dx = abs(shooter->x - target->x);
13049 dy = abs(shooter->y - target->y);
13050 dist = FindDistance(dx,dy)>>16;
13051
13052 damage=FixedMulShift(511-accuracy,damage,9); // Min half damage
13053 if (dist<64)
13054 {
13055 if (dist>2)
13056 damage=FixedMulShift(63-dist,damage,6);
13057 if (damage<1)
13058 damage=1;
13059 }
13060 else
13061 damage=1;
13062
13063 if (damage>MAXDAMAGE) damage=MAXDAMAGE; // absolutely clip it
13064
13065 // SoftError("ShootSprite: damage=%ld dist=%ld\n",damage,dist);
13066
13067 DamageThing((objtype *)target,damage);
13068 if (FirstExplosionState(new->state))
13069 new->whatever = shooter;
13070
13071 SpawnStaticDamage(target, angle);
13072 }
13073 }
13074
13075
13076 /*
13077 =====================
13078 =
13079 = RayShoot
13080 =
13081 = Cast a ray out at the shooter's angle and yzangle, return
13082 =
13083 =====================
13084 */
13085
13086
13087
RayShoot(objtype * shooter,int damage,int accuracy)13088 void RayShoot (objtype * shooter, int damage, int accuracy)
13089 {
13090 objtype *tempactor;
13091 statobj_t *checksprite;
13092 int snx,sny;
13093 int incr[2];
13094 int zincr[2];
13095 int thedir[2];
13096 int cnt;
13097 int grid[2];
13098 int index;
13099 int vx,vy;
13100 int angle;
13101 int yzangle;
13102 int value;
13103 int offset;
13104 int z;
13105 int lastcnt;
13106 int bullethole=0;
13107 enum {gs_door, gs_wall, gs_floor, gs_ceiling, gs_pushwall};
13108 int smokecondition=0;
13109
13110
13111 if ((shooter->areanumber==player->areanumber) && (Near(shooter,player,3)))
13112 SetIllumination(2);
13113
13114 offset = ((GameRandomNumber("RayShoot",0)-128)>>MAXSHOOTSHIFT);
13115 offset = FixedMulShift(accuracy,offset,8);
13116
13117 if (offset>MAXSHOOTOFFSET)
13118 offset=MAXSHOOTOFFSET;
13119
13120 else if (offset<-MAXSHOOTOFFSET)
13121 offset=-MAXSHOOTOFFSET;
13122
13123 angle=(shooter->angle+offset)&(FINEANGLES-1);
13124
13125 offset = ((GameRandomNumber("RayShoot",1)-128)>>MAXSHOOTSHIFT);
13126 offset = FixedMulShift(accuracy,offset,8);
13127
13128 if (offset>MAXSHOOTOFFSET)
13129 offset=MAXSHOOTOFFSET;
13130
13131 else if (offset<-MAXSHOOTOFFSET)
13132 offset=-MAXSHOOTOFFSET;
13133
13134 yzangle=(shooter->yzangle+offset)&(FINEANGLES-1);
13135
13136 vy = -sintable[angle];
13137 vx = costable[angle];
13138 snx=shooter->x&0xffff;
13139 sny=shooter->y&0xffff;
13140 grid[0]=shooter->tilex;
13141 grid[1]=shooter->tiley;
13142 if (shooter->obclass==playerobj)
13143 {
13144 playertype * pstate;
13145
13146 M_LINKSTATE(shooter,pstate);
13147 z=shooter->z+pstate->playerheight-32;
13148 }
13149 else
13150 z=shooter->z-7;
13151 if (vx>0)
13152 {
13153 thedir[0]=1;
13154 snx^=0xffff;
13155 incr[1]=-vx;
13156 }
13157 else
13158 {
13159 thedir[0]=-1;
13160 incr[1]=vx;
13161 }
13162 if (vy>0)
13163 {
13164 thedir[1]=1;
13165 sny^=0xffff;
13166 incr[0]=vy;
13167 }
13168 else
13169 {
13170 thedir[1]=-1;
13171 incr[0]=-vy;
13172 }
13173 zincr[0]=-FixedMulShift(sintable[yzangle],abs(vx),26);
13174 zincr[1]=-FixedMulShift(sintable[yzangle],abs(vy),26);
13175
13176 cnt=FixedMul(snx,incr[0])+FixedMul(sny,incr[1]);
13177 index= (cnt >= 0);
13178 do
13179 {
13180 tempactor = (objtype*)actorat[grid[0]][grid[1]];
13181 value = tilemap[grid[0]][grid[1]];
13182 checksprite = sprites[grid[0]][grid[1]];
13183 if (value)
13184 {
13185 if (value&0x8000)
13186 {
13187 if (!(value&0x4000))
13188 {
13189 if ((doorobjlist[value&0x3ff]->action==dr_closed) || (z<maxheight-64))
13190 {
13191 smokecondition=gs_door;
13192 break;
13193 }
13194 else if (doorobjlist[value&0x3ff]->position<=0x8000)
13195 {
13196 smokecondition=gs_door;
13197 break;
13198 }
13199 }
13200 else
13201 {
13202 if ( maskobjlist[value&0x3ff]->flags & MW_SHOOTABLE )
13203 {
13204 if (z>maxheight-64) // Are we shooting above the glass
13205 {
13206 UpdateMaskedWall(value&0x3ff);
13207 return;
13208 }
13209 }
13210 else if ( maskobjlist[value&0x3ff]->flags & MW_WEAPONBLOCKING )
13211 {
13212 smokecondition=gs_door;
13213 break;
13214 }
13215 }
13216 }
13217 else
13218 {
13219 smokecondition=gs_wall;
13220 break;
13221 }
13222 }
13223
13224 if (checksprite &&
13225 ((checksprite->flags & FL_BLOCK)||(checksprite->flags & FL_SHOOTABLE)) &&
13226 (abs(checksprite->z-z)<32) &&
13227 (InRange(shooter,(objtype *)checksprite,
13228 FindDistance(shooter->x-checksprite->x,shooter->y-checksprite->y) )
13229 ==true
13230 )
13231 )
13232 {
13233 ShootSprite(shooter, checksprite, damage, accuracy, angle);
13234 return;
13235 }
13236
13237
13238 if (tempactor)
13239 {if (tempactor->which == ACTOR)
13240 {if ((abs(tempactor->z-z)<32 ) && (!(tempactor->flags & FL_DYING)) &&
13241 (tempactor->flags & FL_BLOCK) && (tempactor != shooter) &&
13242 (tempactor->obclass!=diskobj) &&
13243 (InRange(shooter,tempactor,
13244 FindDistance(shooter->x-tempactor->x,shooter->y-tempactor->y) )
13245 ==true
13246 )
13247 )
13248 {ShootActor(shooter, tempactor, damage, accuracy, angle);
13249 return;
13250 }
13251 }
13252 else if (tempactor->which == PWALL)
13253 return;
13254 }
13255
13256 if (z<-32)
13257 {
13258 smokecondition=gs_ceiling;
13259 break;
13260 }
13261 else if (z>maxheight)
13262 {
13263 smokecondition=gs_floor;
13264 break;
13265 }
13266 index= (cnt >= 0);
13267 cnt+=incr[index];
13268 z +=zincr[index];
13269 grid[index]+=thedir[index];
13270 }
13271 while (1);
13272
13273 if (IsWindow(grid[0],grid[1]))
13274 return;
13275
13276 lastcnt=cnt-incr[index];
13277
13278 if (smokecondition==gs_floor)
13279 {
13280 int dist;
13281 int tangentangle;
13282
13283 tangentangle=tantable[yzangle];
13284 if (tangentangle!=0)
13285 {
13286 dist=FixedDiv2(((shooter->z-maxheight)<<10),(tangentangle<<1));
13287 xintercept=shooter->x+FixedMul(dist,costable[angle]);
13288 yintercept=shooter->y-FixedMul(dist,sintable[angle]);
13289 }
13290 z=maxheight;
13291 // bullethole=5;
13292 }
13293 else if (smokecondition==gs_ceiling)
13294 {
13295 int dist;
13296 int tangentangle;
13297
13298 if (sky!=0)
13299 return;
13300 tangentangle=tantable[yzangle];
13301 if (tangentangle!=0)
13302 {
13303 dist=FixedDiv2(((shooter->z+32)<<10),(tangentangle<<1));
13304 xintercept=shooter->x+FixedMul(dist,costable[angle]);
13305 yintercept=shooter->y-FixedMul(dist,sintable[angle]);
13306 }
13307 z=-32;
13308 // bullethole=5;
13309 }
13310 else
13311 {
13312 int dx,dy,xydist;
13313
13314
13315 #define CORNERVALUE 0x500
13316
13317
13318 if (IsWindow(grid[0],grid[1]))
13319 return;
13320 if (lastcnt<0)
13321 {
13322 xintercept=grid[0]<<16;
13323 if (smokecondition==gs_door)
13324 {
13325 if (thedir[0]<0)
13326 xintercept+=0x9fff;
13327 else
13328 xintercept+=0x5fff;
13329 yintercept=FixedScale(xintercept-shooter->x,vy,vx)+shooter->y;
13330 if ((yintercept>>16)!=grid[1])
13331 {
13332 if ((yintercept>>16)>grid[1])
13333 yintercept=(grid[1]<<16)+0xffff;
13334 else
13335 yintercept=(grid[1]<<16);
13336 }
13337 }
13338 else if (smokecondition==gs_wall)
13339 {
13340 if (thedir[0]<0)
13341 {
13342 objtype * ta;
13343
13344 xintercept += 0x10000;
13345 yintercept=FixedScale(xintercept-shooter->x,vy,vx)+shooter->y;
13346
13347 xintercept += SMOKEWALLOFFSET;
13348 bullethole=1;
13349 if (yintercept < ((grid[1] << 16) + CORNERVALUE))
13350 bullethole = 0;
13351 else if (yintercept > ((grid[1] << 16) + 0x10000 - CORNERVALUE))
13352 bullethole = 0;
13353
13354 ta = (objtype*)actorat[grid[0]][grid[1]];
13355 if ((ta) && (ta->which==PWALL))
13356 bullethole=0;
13357 }
13358 else
13359 {
13360 objtype * ta;
13361
13362 yintercept=FixedScale(xintercept-shooter->x,vy,vx)+shooter->y;
13363 xintercept-=SMOKEWALLOFFSET;
13364 bullethole=2;
13365 if (yintercept < ((grid[1] << 16) + CORNERVALUE))
13366 bullethole = 0;
13367 else if (yintercept > ((grid[1] << 16) + 0x10000 - CORNERVALUE))
13368 bullethole = 0;
13369
13370 ta = (objtype*)actorat[grid[0]][grid[1]];
13371 if ((ta) && (ta->which==PWALL))
13372 bullethole=0;
13373 }
13374 }
13375 }
13376 else
13377 {
13378 yintercept=grid[1]<<16;
13379 if (smokecondition==gs_door)
13380 {
13381 if (thedir[1]<0)
13382 yintercept+=0x9fff;
13383 else
13384 yintercept+=0x5fff;
13385 xintercept=FixedScale(yintercept-shooter->y,vx,vy)+shooter->x;
13386 if ((xintercept>>16)!=grid[0])
13387 {
13388 if ((xintercept>>16)>grid[0])
13389 xintercept=(grid[0]<<16)+0xffff;
13390 else
13391 xintercept=(grid[0]<<16);
13392 }
13393 }
13394 else if (smokecondition==gs_wall)
13395 {
13396 if (thedir[1]<0)
13397 {
13398 objtype * ta;
13399
13400
13401 yintercept += 0x10000;
13402 xintercept=FixedScale(yintercept-shooter->y,vx,vy)+shooter->x;
13403
13404 yintercept += SMOKEWALLOFFSET;
13405 bullethole=3;
13406 if (xintercept < ((grid[0] << 16) + CORNERVALUE))
13407 bullethole = 0;
13408 else if (xintercept > ((grid[0] << 16) + 0x10000 - CORNERVALUE))
13409 bullethole = 0;
13410
13411 ta = (objtype*)actorat[grid[0]][grid[1]];
13412 if ((ta) && (ta->which==PWALL))
13413 bullethole=0;
13414 }
13415 else
13416 {
13417 objtype * ta;
13418
13419 xintercept=FixedScale(yintercept-shooter->y,vx,vy)+shooter->x;
13420 yintercept-=SMOKEWALLOFFSET;
13421 bullethole=4;
13422 if (xintercept < ((grid[0] << 16) + CORNERVALUE))
13423 bullethole = 0;
13424 else if (xintercept > ((grid[0] << 16) + 0x10000 - CORNERVALUE))
13425 bullethole = 0;
13426
13427 ta = (objtype*)actorat[grid[0]][grid[1]];
13428 if ((ta) && (ta->which==PWALL))
13429 bullethole=0;
13430 }
13431 }
13432 }
13433 dx = xintercept - shooter->x;
13434 dy = shooter->y - yintercept;
13435 xydist = FindDistance(dx,dy);
13436 if (shooter->obclass==playerobj)
13437 {
13438 playertype * pstate;
13439
13440 M_LINKSTATE(shooter,pstate);
13441 z=shooter->z-FixedMulShift(xydist,tantable[yzangle],25)+pstate->playerheight-32;
13442 }
13443 else
13444 z=shooter->z-FixedMulShift(xydist,tantable[yzangle],25);
13445 if (smokecondition==gs_wall)
13446 {
13447 if (z<-32)
13448 z=-32;
13449 }
13450 }
13451 SpawnGunSmoke(xintercept,yintercept,z,angle,bullethole);
13452 }
13453
13454
13455 /*
13456 =====================
13457 =
13458 = T_BossDied ()
13459 =
13460 =====================
13461 */
13462
T_BossDied(objtype * ob)13463 void T_BossDied (objtype *ob)
13464 {
13465
13466 if (ob->ticcount)
13467 return;
13468
13469 switch (ob->obclass)
13470 {
13471 case b_darianobj:
13472 case b_heinrichobj:
13473 case b_darkmonkobj:
13474 case b_robobossobj:
13475 case b_darksnakeobj:
13476 playstate = ex_bossdied;
13477 break;
13478 default:
13479 ;
13480 }
13481 }
13482
13483
13484 /*
13485 =====================
13486 =
13487 = T_Wind ()
13488 =
13489 =====================
13490 */
13491
13492 static int WindDistance = 1000;
13493 static int WindCurrentDistance = 1000;
13494 static int WindHandle = -1;
13495 static int WindLastTic = -1;
13496 static int WindPlaying = false;
13497 static int WindPitch = 0;
13498 static int WindDestPitch = 0;
13499 static int WindPitchRate = 0;
13500
T_Wind(objtype * ob)13501 void T_Wind
13502 (
13503 objtype *ob
13504 )
13505
13506 {
13507 int distance;
13508 int dx;
13509 int dy;
13510
13511 if ( ( GetTicCount() - WindLastTic ) > 0 )
13512 {
13513 WindDistance = 1000;
13514
13515 WindPitch += WindPitchRate;
13516 if ( WindPitch == WindDestPitch )
13517 {
13518 WindDestPitch = ( RandomNumber( "Wind Pitch", 0 ) - 128 ) << 3;
13519 WindPitchRate = 1;
13520 if ( WindDestPitch < WindPitch )
13521 {
13522 WindPitchRate = -WindPitchRate;
13523 }
13524 }
13525 }
13526 WindLastTic = GetTicCount();
13527
13528 dx = ( ob->x - PLAYER[0]->x );
13529 dy = ( PLAYER[0]->y - ob->y );
13530
13531 distance = 1000;
13532 if ( areabyplayer[ ob->areanumber ] )
13533 {
13534 distance = ( FindDistance( dx, dy ) ) >> 13;
13535 }
13536
13537 if ( distance < WindDistance )
13538 {
13539 WindDistance = distance;
13540 }
13541
13542 if ( WindDistance < 255 )
13543 {
13544 WindPlaying = true;
13545 WindCurrentDistance = WindDistance;
13546 }
13547 else
13548 {
13549 if ( WindPlaying )
13550 {
13551 WindCurrentDistance += 3;
13552 }
13553 }
13554
13555 if ( WindPlaying )
13556 {
13557 if ( WindCurrentDistance < 255 )
13558 {
13559 if ( !SD_SoundActive( WindHandle ) )
13560 {
13561 WindHandle = SD_PlayPitchedSound( SD_WINDSND,
13562 255 - WindCurrentDistance, WindPitch );
13563 }
13564 else
13565 {
13566 SD_SetSoundPitch( WindHandle, WindPitch );
13567 SD_SetPan( WindHandle, 255 - WindCurrentDistance, 255 - WindCurrentDistance,
13568 255 - WindCurrentDistance );
13569 }
13570 }
13571 else
13572 {
13573 SD_StopSound( WindHandle );
13574 WindPlaying = false;
13575 }
13576 }
13577 }
13578
13579 /*
13580 =====================
13581 =
13582 = StopWind ()
13583 =
13584 =====================
13585 */
13586
StopWind(void)13587 void StopWind
13588 (
13589 void
13590 )
13591
13592 {
13593 objtype *temp;
13594
13595 FX_SetReverb( 0 );
13596
13597 SD_StopSound( WindHandle );
13598 WindDistance = 1000;
13599 WindCurrentDistance = 1000;
13600 WindHandle = -1;
13601 WindLastTic = -1;
13602 WindPlaying = false;
13603 WindPitch = 0;
13604 WindDestPitch = 0;
13605 WindPitchRate = 0;
13606
13607
13608 for(temp=FIRSTACTOR;temp;temp=temp->next)
13609 {
13610 if (temp->soundhandle != -1)
13611 SD_StopSound(temp->soundhandle);
13612 }
13613 }
13614
13615