diff --git a/code/__DEFINES/dcs/signals/signals_global.dm b/code/__DEFINES/dcs/signals/signals_global.dm index 3c7399d98fa..41c2b4b7459 100644 --- a/code/__DEFINES/dcs/signals/signals_global.dm +++ b/code/__DEFINES/dcs/signals/signals_global.dm @@ -84,6 +84,9 @@ /// (new_name, old_name) #define COMSIG_GLOB_STATION_NAME_CHANGED "!station_name_changed" +/// Global signal sent before we decide what job everyone has +#define COMSIG_GLOB_PRE_JOBS_ASSIGNED "!pre_roles_assigned" + /// global signal when a global nullrod type is picked #define COMSIG_GLOB_NULLROD_PICKED "!nullrod_picked" diff --git a/code/__DEFINES/jobs.dm b/code/__DEFINES/jobs.dm index 7feca0782dc..9b65e8a9c55 100644 --- a/code/__DEFINES/jobs.dm +++ b/code/__DEFINES/jobs.dm @@ -80,6 +80,7 @@ //Supply #define JOB_QUARTERMASTER "Quartermaster" #define JOB_CARGO_TECHNICIAN "Cargo Technician" +#define JOB_CARGO_GORILLA "Cargo Gorilla" #define JOB_SHAFT_MINER "Shaft Miner" #define JOB_BITRUNNER "Bitrunner" #define JOB_CUSTOMS_AGENT "Customs Agent" // SKYRAT EDIT ADDITION @@ -164,31 +165,32 @@ #define JOB_DISPLAY_ORDER_CARGO_TECHNICIAN 20 #define JOB_DISPLAY_ORDER_SHAFT_MINER 21 #define JOB_DISPLAY_ORDER_BITRUNNER 22 -#define JOB_DISPLAY_ORDER_CHIEF_MEDICAL_OFFICER 23 -#define JOB_DISPLAY_ORDER_MEDICAL_DOCTOR 24 -#define JOB_DISPLAY_ORDER_PARAMEDIC 25 -#define JOB_DISPLAY_ORDER_CHEMIST 26 -#define JOB_DISPLAY_ORDER_VIROLOGIST 27 -#define JOB_DISPLAY_ORDER_CORONER 28 -#define JOB_DISPLAY_ORDER_RESEARCH_DIRECTOR 29 -#define JOB_DISPLAY_ORDER_SCIENTIST 30 -#define JOB_DISPLAY_ORDER_ROBOTICIST 31 -#define JOB_DISPLAY_ORDER_GENETICIST 32 -#define JOB_DISPLAY_ORDER_HEAD_OF_SECURITY 33 -#define JOB_DISPLAY_ORDER_WARDEN 34 -#define JOB_DISPLAY_ORDER_DETECTIVE 35 -#define JOB_DISPLAY_ORDER_SECURITY_OFFICER 36 -#define JOB_DISPLAY_ORDER_PRISONER 37 -#define JOB_DISPLAY_ORDER_SECURITY_MEDIC 38 //SKYRAT EDIT ADDITON -#define JOB_DISPLAY_ORDER_CORRECTIONS_OFFICER 39 //SKYRAT EDIT ADDITON -#define JOB_DISPLAY_ORDER_NANOTRASEN_CONSULTANT 40 //SKYRAT EDIT ADDITON -#define JOB_DISPLAY_ORDER_BLUESHIELD 41 //SKYRAT EDIT ADDITON -#define JOB_DISPLAY_ORDER_ORDERLY 42 //SKYRAT EDIT ADDITION -#define JOB_DISPLAY_ORDER_SCIENCE_GUARD 43 //SKYRAT EDIT ADDITION -#define JOB_DISPLAY_ORDER_BOUNCER 44 //SKYRAT EDIT ADDITION -#define JOB_DISPLAY_ORDER_ENGINEER_GUARD 45 //SKYRAT EDIT ADDITION -#define JOB_DISPLAY_ORDER_CUSTOMS_AGENT 46 //SKYRAT EDIT ADDITION -#define JOB_DISPLAY_ORDER_EXP_CORPS 47 //SKYRAT EDIT ADDITON +#define JOB_DISPLAY_ORDER_CARGO_GORILLA 23 +#define JOB_DISPLAY_ORDER_CHIEF_MEDICAL_OFFICER 24 +#define JOB_DISPLAY_ORDER_MEDICAL_DOCTOR 25 +#define JOB_DISPLAY_ORDER_PARAMEDIC 26 +#define JOB_DISPLAY_ORDER_CHEMIST 27 +#define JOB_DISPLAY_ORDER_VIROLOGIST 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_WARDEN 35 +#define JOB_DISPLAY_ORDER_DETECTIVE 36 +#define JOB_DISPLAY_ORDER_SECURITY_OFFICER 37 +#define JOB_DISPLAY_ORDER_PRISONER 38 +#define JOB_DISPLAY_ORDER_SECURITY_MEDIC 100 //SKYRAT EDIT ADDITON +#define JOB_DISPLAY_ORDER_CORRECTIONS_OFFICER 101 //SKYRAT EDIT ADDITON +#define JOB_DISPLAY_ORDER_NANOTRASEN_CONSULTANT 102 //SKYRAT EDIT ADDITON +#define JOB_DISPLAY_ORDER_BLUESHIELD 103 //SKYRAT EDIT ADDITON +#define JOB_DISPLAY_ORDER_ORDERLY 104 //SKYRAT EDIT ADDITION +#define JOB_DISPLAY_ORDER_SCIENCE_GUARD 105 //SKYRAT EDIT ADDITION +#define JOB_DISPLAY_ORDER_BOUNCER 106 //SKYRAT EDIT ADDITION +#define JOB_DISPLAY_ORDER_ENGINEER_GUARD 107 //SKYRAT EDIT ADDITION +#define JOB_DISPLAY_ORDER_CUSTOMS_AGENT 108 //SKYRAT EDIT ADDITION +#define JOB_DISPLAY_ORDER_EXP_CORPS 109 //SKYRAT EDIT ADDITON #define DEPARTMENT_UNASSIGNED "No Department" @@ -236,6 +238,10 @@ #define JOB_CAN_BE_INTERN (1<<8) /// This job cannot have more slots opened by the Head of Personnel (but admins or other random events can still do this). #define JOB_CANNOT_OPEN_SLOTS (1<<9) +/// This job will not display on the job menu when there are no slots available, instead of appearing greyed out +#define JOB_HIDE_WHEN_EMPTY (1<<10) +/// This job cannot be signed up for at round start or recorded in your preferences +#define JOB_LATEJOIN_ONLY (1<<11) /// Combination flag for jobs which are considered regular crew members of the station. #define STATION_JOB_FLAGS (JOB_ANNOUNCE_ARRIVAL|JOB_CREW_MANIFEST|JOB_EQUIP_RANK|JOB_CREW_MEMBER|JOB_NEW_PLAYER_JOINABLE|JOB_REOPEN_ON_ROUNDSTART_LOSS|JOB_ASSIGN_QUIRKS|JOB_CAN_BE_INTERN) diff --git a/code/_globalvars/lists/mapping.dm b/code/_globalvars/lists/mapping.dm index 8ac2f0d3ddf..b77942bad87 100644 --- a/code/_globalvars/lists/mapping.dm +++ b/code/_globalvars/lists/mapping.dm @@ -107,6 +107,7 @@ GLOBAL_LIST_EMPTY(generic_event_spawns) /// essentially allowing a user to override generic job spawnpoints with a specific one GLOBAL_LIST_EMPTY(jobspawn_overrides) +GLOBAL_LIST_EMPTY(gorilla_start) GLOBAL_LIST_EMPTY(wizardstart) GLOBAL_LIST_EMPTY(nukeop_start) GLOBAL_LIST_EMPTY(nukeop_leader_start) diff --git a/code/_globalvars/lists/names.dm b/code/_globalvars/lists/names.dm index bc195bcf5f4..c51fbaa9eb7 100644 --- a/code/_globalvars/lists/names.dm +++ b/code/_globalvars/lists/names.dm @@ -25,6 +25,7 @@ GLOBAL_LIST_INIT(megacarp_first_names, world.file2list("strings/names/megacarp1. GLOBAL_LIST_INIT(megacarp_last_names, world.file2list("strings/names/megacarp2.txt")) GLOBAL_LIST_INIT(cyberauth_names, world.file2list("strings/names/cyberauth.txt")) GLOBAL_LIST_INIT(syndicate_monkey_names, world.file2list("strings/names/syndicate_monkey.txt")) +GLOBAL_LIST_INIT(cargorilla_names, world.file2list("strings/names/cargorilla.txt")) GLOBAL_LIST_INIT(guardian_first_names, world.file2list("strings/names/guardian_descriptions.txt")) GLOBAL_LIST_INIT(guardian_tech_surnames, world.file2list("strings/names/guardian_gamepieces.txt")) GLOBAL_LIST_INIT(guardian_fantasy_surnames, world.file2list("strings/names/guardian_tarot.txt")) diff --git a/code/_onclick/hud/new_player.dm b/code/_onclick/hud/new_player.dm index 376164235a7..6edd9c65d2a 100644 --- a/code/_onclick/hud/new_player.dm +++ b/code/_onclick/hud/new_player.dm @@ -1,38 +1,66 @@ /* SKYRAT EDIT REMOVAL - Custom HTML Lobby Screen #define SHUTTER_MOVEMENT_DURATION 0.4 SECONDS #define SHUTTER_WAIT_DURATION 0.2 SECONDS +/// Maximum number of station trait buttons we will display, please think hard before creating scenarios where there are more than this +#define MAX_STATION_TRAIT_BUTTONS_VERTICAL 3 /datum/hud/new_player ///Whether the menu is currently on the client's screen or not var/menu_hud_status = TRUE /datum/hud/new_player/New(mob/owner) - ..() + . = ..() - if(!owner || !owner.client) + if (!owner || !owner.client) return - if(owner.client.interviewee) + if (owner.client.interviewee) return var/list/buttons = subtypesof(/atom/movable/screen/lobby) - for(var/button_type in buttons) - var/atom/movable/screen/lobby/lobbyscreen = new button_type(our_hud = src) + for (var/atom/movable/screen/lobby/lobbyscreen as anything in buttons) + if (!initial(lobbyscreen.always_available)) + continue + lobbyscreen = new lobbyscreen(our_hud = src) lobbyscreen.SlowInit() static_inventory += lobbyscreen - if(!lobbyscreen.always_shown) + if (!lobbyscreen.always_shown) lobbyscreen.RegisterSignal(src, COMSIG_HUD_LOBBY_COLLAPSED, TYPE_PROC_REF(/atom/movable/screen/lobby, collapse_button)) lobbyscreen.RegisterSignal(src, COMSIG_HUD_LOBBY_EXPANDED, TYPE_PROC_REF(/atom/movable/screen/lobby, expand_button)) - if(istype(lobbyscreen, /atom/movable/screen/lobby/button)) + if (istype(lobbyscreen, /atom/movable/screen/lobby/button)) var/atom/movable/screen/lobby/button/lobby_button = lobbyscreen lobby_button.owner = REF(owner) + add_station_trait_buttons() + +/// Display buttons for relevant station traits +/datum/hud/new_player/proc/add_station_trait_buttons() + if (!mymob?.client || mymob.client.interviewee || !length(GLOB.lobby_station_traits)) + return + var/buttons_created = 0 + var/y_offset = 397 + var/y_button_offset = 27 + for (var/datum/station_trait/trait as anything in GLOB.lobby_station_traits) + if (!trait.can_display_lobby_button()) + continue + var/atom/movable/screen/lobby/button/sign_up/sign_up_button = new(our_hud = src) + sign_up_button.SlowInit() + sign_up_button.owner = REF(mymob) + sign_up_button.screen_loc = offset_to_screen_loc(233, y_offset, mymob.client.view) + y_offset += y_button_offset + static_inventory += sign_up_button + trait.setup_lobby_button(sign_up_button) + buttons_created++ + if (buttons_created >= MAX_STATION_TRAIT_BUTTONS_VERTICAL) + return /atom/movable/screen/lobby plane = SPLASHSCREEN_PLANE layer = LOBBY_MENU_LAYER screen_loc = "TOP,CENTER" - ///Whether this HUD element can be hidden from the client's "screen" (moved off-screen) or not + /// Whether this HUD element can be hidden from the client's "screen" (moved off-screen) or not var/always_shown = FALSE + /// If true we will create this button every time the HUD is generated + var/always_available = TRUE ///Set the HUD in New, as lobby screens are made before Atoms are Initialized. /atom/movable/screen/lobby/New(loc, datum/hud/our_hud, ...) @@ -413,6 +441,23 @@ var/mob/dead/new_player/new_player = hud.mymob new_player.handle_player_polling() +/// A generic "sign up" button used by station traits +/atom/movable/screen/lobby/button/sign_up + icon = 'icons/hud/lobby/signup_button.dmi' + icon_state = "signup" + base_icon_state = "signup" + always_available = FALSE + +/atom/movable/screen/lobby/button/sign_up/MouseEntered(location, control, params) + . = ..() + if(QDELETED(src) || !desc) + return + openToolTip(usr, tip_src = src, params = params, title = name, content = desc,) + +/atom/movable/screen/lobby/button/sign_up/MouseExited() + . = ..() + closeToolTip(usr) + /atom/movable/screen/lobby/button/collapse name = "Collapse Lobby Menu" icon = 'icons/hud/lobby/collapse_expand.dmi' @@ -540,5 +585,5 @@ #undef SHUTTER_MOVEMENT_DURATION #undef SHUTTER_WAIT_DURATION - +#undef MAX_STATION_TRAIT_BUTTONS_VERTICAL */ // SKYRAT EDIT END diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 5053b4672f3..e812e5b2b5d 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -55,6 +55,10 @@ /atom/movable/screen/proc/component_click(atom/movable/screen/component_button/component, params) return +/// Returns the mob this is being displayed to, if any +/atom/movable/screen/proc/get_mob() + return hud?.mymob + /atom/movable/screen/text icon = null icon_state = null diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index 8376059e910..027c70447b0 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -94,6 +94,18 @@ SUBSYSTEM_DEF(job) set_overflow_role(CONFIG_GET(string/overflow_job)) // this must always go after load_jobs_from_config() due to how the legacy systems operate, this always takes precedent. return SS_INIT_SUCCESS +/// Returns a list of jobs that we are allowed to fuck with during random events +/datum/controller/subsystem/job/proc/get_valid_overflow_jobs() + var/static/list/overflow_jobs + if (!isnull(overflow_jobs)) + return overflow_jobs + + overflow_jobs = list() + for (var/datum/job/check_job in joinable_occupations) + if (!check_job.allow_bureaucratic_error) + continue + overflow_jobs += check_job + return overflow_jobs /datum/controller/subsystem/job/proc/set_overflow_role(new_overflow_role) var/datum/job/new_overflow = ispath(new_overflow_role) ? GetJobType(new_overflow_role) : GetJob(new_overflow_role) diff --git a/code/controllers/subsystem/processing/station.dm b/code/controllers/subsystem/processing/station.dm index b30a276fc36..53413166e97 100644 --- a/code/controllers/subsystem/processing/station.dm +++ b/code/controllers/subsystem/processing/station.dm @@ -18,6 +18,7 @@ PROCESSING_SUBSYSTEM_DEF(station) // Autowiki also wants consistent outputs, for example making sure the vending machine page always reports the normal products #if !defined(UNIT_TESTS) && !defined(AUTOWIKI) SetupTraits() + //display_lobby_traits() SKYRAT EDIT REMOVAL #endif announcer = new announcer() //Initialize the station's announcer datum @@ -96,3 +97,14 @@ PROCESSING_SUBSYSTEM_DEF(station) for(var/i in trait_instance.blacklist) var/datum/station_trait/trait_to_remove = i selectable_traits_by_types[initial(trait_to_remove.trait_type)] -= trait_to_remove + +/* SKYRAT EDIT REMOVAL +/// Update station trait lobby buttons for clients who joined before we initialised this subsystem +/datum/controller/subsystem/processing/station/proc/display_lobby_traits() + for (var/mob/dead/new_player/player as anything in GLOB.new_player_list) + var/datum/hud/new_player/observer_hud = player.hud_used + if (!istype(observer_hud)) + continue + observer_hud.add_station_trait_buttons() + observer_hud.show_hud(observer_hud.hud_version) +*/ diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 97b2c85b2aa..bdc55ecdfc0 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -242,6 +242,7 @@ SUBSYSTEM_DEF(ticker) var/can_continue = 0 can_continue = src.mode.pre_setup() //Choose antagonists CHECK_TICK + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_PRE_JOBS_ASSIGNED, src) can_continue = can_continue && SSjob.DivideOccupations() //Distribute jobs CHECK_TICK diff --git a/code/datums/components/ghost_direct_control.dm b/code/datums/components/ghost_direct_control.dm index c4d08380db1..412ae0f767e 100644 --- a/code/datums/components/ghost_direct_control.dm +++ b/code/datums/components/ghost_direct_control.dm @@ -30,7 +30,7 @@ src.ban_type = ban_type src.assumed_control_message = assumed_control_message || "You are [parent]!" src.extra_control_checks = extra_control_checks - src.after_assumed_control= after_assumed_control + src.after_assumed_control = after_assumed_control var/mob/mob_parent = parent LAZYADD(GLOB.joinable_mobs[format_text("[initial(mob_parent.name)]")], mob_parent) @@ -42,9 +42,10 @@ . = ..() RegisterSignal(parent, COMSIG_ATOM_ATTACK_GHOST, PROC_REF(on_ghost_clicked)) RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examined)) + RegisterSignal(parent, COMSIG_MOB_LOGIN, PROC_REF(on_login)) /datum/component/ghost_direct_control/UnregisterFromParent() - UnregisterSignal(parent, list(COMSIG_ATOM_ATTACK_GHOST, COMSIG_ATOM_EXAMINE)) + UnregisterSignal(parent, list(COMSIG_ATOM_ATTACK_GHOST, COMSIG_ATOM_EXAMINE, COMSIG_MOB_LOGIN)) return ..() /datum/component/ghost_direct_control/Destroy(force, silent) @@ -138,3 +139,8 @@ to_chat(new_body, span_boldnotice(assumed_control_message)) after_assumed_control?.Invoke(harbinger) qdel(src) + +/// When someone else assumes control via some other means, get rid of our component +/datum/component/ghost_direct_control/proc/on_login() + SIGNAL_HANDLER + qdel(src) diff --git a/code/datums/station_traits/_station_trait.dm b/code/datums/station_traits/_station_trait.dm index 8e8303c0366..5cbf0d4da9f 100644 --- a/code/datums/station_traits/_station_trait.dm +++ b/code/datums/station_traits/_station_trait.dm @@ -1,3 +1,6 @@ +/// Station traits displayed in the lobby +GLOBAL_LIST_EMPTY(lobby_station_traits) + ///Base class of station traits. These are used to influence rounds in one way or the other by influencing the levers of the station. /datum/station_trait ///Name of the trait @@ -22,6 +25,10 @@ var/trait_flags = STATION_TRAIT_MAP_UNRESTRICTED /// Whether or not this trait can be reverted by an admin var/can_revert = TRUE + /// If set to true we'll show a button on the lobby to notify people about this trait + var/sign_up_button = FALSE + /// Lobby buttons controlled by this trait + var/list/lobby_buttons = list() /// The ID that we look for in dynamic.json. Not synced with 'name' because I can already see this go wrong var/dynamic_threat_id /// If ran during dynamic, do we reduce the total threat? Will be overriden by config if set @@ -34,7 +41,8 @@ if(threat_reduction) GLOB.dynamic_station_traits[src] = threat_reduction - + if(sign_up_button) + GLOB.lobby_station_traits += src if(trait_processes) START_PROCESSING(SSstation, src) if(trait_to_give) @@ -43,14 +51,10 @@ /datum/station_trait/Destroy() SSstation.station_traits -= src GLOB.dynamic_station_traits.Remove(src) + destroy_lobby_buttons() return ..() -/// Proc ran when round starts. Use this for roundstart effects. -/datum/station_trait/proc/on_round_start() - SIGNAL_HANDLER - return - -///type of info the centcom report has on this trait, if any. +/// Returns the type of info the centcom report has on this trait, if any. /datum/station_trait/proc/get_report() return "[name] - [report_message]" @@ -64,7 +68,7 @@ qdel(src) -///Called by decals if they can be colored, to see if we got some cool colors for them. Only takes the first station trait +/// Called by decals if they can be colored, to see if we got some cool colors for them. Only takes the first station trait /proc/request_station_colors(atom/thing_to_color, pattern) for(var/datum/station_trait/trait in SSstation.station_traits) var/decal_color = trait.get_decal_color(thing_to_color, pattern || PATTERN_DEFAULT) @@ -72,6 +76,53 @@ return decal_color return null -///Return a color for the decals, if any +/// Return a color for the decals, if any /datum/station_trait/proc/get_decal_color(thing_to_color, pattern) return + +/// Return TRUE if we want to show a lobby button, by default we assume we don't want it after the round begins +/datum/station_trait/proc/can_display_lobby_button() + return sign_up_button && !SSticker.HasRoundStarted() + +/* SKYRAT EDIT REMOVAL +/// Apply any additional handling we need to our lobby button +/datum/station_trait/proc/setup_lobby_button(atom/movable/screen/lobby/button/sign_up/lobby_button) + SHOULD_CALL_PARENT(TRUE) + lobby_buttons |= lobby_button + RegisterSignal(lobby_button, COMSIG_ATOM_UPDATE_ICON, PROC_REF(on_lobby_button_update_icon)) + RegisterSignal(lobby_button, COMSIG_CLICK, PROC_REF(on_lobby_button_click)) + RegisterSignal(lobby_button, COMSIG_QDELETING, PROC_REF(on_lobby_button_destroyed)) + lobby_button.update_appearance(UPDATE_ICON) + +/// Called when our lobby button is clicked on +/datum/station_trait/proc/on_lobby_button_click(atom/movable/screen/lobby/button/sign_up/lobby_button, location, control, params, mob/dead/new_player/user) + SIGNAL_HANDLER + return + +/// Called when our lobby button tries to update its appearance +/datum/station_trait/proc/on_lobby_button_update_icon(atom/movable/screen/lobby/button/sign_up/lobby_button, updates) + SIGNAL_HANDLER + return + +/// Don't hold references to deleted buttons +/datum/station_trait/proc/on_lobby_button_destroyed(atom/movable/screen/lobby/button/sign_up/lobby_button) + SIGNAL_HANDLER + lobby_buttons -= lobby_button +*/ + +/// Proc ran when round starts. Use this for roundstart effects. By default we clean up our buttons here. +/datum/station_trait/proc/on_round_start() + SIGNAL_HANDLER + destroy_lobby_buttons() + +/// Remove all of our active lobby buttons +/datum/station_trait/proc/destroy_lobby_buttons() + for (var/atom/movable/screen/button as anything in lobby_buttons) + var/mob/hud_owner = button.get_mob() + qdel(button) + if (QDELETED(hud_owner)) + continue + var/datum/hud/using_hud = hud_owner.hud_used + using_hud?.show_hud(using_hud?.hud_version) + lobby_buttons = list() + diff --git a/code/datums/station_traits/job_traits.dm b/code/datums/station_traits/job_traits.dm new file mode 100644 index 00000000000..63351af038c --- /dev/null +++ b/code/datums/station_traits/job_traits.dm @@ -0,0 +1,101 @@ +/** + * A station trait which enables a temporary job + * Generally speaking these should always all be mutually exclusive, don't have too many at once + */ +/datum/station_trait/job + sign_up_button = TRUE + trait_flags = STATION_TRAIT_ABSTRACT + /// What tooltip to show on the button + var/button_desc = "Sign up to gain some kind of unusual job, not available in most rounds." + /// Type of job to enable + var/job_to_add = /datum/job/clown + /// Who signed up to this in the lobby + var/list/lobby_candidates + +/datum/station_trait/job/New() + . = ..() + blacklist += subtypesof(/datum/station_trait/job) - type // All but ourselves + RegisterSignal(SSdcs, COMSIG_GLOB_PRE_JOBS_ASSIGNED, PROC_REF(pre_jobs_assigned)) + +/* SKYRAT EDIT REMOVAL +/datum/station_trait/job/setup_lobby_button(atom/movable/screen/lobby/button/sign_up/lobby_button) + RegisterSignal(lobby_button, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_lobby_button_update_overlays)) + lobby_button.desc = button_desc + return ..() + + +/datum/station_trait/job/on_lobby_button_click(atom/movable/screen/lobby/button/sign_up/lobby_button, location, control, params, mob/dead/new_player/user) + if (LAZYFIND(lobby_candidates, user)) + LAZYREMOVE(lobby_candidates, user) + else + LAZYADD(lobby_candidates, user) + + +/datum/station_trait/job/on_lobby_button_update_icon(atom/movable/screen/lobby/button/sign_up/lobby_button, updates) + if (LAZYFIND(lobby_candidates, lobby_button.get_mob())) + lobby_button.base_icon_state = "signup_on" + else + lobby_button.base_icon_state = "signup" + +/// Add an overlay based on whether you are actively signed up for this role +/datum/station_trait/job/proc/on_lobby_button_update_overlays(atom/movable/screen/lobby/button/sign_up/lobby_button, list/overlays) + SIGNAL_HANDLER + overlays += LAZYFIND(lobby_candidates, lobby_button.get_mob()) ? "tick" : "cross" +*/ + +/// Called before we start assigning roles, assign ours first +/datum/station_trait/job/proc/pre_jobs_assigned() + SIGNAL_HANDLER + sign_up_button = FALSE + destroy_lobby_buttons() + for (var/mob/dead/new_player/signee as anything in lobby_candidates) + if (isnull(signee) || !signee.client || !signee.mind || signee.ready != PLAYER_READY_TO_PLAY) + LAZYREMOVE(lobby_candidates, signee) + if (!LAZYLEN(lobby_candidates)) + on_failed_assignment() + return // Nobody signed up :( + var/mob/dead/new_player/picked_player = pick(lobby_candidates) + picked_player.mind.assigned_role = new job_to_add() + lobby_candidates = null + +/// Called if we didn't assign a role before the round began, we add it to the latejoin menu instead +/datum/station_trait/job/proc/on_failed_assignment() + var/datum/job/our_job = job_to_add + our_job = SSjob.GetJob(our_job::title) + our_job.total_positions++ + + +/// Adds a gorilla to the cargo department, replacing the sloth and the mech +/datum/station_trait/job/cargorilla + name = "Cargo Gorilla" + button_desc = "Sign up to become the Cargo Gorilla, a peaceful shepherd of boxes." + weight = 1 + show_in_report = FALSE // Selective attention test. Did you spot the gorilla? + job_to_add = /datum/job/cargo_gorilla + trait_flags = STATION_TRAIT_MAP_UNRESTRICTED + +/datum/station_trait/job/cargorilla/New() + . = ..() + RegisterSignal(SSatoms, COMSIG_SUBSYSTEM_POST_INITIALIZE, PROC_REF(replace_cargo)) + +/* SKYRAT EDIT REMOVAL +/datum/station_trait/job/cargorilla/on_lobby_button_update_overlays(atom/movable/screen/lobby/button/sign_up/lobby_button, list/overlays) + . = ..() + overlays += LAZYFIND(lobby_candidates, lobby_button.get_mob()) ? "gorilla_on" : "gorilla_off" +*/ + +/// Remove the cargo equipment and personnel that are being replaced by a gorilla. +/datum/station_trait/job/cargorilla/proc/replace_cargo(datum/source) + SIGNAL_HANDLER + var/mob/living/basic/sloth/cargo_sloth = GLOB.cargo_sloth + if(isnull(cargo_sloth)) + lobby_candidates = list() + destroy_lobby_buttons() // Sorry folks + sign_up_button = FALSE + return + + // hmm our sloth looks funny today + qdel(cargo_sloth) + // monkey carries the crates, the age of robot is over + if(GLOB.cargo_ripley) + qdel(GLOB.cargo_ripley) diff --git a/code/datums/station_traits/negative_traits.dm b/code/datums/station_traits/negative_traits.dm index 5c37fd7ede5..8d0583c9d75 100644 --- a/code/datums/station_traits/negative_traits.dm +++ b/code/datums/station_traits/negative_traits.dm @@ -123,7 +123,7 @@ /datum/station_trait/overflow_job_bureaucracy/proc/set_overflow_job_override(datum/source) SIGNAL_HANDLER - var/datum/job/picked_job = pick(SSjob.joinable_occupations) + var/datum/job/picked_job = pick(SSjob.get_valid_overflow_jobs()) chosen_job_name = lowertext(picked_job.title) // like Chief Engineers vs like chief engineers SSjob.set_overflow_role(picked_job.type) diff --git a/code/datums/station_traits/neutral_traits.dm b/code/datums/station_traits/neutral_traits.dm index f0b2c625537..5e864738f8e 100644 --- a/code/datums/station_traits/neutral_traits.dm +++ b/code/datums/station_traits/neutral_traits.dm @@ -141,60 +141,6 @@ var/new_colored_assistant_type = pick(subtypesof(/datum/colored_assistant) - get_configured_colored_assistant_type()) GLOB.colored_assistant = new new_colored_assistant_type -/datum/station_trait/cargorilla - name = "Cargo Gorilla" - trait_type = STATION_TRAIT_NEUTRAL - weight = 1 - show_in_report = FALSE // Selective attention test. Did you spot the gorilla? - - /// The gorilla we created, we only hold this ref until the round starts. - var/mob/living/basic/gorilla/cargorilla/cargorilla - -/datum/station_trait/cargorilla/New() - . = ..() - RegisterSignal(SSatoms, COMSIG_SUBSYSTEM_POST_INITIALIZE, PROC_REF(replace_cargo)) - -/// Replace some cargo equipment and 'personnel' with a gorilla. -/datum/station_trait/cargorilla/proc/replace_cargo(datum/source) - SIGNAL_HANDLER - - var/mob/living/basic/sloth/cargo_sloth = GLOB.cargo_sloth - if(isnull(cargo_sloth)) - return - - cargorilla = new(cargo_sloth.loc) - cargorilla.name = cargo_sloth.name - // We do a poll on roundstart, don't let ghosts in early - INVOKE_ASYNC(src, PROC_REF(make_id_for_gorilla)) - // hm our sloth looks funny today - qdel(cargo_sloth) - - // monkey carries the crates, the age of robot is over - if(GLOB.cargo_ripley) - qdel(GLOB.cargo_ripley) - -/// Makes an ID card for the gorilla -/datum/station_trait/cargorilla/proc/make_id_for_gorilla() - var/obj/item/card/id/advanced/cargo_gorilla/gorilla_id = new(cargorilla.loc) - gorilla_id.registered_name = cargorilla.name - gorilla_id.update_label() - - cargorilla.put_in_hands(gorilla_id, del_on_fail = TRUE) - -/datum/station_trait/cargorilla/on_round_start() - if(!cargorilla) - return - - addtimer(CALLBACK(src, PROC_REF(get_ghost_for_gorilla), cargorilla), 12 SECONDS) // give ghosts a bit of time to funnel in - cargorilla = null - -/// Get us a ghost for the gorilla. -/datum/station_trait/cargorilla/proc/get_ghost_for_gorilla(mob/living/basic/gorilla/cargorilla/gorilla) - if(QDELETED(gorilla)) - return - - gorilla.poll_for_gorilla() - /datum/station_trait/birthday name = "Employee Birthday" trait_type = STATION_TRAIT_NEUTRAL diff --git a/code/modules/client/preferences/middleware/jobs.dm b/code/modules/client/preferences/middleware/jobs.dm index d61fb53c98f..cee99bacec4 100644 --- a/code/modules/client/preferences/middleware/jobs.dm +++ b/code/modules/client/preferences/middleware/jobs.dm @@ -53,6 +53,8 @@ var/list/jobs = list() for (var/datum/job/job as anything in SSjob.joinable_occupations) + if (job.job_flags & JOB_LATEJOIN_ONLY) + continue var/datum/job_department/department_type = job.department_for_prefs || job.departments_list?[1] if (isnull(department_type)) stack_trace("[job] does not have a department set, yet is a joinable occupation!") @@ -118,6 +120,8 @@ var/list/job_required_experience = list() for (var/datum/job/job as anything in SSjob.all_occupations) + if (job.job_flags & JOB_LATEJOIN_ONLY) + continue var/required_playtime_remaining = job.required_playtime_remaining(user.client) if (required_playtime_remaining) job_required_experience[job.title] = list( diff --git a/code/modules/events/bureaucratic_error.dm b/code/modules/events/bureaucratic_error.dm index add5ad58b4a..0e44ac391c1 100644 --- a/code/modules/events/bureaucratic_error.dm +++ b/code/modules/events/bureaucratic_error.dm @@ -13,21 +13,17 @@ priority_announce("A recent bureaucratic error in the Organic Resources Department may result in personnel shortages in some departments and redundant staffing in others.", "Paperwork Mishap Alert") /datum/round_event/bureaucratic_error/start() - var/list/jobs = SSjob.joinable_occupations.Copy() - /* - if(prob(33)) // Only allows latejoining as a single role. Add latejoin AI bluespace pods for fun later. + var/list/jobs = SSjob.get_valid_overflow_jobs() + /* SKYRAT EDIT REMOVAL START + if(prob(33)) // Only allows latejoining as a single role. var/datum/job/overflow = pick_n_take(jobs) overflow.spawn_positions = -1 overflow.total_positions = -1 // Ensures infinite slots as this role. Assistant will still be open for those that cant play it. for(var/job in jobs) var/datum/job/current = job - if(!current.allow_bureaucratic_error) - continue current.total_positions = 0 - else // Adds/removes a random amount of job slots from all jobs. + return */ // SKYRAT EDIT REMOVAL - no more locking off jobs + // Adds/removes a random amount of job slots from all jobs. for(var/datum/job/current as anything in jobs) - if(!current.allow_bureaucratic_error) - continue - var/ran = rand(1,4) // SKYRAT EDIT - no more locking off jobs - current.total_positions = max(current.total_positions + ran, 0) + current.total_positions = max(current.total_positions + rand(-2,4), 1) // SKYRAT EDIT CHANGE - No more locking off jobs - ORIGINAL: current.total_positions = max(current.total_positions + rand(-2,4), 0) diff --git a/code/modules/jobs/job_types/cargo_gorilla.dm b/code/modules/jobs/job_types/cargo_gorilla.dm new file mode 100644 index 00000000000..96a79e3a4d3 --- /dev/null +++ b/code/modules/jobs/job_types/cargo_gorilla.dm @@ -0,0 +1,50 @@ +/datum/job/cargo_gorilla + title = JOB_CARGO_GORILLA + description = "Assist the supply department by moving freight and disposing of unwanted fruits." + department_head = list(JOB_QUARTERMASTER) + faction = FACTION_STATION + total_positions = 0 + spawn_positions = 0 + supervisors = SUPERVISOR_QM + spawn_type = /mob/living/basic/gorilla/cargorilla + config_tag = "CARGO_GORILLA" + random_spawns_possible = FALSE + display_order = JOB_DISPLAY_ORDER_CARGO_GORILLA + departments_list = list(/datum/job_department/cargo) + mail_goodies = list( + /obj/item/food/grown/banana = 1, + ) + rpg_title = "Beast of Burden" + allow_bureaucratic_error = FALSE + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_NEW_PLAYER_JOINABLE | JOB_EQUIP_RANK | JOB_CANNOT_OPEN_SLOTS | JOB_HIDE_WHEN_EMPTY | JOB_LATEJOIN_ONLY + +/datum/job/cargo_gorilla/get_roundstart_spawn_point() + if (length(GLOB.gorilla_start)) + return pick(GLOB.gorilla_start) + return ..() + +/datum/job/cargo_gorilla/get_spawn_mob(client/player_client, atom/spawn_point) + if (!player_client) + return + var/mob/living/the_big_man = new spawn_type(get_turf(spawn_point)) + the_big_man.fully_replace_character_name(the_big_man.real_name, pick(GLOB.cargorilla_names)) + return the_big_man + +/datum/job/cargo_gorilla/after_spawn(mob/living/spawned, client/player_client) + . = ..() + // Gorilla with a wage, what's he buyin? + var/datum/bank_account/bank_account = new(spawned.real_name, src) + bank_account.payday(STARTING_PAYCHECKS, TRUE) + bank_account.replaceable = FALSE + spawned.add_mob_memory(/datum/memory/key/account, remembered_id = bank_account.account_id) + + var/obj/item/card/id/advanced/cargo_gorilla/gorilla_id = new(spawned.loc) + gorilla_id.registered_name = spawned.name + gorilla_id.update_label() + gorilla_id.registered_account = bank_account + bank_account.bank_cards += gorilla_id + spawned.put_in_hands(gorilla_id, del_on_fail = TRUE) + + to_chat(spawned, span_boldnotice("You are Cargorilla, a pacifist friend of the station and carrier of freight.")) + to_chat(spawned, span_notice("You can pick up crates by clicking on them, and drop them by clicking on the ground.")) + spawned.mind.special_role = "Cargorilla" diff --git a/code/modules/mob/dead/new_player/latejoin_menu.dm b/code/modules/mob/dead/new_player/latejoin_menu.dm index 059a5014d0c..d2db3aa34b7 100644 --- a/code/modules/mob/dead/new_player/latejoin_menu.dm +++ b/code/modules/mob/dead/new_player/latejoin_menu.dm @@ -80,6 +80,8 @@ GLOBAL_DATUM_INIT(latejoin_menu, /datum/latejoin_menu, new) ) if(job_availability != JOB_AVAILABLE) + if (job_datum.job_flags & JOB_HIDE_WHEN_EMPTY) + continue job_data["unavailable_reason"] = get_job_unavailable_error_message(job_availability, job_datum.title) if(job_datum.total_positions < 0) @@ -95,6 +97,7 @@ GLOBAL_DATUM_INIT(latejoin_menu, /datum/latejoin_menu, new) /datum/latejoin_menu/ui_static_data(mob/user) var/list/departments = list() + var/mob/dead/new_player/owner = user for(var/datum/job_department/department as anything in SSjob.joinable_departments) var/list/department_jobs = list() @@ -108,6 +111,8 @@ GLOBAL_DATUM_INIT(latejoin_menu, /datum/latejoin_menu, new) //Jobs under multiple departments should only be displayed if this is their first department or the command department if(LAZYLEN(job_datum.departments_list) > 1 && job_datum.departments_list[1] != department.type && !(job_datum.departments_bitflags & DEPARTMENT_BITFLAG_COMMAND)) continue + if((job_datum.job_flags & JOB_HIDE_WHEN_EMPTY) && owner.IsJobUnavailable(job_datum.title, latejoin = TRUE) != JOB_AVAILABLE) + continue var/list/job_data = list( "command" = !!(job_datum.departments_bitflags & DEPARTMENT_BITFLAG_COMMAND), diff --git a/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm index 1e17938c5fd..64cff6780df 100644 --- a/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm +++ b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm @@ -158,31 +158,4 @@ ADD_TRAIT(src, TRAIT_PACIFISM, INNATE_TRAIT) AddComponent(/datum/component/crate_carrier) -/mob/living/basic/gorilla/cargorilla/death(gibbed) - var/datum/component/potential_component = GetComponent(/datum/component/ghost_direct_control) - if(!QDELETED(potential_component)) - qdel(potential_component) - return ..() - -/** - * Poll ghosts for control of the gorilla. Not added in init because we only want to poll when the round starts. - * Preferably in future we can replace this with a popup on the lobby to queue to become a gorilla. - */ -/mob/living/basic/gorilla/cargorilla/proc/poll_for_gorilla() - AddComponent(\ - /datum/component/ghost_direct_control,\ - poll_candidates = TRUE,\ - poll_length = 30 SECONDS,\ - role_name = "Cargorilla",\ - assumed_control_message = "You are Cargorilla, a pacifist friend of the station and carrier of freight.",\ - poll_ignore_key = POLL_IGNORE_CARGORILLA,\ - after_assumed_control = CALLBACK(src, PROC_REF(became_player_controlled)),\ - ) - -/// Called once a ghost assumes control -/mob/living/basic/gorilla/cargorilla/proc/became_player_controlled() - mind.set_assigned_role(SSjob.GetJobType(/datum/job/cargo_technician)) - mind.special_role = "Cargorilla" - to_chat(src, span_notice("You can pick up crates by clicking on them, and drop them by clicking on the ground.")) - #undef GORILLA_HANDS_LAYER diff --git a/code/modules/mob/living/basic/pets/sloth.dm b/code/modules/mob/living/basic/pets/sloth.dm index 0b1546ccf93..125a3a7b97d 100644 --- a/code/modules/mob/living/basic/pets/sloth.dm +++ b/code/modules/mob/living/basic/pets/sloth.dm @@ -44,11 +44,12 @@ GLOBAL_DATUM(cargo_sloth, /mob/living/basic/sloth) AddElement(/datum/element/ai_retaliate) AddComponent(/datum/component/tree_climber) - if(!mapload || isnull(GLOB.cargo_sloth) || !is_station_level(z)) + if(!mapload || !isnull(GLOB.cargo_sloth) || !is_station_level(z)) return // If someone adds non-cargo sloths to maps we'll have a problem but we're fine for now GLOB.cargo_sloth = src + GLOB.gorilla_start += get_turf(src) /mob/living/basic/sloth/Destroy() if(GLOB.cargo_sloth == src) diff --git a/code/modules/tooltip/tooltip.dm b/code/modules/tooltip/tooltip.dm index 49539920920..6d6505d1dc5 100644 --- a/code/modules/tooltip/tooltip.dm +++ b/code/modules/tooltip/tooltip.dm @@ -107,22 +107,22 @@ Notes: //Open a tooltip for user, at a location based on params //Theme is a CSS class in tooltip.html, by default this wrapper chooses a CSS class based on the user's UI_style (Midnight, Plasmafire, Retro, etc) //Includes sanity.checks -/proc/openToolTip(mob/user = null, atom/movable/tip_src = null, params = null,title = "",content = "",theme = "") - if(istype(user)) - if(user.client && user.client.tooltips) - var/ui_style = user.client?.prefs?.read_preference(/datum/preference/choiced/ui_style) - if(!theme && ui_style) - theme = lowertext(ui_style) - if(!theme) - theme = "default" - user.client.tooltips.show(tip_src, params,title,content,theme) +/proc/openToolTip(mob/user = null, atom/movable/tip_src = null, params = null, title = "", content = "", theme = "") + if(!istype(user) || !user.client?.tooltips) + return + var/ui_style = user.client?.prefs?.read_preference(/datum/preference/choiced/ui_style) + if(!theme && ui_style) + theme = lowertext(ui_style) + if(!theme) + theme = "default" + user.client.tooltips.show(tip_src, params, title, content, theme) //Arbitrarily close a user's tooltip //Includes sanity checks. /proc/closeToolTip(mob/user) - if(istype(user)) - if(user.client && user.client.tooltips) - user.client.tooltips.hide() + if(!istype(user) || !user.client?.tooltips) + return + user.client.tooltips.hide() diff --git a/icons/hud/lobby/signup_button.dmi b/icons/hud/lobby/signup_button.dmi new file mode 100644 index 00000000000..4ff31a316c2 Binary files /dev/null and b/icons/hud/lobby/signup_button.dmi differ diff --git a/modular_skyrat/modules/title_screen/code/job_traits.dm b/modular_skyrat/modules/title_screen/code/job_traits.dm new file mode 100644 index 00000000000..2bbf74a4081 --- /dev/null +++ b/modular_skyrat/modules/title_screen/code/job_traits.dm @@ -0,0 +1,2 @@ +/datum/station_trait/proc/on_lobby_button_click(mob/dead/new_player/user) + return diff --git a/modular_skyrat/modules/title_screen/code/new_player.dm b/modular_skyrat/modules/title_screen/code/new_player.dm index 33e8a964695..0841d6c0700 100644 --- a/modular_skyrat/modules/title_screen/code/new_player.dm +++ b/modular_skyrat/modules/title_screen/code/new_player.dm @@ -17,6 +17,11 @@ make_me_an_observer() return + if(href_list["job_traits"]) + play_lobby_button_sound() + show_job_traits() + return + if(href_list["server_swap"]) play_lobby_button_sound() server_swap() @@ -136,6 +141,28 @@ to_chat_immediate(src, "So long, spaceman.") src.client << link(server_ip) +/** + * Shows currently available job traits + */ +/mob/dead/new_player/proc/show_job_traits() + if (!client || client.interviewee) + return + if(!length(GLOB.lobby_station_traits)) + to_chat(src, span_warning("There are currently no job traits available!")) + return + var/list/available_lobby_station_traits = list() + for (var/datum/station_trait/trait as anything in GLOB.lobby_station_traits) + if (!trait.can_display_lobby_button()) + continue + available_lobby_station_traits += trait + + var/datum/station_trait/clicked_trait = tgui_input_list(src, "Select a job trait to sign up for:", "Job Traits", available_lobby_station_traits) + + if(!clicked_trait) + return + + clicked_trait.on_lobby_button_click(src) + /** * Shows the player a list of current polls, if any. */ diff --git a/modular_skyrat/modules/title_screen/code/station_traits.dm b/modular_skyrat/modules/title_screen/code/station_traits.dm new file mode 100644 index 00000000000..a42bd11ecd2 --- /dev/null +++ b/modular_skyrat/modules/title_screen/code/station_traits.dm @@ -0,0 +1,7 @@ +/datum/station_trait/job/on_lobby_button_click(mob/dead/new_player/user) + if (LAZYFIND(lobby_candidates, user)) + LAZYREMOVE(lobby_candidates, user) + to_chat(user, span_redtext("You have been removed from the [name] list of candidates.")) + else + LAZYADD(lobby_candidates, user) + to_chat(user, span_greentext("You have been added to the [name] list of candidates.")) diff --git a/modular_skyrat/modules/title_screen/code/title_screen_html.dm b/modular_skyrat/modules/title_screen/code/title_screen_html.dm index 30f3f2949e2..2c1d3075586 100644 --- a/modular_skyrat/modules/title_screen/code/title_screen_html.dm +++ b/modular_skyrat/modules/title_screen/code/title_screen_html.dm @@ -118,6 +118,9 @@ GLOBAL_LIST_EMPTY(startup_messages) SWAP SERVERS "} + if(length(GLOB.lobby_station_traits) && !SSticker.HasRoundStarted()) + dat += {"JOB TRAITS"} + if(!is_guest_key(src.key)) dat += playerpolls() diff --git a/modular_skyrat/modules/title_screen/code/title_screen_subsystem.dm b/modular_skyrat/modules/title_screen/code/title_screen_subsystem.dm index 3c73ee456a2..0cd00ee82fa 100644 --- a/modular_skyrat/modules/title_screen/code/title_screen_subsystem.dm +++ b/modular_skyrat/modules/title_screen/code/title_screen_subsystem.dm @@ -23,6 +23,8 @@ SUBSYSTEM_DEF(title) var/list/progress_json = list() /// The reference realtime that we're treating as 0 for this run var/progress_reference_time = 0 + /// A list of station traits that have lobby buttons + var/list/available_lobby_station_traits = list() /datum/controller/subsystem/title/Initialize() var/dat diff --git a/strings/names/cargorilla.txt b/strings/names/cargorilla.txt new file mode 100644 index 00000000000..ec135f5ca4d --- /dev/null +++ b/strings/names/cargorilla.txt @@ -0,0 +1,7 @@ +Cala +Cerchak +Citrus +Coco +Grodd +Paperwork +Winston diff --git a/tgstation.dme b/tgstation.dme index 85913d6ed63..e492dafefe8 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1813,6 +1813,7 @@ #include "code\datums\skills\mining.dm" #include "code\datums\station_traits\_station_trait.dm" #include "code\datums\station_traits\admin_panel.dm" +#include "code\datums\station_traits\job_traits.dm" #include "code\datums\station_traits\negative_traits.dm" #include "code\datums\station_traits\neutral_traits.dm" #include "code\datums\station_traits\positive_traits.dm" @@ -4208,6 +4209,7 @@ #include "code\modules\jobs\job_types\bartender.dm" #include "code\modules\jobs\job_types\botanist.dm" #include "code\modules\jobs\job_types\captain.dm" +#include "code\modules\jobs\job_types\cargo_gorilla.dm" #include "code\modules\jobs\job_types\cargo_technician.dm" #include "code\modules\jobs\job_types\chemist.dm" #include "code\modules\jobs\job_types\chief_engineer.dm" @@ -7975,7 +7977,9 @@ #include "modular_skyrat\modules\time_clock\code\mind.dm" #include "modular_skyrat\modules\time_clock\code\off_duty_component.dm" #include "modular_skyrat\modules\title_screen\code\_title_screen_defines.dm" +#include "modular_skyrat\modules\title_screen\code\job_traits.dm" #include "modular_skyrat\modules\title_screen\code\new_player.dm" +#include "modular_skyrat\modules\title_screen\code\station_traits.dm" #include "modular_skyrat\modules\title_screen\code\title_screen_controls.dm" #include "modular_skyrat\modules\title_screen\code\title_screen_html.dm" #include "modular_skyrat\modules\title_screen\code\title_screen_pref_middleware.dm" diff --git a/tgui/packages/tgui/interfaces/common/JobToIcon.ts b/tgui/packages/tgui/interfaces/common/JobToIcon.ts index 87245260bed..75db6d4e678 100644 --- a/tgui/packages/tgui/interfaces/common/JobToIcon.ts +++ b/tgui/packages/tgui/interfaces/common/JobToIcon.ts @@ -12,6 +12,7 @@ const BASEICONS = { Bitrunner: 'gamepad', Botanist: 'seedling', Captain: 'crown', + 'Cargo Gorilla': 'paw', 'Cargo Technician': 'box', 'CentCom Commander': 'star', 'CentCom Head Intern': 'pen-fancy',