ID:148562
 
Ok i have a seeking missile verb, several version of it in fact. Heres version 4 that works:

fire_heat_seeker4()
new/obj/hsmissile(usr.loc)
var/T = 0
for(var/obj/hsmissile/H in usr.loc)
for(var/mob/M in orange(6))
if(M == usr)
del(H)
if(!M)
H.dir = usr.dir
walk(H,H.dir,2)
spawn(20)
del(H)
else
H.dir = usr.dir
walk(H,H.dir,2)
spawn(5)
seek
if(T<=10)//if it hasnt rescanned direction 6 times yet
var/D = get_dir(H,M)//this finds the direction it needs to go to get the M
if(D == NORTH) {if(H.dir == NORTH) ..();if(H.dir == NORTHEAST) H.dir = turn(H.dir, 45);if(H.dir == EAST) H.dir = turn(H.dir, 45);if(H.dir == SOUTHEAST) H.dir = turn(H.dir, 45);if(H.dir == SOUTH) H.dir = turn(H.dir, 45);if(H.dir == SOUTHWEST) H.dir = turn(H.dir, -45);if(H.dir == WEST) H.dir = turn(H.dir, -45);if(H.dir == NORTHWEST)H.dir = turn(H.dir, -45)}
if(D == NORTHEAST) {if(H.dir == NORTH) H.dir = turn(H.dir, -45);if(H.dir == NORTHEAST) ..();if(H.dir == EAST) H.dir = turn(H.dir, 45);if(H.dir == SOUTHEAST) H.dir = turn(H.dir, 45);if(H.dir == SOUTH) H.dir = turn(H.dir, 45);if(H.dir == SOUTHWEST) H.dir = turn(H.dir, 45);if(H.dir == WEST) H.dir = turn(H.dir, -45);if(H.dir == NORTHWEST)H.dir = turn(H.dir, -45)}
if(D == EAST) {if(H.dir == NORTH) H.dir = turn(H.dir, -45);if(H.dir == NORTHEAST) H.dir = turn(H.dir, -45);if(H.dir == EAST) ..();if(H.dir == SOUTHEAST) H.dir = turn(H.dir, 45);if(H.dir == SOUTH) H.dir = turn(H.dir, 45);if(H.dir == SOUTHWEST) H.dir = turn(H.dir, 45);if(H.dir == WEST) H.dir = turn(H.dir, 45);if(H.dir == NORTHWEST)H.dir = turn(H.dir, -45)}
if(D == SOUTHEAST) {if(H.dir == NORTH) H.dir = turn(H.dir, -45);if(H.dir == NORTHEAST) H.dir = turn(H.dir, -45);if(H.dir == EAST) H.dir = turn(H.dir, -45);if(H.dir == SOUTHEAST) ..();if(H.dir == SOUTH) H.dir = turn(H.dir, 45);if(H.dir == SOUTHWEST) H.dir = turn(H.dir, 45);if(H.dir == WEST) H.dir = turn(H.dir, 45);if(H.dir == NORTHWEST)H.dir = turn(H.dir, -45)}
if(D == SOUTH) {if(H.dir == NORTH) H.dir = turn(H.dir, -45);if(H.dir == NORTHEAST) H.dir = turn(H.dir, -45);if(H.dir == EAST) H.dir = turn(H.dir, -45);if(H.dir == SOUTHEAST) H.dir = turn(H.dir, -45);if(H.dir == SOUTH) ..();if(H.dir == SOUTHWEST) H.dir = turn(H.dir, 45);if(H.dir == WEST) H.dir = turn(H.dir, 45);if(H.dir == NORTHWEST)H.dir = turn(H.dir, 45)}
if(D == SOUTHWEST) {if(H.dir == NORTH) H.dir = turn(H.dir, 45);if(H.dir == NORTHEAST) H.dir = turn(H.dir, -45);if(H.dir == EAST) H.dir = turn(H.dir, -45);if(H.dir == SOUTHEAST) H.dir = turn(H.dir, -45);if(H.dir == SOUTH) H.dir = turn(H.dir, -45);if(H.dir == SOUTHWEST) ..();if(H.dir == WEST) H.dir = turn(H.dir, 45);if(H.dir == NORTHWEST)H.dir = turn(H.dir, 45)}
if(D == WEST) {if(H.dir == NORTH) H.dir = turn(H.dir, 45);if(H.dir == NORTHEAST) H.dir = turn(H.dir, 45);if(H.dir == EAST) H.dir = turn(H.dir, -45);if(H.dir == SOUTHEAST) H.dir = turn(H.dir, -45);if(H.dir == SOUTH) H.dir = turn(H.dir, -45);if(H.dir == SOUTHWEST) H.dir = turn(H.dir, -45);if(H.dir == WEST) ..();if(H.dir == NORTHWEST)H.dir = turn(H.dir, 45)}
if(D == NORTHWEST) {if(H.dir == NORTH) H.dir = turn(H.dir, 45);if(H.dir == NORTHEAST) H.dir = turn(H.dir, 45);if(H.dir == EAST) H.dir = turn(H.dir, 45);if(H.dir == SOUTHEAST) H.dir = turn(H.dir, -45);if(H.dir == SOUTH) H.dir = turn(H.dir, -45);if(H.dir == SOUTHWEST) H.dir = turn(H.dir, -45);if(H.dir == WEST) H.dir = turn(H.dir, -45);if(H.dir == NORTHWEST) ..()}
walk(H,H.dir,2)//this makes it go in the direction of D
spawn(5)//waits a half second
T++//adds 1 to T
goto seek//returns to the point 'seek'
else//if it has rescanned direction 6 times or more(for some reason)
del(H)//delete the missile

And heres version 5, I was playing around with variables, and it appears that it should work, but after the missile turns one time it just heads off straight:

fire_heat_seeker5()
new/obj/hsmissile(usr.loc)
var/T = 0
var/N=NORTH;var/NE=NORTHEAST;var/E=EAST;var/ SE=SOUTHEAST;var/S=SOUTH;var/SW=SOUTHWEST;var/W=WEST;var/ NW=NORTHWEST
for(var/obj/hsmissile/H in usr.loc)
for(var/mob/M in orange(6))
if(M == usr)
del(H)
if(!M)
H.dir = usr.dir
walk(H,H.dir,2)
spawn(20)
del(H)
else
H.dir = usr.dir
walk(H,H.dir,2)
var/P = turn(H.dir, 45);var/Q = turn(H.dir, -45)
spawn(5)
seek
if(T<=10)//if it hasnt rescanned direction 6 times yet
var/D = get_dir(H,M)//this finds the direction it needs to go to get the M
if(D==N){if(H.dir==NE)H.dir=P;if(H.dir==E)H.dir=P;if(H.dir== SE)H.dir=P;if(H.dir==S)H.dir=P;if(H.dir==SW)H.dir=Q;if(H.dir ==W)H.dir=Q;if(H.dir==NW)H.dir=Q;if(H.dir==N)..()}
if(D==NE){if(H.dir==N)H.dir=Q;if(H.dir==E)H.dir=P;if(H.dir== SE)H.dir=P;if(H.dir==S)H.dir=P;if(H.dir==SW)H.dir=P;if(H.dir ==W)H.dir=Q;if(H.dir==NW)H.dir=Q;if(H.dir==NE)..()}
if(D==E){if(H.dir==N)H.dir=Q;if(H.dir==NE)H.dir=Q;if(H.dir== SE)H.dir=P;if(H.dir==S)H.dir=P;if(H.dir==SW)H.dir=P;if(H.dir ==W)H.dir=P;if(H.dir==NW)H.dir=Q;if(H.dir==E)..()}
if(D==SE){if(H.dir==N)H.dir=Q;if(H.dir==NE)H.dir=Q;if(H.dir= =E)H.dir=Q;if(H.dir==S)H.dir=P;if(H.dir==SW)H.dir=P;if(H.dir= =W)H.dir=P;if(H.dir==NW)H.dir=Q;if(H.dir==SE)..()}
if(D==S){if(H.dir==N)H.dir=Q;if(H.dir==NE)H.dir=Q;if(H.dir== E)H.dir=Q;if(H.dir==SE)H.dir=Q;if(H.dir==SW)H.dir=P;if(H.dir ==W)H.dir=P;if(H.dir==NW)H.dir=P;if(H.dir==S)..()}
if(D==SW){if(H.dir==N)H.dir=P;if(H.dir==NE)H.dir=Q;if(H.dir= =E)H.dir=Q;if(H.dir==SE)H.dir=Q;if(H.dir==S)H.dir=Q;if(H.dir= =W)H.dir=P;if(H.dir==NW)H.dir=P;if(H.dir==SW)..()}
if(D==W){if(H.dir==N)H.dir=P;if(H.dir==NE)H.dir=P;if(H.dir== E)H.dir=Q;if(H.dir==SE)H.dir=Q;if(H.dir==S)H.dir=Q;if(H.dir= =SW)H.dir=Q;if(H.dir==NW)H.dir=P;if(H.dir==W)..()}
if(D==NW){if(H.dir==N)H.dir=P;if(H.dir==NE)H.dir=P;if(H.dir= =E)H.dir=P;if(H.dir==SE)H.dir=Q;if(H.dir==S)H.dir=Q;if(H.dir= =SW)H.dir=Q;if(H.dir==W)H.dir=Q;if(H.dir==NW)..()}
walk(H,H.dir,2)//this makes it go in the direction of D
spawn(5)//waits a half second
T++//adds 1 to T
goto seek//returns to the point 'seek'
else//if it has rescanned direction 6 times or more(for some reason)
del(H)//delete the missile

Anyone see a difference that would cuase the problem im having/see anything I should change with this?
That directional scanning code is intensely freaky; there has to be a better way of doing it than what you're doing with all those ifs.

There's also this curious little bit:
new/obj/hsmissile(usr.loc)
var/T = 0
for(var/obj/hsmissile/H in usr.loc)
...
Very wrong way to do that. If you want a var H to keep track of the missile you just created, then do so when you create it:
var/obj/hmissile/H = new(usr.loc)
var/T = 0
Looping through every missile would cause problems if ever more than one missile was at your location (for example, if you teleported right onto one and fired). The only one that this proc is supposed to control is the one just fired.

This code has a few other heinous problems as well: Your use of goto for a simple loop, for example. A while() loop and a continue statement will do the trick, so use those. Never use goto when a regular loop construct will suffice just as well (or better); that's 99.9% of the cases.

Likewise, it makes no sense to me to put the seek code in the firing proc. Put it in the missile's own code instead:
obj/hmissile
var/mob/owner

New(newloc,mob/firedby)
owner=firedby
spawn(-1) Seek()

proc/Seek()
...
spawn(5) Seek()

Bump(atom/obstacle)
... // explode

Lummox JR
In response to Lummox JR
Lummox JR wrote:
That directional scanning code is intensely freaky; there has to be a better way of doing it than what you're doing with all those ifs.

Ive tried for awhile, and this was the only thing I could think of turn make sure it turned in the correct direction I was actually hoping someone would know a better way of doing this already because I agree with you, thats some freaky code.

There's also this curious little bit:
new/obj/hsmissile(usr.loc)
> var/T = 0
> for(var/obj/hsmissile/H in usr.loc)
> ...
Very wrong way to do that. If you want a var H to keep track of the missile you just created, then do so when you create it:

I'll do this.

var/obj/hmissile/H = new(usr.loc)
> var/T = 0
Looping through every missile would cause problems if ever more than one missile was at your location (for example, if you teleported right onto one and fired). The only one that this proc is supposed to control is the one just fired.

Ill do this as well.

This code has a few other heinous problems as well: Your use of goto for a simple loop, for example. A while() loop and a continue statement will do the trick, so use those. Never use goto when a regular loop construct will suffice just as well (or better); that's 99.9% of the cases.

Likewise, it makes no sense to me to put the seek code in the firing proc. Put it in the missile's own code instead:
obj/hmissile
> var/mob/owner
>
> New(newloc,mob/firedby)
> owner=firedby
> spawn(-1) Seek()
>
> proc/Seek()
> ...
> spawn(5) Seek()
>
> Bump(atom/obstacle)
> ... // explode

Lummox JR


Ill see what I can do about that as well.

Thanks for the help. I was beginning to wonder if anyone was ever going to help me on this.
In response to Jotdaniel
Jotdaniel wrote:
Lummox JR wrote:
That directional scanning code is intensely freaky; there has to be a better way of doing it than what you're doing with all those ifs.

Ive tried for awhile, and this was the only thing I could think of turn make sure it turned in the correct direction I was actually hoping someone would know a better way of doing this already because I agree with you, thats some freaky code.

Mathematically a good way to do it would be with dot products, but I don't consider that all that feasible; I've written up code on that before and it's a witch. Instead, fiddling with bit flags might be good. My understanding is that you basically want to turn right or left toward a target, and choose one direction or the other if the target is directly behind.

var/d=get_dir(src,target)
if(!d || d==dir)
// do nothing
else
var/right=turn(dir,-90)
if(dir&dir-1) // if current direction is diagonal
if(d==turn(dir,180)) // behind
// consider this either mostly north/south or mostly east/west
if(abs(x-target.x)>abs(y-target.y))
d&=12 // set d to EAST or WEST
else
d&=3 // set d to NORTH or SOUTH
// use XOR: If d matches a cardinal direction, the result
// is a single bit; otherwise it's 0 if d==right, and 2 or
// more bits if d isn't in this direction
right^=d
// n&(n-1) chops off the lowest "on" bit of a number
// which means you get 0 if n had only 1 bit to begin with
dir=turn(dir,right&right-1?45:-45) // turn left if right^d has 2+ bits
else // current direction is cardinal: NSEW
if(d==turn(dir,180)) // if behind
d=pick(right,0) // set this up for the next statement; turn at random
dir=turn(dir,d&right?-45:45)
That part with the bit flags on the diagonal should probably be explained: Any diagonal direction is a number with 2 bits turned on. For example, NORTHEAST is 5, for 1+4 (1=north, 4=east). Let's say that the current direction we're facing is northeast, so the direction 90° to the right is SOUTHEAST (6, 2+4). If the direction to target d is EAST (4), SOUTHEAST (6), or SOUTH (2), we want to turn right. Otherwise, since northeast (ahead) has already been accounted for and southwest will be changed to either south or west, the only other directions are all to the left: WEST (8), NORTHWEST (9), and NORTH (1).
Now, take 4, 6, or 2--the directions to the right--and XOR them with 6 (90° right); the result is 2, 0, or 4, each of which has only 1 bit or 0 bits turned on. However, for 8, 9, and 1 (all to the left), the results are 14, 15, and 7, each of which has not two but three bits turned on.

If the missile is facing in a cardinal direction, however, then it's easier. If you're facing north, then you turn right only if d is one of the eastward directions (d&EAST!=0), and so on; if d is behind the direction you're facing, then it's directly behind you (which isn't always true of the diagonals--hence the more complicated test) and you can simply pick a direction to turn at random.

Lummox JR
In response to Lummox JR
Thanks for trying to help. This is just a bit confusing for me. I'm gonna try and see if I can make out some of what that code does.