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. 15
      sources/GameModes/BaseGameMode.uc
  2. 91
      sources/GameModes/GameMode.uc
  3. 97
      sources/VotingHandlerAdapter.uc

15
sources/GameModes/BaseGameMode.uc

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

91
sources/GameModes/GameMode.uc

@ -39,11 +39,21 @@ var protected config string acronym;
// this game mode (plain string) // this game mode (plain string)
var protected config string mapPrefix; 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() protected function DefaultIt()
{ {
title = "Acedia game mode"; title = "Acedia game mode";
length = "long";
difficulty = "Hell On Earth"; difficulty = "Hell On Earth";
gameTypeClass = "KFMod.KFGameType"; gameTypeClass = "KFMod.KFGameType";
acronym = ""; acronym = "";
@ -176,20 +186,95 @@ public function HashTable GetOptions()
{ {
local int i; local int i;
local HashTable result; local HashTable result;
local Text nextKey, nextValue;
result = _.collections.EmptyHashTable(); result = _.collections.EmptyHashTable();
for (i = 0; i < option.length; i += 1) for (i = 0; i < option.length; i += 1)
{ {
if (!ValidateServerURLName(option[i].key)) continue; if (!ValidateServerURLName(option[i].key)) continue;
if (!ValidateServerURLName(option[i].value)) continue; if (!ValidateServerURLName(option[i].value)) continue;
result.SetItem( _.text.FromString(option[i].key), if (option[i].key ~= "difficulty")
_.text.FromString(option[i].value)); {
_.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; 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 defaultproperties
{ {
configName = "AcediaGameModes" configName = "AcediaGameModes"
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.") 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. * 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. // All available game modes for Acedia, loaded during initialization.
// This array is directly produces replacement for `XVotingHandler`'s // This array is directly produces replacement for `XVotingHandler`'s
// `gameConfig` array and records of `availableGameModes` relate to those of // `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. // 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 // But to not affect game's configs we must restore old value after new map is
// loaded. Store it in config variable for that. // 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 fatNoXVotingHandler, fatBadGameConfigIndexVH;
var private LoggerAPI.Definition fatBadGameConfigIndexAdapter; var private LoggerAPI.Definition fatBadGameConfigIndexAdapter;
@ -201,6 +200,7 @@ public final function PrepareForServerTravel()
local GameMode nextGameMode; local GameMode nextGameMode;
local string nextGameClassName; local string nextGameClassName;
local class<GameInfo> nextGameClass; local class<GameInfo> nextGameClass;
local class<KFGameType> nextKFGameType;
local XVotingHandler votingHandler; local XVotingHandler votingHandler;
if (votingHandlerReference == none) return; if (votingHandlerReference == none) return;
@ -235,9 +235,15 @@ public final function PrepareForServerTravel()
} }
isServerTraveling = true; isServerTraveling = true;
targetGameMode = availableGameModes[pickedVHConfig].ToString(); targetGameMode = availableGameModes[pickedVHConfig].ToString();
nextGameMode = GetConfigFromString(default.targetGameMode); nextGameMode = GetConfigFromString(targetGameMode);
storedGameDifficulty = nextGameClass.default.gameDifficulty; nextKFGameType = class<KFGameType>(nextGameClass);
nextGameClass.default.gameDifficulty = GetNumericDifficulty(nextGameMode); if (nextKFGameType != none)
{
storedGameLength = nextKFGameType.default.kfGameLength;
nextKFGameType.default.kfGameLength =
GetNumericGameLength(nextGameMode);
}
nextGameClass.static.StaticSaveConfig();
SaveConfig(); SaveConfig();
} }
@ -250,11 +256,17 @@ public final function PrepareForServerTravel()
*/ */
public final function GameMode SetupGameModeAfterTravel() public final function GameMode SetupGameModeAfterTravel()
{ {
local KFGameType kfGameType;
if (!isServerTraveling) { if (!isServerTraveling) {
return none; return none;
} }
_server.unreal.GetGameType().default.gameDifficulty = storedGameDifficulty; kfGameType = _server.unreal.GetKFGameType();
if (kfGameType != none) {
kfGameType.default.kfGameLength = storedGameLength;
}
isServerTraveling = false; isServerTraveling = false;
_server.unreal.GetGameType().StaticSaveConfig();
SaveConfig(); SaveConfig();
return GetConfigFromString(targetGameMode); return GetConfigFromString(targetGameMode);
} }
@ -289,43 +301,37 @@ private function GameMode GetConfigFromString(string configName)
// Convert `GameMode`'s difficulty's textual representation into // Convert `GameMode`'s difficulty's textual representation into
// KF's numeric one. // KF's numeric one.
private final function int GetNumericDifficulty(GameMode gameMode) private final function int GetNumericGameLength(BaseGameMode gameMode)
{ {
local int i; local int i;
local string difficulty; local string length;
difficulty = Locs(_.text.IntoString(gameMode.GetDifficulty())); length = Locs(_.text.IntoString(gameMode.GetLength()));
for (i = 0; i < default.beginnerSynonyms.length; i += 1) for (i = 0; i < default.shortSynonyms.length; i += 1)
{ {
if (IsPrefixOf(difficulty, default.beginnerSynonyms[i])) { if (IsPrefixOf(length, default.shortSynonyms[i])) {
return 1; return 0;
} }
} }
for (i = 0; i < default.normalSynonyms.length; i += 1) for (i = 0; i < default.normalSynonyms.length; i += 1)
{ {
if (IsPrefixOf(difficulty, default.normalSynonyms[i])) { if (IsPrefixOf(length, default.normalSynonyms[i])) {
return 2; return 1;
}
}
for (i = 0; i < default.hardSynonyms.length; i += 1)
{
if (IsPrefixOf(difficulty, default.hardSynonyms[i])) {
return 4;
} }
} }
for (i = 0; i < default.suicidalSynonyms.length; i += 1) for (i = 0; i < default.longSynonyms.length; i += 1)
{ {
if (IsPrefixOf(difficulty, default.suicidalSynonyms[i])) { if (IsPrefixOf(length, default.longSynonyms[i])) {
return 5; 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])) { if (IsPrefixOf(length, default.customSynonyms[i])) {
return 7; return 3;
} }
} }
return int(difficulty); return 3;
} }
protected final static function bool IsPrefixOf(string prefix, string value) 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 defaultproperties
{ {
beginnerSynonyms(0) = "easy" shortSynonyms(0) = "short"
beginnerSynonyms(1) = "beginer" normalSynonyms(0) = "normal"
beginnerSynonyms(2) = "beginner" normalSynonyms(1) = "medium"
beginnerSynonyms(3) = "begginer" normalSynonyms(2) = "regular"
beginnerSynonyms(4) = "begginner" longSynonyms(0) = "long"
normalSynonyms(0) = "regular" customSynonyms(0) = "custom"
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"
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`).") 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.") 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.") 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