Move drain to new system

TODO
- There is a seg fault that happens when drain kills the mob
- leech unimplemented
- mob skills unimplemented
This commit is contained in:
gsemaj 2023-07-25 20:22:00 +00:00
parent 1cf2be9968
commit c1aff8d3c3
4 changed files with 51 additions and 14 deletions

View File

@ -93,19 +93,28 @@ static SkillResult handleSkillBuff(SkillData* skill, int power, ICombatant* sour
int duration = skill->durationTime[power];
int strength = skill->values[0][power];
BuffStack passiveBuff = {
skill->drainType == SkillDrainType::PASSIVE ? 1 : duration, // ticks
skill->drainType == SkillDrainType::PASSIVE ? 1 : (duration * 100) / MS_PER_COMBAT_TICK, // ticks
strength, // value
source->getRef(), // source
source == target ? BuffClass::NANO : BuffClass::GROUP_NANO, // buff class
};
int timeBuffId = Abilities::getCSTBFromST(skill->skillType);
SkillDrainType drainType = skill->drainType;
if(!target->addBuff(timeBuffId,
[](EntityRef self, Buff* buff, int status, BuffStack* stack) {
[drainType](EntityRef self, Buff* buff, int status, BuffStack* stack) {
if(buff->id == ECSB_BOUNDINGBALL) {
// drain
ICombatant* combatant = dynamic_cast<ICombatant*>(self.getEntity());
combatant->takeDamage(buff->getLastSource(), 0); // aggro
}
Buffs::timeBuffUpdate(self, buff, status, stack);
if(drainType == SkillDrainType::ACTIVE && status == ETBU_DEL)
Buffs::timeBuffTimeout(self);
},
[](EntityRef self, Buff* buff, time_t currTime) {
// no-op
if(buff->id == ECSB_BOUNDINGBALL)
Buffs::tickDrain(self, buff); // drain
},
&passiveBuff)) return SkillResult(); // no result if already buffed

View File

@ -95,6 +95,12 @@ int Buff::getValue(BuffValueSelector selector) {
return value;
}
EntityRef Buff::getLastSource() {
if(stacks.empty())
return self;
return stacks.back().source;
}
bool Buff::isStale() {
return stacks.empty();
}
@ -142,6 +148,7 @@ void Buffs::timeBuffTick(EntityRef self, Buff* buff) {
return; // not implemented
Entity* entity = self.getEntity();
ICombatant* combatant = dynamic_cast<ICombatant*>(entity);
INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK, pkt);
pkt.eCT = combatant->getCharType();
pkt.iID = combatant->getID();
@ -161,4 +168,30 @@ void Buffs::timeBuffTimeout(EntityRef self) {
pkt.iConditionBitFlag = combatant->getCompositeCondition();
NPCManager::sendToViewable(entity, &pkt, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT, sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT));
}
void Buffs::tickDrain(EntityRef self, Buff* buff) {
if(self.kind != EntityKind::COMBAT_NPC && self.kind != EntityKind::MOB)
return; // not implemented
Entity* entity = self.getEntity();
ICombatant* combatant = dynamic_cast<ICombatant*>(entity);
int damage = combatant->takeDamage(buff->getLastSource(), combatant->getMaxHP() / 100);
size_t resplen = sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK) + sizeof(sSkillResult_Damage);
assert(resplen < CN_PACKET_BUFFER_SIZE - 8);
uint8_t respbuf[CN_PACKET_BUFFER_SIZE];
memset(respbuf, 0, resplen);
sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK *pkt = (sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK*)respbuf;
pkt->iID = self.id;
pkt->eCT = combatant->getCharType();
pkt->iTB_ID = ECSB_BOUNDINGBALL;
sSkillResult_Damage *drain = (sSkillResult_Damage*)(respbuf + sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK));
drain->iDamage = damage;
drain->iHP = combatant->getCurrentHP();
drain->eCT = pkt->eCT;
drain->iID = pkt->iID;
NPCManager::sendToViewable(self.getEntity(), (void*)&respbuf, P_FE2CL_CHAR_TIME_BUFF_TIME_TICK, resplen);
}
#pragma endregion

View File

@ -66,6 +66,7 @@ public:
BuffClass maxClass();
int getValue(BuffValueSelector selector);
EntityRef getLastSource();
/*
* In general, a Buff object won't exist
@ -88,4 +89,5 @@ namespace Buffs {
void timeBuffUpdate(EntityRef self, Buff* buff, int status, BuffStack* stack);
void timeBuffTick(EntityRef self, Buff* buff);
void timeBuffTimeout(EntityRef self);
void tickDrain(EntityRef self, Buff* buff);
}

View File

@ -553,17 +553,6 @@ void MobAI::combatStep(CombatNPC* npc, time_t currTime) {
return;
}
// drain TODO abilities
if (self->skillStyle < 0 && (self->lastDrainTime == 0 || currTime - self->lastDrainTime >= 1000)
&& self->hasBuff(ECSB_BOUNDINGBALL)) {
drainMobHP(self, self->maxHealth / 20); // lose 5% every second
self->lastDrainTime = currTime;
}
// if drain killed the mob, return early
if (self->hp <= 0)
return;
// tick buffs
auto it = npc->buffs.begin();
while(it != npc->buffs.end()) {
@ -578,6 +567,10 @@ void MobAI::combatStep(CombatNPC* npc, time_t currTime) {
else it++;
}
// if debuffs killed the mob, return early
if (self->hp <= 0)
return;
// skip attack if stunned or asleep
if (self->hasBuff(ECSB_STUN) || self->hasBuff(ECSB_MEZ)) {
self->skillStyle = -1; // in this case we also reset the any outlying abilities the mob might be winding up.