60 lines
2.9 KiB
C++
60 lines
2.9 KiB
C++
// PORT extension: free cloak-style auto-hunt pull, using the original BeginFight path.
|
|
#ifdef MT_AUTOHUNT_SERVER_TEST
|
|
#include "group_select.h"
|
|
#else
|
|
#include "sectree_manager.h"
|
|
#include "autohunt_group_select.h"
|
|
#endif
|
|
|
|
struct AutoHuntPullCollector {
|
|
LPCHARACTER owner;
|
|
int radius;
|
|
bool bosses;
|
|
std::vector<mt_autohunt::Candidate> candidates;
|
|
AutoHuntPullCollector(LPCHARACTER ch, int range, bool boss) : owner(ch), radius(range), bosses(boss) {}
|
|
void operator()(LPENTITY ent) {
|
|
if (!ent->IsType(ENTITY_CHARACTER)) return;
|
|
LPCHARACTER mob = (LPCHARACTER)ent;
|
|
if (!mob->IsMonster() || mob->IsPC() || mob->IsDead() || mob->GetMapIndex() != owner->GetMapIndex()) return;
|
|
const int distance = DISTANCE_APPROX(mob->GetX() - owner->GetX(), mob->GetY() - owner->GetY());
|
|
if (distance > radius) return;
|
|
const bool safe = !mob->GetSectree() ||
|
|
(mob->GetSectree()->GetAttribute(mob->GetX(), mob->GetY()) & ATTR_BANPK);
|
|
mt_autohunt::Candidate c;
|
|
c.group = mob->GetParty() ? uint64_t(uintptr_t(mob->GetParty())) << 1 : (uint64_t((DWORD)mob->GetVID()) << 1) | 1;
|
|
c.vid = (DWORD)mob->GetVID();
|
|
c.distance = distance;
|
|
c.eligible = !safe && (bosses || mob->GetMobRank() < MOB_RANK_BOSS) &&
|
|
(!mob->GetVictim() || mob->GetVictim() == owner) && (mob->GetVictim() == owner || mob->CanBeginFight());
|
|
candidates.push_back(c);
|
|
}
|
|
};
|
|
|
|
ACMD(do_autohunt_pull) {
|
|
int groups = 0, radius = 0, bosses = 0;
|
|
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 ||
|
|
(bosses != 0 && bosses != 1)) 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) ||
|
|
ch->GetHP() < ch->GetMaxHP() / 2 || now < ch->GetQuestFlag("autohunt.next_pull")) {
|
|
ch->ChatPacket(CHAT_TYPE_COMMAND, "AutoHuntGather %u done 0", request);
|
|
return;
|
|
}
|
|
// 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);
|
|
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->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);
|
|
}
|