Files
dsrc/sku.0/sys.server/compiled/game/script/library/combat.java
Tekaoh 5c2e112349 Java 11.0.2 migration (#32)
* Code compiles - execution NOT tested

* updating gitignore

* Removed intellij settings files

* Removed more intellij files

* Added exclusion for JDK classes.

* Fixed purchasing script for vendors that have listed coin types.

* Updated script to not kick off until the entire preload is complete.

* adds static name entry for Solo movie poster and tcg9 vendor entry

* clean up empty and orphaned object templates

* adds placeholder black market (static) spawns

* corrects entries for the video game table to correctly set it in tcg series 2 and remove series 1 console errors

* Updated gitignore and removed intellij project files

* Fixed appearance reference for thranta payroll and kashyyyk door, added skipLosCheck objvar due to cannit see issue. Requires updated src

* Fixed appearance and template for terminal (#2)

* Fixed appearance and template for terminal (#3)

* Fixed appearance and template for terminal (#4)

* Deleted another faulty/orphaned object template

* Fixed gcw ranks option on frog. Only issue is that it doesn't award the officer commands or badges.

* Fixed some unneeded java 11 changes
2019-04-18 18:31:52 -05:00

3913 lines
171 KiB
Java
Executable File

package script.library;
import script.*;
import script.combat_engine.*;
import java.util.Vector;
public class combat extends script.base_script
{
public combat()
{
}
public static final float IN_COMBAT_REGEN_MULT = 1.0f;
public static final float OUT_COMBAT_REGEN_MULT = 4.0f;
public static final int PLAYER_COMBAT_BASE_DAMAGE = 60;
public static final int PLAYER_ATTACKER_DAMAGE_LEVEL_MULTIPLIER = 5;
public static final int RANGED_WEAPON = -1;
public static final int MELEE_WEAPON = -2;
public static final int ALL_WEAPONS = -3;
public static final int ALL_LIGHTSABERS = -4;
public static final int FORCE_POWER = -5;
public static final int ALL_BUT_HEAVY = -6;
public static final int WEAPON_TYPE_FORCE_POWER = -1;
public static final int LEFT_CLICK_DEFAULT = 1;
public static final int RIGHT_CLICK_SPECIAL = 2;
public static final int B_RIFLE = 0x00000001;
public static final int B_CARBINE = 0x00000002;
public static final int B_PISTOL = 0x00000004;
public static final int B_HEAVY = 0x00000008;
public static final int B_1HAND_MELEE = 0x00000010;
public static final int B_2HAND_MELEE = 0x00000020;
public static final int B_UNARMED = 0x00000040;
public static final int B_POLEARM = 0x00000080;
public static final int B_THROWN = 0x00000100;
public static final int B_1HAND_LIGHTSABER = 0x00000200;
public static final int B_2HAND_LIGHTSABER = 0x00000400;
public static final int B_POLEARM_LIGHTSABER = 0x00000800;
public static final int B_GROUND_TARGETTING = 0x00001000;
public static final int B_DIRECTIONAL = 0x00002000;
public static final int B_RANGED = 0x08000000;
public static final int B_MELEE = 0x10000000;
public static final int B_ALL = 0x20000000;
public static final int B_ALL_LIGHTSABERS = 0x40000000;
public static final int[] weaponTypeToBitValueMap =
{
B_ALL | B_RANGED | B_RIFLE,
B_ALL | B_RANGED | B_CARBINE,
B_ALL | B_RANGED | B_PISTOL,
B_ALL | B_RANGED | B_HEAVY,
B_ALL | B_MELEE | B_1HAND_MELEE,
B_ALL | B_MELEE | B_2HAND_MELEE,
B_ALL | B_MELEE | B_UNARMED,
B_ALL | B_MELEE | B_POLEARM,
B_ALL | B_RANGED | B_THROWN,
B_ALL | B_ALL_LIGHTSABERS | B_1HAND_LIGHTSABER,
B_ALL | B_ALL_LIGHTSABERS | B_2HAND_LIGHTSABER,
B_ALL | B_ALL_LIGHTSABERS | B_POLEARM_LIGHTSABER,
B_ALL | B_RANGED | B_HEAVY | B_GROUND_TARGETTING,
B_ALL | B_RANGED | B_HEAVY | B_DIRECTIONAL
};
public static final int EFFECT_MAX_DURATION = 180;
public static final float DELAY_EFFECT_TIMER = 30.0f;
public static final int TKA_JEDI_ARMOR_HARD_CAP = 9000;
public static final int MAX_RE_EXOTIC_ELEMENTAL_PENETRATION_SKILLMOD = 10;
public static final int MOVEMENT_MODIFIER_REUSE_TIME = 30;
public static final int AI_LEVEL_ACCURACY_BONUS = 65;
public static final int AI_LEVEL_DEFENSE_BONUS = 65;
public static final int AI_LEVEL_DAMAGE_BONUS = 40;
public static final int AI_LEVEL_DAMAGE_PENALTY = 25;
public static final int AI_LEVEL_MIN_DAMAGE_CAP = 50;
public static final int AI_LEVEL_MAX_DAMAGE_CAP = 75;
public static final float AI_CON_SCALE_MULT = 8.0f;
public static final int VALID_TARGET_NONE = -1;
public static final int VALID_TARGET_STANDARD = 0;
public static final int VALID_TARGET_MOB = 1;
public static final int VALID_TARGET_CREATURE = 2;
public static final int VALID_TARGET_NPC = 3;
public static final int VALID_TARGET_DROID = 4;
public static final int VALID_TARGET_PVP = 5;
public static final int VALID_TARGET_JEDI = 6;
public static final int VALID_TARGET_DEAD = 7;
public static final int VALID_TARGET_FRIEND = 8;
public static final int NON_ATTACK = 0;
public static final int NON_DAMAGE_ATTACK = 4;
public static final int HEAL = 5;
public static final int DELAY_ATTACK = 6;
public static final int REVIVE = 7;
public static final int ACTION_NAME = 0;
public static final int WEAPON_NAME = 1;
public static final int NO_ATTACK_NAME = 2;
public static final int NO_HIT_SPAM = 3;
public static final float ARMOR_BREAK_REDUCTION = 0.5f;
public static final String ATTACKER_DATA = "cached_attacker_data";
public static final String ATTACKER_BASE_CRIT = ATTACKER_DATA + ".base_crit";
public static final String ATTACKER_PVP_CRIT = ATTACKER_DATA + ".pvp_crit";
public static final String ATTACKER_DROID_CRIT = ATTACKER_DATA + ".droid_crit";
public static final String ATTACKER_NPC_CRIT = ATTACKER_DATA + ".npc_crit";
public static final String ATTACKER_CREATURE_CRIT = ATTACKER_DATA + ".creature_crit";
public static final String ATTACKER_HIT_BONUS = ATTACKER_DATA + ".hit_bonus";
public static final String ATTACKER_STRIKETHROUGH = ATTACKER_DATA + ".strikethrough_chance";
public static final String ATTACKER_REDUCE_PARRY = ATTACKER_DATA + ".reduce_parry";
public static final String ATTACKER_REDUCE_BLOCK = ATTACKER_DATA + ".reudce_block";
public static final String ATTACKER_REDUCE_DODGE = ATTACKER_DATA + ".reduce_dodge";
public static final String ATTACKER_REDUCE_GLANCING = ATTACKER_DATA + ".reduce_glancing";
public static final String ATTACKER_REDUCE_EVADE = ATTACKER_DATA + ".reduce_evade";
public static final String DEFENDER_DATA = "cached_defender_data";
public static final String DEFENDER_REDUCE_CRIT = DEFENDER_DATA + ".crit_reduce";
public static final String DEFENDER_INCREASE_MISS = DEFENDER_DATA + ".increase_miss";
public static final String DEFENDER_REDUCE_STRIKETHROUGH = DEFENDER_DATA + ".reduce_strikethrough";
public static final String DEFENDER_REDUCE_PUNISH = DEFENDER_DATA + ".reduce_punish";
public static final String DEFENDER_GLANCING = DEFENDER_DATA + ".increase_glancing";
public static final String DEFENDER_PARRY = DEFENDER_DATA + ".parry_chance";
public static final String DEFENDER_DODGE = DEFENDER_DATA + ".dodge_chance";
public static final String DEFENDER_EVADE = DEFENDER_DATA + ".evade_chance";
public static final String DEFENDER_BLOCK = DEFENDER_DATA + ".block_chance";
public static final String[][] ARMOR_SLOT_LOCATIONS =
{
{
"chest2",
"chest2"
},
{
"hat",
"hat"
},
{
"bicep_r",
"bracer_upper_r"
},
{
"bicep_l",
"bracer_upper_l"
},
{
"pants2",
"pants2"
},
{
"pants2",
"pants2"
}
};
public static final String PSG_SLOT_LOCATION = "utility_belt";
public static final float PSG_BASE_DMG_PER_HIT = 50.0f;
public static final float PSG_DAMAGE_SCALE = 200.0f;
public static final int CONE = 0;
public static final int SINGLE_TARGET = 1;
public static final int AREA = 2;
public static final int TARGET_AREA = 3;
public static final int DUAL_WIELD = 4;
public static final int RAMPAGE = 5;
public static final int RANDOM_HATE_TARGET = 6;
public static final int RANDOM_HATE_TARGET_CONE = 7;
public static final int RANDOM_HATE_TARGET_CONE_TERMINUS = 8;
public static final int HATE_LIST = 9;
public static final int RANDOM_HATE_MULTI = 10;
public static final int AREA_PROGRESSIVE = 11;
public static final int SPLIT_DAMAGE_TARGET_AREA = 12;
public static final int DISTANCE_FARTHEST = 13;
public static final String NONCOMBAT_DATATABLE = "datatables/combat/non_combat_data.iff";
public static final String WEAPON_LEVEL_TABLE = "datatables/combat/weapon_level.iff";
public static final int[] RANGED_WEAPONS =
{
WEAPON_TYPE_RIFLE,
WEAPON_TYPE_LIGHT_RIFLE,
WEAPON_TYPE_PISTOL,
WEAPON_TYPE_HEAVY
};
public static final int[] MELEE_WEAPONS =
{
WEAPON_TYPE_1HAND_MELEE,
WEAPON_TYPE_2HAND_MELEE,
WEAPON_TYPE_UNARMED,
WEAPON_TYPE_POLEARM,
WEAPON_TYPE_WT_1HAND_LIGHTSABER,
WEAPON_TYPE_WT_2HAND_LIGHTSABER,
WEAPON_TYPE_WT_POLEARM_LIGHTSABER
};
public static final String VAR_VOLLEY_GROUPS = "squadleader.volleyGroups";
public static final String ID_VOLLEY_FIRE_PARTICLE = "squadleader.volleyFire";
public static final int VOLLEY_INTERVAL = 30;
public static final String VAR_GROUP_VOLLEY_TARGET = "squadleader.curVolleyTarget";
public static final String VAR_GROUP_LAST_VOLLEY_TIME = "squadleader.lastVolleyTime";
public static final string_id SID_NONE = new string_id();
public static final String CHARGE_TARGET = "charge_target";
public static final String DIED_RECENTLY = "combat.died_recently";
public static final float RECENT_DEATH_EXPIRATION = 60.0f;
public static final String DAMAGE_REDIRECT = "damage_redirect";
public static final String DO_ONCE_ATTACK_OVERRIDE = "default.do_once_attack_override";
public static final String DEFAULT_ATTACK_OVERRIDE = "default.default_attack_override";
public static final int FS_TAUNT_HATE_INCREASE_LOW = 750;
public static final int FS_TAUNT_HATE_INCREASE_MID = 1200;
public static final int FS_TAUNT_HATE_INCREASE_HIGH = 2000;
public static final int FS_TAUNT_LOW_LEVEL = 64;
public static final int FS_TAUNT_MID_LEVEL = 77;
public static final int BH_TAUNT_HATE_INCREASE_LOW = 300;
public static final int BH_TAUNT_HATE_INCREASE_MID = 750;
public static final int BH_TAUNT_HATE_INCREASE_HIGH = 1200;
public static final int BH_TAUNT_LOW_LEVEL = 43;
public static final int BH_TAUNT_MID_LEVEL = 66;
public static final String TEMP_COMBAT_BLOCK = "combat_debuff.all_actions_blocked";
public static final String PERSIST_COMBAT = "persist_combat";
public static final String BUFF_HATE_XFER = "aggroChannelself";
public static final int EGG_AURA_TRIGGER_MIN_RANGE = 15;
public static final int EGG_AURA_TRIGGER_MAX_RANGE = 100;
public static final int EGG_AURA_DURATION = 20;
public static final int DR_ATTACKER_CRITICAL = 0;
public static final int DR_ATTACKER_STRIKETHROUGH = 1;
public static final int DR_DEFENDER_BLOCK = 2;
public static final int DR_DEFENDER_DODGE = 3;
public static final int DR_DEFENDER_PARRY = 4;
public static final int DR_DEFENDER_GLANCE = 5;
public static final int DR_DEFENDER_EVADE = 6;
public static final int DR_ATTACKER_CRITICAL_2 = 7;
public static void sendCombatSpam(obj_id attacker, obj_id defender, obj_id weapon, combat_engine.hit_result result, string_id attackName, boolean sendToAttacker, boolean sendToDefender, boolean sendToBystanders) throws InterruptedException
{
sendCombatSpam(attacker, defender, weapon, result, attackName, sendToAttacker, sendToDefender, sendToBystanders, COMBAT_RESULT_GENERIC);
}
public static void sendCombatSpam(obj_id attacker, obj_id defender, string_id weapon, combat_engine.hit_result result, string_id attackName, boolean sendToAttacker, boolean sendToDefender, boolean sendToBystanders) throws InterruptedException
{
sendCombatSpam(attacker, defender, weapon, result, attackName, sendToAttacker, sendToDefender, sendToBystanders, COMBAT_RESULT_GENERIC);
}
public static void sendCombatSpamMessage(obj_id player, string_id message) throws InterruptedException
{
sendCombatSpamMessage(player, message, COMBAT_RESULT_GENERIC);
}
public static void sendCombatSpamMessage(obj_id attacker, obj_id defender, string_id message, boolean sendToAttacker, boolean sendToDefender, boolean sendToBystanders) throws InterruptedException
{
sendCombatSpamMessage(attacker, defender, message, sendToAttacker, sendToDefender, sendToBystanders, COMBAT_RESULT_GENERIC);
}
public static void sendCombatSpamMessageProse(obj_id player, prose_package pp) throws InterruptedException
{
sendCombatSpamMessageProse(player, pp, COMBAT_RESULT_GENERIC);
}
public static void sendCombatSpamMessageProse(obj_id attacker, obj_id defender, prose_package pp, boolean sendToAttacker, boolean sendToDefender, boolean sendToBystanders) throws InterruptedException
{
sendCombatSpamMessageProse(attacker, defender, pp, sendToAttacker, sendToDefender, sendToBystanders, COMBAT_RESULT_GENERIC);
}
public static void doBasicCombatSpam(String attackName, attacker_results attackerResults, defender_results[] defenderResults, hit_result[] hitData) throws InterruptedException
{
string_id attackId = new string_id("cmd_n", attackName);
doBasicCombatSpam(attackId, SID_NONE, null, attackerResults, defenderResults, hitData);
}
public static void doBasicCombatSpam(string_id attackId, string_id weaponId, obj_id weapon, attacker_results attackerResults, defender_results[] defenderResults, hit_result[] hitData) throws InterruptedException
{
if (isIdValid(weapon))
{
for (int i = 0; i < defenderResults.length; ++i)
{
sendCombatSpam(attackerResults.id, defenderResults[i].id, weapon, hitData[i], attackId, true, true, true, defenderResults[i].result);
}
}
else
{
for (int i = 0; i < defenderResults.length; ++i)
{
sendCombatSpam(attackerResults.id, defenderResults[i].id, weaponId, hitData[i], attackId, true, true, true, defenderResults[i].result);
}
}
}
public static boolean isAreaAttack(int attackType) throws InterruptedException
{
if (attackType == CONE || attackType == AREA || attackType == TARGET_AREA)
{
return true;
}
return false;
}
public static boolean breakMez(obj_id defender) throws InterruptedException
{
int[] buffs = buff.getAllBuffs(defender);
if (buffs == null || buffs.length == 0)
{
return true;
}
for (int b : buffs) {
for (int j = 1; j <= buff.MAX_EFFECTS; j++) {
String effect = buff.getEffectParam(b, j);
if (effect.equals("delay_attack")) {
buff.removeBuff(defender, b);
}
}
}
return true;
}
public static int getAiLevelDiff(obj_id attacker, obj_id defender) throws InterruptedException
{
obj_id master = null;
if (isPlayer(attacker))
{
return 0;
}
if (!isPlayer(defender) && !isMob(defender))
{
return 0;
}
if (isMob(attacker))
{
master = getMaster(attacker);
if (!isPlayer(attacker) && isIdValid(master))
{
return 0;
}
}
if (isMob(defender))
{
master = getMaster(defender);
if (!isPlayer(defender) && !isIdValid(master))
{
return 0;
}
}
int aiLevel = getLevel(attacker);
int defenderLevel = getLevel(defender);
if (!isMob(attacker))
{
aiLevel = getIntObjVar(attacker, "intCombatDifficulty");
}
obj_id defenderGroup = getGroupObject(defender);
if (group.isGroupObject(defenderGroup))
{
defenderLevel = getGroupObjectLevel(defenderGroup);
}
int buffBonus = getEnhancedSkillStatisticModifier(defender, "private_relative_level_mod");
defenderLevel += buffBonus;
return (aiLevel - defenderLevel);
}
public static float getConBalanceScalar(int levelDiff) throws InterruptedException
{
float scale = (Math.abs(levelDiff) + AI_CON_SCALE_MULT) / (10.0f + AI_CON_SCALE_MULT);
return scale;
}
public static int getWeaponDamage(obj_id objAttacker, obj_id objDefender, weapon_data cbtWeaponData, int intAttackerRoll, int intDefenderRoll) throws InterruptedException
{
int intFinalDamage = 0;
float fltMinDamage = cbtWeaponData.minDamage;
float fltMaxDamage = cbtWeaponData.maxDamage;
if (!isPlayer(objAttacker))
{
if (intAttackerRoll > intDefenderRoll)
{
return getAiDamage(objAttacker, objDefender, fltMinDamage, fltMaxDamage);
}
else
{
return (int)rand(fltMinDamage, fltMinDamage + (fltMaxDamage - fltMinDamage));
}
}
if (intAttackerRoll > intDefenderRoll)
{
int intDamage = (int)rand(fltMinDamage + (fltMaxDamage - fltMinDamage), fltMaxDamage);
return intDamage;
}
else
{
int intDamage = (int)(rand(fltMinDamage, fltMinDamage + (fltMaxDamage - fltMinDamage)));
return intDamage;
}
}
public static int getAiDamage(obj_id attacker, obj_id defender, float minDamage, float maxDamage) throws InterruptedException
{
if (!isPlayer(attacker))
{
int levelDiff = getAiLevelDiff(attacker, defender);
combatLog(attacker, defender, "modifyAiRawDamage", "AI Level diff = " + levelDiff);
float levelDiffMod = levelDiff * getConBalanceScalar(levelDiff);
if (levelDiffMod < 0)
{
float damageMod = 1.0f + (levelDiffMod / 10.0f);
combatLog(attacker, defender, "modifyAiRawDamage", "AI Damage Mod = " + damageMod);
float minCap = minDamage / 2.0f;
float maxCap = maxDamage / 2.0f;
combatLog(attacker, defender, "modifyAiRawDamage", "Min Cap = " + minCap);
combatLog(attacker, defender, "modifyAiRawDamage", "Max Cap = " + maxCap);
minDamage *= damageMod;
maxDamage *= damageMod;
if (minDamage < minCap)
{
minDamage = minCap;
}
if (maxDamage < maxCap)
{
maxDamage = maxCap;
}
}
else
{
float maxDmgMod = 1.0f + (levelDiffMod / 10.0f);
combatLog(attacker, defender, "modifyAiRawDamage", "AI Max Damage Mod = " + maxDmgMod);
maxDamage *= maxDmgMod;
maxDamage += levelDiff;
float minDmgMod = 1.0f + (levelDiffMod / (10.0f / levelDiff));
combatLog(attacker, defender, "modifyAiRawDamage", "AI Min Damage Mod = " + minDmgMod);
minDamage *= minDmgMod;
float minCap = maxDamage / 2.0f;
if (minDamage > minCap)
{
minDamage = minCap;
}
}
combatLog(attacker, defender, "modifyAiRawDamage", "New Min Damage = " + minDamage);
combatLog(attacker, defender, "modifyAiRawDamage", "New Max Damage = " + maxDamage);
}
if (utils.checkConfigFlag("ScriptFlags", "e3Demo"))
{
if (isPlayer(defender))
{
int intCurrentHP = getHealth(defender);
int intMaxHP = getMaxHealth(defender);
if ((minDamage > intMaxHP) || (maxDamage > intMaxHP) || (intCurrentHP < (intMaxHP / 2)))
{
minDamage = 1;
maxDamage = 5;
}
}
}
int intDamage = (int)rand(minDamage, maxDamage);
return intDamage;
}
public static void assignDamageCredit(obj_id attacker, obj_id defender, weapon_data weaponData, int damage) throws InterruptedException
{
String xpType = xp.getWeaponXpType(weaponData.weaponType);
if (!isPlayer(attacker))
{
if (pet_lib.isPet(attacker))
{
obj_id master = getMaster(attacker);
if (ai_lib.isMonster(attacker) && isIdValid(master) && hasSkill(master, "outdoors_creaturehandler_novice"))
{
xp.updateCombatXpList(defender, master, xp.CREATUREHANDLER, damage);
xp.updateCombatXpList(defender, attacker, xp.CREATUREHANDLER, damage);
return;
}
else if (isIdValid(master) && !beast_lib.isBeast(attacker))
{
xp.updateCombatXpList(defender, master, xp.PET_DAMAGE, damage);
xp.updateCombatXpList(defender, attacker, xpType, damage);
return;
}
}
}
xp.updateCombatXpList(defender, attacker, xpType, damage);
}
public static boolean expertiseRandomBuffChance(obj_id attacker, combat_data actionData) throws InterruptedException
{
String specialLine = actionData.specialLine;
if (getSkillStatisticModifier(attacker, "expertise_use_buff_chance_line_" + specialLine) > 0 || getSkillStatisticModifier(attacker, "private_use_buff_chance_line_" + specialLine) > 0)
{
int chance = getSkillStatisticModifier(attacker, "expertise_buff_chance_line_" + specialLine);
if (rand(0, 99) > chance)
{
return false;
}
}
return true;
}
public static boolean applyDefenderCombatBuffs(obj_id attacker, obj_id defender, weapon_data weaponData, combat_data actionData) throws InterruptedException
{
String actionName = actionData.actionName;
String buffName = actionData.buffNameTarget;
float buffStrength = actionData.buffStrengthTarget;
float buffDuration = actionData.buffDurationTarget;
if (buffName == null || buffName.equals(""))
{
return false;
}
if (!expertiseRandomBuffChance(attacker, actionData))
{
return false;
}
combatLog(attacker, defender, "applyDefenderCombatBuffs", "Applying defender buff - " + buffName);
String effectName = buff.getEffectParam(buffName, 2);
if (effectName.equals("dot"))
{
effectName = buff.getEffectParam(buffName, 1);
String type = effectName.substring((effectName.lastIndexOf("_") + 1), effectName.length());
if (dot.attemptDotResist(defender, type, 100, true))
{
return false;
}
if (!dot.canApplyDotType(defender, type))
{
return false;
}
}
buffDuration += getExpertiseBuffDurationMods(attacker, actionData, buffName, buffDuration);
return buff.applyBuff(defender, attacker, buffName, buffDuration, buffStrength);
}
public static boolean applyAttackerCombatBuffs(obj_id attacker, combat_data actionData) throws InterruptedException
{
String actionName = actionData.actionName;
String buffName = actionData.buffNameSelf;
float buffStrength = actionData.buffStrengthSelf;
float buffDuration = actionData.buffDurationSelf;
if (buffName == null || buffName.equals(""))
{
return false;
}
if (!expertiseRandomBuffChance(attacker, actionData))
{
return false;
}
combatLog(attacker, null, "applyAttackerCombatBuffs", "Applying attacker buff - " + buffName);
buffDuration += getExpertiseBuffDurationMods(attacker, actionData, buffName, buffDuration);
return buff.applyBuff(attacker, attacker, buffName, buffDuration, buffStrength);
}
public static float getExpertiseBuffDurationMods(obj_id buffCaster, combat_data actionData, String buffName, float buffDuration) throws InterruptedException
{
float expertiseBuffDurationMod = 0.0f;
dictionary dic = dataTableGetRow(buff.BUFF_TABLE, buffName);
if (dic == null)
{
return expertiseBuffDurationMod;
}
String buffGroupName = dic.getString("GROUP1");
if (buffDuration == 0)
{
buffDuration = dic.getFloat("DURATION");
}
String specialLine = actionData.specialLine;
expertiseBuffDurationMod = buffDuration + getEnhancedSkillStatisticModifierUncapped(buffCaster, "expertise_buff_duration_line_" + specialLine);
expertiseBuffDurationMod += getEnhancedSkillStatisticModifierUncapped(buffCaster, "expertise_buff_duration_group_" + toLower(buffGroupName));
expertiseBuffDurationMod += getEnhancedSkillStatisticModifierUncapped(buffCaster, "expertise_buff_duration_single_" + toLower(buffName));
return expertiseBuffDurationMod;
}
public static boolean applyCombatMovementModifier(obj_id attacker, obj_id defender, String actionName) throws InterruptedException
{
boolean isRoot = movement.isRoot(actionName);
boolean isSnare = movement.isSnare(actionName);
boolean isStun = movement.isStunEffect(actionName);
prose_package pp = new prose_package();
String movementType = "";
if (isRoot)
{
movementType = "root";
}
if (isSnare)
{
movementType = "snare";
}
int lastMovementMod;
if (isPlayer(defender))
{
lastMovementMod = utils.getIntScriptVar(defender, "combat.movement." + movementType + ".time");
}
else
{
lastMovementMod = utils.getIntScriptVar(defender, "combat.movement." + movementType + "." + attacker + ".time");
}
if (lastMovementMod + MOVEMENT_MODIFIER_REUSE_TIME > getGameTime())
{
showCombatText(defender, attacker, new string_id("combat_effects", "no_effect"), 1.5f, colors.WHITE);
return false;
}
if (buff.hasBuff(defender, actionName) || !buff.canApplyBuff(defender, actionName))
{
showCombatText(defender, attacker, new string_id("combat_effects", "no_effect"), 1.5f, colors.WHITE);
return false;
}
if (isStun)
{
pp = prose.setStringId(pp, new string_id("combat_effects", "go_stunned"));
showFlyTextPrivateProseWithFlags(defender, defender, pp, 1.5f, colors.LAWNGREEN, FLY_TEXT_FLAG_IS_SNARE);
playClientEffectObj(defender, "appearance/pt_state_cantmove.prt", defender, "", null, "state_stunned");
playClientEffectObj(defender, "sound/sta_rooted_on.snd", defender, "");
}
else if (isRoot)
{
pp = prose.setStringId(pp, new string_id("combat_effects", "go_rooted"));
showFlyTextPrivateProseWithFlags(defender, defender, pp, 1.5f, colors.LAWNGREEN, FLY_TEXT_FLAG_IS_SNARE);
playClientEffectObj(defender, "appearance/pt_state_cantmove.prt", defender, "", null, "state_rooted");
playClientEffectObj(defender, "sound/sta_rooted_on.snd", defender, "");
}
else if (isSnare)
{
pp = prose.setStringId(pp, new string_id("combat_effects", "go_snare"));
showFlyTextPrivateProseWithFlags(defender, defender, pp, 1.5f, colors.LAWNGREEN, FLY_TEXT_FLAG_IS_SNARE);
playClientEffectObj(defender, "appearance/pt_state_slowedmove.prt", defender, "", null, "state_snared");
playClientEffectObj(defender, "sound/sta_snared_on.snd", defender, "");
}
if (isPlayer(defender))
{
utils.setScriptVar(defender, "combat.movement." + movementType + ".time", getGameTime());
}
else
{
utils.setScriptVar(defender, "combat.movement." + movementType + "." + attacker + ".time", getGameTime());
}
return true;
}
public static void removeCombatMovementModifierEffect(obj_id self, String buffName) throws InterruptedException
{
if (buffName == null || buffName.equals(""))
{
return;
}
boolean isVisible = true;
dictionary buffData = dataTableGetRow("datatables/buff/buff.iff", buffName);
if (buffData != null)
{
isVisible = buffData.getInt("VISIBLE") == 1;
}
prose_package pp = new prose_package();
if (movement.isStunEffect(buffName))
{
if (isVisible)
{
pp = prose.setStringId(pp, new string_id("combat_effects", "no_stunned"));
showFlyTextPrivateProseWithFlags(self, self, pp, 1.5f, colors.TOMATO, FLY_TEXT_FLAG_IS_SNARE);
}
stopClientEffectObjByLabel(self, "state_stunned");
playClientEffectObj(self, "sound/sta_rooted_off.snd", self, "");
}
else if (movement.isRoot(buffName))
{
if (isVisible)
{
pp = prose.setStringId(pp, new string_id("combat_effects", "no_rooted"));
showFlyTextPrivateProseWithFlags(self, self, pp, 1.5f, colors.TOMATO, FLY_TEXT_FLAG_IS_SNARE);
}
stopClientEffectObjByLabel(self, "state_rooted");
playClientEffectObj(self, "sound/sta_rooted_off.snd", self, "");
}
else if (movement.isSnare(buffName) && buff.getDuration(buffName) > 0.0f)
{
if (isVisible)
{
pp = prose.setStringId(pp, new string_id("combat_effects", "no_snare"));
showFlyTextPrivateProseWithFlags(self, self, pp, 1.5f, colors.TOMATO, FLY_TEXT_FLAG_IS_SNARE);
}
stopClientEffectObjByLabel(self, "state_snared");
playClientEffectObj(self, "sound/sta_snared_off.snd", self, "");
}
}
public static void removeCombatBuffEffect(obj_id self, String buffName) throws InterruptedException
{
for (int i = 1; i <= buff.MAX_EFFECTS; i++)
{
int effectType = getStringCrc(buff.getEffectParam(buffName, i));
float effectValue = buff.getEffectValue(buffName, i);
if (effectType == (-1161461455))
{
stopClientEffectObjByLabel(self, "state_slowattack");
playClientEffectObj(self, "sound/sta_slow_off.snd", self, "");
}
}
}
public static boolean gainCombatActionAttribute(obj_id self, int action) throws InterruptedException
{
if (getMaxAction(self) == getAction(self))
{
return false;
}
int newAction = getAction(self) + action;
if (newAction > getMaxAction(self))
{
newAction = getMaxAction(self);
}
setAction(self, newAction);
return true;
}
public static boolean drainCombatActionAttributes(obj_id self, int[] actionCost) throws InterruptedException
{
if (!(drainAttributes(self, actionCost[1], actionCost[2])))
{
return false;
}
return true;
}
public static boolean canDrainCombatActionAttributes(obj_id self, int actionCost) throws InterruptedException
{
int[] tempArray =
{
0,
actionCost,
0
};
return canDrainCombatActionAttributes(self, tempArray);
}
public static boolean canDrainCombatActionAttributes(obj_id self, int[] actionCost) throws InterruptedException
{
if (actionCost[1] > 0)
{
if (testDrainAttribute(self, ACTION, actionCost[1]) < 0)
{
return false;
}
}
return true;
}
public static final int ACTION_SUCCESS = 0;
public static final int ACTION_INVALID_DATA = 1;
public static final int ACTION_INVALID_WEAPON = 2;
public static final int ACTION_TOO_TIRED = 3;
public static int canPerformAction(String actionName, obj_id self) throws InterruptedException
{
actionName = getBestAction(self, actionName);
combat_data actionData = combat_engine.getCombatData(actionName);
if (actionData == null)
{
return ACTION_INVALID_DATA;
}
weapon_data weaponData = new weapon_data();
weaponData = weapons.getNewWeaponData(getCurrentWeapon(self));
if (!canUseWeaponWithAbility(self, weaponData, actionData, true))
{
return ACTION_INVALID_WEAPON;
}
int[] actionCost = getActionCost(self, weaponData, actionData);
if (!canDrainCombatActionAttributes(self, actionCost))
{
return ACTION_TOO_TIRED;
}
return ACTION_SUCCESS;
}
public static boolean isCommandoBonus(obj_id self, weapon_data weaponData, int commandType) throws InterruptedException
{
return isPlayer(self) && utils.isProfession(self, utils.COMMANDO) && isHeavyWeapon(weaponData) && (commandType == LEFT_CLICK_DEFAULT);
}
public static int[] getActionCost(obj_id self, weapon_data weaponData, dictionary actionData) throws InterruptedException
{
int[] cost = new int[3];
float healthCost = 0;
float actionCost;
float mindCost;
actionCost = actionData.getFloat("actionCost");
if (isCommandoBonus(self, weaponData, actionData.getInt("commandType")))
{
cost[0] = (int)(0);
cost[1] = (int)(0);
cost[2] = (int)(0);
return cost;
}
String specialLine = actionData.getString("specialLine");
String actionName = actionData.getString("actionName");
int freeshotChance = getEnhancedSkillStatisticModifierUncapped(self, "expertise_freeshot_" + specialLine);
prose_package pp = new prose_package();
if (freeshotChance > 0)
{
int roll = rand(1, 100) + freeshotChance;
if (roll > 100)
{
actionCost = 0;
pp = prose.setStringId(pp, new string_id("spam", "freeshot"));
showFlyTextPrivateProseWithFlags(self, self, pp, 1.5f, colors.LEMONCHIFFON, FLY_TEXT_FLAG_IS_FREESHOT);
pp = prose.setStringId(pp, new string_id("cbt_spam", "freeshot"));
pp = prose.setTU(pp, self);
sendCombatSpamMessageProse(self, self, pp, true, true, true, COMBAT_RESULT_GENERIC);
cost[0] = (int)(0);
cost[1] = (int)(0);
cost[2] = (int)(0);
return cost;
}
}
if (actionCost > 0)
{
float expertiseActionCostMod = 0;
float percentAddFromWeapon = actionData.getFloat("percentAddFromWeapon");
if (percentAddFromWeapon > 0.0f)
{
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_weapon_" + weaponData.weaponType);
if (isMeleeWeapon(weaponData.id))
{
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_weapon_melee");
}
if (isRangedWeapon(weaponData.id))
{
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_weapon_ranged");
}
}
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_all");
if (specialLine != null && !specialLine.equals(""))
{
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_line_" + specialLine);
}
if (actionName != null && !actionName.equals(""))
{
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_single_" + actionName);
}
switch (weaponData.weaponType)
{
case WEAPON_TYPE_PISTOL:
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_pistol");
break;
case WEAPON_TYPE_RIFLE:
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_rifle");
break;
case WEAPON_TYPE_LIGHT_RIFLE:
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_carbine");
break;
case WEAPON_TYPE_HEAVY:
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_heavy");
break;
case WEAPON_TYPE_GROUND_TARGETTING:
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_heavy");
break;
case WEAPON_TYPE_DIRECTIONAL:
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_heavy");
break;
case WEAPON_TYPE_1HAND_MELEE:
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_1h");
break;
case WEAPON_TYPE_2HAND_MELEE:
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_2h");
break;
case WEAPON_TYPE_UNARMED:
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_unarmed");
break;
case WEAPON_TYPE_POLEARM:
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_polearm");
break;
case WEAPON_TYPE_WT_1HAND_LIGHTSABER:
case WEAPON_TYPE_WT_2HAND_LIGHTSABER:
case WEAPON_TYPE_WT_POLEARM_LIGHTSABER:
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_lightsaber");
break;
}
actionCost = actionCost - (actionCost * (expertiseActionCostMod / 100.0f));
if (actionCost < 0)
{
actionCost = 0;
}
}
if (actionCost < 0)
{
float expertiseActionCostMod = 0;
int actionTotal = getLevel(self) * 100;
actionCost = actionTotal * (float)(-1.0f * ((float)actionCost / 100.0f));
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_all");
if (specialLine != null && !specialLine.equals(""))
{
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_line_" + specialLine);
}
if (actionName != null && !actionName.equals(""))
{
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_single_" + actionName);
}
actionCost = actionCost * (1 - (expertiseActionCostMod / 100));
}
if (utils.hasScriptVar(self, "buff.action_burn.value") && actionCost > 0)
{
int rightNow = getGameTime();
int timestamp = utils.getIntScriptVar(self, "buff.action_burn.timestamp");
if (rightNow > timestamp)
{
utils.setScriptVar(self, "buff.action_burn.timestamp", rightNow);
float burnRatio = utils.getFloatScriptVar(self, "buff.action_burn.value");
float actionBurn = (float)actionCost * (burnRatio / 100);
int currentHealth = getHealth(self);
int modifiedHealth = currentHealth - (int)actionBurn;
if (modifiedHealth < 1)
{
modifiedHealth = 1;
}
int[] burnBuffs = buff.getAllBuffsByEffect(self, "action_burn");
obj_id burnBuffOwner = self;
if (burnBuffs.length > 0 && utils.hasScriptVar(self, "buffOwner." + burnBuffs[0]))
{
burnBuffOwner = utils.getObjIdScriptVar(self, "buffOwner." + burnBuffs[0]);
}
setHealth(self, modifiedHealth);
pp = prose.setStringId(pp, new string_id("spam", "crippling_pain"));
showFlyTextPrivateProseWithFlags(self, burnBuffOwner, pp, 1.5f, colors.ORANGERED, FLY_TEXT_FLAG_IS_CRITICAL_HIT);
pp = prose.setStringId(pp, new string_id("cbt_spam", "crippling_pain"));
pp = prose.setTU(pp, self);
pp = prose.setDI(pp, (int)actionBurn);
sendCombatSpamMessageProse(self, burnBuffOwner, pp, true, true, true, COMBAT_RESULT_DEBUFF);
}
}
cost[0] = (int)(0);
cost[1] = (int)(actionCost);
cost[2] = (int)(0);
return cost;
}
public static int[] getActionCost(obj_id self, weapon_data weaponData, combat_data actionData) throws InterruptedException
{
int[] cost = new int[3];
float healthCost = 0;
float actionCost;
float mindCost;
actionCost = actionData.actionCost;
if (isCommandoBonus(self, weaponData, actionData.commandType))
{
cost[0] = (int)(0);
cost[1] = (int)(0);
cost[2] = (int)(0);
return cost;
}
if (beast_lib.isBeast(self))
{
cost[0] = 0;
cost[1] = (int)actionData.vigorCost;
cost[2] = 0;
return cost;
}
String specialLine = actionData.specialLine;
String actionName = actionData.actionName;
int freeshotChance = getEnhancedSkillStatisticModifierUncapped(self, "expertise_freeshot_" + specialLine);
prose_package pp = new prose_package();
if (freeshotChance > 0)
{
int roll = rand(1, 100) + freeshotChance;
if (roll > 100)
{
actionCost = 0;
pp = prose.setStringId(pp, new string_id("spam", "freeshot"));
showFlyTextPrivateProseWithFlags(self, self, pp, 1.5f, colors.LEMONCHIFFON, FLY_TEXT_FLAG_IS_FREESHOT);
pp = prose.setStringId(pp, new string_id("cbt_spam", "freeshot"));
pp = prose.setTU(pp, self);
sendCombatSpamMessageProse(self, self, pp, true, true, true, COMBAT_RESULT_GENERIC);
cost[0] = (int)(0);
cost[1] = (int)(0);
cost[2] = (int)(0);
return cost;
}
}
if (actionCost > 0)
{
float expertiseActionCostMod = 0;
if (actionData.percentAddFromWeapon > 0.0f)
{
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_weapon_" + weaponData.weaponType);
if (isMeleeWeapon(weaponData.id))
{
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_weapon_melee");
}
if (isRangedWeapon(weaponData.id))
{
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_weapon_ranged");
}
}
if (actionData.hitType == HEAL)
{
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "exotic_heal_action_reduction");
}
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_all");
if (specialLine != null && !specialLine.equals(""))
{
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_line_" + specialLine);
}
if (actionName != null && !actionName.equals(""))
{
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_single_" + actionName);
}
switch (weaponData.weaponType)
{
case WEAPON_TYPE_PISTOL:
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_pistol");
break;
case WEAPON_TYPE_RIFLE:
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_rifle");
break;
case WEAPON_TYPE_LIGHT_RIFLE:
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_carbine");
break;
case WEAPON_TYPE_HEAVY:
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_heavy");
break;
case WEAPON_TYPE_GROUND_TARGETTING:
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_heavy");
break;
case WEAPON_TYPE_DIRECTIONAL:
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_heavy");
break;
case WEAPON_TYPE_1HAND_MELEE:
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_1h");
break;
case WEAPON_TYPE_2HAND_MELEE:
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_2h");
break;
case WEAPON_TYPE_UNARMED:
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_unarmed");
break;
case WEAPON_TYPE_POLEARM:
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_polearm");
break;
case WEAPON_TYPE_WT_1HAND_LIGHTSABER:
case WEAPON_TYPE_WT_2HAND_LIGHTSABER:
case WEAPON_TYPE_WT_POLEARM_LIGHTSABER:
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_lightsaber");
break;
}
actionCost = actionCost - (actionCost * (expertiseActionCostMod / 100.0f));
if (actionCost < 0)
{
actionCost = 0;
}
}
if (actionCost < 0)
{
float expertiseActionCostMod = 0;
int actionTotal = getLevel(self) * 100;
actionCost = actionTotal * (float)(-1.0f * ((float)actionCost / 100.0f));
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_all");
if (specialLine != null && !specialLine.equals(""))
{
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_line_" + specialLine);
}
if (actionName != null && !actionName.equals(""))
{
expertiseActionCostMod += getEnhancedSkillStatisticModifierUncapped(self, "expertise_action_single_" + actionName);
}
actionCost = actionCost * (1 - (expertiseActionCostMod / 100));
}
if (utils.hasScriptVar(self, "buff.action_burn.value") && actionCost > 0)
{
int rightNow = getGameTime();
int timestamp = utils.getIntScriptVar(self, "buff.action_burn.timestamp");
if (rightNow > timestamp)
{
utils.setScriptVar(self, "buff.action_burn.timestamp", rightNow);
float burnRatio = utils.getFloatScriptVar(self, "buff.action_burn.value");
float actionBurn = (float)actionCost * (burnRatio / 100);
int currentHealth = getHealth(self);
int modifiedHealth = currentHealth - (int)actionBurn;
if (modifiedHealth < 1)
{
modifiedHealth = 1;
}
setHealth(self, modifiedHealth);
int[] burnBuffs = buff.getAllBuffsByEffect(self, "action_burn");
obj_id burnBuffOwner = self;
if (burnBuffs.length > 0 && utils.hasScriptVar(self, "buffOwner." + burnBuffs[0]))
{
burnBuffOwner = utils.getObjIdScriptVar(self, "buffOwner." + burnBuffs[0]);
}
pp = prose.setStringId(pp, new string_id("spam", "crippling_pain"));
showFlyTextPrivateProseWithFlags(self, burnBuffOwner, pp, 1.5f, colors.ORANGERED, FLY_TEXT_FLAG_IS_CRITICAL_HIT);
pp = prose.setStringId(pp, new string_id("cbt_spam", "crippling_pain"));
pp = prose.setTU(pp, self);
pp = prose.setDI(pp, (int)actionBurn);
sendCombatSpamMessageProse(self, burnBuffOwner, pp, true, true, true, COMBAT_RESULT_DEBUFF);
}
}
cost[0] = (int)(0);
cost[1] = (int)(actionCost);
cost[2] = (int)(0);
combatLog(self, null, "getActionCost", "Final Action cost = [" + cost[0] + ", " + cost[1] + ", " + cost[2] + "]");
return cost;
}
public static int getForceCost(obj_id self, weapon_data weaponData, dictionary actionData) throws InterruptedException
{
return 0;
}
public static int getForceCost(obj_id self, weapon_data weaponData, combat_data actionData) throws InterruptedException
{
return 0;
}
public static boolean validateTarget(obj_id target, int targetCheck) throws InterruptedException
{
obj_id self = getSelf();
if (!storyteller.storytellerCombatCheck(self, target))
{
return false;
}
switch (targetCheck)
{
case VALID_TARGET_MOB:
return isMob(target) && !vehicle.isVehicle(target);
case VALID_TARGET_CREATURE:
return ai_lib.isMonster(target);
case VALID_TARGET_NPC:
return ai_lib.isNpc(target);
case VALID_TARGET_DROID:
return ai_lib.isDroid(target) || ai_lib.isAndroid(target);
case VALID_TARGET_PVP:
return pvpCanAttack(self, target);
case VALID_TARGET_JEDI:
if (isPlayer(target))
{
return isJedi(target);
}
else
{
return jedi.isLightsaber(getCurrentWeapon(target));
}
case VALID_TARGET_DEAD:
return isDead(target);
case VALID_TARGET_FRIEND:
return pvpCanHelp(self, target);
}
return true;
}
public static String getCreatureAnimationName(obj_id self, String playbackName, hit_result hitData, weapon_data weaponData) throws InterruptedException
{
String animName = "";
int niche = ai_lib.aiGetNiche(self);
if (niche == NICHE_VEHICLE)
{
animName = "droid_attack";
}
else
{
if (playbackName.endsWith("ranged"))
{
animName = "creature_attack_ranged";
}
else if (playbackName.endsWith("melee"))
{
animName = "creature_attack";
}
else
{
animName = "creature_attack_special_" + rand(1, 2);
}
}
int avgDamage = (weaponData.minDamage + weaponData.maxDamage) / 2;
if (hitData.damage > avgDamage)
{
animName += "_medium";
}
else
{
animName += "_light";
}
return animName;
}
public static boolean checkWeaponCerts(obj_id player, weapon_data weaponData) throws InterruptedException
{
return checkWeaponCerts(player, weaponData, true);
}
public static boolean checkWeaponCerts(obj_id player, weapon_data weaponData, boolean verbose) throws InterruptedException
{
if (!isPlayer(player))
{
return true;
}
if (!combat.hasCertification(player, weaponData.id, verbose))
{
return false;
}
if (utils.isProfession(player, utils.FORCE_SENSITIVE))
{
if (jedi.isLightsaber(weaponData.weaponType))
{
if (!jedi.hasColorCrystal(weaponData.id))
{
return false;
}
if (!jedi.validateCrystalCount(weaponData.id))
{
return false;
}
}
if (buff.hasBuff(player, "forceRun_1") || buff.hasBuff(player, "forceRun_2"))
{
return false;
}
}
return true;
}
public static int applyArmorProtection(obj_id attacker, obj_id defender, weapon_data weaponData, hit_result hitData, float bypassArmor) throws InterruptedException
{
return applyArmorProtection(attacker, defender, weaponData, hitData, bypassArmor, 0.0f);
}
public static int applyArmorProtection(obj_id attacker, obj_id defender, weapon_data weaponData, hit_result hitData, float bypassArmor, float expertiseDamageBonus) throws InterruptedException
{
float baseDamage = hitData.damage;
float elementalDamage = weaponData.elementalValue;
float baseProtection = 0.0f;
float elementalProtection = 0.0f;
float basePsgProtection = 0.0f;
float elementalPsgProtection = 0.0f;
boolean strikethrough = hitData.strikethrough;
int armor_neglect = getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_armor_neglect");
int player_armor_reduction = getEnhancedSkillStatisticModifierUncapped(defender, "expertise_innate_reduction_all_player");
float neglectMod = 1.0f - (armor_neglect / 100.0f);
float playerMod = 1.0f - (player_armor_reduction / 100.0f);
obj_id armorPiece = null;
obj_id psg = null;
if (isPlayer(defender))
{
boolean isRanged = isRangedWeapon(weaponData.weaponType);
psg = getPsgArmor(defender);
if (isIdValid(defender) || isIdValid(psg))
{
float[] psgProtectionReference = new float[1];
baseProtection = getArmorProtection(defender, defender, psg, weaponData.damageType, psgProtectionReference);
baseProtection *= neglectMod;
baseProtection *= playerMod;
if (isRanged)
{
basePsgProtection = psgProtectionReference[0];
}
elementalProtection = getArmorProtection(defender, defender, psg, weaponData.elementalType, psgProtectionReference, attacker);
if (isRanged)
{
elementalPsgProtection = psgProtectionReference[0];
}
if (isRanged)
{
if (basePsgProtection > 0 || elementalPsgProtection > 0)
{
int psgLevel = armor.getArmorLevel(psg);
if (psgLevel < 0 || psgLevel >= armor.PSG_HIT_EFFECTS.length)
{
psgLevel = 0;
}
playClientEffectObj(defender, armor.PSG_HIT_EFFECTS[psgLevel], defender, "", transform.identity);
}
}
}
}
else
{
baseProtection = getNpcArmorProtection(defender, weaponData.damageType);
baseProtection *= neglectMod;
elementalProtection = getNpcArmorProtection(defender, weaponData.elementalType);
}
if (bypassArmor == 0 && strikethrough)
{
float strikethroughRating = (float)(getStrikethroughValue(attacker, defender) / 100.0f);
bypassArmor = rand(strikethroughRating / 2.0f, strikethroughRating);
hitData.strikethroughAmmount = bypassArmor * 100.0f;
}
if (bypassArmor > 0)
{
if (bypassArmor > 1.0)
{
bypassArmor = 1.0f;
}
if (bypassArmor < 0.0)
{
bypassArmor = 0.0f;
}
}
baseProtection *= 1.0 - bypassArmor;
elementalProtection *= 1.0 - bypassArmor;
if (basePsgProtection > 0)
{
basePsgProtection = scalePsgProtectionByBaseProtection(basePsgProtection, baseProtection);
}
int baseDmgAbsorbed = (int)(baseDamage * (baseProtection + basePsgProtection));
baseDamage -= baseDmgAbsorbed;
int blockValue = 0;
if (hitData.blockResult)
{
blockValue = combat.getBlockAmmount(defender);
if (baseDamage <= blockValue)
{
hitData.block = (int)baseDamage;
baseDamage = 0.0f;
}
else
{
baseDamage -= blockValue;
hitData.block = blockValue;
}
string_id critSpam = new string_id("combat_effects", "block");
prose_package pp = new prose_package();
pp = prose.setStringId(pp, critSpam);
pp = prose.setDI(pp, hitData.block);
showFlyTextPrivateProseWithFlags(defender, defender, pp, 1.5f, colors.LIMEGREEN, FLY_TEXT_FLAG_IS_GLANCING_BLOW);
showFlyTextPrivateProseWithFlags(defender, attacker, pp, 1.5f, colors.LIMEGREEN, FLY_TEXT_FLAG_IS_GLANCING_BLOW);
}
if (baseDamage < 0)
{
baseDmgAbsorbed += baseDamage;
baseDamage = 0;
}
if (expertiseDamageBonus != 0)
{
elementalDamage = elementalDamage * (1.0f + (expertiseDamageBonus / 100.0f));
}
int elementalDmgAbsorbed = (int)(elementalDamage * (elementalProtection));
elementalDamage -= elementalDmgAbsorbed;
if (elementalDamage < 0)
{
elementalDmgAbsorbed += elementalDamage;
elementalDamage = 0;
}
if ((basePsgProtection > 0 || elementalPsgProtection > 0) && isIdValid(psg))
{
decayArmorPiece(psg, baseDamage * basePsgProtection + elementalDamage * elementalPsgProtection);
}
hitData.elementalDamage = (int)elementalDamage;
hitData.elementalDamageType = weaponData.elementalType;
hitData.damage = (int)baseDamage;
if ((baseProtection > 0 || elementalProtection > 0) && isIdValid(armorPiece))
{
hitData.blockingArmor = armorPiece;
}
else if ((basePsgProtection > 0 || elementalPsgProtection > 0) && isIdValid(psg))
{
hitData.blockingArmor = psg;
}
return (baseDmgAbsorbed + elementalDmgAbsorbed);
}
public static float scalePsgProtectionByBaseProtection(float basePsgProtection, float baseProtection) throws InterruptedException
{
if (baseProtection < 0.2f)
{
baseProtection = 0.2f;
}
basePsgProtection *= 10000;
basePsgProtection = (basePsgProtection / 100) / (100 + ((basePsgProtection / 100))) / (baseProtection * 4);
return basePsgProtection;
}
public static obj_id getArmorPieceHit(obj_id defender, int hitLocation) throws InterruptedException
{
String[] armorSlots = ARMOR_SLOT_LOCATIONS[hitLocation];
String slotHit = armorSlots[rand(0, armorSlots.length - 1)];
obj_id armorPiece = getObjectInSlot(defender, slotHit);
int armorType = getGameObjectType(armorPiece);
if (isGameObjectTypeOf(armorType, GOT_armor))
{
return armorPiece;
}
return null;
}
public static obj_id getPsgArmor(obj_id defender) throws InterruptedException
{
obj_id psg = getObjectInSlot(defender, PSG_SLOT_LOCATION);
if (armor.isPsg(psg))
{
return psg;
}
return null;
}
public static float getNpcArmorProtection(obj_id defender, int damageType) throws InterruptedException
{
int generalProtection = 0;
dictionary protections = null;
generalProtection = armor.getArmorGeneralProtection(defender);
generalProtection += getEnhancedSkillStatisticModifier(defender, "private_armor_bonus");
generalProtection -= getEnhancedSkillStatisticModifierUncapped(defender, "expertise_innate_reduction_all_mob");
if (generalProtection == 0 && protections == null)
{
return 0.0f;
}
if (utils.hasScriptVar(defender, "ai.combat.genProtectionBonus"))
{
generalProtection += (int)utils.getFloatScriptVar(defender, "ai.combat.genProtectionBonus");
}
float armorProtection = convertProtectionToPercent(generalProtection);
return armorProtection;
}
public static float getArmorProtection(obj_id defender, obj_id armorPiece, obj_id psg, int damageType, float[] psgProtectionResult) throws InterruptedException
{
return getArmorProtection(defender, armorPiece, psg, damageType, psgProtectionResult, obj_id.NULL_ID);
}
public static float getArmorProtection(obj_id defender, obj_id armorPiece, obj_id psg, int damageType, float[] psgProtectionResult, obj_id attacker) throws InterruptedException
{
int generalProtection = 0;
int armorBonus = getEnhancedSkillStatisticModifier(defender, "private_armor_bonus");
generalProtection += armorBonus;
dictionary protections = null;
dictionary psgProtections = null;
if (isIdValid(armorPiece))
{
generalProtection = armor.getCombatArmorGeneralProtection(armorPiece);
protections = armor.getCombatArmorSpecialProtections(armorPiece);
}
if (isIdValid(psg))
{
psgProtections = armor.getPsgSpecialProtections(psg);
}
if (generalProtection == 0 && protections == null && psgProtections == null)
{
return 0.0f;
}
String damageString = null;
switch (damageType)
{
case DAMAGE_KINETIC:
damageString = "kinetic";
break;
case DAMAGE_ENERGY:
damageString = "energy";
break;
case DAMAGE_BLAST:
damageString = "blast";
break;
case DAMAGE_STUN:
damageString = "stun";
break;
case DAMAGE_RESTRAINT:
damageString = "lightsaber";
break;
case DAMAGE_ELEMENTAL_HEAT:
damageString = "heat";
break;
case DAMAGE_ELEMENTAL_COLD:
damageString = "cold";
break;
case DAMAGE_ELEMENTAL_ACID:
damageString = "acid";
break;
case DAMAGE_ELEMENTAL_ELECTRICAL:
damageString = "electricity";
break;
case DAMAGE_ENVIRONMENTAL_ELECTRICAL:
damageString = "electricity";
break;
default:
break;
}
float value = generalProtection;
float psgValue = 0;
if (damageString != null)
{
if (protections != null)
{
value += protections.getFloat(damageString);
}
if (psgProtections != null)
{
psgValue = psgProtections.getFloat(damageString);
if (psgValue != 0)
{
if (psgProtectionResult != null && psgProtectionResult.length > 0)
{
psgProtectionResult[0] = psgValue / 10000.0f;
}
}
}
}
if (isIdValid(attacker) && damageString != null && damageString.length() > 0)
{
float elementalPenetration = getElementalPenetration(attacker, damageString);
if (elementalPenetration > 0)
{
value *= elementalPenetration;
}
}
value = convertProtectionToPercent(value);
return value;
}
public static float getTerasKasiProtection(obj_id defender) throws InterruptedException
{
if (utils.getIntScriptVar(defender, armor.SCRIPTVAR_ARMOR_COUNT) > 0)
{
return 0.0f;
}
float protection = 0.0f;
float tkaArmor = 0.0f;
float jediArmor = 0.0f;
protection = getEnhancedSkillStatisticModifier(defender, "clothing_armor");
if (hasSkill(defender, "combat_unarmed_novice"))
{
tkaArmor = getSkillStatisticModifier(defender, "tka_armor");
}
if (tkaArmor > protection)
{
protection = tkaArmor;
}
if (hasSkill(defender, "force_title_jedi_novice"))
{
jediArmor = getSkillStatisticModifier(defender, "jedi_armor");
}
if (jediArmor > protection)
{
protection = jediArmor;
}
protection *= 100.0f;
int armorBonus = getEnhancedSkillStatisticModifier(defender, "private_armor_bonus");
protection += armorBonus;
return protection;
}
public static float convertProtectionToPercent(float protection) throws InterruptedException
{
final int reductionThreshold = 2000;
if (protection <= reductionThreshold && protection >= (-1 * reductionThreshold))
{
return protection / 10000.0f;
}
if (protection < 0)
{
protection += reductionThreshold;
protection = protection / (100.0f - (protection / 100.0f));
protection = -0.2f + (protection / 100.0f);
}
else
{
protection -= reductionThreshold;
protection = protection / (100.0f + (protection / 100.0f));
protection = 0.2f + (protection / 100.0f);
}
return protection;
}
public static float getArmorDecayPercentage(obj_id armorPiece) throws InterruptedException
{
float ARMOR_REDUCTION_THRESHOLD = 0.5f;
float reduction = 1.0f;
float hp = getHitpoints(armorPiece);
float maxhp = getMaxHitpoints(armorPiece);
float decayLevel = hp / maxhp;
if (hasObjVar(armorPiece, "slice.resilience"))
{
int resilience = getIntObjVar(armorPiece, "slice.resilience");
ARMOR_REDUCTION_THRESHOLD -= resilience / 100.0f;
}
if (decayLevel < ARMOR_REDUCTION_THRESHOLD)
{
reduction = 1.0f - (ARMOR_REDUCTION_THRESHOLD - decayLevel);
}
return reduction;
}
public static float reduceArmorProtectionFromDecay(obj_id armorPiece, float value) throws InterruptedException
{
float ARMOR_REDUCTION_THRESHOLD = 0.5f;
float hp = getHitpoints(armorPiece);
float maxhp = getMaxHitpoints(armorPiece);
float decayLevel = hp / maxhp;
if (hasObjVar(armorPiece, "slice.resilience"))
{
int resilience = getIntObjVar(armorPiece, "slice.resilience");
ARMOR_REDUCTION_THRESHOLD -= resilience / 100.0f;
}
if (decayLevel < ARMOR_REDUCTION_THRESHOLD)
{
float reduction = 1.0f - (ARMOR_REDUCTION_THRESHOLD - decayLevel);
value *= reduction;
}
return value;
}
public static void decayArmorPiece(obj_id armorPiece, float newDamage) throws InterruptedException
{
if (armor.isPsg(armorPiece))
{
dictionary protections = armor.getArmorSpecialProtections(armorPiece);
float maxEffectiveness = (Float) (((protections.values()).iterator()).next());
if (maxEffectiveness > 0)
{
float effectivenessReduction = PSG_BASE_DMG_PER_HIT + (newDamage / PSG_DAMAGE_SCALE);
float efficiencyReduction = effectivenessReduction / maxEffectiveness;
float currentEfficiency = armor.getPsgEfficiency(armorPiece);
currentEfficiency -= efficiencyReduction;
armor.setPsgEfficiency(armorPiece, currentEfficiency);
}
}
if (utils.isAntiDecay(armorPiece))
{
return;
}
if (static_item.isStaticItem(armorPiece))
{
return;
}
}
public static boolean getGrenadeData(obj_id player, weapon_data weaponData, String params, boolean verbose) throws InterruptedException
{
Long lngId;
try
{
lngId = Long.valueOf(params);
}
catch(NumberFormatException err)
{
if (verbose)
{
sendSystemMessage(player, new string_id("cbt_spam", "grenade_bad_param"));
}
return false;
}
obj_id grenade = obj_id.getObjId(lngId.longValue());
if (!isIdValid(grenade))
{
if (verbose)
{
sendSystemMessage(player, new string_id("cbt_spam", "grenade_invalid"));
}
return false;
}
if (getFirstParentInWorld(grenade) != player)
{
if (verbose)
{
sendSystemMessage(player, new string_id("cbt_spam", "grenade_not_owned"));
}
removeObjVar(grenade, "intUsed");
return false;
}
weaponData.id = grenade;
weaponData.weaponName = getNameStringId(grenade);
weaponData.minDamage = getWeaponMinDamage(grenade);
weaponData.maxDamage = getWeaponMaxDamage(grenade);
weaponData.weaponType = WEAPON_TYPE_THROWN;
weaponData.attackType = ATTACK_TYPE_THROWN;
weaponData.damageType = getWeaponDamageType(grenade);
weaponData.elementalType = getWeaponElementalType(grenade);
weaponData.elementalValue = getWeaponElementalValue(grenade);
weaponData.attackSpeed = getWeaponAttackSpeed(grenade);
weaponData.woundChance = getWeaponWoundChance(grenade);
range_info rng = getWeaponRangeInfo(grenade);
weaponData.minRange = rng.minRange;
weaponData.maxRange = rng.maxRange;
weaponData.accuracy = getWeaponAccuracy(grenade);
weaponData.damageRadius = getWeaponDamageRadius(grenade);
weaponData.attackCost = getWeaponAttackCost(grenade);
return true;
}
public static boolean canPaintTarget(obj_id squadLeader, obj_id target) throws InterruptedException
{
if (!isValidId(target))
{
return false;
}
if (!pvpCanAttack(squadLeader, target))
{
return false;
}
obj_id groupId = getGroupObject(squadLeader);
if (!isIdValid(groupId))
{
return false;
}
if (utils.hasScriptVar(groupId, VAR_GROUP_LAST_VOLLEY_TIME))
{
int lastVolley = utils.getIntScriptVar(groupId, VAR_GROUP_LAST_VOLLEY_TIME);
int now = getGameTime();
int interval = now - lastVolley;
if (interval < VOLLEY_INTERVAL)
{
return false;
}
}
obj_id[] groupMembers = getGroupMemberIds(groupId);
if (groupMembers == null || groupMembers.length < 2)
{
return false;
}
return true;
}
public static void doPaintTarget(obj_id squadLeader, obj_id target) throws InterruptedException
{
obj_id groupId = getGroupObject(squadLeader);
obj_id[] groupMembers = getGroupMemberIds(groupId);
if (!hasScript(target, "systems.combat.volleytarget"))
{
attachScript(target, "systems.combat.volleytarget");
}
utils.setScriptVar(groupId, VAR_GROUP_VOLLEY_TARGET, target);
utils.setScriptVar(groupId, VAR_GROUP_LAST_VOLLEY_TIME, getGameTime());
dictionary parms = new dictionary();
parms.put("objGroup", groupId);
messageTo(target, "msgMarkedByGroup", parms, 0, false);
messageTo(target, "msgUnmarkedByGroup", parms, VOLLEY_INTERVAL * 0.7f, false);
playClientEffectObj(groupMembers, "appearance/pt_special_attack_volley_fire.prt", target, "", new transform(), ID_VOLLEY_FIRE_PARTICLE);
}
public static boolean canUseWeaponWithAbility(obj_id self, weapon_data weaponData, combat_data actionData, boolean verbose) throws InterruptedException
{
if (!isIdValid(weaponData.id))
{
return false;
}
if (((actionData.invalidWeapon & weaponTypeToBitValueMap[weaponData.weaponType]) == 0) && ((actionData.validWeapon & weaponTypeToBitValueMap[weaponData.weaponType]) != 0))
{
return true;
}
if (verbose)
{
sendCombatSpamMessage(self, new string_id("cbt_spam", "invalid_weapon"));
sendSystemMessage(self, new string_id("cbt_spam", "invalid_weapon_single"));
}
return false;
}
public static boolean canUseWeaponWithAbility(obj_id self, weapon_data weaponData, String actionName, boolean verbose) throws InterruptedException
{
return canUseWeaponWithAbility(self, weaponData, combat_engine.getCombatData(actionName), verbose);
}
public static void addHateProcess(obj_id attacker, obj_id defender, hit_result hitData, combat_data actionData) throws InterruptedException
{
if (defender == attacker)
{
return;
}
float hateMod = actionData.hateDamageModifier;
int maxHate = actionData.maxHate;
int hateAdd = actionData.hateAdd;
int hateAddTime = actionData.hateAddTime;
int hateReduction = actionData.hateReduce;
if (hitData.success)
{
if (hateReduction < 1)
{
if (maxHate > 0)
{
final float maxHateDamage = getMaxHate(defender);
setHate(defender, attacker, maxHateDamage + maxHate);
}
if (hateAdd > 0 && hateAddTime > 0)
{
addHateDot(defender, attacker, hateAdd, hateAddTime);
}
float totalHateDamage = hitData.damage * hateMod;
if (totalHateDamage > 0.0f)
{
int skillBonus = getEnhancedSkillStatisticModifier(attacker, "private_taunt_bonus");
totalHateDamage += totalHateDamage * (skillBonus / 100.0f);
if (utils.hasScriptVar(attacker, "ai.combat.aggroBonus"))
{
totalHateDamage += totalHateDamage * utils.getFloatScriptVar(attacker, "ai.combat.aggroBonus");
}
if (utils.hasScriptVar(attacker, "ai.combat.aggroBonusFlat"))
{
totalHateDamage += utils.getFloatScriptVar(attacker, "ai.combat.aggroBonusFlat");
}
if (utils.hasScriptVar(attacker, "ai.combat.aggroReduction"))
{
totalHateDamage -= totalHateDamage * utils.getFloatScriptVar(attacker, "ai.combat.aggroReduction");
}
if (buff.hasBuff(attacker, BUFF_HATE_XFER))
{
int hateTransferBonus = getEnhancedSkillStatisticModifier(attacker, "expertise_aggro_channel");
float hateTransfered = totalHateDamage * (hateTransferBonus / 100.0f);
totalHateDamage -= hateTransfered;
obj_id transferTo = utils.getObjIdScriptVar(attacker, buff.AGGRO_TRANSFER_TO);
addHate(defender, transferTo, hateTransfered);
}
addHate(defender, attacker, totalHateDamage);
}
}
else
{
if ((isPlayer(attacker) || beast_lib.isBeast(attacker)) && (isMob(defender) && !beast_lib.isBeast(defender)))
{
float currentHate = getHate(defender, attacker);
currentHate -= hateReduction;
currentHate = currentHate < 1.0f ? 1.0f : currentHate;
setHate(defender, attacker, currentHate);
}
else if ((isMob(attacker) && !beast_lib.isBeast(attacker)) && (isPlayer(defender) || beast_lib.isBeast(defender)))
{
float currentHate = getHate(attacker, defender);
currentHate -= hateReduction;
currentHate = currentHate < 1.0f ? 1.0f : currentHate;
setHate(attacker, defender, currentHate);
}
}
}
else
{
addHate(defender, attacker, 1.0f);
}
if (isPlayer(attacker))
{
addHate(attacker, defender, 0.0f);
{
obj_id[] hateList = getHateList(attacker);
for (obj_id hateTarget : hateList) {
if (!isPlayer(hateTarget) && isTangible(hateTarget)) {
if (getHateTarget(hateTarget) == attacker) {
resetHateTimer(hateTarget);
}
}
}
}
}
}
public static boolean cachedIsRidingVehicle(obj_id attacker) throws InterruptedException
{
String cacheId = "combat.cache.ridingVehicle";
if (hasCachedCombatValue(attacker, cacheId))
{
return getCachedCombatValueBool(attacker, cacheId);
}
boolean ridingVehicle = vehicle.isRidingVehicle(attacker);
setCachedCombatValue(attacker, cacheId, ridingVehicle);
return ridingVehicle;
}
public static boolean cachedIsGalloping(obj_id attacker) throws InterruptedException
{
String cacheId = "combat.cache.galloping";
if (hasCachedCombatValue(attacker, cacheId))
{
return getCachedCombatValueBool(attacker, cacheId);
}
obj_id mount = getMountId(attacker);
boolean galloping = false;
if (isIdValid(mount))
{
galloping = pet_lib.isGalloping(mount);
}
setCachedCombatValue(attacker, cacheId, galloping);
return galloping;
}
public static boolean cachedIsDead(obj_id attacker) throws InterruptedException
{
String cacheId = "combat.cache.isDead";
if (hasCachedCombatValue(attacker, cacheId))
{
return getCachedCombatValueBool(attacker, cacheId);
}
boolean dead = isDead(attacker);
setCachedCombatValue(attacker, cacheId, dead);
return dead;
}
public static boolean cachedIsIncapacitated(obj_id attacker) throws InterruptedException
{
String cacheId = "combat.cache.isIncapped";
if (hasCachedCombatValue(attacker, cacheId))
{
return getCachedCombatValueBool(attacker, cacheId);
}
boolean incapped = isIncapacitated(attacker);
setCachedCombatValue(attacker, cacheId, incapped);
return incapped;
}
public static int cachedGetLocomotion(obj_id attacker) throws InterruptedException
{
String cacheId = "combat.cache.locomotion";
if (hasCachedCombatValue(attacker, cacheId))
{
return getCachedCombatValueInt(attacker, cacheId);
}
int locomotion = getLocomotion(attacker);
setCachedCombatValue(attacker, cacheId, locomotion);
return locomotion;
}
public static float cachedGetMovementSpeed(obj_id attacker) throws InterruptedException
{
String cacheId = "combat.cache.moveSpeed";
if (hasCachedCombatValue(attacker, cacheId))
{
return getCachedCombatValueFloat(attacker, cacheId);
}
float moveSpeed = getMovementSpeed(attacker);
setCachedCombatValue(attacker, cacheId, moveSpeed);
return moveSpeed;
}
public static float cachedGetRunSpeed(obj_id attacker) throws InterruptedException
{
String cacheId = "combat.cache.runSpeed";
if (hasCachedCombatValue(attacker, cacheId))
{
return getCachedCombatValueFloat(attacker, cacheId);
}
float runSpeed = getRunSpeed(attacker);
setCachedCombatValue(attacker, cacheId, runSpeed);
return runSpeed;
}
public static float cachedGetDistance(obj_id attacker, obj_id defender) throws InterruptedException
{
String cacheId = "combat.cache." + defender + ".distance";
if (hasCachedCombatValue(attacker, cacheId))
{
return getCachedCombatValueFloat(attacker, cacheId);
}
float dist = getDistance(attacker, defender);
setCachedCombatValue(attacker, cacheId, dist);
return dist;
}
public static float cachedGetSpeedAdjustMin(obj_id attacker, obj_id defender) throws InterruptedException
{
String cacheId = "combat.cache." + defender + ".speedAdjustMin";
if (hasCachedCombatValue(attacker, cacheId))
{
return getCachedCombatValueFloat(attacker, cacheId);
}
float adjustMin = 0.0f;
if (cachedGetLocomotion(attacker) == LOCOMOTION_RUNNING)
{
location defenderLocation = getLocation(defender);
defenderLocation.y = getLocation(attacker).y;
if (!isFacing(attacker, defenderLocation))
{
adjustMin -= cachedGetMovementSpeed(attacker) * 0.6f;
}
}
if (cachedGetLocomotion(defender) == LOCOMOTION_RUNNING)
{
location attackerLocation = getLocation(attacker);
attackerLocation.y = getLocation(defender).y;
if (isFacing(defender, attackerLocation))
{
adjustMin -= cachedGetMovementSpeed(defender) * 0.6f;
}
}
float maxAdjustValue = (cachedGetRunSpeed(attacker) + cachedGetRunSpeed(defender)) * 0.75f;
if (adjustMin < -maxAdjustValue)
{
adjustMin = -maxAdjustValue;
}
setCachedCombatValue(attacker, cacheId, adjustMin);
return adjustMin;
}
public static float cachedGetSpeedAdjustMax(obj_id attacker, obj_id defender) throws InterruptedException
{
String cacheId = "combat.cache." + defender + ".speedAdjustMax";
if (hasCachedCombatValue(attacker, cacheId))
{
return getCachedCombatValueFloat(attacker, cacheId);
}
float adjustMax = 0.0f;
if (cachedGetLocomotion(attacker) == LOCOMOTION_RUNNING)
{
location defenderLocation = getLocation(defender);
defenderLocation.y = getLocation(attacker).y;
if (isFacing(attacker, defenderLocation))
{
adjustMax += cachedGetMovementSpeed(attacker) * 0.6f;
}
}
if (cachedGetLocomotion(defender) == LOCOMOTION_RUNNING)
{
location attackerLocation = getLocation(attacker);
attackerLocation.y = getLocation(defender).y;
if (!isFacing(defender, attackerLocation))
{
adjustMax += cachedGetMovementSpeed(defender) * 0.6f;
}
}
float maxAdjustValue = (cachedGetRunSpeed(attacker) + cachedGetRunSpeed(defender)) * 0.75f;
if (adjustMax > maxAdjustValue)
{
adjustMax = maxAdjustValue;
}
setCachedCombatValue(attacker, cacheId, adjustMax);
return adjustMax;
}
public static boolean cachedCanSee(obj_id attacker, obj_id defender) throws InterruptedException
{
return canSee(attacker, defender);
}
public static boolean cachedPvpCanAttack(obj_id attacker, obj_id defender) throws InterruptedException
{
String cacheId = "combat.cache." + defender + ".pvpCanAttack";
if (hasCachedCombatValue(attacker, cacheId))
{
return getCachedCombatValueBool(attacker, cacheId);
}
boolean attackerCanAttack = pvpCanAttack(attacker, defender);
setCachedCombatValue(attacker, cacheId, attackerCanAttack);
return attackerCanAttack;
}
public static boolean cachedIsSameSocialGroup(obj_id attacker, obj_id defender) throws InterruptedException
{
String cacheId = "combat.cache." + defender + ".sameSocialGroup";
if (hasCachedCombatValue(attacker, cacheId))
{
return getCachedCombatValueBool(attacker, cacheId);
}
String attackerSocialGroup = null;
if (!isPlayer(attacker) && !pet_lib.isPet(attacker) && !pet_lib.isPet(defender))
{
attackerSocialGroup = ai_lib.getSocialGroup(attacker);
}
boolean sameSocialGroup = (attackerSocialGroup != null && attackerSocialGroup.equals(ai_lib.getSocialGroup(defender)));
setCachedCombatValue(attacker, cacheId, sameSocialGroup);
return sameSocialGroup;
}
public static boolean isCachedServerFrame(obj_id attacker) throws InterruptedException
{
int serverFrame = utils.getIntScriptVar(attacker, "combat.cache.serverFrame");
int currentFrame = getServerFrame();
return (serverFrame == currentFrame);
}
public static void setCachedServerFrame(obj_id attacker) throws InterruptedException
{
if (!isCachedServerFrame(attacker))
{
utils.removeScriptVarTree(attacker, "combat.cache");
int currentFrame = getServerFrame();
utils.setScriptVar(attacker, "combat.cache.serverFrame", currentFrame);
}
}
public static boolean hasCachedCombatValue(obj_id attacker, String cacheId) throws InterruptedException
{
if (isCachedServerFrame(attacker))
{
return (utils.hasScriptVar(attacker, "combat.cache." + cacheId));
}
return false;
}
public static int getCachedCombatValueInt(obj_id attacker, String cacheId) throws InterruptedException
{
if (isCachedServerFrame(attacker))
{
return (utils.getIntScriptVar(attacker, "combat.cache." + cacheId));
}
return 0;
}
public static float getCachedCombatValueFloat(obj_id attacker, String cacheId) throws InterruptedException
{
if (isCachedServerFrame(attacker))
{
return (utils.getFloatScriptVar(attacker, "combat.cache." + cacheId));
}
return 0.0f;
}
public static boolean getCachedCombatValueBool(obj_id attacker, String cacheId) throws InterruptedException
{
if (isCachedServerFrame(attacker))
{
return (utils.getBooleanScriptVar(attacker, "combat.cache." + cacheId));
}
return false;
}
public static void setCachedCombatValue(obj_id attacker, String cacheId, int value) throws InterruptedException
{
setCachedServerFrame(attacker);
utils.setScriptVar(attacker, "combat.cache." + cacheId, value);
}
public static void setCachedCombatValue(obj_id attacker, String cacheId, float value) throws InterruptedException
{
setCachedServerFrame(attacker);
utils.setScriptVar(attacker, "combat.cache." + cacheId, value);
}
public static void setCachedCombatValue(obj_id attacker, String cacheId, boolean value) throws InterruptedException
{
setCachedServerFrame(attacker);
utils.setScriptVar(attacker, "combat.cache." + cacheId, value);
}
public static void combatLog(obj_id attacker, obj_id defender, String logName, String logMsg) throws InterruptedException
{
}
public static int getWeaponCategory(String weaponType) throws InterruptedException
{
if (weaponType.equals("rifle"))
{
return RANGED_WEAPON;
}
if (weaponType.equals("carbine"))
{
return RANGED_WEAPON;
}
if (weaponType.equals("pistol"))
{
return RANGED_WEAPON;
}
if (weaponType.equals("heavyweapon"))
{
return RANGED_WEAPON;
}
if (weaponType.equals("onehandmelee"))
{
return MELEE_WEAPON;
}
if (weaponType.equals("twohandmelee"))
{
return MELEE_WEAPON;
}
if (weaponType.equals("unarmed"))
{
return MELEE_WEAPON;
}
if (weaponType.equals("polearm"))
{
return MELEE_WEAPON;
}
if (weaponType.equals("thrown"))
{
return RANGED_WEAPON;
}
if (weaponType.equals("onehandlightsaber"))
{
return MELEE_WEAPON;
}
if (weaponType.equals("twohandlightsaber"))
{
return MELEE_WEAPON;
}
if (weaponType.equals("polearmlightsaber"))
{
return MELEE_WEAPON;
}
if (weaponType.equals("force"))
{
return FORCE_POWER;
}
return 0;
}
public static int getWeaponCategory(int weaponType) throws InterruptedException
{
if (weaponType == WEAPON_TYPE_RIFLE)
{
return RANGED_WEAPON;
}
if (weaponType == WEAPON_TYPE_LIGHT_RIFLE)
{
return RANGED_WEAPON;
}
if (weaponType == WEAPON_TYPE_PISTOL)
{
return RANGED_WEAPON;
}
if (weaponType == WEAPON_TYPE_HEAVY)
{
return RANGED_WEAPON;
}
if (weaponType == WEAPON_TYPE_1HAND_MELEE)
{
return MELEE_WEAPON;
}
if (weaponType == WEAPON_TYPE_2HAND_MELEE)
{
return MELEE_WEAPON;
}
if (weaponType == WEAPON_TYPE_UNARMED)
{
return MELEE_WEAPON;
}
if (weaponType == WEAPON_TYPE_POLEARM)
{
return MELEE_WEAPON;
}
if (weaponType == WEAPON_TYPE_THROWN)
{
return RANGED_WEAPON;
}
if (weaponType == WEAPON_TYPE_WT_1HAND_LIGHTSABER)
{
return MELEE_WEAPON;
}
if (weaponType == WEAPON_TYPE_WT_2HAND_LIGHTSABER)
{
return MELEE_WEAPON;
}
if (weaponType == WEAPON_TYPE_WT_POLEARM_LIGHTSABER)
{
return MELEE_WEAPON;
}
if (weaponType == WEAPON_TYPE_FORCE_POWER)
{
return FORCE_POWER;
}
return 0;
}
public static String getWeaponStringCategory(int weaponType) throws InterruptedException
{
int weaponCategory = getWeaponCategory(weaponType);
if (weaponCategory == RANGED_WEAPON)
{
return "ranged";
}
if (weaponCategory == MELEE_WEAPON)
{
return "melee";
}
if (weaponCategory == FORCE_POWER)
{
return "ranged";
}
return null;
}
public static String getWeaponStringCategory(String weaponType) throws InterruptedException
{
int weaponCategory = getWeaponCategory(weaponType);
if (weaponCategory == RANGED_WEAPON)
{
return "ranged";
}
if (weaponCategory == MELEE_WEAPON)
{
return "melee";
}
if (weaponCategory == FORCE_POWER)
{
return "ranged";
}
return null;
}
public static int getWeaponType(String weaponType) throws InterruptedException
{
if (weaponType.equals("rifle"))
{
return WEAPON_TYPE_RIFLE;
}
if (weaponType.equals("carbine"))
{
return WEAPON_TYPE_LIGHT_RIFLE;
}
if (weaponType.equals("pistol"))
{
return WEAPON_TYPE_PISTOL;
}
if (weaponType.equals("heavyweapon"))
{
return WEAPON_TYPE_HEAVY;
}
if (weaponType.equals("onehandmelee"))
{
return WEAPON_TYPE_1HAND_MELEE;
}
if (weaponType.equals("twohandmelee"))
{
return WEAPON_TYPE_2HAND_MELEE;
}
if (weaponType.equals("unarmed"))
{
return WEAPON_TYPE_UNARMED;
}
if (weaponType.equals("polearm"))
{
return WEAPON_TYPE_POLEARM;
}
if (weaponType.equals("thrown"))
{
return WEAPON_TYPE_THROWN;
}
if (weaponType.equals("onehandlightsaber"))
{
return WEAPON_TYPE_WT_1HAND_LIGHTSABER;
}
if (weaponType.equals("twohandlightsaber"))
{
return WEAPON_TYPE_WT_2HAND_LIGHTSABER;
}
if (weaponType.equals("polearmlightsaber"))
{
return WEAPON_TYPE_WT_POLEARM_LIGHTSABER;
}
return 0;
}
public static int getCorrectedWeaponType(int passedType) throws InterruptedException
{
switch (passedType)
{
case WEAPON_TYPE_GROUND_TARGETTING:
return WEAPON_TYPE_HEAVY;
case WEAPON_TYPE_DIRECTIONAL:
return WEAPON_TYPE_HEAVY;
}
return passedType;
}
public static String getWeaponStringType(int weaponType) throws InterruptedException
{
switch (weaponType)
{
case WEAPON_TYPE_RIFLE:
return "rifle";
case WEAPON_TYPE_LIGHT_RIFLE:
return "carbine";
case WEAPON_TYPE_PISTOL:
return "pistol";
case WEAPON_TYPE_HEAVY:
return "heavyweapon";
case WEAPON_TYPE_1HAND_MELEE:
return "onehandmelee";
case WEAPON_TYPE_2HAND_MELEE:
return "twohandmelee";
case WEAPON_TYPE_UNARMED:
return "unarmed";
case WEAPON_TYPE_POLEARM:
return "polearm";
case WEAPON_TYPE_THROWN:
return "thrown";
case WEAPON_TYPE_WT_1HAND_LIGHTSABER:
return "onehandlightsaber";
case WEAPON_TYPE_WT_2HAND_LIGHTSABER:
return "twohandlightsaber";
case WEAPON_TYPE_WT_POLEARM_LIGHTSABER:
return "polearmlightsaber";
case WEAPON_TYPE_FORCE_POWER:
return "force";
}
return "";
}
public static boolean isMeleeWeapon(obj_id weapon) throws InterruptedException
{
int weaponType = getWeaponType(weapon);
return isMeleeWeapon(weaponType);
}
public static boolean isMeleeWeapon(int weaponType) throws InterruptedException
{
return hasBit(weaponType, B_MELEE);
}
public static boolean isRangedWeapon(obj_id weapon) throws InterruptedException
{
int weaponType = getWeaponType(weapon);
return isRangedWeapon(weaponType);
}
public static boolean isHeavyWeapon(int weaponType) throws InterruptedException
{
return hasBit(weaponType, B_HEAVY);
}
public static boolean isHeavyWeapon(obj_id weapon) throws InterruptedException
{
int weaponType = getWeaponType(weapon);
return hasBit(weaponType, B_HEAVY);
}
public static boolean isRangedWeapon(int weaponType) throws InterruptedException
{
return hasBit(weaponType, B_RANGED);
}
public static boolean isLightsaberWeapon(obj_id weapon) throws InterruptedException
{
int weaponType = getWeaponType(weapon);
return isLightsaberWeapon(weaponType);
}
public static boolean isLightsaberWeapon(int weaponType) throws InterruptedException
{
return hasBit(weaponType, B_ALL_LIGHTSABERS);
}
public static boolean isGrenade(weapon_data weaponData) throws InterruptedException
{
return hasBit(weaponData.weaponType, B_THROWN);
}
public static boolean isHeavyWeapon(weapon_data weaponData) throws InterruptedException
{
return hasBit(weaponData.weaponType, B_HEAVY);
}
public static boolean canApplyCombatEffect(obj_id objPlayer) throws InterruptedException
{
if (!isIdValid(objPlayer))
{
return false;
}
if (ai_lib.aiGetNiche(objPlayer) == NICHE_DROID || vehicle.isVehicle(objPlayer) || ai_lib.isTurret(objPlayer) || ai_lib.isAndroid(objPlayer))
{
return false;
}
return true;
}
public static boolean hasCertification(obj_id objPlayer, obj_id objWeapon) throws InterruptedException
{
return hasCertification(objPlayer, objWeapon, true);
}
public static boolean hasCertification(obj_id objPlayer, obj_id objWeapon, boolean verbose) throws InterruptedException
{
boolean hasCert = true;
if (utils.hasScriptVar(objPlayer, "combat.weaponCertified"))
{
obj_id lastCertified = utils.getObjIdScriptVar(objPlayer, "combat.weaponCertified");
if (lastCertified == objWeapon)
{
return true;
}
}
String template = getTemplateName(objWeapon);
if (template == null)
{
return false;
}
if (template.equals("object/weapon/melee/unarmed/unarmed_default_player.iff"))
{
return true;
}
int speciesRequired = dataTableGetInt(combat.WEAPON_LEVEL_TABLE, template, "species_restriction");
if (speciesRequired >= 0)
{
int playerSpecies = getSpecies(objPlayer);
if (playerSpecies != speciesRequired)
{
hasCert = false;
}
}
if (hasObjVar(objWeapon, "factionrestricted.rebel"))
{
if (!factions.isRebel(objPlayer))
{
hasCert = false;
}
}
if (hasObjVar(objWeapon, "factionrestricted.imperial"))
{
if (!factions.isImperial(objPlayer))
{
hasCert = false;
}
}
String classTemplate = getSkillTemplate(objPlayer);
if (isLightsaberWeapon(objWeapon) && !utils.isProfession(objPlayer, utils.FORCE_SENSITIVE))
{
hasCert = false;
}
if (static_item.isDynamicItem(objWeapon))
{
int levelRequired = getIntObjVar(objWeapon, "dynamic_item.intLevelRequired");
int playerLevel = getLevel(objPlayer);
if (playerLevel < levelRequired)
{
hasCert = false;
}
}
else if (static_item.isStaticItem(objWeapon))
{
dictionary itemData = static_item.getMasterItemDictionary(objWeapon);
String skillRequired = itemData.getString("required_skill");
if (skillRequired != null && !skillRequired.equals(""))
{
if (classTemplate != null && !classTemplate.equals(""))
{
if (!classTemplate.startsWith(skillRequired))
{
hasCert = false;
}
}
}
int levelRequired = itemData.getInt("required_level");
int playerLevel = getLevel(objPlayer);
if (playerLevel < levelRequired)
{
hasCert = false;
}
}
else
{
String skillRequired = dataTableGetString(WEAPON_LEVEL_TABLE, template, "secondary_restriction");
if (skillRequired != null && !skillRequired.equals(""))
{
if (classTemplate != null && !classTemplate.equals(""))
{
if (!classTemplate.startsWith(skillRequired))
{
hasCert = false;
}
}
}
int levelRequired = -1;
int playerLevel = getLevel(objPlayer);
if (hasObjVar(objWeapon, weapons.OBJVAR_WP_LEVEL))
{
levelRequired = getIntObjVar(objWeapon, weapons.OBJVAR_WP_LEVEL);
}
else
{
levelRequired = dataTableGetInt(WEAPON_LEVEL_TABLE, template, "weapon_level");
}
if (playerLevel < levelRequired)
{
hasCert = false;
}
}
if (!hasCert && isGod(objPlayer))
{
hasCert = true;
}
if (hasCert)
{
utils.setScriptVar(objPlayer, "combat.weaponCertified", objWeapon);
}
return hasCert;
}
public static void applyCombatSpeedDelay(obj_id target, float delay, int duration) throws InterruptedException
{
int delayStampStart = getGameTime();
int delayStampEnd = delayStampStart + duration;
utils.setScriptVar(target, "speedDelayEffectStart", delayStampStart);
utils.setScriptVar(target, "speedDelayEffectEnd", delayStampEnd);
utils.setScriptVar(target, "speedDelayPotency", delay);
return;
}
public static void doCombatDebuffs(obj_id self) throws InterruptedException
{
if (!utils.hasScriptVar(self, "fltNonCombatHealthRegen"))
{
float fltHealthRegen = getHealthRegenRate(self);
utils.setScriptVar(self, "fltNonCombatHealthRegen", fltHealthRegen);
setRegenRate(self, HEALTH, 0);
}
}
public static boolean clearCombatDebuffs(obj_id self) throws InterruptedException
{
if (getGameTime() > utils.getIntScriptVar(self, "incap.timeStamp"))
{
if (utils.hasScriptVar(self, "fltNonCombatHealthRegen"))
{
float fltHealthRegen = utils.getFloatScriptVar(self, "fltNonCombatHealthRegen");
setRegenRate(self, HEALTH, fltHealthRegen);
utils.removeScriptVar(self, "fltNonCombatHealthRegen");
return true;
}
}
return false;
}
public static boolean isInCombat(obj_id objTarget) throws InterruptedException
{
return getState(objTarget, STATE_COMBAT) > 0 ? true : false;
}
public static String getAttackName(obj_id self) throws InterruptedException
{
String actionName = null;
obj_id weapon = getCurrentWeapon(self);
int weaponType = getWeaponType(weapon);
if (utils.hasScriptVar(self, DO_ONCE_ATTACK_OVERRIDE))
{
actionName = utils.getStringScriptVar(self, DO_ONCE_ATTACK_OVERRIDE);
utils.removeScriptVar(self, DO_ONCE_ATTACK_OVERRIDE);
return actionName;
}
if (utils.hasScriptVar(self, DEFAULT_ATTACK_OVERRIDE))
{
return utils.getStringScriptVar(self, DEFAULT_ATTACK_OVERRIDE);
}
if (hasObjVar(self, DEFAULT_ATTACK_OVERRIDE))
{
LOG("combat.scriptlib", "gcw getStringObjVar(self, DEFAULT_ATTACK_OVERRIDE): " + getStringObjVar(self, DEFAULT_ATTACK_OVERRIDE));
return getStringObjVar(self, DEFAULT_ATTACK_OVERRIDE);
}
if ((getTemplateName(weapon)).equals("object/weapon/ranged/droid/droid_flamethrower.iff"))
{
actionName = "ig88_flame_thrower";
}
else if ((getTemplateName(weapon)).equals("object/weapon/ranged/droid/droid_flamethrower_nomuzzle.iff"))
{
actionName = "ig88_flame_thrower_vertical";
}
else if ((getTemplateName(weapon)).equals("object/weapon/ranged/droid/droid_rocket_launcher.iff"))
{
actionName = "ig88_rocket_launcher";
}
else if (combat.isRangedWeapon(weaponType))
{
if (ai_lib.isHumanoid(self))
{
actionName = "rangedShot";
}
else
{
actionName = "creatureRangedAttack";
}
}
else if (combat.isMeleeWeapon(weaponType))
{
if (ai_lib.isHumanoid(self))
{
actionName = "meleeHit";
}
else
{
actionName = "creatureMeleeAttack";
}
}
else if (combat.isLightsaberWeapon(weaponType))
{
if (ai_lib.isHumanoid(self))
{
actionName = "saberHit";
}
else
{
actionName = "creatureMeleeAttack";
}
}
return actionName;
}
public static String getBestAction(obj_id player, String actionName) throws InterruptedException
{
for (int i = 2; i > 0; i--)
{
String testCmd = actionName + "_" + i;
if (hasCommand(player, testCmd))
{
return testCmd;
}
}
return actionName;
}
public static String getActionAnimation(combat_data actionData, String weaponType) throws InterruptedException
{
String animation = "";
switch (weaponType) {
case "unarmed":
animation = actionData.anim_unarmed;
break;
case "onehandmelee":
animation = actionData.anim_onehandmelee;
break;
case "twohandmelee":
animation = actionData.anim_twohandmelee;
break;
case "polearm":
animation = actionData.anim_polearm;
break;
case "lightRifle":
animation = actionData.anim_lightRifle;
break;
case "pistol":
animation = actionData.anim_pistol;
break;
case "carbine":
animation = actionData.anim_carbine;
break;
case "rifle":
animation = actionData.anim_rifle;
break;
case "heavyweapon":
animation = actionData.anim_heavyweapon;
break;
case "thrown":
animation = actionData.anim_thrown;
break;
case "onehandlightsaber":
animation = actionData.anim_onehandlightsaber;
break;
case "twohandlightsaber":
animation = actionData.anim_twohandlightsaber;
break;
case "polearmlightsaber":
animation = actionData.anim_polearmlightsaber;
break;
}
if (animation.length() < 1)
{
animation = actionData.animDefault;
}
if (animation.startsWith("*creature_attack"))
{
return getCreatureAnimationName(animation);
}
String[] anims = split(animation, ',');
if (anims.length > 1)
{
animation = anims[rand(0, anims.length - 1)];
}
return animation;
}
public static String getCreatureAnimationName(String playbackName) throws InterruptedException
{
obj_id self = getSelf();
String animName = "";
int niche = ai_lib.aiGetNiche(self);
if (niche == NICHE_VEHICLE)
{
animName = "droid_attack";
}
else
{
if (playbackName.endsWith("ranged"))
{
animName = "creature_attack_ranged";
}
else if (playbackName.endsWith("melee"))
{
if (rand(1, 2) == 1)
{
animName = "creature_attack";
}
else
{
animName = "creature_attack_special_1";
}
if (rand(1, 2) == 1)
{
animName += "_light";
}
else
{
animName += "_heavy";
}
return animName;
}
else
{
animName = "creature_attack_special_" + rand(1, 2);
}
}
animName += "_medium";
return animName;
}
public static obj_id makeTrackerEgg(obj_id objPlayer, location locTest, combat_data actionData) throws InterruptedException
{
obj_id objEgg = createObject(actionData.delayAttackEggTemplate, locTest);
if (!isIdValid(objEgg))
{
return null;
}
dictionary combatDict = combat_engine.getCombatDataDictionary(actionData);
utils.setScriptVar(objEgg, "combatDataDict", combatDict);
utils.setScriptVar(objEgg, "objOwner", objPlayer);
utils.setScriptVar(objPlayer, "objEgg", objEgg);
attachScript(objEgg, "systems.combat.combat_delayed_tracker");
return objEgg;
}
public static int makeBit(int bit) throws InterruptedException
{
return (1 << (bit - 1));
}
public static boolean hasBit(int weaponType, int bitValue) throws InterruptedException
{
if (weaponType == -1)
{
return false;
}
return ((weaponTypeToBitValueMap[weaponType] & bitValue) != 0);
}
public static float doCriticalHitEffect(attacker_data attackerData, defender_data defenderData, weapon_data weaponData, hit_result hitData, combat_data actionData) throws InterruptedException
{
int elementalType = weaponData.elementalType;
float elementalDamage = weaponData.elementalValue;
float damageMod = 1.5f;
hitData.critDamage = 2;
int critResist = 0;
float heatResist = 0;
float coldResist = 0;
float acidResist = 0;
float electricResist = 0;
int resistRoll = rand(1, 10000);
if (actionData.percentAddFromWeapon > 0.0f)
{
if (utils.hasScriptVar(defenderData.id, armor.SCRIPTVAR_CACHED_GENERAL_PROTECTION))
{
critResist += utils.getIntScriptVar(defenderData.id, armor.SCRIPTVAR_CACHED_GENERAL_PROTECTION);
}
if (utils.hasScriptVar(defenderData.id, armor.SCRIPTVAR_CACHED_SPECIAL_PROTECTIONS))
{
dictionary protections = utils.getDictionaryScriptVar(defenderData.id, armor.SCRIPTVAR_CACHED_SPECIAL_PROTECTIONS);
heatResist = protections.getFloat("heat");
coldResist = protections.getFloat("cold");
acidResist = protections.getFloat("acid");
electricResist = protections.getFloat("electricity");
}
switch (elementalType)
{
case DAMAGE_ELEMENTAL_HEAT:
if (resistRoll > critResist + heatResist)
{
int level = getLevel(attackerData.id);
if (level == 90)
{
buff.applyBuff(defenderData.id, attackerData.id, "crit_fire_dot_4");
}
else if (level >= 75)
{
buff.applyBuff(defenderData.id, attackerData.id, "crit_fire_dot_3");
}
else if (level >= 50)
{
buff.applyBuff(defenderData.id, attackerData.id, "crit_fire_dot_2");
}
else if (level >= 25)
{
buff.applyBuff(defenderData.id, attackerData.id, "crit_fire_dot_1");
}
damageMod = 1.5f;
hitData.critDamage = 3;
return damageMod;
}
break;
case DAMAGE_ELEMENTAL_COLD:
if (resistRoll > critResist + coldResist && !buff.hasBuff(defenderData.id, "criticalImmunity"))
{
if (!buff.hasBuff(defenderData.id, "criticalColdEffect"))
{
buff.applyBuff(defenderData.id, "criticalColdEffect", 6, (float)elementalDamage / 10.0f);
}
damageMod = 1.5f;
hitData.critDamage = 4;
return damageMod;
}
break;
case DAMAGE_ELEMENTAL_ACID:
if (resistRoll > critResist + acidResist && !buff.hasBuff(defenderData.id, "criticalAcidEffect") && !buff.hasBuff(defenderData.id, "criticalImmunity"))
{
buff.applyBuff(defenderData.id, "criticalAcidEffect");
damageMod = 1.5f;
hitData.critDamage = 5;
return damageMod;
}
break;
case DAMAGE_ELEMENTAL_ELECTRICAL:
if (resistRoll > critResist + electricResist && !buff.hasBuff(defenderData.id, "criticalElectricEffect") && !buff.hasBuff(defenderData.id, "criticalImmunity"))
{
buff.applyBuff(defenderData.id, "criticalElectricEffect");
damageMod = 1.5f;
hitData.critDamage = 6;
return damageMod;
}
break;
}
}
return damageMod;
}
public static color getCriticalColor(int hitDataCritDamage) throws InterruptedException
{
color criticalColor = colors.MEDIUMVIOLETRED;
switch (hitDataCritDamage)
{
case 1:
criticalColor = colors.SLATEGREY;
break;
case 3:
criticalColor = colors.ORANGERED;
break;
case 4:
criticalColor = colors.LIGHTSKYBLUE;
break;
case 5:
criticalColor = colors.DARKOLIVEGREEN;
break;
case 6:
criticalColor = colors.SILVER;
break;
}
return criticalColor;
}
public static obj_id directDamageToDifferentTarget(obj_id attacker, obj_id defender) throws InterruptedException
{
if (buff.hasBuff(defender, "bm_shield_master_player"))
{
obj_id guardian = beast_lib.getBeastOnPlayer(defender);
if (isIdValid(guardian) && exists(guardian) && !isDead(guardian) && !isIncapacitated(guardian) && getEnhancedSkillStatisticModifierUncapped(defender, "damage_immune") <= 0)
{
return guardian;
}
}
if (utils.hasScriptVar(defender, DAMAGE_REDIRECT))
{
obj_id guardian = utils.getObjIdScriptVar(defender, DAMAGE_REDIRECT);
if (isIdValid(guardian) && exists(guardian) && !isMob(guardian) && getEnhancedSkillStatisticModifierUncapped(defender, "damage_immune") <= 0)
{
return guardian;
}
if (isIdValid(guardian) && exists(guardian) && isMob(guardian) && !isDead(guardian) && !isIncapacitated(guardian) && getEnhancedSkillStatisticModifierUncapped(defender, "damage_immune") <= 0 && pvpCanAttack(attacker, guardian))
{
return guardian;
}
else
{
utils.removeScriptVar(defender, DAMAGE_REDIRECT);
}
}
return defender;
}
public static float getMissChance(attacker_data attackerData, defender_data defenderData, combat_data actionData, boolean autoAim) throws InterruptedException
{
obj_id attacker = attackerData.id;
obj_id defender = defenderData.id;
float missChance = isPlayer(attacker) ? 0.0f : 5.0f;
if (autoAim && isRangedWeapon(getCurrentWeapon(attacker)))
{
missChance += 5.0f;
boolean attackerMovePenalty = (getLocomotion(attacker) == LOCOMOTION_RUNNING && isRangedWeapon(getCurrentWeapon(attacker)));
boolean defenderMovePenalty = (getLocomotion(defender) == LOCOMOTION_RUNNING && isRangedWeapon(getCurrentWeapon(defender)));
if (isPlayer(attacker) && attackerMovePenalty)
{
missChance += 5.0f;
}
if (defenderMovePenalty)
{
missChance += 3.0f;
}
}
if (isRangedWeapon(getCurrentWeapon(attackerData.id)))
{
missChance += (getEnhancedSkillStatisticModifierUncapped(defenderData.id, "combat_ranged_attack_avoidance") / 10.0f);
missChance -= (getEnhancedSkillStatisticModifierUncapped(defenderData.id, "combat_ranged_attack_vulnerability") / 10.0f);
}
if (isMeleeWeapon(getCurrentWeapon(attackerData.id)) || isLightsaberWeapon(getCurrentWeapon(attackerData.id)))
{
missChance += (getEnhancedSkillStatisticModifierUncapped(defenderData.id, "combat_melee_attack_avoidance") / 10.0f);
missChance -= (getEnhancedSkillStatisticModifierUncapped(defenderData.id, "combat_melee_attack_vulnerability") / 10.0f);
}
missChance += getAttackerMissChance(attackerData, actionData, autoAim);
missChance += getDefenderMissChance(defenderData, actionData, autoAim);
missChance -= attackerData.hitChance;
missChance += defenderData.increaseMiss;
return missChance;
}
public static float getAttackerMissChance(attacker_data attackerData, combat_data actionData, boolean autoAim) throws InterruptedException
{
float attackerMissChance = 0.0f;
if (isRangedWeapon(getCurrentWeapon(attackerData.id)))
{
attackerMissChance += (getEnhancedSkillStatisticModifierUncapped(attackerData.id, "combat_ranged_attack_miss") / 10.0f);
attackerMissChance -= (getEnhancedSkillStatisticModifierUncapped(attackerData.id, "combat_ranged_attack_miss_reduction") / 10.0f);
}
if (isMeleeWeapon(getCurrentWeapon(attackerData.id)) || isLightsaberWeapon(getCurrentWeapon(attackerData.id)))
{
attackerMissChance += (getEnhancedSkillStatisticModifierUncapped(attackerData.id, "combat_melee_attack_miss") / 10.0f);
attackerMissChance -= (getEnhancedSkillStatisticModifierUncapped(attackerData.id, "combat_melee_attack_miss_reduction") / 10.0f);
}
attackerMissChance += (getEnhancedSkillStatisticModifierUncapped(attackerData.id, "combat_all_attack_miss") / 10.0f);
attackerMissChance -= (getEnhancedSkillStatisticModifierUncapped(attackerData.id, "combat_all_attack_miss_reduction") / 10.0f);
return attackerMissChance;
}
public static float getDefenderMissChance(defender_data defenderData, combat_data actionData, boolean autoAim) throws InterruptedException
{
float defenderMissChance = 0.0f;
defenderMissChance += (getEnhancedSkillStatisticModifierUncapped(defenderData.id, "combat_all_attack_avoidance") / 10.0f);
defenderMissChance -= (getEnhancedSkillStatisticModifierUncapped(defenderData.id, "combat_all_attack_miss_vulnerability") / 10.0f);
return defenderMissChance;
}
public static float getGlancingBlowChance(attacker_data attackerData, defender_data defenderData, combat_data actionData) throws InterruptedException
{
obj_id attacker = attackerData.id;
obj_id defender = defenderData.id;
float glancingChance = 0.0f;
if (isMob(defender) && beast_lib.isBeast(defender))
{
glancingChance += (int)beast_lib.getBeastGlanceChance(defender);
}
if ((isPlayer(attacker) || beast_lib.isBeast(attacker)) && (!isPlayer(defender) && !beast_lib.isBeast(defender)))
{
int attackerLevel = getLevel(attacker);
int defenderLevel = getLevel(defender);
int difficultyClass = getIntObjVar(defender, "difficultyClass");
if (attackerLevel < defenderLevel)
{
glancingChance = 5.0f * (defenderLevel - attackerLevel);
}
switch (difficultyClass)
{
case 1:
if (glancingChance < 5.0f)
{
glancingChance = 5.0f;
}
break;
case 2:
if (glancingChance < 15.0f)
{
glancingChance = 15.0f;
}
}
}
if ((!isPlayer(attacker) && !beast_lib.isBeast(attacker)) && (isPlayer(defender) || beast_lib.isBeast(defender)))
{
int attackerLevel = getLevel(attacker);
int defenderLevel = getLevel(defender);
defenderLevel = Math.round(defenderLevel * 0.75f);
if (attackerLevel < defenderLevel)
{
glancingChance = 2.0f * (defenderLevel - attackerLevel);
}
}
glancingChance += defenderData.glancingChance;
glancingChance -= attackerData.reduceGlancing;
boolean isRangedAttacker = isRangedWeapon(getCurrentWeapon(attacker));
boolean isRangedDefender = isRangedWeapon(getCurrentWeapon(defender));
if (isRangedAttacker)
{
glancingChance += getEnhancedSkillStatisticModifierUncapped(defender, "expertise_glancing_blow_ranged");
if (armor.hasExpertiseArmorSetBonus(defender))
{
glancingChance += getEnhancedSkillStatisticModifierUncapped(defender, "expertise_armorset_glancing_blow_ranged_" + armor.getExpertiseArmorSetId(defender));
}
}
if (!isRangedAttacker)
{
glancingChance += getEnhancedSkillStatisticModifierUncapped(defender, "expertise_glancing_blow_melee");
if (armor.hasExpertiseArmorSetBonus(defender))
{
glancingChance += getEnhancedSkillStatisticModifierUncapped(defender, "expertise_armorset_glancing_blow_melee_" + armor.getExpertiseArmorSetId(defender));
}
}
glancingChance -= actionData.reduceGlancing;
if (beast_lib.isBeast(defender))
{
LOG("beastDamage", "glancingChance: " + glancingChance);
}
return glancingChance;
}
public static float getDefenderGlancingBlowChance(obj_id defender) throws InterruptedException
{
float glancingChance = 0.0f;
boolean isRangedDefender = isRangedWeapon(getCurrentWeapon(defender));
if (!isRangedDefender)
{
glancingChance += getEnhancedSkillStatisticModifierUncapped(defender, "expertise_glancing_blow_melee_defense");
}
glancingChance += getEnhancedSkillStatisticModifierUncapped(defender, "expertise_glancing_blow_all");
glancingChance += utils.getIntScriptVar(defender, "expertise_stance_glance");
glancingChance += (getDiminishedReturnValue(getEnhancedSkillStatisticModifierUncapped(defender, "combat_glancing"), DR_DEFENDER_GLANCE) / 10.0f);
return glancingChance;
}
public static float getAttackerGlancingReduction(obj_id attacker) throws InterruptedException
{
float glancingReduce = 0.0f;
if (beast_lib.isBeastMaster(attacker) || beast_lib.isBeast(attacker))
{
glancingReduce += beast_lib.getBeastModGlancingReduction(attacker);
}
glancingReduce += (float)(getEnhancedSkillStatisticModifierUncapped(attacker, "combat_glancing_blow_reduction") / 7.0f);
glancingReduce += (getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_glancing_blow_reduction"));
glancingReduce -= getEnhancedSkillStatisticModifierUncapped(attacker, "glancing_blow_vulnerable");
return glancingReduce;
}
public static float getPunishingBlowChance(attacker_data attackerData, defender_data defenderData) throws InterruptedException
{
obj_id attacker = attackerData.id;
obj_id defender = defenderData.id;
float punishingChance = 0.0f;
if ((!isPlayer(attacker) && !beast_lib.isBeast(attacker)) && (isPlayer(defender) || beast_lib.isBeast(defender)))
{
int attackerLevel = getLevel(attacker);
int defenderLevel = getLevel(defender);
if (attackerLevel > defenderLevel)
{
punishingChance = 5.0f * (attackerLevel - defenderLevel);
}
int difficultyClass = getIntObjVar(attacker, "difficultyClass");
switch (difficultyClass)
{
case 1:
if (punishingChance < 5.0f)
{
punishingChance = 5.0f;
}
break;
case 2:
if (punishingChance < 15.0f)
{
punishingChance = 15.0f;
}
}
}
punishingChance -= defenderData.reducePunishing;
return punishingChance;
}
public static float getDefenderPunishingBlowReduction(obj_id defender) throws InterruptedException
{
float punishingChance = 0.0f;
if (beast_lib.isBeastMaster(defender) || beast_lib.isBeast(defender))
{
punishingChance += beast_lib.getBeastModPunishingReduction(defender);
}
return punishingChance;
}
public static float getDodgeChance(attacker_data attackerData, defender_data defenderData, combat_data actionData) throws InterruptedException
{
obj_id attacker = attackerData.id;
obj_id defender = defenderData.id;
float dodgeChance = 0.0f;
dodgeChance += defenderData.dodgeChance;
dodgeChance -= attackerData.reduceDodge;
dodgeChance -= actionData.reduceDodge;
boolean isRangedAttacker = isRangedWeapon(getCurrentWeapon(attacker));
if (isRangedAttacker)
{
if (armor.hasExpertiseArmorSetBonus(defender))
{
dodgeChance += getEnhancedSkillStatisticModifierUncapped(defender, "expertise_armorset_ranged_dodge_" + armor.getExpertiseArmorSetId(defender));
}
}
if (!isRangedAttacker)
{
if (armor.hasExpertiseArmorSetBonus(defender))
{
dodgeChance += getEnhancedSkillStatisticModifierUncapped(defender, "expertise_armorset_melee_dodge_" + armor.getExpertiseArmorSetId(defender));
}
}
return dodgeChance;
}
public static float getDefenderDodgeChance(obj_id player) throws InterruptedException
{
float dodgeChance = isPlayer(player) || beast_lib.isBeast(player) ? 5.0f : getLevel(player) * 0.10f;
dodgeChance += (getEnhancedSkillStatisticModifierUncapped(player, "agility_modified") / 100.0f);
dodgeChance += (getEnhancedSkillStatisticModifierUncapped(player, "agility") / 100.0f);
dodgeChance += (getEnhancedSkillStatisticModifierUncapped(player, "luck_modified") / 300.0f);
dodgeChance += (getEnhancedSkillStatisticModifierUncapped(player, "luck") / 300.0f);
dodgeChance += (getDiminishedReturnValue(getEnhancedSkillStatisticModifierUncapped(player, "combat_dodge"), DR_DEFENDER_DODGE) / 10.0f);
dodgeChance += getEnhancedSkillStatisticModifierUncapped(player, "expertise_dodge");
if (beast_lib.isBeastMaster(player) || beast_lib.isBeast(player))
{
dodgeChance += beast_lib.getBeastDodgeChance(player);
}
return dodgeChance;
}
public static float getAttackerDodgeReduction(obj_id attacker) throws InterruptedException
{
float dodgeReduction = 0.0f;
dodgeReduction += (getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_dodge_reduction"));
dodgeReduction += (float)(getEnhancedSkillStatisticModifierUncapped(attacker, "exotic_dodge_reduction") / 7.0f);
dodgeReduction += (float)(getEnhancedSkillStatisticModifierUncapped(attacker, "combat_dodge_reduction") / 7.0f);
return dodgeReduction;
}
public static float getParryChance(attacker_data attackerData, defender_data defenderData, combat_data actionData) throws InterruptedException
{
float parryChance = 0.0f;
parryChance += defenderData.parryChance;
parryChance -= attackerData.reduceParry;
parryChance -= actionData.reduceParry;
return parryChance;
}
public static float getDefenderParryChance(obj_id player) throws InterruptedException
{
float parrySkill = isPlayer(player) || beast_lib.isBeast(player) ? 5.0f : getLevel(player) * 0.09f;
parrySkill += (getDiminishedReturnValue(getEnhancedSkillStatisticModifierUncapped(player, "combat_parry"), DR_DEFENDER_PARRY) / 10.0f);
parrySkill += (getEnhancedSkillStatisticModifierUncapped(player, "precision_modified") / 200.0f);
parrySkill += (getSkillStatisticModifier(player, "precision") / 200.0f);
parrySkill += (getEnhancedSkillStatisticModifierUncapped(player, "agility_modified") / 200.0f);
parrySkill += (getSkillStatisticModifier(player, "agility") / 200.0f);
parrySkill += getEnhancedSkillStatisticModifierUncapped(player, "expertise_parry");
if (beast_lib.isBeastMaster(player) || beast_lib.isBeast(player))
{
parrySkill += beast_lib.getBeastParryChance(player);
}
parrySkill += getSkillStatisticModifier(player, "expertise_stance_saber_block");
boolean isSaberBlocking = buff.hasBuff(player, "saberBlock");
if (isSaberBlocking)
{
float enhancedSaberBlockSkillMod = getSkillStatisticModifier(player, "expertise_saber_block");
parrySkill += enhancedSaberBlockSkillMod;
}
parrySkill = parrySkill > 75.0f ? 75.0f : parrySkill;
return parrySkill;
}
public static float getAttackerParryReduction(obj_id attacker) throws InterruptedException
{
float parryReduction = 0.0f;
parryReduction += (getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_parry_reduction"));
parryReduction += (float)(getEnhancedSkillStatisticModifierUncapped(attacker, "exotic_parry_reduction") / 7.0f);
parryReduction += (float)(getEnhancedSkillStatisticModifierUncapped(attacker, "combat_parry_reduction") / 7.0f);
return parryReduction;
}
public static float getBlockChance(attacker_data attackerData, defender_data defenderData, combat_data actionData) throws InterruptedException
{
float blockChance = 0.0f;
obj_id attacker = attackerData.id;
obj_id defender = defenderData.id;
blockChance += defenderData.blockChance;
blockChance -= attackerData.reduceBlock;
blockChance -= actionData.reduceBlock;
boolean isRangedAttacker = isRangedWeapon(getCurrentWeapon(attacker));
if (isRangedAttacker)
{
if (armor.hasExpertiseArmorSetBonus(defender))
{
blockChance += getEnhancedSkillStatisticModifierUncapped(defender, "expertise_armorset_ranged_block_" + armor.getExpertiseArmorSetId(defender));
}
}
if (!isRangedAttacker)
{
if (armor.hasExpertiseArmorSetBonus(defender))
{
blockChance += getEnhancedSkillStatisticModifierUncapped(defender, "expertise_armorset_melee_block_" + armor.getExpertiseArmorSetId(defender));
}
}
return blockChance;
}
public static float getDefenderBlockChance(obj_id player) throws InterruptedException
{
float blockChance = isPlayer(player) ? 5.0f : getLevel(player) * 0.14f;
blockChance += (getEnhancedSkillStatisticModifierUncapped(player, "precision_modified") / 200.0f);
blockChance += (getEnhancedSkillStatisticModifierUncapped(player, "precision") / 200.0f);
blockChance += (getEnhancedSkillStatisticModifierUncapped(player, "strength_modified") / 200.0f);
blockChance += (getEnhancedSkillStatisticModifierUncapped(player, "strength") / 200.0f);
blockChance += (getDiminishedReturnValue(getEnhancedSkillStatisticModifierUncapped(player, "combat_block_chance"), DR_DEFENDER_BLOCK) / 5.0f);
blockChance += getEnhancedSkillStatisticModifierUncapped(player, "expertise_block_chance");
if (beast_lib.isBeastMaster(player) || beast_lib.isBeast(player))
{
blockChance += beast_lib.getBeastBlockChance(player);
}
if (blockChance > 30.0f)
{
int nextBlockLog = utils.getIntScriptVar(player, "nextBlockLog");
if (getGameTime() > nextBlockLog)
{
float fromBlockChance = getEnhancedSkillStatisticModifierUncapped(player, "combat_block_chance") / 5.0f;
float fromBlockChanceDiminished = (getDiminishedReturnValue(getEnhancedSkillStatisticModifierUncapped(player, "combat_block_chance"), DR_DEFENDER_BLOCK) / 5.0f);
float fromPreMod = getEnhancedSkillStatisticModifierUncapped(player, "precision_modified") / 200.0f;
float fromPre = getEnhancedSkillStatisticModifierUncapped(player, "precision") / 200.0f;
float fromStrMod = getEnhancedSkillStatisticModifierUncapped(player, "strength_modified") / 200.0f;
float fromStr = getEnhancedSkillStatisticModifierUncapped(player, "strength") / 200.0f;
float fromExChance = getEnhancedSkillStatisticModifierUncapped(player, "expertise_block_chance");
float fromBeastMod = 0.0f;
if (beast_lib.isBeastMaster(player) || beast_lib.isBeast(player))
{
fromBeastMod += beast_lib.getBeastBlockChance(player);
}
utils.setScriptVar(player, "nextBlockLog", getGameTime() + 600);
CustomerServiceLog("BLOCK_CHANCE", "Player %TU total block chance: 5% + " + blockChance + " = combat_block_chance(" + fromBlockChance + "/ DRF: " + fromBlockChanceDiminished + ") + precision_modified(" + fromPreMod + ") + precision(" + fromPre + ") + strength_modified(" + fromStrMod + ") + strength(" + fromStr + ") + Expertise Block(" + fromExChance + ") + beast_mod(" + fromBeastMod + ")", player);
}
}
return blockChance;
}
public static float getAttackerBlockReduction(obj_id attacker) throws InterruptedException
{
float blockReduction = 0.0f;
blockReduction += (getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_block_reduction"));
blockReduction += (float)(getEnhancedSkillStatisticModifierUncapped(attacker, "exotic_block_reduction") / 5.0f);
blockReduction += (float)(getEnhancedSkillStatisticModifierUncapped(attacker, "combat_block_reduction") / 5.0f);
return blockReduction;
}
public static int getBlockAmmount(obj_id player) throws InterruptedException
{
int blockAmmount = isPlayer(player) || beast_lib.isBeast(player) ? 25 : Math.round((getLevel(player) * 2));
float blockStat = 0.0f;
blockStat += getEnhancedSkillStatisticModifierUncapped(player, "strength_modified");
blockStat += getSkillStatisticModifier(player, "strength");
blockStat += getEnhancedSkillStatisticModifierUncapped(player, "combat_block_value");
blockStat = Math.round((float)blockStat * 0.5f);
blockAmmount += blockStat;
if (beast_lib.isBeastMaster(player) || beast_lib.isBeast(player))
{
blockAmmount += beast_lib.getBeastBlockValue(player);
}
return blockAmmount;
}
public static float getEvasionChance(attacker_data attackerData, defender_data defenderData) throws InterruptedException
{
float evasionChance = 0.0f;
evasionChance += defenderData.evadeChance;
evasionChance -= attackerData.reduceEvade;
return evasionChance;
}
public static float getDefenderEvasionChance(obj_id player) throws InterruptedException
{
float evasionChance = isPlayer(player) || beast_lib.isBeast(player) ? 5.0f : (getLevel(player) * 0.2f);
evasionChance += (getEnhancedSkillStatisticModifierUncapped(player, "agility_modified") / 100.0f);
evasionChance += (getSkillStatisticModifier(player, "agility") / 100.0f);
evasionChance += (getEnhancedSkillStatisticModifierUncapped(player, "luck_modified") / 300.0f);
evasionChance += (getSkillStatisticModifier(player, "luck") / 300.0f);
evasionChance += (getDiminishedReturnValue(getEnhancedSkillStatisticModifierUncapped(player, "combat_evasion_chance"), DR_DEFENDER_EVADE) / 10.0f);
evasionChance += getEnhancedSkillStatisticModifierUncapped(player, "expertise_evasion_chance");
if (beast_lib.isBeastMaster(player) || beast_lib.isBeast(player))
{
evasionChance += beast_lib.getBeastEvadeChance(player);
}
return evasionChance;
}
public static float getAttackerEvasionReduction(obj_id attacker) throws InterruptedException
{
return 0.0f;
}
public static float getHitReductionChance(obj_id player) throws InterruptedException
{
return getEnhancedSkillStatisticModifierUncapped(player, "expertise_critical_hit_reduction");
}
public static float getPvPHitReductionChance(obj_id player) throws InterruptedException
{
return getEnhancedSkillStatisticModifierUncapped(player, "expertise_critical_hit_pvp_reduction");
}
public static float getEvasionRoll(obj_id player) throws InterruptedException
{
float evasionRoll = 0.0f;
evasionRoll += (getEnhancedSkillStatisticModifierUncapped(player, "combat_evasion_value") / 4.0f);
if (evasionRoll < 0)
{
return -1.0f;
}
evasionRoll += 10.0f;
evasionRoll += (getEnhancedSkillStatisticModifierUncapped(player, "luck_modified") / 10.0f);
evasionRoll += (getSkillStatisticModifier(player, "luck") / 10.0f);
if (beast_lib.isBeastMaster(player) || beast_lib.isBeast(player))
{
evasionRoll += beast_lib.getBeastEvadeValue(player);
}
return evasionRoll > 99.0f ? 99.0f : evasionRoll;
}
public static float getCriticalHitChance(attacker_data attackerData, defender_data defenderData, combat_data actionData, boolean autoAiming) throws InterruptedException
{
obj_id attacker = attackerData.id;
obj_id defender = defenderData.id;
float critChance = attackerData.critChance;
float altCritChance = 0.0f;
String specialLine = actionData.specialLine;
critChance += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_critical_line_" + specialLine);
if (!autoAiming && isPlayer(attacker))
{
critChance += 3.0f;
}
float specificDefenderMod = 0.0f;
if (isPlayer(defender))
{
altCritChance += attackerData.pvpCrit;
}
else if (ai_lib.isDroid(defender) || ai_lib.isAndroid(defender))
{
altCritChance += attackerData.droidCrit;
}
else if (ai_lib.isNpc(defender))
{
altCritChance += attackerData.npcCrit;
}
else if (ai_lib.isMonster(defender))
{
altCritChance += attackerData.creatureCrit;
}
altCritChance = getDiminishedReturnValue(altCritChance, DR_ATTACKER_CRITICAL_2);
critChance -= defenderData.reduceCritical;
if (isPlayer(defender) && (isPlayer(attacker) || (isMob(attacker) && isIdValid(getMaster(attacker)) && isPlayer(getMaster(attacker)))))
{
critChance -= getEnhancedSkillStatisticModifierUncapped(defender, "expertise_critical_hit_pvp_reduction");
}
critChance += actionData.increaseCritical;
critChance += altCritChance;
return critChance;
}
public static float getAttackerCritMod(obj_id attacker) throws InterruptedException
{
float critMod = isPlayer(attacker) ? 5.0f : getLevel(attacker) * 0.15f;
float dr_critMod = 0.0f;
float dr_critMod2 = 0.0f;
critMod += utils.getIntScriptVar(attacker, "expertise_stance_critical");
critMod += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_critical_niche_all");
critMod += (getDiminishedReturnValue(getEnhancedSkillStatisticModifierUncapped(attacker, "combat_critical_hit"), DR_ATTACKER_CRITICAL) / 10.0f);
if (beast_lib.isBeastMaster(attacker) || beast_lib.isBeast(attacker))
{
critMod += beast_lib.getBeastCritChance(attacker);
}
critMod += (getEnhancedSkillStatisticModifierUncapped(attacker, "precision_modified") / 100.0f);
critMod += (getSkillStatisticModifier(attacker, "precision") / 100.0f);
critMod += (getEnhancedSkillStatisticModifierUncapped(attacker, "luck_modified") / 300.0f);
critMod += (getSkillStatisticModifier(attacker, "luck") / 300.0f);
obj_id weapon = getCurrentWeapon(attacker);
if (!isIdValid(weapon))
{
return critMod;
}
weapon_data weaponData = weapons.getNewWeaponData(weapon);
if (weaponData == null)
{
CustomerServiceLog("COMBAT_exception", "getAttackerCritMod: Player %TU caused an exception with bad cached data on weapon " + weapon + "/" + getTemplateName(weapon), attacker);
}
boolean isRangedAttacker = isRangedWeapon(weapon);
if (isRangedAttacker)
{
dr_critMod2 += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_critical_ranged");
dr_critMod += (getEnhancedSkillStatisticModifierUncapped(attacker, "combat_critical_ranged") / 10.0f);
critMod += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_undiminished_critical_ranged");
}
else
{
dr_critMod2 += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_critical_melee");
dr_critMod += (getEnhancedSkillStatisticModifierUncapped(attacker, "combat_critical_melee") / 10.0f);
critMod += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_undiminished_critical_melee");
}
if(weaponData != null) {
switch (weaponData.weaponType) {
case WEAPON_TYPE_PISTOL:
dr_critMod2 += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_critical_pistol");
critMod += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_undiminished_critical_pistol");
break;
case WEAPON_TYPE_RIFLE:
dr_critMod2 += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_critical_rifle");
critMod += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_undiminished_critical_rifle");
break;
case WEAPON_TYPE_LIGHT_RIFLE:
dr_critMod2 += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_critical_carbine");
critMod += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_undiminished_critical_carbine");
break;
case WEAPON_TYPE_HEAVY:
dr_critMod2 += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_critical_heavy");
critMod += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_undiminished_critical_heavy");
break;
case WEAPON_TYPE_GROUND_TARGETTING:
dr_critMod2 += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_critical_heavy");
critMod += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_undiminished_critical_heavy");
break;
case WEAPON_TYPE_DIRECTIONAL:
dr_critMod2 += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_critical_heavy");
critMod += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_undiminished_critical_heavy");
break;
case WEAPON_TYPE_1HAND_MELEE:
dr_critMod2 += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_critical_1h");
critMod += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_undiminished_critical_1h");
break;
case WEAPON_TYPE_2HAND_MELEE:
dr_critMod2 += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_critical_2h");
critMod += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_undiminished_critical_2h");
break;
case WEAPON_TYPE_UNARMED:
dr_critMod2 += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_critical_unarmed");
critMod += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_undiminished_critical_unarmed");
break;
case WEAPON_TYPE_POLEARM:
dr_critMod2 += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_critical_polearm");
critMod += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_undiminished_critical_polearm");
break;
case WEAPON_TYPE_WT_1HAND_LIGHTSABER:
case WEAPON_TYPE_WT_2HAND_LIGHTSABER:
case WEAPON_TYPE_WT_POLEARM_LIGHTSABER:
dr_critMod2 += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_critical_lightsaber");
critMod += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_undiminished_critical_lightsaber");
break;
}
}
dr_critMod = getDiminishedReturnValue(dr_critMod, DR_ATTACKER_CRITICAL);
dr_critMod2 = getDiminishedReturnValue(dr_critMod2, DR_ATTACKER_CRITICAL_2);
critMod += dr_critMod;
critMod += dr_critMod2;
return critMod;
}
public static float getDefenderCriticalChance(obj_id defender) throws InterruptedException
{
float critChance = 0.0f;
critChance -= getEnhancedSkillStatisticModifierUncapped(defender, "critical_hit_vulnerable");
critChance += (getEnhancedSkillStatisticModifierUncapped(defender, "combat_critical_hit_reduction") / 3.0f);
critChance += getEnhancedSkillStatisticModifierUncapped(defender, "expertise_critical_hit_reduction");
return critChance;
}
public static float getStrikethroughChance(attacker_data attackerData, defender_data defenderData, combat_data actionData) throws InterruptedException
{
float strikethroughChance = 0.0f;
strikethroughChance += attackerData.strikethroughChance;
strikethroughChance -= defenderData.reduceStrikethrough;
strikethroughChance += actionData.increaseStrikethrough;
return strikethroughChance;
}
public static float getAttackerStrikethroughChance(obj_id player) throws InterruptedException
{
float strikethrough = isPlayer(player) || beast_lib.isBeast(player) ? 5.0f : getLevel(player) * 0.08f;
strikethrough += (getEnhancedSkillStatisticModifierUncapped(player, "precision_modified") / 200.0f);
strikethrough += (getSkillStatisticModifier(player, "precision") / 200.0f);
strikethrough += (getEnhancedSkillStatisticModifierUncapped(player, "luck_modified") / 200.0f);
strikethrough += (getSkillStatisticModifier(player, "luck") / 200.0f);
strikethrough += (getDiminishedReturnValue(getEnhancedSkillStatisticModifierUncapped(player, "combat_strikethrough_chance"), DR_ATTACKER_STRIKETHROUGH) / 10.0f);
strikethrough += getEnhancedSkillStatisticModifierUncapped(player, "expertise_strikethrough_chance");
if (beast_lib.isBeastMaster(player) || beast_lib.isBeast(player))
{
strikethrough += beast_lib.getBeastStrikethroughChance(player);
}
return strikethrough;
}
public static float getDefenderStrikethroughReduction(obj_id player) throws InterruptedException
{
float strikethroughChance = 0.0f;
strikethroughChance -= getEnhancedSkillStatisticModifierUncapped(player, "strikethrough_vulnerable");
return strikethroughChance;
}
public static float getStrikethroughValue(obj_id attacker, obj_id defender) throws InterruptedException
{
return getAttackerStrikethroughValue(attacker);
}
public static float getAttackerStrikethroughValue(obj_id player) throws InterruptedException
{
float strikethroughValue = isPlayer(player) ? 10.0f : 35.0f;
strikethroughValue += (getEnhancedSkillStatisticModifierUncapped(player, "luck_modified") / 10.0f);
strikethroughValue += (getSkillStatisticModifier(player, "luck") / 10.0f);
strikethroughValue += (getEnhancedSkillStatisticModifierUncapped(player, "combat_strikethrough_value") / 2.0f);
if (beast_lib.isBeastMaster(player) || beast_lib.isBeast(player))
{
strikethroughValue += beast_lib.getBeastStrikethroughValue(player);
}
return strikethroughValue > 99.0f ? 99.0f : strikethroughValue;
}
public static float getToHitBonus(obj_id player) throws InterruptedException
{
float hitBonus = 0.0f;
hitBonus += (getEnhancedSkillStatisticModifierUncapped(player, "strength_modified") / 100.0f);
hitBonus += (getSkillStatisticModifier(player, "strength") / 100.0f);
hitBonus += getEnhancedSkillStatisticModifierUncapped(player, "expertise_to_hit");
if (beast_lib.isBeastMaster(player) || beast_lib.isBeast(player))
{
hitBonus += beast_lib.getBeastHitChance(player);
}
return hitBonus;
}
public static float getDefenderHitReduction(obj_id player) throws InterruptedException
{
float increaseMiss = 0.0f;
return increaseMiss;
}
public static attacker_data fillAttackerCombatAttributes(attacker_data attackerData) throws InterruptedException
{
if (!utils.hasScriptVar(attackerData.id, ATTACKER_DATA))
{
cacheAttackerData(attackerData.id);
}
attackerData.critChance = utils.getFloatScriptVar(attackerData.id, ATTACKER_BASE_CRIT);
attackerData.pvpCrit = utils.getFloatScriptVar(attackerData.id, ATTACKER_PVP_CRIT);
attackerData.npcCrit = utils.getFloatScriptVar(attackerData.id, ATTACKER_NPC_CRIT);
attackerData.droidCrit = utils.getFloatScriptVar(attackerData.id, ATTACKER_DROID_CRIT);
attackerData.creatureCrit = utils.getFloatScriptVar(attackerData.id, ATTACKER_CREATURE_CRIT);
attackerData.hitChance = utils.getFloatScriptVar(attackerData.id, ATTACKER_HIT_BONUS);
attackerData.strikethroughChance = utils.getFloatScriptVar(attackerData.id, ATTACKER_STRIKETHROUGH);
attackerData.reduceParry = utils.getFloatScriptVar(attackerData.id, ATTACKER_REDUCE_PARRY);
attackerData.reduceBlock = utils.getFloatScriptVar(attackerData.id, ATTACKER_REDUCE_BLOCK);
attackerData.reduceDodge = utils.getFloatScriptVar(attackerData.id, ATTACKER_REDUCE_DODGE);
attackerData.reduceGlancing = utils.getFloatScriptVar(attackerData.id, ATTACKER_REDUCE_GLANCING);
attackerData.reduceEvade = utils.getFloatScriptVar(attackerData.id, ATTACKER_REDUCE_EVADE);
return attackerData;
}
public static defender_data fillDefenderCombatAttributes(defender_data defenderData) throws InterruptedException
{
if (!utils.hasScriptVar(defenderData.id, DEFENDER_DATA))
{
cacheDefenderData(defenderData.id);
}
defenderData.reduceCritical = utils.getFloatScriptVar(defenderData.id, DEFENDER_REDUCE_CRIT);
defenderData.increaseMiss = utils.getFloatScriptVar(defenderData.id, DEFENDER_INCREASE_MISS);
defenderData.reduceStrikethrough = utils.getFloatScriptVar(defenderData.id, DEFENDER_REDUCE_STRIKETHROUGH);
defenderData.reducePunishing = utils.getFloatScriptVar(defenderData.id, DEFENDER_REDUCE_PUNISH);
defenderData.glancingChance = utils.getFloatScriptVar(defenderData.id, DEFENDER_GLANCING);
defenderData.parryChance = utils.getFloatScriptVar(defenderData.id, DEFENDER_PARRY);
defenderData.dodgeChance = utils.getFloatScriptVar(defenderData.id, DEFENDER_DODGE);
defenderData.evadeChance = utils.getFloatScriptVar(defenderData.id, DEFENDER_EVADE);
defenderData.blockChance = utils.getFloatScriptVar(defenderData.id, DEFENDER_BLOCK);
return defenderData;
}
public static void cacheCombatData(obj_id self) throws InterruptedException
{
cacheAttackerData(self);
cacheDefenderData(self);
}
public static void clearCachedCombatData(obj_id self) throws InterruptedException
{
utils.removeScriptVarTree(self, ATTACKER_DATA);
utils.removeScriptVarTree(self, DEFENDER_DATA);
}
public static void cacheAttackerData(obj_id attacker) throws InterruptedException
{
utils.setScriptVar(attacker, ATTACKER_BASE_CRIT, getAttackerCritMod(attacker));
utils.setScriptVar(attacker, ATTACKER_PVP_CRIT, (float)getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_critical_niche_pvp"));
utils.setScriptVar(attacker, ATTACKER_DROID_CRIT, (float)getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_critical_niche_droid"));
utils.setScriptVar(attacker, ATTACKER_NPC_CRIT, (float)getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_critical_niche_npc"));
utils.setScriptVar(attacker, ATTACKER_CREATURE_CRIT, (float)getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_critical_niche_creature"));
utils.setScriptVar(attacker, ATTACKER_HIT_BONUS, getToHitBonus(attacker));
utils.setScriptVar(attacker, ATTACKER_STRIKETHROUGH, getAttackerStrikethroughChance(attacker));
utils.setScriptVar(attacker, ATTACKER_REDUCE_PARRY, getAttackerParryReduction(attacker));
utils.setScriptVar(attacker, ATTACKER_REDUCE_BLOCK, getAttackerBlockReduction(attacker));
utils.setScriptVar(attacker, ATTACKER_REDUCE_DODGE, getAttackerDodgeReduction(attacker));
utils.setScriptVar(attacker, ATTACKER_REDUCE_GLANCING, getAttackerGlancingReduction(attacker));
utils.setScriptVar(attacker, ATTACKER_REDUCE_EVADE, getAttackerEvasionReduction(attacker));
}
public static void cacheDefenderData(obj_id defender) throws InterruptedException
{
utils.setScriptVar(defender, DEFENDER_REDUCE_CRIT, getDefenderCriticalChance(defender));
utils.setScriptVar(defender, DEFENDER_INCREASE_MISS, getDefenderHitReduction(defender));
utils.setScriptVar(defender, DEFENDER_REDUCE_STRIKETHROUGH, getDefenderStrikethroughReduction(defender));
utils.setScriptVar(defender, DEFENDER_REDUCE_PUNISH, getDefenderPunishingBlowReduction(defender));
utils.setScriptVar(defender, DEFENDER_GLANCING, getDefenderGlancingBlowChance(defender));
utils.setScriptVar(defender, DEFENDER_PARRY, getDefenderParryChance(defender));
utils.setScriptVar(defender, DEFENDER_DODGE, getDefenderDodgeChance(defender));
utils.setScriptVar(defender, DEFENDER_EVADE, getDefenderEvasionChance(defender));
utils.setScriptVar(defender, DEFENDER_BLOCK, getDefenderBlockChance(defender));
}
public static obj_id getRandomHateTarget(obj_id self) throws InterruptedException
{
obj_id[] potentialTargets = getHateList(self);
if (potentialTargets == null || potentialTargets.length == 0)
{
return null;
}
float max_range = 64.0f;
Vector validTargets = new Vector();
validTargets.setSize(0);
for (obj_id potentialTarget : potentialTargets) {
if (isIdValid(potentialTarget) && exists(potentialTarget) && canSee(self, potentialTarget) && !stealth.hasInvisibleBuff(potentialTarget) && getMaster(potentialTarget) == null && !isDead(potentialTarget)) {
if (getDistance(self, potentialTarget) < max_range) {
utils.addElement(validTargets, potentialTarget);
}
}
}
if (validTargets == null || validTargets.size() == 0)
{
return null;
}
return ((obj_id)validTargets.get(rand(0, validTargets.size() - 1)));
}
public static boolean doBhTaunt(obj_id player, obj_id target) throws InterruptedException
{
if (!isIdValid(player) || !isIdValid(target))
{
return false;
}
if (!exists(player) || !exists(target))
{
return false;
}
obj_id[] enemies = getHateList(target);
if (enemies == null || enemies.length == 0)
{
return false;
}
obj_id topHateTarget = getHateTarget(target);
float topHateAmount = getHate(target, topHateTarget);
int level = getLevel(player);
float increasedHate = topHateAmount;
if (level <= BH_TAUNT_LOW_LEVEL)
{
increasedHate += BH_TAUNT_HATE_INCREASE_LOW;
}
else if (level <= BH_TAUNT_MID_LEVEL)
{
increasedHate += BH_TAUNT_HATE_INCREASE_MID;
}
else
{
increasedHate += BH_TAUNT_HATE_INCREASE_HIGH;
}
addHate(target, player, increasedHate);
return true;
}
public static boolean dsFsTaunt(obj_id player, obj_id target) throws InterruptedException
{
int stanceBuff = buff.getBuffOnTargetFromGroup(player, "fsStance");
if (stanceBuff == 0)
{
return false;
}
if (!isIdValid(player) || !isIdValid(target))
{
return false;
}
if (!exists(player) || !exists(target))
{
return false;
}
obj_id[] enemies = getHateList(target);
if (enemies == null || enemies.length == 0)
{
return false;
}
obj_id topHateTarget = getHateTarget(target);
float topHateAmount = getHate(target, topHateTarget);
int level = getLevel(player);
float increasedHate = topHateAmount;
if (level <= FS_TAUNT_LOW_LEVEL)
{
increasedHate += FS_TAUNT_HATE_INCREASE_LOW;
}
else if (level <= FS_TAUNT_MID_LEVEL)
{
increasedHate += FS_TAUNT_HATE_INCREASE_MID;
}
else
{
increasedHate += FS_TAUNT_HATE_INCREASE_HIGH;
}
addHate(target, player, increasedHate);
return true;
}
public static boolean isStunned(obj_id target) throws InterruptedException
{
return utils.hasScriptVar(target, TEMP_COMBAT_BLOCK);
}
public static int[] getSuccessBasedSingleTargetActionCost(hit_result hitData, combat_data actionData, obj_id attacker, weapon_data weaponData) throws InterruptedException
{
boolean isSingleTargetAttack = actionData.hitType == -1 && actionData.attackType == combat.SINGLE_TARGET && actionData.commandType != combat.LEFT_CLICK_DEFAULT;
int[] freeShot =
{
0,
0,
0
};
if (!isSingleTargetAttack)
{
return freeShot;
}
int freeMiss = getEnhancedSkillStatisticModifierUncapped(attacker, "freeshot_case_miss");
int freeDodge = getEnhancedSkillStatisticModifierUncapped(attacker, "freeshot_case_dodge");
int freeParry = getEnhancedSkillStatisticModifierUncapped(attacker, "freeshot_case_parry");
int freeCrit = getEnhancedSkillStatisticModifierUncapped(attacker, "freeshot_case_crit");
int freeStrike = getEnhancedSkillStatisticModifierUncapped(attacker, "freeshot_case_strikethrough");
boolean isFreeshot = false;
if (hitData.success == false)
{
if (freeMiss > 0)
{
isFreeshot = true;
}
if (hitData.dodge == true && freeDodge > 0)
{
isFreeshot = true;
}
if (hitData.parry == true && freeParry > 0)
{
isFreeshot = true;
}
}
if (hitData.success == true)
{
if (hitData.critical == true && freeCrit > 0)
{
isFreeshot = true;
}
if (hitData.strikethrough == true && freeStrike > 0)
{
isFreeshot = true;
}
}
if (isFreeshot)
{
prose_package pp = new prose_package();
pp = prose.setStringId(pp, new string_id("spam", "freeshot"));
showFlyTextPrivateProseWithFlags(attacker, attacker, pp, 1.5f, colors.LEMONCHIFFON, FLY_TEXT_FLAG_IS_FREESHOT);
return freeShot;
}
int[] shotCost = getActionCost(attacker, weaponData, actionData);
return shotCost;
}
public static void setPersistCombatMode(obj_id target, boolean state) throws InterruptedException
{
if (!isMob(target))
{
return;
}
if (!state)
{
if (utils.hasScriptVar(target, combat.PERSIST_COMBAT))
{
utils.removeScriptVar(target, combat.PERSIST_COMBAT);
}
return;
}
utils.setScriptVar(target, combat.PERSIST_COMBAT, 1);
return;
}
public static boolean isPersistCombatMode(obj_id self) throws InterruptedException
{
return utils.hasScriptVar(self, combat.PERSIST_COMBAT);
}
public static boolean isValidPersistCombat(obj_id self) throws InterruptedException
{
if (isInvulnerable(self))
{
return false;
}
if (!getCreatureCoverVisibility(self))
{
return false;
}
if (isDead(self))
{
return false;
}
obj_id[] hateList = getHateList(self);
if (hateList == null || hateList.length == 0)
{
return false;
}
boolean hasLos = true;
for (obj_id obj_id : hateList) {
hasLos |= canSee(self, obj_id);
}
if (!hasLos)
{
return false;
}
return true;
}
public static boolean isDamageImmune(obj_id attacker, obj_id defender, combat_data actionData) throws InterruptedException
{
boolean attackerImmune = getEnhancedSkillStatisticModifierUncapped(attacker, "damage_immune") > 0;
boolean defenderImmune = getEnhancedSkillStatisticModifierUncapped(defender, "damage_immune") > 0;
prose_package pp = new prose_package();
boolean isBeneficial = (actionData.hitType == NON_ATTACK || actionData.hitType == NON_DAMAGE_ATTACK) && pvpCanHelp(attacker, defender);
if (attackerImmune && !isBeneficial)
{
pp.stringId = new string_id("cbt_spam", "immune_hit_other");
pp.target.set(defender);
pp.other.set(new string_id("cmd_n", actionData.actionName));
sendCombatSpamMessageProse(attacker, pp);
pp.target.set(attacker);
pp.stringId = new string_id("cbt_spam", "immune_target_hit_other");
sendCombatSpamMessageProse(defender, pp);
}
if (defenderImmune && !isBeneficial)
{
pp.stringId = new string_id("cbt_spam", "immune_get_hit");
pp.target.set(attacker);
pp.other.set(new string_id("cmd_n", actionData.actionName));
sendCombatSpamMessageProse(defender, pp);
pp.target.set(defender);
pp.stringId = new string_id("cbt_spam", "immune_target_hit");
sendCombatSpamMessageProse(attacker, pp);
}
return (attackerImmune || defenderImmune) && !isBeneficial;
}
public static float getDiminishedReturnValue(float value, int modType) throws InterruptedException
{
if (value < 0.0f)
{
return value;
}
float[] seedList =
{
500.0f,
500.0f,
500.0f,
500.0f,
500.0f,
500.0f,
500.0f,
50.0f
};
switch (modType)
{
case DR_ATTACKER_CRITICAL:
return (value * (1.0f - (value / (value + seedList[DR_ATTACKER_CRITICAL]))));
case DR_ATTACKER_STRIKETHROUGH:
return (value * (1.0f - (value / (value + seedList[DR_ATTACKER_STRIKETHROUGH]))));
case DR_DEFENDER_BLOCK:
return (value * (1.0f - (value / (value + seedList[DR_DEFENDER_BLOCK]))));
case DR_DEFENDER_DODGE:
return (value * (1.0f - (value / (value + seedList[DR_DEFENDER_DODGE]))));
case DR_DEFENDER_PARRY:
return (value * (1.0f - (value / (value + seedList[DR_DEFENDER_PARRY]))));
case DR_DEFENDER_GLANCE:
return (value * (1.0f - (value / (value + seedList[DR_DEFENDER_GLANCE]))));
case DR_DEFENDER_EVADE:
return (value * (1.0f - (value / (value + seedList[DR_DEFENDER_EVADE]))));
case DR_ATTACKER_CRITICAL_2:
return (value * (1.0f - (value / (value + seedList[DR_ATTACKER_CRITICAL_2]))));
}
return value;
}
public static void mirrorArmor(obj_id commando) throws InterruptedException
{
obj_id[] haters = getHateList(commando);
if (haters != null || haters.length > 0)
{
for (obj_id hater : haters) {
float myHate = getHate(hater, commando);
if (myHate <= 0.0f) {
continue;
}
myHate /= 2.0f;
setHate(hater, commando, myHate);
}
}
}
public static boolean setKillMeter(obj_id player, int value) throws InterruptedException
{
int current = getKillMeter(player);
int delta = value - current;
incrementKillMeter(player, delta);
return true;
}
public static boolean modifyKillMeter(obj_id player, int value) throws InterruptedException
{
int current = getKillMeter(player);
int delta = current + value;
if (delta < 0)
{
delta = 0;
}
if (delta > 50)
{
delta = 50;
}
setKillMeter(player, delta);
return true;
}
public static boolean canDrainKillMeter(obj_id player, int value) throws InterruptedException
{
if (!isPlayer(player))
{
return true;
}
int current = getKillMeter(player);
int delta = current - value;
return delta < 0 ? false : true;
}
public static boolean drainKillMeter(obj_id player, int value) throws InterruptedException
{
if (!isPlayer(player))
{
return true;
}
if (!canDrainKillMeter(player, value))
{
return false;
}
return modifyKillMeter(player, -1 * value);
}
public static location getCommandGroundTargetLocation(String params) throws InterruptedException
{
String[] stringLocationParams = split(params, ' ');
if (stringLocationParams == null || stringLocationParams.length <= 0)
{
return null;
}
location eggLoc = new location();
boolean inCell = false;
if (isIdValid(utils.stringToObjId(stringLocationParams[3])))
{
inCell = true;
}
if (!inCell)
{
eggLoc.x = utils.stringToFloat(stringLocationParams[0]);
eggLoc.y = utils.stringToFloat(stringLocationParams[1]);
eggLoc.z = utils.stringToFloat(stringLocationParams[2]);
}
else
{
eggLoc.cell = utils.stringToObjId(stringLocationParams[3]);
eggLoc.x = utils.stringToFloat(stringLocationParams[4]);
eggLoc.y = utils.stringToFloat(stringLocationParams[5]);
eggLoc.z = utils.stringToFloat(stringLocationParams[6]);
}
return eggLoc;
}
public static float getDevastationChance(obj_id attacker) throws InterruptedException
{
float devastationBonus = 2.0f;
devastationBonus += getEnhancedSkillStatisticModifierUncapped(attacker, "commando_devastation");
devastationBonus += getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_devastation_bonus") / 10.0f;
return devastationBonus;
}
public static float getElementalPenetration(obj_id attacker, String damageString) throws InterruptedException
{
float elementalPenetrationAmount = 0.0f;
if (isIdValid(attacker) && damageString != null && damageString.length() > 0)
{
String elementalPenetrationSkillModName = "exotic_" + damageString + "_penetration";
float elementalPenetrationSkillMod = getEnhancedSkillStatisticModifierUncapped(attacker, elementalPenetrationSkillModName);
if (elementalPenetrationSkillMod > MAX_RE_EXOTIC_ELEMENTAL_PENETRATION_SKILLMOD)
{
elementalPenetrationSkillMod = MAX_RE_EXOTIC_ELEMENTAL_PENETRATION_SKILLMOD;
}
elementalPenetrationAmount = 100.0f - (elementalPenetrationSkillMod * 2.5f);
elementalPenetrationAmount *= 0.01f;
}
return elementalPenetrationAmount;
}
public static boolean hasPrescience(obj_id attacker, obj_id defender, combat_data actionData) throws InterruptedException
{
if (!buff.hasBuff(defender, "bh_prescience"))
{
return false;
}
obj_id owner = buff.getBuffCaster(defender, "bh_prescience");
if (attacker == owner)
{
prose_package pp = new prose_package();
pp.stringId = new string_id("cbt_spam", "bh_prescience_attacker");
pp.target.set(defender);
pp.other.set(new string_id("cmd_n", actionData.actionName));
sendCombatSpamMessageProse(attacker, pp);
pp.target.set(attacker);
pp.stringId = new string_id("cbt_spam", "bh_prescience_defender");
sendCombatSpamMessageProse(defender, pp);
return true;
}
return false;
}
}