mirror of
https://github.com/SWG-Source/dsrc.git
synced 2026-07-13 22:01:04 -04:00
1305 lines
48 KiB
Java
Executable File
1305 lines
48 KiB
Java
Executable File
package script.ai;
|
|
|
|
import script.*;
|
|
import script.base_class.*;
|
|
import script.combat_engine.*;
|
|
import java.util.Arrays;
|
|
import java.util.Hashtable;
|
|
import java.util.Vector;
|
|
import script.base_script;
|
|
|
|
import script.ai.ai_aggro;
|
|
import script.ai.ai_combat;
|
|
import script.ai.ai_combat_assist;
|
|
import script.ai.ai_combat_damage;
|
|
import script.ai.ai_combat_movement;
|
|
import script.ai.ai_combat_target;
|
|
import script.library.ai_lib;
|
|
import script.library.beast_lib;
|
|
import script.library.buff;
|
|
import script.library.colors;
|
|
import script.library.combat;
|
|
import script.library.combat_consts;
|
|
import script.library.factions;
|
|
import script.library.instance;
|
|
import script.library.movement;
|
|
import script.library.pclib;
|
|
import script.library.pet_lib;
|
|
import script.library.posture;
|
|
import script.library.scout;
|
|
import script.library.stealth;
|
|
import script.library.storyteller;
|
|
import script.library.sui;
|
|
import script.library.trial;
|
|
import script.library.utils;
|
|
import script.library.xp;
|
|
import script.library.stealth;
|
|
|
|
public class creature_combat extends script.systems.combat.combat_base
|
|
{
|
|
public creature_combat()
|
|
{
|
|
}
|
|
public static final float MIN_MOVEMENT_DURING_COMBAT = 0.015f;
|
|
public static final float MAX_MOVEMENT_DURING_COMBAT = 0.05f;
|
|
public static final float TOO_CLOSE_DISTANCE = 3f;
|
|
public void clog(String text) throws InterruptedException
|
|
{
|
|
if (text != null)
|
|
{
|
|
LOGC(aiLoggingEnabled(getSelf()), "debug_ai", "creature_combat::" + text);
|
|
}
|
|
}
|
|
public int OnEnteredCombat(obj_id self) throws InterruptedException
|
|
{
|
|
clog("OnEnteredCombat() ----- unit(" + self + ":" + getName(self) + ")");
|
|
clearCombatActions();
|
|
if (!stealth.isDecoy(self))
|
|
{
|
|
aiEquipPrimaryWeapon(self);
|
|
}
|
|
removeTriggerVolume(ai_lib.ALERT_VOLUME_NAME);
|
|
removeTriggerVolume(ai_lib.AGGRO_VOLUME_NAME);
|
|
ai_combat_movement.aiClearMoveMode();
|
|
setMovementRun(self);
|
|
deltadictionary dict = self.getScriptVars();
|
|
dict.put("ai.combat.cover.foundTarget", isPlayer(getHateTarget(self)) ? false : true);
|
|
if (ai_combat_assist.isWaiting())
|
|
{
|
|
ai_combat_movement.aiIdle();
|
|
}
|
|
else
|
|
{
|
|
obj_id target = getHateTarget(self);
|
|
boolean targetCovered = stealth.hasInvisibleBuff(target);
|
|
boolean targetProne = posture.isProne(target);
|
|
if (targetCovered || targetProne)
|
|
{
|
|
showFlyText(self, new string_id("npc_reaction/flytext", "alert"), 2.0f, colors.STEELBLUE);
|
|
}
|
|
utils.setScriptVar(self, "creature_combat.lastCombatFrame", getGameTime());
|
|
if (ai_combat_assist.canCallForAssist())
|
|
{
|
|
ai_combat_assist.callForAssist();
|
|
}
|
|
if (beast_lib.isBeast(self) && getState(self, STATE_COVER) == 1)
|
|
{
|
|
stealth.makeCreatureVisible(self);
|
|
}
|
|
doCombatFrame();
|
|
}
|
|
messageTo(self, "checkForBeastSpecialsTakeOne", null, 1.0f, false);
|
|
setRegenRate(self, HEALTH, 0);
|
|
if (!beast_lib.isBeast(self))
|
|
{
|
|
setRegenRate(self, ACTION, 20);
|
|
}
|
|
else
|
|
{
|
|
int actionRegen = 4;
|
|
obj_id master = getMaster(self);
|
|
int expertiseRegen = 0;
|
|
if (isIdValid(master) && exists(master))
|
|
{
|
|
expertiseRegen = getEnhancedSkillStatisticModifierUncapped(master, "expertise_bm_pet_regen");
|
|
}
|
|
if (expertiseRegen > 0)
|
|
{
|
|
actionRegen += (int)((float)actionRegen * ((float)expertiseRegen / 100.0f));
|
|
}
|
|
setRegenRate(self, ACTION, actionRegen);
|
|
}
|
|
if (combat.isPersistCombatMode(self))
|
|
{
|
|
messageTo(self, "persist_combat", trial.getSessionDict(self, combat.PERSIST_COMBAT), 5.0f, false);
|
|
}
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public int OnExitedCombat(obj_id self) throws InterruptedException
|
|
{
|
|
if (!isIdValid(self) || !exists(self))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
clog("OnExitedCombat() ----- unit(" + self + ":" + getName(self) + ")");
|
|
ai_combat_target.clearTargetList();
|
|
ai_combat_damage.clearAttackerList();
|
|
ai_combat_movement.aiClearMoveMode();
|
|
ai_combat_assist.clearNoAssistCall();
|
|
setLookAtTarget(self, null);
|
|
utils.removeScriptVarTree(self, "me_evasion");
|
|
if (!beast_lib.isBeast(self))
|
|
{
|
|
ai_lib.resetCombatTriggerVolumes();
|
|
float healthRegenMod = hasObjVar(self, "regen_mod.health") ? getFloatObjVar(self, "regen_mod.health") : 1.0f;
|
|
float actionRegenMod = hasObjVar(self, "regen_mod.action") ? getFloatObjVar(self, "regen_mod.action") : 1.0f;
|
|
float healthRegen = (getMaxAttrib(self, HEALTH) / 10.0f) * healthRegenMod;
|
|
float actionRegen = (getMaxAttrib(self, ACTION) / 10.0f) * actionRegenMod;
|
|
setRegenRate(self, HEALTH, (int)healthRegen);
|
|
setRegenRate(self, ACTION, (int)actionRegen);
|
|
}
|
|
else
|
|
{
|
|
int healthRegen = 150;
|
|
int actionRegen = 10;
|
|
obj_id master = getMaster(self);
|
|
int expertiseRegen = 0;
|
|
if (isIdValid(master) && exists(master))
|
|
{
|
|
expertiseRegen = getEnhancedSkillStatisticModifierUncapped(master, "expertise_bm_pet_regen");
|
|
}
|
|
if (expertiseRegen > 0)
|
|
{
|
|
actionRegen += (int)((float)actionRegen * ((float)expertiseRegen / 100.0f));
|
|
healthRegen += (int)((float)healthRegen * ((float)expertiseRegen / 100.0f));
|
|
}
|
|
setRegenRate(self, HEALTH, healthRegen);
|
|
setRegenRate(self, ACTION, actionRegen);
|
|
if (stealth.canBeastStealth(self))
|
|
{
|
|
stealth.makeBeastInvisible(getMaster(self), "appearance/pt_smoke_puff.prt");
|
|
}
|
|
}
|
|
if (!ai_lib.isAiDead(self))
|
|
{
|
|
if (posture.isKnockedDown(self))
|
|
{
|
|
queueCommand(self, (-1322133240), self, "", COMMAND_PRIORITY_DEFAULT);
|
|
}
|
|
else if (!posture.isStanding(self))
|
|
{
|
|
posture.stand(self);
|
|
}
|
|
if (!beast_lib.isBeast(self))
|
|
{
|
|
if (pet_lib.isPet(self))
|
|
{
|
|
messageTo(self, "postCombatPathHome", null, 1, false);
|
|
}
|
|
else
|
|
{
|
|
if (!hasObjVar(self, "forceNoMovement"))
|
|
{
|
|
aiTether(self);
|
|
}
|
|
else
|
|
{
|
|
cleanupForTether(self);
|
|
pathTo(self, aiGetHomeLocation(self));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
bumpSession(self);
|
|
trial.bumpSession(self, combat.PERSIST_COMBAT);
|
|
messageTo(self, "ai_assist_check", null, 0.25f, false);
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public int ai_assist_check(obj_id self, dictionary params) throws InterruptedException
|
|
{
|
|
if (!isIdValid(self) || !exists(self))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
ai_combat_assist.callForAssist();
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public void cleanupForTether(obj_id self) throws InterruptedException
|
|
{
|
|
if (!isIdValid(self) || !exists(self))
|
|
{
|
|
return;
|
|
}
|
|
ai_lib.setMood(self, ai_lib.MOOD_CALM);
|
|
ai_lib.clearCombatData();
|
|
xp.cleanupCreditForKills();
|
|
}
|
|
public int OnAiTetherStart(obj_id self) throws InterruptedException
|
|
{
|
|
if (!isIdValid(self) || !exists(self))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
cleanupForTether(self);
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public int OnAiTetherComplete(obj_id self) throws InterruptedException
|
|
{
|
|
clog("ai::OnAiTetherComplete() --- BEGIN --- self(" + self + ":" + getName(self) + ")");
|
|
ai_lib.resetAi();
|
|
clog("ai::OnAiTetherComplete() --- END --- self(" + self + ":" + getName(self) + ")");
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public int OnHateTargetChanged(obj_id self, obj_id target) throws InterruptedException
|
|
{
|
|
clog("OnHateTargetChanged() self(" + self + ":" + getName(self) + ") target(" + target + ")");
|
|
setLookAtTarget(self, target);
|
|
if (ai_lib.isInCombat(self))
|
|
{
|
|
ai_combat_assist.clearAssist();
|
|
}
|
|
if (pet_lib.isPet(self) && utils.hasScriptVar(self, "ai.combat.target"))
|
|
{
|
|
obj_id combatTarget = utils.getObjIdScriptVar(self, "ai.combat.target");
|
|
if (target != combatTarget)
|
|
{
|
|
float maxHate = getMaxHate(self);
|
|
setHate(self, combatTarget, maxHate + 5000);
|
|
}
|
|
}
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public int OnHateTargetAdded(obj_id self, obj_id target) throws InterruptedException
|
|
{
|
|
clog("creature_combat::OnHateTargetAdded() self(" + self + ":" + getName(self) + ") target(" + target + ")");
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public int OnHateTargetRemoved(obj_id self, obj_id target) throws InterruptedException
|
|
{
|
|
clog("creature_combat::OnHateTargetRemoved() self(" + self + ":" + getName(self) + ") target(" + target + ")");
|
|
if (!isIdValid(target) || !exists(target))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
final int factionStatus = factions.getFactionStatus(self, target);
|
|
if (factionStatus == factions.STATUS_FRIEND || (factionStatus == factions.STATUS_NEUTRAL && !aiIsAggressive(self)))
|
|
{
|
|
if (hasScript(self, "systems.missions.dynamic.mission_bounty_target"))
|
|
{
|
|
obj_id objHunter = getObjIdObjVar(self, "objHunter");
|
|
if (!isIdValid(objHunter) || (objHunter != target))
|
|
{
|
|
pvpRemovePersonalEnemyFlags(self, target);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pvpRemovePersonalEnemyFlags(self, target);
|
|
}
|
|
}
|
|
if (pet_lib.isPet(self) && utils.hasScriptVar(self, "ai.combat.target"))
|
|
{
|
|
obj_id combatTarget = utils.getObjIdScriptVar(self, "ai.combat.target");
|
|
if (target == combatTarget)
|
|
{
|
|
utils.removeScriptVar(self, "ai.combat.target");
|
|
}
|
|
}
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public int OnAiPrimaryWeaponEquipped(obj_id self, obj_id primaryWeapon) throws InterruptedException
|
|
{
|
|
clog("OnAiPrimaryWeaponEquipped() ai(" + self + ") primaryWeapon(" + primaryWeapon + ")");
|
|
clearCombatActions();
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public int OnAiSecondaryWeaponEquipped(obj_id self, obj_id secondaryWeapon) throws InterruptedException
|
|
{
|
|
clog("OnAiSecondaryWeaponEquipped() ai(" + self + ") secondaryWeapon(" + secondaryWeapon + ")");
|
|
clearCombatActions();
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public int OnAddedToWorld(obj_id self) throws InterruptedException
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public int OnAiCombatFrame(obj_id self) throws InterruptedException
|
|
{
|
|
boolean assistWaiting = ai_combat_assist.isWaiting();
|
|
if (assistWaiting || getSkillStatisticModifier(self, "stifle") > 0)
|
|
{
|
|
final obj_id hateTarget = getHateTarget(self);
|
|
faceTo(self, hateTarget);
|
|
if (getCombatDuration(self) > ai_combat_assist.getWaitTime())
|
|
{
|
|
ai_combat_assist.clearAssist();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
doCombatFrame();
|
|
}
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public void doCombatFrame() throws InterruptedException
|
|
{
|
|
final obj_id self = getSelf();
|
|
final obj_id target = getBestTarget(self);
|
|
int lastFrame = utils.getIntScriptVar(self, "creature_combat.lastCombatFrame");
|
|
utils.setScriptVar(self, "creature_combat.lastCombatFrame", getGameTime());
|
|
if (getState(self, STATE_COVER) == 1)
|
|
{
|
|
stealth.makeCreatureVisible(self);
|
|
}
|
|
if (utils.hasScriptVar(self, "petIgnoreAttacks"))
|
|
{
|
|
return;
|
|
}
|
|
if (!isIdValid(target))
|
|
{
|
|
obj_id[] haters = getHateList(self);
|
|
if (haters != null && haters.length > 0 && !utils.hasScriptVar(self, "hateListRetry"))
|
|
{
|
|
Vector goodIds = new Vector();
|
|
goodIds.setSize(0);
|
|
for (int i = 0; i < haters.length; ++i)
|
|
{
|
|
if (isIdValid(haters[i]) && exists(haters[i]))
|
|
{
|
|
utils.addElement(goodIds, haters[i]);
|
|
}
|
|
}
|
|
if (goodIds != null & goodIds.size() > 0)
|
|
{
|
|
int targetIndex = rand(0, goodIds.size() - 1);
|
|
forceHateTarget(self, ((obj_id)goodIds.get(targetIndex)));
|
|
utils.setScriptVar(self, "hateListRetry", 1);
|
|
doCombatFrame();
|
|
}
|
|
}
|
|
if (utils.hasScriptVar(self, "hateListRetry"))
|
|
{
|
|
utils.removeScriptVar(self, "hateListRetry");
|
|
}
|
|
if (beast_lib.isBeast(self))
|
|
{
|
|
obj_id master = getMaster(self);
|
|
if (isIdValid(master) && master.isLoaded())
|
|
{
|
|
beast_lib.beastFollowTarget(self, master);
|
|
}
|
|
else
|
|
{
|
|
aiSetHomeLocation(self, getLocation(self));
|
|
}
|
|
return;
|
|
}
|
|
if (pet_lib.isPet(self))
|
|
{
|
|
messageTo(self, "postCombatPathHome", null, 1, false);
|
|
return;
|
|
}
|
|
if (!hasObjVar(self, "forceNoMovement"))
|
|
{
|
|
aiTether(self);
|
|
}
|
|
else
|
|
{
|
|
cleanupForTether(self);
|
|
pathTo(self, aiGetHomeLocation(self));
|
|
}
|
|
return;
|
|
}
|
|
boolean checkVE = isIdValid(target) && exists(target) && isIdValid(self) && exists(self);
|
|
if (!storyteller.storytellerCombatCheck(self, target))
|
|
{
|
|
if (checkVE)
|
|
{
|
|
removeHateTarget(self, target);
|
|
}
|
|
return;
|
|
}
|
|
if (getState(target, STATE_FEIGN_DEATH) == 1)
|
|
{
|
|
if (checkVE)
|
|
{
|
|
removeHateTarget(self, target);
|
|
}
|
|
return;
|
|
}
|
|
else if (!ai_combat_target.isValidTarget(target))
|
|
{
|
|
if (checkVE)
|
|
{
|
|
removeHateTarget(self, target);
|
|
}
|
|
return;
|
|
}
|
|
final boolean targetCovered = stealth.hasInvisibleBuff(target);
|
|
final boolean targetProne = posture.isProne(target);
|
|
final int freeShotCount = targetCovered ? 3 : (targetProne ? 1 : 0);
|
|
deltadictionary dict = self.getScriptVars();
|
|
if (!dict.getBoolean("ai.combat.cover.foundTarget"))
|
|
{
|
|
if ((getCombatDuration(self) > 10) || (freeShotCount == 0) || (ai_combat_damage.getAttackCount(target) > freeShotCount))
|
|
{
|
|
if (freeShotCount > 0 && !hasScript(self, "systems.dungeon_sequencer.ai_controller"))
|
|
{
|
|
showFlyText(self, new string_id("npc_reaction/flytext", "threaten"), 2.0f, colors.ORANGERED);
|
|
}
|
|
dict.put("ai.combat.cover.foundTarget", true);
|
|
}
|
|
}
|
|
int combatRound = utils.getIntScriptVar(self, "aiCombatRoundCounter");
|
|
combatRound++;
|
|
utils.setScriptVar(self, "aiCombatRoundCounter", combatRound);
|
|
selectWeapon(target);
|
|
final boolean commandQueueClear = (getCurrentCommand(self) == 0);
|
|
if (commandQueueClear)
|
|
{
|
|
utils.removeScriptVar(self, "creature_combat.commandQueueTime");
|
|
if (posture.isKnockedDown(self))
|
|
{
|
|
final int knockDownTime = dict.getInt("ai.combat.knockdown_time");
|
|
if ((getGameTime() - knockDownTime) > aiGetKnockDownRecoveryTime(self))
|
|
{
|
|
queueCommand(self, (-1322133240), self, "", COMMAND_PRIORITY_DEFAULT);
|
|
}
|
|
}
|
|
else if (!posture.isStanding(self))
|
|
{
|
|
posture.stand(self);
|
|
}
|
|
else
|
|
{
|
|
if (dict.getBoolean("ai.combat.cover.foundTarget"))
|
|
{
|
|
attack(target);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!utils.hasScriptVar(self, "creature_combat.commandQueueTime"))
|
|
{
|
|
utils.setScriptVar(self, "creature_combat.commandQueueTime", getGameTime());
|
|
}
|
|
else
|
|
{
|
|
int time = utils.getIntScriptVar(self, "creature_combat.commandQueueTime");
|
|
if (getGameTime() - time > 2)
|
|
{
|
|
clearCombatActions();
|
|
}
|
|
}
|
|
}
|
|
move(target);
|
|
}
|
|
public obj_id getBestTarget(obj_id self) throws InterruptedException
|
|
{
|
|
obj_id primaryTarget = getHateTarget(self);
|
|
if (isIdValid(primaryTarget) && exists(primaryTarget) && !isDead(primaryTarget) && !stealth.hasInvisibleBuff(primaryTarget))
|
|
{
|
|
return primaryTarget;
|
|
}
|
|
obj_id[] hateList = getHateList(self);
|
|
if (hateList == null || hateList.length == 0)
|
|
{
|
|
return null;
|
|
}
|
|
float topHate = 0.0f;
|
|
primaryTarget = null;
|
|
for (int i = 0; i < hateList.length; i++)
|
|
{
|
|
if (!isIdValid(hateList[i]) || !exists(primaryTarget))
|
|
{
|
|
continue;
|
|
}
|
|
if (isDead(hateList[i]) || stealth.hasInvisibleBuff(hateList[i]))
|
|
{
|
|
removeHateTarget(self, hateList[i]);
|
|
continue;
|
|
}
|
|
if (hasObjVar(self, "noPursue") && !combat.cachedCanSee(self, hateList[i]))
|
|
{
|
|
continue;
|
|
}
|
|
if (getHate(self, hateList[i]) > topHate)
|
|
{
|
|
primaryTarget = hateList[i];
|
|
}
|
|
}
|
|
return primaryTarget;
|
|
}
|
|
public void move(obj_id target) throws InterruptedException
|
|
{
|
|
final obj_id self = getSelf();
|
|
if (ai_combat_movement.isAiImmobile(self))
|
|
{
|
|
return;
|
|
}
|
|
if (!posture.isStanding(self))
|
|
{
|
|
return;
|
|
}
|
|
if (!ai_lib.isWithinLeash(self))
|
|
{
|
|
stopCombat(self);
|
|
return;
|
|
}
|
|
deltadictionary dict = self.getScriptVars();
|
|
setLookAtTarget(self, target);
|
|
final obj_id weapon = getCurrentWeapon(self);
|
|
final range_info weaponRange = aiGetWeaponRangeInfo(weapon);
|
|
final float distanceToTarget = getDistance(self, target);
|
|
final int weaponCategory = combat.getWeaponCategory(getWeaponType(weapon));
|
|
final boolean targetCovered = stealth.hasInvisibleBuff(target);
|
|
if (!canSee(self, target))
|
|
{
|
|
ai_combat_movement.aiMoveToSee(target);
|
|
return;
|
|
}
|
|
if ((weaponCategory == combat.RANGED_WEAPON) && (combat.getWeaponCategory(getWeaponType(aiGetPrimaryWeapon(self))) != combat.MELEE_WEAPON))
|
|
{
|
|
if ((distanceToTarget < TOO_CLOSE_DISTANCE) && isPlayer(target))
|
|
{
|
|
ai_combat_movement.aiEvade(target, self, weaponRange, 1f, 1f);
|
|
return;
|
|
}
|
|
else if (!ai_combat_movement.aiIsFleeing(self))
|
|
{
|
|
|
|
}
|
|
|
|
{
|
|
final float midRange = (weaponRange.maxRange - weaponRange.minRange) / 2.0f;
|
|
final float rangeVariation = midRange * 0.2f;
|
|
final float minFollowDistance = (weaponRange.minRange + midRange - rangeVariation);
|
|
final float maxFollowDistance = (weaponRange.minRange + midRange + rangeVariation);
|
|
ai_combat_movement.aiFollow(target, minFollowDistance, maxFollowDistance);
|
|
faceTo(self, target);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
float minFollowDistance = 1.5f;
|
|
float maxFollowDistance = 3.0f;
|
|
if (!hasObjVar(self, "ai.noFollow"))
|
|
{
|
|
ai_combat_movement.aiFollow(target, minFollowDistance, maxFollowDistance);
|
|
}
|
|
else
|
|
{
|
|
if (distanceToTarget > 64)
|
|
{
|
|
stopCombat(self);
|
|
resumeMovement(self);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
suspendMovement(self);
|
|
}
|
|
}
|
|
faceTo(self, target);
|
|
}
|
|
ai_combat_movement.aiEvade(target, self, weaponRange, MIN_MOVEMENT_DURING_COMBAT, MAX_MOVEMENT_DURING_COMBAT);
|
|
}
|
|
public void selectWeapon(obj_id target) throws InterruptedException
|
|
{
|
|
final obj_id self = getSelf();
|
|
if (beast_lib.isBeast(self))
|
|
{
|
|
return;
|
|
}
|
|
if (!aiHasPrimaryWeapon(self))
|
|
{
|
|
}
|
|
if (!aiHasSecondaryWeapon(self))
|
|
{
|
|
aiEquipPrimaryWeapon(self);
|
|
return;
|
|
}
|
|
boolean equipPrimary = true;
|
|
final float distanceToTarget = getDistance(self, target);
|
|
final obj_id primaryWeapon = aiGetPrimaryWeapon(self);
|
|
final obj_id secondaryWeapon = aiGetSecondaryWeapon(self);
|
|
if (!exists(primaryWeapon) || !exists(secondaryWeapon))
|
|
{
|
|
return;
|
|
}
|
|
final range_info primaryWeaponRange = aiGetWeaponRangeInfo(primaryWeapon);
|
|
final boolean primaryWeaponInRange = (distanceToTarget >= primaryWeaponRange.minRange) && (distanceToTarget <= primaryWeaponRange.maxRange);
|
|
final range_info secondaryWeaponRange = aiGetWeaponRangeInfo(secondaryWeapon);
|
|
final boolean secondaryWeaponInRange = (distanceToTarget >= secondaryWeaponRange.minRange) && (distanceToTarget <= secondaryWeaponRange.maxRange);
|
|
if (aiUsingPrimaryWeapon(self) && aiHasSecondaryWeapon(self))
|
|
{
|
|
if (secondaryWeaponInRange)
|
|
{
|
|
if (!primaryWeaponInRange)
|
|
{
|
|
aiEquipSecondaryWeapon(self);
|
|
}
|
|
else if (primaryWeaponRange.maxRange > secondaryWeaponRange.maxRange)
|
|
{
|
|
aiEquipSecondaryWeapon(self);
|
|
}
|
|
}
|
|
}
|
|
else if (aiUsingSecondaryWeapon(self) && primaryWeaponInRange)
|
|
{
|
|
if (!secondaryWeaponInRange)
|
|
{
|
|
aiEquipPrimaryWeapon(self);
|
|
}
|
|
else if (secondaryWeaponRange.maxRange > primaryWeaponRange.maxRange)
|
|
{
|
|
aiEquipPrimaryWeapon(self);
|
|
}
|
|
}
|
|
}
|
|
public void attack(obj_id target) throws InterruptedException
|
|
{
|
|
final obj_id self = getSelf();
|
|
String DEFAULT_ATTACK = combat.getAttackName(self);
|
|
String currentActionString = null;
|
|
String forcedActionString = getStringObjVar(self, "ai.combat.forcedAction");
|
|
String pendingActionString = getStringObjVar(self, "ai.combat.pendingAction");
|
|
String oneShotActionString = getStringObjVar(self, "ai.combat.oneShotAction");
|
|
if (oneShotActionString != null && !hasObjVar(self, "oneShotActionComplete"))
|
|
{
|
|
forcedActionString = oneShotActionString;
|
|
setObjVar(self, "oneShotActionComplete", 1);
|
|
}
|
|
else
|
|
{
|
|
if (oneShotActionString != null)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
int pendingActionTime = getIntObjVar(self, "ai.combat.pendingActionTime");
|
|
currentActionString = DEFAULT_ATTACK;
|
|
clog("attack() pre-check forcedActionString: " + forcedActionString + " pendingActionString: " + pendingActionString + (pendingActionTime > 0 ? " pendingActionTime: " + (getGameTime() - pendingActionTime) : ""));
|
|
if (forcedActionString != null)
|
|
{
|
|
currentActionString = forcedActionString;
|
|
}
|
|
else if (pendingActionString != null)
|
|
{
|
|
if (getGameTime() - pendingActionTime < 2)
|
|
{
|
|
currentActionString = pendingActionString;
|
|
}
|
|
else
|
|
{
|
|
removeObjVar(self, "ai.combat.pendingAction");
|
|
removeObjVar(self, "ai.combat.pendingActionTime");
|
|
currentActionString = DEFAULT_ATTACK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pendingActionString = aiGetCombatAction(self);
|
|
if (pendingActionString != null)
|
|
{
|
|
currentActionString = pendingActionString;
|
|
setObjVar(self, "ai.combat.pendingAction", pendingActionString);
|
|
setObjVar(self, "ai.combat.pendingActionTime", getGameTime());
|
|
}
|
|
else
|
|
{
|
|
currentActionString = DEFAULT_ATTACK;
|
|
}
|
|
}
|
|
clog("attack() post-check currentActionString: " + currentActionString + " pendingActionString: " + pendingActionString);
|
|
int currentActionCrc = 0;
|
|
final int result = combat.canPerformAction(currentActionString, self);
|
|
clog("attack() post-check currentActionString: " + currentActionString + " pendingActionString: " + pendingActionString + " canPerformAction: " + result);
|
|
if (result == combat.ACTION_SUCCESS || oneShotActionString != null)
|
|
{
|
|
currentActionCrc = getStringCrc(currentActionString.toLowerCase());
|
|
}
|
|
else if (result == combat.ACTION_TOO_TIRED)
|
|
{
|
|
if (forcedActionString != null)
|
|
{
|
|
clog("attack() self(" + self + ") target(" + target + ") ACTION(" + forcedActionString + ") TOO TIRED - WAITING TO ATTEMPT FORCED ACTION");
|
|
}
|
|
else
|
|
{
|
|
if (pendingActionString != null)
|
|
{
|
|
clog("attack() self(" + self + ") target(" + target + ") ACTION(" + pendingActionString + ") TOO TIRED - ATTEMPTING DEFAULT ATTACK");
|
|
}
|
|
if (!currentActionString.equals(DEFAULT_ATTACK))
|
|
{
|
|
if (combat.canPerformAction(DEFAULT_ATTACK, self) == combat.ACTION_SUCCESS)
|
|
{
|
|
currentActionString = DEFAULT_ATTACK;
|
|
currentActionCrc = getStringCrc(DEFAULT_ATTACK.toLowerCase());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (result == combat.ACTION_INVALID_WEAPON)
|
|
{
|
|
clearCombatActions();
|
|
clog("attack() ERROR self(" + self + getName(self) + ") ACTION(" + currentActionString + ") weapon(" + (aiUsingPrimaryWeapon(self) ? "primary weapon" : "secondary weapon") + ") INVALID WEAPON FOR ACTION, FIX THE DATA");
|
|
}
|
|
else
|
|
{
|
|
clearCombatActions();
|
|
clog("attack() ERROR self(" + self + getName(self) + ") ACTION(" + currentActionString + ") UNEXPECTED RESULT FROM combat.canPerformAction()");
|
|
}
|
|
if (currentActionCrc != 0)
|
|
{
|
|
combat_data cd = combat_engine.getCombatData(currentActionString);
|
|
if (cd == null)
|
|
{
|
|
return;
|
|
}
|
|
int groupCrc = getStringCrc(cd.cooldownGroup);
|
|
final float coolDownLeft = getCooldownTimeLeft(self, groupCrc);
|
|
if (coolDownLeft <= 0.0f)
|
|
{
|
|
final float distanceToTarget = getDistance(self, target);
|
|
final range_info weaponRange = aiGetWeaponRangeInfo(getCurrentWeapon(self));
|
|
if (distanceToTarget < weaponRange.maxRange || distanceToTarget < cd.maxRange)
|
|
{
|
|
if (canSee(self, target))
|
|
{
|
|
clog("attack() self(" + self + ") target(" + target + ") ACTION(" + currentActionCrc + ":" + currentActionString + ")");
|
|
queueCommand(self, currentActionCrc, target, "", COMMAND_PRIORITY_DEFAULT);
|
|
if (currentActionString.equals(forcedActionString))
|
|
{
|
|
removeObjVar(self, "ai.combat.forcedAction");
|
|
}
|
|
else if (currentActionString.equals(pendingActionString))
|
|
{
|
|
removeObjVar(self, "ai.combat.pendingAction");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
public int OnCreatureDamaged(obj_id self, obj_id attacker, obj_id weapon, int[] damage) throws InterruptedException
|
|
{
|
|
int lastFrame = utils.getIntScriptVar(self, "creature_combat.lastCombatFrame");
|
|
if (!stealth.hasInvisibleBuff(attacker))
|
|
{
|
|
ai_combat_damage.addAttack(attacker);
|
|
}
|
|
if (getGameTime() - lastFrame > 2)
|
|
{
|
|
clog("OnCreatureDamaged() !!!COMBAT STUCK!!! lastFrame: " + lastFrame + " time elapsed: " + (getGameTime() - lastFrame));
|
|
doCombatFrame();
|
|
}
|
|
ai_lib.triggerAgroLinks(self, attacker);
|
|
if (!isPlayer(attacker) && isMob(attacker))
|
|
{
|
|
obj_id master = getMaster(attacker);
|
|
if (isIdValid(master) && exists(master))
|
|
{
|
|
attacker = master;
|
|
}
|
|
}
|
|
if (isIdValid(attacker) && exists(attacker) && isPlayer(attacker) && hasObjVar(self, "requirePlayerSpecialForces") && (pvpGetType(attacker) != PVPTYPE_DECLARED))
|
|
{
|
|
if (pvpNeutralIsMercenaryDeclared(attacker))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
if (!utils.hasScriptVar(attacker, "gcw.specialForcesWarningTime"))
|
|
{
|
|
sui.msgbox(attacker, attacker, "@spam:warn_special_forces_prompt", sui.OK_ONLY, "@spam:warn_special_forces_title", "handleNothing");
|
|
utils.setScriptVar(attacker, "gcw.specialForcesWarningTime", getGameTime());
|
|
}
|
|
else
|
|
{
|
|
int warningTime = utils.getIntScriptVar(attacker, "gcw.specialForcesWarningTime");
|
|
int timeDelta = getGameTime() - warningTime;
|
|
if (timeDelta > 30)
|
|
{
|
|
if (timeDelta > 90)
|
|
{
|
|
sui.msgbox(attacker, attacker, "@spam:warn_special_forces_prompt", sui.OK_ONLY, "@spam:warn_special_forces_title", "handleNothing");
|
|
utils.setScriptVar(attacker, "gcw.specialForcesWarningTime", getGameTime());
|
|
}
|
|
else
|
|
{
|
|
if (0 != factions.pvpGetAlignedFaction(attacker))
|
|
{
|
|
factions.goOvertWithDelay(attacker, 0.0f);
|
|
}
|
|
else
|
|
{
|
|
int currentMercenaryFaction = factions.pvpNeutralGetMercenaryFaction(attacker);
|
|
if ((-615855020) == currentMercenaryFaction)
|
|
{
|
|
pvpNeutralSetMercenaryFaction(attacker, currentMercenaryFaction, true);
|
|
}
|
|
if ((370444368) == currentMercenaryFaction)
|
|
{
|
|
pvpNeutralSetMercenaryFaction(attacker, currentMercenaryFaction, true);
|
|
}
|
|
}
|
|
utils.removeScriptVar(attacker, "gcw.specialForcesWarningTime");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public int OnChangedPosture(obj_id self, int oldPosture, int newPosture) throws InterruptedException
|
|
{
|
|
if (newPosture == POSTURE_KNOCKED_DOWN)
|
|
{
|
|
final deltadictionary dict = self.getScriptVars();
|
|
dict.put("ai.combat.knockdown_time", getGameTime());
|
|
}
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public int vocalizeEndCombat(obj_id self, dictionary params) throws InterruptedException
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public int postCombatPathHome(obj_id self, dictionary params) throws InterruptedException
|
|
{
|
|
if (ai_lib.isInCombat(self))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
if (pet_lib.isPet(self) || beast_lib.isBeast(self))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
if (ai_lib.isFollowing(self))
|
|
{
|
|
ai_lib.resumeFollow(self);
|
|
}
|
|
else
|
|
{
|
|
pathTo(self, aiGetHomeLocation(self));
|
|
}
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public boolean isNearLair(obj_id npc) throws InterruptedException
|
|
{
|
|
obj_id myLair = getObjIdObjVar(npc, "npc_lair.target");
|
|
if (!hasObjVar(npc, "lairSpawn") && !isIdValid(myLair))
|
|
{
|
|
return false;
|
|
}
|
|
if (!isIdValid(myLair))
|
|
{
|
|
myLair = getObjIdObjVar(npc, "poi.baseObject");
|
|
}
|
|
if (isIdValid(myLair) && isInWorld(myLair) && exists(myLair))
|
|
{
|
|
if (getDistance(npc, myLair) < 40f)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
public void killPlayer(obj_id npc, obj_id target) throws InterruptedException
|
|
{
|
|
if (!isIdValid(target) || !isIncapacitated(target) || !isInWorld(target) || !exists(target) || ai_lib.isInCombat(npc))
|
|
{
|
|
return;
|
|
}
|
|
obj_id weapon = getCurrentWeapon(npc);
|
|
int weaponType = getWeaponType(weapon);
|
|
int weaponCat = combat.getWeaponCategory(weaponType);
|
|
float range = getDistance(npc, target);
|
|
if (range > 2.0f)
|
|
{
|
|
setObjVar(npc, "ai.pathingToKill", target);
|
|
ai_lib.pathNear(npc, getLocation(target), 2f);
|
|
return;
|
|
}
|
|
String skeleton = dataTableGetString("datatables/ai/species.iff", ai_lib.aiGetSpecies(npc), "Skeleton");
|
|
if (skeleton != null && !skeleton.equals("human"))
|
|
{
|
|
doAnimationAction(npc, "eat");
|
|
pclib.coupDeGrace(target, npc);
|
|
}
|
|
else
|
|
{
|
|
pclib.coupDeGrace(target, npc, true);
|
|
}
|
|
}
|
|
public int OnFleeTargetLost(obj_id self, obj_id target) throws InterruptedException
|
|
{
|
|
if (!ai_lib.isInCombat(self))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
clog("OnFleeTargetLost() self(" + self + ":" + getName(self) + ") target(" + target + ")");
|
|
stopCombat(self);
|
|
return SCRIPT_OVERRIDE;
|
|
}
|
|
public int OnFleeWaypoint(obj_id self, obj_id target) throws InterruptedException
|
|
{
|
|
if (!ai_lib.isInCombat(self))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
return SCRIPT_OVERRIDE;
|
|
}
|
|
public int OnFleePathNotFound(obj_id self, obj_id target) throws InterruptedException
|
|
{
|
|
if (!ai_lib.isInCombat(self))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
clog("OnFleePathNotFound() self(" + self + ":" + getName(self) + ") target(" + target + ")");
|
|
stopCombat(self);
|
|
return SCRIPT_OVERRIDE;
|
|
}
|
|
public int OnFollowWaiting(obj_id self, obj_id target) throws InterruptedException
|
|
{
|
|
if (!ai_lib.isInCombat(self))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
if (utils.hasScriptVar(self, "ai.combat.pathingToHeal"))
|
|
{
|
|
obj_id healingTarget = utils.getObjIdScriptVar(self, "ai.combat.pathingToHeal");
|
|
ai_combat.executeHealingMove(self, healingTarget);
|
|
return SCRIPT_OVERRIDE;
|
|
}
|
|
faceTo(self, target);
|
|
return SCRIPT_OVERRIDE;
|
|
}
|
|
public int OnFollowMoving(obj_id self, obj_id followTarget) throws InterruptedException
|
|
{
|
|
if (!ai_lib.isInCombat(self))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
if (utils.hasScriptVar(self, "ai.combat.pathingToHeal"))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
return SCRIPT_OVERRIDE;
|
|
}
|
|
public int OnFollowTargetLost(obj_id self, obj_id target) throws InterruptedException
|
|
{
|
|
if (!ai_lib.isInCombat(self))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
clog("OnFollowTargetLost() self(" + self + ":" + getName(self) + ") target(" + target + ")");
|
|
stopCombat(self);
|
|
return SCRIPT_OVERRIDE;
|
|
}
|
|
public int OnFollowPathNotFound(obj_id self, obj_id target) throws InterruptedException
|
|
{
|
|
if (!ai_lib.isInCombat(self))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
clog("OnFollowPathNotFound() self(" + self + ":" + getName(self) + ") target(" + target + ")");
|
|
stopCombat(self);
|
|
return SCRIPT_OVERRIDE;
|
|
}
|
|
public int OnMovePathComplete(obj_id self) throws InterruptedException
|
|
{
|
|
if (!ai_lib.isInCombat(self))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
clog("OnMovePathComplete() self(" + self + ") The AI is dead.");
|
|
if (ai_combat_movement.aiIsMovingToSee())
|
|
{
|
|
ai_combat_movement.aiClearMoveMode();
|
|
ai_combat_movement.aiMoveToSee(ai_combat_movement.aiGetMoveToSeeTarget());
|
|
}
|
|
else if (ai_combat_movement.aiIsMovingToDeathBlow())
|
|
{
|
|
}
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public int OnMoveMoving(obj_id self) throws InterruptedException
|
|
{
|
|
if (!ai_lib.isInCombat(self))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
clog("OnMoveMoving() self(" + self + ") The AI is dead.");
|
|
return SCRIPT_OVERRIDE;
|
|
}
|
|
public int OnMovePathNotFound(obj_id self) throws InterruptedException
|
|
{
|
|
if (!ai_lib.isInCombat(self))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
if (ai_combat_movement.aiIsMovingToSee())
|
|
{
|
|
final obj_id target = ai_combat_movement.aiGetMoveToSeeTarget();
|
|
clog("OnMovePathNotFound() self(" + self + ") The AI was moving to see(" + target + ":" + getName(target) + ") and something went wrong so forcing tether.");
|
|
stopCombat(self);
|
|
}
|
|
else if (ai_combat_movement.aiIsMovingToDeathBlow())
|
|
{
|
|
}
|
|
return SCRIPT_OVERRIDE;
|
|
}
|
|
public int handleMoveRandomClear(obj_id self, dictionary params) throws InterruptedException
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public int handleTaunt(obj_id self, dictionary params) throws InterruptedException
|
|
{
|
|
if (ai_lib.isInCombat(self))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
obj_id target = params.getObjId("player");
|
|
if (!isIdValid(target))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
utils.setScriptVar(self, "ai.combat.isTaunted", (getGameTime() + 20));
|
|
stop(self);
|
|
setTarget(self, target);
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public int getConfusionDuration(obj_id npc, obj_id attacker) throws InterruptedException
|
|
{
|
|
if (getDistance(npc, attacker) < 10.0f)
|
|
{
|
|
return 0;
|
|
}
|
|
int attackerPosture = getPosture(attacker);
|
|
int duration = 0;
|
|
if (attackerPosture == POSTURE_CROUCHED)
|
|
{
|
|
duration = 5;
|
|
}
|
|
else if (attackerPosture == POSTURE_PRONE)
|
|
{
|
|
duration = 10;
|
|
}
|
|
if (!ai_lib.isMonster(npc))
|
|
{
|
|
return duration;
|
|
}
|
|
boolean masked = false;
|
|
if (scout.isScentMasked(attacker, npc))
|
|
{
|
|
masked = true;
|
|
duration += 7;
|
|
}
|
|
return duration;
|
|
}
|
|
public int OnDestroy(obj_id self) throws InterruptedException
|
|
{
|
|
clog("OnDestroy() unit(" + self + ":" + getName(self) + ")");
|
|
if (ai_lib.isAiDead(self))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
int combatDestructionDelay = 0;
|
|
if (pet_lib.isPet(self) || beast_lib.isBeast(self))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
if (ai_lib.isInCombat(self))
|
|
{
|
|
combatDestructionDelay = getGameTime() + 30;
|
|
utils.setScriptVar(self, "combatDestructionDelay", combatDestructionDelay);
|
|
messageTo(self, "handleCombatDestructionDelay", null, 60, false);
|
|
return SCRIPT_OVERRIDE;
|
|
}
|
|
if (!utils.hasScriptVar(self, "combatDestructionDelay"))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
else
|
|
{
|
|
combatDestructionDelay = utils.getIntScriptVar(self, "combatDestructionDelay");
|
|
}
|
|
if (getGameTime() > combatDestructionDelay)
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
messageTo(self, "handleCombatDestructionDelay", null, 30, false);
|
|
return SCRIPT_OVERRIDE;
|
|
}
|
|
public int handleCombatDestructionDelay(obj_id self, dictionary params) throws InterruptedException
|
|
{
|
|
destroyObject(self);
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public int OnDotPulse(obj_id self, dictionary params) throws InterruptedException
|
|
{
|
|
clog("OnDotPulse() self(" + self + ":" + getName(self) + ")");
|
|
if (ai_lib.isInCombat(self))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
if (ai_lib.isAiDead(self))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
if (pet_lib.isPet(self) || beast_lib.isBeast(self))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
obj_id[] players = pvpGetEnemiesInRange(self, self, 128.0f);
|
|
if (players == null || players.length < 1)
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
for (int i = 0; i < players.length; i++)
|
|
{
|
|
if (isIdValid(players[i]) && exists(players[i]) && players[i] != self)
|
|
{
|
|
startCombat(self, players[i]);
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
}
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public int OnIncapacitateTarget(obj_id self, obj_id target) throws InterruptedException
|
|
{
|
|
if (!isIdValid(target))
|
|
{
|
|
clog("OnIncapacitateTarget() self(" + self + ":" + getName(self) + ") target(" + target + ":" + getName(target) + ") INVALID TARGET");
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
if (!isPlayer(target) && !pet_lib.isPet(target) && !beast_lib.isBeast(target))
|
|
{
|
|
clog("OnIncapacitateTarget() self(" + self + ":" + getName(self) + ") target(" + target + ":" + getName(target) + ") TARGET IS NON-PLAYER");
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
if (aiIsKiller(self))
|
|
{
|
|
if (pet_lib.isPet(target))
|
|
{
|
|
clog("OnIncapacitateTarget() self(" + self + ":" + getName(self) + ") target(" + target + ":" + getName(target) + ") DEATH BLOW PET");
|
|
pet_lib.killPet(target);
|
|
}
|
|
else if (beast_lib.isBeast(target))
|
|
{
|
|
clog("OnIncapacitateTarget() self(" + self + ":" + getName(self) + ") target(" + target + ":" + getName(target) + ") DEATH BLOW BEAST");
|
|
beast_lib.killBeast(target, self);
|
|
}
|
|
else
|
|
{
|
|
clog("OnIncapacitateTarget() self(" + self + ":" + getName(self) + ") target(" + target + ":" + getName(target) + ") DEATH BLOW PLAYER");
|
|
pclib.coupDeGrace(target, self);
|
|
}
|
|
}
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public int OnIncapacitated(obj_id self, obj_id killer) throws InterruptedException
|
|
{
|
|
obj_id[] myHateList = getHateList(self);
|
|
if (myHateList == null || myHateList.length == 0)
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
for (int i = 0; i < myHateList.length; i++)
|
|
{
|
|
removeHateTarget(self, myHateList[i]);
|
|
removeHateTarget(myHateList[i], self);
|
|
}
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public int handleAggroCheck(obj_id self, dictionary params) throws InterruptedException
|
|
{
|
|
final obj_id target = params.getObjId("target");
|
|
if (!isIdValid(target) || !exists(target) || isDead(target))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
ai_aggro.stopAttemptingAggroCheck(target);
|
|
ai_aggro.requestAggroCheck(target);
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public int handleAggroStart(obj_id self, dictionary params) throws InterruptedException
|
|
{
|
|
if (beast_lib.isBeast(self))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
final obj_id target = params.getObjId("target");
|
|
if (isIdValid(target) && exists(target) && !isDead(target))
|
|
{
|
|
if (!stealth.hasServerCoverState(target) && canSee(self, target))
|
|
{
|
|
startCombatWithAssist(self, target);
|
|
}
|
|
}
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public int handleSawRecapacitation(obj_id self, dictionary params) throws InterruptedException
|
|
{
|
|
clog("handleSawRecapacitation() self(" + self + ":" + getName(self) + ")");
|
|
final obj_id player = params.getObjId("player");
|
|
stopListeningToMessage(player, "handleSawRecapacitation");
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public void clearCombatActions() throws InterruptedException
|
|
{
|
|
obj_id self = getSelf();
|
|
removeObjVar(self, "ai.combat.forcedAction");
|
|
removeObjVar(self, "ai.combat.pendingAction");
|
|
}
|
|
public int checkForSpecials(obj_id self, dictionary params) throws InterruptedException
|
|
{
|
|
if (!verifyMessage(self, params))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
if (!pet_lib.hasMaster(self)){
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
String bestBeastAbility = beast_lib.getBestAutoRepeatAbility(self);
|
|
obj_id target = getTarget(self);
|
|
if (!isIdValid(target))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
if (!bestBeastAbility.equals(""))
|
|
{
|
|
queueCommand(getMaster(self), getStringCrc(bestBeastAbility), target, "", COMMAND_PRIORITY_DEFAULT);
|
|
}
|
|
messageTo(self, "checkForSpecials", stampMessage(self), 1.0f, false);
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public dictionary stampMessage(obj_id self) throws InterruptedException
|
|
{
|
|
int session = getMessageSession(self);
|
|
utils.setScriptVar(self, "messageStamp", session);
|
|
dictionary dict = new dictionary();
|
|
dict.put("sessionId", session);
|
|
return dict;
|
|
}
|
|
public int getMessageSession(obj_id self) throws InterruptedException
|
|
{
|
|
return utils.hasScriptVar(self, "messageStamp") ? utils.getIntScriptVar(self, "messageStamp") : 0;
|
|
}
|
|
public boolean verifyMessage(obj_id self, dictionary params) throws InterruptedException
|
|
{
|
|
int messageId = params.getInt("sessionId");
|
|
int currentId = utils.getIntScriptVar(self, "messageStamp");
|
|
return messageId == currentId;
|
|
}
|
|
public void bumpSession(obj_id self) throws InterruptedException
|
|
{
|
|
int session = getMessageSession(self);
|
|
session++;
|
|
utils.setScriptVar(self, "messageStamp", session);
|
|
}
|
|
public int checkForBeastSpecialsTakeOne(obj_id self, dictionary params) throws InterruptedException
|
|
{
|
|
if (beast_lib.isBeast(self))
|
|
{
|
|
messageTo(self, "checkForSpecials", stampMessage(self), 1.0f, false);
|
|
}
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
public int persist_combat(obj_id self, dictionary params) throws InterruptedException
|
|
{
|
|
if (!trial.verifySession(self, params, combat.PERSIST_COMBAT))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
if (!combat.isValidPersistCombat(self))
|
|
{
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
resetHateTimer(self);
|
|
messageTo(self, "persist_combat", trial.getSessionDict(self, combat.PERSIST_COMBAT), 5.0f, false);
|
|
return SCRIPT_CONTINUE;
|
|
}
|
|
}
|