ID:1298136
 
(See the best response by Super Saiyan X.)
Code:
var/list/Menu = list()
var/turf/Td = locate(M.x,M.y,M.z)
var/turf/T = locate(M.x+4,M.y,M.z)
var/turf/T1 = locate(M.x-4,M.y,M.z)
var/turf/T2 = locate(M.x,M.y+4,M.z)
var/turf/T3 = locate(M.x,M.y-4,M.z)
var/turf/T4 = locate(M.x+3,M.y+3,M.z)
var/turf/T5 = locate(M.x-3,M.y+3,M.z)
var/turf/T6 = locate(M.x-3,M.y+3,M.z)
var/turf/T7 = locate(M.x-3,M.y-3,M.z)
if(T)
if(!T.density)
if(T in view(M))
Menu.Add(T)
if(T1)
if(!T1.density)
if(T1 in view(M))
Menu.Add(T1)
if(T2)
if(!T2.density)
if(T2 in view(M))
Menu.Add(T2)
if(T3)
if(!T3.density)
if(T3 in view(M))
Menu.Add(T3)
if(T4)
if(!T4.density)
if(T4 in view(M))
Menu.Add(T4)
if(T5)
if(!T5.density)
if(T5 in view(M))
Menu.Add(T5)
if(T6)
if(!T6.density)
if(T6 in view(M))
Menu.Add(T6)
if(T7)
if(!T7.density)
if(T7 in view(M))
Menu.Add(T7)
if(Menu)
src.shunning=1
var/turf/x1 = pick(Menu)//this is the probelm
var/obj/afterImage/afterImage2 = new /obj/afterImage()
afterImage2.layer = MOB_LAYER
afterImage2.icon=src.icon
afterImage2.icon_state=src.icon_state
afterImage2.overlays=src.overlays
afterImage2.underlays = src.underlays
afterImage2.dir=src.dir
afterImage2.loc = src.loc
afterImage2.illusion = 1
flick("shun",afterImage2)
flick("shun",src)
src.Move(x1)
if(!Menu)
src.Move(Td)
return
if(src.loc==null)src.Move(Td)


Problem description:

runtime error: pick() from empty list
proc name: FlashStepNPC (/mob/proc/FlashStepNPC)
source file: AI.dm,646

Why is this error occuring if I'm use the "if(Menu)" before proceeding. What would be a better way of doing this?
You might want to do a length check on the if(Menu)

if(length(Menu))
Best response
To be more explicit:

if(Menu) simply checks if the list object exists - it can exist AND be empty.

However, there are two ways to get a list's length -
length(list)
//and
list.len

Every properly defined list has a len variable. Lists are objects, so.

From my testing, .len is faster than length() (shouldn't really matter though); so you'd want to do:

if(Menu && Menu.len) //if the list exists AND it has contents


That if(!Menu) should just be an else clause, really.
Hmm, I would like to know if I am wrong or not.

Wouldn't this have the same result instead of all those IFs ?

        if(T && !T.density && T in view(M))
Menu.Add(T)


Also there's something bothering me, isn't the NPC finding it all at the same time if all those are true ? Or this supposed to do ? If not, would this be a better option ?

        if(T && !T.density && T in view(M))
Menu.Add(T)
else if(T1 && !T1.density && T1 in view(M))
Menu.Add(T1)


And like Super Saiyan X said in that if(!Menu) line

        else
src.Move(Td)
return


I believe this is the same as this:

if(src.loc == null)

//Is the same as

if(!src.loc)


But tell me if I am wrong, well it's the same result but it looks cleaner to me :|...
You are correct on most parts, Yasu. All of those if statements /can/ be combined, however, for the last statement it'd have to be in parenthesis:
if(T && !T.density && (T in view(M)))



and yes, src.loc == null is the same as !src.loc.
Thank you for confirming it, mind explaining why it needs to be in parenthesis ? I appreciate it!

Also Crit, I've shorten it a bit. I would try to make it a little better, but nothing comes to my mind atm..

        var
mob/M = src
list/Menu = list()
turf/Td = locate(M.x,M.y,M.z)
turf/T = locate(M.x+4,M.y,M.z)
turf/T1 = locate(M.x-4,M.y,M.z)
turf/T2 = locate(M.x,M.y+4,M.z)
turf/T3 = locate(M.x,M.y-4,M.z)
turf/T4 = locate(M.x+3,M.y+3,M.z)
turf/T5 = locate(M.x-3,M.y+3,M.z)
turf/T6 = locate(M.x-3,M.y+3,M.z)
turf/T7 = locate(M.x-3,M.y-3,M.z)
if(T && !T.density && T in view(M))
Menu.Add(T)
else if(T1 && !T1.density && (T1 in view(M)))
Menu.Add(T1)
else if(T2 && !T2.density && (T2 in view(M)))
Menu.Add(T2)
else if(T3 && !T3.density && (T3 in view(M)))
Menu.Add(T3)
else if(T4 && !T4.density && (T4 in view(M)))
Menu.Add(T4)
else if(T5 && !T5.density && (T5 in view(M)))
Menu.Add(T5)
else if(T6 && !T6.density && (T6 in view(M)))
Menu.Add(T)
else if(T7 && !T7.density && (T7 in view(M)))
Menu.Add(T7)
if(Menu && Menu.len)
src.shunning = 1
var/turf/x1 = pick(Menu)
var/obj/afterImage/afterImage2 = new /obj/afterImage()
afterImage2.layer = MOB_LAYER
afterImage2.icon = src.icon
afterImage2.icon_state = src.icon_state
afterImage2.overlays = src.overlays
afterImage2.underlays = src.underlays
afterImage2.dir = src.dir
afterImage2.loc = src.loc
afterImage2.illusion = 1
flick("shun",afterImage2)
flick("shun",src)
src.Move(x1)
else
src.Move(Td)
return
if(!src.loc)
src.Move(td)
if I recall correctly, the in operator has the lowest order of precedence - it happens towards the end in any operations. Basically, to the compiler the operation would look like this: (I think)

if(((T1 && !T1.density) && T1) in view(M))


So, you have to force the compiler to see T1 in view(M) as a single statement.
Very well explained! Didn't know in operator would affect this much.
Well if you don't mind semi-convoluted code:

    var/list/turfs = list()
var/d = NORTH
var/turf/t
for(var/i = 0, i < 8, ++i)
t = get_steps(loc, d, d&(d-1) ? 3 : 4)
if (t && !t.density && (t in view(M))) turfs += t
d = turn(d, 45)


is probably better than those repeated if() statements, and I'm pretty sure that's the pattern of turfs you want.

get_steps looks like this:

proc/get_steps(ref, dir, n)
. = ref
for(var/i = 0, i < n, ++i) . = get_step(., dir)
haha, Jp, I was gonna suggest another way of doing that...my way was silly though.