Autofight and throwing


Questions, Explanations, Howtos

Spider Stomper

Posts: 243

Joined: Sunday, 28th August 2011, 14:04

Post Sunday, 15th April 2012, 01:33

Autofight and throwing

I have made a minor change to autofight.lua, that allows the use of thrown weapons/projectiles. Instead of walking towards the monsters, you will throw any quivered items. I found it to be very useful for hunters and gladiators in the early game.

I changed the function have_ranged() from:
  Code:
local function have_ranged()
  local wp = items.equipped_at("weapon")
  return wp and wp.is_ranged and not wp.is_melded
end

to:
  Code:
local function have_ranged()
  return items.fired_item() ~= nil
end

Spider Stomper

Posts: 243

Joined: Sunday, 28th August 2011, 14:04

Post Sunday, 15th April 2012, 02:07

Re: Autofight and throwing

Here is my complete autofight.lua (actually autofight2.lua). I also made a change to get_monster_info.
  Code:
---------------------------------------------------------------------------
-- autofight.lua:
-- One-key fighting.
--
-- To use this, add this line to your init.txt:
--   lua_file = lua/autofight.lua
--
-- This uses the very incomplete client monster and view bindings, and
-- is currently very primitive. Improvements welcome!
---------------------------------------------------------------------------

local ATT_HOSTILE = 0
local ATT_NEUTRAL = 1

AUTOFIGHT_STOP = 30

local function delta_to_vi(dx, dy)
  local d2v = {
    [-1] = { [-1] = 'y', [0] = 'h', [1] = 'b'},
    [0]  = { [-1] = 'k',            [1] = 'j'},
    [1]  = { [-1] = 'u', [0] = 'l', [1] = 'n'},
  }
  return d2v[dx][dy]
end

local function sign(a)
  return a > 0 and 1 or a < 0 and -1 or 0
end

local function abs(a)
  return a * sign(a)
end

local function adjacent(dx, dy)
  return abs(dx) <= 1 and abs(dy) <= 1
end

local function vector_move(dx, dy)
  local str = ''
  for i = 1,abs(dx) do
    str = str .. delta_to_vi(sign(dx), 0)
  end
  for i = 1,abs(dy) do
    str = str .. delta_to_vi(0, sign(dy))
  end
  return str
end

local function have_reaching()
  local wp = items.equipped_at("weapon")
  return wp and wp.reach_range == 8 and not wp.is_melded
end

local function have_ranged()
  local wp = items.equipped_at("weapon")
  return wp and wp.is_ranged and not wp.is_melded
end

local function have_throwing()
   return items.fired_item() ~= nil
end

local function try_move(dx, dy)
  m = monster.get_monster_at(dx, dy)
  -- attitude > ATT_NEUTRAL should mean you can push past the monster
  if view.is_safe_square(dx, dy) and (not m or m:attitude() > ATT_NEUTRAL) then
    return delta_to_vi(dx, dy)
  else
    return nil
  end
end

local function move_towards(dx, dy)
  local move = nil
  if abs(dx) > abs(dy) then
    if abs(dy) == 1 then
      move = try_move(sign(dx), 0)
    end
    if move == nil then move = try_move(sign(dx), sign(dy)) end
    if move == nil then move = try_move(sign(dx), 0) end
    if move == nil and abs(dx) > abs(dy)+1 then
      move = try_move(sign(dx), 1)
    end
    if move == nil and abs(dx) > abs(dy)+1 then
      move = try_move(sign(dx), -1)
    end
    if move == nil then move = try_move(0, sign(dy)) end
  elseif abs(dx) == abs(dy) then
    move = try_move(sign(dx), sign(dy))
    if move == nil then move = try_move(sign(dx), 0) end
    if move == nil then move = try_move(0, sign(dy)) end
  else
    if abs(dx) == 1 then
      move = try_move(0, sign(dy))
    end
    if move == nil then move = try_move(sign(dx), sign(dy)) end
    if move == nil then move = try_move(0, sign(dy)) end
    if move == nil and abs(dy) > abs(dx)+1 then
      move = try_move(1, sign(dy))
    end
    if move == nil and abs(dy) > abs(dx)+1 then
      move = try_move(-1, sign(dy))
    end
    if move == nil then move = try_move(sign(dx), 0) end
  end
  if move == nil then
    crawl.mpr("Failed to move towards target.")
  else
    crawl.process_keys(move)
  end
end

local function get_monster_info(dx,dy)
  m = monster.get_monster_at(dx,dy)
  if not m then
    return nil
  end
  info = {}
  info.distance = (abs(dx) > abs(dy)) and -abs(dx) or -abs(dy)
  if have_ranged() then
    info.attack_type = you.see_cell_no_trans(dx, dy) and 3 or 0
  elseif not have_reaching() then
    info.attack_type = (-info.distance < 2) and 2 or 0
  else
    if -info.distance > 2 then
      info.attack_type = 0
    elseif -info.distance < 2 then
      info.attack_type = 2
    else
       info.attack_type = view.can_reach(dx, dy) and 1 or 0
    end
  end
  if info.attack_type == 0 and have_throwing() then
     info.attack_type = you.see_cell_no_trans(dx, dy) and 3 or 0
  end
  info.can_attack = (info.attack_type > 0) and 1 or 0
  info.safe = m:is_safe() and -1 or 0
  info.constricting_you = m:is_constricting_you() and 1 or 0
  -- Only prioritize good stabs: sleep and paralysis.
  info.very_stabbable = (m:stabbability() >= 1) and 1 or 0
  info.injury = m:damage_level()
  info.threat = m:threat()
  return info
end

local function compare_monster_info(m1, m2)
  flag_order = {"can_attack", "safe", "distance", "constricting_you", "very_stabbable", "injury", "threat"}
  for i,flag in ipairs(flag_order) do
    if m1[flag] > m2[flag] then
      return true
    elseif m1[flag] < m2[flag] then
      return false
    end
  end
  return false
end

local function is_candidate_for_attack(x,y)
  m = monster.get_monster_at(x, y)
  --if m then crawl.mpr("Checking: (" .. x .. "," .. y .. ") " .. m:desc()) end
  if not m or m:attitude() ~= ATT_HOSTILE then
    return false
  end
  if string.find(m:desc(), "butterfly")
      or string.find(m:desc(), "orb of destruction") then
    return false
  end
  if m:is_firewood() then
  --crawl.mpr("... is firewood.")
    if string.find(m:desc(), "ballistomycete") then
      return true
    end
    return false
  end
  return true
end

local function get_target()
  local x, y, bestx, besty, best_info, new_info
  bestx = 0
  besty = 0
  best_info = nil
  for x = -8,8 do
    for y = -8,8 do
      if is_candidate_for_attack(x, y) then
        new_info = get_monster_info(x, y)
        if (not best_info) or compare_monster_info(new_info, best_info) then
          bestx = x
          besty = y
          best_info = new_info
        end
      end
    end
  end
  return bestx, besty, best_info
end

local function attack_fire(x,y)
  move = 'fr' .. vector_move(x, y) .. 'f'
  crawl.process_keys(move)
end

local function attack_reach(x,y)
  move = 'vr' .. vector_move(x, y) .. '.'
  crawl.process_keys(move)
end

local function attack_melee(x,y)
  move = delta_to_vi(x, y)
  crawl.process_keys(move)
end

local function set_stop_level(key, value)
  AUTOFIGHT_STOP = tonumber(value)
end

local function hp_is_low()
  local hp, mhp = you.hp()
  return (100*hp <= AUTOFIGHT_STOP*mhp)
end

function attack(allow_movement)
  local x, y, info = get_target()
  local caught = you.caught()
  if you.confused() then
    crawl.mpr("You are too confused!")
  elseif caught then
    crawl.mpr("You are " .. caught .. "!")
  elseif hp_is_low() then
    crawl.mpr("You are too injured to fight blindly!")
  elseif info == nil then
    crawl.mpr("No target in view!")
  elseif info.attack_type == 3 then
    attack_fire(x,y)
  elseif info.attack_type == 2 then
    attack_melee(x,y)
  elseif info.attack_type == 1 then
    attack_reach(x,y)
  elseif allow_movement then
    move_towards(x,y)
  else
    crawl.mpr("No target in range!")
  end
end

function hit_closest()
  attack(true)
end

function hit_adjacent()
  attack(false)
end

chk_lua_option.autofight_stop = set_stop_level

User avatar

Pandemonium Purger

Posts: 1341

Joined: Monday, 24th October 2011, 06:13

Post Wednesday, 18th April 2012, 10:01

Re: Autofight and throwing

I rewrote your code, anyone can type it directly into the game. it works, my brother helped. well, here it is:

  Code:
ff
seattle washington. friends for life. mods hate on me and devs ignore my posts. creater of exoelfs and dc:pt
User avatar

Dungeon Master

Posts: 4031

Joined: Thursday, 16th December 2010, 20:37

Location: France

Post Wednesday, 18th April 2012, 12:20

Re: Autofight and throwing

twelwe wrote:I rewrote your code, anyone can type it directly into the game. it works, my brother helped. well, here it is:

  Code:
ff

If you think this comment makes you look smart, think again. This is retarded.

@CommanderC: Thanks for sharing your code, I'll see if we can put it to good use.
<+Grunt> You dereference an invalid pointer! Ouch! That really hurt! The game dies...
User avatar

Abyss Ambulator

Posts: 1249

Joined: Sunday, 18th September 2011, 02:11

Post Wednesday, 18th April 2012, 15:09

Re: Autofight and throwing

If this is implemented, please use it as an option and not as default. I play a lot of tabspamming primary-melee characters where I don't want to be throwing whatever happens to be in my quiver.
User avatar

Ziggurat Zagger

Posts: 5832

Joined: Thursday, 10th February 2011, 18:30

Post Wednesday, 18th April 2012, 15:15

Re: Autofight and throwing

Blade wrote:If this is implemented, please use it as an option and not as default. I play a lot of tabspamming primary-melee characters where I don't want to be throwing whatever happens to be in my quiver.


I totally agree with an init activation switch.
"Be aware that a lot of people on this forum, such as mageykun and XuaXua, have a habit of making things up." - minmay a.k.a. duvessa
Did I make a lame complaint? Check for Bingo!
Totally gracious CSDC Season 2 Division 4 Champeen!

Return to Coding

Who is online

Users browsing this forum: No registered users and 7 guests

cron
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software for PTF.