diff --git a/resources/scripts/Global.lua b/resources/scripts/Global.lua index 6e2c013..c4090ad 100644 --- a/resources/scripts/Global.lua +++ b/resources/scripts/Global.lua @@ -17,3 +17,4 @@ registerEvent(1245187, "opening/OpeningUldah.lua") registerEvent(131078, "warp/WarpInnGridania.lua") registerEvent(131079, "warp/WarpInnLimsaLominsa.lua") registerEvent(131082, "tosort/LimsaInnDoor.lua") +registerEvent(720916, "custom/000/cmndefinnbed_00020.lua") diff --git a/resources/scripts/custom/000/cmndefinnbed_00020.lua b/resources/scripts/custom/000/cmndefinnbed_00020.lua new file mode 100644 index 0000000..9b123de --- /dev/null +++ b/resources/scripts/custom/000/cmndefinnbed_00020.lua @@ -0,0 +1,33 @@ +--- TODO: find a way to hardcode it this way +EVENT_ID = 720916 + +-- TODO: in retail, there is a fade in/out between the prompt and the sleep anim? + +function onTalk(target, player) + --- prompt the bed menu + player:play_scene(target, EVENT_ID, 0, 8192, 0) +end + +function onReturn(scene, results, player) + if scene == 0 then -- prompt + if results[1] == 1 then + -- nothing + elseif results[1] == 2 then + -- dreamfitting not implemented + elseif results[1] == 3 then + -- play sleep animation + player:play_scene(player.id, EVENT_ID, 1, 8192, 0) + player:begin_log_out() + return + elseif results[1] == 4 then + -- play sleep animation + player:play_scene(player.id, EVENT_ID, 1, 8192, 0) + player:begin_log_out() + return + end + + player:finish_event(EVENT_ID) + elseif scene == 1 then -- sleep anim + player:finish_event(EVENT_ID) + end +end diff --git a/resources/scripts/tosort/LimsaInnDoor.lua b/resources/scripts/tosort/LimsaInnDoor.lua index a76d9a2..d4b9be2 100644 --- a/resources/scripts/tosort/LimsaInnDoor.lua +++ b/resources/scripts/tosort/LimsaInnDoor.lua @@ -8,7 +8,9 @@ function onTalk(target, player) player:play_scene(target, EVENT_ID, 00000, 8192, 0) end -function onReturn(results, player) +function onReturn(scene, results, player) + player:finish_event(EVENT_ID) + if results[1] == 1 then -- get warp player:warp(EVENT_ID) diff --git a/resources/scripts/warp/WarpInnLimsaLominsa.lua b/resources/scripts/warp/WarpInnLimsaLominsa.lua index 5517c33..e1df407 100644 --- a/resources/scripts/warp/WarpInnLimsaLominsa.lua +++ b/resources/scripts/warp/WarpInnLimsaLominsa.lua @@ -9,7 +9,9 @@ function onTalk(target, player) --player:play_scene(actorId, EVENT_ID, 00002, 8192, 0) end -function onReturn(results, player) +function onReturn(scene, results, player) + player:finish_event(EVENT_ID) + if results[1] == 1 then -- get warp player:warp(EVENT_ID) diff --git a/src/bin/kawari-world.rs b/src/bin/kawari-world.rs index 337406e..8f68687 100644 --- a/src/bin/kawari-world.rs +++ b/src/bin/kawari-world.rs @@ -468,27 +468,7 @@ async fn client_loop( ClientZoneIpcData::LogOut { .. } => { tracing::info!("Recieved log out from client!"); - // write the player back to the database - database.commit_player_data(&connection.player_data); - - // tell the client to disconnect - { - let ipc = ServerZoneIpcSegment { - op_code: ServerZoneIpcType::LogOutComplete, - timestamp: timestamp_secs(), - data: ServerZoneIpcData::LogOutComplete { unk: [0; 8] }, - ..Default::default() - }; - - connection - .send_segment(PacketSegment { - source_actor: connection.player_data.actor_id, - target_actor: connection.player_data.actor_id, - segment_type: SegmentType::Ipc, - data: SegmentData::Ipc { data: ipc }, - }) - .await; - } + connection.begin_log_out().await; } ClientZoneIpcData::Disconnected { .. } => { tracing::info!("Client disconnected!"); @@ -770,52 +750,7 @@ async fn client_loop( .event .as_mut() .unwrap() - .finish(results, &mut lua_player); - - { - // TODO: handle in lua script - let ipc = ServerZoneIpcSegment { - op_code: ServerZoneIpcType::EventFinish, - timestamp: timestamp_secs(), - data: ServerZoneIpcData::EventFinish { - handler_id: *handler_id, - event: 1, - result: 1, - arg: 0 - }, - ..Default::default() - }; - - connection - .send_segment(PacketSegment { - source_actor: connection.player_data.actor_id, - target_actor: connection.player_data.actor_id, - segment_type: SegmentType::Ipc, - data: SegmentData::Ipc { data: ipc }, - }) - .await; - } - - // give back control to the player - { - let ipc = ServerZoneIpcSegment { - op_code: ServerZoneIpcType::Unk18, - timestamp: timestamp_secs(), - data: ServerZoneIpcData::Unk18 { - unk: [0; 16] - }, - ..Default::default() - }; - - connection - .send_segment(PacketSegment { - source_actor: connection.player_data.actor_id, - target_actor: connection.player_data.actor_id, - segment_type: SegmentType::Ipc, - data: SegmentData::Ipc { data: ipc }, - }) - .await; - } + .finish(*scene, results, &mut lua_player); } } } diff --git a/src/world/connection.rs b/src/world/connection.rs index a2e8f20..bba4501 100644 --- a/src/world/connection.rs +++ b/src/world/connection.rs @@ -600,11 +600,77 @@ impl ZoneConnection { Task::Warp { warp_id } => { self.warp(*warp_id).await; } + Task::BeginLogOut => self.begin_log_out().await, + Task::FinishEvent { handler_id } => { + // sent event finish + { + let ipc = ServerZoneIpcSegment { + op_code: ServerZoneIpcType::EventFinish, + timestamp: timestamp_secs(), + data: ServerZoneIpcData::EventFinish { + handler_id: *handler_id, + event: 1, + result: 1, + arg: 0, + }, + ..Default::default() + }; + + self.send_segment(PacketSegment { + source_actor: self.player_data.actor_id, + target_actor: self.player_data.actor_id, + segment_type: SegmentType::Ipc, + data: SegmentData::Ipc { data: ipc }, + }) + .await; + } + + // give back control to the player + { + let ipc = ServerZoneIpcSegment { + op_code: ServerZoneIpcType::Unk18, + timestamp: timestamp_secs(), + data: ServerZoneIpcData::Unk18 { unk: [0; 16] }, + ..Default::default() + }; + + self.send_segment(PacketSegment { + source_actor: self.player_data.actor_id, + target_actor: self.player_data.actor_id, + segment_type: SegmentType::Ipc, + data: SegmentData::Ipc { data: ipc }, + }) + .await; + } + } } } player.queued_tasks.clear(); } + pub async fn begin_log_out(&mut self) { + // write the player back to the database + self.database.commit_player_data(&self.player_data); + + // tell the client we're ready to disconnect at any moment' + { + let ipc = ServerZoneIpcSegment { + op_code: ServerZoneIpcType::LogOutComplete, + timestamp: timestamp_secs(), + data: ServerZoneIpcData::LogOutComplete { unk: [0; 8] }, + ..Default::default() + }; + + self.send_segment(PacketSegment { + source_actor: self.player_data.actor_id, + target_actor: self.player_data.actor_id, + segment_type: SegmentType::Ipc, + data: SegmentData::Ipc { data: ipc }, + }) + .await; + } + } + pub async fn process_effects_list(&mut self) { // Only update the client if absolutely nessecary (e.g. an effect is added, removed or changed duration) if self.status_effects.dirty { diff --git a/src/world/event.rs b/src/world/event.rs index 6ea1f80..3bb8bb0 100644 --- a/src/world/event.rs +++ b/src/world/event.rs @@ -65,14 +65,14 @@ impl Event { .unwrap(); } - pub fn finish(&mut self, results: &[u32], player: &mut LuaPlayer) { + pub fn finish(&mut self, scene: u16, results: &[u32], player: &mut LuaPlayer) { self.lua .scope(|scope| { let player = scope.create_userdata_ref_mut(player).unwrap(); let func: Function = self.lua.globals().get("onReturn").unwrap(); - func.call::<()>((results, player)).unwrap(); + func.call::<()>((scene, results, player)).unwrap(); Ok(()) }) diff --git a/src/world/lua.rs b/src/world/lua.rs index a85a632..1337052 100644 --- a/src/world/lua.rs +++ b/src/world/lua.rs @@ -16,6 +16,8 @@ pub enum Task { ChangeTerritory { zone_id: u16 }, SetRemakeMode(RemakeMode), Warp { warp_id: u32 }, + BeginLogOut, + FinishEvent { handler_id: u32 }, } #[derive(Default)] @@ -114,6 +116,14 @@ impl LuaPlayer { fn warp(&mut self, warp_id: u32) { self.queued_tasks.push(Task::Warp { warp_id }); } + + fn begin_log_out(&mut self) { + self.queued_tasks.push(Task::BeginLogOut); + } + + fn finish_event(&mut self, handler_id: u32) { + self.queued_tasks.push(Task::FinishEvent { handler_id }); + } } impl UserData for LuaPlayer { @@ -153,6 +163,14 @@ impl UserData for LuaPlayer { this.warp(warp_id); Ok(()) }); + methods.add_method_mut("begin_log_out", |_, this, _: ()| { + this.begin_log_out(); + Ok(()) + }); + methods.add_method_mut("finish_event", |_, this, handler_id: u32| { + this.finish_event(handler_id); + Ok(()) + }); } fn add_fields>(fields: &mut F) {