diff --git a/code/__DEFINES/atom_hud.dm b/code/__DEFINES/atom_hud.dm index 1af3003bb85..57dc338d3eb 100644 --- a/code/__DEFINES/atom_hud.dm +++ b/code/__DEFINES/atom_hud.dm @@ -81,6 +81,7 @@ #define SECHUD_ASSISTANT "hudassistant" #define SECHUD_ATMOSPHERIC_TECHNICIAN "hudatmospherictechnician" #define SECHUD_BARTENDER "hudbartender" +#define SECHUD_BUSSER "hudbusser" #define SECHUD_BITAVATAR "hudbitavatar" #define SECHUD_BITRUNNER "hudbitrunner" #define SECHUD_BOTANIST "hudbotanist" diff --git a/code/__DEFINES/jobs.dm b/code/__DEFINES/jobs.dm index 2c3b151855c..d63efd92445 100644 --- a/code/__DEFINES/jobs.dm +++ b/code/__DEFINES/jobs.dm @@ -93,6 +93,7 @@ #define JOB_LAWYER "Lawyer" #define JOB_CHAPLAIN "Chaplain" #define JOB_PSYCHOLOGIST "Psychologist" +#define JOB_PUN_PUN "Pun Pun" //ERTs #define JOB_ERT_DEATHSQUAD "Death Commando" #define JOB_ERT_COMMANDER "Emergency Response Team Commander" @@ -136,31 +137,32 @@ #define JOB_DISPLAY_ORDER_LAWYER 12 #define JOB_DISPLAY_ORDER_CHAPLAIN 13 #define JOB_DISPLAY_ORDER_PSYCHOLOGIST 14 -#define JOB_DISPLAY_ORDER_AI 15 -#define JOB_DISPLAY_ORDER_CYBORG 16 -#define JOB_DISPLAY_ORDER_CHIEF_ENGINEER 17 -#define JOB_DISPLAY_ORDER_STATION_ENGINEER 18 -#define JOB_DISPLAY_ORDER_ATMOSPHERIC_TECHNICIAN 19 -#define JOB_DISPLAY_ORDER_QUARTERMASTER 20 -#define JOB_DISPLAY_ORDER_CARGO_TECHNICIAN 21 -#define JOB_DISPLAY_ORDER_SHAFT_MINER 22 -#define JOB_DISPLAY_ORDER_BITRUNNER 23 -#define JOB_DISPLAY_ORDER_CARGO_GORILLA 24 -#define JOB_DISPLAY_ORDER_CHIEF_MEDICAL_OFFICER 25 -#define JOB_DISPLAY_ORDER_MEDICAL_DOCTOR 26 -#define JOB_DISPLAY_ORDER_PARAMEDIC 27 -#define JOB_DISPLAY_ORDER_CHEMIST 28 -#define JOB_DISPLAY_ORDER_CORONER 29 -#define JOB_DISPLAY_ORDER_RESEARCH_DIRECTOR 30 -#define JOB_DISPLAY_ORDER_SCIENTIST 31 -#define JOB_DISPLAY_ORDER_ROBOTICIST 32 -#define JOB_DISPLAY_ORDER_GENETICIST 33 -#define JOB_DISPLAY_ORDER_HEAD_OF_SECURITY 34 -#define JOB_DISPLAY_ORDER_VETERAN_ADVISOR 35 -#define JOB_DISPLAY_ORDER_WARDEN 36 -#define JOB_DISPLAY_ORDER_DETECTIVE 37 -#define JOB_DISPLAY_ORDER_SECURITY_OFFICER 38 -#define JOB_DISPLAY_ORDER_PRISONER 39 +#define JOB_DISPLAY_ORDER_PUN_PUN 15 +#define JOB_DISPLAY_ORDER_AI 16 +#define JOB_DISPLAY_ORDER_CYBORG 17 +#define JOB_DISPLAY_ORDER_CHIEF_ENGINEER 18 +#define JOB_DISPLAY_ORDER_STATION_ENGINEER 19 +#define JOB_DISPLAY_ORDER_ATMOSPHERIC_TECHNICIAN 20 +#define JOB_DISPLAY_ORDER_QUARTERMASTER 21 +#define JOB_DISPLAY_ORDER_CARGO_TECHNICIAN 22 +#define JOB_DISPLAY_ORDER_SHAFT_MINER 23 +#define JOB_DISPLAY_ORDER_BITRUNNER 24 +#define JOB_DISPLAY_ORDER_CARGO_GORILLA 25 +#define JOB_DISPLAY_ORDER_CHIEF_MEDICAL_OFFICER 26 +#define JOB_DISPLAY_ORDER_MEDICAL_DOCTOR 27 +#define JOB_DISPLAY_ORDER_PARAMEDIC 28 +#define JOB_DISPLAY_ORDER_CHEMIST 29 +#define JOB_DISPLAY_ORDER_CORONER 30 +#define JOB_DISPLAY_ORDER_RESEARCH_DIRECTOR 31 +#define JOB_DISPLAY_ORDER_SCIENTIST 32 +#define JOB_DISPLAY_ORDER_ROBOTICIST 33 +#define JOB_DISPLAY_ORDER_GENETICIST 34 +#define JOB_DISPLAY_ORDER_HEAD_OF_SECURITY 35 +#define JOB_DISPLAY_ORDER_VETERAN_ADVISOR 36 +#define JOB_DISPLAY_ORDER_WARDEN 37 +#define JOB_DISPLAY_ORDER_DETECTIVE 38 +#define JOB_DISPLAY_ORDER_SECURITY_OFFICER 39 +#define JOB_DISPLAY_ORDER_PRISONER 40 #define DEPARTMENT_UNASSIGNED "No Department" diff --git a/code/controllers/subsystem/processing/station.dm b/code/controllers/subsystem/processing/station.dm index 883ab37456d..3cbdcbac18c 100644 --- a/code/controllers/subsystem/processing/station.dm +++ b/code/controllers/subsystem/processing/station.dm @@ -164,6 +164,8 @@ PROCESSING_SUBSYSTEM_DEF(station) ///Creates a given trait of a specific type, while also removing any blacklisted ones from the future pool. /datum/controller/subsystem/processing/station/proc/setup_trait(datum/station_trait/trait_type) + if(locate(trait_type) in station_traits) + return var/datum/station_trait/trait_instance = new trait_type() station_traits += trait_instance log_game("Station Trait: [trait_instance.name] chosen for this round.") diff --git a/code/datums/id_trim/jobs.dm b/code/datums/id_trim/jobs.dm index a42018406b2..133fbce92bb 100644 --- a/code/datums/id_trim/jobs.dm +++ b/code/datums/id_trim/jobs.dm @@ -156,6 +156,29 @@ ) job = /datum/job/bartender +/datum/id_trim/job/pun_pun + assignment = "busser" + trim_state = "trim_busser" + department_color = COLOR_SERVICE_LIME + subdepartment_color = COLOR_SERVICE_LIME + sechud_icon_state = SECHUD_BUSSER + minimal_access = list( + ACCESS_MINERAL_STOREROOM, + ACCESS_SERVICE, + ACCESS_THEATRE, + ) + extra_access = list( + ACCESS_HYDROPONICS, + ACCESS_KITCHEN, + ACCESS_BAR, + ) + template_access = list( + ACCESS_CAPTAIN, + ACCESS_CHANGE_IDS, + ACCESS_HOP, + ) + job = /datum/job/pun_pun + /datum/id_trim/job/bitrunner assignment = JOB_BITRUNNER trim_state = "trim_bitrunner" diff --git a/code/datums/station_traits/job_traits.dm b/code/datums/station_traits/job_traits.dm index f2bd456aaee..2564955c179 100644 --- a/code/datums/station_traits/job_traits.dm +++ b/code/datums/station_traits/job_traits.dm @@ -243,6 +243,19 @@ qdel(thing_on_table) new /obj/machinery/fax/auto_name(picked_turf) +/datum/station_trait/job/pun_pun + name = "Pun Pun is a Crewmember" + button_desc = "Ook ook ah ah, sign up to play as the bartender's monkey." + weight = 0 //Unrollable by default, available all day during monkey day. + report_message = "We've evaluated the bartender's monkey to have the mental capacity of the average crewmember. As such, we made them one." + show_in_report = TRUE + can_roll_antag = CAN_ROLL_ALWAYS + job_to_add = /datum/job/pun_pun + +/datum/station_trait/job/pun_pun/on_lobby_button_update_overlays(atom/movable/screen/lobby/button/sign_up/lobby_button, list/overlays) + . = ..() + overlays += LAZYFIND(lobby_candidates, lobby_button.get_mob()) ? "pun_pun_on" : "pun_pun_off" + #undef CAN_ROLL_ALWAYS #undef CAN_ROLL_PROTECTED #undef CAN_ROLL_NEVER diff --git a/code/datums/station_traits/positive_traits.dm b/code/datums/station_traits/positive_traits.dm index 945fbe06934..052a8177345 100644 --- a/code/datums/station_traits/positive_traits.dm +++ b/code/datums/station_traits/positive_traits.dm @@ -285,6 +285,7 @@ /datum/job/paramedic = /obj/item/organ/internal/cyberimp/eyes/hud/medical, /datum/job/prisoner = /obj/item/organ/internal/eyes/robotic/shield, /datum/job/psychologist = /obj/item/organ/internal/ears/cybernetic/whisper, + /datum/job/pun_pun = /obj/item/organ/internal/cyberimp/arm/strongarm, /datum/job/quartermaster = /obj/item/organ/internal/stomach/cybernetic/tier3, /datum/job/research_director = /obj/item/organ/internal/cyberimp/bci, /datum/job/roboticist = /obj/item/organ/internal/cyberimp/eyes/hud/diagnostic, diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm index 64c0afe188a..b1a4a75c945 100644 --- a/code/game/objects/effects/landmarks.dm +++ b/code/game/objects/effects/landmarks.dm @@ -306,6 +306,11 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player) GLOB.newplayer_start += loc return INITIALIZE_HINT_QDEL +/obj/effect/landmark/start/pun_pun + name = JOB_PUN_PUN + icon = 'icons/mob/human/human.dmi' + icon_state = "monkey" + /obj/effect/landmark/latejoin name = "JoinLate" diff --git a/code/modules/antagonists/_common/antag_spawner.dm b/code/modules/antagonists/_common/antag_spawner.dm index 5f7a7e579d3..2e418c78d6c 100644 --- a/code/modules/antagonists/_common/antag_spawner.dm +++ b/code/modules/antagonists/_common/antag_spawner.dm @@ -424,15 +424,7 @@ monkey_man.fully_replace_character_name(monkey_man.real_name, pick(GLOB.syndicate_monkey_names)) - monkey_man.dna.add_mutation(/datum/mutation/human/clever) - // Can't make them human or nonclever. At least not with the easy and boring way out. - for(var/datum/mutation/human/mutation as anything in monkey_man.dna.mutations) - mutation.mutadone_proof = TRUE - mutation.instability = 0 - - // Extra backup! - ADD_TRAIT(monkey_man, TRAIT_NO_DNA_SCRAMBLE, SPECIES_TRAIT) - // Anything else requires enough effort that they deserve it. + monkey_man.make_clever_and_no_dna_scramble() monkey_man.mind.enslave_mind_to_creator(user) diff --git a/code/modules/holiday/holidays.dm b/code/modules/holiday/holidays.dm index 6fe7fdbc57d..6366cc7bfb2 100644 --- a/code/modules/holiday/holidays.dm +++ b/code/modules/holiday/holidays.dm @@ -694,6 +694,14 @@ begin_day = 14 begin_month = DECEMBER +/datum/holiday/monkey/celebrate() + . = ..() + SSstation.setup_trait(/datum/station_trait/job/pun_pun) + //SSevents should initialize before SSatoms but who knows if it'll ever change. + if(GLOB.the_one_and_only_punpun) + new /obj/effect/landmark/start/pun_pun(GLOB.the_one_and_only_punpun.loc) + qdel(GLOB.the_one_and_only_punpun) + /datum/holiday/doomsday name = "Mayan Doomsday Anniversary" begin_day = 21 diff --git a/code/modules/jobs/job_types/station_trait/pun_pun.dm b/code/modules/jobs/job_types/station_trait/pun_pun.dm new file mode 100644 index 00000000000..eca4861e77e --- /dev/null +++ b/code/modules/jobs/job_types/station_trait/pun_pun.dm @@ -0,0 +1,53 @@ +///Special job, active during monkey day. +/datum/job/pun_pun + title = JOB_PUN_PUN + description = "Assist the service department by serving drinks and food and entertaining the crew." + department_head = list(JOB_HEAD_OF_PERSONNEL) + faction = FACTION_STATION + total_positions = 0 + spawn_positions = 0 + supervisors = "the Bartender" + spawn_type = /mob/living/carbon/human/species/monkey/punpun + outfit = /datum/outfit/job/pun_pun + config_tag = "PUN_PUN" + random_spawns_possible = FALSE + paycheck = PAYCHECK_LOWER + paycheck_department = ACCOUNT_CIV + display_order = JOB_DISPLAY_ORDER_PUN_PUN + departments_list = list(/datum/job_department/service) + exclusive_mail_goodies = TRUE + mail_goodies = list( + /obj/item/food/grown/banana = 4, + /obj/effect/spawner/random/entertainment/money_medium = 3, + /obj/item/clothing/head/helmet/monkey_sentience = 1, + /obj/item/book/granter/sign_language = 1, + /obj/item/food/monkeycube = 1, + ) + rpg_title = "Homunculus" + allow_bureaucratic_error = FALSE + job_flags = (STATION_JOB_FLAGS|STATION_TRAIT_JOB_FLAGS)&~JOB_ASSIGN_QUIRKS + +/datum/job/pun_pun/get_spawn_mob(client/player_client, atom/spawn_point) + if (!player_client) + return + var/mob/living/monky = new spawn_type(get_turf(spawn_point)) + if(!GLOB.the_one_and_only_punpun) + GLOB.the_one_and_only_punpun = monky + return monky + +/datum/job/pun_pun/after_spawn(mob/living/carbon/human/monkey, client/player_client) + . = ..() + monkey.make_clever_and_no_dna_scramble() + +/datum/outfit/job/pun_pun + name = "Pun Pun" + jobtype = /datum/job/pun_pun + + id_trim = /datum/id_trim/job/pun_pun + belt = /obj/item/modular_computer/pda/pun_pun + uniform = /obj/item/clothing/under/suit/waiter + backpack_contents = list( + /obj/item/gun/ballistic/shotgun/monkey = 1, + /obj/item/storage/box/beanbag = 1, + ) + shoes = null //monkeys cannot equip shoes diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 5f008af5045..1dcd708b3e7 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1074,6 +1074,17 @@ if(use_random_name) fully_replace_character_name(real_name, generate_random_mob_name()) +///Proc used to prevent syndicate monkeys and player-selectable Pun Pun able to use objects while stuck in monkey mode. +/mob/living/carbon/human/proc/make_clever_and_no_dna_scramble() + dna.add_mutation(/datum/mutation/human/clever) + // Can't make them human or nonclever. At least not with the easy and boring way out. + for(var/datum/mutation/human/mutation as anything in dna.mutations) + mutation.mutadone_proof = TRUE + mutation.instability = 0 + + // Extra backup! + ADD_TRAIT(src, TRAIT_NO_DNA_SCRAMBLE, SPECIES_TRAIT) + /mob/living/carbon/human/species/abductor race = /datum/species/abductor diff --git a/code/modules/mob/living/carbon/human/monkey.dm b/code/modules/mob/living/carbon/human/monkey.dm index e63b35ab42a..de7eb94f39f 100644 --- a/code/modules/mob/living/carbon/human/monkey.dm +++ b/code/modules/mob/living/carbon/human/monkey.dm @@ -48,6 +48,11 @@ GLOBAL_DATUM(the_one_and_only_punpun, /mob/living/carbon/human/species/monkey/pu var/memory_saved = FALSE /mob/living/carbon/human/species/monkey/punpun/Initialize(mapload) + // 1 Pun Pun should exist + REGISTER_REQUIRED_MAP_ITEM(1, 1) + if(mapload && (locate(/datum/station_trait/job/pun_pun) in SSstation.station_traits)) + new /obj/effect/landmark/start/pun_pun(loc) //Pun Pun is a crewmember, and may late-join. + return INITIALIZE_HINT_QDEL Read_Memory() var/name_to_use = name @@ -65,8 +70,8 @@ GLOBAL_DATUM(the_one_and_only_punpun, /mob/living/carbon/human/species/monkey/pu if(!GLOB.the_one_and_only_punpun && mapload) GLOB.the_one_and_only_punpun = src - // 1 Pun Pun should exist - REGISTER_REQUIRED_MAP_ITEM(1, 1) + else if(GLOB.the_one_and_only_punpun) + ADD_TRAIT(src, TRAIT_DONT_WRITE_MEMORY, INNATE_TRAIT) //faaaaaaake! fully_replace_character_name(real_name, name_to_use) diff --git a/code/modules/modular_computers/computers/item/role_tablet_presets.dm b/code/modules/modular_computers/computers/item/role_tablet_presets.dm index cbd784b1ef0..7c021c72cf4 100644 --- a/code/modules/modular_computers/computers/item/role_tablet_presets.dm +++ b/code/modules/modular_computers/computers/item/role_tablet_presets.dm @@ -425,6 +425,14 @@ /datum/computer_file/program/borg_monitor, ) +/obj/item/modular_computer/pda/pun_pun + name = "monkey PDA" + greyscale_colors = "#ffcc66#914800" + starting_programs = list( + /datum/computer_file/program/bounty_board, + /datum/computer_file/program/emojipedia, + ) + /** * Non-roles */ diff --git a/code/modules/projectiles/boxes_magazines/internal/shotgun.dm b/code/modules/projectiles/boxes_magazines/internal/shotgun.dm index 5331b5c92f8..6d7d9225142 100644 --- a/code/modules/projectiles/boxes_magazines/internal/shotgun.dm +++ b/code/modules/projectiles/boxes_magazines/internal/shotgun.dm @@ -53,7 +53,10 @@ ammo_type = /obj/item/ammo_casing/shotgun/incapacitate max_ammo = 3 -/obj/item/ammo_box/magazine/internal/shot/musket +/obj/item/ammo_box/magazine/internal/shot/single + name = "single-barrel shotgun internal magazine" + max_ammo = 1 + +/obj/item/ammo_box/magazine/internal/shot/single/musket name = "donk co musket internal magazine" ammo_type = /obj/item/ammo_casing/shotgun/fletchette - max_ammo = 1 diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm index 9be59ffb534..3885cc737a1 100644 --- a/code/modules/projectiles/guns/ballistic/shotgun.dm +++ b/code/modules/projectiles/guns/ballistic/shotgun.dm @@ -287,7 +287,6 @@ can_be_sawn_off = TRUE pb_knockback = 3 // it's a super shotgun! - /obj/item/gun/ballistic/shotgun/doublebarrel/sawoff(mob/user) . = ..() if(.) @@ -343,6 +342,30 @@ return hook.try_fire_gun(target, user, params) return ..() +///An underpowered shotgun given to Pun Pun when the station job trait roll. +/obj/item/gun/ballistic/shotgun/monkey + name = "\improper Barback's Shot" + desc = "A chimp-sized, single-shot and break-action shotgun with an unpractical stock." + icon_state = "chimp_shottie" + inhand_icon_state = "shotgun" + lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi' + force = 8 + obj_flags = CONDUCTS_ELECTRICITY + slot_flags = NONE + accepted_magazine_type = /obj/item/ammo_box/magazine/internal/shot/single + obj_flags = UNIQUE_RENAME + w_class = WEIGHT_CLASS_NORMAL + weapon_weight = WEAPON_MEDIUM + semi_auto = TRUE + bolt_type = BOLT_TYPE_NO_BOLT + spread = 10 + projectile_damage_multiplier = 0.5 + projectile_wound_bonus = -25 + recoil = 1 + pin = /obj/item/firing_pin/monkey + pb_knockback = 1 + /obj/item/gun/ballistic/shotgun/musket name = "\improper Donk Co. Musket" icon = 'icons/obj/weapons/guns/ballistic.dmi' @@ -356,4 +379,4 @@ bolt_type = BOLT_TYPE_LOCKING bolt_wording = "bolt" internal_magazine = TRUE - accepted_magazine_type = /obj/item/ammo_box/magazine/internal/shot/musket + accepted_magazine_type = /obj/item/ammo_box/magazine/internal/shot/single/musket diff --git a/code/modules/uplink/uplink_items/job.dm b/code/modules/uplink/uplink_items/job.dm index be9d558687d..077698cf4db 100644 --- a/code/modules/uplink/uplink_items/job.dm +++ b/code/modules/uplink/uplink_items/job.dm @@ -364,7 +364,7 @@ Please note that these are free-range monkeys that don't react with Mutadone." item = /obj/item/antag_spawner/loadout/monkey_man cost = 6 - restricted_roles = list(JOB_RESEARCH_DIRECTOR, JOB_SCIENTIST, JOB_GENETICIST, JOB_ASSISTANT, JOB_MIME, JOB_CLOWN) + restricted_roles = list(JOB_RESEARCH_DIRECTOR, JOB_SCIENTIST, JOB_GENETICIST, JOB_ASSISTANT, JOB_MIME, JOB_CLOWN, JOB_PUN_PUN) restricted = TRUE refundable = TRUE @@ -375,7 +375,7 @@ item = /obj/item/storage/toolbox/guncase/monkeycase cost = 4 limited_stock = 3 - restricted_roles = list(JOB_ASSISTANT, JOB_MIME, JOB_CLOWN) + restricted_roles = list(JOB_ASSISTANT, JOB_MIME, JOB_CLOWN, JOB_PUN_PUN) restricted = TRUE refundable = FALSE diff --git a/icons/hud/lobby/signup_button.dmi b/icons/hud/lobby/signup_button.dmi index bc5f1f7f24a..e015fa71948 100644 Binary files a/icons/hud/lobby/signup_button.dmi and b/icons/hud/lobby/signup_button.dmi differ diff --git a/icons/mob/huds/hud.dmi b/icons/mob/huds/hud.dmi index 086e886bab7..4513575ef0b 100644 Binary files a/icons/mob/huds/hud.dmi and b/icons/mob/huds/hud.dmi differ diff --git a/icons/obj/card.dmi b/icons/obj/card.dmi index dcfb7f482ae..738d3e51a3a 100644 Binary files a/icons/obj/card.dmi and b/icons/obj/card.dmi differ diff --git a/icons/obj/weapons/guns/ballistic.dmi b/icons/obj/weapons/guns/ballistic.dmi index 4ebb17baec3..ef61f1d2494 100644 Binary files a/icons/obj/weapons/guns/ballistic.dmi and b/icons/obj/weapons/guns/ballistic.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 3f9bf9662de..b45a777c2d4 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -4450,6 +4450,7 @@ #include "code\modules\jobs\job_types\station_trait\bridge_assistant.dm" #include "code\modules\jobs\job_types\station_trait\cargo_gorilla.dm" #include "code\modules\jobs\job_types\station_trait\human_ai.dm" +#include "code\modules\jobs\job_types\station_trait\pun_pun.dm" #include "code\modules\jobs\job_types\station_trait\veteran_advisor.dm" #include "code\modules\keybindings\bindings_atom.dm" #include "code\modules\keybindings\bindings_client.dm" diff --git a/tgui/packages/tgui/interfaces/common/JobToIcon.ts b/tgui/packages/tgui/interfaces/common/JobToIcon.ts index 74927a2ff08..d2a473f3b05 100644 --- a/tgui/packages/tgui/interfaces/common/JobToIcon.ts +++ b/tgui/packages/tgui/interfaces/common/JobToIcon.ts @@ -54,5 +54,6 @@ export const JOB2ICON = { 'Station Engineer': 'gears', 'Syndicate Operative': 'dragon', 'Veteran Security Advisor': 'ribbon', + 'Pun Pun': 'paw', Warden: 'handcuffs', } as const;