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 234 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.
  • Blxck.Outundefined Offline
    Blxck.Outundefined Offline
    Blxck.Out
    wrote last edited by
    #1

    Hi everyone,

    I’m fairly new to writing custom scripts for BO2 and was hoping to get some input. I’m trying to create a system that allows players to purchase a perk in a specific location, where the perk offered is the last one they previously acquired, similar to how it works in Nuketown. Ideally, I’d also like to be able to place this buyable anywhere using position data.

    If anyone could point me in the right direction or share examples of how this might be implemented, I’d really appreciate it. Thanks!

    1 Reply Last reply
    1
    • 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