diff --git a/config.ini b/config.ini index fb7977d..c4d73fb 100644 --- a/config.ini +++ b/config.ini @@ -51,6 +51,11 @@ motd=Welcome to OpenFusion! # and pre-Academy builds must *not* contain it. #enabledpatches=1013 +# Use Original FusionFall's racing score and reward calculation? +# Set false to use Retro's calculation, make sure you have the correct +# patch(es) loaded. +#ogracingscores=true + # xdt json filename #xdtdata=xdt.json # NPC json filename diff --git a/src/Racing.cpp b/src/Racing.cpp index c3b7f6f..f4ef0cf 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,43 @@ 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 = 0, fm = 0; + + if (settings::OGRACINGSCORES) { + score = std::min(epInfo.maxScore, (int)std::exp( + (epInfo.podFactor * podsCollected) / epInfo.maxPods + - (epInfo.timeFactor * timeDiff) / epInfo.maxTime + + epInfo.scaleFactor)); + fm = (1.0 + std::exp(epInfo.scaleFactor - 1.0) * epInfo.podFactor * podsCollected) / epInfo.maxPods; + } else { + score = std::max(0, 500 * podsCollected - 10 * timeDiff); + fm = score * plr->level * (1.0f / 36) * 0.3f; + } // 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..6da0779 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; + // (maybe) available through drops + int maxTime = 0, maxPods = 0; + double scaleFactor = 0.0, podFactor = 0.0, timeFactor = 0.0; }; struct EPRace { diff --git a/src/TableData.cpp b/src/TableData.cpp index 68b7cce..6997770 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,19 @@ static void loadDrops(json& dropData) { continue; } + EPInfo& epInfo = Racing::EPData[EPMap]; + // time limit isn't stored in the XDT, so we include it in the reward table instead - Racing::EPData[EPMap].maxTime = race["TimeLimit"]; + epInfo.maxTime = (int)race["TimeLimit"]; + + // the following has to be present based on the score calculation method + if (settings::OGRACINGSCORES) { + epInfo.maxScore = (int)race["ScoreCap"]; + epInfo.maxPods = (int)race["TotalPods"]; + epInfo.scaleFactor = (double)race["ScaleFactor"]; + epInfo.podFactor = (double)race["PodFactor"]; + epInfo.timeFactor = (double)race["TimeFactor"]; + } // score cutoffs std::vector rankScores; @@ -686,7 +697,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 +1372,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/src/settings.cpp b/src/settings.cpp index 45d2cfc..69e3cdf 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -67,6 +67,9 @@ int settings::MONITORINTERVAL = 5000; // event mode settings int settings::EVENTMODE = 0; +// racing score mode +bool settings::OGRACINGSCORES = true; + void settings::init() { INIReader reader("config.ini"); @@ -111,6 +114,7 @@ void settings::init() { EVENTMODE = reader.GetInteger("shard", "eventmode", EVENTMODE); DISABLEFIRSTUSEFLAG = reader.GetBoolean("shard", "disablefirstuseflag", DISABLEFIRSTUSEFLAG); ANTICHEAT = reader.GetBoolean("shard", "anticheat", ANTICHEAT); + OGRACINGSCORES = reader.GetBoolean("shard", "ogracingscores", OGRACINGSCORES); MONITORENABLED = reader.GetBoolean("monitor", "enabled", MONITORENABLED); MONITORPORT = reader.GetInteger("monitor", "port", MONITORPORT); MONITORINTERVAL = reader.GetInteger("monitor", "interval", MONITORINTERVAL); diff --git a/src/settings.hpp b/src/settings.hpp index 097a1cd..6e3243b 100644 --- a/src/settings.hpp +++ b/src/settings.hpp @@ -38,6 +38,7 @@ namespace settings { extern int MONITORPORT; extern int MONITORINTERVAL; extern bool DISABLEFIRSTUSEFLAG; + extern bool OGRACINGSCORES; void init(); }