mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-11-17 03:20:06 +00:00
Port egg buffs over to new system
This commit is contained in:
parent
e768ebcabe
commit
1670dfd830
@ -40,7 +40,7 @@ static SkillResult handleSkillHealHP(SkillData* skill, int power, ICombatant* so
|
|||||||
sSkillResult_Heal_HP result{};
|
sSkillResult_Heal_HP result{};
|
||||||
result.eCT = target->getCharType();
|
result.eCT = target->getCharType();
|
||||||
result.iID = target->getID();
|
result.iID = target->getID();
|
||||||
result.iHealHP = heal;
|
result.iHealHP = healed;
|
||||||
result.iHP = target->getCurrentHP();
|
result.iHP = target->getCurrentHP();
|
||||||
return SkillResult(sizeof(sSkillResult_Heal_HP), &result);
|
return SkillResult(sizeof(sSkillResult_Heal_HP), &result);
|
||||||
}
|
}
|
||||||
@ -170,7 +170,8 @@ static std::vector<SkillResult> handleSkill(SkillData* skill, int power, ICombat
|
|||||||
assert(skillHandler != nullptr);
|
assert(skillHandler != nullptr);
|
||||||
|
|
||||||
for(ICombatant* target : targets) {
|
for(ICombatant* target : targets) {
|
||||||
SkillResult result = skillHandler(skill, power, src, target);
|
assert(target != nullptr);
|
||||||
|
SkillResult result = skillHandler(skill, power, src != nullptr ? src : target, target);
|
||||||
if(result.size == 0) continue; // skill not applicable
|
if(result.size == 0) continue; // skill not applicable
|
||||||
if(result.size != resultSize) {
|
if(result.size != resultSize) {
|
||||||
std::cout << "[WARN] bad skill result size for " << skill->skillType << " from " << (void*)handleSkillBuff << std::endl;
|
std::cout << "[WARN] bad skill result size for " << skill->skillType << " from " << (void*)handleSkillBuff << std::endl;
|
||||||
@ -181,7 +182,14 @@ static std::vector<SkillResult> handleSkill(SkillData* skill, int power, ICombat
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Abilities::broadcastNanoSkill(CNSocket* sock, sNano& nano, std::vector<ICombatant*> affected) {
|
static void attachSkillResults(std::vector<SkillResult> results, size_t resultSize, uint8_t* pivot) {
|
||||||
|
for(SkillResult& result : results) {
|
||||||
|
memcpy(pivot, result.payload, resultSize);
|
||||||
|
pivot += resultSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Abilities::useNanoSkill(CNSocket* sock, sNano& nano, std::vector<ICombatant*> affected) {
|
||||||
if(SkillTable.count(nano.iSkillID) == 0)
|
if(SkillTable.count(nano.iSkillID) == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -210,16 +218,45 @@ void Abilities::broadcastNanoSkill(CNSocket* sock, sNano& nano, std::vector<ICom
|
|||||||
pkt->eST = skill->skillType;
|
pkt->eST = skill->skillType;
|
||||||
pkt->iTargetCnt = (int32_t)results.size();
|
pkt->iTargetCnt = (int32_t)results.size();
|
||||||
|
|
||||||
uint8_t* appended = (uint8_t*)(pkt + 1);
|
attachSkillResults(results, resultSize, (uint8_t*)(pkt + 1));
|
||||||
for(SkillResult& result : results) {
|
|
||||||
memcpy(appended, result.payload, resultSize);
|
|
||||||
appended += resultSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
sock->sendPacket(pkt, P_FE2CL_NANO_SKILL_USE_SUCC, resplen);
|
sock->sendPacket(pkt, P_FE2CL_NANO_SKILL_USE_SUCC, resplen);
|
||||||
PlayerManager::sendToViewable(sock, pkt, P_FE2CL_NANO_SKILL_USE_SUCC, resplen);
|
PlayerManager::sendToViewable(sock, pkt, P_FE2CL_NANO_SKILL_USE_SUCC, resplen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Abilities::useNPCSkill(EntityRef npc, int skillID, std::vector<ICombatant*> affected) {
|
||||||
|
if(SkillTable.count(skillID) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Entity* entity = npc.getEntity();
|
||||||
|
ICombatant* src = nullptr;
|
||||||
|
if(npc.kind == EntityKind::COMBAT_NPC || npc.kind == EntityKind::MOB)
|
||||||
|
src = dynamic_cast<ICombatant*>(entity);
|
||||||
|
|
||||||
|
SkillData* skill = &SkillTable[skillID];
|
||||||
|
|
||||||
|
std::vector<SkillResult> results = handleSkill(skill, 0, src, affected);
|
||||||
|
size_t resultSize = results.back().size; // guaranteed to be the same for every item
|
||||||
|
|
||||||
|
if (!validOutVarPacket(sizeof(sP_FE2CL_NPC_SKILL_HIT), results.size(), resultSize)) {
|
||||||
|
std::cout << "[WARN] bad sP_FE2CL_NPC_SKILL_HIT packet size\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize response struct
|
||||||
|
size_t resplen = sizeof(sP_FE2CL_NPC_SKILL_HIT) + results.size() * resultSize;
|
||||||
|
uint8_t respbuf[CN_PACKET_BUFFER_SIZE];
|
||||||
|
memset(respbuf, 0, resplen);
|
||||||
|
|
||||||
|
sP_FE2CL_NPC_SKILL_HIT* pkt = (sP_FE2CL_NPC_SKILL_HIT*)respbuf;
|
||||||
|
pkt->iNPC_ID = npc.id;
|
||||||
|
pkt->iSkillID = skillID;
|
||||||
|
pkt->eST = skill->skillType;
|
||||||
|
pkt->iTargetCnt = (int32_t)results.size();
|
||||||
|
|
||||||
|
attachSkillResults(results, resultSize, (uint8_t*)(pkt + 1));
|
||||||
|
NPCManager::sendToViewable(entity, pkt, P_FE2CL_NPC_SKILL_HIT, 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) {
|
||||||
|
|
||||||
std::vector<EntityRef> targets;
|
std::vector<EntityRef> targets;
|
||||||
@ -303,53 +340,3 @@ int Abilities::getCSTBFromST(int eSkillType) {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ICombatant*> Abilities::usePassiveNanoSkill(SkillData* skill, Player* plr) {
|
|
||||||
assert(skill->drainType == SkillDrainType::PASSIVE);
|
|
||||||
|
|
||||||
EntityRef self = PlayerManager::getSockFromID(plr->iID);
|
|
||||||
std::vector<ICombatant*> affected;
|
|
||||||
std::vector<EntityRef> targets;
|
|
||||||
if (skill->targetType == SkillTargetType::GROUP) {
|
|
||||||
targets = plr->getGroupMembers(); // group
|
|
||||||
}
|
|
||||||
else if(skill->targetType == SkillTargetType::SELF) {
|
|
||||||
targets.push_back(self); // self
|
|
||||||
} else {
|
|
||||||
std::cout << "[WARN] Passive skill with type " << skill->skillType << " has target type MOB" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
int timeBuffId = getCSTBFromST(skill->skillType);
|
|
||||||
int boost = Nanos::getNanoBoost(plr) ? 3 : 0;
|
|
||||||
int value = skill->values[0][boost];
|
|
||||||
|
|
||||||
BuffStack passiveBuff = {
|
|
||||||
1, // passive nano buffs refreshed every tick
|
|
||||||
value,
|
|
||||||
self,
|
|
||||||
BuffClass::NONE, // overwritten per target
|
|
||||||
};
|
|
||||||
|
|
||||||
for (EntityRef target : targets) {
|
|
||||||
Entity* entity = target.getEntity();
|
|
||||||
if (entity->kind != PLAYER && entity->kind != COMBAT_NPC && entity->kind != MOB)
|
|
||||||
continue; // not a combatant
|
|
||||||
|
|
||||||
passiveBuff.buffStackClass = target == self ? BuffClass::NANO : BuffClass::GROUP_NANO;
|
|
||||||
ICombatant* combatant = dynamic_cast<ICombatant*>(entity);
|
|
||||||
if(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)) affected.push_back(combatant);
|
|
||||||
}
|
|
||||||
|
|
||||||
return affected;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Abilities::init() {
|
|
||||||
//REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_EMAIL_UPDATE_CHECK, emailUpdateCheck);
|
|
||||||
}
|
|
||||||
|
@ -60,11 +60,9 @@ 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*>);
|
void useNanoSkill(CNSocket*, sNano&, std::vector<ICombatant*>);
|
||||||
|
void useNPCSkill(EntityRef, int skillID, 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);
|
||||||
|
|
||||||
std::vector<ICombatant*> usePassiveNanoSkill(SkillData*, Player*);
|
|
||||||
|
|
||||||
void init();
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "Buffs.hpp"
|
#include "Buffs.hpp"
|
||||||
|
|
||||||
#include "PlayerManager.hpp"
|
#include "PlayerManager.hpp"
|
||||||
|
#include "NPCManager.hpp"
|
||||||
|
|
||||||
using namespace Buffs;
|
using namespace Buffs;
|
||||||
|
|
||||||
@ -120,19 +121,15 @@ void Buffs::timeBuffUpdate(EntityRef self, Buff* buff, int status, BuffStack* st
|
|||||||
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::timeBuffTimeout(EntityRef self) {
|
||||||
void Buffs::timeBuffTimeoutViewable(EntityRef self, Buff* buff, int ct) {
|
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);
|
||||||
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 = combatant->getCharType();
|
||||||
pkt.iID = plr->iID;
|
pkt.iID = combatant->getID();
|
||||||
pkt.iConditionBitFlag = plr->getCompositeCondition();
|
pkt.iConditionBitFlag = combatant->getCompositeCondition();
|
||||||
PlayerManager::sendToViewable(self.sock, pkt, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT);
|
NPCManager::sendToViewable(entity, &pkt, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT, sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT));
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
/* MOVE TO EGG LAMBDA
|
|
||||||
void Buffs::timeBuffTimeout(EntityRef self, BuffStack* buff) {
|
|
||||||
timeBuffUpdate(self, buff, ETBU_DEL);
|
|
||||||
timeBuffTimeoutViewable(self);
|
|
||||||
} */
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
@ -84,5 +84,5 @@ public:
|
|||||||
|
|
||||||
namespace Buffs {
|
namespace Buffs {
|
||||||
void timeBuffUpdate(EntityRef self, Buff* buff, int status, BuffStack* stack);
|
void timeBuffUpdate(EntityRef self, Buff* buff, int status, BuffStack* stack);
|
||||||
//void timeBuffTimeoutViewable(EntityRef self, Buff* buff, int ct);
|
void timeBuffTimeout(EntityRef self);
|
||||||
}
|
}
|
||||||
|
@ -834,7 +834,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];
|
||||||
Abilities::usePassiveNanoSkill(skill, plr);
|
Nanos::applyNanoBuff(skill, plr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "Missions.hpp"
|
#include "Missions.hpp"
|
||||||
#include "Eggs.hpp"
|
#include "Eggs.hpp"
|
||||||
#include "Items.hpp"
|
#include "Items.hpp"
|
||||||
|
#include "Abilities.hpp"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
@ -501,9 +502,12 @@ static void buffCommand(std::string full, std::vector<std::string>& args, CNSock
|
|||||||
if (*tmp)
|
if (*tmp)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Eggs::eggBuffPlayer(sock, skillId, 0, duration)<0)
|
if (Abilities::SkillTable.count(skillId) == 0) {
|
||||||
Chat::sendServerMessage(sock, "/buff: unknown skill Id");
|
Chat::sendServerMessage(sock, "/buff: unknown skill Id");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Eggs::eggBuffPlayer(sock, skillId, 0, duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void eggCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
static void eggCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
91
src/Eggs.cpp
91
src/Eggs.cpp
@ -15,63 +15,47 @@ using namespace Eggs;
|
|||||||
|
|
||||||
std::unordered_map<int, EggType> Eggs::EggTypes;
|
std::unordered_map<int, EggType> Eggs::EggTypes;
|
||||||
|
|
||||||
int Eggs::eggBuffPlayer(CNSocket* sock, int skillId, int eggId, int duration) {
|
void Eggs::eggBuffPlayer(CNSocket* sock, int skillId, int eggId, int duration) {
|
||||||
Player* plr = PlayerManager::getPlayer(sock);
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
// TODO ABILITIES
|
// eggId might be 0 if the buff is made by the /buff command
|
||||||
|
EntityRef src = eggId == 0 ? sock : EntityRef(eggId);
|
||||||
size_t resplen;
|
|
||||||
|
if(Abilities::SkillTable.count(skillId) == 0) {
|
||||||
if (skillId == 183) {
|
std::cout << "[WARN] egg " << eggId << " has skill ID " << skillId << " which doesn't exist" << std::endl;
|
||||||
resplen = sizeof(sP_FE2CL_NPC_SKILL_HIT) + sizeof(sSkillResult_Damage);
|
return;
|
||||||
} else if (skillId == 150) {
|
|
||||||
resplen = sizeof(sP_FE2CL_NPC_SKILL_HIT) + sizeof(sSkillResult_Heal_HP);
|
|
||||||
} else {
|
|
||||||
resplen = sizeof(sP_FE2CL_NPC_SKILL_HIT) + sizeof(sSkillResult_Buff);
|
|
||||||
}
|
|
||||||
assert(resplen < CN_PACKET_BUFFER_SIZE - 8);
|
|
||||||
// we know it's only one trailing struct, so we can skip full validation
|
|
||||||
|
|
||||||
uint8_t respbuf[CN_PACKET_BUFFER_SIZE];
|
|
||||||
auto skillUse = (sP_FE2CL_NPC_SKILL_HIT*)respbuf;
|
|
||||||
|
|
||||||
if (skillId == 183) { // damage egg
|
|
||||||
auto skill = (sSkillResult_Damage*)(respbuf + sizeof(sP_FE2CL_NPC_SKILL_HIT));
|
|
||||||
memset(respbuf, 0, resplen);
|
|
||||||
skill->eCT = 1;
|
|
||||||
skill->iID = plr->iID;
|
|
||||||
skill->iDamage = PC_MAXHEALTH(plr->level) * Abilities::SkillTable[skillId].values[0][0] / 1000;
|
|
||||||
plr->HP -= skill->iDamage;
|
|
||||||
if (plr->HP < 0)
|
|
||||||
plr->HP = 0;
|
|
||||||
skill->iHP = plr->HP;
|
|
||||||
} else if (skillId == 150) { // heal egg
|
|
||||||
auto skill = (sSkillResult_Heal_HP*)(respbuf + sizeof(sP_FE2CL_NPC_SKILL_HIT));
|
|
||||||
memset(respbuf, 0, resplen);
|
|
||||||
skill->eCT = 1;
|
|
||||||
skill->iID = plr->iID;
|
|
||||||
skill->iHealHP = PC_MAXHEALTH(plr->level) * Abilities::SkillTable[skillId].values[0][0] / 1000;
|
|
||||||
plr->HP += skill->iHealHP;
|
|
||||||
if (plr->HP > PC_MAXHEALTH(plr->level))
|
|
||||||
plr->HP = PC_MAXHEALTH(plr->level);
|
|
||||||
skill->iHP = plr->HP;
|
|
||||||
} else { // regular buff egg
|
|
||||||
auto skill = (sSkillResult_Buff*)(respbuf + sizeof(sP_FE2CL_NPC_SKILL_HIT));
|
|
||||||
memset(respbuf, 0, resplen);
|
|
||||||
skill->eCT = 1;
|
|
||||||
skill->iID = plr->iID;
|
|
||||||
skill->iConditionBitFlag = plr->getCompositeCondition();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
skillUse->iNPC_ID = eggId;
|
SkillData* skill = &Abilities::SkillTable[skillId];
|
||||||
skillUse->iSkillID = skillId;
|
if(skill->drainType == SkillDrainType::PASSIVE) {
|
||||||
skillUse->eST = Abilities::SkillTable[skillId].skillType;
|
// apply buff
|
||||||
skillUse->iTargetCnt = 1;
|
if(skill->targetType != SkillTargetType::SELF) {
|
||||||
|
std::cout << "[WARN] weird skill type for egg " << eggId << " with skill " << skillId << ", should be " << (int)skill->targetType << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
sock->sendPacket((void*)&respbuf, P_FE2CL_NPC_SKILL_HIT, resplen);
|
int timeBuffId = Abilities::getCSTBFromST(skill->skillType);
|
||||||
PlayerManager::sendToViewable(sock, (void*)&respbuf, P_FE2CL_NPC_SKILL_HIT, resplen);
|
int value = skill->values[0][0];
|
||||||
|
BuffStack eggBuff = {
|
||||||
|
duration * 1000 / MS_PER_PLAYER_TICK,
|
||||||
|
value,
|
||||||
|
src,
|
||||||
|
BuffClass::EGG
|
||||||
|
};
|
||||||
|
plr->addBuff(timeBuffId,
|
||||||
|
[](EntityRef self, Buff* buff, int status, BuffStack* stack) {
|
||||||
|
Buffs::timeBuffUpdate(self, buff, status, stack);
|
||||||
|
if(status == ETBU_DEL) Buffs::timeBuffTimeout(self);
|
||||||
|
},
|
||||||
|
[](EntityRef self, Buff* buff, time_t currTime) {
|
||||||
|
// no-op
|
||||||
|
},
|
||||||
|
&eggBuff);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
// use skill
|
||||||
|
std::vector<ICombatant*> targets;
|
||||||
|
targets.push_back(dynamic_cast<ICombatant*>(plr));
|
||||||
|
Abilities::useNPCSkill(src, skillId, targets);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void eggStep(CNServer* serv, time_t currTime) {
|
static void eggStep(CNServer* serv, time_t currTime) {
|
||||||
@ -141,16 +125,13 @@ static void eggPickup(CNSocket* sock, CNPacketData* data) {
|
|||||||
|
|
||||||
EggType* type = &EggTypes[typeId];
|
EggType* type = &EggTypes[typeId];
|
||||||
|
|
||||||
// buff the player
|
|
||||||
if (type->effectId != 0)
|
|
||||||
eggBuffPlayer(sock, type->effectId, eggRef.id, type->duration);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SHINY_PICKUP_SUCC is only causing a GUI effect in the client
|
* SHINY_PICKUP_SUCC is only causing a GUI effect in the client
|
||||||
* (buff icon pops up in the bottom of the screen)
|
* (buff icon pops up in the bottom of the screen)
|
||||||
* so we don't send it for non-effect
|
* so we don't send it for non-effect
|
||||||
*/
|
*/
|
||||||
if (type->effectId != 0) {
|
if (type->effectId != 0) {
|
||||||
|
eggBuffPlayer(sock, type->effectId, eggRef.id, type->duration);
|
||||||
INITSTRUCT(sP_FE2CL_REP_SHINY_PICKUP_SUCC, resp);
|
INITSTRUCT(sP_FE2CL_REP_SHINY_PICKUP_SUCC, resp);
|
||||||
resp.iSkillID = type->effectId;
|
resp.iSkillID = type->effectId;
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@ namespace Eggs {
|
|||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
/// returns -1 on fail
|
void eggBuffPlayer(CNSocket* sock, int skillId, int eggId, int duration);
|
||||||
int eggBuffPlayer(CNSocket* sock, int skillId, int eggId, int duration);
|
|
||||||
void npcDataToEggData(int x, int y, int z, sNPCAppearanceData* npc, sShinyAppearanceData* egg);
|
void npcDataToEggData(int x, int y, int z, sNPCAppearanceData* npc, sShinyAppearanceData* egg);
|
||||||
}
|
}
|
||||||
|
@ -240,27 +240,11 @@ void Groups::groupTickInfo(Player* plr) {
|
|||||||
sendToGroup(plr->group, (void*)&respbuf, P_FE2CL_PC_GROUP_MEMBER_INFO, resplen);
|
sendToGroup(plr->group, (void*)&respbuf, P_FE2CL_PC_GROUP_MEMBER_INFO, resplen);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void groupUnbuff(Player* plr) {
|
|
||||||
Group* group = plr->group;
|
|
||||||
for (int i = 0; i < group->members.size(); i++) {
|
|
||||||
for (int n = 0; n < group->members.size(); n++) {
|
|
||||||
if (i == n)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
EntityRef other = group->members[n];
|
|
||||||
|
|
||||||
// TODO ABILITIES
|
|
||||||
//Abilities::applyBuff(sock, otherPlr->Nanos[otherPlr->activeNano].iSkillID, 2, 1, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Groups::groupKick(Player* plr) {
|
void Groups::groupKick(Player* plr) {
|
||||||
Group* group = plr->group;
|
Group* group = plr->group;
|
||||||
|
|
||||||
// if you are the group leader, destroy your own group and kick everybody
|
// if you are the group leader, destroy your own group and kick everybody
|
||||||
if (plr->group->members[0] == PlayerManager::getSockFromID(plr->iID)) {
|
if (plr->group->members[0] == PlayerManager::getSockFromID(plr->iID)) {
|
||||||
groupUnbuff(plr);
|
|
||||||
INITSTRUCT(sP_FE2CL_PC_GROUP_LEAVE_SUCC, resp1);
|
INITSTRUCT(sP_FE2CL_PC_GROUP_LEAVE_SUCC, resp1);
|
||||||
sendToGroup(plr->group, (void*)&resp1, P_FE2CL_PC_GROUP_LEAVE_SUCC, sizeof(sP_FE2CL_PC_GROUP_LEAVE_SUCC));
|
sendToGroup(plr->group, (void*)&resp1, P_FE2CL_PC_GROUP_LEAVE_SUCC, sizeof(sP_FE2CL_PC_GROUP_LEAVE_SUCC));
|
||||||
disbandGroup(plr->group);
|
disbandGroup(plr->group);
|
||||||
|
@ -503,7 +503,7 @@ static void itemUseHandler(CNSocket* sock, CNPacketData* data) {
|
|||||||
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 passive tick
|
// no-op
|
||||||
},
|
},
|
||||||
&gumballBuff);
|
&gumballBuff);
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ void NPCManager::updateNPCPosition(int32_t id, int X, int Y, int Z, uint64_t I,
|
|||||||
Chunking::updateEntityChunk({id}, oldChunk, newChunk);
|
Chunking::updateEntityChunk({id}, oldChunk, newChunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NPCManager::sendToViewable(BaseNPC *npc, void *buf, uint32_t type, size_t size) {
|
void NPCManager::sendToViewable(Entity *npc, void *buf, uint32_t type, size_t size) {
|
||||||
for (auto it = npc->viewableChunks.begin(); it != npc->viewableChunks.end(); it++) {
|
for (auto it = npc->viewableChunks.begin(); it != npc->viewableChunks.end(); it++) {
|
||||||
Chunk* chunk = *it;
|
Chunk* chunk = *it;
|
||||||
for (const EntityRef& ref : chunk->entities) {
|
for (const EntityRef& ref : chunk->entities) {
|
||||||
|
@ -42,7 +42,7 @@ namespace NPCManager {
|
|||||||
void destroyNPC(int32_t);
|
void destroyNPC(int32_t);
|
||||||
void updateNPCPosition(int32_t, int X, int Y, int Z, uint64_t I, int angle);
|
void updateNPCPosition(int32_t, int X, int Y, int Z, uint64_t I, int angle);
|
||||||
|
|
||||||
void sendToViewable(BaseNPC* npc, void* buf, uint32_t type, size_t size);
|
void sendToViewable(Entity* npc, void* buf, uint32_t type, size_t size);
|
||||||
|
|
||||||
BaseNPC *summonNPC(int x, int y, int z, uint64_t instance, int type, bool respawn=false, bool baseInstance=false);
|
BaseNPC *summonNPC(int x, int y, int z, uint64_t instance, int type, bool respawn=false, bool baseInstance=false);
|
||||||
|
|
||||||
|
@ -69,6 +69,52 @@ void Nanos::addNano(CNSocket* sock, int16_t nanoID, int16_t slot, bool spendfm)
|
|||||||
PlayerManager::sendToViewable(sock, resp2, P_FE2CL_REP_PC_CHANGE_LEVEL);
|
PlayerManager::sendToViewable(sock, resp2, P_FE2CL_REP_PC_CHANGE_LEVEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<ICombatant*> Nanos::applyNanoBuff(SkillData* skill, Player* plr) {
|
||||||
|
assert(skill->drainType == SkillDrainType::PASSIVE);
|
||||||
|
|
||||||
|
EntityRef self = PlayerManager::getSockFromID(plr->iID);
|
||||||
|
std::vector<ICombatant*> affected;
|
||||||
|
std::vector<EntityRef> targets;
|
||||||
|
if (skill->targetType == SkillTargetType::GROUP) {
|
||||||
|
targets = plr->getGroupMembers(); // group
|
||||||
|
}
|
||||||
|
else if(skill->targetType == SkillTargetType::SELF) {
|
||||||
|
targets.push_back(self); // self
|
||||||
|
} else {
|
||||||
|
std::cout << "[WARN] Passive skill with type " << skill->skillType << " has target type MOB" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int timeBuffId = Abilities::getCSTBFromST(skill->skillType);
|
||||||
|
int boost = Nanos::getNanoBoost(plr) ? 3 : 0;
|
||||||
|
int value = skill->values[0][boost];
|
||||||
|
|
||||||
|
BuffStack passiveBuff = {
|
||||||
|
1, // passive nano buffs refreshed every tick
|
||||||
|
value,
|
||||||
|
self,
|
||||||
|
BuffClass::NONE, // overwritten per target
|
||||||
|
};
|
||||||
|
|
||||||
|
for (EntityRef target : targets) {
|
||||||
|
Entity* entity = target.getEntity();
|
||||||
|
if (entity->kind != PLAYER && entity->kind != COMBAT_NPC && entity->kind != MOB)
|
||||||
|
continue; // not a combatant
|
||||||
|
|
||||||
|
passiveBuff.buffStackClass = target == self ? BuffClass::NANO : BuffClass::GROUP_NANO;
|
||||||
|
ICombatant* combatant = dynamic_cast<ICombatant*>(entity);
|
||||||
|
if(combatant->addBuff(timeBuffId,
|
||||||
|
[](EntityRef self, Buff* buff, int status, BuffStack* stack) {
|
||||||
|
Buffs::timeBuffUpdate(self, buff, status, stack);
|
||||||
|
},
|
||||||
|
[](EntityRef self, Buff* buff, time_t currTime) {
|
||||||
|
// no-op
|
||||||
|
},
|
||||||
|
&passiveBuff)) affected.push_back(combatant);
|
||||||
|
}
|
||||||
|
|
||||||
|
return affected;
|
||||||
|
}
|
||||||
|
|
||||||
void Nanos::summonNano(CNSocket *sock, int slot, bool silent) {
|
void Nanos::summonNano(CNSocket *sock, int slot, bool silent) {
|
||||||
INITSTRUCT(sP_FE2CL_REP_NANO_ACTIVE_SUCC, resp);
|
INITSTRUCT(sP_FE2CL_REP_NANO_ACTIVE_SUCC, resp);
|
||||||
resp.iActiveNanoSlotNum = slot;
|
resp.iActiveNanoSlotNum = slot;
|
||||||
@ -94,8 +140,8 @@ void Nanos::summonNano(CNSocket *sock, int slot, bool silent) {
|
|||||||
// passive buff effect
|
// passive buff effect
|
||||||
resp.eCSTB___Add = 1;
|
resp.eCSTB___Add = 1;
|
||||||
int boost = Nanos::getNanoBoost(plr);
|
int boost = Nanos::getNanoBoost(plr);
|
||||||
std::vector<ICombatant*> affectedCombatants = Abilities::usePassiveNanoSkill(skill, plr);
|
std::vector<ICombatant*> affectedCombatants = applyNanoBuff(skill, plr);
|
||||||
if(!affectedCombatants.empty()) Abilities::broadcastNanoSkill(sock, nano, affectedCombatants);
|
if(!affectedCombatants.empty()) Abilities::useNanoSkill(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
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "core/Core.hpp"
|
#include "core/Core.hpp"
|
||||||
|
|
||||||
#include "Player.hpp"
|
#include "Player.hpp"
|
||||||
|
#include "Abilities.hpp"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
@ -25,4 +26,5 @@ namespace Nanos {
|
|||||||
void summonNano(CNSocket* sock, int slot, bool silent = false);
|
void summonNano(CNSocket* sock, int slot, bool silent = false);
|
||||||
int nanoStyle(int nanoID);
|
int nanoStyle(int nanoID);
|
||||||
bool getNanoBoost(Player* plr);
|
bool getNanoBoost(Player* plr);
|
||||||
|
std::vector<ICombatant*> applyNanoBuff(SkillData* skill, Player* plr);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user