NPC shop implimented
This commit is contained in:
@@ -103,6 +103,15 @@ Displays character stats, resource bars, and action buttons
|
||||
⚔️ Equipment & Gear
|
||||
</button>
|
||||
|
||||
{# Shop - Opens shop modal #}
|
||||
<button class="action-btn action-btn--special"
|
||||
hx-get="{{ url_for('game.shop_modal', session_id=session_id) }}"
|
||||
hx-target="#modal-container"
|
||||
hx-swap="innerHTML">
|
||||
<span class="action-icon">💰</span>
|
||||
Shop
|
||||
</button>
|
||||
|
||||
{# Skill Trees - Direct link to skills page #}
|
||||
<a class="action-btn action-btn--special"
|
||||
href="{{ url_for('character_views.view_skills', character_id=character.character_id) }}">
|
||||
|
||||
180
public_web/templates/game/partials/shop_modal.html
Normal file
180
public_web/templates/game/partials/shop_modal.html
Normal file
@@ -0,0 +1,180 @@
|
||||
{#
|
||||
Shop Modal
|
||||
Browse and purchase items from the general store
|
||||
#}
|
||||
<div class="modal-overlay" onclick="if(event.target===this) closeModal()"
|
||||
role="dialog" aria-modal="true" aria-labelledby="shop-title">
|
||||
<div class="modal-content shop-modal">
|
||||
{# Header #}
|
||||
<div class="modal-header">
|
||||
<div class="shop-header-info">
|
||||
<h2 class="modal-title" id="shop-title">
|
||||
{{ shop.shop_name|default('General Store') }}
|
||||
</h2>
|
||||
<span class="shop-keeper">{{ shop.shopkeeper_name|default('Merchant') }}</span>
|
||||
</div>
|
||||
<div class="shop-gold-display">
|
||||
<span class="gold-icon">💰</span>
|
||||
<span class="gold-amount">{{ gold }}</span>
|
||||
</div>
|
||||
<button class="modal-close" onclick="closeModal()" aria-label="Close shop">×</button>
|
||||
</div>
|
||||
|
||||
{# Success/Error Message #}
|
||||
{% if message %}
|
||||
<div class="shop-message shop-message--success">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if error %}
|
||||
<div class="shop-message shop-message--error">
|
||||
{{ error }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Tab Filter Bar #}
|
||||
<div class="shop-tabs" role="tablist">
|
||||
<button class="tab {% if filter == 'all' %}active{% endif %}"
|
||||
role="tab"
|
||||
aria-selected="{{ 'true' if filter == 'all' else 'false' }}"
|
||||
hx-get="{{ url_for('game.shop_modal', session_id=session_id, filter='all') }}"
|
||||
hx-target=".shop-modal"
|
||||
hx-swap="outerHTML">
|
||||
All
|
||||
</button>
|
||||
<button class="tab {% if filter == 'weapon' %}active{% endif %}"
|
||||
role="tab"
|
||||
aria-selected="{{ 'true' if filter == 'weapon' else 'false' }}"
|
||||
hx-get="{{ url_for('game.shop_modal', session_id=session_id, filter='weapon') }}"
|
||||
hx-target=".shop-modal"
|
||||
hx-swap="outerHTML">
|
||||
Weapons
|
||||
</button>
|
||||
<button class="tab {% if filter == 'armor' %}active{% endif %}"
|
||||
role="tab"
|
||||
aria-selected="{{ 'true' if filter == 'armor' else 'false' }}"
|
||||
hx-get="{{ url_for('game.shop_modal', session_id=session_id, filter='armor') }}"
|
||||
hx-target=".shop-modal"
|
||||
hx-swap="outerHTML">
|
||||
Armor
|
||||
</button>
|
||||
<button class="tab {% if filter == 'consumable' %}active{% endif %}"
|
||||
role="tab"
|
||||
aria-selected="{{ 'true' if filter == 'consumable' else 'false' }}"
|
||||
hx-get="{{ url_for('game.shop_modal', session_id=session_id, filter='consumable') }}"
|
||||
hx-target=".shop-modal"
|
||||
hx-swap="outerHTML">
|
||||
Consumables
|
||||
</button>
|
||||
<button class="tab {% if filter == 'accessory' %}active{% endif %}"
|
||||
role="tab"
|
||||
aria-selected="{{ 'true' if filter == 'accessory' else 'false' }}"
|
||||
hx-get="{{ url_for('game.shop_modal', session_id=session_id, filter='accessory') }}"
|
||||
hx-target=".shop-modal"
|
||||
hx-swap="outerHTML">
|
||||
Accessories
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{# Body - Item Grid #}
|
||||
<div class="modal-body shop-body">
|
||||
<div class="shop-grid">
|
||||
{% for entry in inventory %}
|
||||
{% set item = entry.item %}
|
||||
{% set price = entry.shop_price %}
|
||||
{% set can_afford = entry.can_afford|default(gold >= price) %}
|
||||
<div class="shop-item rarity-{{ item.rarity|default('common') }}">
|
||||
{# Item Header #}
|
||||
<div class="shop-item-header">
|
||||
<span class="shop-item-name">{{ item.name }}</span>
|
||||
<span class="shop-item-type">{{ item.item_type|default('item')|replace('_', ' ')|title }}</span>
|
||||
</div>
|
||||
|
||||
{# Rarity Tag #}
|
||||
<span class="shop-item-rarity rarity-tag--{{ item.rarity|default('common') }}">
|
||||
{{ item.rarity|default('common')|title }}
|
||||
</span>
|
||||
|
||||
{# Item Description #}
|
||||
<p class="shop-item-desc">{{ item.description|default('A useful item.')|truncate(80) }}</p>
|
||||
|
||||
{# Item Stats #}
|
||||
<div class="shop-item-stats">
|
||||
{% if item.item_type == 'weapon' %}
|
||||
{% if item.damage %}
|
||||
<span class="stat">Damage: {{ item.damage }}</span>
|
||||
{% endif %}
|
||||
{% if item.damage_type %}
|
||||
<span class="stat">{{ item.damage_type|title }}</span>
|
||||
{% endif %}
|
||||
{% elif item.item_type == 'armor' or item.item_type == 'shield' %}
|
||||
{% if item.defense %}
|
||||
<span class="stat">Defense: +{{ item.defense }}</span>
|
||||
{% endif %}
|
||||
{% if item.slot %}
|
||||
<span class="stat">{{ item.slot|replace('_', ' ')|title }}</span>
|
||||
{% endif %}
|
||||
{% elif item.item_type == 'consumable' %}
|
||||
{% if item.hp_restore %}
|
||||
<span class="stat">HP +{{ item.hp_restore }}</span>
|
||||
{% endif %}
|
||||
{% if item.mp_restore %}
|
||||
<span class="stat">MP +{{ item.mp_restore }}</span>
|
||||
{% endif %}
|
||||
{% if item.effect %}
|
||||
<span class="stat">{{ item.effect }}</span>
|
||||
{% endif %}
|
||||
{% elif item.item_type == 'accessory' %}
|
||||
{% if item.stat_bonuses %}
|
||||
{% for stat, bonus in item.stat_bonuses.items() %}
|
||||
<span class="stat">{{ stat|title }}: +{{ bonus }}</span>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# Price and Buy Button #}
|
||||
<div class="shop-item-footer">
|
||||
<span class="shop-item-price {% if not can_afford %}unaffordable{% endif %}">
|
||||
<span class="gold-icon">💰</span> {{ price }}
|
||||
</span>
|
||||
<button class="btn-purchase {% if can_afford %}btn-purchase--available{% else %}btn-purchase--disabled{% endif %}"
|
||||
{% if can_afford %}
|
||||
hx-post="{{ url_for('game.shop_purchase', session_id=session_id) }}"
|
||||
hx-vals='{"item_id": "{{ item.item_id }}", "quantity": 1}'
|
||||
hx-target=".shop-modal"
|
||||
hx-swap="outerHTML"
|
||||
{% else %}
|
||||
disabled
|
||||
{% endif %}
|
||||
aria-label="{% if can_afford %}Purchase {{ item.name }} for {{ price }} gold{% else %}Not enough gold{% endif %}">
|
||||
{% if can_afford %}
|
||||
Buy
|
||||
{% else %}
|
||||
Can't Afford
|
||||
{% endif %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="shop-empty">
|
||||
{% if filter == 'all' %}
|
||||
No items available in this shop.
|
||||
{% else %}
|
||||
No {{ filter|replace('_', ' ') }}s available.
|
||||
{% endif %}
|
||||
</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Footer #}
|
||||
<div class="modal-footer">
|
||||
<div class="shop-footer-gold">
|
||||
<span class="gold-icon">💰</span>
|
||||
<span class="gold-amount">{{ gold }} gold</span>
|
||||
</div>
|
||||
<button class="btn btn--secondary" onclick="closeModal()">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user