ID:2790588
 
Code:
mob     
proc
Damage()
//Rest of the proc, which works fine if I remove this bit. Will provide if necessary.
if(prob(100/15))
var/done = 0
var/injuryraffle = rand(1,100)
if(prob(80))
for(var/obj/Bodypart/Arm/C in B)
if(prob(50) && !done && C.equipped) // Want to choose one arm at random, only 1 arm, and be sure it isn't some random OTHER arm you've picked up. Gotta be your own actual arm.
if(injuryraffle <= 80)
C.Light += 1
C.Injuries += 1
if(!C.Recovering) // Want to avoid having the same proc running multiple times.
C.Recovering = 1
C.InjurySystem()
if(injuryraffle > 80 && injuryraffle <= 95)
C.Medium += 1
C.Injuries += 1
if(!C.Recovering)
C.Recovering = 1
C.InjurySystem()
if(injuryraffle > 95 && injuryraffle <= 99)
C.Heavy += 1
C.Injuries += 1
if(!C.Recovering)
C.Recovering = 1
C.InjurySystem()
if(injuryraffle == 100)
C.Critical += 1
C.Injuries += 1
if(!C.Recovering)
C.Recovering = 1
C.InjurySystem()
done = 1
else
for(var/obj/Bodypart/Torso/C in B)
if(C.equipped)
if(injuryraffle <= 80)
C.Light += 1
C.Injuries += 1
if(!C.Recovering)
C.Recovering = 1
C.InjurySystem()
if(injuryraffle > 80 && injuryraffle <= 95)
C.Medium += 1
C.Injuries += 1
if(!C.Recovering)
C.Recovering = 1
C.InjurySystem()
if(injuryraffle > 95 && injuryraffle <= 99)
C.Heavy += 1
C.Injuries += 1
if(!C.Recovering)
C.Recovering = 1
C.InjurySystem()
if(injuryraffle == 100)
C.Critical += 1
C.Injuries += 1
if(!C.Recovering)
C.Recovering = 1
C.InjurySystem()
DeathCheck()



obj
Bodypart
proc
InjurySystem()
while(Recovering)
if(Light) LightRecovery += rand(2,3)
if(LightRecovery >= 100)
Light -= 1
Injuries -= 1
LightRecovery = 0
if(Fatal)
if(prob(10)) FatalMagnitude += 1
var/damage = (Light + (Medium * 3) + (Heavy * 5) + (Critical * 30) + (Fatal * FatalMagnitude))
condition = 100 - damage
if(condition < 0) condition = 0
if(condition == 0)
Recovering = 0
Destruction()
if(Injuries == 0) Recovering = 0
sleep(50)

Destruction()
usr << "Oops." // Gonna finish this up later.


Problem description:

I have a perfectly functioning combat system, prior to adding this in. The problem is that after adding this in, mobs will freeze in place after dealing 1 injury to the player. I've done some testing and it seems like whatever the problem is has to do with what I'm sharing here. I could be wrong though, and will provide other possibly relevant pieces of code if nobody can help me with what I've already provided.
I'd check InjurySystem() and make sure it's breaking out of that while(Recovering).

It's called in Damage() which I assume happens once before InjurySystem() is called and it becomes locked waiting for that while to finish.

[edit] A fast way to see if this is the case is to remove the sleep() in the while loop and if your game freezes up you know the issue lol.

[2nd edit] something I'm curious about is that you're looping through bodyparts inside of B is that a variable defined for the mobs? Just curious lol.

[3rd edit] Here's another way you can write it too, just to help.

mob/proc/Damage()
if(!prob(100/15)){return FALSE} // Missed!
var injuryraffle = rand(1,100)
var obj/Bodypart/bp
if(prob(80))
bp = locate(/obj/Bodypart/Arm) in B
else
bp = locate(/obj/Bodypart/Torso) in B
if(!bp){return FALSE} // No Bodypart Found
switch(injuryraffle)
if(100)
bp.Critical += 1; bp.Injuries += 1
if(96 to 99)
bp.Critical += 1; bp.Injuries += 1
if(80 to 95)
bp.Critical += 1; bp.Injuries += 1
else
// Anything less than 80
bp.Critical += 1; bp.Injuries += 1
if(!bp.Recovering){bp.Recovering = 1; bp.InjurySystem()}
DeathCheck()
Thanks, realized it was because the mob was waiting on InjurySystem to conclude before continuing. Added spawn() in front of all those C.InjurySystem()s and now I'm being murdered properly again.

And to your second edit; yeah. Copied+Pasted the main body, wrote out mob/proc/Damage manually. Forgot (mob/A,mob/B,dmg,bypass). Sorry for the confusion.

Appreciate the help, always cool to learn better ways to format my code.
If the proc isn't finishing and you're spawn()'ing it, eventually the server/game will crash.

You'll need to make sure while(Recovering) ends.
That while(Recovering) is meant to keep the proc running as long as the body part in question is still injured, so that the "condition" var is accurately kept up to date. The condition var is meant to affect the damage output of associated body parts; punches do less damage with injured arms, etc.

The loop should come to a close when a player goes out of their way to address their wounds by visiting a doctor NPC or player with medical skills.

Is there a better way to handle this than with a spawn()?
In response to Lawpiecla1
The simple problem was that Damage() waited for InjurySystem() to finish, and presumably your NPC controller waited for Damage() to finish before continuing. The simplest solution is to spawn() the blocking proc. I agree with this for simplicity's sake, but there are (and basically always will be) alternatives that are more powerful but more complex. I wouldn't worry about that, especially at the stage where things aren't totally working yet.

Crashing happens to infinite recursion loops that grow the call stack out of control, not to infinite while() or for() loops that sleep every iteration. It's not a problem here.

However, there is one major issue with how you prevent stacked loops. When you get injured in the 5 seconds after Recovering = 0, you'll start another loop and the old loop will continue because Recovering isn't 0 when it's checked after the 5 seconds are up.

The way I like to prevent loop stacking is to separate "should the loop continue" from "is the loop running":
// start the loop if it's not already running
should_loop = TRUE
if(!is_looping)
is_looping = TRUE // only right before the loop actually starts
while(should_loop)
// do stuff
is_looping = FALSE // only right after the loop actually stops

In your case, should_loop is Recovering. You just need to add another variable dedicated to whether the loop is running.