From: bones_was_here Date: Wed, 13 Mar 2024 16:10:01 +0000 (+1000) Subject: monsters: try to avoid danger X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=d1cfb222a3841ec1d5f128a3323bf4266a6e24c9;p=xonotic%2Fxonotic-data.pk3dir.git monsters: try to avoid danger Also makes them avoid falling off platforms and into holes, and try to find another path, when NOT chasing an enemy. This makes them more useful for guarding an area, especially on space maps. --- diff --git a/qcsrc/common/monsters/sv_monsters.qc b/qcsrc/common/monsters/sv_monsters.qc index d516aec2c..123c59d14 100644 --- a/qcsrc/common/monsters/sv_monsters.qc +++ b/qcsrc/common/monsters/sv_monsters.qc @@ -683,8 +683,81 @@ vector Monster_Move_Target(entity this, entity targ) } } -.entity draggedby; +// Check for water/slime/lava and dangerous edges +// (only when the bot is on the ground or jumping intentionally) +// returns a number > 0 for danger +// based on havocbot_checkdanger() +int Monster_CheckDanger(entity this, vector dst_ahead) +{ + float s; + + if((this.flags & FL_FLY) || (this.flags & FL_SWIM)) + { + // Look ahead + traceline(this.origin + this.view_ofs, dst_ahead, true, NULL); + + // Only care about the skybox if it's below + // bones_was_here: does this even matter when flying/swimming? + if (trace_endpos.z < this.origin.z + this.mins.z + && trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY) + return 1; + + s = pointcontents(trace_endpos + '0 0 1'); + if (s != CONTENT_SOLID) + { + if (s == CONTENT_LAVA || s == CONTENT_SLIME) + return 3; + + if (tracebox_hits_trigger_hurt(dst_ahead, this.mins, this.maxs, trace_endpos)) + { + // the traceline check isn't enough but is good as optimization, + // when not true (most of the time) this tracebox call is avoided + tracebox(this.origin + this.view_ofs, this.mins, this.maxs, dst_ahead, true, this); + if (tracebox_hits_trigger_hurt(dst_ahead, this.mins, this.maxs, trace_endpos)) + return 4; + } + } + } + else + { + vector dst_down = dst_ahead - '0 0 3000'; + + // Look downwards + traceline(dst_ahead, dst_down, true, NULL); + //te_lightning2(NULL, this.origin + this.view_ofs, dst_ahead); // Draw "ahead" look + //te_lightning2(NULL, dst_ahead, trace_endpos); // Draw "downwards" look + if (trace_endpos.z < this.origin.z + this.mins.z) + { + if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY) + return 1; + // If following an enemy ignore probably-non-fatal falls, + // if wandering only ignore small falls. + if (trace_endpos.z < (this.origin.z + this.mins.z) - (this.enemy ? 1024 : 100)) + return 2; + + s = pointcontents(trace_endpos + '0 0 1'); + if (s != CONTENT_SOLID) + { + if (s == CONTENT_LAVA || s == CONTENT_SLIME) + return 3; + + if (tracebox_hits_trigger_hurt(dst_ahead, this.mins, this.maxs, trace_endpos)) + { + // the traceline check isn't enough but is good as optimization, + // when not true (most of the time) this tracebox call is avoided + tracebox(dst_ahead, this.mins, this.maxs, dst_down, true, this); + if (tracebox_hits_trigger_hurt(dst_ahead, this.mins, this.maxs, trace_endpos)) + return 4; + } + } + } + } + + return 0; +} + +.entity draggedby; void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed) { // update goal entity if lost @@ -787,7 +860,12 @@ void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed) fixedmakevectors(this.angles); float vz = this.velocity_z; - if(!turret_closetotarget(this, this.moveto, 16)) + // Check for danger ahead + float bboxwidth = min(this.maxs_x - this.mins_x, this.maxs_y - this.mins_y); + int danger = Monster_CheckDanger(this, this.origin + this.view_ofs + + (vdist(this.velocity, >, bboxwidth * 5) ? this.velocity * 0.2 : v_forward * bboxwidth)); + + if(!danger && !turret_closetotarget(this, this.moveto, 16)) { bool do_run = (this.enemy || this.monster_moveto); movelib_move_simple(this, v_forward, ((do_run) ? runspeed : walkspeed), 0.4); @@ -830,6 +908,12 @@ void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed) turny = bound(turny * -1, shortangle_f(real_angle.y, this.angles.y), turny); this.angles_y += turny; } + + if (danger) + { + this.last_trace = time + 0.3; + this.moveto = Monster_WanderTarget(this, this.origin); + } } void Monster_Remove(entity this)