widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #01516
[Merge] lp:~widelands-dev/widelands/storages_garrisons into lp:widelands
cghislai has proposed merging lp:~widelands-dev/widelands/storages_garrisons into lp:widelands.
Requested reviews:
Widelands Developers (widelands-dev)
For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/storages_garrisons/+merge/178704
I'm not finished working on it yet, but I already put it on review so you can check changes and suggest design changes.
This is a refactoring in order to separate storages (entities storing wares/workers) from the warehouse class and garrisons (entities storing soldiers with control) from the militarysites/trainingsites.
I try to commit only playable revisions. Please note that post-b17 savegames may not be compatible.
My plan is to move portdock stuff out of warehouse class and add a an optional garrison on warehouses for headquarters.
--
https://code.launchpad.net/~widelands-dev/widelands/storages_garrisons/+merge/178704
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/storages_garrisons into lp:widelands.
=== modified file 'src/ai/defaultai.cc'
--- src/ai/defaultai.cc 2013-07-26 20:19:36 +0000
+++ src/ai/defaultai.cc 2013-08-06 10:09:46 +0000
@@ -72,7 +72,7 @@
next_attack_consideration_due(300000),
inhibit_road_building (0),
time_of_last_construction (0),
- numof_warehouses (0)
+ numof_storages (0)
{}
DefaultAI::~DefaultAI()
@@ -577,7 +577,7 @@
if (v > 0)
field.military_influence +=
- v * v * militarysite->soldierCapacity();
+ v * v * militarysite->get_garrison()->soldierCapacity();
}
if (dynamic_cast<const ProductionSite *>(building))
@@ -626,7 +626,7 @@
if (v > 0)
field.military_influence +=
- v * v * militarysite->soldierCapacity();
+ v * v * militarysite->get_garrison()->soldierCapacity();
}
}
}
@@ -881,8 +881,8 @@
// Check if the produced wares are needed
Ware_Index wt(static_cast<size_t>(bo.outputs.at(0)));
container_iterate(std::list<EconomyObserver *>, economies, l) {
- // Don't check if the economy has no warehouse.
- if ((*l.current)->economy.warehouses().empty())
+ // Don't check if the economy has no storage.
+ if ((*l.current)->economy.storages().empty())
continue;
if ((*l.current)->economy.needs_ware(wt))
prio += 1 + wares.at(bo.outputs.at(0)).preciousness;
@@ -918,8 +918,8 @@
// the ware they're refreshing
Ware_Index wt(static_cast<size_t>(bo.production_hint));
container_iterate(std::list<EconomyObserver *>, economies, l) {
- // Don't check if the economy has no warehouse.
- if ((*l.current)->economy.warehouses().empty())
+ // Don't check if the economy has no storages.
+ if ((*l.current)->economy.storages().empty())
continue;
if ((*l.current)->economy.needs_ware(wt)) {
prio += wares.at(bo.production_hint).preciousness * inout * 2;
@@ -964,8 +964,8 @@
// Check if the produced wares are needed
container_iterate(std::list<EconomyObserver *>, economies, l) {
- // Don't check if the economy has no warehouse.
- if ((*l.current)->economy.warehouses().empty())
+ // Don't check if the economy has no storages.
+ if ((*l.current)->economy.storages().empty())
continue;
for (uint32_t m = 0; m < bo.outputs.size(); ++m) {
Ware_Index wt(static_cast<size_t>(bo.outputs.at(m)));
@@ -1056,7 +1056,7 @@
// needed for soldier training) near the frontier.
prio += productionsites.size() + mines.size();
prio += militarysites.size() / 3;
- prio -= (bo.cnt_under_construction + numof_warehouses) * 35;
+ prio -= (bo.cnt_under_construction + numof_storages) * 35;
prio *= 2;
// take care about borders and enemies
@@ -1880,13 +1880,13 @@
if (map.find_fields(Area<FCoords>(f, vision), 0, find_unowned) == 0) {
// If no enemy in sight - decrease the number of stationed soldiers
- // as long as it is > 1 - BUT take care that there is a warehouse in the
+ // as long as it is > 1 - BUT take care that there is a storage in the
// same economy where the thrown out soldiers can go to.
- if (ms->economy().warehouses().size()) {
- uint32_t const j = ms->soldierCapacity();
- if (MilitarySite::kPrefersRookies != ms->get_soldier_preference())
+ if (ms->economy().storages().size()) {
+ uint32_t const j = ms->get_garrison()->soldierCapacity();
+ if (Garrison::SoldierPref::Rookies != ms->get_garrison()->get_soldier_preference())
{
- game().send_player_militarysite_set_soldier_preference(*ms, MilitarySite::kPrefersRookies);
+ game().send_player_militarysite_set_soldier_preference(*ms, Garrison::SoldierPref::Rookies);
}
else
if (j > 1)
@@ -1912,7 +1912,7 @@
// the destruction of the flag avoids that defaultAI will have
// too many unused roads - if needed the road will be rebuild
// directly.
- if (static_cast<int32_t>(ms->maxSoldierCapacity() * 4) < bf.military_influence) {
+ if (static_cast<int32_t>(ms->get_garrison()->maxSoldierCapacity() * 4) < bf.military_influence) {
if (ms->get_playercaps() & Widelands::Building::PCap_Dismantle) {
flags_to_be_removed.push_back(ms->base_flag().get_position());
game().send_player_dismantle(*ms);
@@ -1964,12 +1964,12 @@
} else {
// If an enemy is in sight and the number of stationed soldier is not
// at maximum - set it to maximum.
- uint32_t const j = ms->maxSoldierCapacity();
- uint32_t const k = ms->soldierCapacity();
+ uint32_t const j = ms->get_garrison()->maxSoldierCapacity();
+ uint32_t const k = ms->get_garrison()->soldierCapacity();
if (j > k)
game().send_player_change_soldier_capacity(*ms, j - k);
- if (MilitarySite::kPrefersHeroes != ms->get_soldier_preference())
- game().send_player_militarysite_set_soldier_preference(*ms, MilitarySite::kPrefersHeroes);
+ if (Garrison::SoldierPref::Heroes != ms->get_garrison()->get_soldier_preference())
+ game().send_player_militarysite_set_soldier_preference(*ms, Garrison::SoldierPref::Heroes);
changed = true;
}
reorder:;
@@ -2182,7 +2182,7 @@
militarysites.back().bo = &bo;
militarysites.back().checks = bo.desc->get_size();
} else if (bo.type == BuildingObserver::WAREHOUSE)
- ++numof_warehouses;
+ ++numof_storages;
}
}
@@ -2244,8 +2244,8 @@
break;
}
} else if (bo.type == BuildingObserver::WAREHOUSE) {
- assert(numof_warehouses > 0);
- --numof_warehouses;
+ assert(numof_storages > 0);
+ --numof_storages;
}
}
m_buildable_changed = true;
@@ -2310,41 +2310,28 @@
map.find_immovables
(Area<FCoords>(f, vision), &immovables, FindImmovableAttackable());
- for (uint32_t j = 0; j < immovables.size(); ++j)
- if (upcast(MilitarySite, bld, immovables.at(j).object)) {
- if (!player->is_hostile(bld->owner()))
- continue;
- if (bld->canAttack()) {
- int32_t ta = player->findAttackSoldiers(bld->base_flag());
- if (type == NORMAL)
- ta = ta * 2 / 3;
- if (ta < 1)
- continue;
-
- int32_t const tc = ta - bld->presentSoldiers().size();
- if (tc > chance) {
- target = bld;
- chance = tc;
- attackers = ta;
- }
- }
- } else if (upcast(Warehouse, wh, immovables.at(j).object)) {
- if (!player->is_hostile(wh->owner()))
- continue;
- if (wh->canAttack()) {
- int32_t ta = player->findAttackSoldiers(wh->base_flag());
- if (ta < 1)
- continue;
-
- // extra priority push!
- int32_t tc = ta * 2;
- if (tc > chance) {
- target = wh;
- chance = tc;
- attackers = ta;
- }
+ for (uint32_t j = 0; j < immovables.size(); ++j) {
+ if (upcast(GarrisonOwner, go, immovables.at(j).object)) {
+ if (!player->is_hostile(go->get_garrison()->owner())) {
+ continue;
+ }
+ if (!go->get_garrison()->canAttack()) {
+ continue;
+ }
+ int32_t ta = player->findAttackSoldiers(go->get_building()->base_flag());
+ if (type == NORMAL)
+ ta = ta * 2 / 3;
+ if (ta < 1)
+ continue;
+
+ int32_t const tc = ta - go->get_garrison()->presentSoldiers().size();
+ if (tc > chance) {
+ target = go->get_building();
+ chance = tc;
+ attackers = ta;
}
}
+ }
// Reenque militarysite at the end of list
militarysites.push_back(militarysites.front());
=== modified file 'src/ai/defaultai.h'
--- src/ai/defaultai.h 2013-07-26 20:19:36 +0000
+++ src/ai/defaultai.h 2013-08-06 10:09:46 +0000
@@ -191,7 +191,7 @@
int32_t inhibit_road_building;
int32_t time_of_last_construction;
- uint16_t numof_warehouses;
+ uint16_t numof_storages;
};
#endif
=== modified file 'src/economy/economy.cc'
--- src/economy/economy.cc 2013-07-26 20:19:36 +0000
+++ src/economy/economy.cc 2013-08-06 10:09:46 +0000
@@ -27,11 +27,10 @@
#include "economy/route.h"
#include "economy/routeastar.h"
#include "economy/router.h"
-#include "economy/warehousesupply.h"
#include "logic/game.h"
#include "logic/player.h"
+#include "logic/storage.h"
#include "logic/tribe.h"
-#include "logic/warehouse.h"
#include "upcast.h"
#include "wexception.h"
@@ -78,8 +77,8 @@
log("Warning: Economy still has requests left on destruction\n");
if (m_flags.size())
log("Warning: Economy still has flags left on destruction\n");
- if (m_warehouses.size())
- log("Warning: Economy still has warehouses left on destruction\n");
+ if (m_storages.size())
+ log("Warning: Economy still has storages left on destruction\n");
delete[] m_ware_target_quantities;
delete[] m_worker_target_quantities;
@@ -214,22 +213,22 @@
};
/**
- * Find the warehouse closest to the given starting flag.
+ * Find the storage owner closest to the given starting flag.
*
* If the search was successful and \p route is non-null,
* a route is also computed.
*
* \param start starting flag
* \param type whether to path-find as if the path were for a ware
- * \param route if non-null, fill in a route to the warehouse
+ * \param route if non-null, fill in a route to the storage
* \param cost_cutoff if positive, find paths of at most
* that length (in milliseconds)
*/
-Warehouse * Economy::find_closest_warehouse
+StorageOwner* Economy::find_closest_storage
(Flag & start, WareWorker type, Route * route, uint32_t cost_cutoff,
- const Economy::WarehouseAcceptFn & acceptfn)
+ const Economy::StorageAcceptFn & acceptfn)
{
- if (!warehouses().size())
+ if (!storages().size())
return 0;
// A-star with zero estimator = Dijkstra
@@ -243,11 +242,11 @@
return 0;
Flag & flag = current->base_flag();
- if (upcast(Warehouse, warehouse, flag.get_building())) {
- if (!acceptfn || acceptfn(*warehouse)) {
+ if (upcast(StorageOwner, storage_owner, flag.get_building())) {
+ if (!acceptfn || acceptfn(storage_owner)) {
if (route)
astar.routeto(flag, *route);
- return warehouse;
+ return storage_owner;
}
}
}
@@ -368,7 +367,7 @@
/**
* Call this whenever a ware is destroyed or consumed, e.g. food has been
- * eaten or a warehouse has been destroyed.
+ * eaten or a storage has been destroyed.
* This is also called when a ware is removed from the economy through trade or
* a split of the Economy.
*/
@@ -397,32 +396,32 @@
}
/**
- * Add the warehouse to our list of warehouses.
- * This also adds the wares in the warehouse to the economy. However, if wares
- * are added to the warehouse in the future, add_wares() must be called.
+ * Add the storage to our list of storages.
+ * This also adds the wares in the storage to the economy. However, if wares
+ * are added to the storage in the future, add_wares() must be called.
*/
-void Economy::add_warehouse(Warehouse & wh)
+void Economy::add_storage(Storage & storage)
{
- m_warehouses.push_back(&wh);
+ m_storages.push_back(&storage);
}
/**
- * Remove the warehouse and its wares from the economy.
+ * Remove the storage and its wares from the economy.
*/
-void Economy::remove_warehouse(Warehouse & wh)
+void Economy::remove_storage(Storage & storage)
{
- for (size_t i = 0; i < m_warehouses.size(); ++i)
- if (m_warehouses[i] == &wh) {
- m_warehouses[i] = *m_warehouses.rbegin();
- m_warehouses.pop_back();
+ for (size_t i = 0; i < m_storages.size(); ++i)
+ if (m_storages[i] == &storage) {
+ m_storages[i] = *m_storages.rbegin();
+ m_storages.pop_back();
return;
}
- // This assert was modified, since on loading, warehouses might try to
+ // This assert was modified, since on loading, storages might try to
// remove themselves from their own economy, though they weren't added
// (since they weren't initialized)
- assert(m_warehouses.empty());
+ assert(m_storages.empty());
}
/**
@@ -495,8 +494,8 @@
bool Economy::needs_ware(Ware_Index const ware_type) const {
uint32_t const t = ware_target_quantity(ware_type).permanent;
uint32_t quantity = 0;
- container_iterate_const(std::vector<Warehouse *>, m_warehouses, wh) {
- quantity += (*wh)->get_wares().stock(ware_type);
+ container_iterate_const(std::vector<Storage *>, m_storages, storage) {
+ quantity += (*storage)->get_wares().stock(ware_type);
if (t <= quantity)
return false;
}
@@ -507,8 +506,8 @@
bool Economy::needs_worker(Ware_Index const worker_type) const {
uint32_t const t = worker_target_quantity(worker_type).permanent;
uint32_t quantity = 0;
- container_iterate_const(std::vector<Warehouse *>, m_warehouses, wh) {
- quantity += (*wh)->get_workers().stock(worker_type);
+ container_iterate_const(std::vector<Storage *>, m_storages, storage) {
+ quantity += (*storage)->get_workers().stock(worker_type);
if (t <= quantity)
return false;
}
@@ -796,7 +795,7 @@
/**
* Check whether there is a supply for the given request. If the request is a
- * worker request without supply, attempt to create a new worker in a warehouse.
+ * worker request without supply, attempt to create a new worker in a storage.
*/
void Economy::_create_requested_worker(Game & game, Ware_Index index)
{
@@ -820,7 +819,7 @@
return;
// We have worker demand that is not fulfilled by supplies
- // Find warehouses where we can create the required workers,
+ // Find storages where we can create the required workers,
// and collect stats about existing build prerequisites
const Tribe_Descr & tribe = owner().tribe();
const Worker_Descr & w_desc = *tribe.get_worker_descr(index);
@@ -830,20 +829,20 @@
total_available.insert(total_available.begin(), cost.size(), 0);
- for (uint32_t n_wh = 0; n_wh < warehouses().size(); ++n_wh) {
- Warehouse * wh = m_warehouses[n_wh];
+ for (uint32_t storage_idx = 0; storage_idx < m_storages.size(); ++storage_idx) {
+ Storage * storage = m_storages[storage_idx];
- uint32_t planned = wh->get_planned_workers(game, index);
+ uint32_t planned = storage->get_planned_workers(game, index);
total_planned += planned;
- while (wh->can_create_worker(game, index)) {
- wh->create_worker(game, index);
+ while (storage->can_create_worker(game, index)) {
+ storage->create_worker(game, index);
if (!--demand)
return;
}
std::vector<uint32_t> wh_available =
- wh->calc_available_for_worker(game, index);
+ storage->calc_available_for_worker(game, index);
assert(wh_available.size() == total_available.size());
for (uint32_t idx = 0; idx < total_available.size(); ++idx)
@@ -870,25 +869,25 @@
// there are supplies for (otherwise, cyclic transportation might happen)
// Note that supplies might suddenly disappear outside our control because
// of loss of land or silly player actions.
- for (uint32_t n_wh = 0; n_wh < warehouses().size(); ++n_wh) {
- Warehouse * wh = m_warehouses[n_wh];
+ for (uint32_t storage_idx = 0; storage_idx < m_storages.size(); ++storage_idx) {
+ Storage * storage = m_storages[storage_idx];
- uint32_t planned = wh->get_planned_workers(game, index);
+ uint32_t planned = storage->get_planned_workers(game, index);
uint32_t reduce = std::min(planned, total_planned - can_create);
- wh->plan_workers(game, index, planned - reduce);
+ storage->plan_workers(game, index, planned - reduce);
total_planned -= reduce;
}
} else if (total_planned < demand) {
uint32_t plan_goal = std::min(can_create, demand);
- for (uint32_t n_wh = 0; n_wh < warehouses().size(); ++n_wh) {
- Warehouse * wh = m_warehouses[n_wh];
+ for (uint32_t storage_idx = 0; storage_idx < m_storages.size(); ++storage_idx) {
+ Storage * storage = m_storages[storage_idx];
uint32_t supply =
- wh->calc_available_for_worker(game, index)[scarcest_idx];
+ storage->calc_available_for_worker(game, index)[scarcest_idx];
- total_planned -= wh->get_planned_workers(game, index);
+ total_planned -= storage->get_planned_workers(game, index);
uint32_t plan = std::min(supply, plan_goal - total_planned);
- wh->plan_workers(game, index, plan);
+ storage->plan_workers(game, index, plan);
total_planned += plan;
}
}
@@ -896,11 +895,11 @@
/**
* Walk all Requests and find requests of workers than aren't supplied. Then
- * try to create the worker at warehouses.
+ * try to create the worker at storages.
*/
void Economy::_create_requested_workers(Game & game)
{
- if (!warehouses().size())
+ if (!storages().size())
return;
const Tribe_Descr & tribe = owner().tribe();
@@ -920,23 +919,23 @@
/**
* Helper function for \ref _handle_active_supplies
*/
-static bool accept_warehouse_if_policy
- (Warehouse & wh, WareWorker type,
- Ware_Index ware, Warehouse::StockPolicy policy)
+static bool accept_storage_if_policy
+ (StorageOwner* storage, WareWorker type,
+ Ware_Index ware, Storage::StockPolicy policy)
{
- return wh.get_stock_policy(type, ware) == policy;
+ return storage->get_storage()->get_stock_policy(type, ware) == policy;
}
/**
* Send all active supplies (wares that are outside on the road network without
- * being sent to a specific request) to a warehouse.
+ * being sent to a specific request) to a storage.
*/
void Economy::_handle_active_supplies(Game & game)
{
- if (!warehouses().size())
+ if (!storages().size())
return;
- typedef std::vector<std::pair<Supply *, Warehouse *> > Assignments;
+ typedef std::vector<std::pair<Supply *, StorageOwner *> > Assignments;
Assignments assignments;
for (uint32_t idx = 0; idx < m_supplies.get_nrsupplies(); ++idx) {
@@ -950,38 +949,38 @@
bool haveprefer = false;
bool havenormal = false;
- for (uint32_t nwh = 0; nwh < m_warehouses.size(); ++nwh) {
- Warehouse * wh = m_warehouses[nwh];
- Warehouse::StockPolicy policy = wh->get_stock_policy(type, ware);
- if (policy == Warehouse::SP_Prefer) {
+ for (uint32_t storage_idx = 0; storage_idx < m_storages.size(); ++storage_idx) {
+ Storage * storage = m_storages[storage_idx];
+ Storage::StockPolicy policy = storage->get_stock_policy(type, ware);
+ if (policy == Storage::StockPolicy::Prefer) {
haveprefer = true;
break;
}
- if (policy == Warehouse::SP_Normal)
+ if (policy == Storage::StockPolicy::Normal)
havenormal = true;
}
if (!havenormal && !haveprefer && type == wwWARE)
continue;
- Warehouse * wh = find_closest_warehouse
+ StorageOwner * storage_owner = find_closest_storage
(supply.get_position(game)->base_flag(), type, 0, 0,
(!haveprefer && !havenormal)
?
- WarehouseAcceptFn()
+ StorageAcceptFn()
:
boost::bind
- (&accept_warehouse_if_policy,
+ (&accept_storage_if_policy,
_1, type, ware,
- haveprefer ? Warehouse::SP_Prefer : Warehouse::SP_Normal));
+ haveprefer ? Storage::StockPolicy::Prefer : Storage::StockPolicy::Normal));
- if (!wh) {
+ if (!storage_owner) {
log
("Warning: Economy::_handle_active_supplies "
- "didn't find warehouse\n");
+ "didn't find storage\n");
return;
}
- assignments.push_back(std::make_pair(&supply, wh));
+ assignments.push_back(std::make_pair(&supply, storage_owner));
}
// Actually start with the transfers in a separate second phase,
@@ -991,10 +990,10 @@
ss.Unsigned32(0x02decafa); // appears as facade02 in sync stream
ss.Unsigned32(assignments.size());
+ // FIXME CGH check thats working
container_iterate_const(Assignments, assignments, it) {
ss.Unsigned32(it.current->first->get_position(game)->serial());
- ss.Unsigned32(it.current->second->serial());
-
+ ss.Unsigned32(it.current->second->get_building()->serial());
it.current->first->send_to_storage(game, it.current->second);
}
}
=== modified file 'src/economy/economy.h'
--- src/economy/economy.h 2013-07-26 20:19:36 +0000
+++ src/economy/economy.h 2013-08-06 10:09:46 +0000
@@ -34,12 +34,15 @@
namespace Widelands {
+
+class StorageOwner;
+
+class Storage;
struct Player;
struct Game;
struct Flag;
struct Route;
struct RSPairStruct;
-class Warehouse;
struct Request;
struct Supply;
struct Router;
@@ -102,11 +105,11 @@
WareWorker type,
int32_t cost_cutoff = -1);
- typedef boost::function<bool (Warehouse &)> WarehouseAcceptFn;
- Warehouse * find_closest_warehouse
+ typedef boost::function<bool (StorageOwner *)> StorageAcceptFn;
+ StorageOwner * find_closest_storage
(Flag & start, WareWorker type = wwWORKER, Route * route = 0,
uint32_t cost_cutoff = 0,
- const WarehouseAcceptFn & acceptfn = WarehouseAcceptFn());
+ const StorageAcceptFn & acceptfn = StorageAcceptFn());
std::vector<Flag *>::size_type get_nrflags() const {return m_flags.size();}
void add_flag(Flag &);
@@ -122,9 +125,9 @@
void add_workers(Ware_Index, uint32_t count = 1);
void remove_workers(Ware_Index, uint32_t count = 1);
- void add_warehouse(Warehouse &);
- void remove_warehouse(Warehouse &);
- const std::vector<Warehouse *>& warehouses() const {return m_warehouses;}
+ void add_storage(Storage &);
+ void remove_storage(Storage &);
+ const std::vector<Storage *>& storages() const {return m_storages;}
void add_request(Request &);
void remove_request(Request &);
@@ -208,7 +211,7 @@
Flags m_flags;
WareList m_wares; ///< virtual storage with all wares in this Economy
WareList m_workers; ///< virtual storage with all workers in this Economy
- std::vector<Warehouse *> m_warehouses;
+ std::vector<Storage *> m_storages;
RequestList m_requests; ///< requests
SupplyList m_supplies;
=== modified file 'src/economy/idleworkersupply.cc'
--- src/economy/idleworkersupply.cc 2013-07-26 20:19:36 +0000
+++ src/economy/idleworkersupply.cc 2013-08-06 10:09:46 +0000
@@ -25,8 +25,8 @@
#include "logic/player.h"
#include "logic/requirements.h"
#include "logic/soldier.h"
+#include "logic/storage.h"
#include "logic/tribe.h"
-#include "logic/warehouse.h"
#include "logic/worker.h"
#include "wexception.h"
@@ -126,12 +126,12 @@
return m_worker;
}
-void IdleWorkerSupply::send_to_storage(Game & game, Warehouse * wh)
+void IdleWorkerSupply::send_to_storage(Game & game, StorageOwner * storage_owner)
{
assert(!has_storage());
Transfer * t = new Transfer(game, m_worker);
- t->set_destination(*wh);
+ t->set_destination(*storage_owner->get_building());
m_worker.start_task_transfer(game, t);
}
=== modified file 'src/economy/idleworkersupply.h'
--- src/economy/idleworkersupply.h 2013-07-26 20:19:36 +0000
+++ src/economy/idleworkersupply.h 2013-08-06 10:09:46 +0000
@@ -23,6 +23,8 @@
#include "economy/supply.h"
namespace Widelands {
+
+class StorageOwner;
class Worker;
class Economy;
@@ -36,7 +38,7 @@
virtual bool is_active() const throw ();
virtual bool has_storage() const throw ();
virtual void get_ware_type(WareWorker & type, Ware_Index & ware) const;
- virtual void send_to_storage(Game &, Warehouse * wh);
+ virtual void send_to_storage(Game &, StorageOwner * storage_owner);
virtual uint32_t nr_supplies(const Game &, const Request &) const;
virtual WareInstance & launch_item(Game &, const Request &);
=== modified file 'src/economy/portdock.cc'
--- src/economy/portdock.cc 2013-07-26 20:19:36 +0000
+++ src/economy/portdock.cc 2013-08-06 10:09:46 +0000
@@ -488,7 +488,7 @@
// Put all wares from the WaresQueues back into the warehouse
const std::vector<WaresQueue *> & l_expedition_wares = m_warehouse->get_wares_queue_vector();
for (uint8_t i = 0; i < l_expedition_wares.size(); ++i) {
- m_warehouse->insert_wares(l_expedition_wares.at(i)->get_ware(), l_expedition_wares.at(i)->get_filled());
+ m_warehouse->get_storage()->insert_wares(l_expedition_wares.at(i)->get_ware(), l_expedition_wares.at(i)->get_filled());
l_expedition_wares.at(i)->set_filled(0);
l_expedition_wares.at(i)->set_max_fill(0);
}
@@ -501,7 +501,7 @@
} else {
Worker * temp = ew.at(i)->worker;
ew.at(i)->worker = 0;
- m_warehouse->incorporate_worker(game, *temp);
+ m_warehouse->get_storage()->incorporate_worker(game, *temp);
}
}
// Reset expedition workers list
=== modified file 'src/economy/request.cc'
--- src/economy/request.cc 2013-07-26 20:19:36 +0000
+++ src/economy/request.cc 2013-08-06 10:09:46 +0000
@@ -28,8 +28,8 @@
#include "logic/player.h"
#include "logic/productionsite.h"
#include "logic/soldier.h"
+#include "logic/storage.h"
#include "logic/tribe.h"
-#include "logic/warehouse.h"
#include "logic/worker.h"
#include "map_io/widelands_map_map_object_loader.h"
#include "map_io/widelands_map_map_object_saver.h"
@@ -50,22 +50,27 @@
(PlayerImmovable & _target,
Ware_Index const index,
callback_t const cbfn,
- WareWorker const w)
+ WareWorker const w,
+ callback_tranfert_t const transfer_cb)
:
m_type (w),
m_target (_target),
m_target_building (dynamic_cast<Building *>(&_target)),
m_target_productionsite (dynamic_cast<ProductionSite *>(&_target)),
- m_target_warehouse (dynamic_cast<Warehouse *>(&_target)),
+ m_target_storage (nullptr),
m_target_constructionsite (dynamic_cast<ConstructionSite *>(&_target)),
m_economy (_target.get_economy()),
m_index (index),
m_count (1),
m_callbackfn (cbfn),
+ m_transfer_cb (transfer_cb),
m_required_time (_target.owner().egbase().get_gametime()),
m_required_interval(0),
m_last_request_time(m_required_time)
{
+ if (upcast(StorageOwner, storage_owner, &_target)) {
+ m_target_storage = storage_owner->get_storage();
+ }
assert(m_type == wwWARE or m_type == wwWORKER);
if (w == wwWARE and _target.owner().tribe().get_nrwares() <= index)
throw wexception
@@ -354,8 +359,8 @@
modifier = m_target_building->get_priority(get_type(), get_index());
if (m_target_constructionsite)
is_construction_site = true;
- else if (m_target_warehouse)
- // if warehouse calculated a priority use it
+ else if (m_target_storage)
+ // if storage calculated a priority use it
// else lower priority based on cost
return
modifier != 100 ? modifier :
@@ -404,7 +409,7 @@
pri = m_target_building->get_priority(get_type(), get_index());
if (m_target_constructionsite)
return pri + 3;
- else if (m_target_warehouse)
+ else if (m_target_storage)
return pri - 2;
}
return pri;
@@ -486,10 +491,13 @@
Worker & s = supp.launch_worker(game, *this);
ss.Unsigned32(s.serial());
t = new Transfer(game, *this, s);
+ if (m_transfer_cb) {
+ (*m_transfer_cb)(game, *this, m_index, &s, m_target);
+ }
} else {
// Begin the transfer of an item. The item itself is passive.
// launch_item() ensures the WareInstance is transported out of the
- // warehouse. Once it's on the flag, the flag code will decide what to
+ // storage. Once it's on the flag, the flag code will decide what to
// do with it.
WareInstance & item = supp.launch_item(game, *this);
ss.Unsigned32(item.serial());
@@ -533,7 +541,7 @@
*
* Re-open the request.
*/
-void Request::transfer_fail(Game &, Transfer & t) {
+void Request::transfer_fail(Game & game, Transfer & t) {
bool const wasopen = is_open();
t.m_worker = 0;
@@ -541,8 +549,12 @@
remove_transfer(find_transfer(t));
- if (!wasopen)
+ if (!wasopen) {
m_economy->add_request(*this);
+ }
+ if (m_transfer_cb) {
+ m_transfer_cb(game, *this, m_index, nullptr, m_target);
+ }
}
/// Cancel the transfer with the given index.
=== modified file 'src/economy/request.h'
--- src/economy/request.h 2013-07-25 21:05:20 +0000
+++ src/economy/request.h 2013-08-06 10:09:46 +0000
@@ -20,6 +20,8 @@
#ifndef REQUEST_H
#define REQUEST_H
+#include <functional>
+
#include "logic/requirements.h"
#include "logic/wareworker.h"
#include "logic/widelands.h"
@@ -39,11 +41,11 @@
class RequestList;
struct Requirements;
struct Supply;
+class Storage;
struct Transfer;
class Worker;
class Building;
class ProductionSite;
-class Warehouse;
class ConstructionSite;
/**
@@ -63,8 +65,12 @@
typedef void (*callback_t)
(Game &, Request &, Ware_Index, Worker *, PlayerImmovable &);
+ typedef void (*callback_tranfert_t)
+ (Game &, Request &, Ware_Index, Worker *, PlayerImmovable &);
- Request(PlayerImmovable & target, Ware_Index, callback_t, WareWorker);
+ Request
+ (PlayerImmovable & target, Ware_Index, callback_t, WareWorker,
+ callback_tranfert_t transfer_cb = nullptr);
~Request();
PlayerImmovable & target() const throw () {return m_target;}
@@ -120,7 +126,7 @@
// are filled with nulls.
Building * m_target_building;
ProductionSite * m_target_productionsite;
- Warehouse * m_target_warehouse;
+ Storage * m_target_storage;
ConstructionSite * m_target_constructionsite;
Economy * m_economy;
@@ -128,6 +134,7 @@
uint32_t m_count; // how many do we need in total
callback_t m_callbackfn; // called on request success
+ callback_tranfert_t m_transfer_cb; // called on worker transfer start/cancel
// when do we need the first ware (can be in the past)
int32_t m_required_time;
=== modified file 'src/economy/supply.h'
--- src/economy/supply.h 2013-07-26 19:16:51 +0000
+++ src/economy/supply.h 2013-08-06 10:09:46 +0000
@@ -25,10 +25,12 @@
namespace Widelands {
+class StorageOwner;
+
struct PlayerImmovable;
struct Game;
struct Request;
-class Warehouse;
+class StorageOwner;
struct Ware_Index;
class WareInstance;
class Worker;
@@ -77,7 +79,7 @@
* Sets up all the required transfers; assumes that \ref has_storage
* returns \c false.
*/
- virtual void send_to_storage(Game &, Warehouse * wh) = 0;
+ virtual void send_to_storage(Game &, StorageOwner * storage_owner) = 0;
/**
* \return the number of items or workers that can be launched right
=== modified file 'src/economy/transfer.cc'
--- src/economy/transfer.cc 2013-07-26 20:19:36 +0000
+++ src/economy/transfer.cc 2013-08-06 10:09:46 +0000
@@ -191,6 +191,7 @@
Flag & curflag(m_route.get_flag(m_game, 0));
Flag & nextflag(m_route.get_flag(m_game, 1));
if (!curflag.get_road(nextflag)) {
+ //FIXME CGH
upcast(Warehouse, wh, curflag.get_building());
assert(wh);
=== modified file 'src/economy/ware_instance.cc'
--- src/economy/ware_instance.cc 2013-07-26 20:19:36 +0000
+++ src/economy/ware_instance.cc 2013-08-06 10:09:46 +0000
@@ -27,8 +27,8 @@
#include "economy/transfer.h"
#include "logic/game.h"
#include "logic/ship.h"
+#include "logic/storage.h"
#include "logic/tribe.h"
-#include "logic/warehouse.h"
#include "logic/worker.h"
#include "map_io/widelands_map_map_object_loader.h"
#include "map_io/widelands_map_map_object_saver.h"
@@ -54,7 +54,7 @@
virtual bool is_active() const throw ();
virtual bool has_storage() const throw ();
virtual void get_ware_type(WareWorker & type, Ware_Index & ware) const;
- virtual void send_to_storage(Game &, Warehouse * wh);
+ virtual void send_to_storage(Game &, StorageOwner * wh);
virtual uint32_t nr_supplies(const Game &, const Request &) const;
virtual WareInstance & launch_item(Game &, const Request &);
@@ -166,12 +166,12 @@
throw wexception("IdleWareSupply::launch_worker makes no sense");
}
-void IdleWareSupply::send_to_storage(Game & game, Warehouse * wh)
+void IdleWareSupply::send_to_storage(Game & game, StorageOwner * storage_owner)
{
assert(!has_storage());
Transfer * t = new Transfer(game, m_ware);
- t->set_destination(*wh);
+ t->set_destination(*storage_owner->get_building());
m_ware.set_transfer(game, *t);
}
@@ -290,8 +290,8 @@
/**
* Performs the state updates necessary for the current location:
- * - if it's a building, acknowledge the Request or incorporate into warehouse
- * - if it's a flag and we have no request, start the return to warehouse timer
+ * - if it's a building, acknowledge the Request or incorporate into strage
+ * - if it's a flag and we have no request, start the return to storage timer
* and issue a Supply
*
* \note \ref update() may result in the deletion of this object.
@@ -405,22 +405,22 @@
return;
}
- // There are some situations where we might end up in a warehouse
+ // There are some situations where we might end up in a storage
// as part of a requested route, and we need to move out of it
// again, e.g.:
// - we were requested just when we were being carried into the
- // warehouse
+ // storage
// - we were carried into a harbour/warehouse to be
// shipped across the sea, but a better, land-based route has been
// found
- if (upcast(Warehouse, warehouse, &building)) {
- warehouse->do_launch_item(game, *this);
+ if (upcast(StorageOwner, storage_owner, &building)) {
+ storage_owner->get_storage()->do_launch_ware(game, *this);
return;
}
throw wexception
("MO(%u): ware(%s): do not know how to move from building %u (%s at (%u,%u)) "
- "to %u (%s) -> not a warehouse!",
+ "to %u (%s) -> not a storage owner!",
serial(), m_descr->name().c_str(), building.serial(),
building.name().c_str(), building.get_position().x,
building.get_position().y, nextstep->serial(),
=== removed file 'src/economy/warehousesupply.h'
--- src/economy/warehousesupply.h 2013-07-26 20:19:36 +0000
+++ src/economy/warehousesupply.h 1970-01-01 00:00:00 +0000
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2008-2010 by the Widelands Development Team
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef WAREHOUSESUPPLY_H
-#define WAREHOUSESUPPLY_H
-
-#include "logic/warelist.h"
-#include "logic/wareworker.h"
-#include "economy/supply.h"
-
-namespace Widelands {
-
-/*
-WarehouseSupply is the implementation of Supply that is used by Warehouses.
-It also manages the list of wares in the warehouse.
-*/
-struct WarehouseSupply : public Supply {
- WarehouseSupply(Warehouse * const wh) : m_economy(0), m_warehouse(wh) {}
- virtual ~WarehouseSupply();
-
- void set_economy(Economy *);
-
- void set_nrworkers(Ware_Index);
- void set_nrwares (Ware_Index);
-
- const WareList & get_wares () const {return m_wares;}
- const WareList & get_workers() const {return m_workers;}
- uint32_t stock_wares (Ware_Index const i) const {
- return m_wares .stock(i);
- }
- uint32_t stock_workers(Ware_Index const i) const {
- return m_workers.stock(i);
- }
- void add_wares (Ware_Index, uint32_t count);
- void remove_wares (Ware_Index, uint32_t count);
- void add_workers (Ware_Index, uint32_t count);
- void remove_workers(Ware_Index, uint32_t count);
-
- // Supply implementation
- virtual PlayerImmovable * get_position(Game &);
- virtual bool is_active() const throw ();
- virtual bool has_storage() const throw ();
- virtual void get_ware_type(WareWorker & type, Ware_Index & ware) const;
-
- virtual void send_to_storage(Game &, Warehouse * wh);
- virtual uint32_t nr_supplies(const Game &, const Request &) const;
- virtual WareInstance & launch_item(Game &, const Request &);
- virtual Worker & launch_worker(Game &, const Request &);
-
-private:
- Economy * m_economy;
- WareList m_wares;
- WareList m_workers; // we use this to keep the soldiers
- Warehouse * m_warehouse;
-};
-
-}
-
-
-#endif
=== removed file 'src/logic/attackable.h'
--- src/logic/attackable.h 2012-02-15 21:25:34 +0000
+++ src/logic/attackable.h 1970-01-01 00:00:00 +0000
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2008-2009 by the Widelands Development Team
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef ATTACKABLE_H
-#define ATTACKABLE_H
-
-namespace Widelands {
-
-struct Player;
-class Soldier;
-
-enum {
- /**
- * This is the maximum radius that a military building can protect
- * in the sense that an enemy soldier that enters the player's territory
- * will call \ref Attackable::aggressor if it is that close.
- */
- MaxProtectionRadius = 25
-};
-
-/**
- * Buildings can implement this interface to indicate that
- * they can be attacked.
- */
-struct Attackable {
- /**
- * Return the player that owns this attackable.
- */
- virtual Player & owner() const = 0;
-
- /**
- * Determines whether this building can be attacked right now.
- *
- * This should only return false for military sites that have not
- * been occupied yet.
- */
- virtual bool canAttack() = 0;
-
- /**
- * Called by an enemy soldier that enters a node with distance
- * less than or equal to \ref MaxProtectionRadius from the building.
- *
- * This allows the building to send protective forces to intercept
- * the soldier.
- */
- virtual void aggressor(Soldier &) = 0;
-
- /**
- * Called by a soldier who is standing on the building's flag
- * to attack the building.
- *
- * The building must send a soldier for defense, and return \c true.
- * Otherwise, i.e. if the building cannot defend itself anymore,
- * it must destroy itself or turn over to the attacking player,
- * and return \c false.
- *
- * \return \c true if a soldier was launched in defense of the building,
- * or \c false if the building cannot defend itself any longer.
- */
- virtual bool attack(Soldier &) = 0;
-
-protected:
- virtual ~Attackable() {}
-};
-
-}
-
-#endif
=== modified file 'src/logic/building.h'
--- src/logic/building.h 2013-08-02 18:36:03 +0000
+++ src/logic/building.h 2013-08-06 10:09:46 +0000
@@ -258,6 +258,9 @@
void set_defeating_player(Player_Number const player_number) {
m_defeating_player = player_number;
}
+ Player_Number get_defeating_player() {
+ return m_defeating_player;
+ }
void add_worker(Worker &);
void remove_worker(Worker &);
=== modified file 'src/logic/findimmovable.cc'
--- src/logic/findimmovable.cc 2013-07-26 20:19:36 +0000
+++ src/logic/findimmovable.cc 2013-08-06 10:09:46 +0000
@@ -20,7 +20,6 @@
#include "logic/findimmovable.h"
#include "economy/flag.h"
-#include "logic/attackable.h"
#include "logic/immovable.h"
#include "logic/militarysite.h"
#include "upcast.h"
@@ -61,7 +60,8 @@
}
bool FindImmovableAttackable ::accept(const BaseImmovable & imm) const {
- return dynamic_cast<Attackable const *>(&imm);
+ upcast(const GarrisonOwner, go, &imm);
+ return (go && go->get_garrison()->canAttack());
}
bool FindImmovableByDescr::accept(const BaseImmovable & baseimm) const {
=== modified file 'src/logic/game.cc'
--- src/logic/game.cc 2013-07-26 20:19:36 +0000
+++ src/logic/game.cc 2013-08-06 10:09:46 +0000
@@ -792,7 +792,8 @@
(get_gametime(), building.owner().player_number(), building));
}
-void Game::send_player_militarysite_set_soldier_preference (Building & building, uint8_t my_preference)
+void Game::send_player_militarysite_set_soldier_preference
+ (Building & building, Garrison::SoldierPref my_preference)
{
send_player_command
(*new Cmd_MilitarySiteSetSoldierPreference
=== modified file 'src/logic/game.h'
--- src/logic/game.h 2013-07-26 20:19:36 +0000
+++ src/logic/game.h 2013-08-06 10:09:46 +0000
@@ -22,6 +22,7 @@
#include "logic/cmd_queue.h"
#include "logic/editor_game_base.h"
+#include "logic/garrison.h"
#include "md5.h"
#include "random.h"
#include "save_handler.h"
@@ -151,7 +152,7 @@
void send_player_build_road (int32_t, Path &);
void send_player_flagaction (Flag &);
void send_player_start_stop_building (Building &);
- void send_player_militarysite_set_soldier_preference (Building &, uint8_t preference);
+ void send_player_militarysite_set_soldier_preference (Building &, Garrison::SoldierPref preference);
void send_player_start_or_cancel_expedition (Building &);
void send_player_enhance_building (Building &, Building_Index);
=== added file 'src/logic/garrison.h'
--- src/logic/garrison.h 1970-01-01 00:00:00 +0000
+++ src/logic/garrison.h 2013-08-06 10:09:46 +0000
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2008-2009 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GARRISON_H
+#define GARRISON_H
+
+#include <vector>
+
+#include "logic/widelands.h"
+
+namespace Widelands {
+
+
+class Building;
+class Editor_Game_Base;
+class Game;
+struct Player;
+class Soldier;
+
+enum {
+ /**
+ * This is the maximum radius that a military building can protect
+ * in the sense that an enemy soldier that enters the player's territory
+ * will call \ref Attackable::aggressor if it is that close.
+ */
+ MaxProtectionRadius = 25
+};
+
+/**
+ * A garrison represents a bunch of soldiers. Garrisons are owned by GarrisonOwner
+ * buildings. This interface provides various methods to deal with soldier control
+ * and attacks.
+ */
+class Garrison {
+public:
+ enum SoldierPref : uint8_t {
+ None,
+ Rookies,
+ Heroes,
+ };
+ /**
+ * Return the player that owns this attackable.
+ */
+ virtual Player & owner() const = 0;
+
+ /**
+ * Determines whether this building can be attacked right now.
+ *
+ * This should only return false for military sites that have not
+ * been occupied yet, or by passivve garrison such as training sites.
+ */
+ virtual bool canAttack() const = 0;
+
+ /**
+ * Called by an enemy soldier that enters a node with distance
+ * less than or equal to \ref MaxProtectionRadius from the building.
+ *
+ * This allows the building to send protective forces to intercept
+ * the soldier.
+ */
+ virtual void aggressor(Soldier &) = 0;
+
+ /**
+ * Called by a soldier who is standing on the building's flag
+ * to attack the building.
+ *
+ * The building must send a soldier for defense, and return \c true.
+ * Otherwise, i.e. if the building cannot defend itself anymore,
+ * it must destroy itself or turn over to the attacking player,
+ * and return \c false.
+ *
+ * \return \c true if a soldier was launched in defense of the building,
+ * or \c false if the building cannot defend itself any longer.
+ */
+ virtual bool attack(Soldier &) = 0;
+
+ /**
+ * \return a list of soldiers that are currently present in the building.
+ */
+ virtual const std::vector<Soldier *> presentSoldiers() const = 0;
+
+ /**
+ * \return a list of soldiers that are currently stationed in the building.
+ * That is, all soldiers occupying a slot in the garrison.
+ */
+ virtual const std::vector<Soldier *> stationedSoldiers() const = 0;
+
+ /**
+ * \return the minimum number of soldiers that this building can be
+ * configured to hold.
+ */
+ virtual uint32_t minSoldierCapacity() const = 0;
+
+ /**
+ * \return the maximum number of soldiers that this building can be
+ * configured to hold.
+ */
+ virtual uint32_t maxSoldierCapacity() const = 0;
+
+ /**
+ * \return the number of soldiers this building is configured to hold
+ * right now.
+ */
+ virtual uint32_t soldierCapacity() const = 0;
+
+ /**
+ * Sets the capacity for soldiers of this building.
+ *
+ * New soldiers will be requested and old soldiers will be evicted
+ * as necessary.
+ */
+ virtual void setSoldierCapacity(uint32_t capacity) = 0;
+ void changeSoldierCapacity(int32_t const difference) {
+ uint32_t const old_capacity = soldierCapacity();
+ uint32_t const new_capacity =
+ std::min
+ (static_cast<uint32_t>
+ (std::max
+ (static_cast<int32_t>(old_capacity) + difference,
+ static_cast<int32_t>(minSoldierCapacity()))),
+ static_cast<uint32_t>(maxSoldierCapacity()));
+ if (old_capacity != new_capacity)
+ setSoldierCapacity(new_capacity);
+ }
+ /**
+ * Evict the given soldier from the building immediately,
+ * without changing the building's capacity.
+ *
+ * \note This has no effect if the soldier is currently involved in a battle
+ * or otherwise blocked from leaving the building.
+ */
+ virtual void dropSoldier(Soldier &) = 0;
+
+ /**
+ * Add a new soldier into this site. Returns -1 if there is no space
+ * for him, 0 on success
+ */
+ virtual int incorporateSoldier(Editor_Game_Base &, Soldier &) = 0;
+
+ /**
+ * Remove a soldier from the internal list. Most SoldierControls will be
+ * informed by the soldier when it is removed, but WareHouses for example
+ * will not.
+ */
+ virtual int outcorporateSoldier(Editor_Game_Base &, Soldier &) = 0;
+
+ /**
+ * Returns the conquer radius of this garrison
+ */
+ virtual uint32_t conquerRadius() const = 0;
+ /**
+ * Set the soldier preference. Heroes or rookies?
+ */
+ virtual void set_soldier_preference(SoldierPref p) = 0;
+ /**
+ * \return the current soldier preference
+ */
+ virtual SoldierPref get_soldier_preference() const = 0;
+ /**
+ * Try to send the given soldier to attack the fiven target building.
+ * This will fail if the soldier already has a job.
+ */
+ virtual void sendAttacker(Soldier & soldier, Building & target, uint8_t retreat) = 0;
+};
+
+
+/**
+ * A Garrison owner holds a garrison. This interface is to be implemented by
+ * buildings that want to store some soldiers. The GarrionHandler Garrison
+ * implementation may be used as the Garrison provider.
+ */
+class GarrisonOwner {
+public:
+ /**
+ * \return the garrison instance
+ */
+ virtual Garrison* get_garrison() const = 0;
+ /**
+ * @return the building owning the garrison
+ */
+ virtual Building* get_building() = 0;
+ /**
+ * Called when the garrison has been lost. \param defeating is set to the
+ * enemy owner, or this owner if we keep military presence. if \param captured,
+ * the enemy captured the building and a new one must be force built.
+ *
+ * Will not be called by passive garrisons
+ */
+ virtual void garrison_lost(Game & game, Player_Number defeating, bool captured) = 0;
+ /**
+ * Called when the garrison is occupied. You may light up the fire now
+ *
+ * Will not be called by passive garrison
+ */
+ virtual void garrison_occupied() = 0;
+ /**
+ * Called on the new site when a site has been conquered
+ *
+ * Will not be called by passive garrison
+ */
+ virtual void reinit_after_conqueral(Game & game) = 0;
+};
+
+}
+
+#endif
=== added file 'src/logic/garrisonhandler.cc'
--- src/logic/garrisonhandler.cc 1970-01-01 00:00:00 +0000
+++ src/logic/garrisonhandler.cc 2013-08-06 10:09:46 +0000
@@ -0,0 +1,869 @@
+/*
+* Copyright (C) 2002-2004, 2006-2011 by the Widelands Development Team
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*/
+
+#include "logic/garrisonhandler.h"
+
+#include <functional>
+#include <memory>
+#include <vector>
+
+#include <boost/foreach.hpp>
+#include <boost/format.hpp>
+
+#include "container_iterate.h"
+#include "economy/flag.h"
+#include "economy/request.h"
+#include "log.h"
+#include "logic/building.h"
+#include "logic/findbob.h"
+#include "logic/instances.h"
+#include "logic/militarysite.h"
+#include "logic/player.h"
+#include "logic/soldier.h"
+#include "upcast.h"
+
+namespace Widelands {
+
+GarrisonHandler::GarrisonHandler
+ (Building& building, uint32_t min_soldiers, uint32_t max_soldiers, uint32_t conquer_radius,
+ uint32_t heal_per_second, SoldierPref soldier_pref, bool passive)
+: Garrison(),
+m_building(building),
+m_min_capacity(min_soldiers),
+m_max_capacity(max_soldiers),
+m_capacity(max_soldiers),
+m_passive(passive),
+m_heal_per_second(heal_per_second),
+m_last_heal_time(0),
+m_conquer_radius(conquer_radius),
+m_didconquer(false),
+m_soldier_preference(soldier_pref),
+m_last_swap_soldiers_time(0),
+m_try_soldier_upgrade(false),
+m_doing_upgrade_request(false)
+{
+ assert(is_a(GarrisonOwner, &m_building));
+}
+
+GarrisonHandler::~GarrisonHandler()
+{
+ assert(m_normal_soldier_request.get() == nullptr);
+ assert(m_upgrade_soldier_request.get() == nullptr);
+}
+
+void GarrisonHandler::init(Editor_Game_Base & egbase)
+{
+ // Ensure all soldiers are fresh and give them a new task
+ upcast(Game, game, &egbase);
+ container_iterate_const(std::vector<Worker *>, m_building.get_workers(), i) {
+ if (upcast(Soldier, soldier, *i.current)) {
+ soldier->set_location_initially(m_building);
+ assert(!soldier->get_state()); // Should be newly created.
+ if (game) {
+ soldier->start_task_buildingwork(*game);
+ }
+ }
+ }
+ // Update requests and timers
+ update_soldier_request();
+ m_last_heal_time = egbase.get_gametime();
+}
+
+void GarrisonHandler::reinit_after_conqueral(Game& game)
+{
+ m_soldier_requirements = Requirements();
+ conquer_area(game);
+ update_soldier_request();
+}
+
+void GarrisonHandler::cleanup(Editor_Game_Base& egbase)
+{
+ if (m_didconquer && !m_passive) {
+ egbase.unconquer_area
+ (Player_Area<Area<FCoords> >
+ (owner().player_number(),
+ Area<FCoords>(egbase.map().get_fcoords(m_building.get_position()), m_conquer_radius)),
+ m_building.get_defeating_player());
+ }
+}
+
+void GarrisonHandler::cleanup_requests(Editor_Game_Base&)
+{
+ m_normal_soldier_request.reset();
+ m_upgrade_soldier_request.reset();
+}
+
+
+void GarrisonHandler::act(Game& game)
+{
+ const int32_t timeofgame = game.get_gametime();
+ // Ensure requests integrity
+ if (m_normal_soldier_request && m_upgrade_soldier_request)
+ {
+ throw wexception("GarrisonHandler::act: Two soldier requests are ongoing -- should never happen!\n");
+ }
+ // Update requests periodically
+ bool full = stationedSoldiers().size() >= m_capacity;
+ if (!full && !m_doing_upgrade_request && !m_normal_soldier_request) {
+ // if we miss soldiers
+ update_soldier_request();
+ } else {
+ // If we may issue a new upgrade request
+ int32_t time_since_last_swap = (timeofgame - m_last_swap_soldiers_time);
+ if (time_since_last_swap > GARRISON_SWAP_TIMEOUT) {
+ time_since_last_swap = timeofgame;
+ update_soldier_request();
+ }
+ }
+
+ // Calculate the amount of heal point to distribute
+ uint32_t to_heal_amount = static_cast<uint32_t>
+ ((timeofgame - m_last_heal_time) * m_heal_per_second / 1000);
+ const std::vector<Soldier*> soldiers = presentSoldiers();
+ BOOST_FOREACH(Soldier* soldier, soldiers) {
+ uint32_t to_heal = soldier->get_max_hitpoints() - soldier->get_current_hitpoints();
+ if (to_heal > to_heal_amount) to_heal = to_heal_amount;
+ if (to_heal > 0) {
+ soldier->heal(to_heal);
+ to_heal_amount -= to_heal;
+ }
+ if (to_heal_amount <= 0) break;
+ }
+ m_last_heal_time = timeofgame;
+}
+
+void GarrisonHandler::popSoldier(Soldier* soldier)
+{
+ // Pop the soldier and update requests
+ popSoldierJob(soldier, nullptr, nullptr);
+ update_soldier_request();
+}
+
+void GarrisonHandler::set_economy(Economy * const e)
+{
+ // update requests
+ if (m_normal_soldier_request && e)
+ m_normal_soldier_request->set_economy(e);
+ if (m_upgrade_soldier_request && e)
+ m_upgrade_soldier_request->set_economy(e);
+}
+
+bool GarrisonHandler::get_garrison_work(Game& game, Soldier* soldier)
+{
+ // Evict soldiers that have returned home if the capacity is too low
+ if (m_capacity < stationedSoldiers().size()) {
+ soldier->reset_tasks(game);
+ soldier->start_task_leavebuilding(game, true);
+ return true;
+ }
+
+ bool stayhome;
+ uint8_t retreat;
+ if (Map_Object* enemy = popSoldierJob(soldier, &stayhome, &retreat)) {
+ if (upcast(Building, building, enemy)) {
+ soldier->start_task_attack(game, *building, retreat);
+ return true;
+ } else if (upcast(Soldier, opponent, enemy)) {
+ if (!opponent->getBattle()) {
+ soldier->start_task_defense(game, stayhome, retreat);
+ if (stayhome)
+ opponent->send_signal(game, "sleep");
+ return true;
+ }
+ } else
+ throw wexception("GarrisonHandler::get_garrison_work: bad SoldierJob");
+ }
+ return false;
+}
+
+void GarrisonHandler::set_soldier_requirements(Requirements req)
+{
+ m_soldier_requirements = req;
+}
+
+//
+// Garrison implementation
+//
+
+Player& GarrisonHandler::owner() const
+{
+ return m_building.owner();
+}
+
+bool GarrisonHandler::canAttack() const
+{
+ return m_didconquer && !m_passive;
+}
+
+void GarrisonHandler::aggressor(Soldier& enemy)
+{
+ Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
+ Map & map = game.map();
+ // Do not react if enemy is occupied or too far away
+ if
+ (enemy.get_owner() == &owner() || enemy.getBattle()
+ || m_conquer_radius <= map.calc_distance
+ (enemy.get_position(), m_building.get_position()))
+ {
+ return;
+ }
+
+ // Do not react if enemy is at our door
+ if
+ (map.find_bobs
+ (Area<FCoords>(map.get_fcoords(m_building.base_flag().get_position()), 2), 0,
+ FindBobEnemySoldier(&owner())))
+ {
+ return;
+ }
+
+ // Send some soldiers to defend, keeping min capacity inside
+ // This will send 1 soldier out to defend each time agressor()
+ // is called //FIXME?
+ const std::vector<Soldier*>& presents = presentSoldiers();
+ if (presents.size() > m_min_capacity) {
+ container_iterate_const(std::vector<Soldier *>, presents, i) {
+ if (!haveSoldierJob(**i.current)) {
+ SoldierJob sj;
+ sj.soldier = *i.current;
+ sj.enemy = &enemy;
+ sj.stayhome = false;
+ sj.retreat = owner().get_retreat_percentage();
+ m_soldierjobs.push_back(sj);
+ (*i.current)->update_task_buildingwork(game);
+ return;
+ }
+ }
+ }
+
+ // Inform the player, that we are under attack by adding a new entry to the
+ // message queue - a sound will automatically be played.
+ inform_owner(game, InfoType::AGGRESSSED);
+}
+
+bool GarrisonHandler::attack(Soldier& enemy)
+{
+ Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
+
+ const std::vector<Soldier*>& present = presentSoldiers();
+ Soldier * defender = 0;
+
+ if (!present.empty()) {
+ // Find soldier with greatest hitpoints
+ uint32_t current_max = 0;
+ container_iterate_const(std::vector<Soldier *>, present, i) {
+ if ((*i.current)->get_current_hitpoints() > current_max) {
+ defender = *i.current;
+ current_max = defender->get_current_hitpoints();
+ }
+ }
+ } else {
+ // If one of our stationed soldiers is currently walking into the
+ // building, give us another chance.
+ const std::vector<Soldier *>& stationed = stationedSoldiers();
+ container_iterate_const(std::vector<Soldier *>, stationed, i) {
+ if ((*i.current)->get_position() == m_building.get_position()) {
+ defender = *i.current;
+ break;
+ }
+ }
+ }
+
+ if (defender) {
+ popSoldierJob(defender); // defense overrides all other jobs
+
+ SoldierJob sj;
+ sj.soldier = defender;
+ sj.enemy = &enemy;
+ sj.stayhome = true;
+ sj.retreat = 0; // Flag defenders could not retreat
+ m_soldierjobs.push_back(sj);
+
+ defender->update_task_buildingwork(game);
+
+ // Inform the player, that we are under attack by adding a new entry to
+ // the message queue - a sound will automatically be played.
+ inform_owner(game, InfoType::UNDER_ATTACK);
+ return true;
+ }
+
+ // The enemy has defeated our forces, we should inform the player
+ // Code for handling change of owner are handled in the garrison
+ // owner class.
+ upcast(GarrisonOwner, go, &m_building);
+ if (military_presence_kept(game)) {
+ inform_owner(game, InfoType::GARRISON_LOST);
+ go->garrison_lost(game, owner().player_number(), false);
+ } else {
+ inform_owner(game, InfoType::GARRISON_CAPTURED);
+ go->garrison_lost(game, enemy.owner().player_number(), true);
+ }
+ return false;
+}
+
+const std::vector< Soldier* > GarrisonHandler::presentSoldiers() const
+{
+ std::vector<Soldier *> present_soldiers;
+ container_iterate_const(std::vector<Worker*>, m_building.get_workers(), i) {
+ if (upcast(Soldier, s, *i.current)) {
+ if (isPresent(*s)) {
+ present_soldiers.push_back(s);
+ }
+ }
+ }
+ return present_soldiers;
+}
+
+const std::vector< Soldier* > GarrisonHandler::stationedSoldiers() const
+{
+ std::vector<Soldier *> soldiers;
+ container_iterate_const(std::vector<Worker*>, m_building.get_workers(), i) {
+ if (upcast(Soldier, s, *i.current)) {
+ soldiers.push_back(s);
+ }
+ }
+ return soldiers;
+}
+
+uint32_t GarrisonHandler::minSoldierCapacity() const
+{
+ return m_min_capacity;
+}
+
+uint32_t GarrisonHandler::maxSoldierCapacity() const
+{
+ return m_max_capacity;
+}
+
+uint32_t GarrisonHandler::soldierCapacity() const
+{
+ return m_capacity;
+}
+
+void GarrisonHandler::setSoldierCapacity(uint32_t capacity)
+{
+ assert(minSoldierCapacity() <= capacity);
+ assert (capacity <= maxSoldierCapacity());
+ assert(m_capacity != capacity);
+ m_capacity = capacity;
+ update_soldier_request();
+}
+
+void GarrisonHandler::dropSoldier(Soldier& soldier)
+{
+ Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
+
+ if (!isPresent(soldier)) {
+ // This can happen when the "drop soldier" player command is delayed
+ // by network delay or a client has bugs.
+ return;
+ }
+ // Ensure min capacity is respected
+ if (presentSoldiers().size() <= minSoldierCapacity()) {
+ return;
+ }
+ // Drop the soldier and update requests
+ soldier.reset_tasks(game);
+ soldier.start_task_leavebuilding(game, true);
+ update_soldier_request();
+}
+
+int GarrisonHandler::incorporateSoldier(Editor_Game_Base& egbase, Soldier& s)
+{
+ // Adjust the soldier location if required.
+ if (s.get_location(egbase) != &m_building)
+ {
+ s.set_location(&m_building);
+ }
+
+ upcast(Game, game, &egbase);
+ // If it's the first soldier, conquer the area
+ if (!m_passive && !m_didconquer) {
+ conquer_area(egbase);
+ if (game) {
+ inform_owner(*game, InfoType::GARRISON_OCCUPIED);
+ }
+ upcast(GarrisonOwner, go, &m_building);
+ go->garrison_occupied();
+ }
+
+ // Bind the worker into this house, hide him on the map
+ if (game) {
+ s.reset_tasks(*game);
+ if (m_passive) {
+ s.start_task_idle(*game, 0, -1);
+ } else {
+ s.start_task_buildingwork(*game);
+ }
+ }
+ // Make sure the request count is reduced or the request is deleted.
+ update_soldier_request();
+ return 0;
+}
+
+int GarrisonHandler::outcorporateSoldier(Editor_Game_Base&, Soldier&)
+{
+ // not needed
+ log("CGH Outcorporate called\n");
+ return -1;
+}
+
+uint32_t GarrisonHandler::conquerRadius() const
+{
+ return m_conquer_radius;
+}
+
+void GarrisonHandler::set_soldier_preference(GarrisonHandler::SoldierPref p)
+{
+ assert(SoldierPref::Heroes == p || SoldierPref::Rookies == p);
+ m_soldier_preference = p;
+ update_normal_soldier_request();
+}
+
+
+void GarrisonHandler::sendAttacker(Soldier& soldier, Building& target, uint8_t retreat)
+{
+ assert(isPresent(soldier));
+
+ if (haveSoldierJob(soldier)) {
+ return;
+ }
+
+ SoldierJob sj;
+ sj.soldier = &soldier;
+ sj.enemy = ⌖
+ sj.stayhome = false;
+ sj.retreat = retreat;
+ m_soldierjobs.push_back(sj);
+
+ soldier.update_task_buildingwork(ref_cast<Game, Editor_Game_Base>(owner().egbase()));
+}
+
+//
+// Private helper methods
+//
+void GarrisonHandler::inform_owner(Game& game, GarrisonHandler::InfoType info)
+{
+ if (m_passive) {
+ return;
+ }
+ std::string message;
+ std::string message_id;
+ std::string message_title;
+ std::string building_name = m_building.descname();
+ switch (info) {
+ case InfoType::AGGRESSSED:
+ message =
+ (boost::format
+ (_("Your %s discovered an aggressor")) % building_name)
+ .str();
+ message_id = "under_attack";
+ message_title = _("You are under attack");
+ break;
+ case InfoType::UNDER_ATTACK:
+ message =
+ (boost::format
+ (_("Your %s is under attack")) % building_name)
+ .str();
+ message_id = "under_attack";
+ message_title = _("You are under attack");
+ break;
+ case InfoType::GARRISON_LOST:
+ message =
+ (boost::format
+ (_("The enemy defeated your soldiers and destroyed your %s")) % building_name)
+ .str();
+ message_id = "garrison_lost";
+ message_title = _("Garrison lost");
+ break;
+ case InfoType::GARRISON_CAPTURED:
+ message =
+ (boost::format
+ (_("The enemy defeated your soldiers and captured your %s")) % building_name)
+ .str();
+ message_id = "garrison_lost";
+ message_title = _("Garrison captured");
+ break;
+ case InfoType::GARRISON_OCCUPIED:
+ message =
+ (boost::format
+ (_("Your soldier occupied your %s")) % building_name)
+ .str();
+ message_id = "garrison_occupied";
+ message_title = _("Garrison occupied");
+ break;
+ default:
+ assert(false);
+ }
+ m_building.send_message(game, message_id, message_title, message);
+}
+
+bool GarrisonHandler::isPresent(Soldier& soldier) const
+{
+ if
+ (soldier.get_location(owner().egbase()) != &m_building
+ || soldier.get_position() != m_building.get_position())
+ {
+ return false;
+ }
+ // Present soldiers are working for the garrison only if it is not passive
+ if (!m_passive) {
+ return
+ soldier.get_state() == soldier.get_state(Worker::taskBuildingwork);
+ }
+ return true;
+}
+
+void GarrisonHandler::conquer_area(Editor_Game_Base& egbase)
+{
+ assert(!m_didconquer);
+ egbase.conquer_area
+ (Player_Area<Area<FCoords> >
+ (owner().player_number(),
+ Area<FCoords>
+ (egbase.map().get_fcoords(m_building.get_position()), m_conquer_radius)));
+ m_didconquer = true;
+}
+
+bool GarrisonHandler::military_presence_kept(Game& game)
+{
+ // collect information about immovables in the area
+ std::vector<ImmovableFound> immovables;
+
+ // Search in a radius of 3 (needed for big militarysites)
+ FCoords const fc = game.map().get_fcoords(m_building.get_position());
+ game.map().find_immovables(Area<FCoords>(fc, 3), &immovables);
+
+ for (uint32_t i = 0; i < immovables.size(); ++i) {
+ upcast(GarrisonOwner, go, immovables[i].object);
+ if (!go) {
+ continue;
+ }
+ Garrison* g = go->get_garrison();
+ upcast(GarrisonOwner, mygo, &m_building);
+ // NOCOM I changed the logic here to check for any stationed soldier
+ // and not for m_didconquer. So a msite with all slots empty and soldiers
+ // on their way won't keep military presence anymore.
+
+ // Presence kept if any non-empty garrison with higher conquer radius
+ // and owned by our owner is nearby
+ if
+ (mygo != go
+ && owner().player_number() == g->owner().player_number()
+ && conquerRadius() < g->conquerRadius()
+ && !g->stationedSoldiers().empty())
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+//FIXME CGH use a cleaner way without polling required
+void GarrisonHandler::update_soldier_request(bool upgraded_in)
+{
+/*
+ * I have update_soldier_request
+ * update_upgrade_soldier_request
+ * update_normal_soldier_request
+ *
+ * The first one handles state switching between site fill (normal more)
+ * and grabbing soldiers with proper training (upgrade mode). The last
+ * two actually make the requests.
+ *
+ * The input parameter incd is true, if we just incorporated a new soldier
+ * as a result of an upgrade request. In such cases, we will re-arm the
+ * upgrade request.
+ */
+ const uint32_t capacity = soldierCapacity();
+ const uint32_t stationed = stationedSoldiers().size();
+
+ if (m_doing_upgrade_request) {
+ if (upgraded_in && m_upgrade_soldier_request) {// update requests always ask for one soldier at time!
+ m_upgrade_soldier_request.reset();
+ }
+ if (capacity > stationed) {
+ // Somebody is killing my soldiers in the middle of upgrade
+ // or I have kicked out his predecessor already.
+ if
+ ((m_upgrade_soldier_request)
+ && (m_upgrade_soldier_request->is_open() || 0 == m_upgrade_soldier_request->get_count()))
+ {
+ // Economy was not able to find the soldiers I need.
+ // I can safely drop the upgrade request and go to fill mode.
+ m_upgrade_soldier_request.reset();
+ }
+ if (!m_upgrade_soldier_request) {
+ //phoo -- I can safely request new soldiers.
+ m_doing_upgrade_request = false;
+ update_normal_soldier_request();
+ }
+ // else -- ohno please help me! Player is in trouble -- evil grin
+ // An upgraded soldier is on his way, but since we only make one request
+ // at a time, we have to wait for him to arrive before doing another
+ // request to fill capacity.
+ //FIXME
+ } else if (capacity < stationed) {// player is reducing capacity
+ drop_least_suited_soldier();
+ } else {// capacity == stationed size
+ update_upgrade_soldier_request();
+ }
+ } else {// not doing upgrade request
+ if ((capacity != stationed) or (m_normal_soldier_request)) {
+ update_normal_soldier_request();
+ }
+ if ((capacity == stationed) && (! m_normal_soldier_request) && !m_passive) {
+ // Our site is full, we might try to get upgraded soldiers
+ // TODO not allowed for passive garrison for now
+ if (presentSoldiers().size() == capacity && capacity > m_min_capacity) {
+ m_doing_upgrade_request = true;
+ }
+ }
+ }
+}
+
+void GarrisonHandler::update_normal_soldier_request()
+{
+ // Request new soldiers if needed
+ std::vector<Soldier*> soldiers = stationedSoldiers();
+ if (soldiers.size() < m_capacity) {
+ if (!m_normal_soldier_request) {
+ // No ongoing request, fill a new one
+ Request* r = new Request
+ (m_building, m_building.tribe().safe_worker_index("soldier"),
+ GarrisonHandler::request_soldier_callback, wwWORKER);
+ r->set_requirements(m_soldier_requirements);
+ m_normal_soldier_request.reset(r);
+ }
+ // Already an ongoing request, update counts
+ m_normal_soldier_request->set_count(m_capacity - soldiers.size());
+ } else {
+ // No new soldier required. Destroy request if there is one
+ m_normal_soldier_request.reset();
+ }
+ // Evict present soldiers if required
+ const std::vector<Soldier *>& present = presentSoldiers();
+ if (present.size() > m_capacity) {
+ Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
+ for (uint32_t i = 0; i < present.size() - m_capacity; ++i) {
+ Soldier & soldier = *present[i];
+ soldier.reset_tasks(game);
+ soldier.start_task_leavebuilding(game, true);
+ }
+ }
+}
+
+void GarrisonHandler::update_upgrade_soldier_request()
+{
+ bool reqirement_changed = update_upgrade_requirements();
+ // Update the requirements
+ if (!m_try_soldier_upgrade) {
+ return;
+ }
+ // Do not perform a new request if someone is on his way
+ // or if we are going to request the same thing
+ if (m_upgrade_soldier_request) {
+ if (!m_upgrade_soldier_request->is_open()) {
+ // upgraded soldier is on his way
+ return;
+ }
+ if (!reqirement_changed && m_upgrade_soldier_request->get_count() > 0) {
+ // Current request is still valid
+ return;
+ }
+ }
+ // Issue a new request
+ Request* r = new Request
+ (m_building, m_building.tribe().safe_worker_index("soldier"),
+ GarrisonHandler::request_soldier_callback, wwWORKER,
+ GarrisonHandler::request_soldier_transfer_callback);
+ // Honor soldier requirements if set by the garrison owner
+ RequireAnd upgrade_requirement;
+ upgrade_requirement.add(m_soldier_requirements);
+ upgrade_requirement.add(m_soldier_upgrade_requirements);
+ r->set_requirements(upgrade_requirement);
+ r->set_count(1);
+ m_upgrade_soldier_request.reset(r);
+}
+
+void GarrisonHandler::request_soldier_callback
+ (Game& game, Request&, Ware_Index, Worker* w, PlayerImmovable& pi)
+{
+ Soldier& s = ref_cast<Soldier, Worker>(*w);
+ upcast(GarrisonOwner, go, &pi);
+ upcast(GarrisonHandler, gh, go->get_garrison());
+
+ if (!gh->m_doing_upgrade_request) {
+ gh->incorporateSoldier(game, s);
+ } else {
+ gh->incorporateUpgradedSoldier(game, s);
+ }
+}
+
+void GarrisonHandler::request_soldier_transfer_callback
+ (Game&, Request&, Ware_Index, Worker* w, PlayerImmovable& pi)
+{
+ Soldier& s = ref_cast<Soldier, Worker>(*w);
+ upcast(GarrisonOwner, go, &pi);
+ upcast(GarrisonHandler, gh, go->get_garrison());
+
+ if (!gh->m_doing_upgrade_request) {
+ gh->drop_least_suited_soldier(&s);
+ }
+}
+
+bool GarrisonHandler::update_upgrade_requirements()
+{
+ int32_t soldier_upgrade_required_min = m_soldier_upgrade_requirements.getMin();
+ int32_t soldier_upgrade_required_max = m_soldier_upgrade_requirements.getMax();
+
+ if
+ (SoldierPref::Heroes != m_soldier_preference
+ && SoldierPref::Rookies != m_soldier_preference)
+ {
+ m_try_soldier_upgrade = false;
+ return false;
+ }
+
+ // Find the level of the soldier that is currently least-suited.
+ Soldier * worst_guy = find_least_suited_soldier();
+ if (worst_guy == nullptr) {
+ // There could be no soldier in the militarysite right now. No reason to freak out.
+ return false;
+ }
+ int32_t wg_level = worst_guy->get_level(atrTotal);
+
+ // Micro-optimization: I assume that the majority of military sites have only level-zero
+ // soldiers and prefer rookies. Handle them separately.
+ if (m_soldier_preference == SoldierPref::Rookies && wg_level == 0) {
+ m_try_soldier_upgrade = false;
+ return false;
+ }
+ m_try_soldier_upgrade = true;
+
+ // Now I actually build the new requirements.
+ int32_t reqmin = SoldierPref::Heroes == m_soldier_preference ? 1 + wg_level : 0;
+ int32_t reqmax = SoldierPref::Heroes == m_soldier_preference ? SHRT_MAX : wg_level - 1;
+
+ bool maxchanged = reqmax != soldier_upgrade_required_max;
+ bool minchanged = reqmin != soldier_upgrade_required_min;
+
+ if (maxchanged or minchanged) {
+ m_soldier_upgrade_requirements = RequireAttribute(atrTotal, reqmin, reqmax);
+ return true;
+ }
+ return false;
+}
+
+bool GarrisonHandler::incorporateUpgradedSoldier(Editor_Game_Base& egbase, Soldier& s)
+{
+ // Call to drop_least routine has side effects: it tries to drop a soldier. Order is important!
+ assert(isPresent(s));
+ std::vector<Soldier*> stationned = stationedSoldiers();
+ if (stationned.size() <= m_capacity || drop_least_suited_soldier(&s)) {
+ Game & game = ref_cast<Game, Editor_Game_Base>(egbase);
+ s.set_location(&m_building);
+ s.reset_tasks(game);
+ if (!m_passive) {
+ s.start_task_buildingwork(game);
+ } else {
+ s.start_task_idle(game, 0, -1);
+ }
+ // Reset timer for new request
+ m_upgrade_soldier_request.reset();
+ m_last_swap_soldiers_time = game.get_gametime();
+ return true;
+ }
+ return false;
+}
+
+Soldier* GarrisonHandler::find_least_suited_soldier()
+{
+ const std::vector<Soldier *>& present = presentSoldiers();
+ const int32_t multiplier = m_soldier_preference == SoldierPref::Heroes ? -1 : 1;
+ int worst_soldier_level = INT_MIN;
+ Soldier * worst_soldier = nullptr;
+ BOOST_FOREACH(Soldier * sld, present)
+ {
+ int this_soldier_level = multiplier * static_cast<int> (sld->get_level(atrTotal));
+ if (this_soldier_level > worst_soldier_level)
+ {
+ worst_soldier_level = this_soldier_level;
+ worst_soldier = sld;
+ }
+ }
+ return worst_soldier;
+}
+
+bool GarrisonHandler::drop_least_suited_soldier(Soldier* newguy)
+{
+ const std::vector<Soldier *>& present = presentSoldiers();
+ // Don't drop under the minimum capacity if new guy is not here yet
+ if (newguy == nullptr && present.size() <= m_min_capacity) {
+ return false;
+ }
+ Soldier * kickoutCandidate = find_least_suited_soldier();
+
+ // If the arriving guy is worse than worst present, I wont't release.
+ if (newguy != nullptr && kickoutCandidate != nullptr) {
+ int32_t old_level = kickoutCandidate->get_level(atrTotal);
+ int32_t new_level = newguy->get_level(atrTotal);
+ if (m_soldier_preference == SoldierPref::Heroes && old_level >= new_level) {
+ return false;
+ } else if (m_soldier_preference == SoldierPref::Rookies && old_level <= new_level) {
+ return false;
+ }
+ }
+
+ // Now I know that the new guy is worthy.
+ if (kickoutCandidate != nullptr) {
+ Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
+ kickoutCandidate->reset_tasks(game);
+ kickoutCandidate->start_task_leavebuilding(game, true);
+ return true;
+ }
+ return false;
+}
+
+bool GarrisonHandler::haveSoldierJob(Soldier& soldier) const
+{
+ container_iterate_const(std::vector<SoldierJob>, m_soldierjobs, i) {
+ if (i.current->soldier == &soldier) {
+ return true;
+ }
+ }
+ return false;
+}
+
+Map_Object* GarrisonHandler::popSoldierJob(Soldier* soldier, bool* stayhome, uint8_t* retreat)
+{
+ container_iterate(std::vector<SoldierJob>, m_soldierjobs, i)
+ if (i.current->soldier == soldier) {
+ Map_Object * const enemy = i.current->enemy.get(owner().egbase());
+ if (stayhome)
+ *stayhome = i.current->stayhome;
+ if (retreat)
+ *retreat = i.current->retreat;
+ m_soldierjobs.erase(i.current);
+ return enemy;
+ }
+ return 0;
+}
+
+}
=== added file 'src/logic/garrisonhandler.h'
--- src/logic/garrisonhandler.h 1970-01-01 00:00:00 +0000
+++ src/logic/garrisonhandler.h 2013-08-06 10:09:46 +0000
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2002-2004, 2006-2011 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GARRISON_HANDLER_H
+#define GARRISON_HANDLER_H
+
+#include "logic/instances.h"
+#include "logic/garrison.h"
+#include "logic/requirements.h"
+#include "logic/worker.h"
+
+namespace Widelands {
+
+struct Building;
+struct Request;
+class Soldier;
+
+#define GARRISON_SWAP_TIMEOUT 20000
+/**
+ * Implementation of the Garrison interface to used by GarrisonOwner.
+ */
+class GarrisonHandler : public Garrison {
+friend struct Map_Buildingdata_Data_Packet;
+public:
+ /**
+ * Create a new garrison handler
+ * \param building The building that holds this garrison. Must implements GarrisonOwner
+ * \param min_soldiers The minimum soldiers to be present in the garrison
+ * \param max_soldiers The maximum soldiers that can be present in this garrison
+ * \param conquer_radius The radius of the area conqered by this garrison
+ * \param heal_per_second The speed at which soldiers will be healed
+ * \param soldier_pref The soldier preference for rookies or heroes
+ * \param passive A passive garrison is only helpful to keep some soldiers around. It can't
+ * attack nor be attacked. I think of training site or ships
+ */
+ GarrisonHandler
+ (Building& building, uint32_t min_soldiers, uint32_t max_soldiers,
+ uint32_t conquer_radius, uint32_t heal_per_second, SoldierPref soldier_pref,
+ bool passive = false);
+ virtual ~GarrisonHandler();
+
+ /**
+ * Must be called once
+ */
+ void init(Editor_Game_Base &);
+ /**
+ * Must be called once after conqueral
+ */
+ void reinit_after_conqueral(Game & game);
+ /**
+ * Cleanup handled objects
+ */
+ void cleanup(Editor_Game_Base &);
+ /**
+ * Eequests must be cleaned up after the building has
+ * been cleaned up, hence this seperate function.
+ */
+ void cleanup_requests(Editor_Game_Base &);
+ /**
+ * Must be called regularly. It is not time dependant though.
+ */
+ void act(Game &);
+ /**
+ * Must be called when the owner building changes economy
+ */
+ void set_economy(Economy * const e);
+ /**
+ * Pop the given soldier out of the building, while keeping it
+ * in the garrion.
+ */
+ void popSoldier(Soldier* soldier);
+ /**
+ * Get some work for a soldier that asks for it
+ */
+ bool get_garrison_work(Game & game, Soldier* soldier);
+ /**
+ * Set the requirements for that soldier. This will be used when filling
+ * request for soldiers.
+ */
+ void set_soldier_requirements(Requirements req);
+
+ // Garrison implementation
+ virtual Player & owner() const;
+ virtual bool canAttack() const;
+ virtual void aggressor(Soldier &);
+ virtual bool attack(Soldier &);
+ virtual const std::vector<Soldier *> presentSoldiers() const;
+ virtual const std::vector<Soldier *> stationedSoldiers() const;
+ virtual uint32_t minSoldierCapacity() const;
+ virtual uint32_t maxSoldierCapacity() const;
+ virtual uint32_t soldierCapacity() const;
+ virtual void setSoldierCapacity(uint32_t capacity);
+ virtual void dropSoldier(Soldier &);
+ virtual int incorporateSoldier(Editor_Game_Base &, Soldier &);
+ virtual int outcorporateSoldier(Editor_Game_Base &, Soldier &);
+ virtual uint32_t conquerRadius() const;
+ virtual void set_soldier_preference(SoldierPref p);
+ virtual SoldierPref get_soldier_preference() const {
+ return m_soldier_preference;
+ }
+ virtual void sendAttacker(Soldier & soldier, Building & target, uint8_t retreat);
+
+
+private:
+ enum class InfoType : uint8_t {
+ AGGRESSSED,
+ UNDER_ATTACK,
+ GARRISON_LOST,
+ GARRISON_CAPTURED,
+ GARRISON_OCCUPIED
+ };
+ // Helper methods
+ /**
+ * Sends a message to the owner
+ */
+ void inform_owner(Game&, InfoType);
+ /**
+ * Check if a soldier is actually present in building
+ */
+ bool isPresent(Soldier &) const;
+ /**
+ * Conquers the area once a soldier occupied the site
+ */
+ void conquer_area(Editor_Game_Base &);
+ /**
+ * Check if we keep military influence once our garrison
+ * has been conquered
+ */
+ bool military_presence_kept(Game &);
+ /**
+ * Update the soldier requests. If upgraded_incorporated, a soldier
+ * requested by an upgrade request has just been incorporated. This
+ * method handle requesting for normal case (filling slots) or for
+ * upgrading to a better suited soldier
+ */
+ void update_soldier_request(bool upgraded_incorporated = false);
+ /**
+ * Request new soldiers or evict some to fill the capacity
+ */
+ void update_normal_soldier_request();
+ /* There are two kinds of soldier requests: "normal", which is used whenever the military site needs
+ * more soldiers, and "upgrade" which is used when there is a preference for either heroes or
+ * rookies.
+ *
+ * In case of normal requests, the military site is filled. In case of upgrade requests, only one guy
+ * is exchanged at a time.
+ *
+ * There would be more efficient ways to get well trained soldiers. Now, new buildings appearing in battle
+ * field are more vulnerable at the beginning. This is intentional. The purpose of this upgrade thing is
+ * to reduce the benefits of site micromanagement. The intention is not to make gameplay easier
+ * in other ways.
+ */
+ void update_upgrade_soldier_request();
+ /**
+ * The callback function, called whenever one of our soldier requested arrived
+ */
+ static void request_soldier_callback
+ (Game &, Request &, Ware_Index, Worker *, PlayerImmovable &);
+ /**
+ * The transfer callback function, called whenever one of our requested
+ * soldier started to move towards the garrison
+ */
+ static void request_soldier_transfer_callback
+ (Game &, Request &, Ware_Index, Worker *, PlayerImmovable &);
+ /*
+ * When upgrading soldiers, we do not ask for just any soldiers, but soldiers
+ * that are better than what we already have. This routine sets the requirements
+ * used by the request.
+ *
+ * The routine returns true if upgrade request thresholds have changed. This information could be
+ * used to decide whether the soldier-Request should be upgraded. Additionally, the m_try_soldier_upgrade
+ * field will be set so to know if an attempt to get better soldier sould be performed.
+ */
+ bool update_upgrade_requirements();
+ /**
+ * Called when an upgraded soldier comes to join the garrison
+ */
+ bool incorporateUpgradedSoldier(Editor_Game_Base & game, Soldier & s);
+ /**
+ * Find the least suited soldier for this garrison. We don't play
+ * in the same league
+ */
+ Soldier * find_least_suited_soldier();
+ /**
+ * Try to drop the lease suited soldier, return true on success.
+ * If a new soldier s has arrived, extra care will be taken to not drop
+ * anyone if the new one is even worst
+ */
+ bool drop_least_suited_soldier(Soldier * s = nullptr);
+ /**
+ * Return true if we hold a running job for that soldied
+ */
+ bool haveSoldierJob(Soldier &) const;
+ /**
+ * \return the enemy, if any, that the given soldier was scheduled
+ * to attack, and remove the job.
+ */
+ Map_Object * popSoldierJob(Soldier *, bool * stayhome = 0, uint8_t * retreat = 0);
+
+ // Basic fields
+ Building& m_building;
+ uint32_t m_min_capacity;
+ uint32_t m_max_capacity;
+ uint32_t m_capacity;
+ bool m_passive;
+
+ // Healing
+ uint32_t m_heal_per_second;
+ uint32_t m_last_heal_time;
+
+ // Requests
+ Requirements m_soldier_requirements; // This is used to grab a bunch of soldiers: Anything goes
+ RequireAttribute m_soldier_upgrade_requirements; // This is used when exchanging soldiers.
+ std::unique_ptr<Request> m_normal_soldier_request; // filling the site
+ std::unique_ptr<Request> m_upgrade_soldier_request; // seeking for better soldiers
+
+ // Conqueral
+ uint32_t m_conquer_radius;
+ bool m_didconquer;
+
+ // Job
+ struct SoldierJob {
+ Soldier * soldier;
+ Object_Ptr enemy;
+ bool stayhome;
+ uint8_t retreat;
+ };
+ std::vector<SoldierJob> m_soldierjobs;
+
+ // Soldier preferences
+ SoldierPref m_soldier_preference;
+ uint32_t m_last_swap_soldiers_time;
+ bool m_try_soldier_upgrade; // optimization -- if everybody is zero-level, do not downgrade
+ bool m_doing_upgrade_request;
+};
+
+}
+
+#endif
=== modified file 'src/logic/item_ware_descr.h'
--- src/logic/item_ware_descr.h 2013-07-26 20:19:36 +0000
+++ src/logic/item_ware_descr.h 2013-08-06 10:09:46 +0000
@@ -41,7 +41,7 @@
namespace Widelands {
/**
- * Wares can be stored in warehouses. They can be transferred across an
+ * Wares can be stored in storages. They can be transferred across an
* Economy. They can be traded.
* Both items (lumber, stone, ...) and workers are considered wares.
* Every ware has a unique name. Note that an item must not have the same
@@ -75,7 +75,7 @@
/// \return ware's localized descriptive text
const std::string & helptext() const throw () {return m_helptext;}
- /// How much of the ware type that an economy should store in warehouses.
+ /// How much of the ware type that an economy should store in storages.
/// The special value std::numeric_limits<uint32_t>::max() means that the
/// the target quantity of this ware type will never be checked and should
/// not be configurable.
=== modified file 'src/logic/militarysite.cc'
--- src/logic/militarysite.cc 2013-07-31 17:00:28 +0000
+++ src/logic/militarysite.cc 2013-08-06 10:09:46 +0000
@@ -21,8 +21,10 @@
#include <clocale>
#include <cstdio>
+#include <memory>
#include <boost/foreach.hpp>
+#include <boost/format.hpp>
#include <libintl.h>
#include "economy/flag.h"
@@ -33,6 +35,7 @@
#include "logic/editor_game_base.h"
#include "logic/findbob.h"
#include "logic/game.h"
+#include "logic/garrisonhandler.h"
#include "logic/message_queue.h"
#include "logic/player.h"
#include "logic/soldier.h"
@@ -61,7 +64,6 @@
if (m_conquer_radius > 0)
m_workarea_info[m_conquer_radius].insert(descname() + _(" conquer"));
m_prefers_heroes_at_start = global_s.get_safe_bool("prefer_heroes");
-
}
/**
@@ -83,96 +85,39 @@
*/
MilitarySite::MilitarySite(const MilitarySite_Descr & ms_descr) :
-ProductionSite(ms_descr),
-m_didconquer (false),
-m_capacity (ms_descr.get_max_number_of_soldiers()),
-m_nexthealtime(0),
-m_soldier_preference(ms_descr.m_prefers_heroes_at_start ? kPrefersHeroes : kPrefersRookies),
-m_soldier_upgrade_try(false)
+ProductionSite(ms_descr)
{
- m_next_swap_soldiers_time = 0;
+ GarrisonHandler* gh = new GarrisonHandler
+ (*this, 1,
+ descr().get_max_number_of_soldiers(),
+ descr().get_conquers(), descr().get_heal_per_second(),
+ descr().m_prefers_heroes_at_start ? GarrisonHandler::SoldierPref::Heroes
+ : GarrisonHandler::SoldierPref::Rookies);
+ m_garrison.reset(gh);
}
-
MilitarySite::~MilitarySite()
{
- assert(!m_normal_soldier_request);
- assert(!m_upgrade_soldier_request);
-}
-
-
-/**
-===============
-Display number of soldiers.
-===============
-*/
-std::string MilitarySite::get_statistics_string()
-{
- char buffer[255];
- std::string str;
- uint32_t present = presentSoldiers().size();
- uint32_t total = stationedSoldiers().size();
-
- if (present == total) {
- snprintf
- (buffer, sizeof(buffer),
- ngettext("%u soldier", "%u soldiers", total),
- total);
- } else {
- snprintf
- (buffer, sizeof(buffer),
- ngettext("%u(+%u) soldier", "%u(+%u) soldiers", total),
- present, total - present);
- }
- str = buffer;
-
- if (m_capacity > total) {
- snprintf(buffer, sizeof(buffer), " (+%u)", m_capacity - total);
- str += buffer;
- }
-
- return str;
-}
-
+}
void MilitarySite::init(Editor_Game_Base & egbase)
{
ProductionSite::init(egbase);
-
+ m_garrison->init(egbase);
upcast(Game, game, &egbase);
const std::vector<Worker*>& ws = get_workers();
- container_iterate_const(std::vector<Worker *>, ws, i)
+ container_iterate_const(std::vector<Worker *>, ws, i) {
if (upcast(Soldier, soldier, *i.current)) {
soldier->set_location_initially(*this);
- assert(!soldier->get_state()); // Should be newly created.
- if (game)
- soldier->start_task_buildingwork(*game);
+ m_garrison->incorporateSoldier(egbase, *soldier);
}
- update_soldier_request();
-
- // schedule the first healing
- m_nexthealtime = egbase.get_gametime() + 1000;
- if (game)
+ }
+ if (game) {
schedule_act(*game, 1000);
-}
-
-
-/**
-===============
-Change the economy for the wares queues.
-Note that the workers are dealt with in the PlayerImmovable code.
-===============
-*/
-void MilitarySite::set_economy(Economy * const e)
-{
- ProductionSite::set_economy(e);
-
- if (m_normal_soldier_request && e)
- m_normal_soldier_request->set_economy(e);
- if (m_upgrade_soldier_request && e)
- m_upgrade_soldier_request->set_economy(e);
-}
+ }
+}
+
/**
===============
@@ -181,362 +126,12 @@
*/
void MilitarySite::cleanup(Editor_Game_Base & egbase)
{
- // unconquer land
- if (m_didconquer)
- egbase.unconquer_area
- (Player_Area<Area<FCoords> >
- (owner().player_number(),
- Area<FCoords>
- (egbase.map().get_fcoords(get_position()), get_conquers())),
- m_defeating_player);
-
+ // Order matters. Building needed to unconquer, building
+ // cleanup will trigger new requests in garrison, garrison
+ // cleanup will destroy them
+ m_garrison->cleanup(egbase);
ProductionSite::cleanup(egbase);
-
- // Note that removing workers during ProductionSite::cleanup can generate
- // new requests; that's why we delete it at the end of this function.
- m_normal_soldier_request.reset();
- m_upgrade_soldier_request.reset();
-}
-
-
-/*
-===============
-Takes one soldier and adds him to ours
-
-returns 0 on succes, -1 if there was no room for this soldier
-===============
-*/
-int MilitarySite::incorporateSoldier(Editor_Game_Base & egbase, Soldier & s)
-{
-
- if (s.get_location(egbase) != this)
- {
- s.set_location(this);
- }
-
- // Soldier upgrade is done once the site is full. In soldier upgrade, we
- // request one new soldier who is better suited than the existing ones.
- // Normally, I kick out one existing soldier as soon as a new guy starts walking
- // towards here. However, since that is done via infrequent polling, a new soldier
- // can sometimes reach the site before such kick-out happens. In those cases, we
- // should either drop one of the existing soldiers or reject the new guy, to
- // avoid overstocking this site.
-
- if (stationedSoldiers().size() > descr().get_max_number_of_soldiers())
- {
- return incorporateUpgradedSoldier(egbase, s) ? 0 : -1;
- }
-
- if (!m_didconquer) {
- conquer_area(egbase);
- // Building is now occupied - idle animation should be played
- start_animation(egbase, descr().get_animation("idle"));
-
- if (upcast(Game, game, &egbase)) {
- char message[256];
- snprintf
- (message, sizeof(message),
- _("Your soldiers occupied your %s."),
- descname().c_str());
- send_message
- (*game,
- "site_occupied",
- descname(),
- message);
- }
- }
-
- if (upcast(Game, game, &egbase)) {
- // Bind the worker into this house, hide him on the map
- s.reset_tasks(*game);
- s.start_task_buildingwork(*game);
- }
-
- // Make sure the request count is reduced or the request is deleted.
- update_soldier_request(true);
-
- return 0;
-}
-
-
-/*
- * Returns the least wanted soldier -- If player prefers zero-level guys,
- * the most trained soldier is the "weakest guy".
- */
-
-Soldier *
-MilitarySite::find_least_suited_soldier()
-{
- const std::vector<Soldier *> present = presentSoldiers();
- const int32_t multiplier = kPrefersHeroes == m_soldier_preference ? -1:1;
- int worst_soldier_level = INT_MIN;
- Soldier * worst_soldier = nullptr;
- BOOST_FOREACH (Soldier * sld, present)
- {
- int this_soldier_level = multiplier * static_cast<int> (sld->get_level(atrTotal));
- if (this_soldier_level > worst_soldier_level)
- {
- worst_soldier_level = this_soldier_level;
- worst_soldier = sld;
- }
- }
- return worst_soldier;
-}
-
-
-/*
- * Kicks out the least wanted soldier -- If player prefers zero-level guys,
- * the most trained soldier is the "weakest guy".
- *
- * Returns false, if there is only one soldier (won't drop last soldier)
- * or the new guy is not better than the weakest one present, in which case
- * nobody is dropped. If a new guy arrived and nobody was dropped, then
- * caller of this should not allow the new guy to enter.
- *
- * Situations like the above may happen if, for example, when weakest guy
- * that was supposed to be dropped is not present at the moment his replacement
- * arrives.
- */
-
-bool
-MilitarySite::drop_least_suited_soldier(bool new_soldier_has_arrived, Soldier * newguy)
-{
- const std::vector<Soldier *> present = presentSoldiers();
-
- // If I have only one soldier, and the new guy is not here yet, I can't release.
- if (new_soldier_has_arrived || 1 < present.size())
- {
- Soldier * kickoutCandidate = find_least_suited_soldier();
-
- // If the arriving guy is worse than worst present, I wont't release.
- if (nullptr != newguy && nullptr != kickoutCandidate)
- {
- int32_t old_level = kickoutCandidate->get_level(atrTotal);
- int32_t new_level = newguy->get_level(atrTotal);
- if (kPrefersHeroes == m_soldier_preference && old_level >= new_level)
- {
- return false;
- }
- else
- if (kPrefersRookies == m_soldier_preference && old_level <= new_level)
- {
- return false;
- }
- }
-
- // Now I know that the new guy is worthy.
- if (nullptr != kickoutCandidate)
- {
- Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
- kickoutCandidate->reset_tasks(game);
- kickoutCandidate->start_task_leavebuilding(game, true);
- return true;
- }
- }
- return false;
-}
-
-/*
- * This finds room for a soldier in an already full occupied military building.
- *
- * Returns false if the soldier was not incorporated.
- */
-bool
-MilitarySite::incorporateUpgradedSoldier(Editor_Game_Base & egbase, Soldier & s)
-{
- // Call to drop_least routine has side effects: it tries to drop a soldier. Order is important!
- if (stationedSoldiers().size() < m_capacity || drop_least_suited_soldier(true, &s))
- {
- Game & game = ref_cast<Game, Editor_Game_Base>(egbase);
- s.set_location(this);
- s.reset_tasks(game);
- s.start_task_buildingwork(game);
- return true;
- }
- return false;
-}
-
-/*
-===============
-Called when our soldier arrives.
-===============
-*/
-void MilitarySite::request_soldier_callback
- (Game & game,
- Request &,
- Ware_Index,
- Worker * const w,
- PlayerImmovable & target)
-{
- MilitarySite & msite = ref_cast<MilitarySite, PlayerImmovable>(target);
- Soldier & s = ref_cast<Soldier, Worker> (*w);
-
- msite.incorporateSoldier(game, s);
-}
-
-
-/**
- * Update the request for soldiers and cause soldiers to be evicted
- * as appropriate.
- */
-void MilitarySite::update_normal_soldier_request()
-{
- std::vector<Soldier *> present = presentSoldiers();
- uint32_t const stationed = stationedSoldiers().size();
-
- if (stationed < m_capacity) {
- if (!m_normal_soldier_request) {
- m_normal_soldier_request.reset
- (new Request
- (*this,
- tribe().safe_worker_index("soldier"),
- MilitarySite::request_soldier_callback,
- wwWORKER));
- m_normal_soldier_request->set_requirements (m_soldier_requirements);
- }
-
- m_normal_soldier_request->set_count(m_capacity - stationed);
- } else {
- m_normal_soldier_request.reset();
- }
-
- if (m_capacity < present.size()) {
- Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
- for (uint32_t i = 0; i < present.size() - m_capacity; ++i) {
- Soldier & soldier = *present[i];
- soldier.reset_tasks(game);
- soldier.start_task_leavebuilding(game, true);
- }
- }
-}
-
-/* There are two kinds of soldier requests: "normal", which is used whenever the military site needs
- * more soldiers, and "upgrade" which is used when there is a preference for either heroes or
- * rookies.
- *
- * In case of normal requests, the military site is filled. In case of upgrade requests, only one guy
- * is exchanged at a time.
- *
- * There would be more efficient ways to get well trained soldiers. Now, new buildings appearing in battle
- * field are more vulnerable at the beginning. This is intentional. The purpose of this upgrade thing is
- * to reduce the benefits of site micromanagement. The intention is not to make gameplay easier in other ways.
- */
-void MilitarySite::update_upgrade_soldier_request()
-{
- bool reqch = update_upgrade_requirements();
- if (!m_soldier_upgrade_try)
- return;
-
- bool do_rebuild_request = reqch;
-
- if (m_upgrade_soldier_request)
- {
- if (!m_upgrade_soldier_request->is_open())
- // If a replacement is already walking this way, let's not change our minds.
- do_rebuild_request = false;
- if (0 == m_upgrade_soldier_request->get_count())
- do_rebuild_request = true;
- }
- else
- do_rebuild_request = true;
-
- if (do_rebuild_request)
- {
- m_upgrade_soldier_request.reset
- (new Request
- (*this,
- tribe().safe_worker_index("soldier"),
- MilitarySite::request_soldier_callback,
- wwWORKER));
-
- m_upgrade_soldier_request->set_requirements(m_soldier_upgrade_requirements);
- m_upgrade_soldier_request->set_count(1);
- }
-}
-
-/*
- * I have update_soldier_request
- * update_upgrade_soldier_request
- * update_normal_soldier_request
- *
- * The first one handles state switching between site fill (normal more)
- * and grabbing soldiers with proper training (upgrade mode). The last
- * two actually make the requests.
- *
- * The input parameter incd is true, if we just incorporated a new soldier
- * as a result of an upgrade request. In such cases, we will re-arm the
- * upgrade request.
- */
-
-void MilitarySite::update_soldier_request(bool incd)
-{
- const uint32_t capacity = soldierCapacity();
- const uint32_t stationed = stationedSoldiers().size();
-
- if (m_doing_upgrade_request)
- {
- if (incd && m_upgrade_soldier_request) // update requests always ask for one soldier at time!
- {
- m_upgrade_soldier_request.reset();
- }
- if (capacity > stationed)
- {
- // Somebody is killing my soldiers in the middle of upgrade
- // or I have kicked out his predecessor already.
- if
- ((m_upgrade_soldier_request)
- && (m_upgrade_soldier_request->is_open() || 0 == m_upgrade_soldier_request->get_count()))
- {
- // Economy was not able to find the soldiers I need.
- // I can safely drop the upgrade request and go to fill mode.
- m_upgrade_soldier_request.reset();
- }
- if (! m_upgrade_soldier_request)
- {
- //phoo -- I can safely request new soldiers.
- m_doing_upgrade_request = false;
- update_normal_soldier_request();
- }
- // else -- ohno please help me! Player is in trouble -- evil grin
- }
- else // military site is full or overfull
- if (capacity < stationed) // player is reducing capacity
- {
- drop_least_suited_soldier(false, nullptr);
- }
- else // capacity == stationed size
- {
- if
- (m_upgrade_soldier_request
- && (!(m_upgrade_soldier_request->is_open()))
- && 1 == m_upgrade_soldier_request->get_count()
- && (!incd))
- {
- drop_least_suited_soldier(false, nullptr);
- }
- else
- {
- update_upgrade_soldier_request();
- }
- }
- }
- else // not doing upgrade request
- {
- if ((capacity != stationed) or (m_normal_soldier_request))
- update_normal_soldier_request();
-
- if ((capacity == stationed) and (! m_normal_soldier_request))
- {
- if (presentSoldiers().size() == capacity)
- {
- m_doing_upgrade_request = true;
- update_upgrade_soldier_request();
- }
- // Note -- if there are non-present stationed soldiers, nothing gets
- // called. Therefore, I revisit this routine periodically without apparent
- // reason, hoping that all stationed soldiers would be present.
- }
- }
+ m_garrison->cleanup_requests(egbase);
}
/*
@@ -553,60 +148,53 @@
// Maybe a new queueing system like MilitaryAct could be introduced.
ProductionSite::act(game, data);
-
- const int32_t timeofgame = game.get_gametime();
- if (m_normal_soldier_request && m_upgrade_soldier_request)
- {
- throw wexception("MilitarySite::act: Two soldier requests are ongoing -- should never happen!\n");
- }
-
- // I do not get a callback when stationed, non-present soldier returns --
- // Therefore I must poll in some occasions. Let's do that rather infrequently,
- // to keep the game lightweight.
-
- //TODO: I would need two new callbacks, to get rid ot this polling.
- if (timeofgame > m_next_swap_soldiers_time)
- {
- m_next_swap_soldiers_time = timeofgame + (m_soldier_upgrade_try ? 20000 : 100000);
- update_soldier_request();
- }
-
- if (m_nexthealtime <= game.get_gametime()) {
- uint32_t total_heal = descr().get_heal_per_second();
- std::vector<Soldier *> soldiers = presentSoldiers();
-
- for (uint32_t i = 0; i < soldiers.size(); ++i) {
- Soldier & s = *soldiers[i];
-
- // The healing algorithm is totally arbitrary
- if (s.get_current_hitpoints() < s.get_max_hitpoints()) {
- s.heal(total_heal);
- break;
- }
- }
-
- m_nexthealtime = game.get_gametime() + 1000;
- schedule_act(game, 1000);
- }
-}
-
-
-/**
- * The worker is about to be removed.
- *
- * After the removal of the worker, check whether we need to request
- * new soldiers.
- */
-void MilitarySite::remove_worker(Worker & w)
-{
- ProductionSite::remove_worker(w);
-
- if (upcast(Soldier, soldier, &w))
- popSoldierJob(soldier, 0, 0);
-
- update_soldier_request();
-}
-
+ m_garrison->act(game);
+ schedule_act(game, 1000);
+}
+
+/**
+===============
+Display number of soldiers.
+===============
+*/
+std::string MilitarySite::get_statistics_string()
+{
+ std::string str;
+ uint32_t present = m_garrison->presentSoldiers().size();
+ uint32_t total = m_garrison->stationedSoldiers().size();
+ uint32_t capacity = m_garrison->soldierCapacity();
+
+ if (present == total) {
+ str =
+ (boost::format
+ (ngettext(_("%u soldier"), _("%u soldiers"), total)) % total)
+ .str();
+ } else {
+ str =
+ (boost::format
+ (ngettext(_("%u(+%u) soldier"), _("%u(+%u) soldiers"), present))
+ % present % (total - present))
+ .str();
+ }
+
+ if (capacity > total) {
+ str += (boost::format(" (+%u)") % (capacity - total)).str();
+ }
+
+ return str;
+}
+
+/**
+===============
+Change the economy for the wares queues.
+Note that the workers are dealt with in the PlayerImmovable code.
+===============
+*/
+void MilitarySite::set_economy(Economy * const e)
+{
+ ProductionSite::set_economy(e);
+ m_garrison->set_economy(e);
+}
/**
* Called by soldiers in the building.
@@ -614,490 +202,84 @@
bool MilitarySite::get_building_work(Game & game, Worker & worker, bool)
{
if (upcast(Soldier, soldier, &worker)) {
- // Evict soldiers that have returned home if the capacity is too low
- if (m_capacity < presentSoldiers().size()) {
- worker.reset_tasks(game);
- worker.start_task_leavebuilding(game, true);
- return true;
- }
-
- bool stayhome;
- uint8_t retreat;
- if
- (Map_Object * const enemy
- =
- popSoldierJob(soldier, &stayhome, &retreat))
- {
- if (upcast(Building, building, enemy)) {
- soldier->start_task_attack
- (game, *building, retreat);
- return true;
- } else if (upcast(Soldier, opponent, enemy)) {
- if (!opponent->getBattle()) {
- soldier->start_task_defense
- (game, stayhome, retreat);
- if (stayhome)
- opponent->send_signal(game, "sleep");
- return true;
- }
- } else
- throw wexception("MilitarySite::get_building_work: bad SoldierJob");
- }
+ return m_garrison->get_garrison_work(game, soldier);
}
-
return false;
}
-/**
- * \return \c true if the soldier is currently present and idle in the building.
- */
-bool MilitarySite::isPresent(Soldier & soldier) const
-{
- return
- soldier.get_location(owner().egbase()) == this &&
- soldier.get_state() == soldier.get_state(Worker::taskBuildingwork) &&
- soldier.get_position() == get_position();
-}
-
-// TODO(sirver): This method should probably return a const reference.
-std::vector<Soldier *> MilitarySite::presentSoldiers() const
-{
- std::vector<Soldier *> soldiers;
-
- const std::vector<Worker *>& w = get_workers();
- container_iterate_const(std::vector<Worker *>, w, i)
- if (upcast(Soldier, soldier, *i.current))
- if (isPresent(*soldier))
- soldiers.push_back(soldier);
-
- return soldiers;
-}
-
-// TODO(sirver): This method should probably return a const reference.
-std::vector<Soldier *> MilitarySite::stationedSoldiers() const
-{
- std::vector<Soldier *> soldiers;
-
- const std::vector<Worker *>& w = get_workers();
- container_iterate_const(std::vector<Worker *>, w, i)
- if (upcast(Soldier, soldier, *i.current))
- soldiers.push_back(soldier);
-
- return soldiers;
-}
-
-uint32_t MilitarySite::minSoldierCapacity() const throw () {
- return 1;
-}
-uint32_t MilitarySite::maxSoldierCapacity() const throw () {
- return descr().get_max_number_of_soldiers();
-}
-uint32_t MilitarySite::soldierCapacity() const
-{
- return m_capacity;
-}
-
-void MilitarySite::setSoldierCapacity(uint32_t const capacity) {
- assert(minSoldierCapacity() <= capacity);
- assert (capacity <= maxSoldierCapacity());
- assert(m_capacity != capacity);
- m_capacity = capacity;
- update_soldier_request();
-}
-
-void MilitarySite::dropSoldier(Soldier & soldier)
-{
- Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
-
- if (!isPresent(soldier)) {
- // This can happen when the "drop soldier" player command is delayed
- // by network delay or a client has bugs.
- molog("MilitarySite::dropSoldier(%u): not present\n", soldier.serial());
- return;
- }
- if (presentSoldiers().size() <= minSoldierCapacity()) {
- molog("cannot drop last soldier(s)\n");
- return;
- }
-
- soldier.reset_tasks(game);
- soldier.start_task_leavebuilding(game, true);
-
- update_soldier_request();
-}
-
-
-void MilitarySite::conquer_area(Editor_Game_Base & egbase) {
- assert(!m_didconquer);
- egbase.conquer_area
- (Player_Area<Area<FCoords> >
- (owner().player_number(),
- Area<FCoords>
- (egbase.map().get_fcoords(get_position()), get_conquers())));
- m_didconquer = true;
-}
-
-
-bool MilitarySite::canAttack()
-{
- return m_didconquer;
-}
-
-void MilitarySite::aggressor(Soldier & enemy)
-{
- Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
- Map & map = game.map();
- if
- (enemy.get_owner() == &owner() ||
- enemy.getBattle() ||
- get_conquers()
- <=
- map.calc_distance(enemy.get_position(), get_position()))
- return;
-
- if
- (map.find_bobs
- (Area<FCoords>(map.get_fcoords(base_flag().get_position()), 2),
- 0,
- FindBobEnemySoldier(&owner())))
- return;
-
- // We're dealing with a soldier that we might want to keep busy
- // Now would be the time to implement some player-definable
- // policy as to how many soldiers are allowed to leave as defenders
- std::vector<Soldier *> present = presentSoldiers();
-
- if (1 < present.size())
- container_iterate_const(std::vector<Soldier *>, present, i)
- if (!haveSoldierJob(**i.current)) {
- SoldierJob sj;
- sj.soldier = *i.current;
- sj.enemy = &enemy;
- sj.stayhome = false;
- sj.retreat = owner().get_retreat_percentage();
- m_soldierjobs.push_back(sj);
- (*i.current)->update_task_buildingwork(game);
- return;
- }
-
- // Inform the player, that we are under attack by adding a new entry to the
- // message queue - a sound will automatically be played.
- informPlayer(game, true);
-}
-
-bool MilitarySite::attack(Soldier & enemy)
-{
- Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
-
- std::vector<Soldier *> present = presentSoldiers();
- Soldier * defender = 0;
-
- if (!present.empty()) {
- // Find soldier with greatest hitpoints
- uint32_t current_max = 0;
- container_iterate_const(std::vector<Soldier *>, present, i)
- if ((*i.current)->get_current_hitpoints() > current_max) {
- defender = *i.current;
- current_max = defender->get_current_hitpoints();
- }
- } else {
- // If one of our stationed soldiers is currently walking into the
- // building, give us another chance.
- std::vector<Soldier *> stationed = stationedSoldiers();
- container_iterate_const(std::vector<Soldier *>, stationed, i)
- if ((*i.current)->get_position() == get_position()) {
- defender = *i.current;
- break;
- }
- }
-
- if (defender) {
- popSoldierJob(defender); // defense overrides all other jobs
-
- SoldierJob sj;
- sj.soldier = defender;
- sj.enemy = &enemy;
- sj.stayhome = true;
- sj.retreat = 0; // Flag defenders could not retreat
- m_soldierjobs.push_back(sj);
-
- defender->update_task_buildingwork(game);
-
- // Inform the player, that we are under attack by adding a new entry to
- // the message queue - a sound will automatically be played.
- informPlayer(game);
-
- return true;
- } else {
- // The enemy has defeated our forces, we should inform the player
- const Coords coords = get_position();
- {
- char message[2048];
- snprintf
- (message, sizeof(message),
- _("The enemy defeated your soldiers at the %s."),
- descname().c_str());
- send_message
- (game,
- "site_lost",
- _("Militarysite lost!"),
- message);
- }
-
- // Now let's see whether the enemy conquers our militarysite, or whether
- // we still hold the bigger military presence in that area (e.g. if there
- // is a fortress one or two points away from our sentry, the fortress has
- // a higher presence and thus the enemy can just burn down the sentry.
- if (military_presence_kept(game)) {
- // Okay we still got the higher military presence, so the attacked
- // militarysite will be destroyed.
- set_defeating_player(enemy.owner().player_number());
- schedule_destroy(game);
- return false;
- }
-
- // The enemy conquers the building
- // In fact we do not conquer it, but place a new building of same type at
- // the old location.
- Player * enemyplayer = enemy.get_owner();
- const Tribe_Descr & enemytribe = enemyplayer->tribe();
-
- // Add suffix to all descr in former buildings in cases
- // the new owner comes from another tribe
- Building_Descr::FormerBuildings former_buildings;
- BOOST_FOREACH(const Building_Descr * old_descr, m_old_buildings) {
- std::string bldname = old_descr->name();
- // Has this building already a suffix? == conquered building?
- std::string::size_type const dot = bldname.rfind('.');
- if (dot >= bldname.size()) {
- // Add suffix, if the new owner uses another tribe than we.
- if (enemytribe.name() != owner().tribe().name())
- bldname += "." + owner().tribe().name();
- } else if (enemytribe.name() == bldname.substr(dot + 1, bldname.size()))
- bldname = bldname.substr(0, dot);
- Building_Index bldi = enemytribe.safe_building_index(bldname.c_str());
- const Building_Descr * former_descr = enemytribe.get_building_descr(bldi);
- former_buildings.push_back(former_descr);
- }
-
- // Now we destroy the old building before we place the new one.
- set_defeating_player(enemy.owner().player_number());
+Garrison* MilitarySite::get_garrison() const
+{
+ return m_garrison.get();
+}
+
+Building* MilitarySite::get_building()
+{
+ return this;
+}
+
+void MilitarySite::garrison_occupied()
+{
+ start_animation(owner().egbase(), descr().get_animation("idle"));
+}
+
+void MilitarySite::garrison_lost(Game& game, Widelands::Player_Number defeating, bool captured)
+{
+ if (!captured) {
schedule_destroy(game);
-
- enemyplayer->force_building(coords, former_buildings);
- BaseImmovable * const newimm = game.map()[coords].get_immovable();
- upcast(MilitarySite, newsite, newimm);
- newsite->reinit_after_conqueration(game);
-
- // Of course we should inform the victorious player as well
- char message[2048];
- snprintf
- (message, sizeof(message),
- _("Your soldiers defeated the enemy at the %s."),
- newsite->descname().c_str());
- newsite->send_message
- (game,
- "site_defeated",
- _("Enemy at site defeated!"),
- message);
-
- return false;
- }
+ return;
+ }
+ // The enemy conquers the building
+ // In fact we do not conquer it, but place a new building of same type at
+ // the old location.
+ Player * enemyplayer = game.get_player(defeating);
+ const Tribe_Descr & enemytribe = enemyplayer->tribe();
+
+ // Add suffix to all descr in former buildings in cases
+ // the new owner comes from another tribe
+ Building_Descr::FormerBuildings former_buildings;
+ BOOST_FOREACH(const Building_Descr * old_descr, m_old_buildings) {
+ std::string bldname = old_descr->name();
+ // Has this building already a suffix? == conquered building?
+ std::string::size_type const dot = bldname.rfind('.');
+ if (dot >= bldname.size()) {
+ // Add suffix, if the new owner uses another tribe than we.
+ if (enemytribe.name() != owner().tribe().name())
+ bldname += "." + owner().tribe().name();
+ } else if (enemytribe.name() == bldname.substr(dot + 1, bldname.size()))
+ bldname = bldname.substr(0, dot);
+ Building_Index bldi = enemytribe.safe_building_index(bldname.c_str());
+ const Building_Descr * former_descr = enemytribe.get_building_descr(bldi);
+ former_buildings.push_back(former_descr);
+ }
+
+ const Coords coords = get_position();
+ // Now we destroy the old building before we place the new one.
+ set_defeating_player(defeating);
+ schedule_destroy(game);
+
+ enemyplayer->force_building(coords, former_buildings);
+ BaseImmovable * const newimm = game.map()[coords].get_immovable();
+ upcast(GarrisonOwner, go, newimm);
+ go->reinit_after_conqueral(game);
+
+ // Of course we should inform the victorious player as well
+ upcast(Building, new_building, newimm);
+ std::string message =
+ (boost::format
+ (_("Your soldiers defeated the enemy at the %s."))
+ % new_building->descname())
+ .str();
+ new_building->send_message
+ (game, "site_defeated",
+ _("Enemy at site defeated!"),
+ message);
}
-/// Initialises the militarysite after it was "conquered" (the old was replaced)
-void MilitarySite::reinit_after_conqueration(Game & game)
+void MilitarySite::reinit_after_conqueral(Game& game)
{
- clear_requirements();
- conquer_area(game);
- update_soldier_request();
+ m_garrison->reinit_after_conqueral(game);
start_animation(game, descr().get_animation("idle"));
}
-/// Calculates whether the military presence is still kept and \returns true if.
-bool MilitarySite::military_presence_kept(Game & game)
-{
- // collect information about immovables in the area
- std::vector<ImmovableFound> immovables;
-
- // Search in a radius of 3 (needed for big militarysites)
- FCoords const fc = game.map().get_fcoords(get_position());
- game.map().find_immovables(Area<FCoords>(fc, 3), &immovables);
-
- for (uint32_t i = 0; i < immovables.size(); ++i)
- if (upcast(MilitarySite const, militarysite, immovables[i].object))
- if
- (this != militarysite and
- &owner () == &militarysite->owner() and
- get_size() <= militarysite->get_size() and
- militarysite->m_didconquer)
- return true;
- return false;
-}
-
-/// Informs the player about an attack of his opponent.
-void MilitarySite::informPlayer(Game & game, bool const discovered)
-{
- char message[2048];
- snprintf
- (message, sizeof(message),
- discovered ?
- _("Your %s discovered an aggressor.</p>") :
- _("Your %s is under attack.</p>"),
- descname().c_str());
-
- // Add a message as long as no previous message was send from a point with
- // radius <= 5 near the current location in the last 60 seconds
- send_message
- (game,
- "under_attack",
- _("You are under attack"),
- message,
- 60 * 1000, 5);
-}
-
-
-/*
- MilitarySite::set_requirements
-
- Easy to use, overwrite with given requirements.
-*/
-void MilitarySite::set_requirements (const Requirements & r)
-{
- m_soldier_requirements = r;
-}
-
-/*
- MilitarySite::clear_requirements
-
- This should cancel any requirement pushed at this house
-*/
-void MilitarySite::clear_requirements ()
-{
- m_soldier_requirements = Requirements();
-}
-
-void MilitarySite::sendAttacker
- (Soldier & soldier, Building & target, uint8_t retreat)
-{
- assert(isPresent(soldier));
-
- if (haveSoldierJob(soldier))
- return;
-
- SoldierJob sj;
- sj.soldier = &soldier;
- sj.enemy = ⌖
- sj.stayhome = false;
- sj.retreat = retreat;
- m_soldierjobs.push_back(sj);
-
- soldier.update_task_buildingwork
- (ref_cast<Game, Editor_Game_Base>(owner().egbase()));
-}
-
-
-bool MilitarySite::haveSoldierJob(Soldier & soldier)
-{
- container_iterate_const(std::vector<SoldierJob>, m_soldierjobs, i)
- if (i.current->soldier == &soldier)
- return true;
-
- return false;
-}
-
-
-/**
- * \return the enemy, if any, that the given soldier was scheduled
- * to attack, and remove the job.
- */
-Map_Object * MilitarySite::popSoldierJob
- (Soldier * const soldier, bool * const stayhome, uint8_t * const retreat)
-{
- container_iterate(std::vector<SoldierJob>, m_soldierjobs, i)
- if (i.current->soldier == soldier) {
- Map_Object * const enemy = i.current->enemy.get(owner().egbase());
- if (stayhome)
- *stayhome = i.current->stayhome;
- if (retreat)
- *retreat = i.current->retreat;
- m_soldierjobs.erase(i.current);
- return enemy;
- }
- return 0;
-}
-
-
-/*
- * When upgrading soldiers, we do not ask for just any soldiers, but soldiers
- * that are better than what we already have. This routine sets the requirements
- * used by the request.
- *
- * The routine returns true if upgrade request thresholds have changed. This information could be
- * used to decide whether the soldier-Request should be upgraded.
- */
-bool
-MilitarySite::update_upgrade_requirements()
-{
- int32_t soldier_upgrade_required_min = m_soldier_upgrade_requirements.getMin();
- int32_t soldier_upgrade_required_max = m_soldier_upgrade_requirements.getMax();
-
- if (kPrefersHeroes != m_soldier_preference && kPrefersRookies != m_soldier_preference)
- {
- log("MilitarySite::swapSoldiers: error: Unknown player preference %d.\n", m_soldier_preference);
- m_soldier_upgrade_try = false;
- return false;
- }
-
- // Find the level of the soldier that is currently least-suited.
- Soldier * worst_guy = find_least_suited_soldier();
- if (worst_guy == nullptr) {
- // There could be no soldier in the militarysite right now. No reason to freak out.
- return false;
- }
- int32_t wg_level = worst_guy->get_level(atrTotal);
-
- // Micro-optimization: I assume that the majority of military sites have only level-zero
- // soldiers and prefer rookies. Handle them separately.
- m_soldier_upgrade_try = true;
- if (kPrefersRookies == m_soldier_preference) {
- if (0 == wg_level)
- {
- m_soldier_upgrade_try = false;
- return false;
- }
- }
-
- // Now I actually build the new requirements.
- int32_t reqmin = kPrefersHeroes == m_soldier_preference ? 1 + wg_level : 0;
- int32_t reqmax = kPrefersHeroes == m_soldier_preference ? SHRT_MAX : wg_level - 1;
-
- bool maxchanged = reqmax != soldier_upgrade_required_max;
- bool minchanged = reqmin != soldier_upgrade_required_min;
-
- if (maxchanged or minchanged)
- {
- if (m_upgrade_soldier_request && (m_upgrade_soldier_request->is_open()))
- {
- m_upgrade_soldier_request.reset();
- }
- m_soldier_upgrade_requirements = RequireAttribute(atrTotal, reqmin, reqmax);
-
- return true;
- }
-
- return false;
-}
-
-// setters
-
-void
-MilitarySite::set_soldier_preference(MilitarySite::SoldierPreference p)
-{
- assert(kPrefersHeroes == p || kPrefersRookies == p);
- m_soldier_preference = p;
- m_next_swap_soldiers_time = 0;
-}
-
}
=== modified file 'src/logic/militarysite.h'
--- src/logic/militarysite.h 2013-07-26 20:19:36 +0000
+++ src/logic/militarysite.h 2013-08-06 10:09:46 +0000
@@ -20,10 +20,10 @@
#ifndef MILITARYSITE_H
#define MILITARYSITE_H
-#include "logic/attackable.h"
+#include "logic/garrison.h"
+#include "logic/garrisonhandler.h"
#include "logic/productionsite.h"
#include "logic/requirements.h"
-#include "logic/soldiercontrol.h"
namespace Widelands {
@@ -53,121 +53,38 @@
};
class MilitarySite :
- public ProductionSite, public SoldierControl, public Attackable
+ public ProductionSite, public GarrisonOwner
{
friend struct Map_Buildingdata_Data_Packet;
MO_DESCR(MilitarySite_Descr);
public:
- // I assume elsewhere, that enum SoldierPreference fits to uint8_t.
- enum SoldierPreference : uint8_t {
- kNoPreference,
- kPrefersRookies,
- kPrefersHeroes,
- };
-
MilitarySite(const MilitarySite_Descr &);
virtual ~MilitarySite();
- char const * type_name() const throw () {return "militarysite";}
- virtual std::string get_statistics_string();
-
virtual void init(Editor_Game_Base &);
virtual void cleanup(Editor_Game_Base &);
virtual void act(Game &, uint32_t data);
- virtual void remove_worker(Worker &);
+
+ char const * type_name() const throw () {return "militarysite";}
+ virtual std::string get_statistics_string();
virtual void set_economy(Economy *);
virtual bool get_building_work(Game &, Worker &, bool success);
- // Begin implementation of SoldierControl
- virtual std::vector<Soldier *> presentSoldiers() const;
- virtual std::vector<Soldier *> stationedSoldiers() const;
- virtual uint32_t minSoldierCapacity() const throw ();
- virtual uint32_t maxSoldierCapacity() const throw ();
- virtual uint32_t soldierCapacity() const;
- virtual void setSoldierCapacity(uint32_t capacity);
- virtual void dropSoldier(Soldier &);
- virtual int incorporateSoldier(Editor_Game_Base & game, Soldier & s);
- // End implementation of SoldierControl
-
- // Begin implementation of Attackable
- virtual Player & owner() const {return Building::owner();}
- virtual bool canAttack();
- virtual void aggressor(Soldier &);
- virtual bool attack (Soldier &);
- // End implementation of Attackable
-
- /**
- * Launch the given soldier on an attack towards the given
- * target building.
- */
- void sendAttacker(Soldier &, Building &, uint8_t);
-
- /// This methods are helper for use at configure this site.
- void set_requirements (const Requirements &);
- void clear_requirements();
- const Requirements & get_requirements () const {
- return m_soldier_requirements;
- }
-
- void reinit_after_conqueration(Game &);
-
- void update_soldier_request(bool i = false);
-
- void set_soldier_preference(SoldierPreference);
- SoldierPreference get_soldier_preference() const {
- return m_soldier_preference;
- }
+ // GarrisonOwner implementation
+ virtual Garrison* get_garrison() const;
+ virtual Building* get_building();
+ virtual void garrison_occupied();
+ virtual void garrison_lost(Game & game, Player_Number defeating, bool captured);
+ virtual void reinit_after_conqueral(Game& game);
protected:
- void conquer_area(Editor_Game_Base &);
-
virtual void create_options_window
(Interactive_GameBase &, UI::Window * & registry);
private:
- bool isPresent(Soldier &) const;
- static void request_soldier_callback
- (Game &, Request &, Ware_Index, Worker *, PlayerImmovable &);
-
- Map_Object * popSoldierJob
- (Soldier *, bool * stayhome = 0, uint8_t * retreat = 0);
- bool haveSoldierJob(Soldier &);
- bool military_presence_kept(Game &);
- void informPlayer(Game &, bool discovered = false);
- bool update_upgrade_requirements();
- void update_normal_soldier_request();
- void update_upgrade_soldier_request();
- bool incorporateUpgradedSoldier(Editor_Game_Base & game, Soldier & s);
- Soldier * find_least_suited_soldier();
- bool drop_least_suited_soldier(bool new_has_arrived, Soldier * s);
-
-
-private:
- Requirements m_soldier_requirements; // This is used to grab a bunch of soldiers: Anything goes
- RequireAttribute m_soldier_upgrade_requirements; // This is used when exchanging soldiers.
- std::unique_ptr<Request> m_normal_soldier_request; // filling the site
- std::unique_ptr<Request> m_upgrade_soldier_request; // seeking for better soldiers
- bool m_didconquer;
- uint32_t m_capacity;
-
- /**
- * Next gametime where we should heal something.
- */
- int32_t m_nexthealtime;
-
- struct SoldierJob {
- Soldier * soldier;
- Object_Ptr enemy;
- bool stayhome;
- uint8_t retreat;
- };
- std::vector<SoldierJob> m_soldierjobs;
- SoldierPreference m_soldier_preference;
- int32_t m_next_swap_soldiers_time;
- bool m_soldier_upgrade_try; // optimization -- if everybody is zero-level, do not downgrade
- bool m_doing_upgrade_request;
+ std::unique_ptr<GarrisonHandler> m_garrison;
};
}
=== modified file 'src/logic/player.cc'
--- src/logic/player.cc 2013-08-02 18:36:03 +0000
+++ src/logic/player.cc 2013-08-06 10:09:46 +0000
@@ -38,7 +38,6 @@
#include "logic/militarysite.h"
#include "logic/playercommand.h"
#include "logic/soldier.h"
-#include "logic/soldiercontrol.h"
#include "logic/trainingsite.h"
#include "logic/tribe.h"
#include "logic/warehouse.h"
@@ -699,12 +698,14 @@
void Player::military_site_set_soldier_preference(PlayerImmovable & imm, uint8_t m_soldier_preference)
{
- if (&imm.owner() == this)
- if (upcast(MilitarySite, milsite, &imm))
- milsite->set_soldier_preference(static_cast<MilitarySite::SoldierPreference>(m_soldier_preference));
+ if (&imm.owner() == this) {
+ if (upcast(GarrisonOwner, go, &imm)) {
+ Garrison* const garrison = go->get_garrison();
+ garrison->set_soldier_preference(static_cast<Garrison::SoldierPref>(m_soldier_preference));
+ }
+ }
}
-
/*
* enhance this building, remove it, but give the constructionsite
* an idea of enhancing
@@ -861,8 +862,9 @@
return;
if (soldier.get_worker_type() != Worker_Descr::SOLDIER)
return;
- if (upcast(SoldierControl, ctrl, &imm))
- ctrl->dropSoldier(soldier);
+ if (upcast(GarrisonOwner, go, &imm)) {
+ go->get_garrison()->dropSoldier(soldier);
+ }
}
/*
@@ -920,9 +922,10 @@
container_iterate_const(std::vector<BaseImmovable *>, flags, i) {
const Flag * attackerflag = static_cast<Flag *>(*i.current);
- const MilitarySite * ms = static_cast<MilitarySite *>(attackerflag->get_building());
- std::vector<Soldier *> const present = ms->presentSoldiers();
- uint32_t const nr_staying = ms->minSoldierCapacity();
+ GarrisonOwner * go = dynamic_cast<GarrisonOwner *>(attackerflag->get_building());
+ Garrison * garrison = go->get_garrison();
+ std::vector<Soldier *> const present = garrison->presentSoldiers();
+ uint32_t const nr_staying = garrison->minSoldierCapacity();
uint32_t const nr_present = present.size();
if (nr_staying < nr_present) {
uint32_t const nr_taken =
@@ -958,8 +961,8 @@
log("enemyflagaction: count is 0\n");
else if (is_hostile(flag.owner()))
if (Building * const building = flag.get_building())
- if (upcast(Attackable, attackable, building))
- if (attackable->canAttack()) {
+ if (upcast(GarrisonOwner, go, building))
+ if (go->get_garrison()->canAttack()) {
std::vector<Soldier *> attackers;
findAttackSoldiers(flag, &attackers, count);
assert(attackers.size() <= count);
@@ -969,10 +972,10 @@
retreat = std::min
(retreat, tribe().get_military_data().get_max_retreat());
- container_iterate_const(std::vector<Soldier *>, attackers, i)
- ref_cast<MilitarySite, PlayerImmovable>
- (*(*i.current)->get_location(egbase()))
- .sendAttacker(**i.current, *building, retreat);
+ container_iterate_const(std::vector<Soldier *>, attackers, i) {
+ upcast(GarrisonOwner, igo, (*i.current)->get_location(egbase()));
+ igo->get_garrison()->sendAttacker(**i.current, *building, retreat);
+ }
}
}
@@ -1174,13 +1177,13 @@
const uint32_t nrecos = get_nr_economies();
for (uint32_t i = 0; i < nrecos; ++i) {
- const std::vector<Widelands::Warehouse *> & warehouses =
- get_economy_by_number(i)->warehouses();
+ const std::vector<Widelands::Storage *> & storages =
+ get_economy_by_number(i)->storages();
for
- (std::vector<Widelands::Warehouse *>::const_iterator it =
- warehouses.begin();
- it != warehouses.end();
+ (std::vector<Widelands::Storage *>::const_iterator it =
+ storages.begin();
+ it != storages.end();
++it)
{
const Widelands::WareList & wares = (*it)->get_wares();
=== modified file 'src/logic/player.h'
--- src/logic/player.h 2013-08-01 03:23:11 +0000
+++ src/logic/player.h 2013-08-06 10:09:46 +0000
@@ -638,7 +638,7 @@
std::vector< std::vector<uint32_t> > m_ware_consumptions;
/**
- * Statistics of wares stored inside of warehouses over the
+ * Statistics of wares stored inside of storages over the
* life of the game, indexed as
* m_ware_stocks[ware_id][time_index]
*/
=== modified file 'src/logic/playercommand.cc'
--- src/logic/playercommand.cc 2013-07-31 17:00:28 +0000
+++ src/logic/playercommand.cc 2013-08-06 10:09:46 +0000
@@ -520,7 +520,7 @@
PlayerCommand (0, des.Unsigned8())
{
serial = des.Unsigned32();
- preference = des.Unsigned8();
+ preference = static_cast<Garrison::SoldierPref>(des.Unsigned8());
}
void Cmd_MilitarySiteSetSoldierPreference::serialize (StreamWrite & ser)
@@ -528,7 +528,7 @@
ser.Unsigned8 (PLCMD_MILITARYSITESETSOLDIERPREFERENCE);
ser.Unsigned8 (sender());
ser.Unsigned32(serial);
- ser.Unsigned8 (preference);
+ ser.Unsigned8 (static_cast<uint8_t>(preference));
}
void Cmd_MilitarySiteSetSoldierPreference::execute (Game & game)
@@ -549,7 +549,7 @@
// Now serial
const Map_Object & obj = *egbase.objects().get_object(serial);
- fw.Unsigned8(preference);
+ fw.Unsigned8(static_cast<uint8_t>(preference));
fw.Unsigned32(mos.get_object_file_index(obj));
}
@@ -561,7 +561,7 @@
const uint16_t packet_version = fr.Unsigned16();
if (packet_version == PLAYER_CMD_SOLDIERPREFERENCE_VERSION) {
PlayerCommand::Read(fr, egbase, mol);
- preference = fr.Unsigned8();
+ preference = static_cast<Garrison::SoldierPref>(fr.Unsigned8());
const uint32_t building_serial = fr.Unsigned32();
try {
serial = mol.get<Map_Object>(building_serial).serial();
@@ -1607,8 +1607,8 @@
{
if (upcast(Building, building, game.objects().get_object(serial)))
if (&building->owner() == game.get_player(sender()))
- if (upcast(SoldierControl, ctrl, building))
- ctrl->changeSoldierCapacity(val);
+ if (upcast(GarrisonOwner, go, building))
+ go->get_garrison()->changeSoldierCapacity(val);
}
void Cmd_ChangeSoldierCapacity::serialize (StreamWrite & ser)
@@ -1906,18 +1906,18 @@
/*** struct Cmd_SetStockPolicy ***/
Cmd_SetStockPolicy::Cmd_SetStockPolicy
(int32_t time, Player_Number p,
- Warehouse & wh, bool isworker, Ware_Index ware,
- Warehouse::StockPolicy policy)
+ StorageOwner & storage_owner, bool isworker, Ware_Index ware,
+ Storage::StockPolicy policy)
: PlayerCommand(time, p)
{
- m_warehouse = wh.serial();
+ m_storage_owner = storage_owner.get_building()->serial();
m_isworker = isworker;
m_ware = ware;
m_policy = policy;
}
Cmd_SetStockPolicy::Cmd_SetStockPolicy()
-: PlayerCommand(), m_warehouse(0), m_isworker(false), m_policy()
+: PlayerCommand(), m_storage_owner(0), m_isworker(false), m_policy()
{
}
@@ -1930,20 +1930,20 @@
{
// Sanitize data that could have come from the network
if (Player * plr = game.get_player(sender())) {
- if (upcast(Warehouse, warehouse, game.objects().get_object(m_warehouse)))
+ if (upcast(StorageOwner, storage_owner, game.objects().get_object(m_storage_owner)))
{
- if (&warehouse->owner() != plr) {
+ if (&storage_owner->get_building()->owner() != plr) {
log
- ("Cmd_SetStockPolicy: sender %u, but warehouse owner %u\n",
- sender(), warehouse->owner().player_number());
+ ("Cmd_SetStockPolicy: sender %u, but storage owner %u\n",
+ sender(), storage_owner->get_building()->owner().player_number());
return;
}
switch (m_policy) {
- case Warehouse::SP_Normal:
- case Warehouse::SP_Prefer:
- case Warehouse::SP_DontStock:
- case Warehouse::SP_Remove:
+ case Storage::StockPolicy::Normal:
+ case Storage::StockPolicy::Prefer:
+ case Storage::StockPolicy::DontStock:
+ case Storage::StockPolicy::Remove:
break;
default:
log
@@ -1952,7 +1952,7 @@
return;
}
- const Tribe_Descr & tribe = warehouse->tribe();
+ const Tribe_Descr & tribe = storage_owner->get_building()->tribe();
if (m_isworker) {
if (!(m_ware < tribe.get_nrworkers())) {
log
@@ -1960,7 +1960,7 @@
sender(), m_ware.value());
return;
}
- warehouse->set_worker_policy(m_ware, m_policy);
+ storage_owner->get_storage()->set_worker_policy(m_ware, m_policy);
} else {
if (!(m_ware < tribe.get_nrwares())) {
log
@@ -1968,7 +1968,7 @@
sender(), m_ware.value());
return;
}
- warehouse->set_ware_policy(m_ware, m_policy);
+ storage_owner->get_storage()->set_ware_policy(m_ware, m_policy);
}
}
}
@@ -1977,20 +1977,20 @@
Cmd_SetStockPolicy::Cmd_SetStockPolicy(StreamRead & des)
: PlayerCommand(0, des.Unsigned8())
{
- m_warehouse = des.Unsigned32();
+ m_storage_owner = des.Unsigned32();
m_isworker = des.Unsigned8();
m_ware = Ware_Index(des.Unsigned8());
- m_policy = static_cast<Warehouse::StockPolicy>(des.Unsigned8());
+ m_policy = static_cast<Storage::StockPolicy>(des.Unsigned8());
}
void Cmd_SetStockPolicy::serialize(StreamWrite & ser)
{
ser.Unsigned8(PLCMD_SETSTOCKPOLICY);
ser.Unsigned8(sender());
- ser.Unsigned32(m_warehouse);
+ ser.Unsigned32(m_storage_owner);
ser.Unsigned8(m_isworker);
ser.Unsigned8(m_ware.value());
- ser.Unsigned8(m_policy);
+ ser.Unsigned8(static_cast<uint8_t>(m_policy));
}
#define PLAYER_CMD_SETSTOCKPOLICY_VERSION 1
@@ -2002,10 +2002,10 @@
if (version != PLAYER_CMD_SETSTOCKPOLICY_VERSION)
throw game_data_error("unknown/unhandled version %u", version);
PlayerCommand::Read(fr, egbase, mol);
- m_warehouse = fr.Unsigned32();
+ m_storage_owner = fr.Unsigned32();
m_isworker = fr.Unsigned8();
m_ware = Ware_Index(fr.Unsigned8());
- m_policy = static_cast<Warehouse::StockPolicy>(fr.Unsigned8());
+ m_policy = static_cast<Storage::StockPolicy>(fr.Unsigned8());
} catch (const std::exception & e) {
throw game_data_error("Cmd_SetStockPolicy: %s", e.what());
}
@@ -2016,10 +2016,10 @@
{
fw.Unsigned8(PLAYER_CMD_SETSTOCKPOLICY_VERSION);
PlayerCommand::Write(fw, egbase, mos);
- fw.Unsigned32(m_warehouse);
+ fw.Unsigned32(m_storage_owner);
fw.Unsigned8(m_isworker);
fw.Unsigned8(m_ware.value());
- fw.Unsigned8(m_policy);
+ fw.Unsigned8(static_cast<uint8_t>(m_policy));
}
}
=== modified file 'src/logic/playercommand.h'
--- src/logic/playercommand.h 2013-07-26 20:19:36 +0000
+++ src/logic/playercommand.h 2013-08-06 10:09:46 +0000
@@ -24,8 +24,8 @@
#include "economy/flag.h"
#include "logic/message_id.h"
#include "logic/path.h"
+#include "logic/storage.h"
#include "logic/trainingsite.h"
-#include "logic/warehouse.h"
#include "logic/worker.h"
namespace Widelands {
@@ -196,7 +196,8 @@
struct Cmd_MilitarySiteSetSoldierPreference : public PlayerCommand {
Cmd_MilitarySiteSetSoldierPreference() : PlayerCommand(), serial(0) {} // For savegame loading
- Cmd_MilitarySiteSetSoldierPreference (const int32_t t, const Player_Number p, Building & b, uint8_t prefs)
+ Cmd_MilitarySiteSetSoldierPreference
+ (const int32_t t, const Player_Number p, Building & b, Garrison::SoldierPref prefs)
: PlayerCommand(t, p), serial(b.serial()), preference(prefs)
{}
@@ -212,7 +213,7 @@
private:
Serial serial;
- uint8_t preference;
+ Garrison::SoldierPref preference;
};
struct Cmd_StartOrCancelExpedition : public PlayerCommand {
Cmd_StartOrCancelExpedition() : PlayerCommand() {} // For savegame loading
@@ -722,13 +723,13 @@
};
/**
- * Command to change the stock policy for a ware or worker in a warehouse.
+ * Command to change the stock policy for a ware or worker in a storage.
*/
struct Cmd_SetStockPolicy : PlayerCommand {
Cmd_SetStockPolicy
(int32_t time, Player_Number p,
- Warehouse & wh, bool isworker, Ware_Index ware,
- Warehouse::StockPolicy policy);
+ StorageOwner & storage_owner, bool isworker, Ware_Index ware,
+ Storage::StockPolicy policy);
virtual uint8_t id() const;
@@ -744,10 +745,10 @@
void Read (FileRead &, Editor_Game_Base &, Map_Map_Object_Loader &);
private:
- Serial m_warehouse;
+ Serial m_storage_owner;
bool m_isworker;
Ware_Index m_ware;
- Warehouse::StockPolicy m_policy;
+ Storage::StockPolicy m_policy;
};
}
=== modified file 'src/logic/production_program.cc'
--- src/logic/production_program.cc 2013-07-26 20:19:36 +0000
+++ src/logic/production_program.cc 2013-08-06 10:09:46 +0000
@@ -32,12 +32,12 @@
#include "logic/findnode.h"
#include "logic/game.h"
#include "logic/game_data_error.h"
+#include "logic/garrison.h"
#include "logic/mapregion.h"
#include "logic/message_queue.h"
#include "logic/player.h"
#include "logic/productionsite.h"
#include "logic/soldier.h"
-#include "logic/soldiercontrol.h"
#include "logic/trainingsite.h"
#include "logic/tribe.h"
#include "logic/worker_program.h"
@@ -1273,8 +1273,13 @@
void ProductionProgram::ActCheck_Soldier::execute
(Game & game, ProductionSite & ps) const
{
- SoldierControl & ctrl = dynamic_cast<SoldierControl &>(ps);
- const std::vector<Soldier *> soldiers = ctrl.presentSoldiers();
+ GarrisonOwner * go = dynamic_cast<GarrisonOwner *>(&ps);
+ if (!go) {
+ log("CGH no garrison owner for %s %u\n", ps.descr().descname().c_str(), ps.serial());
+ return;
+ }
+ Garrison* ga = go->get_garrison();
+ const std::vector<Soldier *> soldiers = ga->presentSoldiers();
const std::vector<Soldier *>::const_iterator soldiers_end = soldiers.end();
ps.molog(" Checking soldier (%u) level %d)\n", attribute, level);
@@ -1359,8 +1364,10 @@
void ProductionProgram::ActTrain::execute
(Game & game, ProductionSite & ps) const
{
- SoldierControl & ctrl = dynamic_cast<SoldierControl &>(ps);
- const std::vector<Soldier *> soldiers = ctrl.presentSoldiers();
+ GarrisonOwner * go = dynamic_cast<GarrisonOwner *>(&ps);
+ assert(go);
+ const Garrison* ga = go->get_garrison();
+ const std::vector<Soldier *> soldiers = ga->presentSoldiers();
const std::vector<Soldier *>::const_iterator soldiers_end =
soldiers.end();
std::vector<Soldier *>::const_iterator it = soldiers.begin();
=== modified file 'src/logic/soldier.cc'
--- src/logic/soldier.cc 2013-08-06 03:28:00 +0000
+++ src/logic/soldier.cc 2013-08-06 10:09:46 +0000
@@ -28,7 +28,6 @@
#include "graphic/graphic.h"
#include "graphic/rendertarget.h"
#include "helper.h"
-#include "logic/attackable.h"
#include "logic/battle.h"
#include "logic/building.h"
#include "logic/checkstep.h"
@@ -38,11 +37,11 @@
#include "logic/findnode.h"
#include "logic/game.h"
#include "logic/game_data_error.h"
+#include "logic/garrison.h"
#include "logic/message_queue.h"
#include "logic/militarysite.h"
#include "logic/player.h"
#include "logic/tribe.h"
-#include "logic/warehouse.h"
#include "map_io/widelands_map_map_object_loader.h"
#include "map_io/widelands_map_map_object_saver.h"
#include "profile/profile.h"
@@ -764,7 +763,7 @@
struct FindNodeOwned {
FindNodeOwned(Player_Number owner) : m_owner(owner)
{};
- bool accept(const Map & map, const FCoords & coords) const {
+ bool accept(const Map &, const FCoords & coords) const {
return (coords.field->get_owned_by() == m_owner);
}
private:
@@ -789,8 +788,6 @@
void Soldier::start_task_attack
(Game & game, Building & building, uint8_t retreat)
{
- //dynamic_cast<const Attackable &>(building);
-
push_task(game, taskAttack);
State & state = top_state();
state.objvar1 = &building;
@@ -960,13 +957,8 @@
// Count remaining defenders
if (enemy) {
- if (upcast(MilitarySite, ms, enemy)) {
- defenders = ms->presentSoldiers().size();
- }
- if (upcast(Warehouse, wh, enemy)) {
- Requirements noreq;
- defenders = wh->count_workers
- (game, wh->tribe().worker_index("soldier"), noreq);
+ if (upcast(GarrisonOwner, garrison_owner, enemy)) {
+ defenders = garrison_owner->get_garrison()->presentSoldiers().size();
}
// Any enemy soldier at baseflag count as defender.
std::vector<Bob *> soldiers;
@@ -996,20 +988,18 @@
BaseImmovable * const newimm = game.map()[state.coords].get_immovable();
upcast(MilitarySite, newsite, newimm);
if (newsite and (&newsite->owner() == &owner())) {
- if (upcast(SoldierControl, ctrl, newsite)) {
- state.objvar1 = 0;
- if
- (ctrl->stationedSoldiers().size() < ctrl->soldierCapacity() and
- location->base_flag().get_position()
- !=
- newsite ->base_flag().get_position())
- {
- molog("[attack] enemy belongs to us now, move in\n");
- pop_task(game);
- set_location(newsite);
- newsite->update_soldier_request();
- return schedule_act(game, 10);
- }
+ state.objvar1 = 0;
+ if
+ (newsite->get_garrison()->stationedSoldiers().size()
+ < newsite->get_garrison()->soldierCapacity() and
+ location->base_flag().get_position()
+ !=
+ newsite ->base_flag().get_position())
+ {
+ molog("[attack] enemy belongs to us now, move in\n");
+ pop_task(game);
+ set_location(newsite);
+ return schedule_act(game, 10);
}
}
}
@@ -1039,12 +1029,12 @@
}
}
- upcast(Attackable, attackable, enemy);
- assert(attackable);
+ upcast(GarrisonOwner, garrison_o, enemy);
+ assert(garrison_o);
molog("[attack] attacking target building\n");
// give the enemy soldier some time to act
- schedule_act(game, attackable->attack(*this) ? 1000 : 10);
+ schedule_act(game, garrison_o->get_garrison()->attack(*this) ? 1000 : 10);
}
void Soldier::attack_pop(Game & game, State &)
@@ -1788,13 +1778,17 @@
CheckStepWalkOn(descr().movecaps(), false),
FindImmovableAttackable());
- container_iterate_const(std::vector<BaseImmovable *>, attackables, i)
+ container_iterate_const(std::vector<BaseImmovable *>, attackables, i) {
+ const BaseImmovable* base_imm = *i.current;
if
- (ref_cast<PlayerImmovable const, BaseImmovable const>(**i.current)
- .get_owner()->player_number()
- ==
- land_owner)
- dynamic_cast<Attackable &>(**i.current).aggressor(*this);
+ (ref_cast<PlayerImmovable const, BaseImmovable const>(*base_imm)
+ .get_owner()->player_number() == land_owner)
+ {
+ if (upcast(const GarrisonOwner, go, base_imm)) {
+ go->get_garrison()->aggressor(*this);
+ }
+ }
+ }
}
}
=== removed file 'src/logic/soldiercontrol.h'
--- src/logic/soldiercontrol.h 2012-02-15 21:25:34 +0000
+++ src/logic/soldiercontrol.h 1970-01-01 00:00:00 +0000
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2008 by the Widelands Development Team
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef SOLDIERCONTROL_H
-#define SOLDIERCONTROL_H
-
-#include <vector>
-
-namespace Widelands {
-
-class Soldier;
-
-/**
- * This interface is implemented by buildings that explicitly house soldiers.
- *
- * It is used to implement queries for building UI and to implement commands
- * that change the soldiers stationed in a building.
- *
- * Soldiers are \em stationed in a building if that building is their
- * \ref Worker::location. Stationed soldiers are \em present in a building
- * if their current position is inside the building. So for a TrainingSite,
- * the two concepts are equal. However, they're different for a MilitarySite,
- * where soldiers can be outside in combat.
- */
-struct SoldierControl {
- /**
- * \return a list of soldiers that are currently present in the building.
- */
- virtual std::vector<Soldier *> presentSoldiers() const = 0;
-
- /**
- * \return a list of soldiers that are currently stationed in the building.
- */
- virtual std::vector<Soldier *> stationedSoldiers() const = 0;
-
- /**
- * \return the minimum number of soldiers that this building can be
- * configured to hold.
- */
- virtual uint32_t minSoldierCapacity() const = 0;
-
- /**
- * \return the maximum number of soldiers that this building can be
- * configured to hold.
- */
- virtual uint32_t maxSoldierCapacity() const = 0;
-
- /**
- * \return the number of soldiers this building is configured to hold
- * right now.
- */
- virtual uint32_t soldierCapacity() const = 0;
-
- /**
- * Sets the capacity for soldiers of this building.
- *
- * New soldiers will be requested and old soldiers will be evicted
- * as necessary.
- */
- virtual void setSoldierCapacity(uint32_t capacity) = 0;
-
- void changeSoldierCapacity(int32_t const difference) {
- uint32_t const old_capacity = soldierCapacity();
- uint32_t const new_capacity =
- std::min
- (static_cast<uint32_t>
- (std::max
- (static_cast<int32_t>(old_capacity) + difference,
- static_cast<int32_t>(minSoldierCapacity()))),
- maxSoldierCapacity());
- if (old_capacity != new_capacity)
- setSoldierCapacity(new_capacity);
- }
-
- /**
- * Evict the given soldier from the building immediately,
- * without changing the building's capacity.
- *
- * \note This has no effect if the soldier is currently involved in a battle
- * or otherwise blocked from leaving the building.
- */
- virtual void dropSoldier(Soldier &) = 0;
-
- /**
- * Add a new soldier into this site. Returns -1 if there is no space
- * for him, 0 on success
- */
- virtual int incorporateSoldier(Editor_Game_Base &, Soldier &) = 0;
-
- /**
- * Remove a soldier from the internal list. Most SoldierControls will be
- * informed by the soldier when it is removed, but WareHouses for example
- * will not.
- */
- virtual int outcorporateSoldier(Editor_Game_Base &, Soldier &) {return 0;}
-
-protected:
- virtual ~SoldierControl() {}
-};
-
-}
-
-#endif // SOLDIERCONTROL_H
=== added file 'src/logic/storage.h'
--- src/logic/storage.h 1970-01-01 00:00:00 +0000
+++ src/logic/storage.h 2013-08-06 10:09:46 +0000
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2002-2004, 2006-2011 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef STORAGE_H
+#define STORAGE_H
+
+#include <vector>
+
+#include "logic/requirements.h"
+#include "logic/wareworker.h"
+#include "logic/widelands.h"
+
+namespace Widelands {
+
+class Building;
+class Worker;
+class Editor_Game_Base;
+class Game;
+class WareInstance;
+class WareList;
+class Player;
+
+/**
+ * A storage represents wares and workers stocks. It is owned by StrorageOwner buildings.
+ * This interface contains various method used to deal with wares requests, prioriies
+ * and disponibility.
+ */
+class Storage {
+public:
+ /**
+ * Each ware and worker type has an associated per-storage
+ * stock policy that defines whether it will be stocked by this
+ * warehouse.
+ *
+ * \note The values of this enum are written directly into savegames,
+ * so be careful when changing them.
+ */
+ enum class StockPolicy : uint8_t {
+ /**
+ * The default policy allows stocking wares without any special priority.
+ */
+ Normal = 0,
+
+ /**
+ * As long as there are warehouses with this policy for a ware, all
+ * available unstocked supplies will be transferred to warehouses
+ * with this policy.
+ */
+ Prefer = 1,
+
+ /**
+ * If a ware has this stock policy, no new items of this ware will enter
+ * the warehouse.
+ */
+ DontStock = 2,
+
+ /**
+ * Like \ref SP_DontStock, but in addition, existing stock of this ware
+ * will be transported out of the warehouse over time.
+ */
+ Remove = 3,
+ };
+
+ /**
+ * \return the player that own this storage
+ */
+ virtual Player & owner() const = 0;
+ /**
+ * \return the wares present in this storage
+ */
+ virtual const WareList & get_wares() const = 0;
+ /**
+ * \return the workers present in this storage
+ */
+ virtual const WareList & get_workers() const = 0;
+ /**
+ * Increase the stock of the specified ware type
+ */
+ virtual void insert_wares (Ware_Index, uint32_t count) = 0;
+ /**
+ * Decrease the stock of the specified ware type
+ */
+ virtual void remove_wares (Ware_Index, uint32_t count) = 0;
+ /**
+ * Increase the stock of the specified worker type
+ */
+ virtual void insert_workers(Ware_Index, uint32_t count) = 0;
+ /**
+ * Decrease the stock of the specified worker type
+ */
+ virtual void remove_workers(Ware_Index, uint32_t count) = 0;
+ /**
+ * Get a specified ware from the storage.
+ * \return the wareinstance
+ */
+ virtual WareInstance & launch_ware(Game &, Ware_Index) = 0;
+ /**
+ * Launch a ware already instanciated
+ */
+ virtual void do_launch_ware(Game &, WareInstance&) = 0;
+ /**
+ * Adds the specified ware to the storage. The ware might
+ * be removed from the game following this call.
+ */
+ virtual void incorporate_ware(Editor_Game_Base &, WareInstance &) = 0;
+ /**
+ * Get the specified worker from the storage.
+ * \return the worker
+ */
+ virtual Worker & launch_worker(Game &, Ware_Index, const Requirements & = Requirements()) = 0;
+ /**
+ * Adds the specified worker to the storage. The worker might
+ * be removed from the game following this call.
+ */
+ virtual void incorporate_worker(Editor_Game_Base &, Worker &) = 0;
+ /**
+ * \return the storage stock policy for the specified ware
+ */
+ virtual StockPolicy get_ware_policy(Ware_Index ware) const = 0;
+ /**
+ * \return the storage stock policy for the specified worker
+ */
+ virtual StockPolicy get_worker_policy(Ware_Index ware) const = 0;
+ /**
+ * \return the sotrage stock policy for the specified ware or worker
+ */
+ virtual StockPolicy get_stock_policy(WareWorker waretype, Ware_Index wareindex) const = 0;
+ /**
+ * Set the storage stock policy for the specified ware
+ */
+ virtual void set_ware_policy(Ware_Index ware, StockPolicy policy) = 0;
+ /**
+ * Set the storage stock policy for the specified worker
+ */
+ virtual void set_worker_policy(Ware_Index ware, StockPolicy policy) = 0;
+ /**
+ * Return true if the storage has all requirement in stock to create
+ * the specified worker
+ */
+ virtual bool can_create_worker(Game& game, Ware_Index ware_index) = 0;
+ /**
+ * Create a worker.
+ */
+ virtual void create_worker(Game& game, Ware_Index worker_idx) = 0;
+ /**
+ * Return the amount of planned worker of the given worker idx
+ */
+ virtual uint32_t get_planned_workers(Game &, Ware_Index index) const = 0;
+ /**
+ * Plan to create the specified workers
+ */
+ virtual void plan_workers(Game &, Ware_Index index, uint32_t amount) = 0;
+ /**
+ * Calculate the supply of wares available to this warehouse in each of the
+ * buildcost items for the given worker.
+ *
+ * This is the current stock plus any incoming transfers.
+ */
+ virtual std::vector<uint32_t> calc_available_for_worker(Game &, Ware_Index index) const = 0;
+};
+
+/**
+ * A Storage owner holds a sorage instance.
+ */
+class StorageOwner {
+public:
+ /**
+ * Return the storage instance
+ */
+ virtual Storage* get_storage() const = 0;
+ /**
+ * Return the building owning the storage
+ */
+ virtual Building* get_building() = 0;
+};
+
+}
+
+#endif
=== added file 'src/logic/storagehandler.cc'
--- src/logic/storagehandler.cc 1970-01-01 00:00:00 +0000
+++ src/logic/storagehandler.cc 2013-08-06 10:09:46 +0000
@@ -0,0 +1,1125 @@
+/*
+ * Copyright (C) 2002-2004, 2006-2011 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "logic/storagehandler.h"
+
+#include <utility>
+
+#include <boost/foreach.hpp>
+
+#include "economy/economy.h"
+#include "economy/flag.h"
+#include "logic/player.h"
+#include "logic/soldier.h"
+#include "upcast.h"
+#include <helper.h>
+
+namespace Widelands {
+
+//************************************************************
+// CLASS Storage Handler
+//************************************************************
+
+StorageHandler::StorageHandler(Building& building)
+: m_building(building),
+ m_supply(new StorageSupply(this))
+{
+}
+
+StorageHandler::~StorageHandler()
+{
+}
+
+
+void StorageHandler::init(Editor_Game_Base& )
+{
+ Ware_Index const nr_wares = owner().tribe().get_nrwares ();
+ Ware_Index const nr_workers = owner().tribe().get_nrworkers();
+ m_supply->set_nrwares (nr_wares);
+ m_supply->set_nrworkers(nr_workers);
+ m_ware_policy.resize(nr_wares.value(), Storage::StockPolicy::Normal);
+ m_worker_policy.resize(nr_workers.value(), Storage::StockPolicy::Normal);
+
+ // Init autospawn
+ const std::vector <Widelands::Ware_Index> worker_types_without_cost =
+ owner().tribe().worker_types_without_cost();
+ BOOST_FOREACH(Ware_Index idx, worker_types_without_cost) {
+ const Worker_Descr & worker_descr = *owner().tribe().get_worker_descr(idx);
+ if (not worker_descr.is_buildable()) {
+ continue;
+ }
+ if (!owner().is_worker_type_allowed(idx)) {
+ continue;
+ }
+ if (worker_descr.buildcost().empty()) {
+ // Workers of this type can be spawned in warehouses. Start it.
+ add_worker_spawn(idx);
+ }
+ }
+}
+
+void StorageHandler::load_finish(Editor_Game_Base& )
+{
+ // Ensure consistency of PlannedWorker requests
+ uint32_t pwidx = 0;
+ while (pwidx < m_planned_workers.size()) {
+ if (!load_finish_planned_workers(m_planned_workers[pwidx])) {
+ m_planned_workers[pwidx].cleanup();
+ m_planned_workers.erase(m_planned_workers.begin() + pwidx);
+ } else {
+ pwidx++;
+ }
+ }
+ // Verify autospawning for free workers
+ const std::vector <Widelands::Ware_Index> worker_types_without_cost =
+ owner().tribe().worker_types_without_cost();
+ BOOST_FOREACH(Ware_Index idx, worker_types_without_cost) {
+ if (!owner().is_worker_type_allowed(idx)) {
+ continue;
+ }
+ if (is_worker_spawn_set(idx)) {
+ continue;
+ }
+ add_worker_spawn(idx);
+ log
+ ("WARNING: player %u is allowed to create worker type %s but his "
+ "%s %u at (%i, %i) does not have spawning set for that "
+ "worker type; setting it to default values\n",
+ owner().player_number(),
+ owner().tribe().get_worker_descr(idx)->descname().c_str(),
+ m_building.descname().c_str(), m_building.serial(),
+ m_building.get_position().x, m_building.get_position().y);
+ }
+}
+
+
+void StorageHandler::cleanup(Editor_Game_Base&)
+{
+ while (!m_planned_workers.empty()) {
+ m_planned_workers.back().cleanup();
+ m_planned_workers.pop_back();
+ }
+}
+
+//TODO return a value so the owner can schedule_act
+uint32_t StorageHandler::act(Game& game)
+{
+ uint32_t gametime = static_cast<uint32_t>(game.get_gametime());
+ uint32_t spawn_act = update_spawns(game, gametime);
+ uint32_t removal_act = update_removals(game, gametime);
+ // Update planned workers; this is to update the request amounts and
+ // check because whether we suddenly can produce a requested worker. This
+ // is mostly previously available wares may become unavailable due to
+ // secondary requests.
+ update_all_planned_workers(game);
+ // Act in 5 sec, or before if timers will run down
+ uint32_t min_act = 5000;
+ if (spawn_act > 0 && spawn_act < min_act) {
+ min_act = spawn_act;
+ }
+ if (removal_act > 0 && removal_act < min_act) {
+ min_act = removal_act;
+ }
+ return min_act;
+}
+
+void StorageHandler::set_economy(Economy* economy)
+{
+ Economy * const old = m_building.get_economy();
+
+ if (old == economy) {
+ return;
+ }
+
+ if (old) {
+ old->remove_storage(*this);
+ }
+
+ m_supply->set_economy(economy);
+
+ container_iterate_const(std::vector<PlannedWorkers>, m_planned_workers, pw_it) {
+ container_iterate_const(std::vector<Request *>, pw_it.current->requests, req_it) {
+ (*req_it.current)->set_economy(economy);
+ }
+ }
+
+ if (economy) {
+ economy->add_storage(*this);
+ }
+}
+
+uint32_t StorageHandler::count_workers(Game& game, Ware_Index idx, const Requirements& req)
+{
+ uint32_t stock = m_supply->stock_workers(idx);
+ if (stock <= 0) {
+ return stock;
+ }
+ uint32_t matching = 0;
+ // Get list of those for which we stored the attributes
+ // This is similar logic than in launch_worker
+ std::vector<const StockedWorkerAtr*> workers_with_atr;
+ BOOST_FOREACH(StockedWorkerAtr& atr, m_stocked_workers_atr) {
+ if (atr.index == idx) {
+ workers_with_atr.push_back(&atr);
+ }
+ }
+ // First check those without atr
+ Worker* w;
+ bool checkpass = false;
+ const Worker_Descr & workerdescr = *owner().tribe().get_worker_descr(idx);
+ if (stock > workers_with_atr.size()) {
+ w = &workerdescr.create(game, owner(), &m_building, m_building.get_position());
+ checkpass = req.check(*w);
+ if (checkpass) {
+ matching += stock - workers_with_atr.size();
+ }
+ w->remove(game);
+ }
+ // Check with our atr
+ // TODO CGH use smarter way of storing atr, maybe with map
+ BOOST_FOREACH(const StockedWorkerAtr* atr, workers_with_atr) {
+ w = create_with_atr(game, *atr);
+ checkpass = req.check(*w);
+ if (checkpass) {
+ matching++;
+ }
+ w->remove(game);
+ }
+ return matching;
+}
+
+
+void StorageHandler::launch_all_workers(Game & game, bool exp_only, const WareList& excluded)
+{
+ if (!exp_only) {
+ for (Ware_Index id = Ware_Index::First(); id < m_supply->get_workers().get_nrwareids(); ++id) {
+ if (excluded.stock(id)) {
+ continue;
+ }
+ const uint32_t stock = m_supply->get_workers().stock(id);
+ if (stock > 0) {
+ for (uint32_t i = 0; i < stock; ++i) {
+ launch_worker(game, id).start_task_leavebuilding(game, true);
+ }
+ }
+ }
+ return;
+ }
+ BOOST_FOREACH(StockedWorkerAtr atr, m_stocked_workers_atr) {
+ if (excluded.stock(atr.index)) {
+ continue;
+ }
+ if (m_supply->get_workers().stock(atr.index) <= 0) {
+ continue;
+ }
+ Worker* w = create_with_atr(game, atr);
+ w->start_task_leavebuilding(game, true);
+ m_supply->remove_workers(atr.index, 1);
+ }
+}
+
+void StorageHandler::add_ware_spawn
+ (const Ware_Index idx, uint32_t interval, uint32_t stock_max, uint32_t counter, bool dont_exceed)
+{
+ if (m_spawn_wares.count(idx)) {
+ remove_ware_spawn(idx);
+ }
+ if (dont_exceed) {
+ std::vector<uint32_t> values = {interval, interval, stock_max};
+ m_spawn_wares.insert(std::make_pair(idx, values));
+ } else {
+ std::vector<uint32_t> values = {interval, interval, stock_max, counter};
+ m_spawn_wares.insert(std::make_pair(idx, values));
+ }
+}
+
+void StorageHandler::remove_ware_spawn(const Ware_Index idx)
+{
+ m_spawn_wares.erase(idx);
+}
+bool StorageHandler::is_ware_spawn_set(Ware_Index idx)
+{
+ return m_spawn_wares.count(idx);
+}
+
+
+void StorageHandler::add_worker_spawn
+ (const Ware_Index idx, uint32_t interval, uint32_t stock_max, uint32_t counter, bool dont_exceed)
+{
+ if (m_spawn_workers.count(idx)) {
+ remove_worker_spawn(idx);
+ }
+ if (dont_exceed) {
+ std::vector<uint32_t> values = {interval, interval, stock_max};
+ m_spawn_workers.insert(std::make_pair(idx, values));
+ } else {
+ std::vector<uint32_t> values = {interval, interval, stock_max, counter};
+ m_spawn_workers.insert(std::make_pair(idx, values));
+ }
+}
+
+void StorageHandler::remove_worker_spawn(const Ware_Index idx)
+{
+ m_spawn_workers.erase(idx);
+}
+bool StorageHandler::is_worker_spawn_set(Ware_Index idx)
+{
+ return m_spawn_workers.count(idx);
+}
+
+//
+//
+// Storage implementation
+//
+//
+
+Player& StorageHandler::owner() const
+{
+ return m_building.owner();
+}
+
+const WareList& StorageHandler::get_wares() const
+{
+ return m_supply->get_wares();
+}
+
+const WareList& StorageHandler::get_workers() const
+{
+ return m_supply->get_workers();
+}
+
+void StorageHandler::insert_wares(Ware_Index idx, uint32_t count)
+{
+ m_supply->add_wares(idx, count);
+}
+
+void StorageHandler::remove_wares(Ware_Index idx, uint32_t count)
+{
+ m_supply->remove_wares(idx, count);
+}
+
+void StorageHandler::insert_workers(Ware_Index idx, uint32_t count)
+{
+ m_supply->add_workers(idx, count);
+}
+
+void StorageHandler::remove_workers(Ware_Index idx, uint32_t count)
+{
+ m_supply->remove_workers(idx, count);
+}
+
+WareInstance& StorageHandler::launch_ware(Game& game, Ware_Index idx)
+{
+ WareInstance & item = *new WareInstance(idx, owner().tribe().get_ware_descr(idx));
+ item.init(game);
+ do_launch_ware(game, item);
+
+ m_supply->remove_wares(idx, 1);
+
+ return item;
+}
+
+
+void StorageHandler::do_launch_ware(Game& game, WareInstance& ware_inst)
+{
+ // Create a carrier
+ Ware_Index const carrierid = owner().tribe().worker_index("carrier");
+ const Worker_Descr & workerdescr = *owner().tribe().get_worker_descr(carrierid);
+
+ Worker & worker = workerdescr.create(game, owner(), &m_building, m_building.get_position());
+
+ // Yup, this is cheating.
+ if (m_supply->stock_workers(carrierid))
+ m_supply->remove_workers(carrierid, 1);
+
+ // Setup the carrier
+ worker.start_task_dropoff(game, ware_inst);
+}
+
+
+void StorageHandler::incorporate_ware(Editor_Game_Base& egbase, WareInstance& item)
+{
+ m_supply->add_wares(item.descr_index(), 1);
+ return item.destroy(egbase);
+}
+
+Worker& StorageHandler::launch_worker(Game& game, Ware_Index idx, const Requirements& req)
+{
+ do {
+ uint32_t stock = m_supply->stock_workers(idx);
+ if (stock > 0) {
+ // Get list of those for which we stored the attributes, as pointers to actual objects
+ // TODO smarter storage for atrs
+ std::vector<const StockedWorkerAtr*> workers_with_atr;
+ for
+ (std::vector<StockedWorkerAtr>::iterator it = m_stocked_workers_atr.begin();
+ it != m_stocked_workers_atr.end(); ++it)
+ {
+ if ((*it).index == idx) {
+ workers_with_atr.push_back(&(*it));
+ }
+ }
+ // First check if one without atr is enough
+ Worker* w;
+ if (stock > workers_with_atr.size()) {
+ const Worker_Descr & workerdescr = *owner().tribe().get_worker_descr(idx);
+ w = &workerdescr.create(game, owner(), &m_building, m_building.get_position());
+ if (req.check(*w)) {
+ m_supply->remove_workers(idx, 1);
+ return *w;
+ }
+ }
+ // Check with our atr
+ BOOST_FOREACH(const StockedWorkerAtr* atr, workers_with_atr) {
+ w = create_with_atr(game, *atr);
+ if (req.check(*w)) {
+ // We need to find back our atr in original vector to erase it
+ bool removed = false;
+ for
+ (std::vector<StockedWorkerAtr>::iterator it = m_stocked_workers_atr.begin();
+ it != m_stocked_workers_atr.end(); ++it)
+ {
+ if (&(*it) == atr) {
+ m_stocked_workers_atr.erase(it);
+ removed = true;
+ break;
+ }
+ }
+ assert(removed);
+ m_supply->remove_workers(idx, 1);
+ return *w;
+ }
+ }
+ }
+ // Check if we got the tools to create a new one
+ if (can_create_worker(game, idx)) {
+ // don't want to use an upgraded worker, so create new one.
+ create_worker(game, idx);
+ } else {
+ idx = owner().tribe().get_worker_descr(idx)->becomes();
+ }
+ } while (idx != Ware_Index::Null());
+
+ throw wexception
+ ("StorageHandler::launch_worker: worker does not actually exist");
+}
+
+void StorageHandler::incorporate_worker(Editor_Game_Base& egbase, Worker& w)
+{
+ assert(w.get_owner() == &owner());
+ // Rescue carried ware
+ if (WareInstance * const item = w.fetch_carried_item(egbase)) {
+ incorporate_ware(egbase, *item);
+ }
+ // Add to supply
+ Ware_Index worker_index = owner().tribe().worker_index(w.name().c_str());
+ m_supply->add_workers(worker_index, 1);
+
+ // Store the attributes.
+ // FIXME CGH handle soldiers : hp & healing
+ StockedWorkerAtr* atr = store_worker_atr(w);
+ if (atr != nullptr) {
+ m_stocked_workers_atr.push_back(*atr);
+ }
+ // Destroy the instance
+ w.remove(egbase);
+}
+
+Storage::StockPolicy StorageHandler::get_ware_policy(Ware_Index ware) const
+{
+ assert(ware.value() < m_ware_policy.size());
+ return m_ware_policy[ware.value()];
+}
+
+Storage::StockPolicy StorageHandler::get_worker_policy(Ware_Index ware) const
+{
+ assert(ware.value() < m_worker_policy.size());
+ return m_worker_policy[ware.value()];
+}
+
+Storage::StockPolicy StorageHandler::get_stock_policy(WareWorker waretype, Ware_Index wareindex) const
+{
+ if (waretype == wwWORKER)
+ return get_worker_policy(wareindex);
+ else
+ return get_ware_policy(wareindex);
+}
+
+void StorageHandler::set_ware_policy(Ware_Index ware, Storage::StockPolicy policy)
+{
+ assert(ware.value() < m_ware_policy.size());
+ m_ware_policy[ware.value()] = policy;
+}
+
+void StorageHandler::set_worker_policy(Ware_Index ware, Storage::StockPolicy policy)
+{
+ assert(ware.value() < m_worker_policy.size());
+ m_worker_policy[ware.value()] = policy;
+}
+
+bool StorageHandler::can_create_worker(Game&, Ware_Index worker_idx)
+{
+ if (not (worker_idx < m_supply->get_workers().get_nrwareids())) {
+ throw wexception
+ ("worker type %d does not exists (max is %d)",
+ worker_idx.value(), m_supply->get_workers().get_nrwareids().value());
+ }
+
+ const Worker_Descr & w_desc = *owner().tribe().get_worker_descr(worker_idx);
+ assert(&w_desc);
+ if (not w_desc.is_buildable()) {
+ return false;
+ }
+
+ // see if we have the resources
+ const Worker_Descr::Buildcost & buildcost = w_desc.buildcost();
+ container_iterate_const(Worker_Descr::Buildcost, buildcost, it) {
+ const std::string & input_name = it.current->first;
+ if (Ware_Index id_w = owner().tribe().ware_index(input_name)) {
+ if (m_supply->stock_wares (id_w) < it.current->second)
+ return false;
+ } else if ((id_w = owner().tribe().worker_index(input_name))) {
+ if (m_supply->stock_workers(id_w) < it.current->second)
+ return false;
+ } else
+ throw wexception
+ ("worker type %s needs \"%s\" to be built but that is neither "
+ "a ware type nor a worker type defined in the tribe %s",
+ w_desc.descname().c_str(), input_name.c_str(),
+ owner().tribe().name().c_str());
+ }
+ return true;
+}
+
+void StorageHandler::create_worker(Game& game, Ware_Index worker_idx)
+{
+ assert(can_create_worker (game, worker_idx));
+
+ const Worker_Descr & w_desc = *owner().tribe().get_worker_descr(worker_idx);
+ const Worker_Descr::Buildcost & buildcost = w_desc.buildcost();
+ container_iterate_const(Worker_Descr::Buildcost, buildcost, i) {
+ const std::string & input = i.current->first;
+ if (Ware_Index const id_ware = owner().tribe().ware_index(input)) {
+ remove_wares (id_ware, i.current->second);
+ //update statistic accordingly
+ owner().ware_consumed(id_ware, i.current->second);
+ } else
+ remove_workers(owner().tribe().safe_worker_index(input), i.current->second);
+ }
+
+ incorporate_worker(game, w_desc.create(game, owner(), &m_building, m_building.get_position()));
+
+ // Update PlannedWorkers::amount here if appropriate, because this function
+ // may have been called directly by the Economy.
+ // Do not update anything else about PlannedWorkers here, because this
+ // function is called by _update_planned_workers, so avoid recursion
+ container_iterate(std::vector<PlannedWorkers>, m_planned_workers, pw_it) {
+ if (pw_it.current->index == worker_idx && pw_it.current->amount) {
+ pw_it.current->amount--;
+ }
+ }
+}
+
+uint32_t StorageHandler::get_planned_workers(Game&, Ware_Index index) const
+{
+ container_iterate_const(std::vector<PlannedWorkers>, m_planned_workers, i) {
+ if (i.current->index == index)
+ return i.current->amount;
+ }
+
+ return 0;
+}
+
+void StorageHandler::plan_workers(Game& game, Ware_Index index, uint32_t amount)
+{
+ PlannedWorkers * pw = 0;
+
+ container_iterate(std::vector<PlannedWorkers>, m_planned_workers, i) {
+ if (i.current->index == index) {
+ pw = &*i.current;
+ break;
+ }
+ }
+
+ if (!pw) {
+ if (!amount)
+ return;
+
+ m_planned_workers.push_back(PlannedWorkers());
+ pw = &m_planned_workers.back();
+ pw->index = index;
+ pw->amount = 0;
+
+ const Worker_Descr & w_desc = *owner().tribe().get_worker_descr(pw->index);
+ const Worker_Descr::Buildcost & cost = w_desc.buildcost();
+ container_iterate_const(Worker_Descr::Buildcost, cost, cost_it) {
+ const std::string & input_name = cost_it.current->first;
+
+ if (Ware_Index id_w = owner().tribe().ware_index(input_name)) {
+ pw->requests.push_back
+ (new Request
+ (m_building, id_w, &StorageHandler::planned_worker_callback, wwWARE));
+ } else if ((id_w = owner().tribe().worker_index(input_name))) {
+ pw->requests.push_back
+ (new Request
+ (m_building, id_w, &StorageHandler::planned_worker_callback, wwWORKER));
+ } else
+ throw wexception
+ ("plan_workers: bad buildcost '%s'", input_name.c_str());
+ }
+ }
+
+ pw->amount = amount;
+ update_planned_workers(game, *pw);
+}
+
+std::vector< uint32_t > StorageHandler::calc_available_for_worker(Game&, Ware_Index index) const
+{
+ const Worker_Descr & w_desc = *owner().tribe().get_worker_descr(index);
+ const Worker_Descr::Buildcost & cost = w_desc.buildcost();
+ std::vector<uint32_t> available;
+
+ container_iterate_const(Worker_Descr::Buildcost, cost, bc) {
+ const std::string & input_name = bc.current->first;
+ if (Ware_Index id_w = owner().tribe().ware_index(input_name)) {
+ available.push_back(get_wares().stock(id_w));
+ } else if ((id_w = owner().tribe().worker_index(input_name))) {
+ available.push_back(get_workers().stock(id_w));
+ } else
+ throw wexception
+ ("StorageHandler::calc_available_for_worker: buildcost inconsistency '%s'",
+ input_name.c_str());
+ }
+
+ container_iterate_const(std::vector<PlannedWorkers>, m_planned_workers, i) {
+ if (i.current->index == index) {
+ assert(available.size() == i.current->requests.size());
+
+ for (uint32_t idx = 0; idx < available.size(); ++idx)
+ available[idx] += i.current->requests[idx]->get_num_transfers();
+ }
+ }
+
+ return available;
+}
+
+
+//
+//
+//
+// Private methods
+//
+//
+
+uint32_t StorageHandler::update_spawns(Game&, uint32_t gametime)
+{
+ uint32_t min_act = 0;
+ // Update spawnings
+ SpawnMapType::iterator it;
+ for (it = m_spawn_wares.begin(); it != m_spawn_wares.end();) {
+ Ware_Index idx = (*it).first;
+ std::vector<uint32_t> values = (*it).second;
+ bool dont_exceed = values.size() < 4;
+ bool infinite = dont_exceed || values[3] == 0;
+ uint32_t stock = m_supply->stock_wares(idx);
+ uint32_t stock_max = values[2];
+ // Skip if max stock excessed for non infinite spawns
+ if (stock_max > 0 && stock >= stock_max && !dont_exceed) {
+ ++it;
+ continue;
+ }
+ // update timer
+ uint32_t* next_act = &((*it).second[0]);
+ if (*next_act > gametime) {
+ ++it;
+ continue;
+ }
+ uint32_t interval = values[1];
+ while (*next_act <= gametime) {
+ *next_act += interval;
+ }
+ if (!infinite) {
+ // decrease counter
+ uint32_t* counter_p = &((*it).second[3]);
+ (*counter_p)--;
+ m_supply->add_wares(idx, 1);
+ if ((*counter_p) == 0) {
+ m_spawn_wares.erase(it++);
+ continue;
+ }
+ } else {
+ // infinte spawns
+ if (stock < stock_max) {
+ m_supply->add_wares(idx, 1);
+ } else if (stock > stock_max && dont_exceed) {
+ m_supply->remove_wares(idx, 1);
+ }
+ }
+ ++it;
+ uint32_t time_till_next_act = *next_act - gametime;
+ min_act = (min_act == 0 ? time_till_next_act :
+ min_act > time_till_next_act ? time_till_next_act : min_act);
+ }
+ for (it = m_spawn_workers.begin(); it != m_spawn_workers.end();) {
+ Ware_Index idx = (*it).first;
+ std::vector<uint32_t> values = (*it).second;
+ bool dont_exceed = values.size() < 4;
+ bool infinite = dont_exceed || values[3] == 0;
+ uint32_t stock = m_supply->stock_workers(idx);
+ uint32_t stock_max = values[2];
+ // Skip if max stock excessed for non infinite spawns
+ if (stock_max > 0 && stock >= stock_max && !dont_exceed) {
+ ++it;
+ continue;
+ }
+ // update timer
+ uint32_t* next_act = &((*it).second[0]);
+ if (*next_act > gametime) {
+ ++it;
+ continue;
+ }
+ uint32_t interval = values[1];
+ while (*next_act <= gametime) {
+ *next_act += interval;
+ }
+ if (!infinite) {
+ // decrease counter
+ uint32_t* counter_p = &((*it).second[3]);
+ (*counter_p)--;
+ m_supply->add_workers(idx, 1);
+ if ((*counter_p) == 0) {
+ m_spawn_workers.erase(it++);
+ continue;
+ }
+ } else {
+ // infinte spawns
+ if (stock < stock_max) {
+ m_supply->add_workers(idx, 1);
+ } else if (stock > stock_max && dont_exceed) {
+ m_supply->remove_workers(idx, 1);
+ }
+ }
+ ++it;
+ uint32_t time_till_next_act = *next_act - gametime;
+ min_act = (min_act == 0 ? time_till_next_act :
+ min_act > time_till_next_act ? time_till_next_act : min_act);
+ }
+
+ return min_act;
+}
+
+uint32_t StorageHandler::update_removals(Game& game, uint32_t gametime)
+{
+ if (m_removal_next_act > gametime) {
+ return gametime - m_removal_next_act;
+ }
+ while (m_removal_next_act <= gametime) {
+ m_removal_next_act += STORAGE_REMOVAL_INTERVAL;
+ }
+ if (m_building.base_flag().current_items() < m_building.base_flag().total_capacity() / 2) {
+ for (Ware_Index ware = Ware_Index::First(); ware.value() < m_ware_policy.size(); ++ware) {
+ if (get_ware_policy(ware) != StockPolicy::Remove || !get_wares().stock(ware)) {
+ continue;
+ }
+ launch_ware(game, ware);
+ break;
+ }
+ }
+
+ for (Ware_Index widx = Ware_Index::First(); widx.value() < m_worker_policy.size(); ++widx) {
+ if (get_worker_policy(widx) != StockPolicy::Remove || !get_workers().stock(widx)) {
+ continue;
+ }
+ Worker & worker = launch_worker(game, widx);
+ worker.start_task_leavebuilding(game, true);
+ break;
+ }
+ return gametime - m_removal_next_act;
+}
+
+void StorageHandler::update_all_planned_workers(Game& game)
+{
+ uint32_t idx = 0;
+ while (idx < m_planned_workers.size()) {
+ update_planned_workers(game, m_planned_workers[idx]);
+
+ if (!m_planned_workers[idx].amount) {
+ m_planned_workers[idx].cleanup();
+ m_planned_workers.erase(m_planned_workers.begin() + idx);
+ } else {
+ idx++;
+ }
+ }
+}
+
+void StorageHandler::update_planned_workers
+ (Game& game, StorageHandler::PlannedWorkers& planned_workers)
+{
+ const Tribe_Descr& tribe_descr = owner().tribe();
+ const Worker_Descr & w_desc = *tribe_descr.get_worker_descr(planned_workers.index);
+ const Worker_Descr::Buildcost & cost = w_desc.buildcost();
+
+ while (planned_workers.amount && can_create_worker(game, planned_workers.index)) {
+ create_worker(game, planned_workers.index);
+ }
+
+ uint32_t idx = 0;
+ container_iterate_const(Worker_Descr::Buildcost, cost, cost_it) {
+ const std::string & input_name = cost_it.current->first;
+ uint32_t supply;
+
+ if (Ware_Index id_w = tribe_descr.ware_index(input_name)) {
+ supply = m_supply->stock_wares(id_w);
+ } else if ((id_w = tribe_descr.worker_index(input_name))) {
+ supply = m_supply->stock_workers(id_w);
+ } else {
+ throw wexception
+ ("_update_planned_workers: bad buildcost '%s'", input_name.c_str());
+ }
+
+ if (supply >= planned_workers.amount * cost_it.current->second) {
+ planned_workers.requests[idx]->set_count(0);
+ } else {
+ planned_workers.requests[idx]->set_count
+ (planned_workers.amount * cost_it.current->second - supply);
+ }
+ ++idx;
+ }
+
+ while (planned_workers.requests.size() > idx) {
+ delete planned_workers.requests.back();
+ planned_workers.requests.pop_back();
+ }
+}
+
+StorageHandler::StockedWorkerAtr* StorageHandler::store_worker_atr(Worker& w)
+{
+ if (upcast(Soldier, s, &w)) {
+ if
+ (!s->get_attack_level()
+ && !s->get_defense_level()
+ && !s->get_evade_level()
+ && !s->get_hp_level())
+ {
+ return nullptr;
+ }
+ StockedWorkerAtr* atr = new StockedWorkerAtr();
+ atr->atck_lvl = s->get_attack_level();
+ atr->defense_lvl = s->get_defense_level();
+ atr->evade_lvl = s->get_evade_level();
+ atr->exp_or_hp_lvl = s->get_hp_level();
+ atr->index = w.descr().worker_index();
+ atr->descr = &w.descr();
+ return atr;
+ }
+ // Normal worker - only exp
+ if (w.get_current_experience() <= 0) {
+ return nullptr;
+ }
+ StockedWorkerAtr* atr = new StockedWorkerAtr();
+ atr->exp_or_hp_lvl = w.get_current_experience();
+ atr->index = w.descr().worker_index();
+ atr->descr = &w.descr();
+ return atr;
+}
+
+Worker* StorageHandler::create_with_atr(Game& game, StockedWorkerAtr atr)
+{
+ Worker* w = &atr.descr->create(game, owner(), &m_building, m_building.get_position());
+ if (upcast(Soldier, s, w)) {
+ s->set_attack_level(atr.atck_lvl);
+ s->set_defense_level(atr.defense_lvl);
+ s->set_evade_level(atr.evade_lvl);
+ s->set_hp_level(atr.exp_or_hp_lvl);
+ return w;
+ }
+ w->set_experience(atr.exp_or_hp_lvl);
+ return w;
+}
+
+
+void StorageHandler::PlannedWorkers::cleanup()
+{
+ while (!requests.empty()) {
+ delete requests.back();
+ requests.pop_back();
+ }
+}
+
+void StorageHandler::planned_worker_callback
+ (Game& game, Request&, const Ware_Index ware, Worker* const w, PlayerImmovable& target)
+{
+ upcast(StorageOwner, owner, &target);
+ upcast(StorageHandler, sh, owner->get_storage());
+ if (w) {
+ w->schedule_incorporate(game);
+ } else {
+ sh->m_supply->add_wares(ware, 1);
+
+ // This ware may be used to build planned workers,
+ // so it seems like a good idea to update the associated requests
+ // and use the ware before it is sent away again.
+ sh->update_all_planned_workers(game);
+ }
+}
+
+/**
+ * Try to bring the given \ref PlannedWorkers up to date with our game data.
+ * Return \c false if \p pw cannot be salvaged.
+ */
+bool StorageHandler::load_finish_planned_workers(PlannedWorkers & pw)
+{
+ if (!pw.index || !(pw.index < m_supply->get_workers().get_nrwareids()))
+ return false;
+
+ const Worker_Descr * w_desc = owner().tribe().get_worker_descr(pw.index);
+ if (!w_desc || !w_desc->is_buildable())
+ return false;
+
+ const Worker_Descr::Buildcost & cost = w_desc->buildcost();
+ uint32_t idx = 0;
+
+ for
+ (Worker_Descr::Buildcost::const_iterator cost_it = cost.begin();
+ cost_it != cost.end(); ++cost_it, ++idx)
+ {
+ WareWorker type;
+ Ware_Index ware;
+
+ if ((ware = owner().tribe().ware_index(cost_it->first)))
+ type = wwWARE;
+ else if ((ware = owner().tribe().worker_index(cost_it->first)))
+ type = wwWORKER;
+ else
+ return false;
+
+ if (idx < pw.requests.size()) {
+ if
+ (pw.requests[idx]->get_type() == type &&
+ pw.requests[idx]->get_index() == ware)
+ continue;
+
+ std::vector<Request *>::iterator req_it =
+ pw.requests.begin() + idx + 1;
+ while (req_it != pw.requests.end()) {
+ if ((*req_it)->get_type() == type && (*req_it)->get_index() == ware)
+ break;
+ ++req_it;
+ }
+
+ if (req_it != pw.requests.end()) {
+ std::swap(*req_it, pw.requests[idx]);
+ continue;
+ }
+ }
+
+ log
+ ("_load_finish_planned_worker: old savegame: "
+ "need to create new request for '%s'\n",
+ cost_it->first.c_str());
+ pw.requests.insert
+ (pw.requests.begin() + idx,
+ new Request(m_building, ware, &StorageHandler::planned_worker_callback, type));
+ }
+
+ while (pw.requests.size() > idx) {
+ log
+ ("_load_finish_planned_worker: old savegame: "
+ "removing outdated request.\n");
+ delete pw.requests.back();
+ pw.requests.pop_back();
+ }
+
+ return true;
+}
+
+
+// *************************************************************
+//
+// Class StorageSupply
+//
+// *************************************************************
+
+StorageSupply::StorageSupply(StorageHandler* handler)
+: m_handler(*handler),
+ m_economy(nullptr)
+{
+}
+
+StorageSupply::~StorageSupply()
+{
+ if (m_economy) {
+ log
+ ("StorageSupply::~StorageSupply: %s %u still belongs to "
+ "an economy", m_handler.get_building().descname().c_str(),
+ m_handler.get_building().serial());
+ set_economy(nullptr);
+ }
+
+ // We're removed from the Economy. Therefore, the wares can simply
+ // be cleared out. The global inventory will be okay.
+ m_wares .clear();
+ m_workers.clear();
+}
+
+void StorageSupply::set_economy(Economy* const e)
+{
+ if (e == m_economy)
+ return;
+
+ if (m_economy) {
+ m_economy->remove_supply(*this);
+ for (Ware_Index i = Ware_Index::First(); i < m_wares.get_nrwareids(); ++i)
+ if (m_wares.stock(i))
+ m_economy->remove_wares(i, m_wares.stock(i));
+ for (Ware_Index i = Ware_Index::First(); i < m_workers.get_nrwareids(); ++i)
+ if (m_workers.stock(i))
+ m_economy->remove_workers(i, m_workers.stock(i));
+ }
+
+ m_economy = e;
+
+ if (m_economy) {
+ for (Ware_Index i = Ware_Index::First(); i < m_wares.get_nrwareids(); ++i)
+ if (m_wares.stock(i))
+ m_economy->add_wares(i, m_wares.stock(i));
+ for (Ware_Index i = Ware_Index::First(); i < m_workers.get_nrwareids(); ++i)
+ if (m_workers.stock(i))
+ m_economy->add_workers(i, m_workers.stock(i));
+ m_economy->add_supply(*this);
+ }
+}
+
+void StorageSupply::set_nrwares(Ware_Index i)
+{
+ assert(Ware_Index::First() == m_wares.get_nrwareids());
+ m_wares.set_nrwares(i);
+}
+void StorageSupply::set_nrworkers(Ware_Index i)
+{
+ assert(Ware_Index::First() == m_workers.get_nrwareids());
+ m_workers.set_nrwares(i);
+}
+
+void StorageSupply::add_wares(Ware_Index id, uint32_t count)
+{
+ if (!count)
+ return;
+
+ if (m_economy) // No economies in the editor
+ m_economy->add_wares(id, count);
+ m_wares.add(id, count);
+}
+void StorageSupply::remove_wares(Ware_Index id, uint32_t count)
+{
+ if (!count)
+ return;
+
+ m_wares.remove(id, count);
+ if (m_economy) // No economies in the editor
+ m_economy->remove_wares(id, count);
+}
+void StorageSupply::add_workers(Ware_Index id, uint32_t count)
+{
+ if (!count)
+ return;
+
+ if (m_economy) // No economies in the editor
+ m_economy->add_workers(id, count);
+ m_workers.add(id, count);
+}
+void StorageSupply::remove_workers(Ware_Index id, uint32_t count)
+{
+ if (!count)
+ return;
+
+ m_workers.remove(id, count);
+ if (m_economy) // No economies in the editor
+ m_economy->remove_workers(id, count);
+}
+
+PlayerImmovable* StorageSupply::get_position(Game&)
+{
+ return &m_handler.get_building();
+}
+
+bool StorageSupply::is_active() const throw ()
+{
+ return false;
+}
+
+bool StorageSupply::has_storage() const throw ()
+{
+ return true;
+}
+
+void StorageSupply::get_ware_type(WareWorker&, Ware_Index&) const
+{
+ throw wexception
+ ("StorageSupply::get_ware_type: calling this is nonsensical");
+}
+
+void StorageSupply::send_to_storage(Game&, StorageOwner*)
+{
+ throw wexception("StorageSupply::send_to_storage: should never be called");
+}
+
+uint32_t StorageSupply::nr_supplies(const Game&, const Request& req) const
+{
+ // out count_worker method create a worker instance, so we need non-const game
+ Game& non_const_game = ref_cast<Game, Editor_Game_Base>
+ (m_handler.get_building().get_owner()->egbase());
+ if (req.get_type() == wwWORKER)
+ return
+ m_handler.count_workers
+ (non_const_game, req.get_index(), req.get_requirements());
+
+ // Calculate how many wares can be sent out - it might be that we need them
+ // ourselves. E.g. for hiring new soldiers.
+ int32_t const x = m_wares.stock(req.get_index());
+ // only mark an item of that type as available, if the priority of the
+ // request + number of that wares in warehouse is > priority of request
+ // of *this* warehouse + 1 (+1 is important, as else the ware would directly
+ // be taken back to the warehouse as the request of the warehouse would be
+ // highered and would have the same value as the original request)
+ int32_t const y =
+ x + (req.get_priority(0) / 100)
+ - (m_handler.get_building().get_priority(wwWARE, req.get_index()) / 100) - 1;
+ // But the number should never be higher than the number of wares available
+ if (y > x)
+ return x;
+ return (x > 0) ? x : 0;
+}
+
+WareInstance& StorageSupply::launch_item(Game& game, const Request& req)
+{
+ if (req.get_type() != wwWARE)
+ throw wexception("WarehouseSupply::launch_item: called for non-ware request");
+ if (!m_wares.stock(req.get_index()))
+ throw wexception("WarehouseSupply::launch_item: called for non-existing ware");
+
+ return m_handler.launch_ware(game, req.get_index());
+}
+
+Worker& StorageSupply::launch_worker(Game& game, const Request& req)
+{
+ return m_handler.launch_worker(game, req.get_index(), req.get_requirements());
+}
+
+}
=== added file 'src/logic/storagehandler.h'
--- src/logic/storagehandler.h 1970-01-01 00:00:00 +0000
+++ src/logic/storagehandler.h 2013-08-06 10:09:46 +0000
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2002-2004, 2006-2011 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef STORAGEHANDLER_H
+#define STORAGEHANDLER_H
+
+#include <memory>
+
+#include "economy/supply.h"
+#include "logic/requirements.h"
+#include "logic/storage.h"
+#include "logic/warelist.h"
+
+#define STORAGE_REMOVAL_INTERVAL 4000
+
+namespace Widelands {
+
+class Worker_Descr;
+
+class Economy;
+class StorageSupply;
+
+class StorageHandler: public Storage {
+friend struct Map_Buildingdata_Data_Packet;
+public:
+ // Spawning. vector is {next_act, interval, stock_max, [counter]}
+ typedef std::map<Ware_Index, std::vector<uint32_t>> SpawnMapType;
+
+ StorageHandler(Building& building);
+ virtual ~StorageHandler();
+ /**
+ * Must be called once
+ */
+ void init(Editor_Game_Base &);
+ /**
+ * To be called after loading
+ */
+ void load_finish(Editor_Game_Base &);
+ /**
+ * Cleanup handled objects and requests
+ */
+ void cleanup(Editor_Game_Base &);
+ /**
+ * Must be called regularly
+ * \return the time, from now, where a next act should occur
+ */
+ uint32_t act(Game &);
+ /**
+ * Change the economy
+ */
+ void set_economy(Economy *);
+ /**
+ * Return the number of workers satisfying the given requirement that this
+ * storage has in stock
+ */
+ uint32_t count_workers(Game & game, Ware_Index ware, const Requirements & req = Requirements());
+ /**
+ * Launch all workers in the storage.
+ * \param excluded : A WareList with some non-zero value for the
+ * worker type to exclude
+ */
+ void launch_all_workers(Game& game, bool exp_only = false, const WareList& excluded = WareList());
+ /**
+ * Introduce auto spawning of the specified ware
+ * \param idx The ware to autospawn
+ * \param interval The interval between spawns. default to 2500
+ * \param stock_max While the stock is above this value, spawning is disabled. Default to 100.
+ * 0 for infinite spawning
+ * \param counter The amount of wares to spawn. default to 0 (infinite).
+ * \param dont_excdeed if true (default), ware will be removed as well to not exceed stock_max
+ */
+ void add_ware_spawn
+ (Ware_Index idx, uint32_t interval = 2500, uint32_t stock_max = 100,
+ uint32_t counter = 0, bool dont_exceed = true);
+ /**
+ * Disable autospawning of the specified ware
+ */
+ void remove_ware_spawn(Ware_Index idx);
+ bool is_ware_spawn_set(Ware_Index idx);
+ /**
+ * Introduce auto spawning of the specified worker
+ * \param idx The worker to autospawn
+ * \param interval The interval between spawns. default to 2500 (2,5s)
+ * \param stock_max While the stock is above this value, spawning is disabled. Default to 100.
+ * 0 for infinite spawning
+ * \param counter The amount of workers to spawn. default to 0.
+ * \param dont_excdeed if true (default), ware will be removed as well to not exceed stock_max
+ */
+ void add_worker_spawn
+ (Ware_Index idx, uint32_t interval = 2500, uint32_t stock_max = 100,
+ uint32_t counter = 0, bool dont_exceed = true);
+ /**
+ * Remove autospawning of the specified worker
+ */
+ void remove_worker_spawn(Ware_Index idx);
+ bool is_worker_spawn_set(Ware_Index idx);
+ /**
+ * «return the building associated with this storage
+ */
+ Building& get_building() const {return m_building;}
+
+ // Sorage implementation
+ virtual Player & owner() const;
+ virtual const WareList & get_wares() const;
+ virtual const WareList & get_workers() const;
+ virtual void insert_wares (Ware_Index, uint32_t count);
+ virtual void remove_wares (Ware_Index, uint32_t count);
+ virtual void insert_workers(Ware_Index, uint32_t count);
+ virtual void remove_workers(Ware_Index, uint32_t count);
+ virtual WareInstance & launch_ware(Game &, Ware_Index);
+ virtual void do_launch_ware(Game &, WareInstance&);
+ virtual void incorporate_ware(Editor_Game_Base &, WareInstance &);
+ virtual Worker & launch_worker(Game &, Ware_Index, const Requirements & = Requirements());
+ virtual void incorporate_worker(Editor_Game_Base &, Worker &);
+ virtual StockPolicy get_ware_policy(Ware_Index ware) const;
+ virtual StockPolicy get_worker_policy(Ware_Index ware) const;
+ virtual StockPolicy get_stock_policy(WareWorker waretype, Ware_Index wareindex) const;
+ virtual void set_ware_policy(Ware_Index ware, StockPolicy policy);
+ virtual void set_worker_policy(Ware_Index ware, StockPolicy policy);
+ virtual bool can_create_worker(Game& game, Ware_Index worker_idx);
+ virtual void create_worker(Game& game, Ware_Index worker_idx);
+ virtual uint32_t get_planned_workers(Game &, Ware_Index index) const;
+ virtual void plan_workers(Game &, Ware_Index index, uint32_t amount);
+ virtual std::vector<uint32_t> calc_available_for_worker(Game &, Ware_Index index) const;
+private:
+ /**
+ * Plan to produce a certain worker type in this warehouse. This means
+ * requesting all the necessary wares, if multiple different wares types are
+ * needed.
+ */
+ struct PlannedWorkers {
+ /// Index of the worker type we plan to create
+ Ware_Index index;
+ /// How many workers of this type are we supposed to create?
+ uint32_t amount;
+ /// Requests to obtain the required build costs
+ std::vector<Request *> requests;
+ void cleanup();
+ };
+ /**
+ * Store attributes of stocked worker so they can be removed from the game
+ * without loosing experience & co informations
+ */
+ struct StockedWorkerAtr {
+ Ware_Index index;
+ const Worker_Descr* descr;
+ uint32_t atck_lvl;
+ uint32_t evade_lvl;
+ uint32_t defense_lvl;
+ uint32_t exp_or_hp_lvl; // experience or hp level for soldiers
+ };
+
+ // return time for next act
+ uint32_t update_spawns(Game& game, uint32_t gametime);
+ // return time for next act
+ uint32_t update_removals(Game & game, uint32_t gametime);
+ void update_all_planned_workers(Game& game);
+ void update_planned_workers(Game& game, PlannedWorkers& planned_workers);
+ StockedWorkerAtr* store_worker_atr(Worker& w);
+ Worker* create_with_atr(Game& game, StockedWorkerAtr atr);
+ static void planned_worker_callback
+ (Game & game,
+ Request &,
+ Ware_Index const ware,
+ Worker * const w,
+ PlayerImmovable & target);
+ bool load_finish_planned_workers(PlannedWorkers & pw);
+
+ //fields
+ Building & m_building;
+ std::unique_ptr<StorageSupply> m_supply;
+ // policies
+ std::vector<StockPolicy> m_ware_policy;
+ std::vector<StockPolicy> m_worker_policy;
+ // Spawning
+ SpawnMapType m_spawn_wares;
+ SpawnMapType m_spawn_workers;
+ // ware removal
+ uint32_t m_removal_next_act;
+ // planned workers
+ std::vector<PlannedWorkers> m_planned_workers;
+ // Attributes of stocked workers
+ std::vector<StockedWorkerAtr> m_stocked_workers_atr;
+};
+
+/**
+ * A supply implementation for storages
+ */
+class StorageSupply : public Supply {
+public:
+ StorageSupply(StorageHandler* handler);
+ virtual ~StorageSupply();
+
+ void set_economy(Economy *);
+
+ void set_nrwares (Ware_Index);
+ void set_nrworkers(Ware_Index);
+
+ const WareList & get_wares () const {return m_wares;}
+ const WareList & get_workers() const {return m_workers;}
+ uint32_t stock_wares (Ware_Index const i) const {
+ return m_wares .stock(i);
+ }
+ uint32_t stock_workers(Ware_Index const i) const {
+ return m_workers.stock(i);
+ }
+ void add_wares (Ware_Index, uint32_t count);
+ void remove_wares (Ware_Index, uint32_t count);
+ void add_workers (Ware_Index, uint32_t count);
+ void remove_workers(Ware_Index, uint32_t count);
+
+ // Supply implementation
+ virtual PlayerImmovable * get_position(Game &);
+ virtual bool is_active() const throw ();
+ virtual bool has_storage() const throw ();
+ virtual void get_ware_type(WareWorker & type, Ware_Index & ware) const;
+
+ virtual void send_to_storage(Game &, StorageOwner * storage_owner);
+ virtual uint32_t nr_supplies(const Game &, const Request &) const;
+ virtual WareInstance & launch_item(Game &, const Request &);
+ virtual Worker & launch_worker(Game &, const Request &);
+private:
+ StorageHandler & m_handler;
+ Economy * m_economy;
+ WareList m_wares;
+ WareList m_workers; // we use this to keep the soldiers
+};
+
+}
+
+#endif
=== modified file 'src/logic/trainingsite.cc'
--- src/logic/trainingsite.cc 2013-07-26 20:19:36 +0000
+++ src/logic/trainingsite.cc 2013-08-06 10:09:46 +0000
@@ -20,12 +20,14 @@
#include "logic/trainingsite.h"
#include <cstdio>
+#include <memory>
#include "economy/request.h"
#include "helper.h"
#include "i18n.h"
#include "logic/editor_game_base.h"
#include "logic/game.h"
+#include "logic/garrisonhandler.h"
#include "logic/player.h"
#include "logic/production_program.h"
#include "logic/soldier.h"
@@ -157,9 +159,6 @@
TrainingSite::TrainingSite(const TrainingSite_Descr & d) :
ProductionSite (d),
-m_soldier_request(0),
-m_capacity (descr().get_max_number_of_soldiers()),
-m_build_heroes (false),
m_result (Failed)
{
// Initialize this in the constructor so that loading code may
@@ -178,7 +177,13 @@
init_kick_state(atrDefense, d);
if (d.get_train_evade())
init_kick_state(atrEvade, d);
+ GarrisonHandler * ga = new GarrisonHandler
+ (*this, 0, descr().get_max_number_of_soldiers(),
+ descr().get_conquers(), 0, Garrison::SoldierPref::Rookies, true);
+ // FIXME put soldierpref in desc
+ m_garrison.reset(ga);
}
+
void
TrainingSite::init_kick_state(const tAttribute & art, const TrainingSite_Descr & d)
{
@@ -203,31 +208,26 @@
void TrainingSite::init(Editor_Game_Base & egbase)
{
ProductionSite::init(egbase);
-
- upcast(Game, game, &egbase);
-
- container_iterate_const(std::vector<Soldier *>, m_soldiers, i) {
- (*i.current)->set_location_initially(*this);
- assert(not (*i.current)->get_state()); // Should be newly created.
-
- if (game)
- (*i.current)->start_task_idle(*game, 0, -1);
+ m_garrison->init(egbase);
+ const std::vector<Worker*>& ws = get_workers();
+ container_iterate_const(std::vector<Worker *>, ws, i) {
+ if (upcast(Soldier, soldier, *i.current)) {
+ soldier->set_location_initially(*this);
+ m_garrison->incorporateSoldier(egbase, *soldier);
+ }
}
- update_soldier_request();
}
/**
* Change the economy this site belongs to.
- * \par e The new economy. Can be 0 (unconnected buildings have no economy).
+ * \par e The new economy. Can be 0 (unconnected buildings have no economy).
* \note the worker (but not the soldiers) is dealt with in the
* PlayerImmovable code.
*/
void TrainingSite::set_economy(Economy * e)
{
ProductionSite::set_economy(e);
-
- if (m_soldier_request)
- m_soldier_request->set_economy(e);
+ m_garrison->set_economy(e);
}
/**
@@ -237,212 +237,63 @@
*/
void TrainingSite::cleanup(Editor_Game_Base & egbase)
{
- delete m_soldier_request;
- m_soldier_request = 0;
-
+ m_garrison->cleanup(egbase);
ProductionSite::cleanup(egbase);
+ m_garrison->cleanup_requests(egbase);
}
void TrainingSite::add_worker(Worker & w)
{
ProductionSite::add_worker(w);
-
- if (upcast(Soldier, soldier, &w)) {
- // Note that the given Soldier might already be in the array
- // for loadgames.
- if
- (std::find(m_soldiers.begin(), m_soldiers.end(), soldier) ==
- m_soldiers.end())
- m_soldiers.push_back(soldier);
-
- if (upcast(Game, game, &owner().egbase()))
- schedule_act(*game, 100);
+ if (upcast(Game, game, &owner().egbase())) {
+ schedule_act(*game, 100);
}
}
void TrainingSite::remove_worker(Worker & w)
{
- upcast(Game, game, &owner().egbase());
-
- if (upcast(Soldier, soldier, &w)) {
- std::vector<Soldier *>::iterator const it =
- std::find(m_soldiers.begin(), m_soldiers.end(), soldier);
- if (it != m_soldiers.end()) {
- m_soldiers.erase(it);
-
- if (game)
- schedule_act(*game, 100);
- }
- }
ProductionSite::remove_worker(w);
-}
-
-
-/**
- * Request soldiers up to capacity, or let go of surplus soldiers.
- */
-void TrainingSite::update_soldier_request() {
- if (m_soldiers.size() < m_capacity) {
- if (!m_soldier_request) {
- m_soldier_request =
- new Request
- (*this,
- tribe().safe_worker_index("soldier"),
- TrainingSite::request_soldier_callback,
- wwWORKER);
-
- RequireOr r;
-
- // set requirements to match this site
- if (descr().get_train_attack())
- r.add
- (RequireAttribute
- (atrAttack,
- descr().get_min_level(atrAttack),
- descr().get_max_level(atrAttack)));
- if (descr().get_train_defense())
- r.add
- (RequireAttribute
- (atrDefense,
- descr().get_min_level(atrDefense),
- descr().get_max_level(atrDefense)));
- if (descr().get_train_evade())
- r.add
- (RequireAttribute
- (atrEvade,
- descr().get_min_level(atrEvade),
- descr().get_max_level(atrEvade)));
- if (descr().get_train_hp())
- r.add
- (RequireAttribute
- (atrHP,
- descr().get_min_level(atrHP),
- descr().get_max_level(atrHP)));
-
- m_soldier_request->set_requirements(r);
- }
-
- m_soldier_request->set_count(m_capacity - m_soldiers.size());
- } else if (m_soldiers.size() >= m_capacity) {
- delete m_soldier_request;
- m_soldier_request = 0;
-
- while (m_soldiers.size() > m_capacity)
- dropSoldier(**m_soldiers.rbegin());
- }
-}
-
-
-/**
- * Soldier callback. Since the soldier was already added via add_worker,
- * we only need to update the request structure.
- */
-void TrainingSite::request_soldier_callback
- (Game & game,
-#ifndef NDEBUG
- Request & rq,
-#else
- Request &,
-#endif
- Ware_Index,
- Worker * const w,
- PlayerImmovable & target)
-{
- TrainingSite & tsite = ref_cast<TrainingSite, PlayerImmovable>(target);
- Soldier & s = ref_cast<Soldier, Worker> (*w);
-
- assert(s.get_location(game) == &tsite);
- assert(tsite.m_soldier_request == &rq);
-
- tsite.incorporateSoldier(game, s);
-}
-
-/*
-===============
-Takes one soldier and adds him to ours
-
-returns 0 on succes, -1 if there was no room for this soldier
-===============
-*/
-int TrainingSite::incorporateSoldier(Editor_Game_Base & egbase, Soldier & s) {
- if (s.get_location(egbase) != this) {
- if (stationedSoldiers().size() + 1 > descr().get_max_number_of_soldiers())
- return -1;
-
- s.set_location(this);
- }
-
- // Bind the worker into this house, hide him on the map
- if (upcast(Game, game, &egbase))
- s.start_task_idle(*game, 0, -1);
-
- // Make sure the request count is reduced or the request is deleted.
- update_soldier_request();
-
- return 0;
-}
-
-
-std::vector<Soldier *> TrainingSite::presentSoldiers() const
-{
- return m_soldiers;
-}
-
-std::vector<Soldier *> TrainingSite::stationedSoldiers() const
-{
- return m_soldiers;
-}
-
-uint32_t TrainingSite::minSoldierCapacity() const throw () {
- return 0;
-}
-uint32_t TrainingSite::maxSoldierCapacity() const throw () {
- return descr().get_max_number_of_soldiers();
-}
-uint32_t TrainingSite::soldierCapacity() const
-{
- return m_capacity;
-}
-
-void TrainingSite::setSoldierCapacity(uint32_t const capacity) {
- assert(minSoldierCapacity() <= capacity);
- assert (capacity <= maxSoldierCapacity());
- assert(m_capacity != capacity);
- m_capacity = capacity;
- update_soldier_request();
-}
-
-/**
- * Drop a given soldier.
- *
- * 'Dropping' means releasing the soldier from the site. The soldier then
- * becomes available to the economy.
- *
- * \note This is called from player commands, so we need to verify that the
- * soldier is actually stationed here, without breaking anything if he isn't.
- */
-void TrainingSite::dropSoldier(Soldier & soldier)
-{
- Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
-
- std::vector<Soldier *>::iterator it =
- std::find(m_soldiers.begin(), m_soldiers.end(), &soldier);
- if (it == m_soldiers.end()) {
- molog("TrainingSite::dropSoldier: soldier not in training site");
- return;
- }
-
- m_soldiers.erase(it);
-
- soldier.reset_tasks(game);
- soldier.start_task_leavebuilding(game, true);
-
- // Schedule, so that we can call new soldiers on next act()
- schedule_act(game, 100);
-}
-
+ if (upcast(Game, game, &owner().egbase())) {
+ schedule_act(*game, 100);
+ }
+}
+
+void TrainingSite::update_requirements()
+{
+ RequireOr r;
+ // set requirements to match this site
+ if (descr().get_train_attack()) {
+ r.add
+ (RequireAttribute
+ (atrAttack,
+ descr().get_min_level(atrAttack),
+ descr().get_max_level(atrAttack)));
+ }
+ if (descr().get_train_defense()) {
+ r.add
+ (RequireAttribute
+ (atrDefense,
+ descr().get_min_level(atrDefense),
+ descr().get_max_level(atrDefense)));
+ }
+ if (descr().get_train_evade()) {
+ r.add
+ (RequireAttribute
+ (atrEvade,
+ descr().get_min_level(atrEvade),
+ descr().get_max_level(atrEvade)));
+ }
+ if (descr().get_train_hp()) {
+ r.add
+ (RequireAttribute
+ (atrHP,
+ descr().get_min_level(atrHP),
+ descr().get_max_level(atrHP)));
+ }
+ m_garrison->set_soldier_requirements(r);
+}
/**
* Drop all the soldiers that can not be upgraded further at this building.
@@ -451,22 +302,24 @@
{
std::vector<Soldier *> droplist;
- for (uint32_t i = 0; i < m_soldiers.size(); ++i) {
+ const std::vector<Soldier*> soldiers = m_garrison->stationedSoldiers();
+
+ for (uint32_t i = 0; i < soldiers.size(); ++i) {
std::vector<Upgrade>::iterator it = m_upgrades.begin();
for (; it != m_upgrades.end(); ++it) {
- int32_t level = m_soldiers[i]->get_level(it->attribute);
+ int32_t level = soldiers[i]->get_level(it->attribute);
if (level >= it->min && level <= it->max)
break;
}
if (it == m_upgrades.end())
- droplist.push_back(m_soldiers[i]);
+ droplist.push_back(soldiers[i]);
}
// Drop soldiers only now, so that changes in the soldiers array don't
// mess things up
container_iterate_const(std::vector<Soldier *>, droplist, i)
- dropSoldier(**i.current);
+ m_garrison->dropSoldier(**i.current);
}
/**
@@ -477,10 +330,11 @@
{
Soldier * soldier_to_drop = nullptr;
uint32_t highest_soldier_level_seen = 0;
+ const std::vector<Soldier*> soldiers = m_garrison->stationedSoldiers();
- for (uint32_t i = 0; i < m_soldiers.size(); ++i)
+ for (uint32_t i = 0; i < soldiers.size(); ++i)
{
- uint32_t this_soldier_level = m_soldiers[i]->get_level(atrTotal);
+ uint32_t this_soldier_level = soldiers[i]->get_level(atrTotal);
bool this_soldier_is_safe = false;
if (this_soldier_level <= highest_soldier_level_seen)
@@ -499,7 +353,7 @@
// - is below maximum, and
// - is not in a stalled state
// Check done separately for each art.
- int32_t level = m_soldiers[i]->get_level(it->attribute);
+ int32_t level = soldiers[i]->get_level(it->attribute);
// Below maximum -check
if (level > it->max)
@@ -529,7 +383,7 @@
if (!this_soldier_is_safe)
{
// Make this soldier a kick-out candidate
- soldier_to_drop = m_soldiers[i];
+ soldier_to_drop = soldiers[i];
highest_soldier_level_seen = this_soldier_level;
}
}
@@ -538,7 +392,7 @@
if (nullptr != soldier_to_drop)
{
log("TrainingSite::drop_stalled_soldiers: Kicking somebody out.\n");
- dropSoldier (*soldier_to_drop);
+ m_garrison->dropSoldier (*soldier_to_drop);
}
}
@@ -552,7 +406,7 @@
{
ProductionSite::act(game, data);
- update_soldier_request();
+ m_garrison->act(game);
}
@@ -622,7 +476,9 @@
int32_t minlevel = upgrade.max;
int32_t maxlevel = upgrade.min;
- container_iterate_const(std::vector<Soldier *>, m_soldiers, i) {
+ const std::vector<Soldier*> soldiers = m_garrison->stationedSoldiers();
+ container_iterate_const(std::vector<Soldier *>, soldiers, i) {
+ assert((*i.current));
int32_t const level = (*i.current)->get_level(upgrade.attribute);
if (level > upgrade.max || level < upgrade.min)
@@ -787,4 +643,25 @@
log(" / %3d\n", max_stall_val);
}
+
+void TrainingSite::garrison_occupied()
+{
+}
+void TrainingSite::garrison_lost(Game&, Player_Number, bool)
+{
+}
+void TrainingSite::reinit_after_conqueral(Game&)
+{
+}
+Garrison* TrainingSite::get_garrison() const
+{
+ return m_garrison.get();
+}
+Building* TrainingSite::get_building()
+{
+ return this;
+}
+
+
+
}
=== modified file 'src/logic/trainingsite.h'
--- src/logic/trainingsite.h 2013-07-26 20:19:36 +0000
+++ src/logic/trainingsite.h 2013-08-06 10:09:46 +0000
@@ -20,14 +20,16 @@
#ifndef TRAININGSITE_H
#define TRAININGSITE_H
+#include "logic/garrison.h"
#include "logic/productionsite.h"
-#include "logic/soldiercontrol.h"
#include "logic/tattribute.h"
struct TrainingSite_Window;
namespace Widelands {
+class GarrisonHandler;
+
struct TrainingSite_Descr : public ProductionSite_Descr {
TrainingSite_Descr
(char const * name, char const * descname,
@@ -48,7 +50,7 @@
int32_t get_max_level(tAttribute) const;
int32_t get_max_stall() const;
private:
- // FIXME These variables should be per soldier type. They should be in a
+ // FIXME These variables should bper soldier type. They should be in a
// FIXME struct and there should be a vector, indexed by Soldier_Index,
// FIXME with that struct structs as element type.
@@ -95,7 +97,7 @@
* surrounding strongholds, the training site will burn even if it
* contains soldiers!
*/
-class TrainingSite : public ProductionSite, public SoldierControl {
+class TrainingSite : public ProductionSite, public GarrisonOwner {
friend struct Map_Buildingdata_Data_Packet;
MO_DESCR(TrainingSite_Descr);
friend struct ::TrainingSite_Window;
@@ -138,17 +140,13 @@
}
virtual void set_economy(Economy * e);
+ // Garrison implementation
+ virtual Garrison* get_garrison() const;
+ virtual Building* get_building();
+ virtual void garrison_occupied();
+ virtual void garrison_lost(Game& game, Player_Number defeating, bool captured);
+ virtual void reinit_after_conqueral(Game& game);
- // Begin implementation of SoldierControl
- virtual std::vector<Soldier *> presentSoldiers() const;
- virtual std::vector<Soldier *> stationedSoldiers() const;
- virtual uint32_t minSoldierCapacity() const throw ();
- virtual uint32_t maxSoldierCapacity() const throw ();
- virtual uint32_t soldierCapacity() const;
- virtual void setSoldierCapacity(uint32_t capacity);
- virtual void dropSoldier(Soldier &);
- int incorporateSoldier(Editor_Game_Base &, Soldier &);
- // End implementation of SoldierControl
int32_t get_pri(enum tAttribute atr);
void set_pri(enum tAttribute atr, int32_t prio);
@@ -165,10 +163,7 @@
virtual void program_end(Game &, Program_Result);
private:
- void update_soldier_request();
- static void request_soldier_callback
- (Game &, Request &, Ware_Index, Worker *, PlayerImmovable &);
-
+ void update_requirements();
void find_and_start_next_program(Game &);
void start_upgrade(Game &, Upgrade &);
void add_upgrade(tAttribute, const std::string & prefix);
@@ -179,27 +174,12 @@
Upgrade * get_upgrade(tAttribute);
private:
- /// Open requests for soldiers. The soldiers can be under way or unavailable
- Request * m_soldier_request;
-
- /** The soldiers currently at the training site*/
- std::vector<Soldier *> m_soldiers;
-
- /** Number of soldiers that should be trained concurrently.
- * Equal or less to maximum number of soldiers supported by a training site.
- * There is no guarantee there really are m_capacity soldiers in the
- * building - some of them might still be under way or even not yet
- * available*/
- uint32_t m_capacity;
-
- /** True, \b always upgrade already experienced soldiers first, when possible
- * False, \b always upgrade inexperienced soldiers first, when possible */
- bool m_build_heroes;
-
std::vector<Upgrade> m_upgrades;
Upgrade * m_current_upgrade;
+ bool m_build_heroes;
Program_Result m_result; /// The result of the last training program.
+ std::unique_ptr<GarrisonHandler> m_garrison;
// These are used for kicking out soldiers prematurely
static const uint32_t training_state_multiplier;
@@ -211,8 +191,6 @@
TrainFailCount_t training_failure_count;
uint32_t max_stall_val;
void init_kick_state(const tAttribute&, const TrainingSite_Descr&);
-
-
};
}
=== modified file 'src/logic/warehouse.cc'
--- src/logic/warehouse.cc 2013-07-28 08:40:06 +0000
+++ src/logic/warehouse.cc 2013-08-06 10:09:46 +0000
@@ -21,13 +21,15 @@
#include <algorithm>
+#include <boost/foreach.hpp>
+#include <boost/format.hpp>
+
#include "container_iterate.h"
#include "economy/economy.h"
#include "economy/flag.h"
#include "economy/portdock.h"
#include "economy/request.h"
#include "economy/ware_instance.h"
-#include "economy/warehousesupply.h"
#include "economy/wares_queue.h"
#include "log.h"
#include "logic/battle.h"
@@ -40,6 +42,7 @@
#include "logic/player.h"
#include "logic/requirements.h"
#include "logic/soldier.h"
+#include "logic/storagehandler.h"
#include "logic/tribe.h"
#include "logic/worker.h"
#include "profile/profile.h"
@@ -48,192 +51,6 @@
namespace Widelands {
-static const uint32_t WORKER_WITHOUT_COST_SPAWN_INTERVAL = 2500;
-
-WarehouseSupply::~WarehouseSupply()
-{
- if (m_economy) {
- log
- ("WarehouseSupply::~WarehouseSupply: Warehouse %u still belongs to "
- "an economy",
- m_warehouse->serial());
- set_economy(0);
- }
-
- // We're removed from the Economy. Therefore, the wares can simply
- // be cleared out. The global inventory will be okay.
- m_wares .clear();
- m_workers.clear();
-}
-
-/// Inform this supply, how much wares are to be handled
-void WarehouseSupply::set_nrwares(Ware_Index const i) {
- assert(Ware_Index::First() == m_wares.get_nrwareids());
-
- m_wares.set_nrwares(i);
-}
-void WarehouseSupply::set_nrworkers(Ware_Index const i) {
- assert(Ware_Index::First() == m_workers.get_nrwareids());
-
- m_workers.set_nrwares(i);
-}
-
-
-/// Add and remove our wares and the Supply to the economies as necessary.
-void WarehouseSupply::set_economy(Economy * const e)
-{
- if (e == m_economy)
- return;
-
- if (m_economy) {
- m_economy->remove_supply(*this);
- for (Ware_Index i = Ware_Index::First(); i < m_wares.get_nrwareids(); ++i)
- if (m_wares.stock(i))
- m_economy->remove_wares(i, m_wares.stock(i));
- for (Ware_Index i = Ware_Index::First(); i < m_workers.get_nrwareids(); ++i)
- if (m_workers.stock(i))
- m_economy->remove_workers(i, m_workers.stock(i));
- }
-
- m_economy = e;
-
- if (m_economy) {
- for (Ware_Index i = Ware_Index::First(); i < m_wares.get_nrwareids(); ++i)
- if (m_wares.stock(i))
- m_economy->add_wares(i, m_wares.stock(i));
- for (Ware_Index i = Ware_Index::First(); i < m_workers.get_nrwareids(); ++i)
- if (m_workers.stock(i))
- m_economy->add_workers(i, m_workers.stock(i));
- m_economy->add_supply(*this);
- }
-}
-
-
-/// Add wares and update the economy.
-void WarehouseSupply::add_wares (Ware_Index const id, uint32_t const count)
-{
- if (!count)
- return;
-
- if (m_economy) // No economies in the editor
- m_economy->add_wares(id, count);
- m_wares.add(id, count);
-}
-
-
-/// Remove wares and update the economy.
-void WarehouseSupply::remove_wares (Ware_Index const id, uint32_t const count)
-{
- if (!count)
- return;
-
- m_wares.remove(id, count);
- if (m_economy) // No economies in the editor
- m_economy->remove_wares(id, count);
-}
-
-
-/// Add workers and update the economy.
-void WarehouseSupply::add_workers (Ware_Index const id, uint32_t const count)
-{
- if (!count)
- return;
-
- if (m_economy) // No economies in the editor
- m_economy->add_workers(id, count);
- m_workers.add(id, count);
-}
-
-
-/**
- * Remove workers and update the economy.
- * Comments see add_workers
- */
-void WarehouseSupply::remove_workers(Ware_Index const id, uint32_t const count)
-{
- if (!count)
- return;
-
- m_workers.remove(id, count);
- if (m_economy) // No economies in the editor
- m_economy->remove_workers(id, count);
-}
-
-/// Return the position of the Supply, i.e. the owning Warehouse.
-PlayerImmovable * WarehouseSupply::get_position(Game &) {return m_warehouse;}
-
-
-/// Warehouse supplies are never active.
-bool WarehouseSupply::is_active() const throw () {return false;}
-
-bool WarehouseSupply::has_storage() const throw ()
-{
- return true;
-}
-
-void WarehouseSupply::get_ware_type(WareWorker & /* type */, Ware_Index & /* ware */) const
-{
- throw wexception
- ("WarehouseSupply::get_ware_type: calling this is nonsensical");
-}
-
-void WarehouseSupply::send_to_storage(Game &, Warehouse * /* wh */)
-{
- throw wexception("WarehouseSupply::send_to_storage: should never be called");
-}
-
-uint32_t WarehouseSupply::nr_supplies
- (const Game & game, const Request & req) const
-{
- if (req.get_type() == wwWORKER)
- return
- m_warehouse->count_workers
- (game, req.get_index(), req.get_requirements());
-
- // Calculate how many wares can be sent out - it might be that we need them
- // ourselves. E.g. for hiring new soldiers.
- int32_t const x = m_wares.stock(req.get_index());
- // only mark an item of that type as available, if the priority of the
- // request + number of that wares in warehouse is > priority of request
- // of *this* warehouse + 1 (+1 is important, as else the ware would directly
- // be taken back to the warehouse as the request of the warehouse would be
- // highered and would have the same value as the original request)
- int32_t const y =
- x + (req.get_priority(0) / 100)
- - (m_warehouse->get_priority(wwWARE, req.get_index()) / 100) - 1;
- // But the number should never be higher than the number of wares available
- if (y > x)
- return x;
- return (x > 0) ? x : 0;
-}
-
-
-/// Launch a ware as item.
-WareInstance & WarehouseSupply::launch_item(Game & game, const Request & req) {
- if (req.get_type() != wwWARE)
- throw wexception("WarehouseSupply::launch_item: called for non-ware request");
- if (!m_wares.stock(req.get_index()))
- throw wexception("WarehouseSupply::launch_item: called for non-existing ware");
-
- return m_warehouse->launch_item(game, req.get_index());
-}
-
-/// Launch a ware as worker.
-Worker & WarehouseSupply::launch_worker(Game & game, const Request & req)
-{
- return
- m_warehouse->launch_worker
- (game, req.get_index(), req.get_requirements());
-}
-
-
-/*
-==============================
-Warehouse Building
-==============================
-*/
-
-
/// Warehouse Descr
Warehouse_Descr::Warehouse_Descr
(char const * const _name, char const * const _descname,
@@ -251,6 +68,11 @@
m_workarea_info[m_conquers].insert(descname() + _(" conquer"));
}
+Building& Warehouse_Descr::create_object() const
+{
+ return *new Warehouse(*this);
+}
+
/*
==============================
@@ -258,37 +80,16 @@
==============================
*/
-#define SET_WORKER_WITHOUT_COST_SPAWNS(nr, value) \
- for \
- (wl_index_range<uint32_t *> \
- i( \
- m_next_worker_without_cost_spawn, \
- m_next_worker_without_cost_spawn + nr \
- ); \
- i; \
- ++i) \
- *i.current = value; \
-
Warehouse::Warehouse(const Warehouse_Descr & warehouse_descr) :
Building(warehouse_descr),
- m_supply(new WarehouseSupply(this)),
- m_next_military_act(0),
m_portdock(0)
{
- uint8_t nr_worker_types_without_cost =
- warehouse_descr.tribe().worker_types_without_cost().size();
- m_next_worker_without_cost_spawn =
- new uint32_t[nr_worker_types_without_cost];
- SET_WORKER_WITHOUT_COST_SPAWNS(nr_worker_types_without_cost, Never());
-
- m_next_stock_remove_act = 0;
+ m_storage.reset(new StorageHandler(*this));
}
Warehouse::~Warehouse()
{
- delete m_supply;
- delete[] m_next_worker_without_cost_spawn;
for (uint8_t i = 0; i < m_expedition_wares.size(); ++i) {
if (m_expedition_wares.at(i)) {
m_expedition_wares.at(i)->cleanup();
@@ -297,186 +98,46 @@
}
}
-/**
- * Try to bring the given \ref PlannedWorkers up to date with our game data.
- * Return \c false if \p pw cannot be salvaged.
- */
-bool Warehouse::_load_finish_planned_worker(PlannedWorkers & pw)
-{
- if (!pw.index || !(pw.index < m_supply->get_workers().get_nrwareids()))
- return false;
-
- const Worker_Descr * w_desc = tribe().get_worker_descr(pw.index);
- if (!w_desc || !w_desc->is_buildable())
- return false;
-
- const Worker_Descr::Buildcost & cost = w_desc->buildcost();
- uint32_t idx = 0;
-
- for
- (Worker_Descr::Buildcost::const_iterator cost_it = cost.begin();
- cost_it != cost.end(); ++cost_it, ++idx)
- {
- WareWorker type;
- Ware_Index ware;
-
- if ((ware = tribe().ware_index(cost_it->first)))
- type = wwWARE;
- else if ((ware = tribe().worker_index(cost_it->first)))
- type = wwWORKER;
- else
- return false;
-
- if (idx < pw.requests.size()) {
- if
- (pw.requests[idx]->get_type() == type &&
- pw.requests[idx]->get_index() == ware)
- continue;
-
- std::vector<Request *>::iterator req_it =
- pw.requests.begin() + idx + 1;
- while (req_it != pw.requests.end()) {
- if ((*req_it)->get_type() == type && (*req_it)->get_index() == ware)
- break;
- ++req_it;
- }
-
- if (req_it != pw.requests.end()) {
- std::swap(*req_it, pw.requests[idx]);
- continue;
- }
- }
-
- log
- ("_load_finish_planned_worker: old savegame: "
- "need to create new request for '%s'\n",
- cost_it->first.c_str());
- pw.requests.insert
- (pw.requests.begin() + idx,
- new Request(*this, ware, &Warehouse::request_cb, type));
- }
-
- while (pw.requests.size() > idx) {
- log
- ("_load_finish_planned_worker: old savegame: "
- "removing outdated request.\n");
- delete pw.requests.back();
- pw.requests.pop_back();
- }
-
- return true;
-}
-
void Warehouse::load_finish(Editor_Game_Base & egbase) {
Building::load_finish(egbase);
-
- uint32_t next_spawn = Never();
- const std::vector<Ware_Index> & worker_types_without_cost =
- tribe().worker_types_without_cost();
- for (uint8_t i = worker_types_without_cost.size(); i;) {
- Ware_Index const worker_index = worker_types_without_cost.at(--i);
- if
- (owner().is_worker_type_allowed(worker_index) and
- m_next_worker_without_cost_spawn[i] == static_cast<uint32_t>(Never()))
- {
- if (next_spawn == static_cast<uint32_t>(Never()))
- next_spawn =
- schedule_act
- (ref_cast<Game, Editor_Game_Base>(egbase),
- WORKER_WITHOUT_COST_SPAWN_INTERVAL);
- m_next_worker_without_cost_spawn[i] = next_spawn;
- log
- ("WARNING: player %u is allowed to create worker type %s but his "
- "%s %u at (%i, %i) does not have a next_spawn time set for that "
- "worker type; setting it to %u\n",
- owner().player_number(),
- tribe().get_worker_descr(worker_index)->descname().c_str(),
- descname().c_str(), serial(), get_position().x, get_position().y,
- next_spawn);
- }
- }
-
- // Ensure consistency of PlannedWorker requests
- {
- uint32_t pwidx = 0;
- while (pwidx < m_planned_workers.size()) {
- if (!_load_finish_planned_worker(m_planned_workers[pwidx])) {
- m_planned_workers[pwidx].cleanup();
- m_planned_workers.erase(m_planned_workers.begin() + pwidx);
- } else {
- pwidx++;
- }
- }
- }
+ m_storage->load_finish(egbase);
}
void Warehouse::init(Editor_Game_Base & egbase)
{
Building::init(egbase);
-
- Ware_Index const nr_wares = tribe().get_nrwares ();
- Ware_Index const nr_workers = tribe().get_nrworkers();
- m_supply->set_nrwares (nr_wares);
- m_supply->set_nrworkers(nr_workers);
-
- m_ware_policy.resize(nr_wares.value(), SP_Normal);
- m_worker_policy.resize(nr_workers.value(), SP_Normal);
-
- // Even though technically, a warehouse might be completely empty,
- // we let warehouse see always for simplicity's sake (since there's
- // almost always going to be a carrier inside, that shouldn't hurt).
+ m_storage->init(egbase);
+
Player & player = owner();
if (upcast(Game, game, &egbase)) {
+ // Even though technically, a warehouse might be completely empty,
+ // we let warehouse see always for simplicity's sake (since there's
+ // almost always going to be a carrier inside, that shouldn't hurt).
player.see_area
(Area<FCoords>
(egbase.map().get_fcoords(get_position()), vision_range()));
- {
- uint32_t const act_time = schedule_act
- (*game, WORKER_WITHOUT_COST_SPAWN_INTERVAL);
- const std::vector<Ware_Index> & worker_types_without_cost =
- tribe().worker_types_without_cost();
-
- for
- (wl_index_range<uint32_t> i
- (0, worker_types_without_cost.size());
- i; ++i)
- if
- (owner().is_worker_type_allowed
- (worker_types_without_cost.at(i.current)))
- m_next_worker_without_cost_spawn[i.current] = act_time;
- }
- // m_next_military_act is not touched in the loading code. Is only needed
- // if there warehous is created in the game? I assume it's for the
- // conquer_radius thing
- m_next_military_act =
- schedule_act
- (ref_cast<Game, Editor_Game_Base>(egbase), 1000);
-
- m_next_stock_remove_act =
- schedule_act
- (ref_cast<Game, Editor_Game_Base>(egbase), 4000);
-
- log("Message: adding (wh) (%s) %i \n", type_name(), player.player_number());
- char message[2048];
- snprintf
- (message, sizeof(message),
- _("A new %s was added to your economy."),
- descname().c_str());
- send_message
- (ref_cast<Game, Editor_Game_Base>(egbase),
- "warehouse",
- descname(),
- message);
+ schedule_act(*game, 1000);
+ // Send a message
+ std::string message =
+ (boost::format(_("A new %s was added to your economy.")) % descname().c_str())
+ .str();
+ send_message
+ (ref_cast<Game, Editor_Game_Base>(egbase),
+ "warehouse", descname(), message);
}
- if (uint32_t const conquer_radius = get_conquers())
+ // Conquer area
+ if (uint32_t const conquer_radius = get_conquers()) {
egbase.conquer_area
(Player_Area<Area<FCoords> >
(player.player_number(),
Area<FCoords>
(egbase.map().get_fcoords(get_position()), conquer_radius)));
+ }
+ // Init port stuff
+ // FIXME: move in a port class
if (descr().get_isport())
init_portdock(egbase);
}
@@ -507,8 +168,10 @@
}
m_portdock->init(egbase);
- if (get_economy() != 0)
+ if (get_economy() != nullptr) {
m_portdock->set_economy(get_economy());
+ m_storage->set_economy(get_economy());
+ }
}
@@ -538,25 +201,14 @@
void Warehouse::destroy(Editor_Game_Base & egbase)
{
- Game & game = ref_cast<Game, Editor_Game_Base>(egbase);
-
- const WareList & workers = get_workers();
-
- for (Ware_Index id = Ware_Index::First(); id < workers.get_nrwareids(); ++id) {
- const uint32_t stock = workers.stock(id);
-
- if (stock > 0) {
- for (uint32_t i = 0; i < stock; ++i) {
- launch_worker(game, id, Requirements()).start_task_leavebuilding
- (game, true);
- }
- }
+ // Launch all workers in stock
+ if (upcast(Game, game, &egbase)) {
+ m_storage->launch_all_workers(*game);
}
Building::destroy(egbase);
}
-/// Destroy the warehouse.
void Warehouse::cleanup(Editor_Game_Base & egbase)
{
if (m_portdock) {
@@ -574,32 +226,22 @@
}
}
- while (!m_planned_workers.empty()) {
- m_planned_workers.back().cleanup();
- m_planned_workers.pop_back();
- }
-
- // all cached workers are unbound and freed
- container_iterate(IncorporatedWorkers, m_incorporated_workers, cpair) {
- WorkerList & clist = cpair->second;
- while (!clist.empty()) {
- Worker * w = clist.back();
- clist.pop_back();
-
- if (upcast(Game, game, &egbase))
- if (game->objects().object_still_available(w))
- w->reset_tasks(*game);
- }
- }
- m_incorporated_workers.clear();
-
+ // Launch workers with some experience
+ // This happen on dismantle for instance
+ if (upcast(Game, game, &egbase)) {
+ m_storage->launch_all_workers(*game, true);
+ }
+ m_storage->cleanup(egbase);
+
+ // Unconquer area
Map & map = egbase.map();
- if (const uint32_t conquer_radius = get_conquers())
+ if (const uint32_t conquer_radius = get_conquers()) {
egbase.unconquer_area
(Player_Area<Area<FCoords> >
(owner().player_number(),
Area<FCoords>(map.get_fcoords(get_position()), conquer_radius)),
m_defeating_player);
+ }
// Unsee the area that we started seeing in init()
Player & player = owner();
@@ -619,109 +261,17 @@
/// at night ;-)
void Warehouse::act(Game & game, uint32_t const data)
{
- uint32_t const gametime = game.get_gametime();
- {
- const std::vector<Ware_Index> & worker_types_without_cost =
- owner().tribe().worker_types_without_cost();
- for (size_t i = worker_types_without_cost.size(); i;)
- if (m_next_worker_without_cost_spawn[--i] <= gametime) {
- Ware_Index const id = worker_types_without_cost.at(i);
- if (owner().is_worker_type_allowed(id)) {
- int32_t const stock = m_supply->stock_workers(id);
- int32_t tdelta = WORKER_WITHOUT_COST_SPAWN_INTERVAL;
-
- if (stock < 100) {
- tdelta -= 4 * (100 - stock);
- insert_workers(id, 1);
- } else if (stock > 100) {
- tdelta -= 4 * (stock - 100);
- if (tdelta < 10)
- tdelta = 10;
- remove_workers(id, 1);
- }
-
- m_next_worker_without_cost_spawn[i] =
- schedule_act(game, tdelta);
- } else
- m_next_worker_without_cost_spawn[i] = Never();
- }
- }
-
- // Military stuff: Kill the soldiers that are dead.
- if (m_next_military_act <= gametime) {
- Ware_Index const ware = tribe().safe_worker_index("soldier");
-
- if (m_incorporated_workers.count(ware)) {
- WorkerList & soldiers = m_incorporated_workers[ware];
-
- uint32_t total_heal = descr().get_heal_per_second();
- // Do not use container_iterate, as we plan to erase some
- // of those guys
- for
- (WorkerList::iterator it = soldiers.begin();
- it != soldiers.end();
- ++it)
- {
- // This is a safe cast: we know only soldiers can land in this
- // slot in the incorporated array
- Soldier * soldier = static_cast<Soldier *>(*it);
-
- // Soldier dead ...
- if (not soldier or soldier->get_current_hitpoints() == 0) {
- it = soldiers.erase(it);
- m_supply->remove_workers(ware, 1);
- continue;
- }
-
- if (soldier->get_current_hitpoints() < soldier->get_max_hitpoints()) {
- soldier->heal(total_heal);
- continue;
- }
-
- }
- }
- m_next_military_act = schedule_act(game, 1000);
- }
-
- if (static_cast<int32_t>(m_next_stock_remove_act - gametime) <= 0) {
- check_remove_stock(game);
-
- m_next_stock_remove_act = schedule_act(game, 4000);
- }
-
- // Update planned workers; this is to update the request amounts and
- // check because whether we suddenly can produce a requested worker. This
- // is mostly previously available wares may become unavailable due to
- // secondary requests.
- _update_all_planned_workers(game);
-
+ uint32_t act_time = m_storage->act(game);
Building::act(game, data);
+ schedule_act(game, act_time);
}
/// Transfer our registration to the new economy.
void Warehouse::set_economy(Economy * const e)
{
- Economy * const old = get_economy();
-
- if (old == e)
- return;
-
- if (old)
- old->remove_warehouse(*this);
-
- if (m_portdock)
- m_portdock->set_economy(e);
- m_supply->set_economy(e);
- Building::set_economy(e);
-
- container_iterate_const
- (std::vector<PlannedWorkers>, m_planned_workers, pw_it)
- {
- container_iterate_const
- (std::vector<Request *>, pw_it.current->requests, req_it)
- (*req_it.current)->set_economy(e);
- }
+ Economy* old = get_economy();
+ m_storage->set_economy(e);
// Take care about the expeditions WaresQueues
for (uint8_t i = 0; i < m_expedition_wares.size(); ++i) {
@@ -730,688 +280,22 @@
if (e)
m_expedition_wares.at(i)->add_to_economy(*e);
}
-
- if (e)
- e->add_warehouse(*this);
-}
-
-
-const WareList & Warehouse::get_wares() const
-{
- return m_supply->get_wares();
-}
-
-
-const WareList & Warehouse::get_workers() const
-{
- return m_supply->get_workers();
-}
-
-/// Magically create wares in this warehouse. Updates the economy accordingly.
-void Warehouse::insert_wares(Ware_Index const id, uint32_t const count)
-{
- m_supply->add_wares(id, count);
-}
-
-
-/// Magically destroy wares.
-void Warehouse::remove_wares(Ware_Index const id, uint32_t const count)
-{
- m_supply->remove_wares(id, count);
-}
-
-
-/// Magically create workers in this warehouse. Updates the economy accordingly.
-void Warehouse::insert_workers(Ware_Index const id, uint32_t const count)
-{
- m_supply->add_workers(id, count);
-}
-
-
-/// Magically destroy workers.
-void Warehouse::remove_workers(Ware_Index const id, uint32_t const count)
-{
- m_supply->remove_workers(id, count);
-}
-
-
+ Building::set_economy(e);
+}
/// Launch a carrier to fetch an item from our flag.
bool Warehouse::fetch_from_flag(Game & game)
{
Ware_Index const carrierid = tribe().safe_worker_index("carrier");
- if (!m_supply->stock_workers(carrierid)) // XXX yep, let's cheat
- insert_workers(carrierid, 1);
-
- launch_worker(game, carrierid, Requirements()).start_task_fetchfromflag
- (game);
-
- return true;
-}
-
-
-/**
- * \return the number of workers that we can launch satisfying the given
- * requirements.
- */
-uint32_t Warehouse::count_workers
- (const Game & /* game */, Ware_Index ware, const Requirements & req)
-{
- uint32_t sum = 0;
-
- do {
- sum += m_supply->stock_workers(ware);
-
- // NOTE: This code lies about the tAttributes of non-instantiated workers.
- if (m_incorporated_workers.count(ware)) {
- WorkerList & incorporated_workers = m_incorporated_workers[ware];
-
- container_iterate_const(WorkerList, incorporated_workers, cworker)
- if (!req.check(**cworker)) {
- // This is one of the workers in our sum.
- // But he is too stupid for this job
- --sum;
- }
- }
-
- ware = tribe().get_worker_descr(ware)->becomes();
- } while (ware != Ware_Index::Null());
-
- return sum;
-}
-
-
-/// Start a worker of a given type. The worker will
-/// be assigned a job by the caller.
-Worker & Warehouse::launch_worker
- (Game & game, Ware_Index ware, const Requirements & req)
-{
- do {
- if (m_supply->stock_workers(ware)) {
- uint32_t unincorporated = m_supply->stock_workers(ware);
-
- // look if we got one of those in stock
- if (m_incorporated_workers.count(ware)) {
- WorkerList & incorporated_workers = m_incorporated_workers[ware];
-
- container_iterate (WorkerList, incorporated_workers, i) {
- Worker * worker = *i.current;
-
- --unincorporated;
-
- if (req.check(*worker)) {
- worker->reset_tasks(game); // forget everything you did
- worker->set_location(this); // back in a economy
- incorporated_workers.erase(i.current);
-
- m_supply->remove_workers(ware, 1);
- return *worker;
- }
- }
- }
-
- assert(unincorporated <= m_supply->stock_workers(ware));
-
- if (unincorporated) {
- // Create a new one
- // NOTE: This code lies about the tAttributes of the new worker
- m_supply->remove_workers(ware, 1);
- const Worker_Descr & workerdescr = *tribe().get_worker_descr(ware);
- return workerdescr.create(game, owner(), this, m_position);
- }
- }
-
- if (can_create_worker(game, ware)) {
- // don't want to use an upgraded worker, so create new one.
- create_worker(game, ware);
- } else {
- ware = tribe().get_worker_descr(ware)->becomes();
- }
- } while (ware != Ware_Index::Null());
-
- throw wexception
- ("Warehouse::launch_worker: worker does not actually exist");
-}
-
-
-/**
- * This is the opposite of launch_worker: destroy the worker and add the
- * appropriate ware to our warelist
- */
-void Warehouse::incorporate_worker(Editor_Game_Base & egbase, Worker & w)
-{
- assert(w.get_owner() == &owner());
-
- // Do not add workers, that are in the expedition list
- bool expedition_worker = false;
- if (!m_expedition_workers.empty())
- for (uint8_t i = 0; i < m_expedition_workers.size() && !expedition_worker; ++i)
- if (m_expedition_workers.at(i)->worker && &w == m_expedition_workers.at(i)->worker)
- expedition_worker = true;
-
- if (!expedition_worker) {
- if (WareInstance * const item = w.fetch_carried_item(egbase))
- incorporate_item(egbase, *item); // rescue an item
-
- Ware_Index worker_index = tribe().worker_index(w.name().c_str());
- m_supply->add_workers(worker_index, 1);
-
- // We remove carriers, but we keep other workers around.
- // FIXME Remove all workers that do not have properties such as experience.
- // FIXME And even such workers should be removed and only a small record
- // FIXME with the experience (and possibly other data that must survive)
- // FIXME may be kept.
- if (dynamic_cast<Carrier const *>(&w)) {
- w.remove(egbase);
- return;
- }
-
- // Incorporate the worker
- if (!m_incorporated_workers.count(worker_index))
- m_incorporated_workers[worker_index] = std::vector<Worker *>();
- m_incorporated_workers[worker_index].push_back(&w);
- }
- w.set_location(0); // no longer in an economy
-
- if (upcast(Game, game, &egbase)) {
- // Bind the worker into this house, hide him on the map.
- w.reset_tasks(*game);
- w.start_task_idle(*game, 0, -1);
- }
-}
-
-/// Create an instance of a ware and make sure it gets
-/// carried out of the warehouse.
-WareInstance & Warehouse::launch_item(Game & game, Ware_Index const ware) {
- // Create the item
- WareInstance & item = *new WareInstance(ware, tribe().get_ware_descr(ware));
- item.init(game);
- do_launch_item(game, item);
-
- m_supply->remove_wares(ware, 1);
-
- return item;
-}
-
-
-/// Get a carrier to actually move this item out of the warehouse.
-void Warehouse::do_launch_item(Game & game, WareInstance & item)
-{
- // Create a carrier
- Ware_Index const carrierid = tribe().worker_index("carrier");
- const Worker_Descr & workerdescr = *tribe().get_worker_descr(carrierid);
-
- Worker & worker = workerdescr.create(game, owner(), this, m_position);
-
- // Yup, this is cheating.
- if (m_supply->stock_workers(carrierid))
- m_supply->remove_workers(carrierid, 1);
-
- // Setup the carrier
- worker.start_task_dropoff(game, item);
-}
-
-
-/// Swallow the item, adding it to out inventory.
-void Warehouse::incorporate_item(Editor_Game_Base & egbase, WareInstance & item)
-{
- m_supply->add_wares(item.descr_index(), 1);
- return item.destroy(egbase);
-}
-
-
-/// Called when a transfer for one of the idle Requests completes.
-void Warehouse::request_cb
- (Game & game,
- Request &,
- Ware_Index const ware,
- Worker * const w,
- PlayerImmovable & target)
-{
- Warehouse & wh = ref_cast<Warehouse, PlayerImmovable>(target);
-
- if (w) {
- w->schedule_incorporate(game);
- } else {
- wh.m_supply->add_wares(ware, 1);
-
- // This ware may be used to build planned workers,
- // so it seems like a good idea to update the associated requests
- // and use the ware before it is sent away again.
- wh._update_all_planned_workers(game);
- }
-}
-
-/**
- * Receive a ware from a transfer that was not associated to a \ref Request.
- */
-void Warehouse::receive_ware(Game & /* game */, Ware_Index ware)
-{
- m_supply->add_wares(ware, 1);
-}
-
-/**
- * Receive a worker from a transfer that was not associated to a \ref Request.
- */
-void Warehouse::receive_worker(Game & game, Worker & worker)
-{
- worker.schedule_incorporate(game);
-}
-
-Building & Warehouse_Descr::create_object() const {
- return *new Warehouse(*this);
-}
-
-
-bool Warehouse::can_create_worker(Game &, Ware_Index const worker) const {
- if (not (worker < m_supply->get_workers().get_nrwareids()))
- throw wexception
- ("worker type %d does not exists (max is %d)",
- worker.value(), m_supply->get_workers().get_nrwareids().value());
-
- const Worker_Descr & w_desc = *tribe().get_worker_descr(worker);
- assert(&w_desc);
- if (not w_desc.is_buildable())
- return false;
-
- // see if we have the resources
- const Worker_Descr::Buildcost & buildcost = w_desc.buildcost();
- container_iterate_const(Worker_Descr::Buildcost, buildcost, it) {
- const std::string & input_name = it.current->first;
- if (Ware_Index id_w = tribe().ware_index(input_name)) {
- if (m_supply->stock_wares (id_w) < it.current->second)
- return false;
- } else if ((id_w = tribe().worker_index(input_name))) {
- if (m_supply->stock_workers(id_w) < it.current->second)
- return false;
- } else
- throw wexception
- ("worker type %s needs \"%s\" to be built but that is neither "
- "a ware type nor a worker type defined in the tribe %s",
- w_desc.descname().c_str(), input_name.c_str(),
- tribe().name().c_str());
- }
- return true;
-}
-
-
-void Warehouse::create_worker(Game & game, Ware_Index const worker) {
- assert(can_create_worker (game, worker));
-
- const Worker_Descr & w_desc = *tribe().get_worker_descr(worker);
- const Worker_Descr::Buildcost & buildcost = w_desc.buildcost();
- container_iterate_const(Worker_Descr::Buildcost, buildcost, i) {
- const std::string & input = i.current->first;
- if (Ware_Index const id_ware = tribe().ware_index(input)) {
- remove_wares (id_ware, i.current->second);
- //update statistic accordingly
- owner().ware_consumed(id_ware, i.current->second);
- } else
- remove_workers(tribe().safe_worker_index(input), i.current->second);
- }
-
- incorporate_worker(game, w_desc.create(game, owner(), this, m_position));
-
- // Update PlannedWorkers::amount here if appropriate, because this function
- // may have been called directly by the Economy.
- // Do not update anything else about PlannedWorkers here, because this
- // function is called by _update_planned_workers, so avoid recursion
- container_iterate(std::vector<PlannedWorkers>, m_planned_workers, pw_it) {
- if (pw_it.current->index == worker && pw_it.current->amount)
- pw_it.current->amount--;
- }
-}
-
-/**
- * Return the number of workers of the given type that we plan to
- * create in this warehouse.
- */
-uint32_t Warehouse::get_planned_workers(Game & /* game */, Ware_Index index) const
-{
- container_iterate_const(std::vector<PlannedWorkers>, m_planned_workers, i) {
- if (i.current->index == index)
- return i.current->amount;
- }
-
- return 0;
-}
-
-/**
- * Calculate the supply of wares available to this warehouse in each of the
- * buildcost items for the given worker.
- *
- * This is the current stock plus any incoming transfers.
- */
-std::vector<uint32_t> Warehouse::calc_available_for_worker
- (Game & /* game */, Ware_Index index) const
-{
- const Worker_Descr & w_desc = *tribe().get_worker_descr(index);
- const Worker_Descr::Buildcost & cost = w_desc.buildcost();
- std::vector<uint32_t> available;
-
- container_iterate_const(Worker_Descr::Buildcost, cost, bc) {
- const std::string & input_name = bc.current->first;
- if (Ware_Index id_w = tribe().ware_index(input_name)) {
- available.push_back(get_wares().stock(id_w));
- } else if ((id_w = tribe().worker_index(input_name))) {
- available.push_back(get_workers().stock(id_w));
- } else
- throw wexception
- ("Economy::_create_requested_worker: buildcost inconsistency '%s'",
- input_name.c_str());
- }
-
- container_iterate_const(std::vector<PlannedWorkers>, m_planned_workers, i) {
- if (i.current->index == index) {
- assert(available.size() == i.current->requests.size());
-
- for (uint32_t idx = 0; idx < available.size(); ++idx)
- available[idx] += i.current->requests[idx]->get_num_transfers();
- }
- }
-
- return available;
-}
-
-
-/**
- * Set the amount of workers we plan to create
- * of the given \p index to \p amount.
- */
-void Warehouse::plan_workers(Game & game, Ware_Index index, uint32_t amount)
-{
- PlannedWorkers * pw = 0;
-
- container_iterate(std::vector<PlannedWorkers>, m_planned_workers, i) {
- if (i.current->index == index) {
- pw = &*i.current;
- break;
- }
- }
-
- if (!pw) {
- if (!amount)
- return;
-
- m_planned_workers.push_back(PlannedWorkers());
- pw = &m_planned_workers.back();
- pw->index = index;
- pw->amount = 0;
-
- const Worker_Descr & w_desc = *tribe().get_worker_descr(pw->index);
- const Worker_Descr::Buildcost & cost = w_desc.buildcost();
- container_iterate_const(Worker_Descr::Buildcost, cost, cost_it) {
- const std::string & input_name = cost_it.current->first;
-
- if (Ware_Index id_w = tribe().ware_index(input_name)) {
- pw->requests.push_back
- (new Request
- (*this, id_w, &Warehouse::request_cb, wwWARE));
- } else if ((id_w = tribe().worker_index(input_name))) {
- pw->requests.push_back
- (new Request
- (*this, id_w, &Warehouse::request_cb, wwWORKER));
- } else
- throw wexception
- ("plan_workers: bad buildcost '%s'", input_name.c_str());
- }
- }
-
- pw->amount = amount;
- _update_planned_workers(game, *pw);
-}
-
-/**
- * See if we can create the workers of the given plan,
- * and update requests accordingly.
- */
-void Warehouse::_update_planned_workers
- (Game & game, Warehouse::PlannedWorkers & pw)
-{
- const Worker_Descr & w_desc = *tribe().get_worker_descr(pw.index);
- const Worker_Descr::Buildcost & cost = w_desc.buildcost();
-
- while (pw.amount && can_create_worker(game, pw.index))
- create_worker(game, pw.index);
-
- uint32_t idx = 0;
- container_iterate_const(Worker_Descr::Buildcost, cost, cost_it) {
- const std::string & input_name = cost_it.current->first;
- uint32_t supply;
-
- if (Ware_Index id_w = tribe().ware_index(input_name)) {
- supply = m_supply->stock_wares(id_w);
- } else if ((id_w = tribe().worker_index(input_name))) {
- supply = m_supply->stock_workers(id_w);
- } else
- throw wexception
- ("_update_planned_workers: bad buildcost '%s'", input_name.c_str());
-
- if (supply >= pw.amount * cost_it.current->second)
- pw.requests[idx]->set_count(0);
- else
- pw.requests[idx]->set_count
- (pw.amount * cost_it.current->second - supply);
- ++idx;
- }
-
- while (pw.requests.size() > idx) {
- delete pw.requests.back();
- pw.requests.pop_back();
- }
-}
-
-/**
- * Check all planned worker creations.
- *
- * Needs to be called periodically, because some necessary supplies might arrive
- * due to idle transfers instead of by explicit request.
- */
-void Warehouse::_update_all_planned_workers(Game & game)
-{
- uint32_t idx = 0;
- while (idx < m_planned_workers.size()) {
- _update_planned_workers(game, m_planned_workers[idx]);
-
- if (!m_planned_workers[idx].amount) {
- m_planned_workers[idx].cleanup();
- m_planned_workers.erase(m_planned_workers.begin() + idx);
- } else {
- idx++;
- }
- }
-}
-
-void Warehouse::enable_spawn
- (Game & game, uint8_t const worker_types_without_cost_index)
-{
- assert
- (m_next_worker_without_cost_spawn[worker_types_without_cost_index]
- ==
- static_cast<uint32_t>(Never()));
- m_next_worker_without_cost_spawn[worker_types_without_cost_index] =
- schedule_act(game, WORKER_WITHOUT_COST_SPAWN_INTERVAL);
-}
-void Warehouse::disable_spawn(uint8_t const worker_types_without_cost_index)
-{
- assert
- (m_next_worker_without_cost_spawn[worker_types_without_cost_index]
- !=
- static_cast<uint32_t>(Never()));
- m_next_worker_without_cost_spawn[worker_types_without_cost_index] = Never();
-}
-
-
-bool Warehouse::canAttack()
-{
- return get_conquers() > 0;
-}
-
-void Warehouse::aggressor(Soldier & enemy)
-{
- if (!get_conquers())
- return;
-
- Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
- Map & map = game.map();
- if
- (enemy.get_owner() == &owner() ||
- enemy.getBattle() ||
- get_conquers()
- <=
- map.calc_distance(enemy.get_position(), get_position()))
- return;
-
- if
- (game.map().find_bobs
- (Area<FCoords>(map.get_fcoords(base_flag().get_position()), 2),
- 0,
- FindBobEnemySoldier(&owner())))
- return;
-
- Ware_Index const soldier_index = tribe().worker_index("soldier");
- Requirements noreq;
-
- if (!count_workers(game, soldier_index, noreq))
- return;
-
- Soldier & defender =
- ref_cast<Soldier, Worker>(launch_worker(game, soldier_index, noreq));
- defender.start_task_defense(game, false, owner().get_retreat_percentage());
-}
-
-bool Warehouse::attack(Soldier & enemy)
-{
- Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
- Ware_Index const soldier_index = tribe().worker_index("soldier");
- Requirements noreq;
-
- if (count_workers(game, soldier_index, noreq)) {
- Soldier & defender =
- ref_cast<Soldier, Worker>(launch_worker(game, soldier_index, noreq));
- defender.start_task_defense(game, true, 0);
- enemy.send_signal(game, "sleep");
- return true;
- }
-
- set_defeating_player(enemy.owner().player_number());
- schedule_destroy(game);
- return false;
-}
-
-void Warehouse::PlannedWorkers::cleanup()
-{
- while (!requests.empty()) {
- delete requests.back();
- requests.pop_back();
- }
-}
-
-Warehouse::StockPolicy Warehouse::get_ware_policy(Ware_Index ware) const
-{
- assert(ware.value() < m_ware_policy.size());
- return m_ware_policy[ware.value()];
-}
-
-Warehouse::StockPolicy Warehouse::get_worker_policy(Ware_Index ware) const
-{
- assert(ware.value() < m_worker_policy.size());
- return m_worker_policy[ware.value()];
-}
-
-Warehouse::StockPolicy Warehouse::get_stock_policy
- (WareWorker waretype, Ware_Index wareindex) const
-{
- if (waretype == wwWORKER)
- return get_worker_policy(wareindex);
- else
- return get_ware_policy(wareindex);
-}
-
-
-void Warehouse::set_ware_policy(Ware_Index ware, Warehouse::StockPolicy policy)
-{
- assert(ware.value() < m_ware_policy.size());
- m_ware_policy[ware.value()] = policy;
-}
-
-void Warehouse::set_worker_policy
- (Ware_Index ware, Warehouse::StockPolicy policy)
-{
- assert(ware.value() < m_worker_policy.size());
- m_worker_policy[ware.value()] = policy;
-}
-
-/**
- * Check if there are remaining wares with stock policy \ref SP_Remove,
- * and remove one of them if appropriate.
- */
-void Warehouse::check_remove_stock(Game & game)
-{
- if (base_flag().current_items() < base_flag().total_capacity() / 2) {
- for (Ware_Index ware = Ware_Index::First(); ware.value() < m_ware_policy.size(); ++ware) {
- if (get_ware_policy(ware) != SP_Remove || !get_wares().stock(ware))
- continue;
-
- launch_item(game, ware);
- break;
- }
- }
-
- for (Ware_Index widx = Ware_Index::First(); widx.value() < m_worker_policy.size(); ++widx) {
- if (get_worker_policy(widx) != SP_Remove || !get_workers().stock(widx))
- continue;
-
- Worker & worker = launch_worker(game, widx, Requirements());
- worker.start_task_leavebuilding(game, true);
- break;
- }
-}
-
-/*
- * SoldierControl implementations
- */
-std::vector<Soldier *> Warehouse::presentSoldiers() const
-{
- std::vector<Soldier *> rv;
-
- Ware_Index const ware = tribe().safe_worker_index("soldier");
- IncorporatedWorkers::const_iterator sidx = m_incorporated_workers.find(ware);
-
- if (sidx != m_incorporated_workers.end()) {
- const WorkerList & soldiers = sidx->second;
-
- container_iterate_const(WorkerList, soldiers, i)
- rv.push_back(static_cast<Soldier *>(*i));
- }
-
- return rv;
-}
-int Warehouse::incorporateSoldier(Editor_Game_Base & egbase, Soldier & soldier) {
- incorporate_worker(egbase, soldier);
- return 0;
-}
-
-int Warehouse::outcorporateSoldier(Editor_Game_Base & /* egbase */, Soldier & soldier) {
-
- Ware_Index const ware = tribe().safe_worker_index("soldier");
- if (m_incorporated_workers.count(ware)) {
- WorkerList & soldiers = m_incorporated_workers[ware];
-
- WorkerList::iterator i = std::find
- (soldiers.begin(), soldiers.end(), &soldier);
-
- soldiers.erase(i);
- m_supply->remove_workers(ware, 1);
- }
-#ifndef NDEBUG
- else
- throw wexception("outcorporateSoldier: soldier not in this warehouse!");
-#endif
-
- return 0;
-}
+ if (!m_storage->count_workers(game, carrierid)) {
+ m_storage->insert_workers(carrierid, 1);
+ }
+ Worker& w = m_storage->launch_worker(game, carrierid);
+ w.start_task_fetchfromflag(game);
+ return true;
+}
+
void Warehouse::log_general_info(const Editor_Game_Base & egbase)
{
@@ -1421,5 +305,24 @@
molog("Port dock: %u\n", m_portdock ? m_portdock->serial() : 0);
}
+void Warehouse::receive_ware(Game&, Ware_Index ware)
+{
+ m_storage->insert_wares(ware, 1);
+}
+
+void Warehouse::receive_worker(Game& game, Worker& worker)
+{
+ m_storage->incorporate_worker(game, worker);
+}
+
+Building* Warehouse::get_building()
+{
+ return this;
+}
+
+Storage* Warehouse::get_storage() const
+{
+ return m_storage.get();
+}
}
=== modified file 'src/logic/warehouse.h'
--- src/logic/warehouse.h 2013-07-28 08:40:06 +0000
+++ src/logic/warehouse.h 2013-08-06 10:09:46 +0000
@@ -20,10 +20,9 @@
#ifndef WAREHOUSE_H
#define WAREHOUSE_H
-#include "logic/attackable.h"
#include "logic/building.h"
#include "economy/request.h"
-#include "logic/soldiercontrol.h"
+#include "logic/storage.h"
#include "logic/wareworker.h"
struct Interactive_Player;
@@ -31,6 +30,7 @@
namespace Widelands {
+class StorageHandler;
struct Editor_Game_Base;
struct PortDock;
struct Request;
@@ -44,7 +44,6 @@
/*
Warehouse
*/
-struct WarehouseSupply;
struct Warehouse_Descr : public Building_Descr {
Warehouse_Descr
@@ -65,47 +64,12 @@
};
-class Warehouse : public Building, public Attackable, public SoldierControl {
+class Warehouse : public Building, public StorageOwner {
friend struct PortDock;
friend struct Map_Buildingdata_Data_Packet;
MO_DESCR(Warehouse_Descr);
-
public:
- /**
- * Each ware and worker type has an associated per-warehouse
- * stock policy that defines whether it will be stocked by this
- * warehouse.
- *
- * \note The values of this enum are written directly into savegames,
- * so be careful when changing them.
- */
- enum StockPolicy {
- /**
- * The default policy allows stocking wares without any special priority.
- */
- SP_Normal = 0,
-
- /**
- * As long as there are warehouses with this policy for a ware, all
- * available unstocked supplies will be transferred to warehouses
- * with this policy.
- */
- SP_Prefer = 1,
-
- /**
- * If a ware has this stock policy, no new items of this ware will enter
- * the warehouse.
- */
- SP_DontStock = 2,
-
- /**
- * Like \ref SP_DontStock, but in addition, existing stock of this ware
- * will be transported out of the warehouse over time.
- */
- SP_Remove = 3,
- };
-
Warehouse(const Warehouse_Descr &);
virtual ~Warehouse();
@@ -137,67 +101,14 @@
virtual void set_economy(Economy *);
- const WareList & get_wares() const;
- const WareList & get_workers() const;
-
- void insert_wares (Ware_Index, uint32_t count);
- void remove_wares (Ware_Index, uint32_t count);
- void insert_workers(Ware_Index, uint32_t count);
- void remove_workers(Ware_Index, uint32_t count);
-
- /* SoldierControl implementation */
- std::vector<Soldier *> presentSoldiers() const;
- std::vector<Soldier *> stationedSoldiers() const {
- return presentSoldiers();
- }
- uint32_t minSoldierCapacity() const {return 0;}
- uint32_t maxSoldierCapacity() const {return 4294967295U;}
- uint32_t soldierCapacity() const {return maxSoldierCapacity();}
- void setSoldierCapacity(uint32_t /* capacity */) {
- throw wexception("Not implemented for a Warehouse!");
- }
- void dropSoldier(Soldier &) {
- throw wexception("Not implemented for a Warehouse!");
- }
- int incorporateSoldier(Editor_Game_Base &, Soldier &);
- int outcorporateSoldier(Editor_Game_Base &, Soldier &);
-
virtual bool fetch_from_flag(Game &);
- uint32_t count_workers(const Game &, Ware_Index, const Requirements &);
- Worker & launch_worker(Game &, Ware_Index, const Requirements &);
- void incorporate_worker(Editor_Game_Base &, Worker &);
-
- WareInstance & launch_item(Game &, Ware_Index);
- void do_launch_item(Game &, WareInstance &);
- void incorporate_item(Editor_Game_Base &, WareInstance &);
-
- bool can_create_worker(Game &, Ware_Index) const;
- void create_worker(Game &, Ware_Index);
-
- uint32_t get_planned_workers(Game &, Ware_Index index) const;
- void plan_workers(Game &, Ware_Index index, uint32_t amount);
- std::vector<uint32_t> calc_available_for_worker
- (Game &, Ware_Index index) const;
-
- void enable_spawn(Game &, uint8_t worker_types_without_cost_index);
- void disable_spawn(uint8_t worker_types_without_cost_index);
-
- // Begin Attackable implementation
- virtual Player & owner() const {return Building::owner();}
- virtual bool canAttack();
- virtual void aggressor(Soldier &);
- virtual bool attack (Soldier &);
- // End Attackable implementation
-
virtual void receive_ware(Game &, Ware_Index ware);
virtual void receive_worker(Game &, Worker & worker);
- StockPolicy get_ware_policy(Ware_Index ware) const;
- StockPolicy get_worker_policy(Ware_Index ware) const;
- StockPolicy get_stock_policy(WareWorker waretype, Ware_Index wareindex) const;
- void set_ware_policy(Ware_Index ware, StockPolicy policy);
- void set_worker_policy(Ware_Index ware, StockPolicy policy);
+ // StorageOwner
+ virtual Building* get_building();
+ virtual Storage* get_storage() const;
// PortDock stuff
struct Expedition_Worker {
@@ -231,47 +142,7 @@
private:
void init_portdock(Editor_Game_Base & egbase);
- /**
- * Plan to produce a certain worker type in this warehouse. This means
- * requesting all the necessary wares, if multiple different wares types are
- * needed.
- */
- struct PlannedWorkers {
- /// Index of the worker type we plan to create
- Ware_Index index;
-
- /// How many workers of this type are we supposed to create?
- uint32_t amount;
-
- /// Requests to obtain the required build costs
- std::vector<Request *> requests;
-
- void cleanup();
- };
-
- static void request_cb
- (Game &, Request &, Ware_Index, Worker *, PlayerImmovable &);
- void check_remove_stock(Game &);
-
- bool _load_finish_planned_worker(PlannedWorkers & pw);
- void _update_planned_workers(Game &, PlannedWorkers & pw);
- void _update_all_planned_workers(Game &);
-
- WarehouseSupply * m_supply;
-
- std::vector<StockPolicy> m_ware_policy;
- std::vector<StockPolicy> m_worker_policy;
-
- // Workers who live here at the moment
- typedef std::vector<Worker *> WorkerList;
- typedef std::map<Ware_Index, WorkerList> IncorporatedWorkers;
- IncorporatedWorkers m_incorporated_workers;
- uint32_t * m_next_worker_without_cost_spawn;
- uint32_t m_next_military_act;
- uint32_t m_next_stock_remove_act;
-
- std::vector<PlannedWorkers> m_planned_workers;
-
+ std::unique_ptr<StorageHandler> m_storage;
// PortDock stuff
PortDock * m_portdock;
std::vector<WaresQueue *> m_expedition_wares;
=== modified file 'src/logic/worker.cc'
--- src/logic/worker.cc 2013-08-01 08:33:15 +0000
+++ src/logic/worker.cc 2013-08-06 10:09:46 +0000
@@ -1089,7 +1089,7 @@
/**
* Change the location. This should be called in the following situations:
- * \li worker creation (usually, location is a warehouse)
+ * \li worker creation (usually, location is a storage)
* \li worker moves along a route (location is a road and finally building)
* \li current location is destroyed (building burnt down etc...)
*/
@@ -1200,7 +1200,7 @@
// We are destroyed, but we were maybe idling
// or doing something else. Get Location might
- // init a gowarehouse task or something and this results
+ // init a gostorage task or something and this results
// in a dirty stack. Nono, we do not want to end like this
if (upcast(Game, game, &egbase))
reset_tasks(*game);
@@ -1251,7 +1251,7 @@
/**
* Schedule an immediate CMD_INCORPORATE, which will integrate this worker into
- * the warehouse he is standing on.
+ * the storage he is standing on.
*/
void Worker::schedule_incorporate(Game & game)
{
@@ -1261,13 +1261,13 @@
/**
- * Incorporate the worker into the warehouse it's standing on immediately.
+ * Incorporate the worker into the storage it's standing on immediately.
* This will delete the worker.
*/
void Worker::incorporate(Game & game)
{
- if (upcast(Warehouse, wh, get_location(game))) {
- wh->incorporate_worker(game, *this);
+ if (upcast(StorageOwner, storage_owner, get_location(game))) {
+ storage_owner->get_storage()->incorporate_worker(game, *this);
return;
}
@@ -1353,7 +1353,7 @@
void Worker::init_auto_task(Game & game) {
if (PlayerImmovable * location = get_location(game)) {
if
- (get_economy()->warehouses().size() ||
+ (get_economy()->storages().size() ||
location->get_type() == BUILDING)
return start_task_gowarehouse(game);
@@ -2008,7 +2008,7 @@
}
}
- if (dynamic_cast<Warehouse const *>(location)) {
+ if (dynamic_cast<StorageOwner const *>(location)) {
delete m_supply;
m_supply = 0;
@@ -2032,7 +2032,7 @@
if (location->get_type() == BUILDING)
return start_task_leavebuilding(game, true);
- if (!get_economy()->warehouses().size()) {
+ if (!get_economy()->storages().size()) {
molog("[gowarehouse]: No warehouse left in Economy\n");
return pop_task(game);
}
@@ -2158,7 +2158,7 @@
throw wexception
("MO(%u): [dropoff]: not on building on return", serial());
- if (dynamic_cast<Warehouse const *>(location)) {
+ if (dynamic_cast<StorageOwner const *>(location)) {
schedule_incorporate(game);
return;
}
@@ -2285,7 +2285,7 @@
}
// We're back!
- if (dynamic_cast<Warehouse const *>(location)) {
+ if (dynamic_cast<StorageOwner const *>(location)) {
schedule_incorporate(game);
return;
}
@@ -2511,12 +2511,12 @@
game.get_gametime() + 120000 + 200 * (game.logic_rand() % 600);
}
-struct FindFlagWithPlayersWarehouse {
- FindFlagWithPlayersWarehouse(const Player & owner) : m_owner(owner) {}
+struct FindFlagWithPlayersStorage {
+ FindFlagWithPlayersStorage(const Player & owner) : m_owner(owner) {}
bool accept(const BaseImmovable & imm) const {
if (upcast(Flag const, flag, &imm))
if (&flag->owner() == &m_owner)
- if (flag->economy().warehouses().size())
+ if (flag->economy().storages().size())
return true;
return false;
}
@@ -2537,7 +2537,7 @@
if (location && &location->owner() == &owner()) {
molog("[fugitive]: we are on location\n");
- if (dynamic_cast<Warehouse const *>(location))
+ if (dynamic_cast<StorageOwner const *>(location))
return schedule_incorporate(game);
set_location(0);
@@ -2546,7 +2546,7 @@
// check whether we're on a flag and it's time to return home
if (upcast(Flag, flag, map[get_position()].get_immovable())) {
- if (&flag->owner() == &owner() and flag->economy().warehouses().size()) {
+ if (&flag->owner() == &owner() and flag->economy().storages().size()) {
set_location(flag);
return pop_task(game);
}
@@ -2562,12 +2562,12 @@
if
(map.find_immovables
(Area<FCoords>(map.get_fcoords(get_position()), maxdist),
- &flags, FindFlagWithPlayersWarehouse(*get_owner())))
+ &flags, FindFlagWithPlayersStorage(*get_owner())))
{
int32_t bestdist = -1;
Flag * best = 0;
- molog("[fugitive]: found a flag connected to warehouse(s)\n");
+ molog("[fugitive]: found a flag connected to storage(s)\n");
container_iterate_const(std::vector<ImmovableFound>, flags, i) {
Flag & flag = ref_cast<Flag, BaseImmovable>(*i.current->object);
@@ -2593,7 +2593,7 @@
if (best) {
molog("[fugitive]: try to move to flag\n");
- // Warehouse could be on a different island, so check for failure
+ // Storage could be on a different island, so check for failure
// Also, move only a few number of steps in the right direction,
// so that we could theoretically lose the flag again, but also
// perhaps find a closer flag.
=== modified file 'src/logic/worker.h'
--- src/logic/worker.h 2013-07-26 20:19:36 +0000
+++ src/logic/worker.h 2013-08-06 10:09:46 +0000
@@ -145,6 +145,9 @@
/// request a new worker of his old type. Otherwise Ware_Index::Null is
/// returned.
Ware_Index gain_experience (Game &);
+ void set_experience(int32_t exp) {
+ m_current_exp = exp;
+ }
void create_needed_experience(Game &);
Ware_Index level (Game &);
=== modified file 'src/map_io/widelands_map_buildingdata_data_packet.cc'
--- src/map_io/widelands_map_buildingdata_data_packet.cc 2013-08-01 03:23:11 +0000
+++ src/map_io/widelands_map_buildingdata_data_packet.cc 2013-08-06 10:09:46 +0000
@@ -26,7 +26,6 @@
#include "economy/flag.h"
#include "economy/portdock.h"
#include "economy/request.h"
-#include "economy/warehousesupply.h"
#include "economy/wares_queue.h"
#include "logic/constructionsite.h"
#include "logic/dismantlesite.h"
@@ -44,25 +43,32 @@
#include "logic/widelands_fileread.h"
#include "logic/widelands_filewrite.h"
#include "logic/worker.h"
+#include <logic/storagehandler.h>
#include "map_io/widelands_map_map_object_loader.h"
#include "map_io/widelands_map_map_object_saver.h"
#include "upcast.h"
+#include <scripting/pdep/llimits.h>
namespace Widelands {
// Versions
-// Since V3: m_old_buildings vector
+// V3 (b18): m_old_buildings vector
#define CURRENT_PACKET_VERSION 3
// Subversions
#define CURRENT_DISMANTLESITE_PACKET_VERSION 1
-// Since V3: m_prev_building not written
+// CSITE: V3 (b18) m_prev_building not written
#define CURRENT_CONSTRUCTIONSITE_PACKET_VERSION 3
#define CURRENT_PARTIALLYFB_PACKET_VERSION 1
-#define CURRENT_WAREHOUSE_PACKET_VERSION 6
+// WAREHOUSE: V7 (b18) splitted storage
+#define CURRENT_WAREHOUSE_PACKET_VERSION 7
+// MILITARYSITE: V4 (b18) splitted garrison
#define CURRENT_MILITARYSITE_PACKET_VERSION 4
#define CURRENT_PRODUCTIONSITE_PACKET_VERSION 5
+// TRAININGSITE: V4 (b18) splitted garrison/upgrade request
#define CURRENT_TRAININGSITE_PACKET_VERSION 4
+#define CURRENT_GARRISON_PACKET_VERSION 1
+#define CURRENT_STORAGE_PACKET_VERSION 1
void Map_Buildingdata_Data_Packet::Read
@@ -478,54 +484,60 @@
{
try {
uint16_t const packet_version = fr.Unsigned16();
- if
- (1 <= packet_version and
- packet_version <= CURRENT_WAREHOUSE_PACKET_VERSION)
- {
+ if (packet_version < 1 || packet_version > CURRENT_WAREHOUSE_PACKET_VERSION) {
+ throw game_data_error
+ (_("unknown/unhandled version %u"), packet_version);
+ }
+ if (packet_version >= 7) {
+ read_storage(*warehouse.get_storage(), fr, game, mol);
+ } else {
+ // init supply
+ upcast(StorageHandler, sh, warehouse.get_storage());
+ StorageSupply* ss = sh->m_supply.get();
Ware_Index const nr_wares = warehouse.tribe().get_nrwares ();
Ware_Index const nr_tribe_workers = warehouse.tribe().get_nrworkers();
- warehouse.m_supply->set_nrwares (nr_wares);
- warehouse.m_supply->set_nrworkers(nr_tribe_workers);
- warehouse.m_ware_policy.resize(nr_wares.value(), Warehouse::SP_Normal);
- warehouse.m_worker_policy.resize
- (nr_tribe_workers.value(), Warehouse::SP_Normal);
- //log("Reading warehouse stuff for %p\n", &warehouse);
- // supply
+ ss->set_nrwares (nr_wares);
+ ss->set_nrworkers(nr_tribe_workers);
+ sh->m_ware_policy.resize(nr_wares.value(), Storage::StockPolicy::Normal);
+ sh->m_worker_policy.resize
+ (nr_tribe_workers.value(),Storage::StockPolicy::Normal);
+ // ware supplies
const Tribe_Descr & tribe = warehouse.tribe();
while (fr.Unsigned8()) {
- Ware_Index const id = tribe.ware_index(fr.CString());
+ const char* ware_name = fr.CString();
+ Ware_Index const id = tribe.ware_index(ware_name);
+ Storage::StockPolicy policy = Storage::StockPolicy::Normal;
+ uint32_t amount = 0;
if (packet_version >= 5) {
- uint32_t amount = fr.Unsigned32();
- Warehouse::StockPolicy policy =
- static_cast<Warehouse::StockPolicy>(fr.Unsigned8());
-
- if (id) {
- warehouse.insert_wares(id, amount);
- warehouse.set_ware_policy(id, policy);
- }
- } else {
- uint16_t amount = fr.Unsigned16();
-
- if (id)
- warehouse.insert_wares(id, amount);
+ amount = fr.Unsigned32();
+ policy = static_cast<Storage::StockPolicy>(fr.Unsigned8());
+ } else {
+ amount = static_cast<uint32_t>(fr.Unsigned16());
+ }
+ if (id) {
+ ss->add_wares(id, amount);
+ sh->set_ware_policy(id, policy);
+ } else {
+ throw game_data_error(_("warehouse: Unknown ware %s (id %d)\n"), ware_name, id.value());
}
}
+ // worker supplies
while (fr.Unsigned8()) {
- Ware_Index const id = tribe.worker_index(fr.CString());
+ const char* name = fr.CString();
+ Ware_Index const id = tribe.worker_index(name);
+ Storage::StockPolicy policy = Storage::StockPolicy::Normal;
+ uint32_t amount = 0;
if (packet_version >= 5) {
- uint32_t amount = fr.Unsigned32();
- Warehouse::StockPolicy policy =
- static_cast<Warehouse::StockPolicy>(fr.Unsigned8());
-
- if (id) {
- warehouse.insert_workers(id, amount);
- warehouse.set_worker_policy(id, policy);
- }
- } else {
- uint16_t amount = fr.Unsigned16();
-
- if (id)
- warehouse.insert_workers(id, amount);
+ amount = fr.Unsigned32();
+ policy = static_cast<Storage::StockPolicy>(fr.Unsigned8());
+ } else {
+ amount = static_cast<uint32_t>(fr.Unsigned16());
+ }
+ if (id) {
+ ss->add_workers(id, amount);
+ sh->set_worker_policy(id, policy);
+ } else {
+ throw game_data_error(_("storage: Unknown worker %s (id %d)\n"), name, id.value());
}
}
@@ -535,145 +547,104 @@
while (nrrequests--) {
std::unique_ptr<Request> req
(new Request
- (warehouse,
- Ware_Index::First(),
- &Warehouse::request_cb,
- wwWORKER));
+ (warehouse,
+ Ware_Index::First(),
+ &StorageHandler::planned_worker_callback,
+ wwWORKER));
req->Read(fr, game, mol);
}
}
- assert(warehouse.m_incorporated_workers.empty());
- {
- uint16_t const nr_workers = fr.Unsigned16();
- for (uint16_t i = 0; i < nr_workers; ++i) {
- uint32_t const worker_serial = fr.Unsigned32();
-
- try {
- Worker & worker = mol.get<Worker>(worker_serial);
- if (1 == packet_version) {
- char const * const name = fr.CString();
- if (name != worker.name())
- throw game_data_error
- (_("expected %s but found \"%s\""),
- worker.name().c_str(), name);
+ // Incorporated workers
+ uint16_t const nr_workers = fr.Unsigned16();
+ for (uint16_t i = 0; i < nr_workers; ++i) {
+ uint32_t const worker_serial = fr.Unsigned32();
+ try {
+ Worker & worker = mol.get<Worker>(worker_serial);
+ if (1 == packet_version) {
+ char const * const name = fr.CString();
+ if (name != worker.name()) {
+ throw game_data_error
+ (_("incorporated worker name : expected %s but found \"%s\""),
+ worker.name().c_str(), name);
}
- Ware_Index worker_index = tribe.worker_index(worker.name().c_str());
- if (!warehouse.m_incorporated_workers.count(worker_index))
- warehouse.m_incorporated_workers[worker_index] = std::vector<Worker *>();
- warehouse.m_incorporated_workers[worker_index].push_back(&worker);
- } catch (const _wexception & e) {
- throw game_data_error
- ("incorporated worker #%u (%u): %s",
- i, worker_serial, e.what());
- }
+ }
+ StorageHandler::StockedWorkerAtr* atr = sh->store_worker_atr(worker);
+ if (atr != nullptr) {
+ sh->m_stocked_workers_atr.push_back(*atr);
+ }
+ mol.schedule_destroy(worker);
+ } catch (const _wexception & e) {
+ throw game_data_error
+ ("incorporated worker #%u (%u): %s",
+ i, worker_serial, e.what());
}
}
-
+ // Auto spawning
const std::vector<Ware_Index> & worker_types_without_cost =
tribe.worker_types_without_cost();
if (1 == packet_version) { // a single next_spawn time for "carrier"
uint32_t const next_spawn = fr.Unsigned32();
- Ware_Index const worker_index =
- tribe.safe_worker_index("carrier");
+ Ware_Index const worker_index = tribe.safe_worker_index("carrier");
if (not worker_index) {
log
("WARNING: %s %u has a next_spawn time for nonexistent "
- "worker type \"%s\" set to %u, ignoring\n",
- warehouse.descname().c_str(), warehouse.serial(),
- "carrier", next_spawn);
- } else if
- (tribe.get_worker_descr(worker_index)->buildcost().size())
- {
+ "worker type \"%s\" set to %u, ignoring\n",
+ warehouse.descname().c_str(), warehouse.serial(),
+ "carrier", next_spawn);
+ } else if (tribe.get_worker_descr(worker_index)->buildcost().size()) {
log
("WARNING: %s %u has a next_spawn time for worker type "
- "\"%s\", that costs something to build, set to %u, "
- "ignoring\n",
- warehouse.descname().c_str(), warehouse.serial(),
- "carrier", next_spawn);
- } else
- for (uint8_t i = 0;; ++i) {
- assert(i < worker_types_without_cost.size());
- if (worker_types_without_cost.at(i) == worker_index) {
- if
- (warehouse.m_next_worker_without_cost_spawn[i]
- !=
- static_cast<uint32_t>(Never()))
- {
- warehouse.molog
- ("read_warehouse: "
- "m_next_worker_without_cost_spawn[%u] = %u\n",
- i, warehouse.m_next_worker_without_cost_spawn[i]);
- }
- assert
- (warehouse.m_next_worker_without_cost_spawn[i]
- ==
- static_cast<uint32_t>(Never()));
- warehouse.m_next_worker_without_cost_spawn[i] =
- next_spawn;
- break;
- }
- }
- } else
+ "\"%s\", that costs something to build, set to %u, "
+ "ignoring\n",
+ warehouse.descname().c_str(), warehouse.serial(),
+ "carrier", next_spawn);
+ } else {
+ sh->add_worker_spawn(worker_index);
+ uint32_t* next_act = &sh->m_spawn_wares.at(worker_index).at(0);
+ *next_act = next_spawn;
+ }
+ } else {
for (;;) {
char const * const worker_typename = fr.CString ();
- if (not *worker_typename) // encountered the terminator ("")
+ if (not *worker_typename) { // encountered the terminator ("")
break;
- uint32_t const next_spawn = fr.Unsigned32();
- Ware_Index const worker_index =
- tribe.safe_worker_index(worker_typename);
+ }
+ uint32_t const next_spawn = fr.Unsigned32();
+ Ware_Index const worker_index = tribe.safe_worker_index(worker_typename);
if (not worker_index) {
log
("WARNING: %s %u has a next_spawn time for nonexistent "
- "worker type \"%s\" set to %u, ignoring\n",
- warehouse.descname().c_str(), warehouse.serial(),
- worker_typename, next_spawn);
+ "worker type \"%s\" set to %u, ignoring\n",
+ warehouse.descname().c_str(), warehouse.serial(),
+ worker_typename, next_spawn);
continue;
}
if (tribe.get_worker_descr(worker_index)->buildcost().size()) {
log
("WARNING: %s %u has a next_spawn time for worker type "
- "\"%s\", that costs something to build, set to %u, "
- "ignoring\n",
- warehouse.descname().c_str(), warehouse.serial(),
- worker_typename, next_spawn);
+ "\"%s\", that costs something to build, set to %u, "
+ "ignoring\n",
+ warehouse.descname().c_str(), warehouse.serial(),
+ worker_typename, next_spawn);
continue;
}
- for (uint8_t i = 0;; ++i) {
- assert(i < worker_types_without_cost.size());
- if (worker_types_without_cost.at(i) == worker_index) {
- if
- (warehouse.m_next_worker_without_cost_spawn[i]
- !=
- static_cast<uint32_t>(Never()))
- throw game_data_error
- (_
- ("%s %u has a next_spawn time for worker type "
- "\"%s\" set to %u, but it was previously set "
- "to %u\n"),
- warehouse.descname().c_str(), warehouse.serial(),
- worker_typename, next_spawn,
- warehouse.m_next_worker_without_cost_spawn[i]);
- warehouse.m_next_worker_without_cost_spawn[i] =
- next_spawn;
- break;
- }
- }
+ sh->add_worker_spawn(worker_index);
+ uint32_t* next_act = &sh->m_spawn_workers.at(worker_index).at(0);
+ *next_act = next_spawn;
}
- // The checks that the warehouse has a next_spawn time for each
- // worker type that the player is allowed to spawn, is in
- // Warehouse::load_finish.
+ }
+ // The checks that the warehouse has a next_spawn time for each
+ // worker type that the player is allowed to spawn, is in
+ // Warehouse::load_finish.
if (packet_version >= 3) {
// Read planned worker data
// Consistency checks are in Warehouse::load_finish
uint32_t nr_planned_workers = fr.Unsigned32();
while (nr_planned_workers--) {
- warehouse.m_planned_workers.push_back
- (Warehouse::PlannedWorkers());
- Warehouse::PlannedWorkers & pw =
- warehouse.m_planned_workers.back();
+ StorageHandler::PlannedWorkers pw;
pw.index = tribe.worker_index(fr.CString());
pw.amount = fr.Unsigned32();
@@ -681,87 +652,82 @@
while (nr_requests--) {
pw.requests.push_back
(new Request
- (warehouse,
- Ware_Index::First(),
- &Warehouse::request_cb,
- wwWORKER));
+ (warehouse,
+ Ware_Index::First(),
+ &StorageHandler::planned_worker_callback,
+ wwWORKER));
pw.requests.back()->Read(fr, game, mol);
}
+ sh->m_planned_workers.push_back(pw);
}
}
- if (packet_version >= 5)
- warehouse.m_next_stock_remove_act = fr.Unsigned32();
-
- if (packet_version >= 6) {
- if (warehouse.descr().get_isport()) {
- if (Serial portdock = fr.Unsigned32()) {
- warehouse.m_portdock = &mol.get<PortDock>(portdock);
- warehouse.m_portdock->set_economy(warehouse.get_economy());
-
- // Expedition specific stuff
- if (warehouse.m_portdock->expedition_started()) {
- // Expedition workers
- uint8_t num_of_workers = fr.Unsigned8();
- for (uint8_t i = 0; i < num_of_workers; ++i) {
- warehouse.get_expedition_workers().push_back(new Warehouse::Expedition_Worker);
- if (fr.Unsigned8() == 1) {
- warehouse.get_expedition_workers().back()->worker_request =
- new Request
- (warehouse,
- Ware_Index::First(),
- Warehouse::request_expedition_worker_callback,
- wwWORKER);
- warehouse.get_expedition_workers().back()->worker_request->Read(fr, game, mol);
- } else {
- warehouse.get_expedition_workers().back()->worker =
- &mol.get<Worker>(fr.Unsigned32());
- }
+ if (packet_version >= 5) {
+ sh->m_removal_next_act = fr.Unsigned32();
+ }
+ }
+ // Port stuff
+ if (packet_version >= 6) {
+ if (warehouse.descr().get_isport()) {
+ if (Serial portdock = fr.Unsigned32()) {
+ warehouse.m_portdock = &mol.get<PortDock>(portdock);
+ warehouse.m_portdock->set_economy(warehouse.get_economy());
+
+ // Expedition specific stuff
+ if (warehouse.m_portdock->expedition_started()) {
+ // Expedition workers
+ uint8_t num_of_workers = fr.Unsigned8();
+ for (uint8_t i = 0; i < num_of_workers; ++i) {
+ warehouse.get_expedition_workers().push_back(new Warehouse::Expedition_Worker);
+ if (fr.Unsigned8() == 1) {
+ warehouse.get_expedition_workers().back()->worker_request =
+ new Request
+ (warehouse,
+ Ware_Index::First(),
+ Warehouse::request_expedition_worker_callback,
+ wwWORKER);
+ warehouse.get_expedition_workers().back()->worker_request->Read(fr, game, mol);
+ } else {
+ warehouse.get_expedition_workers().back()->worker =
+ &mol.get<Worker>(fr.Unsigned32());
}
-
- // Expedition WaresQueues
- uint8_t nr_queues = fr.Unsigned8();
- assert(warehouse.get_wares_queue_vector().empty());
- for (uint8_t i = 0; i < nr_queues; ++i) {
- WaresQueue * wq = new WaresQueue(warehouse, Ware_Index::Null(), 0);
- wq->Read(fr, game, mol);
- wq->set_callback(PortDock::expedition_wares_queue_callback, warehouse.m_portdock);
-
- if (!wq->get_ware()) {
- delete wq;
- } else {
- warehouse.get_wares_queue_vector().push_back(wq);
- }
+ }
+
+ // Expedition WaresQueues
+ uint8_t nr_queues = fr.Unsigned8();
+ assert(warehouse.get_wares_queue_vector().empty());
+ for (uint8_t i = 0; i < nr_queues; ++i) {
+ WaresQueue * wq = new WaresQueue(warehouse, Ware_Index::Null(), 0);
+ wq->Read(fr, game, mol);
+ wq->set_callback(PortDock::expedition_wares_queue_callback, warehouse.m_portdock);
+
+ if (!wq->get_ware()) {
+ delete wq;
+ } else {
+ warehouse.get_wares_queue_vector().push_back(wq);
}
}
}
}
}
-
- if (uint32_t const conquer_radius = warehouse.get_conquers()) {
- // Add to map of military influence.
- const Map & map = game.map();
- Area<FCoords> a
- (map.get_fcoords(warehouse.get_position()), conquer_radius);
- const Field & first_map_field = map[0];
- Player::Field * const player_fields =
- warehouse.owner().m_fields;
- MapRegion<Area<FCoords> > mr(map, a);
- do
- player_fields[mr.location().field - &first_map_field]
- .military_influence
- += map.calc_influence(mr.location(), Area<>(a, a.radius));
- while (mr.advance(map));
- }
- warehouse.owner().see_area
- (Area<FCoords>
- (game.map().get_fcoords(warehouse.get_position()),
- warehouse.vision_range()));
- warehouse.m_next_military_act = game.get_gametime();
- //log("Read warehouse stuff for %p\n", &warehouse);
- } else
- throw game_data_error
- (_("unknown/unhandled version %u"), packet_version);
+ }
+ // TODO move in warehouse loadfinished?
+ if (uint32_t const conquer_radius = warehouse.get_conquers()) {
+ // Add to map of military influence.
+ const Map & map = game.map();
+ Area<FCoords> a (map.get_fcoords(warehouse.get_position()), conquer_radius);
+ const Field & first_map_field = map[0];
+ Player::Field * const player_fields = warehouse.owner().m_fields;
+ MapRegion<Area<FCoords> > mr(map, a);
+ do {
+ player_fields[mr.location().field - &first_map_field].military_influence
+ += map.calc_influence(mr.location(), Area<>(a, a.radius));
+ } while (mr.advance(map));
+ }
+ warehouse.owner().see_area
+ (Area<FCoords>
+ (game.map().get_fcoords(warehouse.get_position()),
+ warehouse.vision_range()));
} catch (const _wexception & e) {
throw game_data_error(_("warehouse: %s"), e.what());
}
@@ -777,114 +743,61 @@
try {
uint16_t const packet_version = fr.Unsigned16();
bool rel17comp = false;
- if (3 == packet_version and 4 == CURRENT_MILITARYSITE_PACKET_VERSION)
+ if (3 == packet_version and 4 == CURRENT_MILITARYSITE_PACKET_VERSION) {
rel17comp = true;
- if (packet_version == CURRENT_MILITARYSITE_PACKET_VERSION or rel17comp)
- {
+ }
+ if (CURRENT_MILITARYSITE_PACKET_VERSION == 4 || rel17comp) {
read_productionsite(militarysite, fr, game, mol);
-
- militarysite.m_normal_soldier_request.reset();
-
- if (fr.Unsigned8()) {
- militarysite.m_normal_soldier_request.reset
- (new Request
- (militarysite,
- Ware_Index::First(),
- MilitarySite::request_soldier_callback,
- wwWORKER));
- militarysite.m_normal_soldier_request->Read(fr, game, mol);
- }
- else
- militarysite.m_normal_soldier_request.reset();
-
- if (rel17comp) // compatibility with release 17 savegames
- militarysite.m_upgrade_soldier_request.reset();
- else
- if (fr.Unsigned8())
- {
- militarysite.m_upgrade_soldier_request.reset
- (new Request
- (militarysite,
- (!militarysite.m_normal_soldier_request) ? Ware_Index::First()
- : militarysite.descr().tribe().safe_worker_index("soldier"),
- MilitarySite::request_soldier_callback,
- wwWORKER));
- militarysite.m_upgrade_soldier_request->Read(fr, game, mol);
- }
- else
- militarysite.m_upgrade_soldier_request.reset();
-
-
- if ((militarysite.m_didconquer = fr.Unsigned8())) {
- // Add to map of military influence.
- const Map & map = game.map();
- Area<FCoords> a
- (map.get_fcoords(militarysite.get_position()),
- militarysite.get_conquers());
- const Field & first_map_field = map[0];
- Player::Field * const player_fields =
- militarysite.owner().m_fields;
- MapRegion<Area<FCoords> > mr(map, a);
- do
- player_fields[mr.location().field - &first_map_field]
- .military_influence
- += map.calc_influence(mr.location(), Area<>(a, a.radius));
- while (mr.advance(map));
- }
-
- // capacity (modified by user)
- militarysite.m_capacity = fr.Unsigned8();
- militarysite.m_nexthealtime = fr.Signed32();
- if (not (rel17comp)) // compatibility with release 17 savegames
- {
-
- uint16_t reqmin = fr.Unsigned16();
- uint16_t reqmax = fr.Unsigned16();
- militarysite.m_soldier_upgrade_requirements = RequireAttribute(atrTotal, reqmin, reqmax);
- militarysite.m_soldier_preference = static_cast<MilitarySite::SoldierPreference>(fr.Unsigned8());
- militarysite.m_next_swap_soldiers_time = fr.Signed32();
- militarysite.m_soldier_upgrade_try = 0 != fr.Unsigned8() ? true : false;
- militarysite.m_doing_upgrade_request = 0 != fr.Unsigned8() ? true : false;
- }
- else // Release 17 compatibility branch. Some safe values.
- {
- militarysite.m_soldier_preference = MilitarySite::kPrefersRookies;
- if (2 < militarysite.m_capacity)
- militarysite.m_soldier_preference = MilitarySite::kPrefersHeroes;
- militarysite.m_next_swap_soldiers_time = militarysite.m_nexthealtime;
- militarysite.m_soldier_upgrade_try = false;
- militarysite.m_doing_upgrade_request = false;
- }
-
- } else
+ upcast(GarrisonHandler, gh, militarysite.get_garrison());
+
+ if (packet_version == CURRENT_MILITARYSITE_PACKET_VERSION) {
+ read_garrison(*gh, fr, game, mol);
+ } else if (rel17comp) {
+ gh->m_normal_soldier_request.reset();
+ if (fr.Unsigned8()) {
+ gh->m_normal_soldier_request.reset
+ (new Request
+ (militarysite,
+ Ware_Index::First(),
+ GarrisonHandler::request_soldier_callback,
+ wwWORKER));
+ gh->m_normal_soldier_request->Read(fr, game, mol);
+ }
+
+ gh->m_upgrade_soldier_request.reset();
+
+ if ((gh->m_didconquer = fr.Unsigned8())) {
+ // Add to map of military influence.
+ const Map & map = game.map();
+ Area<FCoords> a
+ (map.get_fcoords(militarysite.get_position()),
+ militarysite.get_conquers());
+ const Field & first_map_field = map[0];
+ Player::Field * const player_fields =
+ militarysite.owner().m_fields;
+ MapRegion<Area<FCoords> > mr(map, a);
+ do
+ player_fields[mr.location().field - &first_map_field]
+ .military_influence
+ += map.calc_influence(mr.location(), Area<>(a, a.radius));
+ while (mr.advance(map));
+ }
+
+ // capacity (modified by user)
+ gh->m_capacity = fr.Unsigned8();
+ gh->m_last_heal_time = fr.Signed32() - 1000;
+ // Release 17 compatibility branch. Some safe values.
+ gh->m_soldier_preference = Garrison::SoldierPref::Rookies;
+ if (2 < gh->m_capacity) {
+ gh->m_soldier_preference = Garrison::SoldierPref::Heroes;
+ }
+ gh->m_last_swap_soldiers_time = gh->m_last_heal_time;
+ gh->m_try_soldier_upgrade = false;
+ gh->m_doing_upgrade_request = false;
+ }
+ } else {
throw game_data_error
(_("unknown/unhandled version %u"), packet_version);
-
- // If the site's capacity is outside the allowed range (can happen if
- // the site's type's definition has changed), set the variable to the
- // nearest valid value.
- //
- // This does not drop excessive soldiers, since they are not loaded into
- // the site yet. To do that we would have to do this change by adding a
- // Cmd_ChangeSoldierCapacity to the beginning of the game's command
- // queue. But that would not work because the command queue is not read
- // yet and will be cleared before it is read.
- if (militarysite.m_capacity < militarysite.minSoldierCapacity()) {
- log
- ("WARNING: militarysite %u of player %u at (%i, %i) has capacity "
- "set to %u but it must be at least %u. Changing to that value.\n",
- militarysite.serial(), militarysite.owner().player_number(),
- militarysite.get_position().x, militarysite.get_position().y,
- militarysite.m_capacity, militarysite.minSoldierCapacity());
- militarysite.m_capacity = militarysite.minSoldierCapacity();
- } else if (militarysite.maxSoldierCapacity() < militarysite.m_capacity) {
- log
- ("WARNING: militarysite %u of player %u at (%i, %i) has capacity "
- "set to %u but it can be at most %u. Changing to that value.\n",
- militarysite.serial(), militarysite.owner().player_number(),
- militarysite.get_position().x, militarysite.get_position().y,
- militarysite.m_capacity, militarysite.maxSoldierCapacity());
- militarysite.m_capacity = militarysite.maxSoldierCapacity();
}
} catch (const _wexception & e) {
throw game_data_error(_("militarysite: %s"), e.what());
@@ -1176,28 +1089,30 @@
uint16_t const trainingsite_packet_version = fr.Unsigned16();
bool rel17comp = false; // compatibility with release 17
- if (4 == CURRENT_TRAININGSITE_PACKET_VERSION && 3 == trainingsite_packet_version)
+ if (4 == CURRENT_TRAININGSITE_PACKET_VERSION && 3 == trainingsite_packet_version) {
rel17comp = true;
+ }
+ upcast(GarrisonHandler, gh, trainingsite.get_garrison());
- if (trainingsite_packet_version == CURRENT_TRAININGSITE_PACKET_VERSION or rel17comp)
- {
+ if (trainingsite_packet_version == CURRENT_TRAININGSITE_PACKET_VERSION || rel17comp) {
read_productionsite(trainingsite, fr, game, mol);
-
- delete trainingsite.m_soldier_request;
- trainingsite.m_soldier_request = 0;
- if (fr.Unsigned8()) {
- trainingsite.m_soldier_request =
- new Request
- (trainingsite,
- Ware_Index::First(),
- TrainingSite::request_soldier_callback,
- wwWORKER);
- trainingsite.m_soldier_request->Read(fr, game, mol);
+ if (!rel17comp) {
+ read_garrison(*gh, fr, game, mol);
+ } else {
+ gh->m_normal_soldier_request.reset();
+ if (fr.Unsigned8()) {
+ Request* r = new Request
+ (trainingsite,
+ Ware_Index::First(),
+ GarrisonHandler::request_soldier_callback,
+ wwWORKER);
+ gh->m_normal_soldier_request.reset(r);
+ gh->m_normal_soldier_request->Read(fr, game, mol);
+ }
+ gh->m_capacity = fr.Unsigned8();
}
-
- trainingsite.m_capacity = fr.Unsigned8();
trainingsite.m_build_heroes = fr.Unsigned8();
-
+ // UPgrades
uint8_t const nr_upgrades = fr.Unsigned8();
for (uint8_t i = 0; i < nr_upgrades; ++i) {
tAttribute attribute = static_cast<tAttribute>(fr.Unsigned8());
@@ -1216,9 +1131,8 @@
fr.Signed32();
}
}
- // load premature kick-out state, was not in release 17..
- if (not rel17comp)
- {
+ if (!rel17comp) {
+ // load premature kick-out state, was not in release 17..
uint16_t mapsize = fr.Unsigned16();
while (mapsize)
{
@@ -1231,41 +1145,216 @@
trainingsite.training_failure_count[std::make_pair(traintype, trainlevel)] = t;
}
}
- } else
+
+ if (rel17comp) {
+ // Check capacities
+ if (gh->m_capacity < gh->minSoldierCapacity()) {
+ log
+ ("WARNING: trainingsite %u of player %u at (%i, %i) has capacity "
+ "set to %u but it must be at least %u. Changing to that value.\n",
+ trainingsite.serial(), trainingsite.owner().player_number(),
+ trainingsite.get_position().x, trainingsite.get_position().y,
+ gh->m_capacity, gh->minSoldierCapacity());
+ gh->m_capacity = gh->minSoldierCapacity();
+ } else if (gh->maxSoldierCapacity() < gh->m_capacity) {
+ log
+ ("WARNING: trainingsite %u of player %u at (%i, %i) has capacity "
+ "set to %u but it can be at most %u. Changing to that value.\n",
+ trainingsite.serial(), trainingsite.owner().player_number(),
+ trainingsite.get_position().x, trainingsite.get_position().y,
+ gh->m_capacity, gh->maxSoldierCapacity());
+ gh->m_capacity = gh->maxSoldierCapacity();
+ }
+ }
+ } else {
throw game_data_error
(_("unknown/unhandled version %u"), trainingsite_packet_version);
-
- // If the site's capacity is outside the allowed range (can happen if
- // the site's type's definition has changed), set the variable to the
- // nearest valid value.
- //
- // This does not drop excessive soldiers, since they are not loaded into
- // the site yet. To do that we would have to do this change by adding a
- // Cmd_ChangeSoldierCapacity to the beginning of the game's command
- // queue. But that would not work because the command queue is not read
- // yet and will be cleared before it is read.
- if (trainingsite.m_capacity < trainingsite.minSoldierCapacity()) {
- log
- ("WARNING: trainingsite %u of player %u at (%i, %i) has capacity "
- "set to %u but it must be at least %u. Changing to that value.\n",
- trainingsite.serial(), trainingsite.owner().player_number(),
- trainingsite.get_position().x, trainingsite.get_position().y,
- trainingsite.m_capacity, trainingsite.minSoldierCapacity());
- trainingsite.m_capacity = trainingsite.minSoldierCapacity();
- } else if (trainingsite.maxSoldierCapacity() < trainingsite.m_capacity) {
- log
- ("WARNING: trainingsite %u of player %u at (%i, %i) has capacity "
- "set to %u but it can be at most %u. Changing to that value.\n",
- trainingsite.serial(), trainingsite.owner().player_number(),
- trainingsite.get_position().x, trainingsite.get_position().y,
- trainingsite.m_capacity, trainingsite.maxSoldierCapacity());
- trainingsite.m_capacity = trainingsite.maxSoldierCapacity();
}
} catch (const _wexception & e) {
throw game_data_error(_("trainingsite: %s"), e.what());
}
}
+void Map_Buildingdata_Data_Packet::read_garrison(Garrison& g, FileRead& fr, Game& game, Map_Map_Object_Loader& mor)
+{
+ try {
+ GarrisonHandler& gh = ref_cast<GarrisonHandler, Garrison>(g);
+ uint16_t paquet_version = fr.Unsigned16();
+ gh.m_min_capacity = fr.Unsigned32();
+ gh.m_max_capacity = fr.Unsigned32();
+ gh.m_capacity = fr.Unsigned32();
+ // FIXME CGH ensuire soldiers are added later
+ gh.m_passive = fr.Unsigned8() > 0;
+ gh.m_heal_per_second = fr.Unsigned32();
+ gh.m_last_heal_time = fr.Unsigned32();
+ gh.m_soldier_requirements.Read(fr, game, mor);
+ gh.m_soldier_upgrade_requirements = RequireAttribute
+ (atrTotal, fr.Unsigned32(), fr.Unsigned32());
+ if (fr.Unsigned8()) {
+ gh.m_normal_soldier_request.reset(new Request
+ (gh.m_building, Ware_Index::First(),
+ GarrisonHandler::request_soldier_callback,
+ wwWORKER));
+ gh.m_normal_soldier_request->Read(fr, game, mor);
+ }
+ if (fr.Unsigned8()) {
+ gh.m_upgrade_soldier_request.reset(new Request
+ (gh.m_building,
+ (!gh.m_normal_soldier_request) ? Ware_Index::First()
+ : gh.m_building.descr().tribe().safe_worker_index("soldier"),
+ GarrisonHandler::request_soldier_callback,
+ wwWORKER, GarrisonHandler::request_soldier_transfer_callback));
+ gh.m_upgrade_soldier_request->Read(fr, game, mor);
+ }
+ gh.m_conquer_radius = fr.Unsigned32();
+ gh.m_didconquer = fr.Unsigned8() > 0;
+ gh.m_soldier_preference = static_cast<Garrison::SoldierPref>(fr.Unsigned8());
+ gh.m_last_swap_soldiers_time = fr.Unsigned32();
+ gh.m_try_soldier_upgrade = fr.Unsigned8() > 0;
+ gh.m_doing_upgrade_request = fr.Unsigned8() > 0;
+
+ // Ensure capacity range
+ // If the site's capacity is outside the allowed range (can happen if
+ // the site's type's definition has changed), set the variable to the
+ // nearest valid value.
+ //
+ // This does not drop excessive soldiers, since they are not loaded into
+ // the site yet. To do that we would have to do this change by adding a
+ // Cmd_ChangeSoldierCapacity to the beginning of the game's command
+ // queue. But that would not work because the command queue is not read
+ // yet and will be cleared before it is read.
+ if (gh.m_capacity < gh.m_min_capacity) {
+ log
+ ("WARNING: garrison %u of player %u at (%i, %i) has capacity "
+ "set to %u but it must be at least %u. Changing to that value.\n",
+ gh.m_building.serial(), gh.owner().player_number(),
+ gh.m_building.get_position().x, gh.m_building.get_position().y,
+ gh.m_capacity, gh.minSoldierCapacity());
+ gh.m_capacity = gh.minSoldierCapacity();
+ } else if (gh.maxSoldierCapacity() < gh.m_capacity) {
+ log
+ ("WARNING: militarysite %u of player %u at (%i, %i) has capacity "
+ "set to %u but it can be at most %u. Changing to that value.\n",
+ gh.m_building.serial(), gh.owner().player_number(),
+ gh.m_building.get_position().x, gh.m_building.get_position().y,
+ gh.m_capacity, gh.maxSoldierCapacity());
+ gh.m_capacity = gh.maxSoldierCapacity();
+ }
+ // Update map of military influence
+ if (gh.m_didconquer) {
+ const Map & map = game.map();
+ Area<FCoords> a
+ (map.get_fcoords(gh.m_building.get_position()), gh.m_conquer_radius);
+ const Field & first_map_field = map[0];
+ Player::Field * const player_fields = gh.owner().m_fields;
+ MapRegion<Area<FCoords> > mr(map, a);
+ do
+ player_fields[mr.location().field - &first_map_field]
+ .military_influence
+ += map.calc_influence(mr.location(), Area<>(a, a.radius));
+ while (mr.advance(map));
+ }
+ } catch (const _wexception e) {
+ throw game_data_error(_("garrison: %s"), e.what());
+ }
+}
+
+void Map_Buildingdata_Data_Packet::read_storage
+ (Storage& storage, FileRead& fr, Game& game, Map_Map_Object_Loader& mol)
+{
+ try {
+ StorageHandler & sh = ref_cast<StorageHandler, Storage>(storage);
+ uint16_t packet_version = fr.Unsigned16();
+ if (packet_version != CURRENT_STORAGE_PACKET_VERSION) {
+ throw game_data_error(_("storage: Unkhandled packet version %d"), packet_version);
+ }
+ // basics
+ sh.m_removal_next_act = fr.Unsigned32();
+ // ware supplies
+ StorageSupply* ss = sh.m_supply.get();
+ const Tribe_Descr& tribe = sh.owner().tribe();
+ Ware_Index const nr_wares = tribe.get_nrwares();
+ ss->set_nrwares(nr_wares);
+ sh.m_ware_policy.resize(nr_wares.value(), Storage::StockPolicy::Normal);
+ while (fr.Unsigned8()) {
+ const char* ware_name = fr.CString();
+ Ware_Index const id = tribe.ware_index(ware_name);
+ uint32_t amount = fr.Unsigned32();
+ Storage::StockPolicy policy = static_cast<Storage::StockPolicy>(fr.Unsigned8());
+ if (id) {
+ ss->add_wares(id, amount);
+ sh.set_ware_policy(id, policy);
+ } else {
+ throw game_data_error(_("storage: Unknown ware %s (id %d)\n"), ware_name, id.value());
+ }
+ if (fr.Unsigned8()) {
+ std::vector<uint32_t> spawn_values =
+ {fr.Unsigned32(), fr.Unsigned32(), fr.Unsigned32()};
+ if (fr.Unsigned8()) {
+ spawn_values.push_back(fr.Unsigned32());
+ }
+ sh.m_spawn_wares.insert(std::make_pair(id, spawn_values));
+ }
+ }
+ // worker supplies
+ Ware_Index const nr_workers = tribe.get_nrworkers();
+ ss->set_nrworkers(nr_workers);
+ sh.m_worker_policy.resize(nr_workers.value(), Storage::StockPolicy::Normal);
+ while (fr.Unsigned8()) {
+ const char* worker_name = fr.CString();
+ Ware_Index const id = tribe.ware_index(worker_name);
+ uint32_t amount = fr.Unsigned32();
+ Storage::StockPolicy policy = static_cast<Storage::StockPolicy>(fr.Unsigned8());
+ if (id) {
+ ss->add_workers(id, amount);
+ sh.set_worker_policy(id, policy);
+ } else {
+ throw game_data_error(_("storage: Unknown worker %s (id %d)\n"), worker_name, id.value());
+ }
+ if (fr.Unsigned8()) {
+ std::vector<uint32_t> spawn_values =
+ {fr.Unsigned32(), fr.Unsigned32(), fr.Unsigned32()};
+ if (fr.Unsigned8()) {
+ spawn_values.push_back(fr.Unsigned32());
+ }
+ sh.m_spawn_workers.insert(std::make_pair(id, spawn_values));
+ }
+ }
+ // planned workers
+ uint32_t planned_amount = fr.Unsigned32();
+ while (planned_amount--) {
+ StorageHandler::PlannedWorkers pw;
+ pw.index = tribe.worker_index(fr.CString());
+ pw.amount = fr.Unsigned32();
+ uint32_t nr_requests = fr.Unsigned32();
+ while (nr_requests--) {
+ Request* r = new Request
+ (sh.get_building(),
+ Ware_Index::First(),
+ &StorageHandler::planned_worker_callback,
+ wwWORKER);
+ r->Read(fr, game, mol);
+ pw.requests.push_back(r);
+ }
+ sh.m_planned_workers.push_back(pw);
+ }
+ // stocked attributes
+ uint32_t stocked_amount = fr.Unsigned32();
+ while (stocked_amount--) {
+ StorageHandler::StockedWorkerAtr stocked_atr;
+ stocked_atr.index = tribe.worker_index(fr.CString());;
+ stocked_atr.descr = tribe.get_worker_descr(stocked_atr.index);
+ stocked_atr.atck_lvl = fr.Unsigned32();
+ stocked_atr.evade_lvl = fr.Unsigned32();
+ stocked_atr.defense_lvl = fr.Unsigned32();
+ stocked_atr.exp_or_hp_lvl = fr.Unsigned32();
+ sh.m_stocked_workers_atr.push_back(stocked_atr);
+ }
+ } catch (const _wexception e) {
+ throw game_data_error(_("storage: %s"), e.what());
+ }
+}
+
void Map_Buildingdata_Data_Packet::Write
(FileSystem & fs, Editor_Game_Base & egbase, Map_Map_Object_Saver & mos)
@@ -1453,82 +1542,9 @@
{
fw.Unsigned16(CURRENT_WAREHOUSE_PACKET_VERSION);
- // supply
- const Tribe_Descr & tribe = warehouse.tribe();
- const WareList & wares = warehouse.m_supply->get_wares();
- for (Ware_Index i = Ware_Index::First(); i < wares.get_nrwareids (); ++i) {
- fw.Unsigned8(1);
- fw.String(tribe.get_ware_descr(i)->name());
- fw.Unsigned32(wares.stock(i));
- fw.Unsigned8(warehouse.get_ware_policy(i));
- }
- fw.Unsigned8(0);
- const WareList & workers = warehouse.m_supply->get_workers();
- for (Ware_Index i = Ware_Index::First(); i < workers.get_nrwareids(); ++i) {
- fw.Unsigned8(1);
- fw.String(tribe.get_worker_descr(i)->name());
- fw.Unsigned32(workers.stock(i));
- fw.Unsigned8(warehouse.get_worker_policy(i));
- }
- fw.Unsigned8(0);
-
- // Incorporated workers, write sorted after file-serial.
- uint32_t nworkers = 0;
- container_iterate_const(Warehouse::IncorporatedWorkers, warehouse.m_incorporated_workers, cwt)
- nworkers += cwt->second.size();
-
- fw.Unsigned16(nworkers);
- typedef std::map<uint32_t, const Worker *> TWorkerMap;
- TWorkerMap workermap;
- container_iterate_const(Warehouse::IncorporatedWorkers, warehouse.m_incorporated_workers, cwt) {
- container_iterate_const(Warehouse::WorkerList, cwt->second, i) {
- const Worker & w = *(*i);
- assert(mos.is_object_known(w));
- workermap.insert
- (std::pair<uint32_t, const Worker *>
- (mos.get_object_file_index(w), &w));
- }
- }
-
- container_iterate_const(TWorkerMap, workermap, i)
- {
- const Worker & obj = *i.current->second;
- assert(mos.is_object_known(obj));
- fw.Unsigned32(mos.get_object_file_index(obj));
- }
-
- {
- const std::vector<Ware_Index> & worker_types_without_cost =
- tribe.worker_types_without_cost();
- for (uint8_t i = worker_types_without_cost.size(); i;) {
- uint32_t const next_spawn =
- warehouse.m_next_worker_without_cost_spawn[--i];
- if (next_spawn != static_cast<uint32_t>(Never())) {
- fw.String
- (tribe.get_worker_descr(tribe.worker_types_without_cost().at(i))
- ->name());
- fw.Unsigned32(next_spawn);
- }
- }
- }
- fw.Unsigned8(0); // terminator for spawn times
-
- fw.Unsigned32(warehouse.m_planned_workers.size());
- container_iterate_const
- (std::vector<Warehouse::PlannedWorkers>,
- warehouse.m_planned_workers, pw_it)
- {
- fw.CString(tribe.get_worker_descr(pw_it.current->index)->name());
- fw.Unsigned32(pw_it.current->amount);
-
- fw.Unsigned32(pw_it.current->requests.size());
- container_iterate_const
- (std::vector<Request *>, pw_it.current->requests, req_it)
- (*req_it.current)->Write(fw, game, mos);
- }
-
- fw.Unsigned32(warehouse.m_next_stock_remove_act);
-
+ // Storage
+ write_storage(*warehouse.get_storage(), fw, game, mos);
+ // port stuff
if (warehouse.descr().get_isport()) {
fw.Unsigned32(mos.get_object_file_index_or_zero(warehouse.m_portdock));
@@ -1569,42 +1585,7 @@
{
fw.Unsigned16(CURRENT_MILITARYSITE_PACKET_VERSION);
write_productionsite(militarysite, fw, game, mos);
-
- if (militarysite.m_normal_soldier_request) {
- fw.Unsigned8(1);
- militarysite.m_normal_soldier_request->Write(fw, game, mos);
- } else {
- fw.Unsigned8(0);
- }
-
- if (militarysite.m_upgrade_soldier_request)
- {
- fw.Unsigned8(1);
- militarysite.m_upgrade_soldier_request->Write(fw, game, mos);
- }
- else
- fw.Unsigned8(0);
-
-
- fw.Unsigned8(militarysite.m_didconquer);
- fw.Unsigned8(militarysite.m_capacity);
- fw.Signed32(militarysite.m_nexthealtime);
-
- if (militarysite.m_normal_soldier_request)
- {
- if (militarysite.m_upgrade_soldier_request)
- {
- throw game_data_error
- ("Internal error in a MilitarySite -- cannot continue. Use previous autosave.");
- }
- }
- fw.Unsigned16(militarysite.m_soldier_upgrade_requirements.getMin());
- fw.Unsigned16(militarysite.m_soldier_upgrade_requirements.getMax());
- fw.Unsigned8(militarysite.m_soldier_preference);
- fw.Signed32(militarysite.m_next_swap_soldiers_time);
- fw.Unsigned8(militarysite.m_soldier_upgrade_try ? 1 : 0);
- fw.Unsigned8(militarysite.m_doing_upgrade_request ? 1 : 0);
-
+ write_garrison(*militarysite.get_garrison(), fw, game, mos);
}
@@ -1696,17 +1677,8 @@
fw.Unsigned16(CURRENT_TRAININGSITE_PACKET_VERSION);
write_productionsite(trainingsite, fw, game, mos);
-
- // requests
-
- if (trainingsite.m_soldier_request) {
- fw.Unsigned8(1);
- trainingsite.m_soldier_request->Write(fw, game, mos);
- } else {
- fw.Unsigned8(0);
- }
-
- fw.Unsigned8(trainingsite.m_capacity);
+ write_garrison(*trainingsite.get_garrison(), fw, game, mos);
+
fw.Unsigned8(trainingsite.m_build_heroes);
// upgrades
@@ -1736,4 +1708,138 @@
// DONE
}
+
+void Map_Buildingdata_Data_Packet::write_garrison(const Garrison& gar, FileWrite& fw, Game& g, Map_Map_Object_Saver& mos)
+{
+ const GarrisonHandler& gh = ref_cast<const GarrisonHandler, const Garrison>(gar);
+ fw.Unsigned16(CURRENT_GARRISON_PACKET_VERSION);
+
+ fw.Unsigned32(gh.m_min_capacity);
+ fw.Unsigned32(gh.m_max_capacity);
+ fw.Unsigned32(gh.m_capacity);
+ // Soldiers
+ // FIXME CGH ensure it is not needed
+ fw.Unsigned8(gh.m_passive ? 1 : 0);
+ fw.Unsigned32(gh.m_heal_per_second);
+ fw.Unsigned32(gh.m_last_heal_time);
+ // requirements-requests
+ gh.m_soldier_requirements.Write(fw, g, mos);
+ fw.Unsigned32(gh.m_soldier_upgrade_requirements.getMin());
+ fw.Unsigned32(gh.m_soldier_upgrade_requirements.getMax());
+ if (gh.m_normal_soldier_request && gh.m_upgrade_soldier_request) {
+ throw game_data_error
+ ("Internal error in a garrison -- cannot continue. Use previous autosave.");
+
+ }
+ if (gh.m_normal_soldier_request) {
+ fw.Unsigned8(1);
+ gh.m_normal_soldier_request->Write(fw, g, mos);
+ } else {
+ fw.Unsigned8(0);
+ }
+ if (gh.m_upgrade_soldier_request) {
+ fw.Unsigned8(1);
+ gh.m_upgrade_soldier_request->Write(fw, g, mos);
+ } else {
+ fw.Unsigned8(0);
+ }
+ //
+ fw.Unsigned32(gh.m_conquer_radius);
+ fw.Unsigned8(gh.m_didconquer ? 1 : 0);
+ // Jobs will be done by soldiers (i guess) //FIXME CGH
+ fw.Unsigned8(static_cast<uint8_t>(gh.m_soldier_preference));
+ fw.Unsigned32(gh.m_last_swap_soldiers_time);
+ fw.Unsigned8(gh.m_try_soldier_upgrade ? 1 : 0);
+ fw.Unsigned8(gh.m_doing_upgrade_request ? 1 : 0);
+}
+
+void Map_Buildingdata_Data_Packet::write_storage
+ (const Storage& storage, FileWrite& fw, Game& game, Map_Map_Object_Saver& mos)
+{
+ const StorageHandler& sh = ref_cast<const StorageHandler, const Storage>(storage);
+ fw.Unsigned16(CURRENT_STORAGE_PACKET_VERSION);
+ // basics
+ fw.Unsigned32(sh.m_removal_next_act);
+ // Ware supplies
+ StorageSupply* ss = sh.m_supply.get();
+ const Tribe_Descr& tribe = sh.owner().tribe();
+ const WareList & wares = ss->get_wares();
+ log("WriteStorage : %d wares, %d ware policies\n", wares.get_nrwareids().value(), sh.m_ware_policy.size());
+ for (Ware_Index i = Ware_Index::First(); i < wares.get_nrwareids (); ++i) {
+ fw.Unsigned8(1);
+ fw.String(tribe.get_ware_descr(i)->name());
+ fw.Unsigned32(wares.stock(i));
+ fw.Unsigned8(static_cast<uint8_t>(sh.get_ware_policy(i)));
+ if (sh.m_spawn_wares.count(i)) {
+ std::vector<uint32_t> values = sh.m_spawn_wares.at(i);
+ // Spawning
+ fw.Unsigned8(1);
+ fw.Unsigned32(values[0]);
+ fw.Unsigned32(values[1]);
+ fw.Unsigned32(values[2]);
+ if (values.size() > 3) {
+ fw.Unsigned8(1);
+ fw.Signed32(values[3]);
+ } else {
+ fw.Unsigned8(0);
+ }
+ } else {
+ fw.Unsigned8(0);
+ }
+ }
+ fw.Unsigned8(0);
+ // Worker supplies
+ const WareList & workers = ss->get_workers();
+ for (Ware_Index i = Ware_Index::First(); i < workers.get_nrwareids (); ++i) {
+ fw.Unsigned8(1);
+ fw.String(tribe.get_ware_descr(i)->name());
+ fw.Unsigned32(workers.stock(i));
+ fw.Unsigned8(static_cast<uint8_t>(sh.get_worker_policy(i)));
+ if (sh.m_spawn_workers.count(i)) {
+ std::vector<uint32_t> values = sh.m_spawn_workers.at(i);
+ // Spawning
+ fw.Unsigned8(1);
+ fw.Unsigned32(values[0]);
+ fw.Unsigned32(values[1]);
+ fw.Unsigned32(values[2]);
+ if (values.size() > 3) {
+ fw.Unsigned8(1);
+ fw.Signed32(values[3]);
+ } else {
+ fw.Unsigned8(0);
+ }
+ } else {
+ fw.Unsigned8(0);
+ }
+ }
+ fw.Unsigned8(0);
+ // Planned workers
+ fw.Unsigned32(sh.m_planned_workers.size());
+ container_iterate_const
+ (std::vector<StorageHandler::PlannedWorkers>,
+ sh.m_planned_workers, pw_it)
+ {
+ fw.CString(tribe.get_worker_descr(pw_it.current->index)->name());
+ fw.Unsigned32(pw_it.current->amount);
+
+ fw.Unsigned32(pw_it.current->requests.size());
+ container_iterate_const
+ (std::vector<Request *>, pw_it.current->requests, req_it)
+ (*req_it.current)->Write(fw, game, mos);
+ }
+ // Stocked atributes
+ fw.Unsigned32(sh.m_stocked_workers_atr.size());
+ container_iterate_const
+ (std::vector<StorageHandler::StockedWorkerAtr>,
+ sh.m_stocked_workers_atr, workers_atr_it)
+ {
+ StorageHandler::StockedWorkerAtr entry = *workers_atr_it.current;
+ fw.CString(tribe.get_worker_descr(entry.index)->name());
+ fw.Unsigned32(entry.atck_lvl);
+ fw.Unsigned32(entry.evade_lvl);
+ fw.Unsigned32(entry.defense_lvl);
+ fw.Unsigned32(entry.exp_or_hp_lvl);
+ }
+}
+
}
=== modified file 'src/map_io/widelands_map_buildingdata_data_packet.h'
--- src/map_io/widelands_map_buildingdata_data_packet.h 2013-07-26 20:19:36 +0000
+++ src/map_io/widelands_map_buildingdata_data_packet.h 2013-08-06 10:09:46 +0000
@@ -26,6 +26,12 @@
namespace Widelands {
+class Storage;
+
+class Garrison;
+
+class Garrison;
+
class ConstructionSite;
class Partially_Finished_Building;
class DismantleSite;
@@ -65,6 +71,10 @@
(ProductionSite &, FileRead &, Game &, Map_Map_Object_Loader &);
virtual void read_formerbuildings_v2
(Building &, FileRead &, Game &, Map_Map_Object_Loader &);
+ virtual void read_garrison
+ (Garrison &, FileRead &, Game &, Map_Map_Object_Loader &);
+ virtual void read_storage
+ (Storage &, FileRead &, Game &, Map_Map_Object_Loader &);
virtual void write_constructionsite
(const ConstructionSite &, FileWrite &, Game &, Map_Map_Object_Saver &);
@@ -80,6 +90,10 @@
(const TrainingSite &, FileWrite &, Game &, Map_Map_Object_Saver &);
virtual void write_productionsite
(const ProductionSite &, FileWrite &, Game &, Map_Map_Object_Saver &);
+ virtual void write_garrison
+ (const Garrison &, FileWrite &, Game &, Map_Map_Object_Saver &);
+ virtual void write_storage
+ (const Storage &, FileWrite &, Game &, Map_Map_Object_Saver &);
};
}
=== modified file 'src/scripting/lua_game.cc'
--- src/scripting/lua_game.cc 2013-07-26 20:19:36 +0000
+++ src/scripting/lua_game.cc 2013-08-06 10:09:46 +0000
@@ -30,6 +30,7 @@
#include "logic/path.h"
#include "logic/player.h"
#include "logic/tribe.h"
+#include <logic/storagehandler.h>
#include "scripting/c_utils.h"
#include "scripting/lua_map.h"
#include "scripting/scripting.h"
@@ -179,16 +180,16 @@
*/
int L_Player::get_defeated(lua_State * L) {
Player & p = get(L, get_egbase(L));
- bool have_warehouses = false;
+ bool have_storages = false;
for (uint32_t economy_nr = 0; economy_nr < p.get_nr_economies(); economy_nr++) {
- if (!p.get_economy_by_number(economy_nr)->warehouses().empty()) {
- have_warehouses = true;
+ if (!p.get_economy_by_number(economy_nr)->storages().empty()) {
+ have_storages = true;
break;
}
}
- lua_pushboolean(L, !have_warehouses);
+ lua_pushboolean(L, !have_storages);
return 1;
}
@@ -869,23 +870,14 @@
if (worker_descr.buildcost().empty()) {
// Workers of this type can be spawned in warehouses. Start it.
- uint8_t worker_types_without_cost_index = 0;
- for (;; ++worker_types_without_cost_index) {
- assert
- (worker_types_without_cost_index
- <
- worker_types_without_cost.size());
- if
- (worker_types_without_cost.at
- (worker_types_without_cost_index) == i)
- break;
- }
for (uint32_t j = player.get_nr_economies(); j;) {
Economy & economy = *player.get_economy_by_number(--j);
container_iterate_const
- (std::vector<Warehouse *>, economy.warehouses(), k)
- (*k.current)->enable_spawn
- (game, worker_types_without_cost_index);
+ (std::vector<Storage *>, economy.storages(), k) {
+ if (upcast(StorageHandler, sh, *k.current)) {
+ sh->add_worker_spawn(worker_descr.worker_index());
+ }
+ }
}
}
}
=== modified file 'src/scripting/lua_map.cc'
--- src/scripting/lua_map.cc 2013-07-26 20:19:36 +0000
+++ src/scripting/lua_map.cc 2013-08-06 10:09:46 +0000
@@ -34,6 +34,7 @@
#include "logic/soldier.h"
#include "logic/warelist.h"
#include "logic/widelands_geometry.h"
+#include "logic/storagehandler.h"
#include "scripting/c_utils.h"
#include "scripting/lua_game.h"
#include "wui/mapviewpixelfunctions.h"
@@ -245,12 +246,12 @@
* _SoldierEmployer
*/
int _SoldierEmployer::get_max_soldiers(lua_State * L) {
- lua_pushuint32(L, get_sc(L, get_egbase(L))->maxSoldierCapacity());
+ lua_pushuint32(L, get_garrison(L, get_egbase(L))->maxSoldierCapacity());
return 1;
}
int _SoldierEmployer::get_soldiers(lua_State * L) {
Editor_Game_Base & egbase = get_egbase(L);
- SoldierControl * sc = get_sc(L, egbase);
+ Garrison * sc = get_garrison(L, egbase);
const Tribe_Descr & tribe = get(L, egbase)->owner().tribe();
const Soldier_Descr & soldier_descr = // soldiers
@@ -266,7 +267,7 @@
}
int _SoldierEmployer::set_soldiers(lua_State * L) {
Editor_Game_Base & egbase = get_egbase(L);
- SoldierControl * sc = get_sc(L, egbase);
+ Garrison * garrison = get_garrison(L, egbase);
Building * building = get(L, egbase);
const Tribe_Descr & tribe = building->owner().tribe();
@@ -277,7 +278,7 @@
SoldiersMap setpoints = m_parse_set_soldiers_arguments(L, soldier_descr);
// Get information about current soldiers
- std::vector<Soldier *> curs = sc->stationedSoldiers();
+ std::vector<Soldier *> curs = garrison->stationedSoldiers();
SoldiersMap hist;
container_iterate (std::vector<Soldier * >, curs, s) {
SoldierDescr sd
@@ -305,7 +306,7 @@
int d = sp->second - cur;
if (d < 0) {
while (d) {
- std::vector<Soldier *> stationed_soldiers = sc->stationedSoldiers();
+ std::vector<Soldier *> stationed_soldiers = garrison->stationedSoldiers();
container_iterate_const(std::vector<Soldier *>, stationed_soldiers, s)
{
SoldierDescr is
@@ -315,7 +316,7 @@
(*s.current)->get_evade_level());
if (is == sp->first) {
- sc->outcorporateSoldier(egbase, **s);
+ garrison->outcorporateSoldier(egbase, **s);
(*s.current)->remove(egbase);
++d;
break;
@@ -333,7 +334,7 @@
(sp.current->first.hp, sp.current->first.at,
sp.current->first.de, sp.current->first.ev);
- if (sc->incorporateSoldier(egbase, soldier)) {
+ if (garrison->incorporateSoldier(egbase, soldier)) {
soldier.remove(egbase);
return report_error(L, "No space left for soldier!");
}
@@ -343,6 +344,174 @@
return 0;
}
+//TODO CGH implement
+int _StorageOwner::get_ware_policy(lua_State* L)
+{
+ return 0;
+}
+int _StorageOwner::get_worker_policy(lua_State* L)
+{
+ return 0;
+}
+int _StorageOwner::set_ware_policy(lua_State* L)
+{
+ return 0;
+}
+int _StorageOwner::set_worker_policy(lua_State* L)
+{
+ return 0;
+}
+
+int _StorageOwner::get_wares(lua_State* L)
+{
+ Storage * storage = get_storage(L, get_egbase(L));
+ const Tribe_Descr & tribe = storage->owner().tribe();
+
+ bool return_number = false;
+ WaresSet wares_set = m_parse_get_wares_arguments(L, tribe, &return_number);
+
+ if (not return_number)
+ lua_newtable(L);
+
+ container_iterate_const(WaresSet, wares_set, w) {
+ uint32_t count = storage->get_wares().stock(*w);
+ if (return_number) {
+ lua_pushuint32(L, count);
+ break;
+ } else {
+ lua_pushstring(L, tribe.get_ware_descr(*w)->name());
+ lua_pushuint32(L, count);
+ lua_rawset(L, -3);
+ }
+ }
+ return 1;
+}
+
+int _StorageOwner::set_wares(lua_State* L)
+{
+ Storage * storage = get_storage(L, get_egbase(L));
+ const Tribe_Descr & tribe = storage->owner().tribe();
+
+ WaresMap setpoints = m_parse_set_wares_arguments(L, tribe);
+
+ container_iterate_const(WaresMap, setpoints, i) {
+ storage->insert_wares(i->first, i->second);
+ }
+ return 0;
+}
+
+int _StorageOwner::get_workers(lua_State* L)
+{
+ Storage * storage = get_storage(L, get_egbase(L));
+ const Tribe_Descr & tribe = storage->owner().tribe();
+
+ bool return_number = false;
+ WorkersSet workers_set = m_parse_get_workers_arguments(L, tribe, &return_number);
+
+ if (not return_number)
+ lua_newtable(L);
+
+ container_iterate_const(WorkersSet, workers_set, w) {
+ uint32_t count = storage->get_workers().stock(*w);
+ if (return_number) {
+ lua_pushuint32(L, count);
+ break;
+ } else {
+ lua_pushstring(L, tribe.get_ware_descr(*w)->name());
+ lua_pushuint32(L, count);
+ lua_rawset(L, -3);
+ }
+ }
+ return 1;
+}
+int _StorageOwner::set_workers(lua_State* L)
+{
+ Storage * storage = get_storage(L, get_egbase(L));
+ const Tribe_Descr & tribe = storage->owner().tribe();
+
+ WorkersMap setpoints = m_parse_set_workers_arguments(L, tribe);
+
+ container_iterate_const(WorkersMap, setpoints, i) {
+ if (!storage->owner().is_worker_type_allowed(i->first)) {
+ continue;
+ }
+ storage->insert_workers(i->first, i->second);
+ }
+ return 0;
+}
+
+int _StorageOwner::get_soldiers(lua_State* L)
+{
+ Editor_Game_Base & egbase = get_egbase(L);
+ Storage * storage = get_storage(L, egbase);
+ const Tribe_Descr & tribe = storage->owner().tribe();
+
+ const Soldier_Descr & soldier_descr = // soldiers
+ ref_cast<Soldier_Descr const, Worker_Descr const>
+ (*tribe.get_worker_descr(tribe.worker_index("soldier")));
+
+ Game& game = ref_cast<Game, Editor_Game_Base>(egbase);
+ SoldiersList current_soldiers;
+ while (storage->can_create_worker(game, soldier_descr.worker_index())) {
+ Worker& w = storage->launch_worker(game, soldier_descr.worker_index());
+ upcast(Soldier, s, &w);
+ current_soldiers.push_back(s);
+ }
+ return m_handle_get_soldiers(L, soldier_descr, current_soldiers);
+}
+
+int _StorageOwner::set_soldiers(lua_State* L)
+{
+ Editor_Game_Base & egbase = get_egbase(L);
+ Storage * storage = get_storage(L, egbase);
+ const Tribe_Descr & tribe = storage->owner().tribe();
+
+ const Soldier_Descr & soldier_descr = // soldiers
+ ref_cast<Soldier_Descr const, Worker_Descr const>
+ (*tribe.get_worker_descr(tribe.worker_index("soldier")));
+
+ SoldiersMap setpoints = m_parse_set_soldiers_arguments(L, soldier_descr);
+
+ // Now add them
+ Game& game = ref_cast<Game, Editor_Game_Base>(egbase);
+ container_iterate_const(SoldiersMap, setpoints, sp) {
+ int d = sp->second;
+ if (d < 0) {
+ while (d) {
+ RequireAttribute hp_req(tAttribute::atrHP, sp->first.hp, sp->first.hp);
+ RequireAttribute at_req(tAttribute::atrAttack, sp->first.at, sp->first.at);
+ RequireAttribute de_req(tAttribute::atrDefense, sp->first.de, sp->first.de);
+ RequireAttribute ev_req(tAttribute::atrEvade, sp->first.ev, sp->first.ev);
+ RequireAnd req;
+ req.add(hp_req);
+ req.add(at_req);
+ req.add(de_req);
+ req.add(ev_req);
+ Worker& w = storage->launch_worker(game, soldier_descr.worker_index(), req);
+ w.remove(game);
+ ++d;
+ }
+ } else if (d > 0) {
+ upcast(StorageHandler, sh, storage);
+ for (; d; --d) {
+ Soldier & soldier =
+ ref_cast<Soldier, Worker>
+ (soldier_descr.create
+ (egbase, storage->owner(), 0,sh->get_building().get_position()));
+
+ soldier.set_level
+ (sp.current->first.hp, sp.current->first.at,
+ sp.current->first.de, sp.current->first.ev);
+ storage->incorporate_worker(game, soldier);
+ }
+ }
+ }
+ return 0;
+}
+
+
+
+
/*
@@ -774,6 +943,17 @@
}
return 1;
}
+/* RST
+HasStorage
+------------
+
+.. class:: HasStorage
+
+ Simple wrapper aroung :class: `HasWares` and `HasWorkers`. This interface also
+ contains methods to get and set the various ware policies.
+
+ Supported by :class: Warehouse
+*/
/* RST
Module Classes
@@ -1693,8 +1873,12 @@
METHOD(L_Warehouse, get_wares),
METHOD(L_Warehouse, set_workers),
METHOD(L_Warehouse, get_workers),
+ METHOD(L_Warehouse, get_soldiers),
METHOD(L_Warehouse, set_soldiers),
- METHOD(L_Warehouse, get_soldiers),
+ METHOD(L_Warehouse, set_ware_policy),
+ METHOD(L_Warehouse, get_ware_policy),
+ METHOD(L_Warehouse, get_worker_policy),
+ METHOD(L_Warehouse, get_worker_policy),
{0, 0},
};
const PropertyType<L_Warehouse> L_Warehouse::Properties[] = {
@@ -1729,9 +1913,10 @@
return 0; \
}
// documented in parent class
-WH_SET(ware, Ware);
+// WH_SET(ware, Ware);
// documented in parent class
-WH_SET(worker, Worker);
+// WH_SET(worker, Worker);
+// WH_SET(soldier, Soldier);
#undef WH_SET
#define WH_GET(type, btype) \
@@ -1755,9 +1940,10 @@
return 1; \
}
// documented in parent class
-WH_GET(ware, Ware);
+// WH_GET(ware, Ware);
// documented in parent class
-WH_GET(worker, Worker);
+// WH_GET(worker, Worker);
+// WH_GET(soldier, Soldier);
#undef GET
/*
@@ -1765,8 +1951,117 @@
C METHODS
==========================================================
*/
-
-
+/* FIXME CGH to move to headquarterrs
+int L_Warehouse::get_soldiers(lua_State * L) {
+ Editor_Game_Base & egbase = get_egbase(L);
+ Game & game = get_game(L);
+ const Tribe_Descr & tribe = get(L, egbase)->owner().tribe();
+ Warehouse* wh = get(L, egbase);
+ const WareList& wl = wh->get_workers();
+ Ware_Index ware_idx = tribe.safe_worker_index("soldier");
+ uint16_t amount = wl.stock(ware_idx);
+
+ const Soldier_Descr & soldier_descr = // soldiers
+ ref_cast<Soldier_Descr const, Worker_Descr const>
+ (*tribe.get_worker_descr(ware_idx));
+
+ std::vector<Soldier *> vec;
+ for (uint16_t i = 0 ; i < amount ; i++) {
+ Worker& w = wh->launch_worker(game, ware_idx, Requirements());
+ upcast(Soldier, s, &w);
+ vec.push_back(s);
+ }
+ SoldiersList current_soldiers;
+ return m_handle_get_soldiers(L, soldier_descr, vec);
+}
+
+int L_Warehouse::set_soldiers(lua_State * L) {
+ Editor_Game_Base & egbase = get_egbase(L);
+ Game & game = get_game(L);
+ Warehouse * wh = get(L, egbase);
+ const Tribe_Descr & tribe = wh->owner().tribe();
+
+ const Soldier_Descr & soldier_descr = // soldiers
+ ref_cast<Soldier_Descr const, Worker_Descr const>
+ (*tribe.get_worker_descr(tribe.worker_index("soldier")));
+
+ const WareList& wl = wh->get_workers();
+ Ware_Index ware_idx = tribe.safe_worker_index("soldier");
+ uint16_t amount = wl.stock(ware_idx);
+ SoldiersMap setpoints = m_parse_set_soldiers_arguments(L, soldier_descr);
+
+ std::vector<Soldier *> vec;
+ for (uint16_t i = 0 ; i < amount ; i++) {
+ Worker& w = wh->launch_worker(game, ware_idx, Requirements());
+ upcast(Soldier, s, &w);
+ vec.push_back(s);
+ }
+
+ // Get information about current soldiers
+ std::vector<Soldier *> curs = vec;
+ SoldiersMap hist;
+ container_iterate (std::vector<Soldier * >, curs, s) {
+ SoldierDescr sd
+ ((*s.current)->get_hp_level(),
+ (*s.current)->get_attack_level(),
+ (*s.current)->get_defense_level(),
+ (*s.current)->get_evade_level());
+
+ SoldiersMap::iterator i = hist.find(sd);
+ if (i == hist.end())
+ hist[sd] = 1;
+ else
+ i->second += 1;
+ if (not setpoints.count(sd))
+ setpoints[sd] = 0;
+ }
+
+ // Now adjust them
+ container_iterate_const(SoldiersMap, setpoints, sp) {
+ uint32_t cur = 0;
+ SoldiersMap::iterator i = hist.find(sp->first);
+ if (i != hist.end())
+ cur = i->second;
+
+ int d = sp->second - cur;
+ if (d < 0) {
+ while (d) {
+ std::vector<Soldier *> stationed_soldiers = vec;
+ container_iterate_const(std::vector<Soldier *>, stationed_soldiers, s)
+ {
+ SoldierDescr is
+ ((*s.current)->get_hp_level(),
+ (*s.current)->get_attack_level(),
+ (*s.current)->get_defense_level(),
+ (*s.current)->get_evade_level());
+
+ if (is == sp->first) {
+ Soldier* sol = *s.current;
+ sol->start_task_leavebuilding(game, true);
+ (*s.current)->remove(egbase);
+ ++d;
+ break;
+ }
+ }
+ }
+ } else if (d > 0) {
+ for (; d; --d) {
+ Soldier & soldier =
+ ref_cast<Soldier, Worker>
+ (soldier_descr.create
+ (egbase, wh->owner(), 0, wh->get_position()));
+
+ soldier.set_level
+ (sp.current->first.hp, sp.current->first.at,
+ sp.current->first.de, sp.current->first.ev);
+
+ wh->incorporate_worker(egbase, soldier);
+ }
+ }
+ }
+ return 0;
+}
+*/
/* RST
ProductionSite
--------------
=== modified file 'src/scripting/lua_map.h'
--- src/scripting/lua_map.h 2013-07-26 20:19:36 +0000
+++ src/scripting/lua_map.h 2013-08-06 10:09:46 +0000
@@ -31,6 +31,7 @@
#include "logic/militarysite.h"
#include "logic/productionsite.h"
#include "logic/soldier.h"
+#include "logic/storage.h"
#include "logic/trainingsite.h"
#include "logic/warehouse.h"
#include "logic/worker.h"
@@ -251,6 +252,15 @@
(lua_State *, const Widelands::Tribe_Descr &);
};
+struct L_HasStorage: public L_HasWares, L_HasWorkers {
+ virtual ~L_HasStorage() {}
+
+ virtual int get_ware_policy(lua_State * L) = 0;
+ virtual int get_worker_policy(lua_State * L) = 0;
+ virtual int set_ware_policy(lua_State * L) = 0;
+ virtual int set_worker_policy(lua_State * L) = 0;
+};
+
struct L_HasSoldiers {
struct SoldierDescr {
SoldierDescr(uint8_t ghp, uint8_t gat, uint8_t gde, uint8_t gev) :
@@ -351,7 +361,23 @@
virtual Widelands::Building * get
(lua_State *, Widelands::Editor_Game_Base &) = 0;
- virtual Widelands::SoldierControl * get_sc
+ virtual Widelands::Garrison * get_garrison
+ (lua_State *, Widelands::Editor_Game_Base &) = 0;
+};
+
+struct _StorageOwner : public L_HasStorage, L_HasSoldiers {
+ virtual int set_wares(lua_State * L);
+ virtual int get_wares(lua_State * L);
+ virtual int set_workers(lua_State * L);
+ virtual int get_workers(lua_State * L);
+ virtual int get_ware_policy(lua_State * L);
+ virtual int get_worker_policy(lua_State * L);
+ virtual int set_ware_policy(lua_State * L);
+ virtual int set_worker_policy(lua_State * L);
+ virtual int get_soldiers(lua_State * L);
+ virtual int set_soldiers(lua_State * L);
+
+ virtual Widelands::Storage * get_storage
(lua_State *, Widelands::Editor_Game_Base &) = 0;
};
@@ -416,8 +442,7 @@
};
-class L_Warehouse : public L_Building,
- public L_HasWares, public L_HasWorkers, public _SoldierEmployer
+class L_Warehouse : public L_Building, public _StorageOwner
{
public:
LUNA_CLASS_HEAD(L_Warehouse);
@@ -435,19 +460,21 @@
/*
* Lua Methods
*/
- int set_wares(lua_State *);
- int get_wares(lua_State *);
- int set_workers(lua_State *);
- int get_workers(lua_State *);
/*
* C Methods
*/
CASTED_GET(Warehouse);
- Widelands::SoldierControl * get_sc
+ // FIXME CGH to be put in headquarters
+// Widelands::Garrison * get_sc
+// (lua_State * L, Widelands::Editor_Game_Base & g)
+// {
+// return get(L, g);
+// }
+ virtual Widelands::Storage * get_storage
(lua_State * L, Widelands::Editor_Game_Base & g)
{
- return get(L, g);
+ return get(L, g)->get_storage();
}
};
@@ -508,10 +535,10 @@
* C Methods
*/
CASTED_GET(MilitarySite);
- Widelands::SoldierControl * get_sc
+ Widelands::Garrison * get_garrison
(lua_State * L, Widelands::Editor_Game_Base & g)
{
- return get(L, g);
+ return get(L, g)->get_garrison();
}
};
@@ -538,8 +565,10 @@
* C Methods
*/
CASTED_GET(TrainingSite);
- Widelands::SoldierControl * get_sc
- (lua_State * L, Widelands::Editor_Game_Base & g) {return get(L, g);}
+ Widelands::Garrison * get_garrison
+ (lua_State * L, Widelands::Editor_Game_Base & g) {
+ return get(L, g)->get_garrison();
+ }
};
class L_Bob : public L_MapObject {
=== modified file 'src/wlapplication.cc'
=== modified file 'src/wui/attack_box.h'
--- src/wui/attack_box.h 2013-07-26 19:16:51 +0000
+++ src/wui/attack_box.h 2013-08-06 10:09:46 +0000
@@ -22,7 +22,6 @@
#include <list>
-#include "logic/attackable.h"
#include "logic/bob.h"
#include "logic/player.h"
#include "logic/soldier.h"
=== modified file 'src/wui/buildingwindow.cc'
--- src/wui/buildingwindow.cc 2013-08-05 05:20:07 +0000
+++ src/wui/buildingwindow.cc 2013-08-06 10:09:46 +0000
@@ -427,7 +427,7 @@
{
if (is_a(Widelands::MilitarySite, &m_building))
igbase().game().send_player_militarysite_set_soldier_preference
- (m_building, Widelands::MilitarySite::kPrefersRookies);
+ (m_building, Widelands::Garrison::SoldierPref::Rookies);
die();
}
@@ -437,7 +437,7 @@
{
if (is_a(Widelands::MilitarySite, &m_building))
igbase().game().send_player_militarysite_set_soldier_preference
- (m_building, Widelands::MilitarySite::kPrefersHeroes);
+ (m_building, Widelands::Garrison::SoldierPref::Heroes);
die();
}
=== modified file 'src/wui/fieldaction.cc'
--- src/wui/fieldaction.cc 2013-08-02 18:36:03 +0000
+++ src/wui/fieldaction.cc 2013-08-06 10:09:46 +0000
@@ -24,7 +24,6 @@
#include "economy/road.h"
#include "graphic/graphic.h"
#include "i18n.h"
-#include "logic/attackable.h"
#include "logic/cmd_queue.h"
#include "logic/maphollowregion.h"
#include "logic/militarysite.h"
@@ -480,11 +479,11 @@
if
(upcast
- (Widelands::Attackable, attackable, m_map->get_immovable(m_node)))
+ (Widelands::GarrisonOwner, go, m_map->get_immovable(m_node)))
{
if
- (m_plr && m_plr->is_hostile(attackable->owner()) &&
- attackable->canAttack())
+ (go->get_garrison()->canAttack() && m_plr
+ && m_plr->is_hostile(go->get_garrison()->owner()))
{
m_attack_box = new AttackBox(&a_box, m_plr, &m_node, 0, 0);
a_box.add(m_attack_box, UI::Box::AlignTop);
=== modified file 'src/wui/military_box.h'
--- src/wui/military_box.h 2013-07-26 19:16:51 +0000
+++ src/wui/military_box.h 2013-08-06 10:09:46 +0000
@@ -22,7 +22,6 @@
#include <list>
-#include "logic/attackable.h"
#include "logic/player.h"
#include "ui_basic/box.h"
#include "ui_basic/button.h"
=== modified file 'src/wui/soldiercapacitycontrol.cc'
--- src/wui/soldiercapacitycontrol.cc 2013-07-27 10:35:55 +0000
+++ src/wui/soldiercapacitycontrol.cc 2013-08-06 10:09:46 +0000
@@ -21,12 +21,11 @@
#include "graphic/graphic.h"
#include "logic/player.h"
-#include "logic/soldiercontrol.h"
#include "ui_basic/button.h"
#include "ui_basic/radiobutton.h"
#include "wui/interactive_gamebase.h"
-using Widelands::SoldierControl;
+using Widelands::Garrison;
/**
* Widget to control the capacity of \ref MilitaryBuilding and \ref TrainingSite
@@ -86,16 +85,16 @@
void SoldierCapacityControl::think()
{
- SoldierControl * soldiers = dynamic_cast<SoldierControl *>(&m_building);
- uint32_t const capacity = soldiers->soldierCapacity();
+ Garrison * garrison = dynamic_cast<Widelands::GarrisonOwner *>(&m_building)->get_garrison();
+ uint32_t const capacity = garrison->soldierCapacity();
char buffer[sizeof("4294967295")];
sprintf(buffer, "%2u", capacity);
m_value.set_text(buffer);
bool const can_act = m_igb.can_act(m_building.owner().player_number());
- m_decrease.set_enabled(can_act && soldiers->minSoldierCapacity() < capacity);
- m_increase.set_enabled(can_act && soldiers->maxSoldierCapacity() > capacity);
+ m_decrease.set_enabled(can_act && garrison->minSoldierCapacity() < capacity);
+ m_increase.set_enabled(can_act && garrison->maxSoldierCapacity() > capacity);
}
void SoldierCapacityControl::change_soldier_capacity(int delta)
=== modified file 'src/wui/soldierlist.cc'
--- src/wui/soldierlist.cc 2013-07-27 10:35:55 +0000
+++ src/wui/soldierlist.cc 2013-08-06 10:09:46 +0000
@@ -26,10 +26,10 @@
#include "graphic/graphic.h"
#include "graphic/rendertarget.h"
#include "logic/building.h"
+#include "logic/garrison.h"
#include "logic/militarysite.h"
#include "logic/player.h"
#include "logic/soldier.h"
-#include "logic/soldiercontrol.h"
#include "ui_basic/box.h"
#include "ui_basic/button.h"
#include "ui_basic/table.h"
@@ -39,7 +39,7 @@
#include "wui/soldiercapacitycontrol.h"
using Widelands::Soldier;
-using Widelands::SoldierControl;
+using Widelands::Garrison;
/**
* Iconic representation of soldiers, including their levels and current HP.
@@ -83,7 +83,7 @@
};
Widelands::Editor_Game_Base & m_egbase;
- SoldierControl & m_soldiers;
+ Widelands::Garrison & m_garrison;
SoldierFn m_mouseover_fn;
SoldierFn m_click_fn;
@@ -110,14 +110,14 @@
:
Panel(&parent, 0, 0, 0, 0),
m_egbase(gegbase),
-m_soldiers(*dynamic_cast<SoldierControl *>(&building)),
+m_garrison(*dynamic_cast<Widelands::GarrisonOwner *>(&building)->get_garrison()),
m_last_animate_time(0)
{
Soldier::calc_info_icon_size(building.tribe(), m_icon_width, m_icon_height);
m_icon_width += 2 * IconBorder;
m_icon_height += 2 * IconBorder;
- uint32_t maxcapacity = m_soldiers.maxSoldierCapacity();
+ uint32_t maxcapacity = m_garrison.maxSoldierCapacity();
if (maxcapacity <= MaxColumns) {
m_cols = maxcapacity;
m_rows = 1;
@@ -131,7 +131,7 @@
set_think(true);
// Initialize the icons
- std::vector<Soldier *> soldierlist = m_soldiers.presentSoldiers();
+ std::vector<Soldier *> soldierlist = m_garrison.presentSoldiers();
uint32_t row = 0;
uint32_t col = 0;
container_iterate_const(std::vector<Soldier *>, soldierlist, sit) {
@@ -168,10 +168,10 @@
void SoldierPanel::think()
{
bool changes = false;
- uint32_t capacity = m_soldiers.soldierCapacity();
+ uint32_t capacity = m_garrison.soldierCapacity();
// Update soldier list and target row/col:
- std::vector<Soldier *> soldierlist = m_soldiers.presentSoldiers();
+ std::vector<Soldier *> soldierlist = m_garrison.presentSoldiers();
std::vector<uint32_t> row_occupancy;
row_occupancy.resize(m_rows);
@@ -277,7 +277,7 @@
void SoldierPanel::draw(RenderTarget & dst)
{
// Fill a region matching the current site capacity with black
- uint32_t capacity = m_soldiers.soldierCapacity();
+ uint32_t capacity = m_garrison.soldierCapacity();
uint32_t fullrows = capacity / MaxColumns;
if (fullrows)
@@ -362,7 +362,7 @@
Interactive_GameBase & igb,
Widelands::Building & building);
- SoldierControl & soldiers() const;
+ Garrison & garrison() const;
private:
void mouseover(const Soldier * soldier);
@@ -418,7 +418,7 @@
}
m_soldier_preference.set_state(0);
- if (ms->get_soldier_preference() == Widelands::MilitarySite::kPrefersHeroes) {
+ if (garrison().get_soldier_preference() == Garrison::SoldierPref::Heroes) {
m_soldier_preference.set_state(1);
}
m_soldier_preference.changedto.connect
@@ -432,9 +432,9 @@
add(buttons, UI::Box::AlignCenter, true);
}
-SoldierControl & SoldierList::soldiers() const
+Garrison & SoldierList::garrison() const
{
- return *dynamic_cast<SoldierControl *>(&m_building);
+ return *dynamic_cast<Widelands::GarrisonOwner *>(&m_building)->get_garrison();
}
void SoldierList::mouseover(const Soldier * soldier)
@@ -463,9 +463,9 @@
void SoldierList::eject(const Soldier * soldier)
{
- uint32_t const capacity_min = soldiers().minSoldierCapacity();
+ uint32_t const capacity_min = garrison().minSoldierCapacity();
bool can_act = m_igb.can_act(m_building.owner().player_number());
- bool over_min = capacity_min < soldiers().presentSoldiers().size();
+ bool over_min = capacity_min < garrison().presentSoldiers().size();
if (can_act && over_min)
m_igb.game().send_player_drop_soldier(m_building, soldier->serial());
@@ -474,8 +474,8 @@
void SoldierList::set_soldier_preference(int32_t changed_to) {
upcast(Widelands::MilitarySite, ms, &m_building);
assert(ms);
- ms->set_soldier_preference
- (changed_to == 0 ? Widelands::MilitarySite::kPrefersRookies : Widelands::MilitarySite::kPrefersHeroes);
+ garrison().set_soldier_preference
+ (changed_to == 0 ? Garrison::SoldierPref::Rookies : Garrison::SoldierPref::Heroes);
}
UI::Panel * create_soldier_list
=== modified file 'src/wui/stock_menu.cc'
--- src/wui/stock_menu.cc 2013-07-26 20:19:36 +0000
+++ src/wui/stock_menu.cc 2013-08-06 10:09:46 +0000
@@ -34,15 +34,11 @@
static const char pic_tab_workers_warehouse[] =
"pics/menu_tab_workers_warehouse.png";
-Stock_Menu::Stock_Menu
- (Interactive_Player & plr, UI::UniqueWindow::Registry & registry)
-:
-UI::UniqueWindow(&plr, "stock_menu", ®istry, 480, 640, _("Stock")),
-m_player(plr)
+Stock_Menu::Stock_Menu (Interactive_Player & plr, UI::UniqueWindow::Registry & registry)
+: UI::UniqueWindow(&plr, "stock_menu", ®istry, 480, 640, _("Stock")),
+ m_player(plr)
{
- UI::Tab_Panel * tabs =
- new UI::Tab_Panel
- (this, 0, 0, g_gr->images().get("pics/but1.png"));
+ UI::Tab_Panel * tabs = new UI::Tab_Panel(this, 0, 0, g_gr->images().get("pics/but1.png"));
set_center_panel(tabs);
m_all_wares = new WaresDisplay(tabs, 0, 0, plr.player().tribe(), Widelands::wwWARE, false);
@@ -95,11 +91,12 @@
waresdisplay->remove_all_warelists();
const Widelands::Player & player = *m_player.get_player();
const uint32_t nrecos = player.get_nr_economies();
- for (uint32_t i = 0; i < nrecos; ++i)
+ for (uint32_t i = 0; i < nrecos; ++i) {
waresdisplay->add_warelist
(type == Widelands::wwWARE ?
player.get_economy_by_number(i)->get_wares() :
player.get_economy_by_number(i)->get_workers());
+ }
}
/**
@@ -113,13 +110,13 @@
const Widelands::Player & player = *m_player.get_player();
const uint32_t nrecos = player.get_nr_economies();
for (uint32_t i = 0; i < nrecos; ++i) {
- const std::vector<Widelands::Warehouse *> & warehouses =
- player.get_economy_by_number(i)->warehouses();
+ const std::vector<Widelands::Storage *> & storages =
+ player.get_economy_by_number(i)->storages();
for
- (std::vector<Widelands::Warehouse *>::const_iterator it =
- warehouses.begin();
- it != warehouses.end();
+ (std::vector<Widelands::Storage *>::const_iterator it =
+ storages.begin();
+ it != storages.end();
++it)
{
waresdisplay->add_warelist
=== modified file 'src/wui/trainingsitewindow.cc'
--- src/wui/trainingsitewindow.cc 2013-07-26 20:19:36 +0000
+++ src/wui/trainingsitewindow.cc 2013-08-06 10:09:46 +0000
@@ -36,10 +36,6 @@
TrainingSite_Window
(Interactive_GameBase & parent, TrainingSite &, UI::Window * & registry);
- TrainingSite & trainingsite() {
- return ref_cast<TrainingSite, Widelands::Building>(building());
- }
-
protected:
virtual void create_capsbuttons(UI::Box * buttons);
};
@@ -54,7 +50,7 @@
{
get_tabs()->add
("soldiers", g_gr->images().get(pic_tab_military),
- create_soldier_list(*get_tabs(), parent, trainingsite()),
+ create_soldier_list(*get_tabs(), parent, ts),
_("Soldiers in training"));
}
=== modified file 'src/wui/warehousewindow.cc'
--- src/wui/warehousewindow.cc 2013-08-02 14:20:21 +0000
+++ src/wui/warehousewindow.cc 2013-08-06 10:09:46 +0000
@@ -21,6 +21,7 @@
#include "graphic/rendertarget.h"
#include "logic/player.h"
#include "logic/playercommand.h"
+#include "logic/storage.h"
#include "logic/warehouse.h"
#include "ui_basic/tabpanel.h"
#include "wui/buildingwindow.h"
@@ -63,20 +64,28 @@
m_warehouse(wh)
{
set_inner_size(width, 0);
- add_warelist(type == Widelands::wwWORKER ? m_warehouse.get_workers() : m_warehouse.get_wares());
+ add_warelist(type == Widelands::wwWORKER ?
+ m_warehouse.get_storage()->get_workers()
+ : m_warehouse.get_storage()->get_wares());
}
void WarehouseWaresDisplay::draw_ware(RenderTarget & dst, Widelands::Ware_Index ware)
{
WaresDisplay::draw_ware(dst, ware);
- Warehouse::StockPolicy policy = m_warehouse.get_stock_policy(get_type(), ware);
+ Widelands::Storage::StockPolicy policy = m_warehouse.get_storage()->get_stock_policy(get_type(), ware);
const Image* pic;
switch (policy) {
- case Warehouse::SP_Prefer: pic = g_gr->images().get(pic_policy_prefer); break;
- case Warehouse::SP_DontStock: pic = g_gr->images().get(pic_policy_dontstock); break;
- case Warehouse::SP_Remove: pic = g_gr->images().get(pic_policy_remove); break;
+ case Widelands::Storage::StockPolicy::Prefer:
+ pic = g_gr->images().get(pic_policy_prefer);
+ break;
+ case Widelands::Storage::StockPolicy::DontStock:
+ pic = g_gr->images().get(pic_policy_dontstock);
+ break;
+ case Widelands::Storage::StockPolicy::Remove:
+ pic = g_gr->images().get(pic_policy_remove);
+ break;
default:
// don't draw anything for the normal policy
return;
@@ -93,7 +102,7 @@
(UI::Panel * parent, uint32_t width,
Interactive_GameBase &, Warehouse &, Widelands::WareWorker type);
- void set_policy(Warehouse::StockPolicy);
+ void set_policy(Widelands::Storage::StockPolicy);
private:
Interactive_GameBase & m_gb;
Warehouse & m_wh;
@@ -127,7 +136,7 @@
g_gr->images().get("pics/stock_policy_button_" #policy ".png"), \
tooltip), \
b->sigclicked.connect \
- (boost::bind(&WarehouseWaresPanel::set_policy, this, Warehouse::SP_##policyname)), \
+ (boost::bind(&WarehouseWaresPanel::set_policy, this,Widelands::Storage::StockPolicy::policyname)), \
buttons->add(b, UI::Box::AlignCenter);
ADD_POLICY_BUTTON(normal, Normal, _("Normal policy"))
@@ -140,7 +149,7 @@
/**
* Add Buttons policy buttons
*/
-void WarehouseWaresPanel::set_policy(Warehouse::StockPolicy newpolicy) {
+void WarehouseWaresPanel::set_policy(Widelands::Storage::StockPolicy newpolicy) {
bool is_workers = m_type == Widelands::wwWORKER;
Widelands::Ware_Index nritems =
is_workers ? m_wh.owner().tribe().get_nrworkers() :
Follow ups