ID:264515
 
Problem description:
No compile issues. No run-time issues.
Players should be able to only block the mob infront of you.
My character is able to block from the sides or the back, it's crazy it's like he's Neo from the Matrix.

Extra Info:
The system uses q() + dir to block W/A/S/D directions.
A high block (Up) would block D(DownSlash),etc.
Defense has 50% automation (i.e you can block 2 directions with 1 button).

Code:
//Action States, Defense.           :#defines:

#define DEFLECT_N 1 // 0001
#define DEFLECT_S 2 // 0010
#define DEFLECT_E 4 // 0100
#define DEFLECT_W 8 // 1000
#define DEFEND 15 // 1111


//Blocking System                               :mob/player:

// toggle defending
start_defending()
if (state != STATE_NORMAL) return
else
state = DEFEND
old_state = icon_state
icon_state = "[icon_state] block"

stop_defending()
if (is_defending() )
state = STATE_NORMAL
icon_state = old_state

//checks if they're defending
is_defending()
world << output("Observing: [Attacker] from [Attack_In_Sight] is attacking [src] who is looking [src.dir]","output")
return is_deflecting() //call deflecting proc

is_deflecting(direction = DEFEND) //checks if they're deflecting
return state & direction //checks if they're deflecting specifically

//Override Move Proc
Move(newLoc, moveDir)
if(can_move)
if(state in list(STATE_NORMAL,STATE_RUNNING, KNOCK_BACK)) //havent needed it yet
if(world.time - move_delay >= last_move || moveDir != last_dir)
. = ..()
if(.)
last_move = world.time
last_dir = moveDir
else if(state == STRUGGLE)
var/oldDir = src.dir
. = ..()
src.dir = oldDir
// moveDir = 4 //EAST is what this would be set to if they are moving EAST
else if(is_defending() ) // they're defending
if(state & moveDir) return 0 //ATTACK's & DEFLECT's are linked to the same bit numbers. so in this SPECIFIC case means,
//if they are already blocking in the direction they are trying to then it doesnt need to be set. I see.
state &= ~DEFEND
state |= (moveDir & (moveDir-1)) //the deflections are 1, 2, 4, 8 (cardinal directions)
icon_state = getBlockState(moveDir)
//etc
getBlockState(d)
var/prefix = is_sheathed() ? "sheath_" : "unsheath_"
return "[prefix][dir2combatText(d)] block"

is_sheathed()
return (stance & (STANCE_NORMAL | STANCE_SWORD_SHEATHED))


proc/dir2combatText(d)                     :proc:
switch(d)
if(NORTH) return "high"
if(SOUTH) return "low"
if(EAST) return "right"
if(WEST) return "left"


//Offense & etc                    :mob/player:


attackloop(var/mob/target)
while(target && attack(target))
sleep(1)
attack(var/mob/player/victim)
victim = victim || locate(/mob) in get_step(src,src.dir)
if(!victim) return 0
var/attackDamage = basedamage //prime.execution
var/isBlocking = victim.auto_block(src.attack)
if(isBlocking)

if(victim.is_beside(src)) return
var/effect/symbols/block_party = new(src); flick("block_party", block_party)
attackDamage /= 2
victim.icon_state = "[victim.getBlockState(isBlocking)]"
world << output("blocked [dir2combatText(src.attack)] with [dir2combatText(victim.is_defending())]","output")
return

if(stance == STANCE_SWORD_UNSHEATHED) //sets up condition secondary execution
apply_PowerUps()
attackDamage = damage //condition & damage calc set up

victim.take_damage(attackDamage, src) //execution halted and damage calc overridden in/if block_left()
victim << output("You take [attackDamage] damage! from [src].","output2")
src << output("You hit [victim] for [attackDamage]!","output2")

take_damage(damage, atom/source)
health = max(health - damage, 0)
world << output("Fighting!: [damage] done should match [source]","output2")
if(src.client) src.client.hud.refreshHPBars()
death_check(source)
//are you still here?
apply_PowerUps()
var/item/sword/sword = new /item/sword
world << output("[src]","output2")
src.damage = sword.weapon_damage + src.basedamage
world << output("[damage] = [sword.weapon_damage] and [basedamage]","output2")

auto_block(var/attackDir,attacker) //automation detector
var/blockDir = is_defending()
if(blockDir == DEFEND) return //FIX for phantom bug
world << output("attackDir[attackDir] && blockDir[blockDir]","output2")
return (blockDir) ? attackDir & (blockDir | turn(blockDir, 180)) : 0



Debug:


// if(!blockDir == locate(/mob) in get_step(src,src.dir)) return in "autoblock"

// if(src.is_beside()) return
// if(!Attacker in get_step(src,src.dir)) return in "is_defend()"
//                                              :mob/player:
is_beside(var/mob/M)
return (get_dir(M, src) == turn(M.dir, 90) || get_dir(M, src) == turn(M.dir, -90) )


Will not work.
Where are the lines in that snippet that you posted that won't work ? I see the is_beside() one, but we would need the proc to actually work it out, because the proc isn't in that snippet.
You are passing arguments to is_defending(), but is_defending() does not take any arguments (and therefore does not pass them to is_deflecting(), which DOES take an argument). I assume this results in players always defending as if their state is DEFEND, which defends against everything.
In response to Garthor
Garthor wrote:
You are passing arguments to is_defending(), but is_defending() does not take any arguments (and therefore does not pass them to is_deflecting(), which DOES take an argument). I assume this results in players always defending as if their state is DEFEND, which defends against everything.

Forgot to erase that,[used for AttackDir/Attacker] part of debugging. /update

Andre-g1 wrote:
Where are the lines in that snippet that you posted that won't work ? I see the is_beside() one, but we would need the proc to actually work it out, because the proc isn't in that snippet.

This was sort of like some last resort, tactic. >.> /update
//                                              :mob/player:
is_beside(var/mob/M)
return (get_dir(M, src) == turn(M.dir, 90) || get_dir(M, src) == turn(M.dir, -90) )


Then I tried to break it down into.

is_beside(var/mob/M)        
var/mob/Z = loc
if(!istype(Z)) return
if(get_dir(M, src) == turn(M.dir, 90))// || get_dir(M, src) == turn(M.dir, -90) )
world<< output("<font color = red>WOOOOW</font color = red>","output")
return 1
else
world<< output("<font color = red>WTF??</font color = red>","output")
world<< output("<font color = red>[M],[src],[M.dir]...[get_step(M, src)]==[turn(M.dir, 90)]</font color = red>","output")
return 0



I would get "WTF" -_-. Matter of fact, the actual line would translate into "grass == 8" via world output .



In response to Hulio-G
Try the following.

is_beside(var/mob/M)        
var/mob/Z = loc
if(!istype(Z)) return
if(get_dir(M, src) == turn(M.dir, 90)) || get_dir(M, src) == turn(M.dir, -90) )
world<< output("<font color = red>WOOOOW</font color = red>","output")
return TRUE
else
world<< output("<font color = red>WTF??</font color = red>","output")
world<< output("<font color = red>[M],[src],[M.dir]...[get_step(M, src)]==[turn(M.dir, 90)]</font color = red>","output")
return FALSE

In response to Andre-g1
Andre-g1 wrote:
Try the following.

> is_beside(var/mob/M)      
> var/mob/Z = loc
> if(!istype(Z)) return
> if(get_dir(M, src) == turn(M.dir, 90)) || get_dir(M, src) == turn(M.dir, -90) )
> world<< output("<font color = red>WOOOOW</font color = red>","output")
> return TRUE
> else
> world<< output("<font color = red>WTF??</font color = red>","output")
> world<< output("<font color = red>[M],[src],[M.dir]...[get_step(M, src)]==[turn(M.dir, 90)]</font color = red>","output")
> return FALSE
>


Okay, I retraced events and whenever I added these lines, I would stop getting output.

>     var/mob/Z = loc
> if(!istype(Z)) return


This one below however(same as 0 and 1), would give me "The testNPC, Hulio-G, 1...The grass==8" no matter which direction I was facing.
> is_beside(var/mob/M)      
> if(get_dir(M, src) == turn(M.dir, 90)) || get_dir(M, src) == turn(M.dir, -90) )
> world<< output("<font color = red>WOOOOW</font color = red>","output")
> return TRUE
> else
> world<< output("<font color = red>WTF??</font color = red>","output")
> world<< output("<font color = red>[M],[src],[M.dir]...[get_step(M, src)]==[turn(M.dir, 90)]</font color = red>","output")
> return FALSE
>
In response to Andre-g1
That is, in fact, exactly the same as what he wrote.
In response to Hulio-G
You got your logic mixed up at some point. is_beside is called as victim.is_beside(src) with src being the attacker. The goal is to see whether the attacker is to the left or to the right of the victim.

In is_beside(), src is the victim and M is the attacker. But, you are checking if src is standing to M's left or right. The solution (to keep is_beside() making sense) is to call src.is_beside(victim) instead.
In response to Garthor
Garthor wrote:
You got your logic mixed up at some point. is_beside is called as victim.is_beside(src) with src being the attacker. The goal is to see whether the attacker is to the left or to the right of the victim.

In is_beside(), src is the victim and M is the attacker. But, you are checking if src is standing to M's left or right. The solution (to keep is_beside() making sense) is to call src.is_beside(victim) instead.

Awesome. ;P

Image Hosted by ImageShack.us
In response to Garthor
Hm no.

What he had was only checking for turn(dir,90) while it should be checking for both 90 and -90.