forked from blasthavers/blastmud
Start work on shops.
This commit is contained in:
parent
2053c9cbb3
commit
722757468f
@ -15,6 +15,7 @@ mod describe;
|
|||||||
mod help;
|
mod help;
|
||||||
mod ignore;
|
mod ignore;
|
||||||
mod less_explicit_mode;
|
mod less_explicit_mode;
|
||||||
|
mod list;
|
||||||
mod login;
|
mod login;
|
||||||
mod look;
|
mod look;
|
||||||
mod map;
|
mod map;
|
||||||
@ -107,6 +108,8 @@ static REGISTERED_COMMANDS: UserVerbRegistry = phf_map! {
|
|||||||
"look" => look::VERB,
|
"look" => look::VERB,
|
||||||
"read" => look::VERB,
|
"read" => look::VERB,
|
||||||
|
|
||||||
|
"list" => list::VERB,
|
||||||
|
|
||||||
"lmap" => map::VERB,
|
"lmap" => map::VERB,
|
||||||
|
|
||||||
"\'" => say::VERB,
|
"\'" => say::VERB,
|
||||||
|
47
blastmud_game/src/message_handler/user_commands/list.rs
Normal file
47
blastmud_game/src/message_handler/user_commands/list.rs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
use super::{VerbContext, UserVerb, UserVerbRef, UResult, user_error,
|
||||||
|
get_player_item_or_fail};
|
||||||
|
use crate::{
|
||||||
|
static_content::room,
|
||||||
|
static_content::possession_type::possession_data,
|
||||||
|
};
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use ansi::ansi;
|
||||||
|
|
||||||
|
pub struct Verb;
|
||||||
|
#[async_trait]
|
||||||
|
impl UserVerb for Verb {
|
||||||
|
async fn handle(self: &Self, ctx: &mut VerbContext, _verb: &str, _remaining: &str) -> UResult<()> {
|
||||||
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
|
|
||||||
|
if player_item.is_dead {
|
||||||
|
user_error("Nobody seems to offer you any prices... possibly because you're dead.".to_owned())?
|
||||||
|
}
|
||||||
|
let (heretype, herecode) = player_item.location.split_once("/").unwrap_or(("room", "repro_xv_chargen"));
|
||||||
|
if heretype != "room" {
|
||||||
|
user_error("Can't list stock because you're not in a shop.".to_owned())?;
|
||||||
|
}
|
||||||
|
let room = match room::room_map_by_code().get(herecode) {
|
||||||
|
None => user_error("Can't find that shop.".to_owned())?,
|
||||||
|
Some(r) => r
|
||||||
|
};
|
||||||
|
if room.stock_list.is_empty() {
|
||||||
|
user_error("Can't list stock because you're not in a shop.".to_owned())?
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut msg = String::new();
|
||||||
|
msg.push_str(&format!(ansi!("<bold><bgblue><white>| {:20} | {:15} |<reset>\n"),
|
||||||
|
ansi!("Item"),
|
||||||
|
ansi!("Price")));
|
||||||
|
|
||||||
|
for stock in &room.stock_list {
|
||||||
|
if let Some(possession_type) = possession_data().get(&stock.possession_type) {
|
||||||
|
msg.push_str(&format!("| {:20} | {:15.2} |\n", &possession_type.name, &stock.list_price))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
msg.push('\n');
|
||||||
|
ctx.trans.queue_for_session(&ctx.session, Some(&msg)).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static VERB_INT: Verb = Verb;
|
||||||
|
pub static VERB: UserVerbRef = &VERB_INT as UserVerbRef;
|
@ -92,7 +92,8 @@ impl Default for NPC {
|
|||||||
aliases: vec!(),
|
aliases: vec!(),
|
||||||
says: vec!(),
|
says: vec!(),
|
||||||
total_xp: 1000,
|
total_xp: 1000,
|
||||||
total_skills: SkillType::values().into_iter().map(|sk| (sk, 10.0)).collect(),
|
total_skills: SkillType::values().into_iter()
|
||||||
|
.map(|sk| (sk.clone(), if &sk == &SkillType::Dodge { 8.0 } else { 10.0 })).collect(),
|
||||||
attackable: false,
|
attackable: false,
|
||||||
aggression: 0,
|
aggression: 0,
|
||||||
intrinsic_weapon: None,
|
intrinsic_weapon: None,
|
||||||
@ -155,6 +156,7 @@ pub fn npc_static_items() -> Box<dyn Iterator<Item = StaticItem>> {
|
|||||||
is_static: true,
|
is_static: true,
|
||||||
pronouns: c.pronouns.clone(),
|
pronouns: c.pronouns.clone(),
|
||||||
is_challenge_attack_only: !c.attackable,
|
is_challenge_attack_only: !c.attackable,
|
||||||
|
total_xp: c.total_xp.clone(),
|
||||||
total_skills: c.total_skills.clone(),
|
total_skills: c.total_skills.clone(),
|
||||||
species: c.species.clone(),
|
species: c.species.clone(),
|
||||||
aliases: c.aliases.iter().map(|a| (*a).to_owned()).collect::<Vec<String>>(),
|
aliases: c.aliases.iter().map(|a| (*a).to_owned()).collect::<Vec<String>>(),
|
||||||
|
@ -54,13 +54,23 @@ impl Default for WeaponData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct PossessionData {
|
pub struct PossessionData {
|
||||||
pub weapon_data: Option<WeaponData>
|
pub weapon_data: Option<WeaponData>,
|
||||||
|
pub name: &'static str,
|
||||||
|
pub name_nonexp: Option<&'static str>,
|
||||||
|
#[allow(unused)]
|
||||||
|
pub display: &'static str,
|
||||||
|
#[allow(unused)]
|
||||||
|
pub display_nonexp: Option<&'static str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PossessionData {
|
impl Default for PossessionData {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
weapon_data: None
|
weapon_data: None,
|
||||||
|
name: "Thingy",
|
||||||
|
name_nonexp: None,
|
||||||
|
display: "A generic looking thing",
|
||||||
|
display_nonexp: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -93,6 +103,7 @@ pub enum PossessionType {
|
|||||||
// Special values that substitute for possessions.
|
// Special values that substitute for possessions.
|
||||||
Fangs, // Default weapon for certain animals
|
Fangs, // Default weapon for certain animals
|
||||||
// Real possessions from here on:
|
// Real possessions from here on:
|
||||||
|
AntennaWhip,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fist() -> &'static WeaponData {
|
pub fn fist() -> &'static WeaponData {
|
||||||
@ -156,6 +167,38 @@ pub fn possession_data() -> &'static BTreeMap<PossessionType, PossessionData> {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
}),
|
||||||
|
(AntennaWhip, PossessionData {
|
||||||
|
name: "Antenna whip",
|
||||||
|
display: "A crudely fashioned whip made from a broken metal antenna. It looks a bit flimsy, but it \
|
||||||
|
might do you until you get a better weapon!",
|
||||||
|
weapon_data: Some(WeaponData {
|
||||||
|
uses_skill: SkillType::Whips,
|
||||||
|
raw_min_to_learn: 0.0,
|
||||||
|
raw_max_to_learn: 2.0,
|
||||||
|
normal_attack_start_messages: vec!(
|
||||||
|
Box::new(|attacker, victim, exp|
|
||||||
|
format!("{} lines up {} antenna whip for a strike on {}",
|
||||||
|
&attacker.display_for_sentence(exp, 1, true),
|
||||||
|
&attacker.pronouns.possessive,
|
||||||
|
&victim.display_for_sentence(exp, 1, false),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
normal_attack_success_messages: vec!(
|
||||||
|
Box::new(|attacker, victim, part, exp|
|
||||||
|
format!("{}'s antenna whip scores a painful red line across {}'s {}",
|
||||||
|
&attacker.display_for_sentence(exp, 1, true),
|
||||||
|
&victim.display_for_sentence(exp, 1, false),
|
||||||
|
&part.display(victim.sex.clone())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
normal_attack_mean_damage: 3.0,
|
||||||
|
normal_attack_stdev_damage: 3.0,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
..Default::default()
|
||||||
})
|
})
|
||||||
).into_iter().collect()
|
).into_iter().collect()
|
||||||
})
|
})
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
use super::StaticItem;
|
use super::{
|
||||||
|
StaticItem,
|
||||||
|
possession_type::PossessionType,
|
||||||
|
};
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
@ -6,7 +9,9 @@ use serde::{Serialize, Deserialize};
|
|||||||
use crate::message_handler::user_commands::{
|
use crate::message_handler::user_commands::{
|
||||||
UResult, VerbContext
|
UResult, VerbContext
|
||||||
};
|
};
|
||||||
use crate::models::item::{Item, ItemFlag};
|
use crate::{
|
||||||
|
models::item::{Item, ItemFlag}
|
||||||
|
};
|
||||||
|
|
||||||
mod repro_xv;
|
mod repro_xv;
|
||||||
mod melbs;
|
mod melbs;
|
||||||
@ -145,6 +150,20 @@ pub struct SecondaryZoneRecord {
|
|||||||
pub caption: Option<&'static str>
|
pub caption: Option<&'static str>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct RoomStock {
|
||||||
|
pub possession_type: PossessionType,
|
||||||
|
pub list_price: f64
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for RoomStock {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
possession_type: PossessionType::AntennaWhip,
|
||||||
|
list_price: 1000000000.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Room {
|
pub struct Room {
|
||||||
pub zone: &'static str,
|
pub zone: &'static str,
|
||||||
// Other zones where it can be seen on the map and accessed.
|
// Other zones where it can be seen on the map and accessed.
|
||||||
@ -158,7 +177,9 @@ pub struct Room {
|
|||||||
pub exits: Vec<Exit>,
|
pub exits: Vec<Exit>,
|
||||||
pub should_caption: bool,
|
pub should_caption: bool,
|
||||||
pub repel_npc: bool,
|
pub repel_npc: bool,
|
||||||
pub item_flags: Vec<ItemFlag>
|
pub item_flags: Vec<ItemFlag>,
|
||||||
|
// Empty means not a shop.
|
||||||
|
pub stock_list: Vec<RoomStock>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Room {
|
impl Default for Room {
|
||||||
@ -176,6 +197,7 @@ impl Default for Room {
|
|||||||
should_caption: true,
|
should_caption: true,
|
||||||
repel_npc: false,
|
repel_npc: false,
|
||||||
item_flags: vec!(),
|
item_flags: vec!(),
|
||||||
|
stock_list: vec!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
use super::{
|
use super::{
|
||||||
Room, GridCoords, Exit, Direction, ExitTarget, ExitType,
|
Room, RoomStock, GridCoords, Exit, Direction, ExitTarget, ExitType,
|
||||||
SecondaryZoneRecord
|
SecondaryZoneRecord
|
||||||
};
|
};
|
||||||
use crate::models::item::ItemFlag;
|
use crate::{
|
||||||
|
models::item::ItemFlag,
|
||||||
|
static_content::possession_type::PossessionType
|
||||||
|
};
|
||||||
use ansi::ansi;
|
use ansi::ansi;
|
||||||
|
|
||||||
pub fn room_list() -> Vec<Room> {
|
pub fn room_list() -> Vec<Room> {
|
||||||
@ -1707,10 +1710,41 @@ pub fn room_list() -> Vec<Room> {
|
|||||||
target: ExitTarget::UseGPS,
|
target: ExitTarget::UseGPS,
|
||||||
exit_type: ExitType::Free
|
exit_type: ExitType::Free
|
||||||
},
|
},
|
||||||
|
Exit {
|
||||||
|
direction: Direction::SOUTH,
|
||||||
|
target: ExitTarget::UseGPS,
|
||||||
|
exit_type: ExitType::Free
|
||||||
|
},
|
||||||
),
|
),
|
||||||
should_caption: false,
|
should_caption: false,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
Room {
|
||||||
|
zone: "melbs",
|
||||||
|
secondary_zones: vec!(),
|
||||||
|
code: "melbs_mckillocks_self_defence",
|
||||||
|
name: "McKillock's Self Defence",
|
||||||
|
short: ansi!("<red>MS<reset>"),
|
||||||
|
description: ansi!("A neatly painted shop with bars covering the window, and a mean looking shop-keeper sitting behind a desk. [Use <bold>list<reset> to see stock for sale here]"),
|
||||||
|
description_less_explicit: None,
|
||||||
|
grid_coords: GridCoords { x: 3, y: 0, z: 0 },
|
||||||
|
exits: vec!(
|
||||||
|
Exit {
|
||||||
|
direction: Direction::NORTH,
|
||||||
|
target: ExitTarget::UseGPS,
|
||||||
|
exit_type: ExitType::Free
|
||||||
|
},
|
||||||
|
),
|
||||||
|
should_caption: true,
|
||||||
|
stock_list: vec!(
|
||||||
|
RoomStock {
|
||||||
|
possession_type: PossessionType::AntennaWhip,
|
||||||
|
list_price: 100.0,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
Room {
|
Room {
|
||||||
zone: "melbs",
|
zone: "melbs",
|
||||||
secondary_zones: vec!(),
|
secondary_zones: vec!(),
|
||||||
|
Loading…
Reference in New Issue
Block a user