1 /*------------------------Patrick 14/1/97-----------------------------
2   This source file contains all the functions for the object visibility
3   management system     (which controls visibility for aliens, objects,
4   pickups, autoguns, etc....)
5   It also contains initialisation and behaviour functions for
6   inanimate objects (like chairs, weapons, etc...).
7   --------------------------------------------------------------------*/
8 #include "3dc.h"
9 
10 #include "inline.h"
11 #include "module.h"
12 #include "stratdef.h"
13 #include "gamedef.h"
14 #include "bh_types.h"
15 #include "comp_shp.h"
16 #include "dynblock.h"
17 
18 #include "bh_alien.h"
19 #include "pvisible.h"
20 #include "bh_pred.h"
21 #include "bh_xeno.h"
22 #include "bh_paq.h"
23 #include "bh_queen.h"
24 #include "bh_marin.h"
25 #include "bh_fhug.h"
26 #include "bh_debri.h"
27 #include "bh_plachier.h"
28 #include "plat_shp.h"
29 #include "psnd.h"
30 #include "lighting.h"
31 #include "pldnet.h"
32 #include "bh_dummy.h"
33 #include "bh_videoscreen.h"
34 #include "bh_plift.h"
35 #include "bh_light.h"
36 #include "weapons.h"
37 #include "bh_agun.h"
38 #include "bh_corpse.h"
39 #include "chnkload.h"
40 
41 /* for win95 net game support */
42 #include "pldghost.h"
43 
44 #include "pfarlocs.h"
45 
46 #define UseLocalAssert Yes
47 #include "ourasert.h"
48 
49 #define HMODEL_HACK 0
50 
51 /* prototypes... */
52 static int WorldPointIsInModule(MODULE* thisModule, VECTORCH* thisPoint);
53 static int EmergencyRelocateObject(STRATEGYBLOCK *sbPtr);
54 static void EmergencyPlaceObjectInModule(STRATEGYBLOCK *sbPtr, AIMODULE* target);
55 static void FragmentInanimateObject(STRATEGYBLOCK *sbptr);
56 static void ExplodeInanimateObject(STRATEGYBLOCK *sbptr);
57 static void RespawnInanimateObject(STRATEGYBLOCK *sbPtr);
58 void KillFragmentalObjectForRespawn(STRATEGYBLOCK *sbPtr);
59 
60 void IdentifyObject(STRATEGYBLOCK *sbPtr);
61 
62 /* external global variables used in this file */
63 extern int ModuleArraySize;
64 extern char *ModuleCurrVisArray;
65 extern int NumActiveBlocks;
66 extern int NormalFrameTime;
67 extern int GlobalFrameCounter;
68 
69 extern void ActivateSelfDestructSequence(int seconds);
70 
71 extern SOUND3DDATA Explosion_SoundData;
72 
73 /* this is a default map used in visibility management
74 NB If you use this, you MUST set the shapeIndex field appropriately*/
75 MODULEMAPBLOCK VisibilityDefaultObjectMap =
76 {
77         MapType_Default,
78         I_ShapeCube, /* this is a default value */
79         {0,0,0},
80         {0,0,0},
81         #if StandardStrategyAndCollisions
82         ObFlag_Dynamic|ObFlag_NewtonMovement|ObFlag_MatMul,
83         #else
84         0,
85         #endif
86         0,
87         0,
88         #if StandardStrategyAndCollisions
89         StrategyI_Null,
90         0,
91     GameCollStrat_Default,
92         ShapeCStrat_DoubleExtentEllipsoid,
93         0,
94         #endif
95         0,
96         0,
97         0,
98         #if StandardStrategyAndCollisions
99         0,
100         0,0,0,
101         #endif
102         {0,0,0},
103         0,
104         0,
105         #if StandardStrategyAndCollisions
106         0,
107         0,
108         #endif
109         0,
110         0,
111         {0,0,0}
112 };
113 
114 
115 
116 
117 
118 /*---------------------Patrick 14/1/97-----------------------------
119 
120                         SOURCE FOR VISIBILITY MANAGEMENT SYSTEM
121 
122   -----------------------------------------------------------------*/
123 
124 
125 
126 
127 
128 
129 /*----------------------Patrick 16/1/97-----------------------------
130 This function must be called to initialise the 'containingModule'
131 field in all strategyblocks for rif-loaded objects.     This cannot
132 be done in the first-stage initialisation (via enableBehaviourTypes)
133 as the module system is not enabled at this point.
134 --------------------------------------------------------------------*/
InitObjectVisibilities(void)135 void InitObjectVisibilities(void)
136 {
137         extern int NumActiveStBlocks;
138         extern STRATEGYBLOCK *ActiveStBlockList[];
139 
140         int sbIndex = 0;
141         STRATEGYBLOCK *sbPtr;
142 
143         /* loop thro' the strategy block list, looking for objects that will have
144         their visibilities managed ... */
145         while(sbIndex < NumActiveStBlocks)
146         {
147                 sbPtr = ActiveStBlockList[sbIndex++];
148                 if(     (sbPtr->I_SBtype ==     I_BehaviourAlien)||
149                         (sbPtr->I_SBtype ==     I_BehaviourMarine)||
150                         (sbPtr->I_SBtype ==     I_BehaviourInanimateObject)||
151                         (sbPtr->I_SBtype ==     I_BehaviourVideoScreen)||
152                         (sbPtr->I_SBtype ==     I_BehaviourQueenAlien)||
153                         (sbPtr->I_SBtype ==     I_BehaviourFaceHugger)||
154                         (sbPtr->I_SBtype ==     I_BehaviourPredator)||
155                         (sbPtr->I_SBtype ==     I_BehaviourAutoGun)||
156                         (sbPtr->I_SBtype ==     I_BehaviourPlatform)||
157                         (sbPtr->I_SBtype ==     I_BehaviourBinarySwitch && sbPtr->DynPtr)||/*Allow for switches with no shape*/
158                         (sbPtr->I_SBtype ==     I_BehaviourLinkSwitch && sbPtr->DynPtr)||
159                         (sbPtr->I_SBtype ==     I_BehaviourTrackObject)||
160                         (sbPtr->I_SBtype ==     I_BehaviourFan)||
161                         (sbPtr->I_SBtype ==     I_BehaviourPlacedHierarchy)||
162                         (sbPtr->I_SBtype ==     I_BehaviourPlacedLight)||
163                         (sbPtr->I_SBtype ==     I_BehaviourXenoborg)||
164                         (sbPtr->I_SBtype ==     I_BehaviourSeal)||
165                         (sbPtr->I_SBtype ==     I_BehaviourDatabase)||
166                         (sbPtr->I_SBtype ==     I_BehaviourDummy)||
167                         (sbPtr->I_SBtype ==     I_BehaviourPredatorAlien)
168                         )
169                 {
170                         DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
171                         LOCALASSERT(dynPtr);
172 
173                         sbPtr->containingModule = ModuleFromPosition(&(dynPtr->Position), (MODULE *)0);
174 
175                         sbPtr->maintainVisibility = 1;
176 
177 
178                 }
179                 else
180                 {
181                         /* just in case ... */
182                         if(sbPtr->I_SBtype !=   I_BehaviourGenerator &&
183 						   sbPtr->I_SBtype !=   I_BehaviourMarinePlayer)
184                         {
185                                 sbPtr->containingModule = (MODULE *)0;
186                         }
187                         sbPtr->maintainVisibility = 0;
188                 }
189 
190         }
191 
192         /* initialise each object's visibility */
193         DoObjectVisibilities();
194 
195 }
196 
197 
198 /*----------------------Patrick 13/1/97-----------------------------
199 This function should be called after the dynamics, and before
200 rendering (ie via Cris H's module handler call-back function).
201 
202 It identifies appropriate strategy blocks in the current block list,
203 (those which have a non-zero 'containingModule' field), and calls
204 DoObjectVisibility().
205 --------------------------------------------------------------------*/
206 
DoObjectVisibilities(void)207 void DoObjectVisibilities(void)
208 {
209         extern int NumActiveStBlocks;
210         extern STRATEGYBLOCK *ActiveStBlockList[];
211 
212         int sbIndex = 0;
213         STRATEGYBLOCK *sbPtr;
214 
215         /* loop thro' the strategy block list, looking for objects that need to have
216         their visibilities managed ... */
217         while(sbIndex < NumActiveStBlocks)
218         {
219                 sbPtr = ActiveStBlockList[sbIndex++];
220                 if(sbPtr->maintainVisibility)
221                         DoObjectVisibility(sbPtr);
222         }
223 }
224 
225 
DoObjectVisibility(STRATEGYBLOCK * sbPtr)226 void DoObjectVisibility(STRATEGYBLOCK *sbPtr)
227 {
228         if(!(sbPtr->SBdptr))
229         {
230                 /* Note that we don't call modulefromposition() for far objects, as they mostly don't
231                 move, and those that do (eg AIs) move to precalculated positions in modules. Thus
232                 invisible objects are responsible for looking after their own containingModule field.
233                 This should always be ok: we should always have a correct and valid containing
234                 module. However, we will do a paranoia check for a null containingModule... */
235                 if(!sbPtr->containingModule)
236                 {
237                         textprint("Calling Far EmergencyRelocateObject, On object %x, type %d!\n",(int)sbPtr, sbPtr->I_SBtype);
238                         IdentifyObject(sbPtr);
239                         if(!(EmergencyRelocateObject(sbPtr))) {
240                                 textprint("Relocate failed!\n");
241                                 return;
242                         }
243                 }
244                 if (!sbPtr->containingModule)
245                 {
246                         textprint("Relocate failed and reported success\n");
247                         return;
248                 }
249 
250                 /* Now do the visibility check: the object has no display block, so check if
251                 it's module is visible. If so, make the object visibile too. */
252 
253 
254                 if ( (sbPtr->I_SBtype == I_BehaviourPlacedLight)
255                 &&ThisObjectIsInAModuleVisibleFromCurrentlyVisibleModules(sbPtr))
256                 {
257                         MakePlacedLightNear(sbPtr);
258                         return;
259                 }
260                 else if (sbPtr->I_SBtype == I_BehaviourNetGhost)
261                 {
262                         NETGHOSTDATABLOCK *ghostDataPtr = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr;
263                         if (ghostDataPtr && ghostDataPtr->type == I_BehaviourFlareGrenade)
264                         {
265                                 if(ThisObjectIsInAModuleVisibleFromCurrentlyVisibleModules(sbPtr))
266                                 {
267                                         MakeGhostNear(sbPtr);
268                                         return;
269                                 }
270                         }
271                 }
272 				else if (sbPtr->I_SBtype == I_BehaviourPlatform)
273 				{
274 					PLATFORMLIFT_BEHAVIOUR_BLOCK *platformliftdata = (PLATFORMLIFT_BEHAVIOUR_BLOCK *)sbPtr->SBdataptr;
275                 	//platform lift needs to be made near if its module near or
276 					//if it is moving
277                 	if(ModuleCurrVisArray[(sbPtr->containingModule->m_index)] ||
278 					   platformliftdata->state==PLBS_GoingUp ||
279 					   platformliftdata->state==PLBS_GoingDown)
280 					{
281 						MakeObjectNear(sbPtr);
282 						return;
283 					}
284 				}
285 
286                 if(ModuleCurrVisArray[(sbPtr->containingModule->m_index)])
287                 {
288                         /* module is visible, so make object visible too */
289                         switch(sbPtr->I_SBtype)
290                         {
291                                 case(I_BehaviourAlien):
292                                 {
293                                         MakeAlienNear(sbPtr);
294                                         break;
295                                 }
296                                 case(I_BehaviourVideoScreen):
297                                 {
298                                         MakeObjectNear(sbPtr);
299                                         if(sbPtr->SBdptr) AddLightingEffectToObject(sbPtr->SBdptr,LFX_FLARE);
300                                         break;
301                                 }
302                                 case(I_BehaviourRubberDuck):
303                                 case(I_BehaviourInanimateObject):
304                                 {
305                                         MakeObjectNear(sbPtr);
306                                         break;
307                                 }
308                                 case(I_BehaviourAutoGun):
309                                 {
310                                         MakeSentrygunNear(sbPtr);
311                                         break;
312                                 }
313                                 case(I_BehaviourPlatform):
314                                 {
315                                         MakeObjectNear(sbPtr);
316                                         break;
317                                 }
318                                 case(I_BehaviourBinarySwitch):
319                                 {
320                                         MakeObjectNear(sbPtr);
321                                         break;
322                                 }
323                                 case(I_BehaviourDatabase):
324                                 {
325                                         MakeObjectNear(sbPtr);
326                                         break;
327                                 }
328                                 case(I_BehaviourLinkSwitch):
329                                 {
330                                         MakeObjectNear(sbPtr);
331                                         break;
332                                 }
333                                 case(I_BehaviourPredator):
334                                 {
335                                         MakePredatorNear(sbPtr);
336                                         break;
337                                 }
338                                 case(I_BehaviourXenoborg):
339                                 {
340                                         MakeXenoborgNear(sbPtr);
341                                         break;
342                                 }
343                                 case(I_BehaviourQueenAlien):
344                                 {
345                                         MakeQueenNear(sbPtr);
346                                         break;
347                                 }
348                                 case(I_BehaviourPredatorAlien):
349                                 {
350                                         GLOBALASSERT(0);
351                                         //MakePAQNear(sbPtr);
352                                         break;
353                                 }
354                                 case(I_BehaviourFaceHugger):
355                                 {
356                                         MakeFacehuggerNear(sbPtr);
357                                         break;
358                                 }
359                                 case(I_BehaviourMarine):
360                                 {
361                                         MakeMarineNear(sbPtr);
362                                         break;
363                                 }
364                                 case(I_BehaviourSeal):
365                                 {
366                                         MakeMarineNear(sbPtr);
367                                         break;
368                                 }
369                                 case(I_BehaviourNetGhost):
370                                 {
371                                         NETGHOSTDATABLOCK *ghostDataPtr = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr;
372 
373                                         /* KJL 16:42:40 23/01/99 - near behaviour is triggered differently for
374                                            lightsources such as flares */
375                                         if (ghostDataPtr && ghostDataPtr->type != I_BehaviourFlareGrenade)
376                                         {
377                                                 MakeGhostNear(sbPtr);
378                                         }
379 
380                                         break;
381                                 }
382                                 case(I_BehaviourTrackObject):
383                                 {
384                                         MakeObjectNear(sbPtr);
385                                         break;
386                                 }
387                                 case(I_BehaviourFan):
388                                 {
389                                         MakeObjectNear(sbPtr);
390                                         break;
391                                 }
392                                 case(I_BehaviourNetCorpse):
393                                 {
394                                         MakeCorpseNear(sbPtr);
395                                         break;
396                                 }
397                                 case (I_BehaviourPlacedHierarchy):
398                                 {
399                                         MakePlacedHierarchyNear(sbPtr);
400                                         break;
401                                 }
402                                 case (I_BehaviourPlacedLight):
403                                 {
404                                         /* KJL 16:42:40 23/01/99 - do nothing; near behaviour is triggered
405                                         differently for lightsources */
406                                         break;
407                                 }
408                                 case (I_BehaviourDummy):
409                                 {
410                                         MakeDummyNear(sbPtr);
411                                         break;
412                                 }
413                                 default:
414                                 {
415                                         /* only the above object types should get here */
416                                         LOCALASSERT(1==0);
417                                 }
418                         }
419                 }
420         }
421         else
422         {
423                 /* object is currently visible.
424                 first need to get it's module, as it may have moved under dynamics */
425                 MODULE* newModule;
426                 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
427                 LOCALASSERT(dynPtr);
428 
429                 newModule = ModuleFromPosition(&(dynPtr->Position), (sbPtr->containingModule));
430                 if(!(newModule))
431                 {
432                         /* attempt to relocate object */
433                         textprint("Calling Near EmergencyRelocateObject, On object %x, type %d!\n",(int)sbPtr, sbPtr->I_SBtype);
434                         IdentifyObject(sbPtr);
435                         if(!(EmergencyRelocateObject(sbPtr))) {
436                                 textprint("Relocate failed!\n");
437                                 return;
438                         }
439                 }
440                 else
441                         /* update object's module field */
442                         sbPtr->containingModule = newModule;
443 
444                 /* now check the object's module */
445                 if (sbPtr->I_SBtype == I_BehaviourPlacedLight)
446                 {
447                         if(!ThisObjectIsInAModuleVisibleFromCurrentlyVisibleModules(sbPtr))
448                         {
449                                 MakeObjectFar(sbPtr);
450                         }
451                 }
452                 else if(ModuleCurrVisArray[(sbPtr->containingModule->m_index)] == 0)
453                 {
454                         /* module is invisible, so make object invisible too */
455                         switch(sbPtr->I_SBtype)
456                         {
457                                 case(I_BehaviourAlien):
458                                 {
459                                         MakeAlienFar(sbPtr);
460                                         break;
461                                 }
462                                 case(I_BehaviourRubberDuck):
463                                 case(I_BehaviourVideoScreen):
464                                 case(I_BehaviourInanimateObject):
465                                 {
466                                         MakeObjectFar(sbPtr);
467                                         break;
468                                 }
469                                 case(I_BehaviourAutoGun):
470                                 {
471                                         MakeSentrygunFar(sbPtr);
472                                         break;
473                                 }
474                                 case(I_BehaviourPlatform):
475                                 {
476 					PLATFORMLIFT_BEHAVIOUR_BLOCK *platformliftdata = (PLATFORMLIFT_BEHAVIOUR_BLOCK *)sbPtr->SBdataptr;
477 					//don't make platform lift far if it is currently moving
478 					//(otherwise the lift won't be able to move)
479 					if(platformliftdata->state!=PLBS_GoingUp &&
480 					   platformliftdata->state!=PLBS_GoingDown)
481 					{
482 						MakeObjectFar(sbPtr);
483 					}
484                                         break;
485                                 }
486                                 case(I_BehaviourBinarySwitch):
487                                 {
488                                         MakeObjectFar(sbPtr);
489                                         break;
490                                 }
491                                 case(I_BehaviourDatabase):
492                                 {
493                                         MakeObjectFar(sbPtr);
494                                         break;
495                                 }
496                                 case(I_BehaviourLinkSwitch):
497                                 {
498                                         MakeObjectFar(sbPtr);
499                                         break;
500                                 }
501                                 case(I_BehaviourPredator):
502                                 {
503                                         MakePredatorFar(sbPtr);
504                                         break;
505                                 }
506                                 case(I_BehaviourXenoborg):
507                                 {
508                                         MakeXenoborgFar(sbPtr);
509                                         break;
510                                 }
511                                 case(I_BehaviourQueenAlien):
512                                 {
513                                         MakeQueenFar(sbPtr);
514                                         break;
515                                 }
516                                 case(I_BehaviourPredatorAlien):
517                                 {
518                                         //MakePAQFar(sbPtr);
519                                         GLOBALASSERT(0);
520                                         /* Should be BehaviourAlien! */
521                                         break;
522                                 }
523                                 case(I_BehaviourFaceHugger):
524                                 {
525                                         MakeFacehuggerFar(sbPtr);
526                                         break;
527                                 }
528                                 case(I_BehaviourMarine):
529                                 {
530                                         MakeMarineFar(sbPtr);
531                                         break;
532                                 }
533                                 case(I_BehaviourSeal):
534                                 {
535                                         MakeMarineFar(sbPtr); /* not yet supported */
536                                         break;
537                                 }
538                                 case(I_BehaviourNetGhost):
539                                 {
540                                         MakeGhostFar(sbPtr);
541                                         break;
542                                 }
543                                 case(I_BehaviourTrackObject):
544                                 {
545                                         MakeObjectFar(sbPtr);
546                                         break;
547                                 }
548                                 case(I_BehaviourFan):
549                                 {
550                                         MakeObjectFar(sbPtr);
551                                         break;
552                                 }
553                                 case(I_BehaviourNetCorpse):
554                                 {
555                                         MakeCorpseFar(sbPtr);
556                                         break;
557                                 }
558                                 case (I_BehaviourPlacedHierarchy):
559                                 {
560                                         MakeObjectFar(sbPtr);
561                                         break;
562                                 }
563                                 case (I_BehaviourDummy):
564                                 {
565                                         MakeDummyFar(sbPtr);
566                                         break;
567                                 }
568                                 default:
569                                 {
570                                         /* only the above object types should get here */
571                                         LOCALASSERT(1==0);
572                                 }
573                         }
574 
575                 }
576 
577         }
578 
579 }
580 
581 /*-----------------------Patrick 15/1/97---------------------------
582 This pair of functions can be used to control the visibility of
583 most objects in the environment. Object specific stuff can be done
584 after the approriate call in doObjectVisibility, or a separate
585 function can be used (as for aliens)
586 -------------------------------------------------------------------*/
587 
588 HMODELCONTROLLER DropShipHModelController;
589 
MakeObjectNear(STRATEGYBLOCK * sbPtr)590 void MakeObjectNear(STRATEGYBLOCK *sbPtr)
591 {
592         MODULE tempModule;
593         DISPLAYBLOCK *dPtr;
594         DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
595 
596     LOCALASSERT(dynPtr);
597         LOCALASSERT(sbPtr->SBdptr == NULL);
598 
599         VisibilityDefaultObjectMap.MapShape = sbPtr->shapeIndex;
600         tempModule.m_mapptr = &VisibilityDefaultObjectMap;
601         tempModule.m_sbptr = (STRATEGYBLOCK*)NULL;
602         tempModule.m_numlights = 0;
603         tempModule.m_lightarray = (struct lightblock *)0;
604         tempModule.m_extraitemdata = (struct extraitemdata *)0;
605         tempModule.m_dptr = NULL; /* this is important */
606         tempModule.name = NULL; /* this is important */
607 
608         AllocateModuleObject(&tempModule);
609         dPtr = tempModule.m_dptr;
610         if(dPtr==NULL) return; /* cannot create displayblock, so leave object "far" */
611 
612         sbPtr->SBdptr = dPtr;
613         dPtr->ObStrategyBlock = sbPtr;
614         dPtr->ObMyModule = NULL;
615 
616         /* also need to initialise positional information in the new display
617         block from the existing dynamics block: this necessary because this
618         function is (usually) called between the dynamics and rendering systems
619         so it is not initialised by the dynamics system the first time it is
620         drawn. */
621         dPtr->ObWorld = dynPtr->Position;
622         dPtr->ObEuler = dynPtr->OrientEuler;
623         dPtr->ObMat = dynPtr->OrientMat;
624 
625         #if HMODEL_HACK
626 
627         if (dPtr->ObShape==GetLoadedShapeMSL("computer")) {
628 
629                 extern SECTION Chest;
630                 SECTION *Test_Section;
631 
632                 extern SECTION *GetHierarchyFromLibrary(const char *rif_name);
633 
634                 Test_Section=GetHierarchyFromLibrary("hnpcalien");
635 
636                 //Preprocess_HModel(Test_Section);
637                 Create_HModel(&DropShipHModelController,Test_Section);
638                 InitHModelSequence(&DropShipHModelController,3,3,ONE_FIXED<<1);
639                 dPtr->HModelControlBlock=&DropShipHModelController;
640 
641 
642                 //dPtr->HModelControlBlock->Playing=1;
643                 dPtr->HModelControlBlock->Looped=1;
644 
645         }
646 
647         #endif
648 
649 
650 }
651 
MakeObjectFar(STRATEGYBLOCK * sbPtr)652 void MakeObjectFar(STRATEGYBLOCK *sbPtr)
653 {
654         int i;
655 
656         #if HMODEL_HACK
657 
658         if (sbPtr->SBdptr->ObShape==GetLoadedShapeMSL("chest")) {
659                 Dispel_HModel(&DropShipHModelController);
660         }
661 
662         #endif
663 
664         LOCALASSERT(sbPtr->SBdptr != NULL);
665 
666         /* get rid of the displayblock */
667         i = DestroyActiveObject(sbPtr->SBdptr);
668         if(i!=0)
669         {
670                 LOCALASSERT(1==0);
671         }
672         sbPtr->SBdptr = NULL;
673 
674 }
675 
676 
677 /*----------------------Patrick 15/1/97-----------------------------
678 This function relocates an object back into the environment:
679 this may be an npc, inanimate object, etc.
680 It is called if the visibility system fails to find a
681 containing module for the object, which may happen for a number
682 of reasons, eg: an object is blown out of the visible part of the
683 environment, or an npc falls out...
684 NB returns 0 if relocation failed.
685 --------------------------------------------------------------------*/
686 static int EmergRelocCalls = 0;
EmergencyRelocateObject(STRATEGYBLOCK * sbPtr)687 static int EmergencyRelocateObject(STRATEGYBLOCK *sbPtr)
688 {
689 
690         EmergRelocCalls++;
691 
692         if(sbPtr->I_SBtype == I_BehaviourNetGhost) return 1;
693 
694         /* KJL 14:48:36 09/02/98 - ignore platform lifts */
695         if (sbPtr->I_SBtype == I_BehaviourPlatform) return 1;
696 
697         /* first, try to reset the object's position: if it has a valid 'containingModule',
698         this means that it's last position was in that module, so we can use that as a reset
699         position.
700         NB this means that NPC's will be unable to 'run away' into an invisible module.
701         */
702 
703         if(sbPtr->containingModule)
704         {
705 
706                 /* Nooo, this doesn't work! CDF 3/12/97 Hack. */
707 
708                 if ((sbPtr->I_SBtype!=I_BehaviourAlien)
709                         &&(sbPtr->I_SBtype!=I_BehaviourMarine)
710                 ) {
711                         textprint("Valid containingModule.\n");
712                         sbPtr->DynPtr->Position = sbPtr->DynPtr->PrevPosition;
713                         return 1;
714                 }
715         }
716 
717         /* so, we don't have a previous module... then search the environment for the
718         nearest invisible module that has entry point locations, and relocate to one of
719         these locations. */
720         {
721                 //extern SCENE Global_Scene;
722                 //extern SCENEMODULE **Global_ModulePtr;
723 
724                 AIMODULE *targetModule = 0;
725                 int targetModuleDistance = 0;
726                 //SCENEMODULE *ScenePtr;
727                 AIMODULE *moduleListPointer;
728                 int moduleCounter;
729 
730                 LOCALASSERT(ModuleArraySize);
731                 LOCALASSERT(Global_ModulePtr);
732                 LOCALASSERT(FALLP_EntryPoints); /* NB should never get here in a net game, so the codition should be true */
733 
734                 //ScenePtr = Global_ModulePtr[Global_Scene];
735                 //moduleListPointer = ScenePtr->sm_marray;
736                 {
737                         extern AIMODULE *AIModuleArray;
738                         moduleListPointer = AIModuleArray;
739                 }
740 
741                 for(moduleCounter = 0; moduleCounter < AIModuleArraySize; moduleCounter++)
742                 {
743                         AIMODULE *thisModule = &(moduleListPointer[moduleCounter]);
744                         //MODULE* thisModule = moduleListPointer[moduleCounter];
745 
746                         if(     (!(ModuleCurrVisArray[thisModule->m_index]))&&
747                                 (FALLP_EntryPoints[thisModule->m_index].numEntryPoints != 0)
748                           )
749                         {
750                                 /* a candidate */
751                                 int thisModuleDistance =
752                                         VectorDistance(&(thisModule->m_world), &(sbPtr->DynPtr->Position));
753 
754                                 if((!targetModule) || (thisModuleDistance < targetModuleDistance))
755                                 {
756                                         targetModule = thisModule;
757                                         targetModuleDistance = thisModuleDistance;
758                                 }
759                         }
760                 }
761 
762                 if(!targetModule)
763                 {
764                         /* this condition shouldn't happen, but since I'm paranoid... */
765                         //This can happen on the skirmish levels (where the whole level is visible at once)
766                         //Therefore if the object has a previous containing module , use it.
767                         //Otherwise get rid of it.
768 
769                         //LOCALASSERT(1==0);
770                         if(sbPtr->containingModule)
771                         {
772 
773                                 /* Nooo, this doesn't work! CDF 3/12/97 Hack. */
774 
775                                 textprint("Valid containingModule.\n");
776                                 sbPtr->DynPtr->Position = sbPtr->DynPtr->PrevPosition;
777                                 return 1;
778 
779                         }
780                         DestroyAnyStrategyBlock(sbPtr);
781                         return 0;
782                 }
783 
784                 EmergencyPlaceObjectInModule(sbPtr, targetModule);
785 
786                 #if debug
787                 if (!sbPtr->containingModule)
788                 {
789                         textprint("WARNING!! EmgcyPlcObInMod failed\n");
790                 }
791                 #endif
792 
793 
794                 return sbPtr->containingModule ? 1 : 0;
795         }
796 }
797 
EmergencyPlaceObjectInModule(STRATEGYBLOCK * sbPtr,AIMODULE * targetModule)798 static void EmergencyPlaceObjectInModule(STRATEGYBLOCK *sbPtr, AIMODULE* targetModule)
799 {
800         int noOfEntryPoints;
801         FARENTRYPOINT *entryPointsList;
802         VECTORCH newPosition;
803         MODULE *renderModule;
804 
805         textprint("Calling EmergencyPlaceObjectInModule!\n");
806 
807         /* first off, assert a few pre-conditions */
808         GLOBALASSERT(AIModuleIsPhysical(targetModule));
809         GLOBALASSERT(sbPtr->maintainVisibility);
810         GLOBALASSERT(FALLP_EntryPoints);
811 
812         noOfEntryPoints = FALLP_EntryPoints[(targetModule->m_index)].numEntryPoints;
813         entryPointsList = FALLP_EntryPoints[(targetModule->m_index)].entryPointsList;
814 
815         GLOBALASSERT(noOfEntryPoints);
816 
817         /* just use the first entry point */
818         newPosition = entryPointsList[0].position;
819 
820         /* now set the object's new position and current module.
821            NB this is world position + a little extra in y to make sure */
822         {
823                 DYNAMICSBLOCK *dynPtr;
824 
825                 dynPtr = sbPtr->DynPtr;
826                 dynPtr->Position = newPosition;
827 
828                 dynPtr->Position.vx += targetModule->m_world.vx;
829                 dynPtr->Position.vy += targetModule->m_world.vy;
830                 dynPtr->Position.vz += targetModule->m_world.vz;
831 
832                 dynPtr->PrevPosition = dynPtr->Position;
833 
834         }
835         /* finally, update the sb's module */
836         renderModule=ModuleFromPosition(&sbPtr->DynPtr->Position,NULL);
837 
838         sbPtr->containingModule = renderModule;
839 
840 }
841 
842 
843 
844 
845 /*------------------------Patrick 14/1/97-----------------------------
846   This function returns the module in which a given world-space
847   position is located.  A starting point for the search may also be
848   passed, so that the following search pattern is used:
849   1. is the location in the indicated starting module.
850   2. is the location in any of the starting module's visible-links.
851   3. finally, all modules in the environment are searched until
852      a containing module is found.
853 
854   If no module is found, a null module pointer is returned.
855   NB only 'physical' modules are returned, ie infinite and
856   terminator modules are ignored.
857 
858   The function is designed to be used for objects which move over small
859   distances, and for which a recently containing module is known (eg
860   avp aliens).... so that the first stage of the search will be successful
861   in the majority of cases, and the third stage rarely used.
862   Note that the fn returns the first module which contains the given
863   point, so problems may arise if the point exists in more than one
864   module. This should be ok for environments like avp, where v-linking
865   is not used.
866   --------------------------------------------------------------------*/
867 
868 static int WorldPointIsInModule_WithTolerance(MODULE* thisModule, VECTORCH* thisPoint);
869 static MODULE* ModuleFromPosition_WithTolerance(VECTORCH *position, MODULE* startingModule);
870 
ModuleFromPosition(VECTORCH * position,MODULE * startingModule)871 MODULE* ModuleFromPosition(VECTORCH *position, MODULE* startingModule)
872 {
873         if((startingModule) && (ModuleIsPhysical(startingModule)))
874         {
875                 /* first test for the most trivial, and most likely case */
876                 if(WorldPointIsInModule(startingModule, position))
877                         return startingModule;
878 
879                 /* now test visible-linked modules (If there are any) */
880                 {
881                         VMODULE *vlPtr = startingModule->m_vmptr;
882                         if(vlPtr)
883                         {
884                                 while(vlPtr->vmod_type != vmtype_term)
885                                 {
886                                         MODULE *mPtr = vlPtr->vmod_mref.mref_ptr;
887                                         if(mPtr)
888                                         {
889                                                 if(ModuleIsPhysical(mPtr))
890                                                         if(WorldPointIsInModule(mPtr, position))
891                                                                 return mPtr;
892                                         }
893                                         vlPtr++;
894                                 }
895                         }
896                 }
897         }
898 
899         /* either there is no starting module; the starting module is not physical;
900         we are not in the starting module and it has no visibility-linked modules;
901         or we haven't found a module yet: so search the entire module list */
902         {
903                 extern SCENE Global_Scene;
904                 extern SCENEMODULE **Global_ModulePtr;
905                 extern int ModuleArraySize;
906                 MODULE **moduleListPointer;
907                 int moduleCounter;
908 
909                 LOCALASSERT(ModuleArraySize);
910                 LOCALASSERT(Global_ModulePtr);
911 
912                 moduleListPointer = (Global_ModulePtr[Global_Scene])->sm_marray;
913                 moduleCounter = ModuleArraySize;
914                 while(moduleCounter>0)
915                 {
916                         MODULE *thisModule;
917 
918                         thisModule = *moduleListPointer++;
919                         if(ModuleIsPhysical(thisModule))
920                                 if(WorldPointIsInModule(thisModule, position))
921                                         return (thisModule);
922 
923                         moduleCounter--;
924                 }
925         }
926 
927         /* couldn't find a module */
928 		/*Try with slightly larger module bounding boxes*/
929         return ModuleFromPosition_WithTolerance(position,startingModule);
930 }
931 
932 
933 /*-----------------------Patrick 14/1/97---------------------------
934 Returns 1 if the given WORLD point is in a given module,
935 or 0 otherwise.
936 
937 NB the bizzare structure of this function produces optimum pentium
938 instructions... apparently.
939 -------------------------------------------------------------------*/
WorldPointIsInModule(MODULE * thisModule,VECTORCH * thisPoint)940 static int WorldPointIsInModule(MODULE* thisModule, VECTORCH* thisPoint)
941 {
942         VECTORCH localpoint = *thisPoint;
943         localpoint.vx -= thisModule->m_world.vx;
944         localpoint.vy -= thisModule->m_world.vy;
945         localpoint.vz -= thisModule->m_world.vz;
946 
947         if(localpoint.vx <= thisModule->m_maxx)
948                 if(localpoint.vx >= thisModule->m_minx)
949                         if(localpoint.vy <= thisModule->m_maxy)
950                                 if(localpoint.vy >= thisModule->m_miny)
951                                         if(localpoint.vz <= thisModule->m_maxz)
952                                                 if(localpoint.vz >= thisModule->m_minz)
953                                                         return 1;
954         return 0;
955 }
956 
957 
958 
959 
960 #define ModuleFromPositionTolerance 50
ModuleFromPosition_WithTolerance(VECTORCH * position,MODULE * startingModule)961 static MODULE* ModuleFromPosition_WithTolerance(VECTORCH *position, MODULE* startingModule)
962 {
963         if((startingModule) && (ModuleIsPhysical(startingModule)))
964         {
965                 /* first test for the most trivial, and most likely case */
966                 if(WorldPointIsInModule_WithTolerance(startingModule, position))
967                         return startingModule;
968 
969                 /* now test visible-linked modules (If there are any) */
970                 {
971                         VMODULE *vlPtr = startingModule->m_vmptr;
972                         if(vlPtr)
973                         {
974                                 while(vlPtr->vmod_type != vmtype_term)
975                                 {
976                                         MODULE *mPtr = vlPtr->vmod_mref.mref_ptr;
977                                         if(mPtr)
978                                         {
979                                                 if(ModuleIsPhysical(mPtr))
980                                                         if(WorldPointIsInModule_WithTolerance(mPtr, position))
981                                                                 return mPtr;
982                                         }
983                                         vlPtr++;
984                                 }
985                         }
986                 }
987         }
988 
989         /* either there is no starting module; the starting module is not physical;
990         we are not in the starting module and it has no visibility-linked modules;
991         or we haven't found a module yet: so search the entire module list */
992         {
993                 extern SCENE Global_Scene;
994                 extern SCENEMODULE **Global_ModulePtr;
995                 extern int ModuleArraySize;
996                 MODULE **moduleListPointer;
997                 int moduleCounter;
998 
999                 LOCALASSERT(ModuleArraySize);
1000                 LOCALASSERT(Global_ModulePtr);
1001 
1002                 moduleListPointer = (Global_ModulePtr[Global_Scene])->sm_marray;
1003                 moduleCounter = ModuleArraySize;
1004                 while(moduleCounter>0)
1005                 {
1006                         MODULE *thisModule;
1007 
1008                         thisModule = *moduleListPointer++;
1009                         if(ModuleIsPhysical(thisModule))
1010                                 if(WorldPointIsInModule_WithTolerance(thisModule, position))
1011                                         return (thisModule);
1012 
1013                         moduleCounter--;
1014                 }
1015         }
1016 
1017         /* couldn't find a module */
1018         return (MODULE *)0;
1019 }
1020 
1021 
WorldPointIsInModule_WithTolerance(MODULE * thisModule,VECTORCH * thisPoint)1022 static int WorldPointIsInModule_WithTolerance(MODULE* thisModule, VECTORCH* thisPoint)
1023 {
1024         VECTORCH localpoint = *thisPoint;
1025         localpoint.vx -= thisModule->m_world.vx;
1026         localpoint.vy -= thisModule->m_world.vy;
1027         localpoint.vz -= thisModule->m_world.vz;
1028 
1029         if(localpoint.vx <= thisModule->m_maxx + ModuleFromPositionTolerance)
1030                 if(localpoint.vx >= thisModule->m_minx - ModuleFromPositionTolerance)
1031                         if(localpoint.vy <= thisModule->m_maxy + ModuleFromPositionTolerance)
1032                                 if(localpoint.vy >= thisModule->m_miny - ModuleFromPositionTolerance)
1033                                         if(localpoint.vz <= thisModule->m_maxz + ModuleFromPositionTolerance)
1034                                                 if(localpoint.vz >= thisModule->m_minz - ModuleFromPositionTolerance)
1035                                                         return 1;
1036         return 0;
1037 }
1038 
1039 
1040 
1041 /*---------------------Patrick 14/1/97-----------------------------
1042 
1043                 SUPPORT FUNCTIONS FOR INANIMATE OBJECTS
1044 
1045   -----------------------------------------------------------------*/
1046 
1047 
1048 
1049 
1050 
1051 
1052 /*-----------------------Patrick 16/1/97---------------------------
1053 Inanimate object initialisation and behaviour and functions.
1054 -------------------------------------------------------------------*/
InitInanimateObject(void * bhdata,STRATEGYBLOCK * sbPtr)1055 void InitInanimateObject(void* bhdata, STRATEGYBLOCK *sbPtr)
1056 {
1057         TOOLS_DATA_INANIMATEOBJECT *toolsData = (TOOLS_DATA_INANIMATEOBJECT *)bhdata;
1058         INANIMATEOBJECT_STATUSBLOCK* objectstatusptr;
1059         enum DYNAMICS_TEMPLATE_ID inanimateDynamicsInitialiser;
1060         int i;
1061 
1062         LOCALASSERT(sbPtr->I_SBtype == I_BehaviourInanimateObject);
1063         LOCALASSERT(toolsData);
1064 
1065         /* create, initialise and attach a data block */
1066         objectstatusptr = (void *)AllocateMem(sizeof(INANIMATEOBJECT_STATUSBLOCK));
1067         if(!objectstatusptr)
1068         {
1069                 RemoveBehaviourStrategy(sbPtr);
1070         }
1071 
1072         sbPtr->SBdataptr = objectstatusptr;
1073         objectstatusptr->respawnTimer = 0;
1074         objectstatusptr->lifespanTimer = 0;
1075         objectstatusptr->explosionTimer = 0;
1076 
1077         /* these should be loaded */
1078         objectstatusptr->typeId = toolsData->typeId;
1079         objectstatusptr->subType = toolsData->subType;
1080 
1081         /* set default indestructibility */
1082         objectstatusptr->Indestructable = No;
1083         objectstatusptr->ghosted_object=0;
1084 
1085         /* set the default inanimate object dynamics template: Inanimate for single player,
1086         and Static for multiplayer
1087         NB some objects are always static, and initialised using
1088         the static dynamics template directly */
1089 //      if(AvP.Network==I_No_Network) inanimateDynamicsInitialiser = DYNAMICS_TEMPLATE_INANIMATE;
1090 //      else inanimateDynamicsInitialiser = DYNAMICS_TEMPLATE_STATIC;
1091         inanimateDynamicsInitialiser = DYNAMICS_TEMPLATE_INANIMATE;
1092 
1093         /* Initialise object's stats */
1094         {
1095                 NPC_DATA *NpcData;
1096 
1097                 //#warning Change Me!!!
1098 
1099                 NpcData=GetThisNpcData(I_NPC_DefaultInanimate);
1100                 LOCALASSERT(NpcData);
1101                 sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<<ONE_FIXED_SHIFT;
1102                 sbPtr->SBDamageBlock.Armour=NpcData->StartingStats.Armour<<ONE_FIXED_SHIFT;
1103                 sbPtr->SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags;
1104         }
1105 
1106         sbPtr->SBDamageBlock.Health*=toolsData->integrity;
1107 
1108         if(toolsData->triggering_event)
1109         {
1110                 objectstatusptr->event_target=(OBJECT_EVENT_TARGET*)AllocateMem(sizeof(OBJECT_EVENT_TARGET));
1111 
1112                 objectstatusptr->event_target->triggering_event=toolsData->triggering_event;
1113                 objectstatusptr->event_target->request=toolsData->event_request;
1114                 for(i=0;i<SB_NAME_LENGTH;i++) objectstatusptr->event_target->event_target_ID[i] = toolsData->event_target_ID[i];
1115                 objectstatusptr->event_target->event_target_sbptr=0;
1116         }
1117         else
1118         {
1119                 objectstatusptr->event_target=0;
1120         }
1121 
1122         objectstatusptr->explosionType=toolsData->explosionType;
1123 
1124         /* set inanimate-object-type-specific stuff...
1125         1. dynamics block allocation
1126         2. integrity */
1127         switch(objectstatusptr->typeId)
1128         {
1129                 case IOT_HitMeAndIllDestroyBase:
1130                 case IOT_Static:
1131                 {
1132                         sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_STATIC);
1133                         if(!sbPtr->DynPtr)
1134                         {
1135                                 RemoveBehaviourStrategy(sbPtr);
1136                                 return;
1137                         }
1138                         sbPtr->DynPtr->Mass = toolsData->mass;
1139                         if (toolsData->integrity > 20)
1140                         {
1141                                 objectstatusptr->Indestructable = Yes;
1142                                 sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY;
1143                         }
1144                         else if (toolsData->integrity < 1)
1145                         {
1146                                 sbPtr->integrity = 1; // die immediately
1147                         }
1148                         else
1149                         {
1150                                 sbPtr->integrity = (DEFAULT_OBJECT_INTEGRITY)*(toolsData->integrity);
1151                         }
1152                         break;
1153                 }
1154                 case IOT_Furniture:
1155                 {
1156                         sbPtr->DynPtr = AllocateDynamicsBlock(inanimateDynamicsInitialiser);
1157                         if(!sbPtr->DynPtr)
1158                         {
1159                                 RemoveBehaviourStrategy(sbPtr);
1160                                 return;
1161                         }
1162                         sbPtr->DynPtr->Mass = toolsData->mass;
1163                         if (toolsData->integrity > 20)
1164                         {
1165                                 objectstatusptr->Indestructable = Yes;
1166                                 sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY;
1167                         }
1168                         else if (toolsData->integrity < 1)
1169                         {
1170                                 sbPtr->integrity = 1; // die immediately
1171                         }
1172                         else
1173                         {
1174                                 sbPtr->integrity = (DEFAULT_OBJECT_INTEGRITY)*(toolsData->integrity);
1175                         }
1176                         break;
1177                 }
1178                 case IOT_Weapon:
1179                 {
1180                         sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_PICKUPOBJECT);
1181                         if(!sbPtr->DynPtr)
1182                         {
1183                                 RemoveBehaviourStrategy(sbPtr);
1184                                 return;
1185                         }
1186                         sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY;
1187 						if(objectstatusptr->subType==WEAPON_FLAMETHROWER)
1188 						{
1189 							//flamethrowers explode using a molotov explosion
1190 							objectstatusptr->explosionType=3;
1191 						}
1192                         break;
1193                 }
1194                 case IOT_Ammo:
1195                 {
1196                         sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_PICKUPOBJECT);
1197                         if(!sbPtr->DynPtr)
1198                         {
1199                                 RemoveBehaviourStrategy(sbPtr);
1200                                 return;
1201                         }
1202                         sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY;
1203 
1204 						if(objectstatusptr->subType==AMMO_FLAMETHROWER)
1205 						{
1206 							//flamethrowers explode using a molotov explosion
1207 							objectstatusptr->explosionType=3;
1208 						}
1209                         break;
1210                 }
1211                 case IOT_Health:
1212                 {
1213                         sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_PICKUPOBJECT);
1214 
1215                         if(!sbPtr->DynPtr)
1216                         {
1217                                 RemoveBehaviourStrategy(sbPtr);
1218                                 return;
1219                         }
1220 
1221                         sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY;
1222                         break;
1223                 }
1224                 case IOT_Armour:
1225                 {
1226                         sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_PICKUPOBJECT);
1227                         if(!sbPtr->DynPtr)
1228                         {
1229                                 RemoveBehaviourStrategy(sbPtr);
1230                                 return;
1231                         }
1232 
1233                         sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY;
1234                         break;
1235                 }
1236                 case IOT_Key:
1237                 {
1238                         sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_PICKUPOBJECT);
1239                         if(!sbPtr->DynPtr)
1240                         {
1241                                 RemoveBehaviourStrategy(sbPtr);
1242                                 return;
1243                         }
1244 
1245                         sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY;
1246                         break;
1247                 }
1248                 case IOT_BoxedSentryGun:
1249                 {
1250                         sbPtr->DynPtr = AllocateDynamicsBlock(inanimateDynamicsInitialiser);
1251                         if(!sbPtr->DynPtr)
1252                         {
1253                                 RemoveBehaviourStrategy(sbPtr);
1254                                 return;
1255                         }
1256 
1257                         sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY;
1258                         break;
1259                 }
1260                 case IOT_IRGoggles:
1261                 {
1262                         sbPtr->DynPtr = AllocateDynamicsBlock(inanimateDynamicsInitialiser);
1263                         if(!sbPtr->DynPtr)
1264                         {
1265                                 RemoveBehaviourStrategy(sbPtr);
1266                                 return;
1267                         }
1268                         sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY;
1269                         break;
1270                 }
1271                 case IOT_DataTape:
1272                 {
1273                         sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_STATIC);
1274                         if(!sbPtr->DynPtr)
1275                         {
1276                                 RemoveBehaviourStrategy(sbPtr);
1277                                 return;
1278                         }
1279                         sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY;
1280                         break;
1281                 }
1282         case IOT_MTrackerUpgrade:
1283                 {
1284                         sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_PICKUPOBJECT);
1285                         if(!sbPtr->DynPtr)
1286                         {
1287                                 RemoveBehaviourStrategy(sbPtr);
1288                                 return;
1289                         }
1290                         sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY;
1291                         break;
1292                 }
1293                 case IOT_PheromonePod:
1294                 {
1295                         sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_PICKUPOBJECT);
1296                         if(!sbPtr->DynPtr)
1297                         {
1298                                 RemoveBehaviourStrategy(sbPtr);
1299                                 return;
1300                         }
1301                         sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY;
1302                         break;
1303                 }
1304                 case IOT_SpecialPickupObject:
1305                 {
1306                         sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_PICKUPOBJECT);
1307                         if(!sbPtr->DynPtr)
1308                         {
1309                                 RemoveBehaviourStrategy(sbPtr);
1310                                 return;
1311                         }
1312                         if (toolsData->integrity > 20)
1313                         {
1314                                 objectstatusptr->Indestructable = Yes;
1315                                 sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY;
1316                         }
1317                         else if (toolsData->integrity < 1)
1318                         {
1319                                 sbPtr->integrity = 1; // die immediately
1320                         }
1321                         else
1322                         {
1323                                 sbPtr->integrity = (DEFAULT_OBJECT_INTEGRITY)*(toolsData->integrity);
1324                         }
1325                         break;
1326                 }
1327                 case IOT_FieldCharge:
1328                 {
1329                         sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_PICKUPOBJECT);
1330                         if(!sbPtr->DynPtr)
1331                         {
1332                                 RemoveBehaviourStrategy(sbPtr);
1333                                 return;
1334                         }
1335 
1336                         sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY;
1337                         break;
1338                 }
1339                 default:
1340                 {
1341                         LOCALASSERT(1==0);
1342                         break;
1343                 }
1344         }
1345         /*check to see if object is animated.*/
1346         {
1347                 TXACTRLBLK **pptxactrlblk;
1348                 int item_num;
1349                 int shape_num = toolsData->shapeIndex;
1350                 SHAPEHEADER *shptr = GetShapeData(shape_num);
1351                 pptxactrlblk = &objectstatusptr->inan_tac;
1352                 for(item_num = 0; item_num < shptr->numitems; item_num ++)
1353                 {
1354                         POLYHEADER *poly =  (POLYHEADER*)(shptr->items[item_num]);
1355                         LOCALASSERT(poly);
1356 
1357                         SetupPolygonFlagAccessForShape(shptr);
1358 
1359                         if((Request_PolyFlags((void *)poly)) & iflag_txanim)
1360                                 {
1361                                         TXACTRLBLK *pnew_txactrlblk;
1362 
1363                                         pnew_txactrlblk = AllocateMem(sizeof(TXACTRLBLK));
1364                                         if(pnew_txactrlblk)
1365                                         {
1366                                                 pnew_txactrlblk->tac_flags = 0;
1367                                                 pnew_txactrlblk->tac_item = item_num;
1368                                                 pnew_txactrlblk->tac_sequence = 0;
1369                                                 pnew_txactrlblk->tac_node = 0;
1370                                                 pnew_txactrlblk->tac_txarray = GetTxAnimArrayZ(shape_num, item_num);
1371                                                 pnew_txactrlblk->tac_txah_s = GetTxAnimHeaderFromShape(pnew_txactrlblk, shape_num);
1372 
1373                                                 *pptxactrlblk = pnew_txactrlblk;
1374                                                 pptxactrlblk = &pnew_txactrlblk->tac_next;
1375                                         }
1376                                         else *pptxactrlblk = NULL;
1377                                 }
1378                 }
1379                 *pptxactrlblk=0;
1380 
1381         }
1382 
1383         /* Initialise the dynamics block */
1384         {
1385                 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
1386                 GLOBALASSERT(dynPtr);
1387 
1388         dynPtr->PrevPosition = dynPtr->Position = toolsData->position;
1389                 dynPtr->OrientEuler = toolsData->orientation;
1390                 CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat);
1391                 TransposeMatrixCH(&dynPtr->OrientMat);
1392         }
1393 
1394         /* strategy block initialisation */
1395         sbPtr->shapeIndex = toolsData->shapeIndex;
1396         for(i=0;i<SB_NAME_LENGTH;i++) sbPtr->SBname[i] = toolsData->nameID[i];
1397 
1398         /* these must be initialised for respawning objects in multiplayer game */
1399         objectstatusptr->startingHealth = sbPtr->SBDamageBlock.Health;
1400         objectstatusptr->startingArmour = sbPtr->SBDamageBlock.Armour;
1401 
1402 		if(AvP.Network != I_No_Network)
1403 		{
1404 			//if in a network game , see if this is an allowable weapon
1405 			if(objectstatusptr->typeId==IOT_Weapon)
1406 			{
1407 				if((!netGameData.allowSmartgun && objectstatusptr->subType==WEAPON_SMARTGUN)||
1408 				   (!netGameData.allowFlamer && objectstatusptr->subType==WEAPON_FLAMETHROWER)||
1409 				   (!netGameData.allowSadar && objectstatusptr->subType==WEAPON_SADAR)||
1410 				   (!netGameData.allowGrenadeLauncher && objectstatusptr->subType==WEAPON_GRENADELAUNCHER)||
1411 				   (!netGameData.allowPistols && objectstatusptr->subType==WEAPON_MARINE_PISTOL)||
1412 				   (!netGameData.allowSmartDisc && objectstatusptr->subType==WEAPON_FRISBEE_LAUNCHER)||
1413 				   (!netGameData.allowMinigun && objectstatusptr->subType==WEAPON_MINIGUN))
1414 				{
1415                 	RemoveBehaviourStrategy(sbPtr);
1416                 	return;
1417 				}
1418 			}
1419 			if(objectstatusptr->typeId==IOT_Ammo)
1420 			{
1421 				if((!netGameData.allowSmartgun && objectstatusptr->subType==AMMO_SMARTGUN)||
1422 				   (!netGameData.allowFlamer && objectstatusptr->subType==AMMO_FLAMETHROWER)||
1423 				   (!netGameData.allowSadar && objectstatusptr->subType==AMMO_SADAR_TOW)||
1424 				   (!netGameData.allowGrenadeLauncher && objectstatusptr->subType==AMMO_GRENADE)||
1425 				   (!netGameData.allowPistols && objectstatusptr->subType==AMMO_MARINE_PISTOL_PC)||
1426 				   (!netGameData.allowSmartDisc && objectstatusptr->subType==AMMO_FRISBEE)||
1427 				   (!netGameData.allowMinigun && objectstatusptr->subType==AMMO_MINIGUN))
1428 				{
1429                 	RemoveBehaviourStrategy(sbPtr);
1430                 	return;
1431 				}
1432 			}
1433 		}
1434 }
1435 
InanimateObjectBehaviour(STRATEGYBLOCK * sbPtr)1436 void InanimateObjectBehaviour(STRATEGYBLOCK *sbPtr)
1437 {
1438         /* handle respawn timer here */
1439         INANIMATEOBJECT_STATUSBLOCK* objectstatusptr = sbPtr->SBdataptr;
1440         LOCALASSERT(objectstatusptr);
1441 
1442         LOCALASSERT(!(objectstatusptr->respawnTimer<0)); /* this should never happen */
1443 
1444 		/* Lock disc pickups in place. */
1445 		if ((objectstatusptr->typeId == IOT_Ammo)
1446 			&&(objectstatusptr->subType == (int)AMMO_PRED_DISC)) {
1447 
1448 			sbPtr->DynPtr->LinVelocity.vx=0;
1449 			sbPtr->DynPtr->LinVelocity.vy=0;
1450 			sbPtr->DynPtr->LinVelocity.vz=0;
1451 
1452 			sbPtr->DynPtr->LinImpulse.vx=0;
1453 			sbPtr->DynPtr->LinImpulse.vy=0;
1454 			sbPtr->DynPtr->LinImpulse.vz=0;
1455 		}
1456 
1457         if(objectstatusptr->inan_tac)
1458         {
1459                 DISPLAYBLOCK* dptr = sbPtr->SBdptr;
1460 
1461                 /*deal with texture animation*/
1462                 if(dptr)
1463                 {
1464                         if(!dptr->ObTxAnimCtrlBlks)
1465                                 {
1466                                         dptr->ObTxAnimCtrlBlks = objectstatusptr->inan_tac;
1467                                 }
1468                 }
1469 
1470         }
1471 
1472         if(objectstatusptr->explosionTimer)
1473         {
1474                 //the object is about to explode
1475                 if(objectstatusptr->explosionStartFrame==GlobalFrameCounter)
1476                 {
1477                         //the explosion was triggered earlier this frame
1478                         //therefore don't bother altering the timer until next frame
1479                         return;
1480                 }
1481 
1482                 objectstatusptr->explosionTimer-=NormalFrameTime;
1483                 if(objectstatusptr->explosionTimer<=0)
1484                 {
1485                         objectstatusptr->explosionTimer=-1;
1486                         InanimateObjectIsDamaged(sbPtr,0,0);
1487                         return;
1488                 }
1489 
1490         }
1491 
1492         if(AvP.Network!=I_No_Network)
1493         {
1494                 //see if dropped weapons have timed out
1495                 if(objectstatusptr->lifespanTimer>0)
1496                 {
1497                         objectstatusptr->lifespanTimer-=NormalFrameTime;
1498                         if(objectstatusptr->lifespanTimer<=0)
1499                         {
1500                                 FragmentInanimateObject(sbPtr);
1501                                 DestroyAnyStrategyBlock(sbPtr);
1502                         }
1503                         return;
1504                 }
1505         }
1506 
1507         /* do nothing if the timer is zero */
1508         if(objectstatusptr->respawnTimer==0 || objectstatusptr->respawnTimer==OBJECT_RESPAWN_NO_RESPAWN) return;
1509 
1510         /* textprint("RESPAWN TIMER %d \n", objectstatusptr->respawnTimer); */
1511         /* If we get here, the object is in a respawn state:
1512         this should only happen in a net-game */
1513         LOCALASSERT(AvP.Network!=I_No_Network);
1514         LOCALASSERT(!sbPtr->SBdptr);
1515         LOCALASSERT(!sbPtr->maintainVisibility);
1516 
1517         objectstatusptr->respawnTimer -= NormalFrameTime;
1518         if(objectstatusptr->respawnTimer<=0)
1519         {
1520                 /* time to respawn, then */
1521                 RespawnInanimateObject(sbPtr);
1522                 objectstatusptr->respawnTimer=0;
1523         }
1524 }
1525 
1526 /* this global flag is used to distinguish between messages from the host,
1527 and locally caused damage */
1528 int InanimateDamageFromNetHost = 0;
1529 
1530 
InanimateObjectIsDamaged(STRATEGYBLOCK * sbPtr,DAMAGE_PROFILE * damage,int multiple)1531 void InanimateObjectIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple)
1532 {
1533         INANIMATEOBJECT_STATUSBLOCK* objectstatusptr = sbPtr->SBdataptr;
1534         LOCALASSERT(objectstatusptr);
1535 
1536         if((AvP.Network==I_Peer)&&(!InanimateDamageFromNetHost))
1537         {
1538                 /* this means that the damage was generated locally in a net-game:
1539                 in this case, just send a damage message to the host */
1540                 AddNetMsg_InanimateObjectDamaged(sbPtr,damage,multiple);
1541                 return;
1542         }
1543         else if(AvP.Network==I_Host)
1544         {
1545                 /* if we're the host, inform everyone that the object is dead */
1546                 if(sbPtr->SBDamageBlock.Health <= 0) AddNetMsg_InanimateObjectDestroyed(sbPtr);
1547         }
1548 
1549 		if(sbPtr->SBflags.please_destroy_me)
1550 		{
1551 			//object has already been destroyed , so ignore any further damage
1552 			return;
1553 		}
1554 
1555         //if object has been destroyed , see if it has a target that it needs to notify
1556         if(objectstatusptr->event_target)
1557         {
1558                 if(sbPtr->SBDamageBlock.Health <= 0 && !objectstatusptr->Indestructable)
1559                 {
1560                         if(objectstatusptr->event_target->triggering_event & ObjectEventFlag_Destroyed)
1561                         {
1562                                 RequestState(objectstatusptr->event_target->event_target_sbptr,objectstatusptr->event_target->request,0);
1563                         }
1564                 }
1565         }
1566 
1567         if (!objectstatusptr->Indestructable && objectstatusptr->explosionType)
1568         {
1569 
1570 
1571         	if(InanimateDamageFromNetHost)
1572 			{
1573         		//do explosion effect , without the damage
1574         		switch(objectstatusptr->explosionType)
1575 				{
1576 					case 1:
1577 					{
1578         		        //small explosion
1579 						MakeVolumetricExplosionAt(&(sbPtr->DynPtr->Position),EXPLOSION_SMALL_NOCOLLISIONS);
1580 
1581 						Explosion_SoundData.position=sbPtr->DynPtr->Position;
1582 
1583 						Sound_Play(SID_NADEEXPLODE,"n",&Explosion_SoundData);
1584 
1585 						break;
1586 					}
1587 					case 2:
1588 					{
1589         		        //big explosion
1590 						MakeVolumetricExplosionAt(&(sbPtr->DynPtr->Position),EXPLOSION_HUGE_NOCOLLISIONS);
1591 
1592 						Explosion_SoundData.position=sbPtr->DynPtr->Position;
1593 
1594 						Sound_Play(SID_NICE_EXPLOSION,"n",&Explosion_SoundData);
1595 
1596 						break;
1597 					}
1598 					case 3:
1599         		    {
1600         		        //molotov explosion
1601 						MakeVolumetricExplosionAt(&(sbPtr->DynPtr->Position),EXPLOSION_MOLOTOV);
1602 
1603 						Explosion_SoundData.position=sbPtr->DynPtr->Position;
1604 
1605 						Sound_Play(SID_NADEEXPLODE,"n",&Explosion_SoundData);
1606 
1607 						break;
1608 					}
1609 				}
1610         	}
1611 			else
1612 			{
1613         		if(objectstatusptr->explosionTimer==0)
1614         		{
1615         		        if(sbPtr->SBDamageBlock.Health <= 0)
1616         		        {
1617         		                //start explosion timer
1618         		                //this gives a slight time delay for object destruction, to allow for chain reactions
1619         		                //(rather than all explosive objects going up in one frame)
1620         		                objectstatusptr->explosionTimer=ONE_FIXED/10;
1621         		                objectstatusptr->explosionStartFrame=GlobalFrameCounter;
1622         		                return;
1623         		        }
1624         		}
1625         		else if(objectstatusptr->explosionTimer<0)
1626         		{
1627         		        //time for the explosion
1628         		        objectstatusptr->explosionTimer=0;
1629         		        switch(objectstatusptr->explosionType)
1630 						{
1631 							case 1:
1632 							{
1633         		                //small explosion
1634         		                HandleEffectsOfExplosion
1635         		                (
1636         		                        sbPtr,
1637         		                        &(sbPtr->DynPtr->Position),
1638         		                        5000,
1639         		                        &SmallExplosionDamage,
1640         		                        0
1641         		                );
1642 								Explosion_SoundData.position=sbPtr->DynPtr->Position;
1643 
1644 								Sound_Play(SID_NADEEXPLODE,"n",&Explosion_SoundData);
1645 
1646 								break;
1647 							}
1648 							case 2:
1649 							{
1650         		                //big explosion
1651         		                HandleEffectsOfExplosion
1652         		                (
1653         		                        sbPtr,
1654         		                        &(sbPtr->DynPtr->Position),
1655         		                        10000,
1656         		                        &BigExplosionDamage,
1657         		                        0
1658         		                );
1659 								Explosion_SoundData.position=sbPtr->DynPtr->Position;
1660 
1661 								Sound_Play(SID_NICE_EXPLOSION,"n",&Explosion_SoundData);
1662 
1663 								break;
1664 							}
1665 							case 3:
1666         		            {
1667         		                //molotov explosion
1668         		                HandleEffectsOfExplosion
1669         		                (
1670         		                        sbPtr,
1671         		                        &(sbPtr->DynPtr->Position),
1672 										TemplateAmmo[AMMO_MOLOTOV].MaxRange,
1673 								 		&TemplateAmmo[AMMO_MOLOTOV].MaxDamage[AvP.Difficulty],
1674 										TemplateAmmo[AMMO_MOLOTOV].ExplosionIsFlat
1675         		                );
1676 								Explosion_SoundData.position=sbPtr->DynPtr->Position;
1677 
1678 								Sound_Play(SID_NADEEXPLODE,"n",&Explosion_SoundData);
1679 
1680 								break;
1681 							}
1682 						}
1683 
1684         		        //set health to zero (in case object has recovered in the delay)
1685         		        sbPtr->SBDamageBlock.Health=0;
1686         		}
1687         		else
1688         		{
1689         		        //currently in explosion count down , so wait
1690         		        return;
1691         		}
1692 			}
1693         }
1694 
1695 
1696         switch(objectstatusptr->typeId)
1697         {
1698                 case IOT_Static:
1699                 {
1700                         if (!objectstatusptr->Indestructable)
1701                         {
1702                                 if(sbPtr->SBDamageBlock.Health <= 0)
1703                                 {
1704                                         FragmentInanimateObject(sbPtr);
1705                                         if(AvP.Network==I_No_Network) DestroyAnyStrategyBlock(sbPtr);
1706                                         else KillFragmentalObjectForRespawn(sbPtr);
1707                                 }
1708                         }
1709                         break;
1710                 }
1711                 case IOT_Furniture:
1712                 {
1713                         if (!objectstatusptr->Indestructable)
1714                         {
1715                                 if(sbPtr->SBDamageBlock.Health <= 0)
1716                                 {
1717                                         FragmentInanimateObject(sbPtr);
1718                                         DestroyAnyStrategyBlock(sbPtr);
1719                                 }
1720                         }
1721                         break;
1722                 }
1723                 case IOT_Weapon:
1724                 {
1725                         if(sbPtr->SBDamageBlock.Health <= 0)
1726                         {
1727                                 FragmentInanimateObject(sbPtr);
1728                                 if(AvP.Network==I_No_Network) DestroyAnyStrategyBlock(sbPtr);
1729                                 else KillInanimateObjectForRespawn(sbPtr);
1730                         }
1731                         break;
1732                 }
1733                 case IOT_Ammo:
1734                 {
1735                         if(sbPtr->SBDamageBlock.Health <= 0)
1736                         {
1737                                 FragmentInanimateObject(sbPtr);
1738                                 if(AvP.Network==I_No_Network) DestroyAnyStrategyBlock(sbPtr);
1739                                 else KillInanimateObjectForRespawn(sbPtr);
1740                         }
1741                         break;
1742                 }
1743                 case IOT_Health:
1744                 {
1745                         if(sbPtr->SBDamageBlock.Health <= 0)
1746                         {
1747                                 FragmentInanimateObject(sbPtr);
1748                                 if(AvP.Network==I_No_Network) DestroyAnyStrategyBlock(sbPtr);
1749                                 else KillInanimateObjectForRespawn(sbPtr);
1750                         }
1751                         break;
1752                 }
1753                 case IOT_Armour:
1754                 {
1755                         if(sbPtr->SBDamageBlock.Health <= 0)
1756                         {
1757                                 FragmentInanimateObject(sbPtr);
1758                                 if(AvP.Network==I_No_Network) DestroyAnyStrategyBlock(sbPtr);
1759                                 else KillInanimateObjectForRespawn(sbPtr);
1760                         }
1761                         break;
1762                 }
1763                 case IOT_Key:
1764                 {
1765                         /* do nothing */
1766                         break;
1767                 }
1768                 case IOT_BoxedSentryGun:
1769                 {
1770                         if(sbPtr->SBDamageBlock.Health <= 0)
1771                         {
1772                                 ExplodeInanimateObject(sbPtr);
1773                                 if(AvP.Network==I_No_Network) DestroyAnyStrategyBlock(sbPtr);
1774                                 else KillInanimateObjectForRespawn(sbPtr);
1775                         }
1776                         break;
1777                 }
1778                 case IOT_IRGoggles:
1779                 {
1780                         if(sbPtr->SBDamageBlock.Health <= 0)
1781                         {
1782                                 ExplodeInanimateObject(sbPtr);
1783                                 if(AvP.Network==I_No_Network) DestroyAnyStrategyBlock(sbPtr);
1784                                 else KillInanimateObjectForRespawn(sbPtr);
1785                         }
1786                         break;
1787                 }
1788                 case IOT_DataTape:
1789                 {
1790                         /* do nothing */
1791                         break;
1792                 }
1793         case IOT_MTrackerUpgrade:
1794                 {
1795                         if(sbPtr->SBDamageBlock.Health <= 0)
1796                         {
1797                                 ExplodeInanimateObject(sbPtr);
1798                                 if(AvP.Network==I_No_Network) DestroyAnyStrategyBlock(sbPtr);
1799                                 else KillInanimateObjectForRespawn(sbPtr);
1800                         }
1801                         break;
1802                 }
1803                 case IOT_PheromonePod:
1804                 {
1805                         if(sbPtr->SBDamageBlock.Health <= 0)
1806                         {
1807                                 ExplodeInanimateObject(sbPtr);
1808                                 if(AvP.Network==I_No_Network) DestroyAnyStrategyBlock(sbPtr);
1809                                 else KillInanimateObjectForRespawn(sbPtr);
1810                         }
1811                         break;
1812                 }
1813                 case IOT_SpecialPickupObject:
1814                 {
1815                         if (!objectstatusptr->Indestructable)
1816 						{
1817                         	if(sbPtr->SBDamageBlock.Health <= 0)
1818                         	{
1819                         	        FragmentInanimateObject(sbPtr);
1820                         	        if(AvP.Network==I_No_Network) DestroyAnyStrategyBlock(sbPtr);
1821                         	        else KillInanimateObjectForRespawn(sbPtr);
1822                         	}
1823                         }
1824                         break;
1825                 }
1826                 case IOT_HitMeAndIllDestroyBase:
1827                 {
1828                         if (damage->Penetrative>0) {
1829                                 /* Destroy base. */
1830                                 if (AvP.DestructTimer==-1) {
1831                                         textprint("Boom!  You've blown up the base!\n");
1832                                         ActivateSelfDestructSequence(60);
1833                                         /* Dummy switch hack. */
1834                                         {
1835                                                 STRATEGYBLOCK *evil_switch_SBPtr;
1836                                                 char Evil_Switch_SBname[] = {0x46,0xb9,0x01,0xf0,0x63,0xe4,0x56,0x0,};
1837 
1838                                                 evil_switch_SBPtr=FindSBWithName(Evil_Switch_SBname);
1839 
1840                                                 GLOBALASSERT(evil_switch_SBPtr);
1841 
1842                                                 RequestState(evil_switch_SBPtr,1,Player->ObStrategyBlock);
1843                                         }
1844                                 }
1845                         }
1846                         break;
1847                 }
1848                 case IOT_FieldCharge:
1849                 {
1850                         if(sbPtr->SBDamageBlock.Health <= 0)
1851                         {
1852                                 FragmentInanimateObject(sbPtr);
1853                                 if(AvP.Network==I_No_Network) DestroyAnyStrategyBlock(sbPtr);
1854                                 else KillInanimateObjectForRespawn(sbPtr);
1855                         }
1856                         break;
1857                 }
1858                 default:
1859                 {
1860                         LOCALASSERT(1==0);
1861                         break;
1862                 }
1863         }
1864 }
1865 
1866 #define ObjectRequest_AdjustIntegrity 0x00000001
SendRequestToInanimateObject(STRATEGYBLOCK * sbptr,BOOL state,int extended_data)1867 void SendRequestToInanimateObject(STRATEGYBLOCK* sbptr,BOOL state,int extended_data)
1868 {
1869         INANIMATEOBJECT_STATUSBLOCK* objectstatusptr = sbptr->SBdataptr;
1870         GLOBALASSERT(objectstatusptr);
1871         GLOBALASSERT((sbptr->I_SBtype == I_BehaviourInanimateObject));
1872 
1873 
1874         if(state)
1875         {
1876                 if(extended_data & ObjectRequest_AdjustIntegrity)
1877                 {
1878                         int new_integrity=(extended_data>>7)&0xff;
1879                         sbptr->SBDamageBlock.Health=(10<<ONE_FIXED_SHIFT)*new_integrity;
1880                         sbptr->integrity = DEFAULT_OBJECT_INTEGRITY*new_integrity;
1881 
1882                         if(new_integrity>20)
1883                                 objectstatusptr->Indestructable = Yes;
1884                         else
1885                                 objectstatusptr->Indestructable = No;
1886 
1887                         if(sbptr->integrity==0)
1888                         {
1889                                 //destroy the object by applying some damage to it
1890                                 InanimateObjectIsDamaged(sbptr, &certainDeath, ONE_FIXED);
1891                         }
1892                 }
1893         }
1894 
1895 }
1896 
FragmentInanimateObject(STRATEGYBLOCK * sbPtr)1897 static void FragmentInanimateObject(STRATEGYBLOCK *sbPtr)
1898 {
1899         MakeFragments(sbPtr);
1900 }
1901 
ExplodeInanimateObject(STRATEGYBLOCK * sbPtr)1902 static void ExplodeInanimateObject(STRATEGYBLOCK *sbPtr)
1903 {
1904         Sound_Play(SID_EXPLOSION,"d",&(sbPtr->DynPtr->Position));
1905 }
1906 
1907 /*-------------------Patrick 30/4/96-----------------------
1908   A couple of functions for     supporting respawning objects
1909   in network games...
1910   ---------------------------------------------------------*/
RespawnInanimateObject(STRATEGYBLOCK * sbPtr)1911 static void RespawnInanimateObject(STRATEGYBLOCK *sbPtr)
1912 {
1913         INANIMATEOBJECT_STATUSBLOCK* objectstatusptr = sbPtr->SBdataptr;
1914         LOCALASSERT(objectstatusptr);
1915 
1916         sbPtr->maintainVisibility = 1;
1917         MakeObjectNear(sbPtr);
1918 
1919         /* must respawn health too... */
1920         sbPtr->SBDamageBlock.Health = objectstatusptr->startingHealth;
1921         sbPtr->SBDamageBlock.Armour = objectstatusptr->startingArmour;
1922 
1923 }
1924 
KillInanimateObjectForRespawn(STRATEGYBLOCK * sbPtr)1925 void KillInanimateObjectForRespawn(STRATEGYBLOCK *sbPtr)
1926 {
1927         INANIMATEOBJECT_STATUSBLOCK* objectstatusptr = sbPtr->SBdataptr;
1928         LOCALASSERT(objectstatusptr);
1929         LOCALASSERT(AvP.Network!=I_No_Network);
1930 
1931         /* make the object invisible, and remove it from visibility management */
1932         if(!objectstatusptr->lifespanTimer)
1933         {
1934                 sbPtr->maintainVisibility = 0;
1935                 if(sbPtr->SBdptr) MakeObjectFar(sbPtr);
1936 
1937 				if(netGameData.timeForRespawn>0)
1938                 	objectstatusptr->respawnTimer = netGameData.timeForRespawn*ONE_FIXED;
1939 				else
1940                 	objectstatusptr->respawnTimer = OBJECT_RESPAWN_NO_RESPAWN;
1941         }
1942         else
1943         {
1944                 //get rid of this object permanently
1945                 DestroyAnyStrategyBlock(sbPtr);
1946 
1947         }
1948 
1949 }
1950 
KillFragmentalObjectForRespawn(STRATEGYBLOCK * sbPtr)1951 void KillFragmentalObjectForRespawn(STRATEGYBLOCK *sbPtr)
1952 {
1953         INANIMATEOBJECT_STATUSBLOCK* objectstatusptr = sbPtr->SBdataptr;
1954         LOCALASSERT(objectstatusptr);
1955         LOCALASSERT(AvP.Network!=I_No_Network);
1956 
1957         /* make the object invisible, and remove it from visibility management */
1958         sbPtr->maintainVisibility = 0;
1959         if(sbPtr->SBdptr) MakeObjectFar(sbPtr);
1960 
1961         /* KJL 12:44:23 24/05/98 -
1962 
1963                 Set the respawn counter to be the max allowable, so that if all the
1964         respawn counters are set to zero, it forces all the objects that have been
1965         destroyed (eg. glass) to respawn simultaneously.
1966 
1967         Not a perfect solution: the object will respawn in 9.1 hours on its own. */
1968 
1969         objectstatusptr->respawnTimer = OBJECT_RESPAWN_NO_RESPAWN;
1970 
1971 }
1972 
RespawnAllObjects(void)1973 void RespawnAllObjects(void)
1974 {
1975         int i;
1976 
1977         LOCALASSERT(AvP.Network!=I_No_Network);
1978 
1979         for (i=0; i<NumActiveStBlocks; i++)
1980         {
1981                 STRATEGYBLOCK *sbPtr = ActiveStBlockList[i];
1982 
1983                 if(sbPtr->I_SBtype == I_BehaviourInanimateObject)
1984                 {
1985                         INANIMATEOBJECT_STATUSBLOCK* objectStatusPtr = sbPtr->SBdataptr;
1986                         LOCALASSERT(objectStatusPtr);
1987 
1988                         if(objectStatusPtr->respawnTimer!=0)
1989                         {
1990                                 RespawnInanimateObject(sbPtr);
1991                                 objectStatusPtr->respawnTimer=0;
1992                         }
1993                 }
1994                 else if(sbPtr->I_SBtype == I_BehaviourPlacedLight)
1995                 {
1996                         RespawnLight(sbPtr);
1997                 }
1998         }
1999 }
2000 
RespawnAllPickups(void)2001 void RespawnAllPickups(void)
2002 {
2003 	int i;
2004 
2005 	LOCALASSERT(AvP.Network!=I_No_Network);
2006 
2007 	for (i=0; i<NumActiveStBlocks; i++)
2008 	{
2009 		STRATEGYBLOCK *sbPtr = ActiveStBlockList[i];
2010 
2011 		if(sbPtr->I_SBtype == I_BehaviourInanimateObject)
2012 		{
2013 			INANIMATEOBJECT_STATUSBLOCK* objectStatusPtr = sbPtr->SBdataptr;
2014 			LOCALASSERT(objectStatusPtr);
2015 
2016 			if(objectStatusPtr->typeId==IOT_Weapon ||
2017 			   objectStatusPtr->typeId==IOT_Ammo ||
2018 			   objectStatusPtr->typeId==IOT_Health ||
2019 			   objectStatusPtr->typeId==IOT_Armour ||
2020 			   objectStatusPtr->typeId==IOT_FieldCharge)
2021 			{
2022 				if(objectStatusPtr->respawnTimer!=0)
2023 				{
2024 					RespawnInanimateObject(sbPtr);
2025 					objectStatusPtr->respawnTimer=0;
2026 				}
2027 			}
2028 		}
2029 	}
2030 }
2031 
IdentifyObject(STRATEGYBLOCK * sbPtr)2032 void IdentifyObject(STRATEGYBLOCK *sbPtr) {
2033 
2034         if (sbPtr==NULL) {
2035                 textprint("Object is NULL!\n");
2036                 return;
2037         }
2038 
2039         if (sbPtr->I_SBtype == I_BehaviourInanimateObject) {
2040                 INANIMATEOBJECT_STATUSBLOCK* objStatPtr = sbPtr->SBdataptr;
2041 
2042                 switch(objStatPtr->typeId)
2043                 {
2044                         case(IOT_Weapon):
2045                         {
2046                                 switch(objStatPtr->subType)
2047                                 {
2048                                         case WEAPON_PULSERIFLE:
2049                                         {
2050                                                 textprint("Object is a Pulse Rifle.\n");
2051                                                 return;
2052                                         }
2053                                         case WEAPON_AUTOSHOTGUN:
2054                                         {
2055                                                 textprint("Object is an Autoshotgun.\n");
2056                                                 return;
2057                                         }
2058                                         case WEAPON_SMARTGUN:
2059                                         {
2060                                                 textprint("Object is a Smartgun.\n");
2061                                                 return;
2062                                         }
2063                                         case WEAPON_FLAMETHROWER:
2064                                         {
2065                                                 textprint("Object is a Flamethrower.\n");
2066                                                 return;
2067                                         }
2068                                         case WEAPON_PLASMAGUN:
2069                                         {
2070                                                 textprint("Object is a Plasmagun!\n");
2071                                                 return;
2072                                         }
2073                                         case WEAPON_SADAR:
2074                                         {
2075                                                 textprint("Object is a Sadar.\n");
2076                                                 return;
2077                                         }
2078                                         case WEAPON_GRENADELAUNCHER:
2079                                         {
2080                                                 textprint("Object is a Grenade Launcher.\n");
2081                                                 return;
2082                                         }
2083                                         case WEAPON_MINIGUN:
2084                                         {
2085                                                 textprint("Object is a Minigun.\n");
2086                                                 return;
2087                                         }
2088 
2089                                         default:
2090                                                 textprint("Object is unknown weapon (subtype %d).\n",(int)objStatPtr->subType);
2091                                                 break;
2092                                 }
2093                                 break;
2094                         }
2095                         case(IOT_Ammo):
2096                         {
2097                                 switch(objStatPtr->subType)
2098                                 {
2099                                         case AMMO_10MM_CULW:
2100                                         {
2101                                                 textprint("Object is Pulse Rifle ammo.\n");
2102                                                 break;
2103                                         }
2104                                         case AMMO_SHOTGUN:
2105                                         {
2106                                                 textprint("Object is Shotgun ammo.\n");
2107                                                 break;
2108                                         }
2109                                         case AMMO_SMARTGUN:
2110                                         {
2111                                                 textprint("Object is Smartgun ammo.\n");
2112                                                 break;
2113                                         }
2114                                         case AMMO_FLAMETHROWER:
2115                                         {
2116                                                 textprint("Object is Flamethrower ammo.\n");
2117                                                 break;
2118                                         }
2119                                         case AMMO_PLASMA:
2120                                         {
2121                                                 textprint("Object is Plasmagun ammo!\n");
2122                                                 break;
2123                                         }
2124                                         case AMMO_SADAR_TOW:
2125                                         {
2126                                                 textprint("Object is Sadar ammo.\n");
2127                                                 break;
2128                                         }
2129                                         case AMMO_GRENADE:
2130                                         {
2131                                                 textprint("Object is Grenade Launcher ammo.\n");
2132                                                 break;
2133                                         }
2134                                         case AMMO_MINIGUN:
2135                                         {
2136                                                 textprint("Object is Minigun ammo.\n");
2137                                                 break;
2138                                         }
2139                                         default:
2140                                                 textprint("Object is unlisted ammo (subtype %d).\n",(int)objStatPtr->subType);
2141                                                 break;
2142                                 }
2143 
2144                                 break;
2145                         }
2146                         case(IOT_Health):
2147                         {
2148                                 textprint("Object is health.\n");
2149                                 break;
2150                         }
2151                         case(IOT_Armour):
2152                         {
2153                                 textprint("Object is armour.\n");
2154                                 break;
2155                         }
2156                         case(IOT_FieldCharge):
2157                         {
2158                                 textprint("Object is field charge powerup.\n");
2159                                 break;
2160                         }
2161                         default:
2162                         {
2163                                 textprint("Object is unlisted subtype (%d).\n",(int)objStatPtr->subType);
2164                                 break;
2165                         }
2166                 }
2167         } else {
2168                 switch(sbPtr->I_SBtype) {
2169                         case I_BehaviourMarine:
2170                         {
2171                                 textprint("Object is a marine.\n");
2172                                 textprint("Marine is in %s\n",sbPtr->containingModule->name);
2173                                 break;
2174                         }
2175                         case I_BehaviourAlien:
2176                         {
2177                                 textprint("Object is an alien.\n");
2178                                 break;
2179                         }
2180                         case I_BehaviourPredator:
2181                         {
2182                                 textprint("Object is a predator.\n");
2183                                 break;
2184                         }
2185                         default:
2186                         {
2187                                 textprint("Object is not supported - change PVisible.c for expanded diagnostics!\n");
2188                                 break;
2189                         }
2190                 }
2191         }
2192 
2193         if (!sbPtr->DynPtr) {
2194                 textprint("Object has no dynamics block!\n");
2195         } else {
2196                 textprint("Object world co-ords: %d %d %d\n",sbPtr->DynPtr->Position.vx,sbPtr->DynPtr->Position.vy,sbPtr->DynPtr->Position.vz);
2197         }
2198 
2199 }
2200 
2201 
2202 
CreateMultiplayerWeaponPickup(VECTORCH * location,int type,char * name)2203 STRATEGYBLOCK* CreateMultiplayerWeaponPickup(VECTORCH* location,int type,char* name)
2204 {
2205 	TOOLS_DATA_INANIMATEOBJECT toolsdata;
2206 	STRATEGYBLOCK * sbPtr;
2207 	INANIMATEOBJECT_STATUSBLOCK* objectstatusptr;
2208 	int trueType;
2209 
2210 	if ((type==WEAPON_TWO_PISTOLS)||(type==WEAPON_MARINE_PISTOL)) {
2211 		if (!netGameData.allowPistols) {
2212 			return(0);
2213 		}
2214 	}
2215 
2216 	if (type==WEAPON_TWO_PISTOLS) {
2217 		trueType=WEAPON_MARINE_PISTOL;
2218 	} else {
2219 		trueType=type;
2220 	}
2221 
2222 	//fill out a tools template , and use the normal inanimate object creation function
2223 	toolsdata.position=*location;
2224 	toolsdata.orientation.EulerX=0;
2225 	toolsdata.orientation.EulerY=0;
2226 	toolsdata.orientation.EulerZ=0;
2227 
2228 	toolsdata.typeId=IOT_Weapon;
2229 	toolsdata.subType=trueType;
2230 	toolsdata.mass=5;
2231 	toolsdata.integrity=2;
2232 	toolsdata.triggering_event=0;
2233 	toolsdata.explosionType=0;
2234 
2235 	toolsdata.shapeIndex=-1;
2236 
2237 	//find the weapon's shape
2238 	switch(trueType)
2239 	{
2240 		case WEAPON_MARINE_PISTOL:
2241 			toolsdata.shapeIndex=GetLoadedShapeMSL("Pistol");
2242 			break;
2243 		case WEAPON_PULSERIFLE:
2244 			toolsdata.shapeIndex=GetLoadedShapeMSL("pulse");
2245 			break;
2246 		case WEAPON_SMARTGUN:
2247 			toolsdata.shapeIndex=GetLoadedShapeMSL("smart");
2248 			break;
2249 		case WEAPON_FLAMETHROWER:
2250 			toolsdata.shapeIndex=GetLoadedShapeMSL("flame");
2251 			break;
2252 		case WEAPON_FRISBEE_LAUNCHER:
2253 			toolsdata.shapeIndex=GetLoadedShapeMSL("Skeeter");
2254 			toolsdata.orientation.EulerZ=1024;
2255 			break;
2256 		case WEAPON_SADAR:
2257 			toolsdata.shapeIndex=GetLoadedShapeMSL("sadar");
2258 			break;
2259 		case WEAPON_GRENADELAUNCHER:
2260 			toolsdata.shapeIndex=GetLoadedShapeMSL("grenade");
2261 			break;
2262 		case WEAPON_MINIGUN:
2263 			toolsdata.shapeIndex=GetLoadedShapeMSL("minigun");
2264 			break;
2265 
2266 	}
2267 
2268 	if(toolsdata.shapeIndex==-1)
2269 	{
2270 		//failed to find shape
2271 		//forget about it
2272 		return 0;
2273 	}
2274 	//adjust the weapon , so it isn't stuck through the floor
2275 	toolsdata.position.vy-=(mainshapelist[toolsdata.shapeIndex]->shapemaxy);
2276 
2277 
2278 
2279 	sbPtr = CreateActiveStrategyBlock();
2280 
2281 	InitialiseSBValues(sbPtr);
2282 	if(!sbPtr) return 0;
2283 
2284 	sbPtr->I_SBtype = I_BehaviourInanimateObject;
2285 	sbPtr->shapeIndex=toolsdata.shapeIndex;
2286 
2287 	EnableBehaviourType(sbPtr,I_BehaviourInanimateObject, &toolsdata );
2288 	if(!sbPtr->SBdataptr) return 0;
2289 
2290 	if(!name)
2291 	{
2292 		AssignNewSBName(sbPtr);
2293 		AddNetMsg_CreateWeapon(&sbPtr->SBname[0],trueType,location);
2294 	}
2295 	else
2296 	{
2297 		COPY_NAME(sbPtr->SBname,name);
2298 	}
2299 
2300 	objectstatusptr=(INANIMATEOBJECT_STATUSBLOCK*)sbPtr->SBdataptr;
2301 
2302 	objectstatusptr->lifespanTimer=20*ONE_FIXED;
2303 
2304 	//sort out object visibility
2305 	{
2306 		DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
2307 		LOCALASSERT(dynPtr);
2308 
2309 		sbPtr->containingModule = ModuleFromPosition(&(dynPtr->Position), (MODULE *)0);
2310 		sbPtr->maintainVisibility = 1;
2311 
2312 
2313 		dynPtr->GravityOn = 1;
2314 
2315 	}
2316 
2317 	return sbPtr;
2318 }
2319 
MakePlayersWeaponPickupVisible()2320 void MakePlayersWeaponPickupVisible()
2321 {
2322 	extern int NumActiveStBlocks;
2323 	extern STRATEGYBLOCK *ActiveStBlockList[];
2324 	STRATEGYBLOCK* sbPtr;
2325 	int i;
2326 	/*
2327 	Search through the strategy block list for weapons.
2328 	Any weapons that have a lifespan timer should be made visible.
2329 	There should only be one such object , so we can stop looking once we find it
2330 	*/
2331 
2332 	for(i=NumActiveStBlocks-1;i>=0;i--)
2333 	{
2334 		sbPtr=ActiveStBlockList[i];
2335 		if(sbPtr->I_SBtype==I_BehaviourInanimateObject && !sbPtr->maintainVisibility)
2336 		{
2337 			INANIMATEOBJECT_STATUSBLOCK* objectstatusptr;
2338 			objectstatusptr=(INANIMATEOBJECT_STATUSBLOCK*)sbPtr->SBdataptr;
2339 
2340 			if(objectstatusptr->typeId==IOT_Weapon)
2341 			{
2342 				if(objectstatusptr->lifespanTimer>0)
2343 				{
2344 					//okay we've found the object , so allow it to be visible
2345 					sbPtr->maintainVisibility = 1;
2346 					return;
2347 				}
2348 			}
2349 		}
2350 	}
2351 
2352 }
2353 
2354 
Create_Pred_Disc_Pickup_For_Load()2355 STRATEGYBLOCK* Create_Pred_Disc_Pickup_For_Load()
2356 {
2357 	STRATEGYBLOCK* sbPtr;
2358 	TOOLS_DATA_INANIMATEOBJECT toolsData;
2359 	int discShapeIndex;
2360 
2361 	{
2362 		extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name);
2363 		SECTION* section;
2364 		/*
2365 		We need to find the shape index of the disc object. To do this , we need to
2366 		get the disc head-up-display hierarchy , and search for the disc section
2367 		*/
2368 		section = GetNamedHierarchyFromLibrary("pred_HUD","disk");
2369 		if(!section) return NULL;
2370 
2371 		section = GetThisSection(section,"disk");
2372 		if(!section) return NULL;
2373 
2374 		//found the disc section
2375 		discShapeIndex = section->ShapeNum;
2376 
2377 	}
2378 
2379 	//fill in a tools data for the disc
2380 	memset(&toolsData,0,sizeof(toolsData));
2381 	toolsData.typeId = IOT_Ammo;
2382 	toolsData.subType = (int)AMMO_PRED_DISC;
2383 	toolsData.shapeIndex = discShapeIndex;
2384 
2385 
2386 	sbPtr = CreateActiveStrategyBlock();
2387 
2388 	if(!sbPtr)
2389 	{
2390 		return NULL;
2391 	}
2392 
2393 	InitialiseSBValues(sbPtr);
2394 	sbPtr->I_SBtype = I_BehaviourInanimateObject;
2395 	sbPtr->shapeIndex = discShapeIndex;
2396 
2397 	EnableBehaviourType(sbPtr,I_BehaviourInanimateObject, &toolsData );
2398     sbPtr->maintainVisibility = 1;
2399 
2400 	return sbPtr;
2401 
2402 }
2403 
2404 
2405 /*--------------------**
2406 ** Loading and Saving **
2407 **--------------------*/
2408 #include "savegame.h"
2409 typedef struct inanimate_object_save_block
2410 {
2411 	SAVE_BLOCK_STRATEGY_HEADER header;
2412 
2413 	INANIMATEOBJECT_TYPE typeId;
2414 	int subType; /* weapon id, security level or other relevant enumerated type... */
2415 
2416 	BOOL Indestructable;
2417 	int explosionTimer; //slight time delay after destruction for explosion
2418 
2419 	//strategyblock stuff
2420 	int integrity;
2421 	DAMAGEBLOCK SBDamageBlock;
2422 	DYNAMICSBLOCK dynamics;
2423 }INANIMATE_OBJECT_SAVE_BLOCK;
2424 
2425 
2426 //defines for load/save macros
2427 #define SAVELOAD_BLOCK block
2428 #define SAVELOAD_BEHAV objectstatusptr
2429 
LoadStrategy_InanimateObject(SAVE_BLOCK_STRATEGY_HEADER * header)2430 void LoadStrategy_InanimateObject(SAVE_BLOCK_STRATEGY_HEADER* header)
2431 {
2432 	STRATEGYBLOCK* sbPtr;
2433 	INANIMATEOBJECT_STATUSBLOCK* objectstatusptr;
2434 	INANIMATE_OBJECT_SAVE_BLOCK* block = (INANIMATE_OBJECT_SAVE_BLOCK*) header;
2435 
2436 	//check the size of the save block
2437 	if(header->size!=sizeof(*block)) return;
2438 
2439 	//find the existing strategy block
2440 	sbPtr = FindSBWithName(header->SBname);
2441 	if(!sbPtr)
2442 	{
2443 		//Didn't find the object already existing.
2444 		//Might be a predator disc pickup however.
2445 		if(block->typeId == IOT_Ammo && block->subType == (int)AMMO_PRED_DISC)
2446 		{
2447 			//okay we need to create a disc then
2448 			sbPtr = Create_Pred_Disc_Pickup_For_Load();
2449 		}
2450 		if(!sbPtr) return;
2451 
2452 	}
2453 
2454 	//make sure the strategy found is of the right type
2455 	if(sbPtr->I_SBtype != I_BehaviourInanimateObject) return;
2456 
2457 	objectstatusptr = (INANIMATEOBJECT_STATUSBLOCK*)sbPtr->SBdataptr;
2458 
2459 	//start copying stuff
2460 
2461 	COPYELEMENT_LOAD(Indestructable)
2462 	COPYELEMENT_LOAD(explosionTimer)
2463 	COPYELEMENT_LOAD(typeId)
2464 	COPYELEMENT_LOAD(subType)
2465 
2466 
2467 
2468 	*sbPtr->DynPtr = block->dynamics;
2469 	sbPtr->integrity = block->integrity;
2470 	sbPtr->SBDamageBlock = block->SBDamageBlock;
2471 
2472 }
2473 
2474 
SaveStrategy_InanimateObject(STRATEGYBLOCK * sbPtr)2475 void SaveStrategy_InanimateObject(STRATEGYBLOCK* sbPtr)
2476 {
2477 	INANIMATE_OBJECT_SAVE_BLOCK *block;
2478 	INANIMATEOBJECT_STATUSBLOCK* objectstatusptr;
2479 
2480 	objectstatusptr = (INANIMATEOBJECT_STATUSBLOCK*)sbPtr->SBdataptr;
2481 
2482 	GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
2483 
2484 	//start copying stuff
2485 
2486 	COPYELEMENT_SAVE(Indestructable)
2487 	COPYELEMENT_SAVE(explosionTimer)
2488 	COPYELEMENT_SAVE(typeId)
2489 	COPYELEMENT_SAVE(subType)
2490 
2491 
2492 	block->dynamics = *sbPtr->DynPtr;
2493 	block->dynamics.CollisionReportPtr=0;
2494 
2495 	block->integrity = sbPtr->integrity;
2496 	block->SBDamageBlock = sbPtr->SBDamageBlock;
2497 }
2498