Compare commits

...

5 Commits

Author SHA1 Message Date
FinnHornhoover 2464e4adda
Merge e88ef52d12 into 4592fc42af 2023-10-10 20:06:43 +00:00
FinnHornhoover e88ef52d12
commented out default config value
Co-authored-by: Gent Semaj <gsemaj@proton.me>
2023-10-10 23:06:42 +03:00
FinnHornhoover 30b2f4eb36 added config option for racing score modes 2023-10-10 22:36:10 +03:00
gsemaj 4592fc42af
CI/CD improvements
- PR builds will now run even if they weren't opened as drafts
- PR builds will now re-run when they get new commits
- Builds can now be manually triggered from GitHub
2023-10-10 14:35:07 -04:00
FinnHornhoover f4b36b8f73 added alternate racing score funcitonality 2023-07-24 00:33:19 +03:00
7 changed files with 55 additions and 17 deletions

View File

@ -9,12 +9,13 @@ on:
- CMakeLists.txt
- Makefile
pull_request:
types: ready_for_review
types: [opened, reopened, synchronize, ready_for_review]
paths:
- src/**
- vendor/**
- CMakeLists.txt
- Makefile
workflow_dispatch:
jobs:
ubuntu-build:

View File

@ -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

View File

@ -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<int>* rankScores = &EPRewards[EPData[mapNum].EPID].first;
std::vector<int>* rankRewards = &EPRewards[EPData[mapNum].EPID].second;
std::vector<int>* rankScores = &EPRewards[epInfo.EPID].first;
std::vector<int>* rankRewards = &EPRewards[epInfo.EPID].second;
// top ranking
int topRank = 0;

View File

@ -7,7 +7,11 @@
#include <set>
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 {

View File

@ -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<int> 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;

View File

@ -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);

View File

@ -38,6 +38,7 @@ namespace settings {
extern int MONITORPORT;
extern int MONITORINTERVAL;
extern bool DISABLEFIRSTUSEFLAG;
extern bool OGRACINGSCORES;
void init();
}