From bb91265b2be1d8fff20ccd562343586456b4bf18 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Mon, 20 Oct 2014 00:36:13 -0400 Subject: [PATCH 1/9] Allow npc_types field 'special_abilities' to be set as null in database. Changed due to issues when trying to copy npcs or remove abilities from the field directly in the dataabase. --- .../required/2014_10_16_special_abilities_null.sql | 6 ++++++ zone/zonedb.cpp | 13 +++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 utils/sql/git/required/2014_10_16_special_abilities_null.sql diff --git a/utils/sql/git/required/2014_10_16_special_abilities_null.sql b/utils/sql/git/required/2014_10_16_special_abilities_null.sql new file mode 100644 index 000000000..c01bd725b --- /dev/null +++ b/utils/sql/git/required/2014_10_16_special_abilities_null.sql @@ -0,0 +1,6 @@ +ALTER TABLE `merc_stats` +MODIFY COLUMN `special_abilities` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL AFTER `attack_speed`; + +ALTER TABLE `npc_types` +MODIFY COLUMN `special_abilities` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL AFTER `npcspecialattks`; + diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index e83edf2b9..77b179a68 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -1816,7 +1816,12 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) { tmpNPCType->min_dmg = atoi(row[31]); tmpNPCType->max_dmg = atoi(row[32]); tmpNPCType->attack_count = atoi(row[33]); - strn0cpy(tmpNPCType->special_abilities, row[34], 512); + + if (row[34] != nullptr) + strn0cpy(tmpNPCType->special_abilities, row[34], 512); + else + strn0cpy(tmpNPCType->special_abilities,"\0", 512); + tmpNPCType->npc_spells_id = atoi(row[35]); tmpNPCType->npc_spells_effects_id = atoi(row[36]); tmpNPCType->d_meele_texture1 = atoi(row[37]); @@ -2018,7 +2023,11 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client tmpNPCType->min_dmg = atoi(row[24]); tmpNPCType->max_dmg = atoi(row[25]); tmpNPCType->attack_count = atoi(row[26]); - strn0cpy(tmpNPCType->special_abilities, row[27], 512); + + if (row[27] != nullptr) + strn0cpy(tmpNPCType->special_abilities, row[27], 512); + else + strn0cpy(tmpNPCType->special_abilities,"\0", 512); tmpNPCType->d_meele_texture1 = atoi(row[28]); tmpNPCType->d_meele_texture2 = atoi(row[29]); From 193f7b0fe3336a44e757c574b2474155de9e68c5 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Mon, 20 Oct 2014 01:16:08 -0400 Subject: [PATCH 2/9] Fix so NPC don't ghost when casting spells from scripts while moving. --- zone/spells.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/zone/spells.cpp b/zone/spells.cpp index c6fb43b24..8edb7b448 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -307,6 +307,10 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot, sprintf(temp, "%d", spell_id); parse->EventNPC(EVENT_CAST_BEGIN, CastToNPC(), nullptr, temp, 0); } + + //To prevent NPC ghosting when spells are cast from scripts + if (IsNPC() && IsMoving() && cast_time > 0) + SendPosition(); if(resist_adjust) { From f0f920d0e8426df2470640ba923932d039f36b5e Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 21 Oct 2014 14:14:35 -0400 Subject: [PATCH 3/9] Fix for bug with Discipline recast timers preventing them from working properly if you used a focus effect to reduce recast time to zero. (Specifically the recast timer failed to reset in the situation where you had already used the disc WIHTOUT the focus applied, then applied the focus and tried to have it reduced). --- zone/effects.cpp | 11 ++++++++++- zone/spells.cpp | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/zone/effects.cpp b/zone/effects.cpp index 7822d2e5e..e74e8399e 100644 --- a/zone/effects.cpp +++ b/zone/effects.cpp @@ -683,8 +683,17 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) { { uint32 reduced_recast = spell.recast_time / 1000; reduced_recast -= CastToClient()->GetFocusEffect(focusReduceRecastTime, spell_id); - if(reduced_recast < 0) + if(reduced_recast <= 0){ reduced_recast = 0; + CastToClient()->GetPTimers().Clear(&database, (uint32)DiscTimer); + } + + if (reduced_recast > 0) + CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT, -1, -1, 0, -1, (uint32)DiscTimer, reduced_recast); + else{ + CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT); + return true; + } CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT, -1, -1, 0, -1, (uint32)DiscTimer, reduced_recast); if(spells[spell_id].EndurTimerIndex < MAX_DISCIPLINE_TIMERS) diff --git a/zone/spells.cpp b/zone/spells.cpp index 8edb7b448..c616f794d 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -2195,7 +2195,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 CastToClient()->GetPTimers().Start(casting_spell_timer, casting_spell_timer_duration); mlog(SPELLS__CASTING, "Spell %d: Setting custom reuse timer %d to %d", spell_id, casting_spell_timer, casting_spell_timer_duration); } - else if(spells[spell_id].recast_time > 1000) { + else if(spells[spell_id].recast_time > 1000 && !spells[spell_id].IsDisciplineBuff) { int recast = spells[spell_id].recast_time/1000; if (spell_id == SPELL_LAY_ON_HANDS) //lay on hands { From 22170527c4a61d685bae1dd0dfe9315fcae07a63 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 21 Oct 2014 14:24:25 -0400 Subject: [PATCH 4/9] Small update to prior commit. --- zone/effects.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zone/effects.cpp b/zone/effects.cpp index e74e8399e..3d8138100 100644 --- a/zone/effects.cpp +++ b/zone/effects.cpp @@ -685,7 +685,8 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) { reduced_recast -= CastToClient()->GetFocusEffect(focusReduceRecastTime, spell_id); if(reduced_recast <= 0){ reduced_recast = 0; - CastToClient()->GetPTimers().Clear(&database, (uint32)DiscTimer); + if (GetPTimers().Enabled((uint32)DiscTimer)) + GetPTimers().Clear(&database, (uint32)DiscTimer); } if (reduced_recast > 0) From 5afd6b8628111c5496f6c1500447ef64b223413f Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Fri, 24 Oct 2014 23:36:02 -0400 Subject: [PATCH 5/9] Added 'hit chance' extra attack option can be applied to future special attacks ect. --- zone/attack.cpp | 11 +++++++++-- zone/common.h | 3 ++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/zone/attack.cpp b/zone/attack.cpp index 0b8cf07f1..3d05bad70 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -1288,15 +1288,18 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b mlog(COMBAT__DAMAGE, "Damage calculated to %d (min %d, max %d, str %d, skill %d, DMG %d, lv %d)", damage, min_hit, max_hit, GetSTR(), GetSkill(skillinuse), weapon_damage, mylevel); + int hit_chance_bonus = 0; + if(opts) { damage *= opts->damage_percent; damage += opts->damage_flat; hate *= opts->hate_percent; hate += opts->hate_flat; + hit_chance_bonus += opts->hate_flat; } //check to see if we hit.. - if(!other->CheckHitChance(this, skillinuse, Hand)) { + if(!other->CheckHitChance(this, skillinuse, Hand, hit_chance_bonus)) { mlog(COMBAT__ATTACKS, "Attack missed. Damage set to 0."); damage = 0; } else { //we hit, try to avoid it @@ -1890,14 +1893,18 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool other->AddToHateList(this, hate); } else { + + int hit_chance_bonus = 0; + if(opts) { damage *= opts->damage_percent; damage += opts->damage_flat; hate *= opts->hate_percent; hate += opts->hate_flat; + hit_chance_bonus += opts->hit_chance; } - if(!other->CheckHitChance(this, skillinuse, Hand)) { + if(!other->CheckHitChance(this, skillinuse, Hand, hit_chance_bonus)) { damage = 0; //miss } else { //hit, check for damage avoidance other->AvoidDamage(this, damage); diff --git a/zone/common.h b/zone/common.h index fb56b3f01..c5a55d670 100644 --- a/zone/common.h +++ b/zone/common.h @@ -563,7 +563,7 @@ struct ExtraAttackOptions { : damage_percent(1.0f), damage_flat(0), armor_pen_percent(0.0f), armor_pen_flat(0), crit_percent(1.0f), crit_flat(0.0f), - hate_percent(1.0f), hate_flat(0) + hate_percent(1.0f), hate_flat(0), hit_chance(0) { } float damage_percent; @@ -574,6 +574,7 @@ struct ExtraAttackOptions { float crit_flat; float hate_percent; int hate_flat; + int hit_chance; }; #endif From adb817565445e1a3d5bb30fe4edec02f7524830e Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sun, 26 Oct 2014 02:05:36 -0400 Subject: [PATCH 6/9] Support for spells_new field 'viral_range' --- zone/entity.cpp | 7 +++++-- zone/entity.h | 2 +- zone/mob.cpp | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/zone/entity.cpp b/zone/entity.cpp index 0ce530419..fbccd1baa 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -4612,9 +4612,12 @@ Client *EntityList::FindCorpseDragger(uint16 CorpseID) return nullptr; } -Mob *EntityList::GetTargetForVirus(Mob *spreader) +Mob *EntityList::GetTargetForVirus(Mob *spreader, int range) { - int max_spread_range = RuleI(Spells, VirusSpreadDistance); + int max_spread_range = RuleI(Spells, VirusSpreadDistance); + + if (range) + max_spread_range = range; std::vector TargetsInRange; diff --git a/zone/entity.h b/zone/entity.h index 5776ed936..ad5de09bf 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -134,7 +134,7 @@ public: Mob *GetMob(const char* name); Mob *GetMobByNpcTypeID(uint32 get_id); bool IsMobSpawnedByNpcTypeID(uint32 get_id); - Mob *GetTargetForVirus(Mob* spreader); + Mob *GetTargetForVirus(Mob* spreader, int range); inline NPC *GetNPCByID(uint16 id) { return npc_list.count(id) ? npc_list.at(id) : nullptr; } NPC *GetNPCByNPCTypeID(uint32 npc_id); diff --git a/zone/mob.cpp b/zone/mob.cpp index 8d53d50ef..9fb113392 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -4349,7 +4349,7 @@ void Mob::SpreadVirus(uint16 spell_id, uint16 casterID) // Only spread in zones without perm buffs if(!zone->BuffTimersSuspended()) { for(int i = 0; i < num_targs; i++) { - target = entity_list.GetTargetForVirus(this); + target = entity_list.GetTargetForVirus(this, spells[spell_id].viral_range); if(target) { // Only spreads to the uninfected if(!target->FindBuff(spell_id)) { From 3247137ef2ef090621bc487636693a958bf8c24a Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Mon, 27 Oct 2014 02:20:25 -0400 Subject: [PATCH 7/9] Added swarm pet checks to viral spreading function. --- zone/entity.cpp | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/zone/entity.cpp b/zone/entity.cpp index fbccd1baa..d5354386f 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -4614,8 +4614,8 @@ Client *EntityList::FindCorpseDragger(uint16 CorpseID) Mob *EntityList::GetTargetForVirus(Mob *spreader, int range) { - int max_spread_range = RuleI(Spells, VirusSpreadDistance); - + int max_spread_range = RuleI(Spells, VirusSpreadDistance); + if (range) max_spread_range = range; @@ -4623,34 +4623,38 @@ Mob *EntityList::GetTargetForVirus(Mob *spreader, int range) auto it = mob_list.begin(); while (it != mob_list.end()) { + Mob *cur = it->second; // Make sure the target is in range, has los and is not the mob doing the spreading - if ((it->second->GetID() != spreader->GetID()) && - (it->second->CalculateDistance(spreader->GetX(), spreader->GetY(), + if ((cur->GetID() != spreader->GetID()) && + (cur->CalculateDistance(spreader->GetX(), spreader->GetY(), spreader->GetZ()) <= max_spread_range) && - (spreader->CheckLosFN(it->second))) { + (spreader->CheckLosFN(cur))) { // If the spreader is an npc it can only spread to other npc controlled mobs - if (spreader->IsNPC() && !spreader->IsPet() && it->second->IsNPC()) { - TargetsInRange.push_back(it->second); + if (spreader->IsNPC() && !spreader->IsPet() && !spreader->CastToNPC()->GetSwarmOwner() && cur->IsNPC()) { + TargetsInRange.push_back(cur); } // If the spreader is an npc controlled pet it can spread to any other npc or an npc controlled pet else if (spreader->IsNPC() && spreader->IsPet() && spreader->GetOwner()->IsNPC()) { - if (it->second->IsNPC() && !it->second->IsPet()) { - TargetsInRange.push_back(it->second); - } else if (it->second->IsNPC() && it->second->IsPet() && it->second->GetOwner()->IsNPC()) { - TargetsInRange.push_back(it->second); + if (cur->IsNPC() && !cur->IsPet()) { + TargetsInRange.push_back(cur); + } else if (cur->IsNPC() && cur->IsPet() && cur->GetOwner()->IsNPC()) { + TargetsInRange.push_back(cur); + } + else if (cur->IsNPC() && cur->CastToNPC()->GetSwarmOwner() && cur->GetOwner()->IsNPC()) { + TargetsInRange.push_back(cur); } } // if the spreader is anything else(bot, pet, etc) then it should spread to everything but non client controlled npcs - else if (!spreader->IsNPC() && !it->second->IsNPC()) { - TargetsInRange.push_back(it->second); + else if (!spreader->IsNPC() && !cur->IsNPC()) { + TargetsInRange.push_back(cur); } // if its a pet we need to determine appropriate targets(pet to client, pet to pet, pet to bot, etc) - else if (spreader->IsNPC() && spreader->IsPet() && !spreader->GetOwner()->IsNPC()) { - if (!it->second->IsNPC()) { - TargetsInRange.push_back(it->second); + else if (spreader->IsNPC() && (spreader->IsPet() || spreader->CastToNPC()->GetSwarmOwner()) && !spreader->GetOwner()->IsNPC()) { + if (!cur->IsNPC()) { + TargetsInRange.push_back(cur); } - else if (it->second->IsNPC() && it->second->IsPet() && !it->second->GetOwner()->IsNPC()) { - TargetsInRange.push_back(it->second); + else if (cur->IsNPC() && (cur->IsPet() || cur->CastToNPC()->GetSwarmOwner()) && !cur->GetOwner()->IsNPC()) { + TargetsInRange.push_back(cur); } } } From 57f8f610943d254d25497030778fecf2165f4835 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Thu, 30 Oct 2014 21:22:53 -0400 Subject: [PATCH 8/9] code optimization --- .../sql/git/required/2014_10_16_special_abilities_null.sql | 6 ++---- zone/zonedb.cpp | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/utils/sql/git/required/2014_10_16_special_abilities_null.sql b/utils/sql/git/required/2014_10_16_special_abilities_null.sql index c01bd725b..8f92a114c 100644 --- a/utils/sql/git/required/2014_10_16_special_abilities_null.sql +++ b/utils/sql/git/required/2014_10_16_special_abilities_null.sql @@ -1,6 +1,4 @@ -ALTER TABLE `merc_stats` -MODIFY COLUMN `special_abilities` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL AFTER `attack_speed`; +ALTER TABLE `merc_stats` MODIFY COLUMN `special_abilities` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL AFTER `attack_speed`; -ALTER TABLE `npc_types` -MODIFY COLUMN `special_abilities` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL AFTER `npcspecialattks`; +ALTER TABLE `npc_types` MODIFY COLUMN `special_abilities` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL AFTER `npcspecialattks`; diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 77b179a68..870e5bc62 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -1820,7 +1820,7 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) { if (row[34] != nullptr) strn0cpy(tmpNPCType->special_abilities, row[34], 512); else - strn0cpy(tmpNPCType->special_abilities,"\0", 512); + tmpNPCTYpe->special_abilities[0] = '\0'; tmpNPCType->npc_spells_id = atoi(row[35]); tmpNPCType->npc_spells_effects_id = atoi(row[36]); @@ -2027,7 +2027,7 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client if (row[27] != nullptr) strn0cpy(tmpNPCType->special_abilities, row[27], 512); else - strn0cpy(tmpNPCType->special_abilities,"\0", 512); + tmpNPCTYpe->special_abilities[0] = '\0'; tmpNPCType->d_meele_texture1 = atoi(row[28]); tmpNPCType->d_meele_texture2 = atoi(row[29]); From f84130fc7c4f644922faad1e31c72639aa742a63 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Thu, 30 Oct 2014 21:40:46 -0400 Subject: [PATCH 9/9] fix --- zone/zonedb.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 870e5bc62..2fb79029b 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -1820,7 +1820,7 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) { if (row[34] != nullptr) strn0cpy(tmpNPCType->special_abilities, row[34], 512); else - tmpNPCTYpe->special_abilities[0] = '\0'; + tmpNPCType->special_abilities[0] = '\0'; tmpNPCType->npc_spells_id = atoi(row[35]); tmpNPCType->npc_spells_effects_id = atoi(row[36]); @@ -2027,7 +2027,7 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client if (row[27] != nullptr) strn0cpy(tmpNPCType->special_abilities, row[27], 512); else - tmpNPCTYpe->special_abilities[0] = '\0'; + tmpNPCType->special_abilities[0] = '\0'; tmpNPCType->d_meele_texture1 = atoi(row[28]); tmpNPCType->d_meele_texture2 = atoi(row[29]);