From 2b675c80ce1eed9b28ed4a81abdb5da5d6c62f4f Mon Sep 17 00:00:00 2001 From: Quietust Date: Thu, 14 Mar 2013 12:00:16 -0500 Subject: [PATCH 01/10] Fix createitem to not leak memory --- plugins/createitem.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/createitem.cpp b/plugins/createitem.cpp index 8764f6ae2..ed301e482 100644 --- a/plugins/createitem.cpp +++ b/plugins/createitem.cpp @@ -248,7 +248,9 @@ command_result df_createitem (color_ostream &out, vector & parameters) break; } - if (!makeItem(prod, unit)) + bool result = makeItem(prod, unit); + delete prod; + if (!result) { out.printerr("Failed to create item!\n"); return CR_FAILURE; From 42e9d77e952890ea3aa34029e83d6e9e8d4d82ca Mon Sep 17 00:00:00 2001 From: jj Date: Fri, 15 Mar 2013 14:21:01 +0100 Subject: [PATCH 02/10] scripts/create-items: spawn anvils too --- scripts/create-items.rb | 44 ++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/scripts/create-items.rb b/scripts/create-items.rb index a1f85cc4c..ad50c2e0d 100644 --- a/scripts/create-items.rb +++ b/scripts/create-items.rb @@ -1,31 +1,31 @@ -# create arbitrary items under cursor +# create first necessity items under cursor category = $script_args[0] || 'help' mat_raw = $script_args[1] || 'list' count = $script_args[2] -category = df.match_rawname(category, ['help', 'bars', 'boulders', 'plants', 'logs', 'webs']) || 'help' +category = df.match_rawname(category, ['help', 'bars', 'boulders', 'plants', 'logs', 'webs', 'anvils']) || 'help' if category == 'help' puts < 5 + df.curview.feed_keys(:CURSOR_DOWN_Z) + df.curview.feed_keys(:CURSOR_UP_Z) +else + df.curview.feed_keys(:CURSOR_UP_Z) + df.curview.feed_keys(:CURSOR_DOWN_Z) +end From 381247dc391d6aa0d8601b490f8d81fa502f922c Mon Sep 17 00:00:00 2001 From: jj Date: Sat, 16 Mar 2013 00:51:04 +0100 Subject: [PATCH 03/10] rename scripts/slayrace -> exterminate --- NEWS | 3 ++- scripts/{slayrace.rb => exterminate.rb} | 22 +++++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) rename scripts/{slayrace.rb => exterminate.rb} (77%) diff --git a/NEWS b/NEWS index 9c1cf6676..ce6811ca9 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,7 @@ DFHack future - Is not yet known. + Misc improvements: + - exterminate: renamed from slayrace, add help message DFHack v0.34.11-r3 diff --git a/scripts/slayrace.rb b/scripts/exterminate.rb similarity index 77% rename from scripts/slayrace.rb rename to scripts/exterminate.rb index 4844538d4..4d1047e11 100644 --- a/scripts/slayrace.rb +++ b/scripts/exterminate.rb @@ -1,4 +1,4 @@ -# slay all creatures of a given race +# exterminate creatures # race = name of the race to eradicate, use 'him' to target only the selected creature # use 'undead' to target all undeads @@ -24,7 +24,7 @@ slayit = lambda { |u| else # it's getting hot around here # !!WARNING!! do not call on a magma-safe creature - ouh = df.onupdate_register("slayrace ensure #{u.id}", 1) { + ouh = df.onupdate_register("exterminate ensure #{u.id}", 1) { if u.flags1.dead df.onupdate_unregister(ouh) else @@ -55,7 +55,23 @@ case race when nil all_races.sort_by { |race, cnt| [cnt, race] }.each{ |race, cnt| puts " #{race} #{cnt}" } -when 'him' +when 'help', '?' + puts < Date: Sat, 16 Mar 2013 01:36:49 +0100 Subject: [PATCH 04/10] scripts/exterminate: nicer error message on invalid race --- scripts/exterminate.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/exterminate.rb b/scripts/exterminate.rb index 4d1047e11..5b9e9c448 100644 --- a/scripts/exterminate.rb +++ b/scripts/exterminate.rb @@ -62,7 +62,7 @@ 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 'undead', kill all undead creatures/thralls. -The targets will bleed out, or if they are immune to that, will vanish in a puff of smoke. +The targets will bleed out on the next game tick, or if they are immune to that, will vanish in a puff of smoke. The special final argument 'magma' will make magma rain on the targets instead. @@ -93,7 +93,10 @@ when /^undead/i else raw_race = df.match_rawname(race, all_races.keys) - raise 'invalid race' if not raw_race + if not raw_race + puts "Invalid race, use one of #{all_races.keys.sort.join(' ')}" + throw :script_finished + end race_nr = df.world.raws.creatures.all.index { |cr| cr.creature_id == raw_race } From b74f08c4f8747cf7b57ced7be04c6cb7be79a487 Mon Sep 17 00:00:00 2001 From: jj Date: Sat, 16 Mar 2013 01:37:06 +0100 Subject: [PATCH 05/10] scripts/masspit --- NEWS | 2 ++ scripts/masspit.rb | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 scripts/masspit.rb diff --git a/NEWS b/NEWS index ce6811ca9..15129b262 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,7 @@ DFHack future + New scripts: + - masspit: designate caged creatures in a zone for pitting Misc improvements: - exterminate: renamed from slayrace, add help message diff --git a/scripts/masspit.rb b/scripts/masspit.rb new file mode 100644 index 000000000..460c402e0 --- /dev/null +++ b/scripts/masspit.rb @@ -0,0 +1,40 @@ +# pit all caged creatures in a zone + +case $script_args[0] +when '?', 'help' + puts <= df.cursor.x and zone.y1 <= df.cursor.y and zone.y2 >= df.cursor.y + } + +end + +if not bld + puts "Please select a pit/pond zone" + throw :script_finished +end + +found = 0 +df.world.items.other[:CAGE].each { |cg| + 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 not uref = cg.general_refs.grep(DFHack::GeneralRefContainsUnitst).first + found += 1 + u = uref.unit_tg + puts "Pitting #{u.race_tg.name[0]} #{u.id} #{u.name}" + u.general_refs << DFHack::GeneralRefBuildingCivzoneAssignedst.cpp_new(:building_id => bld.id) + bld.assigned_creature << u.id +} +puts "No creature available for pitting" if found == 0 From dad485e5e163f1dd78db8e5d8bdc369f15a5c190 Mon Sep 17 00:00:00 2001 From: jj Date: Sat, 16 Mar 2013 01:46:31 +0100 Subject: [PATCH 06/10] update doc --- Readme.rst | 17 ++++++++++++----- scripts/exterminate.rb | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/Readme.rst b/Readme.rst index 642f10730..793036a06 100644 --- a/Readme.rst +++ b/Readme.rst @@ -1872,8 +1872,8 @@ Internals: the thoughts are set to be very old, so that the game remove them quickly after you unpause. -slayrace -======== +exterminate +=========== Kills any unit of a given race. With no argument, lists the available races and count eligible targets. @@ -1896,15 +1896,15 @@ Will target any unit on a revealed tile of the map, including ambushers. Ex:: - slayrace gob + exterminate gob To kill a single creature, select the unit with the 'v' cursor and:: - slayrace him + exterminate him To purify all elves on the map with fire (may have side-effects):: - slayrace elve magma + exterminate elve magma magmasource @@ -1926,6 +1926,13 @@ To remove all placed sources, call ``magmasource stop``. With no argument, this command shows an help message and list existing sources. +masspit +======= +Designate all creatures in cages on top of a pit/pond activity zone for pitting. +Works best with an animal stockpile on top of the zone. + +Works with a zone number as argument (eg ``Activity Zone #6`` -> ``masspit 6``) +or with the game cursor on top of the area. digfort ======= diff --git a/scripts/exterminate.rb b/scripts/exterminate.rb index 5b9e9c448..72d1a4b4a 100644 --- a/scripts/exterminate.rb +++ b/scripts/exterminate.rb @@ -67,7 +67,7 @@ The targets will bleed out on the next game tick, or if they are immune to that, The special final argument 'magma' will make magma rain on the targets instead. Ex: exterminate gob - exterminate elf magma + exterminate elve magma exterminate him EOS From 96e7b02127348ec527eb2dba3289a840eebdc040 Mon Sep 17 00:00:00 2001 From: jj Date: Sat, 16 Mar 2013 02:58:21 +0100 Subject: [PATCH 07/10] autofarm: minor tweaks --- scripts/autofarm.rb | 77 ++++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/scripts/autofarm.rb b/scripts/autofarm.rb index e1dc62ae3..b8a6871e9 100644 --- a/scripts/autofarm.rb +++ b/scripts/autofarm.rb @@ -6,10 +6,12 @@ class AutoFarm end def setthreshold(id, v) - if df.world.raws.plants.all.find { |r| r.id == id } - @thresholds[id] = v.to_i + list = df.world.raws.plants.all.find_all { |plt| plt.flags[:SEED] }.map { |plt| plt.id } + if tok = df.match_rawname(id, list) + @thresholds[tok] = v.to_i else - puts "No plant with id #{id}" + puts "No plant with id #{id}, try one of " + + list.map { |w| w =~ /[^\w]/ ? w.inspect : w }.sort.join(' ') end end @@ -17,11 +19,11 @@ class AutoFarm @thresholds.default = v.to_i end - def is_plantable (plant) + def is_plantable(plant) has_seed = plant.flags[:SEED] season = df.cur_season 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 = can_plant && (will_finish || plant.flags[(season+1)%4]) can_plant @@ -36,7 +38,7 @@ class AutoFarm !i.flags.hostile && !i.flags.on_fire && !i.flags.rotten && !i.flags.trader && !i.flags.in_building && !i.flags.construction && !i.flags.artifact) - counts[i.mat_index] = counts[i.mat_index] + i.stack_size + counts[i.mat_index] += i.stack_size end } @@ -53,7 +55,7 @@ class AutoFarm return plantable end - def set_farms( plants, farms) + def set_farms(plants, farms) return if farms.length == 0 if plants.length == 0 plants = [-1] @@ -61,41 +63,36 @@ class AutoFarm season = df.cur_season - idx = 0 - - farms.each { |f| - f.plant_id[season] = plants[idx] - idx = (idx + 1) % plants.length + farms.each_with_index { |f, idx| + f.plant_id[season] = plants[idx % plants.length] } end def process - return false unless @running - plantable = find_plantable_plants - counts = Hash.new(0) + @lastcounts = Hash.new(0) df.world.items.other[:PLANT].each { |i| if (!i.flags.dump && !i.flags.forbid && !i.flags.garbage_collect && !i.flags.hostile && !i.flags.on_fire && !i.flags.rotten && !i.flags.trader && !i.flags.in_building && !i.flags.construction && !i.flags.artifact && plantable.has_key?(i.mat_index)) - counts[i.mat_index] = counts[i.mat_index] + i.stack_size + id = df.world.raws.plants.all[i.mat_index].id + @lastcounts[id] += i.stack_size end } + return unless @running + plants_s = [] plants_u = [] - @lastcounts.clear - plantable.each_key { |k| plant = df.world.raws.plants.all[k] - if (counts[k] < @thresholds[plant.id]) + if (@lastcounts[plant.id] < @thresholds[plant.id]) plants_s.push(k) if plantable[k] == :Surface plants_u.push(k) if plantable[k] == :Underground end - @lastcounts[plant.id] = counts[k] } farms_s = [] @@ -110,11 +107,11 @@ class AutoFarm set_farms(plants_s, farms_s) set_farms(plants_u, farms_u) - end def start - @onupdate = df.onupdate_register('autofarm', 100) { process } + return if @running + @onupdate = df.onupdate_register('autofarm', 1200) { process } @running = true end @@ -125,23 +122,28 @@ class AutoFarm def status stat = @running ? "Running." : "Stopped." + @lastcounts.each { |k,v| + stat << "\n#{k} limit #{@thresholds.fetch(k, 'default')} current #{v}" + } @thresholds.each { |k,v| - stat += "\n#{k} limit #{v} current #{@lastcounts[k]}" + stat << "\n#{k} limit #{v} current 0" unless @lastcounts.has_key?(k) } - stat += "\nDefault: #{@thresholds.default}" + stat << "\nDefault: #{@thresholds.default}" stat end end -$AutoFarm = AutoFarm.new unless $AutoFarm +$AutoFarm ||= AutoFarm.new case $script_args[0] when 'start' - $AutoFarm.start + $AutoFarm.start + puts $AutoFarm.status -when 'end', 'stop' - $AutoFarm.stop +when 'end', 'stop', 'disable' + $AutoFarm.stop + puts 'Stopped.' when 'default' $AutoFarm.setdefault($script_args[1]) @@ -156,10 +158,19 @@ when 'delete' $AutoFarm.stop $AutoFarm = nil +when 'help', '?' + puts < Date: Sat, 16 Mar 2013 12:15:55 +0400 Subject: [PATCH 08/10] Fix soundsense-season printing error messages in worldgen. --- scripts/soundsense-season.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/soundsense-season.lua b/scripts/soundsense-season.lua index 6b7d43cfa..c2b57e35e 100644 --- a/scripts/soundsense-season.lua +++ b/scripts/soundsense-season.lua @@ -1,6 +1,7 @@ -- On map load writes the current season to gamelog.txt local seasons = { + [-1] = 'Nothing', -- worldgen [0] = 'Spring', [1] = 'Summer', [2] = 'Autumn', From 462a08a4eaa5ab9f418d9bc3670d2ed199073009 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Tue, 2 Apr 2013 12:03:37 +0400 Subject: [PATCH 09/10] Fix the search plugin crashing the military screen. The cause of the crash is that the right list is used for multiple different things in different pages, so when cleaning up after a page switch it is not acceptable to mess with it in any way. However the search plugin changed its length, thus causing a crash if the new contents were shorter than the original candidate list. --- plugins/search.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/plugins/search.cpp b/plugins/search.cpp index 4e502b838..541fc9506 100644 --- a/plugins/search.cpp +++ b/plugins/search.cpp @@ -422,12 +422,17 @@ protected: virtual bool can_init(S *screen) { auto list = getLayerList(screen); - if (!list->active) + if (!is_list_valid(screen) || !list->active) return false; return true; } + virtual bool is_list_valid(S*) + { + return true; + } + virtual void do_search() { search_generic::do_search(); @@ -444,8 +449,12 @@ protected: virtual void clear_search() { search_generic::clear_search(); - auto list = getLayerList(this->viewscreen); - list->num_entries = this->get_primary_list()->size(); + + if (is_list_valid(this->viewscreen)) + { + auto list = getLayerList(this->viewscreen); + list->num_entries = this->get_primary_list()->size(); + } } private: @@ -1208,12 +1217,14 @@ public: return 'q'; } - bool can_init(df::viewscreen_layer_militaryst *screen) + // When not on the positions page, this list is used for something + // else entirely, so screwing with it seriously breaks stuff. + bool is_list_valid(df::viewscreen_layer_militaryst *screen) { if (screen->page != df::viewscreen_layer_militaryst::Positions) return false; - return military_search_base::can_init(screen); + return true; } vector *get_primary_list() From 399fd107e40a5ae12bdc7e03eaee53d30e7a651b Mon Sep 17 00:00:00 2001 From: Quietust Date: Mon, 8 Apr 2013 08:29:50 -0500 Subject: [PATCH 10/10] Make createitem create shoes in pairs (as well as gloves) --- plugins/createitem.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/plugins/createitem.cpp b/plugins/createitem.cpp index ed301e482..9697a3947 100644 --- a/plugins/createitem.cpp +++ b/plugins/createitem.cpp @@ -46,18 +46,23 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out ) return CR_OK; } -bool makeItem (df::reaction_product_itemst *prod, df::unit *unit, bool glove2 = false) +bool makeItem (df::reaction_product_itemst *prod, df::unit *unit, bool second_item = false) { vector out_items; vector in_reag; vector in_items; bool is_gloves = (prod->item_type == df::item_type::GLOVES); + bool is_shoes = (prod->item_type == df::item_type::SHOES); prod->produce(unit, &out_items, &in_reag, &in_items, 1, df::job_skill::NONE, df::historical_entity::find(unit->civ_id), ((*gametype == df::game_type::DWARF_MAIN) || (*gametype == df::game_type::DWARF_RECLAIM)) ? df::world_site::find(ui->site_id) : NULL); if (!out_items.size()) return false; + // if we asked to make shoes and we got twice as many as we asked, then we're okay + // otherwise, make a second set because shoes are normally made in pairs + if (is_shoes && out_items.size() == prod->count * 2) + is_shoes = false; for (size_t i = 0; i < out_items.size(); i++) { out_items[i]->moveToGround(unit->pos.x, unit->pos.y, unit->pos.z); @@ -67,10 +72,10 @@ bool makeItem (df::reaction_product_itemst *prod, df::unit *unit, bool glove2 = if (out_items[i]->getGloveHandedness() > 0) is_gloves = false; else - out_items[i]->setGloveHandedness(glove2 ? 2 : 1); + out_items[i]->setGloveHandedness(second_item ? 2 : 1); } } - if (is_gloves && !glove2) + if ((is_gloves || is_shoes) && !second_item) return makeItem(prod, unit, true); return true;