// We cancel schedules when player switches to another weapon -
// WeaponImage::onUnmount and DefaultGame::onClientKilled
datablock TargetProjectileData(GrappleBeam)
{
directDamage = 0.0;
hasDamageRadius = false;
indirectDamage = 0.0;
damageRadius = 0.0;
velInheritFactor = 1.0;
maxRifleRange = 250;
beamColor = "0.1 1.0 0.1";
startBeamWidth = 0.30;
pulseBeamWidth = 0.20;
beamFlareAngle = 3.0;
minFlareSize = 0.0;
maxFlareSize = 400.0;
pulseSpeed = 6.0;
pulseLength = 0.150;
textureName[0] = "special/nonlingradient";
textureName[1] = "special/flare";
textureName[2] = "special/pulse";
textureName[3] = "special/expFlare";
beacon = false;
};
datablock ItemData(GrapplingHook) : TargetingLaser
{
image = GrapplingHookImage;
pickUpName = "a grappling hook";
computeCRC = false;
};
datablock ShapeBaseImageData(GrapplingHookImage) : TargetingLaserImage
{
item = GrapplingHook;
projectile = GrappleBeam;
usesEnergy = true;
minEnergy = 5;
cutOffEnergy = 10;
stateName[3] = "Fire";
stateEnergyDrain[3] = 3;
stateFire[3] = true;
stateAllowImageChange[3] = false;
stateScript[3] = "onFire";
stateTransitionOnTriggerUp[3] = "ReelIn";
stateTransitionOnNoAmmo[3] = "ReelIn";
stateSound[3] = TargetingLaserPaintSound;
//stateTimeoutValue[3] = 2.0;
//stateTransitionOnTimeout[3] = "Deconstruction";
stateTimeoutValue[5] = 1.5;
stateName[6] = "ReelIn";
stateFire[6] = true;
stateSound[6] = TargetingLaserPaintSound;
stateAllowImageChange[6] = false;
stateScript[6] = "onReelIn";
stateTransitionOnTriggerDown[6] = "Deconstruction";
//stateTimeoutValue[6] = 2.0;
//stateTransitionOnTimeout[6] = "Deconstruction";
};
function GrapplingHookImage::onFire(%data, %obj, %slot)
{
//error("GrapplingHookImage::onFire(" SPC %data.getName() SPC %obj.client.nameBase SPC %slot SPC ")");
%p = Parent::onFire(%data, %obj, %slot);
if(isObject(%p))
{
%obj.grapplePos = %p.getTargetPoint();
$GrapplePoint = %obj.grapplePos;
%dist = vectorDist(%obj.grapplePos , %obj.getPosition());
if(%dist > 250)
{
%p.delete();
%obj.lastProjectile = "";
%obj.grapplePos = "";
return;
}
$ropeLength = %dist;
%obj.grappleObject();
%p.schedule(300, "delete");
}
}
function Player::grappleObject(%obj)
{
if(isObject(%obj))
{
if(isEventPending(%obj.grappleSchedule))
cancel(%obj.grappleSchedule);
if(%obj.getState() !$= "Dead")
{
// %obj.setVelocity("0 0 5");
%pos = %obj.getWorldBoxCenter();
%dist = VectorLen(VectorSub(%pos, $GrapplePoint));
%vel = %obj.getVelocity();
if (VectorLen(VectorAdd(%pos, %vel)) > $RopeLength) {
//%mass = %obj.getDatablock().mass;
%rad = VectorSub($GrapplePoint, %pos);
%radx = getWord(%rad, 0); %velx = getWord(%vel, 0);
%rady = getWord(%rad, 1); %vely = getWord(%vel, 1);
%radz = getWord(%rad, 2); %velz = getWord(%vel, 2);
%radH = mSqrt(%radx * %radx + %rady * %rady);
%VelH = mSqrt(%velx * %velx + %vely * %vely);
%VecH = %velx SPC %vely SPC "0";
%radVel = ((%radx * velx) + (%rady * %vely)) / %radH;
//%tanVel = mSqrt(%VelH * %velH - %radVel * %radVel);
%tanDir = VectorCross(%rad, "0 0 10");
%tanx = getWord(%tanDir, 0); %tany = getWord(%tanDir, 1);
%tanVel = (%velx * %tanx + %vely * %tany) / VectorLen(%tanDir);
%tanVec = VectorScale(VectorNormalize(%tanDir), %tanVel);
%radVec = VectorScale(VectorNormalize(%rad), -%radVel);
%radVecH = getWord(%radVec, 0) SPC getWord(%radVec, 1) SPC "0";
if (mSgn(getWord(VectorAdd(%radVecH, %tanVec), 0)) != mSgn(getWord(VectorNormalize(%VecH), 0))
&& mSgn(getWord(VectorAdd(%radVecH, %tanVec), 1)) != mSgn(getWord(VectorNormalize(%VecH), 1))) {
%tanVec = VectorScale(%tanVec, -1);
}
%newVel = VectorScale(VectorNormalize(%tanVec), VectorLen(%tanVel));
%ZtanDir = VectorCross(%rad, %tanDir);
if (mSgn(getWord(%ZtanDir, 0)) != mSgn(getWord(%vel, 0))
&& mSgn(getWord(%ZtanDir, 1)) != mSgn(getWord(%vel, 1)))
%ZtanDir = VectorScale(%ZtanDir, -1);
%Ztanx = getWord(%ZtanDir, 0); %Ztany = getWord(%ZtanDir, 1); %Ztanz = getWord(%ZtanDir, 2);
%ZtanH = mSqrt(%Ztanx * %Ztanx + %Ztany * %Ztany);
%Zvel = (%velH * %ZtanH + %velz * %Ztanz) / VectorLen(%ZtanDir);
%newZVec = VectorScale(VectorNormalize(%ZtanDir), %Zvel);
if (mSgn(%radz) == 1 && mSgn(%velz) == -1)
%newVel = VectorAdd(%newVel, "0 0 5");
%newVel = VectorAdd(%newVel, %newZVec);
%obj.setVelocity(%newVel);
echo("Applying force:" SPC %force);
}
%obj.grappleSchedule = %obj.schedule(250, "grappleObject");
}
}
}
function GrapplingHookImage::onReelIn(%data, %obj, %slot)
{
if(isObject(%obj))
{
if(isEventPending(%obj.grappleSchedule))
cancel(%obj.grappleSchedule);
%dist = vectorDist(%obj.grapplePos , %obj.getPosition());
if(%dist > 250)
{
%data.deconstruct(%obj, %slot);
return;
}
%obj.reelIn();
}
}
$TractorPower = 3;
function Player::reelIn(%obj)
{
if(isObject(%obj))
{
if(isEventPending(%obj.reelSchedule))
cancel(%obj.reelSchedule);
if(%obj.getState() !$= "Dead")
{
%pos = %obj.getWorldBoxCenter();
%dist = VectorLen(VectorSub(%pos, $GrapplePoint));
%vel = %obj.getVelocity();
if (VectorLen(VectorAdd(%pos, %vel)) > $RopeLength) {
//%mass = %obj.getDatablock().mass;
%rad = VectorSub($GrapplePoint, %pos);
%radx = getWord(%rad, 0); %velx = getWord(%vel, 0);
%rady = getWord(%rad, 1); %vely = getWord(%vel, 1);
%radz = getWord(%rad, 2); %velz = getWord(%vel, 2);
%radH = mSqrt(%radx * %radx + %rady * %rady);
%VelH = mSqrt(%velx * %velx + %vely * %vely);
%VecH = %velx SPC %vely SPC "0";
%radVel = ((%radx * velx) + (%rady * %vely)) / %radH;
//%tanVel = mSqrt(%VelH * %velH - %radVel * %radVel);
%tanDir = VectorCross(%rad, "0 0 10");
%tanx = getWord(%tanDir, 0); %tany = getWord(%tanDir, 1);
%tanVel = (%velx * %tanx + %vely * %tany) / VectorLen(%tanDir);
%tanVec = VectorScale(VectorNormalize(%tanDir), %tanVel);
%radVec = VectorScale(VectorNormalize(%rad), -%radVel);
%radVecH = getWord(%radVec, 0) SPC getWord(%radVec, 1) SPC "0";
if (mSgn(getWord(VectorAdd(%radVecH, %tanVec), 0)) != mSgn(getWord(VectorNormalize(%VecH), 0))
&& mSgn(getWord(VectorAdd(%radVecH, %tanVec), 1)) != mSgn(getWord(VectorNormalize(%VecH), 1))) {
%tanVec = VectorScale(%tanVec, -1);
}
%newVel = VectorScale(VectorNormalize(%tanVec), VectorLen(%tanVel));
%ZtanDir = VectorCross(%rad, %tanDir);
if (mSgn(getWord(%ZtanDir, 0)) != mSgn(getWord(%vel, 0))
&& mSgn(getWord(%ZtanDir, 1)) != mSgn(getWord(%vel, 1)))
%ZtanDir = VectorScale(%ZtanDir, -1);
%Ztanx = getWord(%ZtanDir, 0); %Ztany = getWord(%ZtanDir, 1); %Ztanz = getWord(%ZtanDir, 2);
%ZtanH = mSqrt(%Ztanx * %Ztanx + %Ztany * %Ztany);
%Zvel = (%velH * %ZtanH + %velz * %Ztanz) / VectorLen(%ZtanDir);
%newZVec = VectorScale(VectorNormalize(%ZtanDir), %Zvel);
if (mSgn(%radz) == 1 && mSgn(%velz) == -1)
%newVel = VectorAdd(%newVel, "0 0 5");
%newVel = VectorAdd(%newVel, %newZVec);
%newVel = VectorAdd(%newVel, VectorScale(VectorNormalize(%rad), $TractorPower));
$RopeLength = $RopeLength - $TractorPower;
%obj.setVelocity(%newVel);
echo("Applying force:" SPC %force);
}
%obj.reelSchedule = %obj.schedule(250, "reelIn");
}
}
}
function GrapplingHookImage::deconstruct(%data, %obj, %slot)
{
if (isObject(%obj.lastProjectile))
{
%obj.lastProjectile.delete();
%obj.lastProjectile = "";
}
%obj.grapplePos = "";
if(isEventPending(%obj.grappleSchedule))
cancel(%obj.grappleSchedule);
if(isEventPending(%obj.reelSchedule))
cancel(%obj.reelSchedule);
%obj.use(%obj.prevWeapon);
}
function mSgn(%value) {
if (%value == 0) return "0";
else return %value / mAbs(%value);
}