]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/common/gamemodes/gamemode/freezetag/freezetag.qc
Merge branch 'master' into terencehill/bot_ai
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / gamemodes / gamemode / freezetag / freezetag.qc
index e86f6b72f5cdaad4adde20fb59914be4e6a759e4..6919518b8340ff1e65fa1f16d615eaed9eb7582b 100644 (file)
@@ -157,14 +157,14 @@ float freezetag_CheckWinner()
 entity freezetag_LastPlayerForTeam(entity this)
 {
        entity last_pl = NULL;
-       FOREACH_CLIENT(IS_PLAYER(it) && it != this, {
-               if(it.health >= 1)
-               if(!STAT(FROZEN, it))
-               if(SAME_TEAM(it, this))
-               if(!last_pl)
-                       last_pl = it;
-               else
-                       return NULL;
+       FOREACH_CLIENT(IS_PLAYER(it) && it != this && SAME_TEAM(it, this), {
+               if (!STAT(FROZEN, it) && GetResourceAmount(it, RESOURCE_HEALTH) >= 1)
+               {
+                       if (!last_pl)
+                               last_pl = it;
+                       else
+                               return NULL;
+               }
        });
        return last_pl;
 }
@@ -198,6 +198,7 @@ void freezetag_Add_Score(entity targ, entity attacker)
        // else nothing - got frozen by the game type rules themselves
 }
 
+// to be called when the player is frozen by freezetag (on death, spectator join etc), gives the score
 void freezetag_Freeze(entity targ, entity attacker)
 {
        if(STAT(FROZEN, targ))
@@ -213,14 +214,6 @@ void freezetag_Freeze(entity targ, entity attacker)
        freezetag_Add_Score(targ, attacker);
 }
 
-void freezetag_Unfreeze(entity this)
-{
-       this.freezetag_frozen_time = 0;
-       this.freezetag_frozen_timeout = 0;
-
-       Unfreeze(this);
-}
-
 float freezetag_isEliminated(entity e)
 {
        if(IS_PLAYER(e) && (STAT(FROZEN, e) == 1 || IS_DEAD(e)))
@@ -236,9 +229,10 @@ float freezetag_isEliminated(entity e)
 void(entity this) havocbot_role_ft_freeing;
 void(entity this) havocbot_role_ft_offense;
 
-void havocbot_goalrating_freeplayers(entity this, float ratingscale, vector org, float sradius)
+void havocbot_goalrating_ft_freeplayers(entity this, float ratingscale, vector org, float sradius)
 {
-       float t;
+       entity best_pl = NULL;
+       float best_dist2 = FLOAT_MAX;
        FOREACH_CLIENT(IS_PLAYER(it) && it != this && SAME_TEAM(it, this), {
                if (STAT(FROZEN, it) == 1)
                {
@@ -246,14 +240,24 @@ void havocbot_goalrating_freeplayers(entity this, float ratingscale, vector org,
                                continue;
                        navigation_routerating(this, it, ratingscale, 2000);
                }
-               else if(vdist(it.origin - org, >, 400)) // avoid gathering all teammates in one place
+               else if (best_dist2
+                       && GetResourceAmount(it, RESOURCE_HEALTH) < GetResourceAmount(this, RESOURCE_HEALTH) + 30
+                       && vlen2(it.origin - org) < best_dist2)
                {
                        // If teamate is not frozen still seek them out as fight better
                        // in a group.
-                       t = 0.2 * 150 / (this.health + this.armorvalue);
-                       navigation_routerating(this, it, t * ratingscale, 2000);
+                       best_dist2 = vlen2(it.origin - org);
+                       if (best_dist2 < 700 ** 2)
+                       {
+                               best_pl = NULL;
+                               best_dist2 = 0; // already close to a teammate
+                       }
+                       else
+                               best_pl = it;
                }
        });
+       if (best_pl)
+               navigation_routerating(this, best_pl, ratingscale / 2, 2000);
 }
 
 void havocbot_role_ft_offense(entity this)
@@ -266,10 +270,10 @@ void havocbot_role_ft_offense(entity this)
 
        // Count how many players on team are unfrozen.
        int unfrozen = 0;
-       FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(it, this) && !(STAT(FROZEN, it) != 1), { unfrozen++; });
+       FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(it, this) && !STAT(FROZEN, it), { unfrozen++; });
 
        // If only one left on team or if role has timed out then start trying to free players.
-       if (((unfrozen == 0) && (!STAT(FROZEN, this))) || (time > this.havocbot_role_timeout))
+       if ((unfrozen == 0 && !STAT(FROZEN, this)) || time > this.havocbot_role_timeout)
        {
                LOG_TRACE("changing role to freeing");
                this.havocbot_role = havocbot_role_ft_freeing;
@@ -280,9 +284,9 @@ void havocbot_role_ft_offense(entity this)
        if (navigation_goalrating_timeout(this))
        {
                navigation_goalrating_start(this);
-               havocbot_goalrating_items(this, 10000, this.origin, 10000);
-               havocbot_goalrating_enemyplayers(this, 20000, this.origin, 10000);
-               havocbot_goalrating_freeplayers(this, 9000, this.origin, 10000);
+               havocbot_goalrating_items(this, 12000, this.origin, 10000);
+               havocbot_goalrating_enemyplayers(this, 10000, this.origin, 10000);
+               havocbot_goalrating_ft_freeplayers(this, 9000, this.origin, 10000);
                havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
                navigation_goalrating_end(this);
 
@@ -309,9 +313,9 @@ void havocbot_role_ft_freeing(entity this)
        if (navigation_goalrating_timeout(this))
        {
                navigation_goalrating_start(this);
-               havocbot_goalrating_items(this, 8000, this.origin, 10000);
-               havocbot_goalrating_enemyplayers(this, 10000, this.origin, 10000);
-               havocbot_goalrating_freeplayers(this, 20000, this.origin, 10000);
+               havocbot_goalrating_items(this, 10000, this.origin, 10000);
+               havocbot_goalrating_enemyplayers(this, 5000, this.origin, 10000);
+               havocbot_goalrating_ft_freeplayers(this, 20000, this.origin, 10000);
                havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
                navigation_goalrating_end(this);
 
@@ -326,10 +330,10 @@ void havocbot_role_ft_freeing(entity this)
 
 void ft_RemovePlayer(entity this)
 {
-       this.health = 0; // neccessary to update correctly alive stats
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, 0); // neccessary to update correctly alive stats
        if(!STAT(FROZEN, this))
                freezetag_LastPlayerForTeam_Notify(this);
-       freezetag_Unfreeze(this);
+       Unfreeze(this);
        freezetag_count_alive_players();
 }
 
@@ -358,7 +362,7 @@ MUTATOR_HOOKFUNCTION(ft, PlayerDies)
        if(round_handler_CountdownRunning())
        {
                if(STAT(FROZEN, frag_target))
-                       freezetag_Unfreeze(frag_target);
+                       Unfreeze(frag_target);
                freezetag_count_alive_players();
                return true; // let the player die so that he can respawn whenever he wants
        }
@@ -376,8 +380,8 @@ MUTATOR_HOOKFUNCTION(ft, PlayerDies)
                        freezetag_LastPlayerForTeam_Notify(frag_target);
                }
                else
-                       freezetag_Unfreeze(frag_target); // remove ice
-               frag_target.health = 0; // Unfreeze resets health
+                       Unfreeze(frag_target); // remove ice
+               SetResourceAmountExplicit(frag_target, RESOURCE_HEALTH, 0); // Unfreeze resets health
                frag_target.freezetag_frozen_timeout = -2; // freeze on respawn
                return true;
        }
@@ -445,6 +449,15 @@ MUTATOR_HOOKFUNCTION(ft, GiveFragsForKill, CBC_ORDER_FIRST)
        return true;
 }
 
+MUTATOR_HOOKFUNCTION(ft, Unfreeze)
+{
+       entity targ = M_ARGV(0, entity);
+       targ.freezetag_frozen_time = 0;
+       targ.freezetag_frozen_timeout = 0;
+
+       freezetag_count_alive_players();
+}
+
 MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
 {
        if(game_stopped)
@@ -486,11 +499,11 @@ MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
        if(n && STAT(FROZEN, player) == 1) // OK, there is at least one teammate reviving us
        {
                STAT(REVIVE_PROGRESS, player) = bound(0, STAT(REVIVE_PROGRESS, player) + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1);
-               player.health = max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health));
+               SetResourceAmountExplicit(player, RESOURCE_HEALTH, max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health)));
 
                if(STAT(REVIVE_PROGRESS, player) >= 1)
                {
-                       freezetag_Unfreeze(player);
+                       Unfreeze(player);
                        freezetag_count_alive_players();
 
                        if(n == -1)
@@ -520,7 +533,7 @@ MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
        else if(!n && STAT(FROZEN, player) == 1) // only if no teammate is nearby will we reset
        {
                STAT(REVIVE_PROGRESS, player) = bound(0, STAT(REVIVE_PROGRESS, player) - frametime * autocvar_g_freezetag_revive_clearspeed, 1);
-               player.health = max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health));
+               SetResourceAmountExplicit(player, RESOURCE_HEALTH, max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health)));
        }
        else if(!n && !STAT(FROZEN, player))
        {
@@ -555,6 +568,10 @@ MUTATOR_HOOKFUNCTION(ft, HavocBot_ChooseRole)
                        bot.havocbot_role = havocbot_role_ft_offense;
        }
 
+       // if bots spawn all at once assign them a more appropriated role after a while
+       if (time < CS(bot).jointime + 1)
+               bot.havocbot_role_timeout = time + 10 + random() * 10;
+
        return true;
 }
 
@@ -583,7 +600,8 @@ MUTATOR_HOOKFUNCTION(ft, FragCenterMessage)
                return; // target was already frozen, so this is just pushing them off the cliff
 
        Send_Notification(NOTIF_ONE, frag_attacker, MSG_CHOICE, CHOICE_FRAG_FREEZE, frag_target.netname, kill_count_to_attacker, (IS_BOT_CLIENT(frag_target) ? -1 : CS(frag_target).ping));
-       Send_Notification(NOTIF_ONE, frag_target, MSG_CHOICE, CHOICE_FRAGGED_FREEZE, frag_attacker.netname, kill_count_to_target, frag_attacker.health, frag_attacker.armorvalue, (IS_BOT_CLIENT(frag_attacker) ? -1 : CS(frag_attacker).ping));
+       Send_Notification(NOTIF_ONE, frag_target, MSG_CHOICE, CHOICE_FRAGGED_FREEZE, frag_attacker.netname, kill_count_to_target,
+               GetResourceAmount(frag_attacker, RESOURCE_HEALTH), GetResourceAmount(frag_attacker, RESOURCE_ARMOR), (IS_BOT_CLIENT(frag_attacker) ? -1 : CS(frag_attacker).ping));
 
        return true;
 }
@@ -596,7 +614,7 @@ void freezetag_Initialize()
 
        freezetag_teams = BITS(bound(2, freezetag_teams, 4));
        GameRules_scoring(freezetag_teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, {
-           field(SP_FREEZETAG_REVIVALS, "revivals", 0);
+               field(SP_FREEZETAG_REVIVALS, "revivals", 0);
        });
 
        round_handler_Spawn(freezetag_CheckTeams, freezetag_CheckWinner, func_null);