2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
6 ///////////////////////////////////////////////////////////////////////////////
7 // $Header: r:/t2repos/thief2/src/physics/phmod.cpp,v 1.154 2000/03/20 09:45:23 adurant Exp $
46 #include <aiapi.h> // for ObjIsAI()
81 // Must be last header
84 extern BOOL gInsideMT
;
86 mxs_real kSpringCapMag
= 25.0; //extern deffed in phconst
88 ///////////////////////////////////////////////////////////////////////////////
90 // CLASS: cPhysModelTable
94 template cPhysModelTableBase
;
97 tHashSetKey
cPhysModelTable::GetKey(tHashSetNode node
) const
99 return (tHashSetKey
)((((cPhysModel
*)(node
))->m_objID
));
102 ///////////////////////////////////////////////////////////////////////////////
107 cPhysModel::cPhysModel(ObjID objID
, ePhysModelType type
,
108 tPhysSubModId numSubModels
, unsigned flags
)
110 m_nSubModels(numSubModels
),
113 m_nObjectContacts(0),
116 m_nVertexContacts(0),
117 m_pointVsTerrain(FALSE
),
124 // Sphere-hats always have 2 submodels
125 if (type
== kPMT_SphereHat
)
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
;
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
;
159 if (g_pPhysAICollideProp
->Get(objID
, &ai_collides
) && ai_collides
)
160 m_flags
|= kPMF_AICollides
;
162 if (flags
& kPMCF_NoGravity
)
167 // Init all submodels to the given type
168 m_pType
= new ePhysModelType
[m_nSubModels
];
169 for (i
=0; i
<m_nSubModels
; i
++)
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
);
191 // Check for PhysAttach links
192 query
= g_pPhysAttachRelation
->Query(objID
, LINKOBJ_WILDCARD
);
196 m_isAttached
= FALSE
;
199 query
= g_pPhysAttachRelation
->Query(LINKOBJ_WILDCARD
, objID
);
201 for (; !query
->Done(); query
->Next())
209 m_climbingObj
= OBJ_NULL
;
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
);
253 m_pDynamicsData
.SetSize(0);
255 // Allocate controls if controllable
256 if (!(flags
& kPMCF_Uncontrollable
) && (type
!= kPMT_OBB
))
257 m_pControlData
.SetSize(m_nSubModels
);
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
279 g_PhysModels
.AddToMoving(this);
281 g_PhysModels
.AddToStationary(this);
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
)
295 ///////////////////////////////////////
297 cPhysModel::cPhysModel(PhysReadWrite func
) :
300 m_nVertexContacts(0),
301 m_nObjectContacts(0),
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);
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);
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);
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);
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);
370 m_pointVsTerrain
= FALSE
;
372 if (g_PhysVersion
>= 22)
373 func((void *)&m_passThruDT
, sizeof(BOOL
), 1);
377 if (g_PhysVersion
>= 14)
379 func((void *)&m_nAttachments
, sizeof(int), 1);
380 func((void *)&m_isAttached
, sizeof(BOOL
), 1);
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);
400 if (g_PhysVersion
>= 18)
401 func((void *)&m_climbingObj
, sizeof(ObjID
), 1);
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);
416 if (g_PhysVersion
>= 19)
418 func((void *)&m_mantlingState
, sizeof(int), 1);
419 func((void *)&m_mantlingTargVec
, sizeof(mxs_vector
), 1);
424 mx_zero_vec(&m_mantlingTargVec
);
427 if (g_PhysVersion
>= 31)
428 func((void *)&m_referenceFrameObj
, sizeof(ObjID
), 1);
430 m_referenceFrameObj
= NULL
;
432 if (g_PhysVersion
>= 25)
433 func((void *)&m_lastSquishTime
, sizeof(long), 1);
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
);
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);
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);
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);
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())
492 func((void *)&state
, sizeof(int), 1);
494 if ((state
== kPPS_Activating
) ||
495 (state
== kPPS_Deactivating
))
499 func((void *)&limit
, sizeof(mxs_vector
), 1);
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);
515 if (g_PhysVersion
<= 11)
516 m_DynamicsData
.LoadV11(func
);
518 func(&m_DynamicsData
, sizeof(cPhysDynData
), 1);
519 m_pDynamicsData
.SetSize(0);
524 if (g_PhysVersion
>= 7)
526 if (g_PhysVersion
<= 11)
527 m_DynamicsData
.LoadV11(func
);
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
);
538 if (g_PhysVersion
>= 28)
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);
550 if (m_pType
[0] == kPMT_OBB
)
554 m_pDynamicsData
.SetSize(0);
555 for (i
=0; i
<m_nSubModels
; i
++)
556 func(&dummy
, sizeof(cPhysDynData
), 1);
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);
571 func(&m_ControlData
, sizeof(cPhysCtrlData
), 1);
572 m_pControlData
.SetSize(0);
577 if (g_PhysVersion
>= 7)
578 func(&m_ControlData
, sizeof(cPhysCtrlData
), 1);
579 if (g_PhysVersion
>= 28)
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);
591 if (m_pType
[0] == kPMT_OBB
)
595 m_pControlData
.SetSize(0);
596 for (i
=0; i
<m_nSubModels
; i
++)
597 func(&dummy
, sizeof(cPhysCtrlData
), 1);
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);
629 #define DO_SUBMOD_ROT_FIXUP (TRUE)
631 #define DO_SUBMOD_ROT_FIXUP (!config_is_defined("no_submod_rot_fixup"))
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)
653 cPhysCtrlData
*pControls
= GetControls();
655 pControls
->ControlRotation(GetRotation());
662 void cPhysModel::UpdateDiskInfo()
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()
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
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
770 if (m_pDynamicsData
.Size())
772 int size
= m_pDynamicsData
.Size();
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);
784 func(&flag
, sizeof(int), 1);
785 func((void *)&m_DynamicsData
, sizeof(cPhysDynData
), 1);
791 func(&flag
, sizeof(int), 1);
794 if (IsControllable())
796 if (m_pControlData
.Size())
798 int size
= m_pControlData
.Size();
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);
810 func(&flag
, sizeof(int), 1);
811 func((void *)&m_ControlData
, sizeof(cPhysCtrlData
), 1);
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
);
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
);
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
;
876 ObjRotate(GetObjID(), &rot
);
879 ///////////////////////////////////////
881 const mxs_vector
cPhysModel::GetCOG() const
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
);
893 ///////////////////////////////////////
895 static AttachConstrainLock
= FALSE
;
897 void cPhysModel::AddConstraint(ObjID cause
, const mxs_vector
&dir
, mxs_real mag
)
902 for (int i
=0; i
<m_VelConstraintList
.Size(); i
++)
904 if (EqualVectors(m_VelConstraintList
[i
].dir
, dir
))
908 tVelocityConstraint vel_const
;
910 vel_const
.cause
= cause
;
914 LGALLOC_PUSH_CREDIT();
915 m_VelConstraintList
.Append(vel_const
);
916 LGALLOC_POP_CREDIT();
918 // And constrain any attachments
919 if (AttachConstrainLock
== TRUE
)
924 ILinkQuery
*query
= g_pPhysAttachRelation
->Query(ObjID(), LINKOBJ_WILDCARD
);
931 cPhysModel
*pModelDest
= g_PhysModels
.GetActive(link
.dest
);
932 if (pModelDest
!= NULL
)
934 AttachConstrainLock
= TRUE
;
935 pModelDest
->AddConstraint(cause
, dir
, mag
);
936 AttachConstrainLock
= FALSE
;
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
))
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
)
968 ILinkQuery
*query
= g_pPhysAttachRelation
->Query(ObjID(), LINKOBJ_WILDCARD
);
975 cPhysModel
*pModelDest
= g_PhysModels
.GetActive(link
.dest
);
976 if (pModelDest
!= NULL
)
978 AttachConstrainLock
= TRUE
;
979 pModelDest
->AddConstraint(cause
, norm
);
980 AttachConstrainLock
= FALSE
;
987 ///////////////////////////////////////
989 void cPhysModel::AddConstraint(ObjID cause
, tPhysSubModId i
, const mxs_vector
&norm
)
991 BOOL in_model
= FALSE
;
992 BOOL in_submodel
= FALSE
;
995 for (j
=0; j
<m_ConstraintList
.Size(); j
++)
997 if (EqualVectors(m_ConstraintList
[j
].dir
, norm
))
1004 for (j
=0; j
<m_SubModConstraintList
[i
].Size(); j
++)
1006 if (EqualVectors(m_SubModConstraintList
[i
][j
].dir
, norm
))
1013 if (in_model
&& in_submodel
)
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
)
1032 ILinkQuery
*query
= g_pPhysAttachRelation
->Query(ObjID(), LINKOBJ_WILDCARD
);
1039 cPhysModel
*pModelDest
= g_PhysModels
.GetActive(link
.dest
);
1040 if (pModelDest
!= NULL
)
1042 AttachConstrainLock
= TRUE
;
1043 pModelDest
->AddConstraint(cause
, norm
);
1044 AttachConstrainLock
= FALSE
;
1051 ///////////////////////////////////////
1053 void cPhysModel::ApplyConstraints(mxs_vector
*vec
)
1063 mx_copy_vec(&start
, vec
);
1065 for (int i
=0; i
<m_VelConstraintList
.Size(); i
++)
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());
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
)
1134 for (i
=0; (i
<m_ConstraintList
.Size()) && (i
<*num_vecs
); i
++)
1135 mx_copy_vec(&vec_list
[i
], &m_ConstraintList
[i
].dir
);
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
));
1152 ///////////////////////////////////////
1154 BOOL
cPhysModel::IsControlled()
1156 if (!IsControllable())
1159 if (m_ControlData
.GetType() != kPCT_NoControl
)
1162 for (int i
=0; i
<m_pControlData
.Size(); i
++)
1164 if (m_pControlData
[i
].GetType() != kPCT_NoControl
)
1171 ///////////////////////////////////////
1173 BOOL
cPhysModel::IsVelocityControlled()
1175 if (!IsControllable())
1178 if (m_ControlData
.GetType() & kPCT_VelControl
)
1181 for (int i
=0; i
<m_pControlData
.Size(); i
++)
1183 if (m_pControlData
[i
].GetType() & kPCT_VelControl
)
1190 ///////////////////////////////////////
1192 BOOL
cPhysModel::IsAxisVelocityControlled()
1194 if (!IsControllable())
1197 if ((m_ControlData
.GetType() & kPCT_VelControl
) && m_ControlData
.AxisControlled())
1200 for (int i
=0; i
<m_pControlData
.Size(); i
++)
1202 if ((m_pControlData
[i
].GetType() & kPCT_VelControl
) && m_pControlData
[i
].AxisControlled())
1209 ///////////////////////////////////////
1211 BOOL
cPhysModel::IsRotationalVelocityControlled()
1213 if (!IsControllable())
1216 if (m_ControlData
.GetType() & kPCT_RotVelControl
)
1221 for (int i
=0; i
<m_pControlData
.Size(); i
++)
1223 if (m_pControlData
[i
].GetType() & kPCT_RotVelControl
)
1231 ///////////////////////////////////////
1233 BOOL
cPhysModel::IsLocationControlled()
1235 if (!IsControllable())
1238 if (m_ControlData
.GetType() & kPCT_LocControl
)
1241 for (int i
=0; i
<m_pControlData
.Size(); i
++)
1243 if (m_pControlData
[i
].GetType() & kPCT_LocControl
)
1250 ///////////////////////////////////////
1252 BOOL
cPhysModel::IsRotationControlled()
1254 if (!IsControllable())
1257 if (m_ControlData
.GetType() & kPCT_RotControl
)
1260 for (int i
=0; i
<m_pControlData
.Size(); i
++)
1262 if (m_pControlData
[i
].GetType() & kPCT_RotControl
)
1269 ///////////////////////////////////////
1271 void cPhysModel::SetSleep(BOOL state
)
1273 if (IsCreature() && !IsRope() && CreatureSelfPropelled(GetObjID()) && (state
== FALSE
))
1276 if (IsWeapon(0) && (state
== FALSE
))
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
);
1301 if (IsPressurePlate() && (GetPPlateState() != kPPS_Inactive
) && (state
== TRUE
))
1304 if (ObjectPassThru() && (state
== TRUE
))
1307 if (state
!= IsSleeping())
1309 SetFlagState(kPMF_Sleeping
, 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());
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();
1345 WakeUpContacts(this);
1348 g_PhysModels
.StartMoving(this);
1349 PhysMessageWokeUp(GetObjID());
1354 ///////////////////////////////////////
1356 BOOL
cPhysModel::IsTranslating() const
1358 BOOL moving
= FALSE
;
1362 if (!IsZeroVector(GetDynamics()->GetVelocity()))
1365 if (!IsZeroVector(GetDynamics()->GetRotationalVelocity()) &&
1366 !IsZeroVector(m_cog
))
1369 for (int i
=0; i
<NumSubModels(); i
++)
1371 if (!IsZeroVector(GetDynamics(i
)->GetVelocity()))
1374 if (!IsZeroVector(GetDynamics(i
)->GetRotationalVelocity()) &&
1375 !IsZeroVector(m_cog
))
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
))
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
))
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
)
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
)
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
))
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
))
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
))
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
);
1516 BOOL
cPhysModel::GetEdgeContacts(tPhysSubModId subModId
, cEdgeContactList
**ppEdgeContactList
) const
1518 if (m_nEdgeContacts
> 0)
1519 return g_PhysContactLinks
.GetTerrainLinks(m_objID
, subModId
, ppEdgeContactList
);
1524 BOOL
cPhysModel::GetVertexContacts(tPhysSubModId subModId
, cVertexContactList
**ppVertexContactList
) const
1526 if (m_nVertexContacts
> 0)
1527 return g_PhysContactLinks
.GetTerrainLinks(m_objID
, subModId
, ppVertexContactList
);
1532 ////////////////////////////////////////////////////////////////////////////////
1534 void cPhysModel::UpdateEndLocation(mxs_real dt
)
1538 mx_copy_vec(&m_pos
.m_endposition
.loc
.vec
, &m_pos
.m_position
.loc
.vec
);
1543 mx_copy_vec(&m_pos
.m_endposition
.loc
.vec
, &m_pos
.m_targetposition
.loc
.vec
);
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
);
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
;
1572 PlayerMotionGetOffset(i
, &offset
);
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
);
1583 mx_sub_vec(&movement_offset
, &m_pPosition
[i
].m_targetposition
.loc
.vec
, &m_pPosition
[i
].m_position
.loc
.vec
);
1586 mx_add_vec(&m_pPosition
[i
].m_endposition
.loc
.vec
, &m_pPosition
[i
].m_position
.loc
.vec
, &movement_offset
);
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
);
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
1607 return m_pos
.m_endposition
.loc
;
1609 return m_pPosition
[subModId
].m_endposition
.loc
;
1612 ///////////////////////////////////////
1614 const mxs_vector
& cPhysModel::GetEndLocationVec(tPhysSubModId subModId
) const
1617 return m_pos
.m_endposition
.loc
.vec
;
1619 return m_pPosition
[subModId
].m_endposition
.loc
.vec
;
1622 ///////////////////////////////////////
1624 void cPhysModel::SetEndLocationVec(tPhysSubModId subModId
, const mxs_vector
&end_loc
)
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;
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
1641 return m_pos
.m_endposition
.fac
;
1643 return m_pPosition
[subModId
].m_endposition
.fac
;
1646 ///////////////////////////////////////
1648 void cPhysModel::SetEndRotationVec(tPhysSubModId subModId
, const mxs_angvec
&end_ang
)
1651 m_pos
.m_endposition
.fac
= end_ang
;
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
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
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
);
1678 if (cur_mode
==kPM_Crouch
)
1679 speed
*=special_muls
[1];
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
);
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))
1707 if (config_is_defined("player_fall_loud"))
1708 mprintf("Saved Me\n");
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
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
)
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
;
1818 LinkID linkID
= g_pPhysAttachRelation
->GetSingleLink(GetObjID(), LINKOBJ_WILDCARD
);
1823 g_pPhysAttachRelation
->Get(linkID
, &link
);
1824 sPhysAttachData
*pAttachData
= (sPhysAttachData
*)g_pPhysAttachRelation
->GetData(linkID
);
1826 cPhysModel
*pAttachModel
= g_PhysModels
.GetActive(link
.dest
);
1830 mx_add_vec(&m_pos
.m_targetposition
.loc
.vec
, &pAttachModel
->GetTargetLocation(), &pAttachData
->offset
);
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
);
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
);
1864 // Apply constraints
1865 ApplyConstraints(&velocity
);
1867 pDyn
->SetVelocity(velocity
);
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
,
1875 // Adjust location for rotation not around center point
1876 if (!IsPlayer() && !IsZeroVector(m_cog
) && (rot_mag
> 0.0001))
1878 mxs_matrix rotation
;
1880 mxs_matrix both_rot
;
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
));
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
);
1907 mx_sub_vec(&add_offset
, &rot_offset
, &cog_offset
);
1909 mx_addeq_vec(&m_pos
.m_targetposition
.loc
.vec
, &add_offset
);
1914 LinkID linkID
= g_pPhysAttachRelation
->GetSingleLink(GetObjID(), LINKOBJ_WILDCARD
);
1919 g_pPhysAttachRelation
->Get(linkID
, &link
);
1920 sPhysAttachData
*pAttachData
= (sPhysAttachData
*)g_pPhysAttachRelation
->GetData(linkID
);
1922 cPhysModel
*pAttachModel
= g_PhysModels
.GetActive(link
.dest
);
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()));
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);
1975 if (config_is_defined("RopeSpew"))
1976 mprintf(" Obj %d moved from node %d to %d\n", GetObjID(), node_1
, node_1
+ 1);
1980 BreakClimb(GetObjID(), FALSE
, FALSE
);
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)
1990 SetRopeSegment(node_2
);
1991 SetRopeSegmentPct(0.0);
1994 if (config_is_defined("RopeSpew"))
1995 mprintf(" Obj %d moved from node %d to %d\n", GetObjID(), node_1
, node_2
);
2001 // within the segment
2002 mxs_vector on_segment
;
2003 mxs_vector seg_norm
;
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
);
2015 if (config_is_defined("RopeSpew"))
2016 mprintf(" Obj %d is %g along segment %d\n", GetObjID(), GetRopeSegmentPct(), node_1
);
2020 ////////////////////////////////////////
2022 void cPhysModel::UpdateRopeClimbing(mxs_real dt
)
2024 if (!IsRopeClimbing())
2027 ObjID rope
= GetClimbingObj();
2028 cPhysModel
*pRopeModel
= g_PhysModels
.Get(rope
);
2030 Assert_(pRopeModel
);
2032 int node
= GetRopeSegment();
2036 // Adjust rotation to match segment
2037 mxs_vector seg_norm
;
2038 mxs_matrix new_orien
;
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
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
;
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
;
2091 if (config_is_defined("SquishSpew"))
2092 mprintf("Obj %d is squished for %g\n", GetObjID(), magnitude
);
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
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
);
2137 sPhysRopeProp
*pRopeProp
;
2139 if (!g_pPhysRopeProp
->Get(GetObjID(), &pRopeProp
))
2141 Warning(("cPhysModel::UpdateTargetLocation: no rope property on obj %d\n", GetObjID()));
2145 mx_scale_vec(&submod_offset
, &kGravityDir
, (mxs_real
)(i
) * (pRopeProp
->length
/ 8.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);
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);
2165 mx_addeq_vec(&submod_offset
, &next_pos
);
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
);
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);
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
);
2202 mxs_matrix rotation
;
2203 mxs_matrix end_facing
;
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
);
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())
2232 if ((GetSpringTension(i
) > 0) && ((GetDynamics()->GetCurrentTime() == 0.0) || IsRope()))
2234 float damping_factor
= 1.0;
2235 float tension_factor
= 1.0;
2240 tension_factor
= 0.6;
2241 damping_factor
= 0.6;
2250 mprintf("[%d]\n", i
);
2251 mprintf("pre-tension = %g\n", tension
);
2252 mprintf("pre-damping = %g\n", damping
);
2261 tension
= GetSpringTension(i
) * dt
* 700 * tension_factor
;
2266 tension
= GetSpringTension(i
) / dt
;
2267 damping
= GetSpringDamping(i
) + ((1.0 - GetSpringDamping(i
)) * dt
);
2273 mprintf("post-tension = %g\n", _tension
);
2274 mprintf("post-damping = %g\n", _damping
);
2280 sprintf(buff
, "dt = %2.4f\n", dt
);
2281 mprintf("%s", buff
);
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
);
2293 mx_scale_addeq_vec(&velocity
, &m_pDynamicsData
[i
].GetVelocity(), damping
);
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));
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
);
2331 // Back-compute velocity
2332 mx_copy_vec(&velocity
, &GetVelocity());
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
);
2344 m_pDynamicsData
[i
].SetVelocity(velocity
);
2348 ////////////////////////////////////////////////////////////////////////////////
2350 void cPhysModel::UpdateMedium()
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
;
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
;
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
;
2395 new_cell
= new_portal_cell
[1];
2396 new_medium
= kMS_Liquid_Wading
;
2401 new_cell
= new_portal_cell
[0];
2402 new_medium
= kMS_Liquid_Standing
;
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
;
2419 eMediaState new_medium
;
2420 int new_portal_medium
;
2423 MakeHintedLocationFromVector(&new_loc
, &GetEndLocationVec(), &GetLocation(0));
2425 if (CellFromLoc(&new_loc
) != CELL_INVALID
)
2426 new_portal_medium
= WR_CELL(new_loc
.cell
)->medium
;
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()));
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()));
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()));
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()));
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()));
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()));
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()));
2565 pPPlateProp
->cur_pause
= cur_pause
;
2566 g_pPhysPPlateProp
->Set(GetObjID(), pPPlateProp
);
2569 ////////////////////////////////////////////////////////////////////////////////
2571 BOOL
cPhysModel::IsRopeClimbing() const
2575 if ((pModel
= g_PhysModels
.Get(m_climbingObj
)) == NULL
)
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)
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
)
2648 BOOL hard_limit
= FALSE
;
2649 BOOL limited
= FALSE
;
2651 mxs_real plane_const
;
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
;
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()));
2665 end_dist
= mx_dot_vec(&end
, &norm
) - plane_const
;
2672 mx_copy_vec(&end_loc
, &end
);
2674 if (m_TransLimitList
[i
]->callback(GetObjID()))
2678 // project onto plane
2679 mx_scale_add_vec(limit
, &end_loc
, &norm
, -end_dist
);
2689 GetDynamics()->SetVelocity(zero
);
2695 ///////////////////////////////////////
2697 void cPhysModel::AddAngleLimit(int axis
, int angle
, LimitCallback callback
)
2699 sAngleLimit
*limit
= new sAngleLimit
;
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
;
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))
2750 if (m_AngLimitList
[i
]->callback
)
2751 hard_limit
|= m_AngLimitList
[i
]->callback(GetObjID());
2760 *limit
= m_pos
.m_position
.fac
;
2768 GetDynamics()->SetRotationalVelocity(zero
);
2774 ///////////////////////////////////////////////////////////////////////////////
2778 long cPhysModel::InternalSize() const
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
);
2806 ///////////////////////////////////////////////////////////////////////////////