EventManager: added EQUIPMENT_CHANGE event and exposed it to lua.

develop
expwnent 2013-10-24 19:32:52 -04:00
parent ce1bb1e95b
commit 329741f235
6 changed files with 103 additions and 32 deletions

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

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

@ -10,6 +10,7 @@
#include "DataDefs.h"
#include <df/coord.h>
#include <df/unit_inventory_item.h>
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<df::unit_inventory_item>* 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);

@ -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<int32_t, vector<df::unit_inventory_item> > equipmentLog;
static unordered_map<int32_t, vector<InventoryItem> > 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<Plugin*,EventHandler> copy(handlers[EventType::EQUIPMENT_CHANGE].begin(), handlers[EventType::EQUIPMENT_CHANGE].end());
multimap<Plugin*,EventHandler> copy(handlers[EventType::INVENTORY_CHANGE].begin(), handlers[EventType::INVENTORY_CHANGE].end());
unordered_map<int32_t, InventoryItem> itemIdToInventoryItem;
unordered_set<int32_t> 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<InventoryItem>& 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;
//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();
//update equipment
vector<InventoryItem>& equipment = equipmentLog[unit->id];
equipment.clear();
for ( size_t b = 0; b < unit->inventory.size(); b++ ) {
equipmentLog[unit->id].push_back(* unit->inventory[b]);
}
df::unit_inventory_item* dfitem = unit->inventory[b];
InventoryItem item(dfitem->item->id, *dfitem);
equipment.push_back(item);
}
}
}
*/

@ -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<EventManager::InventoryChangeData*>(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<int> 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)
{

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