convert line ends
[canaan.git] / prj / cam / src / deepc / game / dpcgame.cpp
blob981108d20243c4bd25529f9071b5dc277ee9386a
1 /*
2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
4 */
6 // Deep Cover specific game features
8 #include <string.h>
9 #include <math.h>
11 // LG Tech
12 #include <2d.h>
13 #include <rect.h>
14 #include <res.h>
15 #include <types.h>
16 #include <resapi.h>
17 #include <config.h>
18 #include <mprintf.h>
19 #include <matrix.h>
20 #include <gadbox.h>
22 // ActReact enhancments.
23 #include <dpcreact.h>
24 #include <dpcdrprp.h>
25 #include <dpcprop.h>
27 // AI
28 #include <dpcai.h>
30 // Combat: Melee
31 #include <dpcmelee.h>
32 #include <dpcplcst.h>
33 #include <plycbllm.h>
34 #include <dpcmelpr.h>
35 #include <weapon.h>
37 // Damage
38 #include <dmgmodel.h>
39 #include <dmgbase.h>
40 #include <dpcdmg.h>
41 #include <dpcdmprp.h>
43 // File support
44 #include <filevar.h>
46 // Framework
47 #include <appname.h>
48 #include <command.h>
49 #include <gamestr.h>
50 #include <gametool.h>
52 // Input
53 #include <kbcook.h>
54 #include <kb.h>
55 #include <keydefs.h>
56 #include <mouse.h>
57 #include <dpckey.h>
58 #include <gen_bind.h>
59 #include <dpc_bind.h>
60 #include <dpcqbind.h>
61 #include <dpcctrl.h>
63 // Editor
64 #include <editobj.h>
65 #include <editor.h>
67 // Engine features
68 #include <contain.h>
69 #include <culpable.h>
70 #include <frobctrl.h>
71 #include <frobprop.h>
72 #include <pick.h>
73 #include <questapi.h>
74 #include <dpcfrob.h>
75 #include <dpcfsys.h>
76 #include <weapprop.h>
77 #include <gunvhot.h>
79 // Metagame stuff
80 #include <dpcmain.h>
81 #include <dpcmenu.h>
82 #include <init.h>
84 // Player
85 #include <player.h>
86 #include <playrobj.h>
87 #include <plyrmode.h>
88 #include <dpclooko.h>
89 #include <dpcparam.h>
90 #include <dpcpldmg.h>
91 #include <dpcplayr.h>
92 #include <dpcplprp.h>
94 // Loops
95 #include <loopapi.h>
96 #include <scrnloop.h>
98 // Motion
99 #include <headmove.h>
100 #include <dpccret.h>
102 // Multiplayer
103 #include <netsynch.h>
104 #include <netmsg.h>
106 // Objects
107 #include <objsys.h>
108 #include <osysbase.h>
109 #include <objquery.h>
110 #include <objpos.h>
111 #include <objhp.h>
112 #include <objtype.h>
113 #include <lnkquery.h>
114 #include <linkman.h>
115 #include <linkbase.h>
116 #include <relation.h>
117 #include <traitman.h>
118 #include <dpclinks.h>
119 #include <dpcobjst.h>
120 #include <objlpars.h>
122 // Physics
123 #include <physapi.h>
124 #include <phcore.h>
125 #include <phmod.h>
126 #include <phmods.h>
127 #include <phnet.h>
128 #include <phprop.h>
129 #include <physcast.h>
131 // Random numbers.
132 #include <r3d.h>
133 #include <rand.h>
135 // Render: Camera
136 #include <camera.h>
137 #include <dpccam.h>
139 // Render: Lights
140 #include <objlight.h>
142 // Render: Particles
143 #include <particle.h>
144 #include <partprop.h>
146 // Render: General
147 #include <rendobj.h>
148 #include <rendprop.h>
149 #include <mnamprop.h>
150 #include <dpccmapi.h>
151 #include <dpcrend.h> // for pick reset
152 #include <dpccobpr.h>
154 // Scripting
155 #include <scrnovls.h>
156 #include <scrnmode.h>
157 #include <anim_txt.h>
158 #include <creature.h>
159 #include <scrptapi.h>
160 #include <scrptmsg.h>
161 #include <dpcscapi.h>
163 // Simulation
164 #include <iobjnet.h>
165 #include <simbase.h>
166 #include <simtime.h>
167 #include <simstate.h>
168 #include <drkbreth.h>
170 // Sound
171 #include <appsfx.h>
172 #include <schema.h>
173 #include <dpcsndpr.h>
174 #include <dpcsound.h>
176 // Time
177 #include <fixtime.h>
179 // UI
180 #include <cmdterm.h>
181 #include <hud.h>
182 #include <dpccurm.h> // For SCM modes
183 #include <dpcdlg.h>
184 #include <dpchud.h>
185 #include <dpcinv.h>
186 #include <dpcinvpr.h>
187 #include <dpciface.h>
188 #include <dpccurpr.h>
189 #include <dpclbox.h>
190 #include <dpcoptmn.h>
191 #include <dpclding.h>
192 #include <dpcmulti.h>
193 #include <dpcsavui.h>
194 #include <dpcovrly.h>
195 #include <dpcovcst.h>
196 #include <dpcemail.h>
197 #include <dpcpda.h>
199 // Weapons
200 #include <prjctile.h>
201 #include <gunproj.h>
202 #include <dpcammov.h>
203 #include <gunapi.h>
204 #include <gunprop.h>
205 #include <dpcpgapi.h>
207 // Dark tools & other loot
208 #include <drkdiff.h>
209 #include <drkbreth.h>
211 // Debugging
212 #include <bugterm.h>
213 #include <cfgdbg.h>
215 extern "C"
217 #include <event.h>
220 // Other Deep Cover files
221 #include <dpchrm.h>
222 #include <dpcgame.h>
223 #include <dpcutils.h>
224 #include <dpcblood.h>
225 #include <dpcloot.h>
226 #include <dpcreprt.h>
228 #include <drkuires.h>
229 #include <globalid.h>
230 #include <transmod.h>
231 #include <dpcincst.h>
233 #ifndef SHIP
234 #include <dpccmapi.h>
235 #include <dpccs.h>
236 #include <viewmgr.h>
237 #endif
239 #include <dbmem.h>
241 #define USE_DIST 100.0F
243 // is the user typing a message
244 static bool typingMode=FALSE;
246 static Point gLastpos = {-1,-1};
248 bool DPC_mouse = FALSE;
249 EXTERN bool g_lgd3d;
250 IRes *DPC_mouse_hnd;
251 IRes *gDefaultHnd;
252 int DPC_cursor_mode = SCM_NORMAL;
254 extern Rect gun_rect;
255 static Rect power_rect = {{276,254}, {447,390}};
256 static Rect subpower_rect = {{456,254}, {629,390}};
257 ObjID drag_obj = OBJ_NULL; // what is ON the cursor
258 bool DPC_mouse_loaded = FALSE; // have we loaded in cursor art yet?
260 // controllers in dark for focus/actions
261 BOOL active_focus=FALSE;
262 BOOL world_use_in_progress=FALSE;
264 #ifndef SHIP
265 void CameraPositionSpew(void);
266 #endif
268 void DPCDrawCursor(Point pt)
270 // don't allow anything if player dead
271 if (GetPlayerMode() == kPM_Dead)
272 return;
274 // now, depending on cursor mode, draw some help text
275 char temp[255];
276 cStr str;
277 ObjID useobj;
278 short dx, dy, w, bmh;
280 // the easy part: draw the art
281 if (gCursorHnd == gDefaultHnd)
282 DrawCursorByHandle(gCursorHnd,pt); // we should probably decide this a better way....
283 else
284 DrawCursorByHandleCenter(gCursorHnd,pt);
286 AutoAppIPtr(GameStrings);
287 useobj = frobWorldSelectObj;
288 if (useobj == OBJ_NULL)
289 useobj = g_ifaceFocusObj;
290 if (useobj == OBJ_NULL)
291 return;
293 #ifdef EDITOR
294 AutoAppIPtr(DPCCamera);
295 if (pDPCCamera->GetEditMode() != kCameraNormal)
296 return;
297 #endif
299 strcpy(temp,"");
301 AutoAppIPtr(ContainSys);
302 ObjID cont;
304 switch (DPC_cursor_mode)
306 case SCM_NORMAL:
307 // okay, if the object we are over is a world object, use it's world text.
308 if (useobj == frobWorldSelectObj)
310 str = pGameStrings->FetchObjString(useobj, PROP_WORLDCURSOR_NAME);
312 // otherwise, use its inventory text
313 else
315 str = pGameStrings->FetchObjString(useobj, PROP_INVCURSOR_NAME);
317 cont = pContainSys->GetContainer(useobj);
318 if ((cont == OBJ_NULL) || (cont == PlayerObject()))
319 strcpy(temp,str);
321 break;
322 default:
323 return;
324 break;
327 if (strlen(temp) == 0)
328 return;
330 w = gr_font_string_width(gDPCFont, temp);
331 bmh = 16; // rather than compute
332 dx = pt.x - (w / 2);
334 sScrnMode smode;
335 ScrnModeGet(&smode);
336 if (dx + w + 10 > smode.w)
337 dx = smode.w - w - 10;
338 if (dx < 10)
339 dx = 10;
340 dy = pt.y + (bmh / 2) + 2;
342 gr_set_fcolor(gDPCTextColor);
343 gr_font_string(gDPCFontMono, temp, dx, dy);
346 static void doMouseFocusCheck(void)
348 Point mpt;
349 short mx, my;
350 BOOL occlude;
351 mouse_get_xy(&mx,&my);
352 mpt.x = mx; mpt.y = my;
353 occlude = DPCOverlayMouseOcclude(mpt);
355 // timeout any "stale" focus items
356 if (!gFocusTouched)
357 g_ifaceFocusObj = OBJ_NULL;
358 gFocusTouched = FALSE;
360 if ((frobWorldSelectObj == OBJ_NULL) || (frobWorldSelectObj != g_PickCurrentObj) || occlude)
362 int t;
363 if (gPropHUDTime->Get(frobWorldSelectObj,&t))
365 if (t == 0)
366 gPropHUDTime->Delete(frobWorldSelectObj);
369 if ((g_PickCurrentObj != OBJ_NULL) && (!occlude))
371 if (frobWorldSelectObj != g_PickCurrentObj)
373 BOOL showhud;
374 if ((gPropAllowHUDSelect->Get(g_PickCurrentObj,&showhud)) && showhud)
376 gPropHUDTime->Set(g_PickCurrentObj, 0);
377 DPCInterfaceMouseOver(g_PickCurrentObj);
380 frobWorldSelectObj = g_PickCurrentObj;
382 else
383 // highlit_obj =
384 frobWorldSelectObj = OBJ_NULL;
387 // bonus space for cursors and such
388 #define TYPE_MAX 40
389 static char typebuf[TYPE_MAX+3];
392 // parse the key
393 EXTERN int hack_for_kbd_state(void);
394 #define CTRL_STATES (KBM_LCTRL|KBM_RCTRL)
396 bool MouseMode(bool mode, bool clear)
398 BOOL slim_mode;
399 AutoAppIPtr(QuestData);
400 slim_mode = pQuestData->Get("HideInterface");
402 // don't allow into into cursor mode if we are pre-HUD
403 if (mode && slim_mode)
404 return(FALSE);
406 // don't allow out of mouse mode if object on cursor
407 if (!mode && DPC_mouse && (drag_obj != OBJ_NULL))
408 return(FALSE);
410 DPC_mouse = mode;
411 DPCOverlayMouseMode(mode);
413 if (mode)
415 RemoveIBHandler();
416 InstallIBHandler (HK_GAME2_MODE, UI_EVENT_KBD_RAW | UI_EVENT_MOUSE | UI_EVENT_MOUSE_MOVE | UI_EVENT_JOY, FALSE);
418 //dont let input binding sys process mouse move events
419 headmoveSetRelPosX(0);
420 headmoveSetRelPosY(0);
421 g_pInputBinder->SetValidEvents (ALL_EVENTS & (~UI_EVENT_MOUSE_MOVE)); // & (~UI_EVENT_MOUSE));
423 if (!DPC_mouse_loaded)
425 gDefaultHnd = DPC_mouse_hnd = LoadPCX("cursor"); // , INTERFACE_PATH, DPCLoadNoPalette);
426 DPC_mouse_loaded = TRUE;
427 // if () ??
428 SetCursorByHandle(DPC_mouse_hnd);
430 if (gLastpos.x != -1)
431 mouse_put_xy(gLastpos.x,gLastpos.y);
432 if (clear)
433 ClearCursor();
435 else
437 RemoveIBHandler();
438 InstallIBHandler (HK_GAME_MODE, UI_EVENT_KBD_RAW | UI_EVENT_MOUSE | UI_EVENT_MOUSE_MOVE | UI_EVENT_JOY, FALSE);
439 //turn input binder's mouse move events back on
440 g_pInputBinder->SetValidEvents (ALL_EVENTS); // & (~UI_EVENT_MOUSE));
442 int centerx,centery;
443 mouse_get_xy(&gLastpos.x,&gLastpos.y);
444 sScrnMode smode;
445 ScrnModeGet(&smode);
446 centerx = smode.w / 2; //grd_visible_canvas->bm.w / 2;
447 centery = smode.h / 2; //grd_visible_canvas->bm.h / 2;
448 //mprintf("center = %d, %d\n",centerx,centery);
450 // What the heck was this doing? this is certain to cause whiplash on inv mode changes!
451 // removed, 6/9/99 Xemu
452 //centerx = 640 / 2;
453 //centery = 480 / 2;
454 mouse_put_xy(centerx, centery);
455 // clear out HUD selection rectangle
456 if (frobWorldSelectObj != OBJ_NULL)
458 int t;
459 if (gPropHUDTime->Get(frobWorldSelectObj, &t) && (t == 0))
460 gPropHUDTime->Delete(frobWorldSelectObj);
463 frobWorldSelectObj = OBJ_NULL;
464 if (DPC_mouse_loaded)
466 SafeFreeHnd(&DPC_mouse_hnd);
467 DPC_mouse_loaded = FALSE;
472 // make sure nothing gets stuck down
473 //g_pInputBinder->PollAllKeys();
475 return(TRUE);
478 void DPC_check_keys(void)
480 //static bool last_ctrl = FALSE;
483 int kb_mods=hack_for_kbd_state();
484 //bool old_mouse = DPC_mouse;
485 bool ctrl_down = (kb_mods & CTRL_STATES);
486 static bool ctrl_used = FALSE;
487 if (ctrl_down)
489 if (DPC_cursor_mode == SCM_NORMAL)
491 DPCLookCursor();
492 ctrl_used = TRUE;
495 else
497 if (DPC_cursor_mode == SCM_LOOK)
499 if (ctrl_used)
500 ClearCursor();
502 else
503 ctrl_used = FALSE;
509 #pragma off(unreferened)
510 bool DPC_key_parse(int keycode)
512 int kc;
514 // MFDs and other overlaid interface elements
515 if (keycode&KB_FLAG_DOWN)
516 if (DPCOverlayHandleKey(keycode))
517 return(TRUE);
519 // camera recording mode
520 AutoAppIPtr(DPCCamera);
521 if (pDPCCamera->GetEditMode() == kCameraRecord)
522 return DPCControlKeyParse(keycode, pDPCCamera->GetAttachObject(), pDPCCamera->GetCameraSpeed());
524 if (pDPCCamera->GetEditMode() == kCameraEdit)
526 if (!(keycode&KB_FLAG_DOWN))
527 return FALSE;
529 kc=keycode&~KB_FLAG_DOWN;
530 switch (kc)
532 case ' ':
533 SetSimTimePassing(!IsSimTimePassing());
534 return TRUE;
535 case '1':
536 case '2':
537 case '3':
538 case '4':
539 case '5':
540 case '6':
541 case '7':
542 case '8':
543 case '9':
544 pDPCCamera->SwitchCamera(kc-'1');
545 return TRUE;
546 case '0':
547 pDPCCamera->SwitchCamera(10);
548 return TRUE;
550 return FALSE;
553 if (keycode&KB_FLAG_DOWN)
555 kc=keycode&~KB_FLAG_DOWN;
556 switch (kc)
558 //case 'w': g_playerMoveMode = kPlayerRun; return FALSE;
559 //case 's': g_playerMoveMode = kPlayerWalk; return FALSE;
560 //case 'x': g_playerMoveMode = kPlayerBackup; return FALSE;
562 case KEY_BS:
563 strcpy(typebuf,"");
564 typingMode=TRUE;
566 case KEY_F1:
567 break;
569 default:
570 return FALSE;
573 else
576 switch(keycode)
578 case 'w': g_playerMoveMode = kPlayerMoveNone; return FALSE;
579 case 's': g_playerMoveMode = kPlayerMoveNone; return FALSE;
580 case 'x': g_playerMoveMode = kPlayerMoveNone; return FALSE;
581 default:
582 return FALSE;
586 return TRUE;
589 //////////
591 // Throwing an object back into the world. This is a little complex,
592 // because if this is a multiuser game, then we have to hand the object
593 // back to the world host.
596 static cNetMsg *g_pThrowObjMsg = NULL;
599 // This code should only be run on the world host, and deals with actually
600 // putting the object back into the world:
602 static void handleThrowObj(ObjID obj, ObjID src)
604 // Take the object back from the thrower:
605 AutoAppIPtr(NetManager);
606 if (pNetManager->IsNetworkGame())
608 AutoAppIPtr(ObjectNetworking);
609 pObjectNetworking->ObjTakeOver(obj);
612 // Try to deal with throwing out a melee weapon that is still
613 // animating its close
614 AutoAppIPtr(DPCPlayer);
615 if (IsMelee(obj) && IsCurrentPlayerArm(obj))
616 PlayerSwitchMode(kPlayerModeInvalid);
618 ObjPos *pos = ObjPosGet(src);
619 mxs_vector plrpos, dir;
620 mxs_angvec plrang;
621 mxs_matrix mat; // There is no spoon, only the matrix
623 mx_copy_vec(&plrpos,&pos->loc.vec);
625 // Place the object at the player's location, so networking has a more
626 // or less rational start position for the thing:
627 ObjPosCopyUpdate(obj, pos);
629 ObjSetHasRefs(obj,TRUE);
630 PhysRegisterSphereDefault(obj);
632 sGameParams *params = GetGameParams();
633 int randval = Rand() % 100;
634 float power;
636 if (config_is_defined("disable_random_throw"))
637 power = params->throwpower;
638 else
639 power = params->throwpower * (0.9 + (0.2 * (float(randval) / 100)));
641 // get player angle, and disturb it a touch
642 memcpy(&plrang,&pos->fac,sizeof(mxs_angvec));
643 //plrang = pos->fac;
644 if (!config_is_defined("disable_random_throw"))
645 plrang.tz += (Rand() % 0x0A00) - 0x0500;
646 mx_ang2mat(&mat,&plrang);
648 // set our final throw direction in world coords
649 mx_copy_vec(&dir,&mat.vec[0]);
651 if (launchProjectile(src,obj,power,PRJ_FLG_PUSHOUT|PRJ_FLG_MASSIVE|PRJ_FLG_NO_FIRER,NULL,&dir,NULL) == OBJ_NULL)
653 // Head too close to some surface, launch from body instead
654 mxs_vector loc;
655 mx_copy_vec(&loc, &ObjPosGet(src)->loc.vec);
657 launchProjectile(src,obj,power,PRJ_FLG_PUSHOUT|PRJ_FLG_MASSIVE|PRJ_FLG_NO_FIRER,NULL,&dir,&loc);
659 PhysNetBroadcastObjPosByObj(obj);
662 static sNetMsgDesc sThrowObjDesc =
664 kNMF_SendToHost,
665 "ThrowObj",
666 "Throw Object Back to World",
667 NULL,
668 handleThrowObj,
669 {{kNMPT_SenderObjID, kNMPF_None, "Obj"},
670 {kNMPT_SenderObjID, kNMPF_None, "From"},
671 {kNMPT_End}}
675 // Tell the default host that we're throwing the object back to the world
676 // Client code
678 void ThrowObj(ObjID o, ObjID src)
680 // If the host is throwing the thing, then this will just loop back
681 // and land in handleThrowObj:
682 g_pThrowObjMsg->Send(OBJ_NULL, o, src);
684 // And now, the object is no longer on our cursor.
685 if (o == drag_obj)
687 DPCInvLoadCursor(OBJ_NULL);
691 //////////
693 // player is interacting with the interface / frobbing
694 void DPCInterfaceUseItem()
696 // don't allow anything if player dead
697 if (GetPlayerMode() == kPM_Dead)
698 return;
700 if (DPC_cursor_mode == SCM_LOOK)
702 ClearCursor();
703 return;
706 Point pos;
707 mouse_get_xy(&pos.x, &pos.y);
709 // kind of a misnomer now, since doubleclicks are gone
710 DPCOverlayDoubleClick(pos);
712 DPCInvRefresh();
715 // player wants to change mode with no other effects
716 void DPCToggleMode()
718 // don't allow anything if player dead
719 if (GetPlayerMode() == kPM_Dead)
720 return;
721 MouseMode(!DPC_mouse,TRUE);
724 // toggle mode, first frobbing what is under the cursor
725 void DPCFrobObject()
727 // don't allow anything if player dead
728 if (GetPlayerMode() == kPM_Dead)
729 return;
730 DPCDoFrob(FALSE);
733 void DPCFrobObjectInv()
735 // don't allow anything if player dead
736 if (GetPlayerMode() == kPM_Dead)
737 return;
738 // if we have a world object, frob it
739 if (frobWorldSelectObj != OBJ_NULL)
741 DPCDoFrob(FALSE);
743 // otherwise, inv-frob
744 else
746 DPCInterfaceUseItem();
750 void DPCFrobAndMaybeToggleMode() // BOOL start
752 // don't allow anything if player dead
753 if (GetPlayerMode() == kPM_Dead)
754 return;
755 // only do stuff on the downs
756 //if (!start)
757 // return;
759 if (frobWorldSelectObj == OBJ_NULL)
761 if (DPC_cursor_mode == SCM_NORMAL)
762 MouseMode(!DPC_mouse, TRUE);
764 else
766 DPCDoFrob(FALSE);
767 BOOL switchmode = FALSE;
769 if (DPC_cursor_mode == SCM_DRAGOBJ)
771 switchmode = TRUE;
773 else
775 // if the object we are trying to frob has no relevant
776 // frob engine properties, then allow a switch
777 AutoAppIPtr(ObjectSystem);
778 if (pObjectSystem->Exists(frobWorldSelectObj))
780 sFrobInfo *frobinfo;
781 if (!pFrobInfoProp->Get(frobWorldSelectObj, &frobinfo))
782 switchmode = TRUE;
783 else if (frobinfo->actions[kFrobLocWorld] == 0)
784 switchmode = TRUE;
787 if (switchmode)
789 gLastpos.x = -1;
790 MouseMode(!DPC_mouse, TRUE);
795 void DPCHilightObject()
797 AutoAppIPtr(NetManager);
798 if (!pNetManager->Networking())
799 // This feature only really makes sense in multiplayer
800 return;
802 if ((frobWorldSelectObj != OBJ_NULL) && ObjHasRefs(frobWorldSelectObj))
804 DPCBroadcastHilightObject(frobWorldSelectObj);
808 //////////
810 // mouse parsing
812 BOOL DPCInterfaceClick()
814 // Don't allow anything if player dead
815 if (GetPlayerMode() == kPM_Dead)
817 return(TRUE);
820 BOOL retval = FALSE;
821 Point pos;
822 mouse_get_xy(&pos.x, &pos.y);
824 if (DPCOverlayClick(pos)) // interface hacks
826 return(TRUE);
829 switch (DPC_cursor_mode)
831 case SCM_DRAGOBJ:
833 BOOL throw_me = FALSE;
834 if (frobWorldSelectObj == OBJ_NULL)
836 throw_me = TRUE;
838 else
840 frobInvSelectObj = frobWorldSelectObj; // set the target of the tool frob
841 DPCDoFrob(FALSE);
842 //ClearCursor();
843 if (DPCScriptAllowSwap())
845 throw_me = TRUE;
848 if (throw_me && (drag_obj != OBJ_NULL))
850 // throw into world
851 ThrowObj(drag_obj,PlayerObject());
852 retval = true;
854 break;
857 case SCM_LOOK:
859 //retval = TRUE;
861 if (frobWorldSelectObj != OBJ_NULL)
863 DPCLookPopup(frobWorldSelectObj);
864 retval = TRUE;
867 //ClearCursor();
868 break;
871 return(retval);
874 // fire begin / stop
875 static void DPCFireWeapon(BOOL start)
877 if (GetPlayerMode() == kPM_Dead)
879 // removed 5/31/99: Xemu
881 // finish dying, that is to say, unwind or resurrect
882 AutoAppIPtr(ScriptMan);
883 sScrMsg msg(PlayerObject(),"FinishDying");
884 msg.flags |= kSMF_MsgPostToOwner;
885 pScriptMan->SendMessage(&msg);
887 return;
889 //mprintf("firing weapon!\n");
891 // no firing if no interface
892 AutoAppIPtr(QuestData);
893 BOOL slim_mode = pQuestData->Get("HideInterface");
894 if (slim_mode)
896 return;
899 AutoAppIPtr(PlayerGun);
900 AutoAppIPtr(DPCPlayer);
902 if (start)
904 if (pPlayerGun->Get() != OBJ_NULL)
906 pPlayerGun->PullTrigger();
908 StartMeleeAttack(PlayerObject(), GetWeaponObjID(PlayerObject()));
910 else
912 if (pPlayerGun->Get() != OBJ_NULL)
914 pPlayerGun->ReleaseTrigger();
916 FinishMeleeAction(PlayerObject(), GetWeaponObjID(PlayerObject()));
920 // query cursor
921 static void DPCQueryMode(BOOL start)
923 // don't allow anything if player dead
924 if (GetPlayerMode() == kPM_Dead)
925 return;
926 if (start)
928 if (DPC_cursor_mode == SCM_NORMAL)
929 DPCLookCursor();
931 else
933 if (DPC_cursor_mode == SCM_LOOK)
934 ClearCursor();
938 static void DPCSplitMode(BOOL start)
940 // don't allow anything if player dead
941 if (GetPlayerMode() == kPM_Dead)
942 return;
943 if (start)
945 if (DPC_cursor_mode == SCM_NORMAL)
947 DPCSplitCursor();
950 else
952 if (DPC_cursor_mode == SCM_SPLIT)
954 ClearCursor();
959 // drag & drop
960 #define DDNONE 0
961 #define DDFROB 1
962 #define DDMODE 2
964 static void DPCDragDropCore(BOOL start, int func)
966 // don't allow anything if player dead
967 if (GetPlayerMode() == kPM_Dead)
968 return;
969 Point pos;
970 mouse_get_xy(&pos.x, &pos.y);
972 if (start)
974 if (DPCOverlayDragDrop(pos, start))
975 return;
977 else
979 int oldmode = DPC_cursor_mode;
980 DPCInterfaceClick();
981 if (DPCOverlayDragDrop(pos, start))
982 return;
984 if ((DPC_cursor_mode != SCM_NORMAL) || (oldmode != SCM_NORMAL))
985 return;
987 switch (func)
989 case DDFROB:
990 DPCDoFrob(FALSE);
991 break;
992 case DDMODE:
993 MouseMode(!DPC_mouse,TRUE);
994 break;
999 static void DPCDragDropFrob(BOOL start)
1001 DPCDragDropCore(start, DDFROB);
1004 static void DPCDragDropSimple(BOOL start)
1006 DPCDragDropCore(start, DDNONE);
1009 static void DPCDragDropMode(BOOL start)
1011 DPCDragDropCore(start, DDMODE);
1014 static void DPCToggleInv(void)
1016 DPCOverlayChange(kOverlayInv, kOverlayModeToggle);
1019 static void DPCToggleCompass(void)
1021 AutoAppIPtr(DPCPlayer);
1022 AutoAppIPtr(ScriptMan);
1023 ObjID compass = pDPCPlayer->GetEquip(PlayerObject(),kEquipCompass);
1024 if (compass == OBJ_NULL)
1026 return;
1029 // don't allow the compass to be turned on until
1030 // we have the interface "installed"
1031 BOOL slim_mode;
1032 AutoAppIPtr(QuestData);
1033 slim_mode = pQuestData->Get("HideInterface");
1034 if (slim_mode)
1036 return;
1039 sScrMsg msg(compass,"Toggle");
1040 pScriptMan->SendMessage(&msg);
1043 static void DPCCycleAmmo(void)
1045 DPCAmmoChangeTypes();
1048 static void DPCSettingToggle(ObjID gun)
1050 int wpntype;
1051 //AutoAppIPtr(PlayerGun);
1052 AutoAppIPtr(DPCPlayer);
1053 AutoAppIPtr(TraitManager);
1054 AutoAppIPtr(ObjectSystem);
1056 //ObjID gun = pPlayerGun->Get();
1057 if (gun == OBJ_NULL)
1059 return;
1062 g_pWeaponTypeProperty->Get(gun,&wpntype);
1064 // on a melee weapon, do nothing at all
1065 if (g_pMeleeTypeProperty->IsRelevant(gun))
1068 AutoAppIPtr(ContainSys);
1069 // First unapply a meta prop if we have an applied one
1070 const char *metaName = GetWeaponModeUnchangeMetaProp(gun);
1071 if (metaName)
1073 ObjID metaProp = pObjectSystem->GetObjectNamed(metaName);
1074 if (metaProp)
1076 pTraitManager->RemoveObjMetaProperty(gun, metaProp);
1078 int newloc = pContainSys->IsHeld(PlayerObject(),gun);
1079 pDPCPlayer->Equip(PlayerObject(), kEquipWeapon, gun, FALSE);
1080 pContainSys->Add(PlayerObject(), gun, newloc, CTF_NONE);
1082 //pDPCPlayer->Equip(PlayerObject(), kEquipWeapon, gun, FALSE);
1085 else
1087 const char *metaName = GetWeaponModeChangeMetaProp(gun);
1088 if (metaName)
1090 ObjID metaProp = pObjectSystem->GetObjectNamed(metaName);
1091 if (metaProp)
1093 pTraitManager->AddObjMetaProperty(gun, metaProp);
1095 int newloc = pContainSys->IsHeld(PlayerObject(),gun);
1096 pDPCPlayer->Equip(PlayerObject(), kEquipWeapon, gun, FALSE);
1097 pContainSys->Add(PlayerObject(), gun, newloc, CTF_NONE);
1099 //pDPCPlayer->Equip(PlayerObject(), kEquipWeapon, gun, FALSE);
1103 return;
1106 int curmode = GunGetSetting(gun);
1107 int numModes = BaseGunDescGetNumSettings(gun);
1108 if (numModes > 1) {
1109 curmode = (curmode+1) % numModes;
1110 GunSetSetting(gun,curmode);
1112 float zoom = BaseGunDescGetZoom(gun);
1113 ZoomTarget(zoom, 2.0);
1115 // text feedback
1116 char temp[255], fmt[255];
1117 extern char *setting_headlines[2]; // hack
1119 AutoAppIPtr(GameStrings);
1120 cStr str = pGameStrings->FetchObjString(gun, setting_headlines[!curmode]);
1121 DPCStringFetch(fmt,sizeof(fmt), "SettingChange", "misc");
1122 sprintf(temp,fmt,str);
1123 DPCOverlayAddText(temp,DEFAULT_MSG_TIME);
1127 #define MAX_EQUIP_CANDIDATES 64
1129 static int equip_val(ObjID o)
1131 // basically, return the condition
1132 int retval = 0 - (GunGetCondition(o) * 100);
1134 // out of ammo is bad
1135 if (GunStateGetAmmo(o) == 0)
1137 retval = retval + 10000;
1140 // introduce a minor objID element so that there are fewer/no ties
1141 retval = retval + (o % 100);
1143 return(retval);
1146 static int equip_compare(const void *p, const void *q)
1148 ObjID *a = (ObjID *) p;
1149 ObjID *b = (ObjID *) q;
1151 if (equip_val(*b) > equip_val(*a))
1152 return -1;
1153 return(equip_val(*b) < equip_val(*a));
1156 static void DPCUseObj(char *args)
1158 AutoAppIPtr(ContainSys);
1159 AutoAppIPtr(ObjectSystem);
1160 AutoAppIPtr(TraitManager);
1162 // no hotkey usage if dead
1163 if (GetPlayerMode() == kPM_Dead)
1165 return;
1168 // no hotkey usage if no interface
1169 AutoAppIPtr(QuestData);
1170 BOOL slim_mode = pQuestData->Get("HideInterface");
1171 if (slim_mode)
1173 return;
1176 ObjID invobj;
1177 ObjID arch = pObjectSystem->GetObjectNamed(args);
1179 sContainIter *iterp = pContainSys->IterStart(PlayerObject());
1180 while (!iterp->finished)
1182 invobj = iterp->containee;
1184 // Use it as if double clicked in inventory
1185 if (pTraitManager->ObjHasDonor(invobj, arch))
1187 frobInvSelectObj = invobj;
1188 DPCDoFrob(TRUE);
1189 pContainSys->IterEnd(iterp);
1191 DPCInvRefresh();
1192 return;
1194 pContainSys->IterNext(iterp);
1196 pContainSys->IterEnd(iterp);
1198 // give feedback
1199 char temp[255];
1200 char fmt[255];
1201 DPCStringFetch(fmt, sizeof(fmt), "NotInInventory", "misc");
1202 AutoAppIPtr(GameStrings);
1203 cStr str = pGameStrings->FetchObjString(arch, PROP_OBJSHORTNAME_NAME);
1204 sprintf(temp, fmt, str);
1205 DPCOverlayAddText(temp,DEFAULT_MSG_TIME);
1208 static BOOL DPCWeaponEquipCore(char *args, BOOL spew)
1210 // search the player's inventory for a matching weapon
1211 // args can now be NULL meaning unequip only
1212 ObjID invobj;
1213 ObjID candidates[MAX_EQUIP_CANDIDATES];
1214 eContainType newloc;
1215 int count = 0;
1216 int i;
1217 BOOL addme;
1219 AutoAppIPtr(PlayerGun);
1220 AutoAppIPtr(ContainSys);
1221 AutoAppIPtr(ObjectSystem);
1222 AutoAppIPtr(TraitManager);
1223 AutoAppIPtr(DPCPlayer);
1224 AutoAppIPtr(QuestData);
1226 // dont switch if no interface
1227 BOOL slim_mode = pQuestData->Get("HideInterface");
1228 if (slim_mode)
1230 return(FALSE);
1233 // don't switch if we are dead
1234 if (GetPlayerMode() == kPM_Dead)
1236 return (FALSE);
1239 // don't do jack if we are in the middle of reloading
1240 if (pPlayerGun->IsReloading())
1242 return (FALSE);
1245 // dont let you switch weapons mid firing
1246 ObjID gun = pPlayerGun->Get();
1247 if ((gun != OBJ_NULL) && pPlayerGun->IsTriggerPulled())
1249 return(FALSE);
1252 ObjID playerobj = PlayerObject();
1253 ObjID newobj = OBJ_NULL;
1254 ObjID prevobj = pDPCPlayer->GetEquip(playerobj, kEquipWeapon);
1256 if (!args) {
1257 if (prevobj) {
1258 // Just unequipping, thanks
1259 if (IsMelee(prevobj)) {
1260 pDPCPlayer->Equip(playerobj, kEquipWeapon, OBJ_NULL,spew);
1261 DPCInvAddObj(playerobj, prevobj, 1);
1262 } else {
1263 ZoomTarget(1.0, 0.0);
1265 // Lower gun then unequip in player gun code
1266 pPlayerGun->Unequip(prevobj, OBJ_NULL, spew, TRUE);
1268 return TRUE;
1270 else
1272 return FALSE;
1276 ObjID weaparch = pObjectSystem->GetObjectNamed(args);
1277 // bail out if the request object doesn't exist
1278 if (weaparch == OBJ_NULL)
1279 return(FALSE);
1281 for (i=0; i < MAX_EQUIP_CANDIDATES; i++)
1283 candidates[i] = OBJ_NULL;
1286 BOOL currentIsThisKind = FALSE;
1287 sContainIter *iterp = pContainSys->IterStart(playerobj);
1288 while (args && !iterp->finished)
1290 invobj = iterp->containee;
1291 addme = FALSE;
1293 if (pTraitManager->ObjHasDonor(invobj, weaparch))
1295 if (invobj != prevobj)
1297 // equip it, maybe
1298 addme = TRUE;
1300 else
1302 currentIsThisKind = TRUE;
1306 if (addme)
1308 eObjState st = ObjGetObjState(invobj);
1309 if (st == kObjStateNormal)
1311 candidates[count] = invobj;
1312 count++;
1313 // abort out if somehow we have more objects than we can contemplate
1314 if (count == MAX_EQUIP_CANDIDATES)
1316 break;
1320 pContainSys->IterNext(iterp);
1322 pContainSys->IterEnd(iterp);
1324 // if we have no canditates, punt
1325 if (count == 0 && args)
1327 if (currentIsThisKind) {
1328 // User hit '2' when a weapon '2' is equipped (for instance)
1329 // which means -- toggle the setting!
1330 DPCSettingToggle(prevobj);
1331 } else {
1332 return(FALSE);
1336 // sort the candidates by quality
1337 qsort(candidates, count, sizeof(candidates[0]), equip_compare);
1339 // if we have no previous considerations, take the first (best)
1340 if ((prevobj == OBJ_NULL) || (!pTraitManager->ObjHasDonor(prevobj, weaparch)))
1342 newobj = candidates[0];
1344 else
1346 // we want the candidate which is closest above our current object
1347 for (i=0; i < count; i++)
1349 if (equip_val(candidates[i]) > equip_val(prevobj))
1351 newobj = candidates[i];
1352 break;
1355 // if there are none, take the first
1356 if (newobj == OBJ_NULL)
1358 newobj = candidates[0];
1363 // okay, do the swap
1364 if (newobj != OBJ_NULL)
1366 if (pDPCPlayer->CheckRequirements(newobj, spew))
1368 if (prevobj)
1370 if (IsMelee(prevobj))
1372 // first unequip the old thing
1373 newloc = pContainSys->IsHeld(playerobj,newobj);
1374 pDPCPlayer->Equip(playerobj, kEquipWeapon, newobj, spew);
1375 pContainSys->Add(playerobj, prevobj, newloc, CTF_NONE);
1377 else
1379 // Clear any zoom
1380 ZoomTarget(1.0, 0.0);
1382 // Lower gun then unequip in player gun code
1383 pPlayerGun->Unequip(prevobj, newobj, spew, TRUE);
1386 else
1388 pDPCPlayer->Equip(playerobj, kEquipWeapon, newobj, spew);
1390 return TRUE;
1394 return(FALSE);
1397 static void DPCWeaponEquip(char *args)
1399 DPCWeaponEquipCore(args, TRUE);
1402 static void DPCWeaponUnequip(void)
1404 DPCWeaponEquipCore(NULL, TRUE);
1407 static void DPCWeaponUnjam(void)
1409 AutoAppIPtr(DPCPlayer);
1411 ObjID playerobj = PlayerObject();
1412 ObjID gunobj = pDPCPlayer->GetEquip(playerobj, kEquipWeapon);
1414 int state = ObjGetObjState(gunobj);
1415 if (state == kObjStateBroken) {
1416 int skillval = pDPCPlayer->GetTechSkill(kTechRepair);
1417 // skillval goes 0 to ...6?...
1418 if (Rand() % 6 < skillval) {
1419 // success
1420 ObjSetObjState(gunobj, kObjStateNormal);
1421 SchemaPlay((Label *)"unjam",NULL);
1422 } else {
1423 // failure
1424 SchemaPlay((Label *)"unjam_fail",NULL);
1429 static char *weapon_order[] =
1431 "psi amp", "wrench", "pistol", "shotgun", "assault rifle",
1432 "laser pistol", "EMP Rifle", "Electro Shock", "Gren Launcher", "Stasis Field Generator",
1433 "Fusion Cannon", "Crystal Shard", "Viral Prolif", "Worm Launcher",
1436 #define WEAPON_CYCLE (sizeof(weapon_order) / sizeof(char *))
1437 static void DPCWeaponCycle(int dir)
1439 ObjID weaparch;
1440 char archname[255];
1441 int i, count;
1442 int num = 0;
1444 AutoAppIPtr(DPCPlayer);
1445 AutoAppIPtr(TraitManager);
1446 AutoAppIPtr(ObjectSystem);
1448 // find the currently equipped weapon
1449 ObjID current = pDPCPlayer->GetEquip(PlayerObject(), kEquipWeapon);
1450 if (current == OBJ_NULL)
1452 num = 0;
1454 else
1456 weaparch = pTraitManager->GetArchetype(current);
1457 strcpy(archname, pObjectSystem->GetName(weaparch));
1459 for (i=0; i < WEAPON_CYCLE; i++)
1461 //mprintf("comparing %s to %s\n",archname, weapon_order[i]);
1462 if (stricmp(archname,weapon_order[i]) == 0)
1464 // a match!
1465 num = i + dir;
1470 count = 0;
1471 while (count < WEAPON_CYCLE)
1473 count++;
1474 // try to equip this type of weapon
1475 if (num == WEAPON_CYCLE)
1477 num = 0;
1479 if (num < 0)
1481 num = WEAPON_CYCLE - 1;
1483 if (DPCWeaponEquipCore(weapon_order[num], FALSE))
1485 count = WEAPON_CYCLE;
1487 num = num + dir;
1491 static void HackFOVCompute(void)
1493 mxs_vector vecs[4];
1494 mxs_matrix m1, m2;
1495 mxs_angvec av1, av2;
1496 r3_get_view_pyr_vecs(vecs);
1498 mxs_vector *v1 = &vecs[0];
1499 mxs_vector *v2 = &vecs[2];
1501 // take the view pyramid and turn it into angvecs
1502 // by first converting into a rotation matrix
1503 mx_mk_move_x_mat(&m1, v1);
1504 mx_mk_move_x_mat(&m2, v2);
1506 // then deconstructing that
1507 mx_mat2ang(&av1, &m1);
1508 mx_mat2ang(&av2, &m2);
1510 //mprintf ("v1 = %g, %g, %g v2 = %g, %g, %g \n",av1.el[0],av1.el[1],av1.el[2],av2.el[0],av2.el[1],av2.el[2]);
1511 //mprintf ("delta = %g %g %g\n",av1.el[0] - av2.el[0],av1.el[1] - av2.el[1],av1.el[2] - av2.el[2]);
1514 #pragma on(unreferenced)
1516 // per frame updates, for now just spells
1517 // #define PICK_DIST 35
1518 void DPC_sim_update_frame(int ms)
1520 ectsAnimTxtTime=GetSimTime();
1521 ectsAnimTxtUpdateAll();
1523 Point mpt;
1524 mouse_get_xy(&mpt.x,&mpt.y);
1526 headmoveCheck(PlayerCamera(),ms);
1527 playerHeadControl();
1528 // highlit_obj =
1529 doMouseFocusCheck();
1531 sGameParams *params = GetGameParams();
1532 if (!DPC_mouse)
1534 // set focus way out for non-cursor mode
1535 //PickSetFocus(fix_make(mpt.x, 0), fix_make(mpt.y, 0), 10000);
1537 sScrnMode smode;
1538 ScrnModeGet(&smode);
1540 PickSetFocus(fix_make(smode.w / 2,0),fix_make(smode.h / 2,0),params->frobdist);
1541 //PickSetFocus(fix_make(smode.w / 2,0),fix_make(smode.h / 2,0),64);
1543 //doHeadFocusCheck();
1545 else
1547 // pull focus in
1548 PickSetFocus(fix_make(mpt.x, 0), fix_make(mpt.y, 0), params->frobdist);
1552 // Jon: what is this doing?
1553 // Xemu: I think this is intended for checking object consistency per frame and whatnot
1555 IObjectQuery* pQuery;
1556 IObjectSystem* pOS = AppGetObj(IObjectSystem);
1558 pQuery = IObjectSystem_Iter(pOS, kObjectConcrete);
1559 for (; !IObjectQuery_Done(pQuery); IObjectQuery_Next(pQuery))
1561 ObjID id = IObjectQuery_Object(pQuery);
1564 SafeRelease(pQuery);
1565 SafeRelease(pOS);
1568 PickFrameUpdate();
1569 DPC_pick_reset();
1571 PlayerCbllmUpdate(ms);
1572 BreathSimUpdateFrame(ms);
1575 // post render frame updates
1576 void DPC_rend_update_frame(void)
1578 // update_player_medium_sounds();
1581 #pragma off(unreferenced)
1582 static bool key_handler_func(uiEvent* ev, Region* r, void* data)
1584 uiCookedKeyEvent* kev = (uiCookedKeyEvent*)ev;
1585 return DPC_key_parse(kev->code);
1587 #pragma on(unreferenced)
1590 // In-game command terminal
1593 #define NUM_CMD_TERM_LINES 2
1594 #define NUM_BUG_TERM_LINES 10
1595 #define CMD_Y_MARGIN 2
1597 static void build_cmd_term(LGadRoot* root)
1599 Rect r = *LGadBoxRect(root);
1600 short w,h;
1602 guiStyleSetupFont(NULL,StyleFontNormal);
1603 gr_string_size("X",&w,&h);
1604 guiStyleCleanupFont(NULL,StyleFontNormal);
1606 r.lr.y = h * NUM_CMD_TERM_LINES + CMD_Y_MARGIN;
1607 CreateCommandTerminal(root,&r,kCmdTermHideUnfocused);
1609 r.lr.y = h * NUM_BUG_TERM_LINES + CMD_Y_MARGIN;
1610 CreateBugTerminal(root,&r,kCmdTermHideUnfocused);
1613 static int key_handler_id;
1614 static int mouse_handler_id;
1616 void DPC_start_gamemode(void)
1618 LGadRoot* root = LGadCurrentRoot();
1619 uiInstallRegionHandler(LGadBoxRegion(root),UI_EVENT_KBD_COOKED,key_handler_func,NULL,&key_handler_id);
1620 //uiInstallRegionHandler(LGadBoxRegion(root),UI_EVENT_MOUSE,mouse_handler_func,NULL,&mouse_handler_id);
1621 g_pInputBinder->SetValidEvents (ALL_EVENTS); // & (~UI_EVENT_MOUSE));
1623 DPCUtilInitColor();
1625 PickSetCanvas();
1627 //uiDoubleClickTime = 250;
1628 //uiDoubleClickDelay = 100;
1630 build_cmd_term(root);
1632 if (gScrnLoopSetModeFailed)
1634 cStr str = FetchUIString("misc","set_mode_failed","strings");
1635 DPCOverlayAddText(str,DEFAULT_MSG_TIME);
1639 void DPC_end_gamemode(void)
1641 if (DPC_mouse)
1643 MouseMode(FALSE,TRUE);
1646 //uiDoubleClickTime = 0;
1647 //uiDoubleClickDelay = 0;
1649 uiShowMouse(NULL);
1651 if (DPC_mouse_loaded)
1653 //DPC_mouse_hnd->Unlock();
1654 SafeFreeHnd(&DPC_mouse_hnd);
1655 DPC_mouse_loaded = FALSE;
1658 LGadRoot* root = LGadCurrentRoot();
1659 uiRemoveRegionHandler(LGadBoxRegion(root),key_handler_id);
1660 AutoAppIPtr(PlayerGun);
1661 pPlayerGun->Off();
1662 DestroyCommandTerminal();
1663 DestroyBugTerminal();
1665 AutoAppIPtr(DPCCamera);
1666 pDPCCamera->SetEditMode(kCameraNormal);
1669 #ifndef SHIP
1671 void DPCSetViewRect(char* args)
1673 int x1 = 0;
1674 int y1 = 0;
1675 int x2 = 640;
1676 int y2 = 480;
1677 sscanf(args,"%d,%d,%d,%d",&x1,&y1,&x2,&y2);
1678 dpc_rend_rect.ul.x = x1;
1679 dpc_rend_rect.ul.y = y1;
1680 dpc_rend_rect.lr.x = x2;
1681 dpc_rend_rect.lr.y = y2;
1685 void SendSwitch(char *pObjName)
1687 AutoAppIPtr(ScriptMan);
1688 AutoAppIPtr(ObjectSystem);
1690 ObjID objID = pObjectSystem->GetObjectNamed(pObjName);
1691 if (objID != OBJ_NULL)
1693 //mprintf("Sending fake TurnOn to obj %d (%s)\n",objID,pObjName);
1694 sScrMsg msg(objID, "TurnOn");
1695 pScriptMan->SendMessage(&msg);
1699 void TestHUD(int objID)
1701 if (objID != OBJ_NULL)
1703 gPropHUDTime->Set(objID, GetSimTime() + 5000);
1707 #endif
1709 ////////////////////////////////////////////////////////////
1710 // PLAYER OBJECT CALLBACKS
1715 static void player_create_CB(ePlayerEvent event, ObjID player)
1717 switch (event)
1719 case kPlayerCreate:
1721 char buf[80];
1722 // @TODO: get rid of this once the player archetype has the
1723 // correct model
1724 if (config_get_raw("player_model",buf,sizeof(buf)))
1726 buf[sizeof(buf)-1] = '\0';
1727 ObjSetModelName(player,buf);
1730 PhysCreateDefaultPlayer(player);
1732 // make the player "special"
1733 cPhysModel *pModel = g_PhysModels.Get(player);
1734 Assert_(pModel != NULL);
1735 pModel->SetFlagState(kPMF_Special, TRUE);
1736 UpdatePhysProperty(player, PHYS_TYPE);
1738 AutoAppIPtr(NetManager);
1739 if (pNetManager->IsNetworkGame())
1741 // Register the player object in the proxy tables. This used
1742 // to happen at synch time, but now needs to be available
1743 // before we start processing the player's scripts.
1744 AutoAppIPtr(ObjectNetworking);
1745 pObjectNetworking->ObjRegisterProxy(player, player, player);
1748 PlayerCbllmCreate(); // creates "lower brain" and body
1750 break;
1752 case kPlayerLoad:
1753 PlayerCbllmCreate(); // creates "lower brain" and body
1756 // @HACK: get the players connected to each other. This will
1757 // go away once we have the new joinup major mode.
1758 AutoAppIPtr(NetManager);
1759 if (pNetManager->IsNetworkGame()) {
1760 JoinUp();
1764 break;
1766 case kPlayerDestroy:
1767 PlayerCbllmDestroy();
1768 break;
1773 // Look through the playerfactory links on the level. Ideally, we find
1774 // a link whose data is this player's playernum. If not, we use some other
1775 // link as a default.
1776 static ObjID player_factory_CB(void)
1778 AutoAppIPtr_(LinkManager,pLinkMan);
1779 cAutoIPtr<IRelation> pRel ( pLinkMan->GetRelationNamed("PlayerFactory") );
1781 ulong myPlayerNum;
1782 AutoAppIPtr(NetManager);
1783 if (pNetManager->IsNetworkGame())
1785 myPlayerNum = pNetManager->MyPlayerNum();
1787 else
1789 myPlayerNum = 0;
1792 // LinkID id = pRel->GetSingleLink(LINKOBJ_WILDCARD,LINKOBJ_WILDCARD);
1793 LinkID defaultFactory = LINKID_NULL;
1794 LinkID id = LINKID_NULL;
1795 ILinkQuery *pQuery = pRel->Query(LINKOBJ_WILDCARD,LINKOBJ_WILDCARD);
1796 if (pQuery == NULL)
1797 return OBJ_NULL;
1799 // Run through the PlayerFactory links, and see if any of them work
1800 for ( ; (!pQuery->Done()) && (id == LINKID_NULL); pQuery->Next())
1802 int *factoryPtr = (int *) pQuery->Data();
1803 if (factoryPtr == NULL)
1805 // It's an old factory with no player num; use it as the
1806 // default
1807 defaultFactory = pQuery->ID();
1809 else
1811 int factoryNum = *factoryPtr;
1812 if (factoryNum == myPlayerNum)
1814 // Got the right one
1815 id = pQuery->ID();
1817 else if (defaultFactory == LINKID_NULL)
1819 // We don't have any default yet, so try this one
1820 defaultFactory = pQuery->ID();
1825 SafeRelease(pQuery);
1827 if (id == LINKID_NULL)
1829 // We didn't find an appropriate one, so fall back on a default
1830 if (defaultFactory == LINKID_NULL)
1832 // There aren't *any* factories on this level!
1833 return OBJ_NULL;
1835 else
1837 id = defaultFactory;
1841 sLink link;
1842 pRel->Get(id,&link);
1843 return link.source;
1846 static void setup_player_CB()
1848 HookPlayerCreate(player_create_CB);
1849 HookPlayerFactory(player_factory_CB);
1852 ////////////////////////////////////////////////////////////
1853 // CONTAINS LISTENER
1856 static BOOL contain_CB(eContainsEvent ev, ObjID outer, ObjID inner, eContainType , ContainCBData )
1858 switch (ev)
1860 case kContainRemove:
1861 //ObjSetHasRefs(inner,TRUE);
1862 break;
1863 case kContainAdd:
1865 AutoAppIPtr(ObjectNetworking);
1866 if (!pObjectNetworking->ObjIsProxy(inner))
1868 ObjSetHasRefs(inner,FALSE);
1869 // @HACK: Need to make sure this dereg gets broadcast, even
1870 // though the object's now in the container:
1871 PhysNetForceContainedMsgs(TRUE);
1872 PhysDeregisterModel(inner);
1873 PhysNetForceContainedMsgs(FALSE);
1874 ObjForceReref(inner);
1876 break;
1879 return TRUE;
1882 static void setup_contain_CB(void)
1884 AutoAppIPtr(ContainSys);
1885 pContainSys->Listen(OBJ_NULL,contain_CB,NULL);
1888 ////////////////////////////////////////
1889 // Init culpability
1890 struct sCulpRelations
1892 const char* name;
1893 ulong flags;
1896 static sCulpRelations culp_rels[] =
1898 { "~Firer", kCulpTransitive},
1899 { "CurWeapon", 0},
1902 #define NUM_CULP_RELS (sizeof(culp_rels)/sizeof(culp_rels[0]))
1904 // Set up culpability relations for dark
1905 static void DPC_init_culpability()
1907 // set up culpability listeners
1908 AutoAppIPtr_(LinkManager,pLinkMan);
1909 for (int i = 0; i < NUM_CULP_RELS; i++)
1911 sCulpRelations& rel = culp_rels[i];
1912 cAutoIPtr<IRelation> pRel = pLinkMan->GetRelationNamed(rel.name);
1913 AddCulpabilityRelation(pRel,rel.flags);
1917 ///////////////////////////////////////////
1918 // Skill related parameters
1921 // Here's my descriptor, which identifies my stuff to the tag file & editor
1922 sFileVarDesc gBindTableDesc =
1924 kCampaignVar, // Where do I get saved?
1925 "BINDTABLE", // Tag file tag
1926 "Bind Table", // friendly name
1927 FILEVAR_TYPE(sBindTable), // Type (for editing)
1928 {1, 0}, // version
1929 {1, 0}, // last valid version
1930 "deepc", // optional: what game am I in NULL means all
1933 ////////////////////////////////////////
1934 extern void DPCOpenMFD(int which);
1936 static void DPCSummonObj(char *args)
1938 BOOL slim_mode;
1939 AutoAppIPtr(QuestData);
1940 slim_mode = pQuestData->Get("HideInterface");
1942 // don't allow summoning (like nav markers) if we are pre-HUD
1943 if (slim_mode)
1944 return;
1946 AutoAppIPtr(ObjectSystem);
1948 ObjID arch, newobj;
1949 ObjPos *pos;
1950 mxs_vector throwvec = {1.0, 0, 0};
1952 arch = pObjectSystem->GetObjectNamed(args);
1953 if (arch == OBJ_NULL)
1954 return;
1956 if (!OBJ_IS_CONCRETE(arch))
1958 newobj = pObjectSystem->BeginCreate(arch,kObjectConcrete);
1959 pos = ObjPosGet(PlayerObject());
1960 ObjPosSetLocation(newobj, &pos->loc);
1961 pObjectSystem->EndCreate(newobj);
1962 //pGameTools->TeleportObject(newobj, pos->loc.vec, fac);
1963 PhysSetVelocity(newobj, &throwvec);
1967 static void DPCUbermensch(void)
1969 ObjID plr = PlayerObject();
1970 if (plr == OBJ_NULL)
1971 return;
1973 // give the player max stats & skills
1974 int i;
1975 sStatsDesc stats;
1976 for (i=0; i < 5; i++)
1977 stats.m_stats[i] = 6;
1978 g_BaseStatsProperty->Set(plr,&stats);
1980 sWeaponSkills wpnskill;
1981 for (i=0; i < 4; i++)
1982 wpnskill.m_wpn[i] = 6;
1983 g_BaseWeaponProperty->Set(plr,&wpnskill);
1985 sTechSkills techskill;
1986 for (i=0; i < 5; i++)
1987 techskill.m_tech[i] = 6;
1988 g_BaseTechProperty->Set(plr,&techskill);
1990 AutoAppIPtr(DPCPlayer);
1991 pDPCPlayer->RecalcData(plr);
1995 void DPCVersion()
1997 DPCOverlayAddText(AppName(),DEFAULT_MSG_TIME);
2000 extern void DPCEditSynchBrushTextures(void);
2001 extern void DPCEditSynchBrushScales(void);
2002 extern void DPCEditSynchBrushFull(void);
2003 extern void DPCEditMakeDecalBrush(char *args);
2004 //extern void DPCElevatorTest(char *args);
2005 extern void DPCLoadFull(const char *args);
2006 extern void DPCGainPool(int amt);
2007 extern void DPCTrainMFD(int amt);
2008 extern void DPCLoadGameAndLevel(char *args);
2010 static Command DPCDebugKeys[] =
2013 //{ "elevator_test", FUNC_STRING, DPCElevatorTest, "Elevator-transport between two levels"},
2014 { "dpc_save_game", FUNC_INT, DPCSaveGame, ""},
2015 { "dpc_load_game", FUNC_INT, TransModeLoadGame, ""},
2016 #ifndef SHIP
2017 { "dpc_load_full", FUNC_STRING, DPCLoadFull, ""},
2018 //{ "dpc_load_level", FUNC_STRING, DPCLoadGameAndLevel, "[dpc_load_level <slot> <name>] Loads the slot, and goes into the named level"},
2020 { "compute_fov", FUNC_VOID, HackFOVCompute, ""},
2021 { "letterbox", FUNC_BOOL, DPCLetterboxSet, "Set letterbox mode."},
2022 #endif
2024 { "summon_obj", FUNC_STRING, DPCSummonObj, "Summon an object."},
2025 { "ubermensch", FUNC_VOID, DPCUbermensch, "Turns the player into homo superior."},
2026 { "add_pool", FUNC_INT, DPCGainPool, "Give player additional build pool points"},
2027 { "show_version", FUNC_VOID, DPCVersion, "Display version in game mode."},
2029 // editing commands
2030 #ifdef EDITOR
2031 //{ "set_view_rect", FUNC_STRING, DPCSetViewRect, "Set the game view rect"},
2032 { "send_switch", FUNC_STRING, SendSwitch, "Send a switch message to an object"},
2033 { "test_HUD", FUNC_INT, TestHUD, "Put HUD brackets around an object."},
2035 { "camera_pos", FUNC_VOID, CameraPositionSpew, "spew the camera position"},
2036 { "camera_attach", FUNC_STRING, DPCCameraAttach, "attach the camera position"},
2037 { "camera_rec", FUNC_VOID, SetCameraEditStateRecord, "Set the camera edit state to record"},
2038 { "camera_edit", FUNC_VOID, SetCameraEditStateEdit, "Set the camera edit state to edit"},
2039 { "camera_play", FUNC_VOID, SetCameraEditStatePlayback, "Set the camera edit state to playback"},
2040 { "set_camera_speed", FUNC_FLOAT, SetCameraEditSpeed, "Set the edit camera speed"},
2041 { "make_scenes", FUNC_VOID, MakeScenes, "Make all the scene binaries"},
2042 { "cs_start", FUNC_INT, CutSceneStart, "Start a conversation-based cut-scene (conversationID)"},
2043 { "cs_rec", FUNC_INT, CutSceneRecord, "Record a new track for a conversation-based cut-scene (conversationID)"},
2044 { "cs_edit", FUNC_INT, CutSceneEdit, "Edit a conversation-based cut-scene (conversationID)"},
2045 { "cs_play", FUNC_INT, CutScenePlayback, "Playback a conversation-based cut-scene (conversationID)"},
2047 { "train_mfd", FUNC_INT, DPCTrainMFD, "Open up a training MFD"},
2049 { "synch_brush_tx", FUNC_VOID, DPCEditSynchBrushTextures, "Set all textures to current face val"},
2050 { "synch_brush_scale", FUNC_VOID, DPCEditSynchBrushScales, "Synch all txt scales to current faces val"},
2051 { "synch_brush_full", FUNC_VOID, DPCEditSynchBrushFull, "Synch textures & scales"},
2052 { "decal_brush", FUNC_STRING, DPCEditMakeDecalBrush, "[decal_brush x,y] Creates a decal brush off the selected face."},
2053 // physics update
2054 // { "update_creature_physics", FUNC_VOID, UpdateCreaturesPhysics, "Update special flag on creature physics"},
2055 #endif
2059 extern void DrawHistoryToggle(void);
2060 extern void DPCPDAPlayUnreadLog();
2062 void
2063 DPCUseCamera(void)
2065 AutoAppIPtr(DPCPlayer);
2066 AutoAppIPtr(ContainSys);
2067 AutoAppIPtr(ScriptMan);
2068 ObjID targetObj, camObj, player = PlayerObject();
2069 BOOL hasCamera = FALSE;
2070 BOOL anySuccess = FALSE;
2071 int ammoCount;
2073 sContainIter *piter = pContainSys->IterStart(player);
2075 while (!piter->finished)
2077 if (piter->type < DPCCONTAIN_PDOLLBASE)
2079 if (gPropIsPlayerCamera->IsRelevant(camObj = piter->containee)) {
2080 hasCamera = TRUE;
2081 break;
2084 pContainSys->IterNext(piter);
2087 pContainSys->IterEnd(piter);
2089 if (!hasCamera) {
2090 // TDB: play complaint
2091 return;
2094 if ((ammoCount = GunStateGetAmmo(camObj)) <= 0) {
2095 // TDB: play complaint
2096 return;
2099 sPropertyObjIter iter;
2100 gPropIsCameraTarget->IterStart(&iter);
2101 while (gPropIsCameraTarget->IterNext(&iter,&targetObj))
2103 // Camera targets have vhot 0 and vhot 1. vhot 0 is the point
2104 // to be photographed; vhot 1 is a little out from that in a
2105 // normal direction, so the angle of the photo can be enforced.
2106 BOOL success = TRUE;
2107 mxs_vector vHotLoc0, vHotLoc1, camPos;
2108 Location loc0, loc1, hit, camLoc;
2109 ObjPos *playPos = ObjPosGet(player);
2110 ObjID hitObj;
2111 mxs_angvec camAng;
2112 CameraGetLocation(PlayerCamera(), &camPos, &camAng);
2113 VHotGetLoc(&vHotLoc0, targetObj, 0);
2114 VHotGetLoc(&vHotLoc1, targetObj, 1);
2115 MakeLocationFromVector(&loc0, &vHotLoc0);
2116 MakeLocationFromVector(&loc1, &vHotLoc1);
2117 MakeLocationFromVector(&camLoc, &camPos);
2118 if (
2119 (!PhysRaycast(loc0, camLoc, &hit, &hitObj, 0.0) ==
2120 kCollideSphere) && (hitObj == player)
2123 success = FALSE;
2126 mxs_vector hot1Hot0Vec;
2127 mx_sub_vec(&hot1Hot0Vec, &vHotLoc1, &vHotLoc0);
2128 mxs_vector playerHot0Vec;
2129 mx_sub_vec(&playerHot0Vec, &camPos, &vHotLoc0);
2131 // Make sure not too far away
2132 #define MIN_CAMERA_TARGET_DIST 25
2133 if (mx_mag_vec(&playerHot0Vec) > MIN_CAMERA_TARGET_DIST) {
2134 success = FALSE;
2137 // Make sure position is not too far off from normal (vhot0, vhot1)
2138 float dot = mx_dot_vec(&hot1Hot0Vec, &playerHot0Vec);
2139 float angle =
2140 acos(dot /
2141 (mx_mag_vec(&hot1Hot0Vec) * mx_mag_vec(&playerHot0Vec)));
2142 #define MAX_CAMERA_TARGET_ANGLE 1.0 // 57 degrees
2143 if (fabs(angle) > MAX_CAMERA_TARGET_ANGLE) {
2144 success = FALSE;
2147 // Make sure we are facing (near enough) the target by comparison
2148 // with normal
2149 // First figure out player facing direction
2150 mxs_matrix orientMat;
2151 mx_ang2mat(&orientMat, &camAng);
2152 // Flip direction of of playerHot0Vec for some reason (so following
2153 // angle computation faces right way)
2154 mx_negeq_vec(&playerHot0Vec);
2155 dot = mx_dot_vec(&playerHot0Vec, &orientMat.vec[0]);
2157 angle =
2158 acos(dot /
2159 (mx_mag_vec(&playerHot0Vec) * mx_mag_vec(&orientMat.vec[0])));
2161 #define MAX_SCREEN_ANGLE 0.6 // More than this and thing is probably off screen
2162 if (fabs(angle) > MAX_SCREEN_ANGLE) {
2163 success = FALSE;
2166 if (success) {
2167 // TBD: hook into quest
2168 anySuccess = TRUE;
2169 sScrMsg msg(player,"PictureTaken");
2170 msg.data = targetObj;
2171 pScriptMan->SendMessage(&msg);
2175 gPropIsCameraTarget->IterStop(&iter);
2177 sScrMsg msg(player,"UseCamera");
2178 msg.data = anySuccess;
2179 pScriptMan->SendMessage(&msg);
2181 GunStateSetAmmo(camObj, --ammoCount);
2184 static Command DPCCommands[] =
2186 // hotkey accelerators
2187 { "toggle_inv", FUNC_VOID, DPCToggleInv, "toggle inv panel"},
2188 { "cycle_ammo", FUNC_VOID, DPCCycleAmmo, "cycle through available ammo types"},
2189 { "toggle_compass", FUNC_VOID, DPCToggleCompass, "toggle compass state"},
2190 { "query", FUNC_INT, DPCQueryMode, "query cursor 1 = on 0 = off"},
2191 { "split", FUNC_INT, DPCSplitMode, "split cursor 1 = on 0 = off"},
2192 { "DPC_jump_player", FUNC_VOID, DPCPlayerJump, "jump the player"},
2193 { "look_cursor", FUNC_VOID, DPCLookCursor, "puts cursor into look mode"},
2194 { "reload_gun", FUNC_VOID, DPCAmmoReload, "reloads weapon out of inventory"},
2195 { "swap_guns", FUNC_VOID, DPCSwapGuns, "switches primary and secondary weapons"},
2196 { "wpn_setting_toggle", FUNC_VOID, DPCSettingToggle, "toggles between weapon settings"},
2197 { "equip_weapon", FUNC_STRING, DPCWeaponEquip, "searches your inv for a particular weapon and equips it"},
2198 { "cycle_weapon", FUNC_INT, DPCWeaponCycle, "Cycles through next equippable weapon, 1 for fwd, -1 for back"},
2199 { "clear_weapon", FUNC_VOID, DPCWeaponUnequip, "unequips current weapon"},
2200 { "unjam_weapon", FUNC_VOID, DPCWeaponUnjam, "Attempts to unjam current weapon"},
2201 { "open_mfd", FUNC_INT, DPCOpenMFD, "Open up an MFD by overlay constant"},
2202 { "stop_email", FUNC_VOID, DPCEmailStop, "Stop any currently playing email/log"},
2203 { "use_obj", FUNC_STRING, DPCUseObj, "Use an object by name"},
2204 { "msg_history", FUNC_VOID, DrawHistoryToggle, "Toggle message history"},
2205 { "play_unread_log", FUNC_VOID, DPCPDAPlayUnreadLog, "Play an unread log"},
2206 { "use_camera", FUNC_VOID, DPCUseCamera, "Use camera"},
2208 // basic interface support
2209 { "toggle_mouse", FUNC_VOID, DPCToggleMode, "switch between mouselook & cursor modes"},
2210 { "frob_toggle", FUNC_VOID, DPCFrobAndMaybeToggleMode, "switch between modes, also frobbing current selection"},
2211 { "frob_object", FUNC_VOID, DPCFrobObject, "simple frob of selected object"},
2212 { "frob_object_inv", FUNC_VOID, DPCFrobObjectInv, "simple frob of selected object, in world or in inv"},
2213 { "mp_hilight_obj", FUNC_VOID, DPCHilightObject, "hilight an object in MP game"},
2214 //{ "interface_click", FUNC_VOID, DPCInterfaceClick, "interact with objects / interface" },
2215 { "interface_use", FUNC_VOID, DPCInterfaceUseItem, "inv use an item"},
2216 { "fire_weapon", FUNC_INT, DPCFireWeapon, "fire weapon 1 = start 0 = finish"},
2217 { "drag_and_drop", FUNC_INT, DPCDragDropSimple, "drag & drop 1 = start 0 = finish"},
2218 { "drag_and_drop_frob", FUNC_INT, DPCDragDropFrob, "drag & drop 1 = start 0 = finish"},
2219 { "drag_and_drop_mode", FUNC_INT, DPCDragDropMode, "drag & drop 1 = start 0 = finish"},
2220 //{ "dragndrop", FUNC_VOID, DPCBeginDragDrop, "begin drag & drop operation" },
2221 //{ "end_dragndrop", FUNC_VOID, DPCBeginDragDrop, "begin drag & drop operation" },
2223 //{ "fire_at_cursor", FUNC_INT, DPCFireCursor, "fire weapon at cursor, 1=start 0=finish"},
2224 { "test_begin", FUNC_VOID, DPCBeginGame, ""},
2225 { "quicksave", FUNC_VOID, DPCQuickSaveHack, "Save to 'current' subdir."},
2226 { "quickload", FUNC_VOID, DPCQuickLoad, "Load from 'current' subdir."},
2229 // Init the Deep Cover-specific game tools.
2230 void DPCToolsInit(void)
2232 IGameTools* pGameTools = AppGetObj(IGameTools);
2233 pGameTools->SetIsToGameModeGUIDCallback(DPCIsToGameModeGUID);
2234 SafeRelease(pGameTools);
2237 void DPC_init_game(void)
2239 COMMANDS(DPCCommands,HK_ALL); // GAME_MODE | HK_GAME2_MODE);
2240 // note, debug keys are included in ship build as cheat keys
2241 COMMANDS(DPCDebugKeys,HK_ALL);
2243 // Install damage listener/filters
2244 IDamageModel* pDamageModel = AppGetObj(IDamageModel);
2245 pDamageModel->Listen(kDamageMsgImpact | kDamageMsgSlay | kDamageMsgDamage, DPCDamageListener, NULL);
2246 pDamageModel->Listen(kDamageMsgTerminate, DPCLootDamageListener,NULL);
2247 SafeRelease(pDamageModel);
2249 DPCReactionsInit();
2251 DPCUtilsInit();
2253 GunInit();
2254 setup_player_CB();
2255 setup_contain_CB();
2257 // man, we should clean this up some
2258 AutoAppIPtr(PlayerGun);
2259 pPlayerGun->GameInit();
2260 DPCPropertiesInit();
2261 CannisterPropertyInit();
2262 InvDimsPropertyInit();
2263 DoorOpenSoundPropertyInit();
2264 DoorCloseSoundPropertyInit();
2265 DoorTimerPropertyInit();
2266 DPCFrobsysInit();
2267 ObjSoundNamePropInit();
2268 DPCCreaturesInit();
2269 DPCDamageInit();
2270 DPCKeyInit();
2271 DPCFrobPropertiesInit();
2272 DPCPlayerDamageInit();
2273 DPCAIInit();
2274 DPCLinksInit();
2275 MeleeTypePropertyInit();
2276 DPCParamEditInit();
2277 DarkDifficultyInit();
2278 DPCMenusInit();
2279 DPCSoundInit();
2280 CameraObjPropertyInit();
2281 DPCMeleeInit();
2282 GunProjectileInit();
2283 DPCPDANetInit();
2284 DPCBloodInit();
2285 DPCSaveUIInit();
2287 DPCInvListenInit();
2288 DPCOverlayListenInit();
2290 SetGameIBVarsFunc (InitDPCIBVars);
2292 DPCOptionsMenuInit();
2293 DPCMasterModeInit();
2294 DPCReportInit();
2296 DPC_init_culpability();
2297 DPCToolsInit();
2299 // Network messages for the game level:
2300 g_pThrowObjMsg = new cNetMsg(&sThrowObjDesc);
2302 // stolen from dark
2303 BreathSimInit();
2305 // Choose game mode
2306 #ifdef EDITOR
2307 BOOL start_game = config_is_defined("play");
2308 #else
2309 BOOL start_game = TRUE;
2310 #endif
2312 // hack to set initial difficulty level
2313 int diffval = 0;
2314 config_get_int("difficulty",&diffval);
2315 AutoAppIPtr(QuestData);
2316 pQuestData->Create("Difficulty",diffval,kQuestDataCampaign);
2318 if (start_game)
2320 gPrimordialMode = DescribeDPCMasterMode();
2322 if (config_is_defined("quick_start"))
2324 gPrimordialMode = DescribeDPCInitGameMode();
2328 void DPC_term_game(void)
2330 DPCDamageShutDown();
2331 DPCCreaturesTerm();
2332 DPCPlayerDamageTerm();
2333 AutoAppIPtr(PlayerGun);
2334 pPlayerGun->GameTerm();
2335 DPCLinksTerm();
2336 DPCPropertiesShutdown();
2337 MeleeTypePropertyShutdown();
2338 DPCUtilsTerm();
2339 DarkDifficultyTerm();
2340 DPCMenusTerm();
2341 DPCSoundTerm();
2342 CameraObjPropertyTerm();
2343 DPCOptionsMenuTerm();
2344 DPCKeyTerm();
2345 DPCMeleeTerm();
2346 DPCMasterModeTerm();
2347 GunProjectileTerm();
2348 DPCPDANetTerm();
2349 DPCFrobsysTerm();
2350 DPCReportTerm();
2351 DPCBloodTerm();
2352 DPCSaveUITerm();
2354 // Delete network message:
2355 delete g_pThrowObjMsg;