I modified Amadeus's grapplinghook.cs
// We cancel schedules when player switches to another weapon -
// WeaponImage:
nUnmount and DefaultGame:
nClientKilled
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:
nFire(%data, %obj, %slot)
{
//error("GrapplingHookImage:
nFire(" SPC %data.getName() SPC %obj.client.nameBase SPC %slot SPC ")");
%p = Parent:
nFire(%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;
}
//$rad = %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");
%vel = %obj.getVelocity();
%mass = %obj.getDatablock().mass;
%pos = %obj.getWorldBoxCenter();
%rad = VectorSub($GrapplePoint, %pos);
//%radRec = (1 / getWord(%rad, 0)) SPC (1 / getWord(%rad, 1)) SPC (1 / getWord(%rad, 2));
%dist = VectorDist(%pos, $GrapplePoint);
%force = VectorScale(%rad, %mass / (8.5*%dist));
%newVel = VectorAdd(%vel, %force);
%obj.setVelocity(%newVel);
echo("***********" NL "pos:" SPC %pos NL "GP:" SPC $GrapplePoint NL
"rad:" SPC %rad NL "radRec:" SPC %radrec NL "vel:" SPC %vel NL
"force:" SPC %force NL "***********");
%obj.grappleSchedule = %obj.schedule(250, "grappleObject");
}
}
}
function GrapplingHookImage:
nReelIn(%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();
}
}
// was 5
$TractorPower = 5;
function Player::reelIn(%obj)
{
if(isObject(%obj))
{
if(isEventPending(%obj.reelSchedule))
cancel(%obj.reelSchedule);
if(%obj.getState() !$= "Dead")
{
//%vec = VectorNormalize(VectorSub(%obj.grapplePos, %obj.getMuzzlePoint($WeaponSlot)));
//%targetermass = %obj.getDatablock().mass;
//%targetmass = 20000;
//%mul = $TractorPower - ($TractorPower * %targetermass) / (%targetmass + %targetermass);
//%nvec = vectorScale(%vec, %mul);
//%obj.setVelocity(%nvec);
%vel = %obj.getVelocity();
%mass = %obj.getDatablock().mass;
%pos = %obj.getWorldBoxCenter();
%rad = VectorSub($GrapplePoint, %pos);
//%radRec = (1 / getWord(%rad, 0)) SPC (1 / getWord(%rad, 1)) SPC (1 / getWord(%rad, 2));
%dist = VectorDist(%pos, $GrapplePoint);
%force = VectorScale(%rad, %mass / (8.5*%dist));
%tracVel = VectorScale(VectorNormalize(%rad), $TractorPower);
// %newVel = VectorAdd(VectorAdd(%vel, %force), %tracVel);
//JLB vvvvvvvvvvv
%newVel = VectorAdd(%vel, %tracVel);
%obj.setVelocity(%newVel);
%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);
}
It behaves a little better. (less forcefull by default). However, you can still generate great speed by either continuing to hold the 'fire' on the hook or by jetting. You can get a gentler 'swing' by firing the hook and releasing immediately. The reel force is weak. You must provide initial momentum.
We could try something like this while Amadeus finishes his work on his new approach.