/* EQEmu: EQEmulator Copyright (C) 2001-2026 EQEmu Development Team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #pragma once #include "common/repositories/lootdrop_entries_repository.h" #include "common/repositories/lootdrop_repository.h" #include "common/repositories/loottable_entries_repository.h" #include "common/repositories/loottable_repository.h" #include "common/repositories/npc_faction_entries_repository.h" #include "common/rulesys.h" #include "common/zone_store.h" #include "zone/mob.h" #include "zone/qglobals.h" #include "zone/zonedb.h" #include "zone/zonedump.h" #include #include typedef struct { float min_x; float max_x; float min_y; float max_y; float min_z; float max_z; bool say; bool proximity_set; } NPCProximity; struct AISpells_Struct { uint32 type; // 0 = never, must be one (and only one) of the defined values uint16 spellid; // <= 0 = no spell int16 manacost; // -1 = use spdat, -2 = no cast time uint32 time_cancast; // when we can cast this spell next int32 recast_delay; int16 priority; int16 resist_adjust; int8 min_hp; // >0 won't cast if HP is below int8 max_hp; // >0 won't cast if HP is above }; struct AISpellsEffects_Struct { uint16 spelleffectid; int32 base_value; int32 limit; int32 max_value; }; struct AISpellsVar_Struct { uint32 fail_recast; uint32 engaged_no_sp_recast_min; uint32 engaged_no_sp_recast_max; uint8 engaged_beneficial_self_chance; uint8 engaged_beneficial_other_chance; uint8 engaged_detrimental_chance; uint32 pursue_no_sp_recast_min; uint32 pursue_no_sp_recast_max; uint8 pursue_detrimental_chance; uint32 idle_no_sp_recast_min; uint32 idle_no_sp_recast_max; uint8 idle_beneficial_chance; }; struct Roambox { float max_x; float max_y; float min_x; float min_y; float distance; float dest_x; float dest_y; float dest_z; uint32 delay; uint32 min_delay; }; class SwarmPet; class Client; class Group; class Raid; class Spawn2; class Aura; namespace EQ { struct ItemData; } class NPC : public Mob { public: static NPC* SpawnNPC(const char* spawncommand, const glm::vec4& position, Client* client = nullptr); static bool SpawnZoneController(); // loot recording / simulator bool IsRecordLootStats() const; void SetRecordLootStats(bool record_loot_stats); const std::vector &GetRolledItems() const; int GetRolledItemCount(uint32 item_id); NPC(const NPCType* npc_type_data, Spawn2* respawn, const glm::vec4& position, GravityBehavior iflymode, bool IsCorpse = false); virtual ~NPC(); static NPC *SpawnNodeNPC(std::string name, std::string last_name, const glm::vec4 &position); static void SpawnGridNodeNPC(const glm::vec4 &position, int32 grid_id, int32 grid_number, int32 zoffset); static NPC * SpawnZonePointNodeNPC(std::string name, const glm::vec4 &position); //abstract virtual function implementations requird by base abstract class virtual bool Death(Mob* killer_mob, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill, KilledByTypes killed_by = KilledByTypes::Killed_NPC, bool is_buff_tic = false); virtual void Damage(Mob* from, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None); bool Attack(Mob* other, int Hand = EQ::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr) override; virtual bool HasRaid() { return false; } virtual bool HasGroup() { return false; } virtual Raid* GetRaid() { return 0; } virtual Group* GetGroup() { return 0; } virtual bool IsNPC() const { return true; } virtual bool Process(); virtual void AI_Init(); virtual void AI_Start(uint32 iMoveDelay = 0); virtual void AI_Stop(); void AI_DoMovement(); void AI_SetupNextWaypoint(); bool AI_AddNPCSpells(uint32 iDBSpellsID); bool AI_AddNPCSpellsEffects(uint32 iDBSpellsEffectsID); virtual bool AI_EngagedCastCheck(); bool AI_HasSpells() { return HasAISpell; } bool AI_HasSpellsEffects() { return HasAISpellEffects; } void ApplyAISpellEffects(StatBonuses* newbon); virtual bool AI_PursueCastCheck(); virtual bool AI_IdleCastCheck(); virtual void AI_Event_SpellCastFinished(bool iCastSucceeded, uint16 slot); bool AICheckCloseBeneficialSpells(NPC* caster, uint8 chance, float cast_range, uint32 spell_types); void AIYellForHelp(Mob* sender, Mob* attacker); void LevelScale(); virtual void SetTarget(Mob* mob); virtual uint16 GetSkill(EQ::skills::SkillType skill_num) const { if (skill_num <= EQ::skills::HIGHEST_SKILL) { return skills[skill_num]; } return 0; } virtual void CalcBonuses(); virtual int GetCurrentBuffSlots() const { return RuleI(Spells, MaxBuffSlotsNPC); } virtual int GetCurrentSongSlots() const { return RuleI(Spells, MaxSongSlotsNPC); } virtual int GetCurrentDiscSlots() const { return RuleI(Spells, MaxDiscSlotsNPC); } virtual int GetMaxBuffSlots() const { return RuleI(Spells, MaxBuffSlotsNPC); } virtual int GetMaxSongSlots() const { return RuleI(Spells, MaxSongSlotsNPC); } virtual int GetMaxDiscSlots() const { return RuleI(Spells, MaxDiscSlotsNPC); } virtual int GetMaxTotalSlots() const { return RuleI(Spells, MaxTotalSlotsNPC); } virtual int GetPetMaxTotalSlots() const { return RuleI(Spells, MaxTotalSlotsPET); } virtual void InitializeBuffSlots(); virtual void UninitializeBuffSlots(); virtual void SetAttackTimer(); virtual void RangedAttack(Mob* other); virtual void ThrowingAttack(Mob* other) { } int32 GetNumberOfAttacks() const { return attack_count; } void DoRangedAttackDmg(Mob* other, bool Launch = true, int16 damage_mod = 0, int16 chance_mod = 0, EQ::skills::SkillType skill = EQ::skills::SkillArchery, float speed = 4.0f, const char *IDFile = nullptr); bool IsFactionListAlly(uint32 other_faction); bool IsGuard(); FACTION_VALUE CheckNPCFactionAlly(int32 other_faction); virtual FACTION_VALUE GetReverseFactionCon(Mob* iOther); void GoToBind(uint8 bind_number = 0) { GMMove(m_SpawnPoint.x, m_SpawnPoint.y, m_SpawnPoint.z, m_SpawnPoint.w); } void Gate(uint8 bind_number = 0); void GetPetState(SpellBuff_Struct *buffs, uint32 *items, char *name); void SetPetState(SpellBuff_Struct *buffs, uint32 *items); virtual void SpellProcess(); virtual void FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho); // loot void AddItem(const EQ::ItemData *item, uint16 charges, bool equip_item = true); void AddItem( uint32 item_id, uint16 charges, bool equip_item = true, uint32 augment_one = 0, uint32 augment_two = 0, uint32 augment_three = 0, uint32 augment_four = 0, uint32 augment_five = 0, uint32 augment_six = 0 ); void AddLootTable(); void AddLootTable(uint32 loottable_id, bool is_global = false); void AddLootDropTable(uint32 lootdrop_id, uint8 drop_limit, uint8 min_drop); void CheckGlobalLootTables(); void RemoveItem(uint32 item_id, uint16 quantity = 0, uint16 slot = 0); void CheckTrivialMinMaxLevelDrop(Mob *killer); void ClearLootItems(); inline const LootItems &GetLootItems() { return m_loot_items; } LootItem *GetItem(int slot_id); void AddLootCash(uint32 in_copper, uint32 in_silver, uint32 in_gold, uint32 in_platinum); void RemoveLootCash(); void QueryLoot(Client *to, bool is_pet_query = false); bool HasItem(uint32 item_id); uint32 CountItem(uint32 item_id); uint32 GetLootItemIDBySlot(uint16 loot_slot); uint16 GetFirstLootSlotByItemID(uint32 item_id); std::vector GetLootList(); uint32 CountLoot(); inline uint32 GetLoottableID() const { return m_loottable_id; } inline bool DropsGlobalLoot() const { return !m_skip_global_loot; } inline uint32 GetCopper() const { return m_loot_copper; } inline uint32 GetSilver() const { return m_loot_silver; } inline uint32 GetGold() const { return m_loot_gold; } inline uint32 GetPlatinum() const { return m_loot_platinum; } inline void SetCopper(uint32 amt) { m_loot_copper = amt; } inline void SetSilver(uint32 amt) { m_loot_silver = amt; } inline void SetGold(uint32 amt) { m_loot_gold = amt; } inline void SetPlatinum(uint32 amt) { m_loot_platinum = amt; } void DescribeAggro(Client *to_who, Mob *mob, bool verbose); virtual void UpdateEquipmentLight(); virtual int64 CalcMaxMana(); void SetGrid(int32 grid_){ grid=grid_; } void SetSpawnGroupId(uint32 sg2){ spawn_group_id =sg2; } void SetWaypointMax(uint16 wp_){ wp_m=wp_; } void SetSaveWaypoint(uint16 wp_){ save_wp=wp_; } uint16 GetWaypointMax() const { return wp_m; } int32 GetGrid() const { return grid; } Spawn2* GetSpawn() { return respawn2 ? respawn2 : nullptr; } uint32 GetSpawnGroupId() const { return spawn_group_id; } uint32 GetSpawnPointID() const; glm::vec4 const GetSpawnPoint() const { return m_SpawnPoint; } glm::vec4 const GetGuardPoint() const { return m_GuardPoint; } EmuAppearance GetGuardPointAnim() const { return guard_anim; } void SaveGuardPointAnim(EmuAppearance anim) { guard_anim = anim; } uint8 GetPrimSkill() const { return prim_melee_type; } uint8 GetSecSkill() const { return sec_melee_type; } uint8 GetRangedSkill() const { return ranged_type; } void SetPrimSkill(uint8 skill_type) { prim_melee_type = skill_type; } void SetSecSkill(uint8 skill_type) { sec_melee_type = skill_type; } void SetRangedSkill(uint8 skill_type) { ranged_type = skill_type; } uint32 MerchantType; bool merchant_open; inline void MerchantOpenShop() { merchant_open = true; } inline void MerchantCloseShop() { merchant_open = false; } inline bool IsMerchantOpen() { return merchant_open; } inline uint8 GetGreedPercent() { return NPCTypedata->greed; } inline bool GetParcelMerchant() { return NPCTypedata->is_parcel_merchant; } void Depop(bool start_spawn_timer = false); void Stun(int duration); void UnStun(); uint32 GetSwarmOwner(); uint32 GetSwarmTarget(); void SetSwarmTarget(int target_id = 0); void DepopSwarmPets(); void TryDepopTargetLockedPets(Mob* current_target); void PetOnSpawn(NewSpawn_Struct* ns); void SignalNPC(int _signal_id); void SendPayload(int payload_id, std::string payload_value = std::string()); inline int32 GetNPCFactionID() const { return npc_faction_id; } inline int32 GetPrimaryFaction() const { return primary_faction; } inline int32 GetFactionAmount() const { return faction_amount; } int64 GetNPCHate(Mob *in_ent) { return hate_list.GetEntHateAmount(in_ent); } bool IsOnHatelist(Mob *p) { return hate_list.IsEntOnHateList(p); } void SetNPCFactionID(int32 in) { npc_faction_id = in; content_db.GetFactionIDsForNPC(npc_faction_id, &faction_list, &primary_faction); } glm::vec4 m_SpawnPoint; uint32 GetMaxDMG() const {return max_dmg;} uint32 GetMinDMG() const {return min_dmg;} int GetBaseDamage() const { return base_damage; } int GetMinDamage() const { return min_damage; } float GetSlowMitigation() const { return slow_mitigation; } float GetAttackSpeed() const {return attack_speed;} int GetAttackDelay() const {return attack_delay;} bool IsAnimal() const { return(bodytype == BodyType::Animal); } uint16 GetPetSpellID() const {return pet_spell_id;} void SetPetSpellID(uint16 amt) {pet_spell_id = amt;} uint32 GetMaxDamage(uint8 tlevel); void SetTaunting(bool is_taunting); bool IsTaunting() const { return taunting; } void PickPocket(Client* thief); void Disarm(Client* client, int chance); void StartSwarmTimer(uint32 duration) { swarm_timer.Start(duration); } void DisableSwarmTimer() { swarm_timer.Disable(); } void AddLootDrop( const EQ::ItemData *item2, LootdropEntriesRepository::LootdropEntries loot_drop, bool wear_change = false, uint32 augment_one = 0, uint32 augment_two = 0, uint32 augment_three = 0, uint32 augment_four = 0, uint32 augment_five = 0, uint32 augment_six = 0 ); bool MeetsLootDropLevelRequirements(LootdropEntriesRepository::LootdropEntries loot_drop, bool verbose=false); void CheckSignal(); virtual void DoClassAttacks(Mob *target); inline bool IsNotTargetableWithHotkey() const { return no_target_hotkey; } int64 GetNPCHPRegen() const { return hp_regen + itembonuses.HPRegen + spellbonuses.HPRegen; } inline const char* GetAmmoIDfile() const { return ammo_idfile; } void ModifyStatsOnCharm(bool remove_charm, Mob* charmer); //waypoint crap int GetMaxWp() const { return max_wp; } void DisplayWaypointInfo(Client *client); void CalculateNewWaypoint(); void AssignWaypoints(int32 grid_id, int start_wp = 0); void SetWaypointPause(); void UpdateWaypoint(int wp_index); // quest wandering commands void StopWandering(); void ResumeWandering(); void PauseWandering(int pausetime); void MoveTo(const glm::vec4& position, bool saveguardspot); void GetClosestWaypoints(std::list &wp_list, int count, const glm::vec3& location); int GetClosestWaypoint(const glm::vec3& location); uint32 GetEquippedItemFromTextureSlot(uint8 material_slot) const; // returns item id uint32 GetEquipmentMaterial(uint8 material_slot) const; void NextGuardPosition(); void SaveGuardSpot(bool ClearGuardSpot = false); void SaveGuardSpot(const glm::vec4 &pos); inline bool IsGuarding() const { return(m_GuardPoint.w != 0); } void SaveGuardSpotCharm(); void DescribeSpecialAbilities(Client* c); uint16 GetMeleeTexture1() const; uint16 GetMeleeTexture2() const; void RestoreGuardSpotCharm(); void AI_SetRoambox( float max_distance, float roam_distance_variance, uint32 delay = 2500, uint32 min_delay = 2500 ); void AI_SetRoambox(float distance, float max_x, float min_x, float max_y, float min_y, uint32 delay = 2500, uint32 min_delay = 2500); //mercenary stuff void LoadMercenaryTypes(); void LoadMercenaries(); std::list GetMercenaryTypesList() {return mercTypeList; }; std::list GetMercenaryTypesList( uint32 expansion ); std::list GetMercenariesList() {return mercDataList; }; std::list GetMercenariesList( uint32 expansion ); int GetNumMercenaryTypes() { return static_cast(mercTypeList.size()); }; int GetNumMercenaryTypes( uint32 expansion ); int GetNumberOfMercenaries() { return static_cast(mercDataList.size()); }; int GetNumberOfMercenaries( uint32 expansion ); inline bool GetNPCAggro() const { return npc_aggro; } inline void SetNPCAggro(bool in_npc_aggro) { npc_aggro = in_npc_aggro; } inline void GiveNPCTypeData(NPCType *ours) { NPCTypedata_ours = ours; } inline const uint32 GetNPCSpellsID() const { return npc_spells_id; } inline const uint32 GetNPCSpellsEffectsID() const { return npc_spells_effects_id; } float GetProximityMinX(); float GetProximityMaxX(); float GetProximityMinY(); float GetProximityMaxY(); float GetProximityMinZ(); float GetProximityMaxZ(); bool IsProximitySet(); NPCProximity* proximity; Spawn2* respawn2; QGlobalCache *GetQGlobals() { return qGlobals; } QGlobalCache *CreateQGlobals() { qGlobals = new QGlobalCache(); return qGlobals; } SwarmPet *GetSwarmInfo() { return (swarmInfoPtr); } void SetSwarmInfo(SwarmPet *mSwarmInfo) { swarmInfoPtr = mSwarmInfo; } int32 GetAccuracyRating() const { return (accuracy_rating); } void SetAccuracyRating(int32 d) { accuracy_rating = d;} int32 GetAvoidanceRating() const { return (avoidance_rating); } void SetAvoidanceRating(int32 d) { avoidance_rating = d;} int32 GetRawAC() const { return AC; } float GetNPCStat(const std::string& stat); void ModifyNPCStat(const std::string& stat, const std::string& value); virtual void SetLevel(uint8 in_level, bool command = false); bool IsLDoNTrapped() const { return ldon_trapped; } void SetLDoNTrapped(bool n) { ldon_trapped = n; } uint8 GetLDoNTrapType() const { return ldon_trap_type; } void SetLDoNTrapType(uint8 n) { ldon_trap_type = n; } uint16 GetLDoNTrapSpellID() const { return ldon_spell_id; } void SetLDoNTrapSpellID(uint16 n) { ldon_spell_id = n; } bool IsLDoNLocked() const { return ldon_locked; } void SetLDoNLocked(bool n) { ldon_locked = n; } uint16 GetLDoNLockedSkill() const { return ldon_locked_skill; } void SetLDoNLockedSkill(uint16 n) { ldon_locked_skill = n; } bool IsLDoNTrapDetected() const { return ldon_trap_detected; } void SetLDoNTrapDetected(bool n) { ldon_trap_detected = n; } const bool GetCombatEvent() const { return combat_event; } void SetCombatEvent(bool b) { combat_event = b; } /* Only allows players that killed corpse to loot */ const bool HasPrivateCorpse() const { return NPCTypedata_ours ? NPCTypedata_ours->private_corpse : NPCTypedata->private_corpse; } virtual const bool IsUnderwaterOnly() const { return m_is_underwater_only; } virtual const bool IsQuestNPC() const { return m_is_quest_npc; } const char* GetRawNPCTypeName() const { return NPCTypedata_ours ? NPCTypedata_ours->name : NPCTypedata->name; } virtual int GetKillExpMod() const { return NPCTypedata_ours ? NPCTypedata_ours->exp_mod : NPCTypedata->exp_mod; } void ChangeLastName(std::string last_name); void ClearLastName(); bool GetDepop() { return p_depop; } void NPCSlotTexture(uint8 slot, uint32 texture); // Sets new material values for slots uint32 GetAdventureTemplate() const { return adventure_template_id; } void AddSpellToNPCList(int16 iPriority, uint16 iSpellID, uint32 iType, int16 iManaCost, int32 iRecastDelay, int16 iResistAdjust, int8 min_hp, int8 max_hp); void AddSpellEffectToNPCList(uint16 iSpellEffectID, int32 base_value, int32 limit, int32 max_value, bool apply_bonus = false); void RemoveSpellFromNPCList(uint16 spell_id); void RemoveSpellEffectFromNPCList(uint16 iSpellEffectID, bool apply_bonus = false); bool HasAISpellEffect(uint16 spell_effect_id); Timer *GetRefaceTimer() const { return reface_timer; } const uint32 GetAltCurrencyType() const { return NPCTypedata->alt_currency_type; } NPC_Emote_Struct* GetNPCEmote(uint32 emote_id, uint8 event_); void DoNPCEmote(uint8 event_, uint32 emote_id, Mob* t = nullptr); bool CanTalk(); void DoQuestPause(Mob* m); bool FacesTarget(); inline void SetSpellScale(float amt) { spellscale = amt; } inline float GetSpellScale() { return spellscale; } inline void SetHealScale(float amt) { healscale = amt; } inline float GetHealScale() { return healscale; } inline void SetSpellFocusDMG(int32 NewSpellFocusDMG) {SpellFocusDMG = NewSpellFocusDMG;} inline int32 GetSpellFocusDMG() const { return SpellFocusDMG;} inline void SetSpellFocusHeal(int32 NewSpellFocusHeal) {SpellFocusHeal = NewSpellFocusHeal;} inline int32 GetSpellFocusHeal() const {return SpellFocusHeal;} uint32 GetSpawnKillCount(); int GetScore(); void AISpellsList(Client *c); uint16 GetInnateProcSpellID() const { return innate_proc_spell_id; } uint32 GetHeroForgeModel() const { return herosforgemodel; } void SetHeroForgeModel(uint32 model) { herosforgemodel = model; } bool IsRaidTarget() const { return raid_target; }; bool IsRareSpawn() const { return rare_spawn; } void ResetHPUpdateTimer() { send_hp_update_timer.Start(); } bool IgnoreDespawn() { return ignore_despawn; } void SetSimpleRoamBox(float box_size, float move_distance = 0, int move_delay = 0); float GetRoamboxMaxX() const; float GetRoamboxMaxY() const; float GetRoamboxMinX() const; float GetRoamboxMinY() const; float GetRoamboxDistance() const; float GetRoamboxDestinationX() const; float GetRoamboxDestinationY() const; float GetRoamboxDestinationZ() const; uint32 GetRoamboxDelay() const; uint32 GetRoamboxMinDelay() const; inline uint8 GetArmTexture() { return armtexture; } inline uint8 GetBracerTexture() { return bracertexture; } inline uint8 GetHandTexture() { return handtexture; } inline uint8 GetFeetTexture() { return feettexture; } inline uint8 GetLegTexture() { return legtexture; } inline int GetCharmedAccuracy() { return charm_accuracy_rating; } inline int GetCharmedArmorClass() { return charm_ac; } inline int GetCharmedAttack() { return charm_atk; } inline int GetCharmedAttackDelay() { return charm_attack_delay; } inline int GetCharmedAvoidance() { return charm_avoidance_rating; } inline int GetCharmedMaxDamage() { return charm_max_dmg; } inline int GetCharmedMinDamage() { return charm_min_dmg; } inline bool GetAlwaysAggro() { return always_aggro; } inline bool GetNPCAggro() { return npc_aggro; } inline bool GetIgnoreDespawn() { return ignore_despawn; } inline bool GetSkipGlobalLoot() { return m_skip_global_loot; } std::unique_ptr AIautocastspell_timer; virtual int GetStuckBehavior() const { return NPCTypedata_ours ? NPCTypedata_ours->stuck_behavior : NPCTypedata->stuck_behavior; } inline bool IsSkipAutoScale() const { return m_skip_auto_scale; } void ScaleNPC(uint8 npc_level, bool always_scale = false, bool override_special_abilities = false); uint32 GetNPCTintIndex() { return m_npc_tint_id; } void SetNPCTintIndex(uint32 index); void RecalculateSkills(); void ReloadSpells(); void SendPositionToClients(); bool CanPathTo(float x, float y, float z); void DoNpcToNpcAggroScan(); // hand-ins bool CanPetTakeItem(const EQ::ItemInstance *inst); struct HandinEntry { std::string item_id = "0"; uint32 count = 0; EQ::ItemInstance *item = nullptr; bool is_multiquest_item = false; // state }; struct HandinMoney { uint32 platinum = 0; uint32 gold = 0; uint32 silver = 0; uint32 copper = 0; }; struct Handin { std::vector original_items = {}; // this is what the player originally handed in, never modified std::vector items = {}; // items can be removed from this set as successful handins are made HandinMoney original_money = {}; // this is what the player originally handed in, never modified HandinMoney money = {}; // money can be removed from this set as successful handins are made }; // NPC Hand-in bool IsMultiQuestEnabled() { return m_multiquest_enabled; } void MultiQuestEnable() { m_multiquest_enabled = true; } bool IsGuildmasterForClient(Client *c); bool CheckHandin( Client *c, std::map handin, std::map required, std::vector items ); Handin ReturnHandinItems(Client *c); void ResetHandin(); void ResetMultiQuest(); bool HasProcessedHandinReturn() { return m_has_processed_handin_return; } bool HandinStarted() { return m_handin_started; } // zone state save inline void SetQueuedToCorpse() { m_queued_for_corpse = true; } inline bool IsQueuedForCorpse() const { return m_queued_for_corpse; } inline void SetResumedFromZoneSuspend(bool state = true) { m_resumed_from_zone_suspend = state; } inline bool IsResumedFromZoneSuspend() const { return m_resumed_from_zone_suspend; } inline void LoadBuffsFromState(std::vector in_buffs) { int i = 0; for (auto &b: in_buffs) { buffs[i].spellid = b.spellid; buffs[i].casterlevel = b.casterlevel; buffs[i].casterid = b.casterid; strncpy(buffs[i].caster_name, b.caster_name, 64); buffs[i].ticsremaining = b.ticsremaining; buffs[i].counters = b.counters; buffs[i].hit_number = b.hit_number; buffs[i].melee_rune = b.melee_rune; buffs[i].magic_rune = b.magic_rune; buffs[i].dot_rune = b.dot_rune; buffs[i].caston_x = b.caston_x; buffs[i].caston_y = b.caston_y; buffs[i].caston_z = b.caston_z; buffs[i].ExtraDIChance = b.ExtraDIChance; buffs[i].RootBreakChance = b.RootBreakChance; buffs[i].instrument_mod = b.instrument_mod; buffs[i].virus_spread_time = b.virus_spread_time; buffs[i].persistant_buff = b.persistant_buff; buffs[i].client = b.client; buffs[i].UpdateClient = b.UpdateClient; i++; } CalcBonuses(); } protected: void HandleRoambox(); const NPCType* NPCTypedata; NPCType* NPCTypedata_ours; //special case for npcs with uniquely created data. friend class EntityList; friend class Aura; int32 grid; uint32 spawn_group_id; uint16 wp_m; // loot uint32 m_loot_copper; uint32 m_loot_silver; uint32 m_loot_gold; uint32 m_loot_platinum; LootItems m_loot_items; // zone state bool m_resumed_from_zone_suspend = false; bool m_queued_for_corpse = false; // this is to check for corpse creation on zone state restore // this is a timer that protects a NPC from having double assignment of loot // this is to prevent a player from killing a NPC and then zoning out and back in to get loot again // if loot was to be assigned via script again, this protects double assignment for a short time Timer m_resumed_from_zone_suspend_shutoff_timer = {}; std::list faction_list; int32 npc_faction_id; int32 primary_faction; int32 faction_amount; Timer attacked_timer; //running while we are being attacked (damaged) Timer swarm_timer; Timer monkattack_timer; //additional timer for tiger claw usage Timer classattack_timer; Timer knightattack_timer; Timer assist_timer; //ask for help from nearby mobs Timer qglobal_purge_timer; bool combat_event; //true if we are in combat, false otherwise Timer send_hp_update_timer; Timer enraged_timer; Timer *reface_timer; uint32 npc_spells_id; uint8 casting_spell_AIindex; std::vector AIspells; bool HasAISpell; virtual bool AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes, bool bInnates = false); virtual bool AIDoSpellCast(int32 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0); AISpellsVar_Struct AISpellVar; int64 GetFocusEffect(focusType type, uint16 spell_id, Mob *caster = nullptr, bool from_buff_tic = false) override; uint16 innate_proc_spell_id; uint32 npc_spells_effects_id; std::vector AIspellsEffects; bool HasAISpellEffects; uint32 max_dmg; uint32 min_dmg; int base_damage; int min_damage; int32 accuracy_rating; int32 avoidance_rating; int16 attack_count; uint64 npc_mana; float spellscale; float healscale; int32 SpellFocusDMG; int32 SpellFocusHeal; // stats to switch back to after charm wears off // could probably pick a better name, but these probably aren't taken so ... int default_ac; int default_min_dmg; int default_max_dmg; int default_attack_delay; int default_accuracy_rating; int default_avoidance_rating; int default_atk; char default_special_abilities[512]; // when charmed, switch to these int charm_ac; int charm_min_dmg; int charm_max_dmg; int charm_attack_delay; int charm_accuracy_rating; int charm_avoidance_rating; int charm_atk; //pet crap: uint16 pet_spell_id; bool taunting; Timer taunt_timer; //for pet taunting bool npc_aggro; std::deque signal_q; //waypoint crap: std::vector Waypoints; int max_wp; int save_wp; glm::vec4 m_GuardPoint; glm::vec4 m_GuardPointSaved; EmuAppearance guard_anim; Roambox m_roambox = {}; uint16 skills[EQ::skills::HIGHEST_SKILL + 1]; uint32 equipment[EQ::invslot::EQUIPMENT_COUNT]; //this is an array of item IDs uint32 herosforgemodel; //this is the Hero Forge Armor Model (i.e 63 or 84 or 203) uint32 d_melee_texture1; //this is an item Material value uint32 d_melee_texture2; //this is an item Material value (offhand) const char* ammo_idfile; //this determines projectile graphic "IT###" (see item field 'idfile') uint8 prim_melee_type; //Sets the Primary Weapon attack message and animation uint8 sec_melee_type; //Sets the Secondary Weapon attack message and animation uint8 ranged_type; //Sets the Ranged Weapon attack message and animation SwarmPet *swarmInfoPtr; bool ldon_trapped; uint8 ldon_trap_type; uint16 ldon_spell_id; bool ldon_locked; uint16 ldon_locked_skill; bool ldon_trap_detected; QGlobalCache *qGlobals; uint32 adventure_template_id; bool m_is_underwater_only = false; bool m_is_quest_npc = false; //mercenary stuff std::list mercTypeList; std::list mercDataList; bool raid_target; bool ignore_despawn; //NPCs with this set to 1 will ignore the despawn value in spawngroup // NPC Hand-in bool m_multiquest_enabled = false; bool m_handin_started = false; bool m_has_processed_handin_return = false; // this is the working handin data from the player // items can be decremented from this as each successful // check is ran in scripts, the remainder is what is returned Handin m_hand_in = {}; public: const Handin GetHandin() { return m_hand_in; } private: uint32 m_loottable_id; bool m_skip_global_loot; bool m_skip_auto_scale; bool p_depop; bool m_record_loot_stats; std::vector m_rolled_items = {}; };