So far, this script does one of two things:
If a monster at less than 25% health hits a friendly monster with its attack, the script will search for roughly the nearest live enemy and have the monster attack it.
Otherwise, if any monster's attack hits either a friendly monster or itself, the script will politely ask the monster to move in a preferably forward direction.
With this script, I've seen snipers jump down if they're hitting their own soldiers, berserk cyborgs respond to friendly fire but once before turning back to the player, BoBs get off their asses to move up and take the place of a fallen comrade they've mistakenly killed, and troopers reposition themselves when grenading their own feet. None of this happens reliably, but having it happen occasionally gives the monsters a little extra bit of spice and challenge!
I'd certainly welcome any input as to other things monsters might possibly be scripted to do, or point out any potential problems with this code before I release it as a plugin. Sadly, further ideas I've had rely on being able to find a monsters target, which as far as I can tell is only possible if they naturally fire a guided projectile.
Wrkncacnter gave me the two angle functions at the end on discord, he was not sure as to where he found them.
Also, at are two important points there are a trio of commented-out lines that if un-commented will print debug output to the screen. The script:
Code: Select all
Triggers = {}
function Triggers.monster_damaged(monster, aggressor_monster, damage_type, damage_amount, projectile)
if not monster._zerkvit then
monster._zerkvit = ( monster.vitality + damage_amount ) / 4
end
if aggressor_monster and not aggressor_monster.player and aggressor_monster.valid then
if not aggressor_monster._zerkvit then
aggressor_monster._zerkvit = ( aggressor_monster.vitality + damage_amount ) / 4
end
if aggressor_monster._zerkvit >= aggressor_monster.vitality and aggressor_monster ~= monster and aggressor_monster.type.friends[monster.type.class] then
local delta = 524288
-- find nearest enemy target to attack
for m in Monsters() do
if m.valid and m.visible then
if aggressor_monster.type.enemies[m.type.class] and m.life > 0 then
local maybe = math.abs(math.abs(aggressor_monster.facing - angle_between_points(m,aggressor_monster))-180) + math.abs(m.x - aggressor_monster.x) + math.abs(m.y - aggressor_monster.y) + math.abs(m.z - aggressor_monster.z) * 7
if maybe < delta then
badzerktarget = m
delta = maybe
end
end
end
end
end
if badzerktarget then
aggressor_monster:attack(badzerktarget)
-- local bz = "berserking "
-- local on = " on "
-- Players.print(bz..tostring(aggressor_monster)..on..tostring(badzerktarget))
badzerktarget = nil
else
if aggressor_monster == monster or aggressor_monster.type.friends[monster.type.class] then
local dest = Players[0].monster.polygon
local delta = 512
-- find anything to run towards, preferably but not necessarily forewards
for m in Monsters() do
local maybe = math.abs(math.abs(aggressor_monster.facing - angle_between_points(m,aggressor_monster))-180)
if maybe < delta then
dest = m.polygon
delta = maybe
end
end
aggressor_monster:move_by_path(dest)
-- local mv = "moving "
-- local to = " to "
-- Players.print(mv..tostring(aggressor_monster)..to..tostring(dest))
end
end
end
end
function angleOfPoint(pt)
local x, y = pt.x, pt.y
local radian = math.atan2(y, x)
local angle = radian * 180 / math.pi
if angle < 0 then
angle = 360 + angle
end
return angle
end
-- returns the degrees between two points (note: 0 degrees is 'east')
function angle_between_points(a, b)
local x, y = b.x - a.x, b.y - a.y
return angleOfPoint({x = x, y = y})
end
Code: Select all
vhalt: monsters.cpp:321: monster index #39 (0x22f9770) is unused (csalerts_sdl.cpp:273)
FATAL: monsters.cpp:321: monster index #39 (0x22f9770) is unused
Aborted