Browse Source

Fix game difficulty/length switching

Previously game dissivulty was switching through a crutch, when we
could've just used key-value option inside the server URL. That crutch
was repurposed to switch game length that is actually requires it.
develop
Anton Tarasenko 2 years ago
parent
commit
27bfc5f580
  1. 17
      sources/GameModes/BaseGameMode.uc
  2. 93
      sources/GameModes/GameMode.uc
  3. 97
      sources/VotingHandlerAdapter.uc

17
sources/GameModes/BaseGameMode.uc

@ -33,6 +33,8 @@ class BaseGameMode extends AcediaConfig
// Name of the game mode players will see in voting (formatted string)
var protected config string title;
// Preferable game length (plain string)
var protected config string length;
// Preferable difficulty level (plain string)
var protected config string difficulty;
// `Mutator`s to add with this game mode
@ -63,6 +65,7 @@ protected function HashTable ToData()
result = _.collections.EmptyHashTable();
result.SetFormattedString(P("title"), title);
result.SetString(P("length"), length);
result.SetString(P("difficulty"), difficulty);
nextArray = _.collections.EmptyArrayList();
for (i = 0; i < includeFeature.length; i += 1) {
@ -105,8 +108,9 @@ protected function FromData(HashTable source)
if (source == none) {
return;
}
title = source.GetFormattedString(P("title"));
title = source.GetString(P("title"));
title = source.GetFormattedString(P("title"));
length = source.GetString(P("length"));
difficulty = source.GetString(P("difficulty"));
nextArray = source.GetArrayList(P("includeFeature"));
includeFeature = DynamicIntoStringArray(nextArray);
_.memory.Free(nextArray);
@ -195,6 +199,15 @@ public function Text GetTitle()
return _.text.FromFormattedString(title);
}
/**
* @return Specified game length for the game mode.
* Interpretation of this value can depend on each particular game mode.
*/
public function Text GetLength()
{
return _.text.FromString(length);
}
/**
* @return Specified difficulty for the game mode.
* Interpretation of this value can depend on each particular game mode.

93
sources/GameModes/GameMode.uc

@ -39,11 +39,21 @@ var protected config string acronym;
// this game mode (plain string)
var protected config string mapPrefix;
var private LoggerAPI.Definition warnBadOption;
// Aliases are an unnecessary overkill for difficulty names, so just define
// them in special `string` arrays.
// We accept not just these exact words, but any of their prefixes.
var private const array<string> beginnerSynonyms;
var private const array<string> normalSynonyms;
var private const array<string> hardSynonyms;
var private const array<string> suicidalSynonyms;
var private const array<string> hoeSynonyms;
var private LoggerAPI.Definition warnBadOption, warnDifficultyOption;
protected function DefaultIt()
{
title = "Acedia game mode";
length = "long";
difficulty = "Hell On Earth";
gameTypeClass = "KFMod.KFGameType";
acronym = "";
@ -176,20 +186,95 @@ public function HashTable GetOptions()
{
local int i;
local HashTable result;
local Text nextKey, nextValue;
result = _.collections.EmptyHashTable();
for (i = 0; i < option.length; i += 1)
{
if (!ValidateServerURLName(option[i].key)) continue;
if (!ValidateServerURLName(option[i].value)) continue;
result.SetItem( _.text.FromString(option[i].key),
_.text.FromString(option[i].value));
if (option[i].key ~= "difficulty")
{
_.logger.Auto(warnDifficultyOption);
continue;
}
nextKey = _.text.FromString(option[i].key);
nextValue = _.text.FromString(option[i].value);
result.SetItem(nextKey, nextValue);
nextKey.FreeSelf();
nextValue.FreeSelf();
}
// Add difficulty option
nextValue = _.text.FromInt(GetNumericDifficulty());
result.SetItem(P("difficulty"), nextValue);
nextValue.FreeSelf();
return result;
}
// Convert `GameMode`'s difficulty's textual representation into
// KF's numeric one.
private final function int GetNumericDifficulty()
{
local int i;
local string lowerCaseDifficulty;
lowerCaseDifficulty = Locs(_.text.IntoString(GetDifficulty()));
for (i = 0; i < default.beginnerSynonyms.length; i += 1)
{
if (IsPrefixOf(lowerCaseDifficulty, default.beginnerSynonyms[i])) {
return 1;
}
}
for (i = 0; i < default.normalSynonyms.length; i += 1)
{
if (IsPrefixOf(lowerCaseDifficulty, default.normalSynonyms[i])) {
return 2;
}
}
for (i = 0; i < default.hardSynonyms.length; i += 1)
{
if (IsPrefixOf(lowerCaseDifficulty, default.hardSynonyms[i])) {
return 4;
}
}
for (i = 0; i < default.suicidalSynonyms.length; i += 1)
{
if (IsPrefixOf(lowerCaseDifficulty, default.suicidalSynonyms[i])) {
return 5;
}
}
for (i = 0; i < default.hoeSynonyms.length; i += 1)
{
if (IsPrefixOf(lowerCaseDifficulty, default.hoeSynonyms[i])) {
return 7;
}
}
return int(lowerCaseDifficulty);
}
protected final static function bool IsPrefixOf(string prefix, string value)
{
return (InStr(value, prefix) == 0);
}
defaultproperties
{
configName = "AcediaGameModes"
warnBadOption = (l=LOG_Warning,m="Option with key \"%1\" and value \"%2\" specified for game mode \"%3\" contains invalid characters and will be ignored. This is a configuration error, you should fix it.")
beginnerSynonyms(0) = "easy"
beginnerSynonyms(1) = "beginer"
beginnerSynonyms(2) = "beginner"
beginnerSynonyms(3) = "begginer"
beginnerSynonyms(4) = "begginner"
normalSynonyms(0) = "regular"
normalSynonyms(1) = "default"
normalSynonyms(2) = "normal"
hardSynonyms(0) = "harder" // "hard" is prefix of this, so it will count
hardSynonyms(1) = "difficult"
suicidalSynonyms(0) = "suicidal"
hoeSynonyms(0) = "hellonearth"
hoeSynonyms(1) = "hellon earth"
hoeSynonyms(2) = "hell onearth"
hoeSynonyms(3) = "hoe"
warnBadOption = (l=LOG_Warning,m="Option with key \"%1\" and value \"%2\" specified for game mode \"%3\" contains invalid characters and will be ignored. This is a configuration error, you should fix it.")
warnDifficultyOption = (l=LOG_Warning,m="Option with key \"Difficulty\" is specified. This key reserved and will be ignored. Difficulty value should be set through the game mode's \"Difficulty\" setting in \"AcediaGameModes.ini\" config. This is a configuration error, you should fix it.")
}

97
sources/VotingHandlerAdapter.uc

@ -50,15 +50,6 @@ class VotingHandlerAdapter extends AcediaObject
* to read (and forget) from internal state.
*/
// Aliases are an unnecessary overkill for difficulty names, so just define
// them in special `string` arrays.
// We accept detect not just these exact words, but any of their prefixes.
var private const array<string> beginnerSynonyms;
var private const array<string> normalSynonyms;
var private const array<string> hardSynonyms;
var private const array<string> suicidalSynonyms;
var private const array<string> hoeSynonyms;
// All available game modes for Acedia, loaded during initialization.
// This array is directly produces replacement for `XVotingHandler`'s
// `gameConfig` array and records of `availableGameModes` relate to those of
@ -86,7 +77,15 @@ var private config string targetGameMode;
// difficulty by overwriting default value of its `gameDifficulty` variable.
// But to not affect game's configs we must restore old value after new map is
// loaded. Store it in config variable for that.
var private config float storedGameDifficulty;
var private config int storedGameLength;
// Aliases are an unnecessary overkill for difficulty names, so just define
// them in special `string` arrays.
// We accept not just these exact words, but any of their prefixes.
var private const array<string> shortSynonyms;
var private const array<string> normalSynonyms;
var private const array<string> longSynonyms;
var private const array<string> customSynonyms;
var private LoggerAPI.Definition fatNoXVotingHandler, fatBadGameConfigIndexVH;
var private LoggerAPI.Definition fatBadGameConfigIndexAdapter;
@ -201,6 +200,7 @@ public final function PrepareForServerTravel()
local GameMode nextGameMode;
local string nextGameClassName;
local class<GameInfo> nextGameClass;
local class<KFGameType> nextKFGameType;
local XVotingHandler votingHandler;
if (votingHandlerReference == none) return;
@ -235,9 +235,15 @@ public final function PrepareForServerTravel()
}
isServerTraveling = true;
targetGameMode = availableGameModes[pickedVHConfig].ToString();
nextGameMode = GetConfigFromString(default.targetGameMode);
storedGameDifficulty = nextGameClass.default.gameDifficulty;
nextGameClass.default.gameDifficulty = GetNumericDifficulty(nextGameMode);
nextGameMode = GetConfigFromString(targetGameMode);
nextKFGameType = class<KFGameType>(nextGameClass);
if (nextKFGameType != none)
{
storedGameLength = nextKFGameType.default.kfGameLength;
nextKFGameType.default.kfGameLength =
GetNumericGameLength(nextGameMode);
}
nextGameClass.static.StaticSaveConfig();
SaveConfig();
}
@ -250,11 +256,17 @@ public final function PrepareForServerTravel()
*/
public final function GameMode SetupGameModeAfterTravel()
{
local KFGameType kfGameType;
if (!isServerTraveling) {
return none;
}
_server.unreal.GetGameType().default.gameDifficulty = storedGameDifficulty;
kfGameType = _server.unreal.GetKFGameType();
if (kfGameType != none) {
kfGameType.default.kfGameLength = storedGameLength;
}
isServerTraveling = false;
_server.unreal.GetGameType().StaticSaveConfig();
SaveConfig();
return GetConfigFromString(targetGameMode);
}
@ -289,43 +301,37 @@ private function GameMode GetConfigFromString(string configName)
// Convert `GameMode`'s difficulty's textual representation into
// KF's numeric one.
private final function int GetNumericDifficulty(GameMode gameMode)
private final function int GetNumericGameLength(BaseGameMode gameMode)
{
local int i;
local string difficulty;
local string length;
difficulty = Locs(_.text.IntoString(gameMode.GetDifficulty()));
for (i = 0; i < default.beginnerSynonyms.length; i += 1)
length = Locs(_.text.IntoString(gameMode.GetLength()));
for (i = 0; i < default.shortSynonyms.length; i += 1)
{
if (IsPrefixOf(difficulty, default.beginnerSynonyms[i])) {
return 1;
if (IsPrefixOf(length, default.shortSynonyms[i])) {
return 0;
}
}
for (i = 0; i < default.normalSynonyms.length; i += 1)
{
if (IsPrefixOf(difficulty, default.normalSynonyms[i])) {
return 2;
}
}
for (i = 0; i < default.hardSynonyms.length; i += 1)
{
if (IsPrefixOf(difficulty, default.hardSynonyms[i])) {
return 4;
if (IsPrefixOf(length, default.normalSynonyms[i])) {
return 1;
}
}
for (i = 0; i < default.suicidalSynonyms.length; i += 1)
for (i = 0; i < default.longSynonyms.length; i += 1)
{
if (IsPrefixOf(difficulty, default.suicidalSynonyms[i])) {
return 5;
if (IsPrefixOf(length, default.longSynonyms[i])) {
return 2;
}
}
for (i = 0; i < default.hoeSynonyms.length; i += 1)
for (i = 0; i < default.customSynonyms.length; i += 1)
{
if (IsPrefixOf(difficulty, default.hoeSynonyms[i])) {
return 7;
if (IsPrefixOf(length, default.customSynonyms[i])) {
return 3;
}
}
return int(difficulty);
return 3;
}
protected final static function bool IsPrefixOf(string prefix, string value)
@ -335,21 +341,12 @@ protected final static function bool IsPrefixOf(string prefix, string value)
defaultproperties
{
beginnerSynonyms(0) = "easy"
beginnerSynonyms(1) = "beginer"
beginnerSynonyms(2) = "beginner"
beginnerSynonyms(3) = "begginer"
beginnerSynonyms(4) = "begginner"
normalSynonyms(0) = "regular"
normalSynonyms(1) = "default"
normalSynonyms(2) = "normal"
hardSynonyms(0) = "harder" // "hard" is prefix of this, so it will count
hardSynonyms(1) = "difficult"
suicidalSynonyms(0) = "suicidal"
hoeSynonyms(0) = "hellonearth"
hoeSynonyms(1) = "hellon earth"
hoeSynonyms(2) = "hell onearth"
hoeSynonyms(3) = "hoe"
shortSynonyms(0) = "short"
normalSynonyms(0) = "normal"
normalSynonyms(1) = "medium"
normalSynonyms(2) = "regular"
longSynonyms(0) = "long"
customSynonyms(0) = "custom"
fatNoXVotingHandler = (l=LOG_Fatal,m="`XVotingHandler` class is missing. Make sure your server setup supports Acedia's game modes (by used voting handler derived from `XVotingHandler`).")
fatBadGameConfigIndexVH = (l=LOG_Fatal,m="`XVotingHandler`'s `currentGameConfig` variable value of %1 is out-of-bounds for `XVotingHandler.gameConfig` of length %2. Report this issue.")
fatBadGameConfigIndexAdapter = (l=LOG_Fatal,m="`XVotingHandler`'s `currentGameConfig` variable value of %1 is out-of-bounds for `VHAdapter` of length %2. Report this issue.")

Loading…
Cancel
Save