-#define INFECTIONCOLOR_MAX 16
+float infection_players_count = 0;
+float infection_coloridx;
-entity infection_players[INFECTIONCOLOR_MAX];
-float infection_players_count;
float next_round;
+.float infection_jointime;
+.float infectioncolor;
+.float infectioncolor_original;
+
+void infection_SetColor(entity e, float _color)
+{
+ setcolor(e, (_color << 4) | _color);
+}
+
void infection_Initialize()
{
- float i;
- for(i = 0; i < INFECTIONCOLOR_MAX; ++i)
- {
- infection_players[i] = world;
- }
- next_round = time + 5;
+ infection_coloridx = 0;
+ next_round = time + autocvar_g_infection_delay_round;
}
void infection_CheckWinner()
{
+ if (infection_players_count <= 1) return; // There can be no winner
+
// Check if only one color remains
- float i, previnfectioncolor, we_have_a_winner;
+ float previnfectioncolor = -1;
+ float we_have_a_winner = TRUE; // TRUE until below loop proves us wrong
entity e;
- we_have_a_winner = TRUE; // TRUE until below loop proves us wrong
- entity winner = world; //?
- previnfectioncolor = FALSE;
+ FOR_EACH_PLAYER(e)
+ {
+ // All infection colors are the same if we have a winner
+ if (previnfectioncolor != -1 && previnfectioncolor != e.infectioncolor)
+ {
+ // In this case we still have more than one color alive
+ we_have_a_winner = FALSE;
+ break;
+ }
+ previnfectioncolor = e.infectioncolor;
+ }
- float temp_infection_players_count;
- temp_infection_players_count = infection_players_count;
+ if (!we_have_a_winner) return;
- for(i = 0; i < temp_infection_players_count; ++i)
+ // Who is it?
+ entity winner = world;
+ FOR_EACH_PLAYER(e)
{
- e = infection_players[i];
- if(e == world) // empty slot, skip to next
+ if (e.infectioncolor == e.infectioncolor_original)
{
- 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;
+ winner = e;
+ break;
}
+ }
+
+ if (winner.netname)
+ {
+ UpdateFrags(winner, 1);
- if(i > 0)
+ FOR_EACH_PLAYER(e)
{
- 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;
- }
+ centerprint(e, strcat(winner.netname, "^1 wins the round since their color survived.\n"));
}
-
- previnfectioncolor = e.infectioncolor;
+ bprint(winner.netname, "^1 wins the round since their color survived.\n");
}
- if(we_have_a_winner)
+ infection_Initialize();
+}
+
+string color_owner_green, color_owner_red;
+// find whose color your attacker is carrying, TRUE if it's his own, otherwise set color_owner_* to the other owner
+float infection_GetColorOwner(entity me)
+{
+ entity e;
+ FOR_EACH_PLAYER(e)
{
- temp_infection_players_count = infection_players_count;
- for(i = 0; i < temp_infection_players_count; ++i)
+ if (e.infectioncolor_original == me.infectioncolor_original)
{
- 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
- }
+ return TRUE;
}
-
- if(winner.netname != "" && infection_players_count > 1)
+ else if (e.infectioncolor_original == me.infectioncolor)
{
- 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");
+ color_owner_green = strcat(e.netname, "^2's");
+ color_owner_red = strcat(e.netname, "^1's");
+ break;
}
-
- next_round = time + 5;
}
+ return FALSE;
}
-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)
+ // If this is the first time we die... (our infectioncolor remained unchanged)
+ if (frag_target.infectioncolor == frag_target.infectioncolor_original)
{
- for(i = 0; i < temp_infection_players_count; ++i) // check other players...
+ infection_GetColorOwner(frag_attacker);
+ entity e;
+ FOR_EACH_PLAYER(e) // check other players...
{
- e = infection_players[i];
- if(e == world) // empty slot, skip to next
+ if (e.infectioncolor == frag_target.infectioncolor) // And see if they have our original infection color
{
- 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();
+ // 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.
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);
+ e.infectioncolor = frag_attacker.infectioncolor;
+ infection_SetColor(e, e.infectioncolor);
}
}
}
else
{
frag_target.infectioncolor = frag_attacker.infectioncolor;
- setcolor(frag_target, 16 * frag_target.infectioncolor + frag_target.infectioncolor);
+ infection_SetColor(frag_target, frag_target.infectioncolor);
}
- infection_GetFragAttackers_ColorOwner();
-
- if(color_owner_self)
+ if (infection_GetColorOwner(frag_attacker))
+ {
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_attacker, strcat("^2You infected ^7", frag_target.netname, " ^2with ^7", color_owner_green, " ^2color.\n"));
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
+ frag_target.health = cvar("g_balance_health_start"); // "respawn" the player
infection_CheckWinner();
- return 1;
+ return TRUE;
}
MUTATOR_HOOKFUNCTION(infection_RemovePlayer)
{
- if(self.infection_playernum == -1)
- return 0; // nothing to remove
+ if (!self.infection_jointime)
+ return FALSE; // 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;
+ infection_players_count--;
// 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...
+ // ... but ONLY if next_round isn't set. We don't care about the colors if the round has already ended
+ if (!time < next_round)
{
- e = infection_players[i];
- if(e == world) // empty slot, skip to next
+ entity e;
+ FOR_EACH_PLAYER(e) // check other players...
{
- 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
+ if (e.infectioncolor == self.infectioncolor_original) // and see if they have our original infection 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_original = self.infectioncolor;
+ centerprint(frag_attacker, "^2You are now a master.\n");
+ 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)
+ if (infection_players_count > 1 && time >= next_round)
infection_CheckWinner();
- return 1;
+ return TRUE;
}
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 (self.infection_jointime) return TRUE; // only add if we don't have a infection_jointime
+ self.infection_jointime = time;
+ if (++infection_players_count > 1 && time >= next_round)
+ next_round = time + autocvar_g_infection_delay_round; // start a new round immediately
- if(infection_players_count + 1 >= INFECTIONCOLOR_MAX)
+ if (time >= next_round) // spawn too late, give player a random color
{
- 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
+ float skip = floor(random() * infection_players_count);
+ entity e;
+ FOR_EACH_PLAYER(e)
{
- if(infection_players[i] == world) // empty slot, give player this slot
- {
- self.infection_playernum = i;
- break;
- }
+ if (skip--) continue;
+ self.infectioncolor = e.infectioncolor;
+ self.infectioncolor_original = -1; // can't win if player didn't spawn during the round delay
}
- 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 = infection_coloridx++;
self.infectioncolor_original = self.infectioncolor;
}
- setcolor(self, 16 * self.infectioncolor + self.infectioncolor);
+ infection_SetColor(self, self.infectioncolor);
- return 1;
+ return TRUE;
}
MUTATOR_HOOKFUNCTION(infection_GiveFragsForKill)
{
- frag_score = 0; // no frags counted in infection, maybe later (TODO)
- return 1;
+ frag_score = 0; // TODO: no frags counted in infection, maybe later
+ return TRUE;
}
MUTATOR_HOOKFUNCTION(infection_PlayerPreThink)
{
- setcolor(self, 16 * self.infectioncolor + self.infectioncolor); // prevent cheating by changing player colors
- return 1;
+ infection_SetColor(self, self.infectioncolor); // prevent cheating by changing player colors
+ return TRUE;
}
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;
+ 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 TRUE;
+}
+
+MUTATOR_HOOKFUNCTION(infection_BotShouldAttack)
+{
+ return checkentity.infectioncolor == self.infectioncolor; // FIXME: Has reverse meaning
}
MUTATOR_DEFINITION(gamemode_infection)
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_HOOK(BotShouldAttack, infection_BotShouldAttack, CBC_ORDER_ANY);
MUTATOR_ONADD
{
- if(time > 1) // game loads at time 1
+ 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_ONROLLBACK_OR_REMOVE
+ {
+ }
+
MUTATOR_ONREMOVE
{
- //g_infection = 0;
error("This is a game type and it cannot be removed at runtime.");
return -1;
}