2 Commits

Author SHA1 Message Date
FinnHornhoover
62443c53df Merge f4b36b8f73 into d3bef95a7f 2023-08-23 11:21:07 +03:00
FinnHornhoover
f4b36b8f73 added alternate racing score funcitonality 2023-07-24 00:33:19 +03:00
6 changed files with 76 additions and 39 deletions

View File

@@ -53,7 +53,7 @@ jobs:
- name: Upload build artifact - name: Upload build artifact
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2
with: with:
name: 'ubuntu22_04-bin-x64-${{ env.SHORT_SHA }}' name: 'ubuntu20_04-bin-x64-${{ env.SHORT_SHA }}'
path: bin path: bin
windows-build: windows-build:
@@ -112,7 +112,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-22.04 runs-on: ubuntu-latest
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 }}

View File

@@ -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.5/OpenFusionClient-1.5-Installer.exe) - choose to run the file. 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.
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.5/OpenFusionClient-1.5.zip). 1. Download the client from [here](https://github.com/OpenFusionProject/OpenFusion/releases/download/1.4/OpenFusionClient-1.4.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.5-original.zip` or `OpenFusionServer-1.5-academy.zip` from [here](https://github.com/OpenFusionProject/OpenFusion/releases/tag/1.5). 1. Grab `OpenFusionServer-1.4-original.zip` or `OpenFusionServer-1.4-academy.zip` from [here](https://github.com/OpenFusionProject/OpenFusion/releases/tag/1.4).
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.

View File

@@ -69,41 +69,31 @@ static void setValuePlayer(CNSocket* sock, CNPacketData* data) {
// Handle serverside value-changes // Handle serverside value-changes
switch (setData->iSetValueType) { switch (setData->iSetValueType) {
case CN_GM_SET_VALUE_TYPE__HP: case 1:
response.iSetValue = plr->HP = setData->iSetValue; plr->HP = setData->iSetValue;
break; break;
case CN_GM_SET_VALUE_TYPE__WEAPON_BATTERY : case 2:
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 CN_GM_SET_VALUE_TYPE__NANO_BATTERY: case 3:
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 CN_GM_SET_VALUE_TYPE__FUSION_MATTER: case 4:
Missions::updateFusionMatter(sock, setData->iSetValue - plr->fusionmatter); Missions::updateFusionMatter(sock, setData->iSetValue - plr->fusionmatter);
response.iSetValue = plr->fusionmatter;
break; break;
case CN_GM_SET_VALUE_TYPE__CANDY: case 5:
response.iSetValue = plr->money = setData->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);

View File

@@ -97,31 +97,47 @@ 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];
// if there are no divide-by-zero dangers, and at least one factor has been specified
// we switch over to OG scoring
bool useOGScoring = (epInfo.maxPods > 0) && (epInfo.maxTime > 0) && (
(epInfo.scaleFactor > 0.0) || (epInfo.podFactor > 0.0) || (epInfo.timeFactor > 0.0));
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 (useOGScoring) {
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;

View File

@@ -5,7 +5,11 @@
#include "servers/CNShardServer.hpp" #include "servers/CNShardServer.hpp"
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 {

View File

@@ -572,8 +572,35 @@ 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"];
// update max score (if present)
if (race.find("ScoreCap") != race.end()) {
epInfo.maxScore = (int)race["ScoreCap"];
}
// update max pods (if present)
if (race.find("TotalPods") != race.end()) {
epInfo.maxPods = (int)race["TotalPods"];
}
// update scale factor (if present)
if (race.find("ScaleFactor") != race.end()) {
epInfo.scaleFactor = (double)race["ScaleFactor"];
}
// update pod factor (if present)
if (race.find("PodFactor") != race.end()) {
epInfo.podFactor = (double)race["PodFactor"];
}
// update time factor (if present)
if (race.find("TimeFactor") != race.end()) {
epInfo.timeFactor = (double)race["TimeFactor"];
}
// score cutoffs // score cutoffs
std::vector<int> rankScores; std::vector<int> rankScores;