Wards support is now fully extended to allow divine aura / stoneskin / intercept as possible solutions

Addresses issue #115 - minus fervor needs its own work implemented.

AddWard(dmg,keepward,wardtype,damagetype,dmgabsorptionpct,damageabsorptionmaxhealthpct,redirectdmgpct,maxhitcount)
This commit is contained in:
Image 2020-05-16 23:32:13 -04:00
parent f4cf365345
commit 07c14f1d92
4 changed files with 96 additions and 9 deletions

View file

@ -908,6 +908,8 @@ bool Entity::DamageSpawn(Entity* victim, int8 type, int8 damage_type, int32 low_
LogWrite(MISC__TODO, 3, "TODO", "Take players armor into account\nfile: %s, func: %s, line: %i)", __FILE__, __FUNCTION__, __LINE__);
bool useWards = false;
if(damage <= 0){
hit_result = DAMAGE_PACKET_RESULT_NO_DAMAGE;
damage = 0;
@ -915,7 +917,12 @@ bool Entity::DamageSpawn(Entity* victim, int8 type, int8 damage_type, int32 low_
else{
hit_result = DAMAGE_PACKET_RESULT_SUCCESSFUL;
GetZone()->CallSpawnScript(victim, SPAWN_SCRIPT_HEALTHCHANGED, this);
damage = victim->CheckWards(damage, damage_type);
int32 prevDmg = damage;
damage = victim->CheckWards(this, damage, damage_type);
if (damage < prevDmg)
useWards = true;
victim->TakeDamage(damage);
victim->CheckProcs(PROC_TYPE_DAMAGED, this);
@ -953,6 +960,10 @@ bool Entity::DamageSpawn(Entity* victim, int8 type, int8 damage_type, int32 low_
if (victim->IsEntity())
((Entity*)victim)->CheckInterruptSpell(this);
}
else if (useWards)
{
GetZone()->SendDamagePacket(this, victim, DAMAGE_PACKET_TYPE_SIMPLE_DAMAGE, DAMAGE_PACKET_RESULT_NO_DAMAGE, damage_type, 0, spell_name);
}
if (victim->GetHP() <= 0)
KillSpawn(victim, damage_type, blow_type);

View file

@ -1263,7 +1263,7 @@ void Entity::RemoveWard(int32 spellID) {
}
}
int32 Entity::CheckWards(int32 damage, int8 damage_type) {
int32 Entity::CheckWards(Entity* attacker, int32 damage, int8 damage_type) {
map<int32, WardInfo*>::iterator itr;
WardInfo* ward = 0;
LuaSpell* spell = 0;
@ -1272,7 +1272,7 @@ int32 Entity::CheckWards(int32 damage, int8 damage_type) {
// Get the ward with the lowest base damage
for (itr = m_wardList.begin(); itr != m_wardList.end(); itr++) {
if (!ward || itr->second->BaseDamage < ward->BaseDamage) {
if (itr->second->DamageLeft > 0 &&
if ((itr->second->AbsorbAllDamage || itr->second->DamageLeft > 0) &&
(itr->second->WardType == WARD_TYPE_ALL ||
(itr->second->WardType == WARD_TYPE_PHYSICAL && damage_type >= DAMAGE_PACKET_DAMAGE_TYPE_SLASH && damage_type <= DAMAGE_PACKET_DAMAGE_TYPE_PIERCE) ||
(itr->second->WardType == WARD_TYPE_MAGICAL && ((itr->second->DamageType == 0 && damage_type >= DAMAGE_PACKET_DAMAGE_TYPE_PIERCE) || (damage_type >= DAMAGE_PACKET_DAMAGE_TYPE_PIERCE && itr->second->DamageType == damage_type)))))
@ -1285,6 +1285,12 @@ int32 Entity::CheckWards(int32 damage, int8 damage_type) {
spell = ward->Spell;
// damage to redirect at the source (like intercept)
int32 redirectDamage = 0;
if (ward->RedirectDamagePercent)
redirectDamage = (int32)(double)damage * ((double)ward->RedirectDamagePercent / 100.0);
// percentage the spell absorbs of all possible damage
int32 damageToAbsorb = 0;
if (ward->DamageAbsorptionPercentage > 0)
damageToAbsorb = (int32)(double)damage * ((double)ward->DamageAbsorptionPercentage/100.0);
@ -1302,9 +1308,17 @@ int32 Entity::CheckWards(int32 damage, int8 damage_type) {
int32 baseDamageRemaining = damage - damageToAbsorb;
if (damageToAbsorb >= ward->DamageLeft) {
bool hasSpellBeenRemoved = false;
if (ward->AbsorbAllDamage)
{
ward->LastAbsorbedDamage = ward->DamageLeft;
GetZone()->SendHealPacket(ward->Spell->caster, this, HEAL_PACKET_TYPE_ABSORB, damage, spell->spell->GetName());
damage = 0;
}
else if (damageToAbsorb >= ward->DamageLeft) {
// Damage is greater than or equal to the amount left on the ward
ward->LastAbsorbedDamage = ward->DamageLeft;
// remove what damage we can absorb
damageToAbsorb -= ward->DamageLeft;
@ -1315,13 +1329,16 @@ int32 Entity::CheckWards(int32 damage, int8 damage_type) {
spell->damage_remaining = 0;
GetZone()->SendHealPacket(spell->caster, this, HEAL_PACKET_TYPE_ABSORB, ward->DamageLeft, spell->spell->GetName());
if (!ward->keepWard) {
hasSpellBeenRemoved = true;
RemoveWard(spell->spell->GetSpellID());
GetZone()->GetSpellProcess()->DeleteCasterSpell(spell);
}
}
else {
ward->LastAbsorbedDamage = damageToAbsorb;
// Damage is less then the amount left on the ward
ward->DamageLeft -= damageToAbsorb;
spell->damage_remaining = ward->DamageLeft;
if (spell->caster->IsPlayer())
ClientPacketFunctions::SendMaintainedExamineUpdate(GetZone()->GetClientBySpawn(spell->caster), spell->slot_pos, ward->DamageLeft, 1);
@ -1331,6 +1348,31 @@ int32 Entity::CheckWards(int32 damage, int8 damage_type) {
damage = baseDamageRemaining;
}
if (redirectDamage)
{
ward->LastRedirectDamage = redirectDamage;
if (attacker && spell->caster)
attacker->DamageSpawn(spell->caster, DAMAGE_PACKET_TYPE_SPELL_DAMAGE, damage_type, redirectDamage, redirectDamage, 0);
}
bool shouldRemoveSpell = false;
ward->HitCount++; // increment hit count
if (ward->MaxHitCount && spell->num_triggers)
{
spell->num_triggers--;
ClientPacketFunctions::SendMaintainedExamineUpdate(spell->caster->GetZone()->GetClientBySpawn(spell->caster), spell->slot_pos, spell->num_triggers, 0);
}
if (ward->HitCount >= ward->MaxHitCount) // there isn't a max hit requirement with the hit count, so just go based on hit count
shouldRemoveSpell = true;
if (shouldRemoveSpell && !hasSpellBeenRemoved)
{
RemoveWard(spell->spell->GetSpellID());
GetZone()->GetSpellProcess()->DeleteCasterSpell(spell);
}
// Reset ward pointer
ward = 0;
}

View file

@ -255,8 +255,17 @@ struct WardInfo {
int8 WardType;
int8 DamageType;
bool keepWard;
int8 DamageAbsorptionPercentage;
int8 DamageAbsorptionMaxHealthPercent;
int32 DamageAbsorptionPercentage;
int32 DamageAbsorptionMaxHealthPercent;
int32 RedirectDamagePercent;
int32 LastRedirectDamage;
int32 LastAbsorbedDamage;
int32 HitCount;
int32 MaxHitCount;
bool AbsorbAllDamage; // damage is always absorbed, usually spells based on hits, when we pass damage in AddWard as 0 this will be set to true
};
#define WARD_TYPE_ALL 0
@ -720,7 +729,7 @@ public:
/// <summary>Subtracts the given damage from the wards</summary>
/// <param name='damage'>The damage to subtract from the wards</param>
/// <returns>The amount of damage left after wards</returns>
int32 CheckWards(int32 damage, int8 damage_type);
int32 CheckWards(Entity* attacker, int32 damage, int8 damage_type);
map<int16, float> stats;

View file

@ -4934,8 +4934,10 @@ int EQ2Emu_lua_AddWard(lua_State* state) {
bool keepWard = (lua_interface->GetInt8Value(state, 2) == 1);
int8 wardType = lua_interface->GetInt8Value(state, 3);
int8 damageTypes = lua_interface->GetInt8Value(state, 4);
int8 damageAbsorptionPercent = lua_interface->GetInt8Value(state, 5);
int8 damageAbsorptionMaxHealthPercent = lua_interface->GetInt8Value(state, 6);
int32 damageAbsorptionPercent = lua_interface->GetInt32Value(state, 5);
int32 damageAbsorptionMaxHealthPercent = lua_interface->GetInt32Value(state, 6);
int32 redirectDamagePercent = lua_interface->GetInt32Value(state, 7);
int32 maxHitCount = lua_interface->GetInt32Value(state, 8);
LuaSpell* spell = lua_interface->GetCurrentSpell(state);
@ -4957,6 +4959,8 @@ int EQ2Emu_lua_AddWard(lua_State* state) {
ward->Spell = spell;
ward->BaseDamage = damage;
ward->DamageLeft = damage;
ward->AbsorbAllDamage = (damage == 0) ? true : false;
ward->keepWard = keepWard;
ward->WardType = wardType;
if (damageAbsorptionPercent > 100)
@ -4969,6 +4973,17 @@ int EQ2Emu_lua_AddWard(lua_State* state) {
ward->DamageAbsorptionMaxHealthPercent = damageAbsorptionMaxHealthPercent;
ward->RedirectDamagePercent = redirectDamagePercent;
ward->LastRedirectDamage = 0;
ward->LastAbsorbedDamage = 0;
ward->HitCount = 0;
spell->num_triggers = maxHitCount;
spell->had_triggers = true;
spell->cancel_after_all_triggers = false;
ward->MaxHitCount = maxHitCount;
if (wardType == WARD_TYPE_MAGICAL)
ward->DamageType = damageTypes;
@ -5069,6 +5084,16 @@ int EQ2Emu_lua_GetWardValue(lua_State* state) {
lua_interface->SetInt32Value(state, ward->DamageAbsorptionPercentage);
else if (boost::iequals(type, "dmgabsorptionmaxhealthpct"))
lua_interface->SetInt32Value(state, ward->DamageAbsorptionMaxHealthPercent);
else if (boost::iequals(type, "redirectdamagepercent"))
lua_interface->SetInt32Value(state, ward->RedirectDamagePercent);
else if (boost::iequals(type, "lastredirectdamage"))
lua_interface->SetInt32Value(state, ward->LastRedirectDamage);
else if (boost::iequals(type, "lastabsorbeddamage"))
lua_interface->SetInt32Value(state, ward->LastAbsorbedDamage);
else if (boost::iequals(type, "hitcount"))
lua_interface->SetInt32Value(state, ward->HitCount);
else if (boost::iequals(type, "maxhitcount"))
lua_interface->SetInt32Value(state, ward->MaxHitCount);
else
lua_interface->LogError("%s: LUA GetWardValue command argument type '%s' did not match any options", lua_interface->GetScriptName(state), type);
return 1;