Compare commits

...

3 Commits

Author SHA1 Message Date
c113ea4a6c Refactor and generalize NPCEvent logic 2023-09-10 20:02:52 +02:00
208a301a48 Rename coord args in summonNPC() and constructors to clarify purpose
This makes it clearer that the real coords aren't set until the first
call to updateNPCPosition().
2023-09-10 19:49:40 +02:00
278818dd37 Quick fix for Fuse boss fight NPCEvent logic
Will be replaced with a proper rework immediately.
2023-09-10 19:24:19 +02:00
5 changed files with 37 additions and 45 deletions

View File

@ -307,19 +307,19 @@ void CombatNPC::step(time_t currTime) {
} }
void CombatNPC::transition(AIState newState, EntityRef src) { void CombatNPC::transition(AIState newState, EntityRef src) {
state = newState; state = newState;
if (transitionHandlers.find(newState) != transitionHandlers.end()) if (transitionHandlers.find(newState) != transitionHandlers.end())
transitionHandlers[newState](this, src); transitionHandlers[newState](this, src);
else { else {
std::cout << "[WARN] Transition to " << (int)state << " has no handler; going inactive" << std::endl; std::cout << "[WARN] Transition to " << (int)state << " has no handler; going inactive" << std::endl;
transition(AIState::INACTIVE, id); transition(AIState::INACTIVE, id);
} }
/* TODO: fire any triggered events
// trigger special NPCEvents, if applicable
for (NPCEvent& event : NPCManager::NPCEvents) for (NPCEvent& event : NPCManager::NPCEvents)
if (event.trigger == ON_KILLED && event.npcType == type) if (event.triggerState == newState && event.npcType == type)
event.handler(src, this); event.handler(this);
*/
} }
#pragma endregion #pragma endregion

View File

@ -106,11 +106,11 @@ struct CombatNPC : public BaseNPC, public ICombatant {
std::unordered_map<int, Buff*> buffs = {}; std::unordered_map<int, Buff*> buffs = {};
CombatNPC(int x, int y, int z, int angle, uint64_t iID, int t, int id, int maxHP) CombatNPC(int spawnX, int spawnY, int spawnZ, int angle, uint64_t iID, int t, int id, int maxHP)
: BaseNPC(angle, iID, t, id), maxHealth(maxHP) { : BaseNPC(angle, iID, t, id), maxHealth(maxHP) {
spawnX = x; this->spawnX = spawnX;
spawnY = y; this->spawnY = spawnY;
spawnZ = z; this->spawnZ = spawnZ;
kind = EntityKind::COMBAT_NPC; kind = EntityKind::COMBAT_NPC;

View File

@ -50,8 +50,8 @@ struct Mob : public CombatNPC {
// temporary; until we're sure what's what // temporary; until we're sure what's what
nlohmann::json data = {}; nlohmann::json data = {};
Mob(int x, int y, int z, int angle, uint64_t iID, int t, nlohmann::json d, int32_t id) Mob(int spawnX, int spawnY, int spawnZ, int angle, uint64_t iID, int t, nlohmann::json d, int32_t id)
: CombatNPC(x, y, z, angle, iID, t, id, d["m_iHP"]), : CombatNPC(spawnX, spawnY, spawnZ, angle, iID, t, id, d["m_iHP"]),
sightRange(d["m_iSightRange"]) { sightRange(d["m_iSightRange"]) {
state = AIState::ROAMING; state = AIState::ROAMING;
@ -62,9 +62,9 @@ struct Mob : public CombatNPC {
idleRange = (int)data["m_iIdleRange"]; idleRange = (int)data["m_iIdleRange"];
level = data["m_iNpcLevel"]; level = data["m_iNpcLevel"];
roamX = x; roamX = spawnX;
roamY = y; roamY = spawnY;
roamZ = z; roamZ = spawnZ;
offsetX = 0; offsetX = 0;
offsetY = 0; offsetY = 0;

View File

@ -122,16 +122,15 @@ static void npcUnsummonHandler(CNSocket* sock, CNPacketData* data) {
} }
// type must already be checked and updateNPCPosition() must be called on the result // type must already be checked and updateNPCPosition() must be called on the result
BaseNPC *NPCManager::summonNPC(int x, int y, int z, uint64_t instance, int type, bool respawn, bool baseInstance) { BaseNPC *NPCManager::summonNPC(int spawnX, int spawnY, int spawnZ, uint64_t instance, int type, bool respawn, bool baseInstance) {
uint64_t inst = baseInstance ? MAPNUM(instance) : instance; uint64_t inst = baseInstance ? MAPNUM(instance) : instance;
//assert(nextId < INT32_MAX);
int id = nextId--; int id = nextId--;
int team = NPCData[type]["m_iTeam"]; int team = NPCData[type]["m_iTeam"];
BaseNPC *npc = nullptr; BaseNPC *npc = nullptr;
if (team == 2) { if (team == 2) {
npc = new Mob(x, y, z, inst, type, NPCData[type], id); npc = new Mob(spawnX, spawnY, spawnZ, inst, type, NPCData[type], id);
// re-enable respawning, if desired // re-enable respawning, if desired
((Mob*)npc)->summoned = !respawn; ((Mob*)npc)->summoned = !respawn;
@ -294,57 +293,55 @@ BaseNPC* NPCManager::getNearestNPC(std::set<Chunk*>* chunks, int X, int Y, int Z
return npc; return npc;
} }
// TODO: Move this to MobAI, possibly // TODO: Move this to separate file in ai/ subdir when implementing more events
#pragma region NPCEvents #pragma region NPCEvents
// summon right arm and stage 2 body // summon right arm and stage 2 body
static void lordFuseStageTwo(CNSocket *sock, BaseNPC *npc) { static void lordFuseStageTwo(CombatNPC *npc) {
Mob *oldbody = (Mob*)npc; // adaptium, stun Mob *oldbody = (Mob*)npc; // adaptium, stun
Player *plr = PlayerManager::getPlayer(sock);
std::cout << "Lord Fuse stage two" << std::endl; std::cout << "Lord Fuse stage two" << std::endl;
// Fuse doesn't move // Fuse doesn't move
// Blastons, Heal // Blastons, Heal
Mob *newbody = (Mob*)NPCManager::summonNPC(oldbody->x, oldbody->y, oldbody->z, plr->instanceID, 2467); Mob *newbody = (Mob*)NPCManager::summonNPC(oldbody->x, oldbody->y, oldbody->z, oldbody->instanceID, 2467);
newbody->angle = oldbody->angle; newbody->angle = oldbody->angle;
NPCManager::updateNPCPosition(newbody->id, newbody->x, newbody->y, newbody->z, NPCManager::updateNPCPosition(newbody->id, newbody->spawnX, newbody->spawnY, newbody->spawnZ,
plr->instanceID, oldbody->angle); oldbody->instanceID, oldbody->angle);
// right arm, Adaptium, Stun // right arm, Adaptium, Stun
Mob *arm = (Mob*)NPCManager::summonNPC(oldbody->x - 600, oldbody->y, oldbody->z, plr->instanceID, 2469); Mob *arm = (Mob*)NPCManager::summonNPC(oldbody->x - 600, oldbody->y, oldbody->z, oldbody->instanceID, 2469);
arm->angle = oldbody->angle; arm->angle = oldbody->angle;
NPCManager::updateNPCPosition(arm->id, arm->x, arm->y, arm->z, NPCManager::updateNPCPosition(arm->id, arm->spawnX, arm->spawnY, arm->spawnZ,
plr->instanceID, oldbody->angle); oldbody->instanceID, oldbody->angle);
} }
// summon left arm and stage 3 body // summon left arm and stage 3 body
static void lordFuseStageThree(CNSocket *sock, BaseNPC *npc) { static void lordFuseStageThree(CombatNPC *npc) {
Mob *oldbody = (Mob*)npc; Mob *oldbody = (Mob*)npc;
Player *plr = PlayerManager::getPlayer(sock);
std::cout << "Lord Fuse stage three" << std::endl; std::cout << "Lord Fuse stage three" << std::endl;
// Cosmix, Damage Point // Cosmix, Damage Point
Mob *newbody = (Mob*)NPCManager::summonNPC(oldbody->x, oldbody->y, oldbody->z, plr->instanceID, 2468); Mob *newbody = (Mob*)NPCManager::summonNPC(oldbody->x, oldbody->y, oldbody->z, oldbody->instanceID, 2468);
newbody->angle = oldbody->angle; newbody->angle = oldbody->angle;
NPCManager::updateNPCPosition(newbody->id, newbody->x, newbody->y, newbody->z, NPCManager::updateNPCPosition(newbody->id, newbody->spawnX, newbody->spawnY, newbody->spawnZ,
plr->instanceID, oldbody->angle); newbody->instanceID, oldbody->angle);
// Blastons, Heal // Blastons, Heal
Mob *arm = (Mob*)NPCManager::summonNPC(oldbody->x + 600, oldbody->y, oldbody->z, plr->instanceID, 2470); Mob *arm = (Mob*)NPCManager::summonNPC(oldbody->x + 600, oldbody->y, oldbody->z, oldbody->instanceID, 2470);
arm->angle = oldbody->angle; arm->angle = oldbody->angle;
NPCManager::updateNPCPosition(arm->id, arm->x, arm->y, arm->z, NPCManager::updateNPCPosition(arm->id, arm->spawnX, arm->spawnY, arm->spawnZ,
plr->instanceID, oldbody->angle); arm->instanceID, oldbody->angle);
} }
std::vector<NPCEvent> NPCManager::NPCEvents = { std::vector<NPCEvent> NPCManager::NPCEvents = {
NPCEvent(2466, ON_KILLED, lordFuseStageTwo), NPCEvent(2466, AIState::DEAD, lordFuseStageTwo),
NPCEvent(2467, ON_KILLED, lordFuseStageThree), NPCEvent(2467, AIState::DEAD, lordFuseStageThree),
}; };
#pragma endregion NPCEvents #pragma endregion NPCEvents

View File

@ -14,20 +14,15 @@
#define RESURRECT_HEIGHT 400 #define RESURRECT_HEIGHT 400
enum Trigger { typedef void (*NPCEventHandler)(CombatNPC*);
ON_KILLED,
ON_COMBAT
};
typedef void (*NPCEventHandler)(CNSocket*, BaseNPC*);
struct NPCEvent { struct NPCEvent {
int32_t npcType; int32_t npcType;
int trigger; AIState triggerState;
NPCEventHandler handler; NPCEventHandler handler;
NPCEvent(int32_t t, int tr, NPCEventHandler hndlr) NPCEvent(int32_t t, AIState tr, NPCEventHandler hndlr)
: npcType(t), trigger(tr), handler(hndlr) {} : npcType(t), triggerState(tr), handler(hndlr) {}
}; };
namespace NPCManager { namespace NPCManager {