mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-11-22 13:30:06 +00:00
(WIP) Point 2: Generalization
This commit is contained in:
parent
3d572432b3
commit
c32e5b2d5e
@ -153,7 +153,7 @@ bool doDebuff(CNSocket *sock, sSkillResult_Buff *respdata, int i, int32_t target
|
|||||||
respdata[i].eCT = 4;
|
respdata[i].eCT = 4;
|
||||||
respdata[i].iID = mob->id;
|
respdata[i].iID = mob->id;
|
||||||
respdata[i].bProtected = 1;
|
respdata[i].bProtected = 1;
|
||||||
if (mob->skillStyle < 0 && mob->state != MobState::RETREAT
|
if (mob->skillStyle < 0 && mob->state != AIState::RETREAT
|
||||||
&& !(mob->cbf & CSB_BIT_FREEDOM)) { // only debuff if the enemy is not retreating, casting corruption or in freedom
|
&& !(mob->cbf & CSB_BIT_FREEDOM)) { // only debuff if the enemy is not retreating, casting corruption or in freedom
|
||||||
mob->cbf |= bitFlag;
|
mob->cbf |= bitFlag;
|
||||||
mob->unbuffTimes[bitFlag] = getTime() + duration * 100;
|
mob->unbuffTimes[bitFlag] = getTime() + duration * 100;
|
||||||
@ -227,7 +227,7 @@ bool doDamageNDebuff(CNSocket *sock, sSkillResult_Damage_N_Debuff *respdata, int
|
|||||||
respdata[i].iID = mob->id;
|
respdata[i].iID = mob->id;
|
||||||
respdata[i].iHP = mob->hp;
|
respdata[i].iHP = mob->hp;
|
||||||
respdata[i].bProtected = 1;
|
respdata[i].bProtected = 1;
|
||||||
if (mob->skillStyle < 0 && mob->state != MobState::RETREAT
|
if (mob->skillStyle < 0 && mob->state != AIState::RETREAT
|
||||||
&& !(mob->cbf & CSB_BIT_FREEDOM)) { // only debuff if the enemy is not retreating, casting corruption or in freedom
|
&& !(mob->cbf & CSB_BIT_FREEDOM)) { // only debuff if the enemy is not retreating, casting corruption or in freedom
|
||||||
mob->cbf |= bitFlag;
|
mob->cbf |= bitFlag;
|
||||||
mob->unbuffTimes[bitFlag] = getTime() + duration * 100;
|
mob->unbuffTimes[bitFlag] = getTime() + duration * 100;
|
||||||
@ -450,7 +450,7 @@ bool doDamageNDebuff(Mob* mob, sSkillResult_Damage_N_Debuff* respdata, int i, in
|
|||||||
|
|
||||||
if (plr->HP <= 0) {
|
if (plr->HP <= 0) {
|
||||||
mob->target = nullptr;
|
mob->target = nullptr;
|
||||||
mob->state = MobState::RETREAT;
|
mob->state = AIState::RETREAT;
|
||||||
if (!MobAI::aggroCheck(mob, getTime())) {
|
if (!MobAI::aggroCheck(mob, getTime())) {
|
||||||
MobAI::clearDebuff(mob);
|
MobAI::clearDebuff(mob);
|
||||||
if (mob->groupLeader != 0)
|
if (mob->groupLeader != 0)
|
||||||
@ -530,7 +530,7 @@ bool doDamage(Mob* mob, sSkillResult_Damage* respdata, int i, int32_t targetID,
|
|||||||
|
|
||||||
if (plr->HP <= 0) {
|
if (plr->HP <= 0) {
|
||||||
mob->target = nullptr;
|
mob->target = nullptr;
|
||||||
mob->state = MobState::RETREAT;
|
mob->state = AIState::RETREAT;
|
||||||
if (!MobAI::aggroCheck(mob, getTime())) {
|
if (!MobAI::aggroCheck(mob, getTime())) {
|
||||||
MobAI::clearDebuff(mob);
|
MobAI::clearDebuff(mob);
|
||||||
if (mob->groupLeader != 0)
|
if (mob->groupLeader != 0)
|
||||||
@ -588,7 +588,7 @@ bool doLeech(Mob* mob, sSkillResult_Heal_HP* healdata, int i, int32_t targetID,
|
|||||||
|
|
||||||
if (plr->HP <= 0) {
|
if (plr->HP <= 0) {
|
||||||
mob->target = nullptr;
|
mob->target = nullptr;
|
||||||
mob->state = MobState::RETREAT;
|
mob->state = AIState::RETREAT;
|
||||||
if (!MobAI::aggroCheck(mob, getTime())) {
|
if (!MobAI::aggroCheck(mob, getTime())) {
|
||||||
MobAI::clearDebuff(mob);
|
MobAI::clearDebuff(mob);
|
||||||
if (mob->groupLeader != 0)
|
if (mob->groupLeader != 0)
|
||||||
|
@ -50,14 +50,14 @@ int CombatNPC::takeDamage(EntityRef src, int amt) {
|
|||||||
Mob* mob = (Mob*)this;
|
Mob* mob = (Mob*)this;
|
||||||
|
|
||||||
// cannot kill mobs multiple times; cannot harm retreating mobs
|
// cannot kill mobs multiple times; cannot harm retreating mobs
|
||||||
if (mob->state != MobState::ROAMING && mob->state != MobState::COMBAT) {
|
if (mob->state != AIState::ROAMING && mob->state != AIState::COMBAT) {
|
||||||
return 0; // no damage
|
return 0; // no damage
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mob->skillStyle >= 0)
|
if (mob->skillStyle >= 0)
|
||||||
return 0; // don't hurt a mob casting corruption
|
return 0; // don't hurt a mob casting corruption
|
||||||
|
|
||||||
if (mob->state == MobState::ROAMING) {
|
if (mob->state == AIState::ROAMING) {
|
||||||
assert(mob->target == nullptr && src.type == EntityType::PLAYER); // players only for now
|
assert(mob->target == nullptr && src.type == EntityType::PLAYER); // players only for now
|
||||||
MobAI::enterCombat(src.sock, mob);
|
MobAI::enterCombat(src.sock, mob);
|
||||||
|
|
||||||
@ -101,7 +101,31 @@ int32_t CombatNPC::getID() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CombatNPC::step(time_t currTime) {
|
void CombatNPC::step(time_t currTime) {
|
||||||
// stubbed
|
if (playersInView < 0)
|
||||||
|
std::cout << "[WARN] Weird playerview value " << playersInView << std::endl;
|
||||||
|
|
||||||
|
// skip movement and combat if disabled or not in view
|
||||||
|
if ((!MobAI::simulateMobs || playersInView == 0) && state != AIState::DEAD
|
||||||
|
&& state != AIState::RETREAT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case AIState::INACTIVE:
|
||||||
|
// no-op
|
||||||
|
break;
|
||||||
|
case AIState::ROAMING:
|
||||||
|
roamingStep(currTime);
|
||||||
|
break;
|
||||||
|
case AIState::COMBAT:
|
||||||
|
combatStep(currTime);
|
||||||
|
break;
|
||||||
|
case AIState::RETREAT:
|
||||||
|
retreatStep(currTime);
|
||||||
|
break;
|
||||||
|
case AIState::DEAD:
|
||||||
|
deadStep(currTime);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::pair<int,int> getDamage(int attackPower, int defensePower, bool shouldCrit,
|
static std::pair<int,int> getDamage(int attackPower, int defensePower, bool shouldCrit,
|
||||||
@ -268,7 +292,7 @@ void Combat::npcAttackPc(Mob *mob, time_t currTime) {
|
|||||||
|
|
||||||
if (plr->HP <= 0) {
|
if (plr->HP <= 0) {
|
||||||
mob->target = nullptr;
|
mob->target = nullptr;
|
||||||
mob->state = MobState::RETREAT;
|
mob->state = AIState::RETREAT;
|
||||||
if (!MobAI::aggroCheck(mob, currTime)) {
|
if (!MobAI::aggroCheck(mob, currTime)) {
|
||||||
MobAI::clearDebuff(mob);
|
MobAI::clearDebuff(mob);
|
||||||
if (mob->groupLeader != 0)
|
if (mob->groupLeader != 0)
|
||||||
@ -302,7 +326,7 @@ static void genQItemRolls(Player *leader, std::map<int, int>& rolls) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Combat::killMob(CNSocket *sock, Mob *mob) {
|
void Combat::killMob(CNSocket *sock, Mob *mob) {
|
||||||
mob->state = MobState::DEAD;
|
mob->state = AIState::DEAD;
|
||||||
mob->target = nullptr;
|
mob->target = nullptr;
|
||||||
mob->cbf = 0;
|
mob->cbf = 0;
|
||||||
mob->skillStyle = -1;
|
mob->skillStyle = -1;
|
||||||
|
@ -328,7 +328,7 @@ static void toggleAiCommand(std::string full, std::vector<std::string>& args, CN
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
Mob* mob = (Mob*)pair.second;
|
Mob* mob = (Mob*)pair.second;
|
||||||
mob->state = MobState::RETREAT;
|
mob->state = AIState::RETREAT;
|
||||||
mob->target = nullptr;
|
mob->target = nullptr;
|
||||||
mob->nextMovement = getTime();
|
mob->nextMovement = getTime();
|
||||||
|
|
||||||
|
@ -16,6 +16,16 @@ enum class EntityType : uint8_t {
|
|||||||
BUS
|
BUS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class AIState {
|
||||||
|
INACTIVE,
|
||||||
|
ROAMING,
|
||||||
|
COMBAT,
|
||||||
|
RETREAT,
|
||||||
|
DEAD
|
||||||
|
};
|
||||||
|
|
||||||
|
class Chunk;
|
||||||
|
|
||||||
struct Entity {
|
struct Entity {
|
||||||
EntityType kind = EntityType::INVALID;
|
EntityType kind = EntityType::INVALID;
|
||||||
int x = 0, y = 0, z = 0;
|
int x = 0, y = 0, z = 0;
|
||||||
@ -123,6 +133,8 @@ struct CombatNPC : public BaseNPC, public ICombatant {
|
|||||||
int spawnZ = 0;
|
int spawnZ = 0;
|
||||||
int level = 0;
|
int level = 0;
|
||||||
int speed = 300;
|
int speed = 300;
|
||||||
|
AIState state = AIState::INACTIVE;
|
||||||
|
int playersInView = 0; // for optimizing away AI in empty chunks
|
||||||
|
|
||||||
CombatNPC(int x, int y, int z, int angle, uint64_t iID, int t, int id, int maxHP)
|
CombatNPC(int x, int y, int z, 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) {
|
||||||
@ -138,12 +150,16 @@ struct CombatNPC : public BaseNPC, public ICombatant {
|
|||||||
virtual bool isAlive() override;
|
virtual bool isAlive() override;
|
||||||
virtual int getCurrentHP() override;
|
virtual int getCurrentHP() override;
|
||||||
virtual int32_t getID() override;
|
virtual int32_t getID() override;
|
||||||
|
|
||||||
virtual void step(time_t currTime) override;
|
virtual void step(time_t currTime) override;
|
||||||
|
virtual void roamingStep(time_t currTime) {} // no-op by default
|
||||||
|
virtual void combatStep(time_t currTime) {}
|
||||||
|
virtual void retreatStep(time_t currTime) {}
|
||||||
|
virtual void deadStep(time_t currTime) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Mob is in MobAI.hpp, Player is in Player.hpp
|
// Mob is in MobAI.hpp, Player is in Player.hpp
|
||||||
|
|
||||||
// TODO: decouple from BaseNPC
|
|
||||||
struct Egg : public BaseNPC {
|
struct Egg : public BaseNPC {
|
||||||
bool summoned = false;
|
bool summoned = false;
|
||||||
bool dead = false;
|
bool dead = false;
|
||||||
@ -161,7 +177,6 @@ struct Egg : public BaseNPC {
|
|||||||
virtual void disappearFromViewOf(CNSocket *sock) override;
|
virtual void disappearFromViewOf(CNSocket *sock) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: decouple from BaseNPC
|
|
||||||
struct Bus : public BaseNPC {
|
struct Bus : public BaseNPC {
|
||||||
Bus(int angle, uint64_t iID, int t, int id) :
|
Bus(int angle, uint64_t iID, int t, int id) :
|
||||||
BaseNPC(angle, iID, t, id) {
|
BaseNPC(angle, iID, t, id) {
|
||||||
|
@ -68,13 +68,13 @@ void MobAI::followToCombat(Mob *mob) {
|
|||||||
}
|
}
|
||||||
Mob* followerMob = (Mob*)NPCManager::NPCs[leadMob->groupMember[i]];
|
Mob* followerMob = (Mob*)NPCManager::NPCs[leadMob->groupMember[i]];
|
||||||
|
|
||||||
if (followerMob->state != MobState::ROAMING) // only roaming mobs should transition to combat
|
if (followerMob->state != AIState::ROAMING) // only roaming mobs should transition to combat
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
enterCombat(mob->target, followerMob);
|
enterCombat(mob->target, followerMob);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (leadMob->state != MobState::ROAMING)
|
if (leadMob->state != AIState::ROAMING)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
enterCombat(mob->target, leadMob);
|
enterCombat(mob->target, leadMob);
|
||||||
@ -96,19 +96,19 @@ void MobAI::groupRetreat(Mob *mob) {
|
|||||||
}
|
}
|
||||||
Mob* followerMob = (Mob*)NPCManager::NPCs[leadMob->groupMember[i]];
|
Mob* followerMob = (Mob*)NPCManager::NPCs[leadMob->groupMember[i]];
|
||||||
|
|
||||||
if (followerMob->state != MobState::COMBAT)
|
if (followerMob->state != AIState::COMBAT)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
followerMob->target = nullptr;
|
followerMob->target = nullptr;
|
||||||
followerMob->state = MobState::RETREAT;
|
followerMob->state = AIState::RETREAT;
|
||||||
clearDebuff(followerMob);
|
clearDebuff(followerMob);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (leadMob->state != MobState::COMBAT)
|
if (leadMob->state != AIState::COMBAT)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
leadMob->target = nullptr;
|
leadMob->target = nullptr;
|
||||||
leadMob->state = MobState::RETREAT;
|
leadMob->state = AIState::RETREAT;
|
||||||
clearDebuff(leadMob);
|
clearDebuff(leadMob);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,7 +145,7 @@ bool MobAI::aggroCheck(Mob *mob, time_t currTime) {
|
|||||||
if (levelDifference > -10)
|
if (levelDifference > -10)
|
||||||
mobRange = levelDifference < 10 ? mobRange - (levelDifference * mobRange / 15) : mobRange / 3;
|
mobRange = levelDifference < 10 ? mobRange - (levelDifference * mobRange / 15) : mobRange / 3;
|
||||||
|
|
||||||
if (mob->state != MobState::ROAMING && plr->inCombat) // freshly out of aggro mobs
|
if (mob->state != AIState::ROAMING && plr->inCombat) // freshly out of aggro mobs
|
||||||
mobRange = mob->sightRange * 2; // should not be impacted by the above
|
mobRange = mob->sightRange * 2; // should not be impacted by the above
|
||||||
|
|
||||||
if (plr->iSpecialState & (CN_SPECIAL_STATE_FLAG__INVISIBLE|CN_SPECIAL_STATE_FLAG__INVULNERABLE))
|
if (plr->iSpecialState & (CN_SPECIAL_STATE_FLAG__INVISIBLE|CN_SPECIAL_STATE_FLAG__INVULNERABLE))
|
||||||
@ -267,7 +267,7 @@ static void dealCorruption(Mob *mob, std::vector<int> targetData, int skillID, i
|
|||||||
|
|
||||||
if (plr->HP <= 0) {
|
if (plr->HP <= 0) {
|
||||||
mob->target = nullptr;
|
mob->target = nullptr;
|
||||||
mob->state = MobState::RETREAT;
|
mob->state = AIState::RETREAT;
|
||||||
if (!aggroCheck(mob, getTime())) {
|
if (!aggroCheck(mob, getTime())) {
|
||||||
clearDebuff(mob);
|
clearDebuff(mob);
|
||||||
if (mob->groupLeader != 0)
|
if (mob->groupLeader != 0)
|
||||||
@ -395,7 +395,7 @@ static void useAbilities(Mob *mob, time_t currTime) {
|
|||||||
|
|
||||||
void MobAI::enterCombat(CNSocket *sock, Mob *mob) {
|
void MobAI::enterCombat(CNSocket *sock, Mob *mob) {
|
||||||
mob->target = sock;
|
mob->target = sock;
|
||||||
mob->state = MobState::COMBAT;
|
mob->state = AIState::COMBAT;
|
||||||
mob->nextMovement = getTime();
|
mob->nextMovement = getTime();
|
||||||
mob->nextAttack = 0;
|
mob->nextAttack = 0;
|
||||||
|
|
||||||
@ -473,7 +473,7 @@ void Mob::deadStep(time_t currTime) {
|
|||||||
std::cout << "respawning mob " << id << " with HP = " << maxHealth << std::endl;
|
std::cout << "respawning mob " << id << " with HP = " << maxHealth << std::endl;
|
||||||
|
|
||||||
hp = maxHealth;
|
hp = maxHealth;
|
||||||
state = MobState::ROAMING;
|
state = AIState::ROAMING;
|
||||||
|
|
||||||
// if mob is a group leader/follower, spawn where the group is.
|
// if mob is a group leader/follower, spawn where the group is.
|
||||||
if (groupLeader != 0) {
|
if (groupLeader != 0) {
|
||||||
@ -501,7 +501,7 @@ void Mob::combatStep(time_t currTime) {
|
|||||||
// lose aggro if the player lost connection
|
// lose aggro if the player lost connection
|
||||||
if (PlayerManager::players.find(target) == PlayerManager::players.end()) {
|
if (PlayerManager::players.find(target) == PlayerManager::players.end()) {
|
||||||
target = nullptr;
|
target = nullptr;
|
||||||
state = MobState::RETREAT;
|
state = AIState::RETREAT;
|
||||||
if (!aggroCheck(this, currTime)) {
|
if (!aggroCheck(this, currTime)) {
|
||||||
clearDebuff(this);
|
clearDebuff(this);
|
||||||
if (groupLeader != 0)
|
if (groupLeader != 0)
|
||||||
@ -516,7 +516,7 @@ void Mob::combatStep(time_t currTime) {
|
|||||||
if (plr->HP <= 0
|
if (plr->HP <= 0
|
||||||
|| (plr->iSpecialState & CN_SPECIAL_STATE_FLAG__INVULNERABLE)) {
|
|| (plr->iSpecialState & CN_SPECIAL_STATE_FLAG__INVULNERABLE)) {
|
||||||
target = nullptr;
|
target = nullptr;
|
||||||
state = MobState::RETREAT;
|
state = AIState::RETREAT;
|
||||||
if (!aggroCheck(this, currTime)) {
|
if (!aggroCheck(this, currTime)) {
|
||||||
clearDebuff(this);
|
clearDebuff(this);
|
||||||
if (groupLeader != 0)
|
if (groupLeader != 0)
|
||||||
@ -572,7 +572,6 @@ void Mob::combatStep(time_t currTime) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int distanceToTravel = INT_MAX;
|
int distanceToTravel = INT_MAX;
|
||||||
int speed = speed;
|
|
||||||
// movement logic: move when out of range but don't move while casting a skill
|
// movement logic: move when out of range but don't move while casting a skill
|
||||||
if (distance > mobRange && skillStyle == -1) {
|
if (distance > mobRange && skillStyle == -1) {
|
||||||
if (nextMovement != 0 && currTime < nextMovement)
|
if (nextMovement != 0 && currTime < nextMovement)
|
||||||
@ -628,7 +627,7 @@ void Mob::combatStep(time_t currTime) {
|
|||||||
distance = hypot(xyDistance, plr->z - roamZ);
|
distance = hypot(xyDistance, plr->z - roamZ);
|
||||||
if (distance >= data["m_iCombatRange"]) {
|
if (distance >= data["m_iCombatRange"]) {
|
||||||
target = nullptr;
|
target = nullptr;
|
||||||
state = MobState::RETREAT;
|
state = AIState::RETREAT;
|
||||||
clearDebuff(this);
|
clearDebuff(this);
|
||||||
if (groupLeader != 0)
|
if (groupLeader != 0)
|
||||||
groupRetreat(this);
|
groupRetreat(this);
|
||||||
@ -649,7 +648,7 @@ void Mob::roamingStep(time_t currTime) {
|
|||||||
* do so more often than if we waited for nextMovement (which is way too slow).
|
* do so more often than if we waited for nextMovement (which is way too slow).
|
||||||
* In the case of group leaders, this step will be called by dead mobs, so disable attack.
|
* In the case of group leaders, this step will be called by dead mobs, so disable attack.
|
||||||
*/
|
*/
|
||||||
if (state != MobState::DEAD && (nextAttack == 0 || currTime >= nextAttack)) {
|
if (state != AIState::DEAD && (nextAttack == 0 || currTime >= nextAttack)) {
|
||||||
nextAttack = currTime + 500;
|
nextAttack = currTime + 500;
|
||||||
if (aggroCheck(this, currTime))
|
if (aggroCheck(this, currTime))
|
||||||
return;
|
return;
|
||||||
@ -673,7 +672,6 @@ void Mob::roamingStep(time_t currTime) {
|
|||||||
|
|
||||||
int xStart = spawnX - idleRange/2;
|
int xStart = spawnX - idleRange/2;
|
||||||
int yStart = spawnY - idleRange/2;
|
int yStart = spawnY - idleRange/2;
|
||||||
int speed = speed;
|
|
||||||
|
|
||||||
// some mobs don't move (and we mustn't divide/modulus by zero)
|
// some mobs don't move (and we mustn't divide/modulus by zero)
|
||||||
if (idleRange == 0 || speed == 0)
|
if (idleRange == 0 || speed == 0)
|
||||||
@ -760,7 +758,7 @@ void Mob::retreatStep(time_t currTime) {
|
|||||||
// if we got there
|
// if we got there
|
||||||
//if (distance <= mob->data["m_iIdleRange"]) {
|
//if (distance <= mob->data["m_iIdleRange"]) {
|
||||||
if (distance <= 10) { // retreat back to the spawn point
|
if (distance <= 10) { // retreat back to the spawn point
|
||||||
state = MobState::ROAMING;
|
state = AIState::ROAMING;
|
||||||
hp = maxHealth;
|
hp = maxHealth;
|
||||||
killedTime = 0;
|
killedTime = 0;
|
||||||
nextAttack = 0;
|
nextAttack = 0;
|
||||||
@ -775,33 +773,3 @@ void Mob::retreatStep(time_t currTime) {
|
|||||||
clearDebuff(this);
|
clearDebuff(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::step(time_t currTime) {
|
|
||||||
assert(kind == EntityType::MOB);
|
|
||||||
|
|
||||||
if (playersInView < 0)
|
|
||||||
std::cout << "[WARN] Weird playerview value " << playersInView << std::endl;
|
|
||||||
|
|
||||||
// skip mob movement and combat if disabled or not in view
|
|
||||||
if ((!simulateMobs || playersInView == 0) && state != MobState::DEAD
|
|
||||||
&& state != MobState::RETREAT)
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch (state) {
|
|
||||||
case MobState::INACTIVE:
|
|
||||||
// no-op
|
|
||||||
break;
|
|
||||||
case MobState::ROAMING:
|
|
||||||
roamingStep(currTime);
|
|
||||||
break;
|
|
||||||
case MobState::COMBAT:
|
|
||||||
combatStep(currTime);
|
|
||||||
break;
|
|
||||||
case MobState::RETREAT:
|
|
||||||
retreatStep(currTime);
|
|
||||||
break;
|
|
||||||
case MobState::DEAD:
|
|
||||||
deadStep(currTime);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -2,19 +2,10 @@
|
|||||||
|
|
||||||
#include "core/Core.hpp"
|
#include "core/Core.hpp"
|
||||||
#include "NPCManager.hpp"
|
#include "NPCManager.hpp"
|
||||||
|
#include "Entities.hpp"
|
||||||
enum class MobState {
|
|
||||||
INACTIVE,
|
|
||||||
ROAMING,
|
|
||||||
COMBAT,
|
|
||||||
RETREAT,
|
|
||||||
DEAD
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Mob : public CombatNPC {
|
struct Mob : public CombatNPC {
|
||||||
// general
|
// general
|
||||||
MobState state = MobState::INACTIVE;
|
|
||||||
|
|
||||||
std::unordered_map<int32_t,time_t> unbuffTimes = {};
|
std::unordered_map<int32_t,time_t> unbuffTimes = {};
|
||||||
|
|
||||||
// dead
|
// dead
|
||||||
@ -42,16 +33,13 @@ struct Mob : public CombatNPC {
|
|||||||
int offsetX = 0, offsetY = 0;
|
int offsetX = 0, offsetY = 0;
|
||||||
int groupMember[4] = {};
|
int groupMember[4] = {};
|
||||||
|
|
||||||
// for optimizing away AI in empty chunks
|
|
||||||
int playersInView = 0;
|
|
||||||
|
|
||||||
// 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 x, int y, int z, 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(x, y, z, angle, iID, t, id, d["m_iHP"]),
|
||||||
sightRange(d["m_iSightRange"]) {
|
sightRange(d["m_iSightRange"]) {
|
||||||
state = MobState::ROAMING;
|
state = AIState::ROAMING;
|
||||||
|
|
||||||
data = d;
|
data = d;
|
||||||
|
|
||||||
@ -83,13 +71,10 @@ struct Mob : public CombatNPC {
|
|||||||
|
|
||||||
~Mob() {}
|
~Mob() {}
|
||||||
|
|
||||||
virtual void step(time_t currTime) override;
|
virtual void roamingStep(time_t currTime) override;
|
||||||
|
virtual void combatStep(time_t currTime) override;
|
||||||
// we may or may not want these to be generalized to all CombatNPCs later
|
virtual void retreatStep(time_t currTime) override;
|
||||||
void roamingStep(time_t currTime);
|
virtual void deadStep(time_t currTime) override;
|
||||||
void combatStep(time_t currTime);
|
|
||||||
void retreatStep(time_t currTime);
|
|
||||||
void deadStep(time_t currTime);
|
|
||||||
|
|
||||||
auto operator[](std::string s) {
|
auto operator[](std::string s) {
|
||||||
return data[s];
|
return data[s];
|
||||||
|
@ -263,7 +263,7 @@ static void stepNPCPathing() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// do not roam if not roaming
|
// do not roam if not roaming
|
||||||
if (npc->kind == EntityType::MOB && ((Mob*)npc)->state != MobState::ROAMING) {
|
if (npc->kind == EntityType::MOB && ((Mob*)npc)->state != AIState::ROAMING) {
|
||||||
it++;
|
it++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user