ID:2091645
 
(See the best response by Rotem12.)
Code:
attack(mob/M as mob in oview(1)) //attack a mob within 1 tile of you
usr << "You attack [M]!" //send this message to the usr
oview() << "[usr] attacks [M]!" //send this message to everybody else
var/damage = rand(1,10) //assign a random # to a new variable
world << "[damage] damage!" //tell the damage to the world
M.HP -= damage //take away the damage from M


Problem description: I got the above code from the zbt tutorial which works fine but I'd like to modify it a bit by attacking a mob only if its 3 tiles above (x same, y + 3). So, maybe I will have to replae oview(1) with something else but I don't know what...
Thanks

Best response
Someone asked a similar question a few posts ago, take a look at this:

http://www.byond.com/forum/?post=2090200

If you want it to always be 3 tiles above regardless of direction you're facing, you can use locate(x, y+3, z) to grab the turf 3 tiles above.

So the code would change to:
mob/verb/Attack()
if(busy) return // just a generic is-busy check
busy |= BUSY_ATTACKING
spawn(2) busy &= ~BUSY_ATTACKING

for(var/mob/M in locate(x, y+3, z))
//stuff
Seems good, I get x, y, z undefined vars though, how can I pass the current position of the player?
if Attack() is defined under mob, it should have x, y and z.

What did you define Attack() verb under?
@Rotem: Your code won't work for what the question asked. EDIT: Wait... Nevermind, I misread the question. My bad. 3 tiles above, not attack 3 tiles at once. Sorry.

Unfortunately because I misread the question, the below code is applicable, but not exactly: The below is for attacking a 3x3 tile area at one time. Sorry. I'll leave it here because it's useful, but I'm totally off on it being an answer to this question... Where is my coffee?

You want to use modern DM features to acheive this. Specifically, obounds(). We need to adjust by the bounding area of the movable that is attacking, and we also need to adjust the location of the bounding area according to both the bounding size and the direction that is being faced, all taking into account the current and final size of the bounding box.

mob/verb/Attack()
if(busy) return // just a generic is-busy check
busy |= BUSY_ATTACKING

var/ox,oy,ow = TILE_WIDTH*3-bound_width, oh = TILE_HEIGHT*3-bound_height

if(dir&NORTH) //offset the bounding box vertically northward
oy = bound_height
else if(dir&SOUTH) //offset the bounding box vertically southward, taking into account the final size.
oy = -bound_height-TILE_HEIGHT*3
else //center the bounding box vertically
oy = oh/-2

if(dir&WEST) //offset the bounding box horizontally westward taking into account the final size.
ox = -bound_width-TILE_WIDTH*3
else if(dir&EAST) //offset the bounding box horizontally eastward
ox = bound_width
else //center the bounding box horizontally
ox = oh/-2

for(var/mob/M in obounds(src,ox,oy,ow,oh))
//stuff
sleep(2)
busy &= ~BUSY_ATTACKING


Since this is such a general pattern, I keep it around in a global function called: reach()

proc/reach(ref,dir,rw,rh)
if(!dir) dir = ref.dir
var/bw = ref.bound_width, bh = ref.bound_height
var/ow = rw-bw, oh = rh-bh

var/oy = dir&NORTH ? bh : dir&SOUTH ? -bh-oh : oh/-2
var/ox = dir&EAST ? bw : dir&WEST ? -bw-ow : ow/-2

return obounds(ref,ox,oy,ow,oh)


This would simplify your attack function to:

mob/verb/Attack()
if(busy) return // just a generic is-busy check
busy |= BUSY_ATTACKING
for(var/mob/M in reach(src,dir,TILE_WIDTH*3,TILE_HEIGHT*3))
//stuff
sleep(2)
busy &= ~BUSY_ATTACKING