50 plus cmangos updates implemented (to c12832)

Implemented over 50 updates from the cmangos Cata repo, up to and
including c12832 Improve random movement

The core will now work with the creature_template update that was
applied to the database yesterday.
This commit is contained in:
Charles A Edwards 2016-08-16 11:58:07 +01:00 committed by Antz
parent 12f8fbf37d
commit e4d1bdfc74
80 changed files with 3164 additions and 2965 deletions

View file

@ -846,8 +846,24 @@ void WorldSession::BuildListAuctionItems(std::vector<AuctionEntry*> const& aucti
if (levelmin != 0x00 && (proto->RequiredLevel < levelmin || (levelmax != 0x00 && proto->RequiredLevel > levelmax)))
continue;
if (usable != 0x00 && _player->CanUseItem(item) != EQUIP_ERR_OK)
continue;
if (usable != 0x00)
{
if (_player->CanUseItem(item) != EQUIP_ERR_OK)
continue;
if (proto->Class == ITEM_CLASS_RECIPE)
{
if (SpellEntry const* spell = sSpellStore.LookupEntry(proto->Spells[0].SpellId))
{
SpellEffectEntry const* spellEff = spell->GetSpellEffect(EFFECT_INDEX_0);
if (!spellEff)
continue;
if (_player->HasSpell(spellEff->EffectTriggerSpell))
continue;
}
}
}
std::string name = proto->Name1;
sObjectMgr.GetItemLocaleStrings(proto->ItemId, loc_idx, &name);

View file

@ -165,7 +165,7 @@ Creature::Creature(CreatureSubtype subtype) : Unit(),
lootForPickPocketed(false), lootForBody(false), lootForSkin(false),
m_groupLootTimer(0), m_groupLootId(0),
m_lootMoney(0), m_lootGroupRecipientId(0),
m_corpseDecayTimer(0), m_respawnTime(0), m_respawnDelay(25), m_corpseDelay(60), m_respawnradius(5.0f),
m_corpseDecayTimer(0), m_respawnTime(0), m_respawnDelay(25), m_corpseDelay(60), m_aggroDelay(0), m_respawnradius(5.0f),
m_subtype(subtype), m_defaultMovementType(IDLE_MOTION_TYPE), m_equipmentId(0),
m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false),
m_regenHealth(true), m_AI_locked(false), m_IsDeadByDefault(false),
@ -310,7 +310,7 @@ bool Creature::InitEntry(uint32 Entry, CreatureData const* data /*=NULL*/, GameE
SetByteValue(UNIT_FIELD_BYTES_0, 0, 0);
// known valid are: CLASS_WARRIOR,CLASS_PALADIN,CLASS_ROGUE,CLASS_MAGE
SetByteValue(UNIT_FIELD_BYTES_0, 1, uint8(cinfo->unit_class));
SetByteValue(UNIT_FIELD_BYTES_0, 1, uint8(cinfo->UnitClass));
uint32 display_id = ChooseDisplayId(GetCreatureInfo(), data, eventData);
if (!display_id) // Cancel load if no display id
@ -374,28 +374,26 @@ bool Creature::UpdateEntry(uint32 Entry, Team team, const CreatureData* data /*=
if (!InitEntry(Entry, data, eventData))
return false;
m_regenHealth = GetCreatureInfo()->RegenHealth;
// creatures always have melee weapon ready if any
SetSheath(SHEATH_STATE_MELEE);
SelectLevel(GetCreatureInfo(), preserveHPAndPower ? GetHealthPercent() : 100.0f, 100.0f);
SelectLevel(GetCreatureInfo(), preserveHPAndPower ? GetHealthPercent() : 100.0f);
if (team == HORDE)
setFaction(GetCreatureInfo()->FactionHorde);
else
setFaction(GetCreatureInfo()->FactionAlliance);
SetUInt32Value(UNIT_NPC_FLAGS, GetCreatureInfo()->npcflag);
SetUInt32Value(UNIT_NPC_FLAGS, GetCreatureInfo()->NpcFlags);
uint32 attackTimer = GetCreatureInfo()->baseattacktime;
uint32 attackTimer = GetCreatureInfo()->MeleeBaseAttackTime;
SetAttackTime(BASE_ATTACK, attackTimer);
SetAttackTime(OFF_ATTACK, attackTimer - attackTimer / 4);
SetAttackTime(RANGED_ATTACK, GetCreatureInfo()->rangeattacktime);
SetAttackTime(RANGED_ATTACK, GetCreatureInfo()->RangedBaseAttackTime);
uint32 unitFlags = GetCreatureInfo()->unit_flags;
uint32 unitFlags2 = GetCreatureInfo()->unit_flags2;
uint32 unitFlags = GetCreatureInfo()->UnitFlags;
uint32 unitFlags2 = GetCreatureInfo()->UnitFlags2;
// we may need to append or remove additional flags
if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT))
@ -406,15 +404,15 @@ bool Creature::UpdateEntry(uint32 Entry, Team team, const CreatureData* data /*=
// preserve all current dynamic flags if exist
uint32 dynFlags = GetUInt32Value(UNIT_DYNAMIC_FLAGS);
SetUInt32Value(UNIT_DYNAMIC_FLAGS, dynFlags ? dynFlags : GetCreatureInfo()->dynamicflags);
SetUInt32Value(UNIT_DYNAMIC_FLAGS, dynFlags ? dynFlags : GetCreatureInfo()->DynamicFlags);
SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(GetCreatureInfo()->armor));
SetModifierValue(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(GetCreatureInfo()->resistance1));
SetModifierValue(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(GetCreatureInfo()->resistance2));
SetModifierValue(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(GetCreatureInfo()->resistance3));
SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(GetCreatureInfo()->resistance4));
SetModifierValue(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(GetCreatureInfo()->resistance5));
SetModifierValue(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(GetCreatureInfo()->resistance6));
SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(GetCreatureInfo()->Armor));
SetModifierValue(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(GetCreatureInfo()->ResistanceHoly));
SetModifierValue(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(GetCreatureInfo()->ResistanceFire));
SetModifierValue(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(GetCreatureInfo()->ResistanceNature));
SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(GetCreatureInfo()->ResistanceFrost));
SetModifierValue(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(GetCreatureInfo()->ResistanceShadow));
SetModifierValue(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(GetCreatureInfo()->ResistanceArcane));
SetCanModifyStats(true);
UpdateAllStats();
@ -518,6 +516,7 @@ void Creature::Update(uint32 update_diff, uint32 diff)
{
DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "Respawning...");
m_respawnTime = 0;
m_aggroDelay = sWorld.getConfig(CONFIG_UINT32_CREATURE_RESPAWN_AGGRO_DELAY);
lootForPickPocketed = false;
lootForBody = false;
lootForSkin = false;
@ -535,6 +534,7 @@ void Creature::Update(uint32 update_diff, uint32 diff)
CreatureInfo const* cinfo = GetCreatureInfo();
SelectLevel(cinfo);
UpdateAllStats(); // to be sure stats is correct regarding level of the creature
SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_NONE);
if (m_IsDeadByDefault)
{
@ -584,6 +584,11 @@ void Creature::Update(uint32 update_diff, uint32 diff)
}
case ALIVE:
{
if (m_aggroDelay <= update_diff)
m_aggroDelay = 0;
else
m_aggroDelay -= update_diff;
if (m_IsDeadByDefault)
{
if (m_corpseDecayTimer <= update_diff)
@ -819,7 +824,7 @@ bool Creature::IsTrainerOf(Player* pPlayer, bool msg) const
return false;
// pet trainers not have spells in fact now
if (GetCreatureInfo()->trainer_type != TRAINER_TYPE_PETS)
if (GetCreatureInfo()->TrainerType != TRAINER_TYPE_PETS)
{
TrainerSpellData const* cSpells = GetTrainerSpells();
TrainerSpellData const* tSpells = GetTrainerTemplateSpells();
@ -833,15 +838,15 @@ bool Creature::IsTrainerOf(Player* pPlayer, bool msg) const
}
}
switch (GetCreatureInfo()->trainer_type)
switch (GetCreatureInfo()->TrainerType)
{
case TRAINER_TYPE_CLASS:
if (pPlayer->getClass() != GetCreatureInfo()->trainer_class)
if (pPlayer->getClass() != GetCreatureInfo()->TrainerClass)
{
if (msg)
{
pPlayer->PlayerTalkClass->ClearMenus();
switch (GetCreatureInfo()->trainer_class)
switch (GetCreatureInfo()->TrainerClass)
{
case CLASS_DRUID: pPlayer->PlayerTalkClass->SendGossipMenu(4913, GetObjectGuid()); break;
case CLASS_HUNTER: pPlayer->PlayerTalkClass->SendGossipMenu(10090, GetObjectGuid()); break;
@ -869,7 +874,7 @@ bool Creature::IsTrainerOf(Player* pPlayer, bool msg) const
}
break;
case TRAINER_TYPE_MOUNTS:
if (GetCreatureInfo()->trainer_race && pPlayer->getRace() != GetCreatureInfo()->trainer_race)
if (GetCreatureInfo()->TrainerRace && pPlayer->getRace() != GetCreatureInfo()->TrainerRace)
{
// Allowed to train if exalted
if (FactionTemplateEntry const* faction_template = getFactionTemplateEntry())
@ -881,7 +886,7 @@ bool Creature::IsTrainerOf(Player* pPlayer, bool msg) const
if (msg)
{
pPlayer->PlayerTalkClass->ClearMenus();
switch (GetCreatureInfo()->trainer_class)
switch (GetCreatureInfo()->TrainerClass)
{
case RACE_DWARF: pPlayer->PlayerTalkClass->SendGossipMenu(5865, GetObjectGuid()); break;
case RACE_GNOME: pPlayer->PlayerTalkClass->SendGossipMenu(4881, GetObjectGuid()); break;
@ -899,7 +904,7 @@ bool Creature::IsTrainerOf(Player* pPlayer, bool msg) const
}
break;
case TRAINER_TYPE_TRADESKILLS:
if (GetCreatureInfo()->trainer_spell && !pPlayer->HasSpell(GetCreatureInfo()->trainer_spell))
if (GetCreatureInfo()->TrainerSpell && !pPlayer->HasSpell(GetCreatureInfo()->TrainerSpell))
{
if (msg)
{
@ -953,8 +958,8 @@ bool Creature::CanInteractWithBattleMaster(Player* pPlayer, bool msg) const
bool Creature::CanTrainAndResetTalentsOf(Player* pPlayer) const
{
return pPlayer->getLevel() >= 10
&& GetCreatureInfo()->trainer_type == TRAINER_TYPE_CLASS
&& pPlayer->getClass() == GetCreatureInfo()->trainer_class;
&& GetCreatureInfo()->TrainerType == TRAINER_TYPE_CLASS
&& pPlayer->getClass() == GetCreatureInfo()->TrainerType;
}
void Creature::PrepareBodyLootState()
@ -965,9 +970,9 @@ void Creature::PrepareBodyLootState()
if (!lootForBody)
{
// have normal loot
if (GetCreatureInfo()->maxgold > 0 || GetCreatureInfo()->lootid ||
if (GetCreatureInfo()->MaxLootGold > 0 || GetCreatureInfo()->LootId ||
// ... or can have skinning after
(GetCreatureInfo()->SkinLootId && sWorld.getConfig(CONFIG_BOOL_CORPSE_EMPTY_LOOT_SHOW)))
(GetCreatureInfo()->SkinningLootId && sWorld.getConfig(CONFIG_BOOL_CORPSE_EMPTY_LOOT_SHOW)))
{
SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
return;
@ -977,7 +982,7 @@ void Creature::PrepareBodyLootState()
lootForBody = true; // pass this loot mode
// if not have normal loot allow skinning if need
if (!lootForSkin && GetCreatureInfo()->SkinLootId)
if (!lootForSkin && GetCreatureInfo()->SkinningLootId)
{
RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
@ -1162,25 +1167,59 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
WorldDatabase.CommitTransaction();
}
void Creature::SelectLevel(const CreatureInfo* cinfo, float percentHealth, float percentMana)
void Creature::SelectLevel(const CreatureInfo* cinfo, float percentHealth /*= 100.0f*/)
{
uint32 rank = IsPet() ? 0 : cinfo->Rank;
uint32 rank = IsPet() ? 0 : cinfo->Rank; // TODO :: IsPet probably not needed here
// level
uint32 minlevel = std::min(cinfo->maxlevel, cinfo->minlevel);
uint32 maxlevel = std::max(cinfo->maxlevel, cinfo->minlevel);
uint32 const minlevel = cinfo->MinLevel;
uint32 const maxlevel = cinfo->MaxLevel;
uint32 level = minlevel == maxlevel ? minlevel : urand(minlevel, maxlevel);
SetLevel(level);
float rellevel = maxlevel == minlevel ? 0 : (float(level - minlevel)) / (maxlevel - minlevel);
//////////////////////////////////////////////////////////////////////////
// Calculate level dependend stats
//////////////////////////////////////////////////////////////////////////
uint32 health;
uint32 mana;
if (CreatureClassLvlStats const* cCLS = sObjectMgr.GetCreatureClassLvlStats(level, cinfo->UnitClass, cinfo->Expansion))
{
// Use Creature Stats to calculate stat values
// health
health = cCLS->BaseHealth * cinfo->HealthMultiplier;
// mana
mana = cCLS->BaseMana * cinfo->PowerMultiplier;
}
else
{
// Use old style to calculate stat values
float rellevel = maxlevel == minlevel ? 0 : (float(level - minlevel)) / (maxlevel - minlevel);
// health
uint32 minhealth = std::min(cinfo->MaxLevelHealth, cinfo->MinLevelHealth);
uint32 maxhealth = std::max(cinfo->MaxLevelHealth, cinfo->MinLevelHealth);
health = uint32(minhealth + uint32(rellevel * (maxhealth - minhealth)));
// mana
uint32 minmana = std::min(cinfo->MaxLevelMana, cinfo->MinLevelMana);
uint32 maxmana = std::max(cinfo->MaxLevelMana, cinfo->MinLevelMana);
mana = minmana + uint32(rellevel * (maxmana - minmana));
}
health *= _GetHealthMod(rank); // Apply custom config settting
if (health < 1)
health = 1;
//////////////////////////////////////////////////////////////////////////
// Set values
//////////////////////////////////////////////////////////////////////////
// health
float healthmod = _GetHealthMod(rank);
uint32 minhealth = std::min(cinfo->maxhealth, cinfo->minhealth);
uint32 maxhealth = std::max(cinfo->maxhealth, cinfo->minhealth);
uint32 health = uint32(healthmod * (minhealth + uint32(rellevel * (maxhealth - minhealth))));
SetCreateHealth(health);
SetMaxHealth(health);
@ -1189,33 +1228,51 @@ void Creature::SelectLevel(const CreatureInfo* cinfo, float percentHealth, float
else
SetHealthPercent(percentHealth);
// mana
uint32 minmana = std::min(cinfo->maxmana, cinfo->minmana);
uint32 maxmana = std::max(cinfo->maxmana, cinfo->minmana);
uint32 mana = minmana + uint32(rellevel * (maxmana - minmana));
SetCreateMana(mana);
SetMaxPower(POWER_MANA, mana); // MAX Mana
SetPower(POWER_MANA, mana);
// TODO: set UNIT_FIELD_POWER*, for some creature class case (energy, etc)
SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, float(health));
SetModifierValue(UNIT_MOD_MANA, BASE_VALUE, float(mana));
// all power types
for (int i = POWER_MANA; i <= POWER_RUNIC_POWER; ++i)
{
uint32 maxValue = 0;
switch (i)
{
case POWER_MANA: maxValue = mana; break;
case POWER_RAGE: maxValue = 0; break;
case POWER_FOCUS: maxValue = POWER_FOCUS_DEFAULT; break;
case POWER_ENERGY: maxValue = POWER_ENERGY_DEFAULT * cinfo->PowerMultiplier; break;
case POWER_RUNE: maxValue = 0; break;
case POWER_RUNIC_POWER: maxValue = 0; break;
}
uint32 value = maxValue;
// For non regenerating powers set 0
if ((i == POWER_ENERGY || i == POWER_MANA) && !IsRegeneratingPower())
value = 0;
// Mana requires an extra field to be set
if (i == POWER_MANA)
SetCreateMana(value);
SetMaxPower(Powers(i), maxValue);
SetPower(Powers(i), value);
SetModifierValue(UnitMods(UNIT_MOD_POWER_START + i), BASE_VALUE, float(value));
}
// damage
float damagemod = _GetDamageMod(rank);
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, cinfo->mindmg * damagemod);
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, cinfo->maxdmg * damagemod);
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, cinfo->MinMeleeDmg * damagemod);
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, cinfo->MaxMeleeDmg * damagemod);
SetBaseWeaponDamage(OFF_ATTACK, MINDAMAGE, cinfo->mindmg * damagemod);
SetBaseWeaponDamage(OFF_ATTACK, MAXDAMAGE, cinfo->maxdmg * damagemod);
SetBaseWeaponDamage(OFF_ATTACK, MINDAMAGE, cinfo->MinMeleeDmg * damagemod);
SetBaseWeaponDamage(OFF_ATTACK, MAXDAMAGE, cinfo->MaxMeleeDmg * damagemod);
SetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, cinfo->minrangedmg * damagemod);
SetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, cinfo->maxrangedmg * damagemod);
SetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, cinfo->MinRangedDmg * damagemod);
SetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, cinfo->MaxRangedDmg * damagemod);
SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, cinfo->attackpower * damagemod);
SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, cinfo->MeleeAttackPower * damagemod);
}
float Creature::_GetHealthMod(int32 Rank)
@ -1370,7 +1427,7 @@ bool Creature::LoadFromDB(uint32 guidlow, Map* map)
SetHealth(m_deathState == ALIVE ? curhealth : 0);
SetPower(POWER_MANA, data->curmana);
SetMeleeDamageSchool(SpellSchools(GetCreatureInfo()->dmgschool));
SetMeleeDamageSchool(SpellSchools(GetCreatureInfo()->DamageSchool));
// checked at creature_template loading
m_defaultMovementType = MovementGeneratorType(data->movementType);
@ -1561,7 +1618,7 @@ void Creature::SetDeathState(DeathState s)
if (GetTemporaryFactionFlags() & TEMPFACTION_RESTORE_RESPAWN)
ClearTemporaryFaction();
SetMeleeDamageSchool(SpellSchools(GetCreatureInfo()->dmgschool));
SetMeleeDamageSchool(SpellSchools(GetCreatureInfo()->DamageSchool));
// Dynamic flags may be adjusted by spells. Clear them
// first and let spell from *addon apply where needed.
@ -1570,7 +1627,7 @@ void Creature::SetDeathState(DeathState s)
// Flags after LoadCreatureAddon. Any spell in *addon
// will not be able to adjust these.
SetUInt32Value(UNIT_NPC_FLAGS, GetCreatureInfo()->npcflag);
SetUInt32Value(UNIT_NPC_FLAGS, GetCreatureInfo()->NpcFlags);
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
SetWalk(true, true);
@ -1634,7 +1691,7 @@ bool Creature::IsImmuneToSpellEffect(SpellEntry const* spellInfo, SpellEffectInd
return true;
// Taunt immunity special flag check
if (GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_NOT_TAUNTABLE)
if (GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NOT_TAUNTABLE)
{
// Taunt aura apply check
if (spellEffect->Effect == SPELL_EFFECT_APPLY_AURA)
@ -1775,7 +1832,7 @@ bool Creature::IsVisibleInGridForPlayer(Player* pl) const
if (pl->isGameMaster())
return true;
if (GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_INVISIBLE)
if (GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_INVISIBLE)
return false;
// Live player (or with not release body see live creatures or death creatures with corpse disappearing time > 0
@ -1822,6 +1879,10 @@ void Creature::CallAssistance()
if (!m_AlreadyCallAssistance && getVictim() && !IsCharmed())
{
SetNoCallAssistance(true);
if (GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_CALL_ASSIST)
return;
AI()->SendAIEventAround(AI_EVENT_CALL_ASSISTANCE, getVictim(), sWorld.getConfig(CONFIG_UINT32_CREATURE_FAMILY_ASSISTANCE_DELAY), sWorld.getConfig(CONFIG_FLOAT_CREATURE_FAMILY_ASSISTANCE_RADIUS));
}
}
@ -1888,6 +1949,12 @@ bool Creature::CanInitiateAttack()
if (isPassiveToHostile())
return false;
if (m_aggroDelay != 0)
return false;
if (!CanAttackByItself())
return false;
return true;
}
@ -2350,8 +2417,8 @@ VendorItemData const* Creature::GetVendorItems() const
VendorItemData const* Creature::GetVendorTemplateItems() const
{
uint32 vendorId = GetCreatureInfo()->vendorId;
return vendorId ? sObjectMgr.GetNpcVendorTemplateItemList(vendorId) : NULL;
uint32 VendorTemplateId = GetCreatureInfo()->VendorTemplateId;
return VendorTemplateId ? sObjectMgr.GetNpcVendorTemplateItemList(VendorTemplateId) : NULL;
}
uint32 Creature::GetVendorItemCurrentCount(VendorItem const* vItem)
@ -2428,8 +2495,8 @@ uint32 Creature::UpdateVendorItemCurrentCount(VendorItem const* vItem, uint32 us
TrainerSpellData const* Creature::GetTrainerTemplateSpells() const
{
uint32 trainerId = GetCreatureInfo()->trainerId;
return trainerId ? sObjectMgr.GetNpcTrainerTemplateSpells(trainerId) : NULL;
uint32 TrainerTemplateId = GetCreatureInfo()->TrainerTemplateId;
return TrainerTemplateId ? sObjectMgr.GetNpcTrainerTemplateSpells(TrainerTemplateId) : NULL;
}
TrainerSpellData const* Creature::GetTrainerSpells() const
@ -2469,11 +2536,11 @@ void Creature::ClearTemporaryFaction()
// Reset to original faction
setFaction(GetCreatureInfo()->FactionAlliance);
// Reset UNIT_FLAG_NON_ATTACKABLE, UNIT_FLAG_OOC_NOT_ATTACKABLE or UNIT_FLAG_PASSIVE flags
if (m_temporaryFactionFlags & TEMPFACTION_TOGGLE_NON_ATTACKABLE && GetCreatureInfo()->unit_flags & UNIT_FLAG_NON_ATTACKABLE)
if (m_temporaryFactionFlags & TEMPFACTION_TOGGLE_NON_ATTACKABLE && GetCreatureInfo()->UnitFlags & UNIT_FLAG_NON_ATTACKABLE)
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
if (m_temporaryFactionFlags & TEMPFACTION_TOGGLE_OOC_NOT_ATTACK && GetCreatureInfo()->unit_flags & UNIT_FLAG_OOC_NOT_ATTACKABLE && !IsInCombat())
if (m_temporaryFactionFlags & TEMPFACTION_TOGGLE_OOC_NOT_ATTACK && GetCreatureInfo()->UnitFlags & UNIT_FLAG_OOC_NOT_ATTACKABLE && !IsInCombat())
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE);
if (m_temporaryFactionFlags & TEMPFACTION_TOGGLE_PASSIVE && GetCreatureInfo()->unit_flags & UNIT_FLAG_PASSIVE)
if (m_temporaryFactionFlags & TEMPFACTION_TOGGLE_PASSIVE && GetCreatureInfo()->UnitFlags & UNIT_FLAG_PASSIVE)
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE);
m_temporaryFactionFlags = TEMPFACTION_NONE;

View file

@ -49,17 +49,23 @@ struct GameEventCreatureData;
enum CreatureFlagsExtra
{
CREATURE_FLAG_EXTRA_INSTANCE_BIND = 0x00000001, // creature kill bind instance with killer and killer's group
CREATURE_FLAG_EXTRA_CIVILIAN = 0x00000002, // not aggro (ignore faction/reputation hostility)
CREATURE_FLAG_EXTRA_NO_PARRY = 0x00000004, // creature can't parry
CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN = 0x00000008, // creature can't counter-attack at parry
CREATURE_FLAG_EXTRA_NO_BLOCK = 0x00000010, // creature can't block
CREATURE_FLAG_EXTRA_NO_CRUSH = 0x00000020, // creature can't do crush attacks
CREATURE_FLAG_EXTRA_NO_XP_AT_KILL = 0x00000040, // creature kill not provide XP
CREATURE_FLAG_EXTRA_INVISIBLE = 0x00000080, // creature is always invisible for player (mostly trigger creatures)
CREATURE_FLAG_EXTRA_NOT_TAUNTABLE = 0x00000100, // creature is immune to taunt auras and effect attack me
CREATURE_FLAG_EXTRA_AGGRO_ZONE = 0x00000200, // creature sets itself in combat with zone on aggro
CREATURE_FLAG_EXTRA_GUARD = 0x00000400, // creature is a guard
CREATURE_EXTRA_FLAG_INSTANCE_BIND = 0x00000001, // creature kill bind instance with killer and killer's group
CREATURE_EXTRA_FLAG_CIVILIAN = 0x00000002, // not aggro (ignore faction/reputation hostility)
CREATURE_EXTRA_FLAG_NO_PARRY = 0x00000004, // creature can't parry
CREATURE_EXTRA_FLAG_NO_PARRY_HASTEN = 0x00000008, // creature can't counter-attack at parry
CREATURE_EXTRA_FLAG_NO_BLOCK = 0x00000010, // creature can't block
CREATURE_EXTRA_FLAG_NO_CRUSH = 0x00000020, // creature can't do crush attacks
CREATURE_EXTRA_FLAG_NO_XP_AT_KILL = 0x00000040, // creature kill not provide XP
CREATURE_EXTRA_FLAG_INVISIBLE = 0x00000080, // creature is always invisible for player (mostly trigger creatures)
CREATURE_EXTRA_FLAG_NOT_TAUNTABLE = 0x00000100, // creature is immune to taunt auras and effect attack me
CREATURE_EXTRA_FLAG_AGGRO_ZONE = 0x00000200, // creature sets itself in combat with zone on aggro
CREATURE_EXTRA_FLAG_GUARD = 0x00000400, // creature is a guard
CREATURE_EXTRA_FLAG_NO_CALL_ASSIST = 0x00000800, // creature shouldn't call for assistance on aggro
CREATURE_EXTRA_FLAG_ACTIVE = 0x00001000, // creature is active object. Grid of this creature will be loaded and creature set as active
CREATURE_EXTRA_FLAG_MMAP_FORCE_ENABLE = 0x00002000, // creature is forced to use MMaps
CREATURE_EXTRA_FLAG_MMAP_FORCE_DISABLE = 0x00004000, // creature is forced to NOT use MMaps
CREATURE_EXTRA_FLAG_WALK_IN_WATER = 0x00008000, // creature is forced to walk in water even it can swim
CREATURE_EXTRA_FLAG_HAVE_NO_SWIM_ANIMATION = 0x00010000, // we have to not set "swim" animation or creature will have "no animation"
};
// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform
@ -72,8 +78,124 @@ enum CreatureFlagsExtra
#define MAX_KILL_CREDIT 2
#define MAX_CREATURE_MODEL 4
// from `creature_template` table
struct CreatureInfo
{
uint32 Entry;
char* Name;
char* SubName;
char* IconName;
uint32 MinLevel;
uint32 MaxLevel;
uint32 DifficultyEntry[MAX_DIFFICULTY - 1];
uint32 ModelId[MAX_CREATURE_MODEL];
uint32 FactionAlliance;
uint32 FactionHorde;
float Scale;
uint32 Family; // enum CreatureFamily values (optional)
uint32 CreatureType; // enum CreatureType values
uint32 InhabitType;
uint32 RegenerateStats;
bool RacialLeader;
uint32 NpcFlags;
uint32 UnitFlags; // enum UnitFlags mask values
uint32 UnitFlags2; // enum UnitFlags2 mask values
uint32 DynamicFlags;
uint32 ExtraFlags;
uint32 CreatureTypeFlags; // enum CreatureTypeFlags mask values
float SpeedWalk;
float SpeedRun;
uint32 UnitClass; // enum Classes. Note only 4 classes are known for creatures.
uint32 Rank;
int32 Expansion; // creature expansion, important for stats, CAN BE -1 as marker for some invalid cases.
float HealthMultiplier;
float PowerMultiplier;
float DamageMultiplier;
float DamageVariance;
float ArmorMultiplier;
float ExperienceMultiplier;
uint32 MinLevelHealth;
uint32 MaxLevelHealth;
uint32 MinLevelMana;
uint32 MaxLevelMana;
float MinMeleeDmg;
float MaxMeleeDmg;
float MinRangedDmg;
float MaxRangedDmg;
uint32 Armor;
uint32 MeleeAttackPower;
uint32 RangedAttackPower;
uint32 MeleeBaseAttackTime;
uint32 RangedBaseAttackTime;
uint32 DamageSchool;
uint32 MinLootGold;
uint32 MaxLootGold;
uint32 LootId;
uint32 PickpocketLootId;
uint32 SkinningLootId;
uint32 KillCredit[MAX_KILL_CREDIT];
uint32 QuestItems[6];
uint32 MechanicImmuneMask;
int32 ResistanceHoly;
int32 ResistanceFire;
int32 ResistanceNature;
int32 ResistanceFrost;
int32 ResistanceShadow;
int32 ResistanceArcane;
uint32 PetSpellDataId;
uint32 MovementType;
uint32 MovementTemplateId;
uint32 TrainerType;
uint32 TrainerSpell;
uint32 TrainerClass;
uint32 TrainerRace;
uint32 TrainerTemplateId;
uint32 VendorTemplateId;
uint32 EquipmentTemplateId;
uint32 VehicleTemplateId;
uint32 GossipMenuId;
char const* AIName;
// helpers
HighGuid GetHighGuid() const
{
return VehicleTemplateId ? HIGHGUID_VEHICLE : HIGHGUID_UNIT;
}
ObjectGuid GetObjectGuid(uint32 lowguid) const { return ObjectGuid(GetHighGuid(), Entry, lowguid); }
SkillType GetRequiredLootSkill() const
{
if (CreatureTypeFlags & CREATURE_TYPEFLAGS_HERBLOOT)
return SKILL_HERBALISM;
else if (CreatureTypeFlags & CREATURE_TYPEFLAGS_MININGLOOT)
return SKILL_MINING;
else if (CreatureTypeFlags & CREATURE_TYPEFLAGS_ENGINEERLOOT)
return SKILL_ENGINEERING;
else
return SKILL_SKINNING; // normal case
}
bool IsExotic() const
{
return (CreatureTypeFlags & CREATURE_TYPEFLAGS_EXOTIC);
}
bool isTameable(bool exotic) const
{
if (CreatureType != CREATURE_TYPE_BEAST || Family == 0 || (CreatureTypeFlags & CREATURE_TYPEFLAGS_TAMEABLE) == 0)
return false;
// if can tame exotic then can tame any temable
return exotic || !IsExotic();
}
};
// from `creature_template` table
/*
struct CreatureInfo
{
uint32 Entry;
uint32 DifficultyEntry[MAX_DIFFICULTY - 1];
@ -83,16 +205,16 @@ struct CreatureInfo
char* SubName;
char* IconName;
uint32 GossipMenuId;
uint32 minlevel;
uint32 maxlevel;
uint32 minhealth;
uint32 MinLevel;
uint32 MaxLevel;
uint32 MinLevelHealth;
uint32 maxhealth;
uint32 minmana;
uint32 MinLevelMana;
uint32 maxmana;
uint32 armor;
uint32 FactionAlliance;
uint32 FactionHorde;
uint32 npcflag;
uint32 NpcFlags;
float speed_walk;
float speed_run;
float Scale;
@ -102,25 +224,25 @@ struct CreatureInfo
uint32 dmgschool;
uint32 attackpower;
float dmg_multiplier;
uint32 baseattacktime;
uint32 rangeattacktime;
uint32 unit_class; // enum Classes. Note only 4 classes are known for creatures.
uint32 unit_flags; // enum UnitFlags mask values
uint32 unit_flags2; // enum UnitFlags2 mask values
uint32 MeleeAttackPower;
uint32 RangedAttackPower;
uint32 UnitClass; // enum Classes. Note only 4 classes are known for creatures.
uint32 UnitFlags; // enum UnitFlags mask values
uint32 UnitFlags2; // enum UnitFlags2 mask values
uint32 dynamicflags;
uint32 family; // enum CreatureFamily values (optional)
uint32 trainer_type;
uint32 TrainerType;
uint32 trainer_spell;
uint32 trainer_class;
uint32 TrainerClass;
uint32 trainer_race;
float minrangedmg;
float maxrangedmg;
uint32 rangedattackpower;
uint32 type; // enum CreatureType values
uint32 CreatureTypeFlags; // enum CreatureTypeFlags mask values
uint32 lootid;
uint32 Lootid;
uint32 pickpocketLootId;
uint32 SkinLootId;
uint32 SkinningLootId;
int32 resistance1;
int32 resistance2;
int32 resistance3;
@ -128,7 +250,7 @@ struct CreatureInfo
int32 resistance5;
int32 resistance6;
uint32 PetSpellDataId;
uint32 mingold;
uint32 MinLootGold;
uint32 maxgold;
char const* AIName;
uint32 MovementType;
@ -141,8 +263,8 @@ struct CreatureInfo
bool RegenHealth;
uint32 VehicleTemplateId;
uint32 EquipmentTemplateId;
uint32 trainerId;
uint32 vendorId;
uint32 TrainerTemplateId;
uint32 VendorTemplateId;
uint32 MechanicImmuneMask;
uint32 ExtraFlags;
@ -179,7 +301,7 @@ struct CreatureInfo
// if can tame exotic then can tame any temable
return exotic || !IsExotic();
}
};
}; */
struct CreatureTemplateSpells
{
@ -330,6 +452,12 @@ enum SelectFlags
SELECT_FLAG_NOT_IN_MELEE_RANGE = 0x080,
};
enum RegenStatsFlags
{
REGEN_FLAG_HEALTH = 0x001,
REGEN_FLAG_POWER = 0x002,
};
// Vendors
enum
@ -501,7 +629,7 @@ class Creature : public Unit
bool Create(uint32 guidlow, CreatureCreatePos& cPos, CreatureInfo const* cinfo, Team team = TEAM_NONE, const CreatureData* data = NULL, GameEventCreatureData const* eventData = NULL);
bool LoadCreatureAddon(bool reload);
void SelectLevel(const CreatureInfo* cinfo, float percentHealth = 100.0f, float percentMana = 100.0f);
void SelectLevel(const CreatureInfo* cinfo, float percentHealth = 100.0f);
void LoadEquipment(uint32 equip_entry, bool force = false);
bool HasStaticDBSpawnData() const; // listed in `creature` table and have fixed in DB guid
@ -523,12 +651,14 @@ class Creature : public Unit
void SetCorpseDelay(uint32 delay) { m_corpseDelay = delay; }
uint32 GetCorpseDelay() const { return m_corpseDelay; }
bool IsRacialLeader() const { return GetCreatureInfo()->RacialLeader; }
bool IsCivilian() const { return GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_CIVILIAN; }
bool IsGuard() const { return GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_GUARD; }
bool IsCivilian() const { return GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_CIVILIAN; }
bool IsGuard() const { return GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_GUARD; }
bool CanWalk() const { return GetCreatureInfo()->InhabitType & INHABIT_GROUND; }
virtual bool CanSwim() const { return GetCreatureInfo()->InhabitType & INHABIT_WATER; }
bool CanFly() const { return (GetCreatureInfo()->InhabitType & INHABIT_AIR) || (GetByteValue(UNIT_FIELD_BYTES_1, 3) & UNIT_BYTE1_FLAG_FLY_ANIM) || HasAuraType(SPELL_AURA_FLY); }
bool CanSwim() const { return GetCreatureInfo()->InhabitType & INHABIT_WATER; }
bool IsSwimming() const { return (m_movementInfo.HasMovementFlag((MovementFlags)(MOVEFLAG_SWIMMING))); }
bool CanFly() const { return (GetCreatureInfo()->InhabitType & INHABIT_AIR) || (GetByteValue(UNIT_FIELD_BYTES_1, 3) & UNIT_BYTE1_FLAG_FLY_ANIM) || m_movementInfo.HasMovementFlag((MovementFlags)(MOVEFLAG_LEVITATING | MOVEFLAG_CAN_FLY)); }
bool IsFlying() const { return (m_movementInfo.HasMovementFlag((MovementFlags)(MOVEFLAG_FLYING | MOVEFLAG_LEVITATING))); }
bool IsTrainerOf(Player* player, bool msg) const;
bool CanInteractWithBattleMaster(Player* player, bool msg) const;
@ -745,7 +875,8 @@ class Creature : public Unit
bool HasInvolvedQuest(uint32 quest_id) const override;
GridReference<Creature>& GetGridRef() { return m_gridRef; }
bool IsRegeneratingHealth() { return m_regenHealth; }
bool IsRegeneratingHealth() { return GetCreatureInfo()->RegenerateStats & REGEN_FLAG_HEALTH; }
bool IsRegeneratingPower() { return GetCreatureInfo()->RegenerateStats & REGEN_FLAG_POWER; }
virtual uint8 GetPetAutoSpellSize() const { return CREATURE_MAX_SPELLS; }
virtual uint32 GetPetAutoSpellOnPos(uint8 pos) const
{
@ -802,6 +933,7 @@ class Creature : public Unit
time_t m_respawnTime; // (secs) time of next respawn
uint32 m_respawnDelay; // (secs) delay between corpse disappearance and respawning
uint32 m_corpseDelay; // (secs) delay between death and corpse disappearance
uint32 m_aggroDelay; // (msecs)delay between respawn and aggro due to movement
float m_respawnradius;
CreatureSubtype m_subtype; // set in Creatures subclasses for fast it detect without dynamic_cast use

View file

@ -732,7 +732,7 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
break;
case ACTION_T_COMBAT_MOVEMENT:
// ignore no affect case
if (m_isCombatMovement == (action.combat_movement.state != 0))
if (m_isCombatMovement == (action.combat_movement.state != 0) || m_creature->IsNonMeleeSpellCasted(false))
return;
SetCombatMovement(action.combat_movement.state != 0, true);
@ -966,63 +966,38 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
m_throwAIEventMask = action.setThrowMask.eventTypeMask;
break;
}
case ACTION_T_SUMMON_UNIQUE:
case ACTION_T_SET_STAND_STATE:
{
Creature* pCreature = NULL;
MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*m_creature, action.summon_unique.creatureId, true, false, 100, true);
MaNGOS::CreatureLastSearcher<MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(pCreature, u_check);
Cell::VisitGridObjects(m_creature, searcher, 100);
WorldObject* pSpawn = NULL;
pSpawn = pCreature;
if (!pSpawn)
{
Unit* target = GetTargetByType(action.summon_unique.target, pActionInvoker, pAIEventSender, reportTargetError);
if (!target && reportTargetError)
sLog.outErrorEventAI("Event %u - NULL target for ACTION_T_SUMMON_UNIQUE(%u), target-type %u", EventId, action.type, action.summon_unique.target);
CreatureEventAI_Summon_Map::const_iterator i = sEventAIMgr.GetCreatureEventAISummonMap().find(action.summon_unique.spawnId);
if (i == sEventAIMgr.GetCreatureEventAISummonMap().end())
{
sLog.outErrorEventAI("Failed to spawn creature %u. Summon map index %u does not exist. EventID %d. CreatureID %d", action.summon_unique.creatureId, action.summon_unique.spawnId, EventId, m_creature->GetEntry());
return;
}
Creature* pCreature = NULL;
if ((*i).second.SpawnTimeSecs)
pCreature = m_creature->SummonCreature(action.summon_unique.creatureId, (*i).second.position_x, (*i).second.position_y, (*i).second.position_z, (*i).second.orientation, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, (*i).second.SpawnTimeSecs);
else
pCreature = m_creature->SummonCreature(action.summon_unique.creatureId, (*i).second.position_x, (*i).second.position_y, (*i).second.position_z, (*i).second.orientation, TEMPSUMMON_TIMED_OOC_DESPAWN, 0);
if (!pCreature)
sLog.outErrorEventAI("Failed to spawn creature %u. EventId %d.Creature %d", action.summon_unique.creatureId, EventId, m_creature->GetEntry());
else if (action.summon_unique.target != TARGET_T_SELF && target)
pCreature->AI()->AttackStart(target);
break;
}
if (pSpawn)
{
return;
}
m_creature->SetStandState(action.setStandState.standState);
break;
}
case ACTION_T_EMOTE_TARGET:
case ACTION_T_CHANGE_MOVEMENT:
{
Unit* pCreature = m_creature->GetMap()->GetCreature(ObjectGuid(HIGHGUID_UNIT, action.emoteTarget.targetGuid));
if (!pCreature)
switch (action.changeMovement.movementType)
{
sLog.outErrorEventAI("Event %d. Cannot find creature by guid %d", EventId, action.emoteTarget.targetGuid);
return;
case IDLE_MOTION_TYPE:
m_creature->GetMotionMaster()->MoveIdle();
break;
case RANDOM_MOTION_TYPE:
m_creature->GetMotionMaster()->MoveRandomAroundPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), float(action.changeMovement.wanderDistance));
break;
case WAYPOINT_MOTION_TYPE:
m_creature->GetMotionMaster()->MoveWaypoint();
break;
}
break;
}
case ACTION_T_DYNAMIC_MOVEMENT:
{
if (action.dynamicMovement.state && m_DynamicMovement || !action.dynamicMovement.state && !m_DynamicMovement)
break;
m_creature->SetFacingToObject(pCreature);
m_creature->HandleEmote(action.emoteTarget.emoteId);
m_DynamicMovement = action.dynamicMovement.state;
SetCombatMovement(!m_DynamicMovement, true);
break;
}
default:
sLog.outError("CreatureEventAi::ProcessAction(): action(%u) not implemented", static_cast<uint32>(action.type));
break;
}
}

View file

@ -121,10 +121,12 @@ enum EventAI_ActionType
ACTION_T_SET_INVINCIBILITY_HP_LEVEL = 42, // MinHpValue, format(0-flat,1-percent from max health)
ACTION_T_MOUNT_TO_ENTRY_OR_MODEL = 43, // Creature_template entry(param1) OR ModelId (param2) (or 0 for both to unmount)
ACTION_T_CHANCED_TEXT = 44, // Chance to display the text, TextId1, optionally TextId2. If more than just -TextId1 is defined, randomize. Negative values.
ACTION_T_THROW_AI_EVENT = 45, // EventType, Radius, unused
ACTION_T_THROW_AI_EVENT = 45, // EventType, Radius, unused
ACTION_T_SET_THROW_MASK = 46, // EventTypeMask, unused, unused
ACTION_T_SUMMON_UNIQUE = 47, // CreatureId, Target, SpawnId
ACTION_T_EMOTE_TARGET = 48, // EmoteId, TargetGuid
ACTION_T_SET_STAND_STATE = 47, // StandState, unused, unused
ACTION_T_CHANGE_MOVEMENT = 48, // MovementType, WanderDistance, unused
ACTION_T_DYNAMIC_MOVEMENT = 49, // EnableDynamicMovement (1 = on; 0 = off)
ACTION_T_END,
};
@ -173,7 +175,7 @@ enum SpawnedEventMode
struct CreatureEventAI_Action
{
EventAI_ActionType type: 16;
EventAI_ActionType type : 16;
union
{
// ACTION_T_TEXT = 1
@ -384,7 +386,6 @@ struct CreatureEventAI_Action
uint32 creatureId; // set one from fields (or 0 for both to dismount)
uint32 modelId;
} mount;
// ACTION_T_CHANCED_TEXT = 44
struct
{
@ -405,19 +406,27 @@ struct CreatureEventAI_Action
uint32 unused1;
uint32 unused2;
} setThrowMask;
// ACTION_T_SUMMON_UNIQUE = 47
// ACTION_T_SET_STAND_STATE = 47
struct
{
uint32 creatureId;
uint32 target;
uint32 spawnId;
} summon_unique;
// ACTION_T_EMOTE_TARGET = 48
uint32 standState;
uint32 unused1;
uint32 unused2;
} setStandState;
// ACTION_T_CHANGE_MOVEMENT = 48
struct
{
uint32 emoteId;
uint32 targetGuid;
} emoteTarget;
uint32 movementType;
uint32 wanderDistance;
uint32 unused1;
} changeMovement;
// ACTION_T_DYNAMIC_MOVEMENT = 49
struct
{
uint32 state; // bool: 1 = on; 0 = off
uint32 unused1;
uint32 unused2;
} dynamicMovement;
// RAW
struct
{
@ -672,6 +681,8 @@ class CreatureEventAI : public CreatureAI
uint8 m_Phase; // Current phase, max 32 phases
bool m_MeleeEnabled; // If we allow melee auto attack
bool m_DynamicMovement; // Core will control creatures movement if this is enabled
bool m_HasOOCLoSEvent; // Cache if a OOC-LoS Event exists
uint32 m_InvinceabilityHpLevel; // Minimal health level allowed at damage apply
uint32 m_throwAIEventMask; // Automatically throw AIEvents that are encoded into this mask

View file

@ -873,6 +873,21 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
continue;
}
break;
case ACTION_T_SET_STAND_STATE:
if (action.setStandState.standState >= MAX_UNIT_STAND_STATE)
{
sLog.outErrorEventAI("Event %u Action %u uses invalid unit stand state %u (must be smaller than %u)", i, j + 1, action.setStandState.standState, MAX_UNIT_STAND_STATE);
continue;
}
break;
case ACTION_T_CHANGE_MOVEMENT:
if (action.changeMovement.movementType >= MAX_DB_MOTION_TYPE)
{
sLog.outErrorEventAI("Event %u Action %u uses invalid movement type %u (must be smaller than %u)", i, j + 1, action.changeMovement.movementType, MAX_DB_MOTION_TYPE);
continue;
}
break;
default:
sLog.outErrorEventAI("Event %u Action %u have currently not checked at load action type (%u). Need check code update?", i, j + 1, temp.action[j].type);
break;

View file

@ -119,7 +119,7 @@ namespace MaNGOS
{
if (u->GetTypeId() == TYPEID_UNIT && (
((Creature*)u)->IsTotem() || ((Creature*)u)->IsPet() ||
(((Creature*)u)->GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_NO_XP_AT_KILL)))
(((Creature*)u)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_XP_AT_KILL)))
return 0;
uint32 xp_gain = BaseGain(pl->getLevel(), u->getLevel(), GetContentLevelsForMapAndZone(pl->GetMapId(), pl->GetZoneId()));

View file

@ -2048,30 +2048,27 @@ bool GameObject::HasStaticDBSpawnData() const
return sObjectMgr.GetGOData(GetGUIDLow()) != NULL;
}
void GameObject::SetCapturePointSlider(float value)
void GameObject::SetCapturePointSlider(float value, bool isLocked)
{
GameObjectInfo const* info = GetGOInfo();
m_captureSlider = value;
// only activate non-locked capture point
if (value >= 0)
{
m_captureSlider = value;
{ SetLootState(GO_ACTIVATED); }
}
else
m_captureSlider = -value;
if (!isLocked)
SetLootState(GO_ACTIVATED);
// set the state of the capture point based on the slider value
if ((int)m_captureSlider == CAPTURE_SLIDER_ALLIANCE)
{ m_captureState = CAPTURE_STATE_WIN_ALLIANCE; }
m_captureState = CAPTURE_STATE_WIN_ALLIANCE;
else if ((int)m_captureSlider == CAPTURE_SLIDER_HORDE)
{ m_captureState = CAPTURE_STATE_WIN_HORDE; }
m_captureState = CAPTURE_STATE_WIN_HORDE;
else if (m_captureSlider > CAPTURE_SLIDER_MIDDLE + info->capturePoint.neutralPercent * 0.5f)
{ m_captureState = CAPTURE_STATE_PROGRESS_ALLIANCE; }
m_captureState = CAPTURE_STATE_PROGRESS_ALLIANCE;
else if (m_captureSlider < CAPTURE_SLIDER_MIDDLE - info->capturePoint.neutralPercent * 0.5f)
{ m_captureState = CAPTURE_STATE_PROGRESS_HORDE; }
m_captureState = CAPTURE_STATE_PROGRESS_HORDE;
else
{ m_captureState = CAPTURE_STATE_NEUTRAL; }
m_captureState = CAPTURE_STATE_NEUTRAL;
}
void GameObject::TickCapturePoint()

View file

@ -622,11 +622,11 @@ enum CapturePointState
CAPTURE_STATE_WIN_HORDE
};
enum CapturePointSlider
enum CapturePointSliderValue
{
CAPTURE_SLIDER_ALLIANCE = 100, // full alliance
CAPTURE_SLIDER_HORDE = 0, // full horde
CAPTURE_SLIDER_MIDDLE = 50 // middle
CAPTURE_SLIDER_ALLIANCE = 100, // full alliance
CAPTURE_SLIDER_HORDE = 0, // full horde
CAPTURE_SLIDER_MIDDLE = 50 // middle
};
class Unit;
@ -796,8 +796,10 @@ class GameObject : public WorldObject
GameObject* LookupFishingHoleAround(float range);
void SetCapturePointSlider(float value);
float GetCapturePointSlider() const { return m_captureSlider; }
void SetCapturePointSlider(float value, bool isLocked);
float GetCapturePointSliderValue() const { return m_captureSlider; }
float GetInteractionDistance();
uint32 GetScriptId();

View file

@ -583,7 +583,7 @@ void Guild::BroadcastToGuild(WorldSession* session, const std::string& msg, uint
if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(), GR_RIGHT_GCHATSPEAK))
{
WorldPacket data;
ChatHandler::FillMessageData(&data, session, CHAT_MSG_GUILD, language, msg.c_str());
ChatHandler::BuildChatPacket(data, CHAT_MSG_GUILD, msg.c_str(), Language(language), session->GetPlayer()->GetChatTag(), session->GetPlayer()->GetObjectGuid(), session->GetPlayer()->GetName());
for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
{
@ -600,7 +600,7 @@ void Guild::BroadcastAddonToGuild(WorldSession* session, const std::string& msg,
if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(), GR_RIGHT_GCHATSPEAK))
{
WorldPacket data;
ChatHandler::FillMessageData(&data, session,CHAT_MSG_GUILD, CHAT_MSG_ADDON, NULL, ObjectGuid(), msg.c_str(), NULL, prefix.c_str());
ChatHandler::BuildChatPacket(data, CHAT_MSG_GUILD, msg.c_str(), LANG_ADDON, CHAT_TAG_NONE, ObjectGuid(), NULL, ObjectGuid(), NULL, NULL, 0, prefix.c_str());
for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
{
@ -614,18 +614,22 @@ void Guild::BroadcastAddonToGuild(WorldSession* session, const std::string& msg,
void Guild::BroadcastToOfficers(WorldSession* session, const std::string& msg, uint32 language)
{
if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(), GR_RIGHT_OFFCHATSPEAK))
if (!session)
return;
Player* player = session->GetPlayer();
if (!player || !HasRankRight(player->GetRank(), GR_RIGHT_OFFCHATSPEAK))
return;
for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
{
for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
{
WorldPacket data;
ChatHandler::FillMessageData(&data, session, CHAT_MSG_OFFICER, language, msg.c_str());
WorldPacket data;
ChatHandler::BuildChatPacket(data, CHAT_MSG_OFFICER, msg.c_str(), Language(language), player->GetChatTag(), player->GetObjectGuid(), player->GetName());
Player* pl = ObjectAccessor::FindPlayer(ObjectGuid(HIGHGUID_PLAYER, itr->first));
Player* pl = ObjectAccessor::FindPlayer(ObjectGuid(HIGHGUID_PLAYER, itr->first));
if (pl && pl->GetSession() && HasRankRight(pl->GetRank(), GR_RIGHT_OFFCHATLISTEN) && !pl->GetSocial()->HasIgnore(session->GetPlayer()->GetObjectGuid()))
pl->GetSession()->SendPacket(&data);
}
if (pl && pl->GetSession() && HasRankRight(pl->GetRank(), GR_RIGHT_OFFCHATLISTEN) && !pl->GetSocial()->HasIgnore(player->GetObjectGuid()))
pl->GetSession()->SendPacket(&data);
}
}
@ -636,7 +640,7 @@ void Guild::BroadcastAddonToOfficers(WorldSession* session, const std::string& m
for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
{
WorldPacket data;
ChatHandler::FillMessageData(&data, session, CHAT_MSG_OFFICER, CHAT_MSG_ADDON, NULL, ObjectGuid(), msg.c_str(), NULL, prefix.c_str());
ChatHandler::BuildChatPacket(data, CHAT_MSG_OFFICER, msg.c_str(), LANG_ADDON, CHAT_TAG_NONE, ObjectGuid(), NULL, ObjectGuid(), NULL, NULL, 0, prefix.c_str());
Player* pl = ObjectAccessor::FindPlayer(ObjectGuid(HIGHGUID_PLAYER, itr->first));

View file

@ -47,11 +47,11 @@ static eConfigFloatValues const qualityToRate[MAX_ITEM_QUALITY] =
LootStore LootTemplates_Creature("creature_loot_template", "creature entry", true);
LootStore LootTemplates_Disenchant("disenchant_loot_template", "item disenchant id", true);
LootStore LootTemplates_Fishing("fishing_loot_template", "area id", true);
LootStore LootTemplates_Gameobject("gameobject_loot_template", "gameobject lootid", true);
LootStore LootTemplates_Gameobject("gameobject_loot_template", "gameobject Lootid", true);
LootStore LootTemplates_Item("item_loot_template", "item entry with ITEM_FLAG_LOOTABLE", true);
LootStore LootTemplates_Mail("mail_loot_template", "mail template id", false);
LootStore LootTemplates_Milling("milling_loot_template", "item entry (herb)", true);
LootStore LootTemplates_Pickpocketing("pickpocketing_loot_template", "creature pickpocket lootid", true);
LootStore LootTemplates_Pickpocketing("pickpocketing_loot_template", "creature pickpocket Lootid", true);
LootStore LootTemplates_Prospecting("prospecting_loot_template", "item entry (ore)", true);
LootStore LootTemplates_Reference("reference_loot_template", "reference id", false);
LootStore LootTemplates_Skinning("skinning_loot_template", "creature skinning id", true);
@ -1271,12 +1271,12 @@ void LoadLootTemplates_Creature()
{
if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
{
if (uint32 lootid = cInfo->lootid)
if (uint32 Lootid = cInfo->LootId)
{
if (ids_set.find(lootid) == ids_set.end())
LootTemplates_Creature.ReportNotExistedId(lootid);
if (ids_set.find(Lootid) == ids_set.end())
LootTemplates_Creature.ReportNotExistedId(Lootid);
else
ids_setUsed.insert(lootid);
ids_setUsed.insert(Lootid);
}
}
}
@ -1301,12 +1301,12 @@ void LoadLootTemplates_Disenchant()
{
if (ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i))
{
if (uint32 lootid = proto->DisenchantID)
if (uint32 Lootid = proto->DisenchantID)
{
if (ids_set.find(lootid) == ids_set.end())
LootTemplates_Disenchant.ReportNotExistedId(lootid);
if (ids_set.find(Lootid) == ids_set.end())
LootTemplates_Disenchant.ReportNotExistedId(Lootid);
else
ids_setUsed.insert(lootid);
ids_setUsed.insert(Lootid);
}
}
}
@ -1344,12 +1344,12 @@ void LoadLootTemplates_Gameobject()
// remove real entries and check existence loot
for (SQLStorageBase::SQLSIterator<GameObjectInfo> itr = sGOStorage.getDataBegin<GameObjectInfo>(); itr < sGOStorage.getDataEnd<GameObjectInfo>(); ++itr)
{
if (uint32 lootid = itr->GetLootId())
if (uint32 Lootid = itr->GetLootId())
{
if (ids_set.find(lootid) == ids_set.end())
LootTemplates_Gameobject.ReportNotExistedId(lootid);
if (ids_set.find(Lootid) == ids_set.end())
LootTemplates_Gameobject.ReportNotExistedId(Lootid);
else
ids_setUsed.insert(lootid);
ids_setUsed.insert(Lootid);
}
}
for (LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
@ -1419,12 +1419,12 @@ void LoadLootTemplates_Pickpocketing()
{
if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
{
if (uint32 lootid = cInfo->pickpocketLootId)
if (uint32 Lootid = cInfo->PickpocketLootId)
{
if (ids_set.find(lootid) == ids_set.end())
LootTemplates_Pickpocketing.ReportNotExistedId(lootid);
if (ids_set.find(Lootid) == ids_set.end())
LootTemplates_Pickpocketing.ReportNotExistedId(Lootid);
else
ids_setUsed.insert(lootid);
ids_setUsed.insert(Lootid);
}
}
}
@ -1485,12 +1485,12 @@ void LoadLootTemplates_Skinning()
{
if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
{
if (uint32 lootid = cInfo->SkinLootId)
if (uint32 Lootid = cInfo->SkinningLootId)
{
if (ids_set.find(lootid) == ids_set.end())
LootTemplates_Skinning.ReportNotExistedId(lootid);
if (ids_set.find(Lootid) == ids_set.end())
LootTemplates_Skinning.ReportNotExistedId(Lootid);
else
ids_setUsed.insert(lootid);
ids_setUsed.insert(Lootid);
}
}
}

View file

@ -49,6 +49,7 @@
#include "TemporarySummon.h"
#include "movement/packet_builder.h"
#include "CreatureLinkingMgr.h"
#include "Chat.h"
#ifdef ENABLE_ELUNA
#include "LuaEngine.h"
#include "ElunaEventMgr.h"
@ -1550,22 +1551,24 @@ bool WorldObject::IsPositionValid() const
void WorldObject::MonsterSay(const char* text, uint32 language, Unit const* target) const
{
WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildMonsterChat(&data, GetObjectGuid(), CHAT_MSG_MONSTER_SAY, text, language, GetName(), target ? target->GetObjectGuid() : ObjectGuid(), target ? target->GetName() : "");
ChatHandler::BuildChatPacket(data, CHAT_MSG_MONSTER_SAY, text, LANG_UNIVERSAL, CHAT_TAG_NONE, GetObjectGuid(), GetName(),
target ? target->GetObjectGuid() : ObjectGuid(), target ? target->GetName() : "");
SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY), true);
}
void WorldObject::MonsterYell(const char* text, uint32 language, Unit const* target) const
{
WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildMonsterChat(&data, GetObjectGuid(), CHAT_MSG_MONSTER_YELL, text, language, GetName(), target ? target->GetObjectGuid() : ObjectGuid(), target ? target->GetName() : "");
ChatHandler::BuildChatPacket(data, CHAT_MSG_MONSTER_YELL, text, LANG_UNIVERSAL, CHAT_TAG_NONE, GetObjectGuid(), GetName(),
target ? target->GetObjectGuid() : ObjectGuid(), target ? target->GetName() : "");
SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_YELL), true);
}
void WorldObject::MonsterTextEmote(const char* text, Unit const* target, bool IsBossEmote) const
{
WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildMonsterChat(&data, GetObjectGuid(), IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, text, LANG_UNIVERSAL,
GetName(), target ? target->GetObjectGuid() : ObjectGuid(), target ? target->GetName() : "");
ChatHandler::BuildChatPacket(data, IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, text, LANG_UNIVERSAL, CHAT_TAG_NONE, GetObjectGuid(), GetName(),
target ? target->GetObjectGuid() : ObjectGuid(), target ? target->GetName() : "");
SendMessageToSetInRange(&data, sWorld.getConfig(IsBossEmote ? CONFIG_FLOAT_LISTEN_RANGE_YELL : CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE), true);
}
@ -1575,8 +1578,8 @@ void WorldObject::MonsterWhisper(const char* text, Unit const* target, bool IsBo
{ return; }
WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildMonsterChat(&data, GetObjectGuid(), IsBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, text, LANG_UNIVERSAL,
GetName(), target->GetObjectGuid(), target->GetName());
ChatHandler::BuildChatPacket(data, IsBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, text, LANG_UNIVERSAL, CHAT_TAG_NONE, GetObjectGuid(), GetName(),
target->GetObjectGuid(), target->GetName());
((Player*)target)->GetSession()->SendPacket(&data);
}
@ -1584,102 +1587,87 @@ namespace MaNGOS
{
class MonsterChatBuilder
{
public:
MonsterChatBuilder(WorldObject const& obj, ChatMsg msgtype, int32 textId, uint32 language, Unit const* target)
: i_object(obj), i_msgtype(msgtype), i_textId(textId), i_language(language), i_target(target) {}
public:
MonsterChatBuilder(WorldObject const& obj, ChatMsg msgtype, MangosStringLocale const* textData, Language language, Unit const* target)
: i_object(obj), i_msgtype(msgtype), i_textData(textData), i_language(language), i_target(target) {}
void operator()(WorldPacket& data, int32 loc_idx)
{
char const* text = sObjectMgr.GetMangosString(i_textId, loc_idx);
char const* text = nullptr;
if ((int32)i_textData->Content.size() > loc_idx + 1 && !i_textData->Content[loc_idx + 1].empty())
text = i_textData->Content[loc_idx + 1].c_str();
else
text = i_textData->Content[0].c_str();
WorldObject::BuildMonsterChat(&data, i_object.GetObjectGuid(), i_msgtype, text, i_language, i_object.GetNameForLocaleIdx(loc_idx), i_target ? i_target->GetObjectGuid() : ObjectGuid(), i_target ? i_target->GetNameForLocaleIdx(loc_idx) : "");
ChatHandler::BuildChatPacket(data, i_msgtype, text, i_language, CHAT_TAG_NONE, i_object.GetObjectGuid(), i_object.GetNameForLocaleIdx(loc_idx),
i_target ? i_target->GetObjectGuid() : ObjectGuid(), i_target ? i_target->GetNameForLocaleIdx(loc_idx) : "");
}
private:
WorldObject const& i_object;
ChatMsg i_msgtype;
int32 i_textId;
uint32 i_language;
MangosStringLocale const* i_textData;
Language i_language;
Unit const* i_target;
};
} // namespace MaNGOS
void WorldObject::MonsterSay(int32 textId, uint32 language, Unit const* target) const
/// Helper function to create localized around a source
void _DoLocalizedTextAround(WorldObject const* source, MangosStringLocale const* textData, ChatMsg msgtype, Language language, Unit const* target, float range)
{
float range = sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY);
MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_SAY, textId, language, target);
MaNGOS::MonsterChatBuilder say_build(*source, msgtype, textData, language, target);
MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build);
MaNGOS::CameraDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> > say_worker(this, range, say_do);
Cell::VisitWorldObjects(this, say_worker, range);
MaNGOS::CameraDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> > say_worker(source, range, say_do);
Cell::VisitWorldObjects(source, say_worker, range);
}
void WorldObject::MonsterYell(int32 textId, uint32 language, Unit const* target) const
/// Function that sends a text associated to a MangosString
void WorldObject::MonsterText(MangosStringLocale const* textData, Unit const* target) const
{
float range = sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_YELL);
MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_YELL, textId, language, target);
MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build);
MaNGOS::CameraDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> > say_worker(this, range, say_do);
Cell::VisitWorldObjects(this, say_worker, range);
}
MANGOS_ASSERT(textData);
void WorldObject::MonsterYellToZone(int32 textId, uint32 language, Unit const* target) const
{
MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_YELL, textId, language, target);
MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build);
uint32 zoneid = GetZoneId();
Map::PlayerList const& pList = GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr)
if (itr->getSource()->GetZoneId() == zoneid)
say_do(itr->getSource());
}
void WorldObject::MonsterTextEmote(int32 textId, Unit const* target, bool IsBossEmote) const
{
float range = sWorld.getConfig(IsBossEmote ? CONFIG_FLOAT_LISTEN_RANGE_YELL : CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE);
MaNGOS::MonsterChatBuilder say_build(*this, IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, textId, LANG_UNIVERSAL, target);
MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build);
MaNGOS::CameraDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> > say_worker(this, range, say_do);
Cell::VisitWorldObjects(this, say_worker, range);
}
void WorldObject::MonsterWhisper(int32 textId, Unit const* target, bool IsBossWhisper) const
{
if (!target || target->GetTypeId() != TYPEID_PLAYER)
return;
uint32 loc_idx = ((Player*)target)->GetSession()->GetSessionDbLocaleIndex();
char const* text = sObjectMgr.GetMangosString(textId, loc_idx);
WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildMonsterChat(&data, GetObjectGuid(), IsBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, text, LANG_UNIVERSAL,
GetNameForLocaleIdx(loc_idx), target->GetObjectGuid(), "");
((Player*)target)->GetSession()->SendPacket(&data);
}
void WorldObject::BuildMonsterChat(WorldPacket* data, ObjectGuid senderGuid, uint8 msgtype, char const* text, uint32 language, char const* name, ObjectGuid targetGuid, char const* targetName)
{
*data << uint8(msgtype);
*data << uint32(language);
*data << ObjectGuid(senderGuid);
*data << uint32(0); // 2.1.0
*data << uint32(strlen(name) + 1);
*data << name;
*data << ObjectGuid(targetGuid); // Unit Target
if (targetGuid && !targetGuid.IsPlayer())
switch (textData->Type)
{
*data << uint32(strlen(targetName) + 1); // target name length
*data << targetName; // target name
}
*data << uint32(strlen(text) + 1);
*data << text;
*data << uint8(0); // ChatTag
if (msgtype == CHAT_MSG_RAID_BOSS_EMOTE || msgtype == CHAT_MSG_RAID_BOSS_WHISPER)
{
*data << float(0.0f);
*data << uint8(0);
case CHAT_TYPE_SAY:
_DoLocalizedTextAround(this, textData, CHAT_MSG_MONSTER_SAY, textData->LanguageId, target, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY));
break;
case CHAT_TYPE_YELL:
_DoLocalizedTextAround(this, textData, CHAT_MSG_MONSTER_YELL, textData->LanguageId, target, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_YELL));
break;
case CHAT_TYPE_TEXT_EMOTE:
_DoLocalizedTextAround(this, textData, CHAT_MSG_MONSTER_EMOTE, LANG_UNIVERSAL, target, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE));
break;
case CHAT_TYPE_BOSS_EMOTE:
_DoLocalizedTextAround(this, textData, CHAT_MSG_RAID_BOSS_EMOTE, LANG_UNIVERSAL, target, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_YELL));
break;
case CHAT_TYPE_WHISPER:
{
if (!target || target->GetTypeId() != TYPEID_PLAYER)
return;
MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_WHISPER, textData, LANG_UNIVERSAL, target);
MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build);
say_do((Player*)target);
break;
}
case CHAT_TYPE_BOSS_WHISPER:
{
if (!target || target->GetTypeId() != TYPEID_PLAYER)
return;
MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_RAID_BOSS_WHISPER, textData, LANG_UNIVERSAL, target);
MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build);
say_do((Player*)target);
break;
}
case CHAT_TYPE_ZONE_YELL:
{
MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_YELL, textData, textData->LanguageId, target);
MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build);
uint32 zoneid = GetZoneId();
Map::PlayerList const& pList = GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr)
if (itr->getSource()->GetZoneId() == zoneid)
say_do(itr->getSource());
break;
}
}
}

View file

@ -601,16 +601,13 @@ class WorldObject : public Object
virtual void SendMessageToSetInRange(WorldPacket* data, float dist, bool self) const;
void SendMessageToSetExcept(WorldPacket* data, Player const* skipped_receiver) const;
void MonsterSay(const char* text, uint32 language, Unit const* target = NULL) const;
void MonsterYell(const char* text, uint32 language, Unit const* target = NULL) const;
void MonsterSay(const char* text, uint32 language, Unit const* target = nullptr) const;
void MonsterYell(const char* text, uint32 language, Unit const* target = nullptr) const;
void MonsterTextEmote(const char* text, Unit const* target, bool IsBossEmote = false) const;
void MonsterWhisper(const char* text, Unit const* target, bool IsBossWhisper = false) const;
void MonsterSay(int32 textId, uint32 language, Unit const* target = NULL) const;
void MonsterYell(int32 textId, uint32 language, Unit const* target = NULL) const;
void MonsterTextEmote(int32 textId, Unit const* target, bool IsBossEmote = false) const;
void MonsterWhisper(int32 textId, Unit const* receiver, bool IsBossWhisper = false) const;
void MonsterText(MangosStringLocale const* textData, Unit const* target) const;
void MonsterYellToZone(int32 textId, uint32 language, Unit const* target) const;
static void BuildMonsterChat(WorldPacket* data, ObjectGuid senderGuid, uint8 msgtype, char const* text, uint32 language, char const* name, ObjectGuid targetGuid, char const* targetName);
void PlayDistanceSound(uint32 sound_id, Player const* target = NULL) const;
void PlayDirectSound(uint32 sound_id, Player const* target = NULL) const;

View file

@ -527,38 +527,38 @@ void ObjectMgr::LoadCreatureTemplates()
if (!ok2)
continue;
if (cInfo->unit_class != difficultyInfo->unit_class)
if (cInfo->UnitClass != difficultyInfo->UnitFlags)
{
sLog.outErrorDb("Creature (Entry: %u, class %u) has different `unit_class` in difficulty %u mode (Entry: %u, class %u).",
i, cInfo->unit_class, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->unit_class);
sLog.outErrorDb("Creature (Entry: %u, class %u) has different `UnitClass` in difficulty %u mode (Entry: %u, class %u).",
i, cInfo->UnitClass, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->UnitClass);
continue;
}
if (cInfo->npcflag != difficultyInfo->npcflag)
if (cInfo->NpcFlags != difficultyInfo->NpcFlags)
{
sLog.outErrorDb("Creature (Entry: %u) has different `npcflag` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]);
sLog.outErrorDb("Creature (Entry: %u) has different `NpcFlags` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]);
continue;
}
if (cInfo->trainer_class != difficultyInfo->trainer_class)
if (cInfo->TrainerClass != difficultyInfo->TrainerClass)
{
sLog.outErrorDb("Creature (Entry: %u) has different `trainer_class` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]);
sLog.outErrorDb("Creature (Entry: %u) has different `TrainerClass` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]);
continue;
}
if (cInfo->trainer_race != difficultyInfo->trainer_race)
if (cInfo->TrainerRace != difficultyInfo->TrainerRace)
{
sLog.outErrorDb("Creature (Entry: %u) has different `trainer_race` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]);
continue;
}
if (cInfo->trainer_type != difficultyInfo->trainer_type)
if (cInfo->TrainerType != difficultyInfo->TrainerType)
{
sLog.outErrorDb("Creature (Entry: %u) has different `trainer_type` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]);
sLog.outErrorDb("Creature (Entry: %u) has different `TrainerType` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]);
continue;
}
if (cInfo->trainer_spell != difficultyInfo->trainer_spell)
if (cInfo->TrainerSpell != difficultyInfo->TrainerSpell)
{
sLog.outErrorDb("Creature (Entry: %u) has different `trainer_spell` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]);
continue;
@ -630,56 +630,89 @@ void ObjectMgr::LoadCreatureTemplates()
if (!displayScaleEntry)
sLog.outErrorDb("Creature (Entry: %u) has nonexistent modelid in modelid_1/modelid_2/modelid_3/modelid_4", cInfo->Entry);
if (!cInfo->minlevel)
if (!cInfo->MinLevel)
{
sLog.outErrorDb("Creature (Entry: %u) has invalid minlevel, set to 1", cInfo->Entry);
const_cast<CreatureInfo*>(cInfo)->minlevel = 1;
const_cast<CreatureInfo*>(cInfo)->MinLevel = 1;
}
if (cInfo->minlevel > cInfo->maxlevel)
if (cInfo->MinLevel > cInfo->MaxLevel)
{
sLog.outErrorDb("Creature (Entry: %u) has invalid maxlevel, set to minlevel", cInfo->Entry);
const_cast<CreatureInfo*>(cInfo)->maxlevel = cInfo->minlevel;
const_cast<CreatureInfo*>(cInfo)->MaxLevel = cInfo->MinLevel;
}
// use below code for 0-checks for unit_class
if (!cInfo->unit_class)
ERROR_DB_STRICT_LOG("Creature (Entry: %u) not has proper unit_class(%u) for creature_template", cInfo->Entry, cInfo->unit_class);
else if (((1 << (cInfo->unit_class - 1)) & CLASSMASK_ALL_CREATURES) == 0)
sLog.outErrorDb("Creature (Entry: %u) has invalid unit_class(%u) for creature_template", cInfo->Entry, cInfo->unit_class);
if (cInfo->dmgschool >= MAX_SPELL_SCHOOL)
if (cInfo->MinLevel > DEFAULT_MAX_CREATURE_LEVEL)
{
sLog.outErrorDb("Creature (Entry: %u) has invalid spell school value (%u) in `dmgschool`", cInfo->Entry, cInfo->dmgschool);
const_cast<CreatureInfo*>(cInfo)->dmgschool = SPELL_SCHOOL_NORMAL;
sLog.outErrorDb("Creature (Entry: %u) `MinLevel` exceeds maximum allowed value of '%u'", cInfo->Entry, uint32(DEFAULT_MAX_CREATURE_LEVEL));
const_cast<CreatureInfo*>(cInfo)->MinLevel = uint32(DEFAULT_MAX_CREATURE_LEVEL);
}
if (cInfo->baseattacktime == 0)
const_cast<CreatureInfo*>(cInfo)->baseattacktime = BASE_ATTACK_TIME;
if (cInfo->MaxLevel > DEFAULT_MAX_CREATURE_LEVEL)
{
sLog.outErrorDb("Creature (Entry: %u) `MaxLevel` exceeds maximum allowed value of '%u'", cInfo->Entry, uint32(DEFAULT_MAX_CREATURE_LEVEL));
const_cast<CreatureInfo*>(cInfo)->MaxLevel = uint32(DEFAULT_MAX_CREATURE_LEVEL);
}
if (cInfo->rangeattacktime == 0)
const_cast<CreatureInfo*>(cInfo)->rangeattacktime = BASE_ATTACK_TIME;
if (cInfo->Expansion > MAX_EXPANSION)
{
sLog.outErrorDb("Creature (Entry: %u) `Expansion(%u)` is not correct", cInfo->Entry, uint32(MAX_EXPANSION));
const_cast<CreatureInfo*>(cInfo)->Expansion = -1;
}
if (cInfo->npcflag & UNIT_NPC_FLAG_SPELLCLICK)
if (!cInfo->UnitClass || (((1 << (cInfo->UnitClass - 1)) & CLASSMASK_ALL_CREATURES) == 0))
{
ERROR_DB_STRICT_LOG("Creature (Entry: %u) does not have proper `UnitClass` (%u) in creature_template", cInfo->Entry, cInfo->UnitClass);
// Mark NPC as having improper data by his expansion
const_cast<CreatureInfo*>(cInfo)->Expansion = -1;
}
if (!sLog.HasLogFilter(LOG_FILTER_DB_STRICTED_CHECK) && cInfo->Expansion >= 0) // TODO - Remove the DB_STRICTED_CHECK after a while
{
// check if ClassLevel data are available for all possible level of that creature
for (uint32 level = cInfo->MinLevel; level <= cInfo->MaxLevel; ++level)
{
if (!GetCreatureClassLvlStats(level, cInfo->UnitClass, cInfo->Expansion))
{
sLog.outErrorDb("Creature (Entry: %u), level(%u) has no data in `creature_template_classlevelstats`", cInfo->Entry, level);
// Deactivate using ClassLevelStats for this NPC
const_cast<CreatureInfo*>(cInfo)->Expansion = -1;
}
}
}
if (cInfo->DamageSchool >= MAX_SPELL_SCHOOL)
{
sLog.outErrorDb("Creature (Entry: %u) has invalid spell school value (%u) in `DamageSchool`", cInfo->Entry, cInfo->DamageSchool);
const_cast<CreatureInfo*>(cInfo)->DamageSchool = SPELL_SCHOOL_NORMAL;
}
if (cInfo->MeleeAttackPower == 0)
const_cast<CreatureInfo*>(cInfo)->MeleeAttackPower = BASE_ATTACK_TIME;
if (cInfo->RangedAttackPower == 0)
const_cast<CreatureInfo*>(cInfo)->RangedAttackPower = BASE_ATTACK_TIME;
if (cInfo->NpcFlags & UNIT_NPC_FLAG_SPELLCLICK)
{
sLog.outDebug("Creature (Entry: %u) has dynamic flag UNIT_NPC_FLAG_SPELLCLICK (%u) set, but it is expected to be set in run-time based at `npc_spellclick_spells` contents.", cInfo->Entry, UNIT_NPC_FLAG_SPELLCLICK);
const_cast<CreatureInfo*>(cInfo)->npcflag &= ~UNIT_NPC_FLAG_SPELLCLICK;
const_cast<CreatureInfo*>(cInfo)->NpcFlags &= ~UNIT_NPC_FLAG_SPELLCLICK;
}
if ((cInfo->npcflag & UNIT_NPC_FLAG_TRAINER) && cInfo->trainer_type >= MAX_TRAINER_TYPE)
sLog.outErrorDb("Creature (Entry: %u) has wrong trainer type %u", cInfo->Entry, cInfo->trainer_type);
if ((cInfo->NpcFlags & UNIT_NPC_FLAG_TRAINER) && cInfo->TrainerType >= MAX_TRAINER_TYPE)
sLog.outErrorDb("Creature (Entry: %u) has wrong trainer type %u", cInfo->Entry, cInfo->TrainerType);
if (cInfo->type && !sCreatureTypeStore.LookupEntry(cInfo->type))
if (cInfo->CreatureType && !sCreatureTypeStore.LookupEntry(cInfo->CreatureType))
{
sLog.outErrorDb("Creature (Entry: %u) has invalid creature type (%u) in `type`", cInfo->Entry, cInfo->type);
const_cast<CreatureInfo*>(cInfo)->type = CREATURE_TYPE_HUMANOID;
sLog.outErrorDb("Creature (Entry: %u) has invalid creature type (%u) in `type`", cInfo->Entry, cInfo->CreatureType);
const_cast<CreatureInfo*>(cInfo)->CreatureType = CREATURE_TYPE_HUMANOID;
}
// must exist or used hidden but used in data horse case
if (cInfo->family && !sCreatureFamilyStore.LookupEntry(cInfo->family) && cInfo->family != CREATURE_FAMILY_HORSE_CUSTOM)
if (cInfo->Family && !sCreatureFamilyStore.LookupEntry(cInfo->Family) && cInfo->Family != CREATURE_FAMILY_HORSE_CUSTOM)
{
sLog.outErrorDb("Creature (Entry: %u) has invalid creature family (%u) in `family`", cInfo->Entry, cInfo->family);
const_cast<CreatureInfo*>(cInfo)->family = 0;
sLog.outErrorDb("Creature (Entry: %u) has invalid creature family (%u) in `Family`", cInfo->Entry, cInfo->Family);
const_cast<CreatureInfo*>(cInfo)->Family = 0;
}
if (cInfo->InhabitType <= 0 || cInfo->InhabitType > INHABIT_ANYWHERE)
@ -716,10 +749,10 @@ void ObjectMgr::LoadCreatureTemplates()
}
}
if (cInfo->vendorId > 0)
if (cInfo->VendorTemplateId > 0)
{
if (!(cInfo->npcflag & UNIT_NPC_FLAG_VENDOR))
sLog.outErrorDb("Table `creature_template` have creature (Entry: %u) with vendor_id %u but not have flag UNIT_NPC_FLAG_VENDOR (%u), vendor items will ignored.", cInfo->Entry, cInfo->vendorId, UNIT_NPC_FLAG_VENDOR);
if (!(cInfo->NpcFlags & UNIT_NPC_FLAG_VENDOR))
sLog.outErrorDb("Table `creature_template` have creature (Entry: %u) with vendor_id %u but not have flag UNIT_NPC_FLAG_VENDOR (%u), vendor items will ignored.", cInfo->Entry, cInfo->VendorTemplateId, UNIT_NPC_FLAG_VENDOR);
}
/// if not set custom creature Scale then load Scale from CreatureDisplayInfo.dbc
@ -948,6 +981,19 @@ void ObjectMgr::LoadCreatureClassLvlStats()
sLog.outString(">> Loaded %u creature class level stats definitions.", DataCount);
}
CreatureClassLvlStats const* ObjectMgr::GetCreatureClassLvlStats(uint32 level, uint32 unitClass, int32 expansion) const
{
if (expansion < 0)
return nullptr;
CreatureClassLvlStats const* cCLS = &m_creatureClassLvlStats[level][classToIndex[unitClass]][expansion];
if (cCLS->BaseHealth != 0 && cCLS->BaseDamage > 0.1f)
return cCLS;
return nullptr;
}
void ObjectMgr::LoadEquipmentTemplates()
{
sEquipmentStorage.Load();
@ -1401,30 +1447,30 @@ void ObjectMgr::LoadCreatures()
}
}
if (cInfo->RegenHealth && data.curhealth < cInfo->minhealth)
if (cInfo->RegenerateStats & REGEN_FLAG_HEALTH && data.curhealth < cInfo->MinLevelHealth)
{
sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`RegenHealth`=1 and low current health (%u), `creature_template`.`minhealth`=%u.", guid, data.id, data.curhealth, cInfo->minhealth);
data.curhealth = cInfo->minhealth;
sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`RegenHealth`=1 and low current health (%u), `creature_template`.`MinLevelHealth`=%u.", guid, data.id, data.curhealth, cInfo->MinLevelHealth);
data.curhealth = cInfo->MinLevelHealth;
}
if (cInfo->ExtraFlags & CREATURE_FLAG_EXTRA_INSTANCE_BIND)
if (cInfo->ExtraFlags & CREATURE_EXTRA_FLAG_INSTANCE_BIND)
{
if (!mapEntry || !mapEntry->IsDungeon())
sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`ExtraFlags` including CREATURE_FLAG_EXTRA_INSTANCE_BIND (%u) but creature are not in instance.",
guid, data.id, CREATURE_FLAG_EXTRA_INSTANCE_BIND);
sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`ExtraFlags` including CREATURE_EXTRA_FLAG_INSTANCE_BIND (%u) but creature are not in instance.",
guid, data.id, CREATURE_EXTRA_FLAG_INSTANCE_BIND);
}
if (cInfo->ExtraFlags & CREATURE_FLAG_EXTRA_AGGRO_ZONE)
if (cInfo->ExtraFlags & CREATURE_EXTRA_FLAG_AGGRO_ZONE)
{
if (!mapEntry || !mapEntry->IsDungeon())
sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`ExtraFlags` including CREATURE_FLAG_EXTRA_AGGRO_ZONE (%u) but creature are not in instance.",
guid, data.id, CREATURE_FLAG_EXTRA_AGGRO_ZONE);
sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`ExtraFlags` including CREATURE_EXTRA_FLAG_AGGRO_ZONE (%u) but creature are not in instance.",
guid, data.id, CREATURE_EXTRA_FLAG_AGGRO_ZONE);
}
if (data.curmana < cInfo->minmana)
if (data.curmana < cInfo->MinLevelMana)
{
sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with low current mana (%u), `creature_template`.`minmana`=%u.", guid, data.id, data.curmana, cInfo->minmana);
data.curmana = cInfo->minmana;
sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with low current mana (%u), `creature_template`.`MinLevelMana`=%u.", guid, data.id, data.curmana, cInfo->MinLevelMana);
data.curmana = cInfo->MinLevelMana;
}
if (data.spawndist < 0.0f)
@ -6601,7 +6647,7 @@ std::string ObjectMgr::GeneratePetName(uint32 entry)
if (list0.empty() || list1.empty())
{
CreatureInfo const* cinfo = GetCreatureTemplate(entry);
char const* petname = GetPetName(cinfo->family, sWorld.GetDefaultDbcLocale());
char const* petname = GetPetName(cinfo->Family, sWorld.GetDefaultDbcLocale());
if (!petname)
petname = cinfo->Name;
return std::string(petname);
@ -7340,7 +7386,7 @@ void ObjectMgr::LoadNPCSpellClickSpells()
mSpellClickInfoMap.insert(SpellClickInfoMap::value_type(npc_entry, info));
// mark creature template as spell clickable
const_cast<CreatureInfo*>(cInfo)->npcflag |= UNIT_NPC_FLAG_SPELLCLICK;
const_cast<CreatureInfo*>(cInfo)->NpcFlags |= UNIT_NPC_FLAG_SPELLCLICK;
++count;
}
@ -7544,8 +7590,8 @@ void ObjectMgr::LoadCreatureQuestRelations()
CreatureInfo const* cInfo = GetCreatureTemplate(itr->first);
if (!cInfo)
sLog.outErrorDb("Table `creature_questrelation` have data for nonexistent creature entry (%u) and existing quest %u", itr->first, itr->second);
else if (!(cInfo->npcflag & UNIT_NPC_FLAG_QUESTGIVER))
sLog.outErrorDb("Table `creature_questrelation` has creature entry (%u) for quest %u, but npcflag does not include UNIT_NPC_FLAG_QUESTGIVER", itr->first, itr->second);
else if (!(cInfo->NpcFlags & UNIT_NPC_FLAG_QUESTGIVER))
sLog.outErrorDb("Table `creature_questrelation` has creature entry (%u) for quest %u, but NpcFlags does not include UNIT_NPC_FLAG_QUESTGIVER", itr->first, itr->second);
}
}
@ -7558,8 +7604,8 @@ void ObjectMgr::LoadCreatureInvolvedRelations()
CreatureInfo const* cInfo = GetCreatureTemplate(itr->first);
if (!cInfo)
sLog.outErrorDb("Table `creature_involvedrelation` have data for nonexistent creature entry (%u) and existing quest %u", itr->first, itr->second);
else if (!(cInfo->npcflag & UNIT_NPC_FLAG_QUESTGIVER))
sLog.outErrorDb("Table `creature_involvedrelation` has creature entry (%u) for quest %u, but npcflag does not include UNIT_NPC_FLAG_QUESTGIVER", itr->first, itr->second);
else if (!(cInfo->NpcFlags & UNIT_NPC_FLAG_QUESTGIVER))
sLog.outErrorDb("Table `creature_involvedrelation` has creature entry (%u) for quest %u, but NpcFlags does not include UNIT_NPC_FLAG_QUESTGIVER", itr->first, itr->second);
}
}
@ -7997,10 +8043,10 @@ bool ObjectMgr::LoadMangosStrings(DatabaseType& db, char const* table, int32 min
// Load additional string content if necessary
if (extra_content)
{
data.SoundId = fields[10].GetUInt32();
data.Type = fields[11].GetUInt32();
data.LanguageId = (Language)fields[12].GetUInt32();
data.Emote = fields[13].GetUInt32();
data.SoundId = fields[10].GetUInt32();
data.Type = fields[11].GetUInt32();
data.LanguageId = Language(fields[12].GetUInt32());
data.Emote = fields[13].GetUInt32();
if (data.SoundId && !sSoundEntriesStore.LookupEntry(data.SoundId))
{
@ -8010,7 +8056,7 @@ bool ObjectMgr::LoadMangosStrings(DatabaseType& db, char const* table, int32 min
if (!GetLanguageDescByID(data.LanguageId))
{
_DoStringError(entry, "Entry %i in table `%s` using Language %u but Language does not exist.", entry, table, data.LanguageId);
_DoStringError(entry, "Entry %i in table `%s` using Language %u but Language does not exist.", entry, table, uint32(data.LanguageId));
data.LanguageId = LANG_UNIVERSAL;
}
@ -9237,7 +9283,7 @@ void ObjectMgr::LoadTrainers(char const* tableName, bool isTemplates)
continue;
}
if (!(cInfo->npcflag & UNIT_NPC_FLAG_TRAINER))
if (!(cInfo->NpcFlags & UNIT_NPC_FLAG_TRAINER))
{
if (skip_trainers.find(entry) == skip_trainers.end())
{
@ -9247,11 +9293,11 @@ void ObjectMgr::LoadTrainers(char const* tableName, bool isTemplates)
continue;
}
if (TrainerSpellData const* tSpells = cInfo->trainerId ? GetNpcTrainerTemplateSpells(cInfo->trainerId) : NULL)
if (TrainerSpellData const* tSpells = cInfo->TrainerTemplateId ? GetNpcTrainerTemplateSpells(cInfo->TrainerTemplateId) : NULL)
{
if (tSpells->spellList.find(spell) != tSpells->spellList.end())
{
sLog.outErrorDb("Table `%s` (Entry: %u) has spell %u listed in trainer template %u, ignore", tableName, entry, spell, cInfo->trainerId);
sLog.outErrorDb("Table `%s` (Entry: %u) has spell %u listed in trainer template %u, ignore", tableName, entry, spell, cInfo->TrainerTemplateId);
continue;
}
}
@ -9349,12 +9395,12 @@ void ObjectMgr::LoadTrainerTemplates()
{
if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
{
if (cInfo->trainerId)
if (cInfo->TrainerTemplateId)
{
if (m_mCacheTrainerTemplateSpellMap.find(cInfo->trainerId) != m_mCacheTrainerTemplateSpellMap.end())
trainer_ids.erase(cInfo->trainerId);
if (m_mCacheTrainerTemplateSpellMap.find(cInfo->TrainerTemplateId) != m_mCacheTrainerTemplateSpellMap.end())
trainer_ids.erase(cInfo->TrainerTemplateId);
else
sLog.outErrorDb("Creature (Entry: %u) has trainer_id = %u for nonexistent trainer template", cInfo->Entry, cInfo->trainerId);
sLog.outErrorDb("Creature (Entry: %u) has trainer_id = %u for nonexistent trainer template", cInfo->Entry, cInfo->TrainerTemplateId);
}
}
}
@ -9433,12 +9479,12 @@ void ObjectMgr::LoadVendorTemplates()
{
if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
{
if (cInfo->vendorId)
if (cInfo->VendorTemplateId)
{
if (m_mCacheVendorTemplateItemMap.find(cInfo->vendorId) != m_mCacheVendorTemplateItemMap.end())
vendor_ids.erase(cInfo->vendorId);
if (m_mCacheVendorTemplateItemMap.find(cInfo->VendorTemplateId) != m_mCacheVendorTemplateItemMap.end())
vendor_ids.erase(cInfo->VendorTemplateId);
else
sLog.outErrorDb("Creature (Entry: %u) has vendor_id = %u for nonexistent vendor template", cInfo->Entry, cInfo->vendorId);
sLog.outErrorDb("Creature (Entry: %u) has vendor_id = %u for nonexistent vendor template", cInfo->Entry, cInfo->VendorTemplateId);
}
}
}
@ -9593,7 +9639,7 @@ void ObjectMgr::LoadGossipMenuItems(std::set<uint32>& gossipScriptSet)
m_mGossipMenuItemsMap.clear();
QueryResult* result = WorldDatabase.Query(
"SELECT menu_id, id, option_icon, option_text, option_id, npc_option_npcflag, "
"SELECT menu_id, id, option_icon, option_text, option_id, npc_option_NpcFlags, "
"action_menu_id, action_poi_id, action_script_id, box_coded, box_money, box_text, "
"condition_id "
"FROM gossip_menu_option ORDER BY menu_id, id");
@ -9654,7 +9700,7 @@ void ObjectMgr::LoadGossipMenuItems(std::set<uint32>& gossipScriptSet)
gMenuItem.option_icon = fields[2].GetUInt8();
gMenuItem.option_text = fields[3].GetCppString();
gMenuItem.option_id = fields[4].GetUInt32();
gMenuItem.npc_option_npcflag = fields[5].GetUInt32();
gMenuItem.npc_option_NpcFlags = fields[5].GetUInt32();
gMenuItem.action_menu_id = fields[6].GetInt32();
gMenuItem.action_poi_id = fields[7].GetUInt32();
gMenuItem.action_script_id = fields[8].GetUInt32();
@ -9693,7 +9739,7 @@ void ObjectMgr::LoadGossipMenuItems(std::set<uint32>& gossipScriptSet)
if (gMenuItem.option_id >= GOSSIP_OPTION_MAX)
sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u has unknown option id %u. Option will not be used", gMenuItem.menu_id, gMenuItem.id, gMenuItem.option_id);
if (gMenuItem.menu_id && gMenuItem.npc_option_npcflag)
if (gMenuItem.menu_id && gMenuItem.npc_option_NpcFlags)
{
bool found_menu_uses = false;
bool found_flags_uses = false;
@ -9706,12 +9752,12 @@ void ObjectMgr::LoadGossipMenuItems(std::set<uint32>& gossipScriptSet)
found_menu_uses = true;
// some from creatures with gossip menu can use gossip option base at npc_flags
if (gMenuItem.npc_option_npcflag & cInfo->npcflag)
if (gMenuItem.npc_option_NpcFlags & cInfo->NpcFlags)
found_flags_uses = true;
}
if (found_menu_uses && !found_flags_uses)
sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u has `npc_option_npcflag` = %u but creatures using this menu does not have corresponding`npcflag`. Option will not accessible in game.", gMenuItem.menu_id, gMenuItem.id, gMenuItem.npc_option_npcflag);
sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u has `npc_option_NpcFlags` = %u but creatures using this menu does not have corresponding`NpcFlags`. Option will not accessible in game.", gMenuItem.menu_id, gMenuItem.id, gMenuItem.npc_option_NpcFlags);
}
if (gMenuItem.action_poi_id && !GetPointOfInterest(gMenuItem.action_poi_id))
@ -9820,7 +9866,7 @@ bool ObjectMgr::IsVendorItemValid(bool isTemplate, char const* tableName, uint32
return false;
}
if (!(cInfo->npcflag & UNIT_NPC_FLAG_VENDOR))
if (!(cInfo->NpcFlags & UNIT_NPC_FLAG_VENDOR))
{
if (!skip_vendors || skip_vendors->count(vendor_entry) == 0)
{
@ -9923,12 +9969,12 @@ bool ObjectMgr::IsVendorItemValid(bool isTemplate, char const* tableName, uint32
}
else
{
if (!cInfo->vendorId)
if (!cInfo->VendorTemplateId)
sLog.outErrorDb("Table `%s` has duplicate items %u for %s %u, ignoring",
tableName, item_id, idStr, vendor_entry);
else
sLog.outErrorDb("Table `%s` has duplicate items %u for %s %u (or possible in vendor template %u), ignoring",
tableName, item_id, idStr, vendor_entry, cInfo->vendorId);
tableName, item_id, idStr, vendor_entry, cInfo->VendorTemplateId);
}
return false;
}
@ -9974,7 +10020,7 @@ bool ObjectMgr::IsVendorItemValid(bool isTemplate, char const* tableName, uint32
return false;
}
if (!(cInfo->npcflag & UNIT_NPC_FLAG_VENDOR))
if (!(cInfo->NpcFlags & UNIT_NPC_FLAG_VENDOR))
{
if (!skip_vendors || skip_vendors->count(vendor_entry) == 0)
{
@ -10111,12 +10157,12 @@ bool ObjectMgr::IsVendorItemValid(bool isTemplate, char const* tableName, uint32
ChatHandler(pl).PSendSysMessage(LANG_ITEM_ALREADY_IN_LIST, item_id, type == VENDOR_ITEM_TYPE_CURRENCY, ExtendedCost);
else
{
if (!cInfo->vendorId)
if (!cInfo->VendorTemplateId)
sLog.outErrorDb("Table `%s` has duplicate %s %u (with extended cost %u) for %s %u, ignoring",
tableName, nameStr, item_id, ExtendedCost, idStr, vendor_entry);
else
sLog.outErrorDb("Table `%s` has duplicate %s %u (with extended cost %u) for %s %u (or possible in vendor template %u), ignoring",
tableName, nameStr, item_id, ExtendedCost, idStr, vendor_entry, cInfo->vendorId);
tableName, nameStr, item_id, ExtendedCost, idStr, vendor_entry, cInfo->VendorTemplateId);
}
return false;
}
@ -10366,47 +10412,13 @@ bool DoDisplayText(WorldObject* source, int32 entry, Unit const* target /*=NULL*
}
}
switch (data->Type)
if ((data->Type == CHAT_TYPE_WHISPER || data->Type == CHAT_TYPE_BOSS_WHISPER) && (!target || target->GetTypeId() != TYPEID_PLAYER))
{
case CHAT_TYPE_SAY:
source->MonsterSay(entry, data->LanguageId, target);
break;
case CHAT_TYPE_YELL:
source->MonsterYell(entry, data->LanguageId, target);
break;
case CHAT_TYPE_TEXT_EMOTE:
source->MonsterTextEmote(entry, target);
break;
case CHAT_TYPE_BOSS_EMOTE:
source->MonsterTextEmote(entry, target, true);
break;
case CHAT_TYPE_WHISPER:
{
if (target && target->GetTypeId() == TYPEID_PLAYER)
source->MonsterWhisper(entry, target);
else
{
_DoStringError(entry, "DoDisplayText entry %i cannot whisper without target unit (TYPEID_PLAYER).", entry);
return false;
}
break;
}
case CHAT_TYPE_BOSS_WHISPER:
{
if (target && target->GetTypeId() == TYPEID_PLAYER)
source->MonsterWhisper(entry, target, true);
else
{
_DoStringError(entry, "DoDisplayText entry %i cannot whisper without target unit (TYPEID_PLAYER).", entry);
return false;
}
break;
}
case CHAT_TYPE_ZONE_YELL:
source->MonsterYellToZone(entry, data->LanguageId, target);
break;
_DoStringError(entry, "DoDisplayText entry %i cannot whisper without target unit (TYPEID_PLAYER).", entry);
return false;
}
source->MonsterText(data, target);
return true;
}

View file

@ -132,7 +132,7 @@ typedef UNORDERED_MAP < uint32/*(mapid,spawnMode) pair*/, CellObjectGuidsMap > M
#define MIN_MANGOS_STRING_ID 1 // 'mangos_string'
#define MAX_MANGOS_STRING_ID 2000000000
#define MIN_DB_SCRIPT_STRING_ID MAX_MANGOS_STRING_ID // 'db_script_string'
#define MAX_DB_SCRIPT_STRING_ID 2000010000
#define MAX_DB_SCRIPT_STRING_ID 2001000000
#define MIN_CREATURE_AI_TEXT_STRING_ID (-1) // 'creature_ai_texts'
#define MAX_CREATURE_AI_TEXT_STRING_ID (-1000000)
// Anything below MAX_CREATURE_AI_TEXT_STRING_ID is handled by the external script lib
@ -283,7 +283,7 @@ struct GossipMenuItems
uint8 option_icon;
std::string option_text;
uint32 option_id;
uint32 npc_option_npcflag;
uint32 npc_option_NpcFlags;
int32 action_menu_id;
uint32 action_poi_id;
uint32 action_script_id;
@ -1191,6 +1191,19 @@ class ObjectMgr
QuestRelationsMap& GetCreatureQuestRelationsMap() { return m_CreatureQuestRelations; }
uint32 GetModelForRace(uint32 sourceModelId, uint32 racemask);
/**
* \brief: Data returned is used to compute health, mana, armor, damage of creatures. May be nullptr.
* \param uint32 level creature level
* \param uint32 unitClass creature class, related to CLASSMASK_ALL_CREATURES
* \param uint32 expansion creature expansion (we could have creature exp = 0 for wotlk as well as exp = 1 or exp = 2)
* \return: CreatureClassLvlStats const* or nullptr
*
* Description: GetCreatureClassLvlStats give fast access to creature stats data.
* FullName: ObjectMgr::GetCreatureClassLvlStats
* Access: public
* Qualifier: const
**/
CreatureClassLvlStats const* GetCreatureClassLvlStats(uint32 level, uint32 unitClass, int32 expansion) const;
void LoadHotfixData();
HotfixData const& GetHotfixData() const { return m_hotfixData; }

View file

@ -180,7 +180,7 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petentry, uint32 petnumber, bool c
// reget for sure use real creature info selected for Pet at load/creating
CreatureInfo const* cinfo = GetCreatureInfo();
if (cinfo->type == CREATURE_TYPE_CRITTER)
if (cinfo->CreatureType == CREATURE_TYPE_CRITTER)
{
AIM_Initialize();
pos.GetMap()->Add((Creature*)this);
@ -817,7 +817,7 @@ bool Pet::CreateBaseAtCreature(Creature* creature)
return false;
}
if (cinfo->type == CREATURE_TYPE_CRITTER)
if (cinfo->CreatureType == CREATURE_TYPE_CRITTER)
{
setPetType(MINI_PET);
return true;
@ -830,12 +830,12 @@ bool Pet::CreateBaseAtCreature(Creature* creature)
SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, sObjectMgr.GetXPForPetLevel(creature->getLevel()));
SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
if (CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->family))
if (CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->Family))
SetName(cFamily->Name[sWorld.GetDefaultDbcLocale()]);
else
SetName(creature->GetNameForLocaleIdx(sObjectMgr.GetDBCLocaleIndex()));
if (cinfo->type == CREATURE_TYPE_BEAST)
if (cinfo->CreatureType == CREATURE_TYPE_BEAST)
{
SetByteValue(UNIT_FIELD_BYTES_0, 1, CLASS_WARRIOR);
SetByteValue(UNIT_FIELD_BYTES_0, 2, GENDER_NONE);
@ -889,7 +889,7 @@ bool Pet::InitStatsForLevel(uint32 petlevel, Unit* owner)
SetLevel(petlevel);
SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool));
SetMeleeDamageSchool(SpellSchools(cinfo->DamageSchool));
SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(petlevel * 50));
@ -899,7 +899,7 @@ bool Pet::InitStatsForLevel(uint32 petlevel, Unit* owner)
SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0);
CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->family);
CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->Family);
if (cFamily && cFamily->minScale > 0.0f && getPetType() == HUNTER_PET)
{
float Scale;
@ -919,12 +919,12 @@ bool Pet::InitStatsForLevel(uint32 petlevel, Unit* owner)
if (getPetType() != HUNTER_PET)
{
createResistance[SPELL_SCHOOL_HOLY] = cinfo->resistance1;
createResistance[SPELL_SCHOOL_FIRE] = cinfo->resistance2;
createResistance[SPELL_SCHOOL_NATURE] = cinfo->resistance3;
createResistance[SPELL_SCHOOL_FROST] = cinfo->resistance4;
createResistance[SPELL_SCHOOL_SHADOW] = cinfo->resistance5;
createResistance[SPELL_SCHOOL_ARCANE] = cinfo->resistance6;
createResistance[SPELL_SCHOOL_HOLY] = cinfo->ResistanceHoly;
createResistance[SPELL_SCHOOL_FIRE] = cinfo->ResistanceFire;
createResistance[SPELL_SCHOOL_NATURE] = cinfo->ResistanceNature;
createResistance[SPELL_SCHOOL_FROST] = cinfo->ResistanceFrost;
createResistance[SPELL_SCHOOL_SHADOW] = cinfo->ResistanceShadow;
createResistance[SPELL_SCHOOL_ARCANE] = cinfo->ResistanceArcane;
}
switch (getPetType())
@ -985,8 +985,8 @@ bool Pet::InitStatsForLevel(uint32 petlevel, Unit* owner)
sLog.outErrorDb("Summoned pet (Entry: %u) not have pet stats data in DB", cinfo->Entry);
// remove elite bonuses included in DB values
SetCreateHealth(uint32(((float(cinfo->maxhealth) / cinfo->maxlevel) / (1 + 2 * cinfo->Rank)) * petlevel));
SetCreateMana(uint32(((float(cinfo->maxmana) / cinfo->maxlevel) / (1 + 2 * cinfo->Rank)) * petlevel));
SetCreateHealth(uint32(((float(cinfo->MaxLevelHealth) / cinfo->MaxLevel) / (1 + 2 * cinfo->Rank)) * petlevel));
SetCreateMana(uint32(((float(cinfo->MaxLevelMana) / cinfo->MaxLevel) / (1 + 2 * cinfo->Rank)) * petlevel));
SetCreateStat(STAT_STRENGTH, 22);
SetCreateStat(STAT_AGILITY, 22);
@ -1024,7 +1024,7 @@ bool Pet::InitStatsForLevel(uint32 petlevel, Unit* owner)
sLog.outErrorDb("Hunter pet levelstats missing in DB");
// remove elite bonuses included in DB values
SetCreateHealth(uint32(((float(cinfo->maxhealth) / cinfo->maxlevel) / (1 + 2 * cinfo->Rank)) * petlevel));
SetCreateHealth(uint32(((float(cinfo->MaxLevelHealth) / cinfo->MaxLevel) / (1 + 2 * cinfo->Rank)) * petlevel));
SetCreateStat(STAT_STRENGTH, 22);
SetCreateStat(STAT_AGILITY, 22);
@ -1074,7 +1074,7 @@ bool Pet::HaveInDiet(ItemPrototype const* item) const
if (!cInfo)
return false;
CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cInfo->family);
CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cInfo->Family);
if (!cFamily)
return false;
@ -1563,7 +1563,7 @@ void Pet::InitLevelupSpellsForLevel()
{
uint32 level = getLevel();
if (PetLevelupSpellSet const* levelupSpells = GetCreatureInfo()->family ? sSpellMgr.GetPetLevelupSpellList(GetCreatureInfo()->family) : NULL)
if (PetLevelupSpellSet const* levelupSpells = GetCreatureInfo()->Family ? sSpellMgr.GetPetLevelupSpellList(GetCreatureInfo()->Family) : NULL)
{
// PetLevelupSpellSet ordered by levels, process in reversed order
for (PetLevelupSpellSet::const_reverse_iterator itr = levelupSpells->rbegin(); itr != levelupSpells->rend(); ++itr)
@ -1702,7 +1702,7 @@ bool Pet::resetTalents(bool no_cost)
if (!ci)
return false;
// Check pet talent type
CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->family);
CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->Family);
if (!pet_family || pet_family->petTalentType < 0)
return false;
@ -1961,9 +1961,9 @@ bool Pet::IsPermanentPetFor(Player* owner)
// oddly enough, Mage's Water Elemental is still treated as temporary pet with Glyph of Eternal Water
// i.e. does not unsummon at mounting, gets dismissed at teleport etc.
case CLASS_WARLOCK:
return GetCreatureInfo()->type == CREATURE_TYPE_DEMON;
return GetCreatureInfo()->CreatureType == CREATURE_TYPE_DEMON;
case CLASS_DEATH_KNIGHT:
return GetCreatureInfo()->type == CREATURE_TYPE_UNDEAD;
return GetCreatureInfo()->CreatureType == CREATURE_TYPE_UNDEAD;
default:
return false;
}
@ -2012,7 +2012,7 @@ void Pet::LearnPetPassives()
if (!cInfo)
return;
CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cInfo->family);
CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cInfo->Family);
if (!cFamily)
return;

View file

@ -168,7 +168,7 @@ class Pet : public Creature
return m_autospells[pos];
}
bool CanSwim() const override
bool CanSwim() const
{
Unit const* owner = GetOwner();
if (owner)

View file

@ -1526,7 +1526,7 @@ bool Player::BuildEnumData(QueryResult* result, ByteBuffer* data, ByteBuffer* bu
{
petDisplayId = fields[17].GetUInt32();
petLevel = fields[18].GetUInt32();
petFamily = cInfo->family;
petFamily = cInfo->Family;
}
}
@ -1644,9 +1644,9 @@ void Player::ToggleDND()
ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_DND);
}
uint8 Player::GetChatTag() const
ChatTagFlags Player::GetChatTag() const
{
uint8 tag = CHAT_TAG_NONE;
ChatTagFlags tag = CHAT_TAG_NONE;
if (isAFK())
tag |= CHAT_TAG_AFK;
@ -2291,7 +2291,7 @@ void Player::RegenerateHealth(uint32 diff)
ModifyHealth(int32(addvalue));
}
Creature* Player::GetNPCIfCanInteractWith(ObjectGuid guid, uint32 npcflagmask)
Creature* Player::GetNPCIfCanInteractWith(ObjectGuid guid, uint32 NpcFlagsmask)
{
// some basic checks
if (!guid || !IsInWorld() || IsTaxiFlying())
@ -2307,10 +2307,10 @@ Creature* Player::GetNPCIfCanInteractWith(ObjectGuid guid, uint32 npcflagmask)
return NULL;
// appropriate npc type
if (npcflagmask && !unit->HasFlag(UNIT_NPC_FLAGS, npcflagmask))
if (NpcFlagsmask && !unit->HasFlag(UNIT_NPC_FLAGS, NpcFlagsmask))
return NULL;
if (npcflagmask == UNIT_NPC_FLAG_STABLEMASTER)
if (NpcFlagsmask == UNIT_NPC_FLAG_STABLEMASTER)
{
if (getClass() != CLASS_HUNTER)
return NULL;
@ -5047,7 +5047,7 @@ void Player::CleanupChannels()
{
Channel* ch = *m_channels.begin();
m_channels.erase(m_channels.begin()); // remove from player's channel list
ch->Leave(GetObjectGuid(), false); // not send to client, not remove from player's channel list
ch->Leave(this, false); // not send to client, not remove from player's channel list
if (ChannelMgr* cMgr = channelMgr(GetTeam()))
cMgr->LeftChannel(ch->GetName()); // deleted channel if empty
}
@ -5091,13 +5091,13 @@ void Player::UpdateLocalChannels(uint32 newZone)
if ((*i) != new_channel)
{
new_channel->Join(GetObjectGuid(), ""); // will output Changed Channel: N. Name
new_channel->Join(this, ""); // will output Changed Channel: N. Name
// leave old channel
(*i)->Leave(GetObjectGuid(), false); // not send leave channel, it already replaced at client
(*i)->Leave(this, false); // not send leave channel, it already replaced at client
std::string name = (*i)->GetName(); // store name, (*i)erase in LeftChannel
LeftChannel(*i); // remove from player's channel list
cMgr->LeftChannel(name); // delete if empty
cMgr->LeftChannel(name); // delete if empty // delete if empty
}
}
DEBUG_LOG("Player: channels cleaned up!");
@ -5109,7 +5109,7 @@ void Player::LeaveLFGChannel()
{
if ((*i)->IsLFG())
{
(*i)->Leave(GetObjectGuid());
(*i)->Leave(this);
break;
}
}
@ -8120,7 +8120,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
// generate loot only if ready for open and spawned in world
if (go->getLootState() == GO_READY && go->isSpawned())
{
uint32 lootid = go->GetGOInfo()->GetLootId();
uint32 Lootid = go->GetGOInfo()->GetLootId();
if ((go->GetEntry() == BG_AV_OBJECTID_MINE_N || go->GetEntry() == BG_AV_OBJECTID_MINE_S))
{
if (BattleGround* bg = GetBattleGround())
@ -8149,11 +8149,11 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
loot->FillLoot(zone, LootTemplates_Fishing, this, true);
break;
default:
if (!lootid)
if (!Lootid)
break;
DEBUG_LOG(" send normal GO loot");
loot->FillLoot(lootid, LootTemplates_Gameobject, this, false);
loot->FillLoot(Lootid, LootTemplates_Gameobject, this, false);
loot->generateMoneyLoot(go->GetGOInfo()->MinMoneyLoot, go->GetGOInfo()->MaxMoneyLoot);
if (go->GetGoType() == GAMEOBJECT_TYPE_CHEST && go->GetGOInfo()->chest.groupLootRules)
@ -8313,8 +8313,8 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
creature->lootForPickPocketed = true;
loot->clear();
if (uint32 lootid = creature->GetCreatureInfo()->pickpocketLootId)
loot->FillLoot(lootid, LootTemplates_Pickpocketing, this, false);
if (uint32 Lootid = creature->GetCreatureInfo()->PickpocketLootId)
loot->FillLoot(Lootid, LootTemplates_Pickpocketing, this, false);
// Generate extra money for pick pocket loot
const uint32 a = urand(0, creature->getLevel() / 2);
@ -8344,10 +8344,10 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
creature->lootForBody = true;
loot->clear();
if (uint32 lootid = creature->GetCreatureInfo()->lootid)
loot->FillLoot(lootid, LootTemplates_Creature, recipient, false);
if (uint32 Lootid = creature->GetCreatureInfo()->LootId)
loot->FillLoot(Lootid, LootTemplates_Creature, recipient, false);
loot->generateMoneyLoot(creature->GetCreatureInfo()->mingold, creature->GetCreatureInfo()->maxgold);
loot->generateMoneyLoot(creature->GetCreatureInfo()->MinLootGold, creature->GetCreatureInfo()->MaxLootGold);
if (Group* group = creature->GetGroupLootRecipient())
{
@ -8378,7 +8378,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
{
creature->lootForSkin = true;
loot->clear();
loot->FillLoot(creature->GetCreatureInfo()->SkinLootId, LootTemplates_Skinning, this, false);
loot->FillLoot(creature->GetCreatureInfo()->SkinningLootId, LootTemplates_Skinning, this, false);
// let reopen skinning loot if will closed.
if (!loot->empty())
@ -8474,302 +8474,6 @@ void Player::SendUpdateWorldState(uint32 Field, uint32 Value)
GetSession()->SendPacket(&data);
}
static WorldStatePair AV_world_states[] =
{
{ 0x7ae, 0x1 }, // 1966 7 snowfall n
{ 0x532, 0x1 }, // 1330 8 frostwolfhut hc
{ 0x531, 0x0 }, // 1329 9 frostwolfhut ac
{ 0x52e, 0x0 }, // 1326 10 stormpike firstaid a_a
{ 0x571, 0x0 }, // 1393 11 east frostwolf tower horde assaulted -unused
{ 0x570, 0x0 }, // 1392 12 west frostwolf tower horde assaulted - unused
{ 0x567, 0x1 }, // 1383 13 frostwolfe c
{ 0x566, 0x1 }, // 1382 14 frostwolfw c
{ 0x550, 0x1 }, // 1360 15 irondeep (N) ally
{ 0x544, 0x0 }, // 1348 16 ice grave a_a
{ 0x536, 0x0 }, // 1334 17 stormpike grave h_c
{ 0x535, 0x1 }, // 1333 18 stormpike grave a_c
{ 0x518, 0x0 }, // 1304 19 stoneheart grave a_a
{ 0x517, 0x0 }, // 1303 20 stoneheart grave h_a
{ 0x574, 0x0 }, // 1396 21 unk
{ 0x573, 0x0 }, // 1395 22 iceblood tower horde assaulted -unused
{ 0x572, 0x0 }, // 1394 23 towerpoint horde assaulted - unused
{ 0x56f, 0x0 }, // 1391 24 unk
{ 0x56e, 0x0 }, // 1390 25 iceblood a
{ 0x56d, 0x0 }, // 1389 26 towerp a
{ 0x56c, 0x0 }, // 1388 27 frostwolfe a
{ 0x56b, 0x0 }, // 1387 28 froswolfw a
{ 0x56a, 0x1 }, // 1386 29 unk
{ 0x569, 0x1 }, // 1385 30 iceblood c
{ 0x568, 0x1 }, // 1384 31 towerp c
{ 0x565, 0x0 }, // 1381 32 stoneh tower a
{ 0x564, 0x0 }, // 1380 33 icewing tower a
{ 0x563, 0x0 }, // 1379 34 dunn a
{ 0x562, 0x0 }, // 1378 35 duns a
{ 0x561, 0x0 }, // 1377 36 stoneheart bunker alliance assaulted - unused
{ 0x560, 0x0 }, // 1376 37 icewing bunker alliance assaulted - unused
{ 0x55f, 0x0 }, // 1375 38 dunbaldar south alliance assaulted - unused
{ 0x55e, 0x0 }, // 1374 39 dunbaldar north alliance assaulted - unused
{ 0x55d, 0x0 }, // 1373 40 stone tower d
{ 0x3c6, 0x0 }, // 966 41 unk
{ 0x3c4, 0x0 }, // 964 42 unk
{ 0x3c2, 0x0 }, // 962 43 unk
{ 0x516, 0x1 }, // 1302 44 stoneheart grave a_c
{ 0x515, 0x0 }, // 1301 45 stonheart grave h_c
{ 0x3b6, 0x0 }, // 950 46 unk
{ 0x55c, 0x0 }, // 1372 47 icewing tower d
{ 0x55b, 0x0 }, // 1371 48 dunn d
{ 0x55a, 0x0 }, // 1370 49 duns d
{ 0x559, 0x0 }, // 1369 50 unk
{ 0x558, 0x0 }, // 1368 51 iceblood d
{ 0x557, 0x0 }, // 1367 52 towerp d
{ 0x556, 0x0 }, // 1366 53 frostwolfe d
{ 0x555, 0x0 }, // 1365 54 frostwolfw d
{ 0x554, 0x1 }, // 1364 55 stoneh tower c
{ 0x553, 0x1 }, // 1363 56 icewing tower c
{ 0x552, 0x1 }, // 1362 57 dunn c
{ 0x551, 0x1 }, // 1361 58 duns c
{ 0x54f, 0x0 }, // 1359 59 irondeep (N) horde
{ 0x54e, 0x0 }, // 1358 60 irondeep (N) ally
{ 0x54d, 0x1 }, // 1357 61 mine (S) neutral
{ 0x54c, 0x0 }, // 1356 62 mine (S) horde
{ 0x54b, 0x0 }, // 1355 63 mine (S) ally
{ 0x545, 0x0 }, // 1349 64 iceblood h_a
{ 0x543, 0x1 }, // 1347 65 iceblod h_c
{ 0x542, 0x0 }, // 1346 66 iceblood a_c
{ 0x540, 0x0 }, // 1344 67 snowfall h_a
{ 0x53f, 0x0 }, // 1343 68 snowfall a_a
{ 0x53e, 0x0 }, // 1342 69 snowfall h_c
{ 0x53d, 0x0 }, // 1341 70 snowfall a_c
{ 0x53c, 0x0 }, // 1340 71 frostwolf g h_a
{ 0x53b, 0x0 }, // 1339 72 frostwolf g a_a
{ 0x53a, 0x1 }, // 1338 73 frostwolf g h_c
{ 0x539, 0x0 }, // l33t 74 frostwolf g a_c
{ 0x538, 0x0 }, // 1336 75 stormpike grave h_a
{ 0x537, 0x0 }, // 1335 76 stormpike grave a_a
{ 0x534, 0x0 }, // 1332 77 frostwolf hut h_a
{ 0x533, 0x0 }, // 1331 78 frostwolf hut a_a
{ 0x530, 0x0 }, // 1328 79 stormpike first aid h_a
{ 0x52f, 0x0 }, // 1327 80 stormpike first aid h_c
{ 0x52d, 0x1 }, // 1325 81 stormpike first aid a_c
{ 0x0, 0x0 }
};
static WorldStatePair WS_world_states[] =
{
{ 0x62d, 0x0 }, // 1581 7 alliance flag captures
{ 0x62e, 0x0 }, // 1582 8 horde flag captures
{ 0x609, 0x0 }, // 1545 9 unk, set to 1 on alliance flag pickup...
{ 0x60a, 0x0 }, // 1546 10 unk, set to 1 on horde flag pickup, after drop it's -1
{ 0x60b, 0x2 }, // 1547 11 unk
{ 0x641, 0x3 }, // 1601 12 unk (max flag captures?)
{ 0x922, 0x1 }, // 2338 13 horde (0 - hide, 1 - flag ok, 2 - flag picked up (flashing), 3 - flag picked up (not flashing)
{ 0x923, 0x1 }, // 2339 14 alliance (0 - hide, 1 - flag ok, 2 - flag picked up (flashing), 3 - flag picked up (not flashing)
{ 0x1097, 0x1 }, // 4247 15 show time limit?
{ 0x1098, 0x19 }, // 4248 16 time remaining in minutes
{ 0x0, 0x0 }
};
static WorldStatePair AB_world_states[] =
{
{ 0x6e7, 0x0 }, // 1767 7 stables alliance
{ 0x6e8, 0x0 }, // 1768 8 stables horde
{ 0x6e9, 0x0 }, // 1769 9 unk, ST?
{ 0x6ea, 0x0 }, // 1770 10 stables (show/hide)
{ 0x6ec, 0x0 }, // 1772 11 farm (0 - horde controlled, 1 - alliance controlled)
{ 0x6ed, 0x0 }, // 1773 12 farm (show/hide)
{ 0x6ee, 0x0 }, // 1774 13 farm color
{ 0x6ef, 0x0 }, // 1775 14 gold mine color, may be FM?
{ 0x6f0, 0x0 }, // 1776 15 alliance resources
{ 0x6f1, 0x0 }, // 1777 16 horde resources
{ 0x6f2, 0x0 }, // 1778 17 horde bases
{ 0x6f3, 0x0 }, // 1779 18 alliance bases
{ 0x6f4, 0x7d0 }, // 1780 19 max resources (2000)
{ 0x6f6, 0x0 }, // 1782 20 blacksmith color
{ 0x6f7, 0x0 }, // 1783 21 blacksmith (show/hide)
{ 0x6f8, 0x0 }, // 1784 22 unk, bs?
{ 0x6f9, 0x0 }, // 1785 23 unk, bs?
{ 0x6fb, 0x0 }, // 1787 24 gold mine (0 - horde contr, 1 - alliance contr)
{ 0x6fc, 0x0 }, // 1788 25 gold mine (0 - conflict, 1 - horde)
{ 0x6fd, 0x0 }, // 1789 26 gold mine (1 - show/0 - hide)
{ 0x6fe, 0x0 }, // 1790 27 gold mine color
{ 0x700, 0x0 }, // 1792 28 gold mine color, wtf?, may be LM?
{ 0x701, 0x0 }, // 1793 29 lumber mill color (0 - conflict, 1 - horde contr)
{ 0x702, 0x0 }, // 1794 30 lumber mill (show/hide)
{ 0x703, 0x0 }, // 1795 31 lumber mill color color
{ 0x732, 0x1 }, // 1842 32 stables (1 - uncontrolled)
{ 0x733, 0x1 }, // 1843 33 gold mine (1 - uncontrolled)
{ 0x734, 0x1 }, // 1844 34 lumber mill (1 - uncontrolled)
{ 0x735, 0x1 }, // 1845 35 farm (1 - uncontrolled)
{ 0x736, 0x1 }, // 1846 36 blacksmith (1 - uncontrolled)
{ 0x745, 0x2 }, // 1861 37 unk
{ 0x7a3, 0x708 }, // 1955 38 warning limit (1800)
{ 0x0, 0x0 }
};
static WorldStatePair EY_world_states[] =
{
{ 2753, 0 }, // WORLD_STATE_EY_TOWER_COUNT_HORDE
{ 2752, 0 }, // WORLD_STATE_EY_TOWER_COUNT_ALLIANCE
{ 2733, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_DRAENEI_RUINS_HORDE
{ 2732, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_DRAENEI_RUINS_ALLIANCE
{ 2731, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_DRAENEI_RUINS_NEUTRAL
{ 2730, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_MAGE_TOWER_ALLIANCE
{ 2729, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_MAGE_TOWER_HORDE
{ 2728, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_MAGE_TOWER_NEUTRAL
{ 2727, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_FEL_REAVER_HORDE
{ 2726, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_FEL_REAVER_ALLIANCE
{ 2725, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_FEL_REAVER_NEUTRAL
{ 2724, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_BLOOD_ELF_HORDE
{ 2723, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_BLOOD_ELF_ALLIANCE
{ 2722, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_BLOOD_ELF_NEUTRAL
{ 2757, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_NETHERSTORM_FLAG_READY
{ 2770, 1 }, // WORLD_STATE_EY_NETHERSTORM_FLAG_STATE_HORDE
{ 2769, 1 }, // WORLD_STATE_EY_NETHERSTORM_FLAG_STATE_ALLIANCE
{ 2750, 0 }, // WORLD_STATE_EY_RESOURCES_HORDE
{ 2749, 0 }, // WORLD_STATE_EY_RESOURCES_ALLIANCE
{ 2565, 0x8e }, // global unk -- TODO: move to global world state
{ 3085, 0x17b } // global unk -- TODO: move to global world state
};
static WorldStatePair SI_world_states[] = // Silithus
{
{ 2313, 0 }, // WORLD_STATE_SI_GATHERED_A
{ 2314, 0 }, // WORLD_STATE_SI_GATHERED_H
{ 2317, 0 } // WORLD_STATE_SI_SILITHYST_MAX
};
static WorldStatePair EP_world_states[] = // Eastern Plaguelands
{
{ 2327, 0 }, // WORLD_STATE_EP_TOWER_COUNT_ALLIANCE
{ 2328, 0 }, // WORLD_STATE_EP_TOWER_COUNT_HORDE
{ 2355, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_CROWNGUARD_NEUTRAL
{ 2374, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_CROWNGUARD_CONTEST_ALLIANCE
{ 2375, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_CROWNGUARD_CONTEST_HORDE
{ 2376, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_CROWNGUARD_PROGRESS_ALLIANCE
{ 2377, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_CROWNGUARD_PROGRESS_HORDE
{ 2378, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_CROWNGUARD_ALLIANCE
{ 2379, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_CROWNGUARD_HORDE
{ 2354, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_EASTWALL_ALLIANCE
{ 2356, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_EASTWALL_HORDE
{ 2357, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_EASTWALL_PROGRESS_ALLIANCE
{ 2358, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_EASTWALL_PROGRESS_HORDE
{ 2359, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_EASTWALL_CONTEST_ALLIANCE
{ 2360, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_EASTWALL_CONTEST_HORDE
{ 2361, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_EASTWALL_NEUTRAL
{ 2352, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_NORTHPASS_NEUTRAL
{ 2362, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_NORTHPASS_CONTEST_ALLIANCE
{ 2363, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_NORTHPASS_CONTEST_HORDE
{ 2364, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_NORTHPASS_PROGRESS_ALLIANCE
{ 2365, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_NORTHPASS_PROGRESS_HORDE
{ 2372, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_NORTHPASS_ALLIANCE
{ 2373, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_NORTHPASS_HORDE
{ 2353, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_PLAGUEWOOD_NEUTRAL
{ 2366, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_PLAGUEWOOD_CONTEST_ALLIANCE
{ 2367, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_PLAGUEWOOD_CONTEST_HORDE - not in dbc! sent for consistency's sake, and to match field count
{ 2368, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_PLAGUEWOOD_PROGRESS_ALLIANCE
{ 2369, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_PLAGUEWOOD_PROGRESS_HORDE
{ 2370, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_PLAGUEWOOD_ALLIANCE
{ 2371, WORLD_STATE_REMOVE } // WORLD_STATE_EP_PLAGUEWOOD_HORDE
};
static WorldStatePair HP_world_states[] = // Hellfire Peninsula
{
{ 2490, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_TOWER_DISPLAY_A
{ 2489, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_TOWER_DISPLAY_H
{ 2485, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_BROKEN_HILL_NEUTRAL
{ 2484, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_BROKEN_HILL_HORDE
{ 2483, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_BROKEN_HILL_ALLIANCE
{ 2482, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_OVERLOOK_NEUTRAL
{ 2481, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_OVERLOOK_HORDE
{ 2480, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_OVERLOOK_ALLIANCE
{ 2478, 0 }, // WORLD_STATE_HP_TOWER_COUNT_HORDE
{ 2476, 0 }, // WORLD_STATE_HP_TOWER_COUNT_ALLIANCE
{ 2472, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_STADIUM_NEUTRAL
{ 2471, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_STADIUM_ALLIANCE
{ 2470, WORLD_STATE_REMOVE } // WORLD_STATE_HP_STADIUM_HORDE
};
static WorldStatePair TF_world_states[] = // Terokkar Forest
{
{ 2622, 0 }, // WORLD_STATE_TF_TOWER_COUNT_H
{ 2621, 0 }, // WORLD_STATE_TF_TOWER_COUNT_A
{ 2620, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_TOWERS_CONTROLLED
{ 2695, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_SOUTH_EAST_TOWER_HORDE
{ 2694, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_SOUTH_EAST_TOWER_ALLIANCE
{ 2693, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_SOUTH_TOWER_NEUTRAL
{ 2692, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_SOUTH_TOWER_HORDE
{ 2691, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_SOUTH_TOWER_ALLIANCE
{ 2690, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_EAST_TOWER_NEUTRAL
{ 2689, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_EAST_TOWER_HORDE
{ 2688, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_EAST_TOWER_ALLIANCE
{ 2686, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_NORTH_TOWER_NEUTRAL
{ 2685, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_NORTH_TOWER_HORDE
{ 2684, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_NORTH_TOWER_ALLIANCE
{ 2683, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_WEST_TOWER_ALLIANCE
{ 2682, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_WEST_TOWER_HORDE
{ 2681, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_WEST_TOWER_NEUTRAL
{ 2512, 0 }, // WORLD_STATE_TF_TIME_MIN_FIRST_DIGIT
{ 2510, 0 }, // WORLD_STATE_TF_TIME_MIN_SECOND_DIGIT
{ 2509, 0 }, // WORLD_STATE_TF_TIME_HOURS
{ 2508, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_LOCKED_NEUTRAL
{ 2696, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_SOUTH_EAST_TOWER_NEUTRAL
{ 2768, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_LOCKED_HORDE
{ 2767, WORLD_STATE_REMOVE } // WORLD_STATE_TF_LOCKED_ALLIANCE
};
static WorldStatePair ZM_world_states[] = // Zangarmarsh
{
{ 2653, 0x1 }, // WORLD_STATE_ZM_UNK
{ 2652, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_EAST_NEUTRAL
{ 2651, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_EAST_HORDE
{ 2650, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_EAST_ALLIANCE
{ 2649, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_GRAVEYARD_HORDE
{ 2648, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_GRAVEYARD_ALLIANCE
{ 2647, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_GRAVEYARD_NEUTRAL
{ 2646, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_WEST_NEUTRAL
{ 2645, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_WEST_HORDE
{ 2644, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_WEST_ALLIANCE
{ 2560, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_EAST_UI_NEUTRAL
{ 2559, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_EAST_UI_HORDE
{ 2558, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_EAST_UI_ALLIANCE
{ 2557, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_WEST_UI_NEUTRAL
{ 2556, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_WEST_UI_HORDE
{ 2555, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_WEST_UI_ALLIANCE
{ 2658, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_FLAG_READY_HORDE
{ 2657, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_FLAG_NOT_READY_HORDE
{ 2656, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_FLAG_NOT_READY_ALLIANCE
{ 2655, WORLD_STATE_REMOVE } // WORLD_STATE_ZM_FLAG_READY_ALLIANCE
};
static WorldStatePair NA_world_states[] =
{
{ 2503, 0 }, // WORLD_STATE_NA_GUARDS_HORDE
{ 2502, 0 }, // WORLD_STATE_NA_GUARDS_ALLIANCE
{ 2493, 0 }, // WORLD_STATE_NA_GUARDS_MAX
{ 2491, 0 }, // WORLD_STATE_NA_GUARDS_LEFT
{ 2762, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_NORTH_NEUTRAL_H
{ 2662, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_NORTH_NEUTRAL_A
{ 2663, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_NORTH_H
{ 2664, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_NORTH_A
{ 2760, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_SOUTH_NEUTRAL_H
{ 2670, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_SOUTH_NEUTRAL_A
{ 2668, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_SOUTH_H
{ 2669, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_SOUTH_A
{ 2761, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_WEST_NEUTRAL_H
{ 2667, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_WEST_NEUTRAL_A
{ 2665, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_WEST_H
{ 2666, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_WEST_A
{ 2763, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_EAST_NEUTRAL_H
{ 2659, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_EAST_NEUTRAL_A
{ 2660, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_EAST_H
{ 2661, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_EAST_A
{ 2671, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_HALAA_NEUTRAL
{ 2676, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_HALAA_NEUTRAL_A
{ 2677, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_HALAA_NEUTRAL_H
{ 2672, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_HALAA_HORDE
{ 2673, WORLD_STATE_REMOVE } // WORLD_STATE_NA_HALAA_ALLIANCE
};
void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid)
{
// data depends on zoneid/mapid...
@ -8787,136 +8491,53 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid)
size_t count_pos = data.wpos();
data << uint16(0); // count of uint64 blocks, placeholder
// common fields
FillInitialWorldState(data, count, 0x8d8, 0x0); // 2264 1
FillInitialWorldState(data, count, 0x8d7, 0x0); // 2263 2
FillInitialWorldState(data, count, 0x8d6, 0x0); // 2262 3
FillInitialWorldState(data, count, 0x8d5, 0x0); // 2261 4
FillInitialWorldState(data, count, 0x8d4, 0x0); // 2260 5
FillInitialWorldState(data, count, 0x8d3, 0x0); // 2259 6
// 3191 7 Current arena season
// Current arena season
FillInitialWorldState(data, count, 0xC77, sWorld.getConfig(CONFIG_UINT32_ARENA_SEASON_ID));
// 3901 8 Previous arena season
// Previous arena season
FillInitialWorldState(data, count, 0xF3D, sWorld.getConfig(CONFIG_UINT32_ARENA_SEASON_PREVIOUS_ID));
FillInitialWorldState(data, count, 0xED9, 1); // 3801 9 0 - Battle for Wintergrasp in progress, 1 - otherwise
// 4354 10 Time when next Battle for Wintergrasp starts
FillInitialWorldState(data, count, 0x1102, uint32(time(NULL) + 9000));
if (mapid == 530) // Outland
{
FillInitialWorldState(data, count, 0x9bf, 0x0); // 2495
FillInitialWorldState(data, count, 0x9bd, 0xF); // 2493
FillInitialWorldState(data, count, 0x9bb, 0xF); // 2491
}
// 0 - Battle for Wintergrasp in progress, 1 - otherwise
FillInitialWorldState(data, count, 0xED9, 1);
// Time when next Battle for Wintergrasp starts
FillInitialWorldState(data, count, 0x1102, uint32(time(nullptr) + 9000));
switch (zoneid)
{
case 1: // Dun Morogh
case 11: // Wetlands
case 12: // Elwynn Forest
case 38: // Loch Modan
case 40: // Westfall
case 51: // Searing Gorge
case 1519: // Stormwind City
case 1537: // Ironforge
case 2257: // Deeprun Tram
case 3703: // Shattrath City
break;
case 139: // Eastern Plaguelands
if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(zoneid))
outdoorPvP->FillInitialWorldStates(data, count);
else
FillInitialWorldState(data, count, EP_world_states);
break;
case 1377: // Silithus
case 3483: // Hellfire Peninsula
case 3518: // Nagrand
case 3519: // Terokkar Forest
case 3521: // Zangarmarsh
if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(zoneid))
outdoorPvP->FillInitialWorldStates(data, count);
else
FillInitialWorldState(data, count, SI_world_states);
break;
case 2597: // AV
if (bg && bg->GetTypeID() == BATTLEGROUND_AV)
bg->FillInitialWorldStates(data, count);
else
FillInitialWorldState(data, count, AV_world_states);
break;
case 3277: // WS
if (bg && bg->GetTypeID() == BATTLEGROUND_WS)
bg->FillInitialWorldStates(data, count);
else
FillInitialWorldState(data, count, WS_world_states);
break;
case 3358: // AB
if (bg && bg->GetTypeID() == BATTLEGROUND_AB)
bg->FillInitialWorldStates(data, count);
else
FillInitialWorldState(data, count, AB_world_states);
break;
case 3820: // EY
if (bg && bg->GetTypeID() == BATTLEGROUND_EY)
bg->FillInitialWorldStates(data, count);
else
FillInitialWorldState(data, count, EY_world_states);
break;
case 3483: // Hellfire Peninsula
if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(zoneid))
outdoorPvP->FillInitialWorldStates(data, count);
else
FillInitialWorldState(data, count, HP_world_states);
break;
case 3518: // Nagrand
if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(zoneid))
outdoorPvP->FillInitialWorldStates(data, count);
else
FillInitialWorldState(data, count, NA_world_states);
break;
case 3519: // Terokkar Forest
if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(zoneid))
outdoorPvP->FillInitialWorldStates(data, count);
else
FillInitialWorldState(data, count, TF_world_states);
break;
case 3521: // Zangarmarsh
if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(zoneid))
outdoorPvP->FillInitialWorldStates(data, count);
else
FillInitialWorldState(data, count, ZM_world_states);
break;
case 3698: // Nagrand Arena
if (bg && bg->GetTypeID() == BATTLEGROUND_NA)
bg->FillInitialWorldStates(data, count);
else
{
FillInitialWorldState(data, count, 0xa0f, 0x0); // 2575 7
FillInitialWorldState(data, count, 0xa10, 0x0); // 2576 8
FillInitialWorldState(data, count, 0xa11, 0x0); // 2577 9 show
}
break;
case 3702: // Blade's Edge Arena
if (bg && bg->GetTypeID() == BATTLEGROUND_BE)
bg->FillInitialWorldStates(data, count);
else
{
FillInitialWorldState(data, count, 0x9f0, 0x0); // 2544 7 gold
FillInitialWorldState(data, count, 0x9f1, 0x0); // 2545 8 green
FillInitialWorldState(data, count, 0x9f3, 0x0); // 2547 9 show
}
break;
case 3968: // Ruins of Lordaeron
if (bg && bg->GetTypeID() == BATTLEGROUND_RL)
bg->FillInitialWorldStates(data, count);
else
{
FillInitialWorldState(data, count, 0xbb8, 0x0); // 3000 7 gold
FillInitialWorldState(data, count, 0xbb9, 0x0); // 3001 8 green
FillInitialWorldState(data, count, 0xbba, 0x0); // 3002 9 show
}
break;
default:
FillInitialWorldState(data, count, 0x914, 0x0); // 2324 7
FillInitialWorldState(data, count, 0x913, 0x0); // 2323 8
FillInitialWorldState(data, count, 0x912, 0x0); // 2322 9
FillInitialWorldState(data, count, 0x915, 0x0); // 2325 10
break;
}
@ -13093,9 +12714,9 @@ void Player::PrepareGossipMenu(WorldObject* pSource, uint32 menuId)
{
Creature* pCreature = (Creature*)pSource;
uint32 npcflags = pCreature->GetUInt32Value(UNIT_NPC_FLAGS);
uint32 NpcFlagss = pCreature->GetUInt32Value(UNIT_NPC_FLAGS);
if (!(itr->second.npc_option_npcflag & npcflags))
if (!(itr->second.npc_option_NpcFlags & NpcFlagss))
continue;
switch (itr->second.option_id)
@ -13126,7 +12747,7 @@ void Player::PrepareGossipMenu(WorldObject* pSource, uint32 menuId)
case GOSSIP_OPTION_TRAINER:
// pet trainers not have spells in fact now
/* FIXME: gossip menu with single unlearn pet talents option not show by some reason
if (pCreature->GetCreatureInfo()->trainer_type == TRAINER_TYPE_PETS)
if (pCreature->GetCreatureInfo()->TrainerType == TRAINER_TYPE_PETS)
hasMenuItem = false;
else */
if (!pCreature->IsTrainerOf(this, false))
@ -13137,7 +12758,7 @@ void Player::PrepareGossipMenu(WorldObject* pSource, uint32 menuId)
hasMenuItem = false;
break;
case GOSSIP_OPTION_UNLEARNPETSKILLS:
if (pCreature->GetCreatureInfo()->trainer_type != TRAINER_TYPE_PETS || pCreature->GetCreatureInfo()->trainer_class != CLASS_HUNTER)
if (pCreature->GetCreatureInfo()->TrainerType != TRAINER_TYPE_PETS || pCreature->GetCreatureInfo()->TrainerClass != CLASS_HUNTER)
hasMenuItem = false;
else if (Pet* pet = GetPet())
{
@ -18660,39 +18281,24 @@ void Player::RemovePet(PetSaveMode mode)
pet->Unsummon(mode, this);
}
void Player::BuildPlayerChat(WorldPacket* data, uint8 msgtype, const std::string& text, uint32 language, const char* addonPrefix) const
{
*data << uint8(msgtype);
*data << uint32(language);
*data << GetObjectGuid();
*data << uint32(0); // constant unknown time 4.3.4
if (addonPrefix)
*data << addonPrefix;
else
*data << GetObjectGuid();
*data << uint32(text.length() + 1);
*data << text;
*data << uint8(GetChatTag());
}
void Player::Say(const std::string& text, const uint32 language)
{
WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildPlayerChat(&data, CHAT_MSG_SAY, text, language);
WorldPacket data;
ChatHandler::BuildChatPacket(data, CHAT_MSG_SAY, text.c_str(), Language(language), GetChatTag(), GetObjectGuid(), GetName());
SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY), true);
}
void Player::Yell(const std::string& text, const uint32 language)
{
WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildPlayerChat(&data, CHAT_MSG_YELL, text, language);
WorldPacket data;
ChatHandler::BuildChatPacket(data, CHAT_MSG_YELL, text.c_str(), Language(language), GetChatTag(), GetObjectGuid(), GetName());
SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_YELL), true);
}
void Player::TextEmote(const std::string& text)
{
WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildPlayerChat(&data, CHAT_MSG_EMOTE, text, LANG_UNIVERSAL);
WorldPacket data;
ChatHandler::BuildChatPacket(data, CHAT_MSG_EMOTE, text.c_str(), LANG_UNIVERSAL, GetChatTag(), GetObjectGuid(), GetName());
SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE), true, !sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_CHAT));
}
@ -18700,12 +18306,12 @@ void Player::Whisper(const std::string& text, uint32 language, ObjectGuid receiv
{
Player* rPlayer = sObjectMgr.GetPlayer(receiver);
WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildPlayerChat(&data, CHAT_MSG_WHISPER, text, language);
WorldPacket data;
ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER, text.c_str(), Language(language), GetChatTag(), GetObjectGuid(), GetName());
rPlayer->GetSession()->SendPacket(&data);
data.Initialize(SMSG_MESSAGECHAT, 200);
rPlayer->BuildPlayerChat(&data, CHAT_MSG_WHISPER_INFORM, text, language);
data.clear();
ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER_INFORM, text.c_str(), Language(language), CHAT_TAG_NONE, rPlayer->GetObjectGuid());
GetSession()->SendPacket(&data);
if (!isAcceptWhispers())
@ -18721,17 +18327,6 @@ void Player::Whisper(const std::string& text, uint32 language, ObjectGuid receiv
ChatHandler(this).PSendSysMessage(LANG_PLAYER_DND, rPlayer->GetName(), rPlayer->autoReplyMsg.c_str());
}
void Player::WhisperAddon(const std::string& text, const std::string& prefix, ObjectGuid receiver)
{
Player* rPlayer = sObjectMgr.GetPlayer(receiver);
std::string _text(text);
WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildPlayerChat(&data, CHAT_MSG_WHISPER, _text, LANG_UNIVERSAL, prefix.c_str());
rPlayer->GetSession()->SendPacket(&data);
}
void Player::PetSpellInitialize()
{
Pet* pet = GetPet();
@ -18745,7 +18340,7 @@ void Player::PetSpellInitialize()
WorldPacket data(SMSG_PET_SPELLS, 8 + 2 + 4 + 4 + 4 * MAX_UNIT_ACTION_BAR_INDEX + 1 + 1);
data << pet->GetObjectGuid();
data << uint16(pet->GetCreatureInfo()->family); // creature family (required for pet talents)
data << uint16(pet->GetCreatureInfo()->Family); // creature family (required for pet talents)
data << uint32(0);
data << uint8(charmInfo->GetReactState()) << uint8(charmInfo->GetCommandState()) << uint16(0);
@ -18862,7 +18457,7 @@ void Player::CharmSpellInitialize()
{
CreatureInfo const* cinfo = ((Creature*)charm)->GetCreatureInfo();
if (cinfo && cinfo->type == CREATURE_TYPE_DEMON && getClass() == CLASS_WARLOCK)
if (cinfo && cinfo->CreatureType == CREATURE_TYPE_DEMON && getClass() == CLASS_WARLOCK)
{
for (uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i)
{
@ -21486,7 +21081,7 @@ bool Player::isHonorOrXPTarget(Unit* pVictim) const
{
if (((Creature*)pVictim)->IsTotem() ||
((Creature*)pVictim)->IsPet() ||
((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_NO_XP_AT_KILL)
((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_XP_AT_KILL)
return false;
}
return true;
@ -22808,7 +22403,7 @@ void Player::LearnPetTalent(ObjectGuid petGuid, uint32 talentId, uint32 talentRa
if (!ci)
return;
CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->family);
CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->Family);
if (!pet_family)
return;
@ -23033,7 +22628,7 @@ void Player::BuildPetTalentsInfoData(WorldPacket* data)
if (!ci)
return;
CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->family);
CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->Family);
if (!pet_family || pet_family->petTalentType < 0)
return;

View file

@ -43,6 +43,7 @@
#include "ReputationMgr.h"
#include "BattleGround.h"
#include "SharedDefines.h"
#include "Chat.h"
#include<string>
#include<vector>
@ -1111,20 +1112,15 @@ class Player : public Unit
void SendInitialPacketsAfterAddToMap();
void SendInstanceResetWarning(uint32 mapid, Difficulty difficulty, uint32 time);
Creature* GetNPCIfCanInteractWith(ObjectGuid guid, uint32 npcflagmask);
Creature* GetNPCIfCanInteractWith(ObjectGuid guid, uint32 NpcFlagsmask);
GameObject* GetGameObjectIfCanInteractWith(ObjectGuid guid, uint32 gameobject_type = MAX_GAMEOBJECT_TYPE) const;
void ToggleAFK();
void ToggleDND();
bool isAFK() const
{
return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK);
}
bool isDND() const
{
return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_DND);
}
uint8 GetChatTag() const;
bool isAFK() const { return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK); }
bool isDND() const { return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_DND); }
ChatTagFlags GetChatTag() const;
std::string autoReplyMsg;
uint32 GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 newfacialhair, uint32 newskintone);
@ -1219,8 +1215,6 @@ class Player : public Unit
void Yell(const std::string& text, const uint32 language);
void TextEmote(const std::string& text);
void Whisper(const std::string& text, const uint32 language, ObjectGuid receiver);
void WhisperAddon(const std::string& text, const std::string& prefix, ObjectGuid receiver);
void BuildPlayerChat(WorldPacket* data, uint8 msgtype, const std::string& text, uint32 language, const char* addonPrefix = NULL) const;
/*********************************************************/
/*** STORAGE SYSTEM ***/

View file

@ -757,10 +757,16 @@ bool IsPositiveEffect(SpellEntry const* spellproto, SpellEffectIndex effIndex)
case 18153: // Kodo Kombobulator
case 32312: // Move 1
case 37388: // Move 2
case 45863: // Cosmetic - Incinerate to Random Target
case 49634: // Sergeant's Flare
case 54530: // Opening
case 56099: // Throw Ice
case 56099: // Throw Ice
case 58533: // Return to Stormwind
case 58552: // Return to Orgrimmar
case 62105: // To'kini's Blowgun
case 63745: // Sara's Blessing
case 63747: // Sara's Fervor
case 64402: // Rocket Strike
return true;
default:
break;
@ -2220,6 +2226,11 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) cons
if ((spellInfo_1->Id == 62169 && spellInfo_2->Id == 64417) ||
(spellInfo_2->Id == 62169 && spellInfo_1->Id == 64417))
return false;
// Auto Grow and Healthy Spore Visual
if ((spellInfo_1->Id == 62559 && spellInfo_2->Id == 62538) ||
(spellInfo_2->Id == 62559 && spellInfo_1->Id == 62538))
return false;
break;
}
case SPELLFAMILY_MAGE:
@ -3523,9 +3534,9 @@ void SpellMgr::LoadSpellScriptTarget()
}
if (const CreatureInfo* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(itr->targetEntry))
{
if (itr->spellId == 30427 && !cInfo->SkinLootId)
if (itr->spellId == 30427 && !cInfo->SkinningLootId)
{
sLog.outErrorDb("Table `spell_script_target` has creature %u as a target of spellid 30427, but this creature has no skinlootid. Gas extraction will not work!", cInfo->Entry);
sLog.outErrorDb("Table `spell_script_target` has creature %u as a target of spellid 30427, but this creature has no skinLootid. Gas extraction will not work!", cInfo->Entry);
sSpellScriptTargetStorage.EraseEntry(itr->spellId);
continue;
}
@ -3710,7 +3721,7 @@ bool SpellMgr::LoadPetDefaultSpells_helper(CreatureInfo const* cInfo, PetDefault
return false;
// remove duplicates with levelupSpells if any
if (PetLevelupSpellSet const* levelupSpells = cInfo->family ? GetPetLevelupSpellList(cInfo->family) : NULL)
if (PetLevelupSpellSet const* levelupSpells = cInfo->Family ? GetPetLevelupSpellList(cInfo->Family) : NULL)
{
for (int j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
{

View file

@ -883,12 +883,12 @@ void Creature::UpdateDamagePhysical(WeaponAttackType attType)
UnitMods unitMod = (attType == BASE_ATTACK ? UNIT_MOD_DAMAGE_MAINHAND : UNIT_MOD_DAMAGE_OFFHAND);
/* difference in AP between current attack power and base value from DB */
float att_pwr_change = GetTotalAttackPowerValue(attType) - GetCreatureInfo()->attackpower;
float att_pwr_change = GetTotalAttackPowerValue(attType) - GetCreatureInfo()->MeleeAttackPower;
float base_value = GetModifierValue(unitMod, BASE_VALUE) + (att_pwr_change * GetAPMultiplier(attType, false) / 14.0f);
float base_pct = GetModifierValue(unitMod, BASE_PCT);
float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
float dmg_multiplier = GetCreatureInfo()->dmg_multiplier;
float dmg_multiplier = GetCreatureInfo()->DamageMultiplier;
float weapon_mindamage = GetWeaponDamageRange(attType, MINDAMAGE);
float weapon_maxdamage = GetWeaponDamageRange(attType, MAXDAMAGE);

View file

@ -902,48 +902,11 @@ uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* cleanDa
return 0;
}
// no xp,health if type 8 /critters/
if (pVictim->GetTypeId() == TYPEID_UNIT && pVictim->GetCreatureType() == CREATURE_TYPE_CRITTER)
{
// TODO: fix this part
// Critter may not die of damage taken, instead expect it to run away (no fighting back)
// If (this) is TYPEID_PLAYER, (this) will enter combat w/victim, but after some time, automatically leave combat.
// It is unclear how it should work for other cases.
DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamage critter, critter dies");
((Creature*)pVictim)->SetLootRecipient(this);
JustKilledCreature((Creature*)pVictim, NULL);
pVictim->SetHealth(0);
return damage;
}
DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamageStart");
uint32 health = pVictim->GetHealth();
DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "deal dmg:%d to health:%d ", damage, health);
// duel ends when player has 1 or less hp
bool duel_hasEnded = false;
if (pVictim->GetTypeId() == TYPEID_PLAYER && ((Player*)pVictim)->duel && damage >= (health - 1))
{
// prevent kill only if killed in duel and killed by opponent or opponent controlled creature
if (((Player*)pVictim)->duel->opponent == this || ((Player*)pVictim)->duel->opponent->GetObjectGuid() == GetOwnerGuid())
damage = health - 1;
duel_hasEnded = true;
}
// Get in CombatState
if (pVictim != this && damagetype != DOT)
{
SetInCombatWith(pVictim);
pVictim->SetInCombatWith(this);
if (Player* attackedPlayer = pVictim->GetCharmerOrOwnerPlayerOrPlayerItself())
SetContestedPvP(attackedPlayer);
}
// Rage from Damage made (only from direct weapon damage)
if (cleanDamage && damagetype == DIRECT_DAMAGE && this != pVictim && GetTypeId() == TYPEID_PLAYER && (GetPowerType() == POWER_RAGE))
{
@ -978,6 +941,70 @@ uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* cleanDa
}
}
// no xp,health if type 8 /critters/
if (pVictim->GetTypeId() == TYPEID_UNIT && pVictim->GetCreatureType() == CREATURE_TYPE_CRITTER)
{
// TODO: fix this part
// Critter may not die of damage taken, instead expect it to run away (no fighting back)
// If (this) is TYPEID_PLAYER, (this) will enter combat w/victim, but after some time, automatically leave combat.
// It is unclear how it should work for other cases.
DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamage critter, critter dies");
((Creature*)pVictim)->SetLootRecipient(this);
JustKilledCreature((Creature*)pVictim, nullptr);
pVictim->SetHealth(0);
return damage;
}
// share damage by auras
AuraList const& vShareDamageAuras = pVictim->GetAurasByType(SPELL_AURA_SHARE_DAMAGE_PCT);
for (AuraList::const_iterator itr = vShareDamageAuras.begin(); itr != vShareDamageAuras.end(); ++itr)
{
if (!spellProto)
break;
SpellEffectEntry const* spellEffect = spellProto->GetSpellEffect(EFFECT_INDEX_0);
// if damage is done by another shared aura, then skip to avoid circular reference (aura 300 is only applied on effect_idx_0
if (spellEffect && spellEffect->Effect == SPELL_EFFECT_APPLY_AURA &&
spellEffect->EffectApplyAuraName == SPELL_AURA_SHARE_DAMAGE_PCT)
break;
if (Unit* shareTarget = (*itr)->GetCaster())
{
if (shareTarget != pVictim && ((*itr)->GetMiscValue() & damageSchoolMask))
{
SpellEntry const* shareSpell = (*itr)->GetSpellProto();
uint32 shareDamage = uint32(damage*(*itr)->GetModifier()->m_amount / 100.0f);
DealDamageMods(shareTarget, shareDamage, nullptr);
DealDamage(shareTarget, shareDamage, 0, damagetype, GetSpellSchoolMask(shareSpell), shareSpell, false);
}
}
}
// duel ends when player has 1 or less hp
bool duel_hasEnded = false;
if (pVictim->GetTypeId() == TYPEID_PLAYER && ((Player*)pVictim)->duel && damage >= (health - 1))
{
// prevent kill only if killed in duel and killed by opponent or opponent controlled creature
if (((Player*)pVictim)->duel->opponent == this || ((Player*)pVictim)->duel->opponent->GetObjectGuid() == GetOwnerGuid())
damage = health - 1;
duel_hasEnded = true;
}
// Get in CombatState
if (pVictim != this && damagetype != DOT)
{
SetInCombatWith(pVictim);
pVictim->SetInCombatWith(this);
if (Player* attackedPlayer = pVictim->GetCharmerOrOwnerPlayerOrPlayerItself())
SetContestedPvP(attackedPlayer);
}
if (GetTypeId() == TYPEID_PLAYER && this != pVictim)
{
Player* killer = ((Player*)this);
@ -1208,11 +1235,6 @@ uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* cleanDa
pVictim->AttackedBy(this);
}
if (damagetype == DIRECT_DAMAGE || damagetype == SPELL_DIRECT_DAMAGE)
{
if (!spellProto || !(spellProto->GetAuraInterruptFlags() & AURA_INTERRUPT_FLAG_DIRECT_DAMAGE))
pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE);
}
if (pVictim->GetTypeId() != TYPEID_PLAYER)
{
float threat = damage * sSpellMgr.GetSpellThreatMultiplier(spellProto);
@ -1245,21 +1267,6 @@ uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* cleanDa
}
}
// TODO: Store auras by interrupt flag to speed this up.
SpellAuraHolderMap& vAuras = pVictim->GetSpellAuraHolderMap();
for (SpellAuraHolderMap::const_iterator i = vAuras.begin(), next; i != vAuras.end(); i = next)
{
const SpellEntry* se = i->second->GetSpellProto();
next = i; ++next;
if (spellProto && spellProto->Id == se->Id) // Not drop auras added by self
continue;
if (!se->GetProcFlags() && (se->GetAuraInterruptFlags() & AURA_INTERRUPT_FLAG_DAMAGE))
{
pVictim->RemoveAurasDueToSpell(i->second->GetId());
next = vAuras.begin();
}
}
if (damagetype != NODAMAGE && damage && pVictim->GetTypeId() == TYPEID_PLAYER)
{
if (damagetype != DOT)
@ -1426,7 +1433,7 @@ void Unit::JustKilledCreature(Creature* victim, Player* responsiblePlayer)
{
if (m->IsRaidOrHeroicDungeon())
{
if (victim->GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_INSTANCE_BIND)
if (victim->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_INSTANCE_BIND)
{ ((DungeonMap*)m)->PermBindAllPlayers(creditedPlayer); }
}
else
@ -1779,7 +1786,7 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss)
}
// TODO for melee need create structure as in
void Unit::CalculateMeleeDamage(Unit* pVictim, uint32 damage, CalcDamageInfo* damageInfo, WeaponAttackType attackType)
void Unit::CalculateMeleeDamage(Unit* pVictim, CalcDamageInfo* damageInfo, WeaponAttackType attackType /*= BASE_ATTACK*/)
{
damageInfo->attacker = this;
damageInfo->target = pVictim;
@ -1836,7 +1843,7 @@ void Unit::CalculateMeleeDamage(Unit* pVictim, uint32 damage, CalcDamageInfo* da
damageInfo->cleanDamage = 0;
return;
}
damage += CalculateDamage(damageInfo->attackType, false);
uint32 damage = CalculateDamage(damageInfo->attackType, false);
// Add melee damage bonus
damage = MeleeDamageBonusDone(damageInfo->target, damage, damageInfo->attackType);
damage = damageInfo->target->MeleeDamageBonusTaken(this, damage, damageInfo->attackType);
@ -2909,7 +2916,7 @@ void Unit::AttackerStateUpdate(Unit* pVictim, WeaponAttackType attType, bool ext
pVictim = SelectMagnetTarget(pVictim);
CalcDamageInfo damageInfo;
CalculateMeleeDamage(pVictim, 0, &damageInfo, attType);
CalculateMeleeDamage(pVictim, &damageInfo, attType);
// Send log damage message to client
DealDamageMods(pVictim, damageInfo.damage, &damageInfo.absorb);
SendAttackStateUpdate(&damageInfo);
@ -3028,7 +3035,7 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit* pVictim, WeaponAttackT
else
parry_chance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25;
if (parry_chance > 0 && (pVictim->GetTypeId() == TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_NO_PARRY)))
if (parry_chance > 0 && (pVictim->GetTypeId() == TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_PARRY)))
{
parry_chance -= skillBonus;
@ -3066,7 +3073,7 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit* pVictim, WeaponAttackT
// check if attack comes from behind, nobody can parry or block if attacker is behind
if (!from_behind)
{
if (pVictim->GetTypeId() == TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_NO_BLOCK))
if (pVictim->GetTypeId() == TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_BLOCK))
{
tmp = block_chance;
if ((tmp > 0) // check if unit _can_ block
@ -3092,7 +3099,7 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit* pVictim, WeaponAttackT
if (GetLevelForTarget(pVictim) >= pVictim->GetLevelForTarget(this) + 4 &&
// can be from by creature (if can) or from controlled player that considered as creature
((GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->IsPet() &&
!(((Creature*)this)->GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_NO_CRUSH)) ||
!(((Creature*)this)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_CRUSH)) ||
GetTypeId() == TYPEID_PLAYER && GetCharmerOrOwnerGuid()))
{
// when their weapon skill is 15 or more above victim's defense skill
@ -3226,7 +3233,7 @@ bool Unit::IsSpellBlocked(Unit* pCaster, SpellEntry const* spellEntry, WeaponAtt
// Check creatures ExtraFlags for disable block
if (GetTypeId() == TYPEID_UNIT)
{
if (((Creature*)this)->GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_NO_BLOCK)
if (((Creature*)this)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_BLOCK)
return false;
}
@ -3363,7 +3370,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* pVictim, SpellEntry const* spell)
if (pVictim->GetTypeId() == TYPEID_UNIT)
{
uint32 flagEx = ((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags;
if (flagEx & CREATURE_FLAG_EXTRA_NO_PARRY)
if (flagEx & CREATURE_EXTRA_FLAG_NO_PARRY)
canParry = false;
}
// Ignore combat result aura
@ -6225,6 +6232,26 @@ bool Unit::isAttackingPlayer() const
return CheckAllControlledUnits(IsAttackingPlayerHelper(), CONTROLLED_PET | CONTROLLED_TOTEMS | CONTROLLED_GUARDIANS | CONTROLLED_CHARM);
}
bool Unit::CanAttackByItself() const
{
if (!IsVehicle())
return true;
for (uint8 i = 0; i < MAX_VEHICLE_SEAT; ++i)
{
if (uint32 seatId = m_vehicleInfo->GetVehicleEntry()->m_seatID[i])
{
if (VehicleSeatEntry const* seatEntry = sVehicleSeatStore.LookupEntry(seatId))
{
if (seatEntry->m_flags & SEAT_FLAG_CAN_CONTROL)
return false;
}
}
}
return true;
}
void Unit::RemoveAllAttackers()
{
while (!m_attackers.empty())
@ -8431,7 +8458,7 @@ void Unit::SetInCombatState(bool PvP, Unit* enemy)
{ pCreature->AI()->EnterCombat(enemy); }
// Some bosses are set into combat with zone
if (GetMap()->IsDungeon() && (pCreature->GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_AGGRO_ZONE) && enemy && enemy->IsControlledByPlayer())
if (GetMap()->IsDungeon() && (pCreature->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_AGGRO_ZONE) && enemy && enemy->IsControlledByPlayer())
{ pCreature->SetInCombatWithZone(); }
if (InstanceData* mapInstance = GetInstanceData())
@ -8466,7 +8493,7 @@ void Unit::ClearInCombat()
if (GetTypeId() == TYPEID_UNIT)
{
Creature* cThis = static_cast<Creature*>(this);
if (cThis->GetCreatureInfo()->unit_flags & UNIT_FLAG_OOC_NOT_ATTACKABLE && !(cThis->GetTemporaryFactionFlags() & TEMPFACTION_TOGGLE_OOC_NOT_ATTACK))
if (cThis->GetCreatureInfo()->UnitFlags & UNIT_FLAG_OOC_NOT_ATTACKABLE && !(cThis->GetTemporaryFactionFlags() & TEMPFACTION_TOGGLE_OOC_NOT_ATTACK))
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE);
clearUnitState(UNIT_STAT_ATTACK_PLAYER);
@ -8968,10 +8995,10 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced, float ratio, bool ignore
switch (mtype)
{
case MOVE_RUN:
speed *= ((Creature*)this)->GetCreatureInfo()->speed_run;
speed *= ((Creature*)this)->GetCreatureInfo()->SpeedRun;
break;
case MOVE_WALK:
speed *= ((Creature*)this)->GetCreatureInfo()->speed_walk;
speed *= ((Creature*)this)->GetCreatureInfo()->SpeedWalk;
break;
default:
break;
@ -9900,7 +9927,7 @@ uint32 Unit::GetCreatureType() const
return CREATURE_TYPE_HUMANOID;
}
else
return ((Creature*)this)->GetCreatureInfo()->type;
return ((Creature*)this)->GetCreatureInfo()->CreatureType;
}
/*#######################################
@ -10816,76 +10843,91 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* pTarget, uint32 procFlag,
if (itr->second->IsDeleted())
continue;
SpellProcEventEntry const* spellProcEvent = NULL;
SpellProcEventEntry const* spellProcEvent = nullptr;
// check if that aura is triggered by proc event (then it will be managed by proc handler)
if (!IsTriggeredAtSpellProcEvent(pTarget, itr->second, procSpell, procFlag, procExtra, attType, isVictim, spellProcEvent))
{
// spell seem not managed by proc system, although some case need to be handled
// only process damage case on victim
if (!isVictim || !(procFlag & PROC_FLAG_TAKEN_ANY_DAMAGE))
continue;
const SpellEntry* se = itr->second->GetSpellProto();
// check if the aura is interruptible by damage and if its not just added by this spell (spell who is responsible for this damage is procSpell)
if (se->GetAuraInterruptFlags() & AURA_INTERRUPT_FLAG_DAMAGE && (!procSpell || procSpell->Id != se->Id))
{
DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "ProcDamageAndSpell: Added Spell %u to 'remove aura due to spell' list! Reason: Damage received.", se->Id);
removedSpells.push_back(se->Id);
}
continue;
}
itr->second->SetInUse(true); // prevent holder deletion
procTriggered.push_back(ProcTriggeredData(spellProcEvent, itr->second));
}
// Nothing found
if (procTriggered.empty())
return;
// Handle effects proceed this time
for (ProcTriggeredList::const_iterator itr = procTriggered.begin(); itr != procTriggered.end(); ++itr)
if (!procTriggered.empty())
{
// Some auras can be deleted in function called in this loop (except first, ofc)
SpellAuraHolder* triggeredByHolder = itr->triggeredByHolder;
if (triggeredByHolder->IsDeleted())
continue;
SpellProcEventEntry const* spellProcEvent = itr->spellProcEvent;
bool useCharges = triggeredByHolder->GetAuraCharges() > 0;
bool procSuccess = true;
bool anyAuraProc = false;
// For players set spell cooldown if need
uint32 cooldown = 0;
if (GetTypeId() == TYPEID_PLAYER && spellProcEvent && spellProcEvent->cooldown)
cooldown = spellProcEvent->cooldown;
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
// Handle effects proceed this time
for (ProcTriggeredList::const_iterator itr = procTriggered.begin(); itr != procTriggered.end(); ++itr)
{
Aura* triggeredByAura = triggeredByHolder->GetAuraByEffectIndex(SpellEffectIndex(i));
if (!triggeredByAura)
// Some auras can be deleted in function called in this loop (except first, ofc)
SpellAuraHolder* triggeredByHolder = itr->triggeredByHolder;
if (triggeredByHolder->IsDeleted())
continue;
SpellEffectEntry const* spellEffect = triggeredByHolder->GetSpellProto()->GetSpellEffect(SpellEffectIndex(i));
if (!spellEffect)
continue;
SpellProcEventEntry const* spellProcEvent = itr->spellProcEvent;
bool useCharges = triggeredByHolder->GetAuraCharges() > 0;
bool procSuccess = true;
bool anyAuraProc = false;
if (procSpell)
// For players set spell cooldown if need
uint32 cooldown = 0;
if (GetTypeId() == TYPEID_PLAYER && spellProcEvent && spellProcEvent->cooldown)
cooldown = spellProcEvent->cooldown;
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
{
if (spellProcEvent)
{
if (spellProcEvent->spellFamilyMask[i])
{
if (!procSpell->IsFitToFamilyMask(spellProcEvent->spellFamilyMask[i]))
continue;
Aura* triggeredByAura = triggeredByHolder->GetAuraByEffectIndex(SpellEffectIndex(i));
if (!triggeredByAura)
continue;
// don't allow proc from cast end for non modifier spells
// unless they have proc ex defined for that
if (IsCastEndProcModifierAura(triggeredByHolder->GetSpellProto(), SpellEffectIndex(i), procSpell))
SpellEffectEntry const* spellEffect = triggeredByHolder->GetSpellProto()->GetSpellEffect(SpellEffectIndex(i));
if (!spellEffect)
continue;
if (procSpell)
{
if (spellProcEvent)
{
if (spellProcEvent->spellFamilyMask[i])
{
if (useCharges && procExtra != PROC_EX_CAST_END && spellProcEvent->procEx == PROC_EX_NONE)
if (!procSpell->IsFitToFamilyMask(spellProcEvent->spellFamilyMask[i]))
continue;
// don't allow proc from cast end for non modifier spells
// unless they have proc ex defined for that
if (IsCastEndProcModifierAura(triggeredByHolder->GetSpellProto(), SpellEffectIndex(i), procSpell))
{
if (useCharges && procExtra != PROC_EX_CAST_END && spellProcEvent->procEx == PROC_EX_NONE)
continue;
}
else if (spellProcEvent->procEx == PROC_EX_NONE && procExtra == PROC_EX_CAST_END)
continue;
}
else if (spellProcEvent->procEx == PROC_EX_NONE && procExtra == PROC_EX_CAST_END)
// don't check dbc FamilyFlags if schoolMask exists
else if (!triggeredByAura->CanProcFrom(procSpell, procFlag, spellProcEvent->procEx, procExtra, damage != 0, !spellProcEvent->schoolMask))
continue;
}
// don't check dbc FamilyFlags if schoolMask exists
else if (!triggeredByAura->CanProcFrom(procSpell, procFlag, spellProcEvent->procEx, procExtra, damage != 0, !spellProcEvent->schoolMask))
else if (!triggeredByAura->CanProcFrom(procSpell, procFlag, PROC_EX_NONE, procExtra, damage != 0, true))
continue;
}
else if (!triggeredByAura->CanProcFrom(procSpell, procFlag, PROC_EX_NONE, procExtra, damage != 0, true))
continue;
}
SpellAuraProcResult procResult = (*this.*AuraProcHandler[spellEffect->EffectApplyAuraName])(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown);
switch (procResult)
{
SpellAuraProcResult procResult = (*this.*AuraProcHandler[spellEffect->EffectApplyAuraName])(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown);
switch (procResult)
{
case SPELL_AURA_PROC_CANT_TRIGGER:
continue;
case SPELL_AURA_PROC_FAILED:
@ -10893,20 +10935,21 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* pTarget, uint32 procFlag,
break;
case SPELL_AURA_PROC_OK:
break;
}
anyAuraProc = true;
}
anyAuraProc = true;
}
// Remove charge (aura can be removed by triggers)
if (useCharges && procSuccess && anyAuraProc && !triggeredByHolder->IsDeleted())
{
// If last charge dropped add spell to remove list
if (triggeredByHolder->DropAuraCharge())
removedSpells.push_back(triggeredByHolder->GetId());
}
// Remove charge (aura can be removed by triggers)
if (useCharges && procSuccess && anyAuraProc && !triggeredByHolder->IsDeleted())
{
// If last charge dropped add spell to remove list
if (triggeredByHolder->DropAuraCharge())
removedSpells.push_back(triggeredByHolder->GetId());
triggeredByHolder->SetInUse(false);
}
triggeredByHolder->SetInUse(false);
}
if (!removedSpells.empty())

View file

@ -1253,6 +1253,18 @@ enum IgnoreUnitState
#define REGEN_TIME_PRECISE 500 // Used in Spell::CheckPower for precise regeneration in spell cast time
#define REGEN_TIME_HOLY_POWER 10000 // This determines how often holy power regen is processed
// Power type values defines
enum PowerDefaults
{
POWER_RAGE_DEFAULT = 1000,
POWER_FOCUS_DEFAULT = 100,
POWER_ENERGY_DEFAULT = 100,
POWER_RUNE_DEFAULT = 8,
POWER_RUNIC_POWER_DEFAULT = 1000,
POWER_HOLY_POWER_DEFAULT = 3,
POWER_SOUL_SHARDS_DEFAULT = 3,
};
struct SpellProcEventEntry; // used only privately
#define MAX_OBJECT_SLOT 5
@ -1492,6 +1504,11 @@ class Unit : public WorldObject
* @return true if you and/or your pets/minions etc are attacking a player.
*/
bool isAttackingPlayer() const;
/**
* Checks if wa vehicle is allowed to attack other units by itself.
* @return true if vehicle can attack itself.
*/
bool CanAttackByItself() const;
/**
* @return The victim that you are currently attacking
*/
@ -2120,7 +2137,7 @@ class Unit : public WorldObject
* @param damageInfo this is filled with data about what kind of damage that was done
* @param attackType type of attack, base/off/ranged
*/
void CalculateMeleeDamage(Unit* pVictim, uint32 damage, CalcDamageInfo* damageInfo, WeaponAttackType attackType = BASE_ATTACK);
void CalculateMeleeDamage(Unit* pVictim, CalcDamageInfo* damageInfo, WeaponAttackType attackType = BASE_ATTACK);
/**
* Deals melee damage, if the attack was parried we reduce the victims time until next hit
* instead of the weapons normal time by 20 or 60%.