# exterminate creatures

# race = name of the race to eradicate, use 'him' to target only the selected creature
# use 'undead' to target all undeads
race = $script_args[0]

# if the 2nd parameter is 'magma', magma rain for the targets instead of instant death
# if it is 'butcher' mark all units for butchering (wont work with hostiles)
kill_by = $script_args[1]

case kill_by
when 'magma'
	slain = 'burning'
when 'slaughter', 'butcher'
	slain = 'marked for butcher'
when nil
	slain = 'slain'
else
	race = 'help'
end

checkunit = lambda { |u|
	(u.body.blood_count != 0 or u.body.blood_max == 0) and
	not u.flags1.dead and
	not u.flags1.caged and not u.flags1.chained and
	#not u.flags1.hidden_in_ambush and
	not df.map_designation_at(u).hidden
}

slayit = lambda { |u|
	case kill_by
	when 'magma'
		# it's getting hot around here
		# !!WARNING!! do not call on a magma-safe creature
		ouh = df.onupdate_register("exterminate ensure #{u.id}", 1) {
			if u.flags1.dead
				df.onupdate_unregister(ouh)
			else
				x, y, z = u.pos.x, u.pos.y, u.pos.z
				z += 1 while tile = df.map_tile_at(x, y, z+1) and
					tile.shape_passableflow and tile.shape_passablelow
				df.map_tile_at(x, y, z).spawn_magma(7)
			end
		}
	when 'butcher', 'slaughter'
		# mark for slaughter at butcher's shop
		u.flags2.slaughter = true
	else
		# just make them drop dead
		u.body.blood_count = 0
		# some races dont mind having no blood, ensure they are still taken care of.
		u.animal.vanish_countdown = 2
	end
}

all_races = Hash.new(0)

df.world.units.active.map { |u|
	if checkunit[u]
		if (u.enemy.undead or
		    (u.curse.add_tags1.OPPOSED_TO_LIFE and not
		     u.curse.rem_tags1.OPPOSED_TO_LIFE))
			all_races['Undead'] += 1
		else
			all_races[u.race_tg.creature_id] += 1
		end
	end
}

case race
when nil
	all_races.sort_by { |race, cnt| [cnt, race] }.each{ |race, cnt| puts " #{race} #{cnt}" }

when 'help', '?'
	puts <<EOS
Kills all creatures of a given race.
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 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.
The special final argument 'butcher' will mark the targets for butchering instead.

Ex: exterminate gob
    exterminate gob:male
    exterminate elve magma
    exterminate him
    exterminate pig butcher
EOS

when 'him', 'her', 'it', 'that'
	if him = df.unit_find
		case him.race_tg.caste[him.caste].gender
		when 0; puts 'its a she !' if race != 'her'
		when 1; puts 'its a he !'  if race != 'him'
		else;   puts 'its an it !' if race != 'it' and race != 'that'
		end
		slayit[him]
	else
		puts "Select a target ingame"
	end

when /^undead/i
	count = 0
	df.world.units.active.each { |u|
		if (u.enemy.undead or
		    (u.curse.add_tags1.OPPOSED_TO_LIFE and not
		     u.curse.rem_tags1.OPPOSED_TO_LIFE)) and
		   checkunit[u]
			slayit[u]
			count += 1
		end
	}
	puts "#{slain} #{count} undeads"

else
	if race.index(':')
		race, caste = race.split(':')
	end

	raw_race = df.match_rawname(race, all_races.keys)
	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 }

	if caste
		all_castes = df.world.raws.creatures.all[race_nr].caste.map { |c| c.caste_id }
		raw_caste = df.match_rawname(caste, all_castes)
		if not raw_caste
			puts "Invalid caste, use one of #{all_castes.sort.join(' ')}"
			throw :script_finished
		end
		caste_nr = all_castes.index(raw_caste)
	end

	count = 0
	df.world.units.active.each { |u|
		if u.race == race_nr and checkunit[u]
			next if caste_nr and u.caste != caste_nr
			slayit[u]
			count += 1
		end
	}
	puts "#{slain} #{count} #{raw_caste} #{raw_race}"

end