mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-11-22 21:40:05 +00:00
Moved Debuff handling to Combat + Bugfixes
* Majority of mob debuff handling is moved to combatStep(). * Drain now kills the mob and does 40% overall damage. * Bumped up active nano debuff durations, debuffs like drain linger longer but damage less. * Debuffs are cleared upon mob death and retreating. * Patched out vehicle off success packet spam * Boosts and potions now cost the right amount (100 taros) and give the right quantity (100). * Damage was tweaked slightly. At higher levels you are more likely to fall prey to rand(). * Enemies now use run animations during combat and retreating.
This commit is contained in:
parent
2af33da4e8
commit
d21f727e9d
@ -144,7 +144,8 @@ void MobManager::npcAttackPc(Mob *mob, time_t currTime) {
|
|||||||
if (plr->HP <= 0) {
|
if (plr->HP <= 0) {
|
||||||
mob->target = nullptr;
|
mob->target = nullptr;
|
||||||
mob->state = MobState::RETREAT;
|
mob->state = MobState::RETREAT;
|
||||||
aggroCheck(mob, currTime);
|
if (!aggroCheck(mob, currTime))
|
||||||
|
clearDebuff(mob);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,6 +352,7 @@ void MobManager::killMob(CNSocket *sock, Mob *mob) {
|
|||||||
mob->state = MobState::DEAD;
|
mob->state = MobState::DEAD;
|
||||||
mob->target = nullptr;
|
mob->target = nullptr;
|
||||||
mob->appearanceData.iConditionBitFlag = 0;
|
mob->appearanceData.iConditionBitFlag = 0;
|
||||||
|
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?
|
||||||
|
|
||||||
// check for the edge case where hitting the mob did not aggro it
|
// check for the edge case where hitting the mob did not aggro it
|
||||||
@ -449,7 +451,8 @@ void MobManager::combatStep(Mob *mob, time_t currTime) {
|
|||||||
if (PlayerManager::players.find(mob->target) == PlayerManager::players.end()) {
|
if (PlayerManager::players.find(mob->target) == PlayerManager::players.end()) {
|
||||||
mob->target = nullptr;
|
mob->target = nullptr;
|
||||||
mob->state = MobState::RETREAT;
|
mob->state = MobState::RETREAT;
|
||||||
aggroCheck(mob, currTime);
|
if (!aggroCheck(mob, currTime))
|
||||||
|
clearDebuff(mob);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -462,10 +465,40 @@ void MobManager::combatStep(Mob *mob, time_t currTime) {
|
|||||||
if (plr->HP <= 0) {
|
if (plr->HP <= 0) {
|
||||||
mob->target = nullptr;
|
mob->target = nullptr;
|
||||||
mob->state = MobState::RETREAT;
|
mob->state = MobState::RETREAT;
|
||||||
aggroCheck(mob, currTime);
|
if (!aggroCheck(mob, currTime))
|
||||||
|
clearDebuff(mob);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// drain
|
||||||
|
if ((mob->lastDrainTime == 0 || currTime - mob->lastDrainTime >= 1000) && mob->appearanceData.iConditionBitFlag & CSB_BIT_BOUNDINGBALL) {
|
||||||
|
drainMobHP(mob, mob->maxHealth / 15); // lose 6.67% every second
|
||||||
|
mob->lastDrainTime = currTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
// unbuffing
|
||||||
|
std::unordered_map<int32_t, time_t>::iterator it = mob->unbuffTimes.begin();
|
||||||
|
while (it != mob->unbuffTimes.end()) {
|
||||||
|
|
||||||
|
if (currTime >= it->second) {
|
||||||
|
mob->appearanceData.iConditionBitFlag &= ~it->first;
|
||||||
|
|
||||||
|
INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, pkt1);
|
||||||
|
pkt1.eCT = 2;
|
||||||
|
pkt1.iID = mob->appearanceData.iNPC_ID;
|
||||||
|
pkt1.iConditionBitFlag = mob->appearanceData.iConditionBitFlag;
|
||||||
|
NPCManager::sendToViewable(mob, &pkt1, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT, sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT));
|
||||||
|
|
||||||
|
it = mob->unbuffTimes.erase(it);
|
||||||
|
} else {
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip attack if stunned or asleep
|
||||||
|
if (mob->appearanceData.iConditionBitFlag & (CSB_BIT_STUN|CSB_BIT_MEZ))
|
||||||
|
return;
|
||||||
|
|
||||||
int distance = hypot(plr->x - mob->appearanceData.iX, plr->y - mob->appearanceData.iY);
|
int distance = hypot(plr->x - mob->appearanceData.iX, plr->y - mob->appearanceData.iY);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -481,6 +514,7 @@ void MobManager::combatStep(Mob *mob, time_t currTime) {
|
|||||||
pkt.iToX = mob->appearanceData.iX;
|
pkt.iToX = mob->appearanceData.iX;
|
||||||
pkt.iToY = mob->appearanceData.iY;
|
pkt.iToY = mob->appearanceData.iY;
|
||||||
pkt.iToZ = mob->target->plr->z;
|
pkt.iToZ = mob->target->plr->z;
|
||||||
|
pkt.iMoveStyle = 1;
|
||||||
NPCManager::sendToViewable(mob, &pkt, P_FE2CL_NPC_MOVE, sizeof(sP_FE2CL_NPC_MOVE));
|
NPCManager::sendToViewable(mob, &pkt, P_FE2CL_NPC_MOVE, sizeof(sP_FE2CL_NPC_MOVE));
|
||||||
|
|
||||||
mob->nextAttack = currTime + (int)mob->data["m_iInitalTime"] * 100; //I *think* this is what this is
|
mob->nextAttack = currTime + (int)mob->data["m_iInitalTime"] * 100; //I *think* this is what this is
|
||||||
@ -514,6 +548,7 @@ void MobManager::combatStep(Mob *mob, time_t currTime) {
|
|||||||
pkt.iToX = mob->appearanceData.iX = targ.first;
|
pkt.iToX = mob->appearanceData.iX = targ.first;
|
||||||
pkt.iToY = mob->appearanceData.iY = targ.second;
|
pkt.iToY = mob->appearanceData.iY = targ.second;
|
||||||
pkt.iToZ = mob->target->plr->z;
|
pkt.iToZ = mob->target->plr->z;
|
||||||
|
pkt.iMoveStyle = 1;
|
||||||
|
|
||||||
// notify all nearby players
|
// notify all nearby players
|
||||||
NPCManager::sendToViewable(mob, &pkt, P_FE2CL_NPC_MOVE, sizeof(sP_FE2CL_NPC_MOVE));
|
NPCManager::sendToViewable(mob, &pkt, P_FE2CL_NPC_MOVE, sizeof(sP_FE2CL_NPC_MOVE));
|
||||||
@ -525,6 +560,7 @@ void MobManager::combatStep(Mob *mob, time_t currTime) {
|
|||||||
if (distance >= mob->data["m_iCombatRange"]) {
|
if (distance >= mob->data["m_iCombatRange"]) {
|
||||||
mob->target = nullptr;
|
mob->target = nullptr;
|
||||||
mob->state = MobState::RETREAT;
|
mob->state = MobState::RETREAT;
|
||||||
|
clearDebuff(mob);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -615,6 +651,7 @@ void MobManager::retreatStep(Mob *mob, time_t currTime) {
|
|||||||
pkt.iToX = mob->appearanceData.iX = targ.first;
|
pkt.iToX = mob->appearanceData.iX = targ.first;
|
||||||
pkt.iToY = mob->appearanceData.iY = targ.second;
|
pkt.iToY = mob->appearanceData.iY = targ.second;
|
||||||
pkt.iToZ = mob->appearanceData.iZ = mob->spawnZ;
|
pkt.iToZ = mob->appearanceData.iZ = mob->spawnZ;
|
||||||
|
pkt.iMoveStyle = 1;
|
||||||
|
|
||||||
// notify all nearby players
|
// notify all nearby players
|
||||||
NPCManager::sendToViewable(mob, &pkt, P_FE2CL_NPC_MOVE, sizeof(sP_FE2CL_NPC_MOVE));
|
NPCManager::sendToViewable(mob, &pkt, P_FE2CL_NPC_MOVE, sizeof(sP_FE2CL_NPC_MOVE));
|
||||||
@ -631,12 +668,11 @@ void MobManager::retreatStep(Mob *mob, time_t currTime) {
|
|||||||
|
|
||||||
// HACK: we haven't found a better way to refresh a mob's client-side status
|
// HACK: we haven't found a better way to refresh a mob's client-side status
|
||||||
drainMobHP(mob, 0);
|
drainMobHP(mob, 0);
|
||||||
|
clearDebuff(mob);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MobManager::step(CNServer *serv, time_t currTime) {
|
void MobManager::step(CNServer *serv, time_t currTime) {
|
||||||
static time_t lastDrainTime = 0;
|
|
||||||
|
|
||||||
for (auto& pair : Mobs) {
|
for (auto& pair : Mobs) {
|
||||||
int x = pair.second->appearanceData.iX;
|
int x = pair.second->appearanceData.iX;
|
||||||
int y = pair.second->appearanceData.iY;
|
int y = pair.second->appearanceData.iY;
|
||||||
@ -645,40 +681,11 @@ void MobManager::step(CNServer *serv, time_t currTime) {
|
|||||||
if (!ChunkManager::inPopulatedChunks(x, y, pair.second->instanceID))
|
if (!ChunkManager::inPopulatedChunks(x, y, pair.second->instanceID))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// drain
|
|
||||||
if (currTime - lastDrainTime >= 600 && pair.second->appearanceData.iConditionBitFlag & CSB_BIT_BOUNDINGBALL) {
|
|
||||||
drainMobHP(pair.second, pair.second->maxHealth * 3 / 50); // lose 10% every second
|
|
||||||
}
|
|
||||||
|
|
||||||
// unbuffing
|
|
||||||
std::unordered_map<int32_t, time_t>::iterator it = pair.second->unbuffTimes.begin();
|
|
||||||
while (it != pair.second->unbuffTimes.end()) {
|
|
||||||
|
|
||||||
if (currTime >= it->second) {
|
|
||||||
pair.second->appearanceData.iConditionBitFlag &= ~it->first;
|
|
||||||
|
|
||||||
INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, pkt1);
|
|
||||||
pkt1.eCT = 2;
|
|
||||||
pkt1.iID = pair.second->appearanceData.iNPC_ID;
|
|
||||||
pkt1.iConditionBitFlag = pair.second->appearanceData.iConditionBitFlag;
|
|
||||||
NPCManager::sendToViewable(pair.second, &pkt1, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT, sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT));
|
|
||||||
|
|
||||||
it = pair.second->unbuffTimes.erase(it);
|
|
||||||
} else {
|
|
||||||
it++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip mob movement and combat if disabled
|
// skip mob movement and combat if disabled
|
||||||
if (!simulateMobs && pair.second->state != MobState::DEAD
|
if (!simulateMobs && pair.second->state != MobState::DEAD
|
||||||
&& pair.second->state != MobState::RETREAT)
|
&& pair.second->state != MobState::RETREAT)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// skip attack/move if stunned or asleep
|
|
||||||
if (pair.second->appearanceData.iConditionBitFlag & (CSB_BIT_STUN|CSB_BIT_MEZ)
|
|
||||||
&& (pair.second->state == MobState::ROAMING || pair.second->state == MobState::COMBAT))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
switch (pair.second->state) {
|
switch (pair.second->state) {
|
||||||
case MobState::INACTIVE:
|
case MobState::INACTIVE:
|
||||||
// no-op
|
// no-op
|
||||||
@ -698,9 +705,6 @@ void MobManager::step(CNServer *serv, time_t currTime) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currTime - lastDrainTime >= 600)
|
|
||||||
lastDrainTime = currTime;
|
|
||||||
|
|
||||||
// deallocate all NPCs queued for removal
|
// deallocate all NPCs queued for removal
|
||||||
while (RemovalQueue.size() > 0) {
|
while (RemovalQueue.size() > 0) {
|
||||||
NPCManager::destroyNPC(RemovalQueue.front());
|
NPCManager::destroyNPC(RemovalQueue.front());
|
||||||
@ -920,7 +924,7 @@ std::pair<int,int> MobManager::getDamage(int attackPower, int defensePower, bool
|
|||||||
|
|
||||||
// base calculation
|
// base calculation
|
||||||
int damage = attackPower * attackPower / (attackPower + defensePower);
|
int damage = attackPower * attackPower / (attackPower + defensePower);
|
||||||
damage = std::max(10 + attackPower / 10, damage - defensePower * (4 + difficulty) / 40);
|
//damage = std::max(10 + attackPower / 10, damage - defensePower * (4 + difficulty) / 100);
|
||||||
damage = damage * (rand() % 40 + 80) / 100;
|
damage = damage * (rand() % 40 + 80) / 100;
|
||||||
|
|
||||||
// Adaptium/Blastons/Cosmix
|
// Adaptium/Blastons/Cosmix
|
||||||
@ -1082,6 +1086,9 @@ void MobManager::drainMobHP(Mob *mob, int amount) {
|
|||||||
drain->iHP = mob->appearanceData.iHP -= amount;
|
drain->iHP = mob->appearanceData.iHP -= 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)
|
||||||
|
killMob(mob->target, mob);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1137,3 +1144,14 @@ bool MobManager::aggroCheck(Mob *mob, time_t currTime) {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MobManager::clearDebuff(Mob *mob) {
|
||||||
|
mob->appearanceData.iConditionBitFlag = 0;
|
||||||
|
mob->unbuffTimes.clear();
|
||||||
|
|
||||||
|
INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, pkt1);
|
||||||
|
pkt1.eCT = 2;
|
||||||
|
pkt1.iID = mob->appearanceData.iNPC_ID;
|
||||||
|
pkt1.iConditionBitFlag = mob->appearanceData.iConditionBitFlag;
|
||||||
|
NPCManager::sendToViewable(mob, &pkt1, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT, sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT));
|
||||||
|
}
|
@ -46,7 +46,7 @@ struct Mob : public BaseNPC {
|
|||||||
// combat
|
// combat
|
||||||
CNSocket *target = nullptr;
|
CNSocket *target = nullptr;
|
||||||
time_t nextAttack = 0;
|
time_t nextAttack = 0;
|
||||||
|
time_t lastDrainTime = 0;
|
||||||
|
|
||||||
// drop
|
// drop
|
||||||
int dropType;
|
int dropType;
|
||||||
@ -142,4 +142,5 @@ namespace MobManager {
|
|||||||
void drainMobHP(Mob *mob, int amount);
|
void drainMobHP(Mob *mob, int amount);
|
||||||
void incNextMovement(Mob *mob, time_t currTime=0);
|
void incNextMovement(Mob *mob, time_t currTime=0);
|
||||||
bool aggroCheck(Mob *mob, time_t currTime);
|
bool aggroCheck(Mob *mob, time_t currTime);
|
||||||
|
void clearDebuff(Mob *mob);
|
||||||
}
|
}
|
||||||
|
@ -406,16 +406,16 @@ void NPCManager::npcVendorBuyBattery(CNSocket* sock, CNPacketData* data) {
|
|||||||
if (plr == nullptr)
|
if (plr == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int cost = req->Item.iOpt * 10;
|
int cost = req->Item.iOpt * 100;
|
||||||
if ((req->Item.iID == 3 ? (plr->batteryW >= 9999) : (plr->batteryN >= 9999)) || plr->money < cost) { // sanity check
|
if ((req->Item.iID == 3 ? (plr->batteryW >= 9999) : (plr->batteryN >= 9999)) || plr->money < cost) { // sanity check
|
||||||
INITSTRUCT(sP_FE2CL_REP_PC_VENDOR_BATTERY_BUY_FAIL, failResp);
|
INITSTRUCT(sP_FE2CL_REP_PC_VENDOR_BATTERY_BUY_FAIL, failResp);
|
||||||
failResp.iErrorCode = 0;
|
failResp.iErrorCode = 0;
|
||||||
sock->sendPacket((void*)&failResp, P_FE2CL_REP_PC_VENDOR_BATTERY_BUY_FAIL, sizeof(sP_FE2CL_REP_PC_VENDOR_BATTERY_BUY_FAIL));
|
sock->sendPacket((void*)&failResp, P_FE2CL_REP_PC_VENDOR_BATTERY_BUY_FAIL, sizeof(sP_FE2CL_REP_PC_VENDOR_BATTERY_BUY_FAIL));
|
||||||
}
|
}
|
||||||
|
|
||||||
plr->money -= cost;
|
cost = plr->batteryW + plr->batteryN;
|
||||||
plr->batteryW += req->Item.iID == 3 ? req->Item.iOpt * 10 : 0;
|
plr->batteryW += req->Item.iID == 3 ? req->Item.iOpt * 100 : 0;
|
||||||
plr->batteryN += req->Item.iID == 4 ? req->Item.iOpt * 10 : 0;
|
plr->batteryN += req->Item.iID == 4 ? req->Item.iOpt * 100 : 0;
|
||||||
|
|
||||||
// caps
|
// caps
|
||||||
if (plr->batteryW > 9999)
|
if (plr->batteryW > 9999)
|
||||||
@ -423,6 +423,9 @@ void NPCManager::npcVendorBuyBattery(CNSocket* sock, CNPacketData* data) {
|
|||||||
if (plr->batteryN > 9999)
|
if (plr->batteryN > 9999)
|
||||||
plr->batteryN = 9999;
|
plr->batteryN = 9999;
|
||||||
|
|
||||||
|
cost = plr->batteryW + plr->batteryN - cost;
|
||||||
|
plr->money -= cost;
|
||||||
|
|
||||||
INITSTRUCT(sP_FE2CL_REP_PC_VENDOR_BATTERY_BUY_SUCC, resp);
|
INITSTRUCT(sP_FE2CL_REP_PC_VENDOR_BATTERY_BUY_SUCC, resp);
|
||||||
|
|
||||||
resp.iCandy = plr->money;
|
resp.iCandy = plr->money;
|
||||||
|
@ -715,15 +715,15 @@ void activePower(CNSocket *sock, CNPacketData *data,
|
|||||||
|
|
||||||
// active nano power dispatch table
|
// active nano power dispatch table
|
||||||
std::vector<ActivePower> ActivePowers = {
|
std::vector<ActivePower> ActivePowers = {
|
||||||
ActivePower(StunPowers, activePower<sSkillResult_Damage_N_Debuff, doDebuff>, EST_STUN, CSB_BIT_STUN, 2250),
|
ActivePower(StunPowers, activePower<sSkillResult_Damage_N_Debuff, doDebuff>, EST_STUN, CSB_BIT_STUN, 4000),
|
||||||
ActivePower(HealPowers, activePower<sSkillResult_Heal_HP, doHeal>, EST_HEAL_HP, CSB_BIT_NONE, 35),
|
ActivePower(HealPowers, activePower<sSkillResult_Heal_HP, doHeal>, EST_HEAL_HP, CSB_BIT_NONE, 35),
|
||||||
ActivePower(GroupHealPowers, activePower<sSkillResult_Heal_HP, doGroupHeal, GHEAL>,EST_HEAL_HP, CSB_BIT_NONE, 20),
|
ActivePower(GroupHealPowers, activePower<sSkillResult_Heal_HP, doGroupHeal, GHEAL>,EST_HEAL_HP, CSB_BIT_NONE, 20),
|
||||||
// TODO: Recall
|
// TODO: Recall
|
||||||
ActivePower(DrainPowers, activePower<sSkillResult_Buff, doBuff>, EST_BOUNDINGBALL, CSB_BIT_BOUNDINGBALL, 3000),
|
ActivePower(DrainPowers, activePower<sSkillResult_Buff, doBuff>, EST_BOUNDINGBALL, CSB_BIT_BOUNDINGBALL, 6000),
|
||||||
ActivePower(SnarePowers, activePower<sSkillResult_Damage_N_Debuff, doDebuff>, EST_SNARE, CSB_BIT_DN_MOVE_SPEED, 4500),
|
ActivePower(SnarePowers, activePower<sSkillResult_Damage_N_Debuff, doDebuff>, EST_SNARE, CSB_BIT_DN_MOVE_SPEED, 8000),
|
||||||
ActivePower(DamagePowers, activePower<sSkillResult_Damage, doDamage>, EST_DAMAGE, CSB_BIT_NONE, 12),
|
ActivePower(DamagePowers, activePower<sSkillResult_Damage, doDamage>, EST_DAMAGE, CSB_BIT_NONE, 12),
|
||||||
ActivePower(LeechPowers, activePower<sSkillResult_Heal_HP, doLeech, LEECH>, EST_BLOODSUCKING, CSB_BIT_NONE, 18),
|
ActivePower(LeechPowers, activePower<sSkillResult_Heal_HP, doLeech, LEECH>, EST_BLOODSUCKING, CSB_BIT_NONE, 18),
|
||||||
ActivePower(SleepPowers, activePower<sSkillResult_Damage_N_Debuff, doDebuff>, EST_SLEEP, CSB_BIT_MEZ, 4500),
|
ActivePower(SleepPowers, activePower<sSkillResult_Damage_N_Debuff, doDebuff>, EST_SLEEP, CSB_BIT_MEZ, 8000),
|
||||||
};
|
};
|
||||||
|
|
||||||
}; // namespace
|
}; // namespace
|
||||||
|
@ -855,10 +855,10 @@ void PlayerManager::enterPlayerVehicle(CNSocket* sock, CNPacketData* data) {
|
|||||||
sock->sendPacket((void*)&response, P_FE2CL_PC_VEHICLE_ON_SUCC, sizeof(sP_FE2CL_PC_VEHICLE_ON_SUCC));
|
sock->sendPacket((void*)&response, P_FE2CL_PC_VEHICLE_ON_SUCC, sizeof(sP_FE2CL_PC_VEHICLE_ON_SUCC));
|
||||||
|
|
||||||
// send to other players
|
// send to other players
|
||||||
plr.plr->iPCState = 8;
|
plr.plr->iPCState |= 8;
|
||||||
INITSTRUCT(sP_FE2CL_PC_STATE_CHANGE, response2);
|
INITSTRUCT(sP_FE2CL_PC_STATE_CHANGE, response2);
|
||||||
response2.iPC_ID = plr.plr->iID;
|
response2.iPC_ID = plr.plr->iID;
|
||||||
response2.iState = 8;
|
response2.iState = plr.plr->iPCState;
|
||||||
|
|
||||||
for (Chunk* chunk : players[sock].currentChunks) {
|
for (Chunk* chunk : players[sock].currentChunks) {
|
||||||
for (CNSocket* otherSock : chunk->players) {
|
for (CNSocket* otherSock : chunk->players) {
|
||||||
@ -879,20 +879,21 @@ void PlayerManager::enterPlayerVehicle(CNSocket* sock, CNPacketData* data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PlayerManager::exitPlayerVehicle(CNSocket* sock, CNPacketData* data) {
|
void PlayerManager::exitPlayerVehicle(CNSocket* sock, CNPacketData* data) {
|
||||||
|
PlayerView plr = PlayerManager::players[sock];
|
||||||
|
|
||||||
|
if (plr.plr->iPCState & 8) {
|
||||||
INITSTRUCT(sP_FE2CL_PC_VEHICLE_OFF_SUCC, response);
|
INITSTRUCT(sP_FE2CL_PC_VEHICLE_OFF_SUCC, response);
|
||||||
sock->sendPacket((void*)&response, P_FE2CL_PC_VEHICLE_OFF_SUCC, sizeof(sP_FE2CL_PC_VEHICLE_OFF_SUCC));
|
sock->sendPacket((void*)&response, P_FE2CL_PC_VEHICLE_OFF_SUCC, sizeof(sP_FE2CL_PC_VEHICLE_OFF_SUCC));
|
||||||
|
|
||||||
PlayerView plr = PlayerManager::players[sock];
|
|
||||||
|
|
||||||
// send to other players
|
// send to other players
|
||||||
plr.plr->iPCState = 0;
|
plr.plr->iPCState &= ~8;
|
||||||
INITSTRUCT(sP_FE2CL_PC_STATE_CHANGE, response2);
|
INITSTRUCT(sP_FE2CL_PC_STATE_CHANGE, response2);
|
||||||
response2.iPC_ID = plr.plr->iID;
|
response2.iPC_ID = plr.plr->iID;
|
||||||
response2.iState = 0;
|
response2.iState = plr.plr->iPCState;
|
||||||
|
|
||||||
sendToViewable(sock, (void*)&response2, P_FE2CL_PC_STATE_CHANGE, sizeof(sP_FE2CL_PC_STATE_CHANGE));
|
sendToViewable(sock, (void*)&response2, P_FE2CL_PC_STATE_CHANGE, sizeof(sP_FE2CL_PC_STATE_CHANGE));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PlayerManager::setSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data) {
|
void PlayerManager::setSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data) {
|
||||||
setSpecialState(sock, data);
|
setSpecialState(sock, data);
|
||||||
|
Loading…
Reference in New Issue
Block a user