Add PVP immunity to 5M starting gold modifier games 🔧 (#3180)

## Description:

Adds 30 seconds of PVP immunity to 5M starting gold modifier games.
So you cannot insta-nuke other players.

Because I'm sure people would be confused "I cannot attack!!!!" I added
a HeadsUpMessage which informs about the PVP immunity.
We already have a ImmunityTimer progress bar but I don't think its
enough.

<img width="1270" height="745" alt="image"
src="https://github.com/user-attachments/assets/0ee23dc4-1c7b-4d62-8b3d-8de214f03c2b"
/>

I had a second count in the HeadsUpMessage (seconds until PVP immunity
is over) but it felt too busy. So I removed it. You can tell when PVP
immunity is over by looking at the progress bar.

## 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>
This commit is contained in:
FloPinguin
2026-02-12 10:57:18 -08:00
committed by GitHub
co-authored by Evan
parent f8c14398c8
commit 6cc0ef7d14
9 changed files with 45 additions and 9 deletions
+20 -1
View File
@@ -16,6 +16,9 @@ export class HeadsUpMessage extends LitElement implements Layer {
@state()
private isPaused = false;
@state()
private isImmunityActive = false;
@state()
private toastMessage: string | import("lit").TemplateResult | null = null;
@state()
@@ -79,7 +82,18 @@ export class HeadsUpMessage extends LitElement implements Layer {
this.isPaused = pauseUpdate.paused;
}
this.isVisible = this.game.inSpawnPhase() || this.isPaused;
const showImmunityHudDuration = 10 * 10;
const spawnEnd = this.game.config().numSpawnPhaseTurns();
const ticksSinceSpawnEnd = this.game.ticks() - spawnEnd;
this.isImmunityActive =
this.game.config().hasExtendedSpawnImmunity() &&
!this.game.inSpawnPhase() &&
this.game.isSpawnImmunityActive() &&
ticksSinceSpawnEnd < showImmunityHudDuration;
this.isVisible =
this.game.inSpawnPhase() || this.isPaused || this.isImmunityActive;
this.requestUpdate();
}
@@ -91,6 +105,11 @@ export class HeadsUpMessage extends LitElement implements Layer {
return translateText("heads_up_message.multiplayer_game_paused");
}
}
if (this.isImmunityActive) {
return translateText("heads_up_message.pvp_immunity_active", {
seconds: Math.round(this.game.config().spawnImmunityDuration() / 10),
});
}
return this.game.config().isRandomSpawn()
? translateText("heads_up_message.random_spawn")
: translateText("heads_up_message.choose_spawn");
+4 -1
View File
@@ -41,7 +41,10 @@ export class ImmunityTimer extends LitElement implements Layer {
const immunityDuration = this.game.config().spawnImmunityDuration();
const spawnPhaseTurns = this.game.config().numSpawnPhaseTurns();
if (immunityDuration <= 5 * 10 || this.game.inSpawnPhase()) {
if (
!this.game.config().hasExtendedSpawnImmunity() ||
this.game.inSpawnPhase()
) {
this.setInactive();
return;
}