]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Allow targeted bot spawns and remove bots on death
authorMattia Basaglia <mattia.basaglia@gmail.com>
Sun, 19 Mar 2017 14:10:06 +0000 (14:10 +0000)
committerMattia Basaglia <mattia.basaglia@gmail.com>
Sun, 19 Mar 2017 14:10:06 +0000 (14:10 +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

index 67498d895f56133dabdffa3b45e9c3b71255d4a3..5514c7c5d5c572abf8be4f1d3d07ca1fd891f57c 100644 (file)
@@ -60,6 +60,12 @@ void bot_spawn_setup(entity bot)
        PutClientInServer(bot);
 }
 
+void bot_remove(entity bot)
+{
+       currentbots = currentbots - 1;
+       dropclient(bot);
+}
+
 void bot_think(entity this)
 {
        if (this.bot_nextthink > time)
@@ -484,12 +490,28 @@ void bot_removefromlargestteam()
        });
        if(!bcount)
                return; // no bots to remove
-       currentbots = currentbots - 1;
-       dropclient(best);
+       bot_remove(best);
 }
 
 void bot_removenewest()
 {
+       entity best = NULL;
+       MUTATOR_CALLHOOK(Bot_SelectRemove, best);
+       best = M_ARGV(0, entity);
+       if ( best )
+       {
+               if ( !IS_BOT_CLIENT(best) )
+               {
+                       LOG_WARN("Mutator selected a non-bot as a bot to remove\n");
+                       best = NULL;
+               }
+               else
+               {
+                       bot_remove(best);
+                       return;
+               }
+       }
+
        if(teamplay)
        {
                bot_removefromlargestteam();
@@ -497,7 +519,6 @@ void bot_removenewest()
        }
 
        float besttime = 0;
-       entity best = NULL;
        int bcount = 0;
 
        FOREACH_CLIENT(it.isbot,
@@ -520,8 +541,7 @@ void bot_removenewest()
        if(!bcount)
                return; // no bots to remove
 
-       currentbots = currentbots - 1;
-       dropclient(best);
+       bot_remove(best);
 }
 
 void autoskill(float factor)
index f49b4f7bf520d34c4d100718e98ac5a70dc2c258..3c5e6231c7ca81d865e19872b5371a0949cc9df9 100644 (file)
@@ -88,6 +88,10 @@ float bot_fixcount();
  * Sets up an entity created with spawnclient() to be a bot
  */
 void bot_spawn_setup(entity bot);
+/**
+ * Removes the bot
+ */
+void bot_remove(entity bot);
 
 void bot_think(entity this);
 void bot_setnameandstuff(entity this);
index e43f6a455896f73335904e72335d0606671cfed0..74e169caeb682c37d30988637992316b3120e180 100644 (file)
@@ -774,6 +774,15 @@ enum {
     /**/
 MUTATOR_HOOKABLE(Bot_FixCount, EV_Bot_FixCount);
 
+/*
+ * Called when a bot needs to be removed
+ */
+#define EV_Bot_SelectRemove(i, o) \
+    /** bot to remove */  i(entity, MUTATOR_ARGV_0_entity) \
+    /**/                  o(entity, MUTATOR_ARGV_0_entity) \
+    /**/
+MUTATOR_HOOKABLE(Bot_SelectRemove, EV_Bot_SelectRemove);
+
 #define EV_ClientCommand_Spectate(i, o) \
     /** player */ i(entity, MUTATOR_ARGV_0_entity) \
     /**/
index 9e36f15c4cc8ff690bfedff98b8bbbf5d515fd26..e75b5e3169c163a9be5b0b465c2071e03f661767 100644 (file)
@@ -7,6 +7,9 @@ const int SP_TEAM_ENEMY = NUM_TEAM_2;
 .string weapon_name;
 .int sp_spawn_team;
 .entity sp_spawn_spot;
+.bool can_respawn;
+
+int sp_bot_number;
 
 /*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.
@@ -45,6 +48,7 @@ spawnfunc(info_player_singleplayer)
 
 void sp_spawn_bot(entity spawn_point)
 {
+    sp_bot_number++;
     entity bot = spawnclient();
     if (bot)
     {
@@ -60,7 +64,13 @@ void sp_spawn_bot(entity spawn_point)
 void sp_enemy_spawn_think(entity this)
 {
     sp_spawn_bot(this);
-    setthink(this, SUB_Remove);
+    setthink(this, func_null);
+}
+
+
+void sp_enemy_spawn_use(entity this, entity actor, entity trigger)
+{
+    sp_spawn_bot(this);
 }
 
 spawnfunc(info_player_singleplayer_enemy)
@@ -70,7 +80,9 @@ 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);
+    this.use = sp_enemy_spawn_use;
+    if ( this.targetname == "" )
+        setthink(this, sp_enemy_spawn_think);
 }
 
 void sp_delayed_init(entity this)
@@ -78,11 +90,18 @@ 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_spawn_team_entity("Player", SP_TEAM_PLAYER);
         sp_spawn_team_entity("Enemy", SP_TEAM_ENEMY);
     }
+
+    sp_bot_number = 0;
+}
+
+void sp_remove_bot(entity bot)
+{
+    sp_bot_number--;
+    bot.sp_spawn_spot = NULL;
+    bot_clear(bot);
 }
 
 MUTATOR_HOOKFUNCTION(sp, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
@@ -150,8 +169,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 || 
-            (player.sp_spawn_spot && player.sp_spawn_spot !=spawn_spot) )
+        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 )
@@ -169,9 +188,37 @@ MUTATOR_HOOKFUNCTION(sp, HideTeamNagger)
 
 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;
+    M_ARGV(2, int) = sp_bot_number;
     return true;
 }
+
+MUTATOR_HOOKFUNCTION(sp, PlayerDies)
+{
+    entity target = M_ARGV(2, entity);
+    if ( IS_BOT_CLIENT(target) )
+    {
+        if ( target.sp_spawn_spot && !target.sp_spawn_spot.can_respawn )
+        {
+            sp_remove_bot(target);
+        }
+    }
+}
+
+MUTATOR_HOOKFUNCTION(sp, Bot_SelectRemove)
+{
+    FOREACH_CLIENT(it.isbot,
+    {
+        if ( !it.sp_spawn_spot )
+        {
+            M_ARGV(0, entity) = it;
+            return;
+        }
+    });
+}
+
+MUTATOR_HOOKFUNCTION(sp, PlayerPreThink)
+{
+    entity player = M_ARGV(0, entity);
+    if ( IS_BOT_CLIENT(player) && !player.sp_spawn_spot )
+        bot_remove(player);
+}