ID:1513268
 
Hi. I'm trying to add a NPC combat system. The problem is, every way I've thought about adding it is on a loop, which would take a lot of the CPU usage. Does anyone perhaps know a way I could go about adding a NPC combat system without putting it on a loop. The way I want it to be is, the NPC will stand where it spawns until someone walks by, at which point the NPC will attack that person. After the person dies or walks out of the range of the NPC attack(5 tiles), it returns to where it spawed, and repeats the cycle all over again when someone else walks by. Any help on this would be greatly appreciated.
You can use a npc.wake() command every time someone moves. For example:

mob/npc/proc/Wake()
if(awake) return
begin_attack_routine()

mob/player/Move()
..()
for(var/mob/npc/x in viewers(5))
if(istype(x))
spawn(0) x.Wake()
Wouldn't searching for NPCs in your view every time you move also cause an issue?
Any piece of code has rewards and payoffs, that is exactly why profiling code is important.

In this case, I believe that the looping every mob vs every player walk is the safer option performance-wise.
The way I understand your code example now is, a player that walks within 5 steps of the NPC will cause the NPC to attack the player. The problem before was I couldn't get the NPC to follow and attack the person without putting it on a loop. Your code example does help remove some of the code for finding the person to attack out of the combat proc, but it doesn't fully tackle the problem.
Perhaps taking a look at what I already have will help.
proc
wake()
if(awake) return
combatproc()
awake=1

combatproc()
while(awake)
if(dead)return
walk(src,0)
for(var/obj/Safe_Zone/G in loc)goto peace
if(worldpeace)goto peace
var/K=0
for(var/mob/M in oview(8,src))
if(paralysed||M.isiron||M.ispuppet||M.isanimal&&!M.aggressive||village==M.village&&!M.pktoggle||village==M.tmpvillage&&!M.pktoggle||M.name=="Tree")continue
K=1
var/Z=0
if(y==M.y||x==M.x)Z=1
if(Z&&prob(50))
M.faceme2(src)
if(prob(75))
flick("attack",src)
var/obj/breakable/Kunai/L=new()
L.owner=src
walk(L,dir)
else substitution()
else
var/c=100
for(var/mob/G in oview(2,src))if(G==M)c=80
if(prob(c))
walk_to(src,M,1)
for(var/mob/G in oview(1,src))if(G==M)walk_towards(src,M)
else stepback(3)
break
peace
if(!K)step_rand(src)
I added the wake thing to it. The current combat proc makes it lag so bad that I can't even load the game, which is what I am trying to fix
You're going to want some sort of delay between the loop otherwise it runs too often.

Is this the only loop you're using? There is nothing wrong with loop code, as long as the work is valid. It is a very powerful coding concept. If the delay isn't there though, it will cause performance issues.

Please take note, The goto [label] is a bad code design method, and can be avoided by using proper logic within loops and control structures - this gives much more readable code as our brains are not wired for skipping around.
I agree with Pirion that is loop is actually going to be your friend here. You just need to use delays between iterations to save on performance.

While we are talking about delays, consider this. It's possible to adjust the length of delay between each check based on the proximity of things found that the NPC needs to react to.

For instance, if there no players anywhere close to the NPC (and thus nobody there to see your wonderful AI system in action), you could put the mob into passive mode, where it does very little (if anything), and sleeps for 5, 10, 30 seconds, whatever you find appropriate before checking again.

Another possible way to implement this feature is to consider whether or not you are already making use of areas for something. Maybe you have different regions already mapped out. Whenever someone enters an area, have all the NPCs who call that area home "wake up". Beware, that you would most-likely want areas to be contiguous when using this method to ensure that players aren't waking mobs up in some distant corner of your world where nobody is around and CPU is just being wasted.
I added sleep(10) to the end of the combatproc(). This doesn't seem to change a thing. The game doesn't lag, but there's no difference between sleep(10) and sleep(50). The NPC stays right up on your grill without any delays in movement. I'll see what I can do about the "passive" mode. That makes a lot of sense in terms of CPU saving
Make sure your sleep is indented within your while() loop. If it is not then it will only delay once. Furthermore, if that single delay is AFTER your loop (that doesn't end), then you will never even get a delay at all. What you want is for it to sleep during the loop every time the loop starts over.
Absolutely excellent. Thank you lads for your help