Files
dsrc/sku.0/sys.server/compiled/game/script/library/dot.scriptlib
T

3478 lines
106 KiB
Plaintext

/**********************************************************************
* Copyright (c)2000-2002 Sony Online Entertainment Inc.
* All Rights Reserved
*
* Title: dot.scriptlib
* Description: contains the library methods for damage over time effects
* @author $Author:$
* @version $Revision:$
**********************************************************************/
/***** INCLUDES ********************************************************/
include library.prose;
include library.vehicle;
include library.utils;
include library.combat;
include library.ai_lib;
include java.util.Enumeration;
include java.util.HashSet;
include java.util.Vector;
include library.colors;
include library.beast_lib;
include library.skill;
include library.trial;
/***** CONSTANTS *******************************************************/
// Dot types
const string DOT_BLEEDING = "bleeding";
const string DOT_POISON = "poison";
const string DOT_DISEASE = "disease";
const string DOT_FIRE = "fire";
const string DOT_ACID = "acid";
const string DOT_ENERGY = "energy";
const string DOT_COLD = "cold";
const string DOT_ELECTRICITY = "electricity";
const string DOT_KINETIC = "kinetic";
// Scripts
const string SCRIPT_PLAYER_DOT = "player.player_dot";
// Dot ScriptVars
const string VAR_DOT = "dot";
const string VAR_DOT_ROOT = "dot.";
const string VAR_TYPE = ".type";
const string VAR_ATTRIBUTE = ".attribute";
const string VAR_POTENCY = ".potency"; // source only
const string VAR_STRENGTH = ".strength";
const string VAR_DURATION = ".duration";
const string VAR_TIME_START = ".time_start";
const string VAR_LAST_PULSE = ".last_pulse";
const string VAR_HANDLER = ".handler";
const string VAR_ATTACKER = ".attacker";
const string VAR_USES = ".uses"; // source only
// System constants
const int DOT_MAXIMUM_COUNT = 3;
const int BASE_RESISTANCE = 100;
const int BLEEDING_PULSE = 1;
const int POISON_PULSE = 1;
const int DISEASE_PULSE = 1;
const int FIRE_PULSE = 1;
const int ACID_PULSE = 1;
const int ENERGY_PULSE = 1;
const int DOT_GRACE_PERIOD = 60;
const int MOD_DIVISOR = 3;
const int DOT_ARMOR_MITIGATION_PERCENT = 50;
const float VAR_EFFECT_DISPLAY_RADIUS = 45.0f;
// Script Vars
const string SCRIPT_VAR_DOT_GRACE = "dot.dot_grace";
// Hit locations
const string[] HIT_LOCATIONS = {"body", "head", "right_arm", "left_arm", "right_leg", "left_leg"};
// Attribute hit location
const int[] HIT_LOCATION_ATTRIBUTE = {HEALTH, MIND, HEALTH, HEALTH, ACTION, ACTION};
// String id's
const string_id SID_BLEEDING = new string_id("dot_message", "start_bleeding");
const string_id SID_POISONED = new string_id("dot_message", "start_poisoned");
const string_id SID_DISEASED = new string_id("dot_message", "start_diseased");
const string_id SID_FIRE = new string_id("dot_message", "start_fire");
const string_id SID_ACID = new string_id("dot_message", "start_acid");
const string_id SID_ENERGY = new string_id("dot_message", "start_energy");
const string_id SID_COLD = new string_id("dot_message", "start_cold");
const string_id SID_ELECTRICITY = new string_id("dot_message", "start_electricity");
const string_id SID_KINETIC = new string_id("dot_message", "start_kinetic");
const string_id SID_BLEEDING_INCREASE = new string_id("dot_message", "increase_bleeding");
const string_id SID_POISONED_INCREASE = new string_id("dot_message", "increase_poisoned");
const string_id SID_DISEASED_INCREASE = new string_id("dot_message", "increase_diseased");
const string_id SID_FIRE_INCREASE = new string_id("dot_message", "increase_fire");
const string_id SID_ACID_INCREASE = new string_id("dot_message", "increase_acid");
const string_id SID_ENERGY_INCREASE = new string_id("dot_message", "increase_energy");
const string_id SID_COLD_INCREASE = new string_id("dot_message", "increase_cold");
const string_id SID_ELECTRICITY_INCREASE = new string_id("dot_message", "increase_electricity");
const string_id SID_KINETIC_INCREASE = new string_id("dot_message", "increase_kinetic");
const string_id SID_BLEEDING_DECREASE = new string_id("dot_message", "decrease_bleeding");
const string_id SID_POISONED_DECREASE = new string_id("dot_message", "decrease_poisoned");
const string_id SID_DISEASED_DECREASE = new string_id("dot_message", "decrease_diseased");
const string_id SID_FIRE_DECREASE = new string_id("dot_message", "decrease_fire");
const string_id SID_ACID_DECREASE = new string_id("dot_message", "decrease_acid");
const string_id SID_ENERGY_DECREASE = new string_id("dot_message", "decrease_energy");
const string_id SID_COLD_DECREASE = new string_id("dot_message", "decrease_cold");
const string_id SID_ELECTRICITY_DECREASE = new string_id("dot_message", "decrease_electricity");
const string_id SID_KINETIC_DECREASE = new string_id("dot_message", "decrease_kinetic");
const string_id SID_BLEEDING_STOP = new string_id("dot_message", "stop_bleeding");
const string_id SID_POISONED_STOP = new string_id("dot_message", "stop_poisoned");
const string_id SID_DISEASED_STOP = new string_id("dot_message", "stop_diseased");
const string_id SID_FIRE_STOP = new string_id("dot_message", "stop_fire");
const string_id SID_ACID_STOP = new string_id("dot_message", "stop_acid");
const string_id SID_ENERGY_STOP = new string_id("dot_message", "stop_energy");
const string_id SID_COLD_STOP = new string_id("dot_message", "stop_cold");
const string_id SID_ELECTRICITY_STOP = new string_id("dot_message", "stop_electricity");
const string_id SID_KINETIC_STOP = new string_id("dot_message", "stop_kinetic");
const string_id SID_DOT_RESISTED = new string_id("dot_message", "dot_resisted");
const string_id SID_DOT_RESISTED_SPAM = new string_id("dot_message", "spam_dot_resisted");
const string_id SID_BLEED_DMG = new string_id("dot_message", "bleed_dmg");
const string_id SID_BLEED_DMG_ATKR = new string_id("dot_message", "bleed_dmg_atkr");
const string_id SID_POISON_DMG = new string_id("dot_message", "poison_dmg");
const string_id SID_POISON_DMG_ATKR = new string_id("dot_message", "poison_dmg_atkr");
const string_id SID_FIRE_DMG = new string_id("dot_message", "fire_dmg");
const string_id SID_FIRE_DMG_ATKR = new string_id("dot_message", "fire_dmg_atkr");
const string_id SID_DISEASE_DMG = new string_id("dot_message", "disease_dmg");
const string_id SID_DISEASE_DMG_ATKR = new string_id("dot_message", "disease_dmg_atkr");
const string_id SID_ACID_DMG = new string_id("dot_message", "acid_dmg");
const string_id SID_ACID_DMG_ATKR = new string_id("dot_message", "acid_dmg_atkr");
const string_id SID_ENERGY_DMG = new string_id("dot_message", "energy_dmg");
const string_id SID_ENERGY_DMG_ATKR = new string_id("dot_message", "energy_dmg_atkr");
const string_id SID_COLD_DMG = new string_id("dot_message", "cold_dmg");
const string_id SID_COLD_DMG_ATKR = new string_id("dot_message", "cold_dmg_atkr");
const string_id SID_ELECTRICITY_DMG = new string_id("dot_message", "electricity_dmg");
const string_id SID_ELECTRICITY_DMG_ATKR = new string_id("dot_message", "electricity_dmg_atkr");
const string_id SID_KINETIC_DMG = new string_id("dot_message", "kinetic_dmg");
const string_id SID_KINETIC_DMG_ATKR = new string_id("dot_message", "kinetic_dmg_atkr");
/***** TRIGGERS ********************************************************/
/***** MESSAGEHANDLERS *************************************************/
/***** COMMANDHANDLERS *************************************************/
/***** FUNCTIONS *******************************************************/
/***********************************************************************
* @brief Attempts to place a damage over time effect on the specified
* target.
*
* @param obj_id target
* @param string type dot type (poison, bleeding, etc.)
* @param string dot_id a marker enabling a script to find a specific dot.
* No target may have two or more dots with the same dot_id.
* @param int attribute Attribute to apply dot
* @param int potency a modifier to the chance to resist. Potency -1 can't be resisted
* @param int strength the amount of damage inflicted per pulse
* @param int duration the time before the dot dissipates. -1 duration
* dots do not dissipate
* @param boolean verbose whether or not to give messaging
*
* @return boolean true on success. False on error or resist.
***********************************************************************/
boolean applyDotEffect(obj_id target, obj_id attacker, string type, string dot_id, int attribute, int potency, int strength, int duration, boolean verbose, string handler)
{
if(!isIdValid(attacker))
{
attacker = getSelf();
if(!isIdValid(attacker))
{
return false;
}
}
else
{
if (!isMob(target))
return false;
}
if (type == null)
return false;
if (dot_id == null)
return false;
if (attribute < 0 || attribute > 8)
return false;
if (potency != -1 && potency < 1)
return false;
if (strength < 1)
return false;
if (duration < 1)
return false;
if (!canApplyDotType(target, type))
return false;
if(isIdValid(attacker) && isMob(attacker))
{
addHate(target, attacker, 0.0f);
addHate(attacker, target, 0.0f);
}
// Check for resistance. Potency of -1 cannot be resisted.
if (potency != - 1)
{
if (attemptDotResist(target, type, potency, true))
return false;
}
// Keep track of whether or not this dot is to stack on an existing one.
boolean stacking = false;
// Keep track of whether or not the player has already has a dot of this type.
boolean new_dot_type = false;
string[] dot_types = getAllDotsType(target, type);
if (dot_types == null)
new_dot_type = true;
// Check for a dot of the same id. A target can only have one dot of the same id
if (hasDotId(target, dot_id))
{
// The current dot is replaced if the old dot is of lesser strength.
int old_strength = getDotStrength(target, dot_id);
if (old_strength >= strength)
return false;
else
stacking = true;
}
float expertiseDotIncrease = getEnhancedSkillStatisticModifierUncapped(attacker, "expertise_dot_increase");
if(expertiseDotIncrease > 0.0f)
{
// int strold = strength;
strength += (int)((float)strength * (expertiseDotIncrease / 100.0f));
// debugSpeakMsg(attacker, "Eat hot dot increase: " + (strength - strold) + " strength: " + strength + " strold: " + strold);
}
// Duration is modified by dissipation skill mods.
int dissipation_mod;
if (type.equals(DOT_BLEEDING))
dissipation_mod = getEnhancedSkillStatisticModifier(target, "dissipation_bleeding");
else if (type.equals(DOT_POISON))
dissipation_mod = getEnhancedSkillStatisticModifier(target, "dissipation_poison");
else if (type.equals(DOT_DISEASE))
dissipation_mod = getEnhancedSkillStatisticModifier(target, "dissipation_disease");
else if (type.equals(DOT_FIRE))
dissipation_mod = getEnhancedSkillStatisticModifier(target, "dissipation_fire");
else if (type.equals(DOT_ACID))
dissipation_mod = getEnhancedSkillStatisticModifier(target, "dissipation_acid");
else if (type.equals(DOT_ENERGY))
dissipation_mod = getEnhancedSkillStatisticModifier(target, "dissipation_energy");
else
return false;
if (dissipation_mod >0)
{
if (dissipation_mod > 90)
dissipation_mod = 90;
duration = (int)(duration * (1.0f - (dissipation_mod / 100.0f)));
if (duration < 1)
duration = 1;
}
////////////////////////////////////////////////////////////////////////
// Cap the amount of total DOT damage on a target to equal or below 1000
capDots(attacker, target, strength);
// End Cap
////////////////////////////////////////////////////////////////////////
// Set the objvars
utils.setScriptVar(target, VAR_DOT_ROOT + dot_id + VAR_TYPE, type);
utils.setScriptVar(target, VAR_DOT_ROOT + dot_id + VAR_ATTRIBUTE, attribute);
utils.setScriptVar(target, VAR_DOT_ROOT + dot_id + VAR_STRENGTH, strength);
utils.setScriptVar(target, VAR_DOT_ROOT + dot_id + VAR_DURATION, duration);
utils.setScriptVar(target, VAR_DOT_ROOT + dot_id + VAR_TIME_START, getGameTime());
if (handler != null)
utils.setScriptVar(target, VAR_DOT_ROOT + dot_id + VAR_HANDLER, handler);
// NOTE: Attacker not guaranteed to be valid or loaded. Currently only used to track damage for permissions and xp.
if (isIdValid(attacker))
utils.setScriptVar(target, VAR_DOT_ROOT + dot_id + VAR_ATTACKER, attacker);
// Send out the messageTo and system message
int pulse;
string_id old_effect_string;
string_id new_effect_string;
if (type.equals(DOT_BLEEDING))
{
new_effect_string = SID_BLEEDING;
old_effect_string = SID_BLEEDING_INCREASE;
pulse = BLEEDING_PULSE;
if (!buff.hasBuff(target, "bleeding"))
{
buff.applyBuff(target, attacker, "bleeding");
setState(target, STATE_BLEEDING, true);
playClientEffectObj(target, "appearance/pt_state_bleeding.prt", target, "spine3", null, "state_bleeding");
playClientEffectObj(target, "sound/sta_bleeding_on.snd", target, "");
}
}
else if (type.equals(DOT_POISON))
{
old_effect_string = SID_POISONED_INCREASE;
new_effect_string = SID_POISONED;
pulse = POISON_PULSE;
if (!buff.hasBuff(target, "poisoned"))
{
buff.applyBuff(target, attacker, "poisoned");
setState(target, STATE_POISONED, true);
playClientEffectObj(target, "appearance/pt_state_poisoned.prt", target, "", null, "state_poisoned");
playClientEffectObj(target, "sound/sta_poisoned_on.snd", target, "");
}
}
else if (type.equals(DOT_DISEASE))
{
old_effect_string = SID_DISEASED_INCREASE;
new_effect_string = SID_DISEASED;
pulse = DISEASE_PULSE;
if (!buff.hasBuff(target, "diseased"))
{
buff.applyBuff(target, attacker, "diseased");
setState(target, STATE_DISEASED, true);
playClientEffectObj(target, "appearance/pt_state_diseased.prt", target, "", null, "state_diseased");
playClientEffectObj(target, "sound/sta_diseased_on.snd", target, "");
}
}
else if (type.equals(DOT_FIRE))
{
// Cannot get fire dots while swimming
if (getState(target, STATE_SWIMMING) != 1)
{
pulse = FIRE_PULSE;
old_effect_string = SID_FIRE_INCREASE;
new_effect_string = SID_FIRE;
if (!buff.hasBuff(target, "onfire"))
{
new_dot_type = true;
buff.applyBuff(target, attacker, "onfire");
setState(target, STATE_ON_FIRE, true);
playClientEffectObj(target, "appearance/pt_state_onfire.prt", target, "", null, "state_onfire");
playClientEffectObj(target, "sound/sta_onfire_on.snd", target, "");
}
}
else
return false;
}
else if (type.equals(DOT_ACID))
{
old_effect_string = SID_ACID_INCREASE;
new_effect_string = SID_ACID;
pulse = ACID_PULSE;
if (!buff.hasBuff(target, "acid"))
{
buff.applyBuff(target, attacker, "acid");
// setState(target, STATE_DISEASED, true);
playClientEffectObj(target, "appearance/pt_state_acid.prt", target, "", null, "state_acid");
playClientEffectObj(target, "sound/wep_heavy_acid_launcher_hit.snd", target, "");
}
}
else if (type.equals(DOT_ENERGY))
{
old_effect_string = SID_ENERGY_INCREASE;
new_effect_string = SID_ENERGY;
pulse = ENERGY_PULSE;
if (!buff.hasBuff(target, "energy"))
{
buff.applyBuff(target, attacker, "energy");
// setState(target, STATE_DISEASED, true);
playClientEffectObj(target, "appearance/pt_state_energy.prt", target, "", null, "state_energy");
playClientEffectObj(target, "sound/item_electronics_break.snd", target, "");
}
}
else
return false;
// Getting hit with a new dot removes dot grace
if (utils.hasScriptVar(target, SCRIPT_VAR_DOT_GRACE))
utils.removeScriptVar(target, SCRIPT_VAR_DOT_GRACE);
// Attach the dot script
if (!hasScript(target, SCRIPT_PLAYER_DOT))
attachScript(target, SCRIPT_PLAYER_DOT);
if(type.equals(DOT_DISEASE))
{
_applyDiseaseDamage(target, dot_id);
}
// If the dot is stacking with an existing dot_id, no need to send another message.
if (!stacking)
{
dictionary d = new dictionary();
d.put("dot_id", dot_id);
d.put("pulse", pulse);
d.put("attacker", attacker);
messageTo(target, "OnDotPulse", d, pulse, false);
}
applyDotDamage(target, dot_id);
if (verbose)
{
if (new_dot_type)
combat.sendCombatSpamMessage(target, new_effect_string);
else
combat.sendCombatSpamMessage(target, old_effect_string);
}
return true;
}
boolean canApplyDotType(obj_id target, string type)
{
int niche = ai_lib.aiGetNiche(target);
if (!isIdValid(target))
return false;
if (vehicle.isVehicle(target))
return false;
prose_package pp = new prose_package();
if (niche == NICHE_DROID || niche == NICHE_ANDROID)
{
if (type.equals(DOT_POISON) || type.equals(DOT_DISEASE))
{
pp = prose.setStringId(pp, new string_id("spam", "unaffected"));
showFlyTextPrivateProseWithFlags(target, target, pp, 1.5f, colors.MEDIUMPURPLE, FLY_TEXT_FLAG_IS_DOT );
return false;
}
}
if (niche == NICHE_VEHICLE)
{
if (type.equals(DOT_POISON) || type.equals(DOT_DISEASE))
{
pp = prose.setStringId(pp, new string_id("spam", "unaffected"));
showFlyTextPrivateProseWithFlags(target, target, pp, 1.5f, colors.MEDIUMPURPLE, FLY_TEXT_FLAG_IS_DOT );
return false;
}
}
if (ai_lib.isTurret(target))
{
if (type.equals(DOT_POISON) || type.equals(DOT_DISEASE))
{
pp = prose.setStringId(pp, new string_id("spam", "unaffected"));
showFlyTextPrivateProseWithFlags(target, target, pp, 1.5f, colors.MEDIUMPURPLE, FLY_TEXT_FLAG_IS_DOT );
return false;
}
}
// Acid and Electrical DOT's affect all types.
if (checkForDotImmunity(target, type))
{
return false;
}
return true;
}//end canApplyDotType
/***********************************************************************
* @brief Overload for applyDotEffect
*
* @return boolean
***********************************************************************/
boolean applyDotEffect(obj_id target, string type, string dot_id, int strength, int duration)
{
return applyDotEffect(target, null, type, dot_id, HEALTH, 100, strength, duration, true, null);
}
/***********************************************************************
* @brief Overload for applyDotEffect
*
* @return boolean
***********************************************************************/
boolean applyDotEffect(obj_id target, string type, string dot_id, int attribute, int potency, int strength, int duration, boolean verbose)
{
return applyDotEffect(target, null, type, dot_id, attribute, potency, strength, duration, verbose, null);
}
/***********************************************************************
* @brief Overload for applyDotEffect
*
* @return boolean
***********************************************************************/
boolean applyDotEffect(obj_id target, string type, string dot_id, int attribute, int potency, int strength, int duration)
{
return applyDotEffect(target, null, type, dot_id, attribute, potency, strength, duration, true, null);
}
/***********************************************************************
* @brief Overload for applyDotEffect
*
* @return boolean
***********************************************************************/
boolean applyBleedingEffect(obj_id target, string dot_id, int attribute, int strength, int duration)
{
if(!isPlayer(target))
{
if((ai_lib.aiGetNiche(target)==NICHE_DROID)|| ai_lib.isAndroid(target)||(ai_lib.aiGetNiche(target)==NICHE_VEHICLE)||(vehicle.isDriveableVehicle(target)))
{
return false; // droid! or a vehicle
}
}
return applyDotEffect(target, null, DOT_BLEEDING, dot_id, attribute, 150, strength, duration, true, "bleedingStopped");
}
/***********************************************************************
* @brief Overload for applyDotEffect
*
* @return boolean
***********************************************************************/
boolean applyFireEffect(obj_id target, string dot_id, int strength, int duration)
{
return applyDotEffect(target, null, DOT_FIRE, dot_id, HEALTH, 150, strength, duration, true, "bleedingStopped");
}
/***********************************************************************
* @brief Overload for applyDotEffect
*
* @return boolean
***********************************************************************/
boolean applyDotEffect(obj_id target, obj_id attacker, string type, string dot_id, int attribute, int potency, int strength, int duration)
{
return applyDotEffect(target, attacker, type, dot_id, attribute, potency, strength, duration, true, null);
}
/***********************************************************************
* @brief Overload for applyDotEffect
*
* @return boolean
***********************************************************************/
boolean applyBleedingEffect(obj_id target, obj_id attacker, string dot_id, int attribute, int strength, int duration)
{
if(!isPlayer(target))
{
if((ai_lib.aiGetNiche(target)==NICHE_DROID) || ai_lib.isAndroid(target)||(ai_lib.aiGetNiche(target)==NICHE_VEHICLE)||(vehicle.isDriveableVehicle(target)))
{
return false; // droid! or a vehicle
}
}
return applyDotEffect(target, attacker, DOT_BLEEDING, dot_id, attribute, 150, strength, duration, true, "bleedingStopped");
}
/***********************************************************************
* @brief Overload for applyDotEffect
*
* @return boolean
***********************************************************************/
boolean applyFireEffect(obj_id target, obj_id attacker, string dot_id, int strength, int duration)
{
return applyDotEffect(target, attacker, DOT_FIRE, dot_id, HEALTH, 150, strength, duration, true, "bleedingStopped");
}
/***********************************************************************
* @brief removes a dot of the specified dot_id from the given target
*
* @param obj_id target
* @param string dot_id
* @param boolean verbose
*
* @return boolean true on resist false on error or not resisted
***********************************************************************/
boolean removeDotEffect(obj_id target, string dot_id, boolean verbose)
{
////LOG("LOG_CHANNEL", "dot::removeDotEffect -- " + dot_id);
if (!isIdValid(target))
{
//LOG("LOG_CHANNEL", "dot::removeDotEffect -- target is null");
return false;
}
if (dot_id == null)
{
//LOG("LOG_CHANNEL", "dot::removeDotEffect -- dot_id is null");
return false;
}
if (!hasDotId(target, dot_id))
return false;
else
{
string type = getDotType(target, dot_id);
// Get the message handle for dot removal.
string handler = getDotHandler(target, dot_id);
// Remove the dot objvar.
////LOG("LOG_CHANNEL", "dotname ->" + getDotObjVarName(dot_id));
utils.removeScriptVarTree(target, getDotScriptVarName(dot_id));
// Check to see if this is the last dot on the player.
string[] dots = getAllDots(target);
if (dots == null)
{
utils.removeScriptVarTree(target, VAR_DOT_ROOT);
int[] dotBuffs = buff.getAllBuffsByEffect(target, "dot");
if(dotBuffs == null && hasScript(target, SCRIPT_PLAYER_DOT))
detachScript(target, SCRIPT_PLAYER_DOT);
}
// Send a message to the target if we have a handler.
if (handler != null)
{
dictionary d = new dictionary();
messageTo(target, handler, d, 0, true);
}
// Check to see if there are any dots of the given type left. If not, send a message.
string[] dots_type = getAllDotsType(target, type);
if (dots_type == null)
{
if (type.equals(DOT_BLEEDING))
{
if (verbose)
combat.sendCombatSpamMessage(target, SID_BLEEDING_STOP);
setState(target, STATE_BLEEDING, false);
stopClientEffectObjByLabel(target, "state_bleeding");
playClientEffectObj(target, "sound/sta_bleeding_off.snd", target, "");
if (!isBleeding(target))
buff.removeBuff(target, "bleeding");
}
else if (type.equals(DOT_POISON))
{
if (verbose)
combat.sendCombatSpamMessage(target, SID_POISONED_STOP);
setState(target, STATE_POISONED, false);
stopClientEffectObjByLabel(target, "state_poisoned");
playClientEffectObj(target, "sound/sta_poisoned_off.snd", target, "");
if (!isPoisoned(target))
buff.removeBuff(target, "poisoned");
}
else if (type.equals(DOT_DISEASE))
{
if (verbose)
combat.sendCombatSpamMessage(target, SID_DISEASED_STOP);
setState(target, STATE_DISEASED, false);
stopClientEffectObjByLabel(target, "state_diseased");
playClientEffectObj(target, "sound/sta_diseased_off.snd", target, "");
if(hasAttribModifier(target, "dot.disease." + dot_id))
removeAttribOrSkillModModifier(target, "dot.disease." + dot_id);
if (!isDiseased(target))
buff.removeBuff(target, "diseased");
}
else if (type.equals(DOT_FIRE))
{
if (verbose)
combat.sendCombatSpamMessage(target, SID_FIRE_STOP);
setState(target, STATE_ON_FIRE, false);
stopClientEffectObjByLabel(target, "state_onfire");
playClientEffectObj(target, "sound/sta_onfire_off.snd", target, "");
if (!isOnFire(target))
buff.removeBuff(target, "onfire");
}
else if (type.equals(DOT_ACID))
{
if (verbose)
combat.sendCombatSpamMessage(target, SID_ACID_STOP);
// setState(target, STATE_ON_FIRE, false);
stopClientEffectObjByLabel(target, "state_acid");
// playClientEffectObj(target, "sound/sta_onfire_off.snd", target, "");
if (!isAcid(target))
buff.removeBuff(target, "acid");
}
else if (type.equals(DOT_ENERGY))
{
if (verbose)
combat.sendCombatSpamMessage(target, SID_ENERGY_STOP);
// setState(target, STATE_ON_FIRE, false);
stopClientEffectObjByLabel(target, "state_energy");
// playClientEffectObj(target, "sound/sta_onfire_off.snd", target, "");
if (!isEnergy(target))
buff.removeBuff(target, "energy");
}
}
else
{
if (verbose)
{
if (type.equals(DOT_BLEEDING))
combat.sendCombatSpamMessage(target, SID_BLEEDING_DECREASE);
else if (type.equals(DOT_POISON))
combat.sendCombatSpamMessage(target, SID_POISONED_DECREASE);
else if (type.equals(DOT_DISEASE))
combat.sendCombatSpamMessage(target, SID_DISEASED_DECREASE);
else if (type.equals(DOT_FIRE))
combat.sendCombatSpamMessage(target, SID_FIRE_DECREASE);
else if (type.equals(DOT_ACID))
combat.sendCombatSpamMessage(target, SID_ACID_DECREASE);
else if (type.equals(DOT_ENERGY))
combat.sendCombatSpamMessage(target, SID_ENERGY_DECREASE);
}
}
return true;
}
}
/***********************************************************************
* @brief Overload for removeDotEffect
*
* @param obj_id target
* @param string dot_id
*
* @return boolean true on resist false on error or not resisted
***********************************************************************/
boolean removeDotEffect(obj_id target, string dot_id)
{
return removeDotEffect(target, dot_id, true);
}
/***********************************************************************
* @brief Removes all dots from the specified target.
*
* @param obj_id target
* @param string dot_id
*
* @return boolean true on resist false on error or not resisted
***********************************************************************/
boolean removeAllDots(obj_id target)
{
////LOG("LOG_CHANNEL", "dot::removeAllDots");
if (!isIdValid(target))
{
//LOG("LOG_CHANNEL", "dot::removeAllDots -- target is null");
return false;
}
string[] dots = getAllDots(target);
if (dots != null)
{
for (int i = 0; i < dots.length; i++)
removeDotEffect(target, dots[i], false);
}
return true;
}
/***********************************************************************
* @brief Removes all dots from the specified target, of a specified type.
*
* @param obj_id target
* @param string dot_id
*
* @return boolean true on resist false on error or not resisted
***********************************************************************/
boolean removeDotsOfType(obj_id target, string type)
{
if (!isIdValid(target))
{
return false;
}
string[] dots = getAllDotsType(target, type);
if (dots != null)
{
for (int i = 0; i < dots.length; i++)
{
removeDotEffect(target, dots[i], false);
}
return true;
}
return false;
}
boolean _applyDiseaseDamage(obj_id target, string dot_id)
{
int strength = utils.getIntScriptVar(target, VAR_DOT_ROOT + dot_id + VAR_STRENGTH);
int absorption_mod = getEnhancedSkillStatisticModifier(target, "absorption_disease");
if (absorption_mod > 0)
{
if (absorption_mod > 90)
absorption_mod = 90;
strength = (int)(strength * (1.0f - (absorption_mod / 100.0f)));
}
float duration = (float)utils.getIntScriptVar(target, VAR_DOT_ROOT + dot_id + VAR_DURATION);
float up = duration * 0.75f;
float down = duration * 0.25f;
if(addAttribModifier(target, "dot.disease." + dot_id, ACTION, (-1 * strength), duration, up, down, false, true, false))
{
displayDiseaseEffect(getLocation(target));
obj_id attacker = dot.getDotAttacker(target, dot_id);
if (isIdValid(attacker) && exists(attacker))
{
xp.updateCombatXpList(target, attacker, xp.PERMISSIONS_ONLY, strength);
if(!isPlayer(target))
{
addHate(target, attacker, strength);
addHate(attacker, target, 0.0f);
}
}
else
{
xp.updateCombatXpList(target, target, xp.PERMISSIONS_ONLY, strength);
}
}
else
return false;
return true;
}
/***********************************************************************
* @brief applies the damage of the specifed dot
*
* @param obj_id target
* @param string dot_id
*
* @return boolean false on error or duration over
***********************************************************************/
boolean applyDotDamage(obj_id target, string dot_id)
{
if (!isIdValid(target))
return false;
if (dot_id == null)
return false;
if (!hasDotId(target, dot_id))
return false;
string type = dot.getDotType(target, dot_id);
if (type == null)
return false;
int strength = dot.getDotStrength(target, dot_id);
int duration = dot.getDotDuration(target, dot_id);
string dotScriptVar = getDotScriptVarName(dot_id);
// No damage is dealt when the player is under grace period, incapped, or dead
if (!utils.hasScriptVar(target, SCRIPT_VAR_DOT_GRACE))
{
if (isDead(target) || isIncapacitated(target))
return true;
}
else
return true;
// Absorption skill mods on the target reduce the effective strength of the dot during damage pulses.
int absorption_mod = 0;
int vulnerability_mod = (int)getEnhancedSkillStatisticModifierUncapped(target, "dot_vulnerability_all");
dictionary protDic = armor.getCombatArmorSpecialProtections(target);
float resistance = 0.0f;
if(isPlayer(target))
{
resistance = (float)armor.getCombatArmorGeneralProtection(target);
}
if(type.equals(DOT_BLEEDING))
{
absorption_mod += getEnhancedSkillStatisticModifier(target, "absorption_bleeding");
vulnerability_mod += getEnhancedSkillStatisticModifierUncapped(target, "dot_vulnerability_bleed");
if(isPlayer(target))
{
resistance += protDic.getFloat("cold");
}
else
{
// resistance += combat.getNpcArmorProtection(target, DAMAGE_ELEMENTAL_COLD);
resistance += (float)utils.getIntScriptVar(target, armor.SCRIPTVAR_CACHED_GENERAL_PROTECTION);
}
//nerfing skill mod resistances
absorption_mod /= MOD_DIVISOR;
//We don't nerf expertise dot absorption.
absorption_mod += (int)getSkillStatisticModifier(target, "expertise_dot_absorption_all");
absorption_mod += (int)(combat.convertProtectionToPercent(resistance) * DOT_ARMOR_MITIGATION_PERCENT);
}
else if(type.equals(DOT_POISON))
{
absorption_mod += getEnhancedSkillStatisticModifier(target, "absorption_poison");
vulnerability_mod += getEnhancedSkillStatisticModifierUncapped(target, "dot_vulnerability_poison");
if(isPlayer(target))
{
resistance += protDic.getFloat("acid");
}
else
{
// resistance += combat.getNpcArmorProtection(target, DAMAGE_ELEMENTAL_ACID);
resistance += (float)utils.getIntScriptVar(target, armor.SCRIPTVAR_CACHED_GENERAL_PROTECTION);
}
//nerfing skill mod resistances
absorption_mod /= MOD_DIVISOR;
//We don't nerf expertise dot absorption.
absorption_mod += (int)getSkillStatisticModifier(target, "expertise_dot_absorption_all");
absorption_mod += (int)(combat.convertProtectionToPercent(resistance) * DOT_ARMOR_MITIGATION_PERCENT);
}
else if(type.equals(DOT_DISEASE))
{
absorption_mod += getEnhancedSkillStatisticModifier(target, "absorption_disease");
vulnerability_mod += getEnhancedSkillStatisticModifierUncapped(target, "dot_vulnerability_disease");
if(isPlayer(target))
{
resistance += protDic.getFloat("cold");
}
else
{
// resistance += combat.getNpcArmorProtection(target, DAMAGE_ELEMENTAL_COLD);
resistance += (float)utils.getIntScriptVar(target, armor.SCRIPTVAR_CACHED_GENERAL_PROTECTION);
}
//nerfing skill mod resistances
absorption_mod /= MOD_DIVISOR;
//We don't nerf expertise dot absorption.
absorption_mod += (int)getSkillStatisticModifier(target, "expertise_dot_absorption_all");
absorption_mod += (int)(combat.convertProtectionToPercent(resistance) * DOT_ARMOR_MITIGATION_PERCENT);
}
else if(type.equals(DOT_FIRE))
{
absorption_mod += getEnhancedSkillStatisticModifier(target, "absorption_fire");
vulnerability_mod += getEnhancedSkillStatisticModifierUncapped(target, "dot_vulnerability_fire");
if(isPlayer(target))
{
resistance += protDic.getFloat("heat");
}
else
{
// resistance += combat.getNpcArmorProtection(target, DAMAGE_ELEMENTAL_HEAT);
resistance += (float)utils.getIntScriptVar(target, armor.SCRIPTVAR_CACHED_GENERAL_PROTECTION);
}
//nerfing skill mod resistances
absorption_mod /= MOD_DIVISOR;
//We don't nerf expertise dot absorption.
absorption_mod += (int)getSkillStatisticModifier(target, "expertise_dot_absorption_all");
absorption_mod += (int)(combat.convertProtectionToPercent(resistance) * DOT_ARMOR_MITIGATION_PERCENT);
}
else if(type.equals(DOT_ACID))
{
absorption_mod += getEnhancedSkillStatisticModifier(target, "absorption_acid");
vulnerability_mod += getEnhancedSkillStatisticModifierUncapped(target, "dot_vulnerability_acid");
if(isPlayer(target))
{
resistance += protDic.getFloat("acid");
}
else
{
// resistance += combat.getNpcArmorProtection(target, DAMAGE_ELEMENTAL_ACID);
resistance += (float)utils.getIntScriptVar(target, armor.SCRIPTVAR_CACHED_GENERAL_PROTECTION);
}
//nerfing skill mod resistances
absorption_mod /= MOD_DIVISOR;
//We don't nerf expertise dot absorption.
absorption_mod += (int)getSkillStatisticModifier(target, "expertise_dot_absorption_all");
absorption_mod += (int)(combat.convertProtectionToPercent(resistance) * DOT_ARMOR_MITIGATION_PERCENT);
}
else if(type.equals(DOT_ENERGY))
{
absorption_mod += getEnhancedSkillStatisticModifier(target, "absorption_energy");
vulnerability_mod += getEnhancedSkillStatisticModifierUncapped(target, "dot_vulnerability_energy");
if(isPlayer(target))
{
resistance += protDic.getFloat("energy");
}
else
{
// resistance += combat.getNpcArmorProtection(target, DAMAGE_ELEMENTAL_ELECTRICAL);
resistance += (float)utils.getIntScriptVar(target, armor.SCRIPTVAR_CACHED_GENERAL_PROTECTION);
}
//nerfing skill mod resistances
absorption_mod /= MOD_DIVISOR;
//We don't nerf expertise dot absorption.
absorption_mod += (int)getSkillStatisticModifier(target, "expertise_dot_absorption_all");
absorption_mod += (int)(combat.convertProtectionToPercent(resistance) * DOT_ARMOR_MITIGATION_PERCENT);
}
else
return false;
// absorption reduces the strength of a dot by the given %.
int damageAbsorbed = 0;
if (absorption_mod > 0)
{
if (absorption_mod > 50)
absorption_mod = 50;
damageAbsorbed = (int)(strength * (absorption_mod / 100.0f));
strength = (int)(strength * (1.0f - (absorption_mod / 100.0f)));
}
if (vulnerability_mod > 0)
{
strength = (int)(strength * (1.0f + (vulnerability_mod / 100.0f)));
}
// Bring over the generic damage multiply/divisor from combat base to apply to dot damage.
// Generic DoT's have no caster
int expertiseDamageBonus = getEnhancedSkillStatisticModifierUncapped(target, "combat_multiply_damage_taken");
float tempDamageFloat = (float)strength;
tempDamageFloat = tempDamageFloat * (1.0f + ((float)expertiseDamageBonus / 100.0f) );
int expertiseDamageReduction = getEnhancedSkillStatisticModifierUncapped(target, "combat_divide_damage_taken");
expertiseDamageReduction = expertiseDamageReduction > 100 ? 100 : expertiseDamageReduction;
tempDamageFloat = tempDamageFloat * (1.0f - ((float)expertiseDamageReduction / 100.0f));
strength = (int)tempDamageFloat;
// Dots don't incap. Reduce strength to one less than the current attribute if necessary.
int current_attrib = getAttrib(target, HEALTH);
//Disease dots are a primary action debuff and they also damage action at a rate of 33% of the potency.
if (type.equals(DOT_DISEASE))
{
current_attrib = getAttrib(target, ACTION);
strength = Math.round((float)strength / 3.0f);
}
/*
if (current_attrib <= strength)
strength = current_attrib - 1;
*/
obj_id attacker = dot.getDotAttacker(target, dot_id);
// If a player was hit by a dot at one point and was attackable, but now is not, the dot should be removed.
if( (attacker != target) && !pvpCanAttack(attacker, target))
{
removeDotEffect(target, dot_id);
return false;
}
// Per tick resist area, this gives you a chance to nulify that ticks damage
int damageResisted = 0;
if(attemptDotResist(target, type, 100, false))
{
int divisor = rand(2, 25);
int oldStrength = strength;
strength /= divisor;
damageResisted = oldStrength - strength;
}
string mitigationString = "("+damageAbsorbed + getString(new string_id("dot_message", "generic_absorbed"))+damageResisted+getString(new string_id("dot_message", "generic_resisted"))+")";
if(strength > 0)
{
hit_result hit = new hit_result();
hit.damage = strength;
hit.success = true;
string_id strSpam = new string_id("combat_effects", "damage_fly");
prose_package ppFly = new prose_package();
ppFly = prose.setStringId(ppFly, strSpam);
ppFly = prose.setDI(ppFly, -strength);
prose_package ppSpam = new prose_package();
if(type.equals(dot.DOT_BLEEDING))
{
// Track damage for xp calcs
if (isIdValid(attacker) && !isDead(attacker))
{
ppSpam = prose.setStringId(ppSpam, SID_BLEED_DMG_ATKR);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setTO(ppSpam, attacker);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(attacker, target, ppSpam, true, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target,attacker,ppFly, 1f, colors.INDIANRED, FLY_TEXT_FLAG_IS_DOT);
}
else
{
ppSpam = prose.setStringId(ppSpam, SID_BLEED_DMG);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(target, target, ppSpam, false, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target,target,ppFly, 1f, colors.INDIANRED, FLY_TEXT_FLAG_IS_DOT);
}
}
else if(type.equals(dot.DOT_POISON))
{
if (isIdValid(attacker) && !isDead(attacker))
{
ppSpam = prose.setStringId(ppSpam, SID_POISON_DMG_ATKR);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setTO(ppSpam, attacker);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(attacker, target, ppSpam, true, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target,attacker,ppFly, 1f, colors.YELLOWGREEN, FLY_TEXT_FLAG_IS_DOT);
}
else
{
ppSpam = prose.setStringId(ppSpam, SID_POISON_DMG);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(target, target, ppSpam, false, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target,target,ppFly, 1f, colors.YELLOWGREEN, FLY_TEXT_FLAG_IS_DOT);
}
}
else if (type.equals(dot.DOT_DISEASE))
{
if (isIdValid(attacker) && !isDead(attacker))
{
ppSpam = prose.setStringId(ppSpam, SID_DISEASE_DMG_ATKR);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setTO(ppSpam, attacker);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(attacker, target, ppSpam, true, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target,attacker,ppFly, 1f, colors.LIMEGREEN, FLY_TEXT_FLAG_IS_DOT);
}
else
{
ppSpam = prose.setStringId(ppSpam, SID_DISEASE_DMG);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(target, target, ppSpam, false, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target,target,ppFly, 1f, colors.LIMEGREEN, FLY_TEXT_FLAG_IS_DOT);
}
}
else if (type.equals(dot.DOT_FIRE))
{
if (isIdValid(attacker) && !isDead(attacker))
{
ppSpam = prose.setStringId(ppSpam, SID_FIRE_DMG_ATKR);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setTO(ppSpam, attacker);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(attacker, target, ppSpam, true, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target, attacker, ppFly, 1f, colors.FIREBRICK, FLY_TEXT_FLAG_IS_DOT);
}
else
{
ppSpam = prose.setStringId(ppSpam, SID_FIRE_DMG);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(target, target, ppSpam, false, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target, target, ppFly, 1f, colors.FIREBRICK, FLY_TEXT_FLAG_IS_DOT);
}
}
else if (type.equals(dot.DOT_ACID))
{
if (isIdValid(attacker) && !isDead(attacker))
{
ppSpam = prose.setStringId(ppSpam, SID_ACID_DMG_ATKR);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setTO(ppSpam, attacker);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(attacker, target, ppSpam, true, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target, attacker, ppFly, 1f, colors.OLIVEDRAB, FLY_TEXT_FLAG_IS_DOT);
}
else
{
ppSpam = prose.setStringId(ppSpam, SID_ACID_DMG);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(target, target, ppSpam, false, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target, target, ppFly, 1f, colors.OLIVEDRAB, FLY_TEXT_FLAG_IS_DOT);
}
}
else if (type.equals(dot.DOT_ENERGY))
{
if (isIdValid(attacker) && !isDead(attacker))
{
ppSpam = prose.setStringId(ppSpam, SID_ENERGY_DMG_ATKR);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setTO(ppSpam, attacker);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(attacker, target, ppSpam, true, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target, attacker, ppFly, 1f, colors.DEEPSKYBLUE, FLY_TEXT_FLAG_IS_DOT);
}
else
{
ppSpam = prose.setStringId(ppSpam, SID_ENERGY_DMG);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(target, target, ppSpam, false, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target, target, ppFly, 1f, colors.DEEPSKYBLUE, FLY_TEXT_FLAG_IS_DOT);
}
}
else
{
return false;
}
if (!type.equals(DOT_DISEASE))
{
doDamage(attacker, target, hit);
}
else
drainAttributes(target, strength, 0);
if(isIdValid(attacker) && isIdValid(target) && exists(attacker) && exists(target))
{
startCombat(attacker, target);
startCombat(target, attacker);
}
// Track damage for xp calcs
if(isIdValid(attacker) && !isDead(attacker))
{
//try to assign xp based on weapon used
obj_id myWeapon = getCurrentWeapon(attacker);
if(isIdValid(myWeapon))
xp.updateCombatXpList(target, attacker, myWeapon, strength);
else
//since the type no longer matters, we will give rifle. If we gave general we wouldnt be giving full credit.
xp.updateCombatXpList(target, attacker, xp.COMBAT_RANGEDSPECIALIZE_RIFLE, strength);
}
else
{
xp.updateCombatXpList(target, target, xp.PERMISSIONS_ONLY, strength);
}
if(!isPlayer(target))
{
if(isIdValid(attacker) && exists(attacker))
{
addHate(target, attacker, strength);
addHate(attacker, target, 0.0f);
}
}
}
int pulse = getDotPulse(target, dot_id);
// Reduce the duration. Remove the duration if it's over.
duration = duration - pulse;
if (duration < 1)
{
removeDotEffect(target, dot_id);
return false;
}
else
{
// Need to check again in case the damage, itself, triggered a removal in another system.
if (hasDotId(target, dot_id))
utils.setScriptVar(target, dotScriptVar + VAR_DURATION, duration);
return true;
}
}
/***********************************************************************
* @brief applies bleeding, and other special dot effects caused by
* weapons.
*
* @param obj_id attacker
* @param obj_id defender
* @param hit_result results as passed by the combat system
* @param weapon_data weapon as passed by the combat system
* @param float bleeding_mult multiplier to the bleeding severity
*
* @return boolean false on error or no dot applied
***********************************************************************/
boolean applyCombatDots(obj_id attacker, obj_id defender, hit_result results, weapon_data weapon, float bleeding_mult)
{
////LOG("LOG_CHANNEL", "dot::applyCombatDots -- " + attacker + " " + defender);
if (!isIdValid(attacker))
{
////LOG("LOG_CHANNEL", "dot::applyCombatBleeding -- attacker is null");
return false;
}
if (!isIdValid(defender))
{
////LOG("LOG_CHANNEL", "dot::applyCombatBleeding -- defender is null");
return false;
}
if (results == null)
{
////LOG("LOG_CHANNEL", "dot::applyCombatBleeding -- results is null");
return false;
}
if (weapon == null)
{
//LOG("LOG_CHANNEL", "dot::applyCombatBleeding -- weapon is null");
return false;
}
// ***** calculate bleeding *****
int hit_location = results.hitLocation;
float damage = (float)results.damage;
float wound_rating = weapon.woundChance;
if (damage < 1)
return false;
// Get attacker's bleeding mods.
float attacker_mod = getEnhancedSkillStatisticModifier(attacker, "combat_bleeding_attack");
// Get defenders bleeding defense.
float defender_mod = getEnhancedSkillStatisticModifier(attacker, "combat_bleeding_defense");
// The chance to cause bleeding is a function of damage, weapon wound rating, attacker and defender
// skill mods.
float bleeding_base = damage * (1.0f + (attacker_mod - defender_mod) / 100.0f) / 50.0f; // Reduced bleeding base by a factor of 50 [DW]
float bleeding_chance = bleeding_base + wound_rating;
////LOG("LOG_CHANNEL", "bleeding_base ->" + bleeding_base + " bleeding_chance ->" + bleeding_chance);
boolean dot_applied = false;
// Check for bleeding
if (rand(1,10000) <= bleeding_chance) // decreased chance of bleeding by a factor of 100 [DW]
{
// Apply bleeding effect.
float strength = bleeding_base / 30; // Reduced bleeding strength by a factor of 10 [DW]
float duration = rand(120, 300) * (1.0f + (attacker_mod - defender_mod) / 100.0f);
string hit_location_str = "combat_bleeding"; //HIT_LOCATIONS[hit_location]; // Removed bleeding per hit location
int attribute = HIT_LOCATION_ATTRIBUTE[hit_location];
//LOG("LOG_CHANNEL", "strength ->" + strength + " duration ->" + duration + " attribute ->" + attribute);
if (strength > 0)
applyBleedingEffect(defender, attacker, hit_location_str, attribute, (int)strength, (int)duration);
dot_applied = true;
}
// ***** apply special weapon dot effects *****
obj_id weapon_id = weapon.id;
if (combat.hasCertification(attacker, weapon_id))
{
if (utils.hasScriptVarTree(weapon_id, VAR_DOT))
{
string[] weapon_dots = getAllDots(weapon_id);
if (weapon_dots != null)
{
for (int i = 0; i < weapon_dots.length; i++)
{
string type = getDotType(weapon_id, weapon_dots[i]);
int attribute = getDotAttribute(weapon_id, weapon_dots[i]);
int potency = getDotPotency(weapon_id, weapon_dots[i]);
int strength = getDotStrength(weapon_id, weapon_dots[i]);
int duration = getDotDuration(weapon_id, weapon_dots[i]);
if (canApplyDotType(defender, type))
{
applyDotEffect(defender, attacker, type, weapon_dots[i], attribute, potency, strength, duration, true, null);
decrementDotUses(weapon_id, weapon_dots[i]);
dot_applied = true;
}
}
}
}
}
return dot_applied;
}
/***********************************************************************
* @brief changes the strength of a specific dot effect
*
* @param obj_id target
* @param string dot_id
* @param int strength change in current strength
* @param boolean verbose
*
* @return boolean true on success false on error or not resisted
***********************************************************************/
boolean modifyDotEffectStrength(obj_id target, string dot_id, int strength, boolean verbose)
{
if (!isIdValid(target))
{
//LOG("LOG_CHANNEL", "dot::modifyDotEffectStrength -- target is null");
return false;
}
if (dot_id == null)
{
//LOG("LOG_CHANNEL", "dot::modifyDotEffectStrength -- dot_id is null");
return false;
}
if (!hasDotId(target, dot_id))
return false;
int current_strength = getDotStrength(target, dot_id);
string type = getDotType(target, dot_id);
if (current_strength == -1)
{
//LOG("LOG_CHANNEL", "dot::modifyDotEffectStrength -- error in trying to read strength for " + dot_id);
return false;
}
current_strength = current_strength + strength;
if (current_strength < 1)
removeDotEffect(target, dot_id, verbose);
else
{
utils.setScriptVar(target, getDotScriptVarName(dot_id) + VAR_STRENGTH, current_strength);
if (verbose)
{
if (type.equals(DOT_BLEEDING))
combat.sendCombatSpamMessage(target, SID_BLEEDING_DECREASE);
else if (type.equals(DOT_POISON))
combat.sendCombatSpamMessage(target, SID_POISONED_DECREASE);
else if (type.equals(DOT_DISEASE))
combat.sendCombatSpamMessage(target, SID_DISEASED_DECREASE);
else if (type.equals(DOT_FIRE))
combat.sendCombatSpamMessage(target, SID_FIRE_DECREASE);
else if (type.equals(DOT_ACID))
combat.sendCombatSpamMessage(target, SID_FIRE_DECREASE);
else if (type.equals(DOT_ENERGY))
combat.sendCombatSpamMessage(target, SID_FIRE_DECREASE);
}
}
return true;
}
/***********************************************************************
* @brief gets all dots of the specifed type on a target and reduces total strength
* by the specified amount. If there is more reduction than
* strength in a given dot, the dot is removed and the next one
* in the list is affected.
*
* @param obj_id target
* @param string dot_id
* @param int strength change in current strength
*
* @return int the total strength reduced. -1 on fail.
***********************************************************************/
int reduceDotTypeStrength(obj_id target, string type, int strength)
{
if (!isIdValid(target))
{
//LOG("LOG_CHANNEL", "dot::reduceDotTypeStrength -- target is null");
return -1;
}
if(!isMob(target))
{
return -1;
}
if (type == null)
{
//LOG("LOG_CHANNEL", "dot::reduceDotTypeStrength -- dot_id is null");
return -1;
}
if (strength < 1)
{
//LOG("LOG_CHANNEL", "dot::reduceDotTypeStrength -- strength value " + strength + " is illegal.");
return -1;
}
string[] dots = getAllDotsType(target, type);
if (dots == null)
return -1;
// Loop through all dots of the specified type reducing their strength until the total
// is reached.
int remaining_strength = strength;
for (int i = 0; i < dots.length; i++)
{
int dot_strength = getDotStrength(target, dots[i]);
if (dot_strength <= remaining_strength)
{
remaining_strength = remaining_strength - dot_strength;
// If the dot's strength is reduced to zero, remove it.
if (remaining_strength < 1 || i == dots.length - 1)
removeDotEffect(target, dots[i], true);
else
removeDotEffect(target, dots[i], false);
}
else
{
dot_strength = dot_strength - remaining_strength;
modifyDotEffectStrength(target, dots[i], -remaining_strength, true);
remaining_strength = 0;
break;
}
}
return strength - remaining_strength;
}
/***********************************************************************
* @brief checks to see whether or not the given dot is resisted on application of the DoT
*
* @param obj_id target
* @param string type
* @param int potency
*
* @return boolean true on resist false on error or not resisted
***********************************************************************/
boolean attemptDotResist(obj_id target, string type, int potency, boolean showResistFlytext)
{
if (!isIdValid(target))
{
//LOG("LOG_CHANNEL", "dot::attemptDotResist -- target is null");
return false;
}
if (type == null)
{
//LOG("LOG_CHANNEL", "dot::attemptDotResist -- type is null");
return false;
}
// Incapacitated and dead targets always resist dots.
if (isIncapacitated(target) || isDead(target))
return true;
if (potency < 0)
{
if (potency == -1)
{
// Potency of -1 can't be resisted.
return false;
}
else
{
//LOG("LOG_CHANNEL", "dot::attemptDotResist -- potency value of " + potency + " is illegal.");
return false;
}
}
int resistance_mod = 0;
if(type.equals(DOT_BLEEDING))
{
resistance_mod = getEnhancedSkillStatisticModifier(target, "resistance_bleeding");
}
else if(type.equals(DOT_POISON))
{
resistance_mod = getEnhancedSkillStatisticModifier(target, "resistance_poison");
}
else if(type.equals(DOT_DISEASE))
{
resistance_mod = getEnhancedSkillStatisticModifier(target, "resistance_disease");
}
else if(type.equals(DOT_FIRE))
{
resistance_mod = getEnhancedSkillStatisticModifier(target, "resistance_fire");
}
else if(type.equals(DOT_ACID))
{
resistance_mod = getEnhancedSkillStatisticModifier(target, "resistance_acid");
}
else if(type.equals(DOT_ENERGY))
{
resistance_mod = getEnhancedSkillStatisticModifier(target, "resistance_energy");
}
else if(type.equals(DOT_ELECTRICITY))
{
resistance_mod = getEnhancedSkillStatisticModifier(target, "resistance_eletricity");
}
else if(type.equals(DOT_COLD))
{
resistance_mod = getEnhancedSkillStatisticModifier(target, "resistance_cold");
}
else if(type.equals(DOT_KINETIC))
{
resistance_mod = getEnhancedSkillStatisticModifier(target, "resistance_kinetic");
}
else
{
//LOG("LOG_CHANNEL", "dot::attemptDotResist -- dot type " + type + " not found.");
return false;
}
//sendSystemMessageTestingOnly(target, "resistance_mod = "+resistance_mod);
// The resistance check formula is a scaled linear resistance based on a comparison of the
// resisance value to the potency value. This formula causes the base resist rate to go up
// as the resistance increases as well as decreasing the effectiveness of each point of potency.
//with Reverse engineering players were resisting up to around 72% of the dots
//we needed to nerf this down
resistance_mod /= MOD_DIVISOR;
float resist_scale = (0.4f / ((100f + resistance_mod) / 200f)); // Scale of the resistance curve based on resist value
float to_hit_chance = potency * resist_scale; // hit chance based on potency vs resist_mod
// Cap reistance values to 5% & 95%
if (to_hit_chance < 5) to_hit_chance = 5;
if (to_hit_chance > 95) to_hit_chance = 95;
if ((int)rand(1, 100) < to_hit_chance)
{
////LOG("LOG_CHANNEL", "dot not resisted.");
return false;
}
else
{
if(showResistFlytext)
{
combat.sendCombatSpamMessage(target, SID_DOT_RESISTED_SPAM);
prose_package pp = new prose_package();
pp = prose.setStringId(pp, new string_id("spam", "unaffected"));
showFlyTextPrivateProseWithFlags(target, target, pp, 1.5f, colors.MEDIUMPURPLE, FLY_TEXT_FLAG_IS_DOT );
}
return true;
}
}
/***********************************************************************
* @brief checks to see whether or not the target has the specified
* dot_id
*
* @param obj_id target
* @param string dot_id
*
* @return boolean
***********************************************************************/
boolean hasDotId(obj_id target, string dot_id)
{
if (!isIdValid(target))
{
//LOG("LOG_CHANNEL", "dot::hasDotId -- target is null");
return false;
}
if (dot_id == null)
{
//LOG("LOG_CHANNEL", "dot::hasDotId -- dot_id is null");
return false;
}
string scriptvar_name = getDotScriptVarName(dot_id);
if (utils.hasScriptVarTree(target, scriptvar_name))
return true;
else
return false;
}
/***********************************************************************
* @brief returns the scriptvar name given the dot_id
*
* @param string dot_id
*
* @return string
***********************************************************************/
string getDotScriptVarName(string dot_id)
{
return VAR_DOT_ROOT + dot_id;
}
/***********************************************************************
* @brief returns all dot_ids on a target
*
* @param obj_id target
* @param string type
*
* @return string[] null on error or none exists
***********************************************************************/
string[] getAllDots(obj_id target)
{
if (!isIdValid(target))
{
//LOG("LOG_CHANNEL", "dot::getAllDots -- target is null");
return null;
}
// Define a HashSet to store the dot names (so that we don't have duplicates)
HashSet dots_found = new HashSet();
// Go through all the script var keys and extract dot_id values
deltadictionary dd = target.getScriptVars();
Enumeration keys = dd.keys();
while ( keys.hasMoreElements() )
{
string key = (string)(keys.nextElement());
if ( key.startsWith(VAR_DOT_ROOT) )
{
int dotIndex = key.indexOf(".");
if (dotIndex > -1)
{
// Remove the VAR_DOT_ROOT from the beginning of the key
String dotItem = key.substring(dotIndex + 1);
// Find the next "." so that we can extract the dot_id
dotIndex = dotItem.indexOf(".");
if (dotIndex > -1)
{
// Strip off everything after the dot_id value
String dotId = dotItem.substring(0, dotIndex);
dots_found.add(dotId);
}
}
}
}
if (dots_found.size() < 1)
return null;
else
{
// Return the list as a string[]
String[] dot_string = new String[dots_found.size()];
dots_found.toArray(dot_string);
return dot_string;
}
}
/***********************************************************************
* @brief returns all dot_ids on a target of the specified type
*
* @param obj_id target
* @param string type
*
* @return string[] null on error or none exists
***********************************************************************/
string[] getAllDotsType(obj_id target, string type)
{
if (!isIdValid(target))
{
//LOG("LOG_CHANNEL", "dot::getAllDotsType -- target is null");
return null;
}
if (type == null)
{
//LOG("LOG_CHANNEL", "dot::getAllDotsType -- type is null");
return null;
}
Vector dots_found = new Vector();
// Iterate through the dot objvar list looking for dots of the specified type
string[] dots = getAllDots(target);
if (dots != null)
{
for (int i = 0; i < dots.length; ++i)
{
String scriptVarName = VAR_DOT_ROOT + dots[i] + VAR_TYPE;
String scriptVarValue = utils.getStringScriptVar(target, scriptVarName);
if ((scriptVarValue != null) && scriptVarValue.equals(type) )
{
dots_found.addElement(dots[i]);
}
}
}
if (dots_found.size() < 1)
return null;
else
{
String[] dot_string = new String[dots_found.size()];
dots_found.toArray(dot_string);
return dot_string;
}
}
string[] getAllDotsOwner(obj_id owner, obj_id target)
{
if(!isIdValid(target))
{
return null;
}
if(!isIdValid(target))
{
return null;
}
Vector dots_found = new Vector();
// Iterate through the dot objvar list looking for dots of the specified type
string[] dots = getAllDots(target);
if (dots != null)
{
for (int i = 0; i < dots.length; ++i)
{
obj_id who = getDotAttacker(target, dots[i]);
if(isIdValid(who) && owner == who)
{
dots_found.addElement(dots[i]);
}
}
}
if (dots_found.size() < 1)
return null;
else
{
String[] dot_string = new String[dots_found.size()];
dots_found.toArray(dot_string);
return dot_string;
}
}
void removeAllDotsOwner(obj_id owner, obj_id target)
{
string[] dots = getAllDotsOwner(owner, target);
if(dots == null || dots.length == 0)
return;
for(int i = 0; i < dots.length; i++)
{
removeDotEffect(target, dots[i], false);
}
}
/***********************************************************************
* @brief determines whether or not a target is bleeding
*
* @param obj_id target
*
* @return boolean
***********************************************************************/
boolean isBleeding(obj_id target)
{
if (!isIdValid(target))
{
//LOG("LOG_CHANNEL", "dot::isBleeding -- target is null");
return false;
}
string[] dots = getAllDotsType(target, DOT_BLEEDING);
if (dots != null)
return true;
else
return false;
}
/***********************************************************************
* @brief determines whether or not a target is poisoned
*
* @param obj_id target
*
* @return boolean
***********************************************************************/
boolean isPoisoned(obj_id target)
{
if (!isIdValid(target))
{
//LOG("LOG_CHANNEL", "dot::isPoisoned -- target is null");
return false;
}
string[] dots = getAllDotsType(target, DOT_POISON);
if (dots != null)
return true;
else
return false;
}
/***********************************************************************
* @brief determines whether or not a target is diseased
*
* @param obj_id target
*
* @return boolean
***********************************************************************/
boolean isDiseased(obj_id target)
{
if (!isIdValid(target))
{
//LOG("LOG_CHANNEL", "dot::isDiseased -- target is null");
return false;
}
string[] dots = getAllDotsType(target, DOT_DISEASE);
if (dots != null)
return true;
else
return false;
}
/***********************************************************************
* @brief determines whether or not a target is on fire
*
* @param obj_id target
*
* @return boolean
***********************************************************************/
boolean isOnFire(obj_id target)
{
if (!isIdValid(target))
{
//LOG("LOG_CHANNEL", "dot::isOnFire -- target is null");
return false;
}
string[] dots = getAllDotsType(target, DOT_FIRE);
if (dots != null)
return true;
else
return false;
}
/***********************************************************************
* @brief determines whether or not a target is acidic
*
* @param obj_id target
*
* @return boolean
***********************************************************************/
boolean isAcid(obj_id target)
{
if (!isIdValid(target))
{
return false;
}
string[] dots = getAllDotsType(target, DOT_ACID);
if (dots != null)
return true;
else
return false;
}
/***********************************************************************
* @brief determines whether or not a target is on electrified
*
* @param obj_id target
*
* @return boolean
***********************************************************************/
boolean isEnergy(obj_id target)
{
if (!isIdValid(target))
{
//LOG("LOG_CHANNEL", "dot::isOnFire -- target is null");
return false;
}
string[] dots = getAllDotsType(target, DOT_ENERGY);
if (dots != null)
return true;
else
return false;
}
/***********************************************************************
* @brief returns the dot type on a given target for a given
* dot_id
*
* @param obj_id target
* @param string dot_id
*
* @return string null on error or no dot of that id
***********************************************************************/
string getDotType(obj_id target, string dot_id)
{
if (!isIdValid(target))
{
//LOG("LOG_CHANNEL", "dot::getDotType -- target is null.");
return null;
}
if (dot_id == null)
{
//LOG("LOG_CHANNEL", "dot::getDotType -- dot_id is null.");
return null;
}
if (hasDotId(target, dot_id))
{
return utils.getStringScriptVar(target, getDotScriptVarName(dot_id) + VAR_TYPE);
}
else
return null;
}
/***********************************************************************
* @brief returns the dot attribute on a given target for a given
* dot_id
*
* @param obj_id target
* @param string dot_id
*
* @return int -1 on error or no dot of that id
***********************************************************************/
int getDotAttribute(obj_id target, string dot_id)
{
if (!isIdValid(target))
{
//LOG("LOG_CHANNEL", "dot::getDotAttribute -- target is null.");
return -1;
}
if (dot_id == null)
{
//LOG("LOG_CHANNEL", "dot::getDotAttribute -- dot_id is null.");
return -1;
}
if (hasDotId(target, dot_id))
{
return utils.getIntScriptVar(target, getDotScriptVarName(dot_id) + VAR_ATTRIBUTE);
}
else
return -1;
}
/***********************************************************************
* @brief returns the dot potency on a given source for a given
* dot_id. Works only on dot sources, not the target.
*
* @param obj_id source
* @param string dot_id
*
* @return int -1 on error or no dot of that id
***********************************************************************/
int getDotPotency(obj_id source, string dot_id)
{
if (!isIdValid(source))
{
//LOG("LOG_CHANNEL", "dot::getDotPotency -- source is null.");
return -1;
}
if (dot_id == null)
{
//LOG("LOG_CHANNEL", "dot::getDotPotency -- dot_id is null.");
return -1;
}
if (hasDotId(source, dot_id))
{
return utils.getIntScriptVar(source, getDotScriptVarName(dot_id) + VAR_POTENCY);
}
else
return -1;
}
/***********************************************************************
* @brief returns the dot strength on a given target for a given
* dot_id
*
* @param obj_id target
* @param string dot_id
*
* @return int -1 on error or no dot of that id
***********************************************************************/
int getDotStrength(obj_id target, string dot_id)
{
if (!isIdValid(target))
{
//LOG("LOG_CHANNEL", "dot::getDotStrength -- target is null.");
return -1;
}
if (dot_id == null)
{
//LOG("LOG_CHANNEL", "dot::getDotStrength -- dot_id is null.");
return -1;
}
if (hasDotId(target, dot_id))
{
return utils.getIntScriptVar(target, getDotScriptVarName(dot_id) + VAR_STRENGTH);
}
else
return -1;
}
/***********************************************************************
* @brief returns the dot duration on a given target for a given
* dot_id
*
* @param obj_id target
* @param string dot_id
*
* @return int -1 on error or no dot of that id
***********************************************************************/
int getDotDuration(obj_id target, string dot_id)
{
if (!isIdValid(target))
{
//LOG("LOG_CHANNEL", "dot::getDotDuration -- target is null.");
return -1;
}
if (dot_id == null)
{
//LOG("LOG_CHANNEL", "dot::getDotDuration -- dot_id is null.");
return -1;
}
if (hasDotId(target, dot_id))
{
return utils.getIntScriptVar(target, getDotScriptVarName(dot_id) + VAR_DURATION);
}
else
return -1;
}
/***********************************************************************
* @brief returns the dot starttime on a given target for a given
* dot_id
*
* @param obj_id target
* @param string dot_id
*
* @return int -1 on error or no dot of that id
***********************************************************************/
int getDotStartTime(obj_id target, string dot_id)
{
if (!isIdValid(target))
{
//LOG("LOG_CHANNEL", "dot::getDotStartTime -- target is null.");
return -1;
}
if (dot_id == null)
{
//LOG("LOG_CHANNEL", "dot::getDotStartTime -- dot_id is null.");
return -1;
}
if (hasDotId(target, dot_id))
{
return utils.getIntScriptVar(target, getDotScriptVarName(dot_id) + VAR_TIME_START);
}
else
return -1;
}
/***********************************************************************
* @brief returns the dot last pulse on a given target for a given
* dot_id
*
* @param obj_id target
* @param string dot_id
*
* @return int -1 on error or no dot of that id
***********************************************************************/
int getDotLastPulse(obj_id target, string dot_id)
{
if (!isIdValid(target))
{
//LOG("LOG_CHANNEL", "dot::getDotLastPulse -- target is null.");
return -1;
}
if (dot_id == null)
{
//LOG("LOG_CHANNEL", "dot::getDotLastPulse -- dot_id is null.");
return -1;
}
if (hasDotId(target, dot_id))
{
return utils.getIntScriptVar(target, getDotScriptVarName(dot_id) + VAR_LAST_PULSE);
}
else
return -1;
}
/***********************************************************************
* @brief returns the dot handler on a given target for a given
* dot_id
*
* @param obj_id target
* @param string dot_id
*
* @return string null on error or no dot of that id
***********************************************************************/
string getDotHandler(obj_id target, string dot_id)
{
if (!isIdValid(target))
{
//LOG("LOG_CHANNEL", "dot::getDotHandler -- target is null.");
return null;
}
if (dot_id == null)
{
//LOG("LOG_CHANNEL", "dot::getDotHandler -- dot_id is null.");
return null;
}
if (hasDotId(target, dot_id))
{
return utils.getStringScriptVar(target, getDotScriptVarName(dot_id) + VAR_HANDLER);
}
else
return null;
}
/***********************************************************************
* @brief returns the attacker on a given target for a given
* dot_id
*
* @param obj_id target
* @param string dot_id
*
* @return obj_id null on error or no dot of that id
***********************************************************************/
obj_id getDotAttacker(obj_id target, string dot_id)
{
if (!isIdValid(target))
{
//LOG("LOG_CHANNEL", "dot::getDotAttacker -- target is null.");
return null;
}
if (dot_id == null)
{
//LOG("LOG_CHANNEL", "dot::getDotAttacker -- dot_id is null.");
return null;
}
if (hasDotId(target, dot_id))
{
String scriptVarName = getDotScriptVarName(dot_id) + VAR_ATTACKER;
if (utils.hasScriptVar(target, scriptVarName))
return utils.getObjIdScriptVar(target, scriptVarName);
else
return null;
}
else
return null;
}
/***********************************************************************
* @brief returns the pulse time for given dot
*
* @param obj_id target
* @param string dot_id
*
* @return int -1 on error
***********************************************************************/
int getDotPulse(obj_id target, string dot_id)
{
if (!isIdValid(target))
{
//LOG("LOG_CHANNEL", "dot::getDotPulse -- target is null.");
return -1;
}
if (dot_id == null)
{
//LOG("LOG_CHANNEL", "dot::getDotPulse -- dot_id is null.");
return -1;
}
string type = getDotType(target, dot_id);
if (type == null)
{
//LOG("LOG_CHANNEL", "dot::getDotPulse -- dot type is null for " + target);
return -1;
}
if (type.equals(dot.DOT_BLEEDING))
return dot.BLEEDING_PULSE;
else if (type.equals(dot.DOT_POISON))
return dot.POISON_PULSE;
else if (type.equals(dot.DOT_DISEASE))
return dot.DISEASE_PULSE;
else if (type.equals(dot.DOT_FIRE))
return dot.FIRE_PULSE;
else if (type.equals(dot.DOT_ACID))
return dot.ACID_PULSE;
else if (type.equals(dot.DOT_ENERGY))
return dot.ENERGY_PULSE;
else
{
//LOG("LOG_CHANNEL", "dot::getDotPulse -- dot type " + type + " not found.");
return -1;
}
}
/***********************************************************************
* @brief returns the number of uses left on a dot source
*
* @param obj_id target
* @param string dot_id
*
* @return int -1 on error
***********************************************************************/
int getDotUses(obj_id source, string dot_id)
{
if (!isIdValid(source))
{
//LOG("LOG_CHANNEL", "dot::getDotUses -- source is null.");
return -1;
}
if (dot_id == null)
{
//LOG("LOG_CHANNEL", "dot::getDotUses -- dot_id is null.");
return -1;
}
if (hasDotId(source, dot_id))
{
return utils.getIntScriptVar(source, getDotScriptVarName(dot_id) + VAR_USES);
}
else
return -1;
}
/***********************************************************************
* @brief adds dot attack to am item
*
* @param obj_id item
* @param string type
* @param string dot_id
* @param int attribute
* @param int potency
* @param int strength
* @param int duration
*
* @return boolean
***********************************************************************/
boolean addDotAttackToItem(obj_id item, string type, string dot_id, int attribute, int potency, int strength, int duration, boolean stackable, int uses)
{
if (!isIdValid(item))
{
//LOG("LOG_CHANNEL", "dot::addDotAttackToWeapon -- item is null");
return false;
}
if (type == null)
{
//LOG("LOG_CHANNEL", "dot::addDotAttackToWeapon -- type is null");
return false;
}
if (dot_id == null)
{
//LOG("LOG_CHANNEL", "dot::addDotAttackToWeapon -- dot_id is null");
return false;
}
if (attribute < 0 || attribute > 8)
{
//LOG("LOG_CHANNEL", "dot::addDotAttackToWeapon -- attribute value of " + attribute + " is illegal.");
return false;
}
if (potency != -1 && potency < 1)
{
//LOG("LOG_CHANNEL", "dot::addDotAttackToWeapon -- potency value of " + potency + " is illegal.");
return false;
}
if (strength < 1)
{
//LOG("LOG_CHANNEL", "dot::addDotAttackToWeapon -- strength value of " + strength + " is illegal.");
return false;
}
if (duration < 1)
{
//LOG("LOG_CHANNEL", "dot::addDotAttackToWeapon -- duration value of " + duration + " is illegal.");
return false;
}
if (uses != -1 && uses < 1)
{
//LOG("LOG_CHANNEL", "dot::addDotAttackToWeapon -- uses value of " + uses + " is illegal.");
return false;
}
utils.setScriptVar(item, VAR_DOT_ROOT + dot_id + VAR_TYPE, type);
utils.setScriptVar(item, VAR_DOT_ROOT + dot_id + VAR_ATTRIBUTE, attribute);
utils.setScriptVar(item, VAR_DOT_ROOT + dot_id + VAR_POTENCY, potency);
utils.setScriptVar(item, VAR_DOT_ROOT + dot_id + VAR_STRENGTH, strength);
utils.setScriptVar(item, VAR_DOT_ROOT + dot_id + VAR_DURATION, duration);
utils.setScriptVar(item, VAR_DOT_ROOT + dot_id + VAR_USES, uses);
return true;
}
/***********************************************************************
* @brief reduces the number of dot uses on an item.
*
* @param obj_id item
* @param string dot_id
*
* @return boolean fail on error
***********************************************************************/
boolean decrementDotUses(obj_id item, string dot_id)
{
if (!isIdValid(item))
{
//LOG("LOG_CHANNEL", "dot::decrementDotUses -- item is null");
return false;
}
if (dot_id == null)
{
//LOG("LOG_CHANNEL", "dot::decrementDotUses -- dot_id is null");
return false;
}
if (!hasDotId(item, dot_id))
return false;
int uses = getDotUses(item, dot_id);
// Items with -1 uses don't run out.
if (uses != - 1)
{
uses = uses - 1;
if (uses < 1)
utils.removeScriptVarTree(item, getDotScriptVarName(dot_id));
else
utils.setScriptVar(item, VAR_DOT_ROOT + dot_id + VAR_USES, uses);
}
return true;
}
/***********************************************************************
* @brief displays the bleeding particle effect.
*
* @param location loc
*
* @return void
***********************************************************************/
void displayBleedingEffect(location loc)
{
if (loc == null)
{
//LOG("LOG_CHANNEL", "dot::displayBleedingEffect -- location is null");
return;
}
obj_id[] players = getAllPlayers(loc, VAR_EFFECT_DISPLAY_RADIUS);
if (players != null)
{
for (int i = 0; i < players.length; i++)
{
playClientEffectLoc(players[i], "clienteffect/dot_bleeding.cef" , loc, 0);
}
}
return;
}
/***********************************************************************
* @brief displays the poison particle effect.
*
* @param location loc
*
* @return void
***********************************************************************/
void displayPoisonEffect(location loc)
{
if (loc == null)
{
//LOG("LOG_CHANNEL", "dot::displayPoisonEffect -- location is null");
return;
}
obj_id[] players = getAllPlayers(loc, VAR_EFFECT_DISPLAY_RADIUS);
if (players != null)
{
for (int i = 0; i < players.length; i++)
{
playClientEffectLoc(players[i], "clienteffect/dot_poisoned.cef" , loc, 0);
}
}
return;
}
/***********************************************************************
* @brief displays the disease particle effect.
*
* @param location loc
*
* @return void
***********************************************************************/
void displayDiseaseEffect(location loc)
{
if (loc == null)
{
//LOG("LOG_CHANNEL", "dot::displayDiseaseEffect -- location is null");
return;
}
obj_id[] players = getAllPlayers(loc, VAR_EFFECT_DISPLAY_RADIUS);
if (players != null)
{
for (int i = 0; i < players.length; i++)
{
playClientEffectLoc(players[i], "clienteffect/dot_diseased.cef" , loc, 0);
}
}
return;
}
/***********************************************************************
* @brief displays the fire particle effect.
*
* @param location loc
*
* @return void
***********************************************************************/
void displayFireEffect(location loc)
{
if (loc == null)
{
//LOG("LOG_CHANNEL", "dot::displayDiseaseEffect -- location is null");
return;
}
obj_id[] players = getAllPlayers(loc, VAR_EFFECT_DISPLAY_RADIUS);
if (players != null)
{
for (int i = 0; i < players.length; i++)
{
playClientEffectLoc(players[i], "clienteffect/dot_fire.cef" , loc, 0);
}
}
return;
}
/***********************************************************************
* @brief displays the fire particle effect.
*
* @param location loc
*
* @return void
***********************************************************************/
void displayAcidEffect(location loc)
{
if (loc == null)
{
//LOG("LOG_CHANNEL", "dot::displayDiseaseEffect -- location is null");
return;
}
obj_id[] players = getAllPlayers(loc, VAR_EFFECT_DISPLAY_RADIUS);
if (players != null)
{
for (int i = 0; i < players.length; i++)
{
playClientEffectLoc(players[i], "clienteffect/dot_fire.cef" , loc, 0);
}
}
return;
}
/***********************************************************************
* @brief displays the fire particle effect.
*
* @param location loc
*
* @return void
***********************************************************************/
void displayEnergyEffect(location loc)
{
if (loc == null)
{
//LOG("LOG_CHANNEL", "dot::displayDiseaseEffect -- location is null");
return;
}
obj_id[] players = getAllPlayers(loc, VAR_EFFECT_DISPLAY_RADIUS);
if (players != null)
{
for (int i = 0; i < players.length; i++)
{
playClientEffectLoc(players[i], "clienteffect/dot_fire.cef" , loc, 0);
}
}
return;
}
/*******************************************************************
*@brief checks to see if an immunity local var exists of the
* same type as the dot attempting to be applied
*
*@param obj_id target, string type
*
*@return boolen (true if immunity exists, false if it does not)
********************************************************************/
boolean checkForDotImmunity(obj_id target, string type)
{
int resistVar = getEnhancedSkillStatisticModifierUncapped(target, "dot_resist_"+type);
int universal = getEnhancedSkillStatisticModifierUncapped(target, "dot_resist_all");
int elemental = getElementalGroupResist(target, type);
int natural = getNaturalGroupResist(target, type);
int applyCheck = rand(0, 99);
boolean wasResisted = false;
if (applyCheck < resistVar)
wasResisted = true;
if (applyCheck < universal)
wasResisted = true;
if (applyCheck < elemental)
wasResisted = true;
if (applyCheck < natural)
wasResisted = true;
//debugSpeakMsg(target, "type: "+type+" and resist list was "+applyCheck+" vs - "+resistVar+", "+universal+", "+elemental+", "+natural);
return wasResisted;
}
int getElementalGroupResist(obj_id target, string type)
{
if (!type.equals(DOT_FIRE) && !type.equals(DOT_ACID) && !type.equals(DOT_COLD)
&& !type.equals(DOT_ELECTRICITY) && !type.equals(DOT_ENERGY)
&& !type.equals(DOT_KINETIC))
{
return 0;
}
return getEnhancedSkillStatisticModifierUncapped(target, "dot_resist_elemental");
}
int getNaturalGroupResist(obj_id target, string type)
{
if (!type.equals(DOT_POISON) && !type.equals(DOT_DISEASE) && !type.equals(DOT_BLEEDING))
{
return 0;
}
return getEnhancedSkillStatisticModifierUncapped(target, "dot_resist_natural");
}
void capDots(obj_id attacker, obj_id target, int strength)
{
// If the target is not a player, don't cap the DOTs.
if(!isIdValid(target) || !isIdValid(attacker) || !isPlayer(target) || !isPlayer(attacker))
{
return;
}
// Don't cap dots if the attacker is not a player.
if (!isPlayer(attacker) && (isIdValid(getMaster(attacker)) && !isPlayer(getMaster(attacker))))
{
return;
}
string[] allDots = getAllDotsOwner(attacker, target);
if(allDots == null)
{
return;
}
// If the amount of DOTs on the target is greater than what should be possible, remove the oldest.
if(allDots.length >= DOT_MAXIMUM_COUNT)
{
int oldestDot = 0;
for(int i = 1; i < allDots.length; i++)
{
if(getDotStartTime(target, allDots[oldestDot]) > getDotStartTime(target, allDots[i]))
{
oldestDot = i;
}
}
removeDotEffect(target, allDots[oldestDot], true);
}
}
int getDotResistanceMod(string type, obj_id target)
{
int dotResistanceMod = 0;
if(isPlayer(target))
{
if(utils.hasScriptVar(target, "armor.armor_type_tally"))
{
int[] armorTypeTally = utils.getIntArrayScriptVar(target, "armor.armor_type_tally");
if(armorTypeTally.length != 3)
{
return dotResistanceMod;
}
if (type.equals(DOT_BLEEDING)) // Recon 0
{
dotResistanceMod = armorTypeTally[0] * armorTypeTally[0] * 2;
}
else if (type.equals(DOT_POISON)) // Battle 1
{
dotResistanceMod = armorTypeTally[1] * armorTypeTally[1] * 2;
}
else if (type.equals(DOT_DISEASE)) // Recon 0
{
dotResistanceMod = armorTypeTally[0] * armorTypeTally[0] * 2;
}
else if (type.equals(DOT_FIRE)) // Assault 2
{
dotResistanceMod = armorTypeTally[2] * armorTypeTally[2] * 2;
}
else if (type.equals(DOT_ACID)) // Acid Assault 2
{
dotResistanceMod = armorTypeTally[2] * armorTypeTally[2] * 2;
}
else if (type.equals(DOT_ENERGY)) // Energy Battle 1
{
dotResistanceMod = armorTypeTally[1] * armorTypeTally[1] * 2;
}
}
}
else if(beast_lib.isBeast(target))
{
float resilience = beast_lib.getBeastCustomMod(target, beast_lib.MOD_RESILIENCE);
float survival = beast_lib.getBeastCustomMod(target, beast_lib.MOD_SURVIVAL);
int beastResistMod = Math.round((resilience * resilience) + (survival * survival));
dotResistanceMod = beastResistMod;
}
if(dotResistanceMod > 100)
dotResistanceMod = 100;
return dotResistanceMod;
}
/*********************************************************** insert new hotness dot/buff stuff ****************************************************/
boolean applyBuffDotEffect(obj_id target, obj_id attacker, string type, string dot_id, long stack, int attribute, int potency, int strength, int duration, boolean verbose, string buffName)
{
if(!isIdValid(attacker))
{
attacker = getSelf();
if(!isIdValid(attacker))
{
return false;
}
}
else
{
if (!isMob(target))
return false;
}
if (type == null)
return false;
if (dot_id == null)
return false;
if (attribute < 0 || attribute > 8)
return false;
if (potency != -1 && potency < 1)
return false;
if (strength < 1)
return false;
if (duration < 1)
return false;
if (!canApplyDotType(target, type))
{
return false;
}
if(isIdValid(attacker) && isMob(attacker))
{
addHate(target, attacker, 0.0f);
addHate(attacker, target, 0.0f);
}
// Send out the messageTo and system message
string_id old_effect_string;
string_id new_effect_string;
if (type.equals(DOT_FIRE))
{
// Cannot get fire dots while swimming
if (getState(target, STATE_SWIMMING) != 1)
{
old_effect_string = SID_FIRE_INCREASE;
new_effect_string = SID_FIRE;
if(stack == 1)
playClientEffectObj(target, "appearance/pt_state_onfire.prt", target, "", null, "state_onfire");
playClientEffectObj(target, "sound/sta_onfire_on.snd", target, "");
}
else
{
buff.removeBuff(target, buffName);
return false;
}
}
else if (type.equals(DOT_ACID))
{
old_effect_string = SID_ACID_INCREASE;
new_effect_string = SID_ACID;
if(stack == 1)
playClientEffectObj(target, "appearance/pt_state_acid.prt", target, "", null, "state_acid");
playClientEffectObj(target, "sound/wep_heavy_acid_launcher_hit.snd", target, "");
}
else if (type.equals(DOT_ENERGY))
{
old_effect_string = SID_ENERGY_INCREASE;
new_effect_string = SID_ENERGY;
if(stack == 1)
playClientEffectObj(target, "appearance/pt_state_energy.prt", target, "", null, "state_energy");
playClientEffectObj(target, "sound/item_electronics_break.snd", target, "");
}
else if (type.equals(DOT_COLD))
{
old_effect_string = SID_COLD_INCREASE;
new_effect_string = SID_COLD;
if(stack == 1)
playClientEffectObj(target, "appearance/pt_state_energy.prt", target, "", null, "state_cold");
playClientEffectObj(target, "sound/item_electronics_break.snd", target, "");
}
else if (type.equals(DOT_ELECTRICITY))
{
old_effect_string = SID_ELECTRICITY_INCREASE;
new_effect_string = SID_ELECTRICITY;
if(stack == 1)
playClientEffectObj(target, "appearance/pt_state_energy.prt", target, "", null, "state_electricity");
playClientEffectObj(target, "sound/item_electronics_break.snd", target, "");
}
else if (type.equals(DOT_KINETIC))
{
old_effect_string = SID_KINETIC_INCREASE;
new_effect_string = SID_KINETIC;
if(stack == 1)
playClientEffectObj(target, "appearance/pt_state_energy.prt", target, "", null, "state_kinetic");
playClientEffectObj(target, "sound/item_electronics_break.snd", target, "");
}
else if (type.equals(DOT_BLEEDING))
{
new_effect_string = SID_BLEEDING;
old_effect_string = SID_BLEEDING_INCREASE;
if(stack == 1)
playClientEffectObj(target, "appearance/pt_state_bleeding.prt", target, "spine3", null, "state_bleeding");
playClientEffectObj(target, "sound/sta_bleeding_on.snd", target, "");
}
else if (type.equals(DOT_POISON))
{
old_effect_string = SID_POISONED_INCREASE;
new_effect_string = SID_POISONED;
if(stack == 1)
playClientEffectObj(target, "appearance/pt_state_poisoned.prt", target, "", null, "state_poisoned");
playClientEffectObj(target, "sound/sta_poisoned_on.snd", target, "");
}
else
{
buff.removeBuff(target, buffName);
return false;
}
// Attach the dot script
if (!hasScript(target, SCRIPT_PLAYER_DOT))
attachScript(target, SCRIPT_PLAYER_DOT);
/* Dont need this yet
if(type.equals(DOT_DISEASE))
{
_applyDiseaseDamage(target, dot_id);
}
*/
// If the dot is stacking with an existing dot_id, no need to send another message.
if (stack == 1)
{
//fingerprint the messageTo loop
trial.bumpSession(target, buffName);
dictionary d = trial.getSessionDict(target, buffName);
d.put("buffName", buffName);
d.put("caster", attacker);
d.put("strength", strength);
d.put("type", type);
//start the damage MessageTo loop
messageTo(target, "OnBuffDotPulse", d, buff.BUFF_DOT_TICK, false);
}
if (verbose)
{
if (stack == 1)
combat.sendCombatSpamMessage(target, new_effect_string);
else
combat.sendCombatSpamMessage(target, old_effect_string);
}
return true;
}
/***********************************************************************
* @brief applies the damage of the specifed dot Based on the Buff system
*
* @param obj_id target
* @param string dot_id
*
* @return boolean false on error or duration over
***********************************************************************/
boolean applyBuffDotDamage(obj_id target, obj_id caster, string buffName, int strength, string type)
{
if (!isIdValid(target) || !isIdValid(caster))
return false;
// Absorption skill mods on the target reduce the effective strength of the dot during damage pulses.
int absorption_mod = 0;
int vulnerability_mod = (int)getEnhancedSkillStatisticModifierUncapped(target, "dot_vulnerability_all");
dictionary protDic = armor.getCombatArmorSpecialProtections(target);
float resistance = 0.0f;
if(isPlayer(target))
{
resistance = (float)armor.getCombatArmorGeneralProtection(target);
}
if(type.equals(DOT_FIRE))
{
absorption_mod += getEnhancedSkillStatisticModifier(target, "absorption_fire");
vulnerability_mod += getEnhancedSkillStatisticModifierUncapped(target, "dot_vulnerability_fire");
if(isPlayer(target))
{
resistance += protDic.getFloat("heat");
}
else
{
resistance += (float)utils.getIntScriptVar(target, armor.SCRIPTVAR_CACHED_GENERAL_PROTECTION);
}
//nerfing skill mod resistances
absorption_mod /= MOD_DIVISOR;
//We don't nerf expertise dot absorption.
absorption_mod += (int)getSkillStatisticModifier(target, "expertise_dot_absorption_all");
absorption_mod += (int)(combat.convertProtectionToPercent(resistance) * DOT_ARMOR_MITIGATION_PERCENT);
}
else if(type.equals(DOT_ACID))
{
absorption_mod += getEnhancedSkillStatisticModifier(target, "absorption_acid");
vulnerability_mod += getEnhancedSkillStatisticModifierUncapped(target, "dot_vulnerability_acid");
if(isPlayer(target))
{
resistance += protDic.getFloat("acid");
}
else
{
resistance += (float)utils.getIntScriptVar(target, armor.SCRIPTVAR_CACHED_GENERAL_PROTECTION);
}
//nerfing skill mod resistances
absorption_mod /= MOD_DIVISOR;
//We don't nerf expertise dot absorption.
absorption_mod += (int)getSkillStatisticModifier(target, "expertise_dot_absorption_all");
absorption_mod += (int)(combat.convertProtectionToPercent(resistance) * DOT_ARMOR_MITIGATION_PERCENT);
}
else if(type.equals(DOT_COLD))
{
absorption_mod += getEnhancedSkillStatisticModifier(target, "absorption_cold");
vulnerability_mod += getEnhancedSkillStatisticModifierUncapped(target, "dot_vulnerability_cold");
if(isPlayer(target))
{
resistance += protDic.getFloat("cold");
}
else
{
resistance += (float)utils.getIntScriptVar(target, armor.SCRIPTVAR_CACHED_GENERAL_PROTECTION);
}
//nerfing skill mod resistances
absorption_mod /= MOD_DIVISOR;
//We don't nerf expertise dot absorption.
absorption_mod += (int)getSkillStatisticModifier(target, "expertise_dot_absorption_all");
absorption_mod += (int)(combat.convertProtectionToPercent(resistance) * DOT_ARMOR_MITIGATION_PERCENT);
}
else if(type.equals(DOT_ELECTRICITY))
{
absorption_mod += getEnhancedSkillStatisticModifier(target, "absorption_electricity");
vulnerability_mod += getEnhancedSkillStatisticModifierUncapped(target, "dot_vulnerability_electricity");
if(isPlayer(target))
{
resistance += protDic.getFloat("electricity");
}
else
{
resistance += (float)utils.getIntScriptVar(target, armor.SCRIPTVAR_CACHED_GENERAL_PROTECTION);
}
//nerfing skill mod resistances
absorption_mod /= MOD_DIVISOR;
//We don't nerf expertise dot absorption.
absorption_mod += (int)getSkillStatisticModifier(target, "expertise_dot_absorption_all");
absorption_mod += (int)(combat.convertProtectionToPercent(resistance) * DOT_ARMOR_MITIGATION_PERCENT);
}
else if(type.equals(DOT_ENERGY))
{
absorption_mod += getEnhancedSkillStatisticModifier(target, "absorption_energy");
vulnerability_mod += getEnhancedSkillStatisticModifierUncapped(target, "dot_vulnerability_energy");
if(isPlayer(target))
{
resistance += protDic.getFloat("energy");
}
else
{
resistance += (float)utils.getIntScriptVar(target, armor.SCRIPTVAR_CACHED_GENERAL_PROTECTION);
}
//nerfing skill mod resistances
absorption_mod /= MOD_DIVISOR;
//We don't nerf expertise dot absorption.
absorption_mod += (int)getSkillStatisticModifier(target, "expertise_dot_absorption_all");
absorption_mod += (int)(combat.convertProtectionToPercent(resistance) * DOT_ARMOR_MITIGATION_PERCENT);
}
else if(type.equals(DOT_KINETIC))
{
absorption_mod += getEnhancedSkillStatisticModifier(target, "absorption_kinetic");
vulnerability_mod += getEnhancedSkillStatisticModifierUncapped(target, "dot_vulnerability_kinetic");
if(isPlayer(target))
{
resistance += protDic.getFloat("kinetic");
}
else
{
resistance += (float)utils.getIntScriptVar(target, armor.SCRIPTVAR_CACHED_GENERAL_PROTECTION);
}
//nerfing skill mod resistances
absorption_mod /= MOD_DIVISOR;
//We don't nerf expertise dot absorption.
absorption_mod += (int)getSkillStatisticModifier(target, "expertise_dot_absorption_all");
absorption_mod += (int)(combat.convertProtectionToPercent(resistance) * DOT_ARMOR_MITIGATION_PERCENT);
}
else if(type.equals(DOT_BLEEDING))
{
absorption_mod += getEnhancedSkillStatisticModifier(target, "absorption_bleeding");
vulnerability_mod += getEnhancedSkillStatisticModifierUncapped(target, "dot_vulnerability_bleed");
if(isPlayer(target))
{
resistance += protDic.getFloat("cold");
}
else
{
resistance += (float)utils.getIntScriptVar(target, armor.SCRIPTVAR_CACHED_GENERAL_PROTECTION);
}
//nerfing skill mod resistances
absorption_mod /= MOD_DIVISOR;
//We don't nerf expertise dot absorption.
absorption_mod += (int)getSkillStatisticModifier(target, "expertise_dot_absorption_all");
absorption_mod += (int)(combat.convertProtectionToPercent(resistance) * DOT_ARMOR_MITIGATION_PERCENT);
}
else if(type.equals(DOT_POISON))
{
absorption_mod += getEnhancedSkillStatisticModifier(target, "absorption_poison");
vulnerability_mod += getEnhancedSkillStatisticModifierUncapped(target, "dot_vulnerability_poison");
if(isPlayer(target))
{
resistance += protDic.getFloat("acid");
}
else
{
resistance += (float)utils.getIntScriptVar(target, armor.SCRIPTVAR_CACHED_GENERAL_PROTECTION);
}
//nerfing skill mod resistances
absorption_mod /= MOD_DIVISOR;
//We don't nerf expertise dot absorption.
absorption_mod += (int)getSkillStatisticModifier(target, "expertise_dot_absorption_all");
absorption_mod += (int)(combat.convertProtectionToPercent(resistance) * DOT_ARMOR_MITIGATION_PERCENT);
}
else
{
return false;
}
// absorption reduces the strength of a dot by the given %.
int damageAbsorbed = 0;
if (absorption_mod > 0)
{
//cap the amount you can reduce a DoT by by 50%
if (absorption_mod > 50)
absorption_mod = 50;
damageAbsorbed = (int)(strength * (absorption_mod / 100.0f));
strength = (int)(strength * (1.0f - (absorption_mod / 100.0f)));
}
if (vulnerability_mod > 0)
{
strength = (int)(strength * (1.0f + (vulnerability_mod / 100.0f)));
}
// Bring over the generic damage multiply/divisor from combat base to apply to dot damage.
int expertiseDamageBonus = getEnhancedSkillStatisticModifierUncapped(caster, "combat_multiply_damage_dealt");
expertiseDamageBonus += getEnhancedSkillStatisticModifierUncapped(target, "combat_multiply_damage_taken");
float tempDamageFloat = (float)strength;
tempDamageFloat = tempDamageFloat * (1.0f + ((float)expertiseDamageBonus / 100.0f) );
int expertiseDamageReduction = getEnhancedSkillStatisticModifierUncapped(caster, "combat_divide_damage_dealt");
expertiseDamageReduction += getEnhancedSkillStatisticModifierUncapped(target, "combat_divide_damage_taken");
expertiseDamageReduction = expertiseDamageReduction > 100 ? 100 : expertiseDamageReduction;
tempDamageFloat = tempDamageFloat * (1.0f - ((float)expertiseDamageReduction / 100.0f));
strength = (int)tempDamageFloat;
// Dots don't incap. Reduce strength to one less than the current attribute if necessary.
int current_attrib = getAttrib(target, HEALTH);
// If a player was hit by a dot at one point and was attackable, but now is not, the dot should be removed.
if( (caster != target) && !pvpCanAttack(caster, target))
{
buff.removeBuff(target, buffName);
return false;
}
string mitigationString = "("+damageAbsorbed + getString(new string_id("dot_message", "generic_absorbed_buff"))+")";
if(strength > 0)
{
hit_result hit = new hit_result();
hit.damage = strength;
hit.success = true;
string_id strSpam = new string_id("combat_effects", "damage_fly");
prose_package ppFly = new prose_package();
ppFly = prose.setStringId(ppFly, strSpam);
ppFly = prose.setDI(ppFly, -strength);
prose_package ppSpam = new prose_package();
if (type.equals(DOT_FIRE))
{
if (isIdValid(caster) && !isDead(caster))
{
ppSpam = prose.setStringId(ppSpam, SID_FIRE_DMG_ATKR);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setTO(ppSpam, caster);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(caster, target, ppSpam, true, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target, caster, ppFly, 1f, colors.FIREBRICK, FLY_TEXT_FLAG_IS_DOT);
}
else
{
ppSpam = prose.setStringId(ppSpam, SID_FIRE_DMG);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(target, target, ppSpam, false, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target, target, ppFly, 1f, colors.FIREBRICK, FLY_TEXT_FLAG_IS_DOT);
}
}
else if (type.equals(DOT_ACID))
{
if (isIdValid(caster) && !isDead(caster))
{
ppSpam = prose.setStringId(ppSpam, SID_ACID_DMG_ATKR);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setTO(ppSpam, caster);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(caster, target, ppSpam, true, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target, caster, ppFly, 1f, colors.OLIVEDRAB, FLY_TEXT_FLAG_IS_DOT);
}
else
{
ppSpam = prose.setStringId(ppSpam, SID_ACID_DMG);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(target, target, ppSpam, false, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target, target, ppFly, 1f, colors.OLIVEDRAB, FLY_TEXT_FLAG_IS_DOT);
}
}
else if (type.equals(DOT_ENERGY))
{
if (isIdValid(caster) && !isDead(caster))
{
ppSpam = prose.setStringId(ppSpam, SID_ENERGY_DMG_ATKR);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setTO(ppSpam, caster);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(caster, target, ppSpam, true, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target, caster, ppFly, 1f, colors.DEEPSKYBLUE, FLY_TEXT_FLAG_IS_DOT);
}
else
{
ppSpam = prose.setStringId(ppSpam, SID_ENERGY_DMG);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(target, target, ppSpam, false, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target, target, ppFly, 1f, colors.DEEPSKYBLUE, FLY_TEXT_FLAG_IS_DOT);
}
}
else if (type.equals(DOT_COLD))
{
if (isIdValid(caster) && !isDead(caster))
{
ppSpam = prose.setStringId(ppSpam, SID_COLD_DMG_ATKR);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setTO(ppSpam, caster);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(caster, target, ppSpam, true, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target, caster, ppFly, 1f, colors.DEEPSKYBLUE, FLY_TEXT_FLAG_IS_DOT);
}
else
{
ppSpam = prose.setStringId(ppSpam, SID_COLD_DMG);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(target, target, ppSpam, false, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target, target, ppFly, 1f, colors.DEEPSKYBLUE, FLY_TEXT_FLAG_IS_DOT);
}
}
else if (type.equals(DOT_ELECTRICITY))
{
if (isIdValid(caster) && !isDead(caster))
{
ppSpam = prose.setStringId(ppSpam, SID_ELECTRICITY_DMG_ATKR);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setTO(ppSpam, caster);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(caster, target, ppSpam, true, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target, caster, ppFly, 1f, colors.DEEPSKYBLUE, FLY_TEXT_FLAG_IS_DOT);
}
else
{
ppSpam = prose.setStringId(ppSpam, SID_ELECTRICITY_DMG);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(target, target, ppSpam, false, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target, target, ppFly, 1f, colors.DEEPSKYBLUE, FLY_TEXT_FLAG_IS_DOT);
}
}
else if (type.equals(DOT_KINETIC))
{
if (isIdValid(caster) && !isDead(caster))
{
ppSpam = prose.setStringId(ppSpam, SID_KINETIC_DMG_ATKR);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setTO(ppSpam, caster);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(caster, target, ppSpam, true, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target, caster, ppFly, 1f, colors.DEEPSKYBLUE, FLY_TEXT_FLAG_IS_DOT);
}
else
{
ppSpam = prose.setStringId(ppSpam, SID_KINETIC_DMG);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(target, target, ppSpam, false, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target, target, ppFly, 1f, colors.DEEPSKYBLUE, FLY_TEXT_FLAG_IS_DOT);
}
}
else if(type.equals(dot.DOT_BLEEDING))
{
// Track damage for xp calcs
if (isIdValid(caster) && !isDead(caster))
{
ppSpam = prose.setStringId(ppSpam, SID_BLEED_DMG_ATKR);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setTO(ppSpam, caster);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(caster, target, ppSpam, true, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target,caster,ppFly, 1f, colors.INDIANRED, FLY_TEXT_FLAG_IS_DOT);
}
else
{
ppSpam = prose.setStringId(ppSpam, SID_BLEED_DMG);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(target, target, ppSpam, false, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target,target,ppFly, 1f, colors.INDIANRED, FLY_TEXT_FLAG_IS_DOT);
}
}
else if(type.equals(dot.DOT_POISON))
{
if (isIdValid(caster) && !isDead(caster))
{
ppSpam = prose.setStringId(ppSpam, SID_POISON_DMG_ATKR);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setTO(ppSpam, caster);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(caster, target, ppSpam, true, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target,caster,ppFly, 1f, colors.YELLOWGREEN, FLY_TEXT_FLAG_IS_DOT);
}
else
{
ppSpam = prose.setStringId(ppSpam, SID_POISON_DMG);
ppSpam = prose.setTT(ppSpam, target);
ppSpam = prose.setDI(ppSpam, strength);
ppSpam = prose.setTU(ppSpam, mitigationString);
sendCombatSpamMessageProse(target, target, ppSpam, false, true, true, COMBAT_RESULT_DEBUFF);
showFlyTextPrivateProseWithFlags(target,target,ppFly, 1f, colors.YELLOWGREEN, FLY_TEXT_FLAG_IS_DOT);
}
}
else
{
return false;
}
doDamage(caster, target, hit);
if(isIdValid(caster) && isIdValid(target) && exists(caster) && exists(target))
{
startCombat(caster, target);
startCombat(target, caster);
}
// Track damage for xp calcs
if(isIdValid(caster) && !isDead(caster))
{
//try to assign xp based on weapon used
obj_id myWeapon = getCurrentWeapon(caster);
if(isIdValid(myWeapon))
xp.updateCombatXpList(target, caster, myWeapon, strength);
else
//since the type no longer matters, we will give rifle. If we gave general we wouldnt be giving full credit.
xp.updateCombatXpList(target, caster, xp.COMBAT_RANGEDSPECIALIZE_RIFLE, strength);
}
else
{
xp.updateCombatXpList(target, target, xp.PERMISSIONS_ONLY, strength);
}
if(!isPlayer(target))
{
if(isIdValid(caster) && exists(caster))
{
addHate(target, caster, strength);
addHate(caster, target, 0.0f);
}
}
}
return true;
}
boolean removeBuffDotEffect(obj_id target, string type, boolean verbose)
{
////LOG("LOG_CHANNEL", "dot::removeDotEffect -- " + dot_id);
if (!isIdValid(target))
{
//LOG("LOG_CHANNEL", "dot::removeDotEffect -- target is null");
return false;
}
int[] dotBuffs = buff.getAllBuffsByEffect(target, "dot");
if(dotBuffs == null || dotBuffs.length <= 0)
{
string[] dots = getAllDots(target);
if(dots == null && hasScript(target, SCRIPT_PLAYER_DOT))
detachScript(target, SCRIPT_PLAYER_DOT);
}
// Check to see if there are any dots of the given type left. If not, send a message.
if (type.equals(DOT_FIRE))
{
if (verbose)
combat.sendCombatSpamMessage(target, SID_FIRE_STOP);
setState(target, STATE_ON_FIRE, false);
stopClientEffectObjByLabel(target, "state_onfire");
playClientEffectObj(target, "sound/sta_onfire_off.snd", target, "");
}
else if (type.equals(DOT_ACID))
{
if (verbose)
combat.sendCombatSpamMessage(target, SID_ACID_STOP);
stopClientEffectObjByLabel(target, "state_acid");
}
else if (type.equals(DOT_ENERGY))
{
if (verbose)
combat.sendCombatSpamMessage(target, SID_ENERGY_STOP);
stopClientEffectObjByLabel(target, "state_energy");
}
else if (type.equals(DOT_COLD))
{
if (verbose)
combat.sendCombatSpamMessage(target, SID_COLD_STOP);
stopClientEffectObjByLabel(target, "state_cold");
}
else if (type.equals(DOT_ELECTRICITY))
{
if (verbose)
combat.sendCombatSpamMessage(target, SID_ELECTRICITY_STOP);
stopClientEffectObjByLabel(target, "state_electricity");
}
else if (type.equals(DOT_KINETIC))
{
if (verbose)
combat.sendCombatSpamMessage(target, SID_ELECTRICITY_STOP);
stopClientEffectObjByLabel(target, "state_kinetic");
}
else if (type.equals(DOT_POISON))
{
if (verbose)
combat.sendCombatSpamMessage(target, SID_POISONED_STOP);
stopClientEffectObjByLabel(target, "state_poisoned");
}
else if (type.equals(DOT_BLEEDING))
{
if (verbose)
combat.sendCombatSpamMessage(target, SID_BLEEDING_STOP);
stopClientEffectObjByLabel(target, "state_bleeding");
}
return true;
}