Code:
const char szTires[][64] = {"models/props_vehicles/tire001c_car.mdl",
"models/props_vehicles/apc_tire001.mdl",
"models/props_vehicles/tire001a_tractor.mdl",
"models/props_wasteland/wheel01a.mdl",
"models/props_wasteland/wheel02a.mdl"};
...
////MAKE WHEEL////
CBaseEntity *pProp = NULL;
pProp = CreateEntityByName( "prop_physics_multiplayer" );
if(!pProp)
{
SayTextChatHud(UTIL_VarArgs("[%s] Spawn failure.\n", pAdminOP.adminname));
return PLUGIN_STOP;
}
QAngle angles;
VectorAngles(tr.plane.normal, angles);
VFuncs::KeyValue(pProp, "model", szTires[wheel] );
VFuncs::KeyValue(pProp, "spawnflags", "256" );
VFuncs::KeyValue(pProp, "physdamagescale", "0.1" );
VFuncs::KeyValue(pProp, "ExplodeDamage", "0" );
VFuncs::KeyValue(pProp, "ExplodeRadius", "0" );
VFuncs::Spawn(pProp);
VFuncs::Activate(pProp);
VFuncs::SetModel( pProp, szTires[wheel] );
//////////////////
////GET SIZE////
int i = modelinfo->GetModelIndex( szTires[wheel] );
if ( i < 0 )
{
SayTextChatHud(UTIL_VarArgs("[%s] Wheel not precached.\n", pAdminOP.adminname));
return PLUGIN_STOP;
}
const model_t *mod = modelinfo->GetModel( i );
if ( !mod )
{
SayTextChatHud(UTIL_VarArgs("[%s] Wheel has no model_t. This is an engine error.\n", pAdminOP.adminname));
return PLUGIN_STOP;
}
modelinfo->GetModelBounds( mod, mins, maxs );
VectorSubtract( maxs, mins, vecSize );
////////////////
if(wheel < 3)
{
VFuncs::Teleport(pProp, &(tr.endpos + (tr.plane.normal * (vecSize.x/2))), &angles, NULL );
}
else
{
matrix3x4_t m_rgflCoordinateFrame;
Vector vecorigin = tr.endpos + tr.plane.normal * (maxs.y - (mins.y + maxs.y));
VFuncs::Teleport(pProp, &vecorigin, &angles, NULL );
/////////////ROTATE WHEELS THAT FACE WRONG DIRECTION/////////
const float rotationAngle = -90;
// calculate coordinate frame so that we don't have to use EntityToWorldTransform()
AngleMatrix( angles, vecorigin, m_rgflCoordinateFrame );
// compute rotation axis in entity local space
// compute the transform as a matrix so we can concatenate it with the entity's current transform
Vector rotationAxisLs = Vector(0,0,1);
// build a transform that rotates around that axis in local space by the angle
// if there were an AxisAngleMatrix() routine we could use that directly, but there isn't
// so convert to a quaternion first, then a matrix
Quaternion q;
// NOTE: assumes axis is a unit vector, non-unit vectors will bias the resulting rotation angle (but not the axis)
AxisAngleQuaternion( rotationAxisLs, rotationAngle, q );
// convert to a matrix
matrix3x4_t xform;
QuaternionMatrix( q, vec3_origin, xform );
// apply the rotation to the entity input space (local)
matrix3x4_t localToWorldMatrix;
ConcatTransforms( m_rgflCoordinateFrame, xform, localToWorldMatrix );
// extract the compound rotation as a QAngle
QAngle localAngles;
MatrixAngles( localToWorldMatrix, localAngles );
/////////END ROTATE WHEELS THAT FACE WRONG DIRECTION/////////
VFuncs::SetAbsAngles(pProp, localAngles);
}
spawnedEnts.AddToTail(VFuncs::entindex(pProp));
pAdminOP.spawnedServerEnts.AddToTail(VFuncs::entindex(pProp));
//////////////////
//////ADD HINGE//////////
IPhysicsConstraint *m_pConstraint;
IPhysicsObject *pReference = VFuncs::VPhysicsGetObject(pSet);
IPhysicsObject *pAttached = VFuncs::VPhysicsGetObject(pProp);
if ( !pReference || !pAttached )
{
return PLUGIN_STOP;
}
constraint_hingeparams_t hinged;
hinged.Defaults();
hinged.worldPosition = tr.endpos;
hinged.worldAxisDirection = tr.plane.normal;
m_pConstraint = physenv->CreateHingeConstraint( pReference, pAttached, NULL, hinged );
////////////////////////////
pConstraint = m_pConstraint;
if(pConstraint)
{
physConstraints.AddToTail(pConstraint);
SayTextChatHud(UTIL_VarArgs("[%s] Wheel added to ent %i. New ent = %i with constraint ID %i\n", pAdminOP.adminname, VFuncs::entindex(pSet), VFuncs::entindex(pProp), physConstraints.Tail()));
}
else
{
SayTextChatHud(UTIL_VarArgs("[%s] Unable to add constraint.\n", pAdminOP.adminname));
}
Hopefully this is useful. You should be able to take the important parts and make it work in a SourceMod extension/plugin.