2020-04-21 23:15:11 -06:00
use libpso ::packet ::ship ::* ;
2020-05-24 15:59:48 -06:00
use libpso ::packet ::messages ::* ;
2020-04-21 23:15:11 -06:00
use crate ::common ::serverstate ::ClientId ;
use crate ::common ::leveltable ::CharacterLevelTable ;
2020-05-02 22:08:37 -03:00
use crate ::ship ::ship ::{ SendShipPacket , ShipError , Rooms , Clients } ;
use crate ::ship ::location ::{ ClientLocation , RoomId , RoomLobby , ClientLocationError } ;
2020-04-24 20:38:56 -06:00
use crate ::ship ::packet ::builder ;
2020-04-21 23:15:11 -06:00
use crate ::ship ::room ;
2020-05-13 22:32:30 -06:00
use crate ::ship ::items ::ItemManager ;
2021-05-23 18:18:36 +00:00
use std ::convert ::{ TryFrom } ;
2020-04-21 23:15:11 -06:00
pub fn create_room ( id : ClientId ,
create_room : & CreateRoom ,
client_location : & mut ClientLocation ,
2020-04-22 23:49:49 -06:00
clients : & mut Clients ,
2020-05-13 22:32:30 -06:00
item_manager : & mut ItemManager ,
2021-05-23 18:18:36 +00:00
level_table : & CharacterLevelTable ,
2020-04-21 23:15:11 -06:00
rooms : & mut Rooms )
2021-05-23 18:18:36 +00:00
-> Result < Box < dyn Iterator < Item = ( ClientId , SendShipPacket ) > + Send > , anyhow ::Error > {
let client = clients . get ( & id ) . ok_or ( ShipError ::ClientNotFound ( id ) ) ? ;
let level = level_table . get_level_from_exp ( client . character . char_class , client . character . exp ) ;
match room ::Difficulty ::try_from ( create_room . difficulty ) ? {
room ::Difficulty ::Ultimate = > {
if level < 80 {
2021-06-22 23:23:22 +00:00
return Ok ( Box ::new ( vec! [ ( id , SendShipPacket ::SmallDialog ( SmallDialog ::new ( " You must be at least level 80 \n to create Ultimate rooms. " . into ( ) ) ) ) ] . into_iter ( ) ) )
2021-05-23 18:18:36 +00:00
}
} ,
room ::Difficulty ::VeryHard = > {
if level < 40 {
2021-06-22 23:23:22 +00:00
return Ok ( Box ::new ( vec! [ ( id , SendShipPacket ::SmallDialog ( SmallDialog ::new ( " You must be at least level 40 \n to create Very Hard rooms. " . into ( ) ) ) ) ] . into_iter ( ) ) )
2021-05-23 18:18:36 +00:00
}
} ,
room ::Difficulty ::Hard = > {
if level < 20 {
2021-06-22 23:23:22 +00:00
return Ok ( Box ::new ( vec! [ ( id , SendShipPacket ::SmallDialog ( SmallDialog ::new ( " You must be at least level 20 \n to create Hard rooms. " . into ( ) ) ) ) ] . into_iter ( ) ) )
2021-05-23 18:18:36 +00:00
}
} ,
2021-06-23 01:03:54 +00:00
room ::Difficulty ::Normal = > { } ,
2021-05-23 18:18:36 +00:00
} ;
2020-04-21 23:15:11 -06:00
let area = client_location . get_area ( id ) . unwrap ( ) ;
let area_client = client_location . get_local_client ( id ) . unwrap ( ) ;
let lobby_neighbors = client_location . get_client_neighbors ( id ) . unwrap ( ) ;
let room_id = client_location . create_new_room ( id ) . unwrap ( ) ;
let mut room = room ::RoomState ::from_create_room ( create_room , client . character . section_id ) . unwrap ( ) ;
room . bursting = true ;
2020-05-13 22:32:30 -06:00
item_manager . add_character_to_room ( room_id , & client . character , area_client ) ;
2020-04-24 20:38:56 -06:00
let join_room = builder ::room ::join_room ( id , clients , client_location , room_id , & room ) ? ;
2020-04-21 23:15:11 -06:00
rooms [ room_id . 0 ] = Some ( room ) ;
2020-04-24 22:22:19 -06:00
let mut result : Box < dyn Iterator < Item = ( ClientId , SendShipPacket ) > + Send > = Box ::new (
vec! [ ( id , SendShipPacket ::JoinRoom ( join_room ) ) ] . into_iter ( )
) ;
if let Ok ( leader ) = client_location . get_area_leader ( area ) {
let leave_lobby = SendShipPacket ::LeaveLobby ( LeaveLobby ::new ( area_client . local_client . id ( ) , leader . local_client . id ( ) ) ) ;
result = Box ::new ( result . chain ( lobby_neighbors
. into_iter ( )
. map ( move | c | {
( c . client , leave_lobby . clone ( ) )
} ) ) ) ;
2020-04-21 23:15:11 -06:00
}
2020-04-24 22:22:19 -06:00
Ok ( result )
2020-04-21 23:15:11 -06:00
}
pub fn room_name_request ( id : ClientId ,
client_location : & ClientLocation ,
rooms : & Rooms )
-> Box < dyn Iterator < Item = ( ClientId , SendShipPacket ) > + Send > {
let area = client_location . get_area ( id ) . unwrap ( ) ;
match area {
RoomLobby ::Room ( room ) = > Box ::new ( vec! [ ( id , SendShipPacket ::RoomNameResponse ( RoomNameResponse { name : rooms [ room . 0 ] . as_ref ( ) . unwrap ( ) . name . clone ( ) } ) ) ] . into_iter ( ) ) ,
RoomLobby ::Lobby ( _ ) = > panic! ( )
}
}
pub fn join_room ( id : ClientId ,
pkt : & MenuSelect ,
client_location : & mut ClientLocation ,
2020-04-22 23:49:49 -06:00
clients : & mut Clients ,
2020-05-13 22:32:30 -06:00
item_manager : & mut ItemManager ,
2020-04-21 23:15:11 -06:00
level_table : & CharacterLevelTable ,
rooms : & mut Rooms )
2020-04-24 20:38:56 -06:00
-> Result < Box < dyn Iterator < Item = ( ClientId , SendShipPacket ) > + Send > , ShipError > {
2021-05-23 18:18:36 +00:00
let client = clients . get ( & id ) . ok_or ( ShipError ::ClientNotFound ( id ) ) ? ;
let level = level_table . get_level_from_exp ( client . character . char_class , client . character . exp ) ;
2021-06-23 01:03:54 +00:00
let room = rooms . get ( pkt . item as usize ) . ok_or ( ShipError ::InvalidRoom ( pkt . item ) ) ? . as_ref ( ) . unwrap ( ) ; // clippy look what you made me do
2021-05-23 18:18:36 +00:00
match room . mode . difficulty ( ) {
room ::Difficulty ::Ultimate = > {
if level < 80 {
2021-06-22 23:23:22 +00:00
return Ok ( Box ::new ( vec! [ ( id , SendShipPacket ::SmallDialog ( SmallDialog ::new ( " You must be at least level 80 \n to join Ultimate rooms. " . into ( ) ) ) ) ] . into_iter ( ) ) )
2021-05-23 18:18:36 +00:00
}
} ,
room ::Difficulty ::VeryHard = > {
if level < 40 {
2021-06-22 23:23:22 +00:00
return Ok ( Box ::new ( vec! [ ( id , SendShipPacket ::SmallDialog ( SmallDialog ::new ( " You must be at least level 40 \n to join Very Hard rooms. " . into ( ) ) ) ) ] . into_iter ( ) ) )
2021-05-23 18:18:36 +00:00
}
} ,
room ::Difficulty ::Hard = > {
if level < 20 {
2021-06-22 23:23:22 +00:00
return Ok ( Box ::new ( vec! [ ( id , SendShipPacket ::SmallDialog ( SmallDialog ::new ( " You must be at least level 20 \n to join Hard rooms. " . into ( ) ) ) ) ] . into_iter ( ) ) )
2021-05-23 18:18:36 +00:00
}
} ,
2021-06-23 00:02:31 +00:00
_ = > { } ,
2021-05-23 18:18:36 +00:00
} ;
2020-04-21 23:15:11 -06:00
let original_area = client_location . get_area ( id ) . unwrap ( ) ;
let original_neighbors = client_location . get_client_neighbors ( id ) . unwrap ( ) ;
if room . bursting {
2020-04-24 20:38:56 -06:00
return Ok ( Box ::new ( vec! [ ( id , SendShipPacket ::SmallDialog ( SmallDialog ::new ( " player is bursting \n please wait " . into ( ) ) ) ) ] . into_iter ( ) ) )
2020-04-21 23:15:11 -06:00
}
let room_id = RoomId ( pkt . item as usize ) ;
2020-04-25 22:16:40 -06:00
let original_room_clients = client_location . get_clients_in_room ( room_id ) . map_err ( | err | -> ClientLocationError { err . into ( ) } ) ? ;
2020-04-21 23:15:11 -06:00
client_location . add_client_to_room ( id , room_id ) . unwrap ( ) ; // TODO: show room full error or whatever
2020-04-24 20:38:56 -06:00
let client = clients . get ( & id ) . ok_or ( ShipError ::ClientNotFound ( id ) ) ? ;
2020-04-25 22:16:40 -06:00
let area_client = client_location . get_local_client ( id ) . map_err ( | err | -> ClientLocationError { err . into ( ) } ) ? ;
2020-10-31 23:18:25 -06:00
item_manager . add_character_to_room ( room_id , & client . character , area_client ) ;
2020-04-25 22:16:40 -06:00
let leader = client_location . get_room_leader ( room_id ) . map_err ( | err | -> ClientLocationError { err . into ( ) } ) ? ;
2021-06-18 12:18:29 -06:00
let join_room = builder ::room ::join_room ( id , clients , client_location , room_id , room ) ? ;
let add_to = builder ::room ::add_to_room ( id , client , & area_client , & leader , item_manager , level_table , room_id ) ? ;
2020-04-21 23:15:11 -06:00
let room = rooms . get_mut ( room_id . 0 ) . unwrap ( ) . as_mut ( ) . unwrap ( ) ;
room . bursting = true ;
2020-04-24 20:38:56 -06:00
let mut result : Box < dyn Iterator < Item = ( ClientId , SendShipPacket ) > + Send > = Box ::new (
vec! [ ( id , SendShipPacket ::JoinRoom ( join_room ) ) ]
. into_iter ( )
2021-06-18 12:18:29 -06:00
. chain ( original_room_clients . into_iter ( )
2020-04-24 20:38:56 -06:00
. map ( move | c | ( c . client , SendShipPacket ::AddToRoom ( add_to . clone ( ) ) ) )
) ) ;
2020-04-21 23:15:11 -06:00
if let Ok ( leader ) = client_location . get_area_leader ( original_area ) {
let leave_lobby = SendShipPacket ::LeaveLobby ( LeaveLobby ::new ( area_client . local_client . id ( ) , leader . local_client . id ( ) ) ) ;
2020-04-24 20:38:56 -06:00
result = Box ::new ( result . chain ( original_neighbors . into_iter ( )
. map ( move | c | ( c . client , leave_lobby . clone ( ) ) ) ) )
2020-04-21 23:15:11 -06:00
}
2020-04-24 20:38:56 -06:00
Ok ( result )
2020-04-21 23:15:11 -06:00
}
pub fn done_bursting ( id : ClientId ,
client_location : & ClientLocation ,
rooms : & mut Rooms )
-> Box < dyn Iterator < Item = ( ClientId , SendShipPacket ) > + Send > {
let area = client_location . get_area ( id ) . unwrap ( ) ;
if let RoomLobby ::Room ( room_id ) = area {
2021-06-18 12:18:29 -06:00
if let Some ( room ) = rooms . get_mut ( room_id . 0 ) . unwrap ( ) . as_mut ( ) {
2020-05-24 18:42:37 -06:00
room . bursting = false ;
2021-06-18 12:18:29 -06:00
}
2020-04-21 23:15:11 -06:00
}
2020-05-24 18:42:37 -06:00
let area_client = client_location . get_local_client ( id ) . unwrap ( ) ; // TODO: unwrap
Box ::new ( client_location . get_client_neighbors ( id ) . unwrap ( ) . into_iter ( ) // TODO: unwrap
2020-05-24 15:59:48 -06:00
. map ( move | client | {
vec! [
( client . client , SendShipPacket ::Message ( Message ::new ( GameMessage ::BurstDone ( BurstDone {
2020-05-24 18:42:37 -06:00
client : area_client . local_client . id ( ) ,
2020-05-24 15:59:48 -06:00
target : 0
} ) ) ) ) ,
]
} ) . flatten ( ) )
}
2020-04-21 23:15:11 -06:00
pub fn request_room_list ( id : ClientId ,
client_location : & ClientLocation ,
rooms : & Rooms )
-> Box < dyn Iterator < Item = ( ClientId , SendShipPacket ) > + Send > {
let active_room_list = rooms . iter ( )
. enumerate ( )
. filter_map ( | ( i , r ) | {
r . as_ref ( ) . map ( | room | {
RoomList {
menu_id : ROOM_MENU_ID ,
item_id : i as u32 ,
difficulty : room . get_difficulty_for_room_list ( ) ,
players : client_location . get_clients_in_room ( RoomId ( i ) ) . unwrap ( ) . len ( ) as u8 ,
name : libpso ::utf8_to_utf16_array! ( room . name , 16 ) ,
episode : room . get_episode_for_room_list ( ) ,
flags : room . get_flags_for_room_list ( ) ,
}
} )
} ) ;
let baseroom : RoomList = RoomList {
menu_id : ROOM_MENU_ID ,
item_id : ROOM_MENU_ID ,
difficulty : 0x00 ,
players : 0x00 ,
name : libpso ::utf8_to_utf16_array! ( " Room list menu " , 16 ) ,
episode : 0 ,
flags : 0 ,
} ;
Box ::new ( vec! [ ( id , SendShipPacket ::RoomListResponse ( RoomListResponse {
baseroom ,
rooms : active_room_list . collect ( )
} ) ) ] . into_iter ( ) )
}
pub fn cool_62 ( id : ClientId ,
cool_62 : & Like62ButCooler ,
client_location : & ClientLocation )
-> Box < dyn Iterator < Item = ( ClientId , SendShipPacket ) > + Send > {
let target = cool_62 . flag as u8 ;
let cool_62 = cool_62 . clone ( ) ;
Box ::new ( client_location . get_client_neighbors ( id ) . unwrap ( ) . into_iter ( )
. filter ( move | client | client . local_client . id ( ) = = target )
. map ( move | client | {
( client . client , SendShipPacket ::Like62ButCooler ( cool_62 . clone ( ) ) )
} ) )
}