mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 11:20:45 +00:00
dbd4beef11ec1079606426ea0f3d25d1d689be66
27 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
dbd4beef11 | feat: add impassable terrain for non-rectangular maps | ||
|
|
8a8079b979 |
Fix parallel bot boat attacks of nations 🐛 (#4297)
## Description: When a nation attacked multiple bots via boat attacks in parallel, each boat attack computed its troop allocation independently using `player.troops() / 5` without subtracting `botAttackTroopsSent`. The cumulative troop commitment could exceed the nation's actual troop count, and when the queued `AttackExecution`s ran `init()`, they drained the nation to zero. Planetary Realignment found this bug by accident, here Russia has only 39 troops: <img width="1189" height="654" alt="image" src="https://github.com/user-attachments/assets/07b85e00-6734-4ddd-a16e-fe53309e0ef8" /> The land attack path already handled this correctly. The bug in `sendBoatAttack` was introduced by #3786, which made nations see and attack enemies across rivers via boats, and changed `attackBots()` from `.neighbors()` to `.nearby()`. So the bug was on prod for the entirety of v31. This fix extracts the shared attack troop calculation (reserve, bot-aware allocation, troopSendCap, isAttackTooWeak, emoji) into a new `calculateAttackTroops` method, with a callback for the non-bot troop default (land: `player.troops() - targetTroops`, boat: `player.troops() / 5`). Bot targets in both paths now go through the same reserve-aware calculation. ## 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 ## Please put your Discord username so you can be contacted if a bug or regression is found: FloPinguin |
||
|
|
094aa766ce |
Improve "Better troop management for nations 🤖" (#4278)
## Description: **Allow Hard/Impossible nations to retaliate and expand freely** Previously, nations on Hard/Impossible difficulty could be stuck unable to fight back if their `troopSendCap` or `isAttackTooWeak` checks blocked them from sending enough troops. **@legan320** on the main discord noticed it. Now: - `troopSendCap` raises the cap to at least the total incoming attack troops, so nations can match the force being used against them - `isAttackTooWeak` bypasses the 20% minimum check entirely when under attack - `troopSendCap` no longer applies when attacking Terra Nullius, so nations can always expand into unowned land with full troops All checks still apply normally for unprovoked attacks against other players. ## 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 ## Please put your Discord username so you can be contacted if a bug or regression is found: FloPinguin |
||
|
|
82b68d16a1 |
Fix "Better troop management for nations 🤖" (#4265)
## Description: There was a check missing... The troop management stuff should be disabled for team games because nations can expect donations in that case, and its mainly relevant for FFAs. ## 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 ## Please put your Discord username so you can be contacted if a bug or regression is found: FloPinguin |
||
|
|
d96c055df1 |
Better troop management for nations 🤖 (#4239)
## Description:
When human pro players have non-allied players with similar troops next
to them, they wouldn't send out a big attack.
But nations are doing exactly that.
With this PR, they no longer do. On hard and impossible.
On easy and medium they are stupid 😀
```
1. Troop send cap: the nation must retain a minimum fraction of its
strongest non-allied neighbor's troop count (Hard: 75%, Impossible:
90%). Attacks that would drop below this floor are scaled down or
skipped entirely. Allied and same-team neighbors are ignored since
they pose no threat. The cap applies to land attacks, boat attacks,
and random boat attacks.
2. Minimum attack strength: if the capped troop count is less than 20%
of the target's troop count, the attack is skipped as too weak to be
worthwhile. Only applies on Hard and Impossible.
```
_Coded by MiMo 2.5 Pro, reviewed by MiniMax M3_
## 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
## Please put your Discord username so you can be contacted if a bug or
regression is found:
FloPinguin
|
||
|
|
eca5794ebb |
Chore(deps): Update and remove dependencies (#3819)
## Description:
Only mentioning removals/major updates/notable changes below, not all
minor upgrades.
### Removed:
- "@aws-sdk/client-s3": not used anywhere (was used in Archive.ts
previously)
- chai, "@types/chai", sinon-chai: not used anywhere, probably leftover.
Vitest uses a bundled version of Chai for its expect asserations under
the hood too.
- protobufjs, "@types/google-protobuf": not used anywhere, probably left
from evan's experiment with it? Removed from vite.config.ts too.
- "@types/jquery": not used anywhere, probably leftover
- sinon, "@types/sinon": not used anywhere just like chai, probably
leftover. And Vitest provides us with the same functionality.
- "@types/systeminformation": dependency systeminformation was removed
last year, this is an unneeded, deprecated and unmaintained remainder.
- vite-tsconfig-paths: removed, and removed the import and usage in
vite.config.ts and replaced it by adding `tsconfigPaths: true` to the
`resolve` block. Because of this message displayed on running the tests:
"The plugin "vite-tsconfig-paths" is detected. Vite now supports
tsconfig paths resolution natively via the resolve.tsconfigPaths option.
You can remove the plugin and set resolve.tsconfigPaths: true in your
Vite config instead."
- vite-plugin-static-copy: removed, we don't use it anymore (was used in
our vite.config.ts once,, probably before Vite natively supported
copying static assets via its publicDir configuration)
### Updated:
- color.js: v0.5 > v0.6, no breaking change affecting us
- cross-env: v7 > v10. It's a publicly archived repo since Nov 2025. But
before that he got it up-to-date from June 2025, porting to TS, dropping
old Node versions, dependencies etc. Seems still good to use for some
amount of time to come.
- dotenv: v16 > v17, now logs an informational message by default when
it loads an environment file. Can be disabled by using
dotenv.config({quite: true}) if needed.
- ejs: v3 > v5: security patches mostly. Vite still uses v3 btw.
- eslint: v9 > v10. Newly enabled rules by default:
'no-unassigned-vars', 'no-useless-assignment' and
'preserve-caught-error'. Mostly faster and minimum support moved to
higher node versions, which shouldn't be a problem.
- "@eslint/compat": v1 > v2. Minimum supported Node versions, which
should not be a problem.
- intl-messageformat: v10 > v11 no breaking changes that affect us
- jdom: v27 > v29. Faster. Most notably minimum support moved to higher
node v22 version, which should not be a problem. Also, see types/node,
kind of expecting v24 to be installed now.
- nanoid: from v3 to v5, no breaking changes that affect us
- "@opentelemetry/sdk-logs": now that addLogRecordProcessor is removed,
changed Logger.ts to pass an (empty) provider array directly to the
LoggerProvider constructor. Follows the changes in
https://github.com/open-telemetry/opentelemetry-js/pull/5588
- "@tailwindcss/vite": supports vite v8 from 4.2.2, and a fix for it in
4.2.4
- tailwindcss: supports vite v8 from 4.2.2
-- in 4.1.15 (we were already above this version) break-words was
deprecated in favor of wrap-break-word. But break-words, which we use in
15 places, will still work as expected
(https://github.com/tailwindlabs/tailwindcss/pull/19157). Same goes for
also deprecated "order-none".
- "@types/node": from v22 to v24, assuming most now use node 24
- vite v7 > v8:
-- is now on 8.0.10 so first bugs are out of it, while v8 itself also
fixed a big number of bugs.
-- in vite.config.ts, fixed Ts error/compilation issue by changing the
manualChunks option in build.rollupOptions.output to use the function
syntax, which is required by the updated types instead of the object
syntax.
- zod: no changes that affect us
### Prettier:
Updated only because of (new because of update?) Prettier errors for
files untouched in this PR originally:
- PathFinder.Parabola.ts
- WorkerMessages.ts
- ClanModal.handlers.test.ts
- ClanModal.rendering.test.ts
- CONTRIBUTING.md
- README.md
### ESLint:
Fixes needed to silence errors coming from newly enabled recommended
rules 'no-useless-assignment' and 'preserve-caught-error':
For 'no-useless-assignment' (default assignment never used because of
unreachable code or they are guaranteed to get a value, so they can be
undefinedat the start. Exception was AttackExecution, so made the
default value of 0 the default case in the switch statement):
- ClientGameRunner
- GameModeSelector
- NameBoxCalculator
- StructureDrawingUtils
- TerritoryLayer
- Diagnostics
- GameRunner
- ColorAllocator
- DefaultConfig
- AttackExecution
- AiAttackBehavior
- Worker.worker
- GamePreviewBuilder
For 'preserve-caught-error', disabled the rule here because the possible
fix `{cause: error}` was introduced in ES2022 while we're still on
target ES2020 currently:
- GameServer
- Privilege
_Error: The value assigned to 'gameMap' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'timeDisplay' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'scalingFactor' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'radius' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'teamColor' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'gl' is not used in subsequent statements.
(no-useless-assignment)
Error: The value assigned to 'power' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'tickExecutionDuration' is not used in
subsequent statements. (no-useless-assignment)
Error: The value assigned to 'selectedIndex' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'mag' is not used in subsequent statements.
(no-useless-assignment)
Error: The value assigned to 'speed' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'matchesCriteria' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'shouldContinue' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'description' is not used in subsequent
statements. (no-useless-assignment)
Error: There is no `cause` attached to the symptom error being thrown.
(preserve-caught-error)
Error: There is no `cause` attached to the symptom error being thrown.
(preserve-caught-error)_
All tests pass. TypeScript and ESLint errors resolved.
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
tryout33
---------
Co-authored-by: Copilot <copilot@github.com>
|
||
|
|
58ec8b280f |
Nations: Fix city farming + reactive defense posts + fix nuked territory capture 🛡️ (#3814)
## Description: Would be very good to get these fixes last minute into v31. - **Farming nations for cities is fixed**: Here you can see city farming in action, vari farms Finland: https://www.youtube.com/watch?v=J4J0ajlnSHs&t=137s - Lots of 125k gold cities... Now nations will build defense posts instead of cities: - **Nations now build defense posts reactively** instead of through the normal structure build order. When a nation is under significant land attack (incoming/own troops >= 35%), it places a defense post near the attack front -- skipped on Easy, capped at 1 on Medium, and scaled by the incoming troop ratio on Hard/Impossible. Posts spread along the front. The old `defensePostValue()` placement path is removed. - **Nations now capture nuked territory.** `hasLandBorderWithTerraNullius()` was incorrectly filtering out tiles with fallout, causing the `nuked` attack strategy to never dispatch a attack. Big bug . - [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 |
||
|
|
7654537a00 |
Much better river handling for nations and tribes! 🏞️ (#3786)
## Description: In this example, the two nations DONT see each other as neighbors, but as ISLANDERS. Because they dont have a direct border connection, there is water in between. <img width="526" height="329" alt="image" src="https://github.com/user-attachments/assets/cf2c15b5-7793-4445-afd2-920d6cd50a2a" /> This is a big problem, because most of the logic in AiAttackBehavior gets ignored. Only the "islander" strategy runs (late, because its a not-important strat). ### Summary - `PlayerImpl.neighbors()` now includes cross-water neighbors: a new `shoreReachableNeighbors()` helper samples every 10th shore border tile and looks up to 5 tiles in each cardinal direction across water, finding land owners on the other side (covers rivers up to 4 tiles wide). - `AiAttackBehavior.maybeAttack()` extends the `hasNonNukedTerraNullius` check to also trigger on TN detected via `player.neighbors()`, so nations notice and pursue TN that is only reachable across a river. - `sendAttack()` uses a new `hasLandBorderWithTerraNullius()` land-only adjacency check to decide between a land attack and a boat attack for TN, rather than `sharesBorderWith()` which includes water tiles. - Added `sendBoatAttackToNearbyTerraNullius()`: when no TN land is directly adjacent, the AI scans its shore border tiles for unowned land across water and dispatches a transport ship. ### Also works for Tribes! Tribes can boat rivers now, really cool. https://github.com/user-attachments/assets/382e85aa-c437-4e0c-afc2-0c381432da3d ## 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 |
||
|
|
692028d033 |
Make nations more forgiving toward humans on Easy difficulty 🕊️ (#3791)
## Description: - Nations on Easy no longer betray human allies - Nations on Easy now attack humans only 25% of the time (down from 50%) - Increased Easy reaction tick range (65-100, up from 65-80) so nations respond more slowly - Raised MIRV steamroll-stop thresholds on Easy (city gap multiplier 1.5 -> 2, min leader cities 15 -> 20) and slightly tuned Medium/Hard thresholds ## 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 |
||
|
|
8099b9fad7 |
Massive nation improvement 🤖 (#3761)
## Description: - Hard / Impossible nations in team games auto-stop trading with all enemies - If there are a LOT of nations on the map (Enzo stream with 400 nation HvN private games) they no longer start with a city, they start with eco (port / factory) because they cannot gain much gold from bot-killing - Impossible nations built way too many missile silos sometimes, caused by the SAM overwhelming logic. Fixed now. - In public HvN games with 5M starting gold, nations placed their structures way too fast, which slowed down their expansion. And humans could easily cause a lot of damage with one atom bomb. Now their first structure is a SAM (on hard / impossible) and they wait between their earlygame structure placements. - Nations now spread out their port placements more evenly - Nations are now able to attack much stronger enemies in team games (They can expect donations) - Improve performance a bit by adding more early-returns (Dont run any nuking logic if nukes are disabled, no alliance logic if alliances are disabled, no boating logic if transport boats are disabled, ...) - Fix some of the "cannot send troops" messages in the console (DonateTroopExecution) - Nations build their first missile silo sooner, they should also build more SAMs - Nations spend their gold better after reaching the save-up-target (previously they stopped nuking) - Optimized save-up-targets for team games - The richest impossible nation is nuking very dense players now (lot of structure levels on a small island) ### How does a 5M gold HvN start look like now? https://github.com/user-attachments/assets/e9da89c3-c0d4-4144-a741-3101746b16da ## 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 |
||
|
|
f7716c7d42 |
Little Console Cleanup 🧹 (#3741)
## Description: Fixes these console warnings from bots: <img width="591" height="94" alt="Screenshot 2026-04-19 033624" src="https://github.com/user-attachments/assets/6ee79302-e2a7-4195-94e5-c1f455eb1799" /> Removes some spammy logs, they dont seem to be helpful? <img width="271" height="174" alt="Screenshot 2026-04-19 033739" src="https://github.com/user-attachments/assets/70122506-e8fb-4a72-b73e-08e72fe222bd" /> <img width="284" height="656" alt="Screenshot 2026-04-19 033646" src="https://github.com/user-attachments/assets/4b4ebef2-e191-4947-9615-0e26cd9bf075" /> ## 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 |
||
|
|
17c1a6300f |
Trading in lakes 🚤 (#3653)
## Description: - Widened port placement and warship spawn/patrol checks from `isOcean`/`isOceanShore` to `isWater`/`isShore`, so ports can be built on lake shores and ships can operate on lakes, we discussed it here: <img width="996" height="423" alt="image" src="https://github.com/user-attachments/assets/acf1e970-9631-4848-a0ed-6d0470616e1d" /> - Filtered `tradingPorts()` by water component so ports only attempt trades with reachable ports - prevents silent path-not-found failures across disconnected water bodies - Applied the same water component filter when a captured trade ship reroutes to its new owner's nearest port - Removed the `WaterManager` fallback that force-marked isolated water-nuked-tiles as ocean (no longer needed since lakes are now navigable) - Added a check to prevent nations from building ports on water bodies that aren't accessible to other players ## 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: Evan <evanpelle@gmail.com> |
||
|
|
aa59dd23be |
Rebalance HvN (#3433)
## Description: For the next v30 fix version <img width="868" height="364" alt="imaege" src="https://github.com/user-attachments/assets/520a999c-67e7-4c57-8651-895ad9eeb73a" /> HvN balancing for the revamped difficulty steps of v30 sadly doesn't really work out... In medium difficulty games humans nearly always win (boring) In hard difficulty games humans usually lose It was intended differently... So lets get rid of medium difficulty HvN, always use hard difficulty and disable the donation-capability for public game nations. That will tune the human winrate towards a middle ground at about 65% I think. Which should be nice. Easier than in v29 (was frustrating sometimes) but not as easy as it's now. We can only test this in prod lol ## 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 |
||
|
|
e137fcaa6c |
Fix/Perf/Refactor: playerActions and buildableUnits, their callers and related types (#3220)
## Description: TL;DR: it's faster. buildableUnits is called via PlayerView.actions from UnitDisplay (each tick without TileRef), BuildMenu (each tick when open), MainRadialMenu (each tick when open), PlayerPanel (each tick when open), StructureIconsLayer (when placing a building from build bar), NukeTrajectoryPreviewLayer (when placing nuke, on tick when tile changes), ClientGameRunner (on click to attack/auto-boat or hotkey B or G). After https://github.com/openfrontio/OpenFrontIO/pull/3213 got merged, the change with largest impact in https://github.com/openfrontio/OpenFrontIO/pull/3193 was done in such a different way that a new PR was needed The idea in 3193 was to not always ask for Transport Ship from buildableUnits. In such a way that very little extra data was send to the worker. This had the biggest impact on performance (the idea was months older btw, see https://github.com/openfrontio/OpenFrontIO/pull/2295). Now, we do it the other way around, by telling buildableUnits all unit types we want. Or we want them all (undefined). The downside is more data is send in the worker message. The upside is we have more options and can add more in this PR. This PR implements some of the leftovers in 3193 on top of 3213 and adds further improvements. (Some unrelated refactor/perf changes where moved out of this PR and into already merged https://github.com/openfrontio/OpenFrontIO/pull/3233, https://github.com/openfrontio/OpenFrontIO/pull/3234, https://github.com/openfrontio/OpenFrontIO/pull/3235, https://github.com/openfrontio/OpenFrontIO/pull/3236, https://github.com/openfrontio/OpenFrontIO/pull/3237, https://github.com/openfrontio/OpenFrontIO/pull/3238, https://github.com/openfrontio/OpenFrontIO/pull/3239) - **GameRunner**, **WorkerMessages**: _playerActions_ and _PlayerActionsMessage ._ Option to ask for no buildable units (null). It now has 3 modes: get all actions and all buildings (units undefined), get all actions and no buildings (units null), or get all actions and specific building (units contains Unit Types). - **GameRunner**: _playerActions_. fixes wrong assumption in PR 3213: that only if units was undefined, we have to know canAttack. ClientGameRunner wants to know both, in case of a click on non-bordering land, to decide if it should auto-boat using a Transport Ship. So units is not undefined (we only ask for Transport Ship now which has a positive effect on performance for each click/tap) but we need canAttack still. Solved by removing the unit === undefined check before _canAttack_ in _playerActions_. - **GameRunner**, **GameView**, **WorkerClient**, **WorkerMessages**, **Worker.worker**: added _playerBuildables_ / _buildables_ next to existing _playerActions_ / _actions_. With above solved, there was still no option to only get buildable units when the actions are not needed. While **StructureIconsLayer**, **NukeTrajectoryPreviewLayer**, **BuildMenu** and **UnitDisplay** need only that. To not make playerActions more convoluted with more params or so, i've added a new function _playerBuildables_ in **GameView** to only get buildable units (**GameRunner** _playerBuildables_). _playerBuildables_ has 2 modes: get all buildings (units undefined) or get specific buildings (units contains Unit Types). Also update some comments that mentioned .actions in **NukeTrajectoryPreviewLayer**. - **ClientGameRunner**, **PlayerPanel**, **BuildMenu**, **UnitDisplay**, **StructureIconsLayer** and **NukeTrajectoryPreviewLayer**: Since PR 3213, **StructureIconsLayer** and **NukeTrajectoryPreviewLayer** ask for specific types of units from **GameView** _actions_ (**GameRunner** playerActions). Now have the other files do the same. For example **BuildMenu** asks for the new _BuildMenuTypes_ when it calls ._buildables_ and **ClientGameRunner** asks for UnitType.TransportShip when sending a boat - **ClientGameRunner**: canBoatAttack now accepts BuildableUnit[] instead of PlayerActions so we can send it either actions.buildableUnits or just buildables. Have functions call myPlayer.buildables(tileRef, [UnitType.TransportShip]) when we only need a buildable unit and no actions. Or myPlayer.actions(tileRef, null) when we need actions but no buildable units. Or myPlayer.actions(tileRef, [UnitType.TransportShip]) when we need both actions, like canAttack, and a buildable unit. Then if needed send either actions.buildableUnits or buildables to to _canAutoBoat_ / _canBoatAttack_. - **MainRadialMenu**: needs all player buildable unit types including Transport Ship, so the _actions_ call argument for unit types can stay undefined (unchanged) there. - **MainRadialMenu**: now that **BuildMenu** uses _playerBuildables_ instead of _playerActions_, we must put data in _this.buildMenu.playerBuildables_. And since we're not putting the (unneeded) full _actions_ in there anymore, we can now put only the needed and expected _actions._buildableUnits_ in it. - **Game**, **PlayerImpl**, **StructureIconsLayer**: Typesafety and some added perf: new type _PlayerBuildableUnitType_ (see also the below point for how it is formed). So callers of _buildableUnits_ can never ask for the wrong type like e.g. UnitType.Train because it doesn't return data for that type. This type is now used in **PlayerImpl**, **BuildMenu**, **RadialMenuElements**, **StructureDrawingUtils** and **UnitDisplay** for that reason. And **InputHandler**, **StructureIconsLayer** and **UIState** (little more on that in point below). - **InputHandler**, **StructureIconsLayer**, **UIState**: In order to make type safety work for GhostUnit.buildableUnit.type too (line ~217 of StructureIconsLayer), changed type of interface _BuildableUnit_ to _PlayerBuildableType_. Which is only more accurate. Same for and this.structures and uiState.ghostStructure and with the latter, _renderUnitItem_ in **UnitDisplay** and _setGhostStructure_ in **InputHandler**. All Structures are of PlayerBuildableType (there are even some in PlayerBuildables that aren't Structures, but it is much more confined than UnitType). - **Game**: Typesafety and some added perf: added _BuildMenus_ and _BuildableAttacks_ in the same fashion that the existing StructureTypes was already used (simplified it a bit too, with it renamed _StructureTypes_ to _Structures_ and removed _isStructureType_). They can be used with .types or .has(). _BuildableAttacks_.has() is used in **RadialMenuElements**. _BuildableAttacks_ and existing _Structures_ now make up _BuildMenus_. Which is used in **BuildMenu**, **StructureIconsLayer** and **UnitDisplay**. Then _BuildMenus_ together with UnitType.TransportShip make up the _PlayerBuildables_. Which is used in **PlayerImpl** _buildableUnits_ (see point below). And with _PlayerBuildableUnits_ we get the new _PlayerBuildableUnitType_ (see above point on Game / PlayerImpl). - **RadialMenuElements**: replace non-central ATTACK_UNIT_TYPES in **RadialMenuElements** with centralized _BuildableAttackTypes_ too. Use _PlayerBuildableUnitType_ for more type safety (can't by mistake add UnitType.Train to its build menu). Make use of _BuildableAttackTypes_ instead of adding items hardcoded line by line in _getAllEnabledUnits_, just like we already did since PR 3239 with _StructureTypes_. And use _BuildableAttacks.types_ in the same fashion that existing _isStructureTypes_ (now Structures.types) was already used elsewhere. - **PlayerImpl**: _buildableUnits_ -- would do Object.values(UnitTypes) on every call. Now for better perf directly loop over player buildable units by using _PlayerBuildables_ (see above point). In this way we also exclude MIRVWarhead, TradeShip, Train, SamMissile and Shell so there are less unit types to loop through by default. Since a player doesn't build those by themselves, they are only build by Executions which use _canBuild_ directly and not _buildableUnits_. -- for more performance, do for loop instead of using .map and .filter, no intermediate array needed nor callback overhead. We just loop over the given units (which if undefined will contain _PlayerBuildables_). Also pre-allocate the results array to get the most out of it, even if V8 might already be very good at this. -- cache config, railNetwork and inSpawnPhase so they can be re-used inside the for loop. -- cache cost inside the loop -- it would check twice for tile!==null to decide to call findUnitToUpgrade and canBuild. Now once. -- eliminated double/triple checks for the same thing. It called _findUnitToUpgrade_ (and with that _canUpgradeUnit_) and then _canBuild_ which both check if player has enough gold for the cost of the unit type. And they both check if the unit type is disabled. Now we call private functions _canBuildUnitType_, _canUpgradeUnitType_ to first do checks on unit type level for early returns, and _findExistingUnitToUpgrade_ to find existing unit without doing anything extra. in a specific order to check everything only once. The public functions _findUnitToUpgrade_ and _canBuild_ have an unchanged functionality and we don't call them from _buildableUnits_ anymore. -- would get _overlappingRailRoads_ and _computeGhostRailPaths_ when canBuild was true. But this data is only meant for **StructureIconsLayer** and it logically only uses it when placing a new unit, not when upgrading one. Which is also commented on line 351 of **StructureIconsLayer**. So, we now only get overlapping railroads and ghost rails if we're not hovering to upgrade an existing unit. - **PlayerImpl**: _findUnitToUpgrade_: unchanged functionality, but have it call new private function _findExistingUnitToUpgrade_ to find existing unit. - **PlayerImpl**: _canBuild_: unchanged functionality, but have it call new private function _canBuildUnitType_ to do the checks it first did itself. And then new private function _canSpawnUnitType_ for the rest of the checks. This way we can call _canBuildUnitType_ and _canSpawnUnitType_ from _buildableUnits_ in a specific order to prevent double/triple checks. - **PlayerImpl**: _canBuildUnitType_: new private function to be shared by _buildableUnits_, _canBuild_ and _canUpgradeUnit_ to be able do unit type level checks in a specific order to prevent double/triple checks. Via parameter knownCost, _buildableUnits_ can send it the cost it already fetched so that it doesn't have to be fetched again. For caller _canUpgradeUnit_, the isAlive() check (which was previously only done in canBuild) is new but harmless, maybe even better to have also check isAlive() on upgrade now that Nations are also upgrading which might prevent some edge case bugs. - **PlayerImpl**: _canUpgradeUnitType_: new private function to be shared by _buildableUnits_ and _canUpgradeUnit_ to be able do unit type level checks in a specific order to prevent double/triple checks. - **PlayerImpl**: _canSpawnUnitType_: new private function to be shared by _buildableUnits_ and _canBuildUnit_ to be able do unit type level checks in a specific order to prevent double/triple checks. - **PlayerImpl**: _findExistingUnitToUpgrade_: new private function to be shared by _buildableUnits_ and _findUnitToUpgrade_ to be able do unit level checks in a specific order to prevent double/triple checks. - **PlayerImpl**: _isUnitValidToUpgrade_: new private function to be shared by _buildableUnits_ and _canUpgradeUnit_ to be able do unit level checks in a specific order to prevent double/triple checks. - **PlayerImpl.test.ts**: because of the isAlive() check in which is new for _canUpgradeUnit_ (see above at _canBuildUnitType_), the tests needed to have the players be alive at the start, in order to pass. - **BuildMenu**: use .find instead of .filter in canBuildOrUpgrade, a function we already needed to change. This is faster and prevents an allocation. **PERFORMANCE** As for calling ._buildables_ instead of unnecessarily getting ._actions_, there is an obvious win because there's less to send calculate and recieve. Also asking for only the needed buildings helps a lot (especially if TradeShip isn't needed, see the difference in benchmark in original #3193). But the real-world impact is hard to measure. gave it a try in #3193 and those results should be even better now. Now testing only _buildableUnits_ performance in a synthetic benchmark, we get these results. This is after other performance improvments so the base is already better than it was in original #3193: **BEFORE** (only buildableUnits itself) <img width="602" height="96" alt="image" src="https://github.com/user-attachments/assets/7770c0fa-a35e-42fc-90de-1de83242ec23" /> **AFTER** (only buildableUnits itself) <img width="603" height="91" alt="image" src="https://github.com/user-attachments/assets/a1578382-7010-4160-937c-7117bad18beb" /> ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: tryout33 --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> |
||
|
|
f09d9a3a5f |
Nations can overwhelm SAMs now 💥 (+ 3 little nation improvements) (#3246)
## Description: ### SAM Overwhelming (`NationNukeBehavior.ts`) On Impossible difficulty, nations can now destroy enemy SAMs by overwhelming them with coordinated atom bomb salvos. When no good nuke target is found (all trajectories intercepted by SAMs), the nations will: - Identify the easiest enemy SAM to destroy (lowest level first) - Calculate the total interception capacity of all covering SAMs and send enough bombs to overwhelm them (+1 extra per 5 needed to account for enemy building more SAMs during flight) - Plan launches in NukeExecution's Manhattan-distance silo order, tracking which silos have interceptable trajectories (wasted bombs) - Use a sliding window over parabolic flight times to find the best cluster of bombs that can arrive within half the SAM cooldown window - Compute per-bomb wait ticks to synchronize arrivals from silos at different distances - Skip launching if a salvo is already in flight - Upgrade the best SAM-protected silo when silo capacity is insufficient; wait and save gold when only gold is lacking https://github.com/user-attachments/assets/14fa592f-2902-4604-8e37-1eba2b2f0b85 ### 2-Player Endgame Handling (`NationNukeBehavior.ts`) - On Hard/Impossible with only 2 players remaining, `findBestNukeTarget()` directly targets the other player (bypasses all priority logic) - `getPerceivedNukeCost()` returns actual cost (no MIRV saving inflation) when only 2 players are left ### SAM Build Rate (`NationStructureBehavior.ts`) - Reduced SAM perceived cost increase per owned from 1.0 to 0.5, so nations build more SAMs ### Island Attack Variety (`AiAttackBehavior.ts`) - `findNearestIslandEnemy()` now collects up to 2 reachable candidates and has a 33% chance to pick the second-nearest, adding variety to boat attack targeting ## 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 |
||
|
|
4e62114ea0 |
Improve nations 🤖 (#3206)
## Description: - `AiAttackBehavior`: Because bots delete stolen structures now, nations prioritize attacking bots with structures - `NationMIRVBehavior`: Nations no longer MIRV enemies who already got MIRVed in the last 30 seconds. Some humans complained about getting double-MIRVed by nations. And in games with very high starting gold, ALL nations MIRVed the same player (stop steamroll logic). - `NationAllianceBehavior`: Fixes a comparison logic bug (Thanks to Deshack) - `NationNukeBehavior.ts`: Little atom bomb perceived cost balance change - `MIRVExecution`: To make sure the MIRVing nations are attacking the MIRVed nations (even if they don't share a border), the relation gets updated in both directions now. - `SinglePlayerModal` & `HostLobbyModal`: Update the default difficulty to "Medium" (to synchronize the defaults with the public game default) ## Please complete the following: - [X] I have added screenshots for all UI updates - [X] I process any text displayed to the user through translateText() and I've added it to the en.json file - [X] I have added relevant tests to the test directory - [X] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: FloPinguin |
||
|
|
f7d3c2e0bc |
Nations donate troops now 💀 (In team games) (#2984)
## Description: For v29, balances the HvN winrate. In team games, nations now donate troops to their weakest team members (if they have no attack options available). How often they donate depends on the difficulty. This PR also has some other little fixes: - For HvN games, always return true in `shouldAttack()` (make nations a bit more aggressive). - Early exit in `attackWithRandomBoat()` for performance - Early exit in `findNearestIslandEnemy()` for performance AND to make sure nations which are encircled by friends don't run into this method (=> no donation happening!) ## 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 |
||
|
|
18fb513326 |
Pathfinding refinements (#2959)
## Description: ### Short path for multi-source HPA* Math was not mathing, increased the bounds to 260x260, it is a bit slower but should work better. The short path was breaking when player owned a lot of shores. This is because the bounding box of tiles with less than 120 distance + 10 padding could be as big as 260x260 and the optimized array was set to 140x140. I made mistake of calculating it as `2 * (60 + 10)` instead of `2 * (120 + 10)`. ### LoS path refinement Previously, we ran 2 passes of LoS smoothing on the path. However, since we are effectively tracing the same path, the line of sight is essentially the same. This PR makes second line of sight stop on water tiles with magnitude `n + 1` compared to first path. Practically, this means it'll attempt LoS exactly 1 tile after previous corner. See screenshot. <img width="1299" height="1151" alt="image" src="https://github.com/user-attachments/assets/726be236-1ff8-406c-896a-02902a762ab0" /> ### SendBoatAttackIntentEvent The flow of sending transport ships is currently strange. This PR makes the flow more sane. **Old flow** ``` - Player clicks TARGET tile, it can be deep inland - Client asks Worker for the best START tile to TARGET tile - Worker answers `false`, since the tile is inland - Client sends BoatAttackIntent with START=false and TARGET tiles set - Worker accepts BoatAttackIntent, computes DESTINATION as closest shore to TARGET - Worker re-computes best START to DESTINATION - Worker sends boat from START to DESTINATION ``` **New flow** ``` - Player clicks TARGET tile, it can be deep inland - Client sends BoatAttackIntent with TARGET - Worker accepts BoatAttackIntent, computes DESTINATION as closest shore to TARGET - Worker computes START as the best tile to DESTINATION - Worker sends boat from START to DESTINATION ``` ## 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 |
||
|
|
96aa39a415 |
Improve nations 🤖 (#2817)
## Description: ### Refactor - Moved `maybeSpawnWarship()` from `NationExecution` to `NationWarshipBehavior` - Moved `maybeAttack()` (and sub-methods) from `NationExecution` to `AiAttackBehavior` ### Betrayal - Added nice betrayal logic in `maybeBetray()`. Previously that method was basically just a placeholder for a future implementation. ### Attacking - Added `veryWeak()` attack strategy for hard and impossible difficulty nations attack orders to target MIRVed players with higher priority - Optimized the `weakest()` attack strategy so that nations don't attack stronger players. This should make nation-attacks feel less random (humans complained in discord) - `findNearestIslandEnemy()` and `randomBoatTarget()` also no longer returns stronger players - `afk()` and `hated()` attack strategies no longer return MUCH stronger players - Several tiny refactorings, fixes and balance optimizations in `AiAttackBehavior` ### Emojis - Added some `canSendEmoji()` because I saw some "cannot send emoji" warnings in the console ## 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 |
||
|
|
f73953c240 |
☢️ Nations send much better nukes now (Part 2) ☢️ (#2779)
## Description: ### Refactor - Moved `findBestNukeTarget()` (and child methods) from `AiAttackBehavior` to `NationNukeBehavior` because it makes more sense. - `NationNukeBehavior`: Renamed `mg` to `game` (So its similar to the other nation .ts files) - Moved the `removeOldNukeEvents()` method a bit ### New features - Impossible difficulty nations are now optimized for SAM outranging! - 1 of 3 nations is now a hydro-nation. They cannot send atom bombs. They save up for hydros. This is to reduce atom-bomb-spam on the map. - On impossible difficulty, the crown nukes the second place now (in FFAs) - On hard and impossible difficulty, nations now ignore the perceived cost for nukes if they get heavily attacked. Reasoning: They should stop saving for MIRV, they should defend with all their gold! - On medium, hard and impossible difficulty, nations no longer throw nukes at places where another team member already has a nuke "in the flying process" - Optimized `lastNukeSent` a bit (to respect nuke radius) - Adjusted `maybeSendNuke()` to use 30 instead of 10 randomTiles on impossible difficulty to improve chances of finding a perfect SAM outranging spot - On impossible difficulty, nations now ignore their "most hated enemy" if the crown has 50%+ of the map (Very big danger). Instead they are nuking the crown. - Added `isFriendly` check to `findStrongestTeamTarget()` ### Media SAM outranging: https://github.com/user-attachments/assets/d1e88bb6-0060-400b-9c16-24d7399f5949 Team game nukes not hitting the same spot: <img width="1160" height="708" alt="Screenshot 2026-01-03 042236" src="https://github.com/user-attachments/assets/c017fb3c-3e3f-45fb-9d45-dd4caba7a59f" /> ## Please complete the following: - [X] I have added screenshots for all UI updates - [X] I process any text displayed to the user through translateText() and I've added it to the en.json file - [X] I have added relevant tests to the test directory - [X] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: FloPinguin --------- Co-authored-by: iamlewis <lewismmmm@gmail.com> |
||
|
|
23e4bf6725 |
☢️ Nations send much better nukes now (Part 1) ☢️ (#2756)
This is a very important PR for HumansVsNations (But also for
singleplayer).
Humans will throw lots of nukes onto nations, but nations didn't do
that. Until now :)
## Refactor
- Moved all the nuking logic to the new file `NationNukeBehavior.ts`
- Moved `randTerritoryTileArray()` and `randTerritoryTile()` to the new
file `NationUtils.ts` because we need that method in multiple places now
- Because we already have an `NationUtils.ts` (It contains the method
`createNationsForGame` for HumansVsNations) I renamed the old one to
`NationCreation.ts` to avoid confusion
## Bug fixed
- `allRelationsSorted()` in `PlayerImpl` returned dead players all the
time... Which caused nations to not attack / send nukes in some cases...
## Nuke-sending features / improvements
- On hard and impossible difficulty, nations no longer make sure that
nukes will only hit inside of their targets border. This logic very
often stopped nations from throwing nukes. Now their nukes are allowed
to hit TerraNullius (=> ocean!). And in team games, it's even allowed
that their nukes hit other non-friendly players as well! This is very
important for HumansVsNations.
- The basic check for SAMs now gets skipped if we are on easy difficulty
(easy nations are not smart enough to do that)
- I improved the basic check for SAMs (medium difficulty) a bit (nations
send less nukes into SAMs)
- On hard and impossible difficulty, we now use the new method
`isTrajectoryInterceptableBySam()` to avoid SAMs completely. It's
mirroring `NukeTrajectoryPreviewLayer.ts` logic a bit.
- I added "perceived cost" to simulate nations saving up for a MIRV
(Otherwise most hard/impossible nations will spend all their gold on
nukes). But if we are in a team game (MIRVs are not relevant) or if we
already saved up for a MIRV, the "perceived cost" gets ignored.
- Updated the "most hated player" selection in `findBestNukeTarget()` to
ignore very weak players. We don't need to throw nukes at players which
we can easily steamroll by land.
- Added `findFFACrownTarget()` to nuke the crown (based on difficulty).
- Added `findStrongestTeamTarget()` to nuke the strongest team.
- Updated `randTerritoryTile()` so that it has a higher chance of
returning the tiles of a
"leftover-nuked-to-death-player-with-some-tiles-left": `if
(p.numTilesOwned() <= 100) {return
random.randElement(Array.from(p.tiles()));}`.
- Changed `const range = nukeType === UnitType.HydrogenBomb ? 60 : 15`
to `config().nukeMagnitudes(nukeType).inner`. Should make more sense.
- Adjusted `nukeTileScore()` to search for units in
`this.mg.config().nukeMagnitudes(nukeType).inner` instead of fixed 25
- Adjusted `nukeTileScore()` to account for unit levels (levels got
ignored previously). Also increased score for ports from 10_000 to
15_000.
- I made sure that nations can nuke EVERY SINGLE TILE from an enemy,
even if the enemy has no structures ("Prefer tiles that are closer to a
silo" can no longer make the `nukeTileScore()` drop too much,
`bestValue` in `maybeSendNuke()` starts at -1 now)
- In the entire nuking logic, factories were missing. Now they are
added.
## Media
Nation team vs. nation team: They are nuking the very last pixels of
red, just like humans would do it 😀
<img width="915" height="683" alt="image"
src="https://github.com/user-attachments/assets/109c7921-b959-4aa9-a971-0d7742971686"
/>
Hard difficulty FFA game: Nations throwing much more nukes. And they are
nuking the crown.
https://github.com/user-attachments/assets/a6e43924-a6ca-4b1a-a578-4e4f8252e383
Lots of nukes flying:
https://github.com/user-attachments/assets/8fc4edad-a6e6-4476-8a86-08cdef58169e
## Please complete the following:
- [X] I have added screenshots for all UI updates
- [X] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [X] I have added relevant tests to the test directory
- [X] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
FloPinguin
---------
Co-authored-by: iamlewis <lewismmmm@gmail.com>
|
||
|
|
d321c08d92 |
Nations now gang up on players and prioritize traitors/AFK players 🤖 (+ other improvements) (#2730)
## Description: - **Nations now specifically target AFK players, traitors, and players who are already being attacked (they gang up on them).** Depends on the difficulty. - Added ally assistance directly to the attack order (instead of calling it separately beforehand). - Added ally assistance to `findBestNukeTarget`. - Removed some checks from `findBestNukeTarget` (not necessary; better checks will follow in a dedicated nuking PR). - Relation updates on attack now depend on difficulty (makes Easy & Medium nations a bit easier). - On betrayal, every nation in the game previously received a –40 relation penalty toward the betrayer. That was too extreme, so now this only applies only to neighbors. - Nations send fewer alliance requests now; it felt like too many before. - In team games, nations may now reject alliance requests more often (depending on difficulty). - To ensure there are enough non-friendly players to stop the crown with nukes, nations may now reject alliance requests if the other player has too many alliances (on Hard and Impossible difficulty). - Rebalanced nation emoji usage a bit. - Nations may now send an emoji when they get MIRVed. ## Please complete the following: - [X] I have added screenshots for all UI updates - [X] I process any text displayed to the user through translateText() and I've added it to the en.json file - [X] I have added relevant tests to the test directory - [X] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: FloPinguin --------- Co-authored-by: iamlewis <lewismmmm@gmail.com> |
||
|
|
5d52f73278 |
The clown is gone! 🤡 Nations send much better emojis now (#2696)
## Description: Previously, nations just spammed these two rather toxic emojis: 🤡😡 They now send fewer emojis while attacking, and the clown emoji is reserved for special cases. They got the ability to send emojis in much more cases: - Human didn't donate enough for relation update - Human did donate an ok amount - Human did donate a lot - Responding to emojis that they get sent from a human - Nuke sent - MIRV sent - Retaliation warship sent - Traitor tries to ally - Threat asks for / accepts an alliance request - Disliked human tries to ally - Friendly human tries to ally - They are getting attacked by very much troops - They are getting attacked by very little troops - Congratulating the winner - Bragging with their crown - Charming their allies - Clown-Emoting traitors - Easteregg: Sending a rat emoji to very small humans ## Please complete the following: - [X] I have added screenshots for all UI updates - [X] I process any text displayed to the user through translateText() and I've added it to the en.json file - [X] I have added relevant tests to the test directory - [X] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: FloPinguin --------- Co-authored-by: iamlewis <lewismmmm@gmail.com> |
||
|
|
6d2ac30526 |
Fix bots no longer attacking humans 🤖 (#2690)
## Description: A small number of people are complaining that bots no longer attack them and that "This has broken the factory farming strat". In the old #2550 I somehow added that bots on easy difficulty don't attack humans and nations anymore. And public games are on easy difficulty now. But I think the difficulty should actually only change nation behavior, not bot behavior. Their attacks are harmless anyways. So lets remove that little check. Also let `shouldAttack()` return true for bots. ## 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 |
||
|
|
6afaf932a5 |
Make easy and medium nations less aggressive 📊 (#2671)
## Description: 1. Players complained that they have problems allying with nations in the earlygame. So I added an `isEarlygame()` check to `AllianceBehavior`. This should make the easier difficulties much easier :) 2. The attack order of nations now depends on the difficulty. Easy and medium nations got dumbed down, they now take nuked territory before retaliating against attacks again. 3. The attack rate now depends on the difficulty. Easy nations are reacting slower than impossible nations (to make sure the number of sent alliance requests stays the same I removed the difficulty check in `maybeSendAllianceRequests()`). 4. On easy and medium difficulty nations will sometimes just skip an attack if the enemy is a human (`shouldAttack()`). But this did not apply for the nuking logic. Now it does, which makes the easier difficulties a bit easier. 5. I tuned the `getBotAttackMaxParallelism()` method a bit. The nations are doing a bit less parallel bot attacks now, which makes the easier difficulties a bit easier. 6. The settings in MIRVBehavior now depend on the difficulty. On easy difficulty, nations will only send MIRVs very rarely. 7. Unrelated MIRVBehavior Cleanup: There was a 2 second cooldown and cache logic. But it was completely useless because `considerMIRV()` is only called every 4-8 seconds by NationExecution. So I removed it. 8. Unrelated little cleanup: I made a couple of methods `private` ## 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 |
||
|
|
af1e05961c |
Cleanup nations (Part 2) 🧹 (#2647)
## Description: 1. Moved the currently very small betrayal logic from `AiAttackBehavior` to `NationAllianceBehavior` because it makes more sense to have it there. 3. Very small bugfix in `AiAttackBehavior::shouldAttack()`: the numbers in the two `random.chance` calls were the wrong way round. 4. `NationExecution` was quite big and a lot of it was about MIRVs. So I moved all the MIRV logic to the new `NationMIRVBehavior`. 5. `emoji()` and `maybeSendEmoji()` did not really fit in `AiAttackBehavior`. So I moved it to the new `NationEmojiBehavior` (and did some renaming for clarity). I'm planning to extend that class in a future PR. 2. Reordered methods in `AiAttackBehavior` to easily find related methods. 6. Reordered methods in `NationExecution` to easily find related methods. ## 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 |
||
|
|
4d5bb7a835 |
Cleanup nations (Part 1) 🧹 (#2637)
## Description: 1. Using the wording `"Nation"`, `"FakeHuman"` and `"NPC"` at the same time is confusing. So I renamed every mention of `"FakeHuman"` and `"NPC"` in the entire project to `"Nation"`. Just like they are called ingame. 2. `BotBehavior.ts` was originally intended for sharing the logic between nations and bots. But at the moment, the logic there isn't really shared and it's basically just about attacking. So I renamed `BotBehavior.ts` to `AiAttackBehavior.ts`. I use "Ai" to indicate that this file is used by bots AND nations. 3. Moved `execuction/utils/AllianceBehavior.ts` to `execuction/nation/NationAllianceBehavior.ts` to make sure everybody understands that this file is not about alliances in general. It's just about nations and how they handle alliances. 4. Removed `difficultyModifier` from `DefaultConfig`. It's unused and I think we usually want to finetune the difficulty instead of using that method. 5. Added `assertNever` in all `switch (difficulty)` default cases. ## 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 |