chore(release): 0.3.3
[risinglegends.git] / src / server / views / inventory.ts
index 9616ad86c17c35754f83f339d9f31cdb76260662..88e3c8c338342180b9e93d84d5b45adf2970d3af 100644 (file)
@@ -1,10 +1,17 @@
-import { EquipmentSlot, InventoryType } from "shared/inventory";
+import { EquipmentSlot } from "shared/inventory";
 import { EquippedItemDetails } from "../../shared/equipped";
 import { PlayerItem } from "../../shared/items";
 import { capitalize } from "lodash";
+import { ProgressBar } from "./components/progress-bar";
+
+function icon(icon_name?: string): string {
+  const placeholder = 'https://placehold.co/64x64/af936c/6d5f4d';
+  const icon = icon_name ? `/assets/img/icons/equipment/${icon_name}` : placeholder;
+
+  return icon;
+}
 
 function renderEquipmentPlacementGrid(items: EquippedItemDetails[]) {
-  const placeholder = 'https://via.placeholder.com/64x64';
   // @ts-ignore
   const map: Record<EquipmentSlot, EquippedItemDetails> = items.filter(item => item.is_equipped).reduce((acc, item) => {
     acc[item.equipment_slot] = item;
@@ -16,29 +23,29 @@ function renderEquipmentPlacementGrid(items: EquippedItemDetails[]) {
 <tr>
 <td>
 </td>
-<td style="background-image: url('${placeholder}');" title="${map.HEAD ? map.HEAD.name : 'Empty'}">
-${map.HEAD ? map.HEAD.name : 'HEAD'}
+<td style="background-image: url('${icon(map.HEAD?.icon)}');" title="${map.HEAD ? map.HEAD.name : 'Empty'}">
+${map.HEAD ? (map.HEAD.icon ? '' : map.HEAD.name) : 'HEAD'}
 </td>
-<td style="background-image: url('${placeholder}');" title="${map.ARMS ? map.ARMS.name : 'Empty'}">
-${map.ARMS ? map.ARMS.name : 'ARMS'}
+<td style="background-image: url('${icon(map.ARMS?.icon)}');" title="${map.ARMS ? map.ARMS.name : 'Empty'}">
+${map.ARMS ? (map.ARMS.icon ? '' : map.ARMS.name) : 'ARMS'}
 </td>
 </tr>
 <tr>
-<td style="background-image: url('${placeholder}');" title="${map.LEFT_HAND ? map.LEFT_HAND.name : (map.TWO_HANDED ? map.TWO_HANDED.name : '')}">
-${map.LEFT_HAND ? map.LEFT_HAND.name : (map.TWO_HANDED ? map.TWO_HANDED.name : 'L_HAND')}
+<td style="background-image: url('${icon(map.LEFT_HAND ? map.LEFT_HAND.icon : map.TWO_HANDED?.icon)}');" title="${map.LEFT_HAND ? map.LEFT_HAND.name : (map.TWO_HANDED ? map.TWO_HANDED.name : '')}">
+${map.LEFT_HAND ? (map.LEFT_HAND.icon ? '' : map.LEFT_HAND.name) : (map.TWO_HANDED ? (map.TWO_HANDED.icon ? '' : map.TWO_HANDED.name) : 'L_HAND')}
 </td>
-<td style="background-image: url('${placeholder}');" title="${map.CHEST ? map.CHEST.name : ''}">
-${map.CHEST ? map.CHEST.name : 'CHEST'}
+<td style="background-image: url('${icon(map.CHEST?.icon)}');" title="${map.CHEST ? map.CHEST.name : ''}">
+${map.CHEST ? (map.CHEST.icon ? '' : map.CHEST.name) : 'CHEST'}
 </td>
-<td style="background-image: url('${placeholder}');" title="${map.RIGHT_HAND ? map.RIGHT_HAND.name : (map.TWO_HANDED ? map.TWO_HANDED.name : '')}">
-${map.RIGHT_HAND ? map.RIGHT_HAND.name : (map.TWO_HANDED ? map.TWO_HANDED.name : 'R_HAND')}
+<td style="background-image: url('${icon(map.RIGHT_HAND ? map.RIGHT_HAND.icon : map.TWO_HANDED?.icon)}');" title="${map.RIGHT_HAND ? map.RIGHT_HAND.name : (map.TWO_HANDED ? map.TWO_HANDED.name : '')}">
+${map.RIGHT_HAND ? (map.RIGHT_HAND.icon ? '' : map.RIGHT_HAND.name) : (map.TWO_HANDED ? (map.TWO_HANDED.icon ? '' : map.TWO_HANDED.name) : 'R_HAND')}
 </td>
 </tr>
 <tr>
 <td>
 </td>
-<td style="background-image: url('${placeholder}');" title="${map.LEGS ? map.LEGS.name : ''}">
-${map.LEGS ? map.LEGS.name : 'LEGS'}
+<td style="background-image: url('${icon(map.LEGS?.icon)}');" title="${map.LEGS ? map.LEGS.name : ''}">
+${map.LEGS ? (map.LEGS.icon ? '' : map.LEGS.name) : 'LEGS'}
 </td>
 <td>
 </td>
@@ -52,7 +59,7 @@ ${map.LEGS ? map.LEGS.name : 'LEGS'}
 function renderInventoryItems(items: PlayerItem[]): string {
   return items.map(item => {
     return `
-<div class="player-item trigger-modal" data-endpoint="/modal/items/${item.item_id}">
+<div class="player-item" hx-get="/modal/items/${item.item_id}" hx-target="#modal-wrapper">
 <img src="/assets/img/icons/items/${item.icon_name}" title="${item.name}">
 <span class="amount">${item.amount.toLocaleString()}</span>
 </div>`;
@@ -76,19 +83,9 @@ function renderStatBoost(name: string, val: number | string): string {
   return `<span class="requirement-title">${name}</span>: <span class="requirement-value ${typeof val === 'number' ? (val > 0 ? "success": "error") : ""}">${valSign}${val}</span>`;
 }
 
-function generateProgressBar(current: number, max: number, color: string, displayPercent: boolean = true): string {
-  let percent = 0;
-  if(max > 0) {
-    percent = Math.floor((current / max) * 100);
-  }
-  const display = `${displayPercent? `${percent}% - `: ''}`;
-  return `<div class="progress-bar" style="background: linear-gradient(to right, ${color}, ${color} ${percent}%, transparent ${percent}%, transparent)" title="${display}${current}/${max}">${display}${current}/${max}</div>`;
-}
-
 function renderInventoryItem(item: EquippedItemDetails , action: (item: EquippedItemDetails) => string): string {
   return `<div class="store-list">
-    <div>
-      <img src="https://via.placeholder.com/64x64">
+    <div class="inventory-icon" style="background-image: url('${icon(item.icon)}')">
     </div>
     <div class="details">
       <div class="name">${item.name}</div>
@@ -101,38 +98,53 @@ function renderInventoryItem(item: EquippedItemDetails , action: (item: Equipped
         ${renderRequirement('PRF', item.profession)}
       </div>
       <div class="stat-mods">
+        ${item.boosts.defence ? renderStatBoost('DEF', item.boosts.defence) : ''}
         ${item.boosts.strength ? renderStatBoost('STR', item.boosts.strength) : ''}
         ${item.boosts.constitution ? renderStatBoost('CON', item.boosts.constitution) : ''}
         ${item.boosts.dexterity ? renderStatBoost('DEX', item.boosts.dexterity) : ''}
         ${item.boosts.intelligence ? renderStatBoost('INT', item.boosts.intelligence) : ''}
         ${item.boosts.damage ? renderStatBoost('DMG', item.boosts.damage) : ''}
         ${item.boosts.damage_mitigation ? renderStatBoost('MIT', item.boosts.damage_mitigation.toString())+'%' : ''}
-        ${['WEAPON','SPELL'].includes(item.type) ? '': generateProgressBar(item.currentAp, item.maxAp, '#7be67b')}
+        ${ProgressBar(item.currentAp, item.maxAp, `dur-${item.item_id}`, {
+          startingColor: '#7be67b',
+          endingColor: '#7be67b',
+          displayPercent: false,
+          title: item.type === 'SPELL' ? 'Uses' : 'Durability'
+        })}
       </div>
       ${item.hasOwnProperty('id') ? `<div>${item.cost.toLocaleString()}G</div>` : ''}
       </div>
-      <div class="store-actions">
+      <div class="inventory-actions">
         ${action(item)}
       </div>
     </div>`;
 }
 
 function renderInventorySection(inventory: EquippedItemDetails[]): string {
+  const used_slots = inventory.filter(i => i.is_equipped).map(i => i.equipment_slot);
+
   return inventory.map(item => {
     return renderInventoryItem(item, item => {
       if(item.is_equipped) {
-        return `<button type="button" class="unequip-item error" hx-post="/player/unequip/${item.item_id}">Unequip</button>`;
+        return `<button type="button" class="unequip-item red" hx-post="/player/unequip/${item.item_id}">Unequip</button>`;
       }
       else {
-        if(item.equipment_slot === 'ANY_HAND') {
-          return `<button type="button" class="equip-item" hx-post="/player/equip/${item.item_id}/LEFT_HAND">Equip L</button>
-<button type="button" class="equip-item" hx-post="/player/equip/${item.item_id}/RIGHT_HAND">Equip R</button>`;
-        }
-        else if(item.equipment_slot === 'LEFT_HAND') {
-          return `<button type="button" class="equip-item" hx-post="/player/equip/${item.item_id}/${item.equipment_slot}">Equip Left</button>`;
-        }
-        else if(item.equipment_slot === 'RIGHT_HAND') {
-          return `<button type="button" class="equip-item" hx-post="/player/equip/${item.item_id}/${item.equipment_slot}">Equip Right</button>`;
+        if(['ANY_HAND', 'LEFT_HAND', 'RIGHT_HAND'].includes(item.equipment_slot)) {
+          const str: string[] = [
+            `<button type="button" class="equip-item" hx-post="/player/equip/${item.item_id}/LEFT_HAND">Equip L</button>`,
+            `<button type="button" class="equip-item" hx-post="/player/equip/${item.item_id}/RIGHT_HAND">Equip R</button>`
+          ];
+
+          if(used_slots.includes('LEFT_HAND') && !used_slots.includes('RIGHT_HAND')) {
+            return str[1];
+          }
+          else if(used_slots.includes('RIGHT_HAND') && !used_slots.includes('LEFT_HAND')) {
+            return str[0];
+          }
+          else if(used_slots.includes('LEFT_HAND') && used_slots.includes('RIGHT_HAND')) {
+            return "";
+          }
+          return str.join("");
         }
         else {
           return `<button type="button" class="equip-item" hx-post="/player/equip/${item.item_id}/${item.equipment_slot}">Equip</button>`;
@@ -159,7 +171,7 @@ export function renderInventoryPage(inventory: EquippedItemDetails[], items: Pla
   });
 
   const html = `
-  <div id="inventory-page" hx-target="#inventory" hx-swap="innerHTML">
+  <div id="inventory-page" hx-target="section#inventory" hx-swap="true">
     <div id="character-summary">
       ${renderEquipmentPlacementGrid(inventory)}
     </div>