[ZM][RELEASE] [PLUTO ONLY] First box patch for moon + timer + speed patch
-
οΈ Moon β First Box Patch (Plutonium only)This patch makes the first box hits on Moon always give you the right weapons for early setup.
It also includes a few small tweaks that you would need as a zombies player.π§© Features
-
Guaranteed Wave Gun, Gersh Device, and (in co-op) Ray Gun from the box up to round 20
-
QEDs added as a third box hit
-
Game timer
-
Round Timer
-
Movement fix β backspeed and strafe speed now match console behavior
-
Juggernog always spawns at No Manβs Land
-
Spawn Cancel fix
Installation Instructions:-
Enable file extensions
-
Open any folder and go to:
Windows 11: View β Show β File name extensions
Windows 10: View β File name extensions
-
This ensures the file is correctly saved as patch.gsc and not patch.gsc.txt
-
Create the script file
-
Open Notepad (or any text editor).
-
Copy and paste the script code provided below.
-
Save the file as: patch.gsc
-
Create the map folder
-
Press Windows + R
-
Navigate to: %localappdata%/Plutonium/storage/t5/scripts/sp
Inside the sp folder, create a new folder named: zombie_moon
Place your patch.gsc file inside this folder.
Restore the original common file
Replace your common_zombie_patch.ff with the original game file before launching the map.
The patch will not load if youβre using a modified common file unless it was specifically made for moon.
If you donβt have the original file, download and unzip it here:
Download patch- Launch the map and play
Load up Moon in Plutonium and the patch will apply automatically.
π§ͺ Update Log
v1.1 β 10/20/2025
-
Added QEDs as third box hit
-
Added Ray Gun (co-op only) as fourth hit
-
Added game timer
-
Juggernog now always spawns at NML
v1.2 - 10/22/2025
- Added Spawn cancel fix
v1.3 - 10/22/2025
-
Set box to spawn at biodome as initial location
-
Perks alternate again after picking up jug for the first time in no man's land
NotesWorks only on Plutonium (uses replaceFunc)
Tested and confirmed working 100%
Report any gameplay issues if you find them
#include maps\_utility; #include common_scripts\utility; #include maps\_zombiemode_utility; main() { if ( GetDvar( #"zombiemode" ) == "1" ) { level thread onPlayerConnect(); replacefunc(maps\_zombiemode_weapons::treasure_chest_ChooseWeightedRandomWeapon, ::custom_treasure_chest_ChooseWeightedRandomWeapon); replacefunc(maps\zombie_moon_wasteland::perk_machine_arrival_update, ::custom_perk_machine_arrival_update); replacefunc(maps\_zombiemode::round_think, ::custom_round_think); replacefunc(maps\_zombiemode_ai_faller::do_zombie_fall, ::custom_do_zombie_fall); replacefunc(maps\_zombiemode_weapons::init_starting_chest_location, ::custom_init_starting_chest_location); level.moon_visits = 0; } } any_player_has_weapon(weap) { players = get_players(); has_weap = false; for(i = 0; players.size > i; i++) { if(players[i] maps\_zombiemode_weapons::has_weapon_or_upgrade(weap)) has_weap = true; } return has_weap; } game_timer() { hud = create_simple_hud( self ); hud.foreground = true; hud.sort = 1; hud.hidewheninmenu = true; hud.alignX = "left"; hud.alignY = "top"; hud.horzAlign = "user_left"; hud.vertAlign = "user_top"; hud.alpha = 1; //=======================CUSTOM SECTION============== hud.x = hud.x - -720; //This is for the position on X axis, decrease this number to move it further left, and increase it to go right. hud.y = hud.y + 35; //This is for the position on Y axis, decrease this number to move it down, and increase it to go up. hud.fontscale = 1.2; //This is for the font size, increase it by whatever you want and see what you like hud.color = (255, 255, 255); //This is for the color using RGB, use a website for that //========================================= flag_wait("all_players_spawned"); hud setTimerUp(1); } round_timer() { timerHud = create_simple_hud( self ); timerHud.foreground = true; timerHud.sort = 1; timerHud.hidewheninmenu = true; timerHud.alignX = "left"; timerHud.alignY = "top"; timerHud.horzAlign = "user_left"; timerHud.vertAlign = "user_top"; //=======================CUSTOM SECTION============== timerHud.x = timerHud.x - -720; //This is for the position on X axis, decrease this number to move it further left, and increase it to go right. timerHud.y = timerHud.y + 45; //This is for the position on Y axis, decrease this number to move it down, and increase it to go up. timerHud.fontscale = 1.2; //This is for the font size, increase it by whatever you want and see what you like timerHud.color = (255, 0, 0); //This is for the color using RGB, use a website for that //========================================= timerHud.alpha = 1; flag_wait("all_players_spawned"); for (;;){ start_time = GetTime() / 1000; timerHud setTimerUp(0); level waittill("end_of_round"); end_time = GetTime() / 1000; time = end_time - start_time; set_time_frozen(timerHud, time); } } set_time_frozen(hud, time) { level endon("start_of_round"); time = time - 0.1; while(1) { hud settimer(time); wait(0.5); } } patch_moon() { //WaveGun if(!self maps\_zombiemode_weapons::has_weapon_or_upgrade("microwavegundw_zm") && !any_player_has_weapon("microwavegundw_zm")) return "microwavegundw_zm"; //Gersh if(!self maps\_zombiemode_weapons::has_weapon_or_upgrade("zombie_black_hole_bomb")) return "zombie_black_hole_bomb"; if(!self maps\_zombiemode_weapons::has_weapon_or_upgrade("zombie_quantum_bomb")) return "zombie_quantum_bomb"; if (get_players().size > 1){ //RayGun for coop if(!self maps\_zombiemode_weapons::has_weapon_or_upgrade("ray_gun_zm")) return "ray_gun_zm"; } } custom_treasure_chest_ChooseWeightedRandomWeapon( player ) { //First Box by Crybaby / AlexInVr if(level.round_number < 20) { //Moon if (level.script == "zombie_moon") return player patch_moon(); } keys = GetArrayKeys( level.zombie_weapons ); toggle_weapons_in_use = 0; // Filter out any weapons the player already has filtered = []; for( i = 0; i < keys.size; i++ ) { if( !maps\_zombiemode_weapons::get_is_in_box( keys[i] ) ) { continue; } if( isdefined( player ) && is_player_valid(player) && player maps\_zombiemode_weapons::has_weapon_or_upgrade( keys[i] ) ) { if ( maps\_zombiemode_weapons::is_weapon_toggle( keys[i] ) ) { toggle_weapons_in_use++; } continue; } if( !IsDefined( keys[i] ) ) { continue; } num_entries = [[ level.weapon_weighting_funcs[keys[i]] ]](); for( j = 0; j < num_entries; j++ ) { filtered[filtered.size] = keys[i]; } } // Filter out the limited weapons if( IsDefined( level.limited_weapons ) ) { keys2 = GetArrayKeys( level.limited_weapons ); players = get_players(); pap_triggers = GetEntArray("zombie_vending_upgrade", "targetname"); for( q = 0; q < keys2.size; q++ ) { count = 0; for( i = 0; i < players.size; i++ ) { if( players[i] maps\_zombiemode_weapons::has_weapon_or_upgrade( keys2[q] ) ) { count++; } } // Check the pack a punch machines to see if they are holding what we're looking for for ( k=0; k<pap_triggers.size; k++ ) { if ( IsDefined(pap_triggers[k].current_weapon) && pap_triggers[k].current_weapon == keys2[q] ) { count++; } } // Check the other boxes so we don't offer something currently being offered during a fire sale for ( chestIndex = 0; chestIndex < level.chests.size; chestIndex++ ) { if ( IsDefined( level.chests[chestIndex].chest_origin.weapon_string ) && level.chests[chestIndex].chest_origin.weapon_string == keys2[q] ) { count++; } } if ( isdefined( level.random_weapon_powerups ) ) { for ( powerupIndex = 0; powerupIndex < level.random_weapon_powerups.size; powerupIndex++ ) { if ( IsDefined( level.random_weapon_powerups[powerupIndex] ) && level.random_weapon_powerups[powerupIndex].base_weapon == keys2[q] ) { count++; } } } if ( maps\_zombiemode_weapons::is_weapon_toggle( keys2[q] ) ) { toggle_weapons_in_use += count; } if( count >= level.limited_weapons[keys2[q]] ) { filtered = array_remove( filtered, keys2[q] ); } } } // finally, filter based on toggle mechanic if ( IsDefined( level.zombie_weapon_toggles ) ) { keys2 = GetArrayKeys( level.zombie_weapon_toggles ); for( q = 0; q < keys2.size; q++ ) { if ( level.zombie_weapon_toggles[keys2[q]].active ) { if ( toggle_weapons_in_use < level.zombie_weapon_toggle_max_active_count ) { continue; } } filtered = array_remove( filtered, keys2[q] ); } } // try to "force" a little more "real randomness" by randomizing the array before randomly picking a slot in it filtered = array_randomize( filtered ); return filtered[RandomInt( filtered.size )]; } custom_perk_machine_arrival_update() { top_height = 1200; // 700 fall_time = 4; num_model_swaps = 20; perk_index = randomintrange( 0, 2 ); // Flash an effect to the perk machines destination ent = level.speed_cola_ents[0]; level thread maps\zombie_moon_wasteland::perk_arrive_fx( ent.origin ); //while( 1 ) { // Move the perk machines high in the sky maps\zombie_moon_wasteland::move_perk( top_height, 0.01, 0.001 ); wait( 0.3 ); maps\zombie_moon_wasteland::perk_machines_hide( 0, 0, true ); wait( 1 ); // Start the machines falling maps\zombie_moon_wasteland::move_perk( top_height*-1, fall_time, 1.5 ); // Swap visible Perk as we fall wait_step = fall_time / num_model_swaps; for( i=0; i<num_model_swaps; i++ ) { maps\zombie_moon_wasteland::perk_machine_show_selected( perk_index, true ); wait( wait_step ); perk_index++; if( perk_index > 1 ) { perk_index = 0; } } // Make sure we don't get a perk machine duplicate next time we visit while( perk_index == level.last_perk_index ) { perk_index = randomintrange( 0, 2 ); } level.last_perk_index = perk_index; custom_perk_index = 1; //Default to Jug (0: Cola, 1: Jug) if (isDefined(level.ever_been_on_the_moon) && level.ever_been_on_the_moon) { // If we've been on the moon, we already took jug (You should have.... not my problem otherwise) // Switch the perk to SpeedCola (Index 0) level.moon_visits++; if (level.moon_visits >= 2) { custom_perk_index = perk_index; } else { custom_perk_index = 0; } } maps\zombie_moon_wasteland::perk_machine_show_selected( custom_perk_index, false ); } } custom_round_think() { for( ;; ) { ////////////////////////////////////////// //designed by prod DT#36173 maxreward = 50 * level.round_number; if ( maxreward > 500 ) maxreward = 500; level.zombie_vars["rebuild_barrier_cap_per_round"] = maxreward; ////////////////////////////////////////// level.pro_tips_start_time = GetTime(); level.zombie_last_run_time = GetTime(); // Resets the last time a zombie ran level thread maps\_zombiemode_audio::change_zombie_music( "round_start" ); maps\_zombiemode::chalk_one_up(); maps\_zombiemode_powerups::powerup_round_start(); players = get_players(); array_thread( players, maps\_zombiemode_blockers::rebuild_barrier_reward_reset ); level thread maps\_zombiemode::award_grenades_for_survivors(); bbPrint( "zombie_rounds: round %d player_count %d", level.round_number, players.size ); level.round_start_time = GetTime(); level thread [[level.round_spawn_func]](); level notify( "start_of_round" ); [[level.round_wait_func]](); level.first_round = false; level notify( "end_of_round" ); level thread maps\_zombiemode_audio::change_zombie_music( "round_end" ); UploadStats(); if ( 1 != players.size ) { level thread maps\_zombiemode::spectators_respawn(); } level maps\_zombiemode::chalk_round_over(); // here's the difficulty increase over time area timer = level.zombie_vars["zombie_spawn_delay"]; if ( timer > 0.08 ) { level.zombie_vars["zombie_spawn_delay"] = timer * 0.95; } else if ( timer < 0.08 ) { level.zombie_vars["zombie_spawn_delay"] = 0.08; } // Increase the zombie move speed level.zombie_move_speed = level.round_number * level.zombie_vars["zombie_move_speed_multiplier"]; level.round_number++; level notify( "between_round_over" ); } } custom_do_zombie_fall() { self endon("death"); self thread maps\_zombiemode_ai_faller::setup_deathfunc(); // don't drop powerups until we are on the ground self.no_powerups = true; self.in_the_ceiling = true; self.anchor = spawn("script_origin", self.origin); self.anchor.angles = self.angles; self linkto(self.anchor); if ( !IsDefined( self.zone_name ) ) { self.zone_name = self get_current_zone(); } spots = maps\_zombiemode_ai_faller::get_available_fall_locations(); if( spots.size < 1 ) { self unlink(); self.anchor delete(); //IPrintLnBold("deleting zombie faller - no available fall locations"); //can't delete if we're in the middle of spawning, so wait a frame self Hide();//hide so we're not visible for one frame while waiting to delete self delayThread( 0.1, maps\_zombiemode_ai_faller::zombie_faller_delete ); return; } else if ( GetDvarInt(#"zombie_fall_test") ) { // use the spot closest to the first player always player = GetPlayers()[0]; spot = undefined; bestDist = 0.0; for ( i = 0; i < spots.size; i++ ) { checkDist = DistanceSquared(spots[i].origin, player.origin); if ( !IsDefined(spot) || checkDist < bestDist ) { spot = spots[i]; bestDist = checkDist; } } } else { spot = random(spots); } self.zombie_faller_location = spot; //NOTE: multiple zombie fallers could be waiting in the same spot now, need to have spawners detect this // and not use the spot again until the previous zombie has died or dropped down self.zombie_faller_location.is_enabled = false; self thread maps\_zombiemode_ai_faller::zombie_faller_death_wait(); self.zombie_faller_location maps\_zombiemode_ai_faller::parse_script_parameters(); if( !isDefined( spot.angles ) ) { spot.angles = (0, 0, 0); } //Patch begin anim_org = spot.origin; anim_ang = spot.angles; self Hide(); self.anchor moveto(anim_org, .05); self.anchor waittill("movedone"); // face goal target_org = maps\_zombiemode_spawner::get_desired_origin(); if (IsDefined(target_org)) { anim_ang = VectorToAngles(target_org - self.origin); current_pos = self.anchor.origin; // Instantly rotate the anchor instead of waiting for RotateTo self.anchor ForceTeleport(current_pos, (0, anim_ang[1], 0), false, false); } self unlink(); self.anchor delete(); self thread maps\_zombiemode_ai_faller::hide_pop(); // hack to hide the pop when the zombie gets to the start position before the anim starts level thread maps\_zombiemode_ai_faller::zombie_fall_death(self, spot); spot thread maps\_zombiemode_ai_faller::zombie_fall_fx(self); self thread maps\_zombiemode_ai_faller::zombie_faller_death_wait(); //need to thread off the rest because we're apparently still in the middle of our init! self thread maps\_zombiemode_ai_faller::zombie_faller_do_fall(); } custom_init_starting_chest_location() { level.chest_index = 0; start_chest_found = false; for( i = 0; i < level.chests.size; i++ ) { if(level.script == "zombie_theater") { if(IsSubStr(level.chests[i].script_noteworthy, "crematorium_chest" )) { level.chest_index = i; level.chests[level.chest_index] maps\_zombiemode_weapons::hide_rubble(); level.chests[level.chest_index].hidden = false; } else { level.chests[i] maps\_zombiemode_weapons::hide_chest(); } } else if(level.script == "zombie_pentagon") { if(level.chests[i].script_noteworthy == "start_chest") //if(IsSubStr(level.chests[i].script_noteworthy, "start_chest" )) { level.chest_index = i; level.chests[level.chest_index] maps\_zombiemode_weapons::hide_rubble(); level.chests[level.chest_index].hidden = false; } else { level.chests[i] maps\_zombiemode_weapons::hide_chest(); } } else if(level.script == "zombie_coast") { if(IsSubStr(level.chests[i].script_noteworthy, "start_chest" )) //residence_chest = flopper { level.chest_index = i; level.chests[level.chest_index] maps\_zombiemode_weapons::hide_rubble(); level.chests[level.chest_index].hidden = false; } else { level.chests[i] maps\_zombiemode_weapons::hide_chest(); } } else if(level.script == "zombie_temple") { if(IsSubStr(level.chests[i].script_noteworthy, "bridge_chest" )) { level.chest_index = i; level.chests[level.chest_index] maps\_zombiemode_weapons::hide_rubble(); level.chests[level.chest_index].hidden = false; } else { level.chests[i] maps\_zombiemode_weapons::hide_chest(); } } else if(level.script == "zombie_moon") { if(IsSubStr(level.chests[i].script_noteworthy, "forest_chest" )) { level.chest_index = i; level.chests[level.chest_index] maps\_zombiemode_weapons::hide_rubble(); level.chests[level.chest_index].hidden = false; } else { level.chests[i] maps\_zombiemode_weapons::hide_chest(); } } else if( isdefined( level.random_pandora_box_start ) && level.random_pandora_box_start == true ) { if ( start_chest_found || (IsDefined( level.chests[i].start_exclude ) && level.chests[i].start_exclude == 1) ) { level.chests[i] maps\_zombiemode_weapons::hide_chest(); } else { level.chest_index = i; level.chests[level.chest_index] maps\_zombiemode_weapons::hide_rubble(); level.chests[level.chest_index].hidden = false; start_chest_found = true; } } else { // Semi-random implementation (not completely random). The list is randomized // prior to getting here. // Pick from any box marked as the "start_chest" if ( start_chest_found || !IsDefined(level.chests[i].script_noteworthy ) || ( !IsSubStr( level.chests[i].script_noteworthy, "start_chest" ) ) ) { level.chests[i] maps\_zombiemode_weapons::hide_chest(); } else { level.chest_index = i; level.chests[level.chest_index] maps\_zombiemode_weapons::hide_rubble(); level.chests[level.chest_index].hidden = false; start_chest_found = true; } } } // Show the beacon if( !isDefined( level.pandora_show_func ) ) { level.pandora_show_func = maps\_zombiemode_weapons::default_pandora_show_func; } level.chests[level.chest_index] thread [[ level.pandora_show_func ]](); } onPlayerConnect() { for(;;) { level waittill ("connecting", player); player thread onPlayerSpawned(); } } onPlayerSpawned() { for(;;) { self waittill("spawned_player"); self thread game_timer(); self thread round_timer(); self SetClientDvars( "player_backSpeedScale", "1", "player_strafeSpeedScale", "1"); wait 3; self IPrintLn("First box by ^1twitch.tv/^2AlexInZombies"); } }PICS:

-
-
nice!
-
nice!
hindercanrun thx man ! Appreciate it, been trying to find a way to patch this map for a while now
-
what file do i play zombie_moon in? i dont understand
-
f0rbiddin press windows + r on your keyboard
inside the window that pops up, type in %LOCALAPPDATA%
go to the folder plutonium/Storage/t5/scripts/sp
create a new folder name zombie_moon
drop the script inside it,
(Create a new text file, and name it whatever you want, copy the code in the thread, paste it inside, then rename the extension to .gsc)
-
undefined bhfff referenced this topic on
-
Please add the QED's in
-
undefined AlexInVr referenced this topic on
-
how can i change it to give qeds third hit instead of raygun?
-
_Tome What's your discord
-
Glitchy99 Will do right away
-
This post is deleted!
-
UPDATE 10/20/2025:
-
Added QED's as third hit
-
Added a condition so raygun only shows up for coop games as 4th hit of the box
-
Added round timer
-
Jug is always the perk that spawns at NML
-
-
Glitchy99 QED's have been added
-
UPDATE: 10/22/2025, Implemented custom fix for spawn cancel