Determine the distance a ship can move in 1 turn

A place for discussion of making game modifications.
User avatar
sven
Site Admin
Posts: 1621
Joined: Sat Jan 31, 2015 10:24 pm
Location: British Columbia, Canada
Contact:

Re: Determine the distance a ship can move in 1 turn

Post by sven »

harpy eagle wrote:Which revision is the change on? Just want to know when it reaches the public branch.
I've just pushed r22135 to Steam and GoG.com -- it's primarily a hotfix update, but, it also happens to include these updates to the low-level tactical AI motion functions.
User avatar
harpy eagle
Posts: 296
Joined: Sat Mar 10, 2018 3:25 am

Re: Determine the distance a ship can move in 1 turn

Post by harpy eagle »

sven wrote: ship.s>4 --> turn_mult=(25/4),

ship.s==4 --> turn_mult=0.7*(25/4), and

ship.s<4--> turn_mult = (25/4)/3.
Out of curiosity, is ship.s related to ship.speed_class at all?

Also, what is the signature for the motion cost function? I'm guessing it's ship.motion_cost(x,y,r)?

So if I wanted to implement a function that turned a ship to face a given target, would this work?

Code: Select all

local turn_costs = {
  [1]  = 25/4,
  [0]  = 25/4*0.7,
  [-1] = 25/4/3,
}

function turn_cost(ship)
  return turn_costs[(ship.s > 4 and 1) or (ship.s == 4 and 0) or -1]
end

function face_target(ship, target)
  local r = rotate_to_face(ship,target)
  if ship.motion_cost(0,0,r) > ship.max_fuel
    local sign = r/abs(r)
    r = sign * ship.max_fuel/turn_cost(ship)
  end

  local x,y = object_center(ship)
  action.move_ships{ship, x, y, r}
end

-- elsewhere...
if to_target(ship, move_target) <= attack_dist
  face_target(ship, move_target)
end
Although, I think there are two issues with this. The first is that it seems pretty equivalent to just do:

Code: Select all

local x,y,r,r2 = find_min_facing_move_L2(ship,move_target,attack_dist)
if to_target(ship, move_target) <= attack_dist
  x,y = object_center(ship)
end

action.move_ships{ship, x, y, r}
Which involves far less assumptions - especially since we don't need to do our own inverse motion cost calculation.

The second is that either way, we need to pass an x,y into action.move_ships() to actually do a turn without moving. Which is problematic because using object_center() causes all kinds of motion weirdness (ships spinning around in strange ways). In the end I just ended up using ship.x, ship.y for x,y - which mostly works but causes that wiggle I mentioned earlier.
User avatar
sven
Site Admin
Posts: 1621
Joined: Sat Jan 31, 2015 10:24 pm
Location: British Columbia, Canada
Contact:

Re: Determine the distance a ship can move in 1 turn

Post by sven »

harpy eagle wrote: So if I wanted to implement a function that turned a ship to face a given target, would this work?
Sadly, I believe ship.motion_cost doesn't actually do what you'd hope it would. However, this is a function 'ship_can_rotate' that will tell you whether or not a given rotation has a cost <= the ships current fuel.

Equally troublesomely, the value that you'll get from rotate_to_face is an absolute rotation, i.e., a number from 0-7, that corresponds to the degree rotation x 45. So, getting the trig right requires some pain and suffering. So to do what you're trying to do, I'd probably start with a template that looked sortof like this.

Code: Select all


function face_target(ship, target)
  local r = rotate_to_face(ship,target)
  if not ship_can_rotate(ship,r)
    for i=0,7
    	if ship_can_rotate(ship,i)
	    -- TODO figure out if this rotation is the 'best' possible approximation for r.
	    -- the best way i can think to do this involves using a a bunch of sin and cos calls,
	    -- to evaluate dot products -- and while i could write something down that *might* 
	    -- be right, i'm not in a position to debug it atm.
    	end
    end
  end

  action.move_ships{ship, ship.x, ship.y, r}
end
User avatar
sven
Site Admin
Posts: 1621
Joined: Sat Jan 31, 2015 10:24 pm
Location: British Columbia, Canada
Contact:

Re: Determine the distance a ship can move in 1 turn

Post by sven »

harpy eagle wrote: The second is that either way, we need to pass an x,y into action.move_ships() to actually do a turn without moving. Which is problematic because using object_center() causes all kinds of motion weirdness (ships spinning around in strange ways). In the end I just ended up using ship.x, ship.y for x,y - which mostly works but causes that wiggle I mentioned earlier.
In theory, to rotate without moving, you want to send in ship.x, ship.y -- i.e., the motion command expects you to tell it where the bottom left corner of the ship's tile should be, not where it's center should be.

The weird wiggle you're seeing probably has to do with obscure behaviors of find_min_facing_move_L2 that only come into effect when the requested move is impossible. As you can see in the original version of close_and_attack r2==r is used as a flag for the situation where it's possible to move within the stated range of the target, but, not possible to rotate into a state where we're facing the target -- and, thus, where it's not worth performing the second rotation step. So, if you use r2 as a guide for a rotate_to_face_as_close_as_possible type function, you'll sometimes get nonsense.
User avatar
harpy eagle
Posts: 296
Joined: Sat Mar 10, 2018 3:25 am

Re: Determine the distance a ship can move in 1 turn

Post by harpy eagle »

sven wrote:In theory, to rotate without moving, you want to send in ship.x, ship.y -- i.e., the motion command expects you to tell it where the bottom left corner of the ship's tile should be, not where it's center should be.
Ah, okay. Good to know that I was actually doing what I was supposed to be doing, after all.
Post Reply