From 75274ebd6ba90784f5aa837b7e5ea97fc6bfb720 Mon Sep 17 00:00:00 2001 From: Stijn Buys Date: Sat, 20 Oct 2012 16:35:26 +0000 Subject: Item id based inventory, support for weapon dealers. --- src/client/inventorywindow.cc | 4 +- src/client/trademenu.cc | 4 +- src/core/commandbuffer.cc | 9 +- src/core/entity.cc | 4 +- src/core/gameserver.cc | 4 +- src/core/info.cc | 4 +- src/core/inventory.cc | 48 +++- src/core/inventory.h | 29 +- src/core/item.cc | 22 +- src/core/item.h | 41 ++- src/core/netconnection.cc | 68 ++++- src/core/netserver.cc | 19 +- src/game/base/cargo.cc | 276 +------------------ src/game/base/cargo.h | 6 - src/game/base/game.cc | 627 +++++++++++++++++++++++++++++++++--------- src/game/base/planet.cc | 34 ++- src/game/base/planet.h | 2 + src/game/base/savegame.cc | 15 +- src/game/base/ship.cc | 2 - src/game/base/station.cc | 12 +- src/game/base/weapon.cc | 28 +- src/game/base/weapon.h | 8 +- 22 files changed, 785 insertions(+), 481 deletions(-) (limited to 'src') diff --git a/src/client/inventorywindow.cc b/src/client/inventorywindow.cc index 2b956c4..7912d0d 100644 --- a/src/client/inventorywindow.cc +++ b/src/client/inventorywindow.cc @@ -327,11 +327,9 @@ void InventoryWindow::act_eject() std::ostringstream cmdstr; cmdstr << "remote eject "; - cmdstr << inventorywindow_listview->selected()->item()->info()->type()->label() << " "; - cmdstr << inventorywindow_listview->selected()->item()->info()->label() << " "; + cmdstr << inventorywindow_listview->selected()->item()->id() << " "; cmdstr << inventorywindow_ejectslider->value(); - con_debug "Executing command '" << cmdstr.str() << "'" << std::endl; core::CommandBuffer::exec(cmdstr.str()); show_item_info(0); diff --git a/src/client/trademenu.cc b/src/client/trademenu.cc index 1de42e4..6421d43 100644 --- a/src/client/trademenu.cc +++ b/src/client/trademenu.cc @@ -192,7 +192,7 @@ void TradeMenu::set_item(ui::ListItem *item) amount = (long) menu_slider->value(); std::ostringstream commandstr; - commandstr << "remote sell " << item->info()->type()->label() << " " << item->info()->label() << " " << amount; + commandstr << "remote sell " << item->item()->id() << " " << amount; menu_buybutton->set_command(commandstr.str()); menu_buybutton->enable(); } @@ -237,7 +237,7 @@ void TradeMenu::set_item(ui::ListItem *item) amount = (long) menu_slider->value(); std::ostringstream commandstr; - commandstr << "remote buy " << item->info()->type()->label() << " " << item->info()->label() << " " << amount; + commandstr << "remote buy " << item->item()->id() << " " << amount; menu_buybutton->set_command(commandstr.str()); menu_buybutton->enable(); diff --git a/src/core/commandbuffer.cc b/src/core/commandbuffer.cc index d46cc38..78b76af 100644 --- a/src/core/commandbuffer.cc +++ b/src/core/commandbuffer.cc @@ -49,10 +49,13 @@ void func_list_info(std::string const &args) std::istringstream argstream(args); if (!(argstream >> typestr)) { - // no argument, list all info records - Info::list(); + // no arguments, list info types + InfoType::list(); + con_print << " list_info [type] list all info records for a specified type" << std::endl; return; } + + aux::to_label(typestr); Info *info = 0; InfoType *infotype = InfoType::find(typestr); @@ -87,6 +90,8 @@ void func_list_info(std::string const &args) return; } + aux::to_label(labelstr); + // two arguments info = Info::find(infotype, labelstr); if (info) { diff --git a/src/core/entity.cc b/src/core/entity.cc index 825f9bf..78878f9 100644 --- a/src/core/entity.cc +++ b/src/core/entity.cc @@ -94,11 +94,11 @@ void Entity::list_inventory() const return; } - con_print << " ^Nid type label amount" << std::endl; + con_print << " ^Nitem info infotype amount" << std::endl; for (Inventory::Items::const_iterator it = entity_inventory->items().begin(); it != entity_inventory->items().end(); it++) { Item *item = (*it); con_print << " " - << " ^B" << std::setw(4) << item->info()->id() + << " ^B" << std::setw(4) << item->id() << " ^N" << aux::pad_right((item->info()->type() ? item->info()->type()->label() : "NULL"), 8) << " ^N" << aux::pad_right(item->info()->label(), 24) << std::setw(5) << item->amount() << std::endl; diff --git a/src/core/gameserver.cc b/src/core/gameserver.cc index 579f65d..796b99f 100644 --- a/src/core/gameserver.cc +++ b/src/core/gameserver.cc @@ -717,11 +717,11 @@ void GameServer::frame(const unsigned long timestamp) // send network updates server_network->frame(this->timestamp()); } - + // remove deleted entities and mark remaining entities as updated for (Entity::Registry::iterator it = Entity::registry().begin(); it != Entity::registry().end();) { // remove deleted entities - if ((*it).second->entity_destroyed) { + if ((*it).second->destroyed()) { delete (*it).second; (*it).second = 0; Entity::registry().erase(it++); diff --git a/src/core/info.cc b/src/core/info.cc index 8e286dc..dbe4c76 100644 --- a/src/core/info.cc +++ b/src/core/info.cc @@ -91,9 +91,9 @@ Info::Info(const unsigned int id) info_type = 0; info_registry.push_back(this); - info_price = 0; - info_timestamp = 1; + info_price = 0; + info_volume = 0; add_text("Requesting server information..."); } diff --git a/src/core/inventory.cc b/src/core/inventory.cc index 28327a3..c10e1c6 100644 --- a/src/core/inventory.cc +++ b/src/core/inventory.cc @@ -16,6 +16,7 @@ namespace core Inventory::Inventory(const float capacity) { inventory_timestamp = 0; + inventory_timestamp_erase = 0; inventory_capacity = capacity; inventory_capacity_used = 0; inventory_dirty = false; @@ -25,6 +26,7 @@ Inventory::~Inventory() { clear(); inventory_timestamp = 0; + inventory_timestamp_erase = 0; inventory_capacity = 0; inventory_capacity_used = 0; } @@ -48,24 +50,45 @@ void Inventory::set_dirty(const bool dirty) void Inventory::add(Item *item) { + assert(item != (Item *) 0x81); + + // assign an id + unsigned int id = 0; for (Items::iterator it = inventory_items.begin(); it != inventory_items.end(); it++) { - // check if the item was already added - if ((*it) == item) - return; + if ((*it)->id() > id) { + id = (*it)->id(); + } } + id++; + item->set_id(id); + inventory_items.push_back(item); } -void Inventory::remove(Item *item) +void Inventory::erase(Item *item) { for (Items::iterator it = inventory_items.begin(); it != inventory_items.end(); it++) { if ((*it) == item) { + delete (*it); + (*it) = 0; + inventory_items.erase(it); + inventory_timestamp_erase = (game() ? game()->timestamp() : 1); + return; + } + } +} + +void Inventory::erase(const unsigned int id) +{ + for (Items::iterator it = inventory_items.begin(); it != inventory_items.end(); it++) { + if ((*it)->id() == id) { + delete (*it); + (*it) = 0; inventory_items.erase(it); - delete item; + inventory_timestamp_erase = (game() ? game()->timestamp() : 1); return; } } - // FIXME remove doesn't work over network } Item *Inventory::find(const Info *info) const @@ -81,6 +104,19 @@ Item *Inventory::find(const Info *info) const return 0; } +Item *Inventory::find(const unsigned int id) const +{ + // sarch the inventory for a specified item id + for (Items::const_iterator it = inventory_items.begin(); it != inventory_items.end(); it++) { + Item *item = (*it); + if (item->id() == id) { + return item; + } + } + // not found + return 0; +} + void Inventory::clear() { for (Items::iterator it = inventory_items.begin(); it != inventory_items.end(); it++) { diff --git a/src/core/inventory.h b/src/core/inventory.h index 80dbde1..3c3adfa 100644 --- a/src/core/inventory.h +++ b/src/core/inventory.h @@ -23,7 +23,7 @@ public: /** * @brief type definition for items in the inventory */ - typedef std::vector Items; + typedef std::list Items; /** * @brief default constructor @@ -45,13 +45,20 @@ public: }; /** - * @brief return the timestamp of the last server update - * This is a client-side property and shoul not be used server-side + * @brief return the timestamp of the last client-side update + * This is a client-side property */ inline const unsigned long timestamp() const { return inventory_timestamp; } + /** + * @brief return the timestamp of the last item erase + * */ + inline const unsigned long timestamp_erase() const { + return inventory_timestamp_erase; + } + /** * @brief return the maximal inventory capacity, in cubic meters */ @@ -89,6 +96,11 @@ public: * @brief search the inventory for a specific item type */ Item *find(const Info *info) const; + + /** + * @brief search the inventory for a specific item id + */ + Item *find(const unsigned int id) const; /* ---- mutators --------------------------------------------------- */ @@ -98,9 +110,12 @@ public: void add(Item *item); /** - * @brief remove an item from the inventory and delete it + * @brief erase an item from the inventory + * This will call the Item's destructor */ - void remove(Item *item); + void erase(Item *item); + + void erase(const unsigned int id); /** * @brief removes all items from the inventory and delete them @@ -135,8 +150,10 @@ private: // items in the inventory Items inventory_items; - // timestamp when inventory was last updated + // timestamp, last time the inventory was updated unsigned long inventory_timestamp; + // timestamp, last time there was an item deleted from the inventory + unsigned long inventory_timestamp_erase; // maximum inventory capacity, in cubic meters float inventory_capacity; diff --git a/src/core/item.cc b/src/core/item.cc index f6e0382..b6e5bd8 100644 --- a/src/core/item.cc +++ b/src/core/item.cc @@ -24,27 +24,29 @@ Item::Item(const Info *info) item_info = info; item_amount = 0; item_flags = 0; + item_id = 0; item_price = info->price(); set_timestamp(game() ? game()->timestamp() : 1); } -Item::Item(const Item &other) -{ - item_info = other.info(); - item_amount = other.amount(); - item_flags = other.flags(); - item_price = other.price(); - item_dirty = other.dirty(); - set_timestamp(game() ? game()->timestamp() : 1); -} - Item::~Item() { item_info = 0; item_amount = 0; item_flags = 0; item_price = 0; + item_id = 0; +} + +void Item::set_info(const Info *info) +{ + item_info = info; +} + +void Item::set_id(const unsigned int id) +{ + item_id = id; } void Item::set_amount(const long amount) diff --git a/src/core/item.h b/src/core/item.h index 6c99270..ec0d6be 100644 --- a/src/core/item.h +++ b/src/core/item.h @@ -23,13 +23,15 @@ public: Item(const Info *info); - /// copy constructor - Item(const Item &other); - ~Item(); /* ---- inspectors --------------------------------------------- */ + /** + * @brief returns the item id + * */ + inline unsigned int id() const { return item_id; } + /** * @brief associated amount */ @@ -68,6 +70,13 @@ public: return ((item_flags & (unsigned int) flag) == (unsigned int) flag); } + /** + * @brief returns true if the Unique flag is set + */ + inline const bool unique() const { + return ((item_flags & (unsigned int) Unique) == (unsigned int) Unique); + } + /** * @brief return true if the dirty flag is set * */ @@ -76,6 +85,21 @@ public: } /* ---- mutators ----------------------------------------------- */ + + /** + * @brief set item id + * This should never be called from within the game module, + * it is used by Inventory to keep track of unique items + */ + void set_id(const unsigned int id); + + /** + * @brief set item info + * This should never be called from within the game module, + * it essentially changes the item type and is used by NetConnection + * for inventory householding. + */ + void set_info(const Info *info); /** * @brief set associated amount @@ -97,6 +121,13 @@ public: */ void set_price(const long price); + /** + * @brief set all item flags + */ + inline void set_flags(const unsigned int flags) { + item_flags = flags; + } + /** * @brief set item flag */ @@ -115,7 +146,7 @@ public: * @brief set the dirty flag * */ inline void set_dirty(const bool dirty = true) { - item_dirty = true; + item_dirty = dirty; } /* ---- serializers -------------------------------------------- */ @@ -136,6 +167,8 @@ private: unsigned int item_flags; bool item_dirty; + + unsigned int item_id; }; } // namespace core diff --git a/src/core/netconnection.cc b/src/core/netconnection.cc index 3c68be9..24f6a3d 100644 --- a/src/core/netconnection.cc +++ b/src/core/netconnection.cc @@ -754,7 +754,7 @@ void NetConnection::parse_incoming_message(const std::string & message) oldzone->content().clear(); } - // short "pif" message about a different player + // short "pif" message about a different player } else if (player_id != localplayer()->id()) { // find player @@ -895,49 +895,91 @@ void NetConnection::parse_incoming_message(const std::string & message) } else if (command.compare("inv") == 0) { // received inventory update - unsigned int id = 0; + unsigned int entity_id = 0; unsigned long server_timestamp; - // read id - if (!(msgstream >> id >> server_timestamp)) { + // read entity id and server timestamp + if (!(msgstream >> entity_id >> server_timestamp)) { con_warn << "Received invalid inventory update message!" << std::endl; return; } - Entity *entity = Entity::find(id); + Entity *entity = Entity::find(entity_id); if (!entity) { - con_warn << "Received inventory update for non-existing entity " << id << "!" << std::endl; + con_warn << "Received inventory update for non-existing entity " << entity_id << "!" << std::endl; return; } if (!entity->inventory()) { - con_warn << "Received inventory update for entity " << id << " without inventory!" << std::endl; + con_warn << "Received inventory update for entity " << entity_id << " without inventory!" << std::endl; return; } - //con_debug << "CLIENT received inv message for entity " << id << " client timestamp " << entity->inventory()->timestamp() << " server timestamp " << server_timestamp << std::endl; - if (server_timestamp < entity->inventory()->timestamp()) return; + unsigned int item_id = 0; + unsigned int info_id = 0; + + int full_update = 0; + if (!(msgstream >> full_update)) { + con_warn << "Received inventory update for entity " << entity_id << " without full update marker!" << std::endl; + return; + } + + if (full_update == 1) { + // mark all items dirty + for (Inventory::Items::iterator it = entity->inventory()->items().begin(); it != entity->inventory()->items().end(); ++it) { + (*it)->set_dirty(); + } + } + size_t nbitems = 0; if (!(msgstream >> nbitems)) nbitems = 0; //con_debug << "CLIENT number of items: " << nbitems << std::endl; + // receive item updates for (size_t i = 0; i < nbitems; i++) { - if (!(msgstream >> id)) { - con_warn << "Received inventory update without info id for existing entity " << id << "!" << std::endl; + // read item id + if (!(msgstream >> item_id)) { + con_warn << "Received inventory item update for entity " << entity_id << " without item id!" << std::endl; + return; + } + // read info id + if (!(msgstream >> info_id)) { + con_warn << "Received inventory item update for entity " << entity_id << " without info id!" << std::endl; return; } - Info *info = core::game()->request_info(id); - Item *item = entity->inventory()->find(info); + Info *info = core::game()->request_info(info_id); + Item *item = entity->inventory()->find(item_id); if (!item) { item = new Item(info); entity->inventory()->add(item); + item->set_id(item_id); + } else { + if (item->info() != info) { + item->set_info(info); + } } item->receive_server_update(msgstream); + item->set_dirty(false); } + + if (full_update == 1) { + // remove items for which no update was received + for (Inventory::Items::iterator it = entity->inventory()->items().begin(); it != entity->inventory()->items().end();) { + Item *item = (*it); + if (item->dirty()) { + delete (item); + (*it) = 0; + entity->inventory()->items().erase(it++); + } else { + ++it; + } + } + } + entity->inventory()->recalculate(); entity->inventory()->set_timestamp(server_timestamp); diff --git a/src/core/netserver.cc b/src/core/netserver.cc index 81bd303..9fb5f78 100644 --- a/src/core/netserver.cc +++ b/src/core/netserver.cc @@ -667,16 +667,27 @@ void NetServer::send_inventory_update(NetClient *client, Entity *entity, const u if (!entity || !entity->inventory()) return; + // send message header std::ostringstream msg; msg << "inv " << entity->id() << " " << game()->timestamp() << " "; - size_t nbitems = 0; + // send full update marker + bool send_full_update = false; + if (entity->inventory()->timestamp_erase() >= timestamp) { + send_full_update = true; + msg << "1 "; + } else { + send_full_update = false; + msg << "0 "; + } + // send items + size_t nbitems = 0; std::ostringstream itemstr; for (Inventory::Items::const_iterator it = entity->inventory()->items().begin(); it != entity->inventory()->items().end(); it++) { const Item *item = (*it); - if (item->timestamp() >= timestamp) { - itemstr << item->info()->id() << " "; + if (send_full_update || (item->timestamp() >= timestamp)) { + itemstr << item->id() << " " << item->info()->id() << " "; item->serialize_server_update(itemstr); nbitems++; } @@ -733,7 +744,7 @@ void NetServer::parse_incoming_message(NetClient *client, const std::string & me unsigned int protover; if (msgstream >> protover) { if (protover != PROTOCOLVERSION) { - // set protocol version mismatch notification + // send protocol version mismatch notification std::stringstream netmsgstream(""); netmsgstream << "^WProtocol version mismatch: "; netmsgstream << "client " << protover << " server " << PROTOCOLVERSION << "!\n"; diff --git a/src/game/base/cargo.cc b/src/game/base/cargo.cc index 706bf84..5a67ebf 100644 --- a/src/game/base/cargo.cc +++ b/src/game/base/cargo.cc @@ -13,7 +13,6 @@ #include "core/func.h" #include "base/game.h" #include "base/cargo.h" -#include "base/cargopod.h" namespace game { @@ -109,6 +108,11 @@ void Cargo::done() core::Func::remove("list_cargo"); } +void Cargo::list() +{ + core::Info::list(cargo_infotype); +} + /* ---- class Cargo -------------------------------------------- */ Cargo::Cargo() : core::Info(cargo_infotype) @@ -129,275 +133,5 @@ 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("^WCan not sell here"); - return; - } - - if (!seller->owner()) - return; - - if (!buyer->inventory() || !seller->inventory()) { - seller->owner()->send("^WCan not sell here"); - return; - } - - if (!amount) { - return; - } - - // seller is the player - core::Item *seller_item = seller->inventory()->find(this); - if (!seller_item) { - if (seller->owner()) { - seller->owner()->send("^WYou do not own any " + name()); - } - return; - } - - // buyer is the station or planer - core::Item *buyer_item = buyer->inventory()->find(this); - if (!buyer_item) { - seller->owner()->send("^W" + buyer->name() + " ^Bdoes not buy " + 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 = buyer_item->price(); - - seller_item->dec_amount(negotiated_amount); - seller->owner()->set_credits(seller->owner()->credits() + negotiated_price * negotiated_amount); - seller->owner()->set_dirty(); - seller->inventory()->set_dirty(); - - if (buyer_item->amount() >= 0) { - buyer_item->inc_amount(negotiated_amount); - buyer->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("^WCan not buy here"); - return; - } - - if (!buyer->owner()) - return; - - if (!buyer->inventory() || !seller->inventory()) { - buyer->owner()->send("^WCan not buy here"); - return; - } - - if (!amount) { - return; - } - - // seller is the station or planet - core::Item *seller_item = seller->inventory()->find(this); - if (!seller_item) { - if (buyer->owner()) { - buyer->owner()->send("^W" + seller->name() + " ^Bdoes not sell " + name()); - } - return; - } else { - assert(seller_item->info() == this); - } - - int negotiated_amount = amount; - int negotiated_price = seller_item->price(); - long cash = buyer->owner()->credits(); - - // check if the player has enough cash - if (negotiated_price > 0) { - - // negative amount means 'as much as possible' - if (negotiated_amount < 0) { - negotiated_amount = cash / negotiated_price; - } - - // maximum amount the player can afford - if (cash < negotiated_amount * negotiated_price) { - negotiated_amount = cash / negotiated_price; - } - - if (negotiated_amount < 1) { - buyer->owner()->send("^WCan not afford transaction!"); - return; - } - } - - // check cargo size - ignore zero volume cargo - if (volume() > 0 ) { - - // maximum cargo size - if (negotiated_amount * volume() > buyer->inventory()->capacity_available()) { - negotiated_amount = (int)floorf(buyer->inventory()->capacity_available() / volume()); - } - - if (negotiated_amount < 1) { - buyer->owner()->send("^WNot enough cargo space available!"); - return; - } - } - - if (negotiated_amount <= 0) { - // unlimited amount of zero-cost cargo - buyer->owner()->send("^WNo unlimited amounts of zero-cost cargo available!"); - return; - } - - // if amount is set to -1. the base has a limitless supply - - if (seller_item->amount() == 0) { - buyer->owner()->send("^WCargo not available!"); - return; - - } else if (seller_item->amount() > 0) { - - if (negotiated_amount > seller_item->amount()) { - negotiated_amount = seller_item->amount(); - } - - seller_item->dec_amount(negotiated_amount); - seller->inventory()->set_dirty(); - } - - // buyer is the player - core::Item *buyer_item = buyer->inventory()->find(this); - if (!buyer_item) { - buyer_item = new core::Item(this); - buyer->inventory()->add(buyer_item); - } else { - assert(buyer_item->info() == this); - } - buyer_item->inc_amount(negotiated_amount); - buyer->owner()->set_credits(buyer->owner()->credits() - negotiated_price * negotiated_amount); - buyer->owner()->set_dirty(); - 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"; - buyer->owner()->send(msgstr.str()); - buyer->owner()->sound("game/buy"); -} - -// main 'eject cargo' function -void Cargo::eject(core::EntityControlable *ejector, const int amount) -{ - if (!ejector->inventory()) { - return; - } - - if (!amount) { - return; - } - - if ((ejector->state() == core::Entity::Jump) || (ejector->state() == core::Entity::JumpInitiate)) { - if (ejector->owner()) { - ejector->owner()->send("^WCan not eject while hyperspace jump drive is active"); - } - return; - } - - // find the cargo in the inventory - core::Item *item = ejector->inventory()->find(this); - if (!item || !item->amount()) { - if (ejector->owner()) { - ejector->owner()->send("^WYou do not own any " + name()); - } - return; - } else { - assert(item->info() == this); - } - - int negotiated_amount = amount; - if (negotiated_amount < 0) { - negotiated_amount = item->amount(); - } else if (negotiated_amount > item->amount()) { - if (ejector->owner()) { - std::stringstream msgstr; - msgstr << "^WYou only own " << item->amount() << " " << aux::plural("unit", negotiated_amount) << " of " << name(); - ejector->owner()->send(msgstr.str()); - } - return; - } - - item->dec_amount(negotiated_amount); - ejector->inventory()->set_dirty(); - - if (ejector->state() == core::Entity::Docked) { - std::stringstream msgstr; - if (ejector->owner()) { - msgstr << "^BDestroyed " << negotiated_amount << " " << aux::plural("unit", negotiated_amount) << " of " << name(); - ejector->owner()->send(msgstr.str()); - ejector->owner()->sound("fx/eject"); - } - return; - } - - // create cargo pod - CargoPod *pod = new CargoPod(); - - pod->set_color(ejector->color()); - pod->set_color_second(ejector->color_second()); - pod->set_location(ejector->location() + ejector->axis().up() * (ejector->radius() + pod->radius())); - pod->set_axis(ejector->axis()); - pod->set_zone(ejector->zone()); - pod->set_info(item->info()); - - // add loot to inventory - pod->add_inventory(); - pod->inventory()->set_capacity(item->info()->volume() * negotiated_amount); - - core::Item *loot = new core::Item(item->info()); - loot->set_amount(negotiated_amount); - - pod->inventory()->add(loot); - pod->inventory()->set_dirty(); - - if (ejector->owner()) { - std::stringstream msgstr; - msgstr << "^BEjected " << negotiated_amount << " " << aux::plural("unit", negotiated_amount) << " of " << name(); - ejector->owner()->send(msgstr.str()); - ejector->owner()->sound("fx/eject"); - } - - pod->reset(); -} - -void Cargo::list() -{ - core::Info::list(cargo_infotype); -} - } // namespace game diff --git a/src/game/base/cargo.h b/src/game/base/cargo.h index 4d90611..0672cec 100644 --- a/src/game/base/cargo.h +++ b/src/game/base/cargo.h @@ -16,12 +16,6 @@ class Cargo : public core::Info { public: Cargo(); ~Cargo(); - - void buy(core::EntityControlable *buyer, core::Entity *seller, const int amount); - - void sell(core::EntityControlable *seller, core::Entity *buyer, const int amount); - - void eject(core::EntityControlable *ejector, const int amount); /* --- static registry functions ---------------------------------- */ diff --git a/src/game/base/game.cc b/src/game/base/game.cc index 738edca..182c856 100644 --- a/src/game/base/game.cc +++ b/src/game/base/game.cc @@ -18,6 +18,7 @@ #include "filesystem/inifile.h" #include "base/game.h" #include "base/cargo.h" +#include "base/cargopod.h" #include "base/faction.h" #include "base/navpoint.h" #include "base/jumppoint.h" @@ -286,6 +287,11 @@ void Game::func_give(core::Player *player, const std::string &args) return; } + if (!player->control()) { + player->send("^WYou need to join the game first!"); + return; + } + std::istringstream is(args); std::string str; @@ -295,15 +301,11 @@ void Game::func_give(core::Player *player, const std::string &args) if (str.compare("ship") == 0) { std::string labelstr; - if (!player->control()) { - player->send("^WYou need to join the game first!"); - return; - } - ShipModel *shipmodel = 0; if (!(is >> labelstr)) { player->send("Usage: give ship [string]"); } else { + aux::to_label(labelstr); shipmodel = ShipModel::find(labelstr); } @@ -319,7 +321,7 @@ void Game::func_give(core::Player *player, const std::string &args) sys::ConsoleInterface::instance()->rconbuf().pop_front(); } - player->send("Unkown ship type '" + labelstr + "'"); + player->send("Unknown ship type '" + labelstr + "'"); return; } @@ -353,6 +355,12 @@ void Game::func_give(core::Player *player, const std::string &args) ship->set_thrust(player->control()->thrust()); ship->set_state(player->control()->state()); + + // remove the old ship from the physics simulation + oldship->die(); + oldship->reset(); + + // add the new ship to the physics simulation ship->reset(); //target_thrust is protected //ship->target_thrust = player->control()->target_thrust()); @@ -382,15 +390,11 @@ void Game::func_give(core::Player *player, const std::string &args) } else if (str.compare("cargo") == 0) { std::string labelstr; - if (!player->control()) { - player->send("^WYou need to join the game first!"); - return; - } - Cargo *cargo = 0; if (!(is >> labelstr)) { player->send("Usage: give cargo [string] [int]"); - } else { + } else { + aux::to_label(labelstr); cargo = Cargo::find(labelstr); } @@ -406,22 +410,31 @@ void Game::func_give(core::Player *player, const std::string &args) sys::ConsoleInterface::instance()->rconbuf().pop_front(); } - player->send("Unkown cargo type '" + labelstr + "'"); + player->send("Unknown cargo type '" + labelstr + "'"); return; } else { int amount = 0; if (!(is >> amount)) { - amount = -1; + amount = 1; } else { if (!amount) return; } + + int max = 0; + if (cargo->volume()) { + max = (int)floorf(player->control()->inventory()->capacity_available() / cargo->volume()); + } else { + max = amount; + if (max < 1) { + max = 1; + } + } - const int max = (int)floorf(player->control()->inventory()->capacity_available() / cargo->volume()); - if (amount < 0 ) { + if (amount < 0) { amount = max; } - + if ((amount == 0) || (amount > max)) { player->send("^WNot enough cargo space available!"); return; @@ -435,21 +448,19 @@ void Game::func_give(core::Player *player, const std::string &args) assert(item->info() == cargo); } item->inc_amount(amount); + player->control()->inventory()->set_dirty(); - player->sound("game/buy"); + player->control()->owner()->sound("game/buy"); } + } else if (str.compare("weapon") == 0) { std::string labelstr; - - if (!player->control()) { - player->send("^WYou need to join the game first!"); - return; - } - + Weapon *weapon = 0; if (!(is >> labelstr)) { player->send("Usage: give weapon [string] [int]"); - } else { + } else { + aux::to_label(labelstr); weapon = Weapon::find(labelstr); } @@ -465,29 +476,59 @@ void Game::func_give(core::Player *player, const std::string &args) sys::ConsoleInterface::instance()->rconbuf().pop_front(); } - player->send("Unkown weapon type '" + labelstr + "'"); + player->send("Unknown weapon type '" + labelstr + "'"); return; - } else { - core::Item *item = 0; - int amount = 1; - - if (player->control()->inventory()->capacity_available() < weapon->volume()) { + } else { + int amount = 0; + if (!(is >> amount)) { + amount = 1; + } else { + if (!amount) + return; + } + + int max = 0; + if (weapon->volume()) { + max = (int)floorf(player->control()->inventory()->capacity_available() / weapon->volume()); + } else { + max = amount; + if (max < 1) { + max = 1; + } + } + if (amount < 0) { + if (weapon->stackable()) { + amount = max; + } else { + amount = 1; + } + } + + if ((amount == 0) || (amount > max)) { player->send("^WNot enough cargo space available!"); return; } + core::Item *item = 0; + if (weapon->stackable()) { item = player->control()->inventory()->find(weapon); - } - - if (!item) { - item = new core::Item(weapon); - player->control()->inventory()->add(item); + if (!item) { + item = new core::Item(weapon); + player->control()->inventory()->add(item); + } else { + assert(item->info() == weapon); + } + item->inc_amount(amount); } else { - assert(item->info() == weapon); - } + for (int n = 0; n < amount; n++) { + item = new core::Item(weapon); + item->set_flag(core::Item::Unique); + item->set_amount(1); + player->control()->inventory()->add(item); + } + } - item->inc_amount(amount); player->control()->inventory()->set_dirty(); player->sound("game/buy"); } @@ -496,7 +537,7 @@ void Game::func_give(core::Player *player, const std::string &args) player->send("Usage: give cargo [string] [int]"); player->send(" give credits [int]"); player->send(" give ship [string]"); - player->send(" give weapon [string]"); + player->send(" give weapon [string] [int]"); return; } } @@ -615,100 +656,302 @@ void Game::func_specs(core::Player *player, const std::string &args) } -// sell request from a player +// sell items on a base void Game::func_sell(core::Player *player, const std::string &args) { + // must be joined to buy items if (!player->control()) { player->send("^WYou need to join the game first!"); return; } - 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"); + Ship *seller = static_cast(player->control()); + + // must be docked to buy items + if ((seller->state() != core::Entity::Docked) || (!seller->dock())) { + player->send("^WYou need to be docked!"); return; - } else { - aux::to_label(typestr); } - - if (!(is >> labelstr)) { - player->send("Usage: sell [string] [string] [int] sell an item: specify type, label and amount"); + + core::Entity *buyer = seller->dock(); + + // can only buy at planets and stations + if ((buyer->moduletype() != station_enttype) && (buyer->moduletype() != planet_enttype)) { + player->send("^WCan not sell here"); + return; + } + + if (!seller->inventory() || !buyer->inventory()) { + player->send("^WCan not sell here"); return; - } else { - aux::to_label(labelstr); } + core::Item *seller_item = 0; + core::Item *buyer_item = 0; + unsigned int id = 0; 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); + + std::istringstream is(args); + if (is >> id >> amount) { + + seller_item = seller->inventory()->find(id); + if (!seller_item) { + std::stringstream msgstr; + msgstr << "^WItem " << id << " not in inventory"; + player->send(msgstr.str()); + return; + } + + if (amount == 0) { + player->send("^WNo amount specified"); + return; + } + + if (seller_item->info()->type() == Cargo::infotype()) { + // cargo has to be in demand + buyer_item = buyer->inventory()->find(seller_item->info()); + if (!buyer_item) { + player->send("^W" + buyer->name() + " ^Bdoes not buy " + seller_item->info()->name()); + return; + } + } else if (seller_item->info()->type() == Weapon::infotype()) { + // weapons can be sold anywhere + if (!seller_item->unique()) { + buyer_item = buyer->inventory()->find(seller_item->info()); + } + if (!buyer_item) { + buyer_item = new core::Item(seller_item->info()); + buyer_item->set_flags(seller_item->flags()); + buyer->inventory()->add(buyer_item); + } } else { - player->send("Unkown cargo type '" + labelstr + "'"); + player->send("^W" + buyer->name() + " ^Bdoes not buy " + seller_item->info()->name()); + return; + } + + if (amount < 0) { + amount = seller_item->amount(); + } else if (amount > seller_item->amount()) { + amount = seller_item->amount(); + } + + int price = buyer_item->price(); + + seller_item->dec_amount(amount); + seller->owner()->set_credits(seller->owner()->credits() + price * amount); + seller->owner()->set_dirty(); + seller->inventory()->set_dirty(); + + if (buyer_item->amount() >= 0) { + buyer_item->inc_amount(amount); + buyer->inventory()->set_dirty(); + } + + if (seller_item->amount() == 0) { + seller->inventory()->erase(seller_item->id()); + seller->inventory()->set_dirty(); + seller_item = 0; } + + // send a cargo sold message + std::stringstream msgstr; + if (buyer_item->unique()) { + msgstr << "^BSold " << buyer_item->info()->name(); + } else { + msgstr << "^BSold " << amount << " " << aux::plural("unit", amount) << " of " << buyer_item->info()->name() << " for " << price * amount << " credits"; + } + player->send(msgstr.str()); + player->sound("game/buy"); } else { - player->send("Unkown item type '" + typestr + "'"); + player->send("Usage: sell [id] [amount] sell item from inventory"); } - return; } -// buy request from a player +// buy items on a base void Game::func_buy(core::Player *player, const std::string &args) { + // must be joined to buy items if (!player->control()) { player->send("^WYou need to join the game first!"); return; } - std::istringstream is(args); - std::string typestr; - std::string labelstr; - - if (!(is >> typestr)) { - player->send("Usage: buy [string] [string] [int] buy an item: specify type, label and amount"); + Ship *ship = static_cast(player->control()); + + // must be docked to buy items + if ((ship->state() != core::Entity::Docked) || (!ship->dock())) { + player->send("^WYou need to be docked!"); return; - } else { - aux::to_label(typestr); } - - if (!(is >> labelstr)) { - player->send("Usage: buy [string] [string] [int] buy an item: specify type, label and amount"); + + core::Entity *seller = ship->dock(); + + // can only buy at planets and stations + if ((seller->moduletype() != station_enttype) && (seller->moduletype() != planet_enttype)) { + player->send("^WCan not buy here"); + return; + } + + if (!ship->inventory() || !seller->inventory()) { + player->send("^WCan not buy here"); return; - } else { - aux::to_label(labelstr); } + core::Item *item = 0; + unsigned int id = 0; int amount = 0; - if (!(is >> amount)) - amount = 0; + + std::istringstream is_int(args); + if (is_int >> id >> amount) { + + // item id based buy + item = seller->inventory()->find(id); + if (!item) { + std::stringstream msgstr; + msgstr << "^WItem " << id << " not in seller inventory"; + player->send(msgstr.str()); + return; + } + + if (item->info()->type() == ShipModel::infotype()) { + ShipModel *shipmodel = ShipModel::find(item->info()->label()); + if (shipmodel) { + shipmodel->buy(player->control(), player->view()); + } + return; + + } else if ((item->info()->type() == Cargo::infotype()) || (item->info()->type() == Weapon::infotype())) { + + int price = item->price(); + long cash = player->credits(); + + if (item->unique()) { + amount = 1; + } + + // check if the player has enough cash + if (price > 0) { + + // negative amount means 'as much as possible' + if (amount < 0) { + amount = cash / price; + } + + // maximum amount the player can afford + if (cash < (amount * price)) { + amount = cash / price; + } + + if (amount < 1) { + player->send("^WCan not afford transaction!"); + return; + } + } + + // check cargo size - ignore zero volume cargo + if (item->info()->volume() > 0 ) { + + // maximum cargo size + if (amount * item->info()->volume() > ship->inventory()->capacity_available()) { + amount = (int)floorf(ship->inventory()->capacity_available() / item->info()->volume()); + } + + if (amount < 1) { + player->send("^WNot enough cargo space available!"); + return; + } + } + + if (amount <= 0) { + // unlimited amount of zero-cost cargo + player->send("^WUnlimited amounts of free items are not supported!"); + return; + } + + // if amount is set to -1. the base has an unlimited supply + if (item->amount() == 0) { + player->send("^W" + item->info()->name() + " not available!"); + return; + + } else if (item->amount() > 0) { + + if (amount > item->amount()) { + amount = item->amount(); + } + } + + // buyer is the player + core::Item *buyer_item = 0; + if (!item->unique()) { + buyer_item = ship->inventory()->find(item->info()); + } + if (!buyer_item) { + buyer_item = new core::Item(item->info()); + buyer_item->set_flags(item->flags()); + ship->inventory()->add(buyer_item); + } + + // update buyer inventory + buyer_item->inc_amount(amount); + ship->inventory()->set_dirty(); + player->set_credits(player->credits() - price * amount); + player->set_dirty(); + + // update seller inventory + if (item->amount() >= 0) { + item->dec_amount(amount); + seller->inventory()->set_dirty(); + } + + if (item->info()->type() == Weapon::infotype()) { + if (item->amount() == 0) { + seller->inventory()->erase(item->id()); + seller->inventory()->set_dirty(); + } + } + + // send a message to the player + std::stringstream msgstr; + if (buyer_item->unique()) { + msgstr << "^BPurchased a " << buyer_item->info()->name(); + } else { + msgstr << "^BPurchased " << amount << " " << aux::plural("unit", amount) << " of " << buyer_item->info()->name() << " for " << price * amount << " credits"; + } + player->send(msgstr.str()); + player->sound("game/buy"); + } else { + player->send("^WCan not buy " + item->info()->name()); + } + + } else { + + std::istringstream is(args); + std::string typestr; + std::string labelstr; - if (typestr.compare("ship") == 0) { - ShipModel *shipmodel = ShipModel::find(labelstr); - if (shipmodel) { - shipmodel->buy(player->control(), player->view()); + if (!(is >> typestr >> labelstr)) { + player->send("Usage: buy ship [ship label] buy a ship from a base"); + player->send("Usage: buy [id] [amount] buy from base inventory"); + return; } else { - player->send("Unkown ship type '" + labelstr + "'"); + aux::to_label(typestr); + aux::to_label(labelstr); } - } else if (typestr.compare("cargo") == 0) { - Cargo *cargo = Cargo::find(labelstr); - if (cargo) { - cargo->buy(player->control(), player->view(), amount); + + if (typestr.compare("ship") == 0) { + ShipModel *shipmodel = ShipModel::find(labelstr); + if (shipmodel) { + shipmodel->buy(player->control(), player->view()); + } else { + player->send("Unknown ship type '" + labelstr + "'"); + } } else { - player->send("Unkown cargo type '" + labelstr + "'"); + player->send("Unknown item type '" + typestr + "'"); } - } else { - player->send("Unkown item type '" + typestr + "'"); } - return; } -// eject cargo request +// eject item request void Game::func_eject(core::Player *player, const std::string &args) { if (!player->control()) { @@ -717,44 +960,103 @@ void Game::func_eject(core::Player *player, const std::string &args) } std::istringstream is(args); - std::string typestr; - std::string labelstr; - - if (!(is >> typestr)) { - player->send("Usage: eject [string] [string] [int] eject an item: specify type, label and amount"); + unsigned int id; + + if (!(is >> id)) { + player->send("Usage: eject [id] [int] eject inventory item, amount"); return; - } else { - aux::to_label(typestr); } - - if (g_devel->value()) { - if (typestr.compare("mine") == 0) { - SpaceMine::eject(player->control()); - return; + + int amount = 0; + if (!(is >> amount)) + amount = -1; + + if (!amount) { + return; + } + + core::EntityControlable *ejector = player->control(); + + // cannot eject while jumping + if ((ejector->state() == core::Entity::Jump) || (ejector->state() == core::Entity::JumpInitiate)) { + if (ejector->owner()) { + ejector->owner()->send("^WCan not eject while hyperspace jump drive is active"); } + return; } - - if (!(is >> labelstr)) { - player->send("Usage: eject [string] [string] [int] eject an item: specify type, label and amount"); + + // find the item in the inventory + core::Item *item = ejector->inventory()->find(id); + if (!item) { + if (ejector->owner()) { + std::stringstream msgstr; + msgstr << "^WItem " << id << " not in inventory"; + ejector->owner()->send(msgstr.str()); + } return; - } else { - aux::to_label(labelstr); + } + if (!item->amount()) { + if (ejector->owner()) { + ejector->owner()->send("^WYou do not own any " + item->info()->name()); + } + return; + } + + if ((amount < 0) || (amount > item->amount())) { + amount = item->amount(); } - - int amount = 0; - if (!(is >> amount)) - amount = 0; + item->dec_amount(amount); - if (typestr.compare("cargo") == 0) { - Cargo *cargo = Cargo::find(labelstr); - if (cargo) { - cargo->eject(player->control(), amount); - } else { - player->send("Unkown cargo type '" + labelstr + "'"); + if (ejector->state() == core::Entity::Docked) { + if (ejector->owner()) { + std::stringstream msgstr; + msgstr << "^BDestroyed " << amount << " " << aux::plural("unit", amount) << " of " << item->info()->name(); + ejector->owner()->send(msgstr.str()); + ejector->owner()->sound("fx/eject"); } - } else { - player->send("Unkown item type '" + typestr + "'"); + } else { + // create cargo pod + CargoPod *pod = new CargoPod(); + + if (item->unique() && item->info()->modelname().size()) { + pod->set_modelname(item->info()->modelname()); + } + pod->set_color(ejector->color()); + pod->set_color_second(ejector->color_second()); + pod->set_location(ejector->location() + ejector->axis().up() * (ejector->radius() + pod->radius())); + pod->set_axis(ejector->axis()); + pod->set_zone(ejector->zone()); + pod->set_info(item->info()); + + // add loot to inventory + pod->add_inventory(); + pod->inventory()->set_capacity(item->info()->volume() * amount); + + core::Item *loot = new core::Item(item->info()); + loot->set_amount(amount); + loot->set_flags(item->flags()); + + pod->inventory()->add(loot); + pod->inventory()->set_dirty(); + + if (ejector->owner()) { + std::stringstream msgstr; + if (item->unique()) { + msgstr << "^BEjected " << item->info()->name(); + } else { + msgstr << "^BEjected " << amount << " " << aux::plural("unit", amount) << " of " << item->info()->name(); + } + ejector->owner()->send(msgstr.str()); + ejector->owner()->sound("fx/eject"); + } + + pod->reset(); + } + + if (item->amount() == 0) { + ejector->inventory()->erase(item->id()); } + ejector->inventory()->set_dirty(); } // beam in nearby cargo pods @@ -792,12 +1094,14 @@ void Game::func_beam(core::Player *player, const std::string &args) } if (negotiated_amount > 0) { - core::Item *iteminv = inventory->find(item->info()); + core::Item *iteminv = 0; + if (!item->has_flag(core::Item::Unique)) { + iteminv = inventory->find(item->info()); + } if (!iteminv) { iteminv = new core::Item(item->info()); inventory->add(iteminv); } - item->dec_amount(negotiated_amount); iteminv->inc_amount(negotiated_amount); @@ -1101,7 +1405,7 @@ Game::~Game() Cargo::done(); // clear Weapon - Weapon::clear(); + Weapon::done(); // clear ShipModel ShipModel::done(); @@ -1189,6 +1493,7 @@ bool Game::load_zone(core::Zone *zone) // set zone defaults zone->set_color(0.5f); zone->set_ambient_color(0.1f); + zone->set_sky("default"); std::string inifilename("ini/zones/"); inifilename.append(zone->label()); @@ -1326,6 +1631,22 @@ bool Game::load_zone(core::Zone *zone) } } + } else if (zoneini.got_section("weapon")) { + // new weapon trading definition for the current base + item = 0; + inventory = 0; + + if (!entity) { + zoneini.unknown_error("weapon definition without entity"); + } else if ((entity->moduletype() != planet_enttype) && (entity->moduletype() != station_enttype)) { + zoneini.unknown_error("weapon definition for invalid entity type"); + } else { + inventory = entity->inventory(); + if (!inventory) { + inventory = entity->add_inventory(); + } + } + } else { zoneini.unknown_section(); } @@ -1544,7 +1865,7 @@ bool Game::load_zone(core::Zone *zone) } } else if (zoneini.in_section("cargo")) { - // cargo definition for a station or planet + // cargo trade definition for a station or planet if (!entity || !inventory) { continue; } @@ -1574,9 +1895,44 @@ bool Game::load_zone(core::Zone *zone) } else { zoneini.unknown_key(); } + + } else if (zoneini.in_section("weapon")) { + // weapon trade definition for a station or planet + if (!entity || !inventory) { + continue; + } + + if (zoneini.got_key_label("label", strval)) { + Weapon *weapon = Weapon::find(strval); + if (weapon) { + item = inventory->find(weapon); + if (!item) { + item = new core::Item(weapon); + item->set_amount(-1); + item->set_price(weapon->price()); + if (!weapon->stackable()) { + item->set_flag(core::Item::Unique); + } + inventory->add(item); + } + } else { + zoneini.unknown_error("unknown weapon type '" + strval + "'"); + } + + } else if (zoneini.got_key_long("price", l)) { + if (item) { + item->set_price(l); + } + } else if (zoneini.got_key_long("amount", l)) { + if (item) { + item->set_amount(l); + } + } else { + zoneini.unknown_key(); + } } else if (zoneini.in_section("ship")) { - // ship definition for a station or planet + // ship trade definition for a station or planet if (!entity || !inventory) { continue; } @@ -1686,7 +2042,8 @@ bool Game::generate_entity_menus(core::Entity *entity) if (entity->inventory()) { entity->set_flag(core::Entity::KeepAlive); size_t nbcargo = 0; - size_t nbships = 0; + size_t nbweapon = 0; + size_t nbships = 0; for (core::Inventory::Items::const_iterator it = entity->inventory()->items().begin(); it != entity->inventory()->items().end(); it++) { core::Item *item = (*it); @@ -1694,6 +2051,9 @@ bool Game::generate_entity_menus(core::Entity *entity) if (item->info()->type() == Cargo::infotype()) { nbcargo++; + } else if (item->info()->type() == Weapon::infotype()) { + nbweapon++; + } else if (item->info()->type() == ShipModel::infotype()) { if (!menu_dealer) { menu_dealer = new MenuDescription(); @@ -1723,6 +2083,15 @@ bool Game::generate_entity_menus(core::Entity *entity) button->set_alignment(ButtonDescription::Center); menu_main->add_button(button); } + + if (nbweapon > 0) { + con_debug << " " << entity->label() << " " << nbcargo << " weapon " << aux::plural("type", nbweapon) << std::endl; + button = new ButtonDescription(); + button->set_text("Weapon Dealer"); + button->set_command("trade weapon", ButtonDescription::CommandMenu); + button->set_alignment(ButtonDescription::Center); + menu_main->add_button(button); + } if (nbships > 0) { con_debug << " " << entity->label() << " " << nbships << " ship " << aux::plural("type", nbships) << std::endl; diff --git a/src/game/base/planet.cc b/src/game/base/planet.cc index 2adb1fb..06a8219 100644 --- a/src/game/base/planet.cc +++ b/src/game/base/planet.cc @@ -6,7 +6,7 @@ #include "base/game.h" #include "base/planet.h" - +#include "base/weapon.h" namespace game { @@ -27,4 +27,36 @@ Planet::~Planet() } +void Planet::upkeep(const unsigned long timestamp) +{ + if (!inventory()) + return; + + const unsigned long deplete = (Game::g_deplete ? 1000 * (unsigned long) Game::g_deplete->value() : 0); + + if (deplete > 0) { + bool dirty = false; + for (core::Inventory::Items::iterator it = inventory()->items().begin(); it != inventory()->items().end(); ) { + core::Item *item = (*it); + if ((item->amount() > 0) && (item->timestamp() + deplete < timestamp)) { + item->dec_amount(1); + dirty = true; + } + + if ((item->info()->type() == Weapon::infotype()) && (item->amount() == 0)) { + delete (item); + (*it) = 0; + inventory()->items().erase(it++); + dirty = true; + } else { + ++it; + } + } + + if (dirty) { + inventory()->set_dirty(); + } + } +} + } // namespace game diff --git a/src/game/base/planet.h b/src/game/base/planet.h index 19db012..337bab2 100644 --- a/src/game/base/planet.h +++ b/src/game/base/planet.h @@ -21,6 +21,8 @@ class Planet : public core::EntityGlobe public: Planet(); virtual ~Planet(); + + virtual void upkeep(const unsigned long timestamp); }; } // namespace game diff --git a/src/game/base/savegame.cc b/src/game/base/savegame.cc index 0057a50..e70e143 100644 --- a/src/game/base/savegame.cc +++ b/src/game/base/savegame.cc @@ -177,6 +177,14 @@ void SaveGame::load_game(core::Player *player, filesystem::IniFile & inifile) item->unset_flag(core::Item::Tradeable); } } + } else if (inifile.got_key_bool("unique", b)) { + if (item) { + if (b) { + item->set_flag(core::Item::Unique); + } else { + item->unset_flag(core::Item::Unique); + } + } } else { inifile.unknown_key(); } @@ -291,7 +299,12 @@ void SaveGame::inventory_to_stream(core::Inventory *inventory, std::ostream & os os << "label=" << item->info()->label() << std::endl; os << "amount=" << item->amount() << std::endl; os << "price=" << item->price() << std::endl; - os << "tradeable=" << (item->has_flag(core::Item::Tradeable) ? "yes" : "no") << std::endl; + if (item->has_flag(core::Item::Tradeable)) { + os << "tradeable=" << (item->has_flag(core::Item::Tradeable) ? "yes" : "no") << std::endl; + } + if (item->has_flag(core::Item::Unique)) { + os << "unique=" << (item->has_flag(core::Item::Unique) ? "yes" : "no") << std::endl; + } } } diff --git a/src/game/base/ship.cc b/src/game/base/ship.cc index 9874337..22fb269 100644 --- a/src/game/base/ship.cc +++ b/src/game/base/ship.cc @@ -15,8 +15,6 @@ #include "base/ship.h" #include "math/functions.h" - - using math::degrees360f; using math::degrees180f; diff --git a/src/game/base/station.cc b/src/game/base/station.cc index 6493348..31e6b3e 100644 --- a/src/game/base/station.cc +++ b/src/game/base/station.cc @@ -6,6 +6,7 @@ #include "base/game.h" #include "base/station.h" +#include "base/weapon.h" #include "sys/sys.h" namespace game @@ -32,12 +33,21 @@ void Station::upkeep(const unsigned long timestamp) if (deplete > 0) { bool dirty = false; - for (core::Inventory::Items::iterator it = inventory()->items().begin(); it != inventory()->items().end(); it++) { + for (core::Inventory::Items::iterator it = inventory()->items().begin(); it != inventory()->items().end(); ) { core::Item *item = (*it); if ((item->amount() > 0) && (item->timestamp() + deplete < timestamp)) { item->dec_amount(1); dirty = true; } + + if ((item->info()->type() == Weapon::infotype()) && (item->amount() == 0)) { + delete (item); + (*it) = 0; + inventory()->items().erase(it++); + dirty = true; + } else { + ++it; + } } if (dirty) { diff --git a/src/game/base/weapon.cc b/src/game/base/weapon.cc index 7f816e2..8be9f9a 100644 --- a/src/game/base/weapon.cc +++ b/src/game/base/weapon.cc @@ -11,6 +11,7 @@ #include "filesystem/inifile.h" #include "auxiliary/functions.h" #include "core/func.h" +#include "base/cargopod.h" #include "base/game.h" #include "base/weapon.h" @@ -187,6 +188,21 @@ void Weapon::done() core::Func::remove("list_weapons"); } + +Weapon *Weapon::find(const std::string & label) +{ + if (!label.size()) { + return 0; + } + + return (Weapon *) core::Info::find(weapon_infotype, label); +} + +void Weapon::list() +{ + core::Info::list(weapon_infotype); +} + /* ---- class Weapon ------------------------------------------- */ Weapon::Weapon() : core::Info(weapon_infotype) @@ -200,18 +216,14 @@ Weapon::~Weapon() { } -Weapon *Weapon::find(const std::string & label) +void Weapon::set_stackable(bool stackable) { - if (!label.size()) { - return 0; - } - - return (Weapon *) core::Info::find(weapon_infotype, label); + weapon_stackable = stackable; } -void Weapon::list() +void Weapon::set_level(const int level) { - core::Info::list(weapon_infotype); + weapon_level = level; } } // namespace game diff --git a/src/game/base/weapon.h b/src/game/base/weapon.h index b263266..247a3e7 100644 --- a/src/game/base/weapon.h +++ b/src/game/base/weapon.h @@ -25,13 +25,9 @@ public: return weapon_level; } - inline void set_stackable(bool stackable) { - weapon_stackable = stackable; - } + void set_stackable(bool stackable); - inline void set_level(const int level) { - weapon_level = level; - } + void set_level(const int level); /* --- static registry functions ---------------------------------- */ -- cgit v1.2.3