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>2010-10-26 21:08:12 +0000
committerStijn Buys <ingar@osirion.org>2010-10-26 21:08:12 +0000
commit75c6db097b990e58b4b2585580a89561c838d923 (patch)
tree8c913bdc531ea9a76dcaa9e10a65763f95fa55e4
parent23c7d2c11170ee8736673e82a88e87a3d2e538f7 (diff)
updated network protocol version to 20, implemented invemtory depletion, unified depletion with keepalive
-rw-r--r--src/core/application.cc8
-rw-r--r--src/core/cvar.cc3
-rw-r--r--src/core/cvar.h4
-rw-r--r--src/core/entity.cc30
-rw-r--r--src/core/entity.h85
-rw-r--r--src/core/gameserver.cc107
-rw-r--r--src/core/item.cc8
-rw-r--r--src/core/item.h27
-rw-r--r--src/core/net.h4
-rw-r--r--src/game/base/cargopod.cc7
-rw-r--r--src/game/base/cargopod.h2
-rw-r--r--src/game/base/game.cc12
-rw-r--r--src/game/base/game.h10
-rw-r--r--src/game/base/station.cc24
-rw-r--r--src/game/base/station.h2
15 files changed, 208 insertions, 125 deletions
diff --git a/src/core/application.cc b/src/core/application.cc
index 1d7ded2..f21dcad 100644
--- a/src/core/application.cc
+++ b/src/core/application.cc
@@ -110,9 +110,6 @@ void Application::init(int count, char **arguments)
Cvar::sv_private = Cvar::get("sv_private", "0");
Cvar::sv_private->set_info("[bool] enable or disable network server for a client");
- Cvar::cl_prediction = Cvar::get("cl_prediction", "0", Cvar::Archive);
- Cvar::cl_prediction->set_info("[bool] enable or disable client prediction");
-
// load configuration
load_config();
load_autoexec();
@@ -133,10 +130,13 @@ void Application::init(int count, char **arguments)
Cvar::sv_password = Cvar::get("sv_password", "", Cvar::Archive);
Cvar::sv_password->set_info("[string] server rcon password");
+
+ Cvar::sv_keepalive = Cvar::get("sv_keepalive", "120", core::Cvar::Archive);
+ Cvar::sv_keepalive->set_info("[int] number of seconds to keep dynamic objects alive");
// network settings
Cvar::net_host = Cvar::get("net_host", "0.0.0.0", Cvar::Archive);
- Cvar::net_host->set_info("[ip] IP address the network server binds to");
+ Cvar::net_host->set_info("[address] IP address the network server binds to");
Cvar::net_port = Cvar::get("net_port", "8042", Cvar::Archive);
Cvar::net_port->set_info("[int] default network port");
diff --git a/src/core/cvar.cc b/src/core/cvar.cc
index a47b72e..bbdf395 100644
--- a/src/core/cvar.cc
+++ b/src/core/cvar.cc
@@ -25,8 +25,7 @@ Cvar *Cvar::sv_name = 0;
Cvar *Cvar::sv_description = 0;
Cvar *Cvar::sv_password = 0;
Cvar *Cvar::sv_arraysize = 0;
-
-Cvar *Cvar::cl_prediction = 0;
+Cvar *Cvar::sv_keepalive = 0;
Cvar *Cvar::net_host = 0;
Cvar *Cvar::net_port = 0;
diff --git a/src/core/cvar.h b/src/core/cvar.h
index 21491fd..2487adc 100644
--- a/src/core/cvar.h
+++ b/src/core/cvar.h
@@ -156,10 +156,10 @@ public:
static Cvar *sv_description; // server description
static Cvar *sv_password; // server rcon password
static Cvar *sv_arraysize; // vertex array size in MegaBytes
-
+ static Cvar *sv_keepalive; // entity keepalive timeout
+
static Cvar *con_ansi; // console ANSI colors
- static Cvar *cl_prediction; // client prediction
static Cvar *net_host; // network server ip (default binds to all interfaces)
static Cvar *net_port; // network port
diff --git a/src/core/entity.cc b/src/core/entity.cc
index c99c186..4f13efa 100644
--- a/src/core/entity.cc
+++ b/src/core/entity.cc
@@ -160,6 +160,7 @@ Entity::Entity() :
entity_created = true;
entity_destroyed = false;
entity_dirty = false;
+ entity_keepalive = 0;
entity_zone = 0;
entity_oldzone = 0;
@@ -182,6 +183,7 @@ Entity::Entity(std::istream & is)
entity_zone = 0;
entity_oldzone = 0;
entity_visible = true;
+ entity_keepalive = 0;
entity_model = 0;
@@ -471,6 +473,10 @@ void Entity::frame(float seconds)
{
}
+void Entity::upkeep(const unsigned long timestamp)
+{
+}
+
void Entity::add_menu(MenuDescription *menu)
{
entity_menus.push_back(menu);
@@ -544,16 +550,12 @@ EntityDynamic::EntityDynamic() : Entity()
{
entity_state = Normal;
entity_timer = 0;
- entity_keepalive_time = 0.0f;
- entity_keepalive_timeout = 0.0f;
}
EntityDynamic::EntityDynamic(std::istream & is) : Entity(is)
{
entity_state = Normal;
entity_timer = 0;
- entity_keepalive_time = 0.0f;
- entity_keepalive_timeout = 0.0f;
}
EntityDynamic::~EntityDynamic()
@@ -568,16 +570,6 @@ void EntityDynamic::set_state(int state)
}
}
-void EntityDynamic::set_keepalive_time(float time)
-{
- entity_keepalive_time = time;
-}
-
-void EntityDynamic::set_keepalive_timeout(float timeout)
-{
- entity_keepalive_timeout = timeout;
-}
-
void EntityDynamic::reset()
{
Entity::reset();
@@ -596,13 +588,7 @@ void EntityDynamic::frame(float seconds)
if (entity_state == Docked) {
return;
}
-
- if (flag_is_set(KeepAlive)) {
- if ((keepalive_time() > 0.0f) && (keepalive_time() < server()->time())) {
- die();
- }
- }
-
+
// transfer bullet state to entity state
if (entity_body) {
// this makes sure an update is sent if speed goes to 0 in the next step
@@ -822,6 +808,7 @@ void EntityControlable::serialize_client_update(std::ostream & os) const
os << target_thrust << " ";
os << target_roll << " ";
os << target_strafe << " ";
+ os << target_vstrafe << " ";
os << target_afterburner << " ";
}
@@ -833,6 +820,7 @@ void EntityControlable::receive_client_update(std::istream &is)
is >> target_thrust;
is >> target_roll;
is >> target_strafe;
+ is >> target_vstrafe;
is >> target_afterburner;
}
diff --git a/src/core/entity.h b/src/core/entity.h
index 8dd5644..954b261 100644
--- a/src/core/entity.h
+++ b/src/core/entity.h
@@ -216,6 +216,11 @@ public:
return entity_destroyed;
}
+ /// time when the entity was last alive
+ inline unsigned long keepalive() const {
+ return entity_keepalive;
+ }
+
/// list inventory, if available, to console
void list_inventory() const;
@@ -255,6 +260,15 @@ public:
virtual void frame(float seconds);
/**
+ * @brief runs one upkeep frame for the entity
+ * The upkeep frame will be executed by the engine if the entity has the KeepAlive flag set
+ * and the keepalive timeout has been elapsed.
+ * The default implementation does nothing
+ * @param timestamp game timestamp for the current upkeep frame
+ */
+ virtual void upkeep(const unsigned long timestamp);
+
+ /**
* @brief set the zone the entity is currently in
* this fuction removes the entity from its previous zone
* and removes it to the new one, if it is not 0
@@ -282,19 +296,43 @@ public:
entity_radius = radius;
}
- /* ---- actors ---------------------------------------------------- */
+
+ /// set location
+ inline void set_location(const math::Vector3f &location) {
+ entity_location.assign(location);
+ }
+
+ /// set location
+ inline void set_axis(const math::Axis &axis) {
+ entity_axis.assign(axis);
+ }
- /// set flags
+ /// set flag
inline void set_flag(Flags flag) {
entity_flags |= flag;
}
- /// unset flags
+ /// unset flag
inline void unset_flag(Flags flag) {
entity_flags &= ~flag;
}
/**
+ * @brief add an inventory to this entity
+ * Entity takes ownership over the inventory pointer
+ */
+ void set_inventory(Inventory *inventory);
+
+ void set_info(Info *info);
+
+ /// set the timestamp when the entity was last alive
+ void set_keepalive(unsigned long timestamp) {
+ entity_keepalive = timestamp;
+ }
+
+ /* ---- actors ---------------------------------------------------- */
+
+ /**
* @brief reset the physics state
*/
virtual void reset();
@@ -307,16 +345,6 @@ public:
/// clear all update flags
virtual void clear_updates();
-
- /// set location
- inline void set_location(const math::Vector3f &location) {
- entity_location.assign(location);
- }
-
- /// set location
- inline void set_axis(const math::Axis &axis) {
- entity_axis.assign(axis);
- }
/**
* @brief mutable reference to the location
@@ -345,15 +373,7 @@ public:
inline math::Color& get_color_second() {
return entity_color_second;
}
-
- /**
- * @brief add an inventory to this entity
- * Entity takes ownership over the inventory pointer
- */
- void set_inventory(Inventory *inventory);
-
- void set_info(Info *info);
-
+
/* ---- deserializers -------------------------------------- */
/// receive a client-to-server update from a stream
@@ -376,7 +396,6 @@ public:
/// serialize a server-to-client update on a stream
virtual void serialize_server_update(std::ostream & os) const;
-
/* ---- static --------------------------------------------- */
/// type definition for the entity registry
@@ -459,6 +478,8 @@ private:
Extension* entity_extension[4];
+ unsigned long entity_keepalive;
+
static Registry entity_registry;
static size_t entity_nextid;
@@ -494,16 +515,6 @@ public:
return entity_timer;
}
- /// time when the entity was last alive
- inline const float keepalive_time() const {
- return entity_keepalive_time;
- }
-
- /// keepalive timeout
- inline const float keepalive_timeout() const {
- return entity_keepalive_timeout;
- }
-
/*----- mutators -------------------------------------------------- */
/// mass of the entity
@@ -540,12 +551,6 @@ public:
/// set event state
virtual void set_state(int state);
-
- /// set the time when the entity was last alive, in game time seconds
- void set_keepalive_time(float time);
-
- /// set the timeout after which the entitie is deleted, in seconds
- void set_keepalive_timeout(float timeout);
/// runs one game frame for the entity
/**
@@ -560,8 +565,6 @@ public:
virtual void reset();
protected:
- float entity_keepalive_time;
- float entity_keepalive_timeout;
float entity_timer;
int entity_state;
};
diff --git a/src/core/gameserver.cc b/src/core/gameserver.cc
index 344c069..f84e228 100644
--- a/src/core/gameserver.cc
+++ b/src/core/gameserver.cc
@@ -509,19 +509,77 @@ void GameServer::frame(unsigned long timestamp)
server_previoustime = server_timestamp;
server_timestamp = timestamp - server_startup;
- float elapsed = (float)(server_timestamp - server_previoustime) / 1000.0f;
+ const float elapsed = (float)(server_timestamp - server_previoustime) / 1000.0f;
+ const unsigned long keepalive_timeout = (Cvar::sv_keepalive ? 1000 * (unsigned long) Cvar::sv_keepalive->value() : (unsigned long) 0 );
- // copy the previous entity state to the client state
- /*if (!Cvar::sv_dedicated->value()) {
- reset_clientstate();
- }*/
-
- // run a time frame on each entity
- for (Entity::Registry::iterator it = Entity::registry().begin(); it != Entity::registry().end(); it++) {
- Entity *entity = (*it).second;
+ for (Zone::Registry::iterator zit = Zone::registry().begin(); zit != Zone::registry().end(); zit++) {
+ Zone *zone= (*zit).second;
+
+ bool keepalive_run = false;
+ math::Vector3f keepalive_maxbox;
+ math::Vector3f keepalive_minbox;
- if ((entity->type() == Entity::Controlable) || (entity->type() == Entity::Dynamic)) {
- entity->frame(elapsed);
+ // run a game frame on all dynamic and controlable entities
+ for (Zone::Content::iterator it = zone->content().begin(); it != zone->content().end(); it++) {
+ Entity *entity = (*it);
+
+ if (entity->type() == Entity::Dynamic) {
+ entity->frame(elapsed);
+
+ } else if (entity->type() == Entity::Controlable) {
+ EntityControlable *controlable = static_cast<EntityControlable *>(entity);
+ controlable->frame(elapsed);
+
+ if (controlable->owner() && (controlable->owner()->control() == controlable)) {
+ // add player controlable to keepalive bounding box
+ if (!keepalive_run) {
+ keepalive_maxbox.assign(controlable->location());
+ keepalive_minbox.assign(controlable->location());
+ keepalive_run = true;
+ } else {
+ for (size_t i = 0; i < 3; i++) {
+ if (keepalive_maxbox[i] < controlable->location()[i])
+ keepalive_maxbox[i] = controlable->location()[i];
+ if (keepalive_minbox[i] > controlable->location()[i])
+ keepalive_minbox[i] = controlable->location()[i];
+ }
+ }
+ }
+ }
+ }
+
+ // expand keepalive bounding box
+ for (size_t i = 0; i < 3; i++) {
+ keepalive_maxbox[i] += range::fxdistance * 0.5f;
+ keepalive_minbox[i] -= range::fxdistance * 0.5f;
+ }
+
+ // run an upkeep frame on entities that require it
+ for (Zone::Content::iterator it = zone->content().begin(); it != zone->content().end(); it++) {
+ Entity *entity = (*it);
+
+ // if entity is inside the keepalive bounding box, the keepalive timestamp will be set to the current game timestamp
+ if (entity->flag_is_set(Entity::KeepAlive)) {
+ if (keepalive_run) {
+ bool alive = true;
+
+ // bounding box test
+ for (size_t i = 0; alive && (i < 3); i++) {
+ if ((entity->location()[i] > keepalive_maxbox[i]) || (entity->location()[i] < keepalive_minbox[i])) {
+ alive = false;
+ }
+ }
+
+ if (alive) {
+ entity->set_keepalive(server_timestamp);
+ }
+ }
+
+ // run upkeep if the keepalive timeout has elapsed
+ if (entity->keepalive() + keepalive_timeout < server_timestamp) {
+ entity->upkeep(server_timestamp);
+ }
+ }
}
}
@@ -543,7 +601,7 @@ void GameServer::frame(unsigned long timestamp)
EntityControlable *control = player->control();
// the player is viewing an entity
- if (view) {
+ if (view) {
// the view has changed zone
if (view->zone() != player->zone()) {
if (control) {
@@ -589,31 +647,6 @@ void GameServer::frame(unsigned long timestamp)
server_network->frame(server_timestamp);
}
- const float keepalive_distance_squared = range::fxdistance * range::fxdistance;
-
- // FIXME KeepAlive sweep has to be done in linear order, O(n^2) is extremely slow with a large number of entities
-
- for (Entity::Registry::const_iterator it = Entity::registry().begin(); it != Entity::registry().end(); it++) {
-
- // set keepalive timeout
- if ((*it).second->type() == Entity::Controlable) {
- const EntityControlable *controlable = static_cast<const EntityControlable *>((*it).second);
-
- if ( (controlable->state() != Entity::Docked) && controlable->owner() && controlable->zone() ) {
- for (Zone::Content::iterator zit = controlable->zone()->content().begin(); zit != controlable->zone()->content().end(); zit++) {
-
- if ( ((*zit)->flag_is_set(Entity::KeepAlive)) && ((*zit)->type() == Entity::Dynamic) && ((*zit) != controlable) ) {
- EntityDynamic *dynamic = static_cast<EntityDynamic *>(*zit);
- if (math::distancesquared(controlable->location(), dynamic->location()) < keepalive_distance_squared) {
- dynamic->set_keepalive_time(time() + dynamic->keepalive_timeout());
- }
- }
- }
- }
-
- }
- }
-
// remove deleted entities and mark remaining entities as updated
for (Entity::Registry::iterator it = Entity::registry().begin(); it != Entity::registry().end();) {
// remove deleted entities
diff --git a/src/core/item.cc b/src/core/item.cc
index df12885..3768afa 100644
--- a/src/core/item.cc
+++ b/src/core/item.cc
@@ -23,6 +23,7 @@ Item::Item(const Info *info)
{
item_info = info;
item_amount = 0;
+ item_flags = 0;
item_price = info->price();
set_timestamp(game() ? game()->timestamp() : 1);
}
@@ -31,6 +32,7 @@ Item::Item(const Item &other)
{
item_info = other.info();
item_amount = other.amount();
+ item_flags = other.flags();
item_price = other.price();
set_timestamp(game() ? game()->timestamp() : 1);
}
@@ -39,7 +41,8 @@ Item::~Item()
{
item_info = 0;
item_amount = 0;
- item_amount = 0;
+ item_flags = 0;
+ item_price = 0;
}
void Item::set_amount(const long amount)
@@ -73,13 +76,14 @@ void Item::set_timestamp(const unsigned long timestamp)
void Item::serialize_server_update(std::ostream & os) const
{
- os << amount() << " " << price() << " ";
+ os << amount() << " " << price() << " " << flags() << " ";
}
void Item::receive_server_update(std::istream &is)
{
is >> item_amount;
is >> item_price;
+ is >> item_flags;
}
} // namespace core
diff --git a/src/core/item.h b/src/core/item.h
index 0e9e167..ac3188d 100644
--- a/src/core/item.h
+++ b/src/core/item.h
@@ -19,6 +19,8 @@ namespace core
class Item
{
public:
+ enum Flags {Tradeable = 1};
+
Item(const Info *info);
/// copy constructor
@@ -46,7 +48,17 @@ public:
inline const unsigned long timestamp() const {
return item_timestamp;
}
-
+
+ /// item flags
+ inline const unsigned int flags() const {
+ return item_flags;
+ }
+
+ /// returns true of a flag is set
+ inline const bool flag_is_set(const Flags flag) const {
+ return ((item_flags & (unsigned int)flag) == (unsigned int)flag);
+ }
+
/* ---- mutators ----------------------------------------------- */
/**
@@ -59,7 +71,16 @@ public:
void dec_amount(const long amount);
void set_price(const long price);
-
+
+ /// set flag
+ inline void set_flag(Flags flag) {
+ item_flags |= flag;
+ }
+
+ /// unset flag
+ inline void unset_flag(Flags flag) {
+ item_flags &= ~flag;
+ }
void set_dirty();
/* ---- serializers -------------------------------------------- */
@@ -76,6 +97,8 @@ private:
long item_amount;
unsigned long item_timestamp;
+
+ unsigned int item_flags;
};
} // namespace core
diff --git a/src/core/net.h b/src/core/net.h
index 39dfdf6..31fc6d7 100644
--- a/src/core/net.h
+++ b/src/core/net.h
@@ -11,7 +11,7 @@ namespace core
{
/// network protocol version
-const unsigned int PROTOCOLVERSION = 19;
+const unsigned int PROTOCOLVERSION = 20;
/// maximum lenght of a (compressed) network message block
const unsigned int FRAMESIZE = 1152;
@@ -24,7 +24,7 @@ const unsigned int MAXPENDINGCONNECTIONS = 32;
const unsigned int DEFAULTPORT = 8042;
/// network timeout in seconds
-const float NETTIMEOUT = 20;
+const float NETTIMEOUT = 15;
}
diff --git a/src/game/base/cargopod.cc b/src/game/base/cargopod.cc
index 5ea4105..7406d3a 100644
--- a/src/game/base/cargopod.cc
+++ b/src/game/base/cargopod.cc
@@ -17,7 +17,6 @@ CargoPod::CargoPod() : EntityDynamic()
set_label("cargopod");
set_flag(core::Entity::KeepAlive);
- set_keepalive_timeout(Game::g_keepalive ? Game::g_keepalive->value() : 0);
if (Default::podmodel)
set_modelname(Default::podmodel->name());
@@ -35,5 +34,11 @@ CargoPod::~CargoPod()
}
+void CargoPod::upkeep(const unsigned long timestamp)
+{
+ // cargo pods dissapear on upkeep
+ die();
+}
+
} // namespace game
diff --git a/src/game/base/cargopod.h b/src/game/base/cargopod.h
index daeb9bc..7bce9a4 100644
--- a/src/game/base/cargopod.h
+++ b/src/game/base/cargopod.h
@@ -17,6 +17,8 @@ class CargoPod : public core::EntityDynamic
public:
CargoPod();
virtual ~CargoPod();
+
+ virtual void upkeep(const unsigned long timestamp);
};
} // namespace game
diff --git a/src/game/base/game.cc b/src/game/base/game.cc
index 7aa1081..40c7c28 100644
--- a/src/game/base/game.cc
+++ b/src/game/base/game.cc
@@ -54,7 +54,7 @@ core::Cvar *Game::g_impulsespeed = 0;
core::Cvar *Game::g_jumppointrange = 0;
core::Cvar *Game::g_devel = 0;
core::Cvar *Game::g_damping = 0;
-core::Cvar *Game::g_keepalive;
+core::Cvar *Game::g_deplete = 0;
core::Module *factory()
{
@@ -905,8 +905,8 @@ Game::Game() : core::Module("Project::OSiRiON", true)
g_damping = core::Cvar::get("g_damping", "0.1", core::Cvar::Archive);
g_damping->set_info("[float] physics damping factor (0-1)");
- g_keepalive = core::Cvar::get("g_keepalive", "300", core::Cvar::Archive);
- g_keepalive->set_info("[float] amount of time dynamic objects are kept alive, in seconds");
+ g_deplete = core::Cvar::get("g_deplete", "60", core::Cvar::Archive);
+ g_deplete->set_info("[int] number of seconds to deplete 1 unit of cargo from inventories");
}
Game::~Game()
@@ -915,7 +915,6 @@ Game::~Game()
g_jumppointrange = 0;
g_devel = 0;
g_damping = 0;
- g_keepalive = 0;
// game functions are automaticly removed
// FIXME move cleanup sequence to core::
@@ -1025,7 +1024,7 @@ bool Game::load_zone(core::Zone *zone)
bool b;
long l;
-
+
std::string strval;
while (zoneini.getline()) {
@@ -1307,7 +1306,7 @@ bool Game::validate_zone(core::Zone *zone)
JumpGate *jumpgate = static_cast<JumpGate *>(entity);
jumpgate->validate();
} else {
- if ((entity->flags() & core::Entity::Dockable) == core::Entity::Dockable) {
+ if (entity->flag_is_set(core::Entity::Dockable)) {
generate_entity_menus(entity);
}
}
@@ -1351,6 +1350,7 @@ bool Game::generate_entity_menus(core::Entity *entity)
// add trade menus
if (entity->inventory()) {
+ entity->set_flag(core::Entity::KeepAlive);
size_t nbcargo = 0;
size_t nbships = 0;
diff --git a/src/game/base/game.h b/src/game/base/game.h
index d879a30..dd47cef 100644
--- a/src/game/base/game.h
+++ b/src/game/base/game.h
@@ -36,7 +36,7 @@ const unsigned int station_enttype = 262;
const unsigned int cargopod_enttype = 263;
// planet docking distance
-const float planet_safe_distance = 150.0f;
+const float planet_safe_distance = 50.0f;
const float jump_timer_delay = 5.0f;
const float impulse_timer_delay = 3.0f;
@@ -85,12 +85,12 @@ public:
/// game variable: enable or disable development mode (cheat mode)
static core::Cvar *g_devel;
+ /// game variable: number of seconds it takes for 1 unit of cargo to deplete from station inventories
+ static core::Cvar *g_deplete;
+
/// physics variable: default damping factor of space
- static core::Cvar *g_damping;
+ static core::Cvar *g_damping;
- /// game variable: amount of time dynamic objects are kept alive when there are no players
- static core::Cvar *g_keepalive;
-
private:
bool load_world();
diff --git a/src/game/base/station.cc b/src/game/base/station.cc
index 0d992bd..6493348 100644
--- a/src/game/base/station.cc
+++ b/src/game/base/station.cc
@@ -20,6 +20,30 @@ Station::Station() : Entity()
Station::~Station()
{
+
+}
+
+void Station::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(); it++) {
+ core::Item *item = (*it);
+ if ((item->amount() > 0) && (item->timestamp() + deplete < timestamp)) {
+ item->dec_amount(1);
+ dirty = true;
+ }
+ }
+
+ if (dirty) {
+ inventory()->set_dirty();
+ }
+ }
}
}
diff --git a/src/game/base/station.h b/src/game/base/station.h
index 2aa8a95..5f833c4 100644
--- a/src/game/base/station.h
+++ b/src/game/base/station.h
@@ -15,6 +15,8 @@ class Station : public core::Entity
public:
Station();
virtual ~Station();
+
+ virtual void upkeep(const unsigned long timestamp);
};
}