Commit Graph

3027 Commits

Author SHA1 Message Date
Arkadiusz Sygulski 6bd95d4884 Pathfinding - optimize naval invasions (#2932)
# Pathfinding pt. 4

https://pf-pt-4.openfront.dev/

## Description:

Hello again! Pathfinding. It's fast, but inaccurate. This PR makes it
more accurate and actually faster. Sadly it is _faster_ because of a
blunder in previous PR (using BucketQueue where MinHeap would be
better), not because of a new tech. More importantly, it is more
accurate. And that's what people apparently want.

## What changed?

Most of the functional changes relate to `SpatialQuery` module. This is
the thingy that answers "we know the target, which tile of my territory
is the best to launch an invasion". To make it compute a path from South
America to the deep inland China river, it has to work on a coerced map,
one with a very small resolution, so small in fact, that every 4096 map
tiles gets compressed to just one pixel. I hope you see where this is
going.

Previously we selected a random coastal tile within this big pixel
(honestly it wasn't random at all, but could very well be for the
illustrative purposes). Now, we try to be a bit more deliberate. Since
we already know the rough location of the probably best tile, we can
exclude all other tiles from the computation. Imagine a player's
territory spans both Americas on global map - that's a lot of shores.
But since we already know the best tile is somewhere close to Miami, the
problem space was greatly reduced, no need to consider all other shores.
But pathing to the target in China from Miami is still crazy expensive.

This is where second trick comes to play - instead of pathing all the
way to China, we select a _waypoint_ in the rough direction of China,
about 100 to 200 tiles away. This way we fairly cheaply select best tile
to launch an invasion towards this abstract point. And chances are, this
point is far enough, the newly computed path is very close to being
optimal. When you throw a dart from far away, the difference between
scoring 10 and missing is very small. This is why aiming in the general
direction of the board - as opposed to the ceiling - is usually good
enough.

## Okay, but what about the crazy paths when I send invasion to the
opposed bank of a river?!

Well, pathing from America to China is cool, but most players wouldn't
notice the difference on such long paths, what about the short ones? We
now try more accurate pathing first and defer to hierarchy only if it
fails. This produces much better paths for short invasions. While the
fix described above ensures the accuracy is improved also on
medium-to-long routes.

## Playground

Yes.


https://github.com/user-attachments/assets/9cf9586f-c99a-416d-b856-8cf0a21c35ed

## CodeRabbit

Grab a 🥕. Remember `tests/pathfinding/playground` is mostly generated
code and go easy on it. It's enough for it to work and do it's job of
visualizing the paths. No need for throughout review of these files.

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

moleole
2026-01-16 23:10:55 +00:00
evanpelle 3cdbb5651a Merge branch 'v29' 2026-01-16 10:20:47 -08:00
FloPinguin 4e8454f3cc Lobby Gold Options (Starting Gold, Gold Multiplier) 💰 (#2915)
## Description:

We might want to add this to v29 to have a third possible public game
modifier from the beginning on 😄 Would be fun

- Add starting gold option (0 to 1_000_000_000 allowed, also applies to
nations)
- Add gold multiplier option (0.1 to 1000 allowed, also applies to
nations and bots)
- Add third public game modifier (3% chance of starting with 5M gold)
- Why 5M? It's enough gold to massively change the game start but not
enough to insta-hydro someone (launcher + hydro is 6M)

<img width="357" height="140" alt="image"
src="https://github.com/user-attachments/assets/72acc15c-e788-4e04-8590-ac72dd9657c7"
/>


## 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-01-16 10:20:35 -08:00
Ryan d0fda1d535 mergestats (#2904)
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves #2704
## Description:

Merges together easy + medium difficulties.

Before:
<img width="1500" height="580" alt="image"
src="https://github.com/user-attachments/assets/26199d52-8ef2-4feb-ae87-bbfff35e3115"
/>

After:
(dont have one to show oop)

(btw that win ratio in the first screenshot is not mine.. 💀) 

## 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-01-16 10:20:28 -08:00
FloPinguin fb910cbff5 Lobby Gold Options (Starting Gold, Gold Multiplier) 💰 (#2915)
## Description:

We might want to add this to v29 to have a third possible public game
modifier from the beginning on 😄 Would be fun

- Add starting gold option (0 to 1_000_000_000 allowed, also applies to
nations)
- Add gold multiplier option (0.1 to 1000 allowed, also applies to
nations and bots)
- Add third public game modifier (3% chance of starting with 5M gold)
- Why 5M? It's enough gold to massively change the game start but not
enough to insta-hydro someone (launcher + hydro is 6M)

<img width="357" height="140" alt="image"
src="https://github.com/user-attachments/assets/72acc15c-e788-4e04-8590-ac72dd9657c7"
/>


## 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-01-16 10:19:41 -08:00
DevelopingTom d758e21351 Restyle game rank modal (#2918)
## Description:
The game rank modal was still using the old style, which clashes
strongly with the new one.

This PR changes changes the modal style to be consistent with the new
one:

### Old

<img width="894" height="451" alt="image"
src="https://github.com/user-attachments/assets/c83177cf-a1ed-4ee5-9e12-7d2a9d8004cf"
/>

### New


![redesign](https://github.com/user-attachments/assets/ecf4f0ae-88f0-433c-90be-f41447e17afe)

Tagged as `v29` to have a consistent style in the same version.

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

IngloriousTom
2026-01-16 10:14:38 -08:00
Achim Marius b2ba37e0ab Destroy incoming nukes when alliance is created (#2716)
Resolves #2484

## Description:

- When an alliance is created between two players, any incoming nukes
between them are destroyed mid-air.
This prevents the traitor debuff from being applied on impact, even if
the nukes were launched before the alliance was formed.
- If a player has launched nukes at multiple nations, only the nukes
targeting the newly allied nation are destroyed.

This is what the players will see after the alliance is created (in case
they have launched nukes at each other):
<img width="423" height="125" alt="Screenshot 2026-01-04 092907"
src="https://github.com/user-attachments/assets/6544fb7a-7623-4fc3-b799-89ef8fe897d6"
/>


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

assessin.
2026-01-15 20:09:01 -08:00
evanpelle e1d4b9a00e allow name to be placed on shore tiles, this prevents rivers from bisecting player names causing them to be too small 2026-01-15 16:16:33 -08:00
evanpelle dbb5eb5993 use GIT_COMMIT instead of version for manifest.json cache busting to prevent users from pulling stale manifest if the version is not updated 2026-01-15 16:05:00 -08:00
Aaron Tidwell 9cd87f8906 Map generator -verbose and -performance flags (#2721)
Resolves #2718

## Description:

Adds go-style error log levels, with an additional ALL log level.

- WARN/ERROR - Only success output
- INFO - Existing output
- DEBUG - New output
- ALL - New output (includes the logs from when removal/performance is
enabled)

In addition

- Add `-verbose` (`-v`), `-log-level`, `-log-removal`, and
`-log-performance` flags to map generator
- No changes to default behavior of `go run .` without the new flags
- excludes test maps from performance warnings (test maps already skip
the removal steps)
- updates readme with the different flags and how they impact the logger

Default run (matches existing)
`go run . >> output.txt 2>&1`

[output.txt](https://github.com/user-attachments/files/24365745/output.txt)

Default run w/ `-verbose` (log level DEBUG)
`go run . -v >> output.txt 2>&1`

[output.txt](https://github.com/user-attachments/files/24365812/output.txt)

Default run w/ `-log-performance`
`go run . -log-performance >> output.txt 2>&1`

[output.txt](https://github.com/user-attachments/files/24365971/output.txt)

Run of just africa w/ all new logging enabled
`go run . -maps=africa -log-level=all >> output.txt 2>&1`

[output.txt](https://github.com/user-attachments/files/24365724/output.txt)


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

tidwell

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
v0.29.0-beta3
2026-01-15 22:40:45 +00:00
Ryan 01e682b576 Revert "Amended renderNumber to display numbers in the billions range" (#2913)
Reverts openfrontio/OpenFrontIO#2911

## Description:

Reverts confusing "billion"

## 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-01-15 21:15:38 +00:00
Ryan cfa40f2e5e mergestats (#2904)
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves #2704
## Description:

Merges together easy + medium difficulties.

Before:
<img width="1500" height="580" alt="image"
src="https://github.com/user-attachments/assets/26199d52-8ef2-4feb-ae87-bbfff35e3115"
/>

After:
(dont have one to show oop)

(btw that win ratio in the first screenshot is not mine.. 💀) 

## 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-01-15 12:57:46 -08:00
DevelopingTom 0466eeac13 Add train gold to game info ranking (#2901)
## Description:

The game info panel was missing the gold generated with trains, which
was recently added into the recorded stats.
This PR adds the gold train ranking, grouped with the naval trade.

Visually the game info panel is not matching the new visual identity,
but this PR only focuses on the missing data.

<img width="898" height="482" alt="image"
src="https://github.com/user-attachments/assets/6366e5d2-23b6-40b0-b4d4-1227b5a2f811"
/>


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

IngloriousTom
2026-01-15 12:24:35 -08:00
Alexander Hoare 920e029967 Amended renderNumber to display numbers in the billions range (#2911)
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves [#2910](https://github.com/openfrontio/OpenFrontIO/issues/2910)

## Description:

When any number is rendered using the Utils.ts renderNumber() function
that is greater than 999,999,999, the display uses 1001M instead of 1B.

Similar to existing logic, I expand the if statements to check if the
number is greater than a threshold in the billions, and format it
accordingly if so.

Screenshots:
<img width="1268" height="370" alt="image"
src="https://github.com/user-attachments/assets/e4edf28b-94bd-4ec6-a4e6-083b9a2fd4fb"
/>
<img width="271" height="238" alt="img1"
src="https://github.com/user-attachments/assets/bc259f4d-68e8-4b6a-831b-34f02cf56750"
/>


## Please complete the following:

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

visneh
2026-01-15 12:22:50 -08:00
Aotumuri 40a9e54ee7 mls (v4.13) (#2907)
## Description:

mls for v29 
Version identifier within MLS: 4.13

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

aotumuri
2026-01-15 11:22:07 -08:00
Aotumuri 779ba2c518 mls (v4.13) (#2907)
## Description:

mls for v29 
Version identifier within MLS: 4.13

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

aotumuri
2026-01-15 11:21:49 -08:00
Ryan 6719f4177b [Bugfix] Login Modal (#2903)
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves #2889

## Description:

fixes login in modal:
<img width="782" height="330" alt="image"
src="https://github.com/user-attachments/assets/60f1825f-5678-4853-a78b-bbed5198b0fb"
/>
(theres also one more afterwards but that leaks my email and cba to edit
it out)

## 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-01-14 16:56:50 -08:00
Himansu Rawal e1d31ef1ee fix: replace setInterval with recursive setTimeout in Master.ts to pr… (#2869)
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves #2868 

## Description:

This PR addresses a critical memory leak in the Master server process
(causing ~30GB RAM usage).

The issue was caused by `setInterval` calling `fetchLobbies()` every
100ms. When `fetchLobbies` took longer than 100ms to complete (due to
network latency or load), requests would pile up indefinitely, creating
a massive queue of pending Promises and open sockets.

I have refactored the polling logic into a generic `startPolling`
utility (in `src/server/PollingLoop.ts`) that uses a recursive
`setTimeout` pattern. This ensures that the next `fetchLobbies` call is
only scheduled *after* the previous one has completed (successfully or
failed), preventing any request pile-up.

## Please complete the following:

- [x] I have added screenshots for all UI updates (N/A - backend only)
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file (N/A - no user facing text)
- [x] I have added relevant tests to the test directory
(`tests/PollingLoop.test.ts`)
- [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:

codimo
2026-01-14 09:50:43 -08:00
FloPinguin 0421c4e958 Refreshed images for the help modal and other little optimizations (#2897)
## Description:

1. Changed default difficulty in singleplayer / host lobby to Easy (to
synchronize the settings with the public lobby settings)
2. Switch bot count in singleplayer / host lobby to 100 after selecting
"compact map" (to synchronize the settings with the public lobby
settings) (and back to 400 after deselcting)
3. Some little padding optimizations, for example for the modal title:

<img width="961" height="190" alt="Screenshot 2026-01-14 163837"
src="https://github.com/user-attachments/assets/1ecca3e9-8daf-4bed-a75a-c8e840051601"
/>

4. Refreshed images for the help page:


![infoMenu2](https://github.com/user-attachments/assets/dc0c49c1-b970-47e5-a188-56fefc2e1c90)

![infoMenu2Ally](https://github.com/user-attachments/assets/c6c49a2c-eec6-44ae-877e-b8bdd2ab8caf)

![playerInfoOverlay](https://github.com/user-attachments/assets/1c6c2fc0-ecc5-4946-a7a7-35b90c13790a)

![controlPanel](https://github.com/user-attachments/assets/3d10fbf7-fbff-46af-b02a-9bb390dd9955)

![eventsPanelAttack](https://github.com/user-attachments/assets/04af2c91-6be1-458f-bf13-f4ddaf247d8a)

![eventsPanel](https://github.com/user-attachments/assets/517ad982-b001-4a36-9dfd-84a7ca1e0162)

![leaderboard2](https://github.com/user-attachments/assets/8956d053-682f-4055-9fe9-a36b066b1ce3)


## 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-01-14 09:47:44 -08:00
DevelopingTom c8c97abe75 Fix transportship target tile on construction (#2896)
## Description:

The recent pathfinding rework broke the naval invasion target.
This change reverts the code to the previous working one.

<img width="232" height="273" alt="image"
src="https://github.com/user-attachments/assets/0cc3ed80-bd77-4e7b-886b-0ce5012840ac"
/>


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

IngloriousTom
2026-01-14 09:46:08 -08:00
FloPinguin a28a7ef6fd Fix: Bots NEVER attacked someone if they had water access (#2894)
## Description:

Bots always attacked Terra Nullius if they shared a border with Terra
Nullius.
But water is Terra Nullius...
So I changed that condition to `this.bot.neighbors().some((n) =>
!n.isPlayer())`.

## 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-01-14 09:44:18 -08:00
opressorMk2 c40faecb95 Move indicator fx for warships. (#2871)
Been playing this game for months, and after i feel myself enough
experienced about the game, decided to start contributing to the
project. This is my first one!

## Description:

Move indicator fx for warships. Listening MoveWarshipIntentEvent to draw
the fx. Code is basic, respectly layered and written regarding project's
structure.


![warship](https://github.com/user-attachments/assets/7e286e2b-2331-40a3-b62b-ad03dceef676)

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

420coder

---------

Co-authored-by: Ryan <7389646+ryanbarlow97@users.noreply.github.com>
2026-01-14 12:15:40 +00:00
evanpelle 24774b4804 Increase poll rate for matchmaking games from every 3s to 1s because people are not joining games in time v0.29.0-beta2 2026-01-13 20:14:23 -08:00
Evan 42c944c9cc Create ranked type enum, last person not afk wins in 1v1 (#2892)
## Description:

* Add RankedType enum, for now it's just 1v1
* Add new method to MapPlaylist to create 1v1 game config
* Update WinCheck so the last player is declared a winner on 1v1.

## 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-01-13 19:48:14 -08:00
Ryan 247c78151c Discord(et al.) embedded URLs (#2740)
## Description:

Changes URL embeds within other platforms, e.g. Discord, WhatsApp & X.

Updates game URLs to `/game/<code>` instead of `/#join=<code>` (required
for embedded URLs). An added benefit of this is that you would be able
to change a url from `openfront.io/game/RQDUy8nP?replay` to
`api.openfront.io/game/RQDUy8nP?replay` (add api. In front) and be in
the right place for the API data.

Updates URLs when joining/leaving private lobbies

Appends a random string to the end of the URL when inside a private
lobby and options change - this is to force discord to update the
embedded details.

Updates URL in different game states to ?lobby / ?live and ?replay.
These do nothing other than being used as a _cache-busting_ solution.


-----------------------------------------------
### **Lobby Info**

Discord:
<img width="556" height="487" alt="image"
src="https://github.com/user-attachments/assets/efd4a06d-506c-4036-9403-ee7c9a669e21"
/>

WhatsApp:
<img width="353" height="339" alt="image"
src="https://github.com/user-attachments/assets/3b2d0c69-988c-424f-9dee-f4e6a6868f6b"
/>


x.com:
<img width="588" height="325" alt="image"
src="https://github.com/user-attachments/assets/d9e78169-20be-4a3e-8df4-8ad41d08a750"
/>


-------------------------
### **Game Win Details**
Discord:
<img width="506" height="468" alt="image"
src="https://github.com/user-attachments/assets/69947774-c943-4a50-b470-5634ed3bf3d7"
/>

WhatsApp:
<img width="770" height="132" alt="image"
src="https://github.com/user-attachments/assets/eec28bf8-bf64-4ab8-954e-03dfdd1aae40"
/>

x.com
<img width="584" height="350" alt="image"
src="https://github.com/user-attachments/assets/168063e2-b707-422b-b7a1-0025f3ebeb92"
/>


## 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-01-13 19:48:00 -08:00
DevelopingTom c80ccaece9 Record train trading stats (#2891)
## Description:

The current gold stats don’t include gold generated by trains, even
though this is a significant part of the economy for many players.

This PR tracks those stats with two values:
- other players trains visits the player station
- the player trains visits any station

Linked to this infra PR: https://github.com/openfrontio/infra/pull/242

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

IngloriousTom
2026-01-14 01:00:55 +00:00
Ryan 3fff628642 Skins padding fix (#2893)
## Description:

Fixes some visual issues in the skins modal **tailwind only changes +
small movement of logic check**

(padding issue)
<img width="830" height="155" alt="image"
src="https://github.com/user-attachments/assets/6581f887-ee23-4751-a9a3-82416aa1a381"
/>

(huge gap at bottom because it was trying to put a button there but then
stopping due to requirespurchase=false)
<img width="218" height="302" alt="image"
src="https://github.com/user-attachments/assets/0837b256-1137-4ae4-9940-8a4375143f54"
/>



Now:
<img width="303" height="297" alt="image"
src="https://github.com/user-attachments/assets/4ba1556a-444a-4e3e-9d1a-73355dd34dbb"
/>

<img width="844" height="213" alt="image"
src="https://github.com/user-attachments/assets/cce2472c-9ac4-4caf-8052-1d597610b1c9"
/>



## 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-01-14 00:51:50 +00:00
Evan a77c6c3d9d Inject server env vars into index.html, including instance id (#2888)
## Description:

Should fix the broken 1v1 on staging. The issue was that we had multiple
staging environments, and the matchmaker would often route a player to a
game on a different staging server, so the client couldn't find the
game.

So now each deployment has a unique id, and the matchmaker only connects
players & servers that have the same instance id.

## 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-01-13 13:03:58 -08:00
Arkadiusz Sygulski 85def73bd9 Pathfinding Refinement (#2878)
# Pathfinding pt. 3

## Description:

This PR introduces final change to the pathfinding - path refinement. It
optimizes Line of Sight refinement by searching with for the best tile
with a binary search instead of linearly. And then spends the recovered
budget on better refinement of the first and last 50 tiles of the
journey - the place where user is most likely to look at. Additionally
this PR re-introduces magnitude check and makes the ships prefer sailing
close to the coast, but not too close.

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

## What?

| Before | After |
| :--- | :--- |
| <img width="1097" height="1117" alt="image"
src="https://github.com/user-attachments/assets/4a0b300d-10ef-4151-b6dc-33acfb49f992"
/> | <img width="1093" height="1119" alt="image"
src="https://github.com/user-attachments/assets/cf81c515-c145-40f4-91e5-a4353986907b"
/> |
| <img width="1096" height="1129" alt="image"
src="https://github.com/user-attachments/assets/21b46bce-f961-4259-88f6-fe4a66180270"
/> | <img width="1098" height="1126" alt="image"
src="https://github.com/user-attachments/assets/d92587d1-e6b6-4353-b4a4-1efe71bca43d"
/> |

## Performance

There is actually a severe performance impact of these changes. The path
initial path takes almost 2x as long to generate - this is because pre
processing can only do so much if the initial path is ugly. Luckily in
real gameplay we only need to do this calculation once per edge, so the
actual observed performance impact should be much smaller. Cache FTW.

| | No Cache | Cache |
| :--- | :--- | :--- |
| Before | 277.04ms | 208.58ms |
| After | 498.34ms | 264.27ms |

## DebugSpan

Small utility, it allows any code to be easily instrumented for
performance. The idea is the same as with [OTEL
Spans](https://opentelemetry.io/docs/concepts/signals/traces/). Produce
a span, create sub-spans, measure whatever you need. Works only when
`globalThis.__DEBUG_SPAN_ENABLED__ === true`, otherwise no-op.

Cool stuff, try it out:
```ts
// Convenient wrapper, small performance impact
return DebugSpan.wrap('add', () => a + b)

// Synchronous API, basically free
DebugSpan.start('work')
work()
DebugSpan.end()

// Create sub spans
DebugSpan.wrap('complex', () => {
  const aPlusB = DebugSpan.wrap('add', () => a + b)
  DebugSpan.set('additionResult', () => aPlusB)  // Store data
  return aPlusB * c
})

// Access spans, data and timing
const span = DebugSpan.getLast()
const compelxSpan = DebugSpan.getLast('complex')

console.log(complexSpan.duration, complexSpan.data['additionResult'])
```

These are virtually free and can be enabled on-demand **in production**
and available in the devtools. Under the hood devtools integration is
just a wrapper around [Performance
API](https://developer.mozilla.org/en-US/docs/Web/API/Performance_API).
For clarity data keys not prefixed by `$` are omitted from the
integration. Every key prefixed with `$` must be fully JSON
serializable.

<img width="977" height="799" alt="image"
src="https://github.com/user-attachments/assets/b4d43506-1639-4f78-a611-30e61de12a07"
/>
2026-01-13 12:39:54 -08:00
FloPinguin 35b7213c5c Enhance nuke alliance breaking logic to account for allied structures in blast radius 💣 (#2887)
## Description:

Doesn't need a description :D


https://github.com/user-attachments/assets/8de576fd-050b-4b35-8526-e4c88d1a9f25


https://github.com/user-attachments/assets/c99147a1-efdf-426b-96d1-e996e01f89aa

## 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-01-13 12:30:25 -08:00
Wraith 0e3b9cca29 fix(ui): add missing dark variant to styles.css (#2839)
## Description:

fix(ui): add missing dark variant to styles.css

Before:
<img width="549" height="77" alt="image"
src="https://github.com/user-attachments/assets/d7c2bf92-691b-473c-880a-da678eb792a3"
/>

After:
<img width="555" height="84" alt="image"
src="https://github.com/user-attachments/assets/a2c828db-7fea-409a-abdd-fefc0dc237f0"
/>


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

wraith4081

---------

Co-authored-by: Ryan <7389646+ryanbarlow97@users.noreply.github.com>
2026-01-13 20:28:12 +00:00
Aotumuri ed3c7b1a22 make existing keybinds configurable (#2881)
## Description:

This PR makes several existing keybinds configurable that were
previously fixed and could not be changed in the keybind settings.

This is one of the required PRs to fully remove all keybind explanations
from the HelpModal.

This work is based on the following feedback by @ryanbarlow97:
> "This probably needs to be redone / removed from help, and just have a
section saying how to get to the keybinds modal inside settings"
>
https://github.com/openfrontio/OpenFrontIO/pull/2872#issuecomment-3740006017

Some keybinds described in the HelpModal already existed internally, but
users had no way to change them.
By making these keybinds configurable, we can now safely replace those
explanations with a simple reference to the keybind settings instead.

This helps:
- Remove keybind explanations from the HelpModal

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

aotumuri

Co-authored-by: Ryan <7389646+ryanbarlow97@users.noreply.github.com>
2026-01-13 10:35:38 +00:00
Himansu Rawal a40f5b7b8d Add CONTRIBUTING.md file to guide new contributors (#2883)
Co-authored-by: Ryan <7389646+ryanbarlow97@users.noreply.github.com>
2026-01-13 10:13:00 +00:00
bijx 49819728d8 Fix: Lemnos map regenerated with map-generator to update with latest changes (#2884)
## Description:

There was a mismatch between the Lemnos map settings in the `info.json`
and the what was in the resources folder. I regenerated the map using
the map-generator to make sure the latest changes were applied.

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

bijx
2026-01-13 09:50:50 +00:00
FloPinguin 464a4a817a Remove hardcoded numPlayersConfig, calculate it based on the maps land tiles 🔧 (#2874)
## Description:

The calculation is based on: 50 players per 1_000_000 land tiles,
limited at 125 players because of performance
Second number is 75% of that, third one 50%
That way, the player counts are staying mostly the same
Look at the "Dynamic Config" column, these are the new player counts:
(The 125 players limit is missing in that column, only relevant for the
twolakes map)

<img width="930" height="1033" alt="Screenshot_2026-01-12_152758"
src="https://github.com/user-attachments/assets/e1791740-e263-47b3-8b27-4f9aa358d381"
/>
<img width="926" height="324" alt="Screenshot_2026-01-12_152814"
src="https://github.com/user-attachments/assets/78d6789b-374f-4f8b-b50f-f6f08395572b"
/>

This PR also removes `MapDescription` from `Maps.ts` because its unused.
And this PR updates the map-generator `README.md` to reflect the changes

## 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-01-12 21:18:47 -08:00
Ryan 7353d785fb Created ModalHeader and moved/unified all modal headers (#2882)
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves #(issue number)

## Description:

Moved the Modal Headers into its own class

## 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-01-12 21:03:02 -08:00
evanpelle e246289876 Revert "New Year's Eve FX (#2745)"
This reverts commit ec694593a6.
v0.29.0-beta1
2026-01-12 20:56:17 -08:00
FloPinguin 2e57de5cfb Change "This game ended with no winner" to "This game ended with no winner (or a Nation won)" 🙂 (#2880)
## Description:

<img width="982" height="1086" alt="image"
src="https://github.com/user-attachments/assets/fb97f2e2-0e1a-4e21-baad-3e8cbd81624b"
/>

## 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-01-13 02:54:00 +00:00
Ryan 838d99f791 Remove borders from some elements (#2879)
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves #(issue number)

## Description:

Remove borders from some elements

**Tailwind changes only**

## 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-01-13 01:18:42 +00:00
Ryan be83aaa7e1 Remove "colours" from the shop modal (#2877)
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves #(issue number)

## Description:
remove the colours from the shop modal, also small tweak to header bar
in instructions

**Only Tailwind Changes**

<img width="843" height="209" alt="image"
src="https://github.com/user-attachments/assets/1f99aa8d-8756-4b70-9ff0-6495d5eb48bf"
/>

<img width="841" height="183" alt="image"
src="https://github.com/user-attachments/assets/ac40ed0d-7588-4336-b3d1-ce4be5f8a312"
/>



## 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-01-13 00:26:56 +00:00
Ryan 568b23df20 changed to reddit (#2876)
## Description:

fix url

## 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-01-12 23:43:57 +00:00
evanpelle a7714cd798 add canvas dev dependency to fix failing UI test 2026-01-12 09:03:34 -08:00
Arkadiusz Sygulski 0e3ced3bfa Pathfinding Refactor pt. 2 (#2866)
## Playtest

https://pf-pt-2.openfront.dev/

## Pathfinding Refactor pt. 2

<img width="1536" height="1024" alt="image"
src="https://github.com/user-attachments/assets/9477958e-54b7-4c83-b317-ba789e809e9e"
/>


This is a follow-up to a previous PR introducing pathfinding changes.
This time, it introduces a complete refactor of `pathfinding` directory
and breakdown into composable pieces.

### Unified PathFinder interface

`PathFinder<T>` and `SteppingPathFinder<T>` are introduced to unify
**all** pathfinding across the application. First one exposes complete
path, while stepping variant allows the callee to iterate over the path
by calling `.next`. All pathfinders share this one common interface,
which makes them easy to use in any scenario -
`PathFinding.Water(game).search(from, to)`.

`SteppingPathFinder<T>` extends `PathFinder<T>` with an ability to
iterate over the path. It handles caching, storing current index and
invalidation. This allows the units to not care about the inner workings
of the pathfinder and just call `pf.next(current, target)` and receive
instructions on what to do next.

### Common entry point

All pathfinders are now exposed from common `PathFinding` entrypoint:

- `PathFinding.Water`
- `PathFinding.Rail`
- `PathFinding.Stations`
- `PathFinding.Rail`

Additional entry point is introduced for pathfinders which need to work
both in the worker, but also on the frontend, which lacks `Game`
interface. Currently only `UniversalPathFinding.Parabola` is available.

### Spatial Query

New module has been introduced close to `pathfinding` - `SpatialQuery`.
It aims to resolve any questions game may have about finding tiles
meeting criteria. Currently `SpatialQuery.closestShore(player, target)`
and `SpatialQuery.closestShoreByWater(player, target)` are available -
they help answering questions about naval invasion: "What is the best
landing location from user's click?" and "Which our tile should be used
to launch the transport ship?". Under the hood they use very similar
mechanics to pathfinding, so it felt right to put them close by.

### Modular architecture

Pathfinders now support transformers: `MiniMapTransformer`,
`ShoreCoercingTransformer`, `ComponentCheckTransformer`,
`SmoothingTransformer`. Transformers functions like a middleware in the
pathfinding chain. They wrap around the pathfinder and provide
additional functionality. This allows the pathfinder to focus on
actually finding the path instead of doing unrelated things.

Example chain for simple (A*) water pathfinding:
```ts
static WaterSimple(game: Game): SteppingPathFinder<TileRef> {
  const miniMap = game.miniMap();
  const pf = new AStarWater(miniMap);

  return PathFinderBuilder.create(pf)
    .wrap((pf) => new ShoreCoercingTransformer(pf, miniMap))
    .wrap((pf) => new MiniMapTransformer(pf, game.map(), miniMap))
    .buildWithStepper(tileStepperConfig(game));
}
```

The Pathfinder - here `AStarWater` - does not care about the conversion
between minimap and main map tiles. It also does not care if the source
or destination is a land tile. The transformers take care of that. The
pathfinder gets a set of valid coordinates and produces the path -
that's it.

Modular approach makes working on a particular set of utilities much
easier - for example map upscaling is handled consistently across all
pathfinders. Additionally, the pathfinders are not tied to the
particular map resolution used. Pass them a different map and they will
work the same.

### Algorithms

Algorithms used are neatly organized inside
`src/core/pathfinding/algorithms`. They are prefixed with the algorithm
name and suffixed with the use case. File without suffix exposes generic
version ready to traverse any graph with adapters. Specialized versions
either use an adapter or inline logic when performance is critical -
using adapters leads to 20-30% performance loss.

The directory includes `A*` and `BFS` but also other useful utils, such
as `AbstractGraph` used to generate... an abstract graph on top of the
tile map and `ConnectedComponents` helping to identify whether two tiles
are connected by a path without actually computing the path.

### Playground

The playground have been updated with new algorithms, including tweaked
very greedy `A*`.

<img width="2175" height="1424" alt="image"
src="https://github.com/user-attachments/assets/1f833651-0024-4299-bf86-882f5368358c"
/>

### Tests

Yeah, there are some, a little too many if I say so myself. But there
are no useless tests. I had to ensure refactored code works somehow
reliably. This PR comes with trust me bro guarantee, but I would
appreciate someone confirming **naval invasions, nukes (esp. MIRV) and
warships**.

### Discord
`moleole`

GL & HF
2026-01-11 20:11:14 -08:00
Aotumuri bcec4ad758 Fix TargetIcon color to match other icons in HelpModal (#2865)
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves
https://discord.com/channels/1330359017247346812/1330365278420471911/1358027146139795486

## Description:

In HelpModal, only the TargetIcon was displayed in red, which was
inconsistent with the other icons.
This PR updates its color to white so it matches the rest of the icons.

before 

<img width="397" height="458" alt="スクリーンショット 2026-01-11 22 24 54"
src="https://github.com/user-attachments/assets/2a2f5aa0-a31c-4ecb-887e-f151689c3236"
/>

after

<img width="370" height="438" alt="スクリーンショット 2026-01-11 22 25 08"
src="https://github.com/user-attachments/assets/d0c74805-8bc8-4e94-8a18-23488aba0389"
/>


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

Co-authored-by: FloPinguin <25036848+FloPinguin@users.noreply.github.com>
2026-01-11 22:58:09 +00:00
Ryan 3e661752af UI refinements (#2859)
## Description:

UI Refinements requested by @evanpelle  check https://ui.openfront.dev

## 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-01-11 14:52:03 -08:00
Aotumuri 14512e4f87 Make left play icon start replay in Recent Games (#2853)
Resolves
https://discord.com/channels/1359946986937258015/1458658371891761339/1459478370977972316

## Description:

The play-like icon on the left side of the Recent Games UI looked
clickable but did not actually start a replay, which could be
misleading.
This PR updates the behavior so that clicking the icon now starts the
replay, matching the visual affordance and reducing user confusion.



https://github.com/user-attachments/assets/db9f02d9-9492-47ba-948b-6a6e0166d4d3



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

Co-authored-by: Ryan <7389646+ryanbarlow97@users.noreply.github.com>
Co-authored-by: iamlewis <lewismmmm@gmail.com>
2026-01-11 22:45:36 +00:00
Aotumuri 8235da9335 Translate displayMessage events via events_display keys (#2847)
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves #1225

## Description:

Replace all raw displayMessage strings with events_display.* keys +
params and add the new English translations in resources/
  lang/en.json so EventsDisplay can translate them.

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

aotumuri

---------

Co-authored-by: Ryan <7389646+ryanbarlow97@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-01-10 20:10:03 -08:00
TsProphet94 778b6867a4 Britannia Map fix (#2863)
## Description:

Fixed map assets and generated outputs. Fixed issues with map not
loading and pathfinding not working. Britannia (new) and Britannia
Classic. Now work correctly.

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

---------

Co-authored-by: Harry <Harry.bath94@gmail.com>
Co-authored-by: iamlewis <lewismmmm@gmail.com>
2026-01-10 20:09:03 -08:00
Aotumuri 497975e3fc Fix debug translation rendering (#2848)
## Description:

Fixed a bug that prevented debug mode from working.
Made it so that parameters are displayed.

<img width="800" height="559" alt="スクリーンショット 2026-01-10 14 24 51"
src="https://github.com/user-attachments/assets/2eff3073-15fe-4879-9448-c7f20b5e4eab"
/>

translation-key::parameters

## 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:
aotumuri
2026-01-10 19:29:44 -08:00
FloPinguin e130574c5c Very small UI fix 🔧 (#2862)
## Description:

Didier map name had a little UI problem.

And unrelated change: Because Lewis today said "it should be super low"
I turned down the frequency of this map from 2 to 1.

Previous:

<img width="1916" height="1312" alt="image2"
src="https://github.com/user-attachments/assets/0a84160b-91a8-4d02-b707-fa9eea1a15fd"
/>

Fixed:

<img width="562" height="476" alt="image"
src="https://github.com/user-attachments/assets/31fed7b5-c128-45cd-a63d-0aab3345cea3"
/>

## 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-01-10 19:21:17 -08:00