| Author: beffy (c++programmer) |
Here are updated HEAD bot script functions by Michael Schaumburg - thanks for providing them!! :)
In GameConnection::spawnPlayer(), add:
// set the number of NPC's and initialize them
// ----------------------------------------
cancel($scanSchedule); // stop schedule function till all the player are created
%count = MissionGroup.getCount(); // all the members in this group
for(%i=0; %i < %count; %i++){ // step through the group
%obj=MissionGroup.getObject(%i); // get the object ID
%objName=%obj.getClassName(); // get the class name of this object
if(%objName $= "AIPlayer"){ // if its AIPlayer, we found a NPC
%test = %obj.getName(); // wird mit Apply im editor gesetzt
//error("NPC heisst:" SPC %test); // z.B. goove
$npc[$npcCounter] = %obj; // initial the $npc array
npcSetProperties($npc[$npcCounter]); // set the properties of this NPC, in aiPlayer.cs
$npcCounter++; // increase array counter
}
}
Here are some new and adjusted helper functions...
function npcSetProperties(%this) // NPC Properties einstellen
{
//MissionCleanup.add(%this); // zu mission clean addieren
%this.setEnergyLevel(60);
// start with a weapon
%this.incInventory(Crossbow,1);
%this.incInventory(CrossbowAmmo,CrossbowAmmo.maxInventory);
%this.use(Crossbow);
%this.setMoveSpeed(0.2);
startBot(%this);
}
function startBot(%this) // schedule function die ständig
{ // update NPC's
for(%i = 0;%i<$npcCounter;%i++) // wir gehen alle NPC's durch
{
// hier erfolgt der letzte Aufruf mit $npc[%i]
if(isObject($npc[%i]))
AIPlayer::handleWaypointsAndChase($npc[%i]); // von hier werden sämtliche functions aufgerufen
}
$scanSchedule = schedule(500, 0, "startBot"); // die function ruft sich selbst auf
}
function AIPlayer::handleWaypointsAndChase(%this)
{
%count = ClientGroup.getCount();
// look for next "available" human player...
%client = ClientGroup.getObject(AIPlayer::getClosestHuman(%this)); // get the next nearest player
$daPlaya = %client.player; // daPlaya wird hier global deklariert
if(isObject($daPlaya)){ // only if $daPlaya is still an object
%playPos = $daPlaya.getPosition();
AIPlayer::shootHimIfYouSeeHim(%this, %playPos); // bot und human position werden übergeben
}
else{ // happens when a player is killed
%this.fireWeapon(false); // don't shoot on a killed player
%this.stopMove(); // no movement
%this.clearAim();
return;
}
}
//--------------------------------------------------------------------
// get the next nearest player
// given is: %this = bot ID
// return is: %index = player index
//--------------------------------------------------------------------
function AIPlayer::getClosestHuman(%this)
{
%botpos = %this.getTransform(); // get bot position
%count = ClientGroup.getCount(); // number of player
%tempDist2 = 32000; // set this great
for(%i = 0; %i < %count; %i++) // step through
{
%client = ClientGroup.getObject(%i);
if(isObject(%client.player)) // only if client.player is an object
{
%playPos = %client.player.getPosition(); // player position
%tempDist = VectorDist(%playPos, %botPos); // distance player - bot
if(%tempDist2 > %tempDist) // if Dist2 greater Dist we take the smaller
{
%tempDist2 = %tempDist; // save shortest Dist
%index = %i; // set %index
}
}
}
return %index;
}
//--------------------------------------------------------------------
// shoot the player if you see him, if not wait and don't shoot
// given is: %this = bot ID / %playPos = position from global $daPlaya
// return is: nothing
//--------------------------------------------------------------------
function AIPlayer::shootHimIfYouSeeHim(%this, %playPos)
{
%myrange = 70; // ev. adjust
%iSeeHim = AIPlayer::isObjectInView(%this, $daPlaya); // %iSeeHim >0 NPC can see human
//error(%this SPC "isObjectInView:" SPC %iSeeHim);
if(%iSeeHim)
{
//error(%this @ ": I see him!!!");
%this.setAimLocation($daPlaya.getWorldBoxCenter());
// do we have a weapon?
if ( (%this.hasInventory("Crossbow") && %this.hasInventory("CrossbowAmmo"))
|| (%this.hasInventory("Rifle") && %this.hasInventory("RifleAmmo")) )
{
%this.setAimObject($daPlaya);
%this.setAimLocation($daPlaya.getWorldBoxCenter());
// shoooooot
//error("NPC is shooting..." SPC %this);
%rnum = getRandom()* 10;
if(%rnum >5 && %rnum < 9)
%this.fireWeapon(true);
else
%this.fireWeapon(false);
//%this.setImageTrigger(0,true);
}
else
{
//error(%this.player SPC "has no weapon/ammo!");
}
%this.setMoveDestination(%playPos); // can see the human, move to him
}
// no player in sight?
else
{
// clear aim
%this.clearAim();
// check for next nearest player
%nextClient = ClientGroup.getObject(AIPlayer::getClosestHuman(%this));
$daPlaya = %nextClient.player;
if(!isObject($daPlaya))
{
return;
}
%playPos = $daPlaya.getPosition();
//%this.setMoveDestination(%playPos); // without shooting to the human player
%this.setAimObject(%nextClient.player);
%this.setAimLocation($daPlaya.getWorldBoxCenter());
%this.fireWeapon(false);
%this.stopMove();
}
}
//--------------------------------------------------------------------
// checks if the requested object is in a certain range
// given is: bot = %this / human = %object
// return is: 0 = not in sight / 1 = in sight
//--------------------------------------------------------------------
function aiPlayer::isObjectInView(%this, %object)
{
%botPlayer = %this; // das ist der bot; %object ist der humanPlayer
// default sight range of AI:
%this.sightRange = 300.0;
if (!(isObject(%botPlayer) && isObject(%object))) return;
%objPos = %object.getWorldBoxCenter(); // player position
%eyePoint = %botPlayer.getWorldBoxCenter(); // bot position
%distance = VectorDist(%objPos,%eyePoint); // distance berechnen
//error("DISTANCE: " @ %distance);
if (%distance <= %this.sightRange) // in sichtweite ??
{
// if the object is within 1.5 meters sometimes it can
// fall out of the field of view due to the eye height
if (%distance > 2)
{
%eyeTransform = %botPlayer.getEyeTransform();
%eyePoint = firstWord(%eyeTransform)
SPC getWord(%eyeTransform, 1)
SPC getWord(%eyeTransform, 2);
}
%eyeVector = VectorNormalize(%botPlayer.getEyeVector());
//make sure we're not looking through walls...
%mask = $TypeMasks::TerrainObjectType |
$TypeMasks::InteriorObjectType |
$TypeMasks::StaticShapeObjectType;
%losResult = containerRayCast(%objPos, %eyePoint, %mask);
%losObject = GetWord(%losResult, 0);
if (!isObject(%losObject))
{
//create the vector from this client to the client
%objVector = VectorNormalize(VectorSub(%objPos, %eyePoint));
// dot product to determine field of view
%dot = VectorDot(%objVector, %eyeVector);
// within field of view
return (%dot > 0.6);
}
}
return false;
}