Passive nano powers

This commit is contained in:
gsemaj 2022-07-23 18:37:42 -07:00
parent ab4b763f00
commit 723e455b1d
6 changed files with 139 additions and 24 deletions

View File

@ -3,6 +3,7 @@
#include "NPCManager.hpp" #include "NPCManager.hpp"
#include "PlayerManager.hpp" #include "PlayerManager.hpp"
#include "Buffs.hpp" #include "Buffs.hpp"
#include "Nanos.hpp"
#include <assert.h> #include <assert.h>
@ -10,14 +11,92 @@ using namespace Abilities;
std::map<int32_t, SkillData> Abilities::SkillTable; std::map<int32_t, SkillData> Abilities::SkillTable;
/* #pragma region Skill handlers
// New email notification static SkillResult handleSkillBuff(SkillData* skill, ICombatant* target) {
static void emailUpdateCheck(CNSocket* sock, CNPacketData* data) { // the buff skill is special in that its application is not aligned
INITSTRUCT(sP_FE2CL_REP_PC_NEW_EMAIL, resp); // with the SKILL_USE_SUCC packet, since buffs are calculated every tick.
resp.iNewEmailCnt = Database::getUnreadEmailCount(PlayerManager::getPlayer(sock)->iID); // thus, no game state changes should happen here.
sock->sendPacket(resp, P_FE2CL_REP_PC_NEW_EMAIL); sSkillResult_Buff result{};
result.iConditionBitFlag = target->getCompositeCondition();
result.iID = target->getID();
result.bProtected = 0;
result.eCT = target->getCharType();
return SkillResult(sizeof(sSkillResult_Buff), &result);
}
#pragma endregion
void Abilities::broadcastNanoSkill(CNSocket* sock, sNano& nano, std::vector<ICombatant*> affected) {
if(SkillTable.count(nano.iSkillID) == 0)
return;
SkillData* skill = &SkillTable[nano.iSkillID];
Player* plr = PlayerManager::getPlayer(sock);
int count = affected.size();
size_t resultSize = 0;
SkillResult (*skillHandler)(SkillData*, ICombatant*) = nullptr;
switch(skill->skillType)
{
case EST_JUMP:
case EST_RUN:
case EST_FREEDOM:
case EST_PHOENIX:
case EST_INVULNERABLE:
case EST_MINIMAPENEMY:
case EST_MINIMAPTRESURE:
case EST_NANOSTIMPAK:
case EST_PROTECTBATTERY:
case EST_PROTECTINFECTION:
case EST_REWARDBLOB:
case EST_REWARDCASH:
case EST_STAMINA_SELF:
case EST_STEALTH:
resultSize = sizeof(sSkillResult_Buff);
skillHandler = handleSkillBuff;
break;
default:
std::cout << "[WARN] Unhandled skill type " << skill->skillType << std::endl;
return;
}
std::vector<SkillResult> results;
for(ICombatant* target : affected) {
SkillResult result = handleSkillBuff(skill, target);
if(result.size != resultSize) {
std::cout << "[WARN] bad skill result size for " << skill->skillType << " from " << handleSkillBuff << std::endl;
return;
}
results.push_back(result);
}
if (!validOutVarPacket(sizeof(sP_FE2CL_NANO_SKILL_USE_SUCC), count, resultSize)) {
std::cout << "[WARN] bad sP_FE2CL_NANO_SKILL_USE_SUCC packet size\n";
return;
}
// initialize response struct
size_t resplen = sizeof(sP_FE2CL_NANO_SKILL_USE_SUCC) + count * resultSize;
uint8_t respbuf[CN_PACKET_BUFFER_SIZE];
memset(respbuf, 0, resplen);
sP_FE2CL_NANO_SKILL_USE_SUCC* pkt = (sP_FE2CL_NANO_SKILL_USE_SUCC*)respbuf;
pkt->iPC_ID = plr->iID;
pkt->iNanoID = nano.iID;
pkt->iSkillID = nano.iSkillID;
pkt->iNanoStamina = nano.iStamina;
pkt->bNanoDeactive = nano.iStamina <= 0;
pkt->eST = skill->skillType;
pkt->iTargetCnt = count;
char* appended = (char*)(pkt + 1);
for(SkillResult& result : results) {
memcpy(appended, result.payload, resultSize);
appended += resultSize;
}
sock->sendPacket(pkt, P_FE2CL_NANO_SKILL_USE_SUCC, resplen);
PlayerManager::sendToViewable(sock, pkt, P_FE2CL_NANO_SKILL_USE_SUCC, resplen);
} }
*/
std::vector<EntityRef> Abilities::matchTargets(SkillData* skill, int count, int32_t *ids) { std::vector<EntityRef> Abilities::matchTargets(SkillData* skill, int count, int32_t *ids) {
@ -103,13 +182,11 @@ int Abilities::getCSTBFromST(int eSkillType) {
return result; return result;
} }
#pragma region Skill Handlers std::vector<ICombatant*> Abilities::usePassiveNanoSkill(SkillData* skill, Player* plr) {
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<ICombatant*> affected;
std::vector<EntityRef> targets; std::vector<EntityRef> targets;
if (skill->targetType == SkillTargetType::GROUP) { if (skill->targetType == SkillTargetType::GROUP) {
targets = plr->getGroupMembers(); // group targets = plr->getGroupMembers(); // group
@ -121,6 +198,7 @@ bool Abilities::usePassiveNanoSkill(SkillData* skill, Player* plr, int boost) {
} }
int timeBuffId = getCSTBFromST(skill->skillType); int timeBuffId = getCSTBFromST(skill->skillType);
int boost = Nanos::getNanoBoost(plr) ? 3 : 0;
int value = skill->values[0][boost]; int value = skill->values[0][boost];
BuffStack passiveBuff = { BuffStack passiveBuff = {
@ -137,19 +215,18 @@ bool 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);
newBuffApplied |= combatant->addBuff(timeBuffId, if(combatant->addBuff(timeBuffId,
[](EntityRef self, Buff* buff, int status, BuffStack* stack) { [](EntityRef self, Buff* buff, int status, BuffStack* stack) {
Buffs::timeBuffUpdate(self, buff, status, stack); Buffs::timeBuffUpdate(self, buff, status, stack);
}, },
[](EntityRef self, Buff* buff, time_t currTime) { [](EntityRef self, Buff* buff, time_t currTime) {
// TODO time buff tick // TODO time buff tick
}, },
&passiveBuff); &passiveBuff)) affected.push_back(combatant);
} }
return newBuffApplied; return affected;
} }
#pragma endregion
void Abilities::init() { void Abilities::init() {
//REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_EMAIL_UPDATE_CHECK, emailUpdateCheck); //REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_EMAIL_UPDATE_CHECK, emailUpdateCheck);

View File

@ -1,11 +1,15 @@
#pragma once #pragma once
#include "core/Core.hpp"
#include "Entities.hpp" #include "Entities.hpp"
#include "Player.hpp" #include "Player.hpp"
#include <map> #include <map>
#include <vector> #include <vector>
constexpr size_t MAX_SKILLRESULT_SIZE = sizeof(sSkillResult_BatteryDrain);
enum class SkillEffectTarget { enum class SkillEffectTarget {
POINT = 1, POINT = 1,
SELF = 2, SELF = 2,
@ -26,6 +30,15 @@ enum class SkillDrainType {
PASSIVE = 2 PASSIVE = 2
}; };
struct SkillResult {
size_t size;
char payload[MAX_SKILLRESULT_SIZE];
SkillResult(size_t len, void* dat) {
size = len;
memcpy(payload, dat, len);
}
};
struct SkillData { struct SkillData {
int skillType; // eST int skillType; // eST
SkillEffectTarget effectTarget; SkillEffectTarget effectTarget;
@ -44,10 +57,11 @@ struct SkillData {
namespace Abilities { namespace Abilities {
extern std::map<int32_t, SkillData> SkillTable; extern std::map<int32_t, SkillData> SkillTable;
void broadcastNanoSkill(CNSocket*, sNano&, std::vector<ICombatant*>);
std::vector<EntityRef> matchTargets(SkillData*, int, int32_t*); std::vector<EntityRef> matchTargets(SkillData*, int, int32_t*);
int getCSTBFromST(int eSkillType); int getCSTBFromST(int eSkillType);
bool usePassiveNanoSkill(SkillData*, Player*, int); std::vector<ICombatant*> usePassiveNanoSkill(SkillData*, Player*);
void init(); void init();
} }

View File

@ -19,6 +19,7 @@ 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;
#pragma region Player
bool Player::addBuff(int buffId, BuffCallback<int, BuffStack*> onUpdate, BuffCallback<time_t> onTick, 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);
@ -87,6 +88,10 @@ std::vector<EntityRef> Player::getGroupMembers() {
return members; return members;
} }
int32_t Player::getCharType() {
return 1; // eCharType (eCT_PC)
}
int32_t Player::getID() { int32_t Player::getID() {
return iID; return iID;
} }
@ -94,7 +99,9 @@ int32_t Player::getID() {
void Player::step(time_t currTime) { void Player::step(time_t currTime) {
// no-op // no-op
} }
#pragma endregion
#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) { /* stubbed */
return false; return false;
} }
@ -143,6 +150,12 @@ std::vector<EntityRef> CombatNPC::getGroupMembers() {
return members; return members;
} }
int32_t CombatNPC::getCharType() {
if(kind == EntityKind::MOB)
return 4; // eCharType (eCT_MOB)
return 2; // eCharType (eCT_NPC)
}
int32_t CombatNPC::getID() { int32_t CombatNPC::getID() {
return id; return id;
} }
@ -172,6 +185,7 @@ void CombatNPC::transition(AIState newState, EntityRef src) {
event.handler(src, this); event.handler(src, this);
*/ */
} }
#pragma endregion
static std::pair<int,int> getDamage(int attackPower, int defensePower, bool shouldCrit, static std::pair<int,int> getDamage(int attackPower, int defensePower, bool shouldCrit,
bool batteryBoost, int attackerStyle, bool batteryBoost, int attackerStyle,
@ -784,10 +798,7 @@ 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];
if(Abilities::usePassiveNanoSkill(skill, plr, boost * 3)) { Abilities::usePassiveNanoSkill(skill, plr);
// first buff, send back skill use packet(s)
// TODO
}
} }
} }

View File

@ -57,6 +57,7 @@ public:
virtual bool isAlive() = 0; virtual bool isAlive() = 0;
virtual int getCurrentHP() = 0; virtual int getCurrentHP() = 0;
virtual std::vector<EntityRef> getGroupMembers() = 0; virtual std::vector<EntityRef> getGroupMembers() = 0;
virtual int32_t getCharType() = 0;
virtual int32_t getID() = 0; virtual int32_t getID() = 0;
virtual void step(time_t currTime) = 0; virtual void step(time_t currTime) = 0;
}; };
@ -74,6 +75,7 @@ public:
bool loopingPath = false; bool loopingPath = false;
BaseNPC(int _A, uint64_t iID, int t, int _id) { BaseNPC(int _A, uint64_t iID, int t, int _id) {
kind = EntityKind::SIMPLE_NPC;
type = t; type = t;
hp = 400; hp = 400;
angle = _A; angle = _A;
@ -108,6 +110,8 @@ struct CombatNPC : public BaseNPC, public ICombatant {
spawnY = y; spawnY = y;
spawnZ = z; spawnZ = z;
kind = EntityKind::COMBAT_NPC;
stateHandlers[AIState::INACTIVE] = {}; stateHandlers[AIState::INACTIVE] = {};
transitionHandlers[AIState::INACTIVE] = {}; transitionHandlers[AIState::INACTIVE] = {};
} }
@ -124,6 +128,7 @@ struct CombatNPC : public BaseNPC, public ICombatant {
virtual bool isAlive() override; virtual bool isAlive() override;
virtual int getCurrentHP() override; virtual int getCurrentHP() override;
virtual std::vector<EntityRef> getGroupMembers() override; virtual std::vector<EntityRef> getGroupMembers() override;
virtual int32_t getCharType() 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;

View File

@ -86,10 +86,17 @@ void Nanos::summonNano(CNSocket *sock, int slot, bool silent) {
return; // sanity check return; // sanity check
plr->activeNano = nanoID; plr->activeNano = nanoID;
sNano& nano = plr->Nanos[nanoID];
int16_t skillID = plr->Nanos[nanoID].iSkillID; SkillData* skill = Abilities::SkillTable.count(nano.iSkillID) > 0
if (Abilities::SkillTable.count(skillID) > 0 && Abilities::SkillTable[skillID].drainType == SkillDrainType::PASSIVE) ? &Abilities::SkillTable[nano.iSkillID] : nullptr;
resp.eCSTB___Add = 1; // passive buff effect if (slot != -1 && skill != nullptr && skill->drainType == SkillDrainType::PASSIVE) {
// passive buff effect
resp.eCSTB___Add = 1;
int boost = Nanos::getNanoBoost(plr);
std::vector<ICombatant*> affectedCombatants = Abilities::usePassiveNanoSkill(skill, plr);
if(!affectedCombatants.empty()) Abilities::broadcastNanoSkill(sock, nano, affectedCombatants);
}
if (!silent) // silent nano death but only for the summoning player if (!silent) // silent nano death but only for the summoning player
sock->sendPacket(resp, P_FE2CL_REP_NANO_ACTIVE_SUCC); sock->sendPacket(resp, P_FE2CL_REP_NANO_ACTIVE_SUCC);
@ -97,7 +104,7 @@ void Nanos::summonNano(CNSocket *sock, int slot, bool silent) {
// Send to other players, these players can't handle silent nano deaths so this packet needs to be sent. // Send to other players, these players can't handle silent nano deaths so this packet needs to be sent.
INITSTRUCT(sP_FE2CL_NANO_ACTIVE, pkt1); INITSTRUCT(sP_FE2CL_NANO_ACTIVE, pkt1);
pkt1.iPC_ID = plr->iID; pkt1.iPC_ID = plr->iID;
pkt1.Nano = plr->Nanos[nanoID]; pkt1.Nano = nano;
PlayerManager::sendToViewable(sock, pkt1, P_FE2CL_NANO_ACTIVE); PlayerManager::sendToViewable(sock, pkt1, P_FE2CL_NANO_ACTIVE);
} }

View File

@ -99,6 +99,7 @@ struct Player : public Entity, public ICombatant {
virtual bool isAlive() override; virtual bool isAlive() override;
virtual int getCurrentHP() override; virtual int getCurrentHP() override;
virtual std::vector<EntityRef> getGroupMembers() override; virtual std::vector<EntityRef> getGroupMembers() override;
virtual int32_t getCharType() 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;