diff --git a/USAGE.md b/USAGE.md index 74f7846..e2799ac 100644 --- a/USAGE.md +++ b/USAGE.md @@ -129,3 +129,4 @@ These GM commands are implemented in the FFXIV protocol, but only some of them a * `//gm lv `: Sets your current level * `//gm aetheryte `: Unlock an Aetheryte. * `//gm speed `: Increases your movement speed by `multiplier`. +* `//gm orchestrion `: Unlock an Orchestrion song. diff --git a/resources/scripts/Global.lua b/resources/scripts/Global.lua index c00c227..b112ce4 100644 --- a/resources/scripts/Global.lua +++ b/resources/scripts/Global.lua @@ -193,8 +193,11 @@ registerEvent(327918, "common/GenericAetheryte.lua") -- Dock Poga Aetheryte -- Misc. Events registerEvent(720915, "common/GenericMender.lua") registerEvent(720916, "custom/000/cmndefinnbed_00020.lua") +registerEvent(721096, "tosort/ToyChest.lua") registerEvent(721028, "tosort/UnendingJourney.lua") registerEvent(721044, "tosort/CrystalBell.lua") +registerEvent(721226, "tosort/Orchestrion.lua") +registerEvent(721347, "tosort/GlamourDresser.lua") registerEvent(1179657, "tosort/Chocobokeep.lua") -- Chocobokeep in Central Shroud registerEvent(1245185, "opening/OpeningLimsaLominsa.lua") registerEvent(1245186, "opening/OpeningGridania.lua") diff --git a/resources/scripts/commands/debug/UnlockAetheryte.lua b/resources/scripts/commands/debug/UnlockAetheryte.lua index eb94fc5..9106231 100644 --- a/resources/scripts/commands/debug/UnlockAetheryte.lua +++ b/resources/scripts/commands/debug/UnlockAetheryte.lua @@ -29,7 +29,7 @@ function onCommand(args, player) if id == "all" then id = 0 else - player:send_message(sender.."Error parsing id parameter. Must be a territory id or the word 'all'."..usage) + player:send_message(sender.."Error parsing id parameter. Must be an aetheryte id or the word 'all'."..usage) return end end diff --git a/resources/scripts/tosort/GlamourDresser.lua b/resources/scripts/tosort/GlamourDresser.lua new file mode 100644 index 0000000..9ff4c5e --- /dev/null +++ b/resources/scripts/tosort/GlamourDresser.lua @@ -0,0 +1,10 @@ +-- TODO: actually implement this menu + +function onTalk(target, player) + -- You have not yet unlocked the glamour dresser. + player:play_scene(target, EVENT_ID, 00000, 8192, 0) +end + +function onReturn(scene, results, player) + player:finish_event(EVENT_ID) +end diff --git a/resources/scripts/tosort/Orchestrion.lua b/resources/scripts/tosort/Orchestrion.lua new file mode 100644 index 0000000..06ebbe3 --- /dev/null +++ b/resources/scripts/tosort/Orchestrion.lua @@ -0,0 +1,7 @@ +function onTalk(target, player) + player:play_scene(target, EVENT_ID, 00000, 8192, 0) +end + +function onReturn(scene, results, player) + player:finish_event(EVENT_ID) +end diff --git a/resources/scripts/tosort/ToyChest.lua b/resources/scripts/tosort/ToyChest.lua new file mode 100644 index 0000000..07cc6aa --- /dev/null +++ b/resources/scripts/tosort/ToyChest.lua @@ -0,0 +1,10 @@ +-- TODO: actually implement this menu + +function onTalk(target, player) + -- You have not yet unlocked any mini-games. + player:play_scene(target, EVENT_ID, 00000, 8192, 0) +end + +function onReturn(scene, results, player) + player:finish_event(EVENT_ID) +end diff --git a/src/bin/kawari-world.rs b/src/bin/kawari-world.rs index 504b644..b2c61f0 100644 --- a/src/bin/kawari-world.rs +++ b/src/bin/kawari-world.rs @@ -646,6 +646,27 @@ async fn client_loop( connection.player_data.inventory.add_in_next_free_slot(Item { id: *arg0, quantity: 1 }); connection.send_inventory(false).await; } + GameMasterCommandType::Orchestrion => { + let on = *arg0 == 1; // This command uses 1 for on, 2 for off. + let id = *arg1 as u16; + + // id == 0 means "all" + if id == 0 { + /* Currently 792 songs ingame. + * Commented out because this learns literally zero songs + * for some unknown reason. */ + /*for i in 1..793 { + let idd = i as u16; + connection.send_message("test!").await; + connection.actor_control_self(ActorControlSelf { + category: ActorControlCategory::ToggleOrchestrionUnlock { song_id: id, unlocked: on } }).await; + }*/ + } else { + connection.actor_control_self(ActorControlSelf { + category: ActorControlCategory::ToggleOrchestrionUnlock { song_id: id, unlocked: on } + }).await; + } + } GameMasterCommandType::Aetheryte => { let on = *arg0 == 0; let id = *arg1; diff --git a/src/ipc/zone/actor_control.rs b/src/ipc/zone/actor_control.rs index f36e0a1..283d17a 100644 --- a/src/ipc/zone/actor_control.rs +++ b/src/ipc/zone/actor_control.rs @@ -84,6 +84,17 @@ pub enum ActorControlCategory { }, #[brw(magic = 0xFu16)] CancelCast {}, + #[brw(magic = 0x396u16)] + ToggleOrchestrionUnlock { + #[brw(pad_before = 2)] // padding + song_id: u16, + /* TODO: guessed, Sapphire suggests it's an u32 item id, + * but it behaves as an unlock boolean like aetherytes, so + perhaps it's been repurposed since Shadowbringers. */ + #[br(map = read_bool_from::)] + #[bw(map = write_bool_as::)] + unlocked: bool, + }, } #[binrw] diff --git a/src/ipc/zone/mod.rs b/src/ipc/zone/mod.rs index ab4f079..7256897 100644 --- a/src/ipc/zone/mod.rs +++ b/src/ipc/zone/mod.rs @@ -144,6 +144,7 @@ pub enum GameMasterCommandType { ToggleInvisibility = 0xD, ToggleWireframe = 0x26, ChangeTerritory = 0x58, + Orchestrion = 0x74, GiveItem = 0xC8, Aetheryte = 0x5E, }