mirror of
https://github.com/redstrate/Kawari.git
synced 2025-07-10 16:07:45 +00:00
Extend the Lua API:
-Implement GM command collect (subtracts gil from player), but the ingame command's params are unknown, Lua only -Implement GM command inspect, but the IPC opcode for it is different than GMCommand and is thus far unimplemented, Lua only -The Lua API can now access all of the player's inventory (read-only)
This commit is contained in:
parent
877ec335a9
commit
3b6fcb7ba1
6 changed files with 193 additions and 3 deletions
|
@ -12,6 +12,8 @@ GM_EXP = 104
|
||||||
GM_ORCHESTRION = 116
|
GM_ORCHESTRION = 116
|
||||||
GM_GIVE_ITEM = 200
|
GM_GIVE_ITEM = 200
|
||||||
GM_GIL = 201
|
GM_GIL = 201
|
||||||
|
GM_COLLECT = 202
|
||||||
|
GM_INSPECT = 422
|
||||||
GM_WIREFRAME = 550
|
GM_WIREFRAME = 550
|
||||||
GM_TERRITORY = 600
|
GM_TERRITORY = 600
|
||||||
GM_TERRITORY_INFO = 605
|
GM_TERRITORY_INFO = 605
|
||||||
|
@ -20,11 +22,15 @@ registerGMCommand(GM_SET_LEVEL, GM_DIR.."SetLevel.lua")
|
||||||
registerGMCommand(GM_CHANGE_WEATHER, GM_DIR.."ChangeWeather.lua")
|
registerGMCommand(GM_CHANGE_WEATHER, GM_DIR.."ChangeWeather.lua")
|
||||||
registerGMCommand(GM_SPEED, GM_DIR.."SetSpeed.lua")
|
registerGMCommand(GM_SPEED, GM_DIR.."SetSpeed.lua")
|
||||||
registerGMCommand(GM_INVISIBILITY, GM_DIR.."ToggleInvisibility.lua")
|
registerGMCommand(GM_INVISIBILITY, GM_DIR.."ToggleInvisibility.lua")
|
||||||
|
-- TODO: Implement the GMInspect IPC opcode, it's completely different than the normal GMCommand opcode
|
||||||
|
--registerGMCommand(GM_INSPECT, GM_DIR.."InspectPlayer.lua")
|
||||||
registerGMCommand(GM_AETHERYTE, GM_DIR.."UnlockAetheryte.lua")
|
registerGMCommand(GM_AETHERYTE, GM_DIR.."UnlockAetheryte.lua")
|
||||||
registerGMCommand(GM_EXP, GM_DIR.."Exp.lua")
|
registerGMCommand(GM_EXP, GM_DIR.."Exp.lua")
|
||||||
registerGMCommand(GM_ORCHESTRION, GM_DIR.."Orchestrion.lua")
|
registerGMCommand(GM_ORCHESTRION, GM_DIR.."Orchestrion.lua")
|
||||||
registerGMCommand(GM_GIVE_ITEM, GM_DIR.."GiveItem.lua")
|
registerGMCommand(GM_GIVE_ITEM, GM_DIR.."GiveItem.lua")
|
||||||
registerGMCommand(GM_GIL, GM_DIR.."Gil.lua")
|
registerGMCommand(GM_GIL, GM_DIR.."Gil.lua")
|
||||||
|
-- TODO: Figure out how the //gm collect command works ingame, its parameters are not the same as //gm gil
|
||||||
|
--registerGMCommand(GM_COLLECT, GM_DIR.."Collect.lua")
|
||||||
registerGMCommand(GM_WIREFRAME, GM_DIR.."ToggleWireframe.lua")
|
registerGMCommand(GM_WIREFRAME, GM_DIR.."ToggleWireframe.lua")
|
||||||
registerGMCommand(GM_TERRITORY, GM_DIR.."ChangeTerritory.lua")
|
registerGMCommand(GM_TERRITORY, GM_DIR.."ChangeTerritory.lua")
|
||||||
registerGMCommand(GM_TERRITORY_INFO, GM_DIR.."TerritoryInfo.lua")
|
registerGMCommand(GM_TERRITORY_INFO, GM_DIR.."TerritoryInfo.lua")
|
||||||
|
@ -33,7 +39,9 @@ registerGMCommand(GM_TERRITORY_INFO, GM_DIR.."TerritoryInfo.lua")
|
||||||
-- Please keep these in alphabetical order!
|
-- Please keep these in alphabetical order!
|
||||||
|
|
||||||
registerCommand("classjob", DBG_DIR.."ClassJob.lua")
|
registerCommand("classjob", DBG_DIR.."ClassJob.lua")
|
||||||
|
registerCommand("collect", GM_DIR.."Collect.lua") -- TODO: remove this once we figure out the //gm collect command's parameters (see comments above)
|
||||||
registerCommand("festival", DBG_DIR.."Festival.lua")
|
registerCommand("festival", DBG_DIR.."Festival.lua")
|
||||||
|
registerCommand("inspect", GM_DIR.."InspectPlayer.lua") -- TODO: remove this once we figure out the GMInspect IPC opcode
|
||||||
registerCommand("nudge", DBG_DIR.."Nudge.lua")
|
registerCommand("nudge", DBG_DIR.."Nudge.lua")
|
||||||
registerCommand("ost", DBG_DIR.."OnScreenTest.lua")
|
registerCommand("ost", DBG_DIR.."OnScreenTest.lua")
|
||||||
registerCommand("permtest", DBG_DIR.."PermissionTest.lua")
|
registerCommand("permtest", DBG_DIR.."PermissionTest.lua")
|
||||||
|
|
12
resources/scripts/commands/gm/Collect.lua
Normal file
12
resources/scripts/commands/gm/Collect.lua
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
required_rank = GM_RANK_DEBUG
|
||||||
|
command_sender = "[collect] "
|
||||||
|
|
||||||
|
function onCommand(args, player)
|
||||||
|
local amount = tonumber(args[1])
|
||||||
|
if player.gil >= amount then
|
||||||
|
player:remove_gil(amount)
|
||||||
|
printf(player, "Collected %s gil.", amount)
|
||||||
|
else
|
||||||
|
printf(player, "Player does not have that much gil to take! They only possess %s.", player.gil)
|
||||||
|
end
|
||||||
|
end
|
79
resources/scripts/commands/gm/InspectPlayer.lua
Normal file
79
resources/scripts/commands/gm/InspectPlayer.lua
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
required_rank = GM_RANK_DEBUG
|
||||||
|
command_sender = "[inspect] "
|
||||||
|
|
||||||
|
function getItemCondition(condition)
|
||||||
|
return (condition / 30000) * 100
|
||||||
|
end
|
||||||
|
|
||||||
|
function onCommand(args, player)
|
||||||
|
info = "\z
|
||||||
|
--- Info for player ---\n\z
|
||||||
|
Current region: %s\n\z
|
||||||
|
Current zone: %s (%s, %s)\n\z
|
||||||
|
Position: %.3f %.3f %.3f\n\z
|
||||||
|
Rotation: %.3f\n\z
|
||||||
|
--- Currency ---\n\z
|
||||||
|
Gil: %s\n\z
|
||||||
|
--- Equipped items ---\n\z
|
||||||
|
Main hand: (id: %s, condition: %s%%)\n\z
|
||||||
|
Off hand: (id: %s, condition: %s%%)\n\z
|
||||||
|
Head: (id: %s, condition: %s%%)\n\z
|
||||||
|
Body: (id: %s, condition: %s%%)\n\z
|
||||||
|
Hands: (id: %s, condition: %s%%)\n\z
|
||||||
|
Legs: (id: %s, condition: %s%%)\n\z
|
||||||
|
Feet: (id: %s, condition: %s%%)\n\z
|
||||||
|
Ears: (id: %s, condition: %s%%)\n\z
|
||||||
|
Neck: (id: %s, condition: %s%%)\n\z
|
||||||
|
Wrists: (id: %s, condition: %s%%)\n\z
|
||||||
|
Right Ring: (id: %s, condition: %s%%)\n\z
|
||||||
|
Left Ring: (id: %s, condition: %s%%)\n\z
|
||||||
|
Soul Crystal: (id: %s, condition: %s%%)\z
|
||||||
|
"
|
||||||
|
-- Skipping belts because they don't exist anymore.
|
||||||
|
main_hand = player.inventory.equipped.main_hand
|
||||||
|
off_hand = player.inventory.equipped.off_hand
|
||||||
|
head = player.inventory.equipped.head
|
||||||
|
body = player.inventory.equipped.body
|
||||||
|
hands = player.inventory.equipped.hands
|
||||||
|
legs = player.inventory.equipped.legs
|
||||||
|
feet = player.inventory.equipped.feet
|
||||||
|
ears = player.inventory.equipped.ears
|
||||||
|
neck = player.inventory.equipped.neck
|
||||||
|
wrists = player.inventory.equipped.wrists
|
||||||
|
rring = player.inventory.equipped.right_ring
|
||||||
|
lring = player.inventory.equipped.left_ring
|
||||||
|
scrystal = player.inventory.equipped.soul_crystal
|
||||||
|
|
||||||
|
printf(player, info,
|
||||||
|
player.zone.region_name, player.zone.place_name, player.zone.internal_name, player.zone.id,
|
||||||
|
player.position.x, player.position.y, player.position.z,
|
||||||
|
player.rotation, player.gil,
|
||||||
|
main_hand.id, getItemCondition(main_hand.condition),
|
||||||
|
off_hand.id, getItemCondition(off_hand.condition),
|
||||||
|
head.id, getItemCondition(head.condition),
|
||||||
|
body.id, getItemCondition(body.condition),
|
||||||
|
hands.id, getItemCondition(hands.condition),
|
||||||
|
legs.id, getItemCondition(legs.condition),
|
||||||
|
feet.id, getItemCondition(feet.condition),
|
||||||
|
ears.id, getItemCondition(ears.condition),
|
||||||
|
neck.id, getItemCondition(neck.condition),
|
||||||
|
wrists.id, getItemCondition(wrists.condition),
|
||||||
|
lring.id, getItemCondition(lring.condition),
|
||||||
|
rring.id, getItemCondition(rring.condition),
|
||||||
|
scrystal.id, getItemCondition(scrystal.condition)
|
||||||
|
)
|
||||||
|
|
||||||
|
local NO_ITEM <const> = 0
|
||||||
|
|
||||||
|
command_sender = "" -- hush further sender printfs, it looks ugly here
|
||||||
|
printf(player, "--- Player's inventory ---")
|
||||||
|
|
||||||
|
for page_num, page in pairs(player.inventory.pages) do
|
||||||
|
printf(player, "--- Page %s ---", page_num)
|
||||||
|
for slot_num, slot in pairs(page.slots) do
|
||||||
|
if slot.id ~= NO_ITEM then
|
||||||
|
printf(player, "slot %s: (id: %s, condition: %s%%)", slot_num, slot.id, getItemCondition(slot.condition))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -745,6 +745,10 @@ impl ZoneConnection {
|
||||||
self.player_data.inventory.currency.get_slot_mut(0).quantity += *amount;
|
self.player_data.inventory.currency.get_slot_mut(0).quantity += *amount;
|
||||||
self.send_inventory(false).await;
|
self.send_inventory(false).await;
|
||||||
}
|
}
|
||||||
|
Task::RemoveGil { amount } => {
|
||||||
|
self.player_data.inventory.currency.get_slot_mut(0).quantity -= *amount;
|
||||||
|
self.send_inventory(false).await;
|
||||||
|
}
|
||||||
Task::UnlockOrchestrion { id, on } => {
|
Task::UnlockOrchestrion { id, on } => {
|
||||||
// id == 0 means "all"
|
// id == 0 means "all"
|
||||||
if *id == 0 {
|
if *id == 0 {
|
||||||
|
|
|
@ -6,6 +6,7 @@ use crate::{
|
||||||
write_quantized_rotation,
|
write_quantized_rotation,
|
||||||
},
|
},
|
||||||
config::get_config,
|
config::get_config,
|
||||||
|
inventory::{CurrencyStorage, EquippedStorage, GenericStorage, Inventory, Item},
|
||||||
ipc::zone::{
|
ipc::zone::{
|
||||||
ActionEffect, ActorControlCategory, ActorControlSelf, DamageElement, DamageKind,
|
ActionEffect, ActorControlCategory, ActorControlSelf, DamageElement, DamageKind,
|
||||||
DamageType, EffectKind, EventScene, ServerZoneIpcData, ServerZoneIpcSegment, Warp,
|
DamageType, EffectKind, EventScene, ServerZoneIpcData, ServerZoneIpcSegment, Warp,
|
||||||
|
@ -32,6 +33,7 @@ pub enum Task {
|
||||||
SetLevel { level: i32 },
|
SetLevel { level: i32 },
|
||||||
ChangeWeather { id: u16 },
|
ChangeWeather { id: u16 },
|
||||||
AddGil { amount: u32 },
|
AddGil { amount: u32 },
|
||||||
|
RemoveGil { amount: u32 },
|
||||||
UnlockOrchestrion { id: u16, on: bool },
|
UnlockOrchestrion { id: u16, on: bool },
|
||||||
AddItem { id: u32 },
|
AddItem { id: u32 },
|
||||||
}
|
}
|
||||||
|
@ -353,6 +355,10 @@ impl LuaPlayer {
|
||||||
self.queued_tasks.push(Task::AddGil { amount });
|
self.queued_tasks.push(Task::AddGil { amount });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn remove_gil(&mut self, amount: u32) {
|
||||||
|
self.queued_tasks.push(Task::RemoveGil { amount });
|
||||||
|
}
|
||||||
|
|
||||||
fn unlock_orchestrion(&mut self, unlocked: u32, id: u16) {
|
fn unlock_orchestrion(&mut self, unlocked: u32, id: u16) {
|
||||||
self.queued_tasks.push(Task::UnlockOrchestrion {
|
self.queued_tasks.push(Task::UnlockOrchestrion {
|
||||||
id,
|
id,
|
||||||
|
@ -478,6 +484,10 @@ impl UserData for LuaPlayer {
|
||||||
this.add_gil(amount);
|
this.add_gil(amount);
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
methods.add_method_mut("remove_gil", |_, this, amount: u32| {
|
||||||
|
this.remove_gil(amount);
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
methods.add_method_mut("unlock_orchestrion", |_, this, (unlock, id): (u32, u16)| {
|
methods.add_method_mut("unlock_orchestrion", |_, this, (unlock, id): (u32, u16)| {
|
||||||
this.unlock_orchestrion(unlock, id);
|
this.unlock_orchestrion(unlock, id);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -501,7 +511,14 @@ impl UserData for LuaPlayer {
|
||||||
});
|
});
|
||||||
fields.add_field_method_get("rotation", |_, this| Ok(this.player_data.rotation));
|
fields.add_field_method_get("rotation", |_, this| Ok(this.player_data.rotation));
|
||||||
fields.add_field_method_get("position", |_, this| Ok(this.player_data.position));
|
fields.add_field_method_get("position", |_, this| Ok(this.player_data.position));
|
||||||
|
fields.add_field_method_get("inventory", |_, this| {
|
||||||
|
Ok(this.player_data.inventory.clone())
|
||||||
|
});
|
||||||
fields.add_field_method_get("zone", |_, this| Ok(this.zone_data.clone()));
|
fields.add_field_method_get("zone", |_, this| Ok(this.zone_data.clone()));
|
||||||
|
// Helper method to reduce the amount of typing for gil
|
||||||
|
fields.add_field_method_get("gil", |_, this| {
|
||||||
|
Ok(this.player_data.inventory.currency.gil.quantity)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -519,6 +536,76 @@ impl UserData for Position {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl UserData for Inventory {
|
||||||
|
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||||
|
fields.add_field_method_get("equipped", |_, this| Ok(this.equipped));
|
||||||
|
fields.add_field_method_get("pages", |_, this| Ok(this.pages.clone()));
|
||||||
|
fields.add_field_method_get("armoury_main_hand", |_, this| {
|
||||||
|
Ok(this.armoury_main_hand.clone())
|
||||||
|
});
|
||||||
|
fields.add_field_method_get("armoury_head", |_, this| Ok(this.armoury_head.clone()));
|
||||||
|
fields.add_field_method_get("armoury_body", |_, this| Ok(this.armoury_body.clone()));
|
||||||
|
fields.add_field_method_get("armoury_hands", |_, this| Ok(this.armoury_hands.clone()));
|
||||||
|
fields.add_field_method_get("armoury_legs", |_, this| Ok(this.armoury_legs.clone()));
|
||||||
|
fields.add_field_method_get("armoury_feet", |_, this| Ok(this.armoury_feet.clone()));
|
||||||
|
fields.add_field_method_get("armoury_off_hand", |_, this| {
|
||||||
|
Ok(this.armoury_off_hand.clone())
|
||||||
|
});
|
||||||
|
fields.add_field_method_get("armoury_earring", |_, this| {
|
||||||
|
Ok(this.armoury_earring.clone())
|
||||||
|
});
|
||||||
|
fields.add_field_method_get("armoury_necklace", |_, this| {
|
||||||
|
Ok(this.armoury_necklace.clone())
|
||||||
|
});
|
||||||
|
fields.add_field_method_get("armoury_bracelet", |_, this| Ok(this.armoury_body.clone()));
|
||||||
|
fields.add_field_method_get("armoury_rings", |_, this| Ok(this.armoury_rings.clone()));
|
||||||
|
fields.add_field_method_get("armoury_soul_crystal", |_, this| {
|
||||||
|
Ok(this.armoury_soul_crystal.clone())
|
||||||
|
});
|
||||||
|
fields.add_field_method_get("currency", |_, this| Ok(this.currency));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserData for Item {
|
||||||
|
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||||
|
fields.add_field_method_get("quantity", |_, this| Ok(this.quantity));
|
||||||
|
fields.add_field_method_get("id", |_, this| Ok(this.id));
|
||||||
|
fields.add_field_method_get("condition", |_, this| Ok(this.condition));
|
||||||
|
fields.add_field_method_get("glamour_catalog_id", |_, this| Ok(this.condition));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserData for CurrencyStorage {
|
||||||
|
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||||
|
fields.add_field_method_get("gil", |_, this| Ok(this.gil));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> UserData for GenericStorage<N> {
|
||||||
|
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||||
|
fields.add_field_method_get("slots", |_, this| Ok(this.slots.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserData for EquippedStorage {
|
||||||
|
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||||
|
fields.add_field_method_get("main_hand", |_, this| Ok(this.main_hand));
|
||||||
|
fields.add_field_method_get("off_hand", |_, this| Ok(this.off_hand));
|
||||||
|
fields.add_field_method_get("head", |_, this| Ok(this.head));
|
||||||
|
fields.add_field_method_get("body", |_, this| Ok(this.body));
|
||||||
|
fields.add_field_method_get("hands", |_, this| Ok(this.hands));
|
||||||
|
fields.add_field_method_get("belt", |_, this| Ok(this.belt));
|
||||||
|
fields.add_field_method_get("legs", |_, this| Ok(this.legs));
|
||||||
|
fields.add_field_method_get("feet", |_, this| Ok(this.feet));
|
||||||
|
fields.add_field_method_get("ears", |_, this| Ok(this.ears));
|
||||||
|
fields.add_field_method_get("neck", |_, this| Ok(this.neck));
|
||||||
|
fields.add_field_method_get("wrists", |_, this| Ok(this.wrists));
|
||||||
|
fields.add_field_method_get("right_ring", |_, this| Ok(this.right_ring));
|
||||||
|
fields.add_field_method_get("left_ring", |_, this| Ok(this.left_ring));
|
||||||
|
fields.add_field_method_get("soul_crystal", |_, this| Ok(this.soul_crystal));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl UserData for ObjectTypeId {}
|
impl UserData for ObjectTypeId {}
|
||||||
|
|
||||||
impl FromLua for ObjectTypeId {
|
impl FromLua for ObjectTypeId {
|
||||||
|
|
Loading…
Add table
Reference in a new issue