Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bridge Assistant Station Trait #80279

Merged
merged 25 commits into from Dec 17, 2023
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions code/__DEFINES/atom_hud.dm
Expand Up @@ -80,6 +80,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"
Expand Down
74 changes: 39 additions & 35 deletions code/__DEFINES/jobs.dm
Expand Up @@ -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"
Expand Down Expand Up @@ -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"

Expand Down Expand Up @@ -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"
Expand Down
3 changes: 3 additions & 0 deletions code/__DEFINES/traits/declarations.dm
Expand Up @@ -487,6 +487,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
Expand Down
1 change: 1 addition & 0 deletions code/_globalvars/traits/_traits.dm
Expand Up @@ -303,6 +303,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,
Expand Down
2 changes: 1 addition & 1 deletion code/_onclick/hud/new_player.dm
Expand Up @@ -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()
Expand Down
3 changes: 3 additions & 0 deletions code/controllers/subsystem/dynamic/dynamic.dm
Expand Up @@ -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))
Expand Down
4 changes: 4 additions & 0 deletions code/controllers/subsystem/processing/station.dm
Expand Up @@ -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()

Expand Down
7 changes: 7 additions & 0 deletions code/datums/components/twohanded.dm
Expand Up @@ -173,6 +173,13 @@
/datum/component/two_handed/proc/wield(mob/living/carbon/user)
if(wielded)
return
if(HAS_TRAIT(user, TRAIT_NO_TWOHANDING))
if(require_twohands)
to_chat(user, span_warning("You feel too weak to wield this!"))
Fikou marked this conversation as resolved.
Show resolved Hide resolved
user.dropItemToGround(parent, force=TRUE)
else
to_chat(user, span_warning("You feel too weak to wield this with both hands!"))
Fikou marked this conversation as resolved.
Show resolved Hide resolved
return
if(user.get_inactive_held_item())
if(require_twohands)
to_chat(user, span_notice("[parent] is too cumbersome to carry in one hand!"))
Expand Down
22 changes: 22 additions & 0 deletions code/datums/id_trim/jobs.dm
Expand Up @@ -202,6 +202,28 @@
)
job = /datum/job/botanist

/datum/id_trim/job/bridge_assistant
assignment = "Bridge Assistant"
trim_state = "trim_bridgeassistant"
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"
Expand Down
33 changes: 33 additions & 0 deletions code/datums/records/manifest.dm
Expand Up @@ -160,3 +160,36 @@ GLOBAL_DATUM_INIT(manifest, /datum/manifest, new)

target.rank = assignment
target.trim = trim

/datum/manifest/ui_state(mob/user)
Fikou marked this conversation as resolved.
Show resolved Hide resolved
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
)

2 changes: 1 addition & 1 deletion code/datums/station_traits/_station_trait.dm
Expand Up @@ -81,7 +81,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
Expand Down
84 changes: 78 additions & 6 deletions code/datums/station_traits/job_traits.dm
@@ -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
Expand All @@ -7,13 +11,22 @@
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."
/// 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
Comment on lines +27 to +29
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we're sure this works? i thought :: was always calculated at compile time. this feels like it's going to give you the initial of /datum/job::title, not of whatever the job is. Double check this.

Copy link
Member Author

@Fikou Fikou Dec 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its essentially just a wrapper for initial(job_to_add.title)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to decide which one of these we want

blacklist += subtypesof(/datum/station_trait/job) - type // All but ourselves
RegisterSignal(SSdcs, COMSIG_GLOB_PRE_JOBS_ASSIGNED, PROC_REF(pre_jobs_assigned))

Expand Down Expand Up @@ -50,23 +63,27 @@
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)
Fikou marked this conversation as resolved.
Show resolved Hide resolved
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
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?
can_roll_antag = CAN_ROLL_NEVER
job_to_add = /datum/job/cargo_gorilla
trait_flags = STATION_TRAIT_MAP_UNRESTRICTED

Expand All @@ -93,3 +110,58 @@
// 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)
Comment on lines +130 to +131
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think this is silly, this is what downstreams do because they don't have the luxury of being able to edit maps, we really can just map in coffee machines

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i dont want to add the expectation for mappers to deal with this shit

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There doesn't need to be an expectation, a mapper can include a coffee machine if they think one fits the bridge and can not if they do not

If anything, a bridge without a coffee machine is just more job content for the bridge assistant, because now the captain can order them to hunt down a coffee machine

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fyi coffee machines require water recyclers which require plastic to be made and also require to be made in an autolathe (no protolathe prints them)

somewhat tangibly related. im just ranting about how annoying it is to make coffee machines- and most maps don't have them? i think?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no they dont

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

meta has a coffee machine next to cargo in the cafe, no?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NOT ON THE BRIDGE

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fwiw i think its fine in principle. let mappers choose a place manually, but automatic otherwise. also makes it easier to migrate existing "unused, but frequently run" maps like kilo/pubby

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer a landmark system.
Is there's a "coffee maker spawn point" use that.
Findt an open table otherwise

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i still disagree with it in practice but since it's a rare station trait it's like... whatever. i wouldn't want to see it expanded

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(tables)
tables -= picked_table
Fikou marked this conversation as resolved.
Show resolved Hide resolved
var/picked_turf = get_turf(picked_table)
if(length(tables))
var/another_table = pick(tables)
for(var/obj/item/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
thing_on_table.forceMove(get_turf(another_table))
Fikou marked this conversation as resolved.
Show resolved Hide resolved
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
6 changes: 3 additions & 3 deletions code/datums/station_traits/neutral_traits.dm
Expand Up @@ -2,15 +2,15 @@
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
name = "Unnatural atmospherical properties"
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
Expand Down Expand Up @@ -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)
Expand Down