diff --git a/resources/images/buildings/cityAlt1.png b/resources/images/buildings/cityAlt1.png index 1975fd265..2f9c52d8b 100644 Binary files a/resources/images/buildings/cityAlt1.png and b/resources/images/buildings/cityAlt1.png differ diff --git a/resources/images/buildings/factoryAlt1.png b/resources/images/buildings/factoryAlt1.png index 40e82d8c9..d98e21291 100644 Binary files a/resources/images/buildings/factoryAlt1.png and b/resources/images/buildings/factoryAlt1.png differ diff --git a/resources/images/buildings/fortAlt3.png b/resources/images/buildings/fortAlt3.png index 8087a8998..4637bdd8f 100644 Binary files a/resources/images/buildings/fortAlt3.png and b/resources/images/buildings/fortAlt3.png differ diff --git a/resources/images/buildings/port1.png b/resources/images/buildings/port1.png index 4ac18d4fb..1a71f296b 100644 Binary files a/resources/images/buildings/port1.png and b/resources/images/buildings/port1.png differ diff --git a/resources/images/buildings/silo1.png b/resources/images/buildings/silo1.png index 89686639c..a68c5e5c9 100644 Binary files a/resources/images/buildings/silo1.png and b/resources/images/buildings/silo1.png differ diff --git a/resources/images/buildings/silo4.png b/resources/images/buildings/silo4.png index 8216f6b2f..b01f33adf 100644 Binary files a/resources/images/buildings/silo4.png and b/resources/images/buildings/silo4.png differ diff --git a/resources/sprites/halloween/bats.png b/resources/sprites/halloween/bats.png new file mode 100644 index 000000000..ff96f164b Binary files /dev/null and b/resources/sprites/halloween/bats.png differ diff --git a/resources/sprites/halloween/bubble.png b/resources/sprites/halloween/bubble.png new file mode 100644 index 000000000..b8d82112f Binary files /dev/null and b/resources/sprites/halloween/bubble.png differ diff --git a/resources/sprites/halloween/ghost.png b/resources/sprites/halloween/ghost.png new file mode 100644 index 000000000..15603066b Binary files /dev/null and b/resources/sprites/halloween/ghost.png differ diff --git a/resources/sprites/halloween/miniPumpkin.png b/resources/sprites/halloween/miniPumpkin.png new file mode 100644 index 000000000..33274a1ef Binary files /dev/null and b/resources/sprites/halloween/miniPumpkin.png differ diff --git a/resources/sprites/halloween/minifireGreen.png b/resources/sprites/halloween/minifireGreen.png new file mode 100644 index 000000000..8de5aa2ec Binary files /dev/null and b/resources/sprites/halloween/minifireGreen.png differ diff --git a/resources/sprites/halloween/pumpkin.png b/resources/sprites/halloween/pumpkin.png new file mode 100644 index 000000000..a6b772d41 Binary files /dev/null and b/resources/sprites/halloween/pumpkin.png differ diff --git a/resources/sprites/halloween/sam_explosion.png b/resources/sprites/halloween/sam_explosion.png new file mode 100644 index 000000000..f8ad56602 Binary files /dev/null and b/resources/sprites/halloween/sam_explosion.png differ diff --git a/resources/sprites/halloween/shark.png b/resources/sprites/halloween/shark.png new file mode 100644 index 000000000..2ce0a2275 Binary files /dev/null and b/resources/sprites/halloween/shark.png differ diff --git a/resources/sprites/halloween/skull.png b/resources/sprites/halloween/skull.png new file mode 100644 index 000000000..73d9ecacd Binary files /dev/null and b/resources/sprites/halloween/skull.png differ diff --git a/resources/sprites/halloween/skullNuke.png b/resources/sprites/halloween/skullNuke.png new file mode 100644 index 000000000..1a262ab83 Binary files /dev/null and b/resources/sprites/halloween/skullNuke.png differ diff --git a/resources/sprites/halloween/smokeAndFireGreen.png b/resources/sprites/halloween/smokeAndFireGreen.png new file mode 100644 index 000000000..641803e7d Binary files /dev/null and b/resources/sprites/halloween/smokeAndFireGreen.png differ diff --git a/resources/sprites/halloween/tentacle.png b/resources/sprites/halloween/tentacle.png new file mode 100644 index 000000000..9fb590a66 Binary files /dev/null and b/resources/sprites/halloween/tentacle.png differ diff --git a/resources/sprites/halloween/tornado.png b/resources/sprites/halloween/tornado.png new file mode 100644 index 000000000..ba51fc069 Binary files /dev/null and b/resources/sprites/halloween/tornado.png differ diff --git a/src/client/graphics/AnimatedSpriteLoader.ts b/src/client/graphics/AnimatedSpriteLoader.ts index 03e49e0cc..ab6fd5d8e 100644 --- a/src/client/graphics/AnimatedSpriteLoader.ts +++ b/src/client/graphics/AnimatedSpriteLoader.ts @@ -1,15 +1,21 @@ -import miniBigSmoke from "../../../resources/sprites/bigsmoke.png"; import buildingExplosion from "../../../resources/sprites/buildingExplosion.png"; -import conquestSword from "../../../resources/sprites/conquestSword.png"; import dust from "../../../resources/sprites/dust.png"; import miniExplosion from "../../../resources/sprites/miniExplosion.png"; -import miniFire from "../../../resources/sprites/minifire.png"; -import nuke from "../../../resources/sprites/nukeExplosion.png"; import SAMExplosion from "../../../resources/sprites/samExplosion.png"; import sinkingShip from "../../../resources/sprites/sinkingShip.png"; -import miniSmoke from "../../../resources/sprites/smoke.png"; -import miniSmokeAndFire from "../../../resources/sprites/smokeAndFire.png"; import unitExplosion from "../../../resources/sprites/unitExplosion.png"; + +import bats from "../../../resources/sprites/halloween/bats.png"; +import bubble from "../../../resources/sprites/halloween/bubble.png"; +import ghost from "../../../resources/sprites/halloween/ghost.png"; +import minifireGreen from "../../../resources/sprites/halloween/minifireGreen.png"; +import shark from "../../../resources/sprites/halloween/shark.png"; +import skull from "../../../resources/sprites/halloween/skull.png"; +import skullNuke from "../../../resources/sprites/halloween/skullNuke.png"; +import miniSmokeAndFireGreen from "../../../resources/sprites/halloween/smokeAndFireGreen.png"; +import tentacle from "../../../resources/sprites/halloween/tentacle.png"; +import tornado from "../../../resources/sprites/halloween/tornado.png"; + import { Theme } from "../../core/configuration/Config"; import { PlayerView } from "../../core/game/GameView"; import { AnimatedSprite } from "./AnimatedSprite"; @@ -28,7 +34,7 @@ type AnimatedSpriteConfig = { const ANIMATED_SPRITE_CONFIG: Partial> = { [FxType.MiniFire]: { - url: miniFire, + url: minifireGreen, frameWidth: 7, frameCount: 6, frameDuration: 100, @@ -37,28 +43,28 @@ const ANIMATED_SPRITE_CONFIG: Partial> = { originY: 11, }, [FxType.MiniSmoke]: { - url: miniSmoke, - frameWidth: 11, - frameCount: 4, - frameDuration: 120, + url: ghost, + frameWidth: 10, + frameCount: 5, + frameDuration: 100, looping: true, - originX: 2, + originX: 4, originY: 10, }, [FxType.MiniBigSmoke]: { - url: miniBigSmoke, - frameWidth: 24, - frameCount: 5, + url: bats, + frameWidth: 21, + frameCount: 6, frameDuration: 120, looping: true, originX: 9, originY: 14, }, [FxType.MiniSmokeAndFire]: { - url: miniSmokeAndFire, + url: miniSmokeAndFireGreen, frameWidth: 24, frameCount: 5, - frameDuration: 120, + frameDuration: 90, looping: true, originX: 9, originY: 14, @@ -90,15 +96,6 @@ const ANIMATED_SPRITE_CONFIG: Partial> = { originX: 9, originY: 9, }, - [FxType.BuildingExplosion]: { - url: buildingExplosion, - frameWidth: 17, - frameCount: 10, - frameDuration: 70, - looping: false, - originX: 8, - originY: 8, - }, [FxType.SinkingShip]: { url: sinkingShip, frameWidth: 16, @@ -108,14 +105,23 @@ const ANIMATED_SPRITE_CONFIG: Partial> = { originX: 7, originY: 7, }, - [FxType.Nuke]: { - url: nuke, - frameWidth: 60, - frameCount: 9, + [FxType.BuildingExplosion]: { + url: buildingExplosion, + frameWidth: 17, + frameCount: 10, frameDuration: 70, looping: false, - originX: 30, - originY: 30, + originX: 8, + originY: 8, + }, + [FxType.Nuke]: { + url: skullNuke, + frameWidth: 42, + frameCount: 19, + frameDuration: 50, + looping: false, + originX: 20, + originY: 21, }, [FxType.SAMExplosion]: { url: SAMExplosion, @@ -127,16 +133,51 @@ const ANIMATED_SPRITE_CONFIG: Partial> = { originY: 19, }, [FxType.Conquest]: { - url: conquestSword, - frameWidth: 21, - frameCount: 10, + url: skull, + frameWidth: 14, + frameCount: 14, frameDuration: 90, looping: false, - originX: 10, - originY: 16, + originX: 7, + originY: 23, + }, + [FxType.Tentacle]: { + url: tentacle, + frameWidth: 22, + frameCount: 26, + frameDuration: 90, + looping: false, + originX: 13, + originY: 28, + }, + [FxType.Shark]: { + url: shark, + frameWidth: 25, + frameCount: 14, + frameDuration: 90, + looping: false, + originX: 13, + originY: 8, + }, + [FxType.Bubble]: { + url: bubble, + frameWidth: 22, + frameCount: 13, + frameDuration: 80, + looping: false, + originX: 13, + originY: 8, + }, + [FxType.Tornado]: { + url: tornado, + frameWidth: 30, + frameCount: 10, + frameDuration: 80, + looping: true, + originX: 11, + originY: 22, }, }; - export class AnimatedSpriteLoader { private animatedSpriteImageMap: Map = new Map(); // Do not color the same sprite twice diff --git a/src/client/graphics/SpriteLoader.ts b/src/client/graphics/SpriteLoader.ts index 29d5b7791..fdc3a3c14 100644 --- a/src/client/graphics/SpriteLoader.ts +++ b/src/client/graphics/SpriteLoader.ts @@ -1,6 +1,6 @@ import { Colord } from "colord"; -import atomBombSprite from "../../../resources/sprites/atombomb.png"; -import hydrogenBombSprite from "../../../resources/sprites/hydrogenbomb.png"; +import miniPumpkin from "../../../resources/sprites/halloween/miniPumpkin.png"; +import pumpkin from "../../../resources/sprites/halloween/pumpkin.png"; import mirvSprite from "../../../resources/sprites/mirv2.png"; import samMissileSprite from "../../../resources/sprites/samMissile.png"; import tradeShipSprite from "../../../resources/sprites/tradeship.png"; @@ -26,8 +26,8 @@ const SPRITE_CONFIG: Partial> = { [UnitType.TransportShip]: transportShipSprite, [UnitType.Warship]: warshipSprite, [UnitType.SAMMissile]: samMissileSprite, - [UnitType.AtomBomb]: atomBombSprite, - [UnitType.HydrogenBomb]: hydrogenBombSprite, + [UnitType.AtomBomb]: miniPumpkin, + [UnitType.HydrogenBomb]: pumpkin, [UnitType.TradeShip]: tradeShipSprite, [UnitType.MIRV]: mirvSprite, [TrainTypeSprite.Engine]: trainEngineSprite, diff --git a/src/client/graphics/fx/ConquestFx.ts b/src/client/graphics/fx/ConquestFx.ts index 7fa8d0690..2c3f50413 100644 --- a/src/client/graphics/fx/ConquestFx.ts +++ b/src/client/graphics/fx/ConquestFx.ts @@ -26,7 +26,6 @@ export function conquestFxFactory( x, y, FxType.Conquest, - 2500, ); const fadeAnimation = new FadeFx(swordAnimation, 0.1, 0.6); conquestFx.push(fadeAnimation); diff --git a/src/client/graphics/fx/Fx.ts b/src/client/graphics/fx/Fx.ts index d4b206614..fa843de81 100644 --- a/src/client/graphics/fx/Fx.ts +++ b/src/client/graphics/fx/Fx.ts @@ -16,4 +16,8 @@ export enum FxType { UnderConstruction = "UnderConstruction", Dust = "Dust", Conquest = "Conquest", + Tentacle = "Tentacle", + Shark = "Shark", + Bubble = "Bubble", + Tornado = "Tornado", } diff --git a/src/client/graphics/fx/SpriteFx.ts b/src/client/graphics/fx/SpriteFx.ts index 2926121a8..ebe8d410c 100644 --- a/src/client/graphics/fx/SpriteFx.ts +++ b/src/client/graphics/fx/SpriteFx.ts @@ -19,6 +19,35 @@ function fadeInOut( return 1 - f * f; } } +/** + * Move a sprite around + */ +export class MoveSpriteFx implements Fx { + private originX: number; + private originY: number; + constructor( + private fxToMove: SpriteFx, + private toX: number, + private toY: number, + private fadeIn: number = 0.1, + private fadeOut: number = 0.9, + ) { + this.originX = fxToMove.x; + this.originY = fxToMove.y; + } + + renderTick(duration: number, ctx: CanvasRenderingContext2D): boolean { + const t = this.fxToMove.getElapsedTime() / this.fxToMove.getDuration(); + this.fxToMove.x = Math.floor(this.originX * (1 - t) + this.toX * t); + this.fxToMove.y = Math.floor(this.originY * (1 - t) + this.toY * t); + ctx.save(); + ctx.globalAlpha = fadeInOut(t, this.fadeIn, this.fadeOut); + const result = this.fxToMove.renderTick(duration, ctx); + ctx.restore(); + return result; + } +} + /** * Fade in/out another FX */ @@ -49,8 +78,8 @@ export class SpriteFx implements Fx { protected waitToTheEnd = false; constructor( animatedSpriteLoader: AnimatedSpriteLoader, - protected x: number, - protected y: number, + public x: number, + public y: number, fxType: FxType, duration?: number, owner?: PlayerView, diff --git a/src/client/graphics/layers/FxLayer.ts b/src/client/graphics/layers/FxLayer.ts index e5ddf3831..94a9c1040 100644 --- a/src/client/graphics/layers/FxLayer.ts +++ b/src/client/graphics/layers/FxLayer.ts @@ -13,7 +13,7 @@ import { AnimatedSpriteLoader } from "../AnimatedSpriteLoader"; import { conquestFxFactory } from "../fx/ConquestFx"; import { Fx, FxType } from "../fx/Fx"; import { nukeFxFactory, ShockwaveFx } from "../fx/NukeFx"; -import { SpriteFx } from "../fx/SpriteFx"; +import { FadeFx, MoveSpriteFx, SpriteFx } from "../fx/SpriteFx"; import { TargetFx } from "../fx/TargetFx"; import { TextFx } from "../fx/TextFx"; import { UnitExplosionFx } from "../fx/UnitExplosionFx"; @@ -21,6 +21,8 @@ import { Layer } from "./Layer"; export class FxLayer implements Layer { private canvas: HTMLCanvasElement; private context: CanvasRenderingContext2D; + private lastRandomEvent: number = 0; + private randomEventRate: number = 8; private lastRefresh: number = 0; private refreshRate: number = 10; @@ -40,6 +42,14 @@ export class FxLayer implements Layer { } tick() { + if (!this.game.config().userSettings()?.fxLayer()) { + return; + } + this.lastRandomEvent += 1; + if (this.lastRandomEvent > this.randomEventRate) { + this.lastRandomEvent = 0; + this.randomEvent(); + } this.manageBoatTargetFx(); this.game .updatesSinceLastTick() @@ -116,6 +126,72 @@ export class FxLayer implements Layer { this.allFx.push(textFx); } + randomEvent() { + const randX = Math.floor(Math.random() * this.game.width()); + const randY = Math.floor(Math.random() * this.game.height()); + const ref = this.game.ref(randX, randY); + if (this.game.isOcean(ref) && !this.game.isShoreline(ref)) { + const animation = Math.floor(Math.random() * 4); + if (animation === 0) { + const fx = new SpriteFx( + this.animatedSpriteLoader, + randX, + randY, + FxType.Shark, + ); + this.allFx.push(fx); + } else if (animation === 1) { + const fx = new SpriteFx( + this.animatedSpriteLoader, + randX, + randY, + FxType.Bubble, + ); + this.allFx.push(fx); + } else if (animation === 2) { + const fx = new MoveSpriteFx( + new SpriteFx( + this.animatedSpriteLoader, + randX, + randY, + FxType.Tornado, + 6000, + ), + randX - 40, + randY, + 0.1, + 0.8, + ); + this.allFx.push(fx); + } else if (animation === 3) { + const fx = new FadeFx( + new SpriteFx( + this.animatedSpriteLoader, + randX, + randY, + FxType.Tentacle, + ), + 0.1, + 0.8, + ); + this.allFx.push(fx); + } + } else { + const ghost = new FadeFx( + new SpriteFx( + this.animatedSpriteLoader, + randX, + randY, + FxType.MiniSmoke, + 4000, + ), + 0.1, + 0.8, + ); + this.allFx.push(ghost); + } + } + onUnitEvent(unit: UnitView) { switch (unit.type()) { case UnitType.TransportShip: { diff --git a/src/core/Util.ts b/src/core/Util.ts index c5cbe044e..41bac4163 100644 --- a/src/core/Util.ts +++ b/src/core/Util.ts @@ -289,17 +289,17 @@ export function createRandomName( } export const emojiTable = [ - ["😀", "😊", "🥰", "😇", "😎"], + ["😀", "😊", "😇", "😎", "😈"], ["😞", "🥺", "😭", "😱", "😡"], - ["😈", "🤡", "🖕", "🥱", "🤦‍♂️"], - ["👋", "👏", "🤌", "💪", "🫡"], + ["⏳", "🥱", "🤦‍♂️", "🖕", "🤡"], + ["👋", "👏", "👻", "💪", "🎃"], ["👍", "👎", "❓", "🐔", "🐀"], - ["🤝", "🆘", "🕊️", "🏳️", "⏳"], + ["🆘", "🤝", "🕊️", "🏳️", "🛡️"], ["🔥", "💥", "💀", "☢️", "⚠️"], ["↖️", "⬆️", "↗️", "👑", "🥇"], ["⬅️", "🎯", "➡️", "🥈", "🥉"], ["↙️", "⬇️", "↘️", "❤️", "💔"], - ["💰", "⚓", "⛵", "🏡", "🛡️"], + ["💰", "🏭", "🚂", "⚓", "⛵"], ] as const; // 2d to 1d array export const flattenedEmojiTable = emojiTable.flat(); diff --git a/src/core/configuration/PastelTheme.ts b/src/core/configuration/PastelTheme.ts index d40509e1c..5664c41bb 100644 --- a/src/core/configuration/PastelTheme.ts +++ b/src/core/configuration/PastelTheme.ts @@ -18,7 +18,7 @@ export class PastelTheme implements Theme { private nationColorAllocator = new ColorAllocator(nationColors, nationColors); private background = colord({ r: 60, g: 60, b: 60 }); - private shore = colord({ r: 204, g: 203, b: 158 }); + private shore = colord({ r: 223, g: 187, b: 132 }); private falloutColors = [ colord({ r: 120, g: 255, b: 71 }), // Original color colord({ r: 130, g: 255, b: 85 }), // Slightly lighter @@ -26,8 +26,8 @@ export class PastelTheme implements Theme { colord({ r: 125, g: 255, b: 75 }), // Warmer tint colord({ r: 115, g: 250, b: 68 }), // Cooler tint ]; - private water = colord({ r: 70, g: 132, b: 180 }); - private shorelineWater = colord({ r: 100, g: 143, b: 255 }); + private water = colord({ r: 80, g: 76, b: 179 }); + private shorelineWater = colord({ r: 100, g: 110, b: 255 }); private _selfColor = colord({ r: 0, g: 255, b: 0 }); private _allyColor = colord({ r: 255, g: 255, b: 0 }); @@ -97,15 +97,15 @@ export class PastelTheme implements Theme { } case TerrainType.Plains: return colord({ - r: 190, - g: 220 - 2 * mag, - b: 138, + r: 216, + g: 205 - 2 * mag, + b: 127, }); case TerrainType.Highland: return colord({ - r: 200 + 2 * mag, - g: 183 + 2 * mag, - b: 138 + 2 * mag, + r: 223 + 2 * mag, + g: 187 + 2 * mag, + b: 132 + 2 * mag, }); case TerrainType.Mountain: return colord({ diff --git a/src/core/execution/utils/BotBehavior.ts b/src/core/execution/utils/BotBehavior.ts index 868d55f74..2b914db6a 100644 --- a/src/core/execution/utils/BotBehavior.ts +++ b/src/core/execution/utils/BotBehavior.ts @@ -20,7 +20,7 @@ const EMOJI_ASSIST_ACCEPT = (["👍", "⛵", "🤝", "🎯"] as const).map(emoji const EMOJI_RELATION_TOO_LOW = (["🥱", "🤦‍♂️"] as const).map(emojiId); const EMOJI_TARGET_ME = (["🥺", "💀"] as const).map(emojiId); const EMOJI_TARGET_ALLY = (["🕊️", "👎"] as const).map(emojiId); -export const EMOJI_HECKLE = (["🤡", "😡"] as const).map(emojiId); +export const EMOJI_HECKLE = (["👻", "🎃"] as const).map(emojiId); export class BotBehavior { private enemy: Player | null = null;