mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-20 20:45:28 +01:00
Bridge Assistant Station Trait (#80279)
## About The Pull Request adds a station trait which adds a new role, the bridge assistant he is designed to help commandeer the bridge and help out other heads when needed. he is armed with the mini energy gun (the one heads used to have on kilostation), a flash, a toolbelt (with an inducer), some cool shades and a swanky scarf. as he is a nerd he is weak and unable to twohand weapons, preventing him from wielding the fire axe. currently he does not have a mindshield but he cannot roll antag he currently has access to the bridge, announcement console, eva, teleporter, gateway, maint, and a weapon permit (somewhat (not really other than for nerds) interestingly this is the first job that isnt assistant that doesnt have access to any lathes, so he doesnt have orm access unlike all the other jobs (except assistant)) the trait also makes a coffee machine spawn on the bridge here is some useful art of your role  and ingame screenshots    ## Why It's Good For The Game Adds upon the station trait job system with a straight forward role that IS just a human (unlike the cargorilla), and is pretty basic with no custom assets or whatever other than hud icons Having the bridge assistant in some rounds seems like a neat way to protect it since it gets fucked up in like half the time, while also not having enough mechanical depth or gameplay as to warrant it as a permanent role ## Changelog 🆑 add: Bridge Assistant job accessible from a station trait. /🆑 --------- Co-authored-by: san7890 <the@san7890.com>
This commit is contained in:
@@ -83,6 +83,7 @@
|
||||
#define SECHUD_BARTENDER "hudbartender"
|
||||
#define SECHUD_BITRUNNER "hudbitrunner"
|
||||
#define SECHUD_BOTANIST "hudbotanist"
|
||||
#define SECHUD_BRIDGE_ASSISTANT "hudbridgeassistant"
|
||||
#define SECHUD_CAPTAIN "hudcaptain"
|
||||
#define SECHUD_CARGO_TECHNICIAN "hudcargotechnician"
|
||||
#define SECHUD_CHAPLAIN "hudchaplain"
|
||||
|
||||
+39
-35
@@ -48,6 +48,7 @@
|
||||
#define JOB_RESEARCH_DIRECTOR "Research Director"
|
||||
#define JOB_CHIEF_ENGINEER "Chief Engineer"
|
||||
#define JOB_CHIEF_MEDICAL_OFFICER "Chief Medical Officer"
|
||||
#define JOB_BRIDGE_ASSISTANT "Bridge Assistant"
|
||||
//Silicon
|
||||
#define JOB_AI "AI"
|
||||
#define JOB_CYBORG "Cyborg"
|
||||
@@ -122,41 +123,42 @@
|
||||
#define JOB_DISPLAY_ORDER_ASSISTANT 1
|
||||
#define JOB_DISPLAY_ORDER_CAPTAIN 2
|
||||
#define JOB_DISPLAY_ORDER_HEAD_OF_PERSONNEL 3
|
||||
#define JOB_DISPLAY_ORDER_BARTENDER 4
|
||||
#define JOB_DISPLAY_ORDER_BOTANIST 5
|
||||
#define JOB_DISPLAY_ORDER_COOK 6
|
||||
#define JOB_DISPLAY_ORDER_JANITOR 7
|
||||
#define JOB_DISPLAY_ORDER_CLOWN 8
|
||||
#define JOB_DISPLAY_ORDER_MIME 9
|
||||
#define JOB_DISPLAY_ORDER_CURATOR 10
|
||||
#define JOB_DISPLAY_ORDER_LAWYER 11
|
||||
#define JOB_DISPLAY_ORDER_CHAPLAIN 12
|
||||
#define JOB_DISPLAY_ORDER_PSYCHOLOGIST 13
|
||||
#define JOB_DISPLAY_ORDER_AI 14
|
||||
#define JOB_DISPLAY_ORDER_CYBORG 15
|
||||
#define JOB_DISPLAY_ORDER_CHIEF_ENGINEER 16
|
||||
#define JOB_DISPLAY_ORDER_STATION_ENGINEER 17
|
||||
#define JOB_DISPLAY_ORDER_ATMOSPHERIC_TECHNICIAN 18
|
||||
#define JOB_DISPLAY_ORDER_QUARTERMASTER 19
|
||||
#define JOB_DISPLAY_ORDER_CARGO_TECHNICIAN 20
|
||||
#define JOB_DISPLAY_ORDER_SHAFT_MINER 21
|
||||
#define JOB_DISPLAY_ORDER_BITRUNNER 22
|
||||
#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_BRIDGE_ASSISTANT 4
|
||||
#define JOB_DISPLAY_ORDER_BARTENDER 5
|
||||
#define JOB_DISPLAY_ORDER_BOTANIST 6
|
||||
#define JOB_DISPLAY_ORDER_COOK 7
|
||||
#define JOB_DISPLAY_ORDER_JANITOR 8
|
||||
#define JOB_DISPLAY_ORDER_CLOWN 9
|
||||
#define JOB_DISPLAY_ORDER_MIME 10
|
||||
#define JOB_DISPLAY_ORDER_CURATOR 11
|
||||
#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_VIROLOGIST 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_WARDEN 36
|
||||
#define JOB_DISPLAY_ORDER_DETECTIVE 37
|
||||
#define JOB_DISPLAY_ORDER_SECURITY_OFFICER 38
|
||||
#define JOB_DISPLAY_ORDER_PRISONER 39
|
||||
|
||||
#define DEPARTMENT_UNASSIGNED "No Department"
|
||||
|
||||
@@ -209,6 +211,8 @@
|
||||
|
||||
/// 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)
|
||||
/// Combination flag for jobs which should be there for every station trait job.
|
||||
#define STATION_TRAIT_JOB_FLAGS (JOB_CANNOT_OPEN_SLOTS|JOB_HIDE_WHEN_EMPTY|JOB_LATEJOIN_ONLY&~JOB_REOPEN_ON_ROUNDSTART_LOSS)
|
||||
|
||||
#define FACTION_NONE "None"
|
||||
#define FACTION_STATION "Station"
|
||||
|
||||
@@ -489,6 +489,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
|
||||
/// Is the mob standing on an elevated surface? This prevents them from dropping down if not elevated first.
|
||||
#define TRAIT_ON_ELEVATED_SURFACE "on_elevated_surface"
|
||||
|
||||
// Prevents you from twohanding weapons.
|
||||
#define TRAIT_NO_TWOHANDING "no_twohanding"
|
||||
|
||||
// METABOLISMS
|
||||
// Various jobs on the station have historically had better reactions
|
||||
// to various drinks and foodstuffs. Security liking donuts is a classic
|
||||
@@ -817,6 +820,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
|
||||
/// Similar trait given to temporary bodies inhabited by players
|
||||
#define TRAIT_TEMPORARY_BODY "temporary_body"
|
||||
|
||||
/// Trait given to objects with the wallmounted component
|
||||
#define TRAIT_WALLMOUNTED "wallmounted"
|
||||
|
||||
/// Trait given to mechs that can have orebox functionality on movement
|
||||
#define TRAIT_OREBOX_FUNCTIONAL "orebox_functional"
|
||||
|
||||
|
||||
@@ -98,6 +98,9 @@ GLOBAL_LIST_INIT(traits_by_type, list(
|
||||
/datum/wound = list(
|
||||
"TRAIT_WOUND_SCANNED" = TRAIT_WOUND_SCANNED,
|
||||
),
|
||||
/obj = list(
|
||||
"TRAIT_WALLMOUNTED" = TRAIT_WALLMOUNTED,
|
||||
),
|
||||
/mob = list(
|
||||
"TRAIT_ABDUCTOR_SCIENTIST_TRAINING" = TRAIT_ABDUCTOR_SCIENTIST_TRAINING,
|
||||
"TRAIT_ABDUCTOR_TRAINING" = TRAIT_ABDUCTOR_TRAINING,
|
||||
@@ -304,6 +307,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
|
||||
"TRAIT_NO_SOUL" = TRAIT_NO_SOUL,
|
||||
"TRAIT_NO_STRIP" = TRAIT_NO_STRIP,
|
||||
"TRAIT_NO_TRANSFORM" = TRAIT_NO_TRANSFORM,
|
||||
"TRAIT_NO_TWOHANDING" = TRAIT_NO_TWOHANDING,
|
||||
"TRAIT_NOCRITDAMAGE" = TRAIT_NOCRITDAMAGE,
|
||||
"TRAIT_NO_UNDERWEAR" = TRAIT_NO_UNDERWEAR,
|
||||
"TRAIT_NO_ZOMBIFY" = TRAIT_NO_ZOMBIFY,
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
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())
|
||||
if (!trait.can_display_lobby_button(mymob.client))
|
||||
continue
|
||||
var/atom/movable/screen/lobby/button/sign_up/sign_up_button = new(our_hud = src)
|
||||
sign_up_button.SlowInit()
|
||||
|
||||
@@ -931,6 +931,9 @@ SUBSYSTEM_DEF(dynamic)
|
||||
stack_trace("Invalid dynamic configuration variable [variable] in [ruleset.ruletype] [ruleset.name].")
|
||||
continue
|
||||
ruleset.vars[variable] = rule_conf[variable]
|
||||
ruleset.restricted_roles |= SSstation.antag_restricted_roles
|
||||
if(length(ruleset.protected_roles)) //if we care to protect any role, we should protect station trait roles too
|
||||
ruleset.protected_roles |= SSstation.antag_protected_roles
|
||||
if(CONFIG_GET(flag/protect_roles_from_antagonist))
|
||||
ruleset.restricted_roles |= ruleset.protected_roles
|
||||
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
|
||||
|
||||
@@ -11,6 +11,10 @@ PROCESSING_SUBSYSTEM_DEF(station)
|
||||
var/list/selectable_traits_by_types = list(STATION_TRAIT_POSITIVE = list(), STATION_TRAIT_NEUTRAL = list(), STATION_TRAIT_NEGATIVE = list())
|
||||
///Currently active announcer. Starts as a type but gets initialized after traits are selected
|
||||
var/datum/centcom_announcer/announcer = /datum/centcom_announcer/default
|
||||
///A list of trait roles that should be protected from antag
|
||||
var/list/antag_protected_roles = list()
|
||||
///A list of trait roles that should never be able to roll antag
|
||||
var/list/antag_restricted_roles = list()
|
||||
|
||||
/datum/controller/subsystem/processing/station/Initialize()
|
||||
|
||||
|
||||
@@ -173,17 +173,25 @@
|
||||
/datum/component/two_handed/proc/wield(mob/living/carbon/user)
|
||||
if(wielded)
|
||||
return
|
||||
var/atom/atom_parent = parent
|
||||
if(HAS_TRAIT(user, TRAIT_NO_TWOHANDING))
|
||||
if(require_twohands)
|
||||
atom_parent.balloon_alert(user, "too weak to wield!")
|
||||
user.dropItemToGround(parent, force = TRUE)
|
||||
else
|
||||
atom_parent.balloon_alert(user, "too weak to wield with both hands!")
|
||||
return
|
||||
if(user.get_inactive_held_item())
|
||||
if(require_twohands)
|
||||
to_chat(user, span_notice("[parent] is too cumbersome to carry in one hand!"))
|
||||
user.dropItemToGround(parent, force=TRUE)
|
||||
atom_parent.balloon_alert(user, "can't carry in one hand!")
|
||||
user.dropItemToGround(parent, force = TRUE)
|
||||
else
|
||||
to_chat(user, span_warning("You need your other hand to be empty!"))
|
||||
atom_parent.balloon_alert(user, "holding something in other hand!")
|
||||
return
|
||||
if(user.usable_hands < 2)
|
||||
if(require_twohands)
|
||||
user.dropItemToGround(parent, force=TRUE)
|
||||
to_chat(user, span_warning("You don't have enough intact hands."))
|
||||
atom_parent.balloon_alert(user, "not enough hands!")
|
||||
return
|
||||
|
||||
// wield update status
|
||||
|
||||
@@ -16,12 +16,14 @@
|
||||
on_drop = on_drop_callback
|
||||
|
||||
/datum/component/wall_mounted/RegisterWithParent()
|
||||
ADD_TRAIT(parent, TRAIT_WALLMOUNTED, REF(src))
|
||||
RegisterSignal(hanging_wall_turf, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
|
||||
RegisterSignal(hanging_wall_turf, COMSIG_TURF_CHANGE, PROC_REF(on_turf_changing))
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(drop_wallmount))
|
||||
RegisterSignal(parent, COMSIG_QDELETING, PROC_REF(on_linked_destroyed))
|
||||
|
||||
/datum/component/wall_mounted/UnregisterFromParent()
|
||||
REMOVE_TRAIT(parent, TRAIT_WALLMOUNTED, REF(src))
|
||||
UnregisterSignal(hanging_wall_turf, list(COMSIG_ATOM_EXAMINE, COMSIG_TURF_CHANGE))
|
||||
UnregisterSignal(parent, list(COMSIG_QDELETING, COMSIG_MOVABLE_MOVED))
|
||||
hanging_wall_turf = null
|
||||
|
||||
@@ -202,6 +202,28 @@
|
||||
)
|
||||
job = /datum/job/botanist
|
||||
|
||||
/datum/id_trim/job/bridge_assistant
|
||||
assignment = "Bridge Assistant"
|
||||
trim_state = "trim_assistant"
|
||||
department_color = COLOR_COMMAND_BLUE
|
||||
subdepartment_color = COLOR_COMMAND_BLUE
|
||||
sechud_icon_state = SECHUD_BRIDGE_ASSISTANT
|
||||
minimal_access = list(
|
||||
ACCESS_COMMAND,
|
||||
ACCESS_EVA,
|
||||
ACCESS_GATEWAY,
|
||||
ACCESS_MAINT_TUNNELS,
|
||||
ACCESS_RC_ANNOUNCE,
|
||||
ACCESS_TELEPORTER,
|
||||
ACCESS_WEAPONS,
|
||||
)
|
||||
extra_access = list()
|
||||
template_access = list(
|
||||
ACCESS_CAPTAIN,
|
||||
ACCESS_CHANGE_IDS,
|
||||
)
|
||||
job = /datum/job/bridge_assistant
|
||||
|
||||
/datum/id_trim/job/captain
|
||||
assignment = "Captain"
|
||||
intern_alt_name = "Captain-in-Training"
|
||||
|
||||
@@ -160,3 +160,36 @@ GLOBAL_DATUM_INIT(manifest, /datum/manifest, new)
|
||||
|
||||
target.rank = assignment
|
||||
target.trim = trim
|
||||
|
||||
/datum/manifest/ui_state(mob/user)
|
||||
return GLOB.always_state
|
||||
|
||||
/datum/manifest/ui_status(mob/user, datum/ui_state/state)
|
||||
return (isnewplayer(user) || isobserver(user) || isAI(user) || ispAI(user) || user.client?.holder) ? UI_INTERACTIVE : UI_CLOSE
|
||||
|
||||
/datum/manifest/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if (!ui)
|
||||
ui = new(user, src, "CrewManifest")
|
||||
ui.open()
|
||||
|
||||
/datum/manifest/ui_data(mob/user)
|
||||
var/list/positions = list()
|
||||
for(var/datum/job_department/department as anything in SSjob.joinable_departments)
|
||||
var/open = 0
|
||||
var/list/exceptions = list()
|
||||
for(var/datum/job/job as anything in department.department_jobs)
|
||||
if(job.total_positions == -1)
|
||||
exceptions += job.title
|
||||
continue
|
||||
var/open_slots = job.total_positions - job.current_positions
|
||||
if(open_slots < 1)
|
||||
continue
|
||||
open += open_slots
|
||||
positions[department.department_name] = list("exceptions" = exceptions, "open" = open)
|
||||
|
||||
return list(
|
||||
"manifest" = get_manifest(),
|
||||
"positions" = positions
|
||||
)
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ GLOBAL_LIST_EMPTY(lobby_station_traits)
|
||||
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()
|
||||
/datum/station_trait/proc/can_display_lobby_button(client/player)
|
||||
return sign_up_button && !SSticker.HasRoundStarted()
|
||||
|
||||
/// Apply any additional handling we need to our lobby button
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
#define CAN_ROLL_ALWAYS 1 //always can roll for antag
|
||||
#define CAN_ROLL_PROTECTED 2 //can roll if config lets protected roles roll
|
||||
#define CAN_ROLL_NEVER 3 //never roll antag
|
||||
|
||||
/**
|
||||
* A station trait which enables a temporary job
|
||||
* Generally speaking these should always all be mutually exclusive, don't have too many at once
|
||||
@@ -7,13 +11,22 @@
|
||||
abstract_type = /datum/station_trait/job
|
||||
/// What tooltip to show on the button
|
||||
var/button_desc = "Sign up to gain some kind of unusual job, not available in most rounds."
|
||||
/// Can this job roll antag?
|
||||
var/can_roll_antag = CAN_ROLL_ALWAYS
|
||||
/// How many positions to spawn?
|
||||
var/position_amount = 1
|
||||
/// Type of job to enable
|
||||
var/job_to_add = /datum/job/clown
|
||||
var/datum/job/job_to_add = /datum/job/clown
|
||||
/// Who signed up to this in the lobby
|
||||
var/list/lobby_candidates
|
||||
|
||||
/datum/station_trait/job/New()
|
||||
. = ..()
|
||||
switch(can_roll_antag)
|
||||
if(CAN_ROLL_PROTECTED)
|
||||
SSstation.antag_protected_roles += job_to_add::title
|
||||
if(CAN_ROLL_NEVER)
|
||||
SSstation.antag_restricted_roles += job_to_add::title
|
||||
blacklist += subtypesof(/datum/station_trait/job) - type // All but ourselves
|
||||
RegisterSignal(SSdcs, COMSIG_GLOB_PRE_JOBS_ASSIGNED, PROC_REF(pre_jobs_assigned))
|
||||
|
||||
@@ -50,16 +63,19 @@
|
||||
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()
|
||||
for(var/_ in 1 to position_amount)
|
||||
var/mob/dead/new_player/picked_player = pick_n_take(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++
|
||||
var/datum/job/our_job = SSjob.GetJob(job_to_add::title)
|
||||
our_job.total_positions = position_amount
|
||||
|
||||
/datum/station_trait/job/can_display_lobby_button(client/player)
|
||||
var/datum/job/our_job = SSjob.GetJob(job_to_add::title)
|
||||
return our_job.player_old_enough(player) && ..()
|
||||
|
||||
/// Adds a gorilla to the cargo department, replacing the sloth and the mech
|
||||
/datum/station_trait/job/cargorilla
|
||||
@@ -67,6 +83,7 @@
|
||||
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?
|
||||
can_roll_antag = CAN_ROLL_NEVER
|
||||
job_to_add = /datum/job/cargo_gorilla
|
||||
|
||||
/datum/station_trait/job/cargorilla/New()
|
||||
@@ -92,3 +109,61 @@
|
||||
// monkey carries the crates, the age of robot is over
|
||||
if(GLOB.cargo_ripley)
|
||||
qdel(GLOB.cargo_ripley)
|
||||
|
||||
/datum/station_trait/job/bridge_assistant
|
||||
name = "Bridge Assistant"
|
||||
button_desc = "Sign up to become the Bridge Assistant and watch over the Bridge."
|
||||
weight = 2
|
||||
report_message = "We have installed a Bridge Assistant on your station."
|
||||
show_in_report = TRUE
|
||||
can_roll_antag = CAN_ROLL_PROTECTED
|
||||
job_to_add = /datum/job/bridge_assistant
|
||||
|
||||
/datum/station_trait/job/bridge_assistant/New()
|
||||
. = ..()
|
||||
RegisterSignal(SSatoms, COMSIG_SUBSYSTEM_POST_INITIALIZE, PROC_REF(add_coffeemaker))
|
||||
|
||||
/datum/station_trait/job/bridge_assistant/on_lobby_button_update_overlays(atom/movable/screen/lobby/button/sign_up/lobby_button, list/overlays)
|
||||
. = ..()
|
||||
overlays += "bridge_assistant"
|
||||
|
||||
/// Creates a coffeemaker in the bridge, if we don't have one yet.
|
||||
/datum/station_trait/job/bridge_assistant/proc/add_coffeemaker(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
var/area/bridge = GLOB.areas_by_type[/area/station/command/bridge]
|
||||
if(isnull(bridge)) //no bridge, what will he assist?
|
||||
return
|
||||
var/list/possible_coffeemaker_positions = list(/area/station/command/bridge, /area/station/command/meeting_room)
|
||||
var/list/coffeemakers = SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/coffeemaker)
|
||||
for(var/obj/machinery/coffeemaker as anything in coffeemakers) //don't spawn a coffeemaker if there is already one on the bridge
|
||||
if(is_type_in_list(get_area(coffeemaker), possible_coffeemaker_positions))
|
||||
return
|
||||
var/list/tables = list()
|
||||
for(var/turf/area_turf as anything in bridge.get_contained_turfs())
|
||||
var/obj/structure/table/table = locate() in area_turf
|
||||
if(isnull(table))
|
||||
continue
|
||||
if(area_turf.is_blocked_turf(ignore_atoms = list(table))) //don't spawn a coffeemaker on a fax machine or smth
|
||||
continue
|
||||
tables += table
|
||||
if(!length(tables))
|
||||
return
|
||||
var/picked_table = pick_n_take(tables)
|
||||
var/picked_turf = get_turf(picked_table)
|
||||
if(length(tables))
|
||||
var/another_table = pick(tables)
|
||||
for(var/obj/thing_on_table in picked_turf) //if there's paper bins or other shit on the table, get that off
|
||||
if(thing_on_table == picked_table)
|
||||
continue
|
||||
if(HAS_TRAIT(thing_on_table, TRAIT_WALLMOUNTED) || (thing_on_table.flags_1 & ON_BORDER_1) || thing_on_table.layer < TABLE_LAYER)
|
||||
continue
|
||||
if(thing_on_table.invisibility || !thing_on_table.alpha || !thing_on_table.mouse_opacity)
|
||||
continue
|
||||
thing_on_table.forceMove(get_turf(another_table))
|
||||
new /obj/machinery/coffeemaker/impressa(picked_turf)
|
||||
new /obj/item/reagent_containers/cup/coffeepot(picked_turf)
|
||||
new /obj/item/storage/box/coffeepack(picked_turf)
|
||||
|
||||
#undef CAN_ROLL_ALWAYS
|
||||
#undef CAN_ROLL_PROTECTED
|
||||
#undef CAN_ROLL_NEVER
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "Bananium Shipment"
|
||||
trait_type = STATION_TRAIT_NEUTRAL
|
||||
weight = 5
|
||||
report_message = "Rumors has it that the clown planet has been sending support packages to clowns in this system"
|
||||
report_message = "Rumors has it that the clown planet has been sending support packages to clowns in this system."
|
||||
trait_to_give = STATION_TRAIT_BANANIUM_SHIPMENTS
|
||||
|
||||
/datum/station_trait/unnatural_atmosphere
|
||||
@@ -10,7 +10,7 @@
|
||||
trait_type = STATION_TRAIT_NEUTRAL
|
||||
weight = 5
|
||||
show_in_report = TRUE
|
||||
report_message = "System's local planet has irregular atmospherical properties"
|
||||
report_message = "System's local planet has irregular atmospherical properties."
|
||||
trait_to_give = STATION_TRAIT_UNNATURAL_ATMOSPHERE
|
||||
|
||||
// This station trait modifies the atmosphere, which is too far past the time admins are able to revert it
|
||||
@@ -197,7 +197,7 @@
|
||||
|
||||
|
||||
/datum/station_trait/birthday/proc/announce_birthday()
|
||||
report_message = "We here at Nanotrasen would all like to wish [birthday_person ? birthday_person_name : "Employee Name"] a very happy birthday"
|
||||
report_message = "We here at Nanotrasen would all like to wish [birthday_person ? birthday_person_name : "Employee Name"] a very happy birthday."
|
||||
priority_announce("Happy birthday to [birthday_person ? birthday_person_name : "Employee Name"]! Nanotrasen wishes you a very happy [birthday_person ? thtotext(birthday_person.age + 1) : "255th"] birthday.")
|
||||
if(birthday_person)
|
||||
playsound(birthday_person, 'sound/items/party_horn.ogg', 50)
|
||||
|
||||
@@ -190,6 +190,26 @@
|
||||
to_preload += /obj/item/extinguisher/mini
|
||||
return to_preload
|
||||
|
||||
/obj/item/storage/belt/utility/full/inducer/PopulateContents()
|
||||
SSwardrobe.provide_type(/obj/item/screwdriver, src)
|
||||
SSwardrobe.provide_type(/obj/item/wrench, src)
|
||||
SSwardrobe.provide_type(/obj/item/weldingtool, src)
|
||||
SSwardrobe.provide_type(/obj/item/crowbar/red, src)
|
||||
SSwardrobe.provide_type(/obj/item/wirecutters, src)
|
||||
SSwardrobe.provide_type(/obj/item/multitool, src)
|
||||
SSwardrobe.provide_type(/obj/item/inducer, src)
|
||||
|
||||
/obj/item/storage/belt/utility/full/inducer/get_types_to_preload()
|
||||
var/list/to_preload = list() //Yes this is a pain. Yes this is the point
|
||||
to_preload += /obj/item/screwdriver
|
||||
to_preload += /obj/item/wrench
|
||||
to_preload += /obj/item/weldingtool
|
||||
to_preload += /obj/item/crowbar
|
||||
to_preload += /obj/item/wirecutters
|
||||
to_preload += /obj/item/multitool
|
||||
to_preload += /obj/item/inducer
|
||||
return to_preload
|
||||
|
||||
/obj/item/storage/belt/utility/syndicate
|
||||
preload = FALSE
|
||||
|
||||
|
||||
@@ -51,12 +51,7 @@
|
||||
if(!SSticker.HasRoundStarted())
|
||||
tgui_alert(usr, "The game hasn't started yet!")
|
||||
return
|
||||
var/data = "<b>Showing Crew Manifest.</b><hr>"
|
||||
data += "<table cellspacing=5 border=1><tr><th>Name</th><th>Position</th></tr>"
|
||||
for(var/datum/record/crew/entry in GLOB.manifest.general)
|
||||
data += "<tr><td>[entry.name]</td><td>[entry.rank][entry.rank != entry.trim ? " ([entry.trim])" : ""]</td></tr>"
|
||||
data += "</table>"
|
||||
usr << browse(data, "window=manifest;size=440x410")
|
||||
GLOB.manifest.ui_interact(usr)
|
||||
|
||||
/datum/admins/proc/output_ai_laws()
|
||||
var/law_bound_entities = 0
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
/obj/item/food/cornchips/blue = 1,
|
||||
)
|
||||
rpg_title = "Recluse"
|
||||
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
|
||||
job_flags = STATION_JOB_FLAGS
|
||||
|
||||
/datum/outfit/job/bitrunner
|
||||
name = "Bitrunner"
|
||||
|
||||
@@ -288,3 +288,10 @@
|
||||
uniform = /obj/item/clothing/under/plasmaman/bitrunner
|
||||
gloves = /obj/item/clothing/gloves/color/plasmaman/black
|
||||
head = /obj/item/clothing/head/helmet/space/plasmaman/bitrunner
|
||||
|
||||
/datum/outfit/plasmaman/bridge_assistant
|
||||
name = "Bridge Assistant Plasmaman"
|
||||
|
||||
uniform = /obj/item/clothing/under/plasmaman //call me when this is gags and not 10 million new assets
|
||||
gloves = /obj/item/clothing/gloves/color/plasmaman/black
|
||||
head = /obj/item/clothing/head/helmet/space/plasmaman
|
||||
|
||||
@@ -45,14 +45,16 @@ Assistant
|
||||
|
||||
/datum/outfit/job/assistant/pre_equip(mob/living/carbon/human/target)
|
||||
..()
|
||||
give_hat()
|
||||
give_jumpsuit(target)
|
||||
|
||||
/datum/outfit/job/assistant/proc/give_hat()
|
||||
for(var/holidayname in GLOB.holidays)
|
||||
var/datum/holiday/holiday_today = GLOB.holidays[holidayname]
|
||||
var/obj/item/special_hat = holiday_today.holiday_hat
|
||||
if(prob(HOLIDAY_HAT_CHANCE) && !isnull(special_hat) && isnull(head))
|
||||
head = special_hat
|
||||
|
||||
give_jumpsuit(target)
|
||||
|
||||
/datum/outfit/job/assistant/proc/give_jumpsuit(mob/living/carbon/human/target)
|
||||
var/static/jumpsuit_number = 0
|
||||
jumpsuit_number += 1
|
||||
@@ -73,6 +75,9 @@ Assistant
|
||||
/datum/outfit/job/assistant/consistent
|
||||
name = "Assistant - Consistent"
|
||||
|
||||
/datum/outfit/job/assistant/consistent/give_hat()
|
||||
return
|
||||
|
||||
/datum/outfit/job/assistant/consistent/give_jumpsuit(mob/living/carbon/human/target)
|
||||
uniform = /obj/item/clothing/under/color/grey
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
family_heirlooms = list(/obj/item/pen/blue)
|
||||
rpg_title = "Defeated Miniboss"
|
||||
job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE | JOB_ASSIGN_QUIRKS | JOB_CAN_BE_INTERN | JOB_CANNOT_OPEN_SLOTS
|
||||
job_flags = STATION_JOB_FLAGS | JOB_CANNOT_OPEN_SLOTS & ~JOB_REOPEN_ON_ROUNDSTART_LOSS
|
||||
|
||||
/datum/job/prisoner/New()
|
||||
. = ..()
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/datum/job/bridge_assistant
|
||||
title = JOB_BRIDGE_ASSISTANT
|
||||
description = "Watch over the Bridge, command its consoles, and spend your days brewing coffee for higher-ups."
|
||||
auto_deadmin_role_flags = DEADMIN_POSITION_HEAD //not really a head but close enough
|
||||
department_head = list(JOB_CAPTAIN)
|
||||
faction = FACTION_STATION
|
||||
total_positions = 0
|
||||
spawn_positions = 0
|
||||
supervisors = "the Captain, and in non-Bridge related situations the other heads"
|
||||
minimal_player_age = 7
|
||||
exp_requirements = 300
|
||||
exp_required_type = EXP_TYPE_CREW
|
||||
exp_granted_type = EXP_TYPE_CREW
|
||||
config_tag = "BRIDGE_ASSISTANT"
|
||||
|
||||
outfit = /datum/outfit/job/bridge_assistant
|
||||
plasmaman_outfit = /datum/outfit/plasmaman/bridge_assistant
|
||||
|
||||
paycheck = PAYCHECK_CREW
|
||||
paycheck_department = ACCOUNT_CIV
|
||||
|
||||
liver_traits = list(TRAIT_PRETENDER_ROYAL_METABOLISM)
|
||||
|
||||
display_order = JOB_DISPLAY_ORDER_BRIDGE_ASSISTANT
|
||||
departments_list = list(/datum/job_department/command)
|
||||
|
||||
family_heirlooms = list(/obj/item/banner/command/mundane)
|
||||
|
||||
mail_goodies = list(
|
||||
/obj/item/storage/fancy/cigarettes = 1,
|
||||
/obj/item/pen/fountain = 1,
|
||||
)
|
||||
rpg_title = "Royal Guard"
|
||||
allow_bureaucratic_error = FALSE
|
||||
job_flags = STATION_JOB_FLAGS | STATION_TRAIT_JOB_FLAGS
|
||||
ignore_human_authority = TRUE
|
||||
|
||||
/datum/job/bridge_assistant/after_spawn(mob/living/spawned, client/player_client)
|
||||
. = ..()
|
||||
ADD_TRAIT(spawned, TRAIT_NO_TWOHANDING, JOB_TRAIT)
|
||||
|
||||
/datum/job/bridge_assistant/get_roundstart_spawn_point()
|
||||
var/list/chair_turfs = list()
|
||||
var/list/possible_turfs = list()
|
||||
var/area/bridge = GLOB.areas_by_type[/area/station/command/bridge]
|
||||
if(isnull(bridge))
|
||||
return ..() //if no bridge, spawn on the arrivals shuttle (but also what the fuck)
|
||||
for(var/turf/possible_turf as anything in bridge.get_contained_turfs())
|
||||
if(possible_turf.is_blocked_turf())
|
||||
continue
|
||||
if(locate(/obj/structure/chair) in possible_turf)
|
||||
chair_turfs += possible_turf
|
||||
continue
|
||||
possible_turfs += possible_turf
|
||||
if(length(chair_turfs))
|
||||
return pick(chair_turfs) //prioritize turfs with a chair
|
||||
if(length(possible_turfs))
|
||||
return pick(possible_turfs) //if none, just pick a random turf in the bridge
|
||||
return ..() //if the bridge has no turfs, spawn on the arrivals shuttle
|
||||
|
||||
/datum/outfit/job/bridge_assistant
|
||||
name = "Bridge Assistant"
|
||||
jobtype = /datum/job/bridge_assistant
|
||||
|
||||
id_trim = /datum/id_trim/job/bridge_assistant
|
||||
backpack_contents = list(
|
||||
/obj/item/modular_computer/pda/bridge_assistant = 1,
|
||||
)
|
||||
|
||||
uniform = /obj/item/clothing/under/trek/command/next
|
||||
neck = /obj/item/clothing/neck/large_scarf/blue
|
||||
belt = /obj/item/storage/belt/utility/full/inducer
|
||||
ears = /obj/item/radio/headset/headset_com
|
||||
glasses = /obj/item/clothing/glasses/sunglasses
|
||||
gloves = /obj/item/clothing/gloves/fingerless
|
||||
head = /obj/item/clothing/head/soft/black
|
||||
shoes = /obj/item/clothing/shoes/laceup
|
||||
l_pocket = /obj/item/gun/energy/e_gun/mini
|
||||
r_pocket = /obj/item/assembly/flash/handheld
|
||||
+1
-1
@@ -16,7 +16,7 @@
|
||||
)
|
||||
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
|
||||
job_flags = STATION_TRAIT_JOB_FLAGS | JOB_ANNOUNCE_ARRIVAL | JOB_NEW_PLAYER_JOINABLE | JOB_EQUIP_RANK
|
||||
|
||||
/datum/job/cargo_gorilla/get_roundstart_spawn_point()
|
||||
if (length(GLOB.gorilla_start))
|
||||
@@ -1,38 +0,0 @@
|
||||
/datum/crew_manifest
|
||||
|
||||
/datum/crew_manifest/ui_state(mob/user)
|
||||
return GLOB.always_state
|
||||
|
||||
/datum/crew_manifest/ui_status(mob/user, datum/ui_state/state)
|
||||
return (isnewplayer(user) || isobserver(user) || isAI(user) || ispAI(user)) ? UI_INTERACTIVE : UI_CLOSE
|
||||
|
||||
/datum/crew_manifest/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if (!ui)
|
||||
ui = new(user, src, "CrewManifest")
|
||||
ui.open()
|
||||
|
||||
/datum/crew_manifest/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
/datum/crew_manifest/ui_data(mob/user)
|
||||
var/list/positions = list()
|
||||
for(var/datum/job_department/department as anything in SSjob.joinable_departments)
|
||||
var/open = 0
|
||||
var/list/exceptions = list()
|
||||
for(var/datum/job/job as anything in department.department_jobs)
|
||||
if(job.total_positions == -1)
|
||||
exceptions += job.title
|
||||
continue
|
||||
var/open_slots = job.total_positions - job.current_positions
|
||||
if(open_slots < 1)
|
||||
continue
|
||||
open += open_slots
|
||||
positions[department.department_name] = list("exceptions" = exceptions, "open" = open)
|
||||
|
||||
return list(
|
||||
"manifest" = GLOB.manifest.get_manifest(),
|
||||
"positions" = positions
|
||||
)
|
||||
@@ -296,10 +296,7 @@
|
||||
return
|
||||
client.crew_manifest_delay = world.time + (1 SECONDS)
|
||||
|
||||
if(!GLOB.crew_manifest_tgui)
|
||||
GLOB.crew_manifest_tgui = new /datum/crew_manifest(src)
|
||||
|
||||
GLOB.crew_manifest_tgui.ui_interact(src)
|
||||
GLOB.manifest.ui_interact(src)
|
||||
|
||||
/mob/dead/new_player/Move()
|
||||
return 0
|
||||
|
||||
@@ -711,10 +711,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
return
|
||||
client.crew_manifest_delay = world.time + (1 SECONDS)
|
||||
|
||||
if(!GLOB.crew_manifest_tgui)
|
||||
GLOB.crew_manifest_tgui = new /datum/crew_manifest(src)
|
||||
|
||||
GLOB.crew_manifest_tgui.ui_interact(src)
|
||||
GLOB.manifest.ui_interact(src)
|
||||
|
||||
//this is called when a ghost is drag clicked to something.
|
||||
/mob/dead/observer/MouseDrop(atom/over)
|
||||
|
||||
@@ -349,10 +349,7 @@
|
||||
return
|
||||
client.crew_manifest_delay = world.time + (1 SECONDS)
|
||||
|
||||
if(!GLOB.crew_manifest_tgui)
|
||||
GLOB.crew_manifest_tgui = new /datum/crew_manifest(src)
|
||||
|
||||
GLOB.crew_manifest_tgui.ui_interact(src)
|
||||
GLOB.manifest.ui_interact(src)
|
||||
|
||||
/mob/living/silicon/proc/set_autosay() //For allowing the AI and borgs to set the radio behavior of auto announcements (state laws, arrivals).
|
||||
if(!radio)
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
|
||||
/obj/item/modular_computer/pda/heads/quartermaster
|
||||
name = "quartermaster PDA"
|
||||
greyscale_config = /datum/greyscale_config/tablet/stripe_thick
|
||||
greyscale_config = /datum/greyscale_config/tablet/stripe_thick/head
|
||||
greyscale_colors = "#c4b787#18191e#8b4c31"
|
||||
inserted_item = /obj/item/pen/survival
|
||||
stored_paper = 20
|
||||
@@ -412,7 +412,7 @@
|
||||
)
|
||||
|
||||
/**
|
||||
* No Department
|
||||
* No Department/Station Trait
|
||||
*/
|
||||
|
||||
/obj/item/modular_computer/pda/assistant
|
||||
@@ -421,6 +421,14 @@
|
||||
/datum/computer_file/program/bounty_board,
|
||||
)
|
||||
|
||||
/obj/item/modular_computer/pda/bridge_assistant
|
||||
name = "bridge assistant PDA"
|
||||
greyscale_colors = "#374f7e#a92323"
|
||||
starting_programs = list(
|
||||
/datum/computer_file/program/crew_manifest,
|
||||
/datum/computer_file/program/status,
|
||||
)
|
||||
|
||||
/**
|
||||
* Non-roles
|
||||
*/
|
||||
|
||||
@@ -6,5 +6,7 @@
|
||||
for(var/datum/job/job as anything in subtypesof(/datum/job))
|
||||
if(!(initial(job.job_flags) & JOB_CREW_MEMBER))
|
||||
continue
|
||||
if((initial(job.job_flags) & STATION_TRAIT_JOB_FLAGS) == STATION_TRAIT_JOB_FLAGS)
|
||||
continue
|
||||
if(!(job in cyber_trait.job_to_cybernetic))
|
||||
TEST_FAIL("Job [job] does not have an assigned cybernetic for [cyber_trait.type] station trait.")
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 676 B After Width: | Height: | Size: 668 B |
Binary file not shown.
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
+2
-2
@@ -4116,7 +4116,6 @@
|
||||
#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"
|
||||
@@ -4201,6 +4200,8 @@
|
||||
#include "code\modules\jobs\job_types\spawner\syndicate_cybersun_captain.dm"
|
||||
#include "code\modules\jobs\job_types\spawner\venus_human_trap.dm"
|
||||
#include "code\modules\jobs\job_types\spawner\zombie.dm"
|
||||
#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\keybindings\bindings_atom.dm"
|
||||
#include "code\modules\keybindings\bindings_client.dm"
|
||||
#include "code\modules\keybindings\focus.dm"
|
||||
@@ -4425,7 +4426,6 @@
|
||||
#include "code\modules\mob\status_procs.dm"
|
||||
#include "code\modules\mob\transform_procs.dm"
|
||||
#include "code\modules\mob\camera\camera.dm"
|
||||
#include "code\modules\mob\dead\crew_manifest.dm"
|
||||
#include "code\modules\mob\dead\dead.dm"
|
||||
#include "code\modules\mob\dead\new_player\latejoin_menu.dm"
|
||||
#include "code\modules\mob\dead\new_player\login.dm"
|
||||
|
||||
@@ -9,6 +9,7 @@ export const JOB2ICON = {
|
||||
'Bit Avatar': 'code',
|
||||
Bitrunner: 'gamepad',
|
||||
Botanist: 'seedling',
|
||||
'Bridge Assistant': 'building-shield',
|
||||
Captain: 'crown',
|
||||
'Cargo Gorilla': 'paw',
|
||||
'Cargo Technician': 'box',
|
||||
|
||||
Reference in New Issue
Block a user