66#include " modules/Maps.h"
77#include " modules/Units.h"
88
9+ #include " df/building.h"
910#include " df/item.h"
1011#include " df/map_block.h"
1112#include " df/tile_occupancy.h"
@@ -43,7 +44,7 @@ DFhackCExport command_result plugin_init(color_ostream &out, vector<PluginComman
4344 DEBUG (log, out).print (" initializing %s\n " , plugin_name);
4445
4546 commands.push_back (PluginCommand (
46- plugin_name ,
47+ " fix/occupancy " ,
4748 " Fix phantom occupancy issues." ,
4849 do_command));
4950
@@ -142,8 +143,8 @@ static void fix_tile(color_ostream &out, df::coord pos, bool dry_run) {
142143 }
143144}
144145
146+ /*
145147static void fix_map_items(color_ostream &out, bool dry_run) {
146- /*
147148 local cnt = 0
148149 local icnt = 0
149150 local found = {}
@@ -243,8 +244,8 @@ static void fix_map_items(color_ostream &out, bool dry_run) {
243244 elseif should_fix then
244245 print("The problems are too severe to be fixed by this script.")
245246 end
246- */
247247}
248+ */
248249
249250struct OccBuf {
250251private:
@@ -269,9 +270,15 @@ struct OccBuf {
269270 return &buf[off];
270271 return nullptr ;
271272 }
273+
274+ df::tile_occupancy * occ (const df::coord & pos) {
275+ return occ (pos.x , pos.y , pos.z );
276+ }
272277};
273278
274- static void reconcile_map_tile (color_ostream &out, df::tile_occupancy & expected_occ, df::tile_occupancy & block_occ, bool dry_run) {
279+ static void reconcile_map_tile (color_ostream &out, df::tile_occupancy & expected_occ, df::tile_occupancy & block_occ,
280+ bool dry_run, int x, int y, int z)
281+ {
275282 // clear building occupancy if there is no building there
276283 if (expected_occ.bits .building == df::tile_building_occ::None && block_occ.bits .building != df::tile_building_occ::None) {
277284 INFO (log,out).print (" %s building occupancy at (%d, %d, %d)\n " ,
@@ -280,60 +287,63 @@ static void reconcile_map_tile(color_ostream &out, df::tile_occupancy & expected
280287 block_occ.bits .building = df::tile_building_occ::None;
281288 }
282289
283- // check/fix unit occupancy
284- if (occ->bits .unit || occ->bits .unit_grounded ) {
285- vector<df::unit *> units;
286- Units::getUnitsInBox (units, pos.x , pos.y , pos.z , pos.x , pos.y , pos.z );
287- bool found_standing_unit = false ;
288- bool found_grounded_unit = false ;
289- for (auto unit : units) {
290- if (unit->flags1 .bits .caged )
291- continue ;
292- if (unit->flags1 .bits .on_ground )
293- found_grounded_unit = true ;
294- else
295- found_standing_unit = true ;
296- }
297- if (occ->bits .unit != found_standing_unit) {
298- INFO (log,out).print (" %s standing unit occupancy at (%d, %d, %d)\n " ,
299- dry_run ? " would fix" : " fixing" , pos.x , pos.y , pos.z );
300- if (!dry_run)
301- occ->bits .unit = found_standing_unit;
302- }
303- if (occ->bits .unit_grounded != found_grounded_unit) {
304- INFO (log,out).print (" %s grounded unit occupancy at (%d, %d, %d)\n " ,
305- dry_run ? " would fix" : " fixing" , pos.x , pos.y , pos.z );
306- if (!dry_run)
307- occ->bits .unit_grounded = found_grounded_unit;
308- }
290+ // clear unit occupancy if there are no units there
291+ if (!expected_occ.bits .unit && block_occ.bits .unit ) {
292+ INFO (log,out).print (" %s standing unit occupancy at (%d, %d, %d)\n " ,
293+ dry_run ? " would fix" : " fixing" , x, y, z);
294+ if (!dry_run)
295+ block_occ.bits .unit = false ;
296+ }
297+ if (!expected_occ.bits .unit_grounded && block_occ.bits .unit_grounded ) {
298+ INFO (log,out).print (" %s grounded unit occupancy at (%d, %d, %d)\n " ,
299+ dry_run ? " would fix" : " fixing" , x, y, z);
300+ if (!dry_run)
301+ block_occ.bits .unit_grounded = false ;
309302 }
310303
311- // check/fix block occupancy
312- if (occ-> bits .item != found_item ) {
304+ // clear item occupancy if there are no items there
305+ if (!expected_occ. bits .item && block_occ. bits . item ) {
313306 INFO (log,out).print (" %s item occupancy at (%d, %d, %d)\n " ,
314- dry_run ? " would fix" : " fixing" , pos. x , pos. y , pos. z );
307+ dry_run ? " would fix" : " fixing" , x, y, z);
315308 if (!dry_run)
316- occ-> bits .item = found_item ;
309+ block_occ. bits .item = false ;
317310 }
318-
319311}
320312
321313static void fix_map (color_ostream &out, bool dry_run) {
314+ static const uint32_t occ_mask = df::tile_occupancy::mask_building | df::tile_occupancy::mask_unit |
315+ df::tile_occupancy::mask_unit_grounded | df::tile_occupancy::mask_item;
316+
322317 OccBuf occ_buf;
323318
324319 // set expected building occupancy
325320 for (auto bld : world->buildings .all ) {
326-
321+ for (int y = bld->y1 ; y <= bld->y2 ; ++y) {
322+ for (int x = bld->x1 ; x <= bld->x2 ; ++x) {
323+ if (Buildings::containsTile (bld, df::coord2d (x, y))) {
324+ if (auto occ = occ_buf.occ (x, y, bld->z ))
325+ occ->bits .building = df::tile_building_occ::Impassable;
326+ }
327+ }
328+ }
327329 }
328330
329331 // set expected unit occupancy
330332 for (auto unit : world->units .active ) {
331-
333+ if (unit->flags1 .bits .caged )
334+ continue ;
335+ if (auto occ = occ_buf.occ (unit->pos )) {
336+ occ->bits .unit = !unit->flags1 .bits .on_ground ;
337+ occ->bits .unit_grounded = unit->flags1 .bits .on_ground ;
338+ }
332339 }
333340
334341 // set expected item occupancy
335342 for (auto item : world->items .other .IN_PLAY ) {
336-
343+ if (!item->flags .bits .on_ground )
344+ continue ;
345+ if (auto occ = occ_buf.occ (Items::getPosition (item)))
346+ occ->bits .item = true ;
337347 }
338348
339349 // check against expected occupancy and fix
@@ -352,29 +362,34 @@ static void fix_map(color_ostream &out, bool dry_run) {
352362 TRACE (log,out).print (" pos out of bounds (%d, %d, %d)\n " , x, y, z);
353363 continue ;
354364 }
355- reconcile_map_tile (out, *expected_occ, block->occupancy [x][y], dry_run);
365+ df::tile_occupancy &block_occ = block->occupancy [x][y];
366+ if ((expected_occ->whole & occ_mask) != (block_occ.whole & occ_mask)) {
367+ TRACE (log,out).print (" reconciling occupancy at (%d, %d, %d) (%d != %d)\n " ,
368+ x, y, z, expected_occ->whole & occ_mask, block_occ.whole & occ_mask);
369+ reconcile_map_tile (out, *expected_occ, block_occ, dry_run, x, y, z);
370+ }
356371 }
357372 }
358373 }
359374
360- // check/fix item membership in block item vector
361- bool found_item = false ;
362- for (auto item : world->items .other .IN_PLAY ) {
363- if (!item->flags .bits .on_ground || item->pos != pos)
364- continue ;
365- found_item = true ;
366- if (!dry_run) {
367- bool inserted = false ;
368- insert_into_vector (block->items , item->id , &inserted);
369- if (inserted) {
370- INFO (log,out).print (" fixing item membership in map block item list at (%d, %d, %d)\n " ,
371- pos.x , pos.y , pos.z );
372- }
373- } else if (!vector_contains (block->items , item->id )) {
374- INFO (log,out).print (" would fix item membership in map block item list at (%d, %d, %d)\n " ,
375- pos.x , pos.y , pos.z );
376- }
377- }
375+ // check/fix item membership in block item vectors
376+ // bool found_item = false;
377+ // for (auto item : world->items.other.IN_PLAY) {
378+ // if (!item->flags.bits.on_ground || item->pos != pos)
379+ // continue;
380+ // found_item = true;
381+ // if (!dry_run) {
382+ // bool inserted = false;
383+ // insert_into_vector(block->items, item->id, &inserted);
384+ // if (inserted) {
385+ // INFO(log,out).print("fixing item membership in map block item list at (%d, %d, %d)\n",
386+ // pos.x, pos.y, pos.z);
387+ // }
388+ // } else if (!vector_contains(block->items, item->id)) {
389+ // INFO(log,out).print("would fix item membership in map block item list at (%d, %d, %d)\n",
390+ // pos.x, pos.y, pos.z);
391+ // }
392+ // }
378393
379394}
380395
0 commit comments