Spoiler
function( TimelineContext,DamageModifiers,DamageStat_Right,DamageStat_Left,AbilityDamageMultiplier,AbilityDamageMultiplierDefault,CriticalBonus,ShieldedTag,Class,Level,Invulnerable,Attack,BarrierDamageModifier,Barrier,GuardDamageModifier,StatGuard,HealthDamageModifier,Unkillable,HealthMax,StatDamageBonusBarrier,StatDamageBonusGuard,StatDefenseMelee,StatDefenseRanged,StatDefenseMagic,MeleeRange,StatResistanceGuard,StatResistanceBarrier,StatResistanceCritical,IsRune,StatArmor,StatArmorPenetration,StatArmorPenetrationPercentage,FlankingBonusStat,PhysicalResistanceTag,MagicalResistanceTag,AbilityDamageOverride,StatCreatureDamageMultiplier,BasicAttackTag,Stat_Critical_Chance_Override,StatArmorFront,Stat_Defense_All_Front,ArmorPercentageForMagicDefense,RankStat,DifficultyDamageMultiplierProvider,DamageTakenMultiplier )
do
damage = 0;
CLASS_INVALID = 4;
--[[ ATTACKER AND TARGET PARAMETERS ]]--
-- get target
targetCharacter = DA3.GetOwnerCharacter(TimelineContext);
print("target = " .. DA3.ToString(targetCharacter));
if (targetCharacter == nil) then
print("ERROR - no target character");
return damage;
end
-- target class
targetclass = DA3.GetCharacterClass(targetCharacter);
print("target class = " .. targetclass);
-- target level
targetlevel = math.max(1, DA3.GetStatTotalValue(targetCharacter, Level));
print("target creature level = " .. targetlevel);
-- get attacker
sourceCharacter = DA3.GetCasterCharacter(TimelineContext);
print("source = " .. DA3.ToString(sourceCharacter));
if (sourceCharacter == nil) then
print("ERROR - no source character");
return damage;
end
if (DA3.CharacterIsCharacter(sourceCharacter) == false) then
print("!!! source character is not a character, using target character as attacker character to activate trap logic path !!!");
sourceCharacter = targetCharacter;
end
-- attacker class
attackerclass = DA3.GetCharacterClass(sourceCharacter);
print("attacker class = " .. attackerclass);
-- attacker level
attackerlevel = math.max(1, DA3.GetStatTotalValue(sourceCharacter, Level));
print("attacker creature level = " .. attackerlevel);
-- attack damage type
type = DA3.GetDamageType(TimelineContext);
print("Initial damage type = " .. DA3.ToString(type));
-- attack hand
hand = DA3.GetDamageEquipSlot(TimelineContext);
print("initial item hand = " .. DA3.ToString(hand));
isTrap = false;
if(sourceCharacter == targetCharacter) then
print("Trap/Environment damage!");
isTrap = true;
end
MeleeRange = 3.0
isMeleeRange = false;
distance = DA3.GetDistanceBetween(targetCharacter, sourceCharacter, false);
if (distance <= MeleeRange) then
isMeleeRange = true;
end;
--[[ EARLY EXIT SCENARIOS ]]--
-- invulnerable check
invulnerable = DA3.CharacterHasTimelineTag(targetCharacter, Invulnerable);
print("invulnerable = " .. DA3.ToString(invulnerable));
if (invulnerable) then
print("target is invulnerable");
return 0;
end
--[[ ATTACKER SECTION ]]--
-- get damage type
if (type <= 0) then
print("Timeline context damage type invalid - trying to get damage type from items.");
print("IsRune = " .. DA3.ToString(IsRune));
if (IsRune) then
print("Rune - using rune damage type");
type = DA3.GetRuneDamageType(sourceCharacter, hand);
else
print("no rune......");
type = DA3.GetItemDamageType(sourceCharacter, hand);
end
print(" item damage type = " .. DA3.ToString(type));
if (type <= 0) then
print(" setting damage type to default/physical");
type = 1;
end
end
if (type >= 8 and attackerclass ~= CLASS_INVALID) then
type = DA3.GetItemDamageType(sourceCharacter, hand);
print("VS-Race damage type - using regular item damage type: " .. DA3.ToString(type));
elseif(type >= 8 and attackerclass == CLASS_INVALID) then
print("Creature class with VS-Race damage type - setting to Physical (1)");
type = 1;
end
print("Final damage type = " .. DA3.ToString(type));
resistantToPhysicalDamage = DA3.CharacterHasTimelineTag(targetCharacter, PhysicalResistanceTag);
resistantToMagicalDamage = DA3.CharacterHasTimelineTag(targetCharacter, MagicalResistanceTag);
print("target physical resistance: " .. DA3.ToString(resistantToPhysicalDamage) .. ", magical damage: " .. DA3.ToString(resistantToMagicalDamage));
if(type == 1 and resistantToPhysicalDamage) then
print("Physical damage vs. target that is resistant to physical damage - aborting")
return 0;
elseif(type ~= 1 and resistantToMagicalDamage) then
print("Magical damage vs. target that is resistant to magical damage - aborting")
return 0;
end
-- get base damage
damageMultiplier = 1;
if (isTrap == true) then
damage = DA3.GetStatValueWithDamageCalculationModifiers(sourceCharacter, DamageStat_Right, sourceCharacter, targetCharacter);
elseif attackerclass ~= CLASS_INVALID then
damageOverride = DA3.GetAbilityProperty(TimelineContext, AbilityDamageOverride);
if(damageOverride ~= nil and damageOverride > 0) then
print("Using ability damage override for base damage " .. DA3.ToString(damageOverride));
damage = damageOverride;
elseif (hand == 0) then -- EquipSlot_Mainhand
damage = damage + DA3.GetStatValueWithDamageCalculationModifiers(sourceCharacter, DamageStat_Right, sourceCharacter, targetCharacter);
else
damage = damage + DA3.GetStatValueWithDamageCalculationModifiers(sourceCharacter, DamageStat_Left, sourceCharacter, targetCharacter);
end
else -- creatures
if(type == 1) then -- physical
damage = DA3.GetStatValueWithDamageCalculationModifiers(sourceCharacter, DamageStat_Right, sourceCharacter, targetCharacter);
else -- elemental
damage = DA3.GetStatValueWithDamageCalculationModifiers(sourceCharacter, DamageStat_Left, sourceCharacter, targetCharacter);
end
end
print("base damage = " .. damage);
if (attackerclass ~= CLASS_INVALID) and (targetclass ~= CLASS_INVALID) and (type == 1) then -- physical party friendly fire hax to compensate for player armor
damage = damage * 2.5
print("after physical FF compensation = " .. damage);
end
-- apply a bit of random range
damageMin = math.floor(math.max(damage * 0.95, 1) + 0.5)
damageMax = math.floor(math.max(damage * 1.05, 1) + 0.5)
damage = math.random(damageMin, damageMax);
print("base damage after random variation = " .. damage);
flanking = DA3.WedgeTest(targetCharacter, sourceCharacter, 180, 180);
flankingbonus = 0;
print("flanking = " .. DA3.ToString(flanking));
barrier = DA3.GetStatValueWithDamageCalculationModifiers(targetCharacter, Barrier, sourceCharacter, targetCharacter) or 0;
print("Early barrier check: " .. barrier);
-- Physical Damage Reduction due to Armor Rating
if (type == 1 and damage > 0 and IsRune == false) then -- physical (if its a physical damage AND rune then it must be vs-race rune, so we skip armor)
-- get armor value of defender: Armor Rating if flanking and Armor_Rating_Front if not flanking
if(flanking or targetclass == CLASS_INVALID) then -- creatures always use normal armor, no fancy front armor for them
armor = DA3.GetStatValueWithDamageCalculationModifiers(targetCharacter, StatArmor, sourceCharacter, targetCharacter);
else
armor = DA3.GetStatValueWithDamageCalculationModifiers(targetCharacter, StatArmorFront, sourceCharacter, targetCharacter);
end
print("armor = " .. armor);
-- get flat and % armor penetration of attacker
armorPenetration = DA3.GetStatValueWithDamageCalculationModifiers(sourceCharacter, StatArmorPenetration, sourceCharacter, targetCharacter);
armorPenetrationPercentage = DA3.GetStatValueWithDamageCalculationModifiers(sourceCharacter, StatArmorPenetrationPercentage, sourceCharacter, targetCharacter);
print("armorPenetration = " .. armorPenetration);
print("armorPenetrationPercentage = " .. armorPenetrationPercentage);
-- calculate effective armor based on penetration of attacker
effectiveArmor = math.max(0,(armor-armorPenetration)) * ((100-armorPenetrationPercentage)/100);
-- reduce damage by Effective Armor
-- minimum 2 damage when critting, even against massive armor
-- commenting out this section as I get bad parameter error for the ArmorPercentageForMagicDefense param... not sure why
--if (type ~= 1) then
-- effectiveArmor = effectiveArmor * DA3.EvaluateFloatProvider(ArmorPercentageForMagicDefense, TimelineContext)
--end
print("effectiveArmor = " .. effectiveArmor);
barrierCompensateValue = math.min(effectiveArmor, barrier);
print("barrier compensate value: " .. barrierCompensateValue);
armorAdjustedDamage = damage - effectiveArmor;
if (critical) then
damage = math.max(2, armorAdjustedDamage) + barrierCompensateValue;
else
damage = math.max(1, armorAdjustedDamage) + barrierCompensateValue;
end
print("damage (after effectiveArmor) = " .. damage);
end
-- The script parameter name is still StatCreatureDamageMultiplier, but it can be used by players as well
damageMultiplier = DA3.GetStatValueWithDamageCalculationModifiers(sourceCharacter, StatCreatureDamageMultiplier, sourceCharacter, targetCharacter);
damageMultiplier = (damageMultiplier * 100) - 100; -- convert to %
print("damage multiplier = " .. damageMultiplier);
difficultyMultiplier = 0;
rankMultiplier = 0;
if(attackerclass == CLASS_INVALID) then -- creature
-- Difficulty
difficultyMultiplier = (DA3.EvaluateFloatProvider(DifficultyDamageMultiplierProvider, TimelineContext));
difficultyMultiplier = (difficultyMultiplier * 100) - 100; -- convert to %
print("Difficulty multiplier: " .. difficultyMultiplier);
-- Rank
rank = DA3.GetStatTotalValue(sourceCharacter, RankStat) or 0;
rankDamageTable = { 0, 12.5, 25 }
rankIndex = math.max(1,math.min(3,rank+1))
rankMultiplier = rankDamageTable[rankIndex]
print("Rank Multiplier: " .. rankMultiplier);
end
-- ability damage multiplier
print("Caclulating Ability Damage Multiplier (ADM)");
abilityBonus = DA3.GetAbilityProperty(TimelineContext, AbilityDamageMultiplier) or AbilityDamageMultiplierDefault;
-- need to turn it into a percentage-friendly number:
if(abilityBonus > 0) then
abilityBonus = (abilityBonus * 100) - 100;
print("Ability bonus (will be applied along with all other bonuses) = " .. abilityBonus);
end
-- get damage type bonus
if (type == 7) then -- plot
damage = math.floor(damage + 0.5);
return math.max(0, damage);
end
bonusStat = DA3.GetDamageTypeAttackerBonusStat(DamageModifiers, type);
print("bonusStat = " .. DA3.ToString(bonusStat));
typebonus = DA3.GetStatValueWithDamageCalculationModifiers(sourceCharacter, bonusStat, sourceCharacter, targetCharacter);
print ("bonus from damage type = " .. typebonus .. "%");
-- get critical hit bonus
critical = DA3.IsCriticalActivation(TimelineContext);
critical_chance_override = DA3.GetStatValueWithDamageCalculationModifiers(sourceCharacter, Stat_Critical_Chance_Override, sourceCharacter, targetCharacter);
print("critical = " .. DA3.ToString(critical) .. ", critical chance override: " .. critical_chance_override);
if(critical_chance_override ~= nil and critical_chance_override > 0) then
critical = false;
roll = math.random(100);
if(roll <= critical_chance_override) then
critical = true;
end
print("critical result after overrride roll: " .. critical);
end
criticalbonus = 0;
if (critical) and (attackerclass ~= CLASS_INVALID) and not(isTrap) then
criticalbonus = DA3.GetStatValueWithDamageCalculationModifiers(sourceCharacter, CriticalBonus, sourceCharacter, targetCharacter);
criticalResistance = DA3.GetStatValueWithDamageCalculationModifiers(targetCharacter, StatResistanceCritical, sourceCharacter, targetCharacter);
print ("attacker bonus from critical = " .. criticalbonus .. "%");
print ("defender resistance from critical = " .. criticalResistance .. "%");
criticalbonus = criticalbonus - criticalResistance;
print ("final bonus from critical = " .. criticalbonus .. "%");
end
-- attack bonus
attackbonus = 0;
--ability = DA3.GetContextAbility(TimelineContext);
--if (attackerclass ~= CLASS_INVALID and ability ~= nil and DA3.IsAbilityWithTag(ability, BasicAttackTag) == false) then
attackbonus = DA3.GetStatValueWithDamageCalculationModifiers(sourceCharacter, Attack, sourceCharacter, targetCharacter);
print ("bonus from attack stat = " .. attackbonus .. "%");
--end
-- attack bonus based on level difference (SP only)
if(DA3.IsMultiplayer() == false) then
if (attackerclass == CLASS_INVALID) then
difference = attackerlevel - targetlevel;
print("level difference = " .. difference);
if (difference > 3) then
attackbonus = attackbonus + (difference * 25);
end
print("level adjusted attack bonus = " .. attackbonus);
end
end
-- flanking
if (flanking) and not(isTrap) then
flankingbonus = DA3.GetStatValueWithDamageCalculationModifiers(sourceCharacter, FlankingBonusStat, sourceCharacter, targetCharacter);
if(isMeleeRange == false) then
flankingbonus = flankingbonus - 25; -- no default, but can increase by bonuses
if(flankingbonus < 0) then flankingbonus = 0 end
end
print("flanking bonus = " .. flankingbonus);
end
print("target damage before bonus adjustments = " .. damage);
--[[ FINAL INCOMING DAMAGE CALCULATION ]]--
if (attackerclass == CLASS_INVALID) then
damage = damage * (100 + damageMultiplier + abilityBonus + typebonus + criticalbonus + flankingbonus + attackbonus + rankMultiplier + difficultyMultiplier) / 100;
else
damage = damage * (100 + abilityBonus) / 100;
damage = damage * (100 + damageMultiplier + typebonus + attackbonus) / 100;
damage = damage * (100 + criticalbonus + flankingbonus) / 100;
end
print("target adjusted damage = " .. damage);
--[[ TARGET SECTION ]]--
-- Damage Reduction due to Resistances
resistanceStat = DA3.GetDamageTypeVictimResistanceStat(DamageModifiers, type);
print("resistanceStat = " .. DA3.ToString(resistanceStat));
resistance = DA3.GetStatValueWithDamageCalculationModifiers(targetCharacter, resistanceStat, sourceCharacter, targetCharacter);
print ("resistance to damage type = " .. resistance);
damage = damage * ((100 - resistance) / 100);
damage = math.max(0, damage);
print ("damage after resistance = " .. damage);
-- defense resistance
-- Melee defense: physical or nature damage at short range
-- Ranged defense: physical or nature damage not at short range
-- Magic defense: all other damage types
defense = 0;
if (targetclass ~= CLASS_INVALID) then
defenseMelee = DA3.GetStatValueWithDamageCalculationModifiers(targetCharacter, StatDefenseMelee, sourceCharacter, targetCharacter);
defenseRanged = DA3.GetStatValueWithDamageCalculationModifiers(targetCharacter, StatDefenseRanged, sourceCharacter, targetCharacter);
defenseMagic = DA3.GetStatValueWithDamageCalculationModifiers(targetCharacter, StatDefenseMagic, sourceCharacter, targetCharacter);
defenseAllFront = DA3.GetStatValueWithDamageCalculationModifiers(targetCharacter, Stat_Defense_All_Front, sourceCharacter, targetCharacter);
print ("Melee Defense = " .. defenseMelee);
print ("Ranged Defense = " .. defenseRanged);
print ("Magic Defense = " .. defenseMagic);
print ("Front Defense = " .. defenseAllFront);
if(flanking == false) then
print ("Being attacked from front - adding front defense to all other defenses");
defenseMelee = math.min(80,(defenseMelee + defenseAllFront));
defenseRanged = math.min(80,(defenseRanged + defenseAllFront));
defenseMagic = math.min(80,(defenseMagic + defenseAllFront));
end
naturalDamageType = false;
if (type == 1 or type == 5) then
naturalDamageType = true;
end;
print ("naturalDamageType = " .. DA3.ToString(naturalDamageType));
print ("isMeleeRange = " .. DA3.ToString(isMeleeRange));
if (naturalDamageType == true and isMeleeRange == true) then
defense = defenseMelee;
elseif(naturalDamageType == true and isMeleeRange == false) then
defense = defenseRanged;
else
defense = defenseMagic;
end
print ("defense value used for this attack = " .. defense);
end
damage = damage * ((100 - defense) / 100);
print ("damage after defence = " .. damage);
-- get shielded
shielded = DA3.CharacterHasTimelineTag(targetCharacter, ShieldedTag);
print("shielded = " .. DA3.ToString(shielded));
if (shielded) and (flanking == false) then
print("attacker within front arc of shielded target");
damage = damage * 0.5;
print("damage after shielding = " .. damage);
end
remaining = damage;
-- barrier damage bonus
if (remaining > 0) then
print ("barrier = " .. barrier);
if (barrier > 0) then
barriermodifier = DA3.GetAbilityProperty(TimelineContext, BarrierDamageModifier);
if barriermodifier ~= nil
then barriermodifier = barriermodifier*100
else barriermodifier = 0;
end
barrierPenetration = DA3.GetStatValueWithDamageCalculationModifiers(sourceCharacter, StatDamageBonusBarrier, sourceCharacter, targetCharacter) or 0;
barrierResistance = DA3.GetStatValueWithDamageCalculationModifiers(targetCharacter, StatResistanceBarrier, sourceCharacter, targetCharacter) or 0;
print ("barriermodifier = " .. barriermodifier);
print ("barrierPenetration = " .. barrierPenetration);
print ("barrierResistance = " .. barrierResistance);
barriermodifier = barriermodifier + barrierPenetration - barrierResistance;
barrierDamage = remaining + remaining * (barriermodifier / 100)
print ("barriermodifier (total) = " .. barriermodifier .. ", barrier damage total: " .. barrierDamage);
if ( barrierDamage > barrier ) then -- if the total barrier damage inflicted is bigger than the barrier value remaining
damage = math.max(barrier, damage); -- should be just enough to remove the barrier or more only if the base damage, without barrier bonuses, was more than the barrier.
remaining = damage - barrier; -- the remaining damage to handle past the barrier
print("Barrier damage is greater than what's left of the barrier. Update total damage: " .. damage .. ", remaining damage to handle past barrier: " .. remaining);
else -- the total damage reduced the barrier, but did not eliminate it
damage = barrierDamage;
remaining = 0;
print("Barrier damage was enough to take only part of the barrier. Total barrier damage: " .. damage);
print("There should be no need to handle further damage logic beyond this point");
end
end
end
-- guard damage bonus
if (remaining > 0) then
guard = DA3.GetStatValueWithDamageCalculationModifiers(targetCharacter, StatGuard, sourceCharacter, targetCharacter) or 0;
print ("guard = " .. guard);
if (guard > 0) then
guardModifier = DA3.GetAbilityProperty(TimelineContext, GuardDamageModifier) or 0;
guardModifier = guardModifier * 100;
guardDamageBonus = DA3.GetStatValueWithDamageCalculationModifiers(sourceCharacter, StatDamageBonusGuard, sourceCharacter, targetCharacter) or 0;
guardResist = DA3.GetStatValueWithDamageCalculationModifiers(targetCharacter, StatResistanceGuard, sourceCharacter, targetCharacter) or 0;
print ("guardDamageBonus = " .. guardDamageBonus);
print ("guardResist = " .. guardResist);
guardModifier = guardModifier + guardDamageBonus - guardResist;
guardDamage = remaining + remaining * (guardModifier / 100)
print ("guardModifier = " .. guardModifier);
if ( guardDamage > guard ) then -- if the total guard damage inflicted is bigger than the guard value remaining
damage = math.max(guard, damage); -- should be just enough to remove the guard or more only if the base damage, without barrier bonuses, was more than the barrier.
remaining = damage - guard; -- the remaining damage to handle past the guard
print("Guard damage is greater than what's left of the guard. Update total damage: " .. damage .. ", remaining damage to handle past guard: " .. remaining);
else -- the total damage reduced the guard, but did not eliminate it
damage = guardDamage;
remaining = 0;
print("Guard damage was enough to take only part of the guard. Total guard damage: " .. damage);
print("There should be no need to handle further damage logic beyond this point");
end
end
end
-- health damage bonus
if (remaining > 0) then
healthmodifier = DA3.GetAbilityProperty(TimelineContext, HealthDamageModifier) or 0;
print ("healthmodifier = " .. healthmodifier);
if (healthmodifier > 0) then
damage = damage + (remaining * (healthmodifier / 100));
remaining = 0;
end
end
-- damage rounding
-- this is important for making sure that at least 1 damage is applied always by the player against enemies
damage = math.floor(damage + 0.5);
damage = math.max(1, damage);
--// IMPORTANT: unkillable check should be done last, after rounding.
unkillable = DA3.CharacterHasTimelineTag(targetCharacter, Unkillable);
print("unkillable = " .. DA3.ToString(unkillable));
if (unkillable) then
health = DA3.GetCharacterHealth(targetCharacter);
print("health = " .. DA3.ToString(health));
if (health - damage <= 0) then -- if its a killing blow then inflict damage up to 1 health
damage = health - 1;
end
if (damage < 1) then
damage = 0
end
end
print("returned damage = " .. damage);
-- Allows for specific instances where creatures take 0 damage and to not show a floaty
damageTakenMultiplier = DA3.GetStatValueWithDamageCalculationModifiers(targetCharacter, DamageTakenMultiplier, sourceCharacter, targetCharacter);
damage = damage * damageTakenMultiplier
return damage;
end





Retour en haut







