After lots of calcs and tests I finally got an algorithm similar to the amount of zombies per round on Cold War. Making it exactly to CW wasn't possible for me as lots of CW GSCs are hashed, but still, it's amount identical on high rounds.
To summarize I've played Zombies since BO2 and one of the things I've always disliked on zombies was how the multipliers of Zombies is so agressive, round 100 alone for example has 924 zombies. Playing CW I loved how they changed those multipliers so rounds progresses much fast instead of you spending 5hrs+ to get up to 100.
So i'm going to share this here cuz i've searched everywere on the internet and couldn't find much info.
But first thanks to Ivobardolf for posting the stock code on the forum which them I took and started modifying.
#include common_scripts\utility;
#include maps\mp\_utility;
#include maps\mp\zombies\_zm_utility;
#include maps\mp\zombies\_zm_ffotd;
#include maps\mp\zombies\_zm;
#include maps\mp\_visionset_mgr;
#include maps\mp\zombies\_zm_devgui;
#include maps\mp\zombies\_zm_zonemgr;
#include maps\mp\zombies\_zm_unitrigger;
#include maps\mp\zombies\_zm_audio;
#include maps\mp\zombies\_zm_blockers;
#include maps\mp\zombies\_zm_bot;
#include maps\mp\zombies\_zm_clone;
#include maps\mp\zombies\_zm_buildables;
#include maps\mp\zombies\_zm_equipment;
#include maps\mp\zombies\_zm_laststand;
#include maps\mp\zombies\_zm_magicbox;
#include maps\mp\zombies\_zm_perks;
#include maps\mp\zombies\_zm_playerhealth;
#include maps\mp\zombies\_zm_power;
#include maps\mp\zombies\_zm_powerups;
#include maps\mp\zombies\_zm_score;
#include maps\mp\zombies\_zm_spawner;
#include maps\mp\zombies\_zm_gump;
#include maps\mp\zombies\_zm_timer;
#include maps\mp\zombies\_zm_traps;
#include maps\mp\zombies\_zm_weapons;
#include maps\mp\zombies\_zm_tombstone;
#include maps\mp\zombies\_zm_stats;
#include maps\mp\zombies\_zm_pers_upgrades;
#include maps\mp\gametypes_zm\_zm_gametype;
#include maps\mp\zombies\_zm_pers_upgrades_functions;
#include maps\mp\_demo;
#include maps\mp\gametypes_zm\_hud_util;
#include maps\mp\zombies\_zm_melee_weapon;
#include maps\mp\zombies\_zm_ai_dogs;
#include maps\mp\zombies\_zm_pers_upgrades_system;
#include maps\mp\gametypes_zm\_weapons;
#include maps\mp\zombies\_zm_ai_basic;
#include maps\mp\zombies\_zm_game_module;
main()
{
level.round_spawn_func = ::cold_war_spawn;
}
cold_war_spawn()
{
level endon( "intermission" );
level endon( "end_of_round" );
level endon( "restart_round" );
/#
level endon( "kill_round" );
#/
if ( level.intermission )
return;
/#
if ( getdvarint( #"zombie_cheat" ) == 2 || getdvarint( #"zombie_cheat" ) >= 4 )
return;
#/
if ( level.zombie_spawn_locations.size < 1 )
{
/#
assertmsg( "No active spawners in the map. Check to see if the zone is active and if it's pointing to spawners." );
#/
return;
}
ai_calculate_health( level.round_number );
count = 0;
players = get_players();
for ( i = 0; i < players.size; i++ )
players[i].zombification_time = 0;
// Get maximum zombies and calculate the multiplier
max = level.zombie_vars["zombie_max_ai"];
multiplier = level.round_number / 5;
if (multiplier < 1)
multiplier = 1;
if (level.round_number >= 10)
multiplier *= (level.round_number * 0.15);
player_num = get_players().size;
// ADJUST FOR PLAYER NUMBER IF THERE'S ONE PLAYER
if (player_num == 1)
{
// For rounds below 29
if (level.round_number < 29)
{
max += int(0.5 * level.zombie_vars["zombie_ai_per_player"] * multiplier);
}
// Calculate caps dynamically for rounds above 29 for one player
if (level.round_number >= 29)
{
// Start from 97 zombies for Round 29
base_zombies = 97;
// Initialize added zombies counter
added_zombies = 0;
// Loop through the rounds and add zombies
for (i = 0; i < (level.round_number - 29); i++)
{
if ((29 + i) % 2 == 1) { // Odd round: add 2 zombies
added_zombies += 2;
} else { // Even round: add 3 zombies
added_zombies += 3;
}
}
// Set the max zombies based on the added zombies from previous rounds
max = base_zombies + added_zombies;
}
}
// ADJUST FOR PLAYER NUMBER IF THERE'S TWO PLAYERS
else if (player_num == 2)
{
// For rounds below 29
if (level.round_number < 29)
{
max += int((player_num - 1) * level.zombie_vars["zombie_ai_per_player"] * multiplier);
}
// Calculate caps dynamically for rounds above 29 for two players
if (level.round_number >= 29)
{
// Start from 180 zombies for Round 29
base_zombies = 180;
// Initialize added zombies counter
added_zombies = 0;
// Loop through the rounds and add zombies according to the pattern
for (i = 0; i < (level.round_number - 29); i++)
{
if ((29 + i) % 2 == 1)
{ // Odd rounds (e.g., 29, 31, 33, etc.): add 5 zombies
added_zombies += 5;
} else
{ // Even rounds (e.g., 30, 32, 34, etc.): add 6 zombies
added_zombies += 6;
}
}
// Set the max zombies based on the base for Round 29 and added zombies from subsequent rounds
max = base_zombies + added_zombies;
}
}
// ADJUST FOR PLAYER NUMBER IF THERE'S THREE PLAYERS
else if (player_num == 3)
{
// For rounds below 20, calculate the zombies as usual (you can adjust this as needed)
if (level.round_number < 20)
{
max += int((player_num - 1) * level.zombie_vars["zombie_ai_per_player"] * multiplier);
}
// Calculate caps dynamically for rounds above 20 for two players
if (level.round_number >= 20)
{
// Start from 168 zombies for Round 20
base_zombies = 168;
// Initialize added zombies counter
added_zombies = 0;
// Loop through the rounds from 20 onwards
for (i = 0; i < (level.round_number - 20); i++)
{
if ((20 + i) % 5 == 0)
{ // Every 5th round (e.g., round 20, 25, etc.), add 8 zombies
added_zombies += 8;
} else { // For other rounds, add 7 zombies
added_zombies += 7;
}
}
// Set the max zombies based on the base for Round 19 and added zombies from subsequent rounds
max = base_zombies + added_zombies;
}
}
// ADJUST FOR PLAYER NUMBER IF THERE'S FOUR PLAYERS
else if (player_num == 4)
{
// For rounds below 20
if (level.round_number < 20)
{
max += int((player_num - 1) * level.zombie_vars["zombie_ai_per_player"] * multiplier);
}
// Calculate caps dynamically for rounds above 20 for four players
if (level.round_number >= 20)
{
// Starting from 204 zombies at Round 20
base_zombies = 204;
// Calculate zombies for rounds 20 to the current round, adding 9 zombies per round
max = base_zombies + ((level.round_number - 20) * 9);
}
}
if ( !isdefined( level.max_zombie_func ) )
level.max_zombie_func = ::default_max_zombie_func;
if ( !( isdefined( level.kill_counter_hud ) && level.zombie_total > 0 ) )
{
level.zombie_total = [[ level.max_zombie_func ]]( max );
level notify( "zombie_total_set" );
}
if ( isdefined( level.zombie_total_set_func ) )
level thread [[ level.zombie_total_set_func ]]();
if ( level.round_number < 10 || level.speed_change_max > 0 )
level thread zombie_speed_up();
mixed_spawns = 0;
old_spawn = undefined;
while ( true )
{
while ( get_current_zombie_count() >= level.zombie_ai_limit || level.zombie_total <= 0 )
wait 0.1;
while ( get_current_actor_count() >= level.zombie_actor_limit )
{
clear_all_corpses();
wait 0.1;
}
flag_wait( "spawn_zombies" );
while ( level.zombie_spawn_locations.size <= 0 )
wait 0.1;
run_custom_ai_spawn_checks();
spawn_point = level.zombie_spawn_locations[randomint( level.zombie_spawn_locations.size )];
if ( !isdefined( old_spawn ) )
old_spawn = spawn_point;
else if ( spawn_point == old_spawn )
spawn_point = level.zombie_spawn_locations[randomint( level.zombie_spawn_locations.size )];
old_spawn = spawn_point;
if ( isdefined( level.mixed_rounds_enabled ) && level.mixed_rounds_enabled == 1 )
{
spawn_dog = 0;
if ( level.round_number > 30 )
{
if ( randomint( 100 ) < 3 )
spawn_dog = 1;
}
else if ( level.round_number > 25 && mixed_spawns < 3 )
{
if ( randomint( 100 ) < 2 )
spawn_dog = 1;
}
else if ( level.round_number > 20 && mixed_spawns < 2 )
{
if ( randomint( 100 ) < 2 )
spawn_dog = 1;
}
else if ( level.round_number > 15 && mixed_spawns < 1 )
{
if ( randomint( 100 ) < 1 )
spawn_dog = 1;
}
if ( spawn_dog )
{
keys = getarraykeys( level.zones );
for ( i = 0; i < keys.size; i++ )
{
if ( level.zones[keys[i]].is_occupied )
{
akeys = getarraykeys( level.zones[keys[i]].adjacent_zones );
for ( k = 0; k < akeys.size; k++ )
{
if ( level.zones[akeys[k]].is_active && !level.zones[akeys[k]].is_occupied && level.zones[akeys[k]].dog_locations.size > 0 )
{
maps\mp\zombies\_zm_ai_dogs::special_dog_spawn( undefined, 1 );
level.zombie_total--;
wait_network_frame();
}
}
}
}
}
}
if ( isdefined( level.zombie_spawners ) )
{
if ( isdefined( level.use_multiple_spawns ) && level.use_multiple_spawns )
{
if ( isdefined( spawn_point.script_int ) )
{
if ( isdefined( level.zombie_spawn[spawn_point.script_int] ) && level.zombie_spawn[spawn_point.script_int].size )
spawner = random( level.zombie_spawn[spawn_point.script_int] );
else
{
/#
assertmsg( "Wanting to spawn from zombie group " + spawn_point.script_int + "but it doens't exist" );
#/
}
}
else if ( isdefined( level.zones[spawn_point.zone_name].script_int ) && level.zones[spawn_point.zone_name].script_int )
spawner = random( level.zombie_spawn[level.zones[spawn_point.zone_name].script_int] );
else if ( isdefined( level.spawner_int ) && ( isdefined( level.zombie_spawn[level.spawner_int].size ) && level.zombie_spawn[level.spawner_int].size ) )
spawner = random( level.zombie_spawn[level.spawner_int] );
else
spawner = random( level.zombie_spawners );
}
else
spawner = random( level.zombie_spawners );
ai = spawn_zombie( spawner, spawner.targetname, spawn_point );
}
if ( isdefined( ai ) )
{
level.zombie_total--;
ai thread round_spawn_failsafe();
count++;
}
wait( level.zombie_vars["zombie_spawn_delay"] );
wait_network_frame();
}
}
What's the code doing:
It will check for 1, 2, 3 or 4 players and apply the corresponded code.
For 1 player for example, seems like from round 29 and onwards on CW, +2 zombies get added every odd round number and +3 for every even round number. On Round 100 you will end up with 275 zombies instead of 924.
For 2 Players, round 29 onwards adds +5 zombies for odd rounds and +6 for even rounds.
For 3 players, from round 20 onwards, +8 zombies gets added every 5th round and +7 zombies for others rounds.
For 4 players, from round 20 onwards +9 zombies will be added every round.
As for why I said it's a similar algorithm, from round (20/29 onwards) it's 99% identical to CW, but before that it uses the same old formula. I've tried doing maths and everything to create the same multiplier from CW but I'm not really good at coding. And looking at CW GSCs I can see they use lots of variables/multipliers for the calcs.