[MIRROR] Blackmarket refactor and balance, fixing spy bounties, plus a new category for people captured by pirates/tots/contractors. (#26869)

Blackmarket refactor and balance, fixing spy bounties, plus a new category for people captured by pirates/tots/contractors. (#81818)

This PR aims to take care of a few potential hard dels and fix the
fenced goods category first and foremost.

The PR also adds a new one that enables you to buy mobs captured by
antags in advance, before they're sent back to the station. Unlike other
categories, it doesn't have "Launch" and "Teleport" as delivery methods,
instead it uses a special "Supply Pod" delivery method that ships the
chattel directly to your location. This method costs 400 credits,
however, if you've built the LTSRBT, shipment will be free.

Another thing, I always felt LTSRBT to be pretty fucking dumb as is. Way
too overpriced for the benefits it offers: a slighty cheaper delivery
method that, while definitely better than the other two, doesn't really
pay off or honestly even remotely compensate the 4000 credits you just
spent to get it, especially if you're only buying a couple items at
most. So I decided to remove it from cargo and add it to the blackmarket
as a 500 to 750 creds item, available every round.

Human mobs sold by the pirate bounty pad are no longer deleted, instead
they're properly ransomed and sent to the holding facility, much like
for contractors and tots. This means they're also added to the black
market.

The blackmarket system has some issues to it that need to be fixed
(otherwise the "Fenced Goods" and "Hostages" categories wouldn't work).
The Pirate Pad deleting "ransomed" mobs instead of actually ransoming
them is lame. The LTSRBT shouldn't suck as much. Also more market stuff.

This will fix #81809.

🆑
fix: Fixed the "Fenced Goods" black market category.
balance: Removed the LTSRBT from cargo and added it to the blackmarket,
reduced the price from 4000 to 625 on average.
balance: The time it takes for captured mobs to be automatically sent
back to the station from the holding facility has been increased from
3-4 minutes to 6.
add: You can buy mobs captured by contractors, traitors and pirates from
the black market and have them sent back to the station in advance. For
safety, they'll also be handcuffed (not always) upon delivery.
add: Human mobs sold by pirates are not deleted anymore. Instead,
they're now captured and sent to the holding facility.
/🆑

Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
This commit is contained in:
SkyratBot
2024-03-28 22:39:23 -04:00
committed by GitHub
co-authored by Ghom
parent fb781a8435
commit 8dec82ee85
26 changed files with 524 additions and 250 deletions
+3
View File
@@ -36,6 +36,9 @@
///How long pirates will wait for a response before attacking
#define RESPONSE_MAX_TIME 2 MINUTES
/// How long till a spessman should come back after being captured and sent to the holding facility (which some antags use)
#define COME_BACK_FROM_CAPTURE_TIME 6 MINUTES
//ERT Types
#define ERT_BLUE "Blue"
#define ERT_RED "Red"
+2 -1
View File
@@ -7,4 +7,5 @@
#define SHIPPING_METHOD_TELEPORT "Teleport"
// Throws the item from somewhere at the station.
#define SHIPPING_METHOD_LAUNCH "Launch"
// Sends a supply pod to the buyer's location, showy.
#define SHIPPING_METHOD_SUPPLYPOD "Supply Pod"
+7
View File
@@ -64,3 +64,10 @@
#define SUPPLY_PACK_UNCOMMON_DISCOUNTABLE "uncommon_discount"
///Discount category for the silly, overpriced, joke content, sometimes useful or plain bad.
#define SUPPLY_PACK_RARE_DISCOUNTABLE "rare_discount"
///Standard export define for not selling the item.
#define EXPORT_NOT_SOLD 0
///Sell the item
#define EXPORT_SOLD 1
///Sell the item, but for the love of god, don't delete it, we're handling it in a fancier way.
#define EXPORT_SOLD_DONT_DELETE 2
@@ -0,0 +1,2 @@
///From /datum/market_item/spawn_item(): (uplink, shipping_method, shipping_loc)
#define COMSIG_MARKET_ITEM_SPAWNED "market_item_spawned"
@@ -174,6 +174,9 @@
///From obj/item/toy/crayon/spraycan
#define COMSIG_LIVING_MOB_PAINTED "living_mob_painted"
///From obj/closet/supplypod/return_victim: (turf/destination)
#define COMSIG_LIVING_RETURN_FROM_CAPTURE "living_return_from_capture"
///From mob/living/proc/wabbajack(): (randomize_type)
#define COMSIG_LIVING_PRE_WABBAJACKED "living_mob_wabbajacked"
/// Return to stop the rest of the wabbajack from triggering.
+34 -31
View File
@@ -5,9 +5,10 @@ SUBSYSTEM_DEF(blackmarket)
/// Descriptions for each shipping methods.
var/shipping_method_descriptions = list(
SHIPPING_METHOD_LAUNCH="Launches the item at the station from space, cheap but you might not receive your item at all.",
SHIPPING_METHOD_LTSRBT="Long-To-Short-Range-Bluespace-Transceiver, a machine that receives items outside the station and then teleports them to the location of the uplink.",
SHIPPING_METHOD_TELEPORT="Teleports the item in a random area in the station, you get 60 seconds to get there first though."
SHIPPING_METHOD_LAUNCH = "Launches the item at the station from space, cheap but you might not receive your item at all.",
SHIPPING_METHOD_LTSRBT = "Long-To-Short-Range-Bluespace-Transceiver, a machine that receives items outside the station and then teleports them to the location of the uplink.",
SHIPPING_METHOD_TELEPORT = "Teleports the item in a random area in the station, you get 60 seconds to get there first though.",
SHIPPING_METHOD_SUPPLYPOD = "Ships the item inside a supply pod at your exact location. Showy, speedy and expensive.",
)
/// List of all existing markets.
@@ -42,11 +43,7 @@ SUBSYSTEM_DEF(blackmarket)
var/datum/market_purchase/purchase = queued_purchases[1]
queued_purchases.Cut(1,2)
// Uh oh, uplink is gone. We will just keep the money and you will not get your order.
if(!purchase.uplink || QDELETED(purchase.uplink))
queued_purchases -= purchase
qdel(purchase)
continue
var/mob/buyer = recursive_loc_check(purchase.uplink.loc, /mob)
switch(purchase.method)
// Find a ltsrbt pad and make it handle the shipping.
@@ -54,65 +51,71 @@ SUBSYSTEM_DEF(blackmarket)
if(!telepads.len)
continue
// Prioritize pads that don't have a cooldown active.
var/free_pad_found = FALSE
for(var/obj/machinery/ltsrbt/pad in telepads)
var/obj/machinery/ltsrbt/free_pad_found
for(var/obj/machinery/ltsrbt/pad as anything in telepads)
if(pad.recharge_cooldown)
continue
pad.add_to_queue(purchase)
queued_purchases -= purchase
free_pad_found = TRUE
free_pad_found = pad
break
if(free_pad_found)
if(isnull(free_pad_found))
continue
var/obj/machinery/ltsrbt/pad = pick(telepads)
to_chat(buyer, span_notice("[purchase.uplink] flashes a message noting that the order is being processed by [free_pad_found]."))
to_chat(recursive_loc_check(purchase.uplink.loc, /mob), span_notice("[purchase.uplink] flashes a message noting that the order is being processed by [pad]."))
queued_purchases -= purchase
pad.add_to_queue(purchase)
// Get random area, throw it somewhere there.
if(SHIPPING_METHOD_TELEPORT)
var/turf/targetturf = get_safe_random_station_turf()
// This shouldn't happen.
if (!targetturf)
continue
queued_purchases -= purchase
to_chat(recursive_loc_check(purchase.uplink.loc, /mob), span_notice("[purchase.uplink] flashes a message noting that the order is being teleported to [get_area(targetturf)] in 60 seconds."))
to_chat(buyer, span_notice("[purchase.uplink] flashes a message noting that the order is being teleported to [get_area(targetturf)] in 60 seconds."))
// do_teleport does not want to teleport items from nullspace, so it just forceMoves and does sparks.
addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/controller/subsystem/blackmarket,fake_teleport), purchase.entry.spawn_item(), targetturf), 60 SECONDS)
queued_purchases -= purchase
qdel(purchase)
addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/controller/subsystem/blackmarket,fake_teleport), purchase, targetturf), 60 SECONDS)
// Get the current location of the uplink if it exists, then throws the item from space at the station from a random direction.
if(SHIPPING_METHOD_LAUNCH)
var/startSide = pick(GLOB.cardinals)
var/turf/T = get_turf(purchase.uplink)
var/pickedloc = spaceDebrisStartLoc(startSide, T.z)
var/atom/movable/item = purchase.entry.spawn_item(pickedloc)
var/atom/movable/item = purchase.entry.spawn_item(pickedloc, purchase)
item.throw_at(purchase.uplink, 3, 3, spin = FALSE)
to_chat(recursive_loc_check(purchase.uplink.loc, /mob), span_notice("[purchase.uplink] flashes a message noting the order is being launched at the station from [dir2text(startSide)]."))
to_chat(buyer, span_notice("[purchase.uplink] flashes a message noting the order is being launched at the station from [dir2text(startSide)]."))
qdel(purchase)
queued_purchases -= purchase
if(SHIPPING_METHOD_SUPPLYPOD)
var/obj/structure/closet/supplypod/back_to_station/pod = new()
purchase.entry.spawn_item(pod, purchase)
new /obj/effect/pod_landingzone(get_turf(purchase.uplink), pod)
to_chat(buyer, span_notice("[purchase.uplink] flashes a message noting the order is being launched at your location. Right here, right now!"))
qdel(purchase)
if(MC_TICK_CHECK)
break
/// Used to make a teleportation effect as do_teleport does not like moving items from nullspace.
/datum/controller/subsystem/blackmarket/proc/fake_teleport(atom/movable/item, turf/target)
item.forceMove(target)
/datum/controller/subsystem/blackmarket/proc/fake_teleport(datum/market_purchase/purchase, turf/target)
// Oopsie, whoopsie, the item is gone. So long, and thanks for all the money.
if(QDELETED(purchase))
return
var/atom/movable/thing = purchase.entry.spawn_item(target, purchase)
var/datum/effect_system/spark_spread/sparks = new
sparks.set_up(5, 1, target)
sparks.attach(item)
sparks.attach(thing)
sparks.start()
qdel(purchase)
/// Used to add /datum/market_purchase to queued_purchases var. Returns TRUE when queued.
/datum/controller/subsystem/blackmarket/proc/queue_item(datum/market_purchase/P)
if(P.method == SHIPPING_METHOD_LTSRBT && !telepads.len)
/datum/controller/subsystem/blackmarket/proc/queue_item(datum/market_purchase/purchase)
if((purchase.method == SHIPPING_METHOD_LTSRBT && !telepads.len) || isnull(purchase.uplink))
qdel(purchase)
return FALSE
queued_purchases += P
queued_purchases += purchase
return TRUE
+5
View File
@@ -1017,6 +1017,11 @@ GLOBAL_LIST_EMPTY(possible_items)
var/payout_bonus = 0
var/area/dropoff = null
/datum/objective/contract/is_valid_target(datum/mind/possible_target)
if(HAS_TRAIT(possible_target, TRAIT_HAS_BEEN_KIDNAPPED))
return FALSE
return ..()
// Generate a random valid area on the station that the dropoff will happen.
/datum/objective/contract/proc/generate_dropoff()
var/found = FALSE
@@ -271,6 +271,10 @@
. = TRUE
if("send")
start_sending()
//We ensure that the holding facility is loaded in time in case we're selling mobs.
//This isn't the prettiest place to put it, but 'start_sending()' is also used by civilian bounty computers
//And we don't need them to also load the holding facility.
SSmapping.lazy_load_template(LAZY_TEMPLATE_KEY_NINJA_HOLDING_FACILITY)
. = TRUE
if("stop")
stop_sending()
@@ -283,12 +287,9 @@
status_report = "Predicted value: "
var/value = 0
var/datum/export_report/report = new
var/obj/machinery/piratepad/pad = pad_ref?.resolve()
for(var/atom/movable/AM in get_turf(pad))
if(AM == pad)
continue
export_item_and_contents(AM, apply_elastic = FALSE, dry_run = TRUE, external_report = report, ignore_typecache = nosell_typecache)
var/datum/export_report/report = pirate_export_loop(pad)
for(var/datum/export/exported_datum in report.total_amount)
status_report += exported_datum.total_printout(report,notes = FALSE)
@@ -303,13 +304,8 @@
if(!sending)
return
var/datum/export_report/report = new
var/obj/machinery/piratepad/pad = pad_ref?.resolve()
for(var/atom/movable/item_on_pad in get_turf(pad))
if(item_on_pad == pad)
continue
export_item_and_contents(item_on_pad, apply_elastic = FALSE, delete_unsold = FALSE, external_report = report, ignore_typecache = nosell_typecache)
var/datum/export_report/report = pirate_export_loop(pad, dry_run = FALSE)
status_report = "Sold: "
var/value = 0
@@ -341,6 +337,33 @@
pad.icon_state = pad.idle_state
sending = FALSE
///The loop that calculates the value of stuff on a pirate pad, or plain sell them if dry_run is FALSE.
/obj/machinery/computer/piratepad_control/proc/pirate_export_loop(obj/machinery/piratepad/pad, dry_run = TRUE)
var/datum/export_report/report = new
for(var/atom/movable/item_on_pad as anything in get_turf(pad))
if(item_on_pad == pad)
continue
var/list/hidden_mobs = list()
var/skip_movable = FALSE
var/list/item_contents = item_on_pad.get_all_contents()
for(var/atom/movable/thing in reverse_range(item_contents))
///Don't destroy/sell stuff like the captain's laser gun, or borgs.
if(thing.resistance_flags & INDESTRUCTIBLE || is_type_in_typecache(thing, nosell_typecache))
skip_movable = TRUE
break
if(isliving(thing))
hidden_mobs += thing
if(skip_movable)
continue
for(var/mob/living/hidden as anything in hidden_mobs)
///Sell mobs, but leave their contents intact.
export_single_item(hidden, apply_elastic = FALSE, dry_run = dry_run, external_report = report)
///there are still licing mobs inside that item. Stop, don't sell it ffs.
if(locate(/mob/living) in item_on_pad.get_all_contents())
continue
export_item_and_contents(item_on_pad, apply_elastic = FALSE, dry_run = dry_run, delete_unsold = FALSE, external_report = report, ignore_typecache = nosell_typecache)
return report
/// Prepares to sell the items on the pad
/obj/machinery/computer/piratepad_control/proc/start_sending()
var/obj/machinery/piratepad/pad = pad_ref?.resolve()
@@ -391,7 +414,7 @@
/datum/export/pirate/ransom/get_cost(atom/movable/exported_item)
var/mob/living/carbon/human/ransomee = exported_item
if(ransomee.stat != CONSCIOUS || !ransomee.mind) //mint condition only
if(ransomee.stat != CONSCIOUS || !ransomee.mind || HAS_TRAIT(ransomee.mind, TRAIT_HAS_BEEN_KIDNAPPED)) //mint condition only
return 0
else if(FACTION_PIRATE in ransomee.faction) //can't ransom your fellow pirates to CentCom!
return 0
@@ -400,6 +423,33 @@
else
return 1000
/datum/export/pirate/ransom/sell_object(mob/living/carbon/human/sold_item, datum/export_report/report, dry_run = TRUE, apply_elastic = TRUE)
. = ..()
if(. == EXPORT_NOT_SOLD)
return
var/turf/picked_turf = pick(GLOB.holdingfacility)
sold_item.forceMove(picked_turf)
var/mob_cost = get_cost(sold_item)
sold_item.process_capture(mob_cost, mob_cost * 1.2)
do_sparks(8, FALSE, sold_item)
playsound(picked_turf, 'sound/weapons/emitter2.ogg', 25, TRUE)
sold_item.flash_act()
sold_item.adjust_confusion(10 SECONDS)
sold_item.adjust_dizzy(10 SECONDS)
addtimer(src, CALLBACK(src, PROC_REF(send_back_to_station), sold_item), COME_BACK_FROM_CAPTURE_TIME)
to_chat(sold_item, span_hypnophrase("A million voices echo in your head... <i>\"Yaarrr, thanks for the booty, landlubber. \
You will be ransomed back to your station, so it's only a matter of time before we ship you back...</i>"))
return EXPORT_SOLD_DONT_DELETE
///Send them back to the station after a while.
/datum/export/pirate/ransom/proc/send_back_to_station(mob/living/prisoner)
///Deleted or already bailed out of the place.
if(QDELETED(prisoner) || !istype(get_area(prisoner), /area/centcom/central_command_areas/holding))
return
var/obj/structure/closet/supplypod/back_to_station/return_pod = new()
return_pod.return_from_capture(prisoner)
/datum/export/pirate/parrot
cost = 2000
unit_name = "alive parrot"
+18 -18
View File
@@ -133,13 +133,15 @@
do_sparks(3, FALSE, stealing)
// Don't mess with it while it's going away
var/had_attack_hand_interaction = stealing.interaction_flags_atom & INTERACT_ATOM_ATTACK_HAND
stealing.interaction_flags_atom &= ~INTERACT_ATOM_ATTACK_HAND
var/was_anchored = stealing.anchored
stealing.anchored = TRUE
// Add some pizzazz
animate(stealing, time = 0.5 SECONDS, transform = matrix(stealing.transform).Scale(0.01), easing = CUBIC_EASING)
animate(stealing, time = 0.5 SECONDS, transform = stealing.transform.Scale(0.01), easing = CUBIC_EASING)
if(isitem(stealing) && ((stealing.resistance_flags & INDESTRUCTIBLE) || prob(black_market_prob)))
addtimer(CALLBACK(src, PROC_REF(send_to_black_market), stealing), 0.5 SECONDS)
addtimer(CALLBACK(src, PROC_REF(send_to_black_market), stealing, had_attack_hand_interaction, was_anchored), 0.5 SECONDS)
else
addtimer(CALLBACK(src, PROC_REF(finish_cleanup), stealing), 0.5 SECONDS)
@@ -158,33 +160,31 @@
*
* * thing - The item to put up on the black market.
*/
/datum/spy_bounty/proc/send_to_black_market(atom/movable/thing)
/datum/spy_bounty/proc/send_to_black_market(atom/movable/thing, had_attack_hand_interaction, was_anchored)
if(QDELETED(thing)) // Just in case anything does anything weird
return FALSE
thing.interaction_flags_atom = initial(thing.interaction_flags_atom)
thing.anchored = initial(thing.anchored)
///reset the appearance and all.
if(had_attack_hand_interaction)
thing.interaction_flags_atom |= INTERACT_ATOM_ATTACK_HAND
thing.anchored = was_anchored
thing.transform = thing.transform.Scale(10)
thing.moveToNullspace()
var/datum/market_item/new_item = new()
new_item.item = thing
new_item.name = "Stolen [thing.name]"
new_item.desc = "A [thing.name], stolen from somewhere on the station. Whoever owned it probably wouldn't be happy to see it here."
new_item.category = "Fenced Goods"
new_item.stock = 1
new_item.availability_prob = 100
var/item_price
switch(difficulty)
if(SPY_DIFFICULTY_EASY)
new_item.price = PAYCHECK_COMMAND * 2.5
item_price = PAYCHECK_COMMAND * 2.5
if(SPY_DIFFICULTY_MEDIUM)
new_item.price = PAYCHECK_COMMAND * 5
item_price = PAYCHECK_COMMAND * 5
if(SPY_DIFFICULTY_HARD)
new_item.price = PAYCHECK_COMMAND * 10
item_price = PAYCHECK_COMMAND * 10
new_item.price += rand(0, PAYCHECK_COMMAND * 5)
item_price += rand(0, PAYCHECK_COMMAND * 5)
if(thing.resistance_flags & INDESTRUCTIBLE)
new_item.price *= 2
item_price *= 2
var/datum/market_item/stolen_good/new_item = new(thing, item_price)
return SSblackmarket.markets[/datum/market/blackmarket].add_item(new_item)
@@ -15,6 +15,8 @@
var/wanted_message
///List of everything found on the victim at the time of contracting, used to return their stuff afterwards.
var/list/victim_belongings = list()
///timerid for stuff that handles victim chat messages, effects and returnal
var/victim_timerid
/datum/syndicate_contract/New(contract_owner, blacklist, type=CONTRACT_PAYOUT_SMALL)
contract = new(src)
@@ -122,20 +124,8 @@
//we'll start the effects in a few seconds since it takes a moment for the pod to leave.
addtimer(CALLBACK(src, PROC_REF(handle_victim_experience), person_sent), 3 SECONDS)
// This is slightly delayed because of the sleep calls above to handle the narrative.
// We don't want to tell the station instantly.
var/points_to_check
var/datum/bank_account/cargo_account = SSeconomy.get_dep_account(ACCOUNT_CAR)
if(cargo_account)
points_to_check = cargo_account.account_balance
if(points_to_check >= ransom)
cargo_account.adjust_money(-ransom)
else
cargo_account.adjust_money(-points_to_check)
priority_announce(
text = "One of your crew was captured by a rival organisation - we've needed to pay their ransom to bring them back. \
As is policy we've taken a portion of the station's funds to offset the overall cost.",
sender_override = "Nanotrasen Asset Protection")
var/datum/market_item/hostage/market_item = person_sent.process_capture(ransom * (rand(11, 13)/10))
RegisterSignal(market_item, COMSIG_MARKET_ITEM_SPAWNED, PROC_REF(on_victim_shipped))
addtimer(CALLBACK(src, PROC_REF(finish_enter)), 3 SECONDS)
@@ -166,10 +156,10 @@
* level - The current stage of harassement they are facing. This increases by itself, looping until finished.
*/
/datum/syndicate_contract/proc/handle_victim_experience(mob/living/victim, level = VICTIM_EXPERIENCE_START)
// Ship 'em back - dead or alive, 4 minutes wait.
// Ship 'em back - dead or alive
// Even if they weren't the target, we're still treating them the same.
if(!level)
addtimer(CALLBACK(src, PROC_REF(return_victim), victim), (60 * 10) * 4)
victim_timerid = addtimer(CALLBACK(src, PROC_REF(return_victim), victim), COME_BACK_FROM_CAPTURE_TIME, TIMER_STOPPABLE)
if(victim.stat == DEAD)
return
@@ -209,7 +199,7 @@
level++ //move onto the next level.
if(time_until_next)
addtimer(CALLBACK(src, PROC_REF(handle_victim_experience), victim, level), time_until_next)
victim_timerid = addtimer(CALLBACK(src, PROC_REF(handle_victim_experience), victim, level), time_until_next, TIMER_STOPPABLE)
#undef VICTIM_EXPERIENCE_START
#undef VICTIM_EXPERIENCE_FIRST_HIT
@@ -217,34 +207,30 @@
#undef VICTIM_EXPERIENCE_THIRD_HIT
#undef VICTIM_EXPERIENCE_LAST_HIT
// We're returning the victim
/// We're returning the victim to the station
/datum/syndicate_contract/proc/return_victim(mob/living/victim)
var/list/possible_drop_loc = list()
for(var/turf/possible_drop in contract.dropoff.contents)
for(var/turf/possible_drop in shuffle(contract.dropoff.contents))
if(!isspaceturf(possible_drop) && !isclosedturf(possible_drop))
if(!possible_drop.is_blocked_turf())
possible_drop_loc.Add(possible_drop)
if(!possible_drop_loc.len)
to_chat(victim, span_hypnophrase("A million voices echo in your head... \"Seems where you got sent here from won't \
be able to handle our pod... if we wanted the occupant to survive. Brace yourself, corporate dog.\""))
for(var/turf/possible_drop in contract.dropoff.contents)
possible_drop_loc.Add(possible_drop)
if(iscarbon(victim))
var/mob/living/carbon/carbon_victim = victim
if(carbon_victim.can_heartattack())
carbon_victim.set_heartattack(TRUE)
var/turf/destination
if(length(possible_drop_loc))
destination = pick(possible_drop_loc)
var/pod_rand_loc = rand(1, possible_drop_loc.len)
var/obj/structure/closet/supplypod/return_pod = new()
return_pod.bluespace = TRUE
return_pod.explosionSize = list(0,0,0,0)
return_pod.style = STYLE_SYNDICATE
var/obj/structure/closet/supplypod/back_to_station/return_pod = new()
return_pod.return_from_capture(victim, destination)
returnal_side_effects(return_pod, victim)
do_sparks(8, FALSE, victim)
victim.visible_message(span_notice("[victim] vanishes..."))
///Called if the victim is being returned to the station early, when from the black market.
/datum/syndicate_contract/proc/on_victim_shipped(datum/market_item/source, obj/item/market_uplink/uplink, shipping_method, turf/shipping_loc)
SIGNAL_HANDLER
deltimer(victim_timerid)
returnal_side_effects(shipping_loc, source.item)
///The annoying negative effects applied to the victim when returned to the station.
/datum/syndicate_contract/proc/returnal_side_effects(atom/dropoff_location, mob/living/victim)
for(var/datum/weakref/belonging_ref in victim_belongings)
var/obj/item/belonging = belonging_ref.resolve()
if(!belonging)
@@ -256,16 +242,12 @@
continue
if(belonging == human_victim.shoes)
continue
belonging.forceMove(return_pod)
belonging.forceMove(dropoff_location)
for(var/obj/item/W in victim_belongings)
W.forceMove(return_pod)
victim.forceMove(return_pod)
for(var/obj/item/item in victim_belongings)
item.forceMove(dropoff_location)
victim.flash_act()
victim.adjust_eye_blur(3 SECONDS)
victim.adjust_dizzy(3.5 SECONDS)
victim.adjust_confusion(2 SECONDS)
new /obj/effect/pod_landingzone(possible_drop_loc[pod_rand_loc], return_pod)
@@ -15,6 +15,8 @@
var/alive_bonus = 0
/// All stripped targets belongings (weakrefs)
var/list/target_belongings = list()
/// The ID of the stoppable timer for returning the captured crew
var/list/victim_timerid
duplicate_type = /datum/traitor_objective/target_player
@@ -216,6 +218,7 @@
new /obj/effect/pod_landingzone(get_turf(user), new_pod)
/datum/traitor_objective/target_player/kidnapping/proc/enter_check(obj/structure/closet/supplypod/extractionpod/source, entered_atom)
SIGNAL_HANDLER
if(!istype(source))
CRASH("Kidnapping objective's enter_check called with source being not an extraction pod: [source ? source.type : "N/A"]")
@@ -224,9 +227,6 @@
var/mob/living/carbon/human/sent_mob = entered_atom
if(sent_mob.mind)
ADD_TRAIT(sent_mob.mind, TRAIT_HAS_BEEN_KIDNAPPED, TRAIT_GENERIC)
for(var/obj/item/belonging in sent_mob.gather_belongings())
if(belonging == sent_mob.get_item_by_slot(ITEM_SLOT_ICLOTHING) || belonging == sent_mob.get_item_by_slot(ITEM_SLOT_FEET))
continue
@@ -236,12 +236,8 @@
continue
target_belongings.Add(WEAKREF(belonging))
var/datum/bank_account/cargo_account = SSeconomy.get_dep_account(ACCOUNT_CAR)
if(cargo_account) //Just in case
cargo_account.adjust_money(-min(rand(1000, 3000), cargo_account.account_balance)) //Not so much, especially for competent cargo. Plus this can't be mass-triggered like it has been done with contractors
priority_announce("One of your crew was captured by a rival organisation - we've needed to pay their ransom to bring them back. As is policy we've taken a portion of the station's funds to offset the overall cost.", "Nanotrasen Asset Protection", has_important_message = TRUE)
var/datum/market_item/hostage/market_item = sent_mob.process_capture(rand(1000, 3000))
RegisterSignal(market_item, COMSIG_MARKET_ITEM_SPAWNED, PROC_REF(on_victim_shipped))
addtimer(CALLBACK(src, PROC_REF(handle_target), sent_mob), 1.5 SECONDS)
@@ -257,7 +253,7 @@
source.startExitSequence(source)
/datum/traitor_objective/target_player/kidnapping/proc/handle_target(mob/living/carbon/human/sent_mob)
addtimer(CALLBACK(src, PROC_REF(return_target), sent_mob), 3 MINUTES)
victim_timerid = addtimer(CALLBACK(src, PROC_REF(return_target), sent_mob), COME_BACK_FROM_CAPTURE_TIME, TIMER_STOPPABLE)
if(sent_mob.stat == DEAD)
return
@@ -266,29 +262,24 @@
sent_mob.adjust_dizzy(10 SECONDS)
sent_mob.set_eye_blur_if_lower(100 SECONDS)
sent_mob.dna.species.give_important_for_life(sent_mob) // so plasmamen do not get left for dead
to_chat(sent_mob, span_hypnophrase(span_reallybig("A million voices echo in your head... <i>\"Your mind held many valuable secrets - \
to_chat(sent_mob, span_hypnophrase("A million voices echo in your head... <i>\"Your mind held many valuable secrets - \
we thank you for providing them. Your value is expended, and you will be ransomed back to your station. We always get paid, \
so it's only a matter of time before we ship you back...\"</i>")))
so it's only a matter of time before we ship you back...\"</i>"))
/datum/traitor_objective/target_player/kidnapping/proc/return_target(mob/living/carbon/human/sent_mob)
if(!sent_mob || QDELETED(sent_mob)) //suicided and qdeleted themselves
return
var/turf/return_turf = get_safe_random_station_turf()
if(!return_turf) //SOMEHOW
to_chat(sent_mob, span_hypnophrase(span_reallybig("A million voices echo in your head... <i>\"Seems where you got sent here from won't \
be able to handle our pod... You will die here instead.\"</i></span>")))
if (sent_mob.can_heartattack())
sent_mob.set_heartattack(TRUE)
return
var/obj/structure/closet/supplypod/back_to_station/return_pod = new()
return_pod.return_from_capture(sent_mob)
returnal_side_effects(return_pod, sent_mob)
var/obj/structure/closet/supplypod/return_pod = new()
return_pod.bluespace = TRUE
return_pod.explosionSize = list(0,0,0,0)
return_pod.style = STYLE_SYNDICATE
/datum/traitor_objective/target_player/kidnapping/proc/on_victim_shipped(datum/market_item/source, obj/item/market_uplink/uplink, shipping_method, turf/shipping_loc)
SIGNAL_HANDLER
deltimer(victim_timerid)
returnal_side_effects(shipping_loc, source.item)
do_sparks(8, FALSE, sent_mob)
sent_mob.visible_message(span_notice("[sent_mob] vanishes!"))
/datum/traitor_objective/target_player/kidnapping/proc/returnal_side_effects(atom/dropoff_location, mob/living/carbon/human/sent_mob)
for(var/obj/item/belonging in sent_mob.gather_belongings())
if(belonging == sent_mob.get_item_by_slot(ITEM_SLOT_ICLOTHING) || belonging == sent_mob.get_item_by_slot(ITEM_SLOT_FEET))
continue
@@ -298,13 +289,10 @@
var/obj/item/belonging = belonging_ref.resolve()
if(!belonging)
continue
belonging.forceMove(return_pod)
belonging.forceMove(dropoff_location)
sent_mob.forceMove(return_pod)
sent_mob.flash_act()
sent_mob.adjust_confusion(10 SECONDS)
sent_mob.adjust_dizzy(10 SECONDS)
sent_mob.set_eye_blur_if_lower(100 SECONDS)
sent_mob.dna.species.give_important_for_life(sent_mob) // so plasmamen do not get left for dead
new /obj/effect/pod_landingzone(return_turf, return_pod)
+42 -23
View File
@@ -30,6 +30,14 @@ Then the player gets the profit from selling his own wasted time.
///set to false if any objects in a dry run were unscannable
var/all_contents_scannable = TRUE
/// Makes sure the exports list is populated and that the report isn't null.
/proc/init_export(datum/export_report/external_report)
if(!length(GLOB.exports_list))
setupExports()
if(isnull(external_report))
external_report = new
return external_report
/*
* Handles exporting a movable atom and its contents
* Arguments:
@@ -40,32 +48,15 @@ Then the player gets the profit from selling his own wasted time.
** ignore_typecache: typecache containing types that should be completely ignored
*/
/proc/export_item_and_contents(atom/movable/exported_atom, apply_elastic = TRUE, delete_unsold = TRUE, dry_run = FALSE, datum/export_report/external_report, list/ignore_typecache)
if(!GLOB.exports_list.len)
setupExports()
external_report = init_export()
var/list/contents = exported_atom.get_all_contents_ignoring(ignore_typecache)
var/datum/export_report/report = external_report
if(!report) //If we don't have any longer transaction going on
report = new
// We go backwards, so it'll be innermost objects sold first. We also make sure nothing is accidentally delete before everything is sold.
var/list/to_delete = list()
for(var/atom/movable/thing as anything in reverse_range(contents))
var/sold = FALSE
for(var/datum/export/export as anything in GLOB.exports_list)
if(export.applies_to(thing, apply_elastic))
if(!dry_run && (SEND_SIGNAL(thing, COMSIG_ITEM_PRE_EXPORT) & COMPONENT_STOP_EXPORT))
break
//Don't add value of unscannable items for a dry run report
if(dry_run && !export.scannable)
report.all_contents_scannable = FALSE
break
sold = export.sell_object(thing, report, dry_run, apply_elastic)
report.exported_atoms += " [thing.name]"
break
if(!dry_run && (sold || delete_unsold))
var/sold = _export_loop(thing, apply_elastic, dry_run, external_report)
if(!dry_run && (sold || delete_unsold) && sold != EXPORT_SOLD_DONT_DELETE)
if(ismob(thing))
thing.investigate_log("deleted through cargo export", INVESTIGATE_CARGO)
to_delete += thing
@@ -74,7 +65,35 @@ Then the player gets the profit from selling his own wasted time.
if(!QDELETED(thing))
qdel(thing)
return report
return external_report
/// It works like export_item_and_contents(), however it ignores the contents. Meaning only `exported_atom` will be valued.
/proc/export_single_item(atom/movable/exported_atom, apply_elastic = TRUE, delete_unsold = TRUE, dry_run = FALSE, datum/export_report/external_report)
external_report = init_export()
var/sold = _export_loop(exported_atom, apply_elastic, dry_run, external_report)
if(!dry_run && (sold || delete_unsold) && sold != EXPORT_SOLD_DONT_DELETE)
if(ismob(exported_atom))
exported_atom.investigate_log("deleted through cargo export", INVESTIGATE_CARGO)
qdel(exported_atom)
return external_report
/// The main bit responsible for selling the item. Shared by export_single_item() and export_item_and_contents()
/proc/_export_loop(atom/movable/exported_atom, apply_elastic = TRUE, dry_run = FALSE, datum/export_report/external_report)
var/sold = EXPORT_NOT_SOLD
for(var/datum/export/export as anything in GLOB.exports_list)
if(export.applies_to(exported_atom, apply_elastic))
if(!dry_run && (SEND_SIGNAL(exported_atom, COMSIG_ITEM_PRE_EXPORT) & COMPONENT_STOP_EXPORT))
break
//Don't add value of unscannable items for a dry run report
if(dry_run && !export.scannable)
external_report.all_contents_scannable = FALSE
break
sold = export.sell_object(exported_atom, exported_atom, dry_run, apply_elastic)
external_report.exported_atoms += " [exported_atom.name]"
break
return sold
/datum/export
/// Unit name. Only used in "Received [total_amount] [name]s [message]."
@@ -164,7 +183,7 @@ Then the player gets the profit from selling his own wasted time.
var/export_amount = get_amount(sold_item)
if(export_amount <= 0 || (export_value <= 0 && !allow_negative_cost))
return FALSE
return EXPORT_NOT_SOLD
// If we're not doing a dry run, send COMSIG_ITEM_EXPORTED to the sold item
var/export_result
@@ -180,7 +199,7 @@ Then the player gets the profit from selling his own wasted time.
if(apply_elastic)
cost *= NUM_E**(-1 * k_elasticity * export_amount) //marginal cost modifier
SSblackbox.record_feedback("nested tally", "export_sold_cost", 1, list("[sold_item.type]", "[export_value]"))
return TRUE
return EXPORT_SOLD
/*
* Total printout for the cargo console.
+41 -27
View File
@@ -20,39 +20,53 @@
categories += item.category
available_items[item.category] = list()
available_items[item.category] += item
available_items[item.category][item.identifier] = item
RegisterSignal(item, COMSIG_QDELETING, PROC_REF(on_item_del))
return TRUE
/datum/market/proc/on_item_del(datum/market_item/item)
SIGNAL_HANDLER
available_items[item.category] -= item.identifier
if(!length(available_items[item.category]))
available_items -= item.category
/// Handles buying the item, this is mainly for future use and moving the code away from the uplink.
/datum/market/proc/purchase(item, category, method, obj/item/market_uplink/uplink, user)
if(!istype(uplink) || !(method in shipping))
/datum/market/proc/purchase(identifier, category, method, obj/item/market_uplink/uplink, user)
var/datum/market_item/item = available_items[category][identifier]
if(isnull(item))
return FALSE
for(var/datum/market_item/I in available_items[category])
if(I.type != item)
continue
var/price = I.price + shipping[method]
if(!uplink.current_user)///There is no ID card on the user, or the ID card has no account
to_chat(user, span_warning("The uplink sparks, as it can't identify an ID card with a bank account on you."))
return FALSE
var/balance = uplink?.current_user.account_balance
// I can't get the price of the item and shipping in a clean way to the UI, so I have to do this.
if(balance < price)
to_chat(user, span_warning("You don't have enough credits in [uplink] for [I] with [method] shipping."))
return FALSE
if(I.buy(uplink, user, method))
uplink.current_user.adjust_money(-price, "Other: Third Party Transaction")
if(ismob(user))
var/mob/m_user = user
m_user.playsound_local(get_turf(m_user), 'sound/machines/twobeep_high.ogg', 50, TRUE)
return TRUE
if(!istype(uplink) || !((method in shipping) || (method in item.shipping_override)))
return FALSE
var/shipment_fee = item.shipping_override?[method]
if(isnull(shipment_fee))
shipment_fee = shipping[method]
var/price = item.price + shipment_fee
if(!uplink.current_user)///There is no ID card on the user, or the ID card has no account
to_chat(user, span_warning("The uplink sparks, as it can't identify an ID card with a bank account on you."))
return FALSE
var/balance = uplink?.current_user.account_balance
// I can't get the price of the item and shipping in a clean way to the UI, so I have to do this.
if(balance < price)
to_chat(user, span_warning("You don't have enough credits in [uplink] for [item] with [method] shipping."))
return FALSE
if(item.buy(uplink, user, method))
uplink.current_user.adjust_money(-price, "Other: Third Party Transaction")
if(ismob(user))
var/mob/m_user = user
m_user.playsound_local(get_turf(m_user), 'sound/machines/twobeep_high.ogg', 50, TRUE)
return TRUE
return FALSE
/datum/market/blackmarket
name = "Black Market"
shipping = list(SHIPPING_METHOD_LTSRBT =50,
SHIPPING_METHOD_LAUNCH =10,
SHIPPING_METHOD_TELEPORT=75)
shipping = list(
SHIPPING_METHOD_LTSRBT = 40,
SHIPPING_METHOD_LAUNCH = 10,
SHIPPING_METHOD_TELEPORT= 75,
)
+62 -11
View File
@@ -14,7 +14,7 @@
var/stock
/// Path to or the item itself what this entry is for, this should be set even if you override spawn_item to spawn your item.
var/obj/item/item
var/atom/movable/item
/// Minimum price for the item if generated randomly.
var/price_min = 0
@@ -27,27 +27,60 @@
/// Probability for this item to be available. Used by SSblackmarket on init.
var/availability_prob = 0
///The identifier for the market item, generated on runtime and used to access them in the market categories.
var/identifier
///If set, these will override the shipment methods set by the market
var/list/shipping_override
/datum/market_item/New()
if(isnull(price))
price = rand(price_min, price_max)
if(isnull(stock))
stock = rand(stock_min, stock_max)
identifier = "[type]"
///For 'dynamic' market items generated on runtime, this proc is to be used to properly sets the item, especially if it's a hardref.
/datum/market_item/proc/set_item(path_or_ref)
//we're replacing the item to sell, and the old item is an instance!
if(ismovable(item))
UnregisterSignal(item, COMSIG_QDELETING)
item = path_or_ref
identifier = "[path_or_ref]"
if(ismovable(path_or_ref))
RegisterSignal(item, COMSIG_QDELETING, PROC_REF(on_item_del))
identifier = "[REF(src)]"
/datum/market_item/Destroy()
item = null
return ..()
/datum/market_item/proc/on_item_del(datum/source)
SIGNAL_HANDLER
qdel(src)
/// Used for spawning the wanted item, override if you need to do something special with the item.
/datum/market_item/proc/spawn_item(loc)
/datum/market_item/proc/spawn_item(loc, datum/market_purchase/purchase)
SHOULD_CALL_PARENT(TRUE)
SEND_SIGNAL(src, COMSIG_MARKET_ITEM_SPAWNED, purchase.uplink, purchase.method, loc)
if(ismovable(item))
item.forceMove(loc)
return item
var/atom/movable/return_item = item
UnregisterSignal(item, COMSIG_QDELETING)
if(isnull(loc))
item.moveToNullspace()
else
do_sparks(8, FALSE, item)
item.visible_message(span_notice("[item] vanishes..."))
item.forceMove(loc)
item = null
return return_item
if(ispath(item))
return new item(loc)
CRASH("Invalid item type for market item [item || "null"]")
/// Buys the item and makes SSblackmarket handle it.
/datum/market_item/proc/buy(obj/item/market_uplink/uplink, mob/buyer, shipping_method)
SHOULD_CALL_PARENT(TRUE)
// Sanity
if(!istype(uplink) || !istype(buyer))
return FALSE
@@ -70,16 +103,34 @@
/datum/market_purchase
/// The entry being purchased.
var/datum/market_item/entry
/// Instance of the item being sent.
var/item
/// Instance of the item being sent, used by the market telepad
var/atom/movable/item
/// The uplink where this purchase was done from.
var/obj/item/market_uplink/uplink
/// Shipping method used to buy this item.
var/method
/datum/market_purchase/New(_entry, _uplink, _method)
entry = _entry
if(!ispath(entry.item))
/datum/market_purchase/New(datum/market_item/entry, obj/item/market_uplink/uplink, method)
if(!uplink || !entry || !method)
CRASH("[type] created with a false value arg: (entry: [entry] - uplink: [uplink] - method: [method])")
src.entry = entry
src.uplink = uplink
src.method = method
RegisterSignal(entry, COMSIG_QDELETING, PROC_REF(on_instance_del))
RegisterSignal(uplink, COMSIG_QDELETING, PROC_REF(on_instance_del))
if(ismovable(entry.item))
item = entry.item
uplink = _uplink
method = _method
RegisterSignal(entry.item, COMSIG_QDELETING, PROC_REF(on_instance_del))
/datum/market_purchase/Destroy()
entry = null
uplink = null
SSblackmarket.queued_purchases -= src
return ..()
/datum/market_purchase/proc/on_instance_del(datum/source)
SIGNAL_HANDLER
if(QDELETED(src))
return
// Uh oh, uplink or item is gone. We will just keep the money and you will not get your order.
qdel(src)
@@ -39,7 +39,8 @@
/obj/item/storage/pill_bottle/lsd,
/obj/item/storage/pill_bottle/aranesp,
/obj/item/storage/pill_bottle/stimulant))
return new pillbottle(loc)
item = pillbottle
return ..()
/datum/market_item/consumable/floor_pill
name = "Strange Pill"
@@ -0,0 +1,84 @@
///A special category for mobs captured by pirates, tots and contractors, should someone ever want to get them back in advance.
/datum/market_item/hostage
category = "Hostages"
stock = 1
availability_prob = 100
shipping_override = list(SHIPPING_METHOD_LTSRBT = 0, SHIPPING_METHOD_SUPPLYPOD = 350)
/// temporary reference to the 4 in 7 chances of signaler and electropack.
var/obj/item/assembly/signaler/signaler
/datum/market_item/hostage/New(mob/living/mob, new_price)
..()
set_item(mob)
name = "[mob.real_name]"
var/specimen = initial(mob.name)
var/humie_mob = ishuman(mob)
if(humie_mob)
var/mob/living/carbon/human/humie = mob
specimen = humie.dna.species.name
desc = pick(list(
"If you're looking for a recently stolen [specimen], you've come to the right place.",
"we've recently aquired a fine [specimen] from a station around here, eheh...",
"For a limited time, we're offering this [specimen] for you to buy (back).",
))
desc += " DISCLAIMER: The offer will expire once the creature is returned to the station."
if(humie_mob)
desc += "[mob.p_they(TRUE)] may be delivered handcuffed, for safety of course."
price = new_price
RegisterSignal(mob, COMSIG_LIVING_RETURN_FROM_CAPTURE, PROC_REF(on_return_from_capture))
/datum/market_item/hostage/proc/on_return_from_capture(mob/living/source, turf/destination)
SIGNAL_HANDLER
qdel(src) //as if we never existed, our mentions we'll be removed from the market.
/datum/market_item/hostage/Destroy()
signaler = null
return ..()
/datum/market_item/hostage/buy(obj/item/market_uplink/uplink, mob/buyer, shipping_method)
. = ..()
var/mob/living/humie = item
if(!. || !istype(humie) || !prob(57)) // 3 in 7 chance of the electropack set not spawning...
return
signaler = new(uplink.drop_location())
RegisterSignal(signaler, COMSIG_QDELETING, PROC_REF(clear_signaler_ref))
signaler.set_frequency(sanitize_frequency(rand(MIN_FREE_FREQ, MAX_FREE_FREQ)))
signaler.code = rand(1, 100)
buyer.put_in_hands(signaler)
to_chat(buyer, span_notice("A [signaler] appears [buyer.is_holding(signaler) ? "in your hands" : "at your feet"]!"))
/datum/market_item/hostage/proc/clear_signaler_ref(datum/source)
SIGNAL_HANDLER
signaler = null
/datum/market_item/hostage/spawn_item(loc, datum/market_purchase/purchase)
var/mob/living/mob = item
UnregisterSignal(mob, COMSIG_LIVING_RETURN_FROM_CAPTURE)
if(!mob.IsUnconscious())
to_chat(mob, span_boldnicegreen("You have been <u>bought</u> back to the station. Be grateful to whoever got you out of the holding facility early."))
if(!ishuman(item))
return ..()
var/mob/living/carbon/human/humie = item
if(signaler) //57% chance that the mob is equipped with electropack and cuffs
humie.equip_to_slot_or_del(new /obj/item/restraints/handcuffs, ITEM_SLOT_HANDCUFFED, indirect_action = TRUE)
if(humie.back) //try to remove the neck item if possible before we attempt to install the collar bomb
humie.transferItemToLoc(humie.back, loc)
var/obj/item/electropack/pack = new(loc)
pack.set_frequency(signaler.frequency)
pack.code = signaler.code
humie.equip_to_slot_if_possible(pack, ITEM_SLOT_BACK, disable_warning = TRUE)
UnregisterSignal(signaler, COMSIG_QDELETING)
signaler = null
else if(prob(66)) // 29% chance of just cuffs
humie.equip_to_slot_or_del(new /obj/item/restraints/handcuffs, ITEM_SLOT_HANDCUFFED, indirect_action = TRUE)
else // 14% chance of just a tee souvenir and pin, no cuffs and shit.
var/obj/item/clothing/under/misc/syndicate_souvenir/souvenir = new(loc)
humie.equip_to_slot_if_possible(souvenir, ITEM_SLOT_ICLOTHING, indirect_action = TRUE)
var/obj/item/clothing/accessory/anti_sec_pin/pin = new(loc)
pin.attach(souvenir)
if(isnull(humie.w_uniform))
//FUCKING SLAVES, GET YOUR CLOTHES BACK ON!
humie.equip_to_slot_or_del(new /obj/item/clothing/under/costume/jabroni(humie), ITEM_SLOT_ICLOTHING, indirect_action = TRUE)
return ..()
@@ -68,9 +68,11 @@
stock_max = 3
availability_prob = 40
/datum/market_item/misc/holywater/spawn_item(loc)
/datum/market_item/misc/holywater/spawn_item(loc, datum/market_purchase/purchase)
if (prob(6.66))
return new /obj/item/reagent_containers/cup/beaker/unholywater(loc)
item = /obj/item/reagent_containers/cup/beaker/unholywater
else
item = initial(item)
return ..()
/datum/market_item/misc/strange_seed
@@ -0,0 +1,12 @@
///A special category for goods stolen by spies for their bounties.
/datum/market_item/stolen_good
category = "Fenced Goods"
stock = 1
availability_prob = 100
/datum/market_item/stolen_good/New(atom/movable/thing, thing_price)
..()
set_item(thing)
name = "Stolen [thing.name]"
desc = "A [thing.name], stolen from somewhere on the station. Whoever owned it probably wouldn't be happy to see it here."
price = thing_price
@@ -1,6 +1,18 @@
/datum/market_item/tool
category = "Tools"
/datum/market_item/tool/blackmarket_telepad
name = "Black Market LTSRBT"
desc = "Need a faster and better way of transporting your illegal goods from and to the \
station? Fear not, the Long-To-Short-Range-Bluespace-Transceiver is here to help. \
Contains a LTSRBT circuit. Bluespace crystals and ansible not included."
item = /obj/item/circuitboard/machine/ltsrbt
stock_min = 2
stock_max = 4
price_min = CARGO_CRATE_VALUE * 2.5
price_max = CARGO_CRATE_VALUE * 3.75
availability_prob = 100
/datum/market_item/tool/caravan_wrench
name = "Experimental Wrench"
desc = "The extra fast and handy wrench you always wanted!"
+26 -24
View File
@@ -26,13 +26,13 @@
/// The time it takes for the machine to recharge before being able to send or receive items.
var/recharge_time = 0
/// Current recharge progress.
var/recharge_cooldown = 0
COOLDOWN_DECLARE(recharge_cooldown)
/// Base recharge time in seconds which is used to get recharge_time.
var/base_recharge_time = 100
/// Current /datum/market_purchase being received.
var/receiving
var/datum/market_purchase/receiving
/// Current /datum/market_purchase being sent to the target uplink.
var/transmitting
var/datum/market_purchase/transmitting
/// Queue for purchases that the machine should receive and send.
var/list/datum/market_purchase/queue = list()
@@ -67,46 +67,48 @@
/obj/machinery/ltsrbt/proc/add_to_queue(datum/market_purchase/purchase)
if(!recharge_cooldown && !receiving && !transmitting)
receiving = purchase
return
queue += purchase
else
queue += purchase
RegisterSignal(receiving, COMSIG_QDELETING, PROC_REF(on_receiving_del))
/obj/machinery/ltsrbt/proc/on_receiving_del(datum/market_purchase/purchase)
SIGNAL_HANDLER
queue -= purchase
if(receiving == purchase)
receiving = null
if(transmitting == purchase)
transmitting = null
/obj/machinery/ltsrbt/process(seconds_per_tick)
if(machine_stat & NOPOWER)
return
if(recharge_cooldown > 0)
recharge_cooldown -= seconds_per_tick
if(!COOLDOWN_FINISHED(src, recharge_cooldown) && isnull(receiving) && isnull(transmitting))
return
var/turf/T = get_turf(src)
if(receiving)
var/datum/market_purchase/P = receiving
COOLDOWN_START(src, recharge_cooldown, recharge_time)
P.item = P.entry.spawn_item(T)
var/turf/turf = get_turf(src)
if(receiving)
receiving.item = receiving.entry.spawn_item(turf, receiving)
use_power(power_usage_per_teleport / power_efficiency)
var/datum/effect_system/spark_spread/sparks = new
sparks.set_up(5, 1, get_turf(src))
sparks.attach(P.item)
sparks.attach(receiving.item)
sparks.start()
transmitting = receiving
receiving = null
transmitting = P
recharge_cooldown = recharge_time
return
else if(transmitting)
var/datum/market_purchase/P = transmitting
if(!P.item)
QDEL_NULL(transmitting)
if(!(P.item in T.contents))
QDEL_NULL(transmitting)
return
do_teleport(P.item, get_turf(P.uplink))
use_power(power_usage_per_teleport / power_efficiency)
if(transmitting)
if(transmitting.item.loc == turf)
do_teleport(transmitting.item, get_turf(transmitting.uplink))
use_power(power_usage_per_teleport / power_efficiency)
QDEL_NULL(transmitting)
recharge_cooldown = recharge_time
return
if(queue.len)
+18 -13
View File
@@ -9,7 +9,7 @@
var/viewing_category
/// What market is currently being bought from by the uplink?
var/viewing_market
/// What item is the current uplink attempting to buy?
/// the identifier of the item that the current uplink is attempting to buy
var/selected_item
/// Is the uplink in the process of buying the selected item?
var/buying
@@ -56,25 +56,31 @@
current_user = null
data["categories"] = market ? market.categories : null
data["delivery_methods"] = list()
if(market)
for(var/delivery in market.shipping)
data["delivery_methods"] += list(list("name" = delivery, "price" = market.shipping[delivery]))
data["money"] = "N/A cr"
if(current_user)
data["money"] = current_user.account_balance
data["buying"] = buying
if(buying && market)
var/datum/market_item/target_item = market.available_items[viewing_category][selected_item]
var/list/shipping_list = market.shipping
if(length(target_item?.shipping_override))
shipping_list = target_item.shipping_override
for(var/delivery in shipping_list)
UNTYPED_LIST_ADD(data["delivery_methods"], list("name" = delivery, "price" = shipping_list[delivery]))
data["items"] = list()
data["viewing_category"] = viewing_category
data["viewing_category"] = market.categories[viewing_category] ? viewing_category : null
data["viewing_market"] = viewing_market
if(viewing_category && market)
if(market.available_items[viewing_category])
for(var/datum/market_item/I in market.available_items[viewing_category])
var/list/market_category = market.available_items[viewing_category]
for(var/id in market_category)
var/datum/market_item/item = market_category[id]
data["items"] += list(list(
"id" = I.type,
"name" = I.name,
"cost" = I.price,
"amount" = I.stock,
"desc" = I.desc || I.name
"id" = id,
"name" = item.name,
"cost" = item.price,
"amount" = item.stock,
"desc" = item.desc || item.name
))
return data
@@ -123,8 +129,7 @@
if("select")
if(isnull(params["item"]))
return
var/item = text2path(params["item"])
selected_item = item
selected_item = params["item"]
buying = TRUE
. = TRUE
if("cancel")
-13
View File
@@ -118,19 +118,6 @@
if(prob(10)) //A little extra sugar every now and then to shake things up.
new /obj/item/switchblade(our_crate)
/datum/supply_pack/imports/blackmarket_telepad
name = "Black Market LTSRBT"
desc = "Need a faster and better way of transporting your illegal goods from and to the \
station? Fear not, the Long-To-Short-Range-Bluespace-Transceiver (LTSRBT for short) \
is here to help. Contains a LTSRBT circuit, two bluespace crystals, and one ansible."
cost = CARGO_CRATE_VALUE * 20
contraband = TRUE
contains = list(
/obj/item/circuitboard/machine/ltsrbt,
/obj/item/stack/ore/bluespace_crystal/artificial = 2,
/obj/item/stock_parts/subspace/ansible,
)
/datum/supply_pack/imports/contraband
name = "'Contraband' Crate"
desc = "Psst.. bud... want some contraband? I can get you a poster, some nice cigs, dank, even some \
+18
View File
@@ -241,6 +241,24 @@
/obj/structure/closet/supplypod/open(mob/living/user, force = FALSE, special_effects = TRUE)
return
///Called by the drop pods that return captured crewmembers from the ninja den.
/obj/structure/closet/supplypod/proc/return_from_capture(mob/living/victim, turf/destination = get_safe_random_station_turf())
if(isnull(destination)) //Uuuuh, something went wrong. This is gonna hurt.
to_chat(victim, span_hypnophrase("A million voices echo in your head... \"Seems where you got sent won't \
be able to handle our pod... as if we wanted the occupant to survive. Brace yourself, corporate dog.\""))
flags_1 &= ~PREVENT_CONTENTS_EXPLOSION_1
explosionSize = list(0,1,1,1)
destination = get_random_station_turf()
do_sparks(8, FALSE, victim)
victim.visible_message(span_notice("[victim] vanishes..."))
victim.forceMove(src)
new /obj/effect/pod_landingzone(destination, src)
SEND_SIGNAL(victim, COMSIG_LIVING_RETURN_FROM_CAPTURE, destination)
/obj/structure/closet/supplypod/proc/handleReturnAfterDeparting(atom/movable/holder = src)
reversing = FALSE //Now that we're done reversing, we set this to false (otherwise we would get stuck in an infinite loop of calling the close proc at the bottom of open_pod() )
bluespace = TRUE //Make it so that the pod doesn't stay in centcom forever
@@ -218,8 +218,8 @@ GLOBAL_LIST_INIT(pride_pin_reskins, list(
/obj/item/clothing/accessory/anti_sec_pin/attach(obj/item/clothing/under/attach_to, mob/living/attacher)
. = ..()
if (!.)
return FALSE
if (!. || isnull(attacher))
return
var/target = ishuman(attach_to.loc) ? attach_to.loc : attach_to
log_combat(attacher, target, "pinned an 'arrest me immediately' pin onto", src)
+20
View File
@@ -2615,6 +2615,26 @@ GLOBAL_LIST_EMPTY(fire_appearances)
SEND_SIGNAL(src, COMSIG_LIVING_UNFRIENDED, old_friend)
return TRUE
/**
* Common proc used to deduct money from cargo, announce the kidnapping and add src to the black market.
* Returns the black market item, for extra stuff like signals that need to be registered.
*/
/mob/living/proc/process_capture(ransom_price, black_market_price)
if(ransom_price > 0)
var/datum/bank_account/cargo_account = SSeconomy.get_dep_account(ACCOUNT_CAR)
if(cargo_account) //Just in case
cargo_account.adjust_money(-min(ransom_price, cargo_account.account_balance)) //Not so much, especially for competent cargo. Plus this can't be mass-triggered like it has been done with contractors
priority_announce("One of your crew was captured by a rival organisation - we've needed to pay their ransom to bring them back. As is policy we've taken a portion of the station's funds to offset the overall cost.", "Nanotrasen Asset Protection", has_important_message = TRUE)
///The price should be high enough that the contractor can't just buy 'em back with their cut alone.
var/datum/market_item/hostage/market_item = new(src, black_market_price || ransom_price)
SSblackmarket.markets[/datum/market/blackmarket].add_item(market_item)
if(mind)
ADD_TRAIT(mind, TRAIT_HAS_BEEN_KIDNAPPED, TRAIT_GENERIC)
return market_item
/// Admin only proc for making the mob hallucinate a certain thing
/mob/living/proc/admin_give_hallucination(mob/admin)
if(!admin || !check_rights(NONE))
+3
View File
@@ -293,6 +293,7 @@
#include "code\__DEFINES\dcs\signals\signals_backpack.dm"
#include "code\__DEFINES\dcs\signals\signals_beam.dm"
#include "code\__DEFINES\dcs\signals\signals_bitrunning.dm"
#include "code\__DEFINES\dcs\signals\signals_blackmarket.dm"
#include "code\__DEFINES\dcs\signals\signals_blob.dm"
#include "code\__DEFINES\dcs\signals\signals_bot.dm"
#include "code\__DEFINES\dcs\signals\signals_camera.dm"
@@ -3655,7 +3656,9 @@
#include "code\modules\cargo\markets\market_uplink.dm"
#include "code\modules\cargo\markets\market_items\clothing.dm"
#include "code\modules\cargo\markets\market_items\consumables.dm"
#include "code\modules\cargo\markets\market_items\hostages.dm"
#include "code\modules\cargo\markets\market_items\misc.dm"
#include "code\modules\cargo\markets\market_items\stolen_goods.dm"
#include "code\modules\cargo\markets\market_items\tools.dm"
#include "code\modules\cargo\markets\market_items\weapons.dm"
#include "code\modules\cargo\packs\_packs.dm"