mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-19 20:24:49 +00:00
326 lines
8.6 KiB
C#
326 lines
8.6 KiB
C#
//-----------------------------------------------------------------------------
|
|
// Copyright (c) 2012 GarageGames, LLC
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to
|
|
// deal in the Software without restriction, including without limitation the
|
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
// sell copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
// IN THE SOFTWARE.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// AIPlayer callbacks
|
|
// The AIPlayer class implements the following callbacks:
|
|
//
|
|
// PlayerData::onStop(%this,%obj)
|
|
// PlayerData::onMove(%this,%obj)
|
|
// PlayerData::onReachDestination(%this,%obj)
|
|
// PlayerData::onMoveStuck(%this,%obj)
|
|
// PlayerData::onTargetEnterLOS(%this,%obj)
|
|
// PlayerData::onTargetExitLOS(%this,%obj)
|
|
// PlayerData::onAdd(%this,%obj)
|
|
//
|
|
// Since the AIPlayer doesn't implement it's own datablock, these callbacks
|
|
// all take place in the PlayerData namespace.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Demo Pathed AIPlayer.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
function DemoPlayer::onReachDestination(%this,%obj)
|
|
{
|
|
//echo( %obj @ " onReachDestination" );
|
|
|
|
// Moves to the next node on the path.
|
|
// Override for all player. Normally we'd override this for only
|
|
// a specific player datablock or class of players.
|
|
if (%obj.path !$= "")
|
|
{
|
|
if (%obj.currentNode == %obj.targetNode)
|
|
%this.onEndOfPath(%obj,%obj.path);
|
|
else
|
|
%obj.moveToNextNode();
|
|
}
|
|
}
|
|
|
|
function DemoPlayer::onMoveStuck(%this,%obj)
|
|
{
|
|
//echo( %obj @ " onMoveStuck" );
|
|
}
|
|
|
|
function DemoPlayer::onTargetExitLOS(%this,%obj)
|
|
{
|
|
//echo( %obj @ " onTargetExitLOS" );
|
|
}
|
|
|
|
function DemoPlayer::onTargetEnterLOS(%this,%obj)
|
|
{
|
|
//echo( %obj @ " onTargetEnterLOS" );
|
|
}
|
|
|
|
function DemoPlayer::onEndOfPath(%this,%obj,%path)
|
|
{
|
|
%obj.nextTask();
|
|
}
|
|
|
|
function DemoPlayer::onEndSequence(%this,%obj,%slot)
|
|
{
|
|
echo("Sequence Done!");
|
|
%obj.stopThread(%slot);
|
|
%obj.nextTask();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// AIPlayer static functions
|
|
//-----------------------------------------------------------------------------
|
|
|
|
function AIPlayer::produce(%name,%spawnPoint)
|
|
{
|
|
// Create the demo player object
|
|
%player = new AiPlayer()
|
|
{
|
|
dataBlock = DemoPlayer;
|
|
path = "";
|
|
};
|
|
MissionCleanup.add(%player);
|
|
%player.setShapeName(%name);
|
|
%player.setTransform(%spawnPoint);
|
|
return %player;
|
|
}
|
|
|
|
function AIPlayer::spawnOnPath(%name,%path)
|
|
{
|
|
// Spawn a player and place him on the first node of the path
|
|
if (!isObject(%path))
|
|
return 0;
|
|
%node = %path.getObject(0);
|
|
%player = AIPlayer::produce(%name, %node.getTransform());
|
|
return %player;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// AIPlayer methods
|
|
//-----------------------------------------------------------------------------
|
|
|
|
function AIPlayer::followPath(%this,%path,%node)
|
|
{
|
|
// Start the player following a path
|
|
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());
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
function AIPlayer::pushTask(%this,%method)
|
|
{
|
|
if (%this.taskIndex $= "")
|
|
{
|
|
%this.taskIndex = 0;
|
|
%this.taskCurrent = -1;
|
|
}
|
|
%this.task[%this.taskIndex] = %method;
|
|
%this.taskIndex++;
|
|
if (%this.taskCurrent == -1)
|
|
%this.executeTask(%this.taskIndex - 1);
|
|
}
|
|
|
|
function AIPlayer::clearTasks(%this)
|
|
{
|
|
%this.taskIndex = 0;
|
|
%this.taskCurrent = -1;
|
|
}
|
|
|
|
function AIPlayer::nextTask(%this)
|
|
{
|
|
if (%this.taskCurrent != -1)
|
|
if (%this.taskCurrent < %this.taskIndex - 1)
|
|
%this.executeTask(%this.taskCurrent++);
|
|
else
|
|
%this.taskCurrent = -1;
|
|
}
|
|
|
|
function AIPlayer::executeTask(%this,%index)
|
|
{
|
|
%this.taskCurrent = %index;
|
|
eval(%this.getId() @"."@ %this.task[%index] @";");
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
function AIPlayer::singleShot(%this)
|
|
{
|
|
// The shooting delay is used to pulse the trigger
|
|
%this.setImageTrigger(0, true);
|
|
%this.setImageTrigger(0, false);
|
|
%this.trigger = %this.schedule(%this.shootingDelay, singleShot);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
function AIPlayer::wait(%this, %time)
|
|
{
|
|
%this.schedule(%time * 1000, "nextTask");
|
|
}
|
|
|
|
function AIPlayer::done(%this,%time)
|
|
{
|
|
%this.schedule(0, "delete");
|
|
}
|
|
|
|
function AIPlayer::fire(%this,%bool)
|
|
{
|
|
if (%bool)
|
|
{
|
|
cancel(%this.trigger);
|
|
%this.singleShot();
|
|
}
|
|
else
|
|
cancel(%this.trigger);
|
|
%this.nextTask();
|
|
}
|
|
|
|
function AIPlayer::aimAt(%this,%object)
|
|
{
|
|
echo("Aim: "@ %object);
|
|
%this.setAimObject(%object);
|
|
%this.nextTask();
|
|
}
|
|
|
|
function AIPlayer::animate(%this,%seq)
|
|
{
|
|
//%this.stopThread(0);
|
|
//%this.playThread(0,%seq);
|
|
%this.setActionThread(%seq);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Some handy getDistance/nearestTarget functions for the AI to use
|
|
// ----------------------------------------------------------------------------
|
|
|
|
function AIPlayer::getTargetDistance(%this, %target)
|
|
{
|
|
echo("\c4AIPlayer::getTargetDistance("@ %this @", "@ %target @")");
|
|
$tgt = %target;
|
|
%tgtPos = %target.getPosition();
|
|
%eyePoint = %this.getWorldBoxCenter();
|
|
%distance = VectorDist(%tgtPos, %eyePoint);
|
|
echo("Distance to target = "@ %distance);
|
|
return %distance;
|
|
}
|
|
|
|
function AIPlayer::getNearestPlayerTarget(%this)
|
|
{
|
|
echo("\c4AIPlayer::getNearestPlayerTarget("@ %this @")");
|
|
|
|
%index = -1;
|
|
%botPos = %this.getPosition();
|
|
%count = ClientGroup.getCount();
|
|
for(%i = 0; %i < %count; %i++)
|
|
{
|
|
%client = ClientGroup.getObject(%i);
|
|
if (%client.player $= "" || %client.player == 0)
|
|
return -1;
|
|
%playerPos = %client.player.getPosition();
|
|
|
|
%tempDist = VectorDist(%playerPos, %botPos);
|
|
if (%i == 0)
|
|
{
|
|
%dist = %tempDist;
|
|
%index = %i;
|
|
}
|
|
else
|
|
{
|
|
if (%dist > %tempDist)
|
|
{
|
|
%dist = %tempDist;
|
|
%index = %i;
|
|
}
|
|
}
|
|
}
|
|
return %index;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
function AIPlayer::think(%player)
|
|
{
|
|
// Thinking allows us to consider other things...
|
|
%player.schedule(500, think);
|
|
}
|
|
|
|
function AIPlayer::spawn(%path)
|
|
{
|
|
%player = AIPlayer::spawnOnPath("Shootme", %path);
|
|
|
|
if (isObject(%player))
|
|
{
|
|
%player.followPath(%path, -1);
|
|
|
|
// slow this sucker down, I'm tired of chasing him!
|
|
%player.setMoveSpeed(0.5);
|
|
|
|
//%player.mountImage(xxxImage, 0);
|
|
//%player.setInventory(xxxAmmo, 1000);
|
|
//%player.think();
|
|
|
|
return %player;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|