From 8498d7b5d25f0a583d83bf11510c9c8cbab864b8 Mon Sep 17 00:00:00 2001 From: Trust Date: Fri, 20 Jul 2018 23:07:59 -0400 Subject: [PATCH 01/44] /who all fix for zones like scarlet, netherbian, etc --- world/clientlist.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/world/clientlist.cpp b/world/clientlist.cpp index 3f1c3f50c..eb821b22f 100644 --- a/world/clientlist.cpp +++ b/world/clientlist.cpp @@ -530,6 +530,28 @@ void ClientList::SendWhoAll(uint32 fromid,const char* to, int16 admin, Who_All_S //uint32 x = 0; int whomlen = 0; if (whom) { + // fixes for client converting some queries into a race query instead of zone + if (whom->wrace == 221) { + whom->wrace = 0xFFFF; + strcpy(whom->whom, "scarlet"); + } + if (whom->wrace == 327) { + whom->wrace = 0xFFFF; + strcpy(whom->whom, "crystal"); + } + if (whom->wrace == 103) { + whom->wrace = 0xFFFF; + strcpy(whom->whom, "kedge"); + } + if (whom->wrace == 230) { + whom->wrace = 0xFFFF; + strcpy(whom->whom, "akheva"); + } + if (whom->wrace == 229) { + whom->wrace = 0xFFFF; + strcpy(whom->whom, "netherbian"); + } + whomlen = strlen(whom->whom); if(whom->wrace == 0x001A) // 0x001A is the old Froglok race number and is sent by the client for /who all froglok whom->wrace = FROGLOK; // This is what EQEmu uses for the Froglok Race number. From f8f1061cedde1677661f6b2740cfdd775c21458a Mon Sep 17 00:00:00 2001 From: Trust Date: Sun, 22 Jul 2018 12:39:34 -0400 Subject: [PATCH 02/44] [Queryserv] Dropped Item Logging --- common/ruletypes.h | 1 + common/servertalk.h | 22 +++++++++++++ queryserv/database.cpp | 33 +++++++++++++++++++ queryserv/database.h | 1 + queryserv/worldserver.cpp | 5 +++ world/zoneserver.cpp | 1 + zone/client.h | 1 + zone/inventory.cpp | 69 +++++++++++++++++++++++++++++++++++++++ zone/object.cpp | 2 ++ 9 files changed, 135 insertions(+) diff --git a/common/ruletypes.h b/common/ruletypes.h index c89213368..fd5ce8a7d 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -692,6 +692,7 @@ RULE_CATEGORY_END() RULE_CATEGORY(QueryServ) RULE_BOOL(QueryServ, PlayerLogChat, false) // Logs Player Chat RULE_BOOL(QueryServ, PlayerLogTrades, false) // Logs Player Trades +RULE_BOOL(QueryServ, PlayerDropItems, false) // Logs Player dropping items RULE_BOOL(QueryServ, PlayerLogHandins, false) // Logs Player Handins RULE_BOOL(QueryServ, PlayerLogNPCKills, false) // Logs Player NPC Kills RULE_BOOL(QueryServ, PlayerLogDeletes, false) // Logs Player Deletes diff --git a/common/servertalk.h b/common/servertalk.h index e1d019fc4..c5bee9ef8 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -203,6 +203,7 @@ #define ServerOP_CZSignalNPC 0x5017 #define ServerOP_CZSetEntityVariableByNPCTypeID 0x5018 #define ServerOP_WWMarquee 0x5019 +#define ServerOP_QSPlayerDropItem 0x5020 /* Query Serv Generic Packet Flag/Type Enumeration */ enum { QSG_LFGuild = 0 }; @@ -1140,6 +1141,27 @@ struct QSPlayerLogTrade_Struct { QSTradeItems_Struct items[0]; }; +struct QSDropItems_Struct { + uint32 item_id; + uint16 charges; + uint32 aug_1; + uint32 aug_2; + uint32 aug_3; + uint32 aug_4; + uint32 aug_5; +}; + +struct QSPlayerDropItem_Struct { + uint32 char_id; + bool pickup; // 0 drop, 1 pickup + uint32 zone_id; + int x; + int y; + int z; + uint16 _detail_count; + QSDropItems_Struct items[0]; +}; + struct QSHandinItems_Struct { char action_type[7]; // handin, return or reward uint16 char_slot; diff --git a/queryserv/database.cpp b/queryserv/database.cpp index c4e185360..fcda884e4 100644 --- a/queryserv/database.cpp +++ b/queryserv/database.cpp @@ -123,6 +123,39 @@ void Database::AddSpeech(const char* from, const char* to, const char* message, } +void Database::LogPlayerDropItem(QSPlayerDropItem_Struct* QS) { + + std::string query = StringFormat("INSERT INTO `qs_player_drop_record` SET `time` = NOW(), " + "`char_id` = '%i', `pickup` = '%i', " + "`zone_id` = '%i', `x` = '%i', `y` = '%i', `z` = '%i' ", + QS->char_id, QS->pickup, QS->zone_id, QS->x, QS->y, QS->z); + + auto results = QueryDatabase(query); + if (!results.Success()) { + Log(Logs::Detail, Logs::QS_Server, "Failed Drop Record Insert: %s", results.ErrorMessage().c_str()); + Log(Logs::Detail, Logs::QS_Server, "%s", query.c_str()); + } + + if (QS->_detail_count == 0) + return; + + int lastIndex = results.LastInsertedID(); + + for (int i = 0; i < QS->_detail_count; i++) { + query = StringFormat("INSERT INTO `qs_player_drop_record_entries` SET `event_id` = '%i', " + "`item_id` = '%i', `charges` = '%i', `aug_1` = '%i', `aug_2` = '%i', " + "`aug_3` = '%i', `aug_4` = '%i', `aug_5` = '%i'", + lastIndex, QS->items[i].item_id, + QS->items[i].charges, QS->items[i].aug_1, QS->items[i].aug_2, + QS->items[i].aug_3, QS->items[i].aug_4, QS->items[i].aug_5); + results = QueryDatabase(query); + if (!results.Success()) { + Log(Logs::Detail, Logs::QS_Server, "Failed Drop Record Entry Insert: %s", results.ErrorMessage().c_str()); + Log(Logs::Detail, Logs::QS_Server, "%s", query.c_str()); + } + } +} + void Database::LogPlayerTrade(QSPlayerLogTrade_Struct* QS, uint32 detailCount) { std::string query = StringFormat("INSERT INTO `qs_player_trade_record` SET `time` = NOW(), " diff --git a/queryserv/database.h b/queryserv/database.h index b2d32341b..13815c575 100644 --- a/queryserv/database.h +++ b/queryserv/database.h @@ -45,6 +45,7 @@ public: void AddSpeech(const char* from, const char* to, const char* message, uint16 minstatus, uint32 guilddbid, uint8 type); void LogPlayerTrade(QSPlayerLogTrade_Struct* QS, uint32 DetailCount); + void LogPlayerDropItem(QSPlayerDropItem_Struct* QS); void LogPlayerHandin(QSPlayerLogHandin_Struct* QS, uint32 DetailCount); void LogPlayerNPCKill(QSPlayerLogNPCKill_Struct* QS, uint32 Members); void LogPlayerDelete(QSPlayerLogDelete_Struct* QS, uint32 Items); diff --git a/queryserv/worldserver.cpp b/queryserv/worldserver.cpp index 686c92326..a03d23b1e 100644 --- a/queryserv/worldserver.cpp +++ b/queryserv/worldserver.cpp @@ -98,6 +98,11 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) database.LogPlayerTrade(QS, QS->_detail_count); break; } + case ServerOP_QSPlayerDropItem: { + QSPlayerDropItem_Struct *QS = (QSPlayerDropItem_Struct *) p.Data(); + database.LogPlayerDropItem(QS); + break; + } case ServerOP_QSPlayerLogHandins: { QSPlayerLogHandin_Struct *QS = (QSPlayerLogHandin_Struct*)p.Data(); database.LogPlayerHandin(QS, QS->_detail_count); diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index 263aeee2f..7d638d100 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -1295,6 +1295,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) { case ServerOP_QSPlayerLogDeletes: case ServerOP_QSPlayerLogMoves: case ServerOP_QSPlayerLogMerchantTransactions: + case ServerOP_QSPlayerDropItem: { QSLink.SendPacket(pack); break; diff --git a/zone/client.h b/zone/client.h index ead552f73..393ede129 100644 --- a/zone/client.h +++ b/zone/client.h @@ -876,6 +876,7 @@ public: void SetStats(uint8 type,int16 set_val); void IncStats(uint8 type,int16 increase_val); void DropItem(int16 slot_id, bool recurse = true); + void DropItemQS(EQEmu::ItemInstance* inst, bool pickup); int GetItemLinkHash(const EQEmu::ItemInstance* inst); // move to ItemData..or make use of the pre-calculated database field diff --git a/zone/inventory.cpp b/zone/inventory.cpp index d375d94b6..902268e2c 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -688,10 +688,79 @@ void Client::DropItem(int16 slot_id, bool recurse) object->StartDecay(); Log(Logs::General, Logs::Inventory, "Item drop handled ut assolet"); + DropItemQS(inst, false); safe_delete(inst); } +void Client::DropItemQS(EQEmu::ItemInstance* inst, bool pickup) { + if (RuleB(QueryServ, PlayerDropItems)) { + QSPlayerDropItem_Struct qs_audit; + std::list event_details; + memset(&qs_audit, 0, sizeof(QSPlayerDropItem_Struct)); + + qs_audit.char_id = this->character_id; + qs_audit.pickup = pickup; + qs_audit.zone_id = this->GetZoneID(); + qs_audit.x = (int) this->GetX(); + qs_audit.y = (int) this->GetY(); + qs_audit.z = (int) this->GetZ(); + + if (inst) { + auto detail = new QSDropItems_Struct; + detail->item_id = inst->GetID(); + detail->charges = inst->IsClassBag() ? 1 : inst->GetCharges(); + detail->aug_1 = inst->GetAugmentItemID(1); + detail->aug_2 = inst->GetAugmentItemID(2); + detail->aug_3 = inst->GetAugmentItemID(3); + detail->aug_4 = inst->GetAugmentItemID(4); + detail->aug_5 = inst->GetAugmentItemID(5); + event_details.push_back(detail); + + if (inst->IsClassBag()) { + for (uint8 sub_slot = EQEmu::invbag::SLOT_BEGIN; (sub_slot <= EQEmu::invbag::SLOT_END); ++sub_slot) { // this is to catch ALL items + const EQEmu::ItemInstance* bag_inst = inst->GetItem(sub_slot); + if (bag_inst) { + detail = new QSDropItems_Struct; + detail->item_id = bag_inst->GetID(); + detail->charges = (!bag_inst->IsStackable() ? 1 : bag_inst->GetCharges()); + detail->aug_1 = bag_inst->GetAugmentItemID(1); + detail->aug_2 = bag_inst->GetAugmentItemID(2); + detail->aug_3 = bag_inst->GetAugmentItemID(3); + detail->aug_4 = bag_inst->GetAugmentItemID(4); + detail->aug_5 = bag_inst->GetAugmentItemID(5); + event_details.push_back(detail); + } + } + } + } + qs_audit._detail_count = event_details.size(); + + auto qs_pack = new ServerPacket( + ServerOP_QSPlayerDropItem, + sizeof(QSPlayerDropItem_Struct) + + (sizeof(QSDropItems_Struct) * qs_audit._detail_count)); + QSPlayerDropItem_Struct* qs_buf = (QSPlayerDropItem_Struct*) qs_pack->pBuffer; + + memcpy(qs_buf, &qs_audit, sizeof(QSPlayerDropItem_Struct)); + + int offset = 0; + + for (auto iter = event_details.begin(); iter != event_details.end(); ++iter, ++offset) { + QSDropItems_Struct* detail = reinterpret_cast(*iter); + qs_buf->items[offset] = *detail; + safe_delete(detail); + } + + event_details.clear(); + + if (worldserver.Connected()) + worldserver.SendPacket(qs_pack); + + safe_delete(qs_pack); + } +} + // Drop inst void Client::DropInst(const EQEmu::ItemInstance* inst) { diff --git a/zone/object.cpp b/zone/object.cpp index 3ad4a6a9c..4306c6642 100644 --- a/zone/object.cpp +++ b/zone/object.cpp @@ -528,6 +528,8 @@ bool Object::HandleClick(Client* sender, const ClickObject_Struct* click_object) if(cursordelete) // delete the item if it's a duplicate lore. We have to do this because the client expects the item packet sender->DeleteItemInInventory(EQEmu::invslot::slotCursor); + sender->DropItemQS(m_inst, true); + if(!m_ground_spawn) safe_delete(m_inst); From 483b4724e5f30e667bfeb4bec9007500a276add1 Mon Sep 17 00:00:00 2001 From: Trust Date: Sun, 22 Jul 2018 16:38:45 -0400 Subject: [PATCH 03/44] [Exploit] Prevent low level mez testing without aggro. Using low level mez to test if a mob is mezzable and NOT get aggro has been squashed. When you cast you will get 1 point of aggro on a Cannot mez with this spell. --- zone/spells.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/zone/spells.cpp b/zone/spells.cpp index 8f8cfba33..a0b149a8d 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -4247,6 +4247,7 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster) { Log(Logs::Detail, Logs::Spells, "Our level (%d) is higher than the limit of this Mez spell (%d)", GetLevel(), spells[spell_id].max[effect_index]); caster->Message_StringID(MT_Shout, CANNOT_MEZ_WITH_SPELL); + AddToHateList(caster, 1,0,true,false,false,spell_id); return true; } } From 6b02d50a8c4a1193410ee9d34911a7e7f1ca5cd5 Mon Sep 17 00:00:00 2001 From: Trust Date: Sun, 22 Jul 2018 18:22:07 -0400 Subject: [PATCH 04/44] Allow Separate GrayCon Flee rate. Added following Rules: Combat:FleeGray - If true FleeGrayHPRatio will be used. Combat:FleeGrayHPRatio - HP % when a Gray NPC begins to flee. --- common/ruletypes.h | 2 + zone/aggro.cpp | 23 +++++----- zone/entity.h | 2 +- zone/fearpath.cpp | 102 +++++++++++++++++++++++++++++---------------- zone/merc.cpp | 2 +- 5 files changed, 83 insertions(+), 48 deletions(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index c89213368..b1bba0423 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -419,6 +419,8 @@ RULE_BOOL(Combat, UseIntervalAC, true) RULE_INT(Combat, PetAttackMagicLevel, 30) RULE_BOOL(Combat, EnableFearPathing, true) RULE_REAL(Combat, FleeMultiplier, 2.0) // Determines how quickly a NPC will slow down while fleeing. Decrease multiplier to slow NPC down quicker. +RULE_BOOL(Combat, FleeGray, true) // If true FleeGrayHPRatio will be used. +RULE_INT(Combat, FleeGrayHPRatio, 50) //HP % when a Gray NPC begins to flee. RULE_INT(Combat, FleeHPRatio, 25) //HP % when a NPC begins to flee. RULE_BOOL(Combat, FleeIfNotAlone, false) // If false, mobs won't flee if other mobs are in combat with it. RULE_BOOL(Combat, AdjustProcPerMinute, true) diff --git a/zone/aggro.cpp b/zone/aggro.cpp index 91d14498f..f8162322e 100644 --- a/zone/aggro.cpp +++ b/zone/aggro.cpp @@ -424,7 +424,7 @@ Mob* EntityList::AICheckNPCtoNPCAggro(Mob* sender, float iAggroRange, float iAss return nullptr; } -int EntityList::GetHatedCount(Mob *attacker, Mob *exclude) +int EntityList::GetHatedCount(Mob *attacker, Mob *exclude, bool inc_gray_con) { // Return a list of how many non-feared, non-mezzed, non-green mobs, within aggro range, hate *attacker if (!attacker) @@ -434,20 +434,25 @@ int EntityList::GetHatedCount(Mob *attacker, Mob *exclude) for (auto it = npc_list.begin(); it != npc_list.end(); ++it) { NPC *mob = it->second; - if (!mob || (mob == exclude)) + if (!mob || (mob == exclude)) { continue; + } - if (!mob->IsEngaged()) + if (!mob->IsEngaged()) { continue; + } - if (mob->IsFeared() || mob->IsMezzed()) + if (mob->IsFeared() || mob->IsMezzed()) { continue; + } - if (attacker->GetLevelCon(mob->GetLevel()) == CON_GRAY) + if (!inc_gray_con && attacker->GetLevelCon(mob->GetLevel()) == CON_GRAY) { continue; + } - if (!mob->CheckAggro(attacker)) + if (!mob->CheckAggro(attacker)) { continue; + } float AggroRange = mob->GetAggroRange(); @@ -455,14 +460,12 @@ int EntityList::GetHatedCount(Mob *attacker, Mob *exclude) AggroRange *= AggroRange; - if (DistanceSquared(mob->GetPosition(), attacker->GetPosition()) > AggroRange) + if (DistanceSquared(mob->GetPosition(), attacker->GetPosition()) > AggroRange) { continue; - + } Count++; } - return Count; - } void EntityList::AIYellForHelp(Mob* sender, Mob* attacker) { diff --git a/zone/entity.h b/zone/entity.h index f296a8cb4..f32532392 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -416,7 +416,7 @@ public: void CheckClientAggro(Client *around); Mob* AICheckNPCtoNPCAggro(Mob* sender, float iAggroRange, float iAssistRange); - int GetHatedCount(Mob *attacker, Mob *exclude); + int GetHatedCount(Mob *attacker, Mob *exclude, bool inc_gray_con); void AIYellForHelp(Mob* sender, Mob* attacker); bool AICheckCloseBeneficialSpells(NPC* caster, uint8 iChance, float iRange, uint32 iSpellTypes); bool Merc_AICheckCloseBeneficialSpells(Merc* caster, uint8 iChance, float iRange, uint32 iSpellTypes); diff --git a/zone/fearpath.cpp b/zone/fearpath.cpp index 0593cbee2..722e1e417 100644 --- a/zone/fearpath.cpp +++ b/zone/fearpath.cpp @@ -31,87 +31,117 @@ extern Zone* zone; //this is called whenever we are damaged to process possible fleeing void Mob::CheckFlee() { - //if were allready fleeing, dont need to check more... - if(flee_mode && currently_fleeing) + + // if mob is dead why would you run? + if(GetHP() == 0) { return; + } + + // if were already fleeing, don't need to check more... + if(flee_mode && currently_fleeing) { + return; + } //dont bother if we are immune to fleeing - if(GetSpecialAbility(IMMUNE_FLEEING) || spellbonuses.ImmuneToFlee) + if(GetSpecialAbility(IMMUNE_FLEEING) || spellbonuses.ImmuneToFlee) { return; + } - if(!flee_timer.Check()) - return; //only do all this stuff every little while, since - //its not essential that we start running RIGHT away - - //see if were possibly hurt enough - float ratio = GetHPRatio(); - float fleeratio = GetSpecialAbility(FLEE_PERCENT); - fleeratio = fleeratio > 0 ? fleeratio : RuleI(Combat, FleeHPRatio); - - if(ratio >= fleeratio) + // Check if Flee Timer is cleared + if(!flee_timer.Check()) { return; + } - //we might be hurt enough, check con now.. + int hpratio = GetIntHPRatio(); + int fleeratio = GetSpecialAbility(FLEE_PERCENT); // if a special flee_percent exists Mob *hate_top = GetHateTop(); + + // Sanity Check for race conditions + if(hate_top == nullptr) { + return; + } + + // If no special flee_percent check for Gray or Other con rates + if(GetLevelCon(hate_top->GetLevel(), GetLevel()) == CON_GRAY && fleeratio == 0 && RuleB(Combat, FleeGray)) { + fleeratio = RuleI(Combat, FleeGrayHPRatio); + } else if(fleeratio == 0) { + fleeratio = RuleI(Combat, FleeHPRatio ); + } + + // Mob does not have low enough health to flee + if(hpratio >= fleeratio) { + return; + } + + // Sanity Check this should never happen... if(!hate_top) { - //this should never happen... StartFleeing(); return; } - float other_ratio = hate_top->GetHPRatio(); + int other_ratio = hate_top->GetIntHPRatio(); + // If the Client is nearing death the NPC will not flee and instead try to kill the client. if(other_ratio < 20) { - //our hate top is almost dead too... stay and fight return; } - //base our flee ratio on our con. this is how the - //attacker sees the mob, since this is all we can observe + // Flee Chance checking based on con. uint32 con = GetLevelCon(hate_top->GetLevel(), GetLevel()); - float run_ratio; + int flee_chance; switch(con) { //these values are not 100% researched case CON_GRAY: - run_ratio = fleeratio; + flee_chance = 100; break; case CON_GREEN: - run_ratio = fleeratio * 9 / 10; + flee_chance = 90; break; case CON_LIGHTBLUE: - run_ratio = fleeratio * 9 / 10; + flee_chance = 90; break; case CON_BLUE: - run_ratio = fleeratio * 8 / 10; + flee_chance = 80; break; default: - run_ratio = fleeratio * 7 / 10; + flee_chance = 70; break; } - if(ratio < run_ratio) - { - if (RuleB(Combat, FleeIfNotAlone) || - GetSpecialAbility(ALWAYS_FLEE) || - (!RuleB(Combat, FleeIfNotAlone) && (entity_list.GetHatedCount(hate_top, this) == 0))) - StartFleeing(); + + // If we got here we are allowed to roll on flee chance if there is not other hated NPC's in the area. + + if(RuleB(Combat, FleeIfNotAlone) || GetSpecialAbility(ALWAYS_FLEE) || zone->random.Roll(flee_chance) && entity_list.GetHatedCount(hate_top, this, true) == 0) { + currently_fleeing = true; + StartFleeing(); } } + void Mob::ProcessFlee() { //Stop fleeing if effect is applied after they start to run. //When ImmuneToFlee effect fades it will turn fear back on and check if it can still flee. if (flee_mode && (GetSpecialAbility(IMMUNE_FLEEING) || spellbonuses.ImmuneToFlee) && - !spellbonuses.IsFeared && !spellbonuses.IsBlind) { + !spellbonuses.IsFeared && !spellbonuses.IsBlind) { currently_fleeing = false; return; } - //see if we are still dying, if so, do nothing - float fleeratio = GetSpecialAbility(FLEE_PERCENT); - fleeratio = fleeratio > 0 ? fleeratio : RuleI(Combat, FleeHPRatio); - if (GetHPRatio() < fleeratio) + int hpratio = GetIntHPRatio(); + int fleeratio = GetSpecialAbility(FLEE_PERCENT); // if a special flee_percent exists + Mob *hate_top = GetHateTop(); + + // If no special flee_percent check for Gray or Other con rates + if(GetLevelCon(hate_top->GetLevel(), GetLevel()) == CON_GRAY && fleeratio == 0 && RuleB(Combat, FleeGray)) { + fleeratio = RuleI(Combat, FleeGrayHPRatio); + } else if(fleeratio == 0) { + fleeratio = RuleI(Combat, FleeHPRatio ); + } + + // Mob is still too low. Keep Running + if(hpratio < fleeratio) { return; + } //we are not dying anymore... see what we do next diff --git a/zone/merc.cpp b/zone/merc.cpp index a32fab994..c635b43ea 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -1414,7 +1414,7 @@ void Merc::AI_Process() { if(DivineAura()) return; - int hateCount = entity_list.GetHatedCount(this, nullptr); + int hateCount = entity_list.GetHatedCount(this, nullptr, false); if(GetHatedCount() < hateCount) { SetHatedCount(hateCount); From 1bba629514d6398fcd025f78ac5edbd2764dbedc Mon Sep 17 00:00:00 2001 From: Trust Date: Sun, 22 Jul 2018 18:35:50 -0400 Subject: [PATCH 05/44] Prevent Low Level Charm testing without Aggro --- zone/spells.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/zone/spells.cpp b/zone/spells.cpp index a0b149a8d..60591b7b1 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -4339,6 +4339,7 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster) { Log(Logs::Detail, Logs::Spells, "Our level (%d) is higher than the limit of this Charm spell (%d)", GetLevel(), spells[spell_id].max[effect_index]); caster->Message_StringID(MT_Shout, CANNOT_CHARM_YET); + AddToHateList(caster, 1,0,true,false,false,spell_id); return true; } } From 8b2ec7560a0f72d9e79d22ebee8b855e41565773 Mon Sep 17 00:00:00 2001 From: Trust Date: Sat, 4 Aug 2018 15:26:21 -0400 Subject: [PATCH 06/44] editorconfig --- .editorconfig | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..03f782494 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,23 @@ +# EditorConfig is awesome: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true + +# Matches multiple files with brace expansion notation +# Set default charset +[*.{js,py}] +charset = utf-8 + +[*.cpp] +indent_style = tab +[*.h] +indent_style = tab + +# Tab indentation (no size specified) +[Makefile] +indent_style = tab \ No newline at end of file From bf5c5b803eb7593b9ba236d973791befa7df5d6a Mon Sep 17 00:00:00 2001 From: Xackery Date: Sun, 5 Aug 2018 17:12:46 -0700 Subject: [PATCH 07/44] Adjusted zlib cmake to honor policy CMP0074 warning --- CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 817af542c..360d16a0e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,7 +54,8 @@ ENDIF(MSVC OR MINGW) IF(MSVC) IF(CMAKE_CL_64) - SET(ZLIB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x64") + SET(ZLIB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x64/include") + SET(ZLIB_LIBRARY "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x64/lib/zlib.lib") SET(MYSQL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/mysql_x64") SET(LUA_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/luaj_x64") SET(OPENSSL_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/openssl_x64") @@ -67,7 +68,8 @@ IF(MSVC) SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/x64/Release/v110/dynamic") ENDIF() ELSE(CMAKE_CL_64) - SET(ZLIB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x86") + SET(ZLIB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x86/include") + SET(ZLIB_LIBRARY "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x86/lib/zlib.lib") SET(MYSQL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/mysql_x86") SET(LUA_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/luaj_x86") SET(SODIUM_INCLUDE_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/include") From 585ef81fdeef3bc85c101d6f98995c6970206455 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Wed, 15 Aug 2018 21:35:19 -0400 Subject: [PATCH 08/44] Fix lua raid GetGroup(client) and add lua raid GetGroupNumber(index) This number will return group number and not let us iterate a bunch of times to verify group numbers --- zone/lua_raid.cpp | 14 +++++++++++++- zone/lua_raid.h | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/zone/lua_raid.cpp b/zone/lua_raid.cpp index 295fe0220..38ffb28d5 100644 --- a/zone/lua_raid.cpp +++ b/zone/lua_raid.cpp @@ -122,6 +122,16 @@ Lua_Client Lua_Raid::GetMember(int index) { return self->members[index].member; } +int Lua_Raid::GetGroupNumber(int index) { + Lua_Safe_Call_Int(); + + if(index >= 72 || index < 0 || self->members[index].GroupNumber == RAID_GROUPLESS) { + return -1; + } + + return self->members[index].GroupNumber; +} + luabind::scope lua_register_raid() { return luabind::class_("Raid") @@ -133,6 +143,7 @@ luabind::scope lua_register_raid() { .def("GroupCount", (int(Lua_Raid::*)(uint32))&Lua_Raid::GroupCount) .def("RaidCount", (int(Lua_Raid::*)(void))&Lua_Raid::RaidCount) .def("GetGroup", (uint32(Lua_Raid::*)(const char*))&Lua_Raid::GetGroup) + .def("GetGroup", (uint32(Lua_Raid::*)(Lua_Client))&Lua_Raid::GetGroup) .def("SplitExp", (void(Lua_Raid::*)(uint32,Lua_Mob))&Lua_Raid::SplitExp) .def("GetTotalRaidDamage", (uint32(Lua_Raid::*)(Lua_Mob))&Lua_Raid::GetTotalRaidDamage) .def("SplitMoney", (void(Lua_Raid::*)(uint32,uint32,uint32,uint32))&Lua_Raid::SplitMoney) @@ -146,7 +157,8 @@ luabind::scope lua_register_raid() { .def("TeleportGroup", (int(Lua_Raid::*)(Lua_Mob,uint32,uint32,float,float,float,float,uint32))&Lua_Raid::TeleportGroup) .def("TeleportRaid", (int(Lua_Raid::*)(Lua_Mob,uint32,uint32,float,float,float,float))&Lua_Raid::TeleportRaid) .def("GetID", (int(Lua_Raid::*)(void))&Lua_Raid::GetID) - .def("GetMember", (Lua_Client(Lua_Raid::*)(int))&Lua_Raid::GetMember); + .def("GetMember", (Lua_Client(Lua_Raid::*)(int))&Lua_Raid::GetMember) + .def("GetGroupNumber", (int(Lua_Raid::*)(int))&Lua_Raid::GetGroupNumber); } #endif diff --git a/zone/lua_raid.h b/zone/lua_raid.h index cc88a1c3d..eb7a67e24 100644 --- a/zone/lua_raid.h +++ b/zone/lua_raid.h @@ -47,6 +47,7 @@ public: void TeleportRaid(Lua_Mob sender, uint32 zone_id, uint32 instance_id, float x, float y, float z, float h); int GetID(); Lua_Client GetMember(int index); + int GetGroupNumber(int index); }; #endif From 30148c3c567a4d79e7c0eee37ed408686702f3e7 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 16 Aug 2018 13:01:19 -0400 Subject: [PATCH 09/44] AE rampage shouldn't hit target --- zone/hate_list.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/hate_list.cpp b/zone/hate_list.cpp index f02cbe6b6..8ddd89079 100644 --- a/zone/hate_list.cpp +++ b/zone/hate_list.cpp @@ -580,7 +580,7 @@ int HateList::AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOption // This is a temp solution until the hate lists can be rewritten to not have that issue std::vector id_list; for (auto &h : list) { - if (h->entity_on_hatelist && h->entity_on_hatelist != caster && + if (h->entity_on_hatelist && h->entity_on_hatelist != caster && h->entity_on_hatelist != target && caster->CombatRange(h->entity_on_hatelist)) id_list.push_back(h->entity_on_hatelist->GetID()); if (count != -1 && id_list.size() > count) From ffb9323a98044124f79858c9ca579e94912fd9bf Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 16 Aug 2018 13:18:00 -0400 Subject: [PATCH 10/44] Revert "AE rampage shouldn't hit target" This reverts commit 30148c3c567a4d79e7c0eee37ed408686702f3e7. Was thinking of wrong thing ... logs say otherwise :P --- zone/hate_list.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/hate_list.cpp b/zone/hate_list.cpp index 8ddd89079..f02cbe6b6 100644 --- a/zone/hate_list.cpp +++ b/zone/hate_list.cpp @@ -580,7 +580,7 @@ int HateList::AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOption // This is a temp solution until the hate lists can be rewritten to not have that issue std::vector id_list; for (auto &h : list) { - if (h->entity_on_hatelist && h->entity_on_hatelist != caster && h->entity_on_hatelist != target && + if (h->entity_on_hatelist && h->entity_on_hatelist != caster && caster->CombatRange(h->entity_on_hatelist)) id_list.push_back(h->entity_on_hatelist->GetID()); if (count != -1 && id_list.size() > count) From ace81215a1964f9fe7e89abf9e24b6bb0a345f84 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 16 Aug 2018 17:13:34 -0400 Subject: [PATCH 11/44] Correct when tanks can be hit by AE Rampage Tanks will only be hit by AE Rampage if they're the only one on the NPC's hate list. Others on hate list out ranging AE Rampage will also prevent the tank from being hit by AE Rampage. --- zone/hate_list.cpp | 9 ++++++++- zone/mob_ai.cpp | 2 -- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/zone/hate_list.cpp b/zone/hate_list.cpp index f02cbe6b6..5649c0da4 100644 --- a/zone/hate_list.cpp +++ b/zone/hate_list.cpp @@ -575,12 +575,19 @@ int HateList::AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOption if (!target || !caster) return 0; + // tank will be hit ONLY if they are the only target on the hate list + // if there is anyone else on the hate list, the tank will not be hit, even if those others aren't hit either + if (list.size() == 1) { + caster->ProcessAttackRounds(target, opts); + return 1; + } + int hit_count = 0; // This should prevent crashes if something dies (or mainly more than 1 thing goes away) // This is a temp solution until the hate lists can be rewritten to not have that issue std::vector id_list; for (auto &h : list) { - if (h->entity_on_hatelist && h->entity_on_hatelist != caster && + if (h->entity_on_hatelist && h->entity_on_hatelist != caster && h->entity_on_hatelist != target && caster->CombatRange(h->entity_on_hatelist)) id_list.push_back(h->entity_on_hatelist->GetID()); if (count != -1 && id_list.size() > count) diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 154575c40..e769bda95 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -2255,8 +2255,6 @@ void Mob::AreaRampage(ExtraAttackOptions *opts) m_specialattacks = eSpecialAttacks::AERampage; index_hit = hate_list.AreaRampage(this, GetTarget(), rampage_targets, opts); - if(index_hit == 0) - ProcessAttackRounds(GetTarget(), opts); m_specialattacks = eSpecialAttacks::None; } From 7cc5b143fca9077c144f158952c0dbb11fb10d80 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 16 Aug 2018 22:33:07 -0400 Subject: [PATCH 12/44] Make lua raid GetGroup functions signed The server code is unsigned for bad reasons :P --- zone/lua_raid.cpp | 8 ++++---- zone/lua_raid.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/zone/lua_raid.cpp b/zone/lua_raid.cpp index 38ffb28d5..93c1f4c28 100644 --- a/zone/lua_raid.cpp +++ b/zone/lua_raid.cpp @@ -32,12 +32,12 @@ int Lua_Raid::RaidCount() { return self->RaidCount(); } -uint32 Lua_Raid::GetGroup(const char *c) { +int Lua_Raid::GetGroup(const char *c) { Lua_Safe_Call_Int(); return self->GetGroup(c); } -uint32 Lua_Raid::GetGroup(Lua_Client c) { +int Lua_Raid::GetGroup(Lua_Client c) { Lua_Safe_Call_Int(); return self->GetGroup(c); } @@ -142,8 +142,8 @@ luabind::scope lua_register_raid() { .def("CastGroupSpell", (void(Lua_Raid::*)(Lua_Mob,int,uint32))&Lua_Raid::CastGroupSpell) .def("GroupCount", (int(Lua_Raid::*)(uint32))&Lua_Raid::GroupCount) .def("RaidCount", (int(Lua_Raid::*)(void))&Lua_Raid::RaidCount) - .def("GetGroup", (uint32(Lua_Raid::*)(const char*))&Lua_Raid::GetGroup) - .def("GetGroup", (uint32(Lua_Raid::*)(Lua_Client))&Lua_Raid::GetGroup) + .def("GetGroup", (int(Lua_Raid::*)(const char*))&Lua_Raid::GetGroup) + .def("GetGroup", (int(Lua_Raid::*)(Lua_Client))&Lua_Raid::GetGroup) .def("SplitExp", (void(Lua_Raid::*)(uint32,Lua_Mob))&Lua_Raid::SplitExp) .def("GetTotalRaidDamage", (uint32(Lua_Raid::*)(Lua_Mob))&Lua_Raid::GetTotalRaidDamage) .def("SplitMoney", (void(Lua_Raid::*)(uint32,uint32,uint32,uint32))&Lua_Raid::SplitMoney) diff --git a/zone/lua_raid.h b/zone/lua_raid.h index eb7a67e24..626b98bb2 100644 --- a/zone/lua_raid.h +++ b/zone/lua_raid.h @@ -30,8 +30,8 @@ public: void CastGroupSpell(Lua_Mob caster, int spell_id, uint32 group_id); int GroupCount(uint32 group_id); int RaidCount(); - uint32 GetGroup(const char *c); - uint32 GetGroup(Lua_Client c); + int GetGroup(const char *c); + int GetGroup(Lua_Client c); void SplitExp(uint32 exp, Lua_Mob other); uint32 GetTotalRaidDamage(Lua_Mob other); void SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum); From 4b6ab34fd9a04cba18dac9d2da6e6d99721c602c Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sat, 18 Aug 2018 18:12:18 -0500 Subject: [PATCH 13/44] Fix, cleanup and simplify the roambox logic and cleanup a bunch of other related code --- common/eqemu_logsys.h | 4 +- zone/entity.cpp | 36 ++-- zone/merc.cpp | 12 +- zone/mob.h | 8 +- zone/mob_ai.cpp | 491 +++++++++++++++++++++--------------------- zone/npc.cpp | 4 +- zone/npc.h | 18 +- zone/spawn2.cpp | 172 ++++++++++----- zone/waypoints.cpp | 130 ++++++----- 9 files changed, 479 insertions(+), 396 deletions(-) diff --git a/common/eqemu_logsys.h b/common/eqemu_logsys.h index a54edc234..b0afa72f2 100644 --- a/common/eqemu_logsys.h +++ b/common/eqemu_logsys.h @@ -90,6 +90,7 @@ enum LogCategory { FixZ, Food, Traps, + NPCRoamBox, MaxCategoryID /* Don't Remove this*/ }; @@ -144,7 +145,8 @@ static const char* LogCategoryName[LogCategory::MaxCategoryID] = { "HP Update", "FixZ", "Food", - "Traps" + "Traps", + "NPC Roam Box" }; } diff --git a/zone/entity.cpp b/zone/entity.cpp index 264b8cfc9..f61acda94 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -3425,52 +3425,54 @@ void EntityList::ProcessMove(Client *c, const glm::vec3& location) } } -void EntityList::ProcessMove(NPC *n, float x, float y, float z) -{ +void EntityList::ProcessMove(NPC *n, float x, float y, float z) { float last_x = n->GetX(); float last_y = n->GetY(); float last_z = n->GetZ(); std::list events; + for (auto iter = area_list.begin(); iter != area_list.end(); ++iter) { - Area& a = (*iter); + + Area &a = (*iter); bool old_in = true; bool new_in = true; if (last_x < a.min_x || last_x > a.max_x || - last_y < a.min_y || last_y > a.max_y || - last_z < a.min_z || last_z > a.max_z) { + last_y < a.min_y || last_y > a.max_y || + last_z < a.min_z || last_z > a.max_z) { old_in = false; } if (x < a.min_x || x > a.max_x || - y < a.min_y || y > a.max_y || - z < a.min_z || z > a.max_z) { + y < a.min_y || y > a.max_y || + z < a.min_z || z > a.max_z) { new_in = false; } if (old_in && !new_in) { //were in but are no longer. quest_proximity_event evt; - evt.event_id = EVENT_LEAVE_AREA; - evt.client = nullptr; - evt.npc = n; - evt.area_id = a.id; + evt.event_id = EVENT_LEAVE_AREA; + evt.client = nullptr; + evt.npc = n; + evt.area_id = a.id; evt.area_type = a.type; events.push_back(evt); - } else if (!old_in && new_in) { + } + else if (!old_in && new_in) { //were not in but now are quest_proximity_event evt; - evt.event_id = EVENT_ENTER_AREA; - evt.client = nullptr; - evt.npc = n; - evt.area_id = a.id; + evt.event_id = EVENT_ENTER_AREA; + evt.client = nullptr; + evt.npc = n; + evt.area_id = a.id; evt.area_type = a.type; events.push_back(evt); } } for (auto iter = events.begin(); iter != events.end(); ++iter) { - quest_proximity_event& evt = (*iter); + quest_proximity_event &evt = (*iter); std::vector args; args.push_back(&evt.area_id); args.push_back(&evt.area_type); diff --git a/zone/merc.cpp b/zone/merc.cpp index 82d66878a..834b96e44 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -1481,8 +1481,14 @@ void Merc::AI_Process() { if (RuleB(Mercs, MercsUsePathing) && zone->pathing) { bool WaypointChanged, NodeReached; - glm::vec3 Goal = UpdatePath(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), - GetRunspeed(), WaypointChanged, NodeReached); + glm::vec3 Goal = UpdatePath( + GetTarget()->GetX(), + GetTarget()->GetY(), + GetTarget()->GetZ(), + GetRunspeed(), + WaypointChanged, + NodeReached + ); if (WaypointChanged) tar_ndx = 20; @@ -1588,7 +1594,7 @@ void Merc::AI_Process() { } } - if(IsMoving()) + if (IsMoving()) SendPositionUpdate(); else SendPosition(); diff --git a/zone/mob.h b/zone/mob.h index 422c76cd3..bdfbd31bc 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -981,7 +981,7 @@ public: inline bool CheckAggro(Mob* other) {return hate_list.IsEntOnHateList(other);} float CalculateHeadingToTarget(float in_x, float in_y) { return HeadingAngleToMob(in_x, in_y); } - virtual bool CalculateNewPosition(float x, float y, float z, int speed, bool checkZ = true, bool calcheading = true); + virtual bool CalculateNewPosition(float x, float y, float z, float speed, bool check_z = true, bool calculate_heading = true); float CalculateDistance(float x, float y, float z); float GetGroundZ(float new_x, float new_y, float z_offset=0.0); void SendTo(float new_x, float new_y, float new_z); @@ -989,7 +989,7 @@ public: float GetZOffset() const; float GetDefaultRaceSize() const; void FixZ(int32 z_find_offset = 5); - float GetFixedZ(glm::vec3 position, int32 z_find_offset = 5); + float GetFixedZ(glm::vec3 destination, int32 z_find_offset = 5); void NPCSpecialAttacks(const char* parse, int permtag, bool reset = true, bool remove = false); inline uint32 DontHealMeBefore() const { return pDontHealMeBefore; } @@ -1165,7 +1165,7 @@ protected: int _GetWalkSpeed() const; int _GetRunSpeed() const; int _GetFearSpeed() const; - virtual bool MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, bool checkZ = true, bool calcHeading = true); + virtual bool MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, bool check_z = true, bool calculate_heading = true); virtual bool AI_EngagedCastCheck() { return(false); } virtual bool AI_PursueCastCheck() { return(false); } @@ -1443,7 +1443,7 @@ protected: std::unique_ptr AI_feign_remember_timer; std::unique_ptr AI_check_signal_timer; std::unique_ptr AI_scan_door_open_timer; - uint32 pLastFightingDelayMoving; + uint32 time_until_can_move; HateList hate_list; std::set feign_memory_list; // This is to keep track of mobs we cast faction mod spells on diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index e769bda95..0579fd60d 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -30,6 +30,7 @@ #include "string_ids.h" #include "water_map.h" #include "fastmath.h" +#include "../common/data_verification.h" #include #include @@ -459,8 +460,8 @@ void NPC::AI_Init() roambox_min_x = 0; roambox_min_y = 0; roambox_distance = 0; - roambox_movingto_x = 0; - roambox_movingto_y = 0; + roambox_destination_x = 0; + roambox_destination_y = 0; roambox_min_delay = 2500; roambox_delay = 2500; } @@ -476,9 +477,9 @@ void Mob::AI_Start(uint32 iMoveDelay) { return; if (iMoveDelay) - pLastFightingDelayMoving = Timer::GetCurrentTime() + iMoveDelay; + time_until_can_move = Timer::GetCurrentTime() + iMoveDelay; else - pLastFightingDelayMoving = 0; + time_until_can_move = 0; pAIControlled = true; AI_think_timer = std::unique_ptr(new Timer(AIthink_duration)); @@ -1053,7 +1054,7 @@ void Mob::AI_Process() { if (IsCasting()) return; - bool engaged = IsEngaged(); + bool engaged = IsEngaged(); bool doranged = false; if (!zone->CanDoCombat() || IsPetStop() || IsPetRegroup()) { @@ -1063,7 +1064,7 @@ void Mob::AI_Process() { if (moving) { if (AI_scan_door_open_timer->Check()) { - auto &door_list = entity_list.GetDoorsList(); + auto &door_list = entity_list.GetDoorsList(); for (auto itr : door_list) { Doors *door = itr.second; @@ -1096,39 +1097,46 @@ void Mob::AI_Process() { // Begin: Additions for Wiz Fear Code // - if(RuleB(Combat, EnableFearPathing)){ - if(currently_fleeing) { - if((IsRooted() || (IsBlind() && CombatRange(hate_list.GetClosestEntOnHateList(this)))) && !IsPetStop() && !IsPetRegroup()) { + if (RuleB(Combat, EnableFearPathing)) { + if (currently_fleeing) { + if ((IsRooted() || (IsBlind() && CombatRange(hate_list.GetClosestEntOnHateList(this)))) && !IsPetStop() && + !IsPetRegroup()) { //make sure everybody knows were not moving, for appearance sake - if(IsMoving()) - { - if(target) + if (IsMoving()) { + if (target) SetHeading(CalculateHeadingToTarget(target->GetX(), target->GetY())); SetCurrentSpeed(0); - moved=false; + moved = false; } //continue on to attack code, ensuring that we execute the engaged code engaged = true; - } else { - if(AI_movement_timer->Check()) { + } + else { + if (AI_movement_timer->Check()) { // Check if we have reached the last fear point if ((std::abs(GetX() - m_FearWalkTarget.x) < 0.1) && - (std::abs(GetY() - m_FearWalkTarget.y) < 0.1)) { + (std::abs(GetY() - m_FearWalkTarget.y) < 0.1)) { // Calculate a new point to run to CalculateNewFearpoint(); } - if(!RuleB(Pathing, Fear) || !zone->pathing) - { - CalculateNewPosition(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, GetFearSpeed(), true); + if (!RuleB(Pathing, Fear) || !zone->pathing) { + CalculateNewPosition( + m_FearWalkTarget.x, + m_FearWalkTarget.y, + m_FearWalkTarget.z, + GetFearSpeed(), + true + ); } - else - { + else { bool WaypointChanged, NodeReached; - glm::vec3 Goal = UpdatePath(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, - GetFearSpeed(), WaypointChanged, NodeReached); + glm::vec3 Goal = UpdatePath( + m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, + GetFearSpeed(), WaypointChanged, NodeReached + ); - if(WaypointChanged) + if (WaypointChanged) tar_ndx = 20; CalculateNewPosition(Goal.x, Goal.y, Goal.z, GetFearSpeed()); @@ -1154,7 +1162,7 @@ void Mob::AI_Process() { this->FixZ(); if (target_distance <= 15 && !this->CheckLosFN(this->GetTarget())) { - Mob* target = this->GetTarget(); + Mob *target = this->GetTarget(); m_Position.x = target->GetX(); m_Position.y = target->GetY(); @@ -1183,10 +1191,8 @@ void Mob::AI_Process() { // from above, so no extra blind checks needed if ((IsRooted() && !GetSpecialAbility(IGNORE_ROOT_AGGRO_RULES)) || IsBlind()) SetTarget(hate_list.GetClosestEntOnHateList(this)); - else - { - if (AI_target_check_timer->Check()) - { + else { + if (AI_target_check_timer->Check()) { if (IsFocused()) { if (!target) { SetTarget(hate_list.GetEntWithMostHateOnList(this)); @@ -1248,21 +1254,16 @@ void Mob::AI_Process() { bool is_combat_range = CombatRange(target); - if (is_combat_range) - { - if (AI_movement_timer->Check()) - { - if (CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w) - { + if (is_combat_range) { + if (AI_movement_timer->Check()) { + if (CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w) { SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY())); SendPosition(); } SetCurrentSpeed(0); } - if (IsMoving()) - { - if (CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w) - { + if (IsMoving()) { + if (CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w) { SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY())); SendPosition(); } @@ -1287,7 +1288,7 @@ void Mob::AI_Process() { if (zone->random.Roll(flurry_chance)) { ExtraAttackOptions opts; - int cur = GetSpecialAbilityParam(SPECATK_FLURRY, 2); + int cur = GetSpecialAbilityParam(SPECATK_FLURRY, 2); if (cur > 0) opts.damage_percent = cur / 100.0f; @@ -1322,7 +1323,7 @@ void Mob::AI_Process() { if (owner) { int16 flurry_chance = owner->aabonuses.PetFlurry + - owner->spellbonuses.PetFlurry + owner->itembonuses.PetFlurry; + owner->spellbonuses.PetFlurry + owner->itembonuses.PetFlurry; if (flurry_chance && zone->random.Roll(flurry_chance)) Flurry(nullptr); @@ -1330,21 +1331,22 @@ void Mob::AI_Process() { } if ((IsPet() || IsTempPet()) && IsPetOwnerClient()) { - if (spellbonuses.PC_Pet_Rampage[0] || itembonuses.PC_Pet_Rampage[0] || aabonuses.PC_Pet_Rampage[0]) { - int chance = spellbonuses.PC_Pet_Rampage[0] + itembonuses.PC_Pet_Rampage[0] + aabonuses.PC_Pet_Rampage[0]; + if (spellbonuses.PC_Pet_Rampage[0] || itembonuses.PC_Pet_Rampage[0] || + aabonuses.PC_Pet_Rampage[0]) { + int chance = spellbonuses.PC_Pet_Rampage[0] + itembonuses.PC_Pet_Rampage[0] + + aabonuses.PC_Pet_Rampage[0]; if (zone->random.Roll(chance)) { Rampage(nullptr); } } } - if (GetSpecialAbility(SPECATK_RAMPAGE) && !specialed) - { + if (GetSpecialAbility(SPECATK_RAMPAGE) && !specialed) { int rampage_chance = GetSpecialAbilityParam(SPECATK_RAMPAGE, 0); rampage_chance = rampage_chance > 0 ? rampage_chance : 20; if (zone->random.Roll(rampage_chance)) { ExtraAttackOptions opts; - int cur = GetSpecialAbilityParam(SPECATK_RAMPAGE, 3); + int cur = GetSpecialAbilityParam(SPECATK_RAMPAGE, 3); if (cur > 0) { opts.damage_flat = cur; } @@ -1373,13 +1375,12 @@ void Mob::AI_Process() { } } - if (GetSpecialAbility(SPECATK_AREA_RAMPAGE) && !specialed) - { + if (GetSpecialAbility(SPECATK_AREA_RAMPAGE) && !specialed) { int rampage_chance = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 0); rampage_chance = rampage_chance > 0 ? rampage_chance : 20; if (zone->random.Roll(rampage_chance)) { ExtraAttackOptions opts; - int cur = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 3); + int cur = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 3); if (cur > 0) { opts.damage_flat = cur; } @@ -1421,7 +1422,7 @@ void Mob::AI_Process() { } AI_EngagedCastCheck(); - } //end is within combat rangepet + } //end is within combat rangepet else { //we cannot reach our target... //underwater stuff only works with water maps in the zone! @@ -1434,7 +1435,7 @@ void Mob::AI_Process() { Heal(); BuffFadeAll(); AI_walking_timer->Start(100); - pLastFightingDelayMoving = Timer::GetCurrentTime(); + time_until_can_move = Timer::GetCurrentTime(); return; } else if (tar != nullptr) { @@ -1445,8 +1446,7 @@ void Mob::AI_Process() { } // See if we can summon the mob to us - if (!HateSummon()) - { + if (!HateSummon()) { //could not summon them, check ranged... if (GetSpecialAbility(SPECATK_RANGED_ATK)) doranged = true; @@ -1456,18 +1456,18 @@ void Mob::AI_Process() { if (AI_PursueCastCheck()) { //we did something, so do not process movement. } - else if (AI_movement_timer->Check() && target) - { + else if (AI_movement_timer->Check() && target) { if (!IsRooted()) { Log(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", target->GetName()); if (!RuleB(Pathing, Aggro) || !zone->pathing) CalculateNewPosition(target->GetX(), target->GetY(), target->GetZ(), GetRunspeed()); - else - { + else { bool WaypointChanged, NodeReached; - glm::vec3 Goal = UpdatePath(target->GetX(), target->GetY(), target->GetZ(), - GetRunspeed(), WaypointChanged, NodeReached); + glm::vec3 Goal = UpdatePath( + target->GetX(), target->GetY(), target->GetZ(), + GetRunspeed(), WaypointChanged, NodeReached + ); if (WaypointChanged) tar_ndx = 20; @@ -1492,69 +1492,64 @@ void Mob::AI_Process() { if (IsPetStop()) // pet stop won't be engaged, so we will always get here and we want the above branch to execute return; - if(zone->CanDoCombat() && AI_feign_remember_timer->Check()) { + if (zone->CanDoCombat() && AI_feign_remember_timer->Check()) { // 6/14/06 // Improved Feign Death Memory // check to see if any of our previous feigned targets have gotten up. std::set::iterator RememberedCharID; RememberedCharID = feign_memory_list.begin(); while (RememberedCharID != feign_memory_list.end()) { - Client* remember_client = entity_list.GetClientByCharID(*RememberedCharID); + Client *remember_client = entity_list.GetClientByCharID(*RememberedCharID); if (remember_client == nullptr) { //they are gone now... RememberedCharID = feign_memory_list.erase(RememberedCharID); - } else if (!remember_client->GetFeigned()) { - AddToHateList(remember_client->CastToMob(),1); + } + else if (!remember_client->GetFeigned()) { + AddToHateList(remember_client->CastToMob(), 1); RememberedCharID = feign_memory_list.erase(RememberedCharID); break; - } else { + } + else { //they are still feigned, carry on... ++RememberedCharID; } } } - if (AI_IdleCastCheck()) - { + if (AI_IdleCastCheck()) { //we processed a spell action, so do nothing else. } - else if (zone->CanDoCombat() && CastToNPC()->WillAggroNPCs() && AI_scan_area_timer->Check()) - { + else if (zone->CanDoCombat() && CastToNPC()->WillAggroNPCs() && AI_scan_area_timer->Check()) { + /* * NPC to NPC aggro checking, npc needs npc_aggro flag */ - - Mob* temp_target = entity_list.AICheckNPCtoNPCAggro(this, GetAggroRange(), GetAssistRange()); - if (temp_target){ + Mob *temp_target = entity_list.AICheckNPCtoNPCAggro(this, GetAggroRange(), GetAssistRange()); + if (temp_target) { AddToHateList(temp_target); } AI_scan_area_timer->Disable(); - AI_scan_area_timer->Start(RandomTimer(RuleI(NPC, NPCToNPCAggroTimerMin), RuleI(NPC, NPCToNPCAggroTimerMax)), false); + AI_scan_area_timer->Start( + RandomTimer(RuleI(NPC, NPCToNPCAggroTimerMin), RuleI(NPC, NPCToNPCAggroTimerMax)), + false + ); } - else if (AI_movement_timer->Check() && !IsRooted()) - { - if (IsPet()) - { + else if (AI_movement_timer->Check() && !IsRooted()) { + if (IsPet()) { // we're a pet, do as we're told - switch (pStandingPetOrder) - { - case SPO_Follow: - { + switch (pStandingPetOrder) { + case SPO_Follow: { - Mob* owner = GetOwner(); - if(owner == nullptr) + Mob *owner = GetOwner(); + if (owner == nullptr) break; - //if(owner->IsClient()) - // printf("Pet start pos: (%f, %f, %f)\n", GetX(), GetY(), GetZ()); - glm::vec4 ownerPos = owner->GetPosition(); - float dist = DistanceSquared(m_Position, ownerPos); - float distz = ownerPos.z - m_Position.z; + float dist = DistanceSquared(m_Position, ownerPos); + float distz = ownerPos.z - m_Position.z; - if (dist >= 400 || distz > 100) - { + if (dist >= 400 || distz > 100) { int speed = GetWalkspeed(); if (dist >= 1225) // 35 speed = GetRunspeed(); @@ -1565,46 +1560,27 @@ void Mob::AI_Process() { SendPositionUpdate(); moved = true; } - else - { - CalculateNewPosition(owner->GetX(), owner->GetY(), owner->GetZ(), speed); + else { + CalculateNewPosition(owner->GetX(), owner->GetY(), owner->GetZ(), speed); } } - else - { - if(moved) - { + else { + if (moved) { this->FixZ(); SetCurrentSpeed(0); moved = false; } } - /* - //fix up Z - float zdiff = GetZ() - owner->GetZ(); - if(zdiff < 0) - zdiff = 0 - zdiff; - if(zdiff > 2.0f) { - SendTo(GetX(), GetY(), owner->GetZ()); - SendPosition(); - } - - if(owner->IsClient()) - printf("Pet pos: (%f, %f, %f)\n", GetX(), GetY(), GetZ()); - */ - break; } - case SPO_Sit: - { + case SPO_Sit: { SetAppearance(eaSitting, false); break; } - case SPO_Guard: - { + case SPO_Guard: { //only NPCs can guard stuff. (forced by where the guard movement code is in the AI) - if(IsNPC()) { + if (IsNPC()) { CastToNPC()->NextGuardPosition(); } break; @@ -1613,25 +1589,23 @@ void Mob::AI_Process() { if (IsPetRegroup()) return; } - /* Entity has been assigned another entity to follow */ - else if (GetFollowID()) - { - Mob* follow = entity_list.GetMob(GetFollowID()); - if (!follow) SetFollowID(0); - else - { - float dist2 = DistanceSquared(m_Position, follow->GetPosition()); - int followdist = GetFollowDistance(); + /* Entity has been assigned another entity to follow */ + else if (GetFollowID()) { + Mob *follow = entity_list.GetMob(GetFollowID()); + if (!follow) { SetFollowID(0); } + else { + float dist2 = DistanceSquared(m_Position, follow->GetPosition()); + int followdist = GetFollowDistance(); - if (dist2 >= followdist) // Default follow distance is 100 + if (dist2 >= followdist) // Default follow distance is 100 { int speed = GetWalkspeed(); - if (dist2 >= followdist + 150) + if (dist2 >= followdist + 150) { speed = GetRunspeed(); + } CalculateNewPosition(follow->GetX(), follow->GetY(), follow->GetZ(), speed); } - else - { + else { moved = false; SetCurrentSpeed(0); } @@ -1640,20 +1614,21 @@ void Mob::AI_Process() { else //not a pet, and not following somebody... { // dont move till a bit after you last fought - if (pLastFightingDelayMoving < Timer::GetCurrentTime()) - { - if (this->IsClient()) - { - // LD timer expired, drop out of world - if (this->CastToClient()->IsLD()) + if (time_until_can_move < Timer::GetCurrentTime()) { + if (this->IsClient()) { + + /** + * LD timer expired, drop out of world + */ + if (this->CastToClient()->IsLD()) { this->CastToClient()->Disconnect(); + } + return; } - if(IsNPC()) - { - if(RuleB(NPC, SmartLastFightingDelayMoving) && !feign_memory_list.empty()) - { + if (IsNPC()) { + if (RuleB(NPC, SmartLastFightingDelayMoving) && !feign_memory_list.empty()) { minLastFightingDelayMoving = 0; maxLastFightingDelayMoving = 0; } @@ -1661,93 +1636,84 @@ void Mob::AI_Process() { CastToNPC()->AI_DoMovement(); } } - } - } // else if (AImovement_timer->Check()) + } } //Do Ranged attack here - if(doranged) - { + if (doranged) { RangedAttack(target); } } void NPC::AI_DoMovement() { - float walksp = GetMovespeed(); - if(walksp <= 0.0f) - return; //this is idle movement at walk speed, and we are unable to walk right now. - if (roambox_distance > 0) { - if ( - roambox_movingto_x > roambox_max_x - || roambox_movingto_x < roambox_min_x - || roambox_movingto_y > roambox_max_y - || roambox_movingto_y < roambox_min_y - ) - { - float movedist = roambox_distance*roambox_distance; - float movex = zone->random.Real(0, movedist); - float movey = movedist - movex; - movex = sqrtf(movex); - movey = sqrtf(movey); - movex *= zone->random.Int(0, 1) ? 1 : -1; - movey *= zone->random.Int(0, 1) ? 1 : -1; - roambox_movingto_x = GetX() + movex; - roambox_movingto_y = GetY() + movey; - //Try to calculate new coord using distance. - if (roambox_movingto_x > roambox_max_x || roambox_movingto_x < roambox_min_x) - roambox_movingto_x -= movex * 2; - if (roambox_movingto_y > roambox_max_y || roambox_movingto_y < roambox_min_y) - roambox_movingto_y -= movey * 2; - //New coord is still invalid, ignore distance and just pick a new random coord. - //If we're here we may have a roambox where one side is shorter than the specified distance. Commons, Wkarana, etc. - if (roambox_movingto_x > roambox_max_x || roambox_movingto_x < roambox_min_x) - roambox_movingto_x = zone->random.Real(roambox_min_x+1,roambox_max_x-1); - if (roambox_movingto_y > roambox_max_y || roambox_movingto_y < roambox_min_y) - roambox_movingto_y = zone->random.Real(roambox_min_y+1,roambox_max_y-1); - Log(Logs::Detail, Logs::AI, - "Roam Box: d=%.3f (%.3f->%.3f,%.3f->%.3f): Go To (%.3f,%.3f)", - roambox_distance, roambox_min_x, roambox_max_x, roambox_min_y, - roambox_max_y, roambox_movingto_x, roambox_movingto_y); - } - - Log(Logs::Detail, Logs::AI, "Roam Box: d=%.3f (%.3f->%.3f,%.3f->%.3f): Go To (%.3f,%.3f)", - roambox_distance, roambox_min_x, roambox_max_x, roambox_min_y, roambox_max_y, roambox_movingto_x, roambox_movingto_y); + float move_speed = GetMovespeed(); - float new_z = this->FindGroundZ(m_Position.x, m_Position.y, 5) + GetZOffset(); - - if (!CalculateNewPosition(roambox_movingto_x, roambox_movingto_y, new_z, walksp, true)) - { - this->FixZ(); // FixZ on final arrival point. - roambox_movingto_x = roambox_max_x + 1; // force update - pLastFightingDelayMoving = Timer::GetCurrentTime() + RandomTimer(roambox_min_delay, roambox_delay); - SetMoving(false); - SendPosition(); // makes mobs stop clientside - } + if (move_speed <= 0.0f) { + return; } - else if (roamer) - { - if (AI_walking_timer->Check()) - { - movetimercompleted=true; + + /** + * Roambox logic sets precedence + */ + if (roambox_distance > 0) { + + if (!IsMoving()) { + auto move_x = static_cast(zone->random.Real(-roambox_distance, roambox_distance)); + auto move_y = static_cast(zone->random.Real(-roambox_distance, roambox_distance)); + + roambox_destination_x = EQEmu::Clamp((GetX() + move_x), roambox_min_x, roambox_min_y); + roambox_destination_y = EQEmu::Clamp((GetY() + move_y), roambox_min_y, roambox_max_y); + + this->FixZ(); + + Log(Logs::Detail, + Logs::NPCRoamBox, + "Calculate | NPC: %s distance %.3f | min_x %.3f | max_x %.3f | final_x %.3f | min_y %.3f | max_y %.3f | final_y %.3f", + this->GetCleanName(), + roambox_distance, + roambox_min_x, + roambox_max_x, + roambox_destination_x, + roambox_min_y, + roambox_max_y, + roambox_destination_y); + } + + if (!CalculateNewPosition(roambox_destination_x, roambox_destination_y, GetFixedZ(m_Position), move_speed, true)) { + time_until_can_move = Timer::GetCurrentTime() + RandomTimer(roambox_min_delay, roambox_delay); + SetMoving(false); + this->FixZ(); + SendPosition(); + } + + return; + } + else if (roamer) { + if (AI_walking_timer->Check()) { + movetimercompleted = true; AI_walking_timer->Disable(); } - int32 gridno = CastToNPC()->GetGrid(); - if (gridno > 0 || cur_wp==-2) { - if (movetimercompleted==true) { // time to pause at wp is over + if (gridno > 0 || cur_wp == -2) { + if (movetimercompleted == true) { // time to pause at wp is over AI_SetupNextWaypoint(); - } // endif (movetimercompleted==true) - else if (!(AI_walking_timer->Enabled())) - { // currently moving + } // endif (movetimercompleted==true) + else if (!(AI_walking_timer->Enabled())) { // currently moving bool doMove = true; - if (m_CurrentWayPoint.x == GetX() && m_CurrentWayPoint.y == GetY()) - { // are we there yet? then stop - Log(Logs::Detail, Logs::AI, "We have reached waypoint %d (%.3f,%.3f,%.3f) on grid %d", cur_wp, GetX(), GetY(), GetZ(), GetGrid()); - + if (m_CurrentWayPoint.x == GetX() && m_CurrentWayPoint.y == GetY()) { // are we there yet? then stop + Log(Logs::Detail, + Logs::AI, + "We have reached waypoint %d (%.3f,%.3f,%.3f) on grid %d", + cur_wp, + GetX(), + GetY(), + GetZ(), + GetGrid()); + SetWaypointPause(); SetAppearance(eaStanding, false); SetMoving(false); @@ -1773,36 +1739,45 @@ void NPC::AI_DoMovement() { } // wipe feign memory since we reached our first waypoint - if(cur_wp == 1) + if (cur_wp == 1) ClearFeignMemory(); } - if (doMove) - { // not at waypoint yet or at 0 pause WP, so keep moving - if(!RuleB(Pathing, AggroReturnToGrid) || !zone->pathing || (DistractedFromGrid == 0)) - CalculateNewPosition(m_CurrentWayPoint.x, m_CurrentWayPoint.y, m_CurrentWayPoint.z, walksp, true); - else - { - bool WaypointChanged; - bool NodeReached; - glm::vec3 Goal = UpdatePath(m_CurrentWayPoint.x, m_CurrentWayPoint.y, m_CurrentWayPoint.z, walksp, WaypointChanged, NodeReached); - if(WaypointChanged) + if (doMove) { // not at waypoint yet or at 0 pause WP, so keep moving + if (!RuleB(Pathing, AggroReturnToGrid) || !zone->pathing || (DistractedFromGrid == 0)) + CalculateNewPosition( + m_CurrentWayPoint.x, + m_CurrentWayPoint.y, + m_CurrentWayPoint.z, + move_speed, + true + ); + else { + bool WaypointChanged; + bool NodeReached; + glm::vec3 Goal = UpdatePath( + m_CurrentWayPoint.x, + m_CurrentWayPoint.y, + m_CurrentWayPoint.z, + move_speed, + WaypointChanged, + NodeReached + ); + if (WaypointChanged) tar_ndx = 20; - if(NodeReached) + if (NodeReached) entity_list.OpenDoorsNear(CastToNPC()); - CalculateNewPosition(Goal.x, Goal.y, Goal.z, walksp, true); + CalculateNewPosition(Goal.x, Goal.y, Goal.z, move_speed, true); } } } - } // endif (gridno > 0) - // handle new quest grid command processing - else if (gridno < 0) - { // this mob is under quest control - if (movetimercompleted==true) - { // time to pause has ended - SetGrid( 0 - GetGrid()); // revert to AI control + } // endif (gridno > 0) + // handle new quest grid command processing + else if (gridno < 0) { // this mob is under quest control + if (movetimercompleted == true) { // time to pause has ended + SetGrid(0 - GetGrid()); // revert to AI control Log(Logs::Detail, Logs::Pathing, "Quest pathing is finished. Resuming on grid %d", GetGrid()); SetAppearance(eaStanding, false); @@ -1812,39 +1787,55 @@ void NPC::AI_DoMovement() { } } - else if (IsGuarding()) - { + else if (IsGuarding()) { bool CP2Moved; - if(!RuleB(Pathing, Guard) || !zone->pathing) - CP2Moved = CalculateNewPosition(m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z, walksp); - else - { - if(!((m_Position.x == m_GuardPoint.x) && (m_Position.y == m_GuardPoint.y) && (m_Position.z == m_GuardPoint.z))) - { + if (!RuleB(Pathing, Guard) || !zone->pathing) { + CP2Moved = CalculateNewPosition(m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z, move_speed); + } + else { + if (!((m_Position.x == m_GuardPoint.x) && (m_Position.y == m_GuardPoint.y) && + (m_Position.z == m_GuardPoint.z))) { + bool WaypointChanged, NodeReached; - glm::vec3 Goal = UpdatePath(m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z, walksp, WaypointChanged, NodeReached); - if(WaypointChanged) + + glm::vec3 Goal = UpdatePath( + m_GuardPoint.x, + m_GuardPoint.y, + m_GuardPoint.z, + move_speed, + WaypointChanged, + NodeReached + ); + if (WaypointChanged) { tar_ndx = 20; + } - if(NodeReached) + if (NodeReached) { entity_list.OpenDoorsNear(CastToNPC()); + } - CP2Moved = CalculateNewPosition(Goal.x, Goal.y, Goal.z, walksp); + CP2Moved = CalculateNewPosition(Goal.x, Goal.y, Goal.z, move_speed); } - else + else { CP2Moved = false; + } } - if (!CP2Moved) - { - if(moved) { - Log(Logs::Detail, Logs::AI, "Reached guard point (%.3f,%.3f,%.3f)", m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z); + if (!CP2Moved) { + if (moved) { + Log(Logs::Detail, + Logs::AI, + "Reached guard point (%.3f,%.3f,%.3f)", + m_GuardPoint.x, + m_GuardPoint.y, + m_GuardPoint.z); + ClearFeignMemory(); - moved=false; - if (GetTarget() == nullptr || DistanceSquared(m_Position, GetTarget()->GetPosition()) >= 5*5 ) - { + moved = false; + if (GetTarget() == nullptr || DistanceSquared(m_Position, GetTarget()->GetPosition()) >= 5 * 5) { SetHeading(m_GuardPoint.w); - } else { + } + else { FaceTarget(GetTarget()); } SetCurrentSpeed(0); @@ -1968,11 +1959,11 @@ void Mob::AI_Event_NoLongerEngaged() { if (!IsAIControlled()) return; this->AI_walking_timer->Start(RandomTimer(3000,20000)); - pLastFightingDelayMoving = Timer::GetCurrentTime(); + time_until_can_move = Timer::GetCurrentTime(); if (minLastFightingDelayMoving == maxLastFightingDelayMoving) - pLastFightingDelayMoving += minLastFightingDelayMoving; + time_until_can_move += minLastFightingDelayMoving; else - pLastFightingDelayMoving += zone->random.Int(minLastFightingDelayMoving, maxLastFightingDelayMoving); + time_until_can_move += zone->random.Int(minLastFightingDelayMoving, maxLastFightingDelayMoving); // So mobs don't keep running as a ghost until AIwalking_timer fires // if they were moving prior to losing all hate // except if we're a pet, then we might run into some issues with pets backing off when they should immediately be moving diff --git a/zone/npc.cpp b/zone/npc.cpp index 7cf31b617..bf1508858 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -242,8 +242,8 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if roambox_max_y = -2; roambox_min_x = -2; roambox_min_y = -2; - roambox_movingto_x = -2; - roambox_movingto_y = -2; + roambox_destination_x = -2; + roambox_destination_y = -2; roambox_min_delay = 1000; roambox_delay = 1000; p_depop = false; diff --git a/zone/npc.h b/zone/npc.h index 471b47557..52c8b2171 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -311,9 +311,17 @@ public: void SaveGuardSpot(bool iClearGuardSpot = false); inline bool IsGuarding() const { return(m_GuardPoint.w != 0); } void SaveGuardSpotCharm(); - void RestoreGuardSpotCharm(); - void AI_SetRoambox(float iDist, float iRoamDist, uint32 iDelay = 2500, uint32 iMinDelay = 2500); - void AI_SetRoambox(float iDist, float iMaxX, float iMinX, float iMaxY, float iMinY, uint32 iDelay = 2500, uint32 iMinDelay = 2500); + + void RestoreGuardSpotCharm(); + + void AI_SetRoambox( + float max_distance, + float roam_distance_variance, + uint32 delay = 2500, + uint32 min_delay = 2500 + ); + + void AI_SetRoambox(float distance, float max_x, float min_x, float max_y, float min_y, uint32 delay = 2500, uint32 min_delay = 2500); //mercenary stuff void LoadMercTypes(); @@ -530,8 +538,8 @@ protected: float roambox_min_x; float roambox_min_y; float roambox_distance; - float roambox_movingto_x; - float roambox_movingto_y; + float roambox_destination_x; + float roambox_destination_y; uint32 roambox_delay; uint32 roambox_min_delay; diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index bfc474721..71101dff8 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -141,118 +141,181 @@ uint32 Spawn2::despawnTimer(uint32 despawn_timer) bool Spawn2::Process() { IsDespawned = false; - if(!Enabled()) + if (!Enabled()) return true; //grab our spawn group - SpawnGroup* sg = zone->spawn_group_list.GetSpawnGroup(spawngroup_id_); + SpawnGroup *spawn_group = zone->spawn_group_list.GetSpawnGroup(spawngroup_id_); - if(NPCPointerValid() && (sg->despawn == 0 || condition_id != 0)) + if (NPCPointerValid() && (spawn_group->despawn == 0 || condition_id != 0)) { return true; + } - if (timer.Check()) { + if (timer.Check()) { timer.Disable(); Log(Logs::Detail, Logs::Spawns, "Spawn2 %d: Timer has triggered", spawn2_id); //first check our spawn condition, if this isnt active //then we reset the timer and try again next time. - if(condition_id != SC_AlwaysEnabled + if (condition_id != SC_AlwaysEnabled && !zone->spawn_conditions.Check(condition_id, condition_min_value)) { - Log(Logs::Detail, Logs::Spawns, "Spawn2 %d: spawning prevented by spawn condition %d", spawn2_id, condition_id); + Log(Logs::Detail, + Logs::Spawns, + "Spawn2 %d: spawning prevented by spawn condition %d", + spawn2_id, + condition_id); Reset(); - return(true); + return (true); } - if (sg == nullptr) { - database.LoadSpawnGroupsByID(spawngroup_id_,&zone->spawn_group_list); - sg = zone->spawn_group_list.GetSpawnGroup(spawngroup_id_); + if (spawn_group == nullptr) { + database.LoadSpawnGroupsByID(spawngroup_id_, &zone->spawn_group_list); + spawn_group = zone->spawn_group_list.GetSpawnGroup(spawngroup_id_); } - if (sg == nullptr) { - Log(Logs::Detail, Logs::Spawns, "Spawn2 %d: Unable to locate spawn group %d. Disabling.", spawn2_id, spawngroup_id_); + if (spawn_group == nullptr) { + Log(Logs::Detail, + Logs::Spawns, + "Spawn2 %d: Unable to locate spawn group %d. Disabling.", + spawn2_id, + spawngroup_id_); + return false; } //have the spawn group pick an NPC for us - uint32 npcid = sg->GetNPCType(); + uint32 npcid = spawn_group->GetNPCType(); if (npcid == 0) { - Log(Logs::Detail, Logs::Spawns, "Spawn2 %d: Spawn group %d did not yeild an NPC! not spawning.", spawn2_id, spawngroup_id_); - Reset(); //try again later (why?) - return(true); + Log(Logs::Detail, + Logs::Spawns, + "Spawn2 %d: Spawn group %d did not yeild an NPC! not spawning.", + spawn2_id, + spawngroup_id_); + + Reset(); //try again later (why?) + return (true); } //try to find our NPC type. - const NPCType* tmp = database.LoadNPCTypesData(npcid); + const NPCType *tmp = database.LoadNPCTypesData(npcid); if (tmp == nullptr) { - Log(Logs::Detail, Logs::Spawns, "Spawn2 %d: Spawn group %d yeilded an invalid NPC type %d", spawn2_id, spawngroup_id_, npcid); - Reset(); //try again later - return(true); + Log(Logs::Detail, + Logs::Spawns, + "Spawn2 %d: Spawn group %d yeilded an invalid NPC type %d", + spawn2_id, + spawngroup_id_, + npcid); + Reset(); //try again later + return (true); } - if(tmp->unique_spawn_by_name) - { - if(!entity_list.LimitCheckName(tmp->name)) - { - Log(Logs::Detail, Logs::Spawns, "Spawn2 %d: Spawn group %d yeilded NPC type %d, which is unique and one already exists.", spawn2_id, spawngroup_id_, npcid); - timer.Start(5000); //try again in five seconds. - return(true); + if (tmp->unique_spawn_by_name) { + if (!entity_list.LimitCheckName(tmp->name)) { + Log(Logs::Detail, + Logs::Spawns, + "Spawn2 %d: Spawn group %d yeilded NPC type %d, which is unique and one already exists.", + spawn2_id, + spawngroup_id_, + npcid); + timer.Start(5000); //try again in five seconds. + return (true); } } - if(tmp->spawn_limit > 0) { - if(!entity_list.LimitCheckType(npcid, tmp->spawn_limit)) { - Log(Logs::Detail, Logs::Spawns, "Spawn2 %d: Spawn group %d yeilded NPC type %d, which is over its spawn limit (%d)", spawn2_id, spawngroup_id_, npcid, tmp->spawn_limit); - timer.Start(5000); //try again in five seconds. - return(true); + if (tmp->spawn_limit > 0) { + if (!entity_list.LimitCheckType(npcid, tmp->spawn_limit)) { + Log(Logs::Detail, + Logs::Spawns, + "Spawn2 %d: Spawn group %d yeilded NPC type %d, which is over its spawn limit (%d)", + spawn2_id, + spawngroup_id_, + npcid, + tmp->spawn_limit); + timer.Start(5000); //try again in five seconds. + return (true); } } bool ignore_despawn = false; - if (npcthis) - { + if (npcthis) { ignore_despawn = npcthis->IgnoreDespawn(); } - - if (ignore_despawn) - { + + if (ignore_despawn) { return true; } - - if (sg->despawn != 0 && condition_id == 0 && !ignore_despawn) - { + + if (spawn_group->despawn != 0 && condition_id == 0 && !ignore_despawn) { zone->Despawn(spawn2_id); } - if (IsDespawned) - { + if (IsDespawned) { return true; } currentnpcid = npcid; - NPC* npc = new NPC(tmp, this, glm::vec4(x, y, z, heading), FlyMode3); + NPC *npc = new NPC(tmp, this, glm::vec4(x, y, z, heading), FlyMode3); npc->mod_prespawn(this); npcthis = npc; npc->AddLootTable(); - if (npc->DropsGlobalLoot()) + if (npc->DropsGlobalLoot()) { npc->CheckGlobalLootTables(); + } npc->SetSp2(spawngroup_id_); npc->SaveGuardPointAnim(anim); - npc->SetAppearance((EmuAppearance)anim); + npc->SetAppearance((EmuAppearance) anim); entity_list.AddNPC(npc); //this limit add must be done after the AddNPC since we need the entity ID. entity_list.LimitAddNPC(npc); - if(sg->roamdist && sg->roambox[0] && sg->roambox[1] && sg->roambox[2] && sg->roambox[3] && sg->delay && sg->min_delay) - npc->AI_SetRoambox(sg->roamdist,sg->roambox[0],sg->roambox[1],sg->roambox[2],sg->roambox[3],sg->delay,sg->min_delay); - if(zone->InstantGrids()) { - Log(Logs::Detail, Logs::Spawns, "Spawn2 %d: Group %d spawned %s (%d) at (%.3f, %.3f, %.3f).", spawn2_id, spawngroup_id_, npc->GetName(), npcid, x, y, z); + + /** + * Roambox init + */ + if (spawn_group->roamdist && spawn_group->roambox[0] && spawn_group->roambox[1] && spawn_group->roambox[2] && + spawn_group->roambox[3] && spawn_group->delay && spawn_group->min_delay) { + + npc->AI_SetRoambox( + spawn_group->roamdist, + spawn_group->roambox[0], + spawn_group->roambox[1], + spawn_group->roambox[2], + spawn_group->roambox[3], + spawn_group->delay, + spawn_group->min_delay + ); + } + + if (zone->InstantGrids()) { + Log(Logs::Detail, + Logs::Spawns, + "Spawn2 %d: Group %d spawned %s (%d) at (%.3f, %.3f, %.3f).", + spawn2_id, + spawngroup_id_, + npc->GetName(), + npcid, + x, + y, + z); + LoadGrid(); - } else { - Log(Logs::Detail, Logs::Spawns, "Spawn2 %d: Group %d spawned %s (%d) at (%.3f, %.3f, %.3f). Grid loading delayed.", spawn2_id, spawngroup_id_, tmp->name, npcid, x, y, z); + } + else { + Log(Logs::Detail, + Logs::Spawns, + "Spawn2 %d: Group %d spawned %s (%d) at (%.3f, %.3f, %.3f). Grid loading delayed.", + spawn2_id, + spawngroup_id_, + tmp->name, + npcid, + x, + y, + z); } } + return true; } @@ -266,11 +329,11 @@ void Spawn2::Disable() } void Spawn2::LoadGrid() { - if(!npcthis) + if (!npcthis) return; - if(grid_ < 1) + if (grid_ < 1) return; - if(!entity_list.IsMobInZone(npcthis)) + if (!entity_list.IsMobInZone(npcthis)) return; //dont set an NPC's grid until its loaded for them. npcthis->SetGrid(grid_); @@ -278,7 +341,6 @@ void Spawn2::LoadGrid() { Log(Logs::Detail, Logs::Spawns, "Spawn2 %d: Loading grid %d for %s", spawn2_id, grid_, npcthis->GetName()); } - /* All three of these actions basically say that the mob which was associated with this spawn point is no longer relavent. diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index 2351e2686..083cc38ba 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -42,19 +42,27 @@ struct wp_distance int index; }; -void NPC::AI_SetRoambox(float iDist, float iRoamDist, uint32 iDelay, uint32 iMinDelay) { - AI_SetRoambox(iDist, GetX() + iRoamDist, GetX() - iRoamDist, GetY() + iRoamDist, GetY() - iRoamDist, iDelay, iMinDelay); +void NPC::AI_SetRoambox(float max_distance, float roam_distance_variance, uint32 delay, uint32 min_delay) { + AI_SetRoambox( + max_distance, + GetX() + roam_distance_variance, + GetX() - roam_distance_variance, + GetY() + roam_distance_variance, + GetY() - roam_distance_variance, + delay, + min_delay + ); } -void NPC::AI_SetRoambox(float iDist, float iMaxX, float iMinX, float iMaxY, float iMinY, uint32 iDelay, uint32 iMinDelay) { - roambox_distance = iDist; - roambox_max_x = iMaxX; - roambox_min_x = iMinX; - roambox_max_y = iMaxY; - roambox_min_y = iMinY; - roambox_movingto_x = roambox_max_x + 1; // this will trigger a recalc - roambox_delay = iDelay; - roambox_min_delay = iMinDelay; +void NPC::AI_SetRoambox(float distance, float max_x, float min_x, float max_y, float min_y, uint32 delay, uint32 min_delay) { + roambox_distance = distance; + roambox_max_x = max_x; + roambox_min_x = min_x; + roambox_max_y = max_y; + roambox_min_y = min_y; + roambox_destination_x = roambox_max_x + 1; // this will trigger a recalc + roambox_delay = delay; + roambox_min_delay = min_delay; } void NPC::DisplayWaypointInfo(Client *c) { @@ -199,7 +207,7 @@ void NPC::MoveTo(const glm::vec4& position, bool saveguardspot) } cur_wp_pause = 0; - pLastFightingDelayMoving = 0; + time_until_can_move = 0; if (AI_walking_timer->Enabled()) AI_walking_timer->Start(100); } @@ -438,22 +446,16 @@ float Mob::CalculateDistance(float x, float y, float z) { return (float)sqrtf(((m_Position.x - x)*(m_Position.x - x)) + ((m_Position.y - y)*(m_Position.y - y)) + ((m_Position.z - z)*(m_Position.z - z))); } -bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, bool checkZ, bool calcHeading) { +bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, bool check_z, bool calculate_heading) { if (GetID() == 0) return true; - if (speed <= 0) - { + if (speed <= 0) { SetCurrentSpeed(0); return true; } if ((m_Position.x - x == 0) && (m_Position.y - y == 0)) {//spawn is at target coords - if (m_Position.z - z != 0) { - m_Position.z = z; - Log(Logs::Detail, Logs::AI, "Calc Position2 (%.3f, %.3f, %.3f): Jumping pure Z.", x, y, z); - return true; - } return false; } else if ((std::abs(m_Position.x - x) < 0.1) && (std::abs(m_Position.y - y) < 0.1)) { @@ -464,16 +466,17 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo m_Position.x = x; m_Position.y = y; m_Position.z = z; + return true; } - bool send_update = false; int compare_steps = 20; if (tar_ndx < compare_steps && m_TargetLocation.x == x && m_TargetLocation.y == y) { - float new_x = m_Position.x + m_TargetV.x*tar_vector; - float new_y = m_Position.y + m_TargetV.y*tar_vector; - float new_z = m_Position.z + m_TargetV.z*tar_vector; + float new_x = m_Position.x + m_TargetV.x * tar_vector; + float new_y = m_Position.y + m_TargetV.y * tar_vector; + float new_z = m_Position.z + m_TargetV.z * tar_vector; + if (IsNPC()) { entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z); } @@ -482,21 +485,22 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo m_Position.y = new_y; m_Position.z = new_z; - if(checkZ && fix_z_timer.Check() && - (!this->IsEngaged() || flee_mode || currently_fleeing)) + if (check_z && fix_z_timer.Check() && (!this->IsEngaged() || flee_mode || currently_fleeing)) { this->FixZ(); + } tar_ndx++; + return true; } - - if (tar_ndx>50) { + if (tar_ndx > 50) { tar_ndx--; } else { tar_ndx = 0; } + m_TargetLocation = glm::vec3(x, y, z); float nx = this->m_Position.x; @@ -530,14 +534,12 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo // mob move fix - if (numsteps<20) - { - if (numsteps>1) - { + if (numsteps < 20) { + if (numsteps > 1) { tar_vector = 1.0f; - m_TargetV.x = m_TargetV.x / (float)numsteps; - m_TargetV.y = m_TargetV.y / (float)numsteps; - m_TargetV.z = m_TargetV.z / (float)numsteps; + m_TargetV.x = m_TargetV.x / (float) numsteps; + m_TargetV.y = m_TargetV.y / (float) numsteps; + m_TargetV.z = m_TargetV.z / (float) numsteps; float new_x = m_Position.x + m_TargetV.x; float new_y = m_Position.y + m_TargetV.y; @@ -549,12 +551,12 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo m_Position.x = new_x; m_Position.y = new_y; m_Position.z = new_z; - if (calcHeading) + if (calculate_heading) { m_Position.w = CalculateHeadingToTarget(x, y); + } tar_ndx = 20 - numsteps; } - else - { + else { if (IsNPC()) { entity_list.ProcessMove(CastToNPC(), x, y, z); } @@ -578,9 +580,10 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo tar_vector *= (dur / 100.0f); - float new_x = m_Position.x + m_TargetV.x*tar_vector; - float new_y = m_Position.y + m_TargetV.y*tar_vector; - float new_z = m_Position.z + m_TargetV.z*tar_vector; + float new_x = m_Position.x + m_TargetV.x * tar_vector; + float new_y = m_Position.y + m_TargetV.y * tar_vector; + float new_z = m_Position.z + m_TargetV.z * tar_vector; + if (IsNPC()) { entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z); } @@ -588,11 +591,12 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo m_Position.x = new_x; m_Position.y = new_y; m_Position.z = new_z; - if (calcHeading) + if (calculate_heading) { m_Position.w = CalculateHeadingToTarget(x, y); + } } - if (checkZ && fix_z_timer.Check() && !this->IsEngaged()) + if (check_z && fix_z_timer.Check() && !this->IsEngaged()) this->FixZ(); SetMoving(true); @@ -600,13 +604,11 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo m_Delta = glm::vec4(m_Position.x - nx, m_Position.y - ny, m_Position.z - nz, 0.0f); - if (IsClient()) - { + if (IsClient()) { SendPositionUpdate(1); CastToClient()->ResetPositionTimer(); } - else - { + else { SendPositionUpdate(); SetAppearance(eaStanding, false); } @@ -615,8 +617,8 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo return true; } -bool Mob::CalculateNewPosition(float x, float y, float z, int speed, bool checkZ, bool calcHeading) { - return MakeNewPositionAndSendUpdate(x, y, z, speed); +bool Mob::CalculateNewPosition(float x, float y, float z, float speed, bool check_z, bool calculate_heading) { + return MakeNewPositionAndSendUpdate(x, y, z, speed, check_z); } void NPC::AssignWaypoints(int32 grid) @@ -746,10 +748,11 @@ void Mob::SendToFixZ(float new_x, float new_y, float new_z) { } } -float Mob::GetFixedZ(glm::vec3 dest, int32 z_find_offset) { +float Mob::GetFixedZ(glm::vec3 destination, int32 z_find_offset) { BenchTimer timer; timer.reset(); - float new_z = dest.z; + + float new_z = destination.z; if (zone->HasMap() && RuleB(Map, FixZWhenMoving)) { @@ -765,7 +768,7 @@ float Mob::GetFixedZ(glm::vec3 dest, int32 z_find_offset) { /* * Any more than 5 in the offset makes NPC's hop/snap to ceiling in small corridors */ - new_z = this->FindDestGroundZ(dest, z_find_offset); + new_z = this->FindDestGroundZ(destination, z_find_offset); if (new_z != BEST_Z_INVALID) { new_z += this->GetZOffset(); @@ -776,9 +779,15 @@ float Mob::GetFixedZ(glm::vec3 dest, int32 z_find_offset) { auto duration = timer.elapsed(); - Log(Logs::Moderate, Logs::FixZ, - "Mob::GetFixedZ() (%s) returned %4.3f at %4.3f, %4.3f, %4.3f - Took %lf", - this->GetCleanName(), new_z, dest.x, dest.y, dest.z, duration); + Log(Logs::Moderate, + Logs::FixZ, + "Mob::GetFixedZ() (%s) returned %4.3f at %4.3f, %4.3f, %4.3f - Took %lf", + this->GetCleanName(), + new_z, + destination.x, + destination.y, + destination.z, + duration); } return new_z; @@ -790,16 +799,19 @@ void Mob::FixZ(int32 z_find_offset /*= 5*/) { if (!IsClient() && new_z != m_Position.z) { if ((new_z > -2000) && new_z != BEST_Z_INVALID) { - if (RuleB(Map, MobZVisualDebug)) + if (RuleB(Map, MobZVisualDebug)) { this->SendAppearanceEffect(78, 0, 0, 0, 0); + } m_Position.z = new_z; - } else { - if (RuleB(Map, MobZVisualDebug)) + } + else { + if (RuleB(Map, MobZVisualDebug)) { this->SendAppearanceEffect(103, 0, 0, 0, 0); + } Log(Logs::General, Logs::FixZ, "%s is failing to find Z %f", - this->GetCleanName(), std::abs(m_Position.z - new_z)); + this->GetCleanName(), std::abs(m_Position.z - new_z)); } } } From 834062fbf957c17a5492a1c3628d8af610ef5618 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sat, 18 Aug 2018 22:01:46 -0500 Subject: [PATCH 14/44] Add another layer of randomization to roam box logic, npc's who weren't originally spawned in water won't roambox into water --- zone/attack.cpp | 8 ++++++++ zone/entity.cpp | 10 ++++++++++ zone/mob.h | 7 +++++++ zone/mob_ai.cpp | 32 ++++++++++++++++++++++++++++++-- zone/water_map_v2.cpp | 2 +- zone/waypoints.cpp | 2 +- zone/zone.h | 8 ++++---- 7 files changed, 61 insertions(+), 8 deletions(-) diff --git a/zone/attack.cpp b/zone/attack.cpp index a48d68934..d6cf4227f 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -5455,3 +5455,11 @@ void Mob::DoOffHandAttackRounds(Mob *target, ExtraAttackOptions *opts) } } } + +bool Mob::GetWasSpawnedInWater() const { + return spawned_in_water; +} + +void Mob::SetSpawnedInWater(bool spawned_in_water) { + Mob::spawned_in_water = spawned_in_water; +} diff --git a/zone/entity.cpp b/zone/entity.cpp index f61acda94..2523c7d96 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -39,6 +39,7 @@ #include "raids.h" #include "string_ids.h" #include "worldserver.h" +#include "water_map.h" #ifdef _WINDOWS #define snprintf _snprintf @@ -686,6 +687,15 @@ void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue) } } + /** + * Set whether NPC was spawned in or out of water + */ + if (zone->HasMap() && zone->HasWaterMap()) { + npc->SetSpawnedInWater(false); + if (zone->watermap->InLiquid(npc->GetPosition())) { + npc->SetSpawnedInWater(true); + } + } } void EntityList::AddMerc(Merc *merc, bool SendSpawnPacket, bool dontqueue) diff --git a/zone/mob.h b/zone/mob.h index bdfbd31bc..763fa61b7 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -1414,6 +1414,13 @@ protected: bool pseudo_rooted; bool endur_upkeep; bool degenerating_effects; // true if we have a buff that needs to be recalced every tick + bool spawned_in_water; +public: + bool GetWasSpawnedInWater() const; + + void SetSpawnedInWater(bool spawned_in_water); + +protected: // Bind wound Timer bindwound_timer; diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 0579fd60d..9c16dc9b6 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1663,9 +1663,35 @@ void NPC::AI_DoMovement() { auto move_x = static_cast(zone->random.Real(-roambox_distance, roambox_distance)); auto move_y = static_cast(zone->random.Real(-roambox_distance, roambox_distance)); - roambox_destination_x = EQEmu::Clamp((GetX() + move_x), roambox_min_x, roambox_min_y); + roambox_destination_x = EQEmu::Clamp((GetX() + move_x), roambox_min_x, roambox_max_x); roambox_destination_y = EQEmu::Clamp((GetY() + move_y), roambox_min_y, roambox_max_y); + if (roambox_destination_x == roambox_min_x || roambox_destination_x == roambox_max_x) { + roambox_destination_x = static_cast(zone->random.Real(roambox_min_x, roambox_max_y)); + } + + if (roambox_destination_y == roambox_min_y || roambox_destination_y == roambox_max_y) { + roambox_destination_y = static_cast(zone->random.Real(roambox_min_y, roambox_max_y)); + } + + /** + * If mob was not spawned in water, let's not randomly roam them into water + * if the roam box was sloppily configured + */ + if (!this->GetWasSpawnedInWater()) { + if (zone->zonemap != nullptr && zone->watermap != nullptr) { + auto position = glm::vec3( + roambox_destination_x, + roambox_destination_y, + this->FindGroundZ(roambox_destination_x, roambox_destination_y, 5) + ); + + if (zone->watermap->InLiquid(position)) { + return; + } + } + } + this->FixZ(); Log(Logs::Detail, @@ -1681,7 +1707,9 @@ void NPC::AI_DoMovement() { roambox_destination_y); } - if (!CalculateNewPosition(roambox_destination_x, roambox_destination_y, GetFixedZ(m_Position), move_speed, true)) { + float new_z = this->FindGroundZ(m_Position.x, m_Position.y, 5) + GetZOffset(); + + if (!CalculateNewPosition(roambox_destination_x, roambox_destination_y, new_z, move_speed, true)) { time_until_can_move = Timer::GetCurrentTime() + RandomTimer(roambox_min_delay, roambox_delay); SetMoving(false); this->FixZ(); diff --git a/zone/water_map_v2.cpp b/zone/water_map_v2.cpp index 939b9be97..03ae76fa4 100644 --- a/zone/water_map_v2.cpp +++ b/zone/water_map_v2.cpp @@ -30,7 +30,7 @@ bool WaterMapV2::InLava(const glm::vec3& location) const { } bool WaterMapV2::InLiquid(const glm::vec3& location) const { - return InWater(location) || InLava(location); + return InWater(location) || InLava(location) || InVWater(location); } bool WaterMapV2::InPvP(const glm::vec3& location) const { diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index 083cc38ba..5e1f0dd82 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -455,7 +455,7 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b return true; } - if ((m_Position.x - x == 0) && (m_Position.y - y == 0)) {//spawn is at target coords + if ((m_Position.x - x == 0) && (m_Position.y - y == 0)) { //spawn is at target coords return false; } else if ((std::abs(m_Position.x - x) < 0.1) && (std::abs(m_Position.y - y) < 0.1)) { diff --git a/zone/zone.h b/zone/zone.h index c3d5fe8a6..5f8651d8b 100644 --- a/zone/zone.h +++ b/zone/zone.h @@ -212,10 +212,10 @@ public: void ReloadWorld(uint32 Option); void ReloadMerchants(); - Map* zonemap; - WaterMap* watermap; - IPathfinder *pathing; - NewZone_Struct newzone_data; + Map *zonemap; + WaterMap *watermap; + IPathfinder *pathing; + NewZone_Struct newzone_data; SpawnConditionManager spawn_conditions; From 3a7d18f32a0f0fd926bfd4e335a11697e546f585 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sat, 18 Aug 2018 22:48:12 -0500 Subject: [PATCH 15/44] Throttle Z calculations in roambox code, fix typo on fallback logic range --- zone/mob_ai.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 9c16dc9b6..1ed005033 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1666,8 +1666,14 @@ void NPC::AI_DoMovement() { roambox_destination_x = EQEmu::Clamp((GetX() + move_x), roambox_min_x, roambox_max_x); roambox_destination_y = EQEmu::Clamp((GetY() + move_y), roambox_min_y, roambox_max_y); + /** + * If our roambox was configured with large distances, chances of hitting the min or max end of + * the clamp is high, this causes NPC's to gather on the border of a box, to reduce clustering + * either lower the roambox distance or the code will do a simple random between min - max when it + * hits the min or max of the clamp + */ if (roambox_destination_x == roambox_min_x || roambox_destination_x == roambox_max_x) { - roambox_destination_x = static_cast(zone->random.Real(roambox_min_x, roambox_max_y)); + roambox_destination_x = static_cast(zone->random.Real(roambox_min_x, roambox_max_x)); } if (roambox_destination_y == roambox_min_y || roambox_destination_y == roambox_max_y) { @@ -1692,8 +1698,6 @@ void NPC::AI_DoMovement() { } } - this->FixZ(); - Log(Logs::Detail, Logs::NPCRoamBox, "Calculate | NPC: %s distance %.3f | min_x %.3f | max_x %.3f | final_x %.3f | min_y %.3f | max_y %.3f | final_y %.3f", @@ -1707,9 +1711,11 @@ void NPC::AI_DoMovement() { roambox_destination_y); } - float new_z = this->FindGroundZ(m_Position.x, m_Position.y, 5) + GetZOffset(); + if (fix_z_timer.Check()) { + this->FixZ(); + } - if (!CalculateNewPosition(roambox_destination_x, roambox_destination_y, new_z, move_speed, true)) { + if (!CalculateNewPosition(roambox_destination_x, roambox_destination_y, m_Position.z, move_speed, true)) { time_until_can_move = Timer::GetCurrentTime() + RandomTimer(roambox_min_delay, roambox_delay); SetMoving(false); this->FixZ(); From 86f1cedf9126a93357f4b3705bb255f240d90217 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sat, 18 Aug 2018 23:18:55 -0500 Subject: [PATCH 16/44] Add LOS checks into roambox logic to prevent scaling mountains and going over buildings, cpu cycle saves and logging added. Things are looking really good now --- zone/mob_ai.cpp | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 1ed005033..9a62ef15c 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1685,19 +1685,46 @@ void NPC::AI_DoMovement() { * if the roam box was sloppily configured */ if (!this->GetWasSpawnedInWater()) { - if (zone->zonemap != nullptr && zone->watermap != nullptr) { + if (zone->HasMap() && zone->HasWaterMap()) { auto position = glm::vec3( roambox_destination_x, roambox_destination_y, - this->FindGroundZ(roambox_destination_x, roambox_destination_y, 5) + (m_Position.z - 15) ); if (zone->watermap->InLiquid(position)) { + Log(Logs::Detail, + Logs::NPCRoamBox, "%s | My destination is in water and I don't belong there!", + this->GetCleanName()); + return; } } } + /** + * We check for line of sight because we dont' want NPC's scaling on top of buildings and over ridiculous + * mountains, this also peels back the frequency of pathing as well because we don't want to spam LOS checks + * so if we fail a LOS check to our randomly chosen destination, we roll another timer cycle and wait again + * + * This is also far nicer on CPU since roamboxes are heavy by nature + */ + if (!CheckLosFN( + roambox_destination_x, + roambox_destination_y, + m_Position.z + GetZOffset(), + this->GetSize())) { + + time_until_can_move = Timer::GetCurrentTime() + RandomTimer(roambox_min_delay, roambox_delay); + + Log(Logs::Detail, + Logs::NPCRoamBox, + "%s | Can't see where I want to go... I'll try something else...", + this->GetCleanName()); + + return; + } + Log(Logs::Detail, Logs::NPCRoamBox, "Calculate | NPC: %s distance %.3f | min_x %.3f | max_x %.3f | final_x %.3f | min_y %.3f | max_y %.3f | final_y %.3f", From 4c8018e4cabec486a683b1b8999ccf3bea5521c8 Mon Sep 17 00:00:00 2001 From: Trust Date: Fri, 24 Aug 2018 23:04:29 -0400 Subject: [PATCH 17/44] Prevent Gate if near bind location (Rule) and Heal on Gate (Rule) RULE_INT(NPC, NPCGatePercent, 5) // % at which the NPC Will attempt to gate at. RULE_BOOL(NPC, NPCGateNearBind, false) // Will NPC attempt to gate when near bind location? RULE_INT(NPC, NPCGateDistanceBind, 75) // Distance from bind before NPC will attempt to gate RULE_BOOL(NPC, NPCHealOnGate, true) // Will the NPC Heal on Gate. RULE_REAL(NPC, NPCHealOnGateAmount, 25) // How much the npc will heal on gate if enabled. --- common/ruletypes.h | 5 +++++ zone/mob_ai.cpp | 12 ++++++++---- zone/zoning.cpp | 4 ++++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index 71af49010..da08cb858 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -532,6 +532,11 @@ RULE_INT(NPC, NPCToNPCAggroTimerMin, 500) RULE_INT(NPC, NPCToNPCAggroTimerMax, 6000) RULE_BOOL(NPC, UseClassAsLastName, true) // Uses class archetype as LastName for npcs with none RULE_BOOL(NPC, NewLevelScaling, true) // Better level scaling, use old if new formulas would break your server +RULE_INT(NPC, NPCGatePercent, 5) // % at which the NPC Will attempt to gate at. +RULE_BOOL(NPC, NPCGateNearBind, false) // Will NPC attempt to gate when near bind location? +RULE_INT(NPC, NPCGateDistanceBind, 75) // Distance from bind before NPC will attempt to gate +RULE_BOOL(NPC, NPCHealOnGate, true) // Will the NPC Heal on Gate. +RULE_REAL(NPC, NPCHealOnGateAmount, 25) // How much the npc will heal on gate if enabled. RULE_CATEGORY_END() RULE_CATEGORY(Aggro) diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 9a62ef15c..dc8e3447f 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -201,10 +201,14 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes, bool bInnates // If min_hp !=0 then the spell list has specified // custom range and we're inside that range if we // made it here. The hard coded <=5 is for unspecified. - if (AIspells[i].min_hp != 0 || GetHPRatio() <= 5) - { - AIDoSpellCast(i, tar, mana_cost); - return true; + if (GetHPRatio() <= (RuleI(NPC, NPCGatePercent))) { + auto npcSpawnPoint = CastToNPC()->GetSpawnPoint(); + if (!RuleB(NPC, NPCGateNearBind) && DistanceNoZ(m_Position, npcSpawnPoint) < RuleI(NPC, NPCGateDistanceBind)) { + break; + } else { + AIDoSpellCast(i, tar, mana_cost); + return true; + } } break; } diff --git a/zone/zoning.cpp b/zone/zoning.cpp index cbd928f21..9dcf0a774 100644 --- a/zone/zoning.cpp +++ b/zone/zoning.cpp @@ -717,6 +717,10 @@ void Client::GoToSafeCoords(uint16 zone_id, uint16 instance_id) { void Mob::Gate(uint8 bindnum) { GoToBind(bindnum); + if (RuleB(NPC, NPCHealOnGate) && this->IsNPC() && this->GetHPRatio() <= RuleR(NPC, NPCHealOnGateAmount)) { + auto HealAmount = (RuleR(NPC, NPCHealOnGateAmount) / 100); + SetHP(int(this->GetMaxHP() * HealAmount)); + } } void Client::Gate(uint8 bindnum) { From 62f9816aa89fbaa37a3078428d3f0aedba1fd1ba Mon Sep 17 00:00:00 2001 From: Trust Date: Sat, 25 Aug 2018 19:46:37 -0400 Subject: [PATCH 18/44] Returned Logic from PR #766 --- zone/mob_ai.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index dc8e3447f..58088a35b 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -200,8 +200,8 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes, bool bInnates case SpellType_Escape: { // If min_hp !=0 then the spell list has specified // custom range and we're inside that range if we - // made it here. The hard coded <=5 is for unspecified. - if (GetHPRatio() <= (RuleI(NPC, NPCGatePercent))) { + // made it here. + if (AIspells[i].min_hp != 0 || GetHPRatio() <= (RuleI(NPC, NPCGatePercent))) { auto npcSpawnPoint = CastToNPC()->GetSpawnPoint(); if (!RuleB(NPC, NPCGateNearBind) && DistanceNoZ(m_Position, npcSpawnPoint) < RuleI(NPC, NPCGateDistanceBind)) { break; From eb3327970158bba58c6ea2cc7417ad3f05a11a28 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sun, 26 Aug 2018 22:19:56 -0400 Subject: [PATCH 19/44] Reset various pet command states This will prevent charm exploits --- zone/spell_effects.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index e7d182105..7e8db6930 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -3928,6 +3928,12 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) Mob* tempmob = GetOwner(); SetOwnerID(0); SetPetType(petNone); + SetHeld(false); + SetGHeld(false); + SetNoCast(false); + SetFocused(false); + SetPetStop(false); + SetPetRegroup(false); if(tempmob) { tempmob->SetPet(0); From 766dcc464e7312f11e7d0136b247c14eaa87c13d Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Mon, 27 Aug 2018 12:56:46 -0400 Subject: [PATCH 20/44] Fix crash --- zone/fearpath.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/fearpath.cpp b/zone/fearpath.cpp index 722e1e417..168dd2ce6 100644 --- a/zone/fearpath.cpp +++ b/zone/fearpath.cpp @@ -132,7 +132,7 @@ void Mob::ProcessFlee() Mob *hate_top = GetHateTop(); // If no special flee_percent check for Gray or Other con rates - if(GetLevelCon(hate_top->GetLevel(), GetLevel()) == CON_GRAY && fleeratio == 0 && RuleB(Combat, FleeGray)) { + if(hate_top != nullptr && GetLevelCon(hate_top->GetLevel(), GetLevel()) == CON_GRAY && fleeratio == 0 && RuleB(Combat, FleeGray)) { fleeratio = RuleI(Combat, FleeGrayHPRatio); } else if(fleeratio == 0) { fleeratio = RuleI(Combat, FleeHPRatio ); From 555c9004b9bbd45d009bf258f57b9195f0195153 Mon Sep 17 00:00:00 2001 From: Chris Miles Date: Mon, 27 Aug 2018 23:46:10 -0500 Subject: [PATCH 21/44] Update eqemu_server.pl [skip ci] --- utils/scripts/eqemu_server.pl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/utils/scripts/eqemu_server.pl b/utils/scripts/eqemu_server.pl index 9201a9e27..eed4a767e 100644 --- a/utils/scripts/eqemu_server.pl +++ b/utils/scripts/eqemu_server.pl @@ -40,7 +40,12 @@ if($Config{osname}=~/freebsd|linux/i){ if($Config{osname}=~/Win|MS/i){ $OS = "Windows"; } + $has_internet_connection = check_internet_connection(); +if(-e "skip_internet_connection_check.txt"){ + $has_internet_connection = 1; +} + ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(); if(-e "eqemu_server_skip_update.txt"){ From 12f19fd824512da20bcddc2f0d5f1f745b2d3411 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Tue, 28 Aug 2018 00:27:50 -0500 Subject: [PATCH 22/44] Update system_tables.txt [skip ci] --- utils/sql/system_tables.txt | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/utils/sql/system_tables.txt b/utils/sql/system_tables.txt index 7816fea21..a5692dabd 100644 --- a/utils/sql/system_tables.txt +++ b/utils/sql/system_tables.txt @@ -1,11 +1,10 @@ aa_ability aa_actions aa_effects -aa_required_level_cost -aa_ranks aa_rank_effects aa_rank_prereqs -task_activities +aa_ranks +aa_required_level_cost adventure_template adventure_template_entry adventure_template_entry_flavor @@ -18,6 +17,7 @@ char_create_combinations char_create_point_allocations class_skill damageshieldtypes +data_buckets doors faction_list faction_list_mod @@ -33,38 +33,39 @@ ground_spawns horses instance_list items -ldon_trap_templates ldon_trap_entries +ldon_trap_templates level_exp_mods +logsys_categories lootdrop lootdrop_entries loottable loottable_entries merc_armorinfo -merc_weaponinfo -merc_stats +merc_buffs +merc_inventory merc_merchant_entries merc_merchant_template_entries merc_merchant_templates -merc_stance_entries -merc_templates -merc_npc_types merc_name_types -merc_subtypes -merc_types +merc_npc_types merc_spell_list_entries merc_spell_lists -merc_buffs -mercs -merc_inventory +merc_stance_entries +merc_stats +merc_subtypes +merc_templates +merc_types +merc_weaponinfo merchantlist +mercs npc_emotes npc_faction npc_faction_entries npc_spells -npc_spells_entries npc_spells_effects npc_spells_effects_entries +npc_spells_entries npc_types npc_types_metadata npc_types_tint @@ -77,14 +78,15 @@ races saylink skill_caps spawn2 -spawn_conditions spawn_condition_values +spawn_conditions spawn_events spawnentry spawngroup spells_new start_zones starting_items +task_activities tasks tasksets titles From d4e0e8aea254b57c7fcbeb8dc9f451278b6b9097 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Tue, 28 Aug 2018 00:55:06 -0500 Subject: [PATCH 23/44] Revert LOS check code until further refinement --- zone/mob_ai.cpp | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 58088a35b..405ff3643 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1706,29 +1706,6 @@ void NPC::AI_DoMovement() { } } - /** - * We check for line of sight because we dont' want NPC's scaling on top of buildings and over ridiculous - * mountains, this also peels back the frequency of pathing as well because we don't want to spam LOS checks - * so if we fail a LOS check to our randomly chosen destination, we roll another timer cycle and wait again - * - * This is also far nicer on CPU since roamboxes are heavy by nature - */ - if (!CheckLosFN( - roambox_destination_x, - roambox_destination_y, - m_Position.z + GetZOffset(), - this->GetSize())) { - - time_until_can_move = Timer::GetCurrentTime() + RandomTimer(roambox_min_delay, roambox_delay); - - Log(Logs::Detail, - Logs::NPCRoamBox, - "%s | Can't see where I want to go... I'll try something else...", - this->GetCleanName()); - - return; - } - Log(Logs::Detail, Logs::NPCRoamBox, "Calculate | NPC: %s distance %.3f | min_x %.3f | max_x %.3f | final_x %.3f | min_y %.3f | max_y %.3f | final_y %.3f", From b92e83a465639126383c4217eac3c050cfedbf0e Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 3 Sep 2018 01:51:40 -0500 Subject: [PATCH 24/44] Fix client pathing Z while feared --- zone/mob.h | 2 +- zone/mob_ai.cpp | 42 ++++++++++++++++++++++++------------------ zone/waypoints.cpp | 36 ++++++++++++++++++++++-------------- 3 files changed, 47 insertions(+), 33 deletions(-) diff --git a/zone/mob.h b/zone/mob.h index 763fa61b7..4dafe2bf9 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -988,7 +988,7 @@ public: void SendToFixZ(float new_x, float new_y, float new_z); float GetZOffset() const; float GetDefaultRaceSize() const; - void FixZ(int32 z_find_offset = 5); + void FixZ(int32 z_find_offset = 5, bool fix_client_z = false); float GetFixedZ(glm::vec3 destination, int32 z_find_offset = 5); void NPCSpecialAttacks(const char* parse, int permtag, bool reset = true, bool remove = false); diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 405ff3643..fcc54f244 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -779,44 +779,50 @@ void Client::AI_Process() } } - if(RuleB(Combat, EnableFearPathing)){ - if(currently_fleeing) { + if (RuleB(Combat, EnableFearPathing)) { + if (currently_fleeing) { - if (fix_z_timer_engaged.Check()) - this->FixZ(); + if (fix_z_timer.Check()) + this->FixZ(5, true); - if(IsRooted()) { + if (IsRooted()) { //make sure everybody knows were not moving, for appearance sake - if(IsMoving()) - { - if(GetTarget()) + if (IsMoving()) { + if (GetTarget()) SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY())); SetCurrentSpeed(0); } //continue on to attack code, ensuring that we execute the engaged code engaged = true; - } else { - if(AI_movement_timer->Check()) { + } + else { + if (AI_movement_timer->Check()) { int speed = GetFearSpeed(); animation = speed; speed *= 2; SetCurrentSpeed(speed); // Check if we have reached the last fear point if ((std::abs(GetX() - m_FearWalkTarget.x) < 0.1) && - (std::abs(GetY() - m_FearWalkTarget.y) < 0.1)) { + (std::abs(GetY() - m_FearWalkTarget.y) < 0.1)) { // Calculate a new point to run to CalculateNewFearpoint(); } - if(!RuleB(Pathing, Fear) || !zone->pathing) + + if (!RuleB(Pathing, Fear) || !zone->pathing) CalculateNewPosition(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, speed, true); - else - { - bool WaypointChanged, NodeReached; + else { + bool waypoint_changed, node_reached; - glm::vec3 Goal = UpdatePath(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, - speed, WaypointChanged, NodeReached); + glm::vec3 Goal = UpdatePath( + m_FearWalkTarget.x, + m_FearWalkTarget.y, + m_FearWalkTarget.z, + speed, + waypoint_changed, + node_reached + ); - if(WaypointChanged) + if (waypoint_changed) tar_ndx = 20; CalculateNewPosition(Goal.x, Goal.y, Goal.z, speed); diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index 5e1f0dd82..36c996ce8 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -793,26 +793,34 @@ float Mob::GetFixedZ(glm::vec3 destination, int32 z_find_offset) { return new_z; } -void Mob::FixZ(int32 z_find_offset /*= 5*/) { +void Mob::FixZ(int32 z_find_offset /*= 5*/, bool fix_client_z /*= false*/) { glm::vec3 current_loc(m_Position); - float new_z = GetFixedZ(current_loc, z_find_offset); - if (!IsClient() && new_z != m_Position.z) { - if ((new_z > -2000) && new_z != BEST_Z_INVALID) { - if (RuleB(Map, MobZVisualDebug)) { - this->SendAppearanceEffect(78, 0, 0, 0, 0); - } + if (IsClient() && !fix_client_z) + return; - m_Position.z = new_z; + float new_z = GetFixedZ(current_loc, z_find_offset); + + if (new_z == m_Position.z) + return; + + if ((new_z > -2000) && new_z != BEST_Z_INVALID) { + if (RuleB(Map, MobZVisualDebug)) { + this->SendAppearanceEffect(78, 0, 0, 0, 0); } - else { - if (RuleB(Map, MobZVisualDebug)) { - this->SendAppearanceEffect(103, 0, 0, 0, 0); - } - Log(Logs::General, Logs::FixZ, "%s is failing to find Z %f", - this->GetCleanName(), std::abs(m_Position.z - new_z)); + m_Position.z = new_z; + } + else { + if (RuleB(Map, MobZVisualDebug)) { + this->SendAppearanceEffect(103, 0, 0, 0, 0); } + + Log(Logs::General, + Logs::FixZ, + "%s is failing to find Z %f", + this->GetCleanName(), + std::abs(m_Position.z - new_z)); } } From 6fc20939e816463d85e532cd9bca68d832e9a9df Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 3 Sep 2018 02:11:39 -0500 Subject: [PATCH 25/44] Fix for edge case with roambox water logic --- zone/mob_ai.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index fcc54f244..9fe43e1ea 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1702,6 +1702,14 @@ void NPC::AI_DoMovement() { (m_Position.z - 15) ); + /** + * If someone brought us into water when we naturally wouldn't path there, return to spawn + */ + if (zone->watermap->InLiquid(position) && zone->watermap->InLiquid(m_Position)) { + roambox_destination_x = m_SpawnPoint.x; + roambox_destination_y = m_SpawnPoint.y; + } + if (zone->watermap->InLiquid(position)) { Log(Logs::Detail, Logs::NPCRoamBox, "%s | My destination is in water and I don't belong there!", From fc071d1d2f3ed6aae43aeaff730b7efd0f4ca28c Mon Sep 17 00:00:00 2001 From: KimLS Date: Mon, 3 Sep 2018 00:20:43 -0700 Subject: [PATCH 26/44] Set CMP0074 --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 817af542c..aa2716c91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,7 @@ #EQEMU_MAP_DIR CMAKE_MINIMUM_REQUIRED(VERSION 2.8) +cmake_policy(SET CMP0074 NEW) #FindMySQL is located here so lets make it so CMake can find it SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/" ${CMAKE_MODULE_PATH}) From 9b09891aa58037b34a1bbb393bcbf94ed00278ef Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 3 Sep 2018 00:30:50 -0700 Subject: [PATCH 27/44] Revert "Adjusted zlib cmake to honor policy CMP0074 warning" --- CMakeLists.txt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a3e8e3949..aa2716c91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,8 +55,7 @@ ENDIF(MSVC OR MINGW) IF(MSVC) IF(CMAKE_CL_64) - SET(ZLIB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x64/include") - SET(ZLIB_LIBRARY "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x64/lib/zlib.lib") + SET(ZLIB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x64") SET(MYSQL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/mysql_x64") SET(LUA_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/luaj_x64") SET(OPENSSL_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/openssl_x64") @@ -69,8 +68,7 @@ IF(MSVC) SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/x64/Release/v110/dynamic") ENDIF() ELSE(CMAKE_CL_64) - SET(ZLIB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x86/include") - SET(ZLIB_LIBRARY "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x86/lib/zlib.lib") + SET(ZLIB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x86") SET(MYSQL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/mysql_x86") SET(LUA_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/luaj_x86") SET(SODIUM_INCLUDE_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/include") From d2340d3f2e0dbf3ba2106c28eae5f558be9a8298 Mon Sep 17 00:00:00 2001 From: KimLS Date: Mon, 3 Sep 2018 00:41:59 -0700 Subject: [PATCH 28/44] Fix for missing policy --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index aa2716c91..9f3694698 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,7 +28,9 @@ #EQEMU_MAP_DIR CMAKE_MINIMUM_REQUIRED(VERSION 2.8) -cmake_policy(SET CMP0074 NEW) +IF(POLICY CMP0074) + cmake_policy(SET CMP0074 NEW) +ENDIF() #FindMySQL is located here so lets make it so CMake can find it SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/" ${CMAKE_MODULE_PATH}) From 8a28e8500d9b8202545fc6fda5e65b98d0872436 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 3 Sep 2018 03:06:23 -0500 Subject: [PATCH 29/44] Make fear and fleeing respect navmesh for both clients and NPCs --- zone/fearpath.cpp | 29 +++++++++++++++-------------- zone/mob_ai.cpp | 8 ++++++-- zone/zone.cpp | 6 +++--- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/zone/fearpath.cpp b/zone/fearpath.cpp index 168dd2ce6..c73ec448e 100644 --- a/zone/fearpath.cpp +++ b/zone/fearpath.cpp @@ -155,42 +155,43 @@ void Mob::ProcessFlee() } } -void Mob::CalculateNewFearpoint() -{ - if(RuleB(Pathing, Fear) && zone->pathing) - { +void Mob::CalculateNewFearpoint() { + if (RuleB(Pathing, Fear) && zone->pathing) { auto Node = zone->pathing->GetRandomLocation(); if (Node.x != 0.0f || Node.y != 0.0f || Node.z != 0.0f) { ++Node.z; - m_FearWalkTarget = Node; + m_FearWalkTarget = Node; + currently_fleeing = true; + return; } - Log(Logs::Detail, Logs::None, "No path found to selected node. Falling through to old fear point selection."); + Log(Logs::Detail, + Logs::Pathing, + "No path found to selected node. Falling through to old fear point selection."); } - int loop = 0; + int loop = 0; float ranx, rany, ranz; currently_fleeing = true; while (loop < 100) //Max 100 tries { - int ran = 250 - (loop*2); + int ran = 250 - (loop * 2); loop++; - ranx = GetX()+zone->random.Int(0, ran-1)-zone->random.Int(0, ran-1); - rany = GetY()+zone->random.Int(0, ran-1)-zone->random.Int(0, ran-1); - ranz = FindGroundZ(ranx,rany); + ranx = GetX() + zone->random.Int(0, ran - 1) - zone->random.Int(0, ran - 1); + rany = GetY() + zone->random.Int(0, ran - 1) - zone->random.Int(0, ran - 1); + ranz = FindGroundZ(ranx, rany); if (ranz == BEST_Z_INVALID) continue; float fdist = ranz - GetZ(); - if (fdist >= -12 && fdist <= 12 && CheckCoordLosNoZLeaps(GetX(),GetY(),GetZ(),ranx,rany,ranz)) - { + if (fdist >= -12 && fdist <= 12 && CheckCoordLosNoZLeaps(GetX(), GetY(), GetZ(), ranx, rany, ranz)) { break; } } if (currently_fleeing) - m_FearWalkTarget = glm::vec3(ranx, rany, ranz); + m_FearWalkTarget = glm::vec3(ranx, rany, ranz); } diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 9fe43e1ea..2ba5cea7f 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1142,8 +1142,12 @@ void Mob::AI_Process() { bool WaypointChanged, NodeReached; glm::vec3 Goal = UpdatePath( - m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, - GetFearSpeed(), WaypointChanged, NodeReached + m_FearWalkTarget.x, + m_FearWalkTarget.y, + m_FearWalkTarget.z, + GetFearSpeed(), + WaypointChanged, + NodeReached ); if (WaypointChanged) diff --git a/zone/zone.cpp b/zone/zone.cpp index d43527c4f..3b9e5e513 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -904,10 +904,10 @@ bool Zone::Init(bool iStaticZone) { RuleManager::Instance()->LoadRules(&database, r_name.c_str()); } } - - zone->zonemap = Map::LoadMapFile(zone->map_name); + + zone->zonemap = Map::LoadMapFile(zone->map_name); zone->watermap = WaterMap::LoadWaterMapfile(zone->map_name); - zone->pathing = IPathfinder::Load(zone->map_name); + zone->pathing = IPathfinder::Load(zone->map_name); Log(Logs::General, Logs::Status, "Loading spawn conditions..."); if(!spawn_conditions.LoadSpawnConditions(short_name, instanceid)) { From 395cf2e8ce5c04682a1386cbc74fa89ed82e0579 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 3 Sep 2018 03:46:48 -0500 Subject: [PATCH 30/44] Roambox logic now uses navmesh --- zone/mob_ai.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 2ba5cea7f..854a9a339 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1741,7 +1741,20 @@ void NPC::AI_DoMovement() { this->FixZ(); } - if (!CalculateNewPosition(roambox_destination_x, roambox_destination_y, m_Position.z, move_speed, true)) { + bool waypoint_changed, node_reached; + + glm::vec3 Goal = UpdatePath( + roambox_destination_x, + roambox_destination_y, + GetGroundZ(roambox_destination_x, roambox_destination_y), + move_speed, + waypoint_changed, + node_reached + ); + + CalculateNewPosition(Goal.x, Goal.y, Goal.z, move_speed, true); + + if (m_Position.x == roambox_destination_x && m_Position.y == roambox_destination_y) { time_until_can_move = Timer::GetCurrentTime() + RandomTimer(roambox_min_delay, roambox_delay); SetMoving(false); this->FixZ(); From 4a4668b36a6de1905f8833f6752df37075443652 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 3 Sep 2018 03:54:15 -0500 Subject: [PATCH 31/44] Remove an unecessary costly z calc --- zone/mob_ai.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 854a9a339..ac40d30e4 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1746,7 +1746,7 @@ void NPC::AI_DoMovement() { glm::vec3 Goal = UpdatePath( roambox_destination_x, roambox_destination_y, - GetGroundZ(roambox_destination_x, roambox_destination_y), + m_Position.z, move_speed, waypoint_changed, node_reached From 3eee699a890e1f31cdb57ac00cba961485b484c3 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 3 Sep 2018 04:07:13 -0500 Subject: [PATCH 32/44] Calculate roambox destination z once and let navmesh pathfinding calculate it the rest of the time --- zone/mob_ai.cpp | 13 ++++++++----- zone/npc.h | 1 + 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index ac40d30e4..bf09feb73 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -466,6 +466,7 @@ void NPC::AI_Init() roambox_distance = 0; roambox_destination_x = 0; roambox_destination_y = 0; + roambox_destination_z = 0; roambox_min_delay = 2500; roambox_delay = 2500; } @@ -1724,6 +1725,12 @@ void NPC::AI_DoMovement() { } } + glm::vec3 destination; + destination.x = roambox_destination_x; + destination.y = roambox_destination_y; + destination.z = m_Position.z; + roambox_destination_z = GetFixedZ(destination) + this->GetZOffset(); + Log(Logs::Detail, Logs::NPCRoamBox, "Calculate | NPC: %s distance %.3f | min_x %.3f | max_x %.3f | final_x %.3f | min_y %.3f | max_y %.3f | final_y %.3f", @@ -1737,16 +1744,12 @@ void NPC::AI_DoMovement() { roambox_destination_y); } - if (fix_z_timer.Check()) { - this->FixZ(); - } - bool waypoint_changed, node_reached; glm::vec3 Goal = UpdatePath( roambox_destination_x, roambox_destination_y, - m_Position.z, + roambox_destination_z, move_speed, waypoint_changed, node_reached diff --git a/zone/npc.h b/zone/npc.h index 52c8b2171..ec2676f60 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -540,6 +540,7 @@ protected: float roambox_distance; float roambox_destination_x; float roambox_destination_y; + float roambox_destination_z; uint32 roambox_delay; uint32 roambox_min_delay; From 935dde797c4a242a17346c6e8fcf78ba33039e6d Mon Sep 17 00:00:00 2001 From: Trust Date: Mon, 3 Sep 2018 09:34:14 -0400 Subject: [PATCH 33/44] Prevents players from /assist to see if a mob is up due to error or no error messages. --- zone/client_packet.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 5cafbaee2..8fee2460a 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -2950,7 +2950,11 @@ void Client::Handle_OP_Assist(const EQApplicationPacket *app) Distance(m_Position, assistee->GetPosition()) <= TARGETING_RANGE)) { SetAssistExemption(true); eid->entity_id = new_target->GetID(); + } else { + eid->entity_id = 0; } + } else { + eid->entity_id = 0; } } From 7c298a249f40b93736b7a8b8eb6a4e6ed47e6d85 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Tue, 4 Sep 2018 20:27:43 -0500 Subject: [PATCH 34/44] Pets now use navmesh --- zone/mob_ai.cpp | 81 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 60 insertions(+), 21 deletions(-) diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index bf09feb73..5fd422035 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1557,26 +1557,46 @@ void Mob::AI_Process() { case SPO_Follow: { Mob *owner = GetOwner(); - if (owner == nullptr) + if (owner == nullptr) { break; + } - glm::vec4 ownerPos = owner->GetPosition(); - float dist = DistanceSquared(m_Position, ownerPos); - float distz = ownerPos.z - m_Position.z; + glm::vec4 pet_owner_position = owner->GetPosition(); + float distance_to_owner = DistanceSquared(m_Position, pet_owner_position); + float z_distance = pet_owner_position.z - m_Position.z; - if (dist >= 400 || distz > 100) { - int speed = GetWalkspeed(); - if (dist >= 1225) // 35 - speed = GetRunspeed(); + if (distance_to_owner >= 400 || z_distance > 100) { - if (dist >= 202500 || distz > 100) // dist >= 450 - { - m_Position = ownerPos; + int pet_speed = GetWalkspeed(); + + /** + * Distance: >= 35 (Run if far away) + */ + if (distance_to_owner >= 1225) { + pet_speed = GetRunspeed(); + } + + /** + * Distance: >= 450 (Snap to owner) + */ + if (distance_to_owner >= 202500 || z_distance > 100) { + m_Position = pet_owner_position; SendPositionUpdate(); moved = true; } else { - CalculateNewPosition(owner->GetX(), owner->GetY(), owner->GetZ(), speed); + + bool waypoint_changed, node_reached; + glm::vec3 Goal = UpdatePath( + owner->GetX(), + owner->GetY(), + owner->GetZ(), + pet_speed, + waypoint_changed, + node_reached + ); + + CalculateNewPosition(Goal.x, Goal.y, Goal.z, pet_speed, true); } } else { @@ -1601,24 +1621,43 @@ void Mob::AI_Process() { break; } } - if (IsPetRegroup()) + if (IsPetRegroup()) { return; + } } /* Entity has been assigned another entity to follow */ else if (GetFollowID()) { - Mob *follow = entity_list.GetMob(GetFollowID()); - if (!follow) { SetFollowID(0); } + Mob *follow = entity_list.GetMob(static_cast(GetFollowID())); + if (!follow) { + SetFollowID(0); + } else { - float dist2 = DistanceSquared(m_Position, follow->GetPosition()); - int followdist = GetFollowDistance(); - if (dist2 >= followdist) // Default follow distance is 100 - { + float distance = DistanceSquared(m_Position, follow->GetPosition()); + int follow_distance = GetFollowDistance(); + + /** + * Default follow distance is 100 + */ + if (distance >= follow_distance) { int speed = GetWalkspeed(); - if (dist2 >= followdist + 150) { + + if (distance >= follow_distance + 150) { speed = GetRunspeed(); } - CalculateNewPosition(follow->GetX(), follow->GetY(), follow->GetZ(), speed); + + bool waypoint_changed, node_reached; + + glm::vec3 Goal = UpdatePath( + follow->GetX(), + follow->GetY(), + follow->GetZ(), + speed, + waypoint_changed, + node_reached + ); + + CalculateNewPosition(Goal.x, Goal.y, Goal.z, speed, true); } else { moved = false; From 2d84029b37e5ea20684ea93a8ae50d7bec24ecdb Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Fri, 7 Sep 2018 23:54:40 -0400 Subject: [PATCH 35/44] Add FastRegen* to zone table --- common/eq_packet_structs.h | 5 ++++- common/patches/rof.cpp | 6 +++--- common/patches/rof2.cpp | 6 +++--- common/patches/rof_structs.h | 6 +++--- common/patches/sod.cpp | 7 ++++--- common/patches/sod_structs.h | 6 +++--- common/patches/sof.cpp | 6 +++--- common/patches/sof_structs.h | 6 +++--- common/patches/uf.cpp | 6 +++--- common/patches/uf_structs.h | 6 +++--- common/ruletypes.h | 3 --- common/version.h | 2 +- utils/sql/db_update_manifest.txt | 1 + utils/sql/git/required/2018_09_07_FastRegen.sql | 3 +++ zone/bot.cpp | 6 +++--- zone/client_mods.cpp | 9 +++------ zone/merc.cpp | 6 +++--- zone/zonedb.cpp | 9 ++++++++- 18 files changed, 54 insertions(+), 45 deletions(-) create mode 100644 utils/sql/git/required/2018_09_07_FastRegen.sql diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index a35c264e0..c4cbea4fb 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -376,7 +376,10 @@ struct NewZone_Struct { /*0692*/ uint8 unknown692[8]; /*0700*/ float fog_density; /*0704*/ uint32 SuspendBuffs; -/*0704*/ +/*0708*/ uint32 FastRegenHP; +/*0712*/ uint32 FastRegenMana; +/*0716*/ uint32 FastRegenEndurance; +/*0720*/ }; /* diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index 6faabf88c..4364c9cb1 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -1811,6 +1811,9 @@ namespace RoF OUT(zone_id); OUT(zone_instance); OUT(SuspendBuffs); + OUT(FastRegenHP); + OUT(FastRegenMana); + OUT(FastRegenEndurance); eq->FogDensity = emu->fog_density; @@ -1827,9 +1830,6 @@ namespace RoF eq->unknown893 = 0; eq->fall_damage = 0; // 0 = Fall Damage on, 1 = Fall Damage off eq->unknown895 = 0; - eq->unknown896 = 180; - eq->unknown900 = 180; - eq->unknown904 = 180; eq->unknown908 = 2; eq->unknown912 = 2; eq->unknown932 = -1; // Set from PoK Example diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index 9cba1d0b4..99909cb16 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -1880,6 +1880,9 @@ namespace RoF2 OUT(zone_id); OUT(zone_instance); OUT(SuspendBuffs); + OUT(FastRegenHP); + OUT(FastRegenMana); + OUT(FastRegenEndurance); eq->FogDensity = emu->fog_density; @@ -1903,9 +1906,6 @@ namespace RoF2 eq->bNoFear = 0; eq->fall_damage = 0; // 0 = Fall Damage on, 1 = Fall Damage off eq->unknown895 = 0; - eq->FastRegenHP = 180; - eq->FastRegenMana = 180; - eq->FastRegenEndurance = 180; eq->CanPlaceCampsite = 2; eq->CanPlaceGuildBanner = 2; eq->FishingRelated = -1; // Set from PoK Example diff --git a/common/patches/rof_structs.h b/common/patches/rof_structs.h index dcc5e4ccc..885a9aa80 100644 --- a/common/patches/rof_structs.h +++ b/common/patches/rof_structs.h @@ -588,9 +588,9 @@ struct NewZone_Struct { /*0893*/ uint8 unknown893; // Seen 0 - 00 /*0894*/ uint8 fall_damage; // 0 = Fall Damage on, 1 = Fall Damage off /*0895*/ uint8 unknown895; // Seen 0 - 00 -/*0896*/ uint32 unknown896; // Seen 180 -/*0900*/ uint32 unknown900; // Seen 180 -/*0904*/ uint32 unknown904; // Seen 180 +/*0896*/ uint32 FastRegenHP; // Seen 180 +/*0900*/ uint32 FastRegenMana; // Seen 180 +/*0904*/ uint32 FastRegenEndurance; // Seen 180 /*0908*/ uint32 unknown908; // Seen 2 /*0912*/ uint32 unknown912; // Seen 2 /*0916*/ float FogDensity; // Most zones have this set to 0.33 Blightfire had 0.16 diff --git a/common/patches/sod.cpp b/common/patches/sod.cpp index 425341af7..772dcc178 100644 --- a/common/patches/sod.cpp +++ b/common/patches/sod.cpp @@ -1341,6 +1341,10 @@ namespace SoD OUT(zone_id); OUT(zone_instance); OUT(SuspendBuffs); + OUT(FastRegenHP); + OUT(FastRegenMana); + OUT(FastRegenEndurance); + /*fill in some unknowns with observed values, hopefully it will help */ eq->unknown800 = -1; eq->unknown844 = 600; @@ -1354,9 +1358,6 @@ namespace SoD eq->unknown893 = 0; eq->fall_damage = 0; // 0 = Fall Damage on, 1 = Fall Damage off eq->unknown895 = 0; - eq->unknown896 = 180; - eq->unknown900 = 180; - eq->unknown904 = 180; eq->unknown908 = 2; eq->unknown912 = 2; eq->FogDensity = emu->fog_density; diff --git a/common/patches/sod_structs.h b/common/patches/sod_structs.h index 80d0faae9..57e37c957 100644 --- a/common/patches/sod_structs.h +++ b/common/patches/sod_structs.h @@ -456,9 +456,9 @@ struct NewZone_Struct { /*0893*/ uint8 unknown893; //seen 0 - 00 /*0894*/ uint8 fall_damage; // 0 = Fall Damage on, 1 = Fall Damage off /*0895*/ uint8 unknown895; //seen 0 - 00 -/*0896*/ uint32 unknown896; //seen 180 -/*0900*/ uint32 unknown900; //seen 180 -/*0904*/ uint32 unknown904; //seen 180 +/*0896*/ uint32 FastRegenHP; //seen 180 +/*0900*/ uint32 FastRegenMana; //seen 180 +/*0904*/ uint32 FastRegenEndurance; //seen 180 /*0908*/ uint32 unknown908; //seen 2 /*0912*/ uint32 unknown912; //seen 2 /*0916*/ float FogDensity; //Of about 10 or so zones tested, all but one have this set to 0.33 Blightfire had 0.16 diff --git a/common/patches/sof.cpp b/common/patches/sof.cpp index 7051a5eeb..85f326edb 100644 --- a/common/patches/sof.cpp +++ b/common/patches/sof.cpp @@ -1020,6 +1020,9 @@ namespace SoF OUT(zone_id); OUT(zone_instance); OUT(SuspendBuffs); + OUT(FastRegenHP); + OUT(FastRegenMana); + OUT(FastRegenEndurance); /*fill in some unknowns with observed values, hopefully it will help */ eq->unknown796 = -1; @@ -1034,9 +1037,6 @@ namespace SoF eq->unknown889 = 0; eq->fall_damage = 0; // 0 = Fall Damage on, 1 = Fall Damage off eq->unknown891 = 0; - eq->unknown892 = 180; - eq->unknown896 = 180; - eq->unknown900 = 180; eq->unknown904 = 2; eq->unknown908 = 2; diff --git a/common/patches/sof_structs.h b/common/patches/sof_structs.h index a312b48a8..527341c93 100644 --- a/common/patches/sof_structs.h +++ b/common/patches/sof_structs.h @@ -460,9 +460,9 @@ struct NewZone_Struct { /*0893*/ uint8 unknown889; //seen 0 - 00 /*0894*/ uint8 fall_damage; // 0 = Fall Damage on, 1 = Fall Damage off /*0895*/ uint8 unknown891; //seen 0 - 00 -/*0892*/ uint32 unknown892; //seen 180 -/*0896*/ uint32 unknown896; //seen 180 -/*0900*/ uint32 unknown900; //seen 180 +/*0892*/ uint32 FastRegenHP; //seen 180 +/*0896*/ uint32 FastRegenMana; //seen 180 +/*0900*/ uint32 FastRegenEndurance; //seen 180 /*0904*/ uint32 unknown904; //seen 2 /*0908*/ uint32 unknown908; //seen 2 /*0912*/ diff --git a/common/patches/uf.cpp b/common/patches/uf.cpp index 869685e47..840c6fcd7 100644 --- a/common/patches/uf.cpp +++ b/common/patches/uf.cpp @@ -1565,6 +1565,9 @@ namespace UF OUT(zone_id); OUT(zone_instance); OUT(SuspendBuffs); + OUT(FastRegenHP); + OUT(FastRegenMana); + OUT(FastRegenEndurance); eq->FogDensity = emu->fog_density; @@ -1581,9 +1584,6 @@ namespace UF eq->unknown893 = 0; eq->fall_damage = 0; // 0 = Fall Damage on, 1 = Fall Damage off eq->unknown895 = 0; - eq->unknown896 = 180; - eq->unknown900 = 180; - eq->unknown904 = 180; eq->unknown908 = 2; eq->unknown912 = 2; diff --git a/common/patches/uf_structs.h b/common/patches/uf_structs.h index 02361cf1f..fe58b73b2 100644 --- a/common/patches/uf_structs.h +++ b/common/patches/uf_structs.h @@ -456,9 +456,9 @@ struct NewZone_Struct { /*0893*/ uint8 unknown893; //seen 0 - 00 /*0894*/ uint8 fall_damage; // 0 = Fall Damage on, 1 = Fall Damage off /*0895*/ uint8 unknown895; //seen 0 - 00 -/*0896*/ uint32 unknown896; //seen 180 -/*0900*/ uint32 unknown900; //seen 180 -/*0904*/ uint32 unknown904; //seen 180 +/*0896*/ uint32 FastRegenHP; //seen 180 +/*0900*/ uint32 FastRegenMana; //seen 180 +/*0904*/ uint32 FastRegenEndurance; //seen 180 /*0908*/ uint32 unknown908; //seen 2 /*0912*/ uint32 unknown912; //seen 2 /*0916*/ float FogDensity; //Of about 10 or so zones tested, all but one have this set to 0.33 Blightfire had 0.16 diff --git a/common/ruletypes.h b/common/ruletypes.h index 3e6965150..c2f11c1c3 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -94,9 +94,6 @@ RULE_INT(Character, SkillUpModifier, 100) //skill ups are at 100% RULE_BOOL(Character, SharedBankPlat, false) //off by default to prevent duping for now RULE_BOOL(Character, BindAnywhere, false) RULE_BOOL(Character, RestRegenEnabled, true) // Enable OOC Regen -RULE_INT(Character, RestRegenHP, 180) // seconds until full from 0. this is actually zone setable, but most or all zones are 180 -RULE_INT(Character, RestRegenMana, 180) // seconds until full from 0. this is actually zone setable, but most or all zones are 180 -RULE_INT(Character, RestRegenEnd, 180) // seconds until full from 0. this is actually zone setable, but most or all zones are 180 RULE_INT(Character, RestRegenTimeToActivate, 30) // Time in seconds for rest state regen to kick in. RULE_INT(Character, RestRegenRaidTimeToActivate, 300) // Time in seconds for rest state regen to kick in with a raid target. RULE_INT(Character, KillsPerGroupLeadershipAA, 250) // Number of dark blues or above per Group Leadership AA diff --git a/common/version.h b/common/version.h index b95c8ec1d..a6ea279c5 100644 --- a/common/version.h +++ b/common/version.h @@ -30,7 +30,7 @@ Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9125 +#define CURRENT_BINARY_DATABASE_VERSION 9126 #ifdef BOTS #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9019 #else diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 22a593176..fc2fb2391 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -379,6 +379,7 @@ 9123|2018_07_07_data_buckets.sql|SHOW TABLES LIKE 'data_buckets'|empty| 9124|2018_07_09_tasks.sql|SHOW COLUMNS FROM `tasks` LIKE 'type'|empty| 9125|2018_07_20_task_emote.sql|SHOW COLUMNS FROM `tasks` LIKE 'completion_emote'|empty| +9126|2018_09_07_FastRegen.sql|SHOW COLUMNS FROM `zone` LIKE 'FastRegenHP'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/required/2018_09_07_FastRegen.sql b/utils/sql/git/required/2018_09_07_FastRegen.sql new file mode 100644 index 000000000..de44b147d --- /dev/null +++ b/utils/sql/git/required/2018_09_07_FastRegen.sql @@ -0,0 +1,3 @@ +ALTER TABLE `zone` ADD `FastRegenHP` INT NOT NULL DEFAULT '180'; +ALTER TABLE `zone` ADD `FastRegenMana` INT NOT NULL DEFAULT '180'; +ALTER TABLE `zone` ADD `FastRegenEndurance` INT NOT NULL DEFAULT '180'; diff --git a/zone/bot.cpp b/zone/bot.cpp index 4c982d7ac..8ba9ea36c 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -7021,9 +7021,9 @@ void Bot::CalcRestState() { } } - RestRegenHP = 6 * (GetMaxHP() / RuleI(Character, RestRegenHP)); - RestRegenMana = 6 * (GetMaxMana() / RuleI(Character, RestRegenMana)); - RestRegenEndurance = 6 * (GetMaxEndurance() / RuleI(Character, RestRegenEnd)); + RestRegenHP = 6 * (GetMaxHP() / zone->newzone_data.FastRegenHP); + RestRegenMana = 6 * (GetMaxMana() / zone->newzone_data.FastRegenMana)); + RestRegenEndurance = 6 * (GetMaxEndurance() / zone->newzone_data.FastRegenEndurance); } int32 Bot::LevelRegen() { diff --git a/zone/client_mods.cpp b/zone/client_mods.cpp index f342fff9f..39c37c874 100644 --- a/zone/client_mods.cpp +++ b/zone/client_mods.cpp @@ -290,9 +290,8 @@ int32 Client::CalcHPRegen(bool bCombat) // another check for IsClient && !(base + item_regen) && Cur_HP <= 0 do --base; do later if (!bCombat && CanFastRegen() && (IsSitting() || CanMedOnHorse())) { - auto fast_mod = RuleI(Character, RestRegenHP); // TODO: this is actually zone based auto max_hp = GetMaxHP(); - int fast_regen = 6 * (max_hp / fast_mod); + int fast_regen = 6 * (max_hp / zone->newzone_data.FastRegenHP); if (base < fast_regen) // weird, but what the client is doing base = fast_regen; } @@ -1296,9 +1295,8 @@ int32 Client::CalcManaRegen(bool bCombat) regen = regen * 100.0f * AreaManaRegen * 0.01f + 0.5f; if (!bCombat && CanFastRegen() && (IsSitting() || CanMedOnHorse())) { - auto fast_mod = RuleI(Character, RestRegenMana); // TODO: this is actually zone based auto max_mana = GetMaxMana(); - int fast_regen = 6 * (max_mana / fast_mod); + int fast_regen = 6 * (max_mana / zone->newzone_data.FastRegenMana); if (regen < fast_regen) // weird, but what the client is doing regen = fast_regen; } @@ -2264,9 +2262,8 @@ int32 Client::CalcEnduranceRegen(bool bCombat) int regen = base; if (!bCombat && CanFastRegen() && (IsSitting() || CanMedOnHorse())) { - auto fast_mod = RuleI(Character, RestRegenEnd); // TODO: this is actually zone based auto max_end = GetMaxEndurance(); - int fast_regen = 6 * (max_end / fast_mod); + int fast_regen = 6 * (max_end / zone->newzone_data.FastRegenEndurance); if (aa_regen < fast_regen) // weird, but what the client is doing aa_regen = fast_regen; } diff --git a/zone/merc.cpp b/zone/merc.cpp index a4b331fff..42a7f0290 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -1174,11 +1174,11 @@ void Merc::CalcRestState() { } } - RestRegenHP = 6 * (GetMaxHP() / RuleI(Character, RestRegenHP)); + RestRegenHP = 6 * (GetMaxHP() / zone->newzone_data.FastRegenHP); - RestRegenMana = 6 * (GetMaxMana() / RuleI(Character, RestRegenMana)); + RestRegenMana = 6 * (GetMaxMana() / zone->newzone_data.FastRegenMana); - RestRegenEndurance = 6 * (GetMaxEndurance() / RuleI(Character, RestRegenEnd)); + RestRegenEndurance = 6 * (GetMaxEndurance() / zone->newzone_data.FastRegenEndurance); } bool Merc::HasSkill(EQEmu::skills::SkillType skill_id) const { diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index f79288126..59a85b79b 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -143,7 +143,10 @@ bool ZoneDatabase::GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct "snow_duration2, " // 53 "snow_duration3, " // 54 "snow_duration4, " // 55 - "gravity " // 56 + "gravity, " // 56 + "FastRegenHP, " // 57 + "FastRegenMana, " // 58 + "FastRegenEndurance, " // 59 "FROM zone WHERE zoneidnumber = %i AND version = %i", zoneid, instance_id); auto results = QueryDatabase(query); @@ -188,6 +191,10 @@ bool ZoneDatabase::GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct Log(Logs::General, Logs::Debug, "Zone Gravity is %f", zone_data->gravity); allow_mercs = true; + zone_data->FastRegenHP = atoi(row[57]); + zone_data->FastRegenMana = atoi(row[58]); + zone_data->FastRegenEndurance = atoi(row[59]); + int bindable = 0; bindable = atoi(row[31]); From 4276bf320899b6dbf1818edc4460c485b1274751 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Fri, 7 Sep 2018 23:55:51 -0400 Subject: [PATCH 36/44] Too many commas --- zone/zonedb.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 59a85b79b..0db41f51c 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -146,7 +146,7 @@ bool ZoneDatabase::GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct "gravity, " // 56 "FastRegenHP, " // 57 "FastRegenMana, " // 58 - "FastRegenEndurance, " // 59 + "FastRegenEndurance " // 59 "FROM zone WHERE zoneidnumber = %i AND version = %i", zoneid, instance_id); auto results = QueryDatabase(query); From 00e44285a77ee7ab0c42786f2ad763d13c453c2b Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sat, 8 Sep 2018 00:09:14 -0400 Subject: [PATCH 37/44] Fix column cases to make people happy If you already sourced, too fucking bad. --- utils/sql/db_update_manifest.txt | 2 +- utils/sql/git/required/2018_09_07_FastRegen.sql | 6 +++--- zone/zonedb.cpp | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index fc2fb2391..d0efc8d74 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -379,7 +379,7 @@ 9123|2018_07_07_data_buckets.sql|SHOW TABLES LIKE 'data_buckets'|empty| 9124|2018_07_09_tasks.sql|SHOW COLUMNS FROM `tasks` LIKE 'type'|empty| 9125|2018_07_20_task_emote.sql|SHOW COLUMNS FROM `tasks` LIKE 'completion_emote'|empty| -9126|2018_09_07_FastRegen.sql|SHOW COLUMNS FROM `zone` LIKE 'FastRegenHP'|empty| +9126|2018_09_07_FastRegen.sql|SHOW COLUMNS FROM `zone` LIKE 'fast_regen_hp'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/required/2018_09_07_FastRegen.sql b/utils/sql/git/required/2018_09_07_FastRegen.sql index de44b147d..d9c52acf7 100644 --- a/utils/sql/git/required/2018_09_07_FastRegen.sql +++ b/utils/sql/git/required/2018_09_07_FastRegen.sql @@ -1,3 +1,3 @@ -ALTER TABLE `zone` ADD `FastRegenHP` INT NOT NULL DEFAULT '180'; -ALTER TABLE `zone` ADD `FastRegenMana` INT NOT NULL DEFAULT '180'; -ALTER TABLE `zone` ADD `FastRegenEndurance` INT NOT NULL DEFAULT '180'; +ALTER TABLE `zone` ADD `fast_regen_hp` INT NOT NULL DEFAULT '180'; +ALTER TABLE `zone` ADD `fast_regen_mana` INT NOT NULL DEFAULT '180'; +ALTER TABLE `zone` ADD `fast_regen_endurance` INT NOT NULL DEFAULT '180'; diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 0db41f51c..b08b0d32d 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -143,10 +143,10 @@ bool ZoneDatabase::GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct "snow_duration2, " // 53 "snow_duration3, " // 54 "snow_duration4, " // 55 - "gravity, " // 56 - "FastRegenHP, " // 57 - "FastRegenMana, " // 58 - "FastRegenEndurance " // 59 + "gravity, " // 56 + "fast_regen_hp, " // 57 + "fast_regen_mana, " // 58 + "fast_regen_endurance " // 59 "FROM zone WHERE zoneidnumber = %i AND version = %i", zoneid, instance_id); auto results = QueryDatabase(query); From ec40b3dc698766307d283c1a1b39a180ea276297 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sat, 8 Sep 2018 00:11:31 -0400 Subject: [PATCH 38/44] Fix bots --- zone/bot.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index 8ba9ea36c..a5dd4aa41 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -7022,7 +7022,7 @@ void Bot::CalcRestState() { } RestRegenHP = 6 * (GetMaxHP() / zone->newzone_data.FastRegenHP); - RestRegenMana = 6 * (GetMaxMana() / zone->newzone_data.FastRegenMana)); + RestRegenMana = 6 * (GetMaxMana() / zone->newzone_data.FastRegenMana); RestRegenEndurance = 6 * (GetMaxEndurance() / zone->newzone_data.FastRegenEndurance); } From 7836d020ce6b88397580aa8186d1669910e295f9 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sat, 8 Sep 2018 00:22:16 -0400 Subject: [PATCH 39/44] Add NPC Max Aggro Distance to zone table --- common/eq_packet_structs.h | 3 ++- common/version.h | 2 +- utils/sql/db_update_manifest.txt | 1 + utils/sql/git/required/2018_09_07_NPCMaxAggroDist.sql | 1 + zone/mob_ai.cpp | 2 +- zone/zonedb.cpp | 4 +++- 6 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 utils/sql/git/required/2018_09_07_NPCMaxAggroDist.sql diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index c4cbea4fb..bde77822b 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -379,7 +379,8 @@ struct NewZone_Struct { /*0708*/ uint32 FastRegenHP; /*0712*/ uint32 FastRegenMana; /*0716*/ uint32 FastRegenEndurance; -/*0720*/ +/*0720*/ uint32 NPCAggroMaxDist; +/*0724*/ }; /* diff --git a/common/version.h b/common/version.h index a6ea279c5..a7e066ab1 100644 --- a/common/version.h +++ b/common/version.h @@ -30,7 +30,7 @@ Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9126 +#define CURRENT_BINARY_DATABASE_VERSION 9127 #ifdef BOTS #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9019 #else diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index d0efc8d74..e84395a54 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -380,6 +380,7 @@ 9124|2018_07_09_tasks.sql|SHOW COLUMNS FROM `tasks` LIKE 'type'|empty| 9125|2018_07_20_task_emote.sql|SHOW COLUMNS FROM `tasks` LIKE 'completion_emote'|empty| 9126|2018_09_07_FastRegen.sql|SHOW COLUMNS FROM `zone` LIKE 'fast_regen_hp'|empty| +9127|2018_09_07_NPCMaxAggroDist.sql|SHOW COLUMNS FROM `zone` LIKE 'npc_max_aggro_dist'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/required/2018_09_07_NPCMaxAggroDist.sql b/utils/sql/git/required/2018_09_07_NPCMaxAggroDist.sql new file mode 100644 index 000000000..239a483a5 --- /dev/null +++ b/utils/sql/git/required/2018_09_07_NPCMaxAggroDist.sql @@ -0,0 +1 @@ +ALTER TABLE `zone` ADD `npc_max_aggro_dist` INT NOT NULL DEFAULT '600'; diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 5fd422035..766929c97 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1194,7 +1194,7 @@ void Mob::AI_Process() { // NPCs will forget people after 10 mins of not interacting with them or out of range // both of these maybe zone specific, hardcoded for now if (hate_list_cleanup_timer.Check()) { - hate_list.RemoveStaleEntries(600000, 600.0f); + hate_list.RemoveStaleEntries(600000, static_cast(zone->newzone_data.NPCAggroMaxDist)); if (hate_list.IsHateListEmpty()) { AI_Event_NoLongerEngaged(); zone->DelAggroMob(); diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index b08b0d32d..cced38aac 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -146,7 +146,8 @@ bool ZoneDatabase::GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct "gravity, " // 56 "fast_regen_hp, " // 57 "fast_regen_mana, " // 58 - "fast_regen_endurance " // 59 + "fast_regen_endurance, " // 59 + "npc_max_aggro_dist " // 60 "FROM zone WHERE zoneidnumber = %i AND version = %i", zoneid, instance_id); auto results = QueryDatabase(query); @@ -194,6 +195,7 @@ bool ZoneDatabase::GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct zone_data->FastRegenHP = atoi(row[57]); zone_data->FastRegenMana = atoi(row[58]); zone_data->FastRegenEndurance = atoi(row[59]); + zone_data->NPCAggroMaxDist = atoi(row[60]); int bindable = 0; bindable = atoi(row[31]); From 08bd335cdb96524da69bde8f30b9c397f7d4fa2b Mon Sep 17 00:00:00 2001 From: Chris Miles Date: Sun, 9 Sep 2018 00:03:07 -0500 Subject: [PATCH 40/44] Update install.sh [skip ci] --- utils/scripts/linux_installer/install.sh | 50 ++++++++++++------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/utils/scripts/linux_installer/install.sh b/utils/scripts/linux_installer/install.sh index 8f6f2f4d4..64c376bb3 100644 --- a/utils/scripts/linux_installer/install.sh +++ b/utils/scripts/linux_installer/install.sh @@ -54,36 +54,38 @@ export apt_options="-y -qq" # Set autoconfirm and silent install ################################################################ +if [ ! -f ./install_variables.txt ]; then + read -n1 -r -p "Press any key to continue..." key + #::: Setting up user environment (eqemu) + echo "First, we need to set your passwords..." + echo "Make sure that you remember these and keep them somewhere" + echo "" + echo "" + groupadd eqemu + useradd -g eqemu -d $eqemu_server_directory eqemu + passwd eqemu -#::: Setting up user environment (eqemu) -echo "First, we need to set your passwords..." -echo "Make sure that you remember these and keep them somewhere" -echo "" -echo "" -groupadd eqemu -useradd -g eqemu -d $eqemu_server_directory eqemu -passwd eqemu + #::: Make server directory and go to it + mkdir $eqemu_server_directory + cd $eqemu_server_directory -#::: Make server directory and go to it -mkdir $eqemu_server_directory -cd $eqemu_server_directory + #::: Setup MySQL root user PW + read -p "Enter MySQL root (Database) password: " eqemu_db_root_password -#::: Setup MySQL root user PW -read -p "Enter MySQL root (Database) password: " eqemu_db_root_password + #::: Write install variables (later use) + echo "mysql_root:$eqemu_db_root_password" > install_variables.txt -#::: Write install variables (later use) -echo "mysql_root:$eqemu_db_root_password" > install_variables.txt + #::: Setup MySQL server + read -p "Enter Database Name (single word, no special characters, lower case):" eqemu_db_name + read -p "Enter (Database) MySQL EQEmu Server username: " eqemu_db_username + read -p "Enter (Database) MySQL EQEmu Server password: " eqemu_db_password -#::: Setup MySQL server -read -p "Enter Database Name (single word, no special characters, lower case):" eqemu_db_name -read -p "Enter (Database) MySQL EQEmu Server username: " eqemu_db_username -read -p "Enter (Database) MySQL EQEmu Server password: " eqemu_db_password - -#::: Write install variables (later use) -echo "mysql_eqemu_db_name:$eqemu_db_name" >> install_variables.txt -echo "mysql_eqemu_user:$eqemu_db_username" >> install_variables.txt -echo "mysql_eqemu_password:$eqemu_db_password" >> install_variables.txt + #::: Write install variables (later use) + echo "mysql_eqemu_db_name:$eqemu_db_name" >> install_variables.txt + echo "mysql_eqemu_user:$eqemu_db_username" >> install_variables.txt + echo "mysql_eqemu_password:$eqemu_db_password" >> install_variables.txt +fi if [[ "$OS" == "Debian" ]]; then # Install pre-req packages From 92eb64b51ceb650e033bbaf32c9ea0596a850065 Mon Sep 17 00:00:00 2001 From: Chris Miles Date: Sun, 9 Sep 2018 00:04:16 -0500 Subject: [PATCH 41/44] Update install.sh [skip ci] --- utils/scripts/linux_installer/install.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/scripts/linux_installer/install.sh b/utils/scripts/linux_installer/install.sh index 64c376bb3..386503119 100644 --- a/utils/scripts/linux_installer/install.sh +++ b/utils/scripts/linux_installer/install.sh @@ -56,7 +56,8 @@ export apt_options="-y -qq" # Set autoconfirm and silent install if [ ! -f ./install_variables.txt ]; then -read -n1 -r -p "Press any key to continue..." key + read -n1 -r -p "Press any key to continue..." key + #::: Setting up user environment (eqemu) echo "First, we need to set your passwords..." echo "Make sure that you remember these and keep them somewhere" From 55c0cc02a1c6567329f8397b14f5656dbcbe5edb Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 9 Sep 2018 02:27:04 -0500 Subject: [PATCH 42/44] Update eqemu_server.pl [skip ci] --- utils/scripts/eqemu_server.pl | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/utils/scripts/eqemu_server.pl b/utils/scripts/eqemu_server.pl index eed4a767e..29a8142a6 100644 --- a/utils/scripts/eqemu_server.pl +++ b/utils/scripts/eqemu_server.pl @@ -172,19 +172,19 @@ sub show_install_summary_info { if (-e "install_variables.txt") { $file_to_open = "install_variables.txt"; } - elsif(-e "../install_variables.txt"){ + elsif (-e "../install_variables.txt") { $file_to_open = "../install_variables.txt"; } - open (INSTALL_VARS, $file_to_open); - while (){ + open(INSTALL_VARS, $file_to_open); + while () { chomp; $o = $_; @data = split(":", $o); print " - " . $data[0] . "\t" . $data[1] . "\n"; } - close (INSTALL_VARS); - - if($OS eq "Windows"){ + close(INSTALL_VARS); + + if ($OS eq "Windows") { print "[Install] Windows Utility Scripts:\n"; print " - t_start_server.bat Starts EQEmu server with 30 dynamic zones, UCS & Queryserv, dynamic zones\n"; print " - t_start_server_with_loginserver.bat Starts EQEmu server with 30 zones with loginserver\n"; @@ -192,16 +192,16 @@ sub show_install_summary_info { print " - t_database_backup.bat Backs up the Database to backups/ folder - do not run during server is online\n"; print " - t_server_crash_report.pl Will parse any zone crashes for reporting to developers\n"; } - if($OS eq "Linux"){ + if ($OS eq "Linux") { print "[Install] Linux Utility Scripts:\n"; print " - server_start.sh Starts EQEmu server (Quiet) with 30 dynamic zones, UCS & Queryserv, dynamic zones\n"; print " - server_start_dev.sh Starts EQEmu server with 10 dynamic zones, UCS & Queryserv, dynamic zones all verbose\n"; print " - server_stop.sh Stops EQEmu Server (No warning)\n"; print " - server_status.sh Prints the status of the EQEmu Server processes\n"; } - + print "[Configure] eqemu_config.xml Edit to change server settings and name\n"; - + analytics_insertion("install_complete", "null"); } @@ -831,6 +831,7 @@ sub show_menu_prompt { elsif($input eq "setup_bots"){ setup_bots(); $dc = 1; } elsif($input eq "linux_login_server_setup"){ do_linux_login_server_setup(); $dc = 1; } elsif($input eq "quest_heading_convert"){ quest_heading_convert(); $dc = 1; } + elsif($input eq "source_peq_db"){ fetch_peq_db_full(); $dc = 1; } elsif($input eq "exit"){ exit; } From add25eb6179e3f2f831b6d52526fc7450b02379b Mon Sep 17 00:00:00 2001 From: chase Date: Mon, 10 Sep 2018 00:23:09 -0700 Subject: [PATCH 43/44] converting some remaining abs & fabs to use std::abs, fixing some warnings --- common/memory_buffer.h | 2 +- common/misc_functions.h | 2 +- common/patches/rof.cpp | 18 +++++++++--------- zone/aggro.cpp | 30 +++++++++--------------------- zone/client.cpp | 4 ++-- 5 files changed, 22 insertions(+), 34 deletions(-) diff --git a/common/memory_buffer.h b/common/memory_buffer.h index 880b860ae..474953f91 100644 --- a/common/memory_buffer.h +++ b/common/memory_buffer.h @@ -124,7 +124,7 @@ namespace EQEmu class OutBuffer : public std::stringstream { public: - inline size_t size() { return tellp(); } + inline size_t size() { return static_cast(tellp()); } void overwrite(OutBuffer::pos_type position, const char *_Str, std::streamsize _Count); uchar* detach(); }; diff --git a/common/misc_functions.h b/common/misc_functions.h index 2ead697e7..8a7ffd59a 100644 --- a/common/misc_functions.h +++ b/common/misc_functions.h @@ -73,7 +73,7 @@ uint32 SwapBits21And22(uint32 mask); uint32 Catch22(uint32 mask); // macro to catch fp errors (provided by noudness) -#define FCMP(a,b) (fabs(a-b) < FLT_EPSILON) +#define FCMP(a,b) (std::abs(a-b) < FLT_EPSILON) #define _ITOA_BUFLEN 25 const char *itoa(int num); //not thread safe diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index 4364c9cb1..143400bf6 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -2795,7 +2795,7 @@ namespace RoF std::vector skill; std::vector points; - for(auto i = 0; i < emu->total_prereqs; ++i) { + for(auto i = 0u; i < emu->total_prereqs; ++i) { skill.push_back(inapp->ReadUInt32()); points.push_back(inapp->ReadUInt32()); } @@ -2849,7 +2849,7 @@ namespace RoF outapp->WriteUInt32(emu->total_effects); inapp->SetReadPosition(sizeof(AARankInfo_Struct)); - for(auto i = 0; i < emu->total_effects; ++i) { + for(auto i = 0u; i < emu->total_effects; ++i) { outapp->WriteUInt32(inapp->ReadUInt32()); // skill_id outapp->WriteUInt32(inapp->ReadUInt32()); // base1 outapp->WriteUInt32(inapp->ReadUInt32()); // base2 @@ -2905,7 +2905,7 @@ namespace RoF unsigned char *eq_ptr = __packet->pBuffer; eq_ptr += sizeof(structs::CharacterSelect_Struct); - for (int counter = 0; counter < character_count; ++counter) { + for (auto counter = 0u; counter < character_count; ++counter) { emu_cse = (CharacterSelectEntry_Struct *)emu_ptr; eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; // base address @@ -3247,7 +3247,7 @@ namespace RoF InBuffer += title_size; TaskDescriptionData1_Struct *emu_tdd1 = (TaskDescriptionData1_Struct *)InBuffer; - emu_tdd1->StartTime = (time(nullptr) - emu_tdd1->StartTime); // RoF has elapsed time here rather than start time + emu_tdd1->StartTime = (static_cast(time(nullptr)) - emu_tdd1->StartTime); // RoF has elapsed time here rather than start time InBuffer += sizeof(TaskDescriptionData1_Struct); uint32 description_size = strlen(InBuffer) + 1; @@ -3598,10 +3598,10 @@ namespace RoF // calculate size of names, note the packet DOES NOT have null termed c-strings std::vector name_lengths; - for (int i = 0; i < count; ++i) { + for (auto i = 0u; i < count; ++i) { InternalVeteranReward *ivr = (InternalVeteranReward *)__emu_buffer; - for (int i = 0; i < ivr->claim_count; i++) { + for (auto i = 0u; i < ivr->claim_count; i++) { uint32 length = strnlen(ivr->items[i].item_name, 63); if (length) name_lengths.push_back(length); @@ -3621,7 +3621,7 @@ namespace RoF outapp->WriteUInt32(count); auto name_itr = name_lengths.begin(); - for (int i = 0; i < count; i++) { + for (auto i = 0u; i < count; i++) { InternalVeteranReward *ivr = (InternalVeteranReward *)__emu_buffer; outapp->WriteUInt32(ivr->claim_id); @@ -3629,7 +3629,7 @@ namespace RoF outapp->WriteUInt32(ivr->claim_count); outapp->WriteUInt8(1); // enabled - for (int j = 0; j < ivr->claim_count; j++) { + for (auto j = 0u; j < ivr->claim_count; j++) { assert(name_itr != name_lengths.end()); // the way it's written, it should never happen, so just assert outapp->WriteUInt32(*name_itr); outapp->WriteData(ivr->items[j].item_name, *name_itr); @@ -3857,7 +3857,7 @@ namespace RoF VARSTRUCT_ENCODE_STRING(Buffer, emu->name); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->spawnId); VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->level); - VARSTRUCT_ENCODE_TYPE(float, Buffer, SpawnSize - 0.7); // Eye Height? + VARSTRUCT_ENCODE_TYPE(float, Buffer, SpawnSize - 0.7f); // Eye Height? VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->NPC); structs::Spawn_Struct_Bitfields *Bitfields = (structs::Spawn_Struct_Bitfields*)Buffer; diff --git a/zone/aggro.cpp b/zone/aggro.cpp index f8162322e..ec7f61f1a 100644 --- a/zone/aggro.cpp +++ b/zone/aggro.cpp @@ -107,16 +107,10 @@ void NPC::DescribeAggro(Client *towho, Mob *mob, bool verbose) { float iAggroRange = GetAggroRange(); float t1, t2, t3; - t1 = mob->GetX() - GetX(); - t2 = mob->GetY() - GetY(); - t3 = mob->GetZ() - GetZ(); - //Cheap ABS() - if(t1 < 0) - t1 = 0 - t1; - if(t2 < 0) - t2 = 0 - t2; - if(t3 < 0) - t3 = 0 - t3; + t1 = std::abs(mob->GetX() - GetX()); + t2 = std::abs(mob->GetY() - GetY()); + t3 = std::abs(mob->GetZ() - GetZ()); + if(( t1 > iAggroRange) || ( t2 > iAggroRange) || ( t3 > iAggroRange) ) { @@ -271,16 +265,10 @@ bool Mob::CheckWillAggro(Mob *mob) { // Image: I moved this up by itself above faction and distance checks because if one of these return true, theres no reason to go through the other information float t1, t2, t3; - t1 = mob->GetX() - GetX(); - t2 = mob->GetY() - GetY(); - t3 = mob->GetZ() - GetZ(); - //Cheap ABS() - if(t1 < 0) - t1 = 0 - t1; - if(t2 < 0) - t2 = 0 - t2; - if(t3 < 0) - t3 = 0 - t3; + t1 = std::abs(mob->GetX() - GetX()); + t2 = std::abs(mob->GetY() - GetY()); + t3 = std::abs(mob->GetZ() - GetZ()); + if(( t1 > iAggroRange) || ( t2 > iAggroRange) || ( t3 > iAggroRange) @@ -526,7 +514,7 @@ void EntityList::AIYellForHelp(Mob* sender, Mob* attacker) { Log(Logs::General, Logs::None, "AIYellForHelp(\"%s\",\"%s\") %s attacking %s Dist %f Z %f", sender->GetName(), attacker->GetName(), mob->GetName(), attacker->GetName(), DistanceSquared(mob->GetPosition(), - sender->GetPosition()), fabs(sender->GetZ()+mob->GetZ())); + sender->GetPosition()), std::abs(sender->GetZ()+mob->GetZ())); #endif mob->AddToHateList(attacker, 25, 0, false); sender->AddAssistCap(); diff --git a/zone/client.cpp b/zone/client.cpp index 129293970..67cca5866 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -8103,9 +8103,9 @@ void Client::SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, ui { //The ole switcheroo if (npc_value[i] > 0) - npc_value[i] = -abs(npc_value[i]); + npc_value[i] = -std::abs(npc_value[i]); else if (npc_value[i] < 0) - npc_value[i] = abs(npc_value[i]); + npc_value[i] = std::abs(npc_value[i]); } // Adjust the amount you can go up or down so the resulting range From 953bee6c215417178532fba77c7e168008499be3 Mon Sep 17 00:00:00 2001 From: Uleat Date: Tue, 11 Sep 2018 20:05:43 -0400 Subject: [PATCH 44/44] Fix for crash when dropping items (c != python) --- zone/inventory.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/zone/inventory.cpp b/zone/inventory.cpp index 902268e2c..d4604852d 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -610,15 +610,15 @@ void Client::DropItem(int16 slot_id, bool recurse) if (LogSys.log_settings[Logs::Inventory].is_category_enabled) { Log(Logs::General, Logs::Inventory, "DropItem() Hack detected - full item parse:"); Log(Logs::General, Logs::Inventory, "depth: 0, Item: '%s' (id: %u), IsDroppable: %s", - (invalid_drop->GetItem() ? invalid_drop->GetItem()->Name : "null data"), invalid_drop->GetID(), invalid_drop->IsDroppable(false)); + (invalid_drop->GetItem() ? invalid_drop->GetItem()->Name : "null data"), invalid_drop->GetID(), (invalid_drop->IsDroppable(false) ? "true" : "false")); for (auto iter1 : *invalid_drop->GetContents()) { // depth 1 Log(Logs::General, Logs::Inventory, "-depth: 1, Item: '%s' (id: %u), IsDroppable: %s", - (iter1.second->GetItem() ? iter1.second->GetItem()->Name : "null data"), iter1.second->GetID(), iter1.second->IsDroppable(false)); + (iter1.second->GetItem() ? iter1.second->GetItem()->Name : "null data"), iter1.second->GetID(), (iter1.second->IsDroppable(false) ? "true" : "false")); for (auto iter2 : *iter1.second->GetContents()) { // depth 2 Log(Logs::General, Logs::Inventory, "--depth: 2, Item: '%s' (id: %u), IsDroppable: %s", - (iter2.second->GetItem() ? iter2.second->GetItem()->Name : "null data"), iter2.second->GetID(), iter2.second->IsDroppable(false)); + (iter2.second->GetItem() ? iter2.second->GetItem()->Name : "null data"), iter2.second->GetID(), (iter2.second->IsDroppable(false) ? "true" : "false")); } } } @@ -636,21 +636,21 @@ void Client::DropItem(int16 slot_id, bool recurse) if (LogSys.log_settings[Logs::Inventory].is_category_enabled) { Log(Logs::General, Logs::Inventory, "DropItem() Processing - full item parse:"); Log(Logs::General, Logs::Inventory, "depth: 0, Item: '%s' (id: %u), IsDroppable: %s", - (inst->GetItem() ? inst->GetItem()->Name : "null data"), inst->GetID(), inst->IsDroppable(false)); + (inst->GetItem() ? inst->GetItem()->Name : "null data"), inst->GetID(), (inst->IsDroppable(false) ? "true" : "false")); if (!inst->IsDroppable(false)) Log(Logs::General, Logs::Error, "Non-droppable item being processed for drop by '%s'", GetCleanName()); for (auto iter1 : *inst->GetContents()) { // depth 1 Log(Logs::General, Logs::Inventory, "-depth: 1, Item: '%s' (id: %u), IsDroppable: %s", - (iter1.second->GetItem() ? iter1.second->GetItem()->Name : "null data"), iter1.second->GetID(), iter1.second->IsDroppable(false)); + (iter1.second->GetItem() ? iter1.second->GetItem()->Name : "null data"), iter1.second->GetID(), (iter1.second->IsDroppable(false) ? "true" : "false")); if (!iter1.second->IsDroppable(false)) Log(Logs::General, Logs::Error, "Non-droppable item being processed for drop by '%s'", GetCleanName()); for (auto iter2 : *iter1.second->GetContents()) { // depth 2 Log(Logs::General, Logs::Inventory, "--depth: 2, Item: '%s' (id: %u), IsDroppable: %s", - (iter2.second->GetItem() ? iter2.second->GetItem()->Name : "null data"), iter2.second->GetID(), iter2.second->IsDroppable(false)); + (iter2.second->GetItem() ? iter2.second->GetItem()->Name : "null data"), iter2.second->GetID(), (iter2.second->IsDroppable(false) ? "true" : "false")); if (!iter2.second->IsDroppable(false)) Log(Logs::General, Logs::Error, "Non-droppable item being processed for drop by '%s'", GetCleanName());