mirror of
https://github.com/exogen/t2-mapper.git
synced 2026-01-19 20:25:01 +00:00
1031 lines
33 KiB
C#
1031 lines
33 KiB
C#
|
|
package TR2Game {
|
||
|
|
|
||
|
|
function Player::scriptKill(%player, %damageType)
|
||
|
|
{
|
||
|
|
if (%damageType == $DamageType::suicide ||
|
||
|
|
%damageType == $DamageType::RespawnAfterScoring ||
|
||
|
|
%damageType == 0)
|
||
|
|
{
|
||
|
|
%player.client.forceRespawn = true;
|
||
|
|
%player.client.inSpawnBuilding = true;
|
||
|
|
%player.knockedDown = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
Parent::scriptKill(%player, %damageType);
|
||
|
|
}
|
||
|
|
|
||
|
|
function Player::isAboveSomething(%player, %searchrange)
|
||
|
|
{
|
||
|
|
// Borrow some deployment code to determine whether the player is
|
||
|
|
// above something.
|
||
|
|
%mask = $TypeMasks::InteriorObjectType | $TypeMasks::StaticShapeObjectType | $TypeMasks::ForceFieldObjectType;
|
||
|
|
%eyeVec = "0 0 -1";//%player.getEyeVector();
|
||
|
|
%eyeTrans = %player.getEyeTransform();
|
||
|
|
// extract the position of the player's camera from the eye transform (first 3 words)
|
||
|
|
%eyePos = posFromTransform(%eyeTrans);
|
||
|
|
// normalize the eye vector
|
||
|
|
%nEyeVec = VectorNormalize(%eyeVec);
|
||
|
|
// scale (lengthen) the normalized eye vector according to the search range
|
||
|
|
%scEyeVec = VectorScale(%nEyeVec, %searchRange);
|
||
|
|
// add the scaled & normalized eye vector to the position of the camera
|
||
|
|
%eyeEnd = VectorAdd(%eyePos, %scEyeVec);
|
||
|
|
// see if anything gets hit
|
||
|
|
return containerRayCast(%eyePos, %eyeEnd, %mask, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
function ShapeBase::hasAmmo( %this, %weapon )
|
||
|
|
{
|
||
|
|
switch$ ( %weapon )
|
||
|
|
{
|
||
|
|
// TR2
|
||
|
|
case TR2Disc:
|
||
|
|
return( %this.getInventory( TR2DiscAmmo ) > 0 );
|
||
|
|
case TR2GrenadeLauncher:
|
||
|
|
return( %this.getInventory( TR2GrenadeLauncherAmmo ) > 0 );
|
||
|
|
case TR2Chaingun:
|
||
|
|
return( %this.getInventory( TR2ChaingunAmmo ) > 0);
|
||
|
|
case TR2Mortar:
|
||
|
|
return( %this.getInventory( TR2MortarAmmo ) > 0 );
|
||
|
|
case TR2Shocklance:
|
||
|
|
return( true );
|
||
|
|
case TR2GoldTargetingLaser:
|
||
|
|
return( false );
|
||
|
|
case TR2SilverTargetingLaser:
|
||
|
|
return( false );
|
||
|
|
default:
|
||
|
|
return Parent::hasAmmo(%this, %weapon);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function ShapeBase::clearInventory(%this)
|
||
|
|
{
|
||
|
|
// TR2
|
||
|
|
%this.setInventory(TR2Disc,0);
|
||
|
|
%this.setInventory(TR2GrenadeLauncher,0);
|
||
|
|
%this.setInventory(TR2Chaingun,0);
|
||
|
|
%this.setInventory(TR2Mortar,0);
|
||
|
|
%this.setInventory(TR2Shocklance,0);
|
||
|
|
%this.setInventory(TR2GoldTargetingLaser,0);
|
||
|
|
%this.setInventory(TR2SilverTargetingLaser,0);
|
||
|
|
%this.setInventory(TR2DiscAmmo,0);
|
||
|
|
%this.setInventory(TR2GrenadeLauncherAmmo,0);
|
||
|
|
%this.setInventory(TR2MortarAmmo, 0);
|
||
|
|
%this.setInventory(TR2ChaingunAmmo,0);
|
||
|
|
%this.setInventory(TR2Grenade,0);
|
||
|
|
|
||
|
|
Parent::clearInventory(%this);
|
||
|
|
}
|
||
|
|
|
||
|
|
function serverCmdUse(%client,%data)
|
||
|
|
{
|
||
|
|
if( %data $= Disc )
|
||
|
|
%client.getControlObject().use(TR2Disc);
|
||
|
|
else if( %data $= GrenadeLauncher )
|
||
|
|
%client.getControlObject().use(TR2GrenadeLauncher);
|
||
|
|
else if( %data $= Chaingun )
|
||
|
|
%client.getControlObject().use(TR2Chaingun);
|
||
|
|
else if( %data $= Shocklance )
|
||
|
|
%client.getControlObject().use(TR2Shocklance);
|
||
|
|
else if( %data $= Grenade )
|
||
|
|
%client.getControlObject().use(TR2Grenade);
|
||
|
|
else if( %data $= Mortar )
|
||
|
|
%client.getControlObject().use(TR2Mortar);
|
||
|
|
else if( %data $= TargetingLaser )
|
||
|
|
%client.getControlObject().use((%client.team == 1) ? TR2GoldTargetingLaser : TR2SilverTargetingLaser);
|
||
|
|
// etc...
|
||
|
|
else
|
||
|
|
%client.getControlObject().use(%data);
|
||
|
|
}
|
||
|
|
|
||
|
|
function serverCmdStartNewVote(%client, %typeName, %arg1, %arg2, %arg3, %arg4, %playerVote)
|
||
|
|
{
|
||
|
|
parent::serverCmdStartNewVote(%client, %typeName, %arg1, %arg2, %arg3, %arg4, %playerVote);
|
||
|
|
|
||
|
|
//if( %typeName $= "ToggleDisableDeath" && %client.isAdmin )
|
||
|
|
// ToggleDisableDeath(%client);
|
||
|
|
|
||
|
|
if ( %typeName $= "TogglePracticeMode" && %client.isAdmin )
|
||
|
|
TogglePracticeMode(%client);
|
||
|
|
|
||
|
|
if( %typeName $= "ToggleRoles" && %client.isAdmin )
|
||
|
|
TogglePlayerRoles(%client);
|
||
|
|
|
||
|
|
if( %typeName $= "ToggleCrowd" && %client.isAdmin )
|
||
|
|
ToggleCrowd(%client);
|
||
|
|
|
||
|
|
if( %typeName $= "getQueuePos" )
|
||
|
|
{
|
||
|
|
messageQueueClient(%client);
|
||
|
|
}
|
||
|
|
if( %typeName $= "toggleSpecLock" && %client.isAdmin )
|
||
|
|
{
|
||
|
|
toggleSpectatorLock(%client);
|
||
|
|
}
|
||
|
|
|
||
|
|
if( %typeName $= "toggleSpecOnly" )
|
||
|
|
toggleSpecOnly(%client);
|
||
|
|
|
||
|
|
if( %typeName $= "toggleSpecMode" )
|
||
|
|
toggleSpectatorMode(%client);
|
||
|
|
|
||
|
|
if( %typeName $= "tr2JoinGame" )
|
||
|
|
{
|
||
|
|
reindexQueue();
|
||
|
|
if( !$TR2::SpecLock && %client.queueSlot !$= "" && %client.queueSlot <= ((6 * 2) - getActiveCount()) )
|
||
|
|
{
|
||
|
|
Game.assignClientTeam(%client);
|
||
|
|
Game.spawnPlayer(%client, $MatchStarted);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if( %typeName $= "tr2ForceFlagReturn" )
|
||
|
|
{
|
||
|
|
if( %client.isAdmin && $TheFlag.carrier $= "" && (getSimTime() - $TheFlag.dropTime) >= 30000 )
|
||
|
|
{
|
||
|
|
messageAll('MsgAdminForce', '\c0%1 forced the flag to return to the stand.', %client.name);
|
||
|
|
Game.flagReturn($TheFlag, 0);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function toggleSpectatorMode(%client)
|
||
|
|
{
|
||
|
|
if( %client.team <= 0 )
|
||
|
|
{
|
||
|
|
%client.tr2SpecMode = !%client.tr2SpecMode;
|
||
|
|
if( %client.tr2SpecMode )
|
||
|
|
{
|
||
|
|
%target = $TheFlag.carrier $= "" ? $TheFlag : $TheFlag.carrier.client;
|
||
|
|
%type = $TheFlag.carrier $= "" ? 2 : 1;
|
||
|
|
Game.observeObject(%client, %target, %type);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if( %client.camera.mode !$= "observerFly" )
|
||
|
|
%client.camera.getDataBlock().setMode(%client.camera, "observerFly");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function toggleSpectatorLock(%client)
|
||
|
|
{
|
||
|
|
$TR2::SpecLock = !$TR2::SpecLock;
|
||
|
|
%status = $TR2::SpecLock ? "locked spectators in observer mode." : "enabled the spectator queue.";
|
||
|
|
messageAll('MsgAdminForce', '\c0%1 %2.', %client.name, %status);
|
||
|
|
}
|
||
|
|
|
||
|
|
function toggleSpecOnly(%client)
|
||
|
|
{
|
||
|
|
%time = getSimTime() - %client.specOnlyTime;
|
||
|
|
if( %time > 10000 )
|
||
|
|
{
|
||
|
|
%client.specOnly = !%client.specOnly;
|
||
|
|
%status = %client.specOnly ? "You have locked yourself as a spectator." : "You have entered the queue.";
|
||
|
|
messageClient(%client, 'MsgAdminForce', '\c2%1', %status);
|
||
|
|
reindexQueue();
|
||
|
|
messageQueueClient(%client);
|
||
|
|
%client.specOnlyTime = getSimTime();
|
||
|
|
|
||
|
|
%vacant = ((6 * 2) - getActiveCount());
|
||
|
|
if( !%client.specOnly && %vacant > 0 && %client.queueSlot <= %vacant )
|
||
|
|
{
|
||
|
|
Game.assignClientTeam(%client, 0);
|
||
|
|
Game.spawnPlayer(%client, 0);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
messageClient(%client, 'MsgTR2Wait', '\c0You must wait %1 seconds before using this option again!~wfx/powered/station_denied.wav', mFloor((10000 - %time)/1000) );
|
||
|
|
}
|
||
|
|
|
||
|
|
function TogglePlayerRoles(%client)
|
||
|
|
{
|
||
|
|
$TR2::EnableRoles = !$TR2::EnableRoles;
|
||
|
|
%status = $TR2::EnableRoles ? "enabled player roles." : "disabled player roles.";
|
||
|
|
messageAll('MsgAdminForce', '\c2%1 %2', %client.name, %status);
|
||
|
|
}
|
||
|
|
|
||
|
|
function ToggleCrowd(%client)
|
||
|
|
{
|
||
|
|
if ($TR2::EnableCrowd)
|
||
|
|
Game.stopCrowd();
|
||
|
|
|
||
|
|
$TR2::EnableCrowd = !$TR2::EnableCrowd;
|
||
|
|
%status = $TR2::EnableCrowd ? "enabled the crowd." : "disabled the crowd";
|
||
|
|
messageAll('MsgAdminForce', '\c2%1 %2', %client.name, %status);
|
||
|
|
}
|
||
|
|
|
||
|
|
function ToggleDisableDeath(%client)
|
||
|
|
{
|
||
|
|
$TR2::DisableDeath = !$TR2::DisableDeath;
|
||
|
|
%status = $TR2::DisableDeath ? "disabled Death." : "enabled Death.";
|
||
|
|
messageAll('MsgAdminForce', '\c2%1 %2', %client.name, %status);
|
||
|
|
|
||
|
|
// Reset all players' knockdown status
|
||
|
|
for(%i = 0; %i < ClientGroup.getCount(); %i ++)
|
||
|
|
{
|
||
|
|
%cl = ClientGroup.getObject(%i);
|
||
|
|
%cl.knockedDown = false;
|
||
|
|
cancel(%cl.knockdownThread);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function TogglePracticeMode(%client)
|
||
|
|
{
|
||
|
|
$TR2::PracticeMode = !$TR2::PracticeMode;
|
||
|
|
%status = $TR2::PracticeMode ? "enabled Practice Mode." : "disabled Practice Mode.";
|
||
|
|
messageAll('MsgAdminForce', '\c2%1 %2', %client.name, %status);
|
||
|
|
}
|
||
|
|
|
||
|
|
function Flag::shouldApplyImpulse(%data, %obj)
|
||
|
|
{
|
||
|
|
// TR2: Get rid of flag discing
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
function TR2ShockLanceImage::onFire(%this, %obj, %slot)
|
||
|
|
{
|
||
|
|
if( %obj.isCloaked() )
|
||
|
|
{
|
||
|
|
if( %obj.respawnCloakThread !$= "" )
|
||
|
|
{
|
||
|
|
Cancel(%obj.respawnCloakThread);
|
||
|
|
%obj.setCloaked( false );
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if( %obj.getEnergyLevel() > 20 )
|
||
|
|
{
|
||
|
|
%obj.setCloaked( false );
|
||
|
|
%obj.reCloak = %obj.schedule( 500, "setCloaked", true );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
%muzzlePos = %obj.getMuzzlePoint(%slot);
|
||
|
|
%muzzleVec = %obj.getMuzzleVector(%slot);
|
||
|
|
|
||
|
|
%endPos = VectorAdd(%muzzlePos, VectorScale(%muzzleVec, %this.projectile.extension));
|
||
|
|
|
||
|
|
%damageMasks = $TypeMasks::PlayerObjectType | $TypeMasks::VehicleObjectType |
|
||
|
|
$TypeMasks::StationObjectType | $TypeMasks::GeneratorObjectType |
|
||
|
|
$TypeMasks::SensorObjectType | $TypeMasks::TurretObjectType;
|
||
|
|
|
||
|
|
%everythingElseMask = $TypeMasks::TerrainObjectType |
|
||
|
|
$TypeMasks::InteriorObjectType |
|
||
|
|
$TypeMasks::ForceFieldObjectType |
|
||
|
|
$TypeMasks::StaticObjectType |
|
||
|
|
$TypeMasks::MoveableObjectType |
|
||
|
|
$TypeMasks::DamagableItemObjectType;
|
||
|
|
|
||
|
|
// did I miss anything? players, vehicles, stations, gens, sensors, turrets
|
||
|
|
%hit = ContainerRayCast(%muzzlePos, %endPos, %damageMasks | %everythingElseMask, %obj);
|
||
|
|
|
||
|
|
%noDisplay = true;
|
||
|
|
|
||
|
|
if (%hit !$= "0")
|
||
|
|
{
|
||
|
|
%obj.setEnergyLevel(%obj.getEnergyLevel() - %this.hitEnergy);
|
||
|
|
|
||
|
|
%hitobj = getWord(%hit, 0);
|
||
|
|
%hitpos = getWord(%hit, 1) @ " " @ getWord(%hit, 2) @ " " @ getWord(%hit, 3);
|
||
|
|
|
||
|
|
if ( %hitObj.getType() & %damageMasks )
|
||
|
|
{
|
||
|
|
// TR2: Don't allow friendly lances
|
||
|
|
if (%obj.team == %hitobj.team)
|
||
|
|
return;
|
||
|
|
|
||
|
|
%hitobj.applyImpulse(%hitpos, VectorScale(%muzzleVec, %this.projectile.impulse));
|
||
|
|
%obj.playAudio(0, ShockLanceHitSound);
|
||
|
|
|
||
|
|
// This is truly lame, but we need the sourceobject property present...
|
||
|
|
%p = new ShockLanceProjectile() {
|
||
|
|
dataBlock = %this.projectile;
|
||
|
|
initialDirection = %obj.getMuzzleVector(%slot);
|
||
|
|
initialPosition = %obj.getMuzzlePoint(%slot);
|
||
|
|
sourceObject = %obj;
|
||
|
|
sourceSlot = %slot;
|
||
|
|
targetId = %hit;
|
||
|
|
};
|
||
|
|
MissionCleanup.add(%p);
|
||
|
|
|
||
|
|
%damageMultiplier = 1.0;
|
||
|
|
|
||
|
|
if(%hitObj.getDataBlock().getClassName() $= "PlayerData")
|
||
|
|
{
|
||
|
|
// Now we see if we hit from behind...
|
||
|
|
%forwardVec = %hitobj.getForwardVector();
|
||
|
|
%objDir2D = getWord(%forwardVec, 0) @ " " @ getWord(%forwardVec,1) @ " " @ "0.0";
|
||
|
|
%objPos = %hitObj.getPosition();
|
||
|
|
%dif = VectorSub(%objPos, %muzzlePos);
|
||
|
|
%dif = getWord(%dif, 0) @ " " @ getWord(%dif, 1) @ " 0";
|
||
|
|
%dif = VectorNormalize(%dif);
|
||
|
|
%dot = VectorDot(%dif, %objDir2D);
|
||
|
|
|
||
|
|
// 120 Deg angle test...
|
||
|
|
// 1.05 == 60 degrees in radians
|
||
|
|
if (%dot >= mCos(1.05)) {
|
||
|
|
// Rear hit
|
||
|
|
%damageMultiplier = 3.0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
%totalDamage = %this.Projectile.DirectDamage * %damageMultiplier;
|
||
|
|
%hitObj.getDataBlock().damageObject(%hitobj, %p.sourceObject, %hitpos, %totalDamage, $DamageType::ShockLance);
|
||
|
|
|
||
|
|
%noDisplay = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if( %noDisplay )
|
||
|
|
{
|
||
|
|
// Miss
|
||
|
|
%obj.setEnergyLevel(%obj.getEnergyLevel() - %this.missEnergy);
|
||
|
|
%obj.playAudio(0, ShockLanceMissSound);
|
||
|
|
|
||
|
|
%p = new ShockLanceProjectile() {
|
||
|
|
dataBlock = %this.projectile;
|
||
|
|
initialDirection = %obj.getMuzzleVector(%slot);
|
||
|
|
initialPosition = %obj.getMuzzlePoint(%slot);
|
||
|
|
sourceObject = %obj;
|
||
|
|
sourceSlot = %slot;
|
||
|
|
};
|
||
|
|
MissionCleanup.add(%p);
|
||
|
|
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
function Armor::onCollision(%this,%obj,%col,%forceVehicleNode)
|
||
|
|
{
|
||
|
|
// Don't allow corpse looting
|
||
|
|
%dataBlock = %col.getDataBlock();
|
||
|
|
%className = %dataBlock.className;
|
||
|
|
if (%className $= "Armor")
|
||
|
|
if (%col.getState() $= "Dead")
|
||
|
|
return;
|
||
|
|
|
||
|
|
Parent::onCollision(%this, %obj, %col, %forceVehicleNode);
|
||
|
|
|
||
|
|
if (%obj.getState() $= "Dead")
|
||
|
|
return;
|
||
|
|
|
||
|
|
%obj.delayRoleChangeTime = getSimTime();
|
||
|
|
|
||
|
|
%dataBlock = %col.getDataBlock();
|
||
|
|
%className = %dataBlock.className;
|
||
|
|
%client = %obj.client;
|
||
|
|
if (%className $= "Armor")
|
||
|
|
{
|
||
|
|
if (%col.getState() $= "Dead" || %obj.invincible)
|
||
|
|
return;
|
||
|
|
|
||
|
|
CollisionBonus.evaluate(%obj, %col);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function Armor::onDisabled(%this, %obj, %state)
|
||
|
|
{
|
||
|
|
Game.assignOutermostRole(%obj.client);
|
||
|
|
if (!$TR2::DisableDeath || %obj.client.forceRespawn)
|
||
|
|
Parent::onDisabled(%this, %obj, %state);
|
||
|
|
}
|
||
|
|
|
||
|
|
function Armor::damageObject(%data, %targetObject, %sourceObject, %position, %amount, %damageType, %momVec, %mineSC)
|
||
|
|
{
|
||
|
|
//echo("Armor::damageObject() (targetClient = " @ getTaggedString(%targetObject.client.name) @ ")");
|
||
|
|
//echo("Armor::damageObject() (sourceClient = " @ getTaggedString(%sourceObject.client.name) @ ")");
|
||
|
|
//echo("Armor::damageObject() (sourceObj = " @ %sourceObject @ ")");
|
||
|
|
|
||
|
|
if (Game.goalJustScored)
|
||
|
|
return;
|
||
|
|
|
||
|
|
//if (%sourceObject == 0)
|
||
|
|
//{
|
||
|
|
//%targetObject.schedule(2, "setDataBlock", TR2HeavyMaleHumanArmor);
|
||
|
|
%targetObject.delayRoleChangeTime = getSimTime();
|
||
|
|
//}
|
||
|
|
return Parent::DamageObject(%data, %targetObject, %sourceObject, %position, %amount, %damageType, %momVec, %mineSC);
|
||
|
|
}
|
||
|
|
|
||
|
|
function ShapeBase::getHeight(%this)
|
||
|
|
{
|
||
|
|
%z = getWord(%this.getPosition(), 2);
|
||
|
|
return (%z - getTerrainHeight(%this.getPosition()));
|
||
|
|
}
|
||
|
|
|
||
|
|
function ShapeBase::getSpeed(%this)
|
||
|
|
{
|
||
|
|
return (VectorLen(%this.getVelocity()));
|
||
|
|
}
|
||
|
|
|
||
|
|
function ShapeBase::isOutOfBounds(%this)
|
||
|
|
{
|
||
|
|
%shapePos = %this.getPosition();
|
||
|
|
%shapex = firstWord(%shapePos);
|
||
|
|
%shapey = getWord(%shapePos, 1);
|
||
|
|
%bounds = MissionArea.area;
|
||
|
|
%boundsWest = firstWord(%bounds);
|
||
|
|
%boundsNorth = getWord(%bounds, 1);
|
||
|
|
%boundsEast = %boundsWest + getWord(%bounds, 2);
|
||
|
|
%boundsSouth = %boundsNorth + getWord(%bounds, 3);
|
||
|
|
|
||
|
|
return (%shapex < %boundsWest || %shapex > %boundsEast ||
|
||
|
|
%shapey < %boundsNorth || %shapey > %boundsSouth);
|
||
|
|
}
|
||
|
|
|
||
|
|
function ShapeBase::bounceOffGrid(%this, %bounceForce)
|
||
|
|
{
|
||
|
|
if (%bounceForce $= "")
|
||
|
|
%bounceForce = 85;
|
||
|
|
|
||
|
|
%oldVel = %this.getVelocity();
|
||
|
|
%this.setVelocity("0 0 0");
|
||
|
|
|
||
|
|
%vecx = firstWord(%oldVel);
|
||
|
|
%vecy = getWord(%oldVel, 1);
|
||
|
|
%vecz = getWord(%oldVel, 2);
|
||
|
|
|
||
|
|
%shapePos = %this.getPosition();
|
||
|
|
%shapex = firstWord(%shapePos);
|
||
|
|
%shapey = getWord(%shapePos, 1);
|
||
|
|
%bounds = MissionArea.area;
|
||
|
|
%boundsWest = firstWord(%bounds);
|
||
|
|
%boundsNorth = getWord(%bounds, 1);
|
||
|
|
%boundsEast = %boundsWest + getWord(%bounds, 2);
|
||
|
|
%boundsSouth = %boundsNorth + getWord(%bounds, 3);
|
||
|
|
|
||
|
|
// Two cases: 1) object is at E or W side; 2) object is at N or S side
|
||
|
|
if((%shapex <= %boundsWest) || (%shapex >= %boundsEast))
|
||
|
|
%vecx = -%vecx;
|
||
|
|
else
|
||
|
|
%vecy = -%vecy;
|
||
|
|
|
||
|
|
%vec = %vecx SPC %vecy SPC %vecz;
|
||
|
|
|
||
|
|
// normalize the vector, scale it
|
||
|
|
//%vecNorm = VectorNormalize(%vec);
|
||
|
|
//%vec = VectorScale(%vecNorm, 100 * %bounceForce);
|
||
|
|
|
||
|
|
// If the object's speed was pretty slow, give it a boost
|
||
|
|
%oldSpeed = VectorLen(%oldVel);
|
||
|
|
if (%oldSpeed < $TR2_MinimumGridBoost)
|
||
|
|
{
|
||
|
|
%vec = VectorNormalize(%vec);
|
||
|
|
%vec = VectorScale(%vec, $TR2_MinimumGridBoost);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
%vec = VectorScale(%vec, $TR2_GridVelocityScale);
|
||
|
|
|
||
|
|
// apply the impulse to the flag object
|
||
|
|
//%this.applyImpulse(%this.getWorldBoxCenter(), %vec);
|
||
|
|
%this.setVelocity(%vec);
|
||
|
|
}
|
||
|
|
|
||
|
|
function Observer::setMode(%data, %obj, %mode, %targetObj)
|
||
|
|
{
|
||
|
|
if(%mode $= "")
|
||
|
|
return;
|
||
|
|
|
||
|
|
%client = %obj.getControllingClient();
|
||
|
|
|
||
|
|
%obsVector = $TR2_playerObserveParameters;
|
||
|
|
|
||
|
|
if (%client > 0 && %client.obsZoomLevel !$= "")
|
||
|
|
%zoomLevel = %client.obsZoomLevel;
|
||
|
|
else
|
||
|
|
%zoomLevel = 0;
|
||
|
|
%obsVector = VectorScale(%obsVector, $TR2::ObsZoomScale[%zoomLevel]);
|
||
|
|
|
||
|
|
%obsx = getWord(%obsVector, 0);
|
||
|
|
%obsy = getWord(%obsVector, 1);
|
||
|
|
%obsz = getWord(%obsVector, 2);
|
||
|
|
|
||
|
|
switch$ (%mode) {
|
||
|
|
case "justJoined":
|
||
|
|
commandToClient(%client, 'setHudMode', 'Observer');
|
||
|
|
%markerObj = Game.pickObserverSpawn(%client, true);
|
||
|
|
%transform = %markerObj.getTransform();
|
||
|
|
%obj.setTransform(%transform);
|
||
|
|
%obj.setFlyMode();
|
||
|
|
|
||
|
|
case "followFlag":
|
||
|
|
// Follow the dropped flag (hopefully)
|
||
|
|
%position = %targetObj.getPosition();
|
||
|
|
%newTransform = %position SPC %client.lastObsRot;
|
||
|
|
%obj.setOrbitMode(%targetObj, %newTransform, %obsx, %obsy, %obsz);
|
||
|
|
//%obj.setOrbitMode(%targetObj, %targetObj.getTransform(), %obsx, %obsy, %obsz);
|
||
|
|
%obj.mode = %mode;
|
||
|
|
|
||
|
|
|
||
|
|
case "pre-game":
|
||
|
|
commandToClient(%client, 'setHudMode', 'Observer');
|
||
|
|
%obj.setOrbitMode( %targetObj, %targetObj.getTransform(), %obsx, %obsy, %obsz);
|
||
|
|
|
||
|
|
case "observerFollow":
|
||
|
|
// Observer attached to a moving object (assume player for now...)
|
||
|
|
%position = %targetObj.getPosition();
|
||
|
|
%transform = %position SPC %client.lastObsRot;
|
||
|
|
|
||
|
|
//%obj.setOrbitMode(%targetObj, %newTransform, %obsx, %obsy, %obsz);
|
||
|
|
//%transform = %targetObj.getTransform();
|
||
|
|
|
||
|
|
if( !%targetObj.isMounted() )
|
||
|
|
%obj.setOrbitMode(%targetObj, %transform, %obsx, %obsy, %obsz);
|
||
|
|
else
|
||
|
|
{
|
||
|
|
%mount = %targetObj.getObjectMount();
|
||
|
|
if( %mount.getDataBlock().observeParameters $= "" )
|
||
|
|
%params = %transform;
|
||
|
|
else
|
||
|
|
%params = %mount.getDataBlock().observeParameters;
|
||
|
|
|
||
|
|
%obj.setOrbitMode(%mount, %mount.getTransform(), getWord( %params, 0 ), getWord( %params, 1 ), getWord( %params, 2 ));
|
||
|
|
}
|
||
|
|
case "observerFly":
|
||
|
|
// Free-flying observer camera
|
||
|
|
commandToClient(%client, 'setHudMode', 'Observer');
|
||
|
|
%markerObj = Game.pickObserverSpawn(%client, true);
|
||
|
|
%transform = %markerObj.getTransform();
|
||
|
|
%obj.setTransform(%transform);
|
||
|
|
%obj.setFlyMode();
|
||
|
|
|
||
|
|
case "observerStatic" or "observerStaticNoNext":
|
||
|
|
// Non-moving observer camera
|
||
|
|
%markerObj = Game.pickObserverSpawn(%client, true);
|
||
|
|
%transform = %markerObj.getTransform();
|
||
|
|
%obj.setTransform(%transform);
|
||
|
|
|
||
|
|
case "observerTimeout":
|
||
|
|
commandToClient(%client, 'setHudMode', 'Observer');
|
||
|
|
%markerObj = Game.pickObserverSpawn(%client, true);
|
||
|
|
%transform = %markerObj.getTransform();
|
||
|
|
%obj.setTransform(%transform);
|
||
|
|
%obj.setFlyMode();
|
||
|
|
}
|
||
|
|
%obj.mode = %mode;
|
||
|
|
}
|
||
|
|
|
||
|
|
function ShapeBaseImageData::onFire(%data, %obj, %slot)
|
||
|
|
{
|
||
|
|
//if (Game.goalJustScored)
|
||
|
|
// return;
|
||
|
|
|
||
|
|
%data.lightStart = getSimTime();
|
||
|
|
|
||
|
|
// TR2: No need for cloak logic
|
||
|
|
//if( %obj.station $= "" && %obj.isCloaked() )
|
||
|
|
//{
|
||
|
|
// if( %obj.respawnCloakThread !$= "" )
|
||
|
|
// {
|
||
|
|
// Cancel(%obj.respawnCloakThread);
|
||
|
|
// %obj.setCloaked( false );
|
||
|
|
// %obj.respawnCloakThread = "";
|
||
|
|
// }
|
||
|
|
// else
|
||
|
|
// {
|
||
|
|
// if( %obj.getEnergyLevel() > 20 )
|
||
|
|
// {
|
||
|
|
// %obj.setCloaked( false );
|
||
|
|
// %obj.reCloak = %obj.schedule( 500, "setCloaked", true );
|
||
|
|
// }
|
||
|
|
// }
|
||
|
|
//}
|
||
|
|
|
||
|
|
// TR2: Delay the disabling of invincibility to allow one free disc jump
|
||
|
|
if( %obj.client > 0 )
|
||
|
|
{
|
||
|
|
%obj.setInvincibleMode(0 ,0.00);
|
||
|
|
%obj.schedule(200, "setInvincible", false ); // fire your weapon and your invincibility goes away.
|
||
|
|
}
|
||
|
|
|
||
|
|
%vehicle = 0;
|
||
|
|
if(%data.usesEnergy)
|
||
|
|
{
|
||
|
|
if(%data.useMountEnergy)
|
||
|
|
{
|
||
|
|
%useEnergyObj = %obj.getObjectMount();
|
||
|
|
if(!%useEnergyObj)
|
||
|
|
%useEnergyObj = %obj;
|
||
|
|
%energy = %useEnergyObj.getEnergyLevel();
|
||
|
|
%vehicle = %useEnergyObj;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
%energy = %obj.getEnergyLevel();
|
||
|
|
|
||
|
|
if(%data.useCapacitor && %data.usesEnergy)
|
||
|
|
{
|
||
|
|
if( %useEnergyObj.turretObject.getCapacitorLevel() < %data.minEnergy )
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if(%energy < %data.minEnergy)
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if(%data.projectileSpread)
|
||
|
|
{
|
||
|
|
%vector = %obj.getMuzzleVector(%slot);
|
||
|
|
%x = (getRandom() - 0.5) * 2 * 3.1415926 * %data.projectileSpread;
|
||
|
|
%y = (getRandom() - 0.5) * 2 * 3.1415926 * %data.projectileSpread;
|
||
|
|
%z = (getRandom() - 0.5) * 2 * 3.1415926 * %data.projectileSpread;
|
||
|
|
%mat = MatrixCreateFromEuler(%x @ " " @ %y @ " " @ %z);
|
||
|
|
%vector = MatrixMulVector(%mat, %vector);
|
||
|
|
|
||
|
|
%p = new (%data.projectileType)() {
|
||
|
|
dataBlock = %data.projectile;
|
||
|
|
initialDirection = %vector;
|
||
|
|
initialPosition = %obj.getMuzzlePoint(%slot);
|
||
|
|
sourceObject = %obj;
|
||
|
|
sourceSlot = %slot;
|
||
|
|
vehicleObject = %vehicle;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
%p = new (%data.projectileType)() {
|
||
|
|
dataBlock = %data.projectile;
|
||
|
|
initialDirection = %obj.getMuzzleVector(%slot);
|
||
|
|
initialPosition = %obj.getMuzzlePoint(%slot);
|
||
|
|
sourceObject = %obj;
|
||
|
|
sourceSlot = %slot;
|
||
|
|
vehicleObject = %vehicle;
|
||
|
|
};
|
||
|
|
// echo("blah");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (isObject(%obj.lastProjectile) && %obj.deleteLastProjectile)
|
||
|
|
%obj.lastProjectile.delete();
|
||
|
|
|
||
|
|
%obj.lastProjectile = %p;
|
||
|
|
%obj.deleteLastProjectile = %data.deleteLastProjectile;
|
||
|
|
MissionCleanup.add(%p);
|
||
|
|
|
||
|
|
// AI hook
|
||
|
|
if(%obj.client)
|
||
|
|
%obj.client.projectile = %p;
|
||
|
|
|
||
|
|
if(%data.usesEnergy)
|
||
|
|
{
|
||
|
|
if(%data.useMountEnergy)
|
||
|
|
{
|
||
|
|
if( %data.useCapacitor )
|
||
|
|
{
|
||
|
|
%vehicle.turretObject.setCapacitorLevel( %vehicle.turretObject.getCapacitorLevel() - %data.fireEnergy );
|
||
|
|
}
|
||
|
|
else
|
||
|
|
%useEnergyObj.setEnergyLevel(%energy - %data.fireEnergy);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
%obj.setEnergyLevel(%energy - %data.fireEnergy);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
%obj.decInventory(%data.ammo,1);
|
||
|
|
return %p;
|
||
|
|
}
|
||
|
|
|
||
|
|
function updateScores()
|
||
|
|
{
|
||
|
|
if ( !isObject( Game ) )
|
||
|
|
return;
|
||
|
|
|
||
|
|
%numTeams = Game.numTeams;
|
||
|
|
|
||
|
|
// Initialize the team counts:
|
||
|
|
for ( %teamIndex = 0; %teamIndex <= %numTeams; %teamIndex++ )
|
||
|
|
Game.teamCount[%teamIndex] = 0;
|
||
|
|
|
||
|
|
%count = ClientGroup.getCount();
|
||
|
|
for ( %clientIndex = 0; %clientIndex < %count; %clientIndex++ )
|
||
|
|
{
|
||
|
|
%cl = ClientGroup.getObject( %clientIndex );
|
||
|
|
%team = %cl.getSensorGroup();
|
||
|
|
if ( %numTeams == 1 && %team != 0 )
|
||
|
|
%team = 1;
|
||
|
|
Game.teamScores[%team, Game.teamCount[%team], 0] = %cl.name;
|
||
|
|
if ( %cl.score $= "" )
|
||
|
|
Game.teamScores[%team, Game.teamCount[%team], 1] = 0;
|
||
|
|
else
|
||
|
|
Game.teamScores[%team, Game.teamCount[%team], 1] = %cl.passingScore + %cl.receivingScore;
|
||
|
|
Game.teamCount[%team]++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Ugly, non-gametype specific code to deal with tourney mode :/
|
||
|
|
function serverCmdClientPickedTeam( %client, %option )
|
||
|
|
{
|
||
|
|
if( Game.class $= "TR2Game" && %client.lastTeam <= 0 )
|
||
|
|
{
|
||
|
|
Game.forceObserver( %client, "playerChoose" );
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
switch(%option)
|
||
|
|
{
|
||
|
|
case 1:
|
||
|
|
if ( isObject(%client.player) )
|
||
|
|
{
|
||
|
|
%client.player.scriptKill(0);
|
||
|
|
Game.clientChangeTeam(%client, %option, 0);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
Game.clientJoinTeam( %client, %option, false );
|
||
|
|
case 2:
|
||
|
|
if ( isObject(%client.player) )
|
||
|
|
{
|
||
|
|
%client.player.scriptKill(0);
|
||
|
|
Game.clientChangeTeam(%client, %option, 0);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
Game.clientJoinTeam( %client, %option, false );
|
||
|
|
case 3:
|
||
|
|
if( !isObject(%client.player) )
|
||
|
|
{
|
||
|
|
Game.assignClientTeam( %client, $MatchStarted );
|
||
|
|
Game.spawnPlayer( %client, false );
|
||
|
|
}
|
||
|
|
default:
|
||
|
|
if( isObject(%client.player) )
|
||
|
|
{
|
||
|
|
%client.player.scriptKill(0);
|
||
|
|
ClearBottomPrint(%client);
|
||
|
|
}
|
||
|
|
Game.forceObserver( %client, "playerChoose" );
|
||
|
|
%client.observerMode = "observer";
|
||
|
|
%client.notReady = false;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
// End z0dd - ZOD
|
||
|
|
// ------------------------------------------------------------------------------------
|
||
|
|
ClearBottomPrint(%client);
|
||
|
|
%client.observerMode = "pregame";
|
||
|
|
%client.notReady = true;
|
||
|
|
%client.camera.getDataBlock().setMode( %client.camera, "pre-game", %client.player );
|
||
|
|
commandToClient(%client, 'setHudMode', 'Observer');
|
||
|
|
|
||
|
|
|
||
|
|
%client.setControlObject( %client.camera );
|
||
|
|
centerprint( %client, "\nPress FIRE when ready.", 0, 3 );
|
||
|
|
}
|
||
|
|
|
||
|
|
function playerPickTeam( %client )
|
||
|
|
{
|
||
|
|
if( Game.class $= "TR2Game" )
|
||
|
|
{
|
||
|
|
if( %client.lastTeam > 0 )
|
||
|
|
schedule( 0, 0, "commandToClient", %client, 'pickTeamMenu', Game.getTeamName(1), Game.getTeamName(2));
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
%numTeams = Game.numTeams;
|
||
|
|
if(%numTeams > 1)
|
||
|
|
{
|
||
|
|
%client.camera.mode = "PickingTeam";
|
||
|
|
schedule( 0, 0, "commandToClient", %client, 'pickTeamMenu', Game.getTeamName(1), Game.getTeamName(2));
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
Game.clientJoinTeam(%client, 0, 0);
|
||
|
|
%client.observerMode = "pregame";
|
||
|
|
%client.notReady = true;
|
||
|
|
%client.camera.getDataBlock().setMode( %client.camera, "pre-game", %client.player );
|
||
|
|
centerprint( %client, "\nPress FIRE when ready.", 0, 3 );
|
||
|
|
%client.setControlObject( %client.camera );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function Beacon::onUse(%data, %obj)
|
||
|
|
{
|
||
|
|
// look for 3 meters along player's viewpoint for interior or terrain
|
||
|
|
// TR2: increased
|
||
|
|
//%searchRange = 3.0;
|
||
|
|
%searchRange = 5.2;
|
||
|
|
%mask = $TypeMasks::TerrainObjectType | $TypeMasks::InteriorObjectType | $TypeMasks::StaticShapeObjectType | $TypeMasks::ForceFieldObjectType;
|
||
|
|
// get the eye vector and eye transform of the player
|
||
|
|
%eyeVec = %obj.getEyeVector();
|
||
|
|
%eyeTrans = %obj.getEyeTransform();
|
||
|
|
// extract the position of the player's camera from the eye transform (first 3 words)
|
||
|
|
%eyePos = posFromTransform(%eyeTrans);
|
||
|
|
// normalize the eye vector
|
||
|
|
%nEyeVec = VectorNormalize(%eyeVec);
|
||
|
|
// scale (lengthen) the normalized eye vector according to the search range
|
||
|
|
%scEyeVec = VectorScale(%nEyeVec, %searchRange);
|
||
|
|
// add the scaled & normalized eye vector to the position of the camera
|
||
|
|
%eyeEnd = VectorAdd(%eyePos, %scEyeVec);
|
||
|
|
// see if anything gets hit
|
||
|
|
%searchResult = containerRayCast(%eyePos, %eyeEnd, %mask, 0);
|
||
|
|
if(!%searchResult )
|
||
|
|
{
|
||
|
|
// no terrain/interior collision within search range
|
||
|
|
if(%obj.inv[%data.getName()] > 0)
|
||
|
|
messageClient(%obj.client, 'MsgBeaconNoSurface', '\c2Cannot place beacon. Too far from surface.');
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
%searchObj = GetWord(%searchResult, 0);
|
||
|
|
if(%searchObj.getType() & ($TypeMasks::StaticShapeObjectType | $TypeMasks::ForceFieldObjectType) )
|
||
|
|
{
|
||
|
|
// if there's already a beacon where player is aiming, switch its type
|
||
|
|
// otherwise, player can't deploy a beacon there
|
||
|
|
if(%searchObj.getDataBlock().getName() $= TR2DeployedBeacon)
|
||
|
|
switchBeaconType(%searchObj);
|
||
|
|
else
|
||
|
|
messageClient(%obj.client, 'MsgBeaconNoSurface', '\c2Cannot place beacon. Not a valid surface.');
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
else if(%obj.inv[%data.getName()] <= 0)
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
// newly deployed beacons default to "target" type
|
||
|
|
//if($TeamDeployedCount[%obj.team, TargetBeacon] >= $TeamDeployableMax[TargetBeacon])
|
||
|
|
//{
|
||
|
|
// messageClient(%obj.client, 'MsgDeployFailed', '\c2Your team\'s control network has reached its capacity for this item.~wfx/misc/misc.error.wav');
|
||
|
|
// return 0;
|
||
|
|
//}
|
||
|
|
%terrPt = posFromRaycast(%searchResult);
|
||
|
|
%terrNrm = normalFromRaycast(%searchResult);
|
||
|
|
|
||
|
|
%intAngle = getTerrainAngle(%terrNrm); // getTerrainAngle() function found in staticShape.cs
|
||
|
|
%rotAxis = vectorNormalize(vectorCross(%terrNrm, "0 0 1"));
|
||
|
|
if (getWord(%terrNrm, 2) == 1 || getWord(%terrNrm, 2) == -1)
|
||
|
|
%rotAxis = vectorNormalize(vectorCross(%terrNrm, "0 1 0"));
|
||
|
|
%rotation = %rotAxis @ " " @ %intAngle;
|
||
|
|
|
||
|
|
// TR2: T1-style beacon stop
|
||
|
|
%playerSpeed = %obj.getSpeed();
|
||
|
|
if (%obj.isJetting)
|
||
|
|
%obj.setVelocity("0 0 " @ %playerSpeed * $TR2_beaconStopScale);
|
||
|
|
else
|
||
|
|
%obj.setVelocity("0 0 0");
|
||
|
|
if (%playerSpeed > 17)
|
||
|
|
serverPlay3D(CarScreechSound, %obj.getPosition());
|
||
|
|
|
||
|
|
%obj.decInventory(%data, 1);
|
||
|
|
%depBeac = new BeaconObject() {
|
||
|
|
dataBlock = "DeployedBeacon";
|
||
|
|
position = VectorAdd(%terrPt, VectorScale(%terrNrm, 0.05));
|
||
|
|
rotation = %rotation;
|
||
|
|
};
|
||
|
|
//$TeamDeployedCount[%obj.team, TargetBeacon]++;
|
||
|
|
|
||
|
|
// TR2: Auto-delete beacon
|
||
|
|
%depBeac.startFade(2 * 1000, 0, true);
|
||
|
|
%depBeac.schedule(3 * 1000, "delete");
|
||
|
|
|
||
|
|
|
||
|
|
%depBeac.playThread($AmbientThread, "ambient");
|
||
|
|
%depBeac.team = %obj.team;
|
||
|
|
%depBeac.sourceObject = %obj;
|
||
|
|
|
||
|
|
// give it a team target
|
||
|
|
%depBeac.setTarget(%depBeac.team);
|
||
|
|
MissionCleanup.add(%depBeac);
|
||
|
|
}
|
||
|
|
|
||
|
|
function ShapeBase::throwObject(%this,%obj)
|
||
|
|
{
|
||
|
|
//if the object is being thrown by a corpse, use a random vector
|
||
|
|
if (%this.getState() $= "Dead" && %obj.getDataBlock().getName() !$= "TR2Flag1" )
|
||
|
|
{
|
||
|
|
%vec = (-1.0 + getRandom() * 2.0) SPC (-1.0 + getRandom() * 2.0) SPC getRandom();
|
||
|
|
%vec = vectorScale(%vec, 10);
|
||
|
|
}
|
||
|
|
|
||
|
|
// else Initial vel based on the dir the player is looking
|
||
|
|
else
|
||
|
|
{
|
||
|
|
%eye = %this.getEyeVector();
|
||
|
|
%vec = vectorScale(%eye, 20);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Add player's velocity
|
||
|
|
%vec = vectorAdd(%vec, %this.getVelocity());
|
||
|
|
%pos = getBoxCenter(%this.getWorldBox());
|
||
|
|
|
||
|
|
// Add a vertical component to give the item a better arc
|
||
|
|
%dot = vectorDot("0 0 1",%eye);
|
||
|
|
if (%dot < 0)
|
||
|
|
%dot = -%dot;
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
//since flags have a huge mass (so when you shoot them, they don't bounce too far)
|
||
|
|
//we need to up the %vec so that you can still throw them...
|
||
|
|
if (%obj.getDataBlock().getName() $= "TR2Flag1")
|
||
|
|
{
|
||
|
|
// Add the throw strength, which ranges from 0.2 - 1.2
|
||
|
|
// Make it range from 0 - 1
|
||
|
|
//%addedStrength = %this.flagThrowStrength/1.25 - 0.2;
|
||
|
|
%addedStrength = %this.flagThrowStrength - 0.2;
|
||
|
|
%addedStrength *= $TR2_FlagThrowScale;
|
||
|
|
|
||
|
|
%vec = vectorAdd(%vec,vectorScale("0 0 " @ $TR2_UpwardFlagThrust,1 - %dot));
|
||
|
|
%flagVel = %this.getVelocity();
|
||
|
|
%playerRot = %this.getEyeVector();
|
||
|
|
%testDirection = VectorDot(VectorNormalize(%playerVel), VectorNormalize(%playerRot));
|
||
|
|
//%flagVel = VectorScale(%flagVel, 50);
|
||
|
|
%playerVel = VectorNormalize(%this.getVelocity());
|
||
|
|
if (%obj.oneTimer)
|
||
|
|
{
|
||
|
|
%playerVel = VectorScale(%playerVel, $TR2_PlayerVelocityAddedToFlagThrust / 1.3);
|
||
|
|
%addedStrength *= 1.1;
|
||
|
|
//%obj.oneTimer = 0;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
%playerVel = VectorScale(%playerVel, $TR2_PlayerVelocityAddedToFlagThrust);
|
||
|
|
%playerRot = VectorScale(%playerRot, $TR2_ForwardFlagThrust * %addedStrength);
|
||
|
|
//%pos = VectorAdd(VectorNormalize(%playerRot), %this.getPosition());
|
||
|
|
|
||
|
|
%vec = VectorAdd(%vec, %playerVel);
|
||
|
|
%vec = VectorAdd(%vec, %playerRot);
|
||
|
|
|
||
|
|
|
||
|
|
// Don't apply the velocity impulse if the player is facing one direction
|
||
|
|
// but travelling in the other
|
||
|
|
//if (%testDirection > -0.85)
|
||
|
|
%newVel = VectorAdd(%playerVel, %newVel);
|
||
|
|
|
||
|
|
// apply the impulse to the flag object
|
||
|
|
//%flag.applyImpulse(%flag.getPosition(), %newVel);
|
||
|
|
%vec = vectorScale(%vec, $TR2_GeneralFlagBoost);
|
||
|
|
//%vec = %newVel;
|
||
|
|
//echo("applying flag impulse: " @ %vec);
|
||
|
|
|
||
|
|
// Remember the throw velocity in case T2's flag re-catch bug rears
|
||
|
|
// its ugly head, and we need to re-boost it
|
||
|
|
//%obj.throwVelocity = %vec;
|
||
|
|
|
||
|
|
// Try adjust the flag to start further away from the player in order to
|
||
|
|
// bypass T2's re-catch bug
|
||
|
|
%extend = VectorScale(VectorNormalize(%this.getEyeVector()), 2);
|
||
|
|
%pos = VectorAdd(%extend, %pos);
|
||
|
|
|
||
|
|
%this.throwStrength = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
%obj.setTransform(%pos);
|
||
|
|
%obj.applyImpulse(%pos,%vec);
|
||
|
|
%obj.setCollisionTimeout(%this);
|
||
|
|
%data = %obj.getDatablock();
|
||
|
|
%data.onThrow(%obj,%this);
|
||
|
|
|
||
|
|
//call the AI hook
|
||
|
|
//AIThrowObject(%obj);
|
||
|
|
}
|
||
|
|
|
||
|
|
// classic hoses this up.
|
||
|
|
// using the grenade throw from 24834
|
||
|
|
function HandInventory::onUse(%data, %obj)
|
||
|
|
{
|
||
|
|
// %obj = player %data = datablock of what's being thrown
|
||
|
|
if(Game.handInvOnUse(%data, %obj))
|
||
|
|
{
|
||
|
|
//AI HOOK - If you change the %throwStren, tell Tinman!!!
|
||
|
|
//Or edit aiInventory.cs and search for: use(%grenadeType);
|
||
|
|
|
||
|
|
%tossTimeout = getSimTime() - %obj.lastThrowTime[%data];
|
||
|
|
if(%tossTimeout < $HandInvThrowTimeout)
|
||
|
|
return;
|
||
|
|
|
||
|
|
%throwStren = %obj.throwStrength;
|
||
|
|
|
||
|
|
%obj.decInventory(%data, 1);
|
||
|
|
%thrownItem = new Item()
|
||
|
|
{
|
||
|
|
dataBlock = %data.thrownItem;
|
||
|
|
sourceObject = %obj;
|
||
|
|
};
|
||
|
|
MissionCleanup.add(%thrownItem);
|
||
|
|
|
||
|
|
// throw it
|
||
|
|
%eye = %obj.getEyeVector();
|
||
|
|
%vec = vectorScale(%eye, (%throwStren * 20.0));
|
||
|
|
|
||
|
|
// add a vertical component to give it a better arc
|
||
|
|
%dot = vectorDot("0 0 1", %eye);
|
||
|
|
if(%dot < 0)
|
||
|
|
%dot = -%dot;
|
||
|
|
%vec = vectorAdd(%vec, vectorScale("0 0 4", 1 - %dot));
|
||
|
|
|
||
|
|
// add player's velocity
|
||
|
|
%vec = vectorAdd(%vec, vectorScale(%obj.getVelocity(), 0.4));
|
||
|
|
%pos = getBoxCenter(%obj.getWorldBox());
|
||
|
|
|
||
|
|
|
||
|
|
%thrownItem.sourceObject = %obj;
|
||
|
|
%thrownItem.team = %obj.team;
|
||
|
|
%thrownItem.setTransform(%pos);
|
||
|
|
|
||
|
|
%thrownItem.applyImpulse(%pos, %vec);
|
||
|
|
%thrownItem.setCollisionTimeout(%obj);
|
||
|
|
serverPlay3D(GrenadeThrowSound, %pos);
|
||
|
|
%obj.lastThrowTime[%data] = getSimTime();
|
||
|
|
|
||
|
|
%thrownItem.getDataBlock().onThrow(%thrownItem, %obj);
|
||
|
|
%obj.throwStrength = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
};
|