OpenFusion/src/RacingManager.cpp

149 lines
4.9 KiB
C++
Raw Normal View History

2020-11-28 13:29:06 +00:00
#include "CNShardServer.hpp"
#include "CNStructs.hpp"
#include "RacingManager.hpp"
2020-11-28 16:20:37 +00:00
#include "PlayerManager.hpp"
#include "MissionManager.hpp"
#include "ItemManager.hpp"
2020-12-14 20:09:41 +00:00
#include "Database.hpp"
#include "NPCManager.hpp"
2020-11-28 13:29:06 +00:00
2020-11-28 14:16:14 +00:00
std::map<int32_t, EPInfo> RacingManager::EPData;
2020-11-28 16:20:37 +00:00
std::map<CNSocket*, EPRace> RacingManager::EPRaces;
2020-12-22 04:55:43 +00:00
std::map<int32_t, std::pair<std::vector<int>, std::vector<int>>> RacingManager::EPRewards;
2020-11-28 13:29:06 +00:00
2020-11-28 14:16:14 +00:00
void RacingManager::init() {
2020-11-28 16:20:37 +00:00
REGISTER_SHARD_PACKET(P_CL2FE_REQ_EP_RACE_START, racingStart);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_EP_GET_RING, racingGetPod);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_EP_RACE_CANCEL, racingCancel);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_EP_RACE_END, racingEnd);
2020-11-28 13:29:06 +00:00
}
2020-11-28 14:16:14 +00:00
2020-11-28 16:20:37 +00:00
void RacingManager::racingStart(CNSocket* sock, CNPacketData* data) {
if (data->size != sizeof(sP_CL2FE_REQ_EP_RACE_START))
return; // malformed packet
sP_CL2FE_REQ_EP_RACE_START* req = (sP_CL2FE_REQ_EP_RACE_START*)data->buf;
// make ongoing race entry
EPRace race = { 0, req->iEPRaceMode, req->iEPTicketItemSlotNum, getTime() / 1000 };
EPRaces[sock] = race;
INITSTRUCT(sP_FE2CL_REP_EP_RACE_START_SUCC, resp);
resp.iStartTick = 0; // ignored
resp.iLimitTime = 60 * 20; // TODO: calculate(?) this properly
sock->sendPacket((void*)&resp, P_FE2CL_REP_EP_RACE_START_SUCC, sizeof(sP_FE2CL_REP_EP_RACE_START_SUCC));
}
void RacingManager::racingGetPod(CNSocket* sock, CNPacketData* data) {
if (data->size != sizeof(sP_CL2FE_REQ_EP_GET_RING))
return; // malformed packet
if (EPRaces.find(sock) == EPRaces.end())
return; // race not found
sP_CL2FE_REQ_EP_GET_RING* req = (sP_CL2FE_REQ_EP_GET_RING*)data->buf;
EPRaces[sock].ringCount++;
INITSTRUCT(sP_FE2CL_REP_EP_GET_RING_SUCC, resp);
resp.iRingLID = req->iRingLID;
resp.iRingCount_Get = EPRaces[sock].ringCount;
sock->sendPacket((void*)&resp, P_FE2CL_REP_EP_GET_RING_SUCC, sizeof(sP_FE2CL_REP_EP_GET_RING_SUCC));
}
void RacingManager::racingCancel(CNSocket* sock, CNPacketData* data) {
if (data->size != sizeof(sP_CL2FE_REQ_EP_RACE_CANCEL))
return; // malformed packet
if (EPRaces.find(sock) == EPRaces.end())
return; // race not found
EPRaces.erase(sock);
INITSTRUCT(sP_FE2CL_REP_EP_RACE_CANCEL_SUCC, resp);
sock->sendPacket((void*)&resp, P_FE2CL_REP_EP_RACE_CANCEL_SUCC, sizeof(sP_FE2CL_REP_EP_RACE_CANCEL_SUCC));
}
void RacingManager::racingEnd(CNSocket* sock, CNPacketData* data) {
if (data->size != sizeof(sP_CL2FE_REQ_EP_RACE_END))
return; // malformed packet
if (EPRaces.find(sock) == EPRaces.end())
return; // race not found
sP_CL2FE_REQ_EP_RACE_END* req = (sP_CL2FE_REQ_EP_RACE_END*)data->buf;
Player* plr = PlayerManager::getPlayer(sock);
2020-12-14 20:09:41 +00:00
if (NPCManager::NPCs.find(req->iEndEcomID) == NPCManager::NPCs.end())
return; // finish line agent not found
int mapNum = MAPNUM(NPCManager::NPCs[req->iEndEcomID]->instanceID);
if (EPData.find(mapNum) == EPData.end() || EPData[mapNum].EPID == 0)
return; // IZ not found
uint64_t now = getTime() / 1000;
int timeDiff = now - EPRaces[sock].startTime;
2020-11-28 16:20:37 +00:00
int score = 500 * EPRaces[sock].ringCount - 10 * timeDiff;
2020-12-14 21:59:34 +00:00
if (score < 0) score = 0; // lol
int fm = score * plr->level * (1.0f / 36) * 0.3f;
2020-12-14 20:09:41 +00:00
// we submit the ranking first...
Database::RaceRanking postRanking = {};
postRanking.EPID = EPData[mapNum].EPID;
postRanking.PlayerID = plr->iID;
postRanking.RingCount = EPRaces[sock].ringCount;
postRanking.Score = score;
postRanking.Time = timeDiff;
postRanking.Timestamp = now;
Database::postRaceRanking(postRanking);
// ...then we get the top ranking, which may or may not be what we just submitted
2020-12-14 21:59:34 +00:00
Database::RaceRanking topRankingGlobal = Database::getTopRaceRanking(EPData[mapNum].EPID, -1);
Database::RaceRanking topRankingPlayer = Database::getTopRaceRanking(EPData[mapNum].EPID, plr->iID);
2020-11-28 16:20:37 +00:00
INITSTRUCT(sP_FE2CL_REP_EP_RACE_END_SUCC, resp);
2020-12-14 21:59:34 +00:00
resp.iEPTopRank = 1; // top score is always 5 stars, since we're doing it relative to first place
resp.iEPTopRingCount = topRankingPlayer.RingCount;
resp.iEPTopScore = topRankingPlayer.Score;
resp.iEPTopTime = topRankingPlayer.Time;
2020-12-14 20:09:41 +00:00
resp.iEPRaceMode = EPRaces[sock].mode;
2020-12-14 21:59:34 +00:00
if (topRankingGlobal.Score == 0)
resp.iEPRank = 5; // don't divide by zero, just give them the single star they deserve
else
resp.iEPRank = 5 - ((score * 4.0) / topRankingGlobal.Score); // 5 - [0, 4] = [5, 1]
2020-12-14 20:09:41 +00:00
resp.iEPRingCnt = postRanking.RingCount;
resp.iEPScore = postRanking.Score;
resp.iEPRaceTime = postRanking.Time;
resp.iEPRewardFM = fm;
2020-11-28 16:20:37 +00:00
MissionManager::updateFusionMatter(sock, resp.iEPRewardFM);
resp.iFusionMatter = plr->fusionmatter;
resp.iFatigue = 50;
resp.iFatigue_Level = 1;
sItemReward reward;
reward.iSlotNum = ItemManager::findFreeSlot(plr);
reward.eIL = 1;
sItemBase item;
item.iID = 96;
item.iType = 0;
item.iOpt = 1;
reward.sItem = item;
2020-12-14 20:09:41 +00:00
if (reward.iSlotNum > -1) {
2020-11-28 16:20:37 +00:00
resp.RewardItem = reward;
plr->Inven[reward.iSlotNum] = item;
}
2020-12-14 20:09:41 +00:00
EPRaces.erase(sock);
2020-11-28 16:20:37 +00:00
sock->sendPacket((void*)&resp, P_FE2CL_REP_EP_RACE_END_SUCC, sizeof(sP_FE2CL_REP_EP_RACE_END_SUCC));
}
2020-11-28 14:16:14 +00:00