ID:1359199
 
(See the best response by Kaiochao.)
Code:
Projectile
parent_type = /obj
density = 0
Grabbable = 0
Attackable = 0
// copy stats
var
BP = 0
Strength = 0
Force = 0
Accuracy = 0
Agility = 0
dmgMulti = 0
mob/maker


New(mob/ref)
if(!ismob(ref)) del src
..(ref)
position(ref)
set_vars(ref)
spawn() life()



proc
position(atom/movable/m, s = 16)
loc = m.loc
dir = m.dir
var x = m.step_x, y = m.step_y
if(m.dir & NORTH) y += s
if(m.dir & SOUTH) y -= s
if(m.dir & WEST) x -= s
if(m.dir & EAST) x += s
step_x = x
step_y = y

collide(atom/a)
var mob/m = a
if(ismob(m))
if(m.blasted(src))
return
del src


set_vars(mob/c)
BP = c.BP
Strength = c.Strength
Force = c.Force
Accuracy = c.Accuracy
Agility = c.Agility
maker = c.real_name

life()
for()
sleep(1)
step(src, src.dir)

Cross(atom/a)
var Projectile/b = a
if(istype(b))
if(b.maker != maker)
return 0
return 1
return ..(a)

Move()
. = ..()
if(dir & NORTH) if(y == world.maxy) del src
if(dir & SOUTH) if(y == 1) del src
if(dir & WEST) if(x == 1) del src
if(dir & EAST) if(x == world.maxx) del src

Bump(atom/a)
. = ..(a)
collide(a)

Blast
dmgMulti = 0.5
step_size = 32
Standing = 1
bound_x = 11
bound_y = 12
bound_width = 11
bound_height = 7
density = 1
icon = 'Blast1.dmi'

Beam
step_size = 32
icon = 'Beam1.dmi'
icon_state = "Tail"
density = 1

New(l, obj/Skills/Beam/s)
..(l)
var mob/m = s.loc
dir = m.dir
maker = m.key
if(ismob(m)) position(m, 32)
set_vars(m)
spawn() life()
spawn() pickState()

collide(atom/a)
// insert damage instructions
del src


life()
spawn() walk(src, dir, 1)

proc
pickState()
while(src)
var Projectile/Beam/headTest = locate(/Projectile/Beam) in get_step(src, dir)
var Projectile/Beam/tailTest = locate(/Projectile/Beam) in get_step(src, oppositeDir(dir))
if(istype(headTest)) if(headTest.maker != maker) headTest = null
if(istype(tailTest)) if(tailTest.maker != maker) tailTest = null
if(!istype(headTest)) icon_state = "Head"
else if(!istype(tailTest)) icon_state = "Tail"
else icon_state = "Body"
sleep(1)


Problem description:

Hey guys, I've been working on a projectile system, and I'm running into a bit of an issue..

When beams are being shot, in some cases the pickState() proc isn't applying the proper icon_state to the projectile. This seems to ONLY be happening when shooting a beam to the north, or to the east. When shooting it south or west, it always does just fine. In some rare positions, or instances, I haven't isolated it.. shooting it north or east works momentarily, but then it quits after moving.

Tail is at the back of the beam, Body is anything not at the front or back, and Head is the leading beam object.

Anyone have a clue what's wrong with the logic here?


Edit: Here's oppositeDir()

proc
oppositeDir(d) // d == dir
if(d == NORTH) return SOUTH
if(d == SOUTH) return NORTH
if(d == EAST) return WEST
if(d == WEST) return EAST
if(d == NORTHWEST) return SOUTHEAST
if(d == NORTHEAST) return SOUTHWEST
if(d == SOUTHWEST) return NORTHEAST
if(d == SOUTHEAST) return NORTHWEST
After screwing around with things, I've started to figure out the issue. When step_x is greater than 0, east quits working properly. When step_y is greater than 0, north quits working properly. It seems that locate() in list() isn't ideal here, wondering what to do beyond this point.
istype() takes 2 arguments. It checks if one instance is derived from another type or another instance. I'm not sure if that's really what you want to do there or not.

Edit: Nevermind. Your istype() is using an implicit type. It's hard to trace what's going on there.


Also, since directions are actually constant values:
NORTH == 1
SOUTH == 2
EAST == 4
WEST == 8
NORTHEAST == 5
NORTHWEST == 9
SOUTHEAST == 6
SOUTHWEST == 10


A much more efficient proc would be this:
proc
oppositeDir(d) // d == dir
switch(d)
if(1)//NORTH
return SOUTH
if(2)//SOUTH
return NORTH
if(4)//EAST
return WEST
if(8)//WEST
return EAST
if(5)//NORTHEAST
return SOUTHWEST
if(9)//NORTHWEST
return SOUTHEAST
if(6)//SOUTHEAST
return NORTHWEST
if(10)//SOUTHWEST
return NORTHEAST

This should be lightning fast compared to the original. switch() can be very powerful if you know how to use it. I think this is a necessary improvement, since you have already gone as far as to use bitwise operations. You might want to add more comments to your code, just to make things more readable and easier to debug.
In response to Multiverse7
istype() also checks the type of the variable, so if the variable is typed as you're checking for, the 2nd type may be safely omitted :)

I was just thinking to do that earlier! My hesitance has to do with me not remembering the values for each macro too well, but I see your point. With this kind of stuff, performance is really important since it's likely to be running a lot of times, so those changes add up quite a bit. I'll make that change for the sake of being cool.

Now I just need to figure out how to better check the locations, since pixel movement is throwing it off at times.
In response to Multiverse7
Best response
I think a pretty decent "opposite dir" proc would be:
turn(dir, 180)
Well, I fixed it by making these procs and replacing get_step()

atom
movable
proc
inFront(d) // step_size
var x = 0, y = 0
if(dir & 1) y += d
if(dir & 2) y -= d
if(dir & 4) x += d
if(dir & 8) x -= d
return obounds(src, x, y)


inBack(d) // step_size
var x = 0, y = 0
if(dir & 1) y -= d
if(dir & 2) y += d
if(dir & 4) x -= d
if(dir & 8) x += d
return obounds(src, x, y)


Any performance upgrades you guys have in mind?

Edit: The indentation looks off here, gonna fix that (I manually typed the path)

I thought about turn() as well, it may be even faster than my version here.
In response to Kaiochao
For some reason, turn() never crossed my mind. Since it's built-in, it more than likely blows anything we could make right out of the water, and since it can turn in any direction, I would definitely use that instead.