4.9 KiB
| name | description | type |
|---|---|---|
| Town Rendering & Equipment Slots | Much bigger town buildings rendered via PixiJS Graphics on map, NPC rendering/interaction, wandering NPC encounters, extended equipment slots UI, daily tasks, achievements, nearby heroes, collision detection | project |
Updated on 2026-03-27:
Towns on Map (enlarged in March 2026 update):
GameRenderer.drawTowns()draws large ground planes (tan/brown dirt ellipses), then clusters of 5-14 houses spread over ~100px radius- Houses have 3 roof styles (pointed, flat, chimney), 2-3 windows, doors with knobs, optional fences and market stalls
_drawHouse()accepts roofStyle parameter (0=pointed, 1=flat, 2=pointed+chimney)_drawFence()and_drawTownStall()add variety between houses- Town border circle:
radius * TILE_WIDTH * 0.7(was 0.35), scale factor:radius / 8(was /12) - Town name label: 18px font (was 13px), positioned above house cluster
- House positions: deterministic pseudo-random from town.id for consistent layout
GameEngine.setTowns()storesTownData[]and checks hero proximity each tick for enter/exit events- Town data comes from
/townsAPI, converted viatownToTownData()in App.tsx TownDatainterface: id (number), centerX/centerY/radius/size, optional npcs: NPCData[]
NPC Rendering and Interaction (March 2026 update):
NPCDatainterface: id, name, type ('quest_giver'|'merchant'|'healer'), worldX, worldYGameRenderer.drawNPCs()renders type-specific colored diamonds with floating icons (!/$/ +) and name labels- Quest givers: gold body, "!" icon; Merchants: green body, "$" icon; Healers: white body, "+" icon
- Idle sway animation based on NPC id
GameEngine.setNPCs()stores all NPCs,_checkNPCProximity()firesonNearestNPCChangewithin 2 tilesNPCInteraction.tsx: floating panel appears when hero near NPC, type-specific action button- App.tsx wires nearest NPC state, dismiss tracking, and opens NPCDialog for quest givers
- Town NPC fetching:
getTownNPCs()for each town, NPCs positioned at town.worldX + npc.offsetX
Wandering NPC Encounter (March 2026 update):
NPCEncounterEventtype in types.ts: type, npcName, message, cost- Encounter provider checks for
type: "npc_event"response fromrequestEncounter WanderingNPCPopup.tsx: modal with accept/decline, callsPOST /api/v1/hero/npc-almsgiveNPCAlms()API returns hero + received item details
Extended Equipment (spec 6.3):
EquipmentIteminterface with id/slot/formId/name/rarity/ilvl/primaryStat/statTypeHeroState.equipment?: Record<string, EquipmentItem>optional mapHeroResponse.equipmentadded to API typesHeroPaneldynamically renders 5 display slots (main_hand, chest, head, feet, neck) with fallback to legacy weapon/armor fieldsEquipmentPanel.tsx-- compact 5-column grid with tap-to-expand detail, rarity-colored borders
Daily Tasks (spec 10.1) -- now backend-driven:
DailyTasks.tsx-- expandable top-right panel with progress bars- Fetches from
GET /api/v1/hero/daily-tasksviagetDailyTasks()API - Claim button on completed unclaimed tasks calls
POST /api/v1/hero/daily-tasks/{taskId}/claim - Refreshes after victories, buff activations, and claims
DailyTaskResponseinterface in api.ts
Achievements (spec 10.3):
AchievementsPanel.tsx-- expandable panel (trophy icon, top-right at x=240)- Fetches from
GET /api/v1/hero/achievementsviagetAchievements()API - Unlocked: gold border, checkmark, unlock date; Locked: grey with progress bar
- After each victory, compares new achievements with previous state; shows toast for newly unlocked
Nearby Heroes (spec 2.3 shared world):
GET /api/v1/hero/nearbyviagetNearbyHeroes()API; polled every 5 secondsGameEngine.setNearbyHeroes()storesNearbyHeroData[]GameRenderer.drawNearbyHeroes()draws semi-transparent green diamonds with name+level labels and idle swayNearbyHeroDatainterface in types.ts
Collision Detection (spec 2.2):
- Procedural terrain/object generation extracted to
src/game/procedural.ts(shared by renderer and engine) isProcedurallyBlocked(wx, wy)checks if a tile has a blocking object (tree, bush, rock, ruin, stall, well)- Engine
_isBlocked()checks server obstacle set first, falls back to procedural - In
_simulateWalking: before applying position delta, checks next tile; if blocked, tries 90-degree turn, then reverses GameEngine.populateObstacles()accepts server map objects for non-procedural maps
Why: MVP feature expansion per spec sections 2.2, 2.3, 2.4, 2.5, 6.3, 10.1, 10.3.
How to apply: Town rendering is in the ground layer (drawn after tiles, before entities). NPCs are in the entity layer for depth sorting. NPC proximity is checked every engine tick. Equipment UI extends legacy weapon/armor pattern. Daily tasks and achievements are now backend-driven. Collision uses procedural generation for the endless world.