Implement capacity limit system.
This commit is contained in:
parent
99ffe45479
commit
f21f574ebb
@ -61,6 +61,12 @@ pub struct OnlineInfo {
|
|||||||
pub time: Option<DateTime<Utc>>
|
pub time: Option<DateTime<Utc>>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct LocationStats {
|
||||||
|
pub total_count: u64,
|
||||||
|
pub total_weight: u64,
|
||||||
|
}
|
||||||
|
|
||||||
impl DBPool {
|
impl DBPool {
|
||||||
pub async fn record_listener_ping(self: &DBPool, listener: Uuid) -> DResult<()> {
|
pub async fn record_listener_ping(self: &DBPool, listener: Uuid) -> DResult<()> {
|
||||||
self.get_conn().await?.execute(
|
self.get_conn().await?.execute(
|
||||||
@ -622,6 +628,13 @@ impl DBTrans {
|
|||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_location_stats(&self, location: &str) -> DResult<LocationStats> {
|
||||||
|
Ok(serde_json::from_value(self.pg_trans()?.query_one(
|
||||||
|
"SELECT COUNT(*) AS total_count, SUM(details->>'weight') AS total_weight \
|
||||||
|
FROM items WHERE location = $1", &[&location]
|
||||||
|
).await?.get(0))?)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn commit(mut self: Self) -> DResult<()> {
|
pub async fn commit(mut self: Self) -> DResult<()> {
|
||||||
let trans_opt = self.with_trans_mut(|t| std::mem::replace(t, None));
|
let trans_opt = self.with_trans_mut(|t| std::mem::replace(t, None));
|
||||||
if let Some(trans) = trans_opt {
|
if let Some(trans) = trans_opt {
|
||||||
|
@ -7,6 +7,7 @@ use crate::{
|
|||||||
static_content::room,
|
static_content::room,
|
||||||
static_content::possession_type::possession_data,
|
static_content::possession_type::possession_data,
|
||||||
models::item::Item,
|
models::item::Item,
|
||||||
|
services::capacity::{check_item_capacity, CapacityLevel},
|
||||||
};
|
};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use ansi::ansi;
|
use ansi::ansi;
|
||||||
@ -51,19 +52,26 @@ impl UserVerb for Verb {
|
|||||||
user_error("You don't have enough credits to buy that!".to_owned())?;
|
user_error("You don't have enough credits to buy that!".to_owned())?;
|
||||||
}
|
}
|
||||||
user.credits -= stock.list_price;
|
user.credits -= stock.list_price;
|
||||||
|
let player_item_str = format!("player/{}", &player_item.item_code);
|
||||||
let item_code = ctx.trans.alloc_item_code().await?;
|
let item_code = ctx.trans.alloc_item_code().await?;
|
||||||
|
let loc = match check_item_capacity(ctx.trans, &player_item_str,
|
||||||
|
possession_type.weight).await? {
|
||||||
|
CapacityLevel::OverBurdened | CapacityLevel::AboveItemLimit => {
|
||||||
|
match check_item_capacity(ctx.trans, &player_item.location,
|
||||||
|
possession_type.weight).await? {
|
||||||
|
CapacityLevel::AboveItemLimit =>
|
||||||
|
user_error(
|
||||||
|
"You can't carry it, and there is too much stuff \
|
||||||
|
here already".to_owned())?,
|
||||||
|
_ => &player_item.location
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => &player_item_str
|
||||||
|
};
|
||||||
let new_item = Item {
|
let new_item = Item {
|
||||||
item_type: "possession".to_owned(),
|
|
||||||
item_code: format!("{}", item_code),
|
item_code: format!("{}", item_code),
|
||||||
possession_type: Some(stock.possession_type.clone()),
|
location: loc.to_owned(),
|
||||||
display: possession_type.display.to_owned(),
|
..stock.possession_type.clone().into()
|
||||||
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.create_item(&new_item).await?;
|
||||||
ctx.trans.queue_for_session(
|
ctx.trans.queue_for_session(
|
||||||
|
@ -301,6 +301,7 @@ pub struct Item {
|
|||||||
pub flags: Vec<ItemFlag>,
|
pub flags: Vec<ItemFlag>,
|
||||||
pub sex: Option<Sex>,
|
pub sex: Option<Sex>,
|
||||||
pub active_combat: Option<ActiveCombat>,
|
pub active_combat: Option<ActiveCombat>,
|
||||||
|
pub weight: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Item {
|
impl Item {
|
||||||
@ -375,6 +376,7 @@ impl Default for Item {
|
|||||||
flags: vec!(),
|
flags: vec!(),
|
||||||
sex: None,
|
sex: None,
|
||||||
active_combat: Some(Default::default()),
|
active_combat: Some(Default::default()),
|
||||||
|
weight: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use crate::{
|
|||||||
|
|
||||||
pub mod skills;
|
pub mod skills;
|
||||||
pub mod combat;
|
pub mod combat;
|
||||||
|
pub mod capacity;
|
||||||
pub async fn broadcast_to_room(trans: &DBTrans, location: &str, from_item: Option<&Item>,
|
pub async fn broadcast_to_room(trans: &DBTrans, location: &str, from_item: Option<&Item>,
|
||||||
message_explicit_ok: &str, message_nonexplicit: Option<&str>) -> DResult<()> {
|
message_explicit_ok: &str, message_nonexplicit: Option<&str>) -> DResult<()> {
|
||||||
for item in trans.find_items_by_location(location).await? {
|
for item in trans.find_items_by_location(location).await? {
|
||||||
|
36
blastmud_game/src/services/capacity.rs
Normal file
36
blastmud_game/src/services/capacity.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use crate::{
|
||||||
|
db::DBTrans,
|
||||||
|
DResult,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub enum CapacityLevel {
|
||||||
|
Unburdened,
|
||||||
|
SlightlyBurdened,
|
||||||
|
HeavilyBurdened,
|
||||||
|
OverBurdened,
|
||||||
|
AboveItemLimit,
|
||||||
|
}
|
||||||
|
pub async fn check_item_capacity(trans: &DBTrans,
|
||||||
|
container: &str,
|
||||||
|
proposed_weight: u64) -> DResult<CapacityLevel> {
|
||||||
|
let stats = trans.get_location_stats(
|
||||||
|
container
|
||||||
|
).await?;
|
||||||
|
if stats.total_count >= 50 || proposed_weight > 0 && stats.total_count >= 49 {
|
||||||
|
return Ok(CapacityLevel::AboveItemLimit);
|
||||||
|
}
|
||||||
|
if let Some((item_type, _item_code)) = container.split_once("/") {
|
||||||
|
if item_type == "player" || item_type == "npc" {
|
||||||
|
let max_weight = 20000; // TODO Calculate properly
|
||||||
|
let new_weight = stats.total_weight + proposed_weight;
|
||||||
|
if new_weight >= max_weight {
|
||||||
|
return Ok(CapacityLevel::OverBurdened);
|
||||||
|
} else if new_weight >= max_weight * 4 / 5 {
|
||||||
|
return Ok(CapacityLevel::HeavilyBurdened);
|
||||||
|
} else if new_weight >= max_weight / 2 {
|
||||||
|
return Ok(CapacityLevel::SlightlyBurdened);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(CapacityLevel::Unburdened)
|
||||||
|
}
|
@ -110,6 +110,24 @@ pub enum PossessionType {
|
|||||||
AntennaWhip,
|
AntennaWhip,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Into<Item> for PossessionType {
|
||||||
|
fn into(self) -> Item {
|
||||||
|
let possession_dat = possession_data().get(&self).unwrap();
|
||||||
|
Item {
|
||||||
|
item_type: "possession".to_owned(),
|
||||||
|
possession_type: Some(self.clone()),
|
||||||
|
display: possession_dat.display.to_owned(),
|
||||||
|
display_less_explicit: possession_dat.display_less_explicit.map(|d| d.to_owned()),
|
||||||
|
details: Some(possession_dat.details.to_owned()),
|
||||||
|
details_less_explicit: possession_dat.details_less_explicit.map(|d| d.to_owned()),
|
||||||
|
aliases: possession_dat.aliases.iter().map(|al| (*al).to_owned()).collect(),
|
||||||
|
health: possession_dat.max_health,
|
||||||
|
weight: possession_dat.weight,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn fist() -> &'static WeaponData {
|
pub fn fist() -> &'static WeaponData {
|
||||||
static FIST_WEAPON: OnceCell<WeaponData> = OnceCell::new();
|
static FIST_WEAPON: OnceCell<WeaponData> = OnceCell::new();
|
||||||
FIST_WEAPON.get_or_init(|| {
|
FIST_WEAPON.get_or_init(|| {
|
||||||
|
Loading…
Reference in New Issue
Block a user