From badfb31888a6bd62e0a019b3f3dec517df4121ec Mon Sep 17 00:00:00 2001 From: Stijn Buys Date: Sat, 18 Sep 2010 22:11:27 +0000 Subject: trade updates --- doc/GAMEPLAY | 7 ++--- doc/TODO | 35 ++++++--------------- src/client/inventorylistview.cc | 39 +++++++++++++++++++++--- src/client/inventorylistview.h | 11 ++++++- src/client/trademenu.cc | 50 +++++++++++++++++++++++++----- src/client/trademenu.h | 4 +++ src/core/inventory.cc | 2 +- src/core/inventory.h | 2 +- src/core/item.cc | 2 +- src/game/base/cargo.cc | 67 +++++++++++++++++++++++++++++++++++++++++ src/game/base/cargo.h | 2 ++ src/game/base/game.cc | 57 +++++++++++++++++++++++++++++------ src/game/base/game.h | 1 + src/ui/listitem.cc | 1 + src/ui/listitem.h | 10 ++++++ src/ui/listview.cc | 7 +++++ src/ui/listview.h | 3 ++ src/ui/widget.cc | 9 ++++++ src/ui/widget.h | 3 ++ 19 files changed, 257 insertions(+), 55 deletions(-) diff --git a/doc/GAMEPLAY b/doc/GAMEPLAY index 54766ad..79fafba 100644 --- a/doc/GAMEPLAY +++ b/doc/GAMEPLAY @@ -149,10 +149,9 @@ Traveling Capital Ships - As the player earns money, he will hopefully eventually be able - to buy very large capital ships. Apart from beeing large and powerful, - capship can be docked by other players and used like any other dockable - planet or station. + As the player earns money, he will eventually be able to buy very large capital ships. + Apart from beeing large and powerful, capship can be docked by other players and + used like any other dockable planet or station. A ship docked at the capship is able to use it as a carrier, and launch when the carrier has reached its destination, or circumstances require it. diff --git a/doc/TODO b/doc/TODO index ef42f7f..3349760 100644 --- a/doc/TODO +++ b/doc/TODO @@ -5,26 +5,15 @@ ------------------------------------------------------------------ -version 0.1.0: +general: documentation cleanup finish player guide - udpate user manual - - SVN reorganisation - data reorganization - - fix ui widget hierarchy - -version 0.2.0: - cargo - inventories + update user manual server-client event system, hit-once lightweight entities explosion events sound events world sounds eject/beam cargo - -version 0.3.0: weapons ship improvements (radars, shield, armor) @@ -37,13 +26,12 @@ filesystem: fs_base, fs_mod, fs_game, to be used by modules model: - read .ase material name - correct .map texture scaling issues - import .ase models into .map files (+submodel instancing) (ok, misc_model) - correct misc_model position issue when importing .map files + .ase submaterials + .3ds support + .md3 support core: - BUG dedicated server does not show chat messages + BUG dedicated server does not show chat messages (to be verified) fix game.ini load/save sequence network: @@ -57,6 +45,7 @@ network: fix lag/client interpolation cl_prediction or cl_interpolation detect and disconnect clients behaving badly + EXT messages, update extended property "ext id prop value prop value etc", type checking/seperator etc.. EXT zone/color/shield/armor/health @@ -66,25 +55,19 @@ client: fix camera frustum clip (size issue, postponed) tracking camera absolute speed/position gui concept artwork - sanitize view menu remote command (ok) - fix map/hud selection interaction - split chat into chatwindow, chatbox and chathistory - add statuswindow and inventorywindow.h render: star light strenght sphere texture distortion at the poles ui: - add generic trade/inventory widget + sound: entity/event positional sounds jump drive sound events game: - player credits (ok) - entity health/shield/armor data: @@ -92,4 +75,4 @@ data: rename skies (lindblade1, lindblade2, ...) win32 port: - pdcurses support (ok) + diff --git a/src/client/inventorylistview.cc b/src/client/inventorylistview.cc index 1b46fd0..d2752d6 100644 --- a/src/client/inventorylistview.cc +++ b/src/client/inventorylistview.cc @@ -11,17 +11,23 @@ namespace client { InventoryListView::InventoryListView(ui::Widget *parent) : ui::ListView (parent) { + listview_timestamp = 0; set_inventory(0, 0); } InventoryListView::~InventoryListView() { } -void InventoryListView::set_inventory(core::Inventory *inventory, core::InfoType *info_type) +void InventoryListView::set_inventory(core::Inventory *inventory, core::InfoType *infotype) { remove_children(); - if (!inventory || !info_type) { + listview_inventory = inventory; + listview_infotype = infotype; + + const core::Item *selecteditem = (selected() ? selected()->item() : 0); + + if (!inventory || !infotype) { return; } @@ -31,15 +37,38 @@ void InventoryListView::set_inventory(core::Inventory *inventory, core::InfoType for (core::Inventory::Items::const_iterator it = inventory->items().begin(); it != inventory->items().end(); it++) { core::Item *item = (*it); - if (item->info() && item->info()->type() == info_type) { - ui::ListItem *listitem = 0; - listitem = new ui::ListItem(this, item->info()->name().c_str()); + if (item->info() && (item->info()->type() == infotype) && (item->amount() != 0) ) { + ui::ListItem *listitem = 0; + + std::ostringstream str; + str << item->info()->name().c_str(); + + if (item->amount() > 0) { + str << " (" << item->amount() << ")"; + } + listitem = new ui::ListItem(this, str.str().c_str()); listitem->set_height(listitem->font()->height() * 2.0f); + listitem->set_item(item); listitem->set_info(item->info()); + // preserve previous selection during update + if (item == selecteditem) { + ui::ListView::select(listitem); + } } } + listview_timestamp = inventory->timestamp(); + event_resize(); } +void InventoryListView::draw() +{ + if (listview_timestamp != listview_inventory->timestamp()) { + set_inventory(listview_inventory, listview_infotype); + } + + ListView::draw(); +} + } // namespace client \ No newline at end of file diff --git a/src/client/inventorylistview.h b/src/client/inventorylistview.h index 82a9cc4..0d14072 100644 --- a/src/client/inventorylistview.h +++ b/src/client/inventorylistview.h @@ -19,7 +19,16 @@ public: InventoryListView(ui::Widget *parent = 0); ~InventoryListView(); - void set_inventory(core::Inventory *inventory, core::InfoType *info_type); + void set_inventory(core::Inventory *inventory, core::InfoType *infotype); + +protected: + + virtual void draw(); + +private: + unsigned long listview_timestamp; + core::Inventory *listview_inventory; + core::InfoType *listview_infotype; }; } // namespace client diff --git a/src/client/trademenu.cc b/src/client/trademenu.cc index 837ee87..d93864d 100644 --- a/src/client/trademenu.cc +++ b/src/client/trademenu.cc @@ -42,6 +42,15 @@ TradeMenu::TradeMenu(ui::Widget *parent, const char * label) : ui::Window(parent menu_inventorylistview->set_background(false); menu_inventorylistview->set_border(true); + menu_inventorylabel = new ui::Label(menu_tradewindow); + menu_inventorylabel->set_label("label"); + menu_inventorylabel->set_background(false); + menu_inventorylabel->set_border(false); + menu_inventorylabel->set_font(ui::root()->font_small()); + menu_inventorylabel->set_alignment(ui::AlignLeft); + + + menu_modelview = new ui::ModelView(menu_tradewindow); menu_modelview->set_label("modelview"); menu_modelview->set_background(false); @@ -57,12 +66,19 @@ TradeMenu::TradeMenu(ui::Widget *parent, const char * label) : ui::Window(parent menu_traderlistview->set_background(false); menu_traderlistview->set_border(true); + menu_traderlabel = new ui::Label(menu_tradewindow); + menu_traderlabel->set_label("label"); + menu_traderlabel->set_background(false); + menu_traderlabel->set_border(false); + menu_traderlabel->set_font(ui::root()->font_small()); + menu_traderlabel->set_alignment(ui::AlignLeft); + menu_closebutton = new ui::Button(menu_tradewindow, "Return", "view hide"); menu_buyallbutton = new ui::Button(menu_modelview, "<<"); menu_buybutton = new ui::Button(menu_modelview, "<"); - menu_sellallbutton = new ui::Button(menu_modelview, ">"); - menu_sellbutton = new ui::Button(menu_modelview, ">>"); + menu_sellallbutton = new ui::Button(menu_modelview, ">>"); + menu_sellbutton = new ui::Button(menu_modelview, ">"); std::string test("test"); @@ -99,7 +115,8 @@ void TradeMenu::set_item_type(core::InfoType *item_type) void TradeMenu::set_item(ui::ListItem *item) { menu_infotext.clear(); - menu_namelabel->clear(); + menu_namelabel->set_text("Trade"); + menu_traderlabel->clear(); if (!item || !item->info()) { menu_traderlistview->deselect(); @@ -135,6 +152,10 @@ void TradeMenu::set_item(ui::ListItem *item) menu_buybutton->show(); menu_buybutton->set_command("remote buy " + item->info()->type()->label() + " " + item->info()->label() + " 1; "); + std::ostringstream str; + str << "Price: " << item->item()->price(); + menu_traderlabel->set_text(str.str()); + menu_sellallbutton->hide(); menu_sellbutton->hide(); @@ -177,9 +198,12 @@ void TradeMenu::resize() menu_namelabel->set_location(fontmargin, fontmargin); // resize inventory listview - menu_inventorylistview->set_size(ui::UI::elementsize.width(), menu_tradewindow->height() - smallmargin * 2.0f - fontmargin * 3.0f); + menu_inventorylistview->set_size(ui::UI::elementsize.width(), menu_tradewindow->height() - smallmargin * 2.0f - fontmargin * 6.0f); menu_inventorylistview->set_location(fontmargin, fontmargin * 3.0f); + menu_inventorylabel->set_size(menu_inventorylistview->width(), fontmargin); + menu_inventorylabel->set_location(menu_inventorylistview->left(), menu_inventorylistview->bottom() + fontmargin); + // resize modelview menu_modelview->set_size(menu_tradewindow->width() - 2.0f * ui::UI::elementsize.width() - fontmargin * 4.0f, ui::UI::elementsize.width()); menu_modelview->set_location(fontmargin * 2.0f + ui::UI::elementsize.width(), fontmargin * 3.0f); @@ -198,13 +222,16 @@ void TradeMenu::resize() menu_sellbutton->set_location(menu_modelview->width() - 3.0f * fontmargin, menu_modelview->height() - fontmargin); // resize scrollpane - menu_scrollpane->set_size(menu_tradewindow->width() - 2.0f * ui::UI::elementsize.width() - fontmargin * 4.0f, menu_inventorylistview->height() - fontmargin - ui::UI::elementsize.width()); + menu_scrollpane->set_size(menu_tradewindow->width() - 2.0f * ui::UI::elementsize.width() - fontmargin * 4.0f, menu_inventorylistview->height() + 2.0f * fontmargin - ui::UI::elementsize.width()); menu_scrollpane->set_location(fontmargin * 2.0f + ui::UI::elementsize.width(), fontmargin * 4.0f + ui::UI::elementsize.width()); // resize trader listview - menu_traderlistview->set_size(ui::UI::elementsize.width(), menu_tradewindow->height() - smallmargin * 2.0f - fontmargin * 3.0f); + menu_traderlistview->set_size(ui::UI::elementsize.width(), menu_tradewindow->height() - smallmargin * 2.0f - fontmargin * 6.0f); menu_traderlistview->set_location(menu_tradewindow->width() - menu_traderlistview->width() - fontmargin, fontmargin * 3.0f); - + + menu_traderlabel->set_size(menu_traderlistview->width(), fontmargin); + menu_traderlabel->set_location(menu_traderlistview->left(), menu_traderlistview->bottom() + fontmargin); + // resize close button menu_closebutton->set_size(ui::UI::elementsize); menu_closebutton->set_location(0.5f * (menu_tradewindow->width() - ui::UI::elementsize.width()), menu_tradewindow->height() - smallmargin * 1.5f ); @@ -220,4 +247,13 @@ bool TradeMenu::on_emit(Widget *sender, const Event event, void *data) return ui::Window::on_emit(sender, event, data); } +void TradeMenu::draw() +{ + std::stringstream str; + str << "Credits: " << core::localplayer()->credits(); + menu_inventorylabel->set_text(str.str()); + + Window::draw(); +} + } diff --git a/src/client/trademenu.h b/src/client/trademenu.h index 477a372..5f56a08 100644 --- a/src/client/trademenu.h +++ b/src/client/trademenu.h @@ -34,6 +34,8 @@ protected: /// resize event handler virtual void resize(); + virtual void draw(); + /// emit event handler virtual bool on_emit(Widget *sender, const Event event, void *data); @@ -43,6 +45,8 @@ private: ui::Window *menu_tradewindow; ui::Button *menu_closebutton; ui::Label *menu_namelabel; + ui::Label *menu_inventorylabel; + ui::Label *menu_traderlabel; ui::ModelView *menu_modelview; ui::ScrollPane *menu_scrollpane; diff --git a/src/core/inventory.cc b/src/core/inventory.cc index 6afa76f..c659178 100644 --- a/src/core/inventory.cc +++ b/src/core/inventory.cc @@ -29,7 +29,7 @@ void Inventory::set_timestamp(const unsigned long timestamp) inventory_timestamp = timestamp; } -void Inventory::mark() +void Inventory::set_dirty() { inventory_timestamp = core::game()->timestamp(); } diff --git a/src/core/inventory.h b/src/core/inventory.h index c715116..0a412b0 100644 --- a/src/core/inventory.h +++ b/src/core/inventory.h @@ -74,7 +74,7 @@ public: /** * @brief set the timestamp to the current game time */ - void mark(); + void set_dirty(); private: Items inventory_items; diff --git a/src/core/item.cc b/src/core/item.cc index 3528c1a..ca51775 100644 --- a/src/core/item.cc +++ b/src/core/item.cc @@ -16,7 +16,7 @@ Item::Item(const Info *info) { item_info = info; item_amount = 0; - item_price = 0; + item_price = info->price(); } Item::~Item() diff --git a/src/game/base/cargo.cc b/src/game/base/cargo.cc index 420d4d3..689ae92 100644 --- a/src/game/base/cargo.cc +++ b/src/game/base/cargo.cc @@ -103,16 +103,81 @@ Cargo *Cargo::find(const std::string & label) return (Cargo *) core::Info::find(cargo_infotype, label); } +// main 'sell cargo' function +void Cargo::sell(core::EntityControlable *seller, core::Entity *buyer, const int amount) +{ + if (!buyer || !seller) + return; + + // can only sell at planets and stations + if ((buyer->moduletype() != station_enttype) && (buyer->moduletype() != planet_enttype)) { + seller->owner()->send("^BCan not sell here"); + return; + } + + if (!seller->owner()) + return; + + if (!buyer->inventory() || !seller->inventory()) { + seller->owner()->send("^BCan not sell here"); + return; + } + + if (!amount) { + return; + } + + core::Item *seller_item = seller->inventory()->find(this); + if (!seller_item) { + if (seller->owner()) { + seller->owner()->send("^BYou do not own any " + name()); + } + return; + } + + int negotiated_amount = amount; + if (negotiated_amount < 0) { + negotiated_amount = seller_item->amount(); + } else if (negotiated_amount > seller_item->amount()) { + negotiated_amount = seller_item->amount(); + } + + int negotiated_price = price(); // base price + core::Item *buyer_item = buyer->inventory()->find(this); + if (buyer_item) { + negotiated_price = buyer_item->price(); + } + + + seller_item->set_amount(seller_item->amount() - negotiated_amount); + seller->owner()->set_credits(seller->owner()->credits() + negotiated_price * negotiated_amount); + seller->inventory()->set_dirty(); + + // send a cargo purchased message + std::stringstream msgstr; + msgstr << "^BSold " << negotiated_amount << " " << aux::plural("unit", negotiated_amount) << " of " << name() << " for " << negotiated_price * negotiated_amount << " credits"; + seller->owner()->send(msgstr.str()); + seller->owner()->sound("game/buy"); + +} + // main 'buy cargo' function void Cargo::buy(core::EntityControlable *buyer, core::Entity *seller, const int amount) { if (!buyer || !seller) return; + + // can only buy at planets and stations + if ((seller->moduletype() != station_enttype) && (seller->moduletype() != planet_enttype)) { + buyer->owner()->send("^BCan not buy here"); + return; + } if (!buyer->owner()) return; if (!buyer->inventory() || !seller->inventory()) { + buyer->owner()->send("^BCan not buy here"); return; } @@ -156,6 +221,8 @@ void Cargo::buy(core::EntityControlable *buyer, core::Entity *seller, const int buyer_item->inc_amount(negotiated_amount); buyer->owner()->set_credits(buyer->owner()->credits() - negotiated_price * negotiated_amount); + buyer->inventory()->set_dirty(); + // send a cargo purchased message std::stringstream msgstr; msgstr << "^BPurchased " << negotiated_amount << " " << aux::plural("unit", negotiated_amount) << " of " << name() << " for " << negotiated_price * negotiated_amount << " credits"; diff --git a/src/game/base/cargo.h b/src/game/base/cargo.h index 9b2bca5..1e97d40 100644 --- a/src/game/base/cargo.h +++ b/src/game/base/cargo.h @@ -19,6 +19,8 @@ public: void buy(core::EntityControlable *buyer, core::Entity *seller, const int amount); + void sell(core::EntityControlable *seller, core::Entity *buyer, const int amount); + /* -- static functions -- */ static core::InfoType *cargo_infotype; diff --git a/src/game/base/game.cc b/src/game/base/game.cc index 9f8dabc..83d0be8 100644 --- a/src/game/base/game.cc +++ b/src/game/base/game.cc @@ -267,34 +267,71 @@ void Game::func_give(core::Player *player, const std::string &args) } } +// sell request from a player +void Game::func_sell(core::Player *player, const std::string &args) +{ + std::istringstream is(args); + std::string typestr; + std::string labelstr; + + if (!(is >> typestr)) { + player->send("Usage: sell [string] [string] [int] sell an item: specify type, label and amount"); + return; + } else { + aux::to_label(typestr); + } + + if (!(is >> labelstr)) { + player->send("Usage: sell [string] [string] [int] sell an item: specify type, label and amount"); + return; + } else { + aux::to_label(labelstr); + } + + int amount = 0; + if (!(is >> amount)) + amount = 0; + + if (typestr.compare("cargo") == 0) { + Cargo *cargo = Cargo::find(labelstr); + if (cargo) { + cargo->sell(player->control(), player->view(), amount); + } else { + player->send("Unkown cargo type '" + labelstr + "'"); + } + } else { + player->send("Unkown item type '" + typestr + "'"); + } + return; +} + // buy request from a player void Game::func_buy(core::Player *player, const std::string &args) { std::istringstream is(args); std::string typestr; std::string labelstr; - int amount = 0; if (!(is >> typestr)) { - player->send("Usage: buy [string] [string] buy an item, specify type and label"); + player->send("Usage: buy [string] [string] [int] buy an item: specify type, label and amount"); return; } else { aux::to_label(typestr); } if (!(is >> labelstr)) { - labelstr.clear(); + player->send("Usage: buy [string] [string] [int] buy an item: specify type, label and amount"); + return; } else { aux::to_label(labelstr); } - + + int amount = 0; if (!(is >> amount)) amount = 0; if (typestr.compare("ship") == 0) { - ShipDealer::func_buy(player, labelstr); - - + ShipDealer::func_buy(player, labelstr); } else if (typestr.compare("cargo") == 0) { Cargo *cargo = Cargo::find(labelstr); if (cargo) { @@ -305,7 +342,6 @@ void Game::func_buy(core::Player *player, const std::string &args) } else { player->send("Unkown item type '" + typestr + "'"); } - return; } @@ -495,8 +531,11 @@ Game::Game() : core::Module("Project::OSiRiON", true) func->set_info("leave the game and spectate"); func = core::Func::add("buy", Game::func_buy); - func->set_info("[string] [string] buy type of item, name of item"); + func->set_info("[string] [string] [int] buy an item: specify type, label and amount"); + func = core::Func::add("sell", Game::func_sell); + func->set_info("[string] [string] [int] sell an item: specify type, label and amount"); + func = core::Func::add("give", Game::func_give); func->set_info("cheat functions"); diff --git a/src/game/base/game.h b/src/game/base/game.h index e091630..ce37fa6 100644 --- a/src/game/base/game.h +++ b/src/game/base/game.h @@ -107,6 +107,7 @@ private: static void func_respawn(core::Player *player, std::string const &args); static void func_goto(core::Player *player, const std::string &args); static void func_buy(core::Player *player, std::string const &args); + static void func_sell(core::Player *player, const std::string &args); static void func_give(core::Player *player, const std::string &args); }; diff --git a/src/ui/listitem.cc b/src/ui/listitem.cc index dcd4e2a..601d5a8 100644 --- a/src/ui/listitem.cc +++ b/src/ui/listitem.cc @@ -15,6 +15,7 @@ ListItem::ListItem(ListView *parent, const char * text) : Label(parent, text) { set_label("listitem"); listitem_info = 0; + listitem_item = 0; } ListItem::~ListItem() { diff --git a/src/ui/listitem.h b/src/ui/listitem.h index cc03621..1d4cd33 100644 --- a/src/ui/listitem.h +++ b/src/ui/listitem.h @@ -10,6 +10,7 @@ #include #include "core/info.h" +#include "core/item.h" #include "ui/label.h" namespace ui @@ -30,9 +31,17 @@ public: return listitem_info; } + inline const core::Item *item() const { + return listitem_item; + } + inline void set_info(const core::Info *info) { listitem_info = info; } + + inline void set_item(const core::Item *item) { + listitem_item = item; + } protected: /// keypress event handler @@ -45,6 +54,7 @@ protected: private: const core::Info *listitem_info; + const core::Item *listitem_item; }; } // namespace ui diff --git a/src/ui/listview.cc b/src/ui/listview.cc index 646b168..e503807 100644 --- a/src/ui/listview.cc +++ b/src/ui/listview.cc @@ -73,6 +73,13 @@ void ListView::deselect() listview_selecteditem = 0; } +void ListView::select(ListItem *item) +{ + if (is_child(item)) { + listview_selecteditem = item; + } +} + void ListView::clear() { listview_selecteditem = 0; diff --git a/src/ui/listview.h b/src/ui/listview.h index a650348..a0c185b 100644 --- a/src/ui/listview.h +++ b/src/ui/listview.h @@ -53,6 +53,9 @@ public: /// clear all listitems void clear(); + /// set selection to specified ListItem + void select(ListItem *item); + /// set selection to nothing void deselect(); diff --git a/src/ui/widget.cc b/src/ui/widget.cc index 5fe6f17..79281a1 100644 --- a/src/ui/widget.cc +++ b/src/ui/widget.cc @@ -47,6 +47,15 @@ void Widget::remove_children() widget_children.clear(); } +bool Widget::is_child(const Widget *widget) const +{ + for (Children::const_iterator it = widget_children.begin(); it != widget_children.end(); it++) { + if (widget == (*it)) + return true; + } + return false; +} + size_t Widget::list(const size_t indent, const bool visible_only) const { if (visible_only && !visible()) diff --git a/src/ui/widget.h b/src/ui/widget.h index 880b71c..3ae75d2 100644 --- a/src/ui/widget.h +++ b/src/ui/widget.h @@ -139,6 +139,9 @@ public: /// returns true if the widget has mouse focus bool has_mouse_focus() const; + + /// return true of the widget is a child widget + bool is_child(const Widget *widget) const; /* -- mutators --------------------------------------------- */ -- cgit v1.2.3