diff --git a/api/app/api/npcs.py b/api/app/api/npcs.py index b4834b9..a8631d9 100644 --- a/api/app/api/npcs.py +++ b/api/app/api/npcs.py @@ -281,6 +281,7 @@ def get_npcs_at_location(location_id: str): "role": npc.role, "appearance": npc.appearance.brief, "tags": npc.tags, + "image_url": npc.image_url, }) return success_response({ diff --git a/api/app/data/npcs/crossville/npc_blacksmith_hilda.yaml b/api/app/data/npcs/crossville/npc_blacksmith_hilda.yaml index 1aa8d9e..ac21a9f 100644 --- a/api/app/data/npcs/crossville/npc_blacksmith_hilda.yaml +++ b/api/app/data/npcs/crossville/npc_blacksmith_hilda.yaml @@ -3,6 +3,7 @@ npc_id: npc_blacksmith_hilda name: Hilda Ironforge role: blacksmith location_id: crossville_village +image_url: /static/images/npcs/crossville/blacksmith_hilda.png personality: traits: diff --git a/api/app/data/npcs/crossville/npc_grom_ironbeard.yaml b/api/app/data/npcs/crossville/npc_grom_ironbeard.yaml index 0635d23..fd06c16 100644 --- a/api/app/data/npcs/crossville/npc_grom_ironbeard.yaml +++ b/api/app/data/npcs/crossville/npc_grom_ironbeard.yaml @@ -3,6 +3,7 @@ npc_id: npc_grom_ironbeard name: Grom Ironbeard role: bartender location_id: crossville_tavern +image_url: /static/images/npcs/crossville/grom_ironbeard.png personality: traits: diff --git a/api/app/data/npcs/crossville/npc_mayor_aldric.yaml b/api/app/data/npcs/crossville/npc_mayor_aldric.yaml index c71a2ec..fdaf007 100644 --- a/api/app/data/npcs/crossville/npc_mayor_aldric.yaml +++ b/api/app/data/npcs/crossville/npc_mayor_aldric.yaml @@ -3,6 +3,7 @@ npc_id: npc_mayor_aldric name: Mayor Aldric Thornwood role: mayor location_id: crossville_village +image_url: /static/images/npcs/crossville/mayor_aldric.png personality: traits: diff --git a/api/app/data/npcs/crossville/npc_mira_swiftfoot.yaml b/api/app/data/npcs/crossville/npc_mira_swiftfoot.yaml index 0163058..79ae8cd 100644 --- a/api/app/data/npcs/crossville/npc_mira_swiftfoot.yaml +++ b/api/app/data/npcs/crossville/npc_mira_swiftfoot.yaml @@ -3,6 +3,7 @@ npc_id: npc_mira_swiftfoot name: Mira Swiftfoot role: rogue location_id: crossville_tavern +image_url: /static/images/npcs/crossville/mira_swiftfoot.png personality: traits: diff --git a/api/app/models/npc.py b/api/app/models/npc.py index 05510ce..2ea3e2e 100644 --- a/api/app/models/npc.py +++ b/api/app/models/npc.py @@ -296,6 +296,7 @@ class NPC: location_id: str personality: NPCPersonality appearance: NPCAppearance + image_url: Optional[str] = None knowledge: Optional[NPCKnowledge] = None relationships: List[NPCRelationship] = field(default_factory=list) inventory_for_sale: List[NPCInventoryItem] = field(default_factory=list) @@ -316,6 +317,7 @@ class NPC: "name": self.name, "role": self.role, "location_id": self.location_id, + "image_url": self.image_url, "personality": self.personality.to_dict(), "appearance": self.appearance.to_dict(), "knowledge": self.knowledge.to_dict() if self.knowledge else None, @@ -400,6 +402,7 @@ class NPC: name=data["name"], role=data["role"], location_id=data["location_id"], + image_url=data.get("image_url"), personality=personality, appearance=appearance, knowledge=knowledge, diff --git a/api/app/services/npc_loader.py b/api/app/services/npc_loader.py index 0b1054a..b0cf4b7 100644 --- a/api/app/services/npc_loader.py +++ b/api/app/services/npc_loader.py @@ -212,6 +212,7 @@ class NPCLoader: name=data["name"], role=data["role"], location_id=data["location_id"], + image_url=data.get("image_url"), personality=personality, appearance=appearance, knowledge=knowledge, diff --git a/api/docs/DATA_MODELS.md b/api/docs/DATA_MODELS.md index 49958b5..206556d 100644 --- a/api/docs/DATA_MODELS.md +++ b/api/docs/DATA_MODELS.md @@ -225,6 +225,7 @@ Main NPC definition with personality and dialogue data for AI generation. | `location_id` | str | ID of location where NPC resides | | `personality` | NPCPersonality | Personality traits and speech patterns | | `appearance` | NPCAppearance | Physical description | +| `image_url` | Optional[str] | URL path to NPC portrait image (e.g., "/static/images/npcs/crossville/grom_ironbeard.png") | | `knowledge` | Optional[NPCKnowledge] | What the NPC knows (public and secret) | | `relationships` | List[NPCRelationship] | How NPC feels about other NPCs | | `inventory_for_sale` | List[NPCInventoryItem] | Items NPC sells (if merchant) | diff --git a/public_web/app/views/game_views.py b/public_web/app/views/game_views.py index 423d220..8bd607a 100644 --- a/public_web/app/views/game_views.py +++ b/public_web/app/views/game_views.py @@ -704,7 +704,8 @@ def npc_chat_modal(session_id: str, npc_id: str): 'name': npc_data.get('name'), 'role': npc_data.get('role'), 'appearance': npc_data.get('appearance', {}).get('brief', ''), - 'tags': npc_data.get('tags', []) + 'tags': npc_data.get('tags', []), + 'image_url': npc_data.get('image_url') } # Get relationship info diff --git a/public_web/static/images/npcs/crossville/blacksmith_hilda.png b/public_web/static/images/npcs/crossville/blacksmith_hilda.png new file mode 100644 index 0000000..0ce881c Binary files /dev/null and b/public_web/static/images/npcs/crossville/blacksmith_hilda.png differ diff --git a/public_web/static/images/npcs/crossville/grom_ironbeard.png b/public_web/static/images/npcs/crossville/grom_ironbeard.png new file mode 100644 index 0000000..a6393ef Binary files /dev/null and b/public_web/static/images/npcs/crossville/grom_ironbeard.png differ diff --git a/public_web/static/images/npcs/crossville/mayor_aldric.png b/public_web/static/images/npcs/crossville/mayor_aldric.png new file mode 100644 index 0000000..88219df Binary files /dev/null and b/public_web/static/images/npcs/crossville/mayor_aldric.png differ diff --git a/public_web/static/images/npcs/crossville/mira_swiftfoot.png b/public_web/static/images/npcs/crossville/mira_swiftfoot.png new file mode 100644 index 0000000..205c4ca Binary files /dev/null and b/public_web/static/images/npcs/crossville/mira_swiftfoot.png differ