mirror of
https://github.com/Jusctsch5/ironsphererpg.git
synced 2026-01-20 03:54:45 +00:00
Taking everything obtained from http://ironsphererpg2.webs.com/ and dumping it in a git repo
916 lines
24 KiB
C#
916 lines
24 KiB
C#
|
|
function AIConnection::onAIConnect(%client, %name, %team, %skill, %offense, %voice, %voicePitch)
|
|
{
|
|
if ($DebugMode) echo("AIConnection::onAIConnect(" @ %client @ ", " @ %name @ ", " @ %team @ ", " @ %skill @ ", " @ %offense @ ", " @ %voice @ ", " @ %voicePitch @ ")");
|
|
|
|
// Sex/Race defaults
|
|
//%client.sex = "Male";
|
|
//%client.race = "Orc";
|
|
//%client.armor = "Light";
|
|
//storedata(%client, "RACE", %client.sex @ %client.race);
|
|
|
|
//setup the voice and voicePitch
|
|
if (%voice $= "" && %name !$= "fish")
|
|
%voice = "Derm2";
|
|
%client.voice = %voice;
|
|
%client.voiceTag = addTaggedString(%voice);
|
|
|
|
if (%voicePitch $= "" || %voicePitch < 0.5 || %voicePitch > 2.0)
|
|
%voicePitch = 1.0;
|
|
%client.voicePitch = %voicePitch;
|
|
|
|
if(getRandom() > 0.5)
|
|
%client.skin = addTaggedString("basebot");
|
|
else
|
|
%client.skin = addTaggedString("basebbot");
|
|
|
|
%client.name = addTaggedString( "\cp\c9" @ %name @ "\co" );
|
|
%client.nameBase = %name;
|
|
|
|
//echo(%client.name);
|
|
//echo("CADD: " @ %client @ " " @ %client.getAddress());
|
|
//$HostGamePlayerCount++;
|
|
|
|
//setup the target for use with the sensor net, etc...
|
|
|
|
|
|
// console spam fix:
|
|
if ($DebugMode)
|
|
{
|
|
echo("calling allocclienttarget with these vars:");
|
|
echo("%client: " @ %client);
|
|
echo("%client.name: " @ %client.name);
|
|
echo("%client.voiceTag: " @ %client.voiceTag);
|
|
}
|
|
|
|
%client.target = allocClientTarget(%client, %client.name, "", %client.voiceTag, '_BOTConnection', 0, 0, %client.voicePitch);//_ClientConnection
|
|
//lets see if this removes the client from the server window =/
|
|
//messageAllExcept(%client, -1, 'MsgClientJoin', "", %name, %client, %client.target, true);
|
|
|
|
//set the initial team - Game.assignClientTeam() should be called later on...
|
|
%client.team = %team;
|
|
|
|
//assign the skill
|
|
%client.setSkillLevel(100);
|
|
//%client.displayonmasterserver = false;
|
|
//assign the affinity
|
|
%client.offense = true;
|
|
|
|
//clear any flags
|
|
%client.stop(); // this will clear the players move state
|
|
%client.clearStep();
|
|
%client.lastDamageClient = -1;
|
|
%client.lastDamageTurret = -1;
|
|
%client.setEngageTarget(-1);
|
|
%client.setTargetObject(-1);
|
|
%client.objective = "";
|
|
|
|
//clear the defaulttasks flag
|
|
%client.defaultTasksAdded = false;
|
|
|
|
//if the mission is already running, spawn the bot
|
|
if($missionRunning)
|
|
%client.startMission();
|
|
}
|
|
|
|
function AIConnection::startMission(%client)
|
|
{
|
|
if ($DebugMode) echo("AIConnection::startMission(" @ %client @ ")");
|
|
|
|
%client.matchStartReady = true;
|
|
|
|
//spawn the bot...
|
|
onAIspawn(%client);
|
|
}
|
|
|
|
function AIConnection::onAIDrop(%client)
|
|
{
|
|
if ($DebugMode) echo("AIConnection::onAIDrop(" @ %client @ ")");
|
|
|
|
//make sure we're trying to drop an AI
|
|
if(!isObject(%client) || !%client.isAIControlled())
|
|
return;
|
|
AIUnassignClient(%client);
|
|
%client.clearTasks();
|
|
%client.clearStep();
|
|
|
|
if($numAIperSpawnPoint[%client.mySpawnPoint]>0)
|
|
{
|
|
$numAIperSpawnPoint[%client.mySpawnPoint]--;
|
|
}//release the spawnpoint number
|
|
//clear the ai from any objectives, etc...
|
|
|
|
aiReleaseHumanControl(%client.controlByHuman, %client);
|
|
|
|
//kill the player, which should cause the Game object to perform whatever cleanup is required.
|
|
if(isObject(%client.player) && $missionrunning)
|
|
{
|
|
%client.player.scriptKill(0);
|
|
}
|
|
|
|
//do the nav graph cleanup
|
|
%client.missionCycleCleanup();
|
|
//%client.delete();
|
|
//RPG stuff
|
|
|
|
}
|
|
|
|
function AIConnection::endMission(%client)
|
|
{
|
|
//cancel the respawn thread, and spawn them manually
|
|
cancel(%client.respawnThread);
|
|
cancel(%client.objectiveThread);
|
|
}
|
|
|
|
function onAIspawn(%client)
|
|
{
|
|
return 0;//bleh
|
|
}
|
|
function RPGGame::onAIEnterLiquid(%game, %data, %player, %type)
|
|
{
|
|
%player.client.wet = true;
|
|
if(%player.client.targetpos)
|
|
%player.client.stepMove(%player.client.targetPos, 0, 3);
|
|
}
|
|
function RPGGame::onAILeaveLiquid(%game, %data, %player, %type)
|
|
{
|
|
%player.client.wet = false;
|
|
if(%player.client.targetpos)
|
|
%player.client.stepMove(%player.client.targetPos, 0, 3);
|
|
}
|
|
function RPGGame::onAIDoDamage(%game, %clvictim, %bot, %damagetype, %sourceobject)
|
|
{
|
|
if(!IsSameRace(%clVictim, %bot))
|
|
%bot.lastAttackCounter = %bot.AttackCounter;
|
|
}
|
|
|
|
function RPGGame::onAIDamaged(%game, %clVictim, %clAttacker, %damageType, %sourceObject)
|
|
{
|
|
|
|
if(%clVictim.isAiControlled())
|
|
StartDefendSelf(%clVictim, %clAttacker);
|
|
if(!IsSameRace(%clVictim, %clAttacker))
|
|
%clVictim.AttackCounter++;
|
|
}
|
|
|
|
function RPGGame::onAIFriendlyFire(%game, %clVictim, %clAttacker, %damageType, %sourceObject)
|
|
{
|
|
}
|
|
|
|
function RPGGame::onAIKilled(%game, %clVictim, %clKiller, %damageType, %implement)
|
|
{
|
|
if($debugMode == true)
|
|
echo("RPGGame::onAIKilled(" SPC %game SPC "," SPC %clvictim SPC "," SPC %clKiller SPC "," SPC %damagetype SPC "," SPC %implement SPC ") -aiRPG.cs");
|
|
%ai = %clVictim;
|
|
%ai.stop();
|
|
%ai.clearTasks();
|
|
%ai.clearStep();
|
|
%ai.lastDamageClient = -1;
|
|
%ai.lastDamageTurret = -1;
|
|
%ai.shouldEngage = -1;
|
|
%ai.lastAttackCounter = 0;
|
|
%ai.AttackCounter = 0;
|
|
%ai.CountStuck = 0;
|
|
%ai.setEngageTarget(-1);
|
|
%ai.setTargetObject(-1);
|
|
storedata(%ai, "guardzone", 0);
|
|
if(%ai.wandertaskid != 0)
|
|
{
|
|
%ai.wandertaskid.delete();
|
|
%ai.wandertaskid = 0;
|
|
}
|
|
if(%ai.attacktaskid != 0)
|
|
{
|
|
%ai.attacktaskid.delete();
|
|
%ai.attacktaskid = 0;
|
|
}
|
|
if(%ai.weapontaskid != 0)
|
|
{
|
|
%ai.weapontaskid.delete();
|
|
%ai.weapontaskid = 0;
|
|
}
|
|
|
|
$numAIperSpawnPoint[%clVictim.mySpawnPoint]--;
|
|
%ai.defendself = 1;
|
|
EndDefendSelf(%ai);
|
|
%ai.player = 0;
|
|
$aistack[fetchData(%ai,"SpawnIndex")].push(%ai);//push onto stack so we wont have to reconnect a NEW ai each time
|
|
return;
|
|
}
|
|
|
|
function RPGGame::onAIKilledClient(%game, %clVictim, %clAttacker, %damageType, %implement)
|
|
{
|
|
%clAttacker.setVictim(%clVictim, %clVictim.player);
|
|
%clattacker.defendself = 1;
|
|
EndDefendSelf(%clattacker);
|
|
|
|
}
|
|
|
|
function RPGGame::AIInit(%game)
|
|
{
|
|
AIInit();
|
|
}
|
|
|
|
function AIFindClosestEnemy(%srcClient, %radius, %losTimeout)
|
|
{
|
|
//see if there's an enemy near our defense location...
|
|
if (isObject(%srcClient.player))
|
|
%srcLocation = %srcClient.player.getWorldBoxCenter();
|
|
else
|
|
%srcLocation = "0 0 0";
|
|
|
|
return AIFindClosestEnemyToLoc(%srcClient, %srcLocation, %radius, %losTimeout, false, true);
|
|
}
|
|
|
|
function AIFindClosestEnemyToLoc(%srcClient, %srcLocation, %radius, %losTimeout, %ignoreLOS, %distFromClient)
|
|
{
|
|
if(%ignoreLOS $= "")
|
|
%ignoreLOS = false;
|
|
if(%distFromClient $= "")
|
|
%distFromClient = false;
|
|
|
|
%count = ClientGroup.getCount();
|
|
%closestClient = -1;
|
|
%closestDistance = 32767;
|
|
for(%i = 0; %i < %count; %i++)
|
|
{
|
|
%cl = ClientGroup.getObject(%i);
|
|
|
|
//make sure we find someone who's alive
|
|
if(AIClientIsAlive(%cl) && !IsSameRace(%cl, %srcClient))
|
|
{
|
|
//make sure we don't do extra LOS commands on players who are guaranteed to be out of LOS range
|
|
if(vectorDist(%cl.player.getPosition(), %srcLocation) <= %radius)
|
|
{
|
|
//make sure the client can see the enemy
|
|
if(%cl.sleepMode > 0)
|
|
{
|
|
%cast = containerRayCast(%cl.player.getWorldBoxCenter(), %srcClient.player.getWorldBoxCenter(), $TypeMasks::TerrainObjectType | $TypeMasks::InteriorObjectType, 0);
|
|
if(!%cast)
|
|
%hasLOS = true;
|
|
}
|
|
else
|
|
%hasLOS = %srcClient.hasLOSToClient(%cl);
|
|
|
|
if(fetchdata(%cl, "invisible"))
|
|
continue;
|
|
//%losTime = %srcClient.getClientLOSTime(%cl);
|
|
if(%haslos || %ignorelos)
|
|
{
|
|
|
|
%testPos = %cl.player.getWorldBoxCenter();
|
|
if(%distFromClient)
|
|
%distance = %srcClient.getPathDistance(%testPos);
|
|
else
|
|
%distance = AIGetPathDistance(%srcLocation, %testPos);
|
|
|
|
if(%distance > 0 && (%radius < 0 || %distance < %radius) && %distance < %closestDistance)
|
|
{
|
|
%closestClient = %cl;
|
|
%closestDistance = %distance;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return %closestClient SPC %closestDistance;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
function StartDefendSelf(%client, %attacker)
|
|
{
|
|
if(%client.hasattacktask && !IsSameRace(%client, %attacker))// client must have an attack task...
|
|
{
|
|
%client.overrideattacktask = true;//override the attack and wander tasks!
|
|
%client.overridewandertask = true;
|
|
%client.setEngageTarget(%attacker.player);
|
|
%client.setTargetObject(%attacker.player, 0, "Destroy");
|
|
%client.defendself++;
|
|
%client.currenttarget = %attacker;
|
|
%weaponrange = Game.getRange(Game.GetItem(fetchdata(%client, "weaponinhand")));
|
|
%client.stepMove(%attacker.player.getPosition(), %weaponrange , $AIModeWalk);
|
|
schedule(60*1000, %client, "EndDefendSelf", %client);
|
|
|
|
|
|
}
|
|
}
|
|
function EndDefendSelf(%client)
|
|
{
|
|
%client.defendself--;
|
|
if(%client.defendself <= 0)
|
|
{
|
|
//client hasnt been hit for over a min, cancel chase.
|
|
%client.defendself = 0;
|
|
%client.overrideattacktask = false;
|
|
%client.overridewandertask = false;
|
|
}
|
|
}
|
|
function AIRPGAttackTask::init(%task, %client)
|
|
{
|
|
%client.monitorTicker = "";
|
|
%client.attacktaskid = %task;
|
|
|
|
}
|
|
|
|
function AIRPGAttackTask::assume(%task, %client)
|
|
{
|
|
//%task.setWeightFreq(40);
|
|
%min = 40;
|
|
%max = 80;
|
|
%freq = mfloor((getRandom() * (%max - %min)) + %min);
|
|
%task.setMonitorFreq(%freq);
|
|
%client.hasattacktask = true;
|
|
}
|
|
|
|
function AIRPGAttackTask::retire(%task, %client)
|
|
{
|
|
|
|
}
|
|
|
|
function AIRPGAttackTask::weight(%task, %client)
|
|
{
|
|
%player = %client.player;
|
|
|
|
%task.setWeight(2000);
|
|
}
|
|
|
|
function AIRPGAttackTask::monitor(%task, %client)
|
|
{
|
|
%player = %client.player;
|
|
%player.attackThread = "";
|
|
|
|
|
|
|
|
%losrange = 40;
|
|
%afce = AIFindClosestEnemy(%client, %losrange, 15000);
|
|
|
|
%targetId = firstWord(%afce);
|
|
%targetDist = GetWord(%afce, 1);
|
|
|
|
if(%targetId !$= -1)
|
|
{
|
|
%client.lastTimeSpotEnemy = getTime();
|
|
|
|
//time to do a check for the bots in guard mode
|
|
if(fetchdata(%client, "attb") == 1)
|
|
{
|
|
|
|
if( fetchdata(%client, "guardzone") !$= fetchdata(%targetid, "zone") )
|
|
{
|
|
%targetid = -1;
|
|
}
|
|
}
|
|
}
|
|
if(%client.overrideattacktask && %client.currenttarget > 0)
|
|
{
|
|
|
|
%targetid = %client.currenttarget;
|
|
|
|
}
|
|
|
|
|
|
%clientPos = %client.player.getPosition();
|
|
%wrange = Game.GetRange(%client, fetchData(%client, "weaponInHand"));
|
|
%wdelay = Game.GetDelay(%client, fetchData(%client, "weaponInHand"));
|
|
|
|
%tolerance = %wrange;
|
|
|
|
|
|
if(%targetId !$= -1 && isobject(%targetid.player))
|
|
%targetPos = %targetId.player.getPosition();
|
|
else
|
|
%targetPos = -1;
|
|
|
|
//if targetId is -1, it will cancel these tasks out
|
|
%client.setEngageTarget(%targetId.player);
|
|
%client.setTargetObject(%targetId.player, 0, "Destroy");
|
|
%itemid = fetchdata(%client, "weaponinhand");
|
|
%dt = $ItemDamageType[Game.getItem(%client, %itemId)];
|
|
if(%client.trapped)
|
|
%wrange *= 5;
|
|
//check if using magic as a main way of attacking
|
|
if(%targetId !$= -1)
|
|
{
|
|
|
|
if(!fetchdata(%client, "magic"))
|
|
{
|
|
%weapon = (%client.player.getMountedImage($WeaponSlot) == 0) ? "" : %client.player.getMountedImage($WeaponSlot);
|
|
%ammo = $itemAmmo[Game.getItem(%itemid)];
|
|
if(%dt == $DamageType::Archery)
|
|
{
|
|
%ammo = $itemAmmo[Game.getItem(%itemid)];
|
|
if(%client.invcount[%ammo] <= 0)
|
|
serverCmdCycleWeapon(%client, "next");//no ammo switch weapon again.
|
|
%wrange = %wrange / 3;
|
|
}
|
|
//if( %targetDist <= %wrange && (%client.lastfire +%wdelay < getSimTime()))
|
|
//{
|
|
// schedule(250,0,"doaifire", %weapon, %player);
|
|
// %client.lastfire = getSimTime();
|
|
//}
|
|
//randomize target position by tolerance (%wrange).
|
|
|
|
|
|
%targetpos = (GetWord(%targetPos, 0) + %wrange * (getrandom()-0.5)) SPC (GetWord(%targetPos, 1) + %wrange * (getrandom()-0.5)) SPC (GetWord(%targetPos, 2) + %wrange * (getrandom()-0.5));
|
|
|
|
%hd = GetWord(%targetpos, 2) - GetWord(%client.player.getposition(), 2);
|
|
if(%targetid.player)
|
|
{
|
|
%vel = %targetid.player.getVelocity();
|
|
%targetpos = vectoradd(%targetpos, %vel);//should make better bots when chasing.
|
|
}
|
|
if(%client.wet)
|
|
{
|
|
%nvec = VectorSub( %targetid.player.getPosition(), %client.player.getPosition()) ;
|
|
|
|
%targetpos = VectorAdd(%nvec, VectorAdd(%nvec, %targetpos));
|
|
}
|
|
|
|
|
|
if(%client.trapped)
|
|
%mode = $AIModeExpress;
|
|
else if (%client.wet)
|
|
if(%hd > 15)
|
|
%mode = $AIModeGainHeight;
|
|
else
|
|
%mode = $AiModeExpress;
|
|
else
|
|
%mode = $AIModeWalk;
|
|
if(%client.trapped)
|
|
{
|
|
if(getRandom(0,1))
|
|
%targetpos = %client.player.getPosition();
|
|
}
|
|
|
|
%client.stepMove(%targetPos, 0, %mode);
|
|
%client.targetpos = %targetpos;
|
|
%client.overridewandertask = true;
|
|
%client.countStuck = 2;//backup for one step and pounce back. should be better.
|
|
%client.trapped = false;
|
|
}
|
|
else
|
|
{
|
|
//see if you have LOS to the target... if los is aquired FIRE else move
|
|
|
|
%client.overridewandertask = true;
|
|
%haslos = newhasLOStoclient(%client, %targetid);
|
|
|
|
if(%haslos)
|
|
{
|
|
//allowed spells for bots
|
|
%spell[1] = "thorn";
|
|
%spell[2] = "fireball";
|
|
%spell[3] = "icespike";
|
|
%spell[4] = "icestorm";
|
|
%spell[5] = "spikes";
|
|
%spell[6] = "melt";
|
|
%spell[7] = "cloud";
|
|
%spell[8] = "powercloud";
|
|
%spell[9] = "beam";
|
|
%spell[10] = "hellstorm";
|
|
%spell[11] = "snowstorm";
|
|
%spell[12] = "dimensionrift";
|
|
%spell[13] = "ironfist";
|
|
for(%i = 0; %i < 3; %i++)
|
|
{
|
|
%d = getRandom(1,10);
|
|
%spell = %spell[%d];
|
|
if(SkillCanUse(%client, %spell))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if(!SkillCanUse(%client, %spell)) %spell = "thorn";
|
|
//FIRE!
|
|
RPGchat(%client, 0, "#cast " @ %spell);
|
|
%client.stepmove(%targetpos, 30, $AIModeExpress);
|
|
}
|
|
else
|
|
{
|
|
%hd = GetWord(%targetpos, 2) - GetWord(%client.player.getposition(), 2);
|
|
if(%client.trapped)
|
|
%mode = $AIModeExpress;
|
|
else if (%client.wet)
|
|
if(%hd > 15)
|
|
%mode = $AIModeGainHeight;
|
|
else
|
|
%mode = $AiModeExpress;
|
|
else
|
|
%mode = $AIModeWalk;
|
|
if(%client.trapped)
|
|
{
|
|
if(getRandom(0,4))
|
|
%targetpos = %client.player.getPosition();
|
|
}
|
|
%targetpos = (GetWord(%targetPos, 0) + %wrange * (getrandom()-0.5)) SPC (GetWord(%targetPos, 1) + %wrange * (getrandom()-0.5)) SPC (GetWord(%targetPos, 2) + %wrange * (getrandom()-0.5));
|
|
|
|
%client.stepmove(%targetpos, 0, %mode);//walk but keep distance!
|
|
%client.targetpos = %targetpos;
|
|
}
|
|
|
|
}
|
|
|
|
//are we hitting our target????
|
|
if(%client.lastAttackCounter >= %client.AttackCounter && %client.checkCounter >= %client.attackCounter)
|
|
{
|
|
// yes
|
|
|
|
%client.countStuck = 0;
|
|
%client.trapped = false;
|
|
}
|
|
else
|
|
{
|
|
%client.checkCounter = %client.attackCounter;
|
|
%client.countStuck++;
|
|
}
|
|
if(%client.countStuck > 2)
|
|
{
|
|
//echo(%client SPC "IS TRAPPED!!!" SPC %client.namebase);
|
|
%client.trapped = true;
|
|
%client.trappcounter++;
|
|
if(%client.trappcounter > 10)
|
|
%client.lastAttackCounter = %client.attackCounter;//break the running around like a madman.
|
|
}
|
|
}
|
|
else
|
|
if(!%client.overrideattacktask)
|
|
%client.overridewandertask = false;
|
|
|
|
|
|
%client.lastPos = %clientPos;
|
|
}
|
|
function doaifire(%weapon,%player)
|
|
{
|
|
|
|
ShapeBaseImageData::onFire(%weapon, %player, $weaponslot);
|
|
|
|
}
|
|
|
|
//----
|
|
function AIRPGWanderTask::init(%task, %client)
|
|
{
|
|
%client.wandertaskid = %task;
|
|
}
|
|
|
|
function AIRPGWanderTask::assume(%task, %client)
|
|
{
|
|
%client.lastStuckPos = %client.player.getPosition();
|
|
|
|
%min = 50;
|
|
%max = 120;
|
|
%freq = mfloor((getRandom() * (%max - %min)) + %min);
|
|
|
|
%task.setWeightFreq(%freq);
|
|
}
|
|
|
|
function AIRPGWanderTask::retire(%task, %client)
|
|
{
|
|
%client.stepIdle();
|
|
}
|
|
|
|
function AIRPGWanderTask::monitor(%task, %client)
|
|
{
|
|
%player = %client.player;
|
|
|
|
%task.setWeight(900);
|
|
}
|
|
|
|
function AIRPGWanderTask::weight(%task, %client)
|
|
{
|
|
if(!shouldAIBeAt(%client.player.position))
|
|
{
|
|
if(%client.despawntime == 0)
|
|
%client.despawntime = getSimTime() + 30000;
|
|
|
|
if(getSimTime() > %client.despawntime)
|
|
{
|
|
%client.deSpawn();
|
|
}
|
|
}
|
|
else
|
|
%client.despawntime = 0;
|
|
|
|
if(%client.overridewandertask == true)
|
|
return; //overridden for now. This should result in smarter bots.
|
|
%player = %client.player;
|
|
|
|
if(%client.getEngageTarget() != -1)
|
|
return;
|
|
|
|
%clientPos = %client.player.getPosition();
|
|
|
|
//until i figure out more of this AI, use the stepEngage line if you want the bot to avoid the player,
|
|
//or use the stepMove line to make the bot attack the player head-on. Make sure that the skill
|
|
//level is set to 10 in order for the bots to turn fast enough.
|
|
|
|
//something to think about: once i can get AI to damage others, then it would be a good idea to keep the last
|
|
//time of damage, and if the bot sticks around a player without getting any damage thru to its target for too
|
|
//long, then make the bot run away somewhere else.
|
|
|
|
%minrad = 5;
|
|
%maxrad = 30;
|
|
|
|
%tolerance = %maxrad;
|
|
|
|
%m = VectorDist(%clientPos, %client.lastPos);
|
|
if(%m <= 0.4)
|
|
{
|
|
//the bot might be stuck against something, take proper action
|
|
|
|
|
|
|
|
if(%client.stuckCounter $= "")
|
|
{
|
|
%distTravelled = vectorDist(%client.player.getPosition(), %client.lastStuckPos);
|
|
|
|
|
|
|
|
%client.stuckCounter = 0;
|
|
%min = Cap(mfloor(%distTravelled / 40), 1, 500);
|
|
%max = %min + 5;
|
|
%client.stuckCounterLimit = mfloor(getRandom() * (%max - %min)) + %min + 1;
|
|
|
|
|
|
|
|
%client.stepIdle(%clientPos);
|
|
%client.stepName = "";
|
|
%client.stepPos = "";
|
|
}
|
|
|
|
%client.stuckCounter++;
|
|
|
|
if(%client.stuckCounter >= %client.stuckCounterLimit)
|
|
{
|
|
|
|
//max out tolerance
|
|
%tolerance = 99999;
|
|
|
|
//make sure the other conditions aren't blocked by the 2 second jumping around thing
|
|
cancel(%client.TSEsched);
|
|
%client.TempStepEngage = "";
|
|
|
|
//stop idling the bot
|
|
%client.clearStep();
|
|
|
|
%client.lastStuckPos = %client.player.getPosition();
|
|
|
|
%client.stuckCounter = "";
|
|
}
|
|
}
|
|
|
|
if(!%client.TempStepEngage)
|
|
{
|
|
%movePos = -1;
|
|
%stepname = %client.getStepName();
|
|
%stepstatus = %client.getStepStatus();
|
|
if(%stepname $= "NONE" && %client.stepName $= "stepMove")
|
|
{
|
|
//limitation to getStepName involving stepMove, workaround follows:
|
|
%stepname = "AIStepMove";
|
|
if(VectorDist(%clientPos, %client.stepNamePos) <= %tolerance)
|
|
{
|
|
%stepname = "NONE";
|
|
%stepstatus = "Finished";
|
|
%client.stepName = "";
|
|
%client.stepPos = "";
|
|
}
|
|
else
|
|
%stepstatus = "InProgress";
|
|
}
|
|
|
|
if(%stepstatus !$= "InProgress")
|
|
{
|
|
|
|
//Select a random InteriorInstance, and go towards it
|
|
//%interiorId = selectRandomObjectWithRaceID("MissionGroup/Interiors", $RaceID[fetchData(%client, "RACE")]);
|
|
//%originalPos = %interiorId.position;
|
|
|
|
%originalPos = %client.player.getPosition();
|
|
%r = 0;
|
|
for(%i = 0; $ai::attackPos[$aiattack[%client], %i] !$= ""; %i++)
|
|
{
|
|
%d++;
|
|
}
|
|
if(%d != 0)
|
|
%r = %d*getRandom() % %d;
|
|
if(%r < 0) %r = 0;
|
|
if($Ai::AttackPos[$aiAttack[%client],%r] !$="")
|
|
%originalPos = $Ai::AttackPos[$aiAttack[%client],%r];
|
|
|
|
%p = randomPositionXY(%minrad, %maxrad);
|
|
%x = firstWord(%p);
|
|
%y = GetWord(%p, 1);
|
|
%ox = firstWord(%originalPos);
|
|
%oy = GetWord(%originalPos, 1);
|
|
%oxx = %ox + %x;
|
|
%oyy = %oy + %y;
|
|
%ozz = getTerrainHeight(%oxx @ " " @ %oyy @ " 0");
|
|
|
|
%movePos = %oxx @ " " @ %oyy @ " " @ %ozz;
|
|
if(getRpgRoll("1r3") == 1 )
|
|
%moveMode = $AIModeWalk;
|
|
else
|
|
%movemode = $AIModeExpress;
|
|
|
|
}
|
|
else if(%stepname $= "AIStepIdlePatrol")
|
|
{
|
|
//no need to make the bot do a stepMove, a stepIdle has already been issued
|
|
%movePos = -1;
|
|
}
|
|
else
|
|
{
|
|
|
|
%movePos = %client.stepPos;
|
|
%moveMode = $AIModeWalk;
|
|
}
|
|
|
|
if(%movePos !$= -1)
|
|
{
|
|
%client.stepMove(%movePos, %tolerance, %moveMode);
|
|
//%client.setPath(%movePos);
|
|
|
|
//getStepName doesn't recognize stepMove (stupid limitation?? dunno)
|
|
//workaround follows: (which turns out to be more powerful because I can determine position)
|
|
%client.stepName = "stepMove";
|
|
%client.stepPos = %movePos;
|
|
}
|
|
}
|
|
|
|
%client.lastPos = %clientPos;
|
|
}
|
|
function RPGGame::clearTempStepEngage(%game, %client)
|
|
{
|
|
%client.TempStepEngage = "";
|
|
}
|
|
|
|
//----
|
|
function AIRPGSelectWeaponTask::init(%task, %client)
|
|
{
|
|
%client.weapontaskid = %task;
|
|
}
|
|
|
|
function AIRPGSelectWeaponTask::assume(%task, %client)
|
|
{
|
|
%task.setWeightFreq(100);
|
|
}
|
|
|
|
function AIRPGSelectWeaponTask::retire(%task, %client)
|
|
{
|
|
}
|
|
|
|
function AIRPGSelectWeaponTask::monitor(%task, %client)
|
|
{
|
|
%player = %client.player;
|
|
|
|
%task.setWeight(900);
|
|
}
|
|
|
|
function AIRPGSelectWeaponTask::weight(%task, %client)
|
|
{
|
|
%player = %client.player;
|
|
|
|
%task.selectWeaponTaskTicker++;
|
|
|
|
if(%task.selectWeaponTaskTicker > %task.selectWeaponTaskLimit)
|
|
{
|
|
%min = 20;
|
|
%max = 150;
|
|
%nlimit = mfloor((getRandom() * (%max - %min)) + %min);
|
|
%task.selectWeaponTaskLimit = %nlimit;
|
|
%task.selectWeaponTaskTicker = 0;
|
|
|
|
//serverCmdCycleWeapon(%client, "next");//need to change this so the bots discard useless items..
|
|
Game.ShapeBasecycleWeapon(%client.player, "next");
|
|
%itemid = fetchdata(%client, "weaponinhand");
|
|
|
|
if(%itemid == 0)
|
|
{
|
|
Game.ShapeBasecycleWeapon(%client.player, "next");
|
|
%itemid = fetchdata(%client, "weaponinhand");
|
|
|
|
}
|
|
if($ItemDamageType[Game.getItem(%client, %itemId)] == $DamageType::Archery)
|
|
{
|
|
%ammo = $itemAmmo[Game.getItem(%client, %itemid)];
|
|
if(%client.data.invcount[%ammo, 3, 1] <= 0)
|
|
Game.ShapeBasecycleWeapon(%client.player, "next");//no ammo switch weapon again.
|
|
}
|
|
}
|
|
}
|
|
function AIRPGFishWanderTask::init(%task, %client)
|
|
{
|
|
%client.wandertaskid = %task;
|
|
}
|
|
|
|
function AIRPGFishWanderTask::assume(%task, %client)
|
|
{
|
|
%client.lastStuckPos = %client.player.getPosition();
|
|
|
|
%min = 50;
|
|
%max = 120;
|
|
%freq = mfloor((getRandom() * (%max - %min)) + %min);
|
|
|
|
%task.setWeightFreq(%freq/2);
|
|
}
|
|
|
|
function AIRPGFishWanderTask::retire(%task, %client)
|
|
{
|
|
}
|
|
|
|
function AIRPGFishWanderTask::monitor(%task, %client)
|
|
{
|
|
//%player = %client.player;
|
|
|
|
%task.setWeight(600);
|
|
}
|
|
|
|
function AIRPGFishWanderTask::weight(%task, %client)
|
|
{
|
|
%player = %client.player;
|
|
if(!isobject(%client.player))
|
|
{
|
|
if ($DebugMode) echo("ERROR: Task should not have been called - aiRPG.cs AIRPGFishWanderTask Client:" SPC %client SPC " Playerid:" SPC %client.player SPC "Task:" SPC %task);
|
|
//%task.delete();
|
|
return;
|
|
}
|
|
if(%client.getEngageTarget() !$= -1)
|
|
return;
|
|
|
|
%clientPos = %client.player.getPosition();
|
|
|
|
//until i figure out more of this AI, use the stepEngage line if you want the bot to avoid the player,
|
|
//or use the stepMove line to make the bot attack the player head-on. Make sure that the skill
|
|
//level is set to 10 in order for the bots to turn fast enough.
|
|
|
|
|
|
%minrad = -50;
|
|
%maxrad = 50;
|
|
|
|
%tolerance = %maxrad;
|
|
%stuck = false;
|
|
%m = VectorDist(%clientPos, %client.lastPos);
|
|
%d = VectorDist(%clientPos, %client.stepPos);
|
|
if(%m <= 0.5 && %d > 1.5 )
|
|
{
|
|
%unstuckpos = getword(%clientPos, 0)+(getword(%clientPos, 0) - getWord(%client.stepPos, 0)) SPC getword(%clientPos, 1)+(getword(%clientPos, 1) - getWord(%client.stepPos, 1)) SPC getword(%clientPos, 2)+(getword(%clientPos, 2) - getWord(%client.stepPos, 2));
|
|
%stuck = true;
|
|
%client.stuckcounter++;
|
|
if(%client.stuckcounter > 2)
|
|
{
|
|
%unstuckpos = "";
|
|
//if(%client.stuckcounter > 30)
|
|
// %client.player.scriptkill($damagetype::suicide);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
%client.unstuckpos = "";
|
|
%client.stuckcounter = 0;
|
|
}
|
|
|
|
%movePos = -1;
|
|
%stepname = %client.getStepName();
|
|
%stepstatus = "none";
|
|
|
|
|
|
%originalPos = %clientPos;
|
|
if($Ai::AttackPos[$aiAttack[%client],0] !$="")
|
|
%originalPos = $Ai::AttackPos[$aiAttack[%client],0];
|
|
if(%stuck)
|
|
{
|
|
%originalPos = %unstuckPos;
|
|
}
|
|
%p = randomPositionXY(%minrad, %maxrad);
|
|
%x = firstWord(%p);
|
|
%y = GetWord(%p, 1);
|
|
%ox = firstWord(%originalPos);
|
|
%oy = GetWord(%originalPos, 1);
|
|
%oxx = %ox + %x;
|
|
%oyy = %oy + %y;
|
|
%ozz = getTerrainHeight(%oxx @ " " @ %oyy @ " 0");
|
|
%movePos = %oxx @ " " @ %oyy @ " " @ %ozz +5;
|
|
if(getRpgRoll("1r5") == 1 )
|
|
%moveMode = $AIModeGainHeight;
|
|
else
|
|
%movemode = $AIModeExpress;
|
|
if(%movePos !$= -1)
|
|
{
|
|
%client.stepMove(%movePos, %tolerance, %moveMode);
|
|
//%client.setPath(%movePos);
|
|
|
|
//getStepName doesn't recognize stepMove (stupid limitation?? dunno)
|
|
//workaround follows: (which turns out to be more powerful because I can determine position)
|
|
%client.stepName = "stepMove";
|
|
%client.tempmovemode = %moveMode;
|
|
if(!%stuck)
|
|
%client.stepPos = %movePos;
|
|
}
|
|
|
|
|
|
%client.lastPos = %clientPos;
|
|
}
|