Here's a little bit of code I whipped up that spawns a bot directly to the right of the player every time. You can also transfer CONTROL to the object. However, if you draw out a tool or something like that (anything that uses a server command instead of a trigger), the real player will do the action instead.
function servercmdSpawnBot(%cl)
{
if(!isObject(%cl) || !isObject(%cl.player))
return;
%pi = 3.1415926;
%pl = %cl.player;
%vect = %pl.getForwardVector();
%angle = mAtan(getWord(%vect, 0), getWord(%vect, 1));
%angle += %pi/2; //If you want to spawn the bot on the left side of the player, change this to %angle -= %pi/2;
%vectX = mSin(%angle);
%vectY = mCos(%angle);
%scale = mSqrt(mPow(%vectX, 2) + mPow(%vectY, 2));
%dist = 3; //Change this to be however far away from the player you want
%mod = %dist/%scale;
%vectX *= %mod;
%vectY *= %mod;
%x = getWord(%pl.position, 0) + %vectX;
%y = getWord(%pl.position, 1) + %vectY;
%z = getWord(%pl.position, 2);
%bot = new AIPlayer()
{
datablock = PlayerStandardArmor;
position = %x SPC %y SPC %z;
rotation = %pl.rotation;
};
%bot.setAimObject(%pl);
%bot.setMoveObject(%pl);
%bot.doMoveLoop(%cl);
%bot.owner = %cl;
%cl.bot[-1+%cl.bots++] = %bot;
return %bot;
}
function AIPlayer::doMoveLoop(%bot, %cl)
{
if(!isObject(%cl))
return;
%bot.schedule(50, "doMoveLoop", %cl);
if(!isObject(%cl.player) || %cl.player.getState() $= "DEAD")
{
%bot.stop();
%bot.setMoveX(0);
%bot.setMoveY(0);
%bot.setAimObject(0);
%bot.setMoveObject(0);
return;
}
%pl = %cl.player;
%respectfulDist = 10; //How far the bots follow you at.
if(vectorDist(getWords(%bot.position, 0, 1) SPC 0, getWords(%pl.position, 0, 1) SPC 0) <= %respectfulDist)
{
%bot.stop();
%bot.setMoveX(0);
%bot.setMoveY(0);
%bot.setAimObject(%pl);
}
else
{
%bot.setMoveX(0);
%bot.setMoveY(10);
%bot.setAimObject(%pl);
%bot.setMoveObject(%pl);
}
}
package spawnBot
{
function Armor::onTrigger(%data, %obj, %trig, %tog)
{
if(%trig == 4 && %tog)
{
if(isObject(%obj.client) && %obj.client.bots > 0)
{
%eye1 = %obj.getEyePoint();
%eye2 = vectorScale(vectorNormalize(%obj.getEyeVector()), 100);
%ray = containerRaycast(%eye1, %eye2, $TypeMasks::FxBrickObjectType | $TypeMasks::InteriorObjectType | $TypeMasks::PlayerObjectType, %obj);
%hit = getWord(%ray, 0);
if(isObject(%hit) && (%hit.getClassName() $= "AIPlayer" || %hit.getClassName() $= "Player"))
{
%obj.client.setControlObject(%hit);
%hit.client = %obj.client;
return;
}
}
}
Parent::onTrigger(%data, %obj, %trig, %tog);
}
function GameConnection::onClientLeaveGame(%cl)
{
for(%i=0;%i<%cl.bots;%i++)
if(isObject(%cl.bot[%i]))
%cl.bot[%i].delete();
Parent::onClientLeaveGame(%cl);
}
};
activatePackage(spawnBot);