Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
a19f63b
demodular
Shoddd Mar 14, 2026
87823b3
I dont like contractor
Shoddd Mar 14, 2026
5dbf364
https://github.com/tgstation/tgstation/pull/91969
Shoddd Mar 14, 2026
b221d8b
demodularization
Shoddd Mar 14, 2026
645f8c3
fixes some illegal tech
Shoddd Mar 14, 2026
1f0ce66
https://github.com/tgstation/tgstation/pull/88482
Shoddd Mar 14, 2026
f996e76
remove finals https://github.com/tgstation/tgstation/pull/79793
Shoddd Mar 14, 2026
4f732a7
'kill' secondarys
Shoddd Mar 14, 2026
aeec81c
25 tc
Shoddd Mar 14, 2026
bda739a
Merge branch 'master' of https://github.com/Monkestation/Monkestation…
Shoddd Mar 14, 2026
e0d7a16
lets not die
Shoddd Mar 14, 2026
e855708
accidental mega commit because I forgor, does a lot
Shoddd Mar 14, 2026
ee58aaa
finishes up cybernetics, ulti, and implants
Shoddd Mar 14, 2026
bf48791
even more general stuff, shotgun ammo
Shoddd Mar 14, 2026
cf6de0d
repricing recat complete
Shoddd Mar 14, 2026
8e6c146
deeply disturbing
Shoddd Mar 14, 2026
d72dd73
Merge branch 'master' of https://github.com/Monkestation/Monkestation…
Shoddd Mar 14, 2026
f35674e
I heart merge conflict
Shoddd Mar 14, 2026
9f00b3a
divider
Shoddd Mar 15, 2026
99d9a71
aa
Shoddd Mar 15, 2026
0d06216
forgor to commit
Shoddd Mar 16, 2026
ef56db1
aa
Shoddd Mar 17, 2026
d75fdd5
aaa
Shoddd Mar 18, 2026
2a220be
aaa
Shoddd Mar 18, 2026
3d5f492
I HATE TGUI
Shoddd Mar 18, 2026
fcbec8b
Mulligan Kit
Shoddd Mar 18, 2026
06fda7d
https://github.com/tgstation/tgstation/pull/91107
Shoddd Mar 18, 2026
b2ff255
smoke kit and implant
Shoddd Mar 18, 2026
f33552c
hello everypony
Shoddd Mar 18, 2026
8940d53
job items
Shoddd Mar 18, 2026
38a0498
https://github.com/tgstation/tgstation/pull/75696
Shoddd Mar 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion code/__DEFINES/antagonists.dm
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ GLOBAL_LIST_INIT(human_invader_antagonists, list(
#define MAROON_PROB 30

/// How many telecrystals a normal traitor starts with
#define TELECRYSTALS_DEFAULT 20
#define TELECRYSTALS_DEFAULT 25
/// How many telecrystals mapper/admin only "precharged" uplink implant
#define TELECRYSTALS_PRELOADED_IMPLANT 10
/// The normal cost of an uplink implant; used for calcuating how many
Expand Down
2 changes: 2 additions & 0 deletions code/__DEFINES/inventory.dm
Original file line number Diff line number Diff line change
Expand Up @@ -313,3 +313,5 @@ GLOBAL_LIST_INIT(mining_suit_allowed, list(
#define LOCATION_HEAD "on your head"
/// String for items placed in the neck slot.
#define LOCATION_NECK "around your neck"
/// String for items placed in the id slot
#define LOCATION_ID "in your ID slot"
1 change: 1 addition & 0 deletions code/__DEFINES/mobs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@
#define SENTIENCE_HUMANOID 3
#define SENTIENCE_MINEBOT 4
#define SENTIENCE_BOSS 5
#define SENTIENCE_PONY 6

//Mob AI Status
#define POWER_RESTORATION_OFF 0
Expand Down
21 changes: 21 additions & 0 deletions code/__DEFINES/uplink.dm
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
/// This item is purchasable to clown ops
#define UPLINK_CLOWN_OPS (1 << 2)

/// the uplink flag for contractors
#define UPLINK_CONTRACTORS (1 << 6)

/// Progression gets turned into a user-friendly form. This is just an abstract equation that makes progression not too large.
#define DISPLAY_PROGRESSION(time) round(time/60, 0.01)

Expand All @@ -23,3 +26,21 @@

/// Minimal cost for an item to be eligible for a discount
#define TRAITOR_DISCOUNT_MIN_PRICE 4

#define STARTING_COMMON_CONTRACTS 3
#define STARTING_UNCOMMON_CONTRACTS 2
#define STARTING_RARE_CONTRACTS 1
/datum/component/uplink/proc/become_contractor()
uplink_handler.uplink_flag = UPLINK_CONTRACTORS
uplink_handler.clear_secondaries()
uplink_handler.generate_objectives(list(
/datum/traitor_objective/target_player/kidnapping/common = STARTING_COMMON_CONTRACTS,
/datum/traitor_objective/target_player/kidnapping/uncommon = STARTING_UNCOMMON_CONTRACTS,
/datum/traitor_objective/target_player/kidnapping/rare = STARTING_RARE_CONTRACTS,
))
for(var/item in subtypesof(/datum/contractor_item))
uplink_handler.contractor_market_items += new item

#undef STARTING_COMMON_CONTRACTS
#undef STARTING_UNCOMMON_CONTRACTS
#undef STARTING_RARE_CONTRACTS
2 changes: 0 additions & 2 deletions code/__DEFINES/~monkestation/uplink.dm

This file was deleted.

8 changes: 5 additions & 3 deletions code/__HELPERS/game.dm
Original file line number Diff line number Diff line change
Expand Up @@ -257,11 +257,13 @@
return atom_to_find.loc

///Send a message in common radio when a player arrives
/proc/announce_arrival(mob/living/carbon/human/character, rank)
/proc/announce_arrival(mob/living/carbon/human/character, rank, announce_to_ghosts = TRUE)
if(!SSticker.IsRoundInProgress() || QDELETED(character))
return
var/area/player_area = get_area(character)
deadchat_broadcast("<span class='game'> has arrived at the station at <span class='name'>[player_area.name]</span>.</span>", "<span class='game'><span class='name'>[character.real_name]</span> ([rank])</span>", follow_target = character, message_type=DEADCHAT_ARRIVALRATTLE)
if (announce_to_ghosts)
var/area/player_area = get_area(character)

deadchat_broadcast("<span class='game'> has arrived at the station at <span class='name'>[player_area.name]</span>.</span>", "<span class='game'><span class='name'>[character.real_name]</span> ([rank])</span>", follow_target = character, message_type=DEADCHAT_ARRIVALRATTLE)
if(!character.mind)
return
if(!GLOB.announcement_systems.len)
Expand Down
1 change: 0 additions & 1 deletion code/datums/components/uplink.dm
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,6 @@
data["primary_objectives"] = primary_objectives
data["potential_objectives"] = potential_objectives
data["active_objectives"] = active_objectives
data["completed_final_objective"] = uplink_handler.final_objective

var/list/stock_list = uplink_handler.item_stock.Copy()
var/list/extra_purchasable_stock = list()
Expand Down
4 changes: 2 additions & 2 deletions code/datums/records/manifest.dm
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ GLOBAL_DATUM_INIT(manifest, /datum/manifest, new)


/// Injects a record into the manifest.
/datum/manifest/proc/inject(mob/living/carbon/human/person, client/person_client)
/datum/manifest/proc/inject(mob/living/carbon/human/person, client/person_client, atom/appearance_proxy)
set waitfor = FALSE
if(!(person.mind?.assigned_role.job_flags & JOB_CREW_MANIFEST))
return
Expand All @@ -108,7 +108,7 @@ GLOBAL_DATUM_INIT(manifest, /datum/manifest, new)
))

var/assignment = person.mind.assigned_role.title
var/mutable_appearance/character_appearance = new(person.appearance)
var/mutable_appearance/character_appearance = new(appearance_proxy?.appearance || person.appearance)
var/person_gender = "Other"
if(person.gender == "male")
person_gender = "Male"
Expand Down
122 changes: 122 additions & 0 deletions code/game/objects/items/devices/mulligan_kit.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/obj/item/fake_identity_kit
name = "fake identity kit"
desc = "All of the paperwork you need to get a fresh start and a perfect alibi, plus a little digital assistance to insert you into crew records."
icon = 'icons/obj/service/bureaucracy.dmi'
icon_state = "docs_mulligan"
w_class = WEIGHT_CLASS_TINY
interaction_flags_click = NEED_LITERACY|NEED_LIGHT|NEED_DEXTERITY|NEED_HANDS|ALLOW_RESTING
/// What do we set up our "new arrival" as?
var/assigned_job = JOB_ASSISTANT

/obj/item/fake_identity_kit/examine_more(mob/user)
. = ..()
. += span_info("Using this kit after exposure to Mulligan serum will create a fake identity for your new appearance.")
. += span_info("This will add you to various station manifests, create an Assistant-level ID card, and announce your arrival over the radio.")

/obj/item/fake_identity_kit/attack_self(mob/living/carbon/human/user, modifiers)
. = ..()
if (!ishuman(user))
balloon_alert(user, "can't pass as employee!")
return
if (find_record(user.real_name))
balloon_alert(user, "records already exist!")
return

user.temporarilyRemoveItemFromInventory(src)
user.playsound_local(user, 'sound/items/cardshuffle.ogg', 50, TRUE)

var/obj/item/card/id/advanced/original_id = user.get_idcard(hand_first = FALSE)
if (original_id)
user.temporarilyRemoveItemFromInventory(original_id)

var/datum/job/job = SSjob.GetJob(assigned_job)
user.mind.set_assigned_role(job)

var/datum/outfit/job_outfit = job.outfit
var/id_trim = job_outfit::id_trim
var/obj/item/card/id/advanced/fake_id = new()

if (id_trim)
SSid_access.apply_trim_to_card(fake_id, id_trim)
shuffle_inplace(fake_id.access)

fake_id.registered_name = user.real_name
if(user.age)
fake_id.registered_age = user.age
fake_id.update_label()
fake_id.update_icon()

var/placed_in = user.equip_in_one_of_slots(fake_id, list(
LOCATION_ID = ITEM_SLOT_ID,
LOCATION_LPOCKET = ITEM_SLOT_LPOCKET,
LOCATION_RPOCKET = ITEM_SLOT_RPOCKET,
LOCATION_BACKPACK = ITEM_SLOT_BACKPACK,
LOCATION_HANDS = ITEM_SLOT_HANDS,
), qdel_on_fail = FALSE)
if (isnull(placed_in))
fake_id.forceMove(user.drop_location())
to_chat(user, span_warning("You drop your new ID card on the ground."))
else
to_chat(user, span_notice("You quickly put your new ID card [placed_in]."))

user.sec_hud_set_ID()

var/mob/living/carbon/human/dummy/consistent/dummy = new() // For manifest rendering, unfortunately
dummy.physique = user.physique
user.dna.copy_dna(dummy.dna, COPY_DNA_SE|COPY_DNA_SPECIES)
user.copy_clothing_prefs(dummy)
dummy.updateappearance(icon_update = TRUE, mutcolor_update = TRUE, mutations_overlay_update = TRUE)
dummy.dress_up_as_job(job, visual_only = TRUE)

GLOB.manifest.inject(user, appearance_proxy = dummy)
QDEL_NULL(dummy)

if (original_id)
var/returned_to = user.equip_in_one_of_slots(original_id, list(
LOCATION_BACKPACK = ITEM_SLOT_BACKPACK,
LOCATION_LPOCKET = ITEM_SLOT_LPOCKET,
LOCATION_RPOCKET = ITEM_SLOT_RPOCKET,
LOCATION_HANDS = ITEM_SLOT_HANDS,
), qdel_on_fail = FALSE)
if (isnull(returned_to))
fake_id.forceMove(user.drop_location())
to_chat(user, span_warning("You drop your old ID card on the ground."))
else
to_chat(user, span_notice("You stash your old ID card [returned_to]."))

var/obj/item/arrival_announcer/announcer = new(user.drop_location())
user.put_in_hands(announcer)
to_chat(user, span_notice("You quickly eat the leftover paperwork, leaving only the signaller used to announce your arrival on the station."))
qdel(src)

/obj/item/arrival_announcer
name = "arrivals announcement signaller"
desc = "A radio signaller which uses a backdoor in the NT announcement system to trigger a fake announcement that you have just arrived there, then self-destructs."
icon_state = "signaller"
inhand_icon_state = "signaler"
icon = 'icons/obj/assemblies/new_assemblies.dmi'
lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi'
righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi'
interaction_flags_click = NEED_DEXTERITY|NEED_HANDS|ALLOW_RESTING

/obj/item/arrival_announcer/attack_self(mob/living/user, modifiers)
. = ..()
if (!isliving(user))
return

var/name = user.real_name
var/datum/record/manifest_data = find_record(name)
if (isnull(manifest_data))
balloon_alert(user, "no records found!")
return
var/job = manifest_data.rank
if (tgui_alert(user, "Announce arrival of [name] as [job]?", "Are you ready?", list("Yes", "No"), timeout = 30 SECONDS) != "Yes")
return
if (QDELETED(src) || !user.can_perform_action(src, interaction_flags_click))
return

announce_arrival(user, job, announce_to_ghosts = FALSE)
do_sparks(1, FALSE, user)
new /obj/effect/decal/cleanable/ash(user.drop_location())
user.temporarilyRemoveItemFromInventory(src)
qdel(src)
11 changes: 11 additions & 0 deletions code/game/objects/items/food/monkeycube.dm
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,17 @@
tastes = list("buzzing" = 1, "honey" = 1, "regret" = 1)
spawned_mob = /mob/living/basic/bee

/obj/item/food/monkeycube/dangerous_horse
name = "a pony cube"
desc = "This is a cube that, when water is added, creates a syndicate pony powerful enough to break the enemy's face!"
bite_consumption = 10
food_reagents = list(
/datum/reagent/toxin = 15,
/datum/reagent/medicine/strange_reagent = 1,
)
tastes = list("the loss of 5 TC" = 1, "eaten friend" = 1)
spawned_mob = /mob/living/basic/pony/dangerous

/obj/item/food/monkeycube/cow
name = "Cow cube"
desc = "Because not all ethical committees agree with eating chimpanzee."
Expand Down
19 changes: 19 additions & 0 deletions code/game/objects/items/implants/implant_misc.dm
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,25 @@
name = "implanter (EMP)"
imp_type = /obj/item/implant/emp

/obj/item/implant/smoke
name = "smoke implant"
desc = "Releases a plume of smoke."
icon_state = "smoke"
uses = 3

/obj/item/implant/smoke/activate()
. = ..()
uses--
var/datum/effect_system/fluid_spread/smoke/bad/smoke = new
smoke.set_up(6, holder = imp_in, location = imp_in)
smoke.start()
if(!uses)
qdel(src)

/obj/item/implanter/smoke
name = "implanter (Smoke)"
imp_type = /obj/item/implant/smoke

/obj/item/implant/radio
name = "internal radio implant"
var/obj/item/radio/radio
Expand Down
29 changes: 29 additions & 0 deletions code/game/objects/items/storage/medkit.dm
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,35 @@
)
generate_items_inside(items_inside, src)

/obj/item/storage/medkit/surgery_syndie
name = "suspicous surgical medkit"
desc = "An suspicous coloured medkit full of advanced medical equipment."
icon_state = "medkit_tactical_lite"
inhand_icon_state = "medkit-tactical-lite"
damagetype_healed = HEAL_ALL_DAMAGE

/obj/item/storage/medkit/surgery_syndie/PopulateContents()
if(empty)
return
var/static/items_inside = list(
/obj/item/scalpel/advanced = 1,
/obj/item/retractor/advanced = 1,
/obj/item/cautery/advanced = 1,
/obj/item/surgical_drapes = 1,
/obj/item/stack/medical/gauze/twelve = 1,
/obj/item/reagent_containers/medigel/sterilizine = 1,
/obj/item/bonesetter = 1,
/obj/item/blood_filter = 1,
/obj/item/stack/medical/bone_gel = 1,
/obj/item/stack/sticky_tape/surgical = 1,
/obj/item/reagent_containers/syringe = 1,
/obj/item/reagent_containers/cup/bottle/sodium_thiopental = 1,
)
generate_items_inside(items_inside,src)

/obj/item/storage/medkit/surgery_syndie/get_medbot_skin()
return "bezerk"

/obj/item/storage/medkit/ancient
icon_state = "oldfirstaid"
desc = "A first aid kit with the ability to heal common types of injuries."
Expand Down
72 changes: 72 additions & 0 deletions code/game/objects/items/storage/toolbox.dm
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,78 @@
// Somewhere to store it all.
new /obj/item/storage/backpack/satchel(src)

/obj/item/storage/toolbox/guncase/traitor
name = "makarov gun case"
desc = "A weapon's case. Has a blood-red 'S' stamped on the cover. There seems to be a strange switch along the side inside a plastic flap."
icon_state = "pistol_case"
base_icon_state = "pistol_case"
// What ammo box do we spawn in our case?
var/ammo_box_to_spawn = /obj/item/ammo_box/c9mm
// Timer for the bomb in the case.
var/explosion_timer
// Whether or not our case is exploding. Used for determining sprite changes.
var/currently_exploding = FALSE

/obj/item/storage/toolbox/guncase/traitor/Initialize(mapload)
. = ..()
register_context()

/obj/item/storage/toolbox/guncase/traitor/examine(mob/user)
. = ..()
. += span_notice("Activate the Evidence Disposal Explosive using Alt-Right-Click.")

/obj/item/storage/toolbox/guncase/traitor/add_context(atom/source, list/context, obj/item/held_item, mob/user)
. = ..()

context[SCREENTIP_CONTEXT_ALT_RMB] = "Activate Evidence Disposal Explosive"
return CONTEXTUAL_SCREENTIP_SET

/obj/item/storage/toolbox/guncase/traitor/PopulateContents()
new weapon_to_spawn (src)
for(var/i in 1 to 2)
new extra_to_spawn (src)
new ammo_box_to_spawn(src)

/obj/item/storage/toolbox/guncase/traitor/update_icon_state()
. = ..()
if(currently_exploding)
icon_state = "[base_icon_state]_exploding"
else
icon_state = "[base_icon_state]"

/obj/item/storage/toolbox/guncase/traitor/click_alt_secondary(mob/user)
. = ..()
var/i_dont_even_think_once_about_blowing_stuff_up = tgui_alert(user, "Would you like to activate the evidence disposal bomb now?", "BYE BYE", list("Yes","No"))
if(i_dont_even_think_once_about_blowing_stuff_up == "No")
return
explosion_timer = addtimer(CALLBACK(src, PROC_REF(think_fast_chucklenuts)), 5 SECONDS, (TIMER_UNIQUE|TIMER_OVERRIDE))
to_chat(user, span_warning("You prime [src]'s evidence disposal bomb!"))
log_bomber(user, "has activated a", src, "for detonation")
playsound(src, 'sound/weapons/armbomb.ogg', 50, TRUE)
currently_exploding = TRUE
update_appearance()

/// proc to handle our detonation
/obj/item/storage/toolbox/guncase/traitor/proc/think_fast_chucklenuts()
explosion(src, devastation_range = 0, heavy_impact_range = 0, light_impact_range = 2, explosion_cause = src)
qdel(src)

/obj/item/storage/toolbox/guncase/traitor/ammunition
name = "makarov 9mm magazine case"
weapon_to_spawn = /obj/item/ammo_box/magazine/m9mm

/obj/item/storage/toolbox/guncase/traitor/donksoft
name = "\improper Donksoft riot pistol gun case"
weapon_to_spawn = /obj/item/gun/ballistic/automatic/pistol/toy/riot/clandestine
extra_to_spawn = /obj/item/ammo_box/magazine/toy/pistol/riot
ammo_box_to_spawn = /obj/item/ammo_box/foambox/riot

/obj/item/storage/toolbox/guncase/traitor/ammunition/donksoft
name = "\improper Donksoft riot pistol magazine case"
weapon_to_spawn = /obj/item/ammo_box/magazine/toy/pistol/riot
extra_to_spawn = /obj/item/ammo_box/magazine/toy/pistol/riot
ammo_box_to_spawn = /obj/item/ammo_box/foambox/riot

/obj/item/storage/toolbox/repair
name = "robotic repair toolbox"
desc = "Capable of robusting and repairing any troublesome robots after the fact."
Expand Down
Loading