}
}
- if(ons_roundlost)
+ if(ons_roundlost) // TODO: move this junk to a client mutator for onslaught (possible using the WantEventchase hook)
{
- FOREACH_ENTITY_CLASS("onslaught_generator", it.health <= 0, {
+ IL_EACH(g_onsgenerators, it.health <= 0,
+ {
gen = it;
break;
});
entityclass(Rubble);
class(Rubble).float creationtime;
-void RubbleLimit(string cname, float limit, void(entity) deleteproc)
+IntrusiveList g_rubble;
+STATIC_INIT(g_rubble) { g_rubble = IL_NEW(); }
+
+void RubbleLimit(string cname, int limit, void(entity) deleteproc)
{
// remove rubble of the same type if it's at the limit
// remove multiple rubble if the limit has been decreased
entity oldest = NULL;
float oldesttime = 0;
// compare to all other matching entities
- FOREACH_ENTITY_CLASS(cname, true,
+ IL_EACH(g_rubble, it.classname == cname,
{
++c;
if(!oldest || oldesttime > it.creationtime)
entity e = spawn();
e.classname = cname;
e.creationtime = time;
+ IL_PUSH(g_rubble, e);
return e;
}
missile.effects = EF_BRIGHTFIELD | EF_LOWPRECISION;
missile.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, missile);
+ IL_PUSH(g_bot_dodge, missile);
CSQCProjectile(missile, true, PROJECTILE_ELECTRO, true);
}
setsize(this, CPICON_MIN, CPICON_MAX);
}
-void cpicon_construct(entity this)
+void cpicon_construct(entity this, bool isnew)
{
this.netname = "Control Point Icon";
this.cp_origin = this.origin;
this.cp_bob_origin = '0 0 0.1';
this.cp_bob_spd = 0;
+
+ if(isnew)
+ IL_PUSH(g_drawables, this);
}
.vector glowmod;
this.count = (this.health - this.max_health) * frametime;
cpicon_changeteam(this);
- cpicon_construct(this);
+ cpicon_construct(this, isnew);
}
if(sf & CPSF_STATUS)
setsize(this, GENERATOR_MIN, GENERATOR_MAX);
}
-void generator_construct(entity this)
+void generator_construct(entity this, bool isnew)
{
this.netname = "Generator";
this.classname = "onslaught_generator";
+ if(isnew)
+ IL_PUSH(g_onsgenerators, this);
+
setorigin(this, this.origin);
setmodel(this, MDL_ONS_GEN);
setsize(this, GENERATOR_MIN, GENERATOR_MAX);
this.count = 40;
generator_changeteam(this);
- generator_construct(this);
+ generator_construct(this, isnew);
}
if(sf & GSF_STATUS)
REGISTER_NET_LINKED(ENT_CLIENT_GENERATOR)
REGISTER_NET_LINKED(ENT_CLIENT_CONTROLPOINT_ICON)
+
+#ifdef SVQC
+IntrusiveList g_onsshields;
+STATIC_INIT(g_onsshields) { g_onsshields = IL_NEW(); }
+#endif
+
+#ifdef CSQC
+IntrusiveList g_onsgenerators;
+STATIC_INIT(g_onsgenerators) { g_onsgenerators = IL_NEW(); }
+#endif
void ons_CaptureShield_Spawn(entity generator, bool is_generator)
{
entity shield = new(ons_captureshield);
+ IL_PUSH(g_onsshields, shield);
shield.enemy = generator;
shield.team = generator.team;
{
LOG_DEBUG(etos(l), " (generator) is shielded");
l.takedamage = DAMAGE_NO;
+ if(l.bot_attack)
+ IL_REMOVE(g_bot_targets, l);
l.bot_attack = false;
}
else
{
LOG_DEBUG(etos(l), " (generator) is not shielded");
l.takedamage = DAMAGE_AIM;
+ if(!l.bot_attack)
+ IL_PUSH(g_bot_targets, l);
l.bot_attack = true;
}
if (l.goalentity)
{
l.goalentity.takedamage = DAMAGE_NO;
+ if(l.goalentity.bot_attack)
+ IL_REMOVE(g_bot_targets, l.goalentity);
l.goalentity.bot_attack = false;
}
}
if (l.goalentity)
{
l.goalentity.takedamage = DAMAGE_AIM;
+ if(!l.goalentity.bot_attack)
+ IL_PUSH(g_bot_targets, l.goalentity);
l.goalentity.bot_attack = true;
}
}
ons_ControlPoint_UpdateSprite(l);
}
- FOREACH_ENTITY_CLASS("ons_captureshield", true,
+ IL_EACH(g_onsshields, true,
{
it.team = it.enemy.team;
it.colormap = it.enemy.colormap;
e.solid = SOLID_NOT;
e.takedamage = DAMAGE_AIM;
e.bot_attack = true;
+ IL_PUSH(g_bot_targets, e);
e.event_damage = ons_ControlPoint_Icon_Damage;
e.team = player.team;
e.colormap = 1024 + (e.team - 1) * 17;
this.lasthealth = this.max_health = this.health = autocvar_g_onslaught_gen_health;
this.takedamage = DAMAGE_AIM;
this.bot_attack = true;
+ IL_PUSH(g_bot_targets, this);
this.iscaptured = true;
this.islinked = true;
this.isshielded = true;
gen.lasthealth = gen.max_health = gen.health = autocvar_g_onslaught_gen_health;
gen.takedamage = DAMAGE_AIM;
gen.bot_attack = true;
+ IL_PUSH(g_bot_targets, gen);
gen.event_damage = ons_GeneratorDamage;
gen.reset = ons_GeneratorReset;
setthink(gen, ons_GeneratorThink);
LOG_DEBUG(this.netname, " needs armor ", ftos(needarmor));
// See what is around
- FOREACH_ENTITY_FLOAT(bot_pickup, true,
+ IL_EACH(g_items, it.bot_pickup,
{
// gather health and armor only
if (it.solid)
entity ons_Nearest_ControlPoint(entity this, vector pos, float max_dist)
{
entity closest_target = NULL;
- FOREACH_ENTITY_CLASS("onslaught_controlpoint", true,
+ for(entity cp = ons_worldcplist; cp; cp = cp.ons_worldcpnext)
{
- if(SAME_TEAM(it, this))
- if(it.iscaptured)
- if(max_dist <= 0 || vdist(it.origin - pos, <=, max_dist))
- if(vlen2(it.origin - pos) <= vlen2(closest_target.origin - pos) || closest_target == NULL)
- closest_target = it;
- });
- FOREACH_ENTITY_CLASS("onslaught_generator", true,
+ if(SAME_TEAM(cp, this))
+ if(cp.iscaptured)
+ if(max_dist <= 0 || vdist(cp.origin - pos, <=, max_dist))
+ if(vlen2(cp.origin - pos) <= vlen2(closest_target.origin - pos) || closest_target == NULL)
+ closest_target = cp;
+ }
+ for(entity gen = ons_worldgeneratorlist; gen; gen = gen.ons_worldgeneratornext)
{
- if(SAME_TEAM(it, this))
- if(max_dist <= 0 || vdist(it.origin - pos, <, max_dist))
- if(vlen2(it.origin - pos) <= vlen2(closest_target.origin - pos) || closest_target == NULL)
- closest_target = it;
- });
+ if(SAME_TEAM(gen, this))
+ if(max_dist <= 0 || vdist(gen.origin - pos, <, max_dist))
+ if(vlen2(gen.origin - pos) <= vlen2(closest_target.origin - pos) || closest_target == NULL)
+ closest_target = gen;
+ }
return closest_target;
}
vector delta;
float smallest_distance = 0, distance;
- FOREACH_ENTITY_CLASS("onslaught_controlpoint", true,
+ for(entity cp = ons_worldcplist; cp; cp = cp.ons_worldcpnext)
{
- delta = it.origin - pos;
+ delta = cp.origin - pos;
delta_z = 0;
distance = vlen(delta);
- if(SAME_TEAM(it, this))
- if(it.iscaptured)
+ if(SAME_TEAM(cp, this))
+ if(cp.iscaptured)
if(max_dist <= 0 || distance <= max_dist)
if(closest_target == NULL || distance <= smallest_distance )
{
- closest_target = it;
+ closest_target = cp;
smallest_distance = distance;
}
- });
- FOREACH_ENTITY_CLASS("onslaught_generator", true,
+ }
+ for(entity gen = ons_worldgeneratorlist; gen; gen = gen.ons_worldgeneratornext)
{
- delta = it.origin - pos;
+ delta = gen.origin - pos;
delta_z = 0;
distance = vlen(delta);
- if(SAME_TEAM(it, this))
+ if(SAME_TEAM(gen, this))
if(max_dist <= 0 || distance <= max_dist)
if(closest_target == NULL || distance <= smallest_distance )
{
- closest_target = it;
+ closest_target = gen;
smallest_distance = distance;
}
- });
+ }
return closest_target;
}
int ons_Count_SelfControlPoints(entity this)
{
int n = 0;
- FOREACH_ENTITY_CLASS("onslaught_controlpoint", true,
+ for(entity cp = ons_worldcplist; cp; cp = cp.ons_worldcpnext)
{
- if(SAME_TEAM(it, this))
- if(it.iscaptured)
+ if(SAME_TEAM(cp, this))
+ if(cp.iscaptured)
n++;
- });
- FOREACH_ENTITY_CLASS("onslaught_generator", true,
+ }
+ for(entity gen = ons_worldgeneratorlist; gen; gen = gen.ons_worldgeneratornext)
{
- if(SAME_TEAM(it, this))
+ if(SAME_TEAM(gen, this))
n++;
- });
+ }
return n;
}
// list of generators on the map
entity ons_worldgeneratorlist;
.entity ons_worldgeneratornext;
-.entity ons_stalegeneratornext;
// list of control points on the map
entity ons_worldcplist;
set_movetype(missile, MOVETYPE_FLYMISSILE);
missile.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, missile);
+ IL_PUSH(g_bot_dodge, missile);
setorigin(missile, this.origin + v_forward * 14 + '0 0 30' + v_right * -14);
setsize(missile, '0 0 0', '0 0 0');
missile.velocity = dir * 400;
TC(Mage, thismon);
bool need_help = false;
- FOREACH_ENTITY_FLOAT(iscreature, true,
+ FOREACH_CLIENT(IS_PLAYER(it) && it != actor,
{
- if(it != actor)
- if(vdist(it.origin - actor.origin, <=, autocvar_g_monster_mage_heal_range))
+ if(vdist(it.origin - actor.origin, <=, autocvar_g_monster_mage_heal_range))
if(M_Mage_Defend_Heal_Check(actor, it))
{
need_help = true;
}
});
+ if(!need_help)
+ {
+ IL_EACH(g_monsters, it != actor,
+ {
+ if(vdist(it.origin - actor.origin, <=, autocvar_g_monster_mage_heal_range))
+ if(M_Mage_Defend_Heal_Check(actor, it))
+ {
+ need_help = true;
+ break;
+ }
+ });
+ }
+
if(actor.health < (autocvar_g_monster_mage_heal_minhealth) || need_help)
if(time >= actor.attack_finished_single[0])
if(random() < 0.5)
gren.angles = vectoangles (gren.velocity);
gren.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, gren);
+ IL_PUSH(g_bot_dodge, gren);
CSQCProjectile(gren, true, PROJECTILE_SHAMBLER_LIGHTNING, true);
}
proj.event_damage = func_null;
proj.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, proj);
+ IL_PUSH(g_bot_dodge, proj);
proj.damagedbycontents = true;
proj.bouncefactor = 0.3;
setorigin(missile, actor.origin + actor.view_ofs + v_forward * 14);
missile.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, missile);
+ IL_PUSH(g_bot_dodge, missile);
missile.velocity = w_shotdir * (autocvar_g_monster_wyvern_attack_fireball_speed);
missile.avelocity = '300 300 300';
missile.nextthink = time + 5;
RadiusDamage(this, own, autocvar_g_monster_wyvern_attack_fireball_damage, autocvar_g_monster_wyvern_attack_fireball_edgedamage, autocvar_g_monster_wyvern_attack_fireball_force, NULL, NULL, autocvar_g_monster_wyvern_attack_fireball_radius, this.projectiledeathtype, NULL);
- FOREACH_ENTITY_FLOAT(takedamage, DAMAGE_AIM,
+ FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_monster_wyvern_attack_fireball_radius, it.takedamage == DAMAGE_AIM,
{
- if(vdist(it.origin - this.origin, <=, autocvar_g_monster_wyvern_attack_fireball_radius))
- Fire_AddDamage(it, own, 5 * MONSTER_SKILLMOD(own), autocvar_g_monster_wyvern_attack_fireball_damagetime, this.projectiledeathtype);
+ Fire_AddDamage(it, own, 5 * MONSTER_SKILLMOD(own), autocvar_g_monster_wyvern_attack_fireball_damagetime, this.projectiledeathtype);
});
delete(this);
this.classname = "monster";
this.takedamage = DAMAGE_AIM;
this.bot_attack = true;
+ IL_PUSH(g_bot_targets, this);
this.iscreature = true;
this.teleportable = true;
this.damagedbycontents = true;
this.classname = "item_buff";
this.solid = SOLID_TRIGGER;
this.flags = FL_ITEM;
+ this.bot_pickup = true;
+ this.bot_pickupevalfunc = commodity_pickupevalfunc;
+ this.bot_pickupbasevalue = 1000;
+ IL_PUSH(g_items, this);
setthink(this, buff_Think);
settouch(this, buff_Touch);
this.reset = buff_Reset;
if(player.buffs & BUFF_MAGNET.m_itemid)
{
vector pickup_size;
- FOREACH_ENTITY_FLAGS(flags, FL_ITEM,
+ IL_EACH(g_items, true,
{
if(it.buffs)
pickup_size = '1 1 1' * autocvar_g_buffs_magnet_range_buff;
float Item_ItemsTime_UpdateTime(entity e, float t)
{
bool isavailable = (t == 0);
- FOREACH_ENTITY_FLOAT(pure_data, false,
+ IL_EACH(g_items, it != e,
{
- if(!(it.itemdef == e.itemdef || ((e.weapons & WEPSET_SUPERWEAPONS) && (it.weapons & WEPSET_SUPERWEAPONS) && clienttype(it) == CLIENTTYPE_NOTACLIENT)))
+ if(!(it.itemdef == e.itemdef || ((e.weapons & WEPSET_SUPERWEAPONS) && (it.weapons & WEPSET_SUPERWEAPONS))))
continue;
- if (e == it) continue;
if (it.scheduledrespawntime <= time)
isavailable = true;
else if (t == 0 || it.scheduledrespawntime < t)
Item_ItemsTime_ResetTimes();
// ALL the times need to be reset before .reset()ing each item
// since Item_Reset schedules respawn of superweapons and powerups
- FOREACH_ENTITY_FLOAT(pure_data, false,
+ IL_EACH(g_items, it.reset,
{
- if(IS_CLIENT(it))
- continue;
- if (it.reset) Item_ItemsTime_SetTime(it, 0);
+ Item_ItemsTime_SetTime(it, 0);
});
Item_ItemsTime_SetTimesForAllPlayers();
}
proj.angles = vectoangles(proj.velocity);
proj.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, proj);
+ IL_PUSH(g_bot_dodge, proj);
proj.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_ARC;
//CSQCProjectile(proj, true, PROJECTILE_NAPALM_FIRE, true);
fountain.owner = this.owner;
fountain.realowner = this.realowner;
fountain.origin = this.origin;
+ fountain.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, fountain);
+ IL_PUSH(g_bot_dodge, fountain);
setorigin(fountain, fountain.origin);
setthink(fountain, napalm_fountain_think);
fountain.nextthink = time;
case NADE_TYPE_ENTRAP: nade_entrap_boom(this); break;
}
- FOREACH_ENTITY_ENT(aiment, this,
+ IL_EACH(g_projectiles, it.classname == "grapplinghook" && it.aiment == this,
{
- if(it.classname == "grapplinghook")
- RemoveGrapplingHook(it.realowner);
+ RemoveGrapplingHook(it.realowner);
});
delete(this);
is_weapclip = 1;*/
if(ITEM_TOUCH_NEEDKILL()) // || is_weapclip)
{
- FOREACH_ENTITY_ENT(aiment, this,
+ IL_EACH(g_projectiles, it.classname == "grapplinghook" && it.aiment == this,
{
- if(it.classname == "grapplinghook")
- RemoveGrapplingHook(it.realowner);
+ RemoveGrapplingHook(it.realowner);
});
delete(this);
return;
_nade.angles = vectoangles(_nade.velocity);
_nade.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, _nade);
+ IL_PUSH(g_bot_dodge, _nade);
_nade.projectiledeathtype = DEATH_NADE.m_id;
_nade.toss_time = time;
_nade.solid = SOLID_CORPSE; //((_nade.nade_type == NADE_TYPE_TRANSLOCATE) ? SOLID_CORPSE : SOLID_BBOX);
missile.nextthink = time;
missile.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, missile);
+ IL_PUSH(g_bot_dodge, missile);
CSQCProjectile(missile, true, PROJECTILE_RPC, false);
{
// detaches any object attached to e
- FOREACH_ENTITY_ENT(owner, e,
+ IL_EACH(g_sandbox_objects, it.owner == e,
{
- if(it.classname != "object") continue;
-
- vector org;
- org = gettaginfo(it, 0);
+ vector org = gettaginfo(it, 0);
setattachment(it, NULL, "");
it.owner = NULL;
// spawn a new object with default properties
entity e = new(object);
+ IL_PUSH(g_sandbox_objects, e);
e.takedamage = DAMAGE_AIM;
e.damageforcescale = 1;
e.solid = SOLID_BBOX; // SOLID_BSP would be best, but can lag the server badly
string port_string[MAX_STORAGE_ATTACHMENTS]; // fteqcc crashes if this isn't defined as a global
-string sandbox_ObjectPort_Save(entity e, float database)
+string sandbox_ObjectPort_Save(entity e, bool database)
{
// save object properties, and return them as a string
- float i = 0;
- string s;
- entity head;
+ int o = 0;
- for(head = NULL; (head = find(head, classname, "object")); )
- {
+ // order doesn't really matter, as we're writing the file fresh
+ IL_EACH(g_sandbox_objects, it == e || it.owner == e, LAMBDA(
// the main object needs to be first in the array [0] with attached objects following
- float slot, physics, solidity;
- if(head == e) // this is the main object, place it first
+ int slot, physics, solidity;
+ if(it == e) // this is the main object, place it first
{
slot = 0;
- solidity = head.solid; // applied solidity is normal solidity for children
- physics = head.move_movetype; // applied physics are normal physics for parents
+ solidity = it.solid; // applied solidity is normal solidity for children
+ physics = it.move_movetype; // applied physics are normal physics for parents
}
- else if(head.owner == e) // child object, list them in order
+ else if(it.owner == e) // child object, list them in order
{
- i += 1; // children start from 1
- slot = i;
- solidity = head.old_solid; // persisted solidity is normal solidity for children
- physics = head.old_movetype; // persisted physics are normal physics for children
- gettaginfo(head.owner, head.tag_index); // get the name of the tag our object is attached to, used further below
+ o += 1; // children start from 1
+ slot = o;
+ solidity = it.old_solid; // persisted solidity is normal solidity for children
+ physics = it.old_movetype; // persisted physics are normal physics for children
+ gettaginfo(it.owner, it.tag_index); // get the name of the tag our object is attached to, used further below
}
else
continue;
if(slot)
{
// properties stored only for child objects
- if(gettaginfo_name) port_string[slot] = strcat(port_string[slot], "\"", gettaginfo_name, "\" "); else port_string[slot] = strcat(port_string[slot], "\"\" "); // none
+ if(gettaginfo_name)
+ port_string[slot] = strcat(port_string[slot], "\"", gettaginfo_name, "\" ");
+ else
+ port_string[slot] = strcat(port_string[slot], "\"\" "); // none
}
else
{
// properties stored only for parent objects
if(database)
{
- port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.origin), " ");
- port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.angles), " ");
+ port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", it.origin), " ");
+ port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", it.angles), " ");
}
}
// properties stored for all objects
- port_string[slot] = strcat(port_string[slot], "\"", head.model, "\" ");
- port_string[slot] = strcat(port_string[slot], ftos(head.skin), " ");
- port_string[slot] = strcat(port_string[slot], ftos(head.alpha), " ");
- port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.colormod), " ");
- port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.glowmod), " ");
- port_string[slot] = strcat(port_string[slot], ftos(head.frame), " ");
- port_string[slot] = strcat(port_string[slot], ftos(head.scale), " ");
+ port_string[slot] = strcat(port_string[slot], "\"", it.model, "\" ");
+ port_string[slot] = strcat(port_string[slot], ftos(it.skin), " ");
+ port_string[slot] = strcat(port_string[slot], ftos(it.alpha), " ");
+ port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", it.colormod), " ");
+ port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", it.glowmod), " ");
+ port_string[slot] = strcat(port_string[slot], ftos(it.frame), " ");
+ port_string[slot] = strcat(port_string[slot], ftos(it.scale), " ");
port_string[slot] = strcat(port_string[slot], ftos(solidity), " ");
port_string[slot] = strcat(port_string[slot], ftos(physics), " ");
- port_string[slot] = strcat(port_string[slot], ftos(head.damageforcescale), " ");
- if(head.material) port_string[slot] = strcat(port_string[slot], "\"", head.material, "\" "); else port_string[slot] = strcat(port_string[slot], "\"\" "); // none
+ port_string[slot] = strcat(port_string[slot], ftos(it.damageforcescale), " ");
+ if(it.material)
+ port_string[slot] = strcat(port_string[slot], "\"", it.material, "\" ");
+ else
+ port_string[slot] = strcat(port_string[slot], "\"\" "); // none
if(database)
{
// properties stored only for the database
- if(head.crypto_idfp) port_string[slot] = strcat(port_string[slot], "\"", head.crypto_idfp, "\" "); else port_string[slot] = strcat(port_string[slot], "\"\" "); // none
+ if(it.crypto_idfp)
+ port_string[slot] = strcat(port_string[slot], "\"", it.crypto_idfp, "\" ");
+ else
+ port_string[slot] = strcat(port_string[slot], "\"\" "); // none
port_string[slot] = strcat(port_string[slot], "\"", e.netname, "\" ");
port_string[slot] = strcat(port_string[slot], "\"", e.message, "\" ");
port_string[slot] = strcat(port_string[slot], "\"", e.message2, "\" ");
}
- }
+ ));
// now apply the array to a simple string, with the ; symbol separating objects
- s = "";
- for(i = 0; i <= MAX_STORAGE_ATTACHMENTS; ++i)
+ string s = "";
+ for(int j = 0; j <= MAX_STORAGE_ATTACHMENTS; ++j)
{
- if(port_string[i])
- s = strcat(s, port_string[i], "; ");
- port_string[i] = string_null; // fully clear the string
+ if(port_string[j])
+ s = strcat(s, port_string[j], "; ");
+ port_string[j] = string_null; // fully clear the string
}
return s;
void sandbox_Database_Save()
{
// saves all objects to the database file
- entity head;
string file_name;
float file_get;
fputs(file_get, strcat("// sandbox storage \"", autocvar_g_sandbox_storage_name, "\" for map \"", GetMapname(), "\" last updated ", strftime(true, "%d-%m-%Y %H:%M:%S")));
fputs(file_get, strcat(" containing ", ftos(object_count), " objects\n"));
- for(head = NULL; (head = find(head, classname, "object")); )
+ IL_EACH(g_sandbox_objects, !it.owner, // attached objects are persisted separately, ignore them here
{
- // attached objects are persisted separately, ignore them here
- if(head.owner != NULL)
- continue;
-
// use a line of text for each object, listing all properties
- fputs(file_get, strcat(sandbox_ObjectPort_Save(head, true), "\n"));
- }
+ fputs(file_get, strcat(sandbox_ObjectPort_Save(it, true), "\n"));
+ });
fclose(file_get);
}
// this should show the same info as 'mesh' but for attachments
s = "";
j = 0;
- FOREACH_ENTITY_ENT(owner, e,
+ IL_EACH(g_sandbox_objects, it.owner == e,
{
- if(it.classname != "object") continue;
-
++j; // start from 1
gettaginfo(e, it.tag_index);
s = strcat(s, "^1attachment ", ftos(j), "^7 has mesh \"^3", it.model, "^7\" at animation frame ^3", ftos(it.frame));
#pragma once
+
+IntrusiveList g_sandbox_objects;
+STATIC_INIT(g_sandbox_objects) { g_sandbox_objects = IL_NEW(); }
net_notif.nent_net_name = ORDINAL(net_cpid);
Net_LinkEntity(net_notif, false, autocvar_notification_lifetime_runtime, Net_Write_Notification);
- FOREACH_ENTITY_CLASS(
- "net_notification",
+ IL_EACH(
+ g_notifications,
(it.owner.nent_type == net_type || net_type == MSG_Null) && (it.owner.nent_cpid == net_cpid || net_cpid == CPID_Null),
{
it.nent_net_name = -1;
else
{
entity net_notif = new_pure(net_notification);
+ IL_PUSH(g_notifications, net_notif);
net_notif.owner = notif;
net_notif.nent_broadcast = broadcast;
net_notif.nent_client = client;
float prev_soundtime;
#endif
+#ifdef SVQC
+IntrusiveList g_notifications;
+STATIC_INIT(g_notifications) { g_notifications = IL_NEW(); }
+#endif
+
#ifdef SVQC
ENUMCLASS(NOTIF)
/** send to one client and their spectators */
if(this.team)
{
RandomSelection_Init();
- FOREACH_ENTITY_FLAGS(flags, FL_ITEM,
+ IL_EACH(g_items, it.team == this.team,
{
- if(it.team == this.team)
if(it.classname != "item_flag_team" && it.classname != "item_key_team")
{
Item_Show(it, -1);
// marker for item team search
LOG_TRACE("Initializing item team ", ftos(this.team));
RandomSelection_Init();
- FOREACH_ENTITY_FLOAT(team, this.team,
+ IL_EACH(g_items, it.team == this.team,
{
- if(it.flags & FL_ITEM)
if(it.classname != "item_flag_team" && it.classname != "item_key_team")
RandomSelection_Add(it, 0, string_null, it.cnt, 0);
});
e.state = 0;
Item_Show(e, 1);
- FOREACH_ENTITY_FLOAT(team, this.team,
+ IL_EACH(g_items, it.team == this.team,
{
- if(it.flags & FL_ITEM)
if(it.classname != "item_flag_team" && it.classname != "item_key_team")
{
if(it != e)
this.weapons = WepSet_FromWeapon(Weapons_from(weaponid));
this.flags = FL_ITEM | itemflags;
+ IL_PUSH(g_items, this);
if(MUTATOR_CALLHOOK(FilterItem, this)) // error means we do not want the item
{
EXACTTRIGGER_TOUCH(this, trigger);
}
- FOREACH_ENTITY_ENT(enemy, actor,
+ IL_EACH(g_items, it.enemy == actor && it.classname == "droppedweapon",
{
- if(it.classname == "droppedweapon")
- delete(it);
+ delete(it);
});
if(GiveItems(actor, 0, tokenize_console(this.netname)))
{
this.health = this.max_health;
this.takedamage = DAMAGE_NO;
+ if(this.bot_attack)
+ IL_REMOVE(g_bot_targets, this);
this.bot_attack = false;
this.event_damage = func_null;
this.state = 1;
if(!(this.spawnflags & 4))
{
this.takedamage = DAMAGE_AIM;
+ if(!this.bot_attack)
+ IL_PUSH(g_bot_targets, this);
this.bot_attack = true;
this.event_damage = func_breakable_damage;
}
this.reset = func_breakable_reset;
this.reset(this);
- this.init_for_player_needed = 1;
+ IL_PUSH(g_initforplayer, this);
this.init_for_player = func_breakable_init_for_player;
CSQCMODEL_AUTOINIT(this);
#endif
// set mythis as current conveyor where possible
- FOREACH_ENTITY_ENT(conveyor, this,
+ IL_EACH(g_conveyed, it.conveyor == this,
{
it.conveyor = NULL;
+ IL_REMOVE(g_conveyed, it);
});
if(this.state)
}
if(boxesoverlap(emin, emax, this.absmin, this.absmax)) // quick
if(WarpZoneLib_BoxTouchesBrush(emin, emax, this, it)) // accurate
+ {
+ if(!it.conveyor)
+ IL_PUSH(g_conveyed, it);
it.conveyor = this;
+ }
});
- FOREACH_ENTITY_ENT(conveyor, this,
+ IL_EACH(g_conveyed, it.conveyor == this,
{
if(IS_CLIENT(it)) // doing it via velocity has quite some advantages
continue; // done in SV_PlayerPhysics continue;
#pragma once
+
+IntrusiveList g_conveyed;
+STATIC_INIT(g_conveyed) { g_conveyed = IL_NEW(); }
string message_save;
this.health = 10000;
+ if(!this.bot_attack)
+ IL_PUSH(g_bot_targets, this);
this.bot_attack = true;
// exit if still moving around...
#ifdef SVQC
+IntrusiveList g_targetmusic_list;
+STATIC_INIT(g_targetmusic_list) { g_targetmusic_list = IL_NEW(); }
+
// values:
// volume
// noise
}
void target_music_kill()
{
- FOREACH_ENTITY_CLASS("target_music", true, {
+ IL_EACH(g_targetmusic_list, true,
+ {
it.volume = 0;
if (it.targetname == "")
target_music_sendto(it, MSG_ALL, 1);
this.reset = target_music_reset;
if(!this.volume)
this.volume = 1;
+ IL_PUSH(g_targetmusic_list, this);
if(this.targetname == "")
target_music_sendto(this, MSG_INIT, 1);
else
}
void TargetMusic_RestoreGame()
{
- FOREACH_ENTITY_CLASS("target_music", true,
+ IL_EACH(g_targetmusic_list, true,
{
if(it.targetname == "")
target_music_sendto(it, MSG_INIT, 1);
entity Teleport_Find(vector mi, vector ma)
{
- entity e;
- for(e = NULL; (e = find(e, classname, "trigger_teleport")); )
- if(WarpZoneLib_BoxTouchesBrush(mi, ma, e, NULL))
- return e;
+ IL_EACH(g_teleporters, WarpZoneLib_BoxTouchesBrush(mi, ma, it, NULL),
+ {
+ return it;
+ });
return NULL;
}
#pragma once
+IntrusiveList g_teleporters;
+STATIC_INIT(g_teleporters) { g_teleporters = IL_NEW(); }
+
.entity pusher;
const float TELEPORT_FLAG_SOUND = 1;
const float TELEPORT_FLAG_PARTICLES = 2;
return;
}
+ IL_PUSH(g_teleporters, this);
+
this.teleport_next = teleport_first;
teleport_first = this;
}
NET_HANDLE(ENT_CLIENT_TRIGGER_TELEPORT, bool isnew)
{
this.classname = "trigger_teleport";
+ if(isnew)
+ IL_PUSH(g_teleporters, this);
int mytm = ReadByte(); if(mytm) { this.team = mytm - 1; }
this.spawnflags = ReadInt24_t();
this.active = ReadByte();
proj.velocity = normalize(actor.tur_shotdir_updated + randomvec() * actor.shot_spread) * actor.shot_speed;
proj.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, proj);
+ IL_PUSH(g_bot_dodge, proj);
proj.enemy = actor.enemy;
proj.totalfrags = _death;
PROJECTILE_MAKETRIGGER(proj);
if(!this.tur_head) {
tur.tr_precache(tur);
IL_PUSH(g_turrets, this);
+ IL_PUSH(g_bot_targets, this);
}
entity e = find(NULL, classname, "turret_manager");
void turret_targettrigger_touch(entity this, entity toucher)
{
if (this.cnt > time) return;
- FOREACH_ENTITY_STRING_ORDERED(targetname, this.target, {
+ IL_EACH(g_turrets, it.targetname == this.target,
+ {
if (!(it.turret_flags & TUR_FLAG_RECIEVETARGETS)) continue;
if (!it.turret_addtarget) continue;
it.turret_addtarget(it, toucher, this);
set_movetype(beam, MOVETYPE_NONE);
beam.enemy = actor.enemy;
beam.bot_dodge = true;
+ IL_PUSH(g_bot_dodge, beam);
beam.bot_dodgerating = beam.shot_dmg;
sound (beam, CH_SHOTS_SINGLE, SND_TUR_PHASER, VOL_BASE, ATTEN_NORM);
actor.fireflag = 1;
settouch(rocket, walker_rocket_touch);
rocket.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, rocket);
+ IL_PUSH(g_bot_dodge, rocket);
rocket.solid = SOLID_BBOX;
rocket.max_health = time + 9;
rocket.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_GUIDED_HEAT;
return 0;
}
- FOREACH_ENTITY_CLASS("saved_cvar_value", it.netname == tmp_cvar,
+ IL_EACH(g_saved_cvars, it.netname == tmp_cvar,
{
created_saved_value = -1; // skip creation
break; // no need to continue
{
// creating a new entity to keep track of this cvar
entity e = new_pure(saved_cvar_value);
+ IL_PUSH(g_saved_cvars, e);
e.netname = strzone(tmp_cvar);
e.message = strzone(cvar_string(tmp_cvar));
created_saved_value = 1;
vector real_origin(entity ent);
#endif
+IntrusiveList g_saved_cvars;
+STATIC_INIT(g_saved_cvars) { g_saved_cvars = IL_NEW(); }
+
// this returns a tempstring containing a copy of s with additional \n newlines added, it also replaces \n in the text with a real newline
// NOTE: s IS allowed to be a tempstring
string wordwrap(string s, float l);
set_movetype(proj, MOVETYPE_FLYMISSILE);
proj.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, proj);
+ IL_PUSH(g_bot_dodge, proj);
proj.bot_dodge = true;
proj.bot_dodgerating = _dmg;
proj.velocity = _vel;
void vehicles_clearreturn(entity veh)
{
// Remove "return helper" entities, if any.
- FOREACH_ENTITY_ENT(wp00, veh,
+ IL_EACH(g_vehicle_returners, it.wp00 == veh,
{
- if(it.classname == "vehicle_return")
- {
- it.classname = "";
- setthink(it, SUB_Remove);
- it.nextthink = time + 0.1;
+ it.classname = "";
+ setthink(it, SUB_Remove);
+ it.nextthink = time + 0.1;
+ IL_REMOVE(g_vehicle_returners, it);
- if(it.waypointsprite_attached)
- WaypointSprite_Kill(it.waypointsprite_attached);
- }
+ if(it.waypointsprite_attached)
+ WaypointSprite_Kill(it.waypointsprite_attached);
});
}
vehicles_clearreturn(veh);
entity ret = new(vehicle_return);
+ IL_PUSH(g_vehicle_returners, ret);
ret.wp00 = veh;
ret.team = veh.team;
setthink(ret, vehicles_showwp);
this.solid = SOLID_SLIDEBOX;
this.takedamage = DAMAGE_AIM;
this.deadflag = DEAD_NO;
+ if(!this.bot_attack)
+ IL_PUSH(g_bot_targets, this);
this.bot_attack = true;
this.flags = FL_NOTARGET;
this.avelocity = '0 0 0';
this.tur_head.owner = this;
this.takedamage = DAMAGE_NO;
this.bot_attack = true;
+ IL_PUSH(g_bot_targets, this);
this.iscreature = true;
this.teleportable = false; // no teleporting for vehicles, too buggy
this.damagedbycontents = true;
bool vehicles_crushable(entity e);
float vehicle_altitude(entity this, float amax);
+IntrusiveList g_vehicle_returners;
+STATIC_INIT(g_vehicle_returners) { g_vehicle_returners = IL_NEW(); }
+
#endif
void raptor_flare_think(entity this)
{
this.nextthink = time + 0.1;
- FOREACH_ENTITY_ENT(enemy, this.owner,
+ IL_EACH(g_projectiles, it.enemy == this.owner,
{
- if(it.flags & FL_PROJECTILE)
if(vdist(this.origin - it.origin, <, autocvar_g_vehicle_raptor_flare_range))
if(random() > autocvar_g_vehicle_raptor_flare_chase)
it.enemy = this;
{
vector spot;
- FOREACH_ENTITY_ENT(owner, this.owner,
+ IL_EACH(g_projectiles, it.owner == this.owner && it.classname == "spiderbot_rocket",
{
- if(it.classname != "spiderbot_rocket") continue;
it.realowner = this.owner;
it.owner = NULL;
});
void spiderbot_guide_release(entity this)
{
- FOREACH_ENTITY_ENT(realowner, this.owner,
+ bool donetrace = false;
+ IL_EACH(g_projectiles, it.realowner == this.owner && getthink(it) == spiderbot_rocket_guided,
{
- if(i == 0) // something exists, let's trace!
- crosshair_trace(this.owner);
-
- if(getthink(it) == spiderbot_rocket_guided)
+ if(!donetrace) // something exists, let's trace!
{
- it.pos1 = trace_endpos;
- setthink(it, spiderbot_rocket_unguided);
+ donetrace = true;
+ crosshair_trace(this.owner);
}
+
+ it.pos1 = trace_endpos;
+ setthink(it, spiderbot_rocket_unguided);
});
}
missile = new(missile);
missile.owner = missile.realowner = actor;
missile.bot_dodge = true;
+ IL_PUSH(g_bot_dodge, missile);
missile.bot_dodgerating = WEP_CVAR(arc, bolt_damage);
missile.takedamage = DAMAGE_YES;
beam.owner = actor;
set_movetype(beam, MOVETYPE_NONE);
beam.bot_dodge = true;
+ IL_PUSH(g_bot_dodge, beam);
beam.bot_dodgerating = WEP_CVAR(arc, beam_damage);
beam.beam_bursting = burst;
Net_LinkEntity(beam, false, 0, W_Arc_Beam_Send);
settouch(missile, W_Blaster_Touch);
missile.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, missile);
+ IL_PUSH(g_bot_dodge, missile);
missile.missile_flags = MIF_SPLASH;
missile.projectiledeathtype = atk_deathtype;
setthink(missile, W_Blaster_Think);
proj.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, proj);
+ IL_PUSH(g_bot_dodge, proj);
proj.missile_flags = MIF_SPLASH;
CSQCProjectile(proj, true, (proj.cnt ? PROJECTILE_CRYLINK_BOUNCING : PROJECTILE_CRYLINK), true);
proj.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, proj);
+ IL_PUSH(g_bot_dodge, proj);
proj.missile_flags = MIF_SPLASH;
CSQCProjectile(proj, true, (proj.cnt ? PROJECTILE_CRYLINK_BOUNCING : PROJECTILE_CRYLINK), true);
missile.cnt = time + WEP_CVAR(devastator, lifetime);
missile.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, missile);
+ IL_PUSH(g_bot_dodge, missile);
missile.missile_flags = MIF_SPLASH;
CSQCProjectile(missile, WEP_CVAR(devastator, guiderate) == 0 && WEP_CVAR(devastator, speedaccel) == 0, PROJECTILE_ROCKET, false); // because of fly sound
MUTATOR_CALLHOOK(EditProjectile, actor, missile);
}
-#if 0
-METHOD(Devastator, wr_aim, void(entity thiswep, entity actor))
-{
- entity this = actor;
- // aim and decide to fire if appropriate
- PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, WEP_CVAR(devastator, speed), 0, WEP_CVAR(devastator, lifetime), false);
- if(skill >= 2) // skill 0 and 1 bots won't detonate rockets!
- {
- // decide whether to detonate rockets
- entity missile, targetlist, targ;
- targetlist = findchainfloat(bot_attack, true);
- for(missile = NULL; (missile = find(missile, classname, "rocket")); ) if(missile.realowner == actor)
- {
- targ = targetlist;
- while(targ)
- {
- if(targ != missile.realowner && vlen(targ.origin - missile.origin) < WEP_CVAR(devastator, radius))
- {
- PHYS_INPUT_BUTTON_ATCK2(actor) = true;
- break;
- }
- targ = targ.chain;
- }
- }
-
- if(PHYS_INPUT_BUTTON_ATCK2(actor)) PHYS_INPUT_BUTTON_ATCK(actor) = false;
- }
-}
-#else
METHOD(Devastator, wr_aim, void(entity thiswep, entity actor))
{
// aim and decide to fire if appropriate
selfdamage = 0;
teamdamage = 0;
enemydamage = 0;
- FOREACH_ENTITY_ENT(realowner, actor,
+ IL_EACH(g_projectiles, it.realowner == actor && it.classname == "rocket",
{
- if(it.classname != "rocket") continue;
-
entity rocket = it;
- FOREACH_ENTITY_FLOAT(bot_attack, true,
+ IL_EACH(g_bot_targets, it.bot_attack,
{
float d = vlen(it.origin + (it.mins + it.maxs) * 0.5 - rocket.origin);
d = bound(0, edgedamage + (coredamage - edgedamage) * sqrt(1 - d * recipricoledgeradius), 10000);
desirabledamage = desirabledamage - teamdamage;
makevectors(actor.v_angle);
- FOREACH_ENTITY_ENT(realowner, actor,
+ IL_EACH(g_projectiles, it.realowner == actor && it.classname == "rocket",
{
- if(it.classname != "rocket") continue;
-
if(skill > 9) // normal players only do this for the target they are tracking
{
entity rocket = it;
- FOREACH_ENTITY_FLOAT(bot_attack, true,
+ IL_EACH(g_bot_targets, it.bot_attack,
{
if((v_forward * normalize(rocket.origin - it.origin) < 0.1)
&& desirabledamage > 0.1 * coredamage
if(PHYS_INPUT_BUTTON_ATCK2(actor)) PHYS_INPUT_BUTTON_ATCK(actor) = false;
}
}
-#endif
+
METHOD(Devastator, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
if(WEP_CVAR(devastator, reload_ammo) && actor.clip_load < WEP_CVAR(devastator, ammo)) { // forced reload
setsize(proj, '0 0 -3', '0 0 -3');
proj.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, proj);
+ IL_PUSH(g_bot_dodge, proj);
proj.missile_flags = MIF_SPLASH;
CSQCProjectile(proj, true, PROJECTILE_ELECTRO_BEAM, true);
newproj.nextthink = this.nextthink;
newproj.use = this.use;
newproj.flags = this.flags;
+ IL_PUSH(g_projectiles, newproj);
+ IL_PUSH(g_bot_dodge, newproj);
delete(this);
proj.event_damage = W_Electro_Orb_Damage;
proj.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, proj);
+ IL_PUSH(g_bot_dodge, proj);
proj.damagedbycontents = (WEP_CVAR_SEC(electro, damagedbycontents));
proj.bouncefactor = WEP_CVAR_SEC(electro, bouncefactor);
setsize(proj, '-16 -16 -16', '16 16 16');
proj.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, proj);
+ IL_PUSH(g_bot_dodge, proj);
proj.missile_flags = MIF_SPLASH | MIF_PROXY;
CSQCProjectile(proj, true, PROJECTILE_FIREBALL, true);
proj.angles = vectoangles(proj.velocity);
proj.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, proj);
+ IL_PUSH(g_bot_dodge, proj);
proj.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_ARC;
CSQCProjectile(proj, true, PROJECTILE_FIREMINE, true);
missile.angles = vectoangles(missile.velocity);
missile.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, missile);
+ IL_PUSH(g_bot_dodge, missile);
missile.missile_flags = MIF_SPLASH;
CSQCProjectile(missile, true, PROJECTILE_HAGAR, true);
missile.angles = vectoangles(missile.velocity);
missile.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, missile);
+ IL_PUSH(g_bot_dodge, missile);
missile.missile_flags = MIF_SPLASH;
CSQCProjectile(missile, true, PROJECTILE_HAGAR_BOUNCING, true);
missile.angles = vectoangles(missile.velocity);
missile.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, missile);
+ IL_PUSH(g_bot_dodge, missile);
CSQCProjectile(missile, true, PROJECTILE_HAGAR, true);
missile.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, missile);
+ IL_PUSH(g_bot_dodge, missile);
missile.projectiledeathtype = WEP_HLAC.m_id;
CSQCProjectile(missile, true, PROJECTILE_HLAC, true);
missile.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, missile);
+ IL_PUSH(g_bot_dodge, missile);
missile.missile_flags = MIF_SPLASH;
missile.projectiledeathtype = WEP_HLAC.m_id | HITTYPE_SECONDARY;
gren.angles = '0 0 0';
gren.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, gren);
+ IL_PUSH(g_bot_dodge, gren);
CSQCProjectile(gren, true, PROJECTILE_HOOKBOMB, true);
newmine.cnt = this.cnt;
newmine.flags = this.flags;
IL_PUSH(g_projectiles, newmine);
+ IL_PUSH(g_bot_dodge, newmine);
delete(this);
mine.cnt = (WEP_CVAR(minelayer, lifetime) - WEP_CVAR(minelayer, lifetime_countdown));
mine.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, mine);
+ IL_PUSH(g_bot_dodge, mine);
mine.missile_flags = MIF_SPLASH | MIF_ARC | MIF_PROXY;
if(mine.cnt > 0) { mine.cnt += time; }
IL_EACH(g_mines, it.realowner == actor,
{
entity mine = it;
- FOREACH_ENTITY_FLOAT(bot_attack, true,
+ IL_EACH(g_bot_targets, it.bot_attack,
{
float d = vlen(it.origin + (it.mins + it.maxs) * 0.5 - mine.origin);
d = bound(0, edgedamage + (coredamage - edgedamage) * sqrt(1 - d * recipricoledgeradius), 10000);
if(skill > 9) // normal players only do this for the target they are tracking
{
entity mine = it;
- FOREACH_ENTITY_FLOAT(bot_attack, true,
+ IL_EACH(g_bot_targets, it.bot_attack,
{
if((v_forward * normalize(mine.origin - it.origin) < 0.1)
&& desirabledamage > 0.1 * coredamage
gren.angles = vectoangles(gren.velocity);
gren.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, gren);
+ IL_PUSH(g_bot_dodge, gren);
if(WEP_CVAR_PRI(mortar, type) == 0 || WEP_CVAR_PRI(mortar, type) == 2)
CSQCProjectile(gren, true, PROJECTILE_GRENADE, true);
gren.angles = vectoangles(gren.velocity);
gren.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, gren);
+ IL_PUSH(g_bot_dodge, gren);
if(WEP_CVAR_SEC(mortar, type) == 0 || WEP_CVAR_SEC(mortar, type) == 2)
CSQCProjectile(gren, true, PROJECTILE_GRENADE, true);
if(move_out_of_solid(this))
{
this.flags = FL_ITEM;
+ IL_PUSH(g_items, this);
this.velocity = trigger_push_calculatevelocity(this.origin, this.realowner, 128);
tracetoss(this, this);
if(vdist(trace_endpos - this.realowner.origin, <, 128))
gren.angles = vectoangles(gren.velocity);
gren.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, gren);
+ IL_PUSH(g_bot_dodge, gren);
gren.portal_id = time;
actor.porto_current = gren;
set_movetype(missile, MOVETYPE_FLYMISSILE);
missile.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, missile);
+ IL_PUSH(g_bot_dodge, missile);
missile.missile_flags = MIF_SPLASH | MIF_GUIDED_TAG;
W_SetupProjVelocity_UP_PRE(missile, seeker, missile_);
missile.projectiledeathtype = WEP_SEEKER.m_id | HITTYPE_SECONDARY;
missile.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, missile);
+ IL_PUSH(g_bot_dodge, missile);
missile.missile_flags = MIF_SPLASH;
// csqc projectiles
missile.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, missile);
+ IL_PUSH(g_bot_dodge, missile);
//missile.missile_flags = MIF_..?;
set_movetype(missile, MOVETYPE_FLY);
setsize(proj, '0 0 -3', '0 0 -3');
proj.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, proj);
+ IL_PUSH(g_bot_dodge, proj);
proj.missile_flags = MIF_SPLASH;
CSQCProjectile(proj, true, PROJECTILE_ROCKETMINSTA_LASER, true);
setsize(proj, '0 0 -3', '0 0 -3');
proj.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, proj);
+ IL_PUSH(g_bot_dodge, proj);
proj.missile_flags = MIF_SPLASH;
CSQCProjectile(proj, true, PROJECTILE_ROCKETMINSTA_LASER, true);
.int Version; // deprecated, use SendFlags
.int SendFlags;
+ IntrusiveList g_uncustomizables;
+ STATIC_INIT(g_uncustomizables) { g_uncustomizables = IL_NEW(); }
+
void Net_LinkEntity(entity e, bool docull, float dt, bool(entity this, entity to, int sendflags) sendfunc)
{
if (e.classname == "") e.classname = "net_linked";
setcefc(e, customizer);
e.uncustomizeentityforclient = uncustomizer;
e.uncustomizeentityforclient_set = !!uncustomizer;
+ if(uncustomizer)
+ IL_PUSH(g_uncustomizables, e);
}
void UncustomizeEntitiesRun()
{
- FOREACH_ENTITY_FLOAT(uncustomizeentityforclient_set, true, it.uncustomizeentityforclient(it));
+ IL_EACH(g_uncustomizables, it.uncustomizeentityforclient_set, it.uncustomizeentityforclient(it));
}
STRING_ITERATOR(g_buf, string_null, 0);
entity find_bot_by_name(string name);
entity find_bot_by_number(float number);
-void havocbot_goalrating_controlpoints(entity this, float ratingscale, vector org, float sradius);
void havocbot_goalrating_enemyplayers(entity this, float ratingscale, vector org, float sradius);
void havocbot_goalrating_items(entity this, float ratingscale, vector org, float sradius);
int bestcount = 0;
int bcount = 0;
- FOREACH_ENTITY_FLOAT(isbot, true,
+ FOREACH_CLIENT(it.isbot,
{
++bcount;
entity best = NULL;
int bcount = 0;
- FOREACH_ENTITY_FLOAT(isbot, true,
+ FOREACH_CLIENT(it.isbot,
{
++bcount;
#include <common/state.qh>
#include <common/items/_mod.qh>
+#include <common/triggers/teleporters.qh>
#include <common/triggers/trigger/jumppads.qh>
#include <lib/warpzone/common.qh>
if (((dodge * v_up) < 0) && random()*frametime >= 0.5*bound(0,(10-skill-this.bot_dodgeskill)*0.1,1)) this.havocbot_ducktime=time+0.3/bound(0.1,skill+this.bot_dodgeskill,10);
}
+entity havocbot_gettarget(entity this, bool secondary)
+{
+ entity best = NULL;
+ vector eye = CENTER_OR_VIEWOFS(this);
+ IL_EACH(g_bot_targets, boolean((secondary) ? it.classname == "misc_breakablemodel" : it.classname != "misc_breakablemodel"),
+ {
+ vector v = CENTER_OR_VIEWOFS(it);
+ if(vdist(v - eye, <, autocvar_bot_ai_enemydetectionradius))
+ if(!best || vlen2(CENTER_OR_VIEWOFS(best) - eye) > vlen2(v - eye))
+ if(bot_shouldattack(this, it))
+ {
+ traceline(eye, v, true, this);
+ if (trace_ent == it || trace_fraction >= 1)
+ best = it;
+ }
+ });
+
+ return best;
+}
+
void havocbot_chooseenemy(entity this)
{
entity head, best, head2;
this.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_LINKING;
// if pos is inside a teleport, then let's mark it as teleport waypoint
- FOREACH_ENTITY_CLASS("trigger_teleport", WarpZoneLib_BoxTouchesBrush(pos, pos, it, NULL),
+ IL_EACH(g_teleporters, WarpZoneLib_BoxTouchesBrush(pos, pos, it, NULL),
{
wp.wpflags |= WAYPOINTFLAG_TELEPORT;
this.lastteleporttime = 0;
vector o;
ratingscale = ratingscale * 0.0001; // items are rated around 10000 already
- FOREACH_ENTITY_FLOAT(bot_pickup, true,
+ IL_EACH(g_items, it.bot_pickup,
{
o = (it.absmin + it.absmax) * 0.5;
friend_distance = 10000; enemy_distance = 10000;
});
}
-void havocbot_goalrating_controlpoints(entity this, float ratingscale, vector org, float sradius)
-{
- FOREACH_ENTITY_CLASS("dom_controlpoint", vdist((((it.absmin + it.absmax) * 0.5) - org), <, sradius),
- {
- if(it.cnt > -1) // this is just being fought
- navigation_routerating(this, it, ratingscale, 5000);
- else if(it.goalentity.cnt == 0) // unclaimed
- navigation_routerating(this, it, ratingscale * 0.5, 5000);
- else if(it.goalentity.team != this.team) // other team's point
- navigation_routerating(this, it, ratingscale * 0.2, 5000);
- });
-}
-
void havocbot_goalrating_enemyplayers(entity this, float ratingscale, vector org, float sradius)
{
if (autocvar_bot_nofire)
#pragma once
-void havocbot_goalrating_controlpoints(entity this, float ratingscale, vector org, float sradius);
danger = 0;
m1 = it.mins;
m2 = it.maxs;
- FOREACH_ENTITY_FLOAT(bot_dodge, true,
+ IL_EACH(g_bot_dodge, it.bot_dodge,
{
v = it.origin;
v.x = bound(m1_x, v.x, m2_x);
// Returns first bot with matching name
entity find_bot_by_name(string name)
{
- entity bot;
-
- bot = findchainflags(flags, FL_CLIENT);
- while (bot)
+ FOREACH_CLIENT(IS_BOT_CLIENT(it) && it.netname == name,
{
- if(IS_BOT_CLIENT(bot))
- if(bot.netname==name)
- return bot;
-
- bot = bot.chain;
- }
+ return it;
+ });
return NULL;
}
void botframe_deleteuselesswaypoints()
{
- FOREACH_ENTITY_FLOAT(bot_pickup, true,
+ IL_EACH(g_items, it.bot_pickup,
{
// NOTE: this protects waypoints if they're the ONLY nearest
// waypoint. That's the intention.
entity find_bot_by_name(string name) { return NULL; }
entity find_bot_by_number(float number) { return NULL; }
-void havocbot_goalrating_controlpoints(entity this, float ratingscale, vector org, float sradius) { }
void havocbot_goalrating_enemyplayers(entity this, float ratingscale, vector org, float sradius) { }
void havocbot_goalrating_items(entity this, float ratingscale, vector org, float sradius) { }
break;
}
- if((draggee.flags & FL_ITEM) && (vlen(draggee.velocity) < 32))
+ if((draggee.flags & FL_ITEM) && (vdist(draggee.velocity, <, 32)))
{
draggee.velocity = '0 0 0';
SET_ONGROUND(draggee); // floating items are FUN
#include <common/effects/qc/globalsound.qh>
+#include "../common/triggers/func/conveyor.qh"
#include "../common/triggers/teleporters.qh"
#include "../common/vehicles/all.qh"
accuracy_resend(this);
this.spectatortime = time;
+ if(this.bot_attack)
+ IL_REMOVE(g_bot_targets, this);
this.bot_attack = false;
this.hud = HUD_NORMAL;
TRANSMUTE(Observer, this);
this.oldorigin = this.origin;
this.prevorigin = this.origin;
this.lastteleporttime = time; // prevent insane speeds due to changing origin
+ if(this.conveyor)
+ IL_REMOVE(g_conveyed, this);
this.conveyor = NULL; // prevent conveyors at the previous location from moving a freshly spawned player
this.hud = HUD_NORMAL;
this.event_damage = PlayerDamage;
+ if(!this.bot_attack)
+ IL_PUSH(g_bot_targets, this);
this.bot_attack = true;
this.monster_attack = true;
this.killindicator.count = bound(0, ceil(killtime), 10);
//sprint(this, strcat("^1You'll be dead in ", ftos(this.killindicator.cnt), " seconds\n"));
- FOREACH_ENTITY_ENT(enemy, this,
+ IL_EACH(g_clones, it.enemy == this && !(it.effects & CSQCMODEL_EF_RESPAWNGHOST),
{
- if(it.classname != "body")
- continue;
it.killindicator = spawn();
it.killindicator.owner = it;
it.killindicator.scale = 0.5;
if (IS_REAL_CLIENT(this))
sv_notice_join(this);
- FOREACH_ENTITY_FLOAT(init_for_player_needed, true, {
+ IL_EACH(g_initforplayer, it.init_for_player, {
it.init_for_player(it, this);
});
void ClientState_attach(entity this);
+IntrusiveList g_players;
+STATIC_INIT(g_players) { g_players = IL_NEW(); }
+
CLASS(Client, Object)
/** Client name */
ATTRIB(Client, netname, string, this.netname);
CLASS(Player, Client)
INIT(Player) {
this.classname = STR_PLAYER;
+ IL_PUSH(g_players, this);
+ }
+ DESTRUCTOR(Player) {
+ IL_REMOVE(g_players, this);
}
- DESTRUCTOR(Player) { }
ENDCLASS(Player)
METHOD(Client, m_unwind, bool(Client this))
.string cvar_cl_physics;
-.bool init_for_player_needed;
.void(entity this, entity player) init_for_player;
IntrusiveList g_monsters;
IntrusiveList g_projectiles;
STATIC_INIT(g_projectiles) { g_projectiles = IL_NEW(); }
+
+IntrusiveList g_items;
+STATIC_INIT(g_items) { g_items = IL_NEW(); }
+
+IntrusiveList g_initforplayer;
+STATIC_INIT(g_initforplayer) { g_initforplayer = IL_NEW(); }
+
+IntrusiveList g_clones;
+STATIC_INIT(g_clones) { g_clones = IL_NEW(); }
+
+IntrusiveList g_assault_destructibles;
+STATIC_INIT(g_assault_destructibles) { g_assault_destructibles = IL_NEW(); }
+
+IntrusiveList g_assault_objectivedecreasers;
+STATIC_INIT(g_assault_objectivedecreasers) { g_assault_objectivedecreasers = IL_NEW(); }
+
+IntrusiveList g_assault_objectives;
+STATIC_INIT(g_assault_objectives) { g_assault_objectives = IL_NEW(); }
+
+IntrusiveList g_spawnpoints;
+STATIC_INIT(g_spawnpoints) { g_spawnpoints = IL_NEW(); }
+
+IntrusiveList g_bot_targets;
+STATIC_INIT(g_bot_targets) { g_bot_targets = IL_NEW(); }
+
+IntrusiveList g_bot_dodge;
+STATIC_INIT(g_bot_dodge) { g_bot_dodge = IL_NEW(); }
targ.revive_progress = ((frozen_type == 3) ? 1 : 0);
targ.health = ((frozen_type == 3) ? targ_maxhealth : 1);
targ.revive_speed = freeze_time;
+ if(targ.bot_attack)
+ IL_REMOVE(g_bot_targets, targ);
targ.bot_attack = false;
entity ice = new(ice);
STAT(FROZEN, targ) = 0;
targ.revive_progress = 0;
targ.revival_time = time;
+ if(!targ.bot_attack)
+ IL_PUSH(g_bot_targets, targ);
targ.bot_attack = true;
WaypointSprite_Kill(targ.waypointsprite_attached);
missile.classname = "grapplinghook";
missile.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, missile);
+ IL_PUSH(g_bot_dodge, missile);
set_movetype(missile, ((autocvar_g_balance_grapplehook_gravity) ? MOVETYPE_TOSS : MOVETYPE_FLY));
PROJECTILE_MAKETRIGGER(missile);
static_init_late();
static_init_precache();
+ IL_PUSH(g_spawnpoints, e); // just incase
+
MapInfo_Enumerate();
MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
}
}
));
- FOREACH_ENTITY_CLASS("info_player_deathmatch", true, LAMBDA(
+ IL_EACH(g_spawnpoints, true,
+ {
switch(it.team)
{
case NUM_TEAM_1: team1_score = 1; break;
case NUM_TEAM_3: team3_score = 1; break;
case NUM_TEAM_4: team4_score = 1; break;
}
- ));
+ });
ClearWinners();
if(team1_score + team2_score + team3_score + team4_score == 0)
if (m) LOG_INFOF("%d waypoints have been marked total\n", m);
j = 0;
- FOREACH_ENTITY_CLASS("info_player_deathmatch", true,
+ IL_EACH(g_spawnpoints, true,
{
vector org = it.origin;
tracebox(it.origin, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin - '0 0 512', MOVE_NOMONSTERS, NULL);
if (j) LOG_INFOF("%d spawnpoints have no nearest waypoint (marked by player model)\n", j);
j = 0;
- FOREACH_ENTITY_FLAGS(flags, FL_ITEM,
+ IL_EACH(g_items, true,
{
it.effects &= ~(EF_NODEPTHTEST | EF_RED | EF_BLUE);
it.colormod = '0.5 0.5 0.5';
});
- FOREACH_ENTITY_FLAGS(flags, FL_ITEM,
+ IL_EACH(g_items, true,
{
if (navigation_findnearestwaypoint(it, false)) continue;
LOG_INFO("item without waypoint: ", etos(it), " ", vtos(it.origin), "\n");
if (j) LOG_INFOF("%d items have no nearest waypoint and cannot be walked away from (marked with red light)\n", j);
j = 0;
- FOREACH_ENTITY_FLAGS(flags, FL_ITEM,
+ IL_EACH(g_items, true,
{
if (navigation_findnearestwaypoint(it, true)) continue;
LOG_INFO("item without waypoint: ", etos(it), " ", vtos(it.origin), "\n");
{
float m, i;
vector start, org, delta, end, enddown, mstart;
- entity sp;
m = e.dphitcontentsmask;
e.dphitcontentsmask = goodcontents | badcontents;
continue;
// rule 4: we must "see" some spawnpoint or item
- for(sp = NULL; (sp = find(sp, classname, "info_player_deathmatch")); )
- if(checkpvs(mstart, sp))
- if((traceline(mstart, sp.origin, MOVE_NORMAL, e), trace_fraction) >= 1)
- break;
+ entity sp = NULL;
+ IL_EACH(g_spawnpoints, checkpvs(mstart, it),
+ {
+ if((traceline(mstart, it.origin, MOVE_NORMAL, e), trace_fraction) >= 1)
+ {
+ sp = it;
+ break;
+ }
+ });
if(!sp)
{
- for(sp = NULL; (sp = findflags(sp, flags, FL_ITEM)); )
- if(checkpvs(mstart, sp))
- if((traceline(mstart, sp.origin + (sp.mins + sp.maxs) * 0.5, MOVE_NORMAL, e), trace_fraction) >= 1)
- break;
+ IL_EACH(g_items, checkpvs(mstart, it),
+ {
+ if((traceline(mstart, it.origin + (it.mins + it.maxs) * 0.5, MOVE_NORMAL, e), trace_fraction) >= 1)
+ {
+ sp = it;
+ break;
+ }
+ });
+
if(!sp)
continue;
}
//print("^2Activated objective ", this.targetname, "=", etos(this), "\n");
//print("Activator is ", actor.classname, "\n");
- for (entity e = NULL; (e = find(e, target, this.targetname)); )
+ IL_EACH(g_assault_objectivedecreasers, it.target == this.targetname,
{
- if (e.classname == "target_objective_decrease")
- {
- target_objective_decrease_activate(e);
- }
- }
+ target_objective_decrease_activate(it);
+ });
}
vector target_objective_spawn_evalfunc(entity this, entity player, entity spot, vector current)
void assault_setenemytoobjective(entity this)
{
- FOREACH_ENTITY_STRING(targetname, this.target,
+ IL_EACH(g_assault_objectives, it.targetname == this.target,
{
- if(it.classname == "target_objective")
- {
- if(this.enemy == NULL)
- this.enemy = it;
- else
- objerror(this, "more than one objective as target - fix the map!");
- break;
- }
+ if(this.enemy == NULL)
+ this.enemy = it;
+ else
+ objerror(this, "more than one objective as target - fix the map!");
+ break;
});
if(this.enemy == NULL)
SUB_UseTargets(this, this, trigger);
//(Re)spawn all turrets
- FOREACH_ENTITY_CLASS("turret_main", true, LAMBDA(
+ IL_EACH(g_turrets, true,
+ {
// Swap turret teams
if(it.team == NUM_TEAM_1)
it.team = NUM_TEAM_2;
// Doubles as teamchange
turret_respawn(it);
- ));
+ });
}
void assault_roundstart_use_this(entity this)
{
if (!g_assault) { delete(this); return; }
this.classname = "target_objective";
+ IL_PUSH(g_assault_objectives, this);
this.use = assault_objective_use;
this.reset = assault_objective_reset;
this.reset(this);
if (!g_assault) { delete(this); return; }
this.classname = "target_objective_decrease";
+ IL_PUSH(g_assault_objectivedecreasers, this);
if(!this.dmg)
this.dmg = 101;
this.spawnflags = 3;
this.classname = "func_assault_destructible";
+ IL_PUSH(g_assault_destructibles, this);
if(assault_attacker_team == NUM_TEAM_1)
this.team = NUM_TEAM_2;
// legacy bot code
void havocbot_goalrating_ast_targets(entity this, float ratingscale)
{
- FOREACH_ENTITY_CLASS("func_assault_destructible", it.bot_attack,
+ IL_EACH(g_assault_destructibles, it.bot_attack,
{
if (it.target == "")
continue;
bool found = false;
- FOREACH_ENTITY_STRING(targetname, it.target,
+ entity destr = it;
+ IL_EACH(g_assault_objectivedecreasers, it.targetname == destr.target,
{
- if(it.classname != "target_objective_decrease")
- continue;
-
if(it.enemy.health > 0 && it.enemy.health < ASSAULT_VALUE_INACTIVE)
{
found = true;
flag.classname = "item_flag_team";
flag.target = "###item###"; // wut?
flag.flags = FL_ITEM | FL_NOTARGET;
+ IL_PUSH(g_items, flag);
flag.solid = SOLID_TRIGGER;
flag.takedamage = DAMAGE_NO;
flag.damageforcescale = autocvar_g_ctf_flag_damageforcescale;
void havocbot_goalrating_ctf_carrieritems(entity this, float ratingscale, vector org, float sradius)
{
- FOREACH_ENTITY_FLOAT(bot_pickup, true,
+ IL_EACH(g_items, it.bot_pickup,
{
// gather health and armor only
if (it.solid)
this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
navigation_goalrating_start(this);
- FOREACH_ENTITY_CLASS("trigger_race_checkpoint", true,
+ IL_EACH(g_racecheckpoints, true,
{
if(it.cnt == this.race_checkpoint)
navigation_routerating(this, it, 1000000, 5000);
WaypointSprite_UpdateSprites(this.sprite, msg, WP_Null, WP_Null);
total_pps = 0, pps_red = 0, pps_blue = 0, pps_yellow = 0, pps_pink = 0;
- FOREACH_ENTITY_CLASS("dom_controlpoint", true, LAMBDA(
+ IL_EACH(g_dompoints, true,
+ {
if (autocvar_g_domination_point_amt)
points = autocvar_g_domination_point_amt;
else
case NUM_TEAM_4: pps_pink += points/wait_time; break;
}
total_pps += points/wait_time;
- ));
+ });
WaypointSprite_UpdateTeamRadar(this.sprite, RADARICON_DOMPOINT, colormapPaletteColor(this.goalentity.team - 1, 0));
WaypointSprite_Ping(this.sprite);
this.nextthink = time;
settouch(this, dompointtouch);
this.solid = SOLID_TRIGGER;
+ if(!this.flags & FL_ITEM)
+ IL_PUSH(g_items, this);
this.flags = FL_ITEM;
setsize(this, '-32 -32 -32', '32 32 32');
setorigin(this, this.origin + '0 0 20');
void Domination_count_controlpoints()
{
total_controlpoints = redowned = blueowned = yellowowned = pinkowned = 0;
- FOREACH_ENTITY_CLASS("dom_controlpoint", true,
+ IL_EACH(g_dompoints, true,
{
++total_controlpoints;
redowned += (it.goalentity.team == NUM_TEAM_1);
}
//go to best items, or control points you don't own
+void havocbot_goalrating_controlpoints(entity this, float ratingscale, vector org, float sradius)
+{
+ IL_EACH(g_dompoints, vdist((((it.absmin + it.absmax) * 0.5) - org), <, sradius),
+ {
+ if(it.cnt > -1) // this is just being fought
+ navigation_routerating(this, it, ratingscale, 5000);
+ else if(it.goalentity.cnt == 0) // unclaimed
+ navigation_routerating(this, it, ratingscale * 0.5, 5000);
+ else if(it.goalentity.team != this.team) // other team's point
+ navigation_routerating(this, it, ratingscale * 0.2, 5000);
+ });
+}
+
void havocbot_role_dom(entity this)
{
if(IS_DEAD(this))
this.effects = this.effects | EF_LOWPRECISION;
if (autocvar_g_domination_point_fullbright)
this.effects |= EF_FULLBRIGHT;
+
+ IL_PUSH(g_dompoints, this);
}
/*QUAKED spawnfunc_dom_team (0 .5 .8) (-32 -32 -24) (32 32 32)
float domination_teams;
void AnimateDomPoint(entity this);
+
+IntrusiveList g_dompoints;
+STATIC_INIT(g_dompoints) { g_dompoints = IL_NEW(); }
#include <server/teamplay.qh>
+IntrusiveList g_invasion_spawns;
+STATIC_INIT(g_invasion_spawns) { g_invasion_spawns = IL_NEW(); }
float autocvar_g_invasion_round_timelimit;
float autocvar_g_invasion_spawnpoint_spawn_delay;
if(!g_invasion) { delete(this); return; }
this.classname = "invasion_spawnpoint";
+ IL_PUSH(g_invasion_spawns, this);
if(autocvar_g_invasion_zombies_only) // precache only if it hasn't been already
if(this.monsterid) {
{
RandomSelection_Init();
- FOREACH_ENTITY_CLASS("invasion_spawnpoint", true,
+ IL_EACH(g_invasion_spawns, true,
{
RandomSelection_Add(it, 0, string_null, 1, ((time >= it.spawnshieldtime) ? 0.2 : 1)); // give recently used spawnpoints a very low rating
it.spawnshieldtime = time + autocvar_g_invasion_spawnpoint_spawn_delay;
{
entity player = M_ARGV(0, entity);
+ if(player.bot_attack)
+ IL_REMOVE(g_bot_targets, player);
player.bot_attack = false;
}
e.glow_color = autocvar_g_keepawayball_trail_color;
e.glow_trail = true;
e.flags = FL_ITEM;
+ IL_PUSH(g_items, e);
e.pushable = true;
e.reset = ka_Reset;
settouch(e, ka_TouchEvent);
key.angles_y += key.owner.angles.y;
#endif
key.flags = FL_ITEM;
+ IL_PUSH(g_items, key);
key.solid = SOLID_TRIGGER;
set_movetype(key, MOVETYPE_TOSS);
key.pain_finished = time + autocvar_g_balance_keyhunt_delay_return;
if(IS_DEAD(this))
return;
- entity e;
if (this.bot_strategytime < time)
{
this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
navigation_goalrating_start(this);
- for(e = NULL; (e = find(e, classname, "trigger_race_checkpoint")) != NULL; )
+ IL_EACH(g_racecheckpoints, true,
{
- if(e.cnt == this.race_checkpoint)
+ if(it.cnt == this.race_checkpoint)
{
- navigation_routerating(this, e, 1000000, 5000);
+ navigation_routerating(this, it, 1000000, 5000);
}
else if(this.race_checkpoint == -1)
{
- navigation_routerating(this, e, 1000000, 5000);
+ navigation_routerating(this, it, 1000000, 5000);
}
- }
+ });
navigation_goalrating_end(this);
}
animdecide_load_if_needed(clone);
animdecide_setframes(clone, false, frame, frame1time, frame2, frame2time);
+ IL_PUSH(g_clones, clone);
+
MUTATOR_CALLHOOK(CopyBody, this, clone, keepvelocity);
}
race_timed_checkpoint = 255;
}
} else {
- for (entity cp = NULL; (cp = find(cp, classname, "trigger_race_checkpoint")); ) {
- if (cp.sprite) {
- if (cp.race_checkpoint == 0) {
- WaypointSprite_UpdateSprites(cp.sprite, WP_RaceStart, WP_Null, WP_Null);
- } else if (cp.race_checkpoint == race_timed_checkpoint) {
- WaypointSprite_UpdateSprites(cp.sprite, WP_RaceFinish, WP_Null, WP_Null);
- }
+ IL_EACH(g_racecheckpoints, it.sprite,
+ {
+ if (it.race_checkpoint == 0) {
+ WaypointSprite_UpdateSprites(it.sprite, WP_RaceStart, WP_Null, WP_Null);
+ } else if (it.race_checkpoint == race_timed_checkpoint) {
+ WaypointSprite_UpdateSprites(it.sprite, WP_RaceFinish, WP_Null, WP_Null);
}
- }
+ });
}
}
this.sprite.waypointsprite_visible_for_player = race_waypointsprite_visible_for_player;
this.spawn_evalfunc = trigger_race_checkpoint_spawn_evalfunc;
+ IL_PUSH(g_racecheckpoints, this);
+
InitializeEntity(this, trigger_race_checkpoint_verify, INITPRIO_FINDTARGET);
}
vector o0, o1;
float bestfraction, fraction;
- entity lastcp, cp0, cp1;
+ entity lastcp;
float nextcpindex, lastcpindex;
nextcpindex = max(e.race_checkpoint, 0);
return l; // finish
bestfraction = 1;
- for(cp0 = NULL; (cp0 = find(cp0, classname, "trigger_race_checkpoint")); )
+ IL_EACH(g_racecheckpoints, true,
{
- if(cp0.race_checkpoint != lastcpindex)
+ if(it.race_checkpoint != lastcpindex)
continue;
if(lastcp)
- if(cp0 != lastcp)
+ if(it != lastcp)
continue;
- o0 = (cp0.absmin + cp0.absmax) * 0.5;
- for(cp1 = NULL; (cp1 = find(cp1, classname, "trigger_race_checkpoint")); )
+ o0 = (it.absmin + it.absmax) * 0.5;
+ IL_EACH(g_racecheckpoints, true,
{
- if(cp1.race_checkpoint != nextcpindex)
+ if(it.race_checkpoint != nextcpindex)
continue;
- o1 = (cp1.absmin + cp1.absmax) * 0.5;
+ o1 = (it.absmin + it.absmax) * 0.5;
if(o0 == o1)
continue;
fraction = bound(0.0001, vlen(e.origin - o1) / vlen(o0 - o1), 1);
if(fraction < bestfraction)
bestfraction = fraction;
- }
- }
+ });
+ });
// we are at CP "nextcpindex - bestfraction"
// race_timed_checkpoint == 4: then nextcp==4 means 0.9999x, nextcp==0 means 0.0000x
.float race_respawn_checkpoint;
.entity race_respawn_spotref; // try THIS spawn in case you respawn
+IntrusiveList g_racecheckpoints;
+STATIC_INIT(g_racecheckpoints) { g_racecheckpoints = IL_NEW(); }
+
// definitions for functions used outside race.qc
float race_PreviousCheckpoint(float f);
float race_NextCheckpoint(float f);
spawnfunc(info_player_deathmatch)
{
this.classname = "info_player_deathmatch";
+ IL_PUSH(g_spawnpoints, this);
relocate_spawnpoint(this);
}
void StartFrame()
{
// TODO: if move is more than 50ms, split it into two moves (this matches QWSV behavior and the client prediction)
- FOREACH_ENTITY_CLASS(STR_PLAYER, IS_FAKE_CLIENT(it), sys_phys_update(it, frametime));
- FOREACH_ENTITY_CLASS(STR_PLAYER, IS_FAKE_CLIENT(it), PlayerPreThink(it));
+ IL_EACH(g_players, IS_FAKE_CLIENT(it), sys_phys_update(it, frametime));
+ IL_EACH(g_players, IS_FAKE_CLIENT(it), PlayerPreThink(it));
execute_next_frame();
if (autocvar_sv_autopause && !server_is_dedicated) Pause_TryPause(true);
}
#endif
- FOREACH_ENTITY_FLOAT(csqcprojectile_clientanimate, true, CSQCProjectile_Check(it));
+ IL_EACH(g_projectiles, it.csqcprojectile_clientanimate, CSQCProjectile_Check(it));
if (RedirectionThink()) return;
MUTATOR_CALLHOOK(SV_StartFrame);
FOREACH_CLIENT(true, GlobalStats_update(it));
- FOREACH_ENTITY_CLASS(STR_PLAYER, IS_FAKE_CLIENT(it), PlayerPostThink(it));
+ IL_EACH(g_players, IS_FAKE_CLIENT(it), PlayerPostThink(it));
}
.vector originjitter;
// weapon give ent from defrag
void target_give_init(entity this)
{
- entity targ;
- for (targ = NULL; (targ = find(targ, targetname, this.target)); ) {
- if (targ.classname == "weapon_rocketlauncher" || targ.classname == "weapon_devastator") {
- this.ammo_rockets += targ.count * WEP_CVAR(devastator, ammo);
+ IL_EACH(g_items, it.targetname == this.target,
+ {
+ if (it.classname == "weapon_rocketlauncher" || it.classname == "weapon_devastator") {
+ this.ammo_rockets += it.count * WEP_CVAR(devastator, ammo);
this.netname = "devastator";
}
- else if (targ.classname == "weapon_plasmagun") {
- this.ammo_rockets += targ.count * WEP_CVAR_PRI(hagar, ammo); // WEAPONTODO
+ else if (it.classname == "weapon_plasmagun") {
+ this.ammo_rockets += it.count * WEP_CVAR_PRI(hagar, ammo); // WEAPONTODO
if(this.netname == "")
this.netname = "hagar";
else
this.netname = strcat(this.netname, " hagar");
}
- else if (targ.classname == "weapon_bfg") {
- this.ammo_cells += targ.count * WEP_CVAR_PRI(crylink, ammo);
+ else if (it.classname == "weapon_bfg") {
+ this.ammo_cells += it.count * WEP_CVAR_PRI(crylink, ammo);
if(this.netname == "")
this.netname = "crylink";
else
this.netname = strcat(this.netname, " crylink");
}
- else if (targ.classname == "weapon_grenadelauncher" || targ.classname == "weapon_mortar") {
- this.ammo_rockets += targ.count * WEP_CVAR_PRI(mortar, ammo); // WEAPONTODO
+ else if (it.classname == "weapon_grenadelauncher" || it.classname == "weapon_mortar") {
+ this.ammo_rockets += it.count * WEP_CVAR_PRI(mortar, ammo); // WEAPONTODO
if(this.netname == "")
this.netname = "mortar";
else
this.netname = strcat(this.netname, " mortar");
}
- else if (targ.classname == "item_armor_body")
+ else if (it.classname == "item_armor_body")
this.armorvalue = 100;
- else if (targ.classname == "item_health_mega")
+ else if (it.classname == "item_health_mega")
this.health = 200;
- //remove(targ); // removing ents in init functions causes havoc, workaround:
- setthink(targ, SUB_Remove);
- targ.nextthink = time;
- }
+ //remove(it); // removing ents in init functions causes havoc, workaround:
+ setthink(it, SUB_Remove);
+ it.nextthink = time;
+ });
this.spawnflags = 2;
spawnfunc_target_items(this);
InitializeEntity(this, target_init_verify, INITPRIO_FINDTARGET);
void Weapon_whereis(Weapon this, entity cl)
{
if (!autocvar_g_showweaponspawns) return;
- FOREACH_ENTITY_FLOAT(weapon, this.m_id,
+ IL_EACH(g_items, it.weapon == this.m_id,
{
if (it.classname == "droppedweapon" && autocvar_g_showweaponspawns < 2)
continue;
- if (!(it.flags & FL_ITEM))
- continue;
entity wp = WaypointSprite_Spawn(
WP_Weapon,
-2, 0,