import {FightRound} from '../shared/fight';
import { clearFight, loadMonster, getMonsterList, saveFightState, loadMonsterFromFight } from './monster';
-import { Player, expToLevel, maxHp, totalDefence, maxVigor } from '../shared/player';
+import { Player, expToLevel, maxHp, totalDefence, maxVigor, baseDamage } from '../shared/player';
import { clearTravelPlan } from './map';
import { updatePlayer } from './player';
import { getEquippedItems, updateAp } from './inventory';
const primaryStat = attackType === 'physical' ? player.strength : player.intelligence;
const boostStat = attackType === 'physical' ? boost.strength : boost.intelligence;
- const playerDamage = Math.floor(((primaryStat + boostStat) * 1.3) + boost.damage);
+ const playerDamage = baseDamage(primaryStat, boostStat, boost.damage);
const skillsUsed: Record<SkillID | any, number> = {};
let hpHealAfterMasteries: number = -1;
let playerDamageAfterMasteries: number = 0;
getPlayersItems(req.player.id)
]);
- res.send(renderInventoryPage(inventory, items));
+ res.send(renderInventoryPage(req.player, inventory, items));
});
getPlayersItems(req.player.id)
]);
- res.send(renderInventoryPage(inventory, items, item.type) + renderPlayerBar(req.player));
+ res.send(renderInventoryPage(req.player, inventory, items, item.type) + renderPlayerBar(req.player));
});
inventoryRouter.post('/player/equip/:item_id/:slot', authEndpoint, blockPlayerInFight, blockPlayerInDungeon, async (req: Request, res: Response) => {
getPlayersItems(req.player.id)
]);
- res.send(renderInventoryPage(inventory, items, inventoryItem.type) + renderPlayerBar(req.player));
+ res.send(renderInventoryPage(req.player, inventory, items, inventoryItem.type) + renderPlayerBar(req.player));
});
inventoryRouter.put('/item/:item_id', authEndpoint, async (req: Request, res: Response) => {
res.send(
[
renderPlayerBar(req.player),
- renderInventoryPage(inventory, items, 'ITEMS'),
+ renderInventoryPage(req.player, inventory, items, 'ITEMS'),
Alert.SuccessAlert(`You used the ${item.name}`)
].join("")
);
--- /dev/null
+import { EquippedItemDetails } from "../../../shared/equipped";
+import { ItemStatBoostAbbr, ShopEquipment } from "../../../shared/inventory";
+import { baseDamage, Player } from "../../../shared/player";
+
+export function renderStatBoostWithPlayerIncrease(player: Player, name: ItemStatBoostAbbr, item: ShopEquipment | EquippedItemDetails) {
+ const val = item.boosts.damage;
+ let valSign: string = '';
+ if(typeof item.boosts.damage === 'number') {
+ valSign = item.boosts.damage > 0 ? '+' : '-';
+ }
+
+ const primaryStat = item.type === 'WEAPON' ? player.strength : player.intelligence;
+ const boostStat = item.type === 'WEAPON' ? item.boosts.strength : item.boosts.intelligence;
+
+ const effectiveDamage = baseDamage(primaryStat, boostStat, item.boosts.damage);
+ const diff = effectiveDamage - val;
+
+ // calculate any stat boost from the player
+ return `<span class="requirement-title">${name}</span>:
+<span class="requirement-value tooltip ${typeof val === 'number' ? (val > 0 ? "success": "error") : ""}" title="${val}(item) + ${diff}(from stats)">${valSign}${effectiveDamage}</span>`;
+}
import { PlayerItem } from "../../shared/items";
import { capitalize } from "lodash";
import { ProgressBar } from "./components/progress-bar";
+import { Player } from "../../shared/player";
+import { renderStatBoostWithPlayerIncrease } from "./components/stats";
function icon(icon_name?: string): string {
const placeholder = 'https://placehold.co/64x64/af936c/6d5f4d';
return `<span class="requirement-title">${name}</span>: <span class="requirement-value ${typeof val === 'number' ? (val > 0 ? "success": "error") : ""}">${valSign}${val}</span>`;
}
-function renderInventoryItem(item: EquippedItemDetails , action: (item: EquippedItemDetails) => string): string {
+function renderInventoryItem(player: Player, item: EquippedItemDetails , action: (item: EquippedItemDetails) => string): string {
return `<div class="store-list">
<div class="inventory-icon" style="background-image: url('${icon(item.icon)}')">
</div>
${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 ? renderStatBoostWithPlayerIncrease(player, item.affectedSkills.includes('restoration_magic') ? 'HP' : 'DMG', item) : ''}
${item.boosts.damage_mitigation ? renderStatBoost('MIT', item.boosts.damage_mitigation.toString())+'%' : ''}
${ProgressBar(item.currentAp, item.maxAp, `dur-${item.item_id}`, {
startingColor: '#7be67b',
</div>`;
}
-function renderInventorySection(inventory: EquippedItemDetails[]): string {
+function renderInventorySection(player: Player, 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 => {
+ return renderInventoryItem(player, item, item => {
if(item.is_equipped) {
return `<button type="button" class="unequip-item red" hx-post="/player/unequip/${item.item_id}">Unequip</button>`;
}
}
-export function renderInventoryPage(inventory: EquippedItemDetails[], items: PlayerItem[], requestedSlot: string = 'ARMOUR') {
+export function renderInventoryPage(player: Player, inventory: EquippedItemDetails[], items: PlayerItem[], requestedSlot: string = 'ARMOUR') {
const sectionedInventory: {ARMOUR: EquippedItemDetails[], WEAPON: EquippedItemDetails[], SPELL: EquippedItemDetails[], ITEMS: PlayerItem[]} = {
ARMOUR: [],
WEAPON: [],
<div class="inventory-listing listing">
${Object.keys(sectionedInventory).map((type) => {
return `<div class="filter-result inventory-${type} ${type === requestedSlot ? 'active': 'hidden'}" data-filter="${type}" id="filter_${type}">
- ${type === 'ITEMS' ? renderInventoryItems(sectionedInventory[type]) : renderInventorySection(sectionedInventory[type])}
+ ${type === 'ITEMS' ? renderInventoryItems(sectionedInventory[type]) : renderInventorySection(player, sectionedInventory[type])}
</div>`;
}).join("")}
</div>
-import { ShopEquipment } from "../../shared/inventory";
+import { ItemStatBoostAbbr, ShopEquipment } from "../../shared/inventory";
import { ShopItem, Item } from "../../shared/items";
import { capitalize, merge } from "lodash";
import { Player } from "../../shared/player";
import { LocationWithCity } from "shared/map";
import { ProgressBar } from "./components/progress-bar";
import { BackToTown } from "./components/button";
+import { renderStatBoostWithPlayerIncrease } from "./components/stats";
type RenderStatOptions = {
unsigned: boolean
return `<span title="${title}"><span class="requirement-title">${display}</span>: <span class="requirement-value ${opts.unsigned ? '' : (val > 0 ? "success": "error")}">${opts.unsigned ? val : `${valSign}${val}`}</span></span>`;
}
-function renderStatBoost(name: string, val: number | string, title?: string): string {
+function renderStatBoost(name: ItemStatBoostAbbr, val: number | string, title?: string): string {
let valSign: string = '';
if(typeof val === 'number') {
valSign = val > 0 ? '+' : '-';
${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(item.affectedSkills.includes('restoration_magic') ? 'HP' : 'DMG', item.boosts.damage) : ''}
+ ${item.boosts.damage ? renderStatBoostWithPlayerIncrease(player, item.affectedSkills.includes('restoration_magic') ? 'HP' : 'DMG', item) : ''}
${item.boosts.damage_mitigation ? renderStatBoost('MIT', item.boosts.damage_mitigation.toString())+'%' : ''}
${renderStat(isSpell ? 'Uses': 'Durability', isSpell ? 'Uses': 'DUR', item.maxAp, { unsigned: true })}
</div>
</div>
</div>
${BackToTown()}
-</div>`;
+</div>`
return html;
}
export type EquipmentSlot = ArmourEquipmentSlot | WeaponEquipmentSlot;
+export type ItemStatBoostAbbr = 'DEF' |
+'DMG' |
+'STR' |
+'CON' |
+'DEX' |
+'INT' |
+'HP' |
+'MIT';
+
export type InventoryItem = {
item_id: string;
}
}
+export function baseDamage(statValue: number, boostStat: number, damage: number): number {
+ return Math.floor(((statValue + boostStat) * 1.3) + damage);
+}
export type StatDisplay = {
id: Stat,
dexterity = 'dexterity',
intelligence = 'intelligence'
};
+
+export type STAT_ABR = 'STR' | 'CON' | 'DEX' | 'INT';