void CBaseButton :: Spawn( void ) { Precache(); // this button should spark in OFF state if( FBitSet( pev->spawnflags, SF_BUTTON_SPARK_IF_OFF )) { SetThink( &CBaseButton::ButtonSpark ); SetNextThink( 0.5f ); } pev->movetype = MOVETYPE_PUSH; pev->solid = SOLID_BSP; SET_MODEL( edict(), GetModel() ); if( pev->speed == 0 ) pev->speed = 40; if( pev->health > 0 ) { pev->takedamage = DAMAGE_YES; } if( m_flWait == 0 ) m_flWait = 1; if( m_flLip == 0 ) m_flLip = 4; m_iState = STATE_OFF; m_vecPosition1 = GetLocalOrigin(); // Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big Vector vecSize = pev->size - Vector( 2, 2, 2 ); m_vecPosition2 = m_vecPosition1 + (pev->movedir * (DotProductAbs( pev->movedir, vecSize ) - m_flLip)); // Is this a non-moving button? if((( m_vecPosition2 - m_vecPosition1 ).Length() < 1 ) || FBitSet( pev->spawnflags, SF_BUTTON_DONTMOVE )) m_vecPosition2 = m_vecPosition1; m_fStayPushed = (m_flWait == -1) ? TRUE : FALSE; m_fRotating = FALSE; // if the button is flagged for USE button activation only, take away it's touch function and add a use function if( FBitSet( pev->spawnflags, SF_BUTTON_TOUCH_ONLY )) { SetTouch( &CBaseButton::ButtonTouch ); SetUse( NULL ); } else { SetTouch( NULL ); SetUse( &CBaseButton::ButtonUse ); } UTIL_SetOrigin( this, m_vecPosition1 ); m_pUserData = WorldPhysic->CreateKinematicBodyFromEntity( this ); }
//------------------------------------------------------------------------------ // Purpose: Called before spawning, after keyvalues have been parsed. //------------------------------------------------------------------------------ void CFuncMoveLinear::Spawn( void ) { // Convert movedir from angles to a vector QAngle angMoveDir = QAngle( m_vecMoveDir.x, m_vecMoveDir.y, m_vecMoveDir.z ); AngleVectors( angMoveDir, &m_vecMoveDir ); SetMoveType( MOVETYPE_PUSH ); SetModel( STRING( GetModelName() ) ); // Don't allow zero or negative speeds if (m_flSpeed <= 0) { m_flSpeed = 100; } // If move distance is set to zero, use with width of the // brush to determine the size of the move distance if (m_flMoveDistance <= 0) { Vector vecOBB = CollisionProp()->OBBSize(); vecOBB -= Vector( 2, 2, 2 ); m_flMoveDistance = DotProductAbs( m_vecMoveDir, vecOBB ) - m_flLip; } /* BM: Fixing this based on: https://developer.valvesoftware.com/wiki/CFuncMoveLinear_Fix m_vecPosition1 = GetAbsOrigin() - (m_vecMoveDir * m_flMoveDistance * m_flStartPosition); m_vecPosition2 = m_vecPosition1 + (m_vecMoveDir * m_flMoveDistance); m_vecFinalDest = GetAbsOrigin(); //*/ m_vecPosition1 = GetLocalOrigin() - (m_vecMoveDir * m_flMoveDistance * m_flStartPosition); m_vecPosition2 = m_vecPosition1 + (m_vecMoveDir * m_flMoveDistance); m_vecFinalDest = GetLocalOrigin(); //*/ The start & end positions are now calculated in local (parent) space. SetTouch( NULL ); Precache(); // It is solid? SetSolid( SOLID_VPHYSICS ); if ( FClassnameIs( this, "func_water_analog" ) ) { AddSolidFlags( FSOLID_VOLUME_CONTENTS ); } if ( !FClassnameIs( this, "func_water_analog" ) && FBitSet (m_spawnflags, SF_MOVELINEAR_NOTSOLID) ) { AddSolidFlags( FSOLID_NOT_SOLID ); } CreateVPhysics(); }
void CMomentaryDoor :: Spawn( void ) { if( FBitSet( pev->spawnflags, SF_DOOR_PASSABLE )) pev->solid = SOLID_NOT; else pev->solid = SOLID_BSP; pev->movetype = MOVETYPE_PUSH; if( pev->speed <= 0 ) pev->speed = 100; if( pev->movedir == g_vecZero ) pev->movedir = Vector( 1.0f, 0.0f, 0.0f ); Precache(); SetTouch( NULL ); SET_MODEL( edict(), GetModel() ); // if move distance is set to zero, use with width of the // brush to determine the size of the move distance if( m_flMoveDistance <= 0 ) { Vector vecSize = pev->size - Vector( 2, 2, 2 ); m_flMoveDistance = DotProductAbs( pev->movedir, vecSize ) - m_flLip; } m_vecPosition1 = GetLocalOrigin(); m_vecPosition2 = m_vecPosition1 + (pev->movedir * m_flMoveDistance); if( FBitSet( pev->spawnflags, SF_DOOR_START_OPEN )) { UTIL_SetOrigin( this, m_vecPosition2 ); // NOTE: momentary door doesn't have absolute positions // so we need swap it here for right movement m_vecPosition2 = m_vecPosition1; m_vecPosition1 = GetLocalOrigin(); } else { UTIL_SetOrigin( this, m_vecPosition1 ); } m_pUserData = WorldPhysic->CreateKinematicBodyFromEntity( this ); m_iState = STATE_OFF; }
void CPhysMotor::Activate( void ) { BaseClass::Activate(); // This gets called after all objects spawn and after all objects restore if ( m_attachedObject == NULL ) { CBaseEntity *pAttach = gEntList.FindEntityByName( NULL, m_nameAttach, NULL ); if ( pAttach && pAttach->GetMoveType() == MOVETYPE_VPHYSICS ) { m_attachedObject = pAttach; IPhysicsObject *pPhys = m_attachedObject->VPhysicsGetObject(); CalculateAcceleration(); matrix3x4_t matrix; pPhys->GetPositionMatrix( matrix ); Vector motorAxis_ls; VectorIRotate( m_motor.m_axis, matrix, motorAxis_ls ); float inertia = DotProductAbs( pPhys->GetInertia(), motorAxis_ls ); m_motor.m_maxTorque = inertia * m_motor.m_inertiaFactor * (m_angularAcceleration + m_additionalAcceleration); m_motor.m_restistanceDamping = 1.0f; } } if ( m_attachedObject ) { IPhysicsObject *pPhys = m_attachedObject->VPhysicsGetObject(); // create a hinge constraint for this object? if ( m_spawnflags & SF_MOTOR_HINGE ) { // UNDONE: Don't do this on restore? if ( !m_pHinge ) { constraint_hingeparams_t hingeParams; hingeParams.Defaults(); hingeParams.worldAxisDirection = m_motor.m_axis; hingeParams.worldPosition = GetLocalOrigin(); m_pHinge = physenv->CreateHingeConstraint( g_PhysWorldObject, pPhys, NULL, hingeParams ); m_pHinge->SetGameData( (void *)this ); } if ( m_spawnflags & SF_MOTOR_NOCOLLIDE ) { physenv->DisableCollisions( pPhys, g_PhysWorldObject ); } } else { m_pHinge = NULL; } // NOTE: On restore, this path isn't run because m_pController will not be NULL if ( !m_pController ) { m_pController = physenv->CreateMotionController( &m_motor ); m_pController->AttachObject( m_attachedObject->VPhysicsGetObject() ); if ( m_spawnflags & SF_MOTOR_START_ON ) { TurnOn(); } } } // Need to do this on restore since there's no good way to save this if ( m_pController ) { m_pController->SetEventHandler( &m_motor ); } }
IMotionEvent::simresult_e CMotorController::Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular ) { linear = vec3_origin; angular = vec3_origin; if ( m_speed == 0 ) return SIM_NOTHING; matrix3x4_t matrix; pObject->GetPositionMatrix( matrix ); AngularImpulse currentRotAxis; // currentRotAxis is in local space pObject->GetVelocity( NULL, ¤tRotAxis ); // transform motor axis to local space Vector motorAxis_ls; VectorIRotate( m_axis, matrix, motorAxis_ls ); float currentSpeed = DotProduct( currentRotAxis, motorAxis_ls ); float inertia = DotProductAbs( pObject->GetInertia(), motorAxis_ls ); // compute absolute acceleration, don't integrate over the timestep float accel = m_speed - currentSpeed; float rotForce = accel * inertia * m_inertiaFactor; // BUGBUG: This heuristic is a little flaky // UNDONE: Make a better heuristic for speed control if ( fabsf(m_lastAcceleration) > 0 ) { float deltaSpeed = currentSpeed - m_lastSpeed; // make sure they are going the same way if ( deltaSpeed * accel > 0 ) { float factor = deltaSpeed / m_lastAcceleration; factor = 1 - clamp( factor, 0, 1 ); rotForce += m_lastForce * factor * m_restistanceDamping; } else { if ( currentSpeed != 0 ) { // have we reached a steady state that isn't our target? float increase = deltaSpeed / m_lastAcceleration; if ( fabsf(increase) < 0.05 ) { rotForce += m_lastForce * m_restistanceDamping; } } } } // ------------------------------------------------------- if ( m_maxTorque != 0 ) { if ( rotForce > m_maxTorque ) { rotForce = m_maxTorque; } else if ( rotForce < -m_maxTorque ) { rotForce = -m_maxTorque; } } m_lastForce = rotForce; m_lastAcceleration = (rotForce / inertia); m_lastSpeed = currentSpeed; // this is in local space angular = motorAxis_ls * rotForce; return SIM_LOCAL_FORCE; }
void CBaseDoor::Spawn( void ) { if( pev->skin == CONTENTS_NONE ) { // normal door if( FBitSet( pev->spawnflags, SF_DOOR_PASSABLE )) pev->solid = SOLID_NOT; else pev->solid = SOLID_BSP; } else { SetBits( pev->spawnflags, SF_DOOR_SILENT ); pev->solid = SOLID_NOT; // special contents } Precache(); pev->movetype = MOVETYPE_PUSH; SET_MODEL( edict(), GetModel() ); // NOTE: original Half-Life was contain a bug in LinearMove function // while m_flWait was equal 0 then object has stopped forever. See code from quake: /* void LinearMove( Vector vecDest, float flSpeed ) { ... ... ... if( flTravelTime < 0.1f ) { pev->velocity = g_vecZero; pev->nextthink = pev->ltime + 0.1f; return; } } */ // this block was removed from Half-Life and there no difference // between wait = 0 and wait = -1. But in Xash this bug was fixed // and level-designer errors is now actual. I'm set m_flWait to -1 for compatibility if( m_flWait == 0.0f ) m_flWait = -1; if( pev->speed == 0 ) pev->speed = 100; if( pev->movedir == g_vecZero ) pev->movedir = Vector( 1.0f, 0.0f, 0.0f ); m_vecPosition1 = GetLocalOrigin(); // Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big Vector vecSize = pev->size - Vector( 2, 2, 2 ); m_vecPosition2 = m_vecPosition1 + (pev->movedir * (DotProductAbs( pev->movedir, vecSize ) - m_flLip)); ASSERTSZ( m_vecPosition1 != m_vecPosition2, "door start/end positions are equal" ); if( FBitSet( pev->spawnflags, SF_DOOR_START_OPEN )) { UTIL_SetOrigin( this, m_vecPosition2 ); m_vecPosition2 = m_vecPosition1; m_vecPosition1 = GetLocalOrigin(); } else { UTIL_SetOrigin( this, m_vecPosition1 ); } // another hack: PhysX 2.8.4.0 crashed while trying to created kinematic body from this brush-model if ( FStrEq( STRING( gpGlobals->mapname ), "c2a5e" ) && FStrEq( STRING( pev->model ), "*103" )); else m_pUserData = WorldPhysic->CreateKinematicBodyFromEntity( this ); m_iState = STATE_OFF; // if the door is flagged for USE button activation only, use NULL touch function if( FBitSet( pev->spawnflags, SF_DOOR_USE_ONLY )) { SetTouch( NULL ); } else { // touchable button SetTouch( DoorTouch ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- float CalculatePhysicsImpactDamage( int index, gamevcollisionevent_t *pEvent, const impactdamagetable_t &table, float energyScale, bool allowStaticDamage, int &damageType, bool bDamageFromHeldObjects ) { damageType = DMG_CRUSH; int otherIndex = !index; // UNDONE: Expose a flag for self-inflicted damage? Can't think of a valid case so far. if ( pEvent->pEntities[0] == pEvent->pEntities[1] ) return 0; if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_NO_NPC_IMPACT_DMG ) { if( pEvent->pEntities[index]->IsNPC() || pEvent->pEntities[index]->IsPlayer() ) { return 0; } } // use implicit velocities on ragdolls since they may have high constraint velocities that aren't actually executed, just pushed through contacts if (( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_PART_OF_RAGDOLL) && pEvent->pEntities[index]->IsPlayer() ) { pEvent->pObjects[otherIndex]->GetImplicitVelocity( &pEvent->preVelocity[otherIndex], &pEvent->preAngularVelocity[otherIndex] ); } // Dissolving impact damage results in death always. if ( ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_DMG_DISSOLVE ) && !pEvent->pEntities[index]->IsEFlagSet(EFL_NO_DISSOLVE) ) { damageType |= DMG_DISSOLVE; return 1000; } if ( energyScale <= 0.0f ) return 0; const int gameFlagsNoDamage = FVPHYSICS_CONSTRAINT_STATIC | FVPHYSICS_NO_IMPACT_DMG; // NOTE: Crushing damage is handled by stress calcs in vphysics update functions, this is ONLY impact damage // this is a non-moving object due to a constraint - no damage if ( pEvent->pObjects[otherIndex]->GetGameFlags() & gameFlagsNoDamage ) return 0; // If it doesn't take damage from held objects and the object is being held - no damage if ( !bDamageFromHeldObjects && ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) ) { // If it doesn't take damage from held objects - no damage if ( !bDamageFromHeldObjects ) return 0; } if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_MULTIOBJECT_ENTITY ) { // UNDONE: Add up mass here for car wheels and prop_ragdoll pieces? IPhysicsObject *pList[VPHYSICS_MAX_OBJECT_LIST_COUNT]; int count = pEvent->pEntities[otherIndex]->VPhysicsGetObjectList( pList, ARRAYSIZE(pList) ); for ( int i = 0; i < count; i++ ) { if ( pList[i]->GetGameFlags() & gameFlagsNoDamage ) return 0; } } if ( pEvent->pObjects[index]->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) { // players can't damage held objects if ( pEvent->pEntities[otherIndex]->IsPlayer() ) return 0; allowStaticDamage = false; } #if 0 { PhysGetDamageInflictorVelocityStartOfFrame( pEvent->pObjects[otherIndex], pEvent->preVelocity[otherIndex], pEvent->preAngularVelocity[otherIndex] ); } #endif float otherSpeedSqr = pEvent->preVelocity[otherIndex].LengthSqr(); float otherAngSqr = 0; // factor in angular for sharp objects if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_DMG_SLICE ) { otherAngSqr = pEvent->preAngularVelocity[otherIndex].LengthSqr(); } float otherMass = pEvent->pObjects[otherIndex]->GetMass(); if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) { // if the player is holding the object, use its real mass (player holding reduced the mass) CBasePlayer *pPlayer = NULL; if ( gpGlobals->maxClients == 1 ) { pPlayer = UTIL_GetLocalPlayer(); } else { // See which MP player is holding the physics object and then use that player to get the real mass of the object. // This is ugly but better than having linkage between an object and its "holding" player. for ( int i = 1; i <= gpGlobals->maxClients; i++ ) { CBasePlayer *tempPlayer = UTIL_PlayerByIndex( i ); if ( tempPlayer && pEvent->pEntities[index] == tempPlayer->GetHeldObject() ) { pPlayer = tempPlayer; break; } } } if ( pPlayer ) { otherMass = pPlayer->GetHeldObjectMass( pEvent->pObjects[otherIndex] ); } } // NOTE: sum the mass of each object in this system for the purpose of damage if ( pEvent->pEntities[otherIndex] && (pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_MULTIOBJECT_ENTITY) ) { otherMass = PhysGetEntityMass( pEvent->pEntities[otherIndex] ); } if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_HEAVY_OBJECT ) { otherMass = table.largeMassMin; if ( energyScale < 2.0f ) { energyScale = 2.0f; } } // UNDONE: allowStaticDamage is a hack - work out some method for // breakable props to impact the world and break!! if ( !allowStaticDamage ) { if ( otherMass < table.minMass ) return 0; // check to see if the object is small if ( otherMass < table.smallMassMax && otherSpeedSqr < table.smallMassMinSpeedSqr ) return 0; if ( otherSpeedSqr < table.minSpeedSqr && otherAngSqr < table.minRotSpeedSqr ) return 0; } // Add extra oomph for floating objects if ( pEvent->pEntities[index]->IsFloating() && !pEvent->pEntities[otherIndex]->IsWorld() ) { if ( energyScale < 3.0f ) { energyScale = 3.0f; } } float damage = 0; bool bDebug = false;//(&table == &gDefaultPlayerImpactDamageTable); // don't ever take spin damage from slowly spinning objects if ( otherAngSqr > table.minRotSpeedSqr ) { Vector otherInertia = pEvent->pObjects[otherIndex]->GetInertia(); float angularMom = DotProductAbs( otherInertia, pEvent->preAngularVelocity[otherIndex] ); damage = ReadDamageTable( table.angularTable, table.angularCount, angularMom * energyScale, bDebug ); if ( damage > 0 ) { // Msg("Spin : %.1f, Damage %.0f\n", FastSqrt(angularMom), damage ); damageType |= DMG_SLASH; } } float deltaV = pEvent->preVelocity[index].Length() - pEvent->postVelocity[index].Length(); float mass = pEvent->pObjects[index]->GetMass(); // If I lost speed, and I lost less than min velocity, then filter out this energy if ( deltaV > 0 && deltaV < table.myMinVelocity ) { deltaV = 0; } float eliminatedEnergy = deltaV * deltaV * mass; deltaV = pEvent->preVelocity[otherIndex].Length() - pEvent->postVelocity[otherIndex].Length(); float otherEliminatedEnergy = deltaV * deltaV * otherMass; // exaggerate the effects of really large objects if ( otherMass >= table.largeMassMin ) { otherEliminatedEnergy *= table.largeMassScale; float dz = pEvent->preVelocity[otherIndex].z - pEvent->postVelocity[otherIndex].z; if ( deltaV > 0 && dz < 0 && pEvent->preVelocity[otherIndex].z < 0 ) { float factor = fabs(dz / deltaV); otherEliminatedEnergy *= (1 + factor * (table.largeMassFallingScale - 1.0f)); } } eliminatedEnergy += otherEliminatedEnergy; // now in units of this character's speed squared float invMass = pEvent->pObjects[index]->GetInvMass(); if ( !pEvent->pObjects[index]->IsMoveable() ) { // inv mass is zero, but impact damage is enabled on this // prop, so recompute: invMass = 1.0f / pEvent->pObjects[index]->GetMass(); } else if ( pEvent->pObjects[index]->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) { // if the player is holding the object, use it's real mass (player holding reduced the mass) CBasePlayer *pPlayer = NULL; if ( gpGlobals->maxClients == 1 ) { pPlayer = UTIL_GetLocalPlayer(); } else { // See which MP player is holding the physics object and then use that player to get the real mass of the object. // This is ugly but better than having linkage between an object and its "holding" player. for ( int i = 1; i <= gpGlobals->maxClients; i++ ) { CBasePlayer *tempPlayer = UTIL_PlayerByIndex( i ); if ( tempPlayer && pEvent->pEntities[index] == tempPlayer->GetHeldObject() ) { pPlayer = tempPlayer; break; } } } if ( pPlayer ) { float mass = pPlayer->GetHeldObjectMass( pEvent->pObjects[index] ); if ( mass > 0 ) { invMass = 1.0f / mass; } } } eliminatedEnergy *= invMass * energyScale; damage += ReadDamageTable( table.linearTable, table.linearCount, eliminatedEnergy, bDebug ); if ( !pEvent->pObjects[otherIndex]->IsStatic() && otherMass < table.smallMassMax && table.smallMassCap > 0 ) { damage = clamp( damage, 0.f, table.smallMassCap ); } return damage; }
void CBaseButton::Spawn( ) { //---------------------------------------------------- //determine sounds for buttons //a sound of 0 should not make a sound //---------------------------------------------------- if ( m_sounds ) { m_sNoise = MakeButtonSound( m_sounds ); PrecacheScriptSound(m_sNoise.ToCStr()); } else { m_sNoise = NULL_STRING; } Precache(); if ( HasSpawnFlags( SF_BUTTON_SPARK_IF_OFF ) )// this button should spark in OFF state { SetThink ( &CBaseButton::ButtonSpark ); SetNextThink( gpGlobals->curtime + 0.5f );// no hurry, make sure everything else spawns } // Convert movedir from angles to a vector QAngle angMoveDir = QAngle( m_vecMoveDir.x, m_vecMoveDir.y, m_vecMoveDir.z ); AngleVectors( angMoveDir, &m_vecMoveDir ); SetMoveType( MOVETYPE_PUSH ); SetSolid( SOLID_BSP ); SetModel( STRING( GetModelName() ) ); if (m_flSpeed == 0) { m_flSpeed = 40; } m_takedamage = DAMAGE_YES; if (m_flWait == 0) { m_flWait = 1; } if (m_flLip == 0) { m_flLip = 4; } m_toggle_state = TS_AT_BOTTOM; m_vecPosition1 = GetLocalOrigin(); // Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big Vector vecButtonOBB = CollisionProp()->OBBSize(); vecButtonOBB -= Vector( 2, 2, 2 ); m_vecPosition2 = m_vecPosition1 + (m_vecMoveDir * (DotProductAbs( m_vecMoveDir, vecButtonOBB ) - m_flLip)); // Is this a non-moving button? if ( ((m_vecPosition2 - m_vecPosition1).Length() < 1) || HasSpawnFlags(SF_BUTTON_DONTMOVE) ) { m_vecPosition2 = m_vecPosition1; } m_fStayPushed = (m_flWait == -1 ? TRUE : FALSE); m_fRotating = FALSE; if (HasSpawnFlags(SF_BUTTON_LOCKED)) { m_bLocked = true; } // // If using activates the button, set its use function. // if (HasSpawnFlags(SF_BUTTON_USE_ACTIVATES)) { SetUse(&CBaseButton::ButtonUse); } else { SetUse(NULL); } // // If touching activates the button, set its touch function. // if (HasSpawnFlags(SF_BUTTON_TOUCH_ACTIVATES)) { SetTouch( &CBaseButton::ButtonTouch ); } else { SetTouch ( NULL ); } CreateVPhysics(); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CBaseDoor::Spawn() { Precache(); #ifdef HL1_DLL SetSolid( SOLID_BSP ); #else if ( GetMoveParent() && GetRootMoveParent()->GetSolid() == SOLID_BSP ) { SetSolid( SOLID_BSP ); } else { SetSolid( SOLID_VPHYSICS ); } #endif // Convert movedir from angles to a vector QAngle angMoveDir = QAngle( m_vecMoveDir.x, m_vecMoveDir.y, m_vecMoveDir.z ); AngleVectors( angMoveDir, &m_vecMoveDir ); SetModel( STRING( GetModelName() ) ); m_vecPosition1 = GetLocalOrigin(); // Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big Vector vecOBB = CollisionProp()->OBBSize(); vecOBB -= Vector( 2, 2, 2 ); m_vecPosition2 = m_vecPosition1 + (m_vecMoveDir * (DotProductAbs( m_vecMoveDir, vecOBB ) - m_flLip)); if ( !IsRotatingDoor() ) { if ( ( m_eSpawnPosition == FUNC_DOOR_SPAWN_OPEN ) || HasSpawnFlags( SF_DOOR_START_OPEN_OBSOLETE ) ) { // swap pos1 and pos2, put door at pos2 UTIL_SetOrigin( this, m_vecPosition2); m_toggle_state = TS_AT_TOP; } else { m_toggle_state = TS_AT_BOTTOM; } } if (HasSpawnFlags(SF_DOOR_LOCKED)) { m_bLocked = true; } SetMoveType( MOVETYPE_PUSH ); if (m_flSpeed == 0) { m_flSpeed = 100; } SetTouch( &CBaseDoor::DoorTouch ); if ( !FClassnameIs( this, "func_water" ) ) { if ( HasSpawnFlags(SF_DOOR_PASSABLE) ) { //normal door AddEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID ); AddSolidFlags( FSOLID_NOT_SOLID ); } if ( HasSpawnFlags( SF_DOOR_NONSOLID_TO_PLAYER ) ) { SetCollisionGroup( COLLISION_GROUP_PASSABLE_DOOR ); // HACKHACK: Set this hoping that any children of the door that get blocked by the player // will get fixed up by vphysics // NOTE: We could decouple this as a separate behavior, but managing player collisions is already complex enough. // NOTE: This is necessary to prevent the player from blocking the wrecked train car in ep2_outland_01 AddFlag( FL_UNBLOCKABLE_BY_PLAYER ); } if ( m_bIgnoreDebris ) { // both of these flags want to set the collision group and // there isn't a combo group Assert( !HasSpawnFlags( SF_DOOR_NONSOLID_TO_PLAYER ) ); if ( HasSpawnFlags( SF_DOOR_NONSOLID_TO_PLAYER ) ) { Warning("Door %s with conflicting collision settings, removing ignoredebris\n", GetDebugName() ); } else { SetCollisionGroup( COLLISION_GROUP_INTERACTIVE ); } } } if ( ( m_eSpawnPosition == FUNC_DOOR_SPAWN_OPEN ) && HasSpawnFlags( SF_DOOR_START_OPEN_OBSOLETE ) ) { Warning("Door %s using obsolete 'Start Open' spawnflag with 'Spawn Position' set to 'Open'. Reverting to old behavior.\n", GetDebugName() ); } CreateVPhysics(); }
/* ==================== HullForStudio NOTE: pEdict may be NULL ==================== */ hull_t *Mod_HullForStudio( model_t *model, float frame, int sequence, vec3_t angles, vec3_t origin, vec3_t size, byte *pcontroller, byte *pblending, int *numhitboxes, edict_t *pEdict ) { vec3_t angles2; mstudiocache_t *bonecache; mstudiobbox_t *phitbox; int i, j; ASSERT( numhitboxes ); *numhitboxes = 0; // assume error if( mod_studiocache->integer ) { bonecache = Mod_CheckStudioCache( model, frame, sequence, angles, origin, size, pcontroller, pblending ); if( bonecache != NULL ) { Q_memcpy( studio_planes, &cache_planes[bonecache->current_plane], bonecache->numhitboxes * sizeof( mplane_t ) * 6 ); Q_memcpy( studio_hull_hitgroup, &cache_hull_hitgroup[bonecache->current_hull], bonecache->numhitboxes * sizeof( uint )); Q_memcpy( studio_hull, &cache_hull[bonecache->current_hull], bonecache->numhitboxes * sizeof( hull_t )); *numhitboxes = bonecache->numhitboxes; return studio_hull; } } mod_studiohdr = Mod_Extradata( model ); if( !mod_studiohdr ) return NULL; // probably not a studiomodel ASSERT( pBlendAPI != NULL ); VectorCopy( angles, angles2 ); if( !( host.features & ENGINE_COMPENSATE_QUAKE_BUG )) angles2[PITCH] = -angles2[PITCH]; // stupid quake bug pBlendAPI->SV_StudioSetupBones( model, frame, sequence, angles2, origin, pcontroller, pblending, -1, pEdict ); phitbox = (mstudiobbox_t *)((byte *)mod_studiohdr + mod_studiohdr->hitboxindex); for( i = j = 0; i < mod_studiohdr->numhitboxes; i++, j += 6 ) { studio_hull_hitgroup[i] = phitbox[i].group; Mod_SetStudioHullPlane( &studio_planes[j+0], phitbox[i].bone, 0, phitbox[i].bbmax[0] ); Mod_SetStudioHullPlane( &studio_planes[j+1], phitbox[i].bone, 0, phitbox[i].bbmin[0] ); Mod_SetStudioHullPlane( &studio_planes[j+2], phitbox[i].bone, 1, phitbox[i].bbmax[1] ); Mod_SetStudioHullPlane( &studio_planes[j+3], phitbox[i].bone, 1, phitbox[i].bbmin[1] ); Mod_SetStudioHullPlane( &studio_planes[j+4], phitbox[i].bone, 2, phitbox[i].bbmax[2] ); Mod_SetStudioHullPlane( &studio_planes[j+5], phitbox[i].bone, 2, phitbox[i].bbmin[2] ); studio_planes[j+0].dist += DotProductAbs( studio_planes[j+0].normal, size ); studio_planes[j+1].dist -= DotProductAbs( studio_planes[j+1].normal, size ); studio_planes[j+2].dist += DotProductAbs( studio_planes[j+2].normal, size ); studio_planes[j+3].dist -= DotProductAbs( studio_planes[j+3].normal, size ); studio_planes[j+4].dist += DotProductAbs( studio_planes[j+4].normal, size ); studio_planes[j+5].dist -= DotProductAbs( studio_planes[j+5].normal, size ); } // tell trace code about hitbox count *numhitboxes = mod_studiohdr->numhitboxes; if( mod_studiocache->integer ) { Mod_AddToStudioCache( frame, sequence, angles, origin, size, pcontroller, pblending, model, studio_hull, *numhitboxes ); } return studio_hull; }