Implement buying possessions.
This commit is contained in:
parent
722757468f
commit
985f93ca08
@ -11,6 +11,7 @@ use std::sync::Arc;
|
||||
|
||||
mod agree;
|
||||
pub mod attack;
|
||||
mod buy;
|
||||
mod describe;
|
||||
mod help;
|
||||
mod ignore;
|
||||
@ -100,6 +101,7 @@ static REGISTERED_COMMANDS: UserVerbRegistry = phf_map! {
|
||||
|
||||
// Other commands (alphabetical except aliases grouped):
|
||||
"attack" => attack::VERB,
|
||||
"buy" => buy::VERB,
|
||||
"kill" => attack::VERB,
|
||||
"k" => attack::VERB,
|
||||
|
||||
|
86
blastmud_game/src/message_handler/user_commands/buy.rs
Normal file
86
blastmud_game/src/message_handler/user_commands/buy.rs
Normal file
@ -0,0 +1,86 @@
|
||||
use super::{
|
||||
VerbContext, UserVerb, UserVerbRef, UResult, user_error,
|
||||
get_player_item_or_fail,
|
||||
parsing::parse_offset,
|
||||
};
|
||||
use crate::{
|
||||
static_content::room,
|
||||
static_content::possession_type::possession_data,
|
||||
models::item::Item,
|
||||
};
|
||||
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 listen when you try to buy... 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 buy anything 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 buy anything because you're not in a shop.".to_owned())?
|
||||
}
|
||||
|
||||
let (offset_m, remaining) = parse_offset(remaining);
|
||||
let mut offset_remaining = offset_m.unwrap_or(1);
|
||||
let match_item = remaining.trim().to_lowercase();
|
||||
|
||||
if match_item == "" {
|
||||
user_error("You need to specify what to buy.".to_owned())?
|
||||
}
|
||||
|
||||
for stock in &room.stock_list {
|
||||
if let Some(possession_type) = possession_data().get(&stock.possession_type) {
|
||||
if possession_type.display.to_lowercase().starts_with(&match_item) ||
|
||||
possession_type.display_less_explicit.map(|d| d.to_lowercase().starts_with(&match_item)).unwrap_or(false) ||
|
||||
possession_type.aliases.iter().any(|al| al.starts_with(&match_item)) {
|
||||
if offset_remaining <= 1 {
|
||||
if let Some(mut user) = ctx.user_dat.as_mut() {
|
||||
if user.credits < stock.list_price {
|
||||
user_error("You don't have enough credits to buy that!".to_owned())?;
|
||||
}
|
||||
user.credits -= stock.list_price;
|
||||
let item_code = ctx.trans.alloc_item_code().await?;
|
||||
let new_item = Item {
|
||||
item_type: "possession".to_owned(),
|
||||
item_code: format!("{}", item_code),
|
||||
possession_type: Some(stock.possession_type.clone()),
|
||||
display: possession_type.display.to_owned(),
|
||||
display_less_explicit: possession_type.display_less_explicit.map(|d| d.to_owned()),
|
||||
details: Some(possession_type.details.to_owned()),
|
||||
details_less_explicit: possession_type.details_less_explicit.map(|d| d.to_owned()),
|
||||
aliases: possession_type.aliases.iter().map(|al| (*al).to_owned()).collect(),
|
||||
location: format!("player/{}", &player_item.item_code),
|
||||
health: possession_type.max_health,
|
||||
..Default::default()
|
||||
};
|
||||
ctx.trans.create_item(&new_item).await?;
|
||||
ctx.trans.queue_for_session(
|
||||
&ctx.session,
|
||||
Some(&format!("Your wristpad beeps for a deduction of {} credits.\n", stock.list_price))
|
||||
).await?;
|
||||
}
|
||||
return Ok(());
|
||||
} else {
|
||||
offset_remaining -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
user_error(ansi!("That doesn't seem to be for sale. Try <bold>list<reset>").to_owned())
|
||||
}
|
||||
}
|
||||
static VERB_INT: Verb = Verb;
|
||||
pub static VERB: UserVerbRef = &VERB_INT as UserVerbRef;
|
@ -35,10 +35,13 @@ impl UserVerb for Verb {
|
||||
|
||||
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))
|
||||
let display = if ctx.session_dat.less_explicit_mode {
|
||||
possession_type.display_less_explicit.as_ref().unwrap_or(&possession_type.display)
|
||||
} else { &possession_type.display };
|
||||
msg.push_str(&format!("| {:20} | {:15.2} |\n", display, &stock.list_price))
|
||||
}
|
||||
}
|
||||
msg.push('\n');
|
||||
msg.push_str(ansi!("\nUse <bold>buy<reset> item to purchase something.\n"));
|
||||
ctx.trans.queue_for_session(&ctx.session, Some(&msg)).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ use std::collections::BTreeMap;
|
||||
use crate::{
|
||||
language,
|
||||
static_content::species::SpeciesType,
|
||||
static_content::possession_type::PossessionType,
|
||||
};
|
||||
use super::session::Session;
|
||||
|
||||
@ -278,6 +279,7 @@ impl Default for ActiveCombat {
|
||||
pub struct Item {
|
||||
pub item_code: String,
|
||||
pub item_type: String,
|
||||
pub possession_type: Option<PossessionType>,
|
||||
pub display: String,
|
||||
pub display_less_explicit: Option<String>,
|
||||
pub details: Option<String>,
|
||||
@ -351,6 +353,7 @@ impl Default for Item {
|
||||
Self {
|
||||
item_code: "unset".to_owned(),
|
||||
item_type: "unset".to_owned(),
|
||||
possession_type: None,
|
||||
display: "Item".to_owned(),
|
||||
display_less_explicit: None,
|
||||
details: None,
|
||||
|
@ -35,8 +35,8 @@ pub struct User {
|
||||
pub raw_skills: BTreeMap<SkillType, f64>,
|
||||
pub raw_stats: BTreeMap<StatType, f64>,
|
||||
pub last_skill_improve: BTreeMap<SkillType, DateTime<Utc>>,
|
||||
// Reminder: Consider backwards compatibility when updating this. New fields should generally
|
||||
// be an Option, or things will crash out for existing sessions.
|
||||
pub credits: u64,
|
||||
// Reminder: Consider backwards compatibility when updating this.
|
||||
}
|
||||
|
||||
impl Default for UserTermData {
|
||||
@ -77,6 +77,7 @@ impl Default for User {
|
||||
raw_skills: BTreeMap::new(),
|
||||
raw_stats: BTreeMap::new(),
|
||||
last_skill_improve: BTreeMap::new(),
|
||||
credits: 500
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,22 +55,24 @@ impl Default for WeaponData {
|
||||
|
||||
pub struct PossessionData {
|
||||
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>,
|
||||
pub display: &'static str,
|
||||
pub display_less_explicit: Option<&'static str>,
|
||||
pub details: &'static str,
|
||||
pub details_less_explicit: Option<&'static str>,
|
||||
pub aliases: Vec<&'static str>,
|
||||
pub max_health: u64,
|
||||
}
|
||||
|
||||
impl Default for PossessionData {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
weapon_data: None,
|
||||
name: "Thingy",
|
||||
name_nonexp: None,
|
||||
display: "A generic looking thing",
|
||||
display_nonexp: None,
|
||||
display: "Thingy",
|
||||
display_less_explicit: None,
|
||||
details: "A generic looking thing",
|
||||
details_less_explicit: None,
|
||||
aliases: vec!(),
|
||||
max_health: 10,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -169,9 +171,10 @@ pub fn possession_data() -> &'static BTreeMap<PossessionType, PossessionData> {
|
||||
..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 \
|
||||
display: "Antenna whip",
|
||||
details: "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!",
|
||||
aliases: vec!("whip"),
|
||||
weapon_data: Some(WeaponData {
|
||||
uses_skill: SkillType::Whips,
|
||||
raw_min_to_learn: 0.0,
|
||||
|
@ -152,14 +152,14 @@ pub struct SecondaryZoneRecord {
|
||||
|
||||
pub struct RoomStock {
|
||||
pub possession_type: PossessionType,
|
||||
pub list_price: f64
|
||||
pub list_price: u64
|
||||
}
|
||||
|
||||
impl Default for RoomStock {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
possession_type: PossessionType::AntennaWhip,
|
||||
list_price: 1000000000.0
|
||||
list_price: 1000000000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1739,7 +1739,7 @@ pub fn room_list() -> Vec<Room> {
|
||||
stock_list: vec!(
|
||||
RoomStock {
|
||||
possession_type: PossessionType::AntennaWhip,
|
||||
list_price: 100.0,
|
||||
list_price: 100,
|
||||
..Default::default()
|
||||
}
|
||||
),
|
||||
|
Loading…
Reference in New Issue
Block a user