From b6ed5ea4872ed8f823b8727f5769c3a9b7fde5e3 Mon Sep 17 00:00:00 2001 From: Condorra Date: Sun, 9 Apr 2023 23:12:51 +1000 Subject: [PATCH] Implement lmap command for dynzones. --- .../src/message_handler/user_commands/map.rs | 201 +++++++++++++++++- .../dynzone/cokmurl_apartment.rs | 4 +- 2 files changed, 197 insertions(+), 8 deletions(-) diff --git a/blastmud_game/src/message_handler/user_commands/map.rs b/blastmud_game/src/message_handler/user_commands/map.rs index 0bd7a4e..a4abc31 100644 --- a/blastmud_game/src/message_handler/user_commands/map.rs +++ b/blastmud_game/src/message_handler/user_commands/map.rs @@ -3,8 +3,11 @@ use super::{VerbContext, UserVerb, UserVerbRef, UResult, UserError, user_error, use async_trait::async_trait; use ansi::{ansi, flow_around}; use crate::{ - models::item::Item, - static_content::room::{self, Direction} + models::item::{Item, ItemSpecialData}, + static_content::{ + room::{self, Direction, GridCoords}, + dynzone::self + } }; use std::sync::Arc; @@ -91,7 +94,139 @@ pub fn render_lmap(room: &room::Room, width: usize, height: usize, buf } -pub fn caption_lmap(captions: &Vec<(usize, &'static str, &'static str)>, width: usize, height: usize) -> String { +pub fn render_lmap_dynroom<'l, 'm>( + zone: &'l dynzone::Dynzone, + room: &'l dynzone::Dynroom, + width: usize, + height: usize, + captions_needed: &'m mut Vec<(usize, &'l str, &'l str)>, + connectwhere: Option<&'l str> +) -> String { + let mut buf = String::new(); + let my_loc = &room.grid_coords; + let min_x = my_loc.x - (width as i64) / 2; + let max_x = min_x + (width as i64); + let min_y = my_loc.y - (height as i64) / 2; + let max_y = min_y + (height as i64); + + let main_exit_dat: Option<(GridCoords, Direction)> = zone.dyn_rooms + .iter() + .flat_map(|(_, dr)| + dr.exits.iter() + .filter(|ex| match ex.target { + dynzone::ExitTarget::ExitZone => true, + _ => false + }) + .map(|ex| (dr.grid_coords.apply(&ex.direction), ex.direction.clone())) + ).next(); + let main_exit = main_exit_dat.as_ref(); + + for y in min_y..max_y { + for x in min_x..max_x { + let coord = room::GridCoords { x, y, z: my_loc.z }; + let coord_room: Option<&dynzone::Dynroom> = + zone.dyn_rooms.iter() + .find( + |(_, dr)| dr.grid_coords.x == x && + dr.grid_coords.y == y && + dr.grid_coords.z == my_loc.z) + .map(|(_, r)| r); + if my_loc.x == x && my_loc.y == y { + buf.push_str(ansi!(" () ")); + if let Some(room) = coord_room { + if room.should_caption { + captions_needed.push( + ( + (((my_loc.x as i64 - room.grid_coords.x).abs() + + (my_loc.y as i64 - room.grid_coords.y).abs()) as usize), + room.short, room.name + ) + ); + } + } + } else if let Some(room) = coord_room { + if room.should_caption { + captions_needed.push( + ( + (((my_loc.x as i64 - room.grid_coords.x).abs() + + (my_loc.y as i64 - room.grid_coords.y).abs()) as usize), + room.short, room.name + ) + ); + } + buf.push('['); + buf.push_str(room.short); + buf.push(']'); + match room.exits.iter().find(|ex| ex.direction == Direction::EAST) { + None => buf.push(' '), + Some(_) => buf.push('-') + } + } else if main_exit.map(|ex| &ex.0) == Some(&coord) { + buf.push_str("[<<]"); + match main_exit { + Some((ex_coord, Direction::WEST)) => { + buf.push('-'); + if let Some(connect) = connectwhere { + captions_needed.push(( + ((my_loc.x as i64 - ex_coord.x).abs() + (my_loc.y as i64 - ex_coord.y).abs()) + as usize, + "<<", connect + )) + } + }, + _ => buf.push(' ') + } + } else { + buf.push_str(" "); + } + } + for x in min_x..max_x { + let mut coord = room::GridCoords { x, y, z: my_loc.z }; + let coord_room: Option<&'l dynzone::Dynroom> = + zone.dyn_rooms.iter() + .find( + |(_, dr)| dr.grid_coords.x == x && + dr.grid_coords.y == y && + dr.grid_coords.z == my_loc.z) + .map(|(_, r)| r); + match coord_room.and_then( + |r| r.exits.iter().find(|ex| ex.direction == Direction::SOUTH)) { + Some(_) => buf.push_str(" | "), + None if main_exit == Some(&(coord.clone(), Direction::NORTH)) => + buf.push_str(" | "), + None => buf.push_str(" "), + } + let has_se = coord_room.and_then( + |r| r.exits.iter().find(|ex| ex.direction == Direction::SOUTHEAST)) + .is_some() || (main_exit == Some(&(coord.clone(), Direction::NORTHWEST))); + coord.y += 1; + let coord_room_s = + zone.dyn_rooms.iter() + .find( + |(_, dr)| dr.grid_coords.x == x && + dr.grid_coords.y == y && + dr.grid_coords.z == my_loc.z) + .map(|(_, r)| r); + let has_ne = coord_room_s.and_then( + |r| r.exits.iter().find(|ex| ex.direction == Direction::NORTHEAST)) + .is_some() || (main_exit == Some(&(coord, Direction::SOUTHWEST))); + if has_se && has_ne { + buf.push('X'); + } else if has_se { + buf.push('\\'); + } else if has_ne { + buf.push('/'); + } else { + buf.push(' '); + } + } + buf.push('\n'); + } + captions_needed.sort_unstable_by(|a, b| a.0.cmp(&b.0)); + buf +} + +pub fn caption_lmap<'l>(captions: &Vec<(usize, &'l str, &'l str)>, width: usize, height: usize) -> String { let mut buf = String::new(); for room in captions.iter().take(height) { buf.push_str(&format!(ansi!("{}: {:.*}\n"), room.1, width, room.2)); @@ -111,6 +246,48 @@ pub async fn lmap_room(ctx: &VerbContext<'_>, Ok(()) } +pub async fn lmap_room_dyn<'a>( + ctx: &VerbContext<'_>, + zone: &'a dynzone::Dynzone, + room: &'a dynzone::Dynroom, + zoneref: &str +) -> UResult<()> { + let mut captions: Vec<(usize, &str, &str)> = Vec::new(); + let connectwhere_name_opt: Option = match zoneref.split_once("/") { + None => None, + Some((zone_t, zone_c)) => { + let zone_item: Option> = ctx.trans.find_item_by_type_code(zone_t, zone_c).await?; + match zone_item.as_ref().map(|v| v.as_ref()) { + Some(Item { special_data: Some(ItemSpecialData::DynzoneData { zone_exit: Some(zone_exit), ..}), + ..}) => + match zone_exit.split_once("/") { + None => None, + Some((ex_t, ex_c)) => + match ctx.trans.find_item_by_type_code(ex_t, ex_c).await?.as_ref() { + Some(dest_item) => Some( + dest_item.display_for_sentence( + !ctx.session_dat.less_explicit_mode, 1, true + )), + None => None + } + }, + _ => None, + } + } + }; + let lmap_str = + render_lmap_dynroom(zone, room, 9, 7, &mut captions, + connectwhere_name_opt.as_ref().map(|v| v.as_str())); + ctx.trans.queue_for_session( + ctx.session, + Some(&flow_around(&lmap_str, + 45, ansi!(" "), + &caption_lmap(&captions, 14, 27), 31 + )) + ).await?; + Ok(()) +} + pub struct Verb; #[async_trait] impl UserVerb for Verb { @@ -122,13 +299,25 @@ impl UserVerb for Verb { let (heretype, herecode) = player_item.location.split_once("/").unwrap_or(("room", "repro_xv_chargen")); let room_item: Arc = ctx.trans.find_item_by_type_code(heretype, herecode).await? .ok_or_else(|| UserError("Sorry, that no longer exists".to_owned()))?; - if room_item.item_type != "room" { - user_error("Can't map here".to_owned())?; - } else { + if room_item.item_type == "room" { let room = room::room_map_by_code().get(room_item.item_code.as_str()) .ok_or_else(|| UserError("Sorry, that room no longer exists".to_owned()))?; lmap_room(ctx, &room).await?; + } else if room_item.item_type == "dynroom" { + let (dynzone, dynroom) = match &room_item.special_data { + Some(ItemSpecialData::DynroomData { dynzone_code, dynroom_code }) => { + dynzone::DynzoneType::from_str(dynzone_code.as_str()) + .and_then(|dz_t| + dynzone::dynzone_by_type().get(&dz_t)) + .and_then(|dz| dz.dyn_rooms.get(dynroom_code.as_str()).map(|dr| (dz, dr))) + .ok_or_else(|| UserError("Dynamic room doesn't exist anymore.".to_owned()))? + }, + _ => user_error("Expected dynroom to have DynroomData".to_owned())? + }; + lmap_room_dyn(ctx, &dynzone, &dynroom, &room_item.location).await?; + } else { + user_error("Can't map here".to_owned())?; } Ok(()) } diff --git a/blastmud_game/src/static_content/dynzone/cokmurl_apartment.rs b/blastmud_game/src/static_content/dynzone/cokmurl_apartment.rs index f808330..f9c3aaa 100644 --- a/blastmud_game/src/static_content/dynzone/cokmurl_apartment.rs +++ b/blastmud_game/src/static_content/dynzone/cokmurl_apartment.rs @@ -34,7 +34,7 @@ pub fn zone() -> Dynzone { } ), grid_coords: GridCoords { x: 0, y: 0, z: 0 }, - should_caption: false, + should_caption: true, item_flags: vec!(), ..Default::default() }), @@ -52,7 +52,7 @@ pub fn zone() -> Dynzone { } ), grid_coords: GridCoords { x: 1, y: 0, z: 0 }, - should_caption: false, + should_caption: true, item_flags: vec!(), ..Default::default() })