Full Template for ticket #1

This commit is contained in:
DavidWyand-GG 2012-09-19 11:54:25 -04:00
parent 74f265b3b3
commit f439dc8dcd
2150 changed files with 286240 additions and 0 deletions

View file

@ -0,0 +1,328 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// AIPlayer callbacks
// The AIPlayer class implements the following callbacks:
//
// PlayerData::onStop(%this,%obj)
// PlayerData::onMove(%this,%obj)
// PlayerData::onReachDestination(%this,%obj)
// PlayerData::onMoveStuck(%this,%obj)
// PlayerData::onTargetEnterLOS(%this,%obj)
// PlayerData::onTargetExitLOS(%this,%obj)
// PlayerData::onAdd(%this,%obj)
//
// Since the AIPlayer doesn't implement it's own datablock, these callbacks
// all take place in the PlayerData namespace.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Demo Pathed AIPlayer.
//-----------------------------------------------------------------------------
function DemoPlayer::onReachDestination(%this,%obj)
{
//echo( %obj @ " onReachDestination" );
// Moves to the next node on the path.
// Override for all player. Normally we'd override this for only
// a specific player datablock or class of players.
if (%obj.path !$= "")
{
if (%obj.currentNode == %obj.targetNode)
%this.onEndOfPath(%obj,%obj.path);
else
%obj.moveToNextNode();
}
}
function DemoPlayer::onMoveStuck(%this,%obj)
{
//echo( %obj @ " onMoveStuck" );
}
function DemoPlayer::onTargetExitLOS(%this,%obj)
{
//echo( %obj @ " onTargetExitLOS" );
}
function DemoPlayer::onTargetEnterLOS(%this,%obj)
{
//echo( %obj @ " onTargetEnterLOS" );
}
function DemoPlayer::onEndOfPath(%this,%obj,%path)
{
%obj.nextTask();
}
function DemoPlayer::onEndSequence(%this,%obj,%slot)
{
echo("Sequence Done!");
%obj.stopThread(%slot);
%obj.nextTask();
}
//-----------------------------------------------------------------------------
// AIPlayer static functions
//-----------------------------------------------------------------------------
function AIPlayer::spawn(%name,%spawnPoint)
{
// Create the demo player object
%player = new AiPlayer()
{
dataBlock = DemoPlayer;
path = "";
};
MissionCleanup.add(%player);
%player.setShapeName(%name);
%player.setTransform(%spawnPoint);
return %player;
}
function AIPlayer::spawnOnPath(%name,%path)
{
// Spawn a player and place him on the first node of the path
if (!isObject(%path))
return 0;
%node = %path.getObject(0);
%player = AIPlayer::spawn(%name, %node.getTransform());
return %player;
}
//-----------------------------------------------------------------------------
// AIPlayer methods
//-----------------------------------------------------------------------------
function AIPlayer::followPath(%this,%path,%node)
{
// Start the player following a path
%this.stopThread(0);
if (!isObject(%path))
{
%this.path = "";
return;
}
if (%node > %path.getCount() - 1)
%this.targetNode = %path.getCount() - 1;
else
%this.targetNode = %node;
if (%this.path $= %path)
%this.moveToNode(%this.currentNode);
else
{
%this.path = %path;
%this.moveToNode(0);
}
}
function AIPlayer::moveToNextNode(%this)
{
if (%this.targetNode < 0 || %this.currentNode < %this.targetNode)
{
if (%this.currentNode < %this.path.getCount() - 1)
%this.moveToNode(%this.currentNode + 1);
else
%this.moveToNode(0);
}
else
if (%this.currentNode == 0)
%this.moveToNode(%this.path.getCount() - 1);
else
%this.moveToNode(%this.currentNode - 1);
}
function AIPlayer::moveToNode(%this,%index)
{
// Move to the given path node index
%this.currentNode = %index;
%node = %this.path.getObject(%index);
%this.setMoveDestination(%node.getTransform(), %index == %this.targetNode);
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
function AIPlayer::pushTask(%this,%method)
{
if (%this.taskIndex $= "")
{
%this.taskIndex = 0;
%this.taskCurrent = -1;
}
%this.task[%this.taskIndex] = %method;
%this.taskIndex++;
if (%this.taskCurrent == -1)
%this.executeTask(%this.taskIndex - 1);
}
function AIPlayer::clearTasks(%this)
{
%this.taskIndex = 0;
%this.taskCurrent = -1;
}
function AIPlayer::nextTask(%this)
{
if (%this.taskCurrent != -1)
if (%this.taskCurrent < %this.taskIndex - 1)
%this.executeTask(%this.taskCurrent++);
else
%this.taskCurrent = -1;
}
function AIPlayer::executeTask(%this,%index)
{
%this.taskCurrent = %index;
eval(%this.getId() @"."@ %this.task[%index] @";");
}
//-----------------------------------------------------------------------------
function AIPlayer::singleShot(%this)
{
// The shooting delay is used to pulse the trigger
%this.setImageTrigger(0, true);
%this.setImageTrigger(0, false);
%this.trigger = %this.schedule(%this.shootingDelay, singleShot);
}
//-----------------------------------------------------------------------------
function AIPlayer::wait(%this, %time)
{
%this.schedule(%time * 1000, "nextTask");
}
function AIPlayer::done(%this,%time)
{
%this.schedule(0, "delete");
}
function AIPlayer::fire(%this,%bool)
{
if (%bool)
{
cancel(%this.trigger);
%this.singleShot();
}
else
cancel(%this.trigger);
%this.nextTask();
}
function AIPlayer::aimAt(%this,%object)
{
echo("Aim: "@ %object);
%this.setAimObject(%object);
%this.nextTask();
}
function AIPlayer::animate(%this,%seq)
{
//%this.stopThread(0);
//%this.playThread(0,%seq);
%this.setActionThread(%seq);
}
// ----------------------------------------------------------------------------
// Some handy getDistance/nearestTarget functions for the AI to use
// ----------------------------------------------------------------------------
function AIPlayer::getTargetDistance(%this, %target)
{
echo("\c4AIPlayer::getTargetDistance("@ %this @", "@ %target @")");
$tgt = %target;
%tgtPos = %target.getPosition();
%eyePoint = %this.getWorldBoxCenter();
%distance = VectorDist(%tgtPos, %eyePoint);
echo("Distance to target = "@ %distance);
return %distance;
}
function AIPlayer::getNearestPlayerTarget(%this)
{
echo("\c4AIPlayer::getNearestPlayerTarget("@ %this @")");
%index = -1;
%botPos = %this.getPosition();
%count = ClientGroup.getCount();
for(%i = 0; %i < %count; %i++)
{
%client = ClientGroup.getObject(%i);
if (%client.player $= "" || %client.player == 0)
return -1;
%playerPos = %client.player.getPosition();
%tempDist = VectorDist(%playerPos, %botPos);
if (%i == 0)
{
%dist = %tempDist;
%index = %i;
}
else
{
if (%dist > %tempDist)
{
%dist = %tempDist;
%index = %i;
}
}
}
return %index;
}
//-----------------------------------------------------------------------------
function AIManager::think(%this)
{
// We could hook into the player's onDestroyed state instead of having to
// "think", but thinking allows us to consider other things...
if (!isObject(%this.player))
%this.player = %this.spawn();
%this.schedule(500, think);
}
function AIManager::spawn(%this)
{
%player = AIPlayer::spawnOnPath("Shootme", "MissionGroup/Paths/Path1");
if (isObject(%player))
{
%player.followPath("MissionGroup/Paths/Path1", -1);
// slow this sucker down, I'm tired of chasing him!
%player.setMoveSpeed(0.5);
//%player.mountImage(xxxImage, 0);
//%player.setInventory(xxxAmmo, 1000);
return %player;
}
else
return 0;
}

View file

@ -0,0 +1,75 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
// Global movement speed that affects all cameras. This should be moved
// into the camera datablock.
$Camera::movementSpeed = 40;
function Observer::onTrigger(%this,%obj,%trigger,%state)
{
// state = 0 means that a trigger key was released
if (%state == 0)
return;
// Default player triggers: 0=fire 1=altFire 2=jump
%client = %obj.getControllingClient();
switch$ (%obj.mode)
{
case "Observer":
// Do something interesting.
case "Corpse":
// Fade out the corpse
if (isObject(%obj.orbitObj))
{
cancelAll(%obj.orbitObj);
%obj.orbitObj.schedule(0, "startFade", 1000, 0, true);
%obj.orbitObj.schedule(1000, "delete");
}
// Viewing dead corpse, so we probably want to respawn.
game.preparePlayer(%client);
// Set the camera back into observer mode, since in
// debug mode we like to switch to it.
%this.setMode(%obj,"Observer");
}
}
function Observer::setMode(%this,%obj,%mode,%arg1,%arg2,%arg3)
{
switch$ (%mode)
{
case "Observer":
// Let the player fly around
%obj.setFlyMode();
case "Corpse":
// Lock the camera down in orbit around the corpse,
// which should be arg1
%transform = %arg1.getTransform();
%obj.setOrbitMode(%arg1, %transform, 0.5, 4.5, 4.5);
%obj.orbitObj = %arg1;
}
%obj.mode = %mode;
}

View file

@ -0,0 +1,162 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
function CheetahCar::onAdd(%this, %obj)
{
Parent::onAdd(%this, %obj);
%obj.setWheelTire(0,CheetahCarTire);
%obj.setWheelTire(1,CheetahCarTire);
%obj.setWheelTire(2,CheetahCarTireRear);
%obj.setWheelTire(3,CheetahCarTireRear);
// Setup the car with some tires & springs
for (%i = %obj.getWheelCount() - 1; %i >= 0; %i--)
{
%obj.setWheelPowered(%i, true);
%obj.setWheelSpring(%i, CheetahCarSpring);
}
// Steer with the front tires
%obj.setWheelSteering(0, 1);
%obj.setWheelSteering(1, 1);
// Add tail lights
%obj.rightBrakeLight = new PointLight()
{
radius = "1";
isEnabled = "0";
color = "1 0 0.141176 1";
brightness = "2";
castShadows = "1";
priority = "1";
animate = "0";
animationPeriod = "1";
animationPhase = "1";
flareScale = "1";
attenuationRatio = "0 1 1";
shadowType = "DualParaboloidSinglePass";
texSize = "512";
overDarkFactor = "2000 1000 500 100";
shadowDistance = "400";
shadowSoftness = "0.15";
numSplits = "1";
logWeight = "0.91";
fadeStartDistance = "0";
lastSplitTerrainOnly = "0";
representedInLightmap = "0";
shadowDarkenColor = "0 0 0 -1";
includeLightmappedGeometryInShadow = "0";
rotation = "1 0 0 0";
canSave = "1";
canSaveDynamicFields = "1";
splitFadeDistances = "10 20 30 40";
};
%obj.leftBrakeLight = new PointLight()
{
radius = "1";
isEnabled = "0";
color = "1 0 0.141176 1";
brightness = "2";
castShadows = "1";
priority = "1";
animate = "0";
animationPeriod = "1";
animationPhase = "1";
flareScale = "1";
attenuationRatio = "0 1 1";
shadowType = "DualParaboloidSinglePass";
texSize = "512";
overDarkFactor = "2000 1000 500 100";
shadowDistance = "400";
shadowSoftness = "0.15";
numSplits = "1";
logWeight = "0.91";
fadeStartDistance = "0";
lastSplitTerrainOnly = "0";
representedInLightmap = "0";
shadowDarkenColor = "0 0 0 -1";
includeLightmappedGeometryInShadow = "0";
rotation = "1 0 0 0";
canSave = "1";
canSaveDynamicFields = "1";
splitFadeDistances = "10 20 30 40";
};
// Mount a ShapeBaseImageData
%didMount = %obj.mountImage(TurretImage, %this.turretSlot);
// Mount the brake lights
%obj.mountObject(%obj.rightBrakeLight, %this.rightBrakeSlot);
%obj.mountObject(%obj.leftBrakeLight, %this.leftBrakeSlot);
}
function CheetahCar::onRemove(%this, %obj)
{
Parent::onRemove(%this, %obj);
if(isObject(%obj.rightBrakeLight))
%obj.rightBrakeLight.delete();
if(isObject(%obj.leftBrakeLight))
%obj.leftBrakeLight.delete();
if(isObject(%obj.turret))
%obj.turret.delete();
}
function serverCmdtoggleBrakeLights(%client)
{
%car = %client.player.getControlObject();
if (%car.getClassName() $= "WheeledVehicle")
{
if(%car.rightBrakeLight.isEnabled)
{
%car.rightBrakeLight.setLightEnabled(0);
%car.leftBrakeLight.setLightEnabled(0);
}
else
{
%car.rightBrakeLight.setLightEnabled(1);
%car.leftBrakeLight.setLightEnabled(1);
}
}
}
// Callback invoked when an input move trigger state changes when the CheetahCar
// is the control object
function CheetahCar::onTrigger(%this, %obj, %index, %state)
{
// Pass trigger states on to TurretImage (to fire weapon)
switch ( %index )
{
case 0: %obj.setImageTrigger( %this.turretSlot, %state );
case 1: %obj.setImageAltTrigger( %this.turretSlot, %state );
}
}
function TurretImage::onMount(%this, %obj, %slot)
{
// Load the gun
%obj.setImageAmmo(%slot, true);
}

View file

@ -0,0 +1,123 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Misc server commands avialable to clients
//-----------------------------------------------------------------------------
function serverCmdSuicide(%client)
{
if (isObject(%client.player))
%client.player.kill("Suicide");
}
function serverCmdPlayCel(%client,%anim)
{
if (isObject(%client.player))
%client.player.playCelAnimation(%anim);
}
function serverCmdTestAnimation(%client, %anim)
{
if (isObject(%client.player))
%client.player.playTestAnimation(%anim);
}
function serverCmdPlayDeath(%client)
{
if (isObject(%client.player))
%client.player.playDeathAnimation();
}
// ----------------------------------------------------------------------------
// Throw/Toss
// ----------------------------------------------------------------------------
function serverCmdThrow(%client, %data)
{
%player = %client.player;
if(!isObject(%player) || %player.getState() $= "Dead" || !$Game::Running)
return;
switch$ (%data)
{
case "Weapon":
%item = (%player.getMountedImage($WeaponSlot) == 0) ? "" : %player.getMountedImage($WeaponSlot).item;
if (%item !$="")
%player.throw(%item);
case "Ammo":
%weapon = (%player.getMountedImage($WeaponSlot) == 0) ? "" : %player.getMountedImage($WeaponSlot);
if (%weapon !$= "")
{
if(%weapon.ammo !$= "")
%player.throw(%weapon.ammo);
}
default:
if(%player.hasInventory(%data.getName()))
%player.throw(%data);
}
}
// ----------------------------------------------------------------------------
// Force game end and cycle
// Probably don't want this in a final game without some checks. Anyone could
// restart a game.
// ----------------------------------------------------------------------------
function serverCmdFinishGame()
{
cycleGame();
}
// ----------------------------------------------------------------------------
// Cycle weapons
// ----------------------------------------------------------------------------
function serverCmdCycleWeapon(%client, %direction)
{
%client.getControlObject().cycleWeapon(%direction);
}
// ----------------------------------------------------------------------------
// Unmount current weapon
// ----------------------------------------------------------------------------
function serverCmdUnmountWeapon(%client)
{
%client.getControlObject().unmountImage($WeaponSlot);
}
// ----------------------------------------------------------------------------
// Weapon reloading
// ----------------------------------------------------------------------------
function serverCmdReloadWeapon(%client)
{
%player = %client.getControlObject();
%image = %player.getMountedImage($WeaponSlot);
// Don't reload if the weapon's full.
if (%player.getInventory(%image.ammo) == %image.ammo.maxInventory)
return;
if (%image > 0)
%image.clearAmmoClip(%player, $WeaponSlot);
}

View file

@ -0,0 +1,43 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
// First we execute the core default preferences.
exec( "core/scripts/server/defaults.cs" );
// Now add your own game specific server preferences as
// well as any overloaded core defaults here.
// Finally load the preferences saved from the last
// game execution if they exist.
if ( $platform !$= "xenon" )
{
if ( isFile( "./prefs.cs" ) )
exec( "./prefs.cs" );
}
else
{
echo( "Not loading server prefs.cs on Xbox360" );
}

View file

@ -0,0 +1,190 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
// Game duration in secs, no limit if the duration is set to 0
$Game::Duration = 20 * 60;
// When a client score reaches this value, the game is ended.
$Game::EndGameScore = 30;
// Pause while looking over the end game screen (in secs)
$Game::EndGamePause = 10;
//-----------------------------------------------------------------------------
function onServerCreated()
{
// Server::GameType is sent to the master server.
// This variable should uniquely identify your game and/or mod.
$Server::GameType = $appName;
// Server::MissionType sent to the master server. Clients can
// filter servers based on mission type.
$Server::MissionType = "Deathmatch";
// GameStartTime is the sim time the game started. Used to calculated
// game elapsed time.
$Game::StartTime = 0;
// Create the server physics world.
physicsInitWorld( "server" );
// Load up any objects or datablocks saved to the editor managed scripts
%datablockFiles = new ArrayObject();
%datablockFiles.add( "art/shapes/particles/managedParticleData.cs" );
%datablockFiles.add( "art/shapes/particles/managedParticleEmitterData.cs" );
%datablockFiles.add( "art/decals/managedDecalData.cs" );
%datablockFiles.add( "art/datablocks/managedDatablocks.cs" );
%datablockFiles.add( "art/forest/managedItemData.cs" );
%datablockFiles.add( "art/datablocks/datablockExec.cs" );
loadDatablockFiles( %datablockFiles, true );
// Run the other gameplay scripts in this folder
exec("./scriptExec.cs");
// Keep track of when the game started
$Game::StartTime = $Sim::Time;
}
function onServerDestroyed()
{
// This function is called as part of a server shutdown.
physicsDestroyWorld( "server" );
// Clean up the GameCore package here as it persists over the
// life of the server.
if (isPackage(GameCore))
{
deactivatePackage(GameCore);
}
}
//-----------------------------------------------------------------------------
function onGameDurationEnd()
{
// This "redirect" is here so that we can abort the game cycle if
// the $Game::Duration variable has been cleared, without having
// to have a function to cancel the schedule.
if ($Game::Duration && !(EditorIsActive() && GuiEditorIsActive()))
Game.onGameDurationEnd();
}
//-----------------------------------------------------------------------------
function cycleGame()
{
// This is setup as a schedule so that this function can be called
// directly from object callbacks. Object callbacks have to be
// carefull about invoking server functions that could cause
// their object to be deleted.
if (!$Game::Cycling)
{
$Game::Cycling = true;
$Game::Schedule = schedule(0, 0, "onCycleExec");
}
}
function onCycleExec()
{
// End the current game and start another one, we'll pause for a little
// so the end game victory screen can be examined by the clients.
//endGame();
endMission();
$Game::Schedule = schedule($Game::EndGamePause * 1000, 0, "onCyclePauseEnd");
}
function onCyclePauseEnd()
{
$Game::Cycling = false;
// Just cycle through the missions for now.
%search = $Server::MissionFileSpec;
%oldMissionFile = makeRelativePath( $Server::MissionFile );
for( %file = findFirstFile( %search ); %file !$= ""; %file = findNextFile( %search ) )
{
if( %file $= %oldMissionFile )
{
// Get the next one, back to the first if there is no next.
%file = findNextFile( %search );
if( %file $= "" )
%file = findFirstFile(%search);
break;
}
}
if( %file $= "" )
%file = findFirstFile( %search );
loadMission(%file);
}
//-----------------------------------------------------------------------------
// GameConnection Methods
// These methods are extensions to the GameConnection class. Extending
// GameConnection makes it easier to deal with some of this functionality,
// but these could also be implemented as stand-alone functions.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
function GameConnection::onLeaveMissionArea(%this)
{
// The control objects invoke this method when they
// move out of the mission area.
messageClient(%this, 'MsgClientJoin', '\c2Now leaving the mission area!');
}
function GameConnection::onEnterMissionArea(%this)
{
// The control objects invoke this method when they
// move back into the mission area.
messageClient(%this, 'MsgClientJoin', '\c2Now entering the mission area.');
}
//-----------------------------------------------------------------------------
function GameConnection::onDeath(%this, %sourceObject, %sourceClient, %damageType, %damLoc)
{
game.onDeath(%this, %sourceObject, %sourceClient, %damageType, %damLoc);
}
// ----------------------------------------------------------------------------
// weapon HUD
// ----------------------------------------------------------------------------
function GameConnection::setAmmoAmountHud(%client, %amount, %amountInClips )
{
commandToClient(%client, 'SetAmmoAmountHud', %amount, %amountInClips);
}
function GameConnection::RefreshWeaponHud(%client, %amount, %preview, %ret, %zoomRet, %amountInClips)
{
commandToClient(%client, 'RefreshWeaponHud', %amount, %preview, %ret, %zoomRet, %amountInClips);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,112 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// DeathmatchGame
// ----------------------------------------------------------------------------
// Depends on methods found in gameCore.cs. Those added here are specific to
// this game type and/or over-ride the "default" game functionaliy.
//
// The desired Game Type must be added to each mission's LevelInfo object.
// - gameType = "Deathmatch";
// If this information is missing then the GameCore will default to Deathmatch.
// ----------------------------------------------------------------------------
function DeathMatchGame::onMissionLoaded(%game)
{
//echo (%game @"\c4 -> "@ %game.class @" -> DeathMatchGame::onMissionLoaded");
$Server::MissionType = "DeathMatch";
parent::onMissionLoaded(%game);
}
function DeathMatchGame::initGameVars(%game)
{
//echo (%game @"\c4 -> "@ %game.class @" -> DeathMatchGame::initGameVars");
//-----------------------------------------------------------------------------
// What kind of "player" is spawned is either controlled directly by the
// SpawnSphere or it defaults back to the values set here. This also controls
// which SimGroups to attempt to select the spawn sphere's from by walking down
// the list of SpawnGroups till it finds a valid spawn object.
// These override the values set in core/scripts/server/spawn.cs
//-----------------------------------------------------------------------------
// Leave $Game::defaultPlayerClass and $Game::defaultPlayerDataBlock as empty strings ("")
// to spawn a the $Game::defaultCameraClass as the control object.
$Game::defaultPlayerClass = "Player";
$Game::defaultPlayerDataBlock = "DefaultPlayerData";
$Game::defaultPlayerSpawnGroups = "PlayerSpawnPoints PlayerDropPoints";
//-----------------------------------------------------------------------------
// What kind of "camera" is spawned is either controlled directly by the
// SpawnSphere or it defaults back to the values set here. This also controls
// which SimGroups to attempt to select the spawn sphere's from by walking down
// the list of SpawnGroups till it finds a valid spawn object.
// These override the values set in core/scripts/server/spawn.cs
//-----------------------------------------------------------------------------
$Game::defaultCameraClass = "Camera";
$Game::defaultCameraDataBlock = "Observer";
$Game::defaultCameraSpawnGroups = "CameraSpawnPoints PlayerSpawnPoints PlayerDropPoints";
// Set the gameplay parameters
%game.duration = 30 * 60;
%game.endgameScore = 20;
%game.endgamePause = 10;
%game.allowCycling = false; // Is mission cycling allowed?
}
function DeathMatchGame::startGame(%game)
{
//echo (%game @"\c4 -> "@ %game.class @" -> DeathMatchGame::startGame");
parent::startGame(%game);
}
function DeathMatchGame::endGame(%game)
{
//echo (%game @"\c4 -> "@ %game.class @" -> DeathMatchGame::endGame");
parent::endGame(%game);
}
function DeathMatchGame::onGameDurationEnd(%game)
{
//echo (%game @"\c4 -> "@ %game.class @" -> DeathMatchGame::onGameDurationEnd");
parent::onGameDurationEnd(%game);
}
function DeathMatchGame::onClientEnterGame(%game, %client)
{
//echo (%game @"\c4 -> "@ %game.class @" -> DeathMatchGame::onClientEnterGame");
parent::onClientEnterGame(%game, %client);
}
function DeathMatchGame::onClientLeaveGame(%game, %client)
{
//echo (%game @"\c4 -> "@ %game.class @" -> DeathMatchGame::onClientLeaveGame");
parent::onClientLeaveGame(%game, %client);
}

View file

@ -0,0 +1,117 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
function enableManualDetonation(%obj)
{
%obj.detonadeEnabled = true;
}
function doManualDetonation(%obj)
{
%nade = new Item()
{
dataBlock = Detonade;
};
MissionCleanup.add(%nade);
%nade.setTransform(%obj.getTransform());
%nade.sourceObject = %obj.sourceObject;
%nade.schedule(50, "setDamageState", "Destroyed"); // Why must we schedule?!
//%nade.setDamageState(Destroyed);
%obj.delete();
}
function Detonade::onDestroyed(%this, %object, %lastState)
{
radiusDamage(%object, %object.getPosition(), 10, 25, "DetonadeDamage", 2000);
}
function GrenadeLauncherImage::onMount(%this, %obj, %slot)
{
// Make it ready
%obj.detonadeEnabled = true;
Parent::onMount(%this, %obj, %slot);
}
function GrenadeLauncherImage::onAltFire(%this, %obj, %slot)
{
/*
//echo("\c4GrenadeLauncherImage::onFire("@ %this.getName() @", "@ %obj.client.nameBase @", "@ %slot@")");
// It's not ready yet
if(!%obj.detonadeEnabled)
return;
// If we already have one of these... blow it up!!!
if(isObject(%obj.lastProj))
{
doManualDetonation(%obj.lastProj);
if(%obj.lastNade)
{
// We remove the ammo of the last projectile fired only after it has
// been triggered, otherwise we wouldn't be able to set it off.
%obj.lastNade = "";
%obj.decInventory(%this.ammo, 1);
}
return;
}
// We fire our weapon using the straight ahead aiming point of the gun.
%muzzleVector = %obj.getMuzzleVector(%slot);
// Get the player's velocity, we'll then add it to that of the projectile
%objectVelocity = %obj.getVelocity();
%muzzleVelocity = VectorAdd(
VectorScale(%muzzleVector, %this.projectile.muzzleVelocity),
VectorScale(%objectVelocity, %this.projectile.velInheritFactor));
%p = new (%this.projectileType)()
{
dataBlock = %this.projectile;
initialVelocity = %muzzleVelocity;
initialPosition = %obj.getMuzzlePoint(%slot);
sourceObject = %obj;
sourceSlot = %slot;
client = %obj.client;
};
%obj.lastProj = %p;
MissionCleanup.add(%p);
// Decrement inventory ammo.
//%obj.decInventory(%this.ammo, 1);
// Must do some trickiness with reducing the ammo count to account for the
// very last shot. If we don't you wouldn't be able to trigger it.
%currentAmmo = %obj.getInventory(%this.ammo);
if(%currentAmmo == 1)
%obj.lastNade = 1;
else
%obj.decInventory(%this.ammo, 1);
// We don't want to detonate it in our face now do we? Give it a little time.
%obj.detonadeEnabled = false;
schedule(250, 0, "enableManualDetonation", %obj);
*/
}

View file

@ -0,0 +1,99 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
// Inventory items. These objects rely on the item & inventory support
// system defined in item.cs and inventory.cs
//-----------------------------------------------------------------------------
// Health Patches cannot be picked up and are not meant to be added to inventory.
// Health is applied automatically when an objects collides with a patch.
//-----------------------------------------------------------------------------
function HealthPatch::onCollision(%this, %obj, %col)
{
// Apply health to colliding object if it needs it.
// Works for all shapebase objects.
if (%col.getDamageLevel() != 0 && %col.getState() !$= "Dead")
{
%col.applyRepair(%this.repairAmount);
// Update the Health GUI while repairing
%this.doHealthUpdate(%col);
%obj.respawn();
if (%col.client)
messageClient(%col.client, 'MsgHealthPatchUsed', '\c2Health Patch Applied');
serverPlay3D(HealthUseSound, %obj.getTransform());
}
}
function HealthPatch::doHealthUpdate(%this, %obj)
{
// Would be better to add a onRepair() callback to shapeBase.cpp in order to
// prevent any excess/unneccesary schedules from this. But for the time
// being....
// This is just a rough timer to update the Health HUD every 250 ms. From
// my tests a large health pack will fully heal a player from 10 health in
// 36 iterations (ie. 9 seconds). If either the scheduling time, the repair
// amount, or the repair rate is changed then the healthTimer counter should
// be changed also.
if (%obj.healthTimer < 40) // 40 = 10 seconds at 1 iteration per 250 ms.
{
%obj.UpdateHealth();
%this.schedule(250, doHealthUpdate, %obj);
%obj.healthTimer++;
}
else
%obj.healthTimer = 0;
}
function ShapeBase::tossPatch(%this)
{
//error("ShapeBase::tossPatch(" SPC %this.client.nameBase SPC ")");
if(!isObject(%this))
return;
%item = ItemData::createItem(HealthKitPatch);
%item.sourceObject = %this;
%item.static = false;
MissionCleanup.add(%item);
%vec = (-1.0 + getRandom() * 2.0) SPC (-1.0 + getRandom() * 2.0) SPC getRandom();
%vec = vectorScale(%vec, 10);
%eye = %this.getEyeVector();
%dot = vectorDot("0 0 1", %eye);
if (%dot < 0)
%dot = -%dot;
%vec = vectorAdd(%vec, vectorScale("0 0 8", 1 - %dot));
%vec = vectorAdd(%vec, %this.getVelocity());
%pos = getBoxCenter(%this.getWorldBox());
%item.setTransform(%pos);
%item.applyImpulse(%pos, %vec);
%item.setCollisionTimeout(%this);
//serverPlay3D(%item.getDataBlock().throwSound, %item.getTransform());
%item.schedulePop();
return %item;
}

View file

@ -0,0 +1,96 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Variables used by server scripts & code. The ones marked with (c)
// are accessed from code. Variables preceeded by Pref:: are server
// preferences and stored automatically in the ServerPrefs.cs file
// in between server sessions.
//
// (c) Server::ServerType {SinglePlayer, MultiPlayer}
// (c) Server::GameType Unique game name
// (c) Server::Dedicated Bool
// ( ) Server::MissionFile Mission .mis file name
// (c) Server::MissionName DisplayName from .mis file
// (c) Server::MissionType Not used
// (c) Server::PlayerCount Current player count
// (c) Server::GuidList Player GUID (record list?)
// (c) Server::Status Current server status
//
// (c) Pref::Server::Name Server Name
// (c) Pref::Server::Password Password for client connections
// ( ) Pref::Server::AdminPassword Password for client admins
// (c) Pref::Server::Info Server description
// (c) Pref::Server::MaxPlayers Max allowed players
// (c) Pref::Server::RegionMask Registers this mask with master server
// ( ) Pref::Server::BanTime Duration of a player ban
// ( ) Pref::Server::KickBanTime Duration of a player kick & ban
// ( ) Pref::Server::MaxChatLen Max chat message len
// ( ) Pref::Server::FloodProtectionEnabled Bool
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
function initServer()
{
echo("\n--------- Initializing " @ $appName @ ": Server Scripts ---------");
// Server::Status is returned in the Game Info Query and represents the
// current status of the server. This string sould be very short.
$Server::Status = "Unknown";
// Turn on testing/debug script functions
$Server::TestCheats = false;
// Specify where the mission files are.
$Server::MissionFileSpec = "levels/*.mis";
// The common module provides the basic server functionality
initBaseServer();
// Load up game server support scripts
exec("./commands.cs");
exec("./game.cs");
}
//-----------------------------------------------------------------------------
function initDedicated()
{
enableWinConsole(true);
echo("\n--------- Starting Dedicated Server ---------");
// Make sure this variable reflects the correct state.
$Server::Dedicated = true;
// The server isn't started unless a mission has been specified.
if ($missionArg !$= "") {
createServer("MultiPlayer", $missionArg);
}
else
echo("No mission specified (use -mission filename)");
}

View file

@ -0,0 +1,312 @@
//-----------------------------------------------------------------------------
// 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.
}

View file

@ -0,0 +1,151 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
// These scripts make use of dynamic attribute values on Item datablocks,
// these are as follows:
//
// maxInventory Max inventory per object (100 bullets per box, etc.)
// pickupName Name to display when client pickups item
//
// Item objects can have:
//
// count The # of inventory items in the object. This
// defaults to maxInventory if not set.
// Respawntime is the amount of time it takes for a static "auto-respawn"
// object, such as an ammo box or weapon, to re-appear after it's been
// picked up. Any item marked as "static" is automaticlly respawned.
$Item::RespawnTime = 30 * 1000;
// Poptime represents how long dynamic items (those that are thrown or
// dropped) will last in the world before being deleted.
$Item::PopTime = 30 * 1000;
//-----------------------------------------------------------------------------
// ItemData base class methods used by all items
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
function Item::respawn(%this)
{
// This method is used to respawn static ammo and weapon items
// and is usually called when the item is picked up.
// Instant fade...
%this.startFade(0, 0, true);
%this.setHidden(true);
// Shedule a reapearance
%this.schedule($Item::RespawnTime, "setHidden", false);
%this.schedule($Item::RespawnTime + 100, "startFade", 1000, 0, false);
}
function Item::schedulePop(%this)
{
// This method deletes the object after a default duration. Dynamic
// items such as thrown or drop weapons are usually popped to avoid
// world clutter.
%this.schedule($Item::PopTime - 1000, "startFade", 1000, 0, true);
%this.schedule($Item::PopTime, "delete");
}
//-----------------------------------------------------------------------------
// Callbacks to hook items into the inventory system
function ItemData::onThrow(%this, %user, %amount)
{
// Remove the object from the inventory
if (%amount $= "")
%amount = 1;
if (%this.maxInventory !$= "")
if (%amount > %this.maxInventory)
%amount = %this.maxInventory;
if (!%amount)
return 0;
%user.decInventory(%this,%amount);
// Construct the actual object in the world, and add it to
// the mission group so it's cleaned up when the mission is
// done. The object is given a random z rotation.
%obj = new Item()
{
datablock = %this;
rotation = "0 0 1 "@ (getRandom() * 360);
count = %amount;
};
MissionGroup.add(%obj);
%obj.schedulePop();
return %obj;
}
function ItemData::onPickup(%this, %obj, %user, %amount)
{
// Add it to the inventory, this currently ignores the request
// amount, you get what you get. If the object doesn't have
// a count or the datablock doesn't have maxIventory set, the
// object cannot be picked up.
// See if the object has a count
%count = %obj.count;
if (%count $= "")
{
// No, so check the datablock
%count = %this.count;
if (%count $= "")
{
// No, so attempt to provide the maximum amount
if (%this.maxInventory !$= "")
{
if (!(%count = %this.maxInventory))
return;
}
else
%count = 1;
}
}
%user.incInventory(%this, %count);
// Inform the client what they got.
if (%user.client)
messageClient(%user.client, 'MsgItemPickup', '\c0You picked up %1', %this.pickupName);
// If the item is a static respawn item, then go ahead and
// respawn it, otherwise remove it from the world.
// Anything not taken up by inventory is lost.
if (%obj.isStatic())
%obj.respawn();
else
%obj.delete();
return true;
}
function ItemData::createItem(%data)
{
%obj = new Item()
{
dataBlock = %data;
static = true;
rotate = true;
};
return %obj;
}

View file

@ -0,0 +1,508 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
// Timeouts for corpse deletion.
$CorpseTimeoutValue = 45 * 1000;
// // Damage Rate for entering Liquid
// $DamageLava = 0.01;
// $DamageHotLava = 0.01;
// $DamageCrustyLava = 0.01;
// Death Animations
$PlayerDeathAnim::TorsoFrontFallForward = 1;
$PlayerDeathAnim::TorsoFrontFallBack = 2;
$PlayerDeathAnim::TorsoBackFallForward = 3;
$PlayerDeathAnim::TorsoLeftSpinDeath = 4;
$PlayerDeathAnim::TorsoRightSpinDeath = 5;
$PlayerDeathAnim::LegsLeftGimp = 6;
$PlayerDeathAnim::LegsRightGimp = 7;
$PlayerDeathAnim::TorsoBackFallForward = 8;
$PlayerDeathAnim::HeadFrontDirect = 9;
$PlayerDeathAnim::HeadBackFallForward = 10;
$PlayerDeathAnim::ExplosionBlowBack = 11;
//----------------------------------------------------------------------------
// Armor Datablock methods
//----------------------------------------------------------------------------
function Armor::onAdd(%this, %obj)
{
// Vehicle timeout
%obj.mountVehicle = true;
// Default dynamic armor stats
%obj.setRechargeRate(%this.rechargeRate);
%obj.setRepairRate(0);
// Set the numerical Health HUD
//%obj.updateHealth();
// Calling updateHealth() must be delayed now... for some reason
%obj.schedule(50, "updateHealth");
}
function Armor::onRemove(%this, %obj)
{
if (%obj.client.player == %obj)
%obj.client.player = 0;
}
function Armor::onNewDataBlock(%this, %obj)
{
}
//----------------------------------------------------------------------------
function Armor::onMount(%this, %obj, %vehicle, %node)
{
// Node 0 is the pilot's position, we need to dismount his weapon.
if (%node == 0)
{
%obj.setTransform("0 0 0 0 0 1 0");
%obj.setActionThread(%vehicle.getDatablock().mountPose[%node], true, true);
%obj.lastWeapon = %obj.getMountedImage($WeaponSlot);
%obj.unmountImage($WeaponSlot);
%obj.setControlObject(%vehicle);
if(%obj.getClassName() $= "Player")
commandToClient(%obj.client, 'toggleVehicleMap', true);
}
else
{
if (%vehicle.getDataBlock().mountPose[%node] !$= "")
%obj.setActionThread(%vehicle.getDatablock().mountPose[%node]);
else
%obj.setActionThread("root", true);
}
}
function Armor::onUnmount(%this, %obj, %vehicle, %node)
{
if (%node == 0)
{
%obj.mountImage(%obj.lastWeapon, $WeaponSlot);
%obj.setControlObject("");
}
}
function Armor::doDismount(%this, %obj, %forced)
{
//echo("\c4Armor::doDismount(" @ %this @", "@ %obj.client.nameBase @", "@ %forced @")");
// This function is called by player.cc when the jump trigger
// is true while mounted
%vehicle = %obj.mVehicle;
if (!%obj.isMounted() || !isObject(%vehicle))
return;
// Vehicle must be at rest!
if ((VectorLen(%vehicle.getVelocity()) <= %vehicle.getDataBlock().maxDismountSpeed ) || %forced)
{
// Position above dismount point
%pos = getWords(%obj.getTransform(), 0, 2);
%rot = getWords(%obj.getTransform(), 3, 6);
%oldPos = %pos;
%vec[0] = " -1 0 0";
%vec[1] = " 0 0 1";
%vec[2] = " 0 0 -1";
%vec[3] = " 1 0 0";
%vec[4] = "0 -1 0";
%impulseVec = "0 0 0";
%vec[0] = MatrixMulVector(%obj.getTransform(), %vec[0]);
// Make sure the point is valid
%pos = "0 0 0";
%numAttempts = 5;
%success = -1;
for (%i = 0; %i < %numAttempts; %i++)
{
%pos = VectorAdd(%oldPos, VectorScale(%vec[%i], 3));
if (%obj.checkDismountPoint(%oldPos, %pos))
{
%success = %i;
%impulseVec = %vec[%i];
break;
}
}
if (%forced && %success == -1)
%pos = %oldPos;
%obj.mountVehicle = false;
%obj.schedule(4000, "mountVehicles", true);
// Position above dismount point
%obj.unmount();
%obj.setTransform(%pos SPC %rot);//%obj.setTransform(%pos);
//%obj.playAudio(0, UnmountVehicleSound);
%obj.applyImpulse(%pos, VectorScale(%impulseVec, %obj.getDataBlock().mass));
// Set player velocity when ejecting
%vel = %obj.getVelocity();
%vec = vectorDot( %vel, vectorNormalize(%vel));
if(%vec > 50)
{
%scale = 50 / %vec;
%obj.setVelocity(VectorScale(%vel, %scale));
}
//%obj.vehicleTurret = "";
}
else
messageClient(%obj.client, 'msgUnmount', '\c2Cannot exit %1 while moving.', %vehicle.getDataBlock().nameTag);
}
//----------------------------------------------------------------------------
function Armor::onCollision(%this, %obj, %col)
{
if (!isObject(%col) || %obj.getState() $= "Dead")
return;
// Try and pickup all items
if (%col.getClassName() $= "Item")
{
%obj.pickup(%col);
return;
}
// Mount vehicles
if (%col.getType() & $TypeMasks::GameBaseObjectType)
{
%db = %col.getDataBlock();
if ((%db.getClassName() $= "WheeledVehicleData" ) && %obj.mountVehicle && %obj.getState() $= "Move" && %col.mountable)
{
// Only mount drivers for now.
ServerConnection.setFirstPerson(0);
// For this specific example, only one person can fit
// into a vehicle
%mount = %col.getMountNodeObject(0);
if(%mount)
return;
// For this specific FPS Example, always mount the player
// to node 0
%node = 0;
%col.mountObject(%obj, %node);
%obj.mVehicle = %col;
}
}
}
function Armor::onImpact(%this, %obj, %collidedObject, %vec, %vecLen)
{
%obj.damage(0, VectorAdd(%obj.getPosition(), %vec), %vecLen * %this.speedDamageScale, "Impact");
}
//----------------------------------------------------------------------------
function Armor::damage(%this, %obj, %sourceObject, %position, %damage, %damageType)
{
if (!isObject(%obj) || %obj.getState() $= "Dead" || !%damage)
return;
%obj.applyDamage(%damage);
%location = "Body";
// Update the numerical Health HUD
%obj.updateHealth();
// Deal with client callbacks here because we don't have this
// information in the onDamage or onDisable methods
%client = %obj.client;
%sourceClient = %sourceObject ? %sourceObject.client : 0;
if (isObject(%client))
{
// Determine damage direction
if (%damageType !$= "Suicide")
%obj.setDamageDirection(%sourceObject, %position);
if (%obj.getState() $= "Dead")
%client.onDeath(%sourceObject, %sourceClient, %damageType, %location);
}
}
function Armor::onDamage(%this, %obj, %delta)
{
// This method is invoked by the ShapeBase code whenever the
// object's damage level changes.
if (%delta > 0 && %obj.getState() !$= "Dead")
{
// Apply a damage flash
%obj.setDamageFlash(1);
// If the pain is excessive, let's hear about it.
if (%delta > 10)
%obj.playPain();
}
}
// ----------------------------------------------------------------------------
// The player object sets the "disabled" state when damage exceeds it's
// maxDamage value. This is method is invoked by ShapeBase state mangement code.
// If we want to deal with the damage information that actually caused this
// death, then we would have to move this code into the script "damage" method.
function Armor::onDisabled(%this, %obj, %state)
{
// Release the main weapon trigger
%obj.setImageTrigger(0, false);
// Toss current mounted weapon and ammo if any
%item = %obj.getMountedImage($WeaponSlot).item;
if (isObject(%item))
{
%amount = %obj.getInventory(%item.image.ammo);
if (!%item.image.clip)
warn("No clip exists to throw for item ", %item);
if(%amount)
%obj.throw(%item.image.clip, 1);
}
// Toss out a health patch
%obj.tossPatch();
%obj.playDeathCry();
%obj.playDeathAnimation();
//%obj.setDamageFlash(0.75);
// Disable any vehicle map
commandToClient(%obj.client, 'toggleVehicleMap', false);
// Schedule corpse removal. Just keeping the place clean.
%obj.schedule($CorpseTimeoutValue - 1000, "startFade", 1000, 0, true);
%obj.schedule($CorpseTimeoutValue, "delete");
}
//-----------------------------------------------------------------------------
function Armor::onLeaveMissionArea(%this, %obj)
{
//echo("\c4Leaving Mission Area at POS:"@ %obj.getPosition());
// Inform the client
%obj.client.onLeaveMissionArea();
// Damage over time and kill the coward!
//%obj.setDamageDt(0.2, "MissionAreaDamage");
}
function Armor::onEnterMissionArea(%this, %obj)
{
//echo("\c4Entering Mission Area at POS:"@ %obj.getPosition());
// Inform the client
%obj.client.onEnterMissionArea();
// Stop the punishment
//%obj.clearDamageDt();
}
//-----------------------------------------------------------------------------
function Armor::onEnterLiquid(%this, %obj, %coverage, %type)
{
//echo("\c4this:"@ %this @" object:"@ %obj @" just entered water of type:"@ %type @" for "@ %coverage @"coverage");
}
function Armor::onLeaveLiquid(%this, %obj, %type)
{
//
}
//-----------------------------------------------------------------------------
function Armor::onTrigger(%this, %obj, %triggerNum, %val)
{
// This method is invoked when the player receives a trigger move event.
// The player automatically triggers slot 0 and slot one off of triggers #
// 0 & 1. Trigger # 2 is also used as the jump key.
}
//-----------------------------------------------------------------------------
function Armor::onPoseChange(%this, %obj, %oldPose, %newPose)
{
// Set the script anim prefix to be that of the current pose
%obj.setImageScriptAnimPrefix( $WeaponSlot, addTaggedString(%newPose) );
}
//-----------------------------------------------------------------------------
function Armor::onStartSprintMotion(%this, %obj)
{
%obj.setImageGenericTrigger($WeaponSlot, 0, true);
}
function Armor::onStopSprintMotion(%this, %obj)
{
%obj.setImageGenericTrigger($WeaponSlot, 0, false);
}
//-----------------------------------------------------------------------------
// Player methods
//-----------------------------------------------------------------------------
//----------------------------------------------------------------------------
function Player::kill(%this, %damageType)
{
%this.damage(0, %this.getPosition(), 10000, %damageType);
}
//----------------------------------------------------------------------------
function Player::mountVehicles(%this, %bool)
{
// If set to false, this variable disables vehicle mounting.
%this.mountVehicle = %bool;
}
function Player::isPilot(%this)
{
%vehicle = %this.getObjectMount();
// There are two "if" statements to avoid a script warning.
if (%vehicle)
if (%vehicle.getMountNodeObject(0) == %this)
return true;
return false;
}
//----------------------------------------------------------------------------
function Player::playDeathAnimation(%this)
{
%numDeathAnimations = %this.getNumDeathAnimations();
if ( %numDeathAnimations > 0 )
{
if (isObject(%this.client))
{
if (%this.client.deathIdx++ > %numDeathAnimations)
%this.client.deathIdx = 1;
%this.setActionThread("Death" @ %this.client.deathIdx);
}
else
{
%rand = getRandom(1, %numDeathAnimations);
%this.setActionThread("Death" @ %rand);
}
}
}
function Player::playCelAnimation(%this, %anim)
{
if (%this.getState() !$= "Dead")
%this.setActionThread("cel"@%anim);
}
//----------------------------------------------------------------------------
function Player::playDeathCry(%this)
{
%this.playAudio(0, DeathCrySound);
}
function Player::playPain(%this)
{
%this.playAudio(0, PainCrySound);
}
// ----------------------------------------------------------------------------
// Numerical Health Counter
// ----------------------------------------------------------------------------
function Player::updateHealth(%player)
{
//echo("\c4Player::updateHealth() -> Player Health changed, updating HUD!");
// Calcualte player health
%maxDamage = %player.getDatablock().maxDamage;
%damageLevel = %player.getDamageLevel();
%curHealth = %maxDamage - %damageLevel;
%curHealth = mceil(%curHealth);
// Send the player object's current health level to the client, where it
// will Update the numericalHealth HUD.
commandToClient(%player.client, 'setNumericalHealthHUD', %curHealth);
}
function Player::setDamageDirection(%player, %sourceObject, %damagePos)
{
if (isObject(%sourceObject))
{
if (%sourceObject.isField(initialPosition))
{
// Projectiles have this field set to the muzzle point of
// the firing weapon at the time the projectile was created.
// This gives a damage direction towards the firing player,
// turret, vehicle, etc. Bullets and weapon fired grenades
// are examples of projectiles.
%damagePos = %sourceObject.initialPosition;
}
else
{
// Other objects that cause damage, such as mines, use their own
// location as the damage position. This gives a damage direction
// towards the explosive origin rather than the person that lay the
// explosives.
%damagePos = %sourceObject.getPosition();
}
}
// Rotate damage vector into object space
%damageVec = VectorSub(%damagePos, %player.getWorldBoxCenter());
%damageVec = VectorNormalize(%damageVec);
%damageVec = MatrixMulVector(%player.client.getCameraObject().getInverseTransform(), %damageVec);
// Determine largest component of damage vector to get direction
%vecComponents = -%damageVec.x SPC %damageVec.x SPC -%damageVec.y SPC %damageVec.y SPC -%damageVec.z SPC %damageVec.z;
%vecDirections = "Left" SPC "Right" SPC "Bottom" SPC "Front" SPC "Bottom" SPC "Top";
%max = -1;
for (%i = 0; %i < 6; %i++)
{
%value = getWord(%vecComponents, %i);
if (%value > %max)
{
%max = %value;
%damageDir = getWord(%vecDirections, %i);
}
}
commandToClient(%player.client, 'setDamageDirection', %damageDir);
}
function Player::use(%player, %data)
{
// No mounting/using weapons when you're driving!
if (%player.isPilot())
return(false);
Parent::use(%player, %data);
}

View file

@ -0,0 +1,46 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
// "Universal" script methods for projectile damage handling. You can easily
// override these support functions with an equivalent namespace method if your
// weapon needs a unique solution for applying damage.
function ProjectileData::onCollision(%data, %proj, %col, %fade, %pos, %normal)
{
//echo("ProjectileData::onCollision("@%data.getName()@", "@%proj@", "@%col.getClassName()@", "@%fade@", "@%pos@", "@%normal@")");
// Apply damage to the object all shape base objects
if (%data.directDamage > 0)
{
if (%col.getType() & ($TypeMasks::ShapeBaseObjectType))
%col.damage(%proj, %pos, %data.directDamage, %data.damageType);
}
}
function ProjectileData::onExplode(%data, %proj, %position, %mod)
{
//echo("ProjectileData::onExplode("@%data.getName()@", "@%proj@", "@%position@", "@%mod@")");
// Damage objects within the projectiles damage radius
if (%data.damageRadius > 0)
radiusDamage(%proj, %position, %data.damageRadius, %data.radiusDamage, %data.damageType, %data.areaImpulse);
}

View file

@ -0,0 +1,118 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
function ProximityMineData::onThrow( %this, %user, %amount )
{
// Remove the object from the inventory
%user.decInventory( %this, 1 );
// Construct the actual object in the world, and add it to
// the mission group so its cleaned up when the mission is
// done. The object is given a random z rotation.
%obj = new ProximityMine()
{
datablock = %this;
sourceObject = %user;
rotation = "0 0 1 "@ (getRandom() * 360);
static = false;
client = %user.client;
};
MissionCleanup.add(%obj);
return %obj;
}
function ProximityMineData::onTriggered( %this, %obj, %target )
{
//echo(%this.name SPC "triggered by " @ %target.getClassName());
}
function ProximityMineData::onExplode( %this, %obj, %position )
{
// Damage objects within the mine's damage radius
if ( %this.damageRadius > 0 )
radiusDamage( %obj, %position, %this.damageRadius, %this.radiusDamage, %this.damageType, %this.areaImpulse );
}
function ProximityMineData::damage( %this, %obj, %position, %source, %amount, %damageType )
{
// Explode if any damage is applied to the mine
%obj.schedule(50 + getRandom(50), explode);
}
// Customized kill message for deaths caused by proximity mines
function sendMsgClientKilled_MineDamage( %msgType, %client, %sourceClient, %damLoc )
{
if ( %sourceClient $= "" ) // editor placed mine
messageAll( %msgType, '%1 was blown up!', %client.playerName );
else if ( %sourceClient == %client ) // own mine
messageAll( %msgType, '%1 stepped on his own mine!', %client.playerName );
else // enemy placed mine
messageAll( %msgType, '%1 was blown up by %2!', %client.playerName, %sourceClient.playerName );
}
// ----------------------------------------------------------------------------
// Player deployable proximity mine
// ----------------------------------------------------------------------------
// Cannot use the Weapon class for ProximityMineData datablocks as it is already tied
// to ItemData.
function ProxMine::onUse(%this, %obj)
{
// Act like a weapon on use
Weapon::onUse( %this, %obj );
}
function ProxMine::onPickup( %this, %obj, %shape, %amount )
{
// Act like a weapon on pickup
Weapon::onPickup( %this, %obj, %shape, %amount );
}
function ProxMine::onInventory( %this, %obj, %amount )
{
%obj.client.setAmmoAmountHud( 1, %amount );
// Cycle weapons if we are out of ammo
if ( !%amount && ( %slot = %obj.getMountSlot( %this.image ) ) != -1 )
%obj.cycleWeapon( "prev" );
}
function ProxMineImage::onMount( %this, %obj, %slot )
{
// The mine doesn't use ammo from a player's perspective.
%obj.setImageAmmo( %slot, true );
%numMines = %obj.getInventory(%this.item);
%obj.client.RefreshWeaponHud( 1, %this.item.previewImage, %this.item.reticle, %this.item.zoomReticle, %numMines );
}
function ProxMineImage::onUnmount( %this, %obj, %slot )
{
%obj.client.RefreshWeaponHud( 0, "", "" );
}
function ProxMineImage::onFire( %this, %obj, %slot )
{
// To fire a deployable mine is to throw it
%obj.throw( %this.item );
}

View file

@ -0,0 +1,72 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
// Support function which applies damage to objects within the radius of
// some effect, usually an explosion. This function will also optionally
// apply an impulse to each object.
function radiusDamage(%sourceObject, %position, %radius, %damage, %damageType, %impulse)
{
// Use the container system to iterate through all the objects
// within our explosion radius. We'll apply damage to all ShapeBase
// objects.
InitContainerRadiusSearch(%position, %radius, $TypeMasks::ShapeBaseObjectType);
%halfRadius = %radius / 2;
while ((%targetObject = containerSearchNext()) != 0)
{
// Calculate how much exposure the current object has to
// the explosive force. The object types listed are objects
// that will block an explosion. If the object is totally blocked,
// then no damage is applied.
%coverage = calcExplosionCoverage(%position, %targetObject,
$TypeMasks::InteriorObjectType |
$TypeMasks::TerrainObjectType |
$TypeMasks::ForceFieldObjectType |
$TypeMasks::StaticShapeObjectType |
$TypeMasks::VehicleObjectType);
if (%coverage == 0)
continue;
// Radius distance subtracts out the length of smallest bounding
// box axis to return an appriximate distance to the edge of the
// object's bounds, as opposed to the distance to it's center.
%dist = containerSearchCurrRadiusDist();
// Calculate a distance scale for the damage and the impulse.
// Full damage is applied to anything less than half the radius away,
// linear scale from there.
%distScale = (%dist < %halfRadius)? 1.0 : 1.0 - ((%dist - %halfRadius) / %halfRadius);
// Apply the damage
%targetObject.damage(%sourceObject, %position, %damage * %coverage * %distScale, %damageType);
// Apply the impulse
if (%impulse)
{
%impulseVec = VectorSub(%targetObject.getWorldBoxCenter(), %position);
%impulseVec = VectorNormalize(%impulseVec);
%impulseVec = VectorScale(%impulseVec, %impulse * %distScale);
%targetObject.applyImpulse(%position, %impulseVec);
}
}
}

View file

@ -0,0 +1,99 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Support methods used to track our number of ready shells for a charged shot.
// ----------------------------------------------------------------------------
function RocketLauncherImage::readyLoad(%this)
{
//echo("\c4RocketLauncherImage::readyLoad("@ %this.getName()@")");
%this.loadCount = 1;
//echo("\c4 loadCount = "@ %this.loadCount);
}
function RocketLauncherImage::incLoad(%this)
{
//echo("\c4RocketLauncherImage::incLoad("@ %this.getName()@")");
%this.loadCount++;
//echo("\c4 loadCount = "@ %this.loadCount);
}
// ----------------------------------------------------------------------------
// The fire method that does all of the work
// ----------------------------------------------------------------------------
function RocketLauncherImage::onAltFire(%this, %obj, %slot)
{
//echo("\c4RocketLauncherImage::onFire("@ %this.getName() @", "@ %obj.client.nameBase @", "@ %slot@")");
//echo("\c4 #in the pipe = "@ %this.loadCount);
//echo("");
// Let's check amount of ammo, if it's less than the loadCount then only
// fire the number of shots equal to the ammount of remaining ammo.
%currentAmmo = %obj.getInventory(%this.ammo);
if(%currentAmmo < %this.loadCount)
%this.loadCount = %currentAmmo;
for(%shotCount = 0; %shotCount < %this.loadCount; %shotCount++)
{
// Decrement inventory ammo. The image's ammo state is updated
// automatically by the ammo inventory hooks.
%obj.decInventory(%this.ammo, 1);
// We fire our weapon using the straight ahead aiming point of the gun
//%muzzleVector = %obj.getMuzzleVector(%slot);
// We'll need to "skew" the 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 * 0.008 @ " ";
%mat = MatrixCreateFromEuler(%matrix);
// Which we'll use to alter the projectile's initial vector with
%muzzleVector = MatrixMulVector(%mat, %vec);
// Get the player's velocity, we'll then add it to that of the projectile
%objectVelocity = %obj.getVelocity();
%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;
};
MissionCleanup.add(%p);
}
return %p;
}

View file

@ -0,0 +1,61 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
// Load up all scripts. This function is called when
// a server is constructed.
exec("./camera.cs");
exec("./triggers.cs");
exec("./inventory.cs");
exec("./shapeBase.cs");
exec("./item.cs");
exec("./health.cs");
exec("./projectile.cs");
exec("./radiusDamage.cs");
exec("./teleporter.cs");
// Load our supporting weapon script, it contains methods used by all weapons.
exec("./weapon.cs");
// Load our weapon scripts
// We only need weapon scripts for those weapons that work differently from the
// "generic" methods defined in weapon.cs
exec("./rocketLauncher.cs");
exec("./soldierGun.cs");
exec("./grenadeLauncher.cs");
exec("./proximityMine.cs");
// Load our default player script
exec("./player.cs");
// Load our player scripts
exec("./aiPlayer.cs");
exec("./vehicle.cs");
exec("./vehicleWheeled.cs");
exec("./cheetah.cs");
// Load turret support scripts
exec("./turret.cs");
// Load our gametypes
exec("./gameCore.cs"); // This is the 'core' of the gametype functionality.
exec("./gameDM.cs"); // Overrides GameCore with DeathMatch functionality.

View file

@ -0,0 +1,108 @@
//-----------------------------------------------------------------------------
// 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 ShapeBase methods used by all the derived classes
//-----------------------------------------------------------------------------
// ShapeBase object
//-----------------------------------------------------------------------------
// A raycast helper function to keep from having to duplicate code everytime
// that a raycast is needed.
// %this = the object doing the cast, usually a player
// %range = range to search
// %mask = what to look for
function ShapeBase::doRaycast(%this, %range, %mask)
{
// get the eye vector and eye transform of the player
%eyeVec = %this.getEyeVector();
%eyeTrans = %this.getEyeTransform();
// extract the position of the player's camera from the eye transform (first 3 words)
%eyePos = getWord(%eyeTrans, 0) SPC getWord(%eyeTrans, 1) SPC getWord(%eyeTrans, 2);
// normalize the eye vector
%nEyeVec = VectorNormalize(%eyeVec);
// scale (lengthen) the normalized eye vector according to the search range
%scEyeVec = VectorScale(%nEyeVec, %range);
// add the scaled & normalized eye vector to the position of the camera
%eyeEnd = VectorAdd(%eyePos, %scEyeVec);
// see if anything gets hit
%searchResult = containerRayCast(%eyePos, %eyeEnd, %mask, %this);
return %searchResult;
}
//-----------------------------------------------------------------------------
function ShapeBase::damage(%this, %sourceObject, %position, %damage, %damageType)
{
// All damage applied by one object to another should go through this method.
// This function is provided to allow objects some chance of overriding or
// processing damage values and types. As opposed to having weapons call
// ShapeBase::applyDamage directly. Damage is redirected to the datablock,
// this is standard procedure for many built in callbacks.
if (isObject(%this))
%this.getDataBlock().damage(%this, %sourceObject, %position, %damage, %damageType);
}
//-----------------------------------------------------------------------------
function ShapeBase::setDamageDt(%this, %damageAmount, %damageType)
{
// This function is used to apply damage over time. The damage is applied
// at a fixed rate (50 ms). Damage could be applied over time using the
// built in ShapBase C++ repair functions (using a neg. repair), but this
// has the advantage of going through the normal script channels.
if (%this.getState() !$= "Dead")
{
%this.damage(0, "0 0 0", %damageAmount, %damageType);
%this.damageSchedule = %this.schedule(50, "setDamageDt", %damageAmount, %damageType);
}
else
%this.damageSchedule = "";
}
function ShapeBase::clearDamageDt(%this)
{
if (%this.damageSchedule !$= "")
{
cancel(%this.damageSchedule);
%this.damageSchedule = "";
}
}
//-----------------------------------------------------------------------------
// ShapeBase datablock
//-----------------------------------------------------------------------------
function ShapeBaseData::damage(%this, %obj, %position, %source, %amount, %damageType)
{
// Ignore damage by default. This empty method is here to
// avoid console warnings.
}

View file

@ -0,0 +1,32 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
function Soldier_gunImage::onMount(%this, %obj, %slot)
{
// Make it ready
Parent::onMount(%this, %obj, %slot);
}
function Soldier_gunImage::onAltFire(%this, %obj, %slot)
{
echo("Fire Grenade!");
}

View file

@ -0,0 +1,251 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Trigger-derrived teleporter object. Teleports an object from it's entrance to
// it's exit if one is defined.
function TeleporterTrigger::onAdd( %this, %teleporter )
{
// Setup default parameters.
if ( %teleporter.exit $= "" )
%teleporter.exit = "NameOfTeleporterExit";
if ( %teleporter.teleporterCooldown $= "" )
%teleporter.teleporterCooldown = %this.teleporterCooldown;
if ( %teleporter.exitVelocityScale $= "" )
%teleporter.exitVelocityScale = %this.exitVelocityScale;
if ( %teleporter.reorientPlayer $= "" )
%teleporter.reorientPlayer = %this.reorientPlayer;
if ( %teleporter.oneSided $= "" )
%teleporter.oneSided = %this.oneSided;
if ( %teleporter.entranceEffect $= "" )
%teleporter.entranceEffect = %this.entranceEffect;
if ( %teleporter.exitEffect $= "" )
%teleporter.exitEffect = %this.exitEffect;
// We do not want to save this variable between levels,
// clear it out every time the teleporter is added
// to the scene.
%teleporter.timeOfLastTeleport = "";
}
function TeleporterTrigger::onLeaveTrigger(%this,%trigger,%obj)
{
// This is called after onEnterTrigger for BOTH
// The teleporter's entrance and exit
%obj.isTeleporting = false;
}
//ARGS:
// %this - The teleporter datablock.
// %entrance - The teleporter the player has entered (The one calling this function).
// %obj - The object that entered the teleporter.
function TeleporterTrigger::onEnterTrigger(%this, %entrance, %obj)
{
// Get the location of our target position
%exit = nameToID(%entrance.exit);
// Check if the the teleport is valid.
%valid = %this.verifyObject(%obj, %entrance, %exit);
// Bail out early if we cannot complete this teleportation
if (!%valid)
return;
// Kill any players in the exit teleporter.
%this.telefrag(%obj, %exit);
// Create our entrance effects on all clients.
if (isObject(%entrance.entranceEffect))
{
for(%idx = 0; %idx < ClientGroup.getCount(); %idx++)
commandToClient(ClientGroup.getObject(%idx), 'PlayTeleportEffect', %entrance.position, %entrance.entranceEffect.getId());
}
// Teleport the player to the exit teleporter.
%this.teleportPlayer(%obj, %exit);
// Create our exit effects on all clients.
if (isObject(%exit.exitEffect))
{
for(%idx = 0; %idx < ClientGroup.getCount(); %idx++)
commandToClient(ClientGroup.getObject(%idx), 'PlayTeleportEffect', %exit.position, %exit.exitEffect.getId());
}
// Record what time we last teleported so we can determine if enough
// time has elapsed to teleport again
%entrance.timeOfLastTeleport = getSimTime();
// If this is a bidirectional teleporter, log it's exit too.
if (%exit.exit $= %entrance.name)
%exit.timeOfLastTeleport = %entrance.timeOfLastTeleport;
// Tell the client to play the 2D sound for the player that teleported.
if (isObject(%this.teleportSound) && isObject(%obj.client))
%obj.client.play2D(%this.teleportSound);
}
// Here we verify that the teleport is valid.
// Tests go here like if the object is of a 'teleportable' type, if the
// given teleporter has an exit defined, etc.
function TeleporterTrigger::verifyObject(%this, %obj, %entrance, %exit)
{
// Bail out early if we couldn't find an exit for this teleporter.
if (!isObject(%exit))
{
logError("Cound not find an exit for " @ %entrance.name @ ".");
return false;
}
// If the entrance is once sided, make sure the object
// approached it from it's front.
if (%entrance.oneSided)
{
%dotProduct = VectorDot(%entrance.getForwardVector(), %obj.getVelocity());
if (%dotProduct > 0)
return false;
}
// If we are coming directly from another teleporter and it happens
// to be bidirectional, We need to avoid ending sending objects through
// an infinite loop.
if (%obj.isTeleporting)
return false;
// We only want to teleport players
// So bail out early if we have found any
// other object.
if (!%obj.isMemberOfClass("Player"))
return false;
if (%entrance.timeOfLastTeleport > 0 && %entrance.teleporterCooldown > 0)
{
// Get the current time, subtract it from the time it last teleported
// And compare the difference to see if enough time has elapsed to
// activate the teleporter again.
%currentTime = getSimTime();
%timeDifference = %currentTime - %entrance.timeOfLastTeleport;
%db = %entrance.getDatablock();
if (%timeDifference <= %db.teleporterCooldown)
return false;
}
return true;
}
// Function to teleport object %player to teleporter %exit.
function TeleporterTrigger::teleportPlayer(%this, %player, %exit)
{
// Teleport our player to the exit teleporter.
if (%exit.reorientPlayer)
%targetPosition = %exit.getTransform();
else
{
%pos = %exit.getPosition();
%rot = getWords(%player.getTransform(), 3, 6);
%targetPosition = %pos SPC %rot;
}
%player.setTransform(%targetPosition);
// Adjust the player's velocity by the Exit location's scale.
%player.setVelocity(vectorScale(%player.getVelocity(), %exit.exitVelocityScale));
// Prevent the object from doing an immediate second teleport
// In the case of a bidirectional teleporter
%player.isTeleporting = true;
}
// Telefrag is a term used in multiplayer gaming when a player takes a teleporter
// while another player is occupying it's exit. The player at the exit location
// is killed, allowing the original player to arrive at the teleporter.
function TeleporterTrigger::teleFrag(%this, %player, %exit)
{
// When a telefrag happens, there are two cases we have to consider.
// The first case occurs when the player's bounding box is much larger than the exit location,
// it is possible to have players colide even though a player is not within the bounds
// of the trigger Because of this we first check a radius the size of a player's bounding
// box around the exit location.
// Get the bounding box of the player
%boundingBoxSize = %player.getDatablock().boundingBox;
%radius = getWord(%boundingBoxSize, 0);
%boxSizeY = getWord(%boundingBoxSize, 1);
%boxSizeZ = getWord(%boundingBoxSize, 2);
// Use the largest dimention as the radius to check
if (%boxSizeY > %radius)
%radius = %boxSizeY;
if (%boxSizeZ > %radius)
%radius = %boxSizeZ;
%position = %exit.getPosition();
%mask = $TypeMasks::PlayerObjectType;
// Check all objects within the found radius of the exit location, and telefrag
// any players that meet the conditions.
initContainerRadiusSearch( %position, %radius, %mask );
while ( (%objectNearExit = containerSearchNext()) != 0 )
{
if (!%objectNearExit.isMemberOfClass("Player"))
continue;
// Avoid killing the player that is teleporting in the case of two
// Teleporters near eachother.
if (%objectNearExit == %player)
continue;
%objectNearExit.damage(%player, %exit.getTransform(), 10000, "Telefrag");
}
// The second case occurs when the bounds of the trigger are much larger
// than the bounding box of the player. (So multiple players can exist within the
// same trigger). For this case we check all objects contained within the trigger
// and telefrag all players.
%objectsInExit = %exit.getNumObjects();
// Loop through all objects in the teleporter exit
// And kill any players
for(%i = 0; %i < %objectsInExit; %i++)
{
%objectInTeleporter = %exit.getObject(%i);
if (!%objectInTeleporter.isMemberOfClass("Player"))
continue;
// Avoid killing the player that is teleporting in the case of two
// Teleporters near eachother.
if (%objectInTeleporter == %player)
continue;
%objectInTeleporter.damage(%player, %exit.getTransform(), 10000, "Telefrag");
}
}
// Customized kill message for telefrag deaths
function sendMsgClientKilled_Telefrag(%msgType, %client, %sourceClient, %damLoc)
{
messageAll(%msgType, '%1 was telefragged by %2!', %client.playerName, %sourceClient.playerName);
}

View file

@ -0,0 +1,48 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// DefaultTrigger is used by the mission editor. This is also an example
// of trigger methods and callbacks.
function DefaultTrigger::onEnterTrigger(%this,%trigger,%obj)
{
// This method is called whenever an object enters the %trigger
// area, the object is passed as %obj.
}
function DefaultTrigger::onLeaveTrigger(%this,%trigger,%obj)
{
// This method is called whenever an object leaves the %trigger
// area, the object is passed as %obj.
}
function DefaultTrigger::onTickTrigger(%this,%trigger)
{
// This method is called every tickPerioMS, as long as any
// objects intersect the trigger.
// You can iterate through the objects in the list by using these
// methods:
// %trigger.getNumObjects();
// %trigger.getObject(n);
}

View file

@ -0,0 +1,492 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
// Respawntime is the amount of time it takes for a static "auto-respawn"
// turret to re-appear after it's been picked up. Any turret marked as "static"
// is automaticlly respawned.
$TurretShape::RespawnTime = 30 * 1000;
// DestroyedFadeDelay is the how long a destroyed turret sticks around before it
// fades out and is deleted.
$TurretShape::DestroyedFadeDelay = 5 * 1000;
// ----------------------------------------------------------------------------
// TurretShapeData
// ----------------------------------------------------------------------------
function TurretShapeData::onAdd(%this, %obj)
{
%obj.setRechargeRate(%this.rechargeRate);
%obj.setEnergyLevel(%this.MaxEnergy);
%obj.setRepairRate(0);
if (%obj.mountable || %obj.mountable $= "")
%this.isMountable(%obj, true);
else
%this.isMountable(%obj, false);
if (%this.nameTag !$= "")
%obj.setShapeName(%this.nameTag);
// Mount weapons
for(%i = 0; %i < %this.numWeaponMountPoints; %i++)
{
// Handle inventory
%obj.incInventory(%this.weapon[%i], 1);
%obj.incInventory(%this.weaponAmmo[%i], %this.weaponAmmoAmount[%i]);
// Mount the image
%obj.mountImage(%this.weapon[%i].image, %i, %this.startLoaded);
%obj.setImageGenericTrigger(%i, 0, false); // Used to indicate the turret is destroyed
}
if (%this.enterSequence !$= "")
{
%obj.entranceThread = 0;
%obj.playThread(%obj.entranceThread, %this.enterSequence);
%obj.pauseThread(%obj.entranceThread);
}
else
{
%obj.entranceThread = -1;
}
}
function TurretShapeData::onRemove(%this, %obj)
{
//echo("\c4TurretShapeData::onRemove("@ %this.getName() @", "@ %obj.getClassName() @")");
// if there are passengers/driver, kick them out
for(%i = 0; %i < %this.numMountPoints; %i++)
{
if (%obj.getMountNodeObject(%i))
{
%passenger = %obj.getMountNodeObject(%i);
%passenger.getDataBlock().doDismount(%passenger, true);
}
}
}
// This is on MissionGroup so it doesn't happen when the mission has ended
function MissionGroup::respawnTurret(%this, %datablock, %className, %transform, %static, %respawn)
{
%turret = new (%className)()
{
datablock = %datablock;
static = %static;
respawn = %respawn;
};
%turret.setTransform(%transform);
MissionGroup.add(%turret);
return %turret;
}
// ----------------------------------------------------------------------------
// TurretShapeData damage state
// ----------------------------------------------------------------------------
// This method is called by weapons fire
function TurretShapeData::damage(%this, %turret, %sourceObject, %position, %damage, %damageType)
{
//echo("\TurretShapeData::damage(" @ %turret @ ", "@ %sourceObject @ ", " @ %position @ ", "@ %damage @ ", "@ %damageType @ ")");
if (%turret.getState() $= "Dead")
return;
%turret.applyDamage(%damage);
// Update the numerical Health HUD
%mountedObject = %turret.getObjectMount();
if (%mountedObject)
%mountedObject.updateHealth();
// Kill any occupants
if (%turret.getState() $= "Dead")
{
for (%i = 0; %i < %this.numMountPoints; %i++)
{
%player = %turret.getMountNodeObject(%i);
if (%player != 0)
%player.killWithSource(%sourceObject, "InsideTurret");
}
}
}
function TurretShapeData::onDamage(%this, %obj, %delta)
{
// This method is invoked by the ShapeBase code whenever the
// object's damage level changes.
}
function TurretShapeData::onDestroyed(%this, %obj, %lastState)
{
// This method is invoked by the ShapeBase code whenever the
// object's damage state changes.
// Fade out the destroyed object. Then schedule a return.
%obj.startFade(1000, $TurretShape::DestroyedFadeDelay, true);
%obj.schedule($TurretShape::DestroyedFadeDelay + 1000, "delete");
if (%obj.doRespawn())
{
MissionGroup.schedule($TurretShape::RespawnTime, "respawnTurret", %this, %obj.getClassName(), %obj.getTransform(), true, true);
}
}
function TurretShapeData::onDisabled(%this, %obj, %lastState)
{
// This method is invoked by the ShapeBase code whenever the
// object's damage state changes.
}
function TurretShapeData::onEnabled(%this, %obj, %lastState)
{
// This method is invoked by the ShapeBase code whenever the
// object's damage state changes.
}
// ----------------------------------------------------------------------------
// TurretShapeData player mounting and dismounting
// ----------------------------------------------------------------------------
function TurretShapeData::isMountable(%this, %obj, %val)
{
%obj.mountable = %val;
}
function TurretShapeData::onMountObject(%this, %turret, %player, %node)
{
if (%turret.entranceThread >= 0)
{
%turret.setThreadDir(%turret.entranceThread, true);
%turret.setThreadPosition(%turret.entranceThread, 0);
%turret.playThread(%turret.entranceThread, "");
}
}
function TurretShapeData::onUnmountObject(%this, %turret, %player)
{
if (%turret.entranceThread >= 0)
{
// Play the entrance thread backwards for an exit
%turret.setThreadDir(%turret.entranceThread, false);
%turret.setThreadPosition(%turret.entranceThread, 1);
%turret.playThread(%turret.entranceThread, "");
}
}
function TurretShapeData::mountPlayer(%this, %turret, %player)
{
//echo("\c4TurretShapeData::mountPlayer("@ %this.getName() @", "@ %turret @", "@ %player.client.nameBase @")");
if (isObject(%turret) && %turret.getDamageState() !$= "Destroyed")
{
//%player.startFade(1000, 0, true);
//%this.schedule(1000, "setMountTurret", %turret, %player);
//%player.schedule(1500, "startFade", 1000, 0, false);
%this.setMountTurret(%turret, %player);
}
}
function TurretShapeData::setMountTurret(%this, %turret, %player)
{
//echo("\c4TurretShapeData::setMountTurret("@ %this.getName() @", "@ %turret @", "@ %player.client.nameBase @")");
if (isObject(%turret) && %turret.getDamageState() !$= "Destroyed")
{
%node = %this.findEmptySeat(%turret, %player);
if (%node >= 0)
{
//echo("\c4Mount Node: "@ %node);
%turret.mountObject(%player, %node);
//%player.playAudio(0, MountVehicleSound);
%player.mVehicle = %turret;
}
}
}
function TurretShapeData::findEmptySeat(%this, %turret, %player)
{
//echo("\c4This turret has "@ %this.numMountPoints @" mount points.");
for (%i = 0; %i < %this.numMountPoints; %i++)
{
%node = %turret.getMountNodeObject(%i);
if (%node == 0)
return %i;
}
return -1;
}
function TurretShapeData::switchSeats(%this, %turret, %player)
{
for (%i = 0; %i < %this.numMountPoints; %i++)
{
%node = %turret.getMountNodeObject(%i);
if (%node == %player || %node > 0)
continue;
if (%node == 0)
return %i;
}
return -1;
}
function TurretShapeData::onMount(%this, %turret, %player, %node)
{
//echo("\c4TurretShapeData::onMount("@ %this.getName() @", "@ %turret @", "@ %player.client.nameBase @")");
%player.client.RefreshVehicleHud(%turret, %this.reticle, %this.zoomReticle);
//%player.client.UpdateVehicleHealth(%turret);
}
function TurretShapeData::onUnmount(%this, %turret, %player, %node)
{
//echo("\c4TurretShapeData::onUnmount(" @ %this.getName() @ ", " @ %turret @ ", " @ %player.client.nameBase @ ")");
%player.client.RefreshVehicleHud(0, "", "");
}
// ----------------------------------------------------------------------------
// TurretShape damage
// ----------------------------------------------------------------------------
// This method is called by weapons fire
function TurretShape::damage(%this, %sourceObject, %position, %damage, %damageType)
{
//echo("\TurretShape::damage(" @ %this @ ", "@ %sourceObject @ ", " @ %position @ ", "@ %damage @ ", "@ %damageType @ ")");
%this.getDataBlock().damage(%this, %sourceObject, %position, %damage, %damageType);
}
// ----------------------------------------------------------------------------
// TurretDamage
// ----------------------------------------------------------------------------
// Customized kill message for deaths caused by turrets
function sendMsgClientKilled_TurretDamage( %msgType, %client, %sourceClient, %damLoc )
{
if ( %sourceClient $= "" ) // editor placed turret
messageAll( %msgType, '%1 was shot down by a turret!', %client.playerName );
else if ( %sourceClient == %client ) // own mine
messageAll( %msgType, '%1 kill by his own turret!', %client.playerName );
else // enemy placed mine
messageAll( %msgType, '%1 was killed by a turret of %2!', %client.playerName, %sourceClient.playerName );
}
// ----------------------------------------------------------------------------
// AITurretShapeData
// ----------------------------------------------------------------------------
function AITurretShapeData::onAdd(%this, %obj)
{
Parent::onAdd(%this, %obj);
%obj.mountable = false;
}
// Player has thrown a deployable turret. This copies from ItemData::onThrow()
function AITurretShapeData::onThrow(%this, %user, %amount)
{
// Remove the object from the inventory
if (%amount $= "")
%amount = 1;
if (%this.maxInventory !$= "")
if (%amount > %this.maxInventory)
%amount = %this.maxInventory;
if (!%amount)
return 0;
%user.decInventory(%this,%amount);
// Construct the actual object in the world, and add it to
// the mission group so it's cleaned up when the mission is
// done. The turret's rotation matches the player's.
%rot = %user.getEulerRotation();
%obj = new AITurretShape()
{
datablock = %this;
rotation = "0 0 1 " @ getWord(%rot, 2);
count = 1;
sourceObject = %user;
client = %user.client;
isAiControlled = true;
};
MissionGroup.add(%obj);
// Let the turret know that we're a firend
%obj.addToIgnoreList(%user);
// We need to add this turret to a list on the client so that if we die,
// the turret will still ignore our player.
%client = %user.client;
if (%client)
{
if (!%client.ownedTurrets)
{
%client.ownedTurrets = new SimSet();
}
// Go through the client's owned turret list. Make sure we're
// a friend of every turret and every turret is a friend of ours.
// Commence hugging!
for (%i=0; %i<%client.ownedTurrets.getCount(); %i++)
{
%turret = %client.ownedTurrets.getObject(%i);
%turret.addToIgnoreList(%obj);
%obj.addToIgnoreList(%turret);
}
// Add ourselves to the client's owned list.
%client.ownedTurrets.add(%obj);
}
return %obj;
}
function AITurretShapeData::onDestroyed(%this, %turret, %lastState)
{
// This method is invoked by the ShapeBase code whenever the
// object's damage state changes.
%turret.playAudio(0, TurretDestroyed);
%turret.setAllGunsFiring(false);
%turret.resetTarget();
%turret.setTurretState( "Destroyed", true );
// Set the weapons to destoryed
for(%i = 0; %i < %this.numWeaponMountPoints; %i++)
{
%turret.setImageGenericTrigger(%i, 0, true);
}
Parent::onDestroyed(%this, %turret, %lastState);
}
function AITurretShapeData::OnScanning(%this, %turret)
{
//echo("AITurretShapeData::OnScanning: " SPC %this SPC %turret);
%turret.startScanForTargets();
%turret.playAudio(0, TurretScanningSound);
}
function AITurretShapeData::OnTarget(%this, %turret)
{
//echo("AITurretShapeData::OnTarget: " SPC %this SPC %turret);
%turret.startTrackingTarget();
%turret.playAudio(0, TargetAquiredSound);
}
function AITurretShapeData::OnNoTarget(%this, %turret)
{
//echo("AITurretShapeData::OnNoTarget: " SPC %this SPC %turret);
%turret.setAllGunsFiring(false);
%turret.recenterTurret();
%turret.playAudio(0, TargetLostSound);
}
function AITurretShapeData::OnFiring(%this, %turret)
{
//echo("AITurretShapeData::OnFiring: " SPC %this SPC %turret);
%turret.setAllGunsFiring(true);
}
function AITurretShapeData::OnThrown(%this, %turret)
{
//echo("AITurretShapeData::OnThrown: " SPC %this SPC %turret);
%turret.playAudio(0, TurretThrown);
}
function AITurretShapeData::OnDeploy(%this, %turret)
{
//echo("AITurretShapeData::OnDeploy: " SPC %this SPC %turret);
// Set the weapons to loaded
for(%i = 0; %i < %this.numWeaponMountPoints; %i++)
{
%turret.setImageLoaded(%i, true);
}
%turret.playAudio(0, TurretActivatedSound);
}
// ----------------------------------------------------------------------------
// Player deployable turret
// ----------------------------------------------------------------------------
// Cannot use the Weapon class for deployable turrets as it is already tied
// to ItemData.
function DeployableTurretWeapon::onUse(%this, %obj)
{
Weapon::onUse(%this, %obj);
}
function DeployableTurretWeapon::onPickup(%this, %obj, %shape, %amount)
{
Weapon::onPickup(%this, %obj, %shape, %amount);
}
function DeployableTurretWeapon::onInventory(%this, %obj, %amount)
{
if (%obj.client !$= "" && !%obj.isAiControlled)
{
%obj.client.setAmmoAmountHud( 1, %amount );
}
// Cycle weapons if we are out of ammo
if ( !%amount && ( %slot = %obj.getMountSlot( %this.image ) ) != -1 )
%obj.cycleWeapon( "prev" );
}
function DeployableTurretWeaponImage::onMount(%this, %obj, %slot)
{
// The turret doesn't use ammo from a player's perspective.
%obj.setImageAmmo(%slot, true);
%numTurrets = %obj.getInventory(%this.item);
if (%obj.client !$= "" && !%obj.isAiControlled)
%obj.client.RefreshWeaponHud( 1, %this.item.previewImage, %this.item.reticle, %this.item.zoomReticle, %numTurrets);
}
function DeployableTurretWeaponImage::onUnmount(%this, %obj, %slot)
{
if (%obj.client !$= "" && !%obj.isAiControlled)
%obj.client.RefreshWeaponHud(0, "", "");
}
function DeployableTurretWeaponImage::onFire(%this, %obj, %slot)
{
//echo("\DeployableTurretWeaponImage::onFire( "@%this.getName()@", "@%obj.client.nameBase@", "@%slot@" )");
// To fire a deployable turret is to throw it. Schedule the throw
// so that it doesn't happen during this ShapeBaseImageData's state machine.
// If we throw the last one then we end up unmounting while the state machine
// is still being processed.
%obj.schedule(0, "throw", %this.item);
}

View file

@ -0,0 +1,130 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
// Parenting is in place for WheeledVehicleData to VehicleData. This should
// make it easier for people to simply drop in new (generic) vehicles. All that
// the user needs to create is a set of datablocks for the new wheeled vehicle
// to use. This means that no (or little) scripting should be necessary.
// Special, or unique vehicles however will still require some scripting. They
// may need to override the onAdd() function in order to mount weapons,
// differing tires/springs, etc., almost everything else is taken care of in the
// WheeledVehicleData and VehicleData methods. This helps us by not having to
// duplicate the same code for every new vehicle.
// In theory this would work for HoverVehicles and FlyingVehicles also, but
// hasn't been tested or fully implemented for those classes -- yet.
function VehicleData::onAdd(%this, %obj)
{
%obj.setRechargeRate(%this.rechargeRate);
%obj.setEnergyLevel(%this.MaxEnergy);
%obj.setRepairRate(0);
if (%obj.mountable || %obj.mountable $= "")
%this.isMountable(%obj, true);
else
%this.isMountable(%obj, false);
if (%this.nameTag !$= "")
%obj.setShapeName(%this.nameTag);
}
function VehicleData::onRemove(%this, %obj)
{
//echo("\c4VehicleData::onRemove("@ %this.getName() @", "@ %obj.getClassName() @")");
// if there are passengers/driver, kick them out
for(%i = 0; %i < %obj.getDatablock().numMountPoints; %i++)
{
if (%obj.getMountNodeObject(%i))
{
%passenger = %obj.getMountNodeObject(%i);
%passenger.getDataBlock().doDismount(%passenger, true);
}
}
}
// ----------------------------------------------------------------------------
// Vehicle player mounting and dismounting
// ----------------------------------------------------------------------------
function VehicleData::isMountable(%this, %obj, %val)
{
%obj.mountable = %val;
}
function VehicleData::mountPlayer(%this, %vehicle, %player)
{
//echo("\c4VehicleData::mountPlayer("@ %this.getName() @", "@ %vehicle @", "@ %player.client.nameBase @")");
if (isObject(%vehicle) && %vehicle.getDamageState() !$= "Destroyed")
{
%player.startFade(1000, 0, true);
%this.schedule(1000, "setMountVehicle", %vehicle, %player);
%player.schedule(1500, "startFade", 1000, 0, false);
}
}
function VehicleData::setMountVehicle(%this, %vehicle, %player)
{
//echo("\c4VehicleData::setMountVehicle("@ %this.getName() @", "@ %vehicle @", "@ %player.client.nameBase @")");
if (isObject(%vehicle) && %vehicle.getDamageState() !$= "Destroyed")
{
%node = %this.findEmptySeat(%vehicle, %player);
if (%node >= 0)
{
//echo("\c4Mount Node: "@ %node);
%vehicle.mountObject(%player, %node);
//%player.playAudio(0, MountVehicleSound);
%player.mVehicle = %vehicle;
}
}
}
function VehicleData::findEmptySeat(%this, %vehicle, %player)
{
//echo("\c4This vehicle has "@ %this.numMountPoints @" mount points.");
for (%i = 0; %i < %this.numMountPoints; %i++)
{
%node = %vehicle.getMountNodeObject(%i);
if (%node == 0)
return %i;
}
return -1;
}
function VehicleData::switchSeats(%this, %vehicle, %player)
{
for (%i = 0; %i < %this.numMountPoints; %i++)
{
%node = %vehicle.getMountNodeObject(%i);
if (%node == %player || %node > 0)
continue;
if (%node == 0)
return %i;
}
return -1;
}

View file

@ -0,0 +1,102 @@
//-----------------------------------------------------------------------------
// 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 script methods unique to the WheeledVehicle class. All
// other necessary methods are contained in "../server/scripts/vehicle.cs" in
// which the "generic" Vehicle class methods that are shared by all vehicles,
// (flying, hover, and wheeled) can be found.
// Parenting is in place for WheeledVehicleData to VehicleData. This should
// make it easier for people to simply drop in new (generic) vehicles. All that
// the user needs to create is a set of datablocks for the new wheeled vehicle
// to use. This means that no (or little) scripting should be necessary.
function WheeledVehicleData::onAdd(%this, %obj)
{
Parent::onAdd(%this, %obj);
// Setup the car with some tires & springs
for (%i = %obj.getWheelCount() - 1; %i >= 0; %i--)
{
%obj.setWheelTire(%i, DefaultCarTire);
%obj.setWheelSpring(%i, DefaultCarSpring);
%obj.setWheelPowered(%i, false);
}
// Steer with the front tires
%obj.setWheelSteering(0, 1);
%obj.setWheelSteering(1, 1);
// Only power the two rear wheels... assuming there are only 4 wheels.
%obj.setWheelPowered(2, true);
%obj.setWheelPowered(3, true);
}
function WheeledVehicleData::onCollision(%this, %obj, %col, %vec, %speed)
{
// Collision with other objects, including items
}
// Used to kick the players out of the car that your crosshair is over
function serverCmdcarUnmountObj(%client, %obj)
{
%obj.unmount();
%obj.setControlObject(%obj);
%ejectpos = %obj.getPosition();
%ejectpos = VectorAdd(%ejectpos, "0 0 5");
%obj.setTransform(%ejectpos);
%ejectvel = %obj.mVehicle.getVelocity();
%ejectvel = VectorAdd(%ejectvel, "0 0 10");
%ejectvel = VectorScale(%ejectvel, %obj.getDataBlock().mass);
%obj.applyImpulse(%ejectpos, %ejectvel);
}
// Used to flip the car over if it manages to get stuck upside down
function serverCmdflipCar(%client)
{
%car = %client.player.getControlObject();
if (%car.getClassName() $= "WheeledVehicle")
{
%carPos = %car.getPosition();
%carPos = VectorAdd(%carPos, "0 0 3");
%car.setTransform(%carPos SPC "0 0 1 0");
}
}
function serverCmdsetPlayerControl(%client)
{
%client.setControlObject(%client.player);
}
function serverCmddismountVehicle(%client)
{
%car = %client.player.getControlObject();
%passenger = %car.getMountNodeObject(0);
%passenger.getDataBlock().doDismount(%passenger, true);
%client.setControlObject(%client.player);
}

View file

@ -0,0 +1,643 @@
//-----------------------------------------------------------------------------
// 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]);
}
}