implement heat safety

develop
Myk Taylor 2023-02-19 00:57:30 -08:00
parent daa812b21e
commit a0785bded4
No known key found for this signature in database
6 changed files with 111 additions and 30 deletions

@ -74,6 +74,7 @@ struct BuildingTypeKeyHash {
static PersistentDataItem config; static PersistentDataItem config;
// for use in counting available materials for the UI // for use in counting available materials for the UI
static unordered_map<BuildingTypeKey, vector<df::job_item *>, BuildingTypeKeyHash> job_item_repo; static unordered_map<BuildingTypeKey, vector<df::job_item *>, BuildingTypeKeyHash> job_item_repo;
static unordered_map<BuildingTypeKey, HeatSafety, BuildingTypeKeyHash> cur_heat_safety;
// building id -> PlannedBuilding // building id -> PlannedBuilding
static unordered_map<int32_t, PlannedBuilding> planned_buildings; static unordered_map<int32_t, PlannedBuilding> planned_buildings;
// vector id -> filter bucket -> queue of (building id, job_item index) // vector id -> filter bucket -> queue of (building id, job_item index)
@ -456,13 +457,20 @@ static bool isPlannedBuilding(color_ostream &out, df::building *bld) {
return bld && planned_buildings.count(bld->id) > 0; return bld && planned_buildings.count(bld->id) > 0;
} }
static HeatSafety get_heat_safety_filter(const BuildingTypeKey &key) {
if (cur_heat_safety.count(key))
return cur_heat_safety.at(key);
return HEAT_SAFETY_ANY;
}
static bool addPlannedBuilding(color_ostream &out, df::building *bld) { static bool addPlannedBuilding(color_ostream &out, df::building *bld) {
DEBUG(status,out).print("entering addPlannedBuilding\n"); DEBUG(status,out).print("entering addPlannedBuilding\n");
if (!bld || planned_buildings.count(bld->id) if (!bld || planned_buildings.count(bld->id)
|| !isPlannableBuilding(out, bld->getType(), bld->getSubtype(), || !isPlannableBuilding(out, bld->getType(), bld->getSubtype(),
bld->getCustomType())) bld->getCustomType()))
return false; return false;
PlannedBuilding pb(out, bld); BuildingTypeKey key(bld->getType(), bld->getSubtype(), bld->getCustomType());
PlannedBuilding pb(out, bld, get_heat_safety_filter(key));
return registerPlannedBuilding(out, pb); return registerPlannedBuilding(out, pb);
} }
@ -482,6 +490,7 @@ static int scanAvailableItems(color_ostream &out, df::building_type type, int16_
"entering countAvailableItems building_type=%d subtype=%d custom=%d index=%d\n", "entering countAvailableItems building_type=%d subtype=%d custom=%d index=%d\n",
type, subtype, custom, index); type, subtype, custom, index);
BuildingTypeKey key(type, subtype, custom); BuildingTypeKey key(type, subtype, custom);
HeatSafety heat = get_heat_safety_filter(key);
auto &job_items = job_item_repo[key]; auto &job_items = job_item_repo[key];
if (index >= (int)job_items.size()) { if (index >= (int)job_items.size()) {
for (int i = job_items.size(); i <= index; ++i) { for (int i = job_items.size(); i <= index; ++i) {
@ -514,7 +523,7 @@ static int scanAvailableItems(color_ostream &out, df::building_type type, int16_
for (auto vector_id : vector_ids) { for (auto vector_id : vector_ids) {
auto other_id = ENUM_ATTR(job_item_vector_id, other, vector_id); auto other_id = ENUM_ATTR(job_item_vector_id, other, vector_id);
for (auto &item : df::global::world->items.other[other_id]) { for (auto &item : df::global::world->items.other[other_id]) {
if (itemPassesScreen(item) && matchesFilters(item, jitem)) { if (itemPassesScreen(item) && matchesFilters(item, jitem, heat)) {
if (item_ids) if (item_ids)
item_ids->emplace_back(item->id); item_ids->emplace_back(item->id);
++count; ++count;
@ -550,17 +559,56 @@ static int countAvailableItems(color_ostream &out, df::building_type type, int16
return scanAvailableItems(out, type, subtype, custom, index); return scanAvailableItems(out, type, subtype, custom, index);
} }
static bool hasFilter(color_ostream &out, df::building_type type, int16_t subtype, int32_t custom, int index) { static bool hasMaterialFilter(color_ostream &out, df::building_type type, int16_t subtype, int32_t custom, int index) {
DEBUG(status,out).print("entering hasFilter\n"); DEBUG(status,out).print("entering hasMaterialFilter\n");
return false; return false;
} }
static void setFilter(color_ostream &out, df::building_type type, int16_t subtype, int32_t custom, int index) { static void setMaterialFilter(color_ostream &out, df::building_type type, int16_t subtype, int32_t custom, int index, string filter) {
DEBUG(status,out).print("entering setFilter\n"); DEBUG(status,out).print("entering setMaterialFilter\n");
call_buildingplan_lua(&out, "signal_reset");
}
static int getMaterialFilter(lua_State *L) {
color_ostream *out = Lua::GetOutput(L);
if (!out)
out = &Core::getInstance().getConsole();
df::building_type type = (df::building_type)luaL_checkint(L, 1);
int16_t subtype = luaL_checkint(L, 2);
int32_t custom = luaL_checkint(L, 3);
int index = luaL_checkint(L, 4);
DEBUG(status,*out).print(
"entering getMaterialFilter building_type=%d subtype=%d custom=%d index=%d\n",
type, subtype, custom, index);
vector<string> filter;
Lua::PushVector(L, filter);
return 1;
} }
static void clearFilter(color_ostream &out, df::building_type type, int16_t subtype, int32_t custom, int index) { static void setHeatSafetyFilter(color_ostream &out, df::building_type type, int16_t subtype, int32_t custom, int heat) {
DEBUG(status,out).print("entering clearFilter\n"); DEBUG(status,out).print("entering setHeatSafetyFilter\n");
BuildingTypeKey key(type, subtype, custom);
if (heat == HEAT_SAFETY_FIRE || heat == HEAT_SAFETY_MAGMA)
cur_heat_safety[key] = (HeatSafety)heat;
else
cur_heat_safety.erase(key);
call_buildingplan_lua(&out, "signal_reset");
}
static int getHeatSafetyFilter(lua_State *L) {
color_ostream *out = Lua::GetOutput(L);
if (!out)
out = &Core::getInstance().getConsole();
df::building_type type = (df::building_type)luaL_checkint(L, 1);
int16_t subtype = luaL_checkint(L, 2);
int32_t custom = luaL_checkint(L, 3);
DEBUG(status,*out).print(
"entering getHeatSafetyFilter building_type=%d subtype=%d custom=%d\n",
type, subtype, custom);
BuildingTypeKey key(type, subtype, custom);
HeatSafety heat = get_heat_safety_filter(key);
Lua::Push(L, heat);
return 1;
} }
static bool validate_pb(color_ostream &out, df::building *bld, int index) { static bool validate_pb(color_ostream &out, df::building *bld, int index) {
@ -659,9 +707,9 @@ DFHACK_PLUGIN_LUA_FUNCTIONS {
DFHACK_LUA_FUNCTION(doCycle), DFHACK_LUA_FUNCTION(doCycle),
DFHACK_LUA_FUNCTION(scheduleCycle), DFHACK_LUA_FUNCTION(scheduleCycle),
DFHACK_LUA_FUNCTION(countAvailableItems), DFHACK_LUA_FUNCTION(countAvailableItems),
DFHACK_LUA_FUNCTION(hasFilter), DFHACK_LUA_FUNCTION(hasMaterialFilter),
DFHACK_LUA_FUNCTION(setFilter), DFHACK_LUA_FUNCTION(setMaterialFilter),
DFHACK_LUA_FUNCTION(clearFilter), DFHACK_LUA_FUNCTION(setHeatSafetyFilter),
DFHACK_LUA_FUNCTION(getDescString), DFHACK_LUA_FUNCTION(getDescString),
DFHACK_LUA_FUNCTION(getQueuePosition), DFHACK_LUA_FUNCTION(getQueuePosition),
DFHACK_LUA_FUNCTION(makeTopPriority), DFHACK_LUA_FUNCTION(makeTopPriority),
@ -670,5 +718,7 @@ DFHACK_PLUGIN_LUA_FUNCTIONS {
DFHACK_PLUGIN_LUA_COMMANDS { DFHACK_PLUGIN_LUA_COMMANDS {
DFHACK_LUA_COMMAND(getAvailableItems), DFHACK_LUA_COMMAND(getAvailableItems),
DFHACK_LUA_COMMAND(getMaterialFilter),
DFHACK_LUA_COMMAND(getHeatSafetyFilter),
DFHACK_LUA_END DFHACK_LUA_END
}; };

@ -2,6 +2,7 @@
#include "modules/Persistence.h" #include "modules/Persistence.h"
#include "df/building.h"
#include "df/job_item.h" #include "df/job_item.h"
#include "df/job_item_vector_id.h" #include "df/job_item_vector_id.h"
@ -21,6 +22,13 @@ enum ConfigValues {
enum BuildingConfigValues { enum BuildingConfigValues {
BLD_CONFIG_ID = 0, BLD_CONFIG_ID = 0,
BLD_CONFIG_HEAT = 1,
};
enum HeatSafety {
HEAT_SAFETY_ANY = 0,
HEAT_SAFETY_FIRE = 1,
HEAT_SAFETY_MAGMA = 2,
}; };
int get_config_val(DFHack::PersistentDataItem &c, int index); int get_config_val(DFHack::PersistentDataItem &c, int index);
@ -30,6 +38,6 @@ void set_config_bool(DFHack::PersistentDataItem &c, int index, bool value);
std::vector<df::job_item_vector_id> getVectorIds(DFHack::color_ostream &out, df::job_item *job_item); std::vector<df::job_item_vector_id> getVectorIds(DFHack::color_ostream &out, df::job_item *job_item);
bool itemPassesScreen(df::item * item); bool itemPassesScreen(df::item * item);
bool matchesFilters(df::item * item, df::job_item * job_item); bool matchesFilters(df::item * item, df::job_item * job_item, HeatSafety heat);
bool isJobReady(DFHack::color_ostream &out, const std::vector<df::job_item *> &jitems); bool isJobReady(DFHack::color_ostream &out, const std::vector<df::job_item *> &jitems);
void finalizeBuilding(DFHack::color_ostream &out, df::building *bld); void finalizeBuilding(DFHack::color_ostream &out, df::building *bld);

@ -46,7 +46,7 @@ bool itemPassesScreen(df::item * item) {
&& !item->isAssignedToStockpile(); && !item->isAssignedToStockpile();
} }
bool matchesFilters(df::item * item, df::job_item * job_item) { bool matchesFilters(df::item * item, df::job_item * job_item, HeatSafety heat) {
// check the properties that are not checked by Job::isSuitableItem() // check the properties that are not checked by Job::isSuitableItem()
if (job_item->item_type > -1 && job_item->item_type != item->getType()) if (job_item->item_type > -1 && job_item->item_type != item->getType())
return false; return false;
@ -65,10 +65,17 @@ bool matchesFilters(df::item * item, df::job_item * job_item) {
&& !item->hasToolUse(job_item->has_tool_use)) && !item->hasToolUse(job_item->has_tool_use))
return false; return false;
df::job_item jitem = *job_item;
if (heat == HEAT_SAFETY_MAGMA) {
jitem.flags2.bits.magma_safe = true;
jitem.flags2.bits.fire_safe = false;
} else if (heat == HEAT_SAFETY_FIRE && !jitem.flags2.bits.magma_safe)
jitem.flags2.bits.fire_safe = true;
return Job::isSuitableItem( return Job::isSuitableItem(
job_item, item->getType(), item->getSubtype()) &jitem, item->getType(), item->getSubtype())
&& Job::isSuitableMaterial( && Job::isSuitableMaterial(
job_item, item->getMaterial(), item->getMaterialIndex(), &jitem, item->getMaterial(), item->getMaterialIndex(),
item->getType()); item->getType());
} }
@ -173,7 +180,7 @@ static void doVector(color_ostream &out, df::job_item_vector_id vector_id,
auto id = task.first; auto id = task.first;
auto job = bld->jobs[0]; auto job = bld->jobs[0];
auto filter_idx = task.second; auto filter_idx = task.second;
if (matchesFilters(item, job->job_items[filter_idx]) if (matchesFilters(item, job->job_items[filter_idx], planned_buildings.at(id).heat_safety)
&& Job::attachJobItem(job, item, && Job::attachJobItem(job, item,
df::job_item_ref::Hauled, filter_idx)) df::job_item_ref::Hauled, filter_idx))
{ {

@ -62,11 +62,12 @@ static string serialize(const vector<vector<df::job_item_vector_id>> &vector_ids
return join_strings("|", joined); return join_strings("|", joined);
} }
PlannedBuilding::PlannedBuilding(color_ostream &out, df::building *building) PlannedBuilding::PlannedBuilding(color_ostream &out, df::building *bld, HeatSafety heat)
: id(building->id), vector_ids(get_vector_ids(out, id)) { : id(bld->id), vector_ids(get_vector_ids(out, id)), heat_safety(heat) {
DEBUG(status,out).print("creating persistent data for building %d\n", id); DEBUG(status,out).print("creating persistent data for building %d\n", id);
bld_config = World::AddPersistentData(BLD_CONFIG_KEY); bld_config = World::AddPersistentData(BLD_CONFIG_KEY);
set_config_val(bld_config, BLD_CONFIG_ID, id); set_config_val(bld_config, BLD_CONFIG_ID, id);
set_config_val(bld_config, BLD_CONFIG_HEAT, heat_safety);
bld_config.val() = serialize(vector_ids); bld_config.val() = serialize(vector_ids);
DEBUG(status,out).print("serialized state for building %d: %s\n", id, bld_config.val().c_str()); DEBUG(status,out).print("serialized state for building %d: %s\n", id, bld_config.val().c_str());
} }
@ -74,6 +75,7 @@ PlannedBuilding::PlannedBuilding(color_ostream &out, df::building *building)
PlannedBuilding::PlannedBuilding(color_ostream &out, PersistentDataItem &bld_config) PlannedBuilding::PlannedBuilding(color_ostream &out, PersistentDataItem &bld_config)
: id(get_config_val(bld_config, BLD_CONFIG_ID)), : id(get_config_val(bld_config, BLD_CONFIG_ID)),
vector_ids(deserialize(out, bld_config)), vector_ids(deserialize(out, bld_config)),
heat_safety((HeatSafety)get_config_val(bld_config, BLD_CONFIG_HEAT)),
bld_config(bld_config) { } bld_config(bld_config) { }
// Ensure the building still exists and is in a valid state. It can disappear // Ensure the building still exists and is in a valid state. It can disappear

@ -1,5 +1,7 @@
#pragma once #pragma once
#include "buildingplan.h"
#include "Core.h" #include "Core.h"
#include "modules/Persistence.h" #include "modules/Persistence.h"
@ -14,7 +16,9 @@ public:
// job_item idx -> list of vectors the task is linked to // job_item idx -> list of vectors the task is linked to
const std::vector<std::vector<df::job_item_vector_id>> vector_ids; const std::vector<std::vector<df::job_item_vector_id>> vector_ids;
PlannedBuilding(DFHack::color_ostream &out, df::building *building); const HeatSafety heat_safety;
PlannedBuilding(DFHack::color_ostream &out, df::building *bld, HeatSafety heat);
PlannedBuilding(DFHack::color_ostream &out, DFHack::PersistentDataItem &bld_config); PlannedBuilding(DFHack::color_ostream &out, DFHack::PersistentDataItem &bld_config);
void remove(DFHack::color_ostream &out); void remove(DFHack::color_ostream &out);

@ -251,14 +251,18 @@ function ItemSelection:get_entry_icon(item_id)
return self.selected_set[item_id] and get_selected_item_pen() or nil return self.selected_set[item_id] and get_selected_item_pen() or nil
end end
ItemSelectionScreen = defclass(ItemSelectionScreen, gui.ZScreen) BuildingplanScreen = defclass(BuildingplanScreen, gui.ZScreen)
ItemSelectionScreen.ATTRS { BuildingplanScreen.ATTRS {
focus_path='buildingplan/itemselection',
force_pause=true, force_pause=true,
pass_pause=false, pass_pause=false,
pass_movement_keys=true, pass_movement_keys=true,
pass_mouse_clicks=false, pass_mouse_clicks=false,
defocusable=false, defocusable=false,
}
ItemSelectionScreen = defclass(ItemSelectionScreen, BuildingplanScreen)
ItemSelectionScreen.ATTRS {
focus_path='buildingplan/itemselection',
index=DEFAULT_NIL, index=DEFAULT_NIL,
on_submit=DEFAULT_NIL, on_submit=DEFAULT_NIL,
} }
@ -414,7 +418,8 @@ function ItemLine:onInput(keys)
end end
function ItemLine:get_x_pen() function ItemLine:get_x_pen()
return hasFilter(uibs.building_type, uibs.building_subtype, uibs.custom_type, self.idx) and COLOR_GREEN or COLOR_GREY return hasMaterialFilter(uibs.building_type, uibs.building_subtype, uibs.custom_type, self.idx) and
COLOR_GREEN or COLOR_GREY
end end
function get_desc(filter) function get_desc(filter)
@ -599,7 +604,7 @@ function PlannerOverlay:init()
view_id='choose', view_id='choose',
frame={b=0, l=0}, frame={b=0, l=0},
key='CUSTOM_I', key='CUSTOM_I',
label='Choose exact items:', label='Choose from items:',
options={{label='Yes', value=true}, options={{label='Yes', value=true},
{label='No', value=false}}, {label='No', value=false}},
initial_option=false, initial_option=false,
@ -617,10 +622,13 @@ function PlannerOverlay:init()
key='CUSTOM_G', key='CUSTOM_G',
label='Building safety:', label='Building safety:',
options={ options={
{label='Any', value='none'}, {label='Any', value=0},
{label='Magma', value='magma'}, {label='Magma', value=2, pen=COLOR_RED},
{label='Fire', value='fire'}, {label='Fire', value=1, pen=COLOR_LIGHTRED},
}, },
on_change=function(heat)
setHeatSafetyFilter(uibs.building_type, uibs.building_subtype, uibs.custom_type, heat)
end,
}, },
}, },
}, },
@ -663,11 +671,11 @@ function PlannerOverlay:reset()
end end
function PlannerOverlay:set_filter(idx) function PlannerOverlay:set_filter(idx)
print('set_filter', idx) print('TODO: set_filter', idx)
end end
function PlannerOverlay:clear_filter(idx) function PlannerOverlay:clear_filter(idx)
print('clear_filter', idx) setMaterialFilter(uibs.building_type, uibs.building_subtype, uibs.custom_type, idx, "")
end end
function PlannerOverlay:onInput(keys) function PlannerOverlay:onInput(keys)
@ -679,8 +687,8 @@ function PlannerOverlay:onInput(keys)
end end
self.selected = 1 self.selected = 1
self.subviews.choose:setOption(false) self.subviews.choose:setOption(false)
self.subviews.safety:setOption('none')
self:reset() self:reset()
reset_counts_flag = true
return false return false
end end
if PlannerOverlay.super.onInput(self, keys) then if PlannerOverlay.super.onInput(self, keys) then
@ -753,6 +761,8 @@ function PlannerOverlay:onRenderFrame(dc, rect)
if reset_counts_flag then if reset_counts_flag then
self:reset() self:reset()
self.subviews.safety:setOption(getHeatSafetyFilter(
uibs.building_type, uibs.building_subtype, uibs.custom_type))
end end
if not is_choosing_area() then return end if not is_choosing_area() then return end