]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Properly link bots and spawn points in single player
authorMattia Basaglia <mattia.basaglia@gmail.com>
Sun, 19 Mar 2017 09:53:06 +0000 (09:53 +0000)
committerMattia Basaglia <mattia.basaglia@gmail.com>
Sun, 19 Mar 2017 09:53:06 +0000 (09:53 +0000)
qcsrc/server/bot/default/bot.qc
qcsrc/server/bot/default/bot.qh
qcsrc/server/mutators/events.qh
qcsrc/server/mutators/mutator/gamemode_singleplayer.qc
qcsrc/server/mutators/mutator/gamemode_singleplayer.qh

index bcdc32e8d5e274154590f33cc290c859c7d1adab..67498d895f56133dabdffa3b45e9c3b71255d4a3 100644 (file)
@@ -46,15 +46,20 @@ entity bot_spawn()
        entity bot = spawnclient();
        if (bot)
        {
-               setItemGroupCount();
-               currentbots = currentbots + 1;
-               bot_setnameandstuff(bot);
-               ClientConnect(bot);
-               PutClientInServer(bot);
+               bot_spawn_setup(bot);
        }
        return bot;
 }
 
+void bot_spawn_setup(entity bot)
+{
+       setItemGroupCount();
+       currentbots = currentbots + 1;
+       bot_setnameandstuff(bot);
+       ClientConnect(bot);
+       PutClientInServer(bot);
+}
+
 void bot_think(entity this)
 {
        if (this.bot_nextthink > time)
@@ -580,9 +585,12 @@ float bot_fixcount()
 {
        int activerealplayers = 0;
        int realplayers = 0;
-       if (MUTATOR_CALLHOOK(Bot_FixCount, activerealplayers, realplayers)) {
+       int bots = 0;
+
+       if (MUTATOR_CALLHOOK(Bot_FixCount, activerealplayers, realplayers, bots)) {
                activerealplayers = M_ARGV(0, int);
                realplayers = M_ARGV(1, int);
+        bots = M_ARGV(2, int);
        } else {
                FOREACH_CLIENT(IS_REAL_CLIENT(it), LAMBDA(
                        if(IS_PLAYER(it))
@@ -591,14 +599,19 @@ float bot_fixcount()
                ));
        }
 
-       int bots;
        // add/remove bots if needed to make sure there are at least
        // minplayers+bot_number, or remove all bots if no one is playing
        // But don't remove bots immediately on level change, as the real players
        // usually haven't rejoined yet
        bots_would_leave = false;
-       if (teamplay && autocvar_bot_vs_human && AvailableTeams() == 2)
+       if (bots)
+       {
+               // Nothing to do, number of bots set by the hook
+       }
+       else if (teamplay && autocvar_bot_vs_human && AvailableTeams() == 2)
+       {
                bots = min(ceil(fabs(autocvar_bot_vs_human) * activerealplayers), maxclients - realplayers);
+       }
        else if ((realplayers || autocvar_bot_join_empty || (currentbots > 0 && time < 5)))
        {
                float realminplayers, minplayers;
index b72fad9bd600248601794130a2cf0f505c110991..f49b4f7bf520d34c4d100718e98ac5a70dc2c258 100644 (file)
@@ -84,6 +84,10 @@ float bot_ignore_bots; // let bots not attack other bots (only works in non-team
 
 entity bot_spawn();
 float bot_fixcount();
+/*
+ * Sets up an entity created with spawnclient() to be a bot
+ */
+void bot_spawn_setup(entity bot);
 
 void bot_think(entity this);
 void bot_setnameandstuff(entity this);
index 89fec0178c7f01c7d00c22d54f0474a38039d449..e43f6a455896f73335904e72335d0606671cfed0 100644 (file)
@@ -769,6 +769,8 @@ enum {
        /**/                                            o(int, MUTATOR_ARGV_0_int) \
     /** real players */                i(int, MUTATOR_ARGV_1_int) \
     /**/                                       o(int, MUTATOR_ARGV_1_int) \
+    /** bots */                                i(int, MUTATOR_ARGV_2_int) \
+    /**/                                       o(int, MUTATOR_ARGV_2_int) \
     /**/
 MUTATOR_HOOKABLE(Bot_FixCount, EV_Bot_FixCount);
 
index b0b9f07f4f36c44225d69448c2582184e81ca4c6..9e36f15c4cc8ff690bfedff98b8bbbf5d515fd26 100644 (file)
@@ -6,6 +6,7 @@ const int SP_TEAM_ENEMY = NUM_TEAM_2;
 .bool can_drop_weapon;
 .string weapon_name;
 .int sp_spawn_team;
+.entity sp_spawn_spot;
 
 /*QUAKED spawnfunc_tdm_team (0 .5 .8) (-16 -16 -24) (16 16 32)
 Team declaration for TDM gameplay, this allows you to decide what team names and control point models are used in your map.
@@ -22,7 +23,7 @@ spawnfunc(sp_team)
 }
 
 // code from here on is just to support maps that don't have team entities
-void sp_SpawnTeam (string teamname, int teamcolor)
+void sp_spawn_team_entity(string teamname, int teamcolor)
 {
     entity this = new_pure(sp_team);
     this.netname = teamname;
@@ -42,6 +43,26 @@ spawnfunc(info_player_singleplayer)
     spawnfunc_info_player_deathmatch(this);
 }
 
+void sp_spawn_bot(entity spawn_point)
+{
+    entity bot = spawnclient();
+    if (bot)
+    {
+        bot.sp_spawn_spot = spawn_point;
+        bot_spawn_setup(bot);
+    }
+    else
+    {
+        LOG_WARN("Could not spawn bot");
+    }
+}
+
+void sp_enemy_spawn_think(entity this)
+{
+    sp_spawn_bot(this);
+    setthink(this, SUB_Remove);
+}
+
 spawnfunc(info_player_singleplayer_enemy)
 {
        if (!g_singleplayer) { delete(this); return; }
@@ -49,17 +70,18 @@ spawnfunc(info_player_singleplayer_enemy)
        this.team = SP_TEAM_ENEMY;
     this.sp_spawn_team = SP_TEAM_ENEMY;
        spawnfunc_info_player_deathmatch(this);
+    setthink(this, sp_enemy_spawn_think);
 }
 
-void sp_DelayedInit(entity this)
+void sp_delayed_init(entity this)
 {
     // if no teams are found, spawn defaults
     if(find(NULL, classname, "sp_team") == NULL)
     {
         LOG_TRACE("No \"sp_team\" entities found on this map, creating them anyway.");
 
-        sp_SpawnTeam("Player", SP_TEAM_PLAYER);
-        sp_SpawnTeam("Enemy", SP_TEAM_ENEMY);
+        sp_spawn_team_entity("Player", SP_TEAM_PLAYER);
+        sp_spawn_team_entity("Enemy", SP_TEAM_ENEMY);
     }
 }
 
@@ -128,7 +150,8 @@ MUTATOR_HOOKFUNCTION(sp, Spawn_Score)
     vector spawn_score = M_ARGV(2, vector);
     if ( IS_BOT_CLIENT(player) )
     {
-        if ( spawn_spot.sp_spawn_team != SP_TEAM_ENEMY )
+        if ( spawn_spot.sp_spawn_team != SP_TEAM_ENEMY || 
+            (player.sp_spawn_spot && player.sp_spawn_spot !=spawn_spot) )
             spawn_score.x = -1;
     }
     else if ( spawn_spot.sp_spawn_team != SP_TEAM_PLAYER )
@@ -143,3 +166,12 @@ MUTATOR_HOOKFUNCTION(sp, HideTeamNagger)
 {
     return true;
 }
+
+MUTATOR_HOOKFUNCTION(sp, Bot_FixCount)
+{
+    int count = 0;
+    for ( entity e = NULL; (e = findfloat(e, sp_spawn_team, SP_TEAM_ENEMY)); )
+        count++;
+    M_ARGV(2, int) = count;
+    return true;
+}
index 039aceb13529fd6fe134257c86294b7343b4a796..e7ead8637666389e14cc8d86055bae230461e8b8 100644 (file)
@@ -2,7 +2,7 @@
 
 #include "../gamemode.qh"
 
-void sp_DelayedInit(entity this);
+void sp_delayed_init(entity this);
 
 REGISTER_MUTATOR(sp, false)
 {
@@ -10,7 +10,7 @@ REGISTER_MUTATOR(sp, false)
        {
                if (time > 1) // game loads at time 1
                        error("This is a game type and it cannot be added at runtime.");
-               InitializeEntity(NULL, sp_DelayedInit, INITPRIO_GAMETYPE);
+               InitializeEntity(NULL, sp_delayed_init, INITPRIO_GAMETYPE);
 
                ActivateTeamplay();
                SetLimits(-1, -1, autocvar_timelimit_override, -1);