|
|
|
@ -10,6 +10,7 @@
|
|
|
|
|
#include "modules/Screen.h"
|
|
|
|
|
#include "modules/Units.h"
|
|
|
|
|
#include "modules/Items.h"
|
|
|
|
|
#include "modules/Job.h"
|
|
|
|
|
|
|
|
|
|
#include "MiscUtils.h"
|
|
|
|
|
|
|
|
|
@ -58,7 +59,12 @@
|
|
|
|
|
#include "df/item_flaskst.h"
|
|
|
|
|
#include "df/item_backpackst.h"
|
|
|
|
|
#include "df/item_quiverst.h"
|
|
|
|
|
#include "df/building_weaponrackst.h"
|
|
|
|
|
#include "df/building_armorstandst.h"
|
|
|
|
|
#include "df/building_cabinetst.h"
|
|
|
|
|
#include "df/building_boxst.h"
|
|
|
|
|
#include "df/job.h"
|
|
|
|
|
#include "df/general_ref_building_holderst.h"
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
|
@ -139,6 +145,8 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector <Plugi
|
|
|
|
|
" tweak armory [disable]\n"
|
|
|
|
|
" Prevents squad equipment stored on armor stands and weapon racks from\n"
|
|
|
|
|
" being carried off to ordinary stockpiles.\n"
|
|
|
|
|
" tweak stock-armory [disable]\n"
|
|
|
|
|
" Makes dwarves actively haul assigned equipment to the armory.\n"
|
|
|
|
|
));
|
|
|
|
|
return CR_OK;
|
|
|
|
|
}
|
|
|
|
@ -673,7 +681,7 @@ struct military_assign_hook : df::viewscreen_layer_militaryst {
|
|
|
|
|
IMPLEMENT_VMETHOD_INTERPOSE(military_assign_hook, feed);
|
|
|
|
|
IMPLEMENT_VMETHOD_INTERPOSE(military_assign_hook, render);
|
|
|
|
|
|
|
|
|
|
static bool belongs_to_position(df::item *item, df::building *holder, bool any_position)
|
|
|
|
|
static bool belongs_to_position(df::item *item, df::building *holder)
|
|
|
|
|
{
|
|
|
|
|
int sid = holder->getSpecificSquad();
|
|
|
|
|
if (sid < 0)
|
|
|
|
@ -683,7 +691,9 @@ static bool belongs_to_position(df::item *item, df::building *holder, bool any_p
|
|
|
|
|
if (!squad)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (any_position)
|
|
|
|
|
int position = holder->getSpecificPosition();
|
|
|
|
|
|
|
|
|
|
if (position == -1 && holder->getType() == building_type::Weaponrack)
|
|
|
|
|
{
|
|
|
|
|
for (size_t i = 0; i < squad->positions.size(); i++)
|
|
|
|
|
{
|
|
|
|
@ -693,7 +703,7 @@ static bool belongs_to_position(df::item *item, df::building *holder, bool any_p
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
auto cpos = vector_get(squad->positions, holder->getSpecificPosition());
|
|
|
|
|
auto cpos = vector_get(squad->positions, position);
|
|
|
|
|
if (cpos && binsearch_index(cpos->assigned_items, item->id) >= 0)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
@ -701,7 +711,7 @@ static bool belongs_to_position(df::item *item, df::building *holder, bool any_p
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool is_in_armory(df::item *item, bool any_position)
|
|
|
|
|
static bool is_in_armory(df::item *item)
|
|
|
|
|
{
|
|
|
|
|
if (item->flags.bits.in_inventory || item->flags.bits.on_ground)
|
|
|
|
|
return false;
|
|
|
|
@ -714,35 +724,22 @@ static bool is_in_armory(df::item *item, bool any_position)
|
|
|
|
|
if (!holder)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return belongs_to_position(item, holder, any_position);
|
|
|
|
|
return belongs_to_position(item, holder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct armory_weapon_hook : df::item_weaponst {
|
|
|
|
|
typedef df::item_weaponst interpose_base;
|
|
|
|
|
|
|
|
|
|
DEFINE_VMETHOD_INTERPOSE(bool, isCollected, ())
|
|
|
|
|
{
|
|
|
|
|
if (is_in_armory(this, true))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return INTERPOSE_NEXT(isCollected)();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
IMPLEMENT_VMETHOD_INTERPOSE(armory_weapon_hook, isCollected);
|
|
|
|
|
|
|
|
|
|
template<class Item> struct armory_hook : Item {
|
|
|
|
|
typedef Item interpose_base;
|
|
|
|
|
|
|
|
|
|
DEFINE_VMETHOD_INTERPOSE(bool, isCollected, ())
|
|
|
|
|
{
|
|
|
|
|
if (is_in_armory(this, false))
|
|
|
|
|
if (is_in_armory(this))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return INTERPOSE_NEXT(isCollected)();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook<df::item_weaponst>, isCollected);
|
|
|
|
|
template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook<df::item_armorst>, isCollected);
|
|
|
|
|
template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook<df::item_helmst>, isCollected);
|
|
|
|
|
template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook<df::item_shoesst>, isCollected);
|
|
|
|
@ -753,6 +750,112 @@ template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook<df::item_flaskst>, isCollecte
|
|
|
|
|
template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook<df::item_backpackst>, isCollected);
|
|
|
|
|
template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook<df::item_quiverst>, isCollected);
|
|
|
|
|
|
|
|
|
|
static void check_stock_armory(df::building *target, int squad_idx)
|
|
|
|
|
{
|
|
|
|
|
auto squad = df::squad::find(squad_idx);
|
|
|
|
|
if (!squad)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
int position = target->getSpecificPosition();
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < squad->positions.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
if (position >= 0 && position != int(i))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
auto pos = squad->positions[i];
|
|
|
|
|
|
|
|
|
|
for (size_t j = 0; j < pos->assigned_items.size(); j++)
|
|
|
|
|
{
|
|
|
|
|
auto item = df::item::find(pos->assigned_items[j]);
|
|
|
|
|
if (!item || item->stockpile_countdown > 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (item->flags.bits.in_job ||
|
|
|
|
|
item->flags.bits.removed ||
|
|
|
|
|
item->flags.bits.in_building ||
|
|
|
|
|
item->flags.bits.encased ||
|
|
|
|
|
item->flags.bits.owned ||
|
|
|
|
|
item->flags.bits.forbid ||
|
|
|
|
|
item->flags.bits.on_fire)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
auto top = item;
|
|
|
|
|
|
|
|
|
|
while (top->flags.bits.in_inventory)
|
|
|
|
|
{
|
|
|
|
|
auto parent = Items::getContainer(top);
|
|
|
|
|
if (!parent) break;
|
|
|
|
|
top = parent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Items::getGeneralRef(top, general_ref_type::UNIT_HOLDER))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (is_in_armory(item))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (!target->canStoreItem(item, true))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
auto href = df::allocate<df::general_ref_building_holderst>();
|
|
|
|
|
if (!href)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
auto job = new df::job();
|
|
|
|
|
|
|
|
|
|
job->pos = df::coord(target->centerx, target->centery, target->z);
|
|
|
|
|
|
|
|
|
|
switch (target->getType()) {
|
|
|
|
|
case building_type::Weaponrack:
|
|
|
|
|
job->job_type = job_type::StoreWeapon;
|
|
|
|
|
job->flags.bits.specific_dropoff = true;
|
|
|
|
|
break;
|
|
|
|
|
case building_type::Armorstand:
|
|
|
|
|
job->job_type = job_type::StoreArmor;
|
|
|
|
|
job->flags.bits.specific_dropoff = true;
|
|
|
|
|
break;
|
|
|
|
|
case building_type::Cabinet:
|
|
|
|
|
job->job_type = job_type::StoreItemInCabinet;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
job->job_type = job_type::StoreItemInChest;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Job::attachJobItem(job, item, df::job_item_ref::Hauled))
|
|
|
|
|
{
|
|
|
|
|
delete job;
|
|
|
|
|
delete href;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
href->building_id = target->id;
|
|
|
|
|
target->jobs.push_back(job);
|
|
|
|
|
job->references.push_back(href);
|
|
|
|
|
|
|
|
|
|
Job::linkIntoWorld(job);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class Building> struct stock_armory_hook : Building {
|
|
|
|
|
typedef Building interpose_base;
|
|
|
|
|
|
|
|
|
|
DEFINE_VMETHOD_INTERPOSE(void, updateAction, ())
|
|
|
|
|
{
|
|
|
|
|
if (this->specific_squad >= 0 && DF_GLOBAL_VALUE(cur_year_tick,0) % 50 == 0)
|
|
|
|
|
check_stock_armory(this, this->specific_squad);
|
|
|
|
|
|
|
|
|
|
INTERPOSE_NEXT(updateAction)();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<> IMPLEMENT_VMETHOD_INTERPOSE(stock_armory_hook<df::building_weaponrackst>, updateAction);
|
|
|
|
|
template<> IMPLEMENT_VMETHOD_INTERPOSE(stock_armory_hook<df::building_armorstandst>, updateAction);
|
|
|
|
|
template<> IMPLEMENT_VMETHOD_INTERPOSE(stock_armory_hook<df::building_cabinetst>, updateAction);
|
|
|
|
|
template<> IMPLEMENT_VMETHOD_INTERPOSE(stock_armory_hook<df::building_boxst>, updateAction);
|
|
|
|
|
|
|
|
|
|
static void enable_hook(color_ostream &out, VMethodInterposeLinkBase &hook, vector <string> ¶meters)
|
|
|
|
|
{
|
|
|
|
|
if (vector_get(parameters, 1) == "disable")
|
|
|
|
@ -928,7 +1031,7 @@ static command_result tweak(color_ostream &out, vector <string> ¶meters)
|
|
|
|
|
}
|
|
|
|
|
else if (cmd == "armory")
|
|
|
|
|
{
|
|
|
|
|
enable_hook(out, INTERPOSE_HOOK(armory_weapon_hook, isCollected), parameters);
|
|
|
|
|
enable_hook(out, INTERPOSE_HOOK(armory_hook<df::item_weaponst>, isCollected), parameters);
|
|
|
|
|
enable_hook(out, INTERPOSE_HOOK(armory_hook<df::item_armorst>, isCollected), parameters);
|
|
|
|
|
enable_hook(out, INTERPOSE_HOOK(armory_hook<df::item_helmst>, isCollected), parameters);
|
|
|
|
|
enable_hook(out, INTERPOSE_HOOK(armory_hook<df::item_pantsst>, isCollected), parameters);
|
|
|
|
@ -939,6 +1042,13 @@ static command_result tweak(color_ostream &out, vector <string> ¶meters)
|
|
|
|
|
enable_hook(out, INTERPOSE_HOOK(armory_hook<df::item_backpackst>, isCollected), parameters);
|
|
|
|
|
enable_hook(out, INTERPOSE_HOOK(armory_hook<df::item_quiverst>, isCollected), parameters);
|
|
|
|
|
}
|
|
|
|
|
else if (cmd == "stock-armory")
|
|
|
|
|
{
|
|
|
|
|
enable_hook(out, INTERPOSE_HOOK(stock_armory_hook<df::building_armorstandst>, updateAction), parameters);
|
|
|
|
|
enable_hook(out, INTERPOSE_HOOK(stock_armory_hook<df::building_weaponrackst>, updateAction), parameters);
|
|
|
|
|
enable_hook(out, INTERPOSE_HOOK(stock_armory_hook<df::building_boxst>, updateAction), parameters);
|
|
|
|
|
enable_hook(out, INTERPOSE_HOOK(stock_armory_hook<df::building_cabinetst>, updateAction), parameters);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return CR_WRONG_USAGE;
|
|
|
|
|
|
|
|
|
|