Add ability to auto allocate rooms to noble positions.

develop
Anuradha Dissanayake 2014-06-14 23:50:47 +12:00
parent f07f2e1079
commit befab343a1
1 changed files with 301 additions and 1 deletions

@ -16,6 +16,7 @@
#include "df/world.h"
#include "df/building_constructionst.h"
#include "df/building_design.h"
#include "df/entity_position.h"
#include "modules/Gui.h"
#include "modules/Buildings.h"
@ -38,7 +39,7 @@ using df::global::ui_build_selector;
using df::global::world;
DFHACK_PLUGIN("buildingplan");
#define PLUGIN_VERSION 0.12
#define PLUGIN_VERSION 0.14
struct MaterialDescriptor
{
@ -461,6 +462,245 @@ private:
static void delete_item_fn(df::job_item *x) { delete x; }
// START Room Reservation
static bool canReserveRoom(df::building *building)
{
if (!building)
return false;
if (building->jobs.size() > 0 && building->jobs[0]->job_type == job_type::DestroyBuilding)
return false;
return building->is_room;
}
static std::vector<Units::NoblePosition> getUniqueNoblePositions(df::unit *unit)
{
std::vector<Units::NoblePosition> np;
Units::getNoblePositions(&np, unit);
for (auto iter = np.begin(); iter != np.end(); iter++)
{
if (iter->position->code == "MILITIA_CAPTAIN")
{
np.erase(iter);
break;
}
}
return np;
}
class ReservedRoom
{
public:
ReservedRoom(df::building *building, string noble_code)
{
this->building = building;
config = DFHack::World::AddPersistentData("buildingplan/reservedroom");
config.val() = noble_code;
config.ival(1) = building->id;
pos = df::coord(building->centerx, building->centery, building->z);
}
ReservedRoom(PersistentDataItem &config, color_ostream &out)
{
this->config = config;
building = df::building::find(config.ival(1));
if (!building)
return;
pos = df::coord(building->centerx, building->centery, building->z);
}
void remove()
{
DFHack::World::DeletePersistentData(config);
}
bool isValid()
{
if (!building)
return false;
if (Buildings::findAtTile(pos) != building)
return false;
return canReserveRoom(building);
}
int32_t getId()
{
if (!isValid())
return 0;
return building->id;
}
string getCode()
{
return config.val();
}
void setCode(const string &noble_code)
{
config.val() = noble_code;
}
bool checkRoomAssignment()
{
if (!isValid())
return false;
auto np = getOwnersNobleCode();
bool correctOwner = false;
for (auto iter = np.begin(); iter != np.end(); iter++)
{
if (iter->position->code == getCode())
{
correctOwner = true;
break;
}
}
if (correctOwner)
return true;
for (auto iter = world->units.active.begin(); iter != world->units.active.end(); iter++)
{
df::unit* unit = *iter;
if (!Units::isCitizen(unit))
continue;
if (DFHack::Units::isDead(unit))
continue;
np = getUniqueNoblePositions(unit);
for (auto iter = np.begin(); iter != np.end(); iter++)
{
if (iter->position->code == getCode())
{
Buildings::setOwner(building, unit);
break;
}
}
}
return true;
}
private:
df::building *building;
PersistentDataItem config;
df::coord pos;
std::vector<Units::NoblePosition> getOwnersNobleCode()
{
if (!building->owner)
return std::vector<Units::NoblePosition> ();
return getUniqueNoblePositions(building->owner);
}
};
class RoomMonitor
{
public:
RoomMonitor()
{
}
string getReservedNobleCode(int32_t buildingId)
{
for (auto iter = reservedRooms.begin(); iter != reservedRooms.end(); iter++)
{
if (buildingId == iter->getId())
return iter->getCode();
}
return "";
}
void toggleRoomForPosition(int32_t buildingId, string noble_code)
{
bool found = false;
for (auto iter = reservedRooms.begin(); iter != reservedRooms.end(); iter++)
{
if (buildingId != iter->getId())
{
continue;
}
else
{
if (noble_code == iter->getCode())
{
iter->remove();
reservedRooms.erase(iter);
}
else
{
iter->setCode(noble_code);
}
found = true;
break;
}
}
if (!found)
{
ReservedRoom room(df::building::find(buildingId), noble_code);
reservedRooms.push_back(room);
}
}
void doCycle()
{
for (auto iter = reservedRooms.begin(); iter != reservedRooms.end();)
{
if (iter->checkRoomAssignment())
{
++iter;
}
else
{
iter->remove();
iter = reservedRooms.erase(iter);
}
}
}
void reset(color_ostream &out)
{
reservedRooms.clear();
std::vector<PersistentDataItem> items;
DFHack::World::GetPersistentData(&items, "buildingplan/reservedroom");
for (auto i = items.begin(); i != items.end(); i++)
{
ReservedRoom rr(*i, out);
if (rr.isValid())
addRoom(rr);
}
}
private:
vector<ReservedRoom> reservedRooms;
void addRoom(ReservedRoom &rr)
{
for (auto iter = reservedRooms.begin(); iter != reservedRooms.end(); iter++)
{
if (iter->getId() == rr.getId())
return;
}
reservedRooms.push_back(rr);
}
};
static RoomMonitor roomMonitor;
// START Planning
class PlannedBuilding
{
@ -896,6 +1136,7 @@ DFhackCExport command_result plugin_onupdate(color_ostream &out)
{
last_frame_count = world->frame_counter;
planner.doCycle();
roomMonitor.doCycle();
}
return CR_OK;
@ -929,6 +1170,37 @@ struct buildingplan_hook : public df::viewscreen_dwarfmodest
planner.isPlanableBuilding(ui_build_selector->building_type);
}
std::vector<Units::NoblePosition> getNoblePositionOfSelectedBuildingOwner()
{
std::vector<Units::NoblePosition> np;
if (ui->main.mode != df::ui_sidebar_mode::QueryBuilding ||
!world->selected_building ||
!world->selected_building->owner)
{
return np;
}
switch (world->selected_building->getType())
{
case building_type::Bed:
case building_type::Chair:
case building_type::Table:
break;
default:
return np;
}
return getUniqueNoblePositions(world->selected_building->owner);
}
bool isInNobleRoomQueryMode()
{
if (getNoblePositionOfSelectedBuildingOwner().size() > 0)
return canReserveRoom(world->selected_building);
else
return false;
}
bool handleInput(set<df::interface_key> *input)
{
if (isInPlannedBuildingPlacementMode())
@ -1020,6 +1292,19 @@ struct buildingplan_hook : public df::viewscreen_dwarfmodest
}
}
else if (isInNobleRoomQueryMode())
{
auto np = getNoblePositionOfSelectedBuildingOwner();
df::interface_key last_token = *input->rbegin();
if (last_token >= interface_key::STRING_A048 && last_token <= interface_key::STRING_A058)
{
int selection = last_token - interface_key::STRING_A048;
if (np.size() < selection)
return false;
roomMonitor.toggleRoomForPosition(world->selected_building->id, np.at(selection-1).position->code);
return true;
}
}
return false;
}
@ -1130,6 +1415,20 @@ struct buildingplan_hook : public df::viewscreen_dwarfmodest
for (auto it = filters.begin(); it != filters.end(); ++it)
OutputString(COLOR_BLUE, x, y, "*" + *it, true, left_margin);
}
else if (isInNobleRoomQueryMode())
{
auto np = getNoblePositionOfSelectedBuildingOwner();
int y = 24;
OutputString(COLOR_BROWN, x, y, "DFHack", true, left_margin);
OutputString(COLOR_WHITE, x, y, "Auto-allocate to:", true, left_margin);
for (int i = 0; i < np.size() && i < 9; i++)
{
bool enabled = (roomMonitor.getReservedNobleCode(world->selected_building->id)
== np[i].position->code);
OutputToggleString(x, y, np[i].position->name[0].c_str(),
int_to_string(i+1).c_str(), enabled, true, left_margin);
}
}
else
{
planner.in_dummmy_screen = false;
@ -1198,6 +1497,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan
switch (event) {
case SC_MAP_LOADED:
planner.reset(out);
roomMonitor.reset(out);
break;
default:
break;