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