Project::OSiRiON - Git repositories
Project::OSiRiON
News . About . Screenshots . Downloads . Forum . Wiki . Tracker . Git
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStijn Buys <ingar@osirion.org>2012-10-20 16:35:26 +0000
committerStijn Buys <ingar@osirion.org>2012-10-20 16:35:26 +0000
commit75274ebd6ba90784f5aa837b7e5ea97fc6bfb720 (patch)
treea5d51a87bf3f20833df18bc40a3254b946716afb
parentf01629dc14b1ee05b44d2e38b3dffbc1441fd85f (diff)
Item id based inventory, support for weapon dealers.
-rw-r--r--src/client/inventorywindow.cc4
-rw-r--r--src/client/trademenu.cc4
-rw-r--r--src/core/commandbuffer.cc9
-rw-r--r--src/core/entity.cc4
-rw-r--r--src/core/gameserver.cc4
-rw-r--r--src/core/info.cc4
-rw-r--r--src/core/inventory.cc48
-rw-r--r--src/core/inventory.h29
-rw-r--r--src/core/item.cc22
-rw-r--r--src/core/item.h41
-rw-r--r--src/core/netconnection.cc68
-rw-r--r--src/core/netserver.cc19
-rw-r--r--src/game/base/cargo.cc276
-rw-r--r--src/game/base/cargo.h6
-rw-r--r--src/game/base/game.cc627
-rw-r--r--src/game/base/planet.cc34
-rw-r--r--src/game/base/planet.h2
-rw-r--r--src/game/base/savegame.cc15
-rw-r--r--src/game/base/ship.cc2
-rw-r--r--src/game/base/station.cc12
-rw-r--r--src/game/base/weapon.cc28
-rw-r--r--src/game/base/weapon.h8
22 files changed, 785 insertions, 481 deletions
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<Item *> Items;
+ typedef std::list<Item *> Items;
/**
* @brief default constructor
@@ -45,14 +45,21 @@ 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
*/
inline const float capacity() const {
@@ -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,14 +23,16 @@ 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
*/
inline long amount() const { return item_amount; }
@@ -69,6 +71,13 @@ public:
}
/**
+ * @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
* */
inline const bool dirty() const {
@@ -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
@@ -98,6 +122,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
*/
inline void set_flag(Flags 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<Ship *>(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<Ship *>(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 ---------------------------------- */