Skip to content

Commit

Permalink
[MIRROR] Adds new black market pin [MDB IGNORE] (#25569)
Browse files Browse the repository at this point in the history
* Adds new black market pin (#80230)

## About The Pull Request

![image](https://github.com/tgstation/tgstation/assets/7483112/add49cea-8318-475b-985e-3cb14a1d39db)

Adds a fetching red pin which you can wear to visibly align yourself
with the enemies of Nanotrasen, purchaseable from the Black Market
Uplink.
This pin's contained RFID chip will automatically cause you to appear on
Sec HUDs as a wanted criminal and will aggro securitrons, to prove your
dedication to your ideals.

If your convictions are a little less firm, you can also silently pin
this onto _other_ people's clothing if they stand still next to you for
five seconds... though they might notice that they're suddenly wearing a
red badge.

I didn't want this to be a subtype of medal so I made the "you can put
this accessory onto someone else" behaviour into a component to sidestep
object inheritance.
This has been applied to the detective's spy camera, because it makes it
much easier to turn someone into a mole.

This also adds a trait which makes security hate you which I guess
someone could use in a novelty bar drink at some point or something.

## Why It's Good For The Game

It's funny
I think we need more neat things in the black market to make it
sometimes worth using

## Changelog

:cl:
add: Added subversive pins to the black market uplink which make
security hate you
add: The detective's spy cam can now be conveniently pinned onto people
in the same manner as medals
/:cl:

* Adds new black market pin

---------

Co-authored-by: Jacquerel <[email protected]>
  • Loading branch information
2 people authored and FFMirrorBot committed Dec 12, 2023
1 parent 88e65c2 commit bee1f1c
Show file tree
Hide file tree
Showing 12 changed files with 146 additions and 51 deletions.
3 changes: 3 additions & 0 deletions code/__DEFINES/traits/declarations.dm
Original file line number Diff line number Diff line change
Expand Up @@ -1014,4 +1014,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
///Trait given when a mob has been tipped
#define TRAIT_MOB_TIPPED "mob_tipped"

/// Trait which self-identifies as an enemy of the law
#define TRAIT_ALWAYS_WANTED "always_wanted"

// END TRAIT DEFINES
1 change: 1 addition & 0 deletions code/_globalvars/traits/_traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_CLUMSY" = TRAIT_CLUMSY,
"TRAIT_COAGULATING" = TRAIT_COAGULATING,
"TRAIT_CORPSELOCKED" = TRAIT_CORPSELOCKED,
"TRAIT_ALWAYS_WANTED" = TRAIT_ALWAYS_WANTED,
"TRAIT_CRITICAL_CONDITION" = TRAIT_CRITICAL_CONDITION,
"TRAIT_CULT_HALO" = TRAIT_CULT_HALO,
"TRAIT_CURSED" = TRAIT_CURSED,
Expand Down
80 changes: 80 additions & 0 deletions code/datums/components/pinnable_accessory.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/// This accessory can be pinned onto someone else
/datum/component/pinnable_accessory
/// Do we let people know what we're doing?
var/silent
/// How long does it take to pin this onto someone?
var/pinning_time
/// Optional callback invoked before pinning, will cancel if it returns FALSE
var/datum/callback/on_pre_pin

/datum/component/pinnable_accessory/Initialize(silent = FALSE, pinning_time = 2 SECONDS, datum/callback/on_pre_pin = null)
. = ..()
if (!istype(parent, /obj/item/clothing/accessory))
return COMPONENT_INCOMPATIBLE
src.silent = silent
src.pinning_time = pinning_time
src.on_pre_pin = on_pre_pin

/datum/component/pinnable_accessory/RegisterWithParent()
RegisterSignal(parent, COMSIG_ITEM_INTERACTING_WITH_ATOM, PROC_REF(on_atom_interact))

/datum/component/pinnable_accessory/UnregisterFromParent()
UnregisterSignal(parent, COMSIG_ITEM_INTERACTING_WITH_ATOM)

/// Called when you whack someone with this accessory
/datum/component/pinnable_accessory/proc/on_atom_interact(obj/item/clothing/accessory/badge, mob/living/user, atom/target, modifiers)
SIGNAL_HANDLER
if (!ishuman(target) || target == user)
return

INVOKE_ASYNC(src, PROC_REF(try_to_pin), badge, target, user)
return COMPONENT_CANCEL_ATTACK_CHAIN

/// Actually try to pin it on
/datum/component/pinnable_accessory/proc/try_to_pin(obj/item/clothing/accessory/badge, mob/living/carbon/human/distinguished, mob/user)
var/obj/item/clothing/under/distinguished_uniform = distinguished.w_uniform
if(!istype(distinguished_uniform))
distinguished.balloon_alert(user, "no uniform to pin on!")
return

if(!badge.can_attach_accessory(distinguished_uniform, user))
// Check handles feedback messages and etc
return

if (!silent)
user.visible_message(
span_notice("[user] tries to pin [badge] on [distinguished]'s chest."),
span_notice("You try to pin [badge] on [distinguished]'s chest."),
)

if (on_pre_pin && !on_pre_pin.Invoke(distinguished, user))
return
if(!pin_checks(user, distinguished) || !do_after(user, pinning_time, distinguished, extra_checks = CALLBACK(src, PROC_REF(pin_checks), user, distinguished)))
return

var/pinned = distinguished_uniform.attach_accessory(badge, user)
if (silent)
return

if (pinned)
user.visible_message(
span_notice("[user] pins [badge] on [distinguished]'s chest."),
span_notice("You pin [badge] on [distinguished]'s chest."),
)
else
user.visible_message(
span_warning("[user] fails to pin [badge] on [distinguished]'s chest, seemingly unable to part with it."),
span_warning("You fail to pin [badge] on [distinguished]'s chest."),
)

/// Callback for do_after to check if we can still be pinned
/datum/component/pinnable_accessory/proc/pin_checks(mob/living/pinner, mob/living/carbon/human/pinning_on)
if(QDELETED(parent) || QDELETED(pinner) || QDELETED(pinning_on))
return FALSE
if(!pinner.is_holding(parent) || !pinner.Adjacent(pinning_on))
return FALSE
var/obj/item/clothing/accessory/badge = parent
var/obj/item/clothing/under/pinning_on_uniform = pinning_on.w_uniform
if(!istype(pinning_on_uniform) || !badge.can_attach_accessory(pinning_on_uniform, pinner))
return FALSE
return TRUE
6 changes: 6 additions & 0 deletions code/game/data_huds.dm
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,12 @@ Security HUDs! Basic mode shows only the job.
var/image/holder = hud_list[WANTED_HUD]
var/icon/sec_icon = icon(icon, icon_state, dir)
holder.pixel_y = sec_icon.Height() - world.icon_size

if (HAS_TRAIT(src, TRAIT_ALWAYS_WANTED))
holder.icon_state = "hudwanted"
set_hud_image_active(WANTED_HUD)
return

var/perp_name = get_face_name(get_id_name(""))

if(!perp_name || !GLOB.manifest)
Expand Down
6 changes: 5 additions & 1 deletion code/game/objects/items/devices/spyglasses.dm
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,18 @@
icon = 'icons/obj/clothing/accessories.dmi'
icon_state = "pocketprotector"
desc = "An advanced piece of espionage equipment in the shape of a pocket protector. It has a built in 360 degree camera for all your \"admirable\" needs. Microphone not included."
/// The glasses that you can use to see what this can see
var/obj/item/clothing/glasses/sunglasses/spy/linked_glasses
/// Our camera display popup
var/atom/movable/screen/map_view/cam_screen
// Ranges higher than one can be used to see through walls.
/// How far can we actually see? Ranges higher than one can be used to see through walls.
var/cam_range = 1
/// Detects when we move to update the camera view
var/datum/movement_detector/tracker

/obj/item/clothing/accessory/spy_bug/Initialize(mapload)
. = ..()
AddComponent(/datum/component/pinnable_accessory)
tracker = new /datum/movement_detector(src, CALLBACK(src, PROC_REF(update_view)))
cam_screen = new
cam_screen.generate_view("spypopup_map")
Expand Down
11 changes: 11 additions & 0 deletions code/modules/cargo/markets/market_items/clothing.dm
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,14 @@
price_max = CARGO_CRATE_VALUE * 15
stock_max = 1
availability_prob = 40

/datum/market_item/clothing/anti_sec_pin
name = "Subversive Pin"
desc = "Exclusive and fashionable red pin from a limited run, proclaiming your allegiance to enemies of the Nanotrasen corporation. \
Contains an RFID chip which interferes with common scanning equipment, to ensure that they know you are serious. Share them with your friends!"
item = /obj/item/clothing/accessory/anti_sec_pin

price_min = CARGO_CRATE_VALUE * 0.5
price_max = CARGO_CRATE_VALUE * 1.5
stock_max = 5
availability_prob = 70
33 changes: 33 additions & 0 deletions code/modules/clothing/under/accessories/badges.dm
Original file line number Diff line number Diff line change
Expand Up @@ -205,3 +205,36 @@ GLOBAL_LIST_INIT(pride_pin_reskins, list(
name = "debt payer pin"
desc = "I've paid my debt and all I've got was this pin."
icon_state = "debt_payer_pin"

/// Self-identify as a dangerous subversive
/obj/item/clothing/accessory/anti_sec_pin
name = "subversive pin"
desc = "A badge which loudly and proudly proclaims your hostility to the Nanotrasen Security Team, and authority in general."
icon_state = "anti_sec"

/obj/item/clothing/accessory/anti_sec_pin/Initialize(mapload)
. = ..()
AddComponent(/datum/component/pinnable_accessory, silent = TRUE, pinning_time = 5 SECONDS)

/obj/item/clothing/accessory/anti_sec_pin/attach(obj/item/clothing/under/attach_to, mob/living/attacher)
. = ..()
if (!.)
return FALSE

var/target = ishuman(attach_to.loc) ? attach_to.loc : attach_to
log_combat(attacher, target, "pinned an 'arrest me immediately' pin onto", src)
return TRUE

/obj/item/clothing/accessory/anti_sec_pin/accessory_equipped(obj/item/clothing/under/clothes, mob/living/user)
. = ..()
ADD_TRAIT(user, TRAIT_ALWAYS_WANTED, "[CLOTHING_TRAIT]_[REF(src)]")
if (ishuman(user))
var/mob/living/carbon/human/human_wearer = user
human_wearer.sec_hud_set_security_status()

/obj/item/clothing/accessory/anti_sec_pin/accessory_dropped(obj/item/clothing/under/clothes, mob/living/user)
. = ..()
REMOVE_TRAIT(user, TRAIT_ALWAYS_WANTED, "[CLOTHING_TRAIT]_[REF(src)]")
if (ishuman(user))
var/mob/living/carbon/human/human_wearer = user
human_wearer.sec_hud_set_security_status()
54 changes: 5 additions & 49 deletions code/modules/clothing/under/accessories/medals.dm
Original file line number Diff line number Diff line change
Expand Up @@ -13,58 +13,14 @@
/// Who gave out this medal
var/awarder

/// Callback for do_after to check if we can still be pinned
/obj/item/clothing/accessory/medal/proc/pin_checks(mob/living/pinner, mob/living/carbon/human/pinning_on)
if(QDELETED(src) || QDELETED(pinner) || QDELETED(pinning_on))
return FALSE
if(!pinner.is_holding(src) || !pinner.Adjacent(pinning_on))
return FALSE
var/obj/item/clothing/under/pinning_on_uniform = pinning_on.w_uniform
if(!istype(pinning_on_uniform) || !can_attach_accessory(pinning_on_uniform, pinner))
return FALSE
return TRUE

/obj/item/clothing/accessory/medal/pre_attack(atom/target, mob/living/user, params)
/obj/item/clothing/accessory/medal/Initialize(mapload)
. = ..()
if(.)
return
if(!ishuman(target) || target == user)
return

. = TRUE // no attack chain please

var/mob/living/carbon/human/distinguished = target
var/obj/item/clothing/under/distinguished_uniform = distinguished.w_uniform
if(!istype(distinguished_uniform))
distinguished.balloon_alert(user, "no uniform to pin on!")
return .
if(!can_attach_accessory(distinguished_uniform, user))
// Check handles feedback messages and etc
return .

user.visible_message(
span_notice("[user] tries to pin [src] on [distinguished]'s chest."),
span_notice("You try to pin [src] on [distinguished]'s chest."),
)
AddComponent(/datum/component/pinnable_accessory, on_pre_pin = CALLBACK(src, PROC_REF(provide_reason)))

/// Input a reason for the medal for the round end screen
/obj/item/clothing/accessory/medal/proc/provide_reason(mob/living/carbon/human/distinguished, mob/user)
commendation_message = tgui_input_text(user, "Reason for this commendation? It will be recorded by Nanotrasen.", "Commendation", max_length = 140)
if(!commendation_message || !pin_checks(user, distinguished))
return .
if(!do_after(user, 2 SECONDS, distinguished, extra_checks = CALLBACK(src, PROC_REF(pin_checks), user, distinguished)))
return .

if(distinguished_uniform.attach_accessory(src, user))
user.visible_message(
span_notice("[user] pins [src] on [distinguished]'s chest."),
span_notice("You pin [src] on [distinguished]'s chest."),
)
else
user.visible_message(
span_warning("[user] fails to pin [src] on [distinguished]'s chest, seemingly unable to part with it."),
span_warning("You fail to pin [src] on [distinguished]'s chest."),
)

return .
return !!commendation_message

/obj/item/clothing/accessory/medal/attach(obj/item/clothing/under/attach_to, mob/living/attacher)
var/mob/living/distinguished = attach_to.loc
Expand Down
2 changes: 1 addition & 1 deletion code/modules/mob/living/carbon/human/human.dm
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@
#define CHECK_PERMIT(item) (item && item.item_flags & NEEDS_PERMIT)

/mob/living/carbon/human/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null)
if(judgement_criteria & JUDGE_EMAGGED)
if(judgement_criteria & JUDGE_EMAGGED || HAS_TRAIT(src, TRAIT_ALWAYS_WANTED))
return 10 //Everyone is a criminal!

var/threatcount = 0
Expand Down
Binary file modified icons/mob/clothing/accessories.dmi
Binary file not shown.
Binary file modified icons/obj/clothing/accessories.dmi
Binary file not shown.
1 change: 1 addition & 0 deletions tgstation.dme
Original file line number Diff line number Diff line change
Expand Up @@ -1207,6 +1207,7 @@
#include "code\datums\components\pellet_cloud.dm"
#include "code\datums\components\phylactery.dm"
#include "code\datums\components\pinata.dm"
#include "code\datums\components\pinnable_accessory.dm"
#include "code\datums\components\plundering_attacks.dm"
#include "code\datums\components\pricetag.dm"
#include "code\datums\components\punchcooldown.dm"
Expand Down

0 comments on commit bee1f1c

Please sign in to comment.