convert line ends
[canaan.git] / prj / cam / src / physics / phmod.cpp
blob561ed758fee233e383fd06edb518d0436d229473
1 /*
2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
4 */
6 ///////////////////////////////////////////////////////////////////////////////
7 // $Header: r:/t2repos/thief2/src/physics/phmod.cpp,v 1.154 2000/03/20 09:45:23 adurant Exp $
8 //
9 // Model-specific code
12 //#define PROFILE_ON
14 #include <lg.h>
15 #include <config.h>
16 #include <allocapi.h>
17 #include <matrixs.h>
18 #include <timings.h>
19 #include <float.h>
21 #include <wrtype.h>
22 #include <objpos.h>
23 #include <sphrcst.h>
24 #include <creatext.h>
25 #include <doorprop.h>
26 #include <prjctile.h>
27 #include <port.h>
28 #include <plyrspd.h>
30 #include <playrobj.h>
31 #include <plyrmode.h>
32 #include <netman.h>
33 #include <iobjnet.h>
35 // for squishing
36 #include <stimtype.h>
37 #include <stimbase.h>
38 #include <stimsens.h>
39 #include <stimul8r.h>
40 #include <simtime.h>
42 #include <autolink.h>
43 #include <lnkquery.h>
44 #include <linkbase.h>
46 #include <aiapi.h> // for ObjIsAI()
47 #include <media.h>
48 #include <objmedia.h>
49 #include <physapi.h>
50 #include <phclimb.h>
51 #include <phconst.h>
52 #include <phcontct.h>
53 #include <phcore.h>
54 #include <phmod.h>
55 #include <phmods.h>
56 #include <phdyn.h>
57 #include <phctrl.h>
58 #include <phclsn.h>
59 #include <phref.h>
60 #include <phutils.h>
61 #include <phmoapi.h>
62 #include <phprop.h>
63 #include <phoprop.h>
64 #include <phmtprop.h>
65 #include <phnet.h>
67 #include <phmsg.h>
68 #include <phscrt.h>
70 #include <iobjsys.h>
71 #include <appagg.h>
73 // For disk check:
74 #include <aipthobb.h>
75 #include <aiprcore.h>
78 #include <hshsttem.h>
81 // Must be last header
82 #include <dbmem.h>
84 extern BOOL gInsideMT;
86 mxs_real kSpringCapMag = 25.0; //extern deffed in phconst
88 ///////////////////////////////////////////////////////////////////////////////
90 // CLASS: cPhysModelTable
93 #if defined(_MSC_VER)
94 template cPhysModelTableBase;
95 #endif
97 tHashSetKey cPhysModelTable::GetKey(tHashSetNode node) const
99 return (tHashSetKey)((((cPhysModel *)(node))->m_objID));
102 ///////////////////////////////////////////////////////////////////////////////
104 // CLASS: cPhysModel
107 cPhysModel::cPhysModel(ObjID objID, ePhysModelType type,
108 tPhysSubModId numSubModels, unsigned flags)
109 : m_objID(objID),
110 m_nSubModels(numSubModels),
111 m_flags(0),
112 m_base_friction(0),
113 m_nObjectContacts(0),
114 m_nFaceContacts(0),
115 m_nEdgeContacts(0),
116 m_nVertexContacts(0),
117 m_pointVsTerrain(FALSE),
118 m_passThruDT(0),
119 bDiskCheck(TRUE)
121 ILinkQuery *query;
122 int i;
124 // Sphere-hats always have 2 submodels
125 if (type == kPMT_SphereHat)
126 m_nSubModels = 2;
128 // Init the flags
129 if (flags & kPMCF_LowDetail)
130 m_flags |= kPMF_LowDetail;
131 if (flags & kPMCF_Remote)
132 m_flags |= kPMF_Remote;
133 if (flags & kPMCF_NonMoveable)
134 m_flags |= kPMF_NonMoveable;
135 if (flags & kPMCF_Uncontrollable)
136 m_flags |= kPMF_Uncontrollable;
137 if (flags & kPMCF_Player)
138 m_flags |= kPMF_Player;
139 if (flags & kPMCF_Creature)
140 m_flags |= kPMF_Creature;
141 if (flags & kPMCF_Rope)
142 m_flags |= kPMF_Rope;
143 if (flags & kPMCF_Weapon)
144 m_flags |= kPMF_Weapon;
145 if (flags & kPMF_DiskCheck)
146 m_flags |= kPMF_DiskCheck;
148 BOOL facevel;
149 if (g_pPhysFaceVelProp->Get(objID, &facevel) && facevel)
150 m_flags |= kPMF_FacesVel;
152 if (g_pMovingTerrainProperty->IsRelevant(objID))
153 m_flags |= kPMF_MovingTerrain;
155 if (g_pRotDoorProperty->IsRelevant(objID) || g_pTransDoorProperty->IsRelevant(objID))
156 m_flags |= kPMF_Door;
158 BOOL ai_collides;
159 if (g_pPhysAICollideProp->Get(objID, &ai_collides) && ai_collides)
160 m_flags |= kPMF_AICollides;
162 if (flags & kPMCF_NoGravity)
163 m_gravity = 0.0;
164 else
165 m_gravity = 1.0;
167 // Init all submodels to the given type
168 m_pType = new ePhysModelType[m_nSubModels];
169 for (i=0; i<m_nSubModels; i++)
170 m_pType[i] = type;
172 m_base_friction = 0.0;
174 // Init the spring constant
175 LGALLOC_PUSH_CREDIT();
176 m_springInfo.SetSize(m_nSubModels);
177 LGALLOC_POP_CREDIT();
178 for (i=0; i<m_nSubModels; i++)
180 m_springInfo[i].tension = 0.0;
181 m_springInfo[i].damping = 0.0;
184 // Init overall model position & cog offset
185 MakePositionFromVectors(&m_pos.m_position, &(ObjPosGet(objID)->loc.vec), &(ObjPosGet(objID)->fac));
186 MakePositionFromVectors(&m_pos.m_endposition, &m_pos.m_position.loc.vec, &m_pos.m_position.fac);
187 MakePositionFromVectors(&m_pos.m_targetposition, &m_pos.m_position.loc.vec, &m_pos.m_position.fac);
189 mx_zero_vec(&m_cog);
191 // Check for PhysAttach links
192 query = g_pPhysAttachRelation->Query(objID, LINKOBJ_WILDCARD);
193 if (!query->Done())
194 m_isAttached = TRUE;
195 else
196 m_isAttached = FALSE;
197 SafeRelease(query);
199 query = g_pPhysAttachRelation->Query(LINKOBJ_WILDCARD, objID);
200 m_nAttachments = 0;
201 for (; !query->Done(); query->Next())
202 m_nAttachments++;
203 SafeRelease(query);
205 m_rotAxes = ZAxis;
206 m_restAxes = NoAxes;
207 m_atRest = FALSE;
209 m_climbingObj = OBJ_NULL;
210 m_ropeSegment = -1;
211 m_ropePct = 0.0;
212 m_mantlingState = 0;
213 mx_zero_vec(&m_mantlingTargVec);
215 m_referenceFrameObj = OBJ_NULL;
217 m_lastSquishTime = -1.0;
219 // Allocate force list array for location controlling
220 m_pForceList = new cPhysForceList[m_nSubModels];
222 // Allocate position lists
223 m_pPosition = new cPhysPos[m_nSubModels];
225 // Allocate and initialize offsets
226 LGALLOC_PUSH_CREDIT();
227 m_Offset.SetSize(m_nSubModels);
228 LGALLOC_POP_CREDIT();
229 for (i=0; i<m_nSubModels; i++)
230 mx_zero_vec(&m_Offset[i]);
232 // Place all submodels at center of object with a zero facing
233 // and init backpointers while we're at it
234 for (i=0; i<m_nSubModels; i++)
236 MakePositionFromVectors(&m_pPosition[i].m_position, &m_pos.m_position.loc.vec, &m_pos.m_position.fac);
237 mx_zero_vec(&m_pPosition[i].m_endposition.loc.vec);
238 mx_zero_vec(&m_pPosition[i].m_targetposition.loc.vec);
239 mx_mk_angvec(&m_pPosition[i].m_endposition.fac, 0, 0, 0);
240 mx_mk_angvec(&m_pPosition[i].m_targetposition.fac, 0, 0, 0);
241 m_pPosition[i].m_pModel = this;
244 // Initialize submodel constraint lists
245 LGALLOC_PUSH_CREDIT();
246 m_SubModConstraintList.SetSize(m_nSubModels);
247 LGALLOC_POP_CREDIT();
249 // Allocate dynamics if moveable
250 if (!(flags & kPMCF_NonMoveable) && (type != kPMT_OBB))
251 m_pDynamicsData.SetSize(m_nSubModels);
252 else
253 m_pDynamicsData.SetSize(0);
255 // Allocate controls if controllable
256 if (!(flags & kPMCF_Uncontrollable) && (type != kPMT_OBB))
257 m_pControlData.SetSize(m_nSubModels);
258 else
259 m_pControlData.SetSize(0);
261 // Set up backpointers
262 m_DynamicsData.SetModel(this);
263 m_DynamicsData.SetSubModId(-1);
264 m_ControlData.SetModel(this);
265 m_ControlData.SetSubModId(-1);
267 for (i=0; i<m_nSubModels && m_pDynamicsData.Size() && m_pControlData.Size(); i++)
269 m_pDynamicsData[i].SetModel(this);
270 m_pDynamicsData[i].SetSubModId(i);
271 m_pControlData[i].SetModel(this);
272 m_pControlData[i].SetSubModId(i);
275 // Add to model lists
276 if (IsActive())
278 if (IsMoveable())
279 g_PhysModels.AddToMoving(this);
280 else
281 g_PhysModels.AddToStationary(this);
283 else
284 // low detail models start inactive by default
285 g_PhysModels.AddToInactive(this);
287 m_AngLimitList.SetSize(0);
289 m_medium = kMS_Invalid;
291 if (m_flags & kPMF_Weapon)
292 SetSleep(TRUE);
295 ///////////////////////////////////////
297 cPhysModel::cPhysModel(PhysReadWrite func) :
298 m_nFaceContacts(0),
299 m_nEdgeContacts(0),
300 m_nVertexContacts(0),
301 m_nObjectContacts(0),
302 bDiskCheck(FALSE)
304 int flag;
305 int i;
306 tPhysRef dummy;
308 AutoAppIPtr_(ObjectSystem,pObjSys);
310 func((void *)&m_objID, sizeof(ObjID), 1);
311 m_objID = pObjSys->RemapOnLoad(m_objID);
312 func((void *)&m_nSubModels, sizeof(int), 1);
313 func((void *)&m_flags, sizeof(unsigned), 1);
315 BOOL facevel;
316 if (g_pPhysFaceVelProp->Get(m_objID, &facevel) && facevel)
317 m_flags |= kPMF_FacesVel;
319 if (g_pMovingTerrainProperty->IsRelevant(m_objID))
320 m_flags |= kPMF_MovingTerrain;
322 if (g_pRotDoorProperty->IsRelevant(m_objID) || g_pTransDoorProperty->IsRelevant(m_objID))
323 m_flags |= kPMF_Door;
325 BOOL ai_collides = FALSE;
326 if (g_pPhysAICollideProp->Get(m_objID, &ai_collides) && ai_collides)
327 m_flags |= kPMF_AICollides;
329 if (g_PhysVersion >= 6)
330 func((void *)&m_gravity, sizeof(mxs_real), 1);
331 else
332 m_gravity = 1.0;
334 m_pType = new ePhysModelType[m_nSubModels];
335 func((void *)m_pType, sizeof(ePhysModelType), m_nSubModels);
337 func((void *)&m_base_friction, sizeof(mxs_real), 1);
339 if (g_PhysVersion >= 8)
340 func((void *)&m_medium, sizeof(int), 1);
341 else
342 m_medium = 1;
344 if (g_PhysVersion < 26)
345 m_medium = kMS_Invalid;
347 LGALLOC_PUSH_CREDIT();
348 m_springInfo.SetSize(m_nSubModels);
349 LGALLOC_POP_CREDIT();
350 if (g_PhysVersion >= 11)
352 for (i=0; i<m_nSubModels; i++)
354 func((void *)&m_springInfo[i].tension, sizeof(mxs_real), 1);
355 func((void *)&m_springInfo[i].damping, sizeof(mxs_real), 1);
358 else
360 for (i=0; i<m_nSubModels; i++)
362 m_springInfo[i].tension = 0.0;
363 m_springInfo[i].damping = 0.0;
367 if (g_PhysVersion >= 13)
368 func((void *)&m_pointVsTerrain, sizeof(BOOL), 1);
369 else
370 m_pointVsTerrain = FALSE;
372 if (g_PhysVersion >= 22)
373 func((void *)&m_passThruDT, sizeof(BOOL), 1);
374 else
375 m_passThruDT = 0;
377 if (g_PhysVersion >= 14)
379 func((void *)&m_nAttachments, sizeof(int), 1);
380 func((void *)&m_isAttached, sizeof(BOOL), 1);
382 else
384 m_nAttachments = 0;
385 m_isAttached = FALSE;
388 if (g_PhysVersion >= 15)
390 func((void *)&m_rotAxes, sizeof(ePhysAxes), 1);
391 func((void *)&m_restAxes, sizeof(ePhysAxes), 1);
393 else
395 m_rotAxes = ZAxis;
396 m_restAxes = NoAxes;
398 m_atRest = FALSE;
400 if (g_PhysVersion >= 18)
401 func((void *)&m_climbingObj, sizeof(ObjID), 1);
402 else
403 m_climbingObj = OBJ_NULL;
405 if (g_PhysVersion >= 21)
407 func((void *)&m_ropeSegment, sizeof(int), 1);
408 func((void *)&m_ropePct, sizeof(mxs_real), 1);
410 else
412 m_ropeSegment = -1;
413 m_ropePct = 0.0;
416 if (g_PhysVersion >= 19)
418 func((void *)&m_mantlingState, sizeof(int), 1);
419 func((void *)&m_mantlingTargVec, sizeof(mxs_vector), 1);
421 else
423 m_mantlingState = 0;
424 mx_zero_vec(&m_mantlingTargVec);
427 if (g_PhysVersion >= 31)
428 func((void *)&m_referenceFrameObj, sizeof(ObjID), 1);
429 else
430 m_referenceFrameObj = NULL;
432 if (g_PhysVersion >= 25)
433 func((void *)&m_lastSquishTime, sizeof(long), 1);
434 else
435 m_lastSquishTime = -1.0;
437 m_pForceList = new cPhysForceList[m_nSubModels];
439 // Allocate and Read positions for each submodel
440 m_pPosition = new cPhysPos[m_nSubModels];
441 if (g_PhysVersion >= 9)
442 func(m_pPosition, sizeof(cPhysPos), m_nSubModels);
443 else
445 for (i=0; i<m_nSubModels; i++)
447 func(&m_pPosition[i].m_position, sizeof(Position), 1);
448 func(&m_pPosition[i].m_endposition, sizeof(Position), 1);
449 func(&dummy, sizeof(tPhysRef), 1);
450 func(&m_pPosition[i].m_pModel, sizeof(cPhysModel *), 1);
454 if (g_PhysVersion >= 9)
455 func((void *)&m_pos, sizeof(cPhysPos), 1);
456 else
458 func(&m_pos.m_position, sizeof(Position), 1);
459 func(&m_pos.m_endposition, sizeof(Position), 1);
460 func(&dummy, sizeof(tPhysRef), 1);
461 func(&m_pos.m_pModel, sizeof(cPhysModel *), 1);
464 // Update pointers
465 for (i=0; i<m_nSubModels; i++)
466 m_pPosition[i].m_pModel = this;
467 m_pos.m_pModel = this;
469 // Read center-of-gravity
470 func((void *)&m_cog, sizeof(mxs_vector), 1);
472 // Read submodel offsets
473 LGALLOC_PUSH_CREDIT();
474 m_Offset.SetSize(m_nSubModels);
475 LGALLOC_POP_CREDIT();
476 if (g_PhysVersion >= 10)
478 for (i=0; i<m_nSubModels; i++)
479 func((void *)&m_Offset[i], sizeof(mxs_vector), 1);
481 else
483 for (i=0; i<m_nSubModels; i++)
484 mx_sub_vec(&m_Offset[i], &m_pPosition[i].m_position.loc.vec, &m_pos.m_position.loc.vec);
487 // Initialize any pressure plates that are currently in-transit
488 if ((g_PhysVersion >= 29) && IsPressurePlate())
490 int state;
492 func((void *)&state, sizeof(int), 1);
494 if ((state == kPPS_Activating) ||
495 (state == kPPS_Deactivating))
497 mxs_vector limit;
499 func((void *)&limit, sizeof(mxs_vector), 1);
501 ClearTransLimits();
502 AddTransLimit(limit, PressurePlateCallback);
506 // Initialize submodel constraint lists
507 LGALLOC_PUSH_CREDIT();
508 m_SubModConstraintList.SetSize(m_nSubModels);
509 LGALLOC_POP_CREDIT();
511 // Allocate and Read dynamics and control info, if applicable
512 func(&flag, sizeof(int), 1);
513 if (flag == 0x0001)
515 if (g_PhysVersion <= 11)
516 m_DynamicsData.LoadV11(func);
517 else
518 func(&m_DynamicsData, sizeof(cPhysDynData), 1);
519 m_pDynamicsData.SetSize(0);
521 else
522 if (flag == 0x0002)
524 if (g_PhysVersion >= 7)
526 if (g_PhysVersion <= 11)
527 m_DynamicsData.LoadV11(func);
528 else
529 func(&m_DynamicsData, sizeof(cPhysDynData), 1);
531 if (g_PhysVersion <= 11)
533 for (i=0; i<m_nSubModels; i++)
534 m_pDynamicsData[i].LoadV11(func);
536 else
538 if (g_PhysVersion >= 28)
540 int size;
542 func(&size, sizeof(int), 1);
543 m_pDynamicsData.SetSize(size);
545 for (i=0; i<size; i++)
546 func(&m_pDynamicsData[i], sizeof(cPhysDynData), 1);
548 else
550 if (m_pType[0] == kPMT_OBB)
552 cPhysDynData dummy;
554 m_pDynamicsData.SetSize(0);
555 for (i=0; i<m_nSubModels; i++)
556 func(&dummy, sizeof(cPhysDynData), 1);
558 else
560 m_pDynamicsData.SetSize(m_nSubModels);
561 for (i=0; i<m_nSubModels; i++)
562 func(&m_pDynamicsData[i], sizeof(cPhysDynData), 1);
568 func(&flag, sizeof(int), 1);
569 if (flag == 0x0001)
571 func(&m_ControlData, sizeof(cPhysCtrlData), 1);
572 m_pControlData.SetSize(0);
574 else
575 if (flag == 0x0002)
577 if (g_PhysVersion >= 7)
578 func(&m_ControlData, sizeof(cPhysCtrlData), 1);
579 if (g_PhysVersion >= 28)
581 int size;
583 func(&size, sizeof(int), 1);
584 m_pControlData.SetSize(size);
586 for(i=0; i<size; i++)
587 func(&m_pControlData[i], sizeof(cPhysCtrlData), 1);
589 else
591 if (m_pType[0] == kPMT_OBB)
593 cPhysCtrlData dummy;
595 m_pControlData.SetSize(0);
596 for (i=0; i<m_nSubModels; i++)
597 func(&dummy, sizeof(cPhysCtrlData), 1);
599 else
601 m_pControlData.SetSize(m_nSubModels);
602 for (i=0; i<m_nSubModels; i++)
603 func(&m_pControlData[i], sizeof(cPhysCtrlData), 1);
608 // Set up backpointers
609 m_DynamicsData.SetModel(this);
610 m_DynamicsData.SetSubModId(-1);
611 m_ControlData.SetModel(this);
612 m_ControlData.SetSubModId(-1);
614 for (i=0; i<m_pDynamicsData.Size(); i++)
616 m_pDynamicsData[i].SetModel(this);
617 m_pDynamicsData[i].SetSubModId(i);
620 for (i=0; i<m_pControlData.Size(); i++)
622 m_pControlData[i].SetModel(this);
623 m_pControlData[i].SetSubModId(i);
626 m_AngLimitList.SetSize(0);
628 #ifdef SHIP
629 #define DO_SUBMOD_ROT_FIXUP (TRUE)
630 #else
631 #define DO_SUBMOD_ROT_FIXUP (!config_is_defined("no_submod_rot_fixup"))
632 #endif
634 if (DO_SUBMOD_ROT_FIXUP)
636 // @HACK: if we have rest axes and submodel offsest, make sure we're
637 // rotation controlled
638 BOOL rot_ctrl = FALSE;
639 if (GetRestAxes() != NoAxes)
641 for (i=0; i<NumSubModels(); i++)
643 if (mx_mag2_vec(&GetSubModOffset(i)) > 0.0)
645 rot_ctrl = TRUE;
646 break;
651 if (rot_ctrl)
653 cPhysCtrlData *pControls = GetControls();
654 if (pControls)
655 pControls->ControlRotation(GetRotation());
662 void cPhysModel::UpdateDiskInfo()
664 bDiskCheck = TRUE;
665 // If this is an AI, or a pathable object, then set "disk" bit
666 if (g_pObjPathableProperty->IsRelevant(m_objID) ||
667 g_pAIProperty->IsRelevant(m_objID))
668 m_flags |= kPMF_DiskCheck;
672 ///////////////////////////////////////
674 cPhysModel::~cPhysModel()
676 int i;
678 delete[] m_pType;
679 delete[] m_pForceList;
680 delete[] m_pPosition;
682 m_pDynamicsData.SetSize(0);
683 m_pControlData.SetSize(0);
685 for (i=0; i<m_AngLimitList.Size(); i++)
686 delete m_AngLimitList[i];
687 m_AngLimitList.SetSize(0);
689 for (i=0; i<m_TransLimitList.Size(); i++)
690 delete m_TransLimitList[i];
691 m_TransLimitList.SetSize(0);
694 ///////////////////////////////////////
696 void cPhysModel::Write(PhysReadWrite func) const
698 int i;
699 int flag;
701 // Write General info
702 func((void *)&m_objID, sizeof(ObjID), 1);
703 func((void *)&m_nSubModels, sizeof(int), 1);
704 func((void *)&m_flags, sizeof(unsigned), 1);
706 func((void *)&m_gravity, sizeof(mxs_real), 1);
708 func((void *)m_pType, sizeof(ePhysModelType), m_nSubModels);
710 func((void *)&m_base_friction, sizeof(mxs_real), 1);
712 func((void *)&m_medium, sizeof(int), 1);
714 for (i=0; i<m_nSubModels; i++)
716 func((void *)&m_springInfo[i].tension, sizeof(mxs_real), 1);
717 func((void *)&m_springInfo[i].damping, sizeof(mxs_real), 1);
720 func((void *)&m_pointVsTerrain, sizeof(BOOL), 1);
721 func((void *)&m_passThruDT, sizeof(BOOL), 1);
723 func((void *)&m_nAttachments, sizeof(int), 1);
724 func((void *)&m_isAttached, sizeof(BOOL), 1);
726 func((void *)&m_rotAxes, sizeof(ePhysAxes), 1);
727 func((void *)&m_restAxes, sizeof(ePhysAxes), 1);
729 func((void *)&m_climbingObj, sizeof(ObjID), 1);
730 func((void *)&m_ropeSegment, sizeof(int), 1);
731 func((void *)&m_ropePct, sizeof(mxs_real), 1);
732 func((void *)&m_mantlingState, sizeof(int), 1);
733 func((void *)&m_mantlingTargVec, sizeof(mxs_vector), 1);
735 func((void *)&m_referenceFrameObj, sizeof(ObjID), 1);
737 func((void *)&m_lastSquishTime, sizeof(long), 1);
739 // Write positions for each submodel
740 func(m_pPosition, sizeof(cPhysPos), m_nSubModels);
742 // Write overall model position & cog offset
743 func((void *)&m_pos, sizeof(cPhysPos), 1);
744 func((void *)&m_cog, sizeof(mxs_vector), 1);
746 for (i=0; i<m_nSubModels; i++)
747 func((void *)&m_Offset[i], sizeof(mxs_vector), 1);
749 if (IsPressurePlate())
751 int state = GetPPlateState();
753 func((void *)&state, sizeof(int), 1);
755 if ((state == kPPS_Activating) ||
756 (state == kPPS_Deactivating))
758 mxs_vector trans_limit;
759 int trans_limit_size;
761 GetTransLimits(&trans_limit, &trans_limit_size, 1);
763 func((void *)&trans_limit, sizeof(mxs_vector), 1);
767 // Write dynamics and control info, if applicable
768 if (IsMoveable())
770 if (m_pDynamicsData.Size())
772 int size = m_pDynamicsData.Size();
774 flag = 0x0002;
775 func(&flag, sizeof(int), 1);
776 func((void *)&m_DynamicsData, sizeof(cPhysDynData), 1);
777 func(&size, sizeof(int), 1);
778 for (i=0; i<size; i++)
779 func((void *)&m_pDynamicsData[i], sizeof(cPhysDynData), 1);
781 else
783 flag = 0x0001;
784 func(&flag, sizeof(int), 1);
785 func((void *)&m_DynamicsData, sizeof(cPhysDynData), 1);
788 else
790 flag = 0x0000;
791 func(&flag, sizeof(int), 1);
794 if (IsControllable())
796 if (m_pControlData.Size())
798 int size = m_pControlData.Size();
800 flag = 0x0002;
801 func(&flag, sizeof(int), 1);
802 func((void *)&m_ControlData, sizeof(cPhysCtrlData), 1);
803 func(&size, sizeof(int), 1);
804 for (i=0; i<size; i++)
805 func((void *)&m_pControlData[i], sizeof(cPhysCtrlData), 1);
807 else
809 flag = 0x0001;
810 func(&flag, sizeof(int), 1);
811 func((void *)&m_ControlData, sizeof(cPhysCtrlData), 1);
814 else
816 flag = 0x0000;
817 func(&flag, sizeof(int), 1);
821 ///////////////////////////////////////
823 void cPhysModel::SetLocationVec(tPhysSubModId subModId, const mxs_vector & locVec)
825 Assert_(!_isnan(locVec.x) && !_isnan(locVec.y) && !_isnan(locVec.z));
826 AssertSubModIdInRange(subModId);
827 m_pPosition[subModId].m_position.loc.vec = locVec;
828 m_pPosition[subModId].m_targetposition.loc.vec = locVec;
829 m_pPosition[subModId].m_endposition.loc.vec = locVec;
830 UpdateChangedLocation(&(m_pPosition[subModId].m_position.loc));
833 ///////////////////////////////////////
835 void cPhysModel::SetCurrentLocationVec(tPhysSubModId subModId, const mxs_vector & locVec)
837 Assert_(!_isnan(locVec.x) && !_isnan(locVec.y) && !_isnan(locVec.z));
838 AssertSubModIdInRange(subModId);
839 m_pPosition[subModId].m_position.loc.vec = locVec;
840 UpdateChangedLocation(&(m_pPosition[subModId].m_position.loc));
843 ///////////////////////////////////////
845 void cPhysModel::SetLocationVec(const mxs_vector & locVec, BOOL update)
847 Assert_(!_isnan(locVec.x) && !_isnan(locVec.y) && !_isnan(locVec.z));
848 m_pos.m_position.loc.vec = locVec;
849 m_pos.m_targetposition.loc.vec = locVec;
850 m_pos.m_endposition.loc.vec = locVec;
851 UpdateChangedLocation(&m_pos.m_position.loc);
853 if (update)
854 ObjTranslate(GetObjID(), &locVec);
857 ///////////////////////////////////////
859 void cPhysModel::SetCurrentLocationVec(const mxs_vector & locVec, BOOL update)
861 Assert_(!_isnan(locVec.x) && !_isnan(locVec.y) && !_isnan(locVec.z));
862 m_pos.m_position.loc.vec = locVec;
863 UpdateChangedLocation(&m_pos.m_position.loc);
865 if (update)
866 ObjTranslate(GetObjID(), &locVec);
869 ///////////////////////////////////////
871 void cPhysModel::SetRotation(const mxs_angvec & rot, BOOL update)
873 m_pos.m_position.fac = m_pos.m_targetposition.fac = m_pos.m_endposition.fac = rot;
875 if (update)
876 ObjRotate(GetObjID(), &rot);
879 ///////////////////////////////////////
881 const mxs_vector cPhysModel::GetCOG() const
883 mxs_vector cog;
884 mxs_matrix orien;
886 mx_ang2mat(&orien, &m_pos.m_position.fac);
887 mx_mat_mul_vec(&cog, &orien, &m_cog);
888 mx_addeq_vec(&cog, &m_pos.m_position.loc.vec);
890 return cog;
893 ///////////////////////////////////////
895 static AttachConstrainLock = FALSE;
897 void cPhysModel::AddConstraint(ObjID cause, const mxs_vector &dir, mxs_real mag)
899 if (mag == 0)
900 return;
902 for (int i=0; i<m_VelConstraintList.Size(); i++)
904 if (EqualVectors(m_VelConstraintList[i].dir, dir))
905 return;
908 tVelocityConstraint vel_const;
910 vel_const.cause = cause;
911 vel_const.dir = dir;
912 vel_const.mag = mag;
914 LGALLOC_PUSH_CREDIT();
915 m_VelConstraintList.Append(vel_const);
916 LGALLOC_POP_CREDIT();
918 // And constrain any attachments
919 if (AttachConstrainLock == TRUE)
920 return;
922 if (IsAttached())
924 ILinkQuery *query = g_pPhysAttachRelation->Query(ObjID(), LINKOBJ_WILDCARD);
926 if (!query->Done())
928 sLink link;
929 query->Link(&link);
931 cPhysModel *pModelDest = g_PhysModels.GetActive(link.dest);
932 if (pModelDest != NULL)
934 AttachConstrainLock = TRUE;
935 pModelDest->AddConstraint(cause, dir, mag);
936 AttachConstrainLock = FALSE;
939 SafeRelease(query);
943 ////////////////////////////////////////
945 void cPhysModel::AddConstraint(ObjID cause, const mxs_vector &norm)
947 for (int i=0; i<m_ConstraintList.Size(); i++)
949 if (EqualVectors(m_ConstraintList[i].dir, norm))
950 return;
953 tConstraint constraint;
955 constraint.cause = cause;
956 constraint.dir = norm;
958 LGALLOC_PUSH_CREDIT();
959 m_ConstraintList.Append(constraint);
960 LGALLOC_POP_CREDIT();
962 // And constrain any attachments
963 if (AttachConstrainLock == TRUE)
964 return;
966 if (IsAttached())
968 ILinkQuery *query = g_pPhysAttachRelation->Query(ObjID(), LINKOBJ_WILDCARD);
970 if (!query->Done())
972 sLink link;
973 query->Link(&link);
975 cPhysModel *pModelDest = g_PhysModels.GetActive(link.dest);
976 if (pModelDest != NULL)
978 AttachConstrainLock = TRUE;
979 pModelDest->AddConstraint(cause, norm);
980 AttachConstrainLock = FALSE;
983 SafeRelease(query);
987 ///////////////////////////////////////
989 void cPhysModel::AddConstraint(ObjID cause, tPhysSubModId i, const mxs_vector &norm)
991 BOOL in_model = FALSE;
992 BOOL in_submodel = FALSE;
993 int j;
995 for (j=0; j<m_ConstraintList.Size(); j++)
997 if (EqualVectors(m_ConstraintList[j].dir, norm))
999 in_model = TRUE;
1000 break;
1004 for (j=0; j<m_SubModConstraintList[i].Size(); j++)
1006 if (EqualVectors(m_SubModConstraintList[i][j].dir, norm))
1008 in_submodel = TRUE;
1009 break;
1013 if (in_model && in_submodel)
1014 return;
1016 tConstraint constraint;
1018 constraint.cause = cause;
1019 constraint.dir = norm;
1021 LGALLOC_PUSH_CREDIT();
1022 m_ConstraintList.Append(constraint);
1023 m_SubModConstraintList[i].Append(constraint);
1024 LGALLOC_POP_CREDIT();
1026 // And constrain any attachments
1027 if (AttachConstrainLock == TRUE)
1028 return;
1030 if (IsAttached())
1032 ILinkQuery *query = g_pPhysAttachRelation->Query(ObjID(), LINKOBJ_WILDCARD);
1034 if (!query->Done())
1036 sLink link;
1037 query->Link(&link);
1039 cPhysModel *pModelDest = g_PhysModels.GetActive(link.dest);
1040 if (pModelDest != NULL)
1042 AttachConstrainLock = TRUE;
1043 pModelDest->AddConstraint(cause, norm);
1044 AttachConstrainLock = FALSE;
1047 SafeRelease(query);
1051 ///////////////////////////////////////
1053 void cPhysModel::ApplyConstraints(mxs_vector *vec)
1055 mxs_vector mid;
1056 mxs_vector start;
1058 Assert_(gInsideMT);
1060 if (IsAttached())
1061 return;
1063 mx_copy_vec(&start, vec);
1065 for (int i=0; i<m_VelConstraintList.Size(); i++)
1067 mxs_real dp;
1068 mxs_vector dir;
1069 mxs_vector constraint;
1071 mx_copy_vec(&dir, &m_VelConstraintList[i].dir);
1073 mx_scale_vec(&constraint, &dir, m_VelConstraintList[i].mag);
1075 dp = mx_dot_vec(vec, &m_VelConstraintList[i].dir);
1077 if (dp < m_VelConstraintList[i].mag)
1079 PhysRemNormComp(vec, dir);
1080 mx_scaleeq_vec(&dir, -1.0);
1081 PhysRemNormComp(vec, dir);
1082 mx_addeq_vec(vec, &constraint);
1086 mx_copy_vec(&mid, vec);
1088 if (m_ConstraintList.Size() > 0)
1089 PhysConstrain(vec, m_ConstraintList, m_ConstraintList.Size());
1091 if (IsPlayer())
1093 for (i=0; i<m_VelConstraintList.Size(); i++)
1095 if (m_VelConstraintList[i].mag > 0)
1097 mxs_vector constraint;
1098 mx_scale_vec(&constraint, &m_VelConstraintList[i].dir, m_VelConstraintList[i].mag);
1100 if (mx_dot_vec(vec, &constraint) <= 0)
1102 cPhysModel *pSquishModel = g_PhysModels.Get(m_VelConstraintList[i].cause);
1104 mxs_real mass = pSquishModel->GetDynamics()->GetMass();
1105 mxs_real vel = mx_mag_vec(&pSquishModel->GetDynamics()->GetVelocity());
1107 Squish((mass * vel) / 100);
1108 pSquishModel->SetSquishingState(TRUE);
1110 // Don't move, but retain momentum
1111 pSquishModel->SetTargetLocation(pSquishModel->GetLocationVec());
1112 pSquishModel->SetEndLocationVec(pSquishModel->GetLocationVec());
1113 SetEndLocationVec(GetLocationVec());
1120 ///////////////////////////////////////
1122 void cPhysModel::ApplyConstraints(tPhysSubModId i, mxs_vector *vec)
1124 if (m_SubModConstraintList[i].Size() > 0)
1125 PhysConstrain(vec, m_SubModConstraintList[i], m_SubModConstraintList[i].Size());
1128 ///////////////////////////////////////
1130 void cPhysModel::GetConstraints(mxs_vector vec_list[], int *num_vecs)
1132 int i;
1134 for (i=0; (i<m_ConstraintList.Size()) && (i<*num_vecs); i++)
1135 mx_copy_vec(&vec_list[i], &m_ConstraintList[i].dir);
1137 *num_vecs = i;
1140 ///////////////////////////////////////
1142 BOOL cPhysModel::ApplyForces(tPhysSubModId subModId, sPhysForce *flist, int nforces, mxs_real dt,
1143 mxs_vector &start_loc, mxs_vector *end_loc, mxs_vector *force,
1144 mxs_real *ctime, BOOL terrain_check, BOOL object_check)
1146 mx_copy_vec(end_loc, (mxs_vector *)&GetEndLocationVec(subModId));
1147 mx_zero_vec(force);
1148 *ctime = 0.0;
1149 return FALSE;
1152 ///////////////////////////////////////
1154 BOOL cPhysModel::IsControlled()
1156 if (!IsControllable())
1157 return FALSE;
1159 if (m_ControlData.GetType() != kPCT_NoControl)
1160 return TRUE;
1162 for (int i=0; i<m_pControlData.Size(); i++)
1164 if (m_pControlData[i].GetType() != kPCT_NoControl)
1165 return TRUE;
1168 return FALSE;
1171 ///////////////////////////////////////
1173 BOOL cPhysModel::IsVelocityControlled()
1175 if (!IsControllable())
1176 return FALSE;
1178 if (m_ControlData.GetType() & kPCT_VelControl)
1179 return TRUE;
1181 for (int i=0; i<m_pControlData.Size(); i++)
1183 if (m_pControlData[i].GetType() & kPCT_VelControl)
1184 return TRUE;
1187 return FALSE;
1190 ///////////////////////////////////////
1192 BOOL cPhysModel::IsAxisVelocityControlled()
1194 if (!IsControllable())
1195 return FALSE;
1197 if ((m_ControlData.GetType() & kPCT_VelControl) && m_ControlData.AxisControlled())
1198 return TRUE;
1200 for (int i=0; i<m_pControlData.Size(); i++)
1202 if ((m_pControlData[i].GetType() & kPCT_VelControl) && m_pControlData[i].AxisControlled())
1203 return TRUE;
1206 return FALSE;
1209 ///////////////////////////////////////
1211 BOOL cPhysModel::IsRotationalVelocityControlled()
1213 if (!IsControllable())
1214 return FALSE;
1216 if (m_ControlData.GetType() & kPCT_RotVelControl)
1217 return TRUE;
1219 if (!IsPlayer())
1221 for (int i=0; i<m_pControlData.Size(); i++)
1223 if (m_pControlData[i].GetType() & kPCT_RotVelControl)
1224 return TRUE;
1228 return FALSE;
1231 ///////////////////////////////////////
1233 BOOL cPhysModel::IsLocationControlled()
1235 if (!IsControllable())
1236 return FALSE;
1238 if (m_ControlData.GetType() & kPCT_LocControl)
1239 return TRUE;
1241 for (int i=0; i<m_pControlData.Size(); i++)
1243 if (m_pControlData[i].GetType() & kPCT_LocControl)
1244 return TRUE;
1247 return FALSE;
1250 ///////////////////////////////////////
1252 BOOL cPhysModel::IsRotationControlled()
1254 if (!IsControllable())
1255 return FALSE;
1257 if (m_ControlData.GetType() & kPCT_RotControl)
1258 return TRUE;
1260 for (int i=0; i<m_pControlData.Size(); i++)
1262 if (m_pControlData[i].GetType() & kPCT_RotControl)
1263 return TRUE;
1266 return FALSE;
1269 ///////////////////////////////////////
1271 void cPhysModel::SetSleep(BOOL state)
1273 if (IsCreature() && !IsRope() && CreatureSelfPropelled(GetObjID()) && (state == FALSE))
1274 return;
1276 if (IsWeapon(0) && (state == FALSE))
1277 return;
1279 #ifdef NEW_NETWORK_ENABLED
1280 // Tell the other players that this object is or isn't moving now
1281 // We put this call here, because the networking code doesn't want to
1282 // ignore the special cases below...
1283 if (state != IsSleeping())
1285 AutoAppIPtr(NetManager);
1286 if (pNetManager->Networking()) {
1287 AutoAppIPtr(ObjectNetworking);
1288 // If the object isn't hosted here, then we aren't in charge of
1289 // telling the rest of the world about its state changes. Also,
1290 // AI's base their network sleepiness on their Efficiency mode.
1291 if (pObjectNetworking->ObjHostedHere(GetObjID())
1292 && !ObjIsAI(GetObjID()))
1294 AutoAppIPtr(NetManager);
1295 PhysNetSetSleep(GetObjID(), state);
1299 #endif
1301 if (IsPressurePlate() && (GetPPlateState() != kPPS_Inactive) && (state == TRUE))
1302 return;
1304 if (ObjectPassThru() && (state == TRUE))
1305 return;
1307 if (state != IsSleeping())
1309 SetFlagState(kPMF_Sleeping, state);
1311 if (state)
1313 // We don't want to make non physical if we're in contact with another
1314 // object, because it could move after we've become non-physical and
1315 // then we'd just be floating, which isn't so good.
1316 if (RemovesOnSleep() && !InObjectContact())
1318 PhysDeregisterModel(GetObjID());
1319 return;
1322 // Blow away firer link if we had one
1323 SetProjectileFirer(GetObjID(), OBJ_NULL);
1325 g_PhysModels.StopMoving(this);
1326 PhysMessageFellAsleep(GetObjID());
1328 SetCollisionChecked(FALSE);
1329 SetSquishingState(FALSE);
1331 m_DynamicsData.SetFrozen(FALSE);
1332 m_DynamicsData.SetCurrentTime(0);
1334 m_DynamicsData.ZeroCollisionCount();
1335 m_DynamicsData.ZeroAcceleration();
1337 for (int i=0; i<m_pDynamicsData.Size(); i++)
1339 m_pDynamicsData[i].ZeroCollisionCount();
1340 m_pDynamicsData[i].ZeroAcceleration();
1343 else
1345 WakeUpContacts(this);
1347 SetRest(FALSE);
1348 g_PhysModels.StartMoving(this);
1349 PhysMessageWokeUp(GetObjID());
1354 ///////////////////////////////////////
1356 BOOL cPhysModel::IsTranslating() const
1358 BOOL moving = FALSE;
1360 if (IsMoveable())
1362 if (!IsZeroVector(GetDynamics()->GetVelocity()))
1363 moving = TRUE;
1365 if (!IsZeroVector(GetDynamics()->GetRotationalVelocity()) &&
1366 !IsZeroVector(m_cog))
1367 moving = TRUE;
1369 for (int i=0; i<NumSubModels(); i++)
1371 if (!IsZeroVector(GetDynamics(i)->GetVelocity()))
1372 moving = TRUE;
1374 if (!IsZeroVector(GetDynamics(i)->GetRotationalVelocity()) &&
1375 !IsZeroVector(m_cog))
1376 moving = TRUE;
1380 return moving;
1383 ///////////////////////////////////////
1385 void cPhysModel::CreateTerrainContact(tPhysSubModId subModId, const cFacePoly *poly, ObjID objID)
1387 cFaceContactList *pFaceContactList;
1388 cFaceContact *pFaceContact;
1390 if (!GetFaceContacts(subModId, &pFaceContactList) ||
1391 !pFaceContactList->Find(poly, &pFaceContact))
1393 m_nFaceContacts++;
1394 g_PhysContactLinks.CreateTerrainLink(m_objID, subModId, poly, objID);
1396 PhysMessageContactCreate(this, subModId, kContactFace, OBJ_NULL, -1);
1400 void cPhysModel::CreateTerrainContact(tPhysSubModId subModId, const mxs_vector &start, const mxs_vector &end)
1402 cEdgeContactList *pEdgeContactList;
1403 cEdgeContact *pEdgeContact;
1405 if (!GetEdgeContacts(subModId, &pEdgeContactList) ||
1406 !pEdgeContactList->Find(start, end, &pEdgeContact))
1408 m_nEdgeContacts++;
1409 g_PhysContactLinks.CreateTerrainLink(m_objID, subModId, start, end);
1411 PhysMessageContactCreate(this, subModId, kContactEdge, OBJ_NULL, -1);
1415 void cPhysModel::CreateTerrainContact(tPhysSubModId subModId, const mxs_vector &point)
1417 cVertexContactList *pVertexContactList;
1418 cVertexContact *pVertexContact;
1420 if (!GetVertexContacts(subModId, &pVertexContactList) ||
1421 !pVertexContactList->Find(point, &pVertexContact))
1423 m_nVertexContacts++;
1424 g_PhysContactLinks.CreateTerrainLink(m_objID, subModId, point);
1426 PhysMessageContactCreate(this, subModId, kContactVertex, OBJ_NULL, -1);
1430 ///////////////////////////////////////
1432 void cPhysModel::DestroyTerrainContact(tPhysSubModId subModId, const cFacePoly *poly)
1434 m_nFaceContacts--;
1435 g_PhysContactLinks.DestroyTerrainLink(m_objID, subModId, poly);
1437 PhysMessageContactDestroy(this, subModId, kContactFace, OBJ_NULL, -1);
1440 void cPhysModel::DestroyTerrainContact(tPhysSubModId subModId, const mxs_vector &start, const mxs_vector &end)
1442 m_nEdgeContacts--;
1443 g_PhysContactLinks.DestroyTerrainLink(m_objID, subModId, start, end);
1445 PhysMessageContactDestroy(this, subModId, kContactEdge, OBJ_NULL, -1);
1448 void cPhysModel::DestroyTerrainContact(tPhysSubModId subModId, const mxs_vector &point)
1450 m_nVertexContacts--;
1451 g_PhysContactLinks.DestroyTerrainLink(m_objID, subModId, point);
1453 PhysMessageContactDestroy(this, subModId, kContactVertex, OBJ_NULL, -1);
1456 ///////////////////////////////////////
1458 void cPhysModel::DestroyAllTerrainContacts(tPhysSubModId subModId)
1460 cFaceContactList *pFaceContactList;
1461 cEdgeContactList *pEdgeContactList;
1462 cVertexContactList *pVertexContactList;
1464 if (GetFaceContacts(subModId, &pFaceContactList))
1466 cFaceContact *pFaceContact = pFaceContactList->GetFirst();
1468 while (pFaceContact != NULL)
1470 DestroyTerrainContact(subModId, pFaceContact->GetPoly());
1472 if (!GetFaceContacts(subModId, &pFaceContactList))
1473 break;
1474 pFaceContact = pFaceContactList->GetFirst();
1478 if (GetEdgeContacts(subModId, &pEdgeContactList))
1480 cEdgeContact *pEdgeContact = pEdgeContactList->GetFirst();
1482 while (pEdgeContact != NULL)
1484 DestroyTerrainContact(subModId, pEdgeContact->GetStart(), pEdgeContact->GetEnd());
1486 if (!GetEdgeContacts(subModId, &pEdgeContactList))
1487 break;
1488 pEdgeContact = pEdgeContactList->GetFirst();
1492 if (GetVertexContacts(subModId, &pVertexContactList))
1494 cVertexContact *pVertexContact = pVertexContactList->GetFirst();
1496 while (pVertexContact != NULL)
1498 DestroyTerrainContact(subModId, pVertexContact->GetPoint());
1500 if (!GetVertexContacts(subModId, &pVertexContactList))
1501 break;
1502 pVertexContact = pVertexContactList->GetFirst();
1506 ///////////////////////////////////////
1508 BOOL cPhysModel::GetFaceContacts(tPhysSubModId subModId, cFaceContactList **ppFaceContactList) const
1510 if (m_nFaceContacts > 0)
1511 return g_PhysContactLinks.GetTerrainLinks(m_objID, subModId, ppFaceContactList);
1513 return FALSE;
1516 BOOL cPhysModel::GetEdgeContacts(tPhysSubModId subModId, cEdgeContactList **ppEdgeContactList) const
1518 if (m_nEdgeContacts > 0)
1519 return g_PhysContactLinks.GetTerrainLinks(m_objID, subModId, ppEdgeContactList);
1521 return FALSE;
1524 BOOL cPhysModel::GetVertexContacts(tPhysSubModId subModId, cVertexContactList **ppVertexContactList) const
1526 if (m_nVertexContacts > 0)
1527 return g_PhysContactLinks.GetTerrainLinks(m_objID, subModId, ppVertexContactList);
1529 return FALSE;
1532 ////////////////////////////////////////////////////////////////////////////////
1534 void cPhysModel::UpdateEndLocation(mxs_real dt)
1536 if (IsSquishing())
1538 mx_copy_vec(&m_pos.m_endposition.loc.vec, &m_pos.m_position.loc.vec);
1539 return;
1542 // Update location
1543 mx_copy_vec(&m_pos.m_endposition.loc.vec, &m_pos.m_targetposition.loc.vec);
1545 // Update rotation
1546 mx_mk_angvec(&m_pos.m_endposition.fac, m_pos.m_targetposition.fac.tx,
1547 m_pos.m_targetposition.fac.ty,
1548 m_pos.m_targetposition.fac.tz);
1550 if (!EqualVectors(m_pos.m_position.loc.vec, m_pos.m_endposition.loc.vec) ||
1551 (m_pos.m_position.fac.tx != m_pos.m_endposition.fac.tx) ||
1552 (m_pos.m_position.fac.ty != m_pos.m_endposition.fac.ty) ||
1553 (m_pos.m_position.fac.tz != m_pos.m_endposition.fac.tz))
1555 SetUpdateRefs(TRUE);
1558 // Update hints
1559 m_pos.m_endposition.loc.cell = CELL_INVALID;
1560 m_pos.m_endposition.loc.hint = m_pos.m_position.loc.hint;
1563 ///////////////////////////////////////
1565 void cPhysModel::UpdateEndLocation(tPhysSubModId i, mxs_real dt)
1567 mxs_vector movement_offset;
1568 mxs_vector velocity;
1569 mxs_vector offset;
1571 if (IsPlayer())
1572 PlayerMotionGetOffset(i, &offset);
1573 else
1574 mx_zero_vec(&offset);
1576 if ((GetSpringTension(i) > 0 || !IsZeroVector(offset)) && (i < m_pDynamicsData.Size()))
1578 // Find end location based on velocity
1579 mx_copy_vec(&velocity, &m_pDynamicsData[i].GetVelocity());
1580 mx_scale_vec(&movement_offset, &velocity, dt);
1582 else
1583 mx_sub_vec(&movement_offset, &m_pPosition[i].m_targetposition.loc.vec, &m_pPosition[i].m_position.loc.vec);
1585 // Update location
1586 mx_add_vec(&m_pPosition[i].m_endposition.loc.vec, &m_pPosition[i].m_position.loc.vec, &movement_offset);
1588 // Update rotation
1589 mx_mk_angvec(&m_pPosition[i].m_endposition.fac, m_pPosition[i].m_targetposition.fac.tx,
1590 m_pPosition[i].m_targetposition.fac.ty,
1591 m_pPosition[i].m_targetposition.fac.tz);
1592 // Update hints
1593 m_pPosition[i].m_endposition.loc.cell = CELL_INVALID;
1594 m_pPosition[i].m_endposition.loc.hint = m_pPosition[i].m_position.loc.hint;
1596 if (!EqualVectors(m_pPosition[i].m_endposition.loc.vec, m_pPosition[i].m_position.loc.vec))// && IsRope())
1598 SetUpdateRefs(TRUE);
1602 ///////////////////////////////////////
1604 const Location & cPhysModel::GetEndLocation(tPhysSubModId subModId) const
1606 if (subModId == -1)
1607 return m_pos.m_endposition.loc;
1608 else
1609 return m_pPosition[subModId].m_endposition.loc;
1612 ///////////////////////////////////////
1614 const mxs_vector & cPhysModel::GetEndLocationVec(tPhysSubModId subModId) const
1616 if (subModId == -1)
1617 return m_pos.m_endposition.loc.vec;
1618 else
1619 return m_pPosition[subModId].m_endposition.loc.vec;
1622 ///////////////////////////////////////
1624 void cPhysModel::SetEndLocationVec(tPhysSubModId subModId, const mxs_vector &end_loc)
1626 if (subModId == -1)
1628 mx_copy_vec((mxs_vector *) &m_pos.m_endposition.loc.vec, &end_loc);
1629 m_pos.m_endposition.loc.hint = m_pos.m_position.loc.hint;
1630 m_pos.m_endposition.loc.cell = -1;
1632 else
1633 mx_copy_vec((mxs_vector *) &m_pPosition[subModId].m_endposition.loc.vec, &end_loc);
1636 ///////////////////////////////////////
1638 const mxs_angvec & cPhysModel::GetEndRotationVec(tPhysSubModId subModId) const
1640 if (subModId == -1)
1641 return m_pos.m_endposition.fac;
1642 else
1643 return m_pPosition[subModId].m_endposition.fac;
1646 ///////////////////////////////////////
1648 void cPhysModel::SetEndRotationVec(tPhysSubModId subModId, const mxs_angvec &end_ang)
1650 if (subModId == -1)
1651 m_pos.m_endposition.fac = end_ang;
1652 else
1653 m_pPosition[subModId].m_endposition.fac = end_ang;
1656 ////////////////////////////////////////////////////////////////////////////////
1658 #define sq(x) ((x)*(x))
1660 void cPhysModel::PreventPlayerFall()
1662 Assert_(IsPlayer());
1664 cFaceContactList *pFaceContactList;
1666 // get the "correct" speed for constraining our motion
1667 // get player mode
1668 ePlayerMode cur_mode=GetPlayerMode();
1669 float speed=GetTransSpeedScale()*SLOW_MOVE_SPEED;
1670 float special_muls[2]={0.90,0.60}; // was 0.95
1671 float height_check=9.0; // was 8.0
1673 #ifndef SHIP
1674 config_get_float("player_fall_walk",&special_muls[0]);
1675 config_get_float("player_fall_crouch",&special_muls[1]);
1676 config_get_float("player_fall_height",&height_check);
1677 #endif
1678 if (cur_mode==kPM_Crouch)
1679 speed*=special_muls[1];
1680 else
1681 speed*=special_muls[0];
1683 if (GetFaceContacts(PLAYER_FOOT, &pFaceContactList) &&
1684 (mx_mag2_vec(&GetVelocity()) < sq(speed)))
1686 Location start, end, hit;
1687 Location targ_start, targ_end;
1689 // find our forward location
1690 MakeHintedLocationFromVector(&start, &GetLocationVec(PLAYER_FOOT),
1691 &GetLocation(PLAYER_FOOT));
1692 MakeHintedLocationFromVector(&targ_start, &GetTargetLocation(PLAYER_FOOT),
1693 &GetLocation(PLAYER_FOOT));
1695 MakeLocationFromVector(&end, &start.vec);
1696 end.vec.z -= 0.1;
1698 MakeLocationFromVector(&targ_end, &targ_start.vec);
1699 targ_end.vec.z -= height_check;
1701 // would like to hit water, and stop there, i guess?
1703 // Raycast down to see what kind of fall we're talking about
1704 if (PortalRaycast(&targ_start, &targ_end, &hit, 0))
1706 #ifndef SHIP
1707 if (config_is_defined("player_fall_loud"))
1708 mprintf("Saved Me\n");
1709 #endif
1711 m_pos.m_targetposition.loc.vec = m_pos.m_position.loc.vec;
1712 m_pos.m_endposition.loc.vec = m_pos.m_position.loc.vec;
1714 for (int i=0; i<NumSubModels(); i++)
1716 m_pPosition[i].m_targetposition.loc.vec = m_pPosition[i].m_position.loc.vec;
1717 m_pPosition[i].m_endposition.loc.vec = m_pPosition[i].m_position.loc.vec;
1723 DECLARE_TIMER(UM_UpdateTarget, Average);
1724 DECLARE_TIMER(UM_UpdateRope, Average);
1725 DECLARE_TIMER(UM_UpdateEnd, Average);
1726 DECLARE_TIMER(UM_UpdateTargetSub, Average);
1727 DECLARE_TIMER(UM_UpdateSpringSub, Average);
1728 DECLARE_TIMER(UM_UpdateEndSub, Average);
1729 DECLARE_TIMER(UM_PreventFall, Average);
1730 DECLARE_TIMER(UM_UpdateRefs, Average);
1732 void cPhysModel::UpdateModel(mxs_real dt)
1735 TIMER_Start(UM_UpdateTarget);
1736 UpdateTargetLocation(dt);
1737 TIMER_MarkStop(UM_UpdateTarget);
1739 TIMER_Start(UM_UpdateRope);
1740 UpdateRopeClimbing(dt);
1741 TIMER_MarkStop(UM_UpdateRope);
1743 TIMER_Start(UM_UpdateEnd);
1744 UpdateEndLocation(dt);
1745 TIMER_MarkStop(UM_UpdateEnd);
1747 for (int i=0; i<NumSubModels(); i++)
1749 TIMER_Start(UM_UpdateTargetSub);
1750 UpdateTargetLocation(i, dt);
1751 TIMER_MarkStop(UM_UpdateTargetSub);
1753 TIMER_Start(UM_UpdateSpringSub);
1754 UpdateSpringMechanics(i, dt);
1755 TIMER_MarkStop(UM_UpdateSpringSub);
1757 TIMER_Start(UM_UpdateEndSub);
1758 UpdateEndLocation(i, dt);
1759 TIMER_MarkStop(UM_UpdateEndSub);
1762 TIMER_Start(UM_UpdateRefs);
1763 if (UpdateRefsPending())
1765 SetUpdateRefs(FALSE);
1766 PhysUpdateRefs(this);
1768 TIMER_MarkStop(UM_UpdateRefs);
1770 TIMER_Start(UM_PreventFall);
1771 // If we're trying to prevent the player from falling, do it again
1772 if (IsPlayer())
1773 PreventPlayerFall();
1774 TIMER_MarkStop(UM_PreventFall);
1776 if (NumAttachments() > 0)
1778 cAutoLinkQuery query(g_pPhysAttachRelation, LINKOBJ_WILDCARD, GetObjID());
1780 for (;!query->Done(); query->Next())
1782 cPhysModel *pAttachModel = g_PhysModels.Get(query.GetSource());
1783 pAttachModel->UpdateModel(dt);
1789 ///////////////////////////////////////
1791 void cPhysModel::SetTargetLocation(const mxs_vector &loc)
1793 int i;
1795 mx_copy_vec(&m_pos.m_targetposition.loc.vec, &loc);
1797 UpdateEndLocation(.1);
1799 for (i=0; i<NumSubModels(); i++)
1801 UpdateTargetLocation(i, .1);
1802 UpdateSpringMechanics(i, .1);
1803 UpdateEndLocation(i, .1);
1807 ///////////////////////////////////////
1809 void cPhysModel::UpdateTargetLocation(mxs_real dt)
1811 cPhysDynData *pDyn = GetDynamics();
1812 mxs_matrix facing, rotation, end_facing;
1813 mxs_vector velocity, rot_vec;
1814 mxs_real rot_mag;
1816 if (IsAttached())
1818 LinkID linkID = g_pPhysAttachRelation->GetSingleLink(GetObjID(), LINKOBJ_WILDCARD);
1819 sLink link;
1821 if (linkID)
1823 g_pPhysAttachRelation->Get(linkID, &link);
1824 sPhysAttachData *pAttachData = (sPhysAttachData *)g_pPhysAttachRelation->GetData(linkID);
1826 cPhysModel *pAttachModel = g_PhysModels.GetActive(link.dest);
1828 if (pAttachModel)
1830 mx_add_vec(&m_pos.m_targetposition.loc.vec, &pAttachModel->GetTargetLocation(), &pAttachData->offset);
1832 return;
1837 // Setup
1838 mx_copy_vec(&velocity, &pDyn->GetVelocity());
1839 mx_copy_vec(&rot_vec, &pDyn->GetRotationalVelocity());
1841 mx_ang2mat(&facing, &m_pos.m_position.fac);
1843 if (mx_mag2_vec(&rot_vec) > 0.000001)
1845 rot_mag = mx_normeq_vec(&rot_vec) * dt;
1847 mx_mk_rot_vec_mat(&rotation, &rot_vec, mx_rad2ang(rot_mag));
1848 mx_mul_mat(&end_facing, &rotation, &facing);
1850 mx_mat2ang(&m_pos.m_targetposition.fac, &end_facing);
1852 #if 0
1853 if (IsPlayer())
1855 mprintf("ang = %d\n", mx_rad2ang(rot_mag));
1856 mprintf("rot_vec = %g %g %g\n", rot_vec.x, rot_vec.y, rot_vec.z);
1857 mprintf("facing = %d %d %d\n", m_pos.m_position.fac.tx, m_pos.m_position.fac.ty, m_pos.m_position.fac.tz);
1858 mprintf("endfacing = %d %d %d\n", m_pos.m_targetposition.fac.tx, m_pos.m_targetposition.fac.ty, m_pos.m_targetposition.fac.tz);
1860 #endif
1863 #if 0
1864 // Apply constraints
1865 ApplyConstraints(&velocity);
1867 pDyn->SetVelocity(velocity);
1868 #endif
1870 // Update translation and rotation
1871 mx_scale_add_vec((mxs_vector *) &m_pos.m_targetposition.loc.vec,
1872 (mxs_vector *) &m_pos.m_position.loc.vec,
1873 &velocity, dt);
1875 // Adjust location for rotation not around center point
1876 if (!IsPlayer() && !IsZeroVector(m_cog) && (rot_mag > 0.0001))
1878 mxs_matrix rotation;
1879 mxs_matrix obj_for;
1880 mxs_matrix both_rot;
1881 mxs_angvec rot_ang;
1882 mxs_vector rotvel_offset;
1883 mxs_vector cog_offset;
1884 mxs_vector rot_offset;
1885 mxs_vector add_offset;
1887 // How much rotated this frame
1888 mx_scale_vec(&rotvel_offset, &rot_vec, rot_mag);
1889 mx_mk_angvec(&rot_ang, mx_rad2ang(rotvel_offset.x),
1890 mx_rad2ang(rotvel_offset.y),
1891 mx_rad2ang(rotvel_offset.z));
1894 // Set up matrices
1895 mx_ang2mat(&rotation, &rot_ang);
1896 mx_ang2mat(&obj_for, &m_pos.m_position.fac);
1898 mx_mul_mat(&both_rot, &rotation, &obj_for);
1900 // Find starting offset this frame
1901 mx_mat_mul_vec(&cog_offset, &obj_for, &m_cog);
1903 // Find ending offset this frame
1904 mx_mat_mul_vec(&rot_offset, &both_rot, &m_cog);
1906 // Find the delta
1907 mx_sub_vec(&add_offset, &rot_offset, &cog_offset);
1909 mx_addeq_vec(&m_pos.m_targetposition.loc.vec, &add_offset);
1912 if (IsAttached())
1914 LinkID linkID = g_pPhysAttachRelation->GetSingleLink(GetObjID(), LINKOBJ_WILDCARD);
1915 sLink link;
1917 if (linkID)
1919 g_pPhysAttachRelation->Get(linkID, &link);
1920 sPhysAttachData *pAttachData = (sPhysAttachData *)g_pPhysAttachRelation->GetData(linkID);
1922 cPhysModel *pAttachModel = g_PhysModels.GetActive(link.dest);
1924 if (pAttachModel)
1926 mxs_vector targ;
1927 mx_add_vec(&targ, &pAttachModel->GetTargetLocation(), &pAttachData->offset);
1929 mx_subeq_vec(&targ, &m_pos.m_targetposition.loc.vec);
1931 mprintf("targ: %g %g %g\n", targ.x, targ.y, targ.z);
1933 Assert_(fabs(targ.x) < 5.0);
1941 ////////////////////////////////////////
1943 void cPhysModel::ComputeRopeSegPct()
1945 cPhysModel *pRopeModel;
1947 int node_1 = GetRopeSegment();
1948 int node_2 = node_1 - 1;
1950 pRopeModel = g_PhysModels.Get(GetClimbingObj());
1952 if (pRopeModel == NULL)
1954 Warning(("cPhysModel::ComputeRopeSegPct: no physics model for obj %d?\n", GetClimbingObj()));
1955 return;
1958 mxs_vector segment;
1959 mxs_vector end_to_obj;
1961 // @TODO: make sure the rope has been updated
1963 mx_sub_vec(&segment, &pRopeModel->GetLocationVec(node_2), &pRopeModel->GetLocationVec(node_1));
1965 // went past node_1?
1966 mx_sub_vec(&end_to_obj, &GetLocationVec(), &pRopeModel->GetLocationVec(node_1));
1967 if (mx_dot_vec(&end_to_obj, &segment) < 0)
1969 if (node_1 < (pRopeModel->NumSubModels() - 1))
1971 SetRopeSegment(node_1 + 1);
1972 SetRopeSegmentPct(1.0);
1974 #ifndef SHIP
1975 if (config_is_defined("RopeSpew"))
1976 mprintf(" Obj %d moved from node %d to %d\n", GetObjID(), node_1, node_1 + 1);
1977 #endif
1979 else
1980 BreakClimb(GetObjID(), FALSE, FALSE);
1981 return;
1984 // went past node_2?
1985 mx_sub_vec(&end_to_obj, &GetLocationVec(), &pRopeModel->GetLocationVec(node_2));
1986 if (mx_dot_vec(&end_to_obj, &segment) > 0)
1988 if (node_2 > 0)
1990 SetRopeSegment(node_2);
1991 SetRopeSegmentPct(0.0);
1993 #ifndef SHIP
1994 if (config_is_defined("RopeSpew"))
1995 mprintf(" Obj %d moved from node %d to %d\n", GetObjID(), node_1, node_2);
1996 #endif
1998 return;
2001 // within the segment
2002 mxs_vector on_segment;
2003 mxs_vector seg_norm;
2004 mxs_vector to_obj;
2005 mxs_real seg_len;
2007 seg_len = mx_norm_vec(&seg_norm, &segment);
2009 mx_sub_vec(&to_obj, &GetLocationVec(), &pRopeModel->GetLocationVec(node_1));
2010 mx_scale_vec(&on_segment, &seg_norm, mx_dot_vec(&seg_norm, &to_obj));
2012 SetRopeSegmentPct(mx_mag_vec(&on_segment) / seg_len);
2014 #ifndef SHIP
2015 if (config_is_defined("RopeSpew"))
2016 mprintf(" Obj %d is %g along segment %d\n", GetObjID(), GetRopeSegmentPct(), node_1);
2017 #endif
2020 ////////////////////////////////////////
2022 void cPhysModel::UpdateRopeClimbing(mxs_real dt)
2024 if (!IsRopeClimbing())
2025 return;
2027 ObjID rope = GetClimbingObj();
2028 cPhysModel *pRopeModel = g_PhysModels.Get(rope);
2030 Assert_(pRopeModel);
2032 int node = GetRopeSegment();
2034 mxs_matrix orien;
2036 // Adjust rotation to match segment
2037 mxs_vector seg_norm;
2038 mxs_matrix new_orien;
2039 mxs_angvec new_rot;
2041 mx_sub_vec(&seg_norm, &pRopeModel->GetLocationVec(node - 1), &pRopeModel->GetLocationVec(node));
2042 mx_normeq_vec(&seg_norm);
2043 mx_ang2mat(&orien, &m_pos.m_targetposition.fac);
2045 mx_cross_vec(&new_orien.vec[1], &seg_norm, &orien.vec[0]);
2046 mx_cross_vec(&new_orien.vec[0], &new_orien.vec[1], &seg_norm);
2047 mx_cross_vec(&new_orien.vec[2], &new_orien.vec[0], &new_orien.vec[1]);
2049 mx_mat2ang(&new_rot, &new_orien);
2051 m_pos.m_targetposition.fac = new_rot;
2053 // Compute target location
2054 mxs_vector seg;
2055 mxs_vector loc;
2056 mxs_vector mov;
2058 mx_sub_vec(&seg, &pRopeModel->GetLocationVec(node - 1), &pRopeModel->GetLocationVec(node));
2059 mx_scaleeq_vec(&seg, GetRopeSegmentPct());
2061 mx_add_vec(&loc, &pRopeModel->GetLocationVec(node), &seg);
2063 mx_scale_addeq_vec(&loc, &new_orien.vec[0], -1.0);
2064 mx_scale_addeq_vec(&loc, &new_orien.vec[1], -0.1);
2066 mx_sub_vec(&mov, &m_pos.m_targetposition.loc.vec, &m_pos.m_position.loc.vec);
2067 mx_addeq_vec(&loc, &mov);
2069 mxs_vector new_delta;
2070 mx_sub_vec(&new_delta, &loc, &m_pos.m_position.loc.vec);
2071 if (PhysObjValidPos(GetObjID(), &new_delta))
2072 m_pos.m_targetposition.loc.vec = loc;
2073 else
2075 m_pos.m_targetposition.loc.vec = m_pos.m_position.loc.vec;
2076 m_pos.m_targetposition.fac = m_pos.m_position.fac;
2080 ////////////////////////////////////////
2082 void cPhysModel::Squish(mxs_real magnitude)
2084 long time = GetSimTime();
2086 if ((m_lastSquishTime < 0) || (time > (m_lastSquishTime + kSquishPeriod)))
2088 m_lastSquishTime = time;
2090 #ifndef SHIP
2091 if (config_is_defined("SquishSpew"))
2092 mprintf("Obj %d is squished for %g\n", GetObjID(), magnitude);
2093 #endif
2095 AutoAppIPtr_(ObjectSystem, pObjSys);
2096 AutoAppIPtr_(StimSensors, pStimSens);
2097 AutoAppIPtr_(Stimulator, pStim);
2099 StimID stim = pObjSys->GetObjectNamed("BashStim");
2100 StimSensorID sensid = pStimSens->LookupSensor(GetObjID(), stim);
2102 if (sensid != SENSORID_NULL)
2104 sStimEventData evdat = { stim, magnitude, 0, sensid, 0, GetSimTime() };
2105 sStimEvent event(&evdat);
2107 pStim->StimulateSensor(sensid, &event);
2112 ////////////////////////////////////////
2114 void cPhysModel::UpdateTargetLocation(tPhysSubModId i, mxs_real dt)
2116 mxs_matrix obj_rotation;
2117 mxs_vector submod_offset;
2118 mxs_vector submod_targ;
2120 // Offset the submodel target position from the position target
2121 if (IsPlayer())
2123 mxs_angvec upright;
2124 mxs_vector temp_offset, mo_offset;
2126 mx_mk_angvec(&upright, 0, 0, m_pos.m_position.fac.tz);
2127 mx_ang2mat(&obj_rotation, &upright);
2129 PlayerMotionGetOffset(i, &mo_offset);
2130 mx_add_vec(&temp_offset, &m_Offset[i], &mo_offset);
2131 mx_mat_mul_vec(&submod_offset, &obj_rotation, &temp_offset);
2133 else
2135 if (IsRope())
2137 sPhysRopeProp *pRopeProp;
2139 if (!g_pPhysRopeProp->Get(GetObjID(), &pRopeProp))
2141 Warning(("cPhysModel::UpdateTargetLocation: no rope property on obj %d\n", GetObjID()));
2142 return;
2145 mx_scale_vec(&submod_offset, &kGravityDir, (mxs_real)(i) * (pRopeProp->length / 8.0));
2147 if (i > 0)
2149 mxs_vector prev_pos;
2151 mx_sub_vec(&prev_pos, &GetLocationVec(i-1), &GetLocationVec(0));
2152 mx_scaleeq_vec(&prev_pos, 0.6);
2153 prev_pos.z = 0;
2154 mx_addeq_vec(&submod_offset, &prev_pos);
2157 if (i < (NumSubModels() - 1))
2159 mxs_vector next_pos;
2161 mx_sub_vec(&next_pos, &GetLocationVec(i+1), &GetLocationVec(0));
2162 mx_scaleeq_vec(&next_pos, 0.2);
2163 next_pos.z = 0;
2165 mx_addeq_vec(&submod_offset, &next_pos);
2168 else
2170 mx_ang2mat(&obj_rotation, &m_pos.m_position.fac);
2171 mx_mat_mul_vec(&submod_offset, &obj_rotation, &m_Offset[i]);
2175 mx_add_vec(&submod_targ, &m_pos.m_targetposition.loc.vec, &submod_offset);
2176 mx_copy_vec(&m_pPosition[i].m_targetposition.loc.vec, &submod_targ);
2178 #if 0
2179 if (IsCreature())
2181 mxs_vector model_offset;
2182 mxs_vector difference;
2183 mx_sub_vec(&model_offset, &m_pos.m_targetposition.loc.vec, &m_pos.m_position.loc.vec);
2184 mx_sub_vec(&submod_offset, &m_pPosition[i].m_targetposition.loc.vec, &m_pPosition[i].m_position.loc.vec);
2185 mx_sub_vec(&difference, &model_offset, &submod_offset);
2187 Assert_(mx_mag_vec(&difference) < 0.01);
2189 #endif
2191 // Rotation
2192 mxs_vector rot_vec;
2194 mx_copy_vec(&rot_vec, &GetDynamics(i)->GetRotationalVelocity());
2195 m_pPosition[i].m_targetposition.fac.tx += mx_rad2ang(rot_vec.x * dt);
2196 m_pPosition[i].m_targetposition.fac.ty += mx_rad2ang(rot_vec.y * dt);
2197 m_pPosition[i].m_targetposition.fac.tz += mx_rad2ang(rot_vec.z * dt);
2199 #if 0
2201 mxs_matrix facing;
2202 mxs_matrix rotation;
2203 mxs_matrix end_facing;
2204 mxs_real rot_mag;
2206 mx_copy_vec(&rot_vec, &GetDynamics(i)->GetRotationalVelocity());
2208 if (!IsZeroVector(rot_vec))
2210 mx_ang2mat(&facing, &m_pPosition[i].m_position.fac);
2212 rot_mag = mx_normeq_vec(&rot_vec) * dt;
2214 mx_mk_rot_vec_mat(&rotation, &rot_vec, mx_rad2ang(rot_mag));
2215 mx_mul_mat(&end_facing, &rotation, &facing);
2217 mx_mat2ang(&m_pPosition[i].m_targetposition.fac, &end_facing);
2219 #endif
2222 ////////////////////////////////////////
2224 void cPhysModel::UpdateSpringMechanics(tPhysSubModId i, mxs_real dt)
2226 mxs_vector movement_offset;
2227 mxs_vector velocity;
2229 if (i >= m_pDynamicsData.Size())
2230 return;
2232 if ((GetSpringTension(i) > 0) && ((GetDynamics()->GetCurrentTime() == 0.0) || IsRope()))
2234 float damping_factor = 1.0;
2235 float tension_factor = 1.0;
2237 if (dt > 0.05)
2239 dt = 0.05;
2240 tension_factor = 0.6;
2241 damping_factor = 0.6;
2244 if (dt < 0.001)
2245 dt = 0.001;
2247 #if 0
2248 if (IsRope())
2250 mprintf("[%d]\n", i);
2251 mprintf("pre-tension = %g\n", tension);
2252 mprintf("pre-damping = %g\n", damping);
2254 #endif
2256 float tension;
2257 float damping;
2259 if (IsRope())
2261 tension = GetSpringTension(i) * dt * 700 * tension_factor;
2262 damping = 0.8;
2264 else
2266 tension = GetSpringTension(i) / dt;
2267 damping = GetSpringDamping(i) + ((1.0 - GetSpringDamping(i)) * dt);
2270 #if 0
2271 if (IsRope())
2273 mprintf("post-tension = %g\n", _tension);
2274 mprintf("post-damping = %g\n", _damping);
2276 if (i == 7)
2278 char buff[256];
2280 sprintf(buff, "dt = %2.4f\n", dt);
2281 mprintf("%s", buff);
2283 mprintf("\n");
2285 #endif
2287 mx_sub_vec(&movement_offset, &m_pPosition[i].m_targetposition.loc.vec, &m_pPosition[i].m_position.loc.vec);
2289 mx_scale_vec(&velocity, &movement_offset, tension);
2291 velocity.z *= 0.5;
2293 mx_scale_addeq_vec(&velocity, &m_pDynamicsData[i].GetVelocity(), damping);
2296 #if 0
2297 if (IsMantling())
2299 mprintf("movement_offset_scale_2 = %g\n", mx_mag2_vec(&movement_offset));
2300 mprintf("pre-vel = %g %g %g\n", m_pDynamicsData[i].GetVelocity().x, m_pDynamicsData[i].GetVelocity().y, m_pDynamicsData[i].GetVelocity().z);
2301 mprintf("velocity = %g %g %g\n", velocity.x, velocity.y, velocity.z);
2302 mprintf("velocity_mag_2 = %g\n", mx_mag2_vec(&velocity));
2303 mprintf("dt = %d\n", (int)(dt * 100000));
2304 mprintf("\n");
2306 #endif
2308 ApplyConstraints(i, &velocity);
2310 //do the capping AFTER constraints, really.
2311 if (IsPlayer()) //if player, do our spring capping.
2313 float maxmag = kSpringCapMag; //default value
2314 if (-1.0 * velocity.z > maxmag)
2315 maxmag = -1.0 * velocity.z; //so if I'm falling down I don't
2316 //do a Wile E. Coyote bit. Sigh. I wish we knew the
2317 //root cause of the problem with doors and ladders that
2318 //this is *cough* hacking *cough* to fix. AMSD
2319 if (mx_mag_vec(&velocity) > maxmag)
2321 ConfigSpew("SpringCapSpew",("Using spring cap\n"));
2322 mx_scaleeq_vec(&velocity,maxmag/(mx_mag_vec(&velocity)));
2327 m_pDynamicsData[i].SetVelocity(velocity);
2329 else
2331 // Back-compute velocity
2332 mx_copy_vec(&velocity, &GetVelocity());
2333 #if 0
2334 mx_sub_vec(&movement_offset, &m_pPosition[i].m_targetposition.loc.vec, &m_pPosition[i].m_position.loc.vec);
2336 mx_scale_vec(&velocity, &movement_offset, 1 / dt);
2338 if (IsPlayer() && ((i == 1) || (i == 2)))
2339 Assert_(velocity.x == GetVelocity().x);
2341 ApplyConstraints(&velocity);
2342 #endif
2344 m_pDynamicsData[i].SetVelocity(velocity);
2348 ////////////////////////////////////////////////////////////////////////////////
2350 void cPhysModel::UpdateMedium()
2352 if (IsPlayer())
2354 int submod_media_trans[3] = {PLAYER_FOOT, PLAYER_BODY, PLAYER_HEAD};
2355 int new_portal_medium[3];
2356 int new_portal_cell[3];
2357 eMediaState new_medium;
2358 int new_cell;
2360 Location new_loc;
2362 for (int i=0; i<3; i++)
2364 MakeHintedLocationFromVector(&new_loc,
2365 &GetEndLocationVec(submod_media_trans[i]),
2366 &GetLocation(submod_media_trans[i]));
2368 // @HACK: offset the player eyes by eye amount
2369 if (submod_media_trans[i] == PLAYER_HEAD)
2370 new_loc.vec.z += 0.8;
2372 if (CellFromLoc(&new_loc) != CELL_INVALID)
2374 new_portal_cell[i] = new_loc.cell;
2375 new_portal_medium[i] = WR_CELL(new_loc.cell)->medium;
2377 else
2379 new_portal_cell[i] = CELL_INVALID;
2380 new_portal_medium[i] = NO_MEDIUM;
2384 if (new_portal_medium[0] == MEDIA_WATER)
2386 if (new_portal_medium[1] == MEDIA_WATER)
2388 if (new_portal_medium[2] == MEDIA_WATER)
2390 new_cell = new_portal_cell[2];
2391 new_medium = kMS_Liquid_Submerged;
2393 else
2395 new_cell = new_portal_cell[1];
2396 new_medium = kMS_Liquid_Wading;
2399 else
2401 new_cell = new_portal_cell[0];
2402 new_medium = kMS_Liquid_Standing;
2405 else
2407 new_cell = new_portal_cell[0];
2408 new_medium = kMS_Air;
2411 if (m_medium != new_medium)
2413 ObjMediaTrans(GetObjID(), new_cell, (eMediaState)m_medium, new_medium);
2414 m_medium = new_medium;
2417 else
2419 eMediaState new_medium;
2420 int new_portal_medium;
2422 Location new_loc;
2423 MakeHintedLocationFromVector(&new_loc, &GetEndLocationVec(), &GetLocation(0));
2425 if (CellFromLoc(&new_loc) != CELL_INVALID)
2426 new_portal_medium = WR_CELL(new_loc.cell)->medium;
2427 else
2428 new_portal_medium = NO_MEDIUM;
2430 switch (new_portal_medium)
2432 case MEDIA_WATER: new_medium = kMS_Liquid_Submerged; break;
2433 case MEDIA_AIR: new_medium = kMS_Air; break;
2434 case MEDIA_SOLID: new_medium = kMS_Invalid; break;
2436 case NO_MEDIUM: return;
2439 if (m_medium != new_medium)
2441 ObjMediaTrans(GetObjID(), new_loc.cell, (eMediaState)m_medium, new_medium);
2442 m_medium = new_medium;
2447 ////////////////////////////////////////////////////////////////////////////////
2449 mxs_real cPhysModel::GetPPlateActivationWeight() const
2451 sPhysPPlateProp *pPPlateProp;
2453 if (!g_pPhysPPlateProp->Get(GetObjID(), &pPPlateProp))
2455 Warning(("GetPPlateActivationWeight: no pressure plate property on %d\n", GetObjID()));
2456 return 0.0;
2459 return pPPlateProp->activation_weight;
2462 ////////////////////////////////////////
2464 mxs_real cPhysModel::GetPPlateTravel() const
2466 sPhysPPlateProp *pPPlateProp;
2468 if (!g_pPhysPPlateProp->Get(GetObjID(), &pPPlateProp))
2470 Warning(("GetPPlateTravel: no pressure plate property on %d\n", GetObjID()));
2471 return 0.0;
2474 return pPPlateProp->travel;
2477 ///////////////////////////////////////
2479 mxs_real cPhysModel::GetPPlateSpeed() const
2481 sPhysPPlateProp *pPPlateProp;
2483 if (!g_pPhysPPlateProp->Get(GetObjID(), &pPPlateProp))
2485 Warning(("GetPPlateSpeed: no pressure plate property on %d\n", GetObjID()));
2486 return 0.0;
2489 return pPPlateProp->speed;
2492 ///////////////////////////////////////
2494 mxs_real cPhysModel::GetPPlatePause() const
2496 sPhysPPlateProp *pPPlateProp;
2498 if (!g_pPhysPPlateProp->Get(GetObjID(), &pPPlateProp))
2500 Warning(("GetPPlatePause: no pressure plate property on %d\n", GetObjID()));
2501 return 0.0;
2504 return pPPlateProp->pause;
2507 ///////////////////////////////////////
2509 int cPhysModel::GetPPlateState() const
2511 sPhysPPlateProp *pPPlateProp;
2513 if (!g_pPhysPPlateProp->Get(GetObjID(), &pPPlateProp))
2515 Warning(("GetPPlateState: no pressure plate property on %d\n", GetObjID()));
2516 return kPPS_Inactive;
2519 return pPPlateProp->state;
2522 ///////////////////////////////////////
2524 void cPhysModel::SetPPlateState(int state)
2526 sPhysPPlateProp *pPPlateProp;
2528 if (!g_pPhysPPlateProp->Get(GetObjID(), &pPPlateProp))
2530 Warning(("SetPPlateState: no pressure plate property on %d\n", GetObjID()));
2531 return;
2534 pPPlateProp->state = state;
2535 g_pPhysPPlateProp->Set(GetObjID(), pPPlateProp);
2538 ///////////////////////////////////////
2540 mxs_real cPhysModel::GetPPlateCurPause() const
2542 sPhysPPlateProp *pPPlateProp;
2544 if (!g_pPhysPPlateProp->Get(GetObjID(), &pPPlateProp))
2546 Warning(("GetPPlateCurPause: no pressure plate property on %d\n", GetObjID()));
2547 return 0.0;
2550 return pPPlateProp->cur_pause;
2553 ///////////////////////////////////////
2555 void cPhysModel::SetPPlateCurPause(mxs_real cur_pause)
2557 sPhysPPlateProp *pPPlateProp;
2559 if (!g_pPhysPPlateProp->Get(GetObjID(), &pPPlateProp))
2561 Warning(("SetPPlateCurPause: no pressure plate property on %d\n", GetObjID()));
2562 return;
2565 pPPlateProp->cur_pause = cur_pause;
2566 g_pPhysPPlateProp->Set(GetObjID(), pPPlateProp);
2569 ////////////////////////////////////////////////////////////////////////////////
2571 BOOL cPhysModel::IsRopeClimbing() const
2573 cPhysModel *pModel;
2575 if ((pModel = g_PhysModels.Get(m_climbingObj)) == NULL)
2576 return FALSE;
2578 return pModel->IsRope();
2581 ////////////////////////////////////////////////////////////////////////////////
2583 void cPhysModel::Activate(void)
2585 if (m_flags & kPMF_Inactive)
2587 g_PhysModels.ActivateToMoving(this);
2588 m_flags &= ~kPMF_Inactive;
2592 ///////////////////////////////////////
2594 void cPhysModel::Deactivate(void)
2596 if (!(m_flags & kPMF_Inactive))
2598 g_PhysModels.Deactivate(this);
2599 m_flags |= kPMF_Inactive;
2603 ///////////////////////////////////////
2605 void cPhysModel::AddTransLimit(const mxs_vector &loc, LimitCallback callback)
2607 sTransLimit *limit = new sTransLimit;
2609 mx_sub_vec(&limit->norm, &m_pos.m_position.loc.vec, &loc);
2611 if (mx_mag2_vec(&limit->norm) < 0.0001)
2613 delete limit;
2614 return;
2617 mx_normeq_vec(&limit->norm);
2618 limit->plane_const = mx_dot_vec(&limit->norm, &loc);
2620 limit->callback = callback;
2622 LGALLOC_PUSH_CREDIT();
2623 m_TransLimitList.Append(limit);
2624 LGALLOC_POP_CREDIT();
2627 ///////////////////////////////////////
2629 void cPhysModel::GetTransLimits(mxs_vector *limit_list, int *limit_list_size, int max_list_size) const
2631 for (int i=0; i<max_list_size && i<m_TransLimitList.Size(); i++)
2633 // Project our current location onto the plane
2634 mxs_real plane_dist = mx_dot_vec(&GetLocationVec(), &m_TransLimitList[i]->norm) -
2635 m_TransLimitList[i]->plane_const;
2637 mx_scale_add_vec(&limit_list[i], &GetLocationVec(), &m_TransLimitList[i]->norm, -plane_dist);
2640 *limit_list_size = i;
2643 ///////////////////////////////////////
2645 BOOL cPhysModel::CheckTransLimits(const mxs_vector &start, const mxs_vector &end, mxs_vector *limit)
2647 int i;
2648 BOOL hard_limit = FALSE;
2649 BOOL limited = FALSE;
2650 mxs_vector norm;
2651 mxs_real plane_const;
2652 mxs_real end_dist;
2655 for (i=0; i<m_TransLimitList.Size(); i++)
2657 mx_copy_vec(&norm, &m_TransLimitList[i]->norm);
2658 plane_const = m_TransLimitList[i]->plane_const;
2660 #ifdef DBG_ON
2661 if (mx_dot_vec(&start, &norm) - plane_const < 0)
2662 Warning(("CheckTransLimits: start point on far side of limit for obj %d?\n", GetObjID()));
2663 #endif
2665 end_dist = mx_dot_vec(&end, &norm) - plane_const;
2666 if (end_dist < 0)
2668 mxs_vector end_loc;
2670 limited = TRUE;
2672 mx_copy_vec(&end_loc, &end);
2674 if (m_TransLimitList[i]->callback(GetObjID()))
2676 hard_limit = TRUE;
2678 // project onto plane
2679 mx_scale_add_vec(limit, &end_loc, &norm, -end_dist);
2684 if (hard_limit)
2686 mxs_vector zero;
2688 mx_zero_vec(&zero);
2689 GetDynamics()->SetVelocity(zero);
2692 return limited;
2695 ///////////////////////////////////////
2697 void cPhysModel::AddAngleLimit(int axis, int angle, LimitCallback callback)
2699 sAngleLimit *limit = new sAngleLimit;
2701 switch (axis)
2703 case 0: limit->axis = 2; break;
2704 case 1: limit->axis = 2; break;
2705 case 2: limit->axis = 0; break;
2708 mxs_matrix obj_rotation;
2709 mxs_matrix axis_rotation;
2710 mxs_matrix end_rotation;
2712 mx_ang2mat(&obj_rotation, &GetRotation());
2713 mx_mk_rot_vec_mat(&axis_rotation, &obj_rotation.vec[axis], angle * MX_ANG_PI / 180);
2715 mx_mul_mat(&end_rotation, &axis_rotation, &obj_rotation);
2717 mx_cross_vec(&limit->plane_norm, &end_rotation.vec[limit->axis], &end_rotation.vec[axis]);
2719 limit->callback = callback;
2721 LGALLOC_PUSH_CREDIT();
2722 m_AngLimitList.Append(limit);
2723 LGALLOC_POP_CREDIT();
2726 ///////////////////////////////////////
2728 BOOL cPhysModel::CheckAngleLimits(mxs_angvec start, mxs_angvec end, mxs_angvec *limit)
2730 mxs_matrix start_mat, end_mat;
2731 mxs_real start_dp, end_dp;
2732 BOOL hard_limit = FALSE;
2733 BOOL limited = FALSE;
2734 int i;
2736 *limit = end;
2738 mx_ang2mat(&start_mat, &start);
2739 mx_ang2mat(&end_mat, &end);
2741 for (i=0; i<m_AngLimitList.Size(); i++)
2743 start_dp = mx_dot_vec(&start_mat.vec[m_AngLimitList[i]->axis], &m_AngLimitList[i]->plane_norm);
2744 end_dp = mx_dot_vec(&end_mat.vec[m_AngLimitList[i]->axis], &m_AngLimitList[i]->plane_norm);
2746 if (((start_dp * end_dp) < 0) || (end_dp == 0.0 && start_dp != 0.0))
2748 limited = TRUE;
2750 if (m_AngLimitList[i]->callback)
2751 hard_limit |= m_AngLimitList[i]->callback(GetObjID());
2755 if (limited)
2757 if (IsPlayer())
2758 *limit = start;
2759 else
2760 *limit = m_pos.m_position.fac;
2763 if (hard_limit)
2765 mxs_vector zero;
2767 mx_zero_vec(&zero);
2768 GetDynamics()->SetRotationalVelocity(zero);
2771 return limited;
2774 ///////////////////////////////////////////////////////////////////////////////
2776 #ifndef SHIP
2778 long cPhysModel::InternalSize() const
2780 int i;
2781 long size = 0;
2783 size += m_springInfo.Size() * sizeof(tSpringInfo);
2785 size += m_ConstraintList.Size() * sizeof(tConstraint);
2786 for (i=0; i<m_SubModConstraintList.Size(); i++)
2787 size += m_SubModConstraintList[i].Size() * sizeof(tConstraint);
2788 size += m_VelConstraintList.Size() * sizeof(tVelocityConstraint);
2790 size += m_nSubModels * sizeof(ePhysModelType);
2792 size += m_nSubModels * sizeof(cPhysPos);
2793 size += m_Offset.Size() * sizeof(mxs_vector);
2795 size += m_AngLimitList.Size() * (sizeof(sAngleLimit *) + sizeof(sAngleLimit));
2796 size += m_TransLimitList.Size() * (sizeof(sAngleLimit *) + sizeof(sTransLimit));
2798 size += 8 + m_pDynamicsData.Size() * sizeof(cPhysDynData);
2799 size += 8 + m_pControlData.Size() * sizeof(cPhysCtrlData);
2801 return size;
2804 #endif
2806 ///////////////////////////////////////////////////////////////////////////////