X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Fserver%2Fmutators%2Fmutator%2Fgamemode_ctf.qc;h=8a88d5d2e8d7ac60ab0b4bd45601914650fb14ba;hp=017fb265b9adc89fcb7aa5d63ab61d8c66e8dff6;hb=905ec2fbd2b610eeb2591cdddbf71ce24b7bb3ab;hpb=4ee2807b2d8f808928ef14b3e814945b3edb4350 diff --git a/qcsrc/server/mutators/mutator/gamemode_ctf.qc b/qcsrc/server/mutators/mutator/gamemode_ctf.qc index 017fb265b..8a88d5d2e 100644 --- a/qcsrc/server/mutators/mutator/gamemode_ctf.qc +++ b/qcsrc/server/mutators/mutator/gamemode_ctf.qc @@ -91,6 +91,7 @@ float autocvar_g_ctf_flagcarrier_forcefactor; //float autocvar_g_ctf_flagcarrier_waypointforenemy_spotting; bool autocvar_g_ctf_fullbrightflags; bool autocvar_g_ctf_ignore_frags; +bool autocvar_g_ctf_score_ignore_fields; int autocvar_g_ctf_score_capture; int autocvar_g_ctf_score_capture_assist; int autocvar_g_ctf_score_kill; @@ -135,10 +136,14 @@ void ctf_CaptureRecord(entity flag, entity player) string refername = db_get(ServerProgsDB, strcat(GetMapname(), "/captimerecord/netname")); // notify about shit - if(ctf_oneflag) { Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_CTF_CAPTURE_NEUTRAL, player.netname); } - else if(!ctf_captimerecord) { Send_Notification(NOTIF_ALL, NULL, MSG_CHOICE, APP_TEAM_ENT(flag, CHOICE_CTF_CAPTURE_TIME), player.netname, (cap_time * 100)); } - else if(cap_time < cap_record) { Send_Notification(NOTIF_ALL, NULL, MSG_CHOICE, APP_TEAM_ENT(flag, CHOICE_CTF_CAPTURE_BROKEN), player.netname, refername, (cap_time * 100), (cap_record * 100)); } - else { Send_Notification(NOTIF_ALL, NULL, MSG_CHOICE, APP_TEAM_ENT(flag, CHOICE_CTF_CAPTURE_UNBROKEN), player.netname, refername, (cap_time * 100), (cap_record * 100)); } + if(ctf_oneflag) + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_CTF_CAPTURE_NEUTRAL, player.netname); + else if(!ctf_captimerecord) + Send_Notification(NOTIF_ALL, NULL, MSG_CHOICE, APP_TEAM_NUM(flag.team, CHOICE_CTF_CAPTURE_TIME), player.netname, (cap_time * 100)); + else if(cap_time < cap_record) + Send_Notification(NOTIF_ALL, NULL, MSG_CHOICE, APP_TEAM_NUM(flag.team, CHOICE_CTF_CAPTURE_BROKEN), player.netname, refername, (cap_time * 100), (cap_record * 100)); + else + Send_Notification(NOTIF_ALL, NULL, MSG_CHOICE, APP_TEAM_NUM(flag.team, CHOICE_CTF_CAPTURE_UNBROKEN), player.netname, refername, (cap_time * 100), (cap_record * 100)); // write that shit in the database if(!ctf_oneflag) // but not in 1-flag mode @@ -149,6 +154,19 @@ void ctf_CaptureRecord(entity flag, entity player) db_put(ServerProgsDB, strcat(GetMapname(), "/captimerecord/netname"), player.netname); write_recordmarker(player, (time - cap_time), cap_time); } + + if(autocvar_g_ctf_leaderboard && !ctf_oneflag) + race_setTime(GetMapname(), TIME_ENCODE(cap_time), player.crypto_idfp, player.netname, player, false); +} + +bool ctf_Immediate_Return_Allowed(entity flag, entity toucher) +{ + int num_perteam = 0; + FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(toucher, it), { ++num_perteam; }); + + // automatically return if there's only 1 player on the team + return ((autocvar_g_ctf_flag_return || num_perteam <= 1 || (autocvar_g_ctf_flag_return_carrying && toucher.flagcarried)) + && flag.team); } bool ctf_Return_Customize(entity this, entity client) @@ -363,12 +381,12 @@ void ctf_Handle_Drop(entity flag, entity player, int droptype) flag.ctf_status = FLAG_DROPPED; // messages and sounds - Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((flag.team) ? APP_TEAM_ENT(flag, INFO_CTF_LOST) : INFO_CTF_LOST_NEUTRAL), player.netname); + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_LOST), player.netname); _sound(flag, CH_TRIGGER, flag.snd_flag_dropped, VOL_BASE, ATTEN_NONE); ctf_EventLog("dropped", player.team, player); // scoring - PlayerTeamScore_AddScore(player, -autocvar_g_ctf_score_penalty_drop); + PlayerTeamScore_AddScore(player, -((flag.score_drop) ? flag.score_drop : autocvar_g_ctf_score_penalty_drop)); PlayerScore_Add(player, SP_CTF_DROPS, 1); // waypoints @@ -425,11 +443,11 @@ void ctf_Handle_Retrieve(entity flag, entity player) FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), LAMBDA( if(it == sender) - Send_Notification(NOTIF_ONE, it, MSG_CENTER, ((flag.team) ? APP_TEAM_ENT(flag, CENTER_CTF_PASS_SENT) : CENTER_CTF_PASS_SENT_NEUTRAL), player.netname); + Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_NUM(flag.team, CENTER_CTF_PASS_SENT), player.netname); else if(it == player) - Send_Notification(NOTIF_ONE, it, MSG_CENTER, ((flag.team) ? APP_TEAM_ENT(flag, CENTER_CTF_PASS_RECEIVED) : CENTER_CTF_PASS_RECEIVED_NEUTRAL), sender.netname); + Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_NUM(flag.team, CENTER_CTF_PASS_RECEIVED), sender.netname); else if(SAME_TEAM(it, sender)) - Send_Notification(NOTIF_ONE, it, MSG_CENTER, ((flag.team) ? APP_TEAM_ENT(flag, CENTER_CTF_PASS_OTHER) : CENTER_CTF_PASS_OTHER_NEUTRAL), sender.netname, player.netname); + Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_NUM(flag.team, CENTER_CTF_PASS_OTHER), sender.netname, player.netname); )); // create new waypoint @@ -461,6 +479,7 @@ void ctf_Handle_Throw(entity player, entity receiver, int droptype) 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 @@ -551,6 +570,7 @@ void ctf_Handle_Capture(entity flag, entity toucher, int capturetype) if(!player) { return; } // without someone to give the reward to, we can't possibly cap if(CTF_DIFFTEAM(player, flag)) { return; } + if((flag.cnt || enemy_flag.cnt) && flag.cnt != enemy_flag.cnt) { return; } // this should catch some edge cases (capturing grouped flag at ungrouped flag disallowed etc) if(ctf_oneflag) for(tmp_entity = ctf_worldflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_worldflagnext) @@ -566,7 +586,7 @@ void ctf_Handle_Capture(entity flag, entity toucher, int capturetype) player.throw_count = 0; // messages and sounds - Send_Notification(NOTIF_ONE, player, MSG_CENTER, ((enemy_flag.team) ? APP_TEAM_ENT(enemy_flag, CENTER_CTF_CAPTURE) : CENTER_CTF_CAPTURE_NEUTRAL)); + Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_NUM(enemy_flag.team, CENTER_CTF_CAPTURE)); ctf_CaptureRecord(enemy_flag, player); _sound(player, CH_TRIGGER, ((ctf_oneflag) ? player_team_flag.snd_flag_capture : ((DIFF_TEAM(player, flag)) ? enemy_flag.snd_flag_capture : flag.snd_flag_capture)), VOL_BASE, ATTEN_NONE); @@ -578,8 +598,14 @@ void ctf_Handle_Capture(entity flag, entity toucher, int capturetype) } // scoring - PlayerTeamScore_AddScore(player, autocvar_g_ctf_score_capture); - PlayerTeamScore_Add(player, SP_CTF_CAPS, ST_CTF_CAPS, 1); + float pscore = 0; + if(enemy_flag.score_capture || flag.score_capture) + pscore = floor((max(1, enemy_flag.score_capture) + max(1, flag.score_capture)) * 0.5); + PlayerTeamScore_AddScore(player, ((pscore) ? pscore : autocvar_g_ctf_score_capture)); + float capscore = 0; + if(enemy_flag.score_team_capture || flag.score_team_capture) + capscore = floor((max(1, enemy_flag.score_team_capture) + max(1, flag.score_team_capture)) * 0.5); + PlayerTeamScore_Add(player, SP_CTF_CAPS, ST_CTF_CAPS, ((capscore) ? capscore : 1)); old_time = PlayerScore_Add(player, SP_CTF_CAPTIME, 0); new_time = TIME_ENCODE(time - enemy_flag.ctf_pickuptime); @@ -597,7 +623,7 @@ void ctf_Handle_Capture(entity flag, entity toucher, int capturetype) if(flag.speedrunning) { ctf_FakeTimeLimit(player, -1); } if((enemy_flag.ctf_dropper) && (player != enemy_flag.ctf_dropper)) - { PlayerTeamScore_AddScore(enemy_flag.ctf_dropper, autocvar_g_ctf_score_capture_assist); } + { PlayerTeamScore_AddScore(enemy_flag.ctf_dropper, ((enemy_flag.score_assist) ? enemy_flag.score_assist : autocvar_g_ctf_score_capture_assist)); } } // reset the flag @@ -610,12 +636,12 @@ void ctf_Handle_Return(entity flag, entity player) // messages and sounds if(IS_MONSTER(player)) { - Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_ENT(flag, INFO_CTF_RETURN_MONSTER), player.monster_name); + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(flag.team, INFO_CTF_RETURN_MONSTER), player.monster_name); } else if(flag.team) { - Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_ENT(flag, CENTER_CTF_RETURN)); - Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_ENT(flag, INFO_CTF_RETURN), player.netname); + Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_NUM(flag.team, CENTER_CTF_RETURN)); + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(flag.team, INFO_CTF_RETURN), player.netname); } _sound(player, CH_TRIGGER, flag.snd_flag_returned, VOL_BASE, ATTEN_NONE); ctf_EventLog("return", flag.team, player); @@ -623,7 +649,7 @@ void ctf_Handle_Return(entity flag, entity player) // scoring if(IS_PLAYER(player)) { - PlayerTeamScore_AddScore(player, autocvar_g_ctf_score_return); // reward for return + PlayerTeamScore_AddScore(player, ((flag.score_return) ? flag.score_return : autocvar_g_ctf_score_return)); // reward for return PlayerScore_Add(player, SP_CTF_RETURNS, 1); // add to count of returns nades_GiveBonus(player,autocvar_g_nades_bonus_score_medium); @@ -681,13 +707,17 @@ void ctf_Handle_Pickup(entity flag, entity player, int pickuptype) } // messages and sounds - Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((flag.team) ? APP_TEAM_ENT(flag, INFO_CTF_PICKUP) : INFO_CTF_PICKUP_NEUTRAL), player.netname); - if(ctf_stalemate) { Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_STALEMATE_CARRIER); } - if(!flag.team) { Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PICKUP_NEUTRAL); } - else if(CTF_DIFFTEAM(player, flag)) { Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_ENT(flag, CENTER_CTF_PICKUP)); } - else { Send_Notification(NOTIF_ONE, player, MSG_CENTER, ((SAME_TEAM(player, flag)) ? CENTER_CTF_PICKUP_TEAM : CENTER_CTF_PICKUP_TEAM_ENEMY), Team_ColorCode(flag.team)); } + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_PICKUP), player.netname); + if(ctf_stalemate) + Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_STALEMATE_CARRIER); + if(!flag.team) + Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PICKUP_NEUTRAL); + else if(CTF_DIFFTEAM(player, flag)) + Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_NUM(flag.team, CENTER_CTF_PICKUP)); + else + Send_Notification(NOTIF_ONE, player, MSG_CENTER, ((SAME_TEAM(player, flag)) ? CENTER_CTF_PICKUP_RETURN : CENTER_CTF_PICKUP_RETURN_ENEMY), Team_ColorCode(flag.team)); - Send_Notification(NOTIF_TEAM_EXCEPT, player, MSG_CHOICE, ((flag.team) ? APP_TEAM_ENT(flag, CHOICE_CTF_PICKUP_TEAM) : CHOICE_CTF_PICKUP_TEAM_NEUTRAL), Team_ColorCode(player.team), player.netname); + Send_Notification(NOTIF_TEAM_EXCEPT, player, MSG_CHOICE, APP_NUM(flag.team, CHOICE_CTF_PICKUP_TEAM), Team_ColorCode(player.team), player.netname); if(!flag.team) FOREACH_CLIENT(IS_PLAYER(it) && it != player && DIFF_TEAM(it, player), LAMBDA(Send_Notification(NOTIF_ONE, it, MSG_CHOICE, CHOICE_CTF_PICKUP_ENEMY_NEUTRAL, Team_ColorCode(player.team), player.netname))); @@ -696,7 +726,7 @@ void ctf_Handle_Pickup(entity flag, entity player, int pickuptype) FOREACH_CLIENT(IS_PLAYER(it) && it != player, LAMBDA( if(CTF_SAMETEAM(flag, it)) if(SAME_TEAM(player, it)) - Send_Notification(NOTIF_ONE, it, MSG_CHOICE, APP_TEAM_ENT(flag, CHOICE_CTF_PICKUP_TEAM), Team_ColorCode(player.team), player.netname); + 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); )); @@ -710,7 +740,7 @@ void ctf_Handle_Pickup(entity flag, entity player, int pickuptype) { case PICKUP_BASE: { - PlayerTeamScore_AddScore(player, autocvar_g_ctf_score_pickup_base); + PlayerTeamScore_AddScore(player, ((flag.score_pickup) ? flag.score_pickup : autocvar_g_ctf_score_pickup_base)); ctf_EventLog("steal", flag.team, player); break; } @@ -760,14 +790,17 @@ void ctf_CheckFlagReturn(entity flag, int returntype) { switch(returntype) { - case RETURN_DROPPED: Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((flag.team) ? APP_TEAM_ENT(flag, INFO_CTF_FLAGRETURN_DROPPED) : INFO_CTF_FLAGRETURN_DROPPED_NEUTRAL)); break; - case RETURN_DAMAGE: Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((flag.team) ? APP_TEAM_ENT(flag, INFO_CTF_FLAGRETURN_DAMAGED) : INFO_CTF_FLAGRETURN_DAMAGED_NEUTRAL)); break; - case RETURN_SPEEDRUN: Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((flag.team) ? APP_TEAM_ENT(flag, INFO_CTF_FLAGRETURN_SPEEDRUN) : INFO_CTF_FLAGRETURN_SPEEDRUN_NEUTRAL), ctf_captimerecord); break; - case RETURN_NEEDKILL: Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((flag.team) ? APP_TEAM_ENT(flag, INFO_CTF_FLAGRETURN_NEEDKILL) : INFO_CTF_FLAGRETURN_NEEDKILL_NEUTRAL)); break; - + case RETURN_DROPPED: + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_DROPPED)); break; + case RETURN_DAMAGE: + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_DAMAGED)); break; + case RETURN_SPEEDRUN: + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_SPEEDRUN), ctf_captimerecord); break; + case RETURN_NEEDKILL: + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_NEEDKILL)); break; default: case RETURN_TIMEOUT: - { Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((flag.team) ? APP_TEAM_ENT(flag, INFO_CTF_FLAGRETURN_TIMEOUT) : INFO_CTF_FLAGRETURN_TIMEOUT_NEUTRAL)); break; } + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_TIMEOUT)); break; } _sound(flag, CH_TRIGGER, flag.snd_flag_respawn, VOL_BASE, ATTEN_NONE); ctf_EventLog("returned", flag.team, NULL); @@ -860,9 +893,7 @@ void ctf_FlagDamage(entity this, entity inflictor, entity attacker, float damage if(ITEM_DAMAGE_NEEDKILL(deathtype)) { if(autocvar_g_ctf_flag_return_damage_delay) - { - this.ctf_flagdamaged = true; - } + this.ctf_flagdamaged_byworld = true; else { this.health = 0; @@ -891,21 +922,11 @@ void ctf_FlagThink(entity this) 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, CTF_FLAG.m_maxs); } - - switch(this.ctf_status) // reset flag angles in case warpzones adjust it - { - case FLAG_DROPPED: - { - this.angles = '0 0 0'; - break; - } - - default: break; + setsize(this, this.m_mins, this.m_maxs); } // main think method @@ -926,6 +947,8 @@ void ctf_FlagThink(entity this) case FLAG_DROPPED: { + this.angles = '0 0 0'; // reset flag angles in case warpzones adjust it + if(autocvar_g_ctf_flag_dropped_floatinwater) { vector midpoint = ((this.absmin + this.absmax) * 0.5); @@ -949,7 +972,7 @@ void ctf_FlagThink(entity this) return; } } - if(this.ctf_flagdamaged) + if(this.ctf_flagdamaged_byworld) { this.health -= ((this.max_flag_health / autocvar_g_ctf_flag_return_damage_delay) * FLAG_THINKRATE); ctf_CheckFlagReturn(this, RETURN_NEEDKILL); @@ -1027,7 +1050,7 @@ void ctf_FlagThink(entity this) METHOD(Flag, giveTo, bool(Flag this, entity flag, entity toucher)) { return = false; - if(gameover) { return; } + if(game_stopped) return; if(trace_dphitcontents & (DPCONTENTS_PLAYERCLIP | DPCONTENTS_MONSTERCLIP)) { return; } bool is_not_monster = (!IS_MONSTER(toucher)); @@ -1040,12 +1063,9 @@ METHOD(Flag, giveTo, bool(Flag this, entity flag, entity toucher)) flag.health = 0; ctf_CheckFlagReturn(flag, RETURN_NEEDKILL); } - if(!flag.ctf_flagdamaged) { return; } + if(!flag.ctf_flagdamaged_byworld) { return; } } - int num_perteam = 0; - FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(toucher, it), LAMBDA(++num_perteam)); - // special touch behaviors if(STAT(FROZEN, toucher)) { return; } else if(IS_VEHICLE(toucher)) @@ -1097,7 +1117,7 @@ METHOD(Flag, giveTo, bool(Flag this, entity flag, entity toucher)) case FLAG_DROPPED: { - if(CTF_SAMETEAM(toucher, flag) && (autocvar_g_ctf_flag_return || num_perteam <= 1 || (autocvar_g_ctf_flag_return_carrying && toucher.flagcarried)) && flag.team) // automatically return if there's only 1 player on the team + if(CTF_SAMETEAM(toucher, flag) && ctf_Immediate_Return_Allowed(flag, toucher)) ctf_Handle_Return(flag, toucher); // toucher just returned his 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 @@ -1115,8 +1135,13 @@ METHOD(Flag, giveTo, bool(Flag this, entity flag, entity toucher)) if((IS_PLAYER(toucher)) && !IS_DEAD(toucher) && (toucher != flag.pass_sender)) { if(DIFF_TEAM(toucher, flag.pass_sender)) - ctf_Handle_Return(flag, toucher); - else + { + if(ctf_Immediate_Return_Allowed(flag, toucher)) + ctf_Handle_Return(flag, toucher); + else if(is_not_monster && (!toucher.flagcarried)) + ctf_Handle_Pickup(flag, toucher, PICKUP_DROPPED); + } + else if(!toucher.flagcarried) ctf_Handle_Retrieve(flag, toucher); } break; @@ -1172,7 +1197,8 @@ void ctf_RespawnFlag(entity flag) flag.ctf_dropper = NULL; flag.ctf_pickuptime = 0; flag.ctf_droptime = 0; - flag.ctf_flagdamaged = 0; + flag.ctf_flagdamaged_byworld = false; + navigation_dynamicgoal_unset(flag); ctf_CheckStalemate(); } @@ -1187,7 +1213,12 @@ void ctf_Reset(entity this) bool ctf_FlagBase_Customize(entity this, entity client) { - if(client.flagcarried && CTF_SAMETEAM(client, client.flagcarried)) + entity e = WaypointSprite_getviewentity(client); + entity wp_owner = this.owner; + entity flag = e.flagcarried; + if(flag && CTF_SAMETEAM(e, flag)) + return false; + if(flag && (flag.cnt || wp_owner.cnt) && wp_owner.cnt != flag.cnt) return false; return true; } @@ -1196,8 +1227,7 @@ void ctf_DelayedFlagSetup(entity this) // called after a flag is placed on a map { // 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; @@ -1234,6 +1264,7 @@ void ctf_FlagSetup(int teamnumber, entity flag) // called when spawning a flag e 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; @@ -1245,6 +1276,8 @@ void ctf_FlagSetup(int teamnumber, entity flag) // called when spawning a flag e flag.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP; flag.damagedbytriggers = autocvar_g_ctf_flag_return_when_unreachable; flag.damagedbycontents = autocvar_g_ctf_flag_return_when_unreachable; + if(flag.damagedbycontents) + IL_PUSH(g_damagedbycontents, flag); flag.velocity = '0 0 0'; flag.mangle = flag.angles; flag.reset = ctf_Reset; @@ -1253,6 +1286,10 @@ void ctf_FlagSetup(int teamnumber, entity flag) // called when spawning a flag e flag.nextthink = time + FLAG_THINKRATE; flag.ctf_status = FLAG_BASE; + // 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; + string teamname = Static_Team_ColorName_Lower(teamnumber); // appearence if(!flag.scale) { flag.scale = FLAG_SCALE; } @@ -1281,7 +1318,9 @@ void ctf_FlagSetup(int teamnumber, entity flag) // called when spawning a flag e // appearence _setmodel(flag, flag.model); // precision set below - setsize(flag, CTF_FLAG.m_mins, CTF_FLAG.m_maxs); + 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) @@ -1341,7 +1380,7 @@ void havocbot_calculate_middlepoint() entity f; vector s = '0 0 0'; vector fo = '0 0 0'; - float n = 0; + int n = 0; f = ctf_worldflaglist; while (f) @@ -1349,11 +1388,12 @@ void havocbot_calculate_middlepoint() fo = f.origin; s = s + fo; f = f.ctf_worldflagnext; + n++; } if(!n) return; - havocbot_ctf_middlepoint = s * (1.0 / n); - havocbot_ctf_middlepoint_radius = vlen(fo - havocbot_ctf_middlepoint); + havocbot_ctf_middlepoint = s / n; + havocbot_ctf_middlepoint_radius = vlen(fo - havocbot_ctf_middlepoint); } @@ -1414,6 +1454,8 @@ int havocbot_ctf_teamcount(entity bot, vector org, float tc_radius) return c; } +// unused +#if 0 void havocbot_goalrating_ctf_ourflag(entity this, float ratingscale) { entity head; @@ -1427,6 +1469,7 @@ void havocbot_goalrating_ctf_ourflag(entity this, float ratingscale) if (head) navigation_routerating(this, head, ratingscale, 10000); } +#endif void havocbot_goalrating_ctf_ourbase(entity this, float ratingscale) { @@ -1435,7 +1478,15 @@ 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) @@ -1527,7 +1578,7 @@ void havocbot_goalrating_ctf_droppedflags(entity this, float ratingscale, vector 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) @@ -1635,7 +1686,7 @@ void havocbot_role_ctf_carrier(entity this) navigation_goalrating_end(this); - if (this.navigation_hasgoals) + if (this.goalentity) this.havocbot_cantfindflag = time + 10; else if (time > this.havocbot_cantfindflag) { @@ -1809,6 +1860,11 @@ void havocbot_role_ctf_retriever(entity this) mf = havocbot_ctf_find_flag(this); if(mf.ctf_status==FLAG_BASE) { + if(this.goalcurrent == mf) + { + navigation_clearroute(this); + this.bot_strategytime = 0; + } havocbot_ctf_reset_role(this); return; } @@ -2013,6 +2069,7 @@ MUTATOR_HOOKFUNCTION(ctf, PlayerPreThink) 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 @@ -2025,11 +2082,11 @@ MUTATOR_HOOKFUNCTION(ctf, PlayerPreThink) // 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) { @@ -2062,7 +2119,7 @@ MUTATOR_HOOKFUNCTION(ctf, PlayerPreThink) WaypointSprite_UpdateHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(player.health, player.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id)); } -MUTATOR_HOOKFUNCTION(ctf, PlayerDamage_Calculate) // for changing damage and force values that are applied to players in g_damage.qc +MUTATOR_HOOKFUNCTION(ctf, Damage_Calculate) // for changing damage and force values that are applied to players in g_damage.qc { entity frag_attacker = M_ARGV(1, entity); entity frag_target = M_ARGV(2, entity); @@ -2149,6 +2206,42 @@ MUTATOR_HOOKFUNCTION(ctf, ClientDisconnect) ctf_RemovePlayer(player); } +MUTATOR_HOOKFUNCTION(ctf, ClientConnect) +{ + if(!autocvar_g_ctf_leaderboard) + return; + + entity player = M_ARGV(0, entity); + + if(IS_REAL_CLIENT(player)) + { + for(int i = 1; i <= RANKINGS_CNT; ++i) + { + race_SendRankings(i, 0, 0, MSG_ONE); + } + } +} + +MUTATOR_HOOKFUNCTION(ctf, GetPressedKeys) +{ + if(!autocvar_g_ctf_leaderboard) + return; + + entity player = M_ARGV(0, entity); + + if(player.cvar_cl_allow_uidtracking == 1 && player.cvar_cl_allow_uid2name == 1) + { + if (!player.stored_netname) + player.stored_netname = strzone(uid2name(player.crypto_idfp)); + if(player.stored_netname != player.netname) + { + db_put(ServerProgsDB, strcat("/uid2name/", player.crypto_idfp), player.netname); + strunzone(player.stored_netname); + player.stored_netname = strzone(player.netname); + } + } +} + MUTATOR_HOOKFUNCTION(ctf, PortalTeleport) { entity player = M_ARGV(0, entity); @@ -2160,7 +2253,7 @@ MUTATOR_HOOKFUNCTION(ctf, PortalTeleport) MUTATOR_HOOKFUNCTION(ctf, PlayerUseKey) { - if(MUTATOR_RETURNVALUE || gameover) { return; } + if(MUTATOR_RETURNVALUE || game_stopped) return; entity player = M_ARGV(0, entity); @@ -2199,7 +2292,7 @@ MUTATOR_HOOKFUNCTION(ctf, PlayerUseKey) player.throw_antispam = time + autocvar_g_ctf_pass_wait; return true; } - else if(player.flagcarried) + else if(player.flagcarried && !head.flagcarried) { if(closest_target) { @@ -2311,7 +2404,7 @@ MUTATOR_HOOKFUNCTION(ctf, AbortSpeedrun) if(player.flagcarried) { - Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((player.flagcarried.team) ? APP_TEAM_ENT(player.flagcarried, INFO_CTF_FLAGRETURN_ABORTRUN) : INFO_CTF_FLAGRETURN_ABORTRUN_NEUTRAL)); + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(player.flagcarried.team, INFO_CTF_FLAGRETURN_ABORTRUN)); ctf_RespawnFlag(player.flagcarried); return true; } @@ -2357,7 +2450,7 @@ MUTATOR_HOOKFUNCTION(ctf, HavocBot_ChooseRole) return true; } -MUTATOR_HOOKFUNCTION(ctf, GetTeamCount) +MUTATOR_HOOKFUNCTION(ctf, CheckAllowedTeams) { //M_ARGV(0, float) = ctf_teams; M_ARGV(1, string) = "ctf_team"; @@ -2571,6 +2664,14 @@ spawnfunc(team_CTF_bluespawn) { spawnfunc_info_player_team2(this); } spawnfunc(team_CTF_neutralflag) { spawnfunc_item_flag_neutral(this); } spawnfunc(team_neutralobelisk) { spawnfunc_item_flag_neutral(this); } +// compatibility for wop maps +spawnfunc(team_redplayer) { spawnfunc_info_player_team1(this); } +spawnfunc(team_blueplayer) { spawnfunc_info_player_team2(this); } +spawnfunc(team_ctl_redlolly) { spawnfunc_item_flag_team1(this); } +spawnfunc(team_CTL_redlolly) { spawnfunc_item_flag_team1(this); } +spawnfunc(team_ctl_bluelolly) { spawnfunc_item_flag_team2(this); } +spawnfunc(team_CTL_bluelolly) { spawnfunc_item_flag_team2(this); } + // ============== // Initialization