Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions HeavenClient/Character/Inventory/Inventory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,18 @@ namespace ms
}
}

int16_t Inventory::equip_position(int16_t slot, EquipSlot::Id part) const
{
return get_cash_id(InventoryType::Id::EQUIP, slot) ? part + CASH_EQUIP : part;
}

int16_t Inventory::shown_equip(EquipSlot::Id part) const
{
int16_t cash = part + CASH_EQUIP;

return inventories[InventoryType::Id::EQUIPPED].count(cash) ? cash : part;
}

int16_t Inventory::find_free_slot(InventoryType::Id type) const
{
int16_t counter = 1;
Expand Down
12 changes: 12 additions & 0 deletions HeavenClient/Character/Inventory/Inventory.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ namespace ms
ADDCOUNT
};

// How far above its slot a cash item is worn.
static constexpr int16_t CASH_EQUIP = 100;

// Return the move type by value
static Movement movementbyvalue(int8_t value);

Expand Down Expand Up @@ -121,6 +124,15 @@ namespace ms
// Find a free slot for the specified equip.
EquipSlot::Id find_equipslot(int32_t itemid) const;

// The worn position for the equip in Equip tab `slot` at `part`. Like
// v83 (FUN_004f2cbb), an item with a Cash Shop serial is worn 100
// above its slot, over whatever regular item is there.
int16_t equip_position(int16_t slot, EquipSlot::Id part) const;

// The worn position whose item is shown at `part`: the cash item's
// if there is one (FUN_007fec81), else the regular one's.
int16_t shown_equip(EquipSlot::Id part) const;

// Find a free slot in the specified inventory.
int16_t find_free_slot(InventoryType::Id type) const;

Expand Down
13 changes: 11 additions & 2 deletions HeavenClient/Character/Player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,19 @@ namespace ms

void Player::change_equip(int16_t slot)
{
if (int32_t itemid = inventory.get_item_id(InventoryType::Id::EQUIPPED, slot))
EquipSlot::Id part = EquipSlot::by_id(slot % Inventory::CASH_EQUIP);

if (part == EquipSlot::Id::NONE)
return;

// The look wears a cash item over the regular one, but has no cash
// weapons (v83 draws them over the regular weapon's stances).
int16_t shown = part == EquipSlot::Id::WEAPON ? part : inventory.shown_equip(part);

if (int32_t itemid = inventory.get_item_id(InventoryType::Id::EQUIPPED, shown))
look.add_equip(itemid);
else
look.remove_equip(EquipSlot::by_id(slot));
look.remove_equip(part);
}

void Player::use_item(int32_t itemid)
Expand Down
2 changes: 1 addition & 1 deletion HeavenClient/IO/UI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ namespace ms
Music::set_bgmvolume(Music::configured_volume());

// v83 checks the balances on coming back to the Cash Shop.
if (get_element<UICashShop>())
if (auto cashshop = get_element<UICashShop>(); cashshop && cashshop->request())
CheckCashPacket().dispatch();
} else
{
Expand Down
24 changes: 9 additions & 15 deletions HeavenClient/IO/UIStateCashShop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,26 +90,20 @@ namespace ms

return focusedelement->send_cursor(clicked, cursorpos);
}
else
{
focused = UIElement::NONE;

return cursorstate;
}
// A closed dialog lets the window under it have the cursor at
// once, or the first click after it would find no button hovered.
focused = UIElement::NONE;
}
else

if (auto front = get_front())
{
if (auto front = get_front())
{
remove_cursor(front->get_type());
remove_cursor(front->get_type());

return front->send_cursor(clicked, cursorpos);
}
else
{
return Cursor::State::IDLE;
}
return front->send_cursor(clicked, cursorpos);
}

return Cursor::State::IDLE;
}

UIState::Iterator UIStateCashShop::pre_add(UIElement::Type type, bool toggled, bool is_focused)
Expand Down
22 changes: 14 additions & 8 deletions HeavenClient/IO/UITypes/UICashBuy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. //
//////////////////////////////////////////////////////////////////////////////////
#include "UICashBuy.h"
#include "UICashShop.h"

#include "../KeyAction.h"
#include "../UI.h"

#include "../Components/MapleButton.h"

Expand Down Expand Up @@ -164,15 +166,19 @@ namespace ms
void UICashBuy::buy()
{
CashType cash_type = PAYMENTS[payment];
auto cashshop = UI::get().get_element<UICashShop>();

if (is_package(item_id))
BuyCashPackagePacket(cash_type, sn).dispatch();
else if (is_expansion(item_id) && sn == 0)
ExpandSlotsPacket(cash_type, expanded(item_id)).dispatch();
else if (is_expansion(item_id))
ExpandSlotsPacket(cash_type, expanded(item_id), sn).dispatch();
else
BuyCashItemPacket(cash_type, sn).dispatch();
if (cashshop && cashshop->request())
{
if (is_package(item_id))
BuyCashPackagePacket(cash_type, sn).dispatch();
else if (is_expansion(item_id) && sn == 0)
ExpandSlotsPacket(cash_type, expanded(item_id)).dispatch();
else if (is_expansion(item_id))
ExpandSlotsPacket(cash_type, expanded(item_id), sn).dispatch();
else
BuyCashItemPacket(cash_type, sn).dispatch();
}

deactivate();
}
Expand Down
5 changes: 4 additions & 1 deletion HeavenClient/IO/UITypes/UICashGift.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. //
//////////////////////////////////////////////////////////////////////////////////
#include "UICashGift.h"
#include "UICashShop.h"

#include "../KeyAction.h"
#include "../UI.h"
Expand Down Expand Up @@ -181,7 +182,9 @@ namespace ms
if (asking_birthday)
{
// The server answers a wrong code with its own notice.
GiftCashItemPacket(birthday_code(birthday.get_text()), sn, to.get_text(), message.get_text()).dispatch();
if (auto cashshop = UI::get().get_element<UICashShop>(); cashshop && cashshop->request())
GiftCashItemPacket(birthday_code(birthday.get_text()), sn, to.get_text(), message.get_text()).dispatch();

close();

return;
Expand Down
34 changes: 27 additions & 7 deletions HeavenClient/IO/UITypes/UICashShop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ namespace ms
}
}

UICashShop::UICashShop() : tab(EVENT_TAB), subtab(0), page(0), preview_index(0), female(false), credit(0), points(0), prepaid(0), cash_row(0), item_tab(InventoryType::Id::EQUIP), item_row(0)
UICashShop::UICashShop() : tab(EVENT_TAB), subtab(0), page(0), preview_index(0), female(false), credit(0), points(0), prepaid(0), pending(false), cash_row(0), item_tab(InventoryType::Id::EQUIP), item_row(0)
{
nl::node CashShop = NxFiles::ui_classic["CashShop.img"];
nl::node Base = CashShop["Base"];
Expand Down Expand Up @@ -430,7 +430,8 @@ namespace ms
return Button::State::NORMAL;
}
case Buttons::BT_CHECK:
CheckCashPacket().dispatch();
if (request())
CheckCashPacket().dispatch();

return Button::State::NORMAL;
default:
Expand All @@ -448,18 +449,21 @@ namespace ms
{
const Commodity& commodity = listed[index];

if (remove)
if (pending)
return Button::State::NORMAL;

if (remove && request())
SetWishListPacket(unwish(wish_list, commodity.sn)).dispatch();
else if (list_button % 3 == 0)
UI::get().emplace<UICashBuy>(commodity, credit, points, prepaid);
else if (list_button % 3 == 1)
UI::get().emplace<UICashGift>(commodity);
else if (list_button % 3 == 2)
else if (list_button % 3 == 2 && request())
SetWishListPacket(wish(wish_list, commodity.sn)).dispatch();
}
}

if (buttonid >= Buttons::BT_EX_EQUIP && buttonid <= Buttons::BT_EX_TRUNK)
if (buttonid >= Buttons::BT_EX_EQUIP && buttonid <= Buttons::BT_EX_TRUNK && !pending)
{
// Four slots for 4,000 NX, shown as the expansion item: 9111000
// to 9114000 for the bags, 9110000 for the storage.
Expand Down Expand Up @@ -585,7 +589,8 @@ namespace ms
InventoryType::Id type = InventoryType::by_item_id(item.item_id);

// The server picks another slot, or refuses, if this one is taken.
TakeOutCashItemPacket(item.cash_id, type, inventory.find_free_slot(type)).dispatch();
if (request())
TakeOutCashItemPacket(item.cash_id, type, inventory.find_free_slot(type)).dispatch();
return;
}

Expand All @@ -595,11 +600,26 @@ namespace ms
{
int16_t slot = static_cast<int16_t>(item_row * ITEM_COLUMNS + item_cell + 1);

if (int64_t cash_id = inventory.get_cash_id(item_tab, slot))
if (int64_t cash_id = inventory.get_cash_id(item_tab, slot); cash_id && request())
PutBackCashItemPacket(cash_id, item_tab).dispatch();
}
}

bool UICashShop::request()
{
if (pending)
return false;

pending = true;

return true;
}

void UICashShop::answered()
{
pending = false;
}

int16_t UICashShop::grid_cell(Point<int16_t> cursor, Point<int16_t> grid, size_t columns, size_t rows) const
{
Point<int16_t> in_grid = cursor - grid;
Expand Down
8 changes: 8 additions & 0 deletions HeavenClient/IO/UITypes/UICashShop.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ namespace ms
void remove_cash_item(int64_t cash_id);
void set_wish_list(const std::vector<int32_t>& sns);

// v83 (CCashShop+0x18) has one request out at a time and ignores the
// buttons until its answer. Returns whether one may be sent, counting
// it as sent.
bool request();
// A balance or an operation result came.
void answered();

private:
void change_tab(cash_catalog::Tab tab);
void change_subtab(size_t subtab);
Expand Down Expand Up @@ -165,6 +172,7 @@ namespace ms
int32_t credit;
int32_t points;
int32_t prepaid;
bool pending;

std::vector<CashItem> cash_items;
Slider cash_slider;
Expand Down
26 changes: 16 additions & 10 deletions HeavenClient/IO/UITypes/UIEquipInventory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,12 +219,14 @@ namespace ms

void UIEquipInventory::update_slot(EquipSlot::Id slot)
{
if (int32_t item_id = inventory.get_item_id(InventoryType::Id::EQUIPPED, slot))
int16_t shown = inventory.shown_equip(slot);

if (int32_t item_id = inventory.get_item_id(InventoryType::Id::EQUIPPED, shown))
{
const Texture &texture = ItemData::get(item_id).get_icon(false);

icons[slot] = std::make_unique<Icon>(
std::make_unique<EquipIcon>(slot),
std::make_unique<EquipIcon>(shown),
texture,
-1
);
Expand Down Expand Up @@ -270,7 +272,7 @@ namespace ms
return Cursor::State::GRABBING;
} else
{
show_equip(slot);
show_equip(inventory.shown_equip(slot));

return Cursor::State::CANGRAB;
}
Expand Down Expand Up @@ -299,7 +301,8 @@ namespace ms

if (icons[slot])
if (int16_t freeslot = inventory.find_free_slot(InventoryType::Id::EQUIP))
Stage::get().get_player().request(UnequipItemPacket(slot, freeslot), ExclRequest::WAIT);
Stage::get().get_player().request(UnequipItemPacket(inventory.shown_equip(slot), freeslot),
ExclRequest::WAIT);
}

bool UIEquipInventory::is_in_range(Point<int16_t> cursorpos) const
Expand Down Expand Up @@ -334,8 +337,8 @@ namespace ms

void UIEquipInventory::modify(int16_t pos, int8_t mode, int16_t arg)
{
EquipSlot::Id eqpos = EquipSlot::by_id(pos);
EquipSlot::Id eqarg = EquipSlot::by_id(arg);
EquipSlot::Id eqpos = EquipSlot::by_id(pos % Inventory::CASH_EQUIP);
EquipSlot::Id eqarg = EquipSlot::by_id(arg % Inventory::CASH_EQUIP);

switch (mode)
{
Expand All @@ -350,7 +353,7 @@ namespace ms
}
}

void UIEquipInventory::show_equip(EquipSlot::Id slot)
void UIEquipInventory::show_equip(int16_t slot)
{
UI::get().show_equip(Tooltip::Parent::EQUIPINVENTORY, slot);
}
Expand Down Expand Up @@ -386,7 +389,7 @@ namespace ms

void UIEquipInventory::EquipIcon::drop_on_equips(EquipSlot::Id slot) const
{
if (source == slot)
if (source % Inventory::CASH_EQUIP == slot)
Sound(Sound::Name::DRAGEND).play();
}

Expand All @@ -406,8 +409,11 @@ namespace ms

if (equip)
{
if (eqslot == source)
Stage::get().get_player().request(EquipItemPacket(slot, eqslot), ExclRequest::WAIT);
// Only an item worn at the same position swaps with this one.
int16_t worn = Stage::get().get_player().get_inventory().equip_position(slot, eqslot);

if (worn == source)
Stage::get().get_player().request(EquipItemPacket(slot, worn), ExclRequest::WAIT);
} else
{
Stage::get().get_player().request(UnequipItemPacket(source, slot), ExclRequest::WAIT);
Expand Down
4 changes: 3 additions & 1 deletion HeavenClient/IO/UITypes/UIEquipInventory.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ namespace ms
Button::State button_pressed(uint16_t buttonid) override;

private:
void show_equip(EquipSlot::Id slot);
// Shows the tooltip for worn position `slot`.
void show_equip(int16_t slot);
void clear_tooltip();

void load_icons();
Expand All @@ -66,6 +67,7 @@ namespace ms
class EquipIcon : public Icon::Type
{
public:
// For the item at worn position `source`.
EquipIcon(int16_t source);

void drop_on_stage() const override;
Expand Down
Loading
Loading