ID:2013257
 
(See the best response by Ter13.)
I tried to make simple event loop, but all i found browsing - Deadron's event loop, which includes libs. Without libs, how to make a loop?

What are you trying to do?
Looping event, which check for mob in range.
Can you be more specific? What's the use-case? When should it operate? How often should it operate? Is it looking for all mobs? What object is doing the looking?
I have an object. What is my goal - to make him check range 5x5 tiles for any mob. How to do the check - i know, probably. But how to make tick, which run proc every couple of seconds without libs - i have no idea.
Best response
obj/someobj
proc
MobSearch()
set waitfor = 0 //prevent this from blocking
var/list/l
while(loc)
l = viewers(2,src) //get all mobs in a range of 2
if(l.len)
//we found something. Do something.
sleep(10) //delay for 1 second
New()
if(loc) MobSearch() //if we're created in a position, start searching automatically


You'll want to look up while loops, do while loops, and for loops. Those are the three basic kinds of loops.

You should note that this approach is probably better not done at all. Manually polling for objects nearby is incredibly inefficient, and there are much better ways of doing this without looping.

For instance:

trigger_area
parent_type = /atom/movable
var/tmp
atom/owner
incall
outcall

//called when an object steps on top of this one using Move()
Crossed(atom/movable/o)
if(owner&&incall) call(owner,incall)(o,src)

//called when an object steps out of this one using Move()
Uncrossed(atom/movable/o)
if(owner&&outcall) call(owner,outcall)(o,src)

New(loc,radius,owner,incall,outcall,initial_detect=0)
src.owner = owner
src.incall = incall
src.outcall = outcall
if(loc&&isturf(loc))
var/x1 = max(loc.x-radius,1)
var/y1 = max(loc.y-radius,1)
var/x2 = min(loc.x+radius,world.maxx)
var/y2 = min(loc.y+radius,world.maxy)
loc = locate(x1,y1,z)
bound_width = (x2-x1)*TILE_WIDTH
bound_height = (y2-y1)*TILE_HEIGHT

//if we want to detect any objects that are already under this trigger area
if(initial_detect)
for(var/atom/movable/o in obounds(src))
Crossed(o)


The above object is a way to persistently detect objects that cross over a certain part of the map that's defined by the bounding area of this object. These should be stationary. If the detection area needs to be moved, this solution will not work for you. It's just faster to poll if the object needs to move.

You can use them like this:

obj
proximity_mine
var/tmp
trigger_area/trigger_area
proc
Set()
trigger_area = new(loc,2,src,"onTrigger") //set up the trigger_area object with a radius of 2 at the current location, the owner as this object, and the Crossed() hook being "onTrigger".

//called when the proxy mine is triggered by another player
Explode()
for(var/mob/m in obounds(trigger_area))
m.Die()
trigger_area.loc = null
trigger_area = null
loc = null

//called from trigger_area.Crossed()
onTrigger(atom/movable/o,trigger_area/source)
if(source==trigger_area&&ismob(o))
Explode()


This approach requires no constant looping to check for interlopers.
Thank you a lot.
Ter's solution is good advice in any similar case, too. Like for instance if you have a field full of monsters, you really don't want to trigger their AI loops till they're actually in range of anyone, or else you're wasting CPU cycles.
you really don't want to trigger their AI loops till they're actually in range of anyone

It should really be stressed here, though, that my trigger_area solution only works reasonably for stationary objects. Because of the overhead of moving around objects with large bounding boxes, you really don't want a large number of these guys flitting around the map all the time.

For something like AI, it's usually best to develop some kind of a chunk/observer approach that keeps track of what clients are and aren't near. Unfortunately, this is a topic that even someone as well-versed as I am hates dealing with.