diff --git a/changelog.txt b/changelog.txt index 380793866..f5b75ff98 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,9 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 11/06/2014 == +demonstar55: Tracking default sort will now be correct order +Trevius: Fixed dynamic merchant list loading. Allows any merchant to be used in any zone. + == 11/03/2014 == Secrets: Fixed an overflow in melee lifetap calculations (int16 vs int32) Secrets: Fixed overflow on AC and ATK values that can go out of range. diff --git a/common/dbcore.cpp b/common/dbcore.cpp index 21168efa0..fb038db2e 100644 --- a/common/dbcore.cpp +++ b/common/dbcore.cpp @@ -234,6 +234,18 @@ bool DBcore::RunQuery(const char* query, uint32 querylen, char* errbuf, MYSQL_RE return ret; } +void DBcore::TransactionBegin() { + QueryDatabase("START TRANSACTION"); +} + +void DBcore::TransactionCommit() { + QueryDatabase("COMMIT"); +} + +void DBcore::TransactionRollback() { + QueryDatabase("ROLLBACK"); +} + uint32 DBcore::DoEscapeString(char* tobuf, const char* frombuf, uint32 fromlen) { // No good reason to lock the DB, we only need it in the first place to check char encoding. // LockMutex lock(&MDatabase); diff --git a/common/dbcore.h b/common/dbcore.h index 56f326467..9dd5aef5e 100644 --- a/common/dbcore.h +++ b/common/dbcore.h @@ -26,6 +26,9 @@ public: bool RunQuery(const char* query, uint32 querylen, char* errbuf = 0, MYSQL_RES** result = 0, uint32* affected_rows = 0, uint32* last_insert_id = 0, uint32* errnum = 0, bool retry = true); MySQLRequestResult QueryDatabase(const char* query, uint32 querylen, bool retryOnFailureOnce = true); MySQLRequestResult QueryDatabase(std::string query, bool retryOnFailureOnce = true); + void TransactionBegin(); + void TransactionCommit(); + void TransactionRollback(); uint32 DoEscapeString(char* tobuf, const char* frombuf, uint32 fromlen); void ping(); MYSQL* getMySQL(){ return &mysql; } diff --git a/utils/sql/git/required/2014_11_08_RaidMembers.sql b/utils/sql/git/required/2014_11_08_RaidMembers.sql new file mode 100644 index 000000000..79e1bb17a --- /dev/null +++ b/utils/sql/git/required/2014_11_08_RaidMembers.sql @@ -0,0 +1 @@ +ALTER TABLE `raid_members` CHANGE COLUMN `groupid` `groupid` INT(4) UNSIGNED NOT NULL DEFAULT '0' AFTER `charid`; \ No newline at end of file diff --git a/zone/corpse.cpp b/zone/corpse.cpp index f028b4555..8df695a84 100644 --- a/zone/corpse.cpp +++ b/zone/corpse.cpp @@ -402,6 +402,7 @@ Corpse::Corpse(Client* client, int32 in_rezexp) } } + database.TransactionBegin(); if(removed_list.size() != 0) { std::stringstream ss(""); ss << "DELETE FROM inventory WHERE charid=" << client->CharacterID(); @@ -433,6 +434,12 @@ Corpse::Corpse(Client* client, int32 in_rezexp) client->CalcBonuses(); // will only affect offline profile viewing of dead characters..unneeded overhead client->Save(); + + Rezzed(false); + Save(); + database.TransactionCommit(); + + return; } //end "not leaving naked corpses" Rezzed(false); diff --git a/zone/entity.cpp b/zone/entity.cpp index d5354386f..76b9eb8d4 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -63,6 +63,7 @@ extern uint16 adverrornum; Entity::Entity() { id = 0; + spawn_timestamp = time(nullptr); } Entity::~Entity() @@ -2934,8 +2935,14 @@ void EntityList::SignalMobsByNPCID(uint32 snpc, int signal_id) } } +bool tracking_compare(const std::pair &a, const std::pair &b) +{ + return a.first->GetSpawnTimeStamp() > b.first->GetSpawnTimeStamp(); +} + bool EntityList::MakeTrackPacket(Client *client) { + std::list > tracking_list; uint32 distance = 0; float MobDistance; @@ -2950,60 +2957,42 @@ bool EntityList::MakeTrackPacket(Client *client) if (distance < 300) distance = 300; - uint32 spe= 0; - bool ret = false; - - spe = mob_list.size() + 50; - - uchar *buffer1 = new uchar[sizeof(Track_Struct)]; - Track_Struct *track_ent = (Track_Struct*) buffer1; - - uchar *buffer2 = new uchar[sizeof(Track_Struct)*spe]; - Tracking_Struct *track_array = (Tracking_Struct*) buffer2; - memset(track_array, 0, sizeof(Track_Struct)*spe); - - uint32 array_counter = 0; - Group *g = client->GetGroup(); - auto it = mob_list.begin(); - while (it != mob_list.end()) { - if (it->second && ((MobDistance = it->second->DistNoZ(*client)) <= distance)) { - if ((it->second != client) && it->second->IsTrackable()) { - memset(track_ent, 0, sizeof(Track_Struct)); - Mob *cur_entity = it->second; - track_ent->entityid = cur_entity->GetID(); - track_ent->distance = MobDistance; - track_ent->level = cur_entity->GetLevel(); - track_ent->NPC = !cur_entity->IsClient(); - if (g && cur_entity->IsClient() && g->IsGroupMember(cur_entity->CastToMob())) - track_ent->GroupMember = 1; - else - track_ent->GroupMember = 0; - strn0cpy(track_ent->name, cur_entity->GetName(), sizeof(track_ent->name)); - memcpy(&track_array->Entrys[array_counter], track_ent, sizeof(Track_Struct)); - array_counter++; - } - } + for (auto it = mob_list.cbegin(); it != mob_list.cend(); ++it) { + if (!it->second || it->second == client || !it->second->IsTrackable()) + continue; - ++it; + MobDistance = it->second->DistNoZ(*client); + if (MobDistance > distance) + continue; + + tracking_list.push_back(std::make_pair(it->second, MobDistance)); } - if (array_counter <= spe) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Track,sizeof(Track_Struct)*(array_counter)); - memcpy(outapp->pBuffer, track_array,sizeof(Track_Struct)*(array_counter)); - outapp->priority = 6; - client->QueuePacket(outapp); - safe_delete(outapp); - ret = true; - } else { - LogFile->write(EQEMuLog::Status, "ERROR: Unable to transmit a Tracking_Struct packet. Mobs in zone = %i. Mobs in packet = %i", array_counter, spe); + tracking_list.sort(tracking_compare); + EQApplicationPacket *outapp = new EQApplicationPacket(OP_Track, sizeof(Track_Struct) * tracking_list.size()); + Tracking_Struct *outtrack = (Tracking_Struct *)outapp->pBuffer; + outapp->priority = 6; + + int index = 0; + for (auto it = tracking_list.cbegin(); it != tracking_list.cend(); ++it, ++index) { + Mob *cur_entity = it->first; + outtrack->Entrys[index].entityid = cur_entity->GetID(); + outtrack->Entrys[index].distance = it->second; + outtrack->Entrys[index].level = cur_entity->GetLevel(); + outtrack->Entrys[index].NPC = !cur_entity->IsClient(); + if (g && cur_entity->IsClient() && g->IsGroupMember(cur_entity->CastToMob())) + outtrack->Entrys[index].GroupMember = 1; + else + outtrack->Entrys[index].GroupMember = 0; + strn0cpy(outtrack->Entrys[index].name, cur_entity->GetName(), sizeof(outtrack->Entrys[index].name)); } - safe_delete_array(buffer1); - safe_delete_array(buffer2); + client->QueuePacket(outapp); + safe_delete(outapp); - return ret; + return true; } void EntityList::MessageGroup(Mob *sender, bool skipclose, uint32 type, const char *message, ...) diff --git a/zone/entity.h b/zone/entity.h index ad5de09bf..2e6990231 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -97,6 +97,7 @@ public: const Beacon *CastToBeacon() const; inline const uint16& GetID() const { return id; } + inline const time_t& GetSpawnTimeStamp() const { return spawn_timestamp; } virtual const char* GetName() { return ""; } bool CheckCoordLosNoZLeaps(float cur_x, float cur_y, float cur_z, float trg_x, float trg_y, float trg_z, float perwalk=1); @@ -112,6 +113,7 @@ protected: uint32 pDBAsyncWorkID; private: uint16 id; + time_t spawn_timestamp; }; class EntityList diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index 686466b1f..d58ea21bc 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -32,20 +32,34 @@ struct lua_registered_event { }; extern std::map> lua_encounter_events_registered; +extern std::map lua_encounters_loaded; extern void MapOpcodes(); extern void ClearMappedOpcode(EmuOpcode op); +void unregister_event(std::string package_name, std::string name, int evt); + void load_encounter(std::string name) { + if(lua_encounters_loaded.count(name) > 0) + return; + + lua_encounters_loaded[name] = true; parse->EventEncounter(EVENT_ENCOUNTER_LOAD, name, 0); } void load_encounter_with_data(std::string name, std::string info_str) { + if(lua_encounters_loaded.count(name) > 0) + return; + + lua_encounters_loaded[name] = true; std::vector info_ptrs; info_ptrs.push_back(&info_str); parse->EventEncounter(EVENT_ENCOUNTER_LOAD, name, 0, &info_ptrs); } void unload_encounter(std::string name) { + if(lua_encounters_loaded.count(name) == 0) + return; + auto liter = lua_encounter_events_registered.begin(); while(liter != lua_encounter_events_registered.end()) { std::list &elist = liter->second; @@ -65,10 +79,13 @@ void unload_encounter(std::string name) { } } + lua_encounters_loaded.erase(name); parse->EventEncounter(EVENT_ENCOUNTER_UNLOAD, name, 0); } void unload_encounter_with_data(std::string name, std::string info_str) { + if(lua_encounters_loaded.count(name) == 0) + return; auto liter = lua_encounter_events_registered.begin(); while(liter != lua_encounter_events_registered.end()) { @@ -91,12 +108,18 @@ void unload_encounter_with_data(std::string name, std::string info_str) { } } + lua_encounters_loaded.erase(name); std::vector info_ptrs; info_ptrs.push_back(&info_str); parse->EventEncounter(EVENT_ENCOUNTER_UNLOAD, name, 0, &info_ptrs); } void register_event(std::string package_name, std::string name, int evt, luabind::adl::object func) { + if(lua_encounters_loaded.count(name) == 0) + return; + + unregister_event(package_name, name, evt); + lua_registered_event e; e.encounter_name = name; e.lua_reference = func; @@ -109,15 +132,6 @@ void register_event(std::string package_name, std::string name, int evt, luabind lua_encounter_events_registered[package_name] = elist; } else { std::list &elist = liter->second; - auto iter = elist.begin(); - while(iter != elist.end()) { - if(iter->event_id == evt && iter->encounter_name.compare(name) == 0) { - //already registered this event for this encounter - return; - } - ++iter; - } - elist.push_back(e); } } @@ -130,7 +144,9 @@ void unregister_event(std::string package_name, std::string name, int evt) { while(iter != elist.end()) { if(iter->event_id == evt && iter->encounter_name.compare(name) == 0) { iter = elist.erase(iter); + break; } + ++iter; } lua_encounter_events_registered[package_name] = elist; } @@ -145,6 +161,11 @@ void register_npc_event(std::string name, int evt, int npc_id, luabind::adl::obj } } +void register_npc_event(int evt, int npc_id, luabind::adl::object func) { + std::string name = quest_manager.GetEncounter(); + register_npc_event(name, evt, npc_id, func); +} + void unregister_npc_event(std::string name, int evt, int npc_id) { std::stringstream package_name; package_name << "npc_" << npc_id; @@ -152,16 +173,31 @@ void unregister_npc_event(std::string name, int evt, int npc_id) { unregister_event(package_name.str(), name, evt); } +void unregister_npc_event(int evt, int npc_id) { + std::string name = quest_manager.GetEncounter(); + unregister_npc_event(name, evt, npc_id); +} + void register_player_event(std::string name, int evt, luabind::adl::object func) { if(luabind::type(func) == LUA_TFUNCTION) { register_event("player", name, evt, func); } } +void register_player_event(int evt, luabind::adl::object func) { + std::string name = quest_manager.GetEncounter(); + register_player_event(name, evt, func); +} + void unregister_player_event(std::string name, int evt) { unregister_event("player", name, evt); } +void unregister_player_event(int evt) { + std::string name = quest_manager.GetEncounter(); + unregister_player_event(name, evt); +} + void register_item_event(std::string name, int evt, int item_id, luabind::adl::object func) { std::string package_name = "item_"; package_name += std::to_string(static_cast(item_id)); @@ -171,6 +207,11 @@ void register_item_event(std::string name, int evt, int item_id, luabind::adl::o } } +void register_item_event(int evt, int item_id, luabind::adl::object func) { + std::string name = quest_manager.GetEncounter(); + register_item_event(name, evt, item_id, func); +} + void unregister_item_event(std::string name, int evt, int item_id) { std::string package_name = "item_"; package_name += std::to_string(static_cast(item_id)); @@ -178,6 +219,11 @@ void unregister_item_event(std::string name, int evt, int item_id) { unregister_event(package_name, name, evt); } +void unregister_item_event(int evt, int item_id) { + std::string name = quest_manager.GetEncounter(); + unregister_item_event(name, evt, item_id); +} + void register_spell_event(std::string name, int evt, int spell_id, luabind::adl::object func) { if(luabind::type(func) == LUA_TFUNCTION) { std::stringstream package_name; @@ -187,6 +233,11 @@ void register_spell_event(std::string name, int evt, int spell_id, luabind::adl: } } +void register_spell_event(int evt, int spell_id, luabind::adl::object func) { + std::string name = quest_manager.GetEncounter(); + register_spell_event(name, evt, spell_id, func); +} + void unregister_spell_event(std::string name, int evt, int spell_id) { std::stringstream package_name; package_name << "spell_" << spell_id; @@ -194,6 +245,11 @@ void unregister_spell_event(std::string name, int evt, int spell_id) { unregister_event(package_name.str(), name, evt); } +void unregister_spell_event(int evt, int spell_id) { + std::string name = quest_manager.GetEncounter(); + unregister_spell_event(name, evt, spell_id); +} + Lua_Mob lua_spawn2(int npc_type, int grid, int unused, double x, double y, double z, double heading) { return Lua_Mob(quest_manager.spawn2(npc_type, grid, unused, static_cast(x), static_cast(y), static_cast(z), static_cast(heading))); @@ -1161,6 +1217,11 @@ Lua_ItemInst lua_get_quest_item() { return quest_manager.GetQuestItem(); } +std::string lua_get_encounter() { + return quest_manager.GetEncounter(); +} + + void lua_map_opcodes() { MapOpcodes(); } @@ -1195,14 +1256,22 @@ luabind::scope lua_register_general() { luabind::def("unload_encounter", &unload_encounter), luabind::def("load_encounter_with_data", &load_encounter_with_data), luabind::def("unload_encounter_with_data", &unload_encounter_with_data), - luabind::def("register_npc_event", ®ister_npc_event), - luabind::def("unregister_npc_event", &unregister_npc_event), - luabind::def("register_player_event", ®ister_player_event), - luabind::def("unregister_player_event", &unregister_player_event), - luabind::def("register_item_event", ®ister_item_event), - luabind::def("unregister_item_event", &unregister_item_event), - luabind::def("register_spell_event", ®ister_spell_event), - luabind::def("unregister_spell_event", &unregister_spell_event), + luabind::def("register_npc_event", (void(*)(std::string, int, int, luabind::adl::object))®ister_npc_event), + luabind::def("register_npc_event", (void(*)(int, int, luabind::adl::object))®ister_npc_event), + luabind::def("unregister_npc_event", (void(*)(std::string, int, int))&unregister_npc_event), + luabind::def("unregister_npc_event", (void(*)(int, int))&unregister_npc_event), + luabind::def("register_player_event", (void(*)(std::string, int, luabind::adl::object))®ister_player_event), + luabind::def("register_player_event", (void(*)(int, luabind::adl::object))®ister_player_event), + luabind::def("unregister_player_event", (void(*)(std::string, int))&unregister_player_event), + luabind::def("unregister_player_event", (void(*)(int))&unregister_player_event), + luabind::def("register_item_event", (void(*)(std::string, int, int, luabind::adl::object))®ister_item_event), + luabind::def("register_item_event", (void(*)(int, int, luabind::adl::object))®ister_item_event), + luabind::def("unregister_item_event", (void(*)(std::string, int, int))&unregister_item_event), + luabind::def("unregister_item_event", (void(*)(int, int))&unregister_item_event), + luabind::def("register_spell_event", (void(*)(std::string, int, int, luabind::adl::object func))®ister_spell_event), + luabind::def("register_spell_event", (void(*)(int, int, luabind::adl::object func))®ister_spell_event), + luabind::def("unregister_spell_event", (void(*)(std::string, int, int))&unregister_spell_event), + luabind::def("unregister_spell_event", (void(*)(int, int))&unregister_spell_event), luabind::def("spawn2", (Lua_Mob(*)(int,int,int,double,double,double,double))&lua_spawn2), luabind::def("unique_spawn", (Lua_Mob(*)(int,int,int,double,double,double))&lua_unique_spawn), luabind::def("unique_spawn", (Lua_Mob(*)(int,int,int,double,double,double,double))&lua_unique_spawn), @@ -1360,6 +1429,7 @@ luabind::scope lua_register_general() { luabind::def("get_initiator", &lua_get_initiator), luabind::def("get_owner", &lua_get_owner), luabind::def("get_quest_item", &lua_get_quest_item), + luabind::def("get_encounter", &lua_get_encounter), luabind::def("map_opcodes", &lua_map_opcodes), luabind::def("clear_opcode", &lua_clear_opcode), luabind::def("enable_recipe", &lua_enable_recipe), diff --git a/zone/lua_parser.cpp b/zone/lua_parser.cpp index 6f44d4fb8..dce88d5e6 100644 --- a/zone/lua_parser.cpp +++ b/zone/lua_parser.cpp @@ -126,6 +126,7 @@ struct lua_registered_event { }; std::map> lua_encounter_events_registered; +std::map lua_encounters_loaded; LuaParser::LuaParser() { for(int i = 0; i < _LargestEventID; ++i) { @@ -607,7 +608,7 @@ int LuaParser::_EventEncounter(std::string package_name, QuestEventID evt, std:: lua_setfield(L, -2, "data"); } - quest_manager.StartQuest(nullptr, nullptr, nullptr); + quest_manager.StartQuest(nullptr, nullptr, nullptr, encounter_name); if(lua_pcall(L, 1, 1, 0)) { std::string error = lua_tostring(L, -1); AddError(error); @@ -776,6 +777,7 @@ void LuaParser::ReloadQuests() { loaded_.clear(); errors_.clear(); lua_encounter_events_registered.clear(); + lua_encounters_loaded.clear(); if(L) { lua_close(L); diff --git a/zone/mob.cpp b/zone/mob.cpp index cb5d9631d..7e277d438 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -608,7 +608,7 @@ int32 Mob::CalcMaxMana() { int32 Mob::CalcMaxHP() { max_hp = (base_hp + itembonuses.HP + spellbonuses.HP); - max_hp += max_hp * ((aabonuses.MaxHPChange + spellbonuses.MaxHPChange + itembonuses.MaxHPChange) / 10000); + max_hp += max_hp * ((aabonuses.MaxHPChange + spellbonuses.MaxHPChange + itembonuses.MaxHPChange) / 10000.0f); return max_hp; } diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 4de816067..46d2deb34 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -95,6 +95,7 @@ QuestManager quest_manager; Client *initiator = nullptr; \ ItemInst* questitem = nullptr; \ bool depop_npc = false; \ + std::string encounter; \ do { \ if(!quests_running_.empty()) { \ running_quest e = quests_running_.top(); \ @@ -102,6 +103,7 @@ QuestManager quest_manager; initiator = e.initiator; \ questitem = e.questitem; \ depop_npc = e.depop_npc; \ + encounter = e.encounter; \ } \ } while(0) @@ -151,12 +153,13 @@ void QuestManager::Process() { } } -void QuestManager::StartQuest(Mob *_owner, Client *_initiator, ItemInst* _questitem) { +void QuestManager::StartQuest(Mob *_owner, Client *_initiator, ItemInst* _questitem, std::string encounter) { running_quest run; run.owner = _owner; run.initiator = _initiator; run.questitem = _questitem; run.depop_npc = false; + run.encounter = encounter; quests_running_.push(run); } @@ -3006,3 +3009,12 @@ ItemInst *QuestManager::GetQuestItem() const { return nullptr; } + +std::string QuestManager::GetEncounter() const { + if(!quests_running_.empty()) { + running_quest e = quests_running_.top(); + return e.encounter; + } + + return ""; +} diff --git a/zone/questmgr.h b/zone/questmgr.h index 2d1184942..6b47bab04 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -34,12 +34,13 @@ class QuestManager { Client *initiator; ItemInst* questitem; bool depop_npc; + std::string encounter; }; public: QuestManager(); virtual ~QuestManager(); - void StartQuest(Mob *_owner, Client *_initiator = nullptr, ItemInst* _questitem = nullptr); + void StartQuest(Mob *_owner, Client *_initiator = nullptr, ItemInst* _questitem = nullptr, std::string encounter = ""); void EndQuest(); bool QuestsRunning() { return !quests_running_.empty(); } @@ -252,6 +253,7 @@ public: NPC *GetNPC() const; Mob *GetOwner() const; ItemInst *GetQuestItem() const; + std::string GetEncounter() const; inline bool ProximitySayInUse() { return HaveProximitySays; } #ifdef BOTS diff --git a/zone/raids.cpp b/zone/raids.cpp index d377d4174..041b92ad4 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -94,6 +94,10 @@ void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bo c->GetName(), groupleader, rleader, looter); auto results = database.QueryDatabase(query); + if(!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error inserting into raid members: %s", results.ErrorMessage().c_str()); + } + LearnMembers(); VerifyRaid(); if (rleader) { @@ -225,12 +229,12 @@ void Raid::SetRaidLeader(const char *wasLead, const char *name) std::string query = StringFormat("UPDATE raid_members SET israidleader = 0 WHERE name = '%s'", wasLead); auto results = database.QueryDatabase(query); if (!results.Success()) - printf("Set Raid Leader error: %s\n", results.ErrorMessage().c_str()); + LogFile->write(EQEMuLog::Error, "Set Raid Leader error: %s\n", results.ErrorMessage().c_str()); query = StringFormat("UPDATE raid_members SET israidleader = 1 WHERE name = '%s'", name); results = database.QueryDatabase(query); if (!results.Success()) - printf("Set Raid Leader error: %s\n", results.ErrorMessage().c_str()); + LogFile->write(EQEMuLog::Error, "Set Raid Leader error: %s\n", results.ErrorMessage().c_str()); strn0cpy(leadername, name, 64); diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index b97ca0244..924af5555 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -299,7 +299,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) //This effect can also do damage by percent. if (val < 0) { - if (-val > spell.max[i]) + if (spell.max[i] && -val > spell.max[i]) val = -spell.max[i]; if (caster) @@ -309,7 +309,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) else { - if (val > spell.max[i]) + if (spell.max[i] && val > spell.max[i]) val = spell.max[i]; if(caster) @@ -2647,7 +2647,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_Taunt: { if (IsNPC()){ - caster->Taunt(this->CastToNPC(), false, spell.base[i]); + caster->Taunt(this->CastToNPC(), false, static_cast(spell.base[i])); if (spell.base2[i] > 0) CastToNPC()->SetHate(caster, (CastToNPC()->GetHateAmount(caster) + spell.base2[i])); @@ -3558,6 +3558,8 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste case SE_WipeHateList: { + if (IsMezSpell(spell_id)) + break; int wipechance = spells[spell_id].base[i]; int bonus = 0; diff --git a/zone/zone.cpp b/zone/zone.cpp index 476a61f2a..add9e7c6e 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -445,7 +445,7 @@ void Zone::LoadNewMerchantData(uint32 merchantid) { std::list merlist; std::string query = StringFormat("SELECT item, slot, faction_required, level_required, alt_currency_cost, " - "classes_required FROM merchantlist WHERE merchantid=%d ORDER BY slot", merchantid); + "classes_required, probability FROM merchantlist WHERE merchantid=%d ORDER BY slot", merchantid); auto results = database.QueryDatabase(query); if (!results.Success()) { LogFile->write(EQEMuLog::Error, "Error in LoadNewMerchantData query '%s' %s", query.c_str(), results.ErrorMessage().c_str()); @@ -459,8 +459,9 @@ void Zone::LoadNewMerchantData(uint32 merchantid) { ml.slot = atoul(row[1]); ml.faction_required = atoul(row[2]); ml.level_required = atoul(row[3]); - ml.alt_currency_cost = atoul(row[3]); - ml.classes_required = atoul(row[4]); + ml.alt_currency_cost = atoul(row[4]); + ml.classes_required = atoul(row[5]); + ml.probability = atoul(row[6]); merlist.push_back(ml); }