public static void lua_AddEntityRagdoll(int entID, int setupIndex) { var ent = EngineWorld.GetEntityByID((uint)entID); if (ent != null) { var ragdollSetup = new RDSetup(); if (!ragdollSetup.GetSetup(setupIndex)) { ConsoleInfo.Instance.Warning(SYSWARN_NO_RAGDOLL_SETUP, setupIndex); } else { if (!ent.CreateRagdoll(ragdollSetup)) { ConsoleInfo.Instance.Warning(SYSWARN_CANT_CREATE_RAGDOLL, entID); } } } else { ConsoleInfo.Instance.Warning(SYSWARN_NO_ENTITY, entID); } }
public bool CreateRagdoll(RDSetup setup) { // No entity, setup or body count overflow - bypass function. if (setup == null || setup.BodySetup.Count > Bf.BoneTags.Count) { return false; } var result = true; // If ragdoll already exists, overwrite it with new one. if (Bt.BtJoints.Count > 0) { result = DeleteRagdoll(); } // Setup bodies. Bt.BtJoints.Clear(); // update current character animation and full fix body to avoid starting ragdoll partially inside the wall or floor... UpdateCurrentBoneFrame(Bf, Transform); Bt.NoFixAll = false; Bt.NoFixBodyParts = 0x00000000; #if NOPE int map_size = m_bf.animations.model->collision_map.size(); // does not works, strange... m_bf.animations.model->collision_map.size() = m_bf.animations.model->mesh_count; fixPenetrations(nullptr); m_bf.animations.model->collision_map.size() = map_size; #else FixPenetrations(Vector3.Zero); #endif for(var i = 0; i < setup.BodySetup.Count; i++) { // TODO: First check useless? if(i >= Bf.BoneTags.Count || Bt.BtBody[i] == null) { result = false; continue; // If body is absent, return false and bypass this body setup. } var inertia = BulletSharp.Math.Vector3.Zero; var mass = setup.BodySetup[i].Mass; BtEngineDynamicsWorld.RemoveRigidBody(Bt.BtBody[i]); Bt.BtBody[i].CollisionShape.CalculateLocalInertia(mass, out inertia); Bt.BtBody[i].SetMassProps(mass, inertia); Bt.BtBody[i].UpdateInertiaTensor(); Bt.BtBody[i].ClearForces(); Bt.BtBody[i].LinearFactor = BulletSharp.Math.Vector3.One; Bt.BtBody[i].AngularFactor = BulletSharp.Math.Vector3.One; Bt.BtBody[i].SetDamping(setup.BodySetup[i].Damping[0], setup.BodySetup[i].Damping[1]); Bt.BtBody[i].Restitution = setup.BodySetup[i].Restitution; Bt.BtBody[i].Friction = setup.BodySetup[i].Friction; Bt.BtBody[i].SetSleepingThresholds(RD_DEFAULT_SLEEPING_THRESHOLD, RD_DEFAULT_SLEEPING_THRESHOLD); if(Bf.BoneTags[i].Parent == null) { var r = GetInnerBBRadius(Bf.BoneTags[i].MeshBase.BBMin, Bf.BoneTags[i].MeshBase.BBMax); Bt.BtBody[i].CcdMotionThreshold = 0.8f * r; Bt.BtBody[i].CcdSweptSphereRadius = r; } } UpdateRigidBody(true); for(var i = 0; i < Bf.BoneTags.Count; i++) { BtEngineDynamicsWorld.AddRigidBody(Bt.BtBody[i]); Bt.BtBody[i].Activate(); Bt.BtBody[i].LinearVelocity = Speed.ToBullet(); if (i < Bt.GhostObjects.Count && Bt.GhostObjects[i] != null) { BtEngineDynamicsWorld.RemoveCollisionObject(Bt.GhostObjects[i]); BtEngineDynamicsWorld.AddCollisionObject(Bt.GhostObjects[i], CollisionFilterGroups.None, CollisionFilterGroups.None); } } // Setup constraints. Bt.BtJoints.Resize(setup.JointSetup.Count); for(var i = 0; i < setup.JointSetup.Count; i++) { if(setup.JointSetup[i].BodyIndex >= Bf.BoneTags.Count || Bt.BtBody[setup.JointSetup[i].BodyIndex] == null) { result = false; break; // If body 1 or body 2 are absent, return false and bypass this joint. } var localA = new Transform(); var localB = new Transform(); var btB = Bf.BoneTags[setup.JointSetup[i].BodyIndex]; var btA = btB.Parent; if(btA == null) { result = false; break; } #if NOPE localA.setFromOpenGLMatrix(btB->transform); localB.setIdentity(); #else Helper.SetEulerZYX(ref localA.Basis, setup.JointSetup[i].Body1Angle); //localA.Origin = setup.JointSetup[i].Body1Offset; localA.Origin = btB.Transform.Origin; Helper.SetEulerZYX(ref localB.Basis, setup.JointSetup[i].Body2Angle); //localB.Origin = setup.JointSetup[i].Body2Offset; localB.Origin = Vector3.Zero; #endif switch(setup.JointSetup[i].JointType) { case RDJointSetup.Type.Point: Bt.BtJoints[i] = new Point2PointConstraint(Bt.BtBody[btA.Index], Bt.BtBody[btB.Index], localA.Origin.ToBullet(), localB.Origin.ToBullet()); break; case RDJointSetup.Type.Hinge: var hingeC = new HingeConstraint(Bt.BtBody[btA.Index], Bt.BtBody[btB.Index], ((Matrix4) localA).ToBullet(), ((Matrix4) localB).ToBullet()); hingeC.SetLimit(setup.JointSetup[i].JointLimit[0], setup.JointSetup[i].JointLimit[1], 0.9f, 0.3f, 0.3f); Bt.BtJoints[i] = hingeC; break; case RDJointSetup.Type.Cone: var coneC = new ConeTwistConstraint(Bt.BtBody[btA.Index], Bt.BtBody[btB.Index], ((Matrix4)localA).ToBullet(), ((Matrix4)localB).ToBullet()); coneC.SetLimit(setup.JointSetup[i].JointLimit[0], setup.JointSetup[i].JointLimit[1], setup.JointSetup[i].JointLimit[2], 0.9f, 0.3f, 0.7f); Bt.BtJoints[i] = coneC; break; } Bt.BtJoints[i].SetParam(ConstraintParam.StopCfm, setup.JointCfm, -1); Bt.BtJoints[i].SetParam(ConstraintParam.StopErp, setup.JointErp, -1); Bt.BtJoints[i].DebugDrawSize = 64.0f; BtEngineDynamicsWorld.AddConstraint(Bt.BtJoints[i], true); } if(!result) { DeleteRagdoll(); // PARANOID: Clean up the mess, if something went wrong. } else { TypeFlags |= ENTITY_TYPE.Dynamic; } return result; }