Skip to content

Halloween Event#2285

Merged
evanpelle merged 3 commits intoopenfrontio:v26from
DevelopingTom:halloween_v26
Oct 25, 2025
Merged

Halloween Event#2285
evanpelle merged 3 commits intoopenfrontio:v26from
DevelopingTom:halloween_v26

Conversation

@DevelopingTom
Copy link
Contributor

Description:

Changed theme colors for an "autumn" ambiance:

image

Changed structures pixel art:

image

Change existing FX with new halloween-themed ones:

skull.mp4

Added new FX playing randomly on the map:

tentacle.mp4

Added a couple of new emojis, which are used by the bots when attacked:
👻🎃

Please complete the following:

  • I have added screenshots for all UI updates
  • I process any text displayed to the user through translateText() and I've added it to the en.json file
  • I have added relevant tests to the test directory
  • I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced

Please put your Discord username so you can be contacted if a bug or regression is found:

IngloriousTom

@DevelopingTom DevelopingTom requested a review from a team as a code owner October 24, 2025 22:55
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 24, 2025

Walkthrough

This PR swaps many sprite assets for Halloween-themed variants, adds four new FX types (Tentacle, Shark, Bubble, Tornado), implements MoveSpriteFx for moving sprite effects, and adds a randomized FX event generator in FxLayer. Also updates some emoji and pastel theme color values.

Changes

Cohort / File(s) Summary
Halloween Sprite Assets
src/client/graphics/AnimatedSpriteLoader.ts, src/client/graphics/SpriteLoader.ts
Replaced numerous sprite assets with Halloween-themed files (bats, ghost, skull*, pumpkin, minifireGreen, etc.) and updated animation metadata (frameWidth, frameCount, frameDuration, originX/Y) and sprite-to-unit mappings (AtomBomb → miniPumpkin, HydrogenBomb → pumpkin).
FX Types (enum)
src/client/graphics/fx/Fx.ts
Added Tentacle, Shark, Bubble, and Tornado members to the FxType enum.
Sprite FX & Movement
src/client/graphics/fx/SpriteFx.ts
Introduced new exported MoveSpriteFx class for linear movement of sprite FX; changed SpriteFx coordinates x and y from protected to public.
FxLayer: random events
src/client/graphics/layers/FxLayer.ts
Added lastRandomEvent and randomEventRate fields, early-return tick guard, per-tick counter, and randomEvent() method that spawns Shark/Bubble/Tornado/Tentacle or MiniSmoke effects (uses SpriteFx, MoveSpriteFx, FadeFx).
Conquest FX timing
src/client/graphics/fx/ConquestFx.ts
Removed explicit duration argument (2500) from the conquest SpriteFx constructor call.
Theme & Emoji
src/core/configuration/PastelTheme.ts, src/core/Util.ts, src/core/execution/utils/BotBehavior.ts
Adjusted shore/water/terrain colors; replaced several emoji entries in emojiTable; changed EMOJI_HECKLE from ["🤡","😡"] to ["👻","🎃"].

Sequence Diagram(s)

sequenceDiagram
    participant FxLayer
    participant RandomEvent
    participant SpriteFx
    participant MoveSpriteFx
    participant FadeFx

    FxLayer->>FxLayer: tick() ++lastRandomEvent
    alt lastRandomEvent > randomEventRate
        FxLayer->>RandomEvent: randomEvent()
        RandomEvent->>RandomEvent: pick randX, randY
        alt tile is ocean (not shoreline)
            RandomEvent->>SpriteFx: spawn Shark or Bubble (SpriteFx)
            RandomEvent->>MoveSpriteFx: spawn Tornado (MoveSpriteFx→SpriteFx) -> target coords
            RandomEvent->>FadeFx: spawn Tentacle (FadeFx→SpriteFx)
        else not ocean
            RandomEvent->>FadeFx: spawn MiniSmoke ghost (FadeFx→SpriteFx)
        end
        RandomEvent->>FxLayer: push FX into allFx
        FxLayer->>FxLayer: reset lastRandomEvent = 0
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Review MoveSpriteFx: interpolation math, lifecycle, and fade integration.
  • Inspect FxLayer.randomEvent(): bounds, ocean/shoreline detection, and FX choice distribution.
  • Verify Sprite/AnimatedSprite metadata (frame counts/durations/origins) for consistency and off-by-one errors.
  • Confirm public exposure of SpriteFx.x/y doesn't create unexpected mutation paths.

Possibly related PRs

Suggested labels

Feature - Frontend

Suggested reviewers

  • evanpelle
  • scottanderson

Poem

🎃 Green fire flickers, pumpkins grin so wide,
Ghosts and skulls in animated tide,
Sharks and tentacles cut through the foam,
Tornadoes carry sprites far from home,
Emojis wink — the spooky pixels ride. 👻

Pre-merge checks

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title "Halloween Event" is clear, concise, and directly reflects the main unifying theme of all changes in this pull request. The changeset includes Halloween-themed sprite replacements, new FX types with Halloween aesthetic, color adjustments for autumn ambiance, emoji updates (👻 🎃), and random animated effects throughout the map. The title accurately summarizes these primary changes without being vague or misleading, making it easy for teammates scanning the history to understand this is a Halloween event implementation.
Description Check ✅ Passed The description is well-organized and directly related to the changeset across all dimensions. It explains the key changes: theme color modifications for autumn ambiance (with screenshot), pixel art updates for structures (with screenshot), Halloween-themed FX replacements, new random map FX (with video evidence), and new bot heckle emojis. The author provides visual evidence, confirms checklist completion including translation work and testing, and identifies contact information. Every item mentioned in the description aligns with the code changes shown in the raw summary.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f823a27 and d1d5bc9.

📒 Files selected for processing (2)
  • src/client/graphics/AnimatedSpriteLoader.ts (5 hunks)
  • src/client/graphics/layers/FxLayer.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/client/graphics/layers/FxLayer.ts
🔇 Additional comments (2)
src/client/graphics/AnimatedSpriteLoader.ts (2)

8-17: Imports look good.

The Halloween sprite imports are well-organized in a dedicated subdirectory and follow consistent naming patterns.


144-179: New FX types look good.

The configurations for Tentacle, Shark, Bubble, and Tornado follow the established pattern and have appropriate looping behavior. Since these are new additions rather than replacements, they can remain in the codebase after the Halloween event if desired.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/client/graphics/SpriteLoader.ts (1)

157-166: Fix cache key: include theme’s spawn highlight color.

colorizeCanvas uses spawnHighlightColor, but computeSpriteKey omits it. After a theme swap, cached canvases can be wrong. Include it in the key.

- function computeSpriteKey(
-  unit: UnitView,
-  territoryColor: Colord,
-  borderColor: Colord,
- ): string {
+ function computeSpriteKey(
+  unit: UnitView,
+  territoryColor: Colord,
+  borderColor: Colord,
+  spawnHighlightColor: Colord,
+): string {
   const owner = unit.owner();
   const type = `${unit.type()}-${unit.trainType()}-${unit.isLoaded()}`;
-  const key = `${type}-${owner.id()}-${territoryColor.toRgbString()}-${borderColor.toRgbString()}`;
+  const key = `${type}-${owner.id()}-${territoryColor.toRgbString()}-${borderColor.toRgbString()}-${spawnHighlightColor.toRgbString()}`;
   return key;
 }
 
 export const getColoredSprite = (
   unit: UnitView,
   theme: Theme,
   customTerritoryColor?: Colord,
   customBorderColor?: Colord,
 ): HTMLCanvasElement => {
   const territoryColor: Colord =
     customTerritoryColor ?? unit.owner().territoryColor();
   const borderColor: Colord = customBorderColor ?? unit.owner().borderColor();
   const spawnHighlightColor = theme.spawnHighlightColor();
-  const key = computeSpriteKey(unit, territoryColor, borderColor);
+  const key = computeSpriteKey(unit, territoryColor, borderColor, spawnHighlightColor);

Also applies to: 168-197

src/client/graphics/layers/FxLayer.ts (1)

382-390: Await sprite preload in init() or errors/logging won’t behave.

Without await, try/catch won’t catch and “loaded successfully” logs too early.

   async init() {
     this.redraw();
     try {
-      this.animatedSpriteLoader.loadAllAnimatedSpriteImages();
-      console.log("FX sprites loaded successfully");
+      await this.animatedSpriteLoader.loadAllAnimatedSpriteImages();
+      console.log("FX sprites loaded successfully");
     } catch (err) {
       console.error("Failed to load FX sprites:", err);
     }
   }
src/client/graphics/AnimatedSpriteLoader.ts (1)

247-260: Fix colored animation cache key to avoid wrong-tinted sprites after theme change.

colorizeCanvas uses spawnHighlightColor, but the key is only fxType-owner. Include colors (or at least spawnHighlightColor).

-    const territoryColor = owner.territoryColor();
-    const borderColor = owner.borderColor();
-    const spawnHighlightColor = theme.spawnHighlightColor();
-    const key = `${fxType}-${owner.id()}`;
+    const territoryColor = owner.territoryColor();
+    const borderColor = owner.borderColor();
+    const spawnHighlightColor = theme.spawnHighlightColor();
+    const key = `${fxType}-${owner.id()}-${territoryColor.toRgbString()}-${borderColor.toRgbString()}-${spawnHighlightColor.toRgbString()}`;
🧹 Nitpick comments (2)
src/client/graphics/SpriteLoader.ts (1)

55-66: Optional: prefer Image.decode() for faster, cleaner preload.

decode() gives a promise and better error propagation. Keep onload/onerror as fallback for older browsers.

-        await new Promise<void>((resolve, reject) => {
-          img.onload = () => resolve();
-          img.onerror = (err) => reject(err);
-        });
+        if ('decode' in img) {
+          await (img as HTMLImageElement).decode();
+        } else {
+          await new Promise<void>((resolve, reject) => {
+            img.onload = () => resolve();
+            img.onerror = (err) => reject(err);
+          });
+        }
src/client/graphics/fx/SpriteFx.ts (1)

81-83: Keep position updates behind a method (composition-friendly).

Public fields work, but a setter is cleaner and safer. Consider adding setPosition(x, y) and reverting x/y to private in a follow-up.

// In SpriteFx
setPosition(x: number, y: number) {
  this.x = x;
  this.y = y;
}
// In MoveSpriteFx.renderTick:
this.fxToMove.setPosition(
  Math.floor(this.originX * (1 - t) + this.toX * t),
  Math.floor(this.originY * (1 - t) + this.toY * t),
);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4ed1076 and f823a27.

⛔ Files ignored due to path filters (19)
  • resources/images/buildings/cityAlt1.png is excluded by !**/*.png
  • resources/images/buildings/factoryAlt1.png is excluded by !**/*.png
  • resources/images/buildings/fortAlt3.png is excluded by !**/*.png
  • resources/images/buildings/port1.png is excluded by !**/*.png
  • resources/images/buildings/silo1.png is excluded by !**/*.png
  • resources/images/buildings/silo4.png is excluded by !**/*.png
  • resources/sprites/halloween/bats.png is excluded by !**/*.png
  • resources/sprites/halloween/bubble.png is excluded by !**/*.png
  • resources/sprites/halloween/ghost.png is excluded by !**/*.png
  • resources/sprites/halloween/miniPumpkin.png is excluded by !**/*.png
  • resources/sprites/halloween/minifireGreen.png is excluded by !**/*.png
  • resources/sprites/halloween/pumpkin.png is excluded by !**/*.png
  • resources/sprites/halloween/sam_explosion.png is excluded by !**/*.png
  • resources/sprites/halloween/shark.png is excluded by !**/*.png
  • resources/sprites/halloween/skull.png is excluded by !**/*.png
  • resources/sprites/halloween/skullNuke.png is excluded by !**/*.png
  • resources/sprites/halloween/smokeAndFireGreen.png is excluded by !**/*.png
  • resources/sprites/halloween/tentacle.png is excluded by !**/*.png
  • resources/sprites/halloween/tornado.png is excluded by !**/*.png
📒 Files selected for processing (9)
  • src/client/graphics/AnimatedSpriteLoader.ts (5 hunks)
  • src/client/graphics/SpriteLoader.ts (2 hunks)
  • src/client/graphics/fx/ConquestFx.ts (0 hunks)
  • src/client/graphics/fx/Fx.ts (1 hunks)
  • src/client/graphics/fx/SpriteFx.ts (2 hunks)
  • src/client/graphics/layers/FxLayer.ts (3 hunks)
  • src/core/Util.ts (1 hunks)
  • src/core/configuration/PastelTheme.ts (2 hunks)
  • src/core/execution/utils/BotBehavior.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • src/client/graphics/fx/ConquestFx.ts
🧰 Additional context used
🧬 Code graph analysis (2)
src/client/graphics/fx/SpriteFx.ts (1)
src/client/graphics/fx/Fx.ts (1)
  • Fx (1-3)
src/client/graphics/layers/FxLayer.ts (3)
src/client/graphics/layers/Layer.ts (1)
  • Layer (1-7)
src/core/game/GameView.ts (1)
  • ref (658-660)
src/client/graphics/fx/SpriteFx.ts (3)
  • SpriteFx (74-121)
  • MoveSpriteFx (25-49)
  • FadeFx (54-69)
🪛 GitHub Actions: 🧪 CI
src/client/graphics/AnimatedSpriteLoader.ts

[warning] 1-1: Code style issues found in the file. Run 'npx prettier --write' to fix.


[error] 1-1: Prettier formatting check failed. Run 'npx prettier --write' to fix code style issues in this file.

🔇 Additional comments (7)
src/core/configuration/PastelTheme.ts (1)

21-21: Color updates align with the autumn theme.

The new shore, water, and shorelineWater colors create the intended Halloween ambiance. The purple-toned water (80, 76, 179) and tan shore (223, 187, 132) fit the autumn aesthetic.

Also applies to: 29-30

src/core/Util.ts (2)

295-295: Halloween emojis added correctly.

The Halloween emojis 👻 and 🎃 are now in the emoji table and match the EMOJI_HECKLE update in BotBehavior.ts. The dynamic lookup using emojiId() will find these correctly.


292-292: No issues found with emoji value changes.

The codebase uses dynamic emoji lookup via indexOf() (in BotBehavior.ts) and loop-based iteration (in RadialMenuElements.ts), not hardcoded indices. The emoji values used in bot behavior (👍, ⛵, 🤝, 🎯, 🥱, 🤦‍♂️, 🥺, 💀, 🕊️, 👎, 👻, 🎃) are matched by content, not position. Changing the first row emojis does not break any functionality.

src/core/execution/utils/BotBehavior.ts (1)

23-23: Halloween emoji update looks good.

The EMOJI_HECKLE constant now uses Halloween-themed emojis. The dynamic lookup via emojiId() ensures the correct indices are found at runtime, and both 👻 and 🎃 exist in the updated emojiTable.

src/client/graphics/SpriteLoader.ts (1)

29-30: LGTM on Halloween sprite swap.

AtomBomb → miniPumpkin and HydrogenBomb → pumpkin mapping is clear and isolated. No API churn.

src/client/graphics/fx/Fx.ts (1)

19-22: Enum additions look good.

New FxType members are additive and consistent with loader configs.

src/client/graphics/AnimatedSpriteLoader.ts (1)

1-1: Verify formatting locally or check CI logs for specific Prettier failures.

I could not run Prettier in the sandbox environment because dependencies weren't installed. While prettier (3.5.3) and prettier-plugin-organize-imports (4.1.0) are defined in package.json, the sandbox lacks the npm install step.

The file AnimatedSpriteLoader.ts is visible, and imports appear organized (sprite paths grouped together, then framework imports). However, without successfully running Prettier, I cannot confirm the exact formatting violations or whether they've been resolved.

To verify:

  1. Run npm install locally (or in CI logs) and execute npx prettier --check src/client/graphics/AnimatedSpriteLoader.ts to see the actual violations
  2. Check your CI logs to confirm what Prettier reported
  3. Run npx prettier --write src/client/graphics/AnimatedSpriteLoader.ts to auto-fix if needed

coderabbitai[bot]
coderabbitai bot previously approved these changes Oct 24, 2025
@TheGiraffe3 TheGiraffe3 added this to the v26 milestone Oct 25, 2025
Copy link
Collaborator

@evanpelle evanpelle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks Great!

@evanpelle evanpelle merged commit b69adf7 into openfrontio:v26 Oct 25, 2025
9 of 10 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Oct 29, 2025
4 tasks
evanpelle added a commit that referenced this pull request Nov 4, 2025
@coderabbitai coderabbitai bot mentioned this pull request Nov 4, 2025
4 tasks
evanpelle added a commit that referenced this pull request Nov 11, 2025
evanpelle added a commit that referenced this pull request Nov 22, 2025
@coderabbitai coderabbitai bot mentioned this pull request Dec 30, 2025
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants