mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-11-26 15:00:06 +00:00
YET ANOTHER ITERATION of the new ability system
I am very tired
This commit is contained in:
parent
5b58055924
commit
d4253c3b49
@ -104,9 +104,11 @@ int Abilities::getCSTBFromST(int eSkillType) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#pragma region Skill Handlers
|
#pragma region Skill Handlers
|
||||||
void Abilities::usePassiveNanoSkill(SkillData* skill, Player* plr, int boost) {
|
bool Abilities::usePassiveNanoSkill(SkillData* skill, Player* plr, int boost) {
|
||||||
assert(skill->drainType == SkillDrainType::PASSIVE);
|
assert(skill->drainType == SkillDrainType::PASSIVE);
|
||||||
|
|
||||||
|
bool newBuffApplied = false;
|
||||||
|
|
||||||
EntityRef self = PlayerManager::getSockFromID(plr->iID);
|
EntityRef self = PlayerManager::getSockFromID(plr->iID);
|
||||||
std::vector<EntityRef> targets;
|
std::vector<EntityRef> targets;
|
||||||
if (skill->targetType == SkillTargetType::GROUP) {
|
if (skill->targetType == SkillTargetType::GROUP) {
|
||||||
@ -126,14 +128,6 @@ void Abilities::usePassiveNanoSkill(SkillData* skill, Player* plr, int boost) {
|
|||||||
value,
|
value,
|
||||||
self,
|
self,
|
||||||
BuffClass::NONE, // overwritten per target
|
BuffClass::NONE, // overwritten per target
|
||||||
[](EntityRef host, BuffStack* stack) {
|
|
||||||
Buffs::timeBuffUpdate(host, stack, ETBU_ADD);
|
|
||||||
// TODO SKILLUSE/SKILLUSESUCC, sSkillResult_Buff
|
|
||||||
},
|
|
||||||
nullptr,
|
|
||||||
[](EntityRef host, BuffStack* stack) {
|
|
||||||
Buffs::timeBuffUpdate(host, stack, ETBU_DEL);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for (EntityRef target : targets) {
|
for (EntityRef target : targets) {
|
||||||
@ -143,8 +137,17 @@ void Abilities::usePassiveNanoSkill(SkillData* skill, Player* plr, int boost) {
|
|||||||
|
|
||||||
passiveBuff.buffStackClass = target == self ? BuffClass::NANO : BuffClass::GROUP_NANO;
|
passiveBuff.buffStackClass = target == self ? BuffClass::NANO : BuffClass::GROUP_NANO;
|
||||||
ICombatant* combatant = dynamic_cast<ICombatant*>(entity);
|
ICombatant* combatant = dynamic_cast<ICombatant*>(entity);
|
||||||
combatant->addBuff(timeBuffId, &passiveBuff);
|
newBuffApplied |= combatant->addBuff(timeBuffId,
|
||||||
|
[](EntityRef self, Buff* buff, int status, BuffStack* stack) {
|
||||||
|
Buffs::timeBuffUpdate(self, buff, status, stack);
|
||||||
|
},
|
||||||
|
[](EntityRef self, Buff* buff, time_t currTime) {
|
||||||
|
// TODO time buff tick
|
||||||
|
},
|
||||||
|
&passiveBuff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return newBuffApplied;
|
||||||
}
|
}
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ namespace Abilities {
|
|||||||
std::vector<EntityRef> matchTargets(SkillData*, int, int32_t*);
|
std::vector<EntityRef> matchTargets(SkillData*, int, int32_t*);
|
||||||
int getCSTBFromST(int eSkillType);
|
int getCSTBFromST(int eSkillType);
|
||||||
|
|
||||||
void usePassiveNanoSkill(SkillData*, Player*, int);
|
bool usePassiveNanoSkill(SkillData*, Player*, int);
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
}
|
}
|
||||||
|
@ -4,19 +4,16 @@
|
|||||||
|
|
||||||
using namespace Buffs;
|
using namespace Buffs;
|
||||||
|
|
||||||
void Buff::tick() {
|
void Buff::tick(time_t currTime) {
|
||||||
auto it = stacks.begin();
|
auto it = stacks.begin();
|
||||||
while(it != stacks.end()) {
|
while(it != stacks.end()) {
|
||||||
BuffStack& stack = *it;
|
BuffStack& stack = *it;
|
||||||
if(stack.onTick) stack.onTick(self, &stack);
|
if(onTick) onTick(self, this, currTime);
|
||||||
|
|
||||||
if(stack.durationTicks == 0) {
|
if(stack.durationTicks == 0) {
|
||||||
// erase() destroys the callbacks
|
|
||||||
// with the stack struct, so we need
|
|
||||||
// to copy it first.
|
|
||||||
BuffStack deadStack = stack;
|
BuffStack deadStack = stack;
|
||||||
it = stacks.erase(it);
|
it = stacks.erase(it);
|
||||||
if(deadStack.onExpire) deadStack.onExpire(self, &deadStack);
|
if(onUpdate) onUpdate(self, this, ETBU_DEL, &deadStack);
|
||||||
} else {
|
} else {
|
||||||
if(stack.durationTicks > 0) stack.durationTicks--;
|
if(stack.durationTicks > 0) stack.durationTicks--;
|
||||||
it++;
|
it++;
|
||||||
@ -28,15 +25,13 @@ void Buff::clear() {
|
|||||||
while(!stacks.empty()) {
|
while(!stacks.empty()) {
|
||||||
BuffStack stack = stacks.back();
|
BuffStack stack = stacks.back();
|
||||||
stacks.pop_back();
|
stacks.pop_back();
|
||||||
if(stack.onExpire) stack.onExpire(self, &stack);
|
if(onUpdate) onUpdate(self, this, ETBU_DEL, &stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Buff::addStack(BuffStack* stack) {
|
void Buff::addStack(BuffStack* stack) {
|
||||||
BuffStack newStack = *stack;
|
stacks.push_back(*stack);
|
||||||
newStack.buff = this;
|
if(onUpdate) onUpdate(self, this, ETBU_ADD, &stacks.back());
|
||||||
if(newStack.onApply) newStack.onApply(self, &newStack);
|
|
||||||
stacks.push_back(newStack);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Buff::hasClass(BuffClass buffClass) {
|
bool Buff::hasClass(BuffClass buffClass) {
|
||||||
@ -56,34 +51,68 @@ BuffClass Buff::maxClass() {
|
|||||||
return buffClass;
|
return buffClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Buff::getValue(BuffValueSelector selector) {
|
||||||
|
if(isStale()) return 0;
|
||||||
|
|
||||||
|
int value = selector == BuffValueSelector::NET_TOTAL ? 0 : stacks.front().value;
|
||||||
|
for(BuffStack& stack : stacks) {
|
||||||
|
switch(selector)
|
||||||
|
{
|
||||||
|
case BuffValueSelector::NET_TOTAL:
|
||||||
|
value += stack.value;
|
||||||
|
break;
|
||||||
|
case BuffValueSelector::MIN_VALUE:
|
||||||
|
if(stack.value < value) value = stack.value;
|
||||||
|
break;
|
||||||
|
case BuffValueSelector::MAX_VALUE:
|
||||||
|
if(stack.value > value) value = stack.value;
|
||||||
|
break;
|
||||||
|
case BuffValueSelector::MIN_MAGNITUDE:
|
||||||
|
if(abs(stack.value) < abs(value)) value = stack.value;
|
||||||
|
break;
|
||||||
|
case BuffValueSelector::MAX_MAGNITUDE:
|
||||||
|
default:
|
||||||
|
if(abs(stack.value) > abs(value)) value = stack.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
bool Buff::isStale() {
|
bool Buff::isStale() {
|
||||||
return stacks.empty();
|
return stacks.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This will practically never do anything important, but it's here just in case */
|
||||||
|
void Buff::updateCallbacks(BuffCallback<int, BuffStack*> fOnUpdate, BuffCallback<time_t> fonTick) {
|
||||||
|
if(!onUpdate) onUpdate = fOnUpdate;
|
||||||
|
if(!onTick) onTick = fonTick;
|
||||||
|
}
|
||||||
|
|
||||||
#pragma region Handlers
|
#pragma region Handlers
|
||||||
void Buffs::timeBuffUpdate(EntityRef self, BuffStack* stack, int status) {
|
void Buffs::timeBuffUpdate(EntityRef self, Buff* buff, int status, BuffStack* stack) {
|
||||||
|
|
||||||
if(self.kind != EntityKind::PLAYER)
|
if(self.kind != EntityKind::PLAYER)
|
||||||
return; // not implemented
|
return; // not implemented
|
||||||
|
|
||||||
Player* plr = (Player*)self.getEntity();
|
Player* plr = (Player*)self.getEntity();
|
||||||
if(plr == nullptr)
|
if(plr == nullptr)
|
||||||
return;
|
return; // sanity check
|
||||||
|
|
||||||
if(status == ETBU_DEL && plr->hasBuff(stack->buff->id))
|
if(status == ETBU_DEL && !buff->isStale())
|
||||||
return; // no premature status removal!
|
return; // no premature effect deletion
|
||||||
|
|
||||||
sTimeBuff payload{};
|
|
||||||
|
|
||||||
int cbf = plr->getCompositeCondition();
|
int cbf = plr->getCompositeCondition();
|
||||||
|
sTimeBuff payload{};
|
||||||
if(status == ETBU_ADD) {
|
if(status == ETBU_ADD) {
|
||||||
if(stack->buff->id > 0) cbf |= CSB_FROM_ECSB(stack->buff->id);
|
payload.iValue = buff->getValue(BuffValueSelector::MAX_MAGNITUDE);
|
||||||
payload.iValue = stack->value;
|
// we need to explicitly add the ECSB for this buff,
|
||||||
//payload.iTimeLimit = stack->durationTicks * MS_PER_PLAYER_TICK;
|
// in case this is the first stack in and the entry
|
||||||
|
// in the buff map doesn't yet exist
|
||||||
|
if(buff->id > 0) cbf |= CSB_FROM_ECSB(buff->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
INITSTRUCT(sP_FE2CL_PC_BUFF_UPDATE, pkt);
|
INITSTRUCT(sP_FE2CL_PC_BUFF_UPDATE, pkt);
|
||||||
pkt.eCSTB = stack->buff->id; // eCharStatusTimeBuffID
|
pkt.eCSTB = buff->id; // eCharStatusTimeBuffID
|
||||||
pkt.eTBU = status; // eTimeBuffUpdate
|
pkt.eTBU = status; // eTimeBuffUpdate
|
||||||
pkt.eTBT = (int)stack->buffStackClass;
|
pkt.eTBT = (int)stack->buffStackClass;
|
||||||
pkt.iConditionBitFlag = cbf;
|
pkt.iConditionBitFlag = cbf;
|
||||||
@ -91,20 +120,15 @@ void Buffs::timeBuffUpdate(EntityRef self, BuffStack* stack, int status) {
|
|||||||
self.sock->sendPacket((void*)&pkt, P_FE2CL_PC_BUFF_UPDATE, sizeof(sP_FE2CL_PC_BUFF_UPDATE));
|
self.sock->sendPacket((void*)&pkt, P_FE2CL_PC_BUFF_UPDATE, sizeof(sP_FE2CL_PC_BUFF_UPDATE));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Buffs::timeBuffTimeoutViewable(EntityRef self, BuffStack* stack, int ct) {
|
/*
|
||||||
if(self.kind != EntityKind::PLAYER)
|
void Buffs::timeBuffTimeoutViewable(EntityRef self, Buff* buff, int ct) {
|
||||||
return; // not implemented
|
|
||||||
|
|
||||||
Player* plr = (Player*)self.getEntity();
|
|
||||||
if(plr == nullptr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, pkt); // send a buff timeout to other players
|
INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, pkt); // send a buff timeout to other players
|
||||||
pkt.eCT = ct; // 1 for eggs, at least
|
pkt.eCT = ct; // 1 for eggs, at least
|
||||||
pkt.iID = plr->iID;
|
pkt.iID = plr->iID;
|
||||||
pkt.iConditionBitFlag = plr->getCompositeCondition();
|
pkt.iConditionBitFlag = plr->getCompositeCondition();
|
||||||
PlayerManager::sendToViewable(self.sock, pkt, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT);
|
PlayerManager::sendToViewable(self.sock, pkt, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
/* MOVE TO EGG LAMBDA
|
/* MOVE TO EGG LAMBDA
|
||||||
void Buffs::timeBuffTimeout(EntityRef self, BuffStack* buff) {
|
void Buffs::timeBuffTimeout(EntityRef self, BuffStack* buff) {
|
||||||
|
@ -2,13 +2,15 @@
|
|||||||
|
|
||||||
#include "core/Core.hpp"
|
#include "core/Core.hpp"
|
||||||
|
|
||||||
#include "Entities.hpp"
|
#include "EntityRef.hpp"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
/* forward declaration(s) */
|
/* forward declaration(s) */
|
||||||
struct BuffStack;
|
class Buff;
|
||||||
|
template<class... Types>
|
||||||
|
using BuffCallback = std::function<void(EntityRef, Buff*, Types...)>;
|
||||||
|
|
||||||
#define CSB_FROM_ECSB(x) (1 << (x - 1))
|
#define CSB_FROM_ECSB(x) (1 << (x - 1))
|
||||||
|
|
||||||
@ -22,24 +24,19 @@ enum class BuffClass {
|
|||||||
CASH_ITEM = ETBT_CASHITEM
|
CASH_ITEM = ETBT_CASHITEM
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::function<void(EntityRef, BuffStack*)> BuffCallback;
|
enum class BuffValueSelector {
|
||||||
|
MAX_VALUE,
|
||||||
|
MIN_VALUE,
|
||||||
|
MAX_MAGNITUDE,
|
||||||
|
MIN_MAGNITUDE,
|
||||||
|
NET_TOTAL
|
||||||
|
};
|
||||||
|
|
||||||
struct BuffStack {
|
struct BuffStack {
|
||||||
int durationTicks;
|
int durationTicks;
|
||||||
int value;
|
int value;
|
||||||
EntityRef source;
|
EntityRef source;
|
||||||
BuffClass buffStackClass;
|
BuffClass buffStackClass;
|
||||||
|
|
||||||
/* called just before the stack is added */
|
|
||||||
BuffCallback onApply;
|
|
||||||
|
|
||||||
/* called when the stack is ticked */
|
|
||||||
BuffCallback onTick;
|
|
||||||
|
|
||||||
/* called just after the stack is removed */
|
|
||||||
BuffCallback onExpire;
|
|
||||||
|
|
||||||
Buff* buff;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Buff {
|
class Buff {
|
||||||
@ -49,8 +46,12 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
int id;
|
int id;
|
||||||
|
/* called just after a stack is added or removed */
|
||||||
|
BuffCallback<int, BuffStack*> onUpdate;
|
||||||
|
/* called when the buff is ticked */
|
||||||
|
BuffCallback<time_t> onTick;
|
||||||
|
|
||||||
void tick();
|
void tick(time_t);
|
||||||
void clear();
|
void clear();
|
||||||
void addStack(BuffStack* stack);
|
void addStack(BuffStack* stack);
|
||||||
|
|
||||||
@ -62,6 +63,8 @@ public:
|
|||||||
bool hasClass(BuffClass buffClass);
|
bool hasClass(BuffClass buffClass);
|
||||||
BuffClass maxClass();
|
BuffClass maxClass();
|
||||||
|
|
||||||
|
int getValue(BuffValueSelector selector);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In general, a Buff object won't exist
|
* In general, a Buff object won't exist
|
||||||
* unless it has stacks. However, when
|
* unless it has stacks. However, when
|
||||||
@ -71,13 +74,15 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool isStale();
|
bool isStale();
|
||||||
|
|
||||||
Buff(int iid, EntityRef pSelf, BuffStack* firstStack)
|
void updateCallbacks(BuffCallback<int, BuffStack*> fOnUpdate, BuffCallback<time_t> fonTick);
|
||||||
: id(iid), self(pSelf) {
|
|
||||||
|
Buff(int iid, EntityRef pSelf, BuffCallback<int, BuffStack*> fOnUpdate, BuffCallback<time_t> fOnTick, BuffStack* firstStack)
|
||||||
|
: self(pSelf), id(iid), onUpdate(fOnUpdate), onTick(fOnTick) {
|
||||||
addStack(firstStack);
|
addStack(firstStack);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace Buffs {
|
namespace Buffs {
|
||||||
void timeBuffUpdate(EntityRef self, BuffStack* stack, int status);
|
void timeBuffUpdate(EntityRef self, Buff* buff, int status, BuffStack* stack);
|
||||||
void timeBuffTimeoutViewable(EntityRef self, BuffStack* stack, int ct);
|
//void timeBuffTimeoutViewable(EntityRef self, Buff* buff, int ct);
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,17 @@ using namespace Combat;
|
|||||||
/// Player Id -> Bullet Id -> Bullet
|
/// Player Id -> Bullet Id -> Bullet
|
||||||
std::map<int32_t, std::map<int8_t, Bullet>> Combat::Bullets;
|
std::map<int32_t, std::map<int8_t, Bullet>> Combat::Bullets;
|
||||||
|
|
||||||
void Player::addBuff(int buffId, BuffStack* stack) {
|
bool Player::addBuff(int buffId, BuffCallback<int, BuffStack*> onUpdate, BuffCallback<time_t> onTick, BuffStack* stack) {
|
||||||
EntityRef self = PlayerManager::getSockFromID(iID);
|
EntityRef self = PlayerManager::getSockFromID(iID);
|
||||||
if(!hasBuff(buffId)) buffs[buffId] = new Buff(buffId, self, stack);
|
|
||||||
else buffs[buffId]->addStack(stack);
|
if(!hasBuff(buffId)) {
|
||||||
|
buffs[buffId] = new Buff(buffId, self, onUpdate, onTick, stack);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffs[buffId]->updateCallbacks(onUpdate, onTick);
|
||||||
|
buffs[buffId]->addStack(stack);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Buff* Player::getBuff(int buffId) {
|
Buff* Player::getBuff(int buffId) {
|
||||||
@ -88,7 +95,9 @@ void Player::step(time_t currTime) {
|
|||||||
// no-op
|
// no-op
|
||||||
}
|
}
|
||||||
|
|
||||||
void CombatNPC::addBuff(int buffId, BuffStack* stack) { /* stubbed */ }
|
bool CombatNPC::addBuff(int buffId, BuffCallback<int, BuffStack*> onUpdate, BuffCallback<time_t> onTick, BuffStack* stack) { /* stubbed */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Buff* CombatNPC::getBuff(int buffId) { /* stubbed */
|
Buff* CombatNPC::getBuff(int buffId) { /* stubbed */
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -342,43 +351,20 @@ static void combatEnd(CNSocket *sock, CNPacketData *data) {
|
|||||||
plr->healCooldown = 4000;
|
plr->healCooldown = 4000;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dotDamageOnOff(CNSocket *sock, CNPacketData *data) {
|
static void dealGooDamage(CNSocket *sock) {
|
||||||
sP_CL2FE_DOT_DAMAGE_ONOFF *pkt = (sP_CL2FE_DOT_DAMAGE_ONOFF*)data->buf;
|
|
||||||
Player *plr = PlayerManager::getPlayer(sock);
|
Player *plr = PlayerManager::getPlayer(sock);
|
||||||
|
if(plr->iSpecialState & CN_SPECIAL_STATE_FLAG__INVULNERABLE)
|
||||||
|
return; // ignore completely
|
||||||
|
|
||||||
// infection debuff toggles as the client asks it to,
|
|
||||||
// so we add and remove a permanent debuff
|
|
||||||
if (pkt->iFlag && !plr->hasBuff(ECSB_INFECTION)) {
|
|
||||||
BuffStack infection = {
|
|
||||||
-1, // infinite
|
|
||||||
NULL,
|
|
||||||
sock, // self-inflicted
|
|
||||||
BuffClass::ENVIRONMENT,
|
|
||||||
[](EntityRef host, BuffStack* stack) {
|
|
||||||
Buffs::timeBuffUpdate(host, stack, ETBU_ADD);
|
|
||||||
},
|
|
||||||
nullptr, // client toggles for us! todo anticheat lol
|
|
||||||
[](EntityRef host, BuffStack* stack) {
|
|
||||||
Buffs::timeBuffUpdate(host, stack, ETBU_DEL);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
plr->addBuff(ECSB_INFECTION, &infection);
|
|
||||||
} else if(!pkt->iFlag && plr->hasBuff(ECSB_INFECTION)) {
|
|
||||||
plr->removeBuff(ECSB_INFECTION);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dealGooDamage(CNSocket *sock, int amount) {
|
|
||||||
size_t resplen = sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK) + sizeof(sSkillResult_DotDamage);
|
size_t resplen = sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK) + sizeof(sSkillResult_DotDamage);
|
||||||
assert(resplen < CN_PACKET_BUFFER_SIZE - 8);
|
assert(resplen < CN_PACKET_BUFFER_SIZE - 8);
|
||||||
uint8_t respbuf[CN_PACKET_BUFFER_SIZE];
|
uint8_t respbuf[CN_PACKET_BUFFER_SIZE];
|
||||||
Player *plr = PlayerManager::getPlayer(sock);
|
|
||||||
|
|
||||||
memset(respbuf, 0, resplen);
|
memset(respbuf, 0, resplen);
|
||||||
|
|
||||||
sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK *pkt = (sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK*)respbuf;
|
sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK *pkt = (sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK*)respbuf;
|
||||||
sSkillResult_DotDamage *dmg = (sSkillResult_DotDamage*)(respbuf + sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK));
|
sSkillResult_DotDamage *dmg = (sSkillResult_DotDamage*)(respbuf + sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK));
|
||||||
|
|
||||||
|
int amount = PC_MAXHEALTH(plr->level) * 3 / 20;
|
||||||
Buff* protectionBuff = plr->getBuff(ECSB_PROTECT_INFECTION);
|
Buff* protectionBuff = plr->getBuff(ECSB_PROTECT_INFECTION);
|
||||||
if (protectionBuff != nullptr) {
|
if (protectionBuff != nullptr) {
|
||||||
amount = -2; // -2 is the magic number for "Protected" to appear as the damage number
|
amount = -2; // -2 is the magic number for "Protected" to appear as the damage number
|
||||||
@ -415,6 +401,33 @@ static void dealGooDamage(CNSocket *sock, int amount) {
|
|||||||
PlayerManager::sendToViewable(sock, (void*)&respbuf, P_FE2CL_CHAR_TIME_BUFF_TIME_TICK, resplen);
|
PlayerManager::sendToViewable(sock, (void*)&respbuf, P_FE2CL_CHAR_TIME_BUFF_TIME_TICK, resplen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dotDamageOnOff(CNSocket *sock, CNPacketData *data) {
|
||||||
|
sP_CL2FE_DOT_DAMAGE_ONOFF *pkt = (sP_CL2FE_DOT_DAMAGE_ONOFF*)data->buf;
|
||||||
|
Player *plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
|
// infection debuff toggles as the client asks it to,
|
||||||
|
// so we add and remove a permanent debuff
|
||||||
|
if (pkt->iFlag && !plr->hasBuff(ECSB_INFECTION)) {
|
||||||
|
BuffStack infection = {
|
||||||
|
-1, // infinite
|
||||||
|
0, // no value
|
||||||
|
sock, // self-inflicted
|
||||||
|
BuffClass::ENVIRONMENT
|
||||||
|
};
|
||||||
|
plr->addBuff(ECSB_INFECTION,
|
||||||
|
[](EntityRef self, Buff* buff, int status, BuffStack* stack) {
|
||||||
|
Buffs::timeBuffUpdate(self, buff, status, stack);
|
||||||
|
},
|
||||||
|
[](EntityRef self, Buff* buff, time_t currTime) {
|
||||||
|
if(self.kind == EntityKind::PLAYER)
|
||||||
|
dealGooDamage(self.sock);
|
||||||
|
},
|
||||||
|
&infection);
|
||||||
|
} else if(!pkt->iFlag && plr->hasBuff(ECSB_INFECTION)) {
|
||||||
|
plr->removeBuff(ECSB_INFECTION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void pcAttackChars(CNSocket *sock, CNPacketData *data) {
|
static void pcAttackChars(CNSocket *sock, CNPacketData *data) {
|
||||||
sP_CL2FE_REQ_PC_ATTACK_CHARs* pkt = (sP_CL2FE_REQ_PC_ATTACK_CHARs*)data->buf;
|
sP_CL2FE_REQ_PC_ATTACK_CHARs* pkt = (sP_CL2FE_REQ_PC_ATTACK_CHARs*)data->buf;
|
||||||
Player *plr = PlayerManager::getPlayer(sock);
|
Player *plr = PlayerManager::getPlayer(sock);
|
||||||
@ -716,11 +729,6 @@ static void playerTick(CNServer *serv, time_t currTime) {
|
|||||||
if (plr->HP <= 0)
|
if (plr->HP <= 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// fm patch/lake damage
|
|
||||||
if ((plr->hasBuff(ECSB_INFECTION))
|
|
||||||
&& !(plr->iSpecialState & CN_SPECIAL_STATE_FLAG__INVULNERABLE))
|
|
||||||
dealGooDamage(sock, PC_MAXHEALTH(plr->level) * 3 / 20);
|
|
||||||
|
|
||||||
// heal
|
// heal
|
||||||
if (currTime - lastHealTime >= 4000 && !plr->inCombat && plr->HP < PC_MAXHEALTH(plr->level)) {
|
if (currTime - lastHealTime >= 4000 && !plr->inCombat && plr->HP < PC_MAXHEALTH(plr->level)) {
|
||||||
if (currTime - lastHealTime - plr->healCooldown >= 4000) {
|
if (currTime - lastHealTime - plr->healCooldown >= 4000) {
|
||||||
@ -747,7 +755,10 @@ static void playerTick(CNServer *serv, time_t currTime) {
|
|||||||
if (skill->drainType == SkillDrainType::PASSIVE) {
|
if (skill->drainType == SkillDrainType::PASSIVE) {
|
||||||
// apply passive buff
|
// apply passive buff
|
||||||
drainRate = skill->batteryUse[boost * 3];
|
drainRate = skill->batteryUse[boost * 3];
|
||||||
Abilities::usePassiveNanoSkill(skill, plr, boost * 3);
|
if(Abilities::usePassiveNanoSkill(skill, plr, boost * 3)) {
|
||||||
|
// first buff, send back skill use packet(s)
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -783,9 +794,8 @@ static void playerTick(CNServer *serv, time_t currTime) {
|
|||||||
// process buffsets
|
// process buffsets
|
||||||
auto it = plr->buffs.begin();
|
auto it = plr->buffs.begin();
|
||||||
while(it != plr->buffs.end()) {
|
while(it != plr->buffs.end()) {
|
||||||
int buffId = (*it).first;
|
|
||||||
Buff* buff = (*it).second;
|
Buff* buff = (*it).second;
|
||||||
buff->tick();
|
buff->tick(currTime);
|
||||||
if(buff->isStale()) {
|
if(buff->isStale()) {
|
||||||
// garbage collect
|
// garbage collect
|
||||||
it = plr->buffs.erase(it);
|
it = plr->buffs.erase(it);
|
||||||
|
@ -3,22 +3,16 @@
|
|||||||
#include "core/Core.hpp"
|
#include "core/Core.hpp"
|
||||||
#include "Chunking.hpp"
|
#include "Chunking.hpp"
|
||||||
|
|
||||||
|
#include "EntityRef.hpp"
|
||||||
|
#include "Buffs.hpp"
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
/* forward declaration(s) */
|
/* forward declaration(s) */
|
||||||
class Buff;
|
class Chunk;
|
||||||
struct BuffStack;
|
struct Group;
|
||||||
|
|
||||||
enum EntityKind {
|
|
||||||
INVALID,
|
|
||||||
PLAYER,
|
|
||||||
SIMPLE_NPC,
|
|
||||||
COMBAT_NPC,
|
|
||||||
MOB,
|
|
||||||
EGG,
|
|
||||||
BUS
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class AIState {
|
enum class AIState {
|
||||||
INACTIVE,
|
INACTIVE,
|
||||||
@ -28,9 +22,6 @@ enum class AIState {
|
|||||||
DEAD
|
DEAD
|
||||||
};
|
};
|
||||||
|
|
||||||
class Chunk;
|
|
||||||
struct Group;
|
|
||||||
|
|
||||||
struct Entity {
|
struct Entity {
|
||||||
EntityKind kind = EntityKind::INVALID;
|
EntityKind kind = EntityKind::INVALID;
|
||||||
int x = 0, y = 0, z = 0;
|
int x = 0, y = 0, z = 0;
|
||||||
@ -48,42 +39,6 @@ struct Entity {
|
|||||||
virtual void disappearFromViewOf(CNSocket *sock) = 0;
|
virtual void disappearFromViewOf(CNSocket *sock) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EntityRef {
|
|
||||||
EntityKind kind;
|
|
||||||
union {
|
|
||||||
CNSocket *sock;
|
|
||||||
int32_t id;
|
|
||||||
};
|
|
||||||
|
|
||||||
EntityRef(CNSocket *s);
|
|
||||||
EntityRef(int32_t i);
|
|
||||||
|
|
||||||
bool isValid() const;
|
|
||||||
Entity *getEntity() const;
|
|
||||||
|
|
||||||
bool operator==(const EntityRef& other) const {
|
|
||||||
if (kind != other.kind)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (kind == EntityKind::PLAYER)
|
|
||||||
return sock == other.sock;
|
|
||||||
|
|
||||||
return id == other.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
// arbitrary ordering
|
|
||||||
bool operator<(const EntityRef& other) const {
|
|
||||||
if (kind == other.kind) {
|
|
||||||
if (kind == EntityKind::PLAYER)
|
|
||||||
return sock < other.sock;
|
|
||||||
else
|
|
||||||
return id < other.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
return kind < other.kind;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Interfaces
|
* Interfaces
|
||||||
*/
|
*/
|
||||||
@ -92,10 +47,10 @@ public:
|
|||||||
ICombatant() {}
|
ICombatant() {}
|
||||||
virtual ~ICombatant() {}
|
virtual ~ICombatant() {}
|
||||||
|
|
||||||
virtual void addBuff(int buffId, BuffStack* stack) = 0;
|
virtual bool addBuff(int, BuffCallback<int, BuffStack*>, BuffCallback<time_t>, BuffStack*) = 0;
|
||||||
virtual Buff* getBuff(int buffId) = 0;
|
virtual Buff* getBuff(int) = 0;
|
||||||
virtual void removeBuff(int buffId) = 0;
|
virtual void removeBuff(int) = 0;
|
||||||
virtual bool hasBuff(int buffId) = 0;
|
virtual bool hasBuff(int) = 0;
|
||||||
virtual int getCompositeCondition() = 0;
|
virtual int getCompositeCondition() = 0;
|
||||||
virtual int takeDamage(EntityRef, int) = 0;
|
virtual int takeDamage(EntityRef, int) = 0;
|
||||||
virtual void heal(EntityRef, int) = 0;
|
virtual void heal(EntityRef, int) = 0;
|
||||||
@ -159,7 +114,7 @@ struct CombatNPC : public BaseNPC, public ICombatant {
|
|||||||
|
|
||||||
virtual bool isExtant() override { return hp > 0; }
|
virtual bool isExtant() override { return hp > 0; }
|
||||||
|
|
||||||
virtual void addBuff(int buffId, BuffStack* stack) override;
|
virtual bool addBuff(int buffId, BuffCallback<int, BuffStack*> onUpdate, BuffCallback<time_t> onTick, BuffStack* stack) override;
|
||||||
virtual Buff* getBuff(int buffId) override;
|
virtual Buff* getBuff(int buffId) override;
|
||||||
virtual void removeBuff(int buffId) override;
|
virtual void removeBuff(int buffId) override;
|
||||||
virtual bool hasBuff(int buffId) override;
|
virtual bool hasBuff(int buffId) override;
|
||||||
|
52
src/EntityRef.hpp
Normal file
52
src/EntityRef.hpp
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/Core.hpp"
|
||||||
|
|
||||||
|
/* forward declaration(s) */
|
||||||
|
struct Entity;
|
||||||
|
|
||||||
|
enum EntityKind {
|
||||||
|
INVALID,
|
||||||
|
PLAYER,
|
||||||
|
SIMPLE_NPC,
|
||||||
|
COMBAT_NPC,
|
||||||
|
MOB,
|
||||||
|
EGG,
|
||||||
|
BUS
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EntityRef {
|
||||||
|
EntityKind kind;
|
||||||
|
union {
|
||||||
|
CNSocket *sock;
|
||||||
|
int32_t id;
|
||||||
|
};
|
||||||
|
|
||||||
|
EntityRef(CNSocket *s);
|
||||||
|
EntityRef(int32_t i);
|
||||||
|
|
||||||
|
bool isValid() const;
|
||||||
|
Entity *getEntity() const;
|
||||||
|
|
||||||
|
bool operator==(const EntityRef& other) const {
|
||||||
|
if (kind != other.kind)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (kind == EntityKind::PLAYER)
|
||||||
|
return sock == other.sock;
|
||||||
|
|
||||||
|
return id == other.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// arbitrary ordering
|
||||||
|
bool operator<(const EntityRef& other) const {
|
||||||
|
if (kind == other.kind) {
|
||||||
|
if (kind == EntityKind::PLAYER)
|
||||||
|
return sock < other.sock;
|
||||||
|
else
|
||||||
|
return id < other.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return kind < other.kind;
|
||||||
|
}
|
||||||
|
};
|
@ -494,18 +494,18 @@ static void itemUseHandler(CNSocket* sock, CNPacketData* data) {
|
|||||||
int durationMilliseconds = Abilities::SkillTable[144].durationTime[0] * 100;
|
int durationMilliseconds = Abilities::SkillTable[144].durationTime[0] * 100;
|
||||||
BuffStack gumballBuff = {
|
BuffStack gumballBuff = {
|
||||||
durationMilliseconds / MS_PER_PLAYER_TICK,
|
durationMilliseconds / MS_PER_PLAYER_TICK,
|
||||||
NULL,
|
0,
|
||||||
sock,
|
sock,
|
||||||
BuffClass::CASH_ITEM, // or BuffClass::ITEM?
|
BuffClass::CASH_ITEM // or BuffClass::ITEM?
|
||||||
[](EntityRef host, BuffStack* stack) {
|
|
||||||
Buffs::timeBuffUpdate(host, stack, ETBU_ADD);
|
|
||||||
},
|
|
||||||
nullptr,
|
|
||||||
[](EntityRef host, BuffStack* stack) {
|
|
||||||
Buffs::timeBuffUpdate(host, stack, ETBU_DEL);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
player->addBuff(eCSB, &gumballBuff);
|
player->addBuff(eCSB,
|
||||||
|
[](EntityRef self, Buff* buff, int status, BuffStack* stack) {
|
||||||
|
Buffs::timeBuffUpdate(self, buff, status, stack);
|
||||||
|
},
|
||||||
|
[](EntityRef self, Buff* buff, time_t currTime) {
|
||||||
|
// TODO passive tick
|
||||||
|
},
|
||||||
|
&gumballBuff);
|
||||||
|
|
||||||
sock->sendPacket((void*)&respbuf, P_FE2CL_REP_PC_ITEM_USE_SUCC, resplen);
|
sock->sendPacket((void*)&respbuf, P_FE2CL_REP_PC_ITEM_USE_SUCC, resplen);
|
||||||
// update inventory serverside
|
// update inventory serverside
|
||||||
|
@ -208,10 +208,6 @@ static void nanoEquipHandler(CNSocket* sock, CNPacketData* data) {
|
|||||||
// Update player
|
// Update player
|
||||||
plr->equippedNanos[nano->iNanoSlotNum] = nano->iNanoID;
|
plr->equippedNanos[nano->iNanoSlotNum] = nano->iNanoID;
|
||||||
|
|
||||||
// Unbuff gumballs
|
|
||||||
int buffId = ECSB_STIMPAKSLOT1 + nano->iNanoSlotNum;
|
|
||||||
plr->removeBuff(buffId);
|
|
||||||
|
|
||||||
// unsummon nano if replaced
|
// unsummon nano if replaced
|
||||||
if (plr->activeNano == plr->equippedNanos[nano->iNanoSlotNum])
|
if (plr->activeNano == plr->equippedNanos[nano->iNanoSlotNum])
|
||||||
summonNano(sock, -1);
|
summonNano(sock, -1);
|
||||||
|
@ -87,7 +87,7 @@ struct Player : public Entity, public ICombatant {
|
|||||||
virtual void enterIntoViewOf(CNSocket *sock) override;
|
virtual void enterIntoViewOf(CNSocket *sock) override;
|
||||||
virtual void disappearFromViewOf(CNSocket *sock) override;
|
virtual void disappearFromViewOf(CNSocket *sock) override;
|
||||||
|
|
||||||
virtual void addBuff(int buffId, BuffStack* stack) override;
|
virtual bool addBuff(int buffId, BuffCallback<int, BuffStack*> onUpdate, BuffCallback<time_t> onTick, BuffStack* stack) override;
|
||||||
virtual Buff* getBuff(int buffId) override;
|
virtual Buff* getBuff(int buffId) override;
|
||||||
virtual void removeBuff(int buffId) override;
|
virtual void removeBuff(int buffId) override;
|
||||||
virtual bool hasBuff(int buffId) override;
|
virtual bool hasBuff(int buffId) override;
|
||||||
|
Loading…
Reference in New Issue
Block a user