]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
digging out gamemode infection by fruitieX
authorTimePath <andrew.hardaker1995@gmail.com>
Mon, 15 Dec 2014 09:57:03 +0000 (20:57 +1100)
committerTimePath <andrew.hardaker1995@gmail.com>
Mon, 15 Dec 2014 10:00:18 +0000 (21:00 +1100)
(cherry picked from commit 4644e4cdda0033c7db72a7ec5c65cdd3f4c8d654)

Conflicts:
gamemodes.cfg
qcsrc/client/hud.qc
qcsrc/common/mapinfo.qh
qcsrc/server/autocvars.qh
qcsrc/server/bot/aim.qc
qcsrc/server/cl_player.qc
qcsrc/server/g_damage.qc
qcsrc/server/mutators/mutators.qh
qcsrc/server/progs.src

16 files changed:
gamemodes.cfg
qcsrc/client/hud.qc
qcsrc/common/mapinfo.qc
qcsrc/common/mapinfo.qh
qcsrc/menu/xonotic/util.qc
qcsrc/server/autocvars.qh
qcsrc/server/bot/aim.qc
qcsrc/server/bot/bot.qc
qcsrc/server/cl_client.qc
qcsrc/server/cl_player.qc
qcsrc/server/defs.qh
qcsrc/server/g_damage.qc
qcsrc/server/mutators/gamemode_infection.qc [new file with mode: 0644]
qcsrc/server/mutators/mutators.qh
qcsrc/server/mutators/mutators_include.qc
qcsrc/server/teamplay.qc

index b6cbe92cfcba116c79de77e667e30d35d2c6601a..5c97c7cd05b74d600243c4e4988fcae76b9fdfd9 100644 (file)
@@ -499,6 +499,7 @@ set g_race_qualifying_timelimit 0
 set g_race_qualifying_timelimit_override -1
 set g_race_teams 0     "when 2, 3, or 4, the race is played as a team game (the team members can add up their laps)"
 
+
 // ==========
 //  invasion
 // ==========
@@ -511,3 +512,10 @@ set g_invasion_spawn_delay 0.25
 set g_invasion_spawnpoint_spawn_delay 0.5
 set g_invasion_teams 0 "number of teams in invasion (note: use mapinfo to set this)"
 set g_invasion_team_spawns 1 "use team spawns in teamplay invasion mode"
+
+
+// ===========
+//  infection
+// ===========
+set g_infection 0 "Infection: Infect everyone with your color to win!"
+set g_infection_delay_round 5 "delay during which new colors can still be formed, after this a new player will join an existing team (and as such cannot win anymore)"
index 7359468e0969d236738b619a367e8fa8c8553d7f..78b21647ab87f1b3d03e2f7f3f204d4242f0c107 100644 (file)
@@ -3063,6 +3063,17 @@ float kaball_statuschange_time; // time when the status changed
 // we don't need to reset for keepaway since it immediately
 // autocorrects prevstatus as to if the player has the ball or not
 
+void HUD_Mod_Infection(vector pos, vector mySize)
+{
+       mod_active = 1; // Infection should never hide the mod icons panel
+
+       float f = stof(getplayerkeyvalue(player_localentnum - 1, "colors"));
+
+       vector rgb = colormapPaletteColor(floor(f / 16), 0);
+
+       drawpic_aspect_skin(pos, "player", mySize, rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
+}
+
 void HUD_Mod_Keepaway(vector pos, vector mySize)
 {
        mod_active = 1; // keepaway should always show the mod HUD
@@ -3381,15 +3392,16 @@ void HUD_ModIcons_SetFunc()
 {
        switch(gametype)
        {
-               case MAPINFO_TYPE_KEYHUNT:              HUD_ModIcons_GameType = HUD_Mod_KH; break;
-               case MAPINFO_TYPE_CTF:                  HUD_ModIcons_GameType = HUD_Mod_CTF; break;
-               case MAPINFO_TYPE_NEXBALL:              HUD_ModIcons_GameType = HUD_Mod_NexBall; break;
+               case MAPINFO_TYPE_KEYHUNT:      HUD_ModIcons_GameType = HUD_Mod_KH;         break;
+               case MAPINFO_TYPE_CTF:          HUD_ModIcons_GameType = HUD_Mod_CTF;        break;
+               case MAPINFO_TYPE_NEXBALL:      HUD_ModIcons_GameType = HUD_Mod_NexBall;    break;
                case MAPINFO_TYPE_CTS:
-               case MAPINFO_TYPE_RACE:         HUD_ModIcons_GameType = HUD_Mod_Race; break;
+               case MAPINFO_TYPE_RACE:         HUD_ModIcons_GameType = HUD_Mod_Race;       break;
                case MAPINFO_TYPE_CA:
-               case MAPINFO_TYPE_FREEZETAG:    HUD_ModIcons_GameType = HUD_Mod_CA; break;
-               case MAPINFO_TYPE_DOMINATION:   HUD_ModIcons_GameType = HUD_Mod_Dom; break;
-               case MAPINFO_TYPE_KEEPAWAY:     HUD_ModIcons_GameType = HUD_Mod_Keepaway; break;
+               case MAPINFO_TYPE_FREEZETAG:    HUD_ModIcons_GameType = HUD_Mod_CA;         break;
+               case MAPINFO_TYPE_DOMINATION:   HUD_ModIcons_GameType = HUD_Mod_Dom;        break;
+               case MAPINFO_TYPE_KEEPAWAY:     HUD_ModIcons_GameType = HUD_Mod_Keepaway;   break;
+               case MAPINFO_TYPE_INFECTION:    HUD_ModIcons_GameType = HUD_Mod_Infection;  break;
        }
 }
 
@@ -3429,9 +3441,9 @@ void HUD_ModIcons(void)
        }
 
        if(autocvar__hud_configure)
-               HUD_Mod_CTF(panel_pos, panel_size);
-       else
-               HUD_ModIcons_GameType(panel_pos, panel_size);
+               HUD_Mod_CTF(panel_pos, panel_size);
+       else
+               HUD_ModIcons_GameType(panel_pos, panel_size);
 
        draw_endBoldFont();
 }
index 2230d5c790385c0823b1184101395f4edf95396e..30ce6cd788a1fdf13d9ec923de4441eda16dab33 100644 (file)
@@ -368,6 +368,7 @@ float _MapInfo_Generate(string pFilename) // 0: failure, 1: ok ent, 2: ok bsp
                MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_DEATHMATCH;      // DM always works
                MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_LMS;             // LMS always works
                MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_KEEPAWAY;                // Keepaway always works
+               MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_INFECTION;       // INFECTION always works
 
                if(spawnpoints >= 8  && diameter > 4096) {
                        MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_TEAM_DEATHMATCH;
@@ -426,6 +427,7 @@ string _MapInfo_GetDefault(float t)
                case MAPINFO_TYPE_NEXBALL:         return "5 20 0";
                case MAPINFO_TYPE_CTS:             return "20 0 0";
                case MAPINFO_TYPE_FREEZETAG:       return "10 20 0";
+               case MAPINFO_TYPE_INFECTION:       return "5 20 0";
                // NOTE: DO NOT ADD ANY MORE GAME TYPES HERE
                // THIS IS JUST LEGACY SUPPORT FOR NEXUIZ MAPS
                // ONLY ADD NEW STUFF TO _MapInfo_GetDefaultEx
@@ -500,6 +502,22 @@ void _MapInfo_Map_ApplyGametype(string s, float pWantedType, float pThisType, fl
                        cvar_set("fraglimit", sa);
                s = cdr(s);
        }
+       
+       if(pWantedType == MAPINFO_TYPE_INFECTION)
+       {
+               sa = car(s);
+               if(sa != "")
+                       cvar_set("fraglimit", sa);
+               s = cdr(s);
+       }
+       
+       if(pWantedType == MAPINFO_TYPE_INFECTION)
+       {
+               sa = car(s);
+               if(sa != "")
+                       cvar_set("fraglimit", sa);
+               s = cdr(s);
+       }
 
        /* keepaway wuz here
        if(pWantedType == MAPINFO_TYPE_KEEPAWAY)
index bbcc267b2bdbf5d05005155768419c357516e84c..bd51473a45e0776a2a84a07409eec54a8c0b5718 100644 (file)
@@ -82,6 +82,9 @@ REGISTER_GAMETYPE(_("Keepaway"),ka,g_keepaway,KEEPAWAY,TRUE,"timelimit=20 pointl
 REGISTER_GAMETYPE(_("Invasion"),inv,g_invasion,INVASION,FALSE,"pointlimit=50 teams=0",_("Survive against waves of monsters"));
 #define g_invasion IS_GAMETYPE(INVASION)
 
+REGISTER_GAMETYPE(_("Infection"),inf,g_infection,INFECTION,FALSE,"timelimit=20",_("Survive against the infection"))
+#define g_infection IS_GAMETYPE(INFECTION)
+
 const float MAPINFO_FEATURE_WEAPONS       = 1; // not defined for instagib-only maps
 const float MAPINFO_FEATURE_VEHICLES      = 2;
 const float MAPINFO_FEATURE_TURRETS       = 4;
index cf4139fdeea9c51582fecfdd7d710fb9782b2abb..cea9098f83a8d6d406596fe098947aa3a5ca5431 100644 (file)
@@ -652,6 +652,7 @@ float updateCompression()
        GAMETYPE(MAPINFO_TYPE_DEATHMATCH) \
        GAMETYPE(MAPINFO_TYPE_DOMINATION) \
        GAMETYPE(MAPINFO_TYPE_FREEZETAG) \
+       GAMETYPE(MAPINFO_TYPE_INFECTION) \
        GAMETYPE(MAPINFO_TYPE_KEEPAWAY) \
        GAMETYPE(MAPINFO_TYPE_KEYHUNT) \
        GAMETYPE(MAPINFO_TYPE_LMS) \
index 4b9468552db2ce915736e5321ff8d27da540d3ef..0d74b49c91c17022442bbcd1d5394449f961343c 100644 (file)
@@ -837,6 +837,7 @@ float autocvar_g_campcheck_damage;
 float autocvar_g_campcheck_distance;
 float autocvar_g_campcheck_interval;
 float autocvar_g_jump_grunt;
+float autocvar_g_infection_delay_round = 5;
 float autocvar_g_spawn_near_teammate_distance;
 float autocvar_g_spawn_near_teammate_ignore_spawnpoint;
 float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
index 0ae33124717ba894248ec42f55b928117baf8b4c..bb8451afdd6a3b660b1ba400e66d9c3eaf1e5ab1 100644 (file)
@@ -1,4 +1,3 @@
-
 entity ka_ball;
 // traces multiple trajectories to find one that will impact the target
 // 'end' vector is the place it aims for,
@@ -111,6 +110,9 @@ float bot_shouldattack(entity e)
                        return FALSE;
        }
 
+       if(g_infection && e.infectioncolor == self.infectioncolor)
+        return FALSE;
+
        if(e.frozen)
                return FALSE;
 
index 40b769ddd3fb4a78f3b156995a2cf53153800869..ea151306644d06de230d28cef760cc0a2ad5ab81 100644 (file)
@@ -408,6 +408,8 @@ void bot_clientconnect()
        else
                JoinBestTeam(self, FALSE, TRUE);
 
+       self.infection_playernum = -1;
+       
        havocbot_setupbot();
 }
 
index b1dccc7b5c3bc4e3e6517106fd7919eb5976f393..e1c76fb39fde3d1ee4ebf8a79b65c741200bc77b 100644 (file)
@@ -345,7 +345,7 @@ void FixPlayermodel()
                UpdatePlayerSounds(); // update skin sounds
        }
 
-       if(!teamplay)
+       if(!teamplay || !g_infection) //&& ?
                if(strlen(autocvar_sv_defaultplayercolors))
                        if(self.clientcolors != stof(autocvar_sv_defaultplayercolors))
                                setcolor(self, stof(autocvar_sv_defaultplayercolors));
@@ -1188,6 +1188,8 @@ void ClientConnect (void)
 
        if(autocvar_sv_teamnagger && !(autocvar_bot_vs_human && (c3==-1 && c4==-1)) && !g_ca && !g_cts && !g_race) // teamnagger is currently bad for ca, race & cts
                send_CSQC_teamnagger();
+               
+       self.infection_playernum = -1;
 
        CheatInitClient();
 
index 17569147fb091d9e08f9ee4ea7e877287c69f34d..3e6817c2c97ed4e9c9281c159ac48919484cce3c 100644 (file)
@@ -299,6 +299,7 @@ void calculate_player_respawn_time()
 }
 
 void ClientKill_Now_TeamChange();
+void infection_CheckWinner();
 
 void PlayerDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
 {
@@ -536,6 +537,16 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht
 
                // print an obituary message
                Obituary (attacker, inflictor, self, deathtype);
+               
+               if(g_infection)
+               {
+                       if(deathtype == DEATH_HURTTRIGGER || deathtype == DEATH_KILL)
+                       {
+                               PutClientInServer(); // respawn with a random color
+                               infection_CheckWinner();
+                               return;
+                       }
+               }
 
         // increment frag counter for used weapon type
         float w;
index ab4dee3185ff06a02cff82b50c3a177d34b1021c..e951c04fab72ab35e7b8d5b128797368158a4293 100644 (file)
@@ -565,6 +565,10 @@ string deathmessage;
 
 float serverflags;
 
+.float infection_playernum;
+.float infectioncolor;
+.float infectioncolor_original;
+
 .float team_forced; // can be a team number to force a team, or 0 for default action, or -1 for forced spectator
 
 .float player_blocked;
index 28a1c8e8ca23e760a6d5a966899747be9be04ceb..ef81b236bbaf7192ff18de27f9a3611df72fbd7e 100644 (file)
@@ -849,7 +849,8 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float
                }
 
                if (targ == attacker)
-                       damage = damage * autocvar_g_balance_selfdamagepercent; // Partial damage if the attacker hits himself
+                       damage *= //g_infection ? 0 :
+                               autocvar_g_balance_selfdamagepercent;   // Partial damage if the attacker hits himself
 
                // count the damage
                if(attacker)
diff --git a/qcsrc/server/mutators/gamemode_infection.qc b/qcsrc/server/mutators/gamemode_infection.qc
new file mode 100644 (file)
index 0000000..ea25028
--- /dev/null
@@ -0,0 +1,337 @@
+#define INFECTIONCOLOR_MAX 16
+
+entity infection_players[INFECTIONCOLOR_MAX];
+float infection_players_count;
+float next_round;
+
+void infection_Initialize()
+{
+       float i;
+       for(i = 0; i < INFECTIONCOLOR_MAX; ++i)
+       {
+               infection_players[i] = world;
+       }
+       next_round = time + 5;
+}
+
+void infection_CheckWinner()
+{
+       // Check if only one color remains
+       float i, previnfectioncolor, we_have_a_winner;
+       entity e;
+       we_have_a_winner = TRUE; // TRUE until below loop proves us wrong
+       entity winner = world; //?
+       previnfectioncolor = FALSE;
+
+       float temp_infection_players_count;
+       temp_infection_players_count = infection_players_count;
+
+       for(i = 0; i < temp_infection_players_count; ++i)
+       {
+               e = infection_players[i];
+               if(e == world) // empty slot, skip to next
+               {
+                       if(temp_infection_players_count < INFECTIONCOLOR_MAX - 1) // just in case
+                               ++temp_infection_players_count; // keep on searching for one additional since this was empty
+                       continue;
+               }
+
+               if(i > 0)
+               {
+                       if(previnfectioncolor != e.infectioncolor) // all infection colors are the same if we have a winner, in this case we still have more than one color alive
+                       {
+                               we_have_a_winner = FALSE;
+                               break;
+                       }
+               }
+
+               previnfectioncolor = e.infectioncolor;
+       }
+
+       if(we_have_a_winner)
+       {
+               temp_infection_players_count = infection_players_count;
+               for(i = 0; i < temp_infection_players_count; ++i)
+               {
+                       e = infection_players[i];
+                       if(e == world) // empty slot, skip to next
+                       {
+                               if(temp_infection_players_count < INFECTIONCOLOR_MAX - 1) // just in case
+                                       ++temp_infection_players_count;
+                               continue;
+                       }
+
+                       if(e.infectioncolor == e.infectioncolor_original) // here's our winner :)
+                       {
+                               winner = e;
+                               break; // break, we found the winner
+                       }
+               }
+
+               if(winner.netname != "" && infection_players_count > 1)
+               {
+                       UpdateFrags(winner, +1);
+
+                       FOR_EACH_PLAYER(e)
+                       {
+                               centerprint(e, strcat(winner.netname, "^1 wins the round since their color survived.\n"));
+                       }
+                       bprint(winner.netname, "^1 wins the round since their color survived.\n");
+               }
+
+               next_round = time + 5;
+       }
+}
+
+string color_owner_green, color_owner_red;
+float color_owner_self;
+// find whose color your attacker is carrying, set color_owner_self to 1 if it's his own, otherwise set color_owner_* to the other owner
+#define infection_GetFragAttackers_ColorOwner()\
+{\
+       float j;\
+       entity get_frag_attacker_temp;\
+       temp_infection_players_count = infection_players_count;\
+       color_owner_self = 0;\
+       for(j = 0; j < temp_infection_players_count; ++j)\
+       {\
+               get_frag_attacker_temp = infection_players[j];\
+               if(get_frag_attacker_temp == world)\
+               {\
+                       if(temp_infection_players_count < INFECTIONCOLOR_MAX - 1)\
+                               ++temp_infection_players_count;\
+                       continue;\
+               }\
+               if(get_frag_attacker_temp.infectioncolor_original == frag_attacker.infectioncolor_original)\
+               {\
+                       color_owner_self = 1;\
+                       break;\
+               }\
+               else if(get_frag_attacker_temp.infectioncolor_original == frag_attacker.infectioncolor)\
+               {\
+                       color_owner_green = strcat(get_frag_attacker_temp.netname, "^2's");\
+                       color_owner_red = strcat(get_frag_attacker_temp.netname, "^1's");\
+                       break;\
+               }\
+       }\
+} ENDS_WITH_CURLY_BRACE
+
+MUTATOR_HOOKFUNCTION(infection_PlayerDies)
+{
+       float i;
+       entity e;
+
+       float temp_infection_players_count;
+       temp_infection_players_count = infection_players_count;
+
+       if(frag_target.infectioncolor == frag_target.infectioncolor_original) // if this is the first time we die... (our infectioncolor remained unchanged)
+       {
+               for(i = 0; i < temp_infection_players_count; ++i) // check other players...
+               {
+                       e = infection_players[i];
+                       if(e == world) // empty slot, skip to next
+                       {
+                               if(temp_infection_players_count < INFECTIONCOLOR_MAX - 1) // just in case
+                                       ++temp_infection_players_count;
+                               continue;
+                       }
+
+                       if(e.infectioncolor == frag_target.infectioncolor_original) // and see if they have our original infection color
+                       {
+                               infection_GetFragAttackers_ColorOwner();
+                               centerprint(e, strcat("^1Your master ^7", frag_target.netname, "^1 was infected by ^7", frag_attacker.netname, " ^1with ^7", color_owner_red, " ^1color.\n"));
+                               e.infectioncolor = frag_attacker.infectioncolor; // if so, remove it, our infection color has now "died out" from this round and we can not win anymore. The attacker will "summon" all of our previously fragged targets, and also us.
+                               setcolor(e, 16 * e.infectioncolor + e.infectioncolor);
+                       }
+               }
+       }
+       else
+       {
+               frag_target.infectioncolor = frag_attacker.infectioncolor;
+               setcolor(frag_target, 16 * frag_target.infectioncolor + frag_target.infectioncolor);
+       }
+
+       infection_GetFragAttackers_ColorOwner();
+
+       if(color_owner_self)
+               color_owner_green = "^2your own";
+       centerprint(frag_attacker, strcat("^2You infected ^7", frag_target.netname, " ^2with ^7", color_owner_green, " ^2color.\n"));
+
+       if(color_owner_self)
+               color_owner_red = "^1their own";
+       centerprint(frag_target, strcat("^1You were infected by ^7", frag_attacker.netname, " ^1with ^7", color_owner_red, " ^1color.\n"));
+       bprint("^7", frag_target.netname, "^1 was infected by ^7", frag_attacker.netname, " ^1with ^7", color_owner_red, " ^1color.\n");
+
+       frag_target.health = cvar("g_balance_health_start"); // "respawn" the player :P
+
+       infection_CheckWinner();
+
+       return 1;
+}
+
+MUTATOR_HOOKFUNCTION(infection_RemovePlayer)
+{
+       if(self.infection_playernum == -1)
+               return 0; // nothing to remove
+
+       float i, j;
+       /*for (i = self.infection_playernum; i < infection_players_count; ++i)
+       {
+               infection_players[i] = infection_players[i+1];
+               infection_players[i].infection_playernum = infection_players[i].infection_playernum - 1;
+       }
+       */
+
+       infection_players[self.infection_playernum] = world;
+       infection_players_count = infection_players_count - 1;
+
+       // if other players have our color, randomize their color
+       entity e;
+       float temp_infection_players_count;
+       temp_infection_players_count = infection_players_count;
+
+       if(!next_round) // ... but ONLY if next_round isn't set. We don't care about the colors if the round has already ended
+       for(i = 0; i < temp_infection_players_count; ++i) // check other players...
+       {
+               e = infection_players[i];
+               if(e == world) // empty slot, skip to next
+               {
+                       if(temp_infection_players_count < INFECTIONCOLOR_MAX - 1) // just in case
+                               ++temp_infection_players_count;
+                       continue;
+               }
+
+               if(e.infectioncolor == self.infectioncolor_original) // and see if they have our original infection color
+               {
+                       entity random_player = world;
+                       
+                       for(j = 0; j < 100; ++j) // try 100 times to find a color that isn't the same as our color. If this fails we are either damn unlucky, or there are really only players left of our color
+                       {
+                               random_player = infection_players[floor(random() * (INFECTIONCOLOR_MAX - 1))];
+
+                               if(random_player == world) // hit empty slot, try again
+                                       continue;
+
+                               if(random_player.infectioncolor != self.infectioncolor_original) // break if we found another color
+                               {
+                                       break;
+                               }
+                       }
+                       e.infectioncolor = random_player.infectioncolor;
+                       setcolor(e, 16 * e.infectioncolor + e.infectioncolor);
+               }
+       }
+
+       self.infection_playernum = -1;
+
+       if(infection_players_count > 1 && time > autocvar_g_infection_delay_round)
+               infection_CheckWinner();
+
+       return 1;
+}
+
+MUTATOR_HOOKFUNCTION(infection_PlayerSpawn)
+{
+       float i;
+       if(infection_players_count == 1 && time > autocvar_g_infection_delay_round)
+               next_round = time; // start a new round immediately
+
+       if(infection_players_count + 1 >= INFECTIONCOLOR_MAX)
+       {
+               bprint("^1Sorry, only ", ftos(INFECTIONCOLOR_MAX), " players can play infection at once.");
+               return 0;
+       }
+
+       if(self.infection_playernum == -1) // only add if we don't have a infection_playernum
+       {
+               // add player to the players array, give him a playernum
+               for(i = 0; i <= infection_players_count; ++i) // <= because we might not find any empty slots until then, and in that case we need a new slot
+               {
+                       if(infection_players[i] == world) // empty slot, give player this slot
+                       {
+                               self.infection_playernum = i;
+                               break;
+                       }
+               }
+               infection_players[i] = self;
+               infection_players_count = infection_players_count + 1;
+       }
+
+       if(time > autocvar_g_infection_delay_round) // spawn too late, give player a random color
+       {
+               entity random_player = world;
+               
+               for(i = 0; i < 100; ++i) // try 100 times to find a color that isn't the same as our color. If this fails we are either damn unlucky, or there are really only players left of our color
+               {
+                       random_player = infection_players[floor(random() * (INFECTIONCOLOR_MAX - 1))];
+
+                       if(random_player == world) // hit empty slot, try again
+                               continue;
+
+                       if(random_player.infectioncolor != self.infectioncolor_original) // break if we found another color
+                       {
+                               break;
+                       }
+               }
+
+               self.infectioncolor = random_player.infectioncolor;
+               self.infectioncolor_original = -1; // can't win if player didn't spawn during the round delay
+       }
+       else // we are still in the delay period before the round starts
+       {
+               self.infectioncolor = self.infection_playernum;
+               self.infectioncolor_original = self.infectioncolor;
+       }
+       setcolor(self, 16 * self.infectioncolor + self.infectioncolor);
+
+       return 1;
+}
+
+MUTATOR_HOOKFUNCTION(infection_GiveFragsForKill)
+{
+       frag_score = 0; // no frags counted in infection, maybe later (TODO)
+       return 1;
+}
+
+MUTATOR_HOOKFUNCTION(infection_PlayerPreThink)
+{
+       setcolor(self, 16 * self.infectioncolor + self.infectioncolor); // prevent cheating by changing player colors
+       return 1;
+}
+
+MUTATOR_HOOKFUNCTION(infection_PlayerDamage_Calculate)
+{
+    if ((frag_attacker.infectioncolor == frag_target.infectioncolor && frag_attacker != frag_target) || (frag_deathtype == DEATH_FALL) || (frag_deathtype == DEATH_DROWN) || (frag_deathtype == DEATH_SLIME) || (frag_deathtype == DEATH_LAVA))
+    {
+        frag_damage = 0;
+        frag_force = '0 0 0';
+    }
+    return 1;
+}
+
+MUTATOR_DEFINITION(gamemode_infection)
+{
+       MUTATOR_HOOK(MakePlayerObserver, infection_RemovePlayer, CBC_ORDER_ANY);
+       MUTATOR_HOOK(ClientDisconnect, infection_RemovePlayer, CBC_ORDER_ANY);
+       MUTATOR_HOOK(PlayerDies, infection_PlayerDies, CBC_ORDER_ANY);
+       MUTATOR_HOOK(PlayerSpawn, infection_PlayerSpawn, CBC_ORDER_ANY);
+       MUTATOR_HOOK(GiveFragsForKill, infection_GiveFragsForKill, CBC_ORDER_FIRST);
+       MUTATOR_HOOK(PlayerPreThink, infection_PlayerPreThink, CBC_ORDER_FIRST);
+       MUTATOR_HOOK(PlayerDamage_Calculate, infection_PlayerDamage_Calculate, CBC_ORDER_ANY);
+
+       MUTATOR_ONADD
+       {
+               if(time > 1) // game loads at time 1
+                       error("This is a game type and it cannot be added at runtime.");
+               //g_infection = 1;
+               infection_Initialize();
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               //g_infection = 0;
+               error("This is a game type and it cannot be removed at runtime.");
+               return -1;
+       }
+
+       return 0;
+}
index 955ba1a526f24b5bd0f4d0d5d1e1eeefd29d6352..af85da6d972df3bf0b27f3699f648fb0141306bd 100644 (file)
@@ -12,6 +12,7 @@ MUTATOR_DECLARATION(gamemode_invasion);
 MUTATOR_DECLARATION(gamemode_cts);
 MUTATOR_DECLARATION(gamemode_race);
 MUTATOR_DECLARATION(gamemode_tdm);
+MUTATOR_DECLARATION(gamemode_infection);
 
 MUTATOR_DECLARATION(mutator_dodging);
 MUTATOR_DECLARATION(mutator_invincibleprojectiles);
index 220bd059574058f7d6f4fb8e6f7efa7ac9eedec9..b6f3f8da6a1c7f54010fb491458744bd4fd953ec 100644 (file)
@@ -4,6 +4,7 @@
 #include "gamemode_ctf.qc"
 #include "gamemode_domination.qc"
 #include "gamemode_freezetag.qc"
+#include "gamemode_infection.qc"
 #include "gamemode_keyhunt.qc"
 #include "gamemode_keepaway.qc"
 #include "gamemode_nexball.qc"
index bd5d3607c127e2178a62cce0241d72a09ae7c32f..2b697bf6a720f66bb9de62cae2af40fb19a26da2 100644 (file)
@@ -202,6 +202,11 @@ void InitGameplayMode()
        {
                MUTATOR_ADD(gamemode_keepaway);
        }
+       
+       if(g_infection)
+       {
+               MUTATOR_ADD(gamemode_infection);
+       }
 
        if(g_invasion)
        {