Finalize shops, interactions and world data
All checks were successful
Smoke tests / Build and smoke test (push) Successful in 1m53s

This commit is contained in:
AI Agent
2026-03-19 08:12:16 -06:00
parent 52b333fa48
commit 87baaee46f
3 changed files with 72 additions and 63 deletions

View File

@@ -1476,11 +1476,8 @@ async fn cmd_spells(pid: usize, state: &SharedState) -> CommandResult {
async fn cmd_shop(pid: usize, args: &str, state: &SharedState) -> CommandResult {
let mut st = state.lock().await;
let (conn, rid) = match st.players.get_mut(&pid) {
Some(c) => {
let rid = c.player.room_id.clone();
(c, rid)
}
let rid = match st.players.get(&pid) {
Some(c) => c.player.room_id.clone(),
None => return simple("Error\r\n"),
};
@@ -1543,22 +1540,25 @@ async fn cmd_shop(pid: usize, args: &str, state: &SharedState) -> CommandResult
if subargs.is_empty() {
return simple("Buy what?\r\n");
}
let (shop, _npc_name) = {
let npc = st.world.get_npc(&merchant_id).unwrap();
let shop = npc.shop.as_ref().unwrap().clone();
(npc.shop.as_ref().unwrap().clone(), npc.name.clone())
};
let item_to_buy = shop.sells.iter().find(|id| {
let item_id = shop.sells.iter().find(|id| {
if let Some(obj) = st.world.get_object(*id) {
obj.name.to_lowercase().contains(&subargs.to_lowercase())
} else {
false
}
});
}).cloned();
if let Some(item_id) = item_to_buy {
let obj = st.world.get_object(item_id).unwrap().clone();
if let Some(id) = item_id {
let obj = st.world.get_object(&id).unwrap().clone();
let total_copper = (obj.value_gold * 10000 + obj.value_silver * 100 + obj.value_copper) as f32;
let price_copper = (total_copper * shop.markup).ceil() as i32;
if let Some(conn) = st.players.get_mut(&pid) {
let player_total_copper = conn.player.gold * 10000 + conn.player.silver * 100 + conn.player.copper;
if player_total_copper < price_copper {
return simple("You don't have enough money.\r\n");
@@ -1579,6 +1579,9 @@ async fn cmd_shop(pid: usize, args: &str, state: &SharedState) -> CommandResult
ansi::color(ansi::CYAN, &obj.name),
price_copper
))
} else {
simple("Error\r\n")
}
} else {
simple("The merchant doesn't sell that.\r\n")
}
@@ -1588,14 +1591,16 @@ async fn cmd_shop(pid: usize, args: &str, state: &SharedState) -> CommandResult
if subargs.is_empty() {
return simple("Sell what?\r\n");
}
let npc = st.world.get_npc(&merchant_id).unwrap();
let shop = npc.shop.as_ref().unwrap().clone();
let shop = st.world.get_npc(&merchant_id).unwrap().shop.as_ref().unwrap().clone();
let item_idx = conn.player.inventory.iter().position(|o| o.name.to_lowercase().contains(&subargs.to_lowercase()));
if let Some(idx) = item_idx {
let obj = conn.player.inventory[idx].clone();
let item_info = if let Some(conn) = st.players.get(&pid) {
conn.player.inventory.iter().position(|o| o.name.to_lowercase().contains(&subargs.to_lowercase()))
.map(|idx| (idx, conn.player.inventory[idx].clone()))
} else {
None
};
if let Some((idx, obj)) = item_info {
// Check if merchant buys this kind of item
let can_sell = shop.buys.is_empty() || shop.buys.iter().any(|k| {
if let Some(kind) = &obj.kind {
@@ -1612,6 +1617,7 @@ async fn cmd_shop(pid: usize, args: &str, state: &SharedState) -> CommandResult
let total_copper = (obj.value_gold * 10000 + obj.value_silver * 100 + obj.value_copper) as f32;
let price_copper = (total_copper * shop.markdown).floor() as i32;
if let Some(conn) = st.players.get_mut(&pid) {
// Add money to player
let mut player_total_copper = conn.player.gold * 10000 + conn.player.silver * 100 + conn.player.copper;
player_total_copper += price_copper;
@@ -1628,6 +1634,9 @@ async fn cmd_shop(pid: usize, args: &str, state: &SharedState) -> CommandResult
ansi::color(ansi::CYAN, &obj.name),
price_copper
))
} else {
simple("Error\r\n")
}
} else {
simple("You don't have that in your inventory.\r\n")
}

View File

@@ -78,7 +78,7 @@ impl SqliteDb {
.map_err(|e| format!("Failed to set pragmas: {e}"))?;
conn.execute_batch(
CREATE TABLE IF NOT EXISTS players (
r#"CREATE TABLE IF NOT EXISTS players (
name TEXT PRIMARY KEY,
race_id TEXT NOT NULL,
class_id TEXT NOT NULL,
@@ -89,8 +89,8 @@ impl SqliteDb {
max_hp INTEGER NOT NULL,
attack INTEGER NOT NULL,
defense INTEGER NOT NULL,
inventory_json TEXT NOT NULL DEFAULT '[]',
equipped_json TEXT NOT NULL DEFAULT '{}',
inventory_json TEXT NOT NULL DEFAULT "[]",
equipped_json TEXT NOT NULL DEFAULT "{}",
is_admin INTEGER NOT NULL DEFAULT 0,
mana INTEGER NOT NULL DEFAULT 0,
max_mana INTEGER NOT NULL DEFAULT 0,
@@ -127,13 +127,13 @@ impl SqliteDb {
guild_id TEXT NOT NULL,
level INTEGER NOT NULL DEFAULT 1,
PRIMARY KEY (player_name, guild_id)
);",
);"#,
)
.map_err(|e| format!("Failed to create tables: {e}"))?;
// Migration: add is_admin column if missing
let has_admin: bool = conn
.prepare("SELECT COUNT(*) FROM pragma_table_info('players') WHERE name='is_admin'")
.prepare(r#"SELECT COUNT(*) FROM pragma_table_info("players") WHERE name="is_admin""#)
.and_then(|mut s| s.query_row([], |r| r.get::<_, i32>(0)))
.map(|c| c > 0)
.unwrap_or(false);
@@ -146,34 +146,34 @@ impl SqliteDb {
// Migration: equipped_weapon_json/equipped_armor_json -> equipped_json
let has_old_weapon: bool = conn
.prepare("SELECT COUNT(*) FROM pragma_table_info('players') WHERE name='equipped_weapon_json'")
.prepare(r#"SELECT COUNT(*) FROM pragma_table_info("players") WHERE name="equipped_weapon_json""#)
.and_then(|mut s| s.query_row([], |r| r.get::<_, i32>(0)))
.map(|c| c > 0)
.unwrap_or(false);
let has_equipped: bool = conn
.prepare("SELECT COUNT(*) FROM pragma_table_info('players') WHERE name='equipped_json'")
.prepare(r#"SELECT COUNT(*) FROM pragma_table_info("players") WHERE name="equipped_json""#)
.and_then(|mut s| s.query_row([], |r| r.get::<_, i32>(0)))
.map(|c| c > 0)
.unwrap_or(false);
if has_old_weapon && !has_equipped {
let _ = conn.execute(
"ALTER TABLE players ADD COLUMN equipped_json TEXT NOT NULL DEFAULT '{}'",
r#"ALTER TABLE players ADD COLUMN equipped_json TEXT NOT NULL DEFAULT "{}"#,
[],
);
log::info!("Migrating equipped_weapon_json/equipped_armor_json to equipped_json...");
let _ = conn.execute_batch(
"UPDATE players SET equipped_json = '{}' WHERE equipped_weapon_json IS NULL AND equipped_armor_json IS NULL;"
r#"UPDATE players SET equipped_json = "{}" WHERE equipped_weapon_json IS NULL AND equipped_armor_json IS NULL;"#
);
} else if !has_equipped {
let _ = conn.execute(
"ALTER TABLE players ADD COLUMN equipped_json TEXT NOT NULL DEFAULT '{}'",
r#"ALTER TABLE players ADD COLUMN equipped_json TEXT NOT NULL DEFAULT "{}"#,
[],
);
}
// Migration: add mana/endurance columns
let has_mana: bool = conn
.prepare("SELECT COUNT(*) FROM pragma_table_info('players') WHERE name='mana'")
.prepare(r#"SELECT COUNT(*) FROM pragma_table_info("players") WHERE name="mana""#)
.and_then(|mut s| s.query_row([], |r| r.get::<_, i32>(0)))
.map(|c| c > 0)
.unwrap_or(false);
@@ -186,7 +186,7 @@ impl SqliteDb {
// Migration: add currency columns
let has_gold: bool = conn
.prepare("SELECT COUNT(*) FROM pragma_table_info('players') WHERE name='gold'")
.prepare(r#"SELECT COUNT(*) FROM pragma_table_info("players") WHERE name="gold""#)
.and_then(|mut s| s.query_row([], |r| r.get::<_, i32>(0)))
.map(|c| c > 0)
.unwrap_or(false);

View File

@@ -2,7 +2,7 @@ name = "Breda"
description = "Breda is haughty in bearing, with thin auburn hair and narrow blue eyes. She wears simple clothing and several small tools hang from her belt. Breda will purchase monster teeth for a silver coin each."
room = "lawold:well_market_trade_stalls"
race = "race:human"
base_attitude = "aggressive"
base_attitude = "neutral"
[dialogue]
greeting = "What do you want? I'm busy. Unless you have some teeth to sell?"