diff --git a/restoration/source410/BT/MECH.CPP b/restoration/source410/BT/MECH.CPP index fbe89f5b..3583acf4 100644 --- a/restoration/source410/BT/MECH.CPP +++ b/restoration/source410/BT/MECH.CPP @@ -1523,6 +1523,9 @@ void // Integrate position and commit the Origin to the world transform. //----------------------------------------------------------------------- // + Point3D + frame_start_position = localOrigin.linearPosition; + localOrigin.linearPosition.AddScaled( localOrigin.linearPosition, worldLinearVelocity, @@ -1590,6 +1593,94 @@ void } } + // + //----------------------------------------------------------------------- + // COLLISIONS -- the response half of the master performance's ground + // model (binary @4aa6cf-4aab0b). Walls block by FULL FRAME REJECTION, + // never by slide or climb: any blocking contact restores the + // start-of-frame position and zeroes the velocity. The crash itself + // HURTS -- the accumulated collision Damage is dispatched at OUR OWN + // mech, zone -1 (the cylinder lottery), which is what makes wall- + // grinding self-limiting. And a hard enough hit (|v|^2 > 40, the + // binary's @0x4ab184 threshold) staggers the mech: both gait channels + // bind the bump clip (slot 0x20) and recover to Standing at its end. + // + // Guarded on the collision assistant: the engine's GetCurrentCollisions + // walks it unchecked, and only the viewpoint mech gets one + // (StartCollisionAssistant, BTL4APP.CPP:409). + // + // STAGED deltas, named: the crushable-CulturalIcon sentinel (0.00123f + // -- the move stands, gyro crunch) needs the Mech::ProcessCollision + // override, a later increment; the gyro crunch feed itself is with it; + // and the collisionState audio push waits on the same override's + // contact accumulation. + //----------------------------------------------------------------------- + // + if ( + collisionAssistant != NULL && + GetCollisionVolumeCount() > 0 && + collisionVolume != NULL + ) + { + Vector3D + impact_velocity = worldLinearVelocity; + BoxedSolidCollisionList + *collisions = GetCurrentCollisions(); + Damage + collision_damage; + + if (collisions != NULL) + { + ProcessCollisionList( + collisions, time_slice, frame_start_position, + &collision_damage); + } + + if (collision_damage.damageAmount > 0.0f) + { + worldLinearVelocity = Vector3D(0.0f, 0.0f, 0.0f); + localOrigin.linearPosition = frame_start_position; + localToWorld = localOrigin; + MoveCollisionVolume(); + + Entity::TakeDamageMessage + crash( + Entity::TakeDamageMessageID, + sizeof(Entity::TakeDamageMessage), + GetEntityID(), + -1, + collision_damage + ); + Dispatch(&crash); + + Scalar + impact_squared = + impact_velocity.x * impact_velocity.x + + impact_velocity.y * impact_velocity.y + + impact_velocity.z * impact_velocity.z; + if ( + impact_squared > 40.0f && + animationClips[0x20] != ResourceDescription::NullResourceID && + legStateAlarm.GetLevel() != 0x20 + ) + { + SetLegAnimation(0x20); + SetBodyAnimation(0x20); + ForceUpdate(1); + ForceUpdate(0x20); + } + + if (getenv("BT_MECH_LOG")) + { + DEBUG_STREAM << "[crash] BLOCK dmg=" + << collision_damage.damageAmount + << " iv2=" << impact_squared + << (impact_squared > 40.0f ? " KNOCKDOWN" : "") + << endl << flush; + } + } + } + if (getenv("BT_MECH_LOG")) { static Scalar reportAccum = 0.0f;