Torque3D/Templates/Full/game/scripts/server/inventory.cs
2012-09-19 11:54:25 -04:00

313 lines
9.5 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 inventory system is totally scripted, no C++ code involved.
// It uses object datablock names to track inventory and is generally
// object type, or class, agnostic. In other words, it will inventory
// any kind of ShapeBase object, though the throw method does assume
// that the objects are small enough to throw :)
//
// For a ShapeBase object to support inventory, it must have an array
// of inventory max values:
// %this.maxInv[GunAmmo] = 100;
// %this.maxInv[SpeedGun] = 1;
// where the names "SpeedGun" and "GunAmmo" are datablocks.
//
// For objects to be inventoriable, they must provide a set of inventory
// callback methods, mainly:
// onUse
// onThrow
// onPickup
//
// Example methods are given further down. The item.cs file also contains
// example inventory items.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Inventory server commands
//-----------------------------------------------------------------------------
function serverCmdUse(%client, %data)
{
%client.getControlObject().use(%data);
}
//-----------------------------------------------------------------------------
// ShapeBase inventory support
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
function ShapeBase::use(%this, %data)
{
// Use an object in the inventory.
// Need to prevent weapon changing when zooming, but only shapes
// that have a connection.
%conn = %this.getControllingClient();
if (%conn)
{
%defaultFov = %conn.getControlCameraDefaultFov();
%fov = %conn.getControlCameraFov();
if (%fov != %defaultFov)
return false;
}
if (%this.getInventory(%data) > 0)
return %data.onUse(%this);
return false;
}
function ShapeBase::throw(%this, %data, %amount)
{
// Throw objects from inventory. The onThrow method is
// responsible for decrementing the inventory.
if (%this.getInventory(%data) > 0)
{
%obj = %data.onThrow(%this, %amount);
if (%obj)
{
%this.throwObject(%obj);
serverPlay3D(ThrowSnd, %this.getTransform());
return true;
}
}
return false;
}
function ShapeBase::pickup(%this, %obj, %amount)
{
// This method is called to pickup an object and add it to the inventory.
// The datablock onPickup method is actually responsible for doing all the
// work, including incrementing the inventory.
%data = %obj.getDatablock();
// Try and pickup the max if no value was specified
if (%amount $= "")
%amount = %this.maxInventory(%data) - %this.getInventory(%data);
// The datablock does the work...
if (%amount < 0)
%amount = 0;
if (%amount)
return %data.onPickup(%obj, %this, %amount);
return false;
}
//-----------------------------------------------------------------------------
function ShapeBase::hasInventory(%this, %data)
{
return (%this.inv[%data] > 0);
}
function ShapeBase::hasAmmo(%this, %weapon)
{
if (%weapon.image.ammo $= "")
return(true);
else
return(%this.getInventory(%weapon.image.ammo) > 0);
}
function ShapeBase::maxInventory(%this, %data)
{
if (%data.isField("clip"))
{
// Use the clip system which uses the maxInventory
// field on the ammo itself.
return %data.maxInventory;
}
else
{
// Use the ammo pool system which uses the maxInv[]
// array on the object's datablock.
// If there is no limit defined, we assume 0
return %this.getDatablock().maxInv[%data.getName()];
}
}
function ShapeBase::incInventory(%this, %data, %amount)
{
// Increment the inventory by the given amount. The return value
// is the amount actually added, which may be less than the
// requested amount due to inventory restrictions.
%max = %this.maxInventory(%data);
%total = %this.inv[%data.getName()];
if (%total < %max)
{
if (%total + %amount > %max)
%amount = %max - %total;
%this.setInventory(%data, %total + %amount);
return %amount;
}
return 0;
}
function ShapeBase::decInventory(%this, %data, %amount)
{
// Decrement the inventory by the given amount. The return value
// is the amount actually removed.
%total = %this.inv[%data.getName()];
if (%total > 0)
{
if (%total < %amount)
%amount = %total;
%this.setInventory(%data, %total - %amount);
return %amount;
}
return 0;
}
//-----------------------------------------------------------------------------
function ShapeBase::getInventory(%this, %data)
{
// Return the current inventory amount
return %this.inv[%data.getName()];
}
function ShapeBase::setInventory(%this, %data, %value)
{
// Set the inventory amount for this datablock and invoke inventory
// callbacks. All changes to inventory go through this single method.
// Impose inventory limits
if (%value < 0)
%value = 0;
else
{
%max = %this.maxInventory(%data);
if (%value > %max)
%value = %max;
}
// Set the value and invoke object callbacks
%name = %data.getName();
if (%this.inv[%name] != %value)
{
%this.inv[%name] = %value;
%data.onInventory(%this, %value);
%this.getDataBlock().onInventory(%data, %value);
}
return %value;
}
//-----------------------------------------------------------------------------
function ShapeBase::clearInventory(%this)
{
// To be filled in...
}
//-----------------------------------------------------------------------------
function ShapeBase::throwObject(%this, %obj)
{
// Throw the given object in the direction the shape is looking.
// The force value is hardcoded according to the current default
// object mass and mission gravity (20m/s^2).
%throwForce = %this.getDataBlock().throwForce;
if (!%throwForce)
%throwForce = 20;
// Start with the shape's eye vector...
%eye = %this.getEyeVector();
%vec = vectorScale(%eye, %throwForce);
// Add a vertical component to give the object a better arc
%verticalForce = %throwForce / 2;
%dot = vectorDot("0 0 1", %eye);
if (%dot < 0)
%dot = -%dot;
%vec = vectorAdd(%vec, vectorScale("0 0 "@%verticalForce, 1 - %dot));
// Add the shape's velocity
%vec = vectorAdd(%vec, %this.getVelocity());
// Set the object's position and initial velocity
%pos = getBoxCenter(%this.getWorldBox());
%obj.setTransform(%pos);
%obj.applyImpulse(%pos, %vec);
// Since the object is thrown from the center of the shape,
// the object needs to avoid colliding with it's thrower.
%obj.setCollisionTimeout(%this);
}
//-----------------------------------------------------------------------------
// Callback hooks invoked by the inventory system
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// ShapeBase object callbacks invoked by the inventory system
function ShapeBase::onInventory(%this, %data, %value)
{
// Invoked on ShapeBase objects whenever their inventory changes
// for the given datablock.
}
//-----------------------------------------------------------------------------
// ShapeBase datablock callback invoked by the inventory system.
function ShapeBaseData::onUse(%this, %user)
{
// Invoked when the object uses this datablock, should return
// true if the item was used.
return false;
}
function ShapeBaseData::onThrow(%this, %user, %amount)
{
// Invoked when the object is thrown. This method should
// construct and return the actual mission object to be
// physically thrown. This method is also responsible for
// decrementing the user's inventory.
return 0;
}
function ShapeBaseData::onPickup(%this, %obj, %user, %amount)
{
// Invoked when the user attempts to pickup this datablock object.
// The %amount argument is the space in the user's inventory for
// this type of datablock. This method is responsible for
// incrementing the user's inventory is something is addded.
// Should return true if something was added to the inventory.
return false;
}
function ShapeBaseData::onInventory(%this, %user, %value)
{
// Invoked whenever an user's inventory total changes for
// this datablock.
}