Merge remote-tracking branch 'upstream/master' into ambitioncheck

This commit is contained in:
keronshb
2022-02-22 17:10:25 -05:00
1045 changed files with 68632 additions and 58299 deletions
+1
View File
@@ -16,6 +16,7 @@
#define SHOVABLE_ONTO (1<<13)//called on turf.shove_act() to consider whether an object should have a niche effect (defined in their own shove_act()) when someone is pushed onto it, or do a sanity CanPass() check.
#define EXAMINE_SKIP (1<<14) /// Makes the Examine proc not read out this item.
#define IN_STORAGE (1<<15) //is this item in the storage item, such as backpack? used for tooltips
#define HAND_ITEM (1<<16) // If an item is just your hand (circled hand, slapper) and shouldn't block things like riding
/// Integrity defines for clothing (not flags but close enough)
#define CLOTHING_PRISTINE 0 // We have no damage on the clothing
+12
View File
@@ -112,6 +112,18 @@ GLOBAL_LIST_EMPTY(living_heart_cache) //A list of all living hearts in existance
#define BLOB_ATTACK_REFUND 2 //blob refunds this much if it attacks and doesn't spread
#define BLOB_REFLECTOR_COST 15
/// How many telecrystals a normal traitor starts with
#define TELECRYSTALS_DEFAULT 20
/// How many telecrystals mapper/admin only "precharged" uplink implant
#define TELECRYSTALS_PRELOADED_IMPLANT 10
/// The normal cost of an uplink implant; used for calcuating how many
/// TC to charge someone if they get a free implant through choice or
/// because they have nothing else that supports an implant.
#define UPLINK_IMPLANT_TELECRYSTAL_COST 4
/// The dimensions of the antagonist preview icon. Will be scaled to this size.
#define ANTAGONIST_PREVIEW_ICON_SIZE 96
//Objectives-Ambitions Panel
#define REQUEST_NEW_OBJECTIVE "new_objective"
#define REQUEST_DEL_OBJECTIVE "del_objective"
+27
View File
@@ -68,6 +68,21 @@
#define TEMPERATURE_DAMAGE_COEFFICIENT 1.5 //This is used in handle_temperature_damage() for humans, and in reagents that affect body temperature. Temperature damage is multiplied by this amount.
#define SYNTH_PASSIVE_HEAT_GAIN 10 //Degrees C per handle_environment() Synths passively heat up. Mitigated by cooling efficiency. Can lead to overheating if not managed.
#define SYNTH_MAX_PASSIVE_GAIN_TEMP 250 //Degrees C that a synth can be heated up to by their internal heat gain, provided their cooling is insufficient to mitigate it.
#define SYNTH_MIN_PASSIVE_COOLING_TEMP -30 //Degrees C a synth can cool towards at very high cooling efficiency.
#define SYNTH_HEAT_EFFICIENCY_COEFF 0.005 //How quick the difference between the Synth and the environment starts to matter. The smaller the higher the difference has to be for the same change.
#define SYNTH_SINGLE_INFLUENCE_COOLING_EFFECT_CAP 3 //How big can the multiplier for heat / pressure cooling be in an optimal environment
#define SYNTH_TOTAL_ENVIRONMENT_EFFECT_CAP 2 //How big of an multiplier can the environment give in an optimal scenario (maximum efficiency in the end is at a lower cap, this mostly counters low coolant levels)
#define SYNTH_MAX_COOLING_EFFICIENCY 1.5 //The maximum possible cooling efficiency one can achieve at optimal conditions.
#define SYNTH_ACTIVE_COOLING_TEMP_BOUNDARY 10 //The minimum distance from room temperature a Synth needs to have for active cooling to actively cool.
#define SYNTH_ACTIVE_COOLING_LOW_PRESSURE_THRESHOLD 0.05 //At how much percentage of default pressure (or lower) active cooling gets a massive cost penalty.
#define SYNTH_ACTIVE_COOLING_LOW_PRESSURE_PENALTY 2.5 //By how much is active cooling cost multiplied if in a very-low-pressure environment?
#define SYNTH_ACTIVE_COOLING_MIN_ADJUSTMENT 5 //What is the minimum amount of temp you move towards the target point, even if it would be less with default calculations?
#define SYNTH_INTEGRATION_COOLANT_PENALTY 0.4 //Integrating coolant is multiplied with this for calculation of impact on passive cooling.
#define SYNTH_INTEGRATION_COOLANT_CAP 0.25 //Integrating coolant is capped at counting as current_blood * this number. This is so you can't just run on salglu or whatever.
#define SYNTH_COLD_OFFSET -125 //How much colder temps Synths can tolerate. Used in their species.
#define BODYTEMP_NORMAL 310.15 //The natural temperature for a body
#define BODYTEMP_AUTORECOVERY_DIVISOR 11 //This is the divisor which handles how much of the temperature difference between the current body temperature and 310.15K (optimal temperature) humans auto-regenerate each tick. The higher the number, the slower the recovery. This is applied each tick, so long as the mob is alive.
#define BODYTEMP_AUTORECOVERY_MINIMUM 12 //Minimum amount of kelvin moved toward 310K per tick. So long as abs(310.15 - bodytemp) is more than 50.
@@ -128,6 +143,7 @@
#define TANK_MAX_RELEASE_PRESSURE (ONE_ATMOSPHERE*3)
#define TANK_MIN_RELEASE_PRESSURE 0
#define TANK_DEFAULT_RELEASE_PRESSURE 17
#define TANK_POST_FRAGMENT_REACTIONS 5
//CANATMOSPASS
#define ATMOS_PASS_YES 1
@@ -160,6 +176,9 @@
//SNOSTATION
#define ICEMOON_DEFAULT_ATMOS "ICEMOON_ATMOS"
//FESTIVESTATION
#define FESTIVE_ATMOS "o2=22;n2=82;TEMP=266" //this goes here right putnam??
//ATMOSIA GAS MONITOR TAGS
#define ATMOS_GAS_MONITOR_INPUT_O2 "o2_in"
#define ATMOS_GAS_MONITOR_OUTPUT_O2 "o2_out"
@@ -257,6 +276,7 @@
#define GAS_HYPERNOB "nob"
#define GAS_NITROUS "n2o"
#define GAS_NITRYL "no2"
#define GAS_HYDROGEN "hydrogen"
#define GAS_TRITIUM "tritium"
#define GAS_BZ "bz"
#define GAS_STIMULUM "stim"
@@ -264,9 +284,16 @@
#define GAS_MIASMA "miasma"
#define GAS_METHANE "methane"
#define GAS_METHYL_BROMIDE "methyl_bromide"
#define GAS_BROMINE "bromine"
#define GAS_AMMONIA "ammonia"
#define GAS_FLUORINE "fluorine"
#define GAS_ETHANOL "ethanol"
#define GAS_GROUP_CHEMICALS "Chemicals"
#define GAS_FLAG_DANGEROUS (1<<0)
#define GAS_FLAG_BREATH_PROC (1<<1)
#define GAS_FLAG_CHEMICAL (1<<2)
//SUPERMATTER DEFINES
#define HEAT_PENALTY "heat penalties"
+6
View File
@@ -0,0 +1,6 @@
//different types of atom colorations
#define ADMIN_COLOUR_PRIORITY 1 //only used by rare effects like greentext coloring mobs and when admins varedit color
#define TEMPORARY_COLOUR_PRIORITY 2 //e.g. purple effect of the revenant on a mob, black effect when mob electrocuted
#define WASHABLE_COLOUR_PRIORITY 3 //color splashed onto an atom (e.g. paint on turf)
#define FIXED_COLOUR_PRIORITY 4 //color inherent to the atom (e.g. blob color)
#define COLOUR_PRIORITY_AMOUNT 4 //how many priority levels there are.
+197
View File
@@ -0,0 +1,197 @@
// This is eventually for wjohn to add more color standardization stuff like I keep asking him >:(
#define COLOR_INPUT_DISABLED "#F0F0F0"
#define COLOR_INPUT_ENABLED "#D3B5B5"
#define COLOR_DARKMODE_BACKGROUND "#202020"
#define COLOR_DARKMODE_DARKBACKGROUND "#171717"
#define COLOR_DARKMODE_TEXT "#a4bad6"
#define COLOR_WHITE "#FFFFFF"
#define COLOR_VERY_LIGHT_GRAY "#EEEEEE"
#define COLOR_SILVER "#C0C0C0"
#define COLOR_GRAY "#808080"
#define COLOR_FLOORTILE_GRAY "#8D8B8B"
#define COLOR_DARK "#454545"
#define COLOR_ALMOST_BLACK "#333333"
#define COLOR_BLACK "#000000"
#define COLOR_HALF_TRANSPARENT_BLACK "#0000007A"
#define COLOR_RED "#FF0000"
#define COLOR_MOSTLY_PURE_RED "#FF3300"
#define COLOR_DARK_RED "#A50824"
#define COLOR_RED_LIGHT "#FF3333"
#define COLOR_MAROON "#800000"
#define COLOR_VIVID_RED "#FF3232"
#define COLOR_LIGHT_GRAYISH_RED "#E4C7C5"
#define COLOR_SOFT_RED "#FA8282"
#define COLOR_BUBBLEGUM_RED "#950A0A"
#define COLOR_YELLOW "#FFFF00"
#define COLOR_VIVID_YELLOW "#FBFF23"
#define COLOR_VERY_SOFT_YELLOW "#FAE48E"
#define COLOR_OLIVE "#808000"
#define COLOR_VIBRANT_LIME "#00FF00"
#define COLOR_LIME "#32CD32"
#define COLOR_DARK_LIME "#00aa00"
#define COLOR_VERY_PALE_LIME_GREEN "#DDFFD3"
#define COLOR_VERY_DARK_LIME_GREEN "#003300"
#define COLOR_GREEN "#008000"
#define COLOR_DARK_MODERATE_LIME_GREEN "#44964A"
#define COLOR_CYAN "#00FFFF"
#define COLOR_DARK_CYAN "#00A2FF"
#define COLOR_TEAL "#008080"
#define COLOR_BLUE "#0000FF"
#define COLOR_STRONG_BLUE "#1919c8"
#define COLOR_BRIGHT_BLUE "#2CB2E8"
#define COLOR_MODERATE_BLUE "#555CC2"
#define COLOR_AMETHYST "#822BFF"
#define COLOR_BLUE_LIGHT "#33CCFF"
#define COLOR_NAVY "#000080"
#define COLOR_BLUE_GRAY "#75A2BB"
#define COLOR_PINK "#FFC0CB"
#define COLOR_LIGHT_PINK "#ff3cc8"
#define COLOR_MOSTLY_PURE_PINK "#E4005B"
#define COLOR_MAGENTA "#FF00FF"
#define COLOR_STRONG_MAGENTA "#B800B8"
#define COLOR_PURPLE "#800080"
#define COLOR_VIOLET "#B900F7"
#define COLOR_STRONG_VIOLET "#6927c5"
#define COLOR_ORANGE "#FF9900"
#define COLOR_MOSTLY_PURE_ORANGE "#ff8000"
#define COLOR_TAN_ORANGE "#FF7B00"
#define COLOR_BRIGHT_ORANGE "#E2853D"
#define COLOR_LIGHT_ORANGE "#ffc44d"
#define COLOR_PALE_ORANGE "#FFBE9D"
#define COLOR_BEIGE "#CEB689"
#define COLOR_DARK_ORANGE "#C3630C"
#define COLOR_DARK_MODERATE_ORANGE "#8B633B"
#define COLOR_BROWN "#BA9F6D"
#define COLOR_DARK_BROWN "#997C4F"
#define COLOR_ORANGE_BROWN "#a9734f"
//Color defines used by the soapstone (based on readability against grey tiles)
#define COLOR_SOAPSTONE_PLASTIC "#a19d94"
#define COLOR_SOAPSTONE_IRON "#b2b2b2"
#define COLOR_SOAPSTONE_BRONZE "#FE8001"
#define COLOR_SOAPSTONE_SILVER "#FFFFFF"
#define COLOR_SOAPSTONE_GOLD "#FFD900"
#define COLOR_SOAPSTONE_DIAMOND "#00ffee"
#define COLOR_GREEN_GRAY "#99BB76"
#define COLOR_RED_GRAY "#B4696A"
#define COLOR_PALE_BLUE_GRAY "#98C5DF"
#define COLOR_PALE_GREEN_GRAY "#B7D993"
#define COLOR_PALE_RED_GRAY "#D59998"
#define COLOR_PALE_PURPLE_GRAY "#CBB1CA"
#define COLOR_PURPLE_GRAY "#AE8CA8"
//Color defines used by the assembly detailer.
#define COLOR_ASSEMBLY_BLACK "#545454"
#define COLOR_ASSEMBLY_BGRAY "#9497AB"
#define COLOR_ASSEMBLY_WHITE "#E2E2E2"
#define COLOR_ASSEMBLY_RED "#CC4242"
#define COLOR_ASSEMBLY_ORANGE "#E39751"
#define COLOR_ASSEMBLY_BEIGE "#AF9366"
#define COLOR_ASSEMBLY_BROWN "#97670E"
#define COLOR_ASSEMBLY_GOLD "#AA9100"
#define COLOR_ASSEMBLY_YELLOW "#CECA2B"
#define COLOR_ASSEMBLY_GURKHA "#999875"
#define COLOR_ASSEMBLY_LGREEN "#789876"
#define COLOR_ASSEMBLY_GREEN "#44843C"
#define COLOR_ASSEMBLY_LBLUE "#5D99BE"
#define COLOR_ASSEMBLY_BLUE "#38559E"
#define COLOR_ASSEMBLY_PURPLE "#6F6192"
///Colors for xenobiology vatgrowing
#define COLOR_SAMPLE_YELLOW "#c0b823"
#define COLOR_SAMPLE_PURPLE "#342941"
#define COLOR_SAMPLE_GREEN "#98b944"
#define COLOR_SAMPLE_BROWN "#91542d"
#define COLOR_SAMPLE_GRAY "#5e5856"
///Main colors for UI themes
#define COLOR_THEME_MIDNIGHT "#6086A0"
#define COLOR_THEME_PLASMAFIRE "#FFB200"
#define COLOR_THEME_RETRO "#24CA00"
#define COLOR_THEME_SLIMECORE "#4FB259"
#define COLOR_THEME_OPERATIVE "#B8221F"
#define COLOR_THEME_GLASS "#75A4C4"
#define COLOR_THEME_CLOCKWORK "#CFBA47"
///Colors for eigenstates
#define COLOR_PERIWINKLEE "#9999FF"
/**
* Some defines to generalise colours used in lighting.
*
* Important note: colors can end up significantly different from the basic html picture, especially when saturated
*/
/// Bright but quickly dissipating neon green. rgb(100, 200, 100)
#define LIGHT_COLOR_GREEN "#64C864"
/// Electric green. rgb(0, 255, 0)
#define LIGHT_COLOR_ELECTRIC_GREEN "#00FF00"
/// Cold, diluted blue. rgb(100, 150, 250)
#define LIGHT_COLOR_BLUE "#6496FA"
/// Light blueish green. rgb(125, 225, 175)
#define LIGHT_COLOR_BLUEGREEN "#7DE1AF"
/// Diluted cyan. rgb(125, 225, 225)
#define LIGHT_COLOR_CYAN "#7DE1E1"
/// Electric cyan rgb(0, 255, 255)
#define LIGHT_COLOR_ELECTRIC_CYAN "#00FFFF"
/// More-saturated cyan. rgb(64, 206, 255)
#define LIGHT_COLOR_LIGHT_CYAN "#40CEFF"
/// Saturated blue. rgb(51, 117, 248)
#define LIGHT_COLOR_DARK_BLUE "#6496FA"
/// Diluted, mid-warmth pink. rgb(225, 125, 225)
#define LIGHT_COLOR_PINK "#E17DE1"
/// Dimmed yellow, leaning kaki. rgb(225, 225, 125)
#define LIGHT_COLOR_YELLOW "#E1E17D"
/// Clear brown, mostly dim. rgb(150, 100, 50)
#define LIGHT_COLOR_BROWN "#966432"
/// Mostly pure orange. rgb(250, 150, 50)
#define LIGHT_COLOR_ORANGE "#FA9632"
/// Light Purple. rgb(149, 44, 244)
#define LIGHT_COLOR_PURPLE "#952CF4"
/// Less-saturated light purple. rgb(155, 81, 255)
#define LIGHT_COLOR_LAVENDER "#9B51FF"
///slightly desaturated bright yellow.
#define LIGHT_COLOR_HOLY_MAGIC "#FFF743"
/// deep crimson
#define LIGHT_COLOR_BLOOD_MAGIC "#D00000"
/* These ones aren't a direct colour like the ones above, because nothing would fit */
/// Warm orange color, leaning strongly towards yellow. rgb(250, 160, 25)
#define LIGHT_COLOR_FIRE "#FAA019"
/// Very warm yellow, leaning slightly towards orange. rgb(196, 138, 24)
#define LIGHT_COLOR_LAVA "#C48A18"
/// Bright, non-saturated red. Leaning slightly towards pink for visibility. rgb(250, 100, 75)
#define LIGHT_COLOR_FLARE "#FA644B"
/// Weird color, between yellow and green, very slimy. rgb(175, 200, 75)
#define LIGHT_COLOR_SLIME_LAMP "#AFC84B"
/// Extremely diluted yellow, close to skin color (for some reason). rgb(250, 225, 175)
#define LIGHT_COLOR_TUNGSTEN "#FAE1AF"
/// Barely visible cyan-ish hue, as the doctor prescribed. rgb(240, 250, 250)
#define LIGHT_COLOR_HALOGEN "#F0FAFA"
//The GAGS greyscale_colors for each department's computer/machine circuits
#define CIRCUIT_COLOR_GENERIC "#1A7A13"
#define CIRCUIT_COLOR_COMMAND "#1B4594"
#define CIRCUIT_COLOR_SECURITY "#9A151E"
#define CIRCUIT_COLOR_SCIENCE "#BC4A9B"
#define CIRCUIT_COLOR_SERVICE "#92DCBA"
#define CIRCUIT_COLOR_MEDICAL "#00CCFF"
#define CIRCUIT_COLOR_ENGINEERING "#F8D700"
#define CIRCUIT_COLOR_SUPPLY "#C47749"
/// Colors for pride week
#define COLOR_PRIDE_RED "#FF6666"
#define COLOR_PRIDE_ORANGE "#FC9F3C"
#define COLOR_PRIDE_YELLOW "#EAFF51"
#define COLOR_PRIDE_GREEN "#41FC66"
#define COLOR_PRIDE_BLUE "#42FFF2"
#define COLOR_PRIDE_PURPLE "#5D5DFC"
+4
View File
@@ -0,0 +1,4 @@
//Luma coefficients suggested for HDTVs. If you change these, make sure they add up to 1.
#define LUMA_R 0.213
#define LUMA_G 0.715
#define LUMA_B 0.072
-62
View File
@@ -1,62 +0,0 @@
// This is eventually for wjohn to add more color standardization stuff like I keep asking him >:(
#define COLOR_INPUT_DISABLED "#F0F0F0"
#define COLOR_INPUT_ENABLED "#D3B5B5"
#define COLOR_FLOORTILE_GRAY "#8D8B8B"
#define COLOR_ALMOST_BLACK "#333333"
#define COLOR_BLACK "#000000"
#define COLOR_RED "#FF0000"
#define COLOR_RED_LIGHT "#FF3333"
#define COLOR_MAROON "#800000"
#define COLOR_YELLOW "#FFFF00"
#define COLOR_OLIVE "#808000"
#define COLOR_LIME "#32CD32"
#define COLOR_GREEN "#008000"
#define COLOR_CYAN "#00FFFF"
#define COLOR_TEAL "#008080"
#define COLOR_BLUE "#0000FF"
#define COLOR_BLUE_LIGHT "#33CCFF"
#define COLOR_NAVY "#000080"
#define COLOR_PINK "#FFC0CB"
#define COLOR_MAGENTA "#FF00FF"
#define COLOR_PURPLE "#800080"
#define COLOR_ORANGE "#FF9900"
#define COLOR_BEIGE "#CEB689"
#define COLOR_BLUE_GRAY "#75A2BB"
#define COLOR_BROWN "#BA9F6D"
#define COLOR_SOFT_RED "#FA8282"
#define COLOR_DARK_BROWN "#997C4F"
#define COLOR_DARK_ORANGE "#C3630C"
#define COLOR_GREEN_GRAY "#99BB76"
#define COLOR_RED_GRAY "#B4696A"
#define COLOR_PALE_BLUE_GRAY "#98C5DF"
#define COLOR_PALE_GREEN_GRAY "#B7D993"
#define COLOR_PALE_ORANGE "#FFC066"
#define COLOR_PALE_RED_GRAY "#D59998"
#define COLOR_PALE_PURPLE_GRAY "#CBB1CA"
#define COLOR_PURPLE_GRAY "#AE8CA8"
// Color defines used by the assembly detailer.
#define COLOR_ASSEMBLY_BLACK "#545454"
#define COLOR_ASSEMBLY_BGRAY "#9497AB"
#define COLOR_ASSEMBLY_WHITE "#E2E2E2"
#define COLOR_ASSEMBLY_RED "#CC4242"
#define COLOR_ASSEMBLY_ORANGE "#E39751"
#define COLOR_ASSEMBLY_BEIGE "#AF9366"
#define COLOR_ASSEMBLY_BROWN "#97670E"
#define COLOR_ASSEMBLY_GOLD "#AA9100"
#define COLOR_ASSEMBLY_YELLOW "#CECA2B"
#define COLOR_ASSEMBLY_GURKHA "#999875"
#define COLOR_ASSEMBLY_LGREEN "#789876"
#define COLOR_ASSEMBLY_GREEN "#44843C"
#define COLOR_ASSEMBLY_LBLUE "#5D99BE"
#define COLOR_ASSEMBLY_BLUE "#38559E"
#define COLOR_ASSEMBLY_PURPLE "#6F6192"
#define COLOR_ASSEMBLY_PINK "#ff4adc"
#define COLOR_WHITE "#FFFFFF"
#define COLOR_VERY_LIGHT_GRAY "#EEEEEE"
#define COLOR_SILVER "#C0C0C0"
#define COLOR_GRAY "#808080"
#define COLOR_HALF_TRANSPARENT_BLACK "#0000007A"
#define COLOR_BRIGHT_BLUE "#2CB2E8"
+25
View File
@@ -25,6 +25,15 @@
/// Do not allow this random event to continue.
#define CANCEL_PRE_RANDOM_EVENT (1<<0)
/// a weather event of some kind occured
#define COMSIG_WEATHER_TELEGRAPH(event_type) "!weather_telegraph [event_type]"
#define COMSIG_WEATHER_START(event_type) "!weather_start [event_type]"
#define COMSIG_WEATHER_WINDDOWN(event_type) "!weather_winddown [event_type]"
#define COMSIG_WEATHER_END(event_type) "!weather_end [event_type]"
/// called by auxgm add_gas: (gas_id)
#define COMSIG_GLOB_NEW_GAS "!new_gas"
// signals from globally accessible objects
/// from SSsun when the sun changes position : (primary_sun, suns)
#define COMSIG_SUN_MOVED "sun_moved"
@@ -45,6 +54,8 @@
#define COMSIG_PARENT_QDELETING "parent_qdeleting"
/// generic topic handler (usr, href_list)
#define COMSIG_TOPIC "handle_topic"
/// from datum ui_act (usr, action)
#define COMSIG_UI_ACT "COMSIG_UI_ACT"
/// fires on the target datum when an element is attached to it (/datum/element)
#define COMSIG_ELEMENT_ATTACH "element_attach"
@@ -415,6 +426,12 @@
///from /obj/machinery/obj_break(damage_flag): (damage_flag)
#define COMSIG_MACHINERY_BROKEN "machinery_broken"
// /obj/machinery/power/supermatter_crystal signals
/// from /obj/machinery/power/supermatter_crystal/process_atmos(); when the SM delam reaches the point of sounding alarms
#define COMSIG_SUPERMATTER_DELAM_START_ALARM "sm_delam_start_alarm"
/// from /obj/machinery/power/supermatter_crystal/process_atmos(); when the SM sounds an audible alarm
#define COMSIG_SUPERMATTER_DELAM_ALARM "sm_delam_alarm"
// /obj/item signals
#define COMSIG_ITEM_ATTACK "item_attack" //from base of obj/item/attack(): (/mob/living/target, /mob/living/user)
#define COMSIG_ITEM_ATTACK_SELF "item_attack_self" //from base of obj/item/attack_self(): (/mob)
@@ -455,6 +472,14 @@
#define COMSIG_MINE_TRIGGERED "minegoboom" ///from [/obj/effect/mine/proc/triggermine]:
// Uncovered information
#define COMPONENT_DEEPSCAN_UNCOVERED_INFORMATION 1
///Called when an item is being offered, from [/obj/item/proc/on_offered(mob/living/carbon/offerer)]
#define COMSIG_ITEM_OFFERING "item_offering"
///Interrupts the offer proc
#define COMPONENT_OFFER_INTERRUPT (1<<0)
///Called when an someone tries accepting an offered item, from [/obj/item/proc/on_offer_taken(mob/living/carbon/offer, mob/living/carbon/taker)]
#define COMSIG_ITEM_OFFER_TAKEN "item_offer_taken"
///Interrupts the offer acceptance
#define COMPONENT_OFFER_TAKE_INTERRUPT (1<<0)
///from [/obj/structure/closet/supplypod/proc/endlaunch]:
#define COMSIG_SUPPLYPOD_LANDED "supplypodgoboom"
+1 -2
View File
@@ -76,10 +76,9 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
#define isvampire(A) (is_species(A,/datum/species/vampire))
#define isdullahan(A) (is_species(A, /datum/species/dullahan))
#define isangel(A) (is_species(A, /datum/species/angel))
#define ismush(A) (is_species(A, /datum/species/mush))
#define isshadow(A) (is_species(A, /datum/species/shadow))
#define isrobotic(A) (is_species(A, /datum/species/ipc) || is_species(A, /datum/species/synthliz))
#define isrobotic(A) (is_species(A, /datum/species/ipc) || is_species(A, /datum/species/synthliz) || is_species(A, /datum/species/mammal/synthetic))
#define isdwarf(A) (is_species(A, /datum/species/dwarf))
// Citadel specific species
+7 -2
View File
@@ -5,9 +5,10 @@
#define CLICKCATCHER_PLANE -99
#define PLANE_SPACE -95
#define PLANE_SPACE -98
#define PLANE_SPACE_RENDER_TARGET "PLANE_SPACE"
#define PLANE_SPACE_PARALLAX -90
#define PLANE_SPACE_PARALLAX -95
#define PLANE_SPACE_PARALLAX_RENDER_TARGET "PLANE_SPACE_PARALLAX"
#define OPENSPACE_LAYER 17 //Openspace layer over all
@@ -153,6 +154,10 @@
#define CAMERA_STATIC_LAYER 19
#define CAMERA_STATIC_RENDER_TARGET "CAMERA_STATIC_PLANE"
/// Plane for balloon text (text that fades up)
/// It's over lighting and every other crap because this is nearly as important as hud content and only visible to the user.
#define BALLOON_CHAT_PLANE 20
//HUD layer defines
#define FULLSCREEN_PLANE 20
-25
View File
@@ -30,31 +30,6 @@
//Important note on colors. Colors can end up significantly different from the basic html picture, especially when saturated
#define LIGHT_COLOR_WHITE "#FFFFFF"
#define LIGHT_COLOR_RED "#FA8282" //Warm but extremely diluted red. rgb(250, 130, 130)
#define LIGHT_COLOR_GREEN "#64C864" //Bright but quickly dissipating neon green. rgb(100, 200, 100)
#define LIGHT_COLOR_BLUE "#6496FA" //Cold, diluted blue. rgb(100, 150, 250)
#define LIGHT_COLOR_BLUEGREEN "#7DE1AF" //Light blueish green. rgb(125, 225, 175)
#define LIGHT_COLOR_PALEBLUE "#7DAFE1" //A pale blue-ish color. rgb(125, 175, 225)
#define LIGHT_COLOR_CYAN "#7DE1E1" //Diluted cyan. rgb(125, 225, 225)
#define LIGHT_COLOR_LIGHT_CYAN "#40CEFF" //More-saturated cyan. rgb(64, 206, 255)
#define LIGHT_COLOR_DARK_BLUE "#6496FA" //Saturated blue. rgb(51, 117, 248)
#define LIGHT_COLOR_PINK "#E17DE1" //Diluted, mid-warmth pink. rgb(225, 125, 225)
#define LIGHT_COLOR_YELLOW "#E1E17D" //Dimmed yellow, leaning kaki. rgb(225, 225, 125)
#define LIGHT_COLOR_BROWN "#966432" //Clear brown, mostly dim. rgb(150, 100, 50)
#define LIGHT_COLOR_ORANGE "#FA9632" //Mostly pure orange. rgb(250, 150, 50)
#define LIGHT_COLOR_PURPLE "#952CF4" //Light Purple. rgb(149, 44, 244)
#define LIGHT_COLOR_LAVENDER "#9B51FF" //Less-saturated light purple. rgb(155, 81, 255)
#define LIGHT_COLOR_HOLY_MAGIC "#FFF743" //slightly desaturated bright yellow.
#define LIGHT_COLOR_BLOOD_MAGIC "#D00000" //deep crimson
//These ones aren't a direct colour like the ones above, because nothing would fit
#define LIGHT_COLOR_FIRE "#FAA019" //Warm orange color, leaning strongly towards yellow. rgb(250, 160, 25)
#define LIGHT_COLOR_LAVA "#C48A18" //Very warm yellow, leaning slightly towards orange. rgb(196, 138, 24)
#define LIGHT_COLOR_FLARE "#FA644B" //Bright, non-saturated red. Leaning slightly towards pink for visibility. rgb(250, 100, 75)
#define LIGHT_COLOR_SLIME_LAMP "#AFC84B" //Weird color, between yellow and green, very slimy. rgb(175, 200, 75)
#define LIGHT_COLOR_TUNGSTEN "#FAE1AF" //Extremely diluted yellow, close to skin color (for some reason). rgb(250, 225, 175)
#define LIGHT_COLOR_HALOGEN "#F0FAFA" //Barely visible cyan-ish hue, as the doctor prescribed. rgb(240, 250, 250)
#define LIGHT_RANGE_FIRE 3 //How many tiles standard fires glow.
+3 -2
View File
@@ -40,15 +40,16 @@
#define LOG_ASAY (1 << 15)
#define LOG_VIRUS (1 << 16)
#define LOG_SHUTTLE (1 << 18)
#define LOG_VICTIM (1 << 19)
//Individual logging panel pages
#define INDIVIDUAL_ATTACK_LOG (LOG_ATTACK)
#define INDIVIDUAL_ATTACK_LOG (LOG_ATTACK | LOG_VICTIM)
#define INDIVIDUAL_SAY_LOG (LOG_SAY | LOG_WHISPER | LOG_DSAY)
#define INDIVIDUAL_EMOTE_LOG (LOG_EMOTE | LOG_SUBTLER)
#define INDIVIDUAL_COMMS_LOG (LOG_PDA | LOG_CHAT | LOG_COMMENT | LOG_TELECOMMS)
#define INDIVIDUAL_OOC_LOG (LOG_OOC | LOG_ADMIN)
#define INDIVIDUAL_OWNERSHIP_LOG (LOG_OWNERSHIP)
#define INDIVIDUAL_SHOW_ALL_LOG (LOG_ATTACK | LOG_SAY | LOG_WHISPER | LOG_EMOTE | LOG_DSAY | LOG_PDA | LOG_CHAT | LOG_COMMENT | LOG_TELECOMMS | LOG_OOC | LOG_ADMIN | LOG_OWNERSHIP | LOG_GAME)
#define INDIVIDUAL_SHOW_ALL_LOG (LOG_ATTACK | LOG_SAY | LOG_WHISPER | LOG_EMOTE | LOG_DSAY | LOG_PDA | LOG_CHAT | LOG_COMMENT | LOG_TELECOMMS | LOG_OOC | LOG_ADMIN | LOG_OWNERSHIP | LOG_GAME | LOG_VICTIM)
#define LOGSRC_CLIENT "Client"
#define LOGSRC_MOB "Mob"
+18 -11
View File
@@ -48,32 +48,39 @@
#define MC_CHARGE "CHARGE"
#define MC_AI "AI"
#define MC_SENSORS "SENSORS"
#define MC_SIGNALER "SIGNALER"
//NTNet stuff, for modular computers
// NTNet module-configuration values. Do not change these. If you need to add another use larger number (5..6..7 etc)
#define NTNET_SOFTWAREDOWNLOAD 1 // Downloads of software from NTNet
#define NTNET_PEERTOPEER 2 // P2P transfers of files between devices
#define NTNET_COMMUNICATION 3 // Communication (messaging)
#define NTNET_SYSTEMCONTROL 4 // Control of various systems, RCon, air alarm control, etc.
#define NTNET_SOFTWAREDOWNLOAD 1 // Downloads of software from NTNet
#define NTNET_PEERTOPEER 2 // P2P transfers of files between devices
#define NTNET_COMMUNICATION 3 // Communication (messaging)
#define NTNET_SYSTEMCONTROL 4 // Control of various systems, RCon, air alarm control, etc.
//NTNet transfer speeds, used when downloading/uploading a file/program.
#define NTNETSPEED_LOWSIGNAL 0.5 // GQ/s transfer speed when the device is wirelessly connected and on Low signal
#define NTNETSPEED_HIGHSIGNAL 1 // GQ/s transfer speed when the device is wirelessly connected and on High signal
#define NTNETSPEED_ETHERNET 2 // GQ/s transfer speed when the device is using wired connection
#define NTNETSPEED_LOWSIGNAL 0.5 // GQ/s transfer speed when the device is wirelessly connected and on Low signal
#define NTNETSPEED_HIGHSIGNAL 1 // GQ/s transfer speed when the device is wirelessly connected and on High signal
#define NTNETSPEED_ETHERNET 2 // GQ/s transfer speed when the device is using wired connection
//Caps for NTNet logging. Less than 10 would make logging useless anyway, more than 500 may make the log browser too laggy. Defaults to 100 unless user changes it.
#define MAX_NTNET_LOGS 300
#define MIN_NTNET_LOGS 10
//Program bitflags
#define PROGRAM_ALL (~0)
#define PROGRAM_CONSOLE (1<<0)
#define PROGRAM_LAPTOP (1<<1)
#define PROGRAM_TABLET (1<<2)
#define PROGRAM_ALL (~0)
#define PROGRAM_CONSOLE (1<<0)
#define PROGRAM_LAPTOP (1<<1)
#define PROGRAM_TABLET (1<<2)
//Program states
#define PROGRAM_STATE_KILLED 0
#define PROGRAM_STATE_BACKGROUND 1
#define PROGRAM_STATE_ACTIVE 2
//Program categories
#define PROGRAM_CATEGORY_CREW "Crew"
#define PROGRAM_CATEGORY_ENGI "Engineering"
#define PROGRAM_CATEGORY_ROBO "Robotics"
#define PROGRAM_CATEGORY_SUPL "Supply"
#define PROGRAM_CATEGORY_MISC "Other"
#define FIREDOOR_OPEN 1
#define FIREDOOR_CLOSED 2
+8 -13
View File
@@ -323,6 +323,7 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define FIRST_DIAG_STEP 1
#define SECOND_DIAG_STEP 2
#define DEADCHAT_ANNOUNCEMENT "announcement"
#define DEADCHAT_ARRIVALRATTLE "arrivalrattle"
#define DEADCHAT_DEATHRATTLE "deathrattle"
#define DEADCHAT_REGULAR "regular-deadchat"
@@ -344,18 +345,6 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
//TODO Move to a pref
#define STATION_GOAL_BUDGET 1
//Luma coefficients suggested for HDTVs. If you change these, make sure they add up to 1.
#define LUMA_R 0.213
#define LUMA_G 0.715
#define LUMA_B 0.072
//different types of atom colorations
#define ADMIN_COLOUR_PRIORITY 1 //only used by rare effects like greentext coloring mobs and when admins varedit color
#define TEMPORARY_COLOUR_PRIORITY 2 //e.g. purple effect of the revenant on a mob, black effect when mob electrocuted
#define WASHABLE_COLOUR_PRIORITY 3 //color splashed onto an atom (e.g. paint on turf)
#define FIXED_COLOUR_PRIORITY 4 //color inherent to the atom (e.g. blob color)
#define COLOUR_PRIORITY_AMOUNT 4 //how many priority levels there are.
//Endgame Results
#define NUKE_NEAR_MISS 1
#define NUKE_MISS_STATION 2
@@ -379,7 +368,8 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define CLOCK_SILICONS 22
#define CLOCK_PROSELYTIZATION 23
#define SHUTTLE_HIJACK 24
#define GANG_VICTORY 25
#define GANG_DESTROYED 25
#define GANG_OPERATING 26
#define FIELD_TURF 1
#define FIELD_EDGE 2
@@ -567,3 +557,8 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define SHOES_KNOTTED 2
#define WANTED_FILE "wanted_message.json"
// Notification action types
#define NOTIFY_JUMP "jump"
#define NOTIFY_ATTACK "attack"
#define NOTIFY_ORBIT "orbit"
+1 -1
View File
@@ -295,7 +295,7 @@
#define APPRENTICE_AGE_MIN 29 // youngest an apprentice can be
#define SHOES_SLOWDOWN 0 // How much shoes slow you down by default. Negative values speed you up
#define SHOES_SPEED_SLIGHT SHOES_SLOWDOWN - 1 // slightest speed boost to movement
#define POCKET_STRIP_DELAY 40 // time taken (in deciseconds) to search somebody's pockets
#define POCKET_STRIP_DELAY (4 SECONDS) //time taken to search somebody's pockets
#define DOOR_CRUSH_DAMAGE 15 // the amount of damage that airlocks deal when they crush you
#define HUNGER_FACTOR 0.1 // factor at which mob nutrition decreases
-10
View File
@@ -34,12 +34,6 @@
#define TOGGLES_DEFAULT_CHAT (CHAT_OOC|CHAT_DEAD|CHAT_GHOSTEARS|CHAT_GHOSTSIGHT|CHAT_PRAYER|CHAT_RADIO|CHAT_PULLR|CHAT_GHOSTWHISPER|CHAT_GHOSTPDA|CHAT_GHOSTRADIO|CHAT_LOOC|CHAT_BANKCARD)
#define PARALLAX_INSANE -1 //for show offs
#define PARALLAX_HIGH 0 //default.
#define PARALLAX_MED 1
#define PARALLAX_LOW 2
#define PARALLAX_DISABLE 3 //this option must be the highest number
#define PIXEL_SCALING_AUTO 0
#define PIXEL_SCALING_1X 1
#define PIXEL_SCALING_1_2X 1.5
@@ -50,10 +44,6 @@
#define SCALING_METHOD_DISTORT "distort"
#define SCALING_METHOD_BLUR "blur"
#define PARALLAX_DELAY_DEFAULT world.tick_lag
#define PARALLAX_DELAY_MED 1
#define PARALLAX_DELAY_LOW 2
#define SEC_DEPT_NONE "None"
#define SEC_DEPT_RANDOM "Random"
#define SEC_DEPT_ENGINEERING "Engineering"
+1 -1
View File
@@ -13,7 +13,7 @@
#define NITRYL_FORMATION_ENERGY 100000
#define TRITIUM_BURN_OXY_FACTOR 100
#define TRITIUM_BURN_TRIT_FACTOR 10
#define TRITIUM_BURN_RADIOACTIVITY_FACTOR 50000 //The neutrons gotta go somewhere. Completely arbitrary number.
#define TRITIUM_BURN_RADIOACTIVITY_FACTOR 5000 //The neutrons gotta go somewhere. Completely arbitrary number.
#define TRITIUM_MINIMUM_RADIATION_ENERGY 0.1 //minimum 0.01 moles trit or 10 moles oxygen to start producing rads
#define SUPER_SATURATION_THRESHOLD 96
#define STIMULUM_HEAT_SCALE 100000
@@ -60,11 +60,8 @@
#define ANTAG_HUD_BROTHER 23
#define ANTAG_HUD_BLOODSUCKER 24
#define ANTAG_HUD_FUGITIVE 25
#define ANTAG_HUD_HERETIC 26
// Notification action types
#define NOTIFY_JUMP "jump"
#define NOTIFY_ATTACK "attack"
#define NOTIFY_ORBIT "orbit"
#define ANTAG_HUD_HERETIC 26
#define ANTAG_HUD_SPACECOP 27
#define ANTAG_HUD_GANGSTER 28
#define ADD_HUD_TO_COOLDOWN 20 //cooldown for being shown the images for any particular data hud
+13
View File
@@ -0,0 +1,13 @@
#define PARALLAX_DELAY_DEFAULT world.tick_lag
#define PARALLAX_DELAY_MED 1
#define PARALLAX_DELAY_LOW 2
// WARNING - client.prefs uses this, if you change these make sure to update the code in preferences!
#define PARALLAX_DISABLE 0
#define PARALLAX_LOW 1
#define PARALLAX_MED 2
#define PARALLAX_HIGH 3
#define PARALLAX_INSANE 4 // default
// keep this false until we can fix it being a seizure hazard/ugly as sin
#define PARALLAX_ROTATION_ANIMATIONS FALSE
+3 -1
View File
@@ -73,4 +73,6 @@
TECHWEB_POINT_TYPE_GENERIC = "General Research"\
)
#define TECHWEB_BOMB_POINTCAP 50000 //Adjust as needed; Stops toxins from nullifying RND progression mechanics. Current Value Cap Radius: 100
#define BOMB_TARGET_POINTS 50000 //Adjust as needed. Actual hard cap is double this, but will never be reached due to hyperbolic curve.
#define BOMB_TARGET_SIZE 200 // The shockwave radius required for a bomb to get TECHWEB_BOMB_MIDPOINT points.
#define BOMB_SUB_TARGET_EXPONENT 2 // The power of the points curve below the target size. Higher = less points for worse bombs, below target.
+3 -2
View File
@@ -36,7 +36,8 @@
#define ROLE_DEATHSQUAD "deathsquad"
#define ROLE_LAVALAND "lavaland"
#define ROLE_INTERNAL_AFFAIRS "internal affairs agent"
#define ROLE_GANG "gangster"
#define ROLE_FAMILIES "family boss"
#define ROLE_FAMILY_HEAD_ASPIRANT "family head aspirant"
#define ROLE_BLOODSUCKER "bloodsucker"
#define ROLE_SPACE_DRAGON "Space Dragon"
//#define ROLE_MONSTERHUNTER "monster hunter" Disabled for now
@@ -72,9 +73,9 @@ GLOBAL_LIST_INIT(special_roles, list(
ROLE_OVERTHROW = /datum/game_mode/overthrow,
ROLE_INTERNAL_AFFAIRS = /datum/game_mode/traitor/internal_affairs,
ROLE_SENTIENCE,
ROLE_GANG = /datum/game_mode/gang,
ROLE_HERETIC = /datum/game_mode/heretics,
ROLE_BLOODSUCKER = /datum/game_mode/bloodsucker,
ROLE_FAMILIES = /datum/game_mode/gang,
ROLE_SPACE_DRAGON
//ROLE_MONSTERHUNTER Disabled for now
))
-1
View File
@@ -44,7 +44,6 @@
#define SHUTTLE_TRANSIT_BORDER 10
#define PARALLAX_LOOP_TIME 25
#define HYPERSPACE_END_TIME 5
#define HYPERSPACE_WARMUP 1
+1
View File
@@ -44,6 +44,7 @@
#define span_greenannounce(str) ("<span class='greenannounce'>" + str + "</span>")
#define span_greenteamradio(str) ("<span class='greenteamradio'>" + str + "</span>")
#define span_greentext(str) ("<span class='greentext'>" + str + "</span>")
#define span_gangradio(str) ("<span class='gangradio'>" + str + "</span>")
#define span_hear(str) ("<span class='hear'>" + str + "</span>")
#define span_hidden(str) ("<span class='hidden'>" + str + "</span>")
#define span_hierophant(str) ("<span class='hierophant'>" + str + "</span>")
+11 -1
View File
@@ -3,7 +3,6 @@
#define SPECIES_ABDUCTOR "abductor"
#define SPECIES_ANDROID "android"
#define SPECIES_ANGEL "angel"
#define SPECIES_MAMMAL "mammal"
#define SPECIES_MAMMAL_SYNTHETIC "mammal_synthetic"
#define SPECIES_ARACHNID "arachnid"
@@ -53,3 +52,14 @@
#define SPECIES_CATEGORY_SHADOW "shadow"
#define SPECIES_CATEGORY_SKELETON "skeleton"
#define SPECIES_CATEGORY_UNDEAD "undead"
//Species Wing Type Defines ----------------------
#define SPECIES_WINGS_ANGEL list("Angel")
#define SPECIES_WINGS_DRAGON list("Dragon") //could also be considered demon wings or bat wings?
#define SPECIES_WINGS_ROBOT list("Robotic")
#define SPECIES_WINGS_INSECT list("Fly") //"hey when can we have something besides giant fly wings?" "when you sprite it!"
#define SPECIES_WINGS_SKELETAL list("Skeleton")
#define SPECIES_WINGS_MOTH list("Megamoth","Mothra")
#define SPECIES_WINGS_JELLY list("Angel") //no actual slime wings present right now, but I'm making this in the event someone wants to sprite slime wings.
#define SPECIES_WINGS_ALL list("Angel","Dragon","Robotic","Fly","Skeleton","Megamoth","Mothra") //keep this updated
+4
View File
@@ -136,6 +136,10 @@
#define STATUS_EFFECT_INLOVE /datum/status_effect/in_love //Displays you as being in love with someone else, and makes hearts appear around them.
#define STATUS_EFFECT_OFFERING /datum/status_effect/offering // you are offering up an item to people
#define STATUS_EFFECT_HANDSHAKE /datum/status_effect/offering/secret_handshake // you are attempting to perform a secret Family handshake
/////////////
// SLIME //
/////////////
+31
View File
@@ -0,0 +1,31 @@
// All of these must be matched in StripMenu.js.
#define STRIPPABLE_ITEM_HEAD "head"
#define STRIPPABLE_ITEM_BACK "back"
#define STRIPPABLE_ITEM_MASK "mask"
#define STRIPPABLE_ITEM_NECK "neck"
#define STRIPPABLE_ITEM_EYES "eyes"
#define STRIPPABLE_ITEM_EARS "ears"
#define STRIPPABLE_ITEM_JUMPSUIT "jumpsuit"
#define STRIPPABLE_ITEM_SUIT "suit"
#define STRIPPABLE_ITEM_GLOVES "gloves"
#define STRIPPABLE_ITEM_FEET "shoes"
#define STRIPPABLE_ITEM_SUIT_STORAGE "suit_storage"
#define STRIPPABLE_ITEM_ID "id"
#define STRIPPABLE_ITEM_BELT "belt"
#define STRIPPABLE_ITEM_LPOCKET "left_pocket"
#define STRIPPABLE_ITEM_RPOCKET "right_pocket"
#define STRIPPABLE_ITEM_LHAND "left_hand"
#define STRIPPABLE_ITEM_RHAND "right_hand"
#define STRIPPABLE_ITEM_HANDCUFFS "handcuffs"
#define STRIPPABLE_ITEM_LEGCUFFS "legcuffs"
#define STRIPPABLE_ITEM_CORGI_COLLAR "corgi_collar"
#define STRIPPABLE_ITEM_PARROT_HEADSET "parrot_headset"
/// This slot is not obscured.
#define STRIPPABLE_OBSCURING_NONE 0
/// This slot is completely obscured, and cannot be accessed.
#define STRIPPABLE_OBSCURING_COMPLETELY 1
/// This slot can't be seen, but can be accessed.
#define STRIPPABLE_OBSCURING_HIDDEN 2
+10 -6
View File
@@ -29,10 +29,10 @@
* if the arguments to addtimer are the same as an existing timer, it doesn't create a new timer,
* and returns the id of the existing timer
*/
#define TIMER_UNIQUE (1<<0)
#define TIMER_UNIQUE (1<<0)
///For unique timers: Replace the old timer rather then not start this one
#define TIMER_OVERRIDE (1<<1)
#define TIMER_OVERRIDE (1<<1)
/**
* Timing should be based on how timing progresses on clients, not the server.
@@ -41,20 +41,23 @@
* should only be used in conjuction with things that have to progress client side, such as
* animate() or sound()
*/
#define TIMER_CLIENT_TIME (1<<2)
#define TIMER_CLIENT_TIME (1<<2)
///Timer can be stopped using deltimer()
#define TIMER_STOPPABLE (1<<3)
#define TIMER_STOPPABLE (1<<3)
///prevents distinguishing identical timers with the wait variable
///
///To be used with TIMER_UNIQUE
#define TIMER_NO_HASH_WAIT (1<<4)
#define TIMER_NO_HASH_WAIT (1<<4)
///Loops the timer repeatedly until qdeleted
///
///In most cases you want a subsystem instead, so don't use this unless you have a good reason
#define TIMER_LOOP (1<<5)
#define TIMER_LOOP (1<<5)
///Delete the timer on parent datum Destroy() and when deltimer'd
#define TIMER_DELETE_ME (1<<6)
///Empty ID define
#define TIMER_ID_NULL -1
@@ -188,6 +191,7 @@
#define FIRE_PRIORITY_CALLBACKS 600
// #define FIRE_PRIORITY_EXPLOSIONS 666
#define FIRE_PRIORITY_TIMER 700
#define FIRE_PRIORITY_SOUND_LOOPS 800
#define FIRE_PRIORITY_INPUT 1000 // This must always always be the max highest priority. Player input must never be lost.
// SS runlevels
+5
View File
@@ -0,0 +1,5 @@
/// Prepares a text to be used for maptext. Use this so it doesn't look hideous.
#define MAPTEXT(text) {"<span class='maptext'>[##text]</span>"}
/// Macro from Lummox used to get height from a MeasureText proc
#define WXH_TO_HEIGHT(x) text2num(copytext(x, findtextEx(x, "x") + 1))
+3
View File
@@ -104,6 +104,7 @@
#define TRAIT_RESISTCOLD "resist_cold"
#define TRAIT_RESISTHIGHPRESSURE "resist_high_pressure"
#define TRAIT_RESISTLOWPRESSURE "resist_low_pressure"
#define TRAIT_LOWPRESSURECOOLING "low_pressure_cooling"
#define TRAIT_BOMBIMMUNE "bomb_immunity"
#define TRAIT_RADIMMUNE "rad_immunity"
#define TRAIT_GENELESS "geneless"
@@ -121,6 +122,7 @@
#define TRAIT_ROBOTIC_ORGANISM "robotic_organism"
#define TRAIT_ROBOT_RADSHIELDING "robot_radshielding"
#define TRAIT_NOBREATH "no_breath"
#define TRAIT_AUXILIARY_LUNGS "auxiliary_lungs" //Lungs not neccessary required due to nobreath, but provides some other helpful function.
#define TRAIT_ANTIMAGIC "anti_magic"
#define TRAIT_HOLY "holy"
#define TRAIT_DEPRESSION "depression"
@@ -200,6 +202,7 @@
#define TRAIT_FRIENDLY "friendly"
#define TRAIT_SNOB "snob"
#define TRAIT_MULTILINGUAL "multilingual"
#define TRAIT_HEARING_SENSITIVE "hearing_sensitive"
#define TRAIT_CULT_EYES "cult_eyes"
#define TRAIT_AUTO_CATCH_ITEM "auto_catch_item"
#define TRAIT_CLOWN_MENTALITY "clown_mentality" // The future is now, clownman.
+10
View File
@@ -0,0 +1,10 @@
// These are used in uplink_devices.dm to determine whether or not an item is purchasable.
/// This item is purchasable to traitors
#define UPLINK_TRAITORS (1 << 0)
/// This item is purchasable to nuke ops
#define UPLINK_NUKE_OPS (1 << 1)
/// This item is purchasable to clown ops
#define UPLINK_CLOWN_OPS (1 << 2)
+100 -50
View File
@@ -1,17 +1,18 @@
/*
* Holds procs to help with list operations
* Contains groups:
* Misc
* Sorting
* Misc
* Sorting
*/
/*
* Misc
*/
#define LAZYINITLIST(L) if (!L) L = list()
#define LAZYINITLIST(L) if (!L) { L = list(); }
#define UNSETEMPTY(L) if (L && !length(L)) L = null
#define LAZYCOPY(L) (L ? L.Copy() : list() )
///Like LAZYCOPY - copies an input list if the list has entries, If it doesn't the assigned list is nulled
#define LAZYLISTDUPLICATE(L) (L ? L.Copy() : null )
#define LAZYREMOVE(L, I) if(L) { L -= I; if(!length(L)) { L = null; } }
//ambition start
#define LAZYCUT(L, S, E) if((length(L) >= S) && (E == 0 || length(L) >= (E - 1))) { L.Cut(S, E); if(!length(L)) { L = null; } }
@@ -19,17 +20,31 @@
#define LAZYADD(L, I) if(!L) { L = list(); } L += I;
#define LAZYOR(L, I) if(!L) { L = list(); } L |= I;
#define LAZYFIND(L, V) (L ? L.Find(V) : 0)
///returns L[I] if L exists and I is a valid index of L, runtimes if L is not a list
#define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= length(L) ? L[I] : null) : L[I]) : null)
#define LAZYSET(L, K, V) if(!L) { L = list(); } L[K] = V;
#define LAZYLEN(L) length(L)
///This is used to add onto lazy assoc list when the value you're adding is a /list/. This one has extra safety over lazyaddassoc because the value could be null (and thus cant be used to += objects)
#define LAZYADDASSOCLIST(L, K, V) if(!L) { L = list(); } L[K] += list(V);
//Sets a list to null
#define LAZYNULL(L) L = null
#define LAZYCLEARLIST(L) if(L) L.Cut()
#define SANITIZE_LIST(L) ( islist(L) ? L : list() )
#define reverseList(L) reverseRange(L.Copy())
#define LAZYADDASSOC_TG(L, K, V) if(!L) { L = list(); } L[K] += V;
///This is used to add onto lazy assoc list when the value you're adding is a /list/. This one has extra safety over lazyaddassoc because the value could be null (and thus cant be used to += objects)
#define LAZYADDASSOC(L, K, V) if(!L) { L = list(); } L[K] += list(V);
#define LAZYREMOVEASSOC(L, K, V) if(L) { if(L[K]) { L[K] -= V; if(!length(L[K])) L -= K; } if(!length(L)) L = null; }
#define LAZYACCESSASSOC(L, I, K) L ? L[I] ? L[I][K] ? L[I][K] : null : null : null
#define QDEL_LAZYLIST(L) for(var/I in L) qdel(I); L = null;
//These methods don't null the list
#define LAZYCOPY(L) (L ? L.Copy() : list() ) //Use LAZYLISTDUPLICATE instead if you want it to null with no entries
#define LAZYCLEARLIST(L) if(L) L.Cut() // Consider LAZYNULL instead
#define SANITIZE_LIST(L) ( islist(L) ? L : list() )
#define reverseList(L) reverseRange(L.Copy())
/// Performs an insertion on the given lazy list with the given key and value. If the value already exists, a new one will not be made.
#define LAZYORASSOCLIST(lazy_list, key, value) \
LAZYINITLIST(lazy_list); \
LAZYINITLIST(lazy_list[key]); \
lazy_list[key] |= value;
/// Passed into BINARY_INSERT to compare keys
#define COMPARE_KEY __BIN_LIST[__BIN_MID]
@@ -72,7 +87,7 @@
} while(FALSE)
//Returns a list in plain english as a string
/proc/english_list(list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "")
/proc/english_list(list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "" )
var/total = length(input)
switch(total)
if (0)
@@ -95,6 +110,7 @@
/**
* English_list but associative supporting. Higher overhead.
* @depricated
*/
/proc/english_list_assoc(list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "")
var/total = length(input)
@@ -122,6 +138,7 @@
return "[output][and_text][input[index]]"
//Returns list element or null. Should prevent "index out of bounds" error.
/// @depricated
/proc/listgetindex(list/L, index)
if(LAZYLEN(L))
if(isnum(index) && ISINTEGER(index))
@@ -132,17 +149,19 @@
return
//Return either pick(list) or null if list is not of type /list or is empty
/// @depricated
/proc/safepick(list/L)
if(LAZYLEN(L))
return pick(L)
//Checks if the list is empty
/// @depricated
/proc/isemptylist(list/L)
if(!L.len)
return TRUE
return FALSE
//Checks for specific types in a list
//Checks for specific types in a listc
/proc/is_type_in_list(atom/A, list/L)
if(!LAZYLEN(L) || !A)
return FALSE
@@ -183,43 +202,45 @@
/proc/typecache_filter_list_reverse(list/atoms, list/typecache)
RETURN_TYPE(/list)
. = list()
for(var/atom/A as anything in atoms)
if(!typecache[A.type])
. += A
for(var/atom/atom as anything in atoms)
if(!typecache[atom.type])
. += atom
/proc/typecache_filter_multi_list_exclusion(list/atoms, list/typecache_include, list/typecache_exclude)
. = list()
for(var/atom/A as anything in atoms)
if(typecache_include[A.type] && !typecache_exclude[A.type])
. += A
for(var/atom/atom as anything in atoms)
if(typecache_include[atom.type] && !typecache_exclude[atom.type])
. += atom
//Like typesof() or subtypesof(), but returns a typecache instead of a list
///Like typesof() or subtypesof(), but returns a typecache instead of a list
/proc/typecacheof(path, ignore_root_path, only_root_path = FALSE)
if(ispath(path))
var/list/types = list()
var/list/types
var/list/output = list()
if(only_root_path)
types = list(path)
output[path] = TRUE
else
types = ignore_root_path ? subtypesof(path) : typesof(path)
var/list/L = list()
for(var/T in types)
L[T] = TRUE
return L
for(var/T in types)
output[T] = TRUE
return output
else if(islist(path))
var/list/pathlist = path
var/list/L = list()
var/list/output = list()
if(ignore_root_path)
for(var/P in pathlist)
for(var/T in subtypesof(P))
L[T] = TRUE
for(var/current_path in pathlist)
for(var/subtype in subtypesof(current_path))
output[subtype] = TRUE
return output
if(only_root_path)
for(var/current_path in pathlist)
output[current_path] = TRUE
else
for(var/P in pathlist)
if(only_root_path)
L[P] = TRUE
else
for(var/T in typesof(P))
L[T] = TRUE
return L
for(var/current_path in pathlist)
for(var/subpath in typesof(current_path))
output[subpath] = TRUE
return output
/proc/typecacheof_assoc_list(list/pathlist, ignore_root_path = FALSE)
. = list()
@@ -278,9 +299,10 @@
//Picks a random element from a list based on a weighting system:
//1. Adds up the total of weights for each element
//2. Gets the total from 0% to 100% of previous total value.
//2. Gets a number between 1 and that total
//3. For each element in the list, subtracts its weighting from that number
//4. If that makes the number 0 or less, return that element.
//Will output null sometimes if you use decimals (e.g. 0.1 instead of 10) as rand() uses integers, not floats
/proc/pickweight(list/L, base_weight = 1)
var/total = 0
var/item
@@ -289,12 +311,14 @@
L[item] = base_weight
total += L[item]
total = rand() * total
total = rand(base_weight, total)
for (item in L)
total -= L[item]
total -=L [item]
if (total <= 0)
return item
return null
/proc/pickweightAllowZero(list/L) //The original pickweight proc will sometimes pick entries with zero weight. I'm not sure if changing the original will break anything, so I left it be.
var/total = 0
var/item
@@ -366,13 +390,13 @@
//Results will have a length of quality
return results
//Pick a random element from the list and remove it from the list.
/// Pick a random element from the list and remove it from the list.
/proc/pick_n_take(list/L)
RETURN_TYPE(L[_].type)
if(L.len)
var/picked = rand(1,L.len)
. = L[picked]
L.Cut(picked,picked+1) //Cut is far more efficient that Remove()
L.Cut(picked,picked+1) //Cut is far more efficient that Remove()
//Pick a random element from the list by weight and remove it from the list.
//Result is returned as a list in the format list(key, value)
@@ -468,7 +492,7 @@
//uses sortList() but uses the var's name specifically. This should probably be using mergeAtom() instead
/proc/sortNames(list/L, order=1)
return sortTim(L, order >= 0 ? /proc/cmp_name_asc : /proc/cmp_name_dsc)
return sortTim(L.Copy(), order >= 0 ? /proc/cmp_name_asc : /proc/cmp_name_dsc)
//Converts a bitfield to a list of numbers (or words if a wordlist is provided)
@@ -504,10 +528,12 @@
if (L[i] == val)
.++
/// Returns datum/data/record
/proc/find_record(field, value, list/L)
for(var/datum/data/record/R in L)
if(R.fields[field] == value)
return R
return null
//Move a single element from position fromIndex within a list, to position toIndex
@@ -517,10 +543,10 @@
//fromIndex and toIndex must be in the range [1,L.len+1]
//This will preserve associations ~Carnie
/proc/moveElement(list/L, fromIndex, toIndex)
if(fromIndex == toIndex || fromIndex+1 == toIndex) //no need to move
if(fromIndex == toIndex || fromIndex+1 == toIndex) //no need to move
return
if(fromIndex > toIndex)
++fromIndex //since a null will be inserted before fromIndex, the index needs to be nudged right by one
++fromIndex //since a null will be inserted before fromIndex, the index needs to be nudged right by one
L.Insert(toIndex, null)
L.Swap(fromIndex, toIndex)
@@ -532,10 +558,10 @@
//This will preserve associations ~Carnie
/proc/moveRange(list/L, fromIndex, toIndex, len=1)
var/distance = abs(toIndex - fromIndex)
if(len >= distance) //there are more elements to be moved than the distance to be moved. Therefore the same result can be achieved (with fewer operations) by moving elements between where we are and where we are going. The result being, our range we are moving is shifted left or right by dist elements
if(len >= distance) //there are more elements to be moved than the distance to be moved. Therefore the same result can be achieved (with fewer operations) by moving elements between where we are and where we are going. The result being, our range we are moving is shifted left or right by dist elements
if(fromIndex <= toIndex)
return //no need to move
fromIndex += len //we want to shift left instead of right
return //no need to move
fromIndex += len //we want to shift left instead of right
for(var/i=0, i<distance, ++i)
L.Insert(fromIndex, null)
@@ -555,7 +581,7 @@
//Note: if the two ranges overlap, only the destination order will be preserved fully, since some elements will be within both ranges ~Carnie
/proc/swapRange(list/L, fromIndex, toIndex, len=1)
var/distance = abs(toIndex - fromIndex)
if(len > distance) //there is an overlap, therefore swapping each element will require more swaps than inserting new elements
if(len > distance) //there is an overlap, therefore swapping each element will require more swaps than inserting new elements
if(fromIndex < toIndex)
toIndex += len
else
@@ -601,6 +627,12 @@
if(D.vars[varname] == value)
return D
//remove all nulls from a list
/proc/removeNullsFromList(list/L)
while(L.Remove(null))
continue
return L
//Copies a list, and all lists inside it recusively
//Does not copy any other reference type
/proc/deepCopyList(list/l)
@@ -633,11 +665,6 @@
used_key_list[input_key] = 1
return input_key
#if DM_VERSION > 514
#error Remie said that lummox was adding a way to get a lists
#error contents via list.values, if that is true remove this
#error otherwise, update the version and bug lummox
#endif
//Flattens a keyed list into a list of it's contents
/proc/flatten_list(list/key_list)
if(!islist(key_list))
@@ -714,6 +741,29 @@
ret += key
return ret
/proc/compare_list(list/l,list/d)
if(!islist(l) || !islist(d))
return FALSE
if(l.len != d.len)
return FALSE
for(var/i in 1 to l.len)
if(l[i] != d[i])
return FALSE
return TRUE
#define LAZY_LISTS_OR(left_list, right_list)\
( length(left_list)\
? length(right_list)\
? (left_list | right_list)\
: left_list.Copy()\
: length(right_list)\
? right_list.Copy()\
: null\
)
/proc/is_type_in_ref_list(path, list/L)
if(!ispath(path))//not a path
return
+13
View File
@@ -88,6 +88,19 @@
if (CONFIG_GET(flag/log_access))
WRITE_LOG(GLOB.world_game_log, "ACCESS: [text]")
/**
* Writes to a special log file if the log_suspicious_login config flag is set,
* which is intended to contain all logins that failed under suspicious circumstances.
*
* Mirrors this log entry to log_access when access_log_mirror is TRUE, so this proc
* doesn't need to be used alongside log_access and can replace it where appropriate.
*/
/proc/log_suspicious_login(text, access_log_mirror = TRUE)
if (CONFIG_GET(flag/log_suspicious_login))
WRITE_LOG(GLOB.world_suspicious_login_log, "SUSPICIOUS_ACCESS: [text]")
if(access_log_mirror)
log_access(text)
/proc/log_law(text)
if (CONFIG_GET(flag/log_law))
WRITE_LOG(GLOB.world_game_log, "LAW: [text]")
+5 -1
View File
@@ -396,12 +396,16 @@
/proc/ScreenText(obj/O, maptext="", screen_loc="CENTER-7,CENTER-7", maptext_height=480, maptext_width=480)
if(!isobj(O))
O = new /atom/movable/screen/text()
O.maptext = maptext
O.maptext = MAPTEXT(maptext)
O.maptext_height = maptext_height
O.maptext_width = maptext_width
O.screen_loc = screen_loc
return O
/// Removes an image from a client's `.images`. Useful as a callback.
/proc/remove_image_from_client(image/image, client/remove_from)
remove_from?.images -= image
/proc/remove_images_from_clients(image/I, list/show_to)
for(var/client/C in show_to)
C.images -= I
-10
View File
@@ -86,16 +86,6 @@
// Keybindings
init_keybindings()
//Uplink Items
for(var/path in subtypesof(/datum/uplink_item))
var/datum/uplink_item/I = path
if(!initial(I.item)) //We add categories to a separate list.
GLOB.uplink_categories |= initial(I.category)
continue
GLOB.uplink_items += path
//(sub)typesof entries are listed by the order they are loaded in the code, so we'll have to rearrange them here.
GLOB.uplink_items = sortList(GLOB.uplink_items, /proc/cmp_uplink_items_dsc)
init_subtypes(/datum/crafting_recipe, GLOB.crafting_recipes)
INVOKE_ASYNC(GLOBAL_PROC, /proc/init_ref_coin_values) //so the current procedure doesn't sleep because of UNTIL()
+1 -1
View File
@@ -992,7 +992,7 @@ world
letter = lowertext(letter)
var/image/text_image = new(loc = A)
text_image.maptext = "<font size = 4>[letter]</font>"
text_image.maptext = MAPTEXT("<font size = 4>[letter]</font>")
text_image.pixel_x = 7
text_image.pixel_y = 5
qdel(atom_icon)
@@ -1,85 +1,3 @@
/matrix/proc/TurnTo(old_angle, new_angle)
. = new_angle - old_angle
Turn(.) //BYOND handles cases such as -270, 360, 540 etc. DOES NOT HANDLE 180 TURNS WELL, THEY TWEEN AND LOOK LIKE SHIT
/atom/proc/SpinAnimation(speed = 10, loops = -1, clockwise = 1, segments = 3, parallel = TRUE)
if(!segments)
return
var/segment = 360/segments
if(!clockwise)
segment = -segment
var/list/matrices = list()
for(var/i in 1 to segments-1)
var/matrix/M = matrix(transform)
M.Turn(segment*i)
matrices += M
var/matrix/last = matrix(transform)
matrices += last
speed /= segments
if(parallel)
animate(src, transform = matrices[1], time = speed, loops , flags = ANIMATION_PARALLEL)
else
animate(src, transform = matrices[1], time = speed, loops)
for(var/i in 2 to segments) //2 because 1 is covered above
animate(transform = matrices[i], time = speed)
//doesn't have an object argument because this is "Stacking" with the animate call above
//3 billion% intentional
//Dumps the matrix data in format a-f
/matrix/proc/tolist()
. = list()
. += a
. += b
. += c
. += d
. += e
. += f
//Dumps the matrix data in a matrix-grid format
/*
a d 0
b e 0
c f 1
*/
/matrix/proc/togrid()
. = list()
. += a
. += d
. += 0
. += b
. += e
. += 0
. += c
. += f
. += 1
//The X pixel offset of this matrix
/matrix/proc/get_x_shift()
. = c
//The Y pixel offset of this matrix
/matrix/proc/get_y_shift()
. = f
/matrix/proc/get_x_skew()
. = b
/matrix/proc/get_y_skew()
. = d
//Skews a matrix in a particular direction
//Missing arguments are treated as no skew in that direction
//As Rotation is defined as a scale+skew, these procs will break any existing rotation
//Unless the result is multiplied against the current matrix
/matrix/proc/set_skew(x = 0, y = 0)
b = x
d = y
/////////////////////
// COLOUR MATRICES //
/////////////////////
@@ -114,12 +32,64 @@ list(0.393,0.349,0.272,0, 0.769,0.686,0.534,0, 0.189,0.168,0.131,0, 0,0,0,1, 0,0
return list(R + value,R,R,0, G,G + value,G,0, B,B,B + value,0, 0,0,0,1, 0,0,0,0)
/**
* Exxagerates or removes colors
*/
/proc/color_matrix_saturation_percent(percent)
if(percent == 0)
return color_matrix_identity()
percent = clamp(percent, -100, 100)
if(percent > 0)
percent *= 3
var/x = 1 + percent / 100
var/inv = 1 - x
var/R = LUMA_R * inv
var/G = LUMA_G * inv
var/B = LUMA_B * inv
return list(R + x,R,R, G,G + x,G, B,B,B + x)
//Changes distance colors have from rgb(127,127,127) grey
//1 is identity. 0 makes everything grey >1 blows out colors and greys
/proc/color_matrix_contrast(value)
var/add = (1 - value) / 2
return list(value,0,0,0, 0,value,0,0, 0,0,value,0, 0,0,0,1, add,add,add,0)
/**
* Exxagerates or removes brightness
*/
/proc/color_matrix_contrast_percent(percent)
var/static/list/delta_index = list(
0, 0.01, 0.02, 0.04, 0.05, 0.06, 0.07, 0.08, 0.1, 0.11,
0.12, 0.14, 0.15, 0.16, 0.17, 0.18, 0.20, 0.21, 0.22, 0.24,
0.25, 0.27, 0.28, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.42,
0.44, 0.46, 0.48, 0.5, 0.53, 0.56, 0.59, 0.62, 0.65, 0.68,
0.71, 0.74, 0.77, 0.80, 0.83, 0.86, 0.89, 0.92, 0.95, 0.98,
1.0, 1.06, 1.12, 1.18, 1.24, 1.30, 1.36, 1.42, 1.48, 1.54,
1.60, 1.66, 1.72, 1.78, 1.84, 1.90, 1.96, 2.0, 2.12, 2.25,
2.37, 2.50, 2.62, 2.75, 2.87, 3.0, 3.2, 3.4, 3.6, 3.8,
4.0, 4.3, 4.7, 4.9, 5.0, 5.5, 6.0, 6.5, 6.8, 7.0,
7.3, 7.5, 7.8, 8.0, 8.4, 8.7, 9.0, 9.4, 9.6, 9.8,
10.0)
percent = clamp(percent, -100, 100)
if(percent == 0)
return color_matrix_identity()
var/x = 0
if (percent < 0)
x = 127 + percent / 100 * 127;
else
x = percent % 1
if(x == 0)
x = delta_index[percent]
else
x = delta_index[percent] * (1-x) + delta_index[percent+1] * x//use linear interpolation for more granularity.
x = x * 127 + 127
var/mult = x / 127
var/add = 0.5 * (127-x) / 255
return list(mult,0,0, 0,mult,0, 0,0,mult, add,add,add)
//Moves all colors angle degrees around the color wheel while maintaining intensity of the color and not affecting greys
//0 is identity, 120 moves reds to greens, 240 moves reds to blues
/proc/color_matrix_rotate_hue(angle)
@@ -134,6 +104,26 @@ round(cos_inv_third+sqrt3_sin, 0.001), round(cos_inv_third-sqrt3_sin, 0.001), ro
0,0,0,1,
0,0,0,0)
/**
* Moves all colors angle degrees around the color wheel while maintaining intensity of the color and not affecting whites
* TODO: Need a version that only affects one color (ie shift red to blue but leave greens and blues alone)
*/
/proc/color_matrix_rotation(angle)
if(angle == 0)
return color_matrix_identity()
angle = clamp(angle, -180, 180)
var/cos = cos(angle)
var/sin = sin(angle)
var/constA = 0.143
var/constB = 0.140
var/constC = -0.283
return list(
LUMA_R + cos * (1-LUMA_R) + sin * -LUMA_R, LUMA_R + cos * -LUMA_R + sin * constA, LUMA_R + cos * -LUMA_R + sin * -(1-LUMA_R),
LUMA_G + cos * -LUMA_G + sin * -LUMA_G, LUMA_G + cos * (1-LUMA_G) + sin * constB, LUMA_G + cos * -LUMA_G + sin * LUMA_G,
LUMA_B + cos * -LUMA_B + sin * (1-LUMA_B), LUMA_B + cos * -LUMA_B + sin * constC, LUMA_B + cos * (1-LUMA_B) + sin * LUMA_B
)
//These next three rotate values about one axis only
//x is the red axis, y is the green axis, z is the blue axis.
/proc/color_matrix_rotate_x(angle)
@@ -183,3 +173,9 @@ round(cos_inv_third+sqrt3_sin, 0.001), round(cos_inv_third-sqrt3_sin, 0.001), ro
*/
/proc/rgb_construct_color_matrix(rr = 1, rg, rb, gr, gg = 1, gb, br, bg, bb = 1, cr, cg, cb)
return list(rr, rg, rb, gr, gg, gb, br, bg, bb, cr, cg, cb)
/**
* Assembles a color matrix, defaulting to identity
*/
/proc/rgba_construct_color_matrix(rr = 1, rg, rb, ra, gr, gg = 1, gb, ga, br, bg, bb = 1, ba, ar, ag, ab, aa = 1, cr, cg, cb, ca)
return list(rr, rg, rb, ra, gr, gg, gb, ga, br, bg, bb, ba, ar, ag, ab, aa, cr, cg, cb, ca)
@@ -0,0 +1,86 @@
/matrix/proc/TurnTo(old_angle, new_angle)
. = new_angle - old_angle
Turn(.) //BYOND handles cases such as -270, 360, 540 etc. DOES NOT HANDLE 180 TURNS WELL, THEY TWEEN AND LOOK LIKE SHIT
/atom/proc/SpinAnimation(speed = 10, loops = -1, clockwise = 1, segments = 3, parallel = TRUE)
if(!segments)
return
var/segment = 360/segments
if(!clockwise)
segment = -segment
var/list/matrices = list()
for(var/i in 1 to segments-1)
var/matrix/M = matrix(transform)
M.Turn(segment*i)
matrices += M
var/matrix/last = matrix(transform)
matrices += last
speed /= segments
if(parallel)
animate(src, transform = matrices[1], time = speed, loops , flags = ANIMATION_PARALLEL)
else
animate(src, transform = matrices[1], time = speed, loops)
for(var/i in 2 to segments) //2 because 1 is covered above
animate(transform = matrices[i], time = speed)
//doesn't have an object argument because this is "Stacking" with the animate call above
//3 billion% intentional
//Dumps the matrix data in format a-f
/matrix/proc/tolist()
. = list()
. += a
. += b
. += c
. += d
. += e
. += f
//Dumps the matrix data in a matrix-grid format
/*
a d 0
b e 0
c f 1
*/
/matrix/proc/togrid()
. = list()
. += a
. += d
. += 0
. += b
. += e
. += 0
. += c
. += f
. += 1
//The X pixel offset of this matrix
/matrix/proc/get_x_shift()
. = c
//The Y pixel offset of this matrix
/matrix/proc/get_y_shift()
. = f
/matrix/proc/get_x_skew()
. = b
/matrix/proc/get_y_skew()
. = d
//Skews a matrix in a particular direction
//Missing arguments are treated as no skew in that direction
//As Rotation is defined as a scale+skew, these procs will break any existing rotation
//Unless the result is multiplied against the current matrix
/matrix/proc/set_skew(x = 0, y = 0)
b = x
d = y
/**
* constructs a transform matrix, defaulting to identity
*/
/proc/transform_matrix_construct(a = 1, b, c, d = 1, e, f)
return matrix(a, b, c, d, e, f)
+15
View File
@@ -458,6 +458,21 @@ GLOBAL_LIST_EMPTY(species_datums)
if(!HAS_TRAIT(L, TRAIT_PASSTABLE))
L.pass_flags &= ~PASSTABLE
/proc/dance_rotate(atom/movable/AM, datum/callback/callperrotate, set_original_dir=FALSE)
set waitfor = FALSE
var/originaldir = AM.dir
for(var/i in list(NORTH,SOUTH,EAST,WEST,EAST,SOUTH,NORTH,SOUTH,EAST,WEST,EAST,SOUTH))
if(!AM)
return
AM.setDir(i)
callperrotate?.Invoke()
sleep(1)
if(set_original_dir)
AM.setDir(originaldir)
/// Gets the client of the mob, allowing for mocking of the client.
/// You only need to use this if you know you're going to be mocking clients somewhere else.
#define GET_CLIENT(mob) (##mob.client || ##mob.mock_client)
//check if the person is dead, not sure where to put this
#define IS_DEAD_OR_INCAP(source) (source.incapacitated() || source.stat)
+47 -5
View File
@@ -1,8 +1,10 @@
/proc/priority_announce(text, title = "", sound = "attention", type , sender_override)
/proc/priority_announce(text, title = "", sound, type , sender_override, has_important_message)
if(!text)
return
var/announcement
if(!sound)
sound = "attention"
if(type == "Priority")
announcement += "<h1 class='alert'>Priority Announcement</h1>"
@@ -26,7 +28,11 @@
else
GLOB.news_network.SubmitArticle(title + "<br><br>" + text, "Central Command", "Station Announcements", null)
announcement += "<br><span class='alert'>[html_encode(text)]</span><br>"
///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>"
announcement += "<br>"
var/s = sound(get_announcer_sound(sound))
@@ -127,12 +133,44 @@
if("welcome")
. = 'sound/announcer/medibot/welcome.ogg'
/**
* Summon the crew for an emergency meeting
*
* Teleports the crew to a specified area, and tells everyone (via an announcement) who called the meeting. Should only be used during april fools!
* Arguments:
* * user - Mob who called the meeting
* * button_zone - Area where the meeting was called and where everyone will get teleported to
*/
/proc/call_emergency_meeting(mob/living/user, area/button_zone)
var/meeting_sound = sound('sound/misc/emergency_meeting.ogg')
var/announcement
announcement += "<h1 class='alert'>Captain Alert</h1>"
announcement += "<br>[span_alert("[user] has called an Emergency Meeting!")]<br><br>"
for(var/mob/mob_to_teleport in GLOB.player_list) //gotta make sure the whole crew's here!
if(isnewplayer(mob_to_teleport) || iscameramob(mob_to_teleport))
continue
to_chat(mob_to_teleport, announcement)
SEND_SOUND(mob_to_teleport, meeting_sound) //no preferences here, you must hear the funny sound
mob_to_teleport.overlay_fullscreen("emergency_meeting", /atom/movable/screen/fullscreen/scaled/emergency_meeting, 1)
addtimer(CALLBACK(mob_to_teleport, /mob/.proc/clear_fullscreen, "emergency_meeting"), 3 SECONDS)
if (is_station_level(mob_to_teleport.z)) //teleport the mob to the crew meeting
var/turf/target
var/list/turf_list = get_area_turfs(button_zone)
while (!target && turf_list.len)
target = pick_n_take(turf_list)
if (isclosedturf(target))
target = null
continue
mob_to_teleport.forceMove(target)
/proc/print_command_report(text = "", title = null, announce=TRUE)
if(!title)
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")
priority_announce("A report has been downloaded and printed out at all communications consoles.", "Incoming Classified Message", "commandreport", has_important_message = TRUE)
var/datum/comm_message/M = new
M.title = title
@@ -140,13 +178,17 @@
SScommunications.send_message(M)
/proc/minor_announce(message, title = "Attention:", alert)
/proc/minor_announce(message, title = "Attention:", alert, html_encode = TRUE)
if(!message)
return
if (html_encode)
title = html_encode(title)
message = html_encode(message)
for(var/mob/M in GLOB.player_list)
if(!isnewplayer(M) && M.can_hear())
to_chat(M, "<span class='big bold'><font color = red>[html_encode(title)]</font color><BR>[html_encode(message)]</span><BR>")
to_chat(M, "[span_minorannounce("<font color = red>[title]</font color><BR>[message]")]<BR>")
if(M.client.prefs.toggles & SOUND_ANNOUNCEMENTS)
if(alert)
SEND_SOUND(M, sound('sound/misc/notice1.ogg'))
+17 -3
View File
@@ -1,4 +1,4 @@
// Ensure the frequency is within bounds of what it should be sending/receiving at
/// Ensure the frequency is within bounds of what it should be sending/receiving at
/proc/sanitize_frequency(frequency, free = FALSE)
frequency = round(frequency)
if(free)
@@ -8,12 +8,26 @@
if(!(. % 2)) // Ensure the last digit is an odd number
. += 1
// Format frequency by moving the decimal.
/// Format frequency by moving the decimal.
/proc/format_frequency(frequency)
frequency = text2num(frequency)
return "[round(frequency / 10)].[frequency % 10]"
//Opposite of format, returns as a number
///Opposite of format, returns as a number
/proc/unformat_frequency(frequency)
frequency = text2num(frequency)
return frequency * 10
///returns a random unused frequency between MIN_FREE_FREQ & MAX_FREE_FREQ if free = TRUE, and MIN_FREQ & MAX_FREQ if FALSE
/proc/return_unused_frequency(free = FALSE)
var/start = free ? MIN_FREE_FREQ : MIN_FREQ
var/end = free ? MAX_FREE_FREQ : MAX_FREQ
var/freq_to_check = 0
do
freq_to_check = rand(start, end)
if(!(freq_to_check % 2)) // Ensure the last digit is an odd number
freq_to_check++
while((freq_to_check == 0) || ("[freq_to_check]" in GLOB.reverseradiochannels))
return freq_to_check
+2 -2
View File
@@ -590,8 +590,8 @@
var/list/all_teams = list()
var/list/all_antagonists = list()
// for(var/datum/team/A in GLOB.antagonist_teams)
// all_teams |= A
for(var/datum/team/A in GLOB.antagonist_teams)
all_teams |= A
for(var/datum/antagonist/A in GLOB.antagonists)
if(!A.owner)
+2 -2
View File
@@ -591,9 +591,9 @@
switch(child)
if(/datum)
return null
if(/obj || /mob)
if(/obj, /mob)
return /atom/movable
if(/area || /turf)
if(/area, /turf)
return /atom
else
return /datum
+3 -3
View File
@@ -663,10 +663,10 @@ Turf and target are separate in case you want to teleport some distance from a t
return locate(final_x, final_y, T.z)
//Finds the distance between two atoms, in pixels
//centered = 0 counts from turf edge to edge
//centered = 1 counts from turf center to turf center
//centered = FALSE counts from turf edge to edge
//centered = TRUE counts from turf center to turf center
//of course mathematically this is just adding world.icon_size on again
/proc/getPixelDistance(atom/A, atom/B, centered = 1)
/proc/getPixelDistance(atom/A, atom/B, centered = TRUE)
if(!istype(A)||!istype(B))
return 0
. = bounds_dist(A, B) + sqrt((((A.pixel_x+B.pixel_x)**2) + ((A.pixel_y+B.pixel_y)**2)))
+7 -1
View File
@@ -216,7 +216,13 @@ GLOBAL_LIST_INIT(jumpsuitlist, list(PREF_SUIT, PREF_SKIRT))
#define UPLINK_PDA "PDA"
#define UPLINK_RADIO "Radio"
#define UPLINK_PEN "Pen" //like a real spy!
GLOBAL_LIST_INIT(uplink_spawn_loc_list, list(UPLINK_PDA, UPLINK_RADIO, UPLINK_PEN))
#define UPLINK_IMPLANT "Implant"
#define UPLINK_IMPLANT_WITH_PRICE "[UPLINK_IMPLANT] (-[UPLINK_IMPLANT_TELECRYSTAL_COST] TC)"
// What we show to the user
GLOBAL_LIST_INIT(uplink_spawn_loc_list, list(UPLINK_PDA, UPLINK_RADIO, UPLINK_PEN, UPLINK_IMPLANT_WITH_PRICE))
// What is actually saved; if the uplink implant price changes, it won't affect save files then
GLOBAL_LIST_INIT(uplink_spawn_loc_list_save, list(UPLINK_PDA, UPLINK_RADIO, UPLINK_PEN, UPLINK_IMPLANT))
//List of cached alpha masked icons.
GLOBAL_LIST_EMPTY(alpha_masked_worn_icons)
+2
View File
@@ -52,6 +52,8 @@ GLOBAL_LIST_EMPTY(current_observers_list)
//Dynamic Port
GLOBAL_LIST_EMPTY(new_player_list) //all /mob/dead/new_player, in theory all should have clients and those that don't are in the process of spawning and get deleted when done.
//Family Port
GLOBAL_LIST_EMPTY(pre_setup_antags) //minds that have been picked as antag by the gamemode. removed as antag datums are set.
/proc/update_config_movespeed_type_lookup(update_mobs = TRUE)
// NOTE: This is entirely based on the fact that byond typesof/subtypesof gets longer/deeper paths before shallower ones.
-1
View File
@@ -19,7 +19,6 @@ GLOBAL_LIST(chemical_reactions_list) //list of all /datum/chemical_reaction d
GLOBAL_LIST(chemical_reagents_list) //list of all /datum/reagent datums indexed by reagent id. Used by chemistry stuff
GLOBAL_LIST_EMPTY(tech_list) //list of all /datum/tech datums indexed by id.
GLOBAL_LIST_EMPTY(surgeries_list) //list of all surgeries by name, associated with their path.
GLOBAL_LIST_EMPTY(uplink_items) //list of all uplink item typepaths, ascendingly sorted by their initial name.
GLOBAL_LIST_EMPTY(uplink_categories) //list of all uplink categories, listed by the order they are loaded in code. Be careful.
GLOBAL_LIST_EMPTY(crafting_recipes) //list of all table craft recipes
GLOBAL_LIST_EMPTY(rcd_list) //list of Rapid Construction Devices.
+3
View File
@@ -2,6 +2,9 @@ GLOBAL_VAR(log_directory)
GLOBAL_PROTECT(log_directory)
GLOBAL_VAR(world_game_log)
GLOBAL_PROTECT(world_game_log)
/// Log associated with [/proc/log_suspicious_login()] - Intended to hold all logins that failed due to suspicious circumstances such as ban detection, CID randomisation etc.
GLOBAL_VAR(world_suspicious_login_log)
GLOBAL_PROTECT(world_suspicious_login_log)
GLOBAL_VAR(world_runtime_log)
GLOBAL_PROTECT(world_runtime_log)
GLOBAL_VAR(world_qdel_log)
+1
View File
@@ -0,0 +1 @@
GLOBAL_DATUM(changelog_tgui, /datum/changelog)
+2
View File
@@ -38,6 +38,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_RESISTCOLD" = TRAIT_RESISTCOLD,
"TRAIT_RESISTHIGHPRESSURE" = TRAIT_RESISTHIGHPRESSURE,
"TRAIT_RESISTLOWPRESSURE" = TRAIT_RESISTLOWPRESSURE,
"TRAIT_LOWPRESSURECOOLING" = TRAIT_LOWPRESSURECOOLING,
"TRAIT_BOMBIMMUNE" = TRAIT_BOMBIMMUNE,
"TRAIT_RADIMMUNE" = TRAIT_RADIMMUNE,
"TRAIT_GENELESS" = TRAIT_GENELESS,
@@ -55,6 +56,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_ROBOTIC_ORGANISM" = TRAIT_ROBOTIC_ORGANISM,
"TRAIT_ROBOT_RADSHIELDING" = TRAIT_ROBOT_RADSHIELDING,
"TRAIT_NOBREATH" = TRAIT_NOBREATH,
"TRAIT_AUXILIARY_LUNGS" = TRAIT_AUXILIARY_LUNGS,
"TRAIT_ANTIMAGIC" = TRAIT_ANTIMAGIC,
"TRAIT_HOLY" = TRAIT_HOLY,
"TRAIT_DEPRESSION" = TRAIT_DEPRESSION,
-45
View File
@@ -470,51 +470,6 @@
else
setDir(WEST, ismousemovement)
//debug
/atom/movable/screen/proc/scale_to(x1,y1)
if(!y1)
y1 = x1
var/matrix/M = new
M.Scale(x1,y1)
transform = M
/atom/movable/screen/click_catcher
icon = 'icons/mob/screen_gen.dmi'
icon_state = "catcher"
plane = CLICKCATCHER_PLANE
mouse_opacity = MOUSE_OPACITY_OPAQUE
screen_loc = "CENTER"
#define MAX_SAFE_BYOND_ICON_SCALE_TILES (MAX_SAFE_BYOND_ICON_SCALE_PX / world.icon_size)
#define MAX_SAFE_BYOND_ICON_SCALE_PX (33 * 32) //Not using world.icon_size on purpose.
/atom/movable/screen/click_catcher/proc/UpdateGreed(view_size_x = 15, view_size_y = 15)
var/icon/newicon = icon('icons/mob/screen_gen.dmi', "catcher")
var/ox = min(MAX_SAFE_BYOND_ICON_SCALE_TILES, view_size_x)
var/oy = min(MAX_SAFE_BYOND_ICON_SCALE_TILES, view_size_y)
var/px = view_size_x * world.icon_size
var/py = view_size_y * world.icon_size
var/sx = min(MAX_SAFE_BYOND_ICON_SCALE_PX, px)
var/sy = min(MAX_SAFE_BYOND_ICON_SCALE_PX, py)
newicon.Scale(sx, sy)
icon = newicon
screen_loc = "CENTER-[(ox-1)*0.5],CENTER-[(oy-1)*0.5]"
var/matrix/M = new
M.Scale(px/sx, py/sy)
transform = M
/atom/movable/screen/click_catcher/Click(location, control, params)
var/list/modifiers = params2list(params)
if(modifiers["middle"] && iscarbon(usr))
var/mob/living/carbon/C = usr
C.swap_hand()
else
var/turf/T = params2turf(modifiers["screen-loc"], get_turf(usr.client ? usr.client.eye : usr), usr.client)
params += "&catcher=1"
if(T)
T.Click(location, control, params)
. = 1
/* MouseWheelOn */
/mob/proc/MouseWheelOn(atom/A, delta_x, delta_y, params)
+2 -3
View File
@@ -176,9 +176,6 @@
#define ui_ghost_mafia "SOUTH: 6, CENTER+2:24"
#define ui_ghost_spawners "SOUTH: 6, CENTER+1:24" // LEGACY. SAME LOC AS PAI
// #define ui_wanted_lvl "NORTH,11"
//UI position overrides for 1:1 screen layout. (default is 7:5)
#define ui_stamina "EAST-1:28,CENTER:17" // replacing internals button
#define ui_overridden_resist "EAST-3:24,SOUTH+1:7"
@@ -190,3 +187,5 @@
#define ui_boxarea "EAST-4:6,SOUTH+1:6"
#define ui_boxlang "EAST-5:22,SOUTH+1:6"
#define ui_boxvore "EAST-5:22,SOUTH+1:6"
#define ui_wanted_lvl "NORTH,11"
+130 -45
View File
@@ -2,9 +2,6 @@
//PUBLIC - call these wherever you want
/mob/proc/throw_alert(category, type, severity, obj/new_master, override = FALSE)
/* Proc to create or update an alert. Returns the alert if the alert is new or updated, 0 if it was thrown already
category is a text string. Each mob may only have one alert per category; the previous one will be replaced
path is a type path of the actual alert type to throw
@@ -14,6 +11,7 @@
Clicks are forwarded to master
Override makes it so the alert is not replaced until cleared by a clear_alert with clear_override, and it's used for hallucinations.
*/
/mob/proc/throw_alert(category, type, severity, obj/new_master, override = FALSE)
if(!category || QDELETED(src))
return
@@ -42,7 +40,7 @@
thealert.override_alerts = override
if(override)
thealert.timeout = null
thealert.mob_viewer = src
thealert.owner = src
if(new_master)
var/old_layer = new_master.layer
@@ -97,8 +95,10 @@
var/severity = 0
var/alerttooltipstyle = ""
var/override_alerts = FALSE //If it is overriding other alerts of the same type
var/mob/mob_viewer //the mob viewing this alert
var/mob/owner //Alert owner
/// Boolean. If TRUE, the Click() proc will attempt to Click() on the master first if there is a master.
var/click_master = TRUE
/atom/movable/screen/alert/MouseEntered(location,control,params)
if(!QDELETED(src))
@@ -251,6 +251,8 @@ or something covering your eyes."
/atom/movable/screen/alert/mind_control/Click()
var/mob/living/L = usr
if(L != owner)
return
to_chat(L, "<span class='mind_control'>[command]</span>")
/atom/movable/screen/alert/hypnosis
@@ -271,7 +273,7 @@ If you're feeling frisky, examine yourself and click the underlined item to pull
icon_state = "embeddedobject"
/atom/movable/screen/alert/embeddedobject/Click()
if(isliving(usr))
if(isliving(usr) && usr == owner)
var/mob/living/carbon/M = usr
return M.help_shake_act(M)
@@ -300,7 +302,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
/atom/movable/screen/alert/fire/Click()
var/mob/living/L = usr
if(!istype(L) || !L.can_resist())
if(!istype(L) || !L.can_resist() || L != owner)
return
L.MarkResistTime()
if(CHECK_MOBILITY(L, MOBILITY_MOVE))
@@ -308,37 +310,110 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
/atom/movable/screen/alert/give // information set when the give alert is made
icon_state = "default"
var/mob/living/carbon/giver
var/mob/living/carbon/offerer
var/obj/item/receiving
/**
* Handles assigning most of the variables for the alert that pops up when an item is offered
*
* Handles setting the name, description and icon of the alert and tracking the person giving
* and the item being offered, also registers a signal that removes the alert from anyone who moves away from the giver
* Arguments:
* * taker - The person receiving the alert
* * giver - The person giving the alert and item
* * receiving - The item being given by the giver
*/
/atom/movable/screen/alert/give/proc/setup(mob/living/carbon/taker, mob/living/carbon/giver, obj/item/receiving)
name = "[giver] is offering [receiving]"
desc = "[giver] is offering [receiving]. Click this alert to take it."
* Handles assigning most of the variables for the alert that pops up when an item is offered
*
* Handles setting the name, description and icon of the alert and tracking the person giving
* and the item being offered, also registers a signal that removes the alert from anyone who moves away from the offerer
* Arguments:
* * taker - The person receiving the alert
* * offerer - The person giving the alert and item
* * receiving - The item being given by the offerer
*/
/atom/movable/screen/alert/give/proc/setup(mob/living/carbon/taker, mob/living/carbon/offerer, obj/item/receiving)
name = "[offerer] is offering [receiving]"
desc = "[offerer] is offering [receiving]. Click this alert to take it."
icon_state = "template"
cut_overlays()
add_overlay(receiving)
src.receiving = receiving
src.giver = giver
RegisterSignal(taker, COMSIG_MOVABLE_MOVED, .proc/removeAlert)
/atom/movable/screen/alert/give/proc/removeAlert()
to_chat(usr, "<span class='warning'>You moved out of range of [giver]!</span>")
usr.clear_alert("[giver]")
src.offerer = offerer
RegisterSignal(taker, COMSIG_MOVABLE_MOVED, .proc/check_in_range, override = TRUE) //Override to prevent runtimes when people offer a item multiple times
/atom/movable/screen/alert/give/Click(location, control, params)
. = ..()
var/mob/living/carbon/C = usr
C.take(giver, receiving)
if(!.)
return
if(!iscarbon(usr))
CRASH("User for [src] is of type \[[usr.type]\]. This should never happen.")
handle_transfer()
/// An overrideable proc used simply to hand over the item when claimed, this is a proc so that high-fives can override them since nothing is actually transferred
/atom/movable/screen/alert/give/proc/handle_transfer()
var/mob/living/carbon/taker = owner
taker.take(offerer, receiving)
/// Simply checks if the other person is still in range
/atom/movable/screen/alert/give/proc/check_in_range(atom/taker)
SIGNAL_HANDLER
if(!offerer.CanReach(taker))
to_chat(owner, span_warning("You moved out of range of [offerer]!"))
owner.clear_alert("[offerer]")
/atom/movable/screen/alert/give/highfive/setup(mob/living/carbon/taker, mob/living/carbon/offerer, obj/item/receiving)
. = ..()
name = "[offerer] is offering a high-five!"
desc = "[offerer] is offering a high-five! Click this alert to slap it."
RegisterSignal(offerer, COMSIG_PARENT_EXAMINE_MORE, .proc/check_fake_out)
/atom/movable/screen/alert/give/highfive/handle_transfer()
var/mob/living/carbon/taker = owner
if(receiving && (receiving in offerer.held_items))
receiving.on_offer_taken(offerer, taker)
return
too_slow_p1()
/// If the person who offered the high five no longer has it when we try to accept it, we get pranked hard
/atom/movable/screen/alert/give/highfive/proc/too_slow_p1()
var/mob/living/carbon/rube = owner
if(!rube || !offerer)
qdel(src)
return
offerer.visible_message(span_notice("[rube] rushes in to high-five [offerer], but-"), span_nicegreen("[rube] falls for your trick just as planned, lunging for a high-five that no longer exists! Classic!"), ignored_mobs=rube)
to_chat(rube, span_nicegreen("You go in for [offerer]'s high-five, but-"))
addtimer(CALLBACK(src, .proc/too_slow_p2, offerer, rube), 0.5 SECONDS)
/// Part two of the ultimate prank
/atom/movable/screen/alert/give/highfive/proc/too_slow_p2()
var/mob/living/carbon/rube = owner
if(!rube || !offerer)
qdel(src)
return
offerer.visible_message(span_danger("[offerer] pulls away from [rube]'s slap at the last second, dodging the high-five entirely!"), span_nicegreen("[rube] fails to make contact with your hand, making an utter fool of [rube.p_them()]self!"), span_hear("You hear a disappointing sound of flesh not hitting flesh!"), ignored_mobs=rube)
var/all_caps_for_emphasis = uppertext("NO! [offerer] PULLS [offerer.p_their()] HAND AWAY FROM YOURS! YOU'RE TOO SLOW!")
to_chat(rube, span_userdanger("[all_caps_for_emphasis]"))
playsound(offerer, 'sound/weapons/thudswoosh.ogg', 100, TRUE, 1)
rube.Knockdown(1 SECONDS)
SEND_SIGNAL(offerer, COMSIG_ADD_MOOD_EVENT, "high_five", /datum/mood_event/down_low)
SEND_SIGNAL(rube, COMSIG_ADD_MOOD_EVENT, "high_five", /datum/mood_event/too_slow)
qdel(src)
/// If someone examine_more's the offerer while they're trying to pull a too-slow, it'll tip them off to the offerer's trickster ways
/atom/movable/screen/alert/give/highfive/proc/check_fake_out(datum/source, mob/user, list/examine_list)
SIGNAL_HANDLER
if(!receiving)
examine_list += "[span_warning("[offerer]'s arm appears tensed up, as if [offerer.p_they()] plan on pulling it back suddenly...")]\n"
/// Families handshakes
/atom/movable/screen/alert/give/secret_handshake
icon_state = "default"
/atom/movable/screen/alert/give/secret_handshake/setup(mob/living/carbon/taker, mob/living/carbon/offerer, obj/item/receiving)
name = "[offerer] is offering a Handshake"
desc = "[offerer] wants to teach you the Secret Handshake for their Family and induct you! Click on this alert to accept."
icon_state = "template"
cut_overlays()
add_overlay(receiving)
src.receiving = receiving
src.offerer = offerer
RegisterSignal(taker, COMSIG_MOVABLE_MOVED, .proc/check_in_range, override = TRUE) //Override to prevent runtimes when people offer a item multiple times
//ALIENS
@@ -393,10 +468,10 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
/atom/movable/screen/alert/bloodsense/process()
var/atom/blood_target
if(!mob_viewer.mind)
if(!owner.mind)
return
var/datum/antagonist/cult/antag = mob_viewer.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
var/datum/antagonist/cult/antag = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!antag?.cult_team)
return
var/datum/objective/sacrifice/sac_objective = locate() in antag.cult_team.objectives
@@ -433,7 +508,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
add_overlay(narnar)
return
var/turf/P = get_turf(blood_target)
var/turf/Q = get_turf(mob_viewer)
var/turf/Q = get_turf(owner)
if(!P || !Q || (P.z != Q.z)) //The target is on a different Z level, we cannot sense that far.
icon_state = "runed_sense2"
desc = "You can no longer sense your target's presence."
@@ -497,7 +572,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
for(var/mob/living/L in GLOB.alive_mob_list)
if(is_servant_of_ratvar(L))
servants++
var/datum/antagonist/clockcult/C = mob_viewer.mind.has_antag_datum(/datum/antagonist/clockcult,TRUE)
var/datum/antagonist/clockcult/C = owner.mind.has_antag_datum(/datum/antagonist/clockcult,TRUE)
if(C && C.clock_team)
textlist += "[C.clock_team.eminence ? "There is an Eminence." : "<b>There is no Eminence! Get one ASAP!</b>"]<br>"
textlist += "There are currently <b>[servants]</b> servant[servants > 1 ? "s" : ""] of Ratvar.<br>"
@@ -595,7 +670,7 @@ so as to remain in compliance with the most up-to-date laws."
var/atom/target = null
/atom/movable/screen/alert/hackingapc/Click()
if(!usr || !usr.client)
if(!usr || !usr.client || usr != owner)
return
if(!target)
return
@@ -621,7 +696,7 @@ so as to remain in compliance with the most up-to-date laws."
timeout = 300
/atom/movable/screen/alert/notify_cloning/Click()
if(!usr || !usr.client)
if(!usr || !usr.client || usr != owner)
return
var/mob/dead/observer/G = usr
G.reenter_corpse()
@@ -635,7 +710,7 @@ so as to remain in compliance with the most up-to-date laws."
var/action = NOTIFY_JUMP
/atom/movable/screen/alert/notify_action/Click()
if(!usr || !usr.client)
if(!usr || !usr.client || usr != owner)
return
if(!target)
return
@@ -669,14 +744,14 @@ so as to remain in compliance with the most up-to-date laws."
/atom/movable/screen/alert/restrained/Click()
var/mob/living/L = usr
if(!istype(L) || !L.can_resist())
if(!istype(L) || !L.can_resist() || L != owner)
return
L.MarkResistTime()
return L.resist_restraints()
/atom/movable/screen/alert/restrained/buckled/Click()
var/mob/living/L = usr
if(!istype(L) || !L.can_resist())
if(!istype(L) || !L.can_resist() || L != owner)
return
L.MarkResistTime()
return L.resist_buckle()
@@ -693,7 +768,7 @@ so as to remain in compliance with the most up-to-date laws."
/atom/movable/screen/alert/shoes/Click()
var/mob/living/carbon/C = usr
if(!istype(C) || !C.can_resist() || C != mob_viewer || !C.shoes)
if(!istype(C) || !C.can_resist() || C != owner || !C.shoes)
return
C.MarkResistTime()
C.shoes.handle_tying(C)
@@ -701,11 +776,14 @@ so as to remain in compliance with the most up-to-date laws."
// PRIVATE = only edit, use, or override these if you're editing the system as a whole
// Re-render all alerts - also called in /datum/hud/show_hud() because it's needed there
/datum/hud/proc/reorganize_alerts()
/datum/hud/proc/reorganize_alerts(mob/viewmob)
var/mob/screenmob = viewmob || mymob
if(!screenmob.client)
return
var/list/alerts = mymob.alerts
if(!hud_shown)
for(var/i = 1, i <= alerts.len, i++)
mymob.client.screen -= alerts[alerts[i]]
screenmob.client.screen -= alerts[alerts[i]]
return 1
for(var/i = 1, i <= alerts.len, i++)
var/atom/movable/screen/alert/alert = alerts[alerts[i]]
@@ -725,22 +803,29 @@ so as to remain in compliance with the most up-to-date laws."
else
. = ""
alert.screen_loc = .
mymob.client.screen |= alert
screenmob.client.screen |= alert
if(!viewmob)
for(var/M in mymob.observers)
reorganize_alerts(M)
return 1
/atom/movable/screen/alert/Click(location, control, params)
if(!usr || !usr.client)
return
return FALSE
if(usr != owner)
return FALSE
var/paramslist = params2list(params)
if(paramslist["shift"]) // screen objects don't do the normal Click() stuff so we'll cheat
to_chat(usr, "<span class='boldnotice'>[name]</span> - <span class='info'>[desc]</span>")
return
if(master)
return FALSE
if(master && click_master)
return usr.client.Click(master, location, control, params)
return TRUE
/atom/movable/screen/alert/Destroy()
. = ..()
severity = 0
master = null
mob_viewer = null
owner = null
screen_loc = ""
+1 -1
View File
@@ -44,7 +44,7 @@
icon = I
parent = P
icon_state = credited
maptext = credited
maptext = MAPTEXT(credited)
maptext_x = world.icon_size + 8
maptext_y = (world.icon_size / 2) - 4
maptext_width = world.icon_size * 3
+27
View File
@@ -0,0 +1,27 @@
/atom/movable/screen/wanted
name = "Space Police Alertness"
desc = "Shows the current level of hostility the space police is planning to rain down on you. Better be careful."
icon = 'icons/obj/gang/wanted_160x32.dmi'
icon_state = "wanted_0"
screen_loc = ui_wanted_lvl
/// Wanted level, affects the hud icon. Level 0 is default, and the level 0 icon is blank, so in case of no families gamemode (and thus no wanted level), this HUD element will never appear.
level = 2
/// Boolean, have the cops arrived? If so, the icon stops changing and remains the same.
var/cops_arrived = 0
/atom/movable/screen/wanted/New()
return ..()
/atom/movable/screen/wanted/Initialize()
. = ..()
update_icon()
/atom/movable/screen/wanted/MouseEntered(location,control,params)
openToolTip(usr,src,params,title = name,content = desc, theme = "alerttooltipstyle")
/atom/movable/screen/wanted/MouseExited()
closeToolTip(usr)
/atom/movable/screen/wanted/update_icon_state()
. = ..()
icon_state = "wanted_[level][cops_arrived ? "_active" : ""]"
-186
View File
@@ -1,186 +0,0 @@
/mob/proc/overlay_fullscreen(category, type, severity)
var/atom/movable/screen/fullscreen/screen = screens[category]
if (!screen || screen.type != type)
// needs to be recreated
clear_fullscreen(category, FALSE)
screens[category] = screen = new type()
else if ((!severity || severity == screen.severity) && (!client || screen.screen_loc != "CENTER-7,CENTER-7" || screen.view == client.view))
// doesn't need to be updated
return screen
screen.icon_state = "[initial(screen.icon_state)][severity]"
screen.severity = severity
if (client && screen.should_show_to(src))
screen.update_for_view(client.view)
client.screen += screen
return screen
/mob/proc/clear_fullscreen(category, animated = 10)
var/atom/movable/screen/fullscreen/screen = screens[category]
if(!screen)
return
screens -= category
if(animated)
animate(screen, alpha = 0, time = animated)
addtimer(CALLBACK(src, .proc/clear_fullscreen_after_animate, screen), animated, TIMER_CLIENT_TIME)
else
if(client)
client.screen -= screen
qdel(screen)
/mob/proc/clear_fullscreen_after_animate(atom/movable/screen/fullscreen/screen)
if(client)
client.screen -= screen
qdel(screen)
/mob/proc/clear_fullscreens()
for(var/category in screens)
clear_fullscreen(category)
/mob/proc/hide_fullscreens()
if(client)
for(var/category in screens)
client.screen -= screens[category]
/mob/proc/reload_fullscreen()
if(client)
var/atom/movable/screen/fullscreen/screen
for(var/category in screens)
screen = screens[category]
if(screen.should_show_to(src))
screen.update_for_view(client.view)
client.screen |= screen
else
client.screen -= screen
/atom/movable/screen/fullscreen
icon = 'icons/mob/screen_full.dmi'
icon_state = "default"
screen_loc = "CENTER-7,CENTER-7"
layer = FULLSCREEN_LAYER
plane = FULLSCREEN_PLANE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
var/view = 7
var/severity = 0
var/show_when_dead = FALSE
/atom/movable/screen/fullscreen/proc/update_for_view(client_view)
if (screen_loc == "CENTER-7,CENTER-7" && view != client_view)
var/list/actualview = getviewsize(client_view)
view = client_view
transform = matrix(actualview[1]/FULLSCREEN_OVERLAY_RESOLUTION_X, 0, 0, 0, actualview[2]/FULLSCREEN_OVERLAY_RESOLUTION_Y, 0)
/atom/movable/screen/fullscreen/proc/should_show_to(mob/mymob)
if(!show_when_dead && mymob.stat == DEAD)
return FALSE
return TRUE
/atom/movable/screen/fullscreen/Destroy()
severity = 0
. = ..()
/atom/movable/screen/fullscreen/brute
icon_state = "brutedamageoverlay"
layer = UI_DAMAGE_LAYER
plane = FULLSCREEN_PLANE
/atom/movable/screen/fullscreen/oxy
icon_state = "oxydamageoverlay"
layer = UI_DAMAGE_LAYER
plane = FULLSCREEN_PLANE
/atom/movable/screen/fullscreen/crit
icon_state = "passage"
layer = CRIT_LAYER
plane = FULLSCREEN_PLANE
/atom/movable/screen/fullscreen/crit/vision
icon_state = "oxydamageoverlay"
layer = BLIND_LAYER
/atom/movable/screen/fullscreen/blind
icon_state = "blackimageoverlay"
layer = BLIND_LAYER
plane = FULLSCREEN_PLANE
/atom/movable/screen/fullscreen/curse
icon_state = "curse"
layer = CURSE_LAYER
plane = FULLSCREEN_PLANE
/atom/movable/screen/fullscreen/impaired
icon_state = "impairedoverlay"
/atom/movable/screen/fullscreen/blurry
icon = 'icons/mob/screen_gen.dmi'
screen_loc = "WEST,SOUTH to EAST,NORTH"
icon_state = "blurry"
/atom/movable/screen/fullscreen/flash
icon = 'icons/mob/screen_gen.dmi'
screen_loc = "WEST,SOUTH to EAST,NORTH"
icon_state = "flash"
/atom/movable/screen/fullscreen/flash/static
icon = 'icons/mob/screen_gen.dmi'
screen_loc = "WEST,SOUTH to EAST,NORTH"
icon_state = "noise"
/atom/movable/screen/fullscreen/high
icon = 'icons/mob/screen_gen.dmi'
screen_loc = "WEST,SOUTH to EAST,NORTH"
icon_state = "druggy"
/atom/movable/screen/fullscreen/color_vision
icon = 'icons/mob/screen_gen.dmi'
screen_loc = "WEST,SOUTH to EAST,NORTH"
icon_state = "flash"
alpha = 80
/atom/movable/screen/fullscreen/color_vision/green
color = "#00ff00"
/atom/movable/screen/fullscreen/color_vision/red
color = "#ff0000"
/atom/movable/screen/fullscreen/color_vision/blue
color = "#0000ff"
/atom/movable/screen/fullscreen/cinematic_backdrop
icon = 'icons/mob/screen_gen.dmi'
screen_loc = "WEST,SOUTH to EAST,NORTH"
icon_state = "flash"
plane = SPLASHSCREEN_PLANE
layer = SPLASHSCREEN_LAYER - 1
color = "#000000"
show_when_dead = TRUE
/atom/movable/screen/fullscreen/lighting_backdrop
icon = 'icons/mob/screen_gen.dmi'
icon_state = "flash"
transform = matrix(200, 0, 0, 0, 200, 0)
plane = LIGHTING_PLANE
blend_mode = BLEND_OVERLAY
show_when_dead = TRUE
//Provides darkness to the back of the lighting plane
/atom/movable/screen/fullscreen/lighting_backdrop/lit
invisibility = INVISIBILITY_LIGHTING
layer = BACKGROUND_LAYER+21
color = "#000"
show_when_dead = TRUE
//Provides whiteness in case you don't see lights so everything is still visible
/atom/movable/screen/fullscreen/lighting_backdrop/unlit
layer = BACKGROUND_LAYER+20
show_when_dead = TRUE
/atom/movable/screen/fullscreen/see_through_darkness
icon_state = "nightvision"
plane = LIGHTING_PLANE
layer = LIGHTING_LAYER
blend_mode = BLEND_ADD
show_when_dead = TRUE
+7
View File
@@ -93,3 +93,10 @@
screenmob.client.screen -= static_inventory
else
screenmob.client.screen += static_inventory
//We should only see observed mob alerts.
/datum/hud/ghost/reorganize_alerts(mob/viewmob)
var/mob/dead/observer/O = mymob
if (istype(O) && O.observetarget)
return
. = ..()
+8 -3
View File
@@ -35,6 +35,8 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
var/atom/movable/screen/devil/soul_counter/devilsouldisplay
var/atom/movable/screen/synth/coolant_counter/coolant_display
var/atom/movable/screen/action_intent
var/atom/movable/screen/zone_select
var/atom/movable/screen/pull_icon
@@ -58,6 +60,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
var/atom/movable/screen/healthdoll
var/atom/movable/screen/internals
var/atom/movable/screen/wanted/wanted_lvl
// subtypes can override this to force a specific UI style
var/ui_style
@@ -80,6 +83,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
plane_masters["[instance.plane]"] = instance
instance.backdrop(mymob)
/datum/hud/Destroy()
if(mymob.hud_used == src)
mymob.hud_used = null
@@ -100,6 +104,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
healths = null
healthdoll = null
wanted_lvl = null
internals = null
lingchemdisplay = null
devilsouldisplay = null
@@ -131,7 +136,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
return FALSE
screenmob.client.screen = list()
screenmob.client.apply_clickcatcher()
screenmob.client.update_clickcatcher()
var/display_hud_version = version
if(!display_hud_version) //If 0 or blank, display the next hud version
@@ -191,8 +196,6 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
persistent_inventory_update(screenmob)
screenmob.update_action_buttons(1)
reorganize_alerts()
screenmob.reload_fullscreen()
update_parallax_pref(screenmob)
// ensure observers get an accurate and up-to-date view
if (!viewmob)
@@ -202,6 +205,8 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
else if (viewmob.hud_used)
viewmob.hud_used.plane_masters_update()
screenmob.reload_rendering()
return TRUE
/datum/hud/proc/plane_masters_update()
+97 -1
View File
@@ -80,9 +80,101 @@
icon_state = "power_display"
screen_loc = ui_lingchemdisplay
#define ui_coolant_display "EAST,SOUTH+3:15"
/atom/movable/screen/synth
invisibility = INVISIBILITY_ABSTRACT
/atom/movable/screen/synth/proc/clear()
invisibility = INVISIBILITY_ABSTRACT
/atom/movable/screen/synth/proc/update_counter(mob/living/carbon/human/owner)
invisibility = 0
/atom/movable/screen/synth/coolant_counter
icon = 'icons/mob/screen_synth.dmi'
name = "Coolant System Readout"
icon_state = "coolant-3-1"
screen_loc = ui_coolant_display
var/jammed = 0
/atom/movable/screen/synth/coolant_counter/update_counter(mob/living/carbon/owner)
..()
var/valuecolor = "#ff2525"
if(owner.stat == DEAD)
maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='[valuecolor]'>ERR-0F</font></div>"
icon_state = "coolant-3-1"
return
var/coolant_efficiency
var/coolant
if(!jammed)
coolant_efficiency = owner.get_cooling_efficiency()
coolant = owner.blood_volume
else
coolant_efficiency = rand(1, 15) / 10
coolant = rand(1, 600)
jammed--
if(coolant > BLOOD_VOLUME_SAFE * owner.blood_ratio) //I unfortunately have to use this else-if stack because switch doesn't support variables.
valuecolor = "#4bbd34"
else if(coolant > BLOOD_VOLUME_OKAY * owner.blood_ratio)
valuecolor = "#dabb0d"
else if(coolant > BLOOD_VOLUME_BAD * owner.blood_ratio)
valuecolor = "#dd8109"
else if(coolant > BLOOD_VOLUME_SURVIVE * owner.blood_ratio)
valuecolor = "#e7520d"
maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='[valuecolor]'>[round((coolant / (BLOOD_VOLUME_NORMAL * owner.blood_ratio)) * 100, 1)]</font></div>"
var/efficiency_suffix
var/state_suffix
switch(coolant_efficiency)
if(-INFINITY to 0.4)
efficiency_suffix = "1"
if(0.4 to 0.75)
efficiency_suffix = "2"
if(0.75 to 0.95)
efficiency_suffix = "3"
if(0.95 to 1.3)
efficiency_suffix = "4"
else
efficiency_suffix = "5"
var/obj/item/organ/lungs/ipc/L = owner.getorganslot(ORGAN_SLOT_LUNGS)
if(istype(L) && L.is_cooling)
state_suffix = "2"
else
state_suffix = "1"
icon_state = "coolant-[efficiency_suffix]-[state_suffix]"
/atom/movable/screen/synth/coolant_counter/examine(mob/user)
. = ..()
var/mob/living/carbon/human/owner = hud.mymob
if(owner.stat == DEAD)
return
var/coolant
var/total_efficiency
var/environ_efficiency
var/suitlink_efficiency
if(!jammed)
coolant = owner.blood_volume
total_efficiency = owner.get_cooling_efficiency()
environ_efficiency = owner.get_environment_cooling_efficiency()
suitlink_efficiency = owner.check_suitlinking()
else
coolant = rand(1, 600)
total_efficiency = rand(1, 15) / 10
environ_efficiency = rand(1, 20) / 10
. += "<span class='notice'>Performing internal cooling system diagnostics:</span>"
. += "<span class='notice'>Coolant level: [coolant] units, [round((coolant / (BLOOD_VOLUME_NORMAL * owner.blood_ratio)) * 100, 0.1)] percent</span>"
. += "<span class='notice'>Current Cooling Efficiency: [round(total_efficiency * 100, 0.1)] percent, [suitlink_efficiency ? "<font color='green'>active suitlink detected</font>, guaranteeing <font color='green'>[suitlink_efficiency * 100]%</font> environmental cooling efficiency." : "environment viability: [round(environ_efficiency * 100, 0.1)] percent."]</span>"
/atom/movable/screen/synth/coolant_counter/proc/jam(amount, cap = 20)
if(jammed > cap) //Preserve previous more impactful event.
return
jammed = min(jammed + amount, cap)
/datum/hud/human/New(mob/living/carbon/human/owner)
..()
owner.overlay_fullscreen("see_through_darkness", /atom/movable/screen/fullscreen/see_through_darkness)
owner.overlay_fullscreen("see_through_darkness", /atom/movable/screen/fullscreen/special/see_through_darkness)
var/widescreenlayout = FALSE //CIT CHANGE - adds support for different hud layouts depending on widescreen pref
if(owner.client && owner.client.prefs && owner.client.prefs.widescreenpref) //CIT CHANGE - ditto
@@ -359,6 +451,10 @@
sunlight_display.hud = src
infodisplay += sunlight_display
coolant_display = new /atom/movable/screen/synth/coolant_counter //Coolant & cooling efficiency readouts for Synths.
coolant_display.hud = src
infodisplay += coolant_display
zone_select = new /atom/movable/screen/zone_sel()
zone_select.icon = ui_style
zone_select.hud = src
-322
View File
@@ -1,322 +0,0 @@
/datum/hud/proc/create_parallax(mob/viewmob)
var/mob/screenmob = viewmob || mymob
var/client/C = screenmob.client
if (!apply_parallax_pref(viewmob)) //don't want shit computers to crash when specing someone with insane parallax, so use the viewer's pref
return
if(!length(C.parallax_layers_cached))
C.parallax_layers_cached = list()
C.parallax_layers_cached += new /atom/movable/screen/parallax_layer/layer_1(null, C.view)
C.parallax_layers_cached += new /atom/movable/screen/parallax_layer/layer_2(null, C.view)
C.parallax_layers_cached += new /atom/movable/screen/parallax_layer/planet(null, C.view)
if(SSparallax.random_layer)
C.parallax_layers_cached += new SSparallax.random_layer
C.parallax_layers_cached += new /atom/movable/screen/parallax_layer/layer_3(null, C.view)
C.parallax_layers = C.parallax_layers_cached.Copy()
if (length(C.parallax_layers) > C.parallax_layers_max)
C.parallax_layers.len = C.parallax_layers_max
C.screen |= (C.parallax_layers)
var/atom/movable/screen/plane_master/PM = screenmob.hud_used.plane_masters["[PLANE_SPACE]"]
if(screenmob != mymob)
C.screen -= locate(/atom/movable/screen/plane_master/parallax_white) in C.screen
C.screen += PM
PM.color = list(
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1, 1, 1, 1,
0, 0, 0, 0
)
/datum/hud/proc/remove_parallax(mob/viewmob)
var/mob/screenmob = viewmob || mymob
var/client/C = screenmob.client
C.screen -= (C.parallax_layers_cached)
var/atom/movable/screen/plane_master/PM = screenmob.hud_used.plane_masters["[PLANE_SPACE]"]
if(screenmob != mymob)
C.screen -= locate(/atom/movable/screen/plane_master/parallax_white) in C.screen
C.screen += PM
PM.color = initial(PM.color)
C.parallax_layers = null
/datum/hud/proc/apply_parallax_pref(mob/viewmob)
var/mob/screenmob = viewmob || mymob
var/client/C = screenmob.client
if(C.prefs)
var/pref = C.prefs.parallax
if (isnull(pref))
pref = PARALLAX_HIGH
switch(C.prefs.parallax)
if (PARALLAX_INSANE)
C.parallax_throttle = FALSE
C.parallax_layers_max = 5
return TRUE
if (PARALLAX_MED)
C.parallax_throttle = PARALLAX_DELAY_MED
C.parallax_layers_max = 3
return TRUE
if (PARALLAX_LOW)
C.parallax_throttle = PARALLAX_DELAY_LOW
C.parallax_layers_max = 1
return TRUE
if (PARALLAX_DISABLE)
return FALSE
//This is high parallax.
C.parallax_throttle = PARALLAX_DELAY_DEFAULT
C.parallax_layers_max = 4
return TRUE
/datum/hud/proc/update_parallax_pref(mob/viewmob)
remove_parallax(viewmob)
create_parallax(viewmob)
update_parallax()
// This sets which way the current shuttle is moving (returns true if the shuttle has stopped moving so the caller can append their animation)
/datum/hud/proc/set_parallax_movedir(new_parallax_movedir, skip_windups)
. = FALSE
var/client/C = mymob.client
if(new_parallax_movedir == C.parallax_movedir)
return
var/animatedir = new_parallax_movedir
if(new_parallax_movedir == FALSE)
var/animate_time = 0
for(var/thing in C.parallax_layers)
var/atom/movable/screen/parallax_layer/L = thing
L.icon_state = initial(L.icon_state)
L.update_o(C.view)
var/T = PARALLAX_LOOP_TIME / L.speed
if (T > animate_time)
animate_time = T
C.dont_animate_parallax = world.time + min(animate_time, PARALLAX_LOOP_TIME)
animatedir = C.parallax_movedir
var/matrix/newtransform
switch(animatedir)
if(NORTH)
newtransform = matrix(1, 0, 0, 0, 1, 480)
if(SOUTH)
newtransform = matrix(1, 0, 0, 0, 1,-480)
if(EAST)
newtransform = matrix(1, 0, 480, 0, 1, 0)
if(WEST)
newtransform = matrix(1, 0,-480, 0, 1, 0)
var/shortesttimer
if(!skip_windups)
for(var/thing in C.parallax_layers)
var/atom/movable/screen/parallax_layer/L = thing
var/T = PARALLAX_LOOP_TIME / L.speed
if (isnull(shortesttimer))
shortesttimer = T
if (T < shortesttimer)
shortesttimer = T
L.transform = newtransform
animate(L, transform = matrix(), time = T, easing = QUAD_EASING | (new_parallax_movedir ? EASE_IN : EASE_OUT), flags = ANIMATION_END_NOW)
if (new_parallax_movedir)
L.transform = newtransform
animate(transform = matrix(), time = T) //queue up another animate so lag doesn't create a shutter
C.parallax_movedir = new_parallax_movedir
if (C.parallax_animate_timer)
deltimer(C.parallax_animate_timer)
var/datum/callback/CB = CALLBACK(src, .proc/update_parallax_motionblur, C, animatedir, new_parallax_movedir, newtransform)
if(skip_windups)
CB.InvokeAsync()
else
C.parallax_animate_timer = addtimer(CB, min(shortesttimer, PARALLAX_LOOP_TIME), TIMER_CLIENT_TIME|TIMER_STOPPABLE)
/datum/hud/proc/update_parallax_motionblur(client/C, animatedir, new_parallax_movedir, matrix/newtransform)
if(!C)
return
C.parallax_animate_timer = FALSE
for(var/thing in C.parallax_layers)
var/atom/movable/screen/parallax_layer/L = thing
if (!new_parallax_movedir)
animate(L)
continue
var/newstate = initial(L.icon_state)
var/T = PARALLAX_LOOP_TIME / L.speed
if (newstate in icon_states(L.icon))
L.icon_state = newstate
L.update_o(C.view)
L.transform = newtransform
animate(L, transform = matrix(), time = T, loop = -1, flags = ANIMATION_END_NOW)
/datum/hud/proc/update_parallax()
var/client/C = mymob.client
var/turf/posobj = get_turf(C.eye)
if(!posobj)
return
var/area/areaobj = posobj.loc
// Update the movement direction of the parallax if necessary (for shuttles)
set_parallax_movedir(areaobj.parallax_movedir, FALSE)
var/force
if(!C.previous_turf || (C.previous_turf.z != posobj.z))
C.previous_turf = posobj
force = TRUE
if (!force && world.time < C.last_parallax_shift+C.parallax_throttle)
return
//Doing it this way prevents parallax layers from "jumping" when you change Z-Levels.
var/offset_x = posobj.x - C.previous_turf.x
var/offset_y = posobj.y - C.previous_turf.y
if(!offset_x && !offset_y && !force)
return
var/last_delay = world.time - C.last_parallax_shift
last_delay = min(last_delay, C.parallax_throttle)
C.previous_turf = posobj
C.last_parallax_shift = world.time
for(var/thing in C.parallax_layers)
var/atom/movable/screen/parallax_layer/L = thing
L.update_status(mymob)
if (L.view_sized != C.view)
L.update_o(C.view)
var/change_x
var/change_y
if(L.absolute)
L.offset_x = -(posobj.x - SSparallax.planet_x_offset) * L.speed
L.offset_y = -(posobj.y - SSparallax.planet_y_offset) * L.speed
else
change_x = offset_x * L.speed
L.offset_x -= change_x
change_y = offset_y * L.speed
L.offset_y -= change_y
if(L.offset_x > 240)
L.offset_x -= 480
if(L.offset_x < -240)
L.offset_x += 480
if(L.offset_y > 240)
L.offset_y -= 480
if(L.offset_y < -240)
L.offset_y += 480
if(!areaobj.parallax_movedir && C.dont_animate_parallax <= world.time && (offset_x || offset_y) && abs(offset_x) <= max(C.parallax_throttle/world.tick_lag+1,1) && abs(offset_y) <= max(C.parallax_throttle/world.tick_lag+1,1) && (round(abs(change_x)) > 1 || round(abs(change_y)) > 1))
L.transform = matrix(1, 0, offset_x*L.speed, 0, 1, offset_y*L.speed)
animate(L, transform=matrix(), time = last_delay)
L.screen_loc = "CENTER-7:[round(L.offset_x,1)],CENTER-7:[round(L.offset_y,1)]"
/atom/movable/proc/update_parallax_contents()
if(length(client_mobs_in_contents))
for(var/thing in client_mobs_in_contents)
var/mob/M = thing
if(M?.client && M.hud_used && length(M.client.parallax_layers))
M.hud_used.update_parallax()
/mob/proc/update_parallax_teleport() //used for arrivals shuttle
if(client?.eye && hud_used && length(client.parallax_layers))
var/area/areaobj = get_area(client.eye)
hud_used.set_parallax_movedir(areaobj.parallax_movedir, TRUE)
/atom/movable/screen/parallax_layer
icon = 'icons/effects/parallax.dmi'
var/speed = 1
var/offset_x = 0
var/offset_y = 0
var/view_sized
var/absolute = FALSE
blend_mode = BLEND_ADD
plane = PLANE_SPACE_PARALLAX
screen_loc = "CENTER-7,CENTER-7"
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
/atom/movable/screen/parallax_layer/Initialize(mapload, view)
. = ..()
if (!view)
view = world.view
update_o(view)
/atom/movable/screen/parallax_layer/proc/update_o(view)
if (!view)
view = world.view
var/list/viewscales = getviewsize(view)
var/countx = CEILING((viewscales[1]/2)/(480/world.icon_size), 1)+1
var/county = CEILING((viewscales[2]/2)/(480/world.icon_size), 1)+1
var/list/new_overlays = new
for(var/x in -countx to countx)
for(var/y in -county to county)
if(x == 0 && y == 0)
continue
var/mutable_appearance/texture_overlay = mutable_appearance(icon, icon_state)
texture_overlay.transform = matrix(1, 0, x*480, 0, 1, y*480)
new_overlays += texture_overlay
cut_overlays()
add_overlay(new_overlays)
view_sized = view
/atom/movable/screen/parallax_layer/proc/update_status(mob/M)
return
/atom/movable/screen/parallax_layer/layer_1
icon_state = "layer1"
speed = 0.6
layer = 1
/atom/movable/screen/parallax_layer/layer_2
icon_state = "layer2"
speed = 1
layer = 2
/atom/movable/screen/parallax_layer/layer_3
icon_state = "layer3"
speed = 1.4
layer = 3
/atom/movable/screen/parallax_layer/random
blend_mode = BLEND_OVERLAY
speed = 3
layer = 3
/atom/movable/screen/parallax_layer/random/space_gas
icon_state = "space_gas"
/atom/movable/screen/parallax_layer/random/space_gas/Initialize(mapload, view)
. = ..()
src.add_atom_colour(SSparallax.random_parallax_color, ADMIN_COLOUR_PRIORITY)
/atom/movable/screen/parallax_layer/random/asteroids
icon_state = "asteroids"
/atom/movable/screen/parallax_layer/planet
icon_state = "planet"
blend_mode = BLEND_OVERLAY
absolute = TRUE //Status of seperation
speed = 3
layer = 30
/atom/movable/screen/parallax_layer/planet/update_status(mob/M)
var/client/C = M.client
var/turf/posobj = get_turf(C.eye)
if(!posobj)
return
invisibility = is_station_level(posobj.z) ? 0 : INVISIBILITY_ABSTRACT
/atom/movable/screen/parallax_layer/planet/update_o()
return //Shit won't move
+4 -5
View File
@@ -124,8 +124,8 @@
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
/atom/movable/screen/plane_master/lighting/backdrop(mob/mymob)
mymob.overlay_fullscreen("lighting_backdrop_lit", /atom/movable/screen/fullscreen/lighting_backdrop/lit)
mymob.overlay_fullscreen("lighting_backdrop_unlit", /atom/movable/screen/fullscreen/lighting_backdrop/unlit)
mymob.overlay_fullscreen("lighting_backdrop_lit", /atom/movable/screen/fullscreen/special/lighting_backdrop/lit)
mymob.overlay_fullscreen("lighting_backdrop_unlit", /atom/movable/screen/fullscreen/special/lighting_backdrop/unlit)
/*!
* This system works by exploiting BYONDs color matrix filter to use layers to handle emissive blockers.
@@ -143,7 +143,6 @@
add_filter("emissives", 1, alpha_mask_filter(render_source = EMISSIVE_RENDER_TARGET, flags = MASK_INVERSE))
add_filter("object_lighting", 2, alpha_mask_filter(render_source = O_LIGHTING_VISUAL_RENDER_TARGET, flags = MASK_INVERSE))
/**
* Handles emissive overlays and emissive blockers.
*/
@@ -163,9 +162,10 @@
plane = PLANE_SPACE_PARALLAX
blend_mode = BLEND_MULTIPLY
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
render_target = PLANE_SPACE_PARALLAX_RENDER_TARGET
/atom/movable/screen/plane_master/parallax_white
name = "parallax whitifier plane master"
name = "parallax backdrop/space turf plane master"
plane = PLANE_SPACE
/atom/movable/screen/plane_master/camera_static
@@ -174,7 +174,6 @@
appearance_flags = PLANE_MASTER
blend_mode = BLEND_OVERLAY
//Reserved to chat messages, so they are still displayed above the field of vision masking.
/atom/movable/screen/plane_master/chat_messages
name = "runechat plane master"
+70 -66
View File
@@ -9,7 +9,6 @@
/atom/movable/screen
name = ""
icon = 'icons/mob/screen_gen.dmi'
layer = HUD_LAYER
plane = HUD_PLANE
animate_movement = SLIDE_STEPS
speech_span = SPAN_ROBOT
@@ -56,16 +55,12 @@
maptext_width = 480
/atom/movable/screen/swap_hand
layer = HUD_LAYER
plane = HUD_PLANE
name = "swap hand"
/atom/movable/screen/swap_hand/Click()
// At this point in client Click() code we have passed the 1/10 sec check and little else
// We don't even know if it's a middle click
// if(world.time <= usr.next_move)
// return 1
if(usr.incapacitated())
return 1
@@ -74,6 +69,17 @@
M.swap_hand()
return 1
// /atom/movable/screen/skills
// name = "skills"
// icon = 'icons/mob/screen_midnight.dmi'
// icon_state = "skills"
// screen_loc = ui_skill_menu
// /atom/movable/screen/skills/Click()
// if(ishuman(usr))
// var/mob/living/carbon/human/H = usr
// H.mind.print_levels(H)
/atom/movable/screen/craft
name = "crafting menu"
icon = 'icons/mob/screen_midnight.dmi'
@@ -91,7 +97,7 @@
return TRUE
var/area/A = get_area(usr)
if(!A.outdoors)
to_chat(usr, "<span class='warning'>There is already a defined structure here.</span>")
to_chat(usr, span_warning("There is already a defined structure here."))
return TRUE
create_area(usr)
@@ -114,15 +120,12 @@
/// Icon when contains an item. For now used only by humans.
var/icon_full
/// The overlay when hovering over with an item in your hand
var/list/object_overlays = list()
layer = HUD_LAYER
var/image/object_overlay
plane = HUD_PLANE
/atom/movable/screen/inventory/Click(location, control, params)
// At this point in client Click() code we have passed the 1/10 sec check and little else
// We don't even know if it's a middle click
// if(world.time <= usr.next_move)
// return TRUE
if(usr.incapacitated()) // ignore_stasis = TRUE
return TRUE
@@ -138,42 +141,23 @@
usr.update_inv_hands()
return TRUE
/atom/movable/screen/inventory/MouseEntered()
..()
/atom/movable/screen/inventory/MouseEntered(location, control, params)
. = ..()
add_overlays()
//Apply the outline affect
add_stored_outline()
/atom/movable/screen/inventory/MouseExited()
..()
cut_overlay(object_overlays)
object_overlays.Cut()
remove_stored_outline()
/atom/movable/screen/inventory/proc/add_stored_outline()
if(hud?.mymob && slot_id)
var/obj/item/inv_item = hud.mymob.get_item_by_slot(slot_id)
if(inv_item)
if(hud?.mymob.incapacitated() || (slot_id in hud?.mymob.check_obscured_slots()) || !hud?.mymob.canUnEquip(inv_item))
inv_item.apply_outline(_size = 3)
else
inv_item.apply_outline()
/atom/movable/screen/inventory/proc/remove_stored_outline()
if(hud?.mymob && slot_id)
var/obj/item/inv_item = hud.mymob.get_item_by_slot(slot_id)
if(inv_item)
inv_item.remove_outline()
cut_overlay(object_overlay)
QDEL_NULL(object_overlay)
/atom/movable/screen/inventory/update_icon_state()
if(!icon_empty)
icon_empty = icon_state
if(hud?.mymob && slot_id && icon_full)
if(hud.mymob.get_item_by_slot(slot_id))
icon_state = icon_full
else
icon_state = icon_empty
if(!hud?.mymob || !slot_id || !icon_full)
return ..()
icon_state = hud.mymob.get_item_by_slot(slot_id) ? icon_full : icon_empty
return ..()
/atom/movable/screen/inventory/proc/add_overlays()
var/mob/user = hud?.mymob
@@ -189,14 +173,14 @@
var/image/item_overlay = image(holding)
item_overlay.alpha = 92
if(!user.can_equip(holding, slot_id, TRUE, TRUE))
if(!user.can_equip(holding, slot_id, disable_warning = TRUE, bypass_equip_delay_self = TRUE))
item_overlay.color = "#FF0000"
else
item_overlay.color = "#00ff00"
cut_overlay(object_overlays)
// object_overlay = item_overlay
add_overlay(object_overlays)
cut_overlay(object_overlay)
object_overlay = item_overlay
add_overlay(object_overlay)
/atom/movable/screen/inventory/hand
var/mutable_appearance/handcuff_overlay
@@ -232,8 +216,6 @@
var/mob/user = hud?.mymob
if(usr != user)
return TRUE
// if(world.time <= user.next_move)
// return TRUE
if(user.incapacitated())
return TRUE
if (ismecha(user.loc)) // stops inventory actions in a mech
@@ -247,12 +229,24 @@
user.swap_hand(held_index)
return TRUE
// /atom/movable/screen/close
// name = "close"
// plane = ABOVE_HUD_PLANE
// icon_state = "backpack_close"
// /atom/movable/screen/close/Initialize(mapload, new_master)
// . = ..()
// master = new_master
// /atom/movable/screen/close/Click()
// var/datum/component/storage/S = master
// S.hide_from(usr)
// return TRUE
/atom/movable/screen/drop
name = "drop"
icon = 'icons/mob/screen_midnight.dmi'
icon_state = "act_drop"
layer = HUD_LAYER
plane = HUD_PLANE
/atom/movable/screen/drop/Click()
@@ -308,12 +302,12 @@
if(C.internal)
C.internal = null
to_chat(C, "<span class='notice'>You are no longer running on internals.</span>")
to_chat(C, span_notice("You are no longer running on internals."))
icon_state = "internal0"
else
if(!C.getorganslot(ORGAN_SLOT_BREATHING_TUBE))
if(HAS_TRAIT(C, TRAIT_NO_INTERNALS))
to_chat(C, "<span class='warning'>Due to cumbersome equipment or anatomy, you are currently unable to use internals!</span>")
to_chat(C, span_warning("Due to cumbersome equipment or anatomy, you are currently unable to use internals!"))
return
var/obj/item/clothing/check
var/internals = FALSE
@@ -326,37 +320,37 @@
if((check.clothing_flags & ALLOWINTERNALS))
internals = TRUE
if(!internals)
to_chat(C, "<span class='warning'>You are not wearing an internals mask!</span>")
to_chat(C, span_warning("You are not wearing an internals mask!"))
return
var/obj/item/I = C.is_holding_item_of_type(/obj/item/tank)
if(I)
to_chat(C, "<span class='notice'>You are now running on internals from [I] in your [C.get_held_index_name(C.get_held_index_of_item(I))].</span>")
to_chat(C, span_notice("You are now running on internals from [I] in your [C.get_held_index_name(C.get_held_index_of_item(I))]."))
C.internal = I
else if(ishuman(C))
var/mob/living/carbon/human/H = C
if(istype(H.s_store, /obj/item/tank))
to_chat(H, "<span class='notice'>You are now running on internals from [H.s_store] on your [H.wear_suit.name].</span>")
to_chat(H, span_notice("You are now running on internals from [H.s_store] on your [H.wear_suit.name]."))
H.internal = H.s_store
else if(istype(H.belt, /obj/item/tank))
to_chat(H, "<span class='notice'>You are now running on internals from [H.belt] on your belt.</span>")
to_chat(H, span_notice("You are now running on internals from [H.belt] on your belt."))
H.internal = H.belt
else if(istype(H.l_store, /obj/item/tank))
to_chat(H, "<span class='notice'>You are now running on internals from [H.l_store] in your left pocket.</span>")
to_chat(H, span_notice("You are now running on internals from [H.l_store] in your left pocket."))
H.internal = H.l_store
else if(istype(H.r_store, /obj/item/tank))
to_chat(H, "<span class='notice'>You are now running on internals from [H.r_store] in your right pocket.</span>")
to_chat(H, span_notice("You are now running on internals from [H.r_store] in your right pocket."))
H.internal = H.r_store
//Separate so CO2 jetpacks are a little less cumbersome.
if(!C.internal && istype(C.back, /obj/item/tank))
to_chat(C, "<span class='notice'>You are now running on internals from [C.back] on your back.</span>")
to_chat(C, span_notice("You are now running on internals from [C.back] on your back."))
C.internal = C.back
if(C.internal)
icon_state = "internal1"
else
to_chat(C, "<span class='warning'>You don't have an oxygen tank!</span>")
to_chat(C, span_warning("You don't have an oxygen tank!"))
return
C.update_action_buttons_icon()
@@ -378,6 +372,7 @@
icon_state = CONFIG_GET(flag/sprint_enabled)? "walking" : "walking_nosprint"
if(MOVE_INTENT_RUN)
icon_state = CONFIG_GET(flag/sprint_enabled)? "running" : "running_nosprint"
return ..()
/atom/movable/screen/mov_intent/proc/toggle(mob/user)
if(isobserver(user))
@@ -399,12 +394,12 @@
icon_state = "pull"
else
icon_state = "pull0"
return ..()
/atom/movable/screen/resist
name = "resist"
icon = 'icons/mob/screen_midnight.dmi'
icon_state = "act_resist"
layer = HUD_LAYER
plane = HUD_PLANE
/atom/movable/screen/resist/Click()
@@ -416,7 +411,6 @@
name = "rest"
icon = 'icons/mob/screen_midnight.dmi'
icon_state = "act_rest"
layer = HUD_LAYER
plane = HUD_PLANE
/atom/movable/screen/rest/Click()
@@ -427,11 +421,12 @@
/atom/movable/screen/rest/update_icon_state()
var/mob/living/user = hud?.mymob
if(!istype(user))
return
return ..()
if(!user.resting)
icon_state = "act_rest"
else
icon_state = "act_rest0"
return ..()
/atom/movable/screen/throw_catch
name = "throw/catch"
@@ -455,9 +450,9 @@
if(isobserver(usr))
return
var/list/PL = params2list(params)
var/icon_x = text2num(PL["icon-x"])
var/icon_y = text2num(PL["icon-y"])
var/list/modifiers = params2list(params)
var/icon_x = text2num(LAZYACCESS(modifiers, "icon-x"))
var/icon_y = text2num(LAZYACCESS(modifiers, "icon-y"))
var/choice = get_zone_at(icon_x, icon_y)
if (!choice)
return 1
@@ -465,15 +460,16 @@
return set_selected_zone(choice, usr)
/atom/movable/screen/zone_sel/MouseEntered(location, control, params)
. = ..()
MouseMove(location, control, params)
/atom/movable/screen/zone_sel/MouseMove(location, control, params)
if(isobserver(usr))
return
var/list/PL = params2list(params)
var/icon_x = text2num(PL["icon-x"])
var/icon_y = text2num(PL["icon-y"])
var/list/modifiers = params2list(params)
var/icon_x = text2num(LAZYACCESS(modifiers, "icon-x"))
var/icon_y = text2num(LAZYACCESS(modifiers, "icon-y"))
var/choice = get_zone_at(icon_x, icon_y)
if(hovering == choice)
@@ -493,7 +489,6 @@
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
alpha = 128
anchored = TRUE
layer = ABOVE_HUD_LAYER
plane = ABOVE_HUD_PLANE
/atom/movable/screen/zone_sel/MouseExited(location, control, params)
@@ -545,7 +540,7 @@
if(choice != hud.mymob.zone_selected)
hud.mymob.zone_selected = choice
update_icon()
update_appearance()
return TRUE
@@ -562,7 +557,6 @@
/atom/movable/screen/zone_sel/robot
icon = 'icons/mob/screen_cyborg.dmi'
/atom/movable/screen/flash
name = "flash"
icon_state = "blank"
@@ -651,6 +645,11 @@
name = "health doll"
screen_loc = ui_healthdoll
/atom/movable/screen/healthdoll/Click()
if (iscarbon(usr))
var/mob/living/carbon/C = usr
C.check_self_for_injuries()
/atom/movable/screen/healthdoll/living
icon_state = "fullhealth0"
screen_loc = ui_living_healthdoll
@@ -661,6 +660,9 @@
icon_state = "mood5"
screen_loc = ui_mood
/atom/movable/screen/mood/attack_tk()
return
/atom/movable/screen/splash
icon = 'icons/blank_title.png'
icon_state = ""
@@ -671,6 +673,8 @@
/atom/movable/screen/splash/New(client/C, visible, use_previous_title) //TODO: Make this use INITIALIZE_IMMEDIATE, except its not easy
. = ..()
if(!istype(C))
return
holder = C
-1
View File
@@ -11,7 +11,6 @@
// Otherwise jump
else if(A.loc)
forceMove(get_turf(A))
update_parallax_contents()
/mob/dead/observer/ClickOn(var/atom/A, var/params)
if(check_click_intercept(params,A))
@@ -124,9 +124,3 @@ GLOBAL_LIST_INIT(huds, list(
/mob/dead/new_player/reload_huds()
return
/mob/proc/add_click_catcher()
client.screen += client.void
/mob/dead/new_player/add_click_catcher()
return
@@ -0,0 +1,74 @@
/atom/movable/screen/click_catcher
icon = 'icons/screen/clickcatcher.dmi'
icon_state = "catcher"
appearance_flags = TILE_BOUND | NO_CLIENT_COLOR | RESET_TRANSFORM | RESET_COLOR | RESET_ALPHA
plane = CLICKCATCHER_PLANE
plane = CLICKCATCHER_PLANE
mouse_opacity = MOUSE_OPACITY_OPAQUE
screen_loc = "CENTER"
/*
#define MAX_SAFE_BYOND_ICON_SCALE_TILES (MAX_SAFE_BYOND_ICON_SCALE_PX / world.icon_size)
#define MAX_SAFE_BYOND_ICON_SCALE_PX (33 * 32) //Not using world.icon_size on purpose.
/atom/movable/screen/click_catcher/proc/UpdateFill(view_size_x = 15, view_size_y = 15)
var/icon/newicon = icon('icons/mob/screen_gen.dmi', "catcher")
var/ox = min(MAX_SAFE_BYOND_ICON_SCALE_TILES, view_size_x)
var/oy = min(MAX_SAFE_BYOND_ICON_SCALE_TILES, view_size_y)
var/px = view_size_x * world.icon_size
var/py = view_size_y * world.icon_size
var/sx = min(MAX_SAFE_BYOND_ICON_SCALE_PX, px)
var/sy = min(MAX_SAFE_BYOND_ICON_SCALE_PX, py)
newicon.Scale(sx, sy)
icon = newicon
screen_loc = "CENTER-[(ox-1)*0.5],CENTER-[(oy-1)*0.5]"
var/matrix/M = new
M.Scale(px/sx, py/sy)
transform = M
#undef MAX_SAFE_BYOND_ICON_SCALE_TILES
#undef MAX_SAFE_BYOND_ICON_SCALE_PX
*/
/atom/movable/screen/click_catcher/proc/UpdateFill(view_size_x, view_size_y)
screen_loc = "1,1 to [view_size_x],[view_size_y]"
/atom/movable/screen/click_catcher/Click(location, control, params)
var/list/modifiers = params2list(params)
if(modifiers["middle"] && iscarbon(usr))
var/mob/living/carbon/C = usr
C.swap_hand()
else
var/turf/T = Parse(modifiers["screen-loc"], get_turf(usr.client?.eye || usr), usr.client)
params += "&catcher=1"
if(T)
T.Click(location, control, params)
return TRUE
/atom/movable/screen/click_catcher/proc/Parse(scr_loc, turf/origin, client/C)
// screen-loc: Pixel coordinates in screen_loc format ("[tile_x]:[pixel_x],[tile_y]:[pixel_y]")
if(!scr_loc)
return null
var/tX = splittext(scr_loc, ",")
var/tY = splittext(tX[2], ":")
var/tZ = origin.z
tY = tY[1]
tX = splittext(tX[1], ":")
tX = tX[1]
var/list/actual_view = getviewsize(C ? C.view : world.view)
tX = clamp(origin.x + text2num(tX) - round(actual_view[1] / 2) - 1, 1, world.maxx)
tY = clamp(origin.y + text2num(tY) - round(actual_view[2] / 2) - 1, 1, world.maxy)
return locate(tX, tY, tZ)
/**
* Makes a clickcatcher if necessary, and ensures it's fit to our size.
*/
/client/proc/update_clickcatcher(list/view_override)
if(!click_catcher)
click_catcher = new
screen |= click_catcher
if(view_override)
click_catcher.UpdateFill(view_override[1], view_override[2])
else
var/list/view_list = getviewsize(view)
click_catcher.UpdateFill(view_list[1], view_list[2])
+234
View File
@@ -0,0 +1,234 @@
/**
* Adds a fullscreen overlay
*
* @params
* - category - string - must exist. will overwrite any other screen in this category. defaults to type.
* - type - the typepath of the screen
* - severity - severity - different screen objects have differing severities
*/
/mob/proc/overlay_fullscreen(category, type, severity)
ASSERT(type)
if(!category)
category = type
var/atom/movable/screen/fullscreen/screen = fullscreens[category]
if (!screen || screen.type != type)
// needs to be recreated
clear_fullscreen(category, 0)
fullscreens[category] = screen = new type
screen.SetSeverity(severity)
if(client && screen.ShouldShow(src))
screen.SetView(client.view)
client.screen += screen
return screen
/**
* Wipes a fullscreen of a certain category
*
* Second argument is for animation delay.
*/
/mob/proc/clear_fullscreen(category, animated = 10)
if(!fullscreens)
return
var/atom/movable/screen/fullscreen/screen = fullscreens[category]
fullscreens -= category
if(!screen)
return
if(animated > 0)
animate(screen, alpha = 0, time = animated)
addtimer(CALLBACK(src, .proc/_remove_fullscreen_direct, screen), animated, TIMER_CLIENT_TIME)
else
if(client)
client.screen -= screen
qdel(screen)
/mob/proc/_remove_fullscreen_direct(atom/movable/screen/fullscreen/screen)
if(client)
client.screen -= screen
qdel(screen)
/**
* Wipes all fullscreens
*/
/mob/proc/wipe_fullscreens()
for(var/category in fullscreens)
clear_fullscreen(category)
/**
* Removes fullscreens from client but not the mob
*/
/mob/proc/hide_fullscreens()
if(client)
for(var/category in fullscreens)
client.screen -= fullscreens[category]
/**
* Ensures all fullscreens are on client.
*/
/mob/proc/reload_fullscreen()
if(client)
var/atom/movable/screen/fullscreen/screen
for(var/category in fullscreens)
screen = fullscreens[category]
if(screen.ShouldShow(src))
screen.SetView(client.view)
client.screen |= screen
else
client.screen -= screen
/atom/movable/screen/fullscreen
icon = 'icons/screen/fullscreen_15x15.dmi'
icon_state = "default"
screen_loc = "CENTER-7,CENTER-7"
layer = FULLSCREEN_LAYER
plane = FULLSCREEN_PLANE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
/// current view we're adapted to
var/view_current
/// min severity
var/severity_min = 0
/// max severity
var/severity_max = INFINITY
/// current severity
var/severity = 0
/// show this while dead
var/show_when_dead = FALSE
/atom/movable/screen/fullscreen/proc/SetSeverity(severity)
src.severity = clamp(severity, severity_min, severity_max)
icon_state = "[initial(icon_state)][severity]"
/atom/movable/screen/fullscreen/proc/SetView(client_view)
view_current = client_view
/atom/movable/screen/fullscreen/proc/ShouldShow(mob/M)
if(!show_when_dead && M.stat == DEAD)
return FALSE
return TRUE
/atom/movable/screen/fullscreen/Destroy()
SetSeverity(0)
return ..()
/atom/movable/screen/fullscreen/scaled
icon = 'icons/screen/fullscreen_15x15.dmi'
screen_loc = "CENTER-7,CENTER-7"
/// size of sprite in tiles
var/size_x = 15
/// size of sprite in tiles
var/size_y = 15
/atom/movable/screen/fullscreen/scaled/SetView(client_view)
if(view_current != client_view)
var/list/actualview = getviewsize(client_view)
view_current = client_view
transform = matrix(actualview[1] / size_x, 0, 0, 0, actualview[2] / size_y, 0)
return ..()
/atom/movable/screen/fullscreen/scaled/brute
icon_state = "brutedamageoverlay"
layer = UI_DAMAGE_LAYER
plane = FULLSCREEN_PLANE
/atom/movable/screen/fullscreen/scaled/oxy
icon_state = "oxydamageoverlay"
layer = UI_DAMAGE_LAYER
plane = FULLSCREEN_PLANE
/atom/movable/screen/fullscreen/scaled/crit
icon_state = "passage"
layer = CRIT_LAYER
plane = FULLSCREEN_PLANE
/atom/movable/screen/fullscreen/scaled/crit/vision
icon_state = "oxydamageoverlay"
layer = BLIND_LAYER
/atom/movable/screen/fullscreen/scaled/blind
icon_state = "blackimageoverlay"
layer = BLIND_LAYER
plane = FULLSCREEN_PLANE
/atom/movable/screen/fullscreen/scaled/curse
icon_state = "curse"
layer = CURSE_LAYER
plane = FULLSCREEN_PLANE
/atom/movable/screen/fullscreen/scaled/impaired
icon_state = "impairedoverlay"
/atom/movable/screen/fullscreen/scaled/emergency_meeting
icon_state = "emergency_meeting"
show_when_dead = TRUE
layer = CURSE_LAYER
plane = SPLASHSCREEN_PLANE
/atom/movable/screen/fullscreen/tiled/blurry
icon = 'icons/mob/screen_gen.dmi'
screen_loc = "WEST,SOUTH to EAST,NORTH"
icon_state = "cloudy"
/atom/movable/screen/fullscreen/tiled/flash
icon = 'icons/mob/screen_gen.dmi'
screen_loc = "WEST,SOUTH to EAST,NORTH"
icon_state = "flash"
/atom/movable/screen/fullscreen/tiled/flash/static
icon = 'icons/mob/screen_gen.dmi'
screen_loc = "WEST,SOUTH to EAST,NORTH"
icon_state = "noise"
/atom/movable/screen/fullscreen/tiled/high
icon = 'icons/mob/screen_gen.dmi'
screen_loc = "WEST,SOUTH to EAST,NORTH"
icon_state = "druggy"
/atom/movable/screen/fullscreen/tiled/color_vision
icon = 'icons/mob/screen_gen.dmi'
screen_loc = "WEST,SOUTH to EAST,NORTH"
icon_state = "flash"
alpha = 80
/atom/movable/screen/fullscreen/tiled/color_vision/green
color = "#00ff00"
/atom/movable/screen/fullscreen/tiled/color_vision/red
color = "#ff0000"
/atom/movable/screen/fullscreen/tiled/color_vision/blue
color = "#0000ff"
/atom/movable/screen/fullscreen/tiled/cinematic_backdrop
icon = 'icons/mob/screen_gen.dmi'
screen_loc = "WEST,SOUTH to EAST,NORTH"
icon_state = "flash"
plane = SPLASHSCREEN_PLANE
layer = SPLASHSCREEN_LAYER - 1
color = "#000000"
show_when_dead = TRUE
/atom/movable/screen/fullscreen/special/lighting_backdrop
icon = 'icons/mob/screen_gen.dmi'
icon_state = "flash"
transform = matrix(200, 0, 0, 0, 200, 0)
plane = LIGHTING_PLANE
blend_mode = BLEND_OVERLAY
show_when_dead = TRUE
//Provides darkness to the back of the lighting plane
/atom/movable/screen/fullscreen/special/lighting_backdrop/lit
invisibility = INVISIBILITY_LIGHTING
layer = BACKGROUND_LAYER+21
color = "#000"
show_when_dead = TRUE
//Provides whiteness in case you don't see lights so everything is still visible
/atom/movable/screen/fullscreen/special/lighting_backdrop/unlit
layer = BACKGROUND_LAYER+20
show_when_dead = TRUE
/atom/movable/screen/fullscreen/special/see_through_darkness
icon_state = "nightvision"
plane = LIGHTING_PLANE
layer = LIGHTING_LAYER
blend_mode = BLEND_ADD
show_when_dead = TRUE
+21
View File
@@ -0,0 +1,21 @@
/**
* initializes screen rendering. call on mob new
*/
/mob/proc/init_rendering()
/**
* loads screen rendering. call on mob login
*/
/mob/proc/reload_rendering()
if(!client.parallax_holder)
client.CreateParallax()
else
client.parallax_holder.Reset(force = TRUE)
client.update_clickcatcher()
reload_fullscreen()
/**
* destroys screen rendering. call on mob del
*/
/mob/proc/dispose_rendering()
wipe_fullscreens()
+28
View File
@@ -0,0 +1,28 @@
/**
* Holds parallax information.
*/
/datum/parallax
/// List of parallax objects - these are cloned to a parallax holder using Clone on each.
var/list/atom/movable/screen/parallax_layer/objects
/// Parallax layers
var/layers = 0
/datum/parallax/New(create_objects = TRUE)
if(create_objects)
objects = CreateObjects()
layers = objects.len
/datum/parallax/Destroy()
QDEL_LIST(objects)
return ..()
/**
* Gets a new version of the objects inside - used when applying to a holder.
*/
/datum/parallax/proc/GetObjects()
. = list()
for(var/atom/movable/screen/parallax_layer/layer in objects)
. += layer.Clone()
/datum/parallax/proc/CreateObjects()
. = objects = list()
+311
View File
@@ -0,0 +1,311 @@
/**
* # Parallax holders
*
* Holds all the information about a client's parallax
*
* Not on mob because parallax is area based, not mob based.
*
* How parallax works:
* - Layers - normal layers, scroll with movement to relative position, can scroll
* - Absolute - absolute layers, scroll with movement to absolute position, cannot scroll
* - Vis - vis_contents-like model - things in this are directly applied and get no processing whatsoever. Things like overmap ships can use this.
*/
/datum/parallax_holder
/// Client that owns us
var/client/owner
/// The parallax object we're currently rendering
var/datum/parallax/parallax
/// Eye we were last anchored to - used to detect eye changes
var/atom/cached_eye
/// force this eye as the "real" eye - useful for secondary maps
var/atom/forced_eye
/// last turf loc
var/turf/last
/// last area - for parallax scrolling/loop animations
var/area/last_area
/// Holder object for vis
var/atom/movable/screen/parallax_vis/vis_holder
/// are we not on the main map? if so, put map id here
var/secondary_map
/// all layers
var/list/atom/movable/screen/parallax_layer/layers
/// vis contents
var/list/atom/movable/vis
/// currently scrolling?
var/scrolling = FALSE
/// current scroll speed in DS per scroll
var/scroll_speed
/// current scroll turn - applied after angle. if angle is 0 (picture moving north) and turn is 90, it would be like if you turned your viewport 90 deg clockwise.
var/scroll_turn
/// override planemaster we manipulate for turning and other effects
var/atom/movable/screen/plane_master/parallax/planemaster_override
/datum/parallax_holder/New(client/C, secondary_map, forced_eye, planemaster_override)
owner = C
if(!owner)
CRASH("No client")
src.secondary_map = secondary_map
src.forced_eye = forced_eye
src.planemaster_override = planemaster_override
Reset()
/datum/parallax_holder/Destroy()
if(owner)
if(owner.parallax_holder == src)
owner.parallax_holder = null
Remove()
HardResetAnimations()
QDEL_NULL(vis_holder)
QDEL_NULL(parallax)
layers = null
vis = null
last = null
forced_eye = cached_eye = null
owner = null
return ..()
/datum/parallax_holder/proc/Reset(auto_z_change, force)
if(!(cached_eye = Eye()))
// if no eye, tear down
last = cached_eye = last_area = null
SetParallax(null, null, auto_z_change)
return
// first, check loc
var/turf/T = get_turf(cached_eye)
if(!T)
// if in nullspace, tear down
last = cached_eye = last_area = null
SetParallax(null, null, auto_z_change)
return
// set last loc and eye
last = T
last_area = T.loc
// rebuild parallax
SetParallax(SSparallax.get_parallax_datum(T.z), null, auto_z_change, force)
// hard reset positions to correct positions
for(var/atom/movable/screen/parallax_layer/L in layers)
L.ResetPosition(T.x, T.y)
// better updates via client_mobs_in_contents can be created again when important recursive contents is ported!
/datum/parallax_holder/proc/Update(full)
if(!full && !cached_eye || (get_turf(cached_eye) == last))
return
if(!owner) // why are we here
if(!QDELETED(src))
qdel(src)
return
if(cached_eye != Eye())
// eye mismatch, reset
Reset()
return
var/turf/T = get_turf(cached_eye)
if(!last || T.z != last.z)
// z mismatch, reset
Reset()
return
// get rel offsets
var/rel_x = T.x - last.x
var/rel_y = T.y - last.y
// set last
last = T
// move
for(var/atom/movable/screen/parallax_layer/L in layers)
L.RelativePosition(T.x, T.y, rel_x, rel_y)
// process scrolling/movedir
if(last_area != T.loc)
last_area = T.loc
UpdateMotion()
/**
* Gets the eye we should be centered on
*/
/datum/parallax_holder/proc/Eye()
return forced_eye || owner?.eye
/**
* Gets the base parallax planemaster for things like turning
*/
/datum/parallax_holder/proc/GetPlaneMaster()
return planemaster_override || (owner && (locate(/atom/movable/screen/plane_master/parallax) in owner?.screen))
/**
* Syncs us to our parallax objects. Does NOT check if we should have those objects, that's Reset()'s job.
*
* Doesn't move/update positions/screen locs either.
*
* Also ensures movedirs are correct for the eye's pos.
*/
/datum/parallax_holder/proc/Sync(auto_z_change, force)
layers = list()
for(var/atom/movable/screen/parallax_layer/L in parallax.objects)
layers += L
L.map_id = secondary_map
if(!istype(vis_holder))
vis_holder = new /atom/movable/screen/parallax_vis
var/turf/T = get_turf(cached_eye)
vis_holder.vis_contents = vis = T? SSparallax.get_parallax_vis_contents(T.z) : list()
UpdateMotion(auto_z_change, force)
/**
* Updates motion if needed
*/
/datum/parallax_holder/proc/UpdateMotion(auto_z_change, force)
var/turf/T = get_turf(cached_eye)
if(!T)
if(scroll_speed || scroll_turn)
HardResetAnimations()
return
var/list/ret = SSparallax.get_parallax_motion(T.z)
if(ret)
Animation(ret[1], ret[2], auto_z_change? 0 : ret[3], auto_z_change? 0 : ret[4], force)
else
var/area/A = T.loc
Animation(A.parallax_move_speed, A.parallax_move_angle, auto_z_change? 0 : null, auto_z_change? 0 : null, force)
/datum/parallax_holder/proc/Apply(client/C = owner)
if(QDELETED(C))
return
. = list()
for(var/atom/movable/screen/parallax_layer/L in layers)
if(L.parallax_intensity > owner.prefs.parallax)
continue
if(!L.ShouldSee(C, last))
continue
L.SetView(C.view, TRUE)
. |= L
C.screen |= .
if(!secondary_map && (owner.prefs.parallax != PARALLAX_DISABLE))
var/atom/movable/screen/plane_master/parallax_white/PM = locate() in C.screen
if(PM)
PM.color = list(
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1, 1, 1, 1,
0, 0, 0, 0
)
/datum/parallax_holder/proc/Remove(client/C = owner)
if(QDELETED(C))
return
C.screen -= layers
if(!secondary_map)
var/atom/movable/screen/plane_master/parallax_white/PM = locate() in C.screen
if(PM)
PM.color = initial(PM.color)
/datum/parallax_holder/proc/SetParallaxType(path)
if(!ispath(path, /datum/parallax))
CRASH("Invalid path")
SetParallax(new path)
/datum/parallax_holder/proc/SetParallax(datum/parallax/P, delete_old = TRUE, auto_z_change, force)
if(P == parallax)
return
Remove()
if(delete_old && istype(parallax) && !QDELETED(parallax))
qdel(parallax)
HardResetAnimations()
parallax = P
if(!parallax)
return
Sync(auto_z_change, force)
Apply()
/**
* Runs a modifier to parallax as an animation.
*
* @params
* speed - ds per loop
* turn - angle clockwise from north to turn the motion to
* windup - ds to spend on windups. 0 for immediate.
* turn_speed - ds to spend on turning. 0 for immediate.
*/
/datum/parallax_holder/proc/Animation(speed = 25, turn = 0, windup = speed, turn_speed = speed, force)
// Parallax doesn't currently use this method of rotating.
// #if !PARALLAX_ROTATION_ANIMATIONS
// turn_speed = 0
// #endif
if(speed == 0)
StopScrolling(turn = turn, time = windup)
return
// if(turn != scroll_turn && GetPlaneMaster())
// // first handle turn. we turn the planemaster
// var/matrix/turn_transform = matrix()
// turn_transform.Turn(turn)
// scroll_turn = turn
// animate(GetPlaneMaster(), transform = turn_transform, time = turn_speed, easing = QUAD_EASING | EASE_IN, flags = ANIMATION_END_NOW | ANIMATION_LINEAR_TRANSFORM)
if(scroll_speed == speed && !force)
// we're done
return
// speed diff?
scroll_speed = speed
scrolling = TRUE
// always scroll from north; turn handles everything
for(var/atom/movable/screen/parallax_layer/P in layers)
if(P.absolute)
continue
var/matrix/translate_matrix = matrix()
translate_matrix.Translate(cos(turn) * 480, sin(turn) * 480)
var/matrix/target_matrix = matrix()
var/move_speed = speed * P.speed
// do the first segment by shifting down one screen
P.transform = translate_matrix
animate(P, transform = target_matrix, time = move_speed, easing = QUAD_EASING|EASE_IN, flags = ANIMATION_END_NOW)
// queue up another incase lag makes QueueLoop not fire on time, this time by shifting up
animate(transform = translate_matrix, time = 0)
animate(transform = target_matrix, time = move_speed)
P.QueueLoop(move_speed, speed * P.speed, translate_matrix, target_matrix)
/**
* Smoothly stops the animation, turning to a certain angle as needed.
*/
/datum/parallax_holder/proc/StopScrolling(turn = 0, time = 30)
// reset turn
if(turn != scroll_turn && GetPlaneMaster())
var/matrix/turn_transform = matrix()
turn_transform.Turn(turn)
scroll_turn = turn
animate(GetPlaneMaster(), transform = turn_transform, time = time, easing = QUAD_EASING | EASE_OUT, flags = ANIMATION_END_NOW | ANIMATION_LINEAR_TRANSFORM)
if(scroll_speed == 0)
// we're done
scrolling = FALSE
scroll_speed = 0
return
scrolling = FALSE
scroll_speed = 0
// someone can do the math for "stop after a smooth iteration" later.
for(var/atom/movable/screen/parallax_layer/P in layers)
if(P.absolute)
continue
P.CancelAnimation()
var/matrix/translate_matrix = matrix()
translate_matrix.Translate(cos(turn) * 480, sin(turn) * 480)
P.transform = translate_matrix
animate(P, transform = matrix(), time = time, easing = QUAD_EASING | EASE_OUT)
/**
* fully resets animation state
*/
/datum/parallax_holder/proc/HardResetAnimations()
// reset vars
scroll_turn = 0
scroll_speed = 0
scrolling = FALSE
// reset turn
if(GetPlaneMaster())
animate(GetPlaneMaster(), transform = matrix(), time = 0, flags = ANIMATION_END_NOW)
// reset objects
for(var/atom/movable/screen/parallax_layer/P in layers)
if(P.absolute)
continue
P.CancelAnimation()
animate(P, transform = matrix(), time = 0, flags = ANIMATION_END_NOW)
/client/proc/CreateParallax()
if(!parallax_holder)
parallax_holder = new(src)
/atom/movable/screen/parallax_vis
screen_loc = "CENTER,CENTER"
+137
View File
@@ -0,0 +1,137 @@
/atom/movable/screen/parallax_layer
icon = 'icons/screen/parallax.dmi'
blend_mode = BLEND_ADD
plane = PLANE_SPACE_PARALLAX
screen_loc = "CENTER-7,CENTER-7"
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
appearance_flags = PIXEL_SCALE | KEEP_TOGETHER
// notice - all parallax layers are 15x15 tiles. They roll over every 240 pixels.
/// pixel x/y shift per real x/y
var/speed = 1
/// current cached offset x
var/offset_x = 0
/// current cached offset y
var/offset_y = 0
/// normal centered x
var/center_x = 0
/// normal centered y
var/center_y = 0
/// absolute - always determine shift x/y as a function of real x/y instead of allowing for relative scroll.
var/absolute = FALSE
/// parallax level required to see this
var/parallax_intensity = PARALLAX_INSANE
/// current view we're adapted to
var/view_current
/// dynamic self tile - tile to our view size. set this to false for static parallax layers.
var/dynamic_self_tile = TRUE
/// map id
var/map_id
/// queued animation timerid
var/queued_animation
/atom/movable/screen/parallax_layer/proc/ResetPosition(x, y)
// remember that our offsets/directiosn are relative to the player's viewport
// this means we need to scroll reverse to them.
offset_x = -(center_x + speed * x)
offset_y = -(center_y + speed * y)
if(!absolute)
if(offset_x > 240)
offset_x -= 480
if(offset_x < -240)
offset_x += 480
if(offset_y > 240)
offset_y -= 480
if(offset_y < -240)
offset_y += 480
screen_loc = "[map_id && "[map_id]:"]CENTER-7:[round(offset_x,1)],CENTER-7:[round(offset_y,1)]"
/atom/movable/screen/parallax_layer/proc/RelativePosition(x, y, rel_x, rel_y)
if(absolute)
return ResetPosition(x, y)
offset_x -= rel_x * speed
offset_y -= rel_y * speed
if(offset_x > 240)
offset_x -= 480
if(offset_x < -240)
offset_x += 480
if(offset_y > 240)
offset_y -= 480
if(offset_y < -240)
offset_y += 480
screen_loc = "[map_id && "[map_id]:"]CENTER-7:[round(offset_x,1)],CENTER-7:[round(offset_y,1)]"
/atom/movable/screen/parallax_layer/proc/SetView(client_view = world.view, force_update = FALSE)
if(view_current == client_view && !force_update)
return
view_current = client_view
if(!dynamic_self_tile)
return
var/list/real_view = getviewsize(client_view)
var/count_x = CEILING((real_view[1] / 2) / 15, 1) + 1
var/count_y = CEILING((real_view[2] / 2) / 15, 1) + 1
var/list/new_overlays = GetOverlays()
for(var/x in -count_x to count_x)
for(var/y in -count_y to count_y)
if(!x && !y)
continue
var/mutable_appearance/clone = new
// appearance clone
clone.icon = icon
clone.icon_state = icon_state
clone.overlays = GetOverlays()
// do NOT inherit our overlays! parallax layers should never have overlays,
// because if it inherited us it'll result in exponentially increasing overlays
// due to cut_overlays() above over there being a queue operation and not instant!
// clone.overlays = list()
// currently instantly using overlays =.
// clone.blend_mode = blend_mode
// clone.mouse_opacity = mouse_opacity
// clone.plane = plane
// clone.layer = layer
// shift to position
clone.transform = matrix(1, 0, x * 480, 0, 1, y * 480)
new_overlays += clone
overlays = new_overlays
/atom/movable/screen/parallax_layer/proc/ShouldSee(client/C, atom/location)
return TRUE
/**
* Return "natural" overlays, as we're goin to do some fuckery to overlays above.
*/
/atom/movable/screen/parallax_layer/proc/GetOverlays()
return list()
/atom/movable/screen/parallax_layer/proc/Clone()
var/atom/movable/screen/parallax_layer/layer = new type
layer.speed = speed
layer.offset_x = offset_x
layer.offset_y = offset_y
layer.absolute = absolute
layer.parallax_intensity = parallax_intensity
layer.view_current = view_current
layer.appearance = appearance
/atom/movable/screen/parallax_layer/proc/default_x()
return center_x
/atom/movable/screen/parallax_layer/proc/default_y()
return center_y
/atom/movable/screen/parallax_layer/proc/QueueLoop(delay, speed, matrix/translate_matrix, matrix/target_matrix)
if(queued_animation)
CancelAnimation()
queued_animation = addtimer(CALLBACK(src, .proc/_loop, speed, translate_matrix, target_matrix), delay, TIMER_STOPPABLE)
/atom/movable/screen/parallax_layer/proc/_loop(speed, matrix/translate_matrix = matrix(1, 0, 0, 0, 1, 480), matrix/target_matrix = matrix())
transform = translate_matrix
animate(src, transform = target_matrix, time = speed, loop = -1)
animate(transform = translate_matrix, time = 0)
queued_animation = null
/atom/movable/screen/parallax_layer/proc/CancelAnimation()
if(queued_animation)
deltimer(queued_animation)
queued_animation = null
+66
View File
@@ -0,0 +1,66 @@
/datum/parallax/space
var/static/planet_offset_x = rand(100, 160)
var/static/planet_offset_y = rand(100, 160)
var/static/random_layer = pickweightAllowZero(list(
/atom/movable/screen/parallax_layer/space/random/asteroids = 35,
/atom/movable/screen/parallax_layer/space/random/space_gas = 35,
null = 30
))
var/static/random_gas_color = pick(COLOR_TEAL, COLOR_GREEN, COLOR_YELLOW, COLOR_CYAN, COLOR_ORANGE, COLOR_PURPLE)
/datum/parallax/space/CreateObjects()
. = ..()
. += new /atom/movable/screen/parallax_layer/space/layer_1
. += new /atom/movable/screen/parallax_layer/space/layer_2
. += new /atom/movable/screen/parallax_layer/space/layer_3
var/atom/movable/screen/parallax_layer/space/planet/P = new
P.pixel_x = planet_offset_x
P.pixel_y = planet_offset_y
. += P
if(random_layer)
. += new random_layer
if(ispath(random_layer, /atom/movable/screen/parallax_layer/space/random/space_gas))
var/atom/movable/screen/parallax_layer/space/random/space_gas/SG = locate(random_layer) in objects
SG.add_atom_colour(random_gas_color, ADMIN_COLOUR_PRIORITY)
/atom/movable/screen/parallax_layer/space/layer_1
icon_state = "layer1"
speed = 0.6
layer = 1
parallax_intensity = PARALLAX_LOW
/atom/movable/screen/parallax_layer/space/layer_2
icon_state = "layer2"
speed = 1
layer = 2
parallax_intensity = PARALLAX_MED
/atom/movable/screen/parallax_layer/space/layer_3
icon_state = "layer3"
speed = 1.4
layer = 3
parallax_intensity = PARALLAX_HIGH
/atom/movable/screen/parallax_layer/space/random
blend_mode = BLEND_OVERLAY
speed = 3
layer = 3
parallax_intensity = PARALLAX_INSANE
/atom/movable/screen/parallax_layer/space/random/space_gas
icon_state = "space_gas"
/atom/movable/screen/parallax_layer/space/random/asteroids
icon_state = "asteroids"
/atom/movable/screen/parallax_layer/space/planet
icon_state = "planet"
blend_mode = BLEND_OVERLAY
absolute = TRUE //Status of seperation
speed = 3
layer = 30
dynamic_self_tile = FALSE
/atom/movable/screen/parallax_layer/space/planet/ShouldSee(client/C, atom/location)
var/turf/T = get_turf(location)
return ..() && T && is_station_level(T.z)
@@ -348,6 +348,8 @@
/datum/config_entry/flag/dynamic_config_enabled
/datum/config_entry/flag/station_name_needs_approval
//ambition end
config_entry_value = 5
/datum/config_entry/number/max_ambitions // Maximum number of ambitions a mind can store.
@@ -4,6 +4,10 @@
/datum/config_entry/flag/log_access // log login/logout
config_entry_value = TRUE
/// Config entry which special logging of failed logins under suspicious circumstances.
/datum/config_entry/flag/log_suspicious_login
config_entry_value = TRUE
/datum/config_entry/flag/log_say // log client say
config_entry_value = TRUE
+5
View File
@@ -116,6 +116,11 @@ SUBSYSTEM_DEF(air)
/datum/controller/subsystem/air/proc/auxtools_update_reactions()
/datum/controller/subsystem/air/proc/add_reaction(datum/gas_reaction/r)
gas_reactions += r
sortTim(gas_reactions, /proc/cmp_gas_reaction)
auxtools_update_reactions()
/proc/reset_all_air()
SSair.can_fire = 0
message_admins("Air reset begun.")
+17
View File
@@ -14,6 +14,9 @@ SUBSYSTEM_DEF(atoms)
var/list/BadInitializeCalls = list()
/// Atoms that will be deleted once the subsystem is initialized
var/list/queued_deletions = list()
initialized = INITIALIZATION_INSSATOMS
/datum/controller/subsystem/atoms/Initialize(timeofday)
@@ -62,6 +65,12 @@ SUBSYSTEM_DEF(atoms)
testing("Late initialized [late_loaders.len] atoms")
late_loaders.Cut()
for (var/queued_deletion in queued_deletions)
qdel(queued_deletion)
testing("[queued_deletions.len] atoms were queued for deletion.")
queued_deletions.Cut()
/// Init this specific atom
/datum/controller/subsystem/atoms/proc/InitAtom(atom/A, list/arguments)
var/the_type = A.type
@@ -151,6 +160,14 @@ SUBSYSTEM_DEF(atoms)
if(fails & BAD_INIT_SLEPT)
. += "- Slept during Initialize()\n"
/// Prepares an atom to be deleted once the atoms SS is initialized.
/datum/controller/subsystem/atoms/proc/prepare_deletion(atom/target)
if (initialized == INITIALIZATION_INNEW_REGULAR)
// Atoms SS has already completed, just kill it now.
qdel(target)
else
queued_deletions += WEAKREF(target)
/datum/controller/subsystem/atoms/Shutdown()
var/initlog = InitLog()
if(initlog)
+47 -13
View File
@@ -1,33 +1,67 @@
#define COMMUNICATION_COOLDOWN 300
#define COMMUNICATION_COOLDOWN_AI 300
#define COMMUNICATION_COOLDOWN (30 SECONDS)
#define COMMUNICATION_COOLDOWN_AI (30 SECONDS)
#define COMMUNICATION_COOLDOWN_MEETING (5 MINUTES)
SUBSYSTEM_DEF(communications)
name = "Communications"
flags = SS_NO_INIT | SS_NO_FIRE
var/silicon_message_cooldown
var/nonsilicon_message_cooldown
COOLDOWN_DECLARE(silicon_message_cooldown)
COOLDOWN_DECLARE(nonsilicon_message_cooldown)
COOLDOWN_DECLARE(emergency_meeting_cooldown)
/datum/controller/subsystem/communications/proc/can_announce(mob/living/user, is_silicon)
if(is_silicon && silicon_message_cooldown > world.time)
. = FALSE
else if(!is_silicon && nonsilicon_message_cooldown > world.time)
. = FALSE
if(is_silicon && COOLDOWN_FINISHED(src, silicon_message_cooldown))
return TRUE
else if(!is_silicon && COOLDOWN_FINISHED(src, nonsilicon_message_cooldown))
return TRUE
else
. = TRUE
return FALSE
/datum/controller/subsystem/communications/proc/make_announcement(mob/living/user, is_silicon, input)
if(!can_announce(user, is_silicon))
return FALSE
if(is_silicon)
minor_announce(html_decode(input),"[user.name] Announces:")
silicon_message_cooldown = world.time + COMMUNICATION_COOLDOWN_AI
COOLDOWN_START(src, silicon_message_cooldown, COMMUNICATION_COOLDOWN_AI)
else
priority_announce(html_decode(user.treat_message(input)), null, 'sound/misc/announce.ogg', "Captain")
nonsilicon_message_cooldown = world.time + COMMUNICATION_COOLDOWN
priority_announce(html_decode(user.treat_message(input)), null, 'sound/misc/announce.ogg', "Captain", has_important_message = TRUE)
COOLDOWN_START(src, nonsilicon_message_cooldown, COMMUNICATION_COOLDOWN)
user.log_talk(input, LOG_SAY, tag="priority announcement")
message_admins("[ADMIN_LOOKUPFLW(user)] has made a priority announcement.")
/**
* Check if a mob can call an emergency meeting
*
* Should only really happen during april fools.
* Checks to see that it's been at least 5 minutes since the last emergency meeting call.
* Arguments:
* * user - Mob who called the meeting
*/
/datum/controller/subsystem/communications/proc/can_make_emergency_meeting(mob/living/user)
if(!(SSevents.holidays && SSevents.holidays[APRIL_FOOLS]))
return FALSE
else if(COOLDOWN_FINISHED(src, emergency_meeting_cooldown))
return TRUE
else
return FALSE
/**
* Call an emergency meeting
*
* Communications subsystem wrapper for the call_emergency_meeting world proc.
* Checks to make sure the proc can be called, and handles
* relevant logging and timing. See that proc definition for more detail.
* Arguments:
* * user - Mob who called the meeting
*/
/datum/controller/subsystem/communications/proc/emergency_meeting(mob/living/user)
if(!can_make_emergency_meeting(user))
return FALSE
call_emergency_meeting(user, get_area(user))
COOLDOWN_START(src, emergency_meeting_cooldown, COMMUNICATION_COOLDOWN_MEETING)
message_admins("[ADMIN_LOOKUPFLW(user)] has called an emergency meeting.")
/datum/controller/subsystem/communications/proc/send_message(datum/comm_message/sending,print = TRUE,unique = FALSE)
for(var/obj/machinery/computer/communications/C in GLOB.machines)
if(!(C.stat & (BROKEN|NOPOWER)) && is_station_level(C.z))
@@ -40,7 +74,7 @@ SUBSYSTEM_DEF(communications)
var/obj/item/paper/P = new /obj/item/paper(C.loc)
P.name = "paper - '[sending.title]'"
P.info = sending.content
P.update_icon()
P.update_appearance()
#undef COMMUNICATION_COOLDOWN
#undef COMMUNICATION_COOLDOWN_AI
+74 -35
View File
@@ -5,21 +5,6 @@ SUBSYSTEM_DEF(parallax)
priority = FIRE_PRIORITY_PARALLAX
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
var/list/currentrun
var/planet_x_offset = 128
var/planet_y_offset = 128
var/random_layer
var/random_parallax_color
//These are cached per client so needs to be done asap so people joining at roundstart do not miss these.
/datum/controller/subsystem/parallax/PreInit()
. = ..()
if(prob(70)) //70% chance to pick a special extra layer
random_layer = pick(/atom/movable/screen/parallax_layer/random/space_gas, /atom/movable/screen/parallax_layer/random/asteroids)
random_parallax_color = pick(COLOR_TEAL, COLOR_GREEN, COLOR_YELLOW, COLOR_CYAN, COLOR_ORANGE, COLOR_PURPLE)//Special color for random_layer1. Has to be done here so everyone sees the same color. [COLOR_SILVER]
planet_y_offset = rand(100, 160)
planet_x_offset = rand(100, 160)
/datum/controller/subsystem/parallax/fire(resumed = FALSE)
if (!resumed)
@@ -28,28 +13,82 @@ SUBSYSTEM_DEF(parallax)
//cache for sanic speed (lists are references anyways)
var/list/currentrun = src.currentrun
while(length(currentrun))
var/client/processing_client = currentrun[currentrun.len]
currentrun.len--
if (QDELETED(processing_client) || !processing_client.eye)
if(times_fired % 5) // lazy tick
while(length(currentrun))
var/client/processing_client = currentrun[currentrun.len]
currentrun.len--
if (QDELETED(processing_client) || !processing_client.eye)
if (MC_TICK_CHECK)
return
continue
processing_client.parallax_holder?.Update()
if (MC_TICK_CHECK)
return
continue
var/atom/movable/movable_eye = processing_client.eye
if(!istype(movable_eye))
continue
for (movable_eye; isloc(movable_eye.loc) && !isturf(movable_eye.loc); movable_eye = movable_eye.loc);
if(movable_eye == processing_client.movingmob)
else // full tick
while(length(currentrun))
var/client/processing_client = currentrun[currentrun.len]
currentrun.len--
if (QDELETED(processing_client) || !processing_client.eye)
if (MC_TICK_CHECK)
return
continue
processing_client.parallax_holder?.Update(TRUE)
if (MC_TICK_CHECK)
return
continue
if(!isnull(processing_client.movingmob))
LAZYREMOVE(processing_client.movingmob.client_mobs_in_contents, processing_client.mob)
LAZYADD(movable_eye.client_mobs_in_contents, processing_client.mob)
processing_client.movingmob = movable_eye
if (MC_TICK_CHECK)
return
currentrun = null
/**
* Gets parallax type for zlevel.
*/
/datum/controller/subsystem/parallax/proc/get_parallax_type(z)
return /datum/parallax/space
/**
* Gets parallax for zlevel.
*/
/datum/controller/subsystem/parallax/proc/get_parallax_datum(z)
var/datum_type = get_parallax_type(z)
return new datum_type
/**
* Gets parallax added vis contents for zlevel
*/
/datum/controller/subsystem/parallax/proc/get_parallax_vis_contents(z)
return list()
/**
* Gets parallax motion for a zlevel
*
* Returns null or list(speed, dir deg clockwise from north, windup, turnrate)
* THE RETURNED LIST MUST BE A 4-TUPLE, OR PARALLAX WILL CRASH.
* DO NOT SCREW WITH THIS UNLESS YOU KNOW WHAT YOU ARE DOING.
*
* This will override area motion
*/
/datum/controller/subsystem/parallax/proc/get_parallax_motion(z)
return null
/**
* updates all parallax for clients on a z
*/
/datum/controller/subsystem/parallax/proc/update_clients_on_z(z)
for(var/client/C in GLOB.clients)
if(C.mob.z == z)
C.parallax_holder?.Update()
/**
* resets all parallax for clients on a z
*/
/datum/controller/subsystem/parallax/proc/reset_clients_on_z(z)
for(var/client/C in GLOB.clients)
if(C.mob.z == z)
C.parallax_holder?.Reset()
/**
* updates motion of all clients on z
*/
/datum/controller/subsystem/parallax/proc/update_z_motion(z)
for(var/client/C in GLOB.clients)
if(C.mob.z == z)
C.parallax_holder?.UpdateMotion()
@@ -17,7 +17,6 @@ SUBSYSTEM_DEF(processing)
/datum/controller/subsystem/processing/fire(resumed = FALSE)
if (!resumed)
currentrun = processing.Copy()
var/delta_time = (flags & SS_TICKER)? (wait * world.tick_lag * 0.1) : (wait * 0.1)
//cache for sanic speed (lists are references anyways)
var/list/current_run = currentrun
@@ -26,7 +25,7 @@ SUBSYSTEM_DEF(processing)
current_run.len--
if(QDELETED(thing))
processing -= thing
else if(thing.process(delta_time) == PROCESS_KILL)
else if(thing.process(wait * 0.1) == PROCESS_KILL)
// fully stop so that a future START_PROCESSING will work
STOP_PROCESSING(src, thing)
if (MC_TICK_CHECK)
@@ -47,5 +46,5 @@ SUBSYSTEM_DEF(processing)
* If you override this do not call parent, as it will return PROCESS_KILL. This is done to prevent objects that dont override process() from staying in the processing list
*/
/datum/proc/process(delta_time)
SHOULD_NOT_SLEEP(TRUE)
set waitfor = FALSE
return PROCESS_KILL
@@ -48,6 +48,13 @@ PROCESSING_SUBSYSTEM_DEF(quirks)
cli.prefs.save_character()
if (!silent && LAZYLEN(cut))
to_chat(to_chat_target || user, "<span class='boldwarning'>Some quirks have been cut from your character because of these quirks conflicting with your job assignment: [english_list(cut)].</span>")
var/mob/living/carbon/human/H = user
if(istype(H) && H.dna?.species)
var/datum/species/S = H.dna.species
if(S.remove_blacklisted_quirks(H))
to_chat(to_chat_target || user, "<span class='boldwarning'>Some quirks have been cut from your character due to them conflicting with your species: [english_list(S.removed_quirks)]</span>")
/datum/controller/subsystem/processing/quirks/proc/quirk_path_by_name(name)
return quirks[name]
+3 -1
View File
@@ -513,7 +513,9 @@ SUBSYSTEM_DEF(shuttle)
if(!midpoint)
return FALSE
var/area/shuttle/transit/A = new()
A.parallax_movedir = travel_dir
A.parallax_moving = TRUE
A.parallax_move_angle = dir2angle(travel_dir)
A.parallax_move_speed = M.parallax_speed
A.contents = proposal.reserved_turfs
var/obj/docking_port/stationary/transit/new_transit_dock = new(midpoint)
new_transit_dock.reserved_area = proposal
@@ -0,0 +1,3 @@
PROCESSING_SUBSYSTEM_DEF(sound_loops)
name = "Sound Loops"
priority = FIRE_PRIORITY_SOUND_LOOPS
+6 -6
View File
@@ -4,7 +4,7 @@ SUBSYSTEM_DEF(sounds)
name = "Sounds"
flags = SS_NO_FIRE
init_order = INIT_ORDER_SOUNDS
var/static/using_channels_max = CHANNEL_HIGHEST_AVAILABLE //BYOND max channels
var/static/using_channels_max = CHANNEL_HIGHEST_AVAILABLE //BYOND max channels
/// Amount of channels to reserve for random usage rather than reservations being allowed to reserve all channels. Also a nice safeguard for when someone screws up.
var/static/random_channels_min = 50
@@ -42,7 +42,7 @@ SUBSYSTEM_DEF(sounds)
var/text_channel = num2text(channel)
var/using = using_channels[text_channel]
using_channels -= text_channel
if(using != TRUE) // datum channel
if(using != TRUE) // datum channel
using_channels_by_datum[using] -= channel
if(!length(using_channels_by_datum[using]))
using_channels_by_datum -= using
@@ -65,7 +65,7 @@ SUBSYSTEM_DEF(sounds)
/// NO AUTOMATIC CLEANUP - If you use this, you better manually free it later! Returns an integer for channel.
/datum/controller/subsystem/sounds/proc/reserve_sound_channel_datumless()
. = reserve_channel()
if(!.) //oh no..
if(!.) //oh no..
return FALSE
var/text_channel = num2text(.)
using_channels[text_channel] = DATUMLESS
@@ -74,7 +74,7 @@ SUBSYSTEM_DEF(sounds)
/// Reserves a channel for a datum. Automatic cleanup only when the datum is deleted. Returns an integer for channel.
/datum/controller/subsystem/sounds/proc/reserve_sound_channel(datum/D)
if(!D) //i don't like typechecks but someone will fuck it up
if(!D) //i don't like typechecks but someone will fuck it up
CRASH("Attempted to reserve sound channel without datum using the managed proc.")
.= reserve_channel()
if(!.)
@@ -89,7 +89,7 @@ SUBSYSTEM_DEF(sounds)
*/
/datum/controller/subsystem/sounds/proc/reserve_channel()
PRIVATE_PROC(TRUE)
if(channel_reserve_high <= random_channels_min) // out of channels
if(channel_reserve_high <= random_channels_min) // out of channels
return
var/channel = channel_list[channel_reserve_high]
reserved_channels[num2text(channel)] = channel_reserve_high--
@@ -112,7 +112,7 @@ SUBSYSTEM_DEF(sounds)
// now, an existing reserved channel will likely (exception: unreserving last reserved channel) be at index
// get it, and update position.
var/text_reserved = num2text(channel_list[index])
if(!reserved_channels[text_reserved]) //if it isn't already reserved make sure we don't accidently mistakenly put it on reserved list!
if(!reserved_channels[text_reserved]) //if it isn't already reserved make sure we don't accidently mistakenly put it on reserved list!
return
reserved_channels[text_reserved] = index
+4 -2
View File
@@ -603,8 +603,10 @@ SUBSYSTEM_DEF(ticker)
news_message = "The burst of energy released near [station_name()] has been confirmed as merely a test of a new weapon. However, due to an unexpected mechanical error, their communications system has been knocked offline."
if(SHUTTLE_HIJACK)
news_message = "During routine evacuation procedures, the emergency shuttle of [station_name()] had its navigation protocols corrupted and went off course, but was recovered shortly after."
if(GANG_VICTORY)
news_message = "Company officials reaffirmed that sudden deployments of special forces are not in any way connected to rumors of [station_name()] being covered in graffiti."
if(GANG_OPERATING)
news_message = "The company would like to state that any rumors of criminal organizing on board stations such as [station_name()] are falsehoods, and not to be emulated."
if(GANG_DESTROYED)
news_message = "The crew of [station_name()] would like to thank the Spinward Stellar Coalition Police Department for quickly resolving a minor terror threat to the station."
if(SSblackbox.first_death)
var/list/ded = SSblackbox.first_death
+1
View File
@@ -224,6 +224,7 @@
else
to_chat(owner, "<span class='userdanger'>You feel your heart lurching in your chest...</span>")
owner.adjustOxyLoss(8)
else
/datum/brain_trauma/severe/discoordination
name = "Discoordination"
+62 -35
View File
@@ -4,7 +4,7 @@
var/window_id // window_id is used as the window name for browse and onclose
var/width = 0
var/height = 0
var/atom/ref = null
var/datum/weakref/ref = null
var/window_options = "can_close=1;can_minimize=1;can_maximize=0;can_resize=1;titlebar=1;" // window option is set using window_id
var/stylesheets[0]
var/scripts[0]
@@ -16,8 +16,8 @@
/datum/browser/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, atom/nref = null)
user = nuser
RegisterSignal(user, COMSIG_PARENT_QDELETING, .proc/user_deleted)
window_id = nwindow_id
if (ntitle)
title = format_text(ntitle)
@@ -26,7 +26,11 @@
if (nheight)
height = nheight
if (nref)
ref = nref
ref = WEAKREF(nref)
/datum/browser/proc/user_deleted(datum/source)
SIGNAL_HANDLER
user = null
/datum/browser/proc/add_head_content(nhead_content)
head_content = nhead_content
@@ -35,7 +39,7 @@
window_options = nwindow_options
/datum/browser/proc/add_stylesheet(name, file)
if(istype(name, /datum/asset/spritesheet))
if (istype(name, /datum/asset/spritesheet))
var/datum/asset/spritesheet/sheet = name
stylesheets["spritesheet_[sheet.name].css"] = "data/spritesheets/[sheet.name]"
else
@@ -94,27 +98,32 @@
"}
/datum/browser/proc/open(use_onclose = TRUE)
if(isnull(window_id)) //null check because this can potentially nuke goonchat
if(isnull(window_id)) //null check because this can potentially nuke goonchat
WARNING("Browser [title] tried to open with a null ID")
to_chat(user, "<span class='userdanger'>The [title] browser you tried to open failed a sanity check! Please report this on github!</span>")
to_chat(user, span_userdanger("The [title] browser you tried to open failed a sanity check! Please report this on github!"))
return
var/window_size = ""
if(width && height)
if (width && height)
window_size = "size=[width]x[height];"
common_asset.send(user)
if(stylesheets.len)
if (stylesheets.len)
SSassets.transport.send_assets(user, stylesheets)
if(scripts.len)
if (scripts.len)
SSassets.transport.send_assets(user, scripts)
user << browse(get_content(), "window=[window_id];[window_size][window_options]")
if(use_onclose)
if (use_onclose)
setup_onclose()
/datum/browser/proc/setup_onclose()
set waitfor = 0 //winexists sleeps, so we don't need to.
for (var/i in 1 to 10)
if (user && winexists(user, window_id))
onclose(user, window_id, ref)
if (user?.client && winexists(user, window_id))
var/atom/send_ref
if(ref)
send_ref = ref.resolve()
if(!send_ref)
ref = null
onclose(user, window_id, send_ref)
break
/datum/browser/proc/close()
@@ -153,11 +162,35 @@
opentime = 0
close()
//designed as a drop in replacement for alert(); functions the same. (outside of needing User specified)
/proc/tgalert(mob/User, Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1, Timeout = 6000)
/**
* **DEPRECATED: USE tgui_alert(...) INSTEAD**
*
* Designed as a drop in replacement for alert(); functions the same. (outside of needing User specified)
* Arguments:
* * User - The user to show the alert to.
* * Message - The textual body of the alert.
* * Title - The title of the alert's window.
* * Button1 - The first button option.
* * Button2 - The second button option.
* * Button3 - The third button option.
* * StealFocus - Boolean operator controlling if the alert will steal the user's window focus.
* * Timeout - The timeout of the window, after which no responses will be valid.
*/
/proc/tgalert(mob/User, Message, Title, Button1="Ok", Button2, Button3, StealFocus = TRUE, Timeout = 6000)
if (!User)
User = usr
switch(askuser(User, Message, Title, Button1, Button2, Button3, StealFocus, Timeout))
if (!istype(User))
if (istype(User, /client))
var/client/client = User
User = client.mob
else
return
// Get user's response using a modal
var/datum/browser/modal/alert/A = new(User, Message, Title, Button1, Button2, Button3, StealFocus, Timeout)
A.open()
A.wait()
switch(A.selectedbutton)
if (1)
return Button1
if (2)
@@ -197,8 +230,8 @@
.=..()
opentime = 0
/datum/browser/modal/open(use_onclose = 1)
set waitfor = 0
/datum/browser/modal/open(use_onclose)
set waitfor = FALSE
opentime = world.time
if (stealfocus)
@@ -277,7 +310,7 @@
opentime = 0
close()
/proc/presentpicker(var/mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1,Timeout = 6000,list/values, inputtype = "checkbox", width, height, slidecolor)
/proc/presentpicker(mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1,Timeout = 6000,list/values, inputtype = "checkbox", width, height, slidecolor)
if (!istype(User))
if (istype(User, /client/))
var/client/C = User
@@ -290,7 +323,7 @@
if (A.selectedbutton)
return list("button" = A.selectedbutton, "values" = A.valueslist)
/proc/input_bitfield(var/mob/User, title, bitfield, current_value, nwidth = 350, nheight = 350, nslidecolor, allowed_edit_list = null)
/proc/input_bitfield(mob/User, title, bitfield, current_value, nwidth = 350, nheight = 350, nslidecolor, allowed_edit_list = null)
if (!User || !(bitfield in GLOB.bitfields))
return
var/list/pickerlist = list()
@@ -401,7 +434,7 @@
opentime = 0
close()
/proc/presentpreflikepicker(var/mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1,Timeout = 6000,list/settings, width, height, slidecolor)
/proc/presentpreflikepicker(mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1,Timeout = 6000,list/settings, width, height, slidecolor)
if (!istype(User))
if (istype(User, /client/))
var/client/C = User
@@ -414,12 +447,6 @@
if (A.selectedbutton)
return list("button" = A.selectedbutton, "settings" = A.settings)
// This will allow you to show an icon in the browse window
// This is added to mob so that it can be used without a reference to the browser object
// There is probably a better place for this...
/mob/proc/browse_rsc_icon(icon, icon_state, dir = -1)
// Registers the on-close verb for a browse window (client/verb/.windowclose)
// this will be called when the close-button of a window is pressed.
//
@@ -427,8 +454,8 @@
// e.g. canisters, timers, etc.
//
// windowid should be the specified window name
// e.g. code is : user << browse(text, "window=fred")
// then use : onclose(user, "fred")
// e.g. code is : user << browse(text, "window=fred")
// then use : onclose(user, "fred")
//
// Optionally, specify the "ref" parameter as the controlled atom (usually src)
// to pass a "close=1" parameter to the atom's Topic() proc for special handling.
@@ -451,18 +478,18 @@
// otherwise, just reset the client mob's machine var.
//
/client/verb/windowclose(atomref as text)
set hidden = TRUE // hide this verb from the user's panel
set name = ".windowclose" // no autocomplete on cmd line
set hidden = TRUE // hide this verb from the user's panel
set name = ".windowclose" // no autocomplete on cmd line
if(atomref!="null") // if passed a real atomref
var/hsrc = locate(atomref) // find the reffed atom
if(atomref!="null") // if passed a real atomref
var/hsrc = locate(atomref) // find the reffed atom
var/href = "close=1"
if(hsrc)
usr = src.mob
src.Topic(href, params2list(href), hsrc) // this will direct to the atom's
return // Topic() proc via client.Topic()
src.Topic(href, params2list(href), hsrc) // this will direct to the atom's
return // Topic() proc via client.Topic()
// no atomref specified (or not found)
// so just reset the user mob's machine var
if(src && src.mob)
if(src?.mob)
src.mob.unset_machine()
+32
View File
@@ -0,0 +1,32 @@
/datum/changelog
var/static/list/changelog_items = list()
/datum/changelog/ui_state()
return GLOB.always_state
/datum/changelog/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if (!ui)
ui = new(user, src, "Changelog")
ui.open()
/datum/changelog/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
if(action == "get_month")
var/datum/asset/changelog_item/changelog_item = changelog_items[params["date"]]
if (!changelog_item)
changelog_item = new /datum/asset/changelog_item(params["date"])
changelog_items[params["date"]] = changelog_item
return ui.send_asset(changelog_item)
/datum/changelog/ui_static_data()
var/list/data = list( "dates" = list() )
var/regex/ymlRegex = regex(@"\.yml", "g")
for(var/archive_file in flist("[global.config.directory]/../html/changelogs/archive/"))
var/archive_date = ymlRegex.Replace(archive_file, "")
data["dates"] = list(archive_date) + data["dates"]
return data
+2 -4
View File
@@ -18,8 +18,6 @@
#define CHAT_LAYER_Z_STEP 0.0001
/// The number of z-layer 'slices' usable by the chat message layering
#define CHAT_LAYER_MAX_Z (CHAT_LAYER_MAX - CHAT_LAYER) / CHAT_LAYER_Z_STEP
/// Macro from Lummox used to get height from a MeasureText proc
#define WXH_TO_HEIGHT(x) text2num(copytext(x, findtextEx(x, "x") + 1))
/**
* # Chat Message Overlay
@@ -125,7 +123,7 @@
// Append radio icon if from a virtual speaker
if (extra_classes.Find("virtual-speaker"))
var/image/r_icon = image('icons/UI_Icons/chat/chat_icons.dmi', icon_state = "radio")
var/image/r_icon = image('icons/ui_icons/chat/chat_icons.dmi', icon_state = "radio")
text = "\icon[r_icon]&nbsp;" + text
// We dim italicized text to make it more distinguishable from regular text
@@ -165,7 +163,7 @@
message.maptext_width = CHAT_MESSAGE_WIDTH
message.maptext_height = mheight
message.maptext_x = (CHAT_MESSAGE_WIDTH - owner.bound_width) * -0.5
message.maptext = complete_text
message.maptext = MAPTEXT(complete_text)
// View the message
LAZYADDASSOC(owned_by.seen_messages, message_loc, src)
+1 -1
View File
@@ -101,7 +101,7 @@
if(!C)
return
watching += C
M.overlay_fullscreen("cinematic",/atom/movable/screen/fullscreen/cinematic_backdrop)
M.overlay_fullscreen("cinematic",/atom/movable/screen/fullscreen/tiled/cinematic_backdrop)
C.screen += screen
//Sound helper
@@ -0,0 +1,77 @@
///Allows you to set a theme for a set of areas without tying them to looping sounds explicitly
/datum/component/area_sound_manager
///area -> looping sound type
var/list/area_to_looping_type = list()
///Current sound loop
var/datum/looping_sound/our_loop
///A list of "acceptable" z levels to be on. If you leave this, we're gonna delete ourselves
var/list/accepted_zs
///The timer id of our current start delay, if it exists
var/timerid
/datum/component/area_sound_manager/Initialize(area_loop_pairs, change_on, remove_on, acceptable_zs)
if(!ismovable(parent))
return
area_to_looping_type = area_loop_pairs
accepted_zs = acceptable_zs
change_the_track()
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/react_to_move)
RegisterSignal(parent, COMSIG_MOVABLE_Z_CHANGED, .proc/react_to_z_move)
RegisterSignal(parent, change_on, .proc/handle_change)
RegisterSignal(parent, remove_on, .proc/handle_removal)
/datum/component/area_sound_manager/Destroy(force, silent)
QDEL_NULL(our_loop)
. = ..()
/datum/component/area_sound_manager/proc/react_to_move(datum/source, atom/oldloc, dir, forced)
SIGNAL_HANDLER
var/list/loop_lookup = area_to_looping_type
if(loop_lookup[get_area(oldloc)] == loop_lookup[get_area(parent)])
return
change_the_track(TRUE)
/datum/component/area_sound_manager/proc/react_to_z_move(datum/source, old_z, new_z)
SIGNAL_HANDLER
if(!length(accepted_zs) || (new_z in accepted_zs))
return
qdel(src)
/datum/component/area_sound_manager/proc/handle_removal(datum/source)
SIGNAL_HANDLER
qdel(src)
/datum/component/area_sound_manager/proc/handle_change(datum/source)
SIGNAL_HANDLER
change_the_track()
/datum/component/area_sound_manager/proc/change_the_track(skip_start = FALSE)
var/time_remaining = 0
if(our_loop)
var/our_id = our_loop.timerid || timerid
if(our_id)
time_remaining = timeleft(our_id, SSsound_loops) || 0
//Time left will sometimes return negative values, just ignore them and start a new sound loop now
time_remaining = max(time_remaining, 0)
QDEL_NULL(our_loop)
var/area/our_area = get_area(parent)
var/new_loop_type = area_to_looping_type[our_area]
if(!new_loop_type)
return
our_loop = new new_loop_type(parent, FALSE, TRUE, skip_start)
//If we're still playing, wait a bit before changing the sound so we don't double up
if(time_remaining)
timerid = addtimer(CALLBACK(src, .proc/start_looping_sound), time_remaining, TIMER_UNIQUE | TIMER_CLIENT_TIME | TIMER_STOPPABLE | TIMER_NO_HASH_WAIT | TIMER_DELETE_ME, SSsound_loops)
return
timerid = null
our_loop.start()
/datum/component/area_sound_manager/proc/start_looping_sound()
timerid = null
if(our_loop)
our_loop.start()
@@ -66,7 +66,7 @@
/datum/component/storage/concrete/_insert_physical_item(obj/item/I, override = FALSE)
. = TRUE
var/atom/real_location = real_location()
if(I.loc != real_location && real_location)
if(real_location && I.loc != real_location)
I.forceMove(real_location)
refresh_mob_views()
@@ -95,16 +95,19 @@
return FALSE
/datum/component/storage/concrete/proc/on_contents_del(datum/source, atom/A)
SIGNAL_HANDLER
var/atom/real_location = parent
if(A in real_location)
usr = null
remove_from_storage(A, null)
/datum/component/storage/concrete/proc/on_deconstruct(datum/source, disassembled)
SIGNAL_HANDLER
if(drop_all_on_deconstruct)
do_quick_empty()
/datum/component/storage/concrete/proc/on_break(datum/source, damage_flag)
SIGNAL_HANDLER
if(drop_all_on_break)
do_quick_empty()
if(unlock_on_break)
@@ -131,14 +134,16 @@
var/list/seeing_mobs = can_see_contents()
for(var/mob/M in seeing_mobs)
M.client.screen -= AM
if(ismob(parent.loc) && isitem(AM))
var/obj/item/I = AM
var/mob/M = parent.loc
I.dropped(M)
I.item_flags &= ~IN_STORAGE
I.remove_outline()
if(isitem(AM))
var/obj/item/removed_item = AM
removed_item.item_flags &= ~IN_STORAGE
if(ismob(parent.loc))
var/mob/carrying_mob = parent.loc
removed_item.dropped(carrying_mob, TRUE)
if(new_location)
AM.forceMove(new_location) // exited comsig will handle removal reset.
//Reset the items values
_removal_reset(AM)
AM.forceMove(new_location)
//We don't want to call this if the item is being destroyed
AM.on_exit_storage(src)
else
@@ -147,7 +152,7 @@
refresh_mob_views()
if(isobj(parent))
var/obj/O = parent
O.update_icon()
O.update_appearance()
return TRUE
/datum/component/storage/concrete/proc/slave_can_insert_object(datum/component/storage/slave, obj/item/I, stop_messages = FALSE, mob/M)
@@ -158,7 +163,7 @@
if(. && !prevent_warning)
slave.mob_item_insertion_feedback(usr, M, I)
/datum/component/storage/concrete/handle_item_insertion(obj/item/I, prevent_warning = FALSE, mob/M, datum/component/storage/remote) //Remote is null or the slave datum
/datum/component/storage/concrete/handle_item_insertion(obj/item/I, prevent_warning = FALSE, mob/M, datum/component/storage/remote) //Remote is null or the slave datum
var/datum/component/storage/concrete/master = master()
var/atom/parent = src.parent
var/moved = FALSE
@@ -168,7 +173,7 @@
if(!M.temporarilyRemoveItemFromInventory(I))
return FALSE
else
moved = TRUE //At this point if the proc fails we need to manually move the object back to the turf/mob/whatever.
moved = TRUE //At this point if the proc fails we need to manually move the object back to the turf/mob/whatever.
if(I.pulledby)
I.pulledby.stop_pulling()
if(silent)
@@ -203,7 +208,7 @@
/datum/component/storage/concrete/update_icon()
if(isobj(parent))
var/obj/O = parent
O.update_icon()
O.update_appearance()
for(var/i in slaves)
var/datum/component/storage/slave = i
slave.update_icon()
+29 -29
View File
@@ -418,38 +418,38 @@
return TRUE
/datum/component/storage/proc/mousedrop_onto(datum/source, atom/over_object, mob/M)
SIGNAL_HANDLER
set waitfor = FALSE
. = COMPONENT_NO_MOUSEDROP
if(!ismob(M))
return
if(!over_object)
return
if(ismecha(M.loc)) // stops inventory actions in a mech
return
if(M.incapacitated() || !M.canUseStorage())
return
var/atom/A = parent
if(ismob(M)) //all the check for item manipulation are in other places, you can safely open any storages as anything and its not buggy, i checked
A.add_fingerprint(M)
if(istype(A, /obj/item))
var/obj/item/I = A
I.remove_outline() //Removes the outline when we drag
if(!over_object)
return FALSE
if(ismecha(M.loc)) // stops inventory actions in a mech
return FALSE
// this must come before the screen objects only block, dunno why it wasn't before
if(over_object == M)
user_show_to_mob(M, trigger_on_found = TRUE)
return
if(isrevenant(M))
RevenantThrow(over_object, M, source)
return
if(!M.incapacitated())
if(!istype(over_object, /atom/movable/screen))
dump_content_at(over_object, M)
return
if(A.loc != M)
return
playsound(A, "rustle", 50, 1, -5)
A.do_jiggle()
if(istype(over_object, /atom/movable/screen/inventory/hand))
var/atom/movable/screen/inventory/hand/H = over_object
M.putItemFromInventoryInHandIfPossible(A, H.held_index)
return
A.add_fingerprint(M)
A.add_fingerprint(M)
// this must come before the screen objects only block, dunno why it wasn't before
if(over_object == M)
user_show_to_mob(M, trigger_on_found = TRUE)
if(isrevenant(M))
INVOKE_ASYNC(GLOBAL_PROC, .proc/RevenantThrow, over_object, M, source)
return
if(!istype(over_object, /atom/movable/screen))
INVOKE_ASYNC(src, .proc/dump_content_at, over_object, M)
return
if(A.loc != M)
return
playsound(A, "rustle", 50, TRUE, -5)
A.do_jiggle()
if(istype(over_object, /atom/movable/screen/inventory/hand))
var/atom/movable/screen/inventory/hand/H = over_object
M.putItemFromInventoryInHandIfPossible(A, H.held_index)
return
A.add_fingerprint(M)
/datum/component/storage/proc/user_show_to_mob(mob/M, force = FALSE, trigger_on_found = FALSE)
var/atom/A = parent
+3 -3
View File
@@ -370,7 +370,7 @@
user.emote("scream")
user.gain_trauma(/datum/brain_trauma/severe/paralysis/spinesnapped) // oopsie indeed!
shake_camera(user, 7, 7)
user.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/flash)
user.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/tiled/flash)
user.clear_fullscreen("flash", 4.5)
if(94 to 98)
@@ -381,7 +381,7 @@
user.gain_trauma_type(BRAIN_TRAUMA_MILD)
user.playsound_local(get_turf(user), 'sound/weapons/flashbang.ogg', 100, TRUE, 8, 0.9)
shake_camera(user, 6, 6)
user.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/flash)
user.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/tiled/flash)
user.clear_fullscreen("flash", 3.5)
if(84 to 93)
@@ -394,7 +394,7 @@
user.playsound_local(get_turf(user), 'sound/weapons/flashbang.ogg', 100, TRUE, 8, 0.9)
user.DefaultCombatKnockdown(40)
shake_camera(user, 5, 5)
user.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/flash)
user.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/tiled/flash)
user.clear_fullscreen("flash", 2.5)
if(64 to 83)
+92 -58
View File
@@ -1,4 +1,5 @@
GLOBAL_LIST_EMPTY(uplinks)
#define PEN_ROTATIONS 2
/**
* Uplinks
@@ -17,7 +18,7 @@ GLOBAL_LIST_EMPTY(uplinks)
var/telecrystals
var/selected_cat
var/owner = null
var/datum/game_mode/gamemode
var/uplink_flag
var/datum/uplink_purchase_log/purchase_log
var/list/uplink_items
var/hidden_crystals = 0
@@ -26,11 +27,11 @@ GLOBAL_LIST_EMPTY(uplinks)
var/failsafe_code
var/compact_mode = FALSE
var/debug = FALSE
var/saved_player_population = 0
var/list/filters = list()
///Instructions on how to access the uplink based on location
var/unlock_text
var/list/previous_attempts
/datum/component/uplink/Initialize(_owner, _lockable = TRUE, _enabled = FALSE, datum/game_mode/_gamemode, starting_tc = 20, datum/traitor_class/traitor_class)
/datum/component/uplink/Initialize(_owner, _lockable = TRUE, _enabled = FALSE, uplink_flag = UPLINK_TRAITORS, starting_tc = TELECRYSTALS_DEFAULT)
if(!isitem(parent))
return COMPONENT_INCOMPATIBLE
@@ -44,16 +45,13 @@ GLOBAL_LIST_EMPTY(uplinks)
RegisterSignal(parent, COMSIG_IMPLANT_EXISTING_UPLINK, .proc/new_implant)
else if(istype(parent, /obj/item/pda))
RegisterSignal(parent, COMSIG_PDA_CHANGE_RINGTONE, .proc/new_ringtone)
// RegisterSignal(parent, COMSIG_PDA_CHECK_DETONATE, .proc/check_detonate)
else if(istype(parent, /obj/item/radio))
RegisterSignal(parent, COMSIG_RADIO_NEW_FREQUENCY, .proc/new_frequency)
else if(istype(parent, /obj/item/pen))
RegisterSignal(parent, COMSIG_PEN_ROTATED, .proc/pen_rotation)
GLOB.uplinks += src
if(istype(traitor_class))
filters = traitor_class.uplink_filters
starting_tc = traitor_class.TC
uplink_items = get_uplink_items(gamemode, TRUE, allow_restricted, filters)
GLOB.uplinks |= src
if(_owner)
owner = _owner
@@ -64,44 +62,58 @@ GLOBAL_LIST_EMPTY(uplinks)
purchase_log = new(owner, src)
lockable = _lockable
active = _enabled
gamemode = _gamemode
src.uplink_flag = uplink_flag
update_items()
telecrystals = starting_tc
if(!lockable)
active = TRUE
locked = FALSE
saved_player_population = GLOB.joined_player_list.len
previous_attempts = list()
/datum/component/uplink/InheritComponent(datum/component/uplink/U)
lockable |= U.lockable
active |= U.active
if(!gamemode)
gamemode = U.gamemode
uplink_flag |= U.uplink_flag
telecrystals += U.telecrystals
if(purchase_log && U.purchase_log)
purchase_log.MergeWithAndDel(U.purchase_log)
/datum/component/uplink/Destroy()
GLOB.uplinks -= src
gamemode = null
purchase_log = null
return ..()
/datum/component/uplink/proc/update_items()
var/updated_items
updated_items = get_uplink_items(uplink_flag, TRUE, allow_restricted)
update_sales(updated_items)
uplink_items = updated_items
/datum/component/uplink/proc/update_sales(updated_items)
var/discount_categories = list("Discounted Gear", "Discounted Team Gear", "Limited Stock Team Gear")
if (uplink_items == null)
return
for (var/category in discount_categories) // Makes sure discounted items aren't renewed or replaced
if (uplink_items[category] != null && updated_items[category] != null)
updated_items[category] = uplink_items[category]
/datum/component/uplink/proc/LoadTC(mob/user, obj/item/stack/telecrystal/TC, silent = FALSE)
if(!silent)
to_chat(user, "<span class='notice'>You slot [TC] into [parent] and charge its internal uplink.</span>")
to_chat(user, span_notice("You slot [TC] into [parent] and charge its internal uplink."))
var/amt = TC.amount
telecrystals += amt
TC.use(amt)
/datum/component/uplink/proc/set_gamemode(_gamemode)
gamemode = _gamemode
uplink_items = get_uplink_items(gamemode, TRUE, allow_restricted)
// log_uplink("[key_name(user)] loaded [amt] telecrystals into [parent]'s uplink")
/datum/component/uplink/proc/OnAttackBy(datum/source, obj/item/I, mob/user)
SIGNAL_HANDLER
if(!active)
return //no hitting everyone/everything just to try to slot tcs in!
return //no hitting everyone/everything just to try to slot tcs in!
if(istype(I, /obj/item/stack/telecrystal))
LoadTC(user, I)
// CIT SPECIFIC: STEALING from unlocked uplink.
if(active)
if(I.GetComponent(/datum/component/uplink))
var/datum/component/uplink/hidden_uplink = I.GetComponent(/datum/component/uplink)
@@ -118,31 +130,26 @@ GLOBAL_LIST_EMPTY(uplinks)
var/cost = UI.refund_amount || UI.cost
if(I.type == path && UI.refundable && I.check_uplink_validity())
telecrystals += cost
purchase_log.total_spent -= cost
to_chat(user, "<span class='notice'>[I] refunded.</span>")
// log_uplink("[key_name(user)] refunded [UI] for [cost] telecrystals using [parent]'s uplink")
if(purchase_log)
purchase_log.total_spent -= cost
to_chat(user, span_notice("[I] refunded."))
qdel(I)
return
/datum/component/uplink/proc/interact(datum/source, mob/user)
SIGNAL_HANDLER
if(locked)
return
active = TRUE
update_items()
if(user)
//update the saved population
var/previous_player_population = saved_player_population
saved_player_population = GLOB.joined_player_list.len
//if population has changed, update uplink items
if(saved_player_population != previous_player_population)
//make sure discounts are not rerolled
var/old_discounts = uplink_items["Discounted Gear"]
uplink_items = get_uplink_items(gamemode, FALSE, allow_restricted, filters)
if(old_discounts)
uplink_items["Discounted Gear"] = old_discounts
ui_interact(user)
INVOKE_ASYNC(src, .proc/ui_interact, user)
// an unlocked uplink blocks also opening the PDA or headset menu
return COMPONENT_NO_INTERACT
/datum/component/uplink/ui_state(mob/user)
if(istype(parent, /obj/item/implant/uplink))
return GLOB.not_incapacitated_state
@@ -178,15 +185,10 @@ GLOBAL_LIST_EMPTY(uplinks)
var/datum/uplink_item/I = uplink_items[category][item]
if(I.limited_stock == 0)
continue
if(I.restricted_roles.len)
var/is_inaccessible = TRUE
for(var/R in I.restricted_roles)
if(R == user.mind.assigned_role || debug)
is_inaccessible = FALSE
if(is_inaccessible)
if(length(I.restricted_roles))
if(!debug && !(user.mind.assigned_role in I.restricted_roles))
continue
/*
if(I.restricted_species) //catpeople specfic gloves.
if(I.restricted_species)
if(ishuman(user))
var/is_inaccessible = TRUE
var/mob/living/carbon/human/H = user
@@ -196,7 +198,6 @@ GLOBAL_LIST_EMPTY(uplinks)
break
if(is_inaccessible)
continue
*/
cat["items"] += list(list(
"name" = I.name,
"cost" = I.cost,
@@ -255,25 +256,41 @@ GLOBAL_LIST_EMPTY(uplinks)
// Implant signal responses
/datum/component/uplink/proc/implant_activation()
SIGNAL_HANDLER
var/obj/item/implant/implant = parent
locked = FALSE
interact(null, implant.imp_in)
/datum/component/uplink/proc/implanting(datum/source, list/arguments)
SIGNAL_HANDLER
var/mob/user = arguments[2]
owner = "[user.key]"
owner = user?.key
if(owner && !purchase_log)
LAZYINITLIST(GLOB.uplink_purchase_logs_by_key)
if(GLOB.uplink_purchase_logs_by_key[owner])
purchase_log = GLOB.uplink_purchase_logs_by_key[owner]
else
purchase_log = new(owner, src)
/datum/component/uplink/proc/old_implant(datum/source, list/arguments, obj/item/implant/new_implant)
SIGNAL_HANDLER
// It kinda has to be weird like this until implants are components
return SEND_SIGNAL(new_implant, COMSIG_IMPLANT_EXISTING_UPLINK, src)
/datum/component/uplink/proc/new_implant(datum/source, datum/component/uplink/uplink)
SIGNAL_HANDLER
uplink.telecrystals += telecrystals
return COMPONENT_DELETE_NEW_IMPLANT
// PDA signal responses
/datum/component/uplink/proc/new_ringtone(datum/source, mob/living/user, new_ring_text)
SIGNAL_HANDLER
var/obj/item/pda/master = parent
if(trim(lowertext(new_ring_text)) != trim(lowertext(unlock_code)))
if(trim(lowertext(new_ring_text)) == trim(lowertext(failsafe_code)))
@@ -282,14 +299,21 @@ GLOBAL_LIST_EMPTY(uplinks)
return
locked = FALSE
interact(null, user)
to_chat(user, "<span class='hear'>The PDA softly beeps.</span>")
to_chat(user, span_hear("The PDA softly beeps."))
user << browse(null, "window=pda")
master.mode = 0
return COMPONENT_STOP_RINGTONE_CHANGE
/datum/component/uplink/proc/check_detonate()
SIGNAL_HANDLER
// return COMPONENT_PDA_NO_DETONATE
// Radio signal responses
/datum/component/uplink/proc/new_frequency(datum/source, list/arguments)
SIGNAL_HANDLER
var/obj/item/radio/master = parent
var/frequency = arguments[1]
if(frequency != unlock_code)
@@ -303,15 +327,22 @@ GLOBAL_LIST_EMPTY(uplinks)
// Pen signal responses
/datum/component/uplink/proc/pen_rotation(datum/source, degrees, mob/living/carbon/user)
SIGNAL_HANDLER
var/obj/item/pen/master = parent
if(degrees != unlock_code)
if(degrees == failsafe_code) //Getting failsafes on pens is risky business
failsafe()
return
locked = FALSE
master.degrees = 0
interact(null, user)
to_chat(user, "<span class='warning'>Your pen makes a clicking noise, before quickly rotating back to 0 degrees!</span>")
previous_attempts += degrees
if(length(previous_attempts) > PEN_ROTATIONS)
popleft(previous_attempts)
if(compare_list(previous_attempts, unlock_code))
locked = FALSE
previous_attempts.Cut()
master.degrees = 0
interact(null, user)
to_chat(user, span_warning("Your pen makes a clicking noise, before quickly rotating back to 0 degrees!"))
else if(compare_list(previous_attempts, failsafe_code))
failsafe(user)
/datum/component/uplink/proc/setup_unlock_code()
unlock_code = generate_code()
@@ -321,15 +352,18 @@ GLOBAL_LIST_EMPTY(uplinks)
else if(istype(parent,/obj/item/radio))
unlock_note = "<B>Radio Frequency:</B> [format_frequency(unlock_code)] ([P.name])."
else if(istype(parent,/obj/item/pen))
unlock_note = "<B>Uplink Degrees:</B> [unlock_code] ([P.name])."
unlock_note = "<B>Uplink Degrees:</B> [english_list(unlock_code)] ([P.name])."
/datum/component/uplink/proc/generate_code()
if(istype(parent,/obj/item/pda))
return "[rand(100,999)] [pick(GLOB.phonetic_alphabet)]"
else if(istype(parent,/obj/item/radio))
return sanitize_frequency(rand(MIN_FREQ, MAX_FREQ))
return return_unused_frequency()
else if(istype(parent,/obj/item/pen))
return rand(1, 360)
var/list/L = list()
for(var/i in 1 to PEN_ROTATIONS)
L += rand(1, 360)
return L
/datum/component/uplink/proc/failsafe(mob/living/carbon/user)
if(!parent)
@@ -339,5 +373,5 @@ GLOBAL_LIST_EMPTY(uplinks)
return
message_admins("[ADMIN_LOOKUPFLW(user)] has triggered an uplink failsafe explosion at [AREACOORD(T)] The owner of the uplink was [ADMIN_LOOKUPFLW(owner)].")
log_game("[key_name(user)] triggered an uplink failsafe explosion. The owner of the uplink was [key_name(owner)].")
explosion(T,1,2,3)
explosion(parent, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 3)
qdel(parent) //Alternatively could brick the uplink.
+1 -1
View File
@@ -106,7 +106,7 @@
active_timers = null
for(var/thing in timers)
var/datum/timedevent/timer = thing
if (timer.spent)
if (timer.spent && !(timer.flags & TIMER_DELETE_ME))
continue
qdel(timer)
+1 -1
View File
@@ -30,7 +30,7 @@
return
switch(stage)
if(2 || 3) //Pretend to be a cold and give time to spread.
if(2, 3) //Pretend to be a cold and give time to spread.
if(prob(8))
affected_mob.emote("sneeze")
if(prob(8))
+1 -1
View File
@@ -168,7 +168,7 @@
L.visible_message("<span class='warning'>[held_mob] escapes from [L]!</span>", "<span class='warning'>[held_mob] escapes your grip!</span>")
release()
/obj/item/clothing/head/mob_holder/mob_can_equip(mob/living/M, mob/living/equipper, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE)
/obj/item/clothing/head/mob_holder/mob_can_equip(M, equipper, slot, disable_warning, bypass_equip_delay_self)
if(M == held_mob || !ishuman(M)) //monkeys holding monkeys holding monkeys...
return FALSE
return ..()
+517
View File
@@ -0,0 +1,517 @@
/// An element for atoms that, when dragged and dropped onto a mob, opens a strip panel.
/datum/element/strippable
element_flags = ELEMENT_BESPOKE | ELEMENT_DETACH
id_arg_index = 2
/// An assoc list of keys to /datum/strippable_item
var/list/items
/// A proc path that returns TRUE/FALSE if we should show the strip panel for this entity.
/// If it does not exist, the strip menu will always show.
/// Will be called with (mob/user).
var/should_strip_proc_path
/// An existing strip menus
var/list/strip_menus
/datum/element/strippable/Attach(datum/target, list/items, should_strip_proc_path)
. = ..()
if (!isatom(target))
return ELEMENT_INCOMPATIBLE
RegisterSignal(target, COMSIG_MOUSEDROP_ONTO, .proc/mouse_drop_onto)
src.items = items
src.should_strip_proc_path = should_strip_proc_path
/datum/element/strippable/Detach(datum/source)
. = ..()
UnregisterSignal(source, COMSIG_MOUSEDROP_ONTO)
if (!isnull(strip_menus))
qdel(strip_menus[source])
strip_menus -= source
/datum/element/strippable/proc/mouse_drop_onto(datum/source, atom/over, mob/user)
SIGNAL_HANDLER
if (user == source)
return
if (over != user)
return
// Cyborgs buckle people by dragging them onto them, unless in combat mode.
if (iscyborg(user))
var/mob/living/silicon/robot/cyborg_user = user
if (cyborg_user.a_intent == INTENT_HARM)
return
if (!isnull(should_strip_proc_path) && !call(source, should_strip_proc_path)(user))
return
var/datum/strip_menu/strip_menu
if (isnull(strip_menu))
strip_menu = new(source, src)
LAZYSET(strip_menus, source, strip_menu)
INVOKE_ASYNC(strip_menu, /datum/.proc/ui_interact, user)
/// A representation of an item that can be stripped down
/datum/strippable_item
/// The STRIPPABLE_ITEM_* key
var/key
/// Should we warn about dangerous clothing?
var/warn_dangerous_clothing = TRUE
/// Gets the item from the given source.
/datum/strippable_item/proc/get_item(atom/source)
/// Tries to equip the item onto the given source.
/// Returns TRUE/FALSE depending on if it is allowed.
/// This should be used for checking if an item CAN be equipped.
/// It should not perform the equipping itself.
/datum/strippable_item/proc/try_equip(atom/source, obj/item/equipping, mob/user)
if (HAS_TRAIT(equipping, TRAIT_NODROP))
to_chat(user, span_warning("You can't put [equipping] on [source], it's stuck to your hand!"))
return FALSE
return TRUE
/// Start the equipping process. This is the proc you should yield in.
/// Returns TRUE/FALSE depending on if it is allowed.
/datum/strippable_item/proc/start_equip(atom/source, obj/item/equipping, mob/user)
if (warn_dangerous_clothing && isclothing(source))
source.visible_message(
span_notice("[user] tries to put [equipping] on [source]."),
span_notice("[user] tries to put [equipping] on you."),
ignored_mobs = user,
)
if(ishuman(source))
var/mob/living/carbon/human/victim_human = source
if(victim_human.key && !victim_human.client) // AKA braindead
if(victim_human.stat <= SOFT_CRIT && LAZYLEN(victim_human.afk_thefts) <= AFK_THEFT_MAX_MESSAGES)
var/list/new_entry = list(list(user.name, "tried equipping you with [equipping]", world.time))
LAZYADD(victim_human.afk_thefts, new_entry)
to_chat(user, span_notice("You try to put [equipping] on [source]..."))
var/log = "[key_name(source)] is having [equipping] put on them by [key_name(user)]"
user.log_message(log, LOG_ATTACK, color="red")
source.log_message(log, LOG_VICTIM, color="red", log_globally=FALSE)
return TRUE
/// The proc that places the item on the source. This should not yield.
/datum/strippable_item/proc/finish_equip(atom/source, obj/item/equipping, mob/user)
SHOULD_NOT_SLEEP(TRUE)
return TRUE
/// Tries to unequip the item from the given source.
/// Returns TRUE/FALSE depending on if it is allowed.
/// This should be used for checking if it CAN be unequipped.
/// It should not perform the unequipping itself.
/datum/strippable_item/proc/try_unequip(atom/source, mob/user)
SHOULD_NOT_SLEEP(TRUE)
var/obj/item/item = get_item(source)
if (isnull(item))
return FALSE
if (ismob(source))
var/mob/mob_source = source
if (!item.canStrip(user, mob_source))
return FALSE
return TRUE
/// Start the unequipping process. This is the proc you should yield in.
/// Returns TRUE/FALSE depending on if it is allowed.
/datum/strippable_item/proc/start_unequip(atom/source, mob/user)
var/obj/item/item = get_item(source)
if (isnull(item))
return FALSE
source.visible_message(
span_warning("[user] tries to remove [source]'s [item.name]."),
span_userdanger("[user] tries to remove your [item.name]."),
ignored_mobs = user,
)
to_chat(user, span_danger("You try to remove [source]'s [item]..."))
user.log_message("[key_name(source)] is being stripped of [item] by [key_name(user)]", LOG_ATTACK, color="red")
source.log_message("[key_name(source)] is being stripped of [item] by [key_name(user)]", LOG_VICTIM, color="red", log_globally=FALSE)
item.add_fingerprint(source)
if(ishuman(source))
var/mob/living/carbon/human/victim_human = source
if(victim_human.key && !victim_human.client) // AKA braindead
if(victim_human.stat <= SOFT_CRIT && LAZYLEN(victim_human.afk_thefts) <= AFK_THEFT_MAX_MESSAGES)
var/list/new_entry = list(list(user.name, "tried unequipping your [item.name]", world.time))
LAZYADD(victim_human.afk_thefts, new_entry)
return TRUE
/// The proc that unequips the item from the source. This should not yield.
/datum/strippable_item/proc/finish_unequip(atom/source, mob/user)
/// Returns a STRIPPABLE_OBSCURING_* define to report on whether or not this is obscured.
/datum/strippable_item/proc/get_obscuring(atom/source)
SHOULD_NOT_SLEEP(TRUE)
return STRIPPABLE_OBSCURING_NONE
/// Returns the ID of this item's strippable action.
/// Return `null` if there is no alternate action.
/// Any return value of this must be in StripMenu.
/datum/strippable_item/proc/get_alternate_action(atom/source, mob/user)
if(get_obscuring(source) == STRIPPABLE_OBSCURING_COMPLETELY)
return FALSE
return null
/// Performs an alternative action on this strippable_item.
/// `has_alternate_action` needs to be TRUE.
/datum/strippable_item/proc/alternate_action(atom/source, mob/user)
if(get_obscuring(source) == STRIPPABLE_OBSCURING_COMPLETELY)
return null
return TRUE
/// Returns whether or not this item should show.
/datum/strippable_item/proc/should_show(atom/source, mob/user)
return TRUE
/// A preset for equipping items onto mob slots
/datum/strippable_item/mob_item_slot
/// The ITEM_SLOT_* to equip to.
var/item_slot
/datum/strippable_item/mob_item_slot/get_item(atom/source)
if (!ismob(source))
return null
var/mob/mob_source = source
return mob_source.get_item_by_slot(item_slot)
/datum/strippable_item/mob_item_slot/try_equip(atom/source, obj/item/equipping, mob/user)
. = ..()
if (!.)
return
if (!ismob(source))
return FALSE
if (!equipping.mob_can_equip(
source,
user,
item_slot,
disable_warning = TRUE,
bypass_equip_delay_self = TRUE,
))
to_chat(user, span_warning("\The [equipping] doesn't fit in that place!"))
return FALSE
return TRUE
/datum/strippable_item/mob_item_slot/start_equip(atom/source, obj/item/equipping, mob/user)
. = ..()
if (!.)
return
if (!ismob(source))
return FALSE
if (!do_mob(user, source, get_equip_delay(equipping)))
return FALSE
if(get_obscuring(source) == STRIPPABLE_OBSCURING_COMPLETELY)
return FALSE
if (!equipping.mob_can_equip(
source,
user,
item_slot,
disable_warning = TRUE,
bypass_equip_delay_self = TRUE,
))
return FALSE
if (!user.temporarilyRemoveItemFromInventory(equipping))
return FALSE
return TRUE
/datum/strippable_item/mob_item_slot/finish_equip(atom/source, obj/item/equipping, mob/user)
if(!..())
return FALSE
if (!ismob(source))
return FALSE
var/mob/mob_source = source
mob_source.equip_to_slot(equipping, item_slot)
/datum/strippable_item/mob_item_slot/get_obscuring(atom/source)
if (iscarbon(source))
var/mob/living/carbon/carbon_source = source
return (item_slot in carbon_source.check_obscured_slots()) \
? STRIPPABLE_OBSCURING_COMPLETELY \
: STRIPPABLE_OBSCURING_NONE
return FALSE
/datum/strippable_item/mob_item_slot/start_unequip(atom/source, mob/user)
. = ..()
if (!.)
return
return start_unequip_mob(get_item(source), source, user)
/datum/strippable_item/mob_item_slot/finish_unequip(atom/source, mob/user)
var/obj/item/item = get_item(source)
if (isnull(item))
return FALSE
if (!ismob(source))
return FALSE
return finish_unequip_mob(item, source, user)
/// Returns the delay of equipping this item to a mob
/datum/strippable_item/mob_item_slot/proc/get_equip_delay(obj/item/equipping)
return equipping.equip_delay_other
/// A utility function for `/datum/strippable_item`s to start unequipping an item from a mob.
/proc/start_unequip_mob(obj/item/item, mob/source, mob/user, strip_delay)
if (!do_mob(user, source, strip_delay || item.strip_delay, ignorehelditem = TRUE))
return FALSE
return TRUE
/// A utility function for `/datum/strippable_item`s to finish unequipping an item from a mob.
/proc/finish_unequip_mob(obj/item/item, mob/source, mob/user)
if (!item.doStrip(user, source))
return FALSE
user.log_message("[key_name(source)] has been stripped of [item] by [key_name(user)]", LOG_ATTACK, color="red")
source.log_message("[key_name(source)] has been stripped of [item] by [key_name(user)]", LOG_VICTIM, color="red", log_globally=FALSE)
// Updates speed in case stripped speed affecting item
source.update_equipment_speed_mods()
/// A representation of the stripping UI
/datum/strip_menu
/// The owner who has the element /datum/element/strippable
var/atom/movable/owner
/// The strippable element itself
var/datum/element/strippable/strippable
/// A lazy list of user mobs to a list of strip menu keys that they're interacting with
var/list/interactions
/datum/strip_menu/New(atom/movable/owner, datum/element/strippable/strippable)
. = ..()
src.owner = owner
src.strippable = strippable
/datum/strip_menu/Destroy()
owner = null
strippable = null
return ..()
/datum/strip_menu/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if (!ui)
ui = new(user, src, "StripMenu")
ui.open()
/datum/strip_menu/ui_assets(mob/user)
return list(
get_asset_datum(/datum/asset/simple/inventory),
)
/datum/strip_menu/ui_data(mob/user)
var/list/data = list()
var/list/items = list()
for (var/strippable_key in strippable.items)
var/datum/strippable_item/item_data = strippable.items[strippable_key]
if (!item_data.should_show(owner, user))
continue
var/list/result
if(strippable_key in LAZYACCESS(interactions, user))
LAZYSET(result, "interacting", TRUE)
var/obscuring = item_data.get_obscuring(owner)
if (obscuring != STRIPPABLE_OBSCURING_NONE)
LAZYSET(result, "obscured", obscuring)
items[strippable_key] = result
continue
var/obj/item/item = item_data.get_item(owner)
if (isnull(item))
items[strippable_key] = result
continue
LAZYINITLIST(result)
result["icon"] = icon2base64(icon(item.icon, item.icon_state, SOUTH, 1))
result["name"] = item.name
result["alternate"] = item_data.get_alternate_action(owner, user)
items[strippable_key] = result
data["items"] = items
// While most `\the`s are implicit, this one is not.
// In this case, `\The` would otherwise be used.
// This doesn't match with what it's used for, which is to say "Stripping the alien drone",
// as opposed to "Stripping The alien drone".
// Human names will still show without "the", as they are proper nouns.
data["name"] = "\the [owner]"
/// Customize the strip menu
data["long_strip_menu"] = user.client.prefs.long_strip_menu
return data
/datum/strip_menu/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if (.)
return
. = TRUE
var/mob/user = usr
switch (action)
if ("use")
var/key = params["key"]
var/datum/strippable_item/strippable_item = strippable.items[key]
if (isnull(strippable_item))
return
if (!strippable_item.should_show(owner, user))
return
if (strippable_item.get_obscuring(owner) == STRIPPABLE_OBSCURING_COMPLETELY)
return
var/item = strippable_item.get_item(owner)
if (isnull(item))
var/obj/item/held_item = user.get_active_held_item()
if (isnull(held_item))
return
if (strippable_item.try_equip(owner, held_item, user))
LAZYORASSOCLIST(interactions, user, key)
// Yielding call
var/should_finish = strippable_item.start_equip(owner, held_item, user)
LAZYREMOVEASSOC(interactions, user, key)
if (!should_finish)
return
if (QDELETED(src) || QDELETED(owner))
return
// They equipped an item in the meantime
if (!isnull(strippable_item.get_item(owner)))
return
if (!user.Adjacent(owner))
return
strippable_item.finish_equip(owner, held_item, user)
else if (strippable_item.try_unequip(owner, user))
LAZYORASSOCLIST(interactions, user, key)
var/should_unequip = strippable_item.start_unequip(owner, user)
LAZYREMOVEASSOC(interactions, user, key)
// Yielding call
if (!should_unequip)
return
if (QDELETED(src) || QDELETED(owner))
return
// They changed the item in the meantime
if (strippable_item.get_item(owner) != item)
return
if (!user.Adjacent(owner))
return
strippable_item.finish_unequip(owner, user)
if ("alt")
var/key = params["key"]
var/datum/strippable_item/strippable_item = strippable.items[key]
if (isnull(strippable_item))
return
if (!strippable_item.should_show(owner, user))
return
if (strippable_item.get_obscuring(owner) == STRIPPABLE_OBSCURING_COMPLETELY)
return
var/item = strippable_item.get_item(owner)
if (isnull(item))
return
if (isnull(strippable_item.get_alternate_action(owner, user)))
return
LAZYORASSOCLIST(interactions, user, key)
// Potentially yielding
strippable_item.alternate_action(owner, user)
LAZYREMOVEASSOC(interactions, user, key)
/datum/strip_menu/ui_host(mob/user)
return owner
/datum/strip_menu/ui_state(mob/user)
return GLOB.always_state
/datum/strip_menu/ui_status(mob/user, datum/ui_state/state)
. = ..()
if(isliving(user))
var/mob/living/living_user = user
if (
living_user.stat == CONSCIOUS \
&& living_user.Adjacent(owner)
)
return UI_INTERACTIVE
if(IsAdminGhost(user))
return UI_INTERACTIVE
if(user.Adjacent(owner))
return UI_UPDATE
else
return UI_DISABLED
/// Creates an assoc list of keys to /datum/strippable_item
/proc/create_strippable_list(types)
var/list/strippable_items = list()
for (var/strippable_type in types)
var/datum/strippable_item/strippable_item = new strippable_type
strippable_items[strippable_item.key] = strippable_item
return strippable_items
+44
View File
@@ -0,0 +1,44 @@
///This element just handles creating and destroying an area sound manager that's hooked into weather stuff
/datum/element/weather_listener
element_flags = ELEMENT_BESPOKE
id_arg_index = 2
var/weather_type
//What events to change the track on
var/list/sound_change_signals
//The weather type we're working with
var/weather_trait
//The playlist of sounds to draw from. Pass by ref
var/list/playlist
/datum/element/weather_listener/Attach(datum/target, w_type, trait, weather_playlist)
. = ..()
if(!weather_type)
weather_type = w_type
sound_change_signals = list(
COMSIG_WEATHER_TELEGRAPH(weather_type),
COMSIG_WEATHER_START(weather_type),
COMSIG_WEATHER_WINDDOWN(weather_type),
COMSIG_WEATHER_END(weather_type)
)
weather_trait = trait
playlist = weather_playlist
RegisterSignal(target, COMSIG_MOVABLE_Z_CHANGED, .proc/handle_z_level_change, override = TRUE)
RegisterSignal(target, COMSIG_MOB_CLIENT_LOGOUT, .proc/handle_logout, override = TRUE)
/datum/element/weather_listener/Detach(datum/source)
. = ..()
UnregisterSignal(source, COMSIG_MOVABLE_Z_CHANGED, COMSIG_MOB_CLIENT_LOGOUT)
/datum/element/weather_listener/proc/handle_z_level_change(datum/source, old_z, new_z)
SIGNAL_HANDLER
var/list/fitting_z_levels = SSmapping.levels_by_trait(weather_trait)
if(!(new_z in fitting_z_levels))
return
var/datum/component/our_comp = source.AddComponent(/datum/component/area_sound_manager, playlist, list(), COMSIG_MOB_CLIENT_LOGOUT, fitting_z_levels)
our_comp.RegisterSignal(SSdcs, sound_change_signals, /datum/component/area_sound_manager/proc/handle_change)
/datum/element/weather_listener/proc/handle_logout(datum/source, client/this_is_a_null_ref)
SIGNAL_HANDLER
source.RemoveElement(/datum/element/weather_listener, weather_type, weather_trait, playlist)
+47 -34
View File
@@ -1,21 +1,21 @@
/*
output_atoms (list of atoms) The destination(s) for the sounds
output_atoms (list of atoms) The destination(s) for the sounds
mid_sounds (list or soundfile) Since this can be either a list or a single soundfile you can have random sounds. May contain further lists but must contain a soundfile at the end.
mid_length (num) The length to wait between playing mid_sounds
mid_sounds (list or soundfile) Since this can be either a list or a single soundfile you can have random sounds. May contain further lists but must contain a soundfile at the end.
mid_length (num) The length to wait between playing mid_sounds
start_sound (soundfile) Played before starting the mid_sounds loop
start_length (num) How long to wait before starting the main loop after playing start_sound
start_sound (soundfile) Played before starting the mid_sounds loop
start_length (num) How long to wait before starting the main loop after playing start_sound
end_sound (soundfile) The sound played after the main loop has concluded
end_sound (soundfile) The sound played after the main loop has concluded
chance (num) Chance per loop to play a mid_sound
volume (num) Sound output volume
max_loops (num) The max amount of loops to run for.
direct (bool) If true plays directly to provided atoms instead of from them
chance (num) Chance per loop to play a mid_sound
volume (num) Sound output volume
max_loops (num) The max amount of loops to run for.
direct (bool) If true plays directly to provided atoms instead of from them
*/
/datum/looping_sound
var/list/atom/output_atoms
var/atom/parent
var/mid_sounds
var/mid_length
///Override for volume of start sound
@@ -34,38 +34,46 @@
var/falloff_exponent
var/timerid
var/falloff_distance
var/skip_starting_sounds = FALSE
var/loop_started = FALSE
/datum/looping_sound/New(list/_output_atoms=list(), start_immediately=FALSE, _direct=FALSE)
/datum/looping_sound/New(_parent, start_immediately=FALSE, _direct=FALSE, _skip_starting_sounds = FALSE)
if(!mid_sounds)
WARNING("A looping sound datum was created without sounds to play.")
return
output_atoms = _output_atoms
set_parent(_parent)
direct = _direct
skip_starting_sounds = _skip_starting_sounds
if(start_immediately)
start()
/datum/looping_sound/Destroy()
stop()
output_atoms = null
stop(TRUE)
return ..()
/datum/looping_sound/proc/start(atom/add_thing)
if(add_thing)
output_atoms |= add_thing
/datum/looping_sound/proc/start(on_behalf_of)
if(on_behalf_of)
set_parent(on_behalf_of)
if(timerid)
return
on_start()
/datum/looping_sound/proc/stop(atom/remove_thing)
if(remove_thing)
output_atoms -= remove_thing
/datum/looping_sound/proc/stop(null_parent)
if(null_parent)
set_parent(null)
if(!timerid)
return
on_stop()
deltimer(timerid)
deltimer(timerid, SSsound_loops)
timerid = null
loop_started = FALSE
/datum/looping_sound/proc/start_sound_loop()
loop_started = TRUE
sound_loop()
timerid = addtimer(CALLBACK(src, .proc/sound_loop, world.time), mid_length, TIMER_CLIENT_TIME | TIMER_STOPPABLE | TIMER_LOOP | TIMER_DELETE_ME, SSsound_loops)
/datum/looping_sound/proc/sound_loop(starttime)
if(max_loops && world.time >= starttime + mid_length * max_loops)
@@ -73,21 +81,15 @@
return
if(!chance || prob(chance))
play(get_sound(starttime))
if(!timerid)
timerid = addtimer(CALLBACK(src, .proc/sound_loop, world.time), mid_length, TIMER_CLIENT_TIME | TIMER_STOPPABLE | TIMER_LOOP)
/datum/looping_sound/proc/play(soundfile, volume_override)
var/list/atoms_cache = output_atoms
var/sound/S = sound(soundfile)
if(direct)
S.channel = SSsounds.random_available_channel()
S.volume = volume_override || volume //Use volume as fallback if theres no override
for(var/i in 1 to atoms_cache.len)
var/atom/thing = atoms_cache[i]
if(direct)
SEND_SOUND(thing, S)
else
playsound(thing, S, volume, vary, extra_range, falloff_exponent = falloff_exponent, falloff_distance = falloff_distance)
SEND_SOUND(parent, S)
else
playsound(parent, S, volume, vary, extra_range, falloff_exponent = falloff_exponent, falloff_distance = falloff_distance)
/datum/looping_sound/proc/get_sound(starttime, _mid_sounds)
. = _mid_sounds || mid_sounds
@@ -96,11 +98,22 @@
/datum/looping_sound/proc/on_start()
var/start_wait = 0
if(start_sound)
if(start_sound && !skip_starting_sounds)
play(start_sound, start_volume)
start_wait = start_length
addtimer(CALLBACK(src, .proc/sound_loop), start_wait, TIMER_CLIENT_TIME)
timerid = addtimer(CALLBACK(src, .proc/start_sound_loop), start_wait, TIMER_CLIENT_TIME | TIMER_DELETE_ME | TIMER_STOPPABLE, SSsound_loops)
/datum/looping_sound/proc/on_stop()
if(end_sound)
if(end_sound && loop_started)
play(end_sound, end_volume)
/datum/looping_sound/proc/set_parent(new_parent)
if(parent)
UnregisterSignal(parent, COMSIG_PARENT_QDELETING)
parent = new_parent
if(parent)
RegisterSignal(parent, COMSIG_PARENT_QDELETING, .proc/handle_parent_del)
/datum/looping_sound/proc/handle_parent_del(datum/source)
SIGNAL_HANDLER
set_parent(null)

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