first version

This commit is contained in:
GenZmeY 2023-10-07 22:39:09 +03:00
parent dbd06dfe45
commit a6c0466306
Signed by: GenZmeY
GPG Key ID: 424DA4BC3CB2CF39
19 changed files with 629 additions and 1 deletions

33
.editorconfig Normal file
View File

@ -0,0 +1,33 @@
root = true
# Global
[*]
indent_style = unset
indent_size = 4
tab_width = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = unset
# Unreal Engine 3 / Source
[*.uc]
indent_style = tab
[*.{uci,upkg}]
# Unreal Engine 3 / i18n
[*.{chn,cht,cze,dan,deu,dut,esl,esn,fra,frc,hun,int,ita,jpn,kor,pol,por,ptb,rus,tur,ukr}]
charset = utf-16le
# Other
[*.md]
indent_style = space
trim_trailing_whitespace = false
[*.yml]
indent_style = space
indent_size = 2
[*.{txt,cfg,conf}]
indent_style = tab

72
.github/workflows/mega-linter.yml vendored Normal file
View File

@ -0,0 +1,72 @@
---
name: MegaLinter
permissions: read-all
on:
push:
pull_request:
branches: [master]
env:
APPLY_FIXES: none
APPLY_FIXES_EVENT: pull_request
APPLY_FIXES_MODE: commit
DISABLE: SPELL
concurrency:
group: ${{ github.ref }}-${{ github.workflow }}
cancel-in-progress: true
jobs:
build:
name: MegaLinter
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
with:
token: ${{ secrets.PAT || secrets.GITHUB_TOKEN }}
- name: MegaLinter
id: ml
uses: oxsecurity/megalinter@v7
env:
VALIDATE_ALL_CODEBASE: true
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Archive production artifacts
if: ${{ success() }} || ${{ failure() }}
uses: actions/upload-artifact@v3
with:
name: MegaLinter reports
path: |
megalinter-reports
mega-linter.log
- name: Create Pull Request with applied fixes
id: cpr
if: steps.ml.outputs.has_updated_sources == 1 && (env.APPLY_FIXES_EVENT == 'all' || env.APPLY_FIXES_EVENT == github.event_name) && env.APPLY_FIXES_MODE == 'pull_request' && (github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository)
uses: peter-evans/create-pull-request@v5
with:
token: ${{ secrets.PAT || secrets.GITHUB_TOKEN }}
commit-message: "[MegaLinter] Apply linters automatic fixes"
title: "[MegaLinter] Apply linters automatic fixes"
labels: bot
- name: Create PR output
if: steps.ml.outputs.has_updated_sources == 1 && (env.APPLY_FIXES_EVENT == 'all' || env.APPLY_FIXES_EVENT == github.event_name) && env.APPLY_FIXES_MODE == 'pull_request' && (github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository)
run: |
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"
- name: Prepare commit
if: steps.ml.outputs.has_updated_sources == 1 && (env.APPLY_FIXES_EVENT == 'all' || env.APPLY_FIXES_EVENT == github.event_name) && env.APPLY_FIXES_MODE == 'commit' && github.ref != 'refs/heads/main' && (github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository)
run: sudo chown -Rc $UID .git/
- name: Commit and push applied linter fixes
if: steps.ml.outputs.has_updated_sources == 1 && (env.APPLY_FIXES_EVENT == 'all' || env.APPLY_FIXES_EVENT == github.event_name) && env.APPLY_FIXES_MODE == 'commit' && github.ref != 'refs/heads/main' && (github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository)
uses: stefanzweifel/git-auto-commit-action@v4
with:
branch: ${{ github.event.pull_request.head.ref || github.head_ref || github.ref }}
commit_message: "[MegaLinter] Apply linters fixes"
commit_user_name: "github-actions"
commit_user_email: "github-actions[bot]@users.noreply.github.com"

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "tools"]
path = tools
url = https://github.com/GenZmeY/KF2-BuildTools

View File

@ -0,0 +1,69 @@
[img]https://img.shields.io/static/v1?logo=GitHub&labelColor=gray&color=blue&logoColor=white&label=&message=Open Source[/img] [img]https://img.shields.io/github/license/GenZmeY/KF2-TrueRandomBoss[/img] [img]https://img.shields.io/steam/favorites/3047331564[/img] [img]https://img.shields.io/steam/update-date/3047331564[/img] [url=https://steamcommunity.com/sharedfiles/filedetails/changelog/3047331564][img]https://img.shields.io/github/v/tag/GenZmeY/KF2-TrueRandomBoss[/img][/url]
[h1]Description[/h1]
Server-side mutator that makes bosses truly random.
[h1]What does it mean?[/h1]
Some players use the command to predict the boss. Here's the command:
[code]getall kfgamereplicationinfo bossindex[/code]
Copy this command, open the console (~), paste the command and press Enter.
In response, you will receive a string, the last number of which is the boss index:
[code]
0 = Hans Volter
1 = Patriarch
2 = King Fleshpound
3 = Abomination
4 = Matriarch
[/code]
This is possible because the boss is chosen at the beginning of the game.
[b]This mutator sets a random boss index right before the start of the boss wave and thus makes the command above completely useless.[/b]
[h1]Whitelisted?[/h1]
No. This mod is not whitelisted and will de-rank your server. Any XP gained will not be saved.
[h1]Usage (single player)[/h1]
[olist]
[*]Subscribe to this mutator;
[*]Start KF2;
[*]Open console (~) and input:
[b]open KF-BioticsLab?Mutator=TRB.TRBMut[/b]
(replace the map and add the parameters you need)
[*]<Enter>.
[/olist]
[h1]Usage (server)[/h1]
[b]Note:[/b] [i]If you don't understand what is written here, read the article [url=https://wiki.killingfloor2.com/index.php?title=Dedicated_Server_(Killing_Floor_2)][u]Dedicated Server (KF2 wiki)[/u][/url] before following these instructions.[/i]
[olist]
[*]Open your [b]PCServer-KFEngine.ini[/b] / [b]LinuxServer-KFEngine.ini[/b];
[*]Find the [b][IpDrv.TcpNetDriver][/b] section and make sure that there is a line (add if not):
[b]DownloadManagers=OnlineSubsystemSteamworks.SteamWorkshopDownload[/b]
❗️ If there are several [b]DownloadManagers=[/b] then the line above should be the first ❗️
[*]Add the following string to the [b][OnlineSubsystemSteamworks.KFWorkshopSteamworks][/b] section (create one if it doesn't exist):
[b]ServerSubscribedWorkshopItems=3047331564[/b]
[*]Start the server and wait while the mutator is downloading;
[*]Add mutator to server start parameters: [b]?Mutator=TRB.TRBMut[/b] and restart the server.
[/olist]
[h1]Important setup information[/h1]
The config should be created on first start, but now the game contains a bug that initializes the config values randomly if they are not explicitly set. Thus, the config may have incorrect values or not be created at all.
So if you are using this mutator for the first time, I highly recommend doing the following:
[olist]
[*]Create (modify) [b]KFTRB.ini[/b] manually. Put the following content there:
[b][TRB.TRB]
Version=0[/b]
[*]Start the game/server with TRB to generate the contents of the config.
[*]Close the game/server.
[/olist]
[b]Right now this is the only way to correctly create the default config.[/b]
Unfortunately I can't do anything about it because it's a game problem (not mutator). I hope TWI fixes this someday.
[h1]Setup (KFTRB.ini)[/h1]
Honestly, you don't need to edit anything in the config, [b]just make sure you create the default config correctly[/b].
The config exists because I needed it during development ¯\_(ツ)_/¯
[h1]Notes[/h1]
📌 Even if you use this mod, the boss prediction command can sometimes give correct predictions, just by chance. And that's okay. After all, this is a real random :)
[h1]Sources[/h1]
[url=https://github.com/GenZmeY/KF2-TrueRandomBoss]https://github.com/GenZmeY/KF2-TrueRandomBoss[/url] (GNU GPLv3)

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 KiB

View File

@ -0,0 +1 @@
Mutators

View File

@ -0,0 +1 @@
True Random Boss

View File

@ -1 +1,35 @@
# KF2-TrueRandomBoss
# True Random Boss
[![Steam Workshop](https://img.shields.io/static/v1?message=workshop&logo=steam&labelColor=gray&color=blue&logoColor=white&label=steam%20)](https://steamcommunity.com/sharedfiles/filedetails/?id=3047331564)
[![Steam Downloads](https://img.shields.io/steam/downloads/3047331564)](https://steamcommunity.com/sharedfiles/filedetails/?id=3047331564)
[![Steam Favorites](https://img.shields.io/steam/favorites/3047331564)](https://steamcommunity.com/sharedfiles/filedetails/?id=3047331564)
[![MegaLinter](https://github.com/GenZmeY/KF2-TrueRandomBoss/actions/workflows/mega-linter.yml/badge.svg?branch=master)](https://github.com/GenZmeY/KF2-TrueRandomBoss/actions/workflows/mega-linter.yml)
[![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/GenZmeY/KF2-TrueRandomBoss)](https://github.com/GenZmeY/KF2-TrueRandomBoss/tags)
[![GitHub](https://img.shields.io/github/license/GenZmeY/KF2-TrueRandomBoss)](LICENSE)
## Description
Server-side mutator that makes bosses truly random.
## Usage & Setup
[See steam workshop page](https://steamcommunity.com/sharedfiles/filedetails/?id=3047331564)
## Build
**Note:** If you want to build/test/brew/publish a mutator without git-bash and/or scripts, follow [these instructions](https://tripwireinteractive.atlassian.net/wiki/spaces/KF2SW/pages/26247172/KF2+Code+Modding+How-to) instead of what is described here.
1. Install [Killing Floor 2](https://store.steampowered.com/app/232090/Killing_Floor_2/), Killing Floor 2 - SDK and [git for windows](https://git-scm.com/download/win);
2. open git-bash and go to any folder where you want to store sources:
`cd <ANY_FOLDER_YOU_WANT>`
3. Clone this repository and go to the source folder:
`git clone https://github.com/GenZmeY/KF2-TrueRandomBoss && cd KF2-TrueRandomBoss`
4. Download dependencies:
`git submodule init && git submodule update`
5. Compile:
`./tools/builder -c`
5. The compiled files will be here:
`C:\Users\<USERNAME>\Documents\My Games\KillingFloor2\KFGame\Unpublished\BrewedPC\Script\`
## Bug reports
If you find a bug, go to the [issue page](https://github.com/GenZmeY/KF2-TrueRandomBoss/issues) and check if there is a description of your bug. If not, create a new issue.
Describe what the bug looks like and how reproduce it.
## License
[![license](https://www.gnu.org/graphics/gplv3-with-text-136x68.png)](LICENSE)

View File

@ -0,0 +1,40 @@
class KFGI_Access extends Object
within KFGameInfo;
public function SetRandomBoss()
{
OverrideBossIndex(Rand(default.AIBossClassList.Length));
}
public function class<KFPawn_Monster> Boss()
{
return BossAITypePawn(BossIndex);
}
public function OverrideBossIndex(int Index, optional bool Force = false)
{
if (Index < 0 || Index >= default.AIBossClassList.Length)
{
return;
}
if (!UseSpecificBossIndex(BossIndex) || Force)
{
BossIndex = Index;
}
MyKFGRI.CacheSelectedBoss(BossIndex);
}
public function class<KFPawn_Monster> BossAITypePawn(int AIType)
{
if (AIType < AIBossClassList.Length)
return AIBossClassList[AIType];
else
return None;
}
defaultproperties
{
}

222
TRB/Classes/TRB.uc Normal file
View File

@ -0,0 +1,222 @@
class TRB extends Info
config(TRB);
const LatestVersion = 1;
enum E_State
{
S_WAIT,
S_WAVE,
S_TRADER,
S_END
};
var private config int Version;
var private config E_LogLevel LogLevel;
var private config float WavePollingDT;
var private config float TraderPollingDT;
var private KFGameInfo KFGI;
var private KFGI_Access KFGIA;
var private KFGameReplicationInfo KFGRI;
var private E_State GameState;
public simulated function bool SafeDestroy()
{
return (bPendingDelete || bDeleteMe || Destroy());
}
public event PreBeginPlay()
{
`Log_Trace();
if (WorldInfo.NetMode == NM_Client)
{
`Log_Fatal("NetMode == NM_Client, Destroy...");
SafeDestroy();
return;
}
Super.PreBeginPlay();
PreInit();
}
private function PreInit()
{
`Log_Trace();
if (Version == `NO_CONFIG)
{
LogLevel = LL_Info;
WavePollingDT = 5.0f;
TraderPollingDT = 1.0f;
SaveConfig();
}
switch (Version)
{
case `NO_CONFIG:
`Log_Info("Config created");
case MaxInt:
`Log_Info("Config updated to version"@LatestVersion);
break;
case LatestVersion:
`Log_Info("Config is up-to-date");
break;
default:
`Log_Warn("The config version is higher than the current version");
`Log_Warn("Config version is" @ Version @ "but current version is" @ LatestVersion);
`Log_Warn("The config version will be changed to" @ LatestVersion);
break;
}
if (LatestVersion != Version)
{
Version = LatestVersion;
SaveConfig();
}
if (LogLevel == LL_WrongLevel)
{
LogLevel = LL_Info;
`Log_Warn("Wrong 'LogLevel', return to default value");
SaveConfig();
}
`Log_Base("LogLevel:" @ LogLevel);
}
public event PostBeginPlay()
{
`Log_Trace();
if (bPendingDelete || bDeleteMe) return;
Super.PostBeginPlay();
PostInit();
}
private function PostInit()
{
`Log_Trace();
if (WorldInfo == None || WorldInfo.Game == None)
{
SetTimer(1.0f, false, nameof(PostInit));
return;
}
KFGI = KFGameInfo(WorldInfo.Game);
if (KFGI == None)
{
`Log_Fatal("Incompatible gamemode:" @ WorldInfo.Game $ ". Destroy...");
SafeDestroy();
return;
}
if (KFGI.GameReplicationInfo == None)
{
SetTimer(1.0f, false, nameof(PostInit));
return;
}
KFGRI = KFGameReplicationInfo(KFGI.GameReplicationInfo);
if (KFGRI == None)
{
`Log_Fatal("Incompatible Replication info:" @ KFGI.GameReplicationInfo);
SafeDestroy();
return;
}
KFGIA = new(KFGI) class'KFGI_Access';
if (KFGIA == None)
{
`Log_Fatal("Can't create KFGI_Access object");
SafeDestroy();
return;
}
SetTimer(WavePollingDT, true, nameof(WavePolling));
}
private function WavePolling()
{
`Log_Trace();
if (!StateChanged()) return;
`Log_Debug("GameState:" @ GameState);
switch (GameState)
{
case S_TRADER:
if (KFGRI.IsBossWaveNext())
{
`Log_Debug("Prepare to boss wave");
SetTimer(TraderPollingDT, true, nameof(TraderPolling));
ClearTimer(nameof(WavePolling));
}
break;
case S_END:
`Log_Debug("Cleanup");
ClearTimer(nameof(WavePolling));
ClearTimer(nameof(TraderPolling));
SafeDestroy();
break;
case S_WAIT:
case S_WAVE:
default:
break;
}
}
private function TraderPolling()
{
`Log_Trace();
if (KFGRI.GetTraderTimeRemaining() < class'KFGame.KFVoteCollector'.default.TimeAfterSkipTrader || KFGRI.bWaveStarted)
{
`Log_Debug("Prev boss:" @ String(KFGIA.Boss()));
KFGIA.SetRandomBoss();
`Log_Info("New boss:" @ String(KFGIA.Boss()));
ClearTimer(nameof(TraderPolling));
SetTimer(WavePollingDT, true, nameof(WavePolling));
return;
}
}
private function E_State GetState()
{
`Log_Trace();
if (KFGRI.bMatchIsOver) return S_END;
if (!KFGRI.bMatchHasBegun) return S_WAIT;
if (KFGRI.bTraderIsOpen) return S_TRADER;
if (KFGRI.bWaveStarted) return S_WAVE;
}
private function bool StateChanged()
{
local E_State NewState;
local bool StateChanged;
`Log_Trace();
NewState = GetState();
StateChanged = (GameState != NewState);
GameState = NewState;
return StateChanged;
}
defaultproperties
{
GameState = S_WAIT
}

4
TRB/Classes/TRB.upkg Normal file
View File

@ -0,0 +1,4 @@
[Flags]
AllowDownload=False
ClientOptional=False
ServerSideOnly=True

47
TRB/Classes/TRBMut.uc Normal file
View File

@ -0,0 +1,47 @@
class TRBMut extends KFMutator
dependson(TRB);
var private TRB TRB;
public simulated function bool SafeDestroy()
{
return (bPendingDelete || bDeleteMe || Destroy());
}
public event PreBeginPlay()
{
Super.PreBeginPlay();
if (WorldInfo.NetMode == NM_Client) return;
foreach WorldInfo.DynamicActors(class'TRB', TRB)
{
break;
}
if (TRB == None)
{
TRB = WorldInfo.Spawn(class'TRB');
}
if (TRB == None)
{
`Log_Base("FATAL: Can't Spawn 'TRB'");
SafeDestroy();
}
}
public function AddMutator(Mutator Mut)
{
if (Mut == Self) return;
if (Mut.Class == Class)
TRBMut(Mut).SafeDestroy();
else
Super.AddMutator(Mut);
}
defaultproperties
{
}

20
TRB/Classes/_Logger.uc Normal file
View File

@ -0,0 +1,20 @@
class _Logger extends Object
abstract;
enum E_LogLevel
{
LL_WrongLevel,
LL_None,
LL_Fatal,
LL_Error,
LL_Warning,
LL_Info,
LL_Debug,
LL_Trace,
LL_All
};
defaultproperties
{
}

2
TRB/Constants.uci Normal file
View File

@ -0,0 +1,2 @@
// Constants
`define NO_CONFIG 0

3
TRB/Globals.uci Normal file
View File

@ -0,0 +1,3 @@
// Imports
`include(Logger.uci)
`include(Constants.uci)

15
TRB/Logger.uci Normal file
View File

@ -0,0 +1,15 @@
// Logger
`define Log_Tag 'TRB'
`define LocationStatic "`{ClassName}::" $ GetFuncName()
`define Log_Base(msg, cond) `log(`msg `if(`cond), `cond`{endif}, `Log_Tag)
`define Log_Fatal(msg) `log("FATAL:" @ `msg, (LogLevel >= LL_Fatal), `Log_Tag)
`define Log_Error(msg) `log("ERROR:" @ `msg, (LogLevel >= LL_Error), `Log_Tag)
`define Log_Warn(msg) `log("WARN:" @ `msg, (LogLevel >= LL_Warning), `Log_Tag)
`define Log_Info(msg) `log("INFO:" @ `msg, (LogLevel >= LL_Info), `Log_Tag)
`define Log_Debug(msg) `log("DEBUG:" @ `msg, (LogLevel >= LL_Debug), `Log_Tag)
`define Log_Trace(msg) `log("TRACE:" @ `Location `if(`msg) @ `msg`{endif}, (LogLevel >= LL_Trace), `Log_Tag)
`define Log_TraceStatic(msg) `log("TRACE:" @ `LocationStatic `if(`msg) @ `msg`{endif}, (LogLevel >= LL_Trace), `Log_Tag)

61
builder.cfg Normal file
View File

@ -0,0 +1,61 @@
### Build parameters ###
# If True - compresses the mutator when compiling
# Scripts will be stored in binary form
# (reduces the size of the output file)
StripSource="True"
# Mutators to be compiled
# Specify them with a space as a separator,
# Mutators will be compiled in the specified order
PackageBuildOrder="TRB"
### Brew parameters ###
# Packages you want to brew using @peelz's patched KFEditor.
# Useful for cases where regular brew doesn't put *.upk inside the package.
# Specify them with a space as a separator,
# The order doesn't matter
PackagePeelzBrew=""
### Steam Workshop upload parameters ###
# Mutators that will be uploaded to the workshop
# Specify them with a space as a separator,
# The order doesn't matter
PackageUpload="TRB"
### Test parameters ###
# Map:
Map="KF-Nuked"
# Game:
# Survival: KFGameContent.KFGameInfo_Survival
# WeeklyOutbreak: KFGameContent.KFGameInfo_WeeklySurvival
# Endless: KFGameContent.KFGameInfo_Endless
# Objective: KFGameContent.KFGameInfo_Objective
# Versus: KFGameContent.KFGameInfo_VersusSurvival
Game="KFGameContent.KFGameInfo_Survival"
# Difficulty:
# Normal: 0
# Hard: 1
# Suicide: 2
# Hell: 3
Difficulty="0"
# GameLength:
# 4 waves: 0
# 7 waves: 1
# 10 waves: 2
GameLength="0"
# Mutators
Mutators="TRB.TRBMut"
# Additional parameters
Args=""

1
tools Submodule

@ -0,0 +1 @@
Subproject commit fb458ac61f7e6c6426b8dff366dd5e7499e0d95f