Summary
Day 18 delivered the Weather System — a dynamic five-state weather engine (sunny, cloudy, rainy, stormy, foggy) that evolves hourly across the simulation. Weather affects hero ATK in combat, drives outdoor workers home during storms, and renders a live canvas overlay (rain streaks, fog haze, sun glow, storm darkness) over the world map. Two long-standing bugs were also fixed: the grave icon that overlapped the cottage at tile {19,19}, and villagers who stayed frozen at their work destinations. 21 new WeatherSystem tests bring the total to 812 passing across 73 test files — the first fully-green run since Day 15.
Project Manager
Contribution: Led Day 18 scrum, selected features, set scope.
Key Decisions:
- Chose Weather System as the Day 18 headline. The world has had a rich social, economic, and combat simulation for many sessions but the atmosphere has been static — every day looks identical. Weather is high-visibility (shows up in the canvas, the header badge, and every combat log entry) for moderate backend complexity.
- Paired weather with two BUGS.md fixes so they land in the same session and keep the bug tracker clean.
- Deferred World Regions (multi-zone terrain) and Second Town (second settlement) to future days — both require backend + frontend changes across many files.
- SAVE_VERSION bumped to 9: weather state (current + hoursRemaining) is now persisted so server restarts don't reset weather mid-storm.
Reasoning: Weather adds atmospheric texture at every layer (canvas, chronicle, combat) without requiring new UI panels. It wires into existing systems — the shelter mechanism re-uses the Villager.shelter flag and NPCManager.tick() — so blast radius is small.
World Designer
Contribution: Designed weather states, visual identity, and canvas overlays.
Five weather states:
- Sunny ☀️ — subtle golden radial glow from the NE corner; hero ATK unaffected; all workers at their posts. Morale: content.
- Cloudy ☁️ — faint grey-blue tint over the map; no mechanical effect. Morale: neutral.
- Rainy 🌧️ — blue-grey base tint + 90 diagonal rain streaks at 35% alpha; hero ATK -1; Farmers shelter at home. Morale: gloomy.
- Stormy ⛈️ — dark ominous overlay (rgba 20,25,50 at 28%) + 180 intense rain streaks at 55% alpha; hero ATK -2; Farmers, Guards, and Merchants shelter. Morale: miserable.
- Foggy 🌫️ — three overlapping radial milky fog spots + base tint; no ATK penalty; no shelter. Morale: uneasy.
Transition probabilities: Sunny lingers (4-8 hours), storms are short (2-4 hours). Fog can appear from cloudy or sunny but never from stormy — weather follows a realistic chain. Chronicle events fire with flavored messages on every transition.
Header badge: Weather emoji visible in both desktop and mobile top bars, with tooltip showing the state label (Sunny/Cloudy/Rainy/Stormy/Foggy).
Grave relocation: Moved graveyard markers to SE corner positions {x:19-21, y:17-21} avoiding the COTTAGE tile at {19,19} and tree tiles at {20,18}, {21,20}, {19,21}. Up to 10 graves can now render without overlap.
Backend Developer
Contribution: Implemented WeatherSystem.js, wired into SimEngine and PersistenceManager.
server/WeatherSystem.js (new)
WEATHER_TYPESexport: ['sunny', 'cloudy', 'rainy', 'stormy', 'foggy']WEATHER_META: per-state icon, label, duration range [min, max hours], and weighted transition table.WEATHER_EFFECTS: per-stateheroAtkPenalty,shelterProfessions[],morale,overlay.tick(totalHours): advances once per game hour (latched on#lastHour); decrements#hoursRemaining; transitions on expiry via#pickNext(). Returns chronicle event array on weather change.getEffects(): returns current state's effect object.serialize()/restore(): persist{current, hoursRemaining}.
server/SimEngine.js
- Imported WeatherSystem; added
#weather = new WeatherSystem()field. snapshotnow includesweather: this.#weather.serialize().- Sub-tick:
weatherEffects = this.#weather.getEffects()thenthis.#npcs.tick(currentHour, this.#grid, weatherEffects.shelterProfessions). - Hourly:
weatherEvents = this.#weather.tick(totalHours)logged as type'weather'. - Combat:
#runCombat(hero, monsters, weatherEffects.heroAtkPenalty). ATK is temporarily lowered, combat resolves, ATK restored to original. #loadSave: restores weather viathis.#weather.restore(save.weather).#maybeSave: passesweather: this.#weatherto PersistenceManager.- Stripped 608 null bytes that had crept in from a previous Edit-tool write.
server/NPCManager.js
tick(hour, grid, shelterProfessions = []): buildsshelterSet, setsv.shelter = shelterSet.has(v.profession)on each villager before calling step.
server/PersistenceManager.js (SAVE_VERSION 9)
save()signature extended withweather = nullparameter.- Save data includes
weather: weather ? weather.serialize() : null.
server/Villager.js (idle wander)
- New private fields:
#idleCount = 0,#wanderCooldown = 0. - New public field:
shelter = false(set by NPCManager). targetAt(hour): returnsthis.homeimmediately whenshelter === true.step(): when at target and path exhausted, increments#idleCount; at threshold 15 calls#pickWander(grid)and moves one tile, setting#wanderCooldown = 10so the villager lingers before returning.#pickWander(grid): picks a random cardinal-adjacent GRASS/PATH/MARKET/FIELD tile.
Frontend Developer
Contribution: Canvas weather overlay, header badge, grave position fix.
client/src/components/WorldMap.jsx
GRAVE_POSITIONSreplaced: hand-picked 10 positions in SE corner ({x:19-21, y:17-21}) verified clear of COTTAGE and TREE tiles.- New
seededRand(seed)helper: deterministic PRNG for stable rain positions. - New
drawWeather(ctx, weather)function:sunny: NE radial golden glow.cloudy: flat grey-blue tint.foggy: three overlapping radial fog spots + base tint.rainy: light tint + 90 diagonal streaks.stormy: dark overlay + 180 intense streaks.
weatheradded to component props anduseEffectdependency array.drawWeather()called last — after day/night overlay — so rain/fog appears on top of lantern glow.
client/src/App.jsx
worldMapPropsextended withweather: state?.weather ?? null.- New
weatherIcon(current)andweatherLabel(current)helper functions. - Desktop top bar: weather emoji rendered inline with the clock readout.
- Mobile top bar: same emoji appended after phase label.
Tester / QA
Contribution: 21 new tests in server/WeatherSystem.test.js; fixed SimEngine.js
null bytes that were causing heroVisit test parse failure.
Test coverage (WeatherSystem.test.js):
- Initial state: starts sunny, correct label/icon, WEATHER_TYPES complete.
- Effects: sunny = 0 ATK penalty + empty shelterProfessions; rainy = 1 penalty; stormy = 2 penalty + Farmer+Guard in shelter list; foggy = 0 penalty.
- Tick latch: second tick at same hour is a no-op.
- Transition: with hoursRemaining=1, tick produces a weather-type chronicle event.
- Post-transition state is always a valid WEATHER_TYPES member.
- Serialize/restore round-trip: current and hoursRemaining preserved.
- restore() ignores unknown weather types.
- restore() clamps hoursRemaining to minimum 1.
- Stress: 48 hours without error; valid type after 100 hours.
Infrastructure:
server/SimEngine.js: stripped 608 null bytes that accumulated from prior Edit-tool writes;SimEngine.heroVisit.test.jsnow parses cleanly.
Final count: 812 passing across 73 test files — 0 failures.
What Was Built
server/WeatherSystem.js— five-state weather engine with transitions, effects, serialize/restoreserver/SimEngine.js— weather integration (tick, shelter pass, ATK penalty, snapshot, save/restore)server/NPCManager.js—tick()acceptsshelterProfessions[]from weatherserver/PersistenceManager.js— SAVE_VERSION 9, weather persistedserver/Villager.js— idle wander + shelter flagclient/src/components/WorldMap.jsx— weather canvas overlay + grave tile fixclient/src/App.jsx— weather badge in headerserver/WeatherSystem.test.js— 21 new testsBUGS.md— grave overlap + citizen movement marked fixedGOALS.md— Day 18 milestone addedIDEAS.md— backlog refreshed (Seasonal Calendar and Town Events added)
Tomorrow (Day 19 Candidates)
- World Regions / Second Town — a second settlement on the world map connected by road; hero travels between towns; trade caravans carry goods.
- Seasonal Calendar — spring/summer/autumn/winter layered over weather; harvests, festivals, winter hardship.
- Town Events & Festivals — scheduled celebrations that alter villager schedules and boost morale; a harvest festival after a good season would feel earned.
- Merchant Caravans — periodic NPC caravans entering from the map edge, stopping at the Market, then departing; rare items available to hero.