mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 09:30:45 +00:00
Add new public game modifiers 🙂 (#3500)
## Description: Adds 5 new public game modifiers to the Special game mode modifier pool: - **Ports Disabled** - disables port construction, focus on factories - **Nukes Disabled** - disables atom bombs, hydrogen bombs, MIRVs, missile silos and SAM launchers - **SAMs Disabled** - disables SAM launchers (thats funny, you cant protect against nukes, have to space out your stuff) (mutually exclusive with nukes disabled) - **1M Starting Gold** - gives all players 1M starting gold (was requested by people, new chill tier alongside existing 5M and 25M) - **4min Peace Time** - grants 4 minutes of PVP spawn immunity All `PublicGameModifiers` boolean fields are now optional - inactive modifiers are omitted from game JSON instead of being serialized as `false` (stop bloating the JSON size) I think we have enough modifiers now :) Good variety ## Please complete the following: - [X] I have added screenshots for all UI updates - [X] I process any text displayed to the user through translateText() and I've added it to the en.json file - [X] I have added relevant tests to the test directory - [X] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: FloPinguin
This commit is contained in:
+89
-34
@@ -12,6 +12,7 @@ import {
|
||||
Quads,
|
||||
RankedType,
|
||||
Trios,
|
||||
UnitType,
|
||||
mapCategories,
|
||||
} from "../core/game/Game";
|
||||
import { PseudoRandom } from "../core/PseudoRandom";
|
||||
@@ -103,27 +104,40 @@ type ModifierKey =
|
||||
| "isCompact"
|
||||
| "isCrowded"
|
||||
| "isHardNations"
|
||||
| "startingGold"
|
||||
| "startingGoldHigh"
|
||||
| "startingGold1M"
|
||||
| "startingGold5M"
|
||||
| "startingGold25M"
|
||||
| "goldMultiplier"
|
||||
| "isAlliancesDisabled";
|
||||
| "isAlliancesDisabled"
|
||||
| "isPortsDisabled"
|
||||
| "isNukesDisabled"
|
||||
| "isSAMsDisabled"
|
||||
| "isPeaceTime";
|
||||
|
||||
// Each entry represents one "ticket" in the pool. More tickets = higher chance of selection.
|
||||
const SPECIAL_MODIFIER_POOL: ModifierKey[] = [
|
||||
...Array<ModifierKey>(2).fill("isRandomSpawn"),
|
||||
...Array<ModifierKey>(8).fill("isCompact"),
|
||||
...Array<ModifierKey>(1).fill("isCrowded"),
|
||||
...Array<ModifierKey>(5).fill("isCompact"),
|
||||
...Array<ModifierKey>(2).fill("isCrowded"),
|
||||
...Array<ModifierKey>(1).fill("isHardNations"),
|
||||
...Array<ModifierKey>(8).fill("startingGold"),
|
||||
...Array<ModifierKey>(1).fill("startingGoldHigh"),
|
||||
...Array<ModifierKey>(3).fill("startingGold1M"),
|
||||
...Array<ModifierKey>(5).fill("startingGold5M"),
|
||||
...Array<ModifierKey>(1).fill("startingGold25M"),
|
||||
...Array<ModifierKey>(4).fill("goldMultiplier"),
|
||||
...Array<ModifierKey>(1).fill("isAlliancesDisabled"),
|
||||
...Array<ModifierKey>(1).fill("isPortsDisabled"),
|
||||
...Array<ModifierKey>(1).fill("isNukesDisabled"),
|
||||
...Array<ModifierKey>(1).fill("isSAMsDisabled"),
|
||||
...Array<ModifierKey>(1).fill("isPeaceTime"),
|
||||
];
|
||||
|
||||
// Modifiers that cannot be active at the same time.
|
||||
const MUTUALLY_EXCLUSIVE_MODIFIERS: [ModifierKey, ModifierKey][] = [
|
||||
["startingGold", "startingGoldHigh"],
|
||||
["isHardNations", "startingGoldHigh"],
|
||||
["startingGold5M", "startingGold25M"],
|
||||
["startingGold5M", "startingGold1M"],
|
||||
["startingGold25M", "startingGold1M"],
|
||||
["isHardNations", "startingGold25M"],
|
||||
["isNukesDisabled", "isSAMsDisabled"],
|
||||
];
|
||||
|
||||
export class MapPlaylist {
|
||||
@@ -144,13 +158,14 @@ export class MapPlaylist {
|
||||
const playerTeams =
|
||||
mode === GameMode.Team ? this.getTeamCount(map) : undefined;
|
||||
|
||||
let isCompact = this.playlists[type].length % 3 === 0;
|
||||
let isCompact: boolean | undefined =
|
||||
this.playlists[type].length % 3 === 0 || undefined;
|
||||
if (
|
||||
isCompact &&
|
||||
mode === GameMode.Team &&
|
||||
!(await this.supportsCompactMapForTeams(map, playerTeams!))
|
||||
) {
|
||||
isCompact = false;
|
||||
isCompact = undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -162,10 +177,6 @@ export class MapPlaylist {
|
||||
gameMapSize: isCompact ? GameMapSize.Compact : GameMapSize.Normal,
|
||||
publicGameModifiers: {
|
||||
isCompact,
|
||||
isRandomSpawn: false,
|
||||
isCrowded: false,
|
||||
isHardNations: false,
|
||||
isAlliancesDisabled: false,
|
||||
},
|
||||
difficulty:
|
||||
playerTeams === HumansVsNations ? Difficulty.Hard : Difficulty.Medium,
|
||||
@@ -216,7 +227,8 @@ export class MapPlaylist {
|
||||
excludedModifiers.push("isHardNations");
|
||||
}
|
||||
if (playerTeams === HumansVsNations) {
|
||||
excludedModifiers.push("startingGoldHigh"); // Nations are disabled if that modifier is active
|
||||
excludedModifiers.push("startingGold25M"); // Nations are disabled if that modifier is active (Because of PVP immunity)
|
||||
excludedModifiers.push("isPeaceTime"); // Nations don't have PVP immunity
|
||||
}
|
||||
|
||||
const poolResult = this.getRandomSpecialGameModifiers(excludedModifiers);
|
||||
@@ -228,26 +240,34 @@ export class MapPlaylist {
|
||||
goldMultiplier,
|
||||
isAlliancesDisabled,
|
||||
isHardNations,
|
||||
isPortsDisabled,
|
||||
isNukesDisabled,
|
||||
isSAMsDisabled,
|
||||
isPeaceTime,
|
||||
} = poolResult;
|
||||
|
||||
// Crowded modifier: if the map's biggest player count (first number of calculateMapPlayerCounts) is 60 or lower (small maps),
|
||||
// set player count to MAX_PLAYER_COUNT (or 60 if compact map is also enabled)
|
||||
let crowdedMaxPlayers: number | undefined;
|
||||
if (isCrowded) {
|
||||
crowdedMaxPlayers = await this.getCrowdedMaxPlayers(map, isCompact);
|
||||
crowdedMaxPlayers = await this.getCrowdedMaxPlayers(map, !!isCompact);
|
||||
if (crowdedMaxPlayers !== undefined) {
|
||||
crowdedMaxPlayers = this.adjustForTeams(crowdedMaxPlayers, playerTeams);
|
||||
} else {
|
||||
// Map doesn't support crowded. Drop it and pick one replacement only
|
||||
// if it was the sole modifier, so the lobby always has at least one.
|
||||
isCrowded = false;
|
||||
isCrowded = undefined;
|
||||
if (
|
||||
!isRandomSpawn &&
|
||||
!isCompact &&
|
||||
!isHardNations &&
|
||||
startingGold === undefined &&
|
||||
goldMultiplier === undefined &&
|
||||
!isAlliancesDisabled
|
||||
!isAlliancesDisabled &&
|
||||
!isPortsDisabled &&
|
||||
!isNukesDisabled &&
|
||||
!isSAMsDisabled &&
|
||||
!isPeaceTime
|
||||
) {
|
||||
excludedModifiers.push("isCrowded");
|
||||
const fallback = this.getRandomSpecialGameModifiers(
|
||||
@@ -260,6 +280,10 @@ export class MapPlaylist {
|
||||
startingGold,
|
||||
goldMultiplier,
|
||||
isAlliancesDisabled,
|
||||
isPortsDisabled,
|
||||
isNukesDisabled,
|
||||
isSAMsDisabled,
|
||||
isPeaceTime,
|
||||
} = fallback);
|
||||
({ isHardNations } = fallback);
|
||||
}
|
||||
@@ -279,6 +303,28 @@ export class MapPlaylist {
|
||||
? "disabled"
|
||||
: "default";
|
||||
|
||||
// Build disabledUnits from modifiers
|
||||
const disabledUnits: UnitType[] = [];
|
||||
if (isPortsDisabled) {
|
||||
disabledUnits.push(UnitType.Port);
|
||||
}
|
||||
if (isNukesDisabled) {
|
||||
disabledUnits.push(
|
||||
UnitType.MissileSilo,
|
||||
UnitType.AtomBomb,
|
||||
UnitType.HydrogenBomb,
|
||||
UnitType.MIRV,
|
||||
UnitType.SAMLauncher,
|
||||
);
|
||||
}
|
||||
if (isSAMsDisabled) {
|
||||
disabledUnits.push(UnitType.SAMLauncher);
|
||||
}
|
||||
|
||||
// 3min peace = 180s = 1800 ticks
|
||||
// 4min peace = 240s = 2400 ticks
|
||||
const peaceTimeDuration = isPeaceTime ? 240 * 10 : undefined;
|
||||
|
||||
return {
|
||||
donateGold: mode === GameMode.Team,
|
||||
donateTroops: mode === GameMode.Team,
|
||||
@@ -294,10 +340,14 @@ export class MapPlaylist {
|
||||
startingGold,
|
||||
goldMultiplier,
|
||||
isAlliancesDisabled,
|
||||
isPortsDisabled,
|
||||
isNukesDisabled,
|
||||
isSAMsDisabled,
|
||||
isPeaceTime,
|
||||
},
|
||||
startingGold,
|
||||
goldMultiplier,
|
||||
disableAlliances: isAlliancesDisabled,
|
||||
disableAlliances: isAlliancesDisabled ? true : undefined,
|
||||
difficulty:
|
||||
isHardNations || playerTeams === HumansVsNations
|
||||
? Difficulty.Hard
|
||||
@@ -306,16 +356,15 @@ export class MapPlaylist {
|
||||
infiniteTroops: false,
|
||||
maxTimerValue: undefined,
|
||||
instantBuild: false,
|
||||
randomSpawn: isRandomSpawn,
|
||||
randomSpawn: isRandomSpawn ? true : false,
|
||||
nations,
|
||||
gameMode: mode,
|
||||
playerTeams,
|
||||
bots: isCompact ? 100 : 400,
|
||||
spawnImmunityDuration: this.getSpawnImmunityDuration(
|
||||
playerTeams,
|
||||
startingGold,
|
||||
),
|
||||
disabledUnits: [],
|
||||
spawnImmunityDuration:
|
||||
peaceTimeDuration ??
|
||||
this.getSpawnImmunityDuration(playerTeams, startingGold),
|
||||
disabledUnits,
|
||||
} satisfies GameConfig;
|
||||
}
|
||||
|
||||
@@ -476,17 +525,23 @@ export class MapPlaylist {
|
||||
}
|
||||
|
||||
return {
|
||||
isRandomSpawn: selected.has("isRandomSpawn"),
|
||||
isCompact: selected.has("isCompact"),
|
||||
isCrowded: selected.has("isCrowded"),
|
||||
isHardNations: selected.has("isHardNations"),
|
||||
startingGold: selected.has("startingGoldHigh")
|
||||
isRandomSpawn: selected.has("isRandomSpawn") || undefined,
|
||||
isCompact: selected.has("isCompact") || undefined,
|
||||
isCrowded: selected.has("isCrowded") || undefined,
|
||||
isHardNations: selected.has("isHardNations") || undefined,
|
||||
startingGold: selected.has("startingGold25M")
|
||||
? 25_000_000
|
||||
: selected.has("startingGold")
|
||||
: selected.has("startingGold5M")
|
||||
? 5_000_000
|
||||
: undefined,
|
||||
: selected.has("startingGold1M")
|
||||
? 1_000_000
|
||||
: undefined,
|
||||
goldMultiplier: selected.has("goldMultiplier") ? 2 : undefined,
|
||||
isAlliancesDisabled: selected.has("isAlliancesDisabled"),
|
||||
isAlliancesDisabled: selected.has("isAlliancesDisabled") || undefined,
|
||||
isPortsDisabled: selected.has("isPortsDisabled") || undefined,
|
||||
isNukesDisabled: selected.has("isNukesDisabled") || undefined,
|
||||
isSAMsDisabled: selected.has("isSAMsDisabled") || undefined,
|
||||
isPeaceTime: selected.has("isPeaceTime") || undefined,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user