2025-04-18 14:32:39 -04:00
|
|
|
use mlua::{FromLua, Lua, LuaSerdeExt, UserData, UserDataMethods, Value};
|
2025-03-28 00:26:31 -04:00
|
|
|
|
|
|
|
use crate::{
|
2025-05-02 15:36:22 -04:00
|
|
|
common::{ObjectId, ObjectTypeId, Position, timestamp_secs, workdefinitions::RemakeMode},
|
2025-05-02 00:47:11 -04:00
|
|
|
ipc::zone::{
|
2025-05-02 23:24:31 -04:00
|
|
|
ActionEffect, DamageElement, DamageKind, DamageType, EffectKind, EventScene,
|
|
|
|
ServerZoneIpcData, ServerZoneIpcSegment, Warp,
|
2025-03-30 10:01:41 -04:00
|
|
|
},
|
2025-05-02 00:47:11 -04:00
|
|
|
opcodes::ServerZoneIpcType,
|
|
|
|
packet::{PacketSegment, SegmentData, SegmentType},
|
2025-03-28 00:26:31 -04:00
|
|
|
};
|
|
|
|
|
2025-05-02 00:47:11 -04:00
|
|
|
use super::{PlayerData, StatusEffects, Zone};
|
|
|
|
|
2025-05-02 15:36:22 -04:00
|
|
|
pub enum Task {
|
|
|
|
ChangeTerritory { zone_id: u16 },
|
|
|
|
SetRemakeMode(RemakeMode),
|
2025-03-28 23:43:27 -04:00
|
|
|
}
|
|
|
|
|
2025-03-28 00:26:31 -04:00
|
|
|
#[derive(Default)]
|
|
|
|
pub struct LuaPlayer {
|
|
|
|
pub player_data: PlayerData,
|
|
|
|
pub status_effects: StatusEffects,
|
|
|
|
pub queued_segments: Vec<PacketSegment<ServerZoneIpcSegment>>,
|
2025-05-02 15:36:22 -04:00
|
|
|
pub queued_tasks: Vec<Task>,
|
2025-03-28 00:26:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl LuaPlayer {
|
|
|
|
fn queue_segment(&mut self, segment: PacketSegment<ServerZoneIpcSegment>) {
|
|
|
|
self.queued_segments.push(segment);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn send_message(&mut self, message: &str) {
|
|
|
|
let ipc = ServerZoneIpcSegment {
|
|
|
|
op_code: ServerZoneIpcType::ServerChatMessage,
|
|
|
|
timestamp: timestamp_secs(),
|
|
|
|
data: ServerZoneIpcData::ServerChatMessage {
|
|
|
|
message: message.to_string(),
|
|
|
|
unk: 0,
|
|
|
|
},
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
|
|
|
|
self.queue_segment(PacketSegment {
|
|
|
|
source_actor: self.player_data.actor_id,
|
|
|
|
target_actor: self.player_data.actor_id,
|
2025-05-02 00:03:36 -04:00
|
|
|
segment_type: SegmentType::Ipc,
|
|
|
|
data: SegmentData::Ipc { data: ipc },
|
2025-03-28 00:26:31 -04:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
fn give_status_effect(&mut self, effect_id: u16, duration: f32) {
|
|
|
|
self.status_effects.add(effect_id, duration);
|
|
|
|
}
|
2025-03-28 21:28:30 -04:00
|
|
|
|
|
|
|
fn play_scene(&mut self, event_id: u32, scene: u16, scene_flags: u32, param: u8) {
|
|
|
|
let ipc = ServerZoneIpcSegment {
|
2025-05-01 23:20:56 -04:00
|
|
|
op_code: ServerZoneIpcType::EventScene,
|
2025-03-28 21:28:30 -04:00
|
|
|
timestamp: timestamp_secs(),
|
2025-05-02 23:24:31 -04:00
|
|
|
data: ServerZoneIpcData::EventScene(EventScene {
|
2025-03-28 21:28:30 -04:00
|
|
|
actor_id: ObjectTypeId {
|
|
|
|
object_id: ObjectId(self.player_data.actor_id),
|
|
|
|
object_type: 0,
|
|
|
|
},
|
|
|
|
event_id,
|
|
|
|
scene,
|
|
|
|
scene_flags,
|
|
|
|
unk2: param,
|
|
|
|
..Default::default()
|
|
|
|
}),
|
2025-05-02 23:38:44 -04:00
|
|
|
..Default::default()
|
2025-03-28 21:28:30 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
self.queue_segment(PacketSegment {
|
|
|
|
source_actor: self.player_data.actor_id,
|
|
|
|
target_actor: self.player_data.actor_id,
|
2025-05-02 00:03:36 -04:00
|
|
|
segment_type: SegmentType::Ipc,
|
|
|
|
data: SegmentData::Ipc { data: ipc },
|
2025-03-28 21:28:30 -04:00
|
|
|
});
|
|
|
|
}
|
2025-03-28 22:34:34 -04:00
|
|
|
|
|
|
|
fn set_position(&mut self, position: Position) {
|
|
|
|
let ipc = ServerZoneIpcSegment {
|
2025-05-01 23:20:56 -04:00
|
|
|
op_code: ServerZoneIpcType::Warp,
|
2025-03-28 22:34:34 -04:00
|
|
|
timestamp: timestamp_secs(),
|
2025-05-02 23:24:31 -04:00
|
|
|
data: ServerZoneIpcData::Warp(Warp {
|
2025-03-28 22:34:34 -04:00
|
|
|
position,
|
|
|
|
..Default::default()
|
|
|
|
}),
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
|
|
|
|
self.queue_segment(PacketSegment {
|
|
|
|
source_actor: self.player_data.actor_id,
|
|
|
|
target_actor: self.player_data.actor_id,
|
2025-05-02 00:03:36 -04:00
|
|
|
segment_type: SegmentType::Ipc,
|
|
|
|
data: SegmentData::Ipc { data: ipc },
|
2025-03-28 22:34:34 -04:00
|
|
|
});
|
|
|
|
}
|
2025-03-28 23:43:27 -04:00
|
|
|
|
|
|
|
fn change_territory(&mut self, zone_id: u16) {
|
2025-05-02 15:36:22 -04:00
|
|
|
self.queued_tasks.push(Task::ChangeTerritory { zone_id });
|
|
|
|
}
|
|
|
|
|
|
|
|
fn set_remake_mode(&mut self, mode: RemakeMode) {
|
|
|
|
self.queued_tasks.push(Task::SetRemakeMode(mode));
|
2025-03-28 23:43:27 -04:00
|
|
|
}
|
2025-03-28 00:26:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl UserData for LuaPlayer {
|
|
|
|
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
|
|
|
methods.add_method_mut("send_message", |_, this, message: String| {
|
|
|
|
this.send_message(&message);
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
methods.add_method_mut(
|
|
|
|
"give_status_effect",
|
|
|
|
|_, this, (effect_id, duration): (u16, f32)| {
|
|
|
|
this.give_status_effect(effect_id, duration);
|
|
|
|
Ok(())
|
|
|
|
},
|
|
|
|
);
|
2025-03-28 21:28:30 -04:00
|
|
|
methods.add_method_mut(
|
|
|
|
"play_scene",
|
|
|
|
|_, this, (event_id, scene, scene_flags, param): (u32, u16, u32, u8)| {
|
|
|
|
this.play_scene(event_id, scene, scene_flags, param);
|
|
|
|
Ok(())
|
|
|
|
},
|
|
|
|
);
|
2025-03-28 22:34:34 -04:00
|
|
|
methods.add_method_mut("set_position", |_, this, position: Position| {
|
|
|
|
this.set_position(position);
|
|
|
|
Ok(())
|
|
|
|
});
|
2025-03-28 23:43:27 -04:00
|
|
|
methods.add_method_mut("change_territory", |_, this, zone_id: u16| {
|
|
|
|
this.change_territory(zone_id);
|
|
|
|
Ok(())
|
|
|
|
});
|
2025-05-02 15:36:22 -04:00
|
|
|
methods.add_method_mut("set_remake_mode", |lua, this, mode: Value| {
|
|
|
|
let mode: RemakeMode = lua.from_value(mode).unwrap();
|
|
|
|
this.set_remake_mode(mode);
|
|
|
|
Ok(())
|
|
|
|
});
|
2025-03-28 22:34:34 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl UserData for Position {}
|
|
|
|
|
|
|
|
impl FromLua for Position {
|
|
|
|
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
|
|
|
|
match value {
|
|
|
|
Value::UserData(ud) => Ok(*ud.borrow::<Self>()?),
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl UserData for Zone {
|
|
|
|
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
|
|
|
methods.add_method(
|
|
|
|
"get_pop_range",
|
2025-03-29 08:34:55 -04:00
|
|
|
|lua: &Lua, this, id: u32| -> mlua::Result<mlua::Value> {
|
2025-03-28 22:34:34 -04:00
|
|
|
if let Some(pop_range) = this.find_pop_range(id) {
|
|
|
|
let trans = pop_range.0.transform.translation;
|
2025-03-29 08:34:55 -04:00
|
|
|
return lua.pack(Position {
|
2025-03-28 22:34:34 -04:00
|
|
|
x: trans[0],
|
|
|
|
y: trans[1],
|
|
|
|
z: trans[2],
|
|
|
|
});
|
|
|
|
}
|
2025-03-29 08:34:55 -04:00
|
|
|
Ok(mlua::Nil)
|
2025-03-28 22:34:34 -04:00
|
|
|
},
|
|
|
|
);
|
2025-03-28 00:26:31 -04:00
|
|
|
}
|
|
|
|
}
|
2025-03-30 09:29:36 -04:00
|
|
|
|
|
|
|
#[derive(Clone, Debug, Default)]
|
|
|
|
pub struct EffectsBuilder {
|
|
|
|
pub effects: Vec<ActionEffect>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl UserData for EffectsBuilder {
|
|
|
|
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
2025-04-18 14:32:39 -04:00
|
|
|
methods.add_method_mut("damage", |lua, this, (damage_kind, damage_type, damage_element, amount): (Value, Value, Value, u16)| {
|
|
|
|
let damage_kind: DamageKind = lua.from_value(damage_kind).unwrap();
|
|
|
|
let damage_type: DamageType = lua.from_value(damage_type).unwrap();
|
|
|
|
let damage_element: DamageElement = lua.from_value(damage_element).unwrap();
|
|
|
|
|
2025-03-30 09:29:36 -04:00
|
|
|
this.effects.push(ActionEffect {
|
2025-04-18 13:11:29 -04:00
|
|
|
kind: EffectKind::Damage {
|
2025-04-18 14:32:39 -04:00
|
|
|
damage_kind,
|
|
|
|
damage_type,
|
|
|
|
damage_element,
|
2025-04-18 13:11:29 -04:00
|
|
|
bonus_percent: 0,
|
|
|
|
unk3: 0,
|
|
|
|
unk4: 0,
|
|
|
|
amount,
|
|
|
|
},
|
2025-03-30 09:29:36 -04:00
|
|
|
..Default::default()
|
|
|
|
});
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FromLua for EffectsBuilder {
|
|
|
|
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
|
|
|
|
match value {
|
|
|
|
Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()),
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|