[T2] Vengeance mod

In that case, I better post what I have for the grappler. Note that I couldn't test it on players yet.

Code:
//--------------------------------------------------------------------- 
// Grapple Hook 
// 6/11/2004 - June 11, 2004 
// Made by Lt Earthworm (looks/sounds) and Amadeu5 (physics)
//    I actually made this on impulse. I watched a Tribes : Vengeance 
// video with the grappling hook in it and though it was really awesome. 
// I did not want to wait until the game was out to be able to use it, 
// Thus, the Tribes 2 Grappling Hook is born. 
//--------------------------------------------------------------------- 


$GrappleHook::MaxLength = 75;      // Max length of grapple hook
$GrappleHook::UseOtherWeapons = 1; // Ability to use other weapons while grappled. 0 for no, 1 for yes 
$GrappleHook::RopeStrength = 1.3;	// How much can we stretch the rope before it breaks.
$GrappleHook::ScheduleTime = 35; 

datablock AudioProfile(GrappleLineBreakSound)
{
   filename = "fx/weapons/cg_metal2.wav";
   description = AudioDefault3d;
   preload = true;
   effect = TargetingLaserPaintEffect;
};

datablock AudioProfile(GrappleFireSound)
{
   filename = "fx/vehicles/bomber_bomb_dryfire.wav"; // shrike_blaster_projectile_impact.wav
   description = AudioDefault3d;
   preload = true;
   effect = TargetingLaserPaintEffect;
};

datablock AudioProfile(GrappleMissSound)
{
   filename = "fx/vehicles/crash_grav_soft.wav";
   description = AudioDefault3d;
   preload = true;
   effect = TargetingLaserSwitchEffect;
};

datablock TargetProjectileData(GrappleBeam) : BasicTargeter
{
   maxRifleRange = 100;
   beamColor = "0.3 0.3 0.3";

   pulseBeamWidth = 0;
   beamFlareAngle = 0;
   maxFlareSize = 0;
   pulseSpeed = 0;
   pulseLength = 0;

   coupleBeam = 0;
   beacon = false;
};

datablock ItemData(GrapplingHook) : ELFGun
{
   shapeFile = "weapon_elf.dts";
   image = GrapplingHookImage;
   pickUpName = "a grappling hook";
};

datablock ShapeBaseImageData(GrapplingHookImage)
{
   className = WeaponImage;
   shapeFile = "weapon_elf.dts";
   item = GrapplingHook;

   projectile = GrappleBeam;
   projectileType = TargetProjectile;
   deleteLastProjectile = true;

   usesEnergy = true;
   fireEnergy = 1;
   minEnergy = 1;

   stateName[0] = "Activate";
   stateTransitionOnTimeout[0] = "ActivateReady";
   stateTimeoutValue[0] = 0.5;
   stateSequence[0] = "Activate";
   stateSound[0] = BlasterSwitchSound;

   stateName[1] = "ActivateReady";
   stateTransitionOnLoaded[1] = "Ready";
   stateTransitionOnNoAmmo[1] = "NoAmmo";

   stateName[2] = "Ready";
   stateTransitionOnNoAmmo[2] = "NoAmmo";
   stateTransitionOnTriggerDown[2] = "Fire";

   stateName[3] = "Fire";
   stateTransitionOnTimeout[3] = "Reload";
   stateTimeoutValue[3] = 0.3;
   stateFire[3] = true;
   stateRecoil[3] = NoRecoil;
   stateAllowImageChange[3] = false;
   stateSequence[3] = "Fire";
   //stateSound[3] = GrappleFireSound;
   stateScript[3] = "onFire";

   stateName[4] = "Reload";
   stateTransitionOnNoAmmo[4] = "NoAmmo";
   stateTransitionOnTimeout[4] = "Ready";
   stateAllowImageChange[4] = false;
   stateSequence[4] = "Reload";

   stateName[5] = "NoAmmo";
   stateTransitionOnAmmo[5] = "Reload";
   stateSequence[5] = "NoAmmo";
   stateTransitionOnTriggerDown[5] = "DryFire";

   stateName[6] = "DryFire";
   stateTimeoutValue[6] = 0.3;
   stateSound[6] = BlasterDryFireSound;
   stateTransitionOnTimeout[6] = "Ready";
};

// Functions 

function GrapplingHookImage::onFire(%data, %player, %slot)
{
   // If the player has already grappled and if so remove the grapple
   if(%player.isHooked)
   {
      %player.disengageGrapple();
      return;
   }

   // ZOD - lets do this a little differently
   %p = Parent::onFire(%data, %player, %slot);
   if(isObject(%p))
   {
      %pPos = getWord(%p.getTargetPoint(), 0) SPC
              getWord(%p.getTargetPoint(), 1) SPC
              getWord(%p.getTargetPoint(), 2);
   }

   // Get the muzzle position
   %point = %player.getMuzzlePoint(%slot);

   // Get the muzzle vector
   %vector = %player.getMuzzleVector(%slot);
   %vector = vectorScale(%vector, $GrappleHook::MaxLength);

   // Get the end point for the Raycast
   %endPoint = vectorAdd(%point, %vector);

   // Stuff to look for
   %mask = $TypeMasks::InteriorObjectType | $TypeMasks::StaticShapeObjectType |
           $TypeMasks::PlayerObjectType | $TypeMasks::VehicleObjectType |
           $TypeMasks::TerrainObjectType | $TypeMasks::ForceFieldObjectType |
           $TypeMasks::StaticTSObjectType;

   // Raycast to see if we hit anything 
   %search = containerRayCast(%point, %endPoint, %mask, %player);

   // Nothing found. Can't do anything else
   if(!%search) 
   {
      serverPlay3D(GrappleMissSound, %player.getTransform());
      if(isObject(%p))
         %p.delete();

      return;
   }

   // Play the latch on sound
   serverPlay3D(GrappleFireSound, %player.getTransform());

   // We start off with an intact rope
   %player.LineIsBroken = false;

   %hitObj = FirstWord(%search);
   // Don't want to grapple onto those - ZOD, pfft
   if( %hitObj.getType() & ($TypeMasks::TerrainObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::InteriorObjectType) )
      %RayPos = %pPos;

   // Yay! We hit something we can grapple!
   %player.isHooked = true;

   // get the position from the raycast
   if(%search)
      %RayPos = posFromRaycast(%search);

   // Get the vector lenght from %point to %RayPos
   %player.grappleLength = vectorLen(vectorSub(%point, %RayPos));

   if(isObject(%player.lastProjectile))
      %player.lastProjectile.delete();

   if(%hitObj && (%hitObj.getType() & ($TypeMasks::PlayerObjectType | $TypeMasks::VehicleObjectType)))
      %player.moveGrappleSwingLoop(%hitObj); // They got a moving object! 
   else // Fixed grapple
      %player.fixedGrappleSwingLoop(%RayPos);
}

function Player::fixedGrappleSwingLoop(%player, %SwingPos)
{
   if(!isObject(%player))
      return;

   if(isEventPending(%player.grappleSchedule)) 
      cancel(%player.grappleSchedule);

   if(isObject(%player.rope))
      %player.rope.delete();

   if(%player.isHooked == false)
      return;

   if(%player.getState() !$= "Dead")
   {
      %vel = %player.getVelocity();
      %pos = %player.getPosition();
      %rad = VectorSub(%SwingPos, %pos);
      %dist = VectorLen(%rad);

      // Ugly vector math beyond this point, keep out if you don't know what you're doing

      if (%dist > %player.grappleLength &&
          VectorLen(VectorSub(%SwingPos, VectorAdd(%pos, %vel))) > %player.grappleLength) {
	%force = VectorProject(%vel, %rad);
	%surplus = %dist - %player.grappleLength;
	%tanVel = VectorProject(%vel, VectorCross(%rad, VectorCross(%rad, %vel)));
	%value = %tanVel+(getWord(%rad, 2)/%player.grappleLength)*%force;

	// Break the line if there's too much stress on it
	if (%value / %player.grappleLength > $GrappleHook::RopeStrength) {
		%player.LineIsBroken = true;
		%player.disengageGrapple();
	}

	else {
		%mass = %player.getDataBlock().mass;
		%vec = VectorScale(VectorNormalize(%rad), (%dist / %player.grappleLength) * mAbs(%force) * %mass / 2);
		%player.ApplyImpulse(%player.getPosition(), %vec);
	}
      		
       }

      // Create the rope
      %player.rope = new TargetProjectile() {
         datablock = GrappleBeam;
         sourceSlot = 0;
         //sourceObject = %player;
         initialPosition = %player.getMuzzlePoint(0);
         initialDirection = %rad;
      };
      // Add it to the MissionCleanup Simgroup
      MissionCleanup.add(%player.rope);

      %player.grappleSchedule = %player.schedule($GrappleHook::ScheduleTime, "fixedGrappleSwingLoop", %SwingPos);
   }
}

function Player::moveGrappleSwingLoop(%player, %followObj)
{
   if(!isObject(%player))
      return;

   if(isEventPending(%player.grappleSchedule)) 
      cancel(%player.grappleSchedule);

   if(isObject(%player.rope))
      %player.rope.delete();

   // Stop if they have un-grappled
   if(%player.isHooked == false)
      return;

   if(%player.getState() !$= "Dead")
   {
      // Can't quite grapple to a non-existent object, can you?
      if(!isObject(%followObj))
         return;

      %SwingPos = %followObj.getPosition();
      %vel = %player.getVelocity();
      %pos = %player.getPosition();
      %rad = VectorSub(%SwingPos, %pos);
      %dist = VectorLen(%rad);

      // Ugly vector math beyond this point, keep out if you don't know what you're doing

      if (%dist > %player.grappleLength &&
          VectorLen(VectorSub(%SwingPos, VectorAdd(%pos, %vel))) > %player.grappleLength) {
	%force = VectorProject(%vel, %rad);
	%surplus = %dist - %player.grappleLength;
	%tanVel = VectorProject(%vel, VectorCross(%rad, VectorCross(%rad, %vel)));
	%value = %tanVel+(getWord(%rad, 2)/%player.grappleLength)*%force;

	//Break the line if there's too much stress on it
	if (%value / %player.grappleLength > $GrappleHook::RopeStrength) {
		%player.LineIsBroken = true;
		%player.disengageGrapple();
	}

	else {
		%mass = %player.getDataBlock().mass;
		%vec = VectorScale(VectorNormalize(%rad), (%dist / %player.grappleLength) * mAbs(%force) * %mass / 2);
		%player.ApplyImpulse(%player.getPosition(), %vec);

		// Let's not leave the poor bastard alone
		%followObj.applyImpulse(%followObj.getPosition, VectorScale(%vec, 1/%followObj.getDatablock().mass));
	}
       }

      // Create the rope
      %player.rope = new TargetProjectile() {
         datablock = GrappleBeam;
         sourceSlot = 0;
         //sourceObject = %player;
         initialPosition = %player.getMuzzlePoint(0);
         initialDirection = %vec;
      };

      // Add it to the MissionCleanup Simgroup
      MissionCleanup.add(%player.rope);

      %player.grappleSchedule = %player.schedule($GrappleHook::ScheduleTime, "moveGrappleSwingLoop", %followObj);
   }
}

function Player::disengageGrapple(%player)
{
   // Un-Grapple the player
   %player.isHooked = false;
   // If we were clumsy and broke the line then play a sound
   if (%player.LineIsBroken) serverPlay3D(GrappleLineBreakSound, %player.getTransform());
   if(isObject(%player.rope))
      %player.rope.delete();

   if(isEventPending(%player.grappleSchedule)) 
      cancel(%player.grappleSchedule);
}

function GrappleHookImage::onUnmount(%data, %player, %slot)
{
   if(!$GrappleHook::UseOtherWeapons)
      DisengageGrapple(%player);
}

function VectorProject(%vec, %target) {
	return ((getWord(%vec, 0)*getWord(%target, 0))
	       + (getWord(%vec, 1)*getWord(%target, 1))
	       + (getWord(%vec, 2)*getWord(%target, 2))) / VectorLen(%target);
}


Btw entering an invo should disengage the grappler, as you can now grapple onto something and switch to a different loadout with no hook.
 
Amadeu5, as the beam cannot be visible for the grappler, could you add something to make the attachment point easier to see, other than the buggy collision point? A task or waypoint should do.
 
dr_boom said:
Good work Zod, this is really cool :)
Only ZOD? What about all the little people (aka his slaves) :p


Amadeu5, just messed with the grappler to add a task for the player at the position of the grapple point.
There's only one major bug with this method, you cant see any other tasks.
The other method would be to send the position to the client, which in turn the client creates a waypoint. But that would require some client-side scripting, and I know how you dislike that.

Code:
//--------------------------------------------------------------------- 
// Grapple Hook 
// 6/11/2004 - June 11, 2004 
// Made by Lt Earthworm (looks/sounds) and Amadeu5 (physics)
//    I actually made this on impulse. I watched a Tribes : Vengeance 
// video with the grappling hook in it and though it was really awesome. 
// I did not want to wait until the game was out to be able to use it, 
// Thus, the Tribes 2 Grappling Hook is born. 
//---------------------------------------------------------------------  


$GrappleHook::MaxLength = 75;      // Max length of grapple hook
$GrappleHook::UseOtherWeapons = 1; // Ability to use other weapons while grappled. 0 for no, 1 for yes 
$GrappleHook::ImpulseScale = 150;  // How bungee like the grapple is. Lower # = > bungee
$GrappleHook::ScheduleTime = 35; 
$GrappleHook::RopeStrength = 1.3;  // Amadeu5 - How much can we stretch the rope before it breaks.

datablock AudioProfile(GrappleLineBreakSound)
{
   filename = "fx/weapons/cg_metal2.wav";
   description = AudioDefault3d;
   preload = true;
   effect = TargetingLaserPaintEffect;
};

datablock AudioProfile(GrappleFireSound)
{
   filename = "fx/vehicles/bomber_bomb_dryfire.wav";
   description = AudioDefault3d;
   preload = true;
   effect = TargetingLaserPaintEffect;
};

datablock AudioProfile(GrappleMissSound)
{
   filename = "fx/vehicles/crash_grav_soft.wav";
   description = AudioDefault3d;
   preload = true;
   effect = TargetingLaserSwitchEffect;
};

datablock TargetProjectileData(GrappleBeam) : BasicTargeter
{
   maxRifleRange = 100;
   beamColor = "0.3 0.3 0.3";

   pulseBeamWidth = 0;
   beamFlareAngle = 0;
   maxFlareSize = 0;
   pulseSpeed = 0;
   pulseLength = 0;

   coupleBeam = 0;
   beacon = false;
};

datablock ItemData(GrapplingHook) : ELFGun
{
   shapeFile = "weapon_elf.dts";
   image = GrapplingHookImage;
   pickUpName = "a grappling hook";
};

datablock ShapeBaseImageData(GrapplingHookImage)
{
   className = WeaponImage;
   shapeFile = "weapon_elf.dts";
   item = GrapplingHook;

   projectile = GrappleBeam;
   projectileType = TargetProjectile;
   deleteLastProjectile = true;

   usesEnergy = true;
   fireEnergy = 1;
   minEnergy = 1;

   stateName[0] = "Activate";
   stateTransitionOnTimeout[0] = "ActivateReady";
   stateTimeoutValue[0] = 0.5;
   stateSequence[0] = "Activate";
   stateSound[0] = BlasterSwitchSound;

   stateName[1] = "ActivateReady";
   stateTransitionOnLoaded[1] = "Ready";
   stateTransitionOnNoAmmo[1] = "NoAmmo";

   stateName[2] = "Ready";
   stateTransitionOnNoAmmo[2] = "NoAmmo";
   stateTransitionOnTriggerDown[2] = "Fire";

   stateName[3] = "Fire";
   stateTransitionOnTimeout[3] = "Reload";
   stateTimeoutValue[3] = 0.3;
   stateFire[3] = true;
   stateRecoil[3] = NoRecoil;
   stateAllowImageChange[3] = false;
   stateSequence[3] = "Fire";
   //stateSound[3] = GrappleFireSound;
   stateScript[3] = "onFire";

   stateName[4] = "Reload";
   stateTransitionOnNoAmmo[4] = "NoAmmo";
   stateTransitionOnTimeout[4] = "Ready";
   stateAllowImageChange[4] = false;
   stateSequence[4] = "Reload";

   stateName[5] = "NoAmmo";
   stateTransitionOnAmmo[5] = "Reload";
   stateSequence[5] = "NoAmmo";
   stateTransitionOnTriggerDown[5] = "DryFire";

   stateName[6] = "DryFire";
   stateTimeoutValue[6] = 0.3;
   stateSound[6] = BlasterDryFireSound;
   stateTransitionOnTimeout[6] = "Ready";
};

datablock StaticShapeData(GrappleTarget)
{   
   className = Static;
   shapeFile = "turret_muzzlepoint.dts";
   isInvincible = true;
   dynamicType = $TypeMasks::StaticObjectType;
   targetNameTag = 'Grapple';
   targetTypeTag = 'Target';
   heatSignature = 0.0;
};

// Functions 

function GrapplingHookImage::onFire(%data, %player, %slot)
{
   // If the player has already grappled and if so remove the grapple
   if(%player.isHooked)
   {
      %player.disengageGrapple();
      return;
   }

   // ZOD - lets do this a little differently
   %p = Parent::onFire(%data, %player, %slot);
   if(isObject(%p))
   {
      %pPos = getWord(%p.getTargetPoint(), 0) SPC
              getWord(%p.getTargetPoint(), 1) SPC
              getWord(%p.getTargetPoint(), 2);
   }

   // Get the muzzle position
   %point = %player.getMuzzlePoint(%slot);

   // Get the muzzle vector
   %vector = %player.getMuzzleVector(%slot);
   %vector = vectorScale(%vector, $GrappleHook::MaxLength);

   // Get the end point for the Raycast
   %endPoint = vectorAdd(%point, %vector);

   // Stuff to look for
   %mask = $TypeMasks::InteriorObjectType | $TypeMasks::StaticShapeObjectType |
           $TypeMasks::PlayerObjectType | $TypeMasks::VehicleObjectType |
           $TypeMasks::TerrainObjectType | $TypeMasks::ForceFieldObjectType |
           $TypeMasks::StaticTSObjectType;

   // Raycast to see if we hit anything 
   %search = containerRayCast(%point, %endPoint, %mask, %player);

   // Nothing found. Can't do anything else
   if(!%search) 
   {
      serverPlay3D(GrappleMissSound, %player.getTransform());
      if(isObject(%p))
         %p.delete();

      return;
   }

   // Play the latch on sound
   serverPlay3D(GrappleFireSound, %player.getTransform());

   // Amadeu5 - We start off with an intact rope
   %player.LineIsBroken = false;

   %hitObj = FirstWord(%search);
   // Don't want to grapple onto those - ZOD, pfft
   if( %hitObj.getType() & ($TypeMasks::TerrainObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::InteriorObjectType) )
      %RayPos = %pPos;

   // Yay! We hit something we can grapple!
   %player.isHooked = true;

   // get the position from the raycast
   if(%search)
      %RayPos = posFromRaycast(%search);

   // Get the vector lenght from %point to %RayPos
   %player.grappleLength = vectorLen(vectorSub(%point, %RayPos));

   if(isObject(%player.lastProjectile))
      %player.lastProjectile.delete();

   // Add an object for the task
   %player.ropeTarget = new(StaticShape)() {
      dataBlock = GrappleTarget;
   };
   %player.ropeTarget.setTransform(%RayPos SPC "0 0 0 0");
   MissionCleanup.add(%player.ropeTarget);

   if(%hitObj && (%hitObj.getType() & ($TypeMasks::PlayerObjectType | $TypeMasks::VehicleObjectType)))
      %player.moveGrappleSwingLoop(%hitObj); // They got a moving object! 
   else // Fixed grapple
      %player.fixedGrappleSwingLoop(%RayPos);
}

function Player::fixedGrappleSwingLoop(%player, %SwingPos)
{
   if(!isObject(%player))
      return;

   if(isEventPending(%player.grappleSchedule)) 
      cancel(%player.grappleSchedule);

   if(isObject(%player.rope))
      %player.rope.delete();

   if(%player.isHooked == false)
      return;

   if(%player.getState() !$= "Dead")
   {
      // Amadeu5
      %vel = %player.getVelocity();
      %pos = %player.getPosition();
      %rad = VectorSub(%SwingPos, %pos);
      %dist = VectorLen(%rad);
      // Ugly vector math beyond this point, keep out if you don't know what you're doing
      if(%dist > %player.grappleLength && VectorLen(VectorSub(%SwingPos, VectorAdd(%pos, %vel))) > %player.grappleLength)
      {
         %force = VectorProject(%vel, %rad);
         %surplus = %dist - %player.grappleLength;
         %tanVel = VectorProject(%vel, VectorCross(%rad, VectorCross(%rad, %vel)));
         %value = %tanVel+(getWord(%rad, 2)/%player.grappleLength) * %force;

         // Break the line if there's too much stress on it
         if(%value / %player.grappleLength > $GrappleHook::RopeStrength)
         {
            %player.LineIsBroken = true;
            %player.disengageGrapple();
            return;
         }
         else
         {
            %mass = %player.getDataBlock().mass;
            %vec = VectorScale(VectorNormalize(%rad), (%dist / %player.grappleLength) * mAbs(%force) * %mass / 2);
            %player.ApplyImpulse(%player.getPosition(), %vec);
         }
      }
      // End Amadeu5

      // Create the rope
      %player.rope = new TargetProjectile() {
         datablock = GrappleBeam;
         sourceSlot = 0;
         //sourceObject = %player;
         initialPosition = %player.getMuzzlePoint(0);
         initialDirection = %vec;
      };
      // Add it to the MissionCleanup Simgroup
      MissionCleanup.add(%player.rope);

      %player.client.setTargetId(%player.ropetarget.target);
      // Add a null task info, as to not use the previous tasks info and name
      commandToClient(%player.client, 'TaskInfo', %player.client, -1, false, "");
      %player.client.sendTargetTo(%player.client, true);

      %player.grappleSchedule = %player.schedule($GrappleHook::ScheduleTime, "fixedGrappleSwingLoop", %SwingPos);
   }
}

function Player::moveGrappleSwingLoop(%player, %followObj)
{
   if(!isObject(%player))
      return;

   if(isEventPending(%player.grappleSchedule)) 
      cancel(%player.grappleSchedule);

   if(isObject(%player.rope))
      %player.rope.delete();

   // Stop if they have un-grappled
   if(%player.isHooked == false)
      return;

   if(%player.getState() !$= "Dead")
   {
      // Can't quite grapple to a non-existent object, can you?
      if(!isObject(%followObj))
         return;

      // Amadeu5
      %SwingPos = %followObj.getPosition();
      %vel = %player.getVelocity();
      %pos = %player.getPosition();
      %rad = VectorSub(%SwingPos, %pos);
      %dist = VectorLen(%rad);

      // Ugly vector math beyond this point, keep out if you don't know what you're doing
      if(%dist > %player.grappleLength && VectorLen(VectorSub(%SwingPos, VectorAdd(%pos, %vel))) > %player.grappleLength)
      {
         %force = VectorProject(%vel, %rad);
         %surplus = %dist - %player.grappleLength;
         %tanVel = VectorProject(%vel, VectorCross(%rad, VectorCross(%rad, %vel)));
         %value = %tanVel+(getWord(%rad, 2)/%player.grappleLength) * %force;

         //Break the line if there's too much stress on it
         if(%value / %player.grappleLength > $GrappleHook::RopeStrength)
         {
            %player.LineIsBroken = true;
            %player.disengageGrapple();
            return;
         }
         else
         {
            %mass = %player.getDataBlock().mass;
            %vec = VectorScale(VectorNormalize(%rad), (%dist / %player.grappleLength) * mAbs(%force) * %mass / 2);
            %player.ApplyImpulse(%player.getPosition(), %vec);
            // Let's not leave the poor bastard alone
            %followObj.applyImpulse(%followObj.getPosition, VectorScale(%vec, 1/%followObj.getDatablock().mass));
         }
      }
      // End Amadeu5

      // Create the rope
      %player.rope = new TargetProjectile() {
         datablock = GrappleBeam;
         sourceSlot = 0;
         //sourceObject = %player;
         initialPosition = %player.getMuzzlePoint(0);
         initialDirection = %vec;
      };
      // Add it to the MissionCleanup Simgroup
      MissionCleanup.add(%player.rope);

      %player.client.setTargetId(%player.ropetarget.target);
      // Add a null task info, as to not use the previous tasks info and name
      commandToClient(%player.client, 'TaskInfo', %player.client, -1, false, "");
      %player.client.sendTargetTo(%player.client, true);

      %player.grappleSchedule = %player.schedule($GrappleHook::ScheduleTime, "moveGrappleSwingLoop", %followObj);
   }
}

function Player::disengageGrapple(%player)
{
   // Un-Grapple the player
   %player.isHooked = false;

   // Amadeu5 - If we were clumsy and broke the line then play a sound
   if (%player.LineIsBroken)
      serverPlay3D(GrappleLineBreakSound, %player.getTransform());

   if(isObject(%player.rope))
      %player.rope.delete();

   if(isObject(%player.ropeTarget))
      %player.ropeTarget.delete();

   if(isEventPending(%player.grappleSchedule)) 
      cancel(%player.grappleSchedule);
}

function GrappleHookImage::onUnmount(%data, %player, %slot)
{
   if(!$GrappleHook::UseOtherWeapons)
      DisengageGrapple(%player);
}

// Amadeu5
function VectorProject(%vec, %target)
{
   return ((getWord(%vec, 0)*getWord(%target, 0)) +
          (getWord(%vec, 1)*getWord(%target, 1)) +
          (getWord(%vec, 2)*getWord(%target, 2))) / 
          VectorLen(%target);
}
 
ilys said:
Only ZOD? What about all the little people (aka his slaves) :p


Amadeu5, just messed with the grappler to add a task for the player at the position of the grapple point.
There's only one major bug with this method, you cant see any other tasks.
The other method would be to send the position to the client, which in turn the client creates a waypoint. But that would require some client-side scripting, and I know how you dislike that.
I can just beacon the end of the beam :kiss:
 
ilys said:
Only ZOD? What about all the little people (aka his slaves) :p


Amadeu5, just messed with the grappler to add a task for the player at the position of the grapple point.
There's only one major bug with this method, you cant see any other tasks.
The other method would be to send the position to the client, which in turn the client creates a waypoint. But that would require some client-side scripting, and I know how you dislike that.
First of all, I can see the line just fine. Maybe it's something in your settings? :shrug:

Second, I have nothing wrong with client side scripting. In fact, I made some client side scripts for T1 completely from scratch, as well as modified the Viking huds to look like the Presto config I used earlier. I have no idea where you got this from :)

(although it could be that T2 will piss me off enough that I never touch it again... :) )
 
ZOD said:
I can just beacon the end of the beam :kiss:
Yeah, but that is visible to the whole team.
Amadeu5 said:
First of all, I can see the line just fine. Maybe it's something in your settings? :shrug:

Second, I have nothing wrong with client side scripting. In fact, I made some client side scripts for T1 completely from scratch, as well as modified the Viking huds to look like the Presto config I used earlier. I have no idea where you got this from :)

(although it could be that T2 will piss me off enough that I never touch it again... :) )
The grapples TargetProjectileData does not have any width to it, so the grey beam is not visible.
Code:
datablock TargetProjectileData(GrappleBeam) : BasicTargeter
{
   maxRifleRange = 100;
   beamColor = "0.3 0.3 0.3";

   pulseBeamWidth = 0;
   beamFlareAngle = 0;
   maxFlareSize = 0;
   pulseSpeed = 0;
   pulseLength = 0;

   coupleBeam = 0;
   beacon = false;
};
However, even if it were visible there are some bugs with it. The TargetProjectile's end needs to be in line-of-sight of the player, or the beam will go vertical. Same goes for the dot. That is a limit of the TargetProjectileData.

As for the second point, I thought you were someone else but looking back at the topic it was plasmatic.
 
I think he must have been using a hook skin cheat. :)

It should be more visible though. It looks (and even feels a little) like a rubber band.

I also noticed a tendency to experience 'key bounce' which results in attatchment-detatchment.
 
ZOD said:
I dunno what Ilys is talking about, I can always see the beam and where it attached :shrug:

Splain yourself code slave!
How can you see a beam when it has no width?
Code:
datablock TargetProjectileData(GrappleBeam) : BasicTargeter
{
   maxRifleRange = 100;
   beamColor = "0.3 0.3 0.3";

   pulseBeamWidth = 0;
   beamFlareAngle = 0;
   maxFlareSize = 0;
   pulseSpeed = 0;
   pulseLength = 0;

   coupleBeam = 0;
   beacon = false;
};
I'll take some pics to show you what I mean. BRB.

EDIT:
With the code as is, there is no beam
http://ilys.nope.org/nobeam.JPG
With pulseBeamWidth = 1;
http://ilys.nope.org/skybeam.JPG
That also shows the LOS bug. The grapple is attached to the roof.
 
Last edited:
Back
Top