diff --git a/sql/characters.sql b/sql/characters.sql index 431e6d905..2783b8e31 100644 --- a/sql/characters.sql +++ b/sql/characters.sql @@ -21,7 +21,7 @@ DROP TABLE IF EXISTS `character_db_version`; CREATE TABLE `character_db_version` ( - `required_7988_07_characters_characters` bit(1) default NULL + `required_8030_02_characters_character_action` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Last applied sql update to DB'; -- diff --git a/sql/mangos.sql b/sql/mangos.sql index 50671d4b7..3cc81adc6 100644 --- a/sql/mangos.sql +++ b/sql/mangos.sql @@ -23,7 +23,7 @@ DROP TABLE IF EXISTS `db_version`; CREATE TABLE `db_version` ( `version` varchar(120) default NULL, `creature_ai_version` varchar(120) default NULL, - `required_8021_01_mangos_spell_proc_event` bit(1) default NULL + `required_8030_03_mangos_npc_trainer` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; -- diff --git a/sql/updates/8030_01_characters_character_spell.sql b/sql/updates/8030_01_characters_character_spell.sql new file mode 100644 index 000000000..9ff2ede71 --- /dev/null +++ b/sql/updates/8030_01_characters_character_spell.sql @@ -0,0 +1,7 @@ +ALTER TABLE character_db_version CHANGE COLUMN required_7988_07_characters_characters required_8030_01_characters_character_spell bit; + +UPDATE IGNORE character_spell + SET spell = 64901 + WHERE spell = 64904; + +DELETE FROM character_spell WHERE spell = 64904; \ No newline at end of file diff --git a/sql/updates/8030_02_characters_character_action.sql b/sql/updates/8030_02_characters_character_action.sql new file mode 100644 index 000000000..bb834d015 --- /dev/null +++ b/sql/updates/8030_02_characters_character_action.sql @@ -0,0 +1,5 @@ +ALTER TABLE character_db_version CHANGE COLUMN required_8030_01_characters_character_spell required_8030_02_characters_character_action bit; + +UPDATE character_action + SET action = 64901 + WHERE action = 64904 AND type = '0'; diff --git a/sql/updates/8030_03_mangos_npc_trainer.sql b/sql/updates/8030_03_mangos_npc_trainer.sql new file mode 100644 index 000000000..bbf4e4e96 --- /dev/null +++ b/sql/updates/8030_03_mangos_npc_trainer.sql @@ -0,0 +1,2 @@ +ALTER TABLE db_version CHANGE COLUMN required_8021_01_mangos_spell_proc_event required_8030_03_mangos_npc_trainer bit; + diff --git a/sql/updates/Makefile.am b/sql/updates/Makefile.am index e04d52a63..c11a80c9e 100644 --- a/sql/updates/Makefile.am +++ b/sql/updates/Makefile.am @@ -223,6 +223,9 @@ pkgdata_DATA = \ 7988_09_mangos_spell_proc_event.sql \ 8016_01_mangos_npc_spellclick_spells.sql \ 8021_01_mangos_spell_proc_event.sql \ + 8030_01_characters_character_spell.sql \ + 8030_02_characters_character_action.sql \ + 8030_03_mangos_npc_trainer.sql \ README ## Additional files to include when running 'make dist' @@ -426,4 +429,7 @@ EXTRA_DIST = \ 7988_09_mangos_spell_proc_event.sql \ 8016_01_mangos_npc_spellclick_spells.sql \ 8021_01_mangos_spell_proc_event.sql \ + 8030_01_characters_character_spell.sql \ + 8030_02_characters_character_action.sql \ + 8030_03_mangos_npc_trainer.sql \ README diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 13547e3a8..95e65802a 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -49,30 +49,54 @@ extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS]; -class PrioritizeManaPlayerWraper +class PrioritizeManaUnitWraper { - friend struct PrioritizeMana; - public: - explicit PrioritizeManaPlayerWraper(Player* player) : player(player) + explicit PrioritizeManaUnitWraper(Unit* unit) : i_unit(unit) { - uint32 maxmana = player->GetMaxPower(POWER_MANA); - percentMana = maxmana ? player->GetPower(POWER_MANA) * 100 / maxmana : 101; + uint32 maxmana = unit->GetMaxPower(POWER_MANA); + i_percent = maxmana ? unit->GetPower(POWER_MANA) * 100 / maxmana : 101; } - Player* getPlayer() const { return player; } + Unit* getUnit() const { return i_unit; } + uint32 getPercent() const { return i_percent; } private: - Player* player; - uint32 percentMana; + Unit* i_unit; + uint32 i_percent; }; struct PrioritizeMana { - int operator()( PrioritizeManaPlayerWraper const& x, PrioritizeManaPlayerWraper const& y ) const + int operator()( PrioritizeManaUnitWraper const& x, PrioritizeManaUnitWraper const& y ) const { - return x.percentMana < y.percentMana; + return x.getPercent() < y.getPercent(); } }; +typedef std::priority_queue, PrioritizeMana> PrioritizeManaUnitQueue; + +class PrioritizeHealthUnitWraper +{ +public: + explicit PrioritizeHealthUnitWraper(Unit* unit) : i_unit(unit) + { + i_percent = unit->GetHealth() * 100 / unit->GetMaxHealth(); + } + Unit* getUnit() const { return i_unit; } + uint32 getPercent() const { return i_percent; } +private: + Unit* i_unit; + uint32 i_percent; +}; + +struct PrioritizeHealth +{ + int operator()( PrioritizeHealthUnitWraper const& x, PrioritizeHealthUnitWraper const& y ) const + { + return x.getPercent() < y.getPercent(); + } +}; + +typedef std::priority_queue, PrioritizeHealth> PrioritizeHealthUnitQueue; bool IsQuestTameSpell(uint32 spellId) { @@ -1664,139 +1688,16 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,UnitList& TagUnitMap) case TARGET_ALL_PARTY_AROUND_CASTER: case TARGET_ALL_PARTY_AROUND_CASTER_2: case TARGET_ALL_PARTY: - { - Player *pTarget = m_caster->GetCharmerOrOwnerPlayerOrPlayerItself(); - Group *pGroup = pTarget ? pTarget->GetGroup() : NULL; - - if(pGroup) - { - uint8 subgroup = pTarget->GetSubGroup(); - - for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* Target = itr->getSource(); - - // IsHostileTo check duel and controlled by enemy - if( Target && Target->GetSubGroup()==subgroup && !m_caster->IsHostileTo(Target) ) - { - if( m_caster->IsWithinDistInMap(Target, radius) ) - TagUnitMap.push_back(Target); - - if(Pet* pet = Target->GetPet()) - if( m_caster->IsWithinDistInMap(pet, radius) ) - TagUnitMap.push_back(pet); - } - } - } - else - { - Unit* ownerOrSelf = pTarget ? pTarget : m_caster->GetCharmerOrOwnerOrSelf(); - if(ownerOrSelf==m_caster || m_caster->IsWithinDistInMap(ownerOrSelf, radius)) - TagUnitMap.push_back(ownerOrSelf); - if(Pet* pet = ownerOrSelf->GetPet()) - if( m_caster->IsWithinDistInMap(pet, radius) ) - TagUnitMap.push_back(pet); - } + FillRaidOrPartyTargets(TagUnitMap,m_caster,radius,false,true,true); break; - } case TARGET_ALL_RAID_AROUND_CASTER: { - Player *pTarget = m_caster->GetCharmerOrOwnerPlayerOrPlayerItself(); - Group *pGroup = pTarget ? pTarget->GetGroup() : NULL; - if(m_spellInfo->Id == 57669) // Replenishment (special target selection) - { - if(pGroup) - { - typedef std::priority_queue, PrioritizeMana> Top10; - Top10 manaUsers; - - for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL && manaUsers.size() < 10; itr = itr->next()) - { - Player* Target = itr->getSource(); - if (m_caster->GetGUID() != Target->GetGUID() && Target->getPowerType() == POWER_MANA && - !Target->isDead() && m_caster->IsWithinDistInMap(Target, radius)) - { - PrioritizeManaPlayerWraper WTarget(Target); - manaUsers.push(WTarget); - } - } - - while(!manaUsers.empty()) - { - TagUnitMap.push_back(manaUsers.top().getPlayer()); - manaUsers.pop(); - } - } - else - { - Unit* ownerOrSelf = pTarget ? pTarget : m_caster->GetCharmerOrOwnerOrSelf(); - if ((ownerOrSelf==m_caster || m_caster->IsWithinDistInMap(ownerOrSelf, radius)) && - ownerOrSelf->getPowerType() == POWER_MANA) - TagUnitMap.push_back(ownerOrSelf); - - if(Pet* pet = ownerOrSelf->GetPet()) - if( m_caster->IsWithinDistInMap(pet, radius) && pet->getPowerType() == POWER_MANA ) - TagUnitMap.push_back(pet); - } - } - if (m_spellInfo->Id==52759) //Ancestral Awakening (special target selection) - { - float lowestPerc = (float)m_caster->GetHealth() / (float)m_caster->GetMaxHealth(); - Unit* lowestTarget = m_caster; - - if (pGroup) - { - Group::MemberSlotList const& members = pGroup->GetMemberSlots(); - Group::MemberSlotList::const_iterator itr = members.begin(); - for(; itr != members.end(); ++itr) - { - if (Unit* member = ObjectAccessor::GetPlayer(*m_caster, (*itr).guid)) - { - if (member == m_caster || member->isDead() || m_caster->IsHostileTo(member) || !m_caster->IsWithinDistInMap(member, radius)) - continue; - - float perc = (float)member->GetHealth() / (float)member->GetMaxHealth(); - if (perc <= lowestPerc) - { - lowestPerc = perc; - lowestTarget = member; - } - } - } - } - TagUnitMap.push_back(lowestTarget); - } + FillRaidOrPartyManaPriorityTargets(TagUnitMap, m_caster, radius, 10, true, false, false); + else if (m_spellInfo->Id==52759) //Ancestral Awakening (special target selection) + FillRaidOrPartyHealthPriorityTargets(TagUnitMap, m_caster, radius, 1, true, false, false); else - { - if(pGroup) - { - for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* Target = itr->getSource(); - - // IsHostileTo check duel and controlled by enemy - if( Target && !m_caster->IsHostileTo(Target) ) - { - if( m_caster->IsWithinDistInMap(Target, radius) ) - TagUnitMap.push_back(Target); - - if(Pet* pet = Target->GetPet()) - if( m_caster->IsWithinDistInMap(pet, radius) ) - TagUnitMap.push_back(pet); - } - } - } - else - { - Unit* ownerOrSelf = pTarget ? pTarget : m_caster->GetCharmerOrOwnerOrSelf(); - if(ownerOrSelf==m_caster || m_caster->IsWithinDistInMap(ownerOrSelf, radius)) - TagUnitMap.push_back(ownerOrSelf); - if(Pet* pet = ownerOrSelf->GetPet()) - if( m_caster->IsWithinDistInMap(pet, radius) ) - TagUnitMap.push_back(pet); - } - } + FillRaidOrPartyTargets(TagUnitMap, m_caster, radius, true, true, true); break; } case TARGET_SINGLE_FRIEND: @@ -1823,7 +1724,12 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,UnitList& TagUnitMap) m_targets.setDestination(caster->GetPositionX(), caster->GetPositionY(), caster->GetPositionZ()); }break; case TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER: - FillAreaTargets(TagUnitMap, m_targets.m_destX, m_targets.m_destY, radius, PUSH_SELF_CENTER, SPELL_TARGETS_FRIENDLY); + // special target order + if (m_spellInfo->Id==64904) // Hymn of Hope + // target amount stored in parent spell dummy effect but hard for access + FillRaidOrPartyManaPriorityTargets(TagUnitMap, m_caster, radius, 3, true, false, false); + else + FillAreaTargets(TagUnitMap, m_targets.m_destX, m_targets.m_destY, radius, PUSH_SELF_CENTER, SPELL_TARGETS_FRIENDLY); break; case TARGET_ALL_FRIENDLY_UNITS_IN_AREA: FillAreaTargets(TagUnitMap, m_targets.m_destX, m_targets.m_destY, radius, PUSH_DEST_CENTER, SPELL_TARGETS_FRIENDLY); @@ -5729,3 +5635,81 @@ void Spell::FillAreaTargets( UnitList& TagUnitMap, float x, float y, float radiu cell_lock->Visit(cell_lock, world_notifier, *m_caster->GetMap()); cell_lock->Visit(cell_lock, grid_notifier, *m_caster->GetMap()); } + +void Spell::FillRaidOrPartyTargets( UnitList &TagUnitMap, Unit* target, float radius, bool raid, bool withPets, bool withcaster ) +{ + Player *pTarget = target->GetCharmerOrOwnerPlayerOrPlayerItself(); + Group *pGroup = pTarget ? pTarget->GetGroup() : NULL; + + if (pGroup) + { + uint8 subgroup = pTarget->GetSubGroup(); + + for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* Target = itr->getSource(); + + // IsHostileTo check duel and controlled by enemy + if (Target && (raid || subgroup==Target->GetSubGroup()) + && !m_caster->IsHostileTo(Target)) + { + if (Target==m_caster && withcaster || + Target!=m_caster && m_caster->IsWithinDistInMap(Target, radius)) + TagUnitMap.push_back(Target); + + if (withPets) + if (Pet* pet = Target->GetPet()) + if (pet==m_caster && withcaster || + pet!=m_caster && m_caster->IsWithinDistInMap(pet, radius)) + TagUnitMap.push_back(pet); + } + } + } + else + { + Unit* ownerOrSelf = pTarget ? pTarget : target->GetCharmerOrOwnerOrSelf(); + if (ownerOrSelf==m_caster && withcaster || + ownerOrSelf!=m_caster && m_caster->IsWithinDistInMap(ownerOrSelf, radius)) + TagUnitMap.push_back(ownerOrSelf); + + if (withPets) + if (Pet* pet = ownerOrSelf->GetPet()) + if (pet==m_caster && withcaster || + pet!=m_caster && m_caster->IsWithinDistInMap(pet, radius)) + TagUnitMap.push_back(pet); + } +} + +void Spell::FillRaidOrPartyManaPriorityTargets( UnitList &TagUnitMap, Unit* target, float radius, uint32 count, bool raid, bool withPets, bool withCaster ) +{ + FillRaidOrPartyTargets(TagUnitMap,target,radius,raid,withPets,withCaster); + + PrioritizeManaUnitQueue manaUsers; + for(UnitList::const_iterator itr = TagUnitMap.begin(); itr != TagUnitMap.end() && manaUsers.size() < count; ++itr) + if ((*itr)->getPowerType() == POWER_MANA && !(*itr)->isDead()) + manaUsers.push(PrioritizeManaUnitWraper(*itr)); + + TagUnitMap.clear(); + while(!manaUsers.empty()) + { + TagUnitMap.push_back(manaUsers.top().getUnit()); + manaUsers.pop(); + } +} + +void Spell::FillRaidOrPartyHealthPriorityTargets( UnitList &TagUnitMap, Unit* target, float radius, uint32 count, bool raid, bool withPets, bool withCaster ) +{ + FillRaidOrPartyTargets(TagUnitMap,target,radius,raid,withPets,withCaster); + + PrioritizeHealthUnitQueue healthQueue; + for(UnitList::const_iterator itr = TagUnitMap.begin(); itr != TagUnitMap.end() && healthQueue.size() < count; ++itr) + if (!(*itr)->isDead()) + healthQueue.push(PrioritizeHealthUnitWraper(*itr)); + + TagUnitMap.clear(); + while(!healthQueue.empty()) + { + TagUnitMap.push_back(healthQueue.top().getUnit()); + healthQueue.pop(); + } +} \ No newline at end of file diff --git a/src/game/Spell.h b/src/game/Spell.h index 90c8983dc..0e497dfa9 100644 --- a/src/game/Spell.h +++ b/src/game/Spell.h @@ -366,7 +366,11 @@ class Spell typedef std::list UnitList; void FillTargetMap(); void SetTargetMap(uint32 i,uint32 cur,UnitList& TagUnitMap); + void FillAreaTargets( UnitList& TagUnitMap, float x, float y, float radius, SpellNotifyPushType pushType, SpellTargets spellTargets ); + void FillRaidOrPartyTargets( UnitList &TagUnitMap, Unit* target, float radius, bool raid, bool withPets, bool withcaster ); + void FillRaidOrPartyManaPriorityTargets( UnitList &TagUnitMap, Unit* target, float radius, uint32 count, bool raid, bool withPets, bool withcaster ); + void FillRaidOrPartyHealthPriorityTargets( UnitList &TagUnitMap, Unit* target, float radius, uint32 count, bool raid, bool withPets, bool withcaster ); template WorldObject* FindCorpseUsing(); diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index 631af68d2..3c01c22aa 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -4789,7 +4789,7 @@ void Aura::HandleAuraModIncreaseMaxHealth(bool apply, bool /*Real*/) } } -void Aura::HandleAuraModIncreaseEnergy(bool apply, bool /*Real*/) +void Aura::HandleAuraModIncreaseEnergy(bool apply, bool Real) { Powers powerType = m_target->getPowerType(); if(int32(powerType) != m_modifier.m_miscvalue) @@ -4797,6 +4797,19 @@ void Aura::HandleAuraModIncreaseEnergy(bool apply, bool /*Real*/) UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + powerType); + // Special case with temporary increase max/current power (percent) + if (GetId()==64904) // Hymn of Hope + { + if(Real) + { + uint32 val = m_target->GetPower(powerType); + m_target->HandleStatModifier(unitMod, TOTAL_PCT, float(m_modifier.m_amount), apply); + m_target->SetPower(powerType, apply ? val*(100+m_modifier.m_amount)/100 : val*100/(100+m_modifier.m_amount)); + } + return; + } + + // generic flat case m_target->HandleStatModifier(unitMod, TOTAL_VALUE, float(m_modifier.m_amount), apply); } diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 325399255..453d94f96 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "8029" + #define REVISION_NR "8030" #endif // __REVISION_NR_H__