flag.solid = SOLID_TRIGGER;
flag.ctf_dropper = player;
flag.ctf_droptime = time;
+ navigation_dynamicgoal_set(flag);
flag.flags = FL_ITEM | FL_NOTARGET; // clear FL_ONGROUND for MOVETYPE_TOSS
FOREACH_CLIENT(true, LAMBDA(ctf_CaptureShield_Update(it, 1))); // release shield only
// sanity checks
- if(this.mins != CTF_FLAG.m_mins || this.maxs != CTF_FLAG.m_maxs) { // reset the flag boundaries in case it got squished
+ if(this.mins != this.m_mins || this.maxs != this.m_maxs) { // reset the flag boundaries in case it got squished
LOG_TRACE("wtf the flag got squashed?");
- tracebox(this.origin, CTF_FLAG.m_mins, CTF_FLAG.m_maxs, this.origin, MOVE_NOMONSTERS, this);
+ tracebox(this.origin, this.m_mins, this.m_maxs, this.origin, MOVE_NOMONSTERS, this);
if(!trace_startsolid || this.noalign) // can we resize it without getting stuck?
- setsize(this, CTF_FLAG.m_mins * this.scale, CTF_FLAG.m_maxs * this.scale);
+ setsize(this, this.m_mins, this.m_maxs);
}
// main think method
flag.ctf_pickuptime = 0;
flag.ctf_droptime = 0;
flag.ctf_flagdamaged_byworld = false;
+ navigation_dynamicgoal_unset(flag);
ctf_CheckStalemate();
}
{
// bot waypoints
waypoint_spawnforitem_force(this, this.origin);
- this.nearestwaypointtimeout = 0; // activate waypointing again
- this.bot_basewaypoint = this.nearestwaypoint;
+ navigation_dynamicgoal_init(this, true);
// waypointsprites
entity basename;
// appearence
_setmodel(flag, flag.model); // precision set below
setsize(flag, CTF_FLAG.m_mins * flag.scale, CTF_FLAG.m_maxs * flag.scale);
+ flag.m_mins = flag.mins; // store these for squash checks
+ flag.m_maxs = flag.maxs;
setorigin(flag, (flag.origin + FLAG_SPAWN_OFFSET));
if(autocvar_g_ctf_flag_glowtrails)
// NOTE: LEGACY CODE, needs to be re-written!
-void havocbot_calculate_middlepoint()
+void havocbot_ctf_calculate_middlepoint()
{
entity f;
vector s = '0 0 0';
}
if(!n)
return;
- havocbot_ctf_middlepoint = s / n;
- havocbot_ctf_middlepoint_radius = vlen(fo - havocbot_ctf_middlepoint);
+
+ havocbot_middlepoint = s / n;
+ havocbot_middlepoint_radius = vlen(fo - havocbot_middlepoint);
+
+ havocbot_symmetryaxys_equation = '0 0 0';
+ if(n == 2)
+ {
+ // for symmetrical editing of waypoints
+ entity f1 = ctf_worldflaglist;
+ entity f2 = f1.ctf_worldflagnext;
+ float m = -(f1.origin.y - f2.origin.y) / (f1.origin.x - f2.origin.x);
+ float q = havocbot_middlepoint.y - m * havocbot_middlepoint.x;
+ havocbot_symmetryaxys_equation.x = m;
+ havocbot_symmetryaxys_equation.y = q;
+ }
+ // store number of flags in this otherwise unused vector component
+ havocbot_symmetryaxys_equation.z = n;
}
return c;
}
+// unused
+#if 0
void havocbot_goalrating_ctf_ourflag(entity this, float ratingscale)
{
entity head;
if (head)
navigation_routerating(this, head, ratingscale, 10000);
}
+#endif
void havocbot_goalrating_ctf_ourbase(entity this, float ratingscale)
{
while (head)
{
if (CTF_SAMETEAM(this, head))
+ {
+ if (this.flagcarried)
+ if ((this.flagcarried.cnt || head.cnt) && this.flagcarried.cnt != head.cnt)
+ {
+ head = head.ctf_worldflagnext; // skip base if it has a different group
+ continue;
+ }
break;
+ }
head = head.ctf_worldflagnext;
}
if (!head)
if(IS_DEAD(this))
return;
- if(havocbot_ctf_middlepoint == '0 0 0')
- havocbot_calculate_middlepoint();
-
// Check ctf flags
if (this.flagcarried)
{
// Evaluate best position to take
// Count mates on middle position
- cmiddle = havocbot_ctf_teamcount(this, havocbot_ctf_middlepoint, havocbot_ctf_middlepoint_radius * 0.5);
+ cmiddle = havocbot_ctf_teamcount(this, havocbot_middlepoint, havocbot_middlepoint_radius * 0.5);
// Count mates on defense position
- cdefense = havocbot_ctf_teamcount(this, mf.dropped_origin, havocbot_ctf_middlepoint_radius * 0.5);
+ cdefense = havocbot_ctf_teamcount(this, mf.dropped_origin, havocbot_middlepoint_radius * 0.5);
// Count mates on offense position
- coffense = havocbot_ctf_teamcount(this, ef.dropped_origin, havocbot_ctf_middlepoint_radius);
+ coffense = havocbot_ctf_teamcount(this, ef.dropped_origin, havocbot_middlepoint_radius);
if(cdefense<=coffense)
havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_DEFENSE);
navigation_goalrating_end(this);
- if (this.navigation_hasgoals)
+ if (this.goalentity)
this.havocbot_cantfindflag = time + 10;
else if (time > this.havocbot_cantfindflag)
{
{
vector org;
- org = havocbot_ctf_middlepoint;
+ org = havocbot_middlepoint;
org.z = this.origin.z;
this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
navigation_goalrating_start(this);
havocbot_goalrating_ctf_ourstolenflag(this, 50000);
havocbot_goalrating_ctf_droppedflags(this, 30000, this.origin, 10000);
- havocbot_goalrating_enemyplayers(this, 10000, org, havocbot_ctf_middlepoint_radius * 0.5);
- havocbot_goalrating_items(this, 5000, org, havocbot_ctf_middlepoint_radius * 0.5);
+ havocbot_goalrating_enemyplayers(this, 10000, org, havocbot_middlepoint_radius * 0.5);
+ havocbot_goalrating_items(this, 5000, org, havocbot_middlepoint_radius * 0.5);
havocbot_goalrating_items(this, 2500, this.origin, 10000);
havocbot_goalrating_ctf_enemybase(this, 2500);
navigation_goalrating_end(this);
}
if (this.bot_strategytime < time)
{
- float mp_radius;
- vector org;
-
- org = mf.dropped_origin;
- mp_radius = havocbot_ctf_middlepoint_radius;
+ vector org = mf.dropped_origin;
this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
navigation_goalrating_start(this);
havocbot_goalrating_ctf_ourbase(this, 30000);
havocbot_goalrating_ctf_ourstolenflag(this, 20000);
- havocbot_goalrating_ctf_droppedflags(this, 20000, org, mp_radius);
- havocbot_goalrating_enemyplayers(this, 15000, org, mp_radius);
- havocbot_goalrating_items(this, 10000, org, mp_radius);
+ havocbot_goalrating_ctf_droppedflags(this, 20000, org, havocbot_middlepoint_radius);
+ havocbot_goalrating_enemyplayers(this, 15000, org, havocbot_middlepoint_radius);
+ havocbot_goalrating_items(this, 10000, org, havocbot_middlepoint_radius);
havocbot_goalrating_items(this, 5000, this.origin, 10000);
navigation_goalrating_end(this);
}
entity player = M_ARGV(0, entity);
int t = 0, t2 = 0, t3 = 0;
+ bool b1 = false, b2 = false, b3 = false, b4 = false, b5 = false; // TODO: kill this, we WANT to show the other flags, somehow! (note: also means you don't see if you're FC)
// initially clear items so they can be set as necessary later.
player.ctf_flagstatus &= ~(CTF_RED_FLAG_CARRYING | CTF_RED_FLAG_TAKEN | CTF_RED_FLAG_LOST
// scan through all the flags and notify the client about them
for(entity flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext)
{
- if(flag.team == NUM_TEAM_1) { t = CTF_RED_FLAG_CARRYING; t2 = CTF_RED_FLAG_TAKEN; t3 = CTF_RED_FLAG_LOST; }
- if(flag.team == NUM_TEAM_2) { t = CTF_BLUE_FLAG_CARRYING; t2 = CTF_BLUE_FLAG_TAKEN; t3 = CTF_BLUE_FLAG_LOST; }
- if(flag.team == NUM_TEAM_3) { t = CTF_YELLOW_FLAG_CARRYING; t2 = CTF_YELLOW_FLAG_TAKEN; t3 = CTF_YELLOW_FLAG_LOST; }
- if(flag.team == NUM_TEAM_4) { t = CTF_PINK_FLAG_CARRYING; t2 = CTF_PINK_FLAG_TAKEN; t3 = CTF_PINK_FLAG_LOST; }
- if(flag.team == 0) { t = CTF_NEUTRAL_FLAG_CARRYING; t2 = CTF_NEUTRAL_FLAG_TAKEN; t3 = CTF_NEUTRAL_FLAG_LOST; player.ctf_flagstatus |= CTF_FLAG_NEUTRAL; }
+ if(flag.team == NUM_TEAM_1 && !b1) { b1 = true; t = CTF_RED_FLAG_CARRYING; t2 = CTF_RED_FLAG_TAKEN; t3 = CTF_RED_FLAG_LOST; }
+ if(flag.team == NUM_TEAM_2 && !b2) { b2 = true; t = CTF_BLUE_FLAG_CARRYING; t2 = CTF_BLUE_FLAG_TAKEN; t3 = CTF_BLUE_FLAG_LOST; }
+ if(flag.team == NUM_TEAM_3 && !b3) { b3 = true; t = CTF_YELLOW_FLAG_CARRYING; t2 = CTF_YELLOW_FLAG_TAKEN; t3 = CTF_YELLOW_FLAG_LOST; }
+ if(flag.team == NUM_TEAM_4 && !b4) { b4 = true; t = CTF_PINK_FLAG_CARRYING; t2 = CTF_PINK_FLAG_TAKEN; t3 = CTF_PINK_FLAG_LOST; }
+ if(flag.team == 0 && !b5) { b5 = true; t = CTF_NEUTRAL_FLAG_CARRYING; t2 = CTF_NEUTRAL_FLAG_TAKEN; t3 = CTF_NEUTRAL_FLAG_LOST; player.ctf_flagstatus |= CTF_FLAG_NEUTRAL; }
switch(flag.ctf_status)
{
if(tmp_entity.team == 0) { ctf_oneflag = true; }
}
+ havocbot_ctf_calculate_middlepoint();
+
if(NumTeams(ctf_teams) < 2) // somehow, there's not enough flags!
{
ctf_teams = 0; // so set the default red and blue teams