Skip to content

Commit 8b0730f

Browse files
authored
Merge pull request #4936 from myk002/myk_scrub_preserve
[preserve-rooms] scrub reservations when units die off-map
2 parents 956b58d + 0c0201f commit 8b0730f

2 files changed

Lines changed: 43 additions & 13 deletions

File tree

docs/plugins/preserve-rooms.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ This tool mitigates both issues. It records when units leave the map and
1919
reserves their assigned bedrooms, offices, etc. for them. The zones will be
2020
disabled in their absence (so other units don't steal them), and will be
2121
re-enabled and reassigned to them when they appear back on the map. If they die
22-
away from the fort, the zone will become unreserved and available for reuse.
22+
away from the fort, the zone will become unreserved and available for reuse. If
23+
they are captured and held prisoner, their room will continue to be reserved in
24+
their name in the (optimistic) hope of their safe return.
2325

2426
When you click on an assignable zone, you will also now have the option to
2527
associate the room with a noble or administrative role. The room will be

plugins/preserve-rooms.cpp

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -358,26 +358,52 @@ static void assign_nobles(color_ostream &out) {
358358
}
359359
}
360360

361+
static bool scrub_id_from_entries(int32_t id, int32_t key, unordered_map<int32_t, vector<int32_t>> & entries) {
362+
auto it = entries.find(key);
363+
if (it == entries.end())
364+
return false;
365+
auto & entry_ids = it->second;
366+
vector_erase_at(entry_ids, linear_index(entry_ids, id));
367+
if (entry_ids.empty()) {
368+
entries.erase(it);
369+
return true;
370+
}
371+
return false;
372+
}
373+
374+
// clear the reservation for a zone
361375
static void clear_reservation(color_ostream &out, int32_t zone_id, df::building_civzonest * zone = NULL) {
362376
auto it = reserved_zones.find(zone_id);
363377
if (it == reserved_zones.end())
364378
return;
365-
for (auto hfid : it->second) {
366-
auto pending_it = pending_reassignment.find(hfid);
367-
if (pending_it != pending_reassignment.end()) {
368-
auto & zone_ids = pending_it->second;
369-
vector_erase_at(zone_ids, linear_index(zone_ids, zone_id));
370-
if (zone_ids.empty())
371-
pending_reassignment.erase(pending_it);
372-
}
373-
}
379+
for (int32_t hfid : it->second)
380+
scrub_id_from_entries(zone_id, hfid, pending_reassignment);
374381
reserved_zones.erase(zone_id);
375382
if (!zone)
376383
zone = virtual_cast<df::building_civzonest>(df::building::find(zone_id));
377384
if (zone)
378385
zone->spec_sub_flag.bits.active = true;
379386
}
380387

388+
// stop reserving zones for dead units
389+
static void scrub_reservations(color_ostream &out) {
390+
vector<int32_t> hfids_to_scrub;
391+
for (auto &[hfid, zone_ids] : pending_reassignment) {
392+
if (auto hf = df::historical_figure::find(hfid); hf && hf->died_year == -1)
393+
continue;
394+
DEBUG(cycle,out).print("removed reservation for dead or culled hfid %d\n", hfid);
395+
hfids_to_scrub.push_back(hfid);
396+
for (int32_t zone_id : zone_ids) {
397+
if (scrub_id_from_entries(hfid, zone_id, reserved_zones)) {
398+
if (auto zone = virtual_cast<df::building_civzonest>(df::building::find(zone_id)))
399+
zone->spec_sub_flag.bits.active = true;
400+
}
401+
}
402+
}
403+
for (int32_t hfid : hfids_to_scrub)
404+
pending_reassignment.erase(hfid);
405+
}
406+
381407
// handles when units disappear from their assignments compared to the last scan
382408
static void handle_missing_assignments(color_ostream &out,
383409
const unordered_set<int32_t> & active_unit_ids,
@@ -411,9 +437,9 @@ static void handle_missing_assignments(color_ostream &out,
411437
continue;
412438
// unit is off-map or is dead; if we can assign room to spouse then we don't need to reserve the room
413439
auto spouse_hf = df::historical_figure::find(spouse_hfid);
440+
auto spouse = spouse_hf ? df::unit::find(spouse_hf->unit_id) : nullptr;
414441
if (spouse_hf && share_with_spouse) {
415-
if (auto spouse = df::unit::find(spouse_hf->unit_id);
416-
spouse && Units::isActive(spouse) && !Units::isDead(spouse) && active_unit_ids.contains(spouse->id))
442+
if (spouse && Units::isActive(spouse) && !Units::isDead(spouse) && active_unit_ids.contains(spouse->id))
417443
{
418444
DEBUG(cycle,out).print("assigning zone %d (%s) to spouse %s\n",
419445
zone_id, ENUM_KEY_STR(civzone_type, zone->type).c_str(),
@@ -430,7 +456,7 @@ static void handle_missing_assignments(color_ostream &out,
430456
DF2CONSOLE(Units::getReadableName(unit)).c_str());
431457
pending_reassignment[hfid].push_back(zone_id);
432458
reserved_zones[zone_id].push_back(hfid);
433-
if (share_with_spouse && spouse_hfid > -1) {
459+
if (share_with_spouse && spouse) {
434460
DEBUG(cycle,out).print("registering spouse unit for reassignment to zone %d (%s): hfid=%d\n",
435461
zone_id, ENUM_KEY_STR(civzone_type, zone->type).c_str(), spouse_hfid);
436462
pending_reassignment[spouse_hfid].push_back(zone_id);
@@ -489,6 +515,8 @@ static void do_cycle(color_ostream &out) {
489515
DEBUG(cycle,out).print("tracking zone assignments: bedrooms: %zd, offices: %zd, dining halls: %zd, tombs: %zd\n",
490516
last_known_assignments_bedroom.size(), last_known_assignments_office.size(),
491517
last_known_assignments_dining.size(), last_known_assignments_tomb.size());
518+
519+
scrub_reservations(out);
492520
}
493521

494522
if (config.get_bool(CONFIG_TRACK_ROLES)) {

0 commit comments

Comments
 (0)