zone: can now search for merchants (to allow pitting them). autobutcher: ignore merchant animals, ignore war/hunting creatures, fixed autowatch, stop spamming the console if there is nothing to report. updated readme.rst

develop
Robert Heinrich 2012-04-08 12:51:03 +02:00
parent 53118bc986
commit f609aa0db7
2 changed files with 73 additions and 46 deletions

@ -822,8 +822,9 @@ Filters:
:unassigned: Not assigned to zone, chain or built cage. :unassigned: Not assigned to zone, chain or built cage.
:caged: In a built cage. :caged: In a built cage.
:uncaged: Not in a cage (in case you want your stockpiles to be left alone). :uncaged: Not in a cage (in case you want your stockpiles to be left alone).
:foreign: Not of own civilization (i.e. own fortress). :foreign: Not of own civilization.
:own: From own civilization (i.e. own fortress). :own: From own civilization.
:merchant: Is a merchant / belongs to a merchant. Should only be used for pitting, not for stealing animals (slaughter should work).
:war: Trained war creature. :war: Trained war creature.
:tamed: Creature is tame. :tamed: Creature is tame.
:trained: Creature is trained. :trained: Creature is trained.
@ -842,7 +843,7 @@ One convenient way to use the zone tool is to bind the command 'zone assign' to
Usage with filters Usage with filters
------------------ ------------------
All filters can be used together with the 'assign' command. The only restriction is that it's not possible to assign units who are inside built cages or chained because in most cases that won't be desirable anyways. Usually you should always use the filter 'own' (which implies tame) unless you want to use the zone tool for pitting hostiles. 'own' ignores own dwarves unless you specify 'race DWARF' (so it's safe to use 'assign all own' to one big pasture if you want to have all your animals at the same place). 'egglayer' and 'milkable' should be used together with 'female' unless you have a mod with egg-laying male elves who give milk or whatever. All filters can be used together with the 'assign' command. The only restriction is that it's not possible to assign units who are inside built cages or chained because in most cases that won't be desirable anyways. Usually you should always use the filter 'own' (which implies tame) unless you want to use the zone tool for pitting hostiles. 'own' ignores own dwarves unless you specify 'race DWARF' (so it's safe to use 'assign all own' to one big pasture if you want to have all your animals at the same place). 'egglayer' and 'milkable' should be used together with 'female' unless you have a mod with egg-laying male elves who give milk or whatever. Merchants and their animals are ignored unless you specify 'merchant' (pitting them should be no problem, but stealing and pasturing their animals is not a good idea since currently they are not properly added to your own stocks; slaughtering them should work).
``zone assign all own ALPACA minage 3 maxage 10`` ``zone assign all own ALPACA minage 3 maxage 10``
Assign all own alpacas who are between 3 and 10 years old to the selected pasture. Assign all own alpacas who are between 3 and 10 years old to the selected pasture.
@ -855,7 +856,7 @@ All filters can be used together with the 'assign' command. The only restriction
autonestbox autonestbox
=========== ===========
Assigns unpastured female egg-layers to nestbox zones. Requires that you create pen/pasture zones above nestboxes. If the pen is bigger than 1x1 the nestbox must be in the top left corner. Only 1 unit will be assigned per pen, regardless of the size. The age of the units is currently not checked, most birds grow up quite fast. When called without options autonestbox will instantly run once. Assigns unpastured female egg-layers to nestbox zones. Requires that you create pen/pasture zones above nestboxes. If the pen is bigger than 1x1 the nestbox must be in the top left corner. Only 1 unit will be assigned per pen, regardless of the size. The age of the units is currently not checked, most birds grow up quite fast. Egglayers who are also grazers will be ignored, since confining them to a 1x1 pasture is not a good idea. When called without options autonestbox will instantly run once.
Options: Options:
-------- --------
@ -865,7 +866,7 @@ Options:
autobutcher autobutcher
=========== ===========
Assigns lifestock for slaughter once it reaches a specific count. Requires that you add the target race(s) to a watch list. Only tame units of the own civilization will be processed. Named units will be completely ignored (you can give animals nicknames with the tool 'rename unit' to protect them from autobutcher). Once you have too much adults, the oldest will be butchered first. Once you have too much kids, the youngest will be butchered first. If you don't set any target count the following default will be used: 1 male kid, 5 female kids, 1 male adult, 5 female adults. Assigns lifestock for slaughter once it reaches a specific count. Requires that you add the target race(s) to a watch list. Only tame units of the own civilization will be processed. Named units will be completely ignored (you can give animals nicknames with the tool 'rename unit' to protect them from autobutcher). Creatures trained for war or hunting will be ignored as well. Once you have too much adults, the oldest will be butchered first. Once you have too much kids, the youngest will be butchered first. If you don't set any target count the following default will be used: 1 male kid, 5 female kids, 1 male adult, 5 female adults.
Options: Options:
-------- --------

@ -101,11 +101,14 @@ const string zone_help_filters =
" caged - in a built cage\n" " caged - in a built cage\n"
" uncaged - not in cage\n" " uncaged - not in cage\n"
" foreign - not of own civilization (i.e. own fortress)\n" " foreign - not of own civilization (i.e. own fortress)\n"
" own - from own civilization (fortress)\n" " own - from own civilization\n"
" war - trained war creature\n" " war - trained war creature\n"
" tamed - tamed\n" " tamed - tamed\n"
" named - has name or nickname\n" " named - has name or nickname\n"
" can be used to mark named units for slaughter\n" " can be used to mark named units for slaughter\n"
" merchant - is a merchant / belongs to a merchant\n"
" can be used to pit merchants and slaughter their animals\n"
" (could have weird effects during trading, be careful)\n"
" trained - obvious\n" " trained - obvious\n"
" untrained - obvious\n" " untrained - obvious\n"
" male - obvious\n" " male - obvious\n"
@ -136,6 +139,7 @@ const string zone_help_examples =
" 'own' ignores own dwarves unless you specify 'race DWARF'\n" " 'own' ignores own dwarves unless you specify 'race DWARF'\n"
" (so it's safe to use 'assign all own' to one big pasture\n" " (so it's safe to use 'assign all own' to one big pasture\n"
" if you want to have all your animals at the same place).\n" " if you want to have all your animals at the same place).\n"
" Merchants and their animals are ignored by default.\n"
" 'egglayer' and 'milkable' should be used together with 'female'\n" " 'egglayer' and 'milkable' should be used together with 'female'\n"
" unless you have a mod with egg-laying male elves who give milk.\n"; " unless you have a mod with egg-laying male elves who give milk.\n";
@ -158,7 +162,7 @@ const string autobutcher_help =
"that you add the target race(s) to a watch list. Only tame units of your own\n" "that you add the target race(s) to a watch list. Only tame units of your own\n"
"civilization will be processed. Named units will be completely ignored (you can\n" "civilization will be processed. Named units will be completely ignored (you can\n"
"give animals nicknames with the tool 'rename unit' to protect them from\n" "give animals nicknames with the tool 'rename unit' to protect them from\n"
"getting slaughtered automatically.\n" "getting slaughtered automatically. Trained war or hunting pets will be ignored.\n"
"Once you have too much adults, the oldest will be butchered first.\n" "Once you have too much adults, the oldest will be butchered first.\n"
"Once you have too much kids, the youngest will be butchered first.\n" "Once you have too much kids, the youngest will be butchered first.\n"
"If you don't set a target count the following default will be used:\n" "If you don't set a target count the following default will be used:\n"
@ -348,12 +352,12 @@ bool isDead(df::unit* unit)
bool isMerchant(df::unit* unit) bool isMerchant(df::unit* unit)
{ {
return unit->flags1.bits.merchant; return unit->flags1.bits.merchant;
} }
bool isForest(df::unit* unit) bool isForest(df::unit* unit)
{ {
return unit->flags1.bits.forest; return unit->flags1.bits.forest;
} }
bool isMarkedForSlaughter(df::unit* unit) bool isMarkedForSlaughter(df::unit* unit)
@ -535,7 +539,7 @@ bool isFemale(df::unit* unit)
// found a unit with weird position values on one of my maps (negative and in the thousands) // found a unit with weird position values on one of my maps (negative and in the thousands)
// it didn't appear in the animal stocks screen, but looked completely fine otherwise (alive, tame, own, etc) // it didn't appear in the animal stocks screen, but looked completely fine otherwise (alive, tame, own, etc)
// maybe a rare but, but better avoid assigning such units to zones or slaughter etc. // maybe a rare bug, but better avoid assigning such units to zones or slaughter etc.
bool hasValidMapPos(df::unit* unit) bool hasValidMapPos(df::unit* unit)
{ {
if( unit->pos.x >=0 && unit->pos.y >= 0 && unit->pos.z >= 0 if( unit->pos.x >=0 && unit->pos.y >= 0 && unit->pos.z >= 0
@ -550,9 +554,6 @@ bool hasValidMapPos(df::unit* unit)
// dump some unit info // dump some unit info
void unitInfo(color_ostream & out, df::unit* unit, bool verbose = false) void unitInfo(color_ostream & out, df::unit* unit, bool verbose = false)
{ {
if(isDead(unit))
return;
out.print("Unit %d ", unit->id); //race %d, civ %d,", creature->race, creature->civ_id out.print("Unit %d ", unit->id); //race %d, civ %d,", creature->race, creature->civ_id
if(unit->name.has_name) if(unit->name.has_name)
{ {
@ -597,7 +598,7 @@ void unitInfo(color_ostream & out, df::unit* unit, bool verbose = false)
out << ")"; out << ")";
out << ", age: " << getUnitAge(unit); out << ", age: " << getUnitAge(unit);
if(isTame(unit)) if(isTame(unit))
out << ", tame"; out << ", tame";
if(isOwnCiv(unit)) if(isOwnCiv(unit))
out << ", owned"; out << ", owned";
@ -605,10 +606,10 @@ void unitInfo(color_ostream & out, df::unit* unit, bool verbose = false)
out << ", war"; out << ", war";
if(isHunter(unit)) if(isHunter(unit))
out << ", hunter"; out << ", hunter";
if(isMerchant(unit)) if(isMerchant(unit))
out << ", merchant"; out << ", merchant";
if(isForest(unit)) if(isForest(unit))
out << ", forest"; out << ", forest";
if(verbose) if(verbose)
{ {
@ -979,9 +980,9 @@ bool isFreeEgglayer(df::unit * unit)
&& isOwnCiv(unit) && isOwnCiv(unit)
&& isEggLayer(unit) && isEggLayer(unit)
&& !isAssigned(unit) && !isAssigned(unit)
&& !isGrazer(unit) // exclude grazing birds because they're messy && !isGrazer(unit) // exclude grazing birds because they're messy
&& !isMerchant(unit) // don't steal merchant mounts && !isMerchant(unit) // don't steal merchant mounts
&& !isForest(unit) // don't steal birds from traders, they hate that && !isForest(unit) // don't steal birds from traders, they hate that
) )
return true; return true;
else else
@ -1048,18 +1049,10 @@ bool unassignUnitFromZone(df::unit* unit)
// assign to pen or pit // assign to pen or pit
command_result assignUnitToZone(color_ostream& out, df::unit* unit, df::building* building, bool verbose = false) command_result assignUnitToZone(color_ostream& out, df::unit* unit, df::building* building, bool verbose = false)
{ {
//if(!isOwnCiv(unit) || !isTame(unit))
//{
// out << "Creature must be tame and your own." << endl;
// return CR_WRONG_USAGE;
//}
// building must be a pen/pasture or pit // building must be a pen/pasture or pit
//df::building * building = world->buildings.all.at(index);
if(!isPenPasture(building) && !isPit(building)) if(!isPenPasture(building) && !isPit(building))
{ {
out << "Invalid building type. This is not a pen/pasture or pit." << endl; out << "Invalid building type. This is not a pen/pasture or pit." << endl;
//target_zone = -1;
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
} }
@ -1279,6 +1272,7 @@ command_result df_zone (color_ostream &out, vector <string> & parameters)
bool find_war = false; bool find_war = false;
bool find_own = false; bool find_own = false;
bool find_tame = false; bool find_tame = false;
bool find_merchant = false;
bool find_male = false; bool find_male = false;
bool find_female = false; bool find_female = false;
bool find_egglayer = false; bool find_egglayer = false;
@ -1518,6 +1512,10 @@ command_result df_zone (color_ostream &out, vector <string> & parameters)
{ {
find_grazer = true; find_grazer = true;
} }
else if(p == "merchant")
{
find_merchant = true;
}
else if(p == "milkable") else if(p == "milkable")
{ {
find_milkable = true; find_milkable = true;
@ -1628,13 +1626,16 @@ command_result df_zone (color_ostream &out, vector <string> & parameters)
{ {
df::unit *unit = world->units.all[c]; df::unit *unit = world->units.all[c];
// ignore dead units // ignore dead units
if (isDead(unit)) if (isDead(unit))
continue; continue;
// ignore merchant units // ignore merchant units by default
if (isMerchant(unit) || isForest(unit)) if (!find_merchant && (isMerchant(unit) || isForest(unit)))
continue; continue;
// but allow pitting them and stealing from them if specified :)
if (find_merchant && !isMerchant(unit) && !isForest(unit))
continue;
if(find_race && getRaceName(unit) != target_race) if(find_race && getRaceName(unit) != target_race)
continue; continue;
@ -1828,7 +1829,6 @@ command_result df_autonestbox(color_ostream &out, vector <string> & parameters)
} }
} }
return autoNestbox(out, verbose); return autoNestbox(out, verbose);
//return CR_OK;
} }
command_result autoNestbox( color_ostream &out, bool verbose = false ) command_result autoNestbox( color_ostream &out, bool verbose = false )
@ -2008,6 +2008,7 @@ public:
} }
return subcount; return subcount;
} }
int ProcessUnits_mk() int ProcessUnits_mk()
{ {
int subcount = 0; int subcount = 0;
@ -2020,6 +2021,7 @@ public:
} }
return subcount; return subcount;
} }
int ProcessUnits_fa() int ProcessUnits_fa()
{ {
int subcount = 0; int subcount = 0;
@ -2032,6 +2034,7 @@ public:
} }
return subcount; return subcount;
} }
int ProcessUnits_ma() int ProcessUnits_ma()
{ {
int subcount = 0; int subcount = 0;
@ -2123,13 +2126,13 @@ command_result df_autobutcher(color_ostream &out, vector <string> & parameters)
else if (p == "start") else if (p == "start")
{ {
enable_autobutcher = true; enable_autobutcher = true;
out << "Autobutcher started."; out << "Autobutcher started." << endl;
return autoButcher(out, verbose); return autoButcher(out, verbose);
} }
else if (p == "stop") else if (p == "stop")
{ {
enable_autobutcher = false; enable_autobutcher = false;
out << "Autobutcher stopped."; out << "Autobutcher stopped." << endl;
return CR_OK; return CR_OK;
} }
else if(p == "sleep") else if(p == "sleep")
@ -2137,7 +2140,7 @@ command_result df_autobutcher(color_ostream &out, vector <string> & parameters)
parameters.erase(parameters.begin()); parameters.erase(parameters.begin());
if(!parameters.size()) if(!parameters.size())
{ {
out.printerr("No duration specified!"); out.printerr("No duration specified!\n");
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
} }
else else
@ -2147,7 +2150,7 @@ command_result df_autobutcher(color_ostream &out, vector <string> & parameters)
ss >> ticks; ss >> ticks;
if(ticks <= 0) if(ticks <= 0)
{ {
out.printerr("Invalid duration specified (must be > 0)!"); out.printerr("Invalid duration specified (must be > 0)!\n");
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
} }
sleep_autobutcher = ticks; sleep_autobutcher = ticks;
@ -2159,16 +2162,19 @@ command_result df_autobutcher(color_ostream &out, vector <string> & parameters)
{ {
parameters.erase(parameters.begin()); parameters.erase(parameters.begin());
watch_race = true; watch_race = true;
out << "Start watching race(s)." << endl;
} }
else if(p == "unwatch") else if(p == "unwatch")
{ {
parameters.erase(parameters.begin()); parameters.erase(parameters.begin());
unwatch_race = true; unwatch_race = true;
out << "Stop watching race(s)." << endl;
} }
else if(p == "forget") else if(p == "forget")
{ {
parameters.erase(parameters.begin()); parameters.erase(parameters.begin());
forget_race = true; forget_race = true;
out << "Removing race(s) from watchlist." << endl;
} }
else if(p == "target") else if(p == "target")
{ {
@ -2176,7 +2182,7 @@ command_result df_autobutcher(color_ostream &out, vector <string> & parameters)
// fk mk fa ma R (can have more than 1 R) // fk mk fa ma R (can have more than 1 R)
if(parameters.size() < 6) if(parameters.size() < 6)
{ {
out.printerr("Not enough parameters!"); out.printerr("Not enough parameters!\n");
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
} }
else else
@ -2191,6 +2197,7 @@ command_result df_autobutcher(color_ostream &out, vector <string> & parameters)
ma >> target_ma; ma >> target_ma;
parameters.erase(parameters.begin(), parameters.begin()+5); parameters.erase(parameters.begin(), parameters.begin()+5);
change_target = true; change_target = true;
out << "Setting new target count for race(s)." << endl;
} }
} }
else if(p == "autowatch") else if(p == "autowatch")
@ -2217,6 +2224,13 @@ command_result df_autobutcher(color_ostream &out, vector <string> & parameters)
if(list_watched) if(list_watched)
{ {
if(!watched_races.size())
{
out << "The autobutcher race list is empty." << endl;
return CR_OK;
}
out << "Races on autobutcher list: " << endl;
for(size_t i=0; i<watched_races.size(); i++) for(size_t i=0; i<watched_races.size(); i++)
{ {
WatchedRace * w = watched_races[i]; WatchedRace * w = watched_races[i];
@ -2244,7 +2258,7 @@ command_result df_autobutcher(color_ostream &out, vector <string> & parameters)
{ {
if(!parameters.size()) if(!parameters.size())
{ {
out.printerr("No race(s) specified!"); out.printerr("No race(s) specified!\n");
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
} }
while(parameters.size()) while(parameters.size())
@ -2252,7 +2266,9 @@ command_result df_autobutcher(color_ostream &out, vector <string> & parameters)
string tr = parameters.back(); string tr = parameters.back();
target_racenames.push_back(tr); target_racenames.push_back(tr);
parameters.pop_back(); parameters.pop_back();
out << tr << " ";
} }
out << endl;
} }
if(target_racenames.size() && target_racenames[0] == "all") if(target_racenames.size() && target_racenames[0] == "all")
@ -2337,12 +2353,14 @@ command_result df_autobutcher(color_ostream &out, vector <string> & parameters)
return CR_OK; return CR_OK;
} }
// check watched_races vector for a race id, return -1 if nothing found
// calling method needs to check itself if the race is currently being watched or ignored
int getWatchedIndex(int id) int getWatchedIndex(int id)
{ {
for(size_t i=0; i<watched_races.size(); i++) for(size_t i=0; i<watched_races.size(); i++)
{ {
WatchedRace * w = watched_races[i]; WatchedRace * w = watched_races[i];
if(w->raceId == id && w->isWatched) if(w->raceId == id) // && w->isWatched)
return i; return i;
} }
return -1; return -1;
@ -2373,8 +2391,12 @@ command_result autoButcher( color_ostream &out, bool verbose = false )
df::unit * unit = world->units.all[i]; df::unit * unit = world->units.all[i];
if( isDead(unit) if( isDead(unit)
|| isMarkedForSlaughter(unit) || isMarkedForSlaughter(unit)
|| isMerchant(unit) // ignore merchants' draught animals
|| isForest(unit) // ignore merchants' caged animals
|| !isOwnCiv(unit) || !isOwnCiv(unit)
|| !isTame(unit) || !isTame(unit)
|| isWar(unit) // ignore war dogs etc
|| isHunter(unit) // ignore hunting dogs etc
|| (isContainedInItem(unit) && hasValidMapPos(unit) && isBuiltCageAtPos(unit->pos)) || (isContainedInItem(unit) && hasValidMapPos(unit) && isBuiltCageAtPos(unit->pos))
|| unit->name.has_name || unit->name.has_name
) )
@ -2389,13 +2411,16 @@ command_result autoButcher( color_ostream &out, bool verbose = false )
if(watched_index != -1) if(watched_index != -1)
{ {
WatchedRace * w = watched_races[watched_index]; WatchedRace * w = watched_races[watched_index];
w->PushUnit(unit); if(w->isWatched)
w->PushUnit(unit);
} }
else if(enable_autobutcher_autowatch) else if(enable_autobutcher_autowatch)
{ {
WatchedRace * w = new WatchedRace(true, unit->race, default_fk, default_mk, default_fa, default_ma); WatchedRace * w = new WatchedRace(true, unit->race, default_fk, default_mk, default_fa, default_ma);
watched_races.push_back(w); watched_races.push_back(w);
w->PushUnit(unit); w->PushUnit(unit);
df::creature_raw *raw = df::global::world->raws.creatures.all[w->raceId];
out << "New race added to autoslaughter watchlist: " << raw->creature_id << endl;
} }
} }
@ -2406,9 +2431,10 @@ command_result autoButcher( color_ostream &out, bool verbose = false )
int slaughter_subcount = w->ProcessUnits(); int slaughter_subcount = w->ProcessUnits();
slaughter_count += slaughter_subcount; slaughter_count += slaughter_subcount;
df::creature_raw *raw = df::global::world->raws.creatures.all[w->raceId]; df::creature_raw *raw = df::global::world->raws.creatures.all[w->raceId];
out << raw->creature_id << " marked for slaughter: " << slaughter_subcount << endl; if(slaughter_subcount)
out << raw->creature_id << " marked for slaughter: " << slaughter_subcount << endl;
} }
out << slaughter_count << " units total marked for slaughter." << endl; //out << slaughter_count << " units total marked for slaughter." << endl;
return CR_OK; return CR_OK;
} }