mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2025-11-25 10:40:13 +00:00
Compare commits
31 Commits
ea033a97dd
...
refactor
| Author | SHA1 | Date | |
|---|---|---|---|
| 9b2a65f8fd | |||
| 6a69388822 | |||
| 2924a27eb4 | |||
| ba20f5a401 | |||
|
|
eb88fa05cb | ||
|
|
0b73cef187 | ||
|
|
7af39b3d04 | ||
|
|
33206b1207 | ||
|
|
e325f7a40b | ||
|
|
82bee2051a | ||
|
|
4ece1bb89b | ||
|
|
31677e2638 | ||
|
|
d32827b692 | ||
|
|
13c009b448 | ||
|
|
a032497bed | ||
|
|
3b6b61d087 | ||
|
|
6d760f5bce | ||
|
|
2a622f901c | ||
|
|
03d28bf4e4 | ||
|
|
4b834579c5 | ||
|
|
07fe8ca367 | ||
|
|
2f3f8a3951 | ||
| 4f890a9c07 | |||
| 8517e0c7de | |||
| 5fb0cbbcf7 | |||
| 55e9f6531d | |||
|
|
7726357fbe | ||
|
|
564c275d51 | ||
|
|
3ce9ae5f77 | ||
|
|
7c5b9a8105 | ||
|
|
258ff35e20 |
@@ -76,12 +76,20 @@ static SkillResult handleSkillDamageNDebuff(SkillData* skill, int power, ICombat
|
|||||||
}
|
}
|
||||||
|
|
||||||
sSkillResult_Damage_N_Debuff result{};
|
sSkillResult_Damage_N_Debuff result{};
|
||||||
|
|
||||||
result.iDamage = duration / 10; // we use the duration as the damage number (why?)
|
result.iDamage = duration / 10; // we use the duration as the damage number (why?)
|
||||||
result.iHP = target->getCurrentHP();
|
result.iHP = target->getCurrentHP();
|
||||||
result.eCT = target->getCharType();
|
result.eCT = target->getCharType();
|
||||||
result.iID = target->getID();
|
result.iID = target->getID();
|
||||||
result.bProtected = blocked;
|
result.bProtected = blocked;
|
||||||
result.iConditionBitFlag = target->getCompositeCondition();
|
result.iConditionBitFlag = target->getCompositeCondition();
|
||||||
|
|
||||||
|
// for player targets, make sure to update Nano stamina
|
||||||
|
if (target->getCharType() == 1) {
|
||||||
|
Player *plr = dynamic_cast<Player*>(target);
|
||||||
|
result.iStamina = plr->getActiveNano()->iStamina;
|
||||||
|
}
|
||||||
|
|
||||||
return SkillResult(sizeof(sSkillResult_Damage_N_Debuff), &result);
|
return SkillResult(sizeof(sSkillResult_Damage_N_Debuff), &result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +120,8 @@ static SkillResult handleSkillBuff(SkillData* skill, int power, ICombatant* sour
|
|||||||
int duration = skill->durationTime[power];
|
int duration = skill->durationTime[power];
|
||||||
int strength = skill->values[0][power];
|
int strength = skill->values[0][power];
|
||||||
BuffStack passiveBuff = {
|
BuffStack passiveBuff = {
|
||||||
skill->drainType == SkillDrainType::PASSIVE ? 1 : (duration * 100) / MS_PER_COMBAT_TICK, // ticks
|
// if the duration is 0, it needs to be recast every tick
|
||||||
|
duration == 0 ? 1 : (duration * 100) / MS_PER_COMBAT_TICK, // ticks
|
||||||
strength, // value
|
strength, // value
|
||||||
source->getRef(), // source
|
source->getRef(), // source
|
||||||
source == target ? BuffClass::NANO : BuffClass::GROUP_NANO, // buff class
|
source == target ? BuffClass::NANO : BuffClass::GROUP_NANO, // buff class
|
||||||
@@ -123,7 +132,7 @@ static SkillResult handleSkillBuff(SkillData* skill, int power, ICombatant* sour
|
|||||||
int combatLifetime = 0;
|
int combatLifetime = 0;
|
||||||
if(!target->addBuff(timeBuffId,
|
if(!target->addBuff(timeBuffId,
|
||||||
[drainType](EntityRef self, Buff* buff, int status, BuffStack* stack) {
|
[drainType](EntityRef self, Buff* buff, int status, BuffStack* stack) {
|
||||||
if(buff->id == ECSB_BOUNDINGBALL) {
|
if(buff->id == ECSB_BOUNDINGBALL && status == ETBU_ADD) {
|
||||||
// drain
|
// drain
|
||||||
ICombatant* combatant = dynamic_cast<ICombatant*>(self.getEntity());
|
ICombatant* combatant = dynamic_cast<ICombatant*>(self.getEntity());
|
||||||
combatant->takeDamage(buff->getLastSource(), 0); // aggro
|
combatant->takeDamage(buff->getLastSource(), 0); // aggro
|
||||||
@@ -138,7 +147,7 @@ static SkillResult handleSkillBuff(SkillData* skill, int power, ICombatant* sour
|
|||||||
Buffs::tickDrain(self, buff, COMBAT_TICKS_PER_DRAIN_PROC); // drain
|
Buffs::tickDrain(self, buff, COMBAT_TICKS_PER_DRAIN_PROC); // drain
|
||||||
combatLifetime++;
|
combatLifetime++;
|
||||||
},
|
},
|
||||||
&passiveBuff)) return SkillResult(); // no result if already buffed
|
&passiveBuff)) return SkillResult();
|
||||||
|
|
||||||
sSkillResult_Buff result{};
|
sSkillResult_Buff result{};
|
||||||
result.eCT = target->getCharType();
|
result.eCT = target->getCharType();
|
||||||
|
|||||||
@@ -15,12 +15,12 @@ constexpr size_t MAX_SKILLRESULT_SIZE = sizeof(sSkillResult_BatteryDrain);
|
|||||||
enum class SkillType {
|
enum class SkillType {
|
||||||
DAMAGE = 1,
|
DAMAGE = 1,
|
||||||
HEAL_HP = 2,
|
HEAL_HP = 2,
|
||||||
KNOCKDOWN = 3, // dnd
|
KNOCKDOWN = 3, // uses DamageNDebuff
|
||||||
SLEEP = 4, // dnd
|
SLEEP = 4, // uses DamageNDebuff
|
||||||
SNARE = 5, // dnd
|
SNARE = 5, // uses DamageNDebuff
|
||||||
HEAL_STAMINA = 6,
|
HEAL_STAMINA = 6,
|
||||||
STAMINA_SELF = 7,
|
STAMINA_SELF = 7,
|
||||||
STUN = 8, // dnd
|
STUN = 8, // uses DamageNDebuff
|
||||||
WEAPONSLOW = 9,
|
WEAPONSLOW = 9,
|
||||||
JUMP = 10,
|
JUMP = 10,
|
||||||
RUN = 11,
|
RUN = 11,
|
||||||
|
|||||||
@@ -175,10 +175,13 @@ void Player::step(time_t currTime) {
|
|||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region CombatNPC
|
#pragma region CombatNPC
|
||||||
bool CombatNPC::addBuff(int buffId, BuffCallback<int, BuffStack*> onUpdate, BuffCallback<time_t> onTick, BuffStack* stack) { /* stubbed */
|
bool CombatNPC::addBuff(int buffId, BuffCallback<int, BuffStack*> onUpdate, BuffCallback<time_t> onTick, BuffStack* stack) {
|
||||||
if(!isAlive())
|
if(!isAlive())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (this->state != AIState::COMBAT && this->state != AIState::ROAMING)
|
||||||
|
return false;
|
||||||
|
|
||||||
if(!hasBuff(buffId)) {
|
if(!hasBuff(buffId)) {
|
||||||
buffs[buffId] = new Buff(buffId, getRef(), onUpdate, onTick, stack);
|
buffs[buffId] = new Buff(buffId, getRef(), onUpdate, onTick, stack);
|
||||||
return true;
|
return true;
|
||||||
@@ -189,7 +192,7 @@ bool CombatNPC::addBuff(int buffId, BuffCallback<int, BuffStack*> onUpdate, Buff
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Buff* CombatNPC::getBuff(int buffId) { /* stubbed */
|
Buff* CombatNPC::getBuff(int buffId) {
|
||||||
if(hasBuff(buffId)) {
|
if(hasBuff(buffId)) {
|
||||||
return buffs[buffId];
|
return buffs[buffId];
|
||||||
}
|
}
|
||||||
@@ -307,19 +310,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
|
||||||
|
|
||||||
|
|||||||
@@ -359,19 +359,23 @@ static void npcRotateCommand(std::string full, std::vector<std::string>& args, C
|
|||||||
int angle = (plr->angle + 180) % 360;
|
int angle = (plr->angle + 180) % 360;
|
||||||
NPCManager::updateNPCPosition(npc->id, npc->x, npc->y, npc->z, npc->instanceID, angle);
|
NPCManager::updateNPCPosition(npc->id, npc->x, npc->y, npc->z, npc->instanceID, angle);
|
||||||
|
|
||||||
bool isGruntworkNpc = true;
|
// if it's a gruntwork NPC, rotate in-place
|
||||||
|
if (TableData::RunningMobs.find(npc->id) != TableData::RunningMobs.end()) {
|
||||||
|
NPCManager::updateNPCPosition(npc->id, npc->x, npc->y, npc->z, npc->instanceID, angle);
|
||||||
|
|
||||||
// add a rotation entry to the gruntwork file, unless it's already a gruntwork NPC
|
Chat::sendServerMessage(sock, "[NPCR] Successfully set angle to " + std::to_string(angle) + " for gruntwork NPC "
|
||||||
if (TableData::RunningMobs.find(npc->id) == TableData::RunningMobs.end()) {
|
+ std::to_string(npc->id));
|
||||||
|
} else {
|
||||||
TableData::RunningNPCRotations[npc->id] = angle;
|
TableData::RunningNPCRotations[npc->id] = angle;
|
||||||
isGruntworkNpc = false;
|
|
||||||
|
Chat::sendServerMessage(sock, "[NPCR] Successfully set angle to " + std::to_string(angle) + " for NPC "
|
||||||
|
+ std::to_string(npc->id));
|
||||||
}
|
}
|
||||||
|
|
||||||
Chat::sendServerMessage(sock, "[NPCR] Successfully set angle to " + std::to_string(angle) +
|
// update rotation clientside
|
||||||
" for " + (isGruntworkNpc ? "gruntwork " : "") + "NPC " + std::to_string(npc->id));
|
INITSTRUCT(sP_FE2CL_NPC_ENTER, pkt);
|
||||||
|
pkt.NPCAppearanceData = npc->getAppearanceData();
|
||||||
// update rotation clientside by refreshing the player's chunks (same as the /refresh command)
|
sock->sendPacket(pkt, P_FE2CL_NPC_ENTER);
|
||||||
PlayerManager::updatePlayerPositionForWarp(sock, plr->x, plr->y, plr->z, plr->instanceID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void refreshCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
static void refreshCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user