mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2025-10-27 14:50:05 +00:00
Compare commits
12 Commits
refactor
...
2464e4adda
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2464e4adda | ||
|
|
e88ef52d12 | ||
|
|
30b2f4eb36 | ||
|
|
4592fc42af | ||
|
|
70a27afad1 | ||
|
|
6cfb3bf532 | ||
|
|
ab480d88f1 | ||
|
|
89772d763b | ||
| bd0cc3c212 | |||
| c636c538eb | |||
| d3bef95a7f | |||
|
|
f4b36b8f73 |
7
.github/workflows/check-builds.yaml
vendored
7
.github/workflows/check-builds.yaml
vendored
@@ -9,12 +9,13 @@ on:
|
|||||||
- CMakeLists.txt
|
- CMakeLists.txt
|
||||||
- Makefile
|
- Makefile
|
||||||
pull_request:
|
pull_request:
|
||||||
types: ready_for_review
|
types: [opened, reopened, synchronize, ready_for_review]
|
||||||
paths:
|
paths:
|
||||||
- src/**
|
- src/**
|
||||||
- vendor/**
|
- vendor/**
|
||||||
- CMakeLists.txt
|
- CMakeLists.txt
|
||||||
- Makefile
|
- Makefile
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ubuntu-build:
|
ubuntu-build:
|
||||||
@@ -53,7 +54,7 @@ jobs:
|
|||||||
- name: Upload build artifact
|
- name: Upload build artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: 'ubuntu20_04-bin-x64-${{ env.SHORT_SHA }}'
|
name: 'ubuntu22_04-bin-x64-${{ env.SHORT_SHA }}'
|
||||||
path: bin
|
path: bin
|
||||||
|
|
||||||
windows-build:
|
windows-build:
|
||||||
@@ -112,7 +113,7 @@ jobs:
|
|||||||
|
|
||||||
copy-artifacts:
|
copy-artifacts:
|
||||||
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/master'
|
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/master'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
needs: [windows-build, ubuntu-build]
|
needs: [windows-build, ubuntu-build]
|
||||||
env:
|
env:
|
||||||
BOT_SSH_KEY: ${{ secrets.BOT_SSH_KEY }}
|
BOT_SSH_KEY: ${{ secrets.BOT_SSH_KEY }}
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ OpenFusion is a reverse-engineered server for FusionFall. It primarily targets v
|
|||||||
|
|
||||||
### Getting Started
|
### Getting Started
|
||||||
#### Method A: Installer (Easiest)
|
#### Method A: Installer (Easiest)
|
||||||
1. Download the client installer by clicking [here](https://github.com/OpenFusionProject/OpenFusion/releases/download/1.4/OpenFusionClient-1.4-Installer.exe) - choose to run the file.
|
1. Download the client installer by clicking [here](https://github.com/OpenFusionProject/OpenFusion/releases/download/1.5/OpenFusionClient-1.5-Installer.exe) - choose to run the file.
|
||||||
2. After a few moments, the client should open: you will be given a choice between two public servers by default. Select the one you wish to play and click connect.
|
2. After a few moments, the client should open: you will be given a choice between two public servers by default. Select the one you wish to play and click connect.
|
||||||
3. To create an account, simply enter the details you wish to use at the login screen then click Log In. Do *not* click register, as this will just lead to a blank screen.
|
3. To create an account, simply enter the details you wish to use at the login screen then click Log In. Do *not* click register, as this will just lead to a blank screen.
|
||||||
4. Make a new character, and enjoy the game! Your progress will be saved automatically, and you can resume playing by entering the login details you used in step 3.
|
4. Make a new character, and enjoy the game! Your progress will be saved automatically, and you can resume playing by entering the login details you used in step 3.
|
||||||
|
|
||||||
#### Method B: Standalone .zip file
|
#### Method B: Standalone .zip file
|
||||||
1. Download the client from [here](https://github.com/OpenFusionProject/OpenFusion/releases/download/1.4/OpenFusionClient-1.4.zip).
|
1. Download the client from [here](https://github.com/OpenFusionProject/OpenFusion/releases/download/1.5/OpenFusionClient-1.5.zip).
|
||||||
2. Extract it to a folder of your choice. Note: if you are upgrading from an older version, it is preferable to start with a fresh folder rather than overwriting a previous install.
|
2. Extract it to a folder of your choice. Note: if you are upgrading from an older version, it is preferable to start with a fresh folder rather than overwriting a previous install.
|
||||||
3. Run OpenFusionClient.exe - you will be given a choice between two public servers by default. Select the one you wish to play and click connect.
|
3. Run OpenFusionClient.exe - you will be given a choice between two public servers by default. Select the one you wish to play and click connect.
|
||||||
4. To create an account, simply enter the details you wish to use at the login screen then click Log In. Do *not* click register, as this will just lead to a blank screen.
|
4. To create an account, simply enter the details you wish to use at the login screen then click Log In. Do *not* click register, as this will just lead to a blank screen.
|
||||||
@@ -29,7 +29,7 @@ Instructions for getting the client to run on Linux through Wine can be found [h
|
|||||||
|
|
||||||
### Hosting a server
|
### Hosting a server
|
||||||
|
|
||||||
1. Grab `OpenFusionServer-1.4-original.zip` or `OpenFusionServer-1.4-academy.zip` from [here](https://github.com/OpenFusionProject/OpenFusion/releases/tag/1.4).
|
1. Grab `OpenFusionServer-1.5-original.zip` or `OpenFusionServer-1.5-academy.zip` from [here](https://github.com/OpenFusionProject/OpenFusion/releases/tag/1.5).
|
||||||
2. Extract it to a folder of your choice, then run `winfusion.exe` (Windows) or `fusion` (Linux) to start the server.
|
2. Extract it to a folder of your choice, then run `winfusion.exe` (Windows) or `fusion` (Linux) to start the server.
|
||||||
3. Add a new server to the client's list:
|
3. Add a new server to the client's list:
|
||||||
1. For Description, enter anything you want. This is what will show up in the server list.
|
1. For Description, enter anything you want. This is what will show up in the server list.
|
||||||
|
|||||||
@@ -51,6 +51,11 @@ motd=Welcome to OpenFusion!
|
|||||||
# and pre-Academy builds must *not* contain it.
|
# and pre-Academy builds must *not* contain it.
|
||||||
#enabledpatches=1013
|
#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
|
# xdt json filename
|
||||||
#xdtdata=xdt.json
|
#xdtdata=xdt.json
|
||||||
# NPC json filename
|
# NPC json filename
|
||||||
|
|||||||
@@ -72,31 +72,41 @@ static void setValuePlayer(CNSocket* sock, CNPacketData* data) {
|
|||||||
|
|
||||||
// Handle serverside value-changes
|
// Handle serverside value-changes
|
||||||
switch (setData->iSetValueType) {
|
switch (setData->iSetValueType) {
|
||||||
case 1:
|
case CN_GM_SET_VALUE_TYPE__HP:
|
||||||
plr->HP = setData->iSetValue;
|
response.iSetValue = plr->HP = setData->iSetValue;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case CN_GM_SET_VALUE_TYPE__WEAPON_BATTERY :
|
||||||
plr->batteryW = setData->iSetValue;
|
plr->batteryW = setData->iSetValue;
|
||||||
|
|
||||||
// caps
|
// caps
|
||||||
if (plr->batteryW > 9999)
|
if (plr->batteryW > 9999)
|
||||||
plr->batteryW = 9999;
|
plr->batteryW = 9999;
|
||||||
|
|
||||||
|
response.iSetValue = plr->batteryW;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case CN_GM_SET_VALUE_TYPE__NANO_BATTERY:
|
||||||
plr->batteryN = setData->iSetValue;
|
plr->batteryN = setData->iSetValue;
|
||||||
|
|
||||||
// caps
|
// caps
|
||||||
if (plr->batteryN > 9999)
|
if (plr->batteryN > 9999)
|
||||||
plr->batteryN = 9999;
|
plr->batteryN = 9999;
|
||||||
|
|
||||||
|
response.iSetValue = plr->batteryN;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case CN_GM_SET_VALUE_TYPE__FUSION_MATTER:
|
||||||
Missions::updateFusionMatter(sock, setData->iSetValue - plr->fusionmatter);
|
Missions::updateFusionMatter(sock, setData->iSetValue - plr->fusionmatter);
|
||||||
|
response.iSetValue = plr->fusionmatter;
|
||||||
break;
|
break;
|
||||||
case 5:
|
case CN_GM_SET_VALUE_TYPE__CANDY:
|
||||||
plr->money = setData->iSetValue;
|
response.iSetValue = plr->money = setData->iSetValue;
|
||||||
|
break;
|
||||||
|
case CN_GM_SET_VALUE_TYPE__SPEED:
|
||||||
|
case CN_GM_SET_VALUE_TYPE__JUMP:
|
||||||
|
response.iSetValue = setData->iSetValue;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
response.iPC_ID = setData->iPC_ID;
|
response.iPC_ID = setData->iPC_ID;
|
||||||
response.iSetValue = setData->iSetValue;
|
|
||||||
response.iSetValueType = setData->iSetValueType;
|
response.iSetValueType = setData->iSetValueType;
|
||||||
|
|
||||||
sock->sendPacket(response, P_FE2CL_GM_REP_PC_SET_VALUE);
|
sock->sendPacket(response, P_FE2CL_GM_REP_PC_SET_VALUE);
|
||||||
|
|||||||
@@ -359,23 +359,19 @@ static void npcRotateCommand(std::string full, std::vector<std::string>& args, C
|
|||||||
int angle = (plr->angle + 180) % 360;
|
int angle = (plr->angle + 180) % 360;
|
||||||
NPCManager::updateNPCPosition(npc->id, npc->x, npc->y, npc->z, npc->instanceID, angle);
|
NPCManager::updateNPCPosition(npc->id, npc->x, npc->y, npc->z, npc->instanceID, angle);
|
||||||
|
|
||||||
// if it's a gruntwork NPC, rotate in-place
|
bool isGruntworkNpc = true;
|
||||||
if (TableData::RunningMobs.find(npc->id) != TableData::RunningMobs.end()) {
|
|
||||||
NPCManager::updateNPCPosition(npc->id, npc->x, npc->y, npc->z, npc->instanceID, angle);
|
|
||||||
|
|
||||||
Chat::sendServerMessage(sock, "[NPCR] Successfully set angle to " + std::to_string(angle) + " for gruntwork NPC "
|
// add a rotation entry to the gruntwork file, unless it's already a gruntwork NPC
|
||||||
+ std::to_string(npc->id));
|
if (TableData::RunningMobs.find(npc->id) == TableData::RunningMobs.end()) {
|
||||||
} else {
|
|
||||||
TableData::RunningNPCRotations[npc->id] = angle;
|
TableData::RunningNPCRotations[npc->id] = angle;
|
||||||
|
isGruntworkNpc = false;
|
||||||
Chat::sendServerMessage(sock, "[NPCR] Successfully set angle to " + std::to_string(angle) + " for NPC "
|
|
||||||
+ std::to_string(npc->id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// update rotation clientside
|
Chat::sendServerMessage(sock, "[NPCR] Successfully set angle to " + std::to_string(angle) +
|
||||||
INITSTRUCT(sP_FE2CL_NPC_ENTER, pkt);
|
" for " + (isGruntworkNpc ? "gruntwork " : "") + "NPC " + std::to_string(npc->id));
|
||||||
pkt.NPCAppearanceData = npc->getAppearanceData();
|
|
||||||
sock->sendPacket(pkt, P_FE2CL_NPC_ENTER);
|
// update rotation clientside by refreshing the player's chunks (same as the /refresh command)
|
||||||
|
PlayerManager::updatePlayerPositionForWarp(sock, plr->x, plr->y, plr->z, plr->instanceID);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void refreshCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
static void refreshCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
|||||||
@@ -77,7 +77,10 @@ void PlayerManager::updatePlayerPosition(CNSocket* sock, int X, int Y, int Z, ui
|
|||||||
plr->x = X;
|
plr->x = X;
|
||||||
plr->y = Y;
|
plr->y = Y;
|
||||||
plr->z = Z;
|
plr->z = Z;
|
||||||
plr->instanceID = I;
|
if (plr->instanceID != I) {
|
||||||
|
plr->instanceID = I;
|
||||||
|
plr->recallInstance = INSTANCE_OVERWORLD;
|
||||||
|
}
|
||||||
if (oldChunk == newChunk)
|
if (oldChunk == newChunk)
|
||||||
return; // didn't change chunks
|
return; // didn't change chunks
|
||||||
Chunking::updateEntityChunk({sock}, oldChunk, newChunk);
|
Chunking::updateEntityChunk({sock}, oldChunk, newChunk);
|
||||||
@@ -123,24 +126,6 @@ void PlayerManager::sendPlayerTo(CNSocket* sock, int X, int Y, int Z, uint64_t I
|
|||||||
sock->sendPacket(resp, P_FE2CL_REP_PC_WARP_USE_NPC_SUCC);
|
sock->sendPacket(resp, P_FE2CL_REP_PC_WARP_USE_NPC_SUCC);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (I != INSTANCE_OVERWORLD) {
|
|
||||||
INITSTRUCT(sP_FE2CL_INSTANCE_MAP_INFO, pkt);
|
|
||||||
pkt.iInstanceMapNum = (int32_t)MAPNUM(I); // lower 32 bits are mapnum
|
|
||||||
if (I != fromInstance // do not retransmit MAP_INFO on recall
|
|
||||||
&& Racing::EPData.find(pkt.iInstanceMapNum) != Racing::EPData.end()) {
|
|
||||||
EPInfo* ep = &Racing::EPData[pkt.iInstanceMapNum];
|
|
||||||
pkt.iEP_ID = ep->EPID;
|
|
||||||
pkt.iMapCoordX_Min = ep->zoneX * 51200;
|
|
||||||
pkt.iMapCoordX_Max = (ep->zoneX + 1) * 51200;
|
|
||||||
pkt.iMapCoordY_Min = ep->zoneY * 51200;
|
|
||||||
pkt.iMapCoordY_Max = (ep->zoneY + 1) * 51200;
|
|
||||||
pkt.iMapCoordZ_Min = INT32_MIN;
|
|
||||||
pkt.iMapCoordZ_Max = INT32_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
sock->sendPacket(pkt, P_FE2CL_INSTANCE_MAP_INFO);
|
|
||||||
}
|
|
||||||
|
|
||||||
INITSTRUCT(sP_FE2CL_REP_PC_GOTO_SUCC, pkt2);
|
INITSTRUCT(sP_FE2CL_REP_PC_GOTO_SUCC, pkt2);
|
||||||
pkt2.iX = X;
|
pkt2.iX = X;
|
||||||
pkt2.iY = Y;
|
pkt2.iY = Y;
|
||||||
@@ -374,6 +359,24 @@ static void loadPlayer(CNSocket* sock, CNPacketData* data) {
|
|||||||
updatePlayerPosition(sock, plr->x, plr->y, plr->z, plr->instanceID, plr->angle);
|
updatePlayerPosition(sock, plr->x, plr->y, plr->z, plr->instanceID, plr->angle);
|
||||||
|
|
||||||
sock->sendPacket(response, P_FE2CL_REP_PC_LOADING_COMPLETE_SUCC);
|
sock->sendPacket(response, P_FE2CL_REP_PC_LOADING_COMPLETE_SUCC);
|
||||||
|
|
||||||
|
if (plr->instanceID != INSTANCE_OVERWORLD) {
|
||||||
|
INITSTRUCT(sP_FE2CL_INSTANCE_MAP_INFO, pkt);
|
||||||
|
pkt.iInstanceMapNum = (int32_t)MAPNUM(plr->instanceID); // lower 32 bits are mapnum
|
||||||
|
if (pkt.iInstanceMapNum != plr->recallInstance // do not retransmit MAP_INFO on recall
|
||||||
|
&& Racing::EPData.find(pkt.iInstanceMapNum) != Racing::EPData.end()) {
|
||||||
|
EPInfo* ep = &Racing::EPData[pkt.iInstanceMapNum];
|
||||||
|
pkt.iEP_ID = ep->EPID;
|
||||||
|
pkt.iMapCoordX_Min = ep->zoneX * 51200;
|
||||||
|
pkt.iMapCoordX_Max = (ep->zoneX + 1) * 51200;
|
||||||
|
pkt.iMapCoordY_Min = ep->zoneY * 51200;
|
||||||
|
pkt.iMapCoordY_Max = (ep->zoneY + 1) * 51200;
|
||||||
|
pkt.iMapCoordZ_Min = INT32_MIN;
|
||||||
|
pkt.iMapCoordZ_Max = INT32_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
sock->sendPacket(pkt, P_FE2CL_INSTANCE_MAP_INFO);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void heartbeatPlayer(CNSocket* sock, CNPacketData* data) {
|
static void heartbeatPlayer(CNSocket* sock, CNPacketData* data) {
|
||||||
@@ -577,7 +580,7 @@ static void setFirstUseFlag(CNSocket* sock, CNPacketData* data) {
|
|||||||
std::cout << "[WARN] Client submitted invalid first use flag number?!" << std::endl;
|
std::cout << "[WARN] Client submitted invalid first use flag number?!" << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flag->iFlagCode <= 64)
|
if (flag->iFlagCode <= 64)
|
||||||
plr->iFirstUseFlag[0] |= (1ULL << (flag->iFlagCode - 1));
|
plr->iFirstUseFlag[0] |= (1ULL << (flag->iFlagCode - 1));
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ static void racingCancel(CNSocket* sock, CNPacketData* data) {
|
|||||||
INITSTRUCT(sP_FE2CL_REP_EP_RACE_CANCEL_SUCC, resp);
|
INITSTRUCT(sP_FE2CL_REP_EP_RACE_CANCEL_SUCC, resp);
|
||||||
sock->sendPacket(resp, P_FE2CL_REP_EP_RACE_CANCEL_SUCC);
|
sock->sendPacket(resp, P_FE2CL_REP_EP_RACE_CANCEL_SUCC);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This request packet is used for both cancelling the race via the
|
* 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.
|
* 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
|
* 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)
|
if (EPData.find(mapNum) == EPData.end() || EPData[mapNum].EPID == 0)
|
||||||
return; // IZ not found
|
return; // IZ not found
|
||||||
|
|
||||||
uint64_t now = getTime() / 1000;
|
EPInfo& epInfo = EPData[mapNum];
|
||||||
|
EPRace& epRace = EPRaces[sock];
|
||||||
|
|
||||||
int timeDiff = now - EPRaces[sock].startTime;
|
uint64_t now = getTime() / 1000;
|
||||||
int score = 500 * EPRaces[sock].collectedRings.size() - 10 * timeDiff;
|
int timeDiff = now - epRace.startTime;
|
||||||
if (score < 0) score = 0; // lol
|
int podsCollected = epRace.collectedRings.size();
|
||||||
int fm = score * plr->level * (1.0f / 36) * 0.3f;
|
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...
|
// we submit the ranking first...
|
||||||
Database::RaceRanking postRanking = {};
|
Database::RaceRanking postRanking = {};
|
||||||
postRanking.EPID = EPData[mapNum].EPID;
|
postRanking.EPID = epInfo.EPID;
|
||||||
postRanking.PlayerID = plr->iID;
|
postRanking.PlayerID = plr->iID;
|
||||||
postRanking.RingCount = EPRaces[sock].collectedRings.size();
|
postRanking.RingCount = podsCollected;
|
||||||
postRanking.Score = score;
|
postRanking.Score = score;
|
||||||
postRanking.Time = timeDiff;
|
postRanking.Time = timeDiff;
|
||||||
postRanking.Timestamp = getTimestamp();
|
postRanking.Timestamp = getTimestamp();
|
||||||
Database::postRaceRanking(postRanking);
|
Database::postRaceRanking(postRanking);
|
||||||
|
|
||||||
// ...then we get the top ranking, which may or may not be what we just submitted
|
// ...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);
|
INITSTRUCT(sP_FE2CL_REP_EP_RACE_END_SUCC, resp);
|
||||||
|
|
||||||
// get rank scores and rewards
|
// get rank scores and rewards
|
||||||
std::vector<int>* rankScores = &EPRewards[EPData[mapNum].EPID].first;
|
std::vector<int>* rankScores = &EPRewards[epInfo.EPID].first;
|
||||||
std::vector<int>* rankRewards = &EPRewards[EPData[mapNum].EPID].second;
|
std::vector<int>* rankRewards = &EPRewards[epInfo.EPID].second;
|
||||||
|
|
||||||
// top ranking
|
// top ranking
|
||||||
int topRank = 0;
|
int topRank = 0;
|
||||||
|
|||||||
@@ -7,7 +7,11 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
struct EPInfo {
|
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 {
|
struct EPRace {
|
||||||
|
|||||||
@@ -375,7 +375,7 @@ static void loadPaths(json& pathData, int32_t* nextId) {
|
|||||||
Transport::NPCPaths.push_back(pathTemplate);
|
Transport::NPCPaths.push_back(pathTemplate);
|
||||||
}
|
}
|
||||||
std::cout << "[INFO] Loaded " << Transport::NPCPaths.size() << " NPC paths" << std::endl;
|
std::cout << "[INFO] Loaded " << Transport::NPCPaths.size() << " NPC paths" << std::endl;
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (const std::exception& err) {
|
catch (const std::exception& err) {
|
||||||
std::cerr << "[FATAL] Malformed paths.json file! Reason:" << err.what() << std::endl;
|
std::cerr << "[FATAL] Malformed paths.json file! Reason:" << err.what() << std::endl;
|
||||||
@@ -584,8 +584,19 @@ static void loadDrops(json& dropData) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EPInfo& epInfo = Racing::EPData[EPMap];
|
||||||
|
|
||||||
// time limit isn't stored in the XDT, so we include it in the reward table instead
|
// 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
|
// score cutoffs
|
||||||
std::vector<int> rankScores;
|
std::vector<int> rankScores;
|
||||||
@@ -686,7 +697,7 @@ static void loadEggs(json& eggData, int32_t* nextId) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Load gruntwork output, if it exists
|
* Load gruntwork output, if it exists
|
||||||
*/
|
*/
|
||||||
static void loadGruntworkPre(json& gruntwork, int32_t* nextId) {
|
static void loadGruntworkPre(json& gruntwork, int32_t* nextId) {
|
||||||
@@ -1361,7 +1372,7 @@ void TableData::flush() {
|
|||||||
targetIDs.push_back(tID);
|
targetIDs.push_back(tID);
|
||||||
for (int32_t tType : path.targetTypes)
|
for (int32_t tType : path.targetTypes)
|
||||||
targetTypes.push_back(tType);
|
targetTypes.push_back(tType);
|
||||||
|
|
||||||
pathObj["iBaseSpeed"] = path.speed;
|
pathObj["iBaseSpeed"] = path.speed;
|
||||||
pathObj["iTaskID"] = path.escortTaskID;
|
pathObj["iTaskID"] = path.escortTaskID;
|
||||||
pathObj["bRelative"] = path.isRelative;
|
pathObj["bRelative"] = path.isRelative;
|
||||||
|
|||||||
@@ -67,6 +67,9 @@ int settings::MONITORINTERVAL = 5000;
|
|||||||
// event mode settings
|
// event mode settings
|
||||||
int settings::EVENTMODE = 0;
|
int settings::EVENTMODE = 0;
|
||||||
|
|
||||||
|
// racing score mode
|
||||||
|
bool settings::OGRACINGSCORES = true;
|
||||||
|
|
||||||
void settings::init() {
|
void settings::init() {
|
||||||
INIReader reader("config.ini");
|
INIReader reader("config.ini");
|
||||||
|
|
||||||
@@ -111,6 +114,7 @@ void settings::init() {
|
|||||||
EVENTMODE = reader.GetInteger("shard", "eventmode", EVENTMODE);
|
EVENTMODE = reader.GetInteger("shard", "eventmode", EVENTMODE);
|
||||||
DISABLEFIRSTUSEFLAG = reader.GetBoolean("shard", "disablefirstuseflag", DISABLEFIRSTUSEFLAG);
|
DISABLEFIRSTUSEFLAG = reader.GetBoolean("shard", "disablefirstuseflag", DISABLEFIRSTUSEFLAG);
|
||||||
ANTICHEAT = reader.GetBoolean("shard", "anticheat", ANTICHEAT);
|
ANTICHEAT = reader.GetBoolean("shard", "anticheat", ANTICHEAT);
|
||||||
|
OGRACINGSCORES = reader.GetBoolean("shard", "ogracingscores", OGRACINGSCORES);
|
||||||
MONITORENABLED = reader.GetBoolean("monitor", "enabled", MONITORENABLED);
|
MONITORENABLED = reader.GetBoolean("monitor", "enabled", MONITORENABLED);
|
||||||
MONITORPORT = reader.GetInteger("monitor", "port", MONITORPORT);
|
MONITORPORT = reader.GetInteger("monitor", "port", MONITORPORT);
|
||||||
MONITORINTERVAL = reader.GetInteger("monitor", "interval", MONITORINTERVAL);
|
MONITORINTERVAL = reader.GetInteger("monitor", "interval", MONITORINTERVAL);
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ namespace settings {
|
|||||||
extern int MONITORPORT;
|
extern int MONITORPORT;
|
||||||
extern int MONITORINTERVAL;
|
extern int MONITORINTERVAL;
|
||||||
extern bool DISABLEFIRSTUSEFLAG;
|
extern bool DISABLEFIRSTUSEFLAG;
|
||||||
|
extern bool OGRACINGSCORES;
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user