Merge pull request #555 from lethosor/travis

Add .travis.yml and fix whitespace issues
develop
Lethosor 2015-02-16 17:05:29 -05:00
commit e9cc242322
157 changed files with 5894 additions and 5737 deletions

@ -0,0 +1,6 @@
language: cpp
script:
- python travis/lint.py
- python travis/pr-check-base.py
notifications:
email: false

@ -1601,8 +1601,8 @@ void Core::onUpdate(color_ostream &out)
void Core::handleLoadAndUnloadScripts(color_ostream& out, state_change_event event) { void Core::handleLoadAndUnloadScripts(color_ostream& out, state_change_event event) {
if (!df::global::world) if (!df::global::world)
return; return;
//TODO: use different separators for windows //TODO: use different separators for windows
#ifdef _WIN32 #ifdef _WIN32
static const std::string separator = "\\"; static const std::string separator = "\\";
#else #else

@ -72,7 +72,7 @@ class BlockInfo
Block *mblock; Block *mblock;
MapCache *parent; MapCache *parent;
df::map_block *block; df::map_block *block;
df::map_block_column *column; //for plants df::map_block_column *column; //for plants
public: public:
enum GroundType { enum GroundType {

@ -138,13 +138,13 @@
* only defined for compatibility. These macros should always return false * only defined for compatibility. These macros should always return false
* on Windows. * on Windows.
*/ */
#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFFIFO) #define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFFIFO)
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) #define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) #define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) #define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) #define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {

@ -1,300 +1,300 @@
local _ENV = mkmodule('makeown') local _ENV = mkmodule('makeown')
--[[ --[[
'tweak makeown' as a lua include 'tweak makeown' as a lua include
make_own(unit) -- removes foreign flags, sets civ_id to fort civ_id, and sets clothes ownership make_own(unit) -- removes foreign flags, sets civ_id to fort civ_id, and sets clothes ownership
make_citizen(unit) -- called by make_own if unit.race == fort race make_citizen(unit) -- called by make_own if unit.race == fort race
eventually ought to migrate to hack/lua/plugins/tweak.lua eventually ought to migrate to hack/lua/plugins/tweak.lua
and local _ENV = mkmodule('plugin.tweak') and local _ENV = mkmodule('plugin.tweak')
in order to link to functions in the compiled plugin (when/if they become available to lua) in order to link to functions in the compiled plugin (when/if they become available to lua)
--]] --]]
local utils = require 'utils' local utils = require 'utils'
local function fix_clothing_ownership(unit) local function fix_clothing_ownership(unit)
-- extracted/translated from tweak makeown plugin -- extracted/translated from tweak makeown plugin
-- to be called by tweak-fixmigrant/makeown -- to be called by tweak-fixmigrant/makeown
-- units forced into the fort by removing the flags do not own their clothes -- units forced into the fort by removing the flags do not own their clothes
-- which has the result that they drop all their clothes and become unhappy because they are naked -- which has the result that they drop all their clothes and become unhappy because they are naked
-- so we need to make them own their clothes and add them to their uniform -- so we need to make them own their clothes and add them to their uniform
local fixcount = 0 --int fixcount = 0; local fixcount = 0 --int fixcount = 0;
for j=0,#unit.inventory-1 do --for(size_t j=0; j<unit->inventory.size(); j++) for j=0,#unit.inventory-1 do --for(size_t j=0; j<unit->inventory.size(); j++)
local inv_item = unit.inventory[j] --unidf::unit_inventory_item* inv_item = unit->inventory[j]; local inv_item = unit.inventory[j] --unidf::unit_inventory_item* inv_item = unit->inventory[j];
local item = inv_item.item --df::item* item = inv_item->item; local item = inv_item.item --df::item* item = inv_item->item;
-- unforbid items (for the case of kidnapping caravan escorts who have their stuff forbidden by default) -- unforbid items (for the case of kidnapping caravan escorts who have their stuff forbidden by default)
-- moved forbid false to inside if so that armor/weapons stay equiped -- moved forbid false to inside if so that armor/weapons stay equiped
if inv_item.mode == df.unit_inventory_item.T_mode.Worn then --if(inv_item->mode == df::unit_inventory_item::T_mode::Worn) if inv_item.mode == df.unit_inventory_item.T_mode.Worn then --if(inv_item->mode == df::unit_inventory_item::T_mode::Worn)
-- ignore armor? -- ignore armor?
-- it could be leather boots, for example, in which case it would not be nice to forbid ownership -- it could be leather boots, for example, in which case it would not be nice to forbid ownership
--if(item->getEffectiveArmorLevel() != 0) --if(item->getEffectiveArmorLevel() != 0)
-- continue; -- continue;
if not dfhack.items.getOwner(item) then --if(!Items::getOwner(item)) if not dfhack.items.getOwner(item) then --if(!Items::getOwner(item))
if dfhack.items.setOwner(item,unit) then --if(Items::setOwner(item, unit)) if dfhack.items.setOwner(item,unit) then --if(Items::setOwner(item, unit))
item.flags.forbid = false --inv_item->item->flags.bits.forbid = 0; item.flags.forbid = false --inv_item->item->flags.bits.forbid = 0;
-- add to uniform, so they know they should wear their clothes -- add to uniform, so they know they should wear their clothes
unit.military.uniforms[0]:insert('#',item.id) --insert_into_vector(unit->military.uniforms[0], item->id); unit.military.uniforms[0]:insert('#',item.id) --insert_into_vector(unit->military.uniforms[0], item->id);
fixcount = fixcount + 1 --fixcount++; fixcount = fixcount + 1 --fixcount++;
else else
----out << "could not change ownership for item!" << endl; ----out << "could not change ownership for item!" << endl;
print("Makeown: could not change ownership for an item!") print("Makeown: could not change ownership for an item!")
end end
end end
end end
end end
-- clear uniform_drop (without this they would drop their clothes and pick them up some time later) -- clear uniform_drop (without this they would drop their clothes and pick them up some time later)
-- dirty? -- dirty?
unit.military.uniform_drop:resize(0) --unit->military.uniform_drop.clear(); unit.military.uniform_drop:resize(0) --unit->military.uniform_drop.clear();
----out << "ownership for " << fixcount << " clothes fixed" << endl; ----out << "ownership for " << fixcount << " clothes fixed" << endl;
print("Makeown: claimed ownership for "..tostring(fixcount).." worn items") print("Makeown: claimed ownership for "..tostring(fixcount).." worn items")
--return true --return CR_OK; --return true --return CR_OK;
end end
local function entity_link(hf, eid, do_event, add, replace_idx) local function entity_link(hf, eid, do_event, add, replace_idx)
do_event = (do_event == nil) and true or do_event do_event = (do_event == nil) and true or do_event
add = (add == nil) and true or add add = (add == nil) and true or add
replace_idx = replace_idx or -1 replace_idx = replace_idx or -1
local link = add and df.histfig_entity_link_memberst:new() or df.histfig_entity_link_former_memberst:new() local link = add and df.histfig_entity_link_memberst:new() or df.histfig_entity_link_former_memberst:new()
link.entity_id = eid link.entity_id = eid
if replace_idx > -1 then if replace_idx > -1 then
local e = hf.entity_links[replace_idx] local e = hf.entity_links[replace_idx]
link.link_strength = (e.link_strength > 3) and (e.link_strength - 2) or e.link_strength link.link_strength = (e.link_strength > 3) and (e.link_strength - 2) or e.link_strength
hf.entity_links[replace_idx] = link -- replace member link with former member link hf.entity_links[replace_idx] = link -- replace member link with former member link
e:delete() e:delete()
else else
link.link_strength = 100 link.link_strength = 100
hf.entity_links:insert('#', link) hf.entity_links:insert('#', link)
end end
if do_event then if do_event then
event = add and df.history_event_add_hf_entity_linkst:new() or df.history_event_remove_hf_entity_linkst:new() event = add and df.history_event_add_hf_entity_linkst:new() or df.history_event_remove_hf_entity_linkst:new()
event.year = df.global.cur_year event.year = df.global.cur_year
event.seconds = df.global.cur_year_tick event.seconds = df.global.cur_year_tick
event.civ = eid event.civ = eid
event.histfig = hf.id event.histfig = hf.id
event.link_type = 0 event.link_type = 0
event.position_id = -1 event.position_id = -1
event.id = df.global.hist_event_next_id event.id = df.global.hist_event_next_id
df.global.world.history.events:insert('#',event) df.global.world.history.events:insert('#',event)
df.global.hist_event_next_id = df.global.hist_event_next_id + 1 df.global.hist_event_next_id = df.global.hist_event_next_id + 1
end end
end end
local function change_state(hf, site_id, pos) local function change_state(hf, site_id, pos)
hf.info.unk_14.unk_0 = 3 -- state? arrived? hf.info.unk_14.unk_0 = 3 -- state? arrived?
hf.info.unk_14.region:assign(pos) hf.info.unk_14.region:assign(pos)
hf.info.unk_14.site = site_id hf.info.unk_14.site = site_id
event = df.history_event_change_hf_statest:new() event = df.history_event_change_hf_statest:new()
event.year = df.global.cur_year event.year = df.global.cur_year
event.seconds = df.global.cur_year_tick event.seconds = df.global.cur_year_tick
event.hfid = hf.id event.hfid = hf.id
event.state = 3 event.state = 3
event.site = site_id event.site = site_id
event.region_pos:assign(pos) event.region_pos:assign(pos)
event.substate = -1; event.region = -1; event.layer = -1; event.substate = -1; event.region = -1; event.layer = -1;
event.id = df.global.hist_event_next_id event.id = df.global.hist_event_next_id
df.global.world.history.events:insert('#',event) df.global.world.history.events:insert('#',event)
df.global.hist_event_next_id = df.global.hist_event_next_id + 1 df.global.hist_event_next_id = df.global.hist_event_next_id + 1
end end
function make_citizen(unit) function make_citizen(unit)
local dfg = df.global local dfg = df.global
local civ_id = dfg.ui.civ_id local civ_id = dfg.ui.civ_id
local group_id = dfg.ui.group_id local group_id = dfg.ui.group_id
local events = dfg.world.history.events local events = dfg.world.history.events
local fortent = dfg.ui.main.fortress_entity local fortent = dfg.ui.main.fortress_entity
local civent = fortent and df.historical_entity.find(fortent.entity_links[0].target) local civent = fortent and df.historical_entity.find(fortent.entity_links[0].target)
-- utils.binsearch(dfg.world.entities.all, fortent.entity_links[0].target, 'id') -- utils.binsearch(dfg.world.entities.all, fortent.entity_links[0].target, 'id')
local event local event
local region_pos = df.world_site.find(dfg.ui.site_id).pos -- used with state events and hf state local region_pos = df.world_site.find(dfg.ui.site_id).pos -- used with state events and hf state
local hf local hf
-- assume that hf id 1 and hf id 2 are equal. I am unaware of instances of when they are not. -- assume that hf id 1 and hf id 2 are equal. I am unaware of instances of when they are not.
-- occationally a unit does not have both flags set (missing flags1.important_historical_figure) -- occationally a unit does not have both flags set (missing flags1.important_historical_figure)
-- and I don't know what that means yet. -- and I don't know what that means yet.
if unit.flags1.important_historical_figure and unit.flags2.important_historical_figure then if unit.flags1.important_historical_figure and unit.flags2.important_historical_figure then
-- aready hf, find it (unlikely to happen) -- aready hf, find it (unlikely to happen)
hf = utils.binsearch(dfg.world.history.figures, unit.hist_figure_id, 'id') hf = utils.binsearch(dfg.world.history.figures, unit.hist_figure_id, 'id')
--elseif unit.flags1.important_historical_figure or unit.flags2.important_historical_figure then --elseif unit.flags1.important_historical_figure or unit.flags2.important_historical_figure then
-- something wrong, try to fix it? -- something wrong, try to fix it?
--[[ --[[
if unit.hist_figure_id == -1 then if unit.hist_figure_id == -1 then
unit.hist_figure_id = unit.hist_figure_id2 unit.hist_figure_id = unit.hist_figure_id2
end end
if unit.hist_figure_id > -1 then if unit.hist_figure_id > -1 then
unit.hist_figure_id2 = unit.hist_figure_id unit.hist_figure_id2 = unit.hist_figure_id
unit.flags1.important_historical_figure = true unit.flags1.important_historical_figure = true
unit.flags2.important_historical_figure = true unit.flags2.important_historical_figure = true
hf = utils.binsearch(dfg.world.history.figures, unit.hist_figure_id, 'id') hf = utils.binsearch(dfg.world.history.figures, unit.hist_figure_id, 'id')
else else
unit.flags1.important_historical_figure = false unit.flags1.important_historical_figure = false
unit.flags2.important_historical_figure = false unit.flags2.important_historical_figure = false
end end
--]] --]]
--else --else
-- make one -- make one
end end
--local new_hf = false --local new_hf = false
if not hf then if not hf then
--new_hf = true --new_hf = true
hf = df.historical_figure:new() hf = df.historical_figure:new()
hf.profession = unit.profession hf.profession = unit.profession
hf.race = unit.race hf.race = unit.race
hf.caste = unit.caste hf.caste = unit.caste
hf.sex = unit.sex hf.sex = unit.sex
hf.appeared_year = dfg.cur_year hf.appeared_year = dfg.cur_year
hf.born_year = unit.relations.birth_year hf.born_year = unit.relations.birth_year
hf.born_seconds = unit.relations.birth_time hf.born_seconds = unit.relations.birth_time
hf.curse_year = unit.relations.curse_year hf.curse_year = unit.relations.curse_year
hf.curse_seconds = unit.relations.curse_time hf.curse_seconds = unit.relations.curse_time
hf.anon_1 = unit.relations.anon_2 hf.anon_1 = unit.relations.anon_2
hf.anon_2 = unit.relations.anon_3 hf.anon_2 = unit.relations.anon_3
hf.old_year = unit.relations.old_year hf.old_year = unit.relations.old_year
hf.old_seconds = unit.relations.old_time hf.old_seconds = unit.relations.old_time
hf.died_year = -1 hf.died_year = -1
hf.died_seconds = -1 hf.died_seconds = -1
hf.name:assign(unit.name) hf.name:assign(unit.name)
hf.civ_id = unit.civ_id hf.civ_id = unit.civ_id
hf.population_id = unit.population_id hf.population_id = unit.population_id
hf.breed_id = -1 hf.breed_id = -1
hf.unit_id = unit.id hf.unit_id = unit.id
hf.id = dfg.hist_figure_next_id -- id must be set before adding links (for the events) hf.id = dfg.hist_figure_next_id -- id must be set before adding links (for the events)
--history_event_add_hf_entity_linkst not reported for civ on starting 7 --history_event_add_hf_entity_linkst not reported for civ on starting 7
entity_link(hf, civ_id, false) -- so lets skip event here entity_link(hf, civ_id, false) -- so lets skip event here
entity_link(hf, group_id) entity_link(hf, group_id)
hf.info = df.historical_figure_info:new() hf.info = df.historical_figure_info:new()
hf.info.unk_14 = df.historical_figure_info.T_unk_14:new() -- hf state? hf.info.unk_14 = df.historical_figure_info.T_unk_14:new() -- hf state?
--unk_14.region_id = -1; unk_14.beast_id = -1; unk_14.unk_14 = 0 --unk_14.region_id = -1; unk_14.beast_id = -1; unk_14.unk_14 = 0
hf.info.unk_14.unk_18 = -1; hf.info.unk_14.unk_1c = -1 hf.info.unk_14.unk_18 = -1; hf.info.unk_14.unk_1c = -1
-- set values that seem related to state and do event -- set values that seem related to state and do event
change_state(hf, dfg.ui.site_id, region_pos) change_state(hf, dfg.ui.site_id, region_pos)
--lets skip skills for now --lets skip skills for now
--local skills = df.historical_figure_info.T_skills:new() -- skills snap shot --local skills = df.historical_figure_info.T_skills:new() -- skills snap shot
-- ... -- ...
--info.skills = skills --info.skills = skills
dfg.world.history.figures:insert('#', hf) dfg.world.history.figures:insert('#', hf)
dfg.hist_figure_next_id = dfg.hist_figure_next_id + 1 dfg.hist_figure_next_id = dfg.hist_figure_next_id + 1
--new_hf_loc = df.global.world.history.figures[#df.global.world.history.figures - 1] --new_hf_loc = df.global.world.history.figures[#df.global.world.history.figures - 1]
fortent.histfig_ids:insert('#', hf.id) fortent.histfig_ids:insert('#', hf.id)
fortent.hist_figures:insert('#', hf) fortent.hist_figures:insert('#', hf)
civent.histfig_ids:insert('#', hf.id) civent.histfig_ids:insert('#', hf.id)
civent.hist_figures:insert('#', hf) civent.hist_figures:insert('#', hf)
unit.flags1.important_historical_figure = true unit.flags1.important_historical_figure = true
unit.flags2.important_historical_figure = true unit.flags2.important_historical_figure = true
unit.hist_figure_id = hf.id unit.hist_figure_id = hf.id
unit.hist_figure_id2 = hf.id unit.hist_figure_id2 = hf.id
print("Makeown-citizen: created historical figure") print("Makeown-citizen: created historical figure")
else else
-- only insert into civ/fort if not already there -- only insert into civ/fort if not already there
-- Migrants change previous histfig_entity_link_memberst to histfig_entity_link_former_memberst -- Migrants change previous histfig_entity_link_memberst to histfig_entity_link_former_memberst
-- for group entities, add link_member for new group, and reports events for remove from group, -- for group entities, add link_member for new group, and reports events for remove from group,
-- remove from civ, change state, add civ, and add group -- remove from civ, change state, add civ, and add group
hf.civ_id = civ_id -- ensure current civ_id hf.civ_id = civ_id -- ensure current civ_id
local found_civlink = false local found_civlink = false
local found_fortlink = false local found_fortlink = false
local v = hf.entity_links local v = hf.entity_links
for k=#v-1,0,-1 do for k=#v-1,0,-1 do
if df.histfig_entity_link_memberst:is_instance(v[k]) then if df.histfig_entity_link_memberst:is_instance(v[k]) then
entity_link(hf, v[k].entity_id, true, false, k) entity_link(hf, v[k].entity_id, true, false, k)
end end
end end
if hf.info and hf.info.unk_14 then if hf.info and hf.info.unk_14 then
change_state(hf, dfg.ui.site_id, region_pos) change_state(hf, dfg.ui.site_id, region_pos)
-- leave info nil if not found for now -- leave info nil if not found for now
end end
if not found_civlink then entity_link(hf,civ_id) end if not found_civlink then entity_link(hf,civ_id) end
if not found_fortlink then entity_link(hf,group_id) end if not found_fortlink then entity_link(hf,group_id) end
--change entity_links --change entity_links
local found = false local found = false
for _,v in ipairs(civent.histfig_ids) do for _,v in ipairs(civent.histfig_ids) do
if v == hf.id then found = true; break end if v == hf.id then found = true; break end
end end
if not found then if not found then
civent.histfig_ids:insert('#', hf.id) civent.histfig_ids:insert('#', hf.id)
civent.hist_figures:insert('#', hf) civent.hist_figures:insert('#', hf)
end end
found = false found = false
for _,v in ipairs(fortent.histfig_ids) do for _,v in ipairs(fortent.histfig_ids) do
if v == hf.id then found = true; break end if v == hf.id then found = true; break end
end end
if not found then if not found then
fortent.histfig_ids:insert('#', hf.id) fortent.histfig_ids:insert('#', hf.id)
fortent.hist_figures:insert('#', hf) fortent.hist_figures:insert('#', hf)
end end
print("Makeown-citizen: migrated historical figure") print("Makeown-citizen: migrated historical figure")
end -- hf end -- hf
local nemesis = dfhack.units.getNemesis(unit) local nemesis = dfhack.units.getNemesis(unit)
if not nemesis then if not nemesis then
nemesis = df.nemesis_record:new() nemesis = df.nemesis_record:new()
nemesis.figure = hf nemesis.figure = hf
nemesis.unit = unit nemesis.unit = unit
nemesis.unit_id = unit.id nemesis.unit_id = unit.id
nemesis.save_file_id = civent.save_file_id nemesis.save_file_id = civent.save_file_id
nemesis.unk10, nemesis.unk11, nemesis.unk12 = -1, -1, -1 nemesis.unk10, nemesis.unk11, nemesis.unk12 = -1, -1, -1
--group_leader_id = -1 --group_leader_id = -1
nemesis.id = dfg.nemesis_next_id nemesis.id = dfg.nemesis_next_id
nemesis.member_idx = civent.next_member_idx nemesis.member_idx = civent.next_member_idx
civent.next_member_idx = civent.next_member_idx + 1 civent.next_member_idx = civent.next_member_idx + 1
dfg.world.nemesis.all:insert('#', nemesis) dfg.world.nemesis.all:insert('#', nemesis)
dfg.nemesis_next_id = dfg.nemesis_next_id + 1 dfg.nemesis_next_id = dfg.nemesis_next_id + 1
nemesis_link = df.general_ref_is_nemesisst:new() nemesis_link = df.general_ref_is_nemesisst:new()
nemesis_link.nemesis_id = nemesis.id nemesis_link.nemesis_id = nemesis.id
unit.general_refs:insert('#', nemesis_link) unit.general_refs:insert('#', nemesis_link)
--new_nemesis_loc = df.global.world.nemesis.all[#df.global.world.nemesis.all - 1] --new_nemesis_loc = df.global.world.nemesis.all[#df.global.world.nemesis.all - 1]
fortent.nemesis_ids:insert('#', nemesis.id) fortent.nemesis_ids:insert('#', nemesis.id)
fortent.nemesis:insert('#', nemesis) fortent.nemesis:insert('#', nemesis)
civent.nemesis_ids:insert('#', nemesis.id) civent.nemesis_ids:insert('#', nemesis.id)
civent.nemesis:insert('#', nemesis) civent.nemesis:insert('#', nemesis)
print("Makeown-citizen: created nemesis entry") print("Makeown-citizen: created nemesis entry")
else-- only insert into civ/fort if not already there else-- only insert into civ/fort if not already there
local found = false local found = false
for _,v in ipairs(civent.nemesis_ids) do for _,v in ipairs(civent.nemesis_ids) do
if v == nemesis.id then found = true; break end if v == nemesis.id then found = true; break end
end end
if not found then if not found then
civent.nemesis_ids:insert('#', nemesis.id) civent.nemesis_ids:insert('#', nemesis.id)
civent.nemesis:insert('#', nemesis) civent.nemesis:insert('#', nemesis)
end end
found = false found = false
for _,v in ipairs(fortent.nemesis_ids) do for _,v in ipairs(fortent.nemesis_ids) do
if v == nemesis.id then found = true; break end if v == nemesis.id then found = true; break end
end end
if not found then if not found then
fortent.nemesis_ids:insert('#', nemesis.id) fortent.nemesis_ids:insert('#', nemesis.id)
fortent.nemesis:insert('#', nemesis) fortent.nemesis:insert('#', nemesis)
end end
print("Makeown-citizen: migrated nemesis entry") print("Makeown-citizen: migrated nemesis entry")
end -- nemesis end -- nemesis
end end
function make_own(unit) function make_own(unit)
--tweak makeown --tweak makeown
unit.flags2.resident = false; unit.flags1.merchant = false; unit.flags1.forest = false; unit.flags2.resident = false; unit.flags1.merchant = false; unit.flags1.forest = false;
unit.civ_id = df.global.ui.civ_id unit.civ_id = df.global.ui.civ_id
if unit.profession == df.profession.MERCHANT then unit.profession = df.profession.TRADER end if unit.profession == df.profession.MERCHANT then unit.profession = df.profession.TRADER end
if unit.profession2 == df.profession.MERCHANT then unit.profession2 = df.profession.TRADER end if unit.profession2 == df.profession.MERCHANT then unit.profession2 = df.profession.TRADER end
fix_clothing_ownership(unit) fix_clothing_ownership(unit)
if unit.race == df.global.ui.race_id then if unit.race == df.global.ui.race_id then
make_citizen(unit) make_citizen(unit)
end end
end end

@ -1616,12 +1616,12 @@ std::string Units::getCasteProfessionName(int race, int casteid, df::profession
{ {
std::string prof, race_prefix; std::string prof, race_prefix;
if (pid < (df::profession)0 || !is_valid_enum_item(pid)) if (pid < (df::profession)0 || !is_valid_enum_item(pid))
return ""; return "";
int16_t current_race = df::global::ui->race_id; int16_t current_race = df::global::ui->race_id;
if (df::global::gamemode && *df::global::gamemode == df::game_mode::ADVENTURE) if (df::global::gamemode && *df::global::gamemode == df::game_mode::ADVENTURE)
current_race = world->units.active[0]->race; current_race = world->units.active[0]->race;
bool use_race_prefix = (race >= 0 && race != current_race); bool use_race_prefix = (race >= 0 && race != current_race);
if (auto creature = df::creature_raw::find(race)) if (auto creature = df::creature_raw::find(race))
{ {

@ -9,29 +9,29 @@
class Hexsearch class Hexsearch
{ {
public: public:
typedef std::vector<int> SearchArgType; typedef std::vector<int> SearchArgType;
enum SearchConst //TODO add more enum SearchConst //TODO add more
{ {
ANYBYTE=0x101,DWORD_,ANYDWORD,ADDRESS ANYBYTE=0x101,DWORD_,ANYDWORD,ADDRESS
}; };
Hexsearch(const SearchArgType &args,char * startpos,char * endpos); Hexsearch(const SearchArgType &args,char * startpos,char * endpos);
~Hexsearch(); ~Hexsearch();
void Reset(){pos_=startpos_;}; void Reset(){pos_=startpos_;};
void SetStart(char * pos){pos_=pos;}; void SetStart(char * pos){pos_=pos;};
void * FindNext(); void * FindNext();
std::vector<void *> FindAll(); std::vector<void *> FindAll();
private: private:
bool Compare(int a,int b); bool Compare(int a,int b);
void ReparseArgs(); void ReparseArgs();
SearchArgType args_; SearchArgType args_;
char * pos_,* startpos_,* endpos_; char * pos_,* startpos_,* endpos_;
std::vector<int> BadCharShifts,GoodSuffixShift; std::vector<int> BadCharShifts,GoodSuffixShift;
void PrepareGoodSuffixTable(); void PrepareGoodSuffixTable();
void PrepareBadCharShift(); void PrepareBadCharShift();
}; };
#endif #endif

@ -11,19 +11,19 @@ namespace lua
class Hexsearch class Hexsearch
{ {
int tblid; int tblid;
::Hexsearch *p; ::Hexsearch *p;
public: public:
Hexsearch(lua_State *L,int id); Hexsearch(lua_State *L,int id);
~Hexsearch(); ~Hexsearch();
int GetTableId(){return tblid;}; int GetTableId(){return tblid;};
int find(lua_State *L); int find(lua_State *L);
int findall(lua_State *L); int findall(lua_State *L);
int reset(lua_State *L); int reset(lua_State *L);
DEF_LUNE(Hexsearch); DEF_LUNE(Hexsearch);
}; };
void RegisterHexsearch(lua::state &st); void RegisterHexsearch(lua::state &st);

@ -18,25 +18,25 @@ class PlugManager
{ {
public: public:
mapPlugs GetList(){return plugs;}; mapPlugs GetList(){return plugs;};
uint32_t AddNewPlug(std::string name,uint32_t size,uint32_t loc=0); uint32_t AddNewPlug(std::string name,uint32_t size,uint32_t loc=0);
uint32_t FindPlugin(std::string name); uint32_t FindPlugin(std::string name);
static PlugManager &GetInst() static PlugManager &GetInst()
{ {
void *p; void *p;
p=DFHack::Core::getInstance().GetData("dfusion_manager"); p=DFHack::Core::getInstance().GetData("dfusion_manager");
if(p==0) if(p==0)
{ {
p=new PlugManager; p=new PlugManager;
DFHack::Core::getInstance().RegisterData(p,"dfusion_manager"); DFHack::Core::getInstance().RegisterData(p,"dfusion_manager");
} }
return *static_cast<PlugManager*>(p); return *static_cast<PlugManager*>(p);
}; };
protected: protected:
private: private:
PlugManager(){}; PlugManager(){};
mapPlugs plugs; mapPlugs plugs;
}; };
void RegisterMisc(lua::state &st); void RegisterMisc(lua::state &st);

@ -16,7 +16,7 @@ using std::string;
namespace lua namespace lua
{ {
//global lua state singleton //global lua state singleton
class glua class glua
{ {
public: public:
@ -26,13 +26,13 @@ namespace lua
static glua *ptr; static glua *ptr;
state mystate; state mystate;
}; };
//registers basic lua commands //registers basic lua commands
void RegBasics(lua::state &L); void RegBasics(lua::state &L);
//dumps lua function trace, useless unless called from lua. //dumps lua function trace, useless unless called from lua.
string DebugDump(lua::state &L); string DebugDump(lua::state &L);
//register functions, first registers into global scope, second into current table //register functions, first registers into global scope, second into current table
void RegFunctions(lua::state &L,luaL_Reg const *arr); void RegFunctions(lua::state &L,luaL_Reg const *arr);
void RegFunctionsLocal(lua::state &L,luaL_Reg const *arr); void RegFunctionsLocal(lua::state &L,luaL_Reg const *arr);
} }

@ -3,7 +3,7 @@
Hexsearch::Hexsearch(const SearchArgType &args,char * startpos,char * endpos):args_(args),pos_(startpos),startpos_(startpos),endpos_(endpos) Hexsearch::Hexsearch(const SearchArgType &args,char * startpos,char * endpos):args_(args),pos_(startpos),startpos_(startpos),endpos_(endpos)
{ {
ReparseArgs(); ReparseArgs();
} }
Hexsearch::~Hexsearch() Hexsearch::~Hexsearch()
{ {
@ -11,106 +11,106 @@ Hexsearch::~Hexsearch()
} }
inline bool Hexsearch::Compare(int a,int b) inline bool Hexsearch::Compare(int a,int b)
{ {
if(b==Hexsearch::ANYBYTE) if(b==Hexsearch::ANYBYTE)
return true; return true;
if(a==b) if(a==b)
return true; return true;
return false; return false;
} }
void Hexsearch::ReparseArgs() void Hexsearch::ReparseArgs()
{ {
union union
{ {
uint32_t val; uint32_t val;
uint8_t bytes[4]; uint8_t bytes[4];
}B; }B;
SearchArgType targ; SearchArgType targ;
targ=args_; targ=args_;
args_.clear(); args_.clear();
for(size_t i=0;i<targ.size();) for(size_t i=0;i<targ.size();)
{ {
if(targ[i]==DWORD_) if(targ[i]==DWORD_)
{ {
i++; i++;
B.val=targ[i]; B.val=targ[i];
for(int j=0;j<4;j++) for(int j=0;j<4;j++)
{ {
args_.push_back(B.bytes[j]); args_.push_back(B.bytes[j]);
} }
i++; i++;
} }
else if (targ[i]==ANYDWORD) else if (targ[i]==ANYDWORD)
{ {
i++; i++;
for(int j=0;j<4;j++) for(int j=0;j<4;j++)
args_.push_back(ANYBYTE); args_.push_back(ANYBYTE);
} }
else else
{ {
args_.push_back(targ[i]); args_.push_back(targ[i]);
i++; i++;
} }
} }
} }
void * Hexsearch::FindNext() //TODO rewrite using Boyer-Moore algorithm void * Hexsearch::FindNext() //TODO rewrite using Boyer-Moore algorithm
{ {
DFHack::Core &inst=DFHack::Core::getInstance(); DFHack::Core &inst=DFHack::Core::getInstance();
DFHack::Process *p=inst.p; DFHack::Process *p=inst.p;
uint8_t *buf; uint8_t *buf;
buf=new uint8_t[args_.size()]; buf=new uint8_t[args_.size()];
while(pos_<endpos_) while(pos_<endpos_)
{ {
bool found=true; bool found=true;
p->readByte(pos_,buf[0]); p->readByte(pos_,buf[0]);
if(Compare(buf[0],args_[0])) if(Compare(buf[0],args_[0]))
{ {
p->read(pos_,args_.size(),buf); p->read(pos_,args_.size(),buf);
for(size_t i=0;i<args_.size();i++) for(size_t i=0;i<args_.size();i++)
{ {
if(!Compare(buf[i],args_[i])) if(!Compare(buf[i],args_[i]))
{ {
pos_+=i; pos_+=i;
found=false; found=false;
break; break;
} }
} }
if(found) if(found)
{ {
pos_+=args_.size(); pos_+=args_.size();
delete [] buf; delete [] buf;
return pos_-args_.size(); return pos_-args_.size();
} }
} }
pos_ = pos_ + 1; pos_ = pos_ + 1;
} }
delete [] buf; delete [] buf;
return 0; return 0;
} }
std::vector<void *> Hexsearch::FindAll() std::vector<void *> Hexsearch::FindAll()
{ {
std::vector<void *> ret; std::vector<void *> ret;
void * cpos=pos_; void * cpos=pos_;
while(cpos!=0) while(cpos!=0)
{ {
cpos=FindNext(); cpos=FindNext();
if(cpos!=0) if(cpos!=0)
ret.push_back(cpos); ret.push_back(cpos);
} }
return ret; return ret;
} }
void Hexsearch::PrepareBadCharShift() void Hexsearch::PrepareBadCharShift()
{ {
BadCharShifts.resize(256,-1); BadCharShifts.resize(256,-1);
int i=0; int i=0;
for(SearchArgType::reverse_iterator it=args_.rbegin();it!=args_.rend();it++) for(SearchArgType::reverse_iterator it=args_.rbegin();it!=args_.rend();it++)
{ {
BadCharShifts[*it]=i; BadCharShifts[*it]=i;
i++; i++;
} }
} }
void Hexsearch::PrepareGoodSuffixTable() void Hexsearch::PrepareGoodSuffixTable()
{ {
GoodSuffixShift.resize(args_.size()+1,0); GoodSuffixShift.resize(args_.size()+1,0);
} }

@ -2,60 +2,60 @@
int lua::Hexsearch::find(lua_State *L) int lua::Hexsearch::find(lua_State *L)
{ {
lua::state st(L); lua::state st(L);
void * pos=p->FindNext(); void * pos=p->FindNext();
st.push(reinterpret_cast<size_t>(pos)); st.push(reinterpret_cast<size_t>(pos));
return 1; return 1;
} }
int lua::Hexsearch::findall(lua_State *L) int lua::Hexsearch::findall(lua_State *L)
{ {
lua::state st(L); lua::state st(L);
std::vector<void *> pos=p->FindAll(); std::vector<void *> pos=p->FindAll();
st.newtable(); st.newtable();
for(unsigned i=0;i<pos.size();i++) for(unsigned i=0;i<pos.size();i++)
{ {
st.push(i+1); st.push(i+1);
st.push(reinterpret_cast<size_t>(pos[i])); st.push(reinterpret_cast<size_t>(pos[i]));
st.settable(); st.settable();
} }
return 1; return 1;
} }
lua::Hexsearch::Hexsearch(lua_State *L,int id):tblid(id) lua::Hexsearch::Hexsearch(lua_State *L,int id):tblid(id)
{ {
lua::state st(L); lua::state st(L);
char * start,* end; char * start,* end;
::Hexsearch::SearchArgType args; ::Hexsearch::SearchArgType args;
start= (char *)st.as<uint32_t>(1); start= (char *)st.as<uint32_t>(1);
end=(char *)st.as<uint32_t>(2); end=(char *)st.as<uint32_t>(2);
for(int i=3;i<=st.gettop();i++) for(int i=3;i<=st.gettop();i++)
{ {
args.push_back(st.as<int>(i)); args.push_back(st.as<int>(i));
} }
p=new ::Hexsearch(args,start,end); p=new ::Hexsearch(args,start,end);
} }
lua::Hexsearch::~Hexsearch() lua::Hexsearch::~Hexsearch()
{ {
delete p; delete p;
} }
int lua::Hexsearch::reset(lua_State *L) int lua::Hexsearch::reset(lua_State *L)
{ {
lua::state st(L); lua::state st(L);
p->Reset(); p->Reset();
return 0; return 0;
} }
IMP_LUNE(lua::Hexsearch,hexsearch); IMP_LUNE(lua::Hexsearch,hexsearch);
LUNE_METHODS_START(lua::Hexsearch) LUNE_METHODS_START(lua::Hexsearch)
method(lua::Hexsearch,find), method(lua::Hexsearch,find),
method(lua::Hexsearch,findall), method(lua::Hexsearch,findall),
method(lua::Hexsearch,reset), method(lua::Hexsearch,reset),
LUNE_METHODS_END(); LUNE_METHODS_END();
#define __ADDCONST(name) st.push(::Hexsearch:: name); st.setglobal(#name) #define __ADDCONST(name) st.push(::Hexsearch:: name); st.setglobal(#name)
void lua::RegisterHexsearch(lua::state &st) void lua::RegisterHexsearch(lua::state &st)
{ {
Lune<lua::Hexsearch>::Register(st); Lune<lua::Hexsearch>::Register(st);
__ADDCONST(ANYBYTE); __ADDCONST(ANYBYTE);
__ADDCONST(ANYDWORD); __ADDCONST(ANYDWORD);
__ADDCONST(DWORD_); __ADDCONST(DWORD_);
} }
#undef __ADDCONST #undef __ADDCONST

@ -1,21 +1,21 @@
#include "lua_Misc.h" #include "lua_Misc.h"
uint32_t lua::PlugManager::AddNewPlug(std::string name,uint32_t size,uint32_t loc) uint32_t lua::PlugManager::AddNewPlug(std::string name,uint32_t size,uint32_t loc)
{ {
void *p; void *p;
if(size!=0) if(size!=0)
p=new unsigned char[size]; p=new unsigned char[size];
else else
p=(void*)loc; p=(void*)loc;
plugs[name]=p; plugs[name]=p;
return (uint32_t)p; return (uint32_t)p;
} }
uint32_t lua::PlugManager::FindPlugin(std::string name) uint32_t lua::PlugManager::FindPlugin(std::string name)
{ {
mapPlugs::iterator it=plugs.find(name); mapPlugs::iterator it=plugs.find(name);
if(it!=plugs.end()) if(it!=plugs.end())
return (uint32_t)it->second; return (uint32_t)it->second;
else else
return 0; return 0;
} }
@ -24,10 +24,10 @@ static int LoadMod(lua_State *L)
lua::state st(L); lua::state st(L);
std::string modfile=st.as<std::string>(1); std::string modfile=st.as<std::string>(1);
std::string modname=st.as<std::string>(2); std::string modname=st.as<std::string>(2);
uint32_t size_add=st.as<uint32_t>(0,3); uint32_t size_add=st.as<uint32_t>(0,3);
OutFile::File f(modfile); OutFile::File f(modfile);
uint32_t size=f.GetTextSize(); uint32_t size=f.GetTextSize();
uint32_t pos=lua::PlugManager::GetInst().AddNewPlug(modname,size+size_add); uint32_t pos=lua::PlugManager::GetInst().AddNewPlug(modname,size+size_add);
char *buf; char *buf;
buf=new char[size]; buf=new char[size];
f.GetText(buf); f.GetText(buf);
@ -133,22 +133,22 @@ static int GetMod(lua_State *L)
const luaL_Reg lua_misc_func[]= const luaL_Reg lua_misc_func[]=
{ {
{"loadmod",LoadMod}, {"loadmod",LoadMod},
{"getmod",GetMod}, {"getmod",GetMod},
{"loadobj",LoadObj}, {"loadobj",LoadObj},
{"loadobjsymbols",LoadObjSymbols}, {"loadobjsymbols",LoadObjSymbols},
{"findmarker",FindMarker}, {"findmarker",FindMarker},
{"newmod",NewMod}, {"newmod",NewMod},
{NULL,NULL} {NULL,NULL}
}; };
void lua::RegisterMisc(lua::state &st) void lua::RegisterMisc(lua::state &st)
{ {
st.getglobal("engine"); st.getglobal("engine");
if(st.is<lua::nil>()) if(st.is<lua::nil>())
{ {
st.pop(); st.pop();
st.newtable(); st.newtable();
} }
lua::RegFunctionsLocal(st, lua_misc_func); lua::RegFunctionsLocal(st, lua_misc_func);
st.setglobal("engine"); st.setglobal("engine");
} }

@ -2,268 +2,268 @@
static DFHack::Process* GetProcessPtr(lua::state &st) static DFHack::Process* GetProcessPtr(lua::state &st)
{ {
return DFHack::Core::getInstance().p; return DFHack::Core::getInstance().p;
} }
static int lua_Process_readDWord(lua_State *S) static int lua_Process_readDWord(lua_State *S)
{ {
lua::state st(S); lua::state st(S);
DFHack::Process* c=GetProcessPtr(st); DFHack::Process* c=GetProcessPtr(st);
uint32_t ret=c->readDWord( (void *) st.as<uint32_t>(1)); uint32_t ret=c->readDWord( (void *) st.as<uint32_t>(1));
st.push(ret); st.push(ret);
return 1; return 1;
} }
static int lua_Process_writeDWord(lua_State *S) static int lua_Process_writeDWord(lua_State *S)
{ {
lua::state st(S); lua::state st(S);
DFHack::Process* c=GetProcessPtr(st); DFHack::Process* c=GetProcessPtr(st);
c->writeDWord((void *) st.as<uint32_t>(1),st.as<uint32_t>(2)); c->writeDWord((void *) st.as<uint32_t>(1),st.as<uint32_t>(2));
return 0; return 0;
} }
static int lua_Process_readFloat(lua_State *S) static int lua_Process_readFloat(lua_State *S)
{ {
lua::state st(S); lua::state st(S);
DFHack::Process* c=GetProcessPtr(st); DFHack::Process* c=GetProcessPtr(st);
float ret=c->readFloat((void *) st.as<uint32_t>(1)); float ret=c->readFloat((void *) st.as<uint32_t>(1));
st.push(ret); st.push(ret);
return 1; return 1;
} }
static int lua_Process_readWord(lua_State *S) static int lua_Process_readWord(lua_State *S)
{ {
lua::state st(S); lua::state st(S);
DFHack::Process* c=GetProcessPtr(st); DFHack::Process* c=GetProcessPtr(st);
uint16_t ret=c->readWord((void *) st.as<uint32_t>(1)); uint16_t ret=c->readWord((void *) st.as<uint32_t>(1));
st.push(ret); st.push(ret);
return 1; return 1;
} }
static int lua_Process_writeWord(lua_State *S) static int lua_Process_writeWord(lua_State *S)
{ {
lua::state st(S); lua::state st(S);
DFHack::Process* c=GetProcessPtr(st); DFHack::Process* c=GetProcessPtr(st);
c->writeWord((void *) st.as<uint32_t>(1),st.as<uint16_t>(2)); c->writeWord((void *) st.as<uint32_t>(1),st.as<uint16_t>(2));
return 0; return 0;
} }
static int lua_Process_readByte(lua_State *S) static int lua_Process_readByte(lua_State *S)
{ {
lua::state st(S); lua::state st(S);
DFHack::Process* c=GetProcessPtr(st); DFHack::Process* c=GetProcessPtr(st);
uint8_t ret=c->readByte((void *) st.as<uint32_t>(1)); uint8_t ret=c->readByte((void *) st.as<uint32_t>(1));
st.push(ret); st.push(ret);
return 1; return 1;
} }
static int lua_Process_writeByte(lua_State *S) static int lua_Process_writeByte(lua_State *S)
{ {
lua::state st(S); lua::state st(S);
DFHack::Process* c=GetProcessPtr(st); DFHack::Process* c=GetProcessPtr(st);
c->writeByte((void *) st.as<uint32_t>(1),st.as<uint8_t>(2)); c->writeByte((void *) st.as<uint32_t>(1),st.as<uint8_t>(2));
return 0; return 0;
} }
static int lua_Process_read(lua_State *S) static int lua_Process_read(lua_State *S)
{ {
lua::state st(S); lua::state st(S);
DFHack::Process* c=GetProcessPtr(st); DFHack::Process* c=GetProcessPtr(st);
size_t len=st.as<uint32_t>(2); size_t len=st.as<uint32_t>(2);
uint8_t* buf; uint8_t* buf;
if(!st.is<lua::nil>(3)) if(!st.is<lua::nil>(3))
buf=(uint8_t*)lua_touserdata(st,3); buf=(uint8_t*)lua_touserdata(st,3);
else else
buf=new uint8_t[len]; buf=new uint8_t[len];
c->read((void *) st.as<uint32_t>(1),len,buf); c->read((void *) st.as<uint32_t>(1),len,buf);
st.pushlightuserdata(buf); st.pushlightuserdata(buf);
return 1; return 1;
} }
static int lua_Process_write(lua_State *S) static int lua_Process_write(lua_State *S)
{ {
lua::state st(S); lua::state st(S);
DFHack::Process* c=GetProcessPtr(st); DFHack::Process* c=GetProcessPtr(st);
c-> write((void *) st.as<uint32_t>(1),st.as<uint32_t>(2),static_cast<uint8_t*>(lua_touserdata(st,3))); c-> write((void *) st.as<uint32_t>(1),st.as<uint32_t>(2),static_cast<uint8_t*>(lua_touserdata(st,3)));
return 0; return 0;
} }
static int lua_Process_readSTLString (lua_State *S) static int lua_Process_readSTLString (lua_State *S)
{ {
lua::state st(S); lua::state st(S);
DFHack::Process* c=GetProcessPtr(st); DFHack::Process* c=GetProcessPtr(st);
std::string r=c->readSTLString((void *) st.as<uint32_t>(1)); std::string r=c->readSTLString((void *) st.as<uint32_t>(1));
st.push(r); st.push(r);
return 1; return 1;
} }
static int lua_Process_writeSTLString(lua_State *S) static int lua_Process_writeSTLString(lua_State *S)
{ {
lua::state st(S); lua::state st(S);
DFHack::Process* c=GetProcessPtr(st); DFHack::Process* c=GetProcessPtr(st);
c->writeSTLString((void *) st.as<uint32_t>(1),st.as<std::string>(2)); c->writeSTLString((void *) st.as<uint32_t>(1),st.as<std::string>(2));
return 0; return 0;
} }
static int lua_Process_copySTLString(lua_State *S) static int lua_Process_copySTLString(lua_State *S)
{ {
lua::state st(S); lua::state st(S);
DFHack::Process* c=GetProcessPtr(st); DFHack::Process* c=GetProcessPtr(st);
c->copySTLString((void *) st.as<uint32_t>(1),st.as<uint32_t>(2)); c->copySTLString((void *) st.as<uint32_t>(1),st.as<uint32_t>(2));
return 0; return 0;
} }
static int lua_Process_doReadClassName(lua_State *S) static int lua_Process_doReadClassName(lua_State *S)
{ {
lua::state st(S); lua::state st(S);
DFHack::Process* c=GetProcessPtr(st); DFHack::Process* c=GetProcessPtr(st);
std::string r=c->doReadClassName((void*)st.as<size_t>(1)); std::string r=c->doReadClassName((void*)st.as<size_t>(1));
st.push(r); st.push(r);
return 1; return 1;
} }
static int lua_Process_readClassName(lua_State *S) static int lua_Process_readClassName(lua_State *S)
{ {
lua::state st(S); lua::state st(S);
DFHack::Process* c=GetProcessPtr(st); DFHack::Process* c=GetProcessPtr(st);
std::string r=c->readClassName((void*)st.as<size_t>(1)); std::string r=c->readClassName((void*)st.as<size_t>(1));
st.push(r); st.push(r);
return 1; return 1;
} }
static int lua_Process_readCString (lua_State *S) static int lua_Process_readCString (lua_State *S)
{ {
lua::state st(S); lua::state st(S);
DFHack::Process* c=GetProcessPtr(st); DFHack::Process* c=GetProcessPtr(st);
std::string r=c->readCString((void *) st.as<uint32_t>(1)); std::string r=c->readCString((void *) st.as<uint32_t>(1));
st.push(r); st.push(r);
return 1; return 1;
} }
static int lua_Process_isSuspended(lua_State *S) static int lua_Process_isSuspended(lua_State *S)
{ {
lua::state st(S); lua::state st(S);
DFHack::Process* c=GetProcessPtr(st); DFHack::Process* c=GetProcessPtr(st);
st.push(c->isSuspended()); st.push(c->isSuspended());
return 1; return 1;
} }
static int lua_Process_isIdentified(lua_State *S) static int lua_Process_isIdentified(lua_State *S)
{ {
lua::state st(S); lua::state st(S);
DFHack::Process* c=GetProcessPtr(st); DFHack::Process* c=GetProcessPtr(st);
st.push(c->isIdentified()); st.push(c->isIdentified());
return 1; return 1;
} }
static int lua_Process_getMemRanges(lua_State *S) static int lua_Process_getMemRanges(lua_State *S)
{ {
lua::state st(S); lua::state st(S);
DFHack::Process* c=GetProcessPtr(st); DFHack::Process* c=GetProcessPtr(st);
std::vector<DFHack::t_memrange> ranges; std::vector<DFHack::t_memrange> ranges;
c->getMemRanges(ranges); c->getMemRanges(ranges);
st.newtable(); st.newtable();
for(size_t i=0;i<ranges.size();i++) for(size_t i=0;i<ranges.size();i++)
{ {
st.push(i); st.push(i);
st.newtable(); st.newtable();
st.push((uint32_t)ranges[i].start); // WARNING!! lua has only 32bit numbers, possible loss of data!! st.push((uint32_t)ranges[i].start); // WARNING!! lua has only 32bit numbers, possible loss of data!!
st.setfield("start"); st.setfield("start");
st.push((uint32_t)ranges[i].end); st.push((uint32_t)ranges[i].end);
st.setfield("end"); st.setfield("end");
st.push(std::string(ranges[i].name)); st.push(std::string(ranges[i].name));
st.setfield("name"); st.setfield("name");
st.push(ranges[i].read); st.push(ranges[i].read);
st.setfield("read"); st.setfield("read");
st.push(ranges[i].write); st.push(ranges[i].write);
st.setfield("write"); st.setfield("write");
st.push(ranges[i].execute); st.push(ranges[i].execute);
st.setfield("execute"); st.setfield("execute");
st.push(ranges[i].shared); st.push(ranges[i].shared);
st.setfield("shared"); st.setfield("shared");
st.push(ranges[i].valid); st.push(ranges[i].valid);
st.setfield("valid"); st.setfield("valid");
st.settable(); st.settable();
} }
return 1; return 1;
} }
static int lua_Process_getBase(lua_State *S) static int lua_Process_getBase(lua_State *S)
{ {
lua::state st(S); lua::state st(S);
DFHack::Process* c=GetProcessPtr(st); DFHack::Process* c=GetProcessPtr(st);
uint32_t base=c->getBase(); uint32_t base=c->getBase();
st.push(base); st.push(base);
return 1; return 1;
} }
/*static int lua_Process_getPID(lua_State *S) /*static int lua_Process_getPID(lua_State *S)
{ {
lua::state st(S); lua::state st(S);
DFHack::Process* c=GetProcessPtr(st); DFHack::Process* c=GetProcessPtr(st);
int ret=c->getPID(); int ret=c->getPID();
st.push(ret); st.push(ret);
return 1; return 1;
}*/ }*/
static int lua_Process_getPath(lua_State *S) static int lua_Process_getPath(lua_State *S)
{ {
lua::state st(S); lua::state st(S);
DFHack::Process* c=GetProcessPtr(st); DFHack::Process* c=GetProcessPtr(st);
std::string ret=c->getPath(); std::string ret=c->getPath();
st.push(ret); st.push(ret);
return 1; return 1;
} }
static int lua_Process_setPermisions(lua_State *S) static int lua_Process_setPermisions(lua_State *S)
{ {
lua::state st(S); lua::state st(S);
DFHack::Process* c=GetProcessPtr(st); DFHack::Process* c=GetProcessPtr(st);
DFHack::t_memrange range,trange; DFHack::t_memrange range,trange;
st.getfield("start",1); st.getfield("start",1);
range.start= (void *)st.as<uint64_t>(); range.start= (void *)st.as<uint64_t>();
st.pop(); st.pop();
st.getfield("end",1); st.getfield("end",1);
range.end= (void *)st.as<uint64_t>(); range.end= (void *)st.as<uint64_t>();
st.pop(); st.pop();
st.getfield("read",2); st.getfield("read",2);
trange.read=st.as<bool>(); trange.read=st.as<bool>();
st.pop(); st.pop();
st.getfield("write",2); st.getfield("write",2);
trange.write=st.as<bool>(); trange.write=st.as<bool>();
st.pop(); st.pop();
st.getfield("execute",2); st.getfield("execute",2);
trange.execute=st.as<bool>(); trange.execute=st.as<bool>();
st.pop(); st.pop();
c->setPermisions(range,trange); c->setPermisions(range,trange);
return 0; return 0;
} }
#define PROC_FUNC(name) {#name,lua_Process_ ## name} #define PROC_FUNC(name) {#name,lua_Process_ ## name}
const luaL_Reg lua_process_func[]= const luaL_Reg lua_process_func[]=
{ {
PROC_FUNC(readDWord), PROC_FUNC(readDWord),
PROC_FUNC(writeDWord), PROC_FUNC(writeDWord),
PROC_FUNC(readFloat), PROC_FUNC(readFloat),
PROC_FUNC(readWord), PROC_FUNC(readWord),
PROC_FUNC(writeWord), PROC_FUNC(writeWord),
PROC_FUNC(readByte), PROC_FUNC(readByte),
PROC_FUNC(writeByte), PROC_FUNC(writeByte),
PROC_FUNC(read), PROC_FUNC(read),
PROC_FUNC(write), PROC_FUNC(write),
PROC_FUNC(readSTLString), PROC_FUNC(readSTLString),
PROC_FUNC(writeSTLString), PROC_FUNC(writeSTLString),
PROC_FUNC(copySTLString), PROC_FUNC(copySTLString),
PROC_FUNC(doReadClassName), PROC_FUNC(doReadClassName),
PROC_FUNC(readClassName), PROC_FUNC(readClassName),
PROC_FUNC(readCString ), PROC_FUNC(readCString ),
PROC_FUNC(isSuspended), PROC_FUNC(isSuspended),
PROC_FUNC(isIdentified), PROC_FUNC(isIdentified),
PROC_FUNC(getMemRanges), PROC_FUNC(getMemRanges),
PROC_FUNC(getBase), PROC_FUNC(getBase),
//PROC_FUNC(getPID), //not implemented //PROC_FUNC(getPID), //not implemented
PROC_FUNC(getPath), PROC_FUNC(getPath),
PROC_FUNC(setPermisions), PROC_FUNC(setPermisions),
{NULL,NULL} {NULL,NULL}
}; };
#undef PROC_FUNC #undef PROC_FUNC
void lua::RegisterProcess(lua::state &st) void lua::RegisterProcess(lua::state &st)
{ {
st.getglobal("Process"); st.getglobal("Process");
if(st.is<lua::nil>()) if(st.is<lua::nil>())
{ {
st.pop(); st.pop();
st.newtable(); st.newtable();
} }
lua::RegFunctionsLocal(st, lua_process_func); lua::RegFunctionsLocal(st, lua_process_func);
st.setglobal("Process"); st.setglobal("Process");
} }

File diff suppressed because it is too large Load Diff

@ -529,124 +529,124 @@ struct dwarf_info_t
static df::unit_labor hauling_labor_map[] = static df::unit_labor hauling_labor_map[] =
{ {
df::unit_labor::HAUL_ITEM, /* BAR */ df::unit_labor::HAUL_ITEM, /* BAR */
df::unit_labor::HAUL_STONE, /* SMALLGEM */ df::unit_labor::HAUL_STONE, /* SMALLGEM */
df::unit_labor::HAUL_ITEM, /* BLOCKS */ df::unit_labor::HAUL_ITEM, /* BLOCKS */
df::unit_labor::HAUL_STONE, /* ROUGH */ df::unit_labor::HAUL_STONE, /* ROUGH */
df::unit_labor::HAUL_STONE, /* BOULDER */ df::unit_labor::HAUL_STONE, /* BOULDER */
df::unit_labor::HAUL_WOOD, /* WOOD */ df::unit_labor::HAUL_WOOD, /* WOOD */
df::unit_labor::HAUL_FURNITURE, /* DOOR */ df::unit_labor::HAUL_FURNITURE, /* DOOR */
df::unit_labor::HAUL_FURNITURE, /* FLOODGATE */ df::unit_labor::HAUL_FURNITURE, /* FLOODGATE */
df::unit_labor::HAUL_FURNITURE, /* BED */ df::unit_labor::HAUL_FURNITURE, /* BED */
df::unit_labor::HAUL_FURNITURE, /* CHAIR */ df::unit_labor::HAUL_FURNITURE, /* CHAIR */
df::unit_labor::HAUL_ITEM, /* CHAIN */ df::unit_labor::HAUL_ITEM, /* CHAIN */
df::unit_labor::HAUL_ITEM, /* FLASK */ df::unit_labor::HAUL_ITEM, /* FLASK */
df::unit_labor::HAUL_ITEM, /* GOBLET */ df::unit_labor::HAUL_ITEM, /* GOBLET */
df::unit_labor::HAUL_ITEM, /* INSTRUMENT */ df::unit_labor::HAUL_ITEM, /* INSTRUMENT */
df::unit_labor::HAUL_ITEM, /* TOY */ df::unit_labor::HAUL_ITEM, /* TOY */
df::unit_labor::HAUL_FURNITURE, /* WINDOW */ df::unit_labor::HAUL_FURNITURE, /* WINDOW */
df::unit_labor::HAUL_ANIMAL, /* CAGE */ df::unit_labor::HAUL_ANIMAL, /* CAGE */
df::unit_labor::HAUL_ITEM, /* BARREL */ df::unit_labor::HAUL_ITEM, /* BARREL */
df::unit_labor::HAUL_ITEM, /* BUCKET */ df::unit_labor::HAUL_ITEM, /* BUCKET */
df::unit_labor::HAUL_ANIMAL, /* ANIMALTRAP */ df::unit_labor::HAUL_ANIMAL, /* ANIMALTRAP */
df::unit_labor::HAUL_FURNITURE, /* TABLE */ df::unit_labor::HAUL_FURNITURE, /* TABLE */
df::unit_labor::HAUL_FURNITURE, /* COFFIN */ df::unit_labor::HAUL_FURNITURE, /* COFFIN */
df::unit_labor::HAUL_FURNITURE, /* STATUE */ df::unit_labor::HAUL_FURNITURE, /* STATUE */
df::unit_labor::HAUL_REFUSE, /* CORPSE */ df::unit_labor::HAUL_REFUSE, /* CORPSE */
df::unit_labor::HAUL_ITEM, /* WEAPON */ df::unit_labor::HAUL_ITEM, /* WEAPON */
df::unit_labor::HAUL_ITEM, /* ARMOR */ df::unit_labor::HAUL_ITEM, /* ARMOR */
df::unit_labor::HAUL_ITEM, /* SHOES */ df::unit_labor::HAUL_ITEM, /* SHOES */
df::unit_labor::HAUL_ITEM, /* SHIELD */ df::unit_labor::HAUL_ITEM, /* SHIELD */
df::unit_labor::HAUL_ITEM, /* HELM */ df::unit_labor::HAUL_ITEM, /* HELM */
df::unit_labor::HAUL_ITEM, /* GLOVES */ df::unit_labor::HAUL_ITEM, /* GLOVES */
df::unit_labor::HAUL_FURNITURE, /* BOX */ df::unit_labor::HAUL_FURNITURE, /* BOX */
df::unit_labor::HAUL_ITEM, /* BIN */ df::unit_labor::HAUL_ITEM, /* BIN */
df::unit_labor::HAUL_FURNITURE, /* ARMORSTAND */ df::unit_labor::HAUL_FURNITURE, /* ARMORSTAND */
df::unit_labor::HAUL_FURNITURE, /* WEAPONRACK */ df::unit_labor::HAUL_FURNITURE, /* WEAPONRACK */
df::unit_labor::HAUL_FURNITURE, /* CABINET */ df::unit_labor::HAUL_FURNITURE, /* CABINET */
df::unit_labor::HAUL_ITEM, /* FIGURINE */ df::unit_labor::HAUL_ITEM, /* FIGURINE */
df::unit_labor::HAUL_ITEM, /* AMULET */ df::unit_labor::HAUL_ITEM, /* AMULET */
df::unit_labor::HAUL_ITEM, /* SCEPTER */ df::unit_labor::HAUL_ITEM, /* SCEPTER */
df::unit_labor::HAUL_ITEM, /* AMMO */ df::unit_labor::HAUL_ITEM, /* AMMO */
df::unit_labor::HAUL_ITEM, /* CROWN */ df::unit_labor::HAUL_ITEM, /* CROWN */
df::unit_labor::HAUL_ITEM, /* RING */ df::unit_labor::HAUL_ITEM, /* RING */
df::unit_labor::HAUL_ITEM, /* EARRING */ df::unit_labor::HAUL_ITEM, /* EARRING */
df::unit_labor::HAUL_ITEM, /* BRACELET */ df::unit_labor::HAUL_ITEM, /* BRACELET */
df::unit_labor::HAUL_ITEM, /* GEM */ df::unit_labor::HAUL_ITEM, /* GEM */
df::unit_labor::HAUL_FURNITURE, /* ANVIL */ df::unit_labor::HAUL_FURNITURE, /* ANVIL */
df::unit_labor::HAUL_REFUSE, /* CORPSEPIECE */ df::unit_labor::HAUL_REFUSE, /* CORPSEPIECE */
df::unit_labor::HAUL_REFUSE, /* REMAINS */ df::unit_labor::HAUL_REFUSE, /* REMAINS */
df::unit_labor::HAUL_FOOD, /* MEAT */ df::unit_labor::HAUL_FOOD, /* MEAT */
df::unit_labor::HAUL_FOOD, /* FISH */ df::unit_labor::HAUL_FOOD, /* FISH */
df::unit_labor::HAUL_FOOD, /* FISH_RAW */ df::unit_labor::HAUL_FOOD, /* FISH_RAW */
df::unit_labor::HAUL_REFUSE, /* VERMIN */ df::unit_labor::HAUL_REFUSE, /* VERMIN */
df::unit_labor::HAUL_ITEM, /* PET */ df::unit_labor::HAUL_ITEM, /* PET */
df::unit_labor::HAUL_FOOD, /* SEEDS */ df::unit_labor::HAUL_FOOD, /* SEEDS */
df::unit_labor::HAUL_FOOD, /* PLANT */ df::unit_labor::HAUL_FOOD, /* PLANT */
df::unit_labor::HAUL_ITEM, /* SKIN_TANNED */ df::unit_labor::HAUL_ITEM, /* SKIN_TANNED */
df::unit_labor::HAUL_FOOD, /* LEAVES */ df::unit_labor::HAUL_FOOD, /* LEAVES */
df::unit_labor::HAUL_ITEM, /* THREAD */ df::unit_labor::HAUL_ITEM, /* THREAD */
df::unit_labor::HAUL_ITEM, /* CLOTH */ df::unit_labor::HAUL_ITEM, /* CLOTH */
df::unit_labor::HAUL_ITEM, /* TOTEM */ df::unit_labor::HAUL_ITEM, /* TOTEM */
df::unit_labor::HAUL_ITEM, /* PANTS */ df::unit_labor::HAUL_ITEM, /* PANTS */
df::unit_labor::HAUL_ITEM, /* BACKPACK */ df::unit_labor::HAUL_ITEM, /* BACKPACK */
df::unit_labor::HAUL_ITEM, /* QUIVER */ df::unit_labor::HAUL_ITEM, /* QUIVER */
df::unit_labor::HAUL_FURNITURE, /* CATAPULTPARTS */ df::unit_labor::HAUL_FURNITURE, /* CATAPULTPARTS */
df::unit_labor::HAUL_FURNITURE, /* BALLISTAPARTS */ df::unit_labor::HAUL_FURNITURE, /* BALLISTAPARTS */
df::unit_labor::HAUL_FURNITURE, /* SIEGEAMMO */ df::unit_labor::HAUL_FURNITURE, /* SIEGEAMMO */
df::unit_labor::HAUL_FURNITURE, /* BALLISTAARROWHEAD */ df::unit_labor::HAUL_FURNITURE, /* BALLISTAARROWHEAD */
df::unit_labor::HAUL_FURNITURE, /* TRAPPARTS */ df::unit_labor::HAUL_FURNITURE, /* TRAPPARTS */
df::unit_labor::HAUL_FURNITURE, /* TRAPCOMP */ df::unit_labor::HAUL_FURNITURE, /* TRAPCOMP */
df::unit_labor::HAUL_FOOD, /* DRINK */ df::unit_labor::HAUL_FOOD, /* DRINK */
df::unit_labor::HAUL_FOOD, /* POWDER_MISC */ df::unit_labor::HAUL_FOOD, /* POWDER_MISC */
df::unit_labor::HAUL_FOOD, /* CHEESE */ df::unit_labor::HAUL_FOOD, /* CHEESE */
df::unit_labor::HAUL_FOOD, /* FOOD */ df::unit_labor::HAUL_FOOD, /* FOOD */
df::unit_labor::HAUL_FOOD, /* LIQUID_MISC */ df::unit_labor::HAUL_FOOD, /* LIQUID_MISC */
df::unit_labor::HAUL_ITEM, /* COIN */ df::unit_labor::HAUL_ITEM, /* COIN */
df::unit_labor::HAUL_FOOD, /* GLOB */ df::unit_labor::HAUL_FOOD, /* GLOB */
df::unit_labor::HAUL_STONE, /* ROCK */ df::unit_labor::HAUL_STONE, /* ROCK */
df::unit_labor::HAUL_FURNITURE, /* PIPE_SECTION */ df::unit_labor::HAUL_FURNITURE, /* PIPE_SECTION */
df::unit_labor::HAUL_FURNITURE, /* HATCH_COVER */ df::unit_labor::HAUL_FURNITURE, /* HATCH_COVER */
df::unit_labor::HAUL_FURNITURE, /* GRATE */ df::unit_labor::HAUL_FURNITURE, /* GRATE */
df::unit_labor::HAUL_FURNITURE, /* QUERN */ df::unit_labor::HAUL_FURNITURE, /* QUERN */
df::unit_labor::HAUL_FURNITURE, /* MILLSTONE */ df::unit_labor::HAUL_FURNITURE, /* MILLSTONE */
df::unit_labor::HAUL_ITEM, /* SPLINT */ df::unit_labor::HAUL_ITEM, /* SPLINT */
df::unit_labor::HAUL_ITEM, /* CRUTCH */ df::unit_labor::HAUL_ITEM, /* CRUTCH */
df::unit_labor::HAUL_FURNITURE, /* TRACTION_BENCH */ df::unit_labor::HAUL_FURNITURE, /* TRACTION_BENCH */
df::unit_labor::HAUL_ITEM, /* ORTHOPEDIC_CAST */ df::unit_labor::HAUL_ITEM, /* ORTHOPEDIC_CAST */
df::unit_labor::HAUL_ITEM, /* TOOL */ df::unit_labor::HAUL_ITEM, /* TOOL */
df::unit_labor::HAUL_FURNITURE, /* SLAB */ df::unit_labor::HAUL_FURNITURE, /* SLAB */
df::unit_labor::HAUL_FOOD, /* EGG */ df::unit_labor::HAUL_FOOD, /* EGG */
df::unit_labor::HAUL_ITEM, /* BOOK */ df::unit_labor::HAUL_ITEM, /* BOOK */
}; };
static df::unit_labor workshop_build_labor[] = static df::unit_labor workshop_build_labor[] =
{ {
/* Carpenters */ df::unit_labor::CARPENTER, /* Carpenters */ df::unit_labor::CARPENTER,
/* Farmers */ df::unit_labor::PROCESS_PLANT, /* Farmers */ df::unit_labor::PROCESS_PLANT,
/* Masons */ df::unit_labor::MASON, /* Masons */ df::unit_labor::MASON,
/* Craftsdwarfs */ df::unit_labor::STONE_CRAFT, /* Craftsdwarfs */ df::unit_labor::STONE_CRAFT,
/* Jewelers */ df::unit_labor::CUT_GEM, /* Jewelers */ df::unit_labor::CUT_GEM,
/* MetalsmithsForge */ df::unit_labor::METAL_CRAFT, /* MetalsmithsForge */ df::unit_labor::METAL_CRAFT,
/* MagmaForge */ df::unit_labor::METAL_CRAFT, /* MagmaForge */ df::unit_labor::METAL_CRAFT,
/* Bowyers */ df::unit_labor::BOWYER, /* Bowyers */ df::unit_labor::BOWYER,
/* Mechanics */ df::unit_labor::MECHANIC, /* Mechanics */ df::unit_labor::MECHANIC,
/* Siege */ df::unit_labor::SIEGECRAFT, /* Siege */ df::unit_labor::SIEGECRAFT,
/* Butchers */ df::unit_labor::BUTCHER, /* Butchers */ df::unit_labor::BUTCHER,
/* Leatherworks */ df::unit_labor::LEATHER, /* Leatherworks */ df::unit_labor::LEATHER,
/* Tanners */ df::unit_labor::TANNER, /* Tanners */ df::unit_labor::TANNER,
/* Clothiers */ df::unit_labor::CLOTHESMAKER, /* Clothiers */ df::unit_labor::CLOTHESMAKER,
/* Fishery */ df::unit_labor::CLEAN_FISH, /* Fishery */ df::unit_labor::CLEAN_FISH,
/* Still */ df::unit_labor::BREWER, /* Still */ df::unit_labor::BREWER,
/* Loom */ df::unit_labor::WEAVER, /* Loom */ df::unit_labor::WEAVER,
/* Quern */ df::unit_labor::MILLER, /* Quern */ df::unit_labor::MILLER,
/* Kennels */ df::unit_labor::ANIMALTRAIN, /* Kennels */ df::unit_labor::ANIMALTRAIN,
/* Kitchen */ df::unit_labor::COOK, /* Kitchen */ df::unit_labor::COOK,
/* Ashery */ df::unit_labor::LYE_MAKING, /* Ashery */ df::unit_labor::LYE_MAKING,
/* Dyers */ df::unit_labor::DYER, /* Dyers */ df::unit_labor::DYER,
/* Millstone */ df::unit_labor::MILLER, /* Millstone */ df::unit_labor::MILLER,
/* Custom */ df::unit_labor::NONE, /* Custom */ df::unit_labor::NONE,
/* Tool */ df::unit_labor::NONE /* Tool */ df::unit_labor::NONE
}; };
static df::building* get_building_from_job(df::job* j) static df::building* get_building_from_job(df::job* j)
@ -1090,7 +1090,7 @@ public:
JobLaborMapper() JobLaborMapper()
{ {
jlfunc* jlf_hauling = new jlfunc_hauling(); jlfunc* jlf_hauling = new jlfunc_hauling();
jlfunc* jlf_make_furniture = new jlfunc_make(df::unit_labor::FORGE_FURNITURE); jlfunc* jlf_make_furniture = new jlfunc_make(df::unit_labor::FORGE_FURNITURE);
jlfunc* jlf_make_object = new jlfunc_make(df::unit_labor::METAL_CRAFT); jlfunc* jlf_make_object = new jlfunc_make(df::unit_labor::METAL_CRAFT);
jlfunc* jlf_make_armor = new jlfunc_make(df::unit_labor::FORGE_ARMOR); jlfunc* jlf_make_armor = new jlfunc_make(df::unit_labor::FORGE_ARMOR);
@ -1098,236 +1098,236 @@ public:
jlfunc* jlf_no_labor = jlf_const(df::unit_labor::NONE); jlfunc* jlf_no_labor = jlf_const(df::unit_labor::NONE);
job_to_labor_table[df::job_type::CarveFortification] = jlf_const(df::unit_labor::DETAIL); job_to_labor_table[df::job_type::CarveFortification] = jlf_const(df::unit_labor::DETAIL);
job_to_labor_table[df::job_type::DetailWall] = jlf_const(df::unit_labor::DETAIL); job_to_labor_table[df::job_type::DetailWall] = jlf_const(df::unit_labor::DETAIL);
job_to_labor_table[df::job_type::DetailFloor] = jlf_const(df::unit_labor::DETAIL); job_to_labor_table[df::job_type::DetailFloor] = jlf_const(df::unit_labor::DETAIL);
job_to_labor_table[df::job_type::Dig] = jlf_const(df::unit_labor::MINE); job_to_labor_table[df::job_type::Dig] = jlf_const(df::unit_labor::MINE);
job_to_labor_table[df::job_type::CarveUpwardStaircase] = jlf_const(df::unit_labor::MINE); job_to_labor_table[df::job_type::CarveUpwardStaircase] = jlf_const(df::unit_labor::MINE);
job_to_labor_table[df::job_type::CarveDownwardStaircase] = jlf_const(df::unit_labor::MINE); job_to_labor_table[df::job_type::CarveDownwardStaircase] = jlf_const(df::unit_labor::MINE);
job_to_labor_table[df::job_type::CarveUpDownStaircase] = jlf_const(df::unit_labor::MINE); job_to_labor_table[df::job_type::CarveUpDownStaircase] = jlf_const(df::unit_labor::MINE);
job_to_labor_table[df::job_type::CarveRamp] = jlf_const(df::unit_labor::MINE); job_to_labor_table[df::job_type::CarveRamp] = jlf_const(df::unit_labor::MINE);
job_to_labor_table[df::job_type::DigChannel] = jlf_const(df::unit_labor::MINE); job_to_labor_table[df::job_type::DigChannel] = jlf_const(df::unit_labor::MINE);
job_to_labor_table[df::job_type::FellTree] = jlf_const(df::unit_labor::CUTWOOD); job_to_labor_table[df::job_type::FellTree] = jlf_const(df::unit_labor::CUTWOOD);
job_to_labor_table[df::job_type::GatherPlants] = jlf_const(df::unit_labor::HERBALIST); job_to_labor_table[df::job_type::GatherPlants] = jlf_const(df::unit_labor::HERBALIST);
job_to_labor_table[df::job_type::RemoveConstruction] = jlf_no_labor; job_to_labor_table[df::job_type::RemoveConstruction] = jlf_no_labor;
job_to_labor_table[df::job_type::CollectWebs] = jlf_const(df::unit_labor::WEAVER); job_to_labor_table[df::job_type::CollectWebs] = jlf_const(df::unit_labor::WEAVER);
job_to_labor_table[df::job_type::BringItemToDepot] = jlf_no_labor; job_to_labor_table[df::job_type::BringItemToDepot] = jlf_no_labor;
job_to_labor_table[df::job_type::BringItemToShop] = jlf_no_labor; job_to_labor_table[df::job_type::BringItemToShop] = jlf_no_labor;
job_to_labor_table[df::job_type::Eat] = jlf_no_labor; job_to_labor_table[df::job_type::Eat] = jlf_no_labor;
job_to_labor_table[df::job_type::GetProvisions] = jlf_no_labor; job_to_labor_table[df::job_type::GetProvisions] = jlf_no_labor;
job_to_labor_table[df::job_type::Drink] = jlf_no_labor; job_to_labor_table[df::job_type::Drink] = jlf_no_labor;
job_to_labor_table[df::job_type::Drink2] = jlf_no_labor; job_to_labor_table[df::job_type::Drink2] = jlf_no_labor;
job_to_labor_table[df::job_type::FillWaterskin] = jlf_no_labor; job_to_labor_table[df::job_type::FillWaterskin] = jlf_no_labor;
job_to_labor_table[df::job_type::FillWaterskin2] = jlf_no_labor; job_to_labor_table[df::job_type::FillWaterskin2] = jlf_no_labor;
job_to_labor_table[df::job_type::Sleep] = jlf_no_labor; job_to_labor_table[df::job_type::Sleep] = jlf_no_labor;
job_to_labor_table[df::job_type::CollectSand] = jlf_const(df::unit_labor::HAUL_ITEM); job_to_labor_table[df::job_type::CollectSand] = jlf_const(df::unit_labor::HAUL_ITEM);
job_to_labor_table[df::job_type::Fish] = jlf_const(df::unit_labor::FISH); job_to_labor_table[df::job_type::Fish] = jlf_const(df::unit_labor::FISH);
job_to_labor_table[df::job_type::Hunt] = jlf_const(df::unit_labor::HUNT); job_to_labor_table[df::job_type::Hunt] = jlf_const(df::unit_labor::HUNT);
job_to_labor_table[df::job_type::HuntVermin] = jlf_no_labor; job_to_labor_table[df::job_type::HuntVermin] = jlf_no_labor;
job_to_labor_table[df::job_type::Kidnap] = jlf_no_labor; job_to_labor_table[df::job_type::Kidnap] = jlf_no_labor;
job_to_labor_table[df::job_type::BeatCriminal] = jlf_no_labor; job_to_labor_table[df::job_type::BeatCriminal] = jlf_no_labor;
job_to_labor_table[df::job_type::StartingFistFight] = jlf_no_labor; job_to_labor_table[df::job_type::StartingFistFight] = jlf_no_labor;
job_to_labor_table[df::job_type::CollectTaxes] = jlf_no_labor; job_to_labor_table[df::job_type::CollectTaxes] = jlf_no_labor;
job_to_labor_table[df::job_type::GuardTaxCollector] = jlf_no_labor; job_to_labor_table[df::job_type::GuardTaxCollector] = jlf_no_labor;
job_to_labor_table[df::job_type::CatchLiveLandAnimal] = jlf_const(df::unit_labor::HUNT); job_to_labor_table[df::job_type::CatchLiveLandAnimal] = jlf_const(df::unit_labor::HUNT);
job_to_labor_table[df::job_type::CatchLiveFish] = jlf_const(df::unit_labor::FISH); job_to_labor_table[df::job_type::CatchLiveFish] = jlf_const(df::unit_labor::FISH);
job_to_labor_table[df::job_type::ReturnKill] = jlf_no_labor; job_to_labor_table[df::job_type::ReturnKill] = jlf_no_labor;
job_to_labor_table[df::job_type::CheckChest] = jlf_no_labor; job_to_labor_table[df::job_type::CheckChest] = jlf_no_labor;
job_to_labor_table[df::job_type::StoreOwnedItem] = jlf_no_labor; job_to_labor_table[df::job_type::StoreOwnedItem] = jlf_no_labor;
job_to_labor_table[df::job_type::PlaceItemInTomb] = jlf_const(df::unit_labor::HAUL_BODY); job_to_labor_table[df::job_type::PlaceItemInTomb] = jlf_const(df::unit_labor::HAUL_BODY);
job_to_labor_table[df::job_type::StoreItemInStockpile] = jlf_hauling; job_to_labor_table[df::job_type::StoreItemInStockpile] = jlf_hauling;
job_to_labor_table[df::job_type::StoreItemInBag] = jlf_hauling; job_to_labor_table[df::job_type::StoreItemInBag] = jlf_hauling;
job_to_labor_table[df::job_type::StoreItemInHospital] = jlf_hauling; job_to_labor_table[df::job_type::StoreItemInHospital] = jlf_hauling;
job_to_labor_table[df::job_type::StoreItemInChest] = jlf_hauling; job_to_labor_table[df::job_type::StoreItemInChest] = jlf_hauling;
job_to_labor_table[df::job_type::StoreItemInCabinet] = jlf_hauling; job_to_labor_table[df::job_type::StoreItemInCabinet] = jlf_hauling;
job_to_labor_table[df::job_type::StoreWeapon] = jlf_hauling; job_to_labor_table[df::job_type::StoreWeapon] = jlf_hauling;
job_to_labor_table[df::job_type::StoreArmor] = jlf_hauling; job_to_labor_table[df::job_type::StoreArmor] = jlf_hauling;
job_to_labor_table[df::job_type::StoreItemInBarrel] = jlf_hauling; job_to_labor_table[df::job_type::StoreItemInBarrel] = jlf_hauling;
job_to_labor_table[df::job_type::StoreItemInBin] = jlf_const(df::unit_labor::HAUL_ITEM); job_to_labor_table[df::job_type::StoreItemInBin] = jlf_const(df::unit_labor::HAUL_ITEM);
job_to_labor_table[df::job_type::SeekArtifact] = jlf_no_labor; job_to_labor_table[df::job_type::SeekArtifact] = jlf_no_labor;
job_to_labor_table[df::job_type::SeekInfant] = jlf_no_labor; job_to_labor_table[df::job_type::SeekInfant] = jlf_no_labor;
job_to_labor_table[df::job_type::AttendParty] = jlf_no_labor; job_to_labor_table[df::job_type::AttendParty] = jlf_no_labor;
job_to_labor_table[df::job_type::GoShopping] = jlf_no_labor; job_to_labor_table[df::job_type::GoShopping] = jlf_no_labor;
job_to_labor_table[df::job_type::GoShopping2] = jlf_no_labor; job_to_labor_table[df::job_type::GoShopping2] = jlf_no_labor;
job_to_labor_table[df::job_type::Clean] = jlf_const(df::unit_labor::CLEAN); job_to_labor_table[df::job_type::Clean] = jlf_const(df::unit_labor::CLEAN);
job_to_labor_table[df::job_type::Rest] = jlf_no_labor; job_to_labor_table[df::job_type::Rest] = jlf_no_labor;
job_to_labor_table[df::job_type::PickupEquipment] = jlf_no_labor; job_to_labor_table[df::job_type::PickupEquipment] = jlf_no_labor;
job_to_labor_table[df::job_type::DumpItem] = jlf_const(df::unit_labor::HAUL_REFUSE); job_to_labor_table[df::job_type::DumpItem] = jlf_const(df::unit_labor::HAUL_REFUSE);
job_to_labor_table[df::job_type::StrangeMoodCrafter] = jlf_no_labor; job_to_labor_table[df::job_type::StrangeMoodCrafter] = jlf_no_labor;
job_to_labor_table[df::job_type::StrangeMoodJeweller] = jlf_no_labor; job_to_labor_table[df::job_type::StrangeMoodJeweller] = jlf_no_labor;
job_to_labor_table[df::job_type::StrangeMoodForge] = jlf_no_labor; job_to_labor_table[df::job_type::StrangeMoodForge] = jlf_no_labor;
job_to_labor_table[df::job_type::StrangeMoodMagmaForge] = jlf_no_labor; job_to_labor_table[df::job_type::StrangeMoodMagmaForge] = jlf_no_labor;
job_to_labor_table[df::job_type::StrangeMoodBrooding] = jlf_no_labor; job_to_labor_table[df::job_type::StrangeMoodBrooding] = jlf_no_labor;
job_to_labor_table[df::job_type::StrangeMoodFell] = jlf_no_labor; job_to_labor_table[df::job_type::StrangeMoodFell] = jlf_no_labor;
job_to_labor_table[df::job_type::StrangeMoodCarpenter] = jlf_no_labor; job_to_labor_table[df::job_type::StrangeMoodCarpenter] = jlf_no_labor;
job_to_labor_table[df::job_type::StrangeMoodMason] = jlf_no_labor; job_to_labor_table[df::job_type::StrangeMoodMason] = jlf_no_labor;
job_to_labor_table[df::job_type::StrangeMoodBowyer] = jlf_no_labor; job_to_labor_table[df::job_type::StrangeMoodBowyer] = jlf_no_labor;
job_to_labor_table[df::job_type::StrangeMoodTanner] = jlf_no_labor; job_to_labor_table[df::job_type::StrangeMoodTanner] = jlf_no_labor;
job_to_labor_table[df::job_type::StrangeMoodWeaver] = jlf_no_labor; job_to_labor_table[df::job_type::StrangeMoodWeaver] = jlf_no_labor;
job_to_labor_table[df::job_type::StrangeMoodGlassmaker] = jlf_no_labor; job_to_labor_table[df::job_type::StrangeMoodGlassmaker] = jlf_no_labor;
job_to_labor_table[df::job_type::StrangeMoodMechanics] = jlf_no_labor; job_to_labor_table[df::job_type::StrangeMoodMechanics] = jlf_no_labor;
job_to_labor_table[df::job_type::ConstructBuilding] = new jlfunc_construct_bld(); job_to_labor_table[df::job_type::ConstructBuilding] = new jlfunc_construct_bld();
job_to_labor_table[df::job_type::ConstructDoor] = jlf_make_furniture; job_to_labor_table[df::job_type::ConstructDoor] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructFloodgate] = jlf_make_furniture; job_to_labor_table[df::job_type::ConstructFloodgate] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructBed] = jlf_make_furniture; job_to_labor_table[df::job_type::ConstructBed] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructThrone] = jlf_make_furniture; job_to_labor_table[df::job_type::ConstructThrone] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructCoffin] = jlf_make_furniture; job_to_labor_table[df::job_type::ConstructCoffin] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructTable] = jlf_make_furniture; job_to_labor_table[df::job_type::ConstructTable] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructChest] = jlf_make_furniture; job_to_labor_table[df::job_type::ConstructChest] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructBin] = jlf_make_furniture; job_to_labor_table[df::job_type::ConstructBin] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructArmorStand] = jlf_make_furniture; job_to_labor_table[df::job_type::ConstructArmorStand] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructWeaponRack] = jlf_make_furniture; job_to_labor_table[df::job_type::ConstructWeaponRack] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructCabinet] = jlf_make_furniture; job_to_labor_table[df::job_type::ConstructCabinet] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructStatue] = jlf_make_furniture; job_to_labor_table[df::job_type::ConstructStatue] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructBlocks] = jlf_make_furniture; job_to_labor_table[df::job_type::ConstructBlocks] = jlf_make_furniture;
job_to_labor_table[df::job_type::MakeRawGlass] = jlf_const(df::unit_labor::GLASSMAKER); job_to_labor_table[df::job_type::MakeRawGlass] = jlf_const(df::unit_labor::GLASSMAKER);
job_to_labor_table[df::job_type::MakeCrafts] = jlf_make_object; job_to_labor_table[df::job_type::MakeCrafts] = jlf_make_object;
job_to_labor_table[df::job_type::MintCoins] = jlf_const(df::unit_labor::METAL_CRAFT); job_to_labor_table[df::job_type::MintCoins] = jlf_const(df::unit_labor::METAL_CRAFT);
job_to_labor_table[df::job_type::CutGems] = jlf_const(df::unit_labor::CUT_GEM); job_to_labor_table[df::job_type::CutGems] = jlf_const(df::unit_labor::CUT_GEM);
job_to_labor_table[df::job_type::CutGlass] = jlf_const(df::unit_labor::CUT_GEM); job_to_labor_table[df::job_type::CutGlass] = jlf_const(df::unit_labor::CUT_GEM);
job_to_labor_table[df::job_type::EncrustWithGems] = jlf_const(df::unit_labor::ENCRUST_GEM); job_to_labor_table[df::job_type::EncrustWithGems] = jlf_const(df::unit_labor::ENCRUST_GEM);
job_to_labor_table[df::job_type::EncrustWithGlass] = jlf_const(df::unit_labor::ENCRUST_GEM); job_to_labor_table[df::job_type::EncrustWithGlass] = jlf_const(df::unit_labor::ENCRUST_GEM);
job_to_labor_table[df::job_type::DestroyBuilding] = new jlfunc_destroy_bld(); job_to_labor_table[df::job_type::DestroyBuilding] = new jlfunc_destroy_bld();
job_to_labor_table[df::job_type::SmeltOre] = jlf_const(df::unit_labor::SMELT); job_to_labor_table[df::job_type::SmeltOre] = jlf_const(df::unit_labor::SMELT);
job_to_labor_table[df::job_type::MeltMetalObject] = jlf_const(df::unit_labor::SMELT); job_to_labor_table[df::job_type::MeltMetalObject] = jlf_const(df::unit_labor::SMELT);
job_to_labor_table[df::job_type::ExtractMetalStrands] = jlf_const(df::unit_labor::EXTRACT_STRAND); job_to_labor_table[df::job_type::ExtractMetalStrands] = jlf_const(df::unit_labor::EXTRACT_STRAND);
job_to_labor_table[df::job_type::PlantSeeds] = jlf_const(df::unit_labor::PLANT); job_to_labor_table[df::job_type::PlantSeeds] = jlf_const(df::unit_labor::PLANT);
job_to_labor_table[df::job_type::HarvestPlants] = jlf_const(df::unit_labor::PLANT); job_to_labor_table[df::job_type::HarvestPlants] = jlf_const(df::unit_labor::PLANT);
job_to_labor_table[df::job_type::TrainHuntingAnimal] = jlf_const(df::unit_labor::ANIMALTRAIN); job_to_labor_table[df::job_type::TrainHuntingAnimal] = jlf_const(df::unit_labor::ANIMALTRAIN);
job_to_labor_table[df::job_type::TrainWarAnimal] = jlf_const(df::unit_labor::ANIMALTRAIN); job_to_labor_table[df::job_type::TrainWarAnimal] = jlf_const(df::unit_labor::ANIMALTRAIN);
job_to_labor_table[df::job_type::MakeWeapon] = jlf_make_weapon; job_to_labor_table[df::job_type::MakeWeapon] = jlf_make_weapon;
job_to_labor_table[df::job_type::ForgeAnvil] = jlf_make_furniture; job_to_labor_table[df::job_type::ForgeAnvil] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructCatapultParts] = jlf_const(df::unit_labor::SIEGECRAFT); job_to_labor_table[df::job_type::ConstructCatapultParts] = jlf_const(df::unit_labor::SIEGECRAFT);
job_to_labor_table[df::job_type::ConstructBallistaParts] = jlf_const(df::unit_labor::SIEGECRAFT); job_to_labor_table[df::job_type::ConstructBallistaParts] = jlf_const(df::unit_labor::SIEGECRAFT);
job_to_labor_table[df::job_type::MakeArmor] = jlf_make_armor; job_to_labor_table[df::job_type::MakeArmor] = jlf_make_armor;
job_to_labor_table[df::job_type::MakeHelm] = jlf_make_armor; job_to_labor_table[df::job_type::MakeHelm] = jlf_make_armor;
job_to_labor_table[df::job_type::MakePants] = jlf_make_armor; job_to_labor_table[df::job_type::MakePants] = jlf_make_armor;
job_to_labor_table[df::job_type::StudWith] = jlf_make_object; job_to_labor_table[df::job_type::StudWith] = jlf_make_object;
job_to_labor_table[df::job_type::ButcherAnimal] = jlf_const(df::unit_labor::BUTCHER); job_to_labor_table[df::job_type::ButcherAnimal] = jlf_const(df::unit_labor::BUTCHER);
job_to_labor_table[df::job_type::PrepareRawFish] = jlf_const(df::unit_labor::CLEAN_FISH); job_to_labor_table[df::job_type::PrepareRawFish] = jlf_const(df::unit_labor::CLEAN_FISH);
job_to_labor_table[df::job_type::MillPlants] = jlf_const(df::unit_labor::MILLER); job_to_labor_table[df::job_type::MillPlants] = jlf_const(df::unit_labor::MILLER);
job_to_labor_table[df::job_type::BaitTrap] = jlf_const(df::unit_labor::TRAPPER); job_to_labor_table[df::job_type::BaitTrap] = jlf_const(df::unit_labor::TRAPPER);
job_to_labor_table[df::job_type::MilkCreature] = jlf_const(df::unit_labor::MILK); job_to_labor_table[df::job_type::MilkCreature] = jlf_const(df::unit_labor::MILK);
job_to_labor_table[df::job_type::MakeCheese] = jlf_const(df::unit_labor::MAKE_CHEESE); job_to_labor_table[df::job_type::MakeCheese] = jlf_const(df::unit_labor::MAKE_CHEESE);
job_to_labor_table[df::job_type::ProcessPlants] = jlf_const(df::unit_labor::PROCESS_PLANT); job_to_labor_table[df::job_type::ProcessPlants] = jlf_const(df::unit_labor::PROCESS_PLANT);
job_to_labor_table[df::job_type::ProcessPlantsBag] = jlf_const(df::unit_labor::PROCESS_PLANT); job_to_labor_table[df::job_type::ProcessPlantsBag] = jlf_const(df::unit_labor::PROCESS_PLANT);
job_to_labor_table[df::job_type::ProcessPlantsVial] = jlf_const(df::unit_labor::PROCESS_PLANT); job_to_labor_table[df::job_type::ProcessPlantsVial] = jlf_const(df::unit_labor::PROCESS_PLANT);
job_to_labor_table[df::job_type::ProcessPlantsBarrel] = jlf_const(df::unit_labor::PROCESS_PLANT); job_to_labor_table[df::job_type::ProcessPlantsBarrel] = jlf_const(df::unit_labor::PROCESS_PLANT);
job_to_labor_table[df::job_type::PrepareMeal] = jlf_const(df::unit_labor::COOK); job_to_labor_table[df::job_type::PrepareMeal] = jlf_const(df::unit_labor::COOK);
job_to_labor_table[df::job_type::WeaveCloth] = jlf_const(df::unit_labor::WEAVER); job_to_labor_table[df::job_type::WeaveCloth] = jlf_const(df::unit_labor::WEAVER);
job_to_labor_table[df::job_type::MakeGloves] = jlf_make_armor; job_to_labor_table[df::job_type::MakeGloves] = jlf_make_armor;
job_to_labor_table[df::job_type::MakeShoes] = jlf_make_armor; job_to_labor_table[df::job_type::MakeShoes] = jlf_make_armor;
job_to_labor_table[df::job_type::MakeShield] = jlf_make_armor; job_to_labor_table[df::job_type::MakeShield] = jlf_make_armor;
job_to_labor_table[df::job_type::MakeCage] = jlf_make_furniture; job_to_labor_table[df::job_type::MakeCage] = jlf_make_furniture;
job_to_labor_table[df::job_type::MakeChain] = jlf_make_object; job_to_labor_table[df::job_type::MakeChain] = jlf_make_object;
job_to_labor_table[df::job_type::MakeFlask] = jlf_make_object; job_to_labor_table[df::job_type::MakeFlask] = jlf_make_object;
job_to_labor_table[df::job_type::MakeGoblet] = jlf_make_object; job_to_labor_table[df::job_type::MakeGoblet] = jlf_make_object;
job_to_labor_table[df::job_type::MakeInstrument] = jlf_make_object; job_to_labor_table[df::job_type::MakeInstrument] = jlf_make_object;
job_to_labor_table[df::job_type::MakeToy] = jlf_make_object; job_to_labor_table[df::job_type::MakeToy] = jlf_make_object;
job_to_labor_table[df::job_type::MakeAnimalTrap] = jlf_const(df::unit_labor::TRAPPER); job_to_labor_table[df::job_type::MakeAnimalTrap] = jlf_const(df::unit_labor::TRAPPER);
job_to_labor_table[df::job_type::MakeBarrel] = jlf_make_furniture; job_to_labor_table[df::job_type::MakeBarrel] = jlf_make_furniture;
job_to_labor_table[df::job_type::MakeBucket] = jlf_make_furniture; job_to_labor_table[df::job_type::MakeBucket] = jlf_make_furniture;
job_to_labor_table[df::job_type::MakeWindow] = jlf_make_furniture; job_to_labor_table[df::job_type::MakeWindow] = jlf_make_furniture;
job_to_labor_table[df::job_type::MakeTotem] = jlf_const(df::unit_labor::BONE_CARVE); job_to_labor_table[df::job_type::MakeTotem] = jlf_const(df::unit_labor::BONE_CARVE);
job_to_labor_table[df::job_type::MakeAmmo] = jlf_make_weapon; job_to_labor_table[df::job_type::MakeAmmo] = jlf_make_weapon;
job_to_labor_table[df::job_type::DecorateWith] = jlf_make_object; job_to_labor_table[df::job_type::DecorateWith] = jlf_make_object;
job_to_labor_table[df::job_type::MakeBackpack] = jlf_make_object; job_to_labor_table[df::job_type::MakeBackpack] = jlf_make_object;
job_to_labor_table[df::job_type::MakeQuiver] = jlf_make_armor; job_to_labor_table[df::job_type::MakeQuiver] = jlf_make_armor;
job_to_labor_table[df::job_type::MakeBallistaArrowHead] = jlf_make_weapon; job_to_labor_table[df::job_type::MakeBallistaArrowHead] = jlf_make_weapon;
job_to_labor_table[df::job_type::AssembleSiegeAmmo] = jlf_const(df::unit_labor::SIEGECRAFT); job_to_labor_table[df::job_type::AssembleSiegeAmmo] = jlf_const(df::unit_labor::SIEGECRAFT);
job_to_labor_table[df::job_type::LoadCatapult] = jlf_const(df::unit_labor::SIEGEOPERATE); job_to_labor_table[df::job_type::LoadCatapult] = jlf_const(df::unit_labor::SIEGEOPERATE);
job_to_labor_table[df::job_type::LoadBallista] = jlf_const(df::unit_labor::SIEGEOPERATE); job_to_labor_table[df::job_type::LoadBallista] = jlf_const(df::unit_labor::SIEGEOPERATE);
job_to_labor_table[df::job_type::FireCatapult] = jlf_const(df::unit_labor::SIEGEOPERATE); job_to_labor_table[df::job_type::FireCatapult] = jlf_const(df::unit_labor::SIEGEOPERATE);
job_to_labor_table[df::job_type::FireBallista] = jlf_const(df::unit_labor::SIEGEOPERATE); job_to_labor_table[df::job_type::FireBallista] = jlf_const(df::unit_labor::SIEGEOPERATE);
job_to_labor_table[df::job_type::ConstructMechanisms] = jlf_const(df::unit_labor::MECHANIC); job_to_labor_table[df::job_type::ConstructMechanisms] = jlf_const(df::unit_labor::MECHANIC);
job_to_labor_table[df::job_type::MakeTrapComponent] = jlf_const(df::unit_labor::MECHANIC) ; job_to_labor_table[df::job_type::MakeTrapComponent] = jlf_const(df::unit_labor::MECHANIC) ;
job_to_labor_table[df::job_type::LoadCageTrap] = jlf_const(df::unit_labor::MECHANIC) ; job_to_labor_table[df::job_type::LoadCageTrap] = jlf_const(df::unit_labor::MECHANIC) ;
job_to_labor_table[df::job_type::LoadStoneTrap] = jlf_const(df::unit_labor::MECHANIC) ; job_to_labor_table[df::job_type::LoadStoneTrap] = jlf_const(df::unit_labor::MECHANIC) ;
job_to_labor_table[df::job_type::LoadWeaponTrap] = jlf_const(df::unit_labor::MECHANIC) ; job_to_labor_table[df::job_type::LoadWeaponTrap] = jlf_const(df::unit_labor::MECHANIC) ;
job_to_labor_table[df::job_type::CleanTrap] = jlf_const(df::unit_labor::MECHANIC) ; job_to_labor_table[df::job_type::CleanTrap] = jlf_const(df::unit_labor::MECHANIC) ;
job_to_labor_table[df::job_type::CastSpell] = jlf_no_labor; job_to_labor_table[df::job_type::CastSpell] = jlf_no_labor;
job_to_labor_table[df::job_type::LinkBuildingToTrigger] = jlf_const(df::unit_labor::MECHANIC) ; job_to_labor_table[df::job_type::LinkBuildingToTrigger] = jlf_const(df::unit_labor::MECHANIC) ;
job_to_labor_table[df::job_type::PullLever] = jlf_no_labor; job_to_labor_table[df::job_type::PullLever] = jlf_no_labor;
job_to_labor_table[df::job_type::BrewDrink] = jlf_const(df::unit_labor::BREWER) ; job_to_labor_table[df::job_type::BrewDrink] = jlf_const(df::unit_labor::BREWER) ;
job_to_labor_table[df::job_type::ExtractFromPlants] = jlf_const(df::unit_labor::HERBALIST) ; job_to_labor_table[df::job_type::ExtractFromPlants] = jlf_const(df::unit_labor::HERBALIST) ;
job_to_labor_table[df::job_type::ExtractFromRawFish] = jlf_const(df::unit_labor::DISSECT_FISH) ; job_to_labor_table[df::job_type::ExtractFromRawFish] = jlf_const(df::unit_labor::DISSECT_FISH) ;
job_to_labor_table[df::job_type::ExtractFromLandAnimal] = jlf_const(df::unit_labor::DISSECT_VERMIN) ; job_to_labor_table[df::job_type::ExtractFromLandAnimal] = jlf_const(df::unit_labor::DISSECT_VERMIN) ;
job_to_labor_table[df::job_type::TameVermin] = jlf_const(df::unit_labor::ANIMALTRAIN) ; job_to_labor_table[df::job_type::TameVermin] = jlf_const(df::unit_labor::ANIMALTRAIN) ;
job_to_labor_table[df::job_type::TameAnimal] = jlf_const(df::unit_labor::ANIMALTRAIN) ; job_to_labor_table[df::job_type::TameAnimal] = jlf_const(df::unit_labor::ANIMALTRAIN) ;
job_to_labor_table[df::job_type::ChainAnimal] = jlf_no_labor; job_to_labor_table[df::job_type::ChainAnimal] = jlf_no_labor;
job_to_labor_table[df::job_type::UnchainAnimal] = jlf_no_labor; job_to_labor_table[df::job_type::UnchainAnimal] = jlf_no_labor;
job_to_labor_table[df::job_type::UnchainPet] = jlf_no_labor; job_to_labor_table[df::job_type::UnchainPet] = jlf_no_labor;
job_to_labor_table[df::job_type::ReleaseLargeCreature] = jlf_no_labor; job_to_labor_table[df::job_type::ReleaseLargeCreature] = jlf_no_labor;
job_to_labor_table[df::job_type::ReleasePet] = jlf_no_labor; job_to_labor_table[df::job_type::ReleasePet] = jlf_no_labor;
job_to_labor_table[df::job_type::ReleaseSmallCreature] = jlf_no_labor; job_to_labor_table[df::job_type::ReleaseSmallCreature] = jlf_no_labor;
job_to_labor_table[df::job_type::HandleSmallCreature] = jlf_no_labor; job_to_labor_table[df::job_type::HandleSmallCreature] = jlf_no_labor;
job_to_labor_table[df::job_type::HandleLargeCreature] = jlf_no_labor; job_to_labor_table[df::job_type::HandleLargeCreature] = jlf_no_labor;
job_to_labor_table[df::job_type::CageLargeCreature] = jlf_no_labor; job_to_labor_table[df::job_type::CageLargeCreature] = jlf_no_labor;
job_to_labor_table[df::job_type::CageSmallCreature] = jlf_no_labor; job_to_labor_table[df::job_type::CageSmallCreature] = jlf_no_labor;
job_to_labor_table[df::job_type::RecoverWounded] = jlf_const(df::unit_labor::RECOVER_WOUNDED); job_to_labor_table[df::job_type::RecoverWounded] = jlf_const(df::unit_labor::RECOVER_WOUNDED);
job_to_labor_table[df::job_type::DiagnosePatient] = jlf_const(df::unit_labor::DIAGNOSE) ; job_to_labor_table[df::job_type::DiagnosePatient] = jlf_const(df::unit_labor::DIAGNOSE) ;
job_to_labor_table[df::job_type::ImmobilizeBreak] = jlf_const(df::unit_labor::BONE_SETTING) ; job_to_labor_table[df::job_type::ImmobilizeBreak] = jlf_const(df::unit_labor::BONE_SETTING) ;
job_to_labor_table[df::job_type::DressWound] = jlf_const(df::unit_labor::DRESSING_WOUNDS) ; job_to_labor_table[df::job_type::DressWound] = jlf_const(df::unit_labor::DRESSING_WOUNDS) ;
job_to_labor_table[df::job_type::CleanPatient] = jlf_const(df::unit_labor::DRESSING_WOUNDS) ; job_to_labor_table[df::job_type::CleanPatient] = jlf_const(df::unit_labor::DRESSING_WOUNDS) ;
job_to_labor_table[df::job_type::Surgery] = jlf_const(df::unit_labor::SURGERY) ; job_to_labor_table[df::job_type::Surgery] = jlf_const(df::unit_labor::SURGERY) ;
job_to_labor_table[df::job_type::Suture] = jlf_const(df::unit_labor::SUTURING); job_to_labor_table[df::job_type::Suture] = jlf_const(df::unit_labor::SUTURING);
job_to_labor_table[df::job_type::SetBone] = jlf_const(df::unit_labor::BONE_SETTING) ; job_to_labor_table[df::job_type::SetBone] = jlf_const(df::unit_labor::BONE_SETTING) ;
job_to_labor_table[df::job_type::PlaceInTraction] = jlf_const(df::unit_labor::BONE_SETTING) ; job_to_labor_table[df::job_type::PlaceInTraction] = jlf_const(df::unit_labor::BONE_SETTING) ;
job_to_labor_table[df::job_type::DrainAquarium] = jlf_no_labor; job_to_labor_table[df::job_type::DrainAquarium] = jlf_no_labor;
job_to_labor_table[df::job_type::FillAquarium] = jlf_no_labor; job_to_labor_table[df::job_type::FillAquarium] = jlf_no_labor;
job_to_labor_table[df::job_type::FillPond] = jlf_no_labor; job_to_labor_table[df::job_type::FillPond] = jlf_no_labor;
job_to_labor_table[df::job_type::GiveWater] = jlf_const(df::unit_labor::FEED_WATER_CIVILIANS) ; job_to_labor_table[df::job_type::GiveWater] = jlf_const(df::unit_labor::FEED_WATER_CIVILIANS) ;
job_to_labor_table[df::job_type::GiveFood] = jlf_const(df::unit_labor::FEED_WATER_CIVILIANS) ; job_to_labor_table[df::job_type::GiveFood] = jlf_const(df::unit_labor::FEED_WATER_CIVILIANS) ;
job_to_labor_table[df::job_type::GiveWater2] = jlf_no_labor; job_to_labor_table[df::job_type::GiveWater2] = jlf_no_labor;
job_to_labor_table[df::job_type::GiveFood2] = jlf_no_labor; job_to_labor_table[df::job_type::GiveFood2] = jlf_no_labor;
job_to_labor_table[df::job_type::RecoverPet] = jlf_no_labor; job_to_labor_table[df::job_type::RecoverPet] = jlf_no_labor;
job_to_labor_table[df::job_type::PitLargeAnimal] = jlf_no_labor; job_to_labor_table[df::job_type::PitLargeAnimal] = jlf_no_labor;
job_to_labor_table[df::job_type::PitSmallAnimal] = jlf_no_labor; job_to_labor_table[df::job_type::PitSmallAnimal] = jlf_no_labor;
job_to_labor_table[df::job_type::SlaughterAnimal] = jlf_const(df::unit_labor::BUTCHER); job_to_labor_table[df::job_type::SlaughterAnimal] = jlf_const(df::unit_labor::BUTCHER);
job_to_labor_table[df::job_type::MakeCharcoal] = jlf_const(df::unit_labor::BURN_WOOD); job_to_labor_table[df::job_type::MakeCharcoal] = jlf_const(df::unit_labor::BURN_WOOD);
job_to_labor_table[df::job_type::MakeAsh] = jlf_const(df::unit_labor::BURN_WOOD); job_to_labor_table[df::job_type::MakeAsh] = jlf_const(df::unit_labor::BURN_WOOD);
job_to_labor_table[df::job_type::MakeLye] = jlf_const(df::unit_labor::LYE_MAKING); job_to_labor_table[df::job_type::MakeLye] = jlf_const(df::unit_labor::LYE_MAKING);
job_to_labor_table[df::job_type::MakePotashFromLye] = jlf_const(df::unit_labor::POTASH_MAKING); job_to_labor_table[df::job_type::MakePotashFromLye] = jlf_const(df::unit_labor::POTASH_MAKING);
job_to_labor_table[df::job_type::FertilizeField] = jlf_const(df::unit_labor::PLANT); job_to_labor_table[df::job_type::FertilizeField] = jlf_const(df::unit_labor::PLANT);
job_to_labor_table[df::job_type::MakePotashFromAsh] = jlf_const(df::unit_labor::POTASH_MAKING); job_to_labor_table[df::job_type::MakePotashFromAsh] = jlf_const(df::unit_labor::POTASH_MAKING);
job_to_labor_table[df::job_type::DyeThread] = jlf_const(df::unit_labor::DYER); job_to_labor_table[df::job_type::DyeThread] = jlf_const(df::unit_labor::DYER);
job_to_labor_table[df::job_type::DyeCloth] = jlf_const(df::unit_labor::DYER); job_to_labor_table[df::job_type::DyeCloth] = jlf_const(df::unit_labor::DYER);
job_to_labor_table[df::job_type::SewImage] = jlf_make_object; job_to_labor_table[df::job_type::SewImage] = jlf_make_object;
job_to_labor_table[df::job_type::MakePipeSection] = jlf_make_furniture; job_to_labor_table[df::job_type::MakePipeSection] = jlf_make_furniture;
job_to_labor_table[df::job_type::OperatePump] = jlf_const(df::unit_labor::OPERATE_PUMP); job_to_labor_table[df::job_type::OperatePump] = jlf_const(df::unit_labor::OPERATE_PUMP);
job_to_labor_table[df::job_type::ManageWorkOrders] = jlf_no_labor; job_to_labor_table[df::job_type::ManageWorkOrders] = jlf_no_labor;
job_to_labor_table[df::job_type::UpdateStockpileRecords] = jlf_no_labor; job_to_labor_table[df::job_type::UpdateStockpileRecords] = jlf_no_labor;
job_to_labor_table[df::job_type::TradeAtDepot] = jlf_no_labor; job_to_labor_table[df::job_type::TradeAtDepot] = jlf_no_labor;
job_to_labor_table[df::job_type::ConstructHatchCover] = jlf_make_furniture; job_to_labor_table[df::job_type::ConstructHatchCover] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructGrate] = jlf_make_furniture; job_to_labor_table[df::job_type::ConstructGrate] = jlf_make_furniture;
job_to_labor_table[df::job_type::RemoveStairs] = jlf_const(df::unit_labor::MINE); job_to_labor_table[df::job_type::RemoveStairs] = jlf_const(df::unit_labor::MINE);
job_to_labor_table[df::job_type::ConstructQuern] = jlf_make_furniture; job_to_labor_table[df::job_type::ConstructQuern] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructMillstone] = jlf_make_furniture; job_to_labor_table[df::job_type::ConstructMillstone] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructSplint] = jlf_make_furniture; job_to_labor_table[df::job_type::ConstructSplint] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructCrutch] = jlf_make_furniture; job_to_labor_table[df::job_type::ConstructCrutch] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructTractionBench] = jlf_const(df::unit_labor::MECHANIC); job_to_labor_table[df::job_type::ConstructTractionBench] = jlf_const(df::unit_labor::MECHANIC);
job_to_labor_table[df::job_type::CleanSelf] = jlf_no_labor; job_to_labor_table[df::job_type::CleanSelf] = jlf_no_labor;
job_to_labor_table[df::job_type::BringCrutch] = jlf_const(df::unit_labor::BONE_SETTING); job_to_labor_table[df::job_type::BringCrutch] = jlf_const(df::unit_labor::BONE_SETTING);
job_to_labor_table[df::job_type::ApplyCast] = jlf_const(df::unit_labor::BONE_SETTING); job_to_labor_table[df::job_type::ApplyCast] = jlf_const(df::unit_labor::BONE_SETTING);
job_to_labor_table[df::job_type::CustomReaction] = new jlfunc_custom(); job_to_labor_table[df::job_type::CustomReaction] = new jlfunc_custom();
job_to_labor_table[df::job_type::ConstructSlab] = jlf_make_furniture; job_to_labor_table[df::job_type::ConstructSlab] = jlf_make_furniture;
job_to_labor_table[df::job_type::EngraveSlab] = jlf_const(df::unit_labor::DETAIL); job_to_labor_table[df::job_type::EngraveSlab] = jlf_const(df::unit_labor::DETAIL);
job_to_labor_table[df::job_type::ShearCreature] = jlf_const(df::unit_labor::SHEARER); job_to_labor_table[df::job_type::ShearCreature] = jlf_const(df::unit_labor::SHEARER);
job_to_labor_table[df::job_type::SpinThread] = jlf_const(df::unit_labor::SPINNER); job_to_labor_table[df::job_type::SpinThread] = jlf_const(df::unit_labor::SPINNER);
job_to_labor_table[df::job_type::PenLargeAnimal] = jlf_no_labor; job_to_labor_table[df::job_type::PenLargeAnimal] = jlf_no_labor;
job_to_labor_table[df::job_type::PenSmallAnimal] = jlf_no_labor; job_to_labor_table[df::job_type::PenSmallAnimal] = jlf_no_labor;
job_to_labor_table[df::job_type::MakeTool] = jlf_make_furniture; job_to_labor_table[df::job_type::MakeTool] = jlf_make_furniture;
job_to_labor_table[df::job_type::CollectClay] = jlf_const(df::unit_labor::POTTERY); job_to_labor_table[df::job_type::CollectClay] = jlf_const(df::unit_labor::POTTERY);
job_to_labor_table[df::job_type::InstallColonyInHive] = jlf_const(df::unit_labor::BEEKEEPING); job_to_labor_table[df::job_type::InstallColonyInHive] = jlf_const(df::unit_labor::BEEKEEPING);
job_to_labor_table[df::job_type::CollectHiveProducts] = jlf_const(df::unit_labor::BEEKEEPING); job_to_labor_table[df::job_type::CollectHiveProducts] = jlf_const(df::unit_labor::BEEKEEPING);
job_to_labor_table[df::job_type::CauseTrouble] = jlf_no_labor; job_to_labor_table[df::job_type::CauseTrouble] = jlf_no_labor;
job_to_labor_table[df::job_type::DrinkBlood] = jlf_no_labor; job_to_labor_table[df::job_type::DrinkBlood] = jlf_no_labor;
job_to_labor_table[df::job_type::ReportCrime] = jlf_no_labor; job_to_labor_table[df::job_type::ReportCrime] = jlf_no_labor;
job_to_labor_table[df::job_type::ExecuteCriminal] = jlf_no_labor; job_to_labor_table[df::job_type::ExecuteCriminal] = jlf_no_labor;
job_to_labor_table[df::job_type::TrainAnimal] = jlf_const(df::unit_labor::ANIMALTRAIN); job_to_labor_table[df::job_type::TrainAnimal] = jlf_const(df::unit_labor::ANIMALTRAIN);
job_to_labor_table[df::job_type::CarveTrack] = jlf_const(df::unit_labor::DETAIL); job_to_labor_table[df::job_type::CarveTrack] = jlf_const(df::unit_labor::DETAIL);
job_to_labor_table[df::job_type::PushTrackVehicle] = jlf_const(df::unit_labor::PUSH_HAUL_VEHICLE); job_to_labor_table[df::job_type::PushTrackVehicle] = jlf_const(df::unit_labor::PUSH_HAUL_VEHICLE);
job_to_labor_table[df::job_type::PlaceTrackVehicle] = jlf_const(df::unit_labor::PUSH_HAUL_VEHICLE); job_to_labor_table[df::job_type::PlaceTrackVehicle] = jlf_const(df::unit_labor::PUSH_HAUL_VEHICLE);
job_to_labor_table[df::job_type::StoreItemInVehicle] = jlf_const(df::unit_labor::PUSH_HAUL_VEHICLE); job_to_labor_table[df::job_type::StoreItemInVehicle] = jlf_const(df::unit_labor::PUSH_HAUL_VEHICLE);
}; };
@ -1505,7 +1505,7 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <Plug
" disables labors. Generally, each dwarf will be assigned exactly one labor.\n" " disables labors. Generally, each dwarf will be assigned exactly one labor.\n"
" Warning: autolabor will override any manual changes you make to labors\n" " Warning: autolabor will override any manual changes you make to labors\n"
" while it is enabled. Do not try to run both autolabor and autolabor2 at\n" " while it is enabled. Do not try to run both autolabor and autolabor2 at\n"
" the same time." " the same time."
)); ));
generate_labor_to_skill_map(); generate_labor_to_skill_map();
@ -1956,7 +1956,7 @@ private:
df::job_skill skill = labor_to_skill[labor]; df::job_skill skill = labor_to_skill[labor];
if (skill != df::job_skill::NONE) if (skill != df::job_skill::NONE)
{ {
int skill_level = Units::getNominalSkill(dwarf->dwarf, skill, false); int skill_level = Units::getNominalSkill(dwarf->dwarf, skill, false);
high_skill = std::max(high_skill, skill_level); high_skill = std::max(high_skill, skill_level);
} }
} }
@ -2067,7 +2067,7 @@ public:
// add job entries for health care // add job entries for health care
labor_needed[df::unit_labor::RECOVER_WOUNDED] += cnt_recover_wounded; labor_needed[df::unit_labor::RECOVER_WOUNDED] += cnt_recover_wounded;
labor_needed[df::unit_labor::DIAGNOSE] += cnt_diagnosis; labor_needed[df::unit_labor::DIAGNOSE] += cnt_diagnosis;
labor_needed[df::unit_labor::BONE_SETTING] += cnt_immobilize; labor_needed[df::unit_labor::BONE_SETTING] += cnt_immobilize;
labor_needed[df::unit_labor::DRESSING_WOUNDS] += cnt_dressing; labor_needed[df::unit_labor::DRESSING_WOUNDS] += cnt_dressing;
labor_needed[df::unit_labor::DRESSING_WOUNDS] += cnt_cleaning; labor_needed[df::unit_labor::DRESSING_WOUNDS] += cnt_cleaning;

@ -1 +1 @@
Subproject commit a80abe848e4886a210e7a5123192e9221dc85810 Subproject commit 5b167d2ba89b877d80e0609feae8771aeaef356d

@ -71,14 +71,14 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <Plug
" L: Low Traffic\n" " L: Low Traffic\n"
" R: Restricted Traffic\n" " R: Restricted Traffic\n"
)); ));
commands.push_back(PluginCommand( commands.push_back(PluginCommand(
"restrictliquids","Restrict on every visible square with liquid", "restrictliquids","Restrict on every visible square with liquid",
restrictLiquid, false, "" restrictLiquid, false, ""
)); ));
commands.push_back(PluginCommand( commands.push_back(PluginCommand(
"restrictice","Restrict traffic on squares above visible ice", "restrictice","Restrict traffic on squares above visible ice",
restrictIce, false, "" restrictIce, false, ""
)); ));
return CR_OK; return CR_OK;
} }
@ -285,7 +285,7 @@ command_result restrictLiquid(color_ostream &out, std::vector<std::string> & par
command_result restrictIce(color_ostream &out, std::vector<std::string> & params) command_result restrictIce(color_ostream &out, std::vector<std::string> & params)
{ {
return setAllMatching(out, restrictIceProc); return setAllMatching(out, restrictIceProc);
} }
//Helper function for writing new functions that check every tile on the map. //Helper function for writing new functions that check every tile on the map.
@ -383,29 +383,29 @@ void allRestricted(DFCoord coord, MapExtras::MapCache &map)
//Restrict traffic if tile is visible and liquid is present. //Restrict traffic if tile is visible and liquid is present.
void restrictLiquidProc(DFCoord coord, MapExtras::MapCache &map) void restrictLiquidProc(DFCoord coord, MapExtras::MapCache &map)
{ {
df::tile_designation des = map.designationAt(coord); df::tile_designation des = map.designationAt(coord);
if ((des.bits.hidden == 0) && (des.bits.flow_size != 0)) if ((des.bits.hidden == 0) && (des.bits.flow_size != 0))
{ {
des.bits.traffic = tile_traffic::Restricted; des.bits.traffic = tile_traffic::Restricted;
map.setDesignationAt(coord, des); map.setDesignationAt(coord, des);
} }
} }
//Restrict traffice if tile is above visible ice wall. //Restrict traffice if tile is above visible ice wall.
void restrictIceProc(DFCoord coord, MapExtras::MapCache &map) void restrictIceProc(DFCoord coord, MapExtras::MapCache &map)
{ {
//There is no ice below the bottom of the map. //There is no ice below the bottom of the map.
if (coord.z == 0) if (coord.z == 0)
return; return;
DFCoord tile_below = DFCoord(coord.x, coord.y, coord.z - 1); DFCoord tile_below = DFCoord(coord.x, coord.y, coord.z - 1);
df::tiletype tt = map.tiletypeAt(tile_below); df::tiletype tt = map.tiletypeAt(tile_below);
df::tile_designation des = map.designationAt(tile_below); df::tile_designation des = map.designationAt(tile_below);
if ((des.bits.hidden == 0) && (tileMaterial(tt) == tiletype_material::FROZEN_LIQUID)) if ((des.bits.hidden == 0) && (tileMaterial(tt) == tiletype_material::FROZEN_LIQUID))
{ {
des = map.designationAt(coord); des = map.designationAt(coord);
des.bits.traffic = tile_traffic::Restricted; des.bits.traffic = tile_traffic::Restricted;
map.setDesignationAt(coord, des); map.setDesignationAt(coord, des);
} }
} }

@ -9,30 +9,30 @@ DFHACK_PLUGIN("fortplan");
command_result fortplan(color_ostream &out, vector<string> & params); command_result fortplan(color_ostream &out, vector<string> & params);
struct BuildingInfo { struct BuildingInfo {
std::string code; std::string code;
df::building_type type; df::building_type type;
df::furnace_type furnaceType; df::furnace_type furnaceType;
df::workshop_type workshopType; df::workshop_type workshopType;
df::trap_type trapType; df::trap_type trapType;
std::string name; std::string name;
bool variableSize; bool variableSize;
int defaultHeight; int defaultHeight;
int defaultWidth; int defaultWidth;
bool hasCustomOptions; bool hasCustomOptions;
BuildingInfo(std::string theCode, df::building_type theType, std::string theName, int height, int width) { BuildingInfo(std::string theCode, df::building_type theType, std::string theName, int height, int width) {
code = theCode; code = theCode;
type = theType; type = theType;
name = theName; name = theName;
variableSize = false; variableSize = false;
defaultHeight = height; defaultHeight = height;
defaultWidth = width; defaultWidth = width;
hasCustomOptions = false; hasCustomOptions = false;
} }
bool allocate() { bool allocate() {
return planner.allocatePlannedBuilding(type); return planner.allocatePlannedBuilding(type);
} }
}; };
class MatchesCode class MatchesCode
@ -55,32 +55,32 @@ DFhackCExport command_result plugin_init ( color_ostream &out, vector <PluginCom
"Lay out buildings in your fortress based on a Quickfort-style CSV input file.\n" "Lay out buildings in your fortress based on a Quickfort-style CSV input file.\n"
"Usage: fortplan [filename]\n")); "Usage: fortplan [filename]\n"));
buildings.push_back(BuildingInfo("c",df::building_type::Chair,"Chair",1,1)); buildings.push_back(BuildingInfo("c",df::building_type::Chair,"Chair",1,1));
buildings.push_back(BuildingInfo("b",df::building_type::Bed,"Bed",1,1)); buildings.push_back(BuildingInfo("b",df::building_type::Bed,"Bed",1,1));
buildings.push_back(BuildingInfo("t",df::building_type::Table,"Table",1,1)); buildings.push_back(BuildingInfo("t",df::building_type::Table,"Table",1,1));
buildings.push_back(BuildingInfo("n",df::building_type::Coffin,"Coffin",1,1)); buildings.push_back(BuildingInfo("n",df::building_type::Coffin,"Coffin",1,1));
buildings.push_back(BuildingInfo("d",df::building_type::Door,"Door",1,1)); buildings.push_back(BuildingInfo("d",df::building_type::Door,"Door",1,1));
buildings.push_back(BuildingInfo("x",df::building_type::Floodgate,"Floodgate",1,1)); buildings.push_back(BuildingInfo("x",df::building_type::Floodgate,"Floodgate",1,1));
buildings.push_back(BuildingInfo("h",df::building_type::Box,"Box",1,1)); buildings.push_back(BuildingInfo("h",df::building_type::Box,"Box",1,1));
buildings.push_back(BuildingInfo("r",df::building_type::Weaponrack,"Weapon Rack",1,1)); buildings.push_back(BuildingInfo("r",df::building_type::Weaponrack,"Weapon Rack",1,1));
buildings.push_back(BuildingInfo("a",df::building_type::Armorstand,"Armor Stand",1,1)); buildings.push_back(BuildingInfo("a",df::building_type::Armorstand,"Armor Stand",1,1));
buildings.push_back(BuildingInfo("f",df::building_type::Cabinet,"Cabinet",1,1)); buildings.push_back(BuildingInfo("f",df::building_type::Cabinet,"Cabinet",1,1));
buildings.push_back(BuildingInfo("s",df::building_type::Statue,"Statue",1,1)); buildings.push_back(BuildingInfo("s",df::building_type::Statue,"Statue",1,1));
buildings.push_back(BuildingInfo("y",df::building_type::WindowGlass,"Glass Window",1,1)); buildings.push_back(BuildingInfo("y",df::building_type::WindowGlass,"Glass Window",1,1));
buildings.push_back(BuildingInfo("m",df::building_type::AnimalTrap,"Animal Trap",1,1)); buildings.push_back(BuildingInfo("m",df::building_type::AnimalTrap,"Animal Trap",1,1));
buildings.push_back(BuildingInfo("v",df::building_type::Chain,"Chain",1,1)); buildings.push_back(BuildingInfo("v",df::building_type::Chain,"Chain",1,1));
buildings.push_back(BuildingInfo("j",df::building_type::Cage,"Cage",1,1)); buildings.push_back(BuildingInfo("j",df::building_type::Cage,"Cage",1,1));
buildings.push_back(BuildingInfo("H",df::building_type::Hatch,"Floor Hatch",1,1)); buildings.push_back(BuildingInfo("H",df::building_type::Hatch,"Floor Hatch",1,1));
buildings.push_back(BuildingInfo("W",df::building_type::GrateWall,"Wall Grate",1,1)); buildings.push_back(BuildingInfo("W",df::building_type::GrateWall,"Wall Grate",1,1));
buildings.push_back(BuildingInfo("G",df::building_type::GrateFloor,"Floor Grate",1,1)); buildings.push_back(BuildingInfo("G",df::building_type::GrateFloor,"Floor Grate",1,1));
buildings.push_back(BuildingInfo("B",df::building_type::BarsVertical,"Vertical Bars",1,1)); buildings.push_back(BuildingInfo("B",df::building_type::BarsVertical,"Vertical Bars",1,1));
buildings.push_back(BuildingInfo("~b",df::building_type::BarsFloor,"Floor Bars",1,1)); buildings.push_back(BuildingInfo("~b",df::building_type::BarsFloor,"Floor Bars",1,1));
buildings.push_back(BuildingInfo("R",df::building_type::TractionBench,"Traction Bench",1,1)); buildings.push_back(BuildingInfo("R",df::building_type::TractionBench,"Traction Bench",1,1));
buildings.push_back(BuildingInfo("~s",df::building_type::Slab,"Slab",1,1)); buildings.push_back(BuildingInfo("~s",df::building_type::Slab,"Slab",1,1));
buildings.push_back(BuildingInfo("N",df::building_type::NestBox,"Nest Box",1,1)); buildings.push_back(BuildingInfo("N",df::building_type::NestBox,"Nest Box",1,1));
buildings.push_back(BuildingInfo("~h",df::building_type::Hive,"Hive",1,1)); buildings.push_back(BuildingInfo("~h",df::building_type::Hive,"Hive",1,1));
planner.initialize(); planner.initialize();
return CR_OK; return CR_OK;
} }
@ -116,260 +116,260 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable)
} }
std::vector<std::vector<std::string>> tokenizeFile(std::string filename) { std::vector<std::vector<std::string>> tokenizeFile(std::string filename) {
std::ifstream infile(filename.c_str()); std::ifstream infile(filename.c_str());
std::vector<std::vector<std::string>> fileTokens(128, std::vector<std::string>(128)); std::vector<std::vector<std::string>> fileTokens(128, std::vector<std::string>(128));
std::vector<std::vector<std::string>>::size_type x, y; std::vector<std::vector<std::string>>::size_type x, y;
if (!infile.good()) { if (!infile.good()) {
throw -1; throw -1;
} }
std::string line; std::string line;
y = 0; y = 0;
while (std::getline(infile, line)) { while (std::getline(infile, line)) {
x = 0; x = 0;
if (strcmp(line.substr(0,1).c_str(),"#")==0) { if (strcmp(line.substr(0,1).c_str(),"#")==0) {
fileTokens[y++][0] = line; fileTokens[y++][0] = line;
continue; continue;
} }
int start = 0; int start = 0;
auto nextInd = line.find(','); auto nextInd = line.find(',');
std::string curCell = line.substr(start,nextInd-start); std::string curCell = line.substr(start,nextInd-start);
do { do {
fileTokens[y][x] = curCell; fileTokens[y][x] = curCell;
start = nextInd+1; start = nextInd+1;
nextInd = line.find(',',start); nextInd = line.find(',',start);
curCell = line.substr(start,nextInd-start); curCell = line.substr(start,nextInd-start);
x++; x++;
} while (nextInd != line.npos); } while (nextInd != line.npos);
y++; y++;
} }
return fileTokens; return fileTokens;
} }
command_result fortplan(color_ostream &out, vector<string> & params) { command_result fortplan(color_ostream &out, vector<string> & params) {
auto & con = out; auto & con = out;
std::vector<std::vector<std::string>> layout(128, std::vector<std::string>(128)); std::vector<std::vector<std::string>> layout(128, std::vector<std::string>(128));
if (params.size()) { if (params.size()) {
coord32_t cursor; coord32_t cursor;
coord32_t userCursor; coord32_t userCursor;
coord32_t startCursor; coord32_t startCursor;
if (!DFHack::Gui::getCursorCoords(cursor.x, cursor.y, cursor.z)) { if (!DFHack::Gui::getCursorCoords(cursor.x, cursor.y, cursor.z)) {
con.print("You must have an active in-game cursor.\n"); con.print("You must have an active in-game cursor.\n");
return CR_FAILURE; return CR_FAILURE;
} }
DFHack::Gui::getCursorCoords(startCursor.x, startCursor.y, startCursor.z); DFHack::Gui::getCursorCoords(startCursor.x, startCursor.y, startCursor.z);
userCursor = startCursor; userCursor = startCursor;
std::string cwd = Filesystem::getcwd(); std::string cwd = Filesystem::getcwd();
std::string filename = cwd+"/"+params[0]; std::string filename = cwd+"/"+params[0];
con.print("Loading file '%s'...\n",filename.c_str()); con.print("Loading file '%s'...\n",filename.c_str());
try { try {
layout = tokenizeFile(filename); layout = tokenizeFile(filename);
} catch (int e) { } catch (int e) {
con.print("Could not open the file.\n"); con.print("Could not open the file.\n");
return CR_FAILURE; return CR_FAILURE;
} }
if (!is_enabled) { if (!is_enabled) {
plugin_enable(out, true); plugin_enable(out, true);
} }
con.print("Loaded.\n"); con.print("Loaded.\n");
std::vector<std::vector<std::string>>::size_type x, y; std::vector<std::vector<std::string>>::size_type x, y;
bool started = false; bool started = false;
for (y = 0; y < layout.size(); y++) { for (y = 0; y < layout.size(); y++) {
x = 0; x = 0;
auto hashBuild = layout[y][x].find("#build"); auto hashBuild = layout[y][x].find("#build");
if (hashBuild != layout[y][x].npos) { if (hashBuild != layout[y][x].npos) {
auto startLoc = layout[y][x].find("start("); auto startLoc = layout[y][x].find("start(");
if (startLoc != layout[y][x].npos) { if (startLoc != layout[y][x].npos) {
startLoc += 6; startLoc += 6;
auto nextDelimiter = layout[y][x].find(";",startLoc); auto nextDelimiter = layout[y][x].find(";",startLoc);
std::string startXStr = layout[y][x].substr(startLoc,nextDelimiter-startLoc); std::string startXStr = layout[y][x].substr(startLoc,nextDelimiter-startLoc);
int startXOffset = std::stoi(startXStr); int startXOffset = std::stoi(startXStr);
startLoc = nextDelimiter+1; startLoc = nextDelimiter+1;
nextDelimiter = layout[y][x].find(";",startLoc); nextDelimiter = layout[y][x].find(";",startLoc);
std::string startYStr = layout[y][x].substr(startLoc,nextDelimiter-startLoc); std::string startYStr = layout[y][x].substr(startLoc,nextDelimiter-startLoc);
int startYOffset = std::stoi(startYStr); int startYOffset = std::stoi(startYStr);
startCursor.x -= startXOffset; startCursor.x -= startXOffset;
startCursor.y -= startYOffset; startCursor.y -= startYOffset;
DFHack::Gui::setCursorCoords(startCursor.x,startCursor.y,startCursor.z); DFHack::Gui::setCursorCoords(startCursor.x,startCursor.y,startCursor.z);
started = true; started = true;
auto startEnd = layout[y][x].find(")",nextDelimiter); auto startEnd = layout[y][x].find(")",nextDelimiter);
con.print("Starting at (%d,%d,%d) which is described as: %s\n",startCursor.x,startCursor.y,startCursor.z,layout[y][x].substr(nextDelimiter+1,startEnd-nextDelimiter).c_str()); con.print("Starting at (%d,%d,%d) which is described as: %s\n",startCursor.x,startCursor.y,startCursor.z,layout[y][x].substr(nextDelimiter+1,startEnd-nextDelimiter).c_str());
std::string desc = layout[y][x].substr(startEnd+1); std::string desc = layout[y][x].substr(startEnd+1);
if (desc.size()>0) { if (desc.size()>0) {
con.print("Description of this plan: %s\n",desc.c_str()); con.print("Description of this plan: %s\n",desc.c_str());
} }
continue; continue;
} else { } else {
con.print("No start location found for this block\n"); con.print("No start location found for this block\n");
} }
} else if (!started) { } else if (!started) {
con.print("Not a build file: %s\n",layout[y][x].c_str()); con.print("Not a build file: %s\n",layout[y][x].c_str());
break; break;
} }
for (x = 0; x < layout[y].size(); x++) { for (x = 0; x < layout[y].size(); x++) {
if (strcmp(layout[y][x].substr(0,1).c_str(),"#")==0) { if (strcmp(layout[y][x].substr(0,1).c_str(),"#")==0) {
continue; continue;
} }
if (strcmp(layout[y][x].c_str(),"`")!=0) { if (strcmp(layout[y][x].c_str(),"`")!=0) {
auto dataIndex = layout[y][x].find("("); auto dataIndex = layout[y][x].find("(");
std::string curCode; std::string curCode;
std::vector<std::string> curData; std::vector<std::string> curData;
if (dataIndex != layout[y][x].npos) { if (dataIndex != layout[y][x].npos) {
curCode = layout[y][x].substr(0,dataIndex); curCode = layout[y][x].substr(0,dataIndex);
int dataStart = dataIndex+1; int dataStart = dataIndex+1;
auto nextDataStart = layout[y][x].find(",",dataStart); auto nextDataStart = layout[y][x].find(",",dataStart);
while (nextDataStart!=layout[y][x].npos) { while (nextDataStart!=layout[y][x].npos) {
std::string nextData = layout[y][x].substr(dataStart,nextDataStart); std::string nextData = layout[y][x].substr(dataStart,nextDataStart);
if (strcmp(nextData.substr(nextData.size()-1,1).c_str(),")")==0) { if (strcmp(nextData.substr(nextData.size()-1,1).c_str(),")")==0) {
nextData = nextData.substr(0,nextData.size()-1); nextData = nextData.substr(0,nextData.size()-1);
} }
curData.push_back(nextData); curData.push_back(nextData);
dataStart = nextDataStart+1; dataStart = nextDataStart+1;
nextDataStart = layout[y][x].find(",",dataStart); nextDataStart = layout[y][x].find(",",dataStart);
} }
} else { } else {
curCode = layout[y][x]; curCode = layout[y][x];
} }
//con.print("Found a cell with '%s' in it (layout[y][x] %d:%d-%d)\n",layout[y][x].c_str(),lineNum,start,nextInd); //con.print("Found a cell with '%s' in it (layout[y][x] %d:%d-%d)\n",layout[y][x].c_str(),lineNum,start,nextInd);
auto buildingIndex = std::find_if(buildings.begin(), buildings.end(), MatchesCode(curCode.c_str())); auto buildingIndex = std::find_if(buildings.begin(), buildings.end(), MatchesCode(curCode.c_str()));
// = std::find(validInstructions.begin(), validInstructions.end(), layout[y][x]); // = std::find(validInstructions.begin(), validInstructions.end(), layout[y][x]);
if(buildingIndex == buildings.end()) { if(buildingIndex == buildings.end()) {
//con.print("That is not a valid code.\n"); //con.print("That is not a valid code.\n");
} else { } else {
//con.print("I can build that!\n"); //con.print("I can build that!\n");
BuildingInfo buildingInfo = *buildingIndex; BuildingInfo buildingInfo = *buildingIndex;
if (buildingInfo.variableSize || buildingInfo.defaultHeight > 1 || buildingInfo.defaultWidth > 1) { if (buildingInfo.variableSize || buildingInfo.defaultHeight > 1 || buildingInfo.defaultWidth > 1) {
//con.print("Found a building at (%d,%d) called %s, which has a size %dx%d or variable size\n",x,y,buildingInfo.name.c_str(),buildingInfo.defaultWidth, buildingInfo.defaultHeight); //con.print("Found a building at (%d,%d) called %s, which has a size %dx%d or variable size\n",x,y,buildingInfo.name.c_str(),buildingInfo.defaultWidth, buildingInfo.defaultHeight);
// TODO: Make this function smarter, able to determine the exact shape // TODO: Make this function smarter, able to determine the exact shape
// and location of the building // and location of the building
// For now, we just assume that we are always looking at the top left // For now, we just assume that we are always looking at the top left
// corner of where it is located in the input file // corner of where it is located in the input file
coord32_t buildingSize; coord32_t buildingSize;
if (!buildingInfo.variableSize) { if (!buildingInfo.variableSize) {
bool single = true; bool single = true;
bool block = true; bool block = true;
std::vector<std::vector<std::string>>::size_type checkX, checkY; std::vector<std::vector<std::string>>::size_type checkX, checkY;
int yOffset = ((buildingInfo.defaultHeight-1)/2); int yOffset = ((buildingInfo.defaultHeight-1)/2);
int xOffset = ((buildingInfo.defaultWidth-1)/2); int xOffset = ((buildingInfo.defaultWidth-1)/2);
//con.print(" - Checking to see if it's a single, with %d<=x<%d and %d<=y<%d...\n",x-xOffset,x+xOffset,y-yOffset,y+yOffset); //con.print(" - Checking to see if it's a single, with %d<=x<%d and %d<=y<%d...\n",x-xOffset,x+xOffset,y-yOffset,y+yOffset);
// First, check to see if this is in the center of an empty square of its default size // First, check to see if this is in the center of an empty square of its default size
for (checkY = y-yOffset; checkY <= (y+yOffset); checkY++) { for (checkY = y-yOffset; checkY <= (y+yOffset); checkY++) {
for (checkX = x-xOffset; checkX <= (x+xOffset); checkX++) { for (checkX = x-xOffset; checkX <= (x+xOffset); checkX++) {
if (checkX==x && checkY==y) { if (checkX==x && checkY==y) {
continue; continue;
} }
auto checkDataIndex = layout[checkY][checkX].find("("); auto checkDataIndex = layout[checkY][checkX].find("(");
std::string checkCode; std::string checkCode;
if (checkDataIndex != layout[checkY][checkX].npos) { if (checkDataIndex != layout[checkY][checkX].npos) {
checkCode = layout[checkY][checkX].substr(0,checkDataIndex); checkCode = layout[checkY][checkX].substr(0,checkDataIndex);
} else { } else {
checkCode = layout[checkY][checkX]; checkCode = layout[checkY][checkX];
} }
con.print(" - Code at (%d,%d) is '%s': ",checkX,checkY,checkCode.c_str()); con.print(" - Code at (%d,%d) is '%s': ",checkX,checkY,checkCode.c_str());
auto checkIndex = std::find_if(buildings.begin(), buildings.end(), MatchesCode(checkCode.c_str())); auto checkIndex = std::find_if(buildings.begin(), buildings.end(), MatchesCode(checkCode.c_str()));
//if (checkIndex == buildings.end()) { //if (checkIndex == buildings.end()) {
// con.print("this is not a valid code, so we keep going.\n"); // con.print("this is not a valid code, so we keep going.\n");
// continue; // continue;
//} //}
//if (curCode.compare(layout[checkY][checkX]) != 0) { //if (curCode.compare(layout[checkY][checkX]) != 0) {
if (checkIndex != buildings.end()) { if (checkIndex != buildings.end()) {
//con.print("this is a building, so we break.\n"); //con.print("this is a building, so we break.\n");
single = false; single = false;
break; break;
} else { } else {
//con.print("this is not a building, so we keep going.\n"); //con.print("this is not a building, so we keep going.\n");
} }
} }
if (!single) { if (!single) {
//con.print("Not a single. Moving forward.\n"); //con.print("Not a single. Moving forward.\n");
break; break;
} }
} }
if (!single) { if (!single) {
// If that's not the case, check to see if this is the top-left corner of // If that's not the case, check to see if this is the top-left corner of
// a square of its default size // a square of its default size
//con.print(" - It's not single; checking to see if it's a block...\n"); //con.print(" - It's not single; checking to see if it's a block...\n");
for (checkY = y; checkY < (y+buildingInfo.defaultHeight); checkY++) { for (checkY = y; checkY < (y+buildingInfo.defaultHeight); checkY++) {
for (checkX = x; checkX < (x+buildingInfo.defaultWidth); checkX++) { for (checkX = x; checkX < (x+buildingInfo.defaultWidth); checkX++) {
if (checkX==x && checkY==y) { if (checkX==x && checkY==y) {
continue; continue;
} }
auto checkDataIndex = layout[checkY][checkX].find("("); auto checkDataIndex = layout[checkY][checkX].find("(");
std::string checkCode; std::string checkCode;
if (checkDataIndex != layout[checkY][checkX].npos) { if (checkDataIndex != layout[checkY][checkX].npos) {
checkCode = layout[checkY][checkX].substr(0,checkDataIndex); checkCode = layout[checkY][checkX].substr(0,checkDataIndex);
} else { } else {
checkCode = layout[checkY][checkX]; checkCode = layout[checkY][checkX];
} }
//con.print(" - Code at (%d,%d) is '%s': ",checkX,checkY,checkCode.c_str()); //con.print(" - Code at (%d,%d) is '%s': ",checkX,checkY,checkCode.c_str());
if (curCode.compare(checkCode) != 0) { if (curCode.compare(checkCode) != 0) {
//con.print("this is not the same as '%s', so we break.\n",curCode.c_str()); //con.print("this is not the same as '%s', so we break.\n",curCode.c_str());
block = false; block = false;
break; break;
} else { } else {
//con.print("this is the same as '%s', so we erase it and move on.\n",curCode.c_str()); //con.print("this is the same as '%s', so we erase it and move on.\n",curCode.c_str());
layout[checkY][checkX] = "``"; layout[checkY][checkX] = "``";
} }
} }
if (!block) { if (!block) {
//con.print("Not a block. Moving forward.\n"); //con.print("Not a block. Moving forward.\n");
break; break;
} }
} }
} }
if (single) { if (single) {
//con.print("Placing a building with code '%s' centered at (%d,%d) and default size %dx%d.\n",curCode.c_str(),x,y,buildingInfo.defaultWidth,buildingInfo.defaultHeight); //con.print("Placing a building with code '%s' centered at (%d,%d) and default size %dx%d.\n",curCode.c_str(),x,y,buildingInfo.defaultWidth,buildingInfo.defaultHeight);
coord32_t offsetCursor = cursor; coord32_t offsetCursor = cursor;
offsetCursor.x -= xOffset; offsetCursor.x -= xOffset;
offsetCursor.y -= yOffset; offsetCursor.y -= yOffset;
DFHack::Gui::setCursorCoords(offsetCursor.x, offsetCursor.y, offsetCursor.z); DFHack::Gui::setCursorCoords(offsetCursor.x, offsetCursor.y, offsetCursor.z);
if (!buildingInfo.allocate()) { if (!buildingInfo.allocate()) {
con.print("*** There was an error placing building with code '%s' centered at (%d,%d).\n",curCode.c_str(),x,y); con.print("*** There was an error placing building with code '%s' centered at (%d,%d).\n",curCode.c_str(),x,y);
} }
DFHack::Gui::setCursorCoords(cursor.x, cursor.y, cursor.z); DFHack::Gui::setCursorCoords(cursor.x, cursor.y, cursor.z);
} else if (block) { } else if (block) {
//con.print("Placing a building with code '%s' with corner at (%d,%d) and default size %dx%d.\n",curCode.c_str(),x,y,buildingInfo.defaultWidth,buildingInfo.defaultHeight); //con.print("Placing a building with code '%s' with corner at (%d,%d) and default size %dx%d.\n",curCode.c_str(),x,y,buildingInfo.defaultWidth,buildingInfo.defaultHeight);
if (!buildingInfo.allocate()) { if (!buildingInfo.allocate()) {
con.print("*** There was an error placing building with code '%s' with corner at (%d,%d).\n",curCode.c_str(),x,y); con.print("*** There was an error placing building with code '%s' with corner at (%d,%d).\n",curCode.c_str(),x,y);
} }
} else { } else {
con.print("*** Found a code '%s' at (%d,%d) for a building with default size %dx%d with an invalid size designation.\n",curCode.c_str(),x,y,buildingInfo.defaultWidth,buildingInfo.defaultHeight); con.print("*** Found a code '%s' at (%d,%d) for a building with default size %dx%d with an invalid size designation.\n",curCode.c_str(),x,y,buildingInfo.defaultWidth,buildingInfo.defaultHeight);
} }
} else { } else {
//buildingSize = findBuildingExtent(layout, x, y, -1, -1, out); //buildingSize = findBuildingExtent(layout, x, y, -1, -1, out);
//con.print(" - The building has variable size %dx%d\n",buildingSize.x, buildingSize.y); //con.print(" - The building has variable size %dx%d\n",buildingSize.x, buildingSize.y);
//con.print(" - The building has a variable size, which is not yet handled.\n"); //con.print(" - The building has a variable size, which is not yet handled.\n");
} }
} else { } else {
//con.print("Building a(n) %s.\n",buildingInfo.name.c_str()); //con.print("Building a(n) %s.\n",buildingInfo.name.c_str());
if (!buildingInfo.allocate()) { if (!buildingInfo.allocate()) {
con.print("*** There was an error placing the %s at (%d,%d).\n",buildingInfo.name.c_str(),x,y); con.print("*** There was an error placing the %s at (%d,%d).\n",buildingInfo.name.c_str(),x,y);
} }
} }
} }
} }
cursor.x++; cursor.x++;
DFHack::Gui::setCursorCoords(cursor.x, cursor.y, cursor.z); DFHack::Gui::setCursorCoords(cursor.x, cursor.y, cursor.z);
} }
cursor.y++; cursor.y++;
cursor.x = startCursor.x; cursor.x = startCursor.x;
} }
DFHack::Gui::setCursorCoords(userCursor.x, userCursor.y, userCursor.z); DFHack::Gui::setCursorCoords(userCursor.x, userCursor.y, userCursor.z);
con.print("Done with file.\n"); con.print("Done with file.\n");
} else { } else {
con.print("You must supply a filename to read.\n"); con.print("You must supply a filename to read.\n");
} }
return CR_OK; return CR_OK;
} }

@ -1 +1 @@
Subproject commit 07750ad7f7ce7c2506e5198ffb80ca50a73e9c4e Subproject commit 85dcde97197bdde1c1e97ccb536f2cc4cab6818f

@ -130,39 +130,39 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
// CoreSuspender suspend; // CoreSuspender suspend;
// // Actually do something here. Yay. // // Actually do something here. Yay.
// out.print("Doing a test...\n"); // out.print("Doing a test...\n");
// MapExtras::MapCache MC; // MapExtras::MapCache MC;
// EmbarkTile test_tile; // EmbarkTile test_tile;
// if(!gather_embark_tile(0,0, &test_tile, &MC)) // if(!gather_embark_tile(0,0, &test_tile, &MC))
// return CR_FAILURE; // return CR_FAILURE;
// //test-write the file to check it. // //test-write the file to check it.
// std::ofstream output_file("tile.p", std::ios_base::binary); // std::ofstream output_file("tile.p", std::ios_base::binary);
// output_file << test_tile.SerializeAsString(); // output_file << test_tile.SerializeAsString();
// output_file.close(); // output_file.close();
// //
// //load it again to verify. // //load it again to verify.
// std::ifstream input_file("tile.p", std::ios_base::binary); // std::ifstream input_file("tile.p", std::ios_base::binary);
// std::string input_string( (std::istreambuf_iterator<char>(input_file) ), // std::string input_string( (std::istreambuf_iterator<char>(input_file) ),
// (std::istreambuf_iterator<char>() ) ); // (std::istreambuf_iterator<char>() ) );
// EmbarkTile verify_tile; // EmbarkTile verify_tile;
// verify_tile.ParseFromString(input_string); // verify_tile.ParseFromString(input_string);
// //write contents to text file. // //write contents to text file.
// std::ofstream debug_text("tile.txt", std::ios_base::trunc); // std::ofstream debug_text("tile.txt", std::ios_base::trunc);
// debug_text << "world coords:" << verify_tile.world_x()<< "," << verify_tile.world_y()<< "," << verify_tile.world_z() << std::endl; // debug_text << "world coords:" << verify_tile.world_x()<< "," << verify_tile.world_y()<< "," << verify_tile.world_z() << std::endl;
// for(int i = 0; i < verify_tile.tile_layer_size(); i++) { // for(int i = 0; i < verify_tile.tile_layer_size(); i++) {
// debug_text << "layer: " << i << std::endl; // debug_text << "layer: " << i << std::endl;
// for(int j = 0; j < 48; j++) { // for(int j = 0; j < 48; j++) {
// debug_text << " "; // debug_text << " ";
// for(int k = 0; k < 48; k++) { // for(int k = 0; k < 48; k++) {
// debug_text << verify_tile.tile_layer(i).mat_type_table(j*48+k) << ","; // debug_text << verify_tile.tile_layer(i).mat_type_table(j*48+k) << ",";
// } // }
// debug_text << " "; // debug_text << " ";
// for(int k = 0; k < 48; k++) { // for(int k = 0; k < 48; k++) {
// debug_text << std::setw(3) << verify_tile.tile_layer(i).mat_subtype_table(j*48+k) << ","; // debug_text << std::setw(3) << verify_tile.tile_layer(i).mat_subtype_table(j*48+k) << ",";
// } // }
// debug_text << std::endl; // debug_text << std::endl;
// } // }
// debug_text << std::endl; // debug_text << std::endl;
// } // }
// // Give control back to DF. // // Give control back to DF.
// return CR_OK; // return CR_OK;
//} //}
@ -197,12 +197,12 @@ static command_result GetEmbarkInfo(color_ostream &stream, const MapRequest *in,
out->set_available(false); out->set_available(false);
return CR_OK; return CR_OK;
} }
if (in->has_save_folder()) { //If no save folder is given, it means we don't care. if (in->has_save_folder()) { //If no save folder is given, it means we don't care.
if (!(in->save_folder() == world->cur_savegame.save_dir || in->save_folder() == "ANY")) { //isoworld has a different map loaded, don't bother trying to load tiles for it, we don't have them. if (!(in->save_folder() == world->cur_savegame.save_dir || in->save_folder() == "ANY")) { //isoworld has a different map loaded, don't bother trying to load tiles for it, we don't have them.
out->set_available(false); out->set_available(false);
return CR_OK; return CR_OK;
} }
} }
out->set_available(true); out->set_available(true);
out->set_current_year(*cur_year); out->set_current_year(*cur_year);
out->set_current_season(*cur_season); out->set_current_season(*cur_season);
@ -344,12 +344,12 @@ static command_result GetRawNames(color_ostream &stream, const MapRequest *in, R
out->set_available(false); out->set_available(false);
return CR_OK; return CR_OK;
} }
if (in->has_save_folder()) { //If no save folder is given, it means we don't care. if (in->has_save_folder()) { //If no save folder is given, it means we don't care.
if (!(in->save_folder() == world->cur_savegame.save_dir || in->save_folder() == "ANY")) { //isoworld has a different map loaded, don't bother trying to load tiles for it, we don't have them. if (!(in->save_folder() == world->cur_savegame.save_dir || in->save_folder() == "ANY")) { //isoworld has a different map loaded, don't bother trying to load tiles for it, we don't have them.
out->set_available(false); out->set_available(false);
return CR_OK; return CR_OK;
} }
} }
out->set_available(true); out->set_available(true);
for(int i = 0; i < world->raws.inorganics.size(); i++){ for(int i = 0; i < world->raws.inorganics.size(); i++){
out->add_inorganic(world->raws.inorganics[i]->id); out->add_inorganic(world->raws.inorganics[i]->id);

@ -1,24 +1,24 @@
local _ENV = mkmodule('plugins.building-hacks') local _ENV = mkmodule('plugins.building-hacks')
--[[ --[[
from native: from native:
addBuilding(custom type,impassible fix (bool), consumed power, produced power, list of connection points, addBuilding(custom type,impassible fix (bool), consumed power, produced power, list of connection points,
update skip(0/nil to disable),table of frames,frame to tick ratio (-1 for machine control)) update skip(0/nil to disable),table of frames,frame to tick ratio (-1 for machine control))
from here: from here:
registerBuilding{ registerBuilding{
name -- custom workshop id e.g. SOAPMAKER << required! name -- custom workshop id e.g. SOAPMAKER << required!
fix_impassible -- make impassible tiles impassible to liquids too fix_impassible -- make impassible tiles impassible to liquids too
consume -- how much machine power is needed to work consume -- how much machine power is needed to work
produce -- how much machine power is produced produce -- how much machine power is produced
gears -- a table or {x=?,y=?} of connection points for machines gears -- a table or {x=?,y=?} of connection points for machines
action -- a table of number (how much ticks to skip) and a function which gets called on shop update action -- a table of number (how much ticks to skip) and a function which gets called on shop update
animate -- a table of animate -- a table of
frames -- a table of frames -- a table of
tables of 4 numbers (tile,fore,back,bright) OR tables of 4 numbers (tile,fore,back,bright) OR
empty table (tile not modified) OR empty table (tile not modified) OR
{x=<number> y=<number> + 4 numbers like in first case} -- this generates full frame even, usefull for animations that change little (1-2 tiles) {x=<number> y=<number> + 4 numbers like in first case} -- this generates full frame even, usefull for animations that change little (1-2 tiles)
frameLenght -- how many ticks does one frame take OR frameLenght -- how many ticks does one frame take OR
isMechanical -- a bool that says to try to match to mechanical system (i.e. how gears are turning) isMechanical -- a bool that says to try to match to mechanical system (i.e. how gears are turning)
} }
]] ]]
_registeredStuff={} _registeredStuff={}
local function unregall(state) local function unregall(state)
@ -29,23 +29,23 @@ local function unregall(state)
end end
end end
local function onUpdateLocal(workshop) local function onUpdateLocal(workshop)
local f=_registeredStuff[workshop:getCustomType()] local f=_registeredStuff[workshop:getCustomType()]
if f then if f then
f(workshop) f(workshop)
end end
end end
local function findCustomWorkshop(name) local function findCustomWorkshop(name)
local raws=df.global.world.raws.buildings.all local raws=df.global.world.raws.buildings.all
for k,v in ipairs(raws) do for k,v in ipairs(raws) do
if v.code==name then if v.code==name then
return v return v
end end
end end
end end
local function registerUpdateAction(shopId,callback) local function registerUpdateAction(shopId,callback)
_registeredStuff[shopId]=callback _registeredStuff[shopId]=callback
onUpdateAction._library=onUpdateLocal onUpdateAction._library=onUpdateLocal
dfhack.onStateChange.building_hacks=unregall dfhack.onStateChange.building_hacks=unregall
end end
local function generateFrame(tiles,w,h) local function generateFrame(tiles,w,h)
local mTiles={} local mTiles={}
@ -66,7 +66,7 @@ local function generateFrame(tiles,w,h)
return ret return ret
end end
local function processFrames(shop_def,frames) local function processFrames(shop_def,frames)
local w,h=shop_def.dim_x,shop_def.dim_y local w,h=shop_def.dim_x,shop_def.dim_y
for frame_id,frame in ipairs(frames) do for frame_id,frame in ipairs(frames) do
if frame[1].x~=nil then if frame[1].x~=nil then
frames[frame_id]=generateFrame(frame,w,h) frames[frame_id]=generateFrame(frame,w,h)
@ -75,35 +75,35 @@ local function processFrames(shop_def,frames)
return frames return frames
end end
function registerBuilding(args) function registerBuilding(args)
local shop_def=findCustomWorkshop(args.name) local shop_def=findCustomWorkshop(args.name)
local shop_id=shop_def.id local shop_id=shop_def.id
local fix_impassible local fix_impassible
if args.fix_impassible then if args.fix_impassible then
fix_impassible=1 fix_impassible=1
else else
fix_impassible=0 fix_impassible=0
end end
local consume=args.consume or 0 local consume=args.consume or 0
local produce=args.produce or 0 local produce=args.produce or 0
local gears=args.gears or {} local gears=args.gears or {}
local action=args.action --could be nil local action=args.action --could be nil
local updateSkip=0 local updateSkip=0
if action~=nil then if action~=nil then
updateSkip=action[1] updateSkip=action[1]
registerUpdateAction(shop_id,action[2]) registerUpdateAction(shop_id,action[2])
end end
local animate=args.animate local animate=args.animate
local frameLength=1 local frameLength=1
local frames local frames
if animate~=nil then if animate~=nil then
frameLength=animate.frameLength frameLength=animate.frameLength
if animate.isMechanical then if animate.isMechanical then
frameLength=-1 frameLength=-1
end end
frames=processFrames(shop_def,animate.frames) frames=processFrames(shop_def,animate.frames)
end end
local roomSubset=args.canBeRoomSubset or -1 local roomSubset=args.canBeRoomSubset or -1
addBuilding(shop_id,fix_impassible,consume,produce,gears,updateSkip,frames,frameLength,roomSubset) addBuilding(shop_id,fix_impassible,consume,produce,gears,updateSkip,frames,frameLength,roomSubset)
end end
return _ENV return _ENV

@ -211,26 +211,26 @@ function SimpleMenu:init(args)
self.items={} self.items={}
end end
function SimpleMenu:add(name,entry,hints) function SimpleMenu:add(name,entry,hints)
table.insert(self.items,{entry,name,hints}) table.insert(self.items,{entry,name,hints})
end end
function SimpleMenu:display() function SimpleMenu:display()
print("Select choice (q exits):") print("Select choice (q exits):")
for p,c in pairs(self.items) do for p,c in pairs(self.items) do
print(string.format("%3d).%s",p,c[2])) print(string.format("%3d).%s",p,c[2]))
end end
local ans local ans
repeat repeat
local r local r
r=dfhack.lineedit() r=dfhack.lineedit()
if r==nil then return end if r==nil then return end
if r=='q' then return end if r=='q' then return end
ans=tonumber(r) ans=tonumber(r)
if ans==nil or not(ans<=#self.items and ans>0) then if ans==nil or not(ans<=#self.items and ans>0) then
print("Invalid choice.") print("Invalid choice.")
end end
until ans~=nil and (ans<=#self.items and ans>0) until ans~=nil and (ans<=#self.items and ans>0)
if type(self.items[ans][1])=="function" then if type(self.items[ans][1])=="function" then
self.items[ans][1]() self.items[ans][1]()
else else

@ -3,94 +3,94 @@ local dfu=require("plugins.dfusion")
local tools=require("plugins.dfusion.tools") local tools=require("plugins.dfusion.tools")
menu=dfu.SimpleMenu() menu=dfu.SimpleMenu()
function Reincarnate(trg_unit,swap_soul) --only for adventurer i guess function Reincarnate(trg_unit,swap_soul) --only for adventurer i guess
if swap_soul==nil then if swap_soul==nil then
swap_soul=true swap_soul=true
end end
local adv=trg_unit or df.global.world.units.active[0] local adv=trg_unit or df.global.world.units.active[0]
if adv.flags1.dead==false then if adv.flags1.dead==false then
qerror("You are not dead (yet)!") qerror("You are not dead (yet)!")
end end
local hist_fig=dfhack.units.getNemesis(adv).figure local hist_fig=dfhack.units.getNemesis(adv).figure
if hist_fig==nil then if hist_fig==nil then
qerror("No historical figure for adventurer...") qerror("No historical figure for adventurer...")
end end
local events=df.global.world.history.events local events=df.global.world.history.events
local trg_hist_fig local trg_hist_fig
for i=#events-1,0,-1 do -- reverse search because almost always it will be last entry for i=#events-1,0,-1 do -- reverse search because almost always it will be last entry
if df.history_event_hist_figure_diedst:is_instance(events[i]) then if df.history_event_hist_figure_diedst:is_instance(events[i]) then
--print("is instance:"..i) --print("is instance:"..i)
if events[i].victim_hf==hist_fig.id then if events[i].victim_hf==hist_fig.id then
--print("Is same id:"..i) --print("Is same id:"..i)
trg_hist_fig=events[i].slayer_hf trg_hist_fig=events[i].slayer_hf
if trg_hist_fig then if trg_hist_fig then
trg_hist_fig=df.historical_figure.find(trg_hist_fig) trg_hist_fig=df.historical_figure.find(trg_hist_fig)
end end
break break
end end
end end
end end
if trg_hist_fig ==nil then if trg_hist_fig ==nil then
qerror("Slayer not found") qerror("Slayer not found")
end end
local trg_unit=trg_hist_fig.unit_id local trg_unit=trg_hist_fig.unit_id
if trg_unit==nil then if trg_unit==nil then
qerror("Unit id not found!") qerror("Unit id not found!")
end end
local trg_unit_final=df.unit.find(trg_unit) local trg_unit_final=df.unit.find(trg_unit)
change_adv(trg_unit_final) change_adv(trg_unit_final)
if swap_soul then --actually add a soul... if swap_soul then --actually add a soul...
t_soul=adv.status.current_soul t_soul=adv.status.current_soul
adv.status.current_soul=df.NULL adv.status.current_soul=df.NULL
adv.status.souls:resize(0) adv.status.souls:resize(0)
trg_unit_final.status.current_soul=t_soul trg_unit_final.status.current_soul=t_soul
trg_unit_final.status.souls:insert(#trg_unit_final.status.souls,t_soul) trg_unit_final.status.souls:insert(#trg_unit_final.status.souls,t_soul)
end end
end end
menu:add("Reincarnate",Reincarnate,{{df.unit,"optional"}})-- bool, optional menu:add("Reincarnate",Reincarnate,{{df.unit,"optional"}})-- bool, optional
function change_adv(unit,nemesis) function change_adv(unit,nemesis)
if nemesis==nil then if nemesis==nil then
nemesis=true --default value is nemesis switch too. nemesis=true --default value is nemesis switch too.
end end
if unit==nil then if unit==nil then
unit=dfhack.gui.getSelectedUnit()--getCreatureAtPointer() unit=dfhack.gui.getSelectedUnit()--getCreatureAtPointer()
end end
if unit==nil then if unit==nil then
error("Invalid unit!") error("Invalid unit!")
end end
local other=df.global.world.units.active local other=df.global.world.units.active
local unit_indx local unit_indx
for k,v in pairs(other) do for k,v in pairs(other) do
if v==unit then if v==unit then
unit_indx=k unit_indx=k
break break
end end
end end
if unit_indx==nil then if unit_indx==nil then
error("Unit not found in array?!") --should not happen error("Unit not found in array?!") --should not happen
end end
other[unit_indx]=other[0] other[unit_indx]=other[0]
other[0]=unit other[0]=unit
if nemesis then --basicly copied from advtools plugin... if nemesis then --basicly copied from advtools plugin...
local nem=dfhack.units.getNemesis(unit) local nem=dfhack.units.getNemesis(unit)
local other_nem=dfhack.units.getNemesis(other[unit_indx]) local other_nem=dfhack.units.getNemesis(other[unit_indx])
if other_nem then if other_nem then
other_nem.flags[0]=false other_nem.flags[0]=false
other_nem.flags[1]=true other_nem.flags[1]=true
end end
if nem then if nem then
nem.flags[0]=true nem.flags[0]=true
nem.flags[2]=true nem.flags[2]=true
for k,v in pairs(df.global.world.nemesis.all) do for k,v in pairs(df.global.world.nemesis.all) do
if v.id==nem.id then if v.id==nem.id then
df.global.ui_advmode.player_id=k df.global.ui_advmode.player_id=k
end end
end end
else else
qerror("Current unit does not have nemesis record, further working not guaranteed") qerror("Current unit does not have nemesis record, further working not guaranteed")
end end
end end
end end
menu:add("Change adventurer",change_adv) menu:add("Change adventurer",change_adv)
function log_pos() function log_pos()

@ -20,203 +20,203 @@ function build_race_names()
end end
end end
function setrace(name) function setrace(name)
local RaceTable=build_race_names() local RaceTable=build_race_names()
print("Your current race is:"..df.global.world.raws.creatures.all[df.global.ui.race_id].creature_id) print("Your current race is:"..df.global.world.raws.creatures.all[df.global.ui.race_id].creature_id)
local id local id
if name == nil then if name == nil then
print("Type new race's token name in full caps (q to quit):") print("Type new race's token name in full caps (q to quit):")
repeat repeat
local entry=dfhack.lineedit() local entry=dfhack.lineedit()
if entry=="q" then if entry=="q" then
return return
end end
id=RaceTable[entry] id=RaceTable[entry]
until id~=nil until id~=nil
else else
id=RaceTable[name] id=RaceTable[name]
if id==nil then if id==nil then
error("Name not found!") error("Name not found!")
end end
end end
df.global.ui.race_id=id df.global.ui.race_id=id
end end
menu:add("Set current race",setrace) menu:add("Set current race",setrace)
function GiveSentience(names) function GiveSentience(names)
local RaceTable=build_race_names() --slow.If loaded don't load again local RaceTable=build_race_names() --slow.If loaded don't load again
local id,ids local id,ids
if names ==nil then if names ==nil then
ids={} ids={}
print("Type race's token name in full caps to give sentience to:") print("Type race's token name in full caps to give sentience to:")
repeat repeat
id=dfhack.lineedit() id=dfhack.lineedit()
id=RaceTable[entry] id=RaceTable[entry]
if id~=nil then if id~=nil then
table.insert(ids,id) table.insert(ids,id)
end end
until id==nil until id==nil
else else
ids={} ids={}
for _,name in pairs(names) do for _,name in pairs(names) do
id=RaceTable[name] id=RaceTable[name]
table.insert(ids,id) table.insert(ids,id)
end end
end end
for _,id in pairs(ids) do for _,id in pairs(ids) do
local races=df.global.world.raws.creatures.all local races=df.global.world.raws.creatures.all
local castes=races[id].caste local castes=races[id].caste
print(string.format("Caste count:%i",#castes)) print(string.format("Caste count:%i",#castes))
for i =0,#castes-1 do for i =0,#castes-1 do
print("Caste name:"..castes[i].caste_id.."...") print("Caste name:"..castes[i].caste_id.."...")
local flags=castes[i].flags local flags=castes[i].flags
--print(string.format("%x",flagoffset)) --print(string.format("%x",flagoffset))
if flags.CAN_SPEAK then if flags.CAN_SPEAK then
print("\tis sentient.") print("\tis sentient.")
else else
print("\tnon sentient. Allocating IQ...") print("\tnon sentient. Allocating IQ...")
flags.CAN_SPEAK=true flags.CAN_SPEAK=true
end end
end end
end end
end end
menu:add("Give Sentience",GiveSentience) menu:add("Give Sentience",GiveSentience)
function MakeFollow(unit,trgunit) function MakeFollow(unit,trgunit)
if unit == nil then if unit == nil then
unit=dfhack.gui.getSelectedUnit() unit=dfhack.gui.getSelectedUnit()
end end
if unit== nil then if unit== nil then
error("Invalid creature") error("Invalid creature")
end end
if trgunit==nil then if trgunit==nil then
trgunit=df.global.world.units.active[0] trgunit=df.global.world.units.active[0]
end end
unit.relations.group_leader_id=trgunit.id unit.relations.group_leader_id=trgunit.id
local u_nem=dfhack.units.getNemesis(unit) local u_nem=dfhack.units.getNemesis(unit)
local t_nem=dfhack.units.getNemesis(trgunit) local t_nem=dfhack.units.getNemesis(trgunit)
if u_nem then if u_nem then
u_nem.group_leader_id=t_nem.id u_nem.group_leader_id=t_nem.id
end end
if t_nem and u_nem then if t_nem and u_nem then
t_nem.companions:insert(#t_nem.companions,u_nem.id) t_nem.companions:insert(#t_nem.companions,u_nem.id)
end end
end end
menu:add("Make creature follow",MakeFollow) menu:add("Make creature follow",MakeFollow)
function project(unit,trg) --TODO add to menu? function project(unit,trg) --TODO add to menu?
if unit==nil then if unit==nil then
unit=getCreatureAtPointer() unit=getCreatureAtPointer()
end end
if unit==nil then if unit==nil then
error("Failed to project unit. Unit not selected/valid") error("Failed to project unit. Unit not selected/valid")
end end
-- todo: add projectile to world, point to unit, add flag to unit, add gen-ref to projectile. -- todo: add projectile to world, point to unit, add flag to unit, add gen-ref to projectile.
local p=df.proj_unitst:new() local p=df.proj_unitst:new()
local startpos={x=unit.pos.x,y=unit.pos.y,z=unit.pos.z} local startpos={x=unit.pos.x,y=unit.pos.y,z=unit.pos.z}
p.origin_pos=startpos p.origin_pos=startpos
p.target_pos=trg p.target_pos=trg
p.cur_pos=startpos p.cur_pos=startpos
p.prev_pos=startpos p.prev_pos=startpos
p.unit=unit p.unit=unit
--- wtf stuff --- wtf stuff
p.unk14=100 p.unk14=100
p.unk16=-1 p.unk16=-1
p.unk23=-1 p.unk23=-1
p.fall_delay=5 p.fall_delay=5
p.fall_counter=5 p.fall_counter=5
p.collided=true p.collided=true
-- end wtf -- end wtf
local citem=df.global.world.proj_list local citem=df.global.world.proj_list
local maxid=1 local maxid=1
local newlink=df.proj_list_link:new() local newlink=df.proj_list_link:new()
newlink.item=p newlink.item=p
while citem.item~= nil do while citem.item~= nil do
if citem.item.id>maxid then maxid=citem.item.id end if citem.item.id>maxid then maxid=citem.item.id end
if citem.next ~= nil then if citem.next ~= nil then
citem=citem.next citem=citem.next
else else
break break
end end
end end
p.id=maxid+1 p.id=maxid+1
newlink.prev=citem newlink.prev=citem
citem.next=newlink citem.next=newlink
local proj_ref=df.general_ref_projectile:new() local proj_ref=df.general_ref_projectile:new()
proj_ref.projectile_id=p.id proj_ref.projectile_id=p.id
unit.general_refs:insert(#unit.general_refs,proj_ref) unit.general_refs:insert(#unit.general_refs,proj_ref)
unit.flags1.projectile=true unit.flags1.projectile=true
end end
function empregnate(unit) function empregnate(unit)
if unit==nil then if unit==nil then
unit=dfhack.gui.getSelectedUnit() unit=dfhack.gui.getSelectedUnit()
end end
if unit==nil then if unit==nil then
error("Failed to empregnate. Unit not selected/valid") error("Failed to empregnate. Unit not selected/valid")
end end
if unit.curse then if unit.curse then
unit.curse.add_tags2.STERILE=false unit.curse.add_tags2.STERILE=false
end end
local genes = unit.appearance.genes local genes = unit.appearance.genes
if unit.relations.pregnancy_genes == nil then if unit.relations.pregnancy_genes == nil then
print("creating preg ptr.") print("creating preg ptr.")
if false then if false then
print(string.format("%x %x",df.sizeof(unit.relations:_field("pregnancy_genes")))) print(string.format("%x %x",df.sizeof(unit.relations:_field("pregnancy_genes"))))
return return
end end
unit.relations.pregnancy_genes = { new = true, assign = genes } unit.relations.pregnancy_genes = { new = true, assign = genes }
end end
local ngenes = unit.relations.pregnancy_genes local ngenes = unit.relations.pregnancy_genes
if #ngenes.appearance ~= #genes.appearance or #ngenes.colors ~= #genes.colors then if #ngenes.appearance ~= #genes.appearance or #ngenes.colors ~= #genes.colors then
print("Array sizes incorrect, fixing.") print("Array sizes incorrect, fixing.")
ngenes:assign(genes); ngenes:assign(genes);
end end
print("Setting preg timer.") print("Setting preg timer.")
unit.relations.pregnancy_timer=10 unit.relations.pregnancy_timer=10
unit.relations.pregnancy_caste=1 unit.relations.pregnancy_caste=1
end end
menu:add("Empregnate",empregnate) menu:add("Empregnate",empregnate)
function healunit(unit) function healunit(unit)
if unit==nil then if unit==nil then
unit=dfhack.gui.getSelectedUnit() unit=dfhack.gui.getSelectedUnit()
end end
if unit==nil then if unit==nil then
error("Failed to Heal unit. Unit not selected/valid") error("Failed to Heal unit. Unit not selected/valid")
end end
unit.body.wounds:resize(0) -- memory leak here :/ unit.body.wounds:resize(0) -- memory leak here :/
unit.body.blood_count=unit.body.blood_max unit.body.blood_count=unit.body.blood_max
--set flags for standing and grasping... --set flags for standing and grasping...
unit.status2.limbs_stand_max=4 unit.status2.limbs_stand_max=4
unit.status2.limbs_stand_count=4 unit.status2.limbs_stand_count=4
unit.status2.limbs_grasp_max=4 unit.status2.limbs_grasp_max=4
unit.status2.limbs_grasp_count=4 unit.status2.limbs_grasp_count=4
--should also set temperatures, and flags for breath etc... --should also set temperatures, and flags for breath etc...
unit.flags1.dead=false unit.flags1.dead=false
unit.flags2.calculated_bodyparts=false unit.flags2.calculated_bodyparts=false
unit.flags2.calculated_nerves=false unit.flags2.calculated_nerves=false
unit.flags2.circulatory_spray=false unit.flags2.circulatory_spray=false
unit.flags2.vision_good=true unit.flags2.vision_good=true
unit.flags2.vision_damaged=false unit.flags2.vision_damaged=false
unit.flags2.vision_missing=false unit.flags2.vision_missing=false
unit.counters.winded=0 unit.counters.winded=0
unit.counters.unconscious=0 unit.counters.unconscious=0
for k,v in pairs(unit.body.components) do for k,v in pairs(unit.body.components) do
for kk,vv in pairs(v) do for kk,vv in pairs(v) do
if k == 'body_part_status' then v[kk].whole = 0 else v[kk] = 0 end if k == 'body_part_status' then v[kk].whole = 0 else v[kk] = 0 end
end end
end end
end end
menu:add("Heal unit",healunit) menu:add("Heal unit",healunit)
function powerup(unit,labor_rating,military_rating,skills) function powerup(unit,labor_rating,military_rating,skills)
if unit==nil then if unit==nil then
unit=dfhack.gui.getSelectedUnit() unit=dfhack.gui.getSelectedUnit()
end end
if unit==nil then if unit==nil then
error("Failed to power up unit. Unit not selected/valid") error("Failed to power up unit. Unit not selected/valid")
end end
if unit.status.current_soul== nil then if unit.status.current_soul== nil then
error("Failed to power up unit. Unit has no soul") error("Failed to power up unit. Unit has no soul")

@ -5,23 +5,23 @@ message Tile
{ {
enum TileType enum TileType
{ {
EMPTY = 0; EMPTY = 0;
FLOOR = 1; FLOOR = 1;
BOULDER = 2; BOULDER = 2;
PEBBLES = 3; PEBBLES = 3;
WALL = 4; WALL = 4;
FORTIFICATION = 5; FORTIFICATION = 5;
STAIR_UP = 6; STAIR_UP = 6;
STAIR_DOWN = 7; STAIR_DOWN = 7;
STAIR_UPDOWN = 8; STAIR_UPDOWN = 8;
RAMP = 9; RAMP = 9;
RAMP_TOP = 10; RAMP_TOP = 10;
BROOK_BED = 11; BROOK_BED = 11;
BROOK_TOP = 12; BROOK_TOP = 12;
TREE = 13; TREE = 13;
SAPLING = 14; SAPLING = 14;
SHRUB = 15; SHRUB = 15;
ENDLESS_PIT = 16; ENDLESS_PIT = 16;
} }
enum LiquidType enum LiquidType
{ {
@ -49,8 +49,8 @@ message Tile
MAGMA_TYPE = 16; MAGMA_TYPE = 16;
DRIFTWOOD = 17; DRIFTWOOD = 17;
POOL = 18; POOL = 18;
BROOK = 19; BROOK = 19;
RIVER = 20; RIVER = 20;
} }
required uint32 x = 1; required uint32 x = 1;
required uint32 y = 2; required uint32 y = 2;

@ -6,203 +6,203 @@ option optimize_for = LITE_RUNTIME;
//We use shapes, etc, because the actual tiletypes may differ between DF versions. //We use shapes, etc, because the actual tiletypes may differ between DF versions.
enum TiletypeShape enum TiletypeShape
{ {
NO_SHAPE = -1; NO_SHAPE = -1;
EMPTY = 0; EMPTY = 0;
FLOOR = 1; FLOOR = 1;
BOULDER = 2; BOULDER = 2;
PEBBLES = 3; PEBBLES = 3;
WALL = 4; WALL = 4;
FORTIFICATION = 5; FORTIFICATION = 5;
STAIR_UP = 6; STAIR_UP = 6;
STAIR_DOWN = 7; STAIR_DOWN = 7;
STAIR_UPDOWN = 8; STAIR_UPDOWN = 8;
RAMP = 9; RAMP = 9;
RAMP_TOP = 10; RAMP_TOP = 10;
BROOK_BED = 11; BROOK_BED = 11;
BROOK_TOP = 12; BROOK_TOP = 12;
TREE_SHAPE = 13; TREE_SHAPE = 13;
SAPLING = 14; SAPLING = 14;
SHRUB = 15; SHRUB = 15;
ENDLESS_PIT = 16; ENDLESS_PIT = 16;
BRANCH = 17; BRANCH = 17;
TRUNK_BRANCH = 18; TRUNK_BRANCH = 18;
TWIG = 19; TWIG = 19;
} }
enum TiletypeSpecial enum TiletypeSpecial
{ {
NO_SPECIAL = -1; NO_SPECIAL = -1;
NORMAL = 0; NORMAL = 0;
RIVER_SOURCE = 1; RIVER_SOURCE = 1;
WATERFALL = 2; WATERFALL = 2;
SMOOTH = 3; SMOOTH = 3;
FURROWED = 4; FURROWED = 4;
WET = 5; WET = 5;
DEAD = 6; DEAD = 6;
WORN_1 = 7; WORN_1 = 7;
WORN_2 = 8; WORN_2 = 8;
WORN_3 = 9; WORN_3 = 9;
TRACK = 10; TRACK = 10;
SMOOTH_DEAD = 11; SMOOTH_DEAD = 11;
}; };
enum TiletypeMaterial enum TiletypeMaterial
{ {
NO_MATERIAL = -1; NO_MATERIAL = -1;
AIR = 0; AIR = 0;
SOIL = 1; SOIL = 1;
STONE = 2; STONE = 2;
FEATURE = 3; FEATURE = 3;
LAVA_STONE = 4; LAVA_STONE = 4;
MINERAL = 5; MINERAL = 5;
FROZEN_LIQUID = 6; FROZEN_LIQUID = 6;
CONSTRUCTION = 7; CONSTRUCTION = 7;
GRASS_LIGHT = 8; GRASS_LIGHT = 8;
GRASS_DARK = 9; GRASS_DARK = 9;
GRASS_DRY = 10; GRASS_DRY = 10;
GRASS_DEAD = 11; GRASS_DEAD = 11;
PLANT = 12; PLANT = 12;
HFS = 13; HFS = 13;
CAMPFIRE = 14; CAMPFIRE = 14;
FIRE = 15; FIRE = 15;
ASHES = 16; ASHES = 16;
MAGMA = 17; MAGMA = 17;
DRIFTWOOD = 18; DRIFTWOOD = 18;
POOL = 19; POOL = 19;
BROOK = 20; BROOK = 20;
RIVER = 21; RIVER = 21;
ROOT = 22; ROOT = 22;
TREE_MATERIAL = 23; TREE_MATERIAL = 23;
MUSHROOM = 24; MUSHROOM = 24;
UNDERWORLD_GATE = 25; UNDERWORLD_GATE = 25;
} }
enum TiletypeVariant enum TiletypeVariant
{ {
NO_VARIANT = -1; NO_VARIANT = -1;
VAR_1 = 0; VAR_1 = 0;
VAR_2 = 1; VAR_2 = 1;
VAR_3 = 2; VAR_3 = 2;
VAR_4 = 3; VAR_4 = 3;
}; };
message Tiletype message Tiletype
{ {
required int32 id = 1; required int32 id = 1;
optional string name = 2; optional string name = 2;
optional string caption = 3; optional string caption = 3;
optional TiletypeShape shape = 4; optional TiletypeShape shape = 4;
optional TiletypeSpecial special = 5; optional TiletypeSpecial special = 5;
optional TiletypeMaterial material = 6; optional TiletypeMaterial material = 6;
optional TiletypeVariant variant = 7; optional TiletypeVariant variant = 7;
optional string direction = 8; optional string direction = 8;
}; };
message TiletypeList message TiletypeList
{ {
repeated Tiletype tiletype_list = 1; repeated Tiletype tiletype_list = 1;
} }
message MapBlock message MapBlock
{ {
required int32 map_x = 1; required int32 map_x = 1;
required int32 map_y = 2; required int32 map_y = 2;
required int32 map_z = 3; required int32 map_z = 3;
repeated int32 tiles = 4; repeated int32 tiles = 4;
repeated MatPair materials = 5; repeated MatPair materials = 5;
repeated MatPair layer_materials = 6; repeated MatPair layer_materials = 6;
repeated MatPair vein_materials = 7; repeated MatPair vein_materials = 7;
repeated MatPair base_materials = 8; repeated MatPair base_materials = 8;
repeated int32 magma = 9; repeated int32 magma = 9;
repeated int32 water = 10; repeated int32 water = 10;
} }
message MatPair { message MatPair {
required int32 mat_type = 1; required int32 mat_type = 1;
required int32 mat_index = 2; required int32 mat_index = 2;
} }
message ColorDefinition { message ColorDefinition {
required int32 red = 1; required int32 red = 1;
required int32 green = 2; required int32 green = 2;
required int32 blue = 3; required int32 blue = 3;
} }
message MaterialDefinition{ message MaterialDefinition{
required MatPair mat_pair = 1; required MatPair mat_pair = 1;
optional string id = 2; optional string id = 2;
optional string name = 3; optional string name = 3;
optional ColorDefinition state_color = 4; //Simplifying colors to assume room temperature. optional ColorDefinition state_color = 4; //Simplifying colors to assume room temperature.
} }
message MaterialList{ message MaterialList{
repeated MaterialDefinition material_list = 1; repeated MaterialDefinition material_list = 1;
} }
message UnitDefinition message UnitDefinition
{ {
required int32 id = 1; required int32 id = 1;
optional bool isValid = 2; optional bool isValid = 2;
optional int32 pos_x = 3; optional int32 pos_x = 3;
optional int32 pos_y = 4; optional int32 pos_y = 4;
optional int32 pos_z = 5; optional int32 pos_z = 5;
} }
message UnitList message UnitList
{ {
repeated UnitDefinition creature_list = 1; repeated UnitDefinition creature_list = 1;
} }
message BlockRequest message BlockRequest
{ {
optional int32 blocks_needed = 1; optional int32 blocks_needed = 1;
optional int32 min_x = 2; optional int32 min_x = 2;
optional int32 max_x = 3; optional int32 max_x = 3;
optional int32 min_y = 4; optional int32 min_y = 4;
optional int32 max_y = 5; optional int32 max_y = 5;
optional int32 min_z = 6; optional int32 min_z = 6;
optional int32 max_z = 7; optional int32 max_z = 7;
} }
message BlockList message BlockList
{ {
repeated MapBlock map_blocks = 1; repeated MapBlock map_blocks = 1;
optional int32 map_x = 2; optional int32 map_x = 2;
optional int32 map_y = 3; optional int32 map_y = 3;
} }
message PlantDef message PlantDef
{ {
required int32 pos_x = 1; required int32 pos_x = 1;
required int32 pos_y = 2; required int32 pos_y = 2;
required int32 pos_z = 3; required int32 pos_z = 3;
required int32 index = 4; required int32 index = 4;
} }
message PlantList message PlantList
{ {
repeated PlantDef plant_list = 1; repeated PlantDef plant_list = 1;
} }
message ViewInfo message ViewInfo
{ {
optional int32 view_pos_x = 1; optional int32 view_pos_x = 1;
optional int32 view_pos_y = 2; optional int32 view_pos_y = 2;
optional int32 view_pos_z = 3; optional int32 view_pos_z = 3;
optional int32 view_size_x = 4; optional int32 view_size_x = 4;
optional int32 view_size_y = 5; optional int32 view_size_y = 5;
optional int32 cursor_pos_x = 6; optional int32 cursor_pos_x = 6;
optional int32 cursor_pos_y = 7; optional int32 cursor_pos_y = 7;
optional int32 cursor_pos_z = 8; optional int32 cursor_pos_z = 8;
} }
message MapInfo message MapInfo
{ {
optional int32 block_size_x = 1; optional int32 block_size_x = 1;
optional int32 block_size_y = 2; optional int32 block_size_y = 2;
optional int32 block_size_z = 3; optional int32 block_size_z = 3;
optional int32 block_pos_x = 4; optional int32 block_pos_x = 4;
optional int32 block_pos_y = 5; optional int32 block_pos_y = 5;
optional int32 block_pos_z = 6; optional int32 block_pos_z = 6;
optional string world_name = 7; optional string world_name = 7;
optional string world_name_english = 8; optional string world_name_english = 8;
optional string save_name = 9; optional string save_name = 9;
} }

@ -4,73 +4,73 @@ package isoworldremote;
option optimize_for = LITE_RUNTIME; option optimize_for = LITE_RUNTIME;
enum BasicMaterial { enum BasicMaterial {
AIR = 0; AIR = 0;
OTHER = 1; OTHER = 1;
INORGANIC = 2; INORGANIC = 2;
LIQUID = 3; LIQUID = 3;
PLANT = 4; PLANT = 4;
WOOD = 5; WOOD = 5;
}; };
enum LiquidType { enum LiquidType {
ICE = 0; ICE = 0;
WATER = 1; WATER = 1;
MAGMA = 2; MAGMA = 2;
} }
enum BasicShape { enum BasicShape {
NONE = 0; NONE = 0;
OPEN = 1; OPEN = 1;
WALL = 3; WALL = 3;
FLOOR = 4; FLOOR = 4;
RAMP_UP = 5; RAMP_UP = 5;
RAMP_DOWN = 6; RAMP_DOWN = 6;
} }
message ColorDefinition { message ColorDefinition {
required int32 red = 1; required int32 red = 1;
required int32 green = 2; required int32 green = 2;
required int32 blue = 3; required int32 blue = 3;
} }
message EmbarkTileLayer { message EmbarkTileLayer {
repeated BasicMaterial mat_type_table = 4 [packed=true]; repeated BasicMaterial mat_type_table = 4 [packed=true];
repeated int32 mat_subtype_table = 5 [packed=true]; repeated int32 mat_subtype_table = 5 [packed=true];
repeated BasicShape tile_shape_table = 6 [packed=true]; repeated BasicShape tile_shape_table = 6 [packed=true];
repeated ColorDefinition tile_color_table = 7; repeated ColorDefinition tile_color_table = 7;
} }
message EmbarkTile { message EmbarkTile {
required int32 world_x = 1; required int32 world_x = 1;
required int32 world_y = 2; required int32 world_y = 2;
required sint32 world_z = 3; required sint32 world_z = 3;
repeated EmbarkTileLayer tile_layer = 4; repeated EmbarkTileLayer tile_layer = 4;
optional int32 current_year = 5; optional int32 current_year = 5;
optional int32 current_season = 6; optional int32 current_season = 6;
optional bool is_valid = 7; optional bool is_valid = 7;
} }
message TileRequest { message TileRequest {
optional int32 want_x = 1; optional int32 want_x = 1;
optional int32 want_y = 2; optional int32 want_y = 2;
} }
message MapRequest { message MapRequest {
optional string save_folder = 1; optional string save_folder = 1;
} }
message MapReply { message MapReply {
required bool available = 1; required bool available = 1;
optional int32 region_x = 2; optional int32 region_x = 2;
optional int32 region_y = 3; optional int32 region_y = 3;
optional int32 region_size_x = 4; optional int32 region_size_x = 4;
optional int32 region_size_y = 5; optional int32 region_size_y = 5;
optional int32 current_year = 6; optional int32 current_year = 6;
optional int32 current_season = 7; optional int32 current_season = 7;
} }
message RawNames { message RawNames {
required bool available = 1; required bool available = 1;
repeated string inorganic = 2; repeated string inorganic = 2;
repeated string organic = 3; repeated string organic = 3;
} }

@ -276,7 +276,7 @@ class lightingEngineViewscreen:public lightingEngine
{ {
public: public:
lightingEngineViewscreen(renderer_light* target); lightingEngineViewscreen(renderer_light* target);
~lightingEngineViewscreen(); ~lightingEngineViewscreen();
void reinit(); void reinit();
void calculate(); void calculate();
@ -296,7 +296,7 @@ private:
rgbf propogateSun(MapExtras::Block* b, int x,int y,const rgbf& in,bool lastLevel); rgbf propogateSun(MapExtras::Block* b, int x,int y,const rgbf& in,bool lastLevel);
void doRay(std::vector<rgbf> & target, rgbf power,int cx,int cy,int tx,int ty); void doRay(std::vector<rgbf> & target, rgbf power,int cx,int cy,int tx,int ty);
void doFovs(); void doFovs();
void doLight(std::vector<rgbf> & target, int index); void doLight(std::vector<rgbf> & target, int index);
rgbf lightUpCell(std::vector<rgbf> & target, rgbf power,int dx,int dy,int tx,int ty); rgbf lightUpCell(std::vector<rgbf> & target, rgbf power,int dx,int dy,int tx,int ty);
bool addLight(int tileId,const lightSource& light); bool addLight(int tileId,const lightSource& light);
void addOclusion(int tileId,const rgbf& c,float thickness); void addOclusion(int tileId,const rgbf& c,float thickness);
@ -333,7 +333,7 @@ private:
int getW()const {return w;} int getW()const {return w;}
int getH()const {return h;} int getH()const {return h;}
public: public:
void lightWorkerThread(void * arg); void lightWorkerThread(void * arg);
private: private:
rgbf getSkyColor(float v); rgbf getSkyColor(float v);
bool doDebug; bool doDebug;

@ -11,164 +11,164 @@ for k,v in pairs(ret) do
end end
-- add material by id (index,mat pair or token string or a type number), flags is a table of strings -- add material by id (index,mat pair or token string or a type number), flags is a table of strings
-- supported flags (but not implemented): -- supported flags (but not implemented):
-- flicker -- flicker
function addMaterial(id,transparency,emitance,radius,flags) function addMaterial(id,transparency,emitance,radius,flags)
local matinfo local matinfo
if type(id)=="string" then if type(id)=="string" then
matinfo=dfhack.matinfo.find(id) matinfo=dfhack.matinfo.find(id)
elseif type(id)=="table" then elseif type(id)=="table" then
matinfo=dfhack.matinfo.decode(id[1],id[2]) matinfo=dfhack.matinfo.decode(id[1],id[2])
else else
matinfo=dfhack.matinfo.decode(id,0) matinfo=dfhack.matinfo.decode(id,0)
end end
if matinfo==nil then if matinfo==nil then
error("Material not found") error("Material not found")
end end
materials[matinfo.type]=materials[matinfo.type] or {} materials[matinfo.type]=materials[matinfo.type] or {}
materials[matinfo.type][matinfo.index]=makeMaterialDef(transparency,emitance,radius,flags) materials[matinfo.type][matinfo.index]=makeMaterialDef(transparency,emitance,radius,flags)
end end
function buildingLookUp(id) function buildingLookUp(id)
local tokens={} local tokens={}
local lookup={ Workshop=df.workshop_type,Furnace=df.furnace_type,Trap=df.trap_type, local lookup={ Workshop=df.workshop_type,Furnace=df.furnace_type,Trap=df.trap_type,
SiegeEngine=df.siegeengine_type} SiegeEngine=df.siegeengine_type}
for i in string.gmatch(id, "[^:]+") do for i in string.gmatch(id, "[^:]+") do
table.insert(tokens,i) table.insert(tokens,i)
end end
local ret={} local ret={}
ret.type=df.building_type[tokens[1]] ret.type=df.building_type[tokens[1]]
if tokens[2] then if tokens[2] then
local type_array=lookup[tokens[1]] local type_array=lookup[tokens[1]]
if type_array then if type_array then
ret.subtype=type_array[tokens[2]] ret.subtype=type_array[tokens[2]]
end end
if tokens[2]=="Custom" and tokens[3] then --TODO cache for faster lookup if tokens[2]=="Custom" and tokens[3] then --TODO cache for faster lookup
if ret.type==df.building_type.Workshop then if ret.type==df.building_type.Workshop then
for k,v in pairs(df.global.world.raws.buildings.workshops) do for k,v in pairs(df.global.world.raws.buildings.workshops) do
if v.code==tokens[3] then if v.code==tokens[3] then
ret.custom=v.id ret.custom=v.id
return ret return ret
end end
end end
elseif ret.type==df.building_type.Furnace then elseif ret.type==df.building_type.Furnace then
for k,v in pairs(df.global.world.raws.buildings.furnaces) do for k,v in pairs(df.global.world.raws.buildings.furnaces) do
if v.code==tokens[3] then if v.code==tokens[3] then
ret.custom=v.id ret.custom=v.id
return ret return ret
end end
end end
end end
end end
qerror("Invalid custom building:"..tokens[3]) qerror("Invalid custom building:"..tokens[3])
end end
return ret return ret
end end
function itemLookup(id) function itemLookup(id)
local ret={} local ret={}
local tokens={} local tokens={}
for i in string.gmatch(id, "[^:]+") do for i in string.gmatch(id, "[^:]+") do
table.insert(tokens,i) table.insert(tokens,i)
end end
ret.type=df.item_type[tokens[1]] ret.type=df.item_type[tokens[1]]
ret.subtype=-1 ret.subtype=-1
if tokens[2] then if tokens[2] then
for k,v in ipairs(df.global.world.raws.itemdefs.all) do --todo lookup correct itemdef for k,v in ipairs(df.global.world.raws.itemdefs.all) do --todo lookup correct itemdef
if v.id==tokens[2] then if v.id==tokens[2] then
ret.subtype=v.subtype ret.subtype=v.subtype
return ret return ret
end end
end end
qerror("Failed item subtype lookup:"..tokens[2]) qerror("Failed item subtype lookup:"..tokens[2])
end end
return ret return ret
end end
function creatureLookup(id) function creatureLookup(id)
local ret={} local ret={}
local tokens={} local tokens={}
for i in string.gmatch(id, "[^:]+") do for i in string.gmatch(id, "[^:]+") do
table.insert(tokens,i) table.insert(tokens,i)
end end
for k,v in ipairs(df.global.world.raws.creatures.all) do for k,v in ipairs(df.global.world.raws.creatures.all) do
if v.creature_id==tokens[1] then if v.creature_id==tokens[1] then
ret.type=k ret.type=k
if tokens[2] then if tokens[2] then
for k,v in ipairs(v.caste) do for k,v in ipairs(v.caste) do
if v.caste_id==tokens[2] then if v.caste_id==tokens[2] then
ret.subtype=k ret.subtype=k
break break
end end
end end
if ret.subtype==nil then if ret.subtype==nil then
qerror("caste "..tokens[2].." for "..tokens[1].." not found") qerror("caste "..tokens[2].." for "..tokens[1].." not found")
end end
end end
return ret return ret
end end
end end
qerror("Failed to find race:"..tokens[1]) qerror("Failed to find race:"..tokens[1])
end end
-- add creature by id ("DWARF" or "DWARF:MALE") -- add creature by id ("DWARF" or "DWARF:MALE")
-- supported flags: -- supported flags:
function addCreature(id,transparency,emitance,radius,flags) function addCreature(id,transparency,emitance,radius,flags)
local crId=creatureLookup(id) local crId=creatureLookup(id)
local mat=makeMaterialDef(transparency,emitance,radius,flags) local mat=makeMaterialDef(transparency,emitance,radius,flags)
table.insert(creatures,{race=crId.type,caste=crId.subtype or -1, light=mat}) table.insert(creatures,{race=crId.type,caste=crId.subtype or -1, light=mat})
end end
-- add item by id ( "TOTEM" or "WEAPON:PICK" or "WEAPON" for all the weapon types) -- add item by id ( "TOTEM" or "WEAPON:PICK" or "WEAPON" for all the weapon types)
-- supported flags: -- supported flags:
-- hauling --active when hauled TODO::currently all mean same thing... -- hauling --active when hauled TODO::currently all mean same thing...
-- equiped --active while equiped TODO::currently all mean same thing... -- equiped --active while equiped TODO::currently all mean same thing...
-- inBuilding --active in building TODO::currently all mean same thing... -- inBuilding --active in building TODO::currently all mean same thing...
-- contained --active in container TODO::currently all mean same thing... -- contained --active in container TODO::currently all mean same thing...
-- onGround --active on ground -- onGround --active on ground
-- useMaterial --uses material, but the defined things overwrite -- useMaterial --uses material, but the defined things overwrite
function addItem(id,transparency,emitance,radius,flags) function addItem(id,transparency,emitance,radius,flags)
local itemId=itemLookup(id) local itemId=itemLookup(id)
local mat=makeMaterialDef(transparency,emitance,radius,flags) local mat=makeMaterialDef(transparency,emitance,radius,flags)
table.insert(items,{["type"]=itemId.type,subtype=itemId.subtype,light=mat}) table.insert(items,{["type"]=itemId.type,subtype=itemId.subtype,light=mat})
end end
-- add building by id (string e.g. "Statue" or "Workshop:Masons", flags is a table of strings -- add building by id (string e.g. "Statue" or "Workshop:Masons", flags is a table of strings
-- supported flags: -- supported flags:
-- useMaterial --uses material, but the defined things overwrite -- useMaterial --uses material, but the defined things overwrite
-- poweredOnly --glow only when powered -- poweredOnly --glow only when powered
function addBuilding(id,transparency,emitance,radius,flags,size,thickness) function addBuilding(id,transparency,emitance,radius,flags,size,thickness)
size=size or 1 size=size or 1
thickness=thickness or 1 thickness=thickness or 1
local bld=buildingLookUp(id) local bld=buildingLookUp(id)
local mat=makeMaterialDef(transparency,emitance,radius,flags) local mat=makeMaterialDef(transparency,emitance,radius,flags)
mat.size=size mat.size=size
mat.thickness=thickness mat.thickness=thickness
buildings[bld.type]=buildings[bld.type] or {} buildings[bld.type]=buildings[bld.type] or {}
if bld.subtype then if bld.subtype then
if bld.custom then if bld.custom then
buildings[bld.type][bld.subtype]=buildings[bld.type][bld.subtype] or {} buildings[bld.type][bld.subtype]=buildings[bld.type][bld.subtype] or {}
buildings[bld.type][bld.subtype][bld.custom]=mat buildings[bld.type][bld.subtype][bld.custom]=mat
else else
buildings[bld.type][bld.subtype]={[-1]=mat} buildings[bld.type][bld.subtype]={[-1]=mat}
end end
else else
buildings[bld.type][-1]={[-1]=mat} buildings[bld.type][-1]={[-1]=mat}
end end
end end
function makeMaterialDef(transparency,emitance,radius,flags) function makeMaterialDef(transparency,emitance,radius,flags)
local flg local flg
if flags then if flags then
flg={} flg={}
for k,v in ipairs(flags) do for k,v in ipairs(flags) do
flg[v]=true flg[v]=true
end end
end end
return {tr=transparency,em=emitance,rad=radius,flags=flg} return {tr=transparency,em=emitance,rad=radius,flags=flg}
end end
function colorFrom16(col16) function colorFrom16(col16)
local col=df.global.enabler.ccolor[col16] local col=df.global.enabler.ccolor[col16]
return {col[0],col[1],col[2]} return {col[0],col[1],col[2]}
end end
function addGems() function addGems()
for k,v in pairs(df.global.world.raws.inorganics) do for k,v in pairs(df.global.world.raws.inorganics) do
if v.material.flags.IS_GEM then if v.material.flags.IS_GEM then
addMaterial("INORGANIC:"..v.id,colorFrom16(v.material.tile_color[0]+v.material.tile_color[2]*8)) addMaterial("INORGANIC:"..v.id,colorFrom16(v.material.tile_color[0]+v.material.tile_color[2]*8))
end end
end end
end end
------------------------------------------------------------------------ ------------------------------------------------------------------------
---------------- Configuration Starts Here ------------------------- ---------------- Configuration Starts Here -------------------------
@ -184,30 +184,30 @@ special.CITIZEN=makeMaterialDef(nil,{0.80,0.80,0.90},6)
special.LevelDim=0.2 -- darkness. Do not set to 0 special.LevelDim=0.2 -- darkness. Do not set to 0
special.dayHour=-1 -- <0 cycle, else hour of the day special.dayHour=-1 -- <0 cycle, else hour of the day
special.dayColors={ {0,0,0}, --dark at 0 hours special.dayColors={ {0,0,0}, --dark at 0 hours
{0.6,0.5,0.5}, --reddish twilight {0.6,0.5,0.5}, --reddish twilight
{1,1,1}, --fullbright at 12 hours {1,1,1}, --fullbright at 12 hours
{0.5,0.5,0.5}, {0.5,0.5,0.5},
{0,0,0}} --dark at 24 hours {0,0,0}} --dark at 24 hours
special.daySpeed=1 -- 1->1200 cur_year_ticks per day. 2->600 ticks special.daySpeed=1 -- 1->1200 cur_year_ticks per day. 2->600 ticks
special.diffusionCount=1 -- split beam max 1 times to mimic diffuse lights special.diffusionCount=1 -- split beam max 1 times to mimic diffuse lights
special.advMode=0 -- 1 or 0 different modes for adv mode. 0-> use df vision system, special.advMode=0 -- 1 or 0 different modes for adv mode. 0-> use df vision system,
-- 1(does not work)->everything visible, let rendermax light do the work -- 1(does not work)->everything visible, let rendermax light do the work
--TODO dragonfire --TODO dragonfire
--materials --materials
-- glasses -- glasses
addMaterial("GLASS_GREEN",{0.1,0.9,0.5}) addMaterial("GLASS_GREEN",{0.1,0.9,0.5})
addMaterial("GLASS_CLEAR",{0.5,0.95,0.9}) addMaterial("GLASS_CLEAR",{0.5,0.95,0.9})
addMaterial("GLASS_CRYSTAL",{0.75,0.95,0.95}) addMaterial("GLASS_CRYSTAL",{0.75,0.95,0.95})
-- Plants -- Plants
addMaterial("PLANT:TOWER_CAP",nil,{0.65,0.65,0.65},6) addMaterial("PLANT:TOWER_CAP",nil,{0.65,0.65,0.65},6)
addMaterial("PLANT:MUSHROOM_CUP_DIMPLE",nil,{0.03,0.03,0.5},3) addMaterial("PLANT:MUSHROOM_CUP_DIMPLE",nil,{0.03,0.03,0.5},3)
addMaterial("PLANT:CAVE MOSS",nil,{0.1,0.1,0.4},2) addMaterial("PLANT:CAVE MOSS",nil,{0.1,0.1,0.4},2)
addMaterial("PLANT:MUSHROOM_HELMET_PLUMP",nil,{0.2,0.1,0.6},2) addMaterial("PLANT:MUSHROOM_HELMET_PLUMP",nil,{0.2,0.1,0.6},2)
-- inorganics -- inorganics
addMaterial("INORGANIC:ADAMANTINE",{0.1,0.3,0.3},{0.1,0.3,0.3},4) addMaterial("INORGANIC:ADAMANTINE",{0.1,0.3,0.3},{0.1,0.3,0.3},4)
-- creature stuff -- creature stuff
addMaterial("CREATURE:DRAGON:BLOOD",nil,{0.6,0.1,0.1},4) addMaterial("CREATURE:DRAGON:BLOOD",nil,{0.6,0.1,0.1},4)
addGems() addGems()
--buildings --buildings

@ -1 +1 @@
Subproject commit 8270ef2892b640a2e5753844a5e917ba96523fbb Subproject commit a8c5bd263306050ac1dc21140ce52719b0dd598b

@ -1,136 +1,136 @@
class AutoFarm class AutoFarm
def initialize def initialize
@thresholds = Hash.new(50) @thresholds = Hash.new(50)
@lastcounts = Hash.new(0) @lastcounts = Hash.new(0)
end end
def setthreshold(id, v) def setthreshold(id, v)
list = df.world.raws.plants.all.find_all { |plt| plt.flags[:SEED] }.map { |plt| plt.id } list = df.world.raws.plants.all.find_all { |plt| plt.flags[:SEED] }.map { |plt| plt.id }
if tok = df.match_rawname(id, list) if tok = df.match_rawname(id, list)
@thresholds[tok] = v.to_i @thresholds[tok] = v.to_i
else else
puts "No plant with id #{id}, try one of " + puts "No plant with id #{id}, try one of " +
list.map { |w| w =~ /[^\w]/ ? w.inspect : w }.sort.join(' ') list.map { |w| w =~ /[^\w]/ ? w.inspect : w }.sort.join(' ')
end end
end end
def setdefault(v) def setdefault(v)
@thresholds.default = v.to_i @thresholds.default = v.to_i
end end
def is_plantable(plant) def is_plantable(plant)
has_seed = plant.flags[:SEED] has_seed = plant.flags[:SEED]
season = df.cur_season season = df.cur_season
harvest = df.cur_season_tick + plant.growdur * 10 harvest = df.cur_season_tick + plant.growdur * 10
will_finish = harvest < 10080 will_finish = harvest < 10080
can_plant = has_seed && plant.flags[season] can_plant = has_seed && plant.flags[season]
can_plant = can_plant && (will_finish || plant.flags[(season+1)%4]) can_plant = can_plant && (will_finish || plant.flags[(season+1)%4])
can_plant can_plant
end end
def find_plantable_plants def find_plantable_plants
plantable = {} plantable = {}
counts = Hash.new(0) counts = Hash.new(0)
df.world.items.other[:SEEDS].each { |i| df.world.items.other[:SEEDS].each { |i|
if (!i.flags.dump && !i.flags.forbid && !i.flags.garbage_collect && if (!i.flags.dump && !i.flags.forbid && !i.flags.garbage_collect &&
!i.flags.hostile && !i.flags.on_fire && !i.flags.rotten && !i.flags.hostile && !i.flags.on_fire && !i.flags.rotten &&
!i.flags.trader && !i.flags.in_building && !i.flags.construction && !i.flags.trader && !i.flags.in_building && !i.flags.construction &&
!i.flags.artifact) !i.flags.artifact)
counts[i.mat_index] += i.stack_size counts[i.mat_index] += i.stack_size
end end
} }
counts.keys.each { |i| counts.keys.each { |i|
if df.ui.tasks.discovered_plants[i] if df.ui.tasks.discovered_plants[i]
plant = df.world.raws.plants.all[i] plant = df.world.raws.plants.all[i]
if is_plantable(plant) if is_plantable(plant)
plantable[i] = :Surface if (plant.underground_depth_min == 0 || plant.underground_depth_max == 0) plantable[i] = :Surface if (plant.underground_depth_min == 0 || plant.underground_depth_max == 0)
plantable[i] = :Underground if (plant.underground_depth_min > 0 || plant.underground_depth_max > 0) plantable[i] = :Underground if (plant.underground_depth_min > 0 || plant.underground_depth_max > 0)
end end
end end
} }
return plantable return plantable
end end
def set_farms(plants, farms) def set_farms(plants, farms)
return if farms.length == 0 return if farms.length == 0
if plants.length == 0 if plants.length == 0
plants = [-1] plants = [-1]
end end
season = df.cur_season season = df.cur_season
farms.each_with_index { |f, idx| farms.each_with_index { |f, idx|
f.plant_id[season] = plants[idx % plants.length] f.plant_id[season] = plants[idx % plants.length]
} }
end end
def process def process
plantable = find_plantable_plants plantable = find_plantable_plants
@lastcounts = Hash.new(0) @lastcounts = Hash.new(0)
df.world.items.other[:PLANT].each { |i| df.world.items.other[:PLANT].each { |i|
if (!i.flags.dump && !i.flags.forbid && !i.flags.garbage_collect && if (!i.flags.dump && !i.flags.forbid && !i.flags.garbage_collect &&
!i.flags.hostile && !i.flags.on_fire && !i.flags.rotten && !i.flags.hostile && !i.flags.on_fire && !i.flags.rotten &&
!i.flags.trader && !i.flags.in_building && !i.flags.construction && !i.flags.trader && !i.flags.in_building && !i.flags.construction &&
!i.flags.artifact && plantable.has_key?(i.mat_index)) !i.flags.artifact && plantable.has_key?(i.mat_index))
id = df.world.raws.plants.all[i.mat_index].id id = df.world.raws.plants.all[i.mat_index].id
@lastcounts[id] += i.stack_size @lastcounts[id] += i.stack_size
end end
} }
return unless @running return unless @running
plants_s = [] plants_s = []
plants_u = [] plants_u = []
plantable.each_key { |k| plantable.each_key { |k|
plant = df.world.raws.plants.all[k] plant = df.world.raws.plants.all[k]
if (@lastcounts[plant.id] < @thresholds[plant.id]) if (@lastcounts[plant.id] < @thresholds[plant.id])
plants_s.push(k) if plantable[k] == :Surface plants_s.push(k) if plantable[k] == :Surface
plants_u.push(k) if plantable[k] == :Underground plants_u.push(k) if plantable[k] == :Underground
end end
} }
farms_s = [] farms_s = []
farms_u = [] farms_u = []
df.world.buildings.other[:FARM_PLOT].each { |f| df.world.buildings.other[:FARM_PLOT].each { |f|
if (f.flags.exists) if (f.flags.exists)
underground = df.map_designation_at(f.centerx,f.centery,f.z).subterranean underground = df.map_designation_at(f.centerx,f.centery,f.z).subterranean
farms_s.push(f) unless underground farms_s.push(f) unless underground
farms_u.push(f) if underground farms_u.push(f) if underground
end end
} }
set_farms(plants_s, farms_s) set_farms(plants_s, farms_s)
set_farms(plants_u, farms_u) set_farms(plants_u, farms_u)
end end
def start def start
return if @running return if @running
@onupdate = df.onupdate_register('autofarm', 1200) { process } @onupdate = df.onupdate_register('autofarm', 1200) { process }
@running = true @running = true
end end
def stop def stop
df.onupdate_unregister(@onupdate) df.onupdate_unregister(@onupdate)
@running = false @running = false
end end
def status def status
stat = @running ? "Running." : "Stopped." stat = @running ? "Running." : "Stopped."
@lastcounts.each { |k,v| @lastcounts.each { |k,v|
stat << "\n#{k} limit #{@thresholds.fetch(k, 'default')} current #{v}" stat << "\n#{k} limit #{@thresholds.fetch(k, 'default')} current #{v}"
} }
@thresholds.each { |k,v| @thresholds.each { |k,v|
stat << "\n#{k} limit #{v} current 0" unless @lastcounts.has_key?(k) stat << "\n#{k} limit #{v} current 0" unless @lastcounts.has_key?(k)
} }
stat << "\nDefault: #{@thresholds.default}" stat << "\nDefault: #{@thresholds.default}"
stat stat
end end
end end
@ -138,28 +138,28 @@ $AutoFarm ||= AutoFarm.new
case $script_args[0] case $script_args[0]
when 'start', 'enable' when 'start', 'enable'
$AutoFarm.start $AutoFarm.start
puts $AutoFarm.status puts $AutoFarm.status
when 'end', 'stop', 'disable' when 'end', 'stop', 'disable'
$AutoFarm.stop $AutoFarm.stop
puts 'Stopped.' puts 'Stopped.'
when 'default' when 'default'
$AutoFarm.setdefault($script_args[1]) $AutoFarm.setdefault($script_args[1])
when 'threshold' when 'threshold'
t = $script_args[1] t = $script_args[1]
$script_args[2..-1].each {|i| $script_args[2..-1].each {|i|
$AutoFarm.setthreshold(i, t) $AutoFarm.setthreshold(i, t)
} }
when 'delete' when 'delete'
$AutoFarm.stop $AutoFarm.stop
$AutoFarm = nil $AutoFarm = nil
when 'help', '?' when 'help', '?'
puts <<EOS puts <<EOS
Automatically handle crop selection in farm plots based on current plant stocks. Automatically handle crop selection in farm plots based on current plant stocks.
Selects a crop for planting if current stock is below a threshold. Selects a crop for planting if current stock is below a threshold.
Selected crops are dispatched on all farmplots. Selected crops are dispatched on all farmplots.
@ -171,6 +171,6 @@ Usage:
EOS EOS
else else
$AutoFarm.process $AutoFarm.process
puts $AutoFarm.status puts $AutoFarm.status
end end

@ -8,7 +8,7 @@ count = $script_args[2]
category = df.match_rawname(category, ['help', 'bars', 'boulders', 'plants', 'logs', 'webs', 'anvils']) || 'help' category = df.match_rawname(category, ['help', 'bars', 'boulders', 'plants', 'logs', 'webs', 'anvils']) || 'help'
if category == 'help' if category == 'help'
puts <<EOS puts <<EOS
Create first necessity items under the cursor. Create first necessity items under the cursor.
Usage: Usage:
create-items [category] [raws token] [number] create-items [category] [raws token] [number]
@ -28,118 +28,118 @@ Exemples:
create-items plants list create-items plants list
EOS EOS
throw :script_finished throw :script_finished
elsif mat_raw == 'list' elsif mat_raw == 'list'
# allowed with no cursor # allowed with no cursor
elsif df.cursor.x == -30000 elsif df.cursor.x == -30000
puts "Please place the game cursor somewhere" puts "Please place the game cursor somewhere"
throw :script_finished throw :script_finished
elsif !(maptile = df.map_tile_at(df.cursor)) elsif !(maptile = df.map_tile_at(df.cursor))
puts "Error: unallocated map block !" puts "Error: unallocated map block !"
throw :script_finished throw :script_finished
elsif !maptile.shape_passablehigh elsif !maptile.shape_passablehigh
puts "Error: impassible tile !" puts "Error: impassible tile !"
throw :script_finished throw :script_finished
end end
def match_list(tok, list) def match_list(tok, list)
if tok != 'list' if tok != 'list'
tok = df.match_rawname(tok, list) tok = df.match_rawname(tok, list)
if not tok if not tok
puts "Invalid raws token, use one in:" puts "Invalid raws token, use one in:"
tok = 'list' tok = 'list'
end end
end end
if tok == 'list' if tok == 'list'
puts list.map { |w| w =~ /[^\w]/ ? w.inspect : w }.join(' ') puts list.map { |w| w =~ /[^\w]/ ? w.inspect : w }.join(' ')
throw :script_finished throw :script_finished
end end
tok tok
end end
case category case category
when 'bars' when 'bars'
# create metal bar, eg createbar INORGANIC:IRON # create metal bar, eg createbar INORGANIC:IRON
cls = DFHack::ItemBarst cls = DFHack::ItemBarst
if mat_raw !~ /:/ and !(df.decode_mat(mat_raw) rescue nil) if mat_raw !~ /:/ and !(df.decode_mat(mat_raw) rescue nil)
list = df.world.raws.inorganics.find_all { |ino| list = df.world.raws.inorganics.find_all { |ino|
ino.material.flags[:IS_METAL] ino.material.flags[:IS_METAL]
}.map { |ino| ino.id } }.map { |ino| ino.id }
mat_raw = match_list(mat_raw, list) mat_raw = match_list(mat_raw, list)
mat_raw = "INORGANIC:#{mat_raw}" mat_raw = "INORGANIC:#{mat_raw}"
puts mat_raw puts mat_raw
end end
customize = lambda { |item| customize = lambda { |item|
item.dimension = 150 item.dimension = 150
item.subtype = -1 item.subtype = -1
} }
when 'boulders' when 'boulders'
cls = DFHack::ItemBoulderst cls = DFHack::ItemBoulderst
if mat_raw !~ /:/ and !(df.decode_mat(mat_raw) rescue nil) if mat_raw !~ /:/ and !(df.decode_mat(mat_raw) rescue nil)
list = df.world.raws.inorganics.find_all { |ino| list = df.world.raws.inorganics.find_all { |ino|
ino.material.flags[:IS_STONE] ino.material.flags[:IS_STONE]
}.map { |ino| ino.id } }.map { |ino| ino.id }
mat_raw = match_list(mat_raw, list) mat_raw = match_list(mat_raw, list)
mat_raw = "INORGANIC:#{mat_raw}" mat_raw = "INORGANIC:#{mat_raw}"
puts mat_raw puts mat_raw
end end
when 'plants' when 'plants'
cls = DFHack::ItemPlantst cls = DFHack::ItemPlantst
if mat_raw !~ /:/ and !(df.decode_mat(mat_raw) rescue nil) if mat_raw !~ /:/ and !(df.decode_mat(mat_raw) rescue nil)
list = df.world.raws.plants.all.find_all { |plt| list = df.world.raws.plants.all.find_all { |plt|
plt.material.find { |mat| mat.id == 'STRUCTURAL' } plt.material.find { |mat| mat.id == 'STRUCTURAL' }
}.map { |plt| plt.id } }.map { |plt| plt.id }
mat_raw = match_list(mat_raw, list) mat_raw = match_list(mat_raw, list)
mat_raw = "PLANT_MAT:#{mat_raw}:STRUCTURAL" mat_raw = "PLANT_MAT:#{mat_raw}:STRUCTURAL"
puts mat_raw puts mat_raw
end end
when 'logs' when 'logs'
cls = DFHack::ItemWoodst cls = DFHack::ItemWoodst
if mat_raw !~ /:/ and !(df.decode_mat(mat_raw) rescue nil) if mat_raw !~ /:/ and !(df.decode_mat(mat_raw) rescue nil)
list = df.world.raws.plants.all.find_all { |plt| list = df.world.raws.plants.all.find_all { |plt|
plt.material.find { |mat| mat.id == 'WOOD' } plt.material.find { |mat| mat.id == 'WOOD' }
}.map { |plt| plt.id } }.map { |plt| plt.id }
mat_raw = match_list(mat_raw, list) mat_raw = match_list(mat_raw, list)
mat_raw = "PLANT_MAT:#{mat_raw}:WOOD" mat_raw = "PLANT_MAT:#{mat_raw}:WOOD"
puts mat_raw puts mat_raw
end end
when 'webs' when 'webs'
cls = DFHack::ItemThreadst cls = DFHack::ItemThreadst
if mat_raw !~ /:/ and !(df.decode_mat(mat_raw) rescue nil) if mat_raw !~ /:/ and !(df.decode_mat(mat_raw) rescue nil)
list = df.world.raws.creatures.all.find_all { |cre| list = df.world.raws.creatures.all.find_all { |cre|
cre.material.find { |mat| mat.id == 'SILK' } cre.material.find { |mat| mat.id == 'SILK' }
}.map { |cre| cre.creature_id } }.map { |cre| cre.creature_id }
mat_raw = match_list(mat_raw, list) mat_raw = match_list(mat_raw, list)
mat_raw = "CREATURE_MAT:#{mat_raw}:SILK" mat_raw = "CREATURE_MAT:#{mat_raw}:SILK"
puts mat_raw puts mat_raw
end end
count ||= 1 count ||= 1
customize = lambda { |item| customize = lambda { |item|
item.flags.spider_web = true item.flags.spider_web = true
item.dimension = 15000 # XXX may depend on creature (this is for GCS) item.dimension = 15000 # XXX may depend on creature (this is for GCS)
} }
when 'anvils' when 'anvils'
cls = DFHack::ItemAnvilst cls = DFHack::ItemAnvilst
if mat_raw !~ /:/ and !(df.decode_mat(mat_raw) rescue nil) if mat_raw !~ /:/ and !(df.decode_mat(mat_raw) rescue nil)
list = df.world.raws.inorganics.find_all { |ino| list = df.world.raws.inorganics.find_all { |ino|
ino.material.flags[:IS_METAL] ino.material.flags[:IS_METAL]
}.map { |ino| ino.id } }.map { |ino| ino.id }
mat_raw = match_list(mat_raw, list) mat_raw = match_list(mat_raw, list)
mat_raw = "INORGANIC:#{mat_raw}" mat_raw = "INORGANIC:#{mat_raw}"
puts mat_raw puts mat_raw
end end
count ||= 1 count ||= 1
end end
@ -148,30 +148,30 @@ mat = df.decode_mat mat_raw
count ||= 20 count ||= 20
count.to_i.times { count.to_i.times {
item = cls.cpp_new item = cls.cpp_new
item.id = df.item_next_id item.id = df.item_next_id
item.stack_size = 1 item.stack_size = 1
item.mat_type = mat.mat_type item.mat_type = mat.mat_type
item.mat_index = mat.mat_index item.mat_index = mat.mat_index
customize[item] if customize customize[item] if customize
df.item_next_id += 1 df.item_next_id += 1
item.categorize(true) item.categorize(true)
df.world.items.all << item df.world.items.all << item
item.pos = df.cursor item.pos = df.cursor
item.flags.on_ground = true item.flags.on_ground = true
df.map_tile_at.mapblock.items << item.id df.map_tile_at.mapblock.items << item.id
df.map_tile_at.occupancy.item = true df.map_tile_at.occupancy.item = true
} }
# move game view, so that the ui menu updates # move game view, so that the ui menu updates
if df.cursor.z > 5 if df.cursor.z > 5
df.curview.feed_keys(:CURSOR_DOWN_Z) df.curview.feed_keys(:CURSOR_DOWN_Z)
df.curview.feed_keys(:CURSOR_UP_Z) df.curview.feed_keys(:CURSOR_UP_Z)
else else
df.curview.feed_keys(:CURSOR_UP_Z) df.curview.feed_keys(:CURSOR_UP_Z)
df.curview.feed_keys(:CURSOR_DOWN_Z) df.curview.feed_keys(:CURSOR_DOWN_Z)
end end

@ -1,67 +1,67 @@
# show death cause of a creature # show death cause of a creature
def display_death_event(e) def display_death_event(e)
str = "The #{e.victim_hf_tg.race_tg.name[0]} #{e.victim_hf_tg.name} died in year #{e.year}" str = "The #{e.victim_hf_tg.race_tg.name[0]} #{e.victim_hf_tg.name} died in year #{e.year}"
str << " (cause: #{e.death_cause.to_s.downcase})," str << " (cause: #{e.death_cause.to_s.downcase}),"
str << " killed by the #{e.slayer_race_tg.name[0]} #{e.slayer_hf_tg.name}" if e.slayer_hf != -1 str << " killed by the #{e.slayer_race_tg.name[0]} #{e.slayer_hf_tg.name}" if e.slayer_hf != -1
str << " using a #{df.world.raws.itemdefs.weapons[e.weapon.item_subtype].name}" if e.weapon.item_type == :WEAPON str << " using a #{df.world.raws.itemdefs.weapons[e.weapon.item_subtype].name}" if e.weapon.item_type == :WEAPON
str << ", shot by a #{df.world.raws.itemdefs.weapons[e.weapon.shooter_item_subtype].name}" if e.weapon.shooter_item_type == :WEAPON str << ", shot by a #{df.world.raws.itemdefs.weapons[e.weapon.shooter_item_subtype].name}" if e.weapon.shooter_item_type == :WEAPON
puts str.chomp(',') + '.' puts str.chomp(',') + '.'
end end
def display_death_unit(u) def display_death_unit(u)
death_info = u.counters.death_tg death_info = u.counters.death_tg
killer = death_info.killer_tg if death_info killer = death_info.killer_tg if death_info
str = "The #{u.race_tg.name[0]}" str = "The #{u.race_tg.name[0]}"
str << " #{u.name}" if u.name.has_name str << " #{u.name}" if u.name.has_name
str << " died" str << " died"
str << " in year #{death_info.event_year}" if death_info str << " in year #{death_info.event_year}" if death_info
str << " (cause: #{u.counters.death_cause.to_s.downcase})," if u.counters.death_cause != -1 str << " (cause: #{u.counters.death_cause.to_s.downcase})," if u.counters.death_cause != -1
str << " killed by the #{killer.race_tg.name[0]} #{killer.name}" if killer str << " killed by the #{killer.race_tg.name[0]} #{killer.name}" if killer
puts str.chomp(',') + '.' puts str.chomp(',') + '.'
end end
item = df.item_find(:selected) item = df.item_find(:selected)
unit = df.unit_find(:selected) unit = df.unit_find(:selected)
if !item or !item.kind_of?(DFHack::ItemBodyComponent) if !item or !item.kind_of?(DFHack::ItemBodyComponent)
item = df.world.items.other[:ANY_CORPSE].find { |i| df.at_cursor?(i) } item = df.world.items.other[:ANY_CORPSE].find { |i| df.at_cursor?(i) }
end end
if item and item.kind_of?(DFHack::ItemBodyComponent) if item and item.kind_of?(DFHack::ItemBodyComponent)
hf = item.hist_figure_id hf = item.hist_figure_id
elsif unit elsif unit
hf = unit.hist_figure_id hf = unit.hist_figure_id
end end
if not hf if not hf
puts "Please select a corpse in the loo'k' menu, or an unit in the 'u'nitlist screen" puts "Please select a corpse in the loo'k' menu, or an unit in the 'u'nitlist screen"
elsif hf == -1 elsif hf == -1
if unit ||= item.unit_tg if unit ||= item.unit_tg
display_death_unit(unit) display_death_unit(unit)
else else
puts "Not a historical figure, cannot death find info" puts "Not a historical figure, cannot death find info"
end end
else else
histfig = df.world.history.figures.binsearch(hf) histfig = df.world.history.figures.binsearch(hf)
unit = histfig ? df.unit_find(histfig.unit_id) : nil unit = histfig ? df.unit_find(histfig.unit_id) : nil
if unit and not unit.flags1.dead and not unit.flags3.ghostly if unit and not unit.flags1.dead and not unit.flags3.ghostly
puts "#{unit.name} is not dead yet !" puts "#{unit.name} is not dead yet !"
else else
events = df.world.history.events events = df.world.history.events
(0...events.length).reverse_each { |i| (0...events.length).reverse_each { |i|
e = events[i] e = events[i]
if e.kind_of?(DFHack::HistoryEventHistFigureDiedst) and e.victim_hf == hf if e.kind_of?(DFHack::HistoryEventHistFigureDiedst) and e.victim_hf == hf
display_death_event(e) display_death_event(e)
break break
end end
} }
end end
end end

@ -9,49 +9,49 @@ local tile_attrs = df.tiletype.attrs
local args={...} local args={...}
function setCell(x,y,cell) function setCell(x,y,cell)
cell=cell or {} cell=cell or {}
cell.fm=cell.fm or {r=1,g=1,b=1} cell.fm=cell.fm or {r=1,g=1,b=1}
cell.bm=cell.bm or {r=1,g=1,b=1} cell.bm=cell.bm or {r=1,g=1,b=1}
cell.fo=cell.fo or {r=0,g=0,b=0} cell.fo=cell.fo or {r=0,g=0,b=0}
cell.bo=cell.bo or {r=0,g=0,b=0} cell.bo=cell.bo or {r=0,g=0,b=0}
render.setCell(x,y,cell) render.setCell(x,y,cell)
end end
function getCursorPos() function getCursorPos()
local g_cursor=df.global.cursor local g_cursor=df.global.cursor
if g_cursor.x ~= -30000 then if g_cursor.x ~= -30000 then
return copyall(g_cursor) return copyall(g_cursor)
end end
end end
function falloff(color,sqDist,maxdist) function falloff(color,sqDist,maxdist)
local v1=1/(sqDist/maxdist+1) local v1=1/(sqDist/maxdist+1)
local v2=v1-1/(1+maxdist*maxdist) local v2=v1-1/(1+maxdist*maxdist)
local v=v2/(1-1/(1+maxdist*maxdist)) local v=v2/(1-1/(1+maxdist*maxdist))
return {r=v*color.r,g=v*color.g,b=v*color.b} return {r=v*color.r,g=v*color.g,b=v*color.b}
end end
function blend(c1,c2) function blend(c1,c2)
return {r=math.max(c1.r,c2.r), return {r=math.max(c1.r,c2.r),
g=math.max(c1.g,c2.g), g=math.max(c1.g,c2.g),
b=math.max(c1.b,c2.b)} b=math.max(c1.b,c2.b)}
end end
LightOverlay=defclass(LightOverlay,guidm.DwarfOverlay) LightOverlay=defclass(LightOverlay,guidm.DwarfOverlay)
LightOverlay.ATTRS { LightOverlay.ATTRS {
lightMap={}, lightMap={},
dynamic=true, dynamic=true,
dirty=false, dirty=false,
} }
function LightOverlay:init(args) function LightOverlay:init(args)
self.tick=df.global.cur_year_tick_advmode self.tick=df.global.cur_year_tick_advmode
end end
function lightPassable(shape) function lightPassable(shape)
if shape==df.tiletype_shape.WALL or if shape==df.tiletype_shape.WALL or
shape==df.tiletype_shape.BROOK_BED or shape==df.tiletype_shape.BROOK_BED or
shape==df.tiletype_shape.TREE then shape==df.tiletype_shape.TREE then
return false return false
else else
return true return true
end end
end end
function circle(xm, ym,r,plot) function circle(xm, ym,r,plot)
local x = -r local x = -r
@ -64,312 +64,312 @@ function circle(xm, ym,r,plot)
plot(xm+y, ym+x);--/* IV. Quadrant */ plot(xm+y, ym+x);--/* IV. Quadrant */
r = err; r = err;
if (r <= y) then if (r <= y) then
y=y+1 y=y+1
err =err+y*2+1; --/* e_xy+e_y < 0 */ err =err+y*2+1; --/* e_xy+e_y < 0 */
end end
if (r > x or err > y) then if (r > x or err > y) then
x=x+1 x=x+1
err =err+x*2+1; --/* e_xy+e_x > 0 or no 2nd y-step */ err =err+x*2+1; --/* e_xy+e_x > 0 or no 2nd y-step */
end end
until (x >= 0); until (x >= 0);
end end
function line(x0, y0, x1, y1,plot) function line(x0, y0, x1, y1,plot)
local dx = math.abs(x1-x0) local dx = math.abs(x1-x0)
local dy = math.abs(y1-y0) local dy = math.abs(y1-y0)
local sx,sy local sx,sy
if x0 < x1 then sx = 1 else sx = -1 end if x0 < x1 then sx = 1 else sx = -1 end
if y0 < y1 then sy = 1 else sy = -1 end if y0 < y1 then sy = 1 else sy = -1 end
local err = dx-dy local err = dx-dy
while true do while true do
if not plot(x0,y0) then if not plot(x0,y0) then
return return
end end
if x0 == x1 and y0 == y1 then if x0 == x1 and y0 == y1 then
break break
end end
local e2 = 2*err local e2 = 2*err
if e2 > -dy then if e2 > -dy then
err = err - dy err = err - dy
x0 = x0 + sx x0 = x0 + sx
end end
if x0 == x1 and y0 == y1 then if x0 == x1 and y0 == y1 then
if not plot(x0,y0) then if not plot(x0,y0) then
return return
end end
break break
end end
if e2 < dx then if e2 < dx then
err = err + dx err = err + dx
y0 = y0 + sy y0 = y0 + sy
end end
end end
end end
function LightOverlay:calculateFovs() function LightOverlay:calculateFovs()
self.fovs=self.fovs or {} self.fovs=self.fovs or {}
self.precalc=self.precalc or {} self.precalc=self.precalc or {}
for k,v in ipairs(self.fovs) do for k,v in ipairs(self.fovs) do
self:calculateFov(v.pos,v.radius,v.color) self:calculateFov(v.pos,v.radius,v.color)
end end
end end
function LightOverlay:calculateFov(pos,radius,color) function LightOverlay:calculateFov(pos,radius,color)
local vp=self:getViewport() local vp=self:getViewport()
local map = self.df_layout.map local map = self.df_layout.map
local ray=function(tx,ty) local ray=function(tx,ty)
local power=copyall(color) local power=copyall(color)
local lx=pos.x local lx=pos.x
local ly=pos.y local ly=pos.y
local setTile=function(x,y) local setTile=function(x,y)
if x>0 and y>0 and x<=map.width and y<=map.height then if x>0 and y>0 and x<=map.width and y<=map.height then
local dtsq=(lx-x)*(lx-x)+(ly-y)*(ly-y) local dtsq=(lx-x)*(lx-x)+(ly-y)*(ly-y)
local dt=math.sqrt(dtsq) local dt=math.sqrt(dtsq)
local tile=x+y*map.width local tile=x+y*map.width
if self.precalc[tile] then if self.precalc[tile] then
local tcol=blend(self.precalc[tile],power) local tcol=blend(self.precalc[tile],power)
if tcol.r==self.precalc[tile].r and tcol.g==self.precalc[tile].g and self.precalc[tile].b==self.precalc[tile].b if tcol.r==self.precalc[tile].r and tcol.g==self.precalc[tile].g and self.precalc[tile].b==self.precalc[tile].b
and dtsq>0 then and dtsq>0 then
return false return false
end end
end end
local ocol=self.lightMap[tile] or {r=0,g=0,b=0} local ocol=self.lightMap[tile] or {r=0,g=0,b=0}
local ncol=blend(power,ocol) local ncol=blend(power,ocol)
self.lightMap[tile]=ncol self.lightMap[tile]=ncol
local v=self.ocupancy[tile] local v=self.ocupancy[tile]
if dtsq>0 then if dtsq>0 then
power.r=power.r*(v.r^dt) power.r=power.r*(v.r^dt)
power.g=power.g*(v.g^dt) power.g=power.g*(v.g^dt)
power.b=power.b*(v.b^dt) power.b=power.b*(v.b^dt)
end end
lx=x lx=x
ly=y ly=y
local pwsq=power.r*power.r+power.g*power.g+power.b*power.b local pwsq=power.r*power.r+power.g*power.g+power.b*power.b
return pwsq>levelDim*levelDim return pwsq>levelDim*levelDim
end end
return false return false
end end
line(pos.x,pos.y,tx,ty,setTile) line(pos.x,pos.y,tx,ty,setTile)
end end
circle(pos.x,pos.y,radius,ray) circle(pos.x,pos.y,radius,ray)
end end
function LightOverlay:placeLightFov(pos,radius,color) function LightOverlay:placeLightFov(pos,radius,color)
local map = self.df_layout.map local map = self.df_layout.map
local tile=pos.x+pos.y*map.width local tile=pos.x+pos.y*map.width
local ocol=self.precalc[tile] or {r=0,g=0,b=0} local ocol=self.precalc[tile] or {r=0,g=0,b=0}
local ncol=blend(color,ocol) local ncol=blend(color,ocol)
self.precalc[tile]=ncol self.precalc[tile]=ncol
local ocol=self.lightMap[tile] or {r=0,g=0,b=0} local ocol=self.lightMap[tile] or {r=0,g=0,b=0}
local ncol=blend(color,ocol) local ncol=blend(color,ocol)
self.lightMap[tile]=ncol self.lightMap[tile]=ncol
table.insert(self.fovs,{pos=pos,radius=radius,color=color}) table.insert(self.fovs,{pos=pos,radius=radius,color=color})
end end
function LightOverlay:placeLightFov2(pos,radius,color,f,rays) function LightOverlay:placeLightFov2(pos,radius,color,f,rays)
f=f or falloff f=f or falloff
local raycount=rays or 25 local raycount=rays or 25
local vp=self:getViewport() local vp=self:getViewport()
local map = self.df_layout.map local map = self.df_layout.map
local off=math.random(0,math.pi) local off=math.random(0,math.pi)
local done={} local done={}
for d=0,math.pi*2,math.pi*2/raycount do for d=0,math.pi*2,math.pi*2/raycount do
local dx,dy local dx,dy
dx=math.cos(d+off) dx=math.cos(d+off)
dy=math.sin(d+off) dy=math.sin(d+off)
local cx=0 local cx=0
local cy=0 local cy=0
for dt=0,radius,0.01 do for dt=0,radius,0.01 do
if math.abs(math.floor(dt*dx)-cx)>0 or math.abs(math.floor(dt*dy)-cy)> 0then if math.abs(math.floor(dt*dx)-cx)>0 or math.abs(math.floor(dt*dy)-cy)> 0then
local x=cx+pos.x local x=cx+pos.x
local y=cy+pos.y local y=cy+pos.y
if x>0 and y>0 and x<=map.width and y<=map.height and not done[tile] then if x>0 and y>0 and x<=map.width and y<=map.height and not done[tile] then
local tile=x+y*map.width local tile=x+y*map.width
done[tile]=true done[tile]=true
local ncol=f(color,dt*dt,radius) local ncol=f(color,dt*dt,radius)
local ocol=self.lightMap[tile] or {r=0,g=0,b=0} local ocol=self.lightMap[tile] or {r=0,g=0,b=0}
ncol=blend(ncol,ocol) ncol=blend(ncol,ocol)
self.lightMap[tile]=ncol self.lightMap[tile]=ncol
if --(ncol.r==ocol.r and ncol.g==ocol.g and ncol.b==ocol.b) or if --(ncol.r==ocol.r and ncol.g==ocol.g and ncol.b==ocol.b) or
not self.ocupancy[tile] then not self.ocupancy[tile] then
break break
end end
end end
cx=math.floor(dt*dx) cx=math.floor(dt*dx)
cy=math.floor(dt*dy) cy=math.floor(dt*dy)
end end
end end
end end
end end
function LightOverlay:placeLight(pos,radius,color,f) function LightOverlay:placeLight(pos,radius,color,f)
f=f or falloff f=f or falloff
local vp=self:getViewport() local vp=self:getViewport()
local map = self.df_layout.map local map = self.df_layout.map
for i=-radius,radius do for i=-radius,radius do
for j=-radius,radius do for j=-radius,radius do
local x=pos.x+i+1 local x=pos.x+i+1
local y=pos.y+j+1 local y=pos.y+j+1
if x>0 and y>0 and x<=map.width and y<=map.height then if x>0 and y>0 and x<=map.width and y<=map.height then
local tile=x+y*map.width local tile=x+y*map.width
local ncol=f(color,(i*i+j*j),radius) local ncol=f(color,(i*i+j*j),radius)
local ocol=self.lightMap[tile] or {r=0,g=0,b=0} local ocol=self.lightMap[tile] or {r=0,g=0,b=0}
self.lightMap[tile]=blend(ncol,ocol) self.lightMap[tile]=blend(ncol,ocol)
end end
end end
end end
end end
function LightOverlay:calculateLightLava() function LightOverlay:calculateLightLava()
local vp=self:getViewport() local vp=self:getViewport()
local map = self.df_layout.map local map = self.df_layout.map
for i=map.x1,map.x2 do for i=map.x1,map.x2 do
for j=map.y1,map.y2 do for j=map.y1,map.y2 do
local pos={x=i+vp.x1-1,y=j+vp.y1-1,z=vp.z} local pos={x=i+vp.x1-1,y=j+vp.y1-1,z=vp.z}
local pos2={x=i+vp.x1-1,y=j+vp.y1-1,z=vp.z-1} local pos2={x=i+vp.x1-1,y=j+vp.y1-1,z=vp.z-1}
local t1=dfhack.maps.getTileFlags(pos) local t1=dfhack.maps.getTileFlags(pos)
local tt=dfhack.maps.getTileType(pos) local tt=dfhack.maps.getTileType(pos)
if tt then if tt then
local shape=tile_attrs[tt].shape local shape=tile_attrs[tt].shape
local t2=dfhack.maps.getTileFlags(pos2) local t2=dfhack.maps.getTileFlags(pos2)
if (t1 and t1.liquid_type and t1.flow_size>0) or if (t1 and t1.liquid_type and t1.flow_size>0) or
(shape==df.tiletype_shape.EMPTY and t2 and t2.liquid_type and t2.flow_size>0) then (shape==df.tiletype_shape.EMPTY and t2 and t2.liquid_type and t2.flow_size>0) then
--self:placeLight({x=i,y=j},5,{r=0.8,g=0.2,b=0.2}) --self:placeLight({x=i,y=j},5,{r=0.8,g=0.2,b=0.2})
self:placeLightFov({x=i,y=j},5,{r=0.8,g=0.2,b=0.2},nil) self:placeLightFov({x=i,y=j},5,{r=0.8,g=0.2,b=0.2},nil)
end end
end end
end end
end end
end end
function LightOverlay:calculateLightSun() function LightOverlay:calculateLightSun()
local vp=self:getViewport() local vp=self:getViewport()
local map = self.df_layout.map local map = self.df_layout.map
for i=map.x1,map.x2+1 do for i=map.x1,map.x2+1 do
for j=map.y1,map.y2+1 do for j=map.y1,map.y2+1 do
local pos={x=i+vp.x1-1,y=j+vp.y1-1,z=vp.z} local pos={x=i+vp.x1-1,y=j+vp.y1-1,z=vp.z}
local t1=dfhack.maps.getTileFlags(pos) local t1=dfhack.maps.getTileFlags(pos)
if (t1 and t1.outside ) then if (t1 and t1.outside ) then
self:placeLightFov({x=i,y=j},15,{r=1,g=1,b=1},nil) self:placeLightFov({x=i,y=j},15,{r=1,g=1,b=1},nil)
end end
end end
end end
end end
function LightOverlay:calculateLightCursor() function LightOverlay:calculateLightCursor()
local c=getCursorPos() local c=getCursorPos()
if c then if c then
local vp=self:getViewport() local vp=self:getViewport()
local pos=vp:tileToScreen(c) local pos=vp:tileToScreen(c)
--self:placeLight(pos,11,{r=0.96,g=0.84,b=0.03}) --self:placeLight(pos,11,{r=0.96,g=0.84,b=0.03})
self:placeLightFov({x=pos.x+1,y=pos.y+1},11,{r=0.96,g=0.84,b=0.03}) self:placeLightFov({x=pos.x+1,y=pos.y+1},11,{r=0.96,g=0.84,b=0.03})
end end
end end
function LightOverlay:buildOcupancy() function LightOverlay:buildOcupancy()
self.ocupancy={} self.ocupancy={}
local vp=self:getViewport() local vp=self:getViewport()
local map = self.df_layout.map local map = self.df_layout.map
for i=map.x1,map.x2+1 do for i=map.x1,map.x2+1 do
for j=map.y1,map.y2+1 do for j=map.y1,map.y2+1 do
local pos={x=i+vp.x1-1,y=j+vp.y1-1,z=vp.z} local pos={x=i+vp.x1-1,y=j+vp.y1-1,z=vp.z}
local tile=i+j*map.width local tile=i+j*map.width
local tt=dfhack.maps.getTileType(pos) local tt=dfhack.maps.getTileType(pos)
local t1=dfhack.maps.getTileFlags(pos) local t1=dfhack.maps.getTileFlags(pos)
if tt then if tt then
local shape=tile_attrs[tt].shape local shape=tile_attrs[tt].shape
if not lightPassable(shape) then if not lightPassable(shape) then
self.ocupancy[tile]={r=0,g=0,b=0} self.ocupancy[tile]={r=0,g=0,b=0}
else else
if t1 and not t1.liquid_type and t1.flow_size>2 then if t1 and not t1.liquid_type and t1.flow_size>2 then
self.ocupancy[tile]={r=0.5,g=0.5,b=0.7} self.ocupancy[tile]={r=0.5,g=0.5,b=0.7}
else else
self.ocupancy[tile]={r=0.8,g=0.8,b=0.8} self.ocupancy[tile]={r=0.8,g=0.8,b=0.8}
end end
end end
end end
end end
end end
end end
function LightOverlay:changed() function LightOverlay:changed()
if self.dirty or self.tick~=df.global.cur_year_tick_advmode then if self.dirty or self.tick~=df.global.cur_year_tick_advmode then
self.dirty=false self.dirty=false
self.tick=df.global.cur_year_tick_advmode self.tick=df.global.cur_year_tick_advmode
return true return true
end end
return false return false
end end
function LightOverlay:makeLightMap() function LightOverlay:makeLightMap()
if not self:changed() then if not self:changed() then
return return
end end
self.fovs={} self.fovs={}
self.precalc={} self.precalc={}
self.lightMap={} self.lightMap={}
self:buildOcupancy() self:buildOcupancy()
self:calculateLightCursor() self:calculateLightCursor()
self:calculateLightLava() self:calculateLightLava()
self:calculateLightSun() self:calculateLightSun()
self:calculateFovs() self:calculateFovs()
end end
function LightOverlay:onIdle() function LightOverlay:onIdle()
self._native.parent:logic() self._native.parent:logic()
end end
function LightOverlay:render(dc) function LightOverlay:render(dc)
if self.dynamic then if self.dynamic then
self:makeLightMap() self:makeLightMap()
end end
self:renderParent() self:renderParent()
local vp=self:getViewport() local vp=self:getViewport()
local map = self.df_layout.map local map = self.df_layout.map
self.lightMap=self.lightMap or {} self.lightMap=self.lightMap or {}
render.lockGrids() render.lockGrids()
render.invalidate({x=map.x1,y=map.y1,w=map.width,h=map.height}) render.invalidate({x=map.x1,y=map.y1,w=map.width,h=map.height})
render.resetGrids() render.resetGrids()
for i=map.x1,map.x2 do for i=map.x1,map.x2 do
for j=map.y1,map.y2 do for j=map.y1,map.y2 do
local v=self.lightMap[i+j*map.width] local v=self.lightMap[i+j*map.width]
if v then if v then
setCell(i,j,{fm=v,bm=v}) setCell(i,j,{fm=v,bm=v})
else else
local dimRgb={r=levelDim,g=levelDim,b=levelDim} local dimRgb={r=levelDim,g=levelDim,b=levelDim}
setCell(i,j,{fm=dimRgb,bm=dimRgb}) setCell(i,j,{fm=dimRgb,bm=dimRgb})
end end
end end
end end
render.unlockGrids() render.unlockGrids()
end end
function LightOverlay:onDismiss() function LightOverlay:onDismiss()
render.lockGrids() render.lockGrids()
render.resetGrids() render.resetGrids()
render.invalidate() render.invalidate()
render.unlockGrids() render.unlockGrids()
end end
function LightOverlay:onInput(keys) function LightOverlay:onInput(keys)
if keys.STRING_A096 then if keys.STRING_A096 then
self:dismiss() self:dismiss()
else else
self:sendInputToParent(keys) self:sendInputToParent(keys)
if keys.CHANGETAB then if keys.CHANGETAB then
self:updateLayout() self:updateLayout()
end end
if keys.STRING_A126 and not self.dynamic then if keys.STRING_A126 and not self.dynamic then
self:makeLightMap() self:makeLightMap()
end end
self.dirty=true self.dirty=true
end end
end end
if not render.isEnabled() then if not render.isEnabled() then
qerror("Lua rendermode not enabled!") qerror("Lua rendermode not enabled!")
end end
local dyn=true local dyn=true
if #args>0 and args[1]=="static" then dyn=false end if #args>0 and args[1]=="static" then dyn=false end

@ -6,5 +6,5 @@ raise 'select an item' if not tg
o = df.world.items.other o = df.world.items.other
# discard ANY/BAD # discard ANY/BAD
o._indexenum::ENUM.sort.transpose[1][1..-2].each { |k| o._indexenum::ENUM.sort.transpose[1][1..-2].each { |k|
puts k if o[k].find { |i| i == tg } puts k if o[k].find { |i| i == tg }
} }

@ -4,10 +4,10 @@ df.world.arena_spawn.race.clear
df.world.arena_spawn.caste.clear df.world.arena_spawn.caste.clear
df.world.raws.creatures.all.length.times { |r_idx| df.world.raws.creatures.all.length.times { |r_idx|
df.world.raws.creatures.all[r_idx].caste.length.times { |c_idx| df.world.raws.creatures.all[r_idx].caste.length.times { |c_idx|
df.world.arena_spawn.race << r_idx df.world.arena_spawn.race << r_idx
df.world.arena_spawn.caste << c_idx df.world.arena_spawn.caste << c_idx
} }
} }
df.world.arena_spawn.creature_cnt[df.world.arena_spawn.race.length-1] = 0 df.world.arena_spawn.creature_cnt[df.world.arena_spawn.race.length-1] = 0

@ -10,69 +10,69 @@ kill_by = $script_args[1]
case kill_by case kill_by
when 'magma' when 'magma'
slain = 'burning' slain = 'burning'
when 'slaughter', 'butcher' when 'slaughter', 'butcher'
slain = 'marked for butcher' slain = 'marked for butcher'
when nil when nil
slain = 'slain' slain = 'slain'
else else
race = 'help' race = 'help'
end end
checkunit = lambda { |u| checkunit = lambda { |u|
(u.body.blood_count != 0 or u.body.blood_max == 0) and (u.body.blood_count != 0 or u.body.blood_max == 0) and
not u.flags1.dead and not u.flags1.dead and
not u.flags1.caged and not u.flags1.chained and not u.flags1.caged and not u.flags1.chained and
#not u.flags1.hidden_in_ambush and #not u.flags1.hidden_in_ambush and
not df.map_designation_at(u).hidden not df.map_designation_at(u).hidden
} }
slayit = lambda { |u| slayit = lambda { |u|
case kill_by case kill_by
when 'magma' when 'magma'
# it's getting hot around here # it's getting hot around here
# !!WARNING!! do not call on a magma-safe creature # !!WARNING!! do not call on a magma-safe creature
ouh = df.onupdate_register("exterminate ensure #{u.id}", 1) { ouh = df.onupdate_register("exterminate ensure #{u.id}", 1) {
if u.flags1.dead if u.flags1.dead
df.onupdate_unregister(ouh) df.onupdate_unregister(ouh)
else else
x, y, z = u.pos.x, u.pos.y, u.pos.z x, y, z = u.pos.x, u.pos.y, u.pos.z
z += 1 while tile = df.map_tile_at(x, y, z+1) and z += 1 while tile = df.map_tile_at(x, y, z+1) and
tile.shape_passableflow and tile.shape_passablelow tile.shape_passableflow and tile.shape_passablelow
df.map_tile_at(x, y, z).spawn_magma(7) df.map_tile_at(x, y, z).spawn_magma(7)
end end
} }
when 'butcher', 'slaughter' when 'butcher', 'slaughter'
# mark for slaughter at butcher's shop # mark for slaughter at butcher's shop
u.flags2.slaughter = true u.flags2.slaughter = true
else else
# just make them drop dead # just make them drop dead
u.body.blood_count = 0 u.body.blood_count = 0
# some races dont mind having no blood, ensure they are still taken care of. # some races dont mind having no blood, ensure they are still taken care of.
u.animal.vanish_countdown = 2 u.animal.vanish_countdown = 2
end end
} }
all_races = Hash.new(0) all_races = Hash.new(0)
df.world.units.active.map { |u| df.world.units.active.map { |u|
if checkunit[u] if checkunit[u]
if (u.enemy.undead or if (u.enemy.undead or
(u.curse.add_tags1.OPPOSED_TO_LIFE and not (u.curse.add_tags1.OPPOSED_TO_LIFE and not
u.curse.rem_tags1.OPPOSED_TO_LIFE)) u.curse.rem_tags1.OPPOSED_TO_LIFE))
all_races['Undead'] += 1 all_races['Undead'] += 1
else else
all_races[u.race_tg.creature_id] += 1 all_races[u.race_tg.creature_id] += 1
end end
end end
} }
case race case race
when nil when nil
all_races.sort_by { |race, cnt| [cnt, race] }.each{ |race, cnt| puts " #{race} #{cnt}" } all_races.sort_by { |race, cnt| [cnt, race] }.each{ |race, cnt| puts " #{race} #{cnt}" }
when 'help', '?' when 'help', '?'
puts <<EOS puts <<EOS
Kills all creatures of a given race. Kills all creatures of a given race.
With no argument, lists possible targets with their head count. With no argument, lists possible targets with their head count.
With the special argument 'him' or 'her', kill only the currently selected creature. With the special argument 'him' or 'her', kill only the currently selected creature.
@ -91,61 +91,61 @@ Ex: exterminate gob
EOS EOS
when 'him', 'her', 'it', 'that' when 'him', 'her', 'it', 'that'
if him = df.unit_find if him = df.unit_find
case him.race_tg.caste[him.caste].gender case him.race_tg.caste[him.caste].gender
when 0; puts 'its a she !' if race != 'her' when 0; puts 'its a she !' if race != 'her'
when 1; puts 'its a he !' if race != 'him' when 1; puts 'its a he !' if race != 'him'
else; puts 'its an it !' if race != 'it' and race != 'that' else; puts 'its an it !' if race != 'it' and race != 'that'
end end
slayit[him] slayit[him]
else else
puts "Select a target ingame" puts "Select a target ingame"
end end
when /^undead/i when /^undead/i
count = 0 count = 0
df.world.units.active.each { |u| df.world.units.active.each { |u|
if (u.enemy.undead or if (u.enemy.undead or
(u.curse.add_tags1.OPPOSED_TO_LIFE and not (u.curse.add_tags1.OPPOSED_TO_LIFE and not
u.curse.rem_tags1.OPPOSED_TO_LIFE)) and u.curse.rem_tags1.OPPOSED_TO_LIFE)) and
checkunit[u] checkunit[u]
slayit[u] slayit[u]
count += 1 count += 1
end end
} }
puts "#{slain} #{count} undeads" puts "#{slain} #{count} undeads"
else else
if race.index(':') if race.index(':')
race, caste = race.split(':') race, caste = race.split(':')
end end
raw_race = df.match_rawname(race, all_races.keys) raw_race = df.match_rawname(race, all_races.keys)
if not raw_race if not raw_race
puts "Invalid race, use one of #{all_races.keys.sort.join(' ')}" puts "Invalid race, use one of #{all_races.keys.sort.join(' ')}"
throw :script_finished throw :script_finished
end end
race_nr = df.world.raws.creatures.all.index { |cr| cr.creature_id == raw_race } race_nr = df.world.raws.creatures.all.index { |cr| cr.creature_id == raw_race }
if caste if caste
all_castes = df.world.raws.creatures.all[race_nr].caste.map { |c| c.caste_id } all_castes = df.world.raws.creatures.all[race_nr].caste.map { |c| c.caste_id }
raw_caste = df.match_rawname(caste, all_castes) raw_caste = df.match_rawname(caste, all_castes)
if not raw_caste if not raw_caste
puts "Invalid caste, use one of #{all_castes.sort.join(' ')}" puts "Invalid caste, use one of #{all_castes.sort.join(' ')}"
throw :script_finished throw :script_finished
end end
caste_nr = all_castes.index(raw_caste) caste_nr = all_castes.index(raw_caste)
end end
count = 0 count = 0
df.world.units.active.each { |u| df.world.units.active.each { |u|
if u.race == race_nr and checkunit[u] if u.race == race_nr and checkunit[u]
next if caste_nr and u.caste != caste_nr next if caste_nr and u.caste != caste_nr
slayit[u] slayit[u]
count += 1 count += 1
end end
} }
puts "#{slain} #{count} #{raw_caste} #{raw_race}" puts "#{slain} #{count} #{raw_caste} #{raw_race}"
end end

@ -1,64 +1,64 @@
# script to fix loyalty cascade, when you order your militia to kill friendly units # script to fix loyalty cascade, when you order your militia to kill friendly units
def fixunit(unit) def fixunit(unit)
return if unit.race != df.ui.race_id or unit.civ_id != df.ui.civ_id return if unit.race != df.ui.race_id or unit.civ_id != df.ui.civ_id
links = unit.hist_figure_tg.entity_links links = unit.hist_figure_tg.entity_links
fixed = false fixed = false
# check if the unit is a civ renegade # check if the unit is a civ renegade
if i1 = links.index { |l| if i1 = links.index { |l|
l.kind_of?(DFHack::HistfigEntityLinkFormerMemberst) and l.kind_of?(DFHack::HistfigEntityLinkFormerMemberst) and
l.entity_id == df.ui.civ_id l.entity_id == df.ui.civ_id
} and i2 = links.index { |l| } and i2 = links.index { |l|
l.kind_of?(DFHack::HistfigEntityLinkEnemyst) and l.kind_of?(DFHack::HistfigEntityLinkEnemyst) and
l.entity_id == df.ui.civ_id l.entity_id == df.ui.civ_id
} }
fixed = true fixed = true
i1, i2 = i2, i1 if i1 > i2 i1, i2 = i2, i1 if i1 > i2
links.delete_at i2 links.delete_at i2
links.delete_at i1 links.delete_at i1
links << DFHack::HistfigEntityLinkMemberst.cpp_new(:entity_id => df.ui.civ_id, :link_strength => 100) links << DFHack::HistfigEntityLinkMemberst.cpp_new(:entity_id => df.ui.civ_id, :link_strength => 100)
df.add_announcement "fixloyalty: #{unit.name} is now a member of #{df.ui.civ_tg.name} again" df.add_announcement "fixloyalty: #{unit.name} is now a member of #{df.ui.civ_tg.name} again"
end end
# check if the unit is a group renegade # check if the unit is a group renegade
if i1 = links.index { |l| if i1 = links.index { |l|
l.kind_of?(DFHack::HistfigEntityLinkFormerMemberst) and l.kind_of?(DFHack::HistfigEntityLinkFormerMemberst) and
l.entity_id == df.ui.group_id l.entity_id == df.ui.group_id
} and i2 = links.index { |l| } and i2 = links.index { |l|
l.kind_of?(DFHack::HistfigEntityLinkEnemyst) and l.kind_of?(DFHack::HistfigEntityLinkEnemyst) and
l.entity_id == df.ui.group_id l.entity_id == df.ui.group_id
} }
fixed = true fixed = true
i1, i2 = i2, i1 if i1 > i2 i1, i2 = i2, i1 if i1 > i2
links.delete_at i2 links.delete_at i2
links.delete_at i1 links.delete_at i1
links << DFHack::HistfigEntityLinkMemberst.cpp_new(:entity_id => df.ui.group_id, :link_strength => 100) links << DFHack::HistfigEntityLinkMemberst.cpp_new(:entity_id => df.ui.group_id, :link_strength => 100)
df.add_announcement "fixloyalty: #{unit.name} is now a member of #{df.ui.group_tg.name} again" df.add_announcement "fixloyalty: #{unit.name} is now a member of #{df.ui.group_tg.name} again"
end end
# fix the 'is an enemy' cache matrix (mark to be recalculated by the game when needed) # fix the 'is an enemy' cache matrix (mark to be recalculated by the game when needed)
if fixed and unit.enemy.enemy_status_slot != -1 if fixed and unit.enemy.enemy_status_slot != -1
i = unit.enemy.enemy_status_slot i = unit.enemy.enemy_status_slot
unit.enemy.enemy_status_slot = -1 unit.enemy.enemy_status_slot = -1
cache = df.world.enemy_status_cache cache = df.world.enemy_status_cache
cache.slot_used[i] = false cache.slot_used[i] = false
cache.rel_map[i].map! { -1 } cache.rel_map[i].map! { -1 }
cache.rel_map.each { |a| a[i] = -1 } cache.rel_map.each { |a| a[i] = -1 }
cache.next_slot = i if cache.next_slot > i cache.next_slot = i if cache.next_slot > i
end end
# return true if we actually fixed the unit # return true if we actually fixed the unit
fixed fixed
end end
count = 0 count = 0
df.unit_citizens.each { |u| df.unit_citizens.each { |u|
count += 1 if fixunit(u) count += 1 if fixunit(u)
} }
if count > 0 if count > 0
puts "loyalty cascade fixed (#{count} dwarves)" puts "loyalty cascade fixed (#{count} dwarves)"
else else
puts "no loyalty cascade found" puts "no loyalty cascade found"
end end

@ -5,21 +5,21 @@
count = 0 count = 0
df.world.buildings.all.each { |bld| df.world.buildings.all.each { |bld|
# for all doors # for all doors
next if bld._rtti_classname != :building_doorst next if bld._rtti_classname != :building_doorst
# check if it is open # check if it is open
next if bld.close_timer == 0 next if bld.close_timer == 0
# check if occupancy is set # check if occupancy is set
occ = df.map_occupancy_at(bld.x1, bld.y1, bld.z) occ = df.map_occupancy_at(bld.x1, bld.y1, bld.z)
if (occ.unit or occ.unit_grounded) and not if (occ.unit or occ.unit_grounded) and not
# check if an unit is present # check if an unit is present
df.world.units.active.find { |u| u.pos.x == bld.x1 and u.pos.y == bld.y1 and u.pos.z == bld.z } df.world.units.active.find { |u| u.pos.x == bld.x1 and u.pos.y == bld.y1 and u.pos.z == bld.z }
count += 1 count += 1
occ.unit = occ.unit_grounded = false occ.unit = occ.unit_grounded = false
end end
if occ.item and not df.world.items.all.find { |i| i.pos.x == bld.x1 and i.pos.y == bld.y1 and i.pos.z == bld.z } if occ.item and not df.world.items.all.find { |i| i.pos.x == bld.x1 and i.pos.y == bld.y1 and i.pos.z == bld.z }
count += 1 count += 1
occ.item = false occ.item = false
end end
} }
puts "unstuck #{count} doors" puts "unstuck #{count} doors"

@ -30,9 +30,9 @@ if args.help then
end end
if(args.unit) then if(args.unit) then
unit = df.unit.find(args.unit) unit = df.unit.find(args.unit)
else else
unit = dfhack.gui.getSelectedUnit() unit = dfhack.gui.getSelectedUnit()
end end
if not unit then if not unit then

@ -8,42 +8,42 @@ count_max = 100 if count_max == 0
@raws_plant_name ||= {} @raws_plant_name ||= {}
@raws_plant_growdur ||= {} @raws_plant_growdur ||= {}
if @raws_plant_name.empty? if @raws_plant_name.empty?
df.world.raws.plants.all.each_with_index { |p, idx| df.world.raws.plants.all.each_with_index { |p, idx|
@raws_plant_name[idx] = p.id @raws_plant_name[idx] = p.id
@raws_plant_growdur[idx] = p.growdur @raws_plant_growdur[idx] = p.growdur
} }
end end
inventory = Hash.new(0) inventory = Hash.new(0)
df.world.items.other[:SEEDS].each { |seed| df.world.items.other[:SEEDS].each { |seed|
next if not seed.flags.in_building next if not seed.flags.in_building
next if not seed.general_refs.find { |ref| ref._rtti_classname == :general_ref_building_holderst } next if not seed.general_refs.find { |ref| ref._rtti_classname == :general_ref_building_holderst }
next if seed.grow_counter >= @raws_plant_growdur[seed.mat_index] next if seed.grow_counter >= @raws_plant_growdur[seed.mat_index]
inventory[seed.mat_index] += 1 inventory[seed.mat_index] += 1
} }
if !material or material == 'help' or material == 'list' if !material or material == 'help' or material == 'list'
# show a list of available crop types # show a list of available crop types
inventory.sort_by { |mat, c| c }.each { |mat, c| inventory.sort_by { |mat, c| c }.each { |mat, c|
name = df.world.raws.plants.all[mat].id name = df.world.raws.plants.all[mat].id
puts " #{name} #{c}" puts " #{name} #{c}"
} }
else else
mat = df.match_rawname(material, inventory.keys.map { |k| @raws_plant_name[k] }) mat = df.match_rawname(material, inventory.keys.map { |k| @raws_plant_name[k] })
unless wantmat = @raws_plant_name.index(mat) unless wantmat = @raws_plant_name.index(mat)
raise "invalid plant material #{material}" raise "invalid plant material #{material}"
end end
count = 0 count = 0
df.world.items.other[:SEEDS].each { |seed| df.world.items.other[:SEEDS].each { |seed|
next if seed.mat_index != wantmat next if seed.mat_index != wantmat
next if not seed.flags.in_building next if not seed.flags.in_building
next if not seed.general_refs.find { |ref| ref._rtti_classname == :general_ref_building_holderst } next if not seed.general_refs.find { |ref| ref._rtti_classname == :general_ref_building_holderst }
next if seed.grow_counter >= @raws_plant_growdur[seed.mat_index] next if seed.grow_counter >= @raws_plant_growdur[seed.mat_index]
seed.grow_counter = @raws_plant_growdur[seed.mat_index] seed.grow_counter = @raws_plant_growdur[seed.mat_index]
count += 1 count += 1
} }
puts "Grown #{count} #{mat}" puts "Grown #{count} #{mat}"
end end

@ -31,10 +31,10 @@ function CheckCursor(p)
return true return true
end end
function getxyz() -- this will return pointers x,y and z coordinates. function getxyz() -- this will return pointers x,y and z coordinates.
local x=df.global.cursor.x local x=df.global.cursor.x
local y=df.global.cursor.y local y=df.global.cursor.y
local z=df.global.cursor.z local z=df.global.cursor.z
return x,y,z -- return the coords return x,y,z -- return the coords
end end
function GetCaste(race_id,caste_id) function GetCaste(race_id,caste_id)
@ -338,8 +338,8 @@ local cheats={
local dft=require("plugins.dfusion.tools") local dft=require("plugins.dfusion.tools")
for k,v in pairs(unit_list) do for k,v in pairs(unit_list) do
dft.healunit(v) dft.healunit(v)
end end
return true return true
end}, end},
{name="Power up",f=function (unit_list) {name="Power up",f=function (unit_list)
local dft=require("plugins.dfusion.tools") local dft=require("plugins.dfusion.tools")
@ -352,16 +352,16 @@ end},
if not CheckCursor(pos) then if not CheckCursor(pos) then
return false return false
end end
adv=df.global.world.units.active[0] adv=df.global.world.units.active[0]
item=getItemsAtPos(getxyz())[1] item=getItemsAtPos(getxyz())[1]
print(item.id) print(item.id)
for k,v in pairs(unit_list) do for k,v in pairs(unit_list) do
v.riding_item_id=item.id v.riding_item_id=item.id
local ref=df.general_ref_unit_riderst:new() local ref=df.general_ref_unit_riderst:new()
ref.unit_id=v.id ref.unit_id=v.id
item.general_refs:insert("#",ref) item.general_refs:insert("#",ref)
end end
return true return true
end}, end},
} }
--[[ todo: add cheats...]]-- --[[ todo: add cheats...]]--

@ -46,7 +46,7 @@ GmEditorUi = defclass(GmEditorUi, gui.FramedScreen)
GmEditorUi.ATTRS={ GmEditorUi.ATTRS={
frame_style = gui.GREY_LINE_FRAME, frame_style = gui.GREY_LINE_FRAME,
frame_title = "GameMaster's editor", frame_title = "GameMaster's editor",
} }
function GmEditorUi:onHelp() function GmEditorUi:onHelp()
self.subviews.pages:setSelected(2) self.subviews.pages:setSelected(2)
end end
@ -326,7 +326,7 @@ function GmEditorUi:updateTarget(preserve_pos,reindex)
self.subviews.lbl_current_item:itemById('name').text=tostring(trg.target) self.subviews.lbl_current_item:itemById('name').text=tostring(trg.target)
local t={} local t={}
for k,v in pairs(trg.keys) do for k,v in pairs(trg.keys) do
table.insert(t,{text={{text=string.format("%-25s",tostring(v))},{gap=1,text=getStringValue(trg,v)}}}) table.insert(t,{text={{text=string.format("%-25s",tostring(v))},{gap=1,text=getStringValue(trg,v)}}})
end end
local last_pos local last_pos
if preserve_pos then if preserve_pos then

@ -111,7 +111,7 @@ function getRestrictiveMatFilter(itemType)
end end
function createItem(mat,itemType,quality,creator,description) function createItem(mat,itemType,quality,creator,description)
dfhack.items.createItem(itemType[1], itemType[2], mat[1], mat[2], creator) dfhack.items.createItem(itemType[1], itemType[2], mat[1], mat[2], creator)
if df.item_type[itemType[1]]=='SLAB' then if df.item_type[itemType[1]]=='SLAB' then
item.description=description item.description=description
end end

@ -25,13 +25,13 @@ local mod_dir=dfhack.getDFPath().."/hack/mods"
]] ]]
function fileExists(filename) function fileExists(filename)
local file=io.open(filename,"rb") local file=io.open(filename,"rb")
if file==nil then if file==nil then
return return
else else
file:close() file:close()
return true return true
end end
end end
if not fileExists(init_file) then if not fileExists(init_file) then
local initFile=io.open(init_file,"a") local initFile=io.open(init_file,"a")
@ -47,10 +47,10 @@ function copyFile(from,to) --oh so primitive
fileto:close() fileto:close()
end end
function patchInit(initFileName,patch_guard,code) function patchInit(initFileName,patch_guard,code)
local initFile=io.open(initFileName,"a") local initFile=io.open(initFileName,"a")
initFile:write(string.format("\n%s\n%s\n%s",patch_guard[1], initFile:write(string.format("\n%s\n%s\n%s",patch_guard[1],
code,patch_guard[2])) code,patch_guard[2]))
initFile:close() initFile:close()
end end
function patchDofile( luaFileName,patch_guard,dofile_list,mod_path ) function patchDofile( luaFileName,patch_guard,dofile_list,mod_path )
local luaFile=io.open(luaFileName,"a") local luaFile=io.open(luaFileName,"a")
@ -77,89 +77,89 @@ function patchFile(file_name,patch_guard,after_string,code)
entityFile:close() entityFile:close()
end end
function findGuards(str,start,patch_guard) function findGuards(str,start,patch_guard)
local pStart=string.find(str,patch_guard[1],start) local pStart=string.find(str,patch_guard[1],start)
if pStart==nil then return nil end if pStart==nil then return nil end
local pEnd=string.find(str,patch_guard[2],pStart) local pEnd=string.find(str,patch_guard[2],pStart)
if pEnd==nil then error("Start guard token found, but end was not found") end if pEnd==nil then error("Start guard token found, but end was not found") end
return pStart-1,pEnd+#patch_guard[2]+1 return pStart-1,pEnd+#patch_guard[2]+1
end end
function findGuardsFile(filename,patch_guard) function findGuardsFile(filename,patch_guard)
local file=io.open(filename,"r") local file=io.open(filename,"r")
local buf=file:read("*all") local buf=file:read("*all")
return findGuards(buf,1,patch_guard) return findGuards(buf,1,patch_guard)
end end
function unPatchFile(filename,patch_guard) function unPatchFile(filename,patch_guard)
local file=io.open(filename,"r") local file=io.open(filename,"r")
local buf=file:read("*all") local buf=file:read("*all")
file:close() file:close()
local newBuf="" local newBuf=""
local pos=1 local pos=1
local lastPos=1 local lastPos=1
repeat repeat
local endPos local endPos
pos,endPos=findGuards(buf,lastPos,patch_guard) pos,endPos=findGuards(buf,lastPos,patch_guard)
newBuf=newBuf..string.sub(buf,lastPos,pos) newBuf=newBuf..string.sub(buf,lastPos,pos)
if endPos~=nil then if endPos~=nil then
lastPos=endPos lastPos=endPos
end end
until pos==nil until pos==nil
local file=io.open(filename,"w+") local file=io.open(filename,"w+")
file:write(newBuf) file:write(newBuf)
file:close() file:close()
end end
function checkInstalled(dfMod) --try to figure out if installed function checkInstalled(dfMod) --try to figure out if installed
if dfMod.checkInstalled then if dfMod.checkInstalled then
return dfMod.checkInstalled() return dfMod.checkInstalled()
else else
if dfMod.raws_list then if dfMod.raws_list then
for k,v in pairs(dfMod.raws_list) do for k,v in pairs(dfMod.raws_list) do
if fileExists(dfhack.getDFPath().."/raw/objects/"..v) then if fileExists(dfhack.getDFPath().."/raw/objects/"..v) then
return true,v return true,v
end end
end end
end end
if dfMod.patch_entity then if dfMod.patch_entity then
if findGuardsFile(entity_file,dfMod.guard)~=nil then if findGuardsFile(entity_file,dfMod.guard)~=nil then
return true,"entity_default.txt" return true,"entity_default.txt"
end end
end end
if dfMod.patch_files then if dfMod.patch_files then
for k,v in pairs(dfMod.patch_files) do for k,v in pairs(dfMod.patch_files) do
if findGuardsFile(dfhack.getDFPath().."/raw/objects/"..v.filename,dfMod.guard)~=nil then if findGuardsFile(dfhack.getDFPath().."/raw/objects/"..v.filename,dfMod.guard)~=nil then
return true,"v.filename" return true,"v.filename"
end end
end end
end end
if dfMod.patch_init then if dfMod.patch_init then
if findGuardsFile(init_file,dfMod.guard_init)~=nil then if findGuardsFile(init_file,dfMod.guard_init)~=nil then
return true,"init.lua" return true,"init.lua"
end end
end end
end end
end end
manager=defclass(manager,gui.FramedScreen) manager=defclass(manager,gui.FramedScreen)
function manager:init(args) function manager:init(args)
self.mods={} self.mods={}
local mods=self.mods local mods=self.mods
local mlist=dfhack.internal.getDir(mod_dir) local mlist=dfhack.internal.getDir(mod_dir)
if #mlist==0 then if #mlist==0 then
qerror("Mod directory not found! Are you sure it is in:"..mod_dir) qerror("Mod directory not found! Are you sure it is in:"..mod_dir)
end end
for k,v in ipairs(mlist) do for k,v in ipairs(mlist) do
if v~="." and v~=".." then if v~="." and v~=".." then
local f,modData=pcall(dofile,mod_dir.."/".. v .. "/init.lua") local f,modData=pcall(dofile,mod_dir.."/".. v .. "/init.lua")
if f then if f then
mods[modData.name]=modData mods[modData.name]=modData
modData.guard=modData.guard or {">>"..modData.name.." patch","<<End "..modData.name.." patch"} modData.guard=modData.guard or {">>"..modData.name.." patch","<<End "..modData.name.." patch"}
modData.guard_init={"--"..modData.guard[1],"--"..modData.guard[2]} modData.guard_init={"--"..modData.guard[1],"--"..modData.guard[2]}
modData.path=mod_dir.."/"..v..'/' modData.path=mod_dir.."/"..v..'/'
end end
end end
end end
---show thingy ---show thingy
local modList={} local modList={}
for k,v in pairs(self.mods) do for k,v in pairs(self.mods) do
@ -270,29 +270,29 @@ function manager:install(trgMod,force)
local isInstalled,file=checkInstalled(trgMod) -- maybe load from .installed? local isInstalled,file=checkInstalled(trgMod) -- maybe load from .installed?
if isInstalled then if isInstalled then
qerror("Mod already installed. File:"..file) qerror("Mod already installed. File:"..file)
end end
end end
print("installing:"..trgMod.name) print("installing:"..trgMod.name)
if trgMod.pre_install then if trgMod.pre_install then
trgMod.pre_install(args) trgMod.pre_install(args)
end end
if trgMod.raws_list then if trgMod.raws_list then
for k,v in pairs(trgMod.raws_list) do for k,v in pairs(trgMod.raws_list) do
copyFile(trgMod.path..v,dfhack.getDFPath().."/raw/objects/"..v) copyFile(trgMod.path..v,dfhack.getDFPath().."/raw/objects/"..v)
end end
end end
if trgMod.patch_entity then if trgMod.patch_entity then
local entity_target="[ENTITY:MOUNTAIN]" --TODO configure local entity_target="[ENTITY:MOUNTAIN]" --TODO configure
patchFile(entity_file,trgMod.guard,entity_target,trgMod.patch_entity) patchFile(entity_file,trgMod.guard,entity_target,trgMod.patch_entity)
end end
if trgMod.patch_files then if trgMod.patch_files then
for k,v in pairs(trgMod.patch_files) do for k,v in pairs(trgMod.patch_files) do
patchFile(dfhack.getDFPath().."/raw/objects/"..v.filename,trgMod.guard,v.after,v.patch) patchFile(dfhack.getDFPath().."/raw/objects/"..v.filename,trgMod.guard,v.after,v.patch)
end end
end end
if trgMod.patch_init then if trgMod.patch_init then
patchInit(init_file,trgMod.guard_init,trgMod.patch_init) patchInit(init_file,trgMod.guard_init,trgMod.patch_init)
end end
if trgMod.patch_dofile then if trgMod.patch_dofile then
patchDofile(init_file,trgMod.guard_init,trgMod.patch_dofile,trgMod.path) patchDofile(init_file,trgMod.guard_init,trgMod.patch_dofile,trgMod.path)
end end
@ -305,29 +305,29 @@ function manager:install(trgMod,force)
end end
function manager:uninstall(trgMod) function manager:uninstall(trgMod)
print("Uninstalling:"..trgMod.name) print("Uninstalling:"..trgMod.name)
if trgMod.pre_uninstall then if trgMod.pre_uninstall then
trgMod.pre_uninstall(args) trgMod.pre_uninstall(args)
end end
if trgMod.raws_list then if trgMod.raws_list then
for k,v in pairs(trgMod.raws_list) do for k,v in pairs(trgMod.raws_list) do
os.remove(dfhack.getDFPath().."/raw/objects/"..v) os.remove(dfhack.getDFPath().."/raw/objects/"..v)
end end
end end
if trgMod.patch_entity then if trgMod.patch_entity then
unPatchFile(entity_file,trgMod.guard) unPatchFile(entity_file,trgMod.guard)
end end
if trgMod.patch_files then if trgMod.patch_files then
for k,v in pairs(trgMod.patch_files) do for k,v in pairs(trgMod.patch_files) do
unPatchFile(dfhack.getDFPath().."/raw/objects/"..v.filename,trgMod.guard) unPatchFile(dfhack.getDFPath().."/raw/objects/"..v.filename,trgMod.guard)
end end
end end
if trgMod.patch_init or trgMod.patch_dofile then if trgMod.patch_init or trgMod.patch_dofile then
unPatchFile(init_file,trgMod.guard_init) unPatchFile(init_file,trgMod.guard_init)
end end
trgMod.installed=false trgMod.installed=false
if trgMod.post_uninstall then if trgMod.post_uninstall then
trgMod.post_uninstall(args) trgMod.post_uninstall(args)
end end
print("done") print("done")

@ -1,78 +1,78 @@
# control your levers from the dfhack console # control your levers from the dfhack console
def lever_pull_job(bld) def lever_pull_job(bld)
ref = DFHack::GeneralRefBuildingHolderst.cpp_new ref = DFHack::GeneralRefBuildingHolderst.cpp_new
ref.building_id = bld.id ref.building_id = bld.id
job = DFHack::Job.cpp_new job = DFHack::Job.cpp_new
job.job_type = :PullLever job.job_type = :PullLever
job.pos = [bld.centerx, bld.centery, bld.z] job.pos = [bld.centerx, bld.centery, bld.z]
job.general_refs << ref job.general_refs << ref
bld.jobs << job bld.jobs << job
df.job_link job df.job_link job
puts lever_descr(bld) puts lever_descr(bld)
end end
def lever_pull_cheat(bld) def lever_pull_cheat(bld)
bld.linked_mechanisms.each { |i| bld.linked_mechanisms.each { |i|
i.general_refs.grep(DFHack::GeneralRefBuildingHolderst).each { |r| i.general_refs.grep(DFHack::GeneralRefBuildingHolderst).each { |r|
r.building_tg.setTriggerState(bld.state) r.building_tg.setTriggerState(bld.state)
} }
} }
bld.state = (bld.state == 0 ? 1 : 0) bld.state = (bld.state == 0 ? 1 : 0)
puts lever_descr(bld) puts lever_descr(bld)
end end
def lever_descr(bld, idx=nil) def lever_descr(bld, idx=nil)
ret = [] ret = []
# lever description # lever description
descr = '' descr = ''
descr << "#{idx}: " if idx descr << "#{idx}: " if idx
descr << "lever ##{bld.id} @[#{bld.centerx}, #{bld.centery}, #{bld.z}] #{bld.state == 0 ? '\\' : '/'}" descr << "lever ##{bld.id} @[#{bld.centerx}, #{bld.centery}, #{bld.z}] #{bld.state == 0 ? '\\' : '/'}"
bld.jobs.each { |j| bld.jobs.each { |j|
if j.job_type == :PullLever if j.job_type == :PullLever
flags = '' flags = ''
flags << ', repeat' if j.flags.repeat flags << ', repeat' if j.flags.repeat
flags << ', suspended' if j.flags.suspend flags << ', suspended' if j.flags.suspend
descr << " (pull order#{flags})" descr << " (pull order#{flags})"
end end
} }
bld.linked_mechanisms.map { |i| bld.linked_mechanisms.map { |i|
i.general_refs.grep(DFHack::GeneralRefBuildingHolderst) i.general_refs.grep(DFHack::GeneralRefBuildingHolderst)
}.flatten.each { |r| }.flatten.each { |r|
# linked building description # linked building description
tg = r.building_tg tg = r.building_tg
state = '' state = ''
if tg.respond_to?(:gate_flags) if tg.respond_to?(:gate_flags)
state << (tg.gate_flags.closed ? 'closed' : 'opened') state << (tg.gate_flags.closed ? 'closed' : 'opened')
state << ", closing (#{tg.timer})" if tg.gate_flags.closing state << ", closing (#{tg.timer})" if tg.gate_flags.closing
state << ", opening (#{tg.timer})" if tg.gate_flags.opening state << ", opening (#{tg.timer})" if tg.gate_flags.opening
end end
ret << (descr + " linked to #{tg._rtti_classname} ##{tg.id} @[#{tg.centerx}, #{tg.centery}, #{tg.z}] #{state}") ret << (descr + " linked to #{tg._rtti_classname} ##{tg.id} @[#{tg.centerx}, #{tg.centery}, #{tg.z}] #{state}")
# indent other links # indent other links
descr = descr.gsub(/./, ' ') descr = descr.gsub(/./, ' ')
} }
ret << descr if ret.empty? ret << descr if ret.empty?
ret ret
end end
def lever_list def lever_list
@lever_list = [] @lever_list = []
df.world.buildings.other[:TRAP].find_all { |bld| df.world.buildings.other[:TRAP].find_all { |bld|
bld.trap_type == :Lever bld.trap_type == :Lever
}.sort_by { |bld| bld.id }.each { |bld| }.sort_by { |bld| bld.id }.each { |bld|
puts lever_descr(bld, @lever_list.length) puts lever_descr(bld, @lever_list.length)
@lever_list << bld.id @lever_list << bld.id
} }
end end
@ -80,33 +80,33 @@ end
case $script_args[0] case $script_args[0]
when 'pull' when 'pull'
cheat = $script_args.delete('--cheat') || $script_args.delete('--now') cheat = $script_args.delete('--cheat') || $script_args.delete('--now')
id = $script_args[1].to_i id = $script_args[1].to_i
id = @lever_list[id] || id id = @lever_list[id] || id
bld = df.building_find(id) bld = df.building_find(id)
raise 'invalid lever id' if not bld raise 'invalid lever id' if not bld
if cheat if cheat
lever_pull_cheat(bld) lever_pull_cheat(bld)
else else
lever_pull_job(bld) lever_pull_job(bld)
end end
when 'list' when 'list'
lever_list lever_list
when /^\d+$/ when /^\d+$/
id = $script_args[0].to_i id = $script_args[0].to_i
id = @lever_list[id] || id id = @lever_list[id] || id
bld = df.building_find(id) bld = df.building_find(id)
raise 'invalid lever id' if not bld raise 'invalid lever id' if not bld
puts lever_descr(bld) puts lever_descr(bld)
else else
puts <<EOS puts <<EOS
Lever control from the dfhack console Lever control from the dfhack console
Usage: Usage:

@ -20,10 +20,10 @@ def find_all_ore_veins
} }
df.onstatechange_register_once { |st| df.onstatechange_register_once { |st|
if st == :MAP_LOADED if st == :MAP_LOADED
$ore_veins = nil # invalidate veins cache $ore_veins = nil # invalidate veins cache
true true
end end
} }
$ore_veins $ore_veins

@ -2,39 +2,39 @@
case $script_args[0] case $script_args[0]
when '?', 'help' when '?', 'help'
puts <<EOS puts <<EOS
Run this script with the cursor on top of a pit/pond activity zone, or with a zone identifier as argument. Run this script with the cursor on top of a pit/pond activity zone, or with a zone identifier as argument.
It will mark all caged creatures on tiles covered by the zone to be dumped. It will mark all caged creatures on tiles covered by the zone to be dumped.
Works best with an animal stockpile on top of the pit/pond zone. Works best with an animal stockpile on top of the pit/pond zone.
EOS EOS
throw :script_finished throw :script_finished
when /(\d+)/ when /(\d+)/
nr = $1.to_i nr = $1.to_i
bld = df.world.buildings.other[:ACTIVITY_ZONE].find { |zone| zone.zone_num == nr } bld = df.world.buildings.other[:ACTIVITY_ZONE].find { |zone| zone.zone_num == nr }
else else
bld = df.world.buildings.other[:ACTIVITY_ZONE].find { |zone| bld = df.world.buildings.other[:ACTIVITY_ZONE].find { |zone|
zone.zone_flags.pit_pond and zone.z == df.cursor.z and zone.zone_flags.pit_pond and zone.z == df.cursor.z and
zone.x1 <= df.cursor.x and zone.x2 >= df.cursor.x and zone.y1 <= df.cursor.y and zone.y2 >= df.cursor.y zone.x1 <= df.cursor.x and zone.x2 >= df.cursor.x and zone.y1 <= df.cursor.y and zone.y2 >= df.cursor.y
} }
end end
if not bld if not bld
puts "Please select a pit/pond zone" puts "Please select a pit/pond zone"
throw :script_finished throw :script_finished
end end
found = 0 found = 0
df.world.items.other[:CAGE].each { |cg| df.world.items.other[:CAGE].each { |cg|
next if not cg.flags.on_ground next if not cg.flags.on_ground
next if cg.pos.z != bld.z or cg.pos.x < bld.x1 or cg.pos.x > bld.x2 or cg.pos.y < bld.y1 or cg.pos.y > bld.y2 next if cg.pos.z != bld.z or cg.pos.x < bld.x1 or cg.pos.x > bld.x2 or cg.pos.y < bld.y1 or cg.pos.y > bld.y2
next if not uref = cg.general_refs.grep(DFHack::GeneralRefContainsUnitst).first next if not uref = cg.general_refs.grep(DFHack::GeneralRefContainsUnitst).first
found += 1 found += 1
u = uref.unit_tg u = uref.unit_tg
puts "Pitting #{u.race_tg.name[0]} #{u.id} #{u.name}" puts "Pitting #{u.race_tg.name[0]} #{u.id} #{u.name}"
u.general_refs << DFHack::GeneralRefBuildingCivzoneAssignedst.cpp_new(:building_id => bld.id) u.general_refs << DFHack::GeneralRefBuildingCivzoneAssignedst.cpp_new(:building_id => bld.id)
bld.assigned_units << u.id bld.assigned_units << u.id
} }
puts "No creature available for pitting" if found == 0 puts "No creature available for pitting" if found == 0

@ -3,73 +3,73 @@
$sources ||= [] $sources ||= []
cur_source = { cur_source = {
:liquid => 'water', :liquid => 'water',
:amount => 7, :amount => 7,
:pos => [df.cursor.x, df.cursor.y, df.cursor.z] :pos => [df.cursor.x, df.cursor.y, df.cursor.z]
} }
cmd = 'help' cmd = 'help'
$script_args.each { |a| $script_args.each { |a|
case a.downcase case a.downcase
when 'water', 'magma' when 'water', 'magma'
cur_source[:liquid] = a.downcase cur_source[:liquid] = a.downcase
when /^\d+$/ when /^\d+$/
cur_source[:amount] = a.to_i cur_source[:amount] = a.to_i
when 'add', 'del', 'delete', 'clear', 'help', 'list' when 'add', 'del', 'delete', 'clear', 'help', 'list'
cmd = a.downcase cmd = a.downcase
else else
puts "source: unhandled argument #{a}" puts "source: unhandled argument #{a}"
end end
} }
case cmd case cmd
when 'add' when 'add'
$sources_onupdate ||= df.onupdate_register('sources', 12) { $sources_onupdate ||= df.onupdate_register('sources', 12) {
# called every 12 game ticks (100x a dwarf day) # called every 12 game ticks (100x a dwarf day)
$sources.each { |s| $sources.each { |s|
if tile = df.map_tile_at(*s[:pos]) and tile.shape_passableflow if tile = df.map_tile_at(*s[:pos]) and tile.shape_passableflow
# XXX does not check current liquid_type # XXX does not check current liquid_type
des = tile.designation des = tile.designation
cur = des.flow_size cur = des.flow_size
if cur != s[:amount] if cur != s[:amount]
tile.spawn_liquid((cur > s[:amount] ? cur-1 : cur+1), s[:liquid] == 'magma') tile.spawn_liquid((cur > s[:amount] ? cur-1 : cur+1), s[:liquid] == 'magma')
end end
end end
} }
if $sources.empty? if $sources.empty?
df.onupdate_unregister($sources_onupdate) df.onupdate_unregister($sources_onupdate)
$sources_onupdate = nil $sources_onupdate = nil
end end
} }
if cur_source[:pos][0] >= 0 if cur_source[:pos][0] >= 0
if tile = df.map_tile_at(*cur_source[:pos]) if tile = df.map_tile_at(*cur_source[:pos])
if tile.shape_passableflow if tile.shape_passableflow
$sources << cur_source $sources << cur_source
else else
puts "Impassable tile: I'm afraid I can't do that, Dave" puts "Impassable tile: I'm afraid I can't do that, Dave"
end end
else else
puts "Unallocated map block - build something here first" puts "Unallocated map block - build something here first"
end end
else else
puts "Please put the game cursor where you want a source" puts "Please put the game cursor where you want a source"
end end
when 'del', 'delete' when 'del', 'delete'
$sources.delete_if { |s| s[:pos] == cur_source[:pos] } $sources.delete_if { |s| s[:pos] == cur_source[:pos] }
when 'clear' when 'clear'
$sources.clear $sources.clear
when 'list' when 'list'
puts "Source list:", $sources.map { |s| puts "Source list:", $sources.map { |s|
" #{s[:pos].inspect} #{s[:liquid]} #{s[:amount]}" " #{s[:pos].inspect} #{s[:liquid]} #{s[:amount]}"
} }
puts "Current cursor pos: #{[df.cursor.x, df.cursor.y, df.cursor.z].inspect}" if df.cursor.x >= 0 puts "Current cursor pos: #{[df.cursor.x, df.cursor.y, df.cursor.z].inspect}" if df.cursor.x >= 0
else else
puts <<EOS puts <<EOS
Creates a new infinite liquid source at the cursor. Creates a new infinite liquid source at the cursor.
Examples: Examples:

@ -1,185 +1,185 @@
# mark stuff inside of cages for dumping. # mark stuff inside of cages for dumping.
def plural(nr, name) def plural(nr, name)
# '1 cage' / '4 cages' # '1 cage' / '4 cages'
"#{nr} #{name}#{'s' if nr > 1}" "#{nr} #{name}#{'s' if nr > 1}"
end end
def cage_dump_items(list) def cage_dump_items(list)
count = 0 count = 0
count_cage = 0 count_cage = 0
list.each { |cage| list.each { |cage|
pre_count = count pre_count = count
cage.general_refs.each { |ref| cage.general_refs.each { |ref|
next unless ref.kind_of?(DFHack::GeneralRefContainsItemst) next unless ref.kind_of?(DFHack::GeneralRefContainsItemst)
next if ref.item_tg.flags.dump next if ref.item_tg.flags.dump
count += 1 count += 1
ref.item_tg.flags.dump = true ref.item_tg.flags.dump = true
} }
count_cage += 1 if pre_count != count count_cage += 1 if pre_count != count
} }
puts "Dumped #{plural(count, 'item')} in #{plural(count_cage, 'cage')}" puts "Dumped #{plural(count, 'item')} in #{plural(count_cage, 'cage')}"
end end
def cage_dump_armor(list) def cage_dump_armor(list)
count = 0 count = 0
count_cage = 0 count_cage = 0
list.each { |cage| list.each { |cage|
pre_count = count pre_count = count
cage.general_refs.each { |ref| cage.general_refs.each { |ref|
next unless ref.kind_of?(DFHack::GeneralRefContainsUnitst) next unless ref.kind_of?(DFHack::GeneralRefContainsUnitst)
ref.unit_tg.inventory.each { |it| ref.unit_tg.inventory.each { |it|
next if it.mode != :Worn next if it.mode != :Worn
next if it.item.flags.dump next if it.item.flags.dump
count += 1 count += 1
it.item.flags.dump = true it.item.flags.dump = true
} }
} }
count_cage += 1 if pre_count != count count_cage += 1 if pre_count != count
} }
puts "Dumped #{plural(count, 'armor piece')} in #{plural(count_cage, 'cage')}" puts "Dumped #{plural(count, 'armor piece')} in #{plural(count_cage, 'cage')}"
end end
def cage_dump_weapons(list) def cage_dump_weapons(list)
count = 0 count = 0
count_cage = 0 count_cage = 0
list.each { |cage| list.each { |cage|
pre_count = count pre_count = count
cage.general_refs.each { |ref| cage.general_refs.each { |ref|
next unless ref.kind_of?(DFHack::GeneralRefContainsUnitst) next unless ref.kind_of?(DFHack::GeneralRefContainsUnitst)
ref.unit_tg.inventory.each { |it| ref.unit_tg.inventory.each { |it|
next if it.mode != :Weapon next if it.mode != :Weapon
next if it.item.flags.dump next if it.item.flags.dump
count += 1 count += 1
it.item.flags.dump = true it.item.flags.dump = true
} }
} }
count_cage += 1 if pre_count != count count_cage += 1 if pre_count != count
} }
puts "Dumped #{plural(count, 'weapon')} in #{plural(count_cage, 'cage')}" puts "Dumped #{plural(count, 'weapon')} in #{plural(count_cage, 'cage')}"
end end
def cage_dump_all(list) def cage_dump_all(list)
count = 0 count = 0
count_cage = 0 count_cage = 0
list.each { |cage| list.each { |cage|
pre_count = count pre_count = count
cage.general_refs.each { |ref| cage.general_refs.each { |ref|
case ref case ref
when DFHack::GeneralRefContainsItemst when DFHack::GeneralRefContainsItemst
next if ref.item_tg.flags.dump next if ref.item_tg.flags.dump
count += 1 count += 1
ref.item_tg.flags.dump = true ref.item_tg.flags.dump = true
when DFHack::GeneralRefContainsUnitst when DFHack::GeneralRefContainsUnitst
ref.unit_tg.inventory.each { |it| ref.unit_tg.inventory.each { |it|
next if it.item.flags.dump next if it.item.flags.dump
count += 1 count += 1
it.item.flags.dump = true it.item.flags.dump = true
} }
end end
} }
count_cage += 1 if pre_count != count count_cage += 1 if pre_count != count
} }
puts "Dumped #{plural(count, 'item')} in #{plural(count_cage, 'cage')}" puts "Dumped #{plural(count, 'item')} in #{plural(count_cage, 'cage')}"
end end
def cage_dump_list(list) def cage_dump_list(list)
count_total = Hash.new(0) count_total = Hash.new(0)
empty_cages = 0 empty_cages = 0
list.each { |cage| list.each { |cage|
count = Hash.new(0) count = Hash.new(0)
cage.general_refs.each { |ref| cage.general_refs.each { |ref|
case ref case ref
when DFHack::GeneralRefContainsItemst when DFHack::GeneralRefContainsItemst
count[ref.item_tg._rtti_classname] += 1 count[ref.item_tg._rtti_classname] += 1
when DFHack::GeneralRefContainsUnitst when DFHack::GeneralRefContainsUnitst
ref.unit_tg.inventory.each { |it| ref.unit_tg.inventory.each { |it|
count[it.item._rtti_classname] += 1 count[it.item._rtti_classname] += 1
} }
# TODO vermin ? # TODO vermin ?
else else
puts "unhandled ref #{ref.inspect}" if $DEBUG puts "unhandled ref #{ref.inspect}" if $DEBUG
end end
} }
type = case cage type = case cage
when DFHack::ItemCagest; 'Cage' when DFHack::ItemCagest; 'Cage'
when DFHack::ItemAnimaltrapst; 'Animal trap' when DFHack::ItemAnimaltrapst; 'Animal trap'
else cage._rtti_classname else cage._rtti_classname
end end
if count.empty? if count.empty?
empty_cages += 1 empty_cages += 1
else else
puts "#{type} ##{cage.id}: ", count.sort_by { |k, v| v }.map { |k, v| " #{v} #{k}" } puts "#{type} ##{cage.id}: ", count.sort_by { |k, v| v }.map { |k, v| " #{v} #{k}" }
end end
count.each { |k, v| count_total[k] += v } count.each { |k, v| count_total[k] += v }
} }
if list.length > 2 if list.length > 2
puts '', "Total: ", count_total.sort_by { |k, v| v }.map { |k, v| " #{v} #{k}" } puts '', "Total: ", count_total.sort_by { |k, v| v }.map { |k, v| " #{v} #{k}" }
puts "with #{plural(empty_cages, 'empty cage')}" puts "with #{plural(empty_cages, 'empty cage')}"
end end
end end
# handle magic script arguments # handle magic script arguments
here_only = $script_args.delete 'here' here_only = $script_args.delete 'here'
if here_only if here_only
it = df.item_find it = df.item_find
list = [it] list = [it]
if not it.kind_of?(DFHack::ItemCagest) and not it.kind_of?(DFHack::ItemAnimaltrapst) if not it.kind_of?(DFHack::ItemCagest) and not it.kind_of?(DFHack::ItemAnimaltrapst)
list = df.world.items.other[:ANY_CAGE_OR_TRAP].find_all { |i| df.at_cursor?(i) } list = df.world.items.other[:ANY_CAGE_OR_TRAP].find_all { |i| df.at_cursor?(i) }
end end
if list.empty? if list.empty?
puts 'Please select a cage' puts 'Please select a cage'
throw :script_finished throw :script_finished
end end
elsif ids = $script_args.find_all { |arg| arg =~ /^\d+$/ } and ids.first elsif ids = $script_args.find_all { |arg| arg =~ /^\d+$/ } and ids.first
list = [] list = []
ids.each { |id| ids.each { |id|
$script_args.delete id $script_args.delete id
if not it = df.item_find(id.to_i) if not it = df.item_find(id.to_i)
puts "Invalid item id #{id}" puts "Invalid item id #{id}"
elsif not it.kind_of?(DFHack::ItemCagest) and not it.kind_of?(DFHack::ItemAnimaltrapst) elsif not it.kind_of?(DFHack::ItemCagest) and not it.kind_of?(DFHack::ItemAnimaltrapst)
puts "Item ##{id} is not a cage" puts "Item ##{id} is not a cage"
list << it list << it
else else
list << it list << it
end end
} }
if list.empty? if list.empty?
puts 'Please use a valid cage id' puts 'Please use a valid cage id'
throw :script_finished throw :script_finished
end end
else else
list = df.world.items.other[:ANY_CAGE_OR_TRAP] list = df.world.items.other[:ANY_CAGE_OR_TRAP]
end end
# act # act
case $script_args[0] case $script_args[0]
when /^it/i when /^it/i
cage_dump_items(list) cage_dump_items(list)
when /^arm/i when /^arm/i
cage_dump_armor(list) cage_dump_armor(list)
when /^wea/i when /^wea/i
cage_dump_weapons(list) cage_dump_weapons(list)
when 'all' when 'all'
cage_dump_all(list) cage_dump_all(list)
when 'list' when 'list'
cage_dump_list(list) cage_dump_list(list)
else else
puts <<EOS puts <<EOS
Marks items inside all cages for dumping. Marks items inside all cages for dumping.
Add 'here' to dump stuff only for selected cage. Add 'here' to dump stuff only for selected cage.
Add a cage id to dump stuff for this cage only. Add a cage id to dump stuff for this cage only.

@ -5,72 +5,72 @@ $superdwarf_ids ||= []
case $script_args[0] case $script_args[0]
when 'add' when 'add'
if u = df.unit_find if u = df.unit_find
$superdwarf_ids |= [u.id] $superdwarf_ids |= [u.id]
$superdwarf_onupdate ||= df.onupdate_register('superdwarf', 1) { $superdwarf_onupdate ||= df.onupdate_register('superdwarf', 1) {
if $superdwarf_ids.empty? if $superdwarf_ids.empty?
df.onupdate_unregister($superdwarf_onupdate) df.onupdate_unregister($superdwarf_onupdate)
$superdwarf_onupdate = nil $superdwarf_onupdate = nil
else else
$superdwarf_ids.each { |id| $superdwarf_ids.each { |id|
if u = df.unit_find(id) and not u.flags1.dead if u = df.unit_find(id) and not u.flags1.dead
u.actions.each { |a| u.actions.each { |a|
case a.type case a.type
when :Move when :Move
a.data.move.timer = 1 a.data.move.timer = 1
when :Climb when :Climb
a.data.climb.timer = 1 a.data.climb.timer = 1
when :Job when :Job
a.data.job.timer = 1 a.data.job.timer = 1
when :Job2 when :Job2
a.data.job2.timer = 1 a.data.job2.timer = 1
when :Attack when :Attack
# Attack execution timer; fires when reaches zero. # Attack execution timer; fires when reaches zero.
a.data.attack.timer1 = 1 a.data.attack.timer1 = 1
# Attack completion timer: finishes action at zero. # Attack completion timer: finishes action at zero.
# An action must complete before target re-seleciton # An action must complete before target re-seleciton
# occurs. # occurs.
a.data.attack.timer2 = 0 a.data.attack.timer2 = 0
end end
} }
# no sleep # no sleep
if u.counters2.sleepiness_timer > 10000 if u.counters2.sleepiness_timer > 10000
u.counters2.sleepiness_timer = 1 u.counters2.sleepiness_timer = 1
end end
# no break # no break
if b = u.status.misc_traits.find { |t| t.id == :OnBreak } if b = u.status.misc_traits.find { |t| t.id == :OnBreak }
b.value = 500_000 b.value = 500_000
end end
else else
$superdwarf_ids.delete id $superdwarf_ids.delete id
end end
} }
end end
} }
else else
puts "Select a creature using 'v'" puts "Select a creature using 'v'"
end end
when 'del' when 'del'
if u = df.unit_find if u = df.unit_find
$superdwarf_ids.delete u.id $superdwarf_ids.delete u.id
else else
puts "Select a creature using 'v'" puts "Select a creature using 'v'"
end end
when 'clear' when 'clear'
$superdwarf_ids.clear $superdwarf_ids.clear
when 'list' when 'list'
puts "current superdwarves:", $superdwarf_ids.map { |id| df.unit_find(id).name } puts "current superdwarves:", $superdwarf_ids.map { |id| df.unit_find(id).name }
else else
puts "Usage:", puts "Usage:",
" - superdwarf add: give superspeed to currently selected creature", " - superdwarf add: give superspeed to currently selected creature",
" - superdwarf del: remove superspeed to current creature", " - superdwarf del: remove superspeed to current creature",
" - superdwarf clear: remove all superpowers", " - superdwarf clear: remove all superpowers",
" - superdwarf list: list super-dwarves" " - superdwarf list: list super-dwarves"
end end

@ -2,16 +2,16 @@ joblist = df.world.job_list.next
count = 0 count = 0
while joblist while joblist
job = joblist.item job = joblist.item
joblist = joblist.next joblist = joblist.next
if job.job_type == :ConstructBuilding if job.job_type == :ConstructBuilding
if (job.flags.suspend && job.items && job.items[0]) if (job.flags.suspend && job.items && job.items[0])
item = job.items[0].item item = job.items[0].item
job.flags.suspend = false job.flags.suspend = false
count += 1 count += 1
end end
end end
end end
puts "Unsuspended #{count} job(s)." puts "Unsuspended #{count} job(s)."

@ -0,0 +1,122 @@
import re, os, sys
valid_extensions = ['c', 'cpp', 'h', 'hpp', 'mm', 'lua', 'rb', 'proto',
'init', 'init-example']
path_blacklist = [
'library/include/df/',
'plugins/stonesense/allegro',
'plugins/isoworld/allegro',
'plugins/isoworld/agui',
'depends/',
'.git/',
'build',
]
def valid_file(filename):
return len(filter(lambda ext: filename.endswith('.' + ext), valid_extensions)) and \
not len(filter(lambda path: path.replace('\\', '/') in filename.replace('\\', '/'), path_blacklist))
success = True
def error(msg):
global success
success = False
sys.stderr.write(msg + '\n')
class LinterError(Exception): pass
class Linter(object):
def check(self, lines):
failures = []
for i, line in enumerate(lines):
if not self.check_line(line):
failures.append(i + 1)
if len(failures):
raise LinterError('%s: %s' % (self.msg, self.display_lines(failures, len(lines))))
def fix(self, lines):
for i in range(len(lines)):
lines[i] = self.fix_line(lines[i])
def display_lines(self, lines, total):
if len(lines) == total - 1:
return 'entire file'
if not len(lines):
# should never happen
return 'nowhere'
if len(lines) == 1:
return 'line %i' % lines[0]
s = 'lines '
range_start = range_end = lines[0]
for i, line in enumerate(lines):
if line > range_end + 1:
if range_start == range_end:
s += ('%i, ' % range_end)
else:
s += ('%i-%i, ' % (range_start, range_end))
range_start = range_end = line
if i == len(lines) - 1:
s += ('%i' % line)
else:
range_end = line
if i == len(lines) - 1:
s += ('%i-%i, ' % (range_start, range_end))
return s.rstrip(' ').rstrip(',')
class NewlineLinter(Linter):
msg = 'Contains DOS-style newlines'
def check_line(self, line):
return '\r' not in line
def fix_line(self, line):
return line.replace('\r', '')
class TrailingWhitespaceLinter(Linter):
msg = 'Contains trailing whitespace'
def check_line(self, line):
line = line.replace('\r', '')
return not line.endswith(' ') and not line.endswith('\t')
def fix_line(self, line):
return line.rstrip('\t ')
class TabLinter(Linter):
msg = 'Contains tabs'
def check_line(self, line):
return '\t' not in line
def fix_line(self, line):
return line.replace('\t', ' ')
linters = [NewlineLinter(), TrailingWhitespaceLinter(), TabLinter()]
def main():
root_path = os.path.abspath(sys.argv[1] if len(sys.argv) > 1 else '.')
fix = (len(sys.argv) > 2 and sys.argv[2] == '--fix')
global path_blacklist
path_blacklist = map(lambda s: os.path.join(root_path, s), path_blacklist)
for cur, dirnames, filenames in os.walk(root_path):
for filename in filenames:
full_path = os.path.join(cur, filename)
rel_path = full_path.replace(root_path, '.')
if not valid_file(full_path):
continue
lines = []
with open(full_path, 'rb') as f:
lines = f.read().split('\n')
for linter in linters:
try:
linter.check(lines)
except LinterError as e:
error('%s: %s' % (rel_path, e))
if fix:
linter.fix(lines)
contents = '\n'.join(lines)
with open(full_path, 'wb') as f:
f.write(contents)
if success:
print('All linters completed successfully')
sys.exit(0)
else:
sys.exit(1)
if __name__ == '__main__':
main()

@ -0,0 +1,29 @@
import json, os, sys
if sys.version.startswith('2'):
from urllib2 import urlopen, HTTPError
else:
from urllib.request import urlopen
from urllib.error import HTTPError
try:
pr_id = int(os.environ.get('TRAVIS_PULL_REQUEST', 'false'))
except ValueError:
print('Not a pull request')
sys.exit(0)
print('Pull request %i' % pr_id)
res = {}
try:
res = json.loads(urlopen('https://api.github.com/repos/dfhack/dfhack/pulls/%i' % pr_id).read().decode('utf-8'))
except ValueError:
pass
except HTTPError:
print('Failed to retrieve PR information from API')
sys.exit(2)
if 'base' not in res or 'ref' not in res['base']:
print('Invalid JSON returned from API')
sys.exit(2)
if res['base']['ref'] != 'develop':
print('Not based on develop branch')
sys.exit(1)
else:
print('Ok')
sys.exit(0)