mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-11-22 13:30:06 +00:00
Passive nano powers
This commit is contained in:
parent
d4253c3b49
commit
e0a0cc186e
@ -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);
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
@ -755,10 +769,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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,6 +97,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;
|
||||||
|
Loading…
Reference in New Issue
Block a user