diff --git a/src/Racing.cpp b/src/Racing.cpp index c3b7f6f..2b49f4b 100644 --- a/src/Racing.cpp +++ b/src/Racing.cpp @@ -66,7 +66,7 @@ static void racingCancel(CNSocket* sock, CNPacketData* data) { INITSTRUCT(sP_FE2CL_REP_EP_RACE_CANCEL_SUCC, resp); sock->sendPacket(resp, P_FE2CL_REP_EP_RACE_CANCEL_SUCC); - /* + /* * This request packet is used for both cancelling the race via the * NPC at the start, *and* failing the race by running out of time. * If the latter is to happen, the client disables movement until it @@ -99,31 +99,37 @@ static void racingEnd(CNSocket* sock, CNPacketData* data) { if (EPData.find(mapNum) == EPData.end() || EPData[mapNum].EPID == 0) return; // IZ not found - uint64_t now = getTime() / 1000; + EPInfo& epInfo = EPData[mapNum]; + EPRace& epRace = EPRaces[sock]; - int timeDiff = now - EPRaces[sock].startTime; - int score = 500 * EPRaces[sock].collectedRings.size() - 10 * timeDiff; - if (score < 0) score = 0; // lol - int fm = score * plr->level * (1.0f / 36) * 0.3f; + uint64_t now = getTime() / 1000; + int timeDiff = now - epRace.startTime; + int podsCollected = epRace.collectedRings.size(); + + int score = std::min(epInfo.maxScore, (int)std::exp( + (epInfo.podFactor * podsCollected) / epInfo.maxPods + - (epInfo.timeFactor * timeDiff) / epInfo.maxTime + + epInfo.scaleFactor)); + int fm = (1.0 + std::exp(epInfo.scaleFactor - 1.0) * epInfo.podFactor * podsCollected) / epInfo.maxPods; // we submit the ranking first... Database::RaceRanking postRanking = {}; - postRanking.EPID = EPData[mapNum].EPID; + postRanking.EPID = epInfo.EPID; postRanking.PlayerID = plr->iID; - postRanking.RingCount = EPRaces[sock].collectedRings.size(); + postRanking.RingCount = podsCollected; postRanking.Score = score; postRanking.Time = timeDiff; postRanking.Timestamp = getTimestamp(); Database::postRaceRanking(postRanking); // ...then we get the top ranking, which may or may not be what we just submitted - Database::RaceRanking topRankingPlayer = Database::getTopRaceRanking(EPData[mapNum].EPID, plr->iID); + Database::RaceRanking topRankingPlayer = Database::getTopRaceRanking(epInfo.EPID, plr->iID); INITSTRUCT(sP_FE2CL_REP_EP_RACE_END_SUCC, resp); // get rank scores and rewards - std::vector* rankScores = &EPRewards[EPData[mapNum].EPID].first; - std::vector* rankRewards = &EPRewards[EPData[mapNum].EPID].second; + std::vector* rankScores = &EPRewards[epInfo.EPID].first; + std::vector* rankRewards = &EPRewards[epInfo.EPID].second; // top ranking int topRank = 0; diff --git a/src/Racing.hpp b/src/Racing.hpp index a4f3b6d..c449d2b 100644 --- a/src/Racing.hpp +++ b/src/Racing.hpp @@ -7,7 +7,11 @@ #include struct EPInfo { - int zoneX, zoneY, EPID, maxScore, maxTime; + // available through XDT (maxScore may be updated by drops) + int zoneX, zoneY, EPID, maxScore; + // available through drops + int maxTime, maxPods; + double scaleFactor, podFactor, timeFactor; }; struct EPRace { diff --git a/src/TableData.cpp b/src/TableData.cpp index 68b7cce..63116d4 100644 --- a/src/TableData.cpp +++ b/src/TableData.cpp @@ -375,7 +375,7 @@ static void loadPaths(json& pathData, int32_t* nextId) { Transport::NPCPaths.push_back(pathTemplate); } std::cout << "[INFO] Loaded " << Transport::NPCPaths.size() << " NPC paths" << std::endl; - + } catch (const std::exception& err) { std::cerr << "[FATAL] Malformed paths.json file! Reason:" << err.what() << std::endl; @@ -584,8 +584,17 @@ static void loadDrops(json& dropData) { continue; } - // time limit isn't stored in the XDT, so we include it in the reward table instead - Racing::EPData[EPMap].maxTime = race["TimeLimit"]; + EPInfo& epInfo = Racing::EPData[EPMap]; + + // max score is specified in the XDT, but can be updated if specified in the drops JSON + epInfo.maxScore = (int)race["ScoreCap"]; + // time limit and total pods are not stored in the XDT, so we include it in the drops JSON + epInfo.maxTime = (int)race["TimeLimit"]; + epInfo.maxPods = (int)race["TotalPods"]; + // IZ-specific calculated constants included in the drops JSON + epInfo.scaleFactor = (double)race["ScaleFactor"]; + epInfo.podFactor = (double)race["PodFactor"]; + epInfo.timeFactor = (double)race["TimeFactor"]; // score cutoffs std::vector rankScores; @@ -686,7 +695,7 @@ static void loadEggs(json& eggData, int32_t* nextId) { } } -/* +/* * Load gruntwork output, if it exists */ static void loadGruntworkPre(json& gruntwork, int32_t* nextId) { @@ -1361,7 +1370,7 @@ void TableData::flush() { targetIDs.push_back(tID); for (int32_t tType : path.targetTypes) targetTypes.push_back(tType); - + pathObj["iBaseSpeed"] = path.speed; pathObj["iTaskID"] = path.escortTaskID; pathObj["bRelative"] = path.isRelative; diff --git a/tdata b/tdata index cc65dbb..8c98c83 160000 --- a/tdata +++ b/tdata @@ -1 +1 @@ -Subproject commit cc65dbb402b5baa2b604ed66132edd88cc82a52a +Subproject commit 8c98c8368243a6e2a10cc5fe273236754f896e6a