From 329741f23582f8123bd5236acc1d01dcca0a25aa Mon Sep 17 00:00:00 2001 From: expwnent Date: Thu, 24 Oct 2013 19:32:52 -0400 Subject: [PATCH] EventManager: added EQUIPMENT_CHANGE event and exposed it to lua. --- Lua API.rst | 4 ++ NEWS | 2 +- library/include/modules/EventManager.h | 19 ++++-- library/modules/EventManager.cpp | 86 ++++++++++++++++++-------- plugins/eventful.cpp | 22 +++++++ plugins/lua/eventful.lua | 2 +- 6 files changed, 103 insertions(+), 32 deletions(-) diff --git a/Lua API.rst b/Lua API.rst index 54b25fe06..480ff141a 100644 --- a/Lua API.rst +++ b/Lua API.rst @@ -3087,6 +3087,10 @@ These events are straight from EventManager module. Each of them first needs to Gets called when new invasion happens. +9. ``onInventoryChange(unit_id,item_id,old_equip,new_equip)`` + + Gets called when someone picks up an item, puts one down, or changes the way they are holding it. + Functions --------- diff --git a/NEWS b/NEWS index 9197ac72c..a71a6f35d 100644 --- a/NEWS +++ b/NEWS @@ -45,7 +45,7 @@ DFHack v0.34.11-r3 - stocks: An improved stocks display screen. Internals: - Core: there is now a per-save dfhack.init file for when the save is loaded, and another for when it is unloaded - - EventManager: fixed job completion detection + - EventManager: fixed job completion detection, fixed removal of TICK events, added EQUIPMENT_CHANGE event - Lua API for a better random number generator and perlin noise functions. - Once: easy way to make sure something happens once per run of DF, such as an error message diff --git a/library/include/modules/EventManager.h b/library/include/modules/EventManager.h index 5122dfdf2..f73a94253 100644 --- a/library/include/modules/EventManager.h +++ b/library/include/modules/EventManager.h @@ -10,6 +10,7 @@ #include "DataDefs.h" #include +#include namespace DFHack { namespace EventManager { @@ -24,7 +25,7 @@ namespace DFHack { CONSTRUCTION, SYNDROME, INVASION, -// EQUIPMENT_CHANGE, + INVENTORY_CHANGE, EVENT_MAX }; } @@ -53,10 +54,20 @@ namespace DFHack { } }; - /*struct InventoryData { + struct InventoryItem { + //it has to keep the id of an item because the item itself may have been deallocated + int32_t itemId; + df::unit_inventory_item item; + InventoryItem() {} + InventoryItem(int32_t id_in, df::unit_inventory_item item_in): itemId(id_in), item(item_in) {} + }; + struct InventoryChangeData { int32_t unitId; - vector* oldItems; - };*/ + InventoryItem* item_old; + InventoryItem* item_new; + InventoryChangeData() {} + InventoryChangeData(int32_t id_in, InventoryItem* old_in, InventoryItem* new_in): unitId(id_in), item_old(old_in), item_new(new_in) {} + }; DFHACK_EXPORT void registerListener(EventType::EventType e, EventHandler handler, Plugin* plugin); DFHACK_EXPORT int32_t registerTick(EventHandler handler, int32_t when, Plugin* plugin, bool absolute=false); diff --git a/library/modules/EventManager.cpp b/library/modules/EventManager.cpp index 0ec2b0754..bfc7c4907 100644 --- a/library/modules/EventManager.cpp +++ b/library/modules/EventManager.cpp @@ -114,7 +114,7 @@ static void manageBuildingEvent(color_ostream& out); static void manageConstructionEvent(color_ostream& out); static void manageSyndromeEvent(color_ostream& out); static void manageInvasionEvent(color_ostream& out); -//static void manageEquipmentEvent(color_ostream& out); +static void manageEquipmentEvent(color_ostream& out); typedef void (*eventManager_t)(color_ostream&); @@ -128,7 +128,7 @@ static const eventManager_t eventManager[] = { manageConstructionEvent, manageSyndromeEvent, manageInvasionEvent, -// manageEquipmentEvent, + manageEquipmentEvent, }; //job initiated @@ -159,6 +159,7 @@ static int32_t nextInvasion; //equipment change //static unordered_map > equipmentLog; +static unordered_map > equipmentLog; void DFHack::EventManager::onStateChange(color_ostream& out, state_change_event event) { static bool doOnce = false; @@ -181,10 +182,10 @@ void DFHack::EventManager::onStateChange(color_ostream& out, state_change_event livingUnits.clear(); buildings.clear(); constructions.clear(); + equipmentLog.clear(); Buildings::clearBuildings(out); gameLoaded = false; -// equipmentLog.clear(); } else if ( event == DFHack::SC_MAP_LOADED ) { /* int32_t tick = df::global::world->frame_counter; @@ -623,43 +624,76 @@ static void manageInvasionEvent(color_ostream& out) { } } -/* static void manageEquipmentEvent(color_ostream& out) { - multimap copy(handlers[EventType::EQUIPMENT_CHANGE].begin(), handlers[EventType::EQUIPMENT_CHANGE].end()); + multimap copy(handlers[EventType::INVENTORY_CHANGE].begin(), handlers[EventType::INVENTORY_CHANGE].end()); + unordered_map itemIdToInventoryItem; + unordered_set currentlyEquipped; for ( auto a = df::global::world->units.all.begin(); a != df::global::world->units.all.end(); a++ ) { + itemIdToInventoryItem.clear(); + currentlyEquipped.clear(); df::unit* unit = *a; - if ( unit->flags1.bits.dead ) + /*if ( unit->flags1.bits.dead ) continue; + */ - bool isNew = equipmentLog.find(unit->id) == equipmentLog.end(); - bool needsUpdate = isNew || equipmentLog[unit->id].size() != unit->inventory.size(); - if ( !needsUpdate ) { + auto oldEquipment = equipmentLog.find(unit->id); + if ( oldEquipment != equipmentLog.end() ) { + vector& v = (*oldEquipment).second; + for ( auto b = v.begin(); b != v.end(); b++ ) { + InventoryItem& i = *b; + itemIdToInventoryItem[i.itemId] = i; + } for ( size_t b = 0; b < unit->inventory.size(); b++ ) { - df::unit_inventory_item* item = unit->inventory[b]; - df::unit_inventory_item& old = equipmentLog[unit->id][b]; - if ( item->item == old.item && item->mode == old.mode && item->body_part_id == old.body_part_id && item->anon_1 == old.anon_1 && item->wound_id == old->wound_id ) + df::unit_inventory_item* dfitem_new = unit->inventory[b]; + currentlyEquipped.insert(dfitem_new->item->id); + InventoryItem item_new(dfitem_new->item->id, *dfitem_new); + auto c = itemIdToInventoryItem.find(dfitem_new->item->id); + if ( c == itemIdToInventoryItem.end() ) { + //new item equipped (probably just picked up) + InventoryChangeData data(unit->id, NULL, &item_new); + for ( auto h = copy.begin(); h != copy.end(); h++ ) { + EventHandler handle = (*h).second; + handle.eventHandler(out, (void*)&data); + } continue; + } + InventoryItem item_old = (*c).second; - needsUpdate = true; - break; + df::unit_inventory_item& item0 = item_old.item; + df::unit_inventory_item& item1 = item_new.item; + if ( item0.mode == item1.mode && item0.body_part_id == item1.body_part_id && item0.wound_id == item1.wound_id ) + continue; + //some sort of change in how it's equipped + + InventoryChangeData data(unit->id, &item_old, &item_new); + for ( auto h = copy.begin(); h != copy.end(); h++ ) { + EventHandler handle = (*h).second; + handle.eventHandler(out, (void*)&data); + } } - } - - if ( needsUpdate && !isNew ) { - for ( auto c = copy.begin(); c != copy.end(); c++ ) { - EventHandler handle = (*c).second; - handle.eventHandler(out, (void*)&data); + //check for dropped items + for ( auto b = v.begin(); b != v.end(); b++ ) { + InventoryItem i = *b; + if ( currentlyEquipped.find(i.itemId) != currentlyEquipped.end() ) + continue; + //TODO: delete ptr if invalid + InventoryChangeData data(unit->id, &i, NULL); + for ( auto h = copy.begin(); h != copy.end(); h++ ) { + EventHandler handle = (*h).second; + handle.eventHandler(out, (void*)&data); + } } } - if ( needsUpdate ) { - equipmentLog[unit->id].clear(); - for ( size_t b = 0; b < unit->inventory.size(); b++ ) { - equipmentLog[unit->id].push_back(* unit->inventory[b]); - } + //update equipment + vector& equipment = equipmentLog[unit->id]; + equipment.clear(); + for ( size_t b = 0; b < unit->inventory.size(); b++ ) { + df::unit_inventory_item* dfitem = unit->inventory[b]; + InventoryItem item(dfitem->item->id, *dfitem); + equipment.push_back(item); } } } -*/ diff --git a/plugins/eventful.cpp b/plugins/eventful.cpp index 281855203..f93c15edc 100644 --- a/plugins/eventful.cpp +++ b/plugins/eventful.cpp @@ -9,6 +9,7 @@ #include "df/building_workshopst.h" #include "df/unit.h" +#include "df/unit_inventory_item.h" #include "df/item.h" #include "df/item_actual.h" #include "df/unit_wound.h" @@ -120,6 +121,7 @@ static void handle_job_init(color_ostream &out,df::job*){}; static void handle_job_complete(color_ostream &out,df::job*){}; static void handle_constructions(color_ostream &out,df::construction*){}; static void handle_syndrome(color_ostream &out,int32_t,int32_t){}; +static void handle_inventory_change(color_ostream& out,int32_t,int32_t,df::unit_inventory_item*,df::unit_inventory_item*){}; DEFINE_LUA_EVENT_1(onBuildingCreatedDestroyed, handle_int32t, int32_t); DEFINE_LUA_EVENT_1(onJobInitiated,handle_job_init,df::job*); DEFINE_LUA_EVENT_1(onJobCompleted,handle_job_complete,df::job*); @@ -128,6 +130,7 @@ DEFINE_LUA_EVENT_1(onItemCreated,handle_int32t,int32_t); DEFINE_LUA_EVENT_1(onConstructionCreatedDestroyed, handle_constructions, df::construction*); DEFINE_LUA_EVENT_2(onSyndrome, handle_syndrome, int32_t,int32_t); DEFINE_LUA_EVENT_1(onInvasion,handle_int32t,int32_t); +DEFINE_LUA_EVENT_4(onInventoryChange,handle_inventory_change,int32_t,int32_t,df::unit_inventory_item*,df::unit_inventory_item*); DFHACK_PLUGIN_LUA_EVENTS { DFHACK_LUA_EVENT(onWorkshopFillSidebarMenu), DFHACK_LUA_EVENT(postWorkshopFillSidebarMenu), @@ -146,6 +149,7 @@ DFHACK_PLUGIN_LUA_EVENTS { DFHACK_LUA_EVENT(onItemCreated), DFHACK_LUA_EVENT(onSyndrome), DFHACK_LUA_EVENT(onInvasion), + DFHACK_LUA_EVENT(onInventoryChange), DFHACK_LUA_END }; @@ -189,6 +193,23 @@ static void ev_mng_building(color_ostream& out, void* ptr) int32_t myId=int32_t(ptr); onBuildingCreatedDestroyed(out,myId); } +static void ev_mng_inventory(color_ostream& out, void* ptr) +{ + EventManager::InventoryChangeData* data = reinterpret_cast(ptr); + int32_t unitId = data->unitId; + int32_t itemId = -1; + df::unit_inventory_item* item_old = NULL; + df::unit_inventory_item* item_new = NULL; + if ( data->item_old ) { + itemId = data->item_old->itemId; + item_old = &data->item_old->item; + } + if ( data->item_new ) { + itemId = data->item_new->itemId; + item_new = &data->item_new->item; + } + onInventoryChange(out,unitId,itemId,item_old,item_new); +} std::vector enabledEventManagerEvents(EventManager::EventType::EVENT_MAX,-1); typedef void (*handler_t) (color_ostream&,void*); static const handler_t eventHandlers[] = { @@ -201,6 +222,7 @@ static const handler_t eventHandlers[] = { ev_mng_construction, ev_mng_syndrome, ev_mng_invasion, + ev_mng_inventory, }; static void enableEvent(int evType,int freq) { diff --git a/plugins/lua/eventful.lua b/plugins/lua/eventful.lua index 75c7f8c15..a8840424b 100644 --- a/plugins/lua/eventful.lua +++ b/plugins/lua/eventful.lua @@ -116,5 +116,5 @@ local function invertTable(tbl) return ret end eventType=invertTable{[0]="TICK","JOB_INITIATED","JOB_COMPLETED","UNIT_DEATH","ITEM_CREATED", - "BUILDING","CONSTRUCTION","SYNDROME","INVASION","EVENT_MAX"} + "BUILDING","CONSTRUCTION","SYNDROME","INVASION","INVENTORY_CHANGE","EVENT_MAX"} return _ENV