Creating a Buyable Last Acquired Perk System (Nuketown-Style)
-
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!
-
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 perkSo the “machine” is really just:
a trigger
a model / fx / hint string
logic that reads a stored perk name
Best structure- 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.
- 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 codeThis 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 behaviorSo 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 arrayIf 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.
- 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 limitIf 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 amountMatching 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 itSo 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 guessThis is very doable.
The hardest part is usually finding the right stock BO2 perk functions to call, not the trigger itself. -
im not sure if this what you want
-
im not sure if this what you want
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.
-
are you trying to do this for all the maps or just 1???
-
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 startstation_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 anywhereThe 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.
-
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 startstation_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 anywhereThe 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.
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.
-
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.
Blxck.Out Dude I think I know who you are!
-
Blxck.Out did you add me on discord???
-
Blxck.Out did you add me on discord???
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? -
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?AndreTOQU3
yes but there already 1 made i don't see the point of making 1
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