190 lines
8.0 KiB
Diff
190 lines
8.0 KiB
Diff
--- a/server/game/src/sectree_manager.h
|
|
+++ b/server/game/src/sectree_manager.h
|
|
@@ -88,6 +88,18 @@
|
|
}
|
|
*/
|
|
}
|
|
+
|
|
+ // PORT: snapshot traversal for the complete auto-hunt radius.
|
|
+ template<typename Func>
|
|
+ void for_each_in_rect(DWORD minX, DWORD minY, DWORD maxX, DWORD maxY, Func& func) {
|
|
+ FCollectEntity collector;
|
|
+ for (DWORD x = minX / SECTREE_SIZE * SECTREE_SIZE; x <= maxX; x += SECTREE_SIZE)
|
|
+ for (DWORD y = minY / SECTREE_SIZE * SECTREE_SIZE; y <= maxY; y += SECTREE_SIZE) {
|
|
+ LPSECTREE tree = Find(x, y);
|
|
+ if (tree) tree->for_each_entity(collector);
|
|
+ }
|
|
+ collector.ForEach(func);
|
|
+ }
|
|
|
|
void DumpAllToSysErr() {
|
|
SECTREE_MAP::MapType::iterator i;
|
|
--- a/server/game/src/autohunt_pull.h
|
|
+++ b/server/game/src/autohunt_pull.h
|
|
@@ -3,8 +3,37 @@
|
|
#include "group_select.h"
|
|
#else
|
|
#include "sectree_manager.h"
|
|
+#include "autohunt_pull_range.h"
|
|
#include "autohunt_group_select.h"
|
|
#endif
|
|
+
|
|
+// PORT: only mobs pulled by this command receive a temporary extended pursuit leash.
|
|
+struct AutoHuntPullLease {
|
|
+ LPCHARACTER mob;
|
|
+ DWORD ownerPID;
|
|
+ int radius;
|
|
+ int expires;
|
|
+};
|
|
+static std::map<DWORD, AutoHuntPullLease> s_autoHuntPullLeases;
|
|
+int AutoHuntPullLeash(LPCHARACTER mob, LPCHARACTER victim) {
|
|
+ std::map<DWORD, AutoHuntPullLease>::iterator it = s_autoHuntPullLeases.find((DWORD)mob->GetVID());
|
|
+ if (it == s_autoHuntPullLeases.end()) return 4000;
|
|
+ const AutoHuntPullLease& lease = it->second;
|
|
+ if (lease.mob != mob || !victim || !victim->IsPC() || victim->IsDead() ||
|
|
+ victim->GetPlayerID() != lease.ownerPID || mob->GetMapIndex() != victim->GetMapIndex() ||
|
|
+ get_global_time() >= lease.expires) {
|
|
+ s_autoHuntPullLeases.erase(it);
|
|
+ return 4000;
|
|
+ }
|
|
+ return std::max(4000, lease.radius + 1);
|
|
+}
|
|
+static void AutoHuntPullPrune(DWORD cancelPID = 0) {
|
|
+ for (std::map<DWORD, AutoHuntPullLease>::iterator it = s_autoHuntPullLeases.begin(); it != s_autoHuntPullLeases.end();) {
|
|
+ if (it->second.expires <= get_global_time() || (cancelPID && it->second.ownerPID == cancelPID))
|
|
+ s_autoHuntPullLeases.erase(it++);
|
|
+ else ++it;
|
|
+ }
|
|
+}
|
|
|
|
struct AutoHuntPullCollector {
|
|
LPCHARACTER owner;
|
|
@@ -35,8 +64,11 @@
|
|
unsigned int request = 0;
|
|
char extra = 0;
|
|
if (sscanf(argument, "%d %d %d %u %c", &groups, &radius, &bosses, &request, &extra) != 4 ||
|
|
- (groups != 3 && groups != 10 && groups != 20) || radius < 500 || radius > 5000 ||
|
|
+ (groups != 0 && groups != 3 && groups != 10 && groups != 20) || radius < 500 || radius > 15000 ||
|
|
(bosses != 0 && bosses != 1)) return;
|
|
+ if (!ch->IsPC()) return;
|
|
+ AutoHuntPullPrune(groups == 0 ? ch->GetPlayerID() : 0);
|
|
+ if (groups == 0) return;
|
|
const int now = get_global_time();
|
|
if (!ch->IsPC() || ch->IsDead() || ch->IsStun() || !ch->CanHandleItem() || !ch->GetSectree() ||
|
|
(ch->GetSectree()->GetAttribute(ch->GetX(), ch->GetY()) & ATTR_BANPK) ||
|
|
@@ -47,13 +79,23 @@
|
|
// Server-side cooldown survives reconnects and switching auto hunt on/off.
|
|
ch->SetQuestFlag("autohunt.next_pull", now + 10);
|
|
AutoHuntPullCollector collector(ch, radius, bosses != 0);
|
|
- ch->GetSectree()->ForEachAround(collector);
|
|
+ // ForEachAround only covers nine cells: visit every cell intersecting the requested radius.
|
|
+ LPSECTREE_MAP map = SECTREE_MANAGER::instance().GetMap(ch->GetMapIndex());
|
|
+ if (map) map->for_each_in_rect(std::max(0, int(ch->GetX()) - radius),
|
|
+ std::max(0, int(ch->GetY()) - radius), ch->GetX() + radius, ch->GetY() + radius, collector);
|
|
const mt_autohunt::Selection selected = mt_autohunt::SelectGroups(collector.candidates, groups);
|
|
for (size_t i = 0; i < selected.mobs.size(); ++i) {
|
|
LPCHARACTER mob = CHARACTER_MANAGER::instance().Find(selected.mobs[i]);
|
|
if (!mob) continue;
|
|
+ if (mob->IsDead() || (mob->GetVictim() && mob->GetVictim() != ch)) continue;
|
|
+ AutoHuntPullLease lease = {mob, ch->GetPlayerID(), radius, now + 180};
|
|
+ s_autoHuntPullLeases[(DWORD)mob->GetVID()] = lease;
|
|
if (!mob->GetVictim()) mob->BeginFight(ch);
|
|
ch->ChatPacket(CHAT_TYPE_COMMAND, "AutoHuntGather %u mob %u", request, selected.mobs[i]);
|
|
}
|
|
ch->ChatPacket(CHAT_TYPE_COMMAND, "AutoHuntGather %u done %d", request, selected.groups);
|
|
}
|
|
+
|
|
+#ifndef MT_AUTOHUNT_SERVER_TEST
|
|
+#include "server_bonuses.h"
|
|
+#endif
|
|
--- a/server/game/src/char_state.cpp
|
|
+++ b/server/game/src/char_state.cpp
|
|
@@ -3,6 +3,7 @@
|
|
#include "utils.h"
|
|
#include "vector.h"
|
|
#include "char.h"
|
|
+#include "autohunt_pull_range.h"
|
|
#include "battle.h"
|
|
#include "char_manager.h"
|
|
#include "packet.h"
|
|
@@ -1035,7 +1036,7 @@
|
|
|
|
float fDist = DISTANCE_APPROX(GetX() - victim->GetX(), GetY() - victim->GetY());
|
|
|
|
- if (fDist >= 4000.0f) // 40미터 이상 멀어지면 포기
|
|
+ if (fDist >= AutoHuntPullLeash(this, victim)) // 40미터 이상 멀어지면 포기
|
|
{
|
|
MonsterLog("타겟이 멀어서 포기");
|
|
SetVictim(NULL);
|
|
--- a/server/game/src/cmd.cpp
|
|
+++ b/server/game/src/cmd.cpp
|
|
@@ -7,6 +7,7 @@
|
|
#include "desc.h"
|
|
|
|
ACMD(do_autohunt_pull);
|
|
+ACMD(do_server_bonuses);
|
|
ACMD(do_user_horse_ride);
|
|
ACMD(do_user_horse_back);
|
|
ACMD(do_user_horse_feed);
|
|
@@ -281,6 +282,7 @@
|
|
{
|
|
{ "!RESERVED!", NULL, 0, POS_DEAD, GM_IMPLEMENTOR }, /* 반드시 이 것이 처음이어야 한다. */
|
|
{ "autohunt_pull", do_autohunt_pull, 0, POS_STANDING, GM_PLAYER },
|
|
+ { "server_bonuses", do_server_bonuses, 0, POS_DEAD, GM_PLAYER },
|
|
{ "who", do_who, 0, POS_DEAD, GM_IMPLEMENTOR },
|
|
{ "war", do_war, 0, POS_DEAD, GM_PLAYER },
|
|
{ "warp", do_warp, 0, POS_DEAD, GM_LOW_WIZARD },
|
|
--- /dev/null
|
|
+++ b/server/game/src/autohunt_pull_range.h
|
|
@@ -0,0 +1,3 @@
|
|
+#pragma once
|
|
+// PORT extension: ordinary monster pursuit remains 40 metres.
|
|
+int AutoHuntPullLeash(LPCHARACTER mob, LPCHARACTER victim);
|
|
--- /dev/null
|
|
+++ b/server/game/src/server_bonuses.h
|
|
@@ -0,0 +1,14 @@
|
|
+// PORT: report actual global rates and the character's effective event privileges.
|
|
+#ifndef MT_AUTOHUNT_SERVER_TEST
|
|
+#include "priv_manager.h"
|
|
+#endif
|
|
+ACMD(do_server_bonuses) {
|
|
+ if (!ch->IsPC() || get_global_time() < ch->GetQuestFlag("server_bonuses.next_query")) return;
|
|
+ ch->SetQuestFlag("server_bonuses.next_query", get_global_time() + 2);
|
|
+ CHARACTER_MANAGER& cm = CHARACTER_MANAGER::instance();
|
|
+ CPrivManager& pm = CPrivManager::instance();
|
|
+ ch->ChatPacket(CHAT_TYPE_COMMAND, "ServerBonuses %d %d %d %d %d %d %d %d",
|
|
+ cm.GetMobExpRate(NULL), cm.GetMobGoldAmountRate(NULL), cm.GetMobGoldDropRate(NULL), cm.GetGlobalMobItemRate(),
|
|
+ pm.GetPriv(ch, PRIV_EXP_PCT), pm.GetPriv(ch, PRIV_ITEM_DROP),
|
|
+ pm.GetPriv(ch, PRIV_GOLD_DROP), pm.GetPriv(ch, PRIV_GOLD10_DROP));
|
|
+}
|
|
--- a/server/game/src/char.cpp
|
|
+++ b/server/game/src/char.cpp
|
|
@@ -4,6 +4,7 @@
|
|
#include "../../common/VnumHelper.h"
|
|
|
|
#include "char.h"
|
|
+#include "autohunt_pull_range.h"
|
|
|
|
#include "config.h"
|
|
#include "utils.h"
|
|
@@ -5440,7 +5441,7 @@
|
|
if (get_dword_time() - m_pkMobInst->m_dwLastAttackedTime >= 15000) // 마지막으로 공격받은지 15초가 지났고
|
|
{
|
|
// 마지막 맞은 곳으로 부터 50미터 이상 차이나면 포기하고 돌아간다.
|
|
- if (5000 < DISTANCE_APPROX(m_pkMobInst->m_posLastAttacked.x - GetX(), m_pkMobInst->m_posLastAttacked.y - GetY()))
|
|
+ if (MAX(5000, AutoHuntPullLeash(this, pkChr)) < DISTANCE_APPROX(m_pkMobInst->m_posLastAttacked.x - GetX(), m_pkMobInst->m_posLastAttacked.y - GetY()))
|
|
if (Return())
|
|
return true;
|
|
}
|
|
--- a/server/game/src/char_manager.h
|
|
+++ b/server/game/src/char_manager.h
|
|
@@ -92,6 +92,8 @@
|
|
void SetUserDamageRatePremium(int value) { m_iUserDamageRatePremium = value; }
|
|
void SetUserDamageRate(int value ) { m_iUserDamageRate = value; }
|
|
int GetMobItemRate(LPCHARACTER ch);
|
|
+ // PORT: query the global rate without dereferencing a character in locale-specific rules.
|
|
+ int GetGlobalMobItemRate() const { return m_iMobItemRate; }
|
|
int GetMobDamageRate(LPCHARACTER ch);
|
|
int GetMobGoldAmountRate(LPCHARACTER ch);
|
|
int GetMobGoldDropRate(LPCHARACTER ch);
|