flag.angles = '0 0 0';
SetResourceExplicit(flag, RES_HEALTH, flag.max_health);
flag.ctf_droptime = time;
+ flag.ctf_landtime = 0;
flag.ctf_dropper = player;
flag.ctf_status = FLAG_DROPPED;
GameRules_scoring_vip(player, true);
// reset flag
+ flag.solid = SOLID_NOT; // before setorigin to prevent area grid linking
if(player.vehicle)
{
setattachment(flag, player.vehicle, "");
}
set_movetype(flag, MOVETYPE_NONE);
flag.takedamage = DAMAGE_NO;
- flag.solid = SOLID_NOT;
flag.angles = '0 0 0';
flag.ctf_status = FLAG_CARRY;
// reset the flag
setattachment(flag, NULL, "");
tracebox(player.origin - FLAG_DROP_OFFSET, flag.m_mins, flag.m_maxs, player.origin + FLAG_DROP_OFFSET, MOVE_NOMONSTERS, flag);
+ flag.solid = SOLID_TRIGGER; // before setorigin to ensure area grid linking
setorigin(flag, trace_endpos);
+ if (trace_startsolid && !nudgeoutofsolid(flag)) // TODO: trace_allsolid would perform better but isn't 100% reliable yet
+ {
+ // the flag's bbox doesn't fit but we can assume the player's current bbox does
+ tracebox(player.origin - FLAG_DROP_OFFSET, player.mins, player.maxs, player.origin + FLAG_DROP_OFFSET, MOVE_NOMONSTERS, flag);
+ flag.origin = trace_endpos;
+ setsize(flag, player.mins, player.maxs); // this allows physics to move the flag somewhere its think func can resize it
+ }
flag.owner.flagcarried = NULL;
GameRules_scoring_vip(flag.owner, false);
flag.owner = NULL;
- flag.solid = SOLID_TRIGGER;
flag.ctf_dropper = player;
flag.ctf_droptime = time;
+ flag.ctf_landtime = 0;
flag.flags = FL_ITEM | FL_NOTARGET; // clear FL_ONGROUND for MOVETYPE_TOSS
flag.owner = player;
player.flagcarried = flag;
GameRules_scoring_vip(player, true);
+ flag.solid = SOLID_NOT; // before setorigin to prevent area grid linking
if(player.vehicle)
{
setattachment(flag, player.vehicle, "");
// flag setup
set_movetype(flag, MOVETYPE_NONE);
flag.takedamage = DAMAGE_NO;
- flag.solid = SOLID_NOT;
flag.angles = '0 0 0';
flag.ctf_status = FLAG_CARRY;
if(flag.team)
FOREACH_CLIENT(IS_PLAYER(it) && it != player, {
if(CTF_SAMETEAM(flag, it))
- {
- if(SAME_TEAM(player, it))
- Send_Notification(NOTIF_ONE, it, MSG_CHOICE, APP_TEAM_NUM(flag.team, CHOICE_CTF_PICKUP_TEAM), Team_ColorCode(player.team), player.netname);
- else
- Send_Notification(NOTIF_ONE, it, MSG_CHOICE, ((SAME_TEAM(flag, player)) ? CHOICE_CTF_PICKUP_ENEMY_TEAM : CHOICE_CTF_PICKUP_ENEMY), Team_ColorCode(player.team), player.netname);
- }
+ Send_Notification(NOTIF_ONE, it, MSG_CHOICE, ((SAME_TEAM(flag, player)) ? CHOICE_CTF_PICKUP_ENEMY_TEAM : CHOICE_CTF_PICKUP_ENEMY), Team_ColorCode(player.team), player.netname);
+ else if(DIFF_TEAM(player, it))
+ Send_Notification(NOTIF_ONE, it, MSG_CHOICE, APP_NUM(flag.team, CHOICE_CTF_PICKUP_ENEMY_OTHER), Team_ColorCode(player.team), player.netname);
});
_sound(player, CH_TRIGGER, flag.snd_flag_taken, VOL_BASE, ATTEN_NONE);
// sanity checks
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, 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, this.m_mins, this.m_maxs);
for(tmp_entity = ctf_worldflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_worldflagnext)
if(tmp_entity.ctf_status == FLAG_DROPPED)
if(vdist(this.origin - tmp_entity.origin, <, autocvar_g_ctf_dropped_capture_radius))
- if(time > tmp_entity.ctf_droptime + autocvar_g_ctf_dropped_capture_delay)
+ if((this.noalign || tmp_entity.ctf_landtime) && time > ((this.noalign) ? tmp_entity.ctf_droptime : tmp_entity.ctf_landtime) + autocvar_g_ctf_dropped_capture_delay)
ctf_Handle_Capture(this, tmp_entity, CAPTURE_DROPPED);
}
return;
case FLAG_DROPPED:
{
this.angles = '0 0 0'; // reset flag angles in case warpzones adjust it
+ if(IS_ONGROUND(this) && !this.ctf_landtime)
+ this.ctf_landtime = time; // landtime is reset when thrown, and we don't want to restart the timer if the flag is pushed
if(autocvar_g_ctf_flag_dropped_floatinwater)
{
ctf_Handle_Pickup(flag, toucher, PICKUP_BASE); // toucher just stole the neutral flag
}
else if(CTF_SAMETEAM(toucher, flag) && (toucher.flagcarried) && DIFF_TEAM(toucher.flagcarried, flag) && is_not_monster)
- ctf_Handle_Capture(flag, toucher, CAPTURE_NORMAL); // toucher just captured the enemies flag to his base
+ ctf_Handle_Capture(flag, toucher, CAPTURE_NORMAL); // toucher just captured the enemies flag to their base
else if(CTF_DIFFTEAM(toucher, flag) && (toucher.flagcarried) && CTF_SAMETEAM(toucher.flagcarried, toucher) && (!toucher.ctf_captureshielded) && autocvar_g_ctf_flag_return_carrying && (time > toucher.next_take_time) && is_not_monster)
{
ctf_Handle_Return(toucher.flagcarried, toucher); // return their current flag
case FLAG_DROPPED:
{
if(CTF_SAMETEAM(toucher, flag) && ctf_Immediate_Return_Allowed(flag, toucher))
- ctf_Handle_Return(flag, toucher); // toucher just returned his own flag
+ ctf_Handle_Return(flag, toucher); // toucher just returned their own flag
else if(is_not_monster && (!toucher.flagcarried) && ((toucher != flag.ctf_dropper) || (time > flag.ctf_droptime + autocvar_g_ctf_flag_collect_delay)))
ctf_Handle_Pickup(flag, toucher, PICKUP_DROPPED); // toucher just picked up a dropped enemy flag
break;
}
}
-.float last_respawn;
void ctf_RespawnFlag(entity flag)
{
flag.watertype = CONTENT_EMPTY; // TODO: it is unclear why this workaround is needed, likely many other potential breakage points!!
- // check for flag respawn being called twice in a row
- if(flag.last_respawn > time - 0.5)
- { backtrace("flag respawn called twice quickly! please notify Samual about this..."); }
-
- flag.last_respawn = time;
// reset the player (if there is one)
if((flag.owner) && (flag.owner.flagcarried == flag))
// reset the flag
setattachment(flag, NULL, "");
+ flag.solid = SOLID_TRIGGER; // before setorigin to ensure area grid linking
setorigin(flag, flag.ctf_spawnorigin);
//set_movetype(flag, ((flag.noalign) ? MOVETYPE_NONE : MOVETYPE_TOSS)); // would be desired, except maps that want floating flags have it set to fall!
set_movetype(flag, MOVETYPE_NONE); // match the initial setup handling (flag doesn't move when spawned)
flag.takedamage = DAMAGE_NO;
SetResourceExplicit(flag, RES_HEALTH, flag.max_health);
- flag.solid = SOLID_TRIGGER;
flag.velocity = '0 0 0';
flag.angles = flag.mangle;
flag.flags = FL_ITEM | FL_NOTARGET;
flag.ctf_dropper = NULL;
flag.ctf_pickuptime = 0;
flag.ctf_droptime = 0;
+ flag.ctf_landtime = 0;
flag.ctf_flagdamaged_byworld = false;
navigation_dynamicgoal_unset(flag);
flag.nextthink = time + FLAG_THINKRATE;
flag.ctf_status = FLAG_BASE;
+ // set correct team colors
+ flag.glowmod = Team_ColorRGB(teamnum);
+ flag.colormap = (teamnum) ? (teamnum - 1) * 0x11 : 0x00;
+ flag.colormap |= BIT(10); // RENDER_COLORMAPPED
+
// crudely force them all to 0
if(autocvar_g_ctf_score_ignore_fields)
flag.cnt = flag.score_assist = flag.score_team_capture = flag.score_capture = flag.score_drop = flag.score_pickup = flag.score_return = 0;
// appearence
_setmodel(flag, flag.model); // precision set below
- setsize(flag, CTF_FLAG.m_mins * flag.scale, CTF_FLAG.m_maxs * flag.scale);
+ // 0.8.6 with sv_legacy_bbox_expand 1 did this FL_ITEM expansion in DP
+ setsize(flag, CTF_FLAG.m_mins * flag.scale - '15 15 1', CTF_FLAG.m_maxs * flag.scale + '15 15 1');
flag.m_mins = flag.mins; // store these for squash checks
flag.m_maxs = flag.maxs;
setorigin(flag, (flag.origin + FLAG_SPAWN_OFFSET));
else // drop to floor, automatically find a platform and set that as spawn origin
{
flag.noalign = false;
- droptofloor(flag);
+ DropToFloor_QC_DelayedInit(flag);
set_movetype(flag, MOVETYPE_NONE);
}
{
if (head.ctf_status == FLAG_CARRY)
{
- // adjust rating of our flag carrier depending on his health
+ // adjust rating of our flag carrier depending on their health
head = head.tag_entity;
float f = bound(0, (GetResource(head, RES_HEALTH) + GetResource(head, RES_ARMOR)) / 100, 2) - 1;
ratingscale += ratingscale * f * 0.1;
entity goal = this.goalentity;
if (havocbot_ctf_is_basewaypoint(goal) && vdist(goal.origin - this.origin, <, 100))
- this.goalentity_lock_timeout = time + ((this.bot_aimtarg) ? 2 : 3);
+ this.goalentity_lock_timeout = time + ((this.enemy) ? 2 : 3);
if (goal)
this.havocbot_cantfindflag = time + 10;