Initial commit
This commit is contained in:
0
Torque/SDK/example/starter.fps/server/banlist.cs
Normal file
0
Torque/SDK/example/starter.fps/server/banlist.cs
Normal file
47
Torque/SDK/example/starter.fps/server/defaults.cs
Normal file
47
Torque/SDK/example/starter.fps/server/defaults.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// List of master servers to query, each one is tried in order
|
||||
// until one responds
|
||||
$Pref::Server::RegionMask = 2;
|
||||
$pref::Master[0] = "2:master.garagegames.com:28002";
|
||||
|
||||
// Information about the server
|
||||
$Pref::Server::Name = "FPS Starter Kit";
|
||||
$Pref::Server::Info = "This is an fps starter kit test server.";
|
||||
|
||||
// The connection error message is transmitted to the client immediatly
|
||||
// on connection, if any further error occures during the connection
|
||||
// process, such as network traffic mismatch, or missing files, this error
|
||||
// message is display. This message should be replaced with information
|
||||
// usefull to the client, such as the url or ftp address of where the
|
||||
// latest version of the game can be obtained.
|
||||
$Pref::Server::ConnectionError =
|
||||
"You do not have the correct version of the FPS starter kit or "@
|
||||
"the related art needed to play on this server, please contact "@
|
||||
"the server operator for more information.";
|
||||
|
||||
// The network port is also defined by the client, this value
|
||||
// overrides pref::net::port for dedicated servers
|
||||
$Pref::Server::Port = 28000;
|
||||
|
||||
// If the password is set, clients must provide it in order
|
||||
// to connect to the server
|
||||
$Pref::Server::Password = "";
|
||||
|
||||
// Password for admin clients
|
||||
$Pref::Server::AdminPassword = "";
|
||||
|
||||
// Misc server settings.
|
||||
$Pref::Server::MaxPlayers = 64;
|
||||
$Pref::Server::TimeLimit = 20; // In minutes
|
||||
$Pref::Server::KickBanTime = 300; // specified in seconds
|
||||
$Pref::Server::BanTime = 1800; // specified in seconds
|
||||
$Pref::Server::FloodProtectionEnabled = 1;
|
||||
$Pref::Server::MaxChatLen = 120;
|
||||
|
||||
// Voice compression is currently not supported in the Torque Engine
|
||||
// .v12 (1.2 kbits/sec), .v24 (2.4 kbits/sec), .v29 (2.9kbits/sec)
|
||||
$Audio::voiceCodec = ".v12";
|
||||
BIN
Torque/SDK/example/starter.fps/server/defaults.cs.dso
Normal file
BIN
Torque/SDK/example/starter.fps/server/defaults.cs.dso
Normal file
Binary file not shown.
80
Torque/SDK/example/starter.fps/server/init.cs
Normal file
80
Torque/SDK/example/starter.fps/server/init.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// 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 MOD: FPS Starter Kit: Server ---------");
|
||||
|
||||
// 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 = "*/missions/*.mis";
|
||||
|
||||
// The common module provides the basic server functionality
|
||||
initBaseServer();
|
||||
|
||||
// Load up game server support scripts
|
||||
exec("./scripts/commands.cs");
|
||||
exec("./scripts/centerPrint.cs");
|
||||
exec("./scripts/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)");
|
||||
}
|
||||
|
||||
BIN
Torque/SDK/example/starter.fps/server/init.cs.dso
Normal file
BIN
Torque/SDK/example/starter.fps/server/init.cs.dso
Normal file
Binary file not shown.
13
Torque/SDK/example/starter.fps/server/prefs.cs
Normal file
13
Torque/SDK/example/starter.fps/server/prefs.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
$Pref::Server::AdminPassword = "";
|
||||
$Pref::Server::BanTime = 1800;
|
||||
$Pref::Server::ConnectionError = "You do not have the correct version of the FPS starter kit or the related art needed to play on this server, please contact the server operator for more information.";
|
||||
$Pref::Server::FloodProtectionEnabled = 1;
|
||||
$Pref::Server::Info = "This is an fps starter kit test server.";
|
||||
$Pref::Server::KickBanTime = 300;
|
||||
$Pref::Server::MaxChatLen = 120;
|
||||
$Pref::Server::MaxPlayers = 64;
|
||||
$Pref::Server::Name = "FPS Starter Kit";
|
||||
$Pref::Server::Password = "";
|
||||
$Pref::Server::Port = 28000;
|
||||
$Pref::Server::RegionMask = 2;
|
||||
$Pref::Server::TimeLimit = 20;
|
||||
BIN
Torque/SDK/example/starter.fps/server/prefs.cs.dso
Normal file
BIN
Torque/SDK/example/starter.fps/server/prefs.cs.dso
Normal file
Binary file not shown.
672
Torque/SDK/example/starter.fps/server/scripts/BlackKnight.cs
Normal file
672
Torque/SDK/example/starter.fps/server/scripts/BlackKnight.cs
Normal file
@@ -0,0 +1,672 @@
|
||||
$AI_PLAYER_ENABLED = true; //Are bots loaded when markers found on the map
|
||||
$AI_PLAYER_FIREDELAY = 500; //Delay from end of one firing pulse to begin of next shot.
|
||||
$AI_PLAYER_ENHANCED_FOV_TIME =3000; //Length of time bot is given 360deg vision when attacked.
|
||||
$AI_PLAYER_FOV =160; //The bots field of vision 160 means the bot sees -80 to +80 degrees
|
||||
//from it's eye vector.
|
||||
$AI_PLAYER_DETECT_DISTANCE =200; //Sets how close a target has to be before a bot will start reacting
|
||||
//to its presence.
|
||||
$AI_PLAYER_IGNORE_DISTANCE = 150; //A bot will ignore and not shoot at a target beyond this distance.
|
||||
$AI_PLAYER_SCANTIME =500; //This is the minimum time in milliseconds between scans for threats.
|
||||
$AI_PLAYER_CREATION_DELAY =5000; //This delay controls how long a bot will wait to start scanning for
|
||||
//threats upon creation.
|
||||
$AI_PLAYER_TRIGGER_DOWN = 100; //Sets how long the bot holds down the trigger when firing. For single
|
||||
//shot weapons a low value works fine, for continuous fire weapons the
|
||||
//larger the number, the larget the burst of fire will last.
|
||||
$AI_PLAYER_DEFAULTRESPAWN = true; //Sets whether bots respawn or not as a deault - can be overrode by setting
|
||||
//a dynamic variable called respawn in the map editor on a per bot basis.
|
||||
$AI_PLAYER_RESPAWN_DELAY = 20000; //Sets the delay in ms that a bot will wait before respawning.
|
||||
$AI_PLAYER_MAX_ATTENTION = 10; //This number and $AI_PLAYER_SCANTIME are multiplied to set the delay in the //thinking loop. Used to free up processor time on bots out of the mix.
|
||||
//My default values of 500ms min and 10 for an attention level means that a bot will
|
||||
//scan no more often than 500ms and no less than 5 seconds.
|
||||
|
||||
|
||||
|
||||
|
||||
//The AIPlayer Marker is a simple shape that is placed in the map during design time.
|
||||
//The shape is replaced with an AIPlayer at the shapes position, and the shape is hidden.
|
||||
//DO NOT set the shape to be removed upon level loading. If you do so, when you go in to
|
||||
//edit the map the shapes will have been deleted, and if you save the file your AIPlayer markers will
|
||||
//not be saved and your markers will be lost.
|
||||
datablock ItemData(AIPlayerMarker)
|
||||
{
|
||||
//This shape will be listed under the Shapes in the mission editor
|
||||
category = "AIMarker";
|
||||
|
||||
// Basic Item properties
|
||||
//Basic shape file to use as a marker in the editor.
|
||||
shapeFile = "~/data/shapes/markers/octahedron.dts";
|
||||
mass = 1;
|
||||
friction = 1;
|
||||
elasticity = 0.3;
|
||||
|
||||
};
|
||||
|
||||
datablock PlayerData(DemoPlayer : PlayerBody)
|
||||
{
|
||||
shootingDelay = 100;
|
||||
};
|
||||
|
||||
|
||||
function DemoPlayer::onReachDestination(%this,%obj)
|
||||
{
|
||||
// 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::onEndOfPath(%this,%obj,%path)
|
||||
{
|
||||
%obj.nextTask();
|
||||
}
|
||||
|
||||
function DemoPlayer::onEndSequence(%this,%obj,%slot)
|
||||
{
|
||||
echo("Sequence Done!");
|
||||
%obj.stopThread(%slot);
|
||||
%obj.nextTask();
|
||||
}
|
||||
|
||||
|
||||
function DemoPlayer::OnDamage(%this, %obj, %delta)
|
||||
{
|
||||
%obj.attentionlevel=1;
|
||||
%obj.enhancefov(%obj);
|
||||
|
||||
if(%obj.getState() $= "Dead" && %obj.respawn == true)
|
||||
{
|
||||
%obj.delaybeforerespawn(%obj.botname, %obj.marker);
|
||||
%this.player=0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//The load entities function is called from game.cs
|
||||
//The call takes the form of
|
||||
// AIPlayer::LoadEntities();
|
||||
//It is placed in the game.cs file right after the part that reads
|
||||
// Start the game timer
|
||||
// if ($Game::Duration)
|
||||
// $Game::Schedule = schedule($Game::Duration * 1000, 0, "onGameDurationEnd" );
|
||||
// $Game::Running = true;
|
||||
//The call uses a simple brute force method of finding all AIPlayerMarkers
|
||||
//within the given radius of the center of the map. It then inserts an AI player at the
|
||||
//position of each marker, and then hides the marker from view.
|
||||
function AIPlayer::LoadEntities()
|
||||
{
|
||||
//checks to see if the entities are to be processed.
|
||||
if ($AI_PLAYER_ENABLED == true)
|
||||
{
|
||||
echo("Loading AIPlayer entities...");
|
||||
%position = "0 0 0";
|
||||
%radius = 100000.0;
|
||||
InitContainerRadiusSearch(%position, %radius, $TypeMasks::ItemObjectType);
|
||||
%i=0;
|
||||
while ((%targetObject = containerSearchNext()) != 0)
|
||||
{
|
||||
if (%targetobject.getDataBlock().getName() $= "AIPlayerMarker")
|
||||
{
|
||||
%i++;
|
||||
%player = AIPlayer::spawnAtMarker("Kork" @ %i, %targetobject);
|
||||
%targetobject.sethidden(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
echo("Patrol entities disabled...");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//OpenFire - This function is called when the AIPlayer has located a target.
|
||||
|
||||
function AIPlayer::openfire(%this, %obj, %tgt)
|
||||
{
|
||||
//If the AIPlayer is dead, or the target is dead, then the AIPlayer
|
||||
//will not shoot, and the AIPlayer's target will be cleared.
|
||||
if (%obj.getState() $= "Dead" || %tgt.player.getstate() $="Dead")
|
||||
{
|
||||
%firing = false;
|
||||
%obj.clearaim();
|
||||
}
|
||||
else
|
||||
{
|
||||
//If the AIPlayer was not firing, it will check the current distance to the target,
|
||||
//if the target is within the AIPlayer's ignore distance it will shoot, otherwise
|
||||
//the AIPlayer will not shoot.
|
||||
if(!%firing)
|
||||
{
|
||||
%rtt=vectorDist(%obj.getposition(), %tgt.player.getposition());
|
||||
|
||||
if(%rtt < $AI_PLAYER_IGNORE_DISTANCE)
|
||||
{
|
||||
%firing = true;
|
||||
//The following lines is added to keep the AIPlayer stocked with ammo all the time.
|
||||
//If you want the AIPlayer to run out of ammunition then remove this line.
|
||||
%obj.incinventory("Crossbowammo",100);
|
||||
|
||||
//This sets the AIPlayers target to shoot at. It uses a VectorAdd to
|
||||
//help correct for the problem of the AIPlayer shooting at the targets
|
||||
//feet.
|
||||
//I would recommend using a non-ballistic weapon for your AIPlayers
|
||||
//otherwise you may have to do some additional math to calculate a good
|
||||
//ballistics drop based on the AIplayers range to the target.
|
||||
%obj.setAimLocation(VectorAdd(%tgt.player.getPosition(),"0 0 2.0"));
|
||||
//This actually starts the AIPlayer shooting - equivalent to pulling and
|
||||
//holding down the trigger.
|
||||
%obj.setImageTrigger(0,true);
|
||||
}
|
||||
else
|
||||
{
|
||||
%obj.clearaim();
|
||||
}
|
||||
}
|
||||
}
|
||||
//This schedule is set to call the ceasefire method at the end of the desired time
|
||||
//set for the AIPlayer to hold down the trigger
|
||||
%this.trigger = %this.schedule($AI_PLAYER_TRIGGER_DOWN,"ceasefire", %obj);
|
||||
}
|
||||
|
||||
//CeaseFire - this makes the AIPlayer lift off the trigger
|
||||
function AIPlayer::ceasefire(%this, %obj)
|
||||
{
|
||||
//Makes the AIPlayer lift off the trigger
|
||||
%obj.setImageTrigger(0,false);
|
||||
//This schedule is created to implement a delay between the AIPlayer's
|
||||
//shots. This can be used to help set how aggressive the bot is.
|
||||
%this.trigger = %this.schedule($AI_PLAYER_FIREDELAY,"delayfire", %obj);
|
||||
}
|
||||
|
||||
function AIPlayer::delayfire(%this, %obj)
|
||||
{
|
||||
//This clears the AIPlayer's 'firing' flag.
|
||||
//This allows the player to shoot again the next time it
|
||||
//sees and selects a target within range.
|
||||
%firing = false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// AIPlayer static functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function AIPlayer::spawn(%name, %obj)
|
||||
{
|
||||
// Create the demo player object
|
||||
%player = new AIPlayer() {
|
||||
dataBlock = DemoPlayer;
|
||||
//This value is set to true for AIPlayers, it is referenced in player.cs
|
||||
//to help handle respawning bots properly.
|
||||
isbot=true;
|
||||
|
||||
//These variables are set for each bot, this is done on a per bot basis
|
||||
//because the fov and attention level for each bot will be adjusted during
|
||||
//the game.
|
||||
//FOV = Bot's field of vision in degrees. (180 deg. means everything in front of the bot)
|
||||
//attentionlevel = The bot's attention level is raised or lowered based on how near targets
|
||||
//are and whether targets are visible or not.
|
||||
fov=$AI_PLAYER_FOV;
|
||||
attentionlevel = $AI_PLAYER_MAX_ATTENTION/2;
|
||||
|
||||
//The following line allows gives access to the markers dynamic variables and it's spawn position.
|
||||
marker = %obj;
|
||||
|
||||
//The pathname variable is a dynamic variable set during map editing.
|
||||
//This allows the designer to attach each bot to a seperate path
|
||||
path = %obj.pathname;
|
||||
botname = %name;
|
||||
|
||||
};
|
||||
MissionCleanup.add(%player);
|
||||
|
||||
//The following set of if-then statements trap to see if the marker has a dynamic variable
|
||||
//called respawn. (Set during map editing.)
|
||||
//If it does then the players respawn flag is set accordingly true or false
|
||||
//as stated by the variable.
|
||||
//If there is no respawn variable set, then the flag is set to the default global value
|
||||
|
||||
if (%obj.respawn $= "" )
|
||||
{
|
||||
%player.respawn=$AI_PLAYER_DEFAULTRESPAWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (%obj.respawn == true)
|
||||
%player.respawn=true;
|
||||
else
|
||||
%player.respawn=false;
|
||||
}
|
||||
|
||||
//Calls equipbot - to set the AIPlayers initial inventory
|
||||
%player.EquipBot(%player);
|
||||
|
||||
%player.setShapeName(%name);
|
||||
%player.setTransform(%obj.gettransform());
|
||||
%player.followPath(%obj.pathname,-1);
|
||||
//This schedule is set start the bots thinking cycle.
|
||||
//The creation delay is used so that the AIPlayers can be set to not start
|
||||
//thinking for a long delay while the rest of the game loads and initializes.
|
||||
%player.schedule($AI_PLAYER_CREATION_DELAY,"doscan", %player);
|
||||
|
||||
return %player;
|
||||
}
|
||||
|
||||
|
||||
//The delay before respawn function is set to wait a specified duration before
|
||||
//respawning an AIPlayer
|
||||
function AIPlayer::DelayBeforeRespawn(%this, %name, %obj)
|
||||
{
|
||||
%this.respawntrigger = %this.schedule($AI_PLAYER_RESPAWN_DELAY,"respawn", %name, %obj);
|
||||
}
|
||||
|
||||
//Equipbot - this function is called by spawn and respawn and is used to set the bot's
|
||||
//initial inventory.
|
||||
function AIPlayer::EquipBot(%this, %obj)
|
||||
{
|
||||
%obj.mountImage(CrossBowImage,0);
|
||||
%obj.setInventory(CrossbowAmmo,1000);
|
||||
}
|
||||
|
||||
// EnhanceFOV- This function sets the FOV for the AIPlayer to 360 degrees
|
||||
//This function is called from player.cs when the AIPlayer takes damage.
|
||||
//This has the same effect as having the AIPlayer scan all around him when damaged.
|
||||
//This reduces the need to perform a lot of extra checks to see which vector the damage has
|
||||
//come from, etc...
|
||||
function AIPlayer::EnhanceFOV(%this, %obj)
|
||||
{
|
||||
if (%obj.fov != 360)
|
||||
{
|
||||
%obj.fov = 360;
|
||||
%this.fovtrigger = %this.schedule($AI_PLAYER_ENHANCED_FOV_TIME,"restorefov", %obj);
|
||||
}
|
||||
}
|
||||
|
||||
//RestoreFOV - this function resets the AIPlayer's FOV back to the default value for the bot
|
||||
function AIPlayer::restoreFOV(%this, %obj)
|
||||
{
|
||||
%obj.fov = $AI_PLAYER_FOV;
|
||||
}
|
||||
|
||||
|
||||
//This function is called when a bot is respawned, it is nearly identical to spawn
|
||||
//With the exception of the parameters passed to it.
|
||||
function AIPlayer::respawn(%this, %name, %obj)
|
||||
{
|
||||
// Create the demo player object
|
||||
|
||||
%player = new AIPlayer() {
|
||||
dataBlock = PatrolPlayer;
|
||||
isbot=true;
|
||||
attentionlevel = $AI_PLAYER_MAX_ATTENTION/2;
|
||||
fov=$AI_PLAYER_FOV;
|
||||
|
||||
marker = %obj;
|
||||
path = %obj.pathname;
|
||||
|
||||
botname = %name;
|
||||
};
|
||||
MissionCleanup.add(%player);
|
||||
%player.setShapeName(%name);
|
||||
%player.EquipBot(%player);
|
||||
%player.setTransform(%obj.gettransform());
|
||||
%player.followPath(%obj.pathname,-1);
|
||||
|
||||
|
||||
if (%obj.respawn $="" )
|
||||
{
|
||||
%player.respawn=$AI_PLAYER_DEFAULTRESPAWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (%obj.respawn == true)
|
||||
%player.respawn=true;
|
||||
else
|
||||
%player.respawn=false;
|
||||
}
|
||||
%player.schedule($AI_PLAYER_CREATION_DELAY,"doscan", %player);
|
||||
return %player;
|
||||
}
|
||||
|
||||
function AIPlayer::spawnAtMarker(%name,%obj)
|
||||
{
|
||||
// Spawn a player and place him on the first node of the path
|
||||
if (!isObject(%obj))
|
||||
return;
|
||||
%player = AIPlayer::spawn(%name, %obj);
|
||||
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);
|
||||
}
|
||||
|
||||
//AITargeting
|
||||
|
||||
// Return the angle of a vector in relation to world origin
|
||||
//This function comes from code taken from several resources on garagegames
|
||||
//The only mods to the code I made are in the end of the code to ensure that variable
|
||||
//returns the angle in degrees, and that the angle is within 0-360 degrees.
|
||||
//I've seen sets of this code with the function returng %degangle rather than
|
||||
//%angle - but in this script %angle is needed.
|
||||
function AIPlayer::getAngleofVector(%this, %vec)
|
||||
{
|
||||
%vector = VectorNormalize(%vec);
|
||||
%vecx = getWord(%vector,0);
|
||||
%vecy = getWord(%vector,1);
|
||||
if(%vecx >= 0 && %vecy >= 0)
|
||||
%quad = 1;
|
||||
else
|
||||
if(%vecx >= 0 && %vecy < 0)
|
||||
%quad = 2;
|
||||
else
|
||||
if(%vecx < 0 && %vecy < 0)
|
||||
%quad = 3;
|
||||
else
|
||||
%quad = 4;
|
||||
%angle = mATan(%vecy/%vecx, -1);
|
||||
%degangle = mRadToDeg(%angle);
|
||||
switch(%quad)
|
||||
{
|
||||
case 1:
|
||||
%angle = %degangle-90;
|
||||
case 2:
|
||||
%angle = %degangle+270;
|
||||
case 3:
|
||||
%angle = %degangle+90;
|
||||
case 4:
|
||||
%angle = %degangle+450;
|
||||
}
|
||||
if (%angle < 0) %angle = %angle + 360;
|
||||
return %angle;
|
||||
}
|
||||
|
||||
//This is another function taken from code off of garagegames.
|
||||
//The only mods I made to it was to add the extra check to ensure that the
|
||||
//angle is within the 0-360 range.
|
||||
|
||||
function AIPlayer::check2DAngletoTarget(%this, %obj, %tgt)
|
||||
{
|
||||
%eyeVec = VectorNormalize(%this.getEyeVector());
|
||||
%eyeangle = %this.getAngleofVector(%eyeVec);
|
||||
%posVec = VectorSub(%tgt.player.getPosition(), %obj.getPosition());
|
||||
%posangle = %this.getAngleofVector(%posVec);
|
||||
%angle = %posangle - %eyeAngle;
|
||||
%angle = %angle ? %angle : %angle * -1;
|
||||
if (%angle < 0) %angle = %angle + 360;
|
||||
return %angle;
|
||||
}
|
||||
|
||||
//The DoScan function is the thinking part of the bot.
|
||||
//The following code is commented heavily to help explain the logic behind
|
||||
//the scripting.
|
||||
|
||||
function AIPlayer::DoScan(%this, %obj)
|
||||
{
|
||||
//Cancels the ailoop schedule
|
||||
cancel(%this.ailoop);
|
||||
//if the %obj object is invalid then exit the DoScan Loop.
|
||||
if (!%obj)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//By cancelling the ailoop, then checking to see if the bot is valid,
|
||||
//This should cancel any errant ailoops left hanging by bots killed or
|
||||
//removed from the game.
|
||||
|
||||
|
||||
//The next line calls a function to locate the closest human client that is
|
||||
//both within the bot's range, within it's field of vision, and is not hidden by
|
||||
//objects in the environment.
|
||||
%tgtid = %this.GetClosestHumanInSightandRange(%obj);
|
||||
|
||||
//Is the %tgtid valid target?
|
||||
if(%tgtid >=0)
|
||||
{
|
||||
//If yes, then get the player object of the client
|
||||
%tgt=ClientGroup.getobject(%tgtid);
|
||||
|
||||
if (%obj.getaimobject() != %tgt)
|
||||
{
|
||||
//Open fire on the current target
|
||||
%this.openfire(%obj, %tgt);
|
||||
%this.setMoveDestination(%obj, %tgt);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Since there is no valid target, then make sure the AIPlayer is
|
||||
//not firing, and clear it's target so it will face in a normal direction,
|
||||
//rather than tracking towards the target
|
||||
%obj.setImageTrigger(0,false);
|
||||
%obj.clearaim();
|
||||
|
||||
//The attention level is a value from 1 to MAX. The higher the number the
|
||||
//less attention the bot is paying. A level of 1 means that the bot scans
|
||||
//at it's fastest level.
|
||||
//The attention level is adjusted in GetClosestHumanInSightandRange
|
||||
|
||||
//The next line ensures that the AIPlayer's attention never goes above the default max
|
||||
if (%this.attentionlevel == $AI_PLAYER_MAX_ATTENTION)
|
||||
%obj.clearaim();
|
||||
}
|
||||
|
||||
//Sets the bot's next "DoScan" call - based on the default scan time adjusted by the
|
||||
//bot's attention level.
|
||||
%this.ailoop=%this.schedule($AI_PLAYER_SCANTIME * %this.attentionlevel,"DoScan" , %obj);
|
||||
}
|
||||
|
||||
//This is another function taken from code found on garagegames.
|
||||
//It checks to see if there are any static objects blocking the view
|
||||
//from the AIPlayer to the target.
|
||||
function AIPlayer::CheckLOS(%this, %obj, %tgt)
|
||||
{
|
||||
%eyeTrans = %obj.getEyeTransform();
|
||||
%eyeEnd = %tgt.player.getEyeTransform();
|
||||
%searchResult = containerRayCast(%eyeTrans, %eyeEnd, $TypeMasks::PlayerObjectType |
|
||||
$TypeMasks::TerrainObjectType | $TypeMasks::InteriorObjectType, %obj);
|
||||
%foundObject = getword(%searchResult,0);
|
||||
|
||||
if(%foundObject.getType() & $TypeMasks::PlayerObjectType)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function AIPlayer::GetClosestHumanInSightandRange(%this, %obj)
|
||||
{
|
||||
|
||||
%index = -1; //sets the initial index value to -1 The index is the id number of the nearest
|
||||
//human target found
|
||||
%botpos = %this.getposition(); //The bots current position
|
||||
%count = ClientGroup.getCount(); //The number of clients to check
|
||||
|
||||
//The for-next loop cycles through all of the valid clients
|
||||
for(%i=0; %i < %count; %i++)
|
||||
{
|
||||
%client = ClientGroup.getobject(%i); //Get the client info for the client at index %i
|
||||
|
||||
//If the client is invalid then the function bails out returning a -1 value, for no
|
||||
//target found.
|
||||
if (%client.player $= "" || %client.player ==0)
|
||||
return -1;
|
||||
|
||||
//The following line just changes the %client to %tgt to make it easier to follow the code below
|
||||
%tgt = %client;
|
||||
|
||||
%playpos = %client.player.getposition(); //Assigns the player position to a variable
|
||||
%tempdist = vectorDist(%playpos, %botpos); //Determine the distance from the bot to the target
|
||||
|
||||
//The first test we perform is to see if the target is within the bots range
|
||||
//Is target in range? If not bail out of checking to see if its in view.
|
||||
if (%tempdist <= $AI_PLAYER_DETECT_DISTANCE)
|
||||
{
|
||||
//Lower attentionlevel to increase response time...
|
||||
%this.attentionlevel--;
|
||||
if(%this.attentionlevel < 1) %this.attentionlevel=1;
|
||||
|
||||
//The second check is to see if the target is within the FOV of the bot.
|
||||
//Is the target within the fov field of vision of the bot?
|
||||
if(%this.Istargetinview(%obj, %tgt, %obj.fov))
|
||||
{
|
||||
//Lower attentionlevel to increase response time...
|
||||
%this.attentionlevel--;
|
||||
if(%this.attentionlevel < 1) %this.attentionlevel=1;
|
||||
|
||||
//The third check we run is to see if there is anything blocking the
|
||||
//target from the bot.
|
||||
if(%this.CheckLOS(%obj, %tgt))
|
||||
{
|
||||
//We lower the bots attention level again, to further increase it's
|
||||
//response time, this effectively means that the bot will respnd faster to
|
||||
//objects that are both in range and in plain sight.
|
||||
%this.attentionlevel--;
|
||||
|
||||
//Prevent the attention level from dropping below 1
|
||||
if(%this.attentionlevel < 1) %this.attentionlevel=1;
|
||||
|
||||
//If there is no current target, then the index to the client/target
|
||||
//and distance to the target are set. The distance is saved temporarily to run
|
||||
//a comparison against the other clients to determine which is closest.
|
||||
if(%i == 0)
|
||||
{
|
||||
%dist = %tempdist;
|
||||
%index = %i;
|
||||
}
|
||||
else
|
||||
{
|
||||
//If there is a current target, then check the distance to the new target as
|
||||
//compared to the current set target. If the new target is closest, then set
|
||||
//the index and tempdistance to the new target.
|
||||
if(%dist > %tempdist)
|
||||
{
|
||||
%dist = %tempdist;
|
||||
%index = %i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//If there are no targets in view, then the bots attention will slowly lapse and increase
|
||||
//This will slow down how fast the bot thinks and how often it checks for threats.
|
||||
%this.attentionlevel = %this.attentionlevel + 0.5;
|
||||
if(%this.attentionlevel > $AI_PLAYER_MAX_ATTENTION) %this.attentionlevel=$AI_PLAYER_MAX_ATTENTION;
|
||||
}
|
||||
}
|
||||
return %index;
|
||||
}
|
||||
|
||||
//This function checks to see if the target supplied is within the bots FOV
|
||||
function AIPlayer::IsTargetInView(%this, %obj, %tgt, %fov)
|
||||
{
|
||||
%ang = %this.check2dangletotarget(%obj, %tgt);
|
||||
|
||||
%visleft = 360 - (%fov/2);
|
||||
%visright = %fov/2;
|
||||
if (%ang > %visleft || %ang < %visright)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
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::animate(%this,%seq)
|
||||
{
|
||||
//%this.stopThread(0);
|
||||
//%this.playThread(0,%seq);
|
||||
%this.setActionThread(%seq);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BIN
Torque/SDK/example/starter.fps/server/scripts/BlackKnight.cs.dso
Normal file
BIN
Torque/SDK/example/starter.fps/server/scripts/BlackKnight.cs.dso
Normal file
Binary file not shown.
826
Torque/SDK/example/starter.fps/server/scripts/Orc.cs
Normal file
826
Torque/SDK/example/starter.fps/server/scripts/Orc.cs
Normal file
@@ -0,0 +1,826 @@
|
||||
$AI_PLAYER_ENABLED = true; //Are bots loaded when markers found on the map
|
||||
$AI_PLAYER_FIREDELAY = 500; //Delay from end of one firing pulse to begin of next shot.
|
||||
$AI_PLAYER_ENHANCED_FOV_TIME =3000; //Length of time bot is given 360deg vision when attacked.
|
||||
$AI_PLAYER_FOV =160; //The bots field of vision 160 means the bot sees -80 to +80 degrees
|
||||
//from it's eye vector.
|
||||
$AI_PLAYER_DETECT_DISTANCE =200; //Sets how close a target has to be before a bot will start reacting
|
||||
//to its presence.
|
||||
$AI_PLAYER_IGNORE_DISTANCE = 150; //A bot will ignore and not shoot at a target beyond this distance.
|
||||
$AI_PLAYER_SCANTIME =500; //This is the minimum time in milliseconds between scans for threats.
|
||||
$AI_PLAYER_CREATION_DELAY =5000; //This delay controls how long a bot will wait to start scanning for
|
||||
//threats upon creation.
|
||||
$AI_PLAYER_TRIGGER_DOWN = 100; //Sets how long the bot holds down the trigger when firing. For single
|
||||
//shot weapons a low value works fine, for continuous fire weapons the
|
||||
//larger the number, the larget the burst of fire will last.
|
||||
$AI_PLAYER_DEFAULTRESPAWN = true; //Sets whether bots respawn or not as a deault - can be overrode by setting
|
||||
//a dynamic variable called respawn in the map editor on a per bot basis.
|
||||
$AI_PLAYER_RESPAWN_DELAY = 20000; //Sets the delay in ms that a bot will wait before respawning.
|
||||
$AI_PLAYER_MAX_ATTENTION = 10; //This number and $AI_PLAYER_SCANTIME are multiplied to set the delay in the
|
||||
//thinking loop. Used to free up processor time on bots out of the mix.
|
||||
//My default values of 500ms min and 10 for an attention level means that a bot will
|
||||
//scan no more often than 500ms and no less than 5 seconds.
|
||||
|
||||
|
||||
|
||||
|
||||
//The Orc Marker is a simple shape that is placed in the map during design time.
|
||||
//The shape is replaced with an Orc at the shapes position, and the shape is hidden.
|
||||
//DO NOT set the shape to be removed upon level loading. If you do so, when you go in to
|
||||
//edit the map the shapes will have been deleted, and if you save the file your Orc markers will
|
||||
//not be saved and your markers will be lost.
|
||||
exec("~/data/shapes/Orc/Orc.cs");
|
||||
datablock PlayerData(OrcBody)
|
||||
{
|
||||
renderFirstPerson = false;
|
||||
emap = true;
|
||||
|
||||
className = Armor;
|
||||
shapeFile = "~/data/shapes/Orc/Orc.dts";
|
||||
cameraMaxDist = 3;
|
||||
computeCRC = true;
|
||||
|
||||
canObserve = true;
|
||||
cmdCategory = "Clients";
|
||||
|
||||
cameraDefaultFov = 90.0;
|
||||
cameraMinFov = 5.0;
|
||||
cameraMaxFov = 120.0;
|
||||
|
||||
debrisShapeName = "~/data/shapes/Orc/debris_Orc.dts";
|
||||
debris = playerDebris;
|
||||
|
||||
aiAvoidThis = true;
|
||||
|
||||
minLookAngle = -1.4;
|
||||
maxLookAngle = 1.4;
|
||||
maxFreelookAngle = 3.0;
|
||||
|
||||
mass = 90;
|
||||
drag = 0.3;
|
||||
maxdrag = 0.4;
|
||||
density = 10;
|
||||
maxDamage = 100;
|
||||
maxEnergy = 60;
|
||||
repairRate = 0.33;
|
||||
energyPerDamagePoint = 75.0;
|
||||
|
||||
rechargeRate = 0.256;
|
||||
|
||||
runForce = 48 * 90;
|
||||
runEnergyDrain = 0;
|
||||
minRunEnergy = 0;
|
||||
maxForwardSpeed = 14;
|
||||
maxBackwardSpeed = 13;
|
||||
maxSideSpeed = 13;
|
||||
|
||||
maxUnderwaterForwardSpeed = 7.4;
|
||||
maxUnderwaterBackwardSpeed = 6.8;
|
||||
maxUnderwaterSideSpeed = 6.8;
|
||||
|
||||
jumpForce = 8.3 * 90;
|
||||
jumpEnergyDrain = 0;
|
||||
minJumpEnergy = 0;
|
||||
jumpDelay = 15;
|
||||
|
||||
recoverDelay = 9;
|
||||
recoverRunForceScale = 1.2;
|
||||
|
||||
minImpactSpeed = 45;
|
||||
speedDamageScale = 0.4;
|
||||
|
||||
boundingBox = "1.2 1.2 2.3";
|
||||
pickupRadius = 0.75;
|
||||
|
||||
// Damage location details
|
||||
boxNormalHeadPercentage = 0.83;
|
||||
boxNormalTorsoPercentage = 0.49;
|
||||
boxHeadLeftPercentage = 0;
|
||||
boxHeadRightPercentage = 1;
|
||||
boxHeadBackPercentage = 0;
|
||||
boxHeadFrontPercentage = 1;
|
||||
|
||||
// Foot Prints
|
||||
decalData = PlayerFootprint;
|
||||
decalOffset = 0.25;
|
||||
|
||||
footPuffEmitter = LightPuffEmitter;
|
||||
footPuffNumParts = 10;
|
||||
footPuffRadius = 0.25;
|
||||
|
||||
dustEmitter = LiftoffDustEmitter;
|
||||
|
||||
splash = PlayerSplash;
|
||||
splashVelocity = 4.0;
|
||||
splashAngle = 67.0;
|
||||
splashFreqMod = 300.0;
|
||||
splashVelEpsilon = 0.60;
|
||||
bubbleEmitTime = 0.4;
|
||||
splashEmitter[0] = PlayerFoamDropletsEmitter;
|
||||
splashEmitter[1] = PlayerFoamEmitter;
|
||||
splashEmitter[2] = PlayerBubbleEmitter;
|
||||
mediumSplashSoundVelocity = 10.0;
|
||||
hardSplashSoundVelocity = 20.0;
|
||||
exitSplashSoundVelocity = 5.0;
|
||||
|
||||
// Controls over slope of runnable/jumpable surfaces
|
||||
runSurfaceAngle = 70;
|
||||
jumpSurfaceAngle = 80;
|
||||
|
||||
minJumpSpeed = 20;
|
||||
maxJumpSpeed = 30;
|
||||
|
||||
horizMaxSpeed = 68;
|
||||
horizResistSpeed = 33;
|
||||
horizResistFactor = 0.35;
|
||||
|
||||
upMaxSpeed = 80;
|
||||
upResistSpeed = 25;
|
||||
upResistFactor = 0.3;
|
||||
|
||||
footstepSplashHeight = 0.35;
|
||||
|
||||
//NOTE: some sounds commented out until wav's are available
|
||||
|
||||
// Footstep Sounds
|
||||
FootSoftSound = FootLightSoftSound;
|
||||
FootHardSound = FootLightHardSound;
|
||||
FootMetalSound = FootLightMetalSound;
|
||||
FootSnowSound = FootLightSnowSound;
|
||||
FootShallowSound = FootLightShallowSplashSound;
|
||||
FootWadingSound = FootLightWadingSound;
|
||||
FootUnderwaterSound = FootLightUnderwaterSound;
|
||||
|
||||
//FootBubblesSound = FootLightBubblesSound;
|
||||
//movingBubblesSound = ArmorMoveBubblesSound;
|
||||
//waterBreathSound = WaterBreathMaleSound;
|
||||
|
||||
//impactSoftSound = ImpactLightSoftSound;
|
||||
//impactHardSound = ImpactLightHardSound;
|
||||
//impactMetalSound = ImpactLightMetalSound;
|
||||
//impactSnowSound = ImpactLightSnowSound;
|
||||
|
||||
//impactWaterEasy = ImpactLightWaterEasySound;
|
||||
//impactWaterMedium = ImpactLightWaterMediumSound;
|
||||
//impactWaterHard = ImpactLightWaterHardSound;
|
||||
|
||||
groundImpactMinSpeed = 10.0;
|
||||
groundImpactShakeFreq = "4.0 4.0 4.0";
|
||||
groundImpactShakeAmp = "1.0 1.0 1.0";
|
||||
groundImpactShakeDuration = 0.8;
|
||||
groundImpactShakeFalloff = 10.0;
|
||||
|
||||
//exitingWater = ExitingWaterLightSound;
|
||||
|
||||
observeParameters = "0.5 4.5 4.5";
|
||||
|
||||
// Allowable Inventory Items
|
||||
maxInv[BulletAmmo] = 20;
|
||||
maxInv[HealthKit] = 1;
|
||||
maxInv[RifleAmmo] = 100;
|
||||
maxInv[CrossbowAmmo] = 50;
|
||||
maxInv[Crossbow] = 1;
|
||||
maxInv[Rifle] = 1;
|
||||
};
|
||||
|
||||
datablock ItemData(OrcMarker)
|
||||
{
|
||||
//This shape will be listed under the Shapes in the mission editor
|
||||
category = "AIMarker";
|
||||
|
||||
// Basic Item properties
|
||||
//Basic shape file to use as a marker in the editor.
|
||||
shapeFile = "~/data/shapes/markers/octahedron.dts";
|
||||
mass = 1;
|
||||
friction = 1;
|
||||
elasticity = 0.3;
|
||||
|
||||
};
|
||||
|
||||
datablock PlayerData(Orc : OrcBody)
|
||||
{
|
||||
shootingDelay = 100;
|
||||
};
|
||||
|
||||
|
||||
function Orc::onReachDestination(%this,%obj)
|
||||
{
|
||||
// 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 Orc::onEndOfPath(%this,%obj,%path)
|
||||
{
|
||||
%obj.nextTask();
|
||||
}
|
||||
|
||||
function Orc::onEndSequence(%this,%obj,%slot)
|
||||
{
|
||||
echo("Sequence Done!");
|
||||
%obj.stopThread(%slot);
|
||||
%obj.nextTask();
|
||||
}
|
||||
|
||||
|
||||
function Orc::OnDamage(%this, %obj, %delta)
|
||||
{
|
||||
%obj.attentionlevel=1;
|
||||
%obj.enhancefov(%obj);
|
||||
|
||||
if(%obj.getState() $= "Dead" && %obj.respawn == true)
|
||||
{
|
||||
%obj.delaybeforerespawn(%obj.botname, %obj.marker);
|
||||
%this.player=0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//The load entities function is called from game.cs
|
||||
//The call takes the form of
|
||||
// Orc::LoadEntities();
|
||||
//It is placed in the game.cs file right after the part that reads
|
||||
// Start the game timer
|
||||
// if ($Game::Duration)
|
||||
// $Game::Schedule = schedule($Game::Duration * 1000, 0, "onGameDurationEnd" );
|
||||
// $Game::Running = true;
|
||||
//The call uses a simple brute force method of finding all OrcMarkers
|
||||
//within the given radius of the center of the map. It then inserts an AI player at the
|
||||
//position of each marker, and then hides the marker from view.
|
||||
function Orc::LoadEntities()
|
||||
{
|
||||
//checks to see if the entities are to be processed.
|
||||
if ($AI_PLAYER_ENABLED == true)
|
||||
{
|
||||
echo("Loading Orc entities...");
|
||||
%position = "0 0 0";
|
||||
%radius = 100000.0;
|
||||
InitContainerRadiusSearch(%position, %radius, $TypeMasks::ItemObjectType);
|
||||
%i=0;
|
||||
while ((%targetObject = containerSearchNext()) != 0)
|
||||
{
|
||||
if (%targetobject.getDataBlock().getName() $= "OrcMarker")
|
||||
{
|
||||
%i++;
|
||||
%player = Orc::spawnAtMarker("" @ %i, %targetobject);
|
||||
%targetobject.sethidden(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
echo("Patrol entities disabled...");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//OpenFire - This function is called when the Orc has located a target.
|
||||
|
||||
function Orc::openfire(%this, %obj, %tgt)
|
||||
{
|
||||
//If the Orc is dead, or the target is dead, then the Orc
|
||||
//will not shoot, and the Orc's target will be cleared.
|
||||
if (%obj.getState() $= "Dead" || %tgt.player.getstate() $="Dead")
|
||||
{
|
||||
%firing = false;
|
||||
%obj.clearaim();
|
||||
}
|
||||
else
|
||||
{
|
||||
//If the Orc was not firing, it will check the current distance to the target,
|
||||
//if the target is within the Orc's ignore distance it will shoot, otherwise
|
||||
//the Orc will not shoot.
|
||||
if(!%firing)
|
||||
{
|
||||
%rtt=vectorDist(%obj.getposition(), %tgt.player.getposition());
|
||||
|
||||
if(%rtt < $AI_PLAYER_IGNORE_DISTANCE)
|
||||
{
|
||||
%firing = true;
|
||||
//The following lines is added to keep the Orc stocked with ammo all the time.
|
||||
//If you want the Orc to run out of ammunition then remove this line.
|
||||
%obj.incinventory("Crossbowammo",100);
|
||||
|
||||
//This sets the Orcs target to shoot at. It uses a VectorAdd to
|
||||
//help correct for the problem of the Orc shooting at the targets
|
||||
//feet.
|
||||
//I would recommend using a non-ballistic weapon for your Orcs
|
||||
//otherwise you may have to do some additional math to calculate a good
|
||||
//ballistics drop based on the Orcs range to the target.
|
||||
%obj.setAimLocation(VectorAdd(%tgt.player.getPosition(),"0 0 2.0"));
|
||||
//This actually starts the Orc shooting - equivalent to pulling and
|
||||
//holding down the trigger.
|
||||
%obj.setImageTrigger(0,true);
|
||||
}
|
||||
else
|
||||
{
|
||||
%obj.clearaim();
|
||||
}
|
||||
}
|
||||
}
|
||||
//This schedule is set to call the ceasefire method at the end of the desired time
|
||||
//set for the Orc to hold down the trigger
|
||||
%this.trigger = %this.schedule($AI_PLAYER_TRIGGER_DOWN,"ceasefire", %obj);
|
||||
}
|
||||
|
||||
//CeaseFire - this makes the Orc lift off the trigger
|
||||
function Orc::ceasefire(%this, %obj)
|
||||
{
|
||||
//Makes the Orc lift off the trigger
|
||||
%obj.setImageTrigger(0,false);
|
||||
//This schedule is created to implement a delay between the Orc's
|
||||
//shots. This can be used to help set how aggressive the bot is.
|
||||
%this.trigger = %this.schedule($AI_PLAYER_FIREDELAY,"delayfire", %obj);
|
||||
}
|
||||
|
||||
function Orc::delayfire(%this, %obj)
|
||||
{
|
||||
//This clears the Orc's 'firing' flag.
|
||||
//This allows the player to shoot again the next time it
|
||||
//sees and selects a target within range.
|
||||
%firing = false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Orc static functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function Orc::spawn(%name, %obj)
|
||||
{
|
||||
// Create the demo player object
|
||||
%player = new Orc() {
|
||||
dataBlock = Orc;
|
||||
//This value is set to true for Orcs, it is referenced in player.cs
|
||||
//to help handle respawning bots properly.
|
||||
isbot=true;
|
||||
|
||||
//These variables are set for each bot, this is done on a per bot basis
|
||||
//because the fov and attention level for each bot will be adjusted during
|
||||
//the game.
|
||||
//FOV = Bot's field of vision in degrees. (180 deg. means everything in front of the bot)
|
||||
//attentionlevel = The bot's attention level is raised or lowered based on how near targets
|
||||
//are and whether targets are visible or not.
|
||||
fov=$AI_PLAYER_FOV;
|
||||
attentionlevel = $AI_PLAYER_MAX_ATTENTION/2;
|
||||
|
||||
//The following line allows gives access to the markers dynamic variables and it's spawn position.
|
||||
marker = %obj;
|
||||
|
||||
//The pathname variable is a dynamic variable set during map editing.
|
||||
//This allows the designer to attach each bot to a seperate path
|
||||
path = %obj.pathname;
|
||||
botname = %name;
|
||||
|
||||
};
|
||||
MissionCleanup.add(%player);
|
||||
|
||||
//The following set of if-then statements trap to see if the marker has a dynamic variable
|
||||
//called respawn. (Set during map editing.)
|
||||
//If it does then the players respawn flag is set accordingly true or false
|
||||
//as stated by the variable.
|
||||
//If there is no respawn variable set, then the flag is set to the default global value
|
||||
|
||||
if (%obj.respawn $= "" )
|
||||
{
|
||||
%player.respawn=$AI_PLAYER_DEFAULTRESPAWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (%obj.respawn == true)
|
||||
%player.respawn=true;
|
||||
else
|
||||
%player.respawn=false;
|
||||
}
|
||||
|
||||
//Calls equipbot - to set the Orcs initial inventory
|
||||
%player.EquipBot(%player);
|
||||
|
||||
// %player.setShapeName(%name);
|
||||
%player.setTransform(%obj.gettransform());
|
||||
%player.followPath(%obj.pathname,-1);
|
||||
//This schedule is set start the bots thinking cycle.
|
||||
//The creation delay is used so that the Orcs can be set to not start
|
||||
//thinking for a long delay while the rest of the game loads and initializes.
|
||||
%player.schedule($AI_PLAYER_CREATION_DELAY,"doscan", %player);
|
||||
|
||||
return %player;
|
||||
}
|
||||
|
||||
|
||||
//The delay before respawn function is set to wait a specified duration before
|
||||
//respawning an Orc
|
||||
function Orc::DelayBeforeRespawn(%this, %name, %obj)
|
||||
{
|
||||
%this.respawntrigger = %this.schedule($AI_PLAYER_RESPAWN_DELAY,"respawn", %name, %obj);
|
||||
}
|
||||
|
||||
//Equipbot - this function is called by spawn and respawn and is used to set the bot's
|
||||
//initial inventory.
|
||||
function Orc::EquipBot(%this, %obj)
|
||||
{
|
||||
%obj.mountImage(CrossBowImage,0);
|
||||
%obj.setInventory(CrossbowAmmo,1000);
|
||||
}
|
||||
|
||||
// EnhanceFOV- This function sets the FOV for the Orc to 360 degrees
|
||||
//This function is called from player.cs when the Orc takes damage.
|
||||
//This has the same effect as having the Orc scan all around him when damaged.
|
||||
//This reduces the need to perform a lot of extra checks to see which vector the damage has
|
||||
//come from, etc...
|
||||
function Orc::EnhanceFOV(%this, %obj)
|
||||
{
|
||||
if (%obj.fov != 360)
|
||||
{
|
||||
%obj.fov = 360;
|
||||
%this.fovtrigger = %this.schedule($AI_PLAYER_ENHANCED_FOV_TIME,"restorefov", %obj);
|
||||
}
|
||||
}
|
||||
|
||||
//RestoreFOV - this function resets the Orc's FOV back to the default value for the bot
|
||||
function Orc::restoreFOV(%this, %obj)
|
||||
{
|
||||
%obj.fov = $AI_PLAYER_FOV;
|
||||
}
|
||||
|
||||
|
||||
//This function is called when a bot is respawned, it is nearly identical to spawn
|
||||
//With the exception of the parameters passed to it.
|
||||
function Orc::respawn(%this, %name, %obj)
|
||||
{
|
||||
// Create the demo player object
|
||||
|
||||
%player = new Orc() {
|
||||
dataBlock = PatrolPlayer;
|
||||
isbot=true;
|
||||
attentionlevel = $AI_PLAYER_MAX_ATTENTION/2;
|
||||
fov=$AI_PLAYER_FOV;
|
||||
|
||||
marker = %obj;
|
||||
path = %obj.pathname;
|
||||
|
||||
botname = %name;
|
||||
};
|
||||
MissionCleanup.add(%player);
|
||||
%player.setShapeName(%name);
|
||||
%player.EquipBot(%player);
|
||||
%player.setTransform(%obj.gettransform());
|
||||
%player.followPath(%obj.pathname,-1);
|
||||
|
||||
|
||||
if (%obj.respawn $="" )
|
||||
{
|
||||
%player.respawn=$AI_PLAYER_DEFAULTRESPAWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (%obj.respawn == true)
|
||||
%player.respawn=true;
|
||||
else
|
||||
%player.respawn=false;
|
||||
}
|
||||
%player.schedule($AI_PLAYER_CREATION_DELAY,"doscan", %player);
|
||||
return %player;
|
||||
}
|
||||
|
||||
function Orc::spawnAtMarker(%name,%obj)
|
||||
{
|
||||
// Spawn a player and place him on the first node of the path
|
||||
if (!isObject(%obj))
|
||||
return;
|
||||
%player = Orc::spawn(%name, %obj);
|
||||
return %player;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Orc methods
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function Orc::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 Orc::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 Orc::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);
|
||||
}
|
||||
|
||||
//AITargeting
|
||||
|
||||
// Return the angle of a vector in relation to world origin
|
||||
//This function comes from code taken from several resources on garagegames
|
||||
//The only mods to the code I made are in the end of the code to ensure that variable
|
||||
//returns the angle in degrees, and that the angle is within 0-360 degrees.
|
||||
//I've seen sets of this code with the function returng %degangle rather than
|
||||
//%angle - but in this script %angle is needed.
|
||||
function Orc::getAngleofVector(%this, %vec)
|
||||
{
|
||||
%vector = VectorNormalize(%vec);
|
||||
%vecx = getWord(%vector,0);
|
||||
%vecy = getWord(%vector,1);
|
||||
if(%vecx >= 0 && %vecy >= 0)
|
||||
%quad = 1;
|
||||
else
|
||||
if(%vecx >= 0 && %vecy < 0)
|
||||
%quad = 2;
|
||||
else
|
||||
if(%vecx < 0 && %vecy < 0)
|
||||
%quad = 3;
|
||||
else
|
||||
%quad = 4;
|
||||
%angle = mATan(%vecy/%vecx, -1);
|
||||
%degangle = mRadToDeg(%angle);
|
||||
switch(%quad)
|
||||
{
|
||||
case 1:
|
||||
%angle = %degangle-90;
|
||||
case 2:
|
||||
%angle = %degangle+270;
|
||||
case 3:
|
||||
%angle = %degangle+90;
|
||||
case 4:
|
||||
%angle = %degangle+450;
|
||||
}
|
||||
if (%angle < 0) %angle = %angle + 360;
|
||||
return %angle;
|
||||
}
|
||||
|
||||
//This is another function taken from code off of garagegames.
|
||||
//The only mods I made to it was to add the extra check to ensure that the
|
||||
//angle is within the 0-360 range.
|
||||
|
||||
function Orc::check2DAngletoTarget(%this, %obj, %tgt)
|
||||
{
|
||||
%eyeVec = VectorNormalize(%this.getEyeVector());
|
||||
%eyeangle = %this.getAngleofVector(%eyeVec);
|
||||
%posVec = VectorSub(%tgt.player.getPosition(), %obj.getPosition());
|
||||
%posangle = %this.getAngleofVector(%posVec);
|
||||
%angle = %posangle - %eyeAngle;
|
||||
%angle = %angle ? %angle : %angle * -1;
|
||||
if (%angle < 0) %angle = %angle + 360;
|
||||
return %angle;
|
||||
}
|
||||
|
||||
//The DoScan function is the thinking part of the bot.
|
||||
//The following code is commented heavily to help explain the logic behind
|
||||
//the scripting.
|
||||
|
||||
function Orc::DoScan(%this, %obj)
|
||||
{
|
||||
//Cancels the ailoop schedule
|
||||
cancel(%this.ailoop);
|
||||
//if the %obj object is invalid then exit the DoScan Loop.
|
||||
if (!%obj)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//By cancelling the ailoop, then checking to see if the bot is valid,
|
||||
//This should cancel any errant ailoops left hanging by bots killed or
|
||||
//removed from the game.
|
||||
|
||||
|
||||
//The next line calls a function to locate the closest human client that is
|
||||
//both within the bot's range, within it's field of vision, and is not hidden by
|
||||
//objects in the environment.
|
||||
%tgtid = %this.GetClosestHumanInSightandRange(%obj);
|
||||
|
||||
//Is the %tgtid valid target?
|
||||
if(%tgtid >=0)
|
||||
{
|
||||
//If yes, then get the player object of the client
|
||||
%tgt=ClientGroup.getobject(%tgtid);
|
||||
|
||||
if (%obj.getaimobject() != %tgt)
|
||||
{
|
||||
//Open fire on the current target
|
||||
%this.openfire(%obj, %tgt);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Since there is no valid target, then make sure the Orc is
|
||||
//not firing, and clear it's target so it will face in a normal direction,
|
||||
//rather than tracking towards the target
|
||||
%obj.setImageTrigger(0,false);
|
||||
%obj.clearaim();
|
||||
|
||||
//The attention level is a value from 1 to MAX. The higher the number the
|
||||
//less attention the bot is paying. A level of 1 means that the bot scans
|
||||
//at it's fastest level.
|
||||
//The attention level is adjusted in GetClosestHumanInSightandRange
|
||||
|
||||
//The next line ensures that the Orc's attention never goes above the default max
|
||||
if (%this.attentionlevel == $AI_PLAYER_MAX_ATTENTION)
|
||||
%obj.clearaim();
|
||||
}
|
||||
|
||||
//Sets the bot's next "DoScan" call - based on the default scan time adjusted by the
|
||||
//bot's attention level.
|
||||
%this.ailoop=%this.schedule($AI_PLAYER_SCANTIME * %this.attentionlevel,"DoScan" , %obj);
|
||||
}
|
||||
|
||||
//This is another function taken from code found on garagegames.
|
||||
//It checks to see if there are any static objects blocking the view
|
||||
//from the Orc to the target.
|
||||
function Orc::CheckLOS(%this, %obj, %tgt)
|
||||
{
|
||||
%eyeTrans = %obj.getEyeTransform();
|
||||
%eyeEnd = %tgt.player.getEyeTransform();
|
||||
%searchResult = containerRayCast(%eyeTrans, %eyeEnd, $TypeMasks::PlayerObjectType |
|
||||
$TypeMasks::TerrainObjectType | $TypeMasks::InteriorObjectType, %obj);
|
||||
%foundObject = getword(%searchResult,0);
|
||||
|
||||
if(%foundObject.getType() & $TypeMasks::PlayerObjectType)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function Orc::GetClosestHumanInSightandRange(%this, %obj)
|
||||
{
|
||||
|
||||
%index = -1; //sets the initial index value to -1 The index is the id number of the nearest
|
||||
//human target found
|
||||
%botpos = %this.getposition(); //The bots current position
|
||||
%count = ClientGroup.getCount(); //The number of clients to check
|
||||
|
||||
//The for-next loop cycles through all of the valid clients
|
||||
for(%i=0; %i < %count; %i++)
|
||||
{
|
||||
%client = ClientGroup.getobject(%i); //Get the client info for the client at index %i
|
||||
|
||||
//If the client is invalid then the function bails out returning a -1 value, for no
|
||||
//target found.
|
||||
if (%client.player $= "" || %client.player ==0)
|
||||
return -1;
|
||||
|
||||
//The following line just changes the %client to %tgt to make it easier to follow the code below
|
||||
%tgt = %client;
|
||||
|
||||
%playpos = %client.player.getposition(); //Assigns the player position to a variable
|
||||
%tempdist = vectorDist(%playpos, %botpos); //Determine the distance from the bot to the target
|
||||
|
||||
//The first test we perform is to see if the target is within the bots range
|
||||
//Is target in range? If not bail out of checking to see if its in view.
|
||||
if (%tempdist <= $AI_PLAYER_DETECT_DISTANCE)
|
||||
{
|
||||
//Lower attentionlevel to increase response time...
|
||||
%this.attentionlevel--;
|
||||
if(%this.attentionlevel < 1) %this.attentionlevel=1;
|
||||
|
||||
//The second check is to see if the target is within the FOV of the bot.
|
||||
//Is the target within the fov field of vision of the bot?
|
||||
if(%this.Istargetinview(%obj, %tgt, %obj.fov))
|
||||
{
|
||||
//Lower attentionlevel to increase response time...
|
||||
%this.attentionlevel--;
|
||||
if(%this.attentionlevel < 1) %this.attentionlevel=1;
|
||||
|
||||
//The third check we run is to see if there is anything blocking the
|
||||
//target from the bot.
|
||||
if(%this.CheckLOS(%obj, %tgt))
|
||||
{
|
||||
//We lower the bots attention level again, to further increase it's
|
||||
//response time, this effectively means that the bot will respnd faster to
|
||||
//objects that are both in range and in plain sight.
|
||||
%this.attentionlevel--;
|
||||
|
||||
//Prevent the attention level from dropping below 1
|
||||
if(%this.attentionlevel < 1) %this.attentionlevel=1;
|
||||
|
||||
//If there is no current target, then the index to the client/target
|
||||
//and distance to the target are set. The distance is saved temporarily to run
|
||||
//a comparison against the other clients to determine which is closest.
|
||||
if(%i == 0)
|
||||
{
|
||||
%dist = %tempdist;
|
||||
%index = %i;
|
||||
}
|
||||
else
|
||||
{
|
||||
//If there is a current target, then check the distance to the new target as
|
||||
//compared to the current set target. If the new target is closest, then set
|
||||
//the index and tempdistance to the new target.
|
||||
if(%dist > %tempdist)
|
||||
{
|
||||
%dist = %tempdist;
|
||||
%index = %i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//If there are no targets in view, then the bots attention will slowly lapse and increase
|
||||
//This will slow down how fast the bot thinks and how often it checks for threats.
|
||||
%this.attentionlevel = %this.attentionlevel + 0.5;
|
||||
if(%this.attentionlevel > $AI_PLAYER_MAX_ATTENTION) %this.attentionlevel=$AI_PLAYER_MAX_ATTENTION;
|
||||
}
|
||||
}
|
||||
return %index;
|
||||
}
|
||||
|
||||
//This function checks to see if the target supplied is within the bots FOV
|
||||
function Orc::IsTargetInView(%this, %obj, %tgt, %fov)
|
||||
{
|
||||
%ang = %this.check2dangletotarget(%obj, %tgt);
|
||||
|
||||
%visleft = 360 - (%fov/2);
|
||||
%visright = %fov/2;
|
||||
if (%ang > %visleft || %ang < %visright)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function Orc::wait(%this,%time)
|
||||
{
|
||||
%this.schedule(%time * 1000,"nextTask");
|
||||
}
|
||||
|
||||
function Orc::done(%this,%time)
|
||||
{
|
||||
%this.schedule(0,"delete");
|
||||
}
|
||||
|
||||
function Orc::fire(%this,%bool)
|
||||
{
|
||||
if (%bool) {
|
||||
cancel(%this.trigger);
|
||||
%this.singleShot();
|
||||
}
|
||||
else
|
||||
cancel(%this.trigger);
|
||||
%this.nextTask();
|
||||
}
|
||||
|
||||
|
||||
|
||||
function Orc::animate(%this,%seq)
|
||||
{
|
||||
//%this.stopThread(0);
|
||||
//%this.playThread(0,%seq);
|
||||
%this.setActionThread(%seq);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BIN
Torque/SDK/example/starter.fps/server/scripts/Orc.cs.dso
Normal file
BIN
Torque/SDK/example/starter.fps/server/scripts/Orc.cs.dso
Normal file
Binary file not shown.
BIN
Torque/SDK/example/starter.fps/server/scripts/aiPlayer.cs.dso
Normal file
BIN
Torque/SDK/example/starter.fps/server/scripts/aiPlayer.cs.dso
Normal file
Binary file not shown.
113
Torque/SDK/example/starter.fps/server/scripts/audioProfiles.cs
Normal file
113
Torque/SDK/example/starter.fps/server/scripts/audioProfiles.cs
Normal file
@@ -0,0 +1,113 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 3D Sounds
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Single shot sounds
|
||||
|
||||
datablock AudioDescription(AudioDefault3d)
|
||||
{
|
||||
volume = 1.0;
|
||||
isLooping= false;
|
||||
|
||||
is3D = true;
|
||||
ReferenceDistance= 20.0;
|
||||
MaxDistance= 100.0;
|
||||
type = $SimAudioType;
|
||||
};
|
||||
|
||||
datablock AudioDescription(AudioClose3d)
|
||||
{
|
||||
volume = 1.0;
|
||||
isLooping= false;
|
||||
|
||||
is3D = true;
|
||||
ReferenceDistance= 10.0;
|
||||
MaxDistance= 60.0;
|
||||
type = $SimAudioType;
|
||||
};
|
||||
|
||||
datablock AudioDescription(AudioClosest3d)
|
||||
{
|
||||
volume = 1.0;
|
||||
isLooping= false;
|
||||
|
||||
is3D = true;
|
||||
ReferenceDistance= 5.0;
|
||||
MaxDistance= 30.0;
|
||||
type = $SimAudioType;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Looping sounds
|
||||
|
||||
datablock AudioDescription(AudioDefaultLooping3d)
|
||||
{
|
||||
volume = 1.0;
|
||||
isLooping= true;
|
||||
|
||||
is3D = true;
|
||||
ReferenceDistance= 20.0;
|
||||
MaxDistance= 100.0;
|
||||
type = $SimAudioType;
|
||||
};
|
||||
|
||||
datablock AudioDescription(AudioCloseLooping3d)
|
||||
{
|
||||
volume = 1.0;
|
||||
isLooping= true;
|
||||
|
||||
is3D = true;
|
||||
ReferenceDistance= 10.0;
|
||||
MaxDistance= 50.0;
|
||||
type = $SimAudioType;
|
||||
};
|
||||
|
||||
datablock AudioDescription(AudioClosestLooping3d)
|
||||
{
|
||||
volume = 1.0;
|
||||
isLooping= true;
|
||||
|
||||
is3D = true;
|
||||
ReferenceDistance= 5.0;
|
||||
MaxDistance= 30.0;
|
||||
type = $SimAudioType;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 2d sounds
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Used for non-looping environmental sounds (like power on, power off)
|
||||
datablock AudioDescription(Audio2D)
|
||||
{
|
||||
volume = 1.0;
|
||||
isLooping = false;
|
||||
is3D = false;
|
||||
type = $SimAudioType;
|
||||
};
|
||||
|
||||
// Used for Looping Environmental Sounds
|
||||
datablock AudioDescription(AudioLooping2D)
|
||||
{
|
||||
volume = 1.0;
|
||||
isLooping = true;
|
||||
is3D = false;
|
||||
type = $SimAudioType;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
datablock AudioProfile(takeme)
|
||||
{
|
||||
filename = "~/data/sound/takeme.wav";
|
||||
description = "AudioDefaultLooping3d";
|
||||
preload = false;
|
||||
};
|
||||
Binary file not shown.
80
Torque/SDK/example/starter.fps/server/scripts/camera.cs
Normal file
80
Torque/SDK/example/starter.fps/server/scripts/camera.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Global movement speed that affects all cameras. This should be moved
|
||||
// into the camera datablock.
|
||||
$Camera::movementSpeed = 40;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Define a datablock class to use for our observer camera
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
datablock CameraData(Observer)
|
||||
{
|
||||
mode = "Observer";
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
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":
|
||||
// Viewing dead corpse, so we probably want to respawn.
|
||||
%client.spawnPlayer();
|
||||
|
||||
// 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.mode = %mode;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Camera methods
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function Camera::onAdd(%this,%obj)
|
||||
{
|
||||
// Default start mode
|
||||
%this.setMode(%this.mode);
|
||||
}
|
||||
|
||||
function Camera::setMode(%this,%mode,%arg1,%arg2,%arg3)
|
||||
{
|
||||
// Punt this one over to our datablock
|
||||
%this.getDatablock().setMode(%this,%mode,%arg1,%arg2,%arg3);
|
||||
}
|
||||
BIN
Torque/SDK/example/starter.fps/server/scripts/camera.cs.dso
Normal file
BIN
Torque/SDK/example/starter.fps/server/scripts/camera.cs.dso
Normal file
Binary file not shown.
87
Torque/SDK/example/starter.fps/server/scripts/centerPrint.cs
Normal file
87
Torque/SDK/example/starter.fps/server/scripts/centerPrint.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function centerPrintAll( %message, %time, %lines )
|
||||
{
|
||||
if( %lines $= "" || ((%lines > 3) || (%lines < 1)) )
|
||||
%lines = 1;
|
||||
|
||||
%count = ClientGroup.getCount();
|
||||
for (%i = 0; %i < %count; %i++)
|
||||
{
|
||||
%cl = ClientGroup.getObject(%i);
|
||||
if( !%cl.isAIControlled() )
|
||||
commandToClient( %cl, 'centerPrint', %message, %time, %lines );
|
||||
}
|
||||
}
|
||||
|
||||
function bottomPrintAll( %message, %time, %lines )
|
||||
{
|
||||
if( %lines $= "" || ((%lines > 3) || (%lines < 1)) )
|
||||
%lines = 1;
|
||||
|
||||
%count = ClientGroup.getCount();
|
||||
for (%i = 0; %i < %count; %i++)
|
||||
{
|
||||
%cl = ClientGroup.getObject(%i);
|
||||
if( !%cl.isAIControlled() )
|
||||
commandToClient( %cl, 'bottomPrint', %message, %time, %lines );
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------
|
||||
|
||||
function centerPrint( %client, %message, %time, %lines )
|
||||
{
|
||||
if( %lines $= "" || ((%lines > 3) || (%lines < 1)) )
|
||||
%lines = 1;
|
||||
|
||||
|
||||
commandToClient( %client, 'CenterPrint', %message, %time, %lines );
|
||||
}
|
||||
|
||||
function bottomPrint( %client, %message, %time, %lines )
|
||||
{
|
||||
if( %lines $= "" || ((%lines > 3) || (%lines < 1)) )
|
||||
%lines = 1;
|
||||
|
||||
commandToClient( %client, 'BottomPrint', %message, %time, %lines );
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------
|
||||
|
||||
function clearCenterPrint( %client )
|
||||
{
|
||||
commandToClient( %client, 'ClearCenterPrint');
|
||||
}
|
||||
|
||||
function clearBottomPrint( %client )
|
||||
{
|
||||
commandToClient( %client, 'ClearBottomPrint');
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------
|
||||
|
||||
function clearCenterPrintAll()
|
||||
{
|
||||
%count = ClientGroup.getCount();
|
||||
for (%i = 0; %i < %count; %i++)
|
||||
{
|
||||
%cl = ClientGroup.getObject(%i);
|
||||
if( !%cl.isAIControlled() )
|
||||
commandToClient( %cl, 'ClearCenterPrint');
|
||||
}
|
||||
}
|
||||
|
||||
function clearBottomPrintAll()
|
||||
{
|
||||
%count = ClientGroup.getCount();
|
||||
for (%i = 0; %i < %count; %i++)
|
||||
{
|
||||
%cl = ClientGroup.getObject(%i);
|
||||
if( !%cl.isAIControlled() )
|
||||
commandToClient( %cl, 'ClearBottomPrint');
|
||||
}
|
||||
}
|
||||
BIN
Torque/SDK/example/starter.fps/server/scripts/centerPrint.cs.dso
Normal file
BIN
Torque/SDK/example/starter.fps/server/scripts/centerPrint.cs.dso
Normal file
Binary file not shown.
278
Torque/SDK/example/starter.fps/server/scripts/chimneyfire.cs
Normal file
278
Torque/SDK/example/starter.fps/server/scripts/chimneyfire.cs
Normal file
@@ -0,0 +1,278 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
datablock ParticleData(ChimneySmoke)
|
||||
{
|
||||
textureName = "~/data/shapes/particles/smoke";
|
||||
dragCoefficient = 0.0;
|
||||
gravityCoefficient = -0.2; // rises slowly
|
||||
inheritedVelFactor = 0.00;
|
||||
lifetimeMS = 3000;
|
||||
lifetimeVarianceMS = 250;
|
||||
useInvAlpha = false;
|
||||
spinRandomMin = -30.0;
|
||||
spinRandomMax = 30.0;
|
||||
|
||||
colors[0] = "0.6 0.6 0.6 0.1";
|
||||
colors[1] = "0.6 0.6 0.6 0.1";
|
||||
colors[2] = "0.6 0.6 0.6 0.0";
|
||||
|
||||
sizes[0] = 0.5;
|
||||
sizes[1] = 0.75;
|
||||
sizes[2] = 1.5;
|
||||
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.5;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData(ChimneySmokeEmitter)
|
||||
{
|
||||
ejectionPeriodMS = 20;
|
||||
periodVarianceMS = 5;
|
||||
|
||||
ejectionVelocity = 0.25;
|
||||
velocityVariance = 0.10;
|
||||
|
||||
thetaMin = 0.0;
|
||||
thetaMax = 90.0;
|
||||
|
||||
particles = ChimneySmoke;
|
||||
};
|
||||
|
||||
datablock ParticleEmitterNodeData(ChimneySmokeEmitterNode)
|
||||
{
|
||||
timeMultiple = 1;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
datablock ParticleData(ChimneyFire1)
|
||||
{
|
||||
textureName = "~/data/shapes/particles/smoke";
|
||||
dragCoefficient = 0.0;
|
||||
gravityCoefficient = -0.3; // rises slowly
|
||||
inheritedVelFactor = 0.00;
|
||||
lifetimeMS = 500;
|
||||
lifetimeVarianceMS = 250;
|
||||
useInvAlpha = false;
|
||||
spinRandomMin = -30.0;
|
||||
spinRandomMax = 30.0;
|
||||
|
||||
colors[0] = "0.8 0.6 0.0 0.1";
|
||||
colors[1] = "0.8 0.6 0.0 0.1";
|
||||
colors[2] = "0.0 0.0 0.0 0.0";
|
||||
|
||||
sizes[0] = 1.0;
|
||||
sizes[1] = 1.0;
|
||||
sizes[2] = 5.0;
|
||||
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.5;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
|
||||
datablock ParticleData(ChimneyFire2)
|
||||
{
|
||||
textureName = "~/data/shapes/particles/smoke";
|
||||
dragCoefficient = 0.0;
|
||||
gravityCoefficient = -0.5; // rises slowly
|
||||
inheritedVelFactor = 0.00;
|
||||
lifetimeMS = 800;
|
||||
lifetimeVarianceMS = 150;
|
||||
useInvAlpha = false;
|
||||
spinRandomMin = -30.0;
|
||||
spinRandomMax = 30.0;
|
||||
|
||||
colors[0] = "0.6 0.6 0.0 0.1";
|
||||
colors[1] = "0.6 0.6 0.0 0.1";
|
||||
colors[2] = "0.0 0.0 0.0 0.0";
|
||||
|
||||
sizes[0] = 0.5;
|
||||
sizes[1] = 0.5;
|
||||
sizes[2] = 0.5;
|
||||
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.5;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData(ChimneyFireEmitter)
|
||||
{
|
||||
ejectionPeriodMS = 15;
|
||||
periodVarianceMS = 5;
|
||||
|
||||
ejectionVelocity = 0.25;
|
||||
velocityVariance = 0.10;
|
||||
|
||||
thetaMin = 0.0;
|
||||
thetaMax = 90.0;
|
||||
|
||||
particles = "ChimneyFire1" TAB "ChimneyFire2";
|
||||
};
|
||||
|
||||
datablock ParticleEmitterNodeData(ChimneyFireEmitterNode)
|
||||
{
|
||||
timeMultiple = 1;
|
||||
};
|
||||
//Large Fire
|
||||
datablock ParticleData(LargeFire1)
|
||||
{
|
||||
textureName = "~/data/shapes/particles/smoke";
|
||||
dragCoefficient = 0.0;
|
||||
gravityCoefficient = -0.3; // rises slowly
|
||||
inheritedVelFactor = 0.00;
|
||||
lifetimeMS = 500;
|
||||
lifetimeVarianceMS = 250;
|
||||
useInvAlpha = false;
|
||||
spinRandomMin = -30.0;
|
||||
spinRandomMax = 30.0;
|
||||
|
||||
colors[0] = "0.8 0.6 0.0 0.1";
|
||||
colors[1] = "0.8 0.6 0.0 0.1";
|
||||
colors[2] = "0.0 0.0 0.0 0.0";
|
||||
|
||||
sizes[0] = 10.0;
|
||||
sizes[1] = 10.0;
|
||||
sizes[2] = 50.0;
|
||||
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.5;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
|
||||
datablock ParticleData(LargeFire2)
|
||||
{
|
||||
textureName = "~/data/shapes/particles/smoke";
|
||||
dragCoefficient = 0.0;
|
||||
gravityCoefficient = -0.5; // rises slowly
|
||||
inheritedVelFactor = 0.00;
|
||||
lifetimeMS = 800;
|
||||
lifetimeVarianceMS = 150;
|
||||
useInvAlpha = false;
|
||||
spinRandomMin = -30.0;
|
||||
spinRandomMax = 30.0;
|
||||
|
||||
colors[0] = "0.6 0.6 0.0 0.1";
|
||||
colors[1] = "0.6 0.6 0.0 0.1";
|
||||
colors[2] = "0.0 0.0 0.0 0.0";
|
||||
|
||||
sizes[0] = 5;
|
||||
sizes[1] = 5;
|
||||
sizes[2] = 5;
|
||||
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.5;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData(LargeFireEmitter)
|
||||
{
|
||||
ejectionPeriodMS = 15;
|
||||
periodVarianceMS = 5;
|
||||
|
||||
ejectionVelocity = 0.25;
|
||||
velocityVariance = 0.10;
|
||||
|
||||
thetaMin = 0.0;
|
||||
thetaMax = 90.0;
|
||||
|
||||
particles = "LargeFire1" TAB "LargeFire2";
|
||||
};
|
||||
|
||||
datablock ParticleEmitterNodeData(LargeFireEmitterNode)
|
||||
{
|
||||
timeMultiple = 1;
|
||||
};
|
||||
//Black Smoke
|
||||
datablock ParticleData(BlackSmoke)
|
||||
{
|
||||
textureName = "~/data/shapes/particles/smoke";
|
||||
dragCoefficient = 0.0;
|
||||
gravityCoefficient = -0.2; // rises slowly
|
||||
inheritedVelFactor = 0.00;
|
||||
lifetimeMS = 3000;
|
||||
lifetimeVarianceMS = 250;
|
||||
useInvAlpha = false;
|
||||
spinRandomMin = -30.0;
|
||||
spinRandomMax = 30.0;
|
||||
|
||||
colors[0] = "0 0 0 0.1";
|
||||
colors[1] = "0 0 0 0.1";
|
||||
colors[2] = "0 0 0 0.0";
|
||||
|
||||
sizes[0] = 0.5;
|
||||
sizes[1] = 0.75;
|
||||
sizes[2] = 1.5;
|
||||
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.5;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData(BlackSmokeEmitter)
|
||||
{
|
||||
ejectionPeriodMS = 20;
|
||||
periodVarianceMS = 5;
|
||||
|
||||
ejectionVelocity = 0.25;
|
||||
velocityVariance = 0.10;
|
||||
|
||||
thetaMin = 0.0;
|
||||
thetaMax = 90.0;
|
||||
|
||||
particles = BlackSmoke;
|
||||
};
|
||||
|
||||
datablock ParticleEmitterNodeData(BlackSmokeEmitterNode)
|
||||
{
|
||||
timeMultiple = 1;
|
||||
};
|
||||
datablock ParticleData(Snow)
|
||||
{
|
||||
textureName = "~/data/shapes/particles/smoke";
|
||||
dragCoefficient = 0.0;
|
||||
gravityCoefficient = 0.2; // rises slowly
|
||||
inheritedVelFactor = 0.00;
|
||||
lifetimeMS = 30000;
|
||||
lifetimeVarianceMS = 2500;
|
||||
useInvAlpha = false;
|
||||
spinRandomMin = -30.0;
|
||||
spinRandomMax = 30.0;
|
||||
|
||||
colors[0] = "0.6 0.6 0.6 0.1";
|
||||
colors[1] = "0.6 0.6 0.6 0.1";
|
||||
colors[2] = "0.6 0.6 0.6 0.0";
|
||||
|
||||
sizes[0] = 0.5;
|
||||
sizes[1] = 0.75;
|
||||
sizes[2] = 1.5;
|
||||
|
||||
times[0] = 20;
|
||||
times[1] = 20;
|
||||
times[2] = 20;
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData(SnowEmitter)
|
||||
{
|
||||
ejectionPeriodMS = 20;
|
||||
periodVarianceMS = 5;
|
||||
|
||||
ejectionVelocity = 0.25;
|
||||
velocityVariance = 0.10;
|
||||
|
||||
thetaMin = 0.0;
|
||||
thetaMax = 90.0;
|
||||
|
||||
particles = Snow;
|
||||
};
|
||||
|
||||
datablock ParticleEmitterNodeData(SnowEmitterNode)
|
||||
{
|
||||
timeMultiple = 1;
|
||||
};
|
||||
BIN
Torque/SDK/example/starter.fps/server/scripts/chimneyfire.cs.dso
Normal file
BIN
Torque/SDK/example/starter.fps/server/scripts/chimneyfire.cs.dso
Normal file
Binary file not shown.
74
Torque/SDK/example/starter.fps/server/scripts/commands.cs
Normal file
74
Torque/SDK/example/starter.fps/server/scripts/commands.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Misc. server commands avialable to clients
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function serverCmdToggleCamera(%client)
|
||||
{
|
||||
%control = %client.getControlObject();
|
||||
if (%control == %client.player)
|
||||
{
|
||||
%control = %client.camera;
|
||||
%control.mode = toggleCameraFly;
|
||||
}
|
||||
else
|
||||
{
|
||||
%control = %client.player;
|
||||
%control.mode = observerFly;
|
||||
}
|
||||
%client.setControlObject(%control);
|
||||
}
|
||||
|
||||
function serverCmdDropPlayerAtCamera(%client)
|
||||
{
|
||||
if ($Server::TestCheats || isObject(EditorGui))
|
||||
{
|
||||
%client.player.setTransform(%client.camera.getTransform());
|
||||
%client.player.setVelocity("0 0 0");
|
||||
%client.setControlObject(%client.player);
|
||||
}
|
||||
}
|
||||
|
||||
function serverCmdDropCameraAtPlayer(%client)
|
||||
{
|
||||
%client.camera.setTransform(%client.player.getEyeTransform());
|
||||
%client.camera.setVelocity("0 0 0");
|
||||
%client.setControlObject(%client.camera);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function serverCmdSuicide(%client)
|
||||
{
|
||||
if (isObject(%client.player))
|
||||
%client.player.kill("Suicide");
|
||||
}
|
||||
|
||||
function serverCmdPlayCel(%client,%anim)
|
||||
{
|
||||
if (isObject(%client.player))
|
||||
%client.player.playCelAnimation(%anim);
|
||||
}
|
||||
|
||||
function serverCmdPlayDeath(%client)
|
||||
{
|
||||
if (isObject(%client.player))
|
||||
%client.player.playDeathAnimation();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function serverCmdDisplayInventory(%client)
|
||||
{
|
||||
%player = %client.player;
|
||||
//Send the info to the client to display it
|
||||
commandToClient(%client, 'PopInventory',%player);
|
||||
|
||||
}
|
||||
BIN
Torque/SDK/example/starter.fps/server/scripts/commands.cs.dso
Normal file
BIN
Torque/SDK/example/starter.fps/server/scripts/commands.cs.dso
Normal file
Binary file not shown.
941
Torque/SDK/example/starter.fps/server/scripts/crossbow.cs
Normal file
941
Torque/SDK/example/starter.fps/server/scripts/crossbow.cs
Normal file
@@ -0,0 +1,941 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Crossbow weapon. This file contains all the items related to this weapon
|
||||
// including explosions, ammo, the item and the weapon item image.
|
||||
// These objects rely on the item & inventory support system defined
|
||||
// in item.cs and inventory.cs
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sounds profiles
|
||||
|
||||
datablock AudioProfile(CrossbowReloadSound)
|
||||
{
|
||||
filename = "~/data/sound/crossbow_reload.ogg";
|
||||
description = AudioClose3d;
|
||||
preload = true;
|
||||
};
|
||||
|
||||
datablock AudioProfile(CrossbowFireSound)
|
||||
{
|
||||
filename = "~/data/sound/crossbow_firing.ogg";
|
||||
description = AudioClose3d;
|
||||
preload = true;
|
||||
};
|
||||
|
||||
datablock AudioProfile(CrossbowFireEmptySound)
|
||||
{
|
||||
filename = "~/data/sound/crossbow_firing_empty.ogg";
|
||||
description = AudioClose3d;
|
||||
preload = true;
|
||||
};
|
||||
|
||||
datablock AudioProfile(CrossbowExplosionSound)
|
||||
{
|
||||
filename = "~/data/sound/crossbow_explosion.ogg";
|
||||
description = AudioDefault3d;
|
||||
preload = true;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Crossbow bolt projectile splash
|
||||
|
||||
datablock ParticleData(CrossbowSplashMist)
|
||||
{
|
||||
dragCoefficient = 2.0;
|
||||
gravityCoefficient = -0.05;
|
||||
inheritedVelFactor = 0.0;
|
||||
constantAcceleration = 0.0;
|
||||
lifetimeMS = 400;
|
||||
lifetimeVarianceMS = 100;
|
||||
useInvAlpha = false;
|
||||
spinRandomMin = -90.0;
|
||||
spinRandomMax = 500.0;
|
||||
textureName = "~/data/shapes/crossbow/splash";
|
||||
|
||||
colors[0] = "0.7 0.8 1.0 1.0";
|
||||
colors[1] = "0.7 0.8 1.0 0.5";
|
||||
colors[2] = "0.7 0.8 1.0 0.0";
|
||||
|
||||
sizes[0] = 0.5;
|
||||
sizes[1] = 0.5;
|
||||
sizes[2] = 0.8;
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.5;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData(CrossbowSplashMistEmitter)
|
||||
{
|
||||
ejectionPeriodMS = 5;
|
||||
periodVarianceMS = 0;
|
||||
ejectionVelocity = 3.0;
|
||||
velocityVariance = 2.0;
|
||||
ejectionOffset = 0.0;
|
||||
thetaMin = 85;
|
||||
thetaMax = 85;
|
||||
phiReferenceVel = 0;
|
||||
phiVariance = 360;
|
||||
overrideAdvance = false;
|
||||
lifetimeMS = 250;
|
||||
particles = "CrossbowSplashMist";
|
||||
};
|
||||
|
||||
datablock ParticleData( CrossbowSplashParticle )
|
||||
{
|
||||
dragCoefficient = 1;
|
||||
gravityCoefficient = 0.2;
|
||||
inheritedVelFactor = 0.2;
|
||||
constantAcceleration = -0.0;
|
||||
lifetimeMS = 600;
|
||||
lifetimeVarianceMS = 0;
|
||||
colors[0] = "0.7 0.8 1.0 1.0";
|
||||
colors[1] = "0.7 0.8 1.0 0.5";
|
||||
colors[2] = "0.7 0.8 1.0 0.0";
|
||||
sizes[0] = 0.5;
|
||||
sizes[1] = 0.5;
|
||||
sizes[2] = 0.5;
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.5;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData( CrossbowSplashEmitter )
|
||||
{
|
||||
ejectionPeriodMS = 1;
|
||||
periodVarianceMS = 0;
|
||||
ejectionVelocity = 3;
|
||||
velocityVariance = 1.0;
|
||||
ejectionOffset = 0.0;
|
||||
thetaMin = 60;
|
||||
thetaMax = 80;
|
||||
phiReferenceVel = 0;
|
||||
phiVariance = 360;
|
||||
overrideAdvance = false;
|
||||
orientParticles = true;
|
||||
lifetimeMS = 100;
|
||||
particles = "CrossbowSplashParticle";
|
||||
};
|
||||
|
||||
datablock SplashData(CrossbowSplash)
|
||||
{
|
||||
numSegments = 15;
|
||||
ejectionFreq = 15;
|
||||
ejectionAngle = 40;
|
||||
ringLifetime = 0.5;
|
||||
lifetimeMS = 300;
|
||||
velocity = 4.0;
|
||||
startRadius = 0.0;
|
||||
acceleration = -3.0;
|
||||
texWrap = 5.0;
|
||||
|
||||
texture = "~/data/shapes/crossbow/splash";
|
||||
|
||||
emitter[0] = CrossbowSplashEmitter;
|
||||
emitter[1] = CrossbowSplashMistEmitter;
|
||||
|
||||
colors[0] = "0.7 0.8 1.0 0.0";
|
||||
colors[1] = "0.7 0.8 1.0 0.3";
|
||||
colors[2] = "0.7 0.8 1.0 0.7";
|
||||
colors[3] = "0.7 0.8 1.0 0.0";
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.4;
|
||||
times[2] = 0.8;
|
||||
times[3] = 1.0;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Crossbow bolt projectile particles
|
||||
|
||||
datablock ParticleData(CrossbowBoltParticle)
|
||||
{
|
||||
textureName = "~/data/shapes/particles/smoke";
|
||||
dragCoefficient = 0.0;
|
||||
gravityCoefficient = -0.1; // rises slowly
|
||||
inheritedVelFactor = 0.0;
|
||||
lifetimeMS = 150;
|
||||
lifetimeVarianceMS = 10; // ...more or less
|
||||
useInvAlpha = false;
|
||||
spinRandomMin = -30.0;
|
||||
spinRandomMax = 30.0;
|
||||
|
||||
colors[0] = "0.1 0.1 0.1 1.0";
|
||||
colors[1] = "0.1 0.1 0.1 1.0";
|
||||
colors[2] = "0.1 0.1 0.1 0";
|
||||
|
||||
sizes[0] = 0.15;
|
||||
sizes[1] = 0.20;
|
||||
sizes[2] = 0.25;
|
||||
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.3;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
|
||||
datablock ParticleData(CrossbowBubbleParticle)
|
||||
{
|
||||
textureName = "~/data/shapes/particles/bubble";
|
||||
dragCoefficient = 0.0;
|
||||
gravityCoefficient = -0.25; // rises slowly
|
||||
inheritedVelFactor = 0.0;
|
||||
constantAcceleration = 0.0;
|
||||
lifetimeMS = 1500;
|
||||
lifetimeVarianceMS = 600; // ...more or less
|
||||
useInvAlpha = false;
|
||||
spinRandomMin = -100.0;
|
||||
spinRandomMax = 100.0;
|
||||
|
||||
colors[0] = "0.7 0.8 1.0 0.4";
|
||||
colors[1] = "0.7 0.8 1.0 1.0";
|
||||
colors[2] = "0.7 0.8 1.0 0.0";
|
||||
|
||||
sizes[0] = 0.2;
|
||||
sizes[1] = 0.2;
|
||||
sizes[2] = 0.2;
|
||||
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.5;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData(CrossbowBoltEmitter)
|
||||
{
|
||||
ejectionPeriodMS = 2;
|
||||
periodVarianceMS = 0;
|
||||
|
||||
ejectionVelocity = 0.0;
|
||||
velocityVariance = 0.10;
|
||||
|
||||
thetaMin = 0.0;
|
||||
thetaMax = 90.0;
|
||||
|
||||
particles = CrossbowBoltParticle;
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData(CrossbowBoltBubbleEmitter)
|
||||
{
|
||||
ejectionPeriodMS = 9;
|
||||
periodVarianceMS = 0;
|
||||
|
||||
ejectionVelocity = 1.0;
|
||||
ejectionOffset = 0.1;
|
||||
velocityVariance = 0.5;
|
||||
|
||||
thetaMin = 0.0;
|
||||
thetaMax = 80.0;
|
||||
|
||||
phiReferenceVel = 0;
|
||||
phiVariance = 360;
|
||||
overrideAdvances = false;
|
||||
|
||||
particles = CrossbowBubbleParticle;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Explosion Debris
|
||||
|
||||
// Debris "spark" explosion
|
||||
datablock ParticleData(CrossbowDebrisSpark)
|
||||
{
|
||||
textureName = "~/data/shapes/particles/fire";
|
||||
dragCoefficient = 0;
|
||||
gravityCoefficient = 0.0;
|
||||
windCoefficient = 0;
|
||||
inheritedVelFactor = 0.5;
|
||||
constantAcceleration = 0.0;
|
||||
lifetimeMS = 500;
|
||||
lifetimeVarianceMS = 50;
|
||||
spinRandomMin = -90.0;
|
||||
spinRandomMax = 90.0;
|
||||
useInvAlpha = false;
|
||||
|
||||
colors[0] = "0.8 0.2 0 1.0";
|
||||
colors[1] = "0.8 0.2 0 1.0";
|
||||
colors[2] = "0 0 0 0.0";
|
||||
|
||||
sizes[0] = 0.2;
|
||||
sizes[1] = 0.3;
|
||||
sizes[2] = 0.1;
|
||||
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.5;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData(CrossbowDebrisSparkEmitter)
|
||||
{
|
||||
ejectionPeriodMS = 20;
|
||||
periodVarianceMS = 0;
|
||||
ejectionVelocity = 0.5;
|
||||
velocityVariance = 0.25;
|
||||
ejectionOffset = 0.0;
|
||||
thetaMin = 0;
|
||||
thetaMax = 90;
|
||||
phiReferenceVel = 0;
|
||||
phiVariance = 360;
|
||||
overrideAdvances = false;
|
||||
orientParticles = false;
|
||||
lifetimeMS = 300;
|
||||
particles = "CrossbowDebrisSpark";
|
||||
};
|
||||
|
||||
datablock ExplosionData(CrossbowDebrisExplosion)
|
||||
{
|
||||
emitter[0] = CrossbowDebrisSparkEmitter;
|
||||
|
||||
// Turned off..
|
||||
shakeCamera = false;
|
||||
impulseRadius = 0;
|
||||
lightStartRadius = 0;
|
||||
lightEndRadius = 0;
|
||||
};
|
||||
|
||||
// Debris smoke trail
|
||||
datablock ParticleData(CrossbowDebrisTrail)
|
||||
{
|
||||
textureName = "~/data/shapes/particles/fire";
|
||||
dragCoefficient = 1;
|
||||
gravityCoefficient = 0;
|
||||
inheritedVelFactor = 0;
|
||||
windCoefficient = 0;
|
||||
constantAcceleration = 0;
|
||||
lifetimeMS = 800;
|
||||
lifetimeVarianceMS = 100;
|
||||
spinSpeed = 0;
|
||||
spinRandomMin = -90.0;
|
||||
spinRandomMax = 90.0;
|
||||
useInvAlpha = true;
|
||||
|
||||
colors[0] = "0.8 0.3 0.0 1.0";
|
||||
colors[1] = "0.1 0.1 0.1 0.7";
|
||||
colors[2] = "0.1 0.1 0.1 0.0";
|
||||
|
||||
sizes[0] = 0.2;
|
||||
sizes[1] = 0.3;
|
||||
sizes[2] = 0.4;
|
||||
|
||||
times[0] = 0.1;
|
||||
times[1] = 0.2;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData(CrossbowDebrisTrailEmitter)
|
||||
{
|
||||
ejectionPeriodMS = 30;
|
||||
periodVarianceMS = 0;
|
||||
ejectionVelocity = 0.0;
|
||||
velocityVariance = 0.0;
|
||||
ejectionOffset = 0.0;
|
||||
thetaMin = 170;
|
||||
thetaMax = 180;
|
||||
phiReferenceVel = 0;
|
||||
phiVariance = 360;
|
||||
//overrideAdvances = false;
|
||||
//orientParticles = true;
|
||||
lifetimeMS = 5000;
|
||||
particles = "CrossbowDebrisTrail";
|
||||
};
|
||||
|
||||
// Debris object
|
||||
datablock DebrisData(CrossbowExplosionDebris)
|
||||
{
|
||||
shapeFile = "~/data/shapes/crossbow/debris.dts";
|
||||
emitters = "CrossbowDebrisTrailEmitter";
|
||||
explosion = CrossbowDebrisExplosion;
|
||||
|
||||
elasticity = 0.6;
|
||||
friction = 0.5;
|
||||
numBounces = 1;
|
||||
bounceVariance = 1;
|
||||
explodeOnMaxBounce = true;
|
||||
staticOnMaxBounce = false;
|
||||
snapOnMaxBounce = false;
|
||||
minSpinSpeed = 0;
|
||||
maxSpinSpeed = 700;
|
||||
render2D = false;
|
||||
lifetime = 4;
|
||||
lifetimeVariance = 0.4;
|
||||
velocity = 5;
|
||||
velocityVariance = 0.5;
|
||||
fade = false;
|
||||
useRadiusMass = true;
|
||||
baseRadius = 0.3;
|
||||
gravModifier = 0.5;
|
||||
terminalVelocity = 6;
|
||||
ignoreWater = true;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Bolt Explosion
|
||||
|
||||
datablock ParticleData(CrossbowExplosionSmoke)
|
||||
{
|
||||
textureName = "~/data/shapes/particles/smoke";
|
||||
dragCoeffiecient = 100.0;
|
||||
gravityCoefficient = 0;
|
||||
inheritedVelFactor = 0.25;
|
||||
constantAcceleration = -0.30;
|
||||
lifetimeMS = 1200;
|
||||
lifetimeVarianceMS = 300;
|
||||
useInvAlpha = true;
|
||||
spinRandomMin = -80.0;
|
||||
spinRandomMax = 80.0;
|
||||
|
||||
colors[0] = "0.56 0.36 0.26 1.0";
|
||||
colors[1] = "0.2 0.2 0.2 1.0";
|
||||
colors[2] = "0.0 0.0 0.0 0.0";
|
||||
|
||||
sizes[0] = 4.0;
|
||||
sizes[1] = 2.5;
|
||||
sizes[2] = 1.0;
|
||||
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.5;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
|
||||
datablock ParticleData(CrossbowExplosionBubble)
|
||||
{
|
||||
textureName = "~/data/shapes/particles/bubble";
|
||||
dragCoeffiecient = 0.0;
|
||||
gravityCoefficient = -0.25;
|
||||
inheritedVelFactor = 0.0;
|
||||
constantAcceleration = 0.0;
|
||||
lifetimeMS = 1500;
|
||||
lifetimeVarianceMS = 600;
|
||||
useInvAlpha = false;
|
||||
spinRandomMin = -100.0;
|
||||
spinRandomMax = 100.0;
|
||||
|
||||
colors[0] = "0.7 0.8 1.0 0.4";
|
||||
colors[1] = "0.7 0.8 1.0 0.4";
|
||||
colors[2] = "0.7 0.8 1.0 0.0";
|
||||
|
||||
sizes[0] = 0.3;
|
||||
sizes[1] = 0.3;
|
||||
sizes[2] = 0.3;
|
||||
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.5;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData(CrossbowExplosionSmokeEmitter)
|
||||
{
|
||||
ejectionPeriodMS = 10;
|
||||
periodVarianceMS = 0;
|
||||
ejectionVelocity = 4;
|
||||
velocityVariance = 0.5;
|
||||
thetaMin = 0.0;
|
||||
thetaMax = 180.0;
|
||||
lifetimeMS = 250;
|
||||
particles = "CrossbowExplosionSmoke";
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData(CrossbowExplosionBubbleEmitter)
|
||||
{
|
||||
ejectionPeriodMS = 9;
|
||||
periodVarianceMS = 0;
|
||||
ejectionVelocity = 1;
|
||||
ejectionOffset = 0.1;
|
||||
velocityVariance = 0.5;
|
||||
thetaMin = 0.0;
|
||||
thetaMax = 80.0;
|
||||
phiReferenceVel = 0;
|
||||
phiVariance = 360;
|
||||
overrideAdvances = false;
|
||||
particles = "CrossbowExplosionBubble";
|
||||
};
|
||||
|
||||
datablock ParticleData(CrossbowExplosionFire)
|
||||
{
|
||||
textureName = "~/data/shapes/particles/fire";
|
||||
dragCoeffiecient = 100.0;
|
||||
gravityCoefficient = 0;
|
||||
inheritedVelFactor = 0.25;
|
||||
constantAcceleration = 0.1;
|
||||
lifetimeMS = 1200;
|
||||
lifetimeVarianceMS = 300;
|
||||
useInvAlpha = false;
|
||||
spinRandomMin = -80.0;
|
||||
spinRandomMax = 80.0;
|
||||
|
||||
colors[0] = "0.8 0.4 0 0.8";
|
||||
colors[1] = "0.2 0.0 0 0.8";
|
||||
colors[2] = "0.0 0.0 0.0 0.0";
|
||||
|
||||
sizes[0] = 1.5;
|
||||
sizes[1] = 0.9;
|
||||
sizes[2] = 0.5;
|
||||
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.5;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData(CrossbowExplosionFireEmitter)
|
||||
{
|
||||
ejectionPeriodMS = 10;
|
||||
periodVarianceMS = 0;
|
||||
ejectionVelocity = 0.8;
|
||||
velocityVariance = 0.5;
|
||||
thetaMin = 0.0;
|
||||
thetaMax = 180.0;
|
||||
lifetimeMS = 250;
|
||||
particles = "CrossbowExplosionFire";
|
||||
};
|
||||
|
||||
datablock ParticleData(CrossbowExplosionSparks)
|
||||
{
|
||||
textureName = "~/data/shapes/particles/spark";
|
||||
dragCoefficient = 1;
|
||||
gravityCoefficient = 0.0;
|
||||
inheritedVelFactor = 0.2;
|
||||
constantAcceleration = 0.0;
|
||||
lifetimeMS = 500;
|
||||
lifetimeVarianceMS = 350;
|
||||
|
||||
colors[0] = "0.60 0.40 0.30 1.0";
|
||||
colors[1] = "0.60 0.40 0.30 1.0";
|
||||
colors[2] = "1.0 0.40 0.30 0.0";
|
||||
|
||||
sizes[0] = 0.25;
|
||||
sizes[1] = 0.15;
|
||||
sizes[2] = 0.15;
|
||||
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.5;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
|
||||
datablock ParticleData(CrossbowExplosionWaterSparks)
|
||||
{
|
||||
textureName = "~/data/shapes/particles/bubble";
|
||||
dragCoefficient = 0;
|
||||
gravityCoefficient = 0.0;
|
||||
inheritedVelFactor = 0.2;
|
||||
constantAcceleration = 0.0;
|
||||
lifetimeMS = 500;
|
||||
lifetimeVarianceMS = 350;
|
||||
|
||||
colors[0] = "0.4 0.4 1.0 1.0";
|
||||
colors[1] = "0.4 0.4 1.0 1.0";
|
||||
colors[2] = "0.4 0.4 1.0 0.0";
|
||||
|
||||
sizes[0] = 0.5;
|
||||
sizes[1] = 0.5;
|
||||
sizes[2] = 0.5;
|
||||
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.5;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData(CrossbowExplosionSparkEmitter)
|
||||
{
|
||||
ejectionPeriodMS = 3;
|
||||
periodVarianceMS = 0;
|
||||
ejectionVelocity = 5;
|
||||
velocityVariance = 1;
|
||||
ejectionOffset = 0.0;
|
||||
thetaMin = 0;
|
||||
thetaMax = 180;
|
||||
phiReferenceVel = 0;
|
||||
phiVariance = 360;
|
||||
overrideAdvances = false;
|
||||
orientParticles = true;
|
||||
lifetimeMS = 100;
|
||||
particles = "CrossbowExplosionSparks";
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData(CrossbowExplosionWaterSparkEmitter)
|
||||
{
|
||||
ejectionPeriodMS = 3;
|
||||
periodVarianceMS = 0;
|
||||
ejectionVelocity = 4;
|
||||
velocityVariance = 4;
|
||||
ejectionOffset = 0.0;
|
||||
thetaMin = 0;
|
||||
thetaMax = 60;
|
||||
phiReferenceVel = 0;
|
||||
phiVariance = 360;
|
||||
overrideAdvances = false;
|
||||
orientParticles = true;
|
||||
lifetimeMS = 200;
|
||||
particles = "CrossbowExplosionWaterSparks";
|
||||
};
|
||||
|
||||
datablock ExplosionData(CrossbowSubExplosion1)
|
||||
{
|
||||
offset = 0;
|
||||
emitter[0] = CrossbowExplosionSmokeEmitter;
|
||||
emitter[1] = CrossbowExplosionSparkEmitter;
|
||||
};
|
||||
|
||||
datablock ExplosionData(CrossbowSubExplosion2)
|
||||
{
|
||||
offset = 1.0;
|
||||
emitter[0] = CrossbowExplosionSmokeEmitter;
|
||||
emitter[1] = CrossbowExplosionSparkEmitter;
|
||||
};
|
||||
|
||||
datablock ExplosionData(CrossbowSubWaterExplosion1)
|
||||
{
|
||||
delayMS = 100;
|
||||
offset = 1.2;
|
||||
playSpeed = 1.5;
|
||||
|
||||
emitter[0] = CrossbowExplosionBubbleEmitter;
|
||||
emitter[1] = CrossbowExplosionWaterSparkEmitter;
|
||||
|
||||
sizes[0] = "0.75 0.75 0.75";
|
||||
sizes[1] = "1.0 1.0 1.0";
|
||||
sizes[2] = "0.5 0.5 0.5";
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.5;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
|
||||
datablock ExplosionData(CrossbowSubWaterExplosion2)
|
||||
{
|
||||
delayMS = 50;
|
||||
offset = 1.2;
|
||||
playSpeed = 0.75;
|
||||
|
||||
emitter[0] = CrossbowExplosionBubbleEmitter;
|
||||
emitter[1] = CrossbowExplosionWaterSparkEmitter;
|
||||
|
||||
sizes[0] = "1.5 1.5 1.5";
|
||||
sizes[1] = "1.5 1.5 1.5";
|
||||
sizes[2] = "1.0 1.0 1.0";
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.5;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
|
||||
datablock ExplosionData(CrossbowExplosion)
|
||||
{
|
||||
soundProfile = CrossbowExplosionSound;
|
||||
lifeTimeMS = 1200;
|
||||
|
||||
// Volume particles
|
||||
particleEmitter = CrossbowExplosionFireEmitter;
|
||||
particleDensity = 75;
|
||||
particleRadius = 2;
|
||||
|
||||
// Point emission
|
||||
emitter[0] = CrossbowExplosionSmokeEmitter;
|
||||
emitter[1] = CrossbowExplosionSparkEmitter;
|
||||
|
||||
// Sub explosion objects
|
||||
subExplosion[0] = CrossbowSubExplosion1;
|
||||
subExplosion[1] = CrossbowSubExplosion2;
|
||||
|
||||
// Camera Shaking
|
||||
shakeCamera = true;
|
||||
camShakeFreq = "10.0 11.0 10.0";
|
||||
camShakeAmp = "1.0 1.0 1.0";
|
||||
camShakeDuration = 0.5;
|
||||
camShakeRadius = 10.0;
|
||||
|
||||
// Exploding debris
|
||||
debris = CrossbowExplosionDebris;
|
||||
debrisThetaMin = 0;
|
||||
debrisThetaMax = 60;
|
||||
debrisPhiMin = 0;
|
||||
debrisPhiMax = 360;
|
||||
debrisNum = 6;
|
||||
debrisNumVariance = 2;
|
||||
debrisVelocity = 1;
|
||||
debrisVelocityVariance = 0.5;
|
||||
|
||||
// Impulse
|
||||
impulseRadius = 10;
|
||||
impulseForce = 15;
|
||||
|
||||
// Dynamic light
|
||||
lightStartRadius = 6;
|
||||
lightEndRadius = 3;
|
||||
lightStartColor = "0.5 0.5 0";
|
||||
lightEndColor = "0 0 0";
|
||||
};
|
||||
|
||||
datablock ExplosionData(CrossbowWaterExplosion)
|
||||
{
|
||||
soundProfile = CrossbowExplosionSound;
|
||||
|
||||
// Volume particles
|
||||
particleEmitter = CrossbowExplosionBubbleEmitter;
|
||||
particleDensity = 375;
|
||||
particleRadius = 2;
|
||||
|
||||
|
||||
// Point emission
|
||||
emitter[0] = CrossbowExplosionBubbleEmitter;
|
||||
emitter[1] = CrossbowExplosionWaterSparkEmitter;
|
||||
|
||||
// Sub explosion objects
|
||||
subExplosion[0] = CrossbowSubWaterExplosion1;
|
||||
subExplosion[1] = CrossbowSubWaterExplosion2;
|
||||
|
||||
// Camera Shaking
|
||||
shakeCamera = true;
|
||||
camShakeFreq = "8.0 9.0 7.0";
|
||||
camShakeAmp = "3.0 3.0 3.0";
|
||||
camShakeDuration = 1.3;
|
||||
camShakeRadius = 20.0;
|
||||
|
||||
// Exploding debris
|
||||
debris = CrossbowExplosionDebris;
|
||||
debrisThetaMin = 0;
|
||||
debrisThetaMax = 60;
|
||||
debrisPhiMin = 0;
|
||||
debrisPhiMax = 360;
|
||||
debrisNum = 6;
|
||||
debrisNumVariance = 2;
|
||||
debrisVelocity = 0.5;
|
||||
debrisVelocityVariance = 0.2;
|
||||
|
||||
// Impulse
|
||||
impulseRadius = 10;
|
||||
impulseForce = 15;
|
||||
|
||||
// Dynamic light
|
||||
lightStartRadius = 6;
|
||||
lightEndRadius = 3;
|
||||
lightStartColor = "0 0.5 0.5";
|
||||
lightEndColor = "0 0 0";
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Projectile Object
|
||||
|
||||
datablock ProjectileData(CrossbowProjectile)
|
||||
{
|
||||
projectileShapeName = "~/data/shapes/crossbow/projectile.dts";
|
||||
directDamage = 20;
|
||||
radiusDamage = 20;
|
||||
damageRadius = 1.5;
|
||||
areaImpulse = 200;
|
||||
|
||||
explosion = CrossbowExplosion;
|
||||
waterExplosion = CrossbowWaterExplosion;
|
||||
|
||||
particleEmitter = CrossbowBoltEmitter;
|
||||
particleWaterEmitter= CrossbowBoltBubbleEmitter;
|
||||
|
||||
splash = CrossbowSplash;
|
||||
|
||||
muzzleVelocity = 100;
|
||||
velInheritFactor = 0.3;
|
||||
|
||||
armingDelay = 0;
|
||||
lifetime = 5000;
|
||||
fadeDelay = 5000;
|
||||
bounceElasticity = 0;
|
||||
bounceFriction = 0;
|
||||
isBallistic = false;
|
||||
gravityMod = 0.80;
|
||||
|
||||
hasLight = true;
|
||||
lightRadius = 4;
|
||||
lightColor = "0.5 0.5 0.25";
|
||||
|
||||
hasWaterLight = true;
|
||||
waterLightColor = "0 0.5 0.5";
|
||||
};
|
||||
|
||||
function CrossbowProjectile::onCollision(%this,%obj,%col,%fade,%pos,%normal)
|
||||
{
|
||||
// Apply damage to the object all shape base objects
|
||||
if (%col.getType() & $TypeMasks::ShapeBaseObjectType)
|
||||
%col.damage(%obj,%pos,%this.directDamage,"CrossbowBolt");
|
||||
|
||||
// Radius damage is a support scripts defined in radiusDamage.cs
|
||||
// Push the contact point away from the contact surface slightly
|
||||
// along the contact normal to derive the explosion center. -dbs
|
||||
radiusDamage(%obj, %pos, %this.damageRadius, %this.radiusDamage, "Radius", %this.areaImpulse);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Ammo Item
|
||||
|
||||
datablock ItemData(CrossbowAmmo)
|
||||
{
|
||||
// Mission editor category
|
||||
category = "Ammo";
|
||||
|
||||
// Add the Ammo namespace as a parent. The ammo namespace provides
|
||||
// common ammo related functions and hooks into the inventory system.
|
||||
className = "Ammo";
|
||||
|
||||
// Basic Item properties
|
||||
shapeFile = "~/data/shapes/crossbow/ammo.dts";
|
||||
mass = 1;
|
||||
elasticity = 0.2;
|
||||
friction = 0.6;
|
||||
|
||||
// Dynamic properties defined by the scripts
|
||||
pickUpName = "crossbow bolts";
|
||||
maxInventory = 20;
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Weapon Item. This is the item that exists in the world, i.e. when it's
|
||||
// been dropped, thrown or is acting as re-spawnable item. When the weapon
|
||||
// is mounted onto a shape, the CrossbowImage is used.
|
||||
|
||||
datablock ItemData(Crossbow)
|
||||
{
|
||||
// Mission editor category
|
||||
category = "Weapon";
|
||||
|
||||
// Hook into Item Weapon class hierarchy. The weapon namespace
|
||||
// provides common weapon handling functions in addition to hooks
|
||||
// into the inventory system.
|
||||
className = "Weapon";
|
||||
|
||||
// Basic Item properties
|
||||
shapeFile = "~/data/shapes/crossbow/weapon.dts";
|
||||
mass = 1;
|
||||
elasticity = 0.2;
|
||||
friction = 0.6;
|
||||
emap = true;
|
||||
|
||||
// Dynamic properties defined by the scripts
|
||||
pickUpName = "a crossbow";
|
||||
image = CrossbowImage;
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Crossbow image which does all the work. Images do not normally exist in
|
||||
// the world, they can only be mounted on ShapeBase objects.
|
||||
|
||||
datablock ShapeBaseImageData(CrossbowImage)
|
||||
{
|
||||
// Basic Item properties
|
||||
shapeFile = "~/data/shapes/crossbow/weapon.dts";
|
||||
emap = true;
|
||||
|
||||
// Specify mount point & offset for 3rd person, and eye offset
|
||||
// for first person rendering.
|
||||
mountPoint = 0;
|
||||
eyeOffset = "0.1 0.4 -0.6";
|
||||
|
||||
// When firing from a point offset from the eye, muzzle correction
|
||||
// will adjust the muzzle vector to point to the eye LOS point.
|
||||
// Since this weapon doesn't actually fire from the muzzle point,
|
||||
// we need to turn this off.
|
||||
correctMuzzleVector = false;
|
||||
|
||||
// Add the WeaponImage namespace as a parent, WeaponImage namespace
|
||||
// provides some hooks into the inventory system.
|
||||
className = "WeaponImage";
|
||||
|
||||
// Projectile && Ammo.
|
||||
item = Crossbow;
|
||||
ammo = CrossbowAmmo;
|
||||
projectile = CrossbowProjectile;
|
||||
projectileType = Projectile;
|
||||
|
||||
// Images have a state system which controls how the animations
|
||||
// are run, which sounds are played, script callbacks, etc. This
|
||||
// state system is downloaded to the client so that clients can
|
||||
// predict state changes and animate accordingly. The following
|
||||
// system supports basic ready->fire->reload transitions as
|
||||
// well as a no-ammo->dryfire idle state.
|
||||
|
||||
// Initial start up state
|
||||
stateName[0] = "Preactivate";
|
||||
stateTransitionOnLoaded[0] = "Activate";
|
||||
stateTransitionOnNoAmmo[0] = "NoAmmo";
|
||||
|
||||
// Activating the gun. Called when the weapon is first
|
||||
// mounted and there is ammo.
|
||||
stateName[1] = "Activate";
|
||||
stateTransitionOnTimeout[1] = "Ready";
|
||||
stateTimeoutValue[1] = 0.6;
|
||||
stateSequence[1] = "Activate";
|
||||
|
||||
// Ready to fire, just waiting for the trigger
|
||||
stateName[2] = "Ready";
|
||||
stateTransitionOnNoAmmo[2] = "NoAmmo";
|
||||
stateTransitionOnTriggerDown[2] = "Fire";
|
||||
|
||||
// Fire the weapon. Calls the fire script which does
|
||||
// the actual work.
|
||||
stateName[3] = "Fire";
|
||||
stateTransitionOnTimeout[3] = "Reload";
|
||||
stateTimeoutValue[3] = 0.2;
|
||||
stateFire[3] = true;
|
||||
stateRecoil[3] = LightRecoil;
|
||||
stateAllowImageChange[3] = false;
|
||||
stateSequence[3] = "Fire";
|
||||
stateScript[3] = "onFire";
|
||||
stateSound[3] = CrossbowFireSound;
|
||||
|
||||
// Play the relead animation, and transition into
|
||||
stateName[4] = "Reload";
|
||||
stateTransitionOnNoAmmo[4] = "NoAmmo";
|
||||
stateTransitionOnTimeout[4] = "Ready";
|
||||
stateTimeoutValue[4] = 0.8;
|
||||
stateAllowImageChange[4] = false;
|
||||
stateSequence[4] = "Reload";
|
||||
stateEjectShell[4] = true;
|
||||
stateSound[4] = CrossbowReloadSound;
|
||||
|
||||
// No ammo in the weapon, just idle until something
|
||||
// shows up. Play the dry fire sound if the trigger is
|
||||
// pulled.
|
||||
stateName[5] = "NoAmmo";
|
||||
stateTransitionOnAmmo[5] = "Reload";
|
||||
stateSequence[5] = "NoAmmo";
|
||||
stateTransitionOnTriggerDown[5] = "DryFire";
|
||||
|
||||
// No ammo dry fire
|
||||
stateName[6] = "DryFire";
|
||||
stateTimeoutValue[6] = 1.0;
|
||||
stateTransitionOnTimeout[6] = "NoAmmo";
|
||||
stateSound[6] = CrossbowFireEmptySound;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function CrossbowImage::onFire(%this, %obj, %slot)
|
||||
{
|
||||
%projectile = %this.projectile;
|
||||
|
||||
// Decrement inventory ammo. The image's ammo state is update
|
||||
// automatically by the ammo inventory hooks.
|
||||
%obj.decInventory(%this.ammo,1);
|
||||
|
||||
// Determin initial projectile velocity based on the
|
||||
// gun's muzzle point and the object's current velocity
|
||||
%muzzleVector = %obj.getMuzzleVector(%slot);
|
||||
%objectVelocity = %obj.getVelocity();
|
||||
%muzzleVelocity = VectorAdd(
|
||||
VectorScale(%muzzleVector, %projectile.muzzleVelocity),
|
||||
VectorScale(%objectVelocity, %projectile.velInheritFactor));
|
||||
|
||||
// Create the projectile object
|
||||
%p = new (%this.projectileType)() {
|
||||
dataBlock = %projectile;
|
||||
initialVelocity = %muzzleVelocity;
|
||||
initialPosition = %obj.getMuzzlePoint(%slot);
|
||||
sourceObject = %obj;
|
||||
sourceSlot = %slot;
|
||||
client = %obj.client;
|
||||
};
|
||||
MissionCleanup.add(%p);
|
||||
return %p;
|
||||
}
|
||||
BIN
Torque/SDK/example/starter.fps/server/scripts/crossbow.cs.dso
Normal file
BIN
Torque/SDK/example/starter.fps/server/scripts/crossbow.cs.dso
Normal file
Binary file not shown.
133
Torque/SDK/example/starter.fps/server/scripts/doors/door.cs
Normal file
133
Torque/SDK/example/starter.fps/server/scripts/doors/door.cs
Normal file
@@ -0,0 +1,133 @@
|
||||
//Door.cs
|
||||
//writen by Ramen Sama
|
||||
|
||||
|
||||
datablock AudioProfile(doorOpenSound)
|
||||
{
|
||||
filename = "~/data/sound/doorOpen.wav";
|
||||
description = AudioClose3d;
|
||||
preload = false;
|
||||
};
|
||||
|
||||
datablock AudioProfile(doorCloseSound)
|
||||
{
|
||||
filename = "~/data/sound/doorClose.wav";
|
||||
description = AudioClose3d;
|
||||
preload = false;
|
||||
};
|
||||
|
||||
datablock StaticShapeData(door){
|
||||
category = "Doors";
|
||||
//Points to the DTS object change this for your project
|
||||
shapeFile = "~/data/shapes/door/door_redZone.dts";
|
||||
position = "0 0 0";
|
||||
Scale="1 1 1";
|
||||
emap = true;
|
||||
receiveSunLight = "1";
|
||||
};
|
||||
|
||||
//Called when you touch the door
|
||||
function door::onCollision(%this,%door,%col){
|
||||
if (!%door.open){
|
||||
%door.open=true;
|
||||
%door.setthreaddir(0,"true");
|
||||
%door.playthread(0,"open");
|
||||
serverPlay3D(doorOpenSound,%col.getTransform());
|
||||
%this.schedule(2000, close, %door,%col);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function door::close(%this,%door,%col){
|
||||
|
||||
//does a distance check between the door and what hit it last
|
||||
//I have it set for 2... but you can use whatever you like
|
||||
|
||||
%dist=VectorDist(%col.getposition(), %door.getposition());
|
||||
if (%dist > 2){
|
||||
%door.setthreaddir(0,"false");
|
||||
serverPlay3D(doorCloseSound,%col.getTransform());
|
||||
%door.open=false;
|
||||
}
|
||||
else
|
||||
//if the player is too close, just go ahead and start the timer again
|
||||
%this.schedule(2000, close, %door,%col);
|
||||
}
|
||||
|
||||
function door::onSearch(%this,%obj,%source){
|
||||
//Searching will do the same as trying to open it
|
||||
%this.oncollision(%obj,%source);
|
||||
}
|
||||
|
||||
|
||||
function door::make(){
|
||||
|
||||
%pos = $wp.getnodetransform("door");
|
||||
%door = new staticshape(){ dataBlock = door; };
|
||||
%door.settransform(%pos);
|
||||
%door.open=false;
|
||||
%door.searchable=true;
|
||||
|
||||
new Trigger() {
|
||||
position = %pos = $wp.getnodeposition("exit");
|
||||
rotation = "1 0 0 0";
|
||||
scale = "3 1.5 3";
|
||||
dataBlock = "ExitTrigger";
|
||||
polyhedron = "0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 -1.0000000 0.0000000 0.0000000 0.0000000 1.0000000";
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
datablock TriggerData(exitTrigger)
|
||||
{
|
||||
tickPeriodMS = 100;
|
||||
};
|
||||
|
||||
function ExitTrigger::onEnterTrigger(%this,%trigger,%obj)
|
||||
{
|
||||
serverconnection.setblackout(true,500);
|
||||
$canmove=false;
|
||||
%loc = $wp.getnodetransform("start");
|
||||
|
||||
|
||||
//Hack for battle
|
||||
schedule(700,0,teleport,$player,%loc);
|
||||
|
||||
}
|
||||
|
||||
|
||||
function ExitTrigger::oncreate(%this,%trigger,%obj)
|
||||
{
|
||||
error("I've been added to the world");
|
||||
|
||||
}
|
||||
|
||||
|
||||
function teleport(%who, %where){
|
||||
%who.settransform(%where);
|
||||
|
||||
|
||||
//Hack for battle start
|
||||
battleprep();
|
||||
serverconnection.setblackout(false,700);
|
||||
return;
|
||||
|
||||
|
||||
$canmove=true;
|
||||
}
|
||||
|
||||
function ExitTrigger::onLeaveTrigger(%this,%trigger,%obj)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
function ExitTrigger::onTickTrigger(%this,%trigger)
|
||||
{
|
||||
}
|
||||
|
||||
BIN
Torque/SDK/example/starter.fps/server/scripts/doors/door.cs.dso
Normal file
BIN
Torque/SDK/example/starter.fps/server/scripts/doors/door.cs.dso
Normal file
Binary file not shown.
118
Torque/SDK/example/starter.fps/server/scripts/doors/doorGrey1.cs
Normal file
118
Torque/SDK/example/starter.fps/server/scripts/doors/doorGrey1.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
//Door.cs
|
||||
//writen by Ramen Sama
|
||||
|
||||
datablock StaticShapeData(doorgrey1){
|
||||
category = "Doors";
|
||||
//Points to the DTS object change this for your project
|
||||
shapeFile = "~/data/shapes/door/metaldoorSec1.dts";
|
||||
position = "0 0 0";
|
||||
Scale="1 1 1";
|
||||
emap = true;
|
||||
receiveSunLight = "1";
|
||||
};
|
||||
|
||||
//Called when you touch the door
|
||||
function doorgrey1::onCollision(%this,%door,%col){
|
||||
if (!%door.open){
|
||||
%door.open=true;
|
||||
%door.setthreaddir(0,"true");
|
||||
%door.playthread(0,"open");
|
||||
serverPlay3D(doorMetalOpenSound,%col.getTransform());
|
||||
%this.schedule(2000, close, %door,%col);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function doorgrey1::close(%this,%door,%col){
|
||||
|
||||
//does a distance check between the door and what hit it last
|
||||
//I have it set for 2... but you can use whatever you like
|
||||
|
||||
%dist=VectorDist(%col.getposition(), %door.getposition());
|
||||
if (%dist > 2){
|
||||
%door.setthreaddir(0,"false");
|
||||
serverPlay3D(doorMetalCloseSound,%col.getTransform());
|
||||
%door.open=false;
|
||||
}
|
||||
else
|
||||
//if the player is too close, just go ahead and start the timer again
|
||||
%this.schedule(2000, close, %door,%col);
|
||||
}
|
||||
|
||||
function doorgrey1::onSearch(%this,%obj,%source){
|
||||
//Searching will do the same as trying to open it
|
||||
%this.oncollision(%obj,%source);
|
||||
}
|
||||
|
||||
|
||||
function doorgrey1::make(){
|
||||
|
||||
%pos = $wp.getnodetransform("doorgrey1");
|
||||
%door = new staticshape(){ dataBlock = doorgrey1; };
|
||||
%door.settransform(%pos);
|
||||
%door.open=false;
|
||||
%door.searchable=true;
|
||||
|
||||
new Trigger() {
|
||||
position = %pos = $wp.getnodeposition("exit");
|
||||
rotation = "1 0 0 0";
|
||||
scale = "3 1.5 3";
|
||||
dataBlock = "ExitTrigger";
|
||||
polyhedron = "0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 -1.0000000 0.0000000 0.0000000 0.0000000 1.0000000";
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
datablock TriggerData(exitTrigger)
|
||||
{
|
||||
tickPeriodMS = 100;
|
||||
};
|
||||
|
||||
function ExitTrigger::onEnterTrigger(%this,%trigger,%obj)
|
||||
{
|
||||
serverconnection.setblackout(true,500);
|
||||
$canmove=false;
|
||||
%loc = $wp.getnodetransform("start");
|
||||
|
||||
|
||||
//Hack for battle
|
||||
schedule(700,0,teleport,$player,%loc);
|
||||
|
||||
}
|
||||
|
||||
|
||||
function ExitTrigger::oncreate(%this,%trigger,%obj)
|
||||
{
|
||||
error("I've been added to the world");
|
||||
|
||||
}
|
||||
|
||||
|
||||
function teleport(%who, %where){
|
||||
%who.settransform(%where);
|
||||
|
||||
|
||||
//Hack for battle start
|
||||
battleprep();
|
||||
serverconnection.setblackout(false,700);
|
||||
return;
|
||||
|
||||
|
||||
$canmove=true;
|
||||
}
|
||||
|
||||
function ExitTrigger::onLeaveTrigger(%this,%trigger,%obj)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
function ExitTrigger::onTickTrigger(%this,%trigger)
|
||||
{
|
||||
}
|
||||
|
||||
132
Torque/SDK/example/starter.fps/server/scripts/doors/doorMetal.cs
Normal file
132
Torque/SDK/example/starter.fps/server/scripts/doors/doorMetal.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
//Door.cs
|
||||
//writen by Ramen Sama
|
||||
|
||||
datablock AudioProfile(doorMetalOpenSound)
|
||||
{
|
||||
filename = "~/data/sound/doorGrate.wav";
|
||||
description = AudioClose3d;
|
||||
preload = false;
|
||||
};
|
||||
|
||||
datablock AudioProfile(doorMetalCloseSound)
|
||||
{
|
||||
filename = "~/data/sound/doorGrate.wav";
|
||||
description = AudioClose3d;
|
||||
preload = false;
|
||||
};
|
||||
|
||||
datablock StaticShapeData(doorMetal){
|
||||
category = "Doors";
|
||||
//Points to the DTS object change this for your project
|
||||
shapeFile = "~/data/shapes/door/metalGrill.dts";
|
||||
position = "0 0 0";
|
||||
Scale="1 1 1";
|
||||
emap = true;
|
||||
receiveSunLight = "1";
|
||||
};
|
||||
|
||||
//Called when you touch the door
|
||||
function doorMetal::onCollision(%this,%door,%col){
|
||||
if (!%door.open){
|
||||
%door.open=true;
|
||||
%door.setthreaddir(0,"true");
|
||||
%door.playthread(0,"open");
|
||||
serverPlay3D(doorMetalOpenSound,%col.getTransform());
|
||||
%this.schedule(2000, close, %door,%col);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function doorMetal::close(%this,%door,%col){
|
||||
|
||||
//does a distance check between the door and what hit it last
|
||||
//I have it set for 2... but you can use whatever you like
|
||||
|
||||
%dist=VectorDist(%col.getposition(), %door.getposition());
|
||||
if (%dist > 2){
|
||||
%door.setthreaddir(0,"false");
|
||||
serverPlay3D(doorMetalCloseSound,%col.getTransform());
|
||||
%door.open=false;
|
||||
}
|
||||
else
|
||||
//if the player is too close, just go ahead and start the timer again
|
||||
%this.schedule(2000, close, %door,%col);
|
||||
}
|
||||
|
||||
function doorMetal::onSearch(%this,%obj,%source){
|
||||
//Searching will do the same as trying to open it
|
||||
%this.oncollision(%obj,%source);
|
||||
}
|
||||
|
||||
|
||||
function doorMetal::make(){
|
||||
|
||||
%pos = $wp.getnodetransform("doorMetal");
|
||||
%door = new staticshape(){ dataBlock = doorMetal; };
|
||||
%door.settransform(%pos);
|
||||
%door.open=false;
|
||||
%door.searchable=true;
|
||||
|
||||
new Trigger() {
|
||||
position = %pos = $wp.getnodeposition("exit");
|
||||
rotation = "1 0 0 0";
|
||||
scale = "3 1.5 3";
|
||||
dataBlock = "ExitTrigger";
|
||||
polyhedron = "0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 -1.0000000 0.0000000 0.0000000 0.0000000 1.0000000";
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
datablock TriggerData(exitTrigger)
|
||||
{
|
||||
tickPeriodMS = 100;
|
||||
};
|
||||
|
||||
function ExitTrigger::onEnterTrigger(%this,%trigger,%obj)
|
||||
{
|
||||
serverconnection.setblackout(true,500);
|
||||
$canmove=false;
|
||||
%loc = $wp.getnodetransform("start");
|
||||
|
||||
|
||||
//Hack for battle
|
||||
schedule(700,0,teleport,$player,%loc);
|
||||
|
||||
}
|
||||
|
||||
|
||||
function ExitTrigger::oncreate(%this,%trigger,%obj)
|
||||
{
|
||||
error("I've been added to the world");
|
||||
|
||||
}
|
||||
|
||||
|
||||
function teleport(%who, %where){
|
||||
%who.settransform(%where);
|
||||
|
||||
|
||||
//Hack for battle start
|
||||
battleprep();
|
||||
serverconnection.setblackout(false,700);
|
||||
return;
|
||||
|
||||
|
||||
$canmove=true;
|
||||
}
|
||||
|
||||
function ExitTrigger::onLeaveTrigger(%this,%trigger,%obj)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
function ExitTrigger::onTickTrigger(%this,%trigger)
|
||||
{
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,132 @@
|
||||
//Door.cs
|
||||
//writen by Ramen Sama
|
||||
|
||||
datablock AudioProfile(doorMetalOpenSound)
|
||||
{
|
||||
filename = "~/data/sound/doorGrate.wav";
|
||||
description = AudioClose3d;
|
||||
preload = false;
|
||||
};
|
||||
|
||||
datablock AudioProfile(doorMetalCloseSound)
|
||||
{
|
||||
filename = "~/data/sound/doorGrate.wav";
|
||||
description = AudioClose3d;
|
||||
preload = false;
|
||||
};
|
||||
|
||||
datablock StaticShapeData(doorMetalMove){
|
||||
category = "Doors";
|
||||
//Points to the DTS object change this for your project
|
||||
shapeFile = "~/data/shapes/door/metalGrillTrans.dts";
|
||||
position = "0 0 0";
|
||||
Scale="1 1 1";
|
||||
emap = true;
|
||||
receiveSunLight = "1";
|
||||
};
|
||||
|
||||
//Called when you touch the door
|
||||
function doorMetalMove::onCollision(%this,%door,%col){
|
||||
if (!%door.open){
|
||||
%door.open=true;
|
||||
%door.setthreaddir(0,"true");
|
||||
%door.playthread(0,"open");
|
||||
serverPlay3D(doorMetalOpenSound,%col.getTransform());
|
||||
%this.schedule(2000, close, %door,%col);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function doorMetalMove::close(%this,%door,%col){
|
||||
|
||||
//does a distance check between the door and what hit it last
|
||||
//I have it set for 2... but you can use whatever you like
|
||||
|
||||
%dist=VectorDist(%col.getposition(), %door.getposition());
|
||||
if (%dist > 2){
|
||||
%door.setthreaddir(0,"false");
|
||||
serverPlay3D(doorMetalCloseSound,%col.getTransform());
|
||||
%door.open=false;
|
||||
}
|
||||
else
|
||||
//if the player is too close, just go ahead and start the timer again
|
||||
%this.schedule(2000, close, %door,%col);
|
||||
}
|
||||
|
||||
function doorMetalMove::onSearch(%this,%obj,%source){
|
||||
//Searching will do the same as trying to open it
|
||||
%this.oncollision(%obj,%source);
|
||||
}
|
||||
|
||||
|
||||
function doorMetalMove::make(){
|
||||
|
||||
%pos = $wp.getnodetransform("doorMetalMove");
|
||||
%door = new staticshape(){ dataBlock = doorMetalMove; };
|
||||
%door.settransform(%pos);
|
||||
%door.open=false;
|
||||
%door.searchable=true;
|
||||
|
||||
new Trigger() {
|
||||
position = %pos = $wp.getnodeposition("exit");
|
||||
rotation = "1 0 0 0";
|
||||
scale = "3 1.5 3";
|
||||
dataBlock = "ExitTrigger";
|
||||
polyhedron = "0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 -1.0000000 0.0000000 0.0000000 0.0000000 1.0000000";
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
datablock TriggerData(exitTrigger)
|
||||
{
|
||||
tickPeriodMS = 100;
|
||||
};
|
||||
|
||||
function ExitTrigger::onEnterTrigger(%this,%trigger,%obj)
|
||||
{
|
||||
serverconnection.setblackout(true,500);
|
||||
$canmove=false;
|
||||
%loc = $wp.getnodetransform("start");
|
||||
|
||||
|
||||
//Hack for battle
|
||||
schedule(700,0,teleport,$player,%loc);
|
||||
|
||||
}
|
||||
|
||||
|
||||
function ExitTrigger::oncreate(%this,%trigger,%obj)
|
||||
{
|
||||
error("I've been added to the world");
|
||||
|
||||
}
|
||||
|
||||
|
||||
function teleport(%who, %where){
|
||||
%who.settransform(%where);
|
||||
|
||||
|
||||
//Hack for battle start
|
||||
battleprep();
|
||||
serverconnection.setblackout(false,700);
|
||||
return;
|
||||
|
||||
|
||||
$canmove=true;
|
||||
}
|
||||
|
||||
function ExitTrigger::onLeaveTrigger(%this,%trigger,%obj)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
function ExitTrigger::onTickTrigger(%this,%trigger)
|
||||
{
|
||||
}
|
||||
|
||||
Binary file not shown.
132
Torque/SDK/example/starter.fps/server/scripts/doors/doorWood.cs
Normal file
132
Torque/SDK/example/starter.fps/server/scripts/doors/doorWood.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
//DoorWood.cs
|
||||
//writen by Ramen Sama
|
||||
|
||||
datablock AudioProfile(doorWoodOpenSound)
|
||||
{
|
||||
filename = "~/data/sound/doorcreak.wav";
|
||||
description = AudioClose3d;
|
||||
preload = false;
|
||||
};
|
||||
|
||||
datablock AudioProfile(doorWoodCloseSound)
|
||||
{
|
||||
filename = "~/data/sound/doorClose.wav";
|
||||
description = AudioClose3d;
|
||||
preload = false;
|
||||
};
|
||||
|
||||
datablock StaticShapeData(doorWood){
|
||||
category = "Doors";
|
||||
//Points to the DTS object change this for your project
|
||||
shapeFile = "~/data/shapes/door/woodDoor01.dts";
|
||||
position = "0 0 0";
|
||||
Scale="1 1 1";
|
||||
emap = true;
|
||||
receiveSunLight = "1";
|
||||
};
|
||||
|
||||
//Called when you touch the door
|
||||
function doorWood::onCollision(%this,%door,%col){
|
||||
if (!%door.open){
|
||||
%door.open=true;
|
||||
%door.setthreaddir(0,"true");
|
||||
%door.playthread(0,"open");
|
||||
// serverPlay3D(doorWoodOpenSound,%col.getTransform());
|
||||
%this.schedule(2000, close, %door,%col);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function doorWood::close(%this,%door,%col){
|
||||
|
||||
//does a distance check between the door and what hit it last
|
||||
//I have it set for 2... but you can use whatever you like
|
||||
|
||||
%dist=VectorDist(%col.getposition(), %door.getposition());
|
||||
if (%dist > 2){
|
||||
%door.setthreaddir(0,"false");
|
||||
// serverPlay3D(doorWoodCloseSound,%door.getTransform());
|
||||
%door.open=false;
|
||||
}
|
||||
else
|
||||
//if the player is too close, just go ahead and start the timer again
|
||||
%this.schedule(2000, close, %door,%col);
|
||||
}
|
||||
|
||||
function doorWood::onSearch(%this,%obj,%source){
|
||||
//Searching will do the same as trying to open it
|
||||
%this.oncollision(%obj,%source);
|
||||
}
|
||||
|
||||
|
||||
function doorWood::make(){
|
||||
|
||||
%pos = $wp.getnodetransform("doorWood");
|
||||
%door = new staticshape(){ dataBlock = doorWood; };
|
||||
%door.settransform(%pos);
|
||||
%door.open=false;
|
||||
%door.searchable=true;
|
||||
|
||||
new Trigger() {
|
||||
position = %pos = $wp.getnodeposition("exit");
|
||||
rotation = "1 0 0 0";
|
||||
scale = "3 1.5 3";
|
||||
dataBlock = "ExitTrigger";
|
||||
polyhedron = "0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 -1.0000000 0.0000000 0.0000000 0.0000000 1.0000000";
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
datablock TriggerData(exitTrigger)
|
||||
{
|
||||
tickPeriodMS = 100;
|
||||
};
|
||||
|
||||
function ExitTrigger::onEnterTrigger(%this,%trigger,%obj)
|
||||
{
|
||||
serverconnection.setblackout(true,500);
|
||||
$canmove=false;
|
||||
%loc = $wp.getnodetransform("start");
|
||||
|
||||
|
||||
//Hack for battle
|
||||
schedule(700,0,teleport,$player,%loc);
|
||||
|
||||
}
|
||||
|
||||
|
||||
function ExitTrigger::oncreate(%this,%trigger,%obj)
|
||||
{
|
||||
error("I've been added to the world");
|
||||
|
||||
}
|
||||
|
||||
|
||||
function teleport(%who, %where){
|
||||
%who.settransform(%where);
|
||||
|
||||
|
||||
//Hack for battle start
|
||||
battleprep();
|
||||
serverconnection.setblackout(false,700);
|
||||
return;
|
||||
|
||||
|
||||
$canmove=true;
|
||||
}
|
||||
|
||||
function ExitTrigger::onLeaveTrigger(%this,%trigger,%obj)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
function ExitTrigger::onTickTrigger(%this,%trigger)
|
||||
{
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
82
Torque/SDK/example/starter.fps/server/scripts/environment.cs
Normal file
82
Torque/SDK/example/starter.fps/server/scripts/environment.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
datablock AudioProfile(HeavyRainSound)
|
||||
{
|
||||
filename = "~/data/sound/environment/ambient/rain.ogg";
|
||||
description = AudioLooping2d;
|
||||
};
|
||||
|
||||
datablock PrecipitationData(HeavyRain)
|
||||
{
|
||||
soundProfile = "HeavyRainSound";
|
||||
|
||||
dropTexture = "~/data/environment/rain";
|
||||
splashTexture = "~/data/environment/water_splash";
|
||||
dropSize = 0.75;
|
||||
splashSize = 0.2;
|
||||
useTrueBillboards = false;
|
||||
splashMS = 250;
|
||||
};
|
||||
|
||||
datablock PrecipitationData(HeavyRain2)
|
||||
{
|
||||
dropTexture = "~/data/environment/mist";
|
||||
splashTexture = "~/data/environment/mist2";
|
||||
dropSize = 10;
|
||||
splashSize = 0.1;
|
||||
useTrueBillboards = false;
|
||||
splashMS = 250;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
datablock AudioProfile(ThunderCrash1Sound)
|
||||
{
|
||||
filename = "~/data/sound/environment/ambient/thunder1.ogg";
|
||||
description = AudioLightning3d;
|
||||
};
|
||||
|
||||
datablock AudioProfile(ThunderCrash2Sound)
|
||||
{
|
||||
filename = "~/data/sound/environment/ambient/thunder2.ogg";
|
||||
description = AudioLightning3d;
|
||||
};
|
||||
|
||||
datablock AudioProfile(ThunderCrash3Sound)
|
||||
{
|
||||
filename = "~/data/sound/environment/ambient/thunder3.ogg";
|
||||
description = AudioLightning3d;
|
||||
};
|
||||
|
||||
datablock AudioProfile(ThunderCrash4Sound)
|
||||
{
|
||||
filename = "~/data/sound/environment/ambient/thunder4.ogg";
|
||||
description = AudioLightning3d;
|
||||
};
|
||||
|
||||
datablock AudioProfile(LightningHitSound)
|
||||
{
|
||||
filename = "~/data/sound/crossbow_explosion.ogg";
|
||||
description = AudioLightning3d;
|
||||
};
|
||||
|
||||
datablock LightningData(LightningStorm)
|
||||
{
|
||||
strikeTextures[0] = "demo/data/environment/lightning1frame1";
|
||||
strikeTextures[1] = "demo/data/environment/lightning1frame2";
|
||||
strikeTextures[2] = "demo/data/environment/lightning1frame3";
|
||||
|
||||
strikeSound = LightningHitSound;
|
||||
thunderSounds[0] = ThunderCrash1Sound;
|
||||
thunderSounds[1] = ThunderCrash2Sound;
|
||||
thunderSounds[2] = ThunderCrash3Sound;
|
||||
thunderSounds[3] = ThunderCrash4Sound;
|
||||
};
|
||||
|
||||
BIN
Torque/SDK/example/starter.fps/server/scripts/environment.cs.dso
Normal file
BIN
Torque/SDK/example/starter.fps/server/scripts/environment.cs.dso
Normal file
Binary file not shown.
99
Torque/SDK/example/starter.fps/server/scripts/fire.cs
Normal file
99
Torque/SDK/example/starter.fps/server/scripts/fire.cs
Normal file
@@ -0,0 +1,99 @@
|
||||
//-----------------------------------------------------------
|
||||
//particle control data
|
||||
|
||||
datablock ParticleData(Bigfire0Particle)
|
||||
{
|
||||
//----------Image variables---------------
|
||||
textureName = "~/data/shapes/particles/smoke"; //extension not needed
|
||||
|
||||
useInvAlpha = 0; //default = "false"
|
||||
|
||||
inheritedVelFactor = 0.0; //default = 0.0
|
||||
constantAcceleration = 0.0; //default = 0.0
|
||||
|
||||
dragCoefficient = 0.9; //default = 0.0 (must be >= 0.0)
|
||||
windCoefficient = 0.1; //default = 1.0
|
||||
gravityCoefficient = -0.2; //default = 0.0 (negative rises)
|
||||
|
||||
lifetimeMS = 2000.0; //default = 1000 (minimum 100)
|
||||
lifetimeVarianceMS = 50.0; //default = 0.0 (must be < lifetimeMS)
|
||||
|
||||
spinSpeed = 0.0; //default = 0.0 (range -10000 to 10000 ; deg per second)
|
||||
spinRandomMax = 0.0; //default = 0.0 (range -10000 to 10000)
|
||||
spinRandomMin = 0.0; //default = 0.0 (range -10000 to 10000; < spinrandommax)
|
||||
|
||||
//---------Interpolation variables--------
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.33;
|
||||
times[2] = 0.66;
|
||||
times[3] = 1.0;
|
||||
colors[0] = "0.7 0.7 0.0 0.7"; //Red,Green,Blue,Intensity
|
||||
colors[1] = "0.9 0.8 0.0 0.3";
|
||||
colors[2] = "0.8 0.8 0.0 0.2";
|
||||
sizes[0] = 4.0;
|
||||
sizes[1] = 0.5;
|
||||
sizes[2] = 0.2;
|
||||
};
|
||||
datablock ParticleData(Bigfire1Particle)
|
||||
{
|
||||
//----------Image variables---------------
|
||||
textureName = "~/data/shapes/particles/smoke"; //extension not needed
|
||||
|
||||
useInvAlpha = 0; //default = "false"
|
||||
|
||||
inheritedVelFactor = 0.0; //default = 0.0
|
||||
constantAcceleration = 0.0; //default = 0.0
|
||||
|
||||
dragCoefficient = 0.9; //default = 0.0 (must be >= 0.0)
|
||||
windCoefficient = 0.1; //default = 1.0
|
||||
gravityCoefficient = -0.2; //default = 0.0 (negative rises)
|
||||
|
||||
lifetimeMS = 2000.0; //default = 1000 (minimum 100)
|
||||
lifetimeVarianceMS = 50.0; //default = 0.0 (must be < lifetimeMS)
|
||||
|
||||
spinSpeed = 0.0; //default = 0.0 (range -10000 to 10000 ; deg per second)
|
||||
spinRandomMax = 0.0; //default = 0.0 (range -10000 to 10000)
|
||||
spinRandomMin = 0.0; //default = 0.0 (range -10000 to 10000; < spinrandommax)
|
||||
|
||||
//---------Interpolation variables--------
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.33;
|
||||
times[2] = 0.66;
|
||||
times[3] = 1.0;
|
||||
colors[0] = "0.9 0.7 0.0 0.7"; //Red,Green,Blue,Intensity
|
||||
colors[1] = "1 0.8 0.0 0.3";
|
||||
colors[2] = "1 0.8 0.0 0.2";
|
||||
sizes[0] = 5.0;
|
||||
sizes[1] = 0.8;
|
||||
sizes[2] = 1;
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData(BigfireEmitter)
|
||||
{
|
||||
ejectionPeriodMS = 10000; //1000 = 1 particle per second (1ms minimum)
|
||||
periodVarianceMS = 500; //variance has to be less than ejectionPeriodMS
|
||||
|
||||
ejectionVelocity = 0.5; // >= 0.0, from 1.0 to 3.0 meters per second
|
||||
velocityVariance = 0.0; //has to be less than ejectionVelocity
|
||||
ejectionOffset = 0.0; //ejection start distance from the emitter point >=0
|
||||
|
||||
//theta,phi rotation matrix axis angles (degrees) [eg. phi * (PI / 180)]
|
||||
thetaMax = 10.0; //0-180 degrees
|
||||
thetaMin = 0.0; //0-180 0 = All heights (min has to be less than max)
|
||||
phiReferenceVel = 180.0; //0-360, 360=all directions
|
||||
phiVariance = 0.0; //0-360
|
||||
|
||||
overrideAdvances = 0; //0 or 1 function ???
|
||||
|
||||
//orients the particles out from the emitter source (1) or as billboard (0)
|
||||
orientParticles= 1; //0 or 1 "true" or "false"
|
||||
orientOnVelocity = 0; //0 or 1 billboard if no velocity in mission file
|
||||
|
||||
//when tied to an ParticleEmitter object, then these work;
|
||||
//if ParticleEmitterNode then don't need
|
||||
//useEmitterSizes = 0;
|
||||
//useEmitterColors = 0; //default = 0, has to be 0 for ParticleEmitterNode
|
||||
|
||||
particles = "Bigfire0Particle"; //call particle data
|
||||
particles = "Bigfire1Particle";
|
||||
};
|
||||
BIN
Torque/SDK/example/starter.fps/server/scripts/fire.cs.dso
Normal file
BIN
Torque/SDK/example/starter.fps/server/scripts/fire.cs.dso
Normal file
Binary file not shown.
347
Torque/SDK/example/starter.fps/server/scripts/game.cs
Normal file
347
Torque/SDK/example/starter.fps/server/scripts/game.cs
Normal file
@@ -0,0 +1,347 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// 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;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Functions that implement game-play
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function onServerCreated()
|
||||
{
|
||||
// Server::GameType is sent to the master server.
|
||||
// This variable should uniquely identify your game and/or mod.
|
||||
$Server::GameType = "FPS Starter Kit";
|
||||
|
||||
// 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;
|
||||
|
||||
// Load up all datablocks, objects etc. This function is called when
|
||||
// a server is constructed.
|
||||
exec("./audioProfiles.cs");
|
||||
exec("./camera.cs");
|
||||
exec("./markers.cs");
|
||||
exec("./triggers.cs");
|
||||
exec("./inventory.cs");
|
||||
exec("./shapeBase.cs");
|
||||
exec("./item.cs");
|
||||
exec("./health.cs");
|
||||
exec("./staticShape.cs");
|
||||
exec("./weapon.cs");
|
||||
exec("./radiusDamage.cs");
|
||||
exec("./crossbow.cs");
|
||||
exec("./player.cs");
|
||||
exec("./fire.cs");
|
||||
exec("./BlackKnight.cs");
|
||||
exec("./environment.cs");
|
||||
|
||||
//exec("./doors/door.cs");
|
||||
//exec("./doors/doorMetal.cs");
|
||||
//exec("./doors/doorgrey1.cs");
|
||||
exec("./doors/doorWood.cs");
|
||||
//exec("./doors/doorMetalMove.cs");
|
||||
|
||||
// Keep track of when the game started
|
||||
$Game::StartTime = $Sim::Time;
|
||||
}
|
||||
|
||||
function onServerDestroyed()
|
||||
{
|
||||
// This function is called as part of a server shutdown.
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function onMissionLoaded()
|
||||
{
|
||||
// Called by loadMission() once the mission is finished loading.
|
||||
// Nothing special for now, just start up the game play.
|
||||
startGame();
|
||||
}
|
||||
|
||||
function onMissionEnded()
|
||||
{
|
||||
// Called by endMission(), right before the mission is destroyed
|
||||
|
||||
// Normally the game should be ended first before the next
|
||||
// mission is loaded, this is here in case loadMission has been
|
||||
// called directly. The mission will be ended if the server
|
||||
// is destroyed, so we only need to cleanup here.
|
||||
cancel($Game::Schedule);
|
||||
$Game::Running = false;
|
||||
$Game::Cycling = false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function startGame()
|
||||
{
|
||||
if ($Game::Running) {
|
||||
error("startGame: End the game first!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Inform the client we're starting up
|
||||
for( %clientIndex = 0; %clientIndex < ClientGroup.getCount(); %clientIndex++ ) {
|
||||
%cl = ClientGroup.getObject( %clientIndex );
|
||||
commandToClient(%cl, 'GameStart');
|
||||
|
||||
// Other client specific setup..
|
||||
%cl.score = 0;
|
||||
}
|
||||
|
||||
// Start the game timer
|
||||
if ($Game::Duration)
|
||||
$Game::Schedule = schedule($Game::Duration * 1000, 0, "onGameDurationEnd" );
|
||||
$Game::Running = true;
|
||||
|
||||
AIPlayer::LoadEntities();
|
||||
}
|
||||
|
||||
function endGame()
|
||||
{
|
||||
if (!$Game::Running) {
|
||||
error("endGame: No game running!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop the AIManager
|
||||
AIManager.delete();
|
||||
|
||||
// Stop any game timers
|
||||
cancel($Game::Schedule);
|
||||
|
||||
// Inform the client the game is over
|
||||
for( %clientIndex = 0; %clientIndex < ClientGroup.getCount(); %clientIndex++ ) {
|
||||
%cl = ClientGroup.getObject( %clientIndex );
|
||||
commandToClient(%cl, 'GameEnd');
|
||||
}
|
||||
|
||||
// Delete all the temporary mission objects
|
||||
resetMission();
|
||||
$Game::Running = false;
|
||||
}
|
||||
|
||||
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 && !isObject(EditorGui))
|
||||
cycleGame();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
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();
|
||||
$Game::Schedule = schedule($Game::EndGamePause * 1000, 0, "onCyclePauseEnd");
|
||||
}
|
||||
|
||||
function onCyclePauseEnd()
|
||||
{
|
||||
$Game::Cycling = false;
|
||||
|
||||
// Just cycle through the missions for now.
|
||||
%search = $Server::MissionFileSpec;
|
||||
for (%file = findFirstFile(%search); %file !$= ""; %file = findNextFile(%search)) {
|
||||
if (%file $= $Server::MissionFile) {
|
||||
// Get the next one, back to the first if there
|
||||
// is no next.
|
||||
%file = findNextFile(%search);
|
||||
if (%file $= "")
|
||||
%file = findFirstFile(%search);
|
||||
break;
|
||||
}
|
||||
}
|
||||
loadMission(%file);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GameConnection Methods
|
||||
// These methods are extensions to the GameConnection class. Extending
|
||||
// GameConnection make is easier to deal with some of this functionality,
|
||||
// but these could also be implemented as stand-alone functions.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function GameConnection::onClientEnterGame(%this)
|
||||
{
|
||||
commandToClient(%this, 'SyncClock', $Sim::Time - $Game::StartTime);
|
||||
|
||||
// Create a new camera object.
|
||||
%this.camera = new Camera() {
|
||||
dataBlock = Observer;
|
||||
};
|
||||
MissionCleanup.add( %this.camera );
|
||||
%this.camera.scopeToClient(%this);
|
||||
|
||||
// Setup game parameters, the onConnect method currently starts
|
||||
// everyone with a 0 score.
|
||||
%this.score = 0;
|
||||
|
||||
// Create a player object.
|
||||
%this.spawnPlayer();
|
||||
}
|
||||
|
||||
function GameConnection::onClientLeaveGame(%this)
|
||||
{
|
||||
if (isObject(%this.camera))
|
||||
%this.camera.delete();
|
||||
if (isObject(%this.player))
|
||||
%this.player.delete();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function GameConnection::onLeaveMissionArea(%this)
|
||||
{
|
||||
// The control objects invoked this method when they
|
||||
// move out of the mission area.
|
||||
}
|
||||
|
||||
function GameConnection::onEnterMissionArea(%this)
|
||||
{
|
||||
// The control objects invoked this method when they
|
||||
// move back into the mission area.
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function GameConnection::onDeath(%this, %sourceObject, %sourceClient, %damageType, %damLoc)
|
||||
{
|
||||
// Clear out the name on the corpse
|
||||
%this.player.setShapeName("");
|
||||
|
||||
// Switch the client over to the death cam and unhook the player object.
|
||||
if (isObject(%this.camera) && isObject(%this.player)) {
|
||||
%this.camera.setMode("Corpse",%this.player);
|
||||
%this.setControlObject(%this.camera);
|
||||
}
|
||||
%this.player = 0;
|
||||
|
||||
// Doll out points and display an appropriate message
|
||||
if (%damageType $= "Suicide" || %sourceClient == %this) {
|
||||
%this.incScore(-1);
|
||||
messageAll('MsgClientKilled','%1 takes his own life!',%this.name);
|
||||
}
|
||||
else {
|
||||
%sourceClient.incScore(1);
|
||||
messageAll('MsgClientKilled','%1 gets nailed by %2!',%this.name,%sourceClient.name);
|
||||
if (%sourceClient.score >= $Game::EndGameScore)
|
||||
cycleGame();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function GameConnection::spawnPlayer(%this)
|
||||
{
|
||||
// Combination create player and drop him somewhere
|
||||
%spawnPoint = pickSpawnPoint();
|
||||
%this.createPlayer(%spawnPoint);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function GameConnection::createPlayer(%this, %spawnPoint)
|
||||
{
|
||||
if (%this.player > 0) {
|
||||
// The client should not have a player currently
|
||||
// assigned. Assigning a new one could result in
|
||||
// a player ghost.
|
||||
error( "Attempting to create an angus ghost!" );
|
||||
}
|
||||
|
||||
// Create the player object
|
||||
%player = new Player() {
|
||||
dataBlock = PlayerBody;
|
||||
client = %this;
|
||||
};
|
||||
MissionCleanup.add(%player);
|
||||
|
||||
// Player setup...
|
||||
%player.setTransform(%spawnPoint);
|
||||
%player.setShapeName(%this.name);
|
||||
|
||||
// Starting equipment
|
||||
%player.setInventory(Crossbow,1);
|
||||
%player.setInventory(CrossbowAmmo,10);
|
||||
%player.mountImage(CrossbowImage,0);
|
||||
|
||||
// Update the camera to start with the player
|
||||
%this.camera.setTransform(%player.getEyeTransform());
|
||||
|
||||
// Give the client control of the player
|
||||
%this.player = %player;
|
||||
%this.setControlObject(%player);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Support functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function pickSpawnPoint()
|
||||
{
|
||||
%groupName = "MissionGroup/PlayerDropPoints";
|
||||
%group = nameToID(%groupName);
|
||||
|
||||
if (%group != -1) {
|
||||
%count = %group.getCount();
|
||||
if (%count != 0) {
|
||||
%index = getRandom(%count-1);
|
||||
%spawn = %group.getObject(%index);
|
||||
return %spawn.getTransform();
|
||||
}
|
||||
else
|
||||
error("No spawn points found in " @ %groupName);
|
||||
}
|
||||
else
|
||||
error("Missing spawn points group " @ %groupName);
|
||||
|
||||
// Could be no spawn points, in which case we'll stick the
|
||||
// player at the center of the world.
|
||||
return "0 0 300 1 0 0 0";
|
||||
}
|
||||
BIN
Torque/SDK/example/starter.fps/server/scripts/game.cs.dso
Normal file
BIN
Torque/SDK/example/starter.fps/server/scripts/game.cs.dso
Normal file
Binary file not shown.
76
Torque/SDK/example/starter.fps/server/scripts/health.cs
Normal file
76
Torque/SDK/example/starter.fps/server/scripts/health.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Inventory items. These objects rely on the item & inventory support
|
||||
// system defined in item.cs and inventory.cs
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Health kits can be added to your inventory and used to heal up.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
datablock ItemData(HealthKit)
|
||||
{
|
||||
// Mission editor category, this datablock will show up in the
|
||||
// specified category under the "shapes" root category.
|
||||
category = "Health";
|
||||
|
||||
// Basic Item properties
|
||||
shapeFile = "~/data/shapes/items/healthKit.dts";
|
||||
mass = 1;
|
||||
friction = 1;
|
||||
elasticity = 0.3;
|
||||
|
||||
// Dynamic properties defined by the scripts
|
||||
pickupName = "a health kit";
|
||||
repairAmount = 50;
|
||||
};
|
||||
|
||||
function HealthKit::onUse(%this,%user)
|
||||
{
|
||||
// Apply some health to whoever uses it, the health kit is only
|
||||
// used if the user is currently damaged.
|
||||
if (%user.getDamageLevel() != 0) {
|
||||
%user.decInventory(%this,1);
|
||||
%user.applyRepair(%this.repairAmount);
|
||||
if (%user.client)
|
||||
messageClient(%user.client, 'MsgHealthKitUsed', '\c2Health Kit Applied');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Health Patchs cannot be picked up and are not meant to be added to
|
||||
// inventory. Health is applied automatically when an objects collides
|
||||
// with a patch.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
datablock ItemData(HealthPatch)
|
||||
{
|
||||
// Mission editor category, this datablock will show up in the
|
||||
// specified category under the "shapes" root category.
|
||||
category = "Health";
|
||||
|
||||
// Basic Item properties
|
||||
shapeFile = "~/data/shapes/items/healthPatch.dts";
|
||||
mass = 1;
|
||||
friction = 1;
|
||||
elasticity = 0.3;
|
||||
|
||||
// Dynamic properties defined by the scripts
|
||||
repairAmount = 20;
|
||||
maxInventory = 0; // No pickup or throw
|
||||
};
|
||||
|
||||
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);
|
||||
%obj.respawn();
|
||||
if (%col.client)
|
||||
messageClient(%col.client, 'MsgHealthPatchUsed', '\c2Health Patch Applied');
|
||||
}
|
||||
}
|
||||
BIN
Torque/SDK/example/starter.fps/server/scripts/health.cs.dso
Normal file
BIN
Torque/SDK/example/starter.fps/server/scripts/health.cs.dso
Normal file
Binary file not shown.
256
Torque/SDK/example/starter.fps/server/scripts/inventory.cs
Normal file
256
Torque/SDK/example/starter.fps/server/scripts/inventory.cs
Normal file
@@ -0,0 +1,256 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// 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.
|
||||
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);
|
||||
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::maxInventory(%this,%data)
|
||||
{
|
||||
// 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.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.
|
||||
}
|
||||
BIN
Torque/SDK/example/starter.fps/server/scripts/inventory.cs.dso
Normal file
BIN
Torque/SDK/example/starter.fps/server/scripts/inventory.cs.dso
Normal file
Binary file not shown.
130
Torque/SDK/example/starter.fps/server/scripts/item.cs
Normal file
130
Torque/SDK/example/starter.fps/server/scripts/item.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// 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 = 20 * 1000;
|
||||
|
||||
// Poptime represents how long dynamic items (those that are thrown or
|
||||
// dropped) will last in the world before being deleted.
|
||||
$Item::PopTime = 10 * 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.
|
||||
%count = %obj.count;
|
||||
if (%count $= "")
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Hook into the mission editor.
|
||||
|
||||
function ItemData::create(%data)
|
||||
{
|
||||
// The mission editor invokes this method when it wants to create
|
||||
// an object of the given datablock type. For the mission editor
|
||||
// we always create "static" re-spawnable rotating objects.
|
||||
%obj = new Item() {
|
||||
dataBlock = %data;
|
||||
static = true;
|
||||
rotate = true;
|
||||
};
|
||||
return %obj;
|
||||
}
|
||||
|
||||
BIN
Torque/SDK/example/starter.fps/server/scripts/item.cs.dso
Normal file
BIN
Torque/SDK/example/starter.fps/server/scripts/item.cs.dso
Normal file
Binary file not shown.
37
Torque/SDK/example/starter.fps/server/scripts/markers.cs
Normal file
37
Torque/SDK/example/starter.fps/server/scripts/markers.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
datablock MissionMarkerData(WayPointMarker)
|
||||
{
|
||||
category = "Misc";
|
||||
shapeFile = "~/data/shapes/markers/octahedron.dts";
|
||||
};
|
||||
|
||||
datablock MissionMarkerData(SpawnSphereMarker)
|
||||
{
|
||||
category = "Misc";
|
||||
shapeFile = "~/data/shapes/markers/octahedron.dts";
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// - serveral marker types may share MissionMarker datablock type
|
||||
function MissionMarkerData::create(%block)
|
||||
{
|
||||
switch$(%block)
|
||||
{
|
||||
case "WayPointMarker":
|
||||
%obj = new WayPoint() {
|
||||
dataBlock = %block;
|
||||
};
|
||||
return(%obj);
|
||||
case "SpawnSphereMarker":
|
||||
%obj = new SpawnSphere() {
|
||||
datablock = %block;
|
||||
};
|
||||
return(%obj);
|
||||
}
|
||||
return(-1);
|
||||
}
|
||||
BIN
Torque/SDK/example/starter.fps/server/scripts/markers.cs.dso
Normal file
BIN
Torque/SDK/example/starter.fps/server/scripts/markers.cs.dso
Normal file
Binary file not shown.
1120
Torque/SDK/example/starter.fps/server/scripts/player.cs
Normal file
1120
Torque/SDK/example/starter.fps/server/scripts/player.cs
Normal file
File diff suppressed because it is too large
Load Diff
BIN
Torque/SDK/example/starter.fps/server/scripts/player.cs.dso
Normal file
BIN
Torque/SDK/example/starter.fps/server/scripts/player.cs.dso
Normal file
Binary file not shown.
@@ -0,0 +1,54 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// 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::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
60
Torque/SDK/example/starter.fps/server/scripts/shapeBase.cs
Normal file
60
Torque/SDK/example/starter.fps/server/scripts/shapeBase.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// This file contains ShapeBase methods used by all the derived classes
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ShapeBase object
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
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 proceedure
|
||||
// for many built in callbacks.
|
||||
%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 (%obj.getState() !$= "Dead") {
|
||||
%this.damage(0, "0 0 0", %damageAmount, %damageType);
|
||||
%obj.damageSchedule = %obj.schedule(50, "setDamageDt", %damageAmount, %damageType);
|
||||
}
|
||||
else
|
||||
%obj.damageSchedule = "";
|
||||
}
|
||||
|
||||
function ShapeBase::clearDamageDt(%this)
|
||||
{
|
||||
if (%obj.damageSchedule !$= "") {
|
||||
cancel(%obj.damageSchedule);
|
||||
%obj.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.
|
||||
}
|
||||
BIN
Torque/SDK/example/starter.fps/server/scripts/shapeBase.cs.dso
Normal file
BIN
Torque/SDK/example/starter.fps/server/scripts/shapeBase.cs.dso
Normal file
Binary file not shown.
19
Torque/SDK/example/starter.fps/server/scripts/staticShape.cs
Normal file
19
Torque/SDK/example/starter.fps/server/scripts/staticShape.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Hook into the mission editor.
|
||||
|
||||
function StaticShapeData::create(%data)
|
||||
{
|
||||
// The mission editor invokes this method when it wants to create
|
||||
// an object of the given datablock type.
|
||||
%obj = new StaticShape() {
|
||||
dataBlock = %data;
|
||||
};
|
||||
return %obj;
|
||||
}
|
||||
|
||||
|
||||
BIN
Torque/SDK/example/starter.fps/server/scripts/staticShape.cs.dso
Normal file
BIN
Torque/SDK/example/starter.fps/server/scripts/staticShape.cs.dso
Normal file
Binary file not shown.
52
Torque/SDK/example/starter.fps/server/scripts/triggers.cs
Normal file
52
Torque/SDK/example/starter.fps/server/scripts/triggers.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// DefaultTrigger is used by the mission editor. This is also an example
|
||||
// of trigger methods and callbacks.
|
||||
|
||||
datablock TriggerData(DefaultTrigger)
|
||||
{
|
||||
// The period is value is used to control how often the console
|
||||
// onTriggerTick callback is called while there are any objects
|
||||
// in the trigger. The default value is 100 MS.
|
||||
tickPeriodMS = 100;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function DefaultTrigger::onEnterTrigger(%this,%trigger,%obj)
|
||||
{
|
||||
// This method is called whenever an object enters the %trigger
|
||||
// area, the object is passed as %obj. The default onEnterTrigger
|
||||
// method (in the C++ code) invokes the ::onTrigger(%trigger,1) method on
|
||||
// every object (whatever it's type) in the same group as the trigger.
|
||||
Parent::onEnterTrigger(%this,%trigger,%obj);
|
||||
}
|
||||
|
||||
function DefaultTrigger::onLeaveTrigger(%this,%trigger,%obj)
|
||||
{
|
||||
// This method is called whenever an object leaves the %trigger
|
||||
// area, the object is passed as %obj. The default onLeaveTrigger
|
||||
// method (in the C++ code) invokes the ::onTrigger(%trigger,0) method on
|
||||
// every object (whatever it's type) in the same group as the trigger.
|
||||
Parent::onLeaveTrigger(%this,%trigger,%obj);
|
||||
}
|
||||
|
||||
function DefaultTrigger::onTickTrigger(%this,%trigger)
|
||||
{
|
||||
// This method is called every tickPerioMS, as long as any
|
||||
// objects intersect the trigger. The default onTriggerTick
|
||||
// method (in the C++ code) invokes the ::onTriggerTick(%trigger) method on
|
||||
// every object (whatever it's type) in the same group as the trigger.
|
||||
|
||||
// You can iterate through the objects in the list by using these
|
||||
// methods:
|
||||
// %this.getNumObjects();
|
||||
// %this.getObject(n);
|
||||
Parent::onTickTrigger(%this,%trigger);
|
||||
}
|
||||
|
||||
BIN
Torque/SDK/example/starter.fps/server/scripts/triggers.cs.dso
Normal file
BIN
Torque/SDK/example/starter.fps/server/scripts/triggers.cs.dso
Normal file
Binary file not shown.
118
Torque/SDK/example/starter.fps/server/scripts/weapon.cs
Normal file
118
Torque/SDK/example/starter.fps/server/scripts/weapon.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// 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;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Audio profiles
|
||||
|
||||
datablock AudioProfile(WeaponUseSound)
|
||||
{
|
||||
filename = "~/data/sound/weapon_switch.wav";
|
||||
description = AudioClose3d;
|
||||
preload = true;
|
||||
};
|
||||
|
||||
datablock AudioProfile(WeaponPickupSound)
|
||||
{
|
||||
filename = "~/data/sound/weapon_pickup.wav";
|
||||
description = AudioClose3d;
|
||||
preload = true;
|
||||
};
|
||||
|
||||
datablock AudioProfile(AmmoPickupSound)
|
||||
{
|
||||
filename = "~/data/sound/ammo_pickup.wav";
|
||||
description = AudioClose3d;
|
||||
preload = true;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Weapon Class
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function Weapon::onUse(%data,%obj)
|
||||
{
|
||||
// Default behavoir for all weapons is to mount it into the
|
||||
// this 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)
|
||||
messageClient(%obj.client, 'MsgWeaponUsed', '\c0Weapon selected');
|
||||
}
|
||||
}
|
||||
|
||||
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,%obj.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 (%obj.getInventory(%this.ammo))
|
||||
%obj.setImageAmmo(%slot,true);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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,%obj.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);
|
||||
}
|
||||
}
|
||||
BIN
Torque/SDK/example/starter.fps/server/scripts/weapon.cs.dso
Normal file
BIN
Torque/SDK/example/starter.fps/server/scripts/weapon.cs.dso
Normal file
Binary file not shown.
Reference in New Issue
Block a user