chore(release): 0.3.1 v0.3.1
authorxangelo <me@xangelo.ca>
Thu, 31 Aug 2023 21:10:16 +0000 (17:10 -0400)
committerxangelo <me@xangelo.ca>
Thu, 31 Aug 2023 21:10:16 +0000 (17:10 -0400)
14 files changed:
CHANGELOG.md
package-lock.json
package.json
public/assets/css/game.css
public/index.html
src/server/locations/healer/index.ts
src/server/locations/recruiter.ts
src/server/views/components/button.ts
src/server/views/inventory.ts
src/server/views/monster-selector.ts
src/server/views/profile.ts
src/server/views/repair.ts
src/server/views/stores.ts
src/shared/inventory.ts

index 1c03855005e14901b38bae8d9841851c90a09a8d..8561267884262a6204068d4479c9bf64a7455a35 100644 (file)
@@ -2,6 +2,16 @@
 
 All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
 
 
 All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
 
+### [0.3.1](https://git.xangelo.ca/?p=risinglegends.git;a=commitdiff;h=v0.3.1;hp=v0.3.0;ds=sidebyside) (2023-08-31)
+
+
+### Bug Fixes
+
+* add button that goes back to town from any page 06c0e48
+* spells support durability 2dbb9b8
+* stop z-stacking alert messages 6e756e8
+* tooltip text centered due to media-query cbfebd1
+
 ## [0.3.0](https://git.xangelo.ca/?p=risinglegends.git;a=commitdiff;h=v0.3.0;hp=v0.2.17;ds=sidebyside) (2023-08-30)
 
 
 ## [0.3.0](https://git.xangelo.ca/?p=risinglegends.git;a=commitdiff;h=v0.3.0;hp=v0.2.17;ds=sidebyside) (2023-08-30)
 
 
index d404a7a38182533a63db77d92b2307d933956c8c..819d0add4e877ad214b678eaefb4f19aee070be0 100644 (file)
@@ -1,12 +1,12 @@
 {
   "name": "rising-legends",
 {
   "name": "rising-legends",
-  "version": "0.3.0",
+  "version": "0.3.1",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "rising-legends",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "rising-legends",
-      "version": "0.3.0",
+      "version": "0.3.1",
       "dependencies": {
         "@honeycombio/opentelemetry-node": "^0.4.0",
         "@opentelemetry/auto-instrumentations-node": "^0.37.0",
       "dependencies": {
         "@honeycombio/opentelemetry-node": "^0.4.0",
         "@opentelemetry/auto-instrumentations-node": "^0.37.0",
index 5fc62422b80e777aeee89297b459d521ef5449fd..07fa690f042d38afc260d24114998c0ceccfc155 100644 (file)
@@ -1,7 +1,7 @@
 {
   "name": "rising-legends",
   "private": true,
 {
   "name": "rising-legends",
   "private": true,
-  "version": "0.3.0",
+  "version": "0.3.1",
   "scripts": {
     "up": "npx prisma migrate dev --name \"init\"",
     "start": "pm2 start dist/server/api.js",
   "scripts": {
     "up": "npx prisma migrate dev --name \"init\"",
     "start": "pm2 start dist/server/api.js",
index b288eefb7ec4f0be9930fbd52370d63416188417..f467f575ba1bb32301f030dc02154b3dba06c5e6 100644 (file)
@@ -159,15 +159,15 @@ dialog .close-modal {
 }
 
 #alerts {
 }
 
 #alerts {
-  position: relative;
+  position: absolute;
+  right: 0;
+  bottom: 0;
 }
 .alert {
   padding: 0.3rem;
   max-width: 17rem;
 }
 .alert {
   padding: 0.3rem;
   max-width: 17rem;
-  position: absolute;
-  bottom: 1rem;
-  right: 0;
   line-height: 1.2rem;
   line-height: 1.2rem;
+  box-shadow: -3px -3px 4px 0px rgba(0, 0, 0, 0.5);
 }
 .alert.success, button.success {
   border: solid 1px #0a0;
 }
 .alert.success, button.success {
   border: solid 1px #0a0;
@@ -367,6 +367,7 @@ nav.filter-result.active {
 }
 #main-nav {
   margin-bottom: 1rem;
 }
 #main-nav {
   margin-bottom: 1rem;
+  position: relative;
 }
 #main-nav section {
   min-height: 344px;
 }
 #main-nav section {
   min-height: 344px;
@@ -746,12 +747,12 @@ footer {
 
 /* tooltip styling */
 @media(pointer: coarse), (hover: none) {
 
 /* tooltip styling */
 @media(pointer: coarse), (hover: none) {
-  [title] {
+  .tooltip[title] {
     position: realtive;
     display: flex;
     justify-content: center;
   }
     position: realtive;
     display: flex;
     justify-content: center;
   }
-  [title]:focus::after {
+  .tooltip[title]:focus::after {
     content: attr(title);
     background-color: #fff;
     color: #222;
     content: attr(title);
     background-color: #fff;
     color: #222;
index 144ad914d8fdb1c5db15bc7225aeee486ea6efca..32e40fd75cea7cbed9b32ea63874e86f06e55a42 100644 (file)
@@ -61,8 +61,8 @@
             <p><button class="btn" id="logout">Logout</button></p>
           </div>
         </section>
             <p><button class="btn" id="logout">Logout</button></p>
           </div>
         </section>
+        <div id="alerts"></div>
       </div>
       </div>
-      <div id="alerts"></div>
 
       <section id="chat">
         <div id="chat-messages" hx-trigger="load delay:1s" hx-get="/chat/history" hx-swap="afterbegin"></div>
 
       <section id="chat">
         <div id="chat-messages" hx-trigger="load delay:1s" hx-get="/chat/history" hx-swap="afterbegin"></div>
index 16274a2f7b23cd47bfcb464318221dd0596372ec..83551b2a7f532659a9b5116082369f934f558a2e 100644 (file)
@@ -7,6 +7,7 @@ import { getCityDetails, getService } from '../../map';
 import { sample } from 'lodash';
 import { City, Location } from "../../../shared/map";
 import { renderPlayerBar } from "../../views/player-bar";
 import { sample } from 'lodash';
 import { City, Location } from "../../../shared/map";
 import { renderPlayerBar } from "../../views/player-bar";
+import { BackToTown } from "../../views/components/button";
 
 export const router = Router();
 
 
 export const router = Router();
 
@@ -123,6 +124,7 @@ router.get('/city/services/healer/:location_id', authEndpoint, async (req: AuthR
 <h3 class="location-name"><span>${service.name}</span></h3>
 <div class="service-in-town">
 ${text.join("\n")}
 <h3 class="location-name"><span>${service.name}</span></h3>
 <div class="service-in-town">
 ${text.join("\n")}
+${BackToTown()}
 </div>
 </div>
   `);
 </div>
 </div>
   `);
@@ -155,7 +157,6 @@ router.post('/city/services/healer/heal/:location_id', authEndpoint, async (req:
     await updatePlayer(req.player);
 
     text.push(`<p>${getText('heal_successful', service, city)}</p>`);
     await updatePlayer(req.player);
 
     text.push(`<p>${getText('heal_successful', service, city)}</p>`);
-    text.push('<p><button hx-get="/player/explore" hx-target="#explore">Back to Town</button></p>');
   }
 
   res.send(`
   }
 
   res.send(`
@@ -164,6 +165,7 @@ router.post('/city/services/healer/heal/:location_id', authEndpoint, async (req:
 <h3 class="location-name"><span>${service.name}</span></h3>
 <div class="service-in-town">
 ${text.join("\n")}
 <h3 class="location-name"><span>${service.name}</span></h3>
 <div class="service-in-town">
 ${text.join("\n")}
+${BackToTown()}
 </div>
 </div>
 ${renderPlayerBar(req.player)}
 </div>
 </div>
 ${renderPlayerBar(req.player)}
index 4ce985c2eb819a88620ef9cdedd497add1aeb538..96f720d656cf6ce4332acc050ca956faef0d68cc 100644 (file)
@@ -5,6 +5,7 @@ import { logger } from "../lib/logger";
 import * as Alert from "../views/alert";
 import { changeProfession } from "../player";
 import { renderPlayerBar } from "../views/player-bar";
 import * as Alert from "../views/alert";
 import { changeProfession } from "../player";
 import { renderPlayerBar } from "../views/player-bar";
+import { BackToTown } from "../views/components/button";
 
 function p(str: string) {
   return `<p>${str}</p>`;
 
 function p(str: string) {
   return `<p>${str}</p>`;
@@ -69,6 +70,7 @@ router.get('/city/services/profession_recruitor/:location_id', authEndpoint, asy
     html.push(`<p>However, you should visit the ${place} in ${town} that can probably provide some guidance!</p>`);
   }
 
     html.push(`<p>However, you should visit the ${place} in ${town} that can probably provide some guidance!</p>`);
   }
 
+  html.push(BackToTown());
   res.send(`
     <div class="city-title-wrapper"><div class="city-title">${service.city_name}</div></div>
     <div class="city-details">
   res.send(`
     <div class="city-title-wrapper"><div class="city-title">${service.city_name}</div></div>
     <div class="city-details">
index a6daca0784cf6a282817b102c85ff3f3a10ff332..11a9948ca9875fc2e938ca55b0ddfc5cd61b2a10 100644 (file)
@@ -33,3 +33,11 @@ export function Button(attrs: CoreAttributes & Record<string, any>, value: strin
 
   return `<button ${attributes.join(" ")}>${value}</button>`;
 }
 
   return `<button ${attributes.join(" ")}>${value}</button>`;
 }
+
+export function BackToTown(): string {
+  return Button({
+    'id': 'back-to-town',
+    'hx-get': '/player/explore',
+    'hx-target': '#explore'
+  }, 'Back to Town');
+}
index e21d1fd2e74bbcedc94459ffb968dc20e22102dc..6026775d1c91152eb01586d7a2d5ecce36b64227 100644 (file)
@@ -2,6 +2,7 @@ import { EquipmentSlot } from "shared/inventory";
 import { EquippedItemDetails } from "../../shared/equipped";
 import { PlayerItem } from "../../shared/items";
 import { capitalize } from "lodash";
 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';
 
 function icon(icon_name?: string): string {
   const placeholder = 'https://placehold.co/64x64/af936c/6d5f4d';
@@ -82,15 +83,6 @@ 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>`;
 }
 
   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 class="inventory-icon" style="background-image: url('${icon(item.icon)}')">
 function renderInventoryItem(item: EquippedItemDetails , action: (item: EquippedItemDetails) => string): string {
   return `<div class="store-list">
     <div class="inventory-icon" style="background-image: url('${icon(item.icon)}')">
@@ -113,7 +105,12 @@ function renderInventoryItem(item: EquippedItemDetails , action: (item: Equipped
         ${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())+'%' : ''}
         ${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())+'%' : ''}
-        ${['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>
       ${item.hasOwnProperty('id') ? `<div>${item.cost.toLocaleString()}G</div>` : ''}
       </div>
index 58c8665f480da4a72dd6c6338fc92da04b698434..e357835be3082955452dfd74686657b29a54e35a 100644 (file)
@@ -1,6 +1,7 @@
 import { max } from "lodash";
 import { LocationWithCity } from "../../shared/map";
 import { Monster, MonsterForFight } from "../../shared/monsters";
 import { max } from "lodash";
 import { LocationWithCity } from "../../shared/map";
 import { Monster, MonsterForFight } from "../../shared/monsters";
+import { BackToTown } from "./components/button";
 
 export function renderOnlyMonsterSelector(monsters: Monster[] | MonsterForFight[], activeMonsterId: number = 0, location?: LocationWithCity): string {
   let html = `
 
 export function renderOnlyMonsterSelector(monsters: Monster[] | MonsterForFight[], activeMonsterId: number = 0, location?: LocationWithCity): string {
   let html = `
@@ -25,7 +26,11 @@ export function renderMonsterSelector(monsters: Monster[] | MonsterForFight[], a
       const range = [monster.level, monster.level + 3];
       return `<option value="${monster.id}" ${monster.id === activeMonsterId ? 'selected': ''}>${monster.name} (${range[0]} - ${range[1]})</option>`;
   }).join("\n")}
       const range = [monster.level, monster.level + 3];
       return `<option value="${monster.id}" ${monster.id === activeMonsterId ? 'selected': ''}>${monster.name} (${range[0]} - ${range[1]})</option>`;
   }).join("\n")}
-  </select> <button type="submit" class="red">Fight</button></form></div>
+  </select> <button type="submit" class="red">Fight</button></form>
+<br><br>
+${BackToTown()}
+
+</div>
 `;
 
   return html;
 `;
 
   return html;
index 547cdefebe097df44623791138de66cad149742a..e6a1c0cfca3086fa4258a92591da308c78463bf5 100644 (file)
@@ -11,7 +11,7 @@ export function renderProfilePage(player: Player, equipment: EquippedItemDetails
 
   StatDef.forEach(stat => {
     statBreakdown += `<tr>
 
   StatDef.forEach(stat => {
     statBreakdown += `<tr>
-      <th title="${stat.description}" tabindex="0">${stat.display}</th>
+      <th title="${stat.description}" tabindex="0" class="tooltip">${stat.display}</th>
       <td class="${stat.id}">
         ${player[stat.id].toLocaleString()}
         ${player.stat_points ? statPointIncreaser(stat) : ''}
       <td class="${stat.id}">
         ${player[stat.id].toLocaleString()}
         ${player.stat_points ? statPointIncreaser(stat) : ''}
@@ -22,23 +22,23 @@ export function renderProfilePage(player: Player, equipment: EquippedItemDetails
   const html = `<div id="extra-inventory-info">
   <table class="stat-breakdown">
     <tr>
   const html = `<div id="extra-inventory-info">
   <table class="stat-breakdown">
     <tr>
-      <th title="The total amount of damage you can take before you pass out" tabindex="0">HP</th>
+      <th title="The total amount of damage you can take before you pass out" tabindex="0" class="tooltip">HP</th>
       <td>${player.hp.toLocaleString()}/${maxHp(player.constitution, player.level).toLocaleString()}</td>
     </tr>
     <tr>
       <td>${player.hp.toLocaleString()}/${maxHp(player.constitution, player.level).toLocaleString()}</td>
     </tr>
     <tr>
-      <th title="Your energy level. Low vigor will cause your overall defence and damage to drop." tabindex="0">Vigor</th>
+      <th title="Your energy level. Low vigor will cause your overall defence and damage to drop." tabindex="0" class="tooltip">Vigor</th>
       <td>${player.vigor.toLocaleString()}/${maxVigor(player.constitution, player.level).toLocaleString()}</td>
     </tr>
     <tr>
       <td>${player.vigor.toLocaleString()}/${maxVigor(player.constitution, player.level).toLocaleString()}</td>
     </tr>
     <tr>
-      <th title="How many experience points you need to get to your next level" tabindex="0">EXP</th>
+      <th title="How many experience points you need to get to your next level" tabindex="0" class="tooltip">EXP</th>
       <td>${player.exp.toLocaleString()}/${expToLevel(player.level + 1).toLocaleString()}</td>
     </tr>
     <tr>
       <td>${player.exp.toLocaleString()}/${expToLevel(player.level + 1).toLocaleString()}</td>
     </tr>
     <tr>
-      <th title="The max defence you can have (and your true defence affected by your vigor)" tabindex="0">Defence</th>
+      <th title="The max defence you can have (and your true defence affected by your vigor)" tabindex="0" class="tooltip">Defence</th>
       <td>${totalDefence(equipment, player, false).toLocaleString()} (${totalDefence(equipment, player).toLocaleString()})</td>
     </tr>
     <tr>
       <td>${totalDefence(equipment, player, false).toLocaleString()} (${totalDefence(equipment, player).toLocaleString()})</td>
     </tr>
     <tr>
-      <th title="You can use these to increase the base stats below" tabindex="0">Stat Points</th>
+      <th title="You can use these to increase the base stats below" tabindex="0" class="tooltip">Stat Points</th>
       <td class="stat_points">${player.stat_points}</td>
     </tr>
     ${statBreakdown}
       <td class="stat_points">${player.stat_points}</td>
     </tr>
     ${statBreakdown}
index 447dc84edb2bb754641fc807d7d2313024a3da51..a049f9cad23f4b6e8ab02376d1194898448848e9 100644 (file)
@@ -5,6 +5,7 @@ import { LocationWithCity } from "../../shared/map";
 import { EquippedItemDetails } from "../../shared/equipped";
 import { ProgressBar } from "./components/progress-bar";
 import * as City from './components/city';
 import { EquippedItemDetails } from "../../shared/equipped";
 import { ProgressBar } from "./components/progress-bar";
 import * as City from './components/city';
+import { BackToTown } from "./components/button";
 
 function renderStatBoost(name: string, val: number | string): string {
   let valSign: string = '';
 
 function renderStatBoost(name: string, val: number | string): string {
   let valSign: string = '';
@@ -42,9 +43,9 @@ export function renderEquipmentDetails(item: EquippedItemDetails, player: Player
       ${item.boosts.intelligence ? renderStatBoost('INT', item.boosts.intelligence) : ''}
       ${item.boosts.damage ? renderStatBoost(item.affectedSkills.includes('restoration_magic') ? 'HP' : 'DMG', item.boosts.damage) : ''}
       ${item.boosts.damage_mitigation ? renderStatBoost('MIT', item.boosts.damage_mitigation.toString())+'%' : ''}
       ${item.boosts.intelligence ? renderStatBoost('INT', item.boosts.intelligence) : ''}
       ${item.boosts.damage ? renderStatBoost(item.affectedSkills.includes('restoration_magic') ? 'HP' : 'DMG', item.boosts.damage) : ''}
       ${item.boosts.damage_mitigation ? renderStatBoost('MIT', item.boosts.damage_mitigation.toString())+'%' : ''}
-      ${['WEAPON','SPELL'].includes(item.type) ? '' :  ProgressBar(item.currentAp, item.maxAp, `${item.item_id}-ap`, {
+      ${ProgressBar(item.currentAp, item.maxAp, `${item.item_id}-ap`, {
 displayPercent: false,
 displayPercent: false,
-title: 'Durability',
+title: item.type === 'SPELL' ? 'Uses' : 'Durability',
 startingColor: '#7be67b',
 endingColor: '#7be67b'
 })}
 startingColor: '#7be67b',
 endingColor: '#7be67b'
 })}
@@ -78,6 +79,9 @@ export function renderRepairService(equipment: EquippedItemDetails[], player: Pl
   }
 
   equipment.forEach(item => {
   }
 
   equipment.forEach(item => {
+    if(item.maxAp <= 0) {
+      return;
+    }
     const filter = item.type === 'ARMOUR' ? item.equipment_slot : item.type;
 
     listingTypes.add(filter);
     const filter = item.type === 'ARMOUR' ? item.equipment_slot : item.type;
 
     listingTypes.add(filter);
@@ -109,6 +113,7 @@ export function renderRepairService(equipment: EquippedItemDetails[], player: Pl
       ${finalListing.join("\n")}
     </div>
   </div>
       ${finalListing.join("\n")}
     </div>
   </div>
+  ${BackToTown()}
 `)}`;
 
   return html;
 `)}`;
 
   return html;
index be20cf07aece0951e8b30995835ff756b6f91703..10617031c2c4ea6ef93108b8aee74cfd59dec482 100644 (file)
@@ -4,6 +4,7 @@ import { capitalize, merge } from "lodash";
 import { Player } from "../../shared/player";
 import { LocationWithCity } from "shared/map";
 import { ProgressBar } from "./components/progress-bar";
 import { Player } from "../../shared/player";
 import { LocationWithCity } from "shared/map";
 import { ProgressBar } from "./components/progress-bar";
+import { BackToTown } from "./components/button";
 
 type RenderStatOptions = {
   unsigned: boolean
 
 type RenderStatOptions = {
   unsigned: boolean
@@ -54,6 +55,8 @@ function renderShopItem(item: (ShopItem & Item), action: (item: (ShopItem & Item
 }
 
 export function renderEquipmentDetails(item: ShopEquipment, player: Player): string {
 }
 
 export function renderEquipmentDetails(item: ShopEquipment, player: Player): string {
+  const isSpell = item.type === 'SPELL';
+
   return `
     <div class="details">
       <div class="name">${item.name}${item.equipment_slot === 'TWO_HANDED' ? ' (2H)': ''}</div>
   return `
     <div class="details">
       <div class="name">${item.name}${item.equipment_slot === 'TWO_HANDED' ? ' (2H)': ''}</div>
@@ -73,7 +76,7 @@ export function renderEquipmentDetails(item: ShopEquipment, player: Player): str
       ${item.boosts.intelligence ? renderStatBoost('INT', item.boosts.intelligence) : ''}
       ${item.boosts.damage ? renderStatBoost(item.affectedSkills.includes('restoration_magic') ? 'HP' : 'DMG', item.boosts.damage) : ''}
       ${item.boosts.damage_mitigation ? renderStatBoost('MIT', item.boosts.damage_mitigation.toString())+'%' : ''}
       ${item.boosts.intelligence ? renderStatBoost('INT', item.boosts.intelligence) : ''}
       ${item.boosts.damage ? renderStatBoost(item.affectedSkills.includes('restoration_magic') ? 'HP' : 'DMG', item.boosts.damage) : ''}
       ${item.boosts.damage_mitigation ? renderStatBoost('MIT', item.boosts.damage_mitigation.toString())+'%' : ''}
-      ${['SPELL'].includes(item.type) ? '' : renderStat('Durability', 'DUR', item.maxAp, { unsigned: true })}
+      ${renderStat(isSpell ? 'Uses': 'Durability', isSpell ? 'Uses': 'DUR', item.maxAp, { unsigned: true })}
       </div>
       ${item.hasOwnProperty('id') ? `<div class="store-cost">${item.cost.toLocaleString()}G</div>` : ''}
     </div>
       </div>
       ${item.hasOwnProperty('id') ? `<div class="store-cost">${item.cost.toLocaleString()}G</div>` : ''}
     </div>
@@ -140,6 +143,7 @@ export async function renderStore(equipment: ShopEquipment[], items: (ShopItem &
       ${finalListing.join("\n")}
     </div>
   </div>
       ${finalListing.join("\n")}
     </div>
   </div>
+${BackToTown()}
 </div>`;
 
   return html;
 </div>`;
 
   return html;
index 0ed26ddef78e988274df8da97b3832ac253911d3..9084cc82d7ea473e7bc609dbaf3c7d4341ca4f1b 100644 (file)
@@ -1,5 +1,6 @@
 import {Profession} from "./profession";
 import {SkillID} from "./skills";
 import {Profession} from "./profession";
 import {SkillID} from "./skills";
+import { max } from 'lodash';
 
 export type InventoryType = 'ARMOUR' | 'WEAPON' | 'SPELL';
 
 
 export type InventoryType = 'ARMOUR' | 'WEAPON' | 'SPELL';
 
@@ -52,5 +53,5 @@ export function repairCost(item: InventoryItem): number {
 
   const damageRatio = 1 - (item.currentAp / item.maxAp);
 
 
   const damageRatio = 1 - (item.currentAp / item.maxAp);
 
-  return Math.floor(totalCost * damageRatio);
+  return max([Math.floor(totalCost * damageRatio), 1]);
 }
 }