|  |  |  | @ -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; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | 
 |