]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/mutators/gamemode_ctf.qc
Fix balancing with drop penalties; add assist points for previous carriers
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / mutators / gamemode_ctf.qc
index 342f529836e09fb3a0a6d680359b643a384267b0..15e62c5b7e9f51a845859ecbd8d361ffa424116b 100644 (file)
@@ -3,14 +3,6 @@
 //  Last updated: March 30th, 2012
 // ================================================================
 
-float ctf_ReadScore(string parameter) // make this obsolete
-{
-       //if(g_ctf_win_mode != 2)
-               return cvar(strcat("g_ctf_personal", parameter));
-       //else
-       //      return cvar(strcat("g_ctf_flag", parameter));
-}
-
 void ctf_FakeTimeLimit(entity e, float t)
 {
        msg_entity = e;
@@ -184,7 +176,7 @@ void ctf_Handle_Drop(entity flag, entity player, float droptype)
        ctf_EventLog("dropped", player.team, player);
 
        // scoring
-       PlayerTeamScore_AddScore(player, -ctf_ReadScore("penalty_drop"));       
+       PlayerTeamScore_AddScore(player, -autocvar_g_ctf_score_penalty_drop);   
        PlayerScore_Add(player, SP_CTF_DROPS, 1);
        
        // waypoints
@@ -212,7 +204,6 @@ void ctf_Handle_Retrieve(entity flag, entity player)
        entity sender = flag.pass_sender;
        
        // transfer flag to player
-       flag.ctf_carrier = player;
        flag.owner = player;
        flag.owner.flagcarried = flag;
        
@@ -252,6 +243,7 @@ void ctf_Handle_Retrieve(entity flag, entity player)
 void ctf_Handle_Throw(entity player, entity reciever, float droptype)
 {
        entity flag = player.flagcarried;
+       vector targ_origin;
        
        if(!flag) { return; }
        if((droptype == DROP_PASS) && !reciever) { return; }
@@ -272,7 +264,8 @@ void ctf_Handle_Throw(entity player, entity reciever, float droptype)
        {
                case DROP_PASS:
                {
-                       vector targ_origin = WarpZone_RefSys_TransformOrigin(player, reciever, (0.5 * (reciever.absmin + reciever.absmax)));
+                       WarpZone_RefSys_MakeSameRefSys(flag, player);
+                       targ_origin = WarpZone_RefSys_TransformOrigin(reciever, flag, (0.5 * (reciever.absmin + reciever.absmax)));
                        flag.velocity = (normalize(targ_origin - player.origin) * autocvar_g_ctf_pass_velocity);
                        break;
                }
@@ -311,7 +304,7 @@ void ctf_Handle_Throw(entity player, entity reciever, float droptype)
                        
                        // other
                        sound(player, CH_TRIGGER, flag.snd_flag_touch, VOL_BASE, ATTN_NORM);
-                       WarpZone_TrailParticles(world, particleeffectnum(flag.passeffect), reciever.origin, player.origin);
+                       WarpZone_TrailParticles(world, particleeffectnum(flag.passeffect), targ_origin, player.origin);
                        ctf_EventLog("pass", flag.team, player);
                        break;
                }
@@ -351,6 +344,7 @@ void ctf_Handle_Capture(entity flag, entity toucher, float capturetype)
 {
        entity enemy_flag = ((capturetype == CAPTURE_NORMAL) ? toucher.flagcarried : toucher);
        entity player = ((capturetype == CAPTURE_NORMAL) ? toucher : enemy_flag.ctf_dropper);
+       float old_time, new_time; 
        
        if not(player) { return; } // without someone to give the reward to, we can't possibly cap
        
@@ -366,9 +360,14 @@ void ctf_Handle_Capture(entity flag, entity toucher, float capturetype)
        }
        
        // scoring
-       PlayerTeamScore_AddScore(player, ctf_ReadScore("score_capture"));
+       PlayerTeamScore_AddScore(player, autocvar_g_ctf_score_capture);
        PlayerTeamScore_Add(player, SP_CTF_CAPS, ST_CTF_CAPS, 1);
 
+       old_time = PlayerScore_Add(player, SP_CTF_CAPTIME, 0);
+       new_time = TIME_ENCODE(time - enemy_flag.ctf_pickuptime);
+       if(!old_time || new_time < old_time)
+               PlayerScore_Add(player, SP_CTF_CAPTIME, new_time - old_time);
+
        // effects
        if(autocvar_g_ctf_flag_capture_effects) 
        {
@@ -381,6 +380,7 @@ void ctf_Handle_Capture(entity flag, entity toucher, float capturetype)
        {
                WaypointSprite_Kill(player.wps_flagcarrier);
                if(flag.speedrunning) { ctf_FakeTimeLimit(player, -1); }
+               if(enemy_flag.ctf_dropper) { PlayerTeamScore_AddScore(enemy_flag.ctf_dropper, autocvar_g_ctf_score_capture_assist); }
        }
        
        // reset the flag
@@ -397,14 +397,14 @@ void ctf_Handle_Return(entity flag, entity player)
        ctf_EventLog("return", flag.team, player);
 
        // scoring
-       PlayerTeamScore_AddScore(player, ctf_ReadScore("score_return")); // reward for return
+       PlayerTeamScore_AddScore(player, autocvar_g_ctf_score_return); // reward for return
        PlayerScore_Add(player, SP_CTF_RETURNS, 1); // add to count of returns
 
-       TeamScore_AddToTeam(flag.team, ST_SCORE, -ctf_ReadScore("penalty_returned")); // punish the team who was last carrying it
+       TeamScore_AddToTeam(flag.team, ST_SCORE, -autocvar_g_ctf_score_penalty_returned); // punish the team who was last carrying it
        
        if(flag.ctf_dropper) 
        {
-               PlayerScore_Add(flag.ctf_dropper, SP_SCORE, -ctf_ReadScore("penalty_returned")); // punish the player who dropped the flag
+               PlayerScore_Add(flag.ctf_dropper, SP_SCORE, -autocvar_g_ctf_score_penalty_returned); // punish the player who dropped the flag
                ctf_CaptureShield_Update(flag.ctf_dropper, 0); // shield player from picking up flag 
                flag.ctf_dropper.next_take_time = time + autocvar_g_ctf_flag_collect_delay; // set next take time
        }
@@ -469,14 +469,14 @@ void ctf_Handle_Pickup(entity flag, entity player, float pickuptype)
        {               
                case PICKUP_BASE:
                {
-                       PlayerTeamScore_AddScore(player, ctf_ReadScore("score_pickup_base"));
+                       PlayerTeamScore_AddScore(player, autocvar_g_ctf_score_pickup_base);
                        break;
                }
                
                case PICKUP_DROPPED:
                {
                        pickup_dropped_score = (autocvar_g_ctf_flag_return_time ? bound(0, ((flag.ctf_droptime + autocvar_g_ctf_flag_return_time) - time) / autocvar_g_ctf_flag_return_time, 1) : 1);
-                       pickup_dropped_score = floor((ctf_ReadScore("score_pickup_dropped_late") * (1 - pickup_dropped_score) + ctf_ReadScore("score_pickup_dropped_early") * pickup_dropped_score) + 0.5);
+                       pickup_dropped_score = floor((autocvar_g_ctf_score_pickup_dropped_late * (1 - pickup_dropped_score) + autocvar_g_ctf_score_pickup_dropped_early * pickup_dropped_score) + 0.5);
                        print("pickup_dropped_score is ", ftos(pickup_dropped_score), "\n");
                        PlayerTeamScore_AddScore(player, pickup_dropped_score);
                        break;
@@ -707,40 +707,13 @@ void ctf_FlagThink()
                }
                
                case FLAG_PASSING: // todo make work with warpzones
-               {                       
-                       /*vector targ_origin = ((self.pass_target.absmin + self.pass_target.absmax) * 0.5);
-                       vector old_targ_origin = targ_origin;
-                       targ_origin = WarpZone_RefSys_TransformOrigin(self.pass_sender, self.pass_target, targ_origin);
-
-                       print("old: ", vtos(old_targ_origin), ", transformed: ", vtos(targ_origin), ".\n");
-                       
-                       WarpZone_TraceLine(self.origin, targ_origin, MOVE_NOMONSTERS, self);
-                       
-                       te_customflash(self.origin, 40,  2, '1 1 1');
-                       te_customflash(targ_origin, 200, 2, '15 0 0');
-                       
-                       if((self.pass_target.deadflag != DEAD_NO)
-                               || (vlen(self.origin - targ_origin) > autocvar_g_ctf_pass_radius)
-                               || ((trace_fraction < 1) && (trace_ent != self.pass_target))
-                               || (time > self.ctf_droptime + autocvar_g_ctf_pass_timelimit))
-                       {
-                               ctf_Handle_Drop(self, world, DROP_PASS);
-                       }
-                       else // still a viable target, go for it
-                       {
-                               vector desired_direction = normalize(targ_origin - self.origin);
-                               vector current_direction = normalize(self.velocity);
-                               
-                               self.velocity = (normalize(current_direction + (desired_direction * autocvar_g_ctf_pass_turnrate)) * autocvar_g_ctf_pass_velocity); 
-                       }
-                       return;*/
-
+               {
                        vector targ_origin = ((self.pass_target.absmin + self.pass_target.absmax) * 0.5);
                        vector old_targ_origin = targ_origin;
-                       targ_origin = WarpZone_RefSys_TransformOrigin(self.pass_sender, self.pass_target, targ_origin);
+                       targ_origin = WarpZone_RefSys_TransformOrigin(self.pass_target, self, targ_origin);
                        WarpZone_TraceLine(self.origin, targ_origin, MOVE_NOMONSTERS, self);
 
-                       print("old: ", vtos(old_targ_origin), ", transformed: ", vtos(targ_origin), ".\n");
+                       print(strcat("self: ", vtos(self.origin), ", old: ", vtos(old_targ_origin), " (", ftos(vlen(self.origin - old_targ_origin)), "qu)"), ", transformed: ", vtos(targ_origin), " (", ftos(vlen(self.origin - targ_origin)), "qu)", ".\n");
                        
                        if((self.pass_target.deadflag != DEAD_NO)
                                || (vlen(self.origin - targ_origin) > autocvar_g_ctf_pass_radius)
@@ -753,8 +726,7 @@ void ctf_FlagThink()
                        {
                                vector desired_direction = normalize(targ_origin - self.origin);
                                vector current_direction = normalize(self.velocity);
-                               
-                               // self.velocity = (normalize(current_direction + (desired_direction * autocvar_g_ctf_pass_turnrate)) * autocvar_g_ctf_pass_velocity);
+
                                self.velocity = (normalize(current_direction + (desired_direction * autocvar_g_ctf_pass_turnrate)) * autocvar_g_ctf_pass_velocity); 
                        }
                        return;
@@ -1024,9 +996,10 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerPreThink)
        {
                switch(flag.ctf_status)
                {
+                       case FLAG_PASSING:
                        case FLAG_CARRY:
                        {
-                               if(flag.owner == self)
+                               if((flag.owner == self) || (flag.pass_sender == self))
                                        self.items |= ((flag.items & IT_KEY2) ? IT_RED_FLAG_CARRYING : IT_BLUE_FLAG_CARRYING); // carrying: self is currently carrying the flag
                                else 
                                        self.items |= ((flag.items & IT_KEY2) ? IT_RED_FLAG_TAKEN : IT_BLUE_FLAG_TAKEN); // taken: someone on self's team is carrying the flag
@@ -1046,7 +1019,7 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerPreThink)
        
        // update the health of the flag carrier waypointsprite
        if(self.wps_flagcarrier) 
-               WaypointSprite_UpdateHealth(self.wps_flagcarrier, self.health);
+               WaypointSprite_UpdateHealth(self.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(self.health, self.armorvalue, autocvar_g_balance_armor_blockpercent));
        
        return 0;
 }
@@ -1068,7 +1041,7 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerDamage) // for changing damage and force values t
        }
        else if(frag_target.flagcarried && (frag_target.deadflag == DEAD_NO) && IsDifferentTeam(frag_target, frag_attacker)) // if the target is a flagcarrier
        {
-               if(autocvar_g_ctf_flagcarrier_auto_helpme_when_damaged > frag_target.health)
+               if(autocvar_g_ctf_flagcarrier_auto_helpme_when_damaged > ('1 0 0' * healtharmor_maxdamage(frag_target.health, frag_target.armorvalue, autocvar_g_balance_armor_blockpercent)))
                        WaypointSprite_HelpMePing(frag_target.wps_flagcarrier); // TODO: only do this if there is a significant loss of health?
        }
        return 0;
@@ -1078,7 +1051,7 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerDies)
 {
        if((frag_attacker != frag_target) && (frag_attacker.classname == "player") && (frag_target.flagcarried))
        {
-               PlayerTeamScore_AddScore(frag_attacker, ctf_ReadScore("score_kill"));
+               PlayerTeamScore_AddScore(frag_attacker, autocvar_g_ctf_score_kill);
                PlayerScore_Add(frag_attacker, SP_CTF_FCKILLS, 1);
        }
                                
@@ -1148,7 +1121,7 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerUseKey)
                                        {
                                                if(closest_target)
                                                {
-                                                       if(vlen(player.origin - WarpZone_RefSys_TransformOrigin(player, head, head.origin)) < vlen(player.origin - WarpZone_RefSys_TransformOrigin(player, head, closest_target.origin)))
+                                                       if(vlen(player.origin - WarpZone_UnTransformOrigin(head, head.origin)) < vlen(player.origin - WarpZone_UnTransformOrigin(closest_target, closest_target.origin)))
                                                                { closest_target = head; }
                                                }
                                                else { closest_target = head; }
@@ -1185,18 +1158,18 @@ MUTATOR_HOOKFUNCTION(ctf_HelpMePing)
 
 MUTATOR_HOOKFUNCTION(ctf_VehicleEnter)
 {
-       if(other.flagcarried)
+       if(vh_player.flagcarried)
        {
                if(!autocvar_g_ctf_flagcarrier_allow_vehicle_carry)
                {
-                       ctf_Handle_Throw(self, world, DROP_NORMAL);
+                       ctf_Handle_Throw(vh_player, world, DROP_NORMAL);
                }
                else
                {            
-                       setattachment(other.flagcarried, self, ""); 
-                       setorigin(other, VEHICLE_FLAG_OFFSET);
-                       other.flagcarried.scale = VEHICLE_FLAG_SCALE;
-                       //other.flagcarried.angles = '0 0 0';   
+                       setattachment(vh_player.flagcarried, vh_vehicle, ""); 
+                       setorigin(vh_player.flagcarried, VEHICLE_FLAG_OFFSET);
+                       vh_player.flagcarried.scale = VEHICLE_FLAG_SCALE;
+                       //vh_player.flagcarried.angles = '0 0 0';       
                }
        }
                
@@ -1205,12 +1178,12 @@ MUTATOR_HOOKFUNCTION(ctf_VehicleEnter)
 
 MUTATOR_HOOKFUNCTION(ctf_VehicleExit)
 {
-       if(self.owner.flagcarried)
+       if(vh_player.flagcarried)
        {
-               setattachment(self.owner.flagcarried, self.owner, ""); 
-               setorigin(self.owner.flagcarried, FLAG_CARRY_OFFSET);
-               self.owner.flagcarried.scale = FLAG_SCALE;
-               self.owner.flagcarried.angles = '0 0 0';        
+               setattachment(vh_player.flagcarried, vh_player, ""); 
+               setorigin(vh_player.flagcarried, FLAG_CARRY_OFFSET);
+               vh_player.flagcarried.scale = FLAG_SCALE;
+               vh_player.flagcarried.angles = '0 0 0'; 
        }
 
        return 0;