This commit is contained in:
Paul Coene
2015-02-01 09:34:04 -05:00
137 changed files with 6979 additions and 2499 deletions
+8 -9
View File
@@ -481,7 +481,7 @@ void EntityList::AIYellForHelp(Mob* sender, Mob* attacker) {
}
/*
solar: returns false if attack should not be allowed
returns false if attack should not be allowed
I try to list every type of conflict that's possible here, so it's easy
to see how the decision is made. Yea, it could be condensed and made
faster, but I'm doing it this way to make it readable and easy to modify
@@ -550,7 +550,7 @@ bool Mob::IsAttackAllowed(Mob *target, bool isSpellAttack)
}
}
// solar: the format here is a matrix of mob type vs mob type.
// the format here is a matrix of mob type vs mob type.
// redundant ones are omitted and the reverse is tried if it falls through.
// first figure out if we're pets. we always look at the master's flags.
@@ -701,7 +701,7 @@ type', in which case, the answer is yes.
}
// solar: this is to check if non detrimental things are allowed to be done
// this is to check if non detrimental things are allowed to be done
// to the target. clients cannot affect npcs and vice versa, and clients
// cannot affect other clients that are not of the same pvp flag as them.
// also goes for their pets
@@ -717,7 +717,7 @@ bool Mob::IsBeneficialAllowed(Mob *target)
if (target->GetAllowBeneficial())
return true;
// solar: see IsAttackAllowed for notes
// see IsAttackAllowed for notes
// first figure out if we're pets. we always look at the master's flags.
// no need to compare pets to anything
@@ -1233,7 +1233,7 @@ void Mob::ClearFeignMemory() {
AIfeignremember_timer->Disable();
}
bool Mob::PassCharismaCheck(Mob* caster, Mob* spellTarget, uint16 spell_id) {
bool Mob::PassCharismaCheck(Mob* caster, uint16 spell_id) {
/*
Charm formula is correct based on over 50 hours of personal live parsing - Kayen
@@ -1260,9 +1260,9 @@ bool Mob::PassCharismaCheck(Mob* caster, Mob* spellTarget, uint16 spell_id) {
return true;
if (RuleB(Spells, CharismaCharmDuration))
resist_check = ResistSpell(spells[spell_id].resisttype, spell_id, caster,0,0,true,true);
resist_check = ResistSpell(spells[spell_id].resisttype, spell_id, caster,false,0,true,true);
else
resist_check = ResistSpell(spells[spell_id].resisttype, spell_id, caster, 0,0, false, true);
resist_check = ResistSpell(spells[spell_id].resisttype, spell_id, caster, false,0, false, true);
//2: The mob makes a resistance check against the charm
if (resist_check == 100)
@@ -1286,8 +1286,7 @@ bool Mob::PassCharismaCheck(Mob* caster, Mob* spellTarget, uint16 spell_id) {
{
// Assume this is a harmony/pacify spell
// If 'Lull' spell resists, do a second resist check with a charisma modifier AND regular resist checks. If resists agian you gain aggro.
resist_check = ResistSpell(spells[spell_id].resisttype, spell_id, caster, true);
resist_check = ResistSpell(spells[spell_id].resisttype, spell_id, caster, false,0,true);
if (resist_check == 100)
return true;
}
+3 -3
View File
@@ -343,7 +343,7 @@ bool Mob::CheckHitChance(Mob* other, SkillUseTypes skillinuse, int Hand, int16 c
bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
{
/* solar: called when a mob is attacked, does the checks to see if it's a hit
/* called when a mob is attacked, does the checks to see if it's a hit
* and does other mitigation checks. 'this' is the mob being attacked.
*
* special return values:
@@ -1378,7 +1378,7 @@ void Client::Damage(Mob* other, int32 damage, uint16 spell_id, SkillUseTypes att
if(spell_id==0)
spell_id = SPELL_UNKNOWN;
// cut all PVP spell damage to 2/3 -solar
// cut all PVP spell damage to 2/3
// Blasting ourselfs is considered PvP
//Don't do PvP mitigation if the caster is damaging himself
if(other && other->IsClient() && (other != this) && damage > 0) {
@@ -2545,7 +2545,7 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
}
}
// solar: this is called from Damage() when 'this' is attacked by 'other.
// this is called from Damage() when 'this' is attacked by 'other.
// 'this' is the one being attacked
// 'other' is the attacker
// a damage shield causes damage (or healing) to whoever attacks the wearer
+2 -2
View File
@@ -18,7 +18,7 @@
/*
solar: Beacon class, extends Mob. Used for AE rain spells to have a mob
Beacon class, extends Mob. Used for AE rain spells to have a mob
target to center around.
*/
@@ -48,7 +48,7 @@ class Zone;
extern EntityList entity_list;
extern Zone* zone;
// solar: if lifetime is 0 this is a permanent beacon.. not sure if that'll be
// if lifetime is 0 this is a permanent beacon.. not sure if that'll be
// useful for anything
Beacon::Beacon(Mob *at_mob, int lifetime)
:Mob
+1 -1
View File
@@ -2976,7 +2976,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
//Special custom cases for loading effects on to NPC from 'npc_spels_effects' table
if (IsAISpellEffect) {
//Non-Focused Effect to modify incomming spell damage by resist type.
//Non-Focused Effect to modify incoming spell damage by resist type.
case SE_FcSpellVulnerability:
ModVulnerability(base2, effect_value);
break;
+2 -2
View File
@@ -7406,7 +7406,7 @@ float Bot::GetProcChances(float ProcBonus, uint16 hand) {
bool Bot::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
{
/* solar: called when a mob is attacked, does the checks to see if it's a hit
/* called when a mob is attacked, does the checks to see if it's a hit
* and does other mitigation checks. 'this' is the mob being attacked.
*
* special return values:
@@ -7781,7 +7781,7 @@ void Bot::TryBackstab(Mob *other, int ReuseTime) {
if (bIsBehind || bCanFrontalBS){ // Bot is behind other OR can do Frontal Backstab
// solar - chance to assassinate
// chance to assassinate
int chance = 10 + (GetDEX()/10) + (itembonuses.HeroicDEX/10); //18.5% chance at 85 dex 40% chance at 300 dex
if(
level >= 60 && // bot is 60 or higher
+6 -3
View File
@@ -305,6 +305,8 @@ Client::Client(EQStreamInterface* ieqs)
active_light = innate_light;
spell_light = equip_light = NOT_USED;
AI_Init();
}
Client::~Client() {
@@ -402,6 +404,7 @@ Client::~Client() {
//let the stream factory know were done with this stream
eqs->Close();
eqs->ReleaseFromUse();
safe_delete(eqs);
UninitializeBuffSlots();
}
@@ -7275,7 +7278,7 @@ void Client::SendMercPersonalInfo()
stancecount += zone->merc_stance_list[GetMercInfo().MercTemplateID].size();
if(stancecount > MAX_MERC_STANCES || mercCount > MAX_MERC || mercTypeCount > MAX_MERC_GRADES)
{
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: SendMercPersonalInfo canceled: (%i) (%i) (%i)", stancecount, mercCount, mercTypeCount);
Log.Out(Logs::General, Logs::Mercenaries, "SendMercPersonalInfo canceled: (%i) (%i) (%i) for %s", stancecount, mercCount, mercTypeCount, GetName());
SendMercMerchantResponsePacket(0);
return;
}
@@ -7369,13 +7372,13 @@ void Client::SendMercPersonalInfo()
return;
}
}
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: SendMercPersonalInfo Send Successful");
Log.Out(Logs::General, Logs::Mercenaries, "SendMercPersonalInfo Send Successful for %s.", GetName());
SendMercMerchantResponsePacket(0);
}
else
{
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: SendMercPersonalInfo Send Failed Due to no MercData for %i", GetMercInfo().MercTemplateID);
Log.Out(Logs::General, Logs::Mercenaries, "SendMercPersonalInfo Send Failed Due to no MercData (%i) for %s", GetMercInfo().MercTemplateID, GetName());
}
}
+3 -2
View File
@@ -64,6 +64,7 @@ struct Item_Struct;
#include <float.h>
#include <set>
#include <algorithm>
#include <memory>
#define CLIENT_TIMEOUT 90000
@@ -201,7 +202,7 @@ struct ClientReward
class ClientFactory {
public:
Client *MakeClient(EQStream* ieqs);
Client *MakeClient(std::shared_ptr<EQStream> ieqs);
};
class Client : public Mob
@@ -1138,7 +1139,7 @@ public:
void HandleLFGuildResponse(ServerPacket *pack);
void SendLFGuildStatus();
void SendGuildLFGuildStatus();
inline bool XTargettingAvailable() const { return ((ClientVersionBit & BIT_UnderfootAndLater) && RuleB(Character, EnableXTargetting)); }
inline bool XTargettingAvailable() const { return ((ClientVersionBit & BIT_UFAndLater) && RuleB(Character, EnableXTargetting)); }
inline uint8 GetMaxXTargets() const { return MaxXTargets; }
void SetMaxXTargets(uint8 NewMax);
bool IsXTarget(const Mob *m) const;
+41 -41
View File
@@ -413,15 +413,6 @@ int Client::HandlePacket(const EQApplicationPacket *app)
std::cout << "Received 0x" << std::hex << std::setw(4) << std::setfill('0') << opcode << ", size=" << std::dec << app->size << std::endl;
#endif
#ifdef SOLAR
if(0 && opcode != OP_ClientUpdate)
{
Log.LogDebug(Logs::General,"HandlePacket() OPCODE debug enabled client %s", GetName());
std::cerr << "OPCODE: " << std::hex << std::setw(4) << std::setfill('0') << opcode << std::dec << ", size: " << app->size << std::endl;
DumpPacket(app);
}
#endif
switch(client_state) {
case CLIENT_CONNECTING: {
if(ConnectingOpcodes.count(opcode) != 1) {
@@ -848,7 +839,7 @@ void Client::CompleteConnect()
worldserver.SendPacket(pack);
delete pack;
if (IsClient() && CastToClient()->GetClientVersionBit() & BIT_UnderfootAndLater) {
if (IsClient() && CastToClient()->GetClientVersionBit() & BIT_UFAndLater) {
EQApplicationPacket *outapp = MakeBuffsPacket(false);
CastToClient()->FastQueuePacket(&outapp);
}
@@ -1169,7 +1160,6 @@ void Client::Handle_Connect_OP_SendExpZonein(const EQApplicationPacket *app)
//No idea why live sends this if even were not in a guild
SendGuildMOTD();
SpawnMercOnZone();
return;
}
@@ -1227,8 +1217,7 @@ void Client::Handle_Connect_OP_WearChange(const EQApplicationPacket *app)
void Client::Handle_Connect_OP_WorldObjectsSent(const EQApplicationPacket *app)
{
//This is a copy of SendExpZonein created for SoF due to packet order change
//This does not affect clients other than SoF
//This is a copy of SendExpZonein created for SoF+ due to packet order change
//////////////////////////////////////////////////////
// Spawn Appearance Packet
@@ -1295,7 +1284,10 @@ void Client::Handle_Connect_OP_WorldObjectsSent(const EQApplicationPacket *app)
//No idea why live sends this if even were not in a guild
SendGuildMOTD();
SpawnMercOnZone();
if (RuleB(Mercs, AllowMercs))
{
SpawnMercOnZone();
}
return;
}
@@ -1400,6 +1392,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
if (RuleB(Character, SharedBankPlat))
m_pp.platinum_shared = database.GetSharedPlatinum(this->AccountID());
database.ClearOldRecastTimestamps(cid); /* Clear out our old recast timestamps to keep the DB clean */
loaditems = database.GetInventory(cid, &m_inv); /* Load Character Inventory */
database.LoadCharacterBandolier(cid, &m_pp); /* Load Character Bandolier */
database.LoadCharacterBindPoint(cid, &m_pp); /* Load Character Bind */
@@ -1864,7 +1857,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
safe_delete(outapp);
}
if (ClientVersionBit & BIT_UnderfootAndLater) {
if (ClientVersionBit & BIT_UFAndLater) {
outapp = new EQApplicationPacket(OP_XTargetResponse, 8);
outapp->WriteUInt32(GetMaxXTargets());
outapp->WriteUInt32(0);
@@ -5503,16 +5496,6 @@ void Client::Handle_OP_EnvDamage(const EQApplicationPacket *app)
return;
}
EnvDamage2_Struct* ed = (EnvDamage2_Struct*)app->pBuffer;
if (admin >= minStatusToAvoidFalling && GetGM()){
Message(13, "Your GM status protects you from %i points of type %i environmental damage.", ed->damage, ed->dmgtype);
SetHP(GetHP() - 1);//needed or else the client wont acknowledge
return;
}
else if (GetInvul()) {
Message(13, "Your invuln status protects you from %i points of type %i environmental damage.", ed->damage, ed->dmgtype);
SetHP(GetHP() - 1);//needed or else the client wont acknowledge
return;
}
int damage = ed->damage;
@@ -5534,15 +5517,32 @@ void Client::Handle_OP_EnvDamage(const EQApplicationPacket *app)
if (damage < 0)
damage = 31337;
else if (zone->GetZoneID() == 183 || zone->GetZoneID() == 184)
if (admin >= minStatusToAvoidFalling && GetGM()){
Message(13, "Your GM status protects you from %i points of type %i environmental damage.", ed->damage, ed->dmgtype);
SetHP(GetHP() - 1);//needed or else the client wont acknowledge
return;
else
SetHP(GetHP() - damage);
}
else if (GetInvul()) {
Message(13, "Your invuln status protects you from %i points of type %i environmental damage.", ed->damage, ed->dmgtype);
SetHP(GetHP() - 1);//needed or else the client wont acknowledge
return;
}
if (GetHP() <= 0)
{
mod_client_death_env();
else if (zone->GetZoneID() == 183 || zone->GetZoneID() == 184){
return;
}
else{
SetHP(GetHP() - (damage * RuleR(Character, EnvironmentDamageMulipliter)));
/* EVENT_ENVIRONMENTAL_DAMAGE */
int final_damage = (damage * RuleR(Character, EnvironmentDamageMulipliter));
char buf[24];
snprintf(buf, 23, "%u %u %i", ed->damage, ed->dmgtype, final_damage);
parse->EventPlayer(EVENT_ENVIRONMENTAL_DAMAGE, this, buf, 0);
}
if (GetHP() <= 0) {
mod_client_death_env();
Death(0, 32000, SPELL_UNKNOWN, SkillHandtoHand);
}
SendHPUpdate();
@@ -9314,7 +9314,7 @@ void Client::Handle_OP_MercenaryCommand(const EQApplicationPacket *app)
uint32 merc_command = mc->MercCommand; // Seen 0 (zone in with no merc or suspended), 1 (dismiss merc), 5 (normal state), 20 (unknown), 36 (zone in with merc)
int32 option = mc->Option; // Seen -1 (zone in with no merc), 0 (setting to passive stance), 1 (normal or setting to balanced stance)
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: Command %i, Option %i received.", merc_command, option);
Log.Out(Logs::General, Logs::Mercenaries, "Command %i, Option %i received from %s.", merc_command, option, GetName());
if (!RuleB(Mercs, AllowMercs))
return;
@@ -9348,7 +9348,7 @@ void Client::Handle_OP_MercenaryCommand(const EQApplicationPacket *app)
merc->SetStance(mercTemplate->Stances[option]);
GetMercInfo().Stance = mercTemplate->Stances[option];
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: Set Stance: %u", merc->GetStance());
Log.Out(Logs::General, Logs::Mercenaries, "Set Stance: %u for %s (%s)", merc->GetStance(), merc->GetName(), GetName());
}
}
}
@@ -9371,7 +9371,7 @@ void Client::Handle_OP_MercenaryDataRequest(const EQApplicationPacket *app)
uint32 merchant_id = mmsr->MercMerchantID;
uint32 altCurrentType = 19;
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: Data Request for Merchant ID (%i)", merchant_id);
Log.Out(Logs::General, Logs::Mercenaries, "Data Request for Merchant ID (%i) for %s.", merchant_id, GetName());
//client is requesting data about currently owned mercenary
if (merchant_id == 0) {
@@ -9379,12 +9379,12 @@ void Client::Handle_OP_MercenaryDataRequest(const EQApplicationPacket *app)
//send info about your current merc(s)
if (GetMercInfo().mercid)
{
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: SendMercPersonalInfo Request");
Log.Out(Logs::General, Logs::Mercenaries, "SendMercPersonalInfo Request for %s.", GetName());
SendMercPersonalInfo();
}
else
{
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: SendMercPersonalInfo Not Sent - MercID (%i)", GetMercInfo().mercid);
Log.Out(Logs::General, Logs::Mercenaries, "SendMercPersonalInfo Not Sent - MercID (%i) for %s.", GetMercInfo().mercid, GetName());
}
}
@@ -9497,7 +9497,7 @@ void Client::Handle_OP_MercenaryDataUpdateRequest(const EQApplicationPacket *app
return;
}
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: Data Update Request Received.");
Log.Out(Logs::General, Logs::Mercenaries, "Data Update Request Received for %s.", GetName());
if (GetMercID())
{
@@ -9523,7 +9523,7 @@ void Client::Handle_OP_MercenaryDismiss(const EQApplicationPacket *app)
Command = VARSTRUCT_DECODE_TYPE(uint8, InBuffer);
}
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: Dismiss Request ( %i ) Received.", Command);
Log.Out(Logs::General, Logs::Mercenaries, "Dismiss Request ( %i ) Received for %s.", Command, GetName());
// Handle the dismiss here...
DismissMerc(GetMercInfo().mercid);
@@ -9548,7 +9548,7 @@ void Client::Handle_OP_MercenaryHire(const EQApplicationPacket *app)
uint32 merc_unk1 = mmrq->MercUnk01;
uint32 merc_unk2 = mmrq->MercUnk02;
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: Template ID (%i), Merchant ID (%i), Unknown1 (%i), Unknown2 (%i)", merc_template_id, merchant_id, merc_unk1, merc_unk2);
Log.Out(Logs::General, Logs::Mercenaries, "Template ID (%i), Merchant ID (%i), Unknown1 (%i), Unknown2 (%i), Client: %s", merc_template_id, merchant_id, merc_unk1, merc_unk2, GetName());
//HirePending = true;
SetHoTT(0);
@@ -9614,7 +9614,7 @@ void Client::Handle_OP_MercenarySuspendRequest(const EQApplicationPacket *app)
SuspendMercenary_Struct* sm = (SuspendMercenary_Struct*)app->pBuffer;
uint32 merc_suspend = sm->SuspendMerc; // Seen 30 for suspending or unsuspending
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: Suspend ( %i ) received.", merc_suspend);
Log.Out(Logs::General, Logs::Mercenaries, "Suspend ( %i ) received for %s.", merc_suspend, GetName());
if (!RuleB(Mercs, AllowMercs))
return;
@@ -9634,7 +9634,7 @@ void Client::Handle_OP_MercenaryTimerRequest(const EQApplicationPacket *app)
return;
}
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: Timer Request received.");
Log.Out(Logs::General, Logs::Mercenaries, "Timer Request received for %s.", GetName());
if (!RuleB(Mercs, AllowMercs)) {
return;
+4 -1
View File
@@ -960,6 +960,9 @@ void Client::BulkSendInventoryItems()
void Client::BulkSendMerchantInventory(int merchant_id, int npcid) {
const Item_Struct* handyitem = nullptr;
uint32 numItemSlots = 80; //The max number of items passed in the transaction.
if (ClientVersionBit & BIT_RoFAndLater) { // RoF+ can send 200 items
numItemSlots = 200;
}
const Item_Struct *item;
std::list<MerchantList> merlist = zone->merchanttable[merchant_id];
std::list<MerchantList>::const_iterator itr;
@@ -2231,7 +2234,7 @@ void Client::ClearHover()
entity_list.QueueClients(this, outapp, false);
safe_delete(outapp);
if(IsClient() && CastToClient()->GetClientVersionBit() & BIT_UnderfootAndLater)
if(IsClient() && CastToClient()->GetClientVersionBit() & BIT_UFAndLater)
{
EQApplicationPacket *outapp = MakeBuffsPacket(false);
CastToClient()->FastQueuePacket(&outapp);
+1041 -971
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -7,7 +7,7 @@
#define HIGHEST_RESIST 9 //Max resist type value
#define MAX_SPELL_PROJECTILE 10 //Max amount of spell projectiles that can be active by a single mob.
/* solar: macros for IsAttackAllowed, IsBeneficialAllowed */
/* macros for IsAttackAllowed, IsBeneficialAllowed */
#define _CLIENT(x) (x && x->IsClient() && !x->CastToClient()->IsBecomeNPC())
#define _NPC(x) (x && x->IsNPC() && !x->CastToMob()->GetOwnerID())
#define _BECOMENPC(x) (x && x->IsClient() && x->CastToClient()->IsBecomeNPC())
+61 -70
View File
@@ -318,54 +318,30 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
// get their tints
memcpy(item_tint, &client->GetPP().item_tint, sizeof(item_tint));
// solar: TODO soulbound items need not be added to corpse, but they need
// TODO soulbound items need not be added to corpse, but they need
// to go into the regular slots on the player, out of bags
// possessions
// TODO: accomodate soul-bound items
std::list<uint32> removed_list;
//bool cursor = false;
for(i = MAIN_BEGIN; i < EmuConstants::MAP_POSSESSIONS_SIZE; i++) {
for(i = MAIN_BEGIN; i < EmuConstants::MAP_POSSESSIONS_SIZE; ++i) {
if(i == MainAmmo && client->GetClientVersion() >= ClientVersion::SoF) {
item = client->GetInv().GetItem(MainPowerSource);
if((item && (!client->IsBecomeNPC())) || (item && client->IsBecomeNPC() && !item->GetItem()->NoRent)) {
std::list<uint32> slot_list = MoveItemToCorpse(client, item, MainPowerSource);
removed_list.merge(slot_list);
if (item != nullptr) {
if (!client->IsBecomeNPC() || (client->IsBecomeNPC() && !item->GetItem()->NoRent))
MoveItemToCorpse(client, item, MainPowerSource, removed_list);
}
}
item = client->GetInv().GetItem(i);
if((item && (!client->IsBecomeNPC())) || (item && client->IsBecomeNPC() && !item->GetItem()->NoRent)) {
std::list<uint32> slot_list = MoveItemToCorpse(client, item, i);
removed_list.merge(slot_list);
}
if (item == nullptr) { continue; }
if(!client->IsBecomeNPC() || (client->IsBecomeNPC() && !item->GetItem()->NoRent))
MoveItemToCorpse(client, item, i, removed_list);
}
#if 0
// This will either be re-enabled or deleted at some point. The client doesn't appear
// to like to have items deleted from it's buffer..or, I just haven't figure out how -U
// (Besides, the 'corpse' slots equal the size of MapPossessions..not MapPossessions + MapCorpse)
// cursor queue // (change to first client that supports 'death hover' mode, if not SoF.)
if (!RuleB(Character, RespawnFromHover) || client->GetClientVersion() < EQClientSoF) {
// bumped starting assignment to 8001 because any in-memory 'slot 8000' item was moved above as 'slot 30'
// this was mainly for client profile state reflection..should match db player inventory entries now.
i = 8001;
for (auto it = client->GetInv().cursor_begin(); it != client->GetInv().cursor_end(); ++it, i++) {
item = *it;
if ((item && (!client->IsBecomeNPC())) || (item && client->IsBecomeNPC() && !item->GetItem()->NoRent)) {
std::list<uint32> slot_list = MoveItemToCorpse(client, item, i);
removed_list.merge(slot_list);
cursor = true;
}
}
}
#endif
database.TransactionBegin();
if (removed_list.size() != 0) {
// I have an untested process that avoids this snarl up when all possessions inventory is removed..but this isn't broke -U
if (!removed_list.empty()) {
std::stringstream ss("");
ss << "DELETE FROM inventory WHERE charid=" << client->CharacterID();
ss << " AND (";
@@ -385,18 +361,6 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
database.QueryDatabase(ss.str().c_str());
}
#if 0
if (cursor) { // all cursor items should be on corpse (client < SoF or RespawnFromHover = false)
while (!client->GetInv().CursorEmpty())
client->DeleteItemInInventory(MainCursor, 0, false, false);
}
else { // only visible cursor made it to corpse (client >= Sof and RespawnFromHover = true)
std::list<ItemInst*>::const_iterator start = client->GetInv().cursor_begin();
std::list<ItemInst*>::const_iterator finish = client->GetInv().cursor_end();
database.SaveCursor(client->CharacterID(), start, finish);
}
#endif
auto start = client->GetInv().cursor_begin();
auto finish = client->GetInv().cursor_end();
database.SaveCursor(client->CharacterID(), start, finish);
@@ -406,8 +370,13 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
IsRezzed(false);
Save();
database.TransactionCommit();
UpdateEquipLightValue();
spell_light = NOT_USED;
UpdateActiveLightValue();
return;
} //end "not leaving naked corpses"
@@ -419,32 +388,49 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
Save();
}
std::list<uint32> Corpse::MoveItemToCorpse(Client *client, ItemInst *item, int16 equipslot)
void Corpse::MoveItemToCorpse(Client *client, ItemInst *inst, int16 equipSlot, std::list<uint32> &removedList)
{
int bagindex;
int16 interior_slot;
ItemInst *interior_item;
std::list<uint32> returnlist;
AddItem(
inst->GetItem()->ID,
inst->GetCharges(),
equipSlot,
inst->GetAugmentItemID(0),
inst->GetAugmentItemID(1),
inst->GetAugmentItemID(2),
inst->GetAugmentItemID(3),
inst->GetAugmentItemID(4),
inst->GetAugmentItemID(5),
inst->IsAttuned()
);
removedList.push_back(equipSlot);
AddItem(item->GetItem()->ID, item->GetCharges(), equipslot, item->GetAugmentItemID(0), item->GetAugmentItemID(1), item->GetAugmentItemID(2), item->GetAugmentItemID(3), item->GetAugmentItemID(4), item->GetAugmentItemID(5), item->IsAttuned());
returnlist.push_back(equipslot);
while (true) {
if (!inst->IsType(ItemClassContainer)) { break; }
if (equipSlot < EmuConstants::GENERAL_BEGIN || equipSlot > MainCursor) { break; }
// Qualified bag slot iterations. processing bag slots that don't exist is probably not a good idea.
if (item->IsType(ItemClassContainer) && ((equipslot >= EmuConstants::GENERAL_BEGIN && equipslot <= MainCursor))) {
for (bagindex = SUB_BEGIN; bagindex <= EmuConstants::ITEM_CONTAINER_SIZE; bagindex++) {
// For empty bags in cursor queue, slot was previously being resolved as SLOT_INVALID (-1)
interior_slot = Inventory::CalcSlotId(equipslot, bagindex);
interior_item = client->GetInv().GetItem(interior_slot);
for (auto sub_index = SUB_BEGIN; sub_index < EmuConstants::ITEM_CONTAINER_SIZE; ++sub_index) {
int16 real_bag_slot = Inventory::CalcSlotId(equipSlot, sub_index);
auto bag_inst = client->GetInv().GetItem(real_bag_slot);
if (bag_inst == nullptr) { continue; }
if (interior_item) {
AddItem(interior_item->GetItem()->ID, interior_item->GetCharges(), interior_slot, interior_item->GetAugmentItemID(0), interior_item->GetAugmentItemID(1), interior_item->GetAugmentItemID(2), interior_item->GetAugmentItemID(3), interior_item->GetAugmentItemID(4), interior_item->GetAugmentItemID(5), item->IsAttuned());
returnlist.push_back(Inventory::CalcSlotId(equipslot, bagindex));
client->DeleteItemInInventory(interior_slot, 0, true, false);
}
AddItem(
bag_inst->GetItem()->ID,
bag_inst->GetCharges(),
real_bag_slot,
bag_inst->GetAugmentItemID(0),
bag_inst->GetAugmentItemID(1),
bag_inst->GetAugmentItemID(2),
bag_inst->GetAugmentItemID(3),
bag_inst->GetAugmentItemID(4),
bag_inst->GetAugmentItemID(5),
bag_inst->IsAttuned()
);
removedList.push_back(real_bag_slot);
client->DeleteItemInInventory(real_bag_slot, 0, true, false);
}
break;
}
client->DeleteItemInInventory(equipslot, 0, true, false);
return returnlist;
client->DeleteItemInInventory(equipSlot, 0, true, false);
}
// To be called from LoadFromDBData
@@ -979,6 +965,7 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a
Save();
}
auto timestamps = database.GetItemRecastTimestamps(client->CharacterID());
outapp->priority = 6;
client->QueuePacket(outapp);
safe_delete(outapp);
@@ -987,6 +974,8 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a
const Item_Struct* item = database.GetItem(pkitem);
ItemInst* inst = database.CreateItem(item, item->MaxCharges);
if(inst) {
if (item->RecastDelay)
inst->SetRecastTimestamp(timestamps.count(item->RecastType) ? timestamps.at(item->RecastType) : 0);
client->SendItemPacket(EmuConstants::CORPSE_BEGIN, inst, ItemPacketLoot);
safe_delete(inst);
}
@@ -1018,6 +1007,8 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a
if(client && item) {
ItemInst* inst = database.CreateItem(item, item_data->charges, item_data->aug_1, item_data->aug_2, item_data->aug_3, item_data->aug_4, item_data->aug_5, item_data->aug_6, item_data->attuned);
if(inst) {
if (item->RecastDelay)
inst->SetRecastTimestamp(timestamps.count(item->RecastType) ? timestamps.at(item->RecastType) : 0);
// MainGeneral1 is the corpse inventory start offset for Ti(EMu) - CORPSE_END = MainGeneral1 + MainCursor
client->SendItemPacket(i + EmuConstants::CORPSE_BEGIN, inst, ItemPacketLoot);
safe_delete(inst);
@@ -1474,4 +1465,4 @@ void Corpse::LoadPlayerCorpseDecayTime(uint32 corpse_db_id){
else {
corpse_graveyard_timer.SetTimer(3000);
}
}
}
+1 -1
View File
@@ -128,7 +128,7 @@ class Corpse : public Mob {
virtual void UpdateEquipLightValue();
protected:
std::list<uint32> MoveItemToCorpse(Client *client, ItemInst *item, int16 equipslot);
void MoveItemToCorpse(Client *client, ItemInst *inst, int16 equipSlot, std::list<uint32> &removedList);
private:
bool is_player_corpse; /* Determines if Player Corpse or not */
+2 -2
View File
@@ -684,7 +684,7 @@ void EntityList::AETaunt(Client* taunter, float range)
}
}
// solar: causes caster to hit every mob within dist range of center with
// causes caster to hit every mob within dist range of center with
// spell_id.
// NPC spells will only affect other NPCs with compatible faction
void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster, int16 resist_adjust)
@@ -820,7 +820,7 @@ void EntityList::MassGroupBuff(Mob *caster, Mob *center, uint16 spell_id, bool a
}
}
// solar: causes caster to hit every mob within dist range of center with
// causes caster to hit every mob within dist range of center with
// a bard pulse of spell_id.
// NPC spells will only affect other NPCs with compatible faction
void EntityList::AEBardPulse(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster)
+8
View File
@@ -65,6 +65,7 @@ const char *QuestEventSubroutines[_LargestEventID] = {
"EVENT_AGGRO_SAY",
"EVENT_PLAYER_PICKUP",
"EVENT_POPUPRESPONSE",
"EVENT_ENVIRONMENTAL_DAMAGE",
"EVENT_PROXIMITY_SAY",
"EVENT_CAST",
"EVENT_CAST_BEGIN",
@@ -1290,6 +1291,13 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
ExportVar(package_name.c_str(), "popupid", data);
break;
}
case EVENT_ENVIRONMENTAL_DAMAGE:{
Seperator sep(data);
ExportVar(package_name.c_str(), "env_damage", sep.arg[0]);
ExportVar(package_name.c_str(), "env_damage_type", sep.arg[1]);
ExportVar(package_name.c_str(), "env_final_damage", sep.arg[2]);
break;
}
case EVENT_PROXIMITY_SAY: {
ExportVar(package_name.c_str(), "data", objid);
+33
View File
@@ -23,6 +23,7 @@
#include "../common/global_define.h"
#include "../common/misc_functions.h"
#include "../common/eqemu_logsys.h"
#include "embparser.h"
#include "embxs.h"
@@ -3493,6 +3494,37 @@ XS(XS__crosszonesignalnpcbynpctypeid)
XSRETURN_EMPTY;
}
XS(XS__debug);
XS(XS__debug)
{
dXSARGS;
if (items != 1 && items != 2){
Perl_croak(aTHX_ "Usage: debug(message, [debug_level])");
}
else{
std::string log_message = (std::string)SvPV_nolen(ST(0));
uint8 debug_level = 1;
if (items == 2)
debug_level = (uint8)SvIV(ST(1));
if (debug_level > Logs::Detail)
return;
if (debug_level == Logs::General){
Log.Out(Logs::General, Logs::QuestDebug, log_message);
}
else if (debug_level == Logs::Moderate){
Log.Out(Logs::Moderate, Logs::QuestDebug, log_message);
}
else if (debug_level == Logs::Detail){
Log.Out(Logs::Detail, Logs::QuestDebug, log_message);
}
}
XSRETURN_EMPTY;
}
/*
This is the callback perl will look for to setup the
quest package's XSUBs
@@ -3579,6 +3611,7 @@ EXTERN_C XS(boot_quest)
newXS(strcpy(buf, "crosszonesignalclientbycharid"), XS__crosszonesignalclientbycharid, file);
newXS(strcpy(buf, "crosszonesignalclientbyname"), XS__crosszonesignalclientbyname, file);
newXS(strcpy(buf, "crosszonesignalnpcbynpctypeid"), XS__crosszonesignalnpcbynpctypeid, file);
newXS(strcpy(buf, "debug"), XS__debug, file);
newXS(strcpy(buf, "delglobal"), XS__delglobal, file);
newXS(strcpy(buf, "depop"), XS__depop, file);
newXS(strcpy(buf, "depop_withtimer"), XS__depop_withtimer, file);
+1
View File
@@ -33,6 +33,7 @@ typedef enum {
EVENT_AGGRO_SAY,
EVENT_PLAYER_PICKUP,
EVENT_POPUP_RESPONSE,
EVENT_ENVIRONMENTAL_DAMAGE,
EVENT_PROXIMITY_SAY,
EVENT_CAST,
EVENT_CAST_BEGIN,
+1 -2
View File
@@ -506,8 +506,7 @@ void Client::SetLevel(uint8 set_level, bool command)
SetMana(CalcMaxMana());
UpdateWho();
if(GetMerc())
UpdateMercLevel();
UpdateMercLevel();
Save();
}
+2 -2
View File
@@ -879,7 +879,7 @@ void Client::PutLootInInventory(int16 slot_id, const ItemInst &inst, ServerLootI
if(bag_item_data) { // bag contents
int16 interior_slot;
// solar: our bag went into slot_id, now let's pack the contents in
// our bag went into slot_id, now let's pack the contents in
for(int i = SUB_BEGIN; i < EmuConstants::ITEM_CONTAINER_SIZE; i++) {
if(bag_item_data[i] == nullptr)
continue;
@@ -993,7 +993,7 @@ bool Client::AutoPutLootInInventory(ItemInst& inst, bool try_worn, bool try_curs
return false;
}
// solar: helper function for AutoPutLootInInventory
// helper function for AutoPutLootInInventory
void Client::MoveItemCharges(ItemInst &from, int16 to_slot, uint8 type)
{
ItemInst *tmp_inst = m_inv.GetItem(to_slot);
+4 -4
View File
@@ -1612,6 +1612,7 @@ luabind::scope lua_register_events() {
luabind::value("cast_on", static_cast<int>(EVENT_CAST_ON)),
luabind::value("task_accepted", static_cast<int>(EVENT_TASK_ACCEPTED)),
luabind::value("task_stage_complete", static_cast<int>(EVENT_TASK_STAGE_COMPLETE)),
luabind::value("environmental_damage", static_cast<int>(EVENT_ENVIRONMENTAL_DAMAGE)),
luabind::value("task_update", static_cast<int>(EVENT_TASK_UPDATE)),
luabind::value("task_complete", static_cast<int>(EVENT_TASK_COMPLETE)),
luabind::value("task_fail", static_cast<int>(EVENT_TASK_FAIL)),
@@ -1759,12 +1760,11 @@ luabind::scope lua_register_client_version() {
.enum_("constants")
[
luabind::value("Unknown", static_cast<int>(ClientVersion::Unknown)),
luabind::value("Titanium", static_cast<int>(ClientVersion::Tit)), // deprecated
luabind::value("Tit", static_cast<int>(ClientVersion::Tit)),
luabind::value("Titanium", static_cast<int>(ClientVersion::Titanium)),
luabind::value("SoF", static_cast<int>(ClientVersion::SoF)),
luabind::value("SoD", static_cast<int>(ClientVersion::SoD)),
luabind::value("Underfoot", static_cast<int>(ClientVersion::Und)), // deprecated
luabind::value("Und", static_cast<int>(ClientVersion::Und)),
luabind::value("Underfoot", static_cast<int>(ClientVersion::UF)), // deprecated
luabind::value("UF", static_cast<int>(ClientVersion::UF)),
luabind::value("RoF", static_cast<int>(ClientVersion::RoF)),
luabind::value("RoF2", static_cast<int>(ClientVersion::RoF2))
];
+3 -1
View File
@@ -35,13 +35,14 @@
#include "zone.h"
#include "lua_parser.h"
const char *LuaEvents[_LargestEventID] = {
const char *LuaEvents[_LargestEventID] = {
"event_say",
"event_trade",
"event_death",
"event_spawn",
"event_attack",
"event_combat",
"event_environmental_damage",
"event_aggro",
"event_slay",
"event_npc_slay",
@@ -164,6 +165,7 @@ LuaParser::LuaParser() {
NPCArgumentDispatch[EVENT_LEAVE_AREA] = handle_npc_area;
PlayerArgumentDispatch[EVENT_SAY] = handle_player_say;
PlayerArgumentDispatch[EVENT_ENVIRONMENTAL_DAMAGE] = handle_player_environmental_damage;
PlayerArgumentDispatch[EVENT_DEATH] = handle_player_death;
PlayerArgumentDispatch[EVENT_DEATH_COMPLETE] = handle_player_death;
PlayerArgumentDispatch[EVENT_TIMER] = handle_player_timer;
+13
View File
@@ -246,6 +246,19 @@ void handle_player_say(QuestInterface *parse, lua_State* L, Client* client, std:
lua_setfield(L, -2, "language");
}
void handle_player_environmental_damage(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<EQEmu::Any> *extra_pointers){
Seperator sep(data.c_str());
lua_pushinteger(L, std::stoi(sep.arg[0]));
lua_setfield(L, -2, "env_damage");
lua_pushinteger(L, std::stoi(sep.arg[1]));
lua_setfield(L, -2, "env_damage_type");
lua_pushinteger(L, std::stoi(sep.arg[2]));
lua_setfield(L, -2, "env_final_damage");
}
void handle_player_death(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<EQEmu::Any> *extra_pointers) {
Seperator sep(data.c_str());
+2
View File
@@ -44,6 +44,8 @@ void handle_npc_null(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, s
//Player
void handle_player_say(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<EQEmu::Any> *extra_pointers);
void handle_player_environmental_damage(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<EQEmu::Any> *extra_pointers);
void handle_player_death(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<EQEmu::Any> *extra_pointers);
void handle_player_timer(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
+4 -4
View File
@@ -413,9 +413,9 @@ bool Map::LoadV2(FILE *f) {
buf += sizeof(uint32);
}
std::map<std::string, std::shared_ptr<ModelEntry>> models;
std::map<std::string, std::unique_ptr<ModelEntry>> models;
for (uint32 i = 0; i < model_count; ++i) {
std::shared_ptr<ModelEntry> me(new ModelEntry);
std::unique_ptr<ModelEntry> me(new ModelEntry);
std::string name = buf;
buf += name.length() + 1;
@@ -456,7 +456,7 @@ bool Map::LoadV2(FILE *f) {
me->polys[j] = p;
}
models[name] = me;
models[name] = std::move(me);
}
for (uint32 i = 0; i < plac_count; ++i) {
@@ -487,7 +487,7 @@ bool Map::LoadV2(FILE *f) {
if (models.count(name) == 0)
continue;
auto model = models[name];
auto &model = models[name];
auto &mod_polys = model->polys;
auto &mod_verts = model->verts;
for (uint32 j = 0; j < mod_polys.size(); ++j) {
+250 -101
View File
@@ -42,7 +42,7 @@ Merc::Merc(const NPCType* d, float x, float y, float z, float heading)
_baseFR = d->FR;
_basePR = d->PR;
_baseCorrup = d->Corrup;
_OwnerClientVersion = static_cast<unsigned int>(ClientVersion::Tit);
_OwnerClientVersion = static_cast<unsigned int>(ClientVersion::Titanium);
RestRegenHP = 0;
RestRegenMana = 0;
RestRegenEndurance = 0;
@@ -75,7 +75,6 @@ Merc::Merc(const NPCType* d, float x, float y, float z, float heading)
SetMana(GetMaxMana());
SetEndurance(GetMaxEndurance());
AI_Init();
AI_Start();
}
@@ -1737,7 +1736,6 @@ void Merc::AI_Process() {
}
void Merc::AI_Start(int32 iMoveDelay) {
NPC::AI_Start(iMoveDelay);
if (!pAIControlled)
return;
@@ -2244,7 +2242,7 @@ bool Merc::AICastSpell(int8 iChance, int32 iSpellTypes) {
if(CheckAETaunt()) {
//get AE taunt
selectedMercSpell = GetBestMercSpellForAETaunt(this);
Log.Out(Logs::General, Logs::Mercenaries, "AE Taunting");
Log.Out(Logs::General, Logs::Mercenaries, "%s AE Taunting.", GetName());
}
if(selectedMercSpell.spellid == 0 && CheckTaunt()) {
@@ -4766,12 +4764,13 @@ Merc* Merc::LoadMerc(Client *c, MercTemplate* merc_template, uint32 merchant_id,
npc_type->no_target_hotkey = 1;
Merc* merc = new Merc(npc_type, c->GetX(), c->GetY(), c->GetZ(), 0);
merc->GiveNPCTypeData(npc_type); // for clean up, works a bit like pets
if(merc)
{
merc->SetMercData( merc_template->MercTemplateID );
database.LoadMercEquipment(merc);
merc->UpdateMercStats(c);
merc->UpdateMercStats(c, true);
if(updateFromDB)
{
@@ -4809,6 +4808,7 @@ Merc* Merc::LoadMerc(Client *c, MercTemplate* merc_template, uint32 merchant_id,
merc->LoadMercSpells();
}
Log.Out(Logs::General, Logs::Mercenaries, "LoadMerc Successful for %s (%s).", merc->GetName(), c->GetName());
return merc;
}
}
@@ -4837,50 +4837,184 @@ void Merc::UpdateMercInfo(Client *c) {
c->GetMercInfo().drakkinDetails = drakkin_details;
}
void Merc::UpdateMercStats(Client *c) {
if(c->GetMercInfo().MercTemplateID >0)
{
const NPCType* npc_type = database.GetMercType( zone->GetMercTemplate(c->GetMercInfo().MercTemplateID)->MercNPCID, GetRace(), c->GetLevel());
if (npc_type)
{
max_hp = (npc_type->max_hp * npc_type->scalerate) / 100;
base_hp = (npc_type->max_hp * npc_type->scalerate) / 100;
max_mana = (npc_type->Mana * npc_type->scalerate) / 100;
base_mana = (npc_type->Mana * npc_type->scalerate) / 100;
hp_regen = (npc_type->hp_regen * npc_type->scalerate) / 100;
mana_regen = (npc_type->mana_regen * npc_type->scalerate) / 100;
void Merc::UpdateMercStats(Client *c, bool setmax)
{
if (c->GetMercInfo().MercTemplateID > 0) {
Log.Out(Logs::General, Logs::Mercenaries, "Updating Mercenary Stats for %s (%s).", GetName(),
c->GetName());
const NPCType *npc_type = database.GetMercType(
zone->GetMercTemplate(c->GetMercInfo().MercTemplateID)->MercNPCID, GetRace(), c->GetLevel());
if (npc_type) {
max_hp = npc_type->max_hp;
base_hp = npc_type->max_hp;
max_mana = npc_type->Mana;
base_mana = npc_type->Mana;
max_end = npc_type->max_hp; // Hack since Endurance does not exist for NPCType yet
base_end = npc_type->max_hp; // Hack since Endurance does not exist for NPCType yet
hp_regen = npc_type->hp_regen;
mana_regen = npc_type->mana_regen;
max_dmg = npc_type->max_dmg;
min_dmg = npc_type->min_dmg;
_baseAC = npc_type->AC;
_baseATK = npc_type->ATK;
_baseSTR = npc_type->STR;
_baseSTA = npc_type->STA;
_baseDEX = npc_type->DEX;
_baseAGI = npc_type->AGI;
_baseWIS = npc_type->WIS;
_baseINT = npc_type->INT;
_baseCHA = npc_type->CHA;
_baseATK = npc_type->ATK;
_baseMR = npc_type->MR;
_baseFR = npc_type->FR;
_baseDR = npc_type->DR;
_basePR = npc_type->PR;
_baseCR = npc_type->CR;
_baseCorrup = npc_type->Corrup;
uint32 scalepercent = (int)(npc_type->scalerate * RuleI(Mercs, ScaleRate) / 100);
ScaleStats(scalepercent, setmax);
level = npc_type->level;
max_dmg = (npc_type->max_dmg * npc_type->scalerate) / 100;
min_dmg = (npc_type->min_dmg * npc_type->scalerate) / 100;
_baseSTR = (npc_type->STR * npc_type->scalerate) / 100;
_baseSTA = (npc_type->STA * npc_type->scalerate) / 100;
_baseDEX = (npc_type->DEX * npc_type->scalerate) / 100;
_baseAGI = (npc_type->AGI * npc_type->scalerate) / 100;
_baseWIS = (npc_type->WIS * npc_type->scalerate) / 100;
_baseINT = (npc_type->INT * npc_type->scalerate) / 100;
_baseCHA = (npc_type->CHA * npc_type->scalerate) / 100;
_baseATK = (npc_type->ATK * npc_type->scalerate) / 100;
_baseMR = (npc_type->MR * npc_type->scalerate) / 100;
_baseFR = (npc_type->FR * npc_type->scalerate) / 100;
_baseDR = (npc_type->DR * npc_type->scalerate) / 100;
_basePR = (npc_type->PR * npc_type->scalerate) / 100;
_baseCR = (npc_type->CR * npc_type->scalerate) / 100;
_baseCorrup = (npc_type->Corrup * npc_type->scalerate) / 100;
_baseAC = (npc_type->AC * npc_type->scalerate) / 100;
attack_speed = npc_type->attack_speed;
attack_count = npc_type->attack_count;
attack_delay = npc_type->attack_delay;
spellscale = npc_type->spellscale;
healscale = npc_type->healscale;
CalcBonuses();
CalcMaxEndurance();
CalcMaxHP();
CalcMaxMana();
CalcMaxEndurance();
}
}
}
void Merc::ScaleStats(int scalepercent, bool setmax) {
Log.Out(Logs::General, Logs::Mercenaries, "Scaling Mercenary Stats to %d Percent for %s.", scalepercent, GetName());
if (scalepercent <= 0)
return;
float scalerate = (float)scalepercent / 100.0f;
if ((int)((float)base_hp * scalerate) > 1)
{
max_hp = (int)((float)base_hp * scalerate);
base_hp = max_hp;
if (setmax)
cur_hp = max_hp;
}
if (base_mana)
{
max_mana = (int)((float)base_mana * scalerate);
base_mana = max_mana;
if (setmax)
cur_mana = max_mana;
}
if (base_end)
{
max_end = (int)((float)base_end * scalerate);
base_end = max_end;
if (setmax)
cur_end = max_end;
}
if (_baseAC)
{
AC = (int)((float)_baseAC * scalerate);
_baseAC = AC;
}
if (_baseATK)
{
ATK = (int)((float)_baseATK * scalerate);
_baseATK = ATK;
}
if (_baseSTR)
{
STR = (int)((float)_baseSTR * scalerate);
_baseSTR = STR;
}
if (_baseSTA)
{
STA = (int)((float)_baseSTA * scalerate);
_baseSTA = STA;
}
if (_baseAGI)
{
AGI = (int)((float)_baseAGI * scalerate);
_baseAGI = AGI;
}
if (_baseDEX)
{
DEX = (int)((float)_baseDEX * scalerate);
_baseDEX = DEX;
}
if (_baseINT)
{
INT = (int)((float)_baseINT * scalerate);
_baseINT = INT;
}
if (_baseWIS)
{
WIS = (int)((float)_baseWIS * scalerate);
_baseWIS = WIS;
}
if (_baseCHA)
{
CHA = (int)((float)_baseCHA * scalerate);
_baseCHA = CHA;
}
if (_baseMR)
{
MR = (int)((float)_baseMR * scalerate);
_baseMR = MR;
}
if (_baseCR)
{
CR = (int)((float)_baseCR * scalerate);
_baseCR = CR;
}
if (_baseDR)
{
DR = (int)((float)_baseDR * scalerate);
_baseDR = DR;
}
if (_baseFR)
{
FR = (int)((float)_baseFR * scalerate);
_baseFR = FR;
}
if (_basePR)
{
PR = (int)((float)_basePR * scalerate);
_basePR = PR;
}
if (_baseCorrup)
{
Corrup = (int)((float)_baseCorrup * scalerate);
_baseCorrup = Corrup;
}
if (max_dmg)
{
max_dmg = (int)((float)max_dmg * scalerate);
}
if (min_dmg)
{
min_dmg = (int)((float)min_dmg * scalerate);
}
return;
}
void Merc::UpdateMercAppearance() {
// Copied from Bot Code:
uint32 itemID = NO_ITEM;
@@ -4938,7 +5072,7 @@ bool Merc::Spawn(Client *owner) {
SendPosition();
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: Spawn.");
Log.Out(Logs::General, Logs::Mercenaries, "Spawn Mercenary %s.", GetName());
//UpdateMercAppearance();
@@ -5084,7 +5218,8 @@ void Client::SendMercResponsePackets(uint32 ResponseType)
SendMercMerchantResponsePacket(3);
break;
}
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: SendMercResponsePackets %i.", ResponseType);
Log.Out(Logs::General, Logs::Mercenaries, "SendMercResponsePackets %i for %s.", ResponseType, GetName());
}
void Client::UpdateMercTimer()
@@ -5125,7 +5260,7 @@ void Client::UpdateMercTimer()
SendMercResponsePackets(16);
}
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: UpdateMercTimer Complete.");
Log.Out(Logs::General, Logs::Mercenaries, "UpdateMercTimer Complete for %s.", GetName());
// Normal upkeep charge message
//Message(7, "You have been charged a mercenary upkeep cost of %i plat, and %i gold and your mercenary upkeep cost timer has been reset to 15 minutes.", upkeep_plat, upkeep_gold, (int)(RuleI(Mercs, UpkeepIntervalMS) / 1000 / 60));
@@ -5178,7 +5313,7 @@ bool Client::CheckCanHireMerc(Mob* merchant, uint32 template_id) {
}
}
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: CheckCanHireMerc True.");
Log.Out(Logs::General, Logs::Mercenaries, "CheckCanHireMerc True for %s.", GetName());
return true;
}
@@ -5251,7 +5386,7 @@ bool Client::CheckCanSpawnMerc(uint32 template_id) {
return false;
}
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: CheckCanSpawnMerc True.");
Log.Out(Logs::General, Logs::Mercenaries, "CheckCanSpawnMerc True for %s.", GetName());
return true;
}
@@ -5273,7 +5408,7 @@ bool Client::CheckCanUnsuspendMerc() {
return false;
}
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: CheckCanUnsuspendMerc True.");
Log.Out(Logs::General, Logs::Mercenaries, "CheckCanUnsuspendMerc True for %s.", GetName());
return true;
}
@@ -5288,7 +5423,7 @@ void Client::CheckMercSuspendTimer() {
GetMercInfo().SuspendedTime = 0;
SendMercResponsePackets(0);
SendMercSuspendResponsePacket(GetMercInfo().SuspendedTime);
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: CheckMercSuspendTimer Ready.");
Log.Out(Logs::General, Logs::Mercenaries, "CheckMercSuspendTimer Ready for %s.", GetName());
}
}
}
@@ -5301,7 +5436,7 @@ void Client::SuspendMercCommand() {
{
if(!CheckCanUnsuspendMerc())
{
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: SuspendMercCommand Unable to Unsuspend.");
Log.Out(Logs::General, Logs::Mercenaries, "SuspendMercCommand Unable to Unsuspend Merc for %s.", GetName());
return;
}
@@ -5311,13 +5446,13 @@ void Client::SuspendMercCommand() {
if(merc)
{
SpawnMerc(merc, true);
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: SuspendMercCommand Successful Unsuspend.");
Log.Out(Logs::General, Logs::Mercenaries, "SuspendMercCommand Successful Unsuspend for %s.", GetName());
}
else
{
//merc failed to spawn
SendMercResponsePackets(3);
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: SuspendMercCommand Failed to Spawn Merc.");
Log.Out(Logs::General, Logs::Mercenaries, "SuspendMercCommand Failed to Spawn Merc for %s.", GetName());
}
}
else
@@ -5327,10 +5462,27 @@ void Client::SuspendMercCommand() {
if(CurrentMerc && GetMercID())
{
CurrentMerc->Suspend();
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: SuspendMercCommand Successful Suspend.");
Log.Out(Logs::General, Logs::Mercenaries, "SuspendMercCommand Successful Suspend for %s.", GetName());
}
else
{
// Reset Merc Suspend State
GetMercInfo().IsSuspended = true;
//GetMercInfo().SuspendedTime = time(nullptr) + RuleI(Mercs, SuspendIntervalS);
//GetMercInfo().MercTimerRemaining = GetMercTimer()->GetRemainingTime();
//GetMercInfo().Stance = GetStance();
GetMercTimer()->Disable();
SendMercSuspendResponsePacket(GetMercInfo().SuspendedTime);
SendMercTimer(nullptr);
Log.Out(Logs::General, Logs::Mercenaries, "SuspendMercCommand Failed to Get Merc to Suspend. Resetting Suspend State for %s.", GetName());
}
}
}
else
{
SpawnMercOnZone();
Log.Out(Logs::General, Logs::Mercenaries, "SuspendMercCommand Request Failed to Load Merc for %s. Trying SpawnMercOnZone.", GetName());
}
}
@@ -5362,7 +5514,7 @@ void Client::SpawnMercOnZone() {
{
SpawnMerc(merc, false);
}
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: SpawnMercOnZone Normal Merc.");
Log.Out(Logs::General, Logs::Mercenaries, "SpawnMercOnZone Normal Merc for %s.", GetName());
}
else
{
@@ -5378,13 +5530,15 @@ void Client::SpawnMercOnZone() {
// Send Mercenary Status/Timer packet
SendMercTimer(GetMerc());
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: SpawnMercOnZone Suspended Merc.");
Log.Out(Logs::General, Logs::Mercenaries, "SpawnMercOnZone Suspended Merc for %s.", GetName());
}
}
else
{
// No Merc Hired
SendClearMercInfo();
// RoF+ displays a message from the following packet, which seems useless
//SendClearMercInfo();
Log.Out(Logs::General, Logs::Mercenaries, "SpawnMercOnZone Failed to load Merc Info from the Database for %s.", GetName());
}
}
@@ -5398,17 +5552,17 @@ void Client::SendMercTimer(Merc* merc) {
if (!merc)
{
SendMercTimerPacket(NO_MERC_ID, MERC_STATE_SUSPENDED, GetMercInfo().SuspendedTime, GetMercInfo().MercTimerRemaining, RuleI(Mercs, SuspendIntervalMS));
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: SendMercTimer No Merc.");
Log.Out(Logs::General, Logs::Mercenaries, "SendMercTimer No Merc for %s.", GetName());
}
else if (merc->IsSuspended())
{
SendMercTimerPacket(NO_MERC_ID, MERC_STATE_SUSPENDED, GetMercInfo().SuspendedTime, GetMercInfo().MercTimerRemaining, RuleI(Mercs, SuspendIntervalMS));
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: SendMercTimer Suspended Merc.");
Log.Out(Logs::General, Logs::Mercenaries, "SendMercTimer Suspended Merc for %s.", GetName());
}
else
{
SendMercTimerPacket(merc->GetID(), MERC_STATE_NORMAL, NOT_SUSPENDED_TIME, GetMercInfo().MercTimerRemaining, RuleI(Mercs, SuspendIntervalMS));
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: SendMercTimer Normal Merc.");
Log.Out(Logs::General, Logs::Mercenaries, "SendMercTimer Normal Merc for %s.", GetName());
}
}
@@ -5430,7 +5584,7 @@ void Client::SpawnMerc(Merc* merc, bool setMaxStats) {
merc->Unsuspend(setMaxStats);
merc->SetStance(GetMercInfo().Stance);
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: SpawnMerc Success.");
Log.Out(Logs::General, Logs::Mercenaries, "SpawnMerc Success for %s.", GetName());
return;
@@ -5459,7 +5613,7 @@ bool Merc::Suspend() {
// Start the timer to send the packet that refreshes the Unsuspend Button
mercOwner->GetPTimers().Start(pTimerMercSuspend, RuleI(Mercs, SuspendIntervalS));
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: Suspend Complete.");
Log.Out(Logs::General, Logs::Mercenaries, "Suspend Complete for %s.", mercOwner->GetName());
return true;
}
@@ -5545,12 +5699,12 @@ bool Client::DismissMerc(uint32 MercID) {
bool Dismissed = true;
if (!database.DeleteMerc(MercID))
{
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: Dismiss Failed for MercID %i", MercID);
Log.Out(Logs::General, Logs::Mercenaries, "Dismiss Failed Database Query for MercID: %i, Client: %s.", MercID, GetName());
Dismissed = false;
}
else
{
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: Dismiss Successful.");
Log.Out(Logs::General, Logs::Mercenaries, "Dismiss Successful for %s.", GetName());
}
if (GetMerc())
@@ -5603,24 +5757,24 @@ bool Merc::RemoveMercFromGroup(Merc* merc, Group* group) {
if(merc && group)
{
uint32 groupID = group->GetID();
if(merc->HasGroup())
{
if(!group->IsLeader(merc))
{
merc->SetFollowID(0);
if(group->DelMember(merc, true))
if (group->GroupCount() <= 2 && merc->GetGroup() == group && ZoneLoaded)
{
group->DisbandGroup();
}
else if(group->DelMember(merc, true))
{
if(merc->GetMercCharacterID() != 0)
{
database.SetGroupID(merc->GetName(), 0, merc->GetMercCharacterID(), true);
}
}
if(group->GroupCount() <= 1 && ZoneLoaded)
{
group->DisbandGroup();
}
}
else
{
@@ -5633,20 +5787,19 @@ bool Merc::RemoveMercFromGroup(Merc* merc, Group* group) {
if(!group->members[i]->IsClient())
continue;
group->members[i]->CastToClient()->LeaveGroup();
}
for(int i = 0; i < MAX_GROUP_MEMBERS; i++)
{
if(!group->members[i])
continue;
if(!group->members[i]->IsMerc())
continue;
group->members[i]->CastToMerc()->MercJoinClientGroup();
Client *groupMember = group->members[i]->CastToClient();
groupMember->LeaveGroup();
if (groupMember->GetMerc())
{
groupMember->GetMerc()->MercJoinClientGroup();
}
}
// Group should be removed by now, but just in case:
group->DisbandGroup();
Group *oldGroup = entity_list.GetGroupByID(groupID);
if (oldGroup != nullptr)
{
oldGroup->DisbandGroup();
}
}
Result = true;
@@ -5696,45 +5849,40 @@ bool Merc::MercJoinClientGroup() {
if(g->GetID() == 0)
{
delete g;
g = nullptr;
return false;
}
if(AddMercToGroup(this, g))
if (AddMercToGroup(this, g))
{
entity_list.AddGroup(g, g->GetID());
database.SetGroupLeaderName(g->GetID(), mercOwner->GetName());
database.SetGroupID(mercOwner->GetName(), g->GetID(), mercOwner->CharacterID(), false);
database.SetGroupID(this->GetName(), g->GetID(), mercOwner->CharacterID(), true);
database.SetGroupLeaderName(g->GetID(), mercOwner->GetName());
database.RefreshGroupFromDB(mercOwner);
g->SaveGroupLeaderAA();
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: Mercenary joined new group.");
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary joined new group: %s (%s).", GetName(), mercOwner->GetName());
}
else
{
g->DisbandGroup();
Suspend();
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: Mercenary disbanded new group.");
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary disbanded new group: %s (%s).", GetName(), mercOwner->GetName());
}
}
else if (AddMercToGroup(this, mercOwner->GetGroup()))
{
// Group already exists
database.SetGroupID(GetName(), mercOwner->GetGroup()->GetID(), mercOwner->CharacterID(), true);
database.RefreshGroupFromDB(mercOwner);
// Update members that are out of zone
GetGroup()->SendGroupJoinOOZ(this);
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: Mercenary joined existing group.");
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary %s joined existing group with %s.", GetName(), mercOwner->GetName());
}
else
{
Suspend();
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: Mercenary failed to join the group - Suspending");
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary failed to join the group - Suspending %s for (%s).", GetName(), mercOwner->GetName());
}
}
@@ -5785,7 +5933,7 @@ Merc* Client::GetMerc() {
if(GetMercID() == 0)
{
Log.Out(Logs::Detail, Logs::Mercenaries, "Mercenary Debug: GetMerc 0.");
Log.Out(Logs::Detail, Logs::Mercenaries, "GetMerc - GetMercID: 0 for %s.", GetName());
return (nullptr);
}
@@ -5793,14 +5941,14 @@ Merc* Client::GetMerc() {
if(tmp == nullptr)
{
SetMercID(0);
Log.Out(Logs::Detail, Logs::Mercenaries, "Mercenary Debug: GetMerc No Merc.");
Log.Out(Logs::Detail, Logs::Mercenaries, "GetMerc No Merc for %s.", GetName());
return (nullptr);
}
if(tmp->GetOwnerID() != GetID())
{
SetMercID(0);
Log.Out(Logs::Detail, Logs::Mercenaries, "Mercenary Debug: GetMerc Owner Mismatch.");
Log.Out(Logs::Detail, Logs::Mercenaries, "GetMerc Owner Mismatch - OwnerID: %d, ClientID: %d, Client: %s.", tmp->GetOwnerID(), GetID(), GetName());
return (nullptr);
}
@@ -5818,7 +5966,7 @@ uint8 Client::GetNumMercs() {
numMercs++;
}
}
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: GetNumMercs %i.", numMercs);
Log.Out(Logs::General, Logs::Mercenaries, "GetNumMercs Number: %i for %s.", numMercs, GetName());
return numMercs;
}
@@ -5859,7 +6007,7 @@ void Client::SetMerc(Merc* newmerc) {
GetMercInfo().Gender = 0;
GetMercInfo().State = 0;
memset(GetMercInfo().merc_name, 0, 64);
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: SetMerc No Merc.");
Log.Out(Logs::General, Logs::Mercenaries, "SetMerc No Merc for %s.", GetName());
}
else
{
@@ -5876,7 +6024,7 @@ void Client::SetMerc(Merc* newmerc) {
GetMercInfo().Gender = newmerc->GetGender();
GetMercInfo().State = newmerc->IsSuspended() ? MERC_STATE_SUSPENDED : MERC_STATE_NORMAL;
snprintf(GetMercInfo().merc_name, 64, "%s", newmerc->GetName());
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: SetMerc New Merc.");
Log.Out(Logs::General, Logs::Mercenaries, "SetMerc New Merc for %s.", GetName());
}
}
@@ -5884,7 +6032,8 @@ void Client::UpdateMercLevel() {
Merc* merc = GetMerc();
if (merc)
{
merc->UpdateMercStats(this);
merc->UpdateMercStats(this, false);
merc->SendAppearancePacket(AT_WhoLevel, GetLevel(), true, true);
}
}
@@ -5896,7 +6045,7 @@ void Client::SendMercMerchantResponsePacket(int32 response_type) {
MercenaryMerchantResponse_Struct* mmr = (MercenaryMerchantResponse_Struct*)outapp->pBuffer;
mmr->ResponseType = response_type; // send specified response type
FastQueuePacket(&outapp);
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: Sent SendMercMerchantResponsePacket %i.", response_type);
Log.Out(Logs::Moderate, Logs::Mercenaries, "Sent SendMercMerchantResponsePacket ResponseType: %i, Client: %s.", response_type, GetName());
}
}
@@ -5905,7 +6054,7 @@ void Client::SendMercenaryUnknownPacket(uint8 type) {
EQApplicationPacket *outapp = new EQApplicationPacket(OP_MercenaryUnknown1, 1);
outapp->WriteUInt8(type);
FastQueuePacket(&outapp);
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: Sent SendMercenaryUnknownPacket %i.", type);
Log.Out(Logs::Moderate, Logs::Mercenaries, "Sent SendMercenaryUnknownPacket Type: %i, Client: %s.", type, GetName());
}
@@ -5914,7 +6063,7 @@ void Client::SendMercenaryUnsuspendPacket(uint8 type) {
EQApplicationPacket *outapp = new EQApplicationPacket(OP_MercenaryUnsuspendResponse, 1);
outapp->WriteUInt8(type);
FastQueuePacket(&outapp);
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: Sent SendMercenaryUnsuspendPacket %i.", type);
Log.Out(Logs::Moderate, Logs::Mercenaries, "Sent SendMercenaryUnsuspendPacket Type: %i, Client: %s.", type, GetName());
}
@@ -5924,7 +6073,7 @@ void Client::SendMercSuspendResponsePacket(uint32 suspended_time) {
SuspendMercenaryResponse_Struct* smr = (SuspendMercenaryResponse_Struct*)outapp->pBuffer;
smr->SuspendTime = suspended_time; // Seen 0 (not suspended) or c9 c2 64 4f (suspended on Sat Mar 17 11:58:49 2012) - Unix Timestamp
FastQueuePacket(&outapp);
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: Sent SendMercSuspendResponsePacket %i.", suspended_time);
Log.Out(Logs::Moderate, Logs::Mercenaries, "Sent SendMercSuspendResponsePacket Time: %i, Client: %s.", suspended_time, GetName());
}
@@ -5939,7 +6088,7 @@ void Client::SendMercTimerPacket(int32 entity_id, int32 merc_state, int32 suspen
mss->UpdateInterval = update_interval; // Seen 900000 - 15 minutes in ms
mss->MercUnk01 = unk01; // Seen 180000 - 3 minutes in ms - Used for the unsuspend button refresh timer
FastQueuePacket(&outapp);
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: Sent SendMercTimerPacket %i, %i, %i, %i, %i.", entity_id, merc_state, suspended_time, update_interval, unk01);
Log.Out(Logs::Moderate, Logs::Mercenaries, "Sent SendMercTimerPacket EndID: %i, State: %i, SuspendTime: %i, Interval: %i, Unk1: %i, Client: %s.", entity_id, merc_state, suspended_time, update_interval, unk01, GetName());
}
@@ -5950,7 +6099,7 @@ void Client::SendMercAssignPacket(uint32 entityID, uint32 unk01, uint32 unk02) {
mas->MercUnk01 = unk01;
mas->MercUnk02 = unk02;
FastQueuePacket(&outapp);
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: Sent SendMercAssignPacket %i, %i, %i.", entityID, unk01, unk02);
Log.Out(Logs::Moderate, Logs::Mercenaries, "Sent SendMercAssignPacket EndID: %i, Unk1: %i, Unk2: %i, Client: %s.", entityID, unk01, unk02, GetName());
}
void NPC::LoadMercTypes() {
+3 -1
View File
@@ -137,7 +137,7 @@ public:
virtual void FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho);
static Merc* LoadMerc(Client *c, MercTemplate* merc_template, uint32 merchant_id, bool updateFromDB = false);
void UpdateMercInfo(Client *c);
void UpdateMercStats(Client *c);
void UpdateMercStats(Client *c, bool setmax = false);
void UpdateMercAppearance();
virtual void UpdateEquipLightValue();
void AddItem(uint8 slot, uint32 item_id);
@@ -189,6 +189,7 @@ public:
bool TryHide();
// stat functions
virtual void ScaleStats(int scalepercent, bool setmax = false);
virtual void CalcBonuses();
int32 GetEndurance() const {return cur_end;} //This gets our current endurance
inline virtual int32 GetAC() const { return AC; }
@@ -347,6 +348,7 @@ private:
// Private "base stats" Members
int32 base_mana;
int32 base_end;
int32 _baseAC;
uint32 _baseSTR;
uint32 _baseSTA;
+5 -5
View File
@@ -2792,7 +2792,7 @@ void Mob::Say(const char *format, ...)
}
//
// solar: this is like the above, but the first parameter is a string id
// this is like the above, but the first parameter is a string id
//
void Mob::Say_StringID(uint32 string_id, const char *message3, const char *message4, const char *message5, const char *message6, const char *message7, const char *message8, const char *message9)
{
@@ -3092,8 +3092,8 @@ float Mob::FindGroundZ(float new_x, float new_y, float z_offset)
if (zone->zonemap != nullptr)
{
glm::vec3 me;
me.x = m_Position.x;
me.y = m_Position.y;
me.x = new_x;
me.y = new_y;
me.z = m_Position.z + z_offset;
glm::vec3 hit;
float best_z = zone->zonemap->FindBestZ(me, &hit);
@@ -3112,8 +3112,8 @@ float Mob::GetGroundZ(float new_x, float new_y, float z_offset)
if (zone->zonemap != 0)
{
glm::vec3 me;
me.x = m_Position.x;
me.y = m_Position.y;
me.x = new_x;
me.y = new_y;
me.z = m_Position.z+z_offset;
glm::vec3 hit;
float best_z = zone->zonemap->FindBestZ(me, &hit);
+11 -10
View File
@@ -25,6 +25,7 @@
#include "position.h"
#include <set>
#include <vector>
#include <memory>
char* strn0cpy(char* dest, const char* source, uint32 size);
@@ -122,7 +123,7 @@ public:
//Attack
virtual void RogueBackstab(Mob* other, bool min_damage = false, int ReuseTime = 10);
virtual void RogueAssassinate(Mob* other); // solar
virtual void RogueAssassinate(Mob* other);
float MobAngle(Mob *other = 0, float ourx = 0.0f, float oury = 0.0f) const;
// greater than 90 is behind
inline bool BehindMob(Mob *other = 0, float ourx = 0.0f, float oury = 0.0f) const
@@ -577,7 +578,7 @@ public:
void WakeTheDead(uint16 spell_id, Mob *target, uint32 duration);
void Spin();
void Kill();
bool PassCharismaCheck(Mob* caster, Mob* spellTarget, uint16 spell_id);
bool PassCharismaCheck(Mob* caster, uint16 spell_id);
bool TryDeathSave();
bool TryDivineSave();
void DoBuffWearOffEffect(uint32 index);
@@ -879,8 +880,8 @@ public:
virtual FACTION_VALUE GetReverseFactionCon(Mob* iOther) { return FACTION_INDIFFERENT; }
inline bool IsTrackable() const { return(trackable); }
Timer* GetAIThinkTimer() { return AIthink_timer; }
Timer* GetAIMovementTimer() { return AImovement_timer; }
Timer* GetAIThinkTimer() { return AIthink_timer.get(); }
Timer* GetAIMovementTimer() { return AImovement_timer.get(); }
Timer GetAttackTimer() { return attack_timer; }
Timer GetAttackDWTimer() { return attack_dw_timer; }
inline bool IsFindable() { return findable; }
@@ -1170,14 +1171,14 @@ protected:
uint32 maxLastFightingDelayMoving;
float pAggroRange;
float pAssistRange;
Timer* AIthink_timer;
Timer* AImovement_timer;
Timer* AItarget_check_timer;
std::unique_ptr<Timer> AIthink_timer;
std::unique_ptr<Timer> AImovement_timer;
std::unique_ptr<Timer> AItarget_check_timer;
bool movetimercompleted;
bool permarooted;
Timer* AIscanarea_timer;
Timer* AIwalking_timer;
Timer* AIfeignremember_timer;
std::unique_ptr<Timer> AIscanarea_timer;
std::unique_ptr<Timer> AIwalking_timer;
std::unique_ptr<Timer> AIfeignremember_timer;
uint32 pLastFightingDelayMoving;
HateList hate_list;
std::set<uint32> feign_memory_list;
+30 -30
View File
@@ -422,14 +422,15 @@ bool EntityList::AICheckCloseBeneficialSpells(NPC* caster, uint8 iChance, float
return false;
}
void Mob::AI_Init() {
void Mob::AI_Init()
{
pAIControlled = false;
AIthink_timer = 0;
AIwalking_timer = 0;
AImovement_timer = 0;
AItarget_check_timer = 0;
AIfeignremember_timer = nullptr;
AIscanarea_timer = 0;
AIthink_timer.reset(nullptr);
AIwalking_timer.reset(nullptr);
AImovement_timer.reset(nullptr);
AItarget_check_timer.reset(nullptr);
AIfeignremember_timer.reset(nullptr);
AIscanarea_timer.reset(nullptr);
minLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMin);
maxLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMax);
@@ -441,10 +442,9 @@ void Mob::AI_Init() {
pDontCureMeBefore = 0;
}
void NPC::AI_Init() {
Mob::AI_Init();
AIautocastspell_timer = 0;
void NPC::AI_Init()
{
AIautocastspell_timer.reset(nullptr);
casting_spell_AIindex = static_cast<uint8>(AIspells.size());
roambox_max_x = 0;
@@ -458,8 +458,8 @@ void NPC::AI_Init() {
roambox_delay = 2500;
}
void Client::AI_Init() {
Mob::AI_Init();
void Client::AI_Init()
{
minLastFightingDelayMoving = CLIENT_LD_TIMEOUT;
maxLastFightingDelayMoving = CLIENT_LD_TIMEOUT;
}
@@ -474,13 +474,13 @@ void Mob::AI_Start(uint32 iMoveDelay) {
pLastFightingDelayMoving = 0;
pAIControlled = true;
AIthink_timer = new Timer(AIthink_duration);
AIthink_timer = std::unique_ptr<Timer>(new Timer(AIthink_duration));
AIthink_timer->Trigger();
AIwalking_timer = new Timer(0);
AImovement_timer = new Timer(AImovement_duration);
AItarget_check_timer = new Timer(AItarget_check_duration);
AIfeignremember_timer = new Timer(AIfeignremember_delay);
AIscanarea_timer = new Timer(AIscanarea_delay);
AIwalking_timer = std::unique_ptr<Timer>(new Timer(0));
AImovement_timer = std::unique_ptr<Timer>(new Timer(AImovement_duration));
AItarget_check_timer = std::unique_ptr<Timer>(new Timer(AItarget_check_duration));
AIfeignremember_timer = std::unique_ptr<Timer>(new Timer(AIfeignremember_delay));
AIscanarea_timer = std::unique_ptr<Timer>(new Timer(AIscanarea_delay));
#ifdef REVERSE_AGGRO
if(IsNPC() && !CastToNPC()->WillAggroNPCs())
AIscanarea_timer->Disable();
@@ -516,10 +516,10 @@ void NPC::AI_Start(uint32 iMoveDelay) {
return;
if (AIspells.size() == 0) {
AIautocastspell_timer = new Timer(1000);
AIautocastspell_timer = std::unique_ptr<Timer>(new Timer(1000));
AIautocastspell_timer->Disable();
} else {
AIautocastspell_timer = new Timer(750);
AIautocastspell_timer = std::unique_ptr<Timer>(new Timer(750));
AIautocastspell_timer->Start(RandomTimer(0, 15000), false);
}
@@ -540,19 +540,19 @@ void Mob::AI_Stop() {
pAIControlled = false;
safe_delete(AIthink_timer);
safe_delete(AIwalking_timer);
safe_delete(AImovement_timer);
safe_delete(AItarget_check_timer);
safe_delete(AIscanarea_timer);
safe_delete(AIfeignremember_timer);
AIthink_timer.reset(nullptr);
AIwalking_timer.reset(nullptr);
AImovement_timer.reset(nullptr);
AItarget_check_timer.reset(nullptr);
AIscanarea_timer.reset(nullptr);
AIfeignremember_timer.reset(nullptr);
hate_list.WipeHateList();
}
void NPC::AI_Stop() {
Waypoints.clear();
safe_delete(AIautocastspell_timer);
AIautocastspell_timer.reset(nullptr);
}
void Client::AI_Stop() {
@@ -2657,7 +2657,7 @@ DBnpcspells_Struct* ZoneDatabase::GetNPCSpells(uint32 iDBSpellsID) {
npc_spells_cache = new DBnpcspells_Struct*[npc_spells_maxid+1];
npc_spells_loadtried = new bool[npc_spells_maxid+1];
for (uint32 i=0; i<=npc_spells_maxid; i++) {
npc_spells_cache[i] = 0;
npc_spells_cache[i] = nullptr;
npc_spells_loadtried[i] = false;
}
}
@@ -2795,7 +2795,7 @@ DBnpcspellseffects_Struct *ZoneDatabase::GetNPCSpellsEffects(uint32 iDBSpellsEff
npc_spellseffects_cache = new DBnpcspellseffects_Struct *[npc_spellseffects_maxid + 1];
npc_spellseffects_loadtried = new bool[npc_spellseffects_maxid + 1];
for (uint32 i = 0; i <= npc_spellseffects_maxid; i++) {
npc_spellseffects_cache[i] = 0;
npc_spellseffects_cache[i] = nullptr;
npc_spellseffects_loadtried[i] = false;
}
}
+1 -1
View File
@@ -332,7 +332,7 @@ int main(int argc, char** argv) {
Timer quest_timers(100);
UpdateWindowTitle();
bool worldwasconnected = worldserver.Connected();
EQStream* eqss;
std::shared_ptr<EQStream> eqss;
EQStreamInterface *eqsi;
uint8 IDLEZONEUPDATE = 200;
uint8 ZONEUPDATE = 10;
+155 -186
View File
@@ -250,8 +250,8 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if
npc_aggro = d->npc_aggro;
if(!IsMerc())
AI_Start();
AI_Init();
AI_Start();
d_melee_texture1 = d->d_melee_texture1;
d_melee_texture2 = d->d_melee_texture2;
@@ -987,298 +987,267 @@ NPC* NPC::SpawnNPC(const char* spawncommand, const glm::vec4& position, Client*
}
}
uint32 ZoneDatabase::CreateNewNPCCommand(const char* zone, uint32 zone_version,Client *client, NPC* spawn, uint32 extra) {
uint32 ZoneDatabase::CreateNewNPCCommand(const char *zone, uint32 zone_version, Client *client, NPC *spawn,
uint32 extra)
{
uint32 npc_type_id = 0;
uint32 npc_type_id = 0;
if (extra && client && client->GetZoneID())
{
if (extra && client && client->GetZoneID()) {
// Set an npc_type ID within the standard range for the current zone if possible (zone_id * 1000)
int starting_npc_id = client->GetZoneID() * 1000;
std::string query = StringFormat("SELECT MAX(id) FROM npc_types WHERE id >= %i AND id < %i",
starting_npc_id, starting_npc_id + 1000);
auto results = QueryDatabase(query);
starting_npc_id, starting_npc_id + 1000);
auto results = QueryDatabase(query);
if (results.Success()) {
if (results.RowCount() != 0)
{
auto row = results.begin();
npc_type_id = atoi(row[0]) + 1;
// Prevent the npc_type id from exceeding the range for this zone
if (npc_type_id >= (starting_npc_id + 1000))
npc_type_id = 0;
}
else // No npc_type IDs set in this range yet
npc_type_id = starting_npc_id;
}
}
if (results.RowCount() != 0) {
auto row = results.begin();
npc_type_id = atoi(row[0]) + 1;
// Prevent the npc_type id from exceeding the range for this zone
if (npc_type_id >= (starting_npc_id + 1000))
npc_type_id = 0;
} else // No npc_type IDs set in this range yet
npc_type_id = starting_npc_id;
}
}
char tmpstr[64];
EntityList::RemoveNumbers(strn0cpy(tmpstr, spawn->GetName(), sizeof(tmpstr)));
std::string query;
if (npc_type_id)
{
query = StringFormat("INSERT INTO npc_types (id, name, level, race, class, hp, gender, "
"texture, helmtexture, size, loottable_id, merchant_id, face, "
"runspeed, prim_melee_type, sec_melee_type) "
"VALUES(%i, \"%s\" , %i, %i, %i, %i, %i, %i, %i, %f, %i, %i, %i, %f, %i, %i)",
npc_type_id, tmpstr, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(),
spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(),
spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(),
spawn->MerchantType, 0, spawn->GetRunspeed(), 28, 28);
auto results = QueryDatabase(query);
if (npc_type_id) {
query = StringFormat("INSERT INTO npc_types (id, name, level, race, class, hp, gender, "
"texture, helmtexture, size, loottable_id, merchant_id, face, "
"runspeed, prim_melee_type, sec_melee_type) "
"VALUES(%i, \"%s\" , %i, %i, %i, %i, %i, %i, %i, %f, %i, %i, %i, %f, %i, %i)",
npc_type_id, tmpstr, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(),
spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(),
spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(),
spawn->MerchantType, 0, spawn->GetRunspeed(), 28, 28);
auto results = QueryDatabase(query);
if (!results.Success()) {
return false;
}
npc_type_id = results.LastInsertedID();
} else {
query = StringFormat("INSERT INTO npc_types (name, level, race, class, hp, gender, "
"texture, helmtexture, size, loottable_id, merchant_id, face, "
"runspeed, prim_melee_type, sec_melee_type) "
"VALUES(\"%s\", %i, %i, %i, %i, %i, %i, %i, %f, %i, %i, %i, %f, %i, %i)",
tmpstr, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(), spawn->GetMaxHP(),
spawn->GetGender(), spawn->GetTexture(), spawn->GetHelmTexture(), spawn->GetSize(),
spawn->GetLoottableID(), spawn->MerchantType, 0, spawn->GetRunspeed(), 28, 28);
auto results = QueryDatabase(query);
if (!results.Success()) {
return false;
}
npc_type_id = results.LastInsertedID();
}
else
{
query = StringFormat("INSERT INTO npc_types (name, level, race, class, hp, gender, "
"texture, helmtexture, size, loottable_id, merchant_id, face, "
"runspeed, prim_melee_type, sec_melee_type) "
"VALUES(\"%s\", %i, %i, %i, %i, %i, %i, %i, %f, %i, %i, %i, %f, %i, %i)",
tmpstr, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(),
spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(),
spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(),
spawn->MerchantType, 0, spawn->GetRunspeed(), 28, 28);
auto results = QueryDatabase(query);
if (!results.Success()) {
return false;
}
npc_type_id = results.LastInsertedID();
}
if(client)
query = StringFormat("INSERT INTO spawngroup (id, name) VALUES(%i, '%s-%s')", 0, zone, spawn->GetName());
auto results = QueryDatabase(query);
auto results = QueryDatabase(query);
if (!results.Success()) {
return false;
}
uint32 spawngroupid = results.LastInsertedID();
uint32 spawngroupid = results.LastInsertedID();
if(client)
query = StringFormat("INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) "
"VALUES('%s', %u, %f, %f, %f, %i, %f, %i)",
zone, zone_version, spawn->GetX(), spawn->GetY(), spawn->GetZ(), 1200,
spawn->GetHeading(), spawngroupid);
results = QueryDatabase(query);
query = StringFormat("INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) "
"VALUES('%s', %u, %f, %f, %f, %i, %f, %i)",
zone, zone_version, spawn->GetX(), spawn->GetY(), spawn->GetZ(), 1200, spawn->GetHeading(),
spawngroupid);
results = QueryDatabase(query);
if (!results.Success()) {
return false;
}
if(client)
query = StringFormat("INSERT INTO spawnentry (spawngroupID, npcID, chance) VALUES(%i, %i, %i)",
spawngroupid, npc_type_id, 100);
results = QueryDatabase(query);
query = StringFormat("INSERT INTO spawnentry (spawngroupID, npcID, chance) VALUES(%i, %i, %i)", spawngroupid,
npc_type_id, 100);
results = QueryDatabase(query);
if (!results.Success()) {
return false;
}
if(client)
return true;
}
uint32 ZoneDatabase::AddNewNPCSpawnGroupCommand(const char* zone, uint32 zone_version, Client *client, NPC* spawn, uint32 respawnTime) {
uint32 last_insert_id = 0;
uint32 ZoneDatabase::AddNewNPCSpawnGroupCommand(const char *zone, uint32 zone_version, Client *client, NPC *spawn,
uint32 respawnTime)
{
uint32 last_insert_id = 0;
std::string query = StringFormat("INSERT INTO spawngroup (name) VALUES('%s%s%i')",
zone, spawn->GetName(), Timer::GetCurrentTime());
auto results = QueryDatabase(query);
std::string query = StringFormat("INSERT INTO spawngroup (name) VALUES('%s%s%i')", zone, spawn->GetName(),
Timer::GetCurrentTime());
auto results = QueryDatabase(query);
if (!results.Success()) {
return 0;
}
last_insert_id = results.LastInsertedID();
last_insert_id = results.LastInsertedID();
uint32 respawntime = 0;
uint32 spawnid = 0;
if (respawnTime)
respawntime = respawnTime;
else if(spawn->respawn2 && spawn->respawn2->RespawnTimer() != 0)
respawntime = spawn->respawn2->RespawnTimer();
else
respawntime = 1200;
uint32 respawntime = 0;
uint32 spawnid = 0;
if (respawnTime)
respawntime = respawnTime;
else if (spawn->respawn2 && spawn->respawn2->RespawnTimer() != 0)
respawntime = spawn->respawn2->RespawnTimer();
else
respawntime = 1200;
query = StringFormat("INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) "
"VALUES('%s', %u, %f, %f, %f, %i, %f, %i)",
zone, zone_version, spawn->GetX(), spawn->GetY(), spawn->GetZ(), respawntime,
spawn->GetHeading(), last_insert_id);
results = QueryDatabase(query);
if (!results.Success()) {
return 0;
}
spawnid = results.LastInsertedID();
query = StringFormat("INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) "
"VALUES('%s', %u, %f, %f, %f, %i, %f, %i)",
zone, zone_version, spawn->GetX(), spawn->GetY(), spawn->GetZ(), respawntime,
spawn->GetHeading(), last_insert_id);
results = QueryDatabase(query);
if (!results.Success()) {
return 0;
}
spawnid = results.LastInsertedID();
if(client)
query = StringFormat("INSERT INTO spawnentry (spawngroupID, npcID, chance) VALUES(%i, %i, %i)", last_insert_id,
spawn->GetNPCTypeID(), 100);
results = QueryDatabase(query);
if (!results.Success()) {
return 0;
}
query = StringFormat("INSERT INTO spawnentry (spawngroupID, npcID, chance) VALUES(%i, %i, %i)",
last_insert_id, spawn->GetNPCTypeID(), 100);
results = QueryDatabase(query);
if (!results.Success()) {
return 0;
}
if(client)
return spawnid;
return spawnid;
}
uint32 ZoneDatabase::UpdateNPCTypeAppearance(Client *client, NPC* spawn) {
std::string query = StringFormat("UPDATE npc_types SET name = \"%s\", level = %i, race = %i, class = %i, "
"hp = %i, gender = %i, texture = %i, helmtexture = %i, size = %i, "
"loottable_id = %i, merchant_id = %i, face = %i, WHERE id = %i",
spawn->GetName(), spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(),
spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(),
spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(),
spawn->MerchantType, spawn->GetNPCTypeID());
auto results = QueryDatabase(query);
if (!results.Success() && client)
return results.Success() == true? 1: 0;
uint32 ZoneDatabase::UpdateNPCTypeAppearance(Client *client, NPC *spawn)
{
std::string query =
StringFormat("UPDATE npc_types SET name = \"%s\", level = %i, race = %i, class = %i, "
"hp = %i, gender = %i, texture = %i, helmtexture = %i, size = %i, "
"loottable_id = %i, merchant_id = %i, face = %i, WHERE id = %i",
spawn->GetName(), spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(), spawn->GetMaxHP(),
spawn->GetGender(), spawn->GetTexture(), spawn->GetHelmTexture(), spawn->GetSize(),
spawn->GetLoottableID(), spawn->MerchantType, spawn->GetNPCTypeID());
auto results = QueryDatabase(query);
return results.Success() == true ? 1 : 0;
}
uint32 ZoneDatabase::DeleteSpawnLeaveInNPCTypeTable(const char* zone, Client *client, NPC* spawn) {
uint32 ZoneDatabase::DeleteSpawnLeaveInNPCTypeTable(const char *zone, Client *client, NPC *spawn)
{
uint32 id = 0;
uint32 spawngroupID = 0;
std::string query = StringFormat("SELECT id, spawngroupID FROM spawn2 WHERE "
"zone='%s' AND spawngroupID=%i", zone, spawn->GetSp2());
auto results = QueryDatabase(query);
if (!results.Success())
"zone='%s' AND spawngroupID=%i",
zone, spawn->GetSp2());
auto results = QueryDatabase(query);
if (!results.Success())
return 0;
if (results.RowCount() == 0)
return 0;
if (results.RowCount() == 0)
return 0;
auto row = results.begin();
if (row[0])
id = atoi(row[0]);
id = atoi(row[0]);
if (row[1])
spawngroupID = atoi(row[1]);
spawngroupID = atoi(row[1]);
query = StringFormat("DELETE FROM spawn2 WHERE id = '%i'", id);
results = QueryDatabase(query);
query = StringFormat("DELETE FROM spawn2 WHERE id = '%i'", id);
results = QueryDatabase(query);
if (!results.Success())
return 0;
if(client)
query = StringFormat("DELETE FROM spawngroup WHERE id = '%i'", spawngroupID);
results = QueryDatabase(query);
query = StringFormat("DELETE FROM spawngroup WHERE id = '%i'", spawngroupID);
results = QueryDatabase(query);
if (!results.Success())
return 0;
if(client)
query = StringFormat("DELETE FROM spawnentry WHERE spawngroupID = '%i'", spawngroupID);
results = QueryDatabase(query);
query = StringFormat("DELETE FROM spawnentry WHERE spawngroupID = '%i'", spawngroupID);
results = QueryDatabase(query);
if (!results.Success())
return 0;
if(client)
return 1;
}
uint32 ZoneDatabase::DeleteSpawnRemoveFromNPCTypeTable(const char* zone, uint32 zone_version, Client *client, NPC* spawn) {
uint32 ZoneDatabase::DeleteSpawnRemoveFromNPCTypeTable(const char *zone, uint32 zone_version, Client *client,
NPC *spawn)
{
uint32 id = 0;
uint32 spawngroupID = 0;
std::string query = StringFormat("SELECT id, spawngroupID FROM spawn2 WHERE zone = '%s' "
"AND version = %u AND spawngroupID = %i",
zone, zone_version, spawn->GetSp2());
auto results = QueryDatabase(query);
if (!results.Success())
"AND version = %u AND spawngroupID = %i",
zone, zone_version, spawn->GetSp2());
auto results = QueryDatabase(query);
if (!results.Success())
return 0;
if (results.RowCount() == 0)
return 0;
if (results.RowCount() == 0)
return 0;
auto row = results.begin();
if (row[0])
id = atoi(row[0]);
id = atoi(row[0]);
if (row[1])
spawngroupID = atoi(row[1]);
spawngroupID = atoi(row[1]);
query = StringFormat("DELETE FROM spawn2 WHERE id = '%i'", id);
results = QueryDatabase(query);
if (!results.Success())
return 0;
if(client)
query = StringFormat("DELETE FROM spawngroup WHERE id = '%i'", spawngroupID);
query = StringFormat("DELETE FROM spawn2 WHERE id = '%i'", id);
results = QueryDatabase(query);
if (!results.Success())
return 0;
if(client)
query = StringFormat("DELETE FROM spawnentry WHERE spawngroupID = '%i'", spawngroupID);
query = StringFormat("DELETE FROM spawngroup WHERE id = '%i'", spawngroupID);
results = QueryDatabase(query);
if (!results.Success())
return 0;
if(client)
query = StringFormat("DELETE FROM npc_types WHERE id = '%i'", spawn->GetNPCTypeID());
query = StringFormat("DELETE FROM spawnentry WHERE spawngroupID = '%i'", spawngroupID);
results = QueryDatabase(query);
if (!results.Success())
return 0;
if(client)
query = StringFormat("DELETE FROM npc_types WHERE id = '%i'", spawn->GetNPCTypeID());
results = QueryDatabase(query);
if (!results.Success())
return 0;
return 1;
}
uint32 ZoneDatabase::AddSpawnFromSpawnGroup(const char* zone, uint32 zone_version, Client *client, NPC* spawn, uint32 spawnGroupID) {
uint32 ZoneDatabase::AddSpawnFromSpawnGroup(const char *zone, uint32 zone_version, Client *client, NPC *spawn,
uint32 spawnGroupID)
{
uint32 last_insert_id = 0;
std::string query = StringFormat("INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) "
"VALUES('%s', %u, %f, %f, %f, %i, %f, %i)",
zone, zone_version, client->GetX(), client->GetY(), client->GetZ(),
120, client->GetHeading(), spawnGroupID);
auto results = QueryDatabase(query);
if (!results.Success())
std::string query =
StringFormat("INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) "
"VALUES('%s', %u, %f, %f, %f, %i, %f, %i)",
zone, zone_version, client->GetX(), client->GetY(), client->GetZ(), 120, client->GetHeading(),
spawnGroupID);
auto results = QueryDatabase(query);
if (!results.Success())
return 0;
if(client)
return 1;
return 1;
}
uint32 ZoneDatabase::AddNPCTypes(const char* zone, uint32 zone_version, Client *client, NPC* spawn, uint32 spawnGroupID) {
uint32 npc_type_id;
uint32 ZoneDatabase::AddNPCTypes(const char *zone, uint32 zone_version, Client *client, NPC *spawn, uint32 spawnGroupID)
{
uint32 npc_type_id;
char numberlessName[64];
EntityList::RemoveNumbers(strn0cpy(numberlessName, spawn->GetName(), sizeof(numberlessName)));
std::string query = StringFormat("INSERT INTO npc_types (name, level, race, class, hp, gender, "
"texture, helmtexture, size, loottable_id, merchant_id, face, "
"runspeed, prim_melee_type, sec_melee_type) "
"VALUES(\"%s\", %i, %i, %i, %i, %i, %i, %i, %f, %i, %i, %i, %f, %i, %i)",
numberlessName, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(),
spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(),
spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(),
spawn->MerchantType, 0, spawn->GetRunspeed(), 28, 28);
auto results = QueryDatabase(query);
std::string query =
StringFormat("INSERT INTO npc_types (name, level, race, class, hp, gender, "
"texture, helmtexture, size, loottable_id, merchant_id, face, "
"runspeed, prim_melee_type, sec_melee_type) "
"VALUES(\"%s\", %i, %i, %i, %i, %i, %i, %i, %f, %i, %i, %i, %f, %i, %i)",
numberlessName, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(), spawn->GetMaxHP(),
spawn->GetGender(), spawn->GetTexture(), spawn->GetHelmTexture(), spawn->GetSize(),
spawn->GetLoottableID(), spawn->MerchantType, 0, spawn->GetRunspeed(), 28, 28);
auto results = QueryDatabase(query);
if (!results.Success())
return 0;
npc_type_id = results.LastInsertedID();
npc_type_id = results.LastInsertedID();
if(client)
if(client)
client->Message(0, "%s npc_type ID %i created successfully!", numberlessName, npc_type_id);
if (client)
client->Message(0, "%s npc_type ID %i created successfully!", numberlessName, npc_type_id);
return 1;
}
+2 -2
View File
@@ -436,7 +436,7 @@ protected:
uint32 npc_spells_id;
uint8 casting_spell_AIindex;
Timer* AIautocastspell_timer;
std::unique_ptr<Timer> AIautocastspell_timer;
uint32* pDontCastBefore_casting_spell;
std::vector<AISpells_Struct> AIspells;
bool HasAISpell;
@@ -444,7 +444,7 @@ protected:
virtual bool AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0);
AISpellsVar_Struct AISpellVar;
int16 GetFocusEffect(focusType type, uint16 spell_id);
uint32 npc_spells_effects_id;
std::vector<AISpellsEffects_Struct> AIspellsEffects;
bool HasAISpellEffects;
+8 -3
View File
@@ -467,16 +467,21 @@ bool Object::HandleClick(Client* sender, const ClickObject_Struct* click_object)
if (m_inst && sender) {
// if there is a lore conflict, delete the offending item from the server inventory
// the client updates itself and takes care of sending "duplicate lore item" messages
if(sender->CheckLoreConflict(m_inst->GetItem())) {
int16 loreslot = sender->GetInv().HasItem(m_inst->GetItem()->ID, 0, invWhereBank);
auto item = m_inst->GetItem();
if(sender->CheckLoreConflict(item)) {
int16 loreslot = sender->GetInv().HasItem(item->ID, 0, invWhereBank);
if (loreslot != INVALID_INDEX) // if the duplicate is in the bank, delete it.
sender->DeleteItemInInventory(loreslot);
else
cursordelete = true; // otherwise, we delete the new one
}
if (item->RecastDelay)
m_inst->SetRecastTimestamp(
database.GetItemRecastTimestamp(sender->CharacterID(), item->RecastType));
char buf[10];
snprintf(buf, 9, "%u", m_inst->GetItem()->ID);
snprintf(buf, 9, "%u", item->ID);
buf[9] = '\0';
std::vector<EQEmu::Any> args;
args.push_back(m_inst);
+3 -3
View File
@@ -663,7 +663,7 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime)
DoAnim(animPiercing);
}
// solar - assassinate [Kayen: No longer used for regular assassinate 6-29-14]
// assassinate [No longer used for regular assassinate 6-29-14]
void Mob::RogueAssassinate(Mob* other)
{
//can you dodge, parry, etc.. an assassinate??
@@ -857,7 +857,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
if (IsClient()){
_RangeWeapon = CastToClient()->m_inv[MainRange];
if (_RangeWeapon && !_RangeWeapon->GetItem() && _RangeWeapon->GetItem()->ID == range_id)
if (_RangeWeapon && _RangeWeapon->GetItem() && _RangeWeapon->GetItem()->ID == range_id)
RangeWeapon = _RangeWeapon;
_Ammo = CastToClient()->m_inv[AmmoSlot];
@@ -996,7 +996,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
}
if (LaunchProjectile)
return;//Shouldn't reach this point, but just in case.
return;//Shouldn't reach this point durring initial launch phase, but just in case.
//Weapon Proc
if(RangeWeapon && other && !other->HasDied())
+4 -4
View File
@@ -134,7 +134,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
if (spells[spell_id].EndurUpkeep > 0)
SetEndurUpkeep(true);
if(IsClient() && CastToClient()->GetClientVersionBit() & BIT_UnderfootAndLater)
if(IsClient() && CastToClient()->GetClientVersionBit() & BIT_UFAndLater)
{
EQApplicationPacket *outapp = MakeBuffsPacket(false);
CastToClient()->FastQueuePacket(&outapp);
@@ -3409,7 +3409,7 @@ void Mob::BuffProcess()
{
CastToClient()->SendBuffDurationPacket(buffs[buffs_i]);
// Hack to get UF to play nicer, RoF seems fine without it
if (CastToClient()->GetClientVersion() == ClientVersion::Und && buffs[buffs_i].numhits > 0)
if (CastToClient()->GetClientVersion() == ClientVersion::UF && buffs[buffs_i].numhits > 0)
CastToClient()->SendBuffNumHitPacket(buffs[buffs_i], buffs_i);
buffs[buffs_i].UpdateClient = false;
}
@@ -3586,7 +3586,7 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste
}
case SE_Charm: {
if (!caster || !PassCharismaCheck(caster, this, spell_id)) {
if (!caster || !PassCharismaCheck(caster, spell_id)) {
BuffFadeByEffect(SE_Charm);
}
@@ -4175,7 +4175,7 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
safe_delete(outapp);
}
if(IsClient() && CastToClient()->GetClientVersionBit() & BIT_UnderfootAndLater)
if(IsClient() && CastToClient()->GetClientVersionBit() & BIT_UFAndLater)
{
EQApplicationPacket *outapp = MakeBuffsPacket(false);
CastToClient()->FastQueuePacket(&outapp);
+28 -11
View File
@@ -1242,6 +1242,8 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot,
{
//Can we start the timer here? I don't see why not.
CastToClient()->GetPTimers().Start((pTimerItemStart + recasttype), recastdelay);
database.UpdateItemRecastTimestamps(CastToClient()->CharacterID(), recasttype,
CastToClient()->GetPTimers().Get(pTimerItemStart + recasttype)->GetReadyTimestamp());
}
}
@@ -2023,6 +2025,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
//
// Switch #2 - execute the spell
//
switch(CastAction)
{
default:
@@ -2146,6 +2149,15 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
// caster if they're not using TGB
// NOTE: this will always hit the caster, plus the target's group so
// it can affect up to 7 people if the targeted group is not our own
// Allow pets who cast group spells to affect the group.
if (spell_target->IsPetOwnerClient()){
Mob* owner = spell_target->GetOwner();
if (owner)
spell_target = owner;
}
if(spell_target->IsGrouped())
{
Group *target_group = entity_list.GetGroupByMob(spell_target);
@@ -2270,11 +2282,15 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
{
ItemInst *itm = CastToClient()->GetInv().GetItem(inventory_slot);
if(itm && itm->GetItem()->RecastDelay > 0){
CastToClient()->GetPTimers().Start((pTimerItemStart + itm->GetItem()->RecastType), itm->GetItem()->RecastDelay);
auto recast_type = itm->GetItem()->RecastType;
CastToClient()->GetPTimers().Start((pTimerItemStart + recast_type), itm->GetItem()->RecastDelay);
database.UpdateItemRecastTimestamps(
CastToClient()->CharacterID(), recast_type,
CastToClient()->GetPTimers().Get(pTimerItemStart + recast_type)->GetReadyTimestamp());
EQApplicationPacket *outapp = new EQApplicationPacket(OP_ItemRecastDelay, sizeof(ItemRecastDelay_Struct));
ItemRecastDelay_Struct *ird = (ItemRecastDelay_Struct *)outapp->pBuffer;
ird->recast_delay = itm->GetItem()->RecastDelay;
ird->recast_type = itm->GetItem()->RecastType;
ird->recast_type = recast_type;
CastToClient()->QueuePacket(outapp);
safe_delete(outapp);
}
@@ -3659,7 +3675,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
if(!IsHarmonySpell(spell_id))
spelltar->AddToHateList(this, aggro);
else
if(!PassCharismaCheck(this, spelltar, spell_id))
if(!spelltar->PassCharismaCheck(this, spell_id))
spelltar->AddToHateList(this, aggro);
}
else{
@@ -4388,7 +4404,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
level_mod += (2 * level_diff);
}
}
if (CharismaCheck)
{
/*
@@ -4402,7 +4418,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
*/
int16 charisma = caster->GetCHA();
if (IsFear && (spells[spell_id].targettype != 10)){
if (IsFear && (spells[spell_id].targettype != ST_Undead)){
if (charisma < 100)
resist_modifier -= 20;
@@ -4423,8 +4439,10 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
else
resist_modifier += ((75 - charisma)/10) * 6; //Increase Resist Chance
}
}
//Lull spells DO NOT use regular resists on initial cast, instead they use a flat +15 modifier. Live parses confirm this.
//Regular resists are used when checking if mob will aggro off of a lull resist.
if(!CharismaCheck && IsHarmonySpell(spell_id))
@@ -4452,9 +4470,8 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
//Minimum resist chance should be caclulated factoring in the RuleI(Spells, CharmBreakCheckChance)
if (CharmTick) {
int min_charmbreakchance = ((100/RuleI(Spells, CharmBreakCheckChance))/66 * 100)*2;
if (resist_chance < min_charmbreakchance)
float min_charmbreakchance = ((100.0f/static_cast<float>(RuleI(Spells, CharmBreakCheckChance)))/66.0f * 100.0f)*2.0f;
if (resist_chance < static_cast<int>(min_charmbreakchance))
resist_chance = min_charmbreakchance;
}
@@ -4462,9 +4479,9 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
//Minimum resist chance should be caclulated factoring in the RuleI(Spells, RootBreakCheckChance)
if (IsRoot) {
int min_rootbreakchance = ((100/RuleI(Spells, RootBreakCheckChance))/22 * 100)*2;
float min_rootbreakchance = ((100.0f/static_cast<float>(RuleI(Spells, RootBreakCheckChance)))/22.0f * 100.0f)*2.0f;
if (resist_chance < min_rootbreakchance)
if (resist_chance < static_cast<int>(min_rootbreakchance))
resist_chance = min_rootbreakchance;
}
@@ -5248,7 +5265,7 @@ void Client::SendBuffDurationPacket(Buffs_Struct &buff)
void Client::SendBuffNumHitPacket(Buffs_Struct &buff, int slot)
{
// UF+ use this packet
if (GetClientVersion() < ClientVersion::Und)
if (GetClientVersion() < ClientVersion::UF)
return;
EQApplicationPacket *outapp;
outapp = new EQApplicationPacket(OP_BuffCreate, sizeof(BuffIcon_Struct) + sizeof(BuffIconEntry_Struct));
+6 -9
View File
@@ -473,7 +473,7 @@ void WorldServer::Process() {
if (ZoneLoaded) {
SetZone(zone->GetZoneID(), zone->GetInstanceID());
if (zst->zoneid == zone->GetZoneID()) {
// This packet also doubles as "incomming client" notification, lets not shut down before they get here
// This packet also doubles as "incoming client" notification, lets not shut down before they get here
zone->StartShutdownTimer(AUTHENTICATION_TIMEOUT * 1000);
}
else {
@@ -488,22 +488,19 @@ void WorldServer::Process() {
if (!(Zone::Bootup(zst->zoneid, zst->instanceid, zst->makestatic))) {
SendChannelMessage(0, 0, 10, 0, 0, "%s:%i Zone::Bootup failed: %s", net.GetZoneAddress(), net.GetZonePort(), database.GetZoneName(zst->zoneid));
}
// Moved annoucement to ZoneBootup()
// else
// SendEmoteMessage(0, 0, 15, "Zone bootup: %s", zone->GetLongName());
break;
}
case ServerOP_ZoneIncClient: {
if (pack->size != sizeof(ServerZoneIncommingClient_Struct)) {
std::cout << "Wrong size on ServerOP_ZoneIncClient. Got: " << pack->size << ", Expected: " << sizeof(ServerZoneIncommingClient_Struct) << std::endl;
if (pack->size != sizeof(ServerZoneIncomingClient_Struct)) {
std::cout << "Wrong size on ServerOP_ZoneIncClient. Got: " << pack->size << ", Expected: " << sizeof(ServerZoneIncomingClient_Struct) << std::endl;
break;
}
ServerZoneIncommingClient_Struct* szic = (ServerZoneIncommingClient_Struct*) pack->pBuffer;
ServerZoneIncomingClient_Struct* szic = (ServerZoneIncomingClient_Struct*) pack->pBuffer;
if (ZoneLoaded) {
SetZone(zone->GetZoneID(), zone->GetInstanceID());
if (szic->zoneid == zone->GetZoneID()) {
zone->AddAuth(szic);
// This packet also doubles as "incomming client" notification, lets not shut down before they get here
// This packet also doubles as "incoming client" notification, lets not shut down before they get here
zone->StartShutdownTimer(AUTHENTICATION_TIMEOUT * 1000);
}
}
@@ -650,7 +647,7 @@ void WorldServer::Process() {
case ServerOP_Petition: {
std::cout << "Got Server Requested Petition List Refresh" << std::endl;
ServerPetitionUpdate_Struct* sus = (ServerPetitionUpdate_Struct*) pack->pBuffer;
// solar: this was typoed to = instead of ==, not that it acts any different now though..
// this was typoed to = instead of ==, not that it acts any different now though..
if (sus->status == 0) petition_list.ReadDatabase();
else if (sus->status == 1) petition_list.ReadDatabase(); // Until I fix this to be better....
break;
+2 -2
View File
@@ -656,7 +656,7 @@ void Zone::LoadMercSpells(){
merc_spells_list[classid].push_back(tempMercSpellEntry);
}
Log.Out(Logs::General, Logs::Mercenaries, "Mercenary Debug: Loaded %i merc spells.", merc_spells_list[1].size() + merc_spells_list[2].size() + merc_spells_list[9].size() + merc_spells_list[12].size());
Log.Out(Logs::General, Logs::Mercenaries, "Loaded %i merc spells.", merc_spells_list[1].size() + merc_spells_list[2].size() + merc_spells_list[9].size() + merc_spells_list[12].size());
}
@@ -1086,7 +1086,7 @@ bool Zone::SaveZoneCFG() {
return database.SaveZoneCFG(GetZoneID(), GetInstanceVersion(), &newzone_data);
}
void Zone::AddAuth(ServerZoneIncommingClient_Struct* szic) {
void Zone::AddAuth(ServerZoneIncomingClient_Struct* szic) {
ZoneClientAuth_Struct* zca = new ZoneClientAuth_Struct;
memset(zca, 0, sizeof(ZoneClientAuth_Struct));
zca->ip = szic->ip;
+2 -2
View File
@@ -84,7 +84,7 @@ class PathManager;
class WaterMap;
extern EntityList entity_list;
struct NPCType;
struct ServerZoneIncommingClient_Struct;
struct ServerZoneIncomingClient_Struct;
class Zone
{
@@ -149,7 +149,7 @@ public:
void StartShutdownTimer(uint32 set_time = (RuleI(Zone, AutoShutdownDelay)));
void ChangeWeather();
bool HasWeather();
void AddAuth(ServerZoneIncommingClient_Struct* szic);
void AddAuth(ServerZoneIncomingClient_Struct* szic);
void RemoveAuth(const char* iCharName);
void ResetAuth();
bool GetAuth(uint32 iIP, const char* iCharName, uint32* oWID = 0, uint32* oAccID = 0, uint32* oCharID = 0, int16* oStatus = 0, char* oLSKey = 0, bool* oTellsOff = 0);
+202 -127
View File
@@ -1937,8 +1937,8 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) {
return npc;
}
const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 clientlevel) {
const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 clientlevel)
{
//need to save based on merc_npc_type & client level
uint32 merc_type_id = id * 100 + clientlevel;
@@ -1963,7 +1963,7 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client
"0 AS gender, "
"m_armorinfo.texture, "
"m_armorinfo.helmtexture, "
"m_stats.attack_speed, "
"m_stats.attack_delay, "
"m_stats.STR, "
"m_stats.STA, "
"m_stats.DEX, "
@@ -1996,6 +1996,7 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client
"m_stats.AC, "
"m_stats.ATK, "
"m_stats.Accuracy, "
"m_stats.statscale, "
"m_stats.spellscale, "
"m_stats.healscale "
"FROM merc_stats m_stats "
@@ -2014,125 +2015,125 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client
"WHERE m_templates.merc_npc_type_id = %d AND m_stats.clientlevel = %d AND m_types.race_id = %d",
id, clientlevel, raceid); //dual primary keys. one is ID, one is level.
auto results = QueryDatabase(query);
if (!results.Success()) {
return nullptr;
}
auto results = QueryDatabase(query);
if (!results.Success()) {
return nullptr;
}
const NPCType *npc;
const NPCType *npc;
// Process each row returned.
for (auto row = results.begin(); row != results.end(); ++row) {
NPCType *tmpNPCType;
tmpNPCType = new NPCType;
memset (tmpNPCType, 0, sizeof *tmpNPCType);
// Process each row returned.
for (auto row = results.begin(); row != results.end(); ++row) {
NPCType *tmpNPCType;
tmpNPCType = new NPCType;
memset(tmpNPCType, 0, sizeof *tmpNPCType);
tmpNPCType->npc_id = atoi(row[0]);
tmpNPCType->npc_id = atoi(row[0]);
strn0cpy(tmpNPCType->name, row[1], 50);
strn0cpy(tmpNPCType->name, row[1], 50);
tmpNPCType->level = atoi(row[2]);
tmpNPCType->race = atoi(row[3]);
tmpNPCType->class_ = atoi(row[4]);
tmpNPCType->max_hp = atoi(row[5]);
tmpNPCType->cur_hp = tmpNPCType->max_hp;
tmpNPCType->Mana = atoi(row[6]);
tmpNPCType->gender = atoi(row[7]);
tmpNPCType->texture = atoi(row[8]);
tmpNPCType->helmtexture = atoi(row[9]);
tmpNPCType->attack_speed = atof(row[10]);
tmpNPCType->STR = atoi(row[11]);
tmpNPCType->STA = atoi(row[12]);
tmpNPCType->DEX = atoi(row[13]);
tmpNPCType->AGI = atoi(row[14]);
tmpNPCType->INT = atoi(row[15]);
tmpNPCType->WIS = atoi(row[16]);
tmpNPCType->CHA = atoi(row[17]);
tmpNPCType->MR = atoi(row[18]);
tmpNPCType->CR = atoi(row[19]);
tmpNPCType->DR = atoi(row[20]);
tmpNPCType->FR = atoi(row[21]);
tmpNPCType->PR = atoi(row[22]);
tmpNPCType->Corrup = atoi(row[23]);
tmpNPCType->min_dmg = atoi(row[24]);
tmpNPCType->max_dmg = atoi(row[25]);
tmpNPCType->attack_count = atoi(row[26]);
tmpNPCType->level = atoi(row[2]);
tmpNPCType->race = atoi(row[3]);
tmpNPCType->class_ = atoi(row[4]);
tmpNPCType->max_hp = atoi(row[5]);
tmpNPCType->cur_hp = tmpNPCType->max_hp;
tmpNPCType->Mana = atoi(row[6]);
tmpNPCType->gender = atoi(row[7]);
tmpNPCType->texture = atoi(row[8]);
tmpNPCType->helmtexture = atoi(row[9]);
tmpNPCType->attack_delay = atoi(row[10]);
tmpNPCType->STR = atoi(row[11]);
tmpNPCType->STA = atoi(row[12]);
tmpNPCType->DEX = atoi(row[13]);
tmpNPCType->AGI = atoi(row[14]);
tmpNPCType->INT = atoi(row[15]);
tmpNPCType->WIS = atoi(row[16]);
tmpNPCType->CHA = atoi(row[17]);
tmpNPCType->MR = atoi(row[18]);
tmpNPCType->CR = atoi(row[19]);
tmpNPCType->DR = atoi(row[20]);
tmpNPCType->FR = atoi(row[21]);
tmpNPCType->PR = atoi(row[22]);
tmpNPCType->Corrup = atoi(row[23]);
tmpNPCType->min_dmg = atoi(row[24]);
tmpNPCType->max_dmg = atoi(row[25]);
tmpNPCType->attack_count = atoi(row[26]);
if (row[27] != nullptr)
strn0cpy(tmpNPCType->special_abilities, row[27], 512);
else
tmpNPCType->special_abilities[0] = '\0';
tmpNPCType->d_melee_texture1 = atoi(row[28]);
tmpNPCType->d_melee_texture2 = atoi(row[29]);
tmpNPCType->prim_melee_type = atoi(row[30]);
tmpNPCType->sec_melee_type = atoi(row[31]);
tmpNPCType->runspeed= atof(row[32]);
tmpNPCType->d_melee_texture1 = atoi(row[28]);
tmpNPCType->d_melee_texture2 = atoi(row[29]);
tmpNPCType->prim_melee_type = atoi(row[30]);
tmpNPCType->sec_melee_type = atoi(row[31]);
tmpNPCType->runspeed = atof(row[32]);
tmpNPCType->hp_regen = atoi(row[33]);
tmpNPCType->mana_regen = atoi(row[34]);
tmpNPCType->hp_regen = atoi(row[33]);
tmpNPCType->mana_regen = atoi(row[34]);
tmpNPCType->aggroradius = RuleI(Mercs, AggroRadius);
tmpNPCType->aggroradius = RuleI(Mercs, AggroRadius);
if (row[35] && strlen(row[35]))
tmpNPCType->bodytype = (uint8)atoi(row[35]);
else
tmpNPCType->bodytype = 1;
if (row[35] && strlen(row[35]))
tmpNPCType->bodytype = (uint8)atoi(row[35]);
else
tmpNPCType->bodytype = 1;
uint32 armor_tint_id = atoi(row[36]);
tmpNPCType->armor_tint[0] = (atoi(row[37]) & 0xFF) << 16;
tmpNPCType->armor_tint[0] |= (atoi(row[38]) & 0xFF) << 8;
tmpNPCType->armor_tint[0] |= (atoi(row[39]) & 0xFF);
tmpNPCType->armor_tint[0] |= (tmpNPCType->armor_tint[0]) ? (0xFF << 24) : 0;
uint32 armor_tint_id = atoi(row[36]);
tmpNPCType->armor_tint[0] = (atoi(row[37]) & 0xFF) << 16;
tmpNPCType->armor_tint[0] |= (atoi(row[38]) & 0xFF) << 8;
tmpNPCType->armor_tint[0] |= (atoi(row[39]) & 0xFF);
tmpNPCType->armor_tint[0] |= (tmpNPCType->armor_tint[0]) ? (0xFF << 24) : 0;
if (armor_tint_id == 0)
for (int index = MaterialChest; index <= EmuConstants::MATERIAL_END; index++)
tmpNPCType->armor_tint[index] = tmpNPCType->armor_tint[0];
else if (tmpNPCType->armor_tint[0] == 0) {
std::string armorTint_query = StringFormat("SELECT red1h, grn1h, blu1h, "
"red2c, grn2c, blu2c, "
"red3a, grn3a, blu3a, "
"red4b, grn4b, blu4b, "
"red5g, grn5g, blu5g, "
"red6l, grn6l, blu6l, "
"red7f, grn7f, blu7f, "
"red8x, grn8x, blu8x, "
"red9x, grn9x, blu9x "
"FROM npc_types_tint WHERE id = %d",
armor_tint_id);
auto armorTint_results = QueryDatabase(armorTint_query);
if (!results.Success() || results.RowCount() == 0)
armor_tint_id = 0;
else {
auto armorTint_row = results.begin();
if (armor_tint_id == 0)
for (int index = MaterialChest; index <= EmuConstants::MATERIAL_END; index++)
tmpNPCType->armor_tint[index] = tmpNPCType->armor_tint[0];
else if (tmpNPCType->armor_tint[0] == 0) {
std::string armorTint_query = StringFormat("SELECT red1h, grn1h, blu1h, "
"red2c, grn2c, blu2c, "
"red3a, grn3a, blu3a, "
"red4b, grn4b, blu4b, "
"red5g, grn5g, blu5g, "
"red6l, grn6l, blu6l, "
"red7f, grn7f, blu7f, "
"red8x, grn8x, blu8x, "
"red9x, grn9x, blu9x "
"FROM npc_types_tint WHERE id = %d",
armor_tint_id);
auto armorTint_results = QueryDatabase(armorTint_query);
if (!results.Success() || results.RowCount() == 0)
armor_tint_id = 0;
else {
auto armorTint_row = results.begin();
for (int index = EmuConstants::MATERIAL_BEGIN; index <= EmuConstants::MATERIAL_END; index++) {
tmpNPCType->armor_tint[index] = atoi(armorTint_row[index * 3]) << 16;
tmpNPCType->armor_tint[index] |= atoi(armorTint_row[index * 3 + 1]) << 8;
tmpNPCType->armor_tint[index] |= atoi(armorTint_row[index * 3 + 2]);
tmpNPCType->armor_tint[index] |= (tmpNPCType->armor_tint[index]) ? (0xFF << 24) : 0;
}
}
} else
armor_tint_id = 0;
for (int index = EmuConstants::MATERIAL_BEGIN; index <= EmuConstants::MATERIAL_END; index++) {
tmpNPCType->armor_tint[index] = atoi(armorTint_row[index * 3]) << 16;
tmpNPCType->armor_tint[index] |= atoi(armorTint_row[index * 3 + 1]) << 8;
tmpNPCType->armor_tint[index] |= atoi(armorTint_row[index * 3 + 2]);
tmpNPCType->armor_tint[index] |= (tmpNPCType->armor_tint[index]) ? (0xFF << 24) : 0;
}
}
} else
armor_tint_id = 0;
tmpNPCType->AC = atoi(row[40]);
tmpNPCType->ATK = atoi(row[41]);
tmpNPCType->accuracy_rating = atoi(row[42]);
tmpNPCType->scalerate = RuleI(Mercs, ScaleRate);
tmpNPCType->spellscale = atoi(row[43]);
tmpNPCType->healscale = atoi(row[44]);
tmpNPCType->AC = atoi(row[40]);
tmpNPCType->ATK = atoi(row[41]);
tmpNPCType->accuracy_rating = atoi(row[42]);
tmpNPCType->scalerate = atoi(row[43]);
tmpNPCType->spellscale = atoi(row[44]);
tmpNPCType->healscale = atoi(row[45]);
// If Merc with duplicate NPC id already in table,
// free item we attempted to add.
// If Merc with duplicate NPC id already in table,
// free item we attempted to add.
if (zone->merctable.find(merc_type_id) != zone->merctable.end()) {
delete tmpNPCType;
return nullptr;
}
delete tmpNPCType;
return nullptr;
}
zone->merctable[merc_type_id] = tmpNPCType;
npc = tmpNPCType;
}
npc = tmpNPCType;
}
return npc;
}
@@ -2998,6 +2999,14 @@ void ZoneDatabase::RemoveTempFactions(Client *client) {
QueryDatabase(query);
}
void ZoneDatabase::UpdateItemRecastTimestamps(uint32 char_id, uint32 recast_type, uint32 timestamp)
{
std::string query =
StringFormat("REPLACE INTO character_item_recast (id, recast_type, timestamp) VALUES (%u, %u, %u)", char_id,
recast_type, timestamp);
QueryDatabase(query);
}
void ZoneDatabase::LoadPetInfo(Client *client) {
// Load current pet and suspended pet
@@ -3413,38 +3422,102 @@ void ZoneDatabase::MarkCorpseAsRezzed(uint32 db_id) {
uint32 ZoneDatabase::SaveCharacterCorpse(uint32 charid, const char* charname, uint32 zoneid, uint16 instanceid, PlayerCorpse_Struct* dbpc, const glm::vec4& position) {
/* Dump Basic Corpse Data */
std::string query = StringFormat("INSERT INTO `character_corpses` "
"SET `charname` = '%s', `zone_id` = %u, `instance_id` = %u, `charid` = %d,"
"`x` = %1.1f, `y` = %1.1f, `z` = %1.1f, `heading` = %1.1f,"
"`time_of_death` = NOW(), `is_buried` = 0, `is_locked` = %d,"
"`exp` = %u, `size` = %f, `level` = %u, `race` = %u, `gender` = %u,"
"`class` = %u, `deity` = %u, `texture` = %u, `helm_texture` = %u,"
"`copper` = %u, `silver` = %u,`gold` = %u,`platinum` = %u,"
"`hair_color` = %u, `beard_color` = %u, `eye_color_1` = %u,"
"`eye_color_2` = %u, `hair_style` = %u, `face` = %u,"
"`beard` = %u, `drakkin_heritage` = %u, `drakkin_tattoo` = %u,"
"`drakkin_details` = %u, `wc_1` = %u, `wc_2` = %u,"
"`wc_3` = %u, `wc_4` = %u, `wc_5` = %u, `wc_6` = %u,"
"`wc_7` = %u,`wc_8` = %u,`wc_9` = %u",
EscapeString(charname).c_str(), zoneid, instanceid, charid,
position.x, position.y, position.z, position.w,
dbpc->locked, dbpc->exp, dbpc->size, dbpc->level, dbpc->race,
dbpc->gender, dbpc->class_, dbpc->deity, dbpc->texture,
dbpc->helmtexture, dbpc->copper, dbpc->silver, dbpc->gold,
dbpc->plat, dbpc->haircolor, dbpc->beardcolor, dbpc->eyecolor1,
dbpc->eyecolor2, dbpc->hairstyle, dbpc->face, dbpc->beard,
dbpc->drakkin_heritage, dbpc->drakkin_tattoo, dbpc->drakkin_details,
dbpc->item_tint[0].color, dbpc->item_tint[1].color, dbpc->item_tint[2].color,
dbpc->item_tint[3].color, dbpc->item_tint[4].color, dbpc->item_tint[5].color,
dbpc->item_tint[6].color, dbpc->item_tint[7].color, dbpc->item_tint[8].color);
std::string query = StringFormat(
"INSERT INTO `character_corpses` "
"SET `charname` = '%s', "
"`zone_id` = %u, "
"`instance_id` = %u, "
"`charid` = %d, "
"`x` = %1.1f, "
"`y` = %1.1f, "
"`z` = %1.1f, "
"`heading` = %1.1f, "
"`time_of_death` = NOW(), "
"`is_buried` = 0, "
"`is_locked` = %d, "
"`exp` = %u, "
"`size` = %f, "
"`level` = %u, "
"`race` = %u, "
"`gender` = %u, "
"`class` = %u, "
"`deity` = %u, "
"`texture` = %u, "
"`helm_texture` = %u, "
"`copper` = %u, "
"`silver` = %u, "
"`gold` = %u, "
"`platinum` = %u, "
"`hair_color` = %u, "
"`beard_color` = %u, "
"`eye_color_1` = %u, "
"`eye_color_2` = %u, "
"`hair_style` = %u, "
"`face` = %u, "
"`beard` = %u, "
"`drakkin_heritage` = %u, "
"`drakkin_tattoo` = %u, "
"`drakkin_details` = %u, "
"`wc_1` = %u, "
"`wc_2` = %u, "
"`wc_3` = %u, "
"`wc_4` = %u, "
"`wc_5` = %u, "
"`wc_6` = %u, "
"`wc_7` = %u, "
"`wc_8` = %u, "
"`wc_9` = %u ",
EscapeString(charname).c_str(),
zoneid,
instanceid,
charid,
position.x,
position.y,
position.z,
position.w,
dbpc->locked,
dbpc->exp,
dbpc->size,
dbpc->level,
dbpc->race,
dbpc->gender,
dbpc->class_,
dbpc->deity,
dbpc->texture,
dbpc->helmtexture,
dbpc->copper,
dbpc->silver,
dbpc->gold,
dbpc->plat,
dbpc->haircolor,
dbpc->beardcolor,
dbpc->eyecolor1,
dbpc->eyecolor2,
dbpc->hairstyle,
dbpc->face,
dbpc->beard,
dbpc->drakkin_heritage,
dbpc->drakkin_tattoo,
dbpc->drakkin_details,
dbpc->item_tint[0].color,
dbpc->item_tint[1].color,
dbpc->item_tint[2].color,
dbpc->item_tint[3].color,
dbpc->item_tint[4].color,
dbpc->item_tint[5].color,
dbpc->item_tint[6].color,
dbpc->item_tint[7].color,
dbpc->item_tint[8].color
);
auto results = QueryDatabase(query);
uint32 last_insert_id = results.LastInsertedID();
std::string corpse_items_query;
/* Dump Items from Inventory */
uint8 first_entry = 0;
for (unsigned int i = 0; i < dbpc->itemcount; i++) {
if (first_entry != 1){
query = StringFormat("REPLACE INTO `character_corpse_items` \n"
corpse_items_query = StringFormat("REPLACE INTO `character_corpse_items` \n"
" (corpse_id, equip_slot, item_id, charges, aug_1, aug_2, aug_3, aug_4, aug_5, aug_6, attuned) \n"
" VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n",
last_insert_id,
@@ -3462,7 +3535,7 @@ uint32 ZoneDatabase::SaveCharacterCorpse(uint32 charid, const char* charname, ui
first_entry = 1;
}
else{
query = query + StringFormat(", (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n",
corpse_items_query = corpse_items_query + StringFormat(", (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n",
last_insert_id,
dbpc->items[i].equip_slot,
dbpc->items[i].item_id,
@@ -3477,7 +3550,9 @@ uint32 ZoneDatabase::SaveCharacterCorpse(uint32 charid, const char* charname, ui
);
}
}
auto sc_results = QueryDatabase(query);
if (!corpse_items_query.empty())
QueryDatabase(corpse_items_query);
return last_insert_id;
}
+1
View File
@@ -256,6 +256,7 @@ public:
void LoadPetInfo(Client *c);
void SavePetInfo(Client *c);
void RemoveTempFactions(Client *c);
void UpdateItemRecastTimestamps(uint32 char_id, uint32 recast_type, uint32 timestamp);
/* Character Data Loaders */
bool LoadCharacterFactionValues(uint32 character_id, faction_map & val_list);