1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-07-10 16:07:45 +00:00

Begin implementing gil shops, add free item to inventory

Tested against the Florist in New Gridania, although we don't
deduct the item price from you and such.
This commit is contained in:
Joshua Goins 2025-06-30 20:26:15 -04:00
parent a1e6488533
commit 3695ee4352
4 changed files with 28 additions and 4 deletions

4
Cargo.lock generated
View file

@ -567,7 +567,7 @@ dependencies = [
[[package]] [[package]]
name = "icarus" name = "icarus"
version = "0.0.0" version = "0.0.0"
source = "git+https://github.com/redstrate/Icarus?branch=ver%2F2025.06.10.0000.0000#67c49d1e161f140fb5e1ee2bb051e8901ba3f6eb" source = "git+https://github.com/redstrate/Icarus?branch=ver%2F2025.06.10.0000.0000#c6eb3b05ebe54b86c25d09dbc0bfc7b30f5cdadf"
dependencies = [ dependencies = [
"physis", "physis",
] ]
@ -1048,7 +1048,7 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]] [[package]]
name = "physis" name = "physis"
version = "0.5.0" version = "0.5.0"
source = "git+https://github.com/redstrate/physis#6ebb7acfcdcf80e2de9ce8d36fae42bb964d9cfc" source = "git+https://github.com/redstrate/physis#862b16b681e8593f2b327442deddc12922209531"
dependencies = [ dependencies = [
"binrw", "binrw",
"bitflags", "bitflags",

View file

@ -308,6 +308,7 @@ common_events = {
-- NPC shops that accept gil for purchasing items -- NPC shops that accept gil for purchasing items
generic_gil_shops = { generic_gil_shops = {
262157, -- Tanie <Florist>, New Gridania
263220, -- Neon <Air-wheeler dealer>, Solution Nine 263220, -- Neon <Air-wheeler dealer>, Solution Nine
} }

View file

@ -6,6 +6,7 @@ use kawari::RECEIVE_BUFFER_SIZE;
use kawari::common::Position; use kawari::common::Position;
use kawari::common::{GameData, timestamp_secs}; use kawari::common::{GameData, timestamp_secs};
use kawari::config::get_config; use kawari::config::get_config;
use kawari::inventory::Item;
use kawari::ipc::chat::{ServerChatIpcData, ServerChatIpcSegment}; use kawari::ipc::chat::{ServerChatIpcData, ServerChatIpcSegment};
use kawari::ipc::zone::{ use kawari::ipc::zone::{
ActorControlCategory, ActorControlSelf, PlayerEntry, PlayerSpawn, PlayerStatus, SocialList, ActorControlCategory, ActorControlSelf, PlayerEntry, PlayerSpawn, PlayerStatus, SocialList,
@ -790,8 +791,21 @@ async fn client_loop(
ClientZoneIpcData::GilShopTransaction { event_id, unk1: _, buy_sell_mode, item_index, item_quantity, unk2: _ } => { ClientZoneIpcData::GilShopTransaction { event_id, unk1: _, buy_sell_mode, item_index, item_quantity, unk2: _ } => {
tracing::info!("Client is interacting with a shop! {event_id:#?} {buy_sell_mode:#?} {item_quantity:#?} {item_index:#?}"); tracing::info!("Client is interacting with a shop! {event_id:#?} {buy_sell_mode:#?} {item_quantity:#?} {item_index:#?}");
// TODO: update the client's inventory, adjust their gil, and send the proper response packets! let item_id;
connection.send_message("Shops are not implemented yet. Cancelling event...").await; {
let mut game_data = connection.gamedata.lock().unwrap();
item_id = game_data.get_gilshop_item(*event_id, *item_index as u16);
}
if let Some(item_id) = item_id {
// TODO: adjust their gil, and send the proper response packets!
connection.send_message("Shops are not implemented fully yet. Giving you a free item...").await;
connection.player_data.inventory.add_in_next_free_slot(Item::new(1, item_id as u32));
connection.send_inventory(false).await;
} else {
connection.send_message(&format!("Unable to find shop item, this is a bug in Kawari!")).await;
}
// Cancel the event for now so the client doesn't get stuck // Cancel the event for now so the client doesn't get stuck
connection.event_finish(*event_id).await; connection.event_finish(*event_id).await;

View file

@ -2,6 +2,7 @@ use icarus::Action::ActionSheet;
use icarus::Aetheryte::AetheryteSheet; use icarus::Aetheryte::AetheryteSheet;
use icarus::ClassJob::ClassJobSheet; use icarus::ClassJob::ClassJobSheet;
use icarus::EquipSlotCategory::EquipSlotCategorySheet; use icarus::EquipSlotCategory::EquipSlotCategorySheet;
use icarus::GilShopItem::GilShopItemSheet;
use icarus::PlaceName::PlaceNameSheet; use icarus::PlaceName::PlaceNameSheet;
use icarus::TerritoryType::TerritoryTypeSheet; use icarus::TerritoryType::TerritoryTypeSheet;
use icarus::WeatherRate::WeatherRateSheet; use icarus::WeatherRate::WeatherRateSheet;
@ -329,6 +330,14 @@ impl GameData {
pub fn get_exp_array_index(&self, classjob_id: u16) -> Option<i8> { pub fn get_exp_array_index(&self, classjob_id: u16) -> Option<i8> {
self.classjob_exp_indexes.get(classjob_id as usize).copied() self.classjob_exp_indexes.get(classjob_id as usize).copied()
} }
/// Gets the item and it's cost from the specified shop.
pub fn get_gilshop_item(&mut self, gilshop_id: u32, index: u16) -> Option<i32> {
let sheet = GilShopItemSheet::read_from(&mut self.game_data, Language::None)?;
let row = sheet.get_subrow(gilshop_id, index)?;
row.Item().into_i32().copied()
}
} }
// Simple enum for GameData::get_territory_name // Simple enum for GameData::get_territory_name