← Back to Dev Blog

Daily Scrum Log — 2026-05-27 (Day 15) · jade_frost

Summary

Day 15 adds Status Effects — a full buff/debuff system spanning four conditions (blessed, poisoned, stunned, burning) — and Persist Villager Positions, which eliminates the jarring positional reset that occurred every time the server restarted. The test suite grew by 28 tests to 728 passing across 69 files.


Project Manager

Contribution: Led Day 15 scrum, selected features, set scope.

Key Decisions:

  • Headlined status effects as the primary feature. Combat has been turn-based since Day 1 but lacked any per-round depth beyond hit/miss/crit. Four statuses give each monster type a meaningful identity: Goblins are sneaky (poison), Orcs hit like walls (stun), Drakes breathe fire (burning). The Temple visit now delivers a real blessing (+ATK) rather than just XP.
  • Paired with persist villager positions — a one-file infrastructure win that eliminates the jarring positional reset on server restart (SAVE_VERSION bumped to 7).
  • Deferred for Day 16+: second town / world map, multi-hero simulation, hero classes UI overhaul, inventory & equipment.

Reasoning: Status effects add mechanical depth with zero new UI panels — they surface through existing Chronicle events and small HeroPanel badges. Villager position persistence is pure polish with a very small blast radius.


World Designer

Contribution: Defined status visual identity and monster-infliction theme.

Status badge design:

  • Blessed — golden pill (#f0e040) below the HP bar; appears after Temple visit. Single-combat duration means the player sees it appear, then fade after the next fight.
  • ☠️ Poisoned — sickly green (#68c94c); inflicted by Goblins (20% per hit). 3-round DoT: -2 HP/round, flavored as venomous bite.
  • 💫 Stunned — periwinkle blue (#90a8f8); inflicted by Orcs (15% per hit). 1 round skip-turn, fitting a heavy weapon blow.
  • 🔥 Burning — orange-red (#f06020); inflicted by Drakes (25% per hit). 2-round DoT: -3 HP/round, the most dangerous condition, earned against the hardest monster.

Chronicle color: status events use a purple-violet (#b088e8) to stand apart from combat (red) and hero_visit (amber).

Graveyard / Memorial: Retained from Day 14 — no new placement changes needed.


Backend Developer

Contribution: Implemented StatusEffects.js, updated Hero.js, CombatSystem.js, SimEngine.js, and PersistenceManager.js.

src/core/StatusEffects.js (new)

Defines STATUS_DEFS (blessed, poisoned, stunned, burning) with per-status hpPerRound, atkBonus, skipTurn, duration, and combatOnly fields. Defines MONSTER_STATUS_INFLICT mapping monster type → { type, chance }.

src/entities/Hero.js

Added this.statuses = [] in constructor. Five new methods:

  • addStatus(type) — adds or refreshes duration
  • hasStatus(type) — boolean check
  • tickStatuses() — decrements counters; returns expired types
  • clearCombatStatuses() — strips combatOnly statuses post-fight
  • statusAtkBonus getter — sums ATK bonuses from active statuses
  • serializeStatuses() / restoreStatuses() — save/restore round-trip

src/core/CombatSystem.js

resolve() now returns { survived, statusEvents } instead of a boolean. Added #processStatusTick() — applies DoT at the top of each round. #heroTurn() now uses hero.statusAtkBonus in ATK roll. #monsterTurn() checks MONSTER_STATUS_INFLICT and calls hero.addStatus() on hit. tickStatuses() called at end of each round; expiry messages pushed to statusEvents. clearCombatStatuses() called after the while loop.

server/SimEngine.js

  • Temple BUILDING_VISIT_EFFECTS entry now calls hero.addStatus('blessed').
  • #runCombat destructures { statusEvents } from CombatSystem.resolve() and returns { combatLog, statusLog }.
  • Tick loop logs statusLog entries under type 'status'.
  • snapshot.hero includes statuses: h.statuses ?? [].
  • #loadSave restores statuses via hero.restoreStatuses(save.hero.statuses).
  • #loadSave restores positions via PersistenceManager.restoreVillagerPositions().
  • #maybeSave passes npcManager: this.#npcs.

server/PersistenceManager.js (SAVE_VERSION 7)

  • save() serializes hero.statuses and villagerPositions (array of {id,x,y}).
  • New static restoreVillagerPositions(npcManager, positions) — applies saved pos to matching villagers and calls clearPath() so A* recomputes from new position.

Frontend Developer / Designer

Contribution: Status badges in HeroPanel, new event type in EventLog.

client/src/components/HeroPanel.jsx

Added STATUS_META constant (color, bg, label per type). When hero.statuses is non-empty, renders a statusRow of colored pill badges between the region line and the HP bar. Badges only appear for known status types; unknown types are silently filtered. Each badge shows the emoji icon and label name.

client/src/components/EventLog.jsx

  • Added faMagicWandSparkles import.
  • Added status: '#b088e8' to TYPE_COLORS.
  • Added status: faMagicWandSparkles to TYPE_ICONS. Status inflictions, DoT ticks, and expiry messages all appear as purple-violet entries with a sparkle wand icon in the Chronicle.

Tester / QA

Contribution: New test file src/core/StatusEffects.test.js — 28 tests covering:

STATUS_DEFS:

  1. All four types defined.
  2. Blessed has atkBonus 3 and is combatOnly.
  3. Poisoned hpPerRound is -2.
  4. Burning hpPerRound is -3.
  5. Stunned skipTurn is true.

Hero status methods: 6. Starts with no statuses. 7. addStatus adds a status. 8. addStatus refreshes duration on duplicate. 9. tickStatuses removes expired entries and returns them. 10. tickStatuses keeps entries with rounds remaining. 11. statusAtkBonus returns 3 when blessed. 12. statusAtkBonus returns 0 with no buffs. 13. clearCombatStatuses removes blessed, keeps non-combatOnly. 14. serializeStatuses/restoreStatuses round-trip.

MONSTER_STATUS_INFLICT: 15. Drake → burning / 25%. 16. Goblin → poisoned / 20%. 17. Orc → stunned / 15%.

CombatSystem integration: 18. resolve returns { survived, statusEvents }. 19. Blessed ATK bonus accessible before combat clears it. 20. clearCombatStatuses called by resolve — blessed gone after fight. 21. Poisoned DoT generates a status event message.

Existing CombatSystem.test.js: Updated 2 tests to destructure { survived } from the new resolve() return shape.

Results: npm test728 / 728 passing across 69 files (+28 tests).


What Was Built

  • src/core/StatusEffects.js — status definitions + monster infliction table
  • src/entities/Hero.js — status tracking (addStatus, hasStatus, tick, clear, bonus)
  • src/core/CombatSystem.js — per-round DoT, stun skip, monster infliction, expiry log
  • server/SimEngine.js — Temple blesses hero; snapshot includes statuses; status log
  • server/PersistenceManager.js — SAVE_VERSION 7; villager positions + hero statuses saved
  • client/src/components/HeroPanel.jsx — status badge pills
  • client/src/components/EventLog.jsxstatus event type (purple, sparkle icon)
  • src/core/StatusEffects.test.js — 28 new tests

Tomorrow (Day 16 Candidates)

  • Second town + world map — a second settlement connected by road; hero travels between towns; trade caravans carry goods affecting both economies.
  • Inventory & equipment — weapons/armor with stat bonuses, loot drops from monsters, rarity tiers (common → legendary). The Merchant and Smith visits would interact with inventory naturally.
  • Hero classes UI — display heroClass more prominently (class icon, class-specific color accent); Paladin could show a heal-over-time blessed buff that differs from the Temple blessing.
  • Weather system — rain/sun/storm affects morale, crop yield (farmers), and travel speed. A weather overlay on the map canvas would be very atmospheric.