autobutcher: only ignore built cages which are defined as rooms/zoos.

zone: allow mass-assigning of nicknames (to protect a pasture/cage from autobutcher)
develop
Robert Heinrich 2012-04-16 10:15:37 +02:00
parent 9c67250729
commit e6ed81508d
2 changed files with 165 additions and 12 deletions

@ -810,6 +810,8 @@ Options:
:set: Set zone or cage under cursor as default for future assigns.
:assign: Assign unit(s) to the pen or pit marked with the 'set' command. If no filters are set a unit must be selected in the in-game ui. Can also be followed by a valid zone id which will be set instead.
:unassign: Unassign selected creature from it's zone.
:nick: Mass-assign nicknames, must be followed by the name you want to set.
:remnick: Mass-remove nicknames.
:uinfo: Print info about unit(s). If no filters are set a unit must be selected in the in-game ui.
:zinfo: Print info about zone(s). If no filters are set zones under the cursor are listed.
:verbose: Print some more info.
@ -848,16 +850,22 @@ Usage with filters
------------------
All filters can be used together with the 'assign' command. Restrictions: It's not possible to assign units who are inside built cages or chained because in most cases that won't be desirable anyways. It's not possible to cage owned pets because in that case the owner uncages them after a while which results in infinite hauling back and forth. 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). Most filters can be negated (e.g. 'not grazer' -> race is not a grazer).
Mass-renaming
-------------
Using the 'nick' command you can set the same nickname for multiple units. If used without 'assign', 'all' or 'count' it will rename all units in the current default target zone. Combined with 'assign', 'all' or 'count' (and further optional filters) it will rename units matching the filter conditions.
``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.
``zone assign all own caged grazer``
Assign all own grazers who are sitting in cages on stockpiles (e.g. after buying them from merchants) to the selected pasture.
``zone assign all own caged grazer nick ineedgrass``
Assign all own grazers who are sitting in cages on stockpiles (e.g. after buying them from merchants) to the selected pasture and give them the nickname 'ineedgrass'.
``zone assign all own not grazer not race CAT``
Assign all own animals who are not grazers, excluding cats.
``zone assign count 5 own female milkable``
Assign up to 5 own female milkable creatures to the selected pasture.
``zone assign all own race DWARF maxage 2``
Throw all useless kids into a pit :)
``zone nick donttouchme``
Nicknames all units in the current default zone or cage to 'donttouchme'. Mostly intended to be used for special pastures or cages which are not marked as rooms you want to protect from autobutcher.
autonestbox
===========
@ -871,7 +879,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 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.
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 will be processed. Named units will be completely ignored (to protect specific animals fro autobutcher you can give them nicknames with the tool 'rename unit' for single units or with 'zone nick' to mass-rename units in pastures and cages). Creatures trained for war or hunting will be ignored as well. Creatures assigned to cages will be ignored if the cage is defined as a room (to avoid butchering unnamed zoo animals). 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:
--------

@ -803,6 +803,25 @@ int32_t findBuildingIndexById(int32_t id)
return -1;
}
int32_t findUnitIndexById(int32_t id)
{
for (size_t i = 0; i < world->units.all.size(); i++)
{
if(world->units.all.at(i)->id == id)
return i;
}
return -1;
}
df::unit* findUnitById(int32_t id)
{
int32_t index = findUnitIndexById(id);
if(index != -1)
return world->units.all[index];
else
return NULL;
}
// returns id of pen/pit at cursor position (-1 if nothing found)
int32_t findPenPitAtCursor()
{
@ -1007,6 +1026,31 @@ bool isInBuiltCage(df::unit* unit)
return caged;
}
// built cage defined as room (supposed to detect zoo cages)
bool isInBuiltCageRoom(df::unit* unit)
{
bool caged_room = false;
for (size_t b=0; b < world->buildings.all.size(); b++)
{
df::building* building = world->buildings.all[b];
if(building->isRoom() && building->getType() == building_type::Cage)
{
df::building_cagest* cage = (df::building_cagest*) building;
for(size_t c=0; c<cage->assigned_creature.size(); c++)
{
if(cage->assigned_creature[c] == unit->id)
{
caged_room = true;
break;
}
}
}
if(caged_room)
break;
}
return caged_room;
}
// check a map position for a built cage
// animals in cages are CONTAINED_IN_ITEM, no matter if they are on a stockpile or inside a built cage
// if they are on animal stockpiles they should count as unassigned to allow pasturing them
@ -1360,6 +1404,68 @@ command_result assignUnitToBuilding(color_ostream& out, df::unit* unit, df::buil
return result;
}
command_result nickUnitsInZone(color_ostream& out, df::building* building, string nick)
{
// building must be a pen/pasture or pit
if(!isPenPasture(building) && !isPitPond(building))
{
out << "Invalid building type. This is not a pen/pasture or pit/pond." << endl;
return CR_WRONG_USAGE;
}
df::building_civzonest * civz = (df::building_civzonest *) building;
for(size_t i = 0; i < civz->assigned_creature.size(); i++)
{
df::unit* unit = findUnitById(civz->assigned_creature[i]);
if(unit)
Units::setNickname(unit, nick);
}
return CR_OK;
}
command_result nickUnitsInCage(color_ostream& out, df::building* building, string nick)
{
// building must be a pen/pasture or pit
if(!isCage(building))
{
out << "Invalid building type. This is not a cage." << endl;
return CR_WRONG_USAGE;
}
df::building_cagest* cage = (df::building_cagest*) building;
for(size_t i=0; i<cage->assigned_creature.size(); i++)
{
df::unit* unit = findUnitById(cage->assigned_creature[i]);
if(unit)
Units::setNickname(unit, nick);
}
return CR_OK;
}
command_result nickUnitsInChain(color_ostream& out, df::building* building, string nick)
{
out << "sorry. nicknaming chained units is not possible yet." << endl;
return CR_WRONG_USAGE;
}
command_result nickUnitsInBuilding(color_ostream& out, df::building* building, string nick)
{
command_result result = CR_WRONG_USAGE;
if(isActivityZone(building))
result = nickUnitsInZone(out, building, nick);
else if(isCage(building))
result = nickUnitsInCage(out, building, nick);
else if(isChain(building))
result = nickUnitsInChain(out, building, nick);
else
out << "Cannot nickname units in this type of building!" << endl;
return result;
}
// dump some zone info
void zoneInfo(color_ostream & out, df::building* building, bool verbose)
{
@ -1552,6 +1658,8 @@ command_result df_zone (color_ostream &out, vector <string> & parameters)
bool all = false;
bool unit_slaughter = false;
static int target_building = -1;
bool nick_set = false;
string target_nick = "";
for (size_t i = 0; i < parameters.size(); i++)
{
@ -1909,6 +2017,31 @@ command_result df_zone (color_ostream &out, vector <string> & parameters)
return CR_WRONG_USAGE;
building_set = true;
}
else if(p == "nick")
{
if(invert_filter)
return CR_WRONG_USAGE;
if(i == parameters.size()-1)
{
out.printerr("No nickname specified! Use 'remnick' to remove nicknames!");
return CR_WRONG_USAGE;
}
nick_set = true;
target_nick = parameters[i+1];
i++;
out << "Set nickname to: " << target_nick << endl;
}
else if(p == "remnick")
{
if(invert_filter)
return CR_WRONG_USAGE;
nick_set = true;
target_nick = "";
i++;
out << "Remove nickname." << endl;
}
else if(p == "all")
{
if(invert_filter)
@ -2031,11 +2164,10 @@ command_result df_zone (color_ostream &out, vector <string> & parameters)
return CR_OK;
}
// assign to pen or pit
if(building_assign || unit_info || unit_slaughter)
if(building_assign || unit_info || unit_slaughter || nick_set)
{
df::building * building;
if(building_assign)
if(building_assign || (nick_set && !all && !find_count))
{
// try to get building index from the id
int32_t index = findBuildingIndexById(target_building);
@ -2046,6 +2178,12 @@ command_result df_zone (color_ostream &out, vector <string> & parameters)
return CR_WRONG_USAGE;
}
building = world->buildings.all.at(index);
if(nick_set && !building_assign)
{
out << "Renaming all units in target building." << endl;
return nickUnitsInBuilding(out, building, target_nick);
}
}
if(all || find_count)
@ -2133,14 +2271,22 @@ command_result df_zone (color_ostream &out, vector <string> & parameters)
if(unit_info)
{
unitInfo(out, unit, verbose);
continue;
}
else if(building_assign)
if(nick_set)
{
Units::setNickname(unit, target_nick);
}
if(building_assign)
{
command_result result = assignUnitToBuilding(out, unit, building, verbose);
if(result != CR_OK)
return result;
}
else if(unit_slaughter)
if(unit_slaughter)
{
// don't slaughter named creatures unless told to do so
if(!find_named && unit->name.has_name)
@ -2185,7 +2331,6 @@ command_result df_zone (color_ostream &out, vector <string> & parameters)
doMarkForSlaughter(unit);
return CR_OK;
}
}
}
@ -2995,9 +3140,9 @@ command_result autoButcher( color_ostream &out, bool verbose = false )
|| !isTame(unit)
|| isWar(unit) // ignore war dogs etc
|| isHunter(unit) // ignore hunting dogs etc
// ignore creatures in built cages to leave zoos alone
// (TODO: allow some kind of slaughter cages which you can place near the butcher)
|| (isContainedInItem(unit) && isInBuiltCage(unit))
// ignore creatures in built cages which are defined as rooms to leave zoos alone
// (TODO: better solution would be to allow some kind of slaughter cages which you can place near the butcher)
|| (isContainedInItem(unit) && isInBuiltCageRoom(unit))
|| unit->name.has_name
)
continue;