Skip to content

Commit

Permalink
Back In Black (Market) - Black Market Dead Drops and Stock Cycling (#…
Browse files Browse the repository at this point in the history
…3249)

<!-- Write **BELOW** The Headers and **ABOVE** The comments else it may
not be viewable. -->
<!-- You can view Contributing.MD for a detailed description of the pull
request process. -->

## About The Pull Request

<!-- Describe The Pull Request. Please be sure every change is
documented or this can delay review and even discourage maintainers from
merging your PR! -->

### The Catalogue
- The Black Market's catalogue now refreshes every hour with new
choices. The stock for individual entries will not refresh however if
bought. Check in every now and then!
-  Adds the tech and ammo tab
- Entries can be set to have weighting in order to be more or less
likely to appear. Items that recently appeared will be less likely to
show up again, and vice-versa for items that haven't. Particularly rare
or powerful items are exempted from weighting to stop them showing up
too often.
- Kills some items, adds some new items and adjusts some prices and
percentages.
- All blackmarket items are added to the market on generation, and
unavailable items are hidden.
- Paired items are now handled by a list so items can have multiple
paired items.

### Items
- Reflavours the ethereal disco grenade and makes it work on elzu. 
- Makes the powerfist actually work again. The gasused datum removed
itself before it could do the pressure checks.
- Adds a var (show_rigged) to power cells to whether they display
they're going to explode or not. This is a surprise tool that will hurt
you later.

### Delivery Changes
- Adds a new delivery method, Dead drops. The black market will drop off
your package somewhere near the ruin on the planet you're on. If there
isn't a ruin, or a viable spot to land, it'll send it somewhere random
and it's up to you to find it. A generally consistent way to get your
packages
- Makes launch more reliable, and your orders will no longer bounce off
your ship back into the void.
- The LTSRBT has been removed from the outpost market. The board lives
in the Black Market as an occasional spawn in the tech category, or can
be crafted with 2 BS crystals, a bank card, 5 duct tape, a circuit board
and a network card. The cost for bluespace shipping is now 100 credits
up from 50.

### Mechanical and Code Stuff
- Dynamic Encounters keep track of what map templates/ruins were spawned
in them in a list. Used for Dead dead drops so they can calculate a
landing spot, and should hopefully be useful in the future if we need to
get info about the ruins for whatever reason.
- adds get_block_portion and get_position_in_margin to mapzones.dm
- Makes the black market UI a bit wider so all the delivery options fit
on the menu nicely
- adds a parameter for get_overmap_object_by_locatiion to check for the
planet you're on exclusively rather than the ship


## Why It's Good For The Game

<!-- Please add a short description of why you think these changes would
benefit the game. If you can't justify it in words, it might not be
worth adding. -->
The main intent of the PR was to mitigate the reliance of the LTRSBT as
a medium to effectively interact with the black market and was just a
1000 credit buy in fee effectively. It wasn't helped by the Launch was
unreliable to the point of being useless, and it feels really bad to
make a 10k purchase just to turn up empty handed cause it bounced off
your ship by a trajectory out of your control.

Having other viable methods of interacting with the black market should
hopefully mitigate the issue. Not to mention it felt a bit weird in
retrospect you could buy the Super Spooky Illegal Machine at the
outpost. It also doesn't pigeonhole you into asking your captain for an
LTSRBT if you want to smuggle in gear .

The Black Market stock cycling was something that seemed like people
wanted, so it here it is. Weighting also adds a bit more fine control on
what appears.

Rylie asked me to reflavour the disco grenade, and I thought it'd be
funny so here it is too.

## Changelog

:cl:
add: Black Market Stock Cycling and item weighting
add: New black market stock
add: Tech and Ammo tab
add: Dead Drops
add: LTRSBT moved to the Black Market Catalogue
add: LTSRBT Crafting Recipe, 2 BS crystals, a bank card, 5 duct tape, a
circuit board and a network card
add: Reflavours the disco grenade
add: variable for powercells to show if they're rigged
del: Some old blackmarket stock
balance: LTRSBT shipping cost up to 100 credits
balance: Launch delivery more reliable
fix: Powerfist works again
spellcheck: fixed a few typos in the black market
code: Dynamic Overmap encounters store what ruins were spawned
code: get_block_portion and get_position_in_margin methods in
mapzones.dm
code: Pair items now handled by a list
refactor: Black Market item stocking
/:cl:

<!-- Both :cl:'s are required for the changelog to work! You can put
your name to the right of the first :cl: if you want to overwrite your
GitHub username as author ingame. -->
<!-- You can use multiple of the same prefix (they're only used for the
icon ingame) and delete the unneeded ones. Despite some of the tags,
changelogs should generally represent how a player might be affected by
the changes rather than a summary of the PR's contents. -->

---------

Signed-off-by: Gristlebee <[email protected]>
Co-authored-by: Theos <[email protected]>
  • Loading branch information
Gristlebee and SomeguyManperson authored Aug 28, 2024
1 parent 73ed611 commit 0edc3ea
Show file tree
Hide file tree
Showing 26 changed files with 1,124 additions and 303 deletions.
2 changes: 2 additions & 0 deletions code/__DEFINES/blackmarket.dm
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@
#define SHIPPING_METHOD_LTSRBT "LTSRBT"
// Throws the item from somewhere at the uplink.
#define SHIPPING_METHOD_LAUNCH "Launch"
// Drops the item somewhere on the map
#define SHIPPING_METHOD_DEAD_DROP "Dead drop"

68 changes: 64 additions & 4 deletions code/controllers/subsystem/blackmarket.dm
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ SUBSYSTEM_DEF(blackmarket)
/// Descriptions for each shipping methods.
var/shipping_method_descriptions = list(
SHIPPING_METHOD_LAUNCH="Launches the item at your coordinates from across deep space. Cheap, but you might not recieve your item at all. We recommend being stationary in space, away from any large structures, for best results.",
SHIPPING_METHOD_LTSRBT="Long-To-Short-Range-Bluespace-Transceiver, a machine that prepares items at a remote storage location and then teleports them to the location of the LTRSBT."
SHIPPING_METHOD_DEAD_DROP="Our couriers will fire your item via orbital drop pod at the nearest safe abandoned structure for discreet pick up. Reliable, but you'll have to find your package yourself. We accept no responsibility for lost packages if you try to do this in empty space or the outpost.",
SHIPPING_METHOD_LTSRBT="Long-To-Short-Range-Bluespace-Transceiver, a machine that prepares items at a remote storage location and then teleports them to the location of the LTRSBT. Secure, quick and reliable, though it ain't cheap to do."
)

/// List of all existing markets.
Expand All @@ -32,6 +33,9 @@ SUBSYSTEM_DEF(blackmarket)
markets[M].add_item(item, FALSE)

qdel(I)
for(var/market in markets)
var/datum/blackmarket_market/market_to_cycle = markets[market]
market_to_cycle.cycle_stock()
. = ..()

/datum/controller/subsystem/blackmarket/fire(resumed)
Expand Down Expand Up @@ -62,16 +66,72 @@ SUBSYSTEM_DEF(blackmarket)
var/startSide = pick(GLOB.cardinals)
var/turf/T = get_turf(purchase.uplink)
var/datum/virtual_level/vlevel = T.get_virtual_level()
var/pickedloc = vlevel.get_side_turf(startSide)
var/turf/pickedloc

switch(startSide)
if(NORTH)
pickedloc = locate(T.x, (vlevel.high_y - vlevel.reserved_margin),T.z)
if(EAST)
pickedloc = locate((vlevel.high_x - vlevel.reserved_margin), T.y ,T.z)
if(SOUTH)
pickedloc = locate(T.x, (vlevel.low_y + vlevel.reserved_margin),T.z)
if(WEST)
pickedloc = locate((vlevel.low_x + vlevel.reserved_margin), T.y ,T.z)
else
pickedloc = vlevel.get_side_turf(startSide)

var/atom/movable/item = purchase.entry.spawn_item(pickedloc)
item.safe_throw_at(purchase.uplink, 3, 3, spin = FALSE)

item.Move(get_step(pickedloc,get_dir(pickedloc,T)))
to_chat(recursive_loc_check(purchase.uplink.loc, /mob), "<span class='notice'>[purchase.uplink] flashes a message noting the order is being launched at your coordinates from [dir2text(startSide)].</span>")

queued_purchases -= purchase
qdel(purchase)
// Drop the order somewhere with the bounds of overmap encounter's ruin
if(SHIPPING_METHOD_DEAD_DROP)
var/datum/overmap/dynamic/overmap_loc = SSovermap.get_overmap_object_by_location(purchase.uplink, TRUE)
var/datum/virtual_level/zlevel = purchase.uplink.get_virtual_level()
var/turf/landing_turf
var/datum/map_template/ruin
if(!isnull(overmap_loc))
for(var/possible_ruin in overmap_loc.ruin_turfs)
var/turf/lowerbound = overmap_loc.ruin_turfs[possible_ruin]
ruin = overmap_loc.spawned_ruins[possible_ruin]
var/list/possible_ruin_turfs = zlevel.get_block_portion(lowerbound.x,lowerbound.y,(lowerbound.x + ruin.width),(lowerbound.y + ruin.height))
for(var/cycle in 1 to length(possible_ruin_turfs))
var/potential_turf = pick_n_take(possible_ruin_turfs)
if(!isopenturf(potential_turf))
continue
var/turf/open/potential_open_turf = potential_turf
if(ischasm(potential_open_turf))
continue
if(islava(potential_open_turf))
var/turf/open/lava/potential_lava_floor = potential_open_turf
if(!potential_lava_floor.is_safe())
continue
if(istype(potential_open_turf, /turf/open/water/acid))
var/turf/open/water/acid/potential_acid_floor = potential_open_turf
if(!potential_acid_floor.is_safe_to_cross())
continue
if(potential_open_turf.is_blocked_turf())
continue

//yippee, there's a viable turf for the package to land on
landing_turf = potential_open_turf
to_chat(recursive_loc_check(purchase.uplink.loc, /mob),"<span class='notice'>[purchase.uplink] flashes a message noting the order is being launched at a structure in your local area.</span>")
break

if(!landing_turf)
landing_turf = zlevel.get_random_position_in_margin()
to_chat(recursive_loc_check(purchase.uplink.loc, /mob), "<span class='notice'>[purchase.uplink] flashes a message that the pod was unable to reach it's designated landing spot, and has landed somewhere in the local area instead.</span>")

var/obj/structure/closet/supplypod/pod = new()
pod.setStyle(STYLE_BOX)
purchase.entry.spawn_item(pod)
pod.explosionSize = list(0,0,0,1)
new /obj/effect/pod_landingzone(landing_turf, pod)

queued_purchases -= purchase
qdel(purchase)
if(MC_TICK_CHECK)
break

Expand Down
8 changes: 5 additions & 3 deletions code/controllers/subsystem/overmap.dm
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ SUBSYSTEM_DEF(overmap)
mapgen.generate_turfs(vlevel.get_unreserved_block())

var/list/ruin_turfs = list()
var/list/ruin_templates = list()
if(used_ruin)
var/turf/ruin_turf = locate(
rand(
Expand All @@ -302,6 +303,7 @@ SUBSYSTEM_DEF(overmap)
)
used_ruin.load(ruin_turf)
ruin_turfs[used_ruin.name] = ruin_turf
ruin_templates[used_ruin.name] = used_ruin

// fill in the turfs, AFTER generating the ruin. this prevents them from generating within the ruin
// and ALSO prevents the ruin from being spaced when it spawns in
Expand Down Expand Up @@ -376,7 +378,7 @@ SUBSYSTEM_DEF(overmap)
quaternary_dock.dwidth = 0
docking_ports += quaternary_dock

return list(mapzone, docking_ports, ruin_turfs)
return list(mapzone, docking_ports, ruin_turfs, ruin_templates)

/**
* Returns a random, usually empty turf in the overmap
Expand Down Expand Up @@ -418,10 +420,10 @@ SUBSYSTEM_DEF(overmap)
* Gets the parent overmap object (e.g. the planet the atom is on) for a given atom.
* * source - The object you want to get the corresponding parent overmap object for.
*/
/datum/controller/subsystem/overmap/proc/get_overmap_object_by_location(atom/source)
/datum/controller/subsystem/overmap/proc/get_overmap_object_by_location(atom/source, exclude_ship = FALSE)
var/turf/T = get_turf(source)
var/area/ship/A = get_area(source)
while(istype(A) && A.mobile_port)
while(istype(A) && A.mobile_port && !exclude_ship)
if(A.mobile_port.current_ship)
return A.mobile_port.current_ship
A = A.mobile_port.underlying_turf_area[T]
Expand Down
6 changes: 6 additions & 0 deletions code/datums/map_zones.dm
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,9 @@
/datum/virtual_level/proc/get_block()
return block(locate(low_x,low_y,z_value), locate(high_x,high_y,z_value))

/datum/virtual_level/proc/get_block_portion(lower_x, lower_y, higher_x, higher_y)
return block(locate(lower_x,lower_y,z_value), locate(higher_x,higher_y,z_value))

/datum/virtual_level/proc/get_unreserved_block()
return block(locate(low_x + reserved_margin, low_y + reserved_margin, z_value), locate(high_x - reserved_margin,high_y - reserved_margin,z_value))

Expand All @@ -542,6 +545,9 @@
/datum/virtual_level/proc/get_random_position()
return locate(rand(low_x, high_x), rand(low_y, high_y), z_value)

/datum/virtual_level/proc/get_random_position_in_margin()
return locate(rand(low_x + reserved_margin, high_x - reserved_margin), rand(low_y + reserved_margin, high_y - reserved_margin), z_value)

/datum/virtual_level/proc/get_below_turf(turf/Turf)
if(!down_linkage)
return
Expand Down
16 changes: 8 additions & 8 deletions code/game/objects/items/etherealdiscoball.dm
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
/obj/item/etherealballdeployer
name = "Portable Ethereal Disco Ball"
desc = "Press the button for a deployment of slightly-unethical PARTY!"
name = "Portable Animatronic Disco Ball"
desc = "Press the button for a deployment of a copyright free PARTY!"
icon = 'icons/obj/device.dmi'
icon_state = "ethdisco"

/obj/item/etherealballdeployer/attack_self(mob/living/carbon/user)
.=..()
to_chat(user, "<span class='notice'>You deploy the Ethereal Disco Ball.</span>")
to_chat(user, span_notice("You deploy the Ethereal Disco Ball."))
new /obj/structure/etherealball(user.loc)
qdel(src)

/obj/structure/etherealball
name = "Ethereal Disco Ball"
desc = "The ethics of this discoball are questionable."
name = "Animatronic Disco Ball"
desc = "A discoball with an animatronic head inside, seemingly in the likeness of a famous elzousza muscisian. A disclaimer on the side says any resemblence to living persons is entirely coincidental."
icon = 'icons/obj/device.dmi'
icon_state = "ethdisco_head_0"
anchored = TRUE
Expand All @@ -31,15 +31,15 @@
. = ..()
if(TurnedOn)
TurnOff()
to_chat(user, "<span class='notice'>You turn the disco ball off!</span>")
to_chat(user, span_notice("You turn the disco ball off!"))
else
TurnOn()
to_chat(user, "<span class='notice'>You turn the disco ball on!</span>")
to_chat(user, span_notice("You turn the disco ball on!"))

/obj/structure/etherealball/AltClick(mob/living/carbon/human/user)
. = ..()
set_anchored(!anchored)
to_chat(user, "<span class='notice'>You [anchored ? null : "un"]lock the disco ball.</span>")
to_chat(user, span_notice("You [anchored ? null : "un"]lock the disco ball."))

/obj/structure/etherealball/proc/TurnOn()
TurnedOn = TRUE //Same
Expand Down
18 changes: 8 additions & 10 deletions code/game/objects/items/grenades/discogrenade.dm
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
//Ethereal Disco Grenade for Ethereal traitors
//Does not affect ethereals.
//Some basic code pieces taken from flashbang, spawner grenade and ethereal disco ball for functionality (basically a combination of the 3).

//////////////////////
// Primary grenade //
//////////////////////

/obj/item/grenade/discogrenade
name = "Ethereal Disco Grenade"
desc = "An unethical micro-party that will make all non-Ethereal beings dance to its beat!"
name = "Portable Disco Grenade"
desc = "An exotic prototype grenade. Through powerful audiovisual hypnotic cues, victims are afflicted with an unstoppable urge to boogie down. "
icon_state = "disco"
item_state = "flashbang"
lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
Expand Down Expand Up @@ -91,7 +89,7 @@
return
if(target.stat != CONSCIOUS) //Only conscious people can dance
return
if(!target || iselzuose(target)) //Non humans and non etherals can't dance
if(!target) //Non humans and non etherals can't dance
return

var/distance = max(0,get_dist(get_turf(src), target_turf))
Expand All @@ -102,27 +100,27 @@
target.say(pick(message_social_anxiety))
if(rand(3) && target.get_ear_protection() == 0)
target.drop_all_held_items()
target.show_message("<span class='warning'>You cover your ears, the music is just too loud for you.</span>", 2)
target.show_message(span_warning("You cover your ears, the music is just too loud for you."), 2)
return

if(HAS_TRAIT(target, TRAIT_MINDSHIELD))
target.show_message("<span class='warning'>You resist your inner urges to break out your best moves.</span>", 2)
target.show_message(span_warning("You resist your inner urges to break out your best moves."), 2)
target.set_drugginess(5)
return
if(istype(target.get_item_by_slot(ITEM_SLOT_HEAD), /obj/item/clothing/head/foilhat))
to_chat(target, "<span class = 'userdanger'>THOSE GLOW-IN-THE-DARK NANOTRASEN LIGHTBULBS WON'T CORRUPT ME WITH THEIR AGENDA!</span>")
to_chat(target, span_userdanger("BIG DISCO WON'T CORRUPT ME WITH THEIR POST ICW PSY-OP MUSIC!"))
target.emote("scream")
return

target.set_drugginess(10)
target.show_message("<span class='warning'>You feel a strong rythme and your muscles spasm uncontrollably, you begin dancing and cannot move!</span>", 2)
target.show_message(span_warning("You feel a strong rythme and your muscles spasm uncontrollably, you begin dancing and cannot move!"), 2)
target.Immobilize(30)

//Special actions
switch(rand(0, 6))
if(0)
target.Knockdown(4)
target.show_message("<span class='warning'>You [pick("mess", "screw")] up your moves and trip!</span>", 2)
target.show_message(span_warning("You [pick("mess", "screw")] up your moves and trip!"), 2)
if(1 to 3)
target.emote("spin")
if(3 to 4)
Expand Down
3 changes: 2 additions & 1 deletion code/game/objects/items/powerfist.dm
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
return
var/datum/gas_mixture/gasused = tank.air_contents.remove(gasperfist * fisto_setting)
var/turf/T = get_turf(src)
var/mols_used = gasused.total_moles()
if(!T)
return
T.assume_air(gasused)
Expand All @@ -86,7 +87,7 @@
target.visible_message("<span class='danger'>[user]'s powerfist lets out a dull thunk as [user.p_they()] punch[user.p_es()] [target.name]!</span>", \
"<span class='userdanger'>[user]'s punches you!</span>")
return
if(gasused.total_moles() < gasperfist * fisto_setting)
if(mols_used < gasperfist * fisto_setting)
to_chat(user, "<span class='warning'>\The [src]'s piston-ram lets out a weak hiss, it needs more gas!</span>")
playsound(loc, 'sound/weapons/punch4.ogg', 50, TRUE)
target.apply_damage((force / 2), BRUTE)
Expand Down
18 changes: 18 additions & 0 deletions code/game/objects/structures/crates_lockers/crates.dm
Original file line number Diff line number Diff line change
Expand Up @@ -293,3 +293,21 @@
new /obj/item/clothing/mask/breath(src)
for(var/i in 1 to 3)
new /obj/item/tank/internals/oxygen(src)

/obj/structure/closet/crate/cyborg
name = "Cyborg Construction Crate"
desc = "A crate containing the parts to build a cyborg frame."
icon_state = "scicrate"

/obj/structure/closet/crate/cyborg/PopulateContents()
. = ..()
new /obj/item/bodypart/l_arm/robot(src)
new /obj/item/bodypart/r_arm/robot(src)
new /obj/item/bodypart/leg/left/robot(src)
new /obj/item/bodypart/leg/right/robot(src)
new /obj/item/bodypart/chest/robot(src)
new /obj/item/bodypart/head/robot(src)
new /obj/item/robot_suit(src)
new /obj/item/stock_parts/cell/high(src)
for(var/i in 1 to 2)
new /obj/item/assembly/flash/handheld(src)
39 changes: 36 additions & 3 deletions code/modules/cargo/blackmarket/blackmarket_item.dm
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,56 @@
var/stock_min = 1
/// Maximum amount that there should be of this item in the market if generated randomly.
var/stock_max = 0
/// Whether the item is visible and purchasable on the market
var/available = TRUE
/// Probability for this item to be available. Used by SSblackmarket on init.
var/availability_prob = 0
/// If this item should be more or less likely to spawn than usual. Positive is more likely, negative is less
var/weight = 0
/// If this item is affected by avalibility weight. For items that shouldnt appear on their own (paired items), should always appear, or items paticularly rare or powerful that we dont want showing up too often
var/spawn_weighting
// Should there be an unlimited stock of an item
var/unlimited = FALSE
/// Should another item spawn alongside this one in the catalogue?
var/datum/blackmarket_item/pair_item
var/list/pair_item = null


/datum/blackmarket_item/New()
if(isnull(price))
price = rand(price_min, price_max)
randomize_price()
if(isnull(stock))
stock = rand(stock_min, stock_max)
randomize_stock()
if(isnull(spawn_weighting))
if(availability_prob == 0 || availability_prob == 100)
spawn_weighting = FALSE
else
spawn_weighting = TRUE

/// Used for spawning the wanted item, override if you need to do something special with the item.
/datum/blackmarket_item/proc/spawn_item(loc)
return new item(loc)

/datum/blackmarket_item/proc/randomize_price()
price = rand(price_min, price_max)

/datum/blackmarket_item/proc/randomize_stock()
stock = rand(stock_min, stock_max)

/datum/blackmarket_item/proc/cycle(price = TRUE, availibility = TRUE, stock = FALSE, force_appear = FALSE)
if(price)
randomize_price()
if(stock)
randomize_stock()
if(availibility)
if(spawn_weighting ? prob(max(0, (availability_prob + (weight * 10)))) : prob(availability_prob))
available = TRUE
weight--
else
available = FALSE
weight++
if(force_appear)
available = TRUE

/// Buys the item and makes SSblackmarket handle it.
/datum/blackmarket_item/proc/buy(obj/item/blackmarket_uplink/uplink, mob/buyer, shipping_method)
// Sanity
Expand Down
Loading

0 comments on commit 0edc3ea

Please sign in to comment.