mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-11-22 21:40:05 +00:00
[WIP] Replace appearance data with individual fields
Storing certain things in appearance data and others in their own fields was gross. Now everything is stored on the same level and functions have been added to generate appearance data when it's needed by the client.
This commit is contained in:
parent
7ab01b098d
commit
efc00e63b3
@ -151,15 +151,15 @@ bool doDebuff(CNSocket *sock, sSkillResult_Buff *respdata, int i, int32_t target
|
|||||||
Combat::hitMob(sock, mob, 0);
|
Combat::hitMob(sock, mob, 0);
|
||||||
|
|
||||||
respdata[i].eCT = 4;
|
respdata[i].eCT = 4;
|
||||||
respdata[i].iID = mob->appearanceData.iNPC_ID;
|
respdata[i].iID = mob->id;
|
||||||
respdata[i].bProtected = 1;
|
respdata[i].bProtected = 1;
|
||||||
if (mob->skillStyle < 0 && mob->state != MobState::RETREAT
|
if (mob->skillStyle < 0 && mob->state != MobState::RETREAT
|
||||||
&& !(mob->appearanceData.iConditionBitFlag & CSB_BIT_FREEDOM)) { // only debuff if the enemy is not retreating, casting corruption or in freedom
|
&& !(mob->cbf & CSB_BIT_FREEDOM)) { // only debuff if the enemy is not retreating, casting corruption or in freedom
|
||||||
mob->appearanceData.iConditionBitFlag |= bitFlag;
|
mob->cbf |= bitFlag;
|
||||||
mob->unbuffTimes[bitFlag] = getTime() + duration * 100;
|
mob->unbuffTimes[bitFlag] = getTime() + duration * 100;
|
||||||
respdata[i].bProtected = 0;
|
respdata[i].bProtected = 0;
|
||||||
}
|
}
|
||||||
respdata[i].iConditionBitFlag = mob->appearanceData.iConditionBitFlag;
|
respdata[i].iConditionBitFlag = mob->cbf;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -224,16 +224,16 @@ bool doDamageNDebuff(CNSocket *sock, sSkillResult_Damage_N_Debuff *respdata, int
|
|||||||
|
|
||||||
respdata[i].eCT = 4;
|
respdata[i].eCT = 4;
|
||||||
respdata[i].iDamage = duration / 10;
|
respdata[i].iDamage = duration / 10;
|
||||||
respdata[i].iID = mob->appearanceData.iNPC_ID;
|
respdata[i].iID = mob->id;
|
||||||
respdata[i].iHP = mob->appearanceData.iHP;
|
respdata[i].iHP = mob->hp;
|
||||||
respdata[i].bProtected = 1;
|
respdata[i].bProtected = 1;
|
||||||
if (mob->skillStyle < 0 && mob->state != MobState::RETREAT
|
if (mob->skillStyle < 0 && mob->state != MobState::RETREAT
|
||||||
&& !(mob->appearanceData.iConditionBitFlag & CSB_BIT_FREEDOM)) { // only debuff if the enemy is not retreating, casting corruption or in freedom
|
&& !(mob->cbf & CSB_BIT_FREEDOM)) { // only debuff if the enemy is not retreating, casting corruption or in freedom
|
||||||
mob->appearanceData.iConditionBitFlag |= bitFlag;
|
mob->cbf |= bitFlag;
|
||||||
mob->unbuffTimes[bitFlag] = getTime() + duration * 100;
|
mob->unbuffTimes[bitFlag] = getTime() + duration * 100;
|
||||||
respdata[i].bProtected = 0;
|
respdata[i].bProtected = 0;
|
||||||
}
|
}
|
||||||
respdata[i].iConditionBitFlag = mob->appearanceData.iConditionBitFlag;
|
respdata[i].iConditionBitFlag = mob->cbf;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -293,8 +293,8 @@ bool doDamage(CNSocket *sock, sSkillResult_Damage *respdata, int i, int32_t targ
|
|||||||
|
|
||||||
respdata[i].eCT = 4;
|
respdata[i].eCT = 4;
|
||||||
respdata[i].iDamage = damage;
|
respdata[i].iDamage = damage;
|
||||||
respdata[i].iID = mob->appearanceData.iNPC_ID;
|
respdata[i].iID = mob->id;
|
||||||
respdata[i].iHP = mob->appearanceData.iHP;
|
respdata[i].iHP = mob->hp;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -348,8 +348,8 @@ bool doLeech(CNSocket *sock, sSkillResult_Heal_HP *healdata, int i, int32_t targ
|
|||||||
|
|
||||||
damagedata->eCT = 4;
|
damagedata->eCT = 4;
|
||||||
damagedata->iDamage = damage;
|
damagedata->iDamage = damage;
|
||||||
damagedata->iID = mob->appearanceData.iNPC_ID;
|
damagedata->iID = mob->id;
|
||||||
damagedata->iHP = mob->appearanceData.iHP;
|
damagedata->iHP = mob->hp;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -476,13 +476,13 @@ bool doHeal(Mob* mob, sSkillResult_Heal_HP* respdata, int i, int32_t targetID, i
|
|||||||
Mob* targetMob = (Mob*)npc;
|
Mob* targetMob = (Mob*)npc;
|
||||||
|
|
||||||
int healedAmount = amount * targetMob->maxHealth / 1000;
|
int healedAmount = amount * targetMob->maxHealth / 1000;
|
||||||
targetMob->appearanceData.iHP += healedAmount;
|
targetMob->hp += healedAmount;
|
||||||
if (targetMob->appearanceData.iHP > targetMob->maxHealth)
|
if (targetMob->hp > targetMob->maxHealth)
|
||||||
targetMob->appearanceData.iHP = targetMob->maxHealth;
|
targetMob->hp = targetMob->maxHealth;
|
||||||
|
|
||||||
respdata[i].eCT = 4;
|
respdata[i].eCT = 4;
|
||||||
respdata[i].iID = targetMob->appearanceData.iNPC_ID;
|
respdata[i].iID = targetMob->id;
|
||||||
respdata[i].iHP = targetMob->appearanceData.iHP;
|
respdata[i].iHP = targetMob->hp;
|
||||||
respdata[i].iHealHP = healedAmount;
|
respdata[i].iHealHP = healedAmount;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -490,13 +490,13 @@ bool doHeal(Mob* mob, sSkillResult_Heal_HP* respdata, int i, int32_t targetID, i
|
|||||||
|
|
||||||
bool doReturnHeal(Mob* mob, sSkillResult_Heal_HP* respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) {
|
bool doReturnHeal(Mob* mob, sSkillResult_Heal_HP* respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) {
|
||||||
int healedAmount = amount * mob->maxHealth / 1000;
|
int healedAmount = amount * mob->maxHealth / 1000;
|
||||||
mob->appearanceData.iHP += healedAmount;
|
mob->hp += healedAmount;
|
||||||
if (mob->appearanceData.iHP > mob->maxHealth)
|
if (mob->hp > mob->maxHealth)
|
||||||
mob->appearanceData.iHP = mob->maxHealth;
|
mob->hp = mob->maxHealth;
|
||||||
|
|
||||||
respdata[i].eCT = 4;
|
respdata[i].eCT = 4;
|
||||||
respdata[i].iID = mob->appearanceData.iNPC_ID;
|
respdata[i].iID = mob->id;
|
||||||
respdata[i].iHP = mob->appearanceData.iHP;
|
respdata[i].iHP = mob->hp;
|
||||||
respdata[i].iHealHP = healedAmount;
|
respdata[i].iHealHP = healedAmount;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -567,13 +567,13 @@ bool doLeech(Mob* mob, sSkillResult_Heal_HP* healdata, int i, int32_t targetID,
|
|||||||
|
|
||||||
int healedAmount = amount * PC_MAXHEALTH(plr->level) / 1000;
|
int healedAmount = amount * PC_MAXHEALTH(plr->level) / 1000;
|
||||||
|
|
||||||
mob->appearanceData.iHP += healedAmount;
|
mob->hp += healedAmount;
|
||||||
if (mob->appearanceData.iHP > mob->maxHealth)
|
if (mob->hp > mob->maxHealth)
|
||||||
mob->appearanceData.iHP = mob->maxHealth;
|
mob->hp = mob->maxHealth;
|
||||||
|
|
||||||
healdata->eCT = 4;
|
healdata->eCT = 4;
|
||||||
healdata->iID = mob->appearanceData.iNPC_ID;
|
healdata->iID = mob->id;
|
||||||
healdata->iHP = mob->appearanceData.iHP;
|
healdata->iHP = mob->hp;
|
||||||
healdata->iHealHP = healedAmount;
|
healdata->iHealHP = healedAmount;
|
||||||
|
|
||||||
int damage = healedAmount;
|
int damage = healedAmount;
|
||||||
@ -639,9 +639,9 @@ bool doBatteryDrain(Mob* mob, sSkillResult_BatteryDrain* respdata, int i, int32_
|
|||||||
|
|
||||||
bool doBuff(Mob* mob, sSkillResult_Buff* respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) {
|
bool doBuff(Mob* mob, sSkillResult_Buff* respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) {
|
||||||
respdata[i].eCT = 4;
|
respdata[i].eCT = 4;
|
||||||
respdata[i].iID = mob->appearanceData.iNPC_ID;
|
respdata[i].iID = mob->id;
|
||||||
mob->appearanceData.iConditionBitFlag |= bitFlag;
|
mob->cbf |= bitFlag;
|
||||||
respdata[i].iConditionBitFlag = mob->appearanceData.iConditionBitFlag;
|
respdata[i].iConditionBitFlag = mob->cbf;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -670,7 +670,7 @@ template<class sPAYLOAD,
|
|||||||
sP_FE2CL_NPC_SKILL_HIT* resp = (sP_FE2CL_NPC_SKILL_HIT*)respbuf;
|
sP_FE2CL_NPC_SKILL_HIT* resp = (sP_FE2CL_NPC_SKILL_HIT*)respbuf;
|
||||||
sPAYLOAD* respdata = (sPAYLOAD*)(respbuf + sizeof(sP_FE2CL_NPC_SKILL_HIT));
|
sPAYLOAD* respdata = (sPAYLOAD*)(respbuf + sizeof(sP_FE2CL_NPC_SKILL_HIT));
|
||||||
|
|
||||||
resp->iNPC_ID = mob->appearanceData.iNPC_ID;
|
resp->iNPC_ID = mob->id;
|
||||||
resp->iSkillID = skillID;
|
resp->iSkillID = skillID;
|
||||||
resp->iValue1 = mob->hitX;
|
resp->iValue1 = mob->hitX;
|
||||||
resp->iValue2 = mob->hitY;
|
resp->iValue2 = mob->hitY;
|
||||||
|
@ -279,42 +279,42 @@ void Chunking::createInstance(uint64_t instanceID) {
|
|||||||
if (((Mob*)baseNPC)->groupLeader != 0 && ((Mob*)baseNPC)->groupLeader != npcID)
|
if (((Mob*)baseNPC)->groupLeader != 0 && ((Mob*)baseNPC)->groupLeader != npcID)
|
||||||
continue; // follower; don't copy individually
|
continue; // follower; don't copy individually
|
||||||
|
|
||||||
Mob* newMob = new Mob(baseNPC->x, baseNPC->y, baseNPC->z, baseNPC->appearanceData.iAngle,
|
Mob* newMob = new Mob(baseNPC->x, baseNPC->y, baseNPC->z, baseNPC->angle,
|
||||||
instanceID, baseNPC->appearanceData.iNPCType, NPCManager::NPCData[baseNPC->appearanceData.iNPCType], NPCManager::nextId--);
|
instanceID, baseNPC->type, NPCManager::NPCData[baseNPC->type], NPCManager::nextId--);
|
||||||
NPCManager::NPCs[newMob->appearanceData.iNPC_ID] = newMob;
|
NPCManager::NPCs[newMob->id] = newMob;
|
||||||
|
|
||||||
// if in a group, copy over group members as well
|
// if in a group, copy over group members as well
|
||||||
if (((Mob*)baseNPC)->groupLeader != 0) {
|
if (((Mob*)baseNPC)->groupLeader != 0) {
|
||||||
newMob->groupLeader = newMob->appearanceData.iNPC_ID; // set leader ID for new leader
|
newMob->groupLeader = newMob->id; // set leader ID for new leader
|
||||||
Mob* mobData = (Mob*)baseNPC;
|
Mob* mobData = (Mob*)baseNPC;
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
if (mobData->groupMember[i] != 0) {
|
if (mobData->groupMember[i] != 0) {
|
||||||
int followerID = NPCManager::nextId--; // id for follower
|
int followerID = NPCManager::nextId--; // id for follower
|
||||||
BaseNPC* baseFollower = NPCManager::NPCs[mobData->groupMember[i]]; // follower from template
|
BaseNPC* baseFollower = NPCManager::NPCs[mobData->groupMember[i]]; // follower from template
|
||||||
// new follower instance
|
// new follower instance
|
||||||
Mob* newMobFollower = new Mob(baseFollower->x, baseFollower->y, baseFollower->z, baseFollower->appearanceData.iAngle,
|
Mob* newMobFollower = new Mob(baseFollower->x, baseFollower->y, baseFollower->z, baseFollower->angle,
|
||||||
instanceID, baseFollower->appearanceData.iNPCType, NPCManager::NPCData[baseFollower->appearanceData.iNPCType], followerID);
|
instanceID, baseFollower->type, NPCManager::NPCData[baseFollower->type], followerID);
|
||||||
// add follower to NPC maps
|
// add follower to NPC maps
|
||||||
NPCManager::NPCs[followerID] = newMobFollower;
|
NPCManager::NPCs[followerID] = newMobFollower;
|
||||||
// set follower-specific properties
|
// set follower-specific properties
|
||||||
newMobFollower->groupLeader = newMob->appearanceData.iNPC_ID;
|
newMobFollower->groupLeader = newMob->id;
|
||||||
newMobFollower->offsetX = ((Mob*)baseFollower)->offsetX;
|
newMobFollower->offsetX = ((Mob*)baseFollower)->offsetX;
|
||||||
newMobFollower->offsetY = ((Mob*)baseFollower)->offsetY;
|
newMobFollower->offsetY = ((Mob*)baseFollower)->offsetY;
|
||||||
// add follower copy to leader copy
|
// add follower copy to leader copy
|
||||||
newMob->groupMember[i] = followerID;
|
newMob->groupMember[i] = followerID;
|
||||||
NPCManager::updateNPCPosition(followerID, baseFollower->x, baseFollower->y, baseFollower->z,
|
NPCManager::updateNPCPosition(followerID, baseFollower->x, baseFollower->y, baseFollower->z,
|
||||||
instanceID, baseFollower->appearanceData.iAngle);
|
instanceID, baseFollower->angle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NPCManager::updateNPCPosition(newMob->appearanceData.iNPC_ID, baseNPC->x, baseNPC->y, baseNPC->z,
|
NPCManager::updateNPCPosition(newMob->id, baseNPC->x, baseNPC->y, baseNPC->z,
|
||||||
instanceID, baseNPC->appearanceData.iAngle);
|
instanceID, baseNPC->angle);
|
||||||
} else {
|
} else {
|
||||||
BaseNPC* newNPC = new BaseNPC(baseNPC->x, baseNPC->y, baseNPC->z, baseNPC->appearanceData.iAngle,
|
BaseNPC* newNPC = new BaseNPC(baseNPC->x, baseNPC->y, baseNPC->z, baseNPC->angle,
|
||||||
instanceID, baseNPC->appearanceData.iNPCType, NPCManager::nextId--);
|
instanceID, baseNPC->type, NPCManager::nextId--);
|
||||||
NPCManager::NPCs[newNPC->appearanceData.iNPC_ID] = newNPC;
|
NPCManager::NPCs[newNPC->id] = newNPC;
|
||||||
NPCManager::updateNPCPosition(newNPC->appearanceData.iNPC_ID, baseNPC->x, baseNPC->y, baseNPC->z,
|
NPCManager::updateNPCPosition(newNPC->id, baseNPC->x, baseNPC->y, baseNPC->z,
|
||||||
instanceID, baseNPC->appearanceData.iAngle);
|
instanceID, baseNPC->angle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,9 +139,9 @@ static void pcAttackNpcs(CNSocket *sock, CNPacketData *data) {
|
|||||||
|
|
||||||
damage.first = hitMob(sock, mob, damage.first);
|
damage.first = hitMob(sock, mob, damage.first);
|
||||||
|
|
||||||
respdata[i].iID = mob->appearanceData.iNPC_ID;
|
respdata[i].iID = mob->id;
|
||||||
respdata[i].iDamage = damage.first;
|
respdata[i].iDamage = damage.first;
|
||||||
respdata[i].iHP = mob->appearanceData.iHP;
|
respdata[i].iHP = mob->hp;
|
||||||
respdata[i].iHitFlag = damage.second; // hitscan, not a rocket or a grenade
|
respdata[i].iHitFlag = damage.second; // hitscan, not a rocket or a grenade
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,7 +168,7 @@ void Combat::npcAttackPc(Mob *mob, time_t currTime) {
|
|||||||
if (!(plr->iSpecialState & CN_SPECIAL_STATE_FLAG__INVULNERABLE))
|
if (!(plr->iSpecialState & CN_SPECIAL_STATE_FLAG__INVULNERABLE))
|
||||||
plr->HP -= damage.first;
|
plr->HP -= damage.first;
|
||||||
|
|
||||||
pkt->iNPC_ID = mob->appearanceData.iNPC_ID;
|
pkt->iNPC_ID = mob->id;
|
||||||
pkt->iPCCnt = 1;
|
pkt->iPCCnt = 1;
|
||||||
|
|
||||||
atk->iID = plr->iID;
|
atk->iID = plr->iID;
|
||||||
@ -207,20 +207,20 @@ int Combat::hitMob(CNSocket *sock, Mob *mob, int damage) {
|
|||||||
MobAI::followToCombat(mob);
|
MobAI::followToCombat(mob);
|
||||||
}
|
}
|
||||||
|
|
||||||
mob->appearanceData.iHP -= damage;
|
mob->hp -= damage;
|
||||||
|
|
||||||
// wake up sleeping monster
|
// wake up sleeping monster
|
||||||
if (mob->appearanceData.iConditionBitFlag & CSB_BIT_MEZ) {
|
if (mob->cbf & CSB_BIT_MEZ) {
|
||||||
mob->appearanceData.iConditionBitFlag &= ~CSB_BIT_MEZ;
|
mob->cbf &= ~CSB_BIT_MEZ;
|
||||||
|
|
||||||
INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, pkt1);
|
INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, pkt1);
|
||||||
pkt1.eCT = 2;
|
pkt1.eCT = 2;
|
||||||
pkt1.iID = mob->appearanceData.iNPC_ID;
|
pkt1.iID = mob->id;
|
||||||
pkt1.iConditionBitFlag = mob->appearanceData.iConditionBitFlag;
|
pkt1.iConditionBitFlag = mob->cbf;
|
||||||
NPCManager::sendToViewable(mob, &pkt1, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT, sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT));
|
NPCManager::sendToViewable(mob, &pkt1, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT, sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mob->appearanceData.iHP <= 0)
|
if (mob->hp <= 0)
|
||||||
killMob(mob->target, mob);
|
killMob(mob->target, mob);
|
||||||
|
|
||||||
return damage;
|
return damage;
|
||||||
@ -253,7 +253,7 @@ static void genQItemRolls(Player *leader, std::map<int, int>& rolls) {
|
|||||||
void Combat::killMob(CNSocket *sock, Mob *mob) {
|
void Combat::killMob(CNSocket *sock, Mob *mob) {
|
||||||
mob->state = MobState::DEAD;
|
mob->state = MobState::DEAD;
|
||||||
mob->target = nullptr;
|
mob->target = nullptr;
|
||||||
mob->appearanceData.iConditionBitFlag = 0;
|
mob->cbf = 0;
|
||||||
mob->skillStyle = -1;
|
mob->skillStyle = -1;
|
||||||
mob->unbuffTimes.clear();
|
mob->unbuffTimes.clear();
|
||||||
mob->killedTime = getTime(); // XXX: maybe introduce a shard-global time for each step?
|
mob->killedTime = getTime(); // XXX: maybe introduce a shard-global time for each step?
|
||||||
@ -273,7 +273,7 @@ void Combat::killMob(CNSocket *sock, Mob *mob) {
|
|||||||
|
|
||||||
if (plr->groupCnt == 1 && plr->iIDGroup == plr->iID) {
|
if (plr->groupCnt == 1 && plr->iIDGroup == plr->iID) {
|
||||||
Items::giveMobDrop(sock, mob, rolled, eventRolled);
|
Items::giveMobDrop(sock, mob, rolled, eventRolled);
|
||||||
Missions::mobKilled(sock, mob->appearanceData.iNPCType, qitemRolls);
|
Missions::mobKilled(sock, mob->type, qitemRolls);
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < leader->groupCnt; i++) {
|
for (int i = 0; i < leader->groupCnt; i++) {
|
||||||
CNSocket* sockTo = PlayerManager::getSockFromID(leader->groupIDs[i]);
|
CNSocket* sockTo = PlayerManager::getSockFromID(leader->groupIDs[i]);
|
||||||
@ -288,7 +288,7 @@ void Combat::killMob(CNSocket *sock, Mob *mob) {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
Items::giveMobDrop(sockTo, mob, rolled, eventRolled);
|
Items::giveMobDrop(sockTo, mob, rolled, eventRolled);
|
||||||
Missions::mobKilled(sockTo, mob->appearanceData.iNPCType, qitemRolls);
|
Missions::mobKilled(sockTo, mob->type, qitemRolls);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -298,10 +298,10 @@ void Combat::killMob(CNSocket *sock, Mob *mob) {
|
|||||||
|
|
||||||
// fire any triggered events
|
// fire any triggered events
|
||||||
for (NPCEvent& event : NPCManager::NPCEvents)
|
for (NPCEvent& event : NPCManager::NPCEvents)
|
||||||
if (event.trigger == ON_KILLED && event.npcType == mob->appearanceData.iNPCType)
|
if (event.trigger == ON_KILLED && event.npcType == mob->type)
|
||||||
event.handler(sock, mob);
|
event.handler(sock, mob);
|
||||||
|
|
||||||
auto it = Transport::NPCQueues.find(mob->appearanceData.iNPC_ID);
|
auto it = Transport::NPCQueues.find(mob->id);
|
||||||
if (it == Transport::NPCQueues.end() || it->second.empty())
|
if (it == Transport::NPCQueues.end() || it->second.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -319,7 +319,7 @@ void Combat::killMob(CNSocket *sock, Mob *mob) {
|
|||||||
queue.push(point);
|
queue.push(point);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Transport::NPCQueues.erase(mob->appearanceData.iNPC_ID);
|
Transport::NPCQueues.erase(mob->id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -513,9 +513,9 @@ static void pcAttackChars(CNSocket *sock, CNPacketData *data) {
|
|||||||
damage.first = hitMob(sock, mob, damage.first);
|
damage.first = hitMob(sock, mob, damage.first);
|
||||||
|
|
||||||
respdata[i].eCT = pktdata[i*2+1];
|
respdata[i].eCT = pktdata[i*2+1];
|
||||||
respdata[i].iID = mob->appearanceData.iNPC_ID;
|
respdata[i].iID = mob->id;
|
||||||
respdata[i].iDamage = damage.first;
|
respdata[i].iDamage = damage.first;
|
||||||
respdata[i].iHP = mob->appearanceData.iHP;
|
respdata[i].iHP = mob->hp;
|
||||||
respdata[i].iHitFlag = damage.second; // hitscan, not a rocket or a grenade
|
respdata[i].iHitFlag = damage.second; // hitscan, not a rocket or a grenade
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -711,9 +711,9 @@ static void projectileHit(CNSocket* sock, CNPacketData* data) {
|
|||||||
|
|
||||||
damage.first = hitMob(sock, mob, damage.first);
|
damage.first = hitMob(sock, mob, damage.first);
|
||||||
|
|
||||||
respdata[i].iID = mob->appearanceData.iNPC_ID;
|
respdata[i].iID = mob->id;
|
||||||
respdata[i].iDamage = damage.first;
|
respdata[i].iDamage = damage.first;
|
||||||
respdata[i].iHP = mob->appearanceData.iHP;
|
respdata[i].iHP = mob->hp;
|
||||||
respdata[i].iHitFlag = damage.second;
|
respdata[i].iHitFlag = damage.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,20 +243,20 @@ static void summonWCommand(std::string full, std::vector<std::string>& args, CNS
|
|||||||
BaseNPC *npc = NPCManager::summonNPC(plr->x, plr->y, plr->z, plr->instanceID, type, true);
|
BaseNPC *npc = NPCManager::summonNPC(plr->x, plr->y, plr->z, plr->instanceID, type, true);
|
||||||
|
|
||||||
// update angle
|
// update angle
|
||||||
npc->appearanceData.iAngle = (plr->angle + 180) % 360;
|
npc->angle = (plr->angle + 180) % 360;
|
||||||
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, plr->x, plr->y, plr->z, plr->instanceID, npc->appearanceData.iAngle);
|
NPCManager::updateNPCPosition(npc->id, plr->x, plr->y, plr->z, plr->instanceID, npc->angle);
|
||||||
|
|
||||||
// if we're in a lair, we need to spawn the NPC in both the private instance and the template
|
// if we're in a lair, we need to spawn the NPC in both the private instance and the template
|
||||||
if (PLAYERID(plr->instanceID) != 0) {
|
if (PLAYERID(plr->instanceID) != 0) {
|
||||||
npc = NPCManager::summonNPC(plr->x, plr->y, plr->z, plr->instanceID, type, true, true);
|
npc = NPCManager::summonNPC(plr->x, plr->y, plr->z, plr->instanceID, type, true, true);
|
||||||
|
|
||||||
npc->appearanceData.iAngle = (plr->angle + 180) % 360;
|
npc->angle = (plr->angle + 180) % 360;
|
||||||
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, plr->x, plr->y, plr->z, npc->instanceID, npc->appearanceData.iAngle);
|
NPCManager::updateNPCPosition(npc->id, plr->x, plr->y, plr->z, npc->instanceID, npc->angle);
|
||||||
}
|
}
|
||||||
|
|
||||||
Chat::sendServerMessage(sock, "/summonW: placed mob with type: " + std::to_string(type) +
|
Chat::sendServerMessage(sock, "/summonW: placed mob with type: " + std::to_string(type) +
|
||||||
", id: " + std::to_string(npc->appearanceData.iNPC_ID));
|
", id: " + std::to_string(npc->id));
|
||||||
TableData::RunningMobs[npc->appearanceData.iNPC_ID] = npc; // only record the one in the template
|
TableData::RunningMobs[npc->id] = npc; // only record the one in the template
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unsummonWCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
static void unsummonWCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
@ -269,21 +269,21 @@ static void unsummonWCommand(std::string full, std::vector<std::string>& args, C
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TableData::RunningEggs.find(npc->appearanceData.iNPC_ID) != TableData::RunningEggs.end()) {
|
if (TableData::RunningEggs.find(npc->id) != TableData::RunningEggs.end()) {
|
||||||
Chat::sendServerMessage(sock, "/unsummonW: removed egg with type: " + std::to_string(npc->appearanceData.iNPCType) +
|
Chat::sendServerMessage(sock, "/unsummonW: removed egg with type: " + std::to_string(npc->type) +
|
||||||
", id: " + std::to_string(npc->appearanceData.iNPC_ID));
|
", id: " + std::to_string(npc->id));
|
||||||
TableData::RunningEggs.erase(npc->appearanceData.iNPC_ID);
|
TableData::RunningEggs.erase(npc->id);
|
||||||
NPCManager::destroyNPC(npc->appearanceData.iNPC_ID);
|
NPCManager::destroyNPC(npc->id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TableData::RunningMobs.find(npc->appearanceData.iNPC_ID) == TableData::RunningMobs.end()
|
if (TableData::RunningMobs.find(npc->id) == TableData::RunningMobs.end()
|
||||||
&& TableData::RunningGroups.find(npc->appearanceData.iNPC_ID) == TableData::RunningGroups.end()) {
|
&& TableData::RunningGroups.find(npc->id) == TableData::RunningGroups.end()) {
|
||||||
Chat::sendServerMessage(sock, "/unsummonW: Closest NPC is not a gruntwork mob.");
|
Chat::sendServerMessage(sock, "/unsummonW: Closest NPC is not a gruntwork mob.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NPCManager::NPCs.find(npc->appearanceData.iNPC_ID) != NPCManager::NPCs.end() && NPCManager::NPCs[npc->appearanceData.iNPC_ID]->kind == EntityType::MOB) {
|
if (NPCManager::NPCs.find(npc->id) != NPCManager::NPCs.end() && NPCManager::NPCs[npc->id]->kind == EntityType::MOB) {
|
||||||
int leadId = ((Mob*)npc)->groupLeader;
|
int leadId = ((Mob*)npc)->groupLeader;
|
||||||
if (leadId != 0) {
|
if (leadId != 0) {
|
||||||
if (NPCManager::NPCs.find(leadId) == NPCManager::NPCs.end() || NPCManager::NPCs[leadId]->kind != EntityType::MOB) {
|
if (NPCManager::NPCs.find(leadId) == NPCManager::NPCs.end() || NPCManager::NPCs[leadId]->kind != EntityType::MOB) {
|
||||||
@ -308,12 +308,12 @@ static void unsummonWCommand(std::string full, std::vector<std::string>& args, C
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Chat::sendServerMessage(sock, "/unsummonW: removed mob with type: " + std::to_string(npc->appearanceData.iNPCType) +
|
Chat::sendServerMessage(sock, "/unsummonW: removed mob with type: " + std::to_string(npc->type) +
|
||||||
", id: " + std::to_string(npc->appearanceData.iNPC_ID));
|
", id: " + std::to_string(npc->id));
|
||||||
|
|
||||||
TableData::RunningMobs.erase(npc->appearanceData.iNPC_ID);
|
TableData::RunningMobs.erase(npc->id);
|
||||||
|
|
||||||
NPCManager::destroyNPC(npc->appearanceData.iNPC_ID);
|
NPCManager::destroyNPC(npc->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void toggleAiCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
static void toggleAiCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
@ -356,24 +356,24 @@ static void npcRotateCommand(std::string full, std::vector<std::string>& args, C
|
|||||||
}
|
}
|
||||||
|
|
||||||
int angle = (plr->angle + 180) % 360;
|
int angle = (plr->angle + 180) % 360;
|
||||||
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, npc->x, npc->y, npc->z, npc->instanceID, angle);
|
NPCManager::updateNPCPosition(npc->id, npc->x, npc->y, npc->z, npc->instanceID, angle);
|
||||||
|
|
||||||
// if it's a gruntwork NPC, rotate in-place
|
// if it's a gruntwork NPC, rotate in-place
|
||||||
if (TableData::RunningMobs.find(npc->appearanceData.iNPC_ID) != TableData::RunningMobs.end()) {
|
if (TableData::RunningMobs.find(npc->id) != TableData::RunningMobs.end()) {
|
||||||
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, npc->x, npc->y, npc->z, npc->instanceID, angle);
|
NPCManager::updateNPCPosition(npc->id, npc->x, npc->y, npc->z, npc->instanceID, angle);
|
||||||
|
|
||||||
Chat::sendServerMessage(sock, "[NPCR] Successfully set angle to " + std::to_string(angle) + " for gruntwork NPC "
|
Chat::sendServerMessage(sock, "[NPCR] Successfully set angle to " + std::to_string(angle) + " for gruntwork NPC "
|
||||||
+ std::to_string(npc->appearanceData.iNPC_ID));
|
+ std::to_string(npc->id));
|
||||||
} else {
|
} else {
|
||||||
TableData::RunningNPCRotations[npc->appearanceData.iNPC_ID] = angle;
|
TableData::RunningNPCRotations[npc->id] = angle;
|
||||||
|
|
||||||
Chat::sendServerMessage(sock, "[NPCR] Successfully set angle to " + std::to_string(angle) + " for NPC "
|
Chat::sendServerMessage(sock, "[NPCR] Successfully set angle to " + std::to_string(angle) + " for NPC "
|
||||||
+ std::to_string(npc->appearanceData.iNPC_ID));
|
+ std::to_string(npc->id));
|
||||||
}
|
}
|
||||||
|
|
||||||
// update rotation clientside
|
// update rotation clientside
|
||||||
INITSTRUCT(sP_FE2CL_NPC_ENTER, pkt);
|
INITSTRUCT(sP_FE2CL_NPC_ENTER, pkt);
|
||||||
pkt.NPCAppearanceData = npc->appearanceData;
|
pkt.NPCAppearanceData = npc->getAppearanceData();
|
||||||
sock->sendPacket(pkt, P_FE2CL_NPC_ENTER);
|
sock->sendPacket(pkt, P_FE2CL_NPC_ENTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -443,9 +443,9 @@ static void npcInstanceCommand(std::string full, std::vector<std::string>& args,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Chat::sendServerMessage(sock, "[NPCI] Moving NPC with ID " + std::to_string(npc->appearanceData.iNPC_ID) + " to instance " + std::to_string(instance));
|
Chat::sendServerMessage(sock, "[NPCI] Moving NPC with ID " + std::to_string(npc->id) + " to instance " + std::to_string(instance));
|
||||||
TableData::RunningNPCMapNumbers[npc->appearanceData.iNPC_ID] = instance;
|
TableData::RunningNPCMapNumbers[npc->id] = instance;
|
||||||
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, npc->x, npc->y, npc->z, instance, npc->appearanceData.iAngle);
|
NPCManager::updateNPCPosition(npc->id, npc->x, npc->y, npc->z, instance, npc->angle);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void minfoCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
static void minfoCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
@ -610,39 +610,39 @@ static void summonGroupCommand(std::string full, std::vector<std::string>& args,
|
|||||||
|
|
||||||
BaseNPC *npc = NPCManager::summonNPC(x, y, z, plr->instanceID, type, wCommand);
|
BaseNPC *npc = NPCManager::summonNPC(x, y, z, plr->instanceID, type, wCommand);
|
||||||
if (team == 2 && i > 0 && npc->kind == EntityType::MOB) {
|
if (team == 2 && i > 0 && npc->kind == EntityType::MOB) {
|
||||||
leadNpc->groupMember[i-1] = npc->appearanceData.iNPC_ID;
|
leadNpc->groupMember[i-1] = npc->id;
|
||||||
Mob* mob = (Mob*)NPCManager::NPCs[npc->appearanceData.iNPC_ID];
|
Mob* mob = (Mob*)NPCManager::NPCs[npc->id];
|
||||||
mob->groupLeader = leadNpc->appearanceData.iNPC_ID;
|
mob->groupLeader = leadNpc->id;
|
||||||
mob->offsetX = x - plr->x;
|
mob->offsetX = x - plr->x;
|
||||||
mob->offsetY = y - plr->y;
|
mob->offsetY = y - plr->y;
|
||||||
}
|
}
|
||||||
|
|
||||||
npc->appearanceData.iAngle = (plr->angle + 180) % 360;
|
npc->angle = (plr->angle + 180) % 360;
|
||||||
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, x, y, z, plr->instanceID, npc->appearanceData.iAngle);
|
NPCManager::updateNPCPosition(npc->id, x, y, z, plr->instanceID, npc->angle);
|
||||||
|
|
||||||
// if we're in a lair, we need to spawn the NPC in both the private instance and the template
|
// if we're in a lair, we need to spawn the NPC in both the private instance and the template
|
||||||
if (PLAYERID(plr->instanceID) != 0) {
|
if (PLAYERID(plr->instanceID) != 0) {
|
||||||
npc = NPCManager::summonNPC(plr->x, plr->y, plr->z, plr->instanceID, type, wCommand, true);
|
npc = NPCManager::summonNPC(plr->x, plr->y, plr->z, plr->instanceID, type, wCommand, true);
|
||||||
|
|
||||||
if (team == 2 && i > 0 && npc->kind == EntityType::MOB) {
|
if (team == 2 && i > 0 && npc->kind == EntityType::MOB) {
|
||||||
leadNpc->groupMember[i-1] = npc->appearanceData.iNPC_ID;
|
leadNpc->groupMember[i-1] = npc->id;
|
||||||
Mob* mob = (Mob*)NPCManager::NPCs[npc->appearanceData.iNPC_ID];
|
Mob* mob = (Mob*)NPCManager::NPCs[npc->id];
|
||||||
mob->groupLeader = leadNpc->appearanceData.iNPC_ID;
|
mob->groupLeader = leadNpc->id;
|
||||||
mob->offsetX = x - plr->x;
|
mob->offsetX = x - plr->x;
|
||||||
mob->offsetY = y - plr->y;
|
mob->offsetY = y - plr->y;
|
||||||
}
|
}
|
||||||
|
|
||||||
npc->appearanceData.iAngle = (plr->angle + 180) % 360;
|
npc->angle = (plr->angle + 180) % 360;
|
||||||
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, x, y, z, plr->instanceID, npc->appearanceData.iAngle);
|
NPCManager::updateNPCPosition(npc->id, x, y, z, plr->instanceID, npc->angle);
|
||||||
}
|
}
|
||||||
|
|
||||||
Chat::sendServerMessage(sock, "/summonGroup(W): placed mob with type: " + std::to_string(type) +
|
Chat::sendServerMessage(sock, "/summonGroup(W): placed mob with type: " + std::to_string(type) +
|
||||||
", id: " + std::to_string(npc->appearanceData.iNPC_ID));
|
", id: " + std::to_string(npc->id));
|
||||||
|
|
||||||
if (i == 0 && team == 2 && npc->kind == EntityType::MOB) {
|
if (i == 0 && team == 2 && npc->kind == EntityType::MOB) {
|
||||||
type = type2;
|
type = type2;
|
||||||
leadNpc = (Mob*)NPCManager::NPCs[npc->appearanceData.iNPC_ID];
|
leadNpc = (Mob*)NPCManager::NPCs[npc->id];
|
||||||
leadNpc->groupLeader = leadNpc->appearanceData.iNPC_ID;
|
leadNpc->groupLeader = leadNpc->id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -654,7 +654,7 @@ static void summonGroupCommand(std::string full, std::vector<std::string>& args,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TableData::RunningGroups[leadNpc->appearanceData.iNPC_ID] = leadNpc; // only record the leader
|
TableData::RunningGroups[leadNpc->id] = leadNpc; // only record the leader
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flushCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
static void flushCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
@ -671,15 +671,15 @@ static void whoisCommand(std::string full, std::vector<std::string>& args, CNSoc
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Chat::sendServerMessage(sock, "[WHOIS] ID: " + std::to_string(npc->appearanceData.iNPC_ID));
|
Chat::sendServerMessage(sock, "[WHOIS] ID: " + std::to_string(npc->id));
|
||||||
Chat::sendServerMessage(sock, "[WHOIS] Type: " + std::to_string(npc->appearanceData.iNPCType));
|
Chat::sendServerMessage(sock, "[WHOIS] Type: " + std::to_string(npc->type));
|
||||||
Chat::sendServerMessage(sock, "[WHOIS] HP: " + std::to_string(npc->appearanceData.iHP));
|
Chat::sendServerMessage(sock, "[WHOIS] HP: " + std::to_string(npc->hp));
|
||||||
Chat::sendServerMessage(sock, "[WHOIS] CBF: " + std::to_string(npc->appearanceData.iConditionBitFlag));
|
Chat::sendServerMessage(sock, "[WHOIS] CBF: " + std::to_string(npc->cbf));
|
||||||
Chat::sendServerMessage(sock, "[WHOIS] EntityType: " + std::to_string((int)npc->kind));
|
Chat::sendServerMessage(sock, "[WHOIS] EntityType: " + std::to_string((int)npc->kind));
|
||||||
Chat::sendServerMessage(sock, "[WHOIS] X: " + std::to_string(npc->x));
|
Chat::sendServerMessage(sock, "[WHOIS] X: " + std::to_string(npc->x));
|
||||||
Chat::sendServerMessage(sock, "[WHOIS] Y: " + std::to_string(npc->y));
|
Chat::sendServerMessage(sock, "[WHOIS] Y: " + std::to_string(npc->y));
|
||||||
Chat::sendServerMessage(sock, "[WHOIS] Z: " + std::to_string(npc->z));
|
Chat::sendServerMessage(sock, "[WHOIS] Z: " + std::to_string(npc->z));
|
||||||
Chat::sendServerMessage(sock, "[WHOIS] Angle: " + std::to_string(npc->appearanceData.iAngle));
|
Chat::sendServerMessage(sock, "[WHOIS] Angle: " + std::to_string(npc->angle));
|
||||||
std::string chunkPosition = std::to_string(std::get<0>(npc->chunkPos)) + ", " + std::to_string(std::get<1>(npc->chunkPos)) + ", " + std::to_string(std::get<2>(npc->chunkPos));
|
std::string chunkPosition = std::to_string(std::get<0>(npc->chunkPos)) + ", " + std::to_string(std::get<1>(npc->chunkPos)) + ", " + std::to_string(std::get<2>(npc->chunkPos));
|
||||||
Chat::sendServerMessage(sock, "[WHOIS] Chunk: {" + chunkPosition + "}");
|
Chat::sendServerMessage(sock, "[WHOIS] Chunk: {" + chunkPosition + "}");
|
||||||
Chat::sendServerMessage(sock, "[WHOIS] MapNum: " + std::to_string(MAPNUM(npc->instanceID)));
|
Chat::sendServerMessage(sock, "[WHOIS] MapNum: " + std::to_string(MAPNUM(npc->instanceID)));
|
||||||
@ -705,7 +705,7 @@ static void lairUnlockCommand(std::string full, std::vector<std::string>& args,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (auto it = NPCManager::Warps.begin(); it != NPCManager::Warps.end(); it++) {
|
for (auto it = NPCManager::Warps.begin(); it != NPCManager::Warps.end(); it++) {
|
||||||
if (it->second.npcID == npc->appearanceData.iNPCType) {
|
if (it->second.npcID == npc->type) {
|
||||||
taskID = it->second.limitTaskID;
|
taskID = it->second.limitTaskID;
|
||||||
missionID = Missions::Tasks[taskID]->task["m_iHMissionID"];
|
missionID = Missions::Tasks[taskID]->task["m_iHMissionID"];
|
||||||
lastDist = dist;
|
lastDist = dist;
|
||||||
@ -981,7 +981,7 @@ static void pathCommand(std::string full, std::vector<std::string>& args, CNSock
|
|||||||
pathPoints.push_back(marker);
|
pathPoints.push_back(marker);
|
||||||
// map from player
|
// map from player
|
||||||
TableData::RunningNPCPaths[plr->iID] = std::make_pair(npc, pathPoints);
|
TableData::RunningNPCPaths[plr->iID] = std::make_pair(npc, pathPoints);
|
||||||
Chat::sendServerMessage(sock, "[PATH] NPC " + std::to_string(npc->appearanceData.iNPC_ID) + " is now following you");
|
Chat::sendServerMessage(sock, "[PATH] NPC " + std::to_string(npc->id) + " is now following you");
|
||||||
updatePathMarkers(sock);
|
updatePathMarkers(sock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1008,8 +1008,8 @@ static void pathCommand(std::string full, std::vector<std::string>& args, CNSock
|
|||||||
// /path here
|
// /path here
|
||||||
if (args[1] == "here") {
|
if (args[1] == "here") {
|
||||||
// bring the NPC to where the player is standing
|
// bring the NPC to where the player is standing
|
||||||
Transport::NPCQueues.erase(npc->appearanceData.iNPC_ID); // delete transport queue
|
Transport::NPCQueues.erase(npc->id); // delete transport queue
|
||||||
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, plr->x, plr->y, plr->z, npc->instanceID, 0);
|
NPCManager::updateNPCPosition(npc->id, plr->x, plr->y, plr->z, npc->instanceID, 0);
|
||||||
npc->disappearFromViewOf(sock);
|
npc->disappearFromViewOf(sock);
|
||||||
npc->enterIntoViewOf(sock);
|
npc->enterIntoViewOf(sock);
|
||||||
Chat::sendServerMessage(sock, "[PATH] Come here");
|
Chat::sendServerMessage(sock, "[PATH] Come here");
|
||||||
@ -1047,9 +1047,9 @@ static void pathCommand(std::string full, std::vector<std::string>& args, CNSock
|
|||||||
speed = speedArg;
|
speed = speedArg;
|
||||||
}
|
}
|
||||||
// return NPC to home
|
// return NPC to home
|
||||||
Transport::NPCQueues.erase(npc->appearanceData.iNPC_ID); // delete transport queue
|
Transport::NPCQueues.erase(npc->id); // delete transport queue
|
||||||
BaseNPC* home = entry->second[0];
|
BaseNPC* home = entry->second[0];
|
||||||
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, home->x, home->y, home->z, npc->instanceID, 0);
|
NPCManager::updateNPCPosition(npc->id, home->x, home->y, home->z, npc->instanceID, 0);
|
||||||
npc->disappearFromViewOf(sock);
|
npc->disappearFromViewOf(sock);
|
||||||
npc->enterIntoViewOf(sock);
|
npc->enterIntoViewOf(sock);
|
||||||
|
|
||||||
@ -1065,7 +1065,7 @@ static void pathCommand(std::string full, std::vector<std::string>& args, CNSock
|
|||||||
Transport::lerp(&keyframes, from, to, speed); // lerp from A to B
|
Transport::lerp(&keyframes, from, to, speed); // lerp from A to B
|
||||||
from = to; // update point A
|
from = to; // update point A
|
||||||
}
|
}
|
||||||
Transport::NPCQueues[npc->appearanceData.iNPC_ID] = keyframes;
|
Transport::NPCQueues[npc->id] = keyframes;
|
||||||
entry->second.pop_back(); // remove temp end point
|
entry->second.pop_back(); // remove temp end point
|
||||||
|
|
||||||
Chat::sendServerMessage(sock, "[PATH] Testing NPC path");
|
Chat::sendServerMessage(sock, "[PATH] Testing NPC path");
|
||||||
@ -1075,9 +1075,9 @@ static void pathCommand(std::string full, std::vector<std::string>& args, CNSock
|
|||||||
// /path cancel
|
// /path cancel
|
||||||
if (args[1] == "cancel") {
|
if (args[1] == "cancel") {
|
||||||
// return NPC to home
|
// return NPC to home
|
||||||
Transport::NPCQueues.erase(npc->appearanceData.iNPC_ID); // delete transport queue
|
Transport::NPCQueues.erase(npc->id); // delete transport queue
|
||||||
BaseNPC* home = entry->second[0];
|
BaseNPC* home = entry->second[0];
|
||||||
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, home->x, home->y, home->z, npc->instanceID, 0);
|
NPCManager::updateNPCPosition(npc->id, home->x, home->y, home->z, npc->instanceID, 0);
|
||||||
npc->disappearFromViewOf(sock);
|
npc->disappearFromViewOf(sock);
|
||||||
npc->enterIntoViewOf(sock);
|
npc->enterIntoViewOf(sock);
|
||||||
// deallocate markers
|
// deallocate markers
|
||||||
@ -1087,7 +1087,7 @@ static void pathCommand(std::string full, std::vector<std::string>& args, CNSock
|
|||||||
}
|
}
|
||||||
// unmap
|
// unmap
|
||||||
TableData::RunningNPCPaths.erase(plr->iID);
|
TableData::RunningNPCPaths.erase(plr->iID);
|
||||||
Chat::sendServerMessage(sock, "[PATH] NPC " + std::to_string(npc->appearanceData.iNPC_ID) + " is no longer following you");
|
Chat::sendServerMessage(sock, "[PATH] NPC " + std::to_string(npc->id) + " is no longer following you");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1115,9 +1115,9 @@ static void pathCommand(std::string full, std::vector<std::string>& args, CNSock
|
|||||||
}
|
}
|
||||||
|
|
||||||
// return NPC to home and set path to repeat
|
// return NPC to home and set path to repeat
|
||||||
Transport::NPCQueues.erase(npc->appearanceData.iNPC_ID); // delete transport queue
|
Transport::NPCQueues.erase(npc->id); // delete transport queue
|
||||||
BaseNPC* home = entry->second[0];
|
BaseNPC* home = entry->second[0];
|
||||||
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, home->x, home->y, home->z, npc->instanceID, 0);
|
NPCManager::updateNPCPosition(npc->id, home->x, home->y, home->z, npc->instanceID, 0);
|
||||||
npc->disappearFromViewOf(sock);
|
npc->disappearFromViewOf(sock);
|
||||||
npc->enterIntoViewOf(sock);
|
npc->enterIntoViewOf(sock);
|
||||||
npc->loopingPath = true;
|
npc->loopingPath = true;
|
||||||
@ -1134,7 +1134,7 @@ static void pathCommand(std::string full, std::vector<std::string>& args, CNSock
|
|||||||
Transport::lerp(&keyframes, from, to, speed); // lerp from A to B
|
Transport::lerp(&keyframes, from, to, speed); // lerp from A to B
|
||||||
from = to; // update point A
|
from = to; // update point A
|
||||||
}
|
}
|
||||||
Transport::NPCQueues[npc->appearanceData.iNPC_ID] = keyframes;
|
Transport::NPCQueues[npc->id] = keyframes;
|
||||||
entry->second.pop_back(); // remove temp end point
|
entry->second.pop_back(); // remove temp end point
|
||||||
|
|
||||||
// save to gruntwork
|
// save to gruntwork
|
||||||
@ -1161,7 +1161,7 @@ static void pathCommand(std::string full, std::vector<std::string>& args, CNSock
|
|||||||
finishedPath.isLoop = true;
|
finishedPath.isLoop = true;
|
||||||
finishedPath.speed = speed;
|
finishedPath.speed = speed;
|
||||||
finishedPath.points = finalPoints;
|
finishedPath.points = finalPoints;
|
||||||
finishedPath.targetIDs.push_back(npc->appearanceData.iNPC_ID);
|
finishedPath.targetIDs.push_back(npc->id);
|
||||||
|
|
||||||
TableData::FinishedNPCPaths.push_back(finishedPath);
|
TableData::FinishedNPCPaths.push_back(finishedPath);
|
||||||
|
|
||||||
@ -1173,7 +1173,7 @@ static void pathCommand(std::string full, std::vector<std::string>& args, CNSock
|
|||||||
// unmap
|
// unmap
|
||||||
TableData::RunningNPCPaths.erase(plr->iID);
|
TableData::RunningNPCPaths.erase(plr->iID);
|
||||||
|
|
||||||
Chat::sendServerMessage(sock, "[PATH] NPC " + std::to_string(npc->appearanceData.iNPC_ID) + " is no longer following you");
|
Chat::sendServerMessage(sock, "[PATH] NPC " + std::to_string(npc->id) + " is no longer following you");
|
||||||
|
|
||||||
TableData::flush();
|
TableData::flush();
|
||||||
Chat::sendServerMessage(sock, "[PATH] Path saved to gruntwork");
|
Chat::sendServerMessage(sock, "[PATH] Path saved to gruntwork");
|
||||||
|
@ -135,7 +135,7 @@ static void eggStep(CNServer* serv, time_t currTime) {
|
|||||||
// respawn it
|
// respawn it
|
||||||
egg->dead = false;
|
egg->dead = false;
|
||||||
egg->deadUntil = 0;
|
egg->deadUntil = 0;
|
||||||
egg->appearanceData.iHP = 400;
|
egg->hp = 400;
|
||||||
|
|
||||||
Chunking::addEntityToChunks(Chunking::getViewableChunks(egg->chunkPos), {npc.first});
|
Chunking::addEntityToChunks(Chunking::getViewableChunks(egg->chunkPos), {npc.first});
|
||||||
}
|
}
|
||||||
@ -180,7 +180,7 @@ static void eggPickup(CNSocket* sock, CNPacketData* data) {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int typeId = egg->appearanceData.iNPCType;
|
int typeId = egg->type;
|
||||||
if (EggTypes.find(typeId) == EggTypes.end()) {
|
if (EggTypes.find(typeId) == EggTypes.end()) {
|
||||||
std::cout << "[WARN] Egg Type " << typeId << " not found!" << std::endl;
|
std::cout << "[WARN] Egg Type " << typeId << " not found!" << std::endl;
|
||||||
return;
|
return;
|
||||||
@ -255,7 +255,7 @@ static void eggPickup(CNSocket* sock, CNPacketData* data) {
|
|||||||
Chunking::removeEntityFromChunks(Chunking::getViewableChunks(egg->chunkPos), eggRef);
|
Chunking::removeEntityFromChunks(Chunking::getViewableChunks(egg->chunkPos), eggRef);
|
||||||
egg->dead = true;
|
egg->dead = true;
|
||||||
egg->deadUntil = getTime() + (time_t)type->regen * 1000;
|
egg->deadUntil = getTime() + (time_t)type->regen * 1000;
|
||||||
egg->appearanceData.iHP = 0;
|
egg->hp = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,15 +39,26 @@ Entity *EntityRef::getEntity() const {
|
|||||||
return NPCManager::NPCs[id];
|
return NPCManager::NPCs[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sNPCAppearanceData BaseNPC::getAppearanceData() {
|
||||||
|
sNPCAppearanceData data = {};
|
||||||
|
data.iAngle = angle;
|
||||||
|
data.iBarkerType = barkerType;
|
||||||
|
data.iConditionBitFlag = cbf;
|
||||||
|
data.iHP = hp;
|
||||||
|
data.iNPCType = type;
|
||||||
|
data.iNPC_ID = id;
|
||||||
|
data.iX = x;
|
||||||
|
data.iY = y;
|
||||||
|
data.iZ = z;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Entity coming into view.
|
* Entity coming into view.
|
||||||
*/
|
*/
|
||||||
void BaseNPC::enterIntoViewOf(CNSocket *sock) {
|
void BaseNPC::enterIntoViewOf(CNSocket *sock) {
|
||||||
INITSTRUCT(sP_FE2CL_NPC_ENTER, pkt);
|
INITSTRUCT(sP_FE2CL_NPC_ENTER, pkt);
|
||||||
pkt.NPCAppearanceData = appearanceData;
|
pkt.NPCAppearanceData = getAppearanceData();
|
||||||
pkt.NPCAppearanceData.iX = x;
|
|
||||||
pkt.NPCAppearanceData.iY = y;
|
|
||||||
pkt.NPCAppearanceData.iZ = z;
|
|
||||||
sock->sendPacket(pkt, P_FE2CL_NPC_ENTER);
|
sock->sendPacket(pkt, P_FE2CL_NPC_ENTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +67,7 @@ void Bus::enterIntoViewOf(CNSocket *sock) {
|
|||||||
|
|
||||||
// TODO: Potentially decouple this from BaseNPC?
|
// TODO: Potentially decouple this from BaseNPC?
|
||||||
pkt.AppearanceData = {
|
pkt.AppearanceData = {
|
||||||
3, appearanceData.iNPC_ID, appearanceData.iNPCType,
|
3, id, type,
|
||||||
x, y, z
|
x, y, z
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -66,28 +77,36 @@ void Bus::enterIntoViewOf(CNSocket *sock) {
|
|||||||
void Egg::enterIntoViewOf(CNSocket *sock) {
|
void Egg::enterIntoViewOf(CNSocket *sock) {
|
||||||
INITSTRUCT(sP_FE2CL_SHINY_ENTER, pkt);
|
INITSTRUCT(sP_FE2CL_SHINY_ENTER, pkt);
|
||||||
|
|
||||||
Eggs::npcDataToEggData(x, y, z, &appearanceData, &pkt.ShinyAppearanceData);
|
// TODO: Potentially decouple this from BaseNPC?
|
||||||
|
pkt.ShinyAppearanceData = {
|
||||||
|
id, type, 0, // client doesn't care about map num
|
||||||
|
x, y, z
|
||||||
|
};
|
||||||
|
|
||||||
sock->sendPacket(pkt, P_FE2CL_SHINY_ENTER);
|
sock->sendPacket(pkt, P_FE2CL_SHINY_ENTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sPCAppearanceData Player::getAppearanceData() {
|
||||||
|
sPCAppearanceData data = {};
|
||||||
|
data.iID = iID;
|
||||||
|
data.iHP = HP;
|
||||||
|
data.iLv = level;
|
||||||
|
data.iX = x;
|
||||||
|
data.iY = y;
|
||||||
|
data.iZ = z;
|
||||||
|
data.iAngle = angle;
|
||||||
|
data.PCStyle = PCStyle;
|
||||||
|
data.Nano = Nanos[activeNano];
|
||||||
|
data.iPCState = iPCState;
|
||||||
|
data.iSpecialState = iSpecialState;
|
||||||
|
memcpy(data.ItemEquip, Equip, sizeof(sItemBase) * AEQUIP_COUNT);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: this is less effiecient than it was, because of memset()
|
// TODO: this is less effiecient than it was, because of memset()
|
||||||
void Player::enterIntoViewOf(CNSocket *sock) {
|
void Player::enterIntoViewOf(CNSocket *sock) {
|
||||||
INITSTRUCT(sP_FE2CL_PC_NEW, pkt);
|
INITSTRUCT(sP_FE2CL_PC_NEW, pkt);
|
||||||
|
pkt.PCAppearanceData = getAppearanceData();
|
||||||
pkt.PCAppearanceData.iID = iID;
|
|
||||||
pkt.PCAppearanceData.iHP = HP;
|
|
||||||
pkt.PCAppearanceData.iLv = level;
|
|
||||||
pkt.PCAppearanceData.iX = x;
|
|
||||||
pkt.PCAppearanceData.iY = y;
|
|
||||||
pkt.PCAppearanceData.iZ = z;
|
|
||||||
pkt.PCAppearanceData.iAngle = angle;
|
|
||||||
pkt.PCAppearanceData.PCStyle = PCStyle;
|
|
||||||
pkt.PCAppearanceData.Nano = Nanos[activeNano];
|
|
||||||
pkt.PCAppearanceData.iPCState = iPCState;
|
|
||||||
pkt.PCAppearanceData.iSpecialState = iSpecialState;
|
|
||||||
memcpy(pkt.PCAppearanceData.ItemEquip, Equip, sizeof(sItemBase) * AEQUIP_COUNT);
|
|
||||||
|
|
||||||
sock->sendPacket(pkt, P_FE2CL_PC_NEW);
|
sock->sendPacket(pkt, P_FE2CL_PC_NEW);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,20 +115,20 @@ void Player::enterIntoViewOf(CNSocket *sock) {
|
|||||||
*/
|
*/
|
||||||
void BaseNPC::disappearFromViewOf(CNSocket *sock) {
|
void BaseNPC::disappearFromViewOf(CNSocket *sock) {
|
||||||
INITSTRUCT(sP_FE2CL_NPC_EXIT, pkt);
|
INITSTRUCT(sP_FE2CL_NPC_EXIT, pkt);
|
||||||
pkt.iNPC_ID = appearanceData.iNPC_ID;
|
pkt.iNPC_ID = id;
|
||||||
sock->sendPacket(pkt, P_FE2CL_NPC_EXIT);
|
sock->sendPacket(pkt, P_FE2CL_NPC_EXIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bus::disappearFromViewOf(CNSocket *sock) {
|
void Bus::disappearFromViewOf(CNSocket *sock) {
|
||||||
INITSTRUCT(sP_FE2CL_TRANSPORTATION_EXIT, pkt);
|
INITSTRUCT(sP_FE2CL_TRANSPORTATION_EXIT, pkt);
|
||||||
pkt.eTT = 3;
|
pkt.eTT = 3;
|
||||||
pkt.iT_ID = appearanceData.iNPC_ID;
|
pkt.iT_ID = id;
|
||||||
sock->sendPacket(pkt, P_FE2CL_TRANSPORTATION_EXIT);
|
sock->sendPacket(pkt, P_FE2CL_TRANSPORTATION_EXIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Egg::disappearFromViewOf(CNSocket *sock) {
|
void Egg::disappearFromViewOf(CNSocket *sock) {
|
||||||
INITSTRUCT(sP_FE2CL_SHINY_EXIT, pkt);
|
INITSTRUCT(sP_FE2CL_SHINY_EXIT, pkt);
|
||||||
pkt.iShinyID = appearanceData.iNPC_ID;
|
pkt.iShinyID = id;
|
||||||
sock->sendPacket(pkt, P_FE2CL_SHINY_EXIT);
|
sock->sendPacket(pkt, P_FE2CL_SHINY_EXIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,25 +74,31 @@ struct EntityRef {
|
|||||||
*/
|
*/
|
||||||
class BaseNPC : public Entity {
|
class BaseNPC : public Entity {
|
||||||
public:
|
public:
|
||||||
sNPCAppearanceData appearanceData = {};
|
int id;
|
||||||
|
int type;
|
||||||
|
int hp;
|
||||||
|
int angle;
|
||||||
|
int cbf;
|
||||||
|
int barkerType;
|
||||||
bool loopingPath = false;
|
bool loopingPath = false;
|
||||||
|
|
||||||
BaseNPC(int _X, int _Y, int _Z, int angle, uint64_t iID, int t, int id) { // XXX
|
BaseNPC(int _X, int _Y, int _Z, int _A, uint64_t iID, int t, int _id) { // XXX
|
||||||
x = _X;
|
x = _X;
|
||||||
y = _Y;
|
y = _Y;
|
||||||
z = _Z;
|
z = _Z;
|
||||||
appearanceData.iNPCType = t;
|
type = t;
|
||||||
appearanceData.iHP = 400;
|
hp = 400;
|
||||||
appearanceData.iAngle = angle;
|
angle = _A;
|
||||||
appearanceData.iConditionBitFlag = 0;
|
cbf = 0;
|
||||||
appearanceData.iBarkerType = 0;
|
barkerType = 0;
|
||||||
appearanceData.iNPC_ID = id;
|
id = _id;
|
||||||
|
|
||||||
instanceID = iID;
|
instanceID = iID;
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual void enterIntoViewOf(CNSocket *sock) override;
|
virtual void enterIntoViewOf(CNSocket *sock) override;
|
||||||
virtual void disappearFromViewOf(CNSocket *sock) override;
|
virtual void disappearFromViewOf(CNSocket *sock) override;
|
||||||
|
|
||||||
|
sNPCAppearanceData getAppearanceData();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CombatNPC : public BaseNPC {
|
struct CombatNPC : public BaseNPC {
|
||||||
@ -115,7 +121,7 @@ struct CombatNPC : public BaseNPC {
|
|||||||
_stepAI(this, currTime);
|
_stepAI(this, currTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool isAlive() override { return appearanceData.iHP > 0; }
|
virtual bool isAlive() override { return hp > 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Mob is in MobAI.hpp, Player is in Player.hpp
|
// Mob is in MobAI.hpp, Player is in Player.hpp
|
||||||
|
@ -822,12 +822,12 @@ static void giveSingleDrop(CNSocket *sock, Mob* mob, int mobDropId, const DropRo
|
|||||||
|
|
||||||
void Items::giveMobDrop(CNSocket *sock, Mob* mob, const DropRoll& rolled, const DropRoll& eventRolled) {
|
void Items::giveMobDrop(CNSocket *sock, Mob* mob, const DropRoll& rolled, const DropRoll& eventRolled) {
|
||||||
// sanity check
|
// sanity check
|
||||||
if (Items::MobToDropMap.find(mob->appearanceData.iNPCType) == Items::MobToDropMap.end()) {
|
if (Items::MobToDropMap.find(mob->type) == Items::MobToDropMap.end()) {
|
||||||
std::cout << "[WARN] Mob ID " << mob->appearanceData.iNPCType << " has no drops assigned" << std::endl;
|
std::cout << "[WARN] Mob ID " << mob->type << " has no drops assigned" << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// find mob drop id
|
// find mob drop id
|
||||||
int mobDropId = Items::MobToDropMap[mob->appearanceData.iNPCType];
|
int mobDropId = Items::MobToDropMap[mob->type];
|
||||||
|
|
||||||
giveSingleDrop(sock, mob, mobDropId, rolled);
|
giveSingleDrop(sock, mob, mobDropId, rolled);
|
||||||
|
|
||||||
|
@ -373,9 +373,9 @@ static void taskStart(CNSocket* sock, CNPacketData* data) {
|
|||||||
for (EntityRef ref : chunk->entities) {
|
for (EntityRef ref : chunk->entities) {
|
||||||
if (ref.type != EntityType::PLAYER) {
|
if (ref.type != EntityType::PLAYER) {
|
||||||
BaseNPC* npc = (BaseNPC*)ref.getEntity();
|
BaseNPC* npc = (BaseNPC*)ref.getEntity();
|
||||||
NPCPath* path = Transport::findApplicablePath(npc->appearanceData.iNPC_ID, npc->appearanceData.iNPCType, missionData->iTaskNum);
|
NPCPath* path = Transport::findApplicablePath(npc->id, npc->type, missionData->iTaskNum);
|
||||||
if (path != nullptr) {
|
if (path != nullptr) {
|
||||||
Transport::constructPathNPC(npc->appearanceData.iNPC_ID, path);
|
Transport::constructPathNPC(npc->id, path);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,13 +47,13 @@ static std::pair<int,int> lerp(int x1, int y1, int x2, int y2, int speed) {
|
|||||||
|
|
||||||
void MobAI::clearDebuff(Mob *mob) {
|
void MobAI::clearDebuff(Mob *mob) {
|
||||||
mob->skillStyle = -1;
|
mob->skillStyle = -1;
|
||||||
mob->appearanceData.iConditionBitFlag = 0;
|
mob->cbf = 0;
|
||||||
mob->unbuffTimes.clear();
|
mob->unbuffTimes.clear();
|
||||||
|
|
||||||
INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, pkt1);
|
INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, pkt1);
|
||||||
pkt1.eCT = 2;
|
pkt1.eCT = 2;
|
||||||
pkt1.iID = mob->appearanceData.iNPC_ID;
|
pkt1.iID = mob->id;
|
||||||
pkt1.iConditionBitFlag = mob->appearanceData.iConditionBitFlag;
|
pkt1.iConditionBitFlag = mob->cbf;
|
||||||
NPCManager::sendToViewable(mob, &pkt1, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT, sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT));
|
NPCManager::sendToViewable(mob, &pkt1, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT, sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,7 +196,7 @@ static void dealCorruption(Mob *mob, std::vector<int> targetData, int skillID, i
|
|||||||
sP_FE2CL_NPC_SKILL_CORRUPTION_HIT *resp = (sP_FE2CL_NPC_SKILL_CORRUPTION_HIT*)respbuf;
|
sP_FE2CL_NPC_SKILL_CORRUPTION_HIT *resp = (sP_FE2CL_NPC_SKILL_CORRUPTION_HIT*)respbuf;
|
||||||
sCAttackResult *respdata = (sCAttackResult*)(respbuf+sizeof(sP_FE2CL_NPC_SKILL_CORRUPTION_HIT));
|
sCAttackResult *respdata = (sCAttackResult*)(respbuf+sizeof(sP_FE2CL_NPC_SKILL_CORRUPTION_HIT));
|
||||||
|
|
||||||
resp->iNPC_ID = mob->appearanceData.iNPC_ID;
|
resp->iNPC_ID = mob->id;
|
||||||
resp->iSkillID = skillID;
|
resp->iSkillID = skillID;
|
||||||
resp->iStyle = style;
|
resp->iStyle = style;
|
||||||
resp->iValue1 = plr->x;
|
resp->iValue1 = plr->x;
|
||||||
@ -247,7 +247,7 @@ static void dealCorruption(Mob *mob, std::vector<int> targetData, int skillID, i
|
|||||||
if (plr->Nanos[plr->activeNano].iStamina > 150)
|
if (plr->Nanos[plr->activeNano].iStamina > 150)
|
||||||
respdata[i].iNanoStamina = plr->Nanos[plr->activeNano].iStamina = 150;
|
respdata[i].iNanoStamina = plr->Nanos[plr->activeNano].iStamina = 150;
|
||||||
// fire damage power disguised as a corruption attack back at the enemy
|
// fire damage power disguised as a corruption attack back at the enemy
|
||||||
std::vector<int> targetData2 = {1, mob->appearanceData.iNPC_ID, 0, 0, 0};
|
std::vector<int> targetData2 = {1, mob->id, 0, 0, 0};
|
||||||
for (auto& pwr : Abilities::Powers)
|
for (auto& pwr : Abilities::Powers)
|
||||||
if (pwr.skillType == EST_DAMAGE)
|
if (pwr.skillType == EST_DAMAGE)
|
||||||
pwr.handle(sock, targetData2, plr->activeNano, skillID, 0, 200);
|
pwr.handle(sock, targetData2, plr->activeNano, skillID, 0, 200);
|
||||||
@ -362,7 +362,7 @@ static void useAbilities(Mob *mob, time_t currTime) {
|
|||||||
if (random < prob1 + prob2) { // corruption windup
|
if (random < prob1 + prob2) { // corruption windup
|
||||||
int skillID = (int)mob->data["m_iCorruptionType"];
|
int skillID = (int)mob->data["m_iCorruptionType"];
|
||||||
INITSTRUCT(sP_FE2CL_NPC_SKILL_CORRUPTION_READY, pkt);
|
INITSTRUCT(sP_FE2CL_NPC_SKILL_CORRUPTION_READY, pkt);
|
||||||
pkt.iNPC_ID = mob->appearanceData.iNPC_ID;
|
pkt.iNPC_ID = mob->id;
|
||||||
pkt.iSkillID = skillID;
|
pkt.iSkillID = skillID;
|
||||||
pkt.iValue1 = plr->x;
|
pkt.iValue1 = plr->x;
|
||||||
pkt.iValue2 = plr->y;
|
pkt.iValue2 = plr->y;
|
||||||
@ -381,7 +381,7 @@ static void useAbilities(Mob *mob, time_t currTime) {
|
|||||||
if (random < prob1 + prob2 + prob3) { // eruption windup
|
if (random < prob1 + prob2 + prob3) { // eruption windup
|
||||||
int skillID = (int)mob->data["m_iMegaType"];
|
int skillID = (int)mob->data["m_iMegaType"];
|
||||||
INITSTRUCT(sP_FE2CL_NPC_SKILL_READY, pkt);
|
INITSTRUCT(sP_FE2CL_NPC_SKILL_READY, pkt);
|
||||||
pkt.iNPC_ID = mob->appearanceData.iNPC_ID;
|
pkt.iNPC_ID = mob->id;
|
||||||
pkt.iSkillID = skillID;
|
pkt.iSkillID = skillID;
|
||||||
pkt.iValue1 = mob->hitX = plr->x;
|
pkt.iValue1 = mob->hitX = plr->x;
|
||||||
pkt.iValue2 = mob->hitY = plr->y;
|
pkt.iValue2 = mob->hitY = plr->y;
|
||||||
@ -406,13 +406,13 @@ void MobAI::enterCombat(CNSocket *sock, Mob *mob) {
|
|||||||
mob->roamZ = mob->z;
|
mob->roamZ = mob->z;
|
||||||
|
|
||||||
int skillID = (int)mob->data["m_iPassiveBuff"]; // cast passive
|
int skillID = (int)mob->data["m_iPassiveBuff"]; // cast passive
|
||||||
std::vector<int> targetData = {1, mob->appearanceData.iNPC_ID, 0, 0, 0};
|
std::vector<int> targetData = {1, mob->id, 0, 0, 0};
|
||||||
for (auto& pwr : Abilities::Powers)
|
for (auto& pwr : Abilities::Powers)
|
||||||
if (pwr.skillType == Abilities::SkillTable[skillID].skillType)
|
if (pwr.skillType == Abilities::SkillTable[skillID].skillType)
|
||||||
pwr.handle(mob, targetData, skillID, Abilities::SkillTable[skillID].durationTime[0], Abilities::SkillTable[skillID].powerIntensity[0]);
|
pwr.handle(mob, targetData, skillID, Abilities::SkillTable[skillID].durationTime[0], Abilities::SkillTable[skillID].powerIntensity[0]);
|
||||||
|
|
||||||
for (NPCEvent& event : NPCManager::NPCEvents) // trigger an ON_COMBAT
|
for (NPCEvent& event : NPCManager::NPCEvents) // trigger an ON_COMBAT
|
||||||
if (event.trigger == ON_COMBAT && event.npcType == mob->appearanceData.iNPCType)
|
if (event.trigger == ON_COMBAT && event.npcType == mob->type)
|
||||||
event.handler(sock, mob);
|
event.handler(sock, mob);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -426,18 +426,18 @@ static void drainMobHP(Mob *mob, int amount) {
|
|||||||
sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK *pkt = (sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK*)respbuf;
|
sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK *pkt = (sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK*)respbuf;
|
||||||
sSkillResult_Damage *drain = (sSkillResult_Damage*)(respbuf + sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK));
|
sSkillResult_Damage *drain = (sSkillResult_Damage*)(respbuf + sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK));
|
||||||
|
|
||||||
pkt->iID = mob->appearanceData.iNPC_ID;
|
pkt->iID = mob->id;
|
||||||
pkt->eCT = 4; // mob
|
pkt->eCT = 4; // mob
|
||||||
pkt->iTB_ID = ECSB_BOUNDINGBALL;
|
pkt->iTB_ID = ECSB_BOUNDINGBALL;
|
||||||
|
|
||||||
drain->eCT = 4;
|
drain->eCT = 4;
|
||||||
drain->iID = mob->appearanceData.iNPC_ID;
|
drain->iID = mob->id;
|
||||||
drain->iDamage = amount;
|
drain->iDamage = amount;
|
||||||
drain->iHP = mob->appearanceData.iHP -= amount;
|
drain->iHP = mob->hp -= amount;
|
||||||
|
|
||||||
NPCManager::sendToViewable(mob, (void*)&respbuf, P_FE2CL_CHAR_TIME_BUFF_TIME_TICK, resplen);
|
NPCManager::sendToViewable(mob, (void*)&respbuf, P_FE2CL_CHAR_TIME_BUFF_TIME_TICK, resplen);
|
||||||
|
|
||||||
if (mob->appearanceData.iHP <= 0)
|
if (mob->hp <= 0)
|
||||||
Combat::killMob(mob->target, mob);
|
Combat::killMob(mob->target, mob);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -448,14 +448,14 @@ static void deadStep(Mob *mob, time_t currTime) {
|
|||||||
|
|
||||||
INITSTRUCT(sP_FE2CL_NPC_EXIT, pkt);
|
INITSTRUCT(sP_FE2CL_NPC_EXIT, pkt);
|
||||||
|
|
||||||
pkt.iNPC_ID = mob->appearanceData.iNPC_ID;
|
pkt.iNPC_ID = mob->id;
|
||||||
|
|
||||||
NPCManager::sendToViewable(mob, &pkt, P_FE2CL_NPC_EXIT, sizeof(sP_FE2CL_NPC_EXIT));
|
NPCManager::sendToViewable(mob, &pkt, P_FE2CL_NPC_EXIT, sizeof(sP_FE2CL_NPC_EXIT));
|
||||||
|
|
||||||
// if it was summoned, mark it for removal
|
// if it was summoned, mark it for removal
|
||||||
if (mob->summoned) {
|
if (mob->summoned) {
|
||||||
std::cout << "[INFO] Queueing killed summoned mob for removal" << std::endl;
|
std::cout << "[INFO] Queueing killed summoned mob for removal" << std::endl;
|
||||||
NPCManager::queueNPCRemoval(mob->appearanceData.iNPC_ID);
|
NPCManager::queueNPCRemoval(mob->id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -466,15 +466,15 @@ static void deadStep(Mob *mob, time_t currTime) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// to guide their groupmates, group leaders still need to move despite being dead
|
// to guide their groupmates, group leaders still need to move despite being dead
|
||||||
if (mob->groupLeader == mob->appearanceData.iNPC_ID)
|
if (mob->groupLeader == mob->id)
|
||||||
roamingStep(mob, currTime);
|
roamingStep(mob, currTime);
|
||||||
|
|
||||||
if (mob->killedTime != 0 && currTime - mob->killedTime < mob->regenTime * 100)
|
if (mob->killedTime != 0 && currTime - mob->killedTime < mob->regenTime * 100)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::cout << "respawning mob " << mob->appearanceData.iNPC_ID << " with HP = " << mob->maxHealth << std::endl;
|
std::cout << "respawning mob " << mob->id << " with HP = " << mob->maxHealth << std::endl;
|
||||||
|
|
||||||
mob->appearanceData.iHP = mob->maxHealth;
|
mob->hp = mob->maxHealth;
|
||||||
mob->state = MobState::ROAMING;
|
mob->state = MobState::ROAMING;
|
||||||
|
|
||||||
// if mob is a group leader/follower, spawn where the group is.
|
// if mob is a group leader/follower, spawn where the group is.
|
||||||
@ -491,10 +491,7 @@ static void deadStep(Mob *mob, time_t currTime) {
|
|||||||
|
|
||||||
INITSTRUCT(sP_FE2CL_NPC_NEW, pkt);
|
INITSTRUCT(sP_FE2CL_NPC_NEW, pkt);
|
||||||
|
|
||||||
pkt.NPCAppearanceData = mob->appearanceData;
|
pkt.NPCAppearanceData = mob->getAppearanceData();
|
||||||
pkt.NPCAppearanceData.iX = mob->x;
|
|
||||||
pkt.NPCAppearanceData.iY = mob->y;
|
|
||||||
pkt.NPCAppearanceData.iZ = mob->z;
|
|
||||||
|
|
||||||
// notify all nearby players
|
// notify all nearby players
|
||||||
NPCManager::sendToViewable(mob, &pkt, P_FE2CL_NPC_NEW, sizeof(sP_FE2CL_NPC_NEW));
|
NPCManager::sendToViewable(mob, &pkt, P_FE2CL_NPC_NEW, sizeof(sP_FE2CL_NPC_NEW));
|
||||||
@ -532,13 +529,13 @@ static void combatStep(Mob *mob, time_t currTime) {
|
|||||||
|
|
||||||
// drain
|
// drain
|
||||||
if (mob->skillStyle < 0 && (mob->lastDrainTime == 0 || currTime - mob->lastDrainTime >= 1000)
|
if (mob->skillStyle < 0 && (mob->lastDrainTime == 0 || currTime - mob->lastDrainTime >= 1000)
|
||||||
&& mob->appearanceData.iConditionBitFlag & CSB_BIT_BOUNDINGBALL) {
|
&& mob->cbf & CSB_BIT_BOUNDINGBALL) {
|
||||||
drainMobHP(mob, mob->maxHealth / 20); // lose 5% every second
|
drainMobHP(mob, mob->maxHealth / 20); // lose 5% every second
|
||||||
mob->lastDrainTime = currTime;
|
mob->lastDrainTime = currTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if drain killed the mob, return early
|
// if drain killed the mob, return early
|
||||||
if (mob->appearanceData.iHP <= 0)
|
if (mob->hp <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// unbuffing
|
// unbuffing
|
||||||
@ -546,12 +543,12 @@ static void combatStep(Mob *mob, time_t currTime) {
|
|||||||
while (it != mob->unbuffTimes.end()) {
|
while (it != mob->unbuffTimes.end()) {
|
||||||
|
|
||||||
if (currTime >= it->second) {
|
if (currTime >= it->second) {
|
||||||
mob->appearanceData.iConditionBitFlag &= ~it->first;
|
mob->cbf &= ~it->first;
|
||||||
|
|
||||||
INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, pkt1);
|
INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, pkt1);
|
||||||
pkt1.eCT = 2;
|
pkt1.eCT = 2;
|
||||||
pkt1.iID = mob->appearanceData.iNPC_ID;
|
pkt1.iID = mob->id;
|
||||||
pkt1.iConditionBitFlag = mob->appearanceData.iConditionBitFlag;
|
pkt1.iConditionBitFlag = mob->cbf;
|
||||||
NPCManager::sendToViewable(mob, &pkt1, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT, sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT));
|
NPCManager::sendToViewable(mob, &pkt1, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT, sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT));
|
||||||
|
|
||||||
it = mob->unbuffTimes.erase(it);
|
it = mob->unbuffTimes.erase(it);
|
||||||
@ -561,7 +558,7 @@ static void combatStep(Mob *mob, time_t currTime) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// skip attack if stunned or asleep
|
// skip attack if stunned or asleep
|
||||||
if (mob->appearanceData.iConditionBitFlag & (CSB_BIT_STUN|CSB_BIT_MEZ)) {
|
if (mob->cbf & (CSB_BIT_STUN|CSB_BIT_MEZ)) {
|
||||||
mob->skillStyle = -1; // in this case we also reset the any outlying abilities the mob might be winding up.
|
mob->skillStyle = -1; // in this case we also reset the any outlying abilities the mob might be winding up.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -587,7 +584,7 @@ static void combatStep(Mob *mob, time_t currTime) {
|
|||||||
mob->nextAttack = 0;
|
mob->nextAttack = 0;
|
||||||
|
|
||||||
// halve movement speed if snared
|
// halve movement speed if snared
|
||||||
if (mob->appearanceData.iConditionBitFlag & CSB_BIT_DN_MOVE_SPEED)
|
if (mob->cbf & CSB_BIT_DN_MOVE_SPEED)
|
||||||
speed /= 2;
|
speed /= 2;
|
||||||
|
|
||||||
int targetX = plr->x;
|
int targetX = plr->x;
|
||||||
@ -602,11 +599,11 @@ static void combatStep(Mob *mob, time_t currTime) {
|
|||||||
if (distanceToTravel < speed*2/5 && currTime >= mob->nextAttack)
|
if (distanceToTravel < speed*2/5 && currTime >= mob->nextAttack)
|
||||||
mob->nextAttack = 0;
|
mob->nextAttack = 0;
|
||||||
|
|
||||||
NPCManager::updateNPCPosition(mob->appearanceData.iNPC_ID, targ.first, targ.second, mob->z, mob->instanceID, mob->appearanceData.iAngle);
|
NPCManager::updateNPCPosition(mob->id, targ.first, targ.second, mob->z, mob->instanceID, mob->angle);
|
||||||
|
|
||||||
INITSTRUCT(sP_FE2CL_NPC_MOVE, pkt);
|
INITSTRUCT(sP_FE2CL_NPC_MOVE, pkt);
|
||||||
|
|
||||||
pkt.iNPC_ID = mob->appearanceData.iNPC_ID;
|
pkt.iNPC_ID = mob->id;
|
||||||
pkt.iSpeed = speed;
|
pkt.iSpeed = speed;
|
||||||
pkt.iToX = mob->x = targ.first;
|
pkt.iToX = mob->x = targ.first;
|
||||||
pkt.iToY = mob->y = targ.second;
|
pkt.iToY = mob->y = targ.second;
|
||||||
@ -664,7 +661,7 @@ static void roamingStep(Mob *mob, time_t currTime) {
|
|||||||
if (mob->staticPath)
|
if (mob->staticPath)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (mob->groupLeader != 0 && mob->groupLeader != mob->appearanceData.iNPC_ID) // don't roam by yourself without group leader
|
if (mob->groupLeader != 0 && mob->groupLeader != mob->id) // don't roam by yourself without group leader
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -704,7 +701,7 @@ static void roamingStep(Mob *mob, time_t currTime) {
|
|||||||
farY = std::clamp(farY, yStart, yStart + mob->idleRange);
|
farY = std::clamp(farY, yStart, yStart + mob->idleRange);
|
||||||
|
|
||||||
// halve movement speed if snared
|
// halve movement speed if snared
|
||||||
if (mob->appearanceData.iConditionBitFlag & CSB_BIT_DN_MOVE_SPEED)
|
if (mob->cbf & CSB_BIT_DN_MOVE_SPEED)
|
||||||
speed /= 2;
|
speed /= 2;
|
||||||
|
|
||||||
std::queue<Vec3> queue;
|
std::queue<Vec3> queue;
|
||||||
@ -713,9 +710,9 @@ static void roamingStep(Mob *mob, time_t currTime) {
|
|||||||
|
|
||||||
// add a route to the queue; to be processed in Transport::stepNPCPathing()
|
// add a route to the queue; to be processed in Transport::stepNPCPathing()
|
||||||
Transport::lerp(&queue, from, to, speed);
|
Transport::lerp(&queue, from, to, speed);
|
||||||
Transport::NPCQueues[mob->appearanceData.iNPC_ID] = queue;
|
Transport::NPCQueues[mob->id] = queue;
|
||||||
|
|
||||||
if (mob->groupLeader != 0 && mob->groupLeader == mob->appearanceData.iNPC_ID) {
|
if (mob->groupLeader != 0 && mob->groupLeader == mob->id) {
|
||||||
// make followers follow this npc.
|
// make followers follow this npc.
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
if (mob->groupMember[i] == 0)
|
if (mob->groupMember[i] == 0)
|
||||||
@ -731,7 +728,7 @@ static void roamingStep(Mob *mob, time_t currTime) {
|
|||||||
from = { followerMob->x, followerMob->y, followerMob->z };
|
from = { followerMob->x, followerMob->y, followerMob->z };
|
||||||
to = { farX + followerMob->offsetX, farY + followerMob->offsetY, followerMob->z };
|
to = { farX + followerMob->offsetX, farY + followerMob->offsetY, followerMob->z };
|
||||||
Transport::lerp(&queue2, from, to, speed);
|
Transport::lerp(&queue2, from, to, speed);
|
||||||
Transport::NPCQueues[followerMob->appearanceData.iNPC_ID] = queue2;
|
Transport::NPCQueues[followerMob->id] = queue2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -751,7 +748,7 @@ static void retreatStep(Mob *mob, time_t currTime) {
|
|||||||
|
|
||||||
auto targ = lerp(mob->x, mob->y, mob->roamX, mob->roamY, (int)mob->speed*4/5);
|
auto targ = lerp(mob->x, mob->y, mob->roamX, mob->roamY, (int)mob->speed*4/5);
|
||||||
|
|
||||||
pkt.iNPC_ID = mob->appearanceData.iNPC_ID;
|
pkt.iNPC_ID = mob->id;
|
||||||
pkt.iSpeed = (int)mob->speed * 2;
|
pkt.iSpeed = (int)mob->speed * 2;
|
||||||
pkt.iToX = mob->x = targ.first;
|
pkt.iToX = mob->x = targ.first;
|
||||||
pkt.iToY = mob->y = targ.second;
|
pkt.iToY = mob->y = targ.second;
|
||||||
@ -766,10 +763,10 @@ static void retreatStep(Mob *mob, time_t currTime) {
|
|||||||
//if (distance <= mob->data["m_iIdleRange"]) {
|
//if (distance <= mob->data["m_iIdleRange"]) {
|
||||||
if (distance <= 10) { // retreat back to the spawn point
|
if (distance <= 10) { // retreat back to the spawn point
|
||||||
mob->state = MobState::ROAMING;
|
mob->state = MobState::ROAMING;
|
||||||
mob->appearanceData.iHP = mob->maxHealth;
|
mob->hp = mob->maxHealth;
|
||||||
mob->killedTime = 0;
|
mob->killedTime = 0;
|
||||||
mob->nextAttack = 0;
|
mob->nextAttack = 0;
|
||||||
mob->appearanceData.iConditionBitFlag = 0;
|
mob->cbf = 0;
|
||||||
|
|
||||||
// cast a return home heal spell, this is the right way(tm)
|
// cast a return home heal spell, this is the right way(tm)
|
||||||
std::vector<int> targetData = {1, 0, 0, 0, 0};
|
std::vector<int> targetData = {1, 0, 0, 0, 0};
|
||||||
|
@ -72,10 +72,10 @@ struct Mob : public CombatNPC {
|
|||||||
offsetX = 0;
|
offsetX = 0;
|
||||||
offsetY = 0;
|
offsetY = 0;
|
||||||
|
|
||||||
appearanceData.iConditionBitFlag = 0;
|
cbf = 0;
|
||||||
|
|
||||||
// NOTE: there appear to be discrepancies in the dump
|
// NOTE: there appear to be discrepancies in the dump
|
||||||
appearanceData.iHP = maxHealth;
|
hp = maxHealth;
|
||||||
|
|
||||||
kind = EntityType::MOB;
|
kind = EntityType::MOB;
|
||||||
_stepAI = MobAI::step;
|
_stepAI = MobAI::step;
|
||||||
|
@ -67,7 +67,7 @@ void NPCManager::destroyNPC(int32_t id) {
|
|||||||
|
|
||||||
void NPCManager::updateNPCPosition(int32_t id, int X, int Y, int Z, uint64_t I, int angle) {
|
void NPCManager::updateNPCPosition(int32_t id, int X, int Y, int Z, uint64_t I, int angle) {
|
||||||
BaseNPC* npc = NPCs[id];
|
BaseNPC* npc = NPCs[id];
|
||||||
npc->appearanceData.iAngle = angle;
|
npc->angle = angle;
|
||||||
ChunkPos oldChunk = npc->chunkPos;
|
ChunkPos oldChunk = npc->chunkPos;
|
||||||
ChunkPos newChunk = Chunking::chunkPosAt(X, Y, I);
|
ChunkPos newChunk = Chunking::chunkPosAt(X, Y, I);
|
||||||
npc->x = X;
|
npc->x = X;
|
||||||
@ -154,7 +154,7 @@ static void npcSummonHandler(CNSocket* sock, CNPacketData* data) {
|
|||||||
|
|
||||||
for (int i = 0; i < req->iNPCCnt; i++) {
|
for (int i = 0; i < req->iNPCCnt; i++) {
|
||||||
BaseNPC *npc = summonNPC(plr->x, plr->y, plr->z, plr->instanceID, req->iNPCType);
|
BaseNPC *npc = summonNPC(plr->x, plr->y, plr->z, plr->instanceID, req->iNPCType);
|
||||||
updateNPCPosition(npc->appearanceData.iNPC_ID, plr->x, plr->y, plr->z, plr->instanceID, 0);
|
updateNPCPosition(npc->id, plr->x, plr->y, plr->z, plr->instanceID, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,16 +305,16 @@ static void lordFuseStageTwo(CNSocket *sock, BaseNPC *npc) {
|
|||||||
// Blastons, Heal
|
// Blastons, Heal
|
||||||
Mob *newbody = (Mob*)NPCManager::summonNPC(oldbody->spawnX, oldbody->spawnY, oldbody->spawnZ, plr->instanceID, 2467);
|
Mob *newbody = (Mob*)NPCManager::summonNPC(oldbody->spawnX, oldbody->spawnY, oldbody->spawnZ, plr->instanceID, 2467);
|
||||||
|
|
||||||
newbody->appearanceData.iAngle = oldbody->appearanceData.iAngle;
|
newbody->angle = oldbody->angle;
|
||||||
NPCManager::updateNPCPosition(newbody->appearanceData.iNPC_ID, newbody->spawnX, newbody->spawnY, newbody->spawnZ,
|
NPCManager::updateNPCPosition(newbody->id, newbody->spawnX, newbody->spawnY, newbody->spawnZ,
|
||||||
plr->instanceID, oldbody->appearanceData.iAngle);
|
plr->instanceID, oldbody->angle);
|
||||||
|
|
||||||
// right arm, Adaptium, Stun
|
// right arm, Adaptium, Stun
|
||||||
Mob *arm = (Mob*)NPCManager::summonNPC(oldbody->spawnX - 600, oldbody->spawnY, oldbody->spawnZ, plr->instanceID, 2469);
|
Mob *arm = (Mob*)NPCManager::summonNPC(oldbody->spawnX - 600, oldbody->spawnY, oldbody->spawnZ, plr->instanceID, 2469);
|
||||||
|
|
||||||
arm->appearanceData.iAngle = oldbody->appearanceData.iAngle;
|
arm->angle = oldbody->angle;
|
||||||
NPCManager::updateNPCPosition(arm->appearanceData.iNPC_ID, arm->spawnX, arm->spawnY, arm->spawnZ,
|
NPCManager::updateNPCPosition(arm->id, arm->spawnX, arm->spawnY, arm->spawnZ,
|
||||||
plr->instanceID, oldbody->appearanceData.iAngle);
|
plr->instanceID, oldbody->angle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// summon left arm and stage 3 body
|
// summon left arm and stage 3 body
|
||||||
@ -327,16 +327,16 @@ static void lordFuseStageThree(CNSocket *sock, BaseNPC *npc) {
|
|||||||
// Cosmix, Damage Point
|
// Cosmix, Damage Point
|
||||||
Mob *newbody = (Mob*)NPCManager::summonNPC(oldbody->spawnX, oldbody->spawnY, oldbody->spawnZ, plr->instanceID, 2468);
|
Mob *newbody = (Mob*)NPCManager::summonNPC(oldbody->spawnX, oldbody->spawnY, oldbody->spawnZ, plr->instanceID, 2468);
|
||||||
|
|
||||||
newbody->appearanceData.iAngle = oldbody->appearanceData.iAngle;
|
newbody->angle = oldbody->angle;
|
||||||
NPCManager::updateNPCPosition(newbody->appearanceData.iNPC_ID, newbody->spawnX, newbody->spawnY, newbody->spawnZ,
|
NPCManager::updateNPCPosition(newbody->id, newbody->spawnX, newbody->spawnY, newbody->spawnZ,
|
||||||
plr->instanceID, oldbody->appearanceData.iAngle);
|
plr->instanceID, oldbody->angle);
|
||||||
|
|
||||||
// Blastons, Heal
|
// Blastons, Heal
|
||||||
Mob *arm = (Mob*)NPCManager::summonNPC(oldbody->spawnX + 600, oldbody->spawnY, oldbody->spawnZ, plr->instanceID, 2470);
|
Mob *arm = (Mob*)NPCManager::summonNPC(oldbody->spawnX + 600, oldbody->spawnY, oldbody->spawnZ, plr->instanceID, 2470);
|
||||||
|
|
||||||
arm->appearanceData.iAngle = oldbody->appearanceData.iAngle;
|
arm->angle = oldbody->angle;
|
||||||
NPCManager::updateNPCPosition(arm->appearanceData.iNPC_ID, arm->spawnX, arm->spawnY, arm->spawnZ,
|
NPCManager::updateNPCPosition(arm->id, arm->spawnX, arm->spawnY, arm->spawnZ,
|
||||||
plr->instanceID, oldbody->appearanceData.iAngle);
|
plr->instanceID, oldbody->angle);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<NPCEvent> NPCManager::NPCEvents = {
|
std::vector<NPCEvent> NPCManager::NPCEvents = {
|
||||||
|
@ -89,4 +89,6 @@ struct Player : public Entity {
|
|||||||
|
|
||||||
virtual void enterIntoViewOf(CNSocket *sock) override;
|
virtual void enterIntoViewOf(CNSocket *sock) override;
|
||||||
virtual void disappearFromViewOf(CNSocket *sock) override;
|
virtual void disappearFromViewOf(CNSocket *sock) override;
|
||||||
|
|
||||||
|
sPCAppearanceData getAppearanceData();
|
||||||
};
|
};
|
||||||
|
@ -33,7 +33,7 @@ static void movePlayer(CNSocket* sock, CNPacketData* data) {
|
|||||||
// [gruntwork] check if player has a follower and move it
|
// [gruntwork] check if player has a follower and move it
|
||||||
if (TableData::RunningNPCPaths.find(plr->iID) != TableData::RunningNPCPaths.end()) {
|
if (TableData::RunningNPCPaths.find(plr->iID) != TableData::RunningNPCPaths.end()) {
|
||||||
BaseNPC* follower = TableData::RunningNPCPaths[plr->iID].first;
|
BaseNPC* follower = TableData::RunningNPCPaths[plr->iID].first;
|
||||||
Transport::NPCQueues.erase(follower->appearanceData.iNPC_ID); // erase existing points
|
Transport::NPCQueues.erase(follower->id); // erase existing points
|
||||||
std::queue<Vec3> queue;
|
std::queue<Vec3> queue;
|
||||||
Vec3 from = { follower->x, follower->y, follower->z };
|
Vec3 from = { follower->x, follower->y, follower->z };
|
||||||
float drag = 0.95f; // this ensures that they don't bump into the player
|
float drag = 0.95f; // this ensures that they don't bump into the player
|
||||||
@ -45,7 +45,7 @@ static void movePlayer(CNSocket* sock, CNPacketData* data) {
|
|||||||
|
|
||||||
// add a route to the queue; to be processed in Transport::stepNPCPathing()
|
// add a route to the queue; to be processed in Transport::stepNPCPathing()
|
||||||
Transport::lerp(&queue, from, to, NPC_DEFAULT_SPEED * 1.5); // little faster than typical
|
Transport::lerp(&queue, from, to, NPC_DEFAULT_SPEED * 1.5); // little faster than typical
|
||||||
Transport::NPCQueues[follower->appearanceData.iNPC_ID] = queue;
|
Transport::NPCQueues[follower->id] = queue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,9 +315,9 @@ static void loadPaths(json& pathData, int32_t* nextId) {
|
|||||||
passedDistance -= SLIDER_GAP_SIZE; // step down
|
passedDistance -= SLIDER_GAP_SIZE; // step down
|
||||||
// spawn a slider
|
// spawn a slider
|
||||||
Bus* slider = new Bus(point.x, point.y, point.z, 0, INSTANCE_OVERWORLD, 1, (*nextId)--);
|
Bus* slider = new Bus(point.x, point.y, point.z, 0, INSTANCE_OVERWORLD, 1, (*nextId)--);
|
||||||
NPCManager::NPCs[slider->appearanceData.iNPC_ID] = slider;
|
NPCManager::NPCs[slider->id] = slider;
|
||||||
NPCManager::updateNPCPosition(slider->appearanceData.iNPC_ID, slider->x, slider->y, slider->z, INSTANCE_OVERWORLD, 0);
|
NPCManager::updateNPCPosition(slider->id, slider->x, slider->y, slider->z, INSTANCE_OVERWORLD, 0);
|
||||||
Transport::NPCQueues[slider->appearanceData.iNPC_ID] = route;
|
Transport::NPCQueues[slider->id] = route;
|
||||||
}
|
}
|
||||||
// rotate
|
// rotate
|
||||||
route.pop();
|
route.pop();
|
||||||
@ -755,7 +755,7 @@ static void loadGruntworkPost(json& gruntwork, int32_t* nextId) {
|
|||||||
if (NPCManager::NPCs.find(npcID) == NPCManager::NPCs.end())
|
if (NPCManager::NPCs.find(npcID) == NPCManager::NPCs.end())
|
||||||
continue; // NPC not found
|
continue; // NPC not found
|
||||||
BaseNPC* npc = NPCManager::NPCs[npcID];
|
BaseNPC* npc = NPCManager::NPCs[npcID];
|
||||||
npc->appearanceData.iAngle = angle;
|
npc->angle = angle;
|
||||||
|
|
||||||
RunningNPCRotations[npcID] = angle;
|
RunningNPCRotations[npcID] = angle;
|
||||||
}
|
}
|
||||||
@ -768,8 +768,8 @@ static void loadGruntworkPost(json& gruntwork, int32_t* nextId) {
|
|||||||
if (NPCManager::NPCs.find(npcID) == NPCManager::NPCs.end())
|
if (NPCManager::NPCs.find(npcID) == NPCManager::NPCs.end())
|
||||||
continue; // NPC not found
|
continue; // NPC not found
|
||||||
BaseNPC* npc = NPCManager::NPCs[npcID];
|
BaseNPC* npc = NPCManager::NPCs[npcID];
|
||||||
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, npc->x, npc->y,
|
NPCManager::updateNPCPosition(npc->id, npc->x, npc->y,
|
||||||
npc->z, instanceID, npc->appearanceData.iAngle);
|
npc->z, instanceID, npc->angle);
|
||||||
|
|
||||||
RunningNPCMapNumbers[npcID] = instanceID;
|
RunningNPCMapNumbers[npcID] = instanceID;
|
||||||
}
|
}
|
||||||
@ -794,9 +794,9 @@ static void loadGruntworkPost(json& gruntwork, int32_t* nextId) {
|
|||||||
npc = new BaseNPC(mob["iX"], mob["iY"], mob["iZ"], mob["iAngle"], instanceID, mob["iNPCType"], id);
|
npc = new BaseNPC(mob["iX"], mob["iY"], mob["iZ"], mob["iAngle"], instanceID, mob["iNPCType"], id);
|
||||||
}
|
}
|
||||||
|
|
||||||
NPCManager::NPCs[npc->appearanceData.iNPC_ID] = npc;
|
NPCManager::NPCs[npc->id] = npc;
|
||||||
RunningMobs[npc->appearanceData.iNPC_ID] = npc;
|
RunningMobs[npc->id] = npc;
|
||||||
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, mob["iX"], mob["iY"], mob["iZ"], instanceID, mob["iAngle"]);
|
NPCManager::updateNPCPosition(npc->id, mob["iX"], mob["iY"], mob["iZ"], instanceID, mob["iAngle"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// mob groups
|
// mob groups
|
||||||
@ -840,7 +840,7 @@ static void loadGruntworkPost(json& gruntwork, int32_t* nextId) {
|
|||||||
|
|
||||||
tmpFol->offsetX = follower.find("iOffsetX") == follower.end() ? 0 : (int)follower["iOffsetX"];
|
tmpFol->offsetX = follower.find("iOffsetX") == follower.end() ? 0 : (int)follower["iOffsetX"];
|
||||||
tmpFol->offsetY = follower.find("iOffsetY") == follower.end() ? 0 : (int)follower["iOffsetY"];
|
tmpFol->offsetY = follower.find("iOffsetY") == follower.end() ? 0 : (int)follower["iOffsetY"];
|
||||||
tmpFol->groupLeader = tmp->appearanceData.iNPC_ID;
|
tmpFol->groupLeader = tmp->id;
|
||||||
tmp->groupMember[followerCount++] = *nextId;
|
tmp->groupMember[followerCount++] = *nextId;
|
||||||
|
|
||||||
(*nextId)--;
|
(*nextId)--;
|
||||||
@ -850,7 +850,7 @@ static void loadGruntworkPost(json& gruntwork, int32_t* nextId) {
|
|||||||
std::cout << "[WARN] Mob group leader with ID " << *nextId << " has too many followers (" << followers.size() << ")\n";
|
std::cout << "[WARN] Mob group leader with ID " << *nextId << " has too many followers (" << followers.size() << ")\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
RunningGroups[tmp->appearanceData.iNPC_ID] = tmp; // store as running
|
RunningGroups[tmp->id] = tmp; // store as running
|
||||||
}
|
}
|
||||||
|
|
||||||
auto eggs = gruntwork["eggs"];
|
auto eggs = gruntwork["eggs"];
|
||||||
@ -1003,7 +1003,7 @@ static void loadMobs(json& npcData, int32_t* nextId) {
|
|||||||
|
|
||||||
tmpFol->offsetX = follower.find("iOffsetX") == follower.end() ? 0 : (int)follower["iOffsetX"];
|
tmpFol->offsetX = follower.find("iOffsetX") == follower.end() ? 0 : (int)follower["iOffsetX"];
|
||||||
tmpFol->offsetY = follower.find("iOffsetY") == follower.end() ? 0 : (int)follower["iOffsetY"];
|
tmpFol->offsetY = follower.find("iOffsetY") == follower.end() ? 0 : (int)follower["iOffsetY"];
|
||||||
tmpFol->groupLeader = tmp->appearanceData.iNPC_ID;
|
tmpFol->groupLeader = tmp->id;
|
||||||
tmp->groupMember[followerCount++] = *nextId;
|
tmp->groupMember[followerCount++] = *nextId;
|
||||||
|
|
||||||
(*nextId)--;
|
(*nextId)--;
|
||||||
@ -1238,13 +1238,13 @@ void TableData::flush() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: this format deviates slightly from the one in mobs.json
|
// NOTE: this format deviates slightly from the one in mobs.json
|
||||||
mob["iNPCType"] = (int)npc->appearanceData.iNPCType;
|
mob["iNPCType"] = (int)npc->type;
|
||||||
mob["iX"] = x;
|
mob["iX"] = x;
|
||||||
mob["iY"] = y;
|
mob["iY"] = y;
|
||||||
mob["iZ"] = z;
|
mob["iZ"] = z;
|
||||||
mob["iMapNum"] = MAPNUM(npc->instanceID);
|
mob["iMapNum"] = MAPNUM(npc->instanceID);
|
||||||
// this is a bit imperfect, since this is a live angle, not a spawn angle so it'll change often, but eh
|
// this is a bit imperfect, since this is a live angle, not a spawn angle so it'll change often, but eh
|
||||||
mob["iAngle"] = npc->appearanceData.iAngle;
|
mob["iAngle"] = npc->angle;
|
||||||
|
|
||||||
// it's called mobs, but really it's everything
|
// it's called mobs, but really it's everything
|
||||||
gruntwork["mobs"].push_back(mob);
|
gruntwork["mobs"].push_back(mob);
|
||||||
@ -1264,7 +1264,7 @@ void TableData::flush() {
|
|||||||
x = m->spawnX;
|
x = m->spawnX;
|
||||||
y = m->spawnY;
|
y = m->spawnY;
|
||||||
z = m->spawnZ;
|
z = m->spawnZ;
|
||||||
if (m->groupLeader != m->appearanceData.iNPC_ID) { // make sure this is a leader
|
if (m->groupLeader != m->id) { // make sure this is a leader
|
||||||
std::cout << "[WARN] Non-leader mob found in running groups; ignoring\n";
|
std::cout << "[WARN] Non-leader mob found in running groups; ignoring\n";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1285,13 +1285,13 @@ void TableData::flush() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: this format deviates slightly from the one in mobs.json
|
// NOTE: this format deviates slightly from the one in mobs.json
|
||||||
mob["iNPCType"] = (int)npc->appearanceData.iNPCType;
|
mob["iNPCType"] = (int)npc->type;
|
||||||
mob["iX"] = x;
|
mob["iX"] = x;
|
||||||
mob["iY"] = y;
|
mob["iY"] = y;
|
||||||
mob["iZ"] = z;
|
mob["iZ"] = z;
|
||||||
mob["iMapNum"] = MAPNUM(npc->instanceID);
|
mob["iMapNum"] = MAPNUM(npc->instanceID);
|
||||||
// this is a bit imperfect, since this is a live angle, not a spawn angle so it'll change often, but eh
|
// this is a bit imperfect, since this is a live angle, not a spawn angle so it'll change often, but eh
|
||||||
mob["iAngle"] = npc->appearanceData.iAngle;
|
mob["iAngle"] = npc->angle;
|
||||||
|
|
||||||
// followers
|
// followers
|
||||||
while (followers.size() > 0) {
|
while (followers.size() > 0) {
|
||||||
@ -1300,7 +1300,7 @@ void TableData::flush() {
|
|||||||
|
|
||||||
// populate JSON entry
|
// populate JSON entry
|
||||||
json fol;
|
json fol;
|
||||||
fol["iNPCType"] = follower->appearanceData.iNPCType;
|
fol["iNPCType"] = follower->type;
|
||||||
fol["iOffsetX"] = follower->offsetX;
|
fol["iOffsetX"] = follower->offsetX;
|
||||||
fol["iOffsetY"] = follower->offsetY;
|
fol["iOffsetY"] = follower->offsetY;
|
||||||
|
|
||||||
@ -1325,7 +1325,7 @@ void TableData::flush() {
|
|||||||
int mapnum = MAPNUM(npc->instanceID);
|
int mapnum = MAPNUM(npc->instanceID);
|
||||||
if (mapnum != 0)
|
if (mapnum != 0)
|
||||||
egg["iMapNum"] = mapnum;
|
egg["iMapNum"] = mapnum;
|
||||||
egg["iType"] = npc->appearanceData.iNPCType;
|
egg["iType"] = npc->type;
|
||||||
|
|
||||||
gruntwork["eggs"].push_back(egg);
|
gruntwork["eggs"].push_back(egg);
|
||||||
}
|
}
|
||||||
|
@ -276,7 +276,7 @@ static void stepNPCPathing() {
|
|||||||
int distanceBetween = hypot(dXY, point.z - npc->z); // total distance
|
int distanceBetween = hypot(dXY, point.z - npc->z); // total distance
|
||||||
|
|
||||||
// update NPC location to update viewables
|
// update NPC location to update viewables
|
||||||
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, point.x, point.y, point.z, npc->instanceID, npc->appearanceData.iAngle);
|
NPCManager::updateNPCPosition(npc->id, point.x, point.y, point.z, npc->instanceID, npc->angle);
|
||||||
|
|
||||||
// TODO: move walking logic into Entity stack
|
// TODO: move walking logic into Entity stack
|
||||||
switch (npc->kind) {
|
switch (npc->kind) {
|
||||||
@ -284,7 +284,7 @@ static void stepNPCPathing() {
|
|||||||
INITSTRUCT(sP_FE2CL_TRANSPORTATION_MOVE, busMove);
|
INITSTRUCT(sP_FE2CL_TRANSPORTATION_MOVE, busMove);
|
||||||
|
|
||||||
busMove.eTT = 3;
|
busMove.eTT = 3;
|
||||||
busMove.iT_ID = npc->appearanceData.iNPC_ID;
|
busMove.iT_ID = npc->id;
|
||||||
busMove.iMoveStyle = 0; // ???
|
busMove.iMoveStyle = 0; // ???
|
||||||
busMove.iToX = point.x;
|
busMove.iToX = point.x;
|
||||||
busMove.iToY = point.y;
|
busMove.iToY = point.y;
|
||||||
@ -298,7 +298,7 @@ static void stepNPCPathing() {
|
|||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
default:
|
default:
|
||||||
INITSTRUCT(sP_FE2CL_NPC_MOVE, move);
|
INITSTRUCT(sP_FE2CL_NPC_MOVE, move);
|
||||||
move.iNPC_ID = npc->appearanceData.iNPC_ID;
|
move.iNPC_ID = npc->id;
|
||||||
move.iMoveStyle = 0; // ???
|
move.iMoveStyle = 0; // ???
|
||||||
move.iToX = point.x;
|
move.iToX = point.x;
|
||||||
move.iToY = point.y;
|
move.iToY = point.y;
|
||||||
|
Loading…
Reference in New Issue
Block a user