Skip to content

Commit

Permalink
shops mostly working in mp
Browse files Browse the repository at this point in the history
  • Loading branch information
wheybags committed May 17, 2018
1 parent 20a508d commit dd87f2e
Show file tree
Hide file tree
Showing 21 changed files with 199 additions and 244 deletions.
6 changes: 4 additions & 2 deletions apps/fontgenerator/main.cpp
@@ -1,9 +1,11 @@
// clang-format off
#include <misc/disablewarn.h>
#include <StormLib.h>
#include <misc/enablewarn.h>
// clang-format on
#include <cel/celdecoder.h>
#include <faio/fafileobject.h>
#include <iostream>
#include <misc/disablewarn.h>
#include <misc/enablewarn.h>
#include <vector>

void help(char** argv)
Expand Down
6 changes: 3 additions & 3 deletions apps/freeablo/fa_main.cpp
@@ -1,10 +1,10 @@
#include <iostream>

// clang-format off
#include <misc/disablewarn.h>
#include <boost/program_options.hpp>
#include <boost/program_options/parsers.hpp>
#include <misc/enablewarn.h>

// clang-format on
#include <iostream>
#include <faio/fafileobject.h>
#include <settings/settings.h>

Expand Down
62 changes: 43 additions & 19 deletions apps/freeablo/fagui/dialogmanager.cpp
@@ -1,4 +1,6 @@
#include "dialogmanager.h"
#include "../engine/enginemain.h"
#include "../engine/localinputhandler.h"
#include "../faworld/actor.h"
#include "../faworld/equiptarget.h"
#include "../faworld/player.h"
Expand Down Expand Up @@ -393,34 +395,56 @@ namespace FAGui

// While there are some similiraties between buying and selling I do not consider them to be that similar to implement
// using single function. Identification dialog could probably be implemented like a sell dialog though.
void DialogManager::buyDialog(std::vector<FAWorld::Item>& items)
void DialogManager::buyDialog(const FAWorld::Actor* shopkeeper, std::vector<FAWorld::StoreItem>& items)
{
// TODO: this function is a mess, but ot sort of works right now, I'm planning on redoing dialog "soon", so it will do for now.
// Also note that after buying an item it will continue to show up as for sale after until you exit and re-enter dialog, is not fixed for the same
// reason as above.

DialogData d;
d.widen();
int32_t cnt = 0;
auto& inventory = mWorld.getCurrentPlayer()->mInventory;

d.header({(boost::format("%2% Your gold : %1%") % inventory.getTotalGold() % "I have these items for sale :").str()});
d.shopData.items = &items;
d.shopData.shopkeeper = shopkeeper;

d.header(
{(boost::format("%2% Your gold : %1%") % mWorld.getCurrentPlayer()->mInventory.getTotalGold() % "I have these items for sale :").str()});

for (auto it = items.begin(); it != items.end(); ++it)
{
auto& item = *it;
auto price = item.getPrice();
auto price = item.item.getPrice();
auto header = d.getHeader();
d.textLines(item.descriptionForMerchants(), TextColor::white, false, {20, 40, 40})
.setAction([this, price, header, it, &items, &inventory]() mutable {
if (inventory.getTotalGold() < price)
return fillMessageDialog(header, "You do not have enough gold");

if (!inventory.getInv(FAWorld::EquipTargetType::inventory).canFitItem(*it))
return fillMessageDialog(header, "You do not have enough room in inventory");

confirmDialog(header, *it, price, "Are you sure you want to buy this item?", [this, price, it, &inventory, &items]() {
inventory.takeOutGold(price);
inventory.autoPlaceItem(*it);
items.erase(it);
auto recreate = [this, &items] { buyDialog(items); };
mGuiManager.popDialogData();
d.textLines(item.item.descriptionForMerchants(), TextColor::white, false, {20, 40, 40})
.setAction([it, price]() {
auto& self = Engine::EngineMain::get()->mGuiManager->mDialogManager;
FAWorld::CharacterInventory& inventory = self.mWorld.getCurrentPlayer()->mInventory;

// if (inventory.getTotalGold() < price)
// return fillMessageDialog(header, "You do not have enough gold");

// if (!inventory.getInv(FAWorld::EquipTargetType::inventory).canFitItem(it->item))
// return fillMessageDialog(header, "You do not have enough room in inventory");

auto& data = Engine::EngineMain::get()->mGuiManager->mDialogs[Engine::EngineMain::get()->mGuiManager->mDialogs.size() - 1];

data.shopData.itemId = it->storeId;

auto header = data.getHeader();

self.confirmDialog(header, it->item, price, "Are you sure you want to buy this item?", []() {
// inventory.takeOutGold(price);
// inventory.autoPlaceItem(it->item);
// items.erase(it);

auto& shopData = Engine::EngineMain::get()->mGuiManager->mDialogs[Engine::EngineMain::get()->mGuiManager->mDialogs.size() - 1].shopData;

auto input = FAWorld::PlayerInput::BuyItemData{shopData.itemId, shopData.shopkeeper->getId()};
Engine::EngineMain::get()->getLocalInputHandler()->addInput(
FAWorld::PlayerInput(input, Engine::EngineMain::get()->mWorld->getCurrentPlayer()->getId()));
auto recreate = [=] { Engine::EngineMain::get()->mGuiManager->mDialogManager.buyDialog(shopData.shopkeeper, *shopData.items); };
Engine::EngineMain::get()->mGuiManager->popDialogData();
recreate();
});
})
Expand All @@ -446,7 +470,7 @@ namespace FAGui
d.textLines({td.at("introduction")}, TextColor::golden);
d.skip_line();
d.textLines({td.at("talk")}, TextColor::blue).setAction([]() {});
d.textLines({td.at("buyBasic")}).setAction([&]() { buyDialog(mWorld.getStoreData().griswoldBasicItems); });
d.textLines({td.at("buyBasic")}).setAction([&]() { buyDialog(npc, mWorld.getStoreData().griswoldBasicItems); });
d.textLines({td.at("buyPremium")}).setAction([]() {});
d.textLines({td.at("sell")}).setAction([&] { sellDialog(griswoldSellFilter); });
d.textLines({td.at("repair")}).setAction([]() {});
Expand Down
11 changes: 10 additions & 1 deletion apps/freeablo/fagui/dialogmanager.h
Expand Up @@ -16,6 +16,7 @@ namespace FAWorld
class World;
class Actor;
class Item;
class StoreItem;
}

namespace FAGui
Expand Down Expand Up @@ -80,6 +81,14 @@ namespace FAGui
void clearLines();
std::vector<DialogLineData> getHeader() const { return mHeader; }

// HACK
struct
{
const FAWorld::Actor* shopkeeper = nullptr;
std::vector<FAWorld::StoreItem>* items = nullptr;
uint32_t itemId = 0;
} shopData;

private:
std::vector<DialogLineData> mHeader;
std::vector<DialogLineData> mLines;
Expand All @@ -100,7 +109,7 @@ namespace FAGui

private:
template <typename FilterType> void sellDialog(FilterType filter);
void buyDialog(std::vector<FAWorld::Item>& items);
void buyDialog(const FAWorld::Actor* shopkeeper, std::vector<FAWorld::StoreItem>& items);

void talkOgden(const FAWorld::Actor* npc);
void talkFarnham(const FAWorld::Actor* npc);
Expand Down
2 changes: 1 addition & 1 deletion apps/freeablo/fagui/guimanager.cpp
Expand Up @@ -90,7 +90,7 @@ namespace FAGui
return "";
}

GuiManager::GuiManager(Engine::EngineMain& engine) : mEngine(engine)
GuiManager::GuiManager(Engine::EngineMain& engine) : mDialogManager(*this, *engine.mWorld.get()), mEngine(engine)
{
mMenuHandler.reset(new MenuHandler(engine));

Expand Down
17 changes: 9 additions & 8 deletions apps/freeablo/fagui/guimanager.h
@@ -1,17 +1,15 @@

#pragma once

#include "../engine/inputobserverinterface.h"
#include "dialogmanager.h"
#include "textcolor.h"
#include <boost/variant/variant_fwd.hpp>
#include <chrono>
#include <fa_nuklear.h>
#include <functional>
#include <memory>
#include <queue>
#include <string>

#include "../engine/inputobserverinterface.h"
#include <boost/variant/variant_fwd.hpp>
#include <fa_nuklear.h>
#include <memory>

struct nk_context;
typedef uint32_t nk_flags;
struct nk_rect;
Expand Down Expand Up @@ -135,7 +133,10 @@ namespace FAGui
void notify(Engine::KeyboardInputAction action) override;
void keyPress(const Input::Hotkey&) override;

private:
public:
DialogManager mDialogManager;

// private:
Engine::EngineMain& mEngine;
FAWorld::Player* mPlayer = nullptr;
std::string mHoveredInventoryItemText;
Expand Down
10 changes: 8 additions & 2 deletions apps/freeablo/faworld/inventory.cpp
Expand Up @@ -588,9 +588,15 @@ namespace FAWorld
copy.mCount -= toTake;
quantity -= toTake;

mMainInventory.remove(item.mInvX, item.mInvY);
int32_t x = item.mInvX;
int32_t y = item.mInvY;

mMainInventory.remove(x, y);
if (copy.mCount > 0)
mMainInventory.placeItem(copy, item.mInvX, item.mInvY);
{
PlaceItemResult result = mMainInventory.placeItem(copy, x, y);
release_assert(result.succeeded());
}

if (quantity == 0)
return;
Expand Down
2 changes: 1 addition & 1 deletion apps/freeablo/faworld/item.cpp
Expand Up @@ -11,7 +11,7 @@

namespace FAWorld
{
void Item::save(FASaveGame::GameSaver& saver)
void Item::save(FASaveGame::GameSaver& saver) const
{
saver.save(mIsReal);
saver.save(mUniqueId);
Expand Down
2 changes: 1 addition & 1 deletion apps/freeablo/faworld/item.h
Expand Up @@ -53,7 +53,7 @@ namespace FAWorld
public:
Item() = default;

void save(FASaveGame::GameSaver& saver);
void save(FASaveGame::GameSaver& saver) const;
void load(FASaveGame::GameLoader& loader);
~Item();
// retrieve description which is shown when hovering over the items in your inventory
Expand Down
5 changes: 4 additions & 1 deletion apps/freeablo/faworld/player.cpp
@@ -1,6 +1,8 @@
#include "player.h"
#include "../engine/enginemain.h"
#include "../engine/threadmanager.h"
#include "../fagui/dialogmanager.h"
#include "../fagui/guimanager.h"
#include "../fasavegame/gameloader.h"
#include "actorstats.h"
#include "boost/algorithm/clamp.hpp"
Expand Down Expand Up @@ -340,7 +342,8 @@ namespace FAWorld

if (target && target->getPos().isNear(this->getPos()) && canTalkTo(target))
{
// mWorld.mDlgManager->talk(target);
if (mWorld.getCurrentPlayer() == this)
Engine::EngineMain::get()->mGuiManager->mDialogManager.talk(target);
mTarget.clear();
}
}
Expand Down
22 changes: 22 additions & 0 deletions apps/freeablo/faworld/playerbehaviour.cpp
Expand Up @@ -4,6 +4,7 @@
#include "equiptarget.h"
#include "input/inputmanager.h"
#include "player.h"
#include "storedata.h"
#include <misc/assert.h>

namespace FAWorld
Expand Down Expand Up @@ -120,6 +121,27 @@ namespace FAWorld
mPlayer->getWorld()->getItemFactory());
return;
}
case PlayerInput::Type::BuyItem:
{
auto items = mPlayer->getWorld()->getStoreData().griswoldBasicItems;
auto item = std::find_if(items.begin(), items.end(), [&](StoreItem& item) { return item.storeId == input.mData.dataBuyItem.itemId; });

if (item == items.end())
return;

int32_t price = item->item.getPrice();
if (mPlayer->mInventory.getTotalGold() < price)
return;

if (!mPlayer->mInventory.getInv(FAWorld::EquipTargetType::inventory).canFitItem(item->item))
return;

mPlayer->mInventory.takeOutGold(price);
mPlayer->mInventory.autoPlaceItem(item->item);
items.erase(item);

return;
}
case PlayerInput::Type::PlayerJoined:
case PlayerInput::Type::PlayerLeft:
{
Expand Down
12 changes: 12 additions & 0 deletions apps/freeablo/faworld/playerinput.cpp
Expand Up @@ -121,4 +121,16 @@ namespace FAWorld
void PlayerInput::PlayerJoinedData::save(Serial::Saver& saver) { saver.save(peerId); }

void PlayerInput::PlayerJoinedData::load(Serial::Loader& loader) { peerId = loader.load<uint32_t>(); }

void PlayerInput::BuyItemData::save(Serial::Saver& saver)
{
saver.save(itemId);
saver.save(shopkeeperId);
}

void PlayerInput::BuyItemData::load(Serial::Loader& loader)
{
itemId = loader.load<uint32_t>();
shopkeeperId = loader.load<int32_t>();
}
}
11 changes: 10 additions & 1 deletion apps/freeablo/faworld/playerinput.h
Expand Up @@ -14,7 +14,8 @@
MACRO(InventorySlotClicked) \
MACRO(SplitGoldStackIntoCursor) \
MACRO(PlayerJoined) \
MACRO(PlayerLeft)
MACRO(PlayerLeft) \
MACRO(BuyItem)

namespace Serial
{
Expand Down Expand Up @@ -103,6 +104,14 @@ namespace FAWorld
void save(Serial::Saver&) {}
void load(Serial::Loader&) {}
};
struct BuyItemData
{
uint32_t itemId;
int32_t shopkeeperId;

void save(Serial::Saver& saver);
void load(Serial::Loader& loader);
};

// All this macro mess takes care of generating boilerplate code to wrap up the above structs into a union with a type enum, and
// save/load functions. So, eg, if mType == TargetTile, then you can access mData.dataTargetType. You can also call .save() and .load()
Expand Down
41 changes: 38 additions & 3 deletions apps/freeablo/faworld/storedata.cpp
@@ -1,5 +1,5 @@
#include "storedata.h"
#include "item.h"
#include "../fasavegame/gameloader.h"
#include "itemfactory.h"
#include <random/random.h>

Expand All @@ -12,7 +12,42 @@ namespace FAWorld
int32_t count = rng.randomInRange(10, 20);
griswoldBasicItems.resize(count);
for (auto& item : griswoldBasicItems)
item = mItemFactory.generateBaseItem(mItemFactory.randomItemId(ItemFilter::maxQLvl(ilvl), ItemFilter::sellableGriswoldBasic()));
std::sort(griswoldBasicItems.begin(), griswoldBasicItems.end(), [](const Item& lhs, const Item& rhs) { return lhs.baseId() < rhs.baseId(); });
{
item.item = mItemFactory.generateBaseItem(mItemFactory.randomItemId(ItemFilter::maxQLvl(ilvl), ItemFilter::sellableGriswoldBasic()));
item.storeId = mNextItemId;
mNextItemId++;
}

std::sort(griswoldBasicItems.begin(), griswoldBasicItems.end(), [](const StoreItem& lhs, const StoreItem& rhs) {
return lhs.item.baseId() < rhs.item.baseId();
});
}

void StoreData::save(FASaveGame::GameSaver& saver) const
{
saver.save(uint32_t(griswoldBasicItems.size()));
for (auto& item : griswoldBasicItems)
{
saver.save(item.storeId);
item.item.save(saver);
}

saver.save(mNextItemId);
}

void StoreData::load(FASaveGame::GameLoader& loader)
{
griswoldBasicItems.clear();

uint32_t size = loader.load<uint32_t>();
griswoldBasicItems.resize(size);

for (uint32_t i = 0; i < size; i++)
{
griswoldBasicItems[i].storeId = loader.load<uint32_t>();
griswoldBasicItems[i].item.load(loader);
}

mNextItemId = loader.load<uint32_t>();
}
}

0 comments on commit dd87f2e

Please sign in to comment.