Trevius: Mercenaries can now zone once again.

This commit is contained in:
Trevius 2014-11-18 01:02:11 -06:00
parent 0b44f58518
commit a6b9e6cb3c
9 changed files with 2575 additions and 2393 deletions

View File

@ -1,11 +1,14 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50) EQEMu Changelog (Started on Sept 24, 2003 15:50)
------------------------------------------------------- -------------------------------------------------------
== 11/16/2014 == == 11/18/2014 ==
demonstar55: Correct OP_AugmentInfo reply. This fixes RoF display issue with Adventurer's Stone Trevius: Mercenaries can now zone once again.
Still issues with UF/SoF/SoD though.
== 11/17/2014 ==
demonstar55: Correct OP_AugmentInfo reply. This fixes RoF display issue with Adventurer's Stone. Still issues with UF/SoF/SoD though.
== 11/16/2014 == == 11/16/2014 ==
demonstar55: fix size issue with ControlBoat_Struct and exploit fix in OP_BoardBoat demonstar55: fix size issue with ControlBoat_Struct and exploit fix in OP_BoardBoat
Akkadius: Implemented Automatic Database update and versioning system Akkadius: Implemented Automatic Database update and versioning system
Akkadius: Created database revision define, this is located in version.h in common #define CURRENT_BINARY_DATABASE_VERSION 9057 Akkadius: Created database revision define, this is located in version.h in common #define CURRENT_BINARY_DATABASE_VERSION 9057
- This revision define will need to be incremented each time a database update is made - This revision define will need to be incremented each time a database update is made

View File

@ -7297,26 +7297,24 @@ void Client::SendMercPersonalInfo()
{ {
uint32 mercTypeCount = 1; uint32 mercTypeCount = 1;
uint32 mercCount = 1; //TODO: Un-hardcode this and support multiple mercs like in later clients than SoD. uint32 mercCount = 1; //TODO: Un-hardcode this and support multiple mercs like in later clients than SoD.
//uint32 packetSize = 0; uint32 i = 0;
uint32 i=0;
uint32 altCurrentType = 19; //TODO: Implement alternate currency purchases involving mercs! uint32 altCurrentType = 19; //TODO: Implement alternate currency purchases involving mercs!
if (GetClientVersion() >= EQClientRoF) MercTemplate *mercData = &zone->merc_templates[GetMercInfo().MercTemplateID];
int stancecount = 0;
stancecount += zone->merc_stance_list[GetMercInfo().MercTemplateID].size();
if(stancecount > MAX_MERC_STANCES || mercCount > MAX_MERC || mercTypeCount > MAX_MERC_GRADES)
{ {
MercTemplate *mercData = &zone->merc_templates[GetMercInfo().MercTemplateID]; SendMercMerchantResponsePacket(0);
return;
}
if (mercData) if(mercData)
{
if (GetClientVersion() >= EQClientRoF)
{ {
int i = 0; if (mercCount > 0)
int stancecount = 0;
stancecount += zone->merc_stance_list[GetMercInfo().MercTemplateID].size();
if(stancecount > MAX_MERC_STANCES || mercCount > MAX_MERC || mercTypeCount > MAX_MERC_GRADES)
{
SendMercMerchantResponsePacket(0);
return;
}
if (mercCount > 0 && mercCount)
{ {
EQApplicationPacket *outapp = new EQApplicationPacket(OP_MercenaryDataUpdate, sizeof(MercenaryDataUpdate_Struct)); EQApplicationPacket *outapp = new EQApplicationPacket(OP_MercenaryDataUpdate, sizeof(MercenaryDataUpdate_Struct));
MercenaryDataUpdate_Struct* mdus = (MercenaryDataUpdate_Struct*)outapp->pBuffer; MercenaryDataUpdate_Struct* mdus = (MercenaryDataUpdate_Struct*)outapp->pBuffer;
@ -7354,40 +7352,19 @@ void Client::SendMercPersonalInfo()
mdus->MercData[i].MercUnk05 = 1; mdus->MercData[i].MercUnk05 = 1;
FastQueuePacket(&outapp); FastQueuePacket(&outapp);
safe_delete(outapp);
return; return;
} }
} }
} else
else
{
int stancecount = 0;
stancecount += zone->merc_stance_list[GetMercInfo().MercTemplateID].size();
if(mercCount > MAX_MERC || mercTypeCount > MAX_MERC_GRADES)
{ {
if (GetClientVersion() == EQClientSoD) if(mercTypeCount > 0 && mercCount > 0)
{ {
SendMercMerchantResponsePacket(0); EQApplicationPacket *outapp = new EQApplicationPacket(OP_MercenaryDataResponse, sizeof(MercenaryMerchantList_Struct));
} MercenaryMerchantList_Struct* mml = (MercenaryMerchantList_Struct*)outapp->pBuffer;
return; mml->MercTypeCount = mercTypeCount; //We should only have one merc entry.
}
EQApplicationPacket *outapp = new EQApplicationPacket(OP_MercenaryDataResponse, sizeof(MercenaryMerchantList_Struct));
MercenaryMerchantList_Struct* mml = (MercenaryMerchantList_Struct*)outapp->pBuffer;
MercTemplate *mercData = &zone->merc_templates[GetMercInfo().MercTemplateID];
if(mercData)
{
if(mercTypeCount > 0)
{
mml->MercTypeCount = mercTypeCount; //We only should have one merc entry.
mml->MercGrades[i] = 1; mml->MercGrades[i] = 1;
} mml->MercCount = mercCount;
mml->MercCount = mercCount;
if(mercCount > 0)
{
mml->Mercs[i].MercID = mercData->MercTemplateID; mml->Mercs[i].MercID = mercData->MercTemplateID;
mml->Mercs[i].MercType = mercData->MercType; mml->Mercs[i].MercType = mercData->MercType;
mml->Mercs[i].MercSubType = mercData->MercSubType; mml->Mercs[i].MercSubType = mercData->MercSubType;
@ -7404,7 +7381,7 @@ void Client::SendMercPersonalInfo()
mml->Mercs[i].StanceCount = zone->merc_stance_list[mercData->MercTemplateID].size(); mml->Mercs[i].StanceCount = zone->merc_stance_list[mercData->MercTemplateID].size();
mml->Mercs[i].MercUnk03 = 0; mml->Mercs[i].MercUnk03 = 0;
mml->Mercs[i].MercUnk04 = 1; mml->Mercs[i].MercUnk04 = 1;
//mml->Mercs[i].MercName; strn0cpy(mml->Mercs[i].MercName, GetMercInfo().merc_name , sizeof(mml->Mercs[i].MercName));
int stanceindex = 0; int stanceindex = 0;
if(mml->Mercs[i].StanceCount != 0) if(mml->Mercs[i].StanceCount != 0)
{ {
@ -7418,31 +7395,12 @@ void Client::SendMercPersonalInfo()
} }
} }
FastQueuePacket(&outapp); FastQueuePacket(&outapp);
}
else
{
safe_delete(outapp); safe_delete(outapp);
if (GetClientVersion() == EQClientSoD)
{
SendMercMerchantResponsePacket(0);
}
return; return;
} }
if (GetClientVersion() == EQClientSoD)
{
SendMercMerchantResponsePacket(0);
}
}
else
{
safe_delete(outapp);
if (GetClientVersion() == EQClientSoD)
{
SendMercMerchantResponsePacket(0);
}
return;
} }
} }
SendMercMerchantResponsePacket(0);
} }
void Client::SendClearMercInfo() void Client::SendClearMercInfo()

File diff suppressed because it is too large Load Diff

View File

@ -9699,17 +9699,13 @@ void Client::Handle_OP_MercenaryDismiss(const EQApplicationPacket *app)
Message(7, "Mercenary Debug: Dismiss Request ( %i ) Received.", Command); Message(7, "Mercenary Debug: Dismiss Request ( %i ) Received.", Command);
// Handle the dismiss here... // Handle the dismiss here...
if (GetMercID()) { Merc* merc = GetMerc();
Merc* merc = GetMerc(); if (merc) {
if (CheckCanDismissMerc()) {
if (merc) { merc->Dismiss();
if (CheckCanDismissMerc()) {
merc->Dismiss();
}
} }
} }
//SendMercMerchantResponsePacket(10);
} }
void Client::Handle_OP_MercenaryHire(const EQApplicationPacket *app) void Client::Handle_OP_MercenaryHire(const EQApplicationPacket *app)
@ -9749,21 +9745,22 @@ void Client::Handle_OP_MercenaryHire(const EQApplicationPacket *app)
return; return;
} }
if (RuleB(Mercs, ChargeMercPurchaseCost)) {
uint32 cost = Merc::CalcPurchaseCost(merc_template->MercTemplateID, GetLevel()) * 100; // Cost is in gold
TakeMoneyFromPP(cost, true);
}
// Set time remaining to max on Hire // Set time remaining to max on Hire
GetMercInfo().MercTimerRemaining = RuleI(Mercs, UpkeepIntervalMS); GetMercInfo().MercTimerRemaining = RuleI(Mercs, UpkeepIntervalMS);
// Get merc, assign it to client & spawn // Get merc, assign it to client & spawn
Merc* merc = Merc::LoadMerc(this, merc_template, merchant_id, false); Merc* merc = Merc::LoadMerc(this, merc_template, merchant_id, false);
if (merc) { if (merc)
{
SpawnMerc(merc, true); SpawnMerc(merc, true);
merc->Save(); merc->Save();
if (RuleB(Mercs, ChargeMercPurchaseCost)) {
uint32 cost = Merc::CalcPurchaseCost(merc_template->MercTemplateID, GetLevel()) * 100; // Cost is in gold
TakeMoneyFromPP(cost, true);
}
// 0 is approved hire request // 0 is approved hire request
SendMercMerchantResponsePacket(0); SendMercMerchantResponsePacket(0);
} }

View File

@ -78,7 +78,8 @@ bool Client::Process() {
if(Connected() || IsLD()) if(Connected() || IsLD())
{ {
// try to send all packets that weren't sent before // try to send all packets that weren't sent before
if(!IsLD() && zoneinpacket_timer.Check()){ if(!IsLD() && zoneinpacket_timer.Check())
{
SendAllPackets(); SendAllPackets();
} }
@ -145,7 +146,9 @@ bool Client::Process() {
if(mana_timer.Check()) if(mana_timer.Check())
SendManaUpdatePacket(); SendManaUpdatePacket();
if(dead && dead_timer.Check()) {
if(dead && dead_timer.Check())
{
database.MoveCharacterToZone(GetName(),database.GetZoneName(m_pp.binds[0].zoneId)); database.MoveCharacterToZone(GetName(),database.GetZoneName(m_pp.binds[0].zoneId));
m_pp.zone_id = m_pp.binds[0].zoneId; m_pp.zone_id = m_pp.binds[0].zoneId;
m_pp.zoneInstance = 0; m_pp.zoneInstance = 0;
@ -176,14 +179,16 @@ bool Client::Process() {
if(TaskPeriodic_Timer.Check() && taskstate) if(TaskPeriodic_Timer.Check() && taskstate)
taskstate->TaskPeriodicChecks(this); taskstate->TaskPeriodicChecks(this);
if(linkdead_timer.Check()){ if(linkdead_timer.Check())
{
LeaveGroup();
Save(); Save();
if (GetMerc()) if (GetMerc())
{ {
GetMerc()->Save(); GetMerc()->Save();
GetMerc()->Depop(); GetMerc()->Depop();
} }
LeaveGroup();
Raid *myraid = entity_list.GetRaidByClient(this); Raid *myraid = entity_list.GetRaidByClient(this);
if (myraid) if (myraid)
{ {
@ -192,7 +197,8 @@ bool Client::Process() {
return false; //delete client return false; //delete client
} }
if (camp_timer.Check()) { if (camp_timer.Check())
{
LeaveGroup(); LeaveGroup();
Save(); Save();
if (GetMerc()) if (GetMerc())
@ -228,20 +234,22 @@ bool Client::Process() {
} else { } else {
if(!ApplyNextBardPulse(bardsong, song_target, bardsong_slot)) if(!ApplyNextBardPulse(bardsong, song_target, bardsong_slot))
InterruptSpell(SONG_ENDS_ABRUPTLY, 0x121, bardsong); InterruptSpell(SONG_ENDS_ABRUPTLY, 0x121, bardsong);
// SpellFinished(bardsong, bardsong_target, bardsong_slot, spells[bardsong].mana); //SpellFinished(bardsong, bardsong_target, bardsong_slot, spells[bardsong].mana);
} }
} }
if(GetMerc()) if(GetMerc())
{ {
UpdateMercTimer(); UpdateMercTimer();
} }
if(GetMercInfo().MercTemplateID != 0 && GetMercInfo().IsSuspended) if(GetMercInfo().MercTemplateID != 0 && GetMercInfo().IsSuspended)
{ {
if(p_timers.Expired(&database, pTimerMercSuspend, false)) { //CheckMercSuspendTimer();
CheckMercSuspendTimer(); if(p_timers.Expired(&database, pTimerMercSuspend, false))
} {
CheckMercSuspendTimer();
}
} }
if(IsAIControlled()) if(IsAIControlled())
@ -715,16 +723,13 @@ bool Client::Process() {
} }
#endif #endif
if (client_state != CLIENT_LINKDEAD && (client_state == CLIENT_ERROR || client_state == DISCONNECTED || client_state == CLIENT_KICKED || !eqs->CheckState(ESTABLISHED))) { if (client_state != CLIENT_LINKDEAD && (client_state == CLIENT_ERROR || client_state == DISCONNECTED || client_state == CLIENT_KICKED || !eqs->CheckState(ESTABLISHED)))
{
//client logged out or errored out //client logged out or errored out
//ResetTrade(); //ResetTrade();
if (client_state != CLIENT_KICKED) { if (client_state != CLIENT_KICKED) {
Save(); Save();
} }
if (GetMerc())
{
GetMerc()->Depop();
}
client_state = CLIENT_LINKDEAD; client_state = CLIENT_LINKDEAD;
if (zoning || instalog || GetGM()) if (zoning || instalog || GetGM())
@ -732,23 +737,32 @@ bool Client::Process() {
Group *mygroup = GetGroup(); Group *mygroup = GetGroup();
if (mygroup) if (mygroup)
{ {
if (!zoning) { if (!zoning)
{
entity_list.MessageGroup(this, true, 15, "%s logged out.", GetName()); entity_list.MessageGroup(this, true, 15, "%s logged out.", GetName());
mygroup->DelMember(this); LeaveGroup();
} else { }
else
{
entity_list.MessageGroup(this, true, 15, "%s left the zone.", GetName()); entity_list.MessageGroup(this, true, 15, "%s left the zone.", GetName());
mygroup->MemberZoned(this); mygroup->MemberZoned(this);
if (GetMerc() && GetMerc()->HasGroup() && GetMerc()->GetGroup() == mygroup)
{
mygroup->DelMember(GetMerc());
}
} }
} }
Raid *myraid = entity_list.GetRaidByClient(this); Raid *myraid = entity_list.GetRaidByClient(this);
if (myraid) if (myraid)
{ {
if (!zoning) { if (!zoning)
{
//entity_list.MessageGroup(this,true,15,"%s logged out.",GetName()); //entity_list.MessageGroup(this,true,15,"%s logged out.",GetName());
//mygroup->DelMember(this);
myraid->MemberZoned(this); myraid->MemberZoned(this);
} else { }
else
{
//entity_list.MessageGroup(this,true,15,"%s left the zone.",GetName()); //entity_list.MessageGroup(this,true,15,"%s left the zone.",GetName());
myraid->MemberZoned(this); myraid->MemberZoned(this);
} }
@ -774,8 +788,14 @@ bool Client::Process() {
/* Just a set of actions preformed all over in Client::Process */ /* Just a set of actions preformed all over in Client::Process */
void Client::OnDisconnect(bool hard_disconnect) { void Client::OnDisconnect(bool hard_disconnect) {
if(hard_disconnect) { if(hard_disconnect)
{
LeaveGroup(); LeaveGroup();
if (GetMerc())
{
GetMerc()->Save();
GetMerc()->Depop();
}
Raid *MyRaid = entity_list.GetRaidByClient(this); Raid *MyRaid = entity_list.GetRaidByClient(this);
if (MyRaid) if (MyRaid)
@ -791,7 +811,8 @@ void Client::OnDisconnect(bool hard_disconnect) {
} }
Mob *Other = trade->With(); Mob *Other = trade->With();
if(Other) { if(Other)
{
mlog(TRADING__CLIENT, "Client disconnected during a trade. Returning their items."); mlog(TRADING__CLIENT, "Client disconnected during a trade. Returning their items.");
FinishTrade(this); FinishTrade(this);

View File

@ -1069,14 +1069,29 @@ void Group::GroupMessage_StringID(Mob* sender, uint32 type, uint32 string_id, co
void Client::LeaveGroup() { void Client::LeaveGroup() {
Group *g = GetGroup(); Group *g = GetGroup();
if(g) { if(g)
{
if(g->GroupCount() < 3) if(g->GroupCount() < 3)
{
g->DisbandGroup(); g->DisbandGroup();
}
else else
{
g->DelMember(this); g->DelMember(this);
} else { if (GetMerc() && GetMerc()->HasGroup() && GetMerc()->GetGroup() == g)
{
g->DelMember(GetMerc());
}
}
}
else
{
//force things a little //force things a little
database.SetGroupID(GetName(), 0, CharacterID()); database.SetGroupID(GetName(), 0, CharacterID());
if (GetMerc())
{
database.SetGroupID(GetMerc()->GetName(), 0, CharacterID());
}
} }
isgrouped = false; isgrouped = false;

File diff suppressed because it is too large Load Diff

View File

@ -4,12 +4,18 @@
#include "zonedb.h" #include "zonedb.h"
#include "npc.h" #include "npc.h"
#define MAXMERCS 1 #define MAXMERCS 1
#define MERC_DEBUG 0 #define MERC_DEBUG 0
#define TANK 1 #define TANK 1
#define HEALER 2 #define HEALER 2
#define MELEEDPS 9 #define MELEEDPS 9
#define CASTERDPS 12 #define CASTERDPS 12
#define NO_MERC_ID 0
#define MERC_STATE_NORMAL 5
#define MERC_STATE_SUSPENDED 1
#define NOT_SUSPENDED_TIME 0
const int MercAISpellRange = 100; // TODO: Write a method that calcs what the merc's spell range is based on spell, equipment, AA, whatever and replace this const int MercAISpellRange = 100; // TODO: Write a method that calcs what the merc's spell range is based on spell, equipment, AA, whatever and replace this
enum MercStanceType { enum MercStanceType {
@ -25,19 +31,19 @@ enum MercStanceType {
}; };
struct MercSpell { struct MercSpell {
uint16 spellid; // <= 0 = no spell uint16 spellid; // <= 0 = no spell
uint32 type; // 0 = never, must be one (and only one) of the defined values uint32 type; // 0 = never, must be one (and only one) of the defined values
int16 stance; // 0 = all, + = only this stance, - = all except this stance int16 stance; // 0 = all, + = only this stance, - = all except this stance
int16 slot; int16 slot;
uint16 proc_chance; uint16 proc_chance;
uint32 time_cancast; // when we can cast this spell next uint32 time_cancast; // when we can cast this spell next
}; };
struct MercTimer { struct MercTimer {
uint16 timerid; // EndurTimerIndex uint16 timerid; // EndurTimerIndex
uint8 timertype; // 1 = spell, 2 = disc uint8 timertype; // 1 = spell, 2 = disc
uint16 spellid; // <= 0 = no spell uint16 spellid; // <= 0 = no spell
uint32 time_cancast; // when we can cast this spell next uint32 time_cancast; // when we can cast this spell next
}; };
class Merc : public NPC { class Merc : public NPC {
@ -49,7 +55,7 @@ public:
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, SkillUseTypes attack_skill); virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, SkillUseTypes attack_skill);
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, SkillUseTypes attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false); virtual void Damage(Mob* from, int32 damage, uint16 spell_id, SkillUseTypes attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false);
virtual bool Attack(Mob* other, int Hand = MainPrimary, bool FromRiposte = false, bool IsStrikethrough = false, virtual bool Attack(Mob* other, int Hand = MainPrimary, bool FromRiposte = false, bool IsStrikethrough = false,
bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr); bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr);
virtual bool HasRaid() { return false; } virtual bool HasRaid() { return false; }
virtual bool HasGroup() { return (GetGroup() ? true : false); } virtual bool HasGroup() { return (GetGroup() ? true : false); }
virtual Raid* GetRaid() { return 0; } virtual Raid* GetRaid() { return 0; }
@ -126,7 +132,7 @@ public:
static Merc* LoadMerc(Client *c, MercTemplate* merc_template, uint32 merchant_id, bool updateFromDB = false); static Merc* LoadMerc(Client *c, MercTemplate* merc_template, uint32 merchant_id, bool updateFromDB = false);
void UpdateMercInfo(Client *c); void UpdateMercInfo(Client *c);
void UpdateMercStats(Client *c); void UpdateMercStats(Client *c);
void UpdateMercAppearance(Client *c); void UpdateMercAppearance();
void AddItem(uint8 slot, uint32 item_id); void AddItem(uint8 slot, uint32 item_id);
static const char *GetRandomName(); static const char *GetRandomName();
bool Spawn(Client *owner); bool Spawn(Client *owner);
@ -139,8 +145,8 @@ public:
bool GetDepop() { return p_depop; } bool GetDepop() { return p_depop; }
bool IsDead() { return GetHP() < 0;}; bool IsDead() { return GetHP() < 0;};
bool IsMedding() {return _medding; }; bool IsMedding() { return _medding; };
bool IsSuspended() {return _suspended; }; bool IsSuspended() { return _suspended; };
static uint32 CalcPurchaseCost( uint32 templateID , uint8 level, uint8 currency_type = 0); static uint32 CalcPurchaseCost( uint32 templateID , uint8 level, uint8 currency_type = 0);
static uint32 CalcUpkeepCost( uint32 templateID , uint8 level, uint8 currency_type = 0); static uint32 CalcUpkeepCost( uint32 templateID , uint8 level, uint8 currency_type = 0);
@ -164,75 +170,75 @@ public:
inline const uint8 GetClientVersion() const { return _OwnerClientVersion; } inline const uint8 GetClientVersion() const { return _OwnerClientVersion; }
virtual void SetTarget(Mob* mob); virtual void SetTarget(Mob* mob);
bool HasSkill(SkillUseTypes skill_id) const; bool HasSkill(SkillUseTypes skill_id) const;
bool CanHaveSkill(SkillUseTypes skill_id) const; bool CanHaveSkill(SkillUseTypes skill_id) const;
uint16 MaxSkill(SkillUseTypes skillid, uint16 class_, uint16 level) const; uint16 MaxSkill(SkillUseTypes skillid, uint16 class_, uint16 level) const;
inline uint16 MaxSkill(SkillUseTypes skillid) const { return MaxSkill(skillid, GetClass(), GetLevel()); } inline uint16 MaxSkill(SkillUseTypes skillid) const { return MaxSkill(skillid, GetClass(), GetLevel()); }
virtual void DoClassAttacks(Mob *target); virtual void DoClassAttacks(Mob *target);
void CheckHateList(); void CheckHateList();
bool CheckTaunt(); bool CheckTaunt();
bool CheckAETaunt(); bool CheckAETaunt();
bool CheckConfidence(); bool CheckConfidence();
bool TryHide(); bool TryHide();
// stat functions // stat functions
virtual void CalcBonuses(); virtual void CalcBonuses();
int32 GetEndurance() const {return cur_end;} //This gets our current endurance int32 GetEndurance() const {return cur_end;} //This gets our current endurance
inline virtual int32 GetAC() const { return AC; } inline virtual int32 GetAC() const { return AC; }
inline virtual int32 GetATK() const { return ATK; } inline virtual int32 GetATK() const { return ATK; }
inline virtual int32 GetATKBonus() const { return itembonuses.ATK + spellbonuses.ATK; } inline virtual int32 GetATKBonus() const { return itembonuses.ATK + spellbonuses.ATK; }
int32 GetRawACNoShield(int &shield_ac) const; int32 GetRawACNoShield(int &shield_ac) const;
inline virtual int32 GetSTR() const { return STR; } inline virtual int32 GetSTR() const { return STR; }
inline virtual int32 GetSTA() const { return STA; } inline virtual int32 GetSTA() const { return STA; }
inline virtual int32 GetDEX() const { return DEX; } inline virtual int32 GetDEX() const { return DEX; }
inline virtual int32 GetAGI() const { return AGI; } inline virtual int32 GetAGI() const { return AGI; }
inline virtual int32 GetINT() const { return INT; } inline virtual int32 GetINT() const { return INT; }
inline virtual int32 GetWIS() const { return WIS; } inline virtual int32 GetWIS() const { return WIS; }
inline virtual int32 GetCHA() const { return CHA; } inline virtual int32 GetCHA() const { return CHA; }
inline virtual int32 GetMR() const { return MR; } inline virtual int32 GetMR() const { return MR; }
inline virtual int32 GetFR() const { return FR; } inline virtual int32 GetFR() const { return FR; }
inline virtual int32 GetDR() const { return DR; } inline virtual int32 GetDR() const { return DR; }
inline virtual int32 GetPR() const { return PR; } inline virtual int32 GetPR() const { return PR; }
inline virtual int32 GetCR() const { return CR; } inline virtual int32 GetCR() const { return CR; }
inline virtual int32 GetCorrup() const { return Corrup; } inline virtual int32 GetCorrup() const { return Corrup; }
inline virtual int32 GetHeroicSTR() const { return itembonuses.HeroicSTR; } inline virtual int32 GetHeroicSTR() const { return itembonuses.HeroicSTR; }
inline virtual int32 GetHeroicSTA() const { return itembonuses.HeroicSTA; } inline virtual int32 GetHeroicSTA() const { return itembonuses.HeroicSTA; }
inline virtual int32 GetHeroicDEX() const { return itembonuses.HeroicDEX; } inline virtual int32 GetHeroicDEX() const { return itembonuses.HeroicDEX; }
inline virtual int32 GetHeroicAGI() const { return itembonuses.HeroicAGI; } inline virtual int32 GetHeroicAGI() const { return itembonuses.HeroicAGI; }
inline virtual int32 GetHeroicINT() const { return itembonuses.HeroicINT; } inline virtual int32 GetHeroicINT() const { return itembonuses.HeroicINT; }
inline virtual int32 GetHeroicWIS() const { return itembonuses.HeroicWIS; } inline virtual int32 GetHeroicWIS() const { return itembonuses.HeroicWIS; }
inline virtual int32 GetHeroicCHA() const { return itembonuses.HeroicCHA; } inline virtual int32 GetHeroicCHA() const { return itembonuses.HeroicCHA; }
inline virtual int32 GetHeroicMR() const { return itembonuses.HeroicMR; } inline virtual int32 GetHeroicMR() const { return itembonuses.HeroicMR; }
inline virtual int32 GetHeroicFR() const { return itembonuses.HeroicFR; } inline virtual int32 GetHeroicFR() const { return itembonuses.HeroicFR; }
inline virtual int32 GetHeroicDR() const { return itembonuses.HeroicDR; } inline virtual int32 GetHeroicDR() const { return itembonuses.HeroicDR; }
inline virtual int32 GetHeroicPR() const { return itembonuses.HeroicPR; } inline virtual int32 GetHeroicPR() const { return itembonuses.HeroicPR; }
inline virtual int32 GetHeroicCR() const { return itembonuses.HeroicCR; } inline virtual int32 GetHeroicCR() const { return itembonuses.HeroicCR; }
inline virtual int32 GetHeroicCorrup() const { return itembonuses.HeroicCorrup; } inline virtual int32 GetHeroicCorrup() const { return itembonuses.HeroicCorrup; }
// Mod2 // Mod2
inline virtual int32 GetShielding() const { return itembonuses.MeleeMitigation; } inline virtual int32 GetShielding() const { return itembonuses.MeleeMitigation; }
inline virtual int32 GetSpellShield() const { return itembonuses.SpellShield; } inline virtual int32 GetSpellShield() const { return itembonuses.SpellShield; }
inline virtual int32 GetDoTShield() const { return itembonuses.DoTShielding; } inline virtual int32 GetDoTShield() const { return itembonuses.DoTShielding; }
inline virtual int32 GetStunResist() const { return itembonuses.StunResist; } inline virtual int32 GetStunResist() const { return itembonuses.StunResist; }
inline virtual int32 GetStrikeThrough() const { return itembonuses.StrikeThrough; } inline virtual int32 GetStrikeThrough() const { return itembonuses.StrikeThrough; }
inline virtual int32 GetAvoidance() const { return itembonuses.AvoidMeleeChance; } inline virtual int32 GetAvoidance() const { return itembonuses.AvoidMeleeChance; }
inline virtual int32 GetAccuracy() const { return itembonuses.HitChance; } inline virtual int32 GetAccuracy() const { return itembonuses.HitChance; }
inline virtual int32 GetCombatEffects() const { return itembonuses.ProcChance; } inline virtual int32 GetCombatEffects() const { return itembonuses.ProcChance; }
inline virtual int32 GetDS() const { return itembonuses.DamageShield; } inline virtual int32 GetDS() const { return itembonuses.DamageShield; }
// Mod3 // Mod3
inline virtual int32 GetHealAmt() const { return itembonuses.HealAmt; } inline virtual int32 GetHealAmt() const { return itembonuses.HealAmt; }
inline virtual int32 GetSpellDmg() const { return itembonuses.SpellDmg; } inline virtual int32 GetSpellDmg() const { return itembonuses.SpellDmg; }
inline virtual int32 GetClair() const { return itembonuses.Clairvoyance; } inline virtual int32 GetClair() const { return itembonuses.Clairvoyance; }
inline virtual int32 GetDSMit() const { return itembonuses.DSMitigation; } inline virtual int32 GetDSMit() const { return itembonuses.DSMitigation; }
inline virtual int32 GetSingMod() const { return itembonuses.singingMod; } inline virtual int32 GetSingMod() const { return itembonuses.singingMod; }
inline virtual int32 GetBrassMod() const { return itembonuses.brassMod; } inline virtual int32 GetBrassMod() const { return itembonuses.brassMod; }
inline virtual int32 GetPercMod() const { return itembonuses.percussionMod; } inline virtual int32 GetPercMod() const { return itembonuses.percussionMod; }
inline virtual int32 GetStringMod() const { return itembonuses.stringedMod; } inline virtual int32 GetStringMod() const { return itembonuses.stringedMod; }
inline virtual int32 GetWindMod() const { return itembonuses.windMod; } inline virtual int32 GetWindMod() const { return itembonuses.windMod; }
inline virtual int32 GetDelayDeath() const { return aabonuses.DelayDeath + spellbonuses.DelayDeath + itembonuses.DelayDeath + 11; } inline virtual int32 GetDelayDeath() const { return aabonuses.DelayDeath + spellbonuses.DelayDeath + itembonuses.DelayDeath + 11; }
// "SET" Class Methods // "SET" Class Methods
void SetMercData (uint32 templateID ); void SetMercData (uint32 templateID );
@ -267,68 +273,69 @@ protected:
void AddItemBonuses(const Item_Struct *item, StatBonuses* newbon); void AddItemBonuses(const Item_Struct *item, StatBonuses* newbon);
int CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat); int CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat);
int16 GetFocusEffect(focusType type, uint16 spell_id); int16 GetFocusEffect(focusType type, uint16 spell_id);
std::vector<MercSpell> merc_spells; std::vector<MercSpell> merc_spells;
std::map<uint32,MercTimer> timers; std::map<uint32,MercTimer> timers;
uint16 skills[HIGHEST_SKILL+1]; uint16 skills[HIGHEST_SKILL+1];
uint32 equipment[EmuConstants::EQUIPMENT_SIZE]; //this is an array of item IDs uint32 equipment[EmuConstants::EQUIPMENT_SIZE]; //this is an array of item IDs
uint16 d_meele_texture1; //this is an item Material value uint16 d_meele_texture1; //this is an item Material value
uint16 d_meele_texture2; //this is an item Material value (offhand) uint16 d_meele_texture2; //this is an item Material value (offhand)
uint8 prim_melee_type; //Sets the Primary Weapon attack message and animation 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 sec_melee_type; //Sets the Secondary Weapon attack message and animation
private: private:
int32 CalcAC(); int32 CalcAC();
int32 GetACMit(); int32 GetACMit();
int32 GetACAvoid(); int32 GetACAvoid();
int32 acmod(); int32 acmod();
int32 CalcATK(); int32 CalcATK();
//int CalcHaste(); //int CalcHaste();
int32 CalcSTR(); int32 CalcSTR();
int32 CalcSTA(); int32 CalcSTA();
int32 CalcDEX(); int32 CalcDEX();
int32 CalcAGI(); int32 CalcAGI();
int32 CalcINT(); int32 CalcINT();
int32 CalcWIS(); int32 CalcWIS();
int32 CalcCHA(); int32 CalcCHA();
int32 CalcMR(); int32 CalcMR();
int32 CalcFR(); int32 CalcFR();
int32 CalcDR(); int32 CalcDR();
int32 CalcPR(); int32 CalcPR();
int32 CalcCR(); int32 CalcCR();
int32 CalcCorrup(); int32 CalcCorrup();
int32 CalcMaxHP(); int32 CalcMaxHP();
int32 CalcBaseHP(); int32 CalcBaseHP();
int32 GetClassHPFactor(); int32 GetClassHPFactor();
int32 CalcHPRegen(); int32 CalcHPRegen();
int32 CalcHPRegenCap(); int32 CalcHPRegenCap();
int32 CalcMaxMana(); int32 CalcMaxMana();
int32 CalcBaseMana(); int32 CalcBaseMana();
int32 CalcManaRegen(); int32 CalcManaRegen();
int32 CalcBaseManaRegen(); int32 CalcBaseManaRegen();
int32 CalcManaRegenCap(); int32 CalcManaRegenCap();
void CalcMaxEndurance(); //This calculates the maximum endurance we can have void CalcMaxEndurance(); //This calculates the maximum endurance we can have
int32 CalcBaseEndurance(); //Calculates Base End int32 CalcBaseEndurance(); //Calculates Base End
int32 GetMaxEndurance() const {return max_end;} //This gets our endurance from the last CalcMaxEndurance() call int32 GetMaxEndurance() const {return max_end;} //This gets our endurance from the last CalcMaxEndurance() call
int32 CalcEnduranceRegen(); //Calculates endurance regen used in DoEnduranceRegen() int32 CalcEnduranceRegen(); //Calculates endurance regen used in DoEnduranceRegen()
int32 CalcEnduranceRegenCap(); int32 CalcEnduranceRegenCap();
void SetEndurance(int32 newEnd); //This sets the current endurance to the new value void SetEndurance(int32 newEnd); //This sets the current endurance to the new value
void DoEnduranceUpkeep(); //does the endurance upkeep void DoEnduranceUpkeep(); //does the endurance upkeep
void CalcRestState(); void CalcRestState();
int GroupLeadershipAAHealthEnhancement(); int GroupLeadershipAAHealthEnhancement();
int GroupLeadershipAAManaEnhancement(); int GroupLeadershipAAManaEnhancement();
int GroupLeadershipAAHealthRegeneration(); int GroupLeadershipAAHealthRegeneration();
int GroupLeadershipAAOffenseEnhancement(); int GroupLeadershipAAOffenseEnhancement();
void GetMercSize(); void GetMercSize();
void GenerateAppearance(); void GenerateAppearance();
bool LoadMercSpells(); bool LoadMercSpells();
bool CheckStance(int16 stance); bool CheckStance(int16 stance);
std::vector<MercSpell> GetMercSpells() { return merc_spells; } std::vector<MercSpell> GetMercSpells() { return merc_spells; }
@ -344,8 +351,8 @@ private:
uint32 _baseWIS; uint32 _baseWIS;
uint32 _baseCHA; uint32 _baseCHA;
uint32 _baseATK; uint32 _baseATK;
uint32 _baseRace; // Necessary to preserve the race otherwise mercs get their race updated in the db when they get an illusion. uint32 _baseRace; // Necessary to preserve the race otherwise mercs get their race updated in the db when they get an illusion.
uint8 _baseGender; // Merc gender. Necessary to preserve the original value otherwise it can be changed by illusions. uint8 _baseGender; // Merc gender. Necessary to preserve the original value otherwise it can be changed by illusions.
uint32 _baseMR; uint32 _baseMR;
uint32 _baseCR; uint32 _baseCR;
uint32 _baseDR; uint32 _baseDR;
@ -368,19 +375,19 @@ private:
uint32 _currentStance; uint32 _currentStance;
Inventory m_inv; Inventory m_inv;
int32 max_end; int32 max_end;
int32 cur_end; int32 cur_end;
bool _medding; bool _medding;
bool _suspended; bool _suspended;
bool p_depop; bool p_depop;
bool _check_confidence; bool _check_confidence;
bool _lost_confidence; bool _lost_confidence;
int _hatedCount; int _hatedCount;
uint32 owner_char_id; uint32 owner_char_id;
Timer endupkeep_timer; Timer endupkeep_timer;
Timer rest_timer; Timer rest_timer;
Timer confidence_timer; Timer confidence_timer;
Timer check_target_timer; Timer check_target_timer;
}; };
#endif // MERC_H #endif // MERC_H

View File

@ -2107,9 +2107,6 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client
bool ZoneDatabase::LoadMercInfo(Client *client) { bool ZoneDatabase::LoadMercInfo(Client *client) {
if(client->GetEPP().merc_name[0] == 0)
return false;
std::string query = StringFormat("SELECT MercID, Slot, Name, TemplateID, SuspendedTime, " std::string query = StringFormat("SELECT MercID, Slot, Name, TemplateID, SuspendedTime, "
"IsSuspended, TimerRemaining, Gender, StanceID, HP, Mana, " "IsSuspended, TimerRemaining, Gender, StanceID, HP, Mana, "
"Endurance, Face, LuclinHairStyle, LuclinHairColor, " "Endurance, Face, LuclinHairStyle, LuclinHairColor, "
@ -2120,6 +2117,9 @@ bool ZoneDatabase::LoadMercInfo(Client *client) {
if (!results.Success()) if (!results.Success())
return false; return false;
if(results.RowCount() == 0)
return false;
for (auto row = results.begin(); row != results.end(); ++row) { for (auto row = results.begin(); row != results.end(); ++row) {
uint8 slot = atoi(row[1]); uint8 slot = atoi(row[1]);
@ -2156,9 +2156,6 @@ bool ZoneDatabase::LoadMercInfo(Client *client) {
bool ZoneDatabase::LoadCurrentMerc(Client *client) { bool ZoneDatabase::LoadCurrentMerc(Client *client) {
if(client->GetEPP().merc_name[0] == 0)
return false;
uint8 slot = client->GetMercSlot(); uint8 slot = client->GetMercSlot();
if(slot > MAXMERCS) if(slot > MAXMERCS)
@ -2176,6 +2173,9 @@ bool ZoneDatabase::LoadCurrentMerc(Client *client) {
if(!results.Success()) if(!results.Success())
return false; return false;
if(results.RowCount() == 0)
return false;
for (auto row = results.begin(); row != results.end(); ++row) { for (auto row = results.begin(); row != results.end(); ++row) {
client->GetMercInfo(slot).mercid = atoi(row[0]); client->GetMercInfo(slot).mercid = atoi(row[0]);
@ -2211,71 +2211,73 @@ bool ZoneDatabase::SaveMerc(Merc *merc) {
if(!owner) if(!owner)
return false; return false;
if(merc->GetMercID() == 0) { if(merc->GetMercID() == 0)
{
// New merc record // New merc record
uint32 TempNewMercID = 0;
std::string query = StringFormat("INSERT INTO mercs " std::string query = StringFormat("INSERT INTO mercs "
"(OwnerCharacterID, Slot, Name, TemplateID, " "(OwnerCharacterID, Slot, Name, TemplateID, "
"SuspendedTime, IsSuspended, TimerRemaining, " "SuspendedTime, IsSuspended, TimerRemaining, "
"Gender, StanceID, HP, Mana, Endurance, Face, " "Gender, StanceID, HP, Mana, Endurance, Face, "
"LuclinHairStyle, LuclinHairColor, LuclinEyeColor, " "LuclinHairStyle, LuclinHairColor, LuclinEyeColor, "
"LuclinEyeColor2, LuclinBeardColor, LuclinBeard, " "LuclinEyeColor2, LuclinBeardColor, LuclinBeard, "
"DrakkinHeritage, DrakkinTattoo, DrakkinDetails) " "DrakkinHeritage, DrakkinTattoo, DrakkinDetails) "
"VALUES('%u', '%u', '%s', '%u', '%u', '%u', '%u', " "VALUES('%u', '%u', '%s', '%u', '%u', '%u', '%u', "
"'%u', '%u', '%u', '%u', '%u', '%i', '%i', '%i', " "'%u', '%u', '%u', '%u', '%u', '%i', '%i', '%i', "
"'%i', '%i', '%i', '%i', '%i', '%i', '%i')", "'%i', '%i', '%i', '%i', '%i', '%i', '%i')",
merc->GetMercCharacterID(), owner->GetNumMercs(), merc->GetMercCharacterID(), owner->GetNumMercs(),
merc->GetCleanName(), merc->GetMercTemplateID(), merc->GetCleanName(), merc->GetMercTemplateID(),
owner->GetMercInfo().SuspendedTime, merc->IsSuspended(), owner->GetMercInfo().SuspendedTime, merc->IsSuspended(),
owner->GetMercInfo().MercTimerRemaining, merc->GetGender(), owner->GetMercInfo().MercTimerRemaining, merc->GetGender(),
merc->GetStance(), merc->GetHP(), merc->GetMana(), merc->GetStance(), merc->GetHP(), merc->GetMana(),
merc->GetEndurance(), merc->GetLuclinFace(), merc->GetEndurance(), merc->GetLuclinFace(),
merc->GetHairStyle(), merc->GetHairColor(), merc->GetEyeColor1(), merc->GetHairStyle(), merc->GetHairColor(), merc->GetEyeColor1(),
merc->GetEyeColor2(), merc->GetBeardColor(), merc->GetEyeColor2(), merc->GetBeardColor(),
merc->GetBeard(), merc->GetDrakkinHeritage(), merc->GetBeard(), merc->GetDrakkinHeritage(),
merc->GetDrakkinTattoo(), merc->GetDrakkinDetails()); merc->GetDrakkinTattoo(), merc->GetDrakkinDetails());
auto results = database.QueryDatabase(query);
auto results = database.QueryDatabase(query);
if(!results.Success()) { if(!results.Success()) {
owner->Message(13, results.ErrorMessage().c_str()); owner->Message(13, results.ErrorMessage().c_str());
return false; return false;
} else if (results.RowsAffected() != 1) { } else if (results.RowsAffected() != 1) {
owner->Message(13, "Unable to save merc to the database."); owner->Message(13, "Unable to save merc to the database.");
return false; return false;
} }
merc->SetMercID(TempNewMercID); merc->SetMercID(results.LastInsertedID());
merc->UpdateMercInfo(owner); merc->UpdateMercInfo(owner);
database.SaveMercBuffs(merc); database.SaveMercBuffs(merc);
return true; return true;
} }
// Update existing merc record // Update existing merc record
std::string query = StringFormat("UPDATE mercs SET OwnerCharacterID = '%u', Slot = '%u', " std::string query = StringFormat("UPDATE mercs SET OwnerCharacterID = '%u', Slot = '%u', "
"Name = '%s', TemplateID = '%u', SuspendedTime = '%u', " "Name = '%s', TemplateID = '%u', SuspendedTime = '%u', "
"IsSuspended = '%u', TimerRemaining = '%u', Gender = '%u', " "IsSuspended = '%u', TimerRemaining = '%u', Gender = '%u', "
"StanceID = '%u', HP = '%u', Mana = '%u', Endurance = '%u', " "StanceID = '%u', HP = '%u', Mana = '%u', Endurance = '%u', "
"Face = '%i', LuclinHairStyle = '%i', LuclinHairColor = '%i', " "Face = '%i', LuclinHairStyle = '%i', LuclinHairColor = '%i', "
"LuclinEyeColor = '%i', LuclinEyeColor2 = '%i', LuclinBeardColor = '%i', " "LuclinEyeColor = '%i', LuclinEyeColor2 = '%i', LuclinBeardColor = '%i', "
"LuclinBeard = '%i', DrakkinHeritage = '%i', DrakkinTattoo = '%i', " "LuclinBeard = '%i', DrakkinHeritage = '%i', DrakkinTattoo = '%i', "
"DrakkinDetails = '%i' WHERE MercID = '%u'", "DrakkinDetails = '%i' WHERE MercID = '%u'",
merc->GetMercCharacterID(), owner->GetMercSlot(), merc->GetCleanName(), merc->GetMercCharacterID(), owner->GetMercSlot(), merc->GetCleanName(),
merc->GetMercTemplateID(), owner->GetMercInfo().SuspendedTime, merc->GetMercTemplateID(), owner->GetMercInfo().SuspendedTime,
merc->IsSuspended(), owner->GetMercInfo().MercTimerRemaining, merc->IsSuspended(), owner->GetMercInfo().MercTimerRemaining,
merc->GetGender(), merc->GetStance(), merc->GetHP(), merc->GetMana(), merc->GetGender(), merc->GetStance(), merc->GetHP(), merc->GetMana(),
merc->GetEndurance(), merc->GetLuclinFace(), merc->GetHairStyle(), merc->GetEndurance(), merc->GetLuclinFace(), merc->GetHairStyle(),
merc->GetHairColor(), merc->GetEyeColor1(), merc->GetEyeColor2(), merc->GetHairColor(), merc->GetEyeColor1(), merc->GetEyeColor2(),
merc->GetBeardColor(), merc->GetBeard(), merc->GetDrakkinHeritage(), merc->GetBeardColor(), merc->GetBeard(), merc->GetDrakkinHeritage(),
merc->GetDrakkinTattoo(), merc->GetDrakkinDetails(), merc->GetMercID()); merc->GetDrakkinTattoo(), merc->GetDrakkinDetails(), merc->GetMercID());
auto results = database.QueryDatabase(query);
if (!results.Success()) {
owner->Message(13, results.ErrorMessage().c_str());
return false;
} else if (results.RowsAffected() != 1) {
owner->Message(13, "Unable to save merc to the database.");
return false;
}
merc->UpdateMercInfo(owner); auto results = database.QueryDatabase(query);
if (!results.Success()) {
owner->Message(13, results.ErrorMessage().c_str());
return false;
} else if (results.RowsAffected() != 1) {
owner->Message(13, "Unable to save merc to the database.");
return false;
}
merc->UpdateMercInfo(owner);
database.SaveMercBuffs(merc); database.SaveMercBuffs(merc);
return true; return true;
@ -2386,25 +2388,27 @@ void ZoneDatabase::LoadMercBuffs(Merc *merc) {
bool ZoneDatabase::DeleteMerc(uint32 merc_id) { bool ZoneDatabase::DeleteMerc(uint32 merc_id) {
if(merc_id == 0) if(merc_id == 0)
return false; return false;
bool firstQueryWorked = false; // TODO: These queries need to be ran together as a transaction.. ie,
// TODO: These queries need to be ran together as a transaction.. ie, // if one or more fail then they all will fail to commit to the database.
// if one or more fail then they all will fail to commit to the database. // ...Not all mercs will have buffs, so why is it required that both deletes succeed?
std::string query = StringFormat("DELETE FROM merc_buffs WHERE MercID = '%u'", merc_id); std::string query = StringFormat("DELETE FROM merc_buffs WHERE MercId = '%u'", merc_id);
auto results = database.QueryDatabase(query); auto results = database.QueryDatabase(query);
if(!results.Success()) if(!results.Success())
LogFile->write(EQEMuLog::Error, "Error Deleting Merc: %s", results.ErrorMessage().c_str()); {
else LogFile->write(EQEMuLog::Error, "Error Deleting Merc Buffs: %s", results.ErrorMessage().c_str());
firstQueryWorked = true; }
query = StringFormat("DELETE FROM mercs WHERE MercID = '%u'", merc_id); query = StringFormat("DELETE FROM mercs WHERE MercID = '%u'", merc_id);
if(!results.Success()) { results = database.QueryDatabase(query);
if(!results.Success())
{
LogFile->write(EQEMuLog::Error, "Error Deleting Merc: %s", results.ErrorMessage().c_str()); LogFile->write(EQEMuLog::Error, "Error Deleting Merc: %s", results.ErrorMessage().c_str());
return false; return false;
} }
return firstQueryWorked; return true;
} }
void ZoneDatabase::LoadMercEquipment(Merc *merc) { void ZoneDatabase::LoadMercEquipment(Merc *merc) {