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

Plutonium

ElPiketeundefined

ElPikete

@ElPikete
About
Posts
1
Topics
1
Shares
0
Groups
0
Followers
4
Following
4

Posts

Recent Best Controversial

  • [Release] [Zombies] Zenkai + True Quick Revive Coop + More Max Ammo + No Limit Perk
    ElPiketeundefined ElPikete

    I created this mod to play cooperatively with a friend. It includes several cool features that make the experience more intense, in my opinion.

    Zenkai: Every time you die or very near to die, you become stronger, faster, jump higher, and gain more life. Speed and jump have limits, but health and damage don't. You can farm as many Zenkais has you wan't but make the game very boring. Use them wisely.

    True Quick Revive Coop: As in the solo game, if you have a quick revive, you revive almost automatically without another player having to do it. (It doesn't always work, I don't know why.)

    More Max Ammo: If your ammunition level drops, the probability of obtaining a random max ammo drop increases exponentially. If you have no ammunition in any of your weapons and you kill a zombie, you will obtain max ammo with a 100% probability.

    No Limit Perk: Explains itself.

    It's very fun to play in town. It's a little buggy, maybe I'll keep improving it. If anyone wants to do it, go ahead.

    Install: Just name a file however you want with the .gsc extension, copy this code and drop it in: \AppData\Local\Plutonium\storage\t6\scripts\zm

    #include maps\mp\_utility;
    #include maps\mp\zombies\_zm_utility;
    #include maps\mp\zombies\_zm_powerups;
    #include maps\mp\zombies\_zm_score;
    #include common_scripts\utility;
    #include maps\_laststand;
    
    init()
    {
        level thread onPlayerConnect();
        level thread chatMonitor();
        level thread zombieMaxAmmoMonitor();  
    
        level.original_damagecallback = level.callbackactordamage;
        level.callbackactordamage = ::actor_damage_override_wrapper;
        //register_player_damage_callback( ::damage_callback );
    
        level.perk_purchase_limit = 9;
    }
    
    onPlayerConnect()
    {
        while(1)
        {
            level waittill("connected", player);
            player thread onPlayerSpawned();
        }
    }
    
    onPlayerSpawned()
    {
        self endon("disconnect");
        
        while(1)
        {
            self waittill("spawned_player");
            
            self notify("stop_mod");
            
            if(!isDefined(self.modLoaded))
            {
                self.modLoaded = true;
                self iPrintLnBold("^2MOD CARGADO");
                self iPrintLn("^3Chat: ^2!maxammo ^7| ^2!nuke ^7| ^2!zenkai ^7| ^2!health");
            }
    
            // Inicializar estados únicos (PERSISTENTES a través de muertes/revives)
            self.custom_speed = (isDefined(self.pers["custom_speed"])) ? self.pers["custom_speed"] : 1.0;
            self.base_health = 100;
            self.zenkai_bonus = (isDefined(self.pers["zenkai_bonus"])) ? self.pers["zenkai_bonus"] : 0; 
            self.juggernog_bonus = 0; 
            self.jump_boost = (isDefined(self.pers["jump_boost"])) ? self.pers["jump_boost"] : 0;
            self.already_jumped = false;
            self.damage_multiplier = (isDefined(self.pers["damage_multiplier"])) ? self.pers["damage_multiplier"] : 1;
            self.has_quickRevive = false;
    
            // Stamina infinita para mejor jugabilidad
            self SetPerk("specialty_unlimitedsprint");
            
            // Set inicial de vida y velocidad (IMPORTANTE post-spawn)
            self.maxhealth = self.base_health + self.juggernog_bonus + self.zenkai_bonus;
            self.health = self.maxhealth;
    
            // Damos dinero infinito
            //self.score = 999999;
            //self.pers["score"] = 999999;
    
            self.score = 1500;
            self.pers["score"] = 1500;
    
            // Hilos por jugador
            self thread mainPlayerThread();
            self thread reviveMonitor();
            self thread juggernogMonitor();
            self thread quickReviveMonitor();
            self thread watchQuickReviveCoop();
            //self thread showHUDInfo(); //debug
        }
    }
    
    mainPlayerThread()
    {
        self endon("disconnect");
        self endon("stop_mod");
        
        self thread zenkaiThread();
        self thread jumpingThread();
    }
    
    // =====================================================
    // Manejo de daño
    // =====================================================
    
    actor_damage_override_wrapper( inflictor, attacker, damage, flags, meansofdeath, weapon, vpoint, vdir, shitloc, psoffsettime, boneindex )
    {
        damage_override = self actor_damage_override_override( inflictor, attacker, damage, flags, meansofdeath, weapon, vpoint, vdir, shitloc, psoffsettime, boneindex );
        self finishactordamage( inflictor, attacker, damage_override, flags, meansofdeath, weapon, vpoint, vdir, shitloc, psoffsettime, boneindex );
    }
    
    actor_damage_override_override( inflictor, attacker, damage, flags, meansofdeath, weapon, vpoint, vdir, shitloc, psoffsettime, boneindex )
    {
        // Si la víctima ES un jugador, usa el comportamiento normal (no queremos matar al jugador con instakill)
        if ( isPlayer(self) )
        {
            return [[level.original_damagecallback]]( inflictor, attacker, damage, flags, meansofdeath, weapon, vpoint, vdir, shitloc, psoffsettime, boneindex );
        }
    
        // Si el atacante NO es un jugador, usa el daño normal (ej: trampas, fuego, otros zombies)
        if ( !isDefined(attacker) || !isPlayer(attacker) )
        {
            return [[level.original_damagecallback]]( inflictor, attacker, damage, flags, meansofdeath, weapon, vpoint, vdir, shitloc, psoffsettime, boneindex );
        }
    
        // A partir de aquí: víctima = zombie/enemigo, atacante = jugador humano
    
        // Detectar si la víctima es un zombie (opcional, pero más seguro)
        // En Zombies estándar, los zombies tienen "is_zombie" definido o archetype == "zombie"
        if ( !isDefined(self.is_zombie) && self.archetype != "zombie" )
        {
            // Si no es un zombie (ej: perro, avogadro, objeto), usar daño normal
            return [[level.original_damagecallback]]( inflictor, attacker, damage, flags, meansofdeath, weapon, vpoint, vdir, shitloc, psoffsettime, boneindex );
        }
    
        // Inicializar finaldamage
        finaldamage = damage;
        
        // Multiplicamos por el multiplicador de daño del jugadFor
        if (isDefined(attacker.damage_multiplier))
        {
            finaldamage = int(damage * attacker.damage_multiplier);
        }
    
        // Notificacion
        attacker iPrintLnBold("^3Daño infligido: ^7" + int(finaldamage));
    
        // No se porque pero funciona
        return finaldamage;
    }
    
    // =====================================================
    // Monitor de revivir
    // =====================================================
    
    reviveMonitor()
    {
        while(1)
        {
            // Pausa hasta que un jugador reviva
            self waittill("player_revived");
            
            // Asignamos vida maxima 
            self.maxhealth = self.base_health + self.juggernog_bonus + self.zenkai_bonus;
        }
    }
    
    // =====================================================
    // Juggernog monitor, monitorea en tiempo real si el jugador tiene Juggernog 
    // =====================================================
    
    juggernogMonitor()
    {
        self endon("disconnect"); // Termina si el jugador se desconecta
        self endon("stop_mod"); // Termina si el mod se detiene
    
        // Bucle infinito que verifica continuamente si el jugador tiene el juggernaut
        while(1)
        {
            // Si tengo activado le juggernog activo el bonus
            if (self HasPerk("specialty_armorvest")) 
            {
                // Bonus
                self.juggernog_bonus = 150;
    
                // Asignamos vida maxima 
                self.maxhealth = self.base_health + self.juggernog_bonus + self.zenkai_bonus;
            }
            else 
            {
                // Si no tenemos el juggernog, desactivamos el bonus
                self.juggernog_bonus = 0;
            }
    
            // Espera brevemente antes de la próxima comprobación (100 ms)
            wait 0.1;
        }
    }
    
    // =====================================================
    // Auto-Renanimacion (Quick Revive Solo en Coop)
    // =====================================================
    
    watchQuickReviveCoop()
    {
        self endon("disconnect"); // Termina si el jugador se desconecta
        self endon("stop_mod"); // Termina si el mod se detiene
    
        // SOLO FUNCIONA EN COOP (más de 1 jugador)
        if (level.players.size <= 1) return;
    
        while(1)
        {
            // Se activa cuando YO me tumbo
            self waittill("player_downed"); 
    
            // Verificar si tengo Quick Revive activo
            if (self.has_quickRevive)
            {
                // Pequeño delay para evitar conflictos
                wait 1;
    
                // Reanimarme a mi mismo
                maps\mp\zombies\_zm_laststand::auto_revive(self);
    
                // Ya no tenemos quick revive
                self.has_quickRevive = false;
            }
        }
    }
    
    // Función que monitorea en tiempo real si el jugador tiene Quick Revive
    quickReviveMonitor()
    {
        self endon("disconnect"); // Termina si el jugador se desconecta
        self endon("stop_mod"); // Termina si el mod se detiene 
    
        while(1)
        {
            // Si tengo Quick Revive activo la variable
            if (self HasPerk("specialty_quickrevive")) 
            {
                self.has_quickRevive = true;
            }
            else 
            {
                // Si no, no
                self.has_quickRevive = false;
            }
    
            // Espera brevemente antes de la próxima comprobación (100 ms)
            wait 0.1;
        }
    }
    
    
    // =====================================================
    // Hilo de Zenkai
    // =====================================================
    
    zenkaiThread()
    {
        self endon("disconnect"); // Termina si el jugador se desconecta
        self endon("stop_mod"); // Termina si el mod se detiene                
    
        // Estado inicial: Zenkai no activado.
        self.zenkai_activated = false;               
    
        while(1)
        {
            // Zenkai se activa no esta activado y la salud es menor o igual a 20
            if(!self.zenkai_activated && self.health <= 20)
            {
                // Marca Zenkai como activado
                self.zenkai_activated = true;
    
                // Aumenta el bono de salud por Zenkai
                self.zenkai_bonus += 20;             
                self.pers["zenkai_bonus"] = self.zenkai_bonus; 
    
                // Incrementa la velocidad de movimiento
                self.custom_speed += 0.1;            
                if(self.custom_speed > 1.7) self.custom_speed = 1.7; 
                self.pers["custom_speed"] = self.custom_speed; 
                
                // Aplica la nueva velocidad
                self setMoveSpeedScale(self.custom_speed); 
    
                // Aumenta el impulso de salto
                self.jump_boost += 4;               
                if(self.jump_boost > 24) self.jump_boost = 24; 
                self.pers["jump_boost"] = self.jump_boost;
                
                // Aumenta el multiplicador de daño
                self.damage_multiplier += 0.5;         
                self.pers["damage_multiplier"] = self.damage_multiplier; 
    
                // Asignamos vida maxima 
                self.maxhealth = self.base_health + self.juggernog_bonus + self.zenkai_bonus;
    
                // Notificar
                self iPrintLnBold("^4Zenkai Boost! ^2Salud maxima actualizada: ^7" + self.maxhealth);
            }
    
            // Si casi está al máximo de salud
            if (self.health >= self.maxhealth - 5)   
            {
                // Permite reactivar Zenkai en el futuro
                self.zenkai_activated = false;       
            }
    
            // Espera breve antes de volver a comprobar.
            wait 0.1;                                
        }
    }
    
    // =====================================================
    // Thread de saltar
    // =====================================================
    
    jumpingThread()
    {
        self endon("disconnect"); // Termina si el jugador se desconecta
        self endon("stop_mod"); // Termina si el mod se detiene        
    
        while(1)
        {
            // Espera el salto 
            if (!self isOnGround() && !self.already_jumped) {
                for(i = 0; i < self.jump_boost; i++)
                {
                    newPos = self getOrigin() + (0, 0, 1); // Sube X unidades en Z (altura)
                    self setOrigin(newPos);
                }
    
                self.already_jumped = true;
            }
    
            if (self isOnGround())
            {
                self.already_jumped = false;
            }
    
            wait 0.01;
        }
    }
    
    // =====================================================
    // HUD 
    // =====================================================
    
    showHUDInfo()
    {
        self endon("disconnect"); // Termina si el jugador se desconecta
        self endon("stop_mod"); // Termina si el mod se detiene   
    
        // Limpieza
        self destroyStatHUD(self.hud_health_label, self.hud_health_value);
        self destroyStatHUD(self.hud_jump_label, self.hud_jump_value);
        self destroyStatHUD(self.hud_speed_label, self.hud_speed_value);
        self destroyStatHUD(self.hud_damage_label, self.hud_damage_value);
    
        // Labels: right-aligned, x=-12 (derecha), terminan EN ": " (ESPACIO después de :)
        self.hud_health_label = createStatLabelHUD("right", "top", -12, 20, 1.1, "Salud: ");
        self.hud_jump_label    = createStatLabelHUD("right", "top", -12, 36, 1.0, "Salto: ");
        self.hud_speed_label   = createStatLabelHUD("right", "top", -12, 52, 1.0, "Velocidad: ");
        self.hud_damage_label  = createStatLabelHUD("right", "top", -12, 68, 1.0, "Daño: ");
    
        // Values: left-aligned, x MISMO QUE LABEL (-12) → ¡empieza JUSTO donde termina el label (después del espacio)!
        self.hud_health_value  = createStatLeftTextHUD("right", "top", -12, 20, 1.1);
        self.hud_jump_value    = createStatLeftTextHUD("right", "top", -12, 36, 1.0);
        self.hud_speed_value   = createStatLeftTextHUD("right", "top", -12, 52, 1.0);
        self.hud_damage_value  = createStatLeftTextHUD("right", "top", -12, 68, 1.0);
    
        self thread cleanupHUDOnDisconnect();
    
        while(1)
        {
            // Salud
            if(isDefined(self.hud_health_value))
            {
                self.hud_health_value setText("" + self.health);
                color = (self.health <= 20) ? (1, 0.2, 0.2) : (0, 1, 0.4);
                self.hud_health_value.color = color;
                self.hud_health_label.color = color;
            }
    
            // Salto
            jumpVal = isDefined(self.jump_boost) ? self.jump_boost : 0;
            if(isDefined(self.hud_jump_value))
            {
                self.hud_jump_value setText("" + jumpVal);
                color = (jumpVal > 0) ? (0.3, 0.7, 1) : (0.7, 0.7, 0.7);
                self.hud_jump_value.color = color;
                self.hud_jump_label.color = color;
            }
    
            // Velocidad (formateado: 1.0 → "1.0")
            speedVal = isDefined(self.custom_speed) ? self.custom_speed : 1.0;
            if(isDefined(self.hud_speed_value))
            {
                self.hud_speed_value setText("" + speedVal);
                color = (speedVal > 1.0) ? (1, 0.8, 0.2) : (0.7, 0.7, 0.7);
                self.hud_speed_value.color = color;
                self.hud_speed_label.color = color;
            }
    
            // Daño
            dmgVal = isDefined(self.damage_multiplier) ? self.damage_multiplier : 1;
            if(isDefined(self.hud_damage_value))
            {
                self.hud_damage_value setText("" + dmgVal);
                color = (dmgVal > 1) ? (1, 0.4, 0.8) : (0.7, 0.7, 0.7);
                self.hud_damage_value.color = color;
                self.hud_damage_label.color = color;
            }
    
            wait 0.05;  // Más fluido
        }
    }
    
    // NUEVO: Helper para VALUES como TEXT (left-aligned)
    createStatLeftTextHUD(hAlign, vAlign, x, y, scale)
    {
        hud = NewHudElem();
        hud.horzAlign = hAlign;  // "right" (posición desde derecha)
        hud.vertAlign = vAlign;
        hud.alignX = "left";     // ← ¡IZQUIERDA! (texto crece a la derecha)
        hud.alignY = vAlign;
        hud.x = x;
        hud.y = y;
        hud.font = "default";
        hud.fontscale = scale;
        hud.alpha = 1;
        hud.sort = 10;
        return hud;
    }
    
    // Helper para label fijo (setText una vez)
    createStatLabelHUD(hAlign, vAlign, x, y, scale, text)
    {
        hud = NewHudElem();
        hud.horzAlign = hAlign;
        hud.vertAlign = vAlign;
        hud.alignX = hAlign;
        hud.alignY = vAlign;
        hud.x = x;
        hud.y = y;
        hud.font = "default";
        hud.fontscale = scale;
        hud.alpha = 1;
        hud.sort = 10;
        hud setText(text);  // Fijo, un solo configstring
        return hud;
    }
    
    // Destruir pares de HUD (label + value)
    destroyStatHUD(label, value)
    {
        if(isDefined(label)) label destroy();
        if(isDefined(value)) value destroy();
    }
    
    // Limpieza en disconnect (agrega en onPlayerSpawned(): self thread cleanupHUDOnDisconnect();)
    cleanupHUDOnDisconnect()
    {
        self waittill("disconnect");
        self destroyStatHUD(self.hud_health_label, self.hud_health_value);
        self destroyStatHUD(self.hud_jump_label, self.hud_jump_value);
        self destroyStatHUD(self.hud_speed_label, self.hud_speed_value);
        self destroyStatHUD(self.hud_damage_label, self.hud_damage_value);
    }
    
    // =====================================================
    // Monitor de chat
    // =====================================================
    
    chatMonitor()
    {
        level endon("game_ended");
        
        while(1)
        {
            level waittill("say", msg, player);
            cmd = tolower(msg);
    
            if (getsubstr(cmd, 0, 1) == "!")
            {
                cmd = getsubstr(cmd, 1);  // remove "!"
    
                if(cmd == "maxammo")
                {
                    player thread giveMaxAmmo(); // SOLO PARA ESE JUGADOR
                    player iPrintLnBold("^2¡Max Ammo!");
                }
                else if(cmd == "nuke")
                {
                    // Nuke es global (como en el juego original)
                    level thread spawnNuke();
                    iPrintLnBold("^2Nuke activada por ^1" + player.name);
                }
                else if(cmd == "zenkai")
                {
                    player.health = 20;
                }
                else if(cmd == "health")
                {
                    // Notificar
                    player iPrintLnBold("^2Salud maxima: ^7" + player.maxhealth);
                }
            }
            
            wait 0.1;
        }
    }
    
    // =====================================================
    // Max Ammo directo (sin power up)
    // =====================================================
    
    giveMaxAmmo()
    {
        self endon("disconnect");
        weapons = self GetWeaponsList();
        foreach(weapon in weapons)
        {
            self SetWeaponAmmoClip(weapon, WeaponClipSize(weapon));
            self SetWeaponAmmoStock(weapon, WeaponMaxAmmo(weapon));
        }
    }
    
    // =====================================================
    // Spawnear nuke
    // =====================================================
    
    spawnNuke()
    {
        players = get_players();
        if(players.size)
        {
            origin = players[randomInt(players.size)].origin;
            level specific_powerup_drop("nuke", origin);
        }
    }
    
    // =====================================================
    // Monitero de drops de Max Ammo
    // =====================================================
    
    calculate_total_ammo(player)
    {
        weapons = player GetWeaponsList();
        total = 0;
        foreach(weapon in weapons)
        {
            total += player GetWeaponAmmoClip(weapon) + player GetWeaponAmmoStock(weapon);
        }
        return total;
    }
    
    calculate_total_max(player)
    {
        weapons = player GetWeaponsList();
        total = 0;
        foreach(weapon in weapons)
        {
            total += WeaponClipSize(weapon) + WeaponMaxAmmo(weapon);
        }
        return total;
    }
    
    zombieMaxAmmoMonitor()
    {
        level endon("game_ended");
    
        prev_count = 0;
    
        level.forced_max_ammo = false; // bandera global: ¿alguien se quedó sin balas?
        
        while(1)
        {
            players = get_players();
            curr_count = GetAiArray("axis").size;
            
            // Detectar si algún jugador se quedó sin munición
            foreach(player in players)
            {
                if(!isDefined(player.prev_ammo))
                    player.prev_ammo = calculate_total_ammo(player);
                
                current_ammo = calculate_total_ammo(player);
                
                if(current_ammo == 0 && player.prev_ammo > 0)
                {
                    level.forced_max_ammo = true;
                }
                
                player.prev_ammo = current_ammo;
            }
            
            // Al morir un zombie
            if(curr_count < prev_count)
            {
                min_perc = 1.0;
                foreach(player in players)
                {
                    total_left = calculate_total_ammo(player);
                    total_max = calculate_total_max(player);
                    
                    if(total_max > 0)
                    {
                        perc = total_left / total_max;
                        if(perc < min_perc) min_perc = perc;
                    }
                }
                
                drop = false;
                
                if(level.forced_max_ammo)
                {
                    drop = true;
                    level.forced_max_ammo = false;
                }
                else
                {
                    max_desp = 1.0 - min_perc;
                    chance = int(100 * (max_desp * max_desp));
                    if(randomInt(100) < chance)
                        drop = true;
                }
                
                if(drop && players.size)
                {
                    player = players[randomInt(players.size)];
                    drop_origin = player.origin + (randomIntRange(-120,120), randomIntRange(-120,120), 50);
                    trace = bulletTrace(drop_origin + (0,0,100), drop_origin + (0,0,-400), 0, player);
                    level thread specific_powerup_drop("full_ammo", trace["position"]);
    
                    iPrintLnBold("^3Max ammo dropeado: ^7" + int(chance) + " probabilidad");
                }
            }
            
            prev_count = curr_count;
    
            wait 0.1;
        }
    }   
    

    The code is a mess. Sorry for mix English and Spanish but English is not my first language.

    Credits to https://forum.plutonium.pw/topic/32538/release-zm-black-ops-2-custom-perks this post. It give me the respective functions for damage manage.

    It can be played in solo too, it's fun. I hope someone enjoy this mod like i did making it. 😁

    BO2 Modding Releases & Resources
  • 1 / 1
  • Login

  • Don't have an account? Register

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