ironsphererpg/scripts/aiRPG.cs
Jusctsch5 a5143b67f7 T2RPG: Initial commit of ironsphererpg directory
Taking everything obtained from http://ironsphererpg2.webs.com/ and dumping it in a git repo
2015-01-18 21:06:06 -06:00

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;
}