diff --git a/blastmud_game/src/db.rs b/blastmud_game/src/db.rs index 9bdaf4be..23083959 100644 --- a/blastmud_game/src/db.rs +++ b/blastmud_game/src/db.rs @@ -1275,6 +1275,32 @@ impl DBTrans { } } + pub async fn find_corp_consent_by_consenting_corp_consented_user_type( + &self, + corp_consenting: &CorpId, + usr_consented: &str, + consent_type: &ConsentType, + ) -> DResult> { + match self + .pg_trans()? + .query_opt( + "SELECT cc.details FROM corp_consent cc \ + JOIN corp_membership cm_consented ON cc.consented_corp = cm_consented.corp_id \ + WHERE cc.consenting_corp = $1 AND \ + cm_consented.member_username = $2 AND cc.consent_type = $3", + &[ + &corp_consenting.0, + &usr_consented, + &ConsentType::to_str(consent_type), + ], + ) + .await? + { + None => Ok(None), + Some(row) => Ok(Some(serde_json::from_value(row.get(0))?)), + } + } + pub async fn revoke_until_death_consent(&self, party: &str) -> DResult<()> { self.pg_trans()? .execute( @@ -1444,6 +1470,27 @@ impl DBTrans { ) } + pub async fn find_corp_membership( + &self, + corp: &CorpId, + username: &str, + ) -> DResult> { + Ok( + match self + .pg_trans()? + .query_opt( + "SELECT m.details AS mdetails FROM corp_membership m WHERE m.corp_id = $1 \ + AND m.member_username = $2 LIMIT 1", + &[&corp.0, &(username.to_lowercase())], + ) + .await? + { + None => None, + Some(row) => Some(serde_json::from_value(row.get("mdetails"))?), + }, + ) + } + pub async fn create_corp(&self, details: &Corp) -> DResult { let id = self .pg_trans()? diff --git a/blastmud_game/src/message_handler/user_commands/help.rs b/blastmud_game/src/message_handler/user_commands/help.rs index a6d4cdef..7fcac94e 100644 --- a/blastmud_game/src/message_handler/user_commands/help.rs +++ b/blastmud_game/src/message_handler/user_commands/help.rs @@ -125,7 +125,8 @@ static REGISTERED_HELP_PAGES: phf::Map<&'static str, &'static str> = phf_map! { crit fail and do harm), gifts (lets them give you things), and \ visit (lets them on to a tile owned by you legally).\n\ \n\ - To allow, an individual, use the syntax allow type from player options\n\ + To allow, as an individual, use the syntax allow type from player options\n\ + As a corp, use the syntax allow type against corpname by corpname options\n\ Options can be blank to use defaults, or can be one or more of the following, separated by spaces:\n\ \tfor n minutes - replace n with a number. You can use hours, days, or weeks instead of minutes. This makes the consent expire. Fight expires after a week if you don't give a shorter period, and all other consent types have no expiry unless you specify one.\n\ \tuntil death - makes the consent valid only until you next die.\n\ @@ -258,7 +259,8 @@ static EXPLICIT_HELP_PAGES: phf::Map<&'static str, &'static str> = phf_map! { visit (lets them on to a tile owned by you legally), and fuck \ (lets them do fun but dirty things to you).\n\ \n\ - To allow, an individual, use the syntax allow type from player options\n\ + To allow, as an individual, use the syntax allow type from player options\n\ + As a corp, use the syntax allow type against corpname by corpname options\n\ Options can be blank to use defaults, or can be one or more of the following, separated by spaces:\n\ \tuntil n minutes - replace n with a number. You can use hours, days, or weeks instead of minutes. This makes the consent expire. Fight expires after a week if you don't give a shorter period, and all other consent types have no expiry unless you specify one.\n\ \tuntil death - makes the consent valid only until you next die.\n\ diff --git a/blastmud_game/src/message_handler/user_commands/movement.rs b/blastmud_game/src/message_handler/user_commands/movement.rs index 0e2398e7..c52ed2b3 100644 --- a/blastmud_game/src/message_handler/user_commands/movement.rs +++ b/blastmud_game/src/message_handler/user_commands/movement.rs @@ -20,7 +20,7 @@ use crate::{ queue_command, MovementSource, QueueCommand, QueueCommandHandler, QueuedCommandContext, }, services::{ - check_consent, + check_consent, check_one_consent, combat::{change_health, handle_resurrect, stop_attacking_mut}, comms::broadcast_to_room, skills::skill_check_and_grind, @@ -225,29 +225,62 @@ pub async fn check_room_access(trans: &DBTrans, player: &Item, room: &Item) -> U if owner_t == &player.item_type && owner_c == &player.item_code { return Ok(()); } - let owner = match trans.find_item_by_type_code(owner_t, owner_c).await? { - None => return Ok(()), - Some(v) => v, - }; - if check_consent(trans, "enter", &ConsentType::Visit, player, &owner).await? { - return Ok(()); - } + if owner_t == "corp" { + let corp = match trans.find_corp_by_name(owner_c).await? { + None => return Ok(()), // Defunct corp HQ somehow... + Some(v) => v, + }; + if trans + .find_corp_membership(&corp.0, &player.item_code) + .await? + .map(|cm| cm.joined_at.is_some()) + .unwrap_or(false) + { + // Corp members pass the check. + return Ok(()); + } + let consent_opt = trans + .find_corp_consent_by_consenting_corp_consented_user_type( + &corp.0, + &player.item_code, + &ConsentType::Fight, + ) + .await?; + let mut player_hypothet = (*player).clone(); + player_hypothet.location = room.refstr(); + if consent_opt + .as_ref() + .map(|c| check_one_consent(c, "enter", &player_hypothet)) + .unwrap_or(false) + { + return Ok(()); + } + } else { + let owner = match trans.find_item_by_type_code(owner_t, owner_c).await? { + None => return Ok(()), + Some(v) => v, + }; - let mut player_hypothet = (*player).clone(); - // We are asking hypothetically if they entered the room, could they fight - // the owner? We won't save this yet. - player_hypothet.location = room.refstr(); - if check_consent( - trans, - "enter", - &ConsentType::Fight, - &player_hypothet, - &owner, - ) - .await? - { - return Ok(()); + if check_consent(trans, "enter", &ConsentType::Visit, player, &owner).await? { + return Ok(()); + } + + let mut player_hypothet = (*player).clone(); + // We are asking hypothetically if they entered the room, could they fight + // the owner? We won't save this yet. + player_hypothet.location = room.refstr(); + if check_consent( + trans, + "enter", + &ConsentType::Fight, + &player_hypothet, + &owner, + ) + .await? + { + return Ok(()); + } } user_error(ansi!("Your wristpad buzzes and your muscles lock up, stopping you entering. \ diff --git a/blastmud_game/src/services.rs b/blastmud_game/src/services.rs index e1249cf6..f9af7890 100644 --- a/blastmud_game/src/services.rs +++ b/blastmud_game/src/services.rs @@ -24,7 +24,7 @@ pub mod skills; pub mod spawn; pub mod urges; -fn check_one_consent(consent: &Consent, action: &str, target: &Item) -> bool { +pub fn check_one_consent(consent: &Consent, action: &str, target: &Item) -> bool { if let Some((loctype, loccode)) = target.location.split_once("/") { if !consent.only_in.is_empty() { if loctype != "room" || !consent.only_in.iter().any(|v| v == loccode) { diff --git a/blastmud_game/src/static_content/dynzone/murl_deluxe_corporate.rs b/blastmud_game/src/static_content/dynzone/murl_deluxe_corporate.rs index 67ea7cf2..ef5fc2d4 100644 --- a/blastmud_game/src/static_content/dynzone/murl_deluxe_corporate.rs +++ b/blastmud_game/src/static_content/dynzone/murl_deluxe_corporate.rs @@ -11,7 +11,7 @@ pub fn zone() -> Dynzone { ("reception", Dynroom { subcode: "reception", name: "Reception", - short: "DS", + short: "RC", description: "A narrow public area of the corporate suite, with views \ of the bleak wasteland to the north. The walls are painted white, and a long reception \ desk, enamelled to look like dark wood, is built into the room. It is well lit \