-- Start fights and hands out beatings
-- Aggressor 1.3
-- Attempts to start a fistfight or beatcriminal job
-- Fortress mode script called from DFHack, can use either the command line or a popup gui to select participants
-- LNP: [04410r3-x64]
-- GUI Courtesy of scripts from warmist, and Putnam
--
http://www.bay12forums.com/smf/index.php?topic=91166.msg4149991#msg4149991--
http://www.bay12forums.com/smf/index.php?topic=139553.msg5858508#msg5858508-- Many thanks to the inhabitants of Erithkosh, who suffered much during testing
local utils=require('utils')
local script=require('gui.script')
validArgs = utils.invert({
'help',
'verbose',
'nogui',
'victim',
'aggressors',
'death'
})
local args = utils.processArgs({...}, validArgs)
local verbose = false
local userVictim = {}
local cmdVictim = {}
local userAggressors = {}
local cmdAggressors = {}
local userFType = {}
local cmdFType = {}
local helpme = [===[
aggressor.lua
=========
This script creates a StartFistFighting or BeatCriminal job for one or more dwarves aimed at
a single target. The script can operate in two modes. When called without arguments, it
presents a gui allowing selection of the victim and the aggressor(s). Called with arguments,
allows you directly specify victim and aggressor targets. Unit IDs can be discovered with cprobe.
Caution! Some aggressors may crash DF. Crashes appear related to active military as aggressors.
arguments:
-help
print this help message
-nogui
Do not use the gui for target selection. You must provide victim and aggressors arguments
-victim
The fistfight target's unit id.
-aggressors
Unit id of the dwarf that you want to beat up the target. Also takes everyone, butme, or a
comma separated list of unit id's. See examples.
-death
Integer. 0 is a less lethal fistfight, 1 is to the death
-verbose
Flag. Prints out a lot of stuff
Examples
aggressor
Launches gui
aggressor -nogui -victim 76 -aggressors 79 -death 0
Launches the script. Unit 79 gets a StartFistFighting job aimed at unit 76
aggressor -nogui -victim 76 -aggressors 79,80 -death 0
Launches the script. Units 79,80 get a StartFistFighting job aimed at unit 76
aggressor -nogui -victim 76 -aggressors 79 -death 1
Launches the script. Unit 79 gets a BeatCriminal job aimed at unit 76
aggressor -nogui -victim 76 -aggressors everyone -death 0
Launches the script. Citizens (including 76) get a StartFistFighting job aimed at unit 76
aggressor -nogui -victim 76 -aggressors butme -death 0
Launches the script. Citizens (not including 76) get a StartFistFighting job aimed at unit 76
]===]
-- Handle help requests
if args.help then
print(helpme)
return
end
-- Handle user input
if ( args.verbose ) then
verbose = true
end
-- Handle user input
if ( args.nogui and args.victim and args.aggressors and args.death) then
-- Set CommandLine Victim
table.insert(cmdVictim, args.victim)
-- Set CommandLine Attackers
for i in (args.aggressors .. ","):gmatch("([^,]*),") do
-- print(i)
table.insert(cmdAggressors, i)
end
-- Set CommandLine Fight Type
cmdFType = args.death
else
print("Launching Aggressor gui. You might want to review -help.")
end
function getLastJobLink()
-- v43.03: Preserved for legacy uses
-- local st=df.global.world.job_list
-- v44.10r3
local st=df.global.world.jobs.list
while st.next~=nil do
st=st.next
end
return st
end
function addNewJob(job)
local nn=getLastJobLink()
local nl=df.job_list_link:new()
nl.prev=nn
nn.next=nl
nl.item=job
job.list_link=nl
end
function startFight(unit1,unit2,ftype)
local nj=df.job:new()
nj.id=df.global.job_next_id
df.global.job_next_id=df.global.job_next_id+1
nj.flags.special=true
ftype = tonumber(ftype)
-- ftype: 0-fistfight, 1-beatcriminal
if ftype == 0 then
nj.job_type=df.job_type.StartingFistFight
elseif ftype == 1 then
nj.job_type=df.job_type.BeatCriminal
else
qerror('Error: Bad fight type for job!. Neither fist nor beat?')
end
nj.completion_timer=-1
nj.general_refs:insert("#",{new=df.general_ref_unit_beateest,unit_id=unit2.id})
nj.general_refs:insert("#",{new=df.general_ref_unit_workerst,unit_id=unit1.id})
addNewJob(nj)
unit1.job.current_job=nj
end
local function makeFightGroup()
-- Add Fight Types for prompt
local FightGroup={}
table.insert(FightGroup,{'Fist Fight (Less Lethal)',nil,0})
table.insert(FightGroup,{'Beating (Lethal)',nil,1})
return FightGroup
end
local function getCitizenList()
local citizenTable={}
for k,u in ipairs(df.global.world.units.active) do
if dfhack.units.isCitizen(u) then
table.insert(citizenTable,{dfhack.TranslateName(dfhack.units.getVisibleName(u)),nil,u})
end
end
return citizenTable
end
local function getMobList()
local citizenTable={}
for k,u in ipairs(df.global.world.units.active) do
if dfhack.units.isCitizen(u) and u.military.squad_id < 0 then
table.insert(citizenTable,{dfhack.TranslateName(dfhack.units.getVisibleName(u)),nil,u})
end
end
return citizenTable
end
local function makeAggressorGroup()
-- Add multiple aggressor options
local AggGroup={}
table.insert(AggGroup,{'Everyone',nil,'Everyone'})
table.insert(AggGroup,{'Everyone But Self',nil,'ButMe'})
table.insert(AggGroup,{'From List',nil,'FromList'})
return AggGroup
end
local function setAggressors(crowd, userVictim, check)
for k, v in pairs(userVictim) do
if verbose then print("SetAgg:Victim: ",k,v) end
isVictim = v
end
local passAggressors = {}
if string.lower(check) == string.lower('Everyone') then
for k, v in pairs(crowd) do
if verbose then print("SetAgg:EV1:Aggressor: " .. v[1]) end
table.insert(passAggressors, v[3])
end
elseif string.lower(check) == string.lower('ButMe') then
for k, v in pairs(crowd) do
if v[3] ~= isVictim then
if verbose then print("SetAgg:BMe:Aggressor: " .. v[1]) end
table.insert(passAggressors, v[3])
end
end
end
return passAggressors
end
local function aggressor(userVictim, userAggressors, ftype)
local unit1,unit2 = {}
for k, v in pairs(userVictim) do
if verbose then print("Aggro:Victim: ",k,v) end
unit2 = v
end
for k, v in pairs(userAggressors) do
if verbose then print("Aggro:Aggressor: ",k,v,ftype) end
local unit1 = v
startFight(unit1, unit2, ftype)
end
end
-- Let's do this
script.start(function()
-- Get list of valid targets(citizens)
local citizens=getCitizenList()
-- Get list of valid aggressors(the mob)
local mob=getMobList()
local AggressorGroup=makeAggressorGroup()
local fightstyle=makeFightGroup()
local ftype = 0
if #citizens==0 then
script.showMessage('Aggressor',"No citizens! Something is broken.",COLOR_WHITE)
qerror('Error: No citizens! Something is broken.')
return
end
if #mob==0 then
script.showMessage('Aggressor',"No one in the mob! Maybe everyone is in the military?.",COLOR_WHITE)
qerror('Error: No mob! Something is broken.')
return
end
if #fightstyle==0 then
script.showMessage('Aggressor',"No kinds of fights!",COLOR_WHITE)
qerror('Error: No kinds of fights! Something is broken.')
return
end
-- Gui in use
if not args.nogui then
-- Gui is in use, overwrite command line options specified
if verbose then print("GUI in use, overwriting any command line options...") end
userVictim = {}
userAggressors = {}
-- Prompt for fight type
local ok2,name2,fstyle = script.showListPrompt("Aggressor","Choose the fight type",COLOR_WHITE,fightstyle)
ftype = fstyle[3]
if verbose then print("Lst:Type: ", ftype) end
-- Prompt for victim
local ok2,name2,victim = script.showListPrompt("Aggressor","Choose the victim",COLOR_WHITE,citizens)
local isVictim = victim[3]
table.insert(userVictim, victim[3])
-- Prompt for aggressor_group
userAggressors = {}
local ok2,name,ag = script.showListPrompt("Aggressor","Choose the aggressors",COLOR_WHITE,AggressorGroup)
local check = ag[3]
if string.lower(check) == string.lower('Everyone') then
userAggressors = setAggressors(mob, userVictim, check)
elseif string.lower(check) == string.lower('ButMe') then
userAggressors = setAggressors(mob, userVictim, check)
elseif string.lower(check) == string.lower('FromList') then
table.insert(mob,{'Done',nil,'Done'})
local endwatch = ''
local target = ''
while endwatch ~= 'Done' do
for k, v in pairs(mob) do
if v[3] == target then
if verbose then print("Lst:Aggressor: " .. v[1]) end
table.insert(userAggressors, v[3])
table.remove(mob,k)
end
end
local ok2,name2,aggressor=script.showListPrompt("Aggressor","Choose aggressors. Done to Finish",COLOR_WHITE,mob)
if verbose then print("User choice: ", aggressor[1], aggressor[3]) end
endwatch = aggressor[1]
target = aggressor[3]
end
else
-- How?!
qerror('Error: Bad selection in Aggressor Group.')
end
else
-- Gui not in use
for k, v in pairs(cmdVictim) do
table.insert(userVictim, df.unit.find(v))
end
for k, v in pairs(cmdAggressors) do
local check = cmdAggressors[k]
-- print("NoGUI:Aggro",check)
if string.lower(check) == string.lower('Everyone') then
userAggressors = setAggressors(mob, userVictim, check)
elseif string.lower(check) == string.lower('ButMe') then
userAggressors = setAggressors(mob, userVictim, check)
elseif tonumber(check) ~= nil then
table.insert(userAggressors, df.unit.find(check))
else
qerror('Error: Unhandled nogui aggressor type.')
end
end
ftype = cmdFType
end
print("Victims: " .. #userVictim .. " Aggressors: " .. #userAggressors .. " Type:" .. ftype)
-- Start some fights
aggressor(userVictim, userAggressors, ftype)
end)