ID:315290
 
(See the best response by DarkCampainger.)
I need to explain how my shots in my game works first.
You can shot the monsters clicking with your mouse(what else it could be?) and by pressing F.
The damage is based in which pixel of the zombie you hit.

Now the problem:
I decide to make 2 vars(pixelx and pixely) and use pick to make the shot, but I realize that will not work.
If I shot the pixel 7,21 of the zombie it's a head shot and the pixel 3,11 it's a normal-damage shot.
If I do this:
pixelx = pick(3,7)
pixely = pick(11,21)


I have a chance of shot the pixel 3,21, which is nothing. But it's worse. Because of my shot proc:
        shot(mob/m,dire,pixelx,pixely)
if(dire == SOUTH || dire == NORTH)

if((pixelx>8 && pixelx<12) && (pixely>20 && pixely<28))
damage(m,0,50) // This second number is a damage that ignore target's defense

else if((pixelx>4 && pixelx<12) && (pixely>2 && pixely<10))
damage(m,rand(5,10))
if(prob(70)) m.move_speed = 1 //I'm using F_A's pixel movement

else damage(m,rand(7,15))

else if(dire == EAST || dire == SOUTHEAST || dire == NORTHEAST)

if((pixelx>2 && pixelx<10) && (pixely>20 && pixely<28)) damage(m,0,50)

else if((pixelx>4 && pixelx<9) && (pixely>2 && pixely<9))
damage(m,rand(5,10))
if(prob(70)) m.move_speed = 1

else damage(m,rand(7,15))
else

if((pixelx>7 && pixelx<15) && (pixely>20 && pixely<28)) damage(m,0,50)

else if((pixelx>8 && pixelx<9) && (pixely>2 && pixely<13))
damage(m,rand(5,10))
if(prob(70)) m.move_speed = 1

else damage(m,rand(7,15))


It will counted as a headshot and kill the monster.
The only way to avoid this is assign the 3,11 or 7,11 together. I thought about using a list, but I don't know how to do this.

...I just notice I didn't need to make this whole text just to ask that...
Instead of trying to randomly generate values that will be in the ranges your want, why not choose three pixel_x/y pairs that will result in each of the different types of hits, and then use prob() and/or pick() to just set it to one of those?

Another alternative would be to rewrite your shot process to handle both contexts:
For an actual click, use the pixel_x/y locations.
For shots fired with 'F', use probabilities.
In response to DarkCampainger
DarkCampainger wrote:
Instead of trying to randomly generate values that will be in the ranges your want, why not choose three pixel_x/y pairs that will result in each of the different types of hits, and then use prob() and/or pick() to just set it to one of those?

This is exactly what I want, but I don't know how to assign these pairs.
I can't make a var hold 3,7 and then use 3 and 7 separately, can I?
In response to Gland Mopa
Nothing wrong with an if-else chain for 3 values:
if(prob(20)) // 20% chance for headshot
pixelx = 9
pixely = 24
else if(prob(40)) // 32% chance for leg-shot (remaining 80% * 40%)
pixelx = 8
pixely = 6
else // 48% chance for body-shot
pixelx = 8
pixely = 16


Also, for your third-direction set in shot(), this will never be true:
if((pixelx>8 && pixelx<9) // ...

I think you forgot to update the '9' to something larger. Also, for my code above to work for all directions, you'll have to change that pixelx>8 to a pixelx>=8, otherwise there is no single pair that works for all directions.
Best response
However, I would suggest something more like this:

#define HIT_TORSO 1
#define HIT_LEGS 2
#define HIT_HEAD 3

mob
var
health = 100
armor = 4

verb
Shoot(mob/m in view(8, src))
var/hitType = pick(HIT_TORSO, prob(30);HIT_LEGS, prob(15);HIT_HEAD)
m.GetShot(src, hitType)

Click(l, c, p)
var
list/params = params2list(p)
pixelx = params["icon-x"]
pixely = params["icon-y"]

var/hitType = src.GetHitLocation(pixelx, pixely)
src.GetShot(usr, hitType)

proc
GetHitLocation(pixelx, pixely)
if(src.dir == SOUTH || src.dir == NORTH)
if((pixelx>8 && pixelx<12) && (pixely>20 && pixely<28))
return HIT_HEAD

else if((pixelx>4 && pixelx<12) && (pixely>2 && pixely<10))
return HIT_LEGS

return HIT_TORSO

else if(src.dir == EAST || src.dir == SOUTHEAST || src.dir == NORTHEAST)

if((pixelx>2 && pixelx<10) && (pixely>20 && pixely<28))
return HIT_HEAD

else if((pixelx>4 && pixelx<9) && (pixely>2 && pixely<9))
return HIT_LEGS

return HIT_TORSO

else // WEST, SOUTHWEST, NORTHWEST

if((pixelx>7 && pixelx<15) && (pixely>20 && pixely<28))
return HIT_HEAD

else if((pixelx>8 && pixelx<9) && (pixely>2 && pixely<13))
return HIT_LEGS

return HIT_TORSO

GetShot(mob/attacker, hitType)
switch(hitType)
if(HIT_TORSO)
src.TakeDamage(attacker, rand(7,15))
if(HIT_LEGS)
src.TakeDamage(attacker, rand(5,10))
if(prob(70)) src.move_speed = 1
if(HIT_HEAD)
src.TakeDamage(attacker,0,50)

TakeDamage(mob/attacker, damage=0, critical=0)
if(src.health > 0)
src.health -= max(damage - src.armor, 1) + critical
src.DeathCheck(attacker)

DeathCheck(mob/killer)
if(src.health <= 0)
world<<"[src.name] was killed by [killer.name]"
del(src)


This way things are nice and organized, and easier to maintain. I also reversed the ownership on the Shot() and damage() processes, so the mob being attacked is the src.
In response to DarkCampainger
Thank you! *smack*