Skip to content
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Donate
Collapse

Plutonium

  1. Home
  2. BO2 Modding Releases & Resources
  3. [ZM] Cold War Zombies amount per round similar algorithm!

[ZM] Cold War Zombies amount per round similar algorithm!

Scheduled Pinned Locked Moved BO2 Modding Releases & Resources
5 Posts 3 Posters 1.2k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Guilherme_INFRundefined Offline
    Guilherme_INFRundefined Offline
    Guilherme_INFR
    wrote on last edited by
    #1

    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.

    1 Reply Last reply
    1
    • Ivobardolfundefined Offline
      Ivobardolfundefined Offline
      Ivobardolf
      wrote on last edited by
      #2

      Nice, Having 510 Zombies in round 30 for 4 players is a LOT, changes like this makes high rounds when lots of people are in don't take way too much time and it's all just formulas and math to setup what you want 👍 .

      Guilherme_INFRundefined 1 Reply Last reply
      0
      • Guilherme_INFRundefined Offline
        Guilherme_INFRundefined Offline
        Guilherme_INFR
        replied to Ivobardolf on last edited by
        #3

        Ivobardolf Exactly bro 🙂 Such a good change that came in Cold War

        1 Reply Last reply
        1
        • GerardS0406undefined Offline
          GerardS0406undefined Offline
          GerardS0406 VIP
          wrote on last edited by
          #4

          Thanks for posting this!
          You were pretty much spot on about round 20 and 29 being turning points! However, only solo has the 29 round cap.
          If you want to learn more about Cold War's code, here's pseudo code for this exact function. I have replaced all hashes with their real values and changed variable names to make them more helpful to understand, unless they were unknown (only because the scriptbundle required does not exist). Then I put comments for hypothetical values. Round 1-5 are hardcoded values so I have included the max_zombie_func to show that. I hope this helps you understand the code behind it more! Feel free to ask questions. This is Pseudo Code. It will not compile!! Also the default_max_zombie_func will error if you don't handle more than 4 players!:

          get_zombie_count_for_round(n_round, n_player_count) {
              n_player_count = GetPlayers().size;
          
              max = zombie_utility::get_zombie_var(#"zombie_max_ai"); //We don't know - hardcoded in Cold War (assume 24)
          
              if (n_player_count == 1) {
                  highestRound = 29;
                  playerMult = 0.84;
                  additionalMult = zombie_utility::get_zombie_var(#"hash_67b3cbf79292e047"); //We don't know - hardcoded in Cold War (0.5 in bo4)
              } else {
                  highestRound = 20;
                  playerMult = 0.6;
                  additionalMult = 0.5 + n_player_count / 2;
              }
              if (n_round < var_8ca3a339) /*if the round is < 29 on solo OR < 20 on co-op do this*/ {
                  playerMult = zombie_utility::get_zombie_var(#"hash_607bc50072c2a386"); //We don't know - hardcoded in Cold War (0.15 in bo4)
                  multiplier = n_round / 5;
                  if (multiplier < 1) {
                      multiplier = 1;
                  }
                  multiplier *= n_round * playerMult;
              } else {
                  multiplier = n_round * playerMult;
              }
              max += int(additionalMult * zombie_utility::get_zombie_var(#"zombie_ai_per_player") * multiplier); //zombie_ai_per_player is hardcoded in Cold War (we can assume 6)
              if (!isdefined(level.max_zombie_func)) {
                  level.max_zombie_func = &default_max_zombie_func;
              }
              n_zombie_count = [[ level.max_zombie_func ]](max, n_round);
              return function_c112af8e(n_zombie_count);
          }
          
          default_max_zombie_func(max_num, n_round) {
              /#
                  count = getdvarint(#"zombie_default_max", -1);
                  if (count > -1) {
                      return count;
                  }
              #/
              n_players = getplayers().size;
              round1Counts = array(6, 8, 11, 14, 17);
              round2Counts = array(9, 11, 14, 18, 21);
              round3Counts = array(13, 15, 20, 25, 31);
              round4Counts = array(18, 20, 25, 33, 40);
              round5Counts = array(24, 25, 32, 42, 48);
              switch (n_round) {
              case 1:
                  max = round1Counts[n_players - 1];
                  break;
              case 2:
                  max = round2Counts[n_players - 1];
                  break;
              case 3:
                  max = round3Counts[n_players - 1];
                  break;
              case 4:
                  max = round4Counts[n_players - 1];
                  break;
              case 5:
                  max = round5Counts[n_players - 1];
                  break;
              default:
                  max = max_num;
                  break;
              }
              return max;
          }
          

          Here's the result of said function.
          This gets us to about
          8ea6cc24-a789-4e0d-a303-294ce73f8baf-image.png 034a4bd3-4e34-4c06-b7a3-41f77d138a9f-image.png

          Guilherme_INFRundefined 1 Reply Last reply
          0
          • Guilherme_INFRundefined Offline
            Guilherme_INFRundefined Offline
            Guilherme_INFR
            replied to GerardS0406 on last edited by
            #5

            GerardS0406 Oh man that's reaaally nice, thanks! Will take a look when I have some free time 🙂

            1 Reply Last reply
            0

            • Login

            • Don't have an account? Register

            • Login or register to search.
            • First post
              Last post
            0
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Donate