From b1d7d09d7dd8d4d8bd7b1f50ef601f1d969564e0 Mon Sep 17 00:00:00 2001
From: Mario <mario@smbclan.net>
Date: Sun, 19 Jun 2016 10:39:43 +1000
Subject: [PATCH] Optimize some more find loops

---
 qcsrc/common/monsters/monster/mage.qc        | 35 +++++++------
 qcsrc/common/monsters/monster/shambler.qc    | 10 ++--
 qcsrc/common/monsters/monster/spider.qc      |  6 ++-
 qcsrc/common/monsters/sv_monsters.qc         | 19 +++----
 qcsrc/common/mutators/mutator/nades/nades.qc | 17 +++----
 qcsrc/common/t_items.qc                      | 12 ++---
 qcsrc/common/triggers/func/conveyor.qc       | 53 ++++++++++----------
 qcsrc/common/triggers/target/music.qc        | 10 ++--
 qcsrc/common/triggers/target/spawn.qc        |  6 ++-
 qcsrc/common/triggers/teleporters.qc         | 10 ++--
 10 files changed, 86 insertions(+), 92 deletions(-)

diff --git a/qcsrc/common/monsters/monster/mage.qc b/qcsrc/common/monsters/monster/mage.qc
index 44d7121fcd..c964b30827 100644
--- a/qcsrc/common/monsters/monster/mage.qc
+++ b/qcsrc/common/monsters/monster/mage.qc
@@ -249,52 +249,51 @@ void M_Mage_Attack_Spike(entity this, vector dir)
 
 void M_Mage_Defend_Heal(entity this)
 {
-	entity head;
 	float washealed = false;
 
-	for(head = findradius(this.origin, (autocvar_g_monster_mage_heal_range)); head; head = head.chain) if(M_Mage_Defend_Heal_Check(this, head))
+	FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_monster_mage_heal_range, M_Mage_Defend_Heal_Check(this, it),
 	{
 		washealed = true;
 		string fx = "";
-		if(IS_PLAYER(head))
+		if(IS_PLAYER(it))
 		{
 			switch(this.skin)
 			{
 				case 0:
-					if(head.health < autocvar_g_balance_health_regenstable) head.health = bound(0, head.health + (autocvar_g_monster_mage_heal_allies), autocvar_g_balance_health_regenstable);
+					if(it.health < autocvar_g_balance_health_regenstable) it.health = bound(0, it.health + (autocvar_g_monster_mage_heal_allies), autocvar_g_balance_health_regenstable);
 					fx = EFFECT_HEALING.eent_eff_name;
 					break;
 				case 1:
-					if(head.ammo_cells) head.ammo_cells = bound(head.ammo_cells, head.ammo_cells + 1, g_pickup_cells_max);
-					if(head.ammo_plasma) head.ammo_plasma = bound(head.ammo_plasma, head.ammo_plasma + 1, g_pickup_plasma_max);
-					if(head.ammo_rockets) head.ammo_rockets = bound(head.ammo_rockets, head.ammo_rockets + 1, g_pickup_rockets_max);
-					if(head.ammo_shells) head.ammo_shells = bound(head.ammo_shells, head.ammo_shells + 2, g_pickup_shells_max);
-					if(head.ammo_nails) head.ammo_nails = bound(head.ammo_nails, head.ammo_nails + 5, g_pickup_nails_max);
+					if(it.ammo_cells) it.ammo_cells = bound(it.ammo_cells, it.ammo_cells + 1, g_pickup_cells_max);
+					if(it.ammo_plasma) it.ammo_plasma = bound(it.ammo_plasma, it.ammo_plasma + 1, g_pickup_plasma_max);
+					if(it.ammo_rockets) it.ammo_rockets = bound(it.ammo_rockets, it.ammo_rockets + 1, g_pickup_rockets_max);
+					if(it.ammo_shells) it.ammo_shells = bound(it.ammo_shells, it.ammo_shells + 2, g_pickup_shells_max);
+					if(it.ammo_nails) it.ammo_nails = bound(it.ammo_nails, it.ammo_nails + 5, g_pickup_nails_max);
 					fx = "ammoregen_fx";
 					break;
 				case 2:
-					if(head.armorvalue < autocvar_g_balance_armor_regenstable)
+					if(it.armorvalue < autocvar_g_balance_armor_regenstable)
 					{
-						head.armorvalue = bound(0, head.armorvalue + (autocvar_g_monster_mage_heal_allies), autocvar_g_balance_armor_regenstable);
+						it.armorvalue = bound(0, it.armorvalue + (autocvar_g_monster_mage_heal_allies), autocvar_g_balance_armor_regenstable);
 						fx = "armorrepair_fx";
 					}
 					break;
 				case 3:
-					head.health = bound(0, head.health - ((head == this)  ? (autocvar_g_monster_mage_heal_self) : (autocvar_g_monster_mage_heal_allies)), autocvar_g_balance_health_regenstable);
+					it.health = bound(0, it.health - ((it == this)  ? (autocvar_g_monster_mage_heal_self) : (autocvar_g_monster_mage_heal_allies)), autocvar_g_balance_health_regenstable);
 					fx = EFFECT_RAGE.eent_eff_name;
 					break;
 			}
 
-			Send_Effect_(fx, head.origin, '0 0 0', 1);
+			Send_Effect_(fx, it.origin, '0 0 0', 1);
 		}
 		else
 		{
-			Send_Effect(EFFECT_HEALING, head.origin, '0 0 0', 1);
-			head.health = bound(0, head.health + (autocvar_g_monster_mage_heal_allies), head.max_health);
-			if(!(head.spawnflags & MONSTERFLAG_INVINCIBLE) && head.sprite)
-				WaypointSprite_UpdateHealth(head.sprite, head.health);
+			Send_Effect(EFFECT_HEALING, it.origin, '0 0 0', 1);
+			it.health = bound(0, it.health + (autocvar_g_monster_mage_heal_allies), it.max_health);
+			if(!(it.spawnflags & MONSTERFLAG_INVINCIBLE) && it.sprite)
+				WaypointSprite_UpdateHealth(it.sprite, it.health);
 		}
-	}
+	});
 
 	if(washealed)
 	{
diff --git a/qcsrc/common/monsters/monster/shambler.qc b/qcsrc/common/monsters/monster/shambler.qc
index 7a11b139e4..b94332c301 100644
--- a/qcsrc/common/monsters/monster/shambler.qc
+++ b/qcsrc/common/monsters/monster/shambler.qc
@@ -80,8 +80,6 @@ void M_Shambler_Attack_Swing(entity this)
 
 void M_Shambler_Attack_Lightning_Explode(entity this)
 {
-	entity head;
-
 	sound(this, CH_SHOTS, SND_ELECTRO_IMPACT, VOL_BASE, ATTEN_NORM);
 	Send_Effect(EFFECT_ELECTRO_IMPACT, this.origin, '0 0 0', 1);
 
@@ -95,11 +93,11 @@ void M_Shambler_Attack_Lightning_Explode(entity this)
 
 	RadiusDamage (this, this.realowner, (autocvar_g_monster_shambler_attack_lightning_damage), (autocvar_g_monster_shambler_attack_lightning_damage), (autocvar_g_monster_shambler_attack_lightning_radius), NULL, NULL, (autocvar_g_monster_shambler_attack_lightning_force), this.projectiledeathtype, other);
 
-	for(head = findradius(this.origin, (autocvar_g_monster_shambler_attack_lightning_radius_zap)); head; head = head.chain) if(head != this.realowner) if(head.takedamage)
+	FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_monster_shambler_attack_lightning_radius_zap, it != this.realowner && it.takedamage,
 	{
-		te_csqc_lightningarc(this.origin, head.origin);
-		Damage(head, this, this.realowner, (autocvar_g_monster_shambler_attack_lightning_damage_zap) * MONSTER_SKILLMOD(this), DEATH_MONSTER_SHAMBLER_ZAP.m_id, head.origin, '0 0 0');
-	}
+		te_csqc_lightningarc(this.origin, it.origin);
+		Damage(it, this, this.realowner, (autocvar_g_monster_shambler_attack_lightning_damage_zap) * MONSTER_SKILLMOD(this), DEATH_MONSTER_SHAMBLER_ZAP.m_id, it.origin, '0 0 0');
+	});
 
 	setthink(this, SUB_Remove);
 	this.nextthink = time + 0.2;
diff --git a/qcsrc/common/monsters/monster/spider.qc b/qcsrc/common/monsters/monster/spider.qc
index 9338657082..d1ff169b68 100644
--- a/qcsrc/common/monsters/monster/spider.qc
+++ b/qcsrc/common/monsters/monster/spider.qc
@@ -143,8 +143,10 @@ void M_Spider_Attack_Web_Explode(entity this)
 		Send_Effect(EFFECT_ELECTRO_IMPACT, this.origin, '0 0 0', 1);
 		RadiusDamage(this, this.realowner, 0, 0, 25, NULL, NULL, 25, this.projectiledeathtype, NULL);
 
-		for(entity e = findradius(this.origin, 25); e; e = e.chain) if(e != this) if(e.takedamage && !IS_DEAD(e)) if(e.health > 0) if(e.monsterid != MON_SPIDER.monsterid)
-			e.spider_slowness = time + (autocvar_g_monster_spider_attack_web_damagetime);
+		FOREACH_ENTITY_RADIUS(this.origin, 25, it != this && it.takedamage && !IS_DEAD(it) && it.health > 0 && it.monsterid != MON_SPIDER.monsterid,
+		{
+			it.spider_slowness = time + (autocvar_g_monster_spider_attack_web_damagetime);
+		});
 
 		remove(this);
 	}
diff --git a/qcsrc/common/monsters/sv_monsters.qc b/qcsrc/common/monsters/sv_monsters.qc
index c0a15e97b1..5e9eaef32f 100644
--- a/qcsrc/common/monsters/sv_monsters.qc
+++ b/qcsrc/common/monsters/sv_monsters.qc
@@ -123,29 +123,26 @@ entity Monster_FindTarget(entity mon)
 {
 	if(MUTATOR_CALLHOOK(MonsterFindTarget)) { return mon.enemy; } // Handled by a mutator
 
-	entity head, closest_target = NULL;
-	head = findradius(mon.origin, mon.target_range);
+	entity closest_target = NULL;
 
-	while(head) // find the closest acceptable target to pass to
+	// find the closest acceptable target to pass to
+	FOREACH_ENTITY_RADIUS(mon.origin, mon.target_range, it.monster_attack,
 	{
-		if(head.monster_attack)
-		if(Monster_ValidTarget(mon, head))
+		if(Monster_ValidTarget(mon, it))
 		{
 			// if it's a player, use the view origin as reference (stolen from RadiusDamage functions in g_damage.qc)
-			vector head_center = CENTER_OR_VIEWOFS(head);
+			vector head_center = CENTER_OR_VIEWOFS(it);
 			vector ent_center = CENTER_OR_VIEWOFS(mon);
 
 			if(closest_target)
 			{
 				vector closest_target_center = CENTER_OR_VIEWOFS(closest_target);
 				if(vlen2(ent_center - head_center) < vlen2(ent_center - closest_target_center))
-					{ closest_target = head; }
+					{ closest_target = it; }
 			}
-			else { closest_target = head; }
+			else { closest_target = it; }
 		}
-
-		head = head.chain;
-	}
+	});
 
 	return closest_target;
 }
diff --git a/qcsrc/common/mutators/mutator/nades/nades.qc b/qcsrc/common/mutators/mutator/nades/nades.qc
index 1d5a8c37b3..7336c34a4b 100644
--- a/qcsrc/common/mutators/mutator/nades/nades.qc
+++ b/qcsrc/common/mutators/mutator/nades/nades.qc
@@ -426,16 +426,13 @@ void nade_ice_think(entity this)
 
 	float current_freeze_time = this.ltime - time - 0.1;
 
-	entity e;
-	for(e = findradius(this.origin, autocvar_g_nades_nade_radius); e; e = e.chain)
-	if(e != this)
-	if(!autocvar_g_nades_ice_teamcheck || (DIFF_TEAM(e, this.realowner) || e == this.realowner))
-	if(e.takedamage && !IS_DEAD(e))
-	if(e.health > 0)
-	if(!e.revival_time || ((time - e.revival_time) >= 1.5))
-	if(!STAT(FROZEN, e))
-	if(current_freeze_time > 0)
-		nade_ice_freeze(this, e, current_freeze_time);
+	FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_nades_nade_radius, it != this && it.takedamage && !IS_DEAD(it) && it.health > 0 && current_freeze_time > 0,
+	{
+		if(!autocvar_g_nades_ice_teamcheck || (DIFF_TEAM(it, this.realowner) || it == this.realowner))
+		if(!it.revival_time || ((time - it.revival_time) >= 1.5))
+		if(!STAT(FROZEN, it))
+			nade_ice_freeze(this, it, current_freeze_time);
+	});
 }
 
 void nade_ice_boom(entity this)
diff --git a/qcsrc/common/t_items.qc b/qcsrc/common/t_items.qc
index a0255d7d61..1bf751f91c 100644
--- a/qcsrc/common/t_items.qc
+++ b/qcsrc/common/t_items.qc
@@ -825,15 +825,15 @@ LABEL(pickup)
 		if(this.team)
 		{
 			RandomSelection_Init();
-			for(entity head = NULL; (head = findfloat(head, team, this.team)); )
+			FOREACH_ENTITY_FLAGS(flags, FL_ITEM,
 			{
-				if(head.flags & FL_ITEM)
-				if(head.classname != "item_flag_team" && head.classname != "item_key_team")
+				if(it.team == this.team)
+				if(it.classname != "item_flag_team" && it.classname != "item_key_team")
 				{
-					Item_Show(head, -1);
-					RandomSelection_Add(head, 0, string_null, head.cnt, 0);
+					Item_Show(it, -1);
+					RandomSelection_Add(it, 0, string_null, it.cnt, 0);
 				}
-			}
+			});
 			e = RandomSelection_chosen_ent;
 
 		}
diff --git a/qcsrc/common/triggers/func/conveyor.qc b/qcsrc/common/triggers/func/conveyor.qc
index e2335b8831..ab4cc12d5a 100644
--- a/qcsrc/common/triggers/func/conveyor.qc
+++ b/qcsrc/common/triggers/func/conveyor.qc
@@ -8,47 +8,46 @@ void conveyor_think(entity this)
 	this.move_time = time;
 	if(dt <= 0) { return; }
 #endif
-	entity e;
 
 	// set mythis as current conveyor where possible
-	for(e = NULL; (e = findentity(e, conveyor, this)); )
-		e.conveyor = NULL;
+	FOREACH_ENTITY_ENT(conveyor, this,
+	{
+		it.conveyor = NULL;
+	});
 
 	if(this.state)
 	{
-		for(e = findradius((this.absmin + this.absmax) * 0.5, vlen(this.absmax - this.absmin) * 0.5 + 1); e; e = e.chain)
-			if(!e.conveyor.state)
-				if(isPushable(e))
-				{
-					vector emin = e.absmin;
-					vector emax = e.absmax;
-					if(this.solid == SOLID_BSP)
-					{
-						emin -= '1 1 1';
-						emax += '1 1 1';
-					}
-					if(boxesoverlap(emin, emax, this.absmin, this.absmax)) // quick
-						if(WarpZoneLib_BoxTouchesBrush(emin, emax, this, e)) // accurate
-							e.conveyor = this;
-				}
-
-		for(e = NULL; (e = findentity(e, conveyor, this)); )
+		FOREACH_ENTITY_RADIUS((this.absmin + this.absmax) * 0.5, vlen(this.absmax - this.absmin) * 0.5 + 1, !it.conveyor.state && isPushable(it),
+		{
+			vector emin = it.absmin;
+			vector emax = it.absmax;
+			if(this.solid == SOLID_BSP)
+			{
+				emin -= '1 1 1';
+				emax += '1 1 1';
+			}
+			if(boxesoverlap(emin, emax, this.absmin, this.absmax)) // quick
+				if(WarpZoneLib_BoxTouchesBrush(emin, emax, this, it)) // accurate
+					it.conveyor = this;
+		});
+
+		FOREACH_ENTITY_ENT(conveyor, this,
 		{
-			if(IS_CLIENT(e)) // doing it via velocity has quite some advantages
+			if(IS_CLIENT(it)) // doing it via velocity has quite some advantages
 				continue; // done in SV_PlayerPhysics	continue;
 
-			setorigin(e, e.origin + this.movedir * PHYS_INPUT_FRAMETIME);
-			move_out_of_solid(e);
+			setorigin(it, it.origin + this.movedir * PHYS_INPUT_FRAMETIME);
+			move_out_of_solid(it);
 #ifdef SVQC
-			UpdateCSQCProjectile(e);
+			UpdateCSQCProjectile(it);
 #endif
 			/*
 			// stupid conveyor code
-			tracebox(e.origin, e.mins, e.maxs, e.origin + this.movedir * sys_frametime, MOVE_NORMAL, e);
+			tracebox(it.origin, it.mins, it.maxs, it.origin + this.movedir * sys_frametime, MOVE_NORMAL, it);
 			if(trace_fraction > 0)
-				setorigin(e, trace_endpos);
+				setorigin(it, trace_endpos);
 			*/
-		}
+		});
 	}
 
 #ifdef SVQC
diff --git a/qcsrc/common/triggers/target/music.qc b/qcsrc/common/triggers/target/music.qc
index d43cbec769..7abcd67403 100644
--- a/qcsrc/common/triggers/target/music.qc
+++ b/qcsrc/common/triggers/target/music.qc
@@ -71,13 +71,13 @@ spawnfunc(target_music)
 }
 void TargetMusic_RestoreGame()
 {
-	for(entity e = NULL; (e = find(e, classname, "target_music")); )
+	FOREACH_ENTITY_CLASS("target_music", true,
 	{
-		if(e.targetname == "")
-			target_music_sendto(e, MSG_INIT, 1);
+		if(it.targetname == "")
+			target_music_sendto(it, MSG_INIT, 1);
 		else
-			target_music_sendto(e, MSG_INIT, 0);
-	}
+			target_music_sendto(it, MSG_INIT, 0);
+	});
 }
 // values:
 //   volume
diff --git a/qcsrc/common/triggers/target/spawn.qc b/qcsrc/common/triggers/target/spawn.qc
index eced856d7e..bc5271040c 100644
--- a/qcsrc/common/triggers/target/spawn.qc
+++ b/qcsrc/common/triggers/target/spawn.qc
@@ -287,8 +287,10 @@ void target_spawn_use(entity this, entity actor, entity trigger)
 	else
 	{
 		// edit entity
-		for(entity e = NULL; (e = find(e, targetname, this.target)); )
-			target_spawn_useon(e, this, actor, trigger);
+		FOREACH_ENTITY_STRING(targetname, this.target,
+		{
+			target_spawn_useon(it, this, actor, trigger);
+		});
 	}
 }
 
diff --git a/qcsrc/common/triggers/teleporters.qc b/qcsrc/common/triggers/teleporters.qc
index ba472ac557..20f618aa24 100644
--- a/qcsrc/common/triggers/teleporters.qc
+++ b/qcsrc/common/triggers/teleporters.qc
@@ -187,21 +187,21 @@ entity Simple_TeleportPlayer(entity teleporter, entity player)
 	else
 	{
 		RandomSelection_Init();
-		for(e = NULL; (e = find(e, targetname, teleporter.target)); )
+		FOREACH_ENTITY_STRING(targetname, teleporter.target,
 		{
 			p = 1;
 			if(STAT(TELEPORT_TELEFRAG_AVOID, player))
 			{
 			#ifdef SVQC
-				locout = e.origin + '0 0 1' * (1 - player.mins.z - 24);
+				locout = it.origin + '0 0 1' * (1 - player.mins.z - 24);
 			#elif defined(CSQC)
-				locout = e.origin + '0 0 1' * (1 - player.mins.z - 24);
+				locout = it.origin + '0 0 1' * (1 - player.mins.z - 24);
 			#endif
 				if(check_tdeath(player, locout, '0 0 0', '0 0 0'))
 					p = 0;
 			}
-			RandomSelection_Add(e, 0, string_null, (e.cnt ? e.cnt : 1), p);
-		}
+			RandomSelection_Add(it, 0, string_null, (it.cnt ? it.cnt : 1), p);
+		});
 		e = RandomSelection_chosen_ent;
 	}
 
-- 
2.39.5