Merge branch 'master' into dullahan-2-electric-boogaloo

This commit is contained in:
timothyteakettle
2022-08-11 14:43:48 +01:00
138 changed files with 2006 additions and 306 deletions

View File

@@ -13,7 +13,7 @@
"source.fixAll.eslint": true
},
"workbench.editorAssociations": {
"*.dmi": "imagePreview.previewEditor"
"*.dmi": "dmiEditor.dmiEditor"
},
"files.eol": "\n",
"gitlens.advanced.blame.customArguments": ["-w"],

View File

@@ -21,6 +21,12 @@
#define COMSIG_GLOB_PLAY_CINEMATIC "!play_cinematic"
#define COMPONENT_GLOB_BLOCK_CINEMATIC 1
/// job subsystem has spawned and equipped a new mob
#define COMSIG_GLOB_JOB_AFTER_SPAWN "!job_after_spawn"
/// job datum has been called to deal with the aftermath of a latejoin spawn
#define COMSIG_GLOB_JOB_AFTER_LATEJOIN_SPAWN "!job_after_latejoin_spawn"
#define COMSIG_GLOB_PRE_RANDOM_EVENT "!pre_random_event"
/// Do not allow this random event to continue.
#define CANCEL_PRE_RANDOM_EVENT (1<<0)
@@ -670,3 +676,6 @@
// /datum/component/identification signals
#define COMSIG_IDENTIFICATION_KNOWLEDGE_CHECK "id_knowledge_check" // (mob/user) - returns a value from ID_COMPONENT_KNOWLEDGE_NONE to ID_COMPONENT_KNOWLEDGE_FULL
///from base of [/datum/component/multiple_lives/proc/respawn]: (mob/respawned_mob, gibbed, lives_left)
#define COMSIG_ON_MULTIPLE_LIVES_RESPAWN "on_multiple_lives_respawn"

View File

@@ -151,3 +151,43 @@
#define SOUND_AREA_LAVALAND SOUND_ENVIRONMENT_MOUNTAINS
#define SOUND_AREA_ICEMOON SOUND_ENVIRONMENT_CAVE
#define SOUND_AREA_WOODFLOOR SOUND_ENVIRONMENT_CITY
///Announcer audio keys
#define ANNOUNCER_AIMALF "aimalf"
#define ANNOUNCER_ALIENS "aliens"
#define ANNOUNCER_ANIMES "animes"
#define ANNOUNCER_GRANOMALIES "granomalies"
#define ANNOUNCER_INTERCEPT "intercept"
#define ANNOUNCER_IONSTORM "ionstorm"
#define ANNOUNCER_METEORS "meteors"
#define ANNOUNCER_NEWAI "newAI"
#define ANNOUNCER_OUTBREAK5 "outbreak5"
#define ANNOUNCER_OUTBREAK7 "outbreak7"
#define ANNOUNCER_POWEROFF "poweroff"
#define ANNOUNCER_POWERON "poweron"
#define ANNOUNCER_RADIATION "radiation"
#define ANNOUNCER_SHUTTLECALLED "shuttlecalled"
#define ANNOUNCER_SHUTTLEDOCK "shuttledock"
#define ANNOUNCER_SHUTTLERECALLED "shuttlerecalled"
#define ANNOUNCER_SPANOMALIES "spanomalies"
/// Global list of all of our announcer keys.
GLOBAL_LIST_INIT(announcer_keys, list(
ANNOUNCER_AIMALF,
ANNOUNCER_ALIENS,
ANNOUNCER_ANIMES,
ANNOUNCER_GRANOMALIES,
ANNOUNCER_INTERCEPT,
ANNOUNCER_IONSTORM,
ANNOUNCER_METEORS,
ANNOUNCER_NEWAI,
ANNOUNCER_OUTBREAK5,
ANNOUNCER_OUTBREAK7,
ANNOUNCER_POWEROFF,
ANNOUNCER_POWERON,
ANNOUNCER_RADIATION,
ANNOUNCER_SHUTTLECALLED,
ANNOUNCER_SHUTTLEDOCK,
ANNOUNCER_SHUTTLERECALLED,
ANNOUNCER_SPANOMALIES,
))

View File

@@ -0,0 +1,9 @@
#define STATION_TRAIT_POSITIVE 1
#define STATION_TRAIT_NEUTRAL 2
#define STATION_TRAIT_NEGATIVE 3
#define STATION_TRAIT_ABSTRACT (1<<0)
/// The data file that future station traits are stored in
#define FUTURE_STATION_TRAITS_FILE "data/future_station_traits.json"

View File

@@ -113,6 +113,7 @@
#define INIT_ORDER_VIS 80
#define INIT_ORDER_ACHIEVEMENTS 77
#define INIT_ORDER_RESEARCH 75
#define INIT_ORDER_STATION 74 //This is high priority because it manipulates a lot of the subsystems that will initialize after it.
#define INIT_ORDER_EVENTS 70
#define INIT_ORDER_JOBS 65
#define INIT_ORDER_QUIRKS 60

View File

@@ -302,6 +302,7 @@
#define GLOVE_TRAIT "glove" //inherited by your cool gloves
#define BOOK_TRAIT "granter (book)" // knowledge is power
#define TURF_TRAIT "turf"
#define STATION_TRAIT "station-trait"
// unique trait sources, still defines
#define STATUE_TRAIT "statue"
@@ -365,3 +366,16 @@
#define MAPPING_HELPER_TRAIT "mapping-helper"
/// Trait associated with mafia
#define MAFIA_TRAIT "mafia"
///Traits given by station traits
#define STATION_TRAIT_BANANIUM_SHIPMENTS "station_trait_bananium_shipments"
#define STATION_TRAIT_UNNATURAL_ATMOSPHERE "station_trait_unnatural_atmosphere"
#define STATION_TRAIT_UNIQUE_AI "station_trait_unique_ai"
#define STATION_TRAIT_CARP_INFESTATION "station_trait_carp_infestation"
#define STATION_TRAIT_PREMIUM_INTERNALS "station_trait_premium_internals"
#define STATION_TRAIT_LATE_ARRIVALS "station_trait_late_arrivals"
#define STATION_TRAIT_RANDOM_ARRIVALS "station_trait_random_arrivals"
#define STATION_TRAIT_HANGOVER "station_trait_hangover"
#define STATION_TRAIT_FILLED_MAINT "station_trait_filled_maint"
#define STATION_TRAIT_EMPTY_MAINT "station_trait_empty_maint"
#define STATION_TRAIT_PDA_GLITCHED "station_trait_pda_glitched"

View File

@@ -5,6 +5,9 @@
locate(min(CENTER.x+(RADIUS),world.maxx), min(CENTER.y+(RADIUS),world.maxy), CENTER.z) \
)
/// Returns either the error landmark or the location of the room. Needless to say, if this is used, it means things have gone awry.
#define GET_ERROR_ROOM ((locate(/obj/effect/landmark/error) in GLOB.landmarks_list) || locate(4,4,1))
#define Z_TURFS(ZLEVEL) block(locate(1,1,ZLEVEL), locate(world.maxx, world.maxy, ZLEVEL))
#define CULT_POLL_WAIT 2400

View File

@@ -4,7 +4,9 @@
var/announcement
if(!sound)
sound = "attention"
sound = SSstation.announcer.get_rand_alert_sound()
else if(SSstation.announcer.event_sounds[sound])
sound = SSstation.announcer.event_sounds[sound]
if(type == "Priority")
announcement += "<h1 class='alert'>Priority Announcement</h1>"
@@ -29,110 +31,19 @@
GLOB.news_network.SubmitArticle(title + "<br><br>" + text, "Central Command", "Station Announcements", null)
///If the announcer overrides alert messages, use that message.
// if(SSstation.announcer.custom_alert_message && !has_important_message)
// announcement += SSstation.announcer.custom_alert_message
// else
announcement += "<br>[span_alert("[html_encode(text)]")]<br>"
if(SSstation.announcer.custom_alert_message && !has_important_message)
announcement += SSstation.announcer.custom_alert_message
else
announcement += "<br>[span_alert("[html_encode(text)]")]<br>"
announcement += "<br>"
var/s = sound(get_announcer_sound(sound))
var/s = sound(sound)
for(var/mob/M in GLOB.player_list)
if(!isnewplayer(M) && M.can_hear())
to_chat(M, announcement)
if(M.client.prefs.toggles & SOUND_ANNOUNCEMENTS)
SEND_SOUND(M, s)
/proc/get_announcer_sound(soundid)
if(isfile(soundid))
return soundid
else if(!istext(soundid))
CRASH("Invalid type passed to get_announcer_sound()")
switch(GLOB.announcertype) //These are all individually hardcoded to allow the announcer sounds to be included in the rsc, reducing lag from sending resources midgame.
if("classic")
switch(soundid)
if("aimalf")
. = 'sound/announcer/classic/aimalf.ogg'
if("aliens")
. = 'sound/announcer/classic/aliens.ogg'
if("animes")
. = 'sound/announcer/classic/animes.ogg'
if("attention")
. = 'sound/announcer/classic/attention.ogg'
if("commandreport")
. = 'sound/announcer/classic/commandreport.ogg'
if("granomalies")
. = 'sound/announcer/classic/granomalies.ogg'
if("intercept")
. = 'sound/announcer/classic/intercept.ogg'
if("ionstorm")
. = 'sound/announcer/classic/ionstorm.ogg'
if("meteors")
. = 'sound/announcer/classic/meteors.ogg'
if("newAI")
. = 'sound/announcer/classic/newAI.ogg'
if("outbreak5")
. = 'sound/announcer/classic/outbreak5.ogg'
if("outbreak7")
. = 'sound/announcer/classic/outbreak7.ogg'
if("poweroff")
. = 'sound/announcer/classic/poweroff.ogg'
if("poweron")
. = 'sound/announcer/classic/poweron.ogg'
if("radiation")
. = 'sound/announcer/classic/radiation.ogg'
if("shuttlecalled")
. = 'sound/announcer/classic/shuttlecalled.ogg'
if("shuttledock")
. = 'sound/announcer/classic/shuttledock.ogg'
if("shuttlerecalled")
. = 'sound/announcer/classic/shuttlerecalled.ogg'
if("spanomalies")
. = 'sound/announcer/classic/spanomalies.ogg'
if("welcome")
. = 'sound/announcer/classic/welcome.ogg'
if("medibot")
switch(soundid)
if("aimalf")
. = 'sound/announcer/classic/aimalf.ogg'
if("aliens")
. = 'sound/announcer/medibot/aliens.ogg'
if("animes")
. = 'sound/announcer/medibot/animes.ogg'
if("attention")
. = 'sound/announcer/medibot/attention.ogg'
if("commandreport")
. = 'sound/announcer/medibot/commandreport.ogg'
if("granomalies")
. = 'sound/announcer/medibot/granomalies.ogg'
if("intercept")
. = 'sound/announcer/medibot/intercept.ogg'
if("ionstorm")
. = 'sound/announcer/medibot/ionstorm.ogg'
if("meteors")
. = 'sound/announcer/medibot/meteors.ogg'
if("newAI")
. = 'sound/announcer/medibot/newAI.ogg'
if("outbreak5")
. = 'sound/announcer/medibot/outbreak5.ogg'
if("outbreak7")
. = 'sound/announcer/medibot/outbreak7.ogg'
if("poweroff")
. = 'sound/announcer/medibot/poweroff.ogg'
if("poweron")
. = 'sound/announcer/medibot/poweron.ogg'
if("radiation")
. = 'sound/announcer/medibot/radiation.ogg'
if("shuttlecalled")
. = 'sound/announcer/medibot/shuttlecalled.ogg'
if("shuttledock")
. = 'sound/announcer/medibot/shuttledocked.ogg'
if("shuttlerecalled")
. = 'sound/announcer/medibot/shuttlerecalled.ogg'
if("spanomalies")
. = 'sound/announcer/medibot/spanomalies.ogg'
if("welcome")
. = 'sound/announcer/medibot/welcome.ogg'
/**
* Summon the crew for an emergency meeting
*
@@ -170,7 +81,7 @@
title = "Classified [command_name()] Update"
if(announce)
priority_announce("A report has been downloaded and printed out at all communications consoles.", "Incoming Classified Message", "commandreport", has_important_message = TRUE)
priority_announce("A report has been downloaded and printed out at all communications consoles.", "Incoming Classified Message", SSstation.announcer.get_rand_report_sound(), has_important_message = TRUE)
var/datum/comm_message/M = new
M.title = title

View File

@@ -37,6 +37,7 @@ GLOBAL_LIST_EMPTY(emergencyresponseteamspawn)
GLOBAL_LIST_EMPTY(servant_spawns) //Servants of Ratvar spawn here
GLOBAL_LIST_EMPTY(city_of_cogs_spawns) //Anyone entering the City of Cogs spawns here
GLOBAL_LIST_EMPTY(ruin_landmarks)
GLOBAL_LIST_EMPTY(bar_areas)
//away missions
GLOBAL_LIST_EMPTY(vr_spawnpoints)

View File

@@ -6,8 +6,6 @@ GLOBAL_VAR_INIT(year, time2text(world.realtime,"YYYY"))
GLOBAL_VAR_INIT(year_integer, text2num(year)) // = 2013???
GLOBAL_VAR_INIT(announcertype, "standard")
// For FTP requests. (i.e. downloading runtime logs.)
// However it'd be ok to use for accessing attack logs and such too, which are even laggier.
GLOBAL_VAR_INIT(fileaccess_timer, 0)

View File

@@ -246,7 +246,7 @@
//used to initialize the subsystem AFTER the map has loaded
/datum/controller/subsystem/Initialize(start_timeofday)
initialized = TRUE
// SEND_SIGNAL(src, COMSIG_SUBSYSTEM_POST_INITIALIZE, start_timeofday)
SEND_SIGNAL(src, COMSIG_SUBSYSTEM_POST_INITIALIZE, start_timeofday)
var/time = (REALTIMEOFDAY - start_timeofday) / 10
var/msg = "Initialized [name] subsystem within [time] second[time == 1 ? "" : "s"]!"
to_chat(world, span_boldannounce("[msg]"))

View File

@@ -47,6 +47,10 @@ SUBSYSTEM_DEF(economy)
"rainbow" = 1000)
var/list/bank_accounts = list() //List of normal accounts (not department accounts)
var/list/dep_cards = list()
///The modifier multiplied to the value of bounties paid out.
var/bounty_modifier = 1
///The modifier multiplied to the value of cargo pack prices.
var/pack_price_modifier = 1
/datum/controller/subsystem/economy/Initialize(timeofday)
var/budget_to_hand_out = round(budget_pool / department_accounts.len)

View File

@@ -434,20 +434,7 @@ SUBSYSTEM_DEF(job)
//If we joined at roundstart we should be positioned at our workstation
if(!joined_late)
var/obj/S = null
for(var/obj/effect/landmark/start/sloc in GLOB.start_landmarks_list)
if(!sloc.job_spawnpoint)
continue
if(sloc.name != rank)
S = sloc //so we can revert to spawning them on top of eachother if something goes wrong
continue
if(locate(/mob/living) in sloc.loc)
continue
S = sloc
sloc.used = TRUE
break
if(length(GLOB.jobspawn_overrides[rank]))
S = pick(GLOB.jobspawn_overrides[rank])
var/atom/S = job.get_roundstart_spawn_point(H)
if(S)
S.JoinPlayerHere(H, FALSE)
if(!S) //if there isn't a spawnpoint send them to latejoin, if there's no latejoin go yell at your mapper
@@ -494,7 +481,7 @@ SUBSYSTEM_DEF(job)
if(job && H)
if(job.dresscodecompliant)// CIT CHANGE - dress code compliance
equip_loadout(N, H) // CIT CHANGE - allows players to spawn with loadout items
job.after_spawn(H, M, joined_late) // note: this happens before the mob has a key! M will always have a client, H might not.
job.after_spawn(H, M.client, joined_late) // note: this happens before the mob has a key! M will always have a client, H might not.
equip_loadout(N, H, TRUE)//CIT CHANGE - makes players spawn with in-backpack loadout items properly. A little hacky but it works
var/list/tcg_cards
@@ -768,6 +755,35 @@ SUBSYSTEM_DEF(job)
return FALSE
job.current_positions = max(0, job.current_positions - 1)
/datum/controller/subsystem/job/proc/get_last_resort_spawn_points()
//bad mojo
var/area/shuttle/arrival/arrivals_area = GLOB.areas_by_type[/area/shuttle/arrival]
if(arrivals_area)
//first check if we can find a chair
var/obj/structure/chair/shuttle_chair = locate() in arrivals_area
if(shuttle_chair)
return shuttle_chair
//last hurrah
var/list/turf/available_turfs = list()
for(var/turf/arrivals_turf in arrivals_area)
if(!is_blocked_turf(arrivals_turf, TRUE))
available_turfs += arrivals_turf
if(length(available_turfs))
return pick(available_turfs)
//pick an open spot on arrivals and dump em
var/list/arrivals_turfs = shuffle(get_area_turfs(/area/shuttle/arrival))
if(length(arrivals_turfs))
for(var/turf/arrivals_turf in arrivals_turfs)
if(!is_blocked_turf(arrivals_turf, TRUE))
return arrivals_turf
//last chance, pick ANY spot on arrivals and dump em
return pick(arrivals_turfs)
stack_trace("Unable to find last resort spawn point.")
return GET_ERROR_ROOM
///////////////////////////////////
//Keeps track of all living heads//
///////////////////////////////////

View File

@@ -81,7 +81,6 @@ SUBSYSTEM_DEF(mapping)
to_chat(world, "<span class='boldannounce'>Unable to load next or default map config, defaulting to Box Station</span>")
config = old_config
GLOB.year_integer += config.year_offset
GLOB.announcertype = (config.announcertype == "standard" ? (prob(1) ? "medibot" : "classic") : config.announcertype)
initialize_biomes()
loadWorld()
repopulate_sorted_areas()

View File

@@ -0,0 +1,84 @@
PROCESSING_SUBSYSTEM_DEF(station)
name = "Station"
init_order = INIT_ORDER_STATION
flags = SS_BACKGROUND
runlevels = RUNLEVEL_GAME
wait = 5 SECONDS
///A list of currently active station traits
var/list/station_traits = list()
///Assoc list of trait type || assoc list of traits with weighted value. Used for picking traits from a specific category.
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
/datum/controller/subsystem/processing/station/Initialize(timeofday)
//If doing unit tests we don't do none of that trait shit ya know?
#ifndef UNIT_TESTS
SetupTraits()
#endif
announcer = new announcer() //Initialize the station's announcer datum
return ..()
///Rolls for the amount of traits and adds them to the traits list
/datum/controller/subsystem/processing/station/proc/SetupTraits()
if (fexists(FUTURE_STATION_TRAITS_FILE))
var/forced_traits_contents = file2text(FUTURE_STATION_TRAITS_FILE)
fdel(FUTURE_STATION_TRAITS_FILE)
var/list/forced_traits_text_paths = json_decode(forced_traits_contents)
forced_traits_text_paths = SANITIZE_LIST(forced_traits_text_paths)
for (var/trait_text_path in forced_traits_text_paths)
var/station_trait_path = text2path(trait_text_path)
if (!ispath(station_trait_path, /datum/station_trait) || station_trait_path == /datum/station_trait)
var/message = "Invalid station trait path [station_trait_path] was requested in the future station traits!"
log_game(message)
message_admins(message)
continue
setup_trait(station_trait_path)
return
for(var/i in subtypesof(/datum/station_trait))
var/datum/station_trait/trait_typepath = i
// If forced, (probably debugging), just set it up now, keep it out of the pool.
if(initial(trait_typepath.force))
setup_trait(trait_typepath)
continue
if(initial(trait_typepath.trait_flags) & STATION_TRAIT_ABSTRACT || initial(trait_typepath.weight) == 0)
continue //Dont add abstract ones to it
selectable_traits_by_types[initial(trait_typepath.trait_type)][trait_typepath] = initial(trait_typepath.weight)
var/positive_trait_count = pick(20;0, 5;1, 1;2)
var/neutral_trait_count = pick(10;0, 10;1, 3;2)
var/negative_trait_count = pick(20;0, 5;1, 1;2)
can_fire = FALSE
pick_traits(STATION_TRAIT_POSITIVE, positive_trait_count)
pick_traits(STATION_TRAIT_NEUTRAL, neutral_trait_count)
pick_traits(STATION_TRAIT_NEGATIVE, negative_trait_count)
///Picks traits of a specific category (e.g. bad or good) and a specified amount, then initializes them and adds them to the list of traits.
/datum/controller/subsystem/processing/station/proc/pick_traits(trait_sign, amount)
if(!amount)
return
for(var/iterator in 1 to amount)
var/datum/station_trait/trait_type = pickweight(selectable_traits_by_types[trait_sign]) //Rolls from the table for the specific trait type
setup_trait(trait_type)
///Creates a given trait of a specific type, while also removing any blacklisted ones from the future pool.
/datum/controller/subsystem/processing/station/proc/setup_trait(datum/station_trait/trait_type)
var/datum/station_trait/trait_instance = new trait_type()
can_fire = can_fire || trait_instance.trait_processes
station_traits += trait_instance
if(!trait_instance.blacklist)
return
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

View File

@@ -301,7 +301,7 @@ SUBSYSTEM_DEF(ticker)
SSdbcore.SetRoundStart()
to_chat(world, "<span class='notice'><B>Welcome to [station_name()], enjoy your stay!</B></span>")
SEND_SOUND(world, sound(get_announcer_sound("welcome")))
SEND_SOUND(world, sound(SSstation.announcer.get_rand_welcome_sound()))
current_state = GAME_STATE_PLAYING
Master.SetRunLevel(RUNLEVEL_GAME)

View File

@@ -169,7 +169,7 @@ SUBSYSTEM_DEF(traumas)
/obj/structure/fluff/empty_sleeper/syndicate, /obj/item/implant/radio/syndicate, /obj/item/clothing/head/helmet/space/syndicate, /obj/machinery/nuclearbomb/syndicate, /obj/item/grenade/syndieminibomb, /obj/item/storage/backpack/duffelbag/syndie, /obj/item/gun/ballistic/automatic/pistol, /obj/item/gun/ballistic/revolver,
/obj/item/gun/ballistic/automatic/shotgun/bulldog, /obj/item/gun/ballistic/automatic/c20r, /obj/item/gun/ballistic/automatic/m90, /obj/item/gun/ballistic/automatic/l6_saw, /obj/item/storage/belt/grenade/full, /obj/item/gun/ballistic/automatic/sniper_rifle/syndicate, /obj/item/gun/energy/kinetic_accelerator/crossbow,
/obj/item/melee/transforming/energy/sword/saber, /obj/item/dualsaber, /obj/item/melee/powerfist, /obj/item/storage/box/syndie_kit, /obj/item/grenade/spawnergrenade/manhacks, /obj/item/grenade/chem_grenade/bioterrorfoam, /obj/item/reagent_containers/spray/chemsprayer/bioterror, /obj/item/ammo_box/magazine/m10mm,
/obj/item/ammo_box/magazine/pistolm9mm, /obj/item/ammo_box/a357, /obj/item/ammo_box/magazine/m12g, /obj/item/ammo_box/magazine/mm195x129, /obj/item/antag_spawner/nuke_ops, /obj/vehicle/sealed/mecha/combat/gygax/dark, /obj/vehicle/sealed/mecha/combat/marauder/mauler, /obj/item/soap/syndie, /obj/item/gun/syringe/syndicate, /obj/item/cartridge/virus/syndicate,
/obj/item/ammo_box/magazine/pistolm9mm, /obj/item/ammo_box/a357, /obj/item/ammo_box/magazine/m12g, /obj/item/ammo_box/magazine/mm712x82, /obj/item/antag_spawner/nuke_ops, /obj/vehicle/sealed/mecha/combat/gygax/dark, /obj/vehicle/sealed/mecha/combat/marauder/mauler, /obj/item/soap/syndie, /obj/item/gun/syringe/syndicate, /obj/item/cartridge/virus/syndicate,
/obj/item/cartridge/virus/frame, /obj/item/chameleon, /obj/item/storage/box/syndie_kit/cutouts, /obj/item/clothing/suit/space/hardsuit/syndi, /obj/item/card/emag, /obj/item/storage/toolbox/syndicate, /obj/item/storage/book/bible/syndicate, /obj/item/encryptionkey/binary, /obj/item/encryptionkey/syndicate, /obj/item/aiModule/syndicate,
/obj/item/clothing/shoes/magboots/syndie, /obj/item/powersink, /obj/item/sbeacondrop, /obj/item/sbeacondrop/bomb, /obj/item/syndicatedetonator, /obj/item/shield/energy, /obj/item/assault_pod, /obj/item/slimepotion/slime/sentience/nuclear, /obj/item/stack/telecrystal, /obj/item/jammer, /obj/item/codespeak_manual/unlimited,
/obj/item/toy/cards/deck/syndicate, /obj/item/storage/secure/briefcase/syndie, /obj/item/storage/fancy/cigarettes/cigpack_syndicate, /obj/item/toy/syndicateballoon, /obj/item/clothing/gloves/fingerless/pugilist/rapid, /obj/item/paper/fluff/ruins/thederelict/syndie_mission, /obj/item/organ/cyberimp/eyes/hud/security/syndicate, /obj/item/clothing/head/HoS/syndicate,

View File

@@ -223,6 +223,11 @@
/datum/ai_laws/proc/set_laws_config()
var/list/law_ids = CONFIG_GET(keyed_list/random_laws)
if(HAS_TRAIT(SSstation, STATION_TRAIT_UNIQUE_AI))
pick_weighted_lawset()
return
switch(CONFIG_GET(number/default_laws))
if(0)
add_inherent_law("You may not injure a human being or cause one to come to harm.")

View File

@@ -0,0 +1,23 @@
///Data holder for the announcers that can be used in a game, this can be used to have alternative announcements outside of the default e.g.the intern
/datum/centcom_announcer
///Roundshift start audio
var/welcome_sounds = list()
///Sounds made when announcement is receivedc
var/alert_sounds = list()
///Sounds made when command report is received
var/command_report_sounds = list()
///Event audio, can be used for specific event announcements and is assoc key - sound. If no sound is found the default is used.area
var/event_sounds = list()
///Override this to have a custom message to show instead of the normal priority announcement
var/custom_alert_message
/datum/centcom_announcer/proc/get_rand_welcome_sound()
return pick(welcome_sounds)
/datum/centcom_announcer/proc/get_rand_alert_sound()
return pick(alert_sounds)
/datum/centcom_announcer/proc/get_rand_report_sound()
return pick(command_report_sounds)

View File

@@ -0,0 +1,21 @@
/datum/centcom_announcer/default
welcome_sounds = list('sound/announcer/classic/welcome.ogg')
alert_sounds = list('sound/announcer/classic/attention.ogg')
command_report_sounds = list('sound/announcer/classic/commandreport.ogg')
event_sounds = list(ANNOUNCER_AIMALF = 'sound/announcer/classic/aimalf.ogg',
ANNOUNCER_ALIENS = 'sound/announcer/classic/aliens.ogg',
ANNOUNCER_ANIMES = 'sound/announcer/classic/animes.ogg',
ANNOUNCER_GRANOMALIES = 'sound/announcer/classic/granomalies.ogg',
ANNOUNCER_INTERCEPT = 'sound/announcer/classic/intercept.ogg',
ANNOUNCER_IONSTORM = 'sound/announcer/classic/ionstorm.ogg',
ANNOUNCER_METEORS = 'sound/announcer/classic/meteors.ogg',
ANNOUNCER_NEWAI = 'sound/announcer/classic/newai.ogg',
ANNOUNCER_OUTBREAK5 = 'sound/announcer/classic/outbreak5.ogg',
ANNOUNCER_OUTBREAK7 = 'sound/announcer/classic/outbreak7.ogg',
ANNOUNCER_POWEROFF = 'sound/announcer/classic/poweroff.ogg',
ANNOUNCER_POWERON = 'sound/announcer/classic/poweron.ogg',
ANNOUNCER_RADIATION = 'sound/announcer/classic/radiation.ogg',
ANNOUNCER_SHUTTLECALLED = 'sound/announcer/classic/shuttlecalled.ogg',
ANNOUNCER_SHUTTLEDOCK = 'sound/announcer/classic/shuttledock.ogg',
ANNOUNCER_SHUTTLERECALLED = 'sound/announcer/classic/shuttlerecalled.ogg',
ANNOUNCER_SPANOMALIES = 'sound/announcer/classic/spanomalies.ogg')

View File

@@ -0,0 +1,47 @@
/datum/centcom_announcer/intern
welcome_sounds = list('sound/announcer/intern/welcome/1.ogg',
'sound/announcer/intern/welcome/2.ogg',
'sound/announcer/intern/welcome/3.ogg',
'sound/announcer/intern/welcome/4.ogg',
'sound/announcer/intern/welcome/5.ogg',
'sound/announcer/intern/welcome/6.ogg')
alert_sounds = list('sound/announcer/intern/alerts/1.ogg',
'sound/announcer/intern/alerts/2.ogg',
'sound/announcer/intern/alerts/3.ogg',
'sound/announcer/intern/alerts/4.ogg',
'sound/announcer/intern/alerts/5.ogg',
'sound/announcer/intern/alerts/6.ogg',
'sound/announcer/intern/alerts/7.ogg',
'sound/announcer/intern/alerts/8.ogg',
'sound/announcer/intern/alerts/9.ogg',
'sound/announcer/intern/alerts/10.ogg',
'sound/announcer/intern/alerts/11.ogg',
'sound/announcer/intern/alerts/12.ogg',
'sound/announcer/intern/alerts/13.ogg',
'sound/announcer/intern/alerts/14.ogg')
command_report_sounds = list('sound/announcer/intern/commandreport/1.ogg',
'sound/announcer/intern/commandreport/2.ogg',
'sound/announcer/intern/commandreport/3.ogg')
event_sounds = list(ANNOUNCER_AIMALF = 'sound/announcer/classic/aimalf.ogg',
ANNOUNCER_ALIENS = 'sound/announcer/intern/aliens.ogg',
ANNOUNCER_ANIMES = 'sound/announcer/intern/animes.ogg',
ANNOUNCER_GRANOMALIES = 'sound/announcer/intern/granomalies.ogg',
ANNOUNCER_INTERCEPT = 'sound/announcer/intern/intercept.ogg',
ANNOUNCER_IONSTORM = 'sound/announcer/intern/ionstorm.ogg',
ANNOUNCER_METEORS = 'sound/announcer/intern/meteors.ogg',
ANNOUNCER_NEWAI = 'sound/announcer/classic/newai.ogg',
ANNOUNCER_OUTBREAK5 = 'sound/announcer/intern/outbreak5.ogg',
ANNOUNCER_OUTBREAK7 = 'sound/announcer/intern/outbreak7.ogg',
ANNOUNCER_POWEROFF = 'sound/announcer/intern/poweroff.ogg',
ANNOUNCER_POWERON = 'sound/announcer/intern/poweron.ogg',
ANNOUNCER_RADIATION = 'sound/announcer/intern/radiation.ogg',
ANNOUNCER_SHUTTLECALLED = 'sound/announcer/intern/shuttlecalled.ogg',
ANNOUNCER_SHUTTLEDOCK = 'sound/announcer/intern/shuttledock.ogg',
ANNOUNCER_SHUTTLERECALLED = 'sound/announcer/intern/shuttlerecalled.ogg',
ANNOUNCER_SPANOMALIES = 'sound/announcer/intern/spanomalies.ogg')
custom_alert_message = "<br><span class='alert'>Please stand by for an important message from our new intern.</span><br>"

View File

@@ -0,0 +1,22 @@
/datum/centcom_announcer/medbot
welcome_sounds = list('sound/announcer/medibot/welcome.ogg',
'sound/announcer/medibot/newAI.ogg')
alert_sounds = list('sound/announcer/medibot/attention.ogg')
command_report_sounds = list('sound/announcer/medibot/commandreport.ogg')
event_sounds = list(ANNOUNCER_AIMALF = 'sound/announcer/classic/aimalf.ogg',
ANNOUNCER_ALIENS = 'sound/announcer/medibot/aliens.ogg',
ANNOUNCER_ANIMES = 'sound/announcer/medibot/animes.ogg',
ANNOUNCER_GRANOMALIES = 'sound/announcer/medibot/granomalies.ogg',
ANNOUNCER_INTERCEPT = 'sound/announcer/medibot/intercept.ogg',
ANNOUNCER_IONSTORM = 'sound/announcer/medibot/ionstorm.ogg',
ANNOUNCER_METEORS = 'sound/announcer/medibot/meteors.ogg',
ANNOUNCER_NEWAI = 'sound/announcer/medibot/newai.ogg',
ANNOUNCER_OUTBREAK5 = 'sound/announcer/medibot/outbreak5.ogg',
ANNOUNCER_OUTBREAK7 = 'sound/announcer/medibot/outbreak7.ogg',
ANNOUNCER_POWEROFF = 'sound/announcer/medibot/poweroff.ogg',
ANNOUNCER_POWERON = 'sound/announcer/medibot/poweron.ogg',
ANNOUNCER_RADIATION = 'sound/announcer/medibot/radiation.ogg',
ANNOUNCER_SHUTTLECALLED = 'sound/announcer/medibot/shuttlecalled.ogg',
ANNOUNCER_SHUTTLEDOCK = 'sound/announcer/medibot/shuttledocked.ogg',
ANNOUNCER_SHUTTLERECALLED = 'sound/announcer/medibot/shuttlerecalled.ogg',
ANNOUNCER_SPANOMALIES = 'sound/announcer/medibot/spanomalies.ogg')

View File

@@ -24,6 +24,9 @@
var/target_pressure = rand(minimum_pressure, maximum_pressure)
var/pressure_scale = target_pressure / maximum_pressure
if(HAS_TRAIT(SSstation, STATION_TRAIT_UNNATURAL_ATMOSPHERE))
restricted_chance = restricted_chance + 40
// First let's set up the gasmix and base gases for this template
// We make the string from a gasmix in this proc because gases need to calculate their pressure
var/datum/gas_mixture/gasmix = new

View File

@@ -15,7 +15,6 @@
GAS_BZ=0.1,
GAS_BROMINE=0.1
)
restricted_chance = 30
minimum_pressure = HAZARD_LOW_PRESSURE + 10
maximum_pressure = LAVALAND_EQUIPMENT_EFFECT_PRESSURE - 1
@@ -62,7 +61,7 @@
GAS_METHYL_BROMIDE=0.1,
GAS_HYDROGEN=0.1
)
restricted_chance = 10
restricted_chance = 5
minimum_pressure = HAZARD_LOW_PRESSURE + 10
maximum_pressure = LAVALAND_EQUIPMENT_EFFECT_PRESSURE - 1

View File

@@ -0,0 +1,47 @@
/**
* A simple component that spawns a mob of the same type and transfers itself to it when parent dies.
* For more complex behaviors, use the COMSIG_ON_MULTIPLE_LIVES_RESPAWN comsig.
*/
/datum/component/multiple_lives
can_transfer = TRUE
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
/// The number of respawns the living mob has left.
var/lives_left
/datum/component/multiple_lives/Initialize(lives_left)
if(!isliving(parent))
return COMPONENT_INCOMPATIBLE
src.lives_left = lives_left
/datum/component/multiple_lives/RegisterWithParent()
RegisterSignal(parent, COMSIG_MOB_DEATH, .proc/respawn)
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_examine)
/datum/component/multiple_lives/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_MOB_DEATH, COMSIG_PARENT_EXAMINE))
/datum/component/multiple_lives/proc/respawn(mob/living/source, gibbed)
SIGNAL_HANDLER
if(source.suiciding) //Freed from this mortail coil.
qdel(src)
return
var/mob/living/respawned_mob = new source.type (source.drop_location())
source.mind?.transfer_to(respawned_mob)
lives_left--
if(lives_left <= 0)
qdel(src)
source.TransferComponents(respawned_mob)
SEND_SIGNAL(source, COMSIG_ON_MULTIPLE_LIVES_RESPAWN, respawned_mob, gibbed, lives_left)
/datum/component/multiple_lives/proc/on_examine(mob/living/source, mob/user, list/examine_list)
SIGNAL_HANDLER
if(isobserver(user) || source == user)
examine_list += "[source.p_theyve(TRUE)] [lives_left] extra lives left."
/datum/component/multiple_lives/InheritComponent(datum/component/multiple_lives/new_comp , lives_left)
src.lives_left += new_comp ? new_comp.lives_left : lives_left
/datum/component/multiple_lives/PostTransfer()
if(!isliving(parent))
return COMPONENT_INCOMPATIBLE

View File

@@ -82,12 +82,14 @@
var/move_delay = 2
var/last_move = 0
/datum/component/twitch_plays/simple_movement/auto/Initialize(...)
/datum/component/twitch_plays/simple_movement/auto/Initialize(move_delay)
if(!ismovable(parent))
return COMPONENT_INCOMPATIBLE
. = ..()
if(. & COMPONENT_INCOMPATIBLE)
return
if(!isnull(move_delay))
src.move_delay = move_delay
START_PROCESSING(SSfastprocess, src)
/datum/component/twitch_plays/simple_movement/auto/Destroy(force, silent)
@@ -95,10 +97,10 @@
return ..()
/datum/component/twitch_plays/simple_movement/auto/process()
if(world.time < (last_move + move_delay))
return
var/dir = fetch_data(null, TRUE)
if(!dir)
return
if(world.time < (last_move + move_delay))
return
last_move = world.time
step(parent, dir)

View File

@@ -0,0 +1,57 @@
///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
var/name = "unnamed station trait"
///The type of this trait. Used to classify how this trait influences the station
var/trait_type = STATION_TRAIT_NEUTRAL
///Whether or not this trait uses process()
var/trait_processes = FALSE
///Chance relative to other traits of its type to be picked
var/weight = 10
///Whether this trait is always enabled; generally used for debugging
var/force = FALSE
///Does this trait show in the centcom report?
var/show_in_report = FALSE
///What message to show in the centcom report?
var/report_message
///What code-trait does this station trait give? gives none if null
var/trait_to_give
///What traits are incompatible with this one?
var/blacklist
///Extra flags for station traits such as it being abstract
var/trait_flags
/// Whether or not this trait can be reverted by an admin
var/can_revert = TRUE
/datum/station_trait/New()
. = ..()
RegisterSignal(SSticker, COMSIG_TICKER_ROUND_STARTING, .proc/on_round_start)
if(trait_processes)
START_PROCESSING(SSstation, src)
if(trait_to_give)
ADD_TRAIT(SSstation, trait_to_give, STATION_TRAIT)
/datum/station_trait/Destroy()
SSstation.station_traits -= src
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.
/datum/station_trait/proc/get_report()
return "[name] - [report_message]"
/// Will attempt to revert the station trait, used by admins.
/datum/station_trait/proc/revert()
if (!can_revert)
CRASH("revert() was called on [type], which can't be reverted!")
if (trait_to_give)
REMOVE_TRAIT(SSstation, trait_to_give, STATION_TRAIT)
qdel(src)

View File

@@ -0,0 +1,133 @@
/// Opens the station traits admin panel
/datum/admins/proc/station_traits_panel()
set name = "Modify Station Traits"
set category = "Admin.Events"
var/static/datum/station_traits_panel/station_traits_panel = new
station_traits_panel.ui_interact(usr)
/datum/station_traits_panel
var/static/list/future_traits
/datum/station_traits_panel/ui_data(mob/user)
var/list/data = list()
data["too_late_to_revert"] = too_late_to_revert()
var/list/current_station_traits = list()
for (var/datum/station_trait/station_trait as anything in SSstation.station_traits)
current_station_traits += list(list(
"name" = station_trait.name,
"can_revert" = station_trait.can_revert,
"ref" = REF(station_trait),
))
data["current_traits"] = current_station_traits
data["future_station_traits"] = future_traits
return data
/datum/station_traits_panel/ui_static_data(mob/user)
var/list/data = list()
var/list/valid_station_traits = list()
for (var/datum/station_trait/station_trait_path as anything in subtypesof(/datum/station_trait))
valid_station_traits += list(list(
"name" = initial(station_trait_path.name),
"path" = station_trait_path,
))
data["valid_station_traits"] = valid_station_traits
return data
/datum/station_traits_panel/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if (.)
return
switch (action)
if ("revert")
var/ref = params["ref"]
if (!ref)
return TRUE
var/datum/station_trait/station_trait = locate(ref)
if (!istype(station_trait))
return TRUE
if (too_late_to_revert())
to_chat(usr, span_warning("It's too late to revert station traits, the round has already started!"))
return TRUE
if (!station_trait.can_revert)
stack_trace("[station_trait.type] can't be reverted, but was requested anyway.")
return TRUE
var/message = "[key_name(usr)] reverted the station trait [station_trait.name] ([station_trait.type])"
log_admin(message)
message_admins(message)
station_trait.revert()
return TRUE
if ("setup_future_traits")
if (too_late_for_future_traits())
to_chat(usr, span_warning("It's too late to add future station traits, the round is already over!"))
return TRUE
var/list/new_future_traits = list()
var/list/station_trait_names = list()
for (var/station_trait_text in params["station_traits"])
var/datum/station_trait/station_trait_path = text2path(station_trait_text)
if (!ispath(station_trait_path, /datum/station_trait) || station_trait_path == /datum/station_trait)
log_admin("[key_name(usr)] tried to set an invalid future station trait: [station_trait_text]")
to_chat(usr, span_warning("Invalid future station trait: [station_trait_text]"))
return TRUE
station_trait_names += initial(station_trait_path.name)
new_future_traits += list(list(
"name" = initial(station_trait_path.name),
"path" = station_trait_path,
))
var/message = "[key_name(usr)] has prepared the following station traits for next round: [station_trait_names.Join(", ") || "None"]"
log_admin(message)
message_admins(message)
future_traits = new_future_traits
rustg_file_write(json_encode(params["station_traits"]), FUTURE_STATION_TRAITS_FILE)
return TRUE
if ("clear_future_traits")
if (!future_traits)
to_chat(usr, span_warning("There are no future station traits."))
return TRUE
var/message = "[key_name(usr)] has cleared the station traits for next round."
log_admin(message)
message_admins(message)
fdel(FUTURE_STATION_TRAITS_FILE)
future_traits = null
return TRUE
/datum/station_traits_panel/proc/too_late_for_future_traits()
return SSticker.current_state >= GAME_STATE_FINISHED
/datum/station_traits_panel/proc/too_late_to_revert()
return SSticker.current_state >= GAME_STATE_PLAYING
/datum/station_traits_panel/ui_status(mob/user, datum/ui_state/state)
return check_rights_for(user.client, R_FUN) ? UI_INTERACTIVE : UI_CLOSE
/datum/station_traits_panel/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "StationTraitsPanel")
ui.open()

View File

@@ -0,0 +1,287 @@
/datum/station_trait/carp_infestation
name = "Carp infestation"
trait_type = STATION_TRAIT_NEGATIVE
weight = 5
show_in_report = TRUE
report_message = "Dangerous fauna is present in the area of this station."
trait_to_give = STATION_TRAIT_CARP_INFESTATION
/datum/station_trait/distant_supply_lines
name = "Distant supply lines"
trait_type = STATION_TRAIT_NEGATIVE
weight = 3
show_in_report = TRUE
report_message = "Due to the distance to our normal supply lines, cargo orders are more expensive."
blacklist = list(/datum/station_trait/strong_supply_lines)
/datum/station_trait/distant_supply_lines/on_round_start()
SSeconomy.pack_price_modifier *= 1.2
/datum/station_trait/late_arrivals
name = "Late Arrivals"
trait_type = STATION_TRAIT_NEGATIVE
weight = 2
show_in_report = TRUE
report_message = "Sorry for that, we didn't expect to fly into that vomiting goose while bringing you to your new station."
trait_to_give = STATION_TRAIT_LATE_ARRIVALS
blacklist = list(/datum/station_trait/random_spawns, /datum/station_trait/hangover)
/datum/station_trait/random_spawns
name = "Drive-by landing"
trait_type = STATION_TRAIT_NEGATIVE
weight = 2
show_in_report = TRUE
report_message = "Sorry for that, we missed your station by a few miles, so we just launched you towards your station in pods. Hope you don't mind!"
trait_to_give = STATION_TRAIT_RANDOM_ARRIVALS
blacklist = list(/datum/station_trait/late_arrivals, /datum/station_trait/hangover)
/datum/station_trait/hangover
name = "Hangover"
trait_type = STATION_TRAIT_NEGATIVE
weight = 0
show_in_report = TRUE
report_message = "Ohh....Man....That mandatory office party from last shift...God that was awesome..I woke up in some random toilet 3 sectors away..."
trait_to_give = STATION_TRAIT_HANGOVER
blacklist = list(/datum/station_trait/late_arrivals, /datum/station_trait/random_spawns)
/datum/station_trait/hangover/New()
. = ..()
RegisterSignal(SSdcs, COMSIG_GLOB_JOB_AFTER_LATEJOIN_SPAWN, .proc/on_job_after_spawn)
/datum/station_trait/hangover/revert()
for (var/obj/effect/landmark/start/hangover/hangover_spot in GLOB.start_landmarks_list)
QDEL_LIST(hangover_spot.debris)
return ..()
/datum/station_trait/hangover/proc/on_job_after_spawn(datum/source, datum/job/job, mob/living/spawned_mob)
SIGNAL_HANDLER
if(prob(65)) // most aren't hungover
return
if(!iscarbon(spawned_mob)) // don't want silicons or similar to be counted here
return
if(HAS_TRAIT(spawned_mob, TRAIT_ROBOTIC_ORGANISM)) // robots can't get hungover
return
if(HAS_TRAIT(spawned_mob, TRAIT_TOXIC_ALCOHOL)) // people with alcohol intolerance also can't
return
var/obj/item/hat = pick(
/obj/item/clothing/head/sombrero,
/obj/item/clothing/head/fedora,
/obj/item/clothing/mask/balaclava,
/obj/item/clothing/head/ushanka,
/obj/item/clothing/head/cardborg,
/obj/item/clothing/head/pirate,
/obj/item/clothing/head/cone,
)
hat = new hat(spawned_mob)
spawned_mob.equip_to_slot_or_del(hat, ITEM_SLOT_HEAD)
/datum/station_trait/blackout
name = "Blackout"
trait_type = STATION_TRAIT_NEGATIVE
weight = 3
show_in_report = TRUE
report_message = "Station lights seem to be damaged, be safe when starting your shift today."
/datum/station_trait/blackout/on_round_start()
. = ..()
for(var/obj/machinery/power/apc/apc as anything in GLOB.apcs_list)
if(is_station_level(apc.z) && prob(60))
apc.overload_lighting()
/datum/station_trait/empty_maint
name = "Cleaned out maintenance"
trait_type = STATION_TRAIT_NEGATIVE
weight = 5
show_in_report = TRUE
report_message = "Our workers cleaned out most of the junk in the maintenace areas."
blacklist = list(/datum/station_trait/filled_maint)
trait_to_give = STATION_TRAIT_EMPTY_MAINT
// This station trait is checked when loot drops initialize, so it's too late
can_revert = FALSE
/datum/station_trait/overflow_job_bureaucracy
name = "Overflow bureaucracy mistake"
trait_type = STATION_TRAIT_NEGATIVE
weight = 4
show_in_report = TRUE
var/chosen_job_name
/datum/station_trait/overflow_job_bureaucracy/New()
. = ..()
RegisterSignal(SSjob, COMSIG_SUBSYSTEM_POST_INITIALIZE, .proc/set_overflow_job_override)
/datum/station_trait/overflow_job_bureaucracy/get_report()
return "[name] - It seems for some reason we put out the wrong job-listing for the overflow role this shift...I hope you like [chosen_job_name]s."
/datum/station_trait/overflow_job_bureaucracy/proc/set_overflow_job_override(datum/source)
SIGNAL_HANDLER
var/datum/job/picked_job = pick(get_all_jobs())
chosen_job_name = lowertext(picked_job.title) // like Chief Engineers vs like chief engineers
SSjob.set_overflow_role(picked_job.type)
/datum/station_trait/slow_shuttle
name = "Slow Shuttle"
trait_type = STATION_TRAIT_NEGATIVE
weight = 5
show_in_report = TRUE
report_message = "Due to distance to our supply station, the cargo shuttle will have a slower flight time to your cargo department."
blacklist = list(/datum/station_trait/quick_shuttle)
/datum/station_trait/slow_shuttle/on_round_start()
. = ..()
SSshuttle.supply.callTime *= 1.5
/datum/station_trait/bot_languages
name = "Bot Language Matrix Malfunction"
trait_type = STATION_TRAIT_NEGATIVE
weight = 3
show_in_report = TRUE
report_message = "Your station's friendly bots have had their language matrix fried due to an event, resulting in some strange and unfamiliar speech patterns."
/datum/station_trait/bot_languages/New()
. = ..()
/// What "caused" our robots to go haywire (fluff)
var/event_source = pick(list("an ion storm", "a syndicate hacking attempt", "a malfunction", "issues with your onboard AI", "an intern's mistakes", "budget cuts"))
report_message = "Your station's friendly bots have had their language matrix fried due to [event_source], resulting in some strange and unfamiliar speech patterns."
/datum/station_trait/bot_languages/on_round_start()
. = ..()
//All bots that exist round start have their set language randomized.
for(var/mob/living/simple_animal/bot/found_bot in GLOB.alive_mob_list)
/// The bot's language holder - so we can randomize and change their language
var/datum/language_holder/bot_languages = found_bot.get_language_holder()
bot_languages.selected_language = bot_languages.get_random_spoken_language()
/datum/station_trait/revenge_of_pun_pun
name = "Revenge of Pun Pun"
trait_type = STATION_TRAIT_NEGATIVE
weight = 2
// Way too much is done on atoms SS to be reverted, and it'd look
// kinda clunky on round start. It's not impossible to make this work,
// but it's a project for...someone else.
can_revert = FALSE
var/static/list/weapon_types
/datum/station_trait/revenge_of_pun_pun/New()
if(!weapon_types)
weapon_types = list(
/obj/item/chair = 25,
/obj/item/tailclub = 15,
/obj/item/melee/baseball_bat = 10,
/obj/item/melee/chainofcommand/tailwhip = 15,
/obj/item/melee/chainofcommand/tailwhip/kitty = 15,
/obj/item/reagent_containers/food/drinks/bottle = 25,
/obj/item/gun/ballistic/automatic/pistol = 1,
)
RegisterSignal(SSatoms, COMSIG_SUBSYSTEM_POST_INITIALIZE, .proc/arm_monke)
/datum/station_trait/revenge_of_pun_pun/proc/arm_monke()
SIGNAL_HANDLER
var/mob/living/carbon/monkey/punpun = locate()
if(!punpun)
return
var/weapon_type = pickweight(weapon_types)
var/obj/item/weapon = new weapon_type
if(!punpun.put_in_l_hand(weapon) && !punpun.put_in_r_hand(weapon))
// Guess they did all this with whatever they have in their hands already
qdel(weapon)
weapon = punpun.get_active_held_item() || punpun.get_inactive_held_item()
weapon?.add_mob_blood(punpun)
punpun.add_mob_blood(punpun)
punpun.aggressive = TRUE
var/area/place = get_area(punpun)
var/list/area_open_turfs = list()
for(var/turf/location in place)
if(location.density)
continue
area_open_turfs += location
punpun.forceMove(pick(area_open_turfs))
for(var/i in 1 to rand(10, 40))
new /obj/effect/decal/cleanable/blood(pick(area_open_turfs))
var/list/blood_path = list()
for(var/i in 1 to 10) // Only 10 attempts
var/turf/destination = pick(area_open_turfs)
var/turf/next_step = get_step_to(punpun, destination)
for(var/k in 1 to 30) // Max 30 steps
if(!next_step)
break
blood_path += next_step
next_step = get_step_to(next_step, destination)
if(length(blood_path))
break
if(!length(blood_path))
CRASH("Unable to make a path from punpun")
var/turf/last_location
for(var/turf/location as anything in blood_path)
last_location = location
if(prob(80))
new /obj/effect/decal/cleanable/blood(location)
if(prob(50))
var/static/blood_types = list(
/obj/effect/decal/cleanable/blood/splatter,
/obj/effect/decal/cleanable/blood/gibs,
)
var/blood_type = pick(blood_types)
new blood_type(get_turf(pick(orange(location, 2))))
new /obj/effect/decal/cleanable/blood/gibs/torso(last_location)
// Abstract station trait used for traits that modify a random event in some way (their weight or max occurrences).
/datum/station_trait/random_event_weight_modifier
name = "Random Event Modifier"
report_message = "A random event has been modified this shift! Someone forgot to set this!"
show_in_report = TRUE
trait_flags = STATION_TRAIT_ABSTRACT
weight = 0
/// The path to the round_event_control that we modify.
var/event_control_path
/// Multiplier applied to the weight of the event.
var/weight_multiplier = 1
/// Flat modifier added to the amount of max occurances the random event can have.
var/max_occurrences_modifier = 0
/datum/station_trait/random_event_weight_modifier/on_round_start()
. = ..()
var/datum/round_event_control/modified_event = locate(event_control_path) in SSevents.control
if(!modified_event)
CRASH("[type] could not find a round event controller to modify on round start (likely has an invalid event_control_path set)!")
modified_event.weight *= weight_multiplier
modified_event.max_occurrences += max_occurrences_modifier
/datum/station_trait/random_event_weight_modifier/ion_storms
name = "Ionic Stormfront"
report_message = "An ionic stormfront is passing over your station's system. Expect an increased likelihood of ion storms afflicting your station's silicon units."
trait_type = STATION_TRAIT_NEGATIVE
trait_flags = NONE
weight = 3
event_control_path = /datum/round_event_control/ion_storm
weight_multiplier = 2
/datum/station_trait/random_event_weight_modifier/rad_storms
name = "Radiation Stormfront"
report_message = "A radioactive stormfront is passing through your station's system. Expect an increased likelihood of radiation storms passing over your station, as well the potential for multiple radiation storms to occur during your shift."
trait_type = STATION_TRAIT_NEGATIVE
trait_flags = NONE
weight = 2
event_control_path = /datum/round_event_control/radiation_storm
weight_multiplier = 1.5
max_occurrences_modifier = 2

View File

@@ -0,0 +1,116 @@
/datum/station_trait/bananium_shipment
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"
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"
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
can_revert = FALSE
/datum/station_trait/unique_ai
name = "Unique AI"
trait_type = STATION_TRAIT_NEUTRAL
weight = 5
show_in_report = TRUE
report_message = "For experimental purposes, this station AI might show divergence from default lawset. Do not meddle with this experiment."
trait_to_give = STATION_TRAIT_UNIQUE_AI
/datum/station_trait/ian_adventure
name = "Ian's Adventure"
trait_type = STATION_TRAIT_NEUTRAL
weight = 5
show_in_report = FALSE
report_message = "Ian has gone exploring somewhere in the station."
/datum/station_trait/ian_adventure/on_round_start()
for(var/mob/living/simple_animal/pet/dog/corgi/dog in GLOB.mob_list)
if(!(istype(dog, /mob/living/simple_animal/pet/dog/corgi/Ian) || istype(dog, /mob/living/simple_animal/pet/dog/corgi/puppy)))
continue
// Makes this station trait more interesting. Ian probably won't go anywhere without a little external help.
// Also gives him a couple extra lives to survive eventual tiders.
dog.AddComponent(/datum/component/twitch_plays/simple_movement/auto, 3 SECONDS)
dog.AddComponent(/datum/component/multiple_lives, 2)
RegisterSignal(dog, COMSIG_ON_MULTIPLE_LIVES_RESPAWN, .proc/do_corgi_respawn)
// The extended safety checks at time of writing are about chasms and lava
// if there are any chasms and lava on stations in the future, woah
var/turf/current_turf = get_turf(dog)
var/turf/adventure_turf = find_safe_turf(extended_safety_checks = TRUE, dense_atoms = FALSE)
// Poof!
do_smoke(location=current_turf)
dog.forceMove(adventure_turf)
do_smoke(location=adventure_turf)
/// Moves the new dog somewhere safe, equips it with the old one's inventory and makes it deadchat_playable.
/datum/station_trait/ian_adventure/proc/do_corgi_respawn(mob/living/simple_animal/pet/dog/corgi/old_dog, mob/living/simple_animal/pet/dog/corgi/new_dog, gibbed, lives_left)
SIGNAL_HANDLER
var/turf/current_turf = get_turf(new_dog)
var/turf/adventure_turf = find_safe_turf(extended_safety_checks = TRUE, dense_atoms = FALSE)
do_smoke(location=current_turf)
new_dog.forceMove(adventure_turf)
do_smoke(location=adventure_turf)
if(old_dog.inventory_back)
var/obj/item/old_dog_back = old_dog.inventory_back
old_dog.inventory_back = null
old_dog_back.forceMove(new_dog)
new_dog.inventory_back = old_dog_back
if(old_dog.inventory_head)
var/obj/item/old_dog_hat = old_dog.inventory_head
old_dog.inventory_head = null
new_dog.place_on_head(old_dog_hat)
new_dog.update_corgi_fluff()
new_dog.regenerate_icons()
new_dog.AddComponent(/datum/component/twitch_plays/simple_movement/auto, 3 SECONDS)
if(lives_left)
RegisterSignal(new_dog, COMSIG_ON_MULTIPLE_LIVES_RESPAWN, .proc/do_corgi_respawn)
if(!gibbed) //The old dog will now disappear so we won't have more than one Ian at a time.
qdel(old_dog)
/datum/station_trait/glitched_pdas
name = "PDA glitch"
trait_type = STATION_TRAIT_NEUTRAL
weight = 15
show_in_report = TRUE
report_message = "Something seems to be wrong with the PDAs issued to you all this shift. Nothing too bad though."
trait_to_give = STATION_TRAIT_PDA_GLITCHED
/datum/station_trait/announcement_intern
name = "Announcement Intern"
trait_type = STATION_TRAIT_NEUTRAL
weight = 1
show_in_report = TRUE
report_message = "Please be nice to him."
blacklist = list(/datum/station_trait/announcement_medbot)
/datum/station_trait/announcement_intern/New()
. = ..()
SSstation.announcer = /datum/centcom_announcer/intern
/datum/station_trait/announcement_medbot
name = "Announcement \"System\""
trait_type = STATION_TRAIT_NEUTRAL
weight = 1
show_in_report = TRUE
report_message = "Our announcement system is under scheduled maintanance at the moment. Thankfully, we have a backup."
blacklist = list(/datum/station_trait/announcement_intern)
/datum/station_trait/announcement_medbot/New()
. = ..()
SSstation.announcer = /datum/centcom_announcer/medbot

View File

@@ -0,0 +1,279 @@
#define PARTY_COOLDOWN_LENGTH_MIN 6 MINUTES
#define PARTY_COOLDOWN_LENGTH_MAX 12 MINUTES
/datum/station_trait/lucky_winner
name = "Lucky winner"
trait_type = STATION_TRAIT_POSITIVE
weight = 1
show_in_report = TRUE
report_message = "Your station has won the grand prize of the annual station charity event. Free snacks will be delivered to the bar every now and then."
trait_processes = TRUE
COOLDOWN_DECLARE(party_cooldown)
/datum/station_trait/lucky_winner/on_round_start()
. = ..()
COOLDOWN_START(src, party_cooldown, rand(PARTY_COOLDOWN_LENGTH_MIN, PARTY_COOLDOWN_LENGTH_MAX))
/datum/station_trait/lucky_winner/process(delta_time)
if(!COOLDOWN_FINISHED(src, party_cooldown))
return
COOLDOWN_START(src, party_cooldown, rand(PARTY_COOLDOWN_LENGTH_MIN, PARTY_COOLDOWN_LENGTH_MAX))
var/area/area_to_spawn_in = pick(GLOB.bar_areas)
var/turf/T = pick(area_to_spawn_in.contents)
var/obj/structure/closet/supplypod/centcompod/toLaunch = new()
var/obj/item/pizzabox/pizza_to_spawn = pick(list(/obj/item/pizzabox/margherita, /obj/item/pizzabox/mushroom, /obj/item/pizzabox/meat, /obj/item/pizzabox/vegetable, /obj/item/pizzabox/pineapple))
new pizza_to_spawn(toLaunch)
for(var/i in 1 to 6)
if(prob(50))
new /obj/item/reagent_containers/food/drinks/beer(toLaunch)
else
for(var/m in 1 to 2)
var/obj/item/soda_to_spawn = pick(list(/obj/item/reagent_containers/food/drinks/soda_cans/sol_dry,
/obj/item/reagent_containers/food/drinks/soda_cans/space_up,
/obj/item/reagent_containers/food/drinks/soda_cans/starkist,
/obj/item/reagent_containers/food/drinks/soda_cans/cola,
/obj/item/reagent_containers/food/drinks/soda_cans/space_mountain_wind,
/obj/item/reagent_containers/food/drinks/soda_cans/dr_gibb,
/obj/item/reagent_containers/food/drinks/soda_cans/pwr_game))
new soda_to_spawn(toLaunch)
new /obj/effect/pod_landingzone(T, toLaunch)
/datum/station_trait/galactic_grant
name = "Galactic grant"
trait_type = STATION_TRAIT_POSITIVE
weight = 6
show_in_report = TRUE
report_message = "Your station has been selected for a special grant. Some extra funds has been made available to your cargo department."
/datum/station_trait/galactic_grant/on_round_start()
var/datum/bank_account/cargo_bank = SSeconomy.get_dep_account(ACCOUNT_CAR)
cargo_bank.adjust_money(rand(2000, 5000))
/datum/station_trait/premium_internals_box
name = "Premium internals boxes"
trait_type = STATION_TRAIT_POSITIVE
weight = 10
show_in_report = TRUE
report_message = "The internals boxes for your crew have been filled with bonus equipment."
trait_to_give = STATION_TRAIT_PREMIUM_INTERNALS
/datum/station_trait/bountiful_bounties
name = "Bountiful bounties"
trait_type = STATION_TRAIT_POSITIVE
weight = 5
show_in_report = TRUE
report_message = "It seems collectors in this system are extra keen to on bounties, and will pay more to see their completion."
/datum/station_trait/bountiful_bounties/on_round_start()
SSeconomy.bounty_modifier *= 1.2
/datum/station_trait/strong_supply_lines
name = "Strong supply lines"
trait_type = STATION_TRAIT_POSITIVE
weight = 5
show_in_report = TRUE
report_message = "Prices are low in this system, BUY BUY BUY!"
blacklist = list(/datum/station_trait/distant_supply_lines)
/datum/station_trait/strong_supply_lines/on_round_start()
SSeconomy.pack_price_modifier *= 0.8
/datum/station_trait/scarves
name = "Scarves"
trait_type = STATION_TRAIT_POSITIVE
weight = 5
show_in_report = TRUE
var/list/scarves
/datum/station_trait/scarves/New()
. = ..()
report_message = pick(
"Nanotrasen is experimenting with seeing if neck warmth improves employee morale.",
"After Space Fashion Week, scarves are the hot new accessory.",
"Everyone was simultaneously a little bit cold when they packed to go to the station.",
"The station is definitely not under attack by neck grappling aliens masquerading as wool. Definitely not.",
"You all get free scarves. Don't ask why.",
"A shipment of scarves was delivered to the station.",
)
scarves = typesof(/obj/item/clothing/neck/scarf) + list(
/obj/item/clothing/neck/stripedredscarf,
/obj/item/clothing/neck/stripedgreenscarf,
/obj/item/clothing/neck/stripedbluescarf,
)
scarves -= /obj/item/clothing/neck/scarf/zomb // donator snowflake code--mayhaps we should make a glob for this or similar
RegisterSignal(SSdcs, COMSIG_GLOB_JOB_AFTER_SPAWN, .proc/on_job_after_spawn)
/datum/station_trait/scarves/proc/on_job_after_spawn(datum/source, datum/job/job, mob/living/spawned, client/player_client)
SIGNAL_HANDLER
var/scarf_type = pick(scarves)
spawned.equip_to_slot_or_del(new scarf_type(spawned), ITEM_SLOT_NECK)
/datum/station_trait/filled_maint
name = "Filled up maintenance"
trait_type = STATION_TRAIT_POSITIVE
weight = 5
show_in_report = TRUE
report_message = "Our workers accidentaly forgot more of their personal belongings in the maintenace areas."
blacklist = list(/datum/station_trait/empty_maint)
trait_to_give = STATION_TRAIT_FILLED_MAINT
// This station trait is checked when loot drops initialize, so it's too late
can_revert = FALSE
/datum/station_trait/quick_shuttle
name = "Quick Shuttle"
trait_type = STATION_TRAIT_POSITIVE
weight = 6
show_in_report = TRUE
report_message = "Due to proximity to our supply station, the cargo shuttle will have a quicker flight time to your cargo department."
blacklist = list(/datum/station_trait/slow_shuttle)
/datum/station_trait/quick_shuttle/on_round_start()
. = ..()
SSshuttle.supply.callTime *= 0.5
/datum/station_trait/deathrattle_department
name = "deathrattled department"
trait_type = STATION_TRAIT_POSITIVE
show_in_report = TRUE
trait_flags = STATION_TRAIT_ABSTRACT
blacklist = list(/datum/station_trait/deathrattle_all)
var/department_head
var/department_name = "department"
var/datum/deathrattle_group/deathrattle_group
/datum/station_trait/deathrattle_department/New()
. = ..()
deathrattle_group = new("[department_name] group")
blacklist += subtypesof(/datum/station_trait/deathrattle_department) - type //All but ourselves
report_message = "All members of [department_name] have received an implant to notify each other if one of them dies. This should help improve job-safety!"
RegisterSignal(SSdcs, COMSIG_GLOB_JOB_AFTER_SPAWN, .proc/on_job_after_spawn)
/datum/station_trait/deathrattle_department/proc/on_job_after_spawn(datum/source, datum/job/job, mob/living/spawned, client/player_client)
SIGNAL_HANDLER
if(department_head != job.title && !(src.department_head in job.department_head))
return
var/obj/item/implant/deathrattle/implant_to_give = new()
deathrattle_group.register(implant_to_give)
implant_to_give.implant(spawned, spawned, TRUE, TRUE)
/datum/station_trait/deathrattle_department/service
name = "Deathrattled Service"
trait_flags = NONE
weight = 1
department_head = "Head of Personnel"
department_name = "Service"
/datum/station_trait/deathrattle_department/cargo
name = "Deathrattled Cargo"
trait_flags = NONE
weight = 2
department_head = "Quartermaster"
department_name = "Cargo"
/datum/station_trait/deathrattle_department/engineering
name = "Deathrattled Engineering"
trait_flags = NONE
weight = 2
department_head = "Chief Engineer"
department_name = "Engineering"
/datum/station_trait/deathrattle_department/command
name = "Deathrattled Command"
trait_flags = NONE
weight = 1
department_head = "Captain"
department_name = "Command"
/datum/station_trait/deathrattle_department/science
name = "Deathrattled Science"
trait_flags = NONE
weight = 1
department_head = "Research Director"
department_name = "Science"
/datum/station_trait/deathrattle_department/security
name = "Deathrattled Security"
trait_flags = NONE
weight = 1
department_head = "Head of Security"
department_name = "Security"
/datum/station_trait/deathrattle_department/medical
name = "Deathrattled Medical"
trait_flags = NONE
weight = 1
department_head = "Chief Medical Officer"
department_name = "Medical"
/datum/station_trait/deathrattle_all
name = "Deathrattled Station"
trait_type = STATION_TRAIT_POSITIVE
show_in_report = TRUE
weight = 1
report_message = "All members of the station have received an implant to notify each other if one of them dies. This should help improve job-safety!"
var/datum/deathrattle_group/deathrattle_group
/datum/station_trait/deathrattle_all/New()
. = ..()
deathrattle_group = new("station group")
blacklist = subtypesof(/datum/station_trait/deathrattle_department)
RegisterSignal(SSdcs, COMSIG_GLOB_JOB_AFTER_SPAWN, .proc/on_job_after_spawn)
/datum/station_trait/deathrattle_all/proc/on_job_after_spawn(datum/source, datum/job/job, mob/living/spawned, client/player_client)
SIGNAL_HANDLER
var/obj/item/implant/deathrattle/implant_to_give = new()
deathrattle_group.register(implant_to_give)
implant_to_give.implant(spawned, spawned, TRUE, TRUE)
/datum/station_trait/wallets
name = "Wallets!"
trait_type = STATION_TRAIT_POSITIVE
show_in_report = TRUE
weight = 10
report_message = "It has become temporarily fashionable to use a wallet, so everyone on the station has been issued one."
/datum/station_trait/wallets/New()
. = ..()
RegisterSignal(SSdcs, COMSIG_GLOB_JOB_AFTER_SPAWN, .proc/on_job_after_spawn)
/datum/station_trait/wallets/proc/on_job_after_spawn(datum/source, datum/job/job, mob/living/living_mob, mob/M, joined_late)
SIGNAL_HANDLER
var/obj/item/card/id/id_card = living_mob.get_item_by_slot(ITEM_SLOT_ID)
if(!istype(id_card))
return
living_mob.temporarilyRemoveItemFromInventory(id_card, force=TRUE)
// "Doc, what's wrong with me?"
var/obj/item/storage/wallet/wallet = new(src)
// "You've got a wallet embedded in your chest."
wallet.add_fingerprint(living_mob, ignoregloves = TRUE)
living_mob.equip_to_slot_if_possible(wallet, ITEM_SLOT_ID)
id_card.forceMove(wallet)
// Put our filthy fingerprints all over the contents
for(var/obj/item/item in wallet)
item.add_fingerprint(living_mob, ignoregloves = TRUE)

View File

@@ -878,9 +878,9 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
nightshift_public_area = NIGHTSHIFT_AREA_RECREATION
sound_environment = SOUND_AREA_WOODFLOOR
// /area/service/bar/Initialize(mapload)
// . = ..()
// GLOB.bar_areas += src
/area/service/bar/Initialize(mapload)
. = ..()
GLOB.bar_areas += src
/area/service/bar/atrium
name = "Atrium"

View File

@@ -30,4 +30,4 @@
/datum/game_mode/extended/announced/send_intercept(report = 0)
if(flipseclevel) //CIT CHANGE - allows the sec level to be flipped roundstart
return ..()
priority_announce("Thanks to the tireless efforts of our security and intelligence divisions, there are currently no credible threats to [station_name()]. All station construction projects have been authorized. Have a secure shift!", "Security Report", "commandreport")
priority_announce("Thanks to the tireless efforts of our security and intelligence divisions, there are currently no credible threats to [station_name()]. All station construction projects have been authorized. Have a secure shift!", "Security Report", SSstation.announcer.get_rand_report_sound())

View File

@@ -278,7 +278,7 @@
/datum/game_mode/proc/send_intercept()
if(flipseclevel && !(config_tag == "extended"))//CIT CHANGE - lets the security level be flipped roundstart
priority_announce("Thanks to the tireless efforts of our security and intelligence divisions, there are currently no credible threats to [station_name()]. All station construction projects have been authorized. Have a secure shift!", "Security Report", "commandreport")
priority_announce("Thanks to the tireless efforts of our security and intelligence divisions, there are currently no credible threats to [station_name()]. All station construction projects have been authorized. Have a secure shift!", "Security Report", SSstation.announcer.get_rand_report_sound())
return
var/intercepttext = "<b><i>Central Command Status Summary</i></b><hr>"
intercepttext += "<b>Central Command has intercepted and partially decoded a Syndicate transmission with vital information regarding their movements. The following report outlines the most \

View File

@@ -244,7 +244,7 @@
nuke_request(reason, usr)
to_chat(usr, span_notice("Request sent."))
usr.log_message("has requested the nuclear codes from CentCom with reason \"[reason]\"", LOG_SAY)
priority_announce("The codes for the on-station nuclear self-destruct have been requested by [usr]. Confirmation or denial of this request will be sent shortly.", "Nuclear Self-Destruct Codes Requested", "commandreport")
priority_announce("The codes for the on-station nuclear self-destruct have been requested by [usr]. Confirmation or denial of this request will be sent shortly.", "Nuclear Self-Destruct Codes Requested", SSstation.announcer.get_rand_report_sound())
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE)
COOLDOWN_START(src, important_action_cooldown, IMPORTANT_ACTION_COOLDOWN)
if ("restoreBackupRoutingData")

View File

@@ -1356,6 +1356,7 @@
/obj/machinery/door/airlock/proc/remove_electrify()
secondsElectrified = NOT_ELECTRIFIED
unelectrify_timerid = null
diag_hud_set_electrified()
/obj/machinery/door/airlock/proc/set_electrified(seconds, mob/user)
secondsElectrified = seconds

View File

@@ -322,3 +322,9 @@
/obj/effect/particle_effect/smoke/transparent
opaque = FALSE
/proc/do_smoke(range=0, location=null, smoke_type=/obj/effect/particle_effect/smoke)
var/datum/effect_system/smoke_spread/smoke = new
smoke.effect_type = smoke_type
smoke.set_up(range, location)
smoke.start()

View File

@@ -528,3 +528,70 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
name = "portal exit"
icon_state = "portal_exit"
var/id
/obj/effect/landmark/start/hangover
name = "hangover spawn"
icon_state = "hangover_spawn"
/// A list of everything this hangover spawn created
var/list/debris = list()
/obj/effect/landmark/start/hangover/Initialize(mapload)
. = ..()
return INITIALIZE_HINT_LATELOAD
/obj/effect/landmark/start/hangover/Destroy()
debris = null
return ..()
/obj/effect/landmark/start/hangover/LateInitialize()
. = ..()
if(!HAS_TRAIT(SSstation, STATION_TRAIT_HANGOVER))
return
if(prob(60))
debris += new /obj/effect/decal/cleanable/vomit(get_turf(src))
if(prob(70))
var/bottle_count = rand(1, 3)
for(var/index in 1 to bottle_count)
var/turf/turf_to_spawn_on = get_step(src, pick(GLOB.alldirs))
if(!isopenturf(turf_to_spawn_on))
continue
var/dense_object = FALSE
for(var/atom/content in turf_to_spawn_on.contents)
if(content.density)
dense_object = TRUE
break
if(dense_object)
continue
debris += new /obj/item/reagent_containers/food/drinks/beer/almost_empty(turf_to_spawn_on)
///Spawns the mob with some drugginess/drunkeness, and some disgust.
/obj/effect/landmark/start/hangover/proc/make_hungover(mob/hangover_mob)
if(!iscarbon(hangover_mob))
return
var/mob/living/carbon/spawned_carbon = hangover_mob
spawned_carbon.set_resting(TRUE, silent = TRUE)
if(prob(50))
spawned_carbon.adjust_drugginess(rand(15, 20))
else
spawned_carbon.drunkenness += rand(15, 25)
spawned_carbon.adjust_disgust(rand(5, 55)) //How hungover are you?
if(spawned_carbon.head)
return
/obj/effect/landmark/start/hangover/JoinPlayerHere(mob/joining_mob, buckle)
. = ..()
make_hungover(joining_mob)
/obj/effect/landmark/start/hangover/closet
name = "hangover spawn closet"
icon_state = "hangover_spawn_closet"
/obj/effect/landmark/start/hangover/closet/JoinPlayerHere(mob/joining_mob, buckle)
make_hungover(joining_mob)
for(var/obj/structure/closet/closet in contents)
if(closet.opened)
continue
joining_mob.forceMove(closet)
return
return ..() //Call parent as fallback

View File

@@ -2,6 +2,7 @@
icon = 'icons/effects/landmarks_static.dmi'
icon_state = "random_loot"
layer = OBJ_LAYER
var/spawn_on_init = TRUE
var/spawn_on_turf = TRUE
var/lootcount = 1 //how many items will be spawned
var/lootdoubles = TRUE //if the same item can be spawned twice
@@ -10,10 +11,19 @@
/obj/effect/spawner/lootdrop/Initialize(mapload)
..()
if(should_spawn_on_init())
spawn_loot()
return INITIALIZE_HINT_QDEL
/obj/effect/spawner/lootdrop/proc/should_spawn_on_init()
return spawn_on_init
/obj/effect/spawner/lootdrop/proc/spawn_loot(lootcount_override)
var/lootcount = isnull(lootcount_override) ? src.lootcount : lootcount_override
if(loot && loot.len)
var/atom/A = spawn_on_turf ? get_turf(src) : loc
var/loot_spawned = 0
while((lootcount-loot_spawned) && loot.len)
while((lootcount-loot_spawned) > 0 && loot.len)
var/lootspawn = pickweight(loot)
if(!lootdoubles)
loot.Remove(lootspawn)
@@ -29,7 +39,6 @@
if (loot_spawned)
spawned_loot.pixel_x = spawned_loot.pixel_y = ((!(loot_spawned%2)*loot_spawned/2)*-1)+((loot_spawned%2)*(loot_spawned+1)/2*1)
loot_spawned++
return INITIALIZE_HINT_QDEL
/obj/effect/spawner/lootdrop/bedsheet
icon = 'icons/obj/bedsheets.dmi'
@@ -162,6 +171,15 @@
loot = GLOB.maintenance_loot
. = ..()
/obj/effect/spawner/lootdrop/maintenance/spawn_loot(lootcount_override)
if(isnull(lootcount_override))
if(HAS_TRAIT(SSstation, STATION_TRAIT_FILLED_MAINT))
lootcount_override = round(lootcount * 1.5)
else if(HAS_TRAIT(SSstation, STATION_TRAIT_EMPTY_MAINT))
lootcount_override = round(lootcount * 0.5)
. = ..()
/obj/effect/spawner/lootdrop/glowstick
name = "random colored glowstick"
icon = 'icons/obj/lighting.dmi'

View File

@@ -561,4 +561,4 @@
singular_name = "catwalk floor tile"
desc = "Flooring that shows its contents underneath. Engineers love it!"
icon_state = "catwalk_tile"
turf_type = /turf/open/floor/plating/catwalk_floor
turf_type = /turf/open/floor/catwalk_floor

View File

@@ -121,6 +121,10 @@
else
new /obj/item/tank/internals/plasmaman/belt(src)
if(HAS_TRAIT(SSstation, STATION_TRAIT_PREMIUM_INTERNALS))
new /obj/item/flashlight/flare(src)
new /obj/item/radio/off(src)
/obj/item/storage/box/survival/radio/PopulateContents()
..() // we want the survival stuff too.
new /obj/item/radio/off(src)
@@ -773,6 +777,10 @@
else
new /obj/item/tank/internals/plasmaman/belt(src)
if(HAS_TRAIT(SSstation, STATION_TRAIT_PREMIUM_INTERNALS))
new /obj/item/flashlight/flare(src)
new /obj/item/radio/off(src)
/obj/item/storage/box/rubbershot
name = "box of rubber shots"
desc = "A box full of rubber shots, designed for riot shotguns."

View File

@@ -5,7 +5,7 @@
* you can crowbar it to interact with the underneath stuff without destroying the tile...
* unless you want to!
*/
/turf/open/floor/plating/catwalk_floor
/turf/open/floor/catwalk_floor
icon = 'icons/turf/floors/catwalk_plating.dmi'
icon_state = "catwalk_below"
floor_tile = /obj/item/stack/tile/catwalk
@@ -16,29 +16,35 @@
barefootstep = FOOTSTEP_CATWALK
clawfootstep = FOOTSTEP_CATWALK
heavyfootstep = FOOTSTEP_CATWALK
intact = FALSE
var/covered = TRUE
/turf/open/floor/plating/catwalk_floor/Initialize(mapload)
/turf/open/floor/catwalk_floor/Initialize(mapload)
. = ..()
layer = CATWALK_LAYER
update_icon(UPDATE_OVERLAYS)
/turf/open/floor/plating/catwalk_floor/update_overlays()
/turf/open/floor/catwalk_floor/update_overlays()
. = ..()
var/static/catwalk_overlay
var/static/image/catwalk_overlay
if(isnull(catwalk_overlay))
catwalk_overlay = iconstate2appearance(icon, "catwalk_above")
catwalk_overlay = new()
catwalk_overlay.icon = icon
catwalk_overlay.icon_state = "catwalk_above"
catwalk_overlay.plane = GAME_PLANE
catwalk_overlay.layer = CATWALK_LAYER
catwalk_overlay = catwalk_overlay.appearance
if(covered)
. += catwalk_overlay
/turf/open/floor/plating/catwalk_floor/screwdriver_act(mob/living/user, obj/item/tool)
/turf/open/floor/catwalk_floor/screwdriver_act(mob/living/user, obj/item/tool)
. = ..()
covered = !covered
user.balloon_alert(user, "[!covered ? "cover removed" : "cover added"]")
update_icon(UPDATE_OVERLAYS)
/turf/open/floor/plating/catwalk_floor/pry_tile(obj/item/crowbar, mob/user, silent)
/turf/open/floor/catwalk_floor/crowbar_act(mob/user, obj/item/I)
if(covered)
user.balloon_alert(user, "remove cover first!")
return FALSE
. = ..()
return pry_tile(I, user)

View File

@@ -623,7 +623,7 @@
SSticker.start_immediately = FALSE
SSticker.SetTimeLeft(1800)
to_chat(world, "<b>The game will start in 180 seconds.</b>")
SEND_SOUND(world, sound(get_announcer_sound("attention")))
SEND_SOUND(world, sound(SSstation.announcer.get_rand_alert_sound()))
message_admins("<font color='blue'>[usr.key] has cancelled immediate game start. Game will start in 180 seconds.</font>")
log_admin("[usr.key] has cancelled immediate game start.")
else
@@ -706,7 +706,7 @@
log_admin("[key_name(usr)] delayed the round start.")
else
to_chat(world, "<b>The game will start in [DisplayTimeText(newtime)].</b>", confidential = TRUE)
SEND_SOUND(world, sound(get_announcer_sound("attention")))
SEND_SOUND(world, sound(SSstation.announcer.get_rand_alert_sound()))
log_admin("[key_name(usr)] set the pre-game delay to [DisplayTimeText(newtime)].")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Delay Game Start") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

View File

@@ -75,6 +75,7 @@ GLOBAL_PROTECT(admin_verbs_admin)
/client/proc/toggle_combo_hud, // toggle display of the combination pizza antag and taco sci/med/eng hud
/client/proc/toggle_AI_interact, /*toggle admin ability to interact with machines as an AI*/
/datum/admins/proc/open_shuttlepanel, /* Opens shuttle manipulator UI */
/datum/admins/proc/station_traits_panel, /* Opens station traits UI */
/client/proc/deadchat,
/client/proc/toggleprayers,
// /client/proc/toggle_prayer_sound,

View File

@@ -560,7 +560,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
var/announce_command_report = TRUE
switch(confirm)
if("Yes")
priority_announce(input, null, "commandreport")
priority_announce(input, null, SSstation.announcer.get_rand_report_sound())
announce_command_report = FALSE
if("Cancel")
return

View File

@@ -352,7 +352,7 @@
if(is_station_level(W.z) && !istype(get_area(W), /area/command) && !istype(get_area(W), /area/commons) && !istype(get_area(W), /area/service) && !istype(get_area(W), /area/command/heads_quarters) && !istype(get_area(W), /area/security/prison))
W.req_access = list()
message_admins("[key_name_admin(holder)] activated Egalitarian Station mode")
priority_announce("CentCom airlock control override activated. Please take this time to get acquainted with your coworkers.", null, "commandreport")
priority_announce("CentCom airlock control override activated. Please take this time to get acquainted with your coworkers.", null, SSstation.announcer.get_rand_report_sound())
if("ancap")
if(!is_funmin)
return
@@ -360,9 +360,9 @@
SSeconomy.full_ancap = !SSeconomy.full_ancap
message_admins("[key_name_admin(holder)] toggled Anarcho-capitalist mode")
if(SSeconomy.full_ancap)
priority_announce("The NAP is now in full effect.", null, "commandreport")
priority_announce("The NAP is now in full effect.", null, SSstation.announcer.get_rand_report_sound())
else
priority_announce("The NAP has been revoked.", null, "commandreport")
priority_announce("The NAP has been revoked.", null, SSstation.announcer.get_rand_report_sound())
if("blackout")
if(!is_funmin)
return
@@ -528,7 +528,7 @@
message_admins("[key_name_admin(holder)] made everything kawaii.")
for(var/i in GLOB.human_list)
var/mob/living/carbon/human/H = i
SEND_SOUND(H, sound(get_announcer_sound("animes")))
SEND_SOUND(H, sound(SSstation.announcer.event_sounds[ANNOUNCER_ANIMES]))
if(H.dna.species.id == "human")
if(H.dna.features["tail_human"] == "None" || H.dna.features["ears"] == "None")

View File

@@ -53,7 +53,7 @@ GLOBAL_VAR_INIT(war_declared, FALSE)
if(!check_allowed(user) || !war_declaration)
return
priority_announce(war_declaration, title = "Declaration of War", sound = 'sound/machines/alarm.ogg')
priority_announce(war_declaration, title = "Declaration of War", sound = 'sound/machines/alarm.ogg', has_important_message = TRUE)
to_chat(user, "You've attracted the attention of powerful forces within the syndicate. A bonus bundle of telecrystals has been granted to your team. Great things await you if you complete the mission.")

View File

@@ -135,12 +135,13 @@
id = GAS_NITRIC
specific_heat = 20
name = "Nitric oxide"
flags = GAS_FLAG_DANGEROUS
odor = "sharp sweetness"
odor_strength = 1
fusion_power = 15
enthalpy = 91290
heat_resistance = 2
powermix = -1
heat_penalty = -1
/datum/gas/nitryl
id = GAS_NITRYL

View File

@@ -729,11 +729,11 @@
/datum/gas_reaction/nitric_oxide/react(datum/gas_mixture/air, datum/holder)
var/nitric = air.get_moles(GAS_NITRIC)
var/oxygen = air.get_moles(GAS_O2)
var/max_amount = max(nitric / 10, MINIMUM_MOLE_COUNT)
var/enthalpy = air.return_temperature() * (air.heat_capacity() + R_IDEAL_GAS_EQUATION * air.total_moles());
var/max_amount = max(nitric / 8, MINIMUM_MOLE_COUNT)
var/enthalpy = air.return_temperature() * (air.heat_capacity() + R_IDEAL_GAS_EQUATION * air.total_moles())
var/list/enthalpies = GLOB.gas_data.enthalpies
if(oxygen > MINIMUM_MOLE_COUNT)
var/reaction_amount = min(max_amount, oxygen)
var/reaction_amount = min(max_amount, oxygen)/4
air.adjust_moles(GAS_NITRIC, -reaction_amount*2)
air.adjust_moles(GAS_O2, -reaction_amount)
air.adjust_moles(GAS_NITRYL, reaction_amount*2)

View File

@@ -23,7 +23,7 @@ GLOBAL_LIST_EMPTY(bounties_list)
if(can_claim())
var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
if(D)
D.adjust_money(reward)
D.adjust_money(reward * SSeconomy.bounty_modifier)
claimed = TRUE
// If an item sent in the cargo shuttle can satisfy the bounty.

View File

@@ -99,7 +99,7 @@
for(var/datum/supply_order/SO in SSshuttle.shoppinglist)
data["cart"] += list(list(
"object" = SO.pack.name,
"cost" = SO.pack.cost,
"cost" = SO.pack.get_cost(),
"id" = SO.id,
"orderer" = SO.orderer,
"paid" = !isnull(SO.paying_account) //paid by requester
@@ -109,7 +109,7 @@
for(var/datum/supply_order/SO in SSshuttle.requestlist)
data["requests"] += list(list(
"object" = SO.pack.name,
"cost" = SO.pack.cost,
"cost" = SO.pack.get_cost(),
"orderer" = SO.orderer,
"reason" = SO.reason,
"id" = SO.id
@@ -132,7 +132,7 @@
continue
data["supplies"][P.group]["packs"] += list(list(
"name" = P.name,
"cost" = P.cost,
"cost" = P.get_cost(),
"id" = pack,
"desc" = P.desc || P.name, // If there is a description, use it. Otherwise use the pack's name.
"goody" = P.goody,

View File

@@ -332,7 +332,7 @@
/datum/export/weapon/l6sawammo
cost = 60
unit_name = "L6 SAW ammo box"
export_types = list(/obj/item/ammo_box/magazine/mm195x129)
export_types = list(/obj/item/ammo_box/magazine/mm712x82)
include_subtypes = TRUE
/datum/export/weapon/rocket

View File

@@ -81,7 +81,7 @@
continue // i'd be right happy to
meme_pack_data[P.group]["packs"] += list(list(
"name" = P.name,
"cost" = P.cost,
"cost" = P.get_cost(),
"id" = pack,
"desc" = P.desc || P.name // If there is a description, use it. Otherwise use the pack's name.
))
@@ -174,7 +174,7 @@
if(D)
points_to_check = D.account_balance
if(!(obj_flags & EMAGGED))
if(SO.pack.cost <= points_to_check)
if(SO.pack.get_cost() <= points_to_check)
var/LZ
if (istype(beacon) && usingBeacon)//prioritize beacons over landing in cargobay
LZ = get_turf(beacon)
@@ -191,13 +191,13 @@
CHECK_TICK
if(empty_turfs && empty_turfs.len)
LZ = pick(empty_turfs)
if (SO.pack.cost <= points_to_check && LZ)//we need to call the cost check again because of the CHECK_TICK call
D.adjust_money(-SO.pack.cost)
if (SO.pack.get_cost() <= points_to_check && LZ)//we need to call the cost check again because of the CHECK_TICK call
D.adjust_money(-SO.pack.get_cost())
new /obj/effect/pod_landingzone(LZ, podType, SO)
. = TRUE
update_icon()
else
if(SO.pack.cost * (0.72*MAX_EMAG_ROCKETS) <= points_to_check) // bulk discount :^)
if(SO.pack.get_cost() * (0.72*MAX_EMAG_ROCKETS) <= points_to_check) // bulk discount :^)
landingzone = GLOB.areas_by_type[pick(GLOB.the_station_areas)] //override default landing zone
for(var/turf/open/floor/T in landingzone.contents)
if(is_blocked_turf(T))
@@ -205,7 +205,7 @@
LAZYADD(empty_turfs, T)
CHECK_TICK
if(empty_turfs && empty_turfs.len)
D.adjust_money(-(SO.pack.cost * (0.72*MAX_EMAG_ROCKETS)))
D.adjust_money(-(SO.pack.get_cost() * (0.72*MAX_EMAG_ROCKETS)))
SO.generateRequisition(get_turf(src))
for(var/i in 1 to MAX_EMAG_ROCKETS)

View File

@@ -38,6 +38,9 @@
fill(C)
return C
/datum/supply_pack/proc/get_cost()
return cost * SSeconomy.pack_price_modifier
/datum/supply_pack/proc/fill(obj/structure/closet/crate/C)
if (admin_spawned)
for(var/item in contains)

View File

@@ -233,6 +233,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/screenshake = 100
var/damagescreenshake = 2
var/recoil_screenshake = 100
var/arousable = TRUE
var/autostand = TRUE
var/auto_ooc = FALSE
@@ -907,6 +908,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<b>Screen Shake:</b> <a href='?_src_=prefs;preference=screenshake'>[(screenshake==100) ? "Full" : ((screenshake==0) ? "None" : "[screenshake]")]</a><br>"
if (user && user.client && !user.client.prefs.screenshake==0)
dat += "<b>Damage Screen Shake:</b> <a href='?_src_=prefs;preference=damagescreenshake'>[(damagescreenshake==1) ? "On" : ((damagescreenshake==0) ? "Off" : "Only when down")]</a><br>"
dat += "<b>Recoil Screen Push:</b> <a href='?_src_=prefs;preference=recoil_screenshake'>[(recoil_screenshake==100) ? "Full" : ((recoil_screenshake==0) ? "None" : "[screenshake]")]</a><br>"
var/p_chaos
if (!preferred_chaos)
p_chaos = "No preference"
@@ -2782,7 +2784,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("no_tetris_storage")
no_tetris_storage = !no_tetris_storage
if ("screenshake")
var/desiredshake = input(user, "Set the amount of screenshake you want. \n(0 = disabled, 100 = full, 200 = maximum.)", "Character Preference", screenshake) as null|num
var/desiredshake = input(user, "Set the amount of screenshake you want. \n(0 = disabled, 100 = full, no maximum (at your own risk).)", "Character Preference", screenshake) as null|num
if (!isnull(desiredshake))
screenshake = desiredshake
if("damagescreenshake")
@@ -2795,6 +2797,10 @@ GLOBAL_LIST_EMPTY(preferences_datums)
damagescreenshake = 0
else
damagescreenshake = 1
if ("recoil_screenshake")
var/desiredshake = input(user, "Set the amount of recoil screenshake/push you want. \n(0 = disabled, 100 = full, no maximum (at your own risk).)", "Character Preference", screenshake) as null|num
if (!isnull(desiredshake))
recoil_screenshake = desiredshake
if("nameless")
nameless = !nameless
//END CITADEL EDIT

View File

@@ -213,6 +213,7 @@
heat_protection = FEET|LEGS
max_heat_protection_temperature = SHOES_MAX_TEMP_PROTECT
resistance_flags = FIRE_PROOF
lace_time = 10 SECONDS
/obj/item/clothing/shoes/cult
name = "\improper Nar'Sien invoker boots"

View File

@@ -6,6 +6,13 @@
earliest_start = 10 MINUTES
max_occurrences = 6
/datum/round_event_control/carp_migration/New()
. = ..()
if(HAS_TRAIT(SSstation, STATION_TRAIT_CARP_INFESTATION))
weight *= 3
max_occurrences *= 2
earliest_start *= 0.5
/datum/round_event/carp_migration
announceWhen = 3
startWhen = 50

View File

@@ -37,7 +37,7 @@
// if(PIRATES_DUTCHMAN)
// ship_name = "Flying Dutchman"
priority_announce("Incoming subspace communication. Secure channel opened at all communication consoles.", "Incoming Message", "commandreport")
priority_announce("Incoming subspace communication. Secure channel opened at all communication consoles.", "Incoming Message", SSstation.announcer.get_rand_report_sound())
var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
if(D)
payoff = max(payoff_min, FLOOR(D.account_balance * 0.80, 1000))

View File

@@ -9,7 +9,7 @@
fakeable = FALSE
/datum/round_event/untied_shoes/start()
var/iterations = 1
var/budget = rand(5 SECONDS,20 SECONDS)
for(var/mob/living/carbon/C in shuffle(GLOB.alive_mob_list))
if(!C.client)
continue
@@ -17,12 +17,15 @@
continue
if (HAS_TRAIT(C,TRAIT_EXEMPT_HEALTH_EVENTS))
continue
if(!C.shoes || !C.shoes.can_be_tied || C.shoes.tied != SHOES_TIED)
if(!C.shoes || !C.shoes.can_be_tied || C.shoes.tied != SHOES_TIED || C.shoes.lace_time > budget)
continue
if(!is_station_level(C.z) && prob(50))
continue
if(prob(5))
C.shoes.adjust_laces(SHOES_KNOTTED)
budget -= C.shoes.lace_time // doubling up on the budget removal on purpose
else
C.shoes.adjust_laces(SHOES_UNTIED)
iterations++
if(prob(100/iterations))
budget -= C.shoes.lace_time
if(budget < 5 SECONDS)
return

View File

@@ -888,7 +888,7 @@ GLOBAL_LIST_INIT(hallucination_list, list(
if("blob alert")
to_chat(target, "<h1 class='alert'>Biohazard Alert</h1>")
to_chat(target, "<br><br><span class='alert'>Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.</span><br><br>")
SEND_SOUND(target, get_announcer_sound("outbreak5"))
SEND_SOUND(target, SSstation.announcer.event_sounds[ANNOUNCER_OUTBREAK5])
if("ratvar")
target.playsound_local(target, 'sound/machines/clockcult/ark_deathrattle.ogg', 50, FALSE, pressure_affected = FALSE)
target.playsound_local(target, 'sound/effects/clockcult_gateway_disrupted.ogg', 50, FALSE, pressure_affected = FALSE)
@@ -897,15 +897,15 @@ GLOBAL_LIST_INIT(hallucination_list, list(
if("shuttle dock")
to_chat(target, "<h1 class='alert'>Priority Announcement</h1>")
to_chat(target, "<br><br><span class='alert'>The Emergency Shuttle has docked with the station. You have 3 minutes to board the Emergency Shuttle.</span><br><br>")
SEND_SOUND(target, get_announcer_sound("shuttledock"))
SEND_SOUND(target, SSstation.announcer.event_sounds[ANNOUNCER_SHUTTLEDOCK])
if("malf ai") //AI is doomsdaying!
to_chat(target, "<h1 class='alert'>Anomaly Alert</h1>")
to_chat(target, "<br><br><span class='alert'>Hostile runtimes detected in all station systems, please deactivate your AI to prevent possible damage to its morality core.</span><br><br>")
SEND_SOUND(target, get_announcer_sound("aimalf"))
SEND_SOUND(target, SSstation.announcer.event_sounds[ANNOUNCER_AIMALF])
if("meteors") //Meteors inbound!
to_chat(target, "<h1 class='alert'>Meteor Alert</h1>")
to_chat(target, "<br><br><span class='alert'>[generateMeteorString(rand(60, 90),FALSE,pick(GLOB.cardinals))]</span><br><br>")
SEND_SOUND(target, get_announcer_sound("meteors"))
SEND_SOUND(target, SSstation.announcer.event_sounds[ANNOUNCER_METEORS])
if("supermatter")
SEND_SOUND(target, 'sound/magic/charge.ogg')
to_chat(target, "<span class='boldannounce'>You feel reality distort for a moment...</span>")

View File

@@ -347,6 +347,9 @@
foodtype = GRAIN | ALCOHOL
custom_price = PRICE_PRETTY_CHEAP
/obj/item/reagent_containers/food/drinks/beer/almost_empty
list_reagents = list(/datum/reagent/consumable/ethanol/beer = 1)
/obj/item/reagent_containers/food/drinks/beer/light
name = "Carp Lite"
desc = "Brewed with \"Pure Ice Asteroid Spring Water\"."

View File

@@ -66,6 +66,9 @@
/// Should this job be allowed to be picked for the bureaucratic error event?
var/allow_bureaucratic_error = TRUE
///Is this job affected by weird spawns like the ones from station traits
var/random_spawns_possible = TRUE
var/display_order = JOB_DISPLAY_ORDER_DEFAULT
//If a job complies with dresscodes, loadout items will not be equipped instead of the job's outfit, instead placing the items into the player's backpack.
@@ -109,14 +112,16 @@
//Only override this proc
//H is usually a human unless an /equip override transformed it
/datum/job/proc/after_spawn(mob/living/H, mob/M, latejoin = FALSE)
/datum/job/proc/after_spawn(mob/living/spawned, client/player_client, latejoin = FALSE)
SHOULD_CALL_PARENT(TRUE)
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_JOB_AFTER_SPAWN, src, spawned, player_client)
//do actions on H but send messages to M as the key may not have been transferred_yet
if(mind_traits)
for(var/t in mind_traits)
ADD_TRAIT(H.mind, t, JOB_TRAIT)
ADD_TRAIT(spawned.mind, t, JOB_TRAIT)
if(/datum/quirk/paraplegic in blacklisted_quirks)
H.regenerate_limbs() //if you can't be a paraplegic, attempt to regenerate limbs to stop amputated limb selection
H.set_resting(FALSE, TRUE) //they probably shouldn't be on the floor because they had no legs then suddenly had legs
spawned.regenerate_limbs() //if you can't be a paraplegic, attempt to regenerate limbs to stop amputated limb selection
spawned.set_resting(FALSE, TRUE) //they probably shouldn't be on the floor because they had no legs then suddenly had legs
/datum/job/proc/announce(mob/living/carbon/human/H)
if(head_announce)
@@ -323,3 +328,66 @@
if(CONFIG_GET(flag/security_has_maint_access))
return list(ACCESS_MAINT_TUNNELS)
return list()
/// Handles finding and picking a valid roundstart effect landmark spawn point, in case no uncommon different spawning events occur.
/datum/job/proc/get_default_roundstart_spawn_point()
for(var/obj/effect/landmark/start/spawn_point as anything in GLOB.start_landmarks_list)
if(spawn_point.name != title)
continue
. = spawn_point
if(spawn_point.used) //so we can revert to spawning them on top of eachother if something goes wrong
continue
spawn_point.used = TRUE
break
if(!.)
log_world("Couldn't find a round start spawn point for [title]")
/// Finds a valid latejoin spawn point, checking for events and special conditions.
/datum/job/proc/get_latejoin_spawn_point()
if(length(GLOB.jobspawn_overrides[title])) //We're doing something special today.
return pick(GLOB.jobspawn_overrides[title])
if(length(SSjob.latejoin_trackers))
return pick(SSjob.latejoin_trackers)
return SSjob.get_last_resort_spawn_points()
/// Returns an atom where the mob should spawn in.
/datum/job/proc/get_roundstart_spawn_point(var/mob/M)
if(random_spawns_possible)
if(HAS_TRAIT(SSstation, STATION_TRAIT_LATE_ARRIVALS))
return get_latejoin_spawn_point()
if(HAS_TRAIT(SSstation, STATION_TRAIT_RANDOM_ARRIVALS))
return get_safe_random_station_turf(typesof(/area/hallway)) || get_latejoin_spawn_point()
if(HAS_TRAIT(SSstation, STATION_TRAIT_HANGOVER))
if(!M || (!HAS_TRAIT(M, TRAIT_TOXIC_ALCOHOL) && !(HAS_TRAIT(M, TRAIT_ALCOHOL_TOLERANCE) && prob(70))))
var/obj/effect/landmark/start/hangover_spawn_point
for(var/obj/effect/landmark/start/hangover/hangover_landmark in GLOB.start_landmarks_list)
hangover_spawn_point = hangover_landmark
if(hangover_landmark.used) //so we can revert to spawning them on top of eachother if something goes wrong
continue
hangover_landmark.used = TRUE
break
return hangover_spawn_point || get_latejoin_spawn_point()
if(length(GLOB.jobspawn_overrides[title]))
return pick(GLOB.jobspawn_overrides[title])
var/obj/effect/landmark/start/spawn_point = get_default_roundstart_spawn_point()
if(!spawn_point) //if there isn't a spawnpoint send them to latejoin, if there's no latejoin go yell at your mapper
return get_latejoin_spawn_point()
return spawn_point
/**
* Called after a successful roundstart spawn.
* Client is not yet in the mob.
* This happens after after_spawn()
*/
/datum/job/proc/after_roundstart_spawn(mob/living/spawning, client/player_client)
SHOULD_CALL_PARENT(TRUE)
/**
* Called after a successful latejoin spawn.
* Client is in the mob.
* This happens after after_spawn()
*/
/datum/job/proc/after_latejoin_spawn(mob/living/spawning)
SHOULD_CALL_PARENT(TRUE)
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_JOB_AFTER_LATEJOIN_SPAWN, src, spawning)

View File

@@ -15,6 +15,7 @@
exp_type_department = EXP_TYPE_SILICON
display_order = JOB_DISPLAY_ORDER_AI
allow_bureaucratic_error = FALSE
random_spawns_possible = FALSE
var/do_special_check = TRUE
threat = 5
considered_combat_role = TRUE

View File

@@ -49,6 +49,11 @@
chameleon_extras = /obj/item/stamp/clown
/datum/outfit/job/clown/pre_equip(mob/living/carbon/human/H, visualsOnly)
. = ..()
if(HAS_TRAIT(SSstation, STATION_TRAIT_BANANIUM_SHIPMENTS))
backpack_contents[/obj/item/stack/sheet/mineral/bananium] = 5
/datum/outfit/job/clown/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
..()
if(visualsOnly)

View File

@@ -12,7 +12,7 @@
exp_requirements = 120
exp_type = EXP_TYPE_CREW
considered_combat_role = TRUE
random_spawns_possible = FALSE
starting_modifiers = list(/datum/skill_modifier/job/level/wiring/basic)
display_order = JOB_DISPLAY_ORDER_CYBORG
@@ -22,8 +22,11 @@
CRASH("dynamic preview is unsupported")
return H.Robotize(FALSE, latejoin)
/datum/job/cyborg/after_spawn(mob/living/silicon/robot/R, mob/M)
R.updatename(M.client)
/datum/job/cyborg/after_spawn(mob/living/silicon/robot/R, client/player_client)
. = ..()
if(!istype(R))
return
R.updatename(player_client)
R.gender = NEUTER
/datum/job/cyborg/radio_help_message(mob/M)

View File

@@ -7,13 +7,18 @@
total_positions = 0
spawn_positions = 0
supervisors = "the security team"
random_spawns_possible = FALSE
outfit = /datum/outfit/job/prisoner
plasma_outfit = /datum/outfit/plasmaman/prisoner
display_order = JOB_DISPLAY_ORDER_PRISONER
/datum/job/prisoner/get_latejoin_spawn_point()
return get_roundstart_spawn_point()
/datum/job/prisoner/after_spawn(mob/living/carbon/human/H, mob/M)
. = ..()
var/list/policies = CONFIG_GET(keyed_list/policy)
var/policy = policies[POLICYCONFIG_JOB_PRISONER]
if(policy)

View File

@@ -30,8 +30,6 @@
var/maptype = MAP_TYPE_STATION //This should be used to adjust ingame behavior depending on the specific type of map being played. For instance, if an overmap were added, it'd be appropriate for it to only generate with a MAP_TYPE_SHIP
var/announcertype = "standard" //Determines the announcer the map uses. standard uses the default announcer, classic, but has a random chance to use other similarly-themed announcers, like medibot
var/allow_custom_shuttles = TRUE
var/shuttles = list(
"cargo" = "cargo_box",
@@ -178,9 +176,6 @@
if ("maptype" in json)
maptype = json["maptype"]
if ("announcertype" in json)
announcertype = json["announcertype"]
if ("orientation" in json)
orientation = json["orientation"]
if(!(orientation in GLOB.cardinals))
@@ -277,7 +272,6 @@
jsonlist["year_offset"] = year_offset
jsonlist["minetype"] = minetype
jsonlist["maptype"] = maptype
jsonlist["announcertype"] = announcertype
jsonlist["orientation"] = orientation
jsonlist["allow_custom_shuttles"] = allow_custom_shuttles
jsonlist["job_whitelist"] = job_whitelist

View File

@@ -19,6 +19,7 @@
attack_verb = list("smashed", "crushed", "cleaved", "chopped", "pulped")
sharpness = SHARP_EDGED
actions_types = list(/datum/action/item_action/toggle_light)
obj_flags = UNIQUE_RENAME
var/list/trophies = list()
var/charged = TRUE
var/charge_time = 15

View File

@@ -468,12 +468,14 @@
SSjob.AssignRole(src, rank, 1)
var/mob/living/character = create_character(TRUE) //creates the human and transfers vars and mind
var/datum/job/job = SSjob.GetJob(rank)
var/equip = SSjob.EquipRank(character, rank, TRUE)
job.after_latejoin_spawn(character)
if(isliving(equip)) //Borgs get borged in the equip, so we need to make sure we handle the new mob.
character = equip
var/datum/job/job = SSjob.GetJob(rank)
if(job && !job.override_latejoin_spawn(character))
SSjob.SendToLateJoin(character)
if(!arrivals_docked)

View File

@@ -832,15 +832,15 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/left_state = DEFAULT_LEFT_EYE_STATE
var/right_state = DEFAULT_RIGHT_EYE_STATE
if(eye_type in GLOB.eye_types)
left_state = eye_type + "_left_eye"
right_state = eye_type + "_right_eye"
left_state = "[eye_type]_left_eye"
right_state = "[eye_type]_right_eye"
var/mutable_appearance/left_eye = mutable_appearance('icons/mob/eyes.dmi', left_state, -BODY_LAYER)
var/mutable_appearance/right_eye = mutable_appearance('icons/mob/eyes.dmi', right_state, -BODY_LAYER)
left_eye.category = "HEAD"
right_eye.category = "HEAD"
if((EYECOLOR in species_traits) && has_eyes)
left_eye.color = "#" + H.left_eye_color
right_eye.color = "#" + H.right_eye_color
left_eye.color = "#[H.left_eye_color]"
right_eye.color = "#[H.right_eye_color]"
if(OFFSET_EYES in offset_features)
left_eye.pixel_x += offset_features[OFFSET_EYES][1]
left_eye.pixel_y += offset_features[OFFSET_EYES][2]

View File

@@ -366,6 +366,8 @@ GLOBAL_LIST_INIT(strippable_corgi_items, create_strippable_list(list(
return valid
/mob/living/simple_animal/pet/dog/corgi/proc/update_corgi_fluff()
// First, change back to defaults
name = real_name

View File

@@ -436,7 +436,7 @@ Difficulty: Very Hard
H.dropItemToGround(W)
var/datum/job/clown/C = new /datum/job/clown()
C.equip(H)
C.after_spawn(H, H, TRUE)
C.after_spawn(H, H.client, TRUE)
qdel(C)
affected_targets.Add(H)

File diff suppressed because one or more lines are too long

View File

@@ -250,7 +250,17 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
animate(pixel_x=rand(min,max), pixel_y=rand(min,max), time=1)
animate(pixel_x=oldx, pixel_y=oldy, time=1)
/proc/directional_recoil(mob/M, strength=1, angle = 0)
if(!M || !M.client)
return
var/client/C = M.client
var/client_screenshake = (C.prefs.recoil_screenshake * 0.01)
strength *= client_screenshake
var/recoil_x = -sin(angle)*4*strength + rand(-strength, strength)
var/recoil_y = -cos(angle)*4*strength + rand(-strength, strength)
animate(C, pixel_x=recoil_x, pixel_y=recoil_y, time=1, easing=SINE_EASING|EASE_OUT, flags=ANIMATION_PARALLEL|ANIMATION_RELATIVE)
animate(pixel_x=0, pixel_y=0, time=3, easing=SINE_EASING|EASE_IN) // according to bhjin this works on more recent byond versions
// if you havent updated uuh sucks to be you then
/proc/findname(msg)
if(!istext(msg))

View File

@@ -104,7 +104,7 @@
continue
data["supplies"][P.group]["packs"] += list(list(
"name" = P.name,
"cost" = P.cost,
"cost" = P.get_cost(),
"id" = pack,
"desc" = P.desc || P.name, // If there is a description, use it. Otherwise use the pack's name.
"goody" = P.goody,
@@ -131,7 +131,7 @@
for(var/datum/supply_order/SO in SSshuttle.shoppinglist)
data["cart"] += list(list(
"object" = SO.pack.name,
"cost" = SO.pack.cost,
"cost" = SO.pack.get_cost(),
"id" = SO.id,
"orderer" = SO.orderer,
"paid" = !isnull(SO.paying_account) //paid by requester
@@ -141,7 +141,7 @@
for(var/datum/supply_order/SO in SSshuttle.requestlist)
data["requests"] += list(list(
"object" = SO.pack.name,
"cost" = SO.pack.cost,
"cost" = SO.pack.get_cost(),
"orderer" = SO.orderer,
"reason" = SO.reason,
"id" = SO.id

View File

@@ -15,40 +15,29 @@
/// Radio connection datum used by signalers.
var/datum/radio_frequency/radio_connection
/datum/computer_file/program/signaler/run_program(mob/living/user)
. = ..()
if (!.)
return
if(!computer?.get_modular_computer_part(MC_SIGNALER)) //Giving a clue to users why the program is spitting out zeros.
to_chat(user, span_warning("\The [computer] flashes an error: \"hardware\\signal_hardware\\startup.bin -- file not found\"."))
/datum/computer_file/program/signaler/New()
set_frequency(signal_frequency)
return ..()
/datum/computer_file/program/signaler/ui_data(mob/user)
var/list/data = get_header_data()
var/obj/item/computer_hardware/radio_card/sensor = computer?.get_modular_computer_part(MC_SIGNALER)
if(sensor?.check_functionality())
data["frequency"] = signal_frequency
data["code"] = signal_code
data["minFrequency"] = MIN_FREE_FREQ
data["maxFrequency"] = MAX_FREE_FREQ
data["frequency"] = signal_frequency
data["code"] = signal_code
data["minFrequency"] = MIN_FREE_FREQ
data["maxFrequency"] = MAX_FREE_FREQ
return data
/datum/computer_file/program/signaler/ui_act(action, list/params)
. = ..()
if(.)
return
var/obj/item/computer_hardware/radio_card/sensor = computer?.get_modular_computer_part(MC_SIGNALER)
if(!(sensor?.check_functionality()))
playsound(src, 'sound/machines/scanbuzz.ogg', 100, FALSE)
return
switch(action)
if("signal")
INVOKE_ASYNC(src, .proc/signal)
. = TRUE
if("freq")
signal_frequency = unformat_frequency(params["freq"])
signal_frequency = sanitize_frequency(signal_frequency, TRUE)
set_frequency(signal_frequency)
var/new_signal_frequency = sanitize_frequency(unformat_frequency(params["freq"]), TRUE)
set_frequency(new_signal_frequency)
. = TRUE
if("code")
signal_code = text2num(params["code"])

View File

@@ -173,7 +173,7 @@
O.renamedByPlayer = TRUE
if(penchoice == "Change description")
var/input = stripped_input(user,"Describe [O] here:", ,"[O.desc]", 140)
var/input = stripped_input(user,"Describe [O] here:", ,"[O.desc]", 350)
var/olddesc = O.desc
if(QDELETED(O) || !user.canUseTopic(O, BE_CLOSE))
return

View File

@@ -1,36 +1,28 @@
// 1.95x129mm (SAW)
// 7.12x82mm (SAW)
/obj/item/ammo_casing/mm195x129
name = "1.95x129mm bullet casing"
desc = "A 1.95x129mm bullet casing."
/obj/item/ammo_casing/mm712x82
name = "7.12x82mm bullet casing"
desc = "A 7.12x82mm bullet casing."
icon_state = "762-casing"
caliber = "mm195129"
projectile_type = /obj/item/projectile/bullet/mm195x129
caliber = "mm71282"
projectile_type = /obj/item/projectile/bullet/mm712x82
/obj/item/ammo_casing/mm195x129/ap
name = "1.95x129mm armor-piercing bullet casing"
desc = "A 1.95x129mm bullet casing designed with a hardened-tipped core to help penetrate armored targets."
projectile_type = /obj/item/projectile/bullet/mm195x129_ap
/obj/item/ammo_casing/mm712x82/ap
name = "7.12x82mm armor-piercing bullet casing"
desc = "A 7.12x82mm bullet casing designed with a hardened-tipped core to help penetrate armored targets."
projectile_type = /obj/item/projectile/bullet/mm712x82_ap
/obj/item/ammo_casing/mm195x129/hollow
name = "1.95x129mm hollow-point bullet casing"
desc = "A 1.95x129mm bullet casing designed to cause more damage to unarmored targets."
projectile_type = /obj/item/projectile/bullet/mm195x129_hp
/obj/item/ammo_casing/mm712x82/hollow
name = "7.12x82mm hollow-point bullet casing"
desc = "A 7.12x82mm bullet casing designed to cause more damage to unarmored targets."
projectile_type = /obj/item/projectile/bullet/mm712x82_hp
/obj/item/ammo_casing/mm195x129/incen
name = "1.95x129mm incendiary bullet casing"
desc = "A 1.95x129mm bullet casing designed with a chemical-filled capsule on the tip that when bursted, reacts with the atmosphere to produce a fireball, engulfing the target in flames."
projectile_type = /obj/item/projectile/bullet/incendiary/mm195x129
/obj/item/ammo_casing/mm712x82/incen
name = "7.12x82mm incendiary bullet casing"
desc = "A 7.12x82mm bullet casing designed with a chemical-filled capsule on the tip that when bursted, reacts with the atmosphere to produce a fireball, engulfing the target in flames."
projectile_type = /obj/item/projectile/bullet/incendiary/mm712x82
/obj/item/ammo_casing/mm712x82/match
name = "7.12x82mm match bullet casing"
desc = "A 7.12x82mm bullet casing manufactured to unfailingly high standards, you could pull off some cool trickshots with this."
projectile_type = /obj/item/projectile/bullet/mm712x82_match
/obj/item/projectile/bullet/mm712x82_match
name = "7.12x82mm match bullet"
damage = 40
ricochets_max = 2
ricochet_chance = 60
ricochet_auto_aim_range = 4
ricochet_incidence_leeway = 35
projectile_type = /obj/item/projectile/bullet/mm712x82/match

View File

@@ -1,23 +1,23 @@
/obj/item/ammo_box/magazine/mm195x129
name = "box magazine (1.95x129mm)"
/obj/item/ammo_box/magazine/mm712x82
name = "box magazine (7.12x82mm)"
icon_state = "a762-50"
ammo_type = /obj/item/ammo_casing/mm195x129
caliber = "mm195129"
ammo_type = /obj/item/ammo_casing/mm712x82
caliber = "mm71282"
max_ammo = 50
/obj/item/ammo_box/magazine/mm195x129/hollow
name = "box magazine (Hollow-Point 1.95x129mm)"
ammo_type = /obj/item/ammo_casing/mm195x129/hollow
/obj/item/ammo_box/magazine/mm712x82/hollow
name = "box magazine (Hollow-Point 7.12x82mm)"
ammo_type = /obj/item/ammo_casing/mm712x82/hollow
/obj/item/ammo_box/magazine/mm195x129/ap
name = "box magazine (Armor Penetrating 1.95x129mm)"
ammo_type = /obj/item/ammo_casing/mm195x129/ap
/obj/item/ammo_box/magazine/mm712x82/ap
name = "box magazine (Armor Penetrating 7.12x82mm)"
ammo_type = /obj/item/ammo_casing/mm712x82/ap
/obj/item/ammo_box/magazine/mm195x129/incen
name = "box magazine (Incendiary 1.95x129mm)"
ammo_type = /obj/item/ammo_casing/mm195x129/incen
/obj/item/ammo_box/magazine/mm712x82/incen
name = "box magazine (Incendiary 7.12x82mm)"
ammo_type = /obj/item/ammo_casing/mm712x82/incen
/obj/item/ammo_box/magazine/mm195x129/update_icon()
/obj/item/ammo_box/magazine/mm712x82/update_icon()
..()
icon_state = "a762-[round(ammo_count(),10)]"

View File

@@ -94,6 +94,9 @@
var/automatic = 0 //can gun use it, 0 is no, anything above 0 is the delay between clicks in ds
/// directional recoil multiplier
var/dir_recoil_amp = 10
/obj/item/gun/Initialize(mapload)
. = ..()
if(no_pin_required)
@@ -159,7 +162,7 @@
/obj/item/gun/proc/shoot_live_shot(mob/living/user, pointblank = FALSE, mob/pbtarget, message = 1, stam_cost = 0)
if(recoil)
shake_camera(user, recoil + 1, recoil)
directional_recoil(user, recoil*dir_recoil_amp, Get_Angle(user, pbtarget))
if(stam_cost) //CIT CHANGE - makes gun recoil cause staminaloss
var/safe_cost = clamp(stam_cost, 0, user.stamina_buffer)*(firing && burst_size >= 2 ? 1/burst_size : 1)

View File

@@ -296,13 +296,13 @@
/obj/item/gun/ballistic/automatic/l6_saw
name = "\improper L6 SAW"
desc = "A heavily modified 1.95x129mm light machine gun, designated 'L6 SAW'. Has 'Aussec Armoury - 2531' engraved on the receiver below the designation."
desc = "A heavily modified 7.12x82mm light machine gun, designated 'L6 SAW'. Has 'Aussec Armoury - 2531' engraved on the receiver below the designation."
icon_state = "l6closed100"
item_state = "l6closedmag"
fire_sound = "sound/weapons/lmgshot.ogg"
w_class = WEIGHT_CLASS_HUGE
slot_flags = 0
mag_type = /obj/item/ammo_box/magazine/mm195x129
mag_type = /obj/item/ammo_box/magazine/mm712x82
weapon_weight = WEAPON_HEAVY
var/cover_open = FALSE
can_suppress = FALSE

View File

@@ -167,6 +167,7 @@
icon_state = "goldrevolver"
fire_sound = 'sound/weapons/resonator_blast.ogg'
recoil = 8
dir_recoil_amp = 5 // 40 directional recoil is already really funny
pin = /obj/item/firing_pin
/obj/item/gun/ballistic/revolver/nagant

View File

@@ -21,22 +21,22 @@
/obj/item/projectile/bullet/syndicate_turret
damage = 20
// 1.95x129mm (SAW)
// 7.12x82mm (SAW)
/obj/item/projectile/bullet/mm195x129
name = "1.95x129mm bullet"
/obj/item/projectile/bullet/mm712x82
name = "7.12x82mm bullet"
damage = 40
armour_penetration = 5
wound_bonus = -50
wound_falloff_tile = 0
/obj/item/projectile/bullet/mm195x129_ap
name = "1.95x129mm armor-piercing bullet"
/obj/item/projectile/bullet/mm712x82_ap
name = "7.12x82mm armor-piercing bullet"
damage = 40
armour_penetration = 75
/obj/item/projectile/bullet/mm195x129_hp
name = "1.95x129mm hollow-point bullet"
/obj/item/projectile/bullet/mm712x82_hp
name = "7.12x82mm hollow-point bullet"
damage = 50
armour_penetration = -60
sharpness = SHARP_EDGED
@@ -44,7 +44,15 @@
bare_wound_bonus = 30
wound_falloff_tile = -8
/obj/item/projectile/bullet/incendiary/mm195x129
name = "1.95x129mm incendiary bullet"
/obj/item/projectile/bullet/incendiary/mm712x82
name = "7.12x82mm incendiary bullet"
damage = 20
fire_stacks = 3
/obj/item/projectile/bullet/mm712x82/match
name = "7.12x82mm match bullet"
damage = 40
ricochets_max = 2
ricochet_chance = 60
ricochet_auto_aim_range = 4
ricochet_incidence_leeway = 35

View File

@@ -131,7 +131,7 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list(
for(var/datum/supply_order/SO in SSshuttle.shoppinglist)
if(!empty_turfs.len)
break
var/price = SO.pack.cost
var/price = SO.pack.get_cost()
if(SO.applied_coupon)
price *= (1 - SO.applied_coupon.discount_pct_off)
@@ -163,8 +163,8 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list(
LAZYADD(goodies_by_buyer[SO.paying_account], SO)
D.bank_card_talk("Cargo order #[SO.id] has shipped. [price] credits have been charged to your bank account.")
var/datum/bank_account/department/cargo = SSeconomy.get_dep_account(ACCOUNT_CAR)
cargo.adjust_money(price - SO.pack.cost) //Cargo gets the handling fee
value += SO.pack.cost
cargo.adjust_money(price - SO.pack.get_cost()) //Cargo gets the handling fee
value += SO.pack.get_cost()
SSshuttle.shoppinglist -= SO
SSshuttle.orderhistory += SO
QDEL_NULL(SO.applied_coupon)
@@ -172,7 +172,7 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list(
if(!SO.pack.goody && !ispath(SO.pack.crate_type, /obj/structure/closet/secure_closet/cargo)) //we handle goody crates and material closets below
SO.generate(pick_n_take(empty_turfs))
SSblackbox.record_feedback("nested tally", "cargo_imports", 1, list("[SO.pack.cost]", "[SO.pack.name]"))
SSblackbox.record_feedback("nested tally", "cargo_imports", 1, list("[SO.pack.get_cost()]", "[SO.pack.name]"))
investigate_log("Order #[SO.id] ([SO.pack.name], placed by [key_name(SO.orderer_ckey)]), paid by [D.account_holder] has shipped.", INVESTIGATE_CARGO)
if(SO.pack.dangerous)
message_admins("\A [SO.pack.name] ordered by [ADMIN_LOOKUPFLW(SO.orderer_ckey)], paid by [D.account_holder] has shipped.")

View File

@@ -12,7 +12,7 @@
var/report_message = "Complete this goal."
/datum/station_goal/proc/send_report()
priority_announce("Priority Nanotrasen directive received. Project \"[name]\" details inbound.", "Incoming Priority Message", "commandreport")
priority_announce("Priority Nanotrasen directive received. Project \"[name]\" details inbound.", "Incoming Priority Message", SSstation.announcer.get_rand_report_sound())
print_command_report(get_report(),"Nanotrasen Directive [pick(GLOB.phonetic_alphabet)] \Roman[rand(1,50)]", announce=FALSE)
on_report()

View File

@@ -59,7 +59,7 @@
/datum/tcg_card/pack_nuclear/l6saw
name = "L6 Saw LMG"
desc = "A heavily modified 1.95x129mm light machine gun, designated 'L6 SAW'. Has 'Aussec Armoury - 2531' engraved on the receiver below the designation."
desc = "A heavily modified 7.12x82mm light machine gun, designated 'L6 SAW'. Has 'Aussec Armoury - 2531' engraved on the receiver below the designation."
rules = "After equipped unit dies, this card goes to the bottom of draw deck"
icon_state = "l6saw"

View File

@@ -209,29 +209,29 @@
purchasable_from = UPLINK_NUKE_OPS
/datum/uplink_item/ammo/machinegun/basic
name = "1.95x129mm Box Magazine"
desc = "A 50-round magazine of 1.95x129mm ammunition for use with the L6 SAW. \
name = "7.12x82mm Box Magazine"
desc = "A 50-round magazine of 7.12x82mm ammunition for use with the L6 SAW. \
By the time you need to use this, you'll already be standing on a pile of corpses"
item = /obj/item/ammo_box/magazine/mm195x129
item = /obj/item/ammo_box/magazine/mm712x82
/datum/uplink_item/ammo/machinegun/ap
name = "1.95x129mm (Armor Penetrating) Box Magazine"
desc = "A 50-round magazine of 1.95x129mm ammunition for use in the L6 SAW; equipped with special properties \
name = "7.12x82mm (Armor Penetrating) Box Magazine"
desc = "A 50-round magazine of 7.12x82mm ammunition for use in the L6 SAW; equipped with special properties \
to puncture even the most durable armor."
item = /obj/item/ammo_box/magazine/mm195x129/ap
item = /obj/item/ammo_box/magazine/mm712x82/ap
cost = 9
/datum/uplink_item/ammo/machinegun/hollow
name = "1.95x129mm (Hollow-Point) Box Magazine"
desc = "A 50-round magazine of 1.95x129mm ammunition for use in the L6 SAW; equipped with hollow-point tips to help \
name = "7.12x82mm (Hollow-Point) Box Magazine"
desc = "A 50-round magazine of 7.12x82mm ammunition for use in the L6 SAW; equipped with hollow-point tips to help \
with the unarmored masses of crew."
item = /obj/item/ammo_box/magazine/mm195x129/hollow
item = /obj/item/ammo_box/magazine/mm712x82/hollow
/datum/uplink_item/ammo/machinegun/incen
name = "1.95x129mm (Incendiary) Box Magazine"
desc = "A 50-round magazine of 1.95x129mm ammunition for use in the L6 SAW; tipped with a special flammable \
name = "7.12x82mm (Incendiary) Box Magazine"
desc = "A 50-round magazine of 7.12x82mm ammunition for use in the L6 SAW; tipped with a special flammable \
mixture that'll ignite anyone struck by the bullet. Some men just want to watch the world burn."
item = /obj/item/ammo_box/magazine/mm195x129/incen
item = /obj/item/ammo_box/magazine/mm712x82/incen
/datum/uplink_item/ammo/rocket
purchasable_from = UPLINK_NUKE_OPS

View File

@@ -213,7 +213,7 @@
/datum/uplink_item/dangerous/machinegun
name = "L6 Squad Automatic Weapon"
desc = "A fully-loaded Aussec Armoury belt-fed machine gun. \
This deadly weapon has a massive 50-round magazine of devastating 1.95x129mm ammunition."
This deadly weapon has a massive 50-round magazine of devastating 7.12x82mm ammunition."
item = /obj/item/gun/ballistic/automatic/l6_saw
cost = 18
surplus = 0

View File

@@ -1,4 +0,0 @@
author: "TripleShades"
delete-after: True
changes:
- qol: "Three gateways will no longer lose power via Magical SMES Units"

View File

@@ -1,4 +0,0 @@
author: "timothyteakettle"
delete-after: True
changes:
- rscadd: "lets AIs control status displays (vtuber mode)"

View File

@@ -1,4 +0,0 @@
author: "MrJWhit"
delete-after: True
changes:
- rscadd: "Adds more AI screens on box"

View File

@@ -14,3 +14,44 @@
- code_imp: doesn't snowflake the bomb cap for linux anymore, servers that need
to tweak it can do it themselves (I didn't even put it down right, should be
5000 instead of 50000, yikes)
2022-08-04:
MrJWhit:
- rscadd: Adds more AI screens on box
TripleShades:
- qol: Three gateways will no longer lose power via Magical SMES Units
timothyteakettle:
- rscadd: lets AIs control status displays (vtuber mode)
2022-08-05:
Hatterhat:
- tweak: The L6 Squad Automatic Weapon, as used by Syndicate nuclear operatives,
now fires 7.12x82mm, with no change in ballistic performance. This has the side
effect of making it now capable of utilizing match-grade ammunition, which some
would think are mutually incompatible concepts.
Putnam3145:
- tweak: Untied shoelaces probabilities rework
- balance: Miner boots are slightly harder to tie/untie now
2022-08-08:
Hatterhat:
- tweak: Proto-kinetic crushers and variants can now be renamed via pen.
- tweak: Custom descriptions on items tagged with UNIQUE_RENAME can now go to 350
characters, up from 140.
- tweak: Recoil now pushes your screen in the opposite direction of where you're
shooting. It makes sense in context, I swear. Adjust the setting for this in
your client prefs, because it defaults to on.
Linzolle:
- bugfix: catwalk overlays behave properly, appearing on top of cables and such
Putnam3145:
- tweak: Various gases now have shortened names for filters
- balance: Nitric oxide now removes from the power mix like nitrogen/pluoxium do
- balance: Nitric oxide now becomes, at most, 20% nitrogen dioxide instead of 50%
SandPoot:
- bugfix: Fixed the lack of eyes making ERROR appear on people.
- qol: Set up for the dmi editor extension, very helpful as you can see the existant
states and their names opposed to only images in a huge spritesheet.
2022-08-09:
Putnam3145:
- rscadd: 'Adds station traits: Small modifiers that can randomly be chosen each
round. They are usually logged in the intercept the station receives early in
the round'
- refactor: Announcement audio is now stored in a datum to make it easy to add different
announcers

Binary file not shown.

Before

Width:  |  Height:  |  Size: 484 B

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 396 B

After

Width:  |  Height:  |  Size: 484 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More