Commit Graph

3250 Commits

Author SHA1 Message Date
scamiv ea2a76609f perf(core): speed up packedTileUpdates (Uint32 pairs, no tile wrappers) (#3255)
## Description
Reduces CPU + GC pressure from tile update serialization.

**What changed**
- Switched `packedTileUpdates` from `BigUint64Array` (BigInt packing) to
`Uint32Array` `[tileRef, state]` pairs, updating `GameView` ingestion.
- Updated tile state to use `GameMap.tileState(tile)` and
`GameMap.updateTile(tile, state)`.
- Removed per-tile `GameUpdateType.Tile` wrapper allocations by
recording raw `(tile, state)` pairs in `GameImpl` and draining them via
`drainPackedTileUpdates()` in `GameRunner`.

**Why it’s faster**
- Avoids BigInt and pack/unpack.
- Avoids per-tile object allocations.

**Compatibility**
- Wire format change: `packedTileUpdates` is now `Uint32Array` pairs
instead of `BigUint64Array`.

## Please complete the following:

- [ ] I have added screenshots for all UI updates
- [ ] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [ ] I have added relevant tests to the test directory
- [ ] 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:

DISCORD_USERNAME
2026-02-20 23:01:03 -06:00
VariableVince 444aa16ac8 Fix: less console warn spam on each attack-click (#3262)
## Description:

Rabbit suggestion to move console warn for not being able to send boat
to doBoatAttackUnderCursor and remove it from canBoatAttack.

On each attack-click on land, if that land is own land or ally and
canAttack is false, it will check canAutoBoat. Even if user had no
intention to attack, there would be a warning that no boat could be
send. Now only do that warning when user actually intended to send a
boat using hotkey G which calls doBoatAttackUnderCursor.

## 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:

tryout33
2026-02-20 22:58:14 -06:00
evanpelle b865e0af8f bugfix: ranked 1v1 did not set the start time, so the game started immediately before players had time to join 2026-02-20 13:32:36 -06:00
FloPinguin 07b5d6e41f Prevent self-retaliation crash when own nuke destroys own ship 🔧 (#3260)
## Description:

Noticed this in two singleplayer games:

When a nation's nuke destroys its own transport/trade ship in the blast
radius, `NationWarshipBehavior` incorrectly tries to retaliate against
itself, calling `updateRelation(self)` which throws (GameRunner tick
error).

Added a self-check in `maybeRetaliateWithWarship` to skip retaliation
when the destroyer is the player itself.

## 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
2026-02-20 17:44:57 +00:00
FloPinguin 354c703d39 Reduce main page images filesize by 90% 🖼️ (#3258)
## Description:

Reduce main page images filesize by 90%
Converted to webp

## 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
2026-02-20 17:27:16 +00:00
Mattia Migliorini 90204f6628 Add alliance renewal action to Radial Menu (#3148)
## Description:

The following PR replaces the (disabled) alliance request button with an
alliance extension/renewal button when the alliance with the target
player is expiring.

Agreeing to renewal via radial menu also hides the message in the
EventsDisplay.

<img width="369" height="364" alt="image"
src="https://github.com/user-attachments/assets/d8040f5c-ad7b-47d0-852f-925ecbf273a8"
/>


https://github.com/user-attachments/assets/aa589edf-6505-46bf-88a3-aa4c2df9137f

Icon size adjusted:

<img width="294" height="252" alt="image"
src="https://github.com/user-attachments/assets/7ca63500-b1fb-427b-965c-cf121a5213da"
/>

## 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:

deshack_82603

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-02-19 19:47:57 -06:00
scamiv f6a08e16db Perf alloc (#3241)
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves #(issue number)

## Description:

## PR Title
perf(core): reduce hot-path allocations & safe optimizations

This PR brings in a set of allocation-focused optimizations in core hot
paths

### Scope
- `src/core/execution/NukeExecution.ts`
- `src/core/execution/WarshipExecution.ts`
- `src/core/game/UnitGrid.ts`
- `src/core/game/PlayerImpl.ts`
- `src/core/configuration/DefaultConfig.ts`
- `src/core/execution/SAMLauncherExecution.ts`

### What Changed
- `NukeExecution.detonate`: reduced call overhead/allocations by caching
`mg`/`config`, avoiding repeated lookups, and using allocation-free
loops (no `forEach` closures) in the diminishing-effect pass.
- `WarshipExecution.findTargetUnit`: replaced allocate+sort flow with
single-pass best-target selection.
- `UnitGrid.nearbyUnits`: reduced call overhead and allocations via
single-type fast path and cached query coordinates.
- `PlayerImpl.units`: added fast paths for common small-arity type
queries (1-3 unit types).
- `DefaultConfig.unitInfo`: cached `UnitInfo` objects per `UnitType` to
avoid repeated object/closure creation.
- `SAMLauncherExecution` targeting: removed sort churn and streamlined
target selection with single-pass hydrogen prioritization.



### Rebase
- One conflict was resolved in `NukeExecution.detonate` by keeping
`main`'s diminishing-effect-per-impacted-tile behavior, while retaining
the allocation-reduction refactors.


## Please complete the following:

- [ ] I have added screenshots for all UI updates
- [ ] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [ ] I have added relevant tests to the test directory
- [ ] 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:

DISCORD_USERNAME
2026-02-19 19:01:12 -06:00
VariableVince c235debb57 Cleanup: Replace literals by enums (#3252)
## Description:

Some literals were present that could/should have been enums. Replaced
them.

For Util.ts > createRandomName, also changed type of parameter
playerType from string to PlayerType. All callers already send it this
type.

## 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:

tryout33
2026-02-19 16:58:07 -06:00
scamiv fcf45db672 perf(core): reduce packed tile update churn (#3253)
## Description:
- Build packedTileUpdates directly into a BigUint64Array (avoid
intermediate JS array + copy).

- Transfer packedTileUpdates.buffer in worker postMessage to avoid
structured-clone.


- Avoids large short-lived allocations during tile-update (lower peak
heap and GC pressure).
- Prevents duplicating buffers across thread boundaries when the main
thread is behind. (one buffer per queued update, not two)

**Notes**

- after postMessage(..., [packedTileUpdates.buffer]) transfer the
worker’s packedTileUpdates becomes unusable (its .buffer is detached).


- [ ] I have added screenshots for all UI updates
- [ ] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [ ] I have added relevant tests to the test directory
- [ ] 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:

DISCORD_USERNAME
2026-02-19 15:53:46 -06:00
VariableVince 7ee07fc9f0 Homepage mobile: put Solo and Ranked buttons above the public lobbies (#3245)
## Description:

Put Solo and Ranked above the public lobby buttons on mobile.

The Solo, Ranked, Create Lobby and Join Lobby buttons fall outside of
view on the average mobile screen. Since Solo is the most played game
mode and could probably be more directed to beginners, this button needs
to be in view for those who don't realize right away that there are more
buttons when scrolling down.

Ranked just has its place to the right of it and moves with it.

Create Lobby and Join Lobby are for players who already know their way
around a bit, so it's ok if they stay at the bottom. This way we
advertise having 3 public lobbies as well, as all 3 are in view always
(the 3rd at least partly which makes one curious to look what lobby it
is showing).

**BEFORE**

https://github.com/user-attachments/assets/c56e124e-069a-48bd-8860-c1113cca102f

**AFTER**

https://github.com/user-attachments/assets/83306828-d1e1-439e-9058-7f741d704ea3

## 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:

tryout33

---------

Co-authored-by: Ryan <7389646+ryanbarlow97@users.noreply.github.com>
2026-02-19 19:12:59 +00:00
FloPinguin bb1ddfbcaa Make "Not Logged In" button open Account modal & fix Account loading state (#3247)
## Description:

**TerritoryPatternsModal.ts**
- Changed the "Not Logged In" indicator from a static `div` to a
clickable `button`
- Clicking it now closes the skins modal and navigates to the Account
page via `window.showPage("page-account")`
- Added hover effect (`hover:bg-red-500/30`) for visual feedback

**AccountModal.ts**
- Fixed the inline Account modal's loading state ("Fetching account
information...") rendering without a background or header (white text on
light background 💀)
- The loading spinner is now wrapped in `modalContainerClass` (dark
glassmorphic background) with a proper `modalHeader` including the title
and back button, matching the loaded state's appearance

**SinglePlayerModal.ts**
- Changed the "Sign in for achievements" banner from a static `div` to a
clickable `button` that closes the modal and navigates to the Account
page
- Added hover effect for visual feedback

**Matchmaking.ts**
- When the "You must be logged in to play ranked matchmaking" toast
appears, the user is now also navigated to the Account page so they can
log in immediately

## 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
2026-02-19 18:01:27 +00:00
Ryan 70f2abb181 Homepage update & add 3 public lobbies (#3191)
## Description:

Update UI 
check https://homepageupdate.openfront.dev/ 

Improved mobile UI (now fills whole screen for all modals) e.g.:
<img width="432" height="852" alt="image"
src="https://github.com/user-attachments/assets/56de40af-4137-4c57-96b7-3910c9a665b8"
/>

Converted PublicLobby to be "GameModeSelector" to get a nicer 4x4 grid
div, where <GameModeSelector> now handles all the username validation
now (removed redundant code from modals such as matchmaking) also fixed
a bug where someone could have "[XX] X" as thier username (when the
minimum should be 3 chars for their name)

Now visually displays the 3 lobbies ffa/team/special (which is a
continuation from the work done in: #3196 )
<img width="818" height="563" alt="image"
src="https://github.com/user-attachments/assets/a15cd31b-6061-4fb8-83ee-ffde6225cfa7"
/>

updated the background:
<img width="1919" height="807" alt="image"
src="https://github.com/user-attachments/assets/358a7434-51b8-4540-baf2-d1be05053c44"
/>



slightly updated the glassy-look to be less glassy:
<img width="825" height="729" alt="image"
src="https://github.com/user-attachments/assets/1801871b-bbf8-43db-ac53-489337ae80a5"
/>



## 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:

w.o.n
2026-02-18 23:11:01 -06:00
VariableVince 2a7db43db3 Small refactor/cleanup: RadialMenuElements and PlayerImpl (#3239)
## Description:

PR 7/x in effort to break up PR #3220. Follows on already merged #3238.

Please see if these can be merged for v30.

-**RadialMenuElements**: 
- _getAllEnabledUnits_: use camelCase instead of PascalCase so change
Units into units.
- _getAllEnabledUnits_: use StructureTypes to loop through instead of
having 6 individual lines of code to check if a structure is enabled.
StructureTypes contains and will keep containing the same structures as
those that are checked here. PR 3220 will later on also replace the
individual lines for the attack type units into a loop with a newly
introduced Types array, in the same way as we do in this PR with
StructureTypes.
- _getAllEnabledUnits_: rename the long named const
addStructureIfEnabled to just addIfEnabled, which is clear enough from
the context it is used in.

-**PlayerImpl**
- _buildableUnits_: removed unnecessary "as BuildableUnit" after the
in-loop return; the function itself already says it returns
BuildableUnit[].

## 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:

tryout33
2026-02-19 00:27:12 +00:00
DevelopingTom 031a17d880 Optimize nuke explosion (#3176)
## Description:

When a nuke detonates, the explosion is looping over each tiles. Among
other things, it filters the owner units to find the `TransportShips`
units.

This operation is cpu-intensive and repeated over each tiles can make
the tick noticably slower.

On this screenshot the detonation function took 100ms:
<img width="1617" height="488" alt="image"
src="https://github.com/user-attachments/assets/07009b18-4342-4caf-9e82-9ae5147b63f8"
/>
<img width="1645" height="375" alt="image"
src="https://github.com/user-attachments/assets/fe9ead87-550a-4166-96ab-092d0c08be82"
/>

I suspect it led to a few frame freeze when I MIRVed too.

Suggestion: loop over the impacted players rather than the tiles.

With this suggestion, the same nuke takes between 4ms to 20ms:
<img width="989" height="365" alt="image"
src="https://github.com/user-attachments/assets/25c0faf0-cc34-41b7-8091-b14bde6db595"
/>


However this changes the death formula used, as they were repeated over
each tiles with ever-smaller values, and with this change the operation
is done all-at-once. This will result in a different outcome.

In my opinion the performance gain is seductive enough to maybe tweak
the formula to make it work with this revised strategy.
What do you think?

## Please complete the following:

- [ ] I have added screenshots for all UI updates
- [ ] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [ ] I have added relevant tests to the test directory
- [ ] 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:

IngloriousTom
2026-02-18 17:00:56 -06:00
VariableVince 8b66c8bd53 Perf/refactor: use StructureTypes, remove territoryBound (#3238)
## Description:

PR 6/x in effort to break up PR
https://github.com/openfrontio/OpenFrontIO/pull/3220. Follows on already
merged https://github.com/openfrontio/OpenFrontIO/pull/3237.

Please see if these can be merged for v30.

- **PlayerImpl**: validStructureSpawnTiles did a filter on unit types to
get isTerroritoryBound units, on every call again. It read this from
unit info in DefaultConfig. While having it centrally in DefaultConfig
unitInfo is good for maintainability, other code uses hardcoded
StructureTypes and isisStructureType from Game.ts. Which has the same
purpose and thus contains the same unit types. StructureTypes and
isisStructureType do need manual maintainance outside of DefaultConfig.
And are more bug prone/less type safe. But, using them gives more speed
compared to getting these unit types out of DefaultConfig unitInfo
centrally with some cached function in GameImpl for example (tested with
buildableUnits and MIRVPerf.ts). So I went with StructureTypes in
validStructureSpawnTiles too.

- **PlayerExecution**: now validStructureSpawnTiles no longer needs
isTerritoryBound (see the point above), PlayerExecution is the last
place where it was used. Replaced it for isStructureType here too (since
it has the same meaning and outcome).

- **Game.ts** and **DefaultConfig** unitInfo: remove the now unused
_territoryBound_. As it was only used in validStructureSpawnTiles and
PlayerExecution and has been replaced in both (see the two points
above).

## 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:

tryout33
2026-02-18 22:43:16 +00:00
VariableVince 348ccfc2c3 Perf/small refactor: NationStructureBehavio (#3237)
## Description:

PR 5/x in effort to break up PR
https://github.com/openfrontio/OpenFrontIO/pull/3220. Follows on already
merged https://github.com/openfrontio/OpenFrontIO/pull/3236.

Please see if these can be merged for v30.

**NationStructureBehavior**:
- maybeSpawnStructure: cache this.game to be used twice.
- maybeSpawnStructure: instead of hardcoded ruling out Defense Post for
upgrade check, check dynamically if type is upgradable. That way if
defense posts ever do become upgradable, we don't run into a bug right
away.

- maybeUpgradeStructure: removed canUpgradeUnit check. Since it already
checked this right before in findBestStructureToUpgrade, so only
upgradable units are returned. And canUpgradeUnit is also checked right
after in UpgradeStructureExecution. So we're going from 3 times to 2
times canUpgradeUnit, small perf win too.

- findBestStructureToUpgrade: cache this.game to be used thrice.

- shouldBuildStructure: cache this.game.config() to be used twice.

- getTotalStructureDensity: this.player.units can handle an array of
unit types to count. Input StructureTypes like this so we don't need a
loop and count, and only have to get an array length once.
getTotalStructureDensity needs to ignore unit levels so we can't make
use of other pre-defined functions in PlayerImpl (which were created to
avoid array length calls), but at least this saves a few.

## 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:

tryout33
2026-02-18 22:23:01 +00:00
evanpelle 4a88f1d089 increase max json size to 5mb so allow receiving larger singleplayer games 2026-02-18 16:13:20 -06:00
VariableVince 4f08e57304 Small refactor: nearbyUnits readonly UnitType[] (#3236)
## Description:

PR 4/x in effort to break up PR
https://github.com/openfrontio/OpenFrontIO/pull/3220. Follows on already
merged https://github.com/openfrontio/OpenFrontIO/pull/3235.

Please see if these can be merged for v30.

- **Game**/**GameImpl**/**GameView**: nearbyUnits required "UnitType |
UnitType[]" for tiles, but calls UnitGrid nearbyUnits which requires
"UnitType | readonly UnitType[]". Made the requirement the same for
Game/GameImpl/GameView nearbyUnits. This way, we don't have make a
shallow copy of the StructureTypes array everytime we want to send it as
an argument. Other callers than listNukeBreakAlliance in Util.ts are
unaffected.
- **Util.ts**: listNukeBreakAlliance needs no shallow copy of
StructureTypes anymore as argument for NearbyUnits

## 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:

tryout33
2026-02-18 21:51:36 +00:00
Mattia Migliorini ba2a947061 Feat: Display ghost railways when building cities and ports (#3202)
## Description:

Based on [this suggestion on
Discord](https://discord.com/channels/1284581928254701718/1447110257196138577)
and feedback gathered in [this
thread](https://discord.com/channels/1359946986937258015/1469598906173227184).

Supersedes #3143 

This PR introduces "ghost railways": when you are going to place a city
or port, previews railway connections that will be made when actually
building the structure.

Ghost railways are skipped if the structure is going to be snapped to
existing railways (as in railway snapping functionality introduced in
#3156 ).

### Video


https://github.com/user-attachments/assets/ff8cf325-6501-4df8-801d-c8ae3ced3d0e


### Ghost rails color revisited

black with 40% opacity

<img width="695" height="430" alt="image"
src="https://github.com/user-attachments/assets/272efbcc-4185-426a-921c-7fae61f6c462"
/>


## 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:

deshack_82603
2026-02-18 21:44:08 +00:00
evanpelle f7ebde1c7f reduce error log spam: don't error on client id mismatch and don't log abort in worker matchmaking polling 2026-02-18 15:42:00 -06:00
VariableVince f1cd478970 Cleanup/refactor: Remove some redundant checks (#3235)
## Description:

PR 3/x in effort to break up PR
https://github.com/openfrontio/OpenFrontIO/pull/3220. Follows on already
merged https://github.com/openfrontio/OpenFrontIO/pull/3233 and
https://github.com/openfrontio/OpenFrontIO/pull/3234.

Please see if these can be merged for v30.

- **ClientGameRunner**: removed two redundant myPlayer===null checks
since that was already done right above, instead use !.
- **BuildMenu**: just like in UnitDisplay, assign public PlayerActions
default value of null. So that in canCreateOrBuild, where we already do
a === null check on it btw, we can safely skip the assignment to const
buildableUnits and just directly loop over
this.playerActions.buildableUnits.
- **RadialMenuElements**: don't call canBuildOrUpgrade 3x in
CreateMenuElements for the .map on flattenedBuildTable, instead do it
once and re-use outcome.

## 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:

tryout33
2026-02-18 21:09:24 +00:00
VariableVince f4f7ae3929 Cleanup: comments in BuildMenu and error messages in worker.worker (#3233)
## Description:

PR 1/x in effort to break up PR
https://github.com/openfrontio/OpenFrontIO/pull/3220.
Please see if these can be merged for v30.

- **BuildMenu**: remove one redundant comment about replacing an icon
(which has been done long ago already). And fix typo in one other
comment.
- **Worker.worker**: correct some existing error messages.

## 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:

tryout33
2026-02-18 20:21:19 +00:00
VariableVince 52036cc20c Cleanup: remove unused code from four files (#3234)
## Description:

PR 2/x in effort to break up PR
https://github.com/openfrontio/OpenFrontIO/pull/3220.

Removes unused code and properties.

- **Game.ts** and **DefaultConfig** unitInfo: removed
_canBuildTrainStation_ and _expirimental_ properties, as they weren't
used anywhere anymore.

- **PlayerActionHandler**: remove unused getPlayerActions, the only
potential caller MainRadialMenu already just calls myPlayer.actions via
GameView directly.

- **StructureIconsLayer**: remove unused PlayerActions

## 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:

tryout33
2026-02-18 20:17:46 +00:00
Evan 2b830e9fcd Update tradeship spawn & gold meta (#3232)
## Description:

Now that pathfinding is much more efficient with hpa*, we can add more
trade ships.

This PR does the following:

1. No gold bonus for additional ports, keeps the meta simple
2. cut the gold per trade ship roughly in half.
3. Use a "pity bonus", the more times a port has failed to spawn a
tradeship, the higher the likelyhood it will spawn one
4. Increase the sigmoid so the mid-point is 200, with a half life of 50.
In tests about ~400 trade ships max.

It's pretty difficult to balance on singleplayer so I'm sure the values
will be adjusted after playtests.

## 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:

evan
2026-02-17 21:40:20 -06:00
Abdallah Bahrawi 7bf6bfd4b9 🔴 Major SAM Targeting Fix (#3223)
## Description:

Bug (before): In multi-nuke scenarios (e.g., 6 incoming nukes), SAMs,
when stacked, could behave like they only engage one nuke at a time,
letting other nukes slip through and wipe the SAM stack. This was most
noticeable when nukes entered from certain angles/entry sides (from what
I’ve noticed, it happens more often in the 2 o’clock to 6 o’clock
direction).

<img width="734" height="743" alt="asadasada"
src="https://github.com/user-attachments/assets/7ca6c9ef-b2b4-47ea-bed2-249a84c8f5ed"
/>

What was fixed:
1- Removed permanent "unreachable" caching: When a nuke was out of SAM
range on first evaluation, it was cached as null (permanently
unreachable) and never re-evaluated. Since nukes move each tick, they
could later enter interception range but would be ignored. The fix
removes this permanent cache, so nukes are re-evaluated every tick.

2 - Moved targetedBySAM filter into the targeting system: The
targetedBySAM() check was at the launch decision, if the
highest-priority nuke was already claimed by another SAM, the launcher
skipped firing entirely instead of falling back to the next best target.
The fix moves the filter inside getSingleTarget() so claimed nukes are
excluded before ranking.

3 - Cleared targetedBySAM flag on SAM missile abort: When a SAM missile
aborted (for example target became allied), the targetedBySAM flag was
never cleared. This permanently prevented all other SAMs from targeting
that nuke. The fix calls setTargetedBySAM(false) on abort so the nuke
becomes available for re-targeting.

**Videos:** 
I uploaded a before/after clip showing SAM performance intercepting 6
nukes, before the fix, nukes could break through, but after the fix,
SAMs consistently intercept as expected.

Before: 

https://github.com/user-attachments/assets/d5a85354-f35c-4aca-82f8-902f5966312b

after:

https://github.com/user-attachments/assets/54074c09-fbdf-44d5-a88c-b1d54b20fee2

- Deployed for further testing

## 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:

abodcraft1

---------

Co-authored-by: Ryan <7389646+ryanbarlow97@users.noreply.github.com>
2026-02-17 23:12:56 +00:00
1brucben 1443b62207 Refactor attacker troop loss calculation (#3227)
## Description:
This PR fixes (at least partially) the attack loss imbalance. Would
recommend adjusting the weighting towards 100% in the long run and then
removing redundant code. I haven't tested it at 100% yet, but it might
actually be fine to change it now. I don't notice any substantial
differences in how the game feels at 50%.


## 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:

1brucben
2026-02-17 14:56:36 -06:00
FloPinguin f276a72635 Remove win modal animation 🖌️ (#3230)
## Description:

Win modal animation looks bugged (https://youtu.be/fmR4nZL5RLg?t=3839)
Just remove it, make the game feel snappier
Reported by Wonder

## 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

Co-authored-by: Ryan <7389646+ryanbarlow97@users.noreply.github.com>
2026-02-17 20:35:38 +00:00
TsProphet94 0b46f90d81 Feature add alps clean (#3229)
## Description:

Fixes closed PR and adds the new “Alps” map and register it in the
game/map playlist. With 7 geographically accurate nations. Pure large
land map for land warfare only.

<img width="2564" height="1400" alt="Untitled"
src="https://github.com/user-attachments/assets/2c51fad3-7345-46a8-9256-2874d1c4211b"
/>

<img width="2000" height="1837"
alt="551068953-fe4445cd-c0b2-4a5a-b652-1e480e38cdb6"
src="https://github.com/user-attachments/assets/1c466262-e20b-46bc-b782-944cbf6ee62a"
/>


![551068657-3125718d-9bf2-44d5-8e3b-a5073df5b785](https://github.com/user-attachments/assets/1abf131a-2e3e-4acf-b205-2bf56f229ed1)

## 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:

TsProphet
2026-02-17 17:22:23 +00:00
FloPinguin 86e51ab790 Fix nation spawnkilling 🔧 (#3222)
## Description:

As far as I can remember, in v28 the spawn immunity applied to both
humans and nations.
With the configurable spawn immunity (added for v29) the spawn immunity
no longer applies to nations... Because its called PVP immunity now.
So right now it's possible to spawnkill nations. This is a big problem
for the 5M gold modifier games... And you can "cheat" in singleplayer.

This PR changes two things:
- Nations always have 5 seconds spawn immunity now, no matter whats
configured for the PVP immunity
- Nations attack TerraNullius earlier (Otherwise the easy nations would
sometimes do their first attack after the 5 seconds are over, spawnkills
would still be possible)

## 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

---------

Co-authored-by: Ryan <7389646+ryanbarlow97@users.noreply.github.com>
2026-02-17 00:19:36 +00:00
FloPinguin 18f52c01bb Improve moble UI again (#3226)
## Description:

- Fix HeadsUpMessage appearing above Settings modal
- Fix HeadsUpMessage appearing above Leaderboard
- Remove PlayerInfoOverlay show/hide animation (we need quick access to
the data!)

- Close PlayerInfoOverlay on tap outside the map (gray area)

- Fix error when tapping gray area outside the map
- Close PlayerInfoOverlay on click/tap on itself


## 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
2026-02-16 23:28:43 +00:00
FloPinguin 4c44da4940 Adjust styling for attack ratio popup and event display button (#3225)
## Description:

Before:

<img width="445" height="501" alt="Screenshot 2026-02-16 205903"
src="https://github.com/user-attachments/assets/3add2b1c-f108-4138-9066-ce16ce9fb76d"
/>

After:

<img width="484" height="515" alt="Screenshot 2026-02-16 210819"
src="https://github.com/user-attachments/assets/cb7ba559-535e-4e87-a4b2-4bf744b98e6e"
/>

## 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
2026-02-16 20:56:50 +00:00
FloPinguin eebe3a7dbc Enhance map loading 🔧 (#3219)
## Description:

While loading the main page we also load a lot of map manifests and
thumbnails.
On prod its especially extreme, because we don't have "featured maps"
there (186 json requests!).
With this PR we only load the files when the map display is in the
viewport.

On main.openfront.dev (main page load):

<img width="425" height="539" alt="image"
src="https://github.com/user-attachments/assets/156338d2-7a3f-4518-a726-cb3dec3df908"
/>

## 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
2026-02-16 11:45:16 -08:00
dependabot[bot] 68ff2773fc Bump qs from 6.14.1 to 6.14.2 in the npm_and_yarn group across 1 directory (#3204)
Bumps the npm_and_yarn group with 1 update in the / directory:
[qs](https://github.com/ljharb/qs).

Updates `qs` from 6.14.1 to 6.14.2
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/ljharb/qs/blob/main/CHANGELOG.md">qs's
changelog</a>.</em></p>
<blockquote>
<h2><strong>6.14.2</strong></h2>
<ul>
<li>[Fix] <code>parse</code>: mark overflow objects for indexed notation
exceeding <code>arrayLimit</code> (<a
href="https://redirect.github.com/ljharb/qs/issues/546">#546</a>)</li>
<li>[Fix] <code>arrayLimit</code> means max count, not max index, in
<code>combine</code>/<code>merge</code>/<code>parseArrayValue</code></li>
<li>[Fix] <code>parse</code>: throw on <code>arrayLimit</code> exceeded
with indexed notation when <code>throwOnLimitExceeded</code> is true (<a
href="https://redirect.github.com/ljharb/qs/issues/529">#529</a>)</li>
<li>[Fix] <code>parse</code>: enforce <code>arrayLimit</code> on
<code>comma</code>-parsed values</li>
<li>[Fix] <code>parse</code>: fix error message to reflect arrayLimit as
max index; remove extraneous comments (<a
href="https://redirect.github.com/ljharb/qs/issues/545">#545</a>)</li>
<li>[Robustness] avoid <code>.push</code>, use <code>void</code></li>
<li>[readme] document that <code>addQueryPrefix</code> does not add
<code>?</code> to empty output (<a
href="https://redirect.github.com/ljharb/qs/issues/418">#418</a>)</li>
<li>[readme] clarify <code>parseArrays</code> and
<code>arrayLimit</code> documentation (<a
href="https://redirect.github.com/ljharb/qs/issues/543">#543</a>)</li>
<li>[readme] replace runkit CI badge with shields.io check-runs
badge</li>
<li>[meta] fix changelog typo (<code>arrayLength</code> →
<code>arrayLimit</code>)</li>
<li>[actions] fix rebase workflow permissions</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/ljharb/qs/commit/bdcf0c7f82387c18ac8fabfccd2f440645cef47b"><code>bdcf0c7</code></a>
v6.14.2</li>
<li><a
href="https://github.com/ljharb/qs/commit/294db90c812ddbe7d7a35d5687c505fd21a2d6a2"><code>294db90</code></a>
[readme] document that <code>addQueryPrefix</code> does not add
<code>?</code> to empty output</li>
<li><a
href="https://github.com/ljharb/qs/commit/5c308e5516c270a78caa6f278465914090f91ec6"><code>5c308e5</code></a>
[readme] clarify <code>parseArrays</code> and <code>arrayLimit</code>
documentation</li>
<li><a
href="https://github.com/ljharb/qs/commit/6addf8cf738d529c54d91f6f3ffb6c1be91bbfdc"><code>6addf8c</code></a>
[Fix] <code>parse</code>: mark overflow objects for indexed notation
exceeding <code>arrayLimit</code></li>
<li><a
href="https://github.com/ljharb/qs/commit/cfc108f662326d6ab540f3545ef0b832baf83cdf"><code>cfc108f</code></a>
[Fix] <code>arrayLimit</code> means max count, not max index, in
<code>combine</code>/<code>merge</code>/`pars...</li>
<li><a
href="https://github.com/ljharb/qs/commit/febb64442a80e49200211fa38d3c96b58024ac77"><code>febb644</code></a>
[Fix] <code>parse</code>: throw on <code>arrayLimit</code> exceeded with
indexed notation when `thr...</li>
<li><a
href="https://github.com/ljharb/qs/commit/f6a7abff1f13d644db9b05fe4f2c98ada6bf8482"><code>f6a7abf</code></a>
[Fix] <code>parse</code>: enforce <code>arrayLimit</code> on
<code>comma</code>-parsed values</li>
<li><a
href="https://github.com/ljharb/qs/commit/fbc5206c25b4d1851cea683f02c10756c521d15a"><code>fbc5206</code></a>
[Fix] <code>parse</code>: fix error message to reflect arrayLimit as max
index; remove e...</li>
<li><a
href="https://github.com/ljharb/qs/commit/1b9a8b4e78c6aff4c22fa559107227f02fd0216a"><code>1b9a8b4</code></a>
[actions] fix rebase workflow permissions</li>
<li><a
href="https://github.com/ljharb/qs/commit/2a35775614e0fb46ac8a3060201a32a7c23a7fda"><code>2a35775</code></a>
[meta] fix changelog typo (<code>arrayLength</code> →
<code>arrayLimit</code>)</li>
<li>Additional commits viewable in <a
href="https://github.com/ljharb/qs/compare/v6.14.1...v6.14.2">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=qs&package-manager=npm_and_yarn&previous-version=6.14.1&new-version=6.14.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/openfrontio/OpenFrontIO/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-16 11:32:16 -08:00
VariableVince 52012e321b Fix: npm run perf errors on Windows (#3192)
## Description:

Npm script 'perf' errors on Windows: "Error [ERR_MODULE_NOT_FOUND]:
Cannot find module '(XXX)\OpenFrontIO\tests\perf\*.ts'". It probably
worked fine on Linux or Mac, that i don't know. Replaced it with a file
that also runs all tests in the folder, which is then simply ran by the
script.

There are possibly better ways to address this but this just works.

## 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:

tryout33
2026-02-16 11:25:54 -08:00
VariableVince 5e2930075a Fix: console error stemming from WinModal (#3221)
## Description:

Fix console error triggered by this.game being undefined but WinModal
render() still tries to get this.game.myPlayer?.

There is no guard needed in tick() or show() (the latter only called by
tick). Because when this.game is undefined tick() won't be called
anyway.

![undefined in WinModal reading myPlayer in console at game
start](https://github.com/user-attachments/assets/0c399516-f6a1-418d-916b-2633413eb241)

![undefined in WinModal reading myPlayer in console at game start
B](https://github.com/user-attachments/assets/28986383-596a-4a64-bc26-b00f28828bb7)

## 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:

tryout33
2026-02-16 11:19:06 -08:00
FloPinguin 4e62114ea0 Improve nations 🤖 (#3206)
## Description:

- `AiAttackBehavior`: Because bots delete stolen structures now, nations
prioritize attacking bots with structures
- `NationMIRVBehavior`: Nations no longer MIRV enemies who already got
MIRVed in the last 30 seconds. Some humans complained about getting
double-MIRVed by nations. And in games with very high starting gold, ALL
nations MIRVed the same player (stop steamroll logic).
- `NationAllianceBehavior`: Fixes a comparison logic bug (Thanks to
Deshack)
- `NationNukeBehavior.ts`: Little atom bomb perceived cost balance
change
- `MIRVExecution`: To make sure the MIRVing nations are attacking the
MIRVed nations (even if they don't share a border), the relation gets
updated in both directions now.
- `SinglePlayerModal` & `HostLobbyModal`: Update the default difficulty
to "Medium" (to synchronize the defaults with the public game default)

## 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
2026-02-16 11:13:07 -08:00
Ryan 4bc168dffb make usernames linkable in news (#3200)
## Description:

make usernames linkable in news

now:
<img width="399" height="153" alt="image"
src="https://github.com/user-attachments/assets/39644fe2-9af1-4765-b839-9f8b5f9d0418"
/>


before:
<img width="409" height="82" alt="image"
src="https://github.com/user-attachments/assets/d7a1c37e-63cf-4417-ac61-c6db39a33851"
/>



## 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:

w.o.n

Co-authored-by: iamlewis <lewismmmm@gmail.com>
2026-02-16 11:11:10 -08:00
Mattia Migliorini f362e47413 Cancel nukes when accepting alliance via radial menu (#3155)
Resolves #3154

## Description:

#2716 introduced nuke cancellation logic on alliance acceptance via
`AllianceRequestReplyExecution`. The radial menu action, though, calls
`AllianceRequestExecution` instead, which accepts the alliance if a
request has already been made by the other player.

This PR moves the nuke cancellation logic to `GameImpl`, hooking into
the `acceptAllianceRequest` method, therefore accounting for every
alliance acceptance, regardless of the specific action that brought to
that.

## 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:

deshack_82603
2026-02-16 11:10:26 -08:00
FloPinguin d0bb3a016e "Catching up..." HeadsUpMessage 🏃‍♀️ (#3194)
## Description:

After an internet problem or page reload the game catches up, replaying
the ticks.

But especially new players might be confused what is happening. The game
runs fast???
And you can't easily tell when its finished catching up. You need to
spot when it stops running faster than usual.

So add a HeadsUpMessage to tell people what is happening.


https://github.com/user-attachments/assets/6fcdd85f-c58e-4549-89d0-5ba51df39339

## 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

---------

Co-authored-by: iamlewis <lewismmmm@gmail.com>
2026-02-16 11:08:11 -08:00
FloPinguin 086a7e9000 Improve mobile UI (#3217)
## Description:

### Leaderboard cut off

Previous:

<img width="285" height="255" alt="Screenshot 2026-02-15 171617"
src="https://github.com/user-attachments/assets/affb7559-3885-4cc3-bc1a-f653dcb13fb2"
/>

Now: 

<img width="302" height="299" alt="Screenshot 2026-02-15 171603"
src="https://github.com/user-attachments/assets/623fe424-d744-46f7-99aa-710b010c4084"
/>

### Attack ratio popup cut off

Previous:

<img width="276" height="806" alt="Screenshot 2026-02-15 171542"
src="https://github.com/user-attachments/assets/2ac0ec19-feea-465a-b04b-323a18309d4d"
/>

Now: 

<img width="278" height="807" alt="Screenshot 2026-02-15 171533"
src="https://github.com/user-attachments/assets/7e06aa96-04ba-4454-ba0e-cdaad74f79be"
/>

Also fixed this text overlap problem on boat retreat:

<img width="359" height="192" alt="Screenshot 2026-02-15 172603"
src="https://github.com/user-attachments/assets/e4cef05c-5dc3-4960-ab21-a2f0740e3380"
/>

## 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
2026-02-16 18:00:25 +00:00
Vivacious Box 040766d417 Add units filter on playeractions for performance (#3213)
## Description:

The ghost structure calls player actions each frame, which is costly
since it's checking for all possible actions.
This add a unit list filter in actions so if there are units it only
checks for buildability of those units.

Before:
![WhatsApp Image 2026-02-14 at 23 25
25](https://github.com/user-attachments/assets/beda6142-9dc7-4a9c-a702-cee3b6ea043c)
Player actions takes 20-30% of the worker

After:
<img width="825" height="342" alt="image"
src="https://github.com/user-attachments/assets/36e47547-5028-4dc9-bc42-e17df4a87200"
/>
Player actions takes 1-3% of the worker


Both performances are relevant only when a ghost structure is selected

## 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:

Mr. Box
2026-02-14 19:54:12 -08:00
FloPinguin 1e5db18885 Update 1v1 game configuration: Original format 🗡️ (#3209)
## Description:

This PR changes the ranked 1vs1 config to use the original format
(tournaments and openfront 1vs1 club):
https://discord.com/channels/1359946986937258015/1463178945108246757
(Reasoning in the discord thread)

But I still think we need a **1vs1 "party mode"**. With nations, ALL our
small maps, and sometimes compact maps. Maybe even sometimes with 5M
starting gold.
- Offering it to all 1vs1 players below a specific ELO count is probably
not the best idea: Some people will avoid getting too much ELO, others
will hate it until they have enough ELO.
- Offering another matchmaking queue might be an idea, but might cause
too much complexity (needs its own ELO system and its own leaderboard).
- A solution could be: Offer 1vs1 party games without ELO in the
upcoming new "special" rotation (Collect 20 players and put them into 10
games)

## 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
2026-02-14 19:49:45 -08:00
FloPinguin 0c7da790f1 Improve Ingame UI (#3212)
## Description:

- **Dynamic sidebar offset for top bars** - GameLeftSidebar,
GameRightSidebar, and PlayerInfoOverlay now shift down when SpawnTimer
and/or ImmunityTimer bars are visible (7px per bar). Implemented via
events.
- **Fixed text overflow** in HeadsUpMessage.ts (Random spawn message is
long)
- **Fixed inconsistent text sizing** in EventsDisplay 
- **Alliance icon horizontal** in PlayerInfoOverlay so the size of the
overlay doesn't change if there is an alliance
- **Nation relation coloring** - Nation player names are now colored
based on their relation
- **Background & Blur Unification**
- **Border Radius & Page Edge Gap Standardization**
- **EventsDisplay collapsed button:** Fixed badge hidden / inline-block
CSS conflict (conditional rendering), added gap-2 between text and badge
- **Right panel spacing:** Changed right container from sm:w-1/2 to
sm:flex-1 to fill remaining space
- **Leaderboard**: Rounded grid corners (rounded-lg overflow-hidden),
removed last-row border, added `willUpdate` for auto-refresh on
hide/show click, plus button styled to match toggle buttons
- Other little CSS fixes (margins etc)

Showcase:
(Note the red mexico name on betrayal)


https://github.com/user-attachments/assets/f0ed91de-3a07-4564-a209-3d7723edee55

Two progress bars at the top, mobile UI not cut off:


https://github.com/user-attachments/assets/83f1fd64-ceab-4a74-8d16-6e1eeea1709d

HeadsUpMessage text overflow fixed, SpawnTimer does not cut off the
PlayerInfoOverlay:

<img width="516" height="929" alt="Screenshot 2026-02-14 214410"
src="https://github.com/user-attachments/assets/74f0edea-8c01-4394-a3d0-a3245922e0da"
/>

Previous:

<img width="306" height="118" alt="Screenshot 2026-02-14 213705"
src="https://github.com/user-attachments/assets/a7c7e8f3-f0e8-4213-8a8f-4f3677e9fc98"
/>

Smaller event panel text:

<img width="594" height="975" alt="Screenshot 2026-02-14 215738"
src="https://github.com/user-attachments/assets/33e80570-9260-40b0-b810-c71eda4861fc"
/>

## 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
2026-02-14 19:48:43 -08:00
evanpelle 8e889fe857 Merge branch 'v29' 2026-02-14 12:14:19 -08:00
Evan 2e2e686699 have lobby schedule ffa, teams, & special game types (#3196)
## Description:

This implements the backend for multiple lobbies in preparation for
https://github.com/openfrontio/OpenFrontIO/pull/3191

The server now schedules & sends a map of game type (ffa, teams,
special) => public lobbies.

NOTE: this is just temporary, the lobby only shows ffa currently.

Have the Master scheduler schedule ffa, teams, & special games. 

## 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:

evan
2026-02-14 11:59:35 -08:00
gabigabogabu 6e557c52db Add Hawaii map (#3187)
## Description:
Add Hawaii as a new regional map. Features 9 nations across the Hawaiian
island chain (Niihau, Kauai, Oahu, Molokai, Lanai, Kahoolawe, Maui,
Kona, Hilo). ~~612K land tiles at 3920x2544~~ 408K land tiles at
3200x2076, terrain generated from real relief data with accurate
volcanic peaks and coastal lowlands. Playlist frequency: 4.

![Hawaii
thumbnail](https://raw.githubusercontent.com/gabigabogabu/OpenFrontIO/feature/hawaii-map/resources/maps/hawaii/thumbnail.webp)

## Checklist
- [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

Source:
https://commons.wikimedia.org/wiki/File:USA_Hawaii_relief_location_map.svg
Discord: gabigabogabu
2026-02-14 17:28:42 +00:00
Mattia Migliorini b74e5c84e0 Fix height of ToggleInputCard in Lobby Options (#3201)
## Description:

Fixes height of ToggleInputCard elements in order to force consistency,
i.e. same height of elements in the same row.

### Before:

<img width="762" height="581" alt="Screenshot 2026-02-13 at 17 34 57"
src="https://github.com/user-attachments/assets/23a31fbc-880e-428c-a03d-0b49e4de00dc"
/>


### After - Single Player:

<img width="756" height="792" alt="image"
src="https://github.com/user-attachments/assets/62eaaa34-97f7-40ff-9291-c31a820b826a"
/>


### After - Private Lobby:

<img width="758" height="792" alt="image"
src="https://github.com/user-attachments/assets/37b4d996-5d81-4f76-b95f-3e64707f180e"
/>


### Behavior when toggling the highest element on the row:


https://github.com/user-attachments/assets/6ff26902-2f3c-474f-8bde-0eddcacf9570


## 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:

deshack_82603
2026-02-13 20:02:25 -08:00
evanpelle a2a8035b1d require login before trialing a skin v0.29.16 2026-02-13 19:46:46 -08:00
evanpelle 712ce96794 Fix JWT refresh race condition causing unexpected logouts 2026-02-13 17:07:54 -08:00
SwayLE3 fc65571264 add the flag of Occitania (#3179)
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves #(issue number)

## Description:

Add a flag : Occitania flag
<img width="1090" height="664" alt="image"
src="https://github.com/user-attachments/assets/6ad5eb7c-a8f1-4c61-995c-e4f0c6d71204"
/>

added the Occitania flag via the svg (same as the flags already in-game)
and added it to countries.json

## 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:

young_la_flame

---------

Co-authored-by: Jules <swayle3@Jules.local>
2026-02-13 08:47:42 -08:00