This commit is contained in:
SecretsOTheP 2014-11-09 03:40:59 -05:00
commit d8a8b8e6dc
15 changed files with 186 additions and 75 deletions

View File

@ -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.

View File

@ -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);

View File

@ -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; }

View File

@ -0,0 +1 @@
ALTER TABLE `raid_members` CHANGE COLUMN `groupid` `groupid` INT(4) UNSIGNED NOT NULL DEFAULT '0' AFTER `charid`;

View File

@ -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);

View File

@ -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<Mob *, float> &a, const std::pair<Mob *, float> &b)
{
return a.first->GetSpawnTimeStamp() > b.first->GetSpawnTimeStamp();
}
bool EntityList::MakeTrackPacket(Client *client)
{
std::list<std::pair<Mob *, float> > 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;
MobDistance = it->second->DistNoZ(*client);
if (MobDistance > distance)
continue;
tracking_list.push_back(std::make_pair(it->second, MobDistance));
}
++it;
}
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));
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));
}
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);
}
safe_delete_array(buffer1);
safe_delete_array(buffer2);
return ret;
return true;
}
void EntityList::MessageGroup(Mob *sender, bool skipclose, uint32 type, const char *message, ...)

View File

@ -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

View File

@ -32,20 +32,34 @@ struct lua_registered_event {
};
extern std::map<std::string, std::list<lua_registered_event>> lua_encounter_events_registered;
extern std::map<std::string, bool> 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<EQEmu::Any> 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<lua_registered_event> &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<EQEmu::Any> 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<lua_registered_event> &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<long long>(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<long long>(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<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(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", &register_npc_event),
luabind::def("unregister_npc_event", &unregister_npc_event),
luabind::def("register_player_event", &register_player_event),
luabind::def("unregister_player_event", &unregister_player_event),
luabind::def("register_item_event", &register_item_event),
luabind::def("unregister_item_event", &unregister_item_event),
luabind::def("register_spell_event", &register_spell_event),
luabind::def("unregister_spell_event", &unregister_spell_event),
luabind::def("register_npc_event", (void(*)(std::string, int, int, luabind::adl::object))&register_npc_event),
luabind::def("register_npc_event", (void(*)(int, int, luabind::adl::object))&register_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))&register_player_event),
luabind::def("register_player_event", (void(*)(int, luabind::adl::object))&register_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))&register_item_event),
luabind::def("register_item_event", (void(*)(int, int, luabind::adl::object))&register_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))&register_spell_event),
luabind::def("register_spell_event", (void(*)(int, int, luabind::adl::object func))&register_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),

View File

@ -126,6 +126,7 @@ struct lua_registered_event {
};
std::map<std::string, std::list<lua_registered_event>> lua_encounter_events_registered;
std::map<std::string, bool> 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);

View File

@ -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;
}

View File

@ -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 "";
}

View File

@ -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

View File

@ -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);

View File

@ -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<float>(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;

View File

@ -445,7 +445,7 @@ void Zone::LoadNewMerchantData(uint32 merchantid) {
std::list<MerchantList> 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);
}