step 10.14: done

This commit is contained in:
bepis
2026-10-23 05:54:46 +11:00
parent 32fb0eee9a
commit 2a79c4ea43
7 changed files with 263 additions and 71 deletions
+17 -9
View File
@@ -4,9 +4,7 @@ const { getDb } = require('../db');
const { AppError } = require('../utils/errors');
const { getEquipmentBonuses } = require('../game/equipment');
const { calcDerived } = require('../game/stats');
// Rarity defaults for materials (buy_price = 0).
const MATERIAL_SELL_DEFAULTS = { common: 2, uncommon: 4, rare: 8, epic: 16, legendary: 32 };
const { materialSellPrice } = require('../game/rewards');
// Prepared statements cached per DB handle (WeakMap).
const stmtCache = new WeakMap();
@@ -73,6 +71,11 @@ function getStmts(db) {
'DELETE FROM inventory WHERE id = ? AND quantity = ?'
),
// Delete inventory row when the sale exhausts the entire row.
deleteRowExact: db.prepare(
'DELETE FROM inventory WHERE id = ? AND quantity = ?'
),
// List all inventory items for a character.
listInventory: db.prepare(
`SELECT i.id AS inventory_id, i.item_id, i.quantity, i.equipped_slot, it.slug, it.name, it.type, it.rarity,
@@ -115,10 +118,10 @@ function getStock(characterId) {
levelReq: row.min_level,
levelOk: row.levelOk === 1,
canAfford: ch.gold >= row.buy_price,
// For materials: calculate sell price.
// For materials: use item-level formula.
sellPrice: row.buy_price > 0
? Math.floor(row.buy_price * 0.4)
: Math.max(1, Math.floor((MATERIAL_SELL_DEFAULTS[row.rarity] || 2) * ch.level / row.min_level)),
: materialSellPrice(row.rarity, row.min_level),
}));
return {
@@ -167,13 +170,12 @@ function sellItem(characterId, itemId, quantity) {
throw new AppError('VALIDATION_ERROR', 'Only materials can be sold.', 400);
}
// Calculate sell price for this material.
// Calculate sell price for this material (item-level formula).
let sellPrice;
if (item.buy_price > 0) {
sellPrice = Math.floor(item.buy_price * 0.4);
} else {
const defaultRate = MATERIAL_SELL_DEFAULTS[item.rarity] || 2;
sellPrice = Math.max(1, Math.floor(defaultRate * ch.level / item.min_level));
sellPrice = materialSellPrice(item.rarity, item.min_level);
}
// Calculate how many we can actually sell from available rows.
@@ -199,7 +201,13 @@ function sellItem(characterId, itemId, quantity) {
if (sale.qty === 1) {
s.deleteRow.run(sale.rowId, 1);
} else {
s.decrementQty.run(sale.qty, sale.rowId, sale.qty);
// Check if this row's quantity exactly matches the sale qty
const chRow = db.prepare('SELECT quantity FROM inventory WHERE id = ?').get(sale.rowId);
if (chRow && chRow.quantity === sale.qty) {
s.deleteRowExact.run(sale.rowId, sale.qty); // delete when sale exhausts the row
} else {
s.decrementQty.run(sale.qty, sale.rowId, sale.qty);
}
}
}
s.updateGold.run(newGoldVal, cid);