mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16:51:29 +00:00
* [Zone] State saving improvements * Make sure we load spawn enabled off of the state row * Update npc.h * Update spawn2.cpp * Update database_instances.cpp * Update database_instances.cpp
815 lines
29 KiB
C++
815 lines
29 KiB
C++
/* EQEMu: Everquest Server Emulator
|
|
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
|
|
|
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; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
are required to give you total support for your newly bought product;
|
|
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, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
#ifndef NPC_H
|
|
#define NPC_H
|
|
|
|
#include "../common/rulesys.h"
|
|
|
|
#include "mob.h"
|
|
#include "qglobals.h"
|
|
#include "zonedb.h"
|
|
#include "../common/zone_store.h"
|
|
#include "zonedump.h"
|
|
#include "../common/repositories/npc_faction_entries_repository.h"
|
|
#include "../common/repositories/loottable_repository.h"
|
|
#include "../common/repositories/loottable_entries_repository.h"
|
|
#include "../common/repositories/lootdrop_repository.h"
|
|
#include "../common/repositories/lootdrop_entries_repository.h"
|
|
|
|
#include <deque>
|
|
#include <list>
|
|
|
|
|
|
#ifdef _WINDOWS
|
|
#define M_PI 3.141592
|
|
#endif
|
|
|
|
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<uint32> &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<int> 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 is_charm_removed);
|
|
|
|
//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<wplist> &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<MercType> GetMercenaryTypesList() {return mercTypeList; };
|
|
std::list<MercType> GetMercenaryTypesList( uint32 expansion );
|
|
std::list<MercData> GetMercenariesList() {return mercDataList; };
|
|
std::list<MercData> GetMercenariesList( uint32 expansion );
|
|
int GetNumMercenaryTypes() { return static_cast<int>(mercTypeList.size()); };
|
|
int GetNumMercenaryTypes( uint32 expansion );
|
|
int GetNumberOfMercenaries() { return static_cast<int>(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<Timer> 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);
|
|
|
|
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<HandinEntry> original_items = {}; // this is what the player originally handed in, never modified
|
|
std::vector<HandinEntry> 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<std::string, uint32> handin,
|
|
std::map<std::string, uint32> required,
|
|
std::vector<EQ::ItemInstance *> 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() { return m_queued_for_corpse; }
|
|
inline uint32_t SetCorpseDecayTime(uint32_t decay_time) { return m_corpse_decay_time = decay_time; }
|
|
inline void SetResumedFromZoneSuspend(bool state = true) { m_resumed_from_zone_suspend = state; }
|
|
inline bool IsResumedFromZoneSuspend() { return m_resumed_from_zone_suspend; }
|
|
|
|
inline void LoadBuffsFromState(std::vector<Buffs_Struct> 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
|
|
uint32_t m_corpse_decay_time = 0; // decay time set on zone state restore
|
|
Timer m_corpse_queue_timer = {}; // this is to check for corpse creation on zone state restore
|
|
Timer m_corpse_queue_shutoff_timer = {};
|
|
|
|
// this is a 30-second 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 30 seconds
|
|
Timer m_resumed_from_zone_suspend_shutoff_timer = {};
|
|
|
|
std::list<NpcFactionEntriesRepository::NpcFactionEntries> 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_Struct> 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_Struct> 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<int> signal_q;
|
|
|
|
//waypoint crap:
|
|
std::vector<wplist> 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<MercType> mercTypeList;
|
|
std::list<MercData> 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<uint32> m_rolled_items = {};
|
|
};
|
|
|
|
#endif
|
|
|