From: xangelo Date: Thu, 17 Oct 2024 20:21:32 +0000 (-0400) Subject: feat: display base damage and level-based boost X-Git-Url: https://git.xangelo.ca/?a=commitdiff_plain;h=b12078b2eb511d9dc0ae3e76ee1f12fc3b708ebe;p=risinglegends.git feat: display base damage and level-based boost Weapon and spell damage has two components: - A static value, that the item comes with - A "dynamic" value based on your skills The total damage that it deals is a combination of those two values. This change displays the static value AND the amount you gain based on your skills. --- diff --git a/src/server/fight.ts b/src/server/fight.ts index 93e9b3c..3a97a9d 100644 --- a/src/server/fight.ts +++ b/src/server/fight.ts @@ -1,6 +1,6 @@ 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'; @@ -111,7 +111,7 @@ export async function fightRound(player: Player, monster: Fight, data: {action: 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 = {}; let hpHealAfterMasteries: number = -1; let playerDamageAfterMasteries: number = 0; diff --git a/src/server/routes/inventory.ts b/src/server/routes/inventory.ts index cf88bdf..31c9bb1 100644 --- a/src/server/routes/inventory.ts +++ b/src/server/routes/inventory.ts @@ -23,7 +23,7 @@ inventoryRouter.get('/player/inventory', authEndpoint, async (req: Request, res: getPlayersItems(req.player.id) ]); - res.send(renderInventoryPage(inventory, items)); + res.send(renderInventoryPage(req.player, inventory, items)); }); @@ -38,7 +38,7 @@ inventoryRouter.post('/player/unequip/:item_id', authEndpoint, blockPlayerInFigh 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) => { @@ -90,7 +90,7 @@ inventoryRouter.post('/player/equip/:item_id/:slot', authEndpoint, blockPlayerIn 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) => { @@ -129,7 +129,7 @@ inventoryRouter.put('/item/:item_id', authEndpoint, async (req: Request, res: Re res.send( [ renderPlayerBar(req.player), - renderInventoryPage(inventory, items, 'ITEMS'), + renderInventoryPage(req.player, inventory, items, 'ITEMS'), Alert.SuccessAlert(`You used the ${item.name}`) ].join("") ); diff --git a/src/server/views/components/stats.ts b/src/server/views/components/stats.ts new file mode 100644 index 0000000..2e313fd --- /dev/null +++ b/src/server/views/components/stats.ts @@ -0,0 +1,21 @@ +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 `${name}: +${valSign}${effectiveDamage}`; +} diff --git a/src/server/views/inventory.ts b/src/server/views/inventory.ts index 88e3c8c..d9b8c43 100644 --- a/src/server/views/inventory.ts +++ b/src/server/views/inventory.ts @@ -3,6 +3,8 @@ import { EquippedItemDetails } from "../../shared/equipped"; 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'; @@ -83,7 +85,7 @@ function renderStatBoost(name: string, val: number | string): string { return `${name}: ${valSign}${val}`; } -function renderInventoryItem(item: EquippedItemDetails , action: (item: EquippedItemDetails) => string): string { +function renderInventoryItem(player: Player, item: EquippedItemDetails , action: (item: EquippedItemDetails) => string): string { return `
@@ -103,7 +105,7 @@ function renderInventoryItem(item: EquippedItemDetails , action: (item: Equipped ${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', @@ -120,11 +122,11 @@ function renderInventoryItem(item: EquippedItemDetails , action: (item: Equipped
`; } -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 ``; } @@ -155,7 +157,7 @@ function renderInventorySection(inventory: EquippedItemDetails[]): string { } -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: [], @@ -185,7 +187,7 @@ export function renderInventoryPage(inventory: EquippedItemDetails[], items: Pla
${Object.keys(sectionedInventory).map((type) => { return `
- ${type === 'ITEMS' ? renderInventoryItems(sectionedInventory[type]) : renderInventorySection(sectionedInventory[type])} + ${type === 'ITEMS' ? renderInventoryItems(sectionedInventory[type]) : renderInventorySection(player, sectionedInventory[type])}
`; }).join("")}
diff --git a/src/server/views/stores.ts b/src/server/views/stores.ts index 1061703..dcbdcaf 100644 --- a/src/server/views/stores.ts +++ b/src/server/views/stores.ts @@ -1,10 +1,11 @@ -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 @@ -23,7 +24,7 @@ function renderStat(title: string, display: string, val: any, options?: RenderSt return `${display}: ${opts.unsigned ? val : `${valSign}${val}`}`; } -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 ? '+' : '-'; @@ -74,7 +75,7 @@ export function renderEquipmentDetails(item: ShopEquipment, player: Player): str ${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 })} @@ -144,7 +145,7 @@ export async function renderStore(equipment: ShopEquipment[], items: (ShopItem & ${BackToTown()} -`; +` return html; } diff --git a/src/shared/inventory.ts b/src/shared/inventory.ts index 9084cc8..f78d65b 100644 --- a/src/shared/inventory.ts +++ b/src/shared/inventory.ts @@ -9,6 +9,15 @@ export type WeaponEquipmentSlot = 'LEFT_HAND' | 'RIGHT_HAND' | 'TWO_HANDED' | 'A export type EquipmentSlot = ArmourEquipmentSlot | WeaponEquipmentSlot; +export type ItemStatBoostAbbr = 'DEF' | +'DMG' | +'STR' | +'CON' | +'DEX' | +'INT' | +'HP' | +'MIT'; + export type InventoryItem = { item_id: string; diff --git a/src/shared/player.ts b/src/shared/player.ts index 339396d..d9aac73 100644 --- a/src/shared/player.ts +++ b/src/shared/player.ts @@ -69,6 +69,9 @@ export function totalDefence(equippedItems: EquippedItemDetails[], player: Playe } } +export function baseDamage(statValue: number, boostStat: number, damage: number): number { + return Math.floor(((statValue + boostStat) * 1.3) + damage); +} export type StatDisplay = { id: Stat, diff --git a/src/shared/stats.ts b/src/shared/stats.ts index a553bd4..14ae4fd 100644 --- a/src/shared/stats.ts +++ b/src/shared/stats.ts @@ -4,3 +4,5 @@ export enum Stat { dexterity = 'dexterity', intelligence = 'intelligence' }; + +export type STAT_ABR = 'STR' | 'CON' | 'DEX' | 'INT';