2023-01-15 17:30:23 +11:00
use super ::{ VerbContext , UserVerb , UserVerbRef , UResult , user_error ,
get_player_item_or_fail , search_item_for_user } ;
use async_trait ::async_trait ;
use ansi ::ansi ;
use crate ::services ::broadcast_to_room ;
use crate ::db ::{ DBTrans , ItemSearchParams } ;
use crate ::models ::{ item ::{ Item , LocationActionType , Subattack } } ;
use async_recursion ::async_recursion ;
2023-01-15 23:16:02 +11:00
pub async fn stop_attacking ( trans : & DBTrans , by_whom : & Item , to_whom : & Item ) -> UResult < ( ) > {
let mut new_to_whom = ( * to_whom ) . clone ( ) ;
if let Some ( ac ) = new_to_whom . active_combat . as_mut ( ) {
let old_attacker = format! ( " {} / {} " , by_whom . item_type , by_whom . item_code ) ;
ac . attacked_by . retain ( | v | v ! = & old_attacker ) ;
trans . save_item_model ( & new_to_whom ) . await ? ;
}
let mut new_by_whom = ( * by_whom ) . clone ( ) ;
if let Some ( ac ) = new_by_whom . active_combat . as_mut ( ) {
ac . attacking = None ;
}
new_by_whom . action_type = LocationActionType ::Normal ;
trans . save_item_model ( & new_by_whom ) . await ? ;
Ok ( ( ) )
}
2023-01-15 17:30:23 +11:00
#[ async_recursion ]
2023-01-15 23:16:02 +11:00
pub async fn start_attack ( trans : & DBTrans , by_whom : & Item , to_whom : & Item ) -> UResult < ( ) > {
2023-01-15 17:30:23 +11:00
let mut msg_exp = String ::new ( ) ;
let mut msg_nonexp = String ::new ( ) ;
let mut verb : String = " attacks " . to_string ( ) ;
match by_whom . action_type {
LocationActionType ::Sitting | LocationActionType ::Reclining = > {
msg_exp . push_str ( & format! ( ansi! ( " {} stands up. \n " ) , & by_whom . display ) ) ;
msg_nonexp . push_str ( & format! ( ansi! ( " {} stands up. \n " ) ,
by_whom . display_less_explicit . as_ref ( ) . unwrap_or ( & by_whom . display ) ) ) ;
} ,
LocationActionType ::Attacking ( _ ) = > {
match by_whom . active_combat . as_ref ( ) . and_then ( | ac | ac . attacking . as_ref ( ) . and_then ( | s | s . split_once ( " / " ) ) ) {
Some ( ( cur_type , cur_code ) ) if cur_type = = to_whom . item_type & & cur_code = = to_whom . item_code = >
user_error ( format! ( " You're already attacking {} ! " , to_whom . pronouns . object ) ) ? ,
Some ( ( cur_type , cur_code ) ) = > {
if let Some ( cur_item_arc ) = trans . find_item_by_type_code ( cur_type , cur_code ) . await ? {
2023-01-15 23:16:02 +11:00
stop_attacking ( trans , by_whom , & cur_item_arc ) . await ? ;
2023-01-15 17:30:23 +11:00
}
}
_ = > { }
}
verb = " refocuses " . to_string ( ) + & by_whom . pronouns . possessive + " attacks on " ;
} ,
_ = > { }
}
msg_exp . push_str ( & format! (
ansi! ( " <red>{} {} {}.<reset> \n " ) ,
& by_whom . display_for_sentence ( true , 1 , true ) ,
verb ,
& to_whom . display_for_sentence ( true , 1 , false ) )
) ;
msg_nonexp . push_str ( & format! (
ansi! ( " <red>{} {} {}.<reset> \n " ) ,
& by_whom . display_for_sentence ( false , 1 , true ) ,
verb ,
& to_whom . display_for_sentence ( false , 1 , false ) )
) ;
broadcast_to_room ( trans , & by_whom . location , None , & msg_exp , Some ( msg_nonexp . as_str ( ) ) ) . await ? ;
let mut by_whom_for_update = by_whom . clone ( ) ;
by_whom_for_update . active_combat . get_or_insert_with ( | | Default ::default ( ) ) . attacking =
Some ( format! ( " {} / {} " ,
& to_whom . item_type , & to_whom . item_code ) ) ;
by_whom_for_update . action_type = LocationActionType ::Attacking ( Subattack ::Normal ) ;
let mut to_whom_for_update = to_whom . clone ( ) ;
to_whom_for_update . active_combat . get_or_insert_with ( | | Default ::default ( ) ) . attacked_by . push (
format! ( " {} / {} " ,
& by_whom . item_type , & by_whom . item_code )
) ;
trans . save_item_model ( & by_whom_for_update ) . await ? ;
trans . save_item_model ( & to_whom_for_update ) . await ? ;
// Auto-counterattack if victim isn't busy.
if to_whom_for_update . active_combat . as_ref ( ) . and_then ( | ac | ac . attacking . as_ref ( ) ) = = None {
start_attack ( trans , & to_whom_for_update , & by_whom_for_update ) . await ? ;
}
Ok ( ( ) )
}
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 ? ;
let attack_whom = search_item_for_user ( ctx , & ItemSearchParams {
include_loc_contents : true ,
.. ItemSearchParams ::base ( & player_item , remaining )
} ) . await ? ;
match attack_whom . item_type . as_str ( ) {
" npc " = > { }
" player " = > { } ,
_ = > user_error ( " Only characters (players / NPCs) accept whispers " . to_string ( ) ) ?
}
if attack_whom . item_code = = player_item . item_code & & attack_whom . item_type = = player_item . item_type {
user_error ( " That's you, silly! " . to_string ( ) ) ?
}
if attack_whom . is_challenge_attack_only {
// Add challenge check here.
user_error ( ansi! ( " <blue>Your wristpad vibrates and blocks you from doing that.<reset> You get a feeling that while the empire might be gone, the system to stop subjects with working wristpads from fighting each unless they have an accepted challenge very much functional. [Try <bold>help challenge<reset>] " ) . to_string ( ) ) ?
}
start_attack ( & ctx . trans , & player_item , & attack_whom ) . await
}
}
static VERB_INT : Verb = Verb ;
pub static VERB : UserVerbRef = & VERB_INT as UserVerbRef ;