Added documentation

This commit is contained in:
Robert MacGregor 2015-10-10 16:08:43 -04:00
parent d6352a5a41
commit 167137f755
10 changed files with 198 additions and 36 deletions

View file

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2014 Robert MacGregor
Copyright (c) 2015 Robert MacGregor
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -3,7 +3,22 @@
// Source file for the DXAI commander AI implementation.
// https://github.com/Ragora/T2-DXAI.git
//
// Copyright (c) 2014 Robert MacGregor
// The AICommander type is a complex beast. They have the following proerties associated
// with them:
// * %commander.botList: A SimSet of all bots that are currently associated with the
// given commander.
// * %commander.idleBotList: A SimSet of all bots that are currently considered be idle.
// These bots were not explicitly given anything to do by the commander AI and so they are
// not doing anything particularly helpful.
// * %commander.botAssignments[%assignmentID]: An associative container that maps
// assignment ID's (those desiginated by $DXAI::Priorities::*) to the total number of
// bots assigned.
// * %commander.objectiveCycles[%assignmentID]: An associative container that maps assignment
// ID's (those desiginated by $DXAI::Priorities::*) to an instance of a CyclicSet which contains
// the ID's of AI nav graph placed objective markers to allow for cycling through the objectives
// set for the team.
//
// Copyright (c) 2015 Robert MacGregor
// This software is licensed under the MIT license. Refer to LICENSE.txt for more information.
//------------------------------------------------------------------------------------------
@ -18,6 +33,12 @@ $DXAI::Priorities::CaptureObjective = 5;
$DXAI::Priorities::AttackTurret = 6;
$DXAI::Priorities::Count = 3;
//------------------------------------------------------------------------------------------
// Description: These global variables are the default priorities that commanders will
// initialize with for specific tasks that can be distributed to the bots on the team.
//
// NOTE: These should be fairly laid back initially and allow for a good count of idle bots.
//------------------------------------------------------------------------------------------
$DXAI::Priorities::DefaultPriorityValue[$DXAI::Priorities::DefendGenerator] = 2;
$DXAI::Priorities::DefaultPriorityValue[$DXAI::Priorities::DefendFlag] = 3;
$DXAI::Priorities::DefaultPriorityValue[$DXAI::Priorities::ScoutBase] = 1;
@ -26,6 +47,11 @@ $DXAI::Priorities::Text[$DXAI::Priorities::DefendGenerator] = "Defending a Gener
$DXAI::Priorities::Text[$DXAI::Priorities::DefendFlag] = "Defending the Flag";
$DXAI::Priorities::Text[$DXAI::Priorities::ScoutBase] = "Scouting a Location";
//------------------------------------------------------------------------------------------
// Description: Sets up the AI commander by creating the bot list sim sets as well as
// claiming the bots that are currently on their team. Bots claimed will have all of their
// independent ticks started up such as the visual acuity tick.
//------------------------------------------------------------------------------------------
function AICommander::setup(%this)
{
%this.botList = new SimSet();
@ -44,6 +70,8 @@ function AICommander::setup(%this)
%currentClient.initialize();
%currentClient.visibleHostiles = new SimSet();
// Start our ticks.
%currentClient.updateVisualAcuity();
%currentClient.stuckCheck();
}
@ -59,6 +87,14 @@ function AICommander::setup(%this)
}
}
//------------------------------------------------------------------------------------------
// Description: Skims the objectives for the AI commander's team and pulls out any that
// we can use when assigning tasks to bots. This is done with some recursion down the line
// of nested SimGroup instances. When a usable objective is located, it is added to the
// cycler associated with the most appropriate task.
// Param %group: The group to recurse down.
// NOTE: This is an internal function and therefore should not be called directly.
//------------------------------------------------------------------------------------------
function AICommander::_skimObjectiveGroup(%this, %group)
{
for (%iteration = 0; %iteration < %group.getCount(); %iteration++)
@ -93,6 +129,11 @@ function AICommander::_skimObjectiveGroup(%this, %group)
}
}
//------------------------------------------------------------------------------------------
// Description: Loads or reloads the objectives for the AI commander's team. It searches
// for the AIObjectives group associated with the team (all teams have one called that)
// and passes it off to _skimObjectGroup which does the actual objective processing.
//------------------------------------------------------------------------------------------
function AICommander::loadObjectives(%this)
{
// First we clear the old cyclers
@ -133,6 +174,16 @@ function AICommander::loadObjectives(%this)
%this.objectiveCycles[$DXAI::Priorities::ScoutBase].add(%scoutLocationObjective);
}
//------------------------------------------------------------------------------------------
// Description: Distributes and assigns tasks to all bots under the jurisdiction of the
// AI commander according to current tasks priorities.
//
// TODO: Assign something to bots that are considered to be idle so they can stop sitting
// on top of the inventory stations like lazy bums.
// FIXME: This will be called when the commander wants to distribute tasks differently
// than what was previous set, and so blindly instructing bots to rearm isn't exactly
// the best choice in hindsight.
//------------------------------------------------------------------------------------------
function AICommander::assignTasks(%this)
{
// First, assign objectives that all bots should have
@ -214,6 +265,9 @@ function AICommander::assignTasks(%this)
%priorityQueue.delete();
}
//------------------------------------------------------------------------------------------
// Description:
//------------------------------------------------------------------------------------------
function AICommander::deassignBots(%this, %taskID, %count)
{
// TODO: More efficient removal?
@ -271,12 +325,23 @@ function AICommander::assignTask(%this, %taskID, %bot)
%bot.assignment = %taskID;
}
//------------------------------------------------------------------------------------------
// Description: Helper function that is used to set the default task prioritizations on
// the commander object.
//------------------------------------------------------------------------------------------
function AICommander::setDefaultPriorities(%this)
{
for (%iteration = 0; %iteration < $DXAI::Priorities::Count; %iteration++)
%this.priorities[%iteration] = $DXAI::Priorities::DefaultPriorityValue[%iteration];
}
//------------------------------------------------------------------------------------------
// Description: Performs a deinitialization that should be ran before deleting the
// commander object itself.
//
// NOTE: This is called automatically by .delete so this shouldn't have to be called
// directly.
//------------------------------------------------------------------------------------------
function AICommander::cleanUp(%this)
{
for (%iteration = 0; %iteration < %this.botList.getCount(); %iteration++)
@ -285,17 +350,31 @@ function AICommander::cleanUp(%this)
cancel(%current.visualAcuityTick);
cancel(%current.stuckCheckTick);
}
%this.botList.delete();
%this.idleBotList.delete();
}
//------------------------------------------------------------------------------------------
// Description: An overwritten delete function to perform proper cleanup before actually
// deleting the commander object.
//------------------------------------------------------------------------------------------
function AICommander::delete(%this)
{
%this.cleanUp();
ScriptObject::delete(%this);
}
function AICommander::update(%this)
{
for (%iteration = 0; %iteration < %this.botList.getCount(); %iteration++)
%this.botList.getObject(%iteration).update();
}
//------------------------------------------------------------------------------------------
// Description: Removes the given bot from this AI commander's jurisdiction.
// Param %bot: The AIConnection to remove.
//------------------------------------------------------------------------------------------
function AICommander::removeBot(%this, %bot)
{
%this.botList.remove(%bot);
@ -304,15 +383,23 @@ function AICommander::removeBot(%this, %bot)
%bot.commander = -1;
}
//------------------------------------------------------------------------------------------
// Description: Adds the given bot to the jurisdiction of this AI commander if the bot and
// commander work for the same team.
// Param %bot: The AIConnection to add.
// Return: A boolean representing whether or not the bot was successfully added. False is
// returned if the two are not on the same time at the time of adding.
//------------------------------------------------------------------------------------------
function AICommander::addBot(%this, %bot)
{
if (!%this.botList.isMember(%bot))
%this.botList.add(%bot);
if (!%this.idleBotList.isMember(%bot))
%this.idleBotList.add(%bot);
if (%bot.team != %this.team)
return false;
%this.botList.add(%bot);
%this.idleBotList.add(%bot);
%bot.commander = %this;
return true;
}
function AICommander::notifyPlayerDeath(%this, %killedClient, %killedByClient)

View file

@ -4,7 +4,7 @@
// AI enhancement project.
// https://github.com/Ragora/T2-DXAI.git
//
// Copyright (c) 2014 Robert MacGregor
// Copyright (c) 2015 Robert MacGregor
// This software is licensed under the MIT license.
// Refer to LICENSE.txt for more information.
//------------------------------------------------------------------------------------------

View file

@ -3,7 +3,7 @@
// Configuration file for the experimental DXAI system.
// https://github.com/Ragora/T2-DXAI.git
//
// Copyright (c) 2014 Robert MacGregor
// Copyright (c) 2015 Robert MacGregor
// This software is licensed under the MIT license.
// Refer to LICENSE.txt for more information.
//------------------------------------------------------------------------------------------

View file

@ -4,7 +4,7 @@
// that is cycled through from start to finish before looping back to start.
// https://github.com/Ragora/T2-DXAI.git
//
// Copyright (c) 2014 Robert MacGregor
// Copyright (c) 2015 Robert MacGregor
// This software is licensed under the MIT license. Refer to LICENSE.txt for more information.
//------------------------------------------------------------------------------------------

View file

@ -3,7 +3,7 @@
// Helper functions used in the experimental DXAI system.
// https://github.com/Ragora/T2-DXAI.git
//
// Copyright (c) 2014 Robert MacGregor
// Copyright (c) 2015 Robert MacGregor
// This software is licensed under the MIT license.
// Refer to LICENSE.txt for more information.
//------------------------------------------------------------------------------------------
@ -49,7 +49,9 @@ function pointInTriangle(%point, %a, %b, %c)
// as the game's scripting environment for the gameplay is single threaded
// and it probably does a hash to store the values.
// FIXME: Mathematical optimizations, right now it's a hack because of no
// reliable way of getting a player's X facing?
// reliable way of getting a player's X facing? Also, the horizontal view cones may
// be all that's necessary. A player height check could be used to help alleviate
// computational complexity.
//------------------------------------------------------------------------------------------
function GameConnection::calculateViewCone(%this, %distance)
{
@ -243,6 +245,9 @@ function GameConnection::getObjectsInViewcone(%this, %typeMask, %distance, %perf
// Description: Gets a random position somewhere within %distance of the given position.
// Param %position: The position to generate a new position around.
// Param %distance: The maximum distance the new position may be
// Param %raycast: A boolean representing whether or not a raycast should be made from
// %position to the randomly chosen location to stop on objects that may be in the way.
// This is useful for grabbing positions indoors.
//------------------------------------------------------------------------------------------
function getRandomPosition(%position, %distance, %raycast)
{
@ -261,13 +266,27 @@ function getRandomPosition(%position, %distance, %raycast)
return %result;
}
//------------------------------------------------------------------------------------------
// Description: Gets a random position somewhere within %distance of the given position
// relative to the terrain object using getTerrainHeight. This is faster to use than
// getRandomPosition with the raycast setting if all that is necessary is generating a
// position relative to the terrain object.
// Param %position: The position to generate a new position around.
// Param %distance: The maximum distance the new position may be
//------------------------------------------------------------------------------------------
function getRandomPositionOnTerrain(%position, %distance)
{
%result = getRandomPosition(%position, %distance);
return setWord(%result, 2, getTerrainHeight(%result));
}
function vectorMultiply(%vec1, %vec2)
//------------------------------------------------------------------------------------------
// Description: Multiplies two vectors together and returns the result.
// Param %vec1: The first vector to multiply.
// Param %vec2: The second vector to multiply.
// Return: The product of the multiplication.
//------------------------------------------------------------------------------------------
function vectorMult(%vec1, %vec2)
{
return (getWord(%vec1, 0) * getWord(%vec2, 0)) SPC
(getWord(%vec1, 1) * getWord(%vec2, 1)) SPC

View file

@ -4,7 +4,7 @@
// appropriate tasks.
// https://github.com/Ragora/T2-DXAI.git
//
// Copyright (c) 2014 Robert MacGregor
// Copyright (c) 2015 Robert MacGregor
// This software is licensed under the MIT license. Refer to LICENSE.txt for more information.
//------------------------------------------------------------------------------------------

View file

@ -3,7 +3,7 @@
// Main source file for the DXAI experimental AI enhancement project.
// https://github.com/Ragora/T2-DXAI.git
//
// Copyright (c) 2014 Robert MacGregor
// Copyright (c) 2015 Robert MacGregor
// This software is licensed under the MIT license. Refer to LICENSE.txt for more information.
//------------------------------------------------------------------------------------------
@ -16,20 +16,28 @@ exec("scripts/DXAI/priorityqueue.cs");
exec("scripts/DXAI/cyclicset.cs");
exec("scripts/DXAI/loadouts.cs");
// General DXAI API implementations
//------------------------------------------------------------------------------------------
// Description: This cleanup function is called when the mission ends to clean up all
// active commanders and to delete them for the next mission which guarantees a blank
// slate.
//------------------------------------------------------------------------------------------
function DXAI::cleanup()
{
$DXAI::System::Setup = false;
for (%iteration = 1; %iteration < $DXAI::ActiveCommanderCount + 1; %iteration++)
{
$DXAI::ActiveCommander[%iteration].cleanup();
$DXAI::ActiveCommander[%iteration].delete();
}
$DXAI::ActiveCommanderCount = 0;
}
//------------------------------------------------------------------------------------------
// Description: This cleanup function is called when the mission starts to to instantiate
// and setup all AI commanders for the game.
// Param %numTeams: The number of teams to initialize for.
//
// TODO: Perhaps calculate %numTeams from the game object?
//------------------------------------------------------------------------------------------
function DXAI::setup(%numTeams)
{
// Mark the environment as invalidated for each new run so that our hooks
@ -61,6 +69,21 @@ function DXAI::setup(%numTeams)
$DXAI::ActiveCommanderCount = %numTeams;
}
//------------------------------------------------------------------------------------------
// Why: Due to the way the AI system must hook into some functions and the way game
// modes work, we must generate runtime overrides for some gamemode related functions. We
// can't simply hook DefaultGame functions base game modes will declare their own and so
// we'll need to hook those functions post-start as the game mode scripts are executed for
// each mission run.
// Description: This function is called once per update tick (roughly 32 milliseconds) to
// check that the hooks we need are actually active if the system detects that may be a
// necessity to do so. A runtime check is initiated at gamemode start and for each exec
// call made during runtime as any given exec can overwrite the hooks we required.
// If they were not overwritten, the function will return 11595 and do nothing else if the
// appropriate dummy parameters are passed in.
//
// TODO: Perhaps calculate %numTeams from the game object?
//------------------------------------------------------------------------------------------
function DXAI::validateEnvironment()
{
%gameModeName = $CurrentMissionType @ "Game";
@ -90,6 +113,14 @@ function DXAI::validateEnvironment()
$DXAI::System::InvalidatedEnvironment = false;
}
//------------------------------------------------------------------------------------------
// Description: This update function is scheduled to be called roughly once every 32
// milliseconds which updates each active commander in the game as well as performs
// an environment validation if necessary.
//
// NOTE: This is called on its own scheduled tick, therefore it should not be called
// directly.
//------------------------------------------------------------------------------------------
function DXAI::update()
{
if (isEventPending($DXAI::updateHandle))
@ -116,9 +147,19 @@ function DXAI::notifyPlayerDeath(%killed, %killedBy)
$DXAI::ActiveCommander[%iteration].notifyPlayerDeath(%killed, %killedBy);
}
// Hooks for the AI System
//------------------------------------------------------------------------------------------
// Description: There is a series of functions that the AI code can safely hook without
// worry of being overwritten implicitly such as the disconnect or exec functions. For
// those that can be, there is an environment validation that is performed to ensure that
// the necessary code will be called in response to the events we need to know about in
// this AI system.
//------------------------------------------------------------------------------------------
package DXAI_Hooks
{
//------------------------------------------------------------------------------------------
// Description: Called when the mission ends. We use this to perform any necessary cleanup
// operations between games.
//------------------------------------------------------------------------------------------
function DefaultGame::gameOver(%game)
{
parent::gameOver(%game);
@ -126,6 +167,10 @@ package DXAI_Hooks
DXAI::cleanup();
}
//------------------------------------------------------------------------------------------
// Description: Called when the mission starts. We use this to perform initialization and
// to start the update ticks.
//------------------------------------------------------------------------------------------
function DefaultGame::startMatch(%game)
{
parent::startMatch(%game);
@ -134,14 +179,22 @@ package DXAI_Hooks
DXAI::update();
}
// Listen server fix
//------------------------------------------------------------------------------------------
// Description: We hook the disconnect function as a step to fix console spam from leaving
// a listen server due to the AI code continuing to run post-server shutdown in those
// cases.
//------------------------------------------------------------------------------------------
function disconnect()
{
parent::disconnect();
DXAI::Cleanup();
DXAI::cleanup();
}
//------------------------------------------------------------------------------------------
// Description: In the game, bots can be made to change teams which means we need to hook
// this event so that commander affiliations can be properly updated.
//------------------------------------------------------------------------------------------
function DefaultGame::AIChangeTeam(%game, %client, %newTeam)
{
// Remove us from the old commander's control first
@ -152,6 +205,10 @@ package DXAI_Hooks
$DXAI::ActiveCommander[%newTeam].addBot(%client);
}
//------------------------------------------------------------------------------------------
// Description: In the game, bots can be kicked like regular players so we hook this to
// ensure that commanders are properly notified of lesser bot counts.
//------------------------------------------------------------------------------------------
function AIConnection::onAIDrop(%client)
{
if (isObject(%client.commander))
@ -175,6 +232,11 @@ package DXAI_Hooks
DXAI::notifyPlayerDeath(%clVictim, %clKiller);
}
//------------------------------------------------------------------------------------------
// Description: We hook this function to implement some basic sound simulation for bots.
// This means that if something explodes, a bot will hear it and if the sound is close
// enough, they will shimmy away from the source using setDangerLocation.
//------------------------------------------------------------------------------------------
function ProjectileData::onExplode(%data, %proj, %pos, %mod)
{
parent::onExplode(%data, %proj, %pos, %mod);
@ -223,8 +285,11 @@ package DXAI_Hooks
}
}
// The CreateServer function is hooked so that we can try and guarantee that the DXAI gamemode hooks still
// exist in the runtime.
//------------------------------------------------------------------------------------------
// Description: This function is hooked so that we can try and guarantee that the DXAI
// gamemode hooks still exist in the runtime as game mode scripts are executed for each
// mission load.
//------------------------------------------------------------------------------------------
function CreateServer(%mission, %missionType)
{
// Perform the default exec's

View file

@ -3,19 +3,10 @@
// Source file for the DXAI enhanced objective implementations.
// https://github.com/Ragora/T2-DXAI.git
//
// Copyright (c) 2014 Robert MacGregor
// Copyright (c) 2015 Robert MacGregor
// This software is licensed under the MIT license. Refer to LICENSE.txt for more information.
//------------------------------------------------------------------------------------------
// Weights
// AIEnhancedFlagCaptureTask - $DXAI::Task::MediumPriority
// AIEnhancedEscort - $DXAI::Task::MediumPriority
// AIEnhancedDefendLocation - $DXAI::Task::MediumPriority
// AIEnhancedScoutLocation - $DXAI::Task::MediumPriority
// AIEnhancedEngageTarget - $DXAI::Task::VeryHighPriority
// AIEnhancedReturnFlagTask - $DXAI::Task::HighPriority
// AIEnhancedRearmTask - $DXAI::Task::HighPriority
$DXAI::Task::NoPriority = 0;
$DXAI::Task::LowPriority = 100;
$DXAI::Task::MediumPriority = 200;

View file

@ -6,7 +6,7 @@
// FIXME: Make the keys regular priorities so more than one value can occupy the same
// priority value.
//
// Copyright (c) 2014 Robert MacGregor
// Copyright (c) 2015 Robert MacGregor
// This software is licensed under the MIT license. Refer to LICENSE.txt for more information.
//------------------------------------------------------------------------------------------