From f609aa0db77824e4efcb2470d865de65f66becb1 Mon Sep 17 00:00:00 2001 From: Robert Heinrich Date: Sun, 8 Apr 2012 12:51:03 +0200 Subject: [PATCH] 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 --- README.rst | 11 ++--- plugins/zone.cpp | 108 +++++++++++++++++++++++++++++------------------ 2 files changed, 73 insertions(+), 46 deletions(-) diff --git a/README.rst b/README.rst index 2183d7064..36e47685d 100644 --- a/README.rst +++ b/README.rst @@ -822,8 +822,9 @@ Filters: :unassigned: Not assigned to zone, chain or built cage. :caged: In a built cage. :uncaged: Not in a cage (in case you want your stockpiles to be left alone). -:foreign: Not of own civilization (i.e. own fortress). -:own: From own civilization (i.e. own fortress). +:foreign: Not of own civilization. +: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. :tamed: Creature is tame. :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 ------------------ -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`` 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 =========== -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: -------- @@ -865,7 +866,7 @@ Options: 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: -------- diff --git a/plugins/zone.cpp b/plugins/zone.cpp index a117bddab..770d6c052 100644 --- a/plugins/zone.cpp +++ b/plugins/zone.cpp @@ -101,11 +101,14 @@ const string zone_help_filters = " caged - in a built cage\n" " uncaged - not in cage\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" " tamed - tamed\n" " named - has name or nickname\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" " untrained - obvious\n" " male - obvious\n" @@ -136,6 +139,7 @@ const string zone_help_examples = " 'own' ignores own dwarves unless you specify 'race DWARF'\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" + " Merchants and their animals are ignored by default.\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"; @@ -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" "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" - "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 kids, the youngest will be butchered first.\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) { - return unit->flags1.bits.merchant; + return unit->flags1.bits.merchant; } bool isForest(df::unit* unit) { - return unit->flags1.bits.forest; + return unit->flags1.bits.forest; } 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) // 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) { 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 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 if(unit->name.has_name) { @@ -597,7 +598,7 @@ void unitInfo(color_ostream & out, df::unit* unit, bool verbose = false) out << ")"; out << ", age: " << getUnitAge(unit); - if(isTame(unit)) + if(isTame(unit)) out << ", tame"; if(isOwnCiv(unit)) out << ", owned"; @@ -605,10 +606,10 @@ void unitInfo(color_ostream & out, df::unit* unit, bool verbose = false) out << ", war"; if(isHunter(unit)) out << ", hunter"; - if(isMerchant(unit)) - out << ", merchant"; - if(isForest(unit)) - out << ", forest"; + if(isMerchant(unit)) + out << ", merchant"; + if(isForest(unit)) + out << ", forest"; if(verbose) { @@ -979,9 +980,9 @@ bool isFreeEgglayer(df::unit * unit) && isOwnCiv(unit) && isEggLayer(unit) && !isAssigned(unit) - && !isGrazer(unit) // exclude grazing birds because they're messy - && !isMerchant(unit) // don't steal merchant mounts - && !isForest(unit) // don't steal birds from traders, they hate that + && !isGrazer(unit) // exclude grazing birds because they're messy + && !isMerchant(unit) // don't steal merchant mounts + && !isForest(unit) // don't steal birds from traders, they hate that ) return true; else @@ -1048,18 +1049,10 @@ bool unassignUnitFromZone(df::unit* unit) // assign to pen or pit 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 - //df::building * building = world->buildings.all.at(index); if(!isPenPasture(building) && !isPit(building)) { out << "Invalid building type. This is not a pen/pasture or pit." << endl; - //target_zone = -1; return CR_WRONG_USAGE; } @@ -1279,6 +1272,7 @@ command_result df_zone (color_ostream &out, vector & parameters) bool find_war = false; bool find_own = false; bool find_tame = false; + bool find_merchant = false; bool find_male = false; bool find_female = false; bool find_egglayer = false; @@ -1518,6 +1512,10 @@ command_result df_zone (color_ostream &out, vector & parameters) { find_grazer = true; } + else if(p == "merchant") + { + find_merchant = true; + } else if(p == "milkable") { find_milkable = true; @@ -1628,13 +1626,16 @@ command_result df_zone (color_ostream &out, vector & parameters) { df::unit *unit = world->units.all[c]; - // ignore dead units - if (isDead(unit)) - continue; + // ignore dead units + if (isDead(unit)) + continue; - // ignore merchant units - if (isMerchant(unit) || isForest(unit)) - continue; + // ignore merchant units by default + if (!find_merchant && (isMerchant(unit) || isForest(unit))) + 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) continue; @@ -1828,7 +1829,6 @@ command_result df_autonestbox(color_ostream &out, vector & parameters) } } return autoNestbox(out, verbose); - //return CR_OK; } command_result autoNestbox( color_ostream &out, bool verbose = false ) @@ -2008,6 +2008,7 @@ public: } return subcount; } + int ProcessUnits_mk() { int subcount = 0; @@ -2020,6 +2021,7 @@ public: } return subcount; } + int ProcessUnits_fa() { int subcount = 0; @@ -2032,6 +2034,7 @@ public: } return subcount; } + int ProcessUnits_ma() { int subcount = 0; @@ -2123,13 +2126,13 @@ command_result df_autobutcher(color_ostream &out, vector & parameters) else if (p == "start") { enable_autobutcher = true; - out << "Autobutcher started."; + out << "Autobutcher started." << endl; return autoButcher(out, verbose); } else if (p == "stop") { enable_autobutcher = false; - out << "Autobutcher stopped."; + out << "Autobutcher stopped." << endl; return CR_OK; } else if(p == "sleep") @@ -2137,7 +2140,7 @@ command_result df_autobutcher(color_ostream &out, vector & parameters) parameters.erase(parameters.begin()); if(!parameters.size()) { - out.printerr("No duration specified!"); + out.printerr("No duration specified!\n"); return CR_WRONG_USAGE; } else @@ -2147,7 +2150,7 @@ command_result df_autobutcher(color_ostream &out, vector & parameters) ss >> ticks; if(ticks <= 0) { - out.printerr("Invalid duration specified (must be > 0)!"); + out.printerr("Invalid duration specified (must be > 0)!\n"); return CR_WRONG_USAGE; } sleep_autobutcher = ticks; @@ -2159,16 +2162,19 @@ command_result df_autobutcher(color_ostream &out, vector & parameters) { parameters.erase(parameters.begin()); watch_race = true; + out << "Start watching race(s)." << endl; } else if(p == "unwatch") { parameters.erase(parameters.begin()); unwatch_race = true; + out << "Stop watching race(s)." << endl; } else if(p == "forget") { parameters.erase(parameters.begin()); forget_race = true; + out << "Removing race(s) from watchlist." << endl; } else if(p == "target") { @@ -2176,7 +2182,7 @@ command_result df_autobutcher(color_ostream &out, vector & parameters) // fk mk fa ma R (can have more than 1 R) if(parameters.size() < 6) { - out.printerr("Not enough parameters!"); + out.printerr("Not enough parameters!\n"); return CR_WRONG_USAGE; } else @@ -2191,6 +2197,7 @@ command_result df_autobutcher(color_ostream &out, vector & parameters) ma >> target_ma; parameters.erase(parameters.begin(), parameters.begin()+5); change_target = true; + out << "Setting new target count for race(s)." << endl; } } else if(p == "autowatch") @@ -2217,6 +2224,13 @@ command_result df_autobutcher(color_ostream &out, vector & parameters) 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 & parameters) { if(!parameters.size()) { - out.printerr("No race(s) specified!"); + out.printerr("No race(s) specified!\n"); return CR_WRONG_USAGE; } while(parameters.size()) @@ -2252,7 +2266,9 @@ command_result df_autobutcher(color_ostream &out, vector & parameters) string tr = parameters.back(); target_racenames.push_back(tr); parameters.pop_back(); + out << tr << " "; } + out << endl; } if(target_racenames.size() && target_racenames[0] == "all") @@ -2337,12 +2353,14 @@ command_result df_autobutcher(color_ostream &out, vector & parameters) 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) { for(size_t i=0; iraceId == id && w->isWatched) + if(w->raceId == id) // && w->isWatched) return i; } return -1; @@ -2373,8 +2391,12 @@ command_result autoButcher( color_ostream &out, bool verbose = false ) df::unit * unit = world->units.all[i]; if( isDead(unit) || isMarkedForSlaughter(unit) + || isMerchant(unit) // ignore merchants' draught animals + || isForest(unit) // ignore merchants' caged animals || !isOwnCiv(unit) || !isTame(unit) + || isWar(unit) // ignore war dogs etc + || isHunter(unit) // ignore hunting dogs etc || (isContainedInItem(unit) && hasValidMapPos(unit) && isBuiltCageAtPos(unit->pos)) || unit->name.has_name ) @@ -2389,13 +2411,16 @@ command_result autoButcher( color_ostream &out, bool verbose = false ) if(watched_index != -1) { WatchedRace * w = watched_races[watched_index]; - w->PushUnit(unit); + if(w->isWatched) + w->PushUnit(unit); } else if(enable_autobutcher_autowatch) { WatchedRace * w = new WatchedRace(true, unit->race, default_fk, default_mk, default_fa, default_ma); watched_races.push_back(w); 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(); slaughter_count += slaughter_subcount; 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; } \ No newline at end of file