TacoServer/Classic/scripts/autoexec/flagTunnelingFix.cs

297 lines
12 KiB
C#
Raw Normal View History

2024-03-31 23:31:48 +00:00
//Fixes for collision tunneling among other flag issues, note only works in classic ctf game types
//Script By:DarkTiger
2024-10-19 19:10:31 +00:00
//V2.1
$ftEnable = 1;//disables all
2024-03-31 23:31:48 +00:00
$limitFlagCalls = 1; // prevents frame perfect events witch can cause bad outcomes
2024-10-19 19:10:31 +00:00
$antiCeiling = 1; // note this is auto enabled with $boxStuckFix as it needs to check for this
$antiTerTunnel = 0;//prevents terrain tunneling keeps the flag above the terrain leave this off unless you think its a problem
2024-03-31 23:31:48 +00:00
$antiFlagImpluse = 1000;//time out period to prevent explosions from effecting flags on drop/toss
2024-10-19 19:10:31 +00:00
$boxStuckFix = 1;
2024-03-31 23:31:48 +00:00
2024-10-19 19:10:31 +00:00
//best to leave these values alone unless you understand what the code is doing
$flagSimTime = 60;//note a higher the time, the larger the sweep scans will be
$flagCheckRadius = 50;
$playerBoxA = "-0.6 -0.6 0";
$playerBoxB = "0.6 0.6 2.3";
2024-10-19 19:10:31 +00:00
$flagStuckTime = 1000;
$flagSimRate = 30;
$tickDelay = 1; //delay the sim by 1 ticks in case its not needed
function flagSim(%flag,%player){
%bypassBoxCheck = 0;// debug sim
//%mass = 80;// not needed
%bounceFriction = 0.6;
%bounceElasticity = 0.2;
%drag = 0.5;
%simRate = $flagSimRate;
%timeFrame = mFloor(1000 / %simRate);
%dt = %timeFrame / 1000;
%Box2 = %flag.getWorldBox();
%Box1 = %player.getWorldBox();
if(!%flag.isHome && !isObject(%flag.carrier)){
if((boxIntersect(%Box1, %Box2) || %bypassBoxCheck) && vectorLen(%flag.finalVel) > 1 && %flag.countsim < 32){
%flag.setVelocity("0 0 0");// keep it zeroed out
%xform = %flag.getTransform();
%oldPos = getWords(%xform,0,2);// we dont use lastSimPos here as it will be fighting the engine too much instead we use it in the raycast
%flag.finalVel = vectorAdd(%flag.finalVel, "0 0" SPC (getGravity() * 1) * %dt);// engine adds its gravity so... prob not needed
%flag.finalVel = vectorSub(%flag.finalVel, vectorScale(%flag.finalVel, %drag * %dt));
%newPos = vectorAdd(%oldPos, vectorScale(%flag.finalVel,%dt));
%mask = $TypeMasks::InteriorObjectType | $TypeMasks::StaticTSObjectType | $TypeMasks::TerrainObjectType;//$TypeMasks::ForceFieldObjectType
%movRayB = containerRayCast(%flag.lastSimPos, %newPos, %mask, %flag);
%movRayT = containerRayCast(vectorAdd(%flag.lastSimPos,"0 0 2.4"), vectorAdd(%newPos,"0 0 2.4"), %mask, %flag);
if(%movRayB){
%hitRay = %movRayB;
}
if(%movRayT){
%hitRay = getWord(%movRayT,0) SPC %oldPos SPC getWords(%movRayT,4,6);
}
if(%hitRay){
%normal = getWords(%hitRay, 4, 6);
// Reflect the velocity around the surface normal
%reflectedVel = vectorSub(%flag.finalVel, vectorScale(%normal, vectorDot(%flag.finalVel, %normal) * 2.0));
// Calculate the tangent component for surface friction
%tangent = vectorSub(%reflectedVel, vectorScale(%normal, vectorDot(%reflectedVel, %normal)));
// Apply surface friction
%bounceVel = vectorSub(%reflectedVel, vectorScale(%tangent, %bounceFriction));
// Apply elasticity to modulate the speed of the bounce
%flag.finalVel = vectorScale(%bounceVel, %bounceElasticity);
// Adjust the new position to the point of impact plus a small offset along the normal
%newPos = vectorAdd(getWords(%hitRay, 1, 3), vectorScale(%normal, 0.05));
}
%flag.lastSimPos = %newPos;// we do this so theres no gaps in are sim other wise it could end up underground
%flag.setTransform(%newPos SPC getWords(%xform,3,6));
//%flag.setVelocity(%flag.finalVel);
%flag.countsim++;
schedule(%timeFrame,0,"flagSim",%flag,%player);
}
else{
//error("simCount" SPC %flag.countsim SPC vectorLen(%flag.finalVel));
if(vectorLen(%flag.finalVel) && %flag.countsim > 0){
%flag.setVelocity(%flag.finalVel);
}
}
}
}
function delayStartFlag(%obj,%this){
%obj.countsim = 0;
%obj.lastSimPos = %obj.getPosition();
%drag = 0.5;
%dt = mFloor(1000 / $flagSimRate) / 1000;
for(%i = 0; %i < $tickDelay; %i++){
%obj.finalVel = vectorSub(%obj.finalVel, vectorScale(%obj.finalVel, %drag * %dt));
}
flagSim(%obj,%this);
}
package flagFix{
2024-10-19 19:10:31 +00:00
function ShapeBase::throwObject(%this,%obj){
parent::throwObject(%this,%obj);
%data = %obj.getDatablock();
if(%data.getName() $= "Flag"){
%fpos = %obj.getPosition();
if($boxStuckFix){
%obj.finalVel = %obj.getVelocity();
%upRay = containerRayCast(vectorAdd(%fpos,"0 0 0.1"), vectorAdd(%fpos,"0 0 2.5"), $TypeMasks::InteriorObjectType | $TypeMasks::StaticTSObjectType | $TypeMasks::ForceFieldObjectType, %obj);
if(%upRay){
%dist = vectorDist(%fpos,getWords(%upRay,1,3));
%obj.setTransform(vectorSub(%fpos,"0 0" SPC (2.6 - %dist)) SPC getWords(%obj.getTransform(), 3, 6));
error("Ceiling" SPC %dist);
}
%wallRay = containerRayCast(%fpos, VectorAdd(%fpos, VectorScale(%this.getForwardVector(), 2)), $TypeMasks::InteriorObjectType | $TypeMasks::StaticTSObjectType | $TypeMasks::ForceFieldObjectType, %obj);
if(!%wallRay){
schedule($tickDelay * mFloor(1000 / $flagSimRate),0,"delayStartFlag",%obj,%this);
}
}
else if($antiCeiling){
//0.1 offset any fp errors with the flag position being at ground level, 2.4 offset flag height offset + some extra
%upRay = containerRayCast(vectorAdd(%fpos,"0 0 0.1"), vectorAdd(%fpos,"0 0 2.5"), $TypeMasks::InteriorObjectType | $TypeMasks::StaticTSObjectType | $TypeMasks::ForceFieldObjectType, %obj);
if(%upRay){
%dist = vectorDist(%fpos,getWords(%upRay,1,3));
%obj.setTransform(vectorSub(%fpos,"0 0" SPC (2.6 - %dist)) SPC getWords(%obj.getTransform(), 3, 6));
//error("bump2");
}
}
}
}
function CTFGame::startFlagCollisionSearch(%game, %flag){
parent::startFlagCollisionSearch(%game, %flag);
if((getSimTime() - %game.fcs) >= $flagSimTime && $ftEnable){
%game.flagColTest(%flag);
%game.fcs = getSimTime();
}
}
function SCtFGame::startFlagCollisionSearch(%game, %flag){
parent::startFlagCollisionSearch(%game, %flag);
if((getSimTime() - %game.fcs) >= $flagSimTime && $ftEnable){
%game.flagColTest(%flag);
%game.fcs = getSimTime();
}
}
function PracticeCTFGame::startFlagCollisionSearch(%game, %flag){
parent::startFlagCollisionSearch(%game, %flag);
if((getSimTime() - %game.fcs) >= $flagSimTime && $ftEnable){
%game.flagColTest(%flag);
%game.fcs = getSimTime();
}
}
function CTFGame::startMatch(%game){
parent::startMatch(%game);
if(!isEventPending(Game.flagLoop)){
%game.atHomeFlagLoop();
}
2023-03-24 17:28:19 +00:00
%game.fcs = getSimTime();
}
function SCtFGame::startMatch(%game){
parent::startMatch(%game);
if(!isEventPending(Game.flagLoop)){
%game.atHomeFlagLoop();
}
%game.fcs = getSimTime();
}
function PracticeCTFGame::startMatch(%game){
parent::startMatch(%game);
if(!isEventPending(Game.flagLoop)){
%game.atHomeFlagLoop();
}
%game.fcs = getSimTime();
}
2024-03-31 23:31:48 +00:00
//prevents frame perfect flag touches witch can cause bad stuff to happen in ctf
function CTFGame::playerTouchFlag(%game, %player, %flag){
if(%flag.lastFlagCallms > 0 && $limitFlagCalls){
%timeDif = getSimTime() - %flag.lastFlagCallms;
2024-10-19 19:10:31 +00:00
if(%timeDif < 32){
return;
2024-03-31 23:31:48 +00:00
}
}
%flag.lastFlagCallms = getSimTime();
parent::playerTouchFlag(%game, %player, %flag);
}
2024-10-19 19:10:31 +00:00
2024-03-31 23:31:48 +00:00
function SCtFGame::playerTouchFlag(%game, %player, %flag){
if(%flag.lastFlagCallms > 0 && $limitFlagCalls){
%timeDif = getSimTime() - %flag.lastFlagCallms;
if(%timeDif < 32){
2024-10-19 19:10:31 +00:00
return;
2024-03-31 23:31:48 +00:00
}
}
%flag.lastFlagCallms = getSimTime();
parent::playerTouchFlag(%game, %player, %flag);
}
2024-10-19 19:10:31 +00:00
2024-03-31 23:31:48 +00:00
function PracticeCTFGame::playerTouchFlag(%game, %player, %flag){
if(%flag.lastFlagCallms > 0 && $limitFlagCalls){
%timeDif = getSimTime() - %flag.lastFlagCallms;
if(%timeDif < 32){
2024-10-19 19:10:31 +00:00
return;
2024-03-31 23:31:48 +00:00
}
}
%flag.lastFlagCallms = getSimTime();
parent::playerTouchFlag(%game, %player, %flag);
}
2024-10-19 19:10:31 +00:00
2024-03-31 23:31:48 +00:00
function CTFGame::playerDroppedFlag(%game, %player){
%flag = %player.holdingFlag;
%flag.lastDropTime = getSimTime();
parent::playerDroppedFlag(%game, %player);
}
2024-10-19 19:10:31 +00:00
2024-03-31 23:31:48 +00:00
function SCtFGame::playerDroppedFlag(%game, %player){
%flag = %player.holdingFlag;
%flag.lastDropTime = getSimTime();
parent::playerDroppedFlag(%game, %player);
}
2024-10-19 19:10:31 +00:00
2024-03-31 23:31:48 +00:00
function PracticeCTFGame::playerDroppedFlag(%game, %player){
%flag = %player.holdingFlag;
%flag.lastDropTime = getSimTime();
parent::playerDroppedFlag(%game, %player);
}
2024-10-19 19:10:31 +00:00
2024-03-31 23:31:48 +00:00
function Flag::shouldApplyImpulse(%data, %obj){
2024-10-19 19:10:31 +00:00
%val = parent::shouldApplyImpulse(%data, %obj);
//error("meow");
2024-03-31 23:31:48 +00:00
if($antiFlagImpluse > 0 && %val && %obj.lastDropTime > 0){
%time = getSimTime() - %obj.lastDropTime;
if(%time < $antiFlagImpluse){
2024-10-19 19:10:31 +00:00
%val = 0;
2024-03-31 23:31:48 +00:00
}
}
return %val;
}
};
activatePackage(flagFix);
function DefaultGame::flagColTest(%game, %flag){
2023-11-06 22:07:44 +00:00
//flag ceiling check
2024-03-31 23:31:48 +00:00
%curPos = %flag.getWorldBoxCenter();
2023-11-06 22:07:44 +00:00
if( !%flag.isHome ){
2024-03-31 23:31:48 +00:00
if($antiTerTunnel){
2024-10-19 19:10:31 +00:00
// anti flag tunneling on terrain
2024-03-31 23:31:48 +00:00
if(%flag.lastUpdate > 0 && (getSimTime() - %flag.lastUpdate) < 128){//make sure are last position is current
%terRay = containerRayCast(%flag.dtLastPos, %curPos, $TypeMasks::TerrainObjectType, %flag);
if(%terRay){
%curPos = vectorAdd(getWords(%terRay,1,3), "0 0 0.5");
%flag.setTransform(%curPos SPC getWords(%flag.getTransform(), 3, 6));
2023-11-06 22:07:44 +00:00
}
2023-03-24 17:28:19 +00:00
}
2024-03-31 23:31:48 +00:00
%flag.lastUpdate = getSimTime();
%flag.dtLastPos = %curPos;
2023-03-24 17:28:19 +00:00
}
}
2023-11-06 22:07:44 +00:00
////////////////////////////////////////////////////////////////////////////////
//flag collision check
%Box2 = %flag.getWorldBox();
2024-03-31 23:31:48 +00:00
InitContainerRadiusSearch( %curPos, $flagCheckRadius, $TypeMasks::PlayerObjectType);
while((%player = containerSearchNext()) != 0){
%playerPos = %player.getPosition();
if(%player.lastSim > 0 && (%player.getState() !$= "Dead")){// only check at speed
2024-03-31 23:31:48 +00:00
if((getSimTime() - %player.lastSim) <= 128){//make sure are last position is valid
%sweepCount = mFloor(vectorDist(%playerPos, %player.oldPos) + 1);
for(%i = 0; %i < %sweepCount; %i++){// sweep behind us to see if we should have hit something
%lerpPos = vectorLerp(%playerPos, %player.oldPos, (%i+1)/%sweepCount);//back sweep
%Box1 = vectorAdd($playerBoxA, %lerpPos) SPC vectorAdd($playerBoxB, %lerpPos);
if(boxIntersect(%Box1, %Box2)){
%flag.getDataBlock().onCollision(%flag, %player);
break;
}
}
}
}
%player.oldPos = %playerPos;
%player.lastSim = getSimTime();
}
2024-10-19 19:10:31 +00:00
}
function vectorLerp(%point1, %point2, %t) {
return vectorAdd(%point1, vectorScale(vectorSub(%point2, %point1), %t));
}
function boxIntersect(%a, %b){
return (getWord(%a, 0) <= getWord(%b, 3) && getWord(%a, 3) >= getWord(%b, 0)) &&
(getWord(%a, 1) <= getWord(%b, 4) && getWord(%a, 4) >= getWord(%b, 1)) &&
(getWord(%a, 2) <= getWord(%b, 5) && getWord(%a, 5) >= getWord(%b, 2));
}
function DefaultGame::atHomeFlagLoop(%game){
if($TeamFlag[1].isHome ){
%game.flagColTest($TeamFlag[1], 0);
}
if($TeamFlag[2].isHome){
%game.flagColTest($TeamFlag[2], 0);
}
%speed = ($HostGamePlayerCount - $HostGameBotCount > 0) ? $flagSimTime : 30000;
if(isObject(Game) && $missionRunning && $ftEnable)
%game.flagLoop = %game.schedule(%speed, "atHomeFlagLoop");
2024-10-19 19:10:31 +00:00
}