mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 21:44:49 +00:00
6eff1fc1966fac50eecfefed0701e22fe46c8d70
28 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
bcdc2126c6 |
bugfix: SAM was only reloading when not in cooldown (#3817)
## Description: reloadMissile() was inside the isInCooldown() block. For level-2+ SAMs, isInCooldown() returns queue.length === level, so after firing one of two missiles (queue.length = 1 < level = 2) the SAM is not in cooldown — meaning expired timers were never cleaned up. Stale queue entries caused subsequent shots to be treated as still-cooling even after the cooldown elapsed. SAM execution now mirrors the missile silo execution ## 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 |
||
|
|
742a544a69 |
2661 PR 3/3 Warship Manual Override, Aggro Override, and Heal-at-Port Command (#3501)
Part of [#2661](https://github.com/openfrontio/OpenFrontIO/issues/2661) (split into 3 PRs so they are not too large..) ## Description: Part 3/3 of [#2661](https://github.com/openfrontio/OpenFrontIO/issues/2661). This PR adds the retreat control and override behavior for warships: - Manual override: moving a warship manually cancels retreat and suppresses auto-retreat for 5 seconds - Aggro override: a retreating warship will aggro a nearby enemy transport or warship before continuing retreat - Heal-at-port command for sending a warship to a friendly port manually - Friendly-port validation for HealAtPortExecution - Regression tests for manual override, aggro override, and heal-at-port behavior ## 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: zixer._ --------- Co-authored-by: iamlewis <lewismmmm@gmail.com> Co-authored-by: evanpelle <evanpelle@gmail.com> |
||
|
|
eb51853b05 |
Perf/Fix: spawn and other functions that need closest by unit (#3243)
## Description: Performance improvements. - **PlayerImpl**: for _nukeSpawn_, cache config to const. - **Other files**: for nukeSpawn and other functions doing the same, introduce findClosestBy function. - for **TradeShipExecution**, with the move from _distSortUnit_ to _findClosestBy_, also add check if port isActive, !_isMarkedForDeletion_ and !_isUnderConstruction_. These checks should have been there already, so now do it in one go to make use of the predicate isCandidate in findClosestBy. - for **TradeShipExectution.test.ts**, add mock functions for _isMarkedForDeletion_ and _isUnderConstruction_ because of the above. Also, set Unit tiles and Pathfinding node to actual valid TileRefs for the testing map. This prevents NaN as return value from manhattanDist. This problem was already present with the use of distSortUnit, but that function just did NaN - NaN, returned the first and only port unit in the array and called it a day. For findClosestBy we have to make sure the predicate manhattanDist actually returns a number instead of NaN so we need actually valid tiles. We now have a working test instead of a test that actually silently failed like before. - **PlayerImpl**: _warshipSpawn_ and _nukeSpawn_: Make use of the isCandidate predicate of findClosestBy to have warshipSpawn not return ports under construction or (smaller change) inactive. This fixes a bug i have seen right away (where Warship spawns from under construction Port). Same for _nukeSpawn_ silos, don't return inactive silo just to be sure now that we can easily add it to isCandidate predicate anyway. This costs no performance in the _nukeSpawn_ benchmarks actually. This should as a by-effecft fix an edge case bug i have seen, where a nuke is sent from a phantom silo. Some of this goes along with PR #3220 since playerImpl buildableUnits makes use of the underlying spawn functions via canBuild. Just like ConstructionExecution does. But i didn't want to add more to PR 3220 since there's already a lot in there. The new function _findClosestBy_ could also be applied to some other parts of code to benefit of it being faster, so i did that. _findClosestBy_ uses _findMinimumBy_, which is a little more generic in name. I think _findMinimumBy_ could be used by other parts of code, while _findClosestBy_ is more clear naming for what it does now. But we could ditch _findMinimumBy_ and just leave findClosestBy? Examples of synthetic benchmarks (not included in this PR): **BEFORE CHANGES (before Scamiv's PR #3241)** <img width="705" height="91" alt="image" src="https://github.com/user-attachments/assets/d6d91c08-39f1-4387-9ccc-e51951caa539" /> <img width="751" height="101" alt="image" src="https://github.com/user-attachments/assets/80d400ac-3408-4107-aa58-6d2a847311e9" /> **AFTER CHANGES (before Scamiv's PR #3241)**   **BEFORE CHANGES (after Scamiv's PR #3241)**   **AFTER CHANGES (after Scamiv's PR #3241)** <img width="717" height="96" alt="image" src="https://github.com/user-attachments/assets/5b106843-bf6e-4448-a8e8-94448fb30ced" /> <img width="767" height="92" alt="image" src="https://github.com/user-attachments/assets/e6714c7b-26c1-455b-adae-f0060f1cbc7b" /> _Also see more **BEFORE** and **AFTER** in this comment:_ https://github.com/openfrontio/OpenFrontIO/pull/3243#issuecomment-3949060395 _And here a comparison in the flame charts:_ - based on the same replay and tried to get the performance recording going at the same speed and length but always end up with small differences - because of a bug in replays currently, it puts you in with the same clientID/persistantID currently. This means we can also record part of what is normally only recordable with live human input (the playerActions/playerBuildables). **BEFORE** flame chart with nukeSpawn (human player) and maybeSendNuke (Nation players, uses nukeSpawn via canBuild):    **AFTER** flame chart with nukeSpawn (human player) and maybeSendNuke (Nation players, uses nukeSpawn via canBuild):      ## 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 |
||
|
|
0dc8fbf129 |
Fix inverse annexation (#3448)
## Description: An inverse annexation could happen where the small player (even with 0,01% tiles owned) could fully annex the large player. **TL;DR:** basically wrong use of calculateBoundingBox in surroundedBySamePlayer, feeding it all bordertiles, making enemyBox far bigger than it actually was in some cases. Which resulted in enemyBox of small player with two small clusters at some distance from each other, being seen as inscribing the largest cluster of the bigger player. While that largest cluster is actually the border tiles of the bigger player surrounding the main cluster of the small player. Instead of an annexation of small by bigger, small would incorrectly annex bigger completely. **Situation:** bigger player fully surrounds main cluster of smaller player. Those border tiles are also the largest cluster of the bigger player, for which surroundedBySamePlayer is called. SurroundedBySamePlayer finds the small player as the only bordering enemy of this cluster. Then it needs to check which of the two players is surrounded by the other one. EnemyBox uses calculateBoundingBox with all border tiles of the small player as argument. The small player also has at least one seperate cluster elsewhere, could be on another island, which count as border tiles too. The enemyBox from the main cluster of the small player to the seperate cluster elsewhere, can be huge. Now inscribed() is called and it determines that largest cluster box of the bigger player (which was in fact calculated correctly, also making use of calculateBoundingBox) is surrounded by the bigger enemyBox. And so the small surrounded player fully annexes the bigger player. **Fix:** instead of a global enemyBox, we only need the localEnemyBox that touches the largest cluster of the bigger player. With that, inscribed() can correctly conclude that largest cluster box surrounds the localEnemyBox. As a matter of fact isSurrounded() already used the same method to calculate its enemyBox as introduced by @scamiv for v30: https://github.com/openfrontio/OpenFrontIO/pull/3127/changes#diff-fb1101a2b50dd7c353d082ff7a3351cff5469b8249b3ebca91c10573a3dfaaf1 - Change in PlayerExecution - Added test NoInverseAnnexation.test.ts, which fails before and passes after the fix The bug was introduced in this commit 10 months ago: https://github.com/openfrontio/OpenFrontIO/commit/c4381a9ad3828b06764ab1a21fc1514e37aacfd7 It has probably led to some weird annexations happening since then. The bug could seemingly happen on any map. But was noted recently a few times on square islands (Sierpinski) or maps (The Box/The Alps), where the circumstances probably highten the chances of the bug occuring. **Bug reports:** https://discord.com/channels/1359946986937258015/1481916231689703477/1481916231689703477 https://discord.com/channels/1359946986937258015/1481916231689703477/1481963273367851030 https://discord.com/channels/1284581928254701718/1479993924432171008/1479995658302652496 https://discord.com/channels/1284581928254701718/1479993924432171008/1481865495492956182 https://discord.com/channels/1284581928254701718/1483047153571201034 **BEFORE:** https://github.com/user-attachments/assets/4440182b-f696-45cf-bb01-b10159df8763 **AFTER**, on the same replay but with the bugfix: https://github.com/user-attachments/assets/5f461ab2-eb62-4cc3-ae07-e2224adbbc6a ## 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 |
||
|
|
c911bfb2d8 |
Packed unit updates / MotionPlans (#3292)
## Description: Reduce per-step `Unit` update traffic by shipping packed motion plans and letting the client advance plan-driven units locally. Changes: - Add packed motion plan records (`packedMotionPlans?: Uint32Array`) to game updates and transfer the buffer worker -> main. - Introduce `src/core/game/MotionPlans.ts` (schema + pack/unpack) for grid + train motion plans. - Extend `Game` with `recordMotionPlan(...)` and `drainPackedMotionPlans()`, and implement buffering/packing in `GameImpl`. - Treat units with motion plans as “plan-driven”: suppress per-tile `Unit` updates on `move()` and advance positions client-side. - Emit motion plans from executions: - `TradeShipExecution`: record/update grid motion plans and `touch()` when changing target after capture. - `TransportShipExecution`: record initial plan and update it when destination changes. - `TrainExecution`: record a train plan on init (engine + cars). - Client: apply motion plans in `GameView` and ensure `UnitLayer` updates sprites for motion-planned units even when no `Unit` updates arrived. ## 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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
2dada6f516 |
Handle Nation win condition (#2824)
Resolves #2823 ## Description: When playing in single-player mode, if an NPC reaches 80% land control before the player, the game enters a broken state where: - The game clock stops - Win checking stops permanently - Even if the player later conquers 100% of land, victory is never awarded - The game becomes "stuck" in a zombie state. This PR addresses this allowing Nations to be set as winners in single mode, and in this case showing a "Nation {nation} has won" modal to the user. This WinModal is the same as the "{player} has won", with the only change being the title. Nation wins in FFA, from the human player perspective: <img width="1457" height="837" alt="image" src="https://github.com/user-attachments/assets/1ce569bd-6616-4a23-b4a4-afedad2c64f8" /> ## 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 |
||
|
|
b090f2f624 |
HPA* Pathfinding (#2815)
## Pathfinding with HPA*
Hi! The primary objective of this PR is to replace per-tile A* with
hierarchical pathfinding - HPA*. In practice, this means we create an
abstract graph on top of the actual map with far fewer points and use it
to decide on general path structure. Only then we go back to tile-level
and build path between selected waypoints. This speeds up long distance
pathfinding by over 1000x in some cases. To make the review easier, it
comes with a benchmark and visual playground.
## PREPROCESSING
H part of HPA* means "hierarchical" and requires preprocessing.
This PR includes pre-processing as part inside `new Game()` constructor.
It takes about 135ms for `giantworldmap` on my machine, which increases
the effective initialization from ~95ms to ~230ms. This time could be
reduced in different ways, which are **out of scope** for this PR.
After confirming the initialization time is bearable on low-end devices,
I argue merging this PR as-is is acceptable tradeoff. It creates small
lag at the beginning of a round but pays for itself in the first minute
of the match.
## Nerdy details
**Architecture**
- HPA*-style hierarchical pathfinding
- 32×32 sectors on minimap with gateway nodes on borders
- Gateway graph built via BFS during preprocessing
- Water component optimization skips unreachable gateway pairs
- A* on gateway graph → local A* within sectors → Bresenham path
smoothing
- Minimap upscaling identical to currently used in MiniAStar
**Key Optimizations**
- Typed arrays instead of high-level primitives
- Stamp-based visited tracking (no need to recreate buffers, O(1)
clearing)
- Optional - enabled by default - caching of tile paths between gateways
- Line of sight smoothing for the final path
## Review Focus
Play with included tools, benchmark and visualization. Pathfinding
should be safe to merge as a black box - you do not need to understand
the details. Outcomes can be tested empirically in-game. Visualize (and
share!) edge cases with included playground. Confirm the 100x speedup is
real with benchmark.
If you plan to dive into the code, I suggest the following order:
- Pathfinding abstraction in `src/core/pathfinding/`
- Pathfinding tests in `tests/core/pathfinding/`
- NavMesh in `src/core/pathfinding/navmesh/` + integration with
`Game.ts`
- Benchmark in `tests/pathfinding/benchmark/`
Do not look at playground's code, it has been created with a clanker.
The design is 100% mine and I spent way too long polishing it, but I
haven't even once edited the code manually. There is probably no
abstraction whatsoever, just do not look at the code, let it play.
## Core Changes
#### Pathfinding (`src/core/pathfinding/navmesh/`)
- HPA* + refinement -> three phased pathfinding: A* over the graph ->
naive path -> refinement
- comes with A* and BFS optimized for for specific needs
#### Pre-Processing (`src/core/pathfinding/navmesh/`)
- identify water bodies to avoid pathfinding between disconnected nodes
- create high-level graph of gateways on top of tile map
#### Abstraction (`src/core/pathfinding/`)
- common `PathFinder` interface that can return full path and also act
as state machine (`.next()`)
- adapters for both new and legacy algorithm with fallback to legacy if
navigation mesh not available
#### Benchmark (`tests/pathfinding/benchmark/`)
- `npx tsx tests/pathfinding/benchmark/run.ts` - no guesswork, numbers
- `npx tsx tests/pathfinding/benchmark/run.ts --synthetic` - 1000s of
synthetic paths
- `npx tsc tests/pathfinding/benchmark/generate.ts` - generate more as
needed, test new maps
- includes ONE synthetic scenario to avoid PR bloat, generate more
locally / later
#### Playground (`tests/pathfinding/playground/`)
- `npx tsx tests/pathfinding/playground/server.ts` - visualize paths
with both new and legacy algorithm
## Benchmarks
### Compared with legacy in default - hand picked - scenario:
```
Initialization: 95.95ms -> 227.29ms
Pathfinding: 3038.43ms -> 6.45ms
Distance: 26972 -> 26810 tiles
```
### 42,000 synthetic routes across all maps
```
Running 42 synthetic scenarios with hpa.cached adapter...
✅ synthetic/achiran | Init: 93.42ms | Path: 139.07ms | Dist: 1481630 tiles | Routes: 1000/1000
✅ synthetic/africa | Init: 87.14ms | Path: 155.08ms | Dist: 1829414 tiles | Routes: 1000/1000
✅ synthetic/asia | Init: 57.60ms | Path: 112.55ms | Dist:
|
||
|
|
d7bcbf54f3 |
Add tests for MIRV execution (#2767)
## Description: This is a companion PR to https://github.com/openfrontio/OpenFrontIO/pull/2765. It implements tests and a performance benchmark for MIRV. ```bash $ npm test -- tests/core/executions/MIRVExecution.test.ts ✓ tests/core/executions/MIRVExecution.test.ts (9 tests) 71ms ✓ MIRVExecution (9) ✓ MIRV should launch successfully 10ms ✓ MIRV should break alliances on launch 5ms ✓ MIRV should separate into warheads 20ms ✓ MIRV warheads should only target tiles owned by target player 15ms ✓ MIRV warheads should be distributed with minimum spacing 12ms ✓ MIRV should display warning message on launch 2ms ✓ MIRV should not launch if player cannot build it 2ms ✓ MIRV should not launch when targeting terra nullius 2ms ✓ MIRV should launch when targeting own territory without breaking alliances 2ms ``` ```bash $ npm tsx tests/perf/MIRVPerf.ts ... === MIRV Performance Benchmark Results === MIRV target selection - sparse territory x 53.53 ops/sec ±0.48% (71 runs sampled) MIRV target selection - dense territory x 53.39 ops/sec ±0.57% (70 runs sampled) MIRV target selection - giant world map (350 targets) x 1,129 ops/sec ±0.98% (90 runs sampled) ``` ## 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 - [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 |
||
|
|
26f5d40819 |
build: migrate build system to Vite and test runner to Vitest & Remove depracated husky usage (#2703)
- Replace Webpack with Vite for faster client bundling and HMR. - Migrate tests from Jest to Vitest and update configuration. - Update Web Worker instantiation to standard ESM syntax. - Implement Env utility in `src/core` for safe, hybrid environment variable access (Vite vs Node). - Refactor configuration loaders to remove direct `process.env` dependencies in shared code. - Update TypeScript environment definitions and project scripts for the new toolchain. - Remove the [depracated usage of the husky](https://github.com/typicode/husky/releases/tag/v9.0.1). ## Description: migrate build system to Vite and test runner to Vitest & Remove depracated husky usage ## 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 - [ ] 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: evanpelle <evanpelle@gmail.com> |
||
|
|
6112547273 |
Improve random spawn (#2503)
## Description: This is a previously approved PR with an additional commit that fixes case when nations change spawn & jump around, their previous territory wasn't getting deleted. ## 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: nikolaj_mykola --------- Co-authored-by: Evan <evanpelle@gmail.com> |
||
|
|
8f53785a80 |
BUG FIX: Gold double deduction + Rmoval of UnitType.Construction (#2378)
## Description: - Removed the temporary UnitType.Construction and embedded construction state into real units via isUnderConstruction(). - Centralized non-structure spawning to perform a single validation right before unit creation/launch. - Updated UI layers to render construction state without relying on the removed enum. - Adjusted and created tests to match the new flow and to cover the no-refundscenarios. # Tests updated - tests/economy/ConstructionGold.test.ts: covers structure cost deduction and income, tolerant of passive income; ensures no refunds during construction. - tests/nukes/HydrogenAndMirv.test.ts: accounts for single-check launch flow; MIRV test targets a player-owned tile; ensures launch after payment. - tests/client/graphics/UILayer.test.ts: mocks now provide isUnderConstruction and real type strings; ## 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: CrackeRR1 --------- Co-authored-by: Evan <evanpelle@gmail.com> |
||
|
|
d3c4cd6620 |
Record missing stats (#2407)
## Description: Some stats are missing from the recorded game stats: - Unit upgrade - Gold from trade and from steal The gold from trade/steal was introduced with [PR 784](https://github.com/openfrontio/OpenFrontIO/pull/784) but was quickly reverted with [PR 927](https://github.com/openfrontio/OpenFrontIO/pull/927), probably involuntarily. ## 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 |
||
|
|
f161c94ff4 |
Max timer (#1289)
## Description: Adds a max timer setting The timer starts at max timer and goes down, becoming red if reaching < 1 min The player with the biggest territory wins at the end of the timer  ## 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 - [x] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors ## Please put your Discord username so you can be contacted if a bug or regression is found: Vivacious Box --------- Co-authored-by: Loymdayddaud <145969603+TheGiraffe3@users.noreply.github.com> |
||
|
|
187ef1f2dd |
feat(PlayerExecution): downgrade defense posts on capture (#1957)
## Description: Closes https://github.com/openfrontio/OpenFrontIO/issues/1619. On capture, defense posts will be downgraded. On the live version this means defense posts will be destroyed, as defense posts can only be level 1. Misc. changes: - added `decreaserLevel` helper - cleaned up if/else in tick unit loop for clarity to avoid yet another nested layer Continuation of the stale PR, https://github.com/openfrontio/OpenFrontIO/pull/1622. ## 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: Discord username: `seekerreturns` |
||
|
|
fa7b7fceb3 |
Enable the @typescript-eslint/no-unused-vars eslint rule (#2130)
## Description: ### ✅ Summary of Changes This PR enables the ESLint rule **`@typescript-eslint/no-unused-vars`** as requested in the issue and applies the necessary code adjustments across the project. #### 🔧 What was done: - Activated the rule `@typescript-eslint/no-unused-vars` in the ESLint config. - Updated ~70 files to comply with the rule: - Replaced unused variables with a `_` prefix where appropriate. - Added inline ESLint disable comments (`eslint-disable-next-line`) for specific cases where the variable or code block seemed important for context, readability, or future use. - Ensured no linting errors remain related to this rule. --- ### ❓ Clarification Some cases were handled with inline disable comments instead of removing the variable entirely, to avoid accidental breaking changes or loss of intent. If a different approach is preferred (e.g., stricter removal or alternative handling), I’m happy to adjust the implementation accordingly — just let me know! --- ### 🙌 Next Steps Please review and let me know if: - Any file should be handled differently. - You prefer removal instead of disabling in certain areas. - Additional rules should be enforced or reverted. I’m available to make any follow-up improvements needed. --- ### 🎃 Hacktoberfest Note I'm participating in **Hacktoberfest**, so if this PR is accepted, please add the label: `hacktoberfest-accepted` Thank you! #1784 ## 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: DISCORD_USERNAME |
||
|
|
eeeb7e4b4e |
SAM smart targeting (#1618)
## Description: Current SAM behavior is to shoot a missile as soon as a nuke is in range. Players can exploit it by overshooting behind the SAM, so the SAM missile will take way longer to reach the nuke, usually too late to prevent its explosion. This PR introduces a "smart" targeting system that allows SAM to calculate an optimal interception tile along the nuke's trajectory. They can also preshot before the nuke becomes vulnerable, as long as the interception tile will be within the vulnerable window. This change makes SAM range enforcement much more strict. Changes: - Nukes now precompute their full trajectory on creation and update their current position index every tick. - SAMs use this trajectory data and their own missile speed to calculate the ideal interception tile. - SAM missiles now aim directly at that interception point rather than chasing the nuke. Small changes on the fly: - `BezierCurve` now uses a provided increment so the curve LUT is the optimal size - Increased nuke opacity when untargetable: 0.4 → 0.5 - Slightly extended nuke vulnerability range to SAMs: 120 → 150 === Preshot an incoming nuke still in the unfocusable state. Notice how the nuke is destroyed as soon as becomes focusable: https://github.com/user-attachments/assets/9fbf1ae4-33b4-4fa0-9b53-cb53f3adc17b Shooting right at the range limit: https://github.com/user-attachments/assets/d68793ac-b249-45fe-88bf-e20f70758449 Shooting behind the SAM: https://github.com/user-attachments/assets/800cd7ff-d9d9-40f3-aba8-fa3ab526b3b2 ## 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 - [x] I have read and accepted the CLA agreement (only required once). ## Please put your Discord username so you can be contacted if a bug or regression is found: IngloriousTom |
||
|
|
65937b7e69 |
bugfix: when nuking nearby water, the attacker was not marked as a traitor on launch (#1574)
## Description: There was a bug where we only checked for betrayals if the target tile was owned. ## 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 - [x] I have read and accepted the CLA aggreement (only required once). ## Please put your Discord username so you can be contacted if a bug or regression is found: evan |
||
|
|
b850a2f93d |
Tradeship performance (#1448)
## Description: Small performance improvements for tradeship execution. With the new cap of 100 tradeships in total, the impact is smaller but still there. Also added jlrouillard's (Vivacious Box) test with permission from PR #1449. Tests 100% passed. - Save tradeship owner, destination port owner and tradeship current tile in constants for re-use. - Added check if wasCaptured was already set to true, before comparing origOwner and tradeship owner and setting wasCaptured to true. Currently, wasCaptured is set to true once and never back to false again. This PR keeps it that way but a but faster. - One less call to pathfinder needed: before calling pathfinder, check if current tile is destination port tile, and if so call complete. This is basically the same as pathfinder would do, but less complex without need for e.g. manhattan distance. - case PathFindResultType.Completed: isn't needed anymore because of the above. Kept as fallback. But moved it down in the switch statement, as there's a low(er) chance the case will ever be true. - Test if we need to find a new destination port for captured ship: currently, if this.wasCaptured is true, it will look for a new destination port each tick again and again. With this PR, only do this if destination port isn't owned by capturer, or if that port has become inactive. In tests with thousands of tradeships, went down from 300K+ times setting 'new' port, to only 1250 calls. **Q:** Will this code work for ships that are captured again, after being captured already? **A:** Yes. After wasCaptured is set to true once (after first capture), we only need to check each tick if the destination port is owned by the current tradeship owner, to know if we need to assign a new destination port again. ## 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 - [x] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors ## Please put your Discord username so you can be contacted if a bug or regression is found: tryout33 |
||
|
|
be01b90b25 |
Eslint (#998)
## Description: Enable a few eslint rules: - `@typescript-eslint/no-empty-object-type` - `@typescript-eslint/no-require-imports` - `no-useless-escape` ## 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 - [x] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors --------- Co-authored-by: Scott Anderson <scottanderson@users.noreply.github.com> |
||
|
|
ca522a5937 |
refactor cosmetics out of PlayerInfo (#1299)
## Description: Remove Cosmetics from PlayerInfo. The game engine should have no knowledge of cosmetics since they shouldn't affect game play at all. Instead pass player cosmetics into the GameView. ## 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 - [x] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors ## Please put your Discord username so you can be contacted if a bug or regression is found: evan |
||
|
|
ad42dc0ee8 |
Fix sam targetting everything (#1280)
## Description: There was a regression on how sam targets nukes. This fixes it ## 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 - [x] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors ## Please put your Discord username so you can be contacted if a bug or regression is found: Vivacious Box |
||
|
|
b48770faf0 |
Move maps generation out of repo, new map structure (#1256)
## Description: Move map generation outside of main repo, it has been rewritten in Go and is much faster. Also refactor how maps are stored, one dir per map. The map binaries are basically identical to before. Some maps like Africa have 1% difference in bytes, but playing it looks exactly the same. Use lazy loading for map data access so only needed files are accessed. Unit tests now load map binary instead of regenerating it from scratch, speeding them up. ## 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 - [x] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors ## Please put your Discord username so you can be contacted if a bug or regression is found: evan |
||
|
|
b71acdc993 |
Patterned territory (#786)
## Description: This is meant to give players more customization options. Permission handling hasn’t really been implemented yet. ## 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 - [x] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors ## Please put your Discord username so you can be contacted if a bug or regression is found: aotumuri |
||
|
|
7fa11ed035 |
Set a targetable status for nukes (#1174)
## Description: Set a targetable status for units (specifically atom bomb and hydro) A nuke is targetable near launch and target but is untargetable mid air. An untargetable unit is half transparent to show that it cannot be destroyed.  ## 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 - [x] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors ## Please put your Discord username so you can be contacted if a bug or regression is found: Vivacious Box |
||
|
|
52ecaea06c |
Redraw stacked buildings sprites (#1170)
## Description: When buildings are stacked on each other, the buildings under are not redrawn when the stacked building is destroyed. A simple outer range + sprite radius check triggers a touch which redraws the buildings. Sprite radius is set to 16 (dont forget to change it if it ever changes) ### Before:  ### After:  ## 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 - [x] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors ## Please put your Discord username so you can be contacted if a bug or regression is found: Vivacious Box |