Skip to content
  • 0 Unread 0
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
Collapse

Plutonium

  1. Home
  2. BO2 Modding Support & Discussion
  3. Creating a Buyable Last Acquired Perk System (Nuketown-Style)

Creating a Buyable Last Acquired Perk System (Nuketown-Style)

Scheduled Pinned Locked Moved BO2 Modding Support & Discussion
11 Posts 4 Posters 236 Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • unknowghostundefined Offline
    unknowghostundefined Offline
    unknowghost
    Contributor
    wrote last edited by
    #2

    Basic idea

    When a player buys a perk anywhere on the map:

    store that perk name on the player
    example: player.last_bought_perk = "juggernog";

    Then your custom buyable spot does this:

    player uses trigger
    script checks player.last_bought_perk
    if it exists, and they don’t already have it, and they have enough points:
    charge points
    give that perk

    So the “machine” is really just:

    a trigger
    a model / fx / hint string
    logic that reads a stored perk name
    Best structure

    1. Track the last perk the player bought

    Somewhere in your perk purchase success flow, add something like:

    player.last_bought_perk = perk_name;

    Important: do this after the purchase succeeds, not before.

    1. Spawn a custom trigger anywhere

    Use a trigger_use at any origin you want.

    Something like:

    spawn_custom_perk_trigger(origin, angles)
    {
    trig = spawn("trigger_use", origin, 0, 50, 70);
    trig setCursorHint("HINT_NOICON");
    trig setHintString("Press &&1 to buy your last perk");
    trig.angles = angles;

    trig thread custom_perk_trigger_think();
    return trig;
    

    }

    Then in the think loop:

    custom_perk_trigger_think()
    {
    self endon("death");

    for(;;)
    {
        self waittill("trigger", player);
    
        if (!isPlayer(player))
            continue;
    
        perk = player.last_bought_perk;
    
        if (!isDefined(perk))
        {
            player iprintlnbold("No stored perk yet.");
            continue;
        }
    
        if (player_has_perk(player, perk))
        {
            player iprintlnbold("You already have " + perk);
            continue;
        }
    
        cost = get_perk_cost(perk);
    
        if (player.score < cost)
        {
            player iprintlnbold("Not enough points.");
            continue;
        }
    
        player.score -= cost;
        give_player_perk(player, perk);
        player iprintlnbold("Bought " + perk);
    }
    

    }
    3. Reuse existing perk code

    This part matters most.

    Do not manually fake every perk if the game already has perk-grant code.
    Try to reuse BO2’s normal perk functions, because those usually handle:

    icons
    perk flags
    HUD updates
    limit checks
    revive/downed logic
    special-case behavior

    So your custom code should mostly decide:

    what perk
    where the buyable is
    when to call the real give-perk function
    4. Store locations in an array

    If you want place-anywhere support, define locations like:

    level.custom_perk_spots = [];
    level.custom_perk_spots[0] = (100, 200, 20);
    level.custom_perk_spots[1] = (300, 150, 20);
    level.custom_perk_spots[2] = (-500, 80, 10);

    Then loop them on init:

    init_custom_perk_spots()
    {
    for (i = 0; i < level.custom_perk_spots.size; i++)
    {
    spawn_custom_perk_trigger(level.custom_perk_spots[i], (0,0,0));
    }
    }

    An even nicer way is to place script_origin / script_model entities in Radiant and scan for them by targetname.

    1. Use per-player storage, not global

    This should almost definitely be:

    player.last_bought_perk

    and not:

    level.last_bought_perk

    because each player should have their own last perk.

    Things to watch out for
    Perk limit

    If BO2 still has a perk cap in your setup, your custom trigger should respect it unless you want otherwise.

    Duplicate perks

    Do not let the player buy a perk they already own.

    Lost perks / downing

    Decide what should happen after down/revive:

    keep stored last perk?
    clear it?
    update it only on successful purchase?

    Usually keeping the stored value is fine.

    Cost

    Decide whether:

    cost should match the actual perk
    or this custom buyable always costs one fixed amount

    Matching the actual perk is usually better.

    Mule Kick / special perks

    Some perks can be messy because they touch weapons/inventory behavior. Reusing stock perk code helps a lot here.

    Simplest mental model

    Think of it like this:

    normal perk machine = decides a fixed perk, then gives it
    your custom trigger = decides perk from player.last_bought_perk, then gives it

    So the only new part is the selection logic.

    Very small example flow
    on_perk_bought(player, perk)
    {
    player.last_bought_perk = perk;
    }

    custom_buy_use(player)
    {
    perk = player.last_bought_perk;

    if (!isDefined(perk))
        return;
    
    if (player_has_perk(player, perk))
        return;
    
    if (!player_can_buy_perk(player, perk))
        return;
    
    take_points(player, get_perk_cost(perk));
    give_player_perk(player, perk);
    

    }
    My honest guess

    This is very doable.
    The hardest part is usually finding the right stock BO2 perk functions to call, not the trigger itself.

    1 Reply Last reply
    0
    • unknowghostundefined Offline
      unknowghostundefined Offline
      unknowghost
      Contributor
      wrote last edited by
      #3

      im not sure if this what you want

      Blxck.Outundefined 1 Reply Last reply
      0
      • unknowghostundefined unknowghost

        im not sure if this what you want

        Blxck.Outundefined Offline
        Blxck.Outundefined Offline
        Blxck.Out
        wrote last edited by
        #4

        unknowghost Sorry! I should’ve clarified, I was referring to Power-ups (Instakill, Max Ammo, etc.).

        What I’m basically trying to accomplish is creating a static model with a buyable script tied to it, where players can purchase the last power-up they picked up. The static model would inherit whatever that last power-up was, which of course means it would also need a default power-up on game start.

        I tried joining your discord server, however it seems all links related to it are dead.

        1 Reply Last reply
        0
        • unknowghostundefined Offline
          unknowghostundefined Offline
          unknowghost
          Contributor
          wrote last edited by
          #5

          are you trying to do this for all the maps or just 1???

          1 Reply Last reply
          0
          • unknowghostundefined Offline
            unknowghostundefined Offline
            unknowghost
            Contributor
            wrote last edited by
            #6

            also here something that might help so here
            Use it like this:

            call init_last_powerup_station(); on map init
            when a power-up is successfully picked up, call last_powerup_station_set(powerup_name);

            The logic is complete. The only names you may need to swap are the stock BO2 score/power-up function names, since those can differ by base.

            // ======================================================
            // LAST PICKED POWER-UP BUY STATION (BO2 / GSC)
            // ======================================================

            init_last_powerup_station()
            {
            level.last_powerup_station_powerup = "double_points"; // default on game start

            station_origin = (0, 0, 0);     // CHANGE THIS
            station_angles = (0, 0, 0);     // CHANGE THIS
            
            // Optional model
            level.last_powerup_station_model = spawn("script_model", station_origin);
            level.last_powerup_station_model.angles = station_angles;
            level.last_powerup_station_model setModel("tag_origin"); // replace with your model if wanted
            
            // Use trigger
            level.last_powerup_station_trigger = spawn("trigger_use", station_origin, 0, 64, 72);
            level.last_powerup_station_trigger.angles = station_angles;
            level.last_powerup_station_trigger setCursorHint("HINT_NOICON");
            level.last_powerup_station_trigger thread last_powerup_station_think();
            
            update_last_powerup_station();
            

            }

            // Call this from your power-up pickup code after the pickup succeeds
            last_powerup_station_set(powerup_name)
            {
            if (!isDefined(powerup_name) || powerup_name == "")
            return;

            level.last_powerup_station_powerup = powerup_name;
            update_last_powerup_station();
            

            }

            update_last_powerup_station()
            {
            if (!isDefined(level.last_powerup_station_trigger))
            return;

            powerup = level.last_powerup_station_powerup;
            
            hint = "Press &&1 to buy " + get_powerup_display_name(powerup);
            level.last_powerup_station_trigger setHintString(hint);
            
            // Optional:
            // If you have custom icon models/shaders, update them here
            // based on "powerup".
            

            }

            last_powerup_station_think()
            {
            self endon("death");

            for (;;)
            {
                self waittill("trigger", player);
            
                if (!isDefined(player))
                    continue;
            
                powerup = level.last_powerup_station_powerup;
            
                if (!can_buy_station_powerup(player, powerup))
                    continue;
            
                cost = get_powerup_cost(powerup);
                take_station_points(player, cost);
                activate_station_powerup(powerup, player);
            
                player iprintlnbold("Bought " + get_powerup_display_name(powerup));
            }
            

            }

            can_buy_station_powerup(player, powerup)
            {
            if (!isDefined(powerup) || powerup == "")
            {
            player iprintlnbold("No power-up stored.");
            return false;
            }

            cost = get_powerup_cost(powerup);
            
            if (player.score < cost)
            {
                player iprintlnbold("Need " + cost + " points.");
                return false;
            }
            
            return true;
            

            }

            take_station_points(player, cost)
            {
            // Replace with your map's real BO2 score remove function if needed
            player.score -= cost;
            }

            get_powerup_cost(powerup)
            {
            switch (powerup)
            {
            case "instakill":
            return 2000;

                case "double_points":
                    return 2000;
            
                case "max_ammo":
                    return 2500;
            
                case "carpenter":
                    return 1500;
            
                case "nuke":
                    return 3000;
            
                case "fire_sale":
                    return 2000;
            }
            
            return 2000;
            

            }

            get_powerup_display_name(powerup)
            {
            switch (powerup)
            {
            case "instakill":
            return "Insta-Kill";

                case "double_points":
                    return "Double Points";
            
                case "max_ammo":
                    return "Max Ammo";
            
                case "carpenter":
                    return "Carpenter";
            
                case "nuke":
                    return "Nuke";
            
                case "fire_sale":
                    return "Fire Sale";
            }
            
            return powerup;
            

            }

            activate_station_powerup(powerup, player)
            {
            // Keep this as a dispatcher.
            // Replace each case with your BO2 stock power-up call.

            switch (powerup)
            {
                case "instakill":
                    station_do_instakill(player);
                    break;
            
                case "double_points":
                    station_do_double_points(player);
                    break;
            
                case "max_ammo":
                    station_do_max_ammo(player);
                    break;
            
                case "carpenter":
                    station_do_carpenter(player);
                    break;
            
                case "nuke":
                    station_do_nuke(player);
                    break;
            
                case "fire_sale":
                    station_do_fire_sale(player);
                    break;
            }
            

            }

            // ======================================================
            // WRAPPERS - replace internals with your BO2 stock calls
            // ======================================================

            station_do_instakill(player)
            {
            // replace with BO2 stock Insta-Kill activation
            level notify("station_instakill");
            }

            station_do_double_points(player)
            {
            // replace with BO2 stock Double Points activation
            level notify("station_double_points");
            }

            station_do_max_ammo(player)
            {
            // replace with BO2 stock Max Ammo activation
            level notify("station_max_ammo");
            }

            station_do_carpenter(player)
            {
            // replace with BO2 stock Carpenter activation
            level notify("station_carpenter");
            }

            station_do_nuke(player)
            {
            // replace with BO2 stock Nuke activation
            level notify("station_nuke");
            }

            station_do_fire_sale(player)
            {
            // replace with BO2 stock Fire Sale activation
            level notify("station_fire_sale");
            }

            And this is the hook you add where a power-up gets collected:

            last_powerup_station_set(powerup_name);

            Example:

            // after player picks up Insta-Kill successfully
            last_powerup_station_set("instakill");

            So the whole system is:

            default power-up on start
            updates whenever a drop is picked up
            station always sells the latest stored drop
            cost is per power-up
            trigger can be placed anywhere

            The only part you still need to wire into your exact BO2 base is the inside of:

            station_do_instakill()
            station_do_double_points()
            station_do_max_ammo()
            station_do_carpenter()
            station_do_nuke()
            station_do_fire_sale()

            because those exact stock BO2 function names vary.

            Blxck.Outundefined 1 Reply Last reply
            1
            • unknowghostundefined unknowghost

              also here something that might help so here
              Use it like this:

              call init_last_powerup_station(); on map init
              when a power-up is successfully picked up, call last_powerup_station_set(powerup_name);

              The logic is complete. The only names you may need to swap are the stock BO2 score/power-up function names, since those can differ by base.

              // ======================================================
              // LAST PICKED POWER-UP BUY STATION (BO2 / GSC)
              // ======================================================

              init_last_powerup_station()
              {
              level.last_powerup_station_powerup = "double_points"; // default on game start

              station_origin = (0, 0, 0);     // CHANGE THIS
              station_angles = (0, 0, 0);     // CHANGE THIS
              
              // Optional model
              level.last_powerup_station_model = spawn("script_model", station_origin);
              level.last_powerup_station_model.angles = station_angles;
              level.last_powerup_station_model setModel("tag_origin"); // replace with your model if wanted
              
              // Use trigger
              level.last_powerup_station_trigger = spawn("trigger_use", station_origin, 0, 64, 72);
              level.last_powerup_station_trigger.angles = station_angles;
              level.last_powerup_station_trigger setCursorHint("HINT_NOICON");
              level.last_powerup_station_trigger thread last_powerup_station_think();
              
              update_last_powerup_station();
              

              }

              // Call this from your power-up pickup code after the pickup succeeds
              last_powerup_station_set(powerup_name)
              {
              if (!isDefined(powerup_name) || powerup_name == "")
              return;

              level.last_powerup_station_powerup = powerup_name;
              update_last_powerup_station();
              

              }

              update_last_powerup_station()
              {
              if (!isDefined(level.last_powerup_station_trigger))
              return;

              powerup = level.last_powerup_station_powerup;
              
              hint = "Press &&1 to buy " + get_powerup_display_name(powerup);
              level.last_powerup_station_trigger setHintString(hint);
              
              // Optional:
              // If you have custom icon models/shaders, update them here
              // based on "powerup".
              

              }

              last_powerup_station_think()
              {
              self endon("death");

              for (;;)
              {
                  self waittill("trigger", player);
              
                  if (!isDefined(player))
                      continue;
              
                  powerup = level.last_powerup_station_powerup;
              
                  if (!can_buy_station_powerup(player, powerup))
                      continue;
              
                  cost = get_powerup_cost(powerup);
                  take_station_points(player, cost);
                  activate_station_powerup(powerup, player);
              
                  player iprintlnbold("Bought " + get_powerup_display_name(powerup));
              }
              

              }

              can_buy_station_powerup(player, powerup)
              {
              if (!isDefined(powerup) || powerup == "")
              {
              player iprintlnbold("No power-up stored.");
              return false;
              }

              cost = get_powerup_cost(powerup);
              
              if (player.score < cost)
              {
                  player iprintlnbold("Need " + cost + " points.");
                  return false;
              }
              
              return true;
              

              }

              take_station_points(player, cost)
              {
              // Replace with your map's real BO2 score remove function if needed
              player.score -= cost;
              }

              get_powerup_cost(powerup)
              {
              switch (powerup)
              {
              case "instakill":
              return 2000;

                  case "double_points":
                      return 2000;
              
                  case "max_ammo":
                      return 2500;
              
                  case "carpenter":
                      return 1500;
              
                  case "nuke":
                      return 3000;
              
                  case "fire_sale":
                      return 2000;
              }
              
              return 2000;
              

              }

              get_powerup_display_name(powerup)
              {
              switch (powerup)
              {
              case "instakill":
              return "Insta-Kill";

                  case "double_points":
                      return "Double Points";
              
                  case "max_ammo":
                      return "Max Ammo";
              
                  case "carpenter":
                      return "Carpenter";
              
                  case "nuke":
                      return "Nuke";
              
                  case "fire_sale":
                      return "Fire Sale";
              }
              
              return powerup;
              

              }

              activate_station_powerup(powerup, player)
              {
              // Keep this as a dispatcher.
              // Replace each case with your BO2 stock power-up call.

              switch (powerup)
              {
                  case "instakill":
                      station_do_instakill(player);
                      break;
              
                  case "double_points":
                      station_do_double_points(player);
                      break;
              
                  case "max_ammo":
                      station_do_max_ammo(player);
                      break;
              
                  case "carpenter":
                      station_do_carpenter(player);
                      break;
              
                  case "nuke":
                      station_do_nuke(player);
                      break;
              
                  case "fire_sale":
                      station_do_fire_sale(player);
                      break;
              }
              

              }

              // ======================================================
              // WRAPPERS - replace internals with your BO2 stock calls
              // ======================================================

              station_do_instakill(player)
              {
              // replace with BO2 stock Insta-Kill activation
              level notify("station_instakill");
              }

              station_do_double_points(player)
              {
              // replace with BO2 stock Double Points activation
              level notify("station_double_points");
              }

              station_do_max_ammo(player)
              {
              // replace with BO2 stock Max Ammo activation
              level notify("station_max_ammo");
              }

              station_do_carpenter(player)
              {
              // replace with BO2 stock Carpenter activation
              level notify("station_carpenter");
              }

              station_do_nuke(player)
              {
              // replace with BO2 stock Nuke activation
              level notify("station_nuke");
              }

              station_do_fire_sale(player)
              {
              // replace with BO2 stock Fire Sale activation
              level notify("station_fire_sale");
              }

              And this is the hook you add where a power-up gets collected:

              last_powerup_station_set(powerup_name);

              Example:

              // after player picks up Insta-Kill successfully
              last_powerup_station_set("instakill");

              So the whole system is:

              default power-up on start
              updates whenever a drop is picked up
              station always sells the latest stored drop
              cost is per power-up
              trigger can be placed anywhere

              The only part you still need to wire into your exact BO2 base is the inside of:

              station_do_instakill()
              station_do_double_points()
              station_do_max_ammo()
              station_do_carpenter()
              station_do_nuke()
              station_do_fire_sale()

              because those exact stock BO2 function names vary.

              Blxck.Outundefined Offline
              Blxck.Outundefined Offline
              Blxck.Out
              wrote last edited by
              #7

              unknowghost Thanks! This is exactly what I was looking for. I just tested it in-game, and everything seems to be working properly except for the trigger, I can’t seem to find it.

              Combat Medicundefined 1 Reply Last reply
              0
              • Blxck.Outundefined Blxck.Out

                unknowghost Thanks! This is exactly what I was looking for. I just tested it in-game, and everything seems to be working properly except for the trigger, I can’t seem to find it.

                Combat Medicundefined Offline
                Combat Medicundefined Offline
                Combat Medic
                wrote last edited by
                #8

                Blxck.Out Dude I think I know who you are!

                1 Reply Last reply
                0
                • unknowghostundefined Offline
                  unknowghostundefined Offline
                  unknowghost
                  Contributor
                  wrote last edited by
                  #9

                  Blxck.Out did you add me on discord???

                  AndreTOQU3undefined 1 Reply Last reply
                  0
                  • unknowghostundefined unknowghost

                    Blxck.Out did you add me on discord???

                    AndreTOQU3undefined Offline
                    AndreTOQU3undefined Offline
                    AndreTOQU3
                    wrote last edited by
                    #10

                    unknowghost
                    Could you create a script where it would be possible to buy the same perk twice, but receive a different perk the second time?

                    unknowghostundefined 1 Reply Last reply
                    0
                    • AndreTOQU3undefined AndreTOQU3

                      unknowghost
                      Could you create a script where it would be possible to buy the same perk twice, but receive a different perk the second time?

                      unknowghostundefined Offline
                      unknowghostundefined Offline
                      unknowghost
                      Contributor
                      wrote last edited by
                      #11

                      AndreTOQU3
                      yes but there already 1 made i don't see the point of making 1

                      1 Reply Last reply
                      0

                      Hello! It looks like you're interested in this conversation, but you don't have an account yet.

                      Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

                      With your input, this post could be even better 💗

                      Register Login
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      • Login

                      • Don't have an account? Register

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