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