mirror of
https://github.com/redstrate/Kawari.git
synced 2025-05-12 14:47:46 +00:00
Begin scripting the inn NPCs
This kinda works, you can now talk to them without locking up your character but you aren't warped yet. I also need to clean up the mess of the Lua API.
This commit is contained in:
parent
85a2abb49e
commit
3139d63b91
7 changed files with 216 additions and 6 deletions
|
@ -154,6 +154,16 @@
|
||||||
"name": "Delete",
|
"name": "Delete",
|
||||||
"opcode": 149,
|
"opcode": 149,
|
||||||
"size": 8
|
"size": 8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "EventFinish",
|
||||||
|
"opcode": 375,
|
||||||
|
"size": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Unk18",
|
||||||
|
"opcode": 116,
|
||||||
|
"size": 16
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"ClientZoneIpcType": [
|
"ClientZoneIpcType": [
|
||||||
|
@ -266,6 +276,16 @@
|
||||||
"name": "ItemOperation",
|
"name": "ItemOperation",
|
||||||
"opcode": 583,
|
"opcode": 583,
|
||||||
"size": 48
|
"size": 48
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "StartTalkEvent",
|
||||||
|
"opcode": 300,
|
||||||
|
"size": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "EventHandlerReturn",
|
||||||
|
"opcode": 281,
|
||||||
|
"size": 16
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"ServerChatIpcType": [
|
"ServerChatIpcType": [
|
||||||
|
|
|
@ -10,3 +10,9 @@ registerAction(9, "actions/FastBlade.lua")
|
||||||
-- Items
|
-- Items
|
||||||
registerAction(6221, "items/Fantasia.lua")
|
registerAction(6221, "items/Fantasia.lua")
|
||||||
|
|
||||||
|
-- Events
|
||||||
|
registerEvent(1245185, "opening/OpeningLimsaLominsa.lua")
|
||||||
|
registerEvent(1245186, "opening/OpeningGridania.lua")
|
||||||
|
registerEvent(1245187, "opening/OpeningUldah.lua")
|
||||||
|
registerEvent(131078, "warp/WarpInnGridania.lua")
|
||||||
|
registerEvent(131079, "warp/WarpInnLimsaLominsa.lua")
|
||||||
|
|
10
resources/scripts/warp/WarpInnGridania.lua
Normal file
10
resources/scripts/warp/WarpInnGridania.lua
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
--- TODO: find a way to hardcode it this way
|
||||||
|
EVENT_ID = 131079 -- TODO: wrong, i was testing in limsa
|
||||||
|
|
||||||
|
function onTalk(actorId, player)
|
||||||
|
-- has inn access
|
||||||
|
-- player:play_scene(131079, 00001, 1, 0)
|
||||||
|
|
||||||
|
-- doesn't have inn access
|
||||||
|
player:play_scene(actorId, EVENT_ID, 00002, 8192, 0)
|
||||||
|
end
|
10
resources/scripts/warp/WarpInnLimsaLominsa.lua
Normal file
10
resources/scripts/warp/WarpInnLimsaLominsa.lua
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
--- TODO: find a way to hardcode it this way
|
||||||
|
EVENT_ID = 131079
|
||||||
|
|
||||||
|
function onTalk(actorId, player)
|
||||||
|
-- has inn access
|
||||||
|
player:play_scene(actorId, EVENT_ID, 00001, 8192, 0)
|
||||||
|
|
||||||
|
-- doesn't have inn access
|
||||||
|
--player:play_scene(actorId, EVENT_ID, 00002, 8192, 0)
|
||||||
|
end
|
|
@ -11,7 +11,7 @@ use kawari::inventory::{Inventory, Item};
|
||||||
use kawari::ipc::chat::{ServerChatIpcData, ServerChatIpcSegment};
|
use kawari::ipc::chat::{ServerChatIpcData, ServerChatIpcSegment};
|
||||||
use kawari::ipc::kawari::{CustomIpcData, CustomIpcSegment, CustomIpcType};
|
use kawari::ipc::kawari::{CustomIpcData, CustomIpcSegment, CustomIpcType};
|
||||||
use kawari::ipc::zone::{
|
use kawari::ipc::zone::{
|
||||||
ActionEffect, ActionResult, ClientZoneIpcData, EffectKind, GameMasterCommandType,
|
ActionEffect, ActionResult, ClientZoneIpcData, EffectKind, EventStart, GameMasterCommandType,
|
||||||
GameMasterRank, OnlineStatus, ServerZoneIpcData, ServerZoneIpcSegment, SocialListRequestType,
|
GameMasterRank, OnlineStatus, ServerZoneIpcData, ServerZoneIpcSegment, SocialListRequestType,
|
||||||
};
|
};
|
||||||
use kawari::ipc::zone::{
|
use kawari::ipc::zone::{
|
||||||
|
@ -40,6 +40,7 @@ use tokio::task::JoinHandle;
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct ExtraLuaState {
|
struct ExtraLuaState {
|
||||||
action_scripts: HashMap<u32, String>,
|
action_scripts: HashMap<u32, String>,
|
||||||
|
event_scripts: HashMap<u32, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_main_loop() -> (ServerHandle, JoinHandle<()>) {
|
fn spawn_main_loop() -> (ServerHandle, JoinHandle<()>) {
|
||||||
|
@ -727,6 +728,119 @@ async fn client_loop(
|
||||||
connection.player_data.inventory.process_action(action);
|
connection.player_data.inventory.process_action(action);
|
||||||
connection.send_inventory(true).await;
|
connection.send_inventory(true).await;
|
||||||
}
|
}
|
||||||
|
ClientZoneIpcData::StartTalkEvent { actor_id, event_id } => {
|
||||||
|
// load scene
|
||||||
|
{
|
||||||
|
let ipc = ServerZoneIpcSegment {
|
||||||
|
op_code: ServerZoneIpcType::EventStart,
|
||||||
|
timestamp: timestamp_secs(),
|
||||||
|
data: ServerZoneIpcData::EventStart(EventStart {
|
||||||
|
target_id: *actor_id,
|
||||||
|
event_id: *event_id,
|
||||||
|
event_type: 1, // talk?
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
dbg!(&ipc);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
let lua = lua.lock().unwrap();
|
||||||
|
let state = lua.app_data_ref::<ExtraLuaState>().unwrap();
|
||||||
|
|
||||||
|
if let Some(event_script) =
|
||||||
|
state.event_scripts.get(&event_id)
|
||||||
|
{
|
||||||
|
// run script
|
||||||
|
lua.scope(|scope| {
|
||||||
|
let connection_data = scope
|
||||||
|
.create_userdata_ref_mut(&mut lua_player)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let config = get_config();
|
||||||
|
|
||||||
|
let file_name = format!(
|
||||||
|
"{}/{}",
|
||||||
|
&config.world.scripts_location, event_script
|
||||||
|
);
|
||||||
|
lua.load(
|
||||||
|
std::fs::read(&file_name)
|
||||||
|
.expect("Failed to locate scripts directory!"),
|
||||||
|
)
|
||||||
|
.set_name("@".to_string() + &file_name)
|
||||||
|
.exec()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let func: Function =
|
||||||
|
lua.globals().get("onTalk").unwrap();
|
||||||
|
|
||||||
|
func.call::<()>((actor_id.object_id.0, &connection_data))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
} else {
|
||||||
|
tracing::warn!("Event {event_id} isn't scripted yet! Ignoring...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ClientZoneIpcData::EventHandlerReturn { handler_id, scene, error_code, num_results, results } => {
|
||||||
|
tracing::info!("Finishing this event... {handler_id} {scene} {error_code} {num_results} {results:#?}");
|
||||||
|
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SegmentData::KeepAliveRequest { id, timestamp } => {
|
SegmentData::KeepAliveRequest { id, timestamp } => {
|
||||||
|
@ -1038,10 +1152,22 @@ async fn main() {
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let register_event_func = lua
|
||||||
|
.create_function(|lua, (event_id, event_script): (u32, String)| {
|
||||||
|
tracing::info!("Registering {event_id} with {event_script}!");
|
||||||
|
let mut state = lua.app_data_mut::<ExtraLuaState>().unwrap();
|
||||||
|
let _ = state.event_scripts.insert(event_id, event_script);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
lua.set_app_data(ExtraLuaState::default());
|
lua.set_app_data(ExtraLuaState::default());
|
||||||
lua.globals()
|
lua.globals()
|
||||||
.set("registerAction", register_action_func)
|
.set("registerAction", register_action_func)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
lua.globals()
|
||||||
|
.set("registerEvent", register_event_func)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let effectsbuilder_constructor = lua
|
let effectsbuilder_constructor = lua
|
||||||
.create_function(|_, ()| Ok(EffectsBuilder::default()))
|
.create_function(|_, ()| Ok(EffectsBuilder::default()))
|
||||||
|
|
|
@ -76,6 +76,7 @@ pub use item_operation::ItemOperation;
|
||||||
mod equip;
|
mod equip;
|
||||||
pub use equip::Equip;
|
pub use equip::Equip;
|
||||||
|
|
||||||
|
use crate::common::ObjectTypeId;
|
||||||
use crate::common::Position;
|
use crate::common::Position;
|
||||||
use crate::common::read_string;
|
use crate::common::read_string;
|
||||||
use crate::common::write_string;
|
use crate::common::write_string;
|
||||||
|
@ -220,6 +221,19 @@ pub enum ServerZoneIpcData {
|
||||||
#[brw(pad_before = 3)] // padding
|
#[brw(pad_before = 3)] // padding
|
||||||
actor_id: u32,
|
actor_id: u32,
|
||||||
},
|
},
|
||||||
|
/// Sent to the client to stop their currently playing event.
|
||||||
|
EventFinish {
|
||||||
|
handler_id: u32,
|
||||||
|
event: u8,
|
||||||
|
result: u8,
|
||||||
|
#[brw(pad_before = 2)] // padding
|
||||||
|
#[brw(pad_after = 4)] // padding
|
||||||
|
arg: u32,
|
||||||
|
},
|
||||||
|
/// Sent after EventFinish? it un-occupies the character lol
|
||||||
|
Unk18 {
|
||||||
|
unk: [u8; 16], // all zero...
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[binrw]
|
#[binrw]
|
||||||
|
@ -354,6 +368,21 @@ pub enum ClientZoneIpcData {
|
||||||
},
|
},
|
||||||
#[br(pre_assert(*magic == ClientZoneIpcType::ItemOperation))]
|
#[br(pre_assert(*magic == ClientZoneIpcType::ItemOperation))]
|
||||||
ItemOperation(ItemOperation),
|
ItemOperation(ItemOperation),
|
||||||
|
#[br(pre_assert(*magic == ClientZoneIpcType::StartTalkEvent))]
|
||||||
|
StartTalkEvent {
|
||||||
|
actor_id: ObjectTypeId,
|
||||||
|
#[brw(pad_after = 4)] // padding
|
||||||
|
event_id: u32,
|
||||||
|
},
|
||||||
|
#[br(pre_assert(*magic == ClientZoneIpcType::EventHandlerReturn))]
|
||||||
|
EventHandlerReturn {
|
||||||
|
handler_id: u32,
|
||||||
|
scene: u16,
|
||||||
|
error_code: u8,
|
||||||
|
num_results: u8,
|
||||||
|
#[brw(pad_after = 4)] // padding
|
||||||
|
results: [u32; 1],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -53,14 +53,21 @@ impl LuaPlayer {
|
||||||
self.status_effects.add(effect_id, duration);
|
self.status_effects.add(effect_id, duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn play_scene(&mut self, event_id: u32, scene: u16, scene_flags: u32, param: u8) {
|
fn play_scene(
|
||||||
|
&mut self,
|
||||||
|
actor_id: u32,
|
||||||
|
event_id: u32,
|
||||||
|
scene: u16,
|
||||||
|
scene_flags: u32,
|
||||||
|
param: u8,
|
||||||
|
) {
|
||||||
let ipc = ServerZoneIpcSegment {
|
let ipc = ServerZoneIpcSegment {
|
||||||
op_code: ServerZoneIpcType::EventScene,
|
op_code: ServerZoneIpcType::EventScene,
|
||||||
timestamp: timestamp_secs(),
|
timestamp: timestamp_secs(),
|
||||||
data: ServerZoneIpcData::EventScene(EventScene {
|
data: ServerZoneIpcData::EventScene(EventScene {
|
||||||
actor_id: ObjectTypeId {
|
actor_id: ObjectTypeId {
|
||||||
object_id: ObjectId(self.player_data.actor_id),
|
object_id: ObjectId(actor_id),
|
||||||
object_type: 0,
|
object_type: 1,
|
||||||
},
|
},
|
||||||
event_id,
|
event_id,
|
||||||
scene,
|
scene,
|
||||||
|
@ -71,6 +78,8 @@ impl LuaPlayer {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dbg!(&ipc);
|
||||||
|
|
||||||
self.queue_segment(PacketSegment {
|
self.queue_segment(PacketSegment {
|
||||||
source_actor: self.player_data.actor_id,
|
source_actor: self.player_data.actor_id,
|
||||||
target_actor: self.player_data.actor_id,
|
target_actor: self.player_data.actor_id,
|
||||||
|
@ -122,8 +131,8 @@ impl UserData for LuaPlayer {
|
||||||
);
|
);
|
||||||
methods.add_method_mut(
|
methods.add_method_mut(
|
||||||
"play_scene",
|
"play_scene",
|
||||||
|_, this, (event_id, scene, scene_flags, param): (u32, u16, u32, u8)| {
|
|_, this, (actor_id, event_id, scene, scene_flags, param): (u32, u32, u16, u32, u8)| {
|
||||||
this.play_scene(event_id, scene, scene_flags, param);
|
this.play_scene(actor_id, event_id, scene, scene_flags, param);
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Reference in a new issue