mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-24 22:54:50 +00:00
644 lines
22 KiB
C#
644 lines
22 KiB
C#
//-----------------------------------------------------------------------------
|
|
// Copyright (c) 2012 GarageGames, LLC
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to
|
|
// deal in the Software without restriction, including without limitation the
|
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
// sell copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
// IN THE SOFTWARE.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// This file contains Weapon and Ammo Class/"namespace" helper methods as well
|
|
// as hooks into the inventory system. These functions are not attached to a
|
|
// specific C++ class or datablock, but define a set of methods which are part
|
|
// of dynamic namespaces "class". The Items include these namespaces into their
|
|
// scope using the ItemData and ItemImageData "className" variable.
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// All ShapeBase images are mounted into one of 8 slots on a shape. This weapon
|
|
// system assumes all primary weapons are mounted into this specified slot:
|
|
$WeaponSlot = 0;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Weapon Class
|
|
//-----------------------------------------------------------------------------
|
|
|
|
function Weapon::onUse(%data, %obj)
|
|
{
|
|
// Default behavior for all weapons is to mount it into the object's weapon
|
|
// slot, which is currently assumed to be slot 0
|
|
if (%obj.getMountedImage($WeaponSlot) != %data.image.getId())
|
|
{
|
|
serverPlay3D(WeaponUseSound, %obj.getTransform());
|
|
|
|
%obj.mountImage(%data.image, $WeaponSlot);
|
|
if (%obj.client)
|
|
{
|
|
if (%data.description !$= "")
|
|
messageClient(%obj.client, 'MsgWeaponUsed', '\c0%1 selected.', %data.description);
|
|
else
|
|
messageClient(%obj.client, 'MsgWeaponUsed', '\c0Weapon selected');
|
|
}
|
|
|
|
// If this is a Player class object then allow the weapon to modify allowed poses
|
|
if (%obj.isInNamespaceHierarchy("Player"))
|
|
{
|
|
// Start by allowing everything
|
|
%obj.allowAllPoses();
|
|
|
|
// Now see what isn't allowed by the weapon
|
|
|
|
%image = %data.image;
|
|
|
|
if (%image.jumpingDisallowed)
|
|
%obj.allowJumping(false);
|
|
|
|
if (%image.jetJumpingDisallowed)
|
|
%obj.allowJetJumping(false);
|
|
|
|
if (%image.sprintDisallowed)
|
|
%obj.allowSprinting(false);
|
|
|
|
if (%image.crouchDisallowed)
|
|
%obj.allowCrouching(false);
|
|
|
|
if (%image.proneDisallowed)
|
|
%obj.allowProne(false);
|
|
|
|
if (%image.swimmingDisallowed)
|
|
%obj.allowSwimming(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
function Weapon::onPickup(%this, %obj, %shape, %amount)
|
|
{
|
|
// The parent Item method performs the actual pickup.
|
|
// For player's we automatically use the weapon if the
|
|
// player does not already have one in hand.
|
|
if (Parent::onPickup(%this, %obj, %shape, %amount))
|
|
{
|
|
serverPlay3D(WeaponPickupSound, %shape.getTransform());
|
|
if (%shape.getClassName() $= "Player" && %shape.getMountedImage($WeaponSlot) == 0)
|
|
%shape.use(%this);
|
|
}
|
|
}
|
|
|
|
function Weapon::onInventory(%this, %obj, %amount)
|
|
{
|
|
// Weapon inventory has changed, make sure there are no weapons
|
|
// of this type mounted if there are none left in inventory.
|
|
if (!%amount && (%slot = %obj.getMountSlot(%this.image)) != -1)
|
|
%obj.unmountImage(%slot);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Weapon Image Class
|
|
//-----------------------------------------------------------------------------
|
|
|
|
function WeaponImage::onMount(%this, %obj, %slot)
|
|
{
|
|
// Images assume a false ammo state on load. We need to
|
|
// set the state according to the current inventory.
|
|
if(%this.isField("clip"))
|
|
{
|
|
// Use the clip system for this weapon. Check if the player already has
|
|
// some ammo in a clip.
|
|
if (%obj.getInventory(%this.ammo))
|
|
{
|
|
%obj.setImageAmmo(%slot, true);
|
|
%currentAmmo = %obj.getInventory(%this.ammo);
|
|
}
|
|
else if(%obj.getInventory(%this.clip) > 0)
|
|
{
|
|
// Fill the weapon up from the first clip
|
|
%obj.setInventory(%this.ammo, %this.ammo.maxInventory);
|
|
%obj.setImageAmmo(%slot, true);
|
|
|
|
// Add any spare ammo that may be "in the player's pocket"
|
|
%currentAmmo = %this.ammo.maxInventory;
|
|
%amountInClips += %obj.getFieldValue( "remaining" @ %this.ammo.getName());
|
|
}
|
|
else
|
|
{
|
|
%currentAmmo = 0 + %obj.getFieldValue( "remaining" @ %this.ammo.getName());
|
|
}
|
|
|
|
%amountInClips = %obj.getInventory(%this.clip);
|
|
%amountInClips *= %this.ammo.maxInventory;
|
|
|
|
if (%obj.client !$= "" && !%obj.isAiControlled)
|
|
%obj.client.RefreshWeaponHud(%currentAmmo, %this.item.previewImage, %this.item.reticle, %this.item.zoomReticle, %amountInClips);
|
|
}
|
|
else if(%this.ammo !$= "")
|
|
{
|
|
// Use the ammo pool system for this weapon
|
|
if (%obj.getInventory(%this.ammo))
|
|
{
|
|
%obj.setImageAmmo(%slot, true);
|
|
%currentAmmo = %obj.getInventory(%this.ammo);
|
|
}
|
|
else
|
|
%currentAmmo = 0;
|
|
|
|
if (%obj.client !$= "" && !%obj.isAiControlled)
|
|
%obj.client.RefreshWeaponHud( 1, %this.item.previewImage, %this.item.reticle, %this.item.zoomReticle, %currentAmmo );
|
|
}
|
|
}
|
|
|
|
function WeaponImage::onUnmount(%this, %obj, %slot)
|
|
{
|
|
if (%obj.client !$= "" && !%obj.isAiControlled)
|
|
%obj.client.RefreshWeaponHud(0, "", "");
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// A "generic" weaponimage onFire handler for most weapons. Can be overridden
|
|
// with an appropriate namespace method for any weapon that requires a custom
|
|
// firing solution.
|
|
|
|
// projectileSpread is a dynamic property declared in the weaponImage datablock
|
|
// for those weapons in which bullet skew is desired. Must be greater than 0,
|
|
// otherwise the projectile goes straight ahead as normal. lower values give
|
|
// greater accuracy, higher values increase the spread pattern.
|
|
// ----------------------------------------------------------------------------
|
|
|
|
function WeaponImage::onFire(%this, %obj, %slot)
|
|
{
|
|
//echo("\c4WeaponImage::onFire( "@%this.getName()@", "@%obj.client.nameBase@", "@%slot@" )");
|
|
|
|
// Make sure we have valid data
|
|
if (!isObject(%this.projectile))
|
|
{
|
|
error("WeaponImage::onFire() - Invalid projectile datablock");
|
|
return;
|
|
}
|
|
|
|
// Decrement inventory ammo. The image's ammo state is updated
|
|
// automatically by the ammo inventory hooks.
|
|
if ( !%this.infiniteAmmo )
|
|
%obj.decInventory(%this.ammo, 1);
|
|
|
|
// Get the player's velocity, we'll then add it to that of the projectile
|
|
%objectVelocity = %obj.getVelocity();
|
|
|
|
%numProjectiles = %this.projectileNum;
|
|
if (%numProjectiles == 0)
|
|
%numProjectiles = 1;
|
|
|
|
for (%i = 0; %i < %numProjectiles; %i++)
|
|
{
|
|
if (%this.projectileSpread)
|
|
{
|
|
// We'll need to "skew" this projectile a little bit. We start by
|
|
// getting the straight ahead aiming point of the gun
|
|
%vec = %obj.getMuzzleVector(%slot);
|
|
|
|
// Then we'll create a spread matrix by randomly generating x, y, and z
|
|
// points in a circle
|
|
%matrix = "";
|
|
for(%j = 0; %j < 3; %j++)
|
|
%matrix = %matrix @ (getRandom() - 0.5) * 2 * 3.1415926 * %this.projectileSpread @ " ";
|
|
%mat = MatrixCreateFromEuler(%matrix);
|
|
|
|
// Which we'll use to alter the projectile's initial vector with
|
|
%muzzleVector = MatrixMulVector(%mat, %vec);
|
|
}
|
|
else
|
|
{
|
|
// Weapon projectile doesn't have a spread factor so we fire it using
|
|
// the straight ahead aiming point of the gun
|
|
%muzzleVector = %obj.getMuzzleVector(%slot);
|
|
}
|
|
|
|
// Add player's velocity
|
|
%muzzleVelocity = VectorAdd(
|
|
VectorScale(%muzzleVector, %this.projectile.muzzleVelocity),
|
|
VectorScale(%objectVelocity, %this.projectile.velInheritFactor));
|
|
|
|
// Create the projectile object
|
|
%p = new (%this.projectileType)()
|
|
{
|
|
dataBlock = %this.projectile;
|
|
initialVelocity = %muzzleVelocity;
|
|
initialPosition = %obj.getMuzzlePoint(%slot);
|
|
sourceObject = %obj;
|
|
sourceSlot = %slot;
|
|
client = %obj.client;
|
|
sourceClass = %obj.getClassName();
|
|
};
|
|
MissionCleanup.add(%p);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// A "generic" weaponimage onAltFire handler for most weapons. Can be
|
|
// overridden with an appropriate namespace method for any weapon that requires
|
|
// a custom firing solution.
|
|
// ----------------------------------------------------------------------------
|
|
|
|
function WeaponImage::onAltFire(%this, %obj, %slot)
|
|
{
|
|
//echo("\c4WeaponImage::onAltFire("@%this.getName()@", "@%obj.client.nameBase@", "@%slot@")");
|
|
|
|
// Decrement inventory ammo. The image's ammo state is updated
|
|
// automatically by the ammo inventory hooks.
|
|
%obj.decInventory(%this.ammo, 1);
|
|
|
|
// Get the player's velocity, we'll then add it to that of the projectile
|
|
%objectVelocity = %obj.getVelocity();
|
|
|
|
%numProjectiles = %this.altProjectileNum;
|
|
if (%numProjectiles == 0)
|
|
%numProjectiles = 1;
|
|
|
|
for (%i = 0; %i < %numProjectiles; %i++)
|
|
{
|
|
if (%this.altProjectileSpread)
|
|
{
|
|
// We'll need to "skew" this projectile a little bit. We start by
|
|
// getting the straight ahead aiming point of the gun
|
|
%vec = %obj.getMuzzleVector(%slot);
|
|
|
|
// Then we'll create a spread matrix by randomly generating x, y, and z
|
|
// points in a circle
|
|
%matrix = "";
|
|
for(%i = 0; %i < 3; %i++)
|
|
%matrix = %matrix @ (getRandom() - 0.5) * 2 * 3.1415926 * %this.altProjectileSpread @ " ";
|
|
%mat = MatrixCreateFromEuler(%matrix);
|
|
|
|
// Which we'll use to alter the projectile's initial vector with
|
|
%muzzleVector = MatrixMulVector(%mat, %vec);
|
|
}
|
|
else
|
|
{
|
|
// Weapon projectile doesn't have a spread factor so we fire it using
|
|
// the straight ahead aiming point of the gun.
|
|
%muzzleVector = %obj.getMuzzleVector(%slot);
|
|
}
|
|
|
|
// Add player's velocity
|
|
%muzzleVelocity = VectorAdd(
|
|
VectorScale(%muzzleVector, %this.altProjectile.muzzleVelocity),
|
|
VectorScale(%objectVelocity, %this.altProjectile.velInheritFactor));
|
|
|
|
// Create the projectile object
|
|
%p = new (%this.projectileType)()
|
|
{
|
|
dataBlock = %this.altProjectile;
|
|
initialVelocity = %muzzleVelocity;
|
|
initialPosition = %obj.getMuzzlePoint(%slot);
|
|
sourceObject = %obj;
|
|
sourceSlot = %slot;
|
|
client = %obj.client;
|
|
};
|
|
MissionCleanup.add(%p);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// A "generic" weaponimage onWetFire handler for most weapons. Can be
|
|
// overridden with an appropriate namespace method for any weapon that requires
|
|
// a custom firing solution.
|
|
// ----------------------------------------------------------------------------
|
|
|
|
function WeaponImage::onWetFire(%this, %obj, %slot)
|
|
{
|
|
//echo("\c4WeaponImage::onWetFire("@%this.getName()@", "@%obj.client.nameBase@", "@%slot@")");
|
|
|
|
// Decrement inventory ammo. The image's ammo state is updated
|
|
// automatically by the ammo inventory hooks.
|
|
%obj.decInventory(%this.ammo, 1);
|
|
|
|
// Get the player's velocity, we'll then add it to that of the projectile
|
|
%objectVelocity = %obj.getVelocity();
|
|
|
|
%numProjectiles = %this.projectileNum;
|
|
if (%numProjectiles == 0)
|
|
%numProjectiles = 1;
|
|
|
|
for (%i = 0; %i < %numProjectiles; %i++)
|
|
{
|
|
if (%this.wetProjectileSpread)
|
|
{
|
|
// We'll need to "skew" this projectile a little bit. We start by
|
|
// getting the straight ahead aiming point of the gun
|
|
%vec = %obj.getMuzzleVector(%slot);
|
|
|
|
// Then we'll create a spread matrix by randomly generating x, y, and z
|
|
// points in a circle
|
|
%matrix = "";
|
|
for(%j = 0; %j < 3; %j++)
|
|
%matrix = %matrix @ (getRandom() - 0.5) * 2 * 3.1415926 * %this.wetProjectileSpread @ " ";
|
|
%mat = MatrixCreateFromEuler(%matrix);
|
|
|
|
// Which we'll use to alter the projectile's initial vector with
|
|
%muzzleVector = MatrixMulVector(%mat, %vec);
|
|
}
|
|
else
|
|
{
|
|
// Weapon projectile doesn't have a spread factor so we fire it using
|
|
// the straight ahead aiming point of the gun.
|
|
%muzzleVector = %obj.getMuzzleVector(%slot);
|
|
}
|
|
|
|
// Add player's velocity
|
|
%muzzleVelocity = VectorAdd(
|
|
VectorScale(%muzzleVector, %this.wetProjectile.muzzleVelocity),
|
|
VectorScale(%objectVelocity, %this.wetProjectile.velInheritFactor));
|
|
|
|
// Create the projectile object
|
|
%p = new (%this.projectileType)()
|
|
{
|
|
dataBlock = %this.wetProjectile;
|
|
initialVelocity = %muzzleVelocity;
|
|
initialPosition = %obj.getMuzzlePoint(%slot);
|
|
sourceObject = %obj;
|
|
sourceSlot = %slot;
|
|
client = %obj.client;
|
|
};
|
|
MissionCleanup.add(%p);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Clip Management
|
|
//-----------------------------------------------------------------------------
|
|
|
|
function WeaponImage::onClipEmpty(%this, %obj, %slot)
|
|
{
|
|
//echo("WeaponImage::onClipEmpty: " SPC %this SPC %obj SPC %slot);
|
|
|
|
// Attempt to automatically reload. Schedule this so it occurs
|
|
// outside of the current state that called this method
|
|
%this.schedule(0, "reloadAmmoClip", %obj, %slot);
|
|
}
|
|
|
|
function WeaponImage::reloadAmmoClip(%this, %obj, %slot)
|
|
{
|
|
//echo("WeaponImage::reloadAmmoClip: " SPC %this SPC %obj SPC %slot);
|
|
|
|
// Make sure we're indeed the currect image on the given slot
|
|
if (%this != %obj.getMountedImage(%slot))
|
|
return;
|
|
|
|
if ( %this.isField("clip") )
|
|
{
|
|
if (%obj.getInventory(%this.clip) > 0)
|
|
{
|
|
%obj.decInventory(%this.clip, 1);
|
|
%obj.setInventory(%this.ammo, %this.ammo.maxInventory);
|
|
%obj.setImageAmmo(%slot, true);
|
|
}
|
|
else
|
|
{
|
|
%amountInPocket = %obj.getFieldValue( "remaining" @ %this.ammo.getName());
|
|
if ( %amountInPocket )
|
|
{
|
|
%obj.setFieldValue( "remaining" @ %this.ammo.getName(), 0);
|
|
%obj.setInventory( %this.ammo, %amountInPocket );
|
|
%obj.setImageAmmo( %slot, true );
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
function WeaponImage::clearAmmoClip( %this, %obj, %slot )
|
|
{
|
|
//echo("WeaponImage::clearAmmoClip: " SPC %this SPC %obj SPC %slot);
|
|
|
|
// if we're not empty put the remaining bullets from the current clip
|
|
// in to the player's "pocket".
|
|
|
|
if ( %this.isField( "clip" ) )
|
|
{
|
|
// Commenting out this line will use a "hard clip" system, where
|
|
// A player will lose any ammo currently in the gun when reloading.
|
|
%pocketAmount = %this.stashSpareAmmo( %obj );
|
|
|
|
if ( %obj.getInventory( %this.clip ) > 0 || %pocketAmount != 0 )
|
|
%obj.setImageAmmo(%slot, false);
|
|
}
|
|
}
|
|
function WeaponImage::stashSpareAmmo( %this, %player )
|
|
{
|
|
// If the amount in our pocket plus what we are about to add from the clip
|
|
// Is over a clip, add a clip to inventory and keep the remainder
|
|
// on the player
|
|
if (%player.getInventory( %this.ammo ) < %this.ammo.maxInventory )
|
|
{
|
|
%nameOfAmmoField = "remaining" @ %this.ammo.getName();
|
|
|
|
%amountInPocket = %player.getFieldValue( %nameOfAmmoField );
|
|
|
|
%amountInGun = %player.getInventory( %this.ammo );
|
|
|
|
%combinedAmmo = %amountInGun + %amountInPocket;
|
|
|
|
// Give the player another clip if the amount in our pocket + the
|
|
// Amount in our gun is over the size of a clip.
|
|
if ( %combinedAmmo >= %this.ammo.maxInventory )
|
|
{
|
|
%player.setFieldValue( %nameOfAmmoField, %combinedAmmo - %this.ammo.maxInventory );
|
|
%player.incInventory( %this.clip, 1 );
|
|
}
|
|
else if ( %player.getInventory(%this.clip) > 0 )// Only put it back in our pocket if we have clips.
|
|
%player.setFieldValue( %nameOfAmmoField, %combinedAmmo );
|
|
|
|
return %player.getFieldValue( %nameOfAmmoField );
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Clip Class
|
|
//-----------------------------------------------------------------------------
|
|
|
|
function AmmoClip::onPickup(%this, %obj, %shape, %amount)
|
|
{
|
|
// The parent Item method performs the actual pickup.
|
|
if (Parent::onPickup(%this, %obj, %shape, %amount))
|
|
serverPlay3D(AmmoPickupSound, %shape.getTransform());
|
|
|
|
// The clip inventory state has changed, we need to update the
|
|
// current mounted image using this clip to reflect the new state.
|
|
if ((%image = %shape.getMountedImage($WeaponSlot)) > 0)
|
|
{
|
|
// Check if this weapon uses the clip we just picked up and if
|
|
// there is no ammo.
|
|
if (%image.isField("clip") && %image.clip.getId() == %this.getId())
|
|
{
|
|
%outOfAmmo = !%shape.getImageAmmo($WeaponSlot);
|
|
|
|
%currentAmmo = %shape.getInventory(%image.ammo);
|
|
|
|
if ( isObject( %image.clip ) )
|
|
%amountInClips = %shape.getInventory(%image.clip);
|
|
|
|
%amountInClips *= %image.ammo.maxInventory;
|
|
%amountInClips += %obj.getFieldValue( "remaining" @ %this.ammo.getName() );
|
|
|
|
%shape.client.setAmmoAmountHud(%currentAmmo, %amountInClips );
|
|
|
|
if (%outOfAmmo)
|
|
{
|
|
%image.onClipEmpty(%shape, $WeaponSlot);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Ammmo Class
|
|
//-----------------------------------------------------------------------------
|
|
|
|
function Ammo::onPickup(%this, %obj, %shape, %amount)
|
|
{
|
|
// The parent Item method performs the actual pickup.
|
|
if (Parent::onPickup(%this, %obj, %shape, %amount))
|
|
serverPlay3D(AmmoPickupSound, %shape.getTransform());
|
|
}
|
|
|
|
function Ammo::onInventory(%this, %obj, %amount)
|
|
{
|
|
// The ammo inventory state has changed, we need to update any
|
|
// mounted images using this ammo to reflect the new state.
|
|
for (%i = 0; %i < 8; %i++)
|
|
{
|
|
if ((%image = %obj.getMountedImage(%i)) > 0)
|
|
if (isObject(%image.ammo) && %image.ammo.getId() == %this.getId())
|
|
{
|
|
%obj.setImageAmmo(%i, %amount != 0);
|
|
%currentAmmo = %obj.getInventory(%this);
|
|
|
|
if (%obj.getClassname() $= "Player")
|
|
{
|
|
if ( isObject( %this.clip ) )
|
|
{
|
|
%amountInClips = %obj.getInventory(%this.clip);
|
|
%amountInClips *= %this.maxInventory;
|
|
%amountInClips += %obj.getFieldValue( "remaining" @ %this.getName() );
|
|
}
|
|
else //Is a single fire weapon, like the grenade launcher.
|
|
{
|
|
%amountInClips = %currentAmmo;
|
|
%currentAmmo = 1;
|
|
}
|
|
|
|
if (%obj.client !$= "" && !%obj.isAiControlled)
|
|
%obj.client.setAmmoAmountHud(%currentAmmo, %amountInClips);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Weapon cycling
|
|
// ----------------------------------------------------------------------------
|
|
|
|
function ShapeBase::clearWeaponCycle(%this)
|
|
{
|
|
%this.totalCycledWeapons = 0;
|
|
}
|
|
|
|
function ShapeBase::addToWeaponCycle(%this, %weapon)
|
|
{
|
|
%this.cycleWeapon[%this.totalCycledWeapons++ - 1] = %weapon;
|
|
}
|
|
|
|
function ShapeBase::cycleWeapon(%this, %direction)
|
|
{
|
|
// Can't cycle what we don't have
|
|
if (%this.totalCycledWeapons == 0)
|
|
return;
|
|
|
|
// Find out the index of the current weapon, if any (not all
|
|
// available weapons may be part of the cycle)
|
|
%currentIndex = -1;
|
|
if (%this.getMountedImage($WeaponSlot) != 0)
|
|
{
|
|
%curWeapon = %this.getMountedImage($WeaponSlot).item.getName();
|
|
for (%i=0; %i<%this.totalCycledWeapons; %i++)
|
|
{
|
|
if (%this.cycleWeapon[%i] $= %curWeapon)
|
|
{
|
|
%currentIndex = %i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get the next weapon index
|
|
%nextIndex = 0;
|
|
%dir = 1;
|
|
if (%currentIndex != -1)
|
|
{
|
|
if (%direction $= "prev")
|
|
{
|
|
%dir = -1;
|
|
%nextIndex = %currentIndex - 1;
|
|
if (%nextIndex < 0)
|
|
{
|
|
// Wrap around to the end
|
|
%nextIndex = %this.totalCycledWeapons - 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
%nextIndex = %currentIndex + 1;
|
|
if (%nextIndex >= %this.totalCycledWeapons)
|
|
{
|
|
// Wrap back to the beginning
|
|
%nextIndex = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// We now need to check if the next index is a valid weapon. If not,
|
|
// then continue to cycle to the next weapon, in the appropriate direction,
|
|
// until one is found. If nothing is found, then do nothing.
|
|
%found = false;
|
|
for (%i=0; %i<%this.totalCycledWeapons; %i++)
|
|
{
|
|
%weapon = %this.cycleWeapon[%nextIndex];
|
|
if (%weapon !$= "" && %this.hasInventory(%weapon) && %this.hasAmmo(%weapon))
|
|
{
|
|
// We've found out weapon
|
|
%found = true;
|
|
break;
|
|
}
|
|
|
|
%nextIndex = %nextIndex + %dir;
|
|
if (%nextIndex < 0)
|
|
{
|
|
%nextIndex = %this.totalCycledWeapons - 1;
|
|
}
|
|
else if (%nextIndex >= %this.totalCycledWeapons)
|
|
{
|
|
%nextIndex = 0;
|
|
}
|
|
}
|
|
|
|
if (%found)
|
|
{
|
|
%this.use(%this.cycleWeapon[%nextIndex]);
|
|
}
|
|
}
|