]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/mutators/gamemode_keyhunt.qc
Mapinfo: decentralise mapinfo parsing
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / mutators / gamemode_keyhunt.qc
index 68097755e8e23a5515e95845c9adb7201cbad047..8f680ae648ee9c583b91c419029e0a83423e9e55 100644 (file)
@@ -2,6 +2,28 @@
 
 #include "gamemode.qh"
 
+float autocvar_g_balance_keyhunt_damageforcescale;
+float autocvar_g_balance_keyhunt_delay_collect;
+float autocvar_g_balance_keyhunt_delay_return;
+float autocvar_g_balance_keyhunt_delay_round;
+float autocvar_g_balance_keyhunt_delay_tracking;
+float autocvar_g_balance_keyhunt_dropvelocity;
+float autocvar_g_balance_keyhunt_maxdist;
+float autocvar_g_balance_keyhunt_protecttime;
+
+int autocvar_g_balance_keyhunt_score_capture;
+int autocvar_g_balance_keyhunt_score_carrierfrag;
+int autocvar_g_balance_keyhunt_score_collect;
+int autocvar_g_balance_keyhunt_score_destroyed;
+int autocvar_g_balance_keyhunt_score_destroyed_ownfactor;
+int autocvar_g_balance_keyhunt_score_push;
+float autocvar_g_balance_keyhunt_throwvelocity;
+
+int autocvar_g_keyhunt_point_leadlimit;
+bool autocvar_g_keyhunt_team_spawns;
+#define autocvar_g_keyhunt_point_limit cvar("g_keyhunt_point_limit")
+int autocvar_g_keyhunt_teams;
+int autocvar_g_keyhunt_teams_override;
 
 // #define KH_PLAYER_USE_ATTACHMENT
 // #define KH_PLAYER_USE_CARRIEDMODEL
@@ -1037,15 +1059,219 @@ void kh_finalize()
        kh_controller = world;
 }
 
+// legacy bot role
+
+void() havocbot_role_kh_carrier;
+void() havocbot_role_kh_defense;
+void() havocbot_role_kh_offense;
+void() havocbot_role_kh_freelancer;
+
+
+void havocbot_goalrating_kh(float ratingscale_team, float ratingscale_dropped, float ratingscale_enemy)
+{SELFPARAM();
+       entity head;
+       for (head = kh_worldkeylist; head; head = head.kh_worldkeynext)
+       {
+               if(head.owner == self)
+                       continue;
+               if(!kh_tracking_enabled)
+               {
+                       // if it's carried by our team we know about it
+                       // otherwise we have to see it to know about it
+                       if(!head.owner || head.team != self.team)
+                       {
+                               traceline(self.origin + self.view_ofs, head.origin, MOVE_NOMONSTERS, self);
+                               if (trace_fraction < 1 && trace_ent != head)
+                                       continue; // skip what I can't see
+                       }
+               }
+               if(!head.owner)
+                       navigation_routerating(head, ratingscale_dropped * BOT_PICKUP_RATING_HIGH, 100000);
+               else if(head.team == self.team)
+                       navigation_routerating(head.owner, ratingscale_team * BOT_PICKUP_RATING_HIGH, 100000);
+               else
+                       navigation_routerating(head.owner, ratingscale_enemy * BOT_PICKUP_RATING_HIGH, 100000);
+       }
+
+       havocbot_goalrating_items(1, self.origin, 10000);
+}
+
+void havocbot_role_kh_carrier()
+{SELFPARAM();
+       if(self.deadflag != DEAD_NO)
+               return;
+
+       if (!(self.kh_next))
+       {
+               LOG_TRACE("changing role to freelancer\n");
+               self.havocbot_role = havocbot_role_kh_freelancer;
+               self.havocbot_role_timeout = 0;
+               return;
+       }
+
+       if (self.bot_strategytime < time)
+       {
+               self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+               navigation_goalrating_start();
+
+               if(kh_Key_AllOwnedByWhichTeam() == self.team)
+                       havocbot_goalrating_kh(10, 0.1, 0.1); // bring home
+               else
+                       havocbot_goalrating_kh(4, 4, 1); // play defensively
+
+               navigation_goalrating_end();
+       }
+}
+
+void havocbot_role_kh_defense()
+{SELFPARAM();
+       if(self.deadflag != DEAD_NO)
+               return;
+
+       if (self.kh_next)
+       {
+               LOG_TRACE("changing role to carrier\n");
+               self.havocbot_role = havocbot_role_kh_carrier;
+               self.havocbot_role_timeout = 0;
+               return;
+       }
+
+       if (!self.havocbot_role_timeout)
+               self.havocbot_role_timeout = time + random() * 10 + 20;
+       if (time > self.havocbot_role_timeout)
+       {
+               LOG_TRACE("changing role to freelancer\n");
+               self.havocbot_role = havocbot_role_kh_freelancer;
+               self.havocbot_role_timeout = 0;
+               return;
+       }
+
+       if (self.bot_strategytime < time)
+       {
+               float key_owner_team;
+               self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+               navigation_goalrating_start();
+
+               key_owner_team = kh_Key_AllOwnedByWhichTeam();
+               if(key_owner_team == self.team)
+                       havocbot_goalrating_kh(10, 0.1, 0.1); // defend key carriers
+               else if(key_owner_team == -1)
+                       havocbot_goalrating_kh(4, 1, 0.1); // play defensively
+               else
+                       havocbot_goalrating_kh(0.1, 0.1, 10); // ATTACK ANYWAY
+
+               navigation_goalrating_end();
+       }
+}
+
+void havocbot_role_kh_offense()
+{SELFPARAM();
+       if(self.deadflag != DEAD_NO)
+               return;
+
+       if (self.kh_next)
+       {
+               LOG_TRACE("changing role to carrier\n");
+               self.havocbot_role = havocbot_role_kh_carrier;
+               self.havocbot_role_timeout = 0;
+               return;
+       }
+
+       if (!self.havocbot_role_timeout)
+               self.havocbot_role_timeout = time + random() * 10 + 20;
+       if (time > self.havocbot_role_timeout)
+       {
+               LOG_TRACE("changing role to freelancer\n");
+               self.havocbot_role = havocbot_role_kh_freelancer;
+               self.havocbot_role_timeout = 0;
+               return;
+       }
+
+       if (self.bot_strategytime < time)
+       {
+               float key_owner_team;
+
+               self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+               navigation_goalrating_start();
+
+               key_owner_team = kh_Key_AllOwnedByWhichTeam();
+               if(key_owner_team == self.team)
+                       havocbot_goalrating_kh(10, 0.1, 0.1); // defend anyway
+               else if(key_owner_team == -1)
+                       havocbot_goalrating_kh(0.1, 1, 4); // play offensively
+               else
+                       havocbot_goalrating_kh(0.1, 0.1, 10); // ATTACK! EMERGENCY!
+
+               navigation_goalrating_end();
+       }
+}
+
+void havocbot_role_kh_freelancer()
+{SELFPARAM();
+       if(self.deadflag != DEAD_NO)
+               return;
+
+       if (self.kh_next)
+       {
+               LOG_TRACE("changing role to carrier\n");
+               self.havocbot_role = havocbot_role_kh_carrier;
+               self.havocbot_role_timeout = 0;
+               return;
+       }
+
+       if (!self.havocbot_role_timeout)
+               self.havocbot_role_timeout = time + random() * 10 + 10;
+       if (time > self.havocbot_role_timeout)
+       {
+               if (random() < 0.5)
+               {
+                       LOG_TRACE("changing role to offense\n");
+                       self.havocbot_role = havocbot_role_kh_offense;
+               }
+               else
+               {
+                       LOG_TRACE("changing role to defense\n");
+                       self.havocbot_role = havocbot_role_kh_defense;
+               }
+               self.havocbot_role_timeout = 0;
+               return;
+       }
+
+       if (self.bot_strategytime < time)
+       {
+               float key_owner_team;
+
+               self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+               navigation_goalrating_start();
+
+               key_owner_team = kh_Key_AllOwnedByWhichTeam();
+               if(key_owner_team == self.team)
+                       havocbot_goalrating_kh(10, 0.1, 0.1); // defend anyway
+               else if(key_owner_team == -1)
+                       havocbot_goalrating_kh(1, 10, 4); // prefer dropped keys
+               else
+                       havocbot_goalrating_kh(0.1, 0.1, 10); // ATTACK ANYWAY
+
+               navigation_goalrating_end();
+       }
+}
+
+
 // register this as a mutator
 
-MUTATOR_HOOKFUNCTION(kh_Key_DropAll)
+MUTATOR_HOOKFUNCTION(kh, ClientDisconnect)
 {SELFPARAM();
        kh_Key_DropAll(self, true);
        return 0;
 }
 
-MUTATOR_HOOKFUNCTION(kh_PlayerDies)
+MUTATOR_HOOKFUNCTION(kh, MakePlayerObserver)
+{SELFPARAM();
+       kh_Key_DropAll(self, true);
+       return 0;
+}
+
+MUTATOR_HOOKFUNCTION(kh, PlayerDies)
 {SELFPARAM();
        if(self == other)
                kh_Key_DropAll(self, true);
@@ -1056,31 +1282,31 @@ MUTATOR_HOOKFUNCTION(kh_PlayerDies)
        return 0;
 }
 
-MUTATOR_HOOKFUNCTION(kh_GiveFragsForKill)
+MUTATOR_HOOKFUNCTION(kh, GiveFragsForKill, CBC_ORDER_FIRST)
 {
        frag_score = kh_HandleFrags(frag_attacker, frag_target, frag_score);
        return 0;
 }
 
-MUTATOR_HOOKFUNCTION(kh_finalize)
+MUTATOR_HOOKFUNCTION(kh, MatchEnd)
 {
        kh_finalize();
        return 0;
 }
 
-MUTATOR_HOOKFUNCTION(kh_GetTeamCount)
+MUTATOR_HOOKFUNCTION(kh, GetTeamCount, CBC_ORDER_EXCLUSIVE)
 {
        ret_float = kh_teams;
-       return 0;
+       return false;
 }
 
-MUTATOR_HOOKFUNCTION(kh_SpectateCopy)
+MUTATOR_HOOKFUNCTION(khSpectateCopy)
 {SELFPARAM();
        self.kh_state = other.kh_state;
        return 0;
 }
 
-MUTATOR_HOOKFUNCTION(kh_PlayerUseKey)
+MUTATOR_HOOKFUNCTION(khPlayerUseKey)
 {SELFPARAM();
        if(MUTATOR_RETURNVALUE == 0)
        {
@@ -1095,16 +1321,40 @@ MUTATOR_HOOKFUNCTION(kh_PlayerUseKey)
        return 0;
 }
 
-MUTATOR_DEFINITION(gamemode_keyhunt)
+MUTATOR_HOOKFUNCTION(kh, HavocBot_ChooseRole)
+{
+       if(self.deadflag != DEAD_NO)
+               return true;
+
+       float r = random() * 3;
+       if (r < 1)
+               self.havocbot_role = havocbot_role_kh_offense;
+       else if (r < 2)
+               self.havocbot_role = havocbot_role_kh_defense;
+       else
+               self.havocbot_role = havocbot_role_kh_freelancer;
+
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(kh, DropSpecialItems)
+{
+       kh_Key_DropAll(frag_target, false);
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(kh, reset_map_global)
+{
+       kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_round + (game_starttime - time), kh_StartRound);
+       return false;
+}
+
+REGISTER_MUTATOR(kh, IS_GAMETYPE(KEYHUNT))
 {
-       MUTATOR_HOOK(MakePlayerObserver, kh_Key_DropAll, CBC_ORDER_ANY);
-       MUTATOR_HOOK(ClientDisconnect, kh_Key_DropAll, CBC_ORDER_ANY);
-       MUTATOR_HOOK(PlayerDies, kh_PlayerDies, CBC_ORDER_ANY);
-       MUTATOR_HOOK(GiveFragsForKill, kh_GiveFragsForKill, CBC_ORDER_FIRST);
-       MUTATOR_HOOK(MatchEnd, kh_finalize, CBC_ORDER_ANY);
-       MUTATOR_HOOK(GetTeamCount, kh_GetTeamCount, CBC_ORDER_EXCLUSIVE);
-       MUTATOR_HOOK(SpectateCopy, kh_SpectateCopy, CBC_ORDER_ANY);
-       MUTATOR_HOOK(PlayerUseKey, kh_PlayerUseKey, CBC_ORDER_ANY);
+       ActivateTeamplay();
+       SetLimits(autocvar_g_keyhunt_point_limit, autocvar_g_keyhunt_point_leadlimit, -1, -1);
+       if(autocvar_g_keyhunt_team_spawns)
+               have_team_spawns = -1; // request team spawns
 
        MUTATOR_ONADD
        {