Merge remote-tracking branch 'lethosor/dwarfvet-cleanup' into develop

develop
lethosor 2021-05-10 00:27:06 -04:00
commit faef412c78
No known key found for this signature in database
GPG Key ID: 76A269552F4F58C1
1 changed files with 59 additions and 130 deletions

@ -46,6 +46,7 @@
#include "df/world.h"
#include <map>
#include <unordered_set>
#include <vector>
using namespace DFHack;
@ -60,7 +61,7 @@ DFHACK_PLUGIN_IS_ENABLED(dwarfvet_enabled);
REQUIRE_GLOBAL(ui);
REQUIRE_GLOBAL(world);
static vector<int32_t> tracked_units;
static unordered_set<int32_t> tracked_units;
static int32_t howOften = 100;
struct hospital_spot {
@ -145,8 +146,8 @@ AnimalHospital::AnimalHospital(df::building * building, color_ostream &out) {
AnimalHospital::~AnimalHospital() {
// Go through and delete all the patients
for (vector<Patient*>::iterator accepted_patient = this->accepted_patients.begin(); accepted_patient != this->accepted_patients.end(); accepted_patient++) {
delete (*accepted_patient);
for (Patient* accepted_patient : this->accepted_patients) {
delete accepted_patient;
}
}
@ -159,7 +160,7 @@ bool AnimalHospital::acceptPatient(int32_t id, color_ostream &out) {
// Yup, let's find the next open spot,
// and give it to our patient
int spot_cur = 0; // fuck the STL for requiring a second counter to make this usable
int spot_cur = 0;
for (vector<bool>::iterator spot = this->spots_in_use.begin(); spot != this->spots_in_use.end(); spot++) {
if (*spot == false) {
*spot = true;
@ -193,11 +194,11 @@ void AnimalHospital::reportUsage(color_ostream &out) {
// Debugging tool to see parts of the hospital in use
int length_cursor = this->length;
for (vector<bool>::iterator spot = this->spots_in_use.begin(); spot != this->spots_in_use.end(); spot++) {
if (*spot) out.print("t");
if (!(*spot)) out.print("f");
for (bool spot : this->spots_in_use) {
if (spot) out.print("X");
else out.print("-");
length_cursor--;
if (length_cursor < 0) {
if (length_cursor <= 0) {
out.print("\n");
length_cursor = this->length;
}
@ -276,62 +277,16 @@ void AnimalHospital::calculateHospital(bool force, color_ostream &out) {
// NOTE: under some conditions, this generates a false warning. Not a lot I can do about it
// Mark spots used by that building as used; FIXME: handle special logic for traction benches and such
int building_offset_x = building->x1 - this->x1;
int building_offset_y = building->y1 - this->y1;
int building_length = building->x2 - building->x1 + 1;
int building_height = building->y2 - building->y1 + 1;
// Cap the used calculation to only include the part in the hospital
if (this->x1 > building->x1) {
building_offset_x -= (this->x1 - building->x1);
}
if (this->y1 > building->y1) {
building_offset_y -= (building->y1 - this->y1);
}
if ((this->x2 < building->x2) && building_offset_x) {
building_length -= (this->x2 - building->x2) + 1;
}
if ((this->y2 < building->y2) && building_offset_y) {
building_height = (building->y2 - this->y2) + 1;
}
// Quick explination, if a building is north or east of the activity zone,
// we get a negative offset, we'll just skip those lines below. If its
// south or west, we make the building length/height lower to compinsate.
/* if we have a negative x offset, we correct that */
if (building_offset_x < 0) {
building_height += building_offset_x;
building_offset_x = 0;
}
/* Handle negative y offset */
if (building_offset_y < 0) {
building_length += building_offset_y;
building_offset_y = 0;
};
/* Advance the pointer to first row we need to mark */
int spot_cur = 0;
if (building_offset_y) {
spot_cur = (length+1) * building_offset_y;
}
spot_cur += building_offset_x;
/* Start marking! */
for (int i = 0; i < building_height; i++) {
for (int j = 0; j < building_length; j++) {
spots_in_use[spot_cur+j] = true;
int overlap_x1 = std::max(building->x1, this->x1);
int overlap_y1 = std::max(building->y1, this->y1);
int overlap_x2 = std::min(building->x2, this->x2);
int overlap_y2 = std::min(building->y2, this->y2);
for (int x = overlap_x1; x <= overlap_x2; x++) {
for (int y = overlap_y1; y <= overlap_y2; y++) {
int spot_index = (x - this->x1) + (this->length * (y - this->y1));
spots_in_use.at(spot_index) = true;
}
// Wind the cursor to the start of the next row
spot_cur += length+1;
}
// *phew*, done. Now repeat the process for the next building!
}
}
@ -348,7 +303,7 @@ void AnimalHospital::dischargePatient(Patient * patient, color_ostream &out) {
if ( (*accepted_patient)->getID() == id) {
out.print("Discharging unit %d from hospital %d\n", id, this->id);
// Reclaim their spot
spots_in_use[(*accepted_patient)->getSpotIndex()] = false;
spots_in_use.at((*accepted_patient)->getSpotIndex()) = false;
this->spots_open++;
delete (*accepted_patient);
this->accepted_patients.erase(accepted_patient);
@ -357,36 +312,21 @@ void AnimalHospital::dischargePatient(Patient * patient, color_ostream &out) {
}
// And the master list
for (vector<int32_t>::iterator it = tracked_units.begin(); it != tracked_units.end(); it++) {
if ((*it) == id) {
tracked_units.erase(it);
break;
}
}
tracked_units.erase(id);
return;
}
void AnimalHospital::processPatients(color_ostream &out) {
// Where the magic happens
for (vector<Patient*>::iterator patient = this->accepted_patients.begin(); patient != this->accepted_patients.end(); patient++) {
int id = (*patient)->getID();
df::unit * real_unit = nullptr;
// Appears the health bits can get freed/realloced too -_-;, Find the unit from the main
// index and check it there.
auto units = world->units.all;
for ( size_t a = 0; a < units.size(); a++ ) {
real_unit = units[a];
if (real_unit->id == id) {
break;
}
}
for (Patient *patient : this->accepted_patients) {
int id = patient->getID();
df::unit *real_unit = df::unit::find(id);
// Check to make sure the unit hasn't expired before assigning a job, or if they've been healed
if (!real_unit || !Units::isActive(real_unit) || !real_unit->health->flags.bits.needs_healthcare) {
// discharge the patient from the hospital
this->dischargePatient(*patient, out);
this->dischargePatient(patient, out);
return;
}
@ -396,9 +336,9 @@ void AnimalHospital::processPatients(color_ostream &out) {
df::job * job = new df::job;
DFHack::Job::linkIntoWorld(job);
job->pos.x = (*patient)->returnX();
job->pos.y = (*patient)->returnY();
job->pos.z = (*patient)->returnZ();
job->pos.x = patient->returnX();
job->pos.y = patient->returnY();
job->pos.z = patient->returnZ();
job->flags.bits.special = 1;
job->job_type = df::enums::job_type::Rest;
df::general_ref *ref = df::allocate<df::general_ref_unit_workerst>();
@ -418,8 +358,8 @@ void delete_animal_hospital_vector(color_ostream &out) {
if (dwarfvet_enabled) {
out.print("Clearing all animal hospitals\n");
}
for (vector<AnimalHospital*>::iterator animal_hospital = animal_hospital_zones.begin(); animal_hospital != animal_hospital_zones.end(); animal_hospital++) {
delete (*animal_hospital);
for (AnimalHospital *animal_hospital : animal_hospital_zones) {
delete animal_hospital;
}
animal_hospital_zones.clear();
}
@ -474,8 +414,6 @@ void tickHandler(color_ostream& out, void* data) {
return;
CoreSuspender suspend;
int32_t own_race_id = df::global::ui->race_id;
int32_t own_civ_id = df::global::ui->civ_id;
auto units = world->units.all;
/**
* Generate a list of animal hospitals on the map
@ -496,8 +434,7 @@ void tickHandler(color_ostream& out, void* data) {
// Walk the building tree, and generate a list of animal hospitals on the map
for (size_t b =0 ; b < world->buildings.all.size(); b++) {
df::building* building = world->buildings.all[b];
for (df::building* building : df::building::get_vector()) {
if (isActiveAnimalHospital(building)) {
hospitals_on_map.push_back(building);
}
@ -531,7 +468,7 @@ void tickHandler(color_ostream& out, void* data) {
// Now walk our list of known hospitals, do a bit of checking, then compare
// TODO: this doesn't handle zone resizes at all
for (vector<AnimalHospital*>::iterator animal_hospital = animal_hospital_zones.begin(); animal_hospital != animal_hospital_zones.end(); animal_hospital++) {
for (AnimalHospital *animal_hospital : animal_hospital_zones) {
// If a zone is changed at all, DF seems to reallocate it.
//
// Each AnimalHospital has a "to_be_deleted" bool. We're going to set that to true, and clear it if we can't
@ -540,13 +477,13 @@ void tickHandler(color_ostream& out, void* data) {
//
// Surviving hospitals will be copied to scratch which will become the new AHZ vector
(*animal_hospital)->to_be_deleted = true;
for (vector<df::building*>::iterator current_hospital = hospitals_on_map.begin(); current_hospital != hospitals_on_map.end(); current_hospital++) {
animal_hospital->to_be_deleted = true;
for (df::building *current_hospital : hospitals_on_map) {
/* Keep the hospital if its still valid */
if ((*animal_hospital)->getID() == (*current_hospital)->id) {
ahz_scratch.push_back(*animal_hospital);
(*animal_hospital)->to_be_deleted = false;
if (animal_hospital->getID() == current_hospital->id) {
ahz_scratch.push_back(animal_hospital);
animal_hospital->to_be_deleted = false;
break;
}
@ -556,20 +493,20 @@ void tickHandler(color_ostream& out, void* data) {
// Report what we're deleting by checking the to_be_deleted bool.
//
// Whatsever left is added to the pending add list
for (vector<AnimalHospital*>::iterator animal_hospital = animal_hospital_zones.begin(); animal_hospital != animal_hospital_zones.end(); animal_hospital++) {
if ((*animal_hospital)->to_be_deleted) {
out.print("Hospital #%d removed\n", (*animal_hospital)->getID());
delete *animal_hospital;
for (AnimalHospital *animal_hospital : animal_hospital_zones) {
if (animal_hospital->to_be_deleted) {
out.print("Hospital #%d removed\n", animal_hospital->getID());
delete animal_hospital;
}
}
/* Now we need to walk the scratch and add anything that is a hospital and wasn't in the vector */
for (vector<df::building*>::iterator current_hospital = hospitals_on_map.begin(); current_hospital != hospitals_on_map.end(); current_hospital++) {
for (df::building *current_hospital : hospitals_on_map) {
bool new_hospital = true;
for (vector<AnimalHospital*>::iterator animal_hospital = ahz_scratch.begin(); animal_hospital != ahz_scratch.end(); animal_hospital++) {
if ((*animal_hospital)->getID() == (*current_hospital)->id) {
for (AnimalHospital *animal_hospital : ahz_scratch) {
if (animal_hospital->getID() == current_hospital->id) {
// Next if we're already here
new_hospital = false;
break;
@ -577,19 +514,19 @@ void tickHandler(color_ostream& out, void* data) {
}
// Add it if its new
if (new_hospital == true) to_be_added.push_back(*current_hospital);
if (new_hospital == true) to_be_added.push_back(current_hospital);
}
/* Now add it to the scratch AHZ */
for (vector<df::building*>::iterator current_hospital = to_be_added.begin(); current_hospital != to_be_added.end(); current_hospital++) {
for (df::building *current_hospital : to_be_added) {
// Add it to the vector
out.print("Adding new hospital #id: %d at x1 %d y1: %d z: %d\n",
(*current_hospital)->id,
(*current_hospital)->x1,
(*current_hospital)->y1,
(*current_hospital)->z
current_hospital->id,
current_hospital->x1,
current_hospital->y1,
current_hospital->z
);
AnimalHospital * hospital = new AnimalHospital(*current_hospital, out);
AnimalHospital * hospital = new AnimalHospital(current_hospital, out);
ahz_scratch.push_back(hospital);
}
@ -621,9 +558,7 @@ void tickHandler(color_ostream& out, void* data) {
*/
processUnits:
/* Code borrowed from petcapRemover.cpp */
for ( size_t a = 0; a < units.size(); a++ ) {
df::unit* unit = units[a];
for (df::unit *unit : df::unit::get_vector()) {
/* As hilarious as it would be, lets not treat FB :) */
if ( !Units::isActive(unit) || unit->flags1.bits.active_invader || unit->flags2.bits.underworld || unit->flags2.bits.visitor_uninvited || unit->flags2.bits.visitor ) {
continue;
@ -723,12 +658,7 @@ processUnits:
*/
// Now we need to find if this unit can be accepted at a hospital
bool awareOfUnit = false;
for (vector<int32_t>::iterator it = tracked_units.begin(); it != tracked_units.end(); it++) {
if ((*it) == unit->id) {
awareOfUnit = true;
}
}
bool awareOfUnit = tracked_units.count(unit->id);
// New unit for dwarfvet to be aware of!
if (!awareOfUnit) {
// The master list handles all patients which are accepted
@ -737,7 +667,7 @@ processUnits:
for (auto animal_hospital : animal_hospital_zones) {
if (animal_hospital->acceptPatient(unit->id, out)) {
out.print("Accepted patient %d at hospital %d\n", unit->id, animal_hospital->getID());
tracked_units.push_back(unit->id);
tracked_units.insert(unit->id);
break;
}
}
@ -746,9 +676,9 @@ processUnits:
}
// The final step, process all patients!
for (vector<AnimalHospital*>::iterator animal_hospital = animal_hospital_zones.begin(); animal_hospital != animal_hospital_zones.end(); animal_hospital++) {
(*animal_hospital)->calculateHospital(true, out);
(*animal_hospital)->processPatients(out);
for (AnimalHospital *animal_hospital : animal_hospital_zones) {
animal_hospital->calculateHospital(true, out);
animal_hospital->processPatients(out);
}
cleanup:
@ -772,8 +702,7 @@ command_result dwarfvet (color_ostream &out, std::vector <std::string> & paramet
}
if ( parameters[a] == "report") {
out.print("Current animal hospitals are:\n");
for (size_t b =0 ; b < world->buildings.all.size(); b++) {
df::building* building = world->buildings.all[b];
for (df::building *building : df::building::get_vector()) {
if (isActiveAnimalHospital(building)) {
out.print(" at x1: %d, x2: %d, y1: %d, y2: %d, z: %d\n", building->x1, building->x2, building->y1, building->y2, building->z);
}
@ -782,9 +711,9 @@ command_result dwarfvet (color_ostream &out, std::vector <std::string> & paramet
}
if ( parameters[a] == "report-usage") {
out.print("Current animal hospitals are:\n");
for (vector<AnimalHospital*>::iterator animal_hospital = animal_hospital_zones.begin(); animal_hospital != animal_hospital_zones.end(); animal_hospital++) {
(*animal_hospital)->calculateHospital(true, out);
(*animal_hospital)->reportUsage(out);
for (AnimalHospital *animal_hospital : animal_hospital_zones) {
animal_hospital->calculateHospital(true, out);
animal_hospital->reportUsage(out);
}
return CR_OK;
}