I can only quote Superku, as I can't really say better than he already did:
Originally Posted by Superku
Having one game loop is the way to go IMO, so as long as your project isn't that complex already change it.
wait(1) is rather "slow" and you have no real influence on when functions are executed. proc_mode (in particular PROC_GLOBAL) is a game and project killer, leading to seemingly random crashes as it affects all kinds of functions you don't want it to have an impact on. Example:
Code
///////////////////////////////
#include <acknex.h>
#include <default.c>
///////////////////////////////

void projectile()
{
    my.skill1 = 128;
    my.pan = random(20)-10;
    my.tilt = random(20)-10;
    while(my.skill1 > 0)
    {
        c_move(me,vector(16*time_step,0,0),nullvector,0);
        my.skill1 -= time_step;
        
        VECTOR temp;
        vec_set(temp,my.x);
        if(vec_to_screen(temp,camera)) draw_text(str_printf(NULL,"%d",(int)proc_mode),temp.x,temp.y,COLOR_RED);
        
        wait(1);
    }
    ptr_remove(me);
}

void spawnProjectile()
{
    proc_mode = PROC_GLOBAL;
    wait(1); // <- doesn't help as proc_mode is restored after wait
    ent_create(CUBE_MDL,vector(0,random(16)-8,0),projectile);
}

void reload()
{
    level_load(NULL);
}

void main()
{
    fps_max = 60;
    video_mode = 10;
    level_load(NULL);
    on_mouse_left = spawnProjectile; // press left mouse button a few times,
    on_mouse_right = reload; // then the right mouse button to crash the game
}


What I've done for the past few years for new projects was to use on_frame, like this:

Code
///////////////////////////////
#include <acknex.h>
#include <default.c>

// header files
#include "player.h"

// implementation:
#include "player.c"

///////////////////////////////

void mainFrameEvent()
{
	input update function;
	if(gameMode == GAME_MODE_PLAY)
	{
		objectsUpdate();
		enemiesUpdate();
		playerUpdate();
	}
	if(gameMode == other modes) { ... }
}

void main()
{
	fps_max = 60;
	level_load(NULL);
	...
	on_frame = mainFrameEvent;
}


This way you have complete control over what gets executed when and how. You could for example freeze all enemies or projectiles in the game with a simple if(variable) check, while allowing the player to move freely.
You only have to let's say create a list of objects after level_load (on_level_load or what it's called) and free that list on or before level change.

I still use wait(1) entity loops here and there but just for some level decoration/ dynamic objects which don't have an actual influence on gameplay.
And
Originally Posted by Superku
Sorry, but you are wrong. A big project is super tough to manage and debug when using wait. The initial setup is a little easier but that's about it, no other advantages, only disadvantages.
Btw. 10000 waits eat up 2ms of performance already on a 6700k. You'd have to do one hell of an optimization to save 2ms normally, or you could just NOT use wait.

And also a test results performed by txesmi in the past:
Originally Posted by txesmi
The only way of speaking about the offtopic is with numbers.

[Linked Image]

Code
-----------------------------------------
| a wait per entity | own scheduler     |
| 1 byte stack      | 1 byte stack      |
-----------------------------------------
| a wait per entity | own scheduler     |
| 128 bytes stack   | 128 bytes stack   |
-----------------------------------------

Notice that the stack memory size has also its impact in the difference.


Code
#include <acknex.h>
#include <default.c>

#define ENT_COUNT    10000
#define STACK_SIZE   1
#define COMPLEXITY   1

ENTITY *ents[ENT_COUNT];

action actWait() {
	BYTE _n[STACK_SIZE];
	while(1) {
		int _i = 0;
		for(; _i<COMPLEXITY; _i+=1)
			_n[random(STACK_SIZE)] = random(256);
		wait(1);
	}
}

var actList(ENTITY *_ent) {
	BYTE _n[STACK_SIZE];
	int _i = 0;
	for(; _i<COMPLEXITY; _i+=1)
		_n[random(STACK_SIZE)] = random(256);
	return -1;
}

void entLoop () {
	while(!key_esc) {
		wait(1);
		ENTITY **_ent = ents;
		ENTITY **_entLast = _ent + ENT_COUNT;
		for(; _ent<_entLast; _ent++) {
			if(*_ent == NULL)
				continue;
			var _result = actList(*_ent);
			if(_result == 0)
				continue;
			switch(_result) {
				case 1:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 2:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 3:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 4:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 5:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 6:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 7:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 8:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 9:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 10:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 11:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 12:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 13:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 14:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 15:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 16:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 17:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 18:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				case 19:
					ent_remove(*_ent);
					*_ent = NULL;
					break;
				default:
					break;
			}
		}
	}
}

void main () {
	max_entities = ENT_COUNT;
	
	void _act ();
	_act = actWait;
//	_act = actList;
	
	level_load("");
	def_debug();
	int _i = 0;
	for(; _i<ENT_COUNT; _i+=1)
		ents[_i] = ent_create(SPHERE_MDL, vector(0, 0, -1000), _act);
	if(_act == actList)
		entLoop();
}


I gived a bit of complexity to the scheduler loop so it can be considered a complete flux manager. The numbers speak by themself. It is clear it gains performance with a single while loop but it is not that much. Take into account that we are speaking about a difference of 3/10000 ms/ent: the time taken by few operations. Bad programming practices will waste more time.

Salud!

Greets!


Looking for free stuff?? Take a look here: http://badcom.at.ua
Support me on: https://boosty.to/3rung