OpenFusion/src/Buffs.cpp

136 lines
4.3 KiB
C++
Raw Normal View History

2022-07-18 03:49:10 +00:00
#include "Buffs.hpp"
#include "PlayerManager.hpp"
2022-07-30 20:47:27 +00:00
#include "NPCManager.hpp"
2022-07-18 03:49:10 +00:00
using namespace Buffs;
void Buff::tick(time_t currTime) {
2022-07-18 03:49:10 +00:00
auto it = stacks.begin();
while(it != stacks.end()) {
BuffStack& stack = *it;
if(onTick) onTick(self, this, currTime);
2022-07-18 03:49:10 +00:00
if(stack.durationTicks == 0) {
BuffStack deadStack = stack;
2022-07-18 03:49:10 +00:00
it = stacks.erase(it);
if(onUpdate) onUpdate(self, this, ETBU_DEL, &deadStack);
2022-07-20 16:15:01 +00:00
} else {
if(stack.durationTicks > 0) stack.durationTicks--;
it++;
}
2022-07-18 03:49:10 +00:00
}
}
void Buff::clear() {
2022-07-18 03:49:10 +00:00
while(!stacks.empty()) {
BuffStack stack = stacks.back();
stacks.pop_back();
if(onUpdate) onUpdate(self, this, ETBU_DEL, &stack);
2022-07-18 03:49:10 +00:00
}
}
void Buff::addStack(BuffStack* stack) {
stacks.push_back(*stack);
if(onUpdate) onUpdate(self, this, ETBU_ADD, &stacks.back());
2022-07-18 03:49:10 +00:00
}
bool Buff::hasClass(BuffClass buffClass) {
for(BuffStack& stack : stacks) {
2022-07-19 08:09:25 +00:00
if(stack.buffStackClass == buffClass)
return true;
}
return false;
}
2022-07-18 03:49:10 +00:00
BuffClass Buff::maxClass() {
BuffClass buffClass = BuffClass::NONE;
2022-07-18 03:49:10 +00:00
for(BuffStack& stack : stacks) {
2022-07-19 08:09:25 +00:00
if(stack.buffStackClass > buffClass)
buffClass = stack.buffStackClass;
2022-07-18 03:49:10 +00:00
}
return buffClass;
2022-07-18 03:49:10 +00:00
}
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;
}
2022-07-18 03:49:10 +00:00
bool Buff::isStale() {
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
void Buffs::timeBuffUpdate(EntityRef self, Buff* buff, int status, BuffStack* stack) {
2022-07-18 03:49:10 +00:00
if(self.kind != EntityKind::PLAYER)
return; // not implemented
Player* plr = (Player*)self.getEntity();
if(plr == nullptr)
return; // sanity check
if(status == ETBU_DEL && !buff->isStale())
return; // no premature effect deletion
2022-07-21 16:22:19 +00:00
int cbf = plr->getCompositeCondition();
sTimeBuff payload{};
2022-07-21 16:22:19 +00:00
if(status == ETBU_ADD) {
payload.iValue = buff->getValue(BuffValueSelector::MAX_MAGNITUDE);
// we need to explicitly add the ECSB for this buff,
// 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);
2022-07-21 16:22:19 +00:00
}
2022-07-18 03:49:10 +00:00
INITSTRUCT(sP_FE2CL_PC_BUFF_UPDATE, pkt);
pkt.eCSTB = buff->id; // eCharStatusTimeBuffID
pkt.eTBU = status; // eTimeBuffUpdate
2022-07-19 08:09:25 +00:00
pkt.eTBT = (int)stack->buffStackClass;
pkt.iConditionBitFlag = cbf;
2022-07-21 16:22:19 +00:00
pkt.TimeBuff = payload;
2022-07-18 03:49:10 +00:00
self.sock->sendPacket((void*)&pkt, P_FE2CL_PC_BUFF_UPDATE, sizeof(sP_FE2CL_PC_BUFF_UPDATE));
}
2022-07-30 20:47:27 +00:00
void Buffs::timeBuffTimeout(EntityRef self) {
if(self.kind != EntityKind::PLAYER && self.kind != EntityKind::COMBAT_NPC && self.kind != EntityKind::MOB)
return; // not a combatant
Entity* entity = self.getEntity();
ICombatant* combatant = dynamic_cast<ICombatant*>(entity);
2022-07-18 03:49:10 +00:00
INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, pkt); // send a buff timeout to other players
2022-07-30 20:47:27 +00:00
pkt.eCT = combatant->getCharType();
pkt.iID = combatant->getID();
pkt.iConditionBitFlag = combatant->getCompositeCondition();
NPCManager::sendToViewable(entity, &pkt, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT, sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT));
2022-07-18 03:49:10 +00:00
}
#pragma endregion