From 63cf60651482d650ae40d005bd4847d5111123a9 Mon Sep 17 00:00:00 2001 From: Mario Date: Mon, 22 Aug 2016 16:42:38 +1000 Subject: [PATCH] Intrusify bot targets --- .../gamemode/onslaught/sv_onslaught.qc | 7 ++ qcsrc/common/monsters/sv_monsters.qc | 1 + qcsrc/common/triggers/func/breakable.qc | 4 + qcsrc/common/turrets/sv_turrets.qc | 1 + qcsrc/common/vehicles/sv_vehicles.qc | 2 + qcsrc/common/weapons/weapon/devastator.qc | 4 +- qcsrc/common/weapons/weapon/minelayer.qc | 4 +- qcsrc/server/bot/default/havocbot/havocbot.qc | 98 ++++++------------- qcsrc/server/client.qc | 4 + qcsrc/server/defs.qh | 3 + qcsrc/server/g_damage.qc | 4 + .../mutators/mutator/gamemode_invasion.qc | 2 + 12 files changed, 61 insertions(+), 73 deletions(-) diff --git a/qcsrc/common/gamemodes/gamemode/onslaught/sv_onslaught.qc b/qcsrc/common/gamemodes/gamemode/onslaught/sv_onslaught.qc index 643a02954c..3f48fd15a9 100644 --- a/qcsrc/common/gamemodes/gamemode/onslaught/sv_onslaught.qc +++ b/qcsrc/common/gamemodes/gamemode/onslaught/sv_onslaught.qc @@ -196,12 +196,16 @@ void onslaught_updatelinks() { 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; } @@ -566,6 +570,7 @@ void ons_ControlPoint_Icon_Spawn(entity cp, entity player) 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; @@ -917,6 +922,7 @@ void ons_GeneratorReset(entity this) 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; @@ -979,6 +985,7 @@ void ons_GeneratorSetup(entity gen) // called when spawning a generator entity o 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); diff --git a/qcsrc/common/monsters/sv_monsters.qc b/qcsrc/common/monsters/sv_monsters.qc index a4f7e6acaa..1fbb410da0 100644 --- a/qcsrc/common/monsters/sv_monsters.qc +++ b/qcsrc/common/monsters/sv_monsters.qc @@ -1324,6 +1324,7 @@ bool Monster_Spawn(entity this, int mon_id) 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; diff --git a/qcsrc/common/triggers/func/breakable.qc b/qcsrc/common/triggers/func/breakable.qc index b922a65b6a..13094e790a 100644 --- a/qcsrc/common/triggers/func/breakable.qc +++ b/qcsrc/common/triggers/func/breakable.qc @@ -134,6 +134,8 @@ void func_breakable_behave_destroyed(entity this) { 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; @@ -155,6 +157,8 @@ void func_breakable_behave_restore(entity this) 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; } diff --git a/qcsrc/common/turrets/sv_turrets.qc b/qcsrc/common/turrets/sv_turrets.qc index dabb7ee35d..adad91a0b9 100644 --- a/qcsrc/common/turrets/sv_turrets.qc +++ b/qcsrc/common/turrets/sv_turrets.qc @@ -1252,6 +1252,7 @@ bool turret_initialize(entity this, Turret tur) 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"); diff --git a/qcsrc/common/vehicles/sv_vehicles.qc b/qcsrc/common/vehicles/sv_vehicles.qc index 39f959d14b..a010ba2c44 100644 --- a/qcsrc/common/vehicles/sv_vehicles.qc +++ b/qcsrc/common/vehicles/sv_vehicles.qc @@ -1077,6 +1077,7 @@ void vehicles_spawn(entity this) this.takedamage = DAMAGE_AIM; this.deadflag = DEAD_NO; this.bot_attack = true; + IL_PUSH(g_bot_targets, this); this.flags = FL_NOTARGET; this.avelocity = '0 0 0'; this.velocity = '0 0 0'; @@ -1161,6 +1162,7 @@ bool vehicle_initialize(entity this, Vehicle info, bool nodrop) 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; diff --git a/qcsrc/common/weapons/weapon/devastator.qc b/qcsrc/common/weapons/weapon/devastator.qc index d44ee7ec20..a99bce47ed 100644 --- a/qcsrc/common/weapons/weapon/devastator.qc +++ b/qcsrc/common/weapons/weapon/devastator.qc @@ -463,7 +463,7 @@ METHOD(Devastator, wr_aim, void(entity thiswep, entity actor)) IL_EACH(g_projectiles, it.realowner == actor && it.classname == "rocket", { 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); @@ -489,7 +489,7 @@ METHOD(Devastator, wr_aim, void(entity thiswep, entity actor)) 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 diff --git a/qcsrc/common/weapons/weapon/minelayer.qc b/qcsrc/common/weapons/weapon/minelayer.qc index a3b356954a..568fb6bd44 100644 --- a/qcsrc/common/weapons/weapon/minelayer.qc +++ b/qcsrc/common/weapons/weapon/minelayer.qc @@ -436,7 +436,7 @@ METHOD(MineLayer, wr_aim, void(entity thiswep, entity actor)) 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); @@ -463,7 +463,7 @@ METHOD(MineLayer, wr_aim, void(entity thiswep, entity actor)) 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 diff --git a/qcsrc/server/bot/default/havocbot/havocbot.qc b/qcsrc/server/bot/default/havocbot/havocbot.qc index 78a1f745d9..cbb6a68b6d 100644 --- a/qcsrc/server/bot/default/havocbot/havocbot.qc +++ b/qcsrc/server/bot/default/havocbot/havocbot.qc @@ -837,11 +837,28 @@ void havocbot_movetogoal(entity this) 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; - float rating, bestrating, hf; - vector eye, v; if (autocvar_bot_nofire || IS_INDEPENDENT_PLAYER(this)) { this.enemy = NULL; @@ -880,81 +897,24 @@ void havocbot_chooseenemy(entity this) if (time < this.havocbot_chooseenemy_finished) return; this.havocbot_chooseenemy_finished = time + autocvar_bot_ai_enemydetectioninterval; - eye = this.origin + this.view_ofs; - best = NULL; - bestrating = 100000000; - head = head2 = findchainfloat(bot_attack, true); - - // Backup hit flags - hf = this.dphitcontentsmask; // Search for enemies, if no enemy can be seen directly try to look through transparent objects + int myhit = this.dphitcontentsmask; this.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE; - bool scan_transparent = false; - bool scan_secondary_targets = false; - bool have_secondary_targets = false; - while(true) + entity best = havocbot_gettarget(this, false); // first try primary targets + if(!best) + best = havocbot_gettarget(this, true); // now try secondary targets + if(!best && this.weapons) { - scan_secondary_targets = false; -LABEL(scan_targets) - for( ; head; head = head.chain) - { - if(!scan_secondary_targets) - { - if(head.classname == "misc_breakablemodel") - { - have_secondary_targets = true; - continue; - } - } - else - { - if(head.classname != "misc_breakablemodel") - continue; - } - - v = (head.absmin + head.absmax) * 0.5; - rating = vlen(v - eye); - if (rating rating) - if (bot_shouldattack(this, head)) - { - traceline(eye, v, true, this); - if (trace_ent == head || trace_fraction >= 1) - { - best = head; - bestrating = rating; - } - } - } - - if(!best && have_secondary_targets && !scan_secondary_targets) - { - scan_secondary_targets = true; - // restart the loop - head = head2; - bestrating = 100000000; - goto scan_targets; - } - - // I want to do a second scan if no enemy was found or I don't have weapons - // TODO: Perform the scan when using the rifle (requires changes on the rifle code) - if(best || this.weapons) // || this.weapon == WEP_RIFLE.m_id - break; - if(scan_transparent) - break; - - // Set flags to see through transparent objects this.dphitcontentsmask |= DPCONTENTS_OPAQUE; - - head = head2; - scan_transparent = true; + best = havocbot_gettarget(this, false); + if(!best) + best = havocbot_gettarget(this, true); } - // Restore hit flags - this.dphitcontentsmask = hf; + this.dphitcontentsmask = myhit; this.enemy = best; this.havocbot_stickenemy = true; diff --git a/qcsrc/server/client.qc b/qcsrc/server/client.qc index 686829e333..9a38c2f611 100644 --- a/qcsrc/server/client.qc +++ b/qcsrc/server/client.qc @@ -294,6 +294,8 @@ void PutObserverInServer(entity this) 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); @@ -632,6 +634,8 @@ void PutClientInServer(entity this) this.event_damage = PlayerDamage; + if(!this.bot_attack) + IL_PUSH(g_bot_targets, this); this.bot_attack = true; this.monster_attack = true; diff --git a/qcsrc/server/defs.qh b/qcsrc/server/defs.qh index 447d4a8ea8..6fbff1a967 100644 --- a/qcsrc/server/defs.qh +++ b/qcsrc/server/defs.qh @@ -466,3 +466,6 @@ 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(); } diff --git a/qcsrc/server/g_damage.qc b/qcsrc/server/g_damage.qc index e3cada6c84..97e82b50ed 100644 --- a/qcsrc/server/g_damage.qc +++ b/qcsrc/server/g_damage.qc @@ -526,6 +526,8 @@ void Freeze (entity targ, float freeze_time, float frozen_type, float show_waypo 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); @@ -563,6 +565,8 @@ void Unfreeze (entity targ) 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); diff --git a/qcsrc/server/mutators/mutator/gamemode_invasion.qc b/qcsrc/server/mutators/mutator/gamemode_invasion.qc index 7083d3a8f6..d43d504821 100644 --- a/qcsrc/server/mutators/mutator/gamemode_invasion.qc +++ b/qcsrc/server/mutators/mutator/gamemode_invasion.qc @@ -343,6 +343,8 @@ MUTATOR_HOOKFUNCTION(inv, PlayerSpawn) { entity player = M_ARGV(0, entity); + if(player.bot_attack) + IL_REMOVE(g_bot_targets, player); player.bot_attack = false; } -- 2.39.2