Merge branch 'master' into upstream-merge-33316

This commit is contained in:
deathride58
2017-12-11 00:01:02 +00:00
committed by GitHub
395 changed files with 6473 additions and 3467 deletions
+2 -2
View File
@@ -24,7 +24,7 @@
#define MUT_MUTE "Mute"
#define SMILE "Smile"
#define STONER "Stoner"
#define UNINTELLIGABLE "Unintelligable"
#define UNINTELLIGIBLE "Unintelligible"
#define SWEDISH "Swedish"
#define CHAV "Chav"
#define ELVIS "Elvis"
@@ -82,7 +82,7 @@
#define DNA_MUTANTTAIL_BLOCK 17
#define DNA_MUTANTWING_BLOCK 18
#define DNA_WINGCOLOR_BLOCK 19
#define DNA_STRUC_ENZYMES_BLOCKS 19
#define DNA_STRUC_ENZYMES_BLOCKS 18
#define DNA_UNIQUE_ENZYMES_LEN 32
//Transformation proc stuff
+65 -53
View File
@@ -1,14 +1,5 @@
#define FIRE_DAMAGE_MODIFIER 0.0215 //Higher values result in more external fire damage to the skin (default 0.0215)
#define AIR_DAMAGE_MODIFIER 2.025 //More means less damage from hot air scalding lungs, less = more damage. (default 2.025)
#define MOLES_CELLSTANDARD (ONE_ATMOSPHERE*CELL_VOLUME/(T20C*R_IDEAL_GAS_EQUATION)) //moles in a 2.5 m^3 cell at 101.325 Pa and 20 degC
#define M_CELL_WITH_RATIO (MOLES_CELLSTANDARD * 0.005)
#define O2STANDARD 0.21
#define N2STANDARD 0.79
#define MOLES_O2STANDARD (MOLES_CELLSTANDARD*O2STANDARD) // O2 standard value (21%)
#define MOLES_N2STANDARD (MOLES_CELLSTANDARD*N2STANDARD) // N2 standard value (79%)
//indices of values in gas lists. used by listmos.
//LISTMOS
//indices of values in gas lists.
#define MOLES 1
#define ARCHIVE 2
#define GAS_META 3
@@ -19,32 +10,35 @@
#define META_GAS_DANGER 5
#define META_GAS_ID 6
//stuff you should probably leave well alone!
//ATMOS
#define CELL_VOLUME 2500 //liters in a cell
#define BREATH_VOLUME 0.5 //liters in a normal breath
#define BREATH_PERCENTAGE (BREATH_VOLUME/CELL_VOLUME) //Amount of air to take a from a tile
#define HUMAN_NEEDED_OXYGEN (MOLES_CELLSTANDARD*BREATH_PERCENTAGE*0.16) //Amount of air needed before pass out/suffocation commences
#define NORMPIPERATE 30 //pipe-insulation rate divisor
#define HEATPIPERATE 8 //heat-exch pipe insulation
#define FLOWFRAC 0.99 //fraction of gas transfered per process
#define TANK_MELT_TEMPERATURE 1000000
#define TANK_LEAK_PRESSURE (30.*ONE_ATMOSPHERE) //Tank starts leaking
#define TANK_RUPTURE_PRESSURE (35.*ONE_ATMOSPHERE) //Tank spills all contents into atmosphere
#define TANK_FRAGMENT_PRESSURE (40.*ONE_ATMOSPHERE) //Boom 3x3 base explosion
#define TANK_FRAGMENT_SCALE (6.*ONE_ATMOSPHERE) //+1 for each SCALE kPa aboe threshold
#define MINIMUM_AIR_RATIO_TO_SUSPEND 0.1 //Ratio of air that must move to/from a tile to reset group processing
#define MINIMUM_AIR_RATIO_TO_MOVE 0.001 //Minimum ratio of air that must move to/from a tile
#define MINIMUM_AIR_TO_SUSPEND (MOLES_CELLSTANDARD*MINIMUM_AIR_RATIO_TO_SUSPEND) //Minimum amount of air that has to move before a group processing can be suspended
#define MINIMUM_MOLES_DELTA_TO_MOVE (MOLES_CELLSTANDARD*MINIMUM_AIR_RATIO_TO_MOVE) //Either this must be active
#define EXCITED_GROUP_BREAKDOWN_CYCLES 4
#define EXCITED_GROUP_DISMANTLE_CYCLES 16
#define MINIMUM_TEMPERATURE_TO_MOVE (T20C+100) //or this (or both, obviously)
#define MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND 0.012
//stuff you should probably leave well alone!
#define MOLES_CELLSTANDARD (ONE_ATMOSPHERE*CELL_VOLUME/(T20C*R_IDEAL_GAS_EQUATION)) //moles in a 2.5 m^3 cell at 101.325 Pa and 20 degC
#define M_CELL_WITH_RATIO (MOLES_CELLSTANDARD * 0.005) //compared against for superconductivity
#define O2STANDARD 0.21 //percentage of oxygen in a normal mixture of air
#define N2STANDARD 0.79 //same but for nitrogen
#define MOLES_O2STANDARD (MOLES_CELLSTANDARD*O2STANDARD) // O2 standard value (21%)
#define MOLES_N2STANDARD (MOLES_CELLSTANDARD*N2STANDARD) // N2 standard value (79%)
#define CELL_VOLUME 2500 //liters in a cell
#define BREATH_VOLUME 0.5 //liters in a normal breath
#define BREATH_PERCENTAGE (BREATH_VOLUME/CELL_VOLUME) //Amount of air to take a from a tile
#define HUMAN_NEEDED_OXYGEN (MOLES_CELLSTANDARD*BREATH_PERCENTAGE*0.16) //Amount of air needed before pass out/suffocation commences
//EXCITED GROUPS
#define EXCITED_GROUP_BREAKDOWN_CYCLES 4 //number of FULL air controller ticks before an excited group breaks down (averages gas contents across turfs)
#define EXCITED_GROUP_DISMANTLE_CYCLES 16 //number of FULL air controller ticks before an excited group dismantles and removes its turfs from active
#define MINIMUM_AIR_RATIO_TO_SUSPEND 0.1 //Ratio of air that must move to/from a tile to reset group processing
#define MINIMUM_AIR_RATIO_TO_MOVE 0.001 //Minimum ratio of air that must move to/from a tile
#define MINIMUM_AIR_TO_SUSPEND (MOLES_CELLSTANDARD*MINIMUM_AIR_RATIO_TO_SUSPEND) //Minimum amount of air that has to move before a group processing can be suspended
#define MINIMUM_MOLES_DELTA_TO_MOVE (MOLES_CELLSTANDARD*MINIMUM_AIR_RATIO_TO_MOVE) //Either this must be active
#define MINIMUM_TEMPERATURE_TO_MOVE (T20C+100) //or this (or both, obviously)
#define MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND 4 //Minimum temperature difference before group processing is suspended
#define MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER 0.5 //Minimum temperature difference before the gas temperatures are just set to be equal
#define MINIMUM_TEMPERATURE_FOR_SUPERCONDUCTION T20C+10
#define MINIMUM_TEMPERATURE_START_SUPERCONDUCTION T20C+200
//HEAT TRANSFER COEFFICIENTS
//Must be between 0 and 1. Values closer to 1 equalize temperature faster
//Should not exceed 0.4 else strange heat flow occur
#define FLOOR_HEAT_TRANSFER_COEFFICIENT 0.4
#define WALL_HEAT_TRANSFER_COEFFICIENT 0.0
#define DOOR_HEAT_TRANSFER_COEFFICIENT 0.0
@@ -52,20 +46,31 @@
#define OPEN_HEAT_TRANSFER_COEFFICIENT 0.4
#define WINDOW_HEAT_TRANSFER_COEFFICIENT 0.1 //a hack for now
#define HEAT_CAPACITY_VACUUM 7000 //a hack to help make vacuums "cold", sacrificing realism for gameplay
//Must be between 0 and 1. Values closer to 1 equalize temperature faster
//Should not exceed 0.4 else strange heat flow occur
//FIRE
#define FIRE_MINIMUM_TEMPERATURE_TO_SPREAD 150+T0C
#define FIRE_MINIMUM_TEMPERATURE_TO_EXIST 100+T0C
#define FIRE_SPREAD_RADIOSITY_SCALE 0.85
#define FIRE_GROWTH_RATE 40000 //For small fires
#define CARBON_LIFEFORM_FIRE_RESISTANCE 200+T0C //Resistance to fire damage
#define CARBON_LIFEFORM_FIRE_DAMAGE 4 //Fire damage
#define PLASMA_MINIMUM_BURN_TEMPERATURE 100+T0C
//GASES
#define MIN_TOXIC_GAS_DAMAGE 1
#define MAX_TOXIC_GAS_DAMAGE 10
#define MOLES_GAS_VISIBLE 0.5 //Moles in a standard cell after which gases are visible
#define STOP_REACTIONS 2
#define PLASMA_MINIMUM_BURN_TEMPERATURE 100+T0C
#define GAS_STIM_MINIMUM 0.002
//REACTIONS
//return values for reactions (bitflags)
#define NO_REACTION 0
#define REACTING 1
#define STOP_REACTIONS 2
//HUMANS
//Hurty numbers
#define FIRE_DAMAGE_MODIFIER 0.0215 //Higher values result in more external fire damage to the skin
#define AIR_DAMAGE_MODIFIER 2.025 //More means less damage from hot air scalding lungs, less = more damage
// Pressure limits.
#define HAZARD_HIGH_PRESSURE 550 //This determins at what pressure the ultra-high pressure red icon is displayed. (This one is set as a constant)
@@ -107,65 +112,71 @@
#define SHOES_MIN_TEMP_PROTECT 2.0 //For gloves
#define SHOES_MAX_TEMP_PROTECT 1500 //For gloves
#define PRESSURE_DAMAGE_COEFFICIENT 4 //The amount of pressure damage someone takes is equal to (pressure / HAZARD_HIGH_PRESSURE)*PRESSURE_DAMAGE_COEFFICIENT, with the maximum of MAX_PRESSURE_DAMAGE
#define MAX_HIGH_PRESSURE_DAMAGE 4
#define LOW_PRESSURE_DAMAGE 4 //The amount of damage someone takes when in a low pressure area (The pressure threshold is so low that it doesn't make sense to do any calculations, so it just applies this flat value).
#define COLD_SLOWDOWN_FACTOR 20 //Humans are slowed by the difference between bodytemp and BODYTEMP_COLD_DAMAGE_LIMIT divided by this
// Atmos pipe limits
//PIPES
//Atmos pipe limits
#define MAX_OUTPUT_PRESSURE 4500 // (kPa) What pressure pumps and powered equipment max out at.
#define MAX_TRANSFER_RATE 200 // (L/s) Maximum speed powered equipment can work at.
//Atmos machinery pipenet stuff
// used for device_type vars; used by DEVICE_TYPE_LOOP
//used for device_type vars; used by DEVICE_TYPE_LOOP
#define UNARY 1
#define BINARY 2
#define TRINARY 3
#define QUATERNARY 4
// this is the standard for loop used by all sorts of atmos machinery procs
//TODO: finally remove this bullshit
//this is the standard for loop used by all sorts of atmos machinery procs
#define DEVICE_TYPE_LOOP var/I in 1 to device_type
// defines for the various machinery lists
// NODE_I, AIR_I, PARENT_I are used within DEVICE_TYPE_LOOP
//defines for the various machinery lists
//NODE_I, AIR_I, PARENT_I are used within DEVICE_TYPE_LOOP
// nodes list - all atmos machinery
//nodes list - all atmos machinery
#define NODE1 nodes[1]
#define NODE2 nodes[2]
#define NODE3 nodes[3]
#define NODE4 nodes[4]
#define NODE_I nodes[I]
// airs list - components only
//airs list - components only
#define AIR1 airs[1]
#define AIR2 airs[2]
#define AIR3 airs[3]
#define AIR_I airs[I]
// parents list - components only
//parents list - components only
#define PARENT1 parents[1]
#define PARENT2 parents[2]
#define PARENT3 parents[3]
#define PARENT_I parents[I]
//Tanks
#define TANK_MAX_RELEASE_PRESSURE (ONE_ATMOSPHERE*3)
#define TANK_MIN_RELEASE_PRESSURE 0
#define TANK_DEFAULT_RELEASE_PRESSURE 16
//TANKS
#define TANK_MELT_TEMPERATURE 1000000 //temperature in kelvins at which a tank will start to melt
#define TANK_LEAK_PRESSURE (30.*ONE_ATMOSPHERE) //Tank starts leaking
#define TANK_RUPTURE_PRESSURE (35.*ONE_ATMOSPHERE) //Tank spills all contents into atmosphere
#define TANK_FRAGMENT_PRESSURE (40.*ONE_ATMOSPHERE) //Boom 3x3 base explosion
#define TANK_FRAGMENT_SCALE (6.*ONE_ATMOSPHERE) //+1 for each SCALE kPa aboe threshold
#define TANK_MAX_RELEASE_PRESSURE (ONE_ATMOSPHERE*3)
#define TANK_MIN_RELEASE_PRESSURE 0
#define TANK_DEFAULT_RELEASE_PRESSURE 16
//CANATMOSPASS
#define ATMOS_PASS_YES 1
#define ATMOS_PASS_NO 0
#define ATMOS_PASS_PROC -1 //ask CanAtmosPass()
#define ATMOS_PASS_DENSITY -2 //just check density
#define CANATMOSPASS(A, O) ( A.CanAtmosPass == ATMOS_PASS_PROC ? A.CanAtmosPass(O) : ( A.CanAtmosPass == ATMOS_PASS_DENSITY ? !A.density : A.CanAtmosPass ) )
//LAVALAND
#define LAVALAND_EQUIPMENT_EFFECT_PRESSURE 50 //what pressure you have to be under to increase the effect of equipment meant for lavaland
#define LAVALAND_DEFAULT_ATMOS "o2=14;n2=23;TEMP=300"
//MULTIPIPES
//IF YOU EVER CHANGE THESE CHANGE SPRITES TO MATCH.
#define PIPING_LAYER_MIN 1
#define PIPING_LAYER_MAX 3
@@ -179,6 +190,7 @@
#define PIPING_DEFAULT_LAYER_ONLY 4 //can only exist at PIPING_LAYER_DEFAULT
#define PIPING_CARDINAL_AUTONORMALIZE 8 //north/south east/west doesn't matter, auto normalize on build.
//HELPERS
#define THERMAL_ENERGY(gas) (gas.temperature * gas.heat_capacity())
#define ADD_GAS(gas_id, out_list)\
+10 -5
View File
@@ -1,9 +1,9 @@
//component id defines
#define BELLIGERENT_EYE "belligerent_eye"
#define VANGUARD_COGWHEEL "vanguard_cogwheel"
#define GEIS_CAPACITOR "geis_capacitor"
//component id defines; sometimes these may not make sense in regards to their use in scripture but important ones are bright
#define BELLIGERENT_EYE "belligerent_eye" //Use this for offensive and damaging scripture!
#define VANGUARD_COGWHEEL "vanguard_cogwheel" //Use this for defensive and healing scripture!
#define GEIS_CAPACITOR "geis_capacitor" //Use this for niche scripture!
#define REPLICANT_ALLOY "replicant_alloy"
#define HIEROPHANT_ANSIBLE "hierophant_ansible"
#define HIEROPHANT_ANSIBLE "hierophant_ansible" //Use this for construction-related scripture!
GLOBAL_VAR_INIT(clockwork_construction_value, 0) //The total value of all structures built by the clockwork cult
GLOBAL_VAR_INIT(clockwork_caches, 0) //How many clockwork caches exist in the world (not each individual)
@@ -69,6 +69,9 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us
//Objective text define
#define CLOCKCULT_OBJECTIVE "Construct the Ark of the Clockwork Justicar and free Ratvar."
//Eminence defines
#define SUPERHEATED_CLOCKWORK_WALL_LIMIT 20 //How many walls can be superheated at once
//misc clockcult stuff
#define SIGIL_ACCESS_RANGE 2 //range at which transmission sigils can access power
@@ -86,3 +89,5 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us
#define MARAUDER_SCRIPTURE_SCALING_TIME 50 //The amount of extra deciseconds tacked on to the marauder scripture recital time per recent marauder
#define MARAUDER_SCRIPTURE_SCALING_MAX 300 //The maximum extra time applied to the marauder scripture
#define ARK_SCREAM_COOLDOWN 600 //This much time has to pass between instances of the Ark taking damage before it will "scream" again
+4
View File
@@ -77,6 +77,10 @@
#define COMSIG_MACHINE_PROCESS "machine_process" //from machinery subsystem fire(): ()
#define COMSIG_MACHINE_PROCESS_ATMOS "machine_process_atmos" //from air subsystem process_atmos_machinery(): ()
// /mob/living/carbon/human signals
#define COMSIG_HUMAN_MELEE_UNARMED_ATTACK "human_melee_unarmed_attack" //from mob/living/carbon/human/UnarmedAttack(): (atom/target)
#define COMSIG_HUMAN_MELEE_UNARMED_ATTACKBY "human_melee_unarmed_attackby" //from mob/living/carbon/human/UnarmedAttack(): (mob/living/carbon/human/attacker)
#define CALTROP_BYPASS_SHOES 1
#define CALTROP_IGNORE_WALKERS 2
+5
View File
@@ -23,6 +23,11 @@
#define WINDOW_IN_FRAME 1
#define WINDOW_SCREWED_TO_FRAME 2
//airlock assembly construction states
#define AIRLOCK_ASSEMBLY_NEEDS_WIRES 0
#define AIRLOCK_ASSEMBLY_NEEDS_ELECTRONICS 1
#define AIRLOCK_ASSEMBLY_NEEDS_SCREWDRIVER 2
//plastic flaps construction states
#define PLASTIC_FLAPS_NORMAL 0
#define PLASTIC_FLAPS_DETACHED 1
+2
View File
@@ -144,6 +144,8 @@
#define iscameramob(A) (istype(A, /mob/camera))
#define iseminence(A) (istype(A, /mob/camera/eminence))
//Objects
#define isobj(A) istype(A, /obj) //override the byond proc because it returns true on children of /atom/movable that aren't objs
+3
View File
@@ -491,6 +491,9 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
#define RIDING_OFFSET_ALL "ALL"
//text files
#define BRAIN_DAMAGE_FILE "brain_damage_lines.json"
//Fullscreen overlay resolution in tiles.
#define FULLSCREEN_OVERLAY_RESOLUTION_X 15
#define FULLSCREEN_OVERLAY_RESOLUTION_Y 15
+11
View File
@@ -51,6 +51,17 @@
#define DEVIL_BODYPART "devil"
/*see __DEFINES/inventory.dm for bodypart bitflag defines*/
//Brain Damage defines
#define BRAIN_DAMAGE_MILD 50
#define BRAIN_DAMAGE_SEVERE 120
#define BRAIN_DAMAGE_DEATH 200
#define BRAIN_TRAUMA_MILD /datum/brain_trauma/mild
#define BRAIN_TRAUMA_SEVERE /datum/brain_trauma/severe
#define BRAIN_TRAUMA_SPECIAL /datum/brain_trauma/special
#define BRAIN_DAMAGE_INTEGRITY_MULTIPLIER 0.5
//Health hud screws for carbon mobs
#define SCREWYHUD_NONE 0
#define SCREWYHUD_CRIT 1
+5 -1
View File
@@ -70,4 +70,8 @@
//Rotation params
#define ROTATE_DIR 1
#define ROTATE_SMOOTH 2
#define ROTATE_OFFSET 4
#define ROTATE_OFFSET 4
#define SHUTTLE_DOCKER_LANDING_CLEAR 1
#define SHUTTLE_DOCKER_BLOCKED_BY_HIDDEN_PORT 2
#define SHUTTLE_DOCKER_BLOCKED 3
+33 -31
View File
@@ -1,31 +1,33 @@
/*
Used with the various stat variables (mob, machines)
*/
//mob/var/stat things
#define CONSCIOUS 0
#define SOFT_CRIT 1
#define UNCONSCIOUS 2
#define DEAD 3
//mob disabilities stat
#define BLIND 1
#define MUTE 2
#define DEAF 4
#define NEARSIGHT 8
#define FAT 32
#define HUSK 64
#define NOCLONE 128
#define CLUMSY 256
// bitflags for machine stat variable
#define BROKEN 1
#define NOPOWER 2
#define MAINT 4 // under maintaince
#define EMPED 8 // temporary broken by EMP pulse
//ai power requirement defines
#define POWER_REQ_NONE 0
#define POWER_REQ_ALL 1
#define POWER_REQ_CLOCKCULT 2
/*
Used with the various stat variables (mob, machines)
*/
//mob/var/stat things
#define CONSCIOUS 0
#define SOFT_CRIT 1
#define UNCONSCIOUS 2
#define DEAD 3
//mob disabilities stat
#define BLIND 1
#define MUTE 2
#define DEAF 4
#define NEARSIGHT 8
#define FAT 32
#define HUSK 64
#define NOCLONE 128
#define CLUMSY 256
#define DUMB 512
#define MONKEYLIKE 1024 //sets IsAdvancedToolUser to FALSE
// bitflags for machine stat variable
#define BROKEN 1
#define NOPOWER 2
#define MAINT 4 // under maintaince
#define EMPED 8 // temporary broken by EMP pulse
//ai power requirement defines
#define POWER_REQ_NONE 0
#define POWER_REQ_ALL 1
#define POWER_REQ_CLOCKCULT 2
+16 -16
View File
@@ -9,6 +9,16 @@
* Misc
*/
#define LAZYINITLIST(L) if (!L) L = list()
#define UNSETEMPTY(L) if (L && !L.len) L = null
#define LAZYREMOVE(L, I) if(L) { L -= I; if(!L.len) { L = null; } }
#define LAZYADD(L, I) if(!L) { L = list(); } L += I;
#define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= L.len ? L[I] : null) : L[I]) : null)
#define LAZYSET(L, K, V) if(!L) { L = list(); } L[K] = V;
#define LAZYLEN(L) length(L)
#define LAZYCLEARLIST(L) if(L) L.Cut()
#define SANITIZE_LIST(L) ( islist(L) ? L : list() )
//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 = "" )
var/total = input.len
@@ -32,7 +42,7 @@
//Returns list element or null. Should prevent "index out of bounds" error.
/proc/listgetindex(list/L, index)
if(istype(L))
if(LAZYLEN(L))
if(isnum(index) && IsInteger(index))
if(IsInRange(index,1,L.len))
return L[index]
@@ -42,7 +52,7 @@
//Return either pick(list) or null if list is not of type /list or is empty
/proc/safepick(list/L)
if(istype(L) && L.len)
if(LAZYLEN(L))
return pick(L)
//Checks if the list is empty
@@ -53,7 +63,7 @@
//Checks for specific types in a list
/proc/is_type_in_list(atom/A, list/L)
if(!L || !L.len || !A)
if(!LAZYLEN(L) || !A)
return FALSE
for(var/type in L)
if(istype(A, type))
@@ -62,7 +72,7 @@
//Checks for specific types in specifically structured (Assoc "type" = TRUE) lists ('typecaches')
/proc/is_type_in_typecache(atom/A, list/L)
if(!L || !L.len || !A)
if(!LAZYLEN(L) || !A)
return FALSE
if(ispath(A))
@@ -72,7 +82,7 @@
//Checks for a string in a list
/proc/is_string_in_list(string, list/L)
if(!L || !L.len || !string)
if(!LAZYLEN(L) || !string)
return
for(var/V in L)
if(string == V)
@@ -81,7 +91,7 @@
//Removes a string from a list
/proc/remove_strings_from_list(string, list/L)
if(!L || !L.len || !string)
if(!LAZYLEN(L) || !string)
return
for(var/V in L)
if(V == string)
@@ -486,16 +496,6 @@
//Picks from the list, with some safeties, and returns the "default" arg if it fails
#define DEFAULTPICK(L, default) ((islist(L) && length(L)) ? pick(L) : default)
#define LAZYINITLIST(L) if (!L) L = list()
#define UNSETEMPTY(L) if (L && !L.len) L = null
#define LAZYREMOVE(L, I) if(L) { L -= I; if(!L.len) { L = null; } }
#define LAZYADD(L, I) if(!L) { L = list(); } L += I;
#define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= L.len ? L[I] : null) : L[I]) : null)
#define LAZYSET(L, K, V) if(!L) { L = list(); } L[K] = V;
#define LAZYLEN(L) length(L)
#define LAZYCLEARLIST(L) if(L) L.Cut()
#define SANITIZE_LIST(L) ( islist(L) ? L : list() )
/* Definining a counter as a series of key -> numeric value entries
* All these procs modify in place.
-19
View File
@@ -326,25 +326,6 @@
return M
return null
// Will return a list of active candidates. It increases the buffer 5 times until it finds a candidate which is active within the buffer.
/proc/get_candidates(be_special_type, afk_bracket = CONFIG_GET(number/inactivity_period), jobbanType)
var/list/candidates = list()
// Keep looping until we find a non-afk candidate within the time bracket (we limit the bracket to 10 minutes (6000))
var/afk_period = CONFIG_GET(number/afk_period)
while(!candidates.len && afk_bracket < afk_period)
for(var/mob/dead/observer/G in GLOB.player_list)
if(G.client != null)
if(!(G.mind && G.mind.current && G.mind.current.stat != DEAD))
if(!G.client.is_afk(afk_bracket) && (be_special_type in G.client.prefs.be_special))
if (jobbanType)
if(!(jobban_isbanned(G, jobbanType) || jobban_isbanned(G, "Syndicate")))
candidates += G.client
else
candidates += G.client
afk_bracket += 600 // Add a minute to the bracket, for every attempt
return candidates
/proc/considered_alive(datum/mind/M, enforce_human = TRUE)
if(M && M.current)
if(enforce_human)
+1 -1
View File
@@ -198,7 +198,7 @@ GLOBAL_LIST_INIT(sqrtTable, list(1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4,
var/list/screen_loc_Y = splittext(screen_loc_params[2],":")
var/x = (text2num(screen_loc_X[1]) * 32 + text2num(screen_loc_X[2]) - 32)
var/y = (text2num(screen_loc_Y[1]) * 32 + text2num(screen_loc_Y[2]) - 32)
var/list/screenview = getviewsize(client)
var/list/screenview = getviewsize(client.view)
var/screenviewX = screenview[1] * world.icon_size
var/screenviewY = screenview[2] * world.icon_size
var/ox = round(screenviewX/2) - client.pixel_x //"origin" x
+1 -1
View File
@@ -359,7 +359,7 @@ Proc for attack log creation, because really why not
if(!user)
return 0
var/atom/Tloc = null
if(target)
if(target && !isturf(target))
Tloc = target.loc
var/atom/Uloc = user.loc
+17 -24
View File
@@ -14,30 +14,23 @@
//breaks when hittin invalid characters thereafter
/proc/hex2num(hex)
. = 0
if(istext(hex))
var/negative = 0
var/len = length(hex)
for(var/i=1, i<=len, i++)
var/num = text2ascii(hex,i)
switch(num)
if(48 to 57)
num -= 48 //0-9
if(97 to 102)
num -= 87 //a-f
if(65 to 70)
num -= 55 //A-F
if(45)
negative = 1//-
else
if(num)
break
else
continue
. *= 16
. += num
if(negative)
. *= -1
return .
var/place = 1
for(var/i in length(hex) to 1 step -1)
var/num = text2ascii(hex, i)
switch(num)
if(48 to 57)
num -= 48 //0-9
if(97 to 102)
num -= 87 //a-f
if(65 to 70)
num -= 55 //A-F
if(45)
return . * -1 // -
else
CRASH("Malformed hex number")
. += num * place
place *= 16
//Returns the hex value of a decimal number
//len == length of returned string
+7
View File
@@ -1507,3 +1507,10 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
else
return "\[[url_encode(thing.tag)]\]"
return "\ref[input]"
//Returns a list of all servants of Ratvar and observers.
/proc/servants_and_ghosts()
. = list()
for(var/V in GLOB.player_list)
if(is_servant_of_ratvar(V) || isobserver(V))
. += V
-1
View File
@@ -35,4 +35,3 @@ GLOBAL_PROTECT(MAX_EX_FLASH_RANGE)
GLOBAL_VAR_INIT(MAX_EX_FLAME_RANGE, 14)
GLOBAL_PROTECT(MAX_EX_FLAME_RANGE)
GLOBAL_VAR_INIT(DYN_EX_SCALE, 0.5)
+1
View File
@@ -4,6 +4,7 @@ GLOBAL_LIST_EMPTY(airlocks) //list of all airlocks
GLOBAL_LIST_EMPTY(mechas_list) //list of all mechs. Used by hostile mobs target tracking.
GLOBAL_LIST_EMPTY(shuttle_caller_list) //list of all communication consoles and AIs, for automatic shuttle calls when there are none.
GLOBAL_LIST_EMPTY(machines) //NOTE: this is a list of ALL machines now. The processing machines list is SSmachine.processing !
GLOBAL_LIST_EMPTY(navigation_computers) //list of all /obj/machinery/computer/camera_advanced/shuttle_docker
GLOBAL_LIST_EMPTY(syndicate_shuttle_boards) //important to keep track of for managing nukeops war declarations.
GLOBAL_LIST_EMPTY(navbeacons) //list of all bot nagivation beacons, used for patrolling.
GLOBAL_LIST_EMPTY(teleportbeacons) //list of all tracking beacons used by teleporters
+27 -17
View File
@@ -285,7 +285,7 @@
if(!stat && mind && iscarbon(A) && A != src)
var/datum/antagonist/changeling/C = mind.has_antag_datum(/datum/antagonist/changeling)
if(C && C.chosen_sting)
C.chosen_sting.try_to_sting(src,A)
C.chosen_sting.try_to_sting(src,A)
next_click = world.time + 5
return
swap_hand()
@@ -349,7 +349,7 @@
if(!stat && mind && iscarbon(A) && A != src)
var/datum/antagonist/changeling/C = mind.has_antag_datum(/datum/antagonist/changeling)
if(C && C.chosen_sting)
C.chosen_sting.try_to_sting(src,A)
C.chosen_sting.try_to_sting(src,A)
next_click = world.time + 5
return
..()
@@ -433,28 +433,38 @@
else
setDir(WEST)
//debug
/obj/screen/proc/scale_to(x1,y1)
if(!y1)
y1 = x1
var/matrix/M = new
M.Scale(x1,y1)
transform = M
/obj/screen/click_catcher
icon = 'icons/mob/screen_gen.dmi'
icon_state = "flash"
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.
/obj/screen/click_catcher/proc/UpdateGreed(view_size_x = 15, view_size_y = 15)
var/icon/newicon = icon('icons/mob/screen_gen.dmi', "flash")
if(view_size_x > 32 || view_size_y > 32)
newicon.Scale(16 * world.icon_size,16 * world.icon_size)
icon = newicon
var/tx = ((view_size_x - 1)*0.5)/16
var/ty = ((view_size_y - 1)*0.5)/16
var/matrix/M = new
M.Scale(tx, ty)
transform = M
screen_loc = "CENTER-16,CENTER-16"
else
screen_loc = "CENTER-[(view_size_x-1)*0.5],CENTER-[(view_size_y-1)*0.5]"
newicon.Scale(view_size_x * world.icon_size,view_size_y * world.icon_size)
icon = newicon
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
/obj/screen/click_catcher/Click(location, control, params)
var/list/modifiers = params2list(params)
+16
View File
@@ -8,15 +8,22 @@
var/button_icon_state
var/appearance_cache
var/id
/obj/screen/movable/action_button/Click(location,control,params)
var/list/modifiers = params2list(params)
if(modifiers["shift"])
if(locked)
to_chat(usr, "<span class='warning'>Action button \"[name]\" is locked, unlock it first.</span>")
return TRUE
moved = 0
usr.update_action_buttons() //redraw buttons that are no longer considered "moved"
return TRUE
if(modifiers["ctrl"])
locked = !locked
to_chat(usr, "<span class='notice'>Action button \"[name]\" [locked ? "" : "un"]locked.</span>")
if(id && usr.client) //try to (un)remember position
usr.client.prefs.action_buttons_screen_locs["[name]_[id]"] = locked ? moved : null
return TRUE
if(usr.next_click > world.time)
return
@@ -38,21 +45,30 @@
/obj/screen/movable/action_button/hide_toggle/Click(location,control,params)
var/list/modifiers = params2list(params)
if(modifiers["shift"])
if(locked)
to_chat(usr, "<span class='warning'>Action button \"[name]\" is locked, unlock it first.</span>")
return TRUE
moved = FALSE
usr.update_action_buttons(TRUE)
return TRUE
if(modifiers["ctrl"])
locked = !locked
to_chat(usr, "<span class='notice'>Action button \"[name]\" [locked ? "" : "un"]locked.</span>")
if(id && usr.client) //try to (un)remember position
usr.client.prefs.action_buttons_screen_locs["[name]_[id]"] = locked ? moved : null
return TRUE
if(modifiers["alt"])
for(var/V in usr.actions)
var/datum/action/A = V
var/obj/screen/movable/action_button/B = A.button
B.moved = FALSE
if(B.id && usr.client)
usr.client.prefs.action_buttons_screen_locs["[B.name]_[B.id]"] = null
B.locked = usr.client.prefs.buttons_locked
locked = usr.client.prefs.buttons_locked
moved = FALSE
if(id && usr.client)
usr.client.prefs.action_buttons_screen_locs["[name]_[id]"] = null
usr.update_action_buttons(TRUE)
to_chat(usr, "<span class='notice'>Action button positions have been reset.</span>")
return TRUE
+5 -13
View File
@@ -388,23 +388,15 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
desc = "<font size=3><b>CHETR<br>NYY<br>HAGEHUGF-NAQ-UBABE<br>RATVAR.</b></font>"
else
var/servants = 0
var/validservants = 0
var/list/textlist
for(var/mob/living/L in GLOB.alive_mob_list)
if(is_servant_of_ratvar(L))
servants++
if(ishuman(L) || issilicon(L))
validservants++
if(servants > 1)
if(validservants > 1)
textlist = list("<b>[servants]</b> Servants, <b>[validservants]</b> of which count towards scripture.<br>")
else
textlist = list("<b>[servants]</b> Servants, [validservants ? "<b>[validservants]</b> of which counts":"none of which count"] towards scripture.<br>")
else
textlist = list("<b>[servants]</b> Servant, who [validservants ? "counts":"does not count"] towards scripture.<br>")
for(var/i in SSticker.scripture_states)
if(i != SCRIPTURE_DRIVER) //ignore the always-unlocked stuff
textlist += "[i] Scripture: <b>[SSticker.scripture_states[i] ? "UNLOCKED":"LOCKED"]</b><br>"
textlist = list("[SSticker.mode.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>"
for(var/i in SSticker.scripture_states)
if(i != SCRIPTURE_DRIVER) //ignore the always-unlocked stuff
textlist += "[i] Scripture: <b>[SSticker.scripture_states[i] ? "UNLOCKED":"LOCKED"]</b><br>"
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
if(G)
var/time_info = G.get_arrival_time(FALSE)
+2 -2
View File
@@ -135,6 +135,6 @@
var/attack_message = "[src] has been [message_verb][message_hit_area] with [I]."
if(user in viewers(src, null))
attack_message = "[user] has [message_verb] [src][message_hit_area] with [I]!"
visible_message("<span class='danger'>[attack_message]</span>", \
visible_message("<span class='danger'>[attack_message]</span>",\
"<span class='userdanger'>[attack_message]</span>", null, COMBAT_MESSAGE_RANGE)
return 1
return 1
+49 -28
View File
@@ -11,7 +11,7 @@
attack_verb = list("poked", "jabbed", "hit")
light_color = "#37FFF7"
var/light_brightness = 3
actions_types = list(/datum/action/item_action/pick_color)
actions_types = list()
/obj/item/toy/sword/cx/attack_self(mob/user)
active = !( active )
@@ -57,18 +57,21 @@
var/mob/M = loc
M.update_inv_hands()
/obj/item/toy/sword/cx/ui_action_click(mob/user, var/datum/action/A)
if(istype(A, /datum/action/item_action/pick_color))
if(alert("Are you sure you want to recolor your blade?", "Confirm Repaint", "Yes", "No") == "Yes")
var/energy_color_input = input(usr,"Choose Energy Color") as color|null
if(energy_color_input)
light_color = sanitize_hexcolor(energy_color_input, desired_format=6, include_crunch=1)
update_icon()
update_light()
A.UpdateButtonIcon()
/obj/item/toy/sword/cx/AltClick(mob/living/user)
if(user.incapacitated() || !istype(user))
to_chat(user, "<span class='warning'>You can't do that right now!</span>")
return
if(!in_range(src, user))
return
if(user.incapacitated() || !istype(user) || !in_range(src, user))
return
else
..()
if(alert("Are you sure you want to recolor your blade?", "Confirm Repaint", "Yes", "No") == "Yes")
var/energy_color_input = input(usr,"Choose Energy Color") as color|null
if(energy_color_input)
light_color = sanitize_hexcolor(energy_color_input, desired_format=6, include_crunch=1)
update_icon()
update_light()
/obj/item/toy/sword/cx/worn_overlays(isinhands, icon_file)
. = ..()
@@ -79,7 +82,21 @@
. += blade_inhand
/obj/item/toy/sword/cx/attackby(obj/item/W, mob/living/user, params)
return //NO MORE MAKING DUAL ESWORDS
if(istype(W, /obj/item/toy/sword/cx))
if((W.flags_1 & NODROP_1) || (flags_1 & NODROP_1))
to_chat(user, "<span class='warning'>\the [flags_1 & NODROP_1 ? src : W] is stuck to your hand, you can't attach it to \the [flags_1 & NODROP_1 ? W : src]!</span>")
return
else
to_chat(user, "<span class='notice'>You combine the two plastic swords, making a single supermassive toy! You're fake-cool.</span>")
new /obj/item/twohanded/hypereutactic/toy(user.loc)
qdel(W)
qdel(src)
else
return ..()
/obj/item/toy/sword/cx/examine(mob/user)
..()
to_chat(user, "<span class='notice'>Alt-click to recolor it.</span>")
/*///autolathe memes/// I really need to stop doing this and find a proper way of adding in my toys
@@ -124,7 +141,7 @@
origin_tech = "combat=3;magnets=4"
block_chance = 60
light_color = "#37FFF7"
actions_types = list(/datum/action/item_action/pick_color)
actions_types = list()
/obj/item/melee/transforming/energy/sword/cx/transform_weapon(mob/living/user, supress_message_text)
active = !active //I'd use a ..() here but it'd inherit from the regular esword's proc instead, so SPAGHETTI CODE
@@ -152,9 +169,6 @@
update_icon()
transform_messages(user, supress_message_text)
add_fingerprint(user)
for(var/X in actions)
var/datum/action/A = X
A.UpdateButtonIcon()
return TRUE
/obj/item/melee/transforming/energy/sword/cx/transform_messages(mob/living/user, supress_message_text)
@@ -181,18 +195,25 @@
var/mob/M = loc
M.update_inv_hands()
/obj/item/melee/transforming/energy/sword/cx/ui_action_click(mob/user, var/datum/action/A)
if(istype(A, /datum/action/item_action/pick_color))
if(alert("Are you sure you want to recolor your blade?", "Confirm Repaint", "Yes", "No") == "Yes")
var/energy_color_input = input(usr,"Choose Energy Color") as color|null
if(energy_color_input)
light_color = sanitize_hexcolor(energy_color_input, desired_format=6, include_crunch=1)
update_icon()
update_light()
A.UpdateButtonIcon()
/obj/item/melee/transforming/energy/sword/cx/AltClick(mob/living/user)
if(user.incapacitated() || !istype(user))
to_chat(user, "<span class='warning'>You can't do that right now!</span>")
return
if(!in_range(src, user))
return
if(user.incapacitated() || !istype(user) || !in_range(src, user))
return
else
..()
if(alert("Are you sure you want to recolor your blade?", "Confirm Repaint", "Yes", "No") == "Yes")
var/energy_color_input = input(usr,"Choose Energy Color") as color|null
if(energy_color_input)
light_color = sanitize_hexcolor(energy_color_input, desired_format=6, include_crunch=1)
update_icon()
update_light()
/obj/item/melee/transforming/energy/sword/cx/examine(mob/user)
..()
to_chat(user, "<span class='notice'>Alt-click to recolor it.</span>")
/obj/item/melee/transforming/energy/sword/cx/worn_overlays(isinhands, icon_file)
. = ..()
+53 -39
View File
@@ -16,17 +16,20 @@
/obj/item/clothing/neck/cloak/inferno
name = "Kiara's Cloak"
desc = "The design on this seems a little too familiar."
icon = 'icons/obj/clothing/cloaks.dmi'
icon_state = "infcloak"
item_state = "infcloak"
icon = 'icons/obj/custom.dmi'
icon_state = "infcloak-i"
icon_override = 'icons/obj/custom.dmi'
item_state = "infcloak-w"
w_class = WEIGHT_CLASS_SMALL
body_parts_covered = CHEST|GROIN|LEGS|ARMS
/obj/item/clothing/neck/petcollar/inferno
name = "Kiara's Collar"
desc = "A soft black collar that seems to stretch to fit whoever wears it."
icon_state = "infcollar"
item_state = "infcollar"
icon = 'icons/obj/custom.dmi'
icon_state = "infcollar-i"
icon_override = 'icons/obj/custom.dmi'
item_state = "infcollar-w"
item_color = null
tagname = null
@@ -43,7 +46,7 @@
/obj/item/lighter/gold
name = "\improper Engraved Zippo"
desc = "A shiny and relatively expensive zippo lighter. There's a small etched in verse on the bottom that reads, 'No Gods, No Masters, Only Man.'"
icon = 'icons/obj/cigarettes.dmi'
icon = 'icons/obj/custom.dmi'
icon_state = "gold_zippo"
item_state = "gold_zippo"
w_class = WEIGHT_CLASS_TINY
@@ -58,16 +61,20 @@
/obj/item/clothing/neck/scarf/zomb //Default white color, same functionality as beanies.
name = "A special scarf"
icon_state = "zombscarf"
icon = 'icons/obj/custom.dmi'
icon_state = "zombscarf-i"
desc = "A fashionable collar"
item_color = "zombscarf"
icon_override = 'icons/obj/custom.dmi'
item_color = "zombscarf-w"
dog_fashion = /datum/dog_fashion/head
/obj/item/clothing/suit/toggle/labcoat/mad/red
name = "\improper The Mad's labcoat"
desc = "An oddly special looking coat."
icon_state = "labred"
item_state = "labred"
icon = 'icons/obj/custom.dmi'
icon_state = "labred-i"
icon_override = 'icons/obj/custom.dmi'
item_state = "labred-w"
/*PLACEHOLDER*/
@@ -86,17 +93,17 @@
/obj/item/clothing/neck/cloak/carrot
name = "carrot cloak"
desc = "A cloak in the shape and color of a carrot!"
icon = 'icons/obj/clothing/cloaks.dmi'
icon_override = 'icons/mob/citadel/suit.dmi'
icon_state = "carrotcloak"
item_state = "carrotcloak"
icon = 'icons/obj/custom.dmi'
icon_override = 'icons/obj/custom.dmi'
icon_state = "carrotcloak-i"
item_state = "carrotcloak-w"
w_class = WEIGHT_CLASS_SMALL
body_parts_covered = CHEST|GROIN|LEGS|ARMS
/obj/item/toy/plush/tree
name = "christmass tree plushie"
desc = "A festive plush that squeeks when you squeeze it!"
icon = 'icons/obj/plushes.dmi'
icon = 'icons/obj/custom.dmi'
icon_state = "pine_c"
item_state = "pine_c"
w_class = WEIGHT_CLASS_SMALL
@@ -107,10 +114,10 @@
/obj/item/clothing/neck/cloak/festive
name = "Celebratory Cloak of Morozko"
desc = " It probably will protect from snow, charcoal or elves."
icon = 'icons/obj/clothing/cloaks.dmi'
icon_override = 'icons/mob/citadel/suit.dmi'
icon_state = "festivecloak"
item_state = "festiveloak"
icon = 'icons/obj/custom.dmi'
icon_state = "festive-i"
item_state = "festive-w"
icon_override = 'icons/obj/custom.dmi'
w_class = WEIGHT_CLASS_SMALL
body_parts_covered = CHEST|GROIN|LEGS|ARMS
@@ -119,9 +126,10 @@
/obj/item/clothing/mask/luchador/zigfie
name = "Alboroto Rosa mask"
icon = 'icons/mob/mask.dmi'
icon_state = "lucharzigfie"
item_state = "lucharzigfie"
icon = 'icons/obj/custom.dmi'
icon_state = "lucharzigfie-i"
icon_override = 'icons/obj/custom.dmi'
item_state = "lucharzigfie-w"
/*PLACEHOLDER*/
@@ -159,8 +167,10 @@
/obj/item/clothing/suit/trenchcoat/green
name = "Reece's Great Coat"
desc = "You would swear this was in your nightmares after eating too many veggies."
icon_state = "hos-g"
item_state = "hos-g"
icon = 'icons/obj/custom.dmi'
icon_state = "hos-g-i"
icon_override = 'icons/obj/custom.dmi'
item_state = "hos-g-w"
body_parts_covered = CHEST|GROIN|ARMS|LEGS
@@ -170,14 +180,15 @@
desc = "Every good russian spaceman knows it's a good idea to bring along a couple of pints of whiskey wherever they go."
icon = 'icons/obj/custom.dmi'
icon_state = "russianflask"
item_state = "russianflask"
volume = 60
/obj/item/clothing/mask/gas/stalker
name = "S.T.A.L.K.E.R. mask"
desc = "Smells like reactor four."
item_state = "stalker"
icon_state = "stalker"
icon = 'icons/obj/custom.dmi'
item_state = "stalker-w"
icon_override = 'icons/obj/custom.dmi'
icon_state = "stalker-i"
/*Sylas*/
@@ -185,8 +196,9 @@
name = "collar"
desc = "It's a collar..."
icon = 'icons/obj/custom.dmi'
icon_state = "petcollar-stripe"
item_color = "petcollar-stripe"
icon_state = "petcollar-stripe-i"
icon_override = 'icons/obj/custom.dmi'
item_state = "petcollar-stripe-w"
tagname = null
@@ -194,17 +206,21 @@
/obj/item/clothing/under/singery/custom
name = "bluish performer's outfit"
desc = "Just looking at this makes you want to sing."
icon_state = "ssing"
item_state = "ssing"
item_color = "ssing"
icon = 'icons/obj/custom.dmi'
icon_state = "singer-i"
icon_override = 'icons/obj/custom.dmi'
item_state = "singer-w"
item_color = "singer-i"
fitted = NO_FEMALE_UNIFORM
alternate_worn_layer = ABOVE_SHOES_LAYER
can_adjust = 0
/obj/item/clothing/shoes/sneakers/pink
icon_state = "pink"
item_state = "pink"
icon = 'icons/obj/custom.dmi'
icon_state = "pink-i"
icon_override = 'icons/obj/custom.dmi'
item_state = "pink-w"
/*Fractious*/
@@ -212,10 +228,8 @@
/obj/item/clothing/suit/vermillion
name = "vermillion clothing"
desc = "Some clothing."
icon_state = "vermillion-w"
item_state = "vermillion-i"
icon_state = "vermillion-i"
item_state = "vermillion-w"
body_parts_covered = CHEST|GROIN|LEGS|ARMS|HANDS
icon = 'icons/obj/custom.dmi'
icon_override = 'icons/obj/custom.dmi'
@@ -168,7 +168,10 @@ GLOBAL_PROTECT(config_dir)
mode_names[M.config_tag] = M.name
probabilities[M.config_tag] = M.probability
mode_reports[M.config_tag] = M.generate_report()
mode_false_report_weight[M.config_tag] = M.false_report_weight
if(M.probability)
mode_false_report_weight[M.config_tag] = M.false_report_weight
else
mode_false_report_weight[M.config_tag] = 1
if(M.votable)
votable_modes += M.config_tag
qdel(M)
@@ -208,9 +208,9 @@ CONFIG_DEF(string/panic_server_name)
/datum/config_entry/string/panic_server_name/ValidateAndSet(str_val)
return str_val != "\[Put the name here\]" && ..()
CONFIG_DEF(string/panic_address) //Reconnect a player this linked server if this server isn't accepting new players
CONFIG_DEF(string/panic_server_address) //Reconnect a player this linked server if this server isn't accepting new players
/datum/config_entry/string/panic_address/ValidateAndSet(str_val)
/datum/config_entry/string/panic_server_address/ValidateAndSet(str_val)
return str_val != "byond://address:port" && ..()
CONFIG_DEF(string/invoke_youtubedl)
@@ -377,7 +377,7 @@ CONFIG_TWEAK(number/mc_tick_rate/ValidateAndSet(str_val))
CONFIG_DEF(flag/resume_after_initializations)
CONFIG_TWEAK(flag/ValidateAndSet(str_val))
CONFIG_TWEAK(flag/resume_after_initializations/ValidateAndSet(str_val))
. = ..()
if(. && Master.current_runlevel)
world.sleep_offline = !value
@@ -385,3 +385,6 @@ CONFIG_TWEAK(flag/ValidateAndSet(str_val))
CONFIG_DEF(number/rounds_until_hard_restart)
value = -1
min_val = 0
CONFIG_DEF(string/default_view)
value = "15x15"
@@ -263,4 +263,4 @@ CONFIG_DEF(number/emergency_shuttle_autocall_threshold)
max_val = 1
integer = FALSE
CONFIG_DEF(flag/ic_printing)
CONFIG_DEF(flag/ic_printing)
+10 -2
View File
@@ -45,7 +45,14 @@ SUBSYSTEM_DEF(blackbox)
return ..()
/datum/controller/subsystem/blackbox/vv_edit_var(var_name, var_value)
return FALSE
switch(var_name)
if("feedback")
return FALSE
if("sealed")
if(var_value)
return Seal()
return FALSE
return ..()
/datum/controller/subsystem/blackbox/Shutdown()
sealed = FALSE
@@ -76,11 +83,12 @@ SUBSYSTEM_DEF(blackbox)
/datum/controller/subsystem/blackbox/proc/Seal()
if(sealed)
return
return FALSE
if(IsAdminAdvancedProcCall())
message_admins("[key_name_admin(usr)] sealed the blackbox!")
log_game("Blackbox sealed[IsAdminAdvancedProcCall() ? " by [key_name(usr)]" : ""].")
sealed = TRUE
return TRUE
/datum/controller/subsystem/blackbox/proc/log_research(tech, level)
if(!(tech in research_levels) || research_levels[tech] < level)
+40 -1
View File
@@ -44,6 +44,9 @@ SUBSYSTEM_DEF(shuttle)
var/list/requestlist = list()
var/list/orderhistory = list()
var/list/hidden_shuttle_turfs = list() //all turfs hidden from navigation computers associated with a list containing the image hiding them and the type of the turf they are pretending to be
var/list/hidden_shuttle_turf_images = list() //only the images from the above list
var/datum/round_event/shuttle_loan/shuttle_loan
var/shuttle_purchased = FALSE //If the station has purchased a replacement escape shuttle this round
@@ -648,4 +651,40 @@ SUBSYSTEM_DEF(shuttle)
var/list/xs = overlap[1]
var/list/ys = overlap[2]
if(xs.len && ys.len)
.[port] = overlap
.[port] = overlap
/datum/controller/subsystem/shuttle/proc/update_hidden_docking_ports(list/remove_turfs, list/add_turfs)
var/list/remove_images = list()
var/list/add_images = list()
if(remove_turfs)
for(var/T in remove_turfs)
var/list/L = hidden_shuttle_turfs[T]
if(L)
remove_images += L[1]
hidden_shuttle_turfs -= remove_turfs
if(add_turfs)
for(var/V in add_turfs)
var/turf/T = V
var/image/I
if(remove_images.len)
//we can just reuse any images we are about to delete instead of making new ones
I = remove_images[1]
remove_images.Cut(1, 2)
I.loc = T
else
I = image(loc = T)
add_images += I
I.appearance = T.appearance
I.override = TRUE
hidden_shuttle_turfs[T] = list(I, T.type)
hidden_shuttle_turf_images -= remove_images
hidden_shuttle_turf_images += add_images
for(var/V in GLOB.navigation_computers)
var/obj/machinery/computer/camera_advanced/shuttle_docker/C = V
C.update_hidden_docking_ports(remove_images, add_images)
QDEL_LIST(remove_images)
+11 -4
View File
@@ -33,8 +33,8 @@ SUBSYSTEM_DEF(ticker)
SCRIPTURE_APPLICATION = FALSE) //list of clockcult scripture states for announcements
var/delay_end = 0 //if set true, the round will not restart on it's own
var/admin_delay_notice = "" //a message to display to anyone who tries to restart the world after a delay
var/ready_for_reboot = FALSE //all roundend preparation done with, all that's left is reboot
var/triai = 0 //Global holder for Triumvirate
var/tipped = 0 //Did we broadcast the tip of the day yet?
@@ -584,10 +584,17 @@ SUBSYSTEM_DEF(ticker)
SSblackbox.Seal()
sleep(50)
if(mode.station_was_nuked)
Reboot("Station destroyed by Nuclear Device.", "nuke")
ready_for_reboot = TRUE
standard_reboot()
/datum/controller/subsystem/ticker/proc/standard_reboot()
if(ready_for_reboot)
if(mode.station_was_nuked)
Reboot("Station destroyed by Nuclear Device.", "nuke")
else
Reboot("Round ended.", "proper completion")
else
Reboot("Round ended.", "proper completion")
CRASH("Attempted standard reboot without ticker roundend completion")
/datum/controller/subsystem/ticker/proc/send_tip_of_the_round()
var/m
+52
View File
@@ -0,0 +1,52 @@
SUBSYSTEM_DEF(traumas)
name = "Traumas"
flags = SS_NO_FIRE
var/list/phobia_types
var/list/phobia_words
var/list/phobia_mobs
var/list/phobia_objs
var/list/phobia_turfs
var/list/phobia_species
#define PHOBIA_FILE "phobia.json"
/datum/controller/subsystem/traumas/Initialize()
phobia_types = list("spiders", "space", "security", "clowns", "greytide", "lizards", "skeletons")
phobia_words = list("spiders" = strings(PHOBIA_FILE, "spiders"),
"space" = strings(PHOBIA_FILE, "space"),
"security" = strings(PHOBIA_FILE, "security"),
"clowns" = strings(PHOBIA_FILE, "clowns"),
"greytide" = strings(PHOBIA_FILE, "greytide"),
"lizards" = strings(PHOBIA_FILE, "lizards"),
"skeletons" = strings(PHOBIA_FILE, "skeletons"),
)
phobia_mobs = list("spiders" = typecacheof(list(/mob/living/simple_animal/hostile/poison/giant_spider)),
"security" = typecacheof(list(/mob/living/simple_animal/bot/secbot)),
"lizards" = typecacheof(list(/mob/living/simple_animal/hostile/lizard))
)
phobia_objs = list("spiders" = typecacheof(list(/obj/structure/spider)),
"security" = typecacheof(list(/obj/item/clothing/under/rank/security, /obj/item/clothing/under/rank/warden,
/obj/item/clothing/under/rank/head_of_security, /obj/item/clothing/under/rank/det,
/obj/item/melee/baton, /obj/item/gun/energy/taser, /obj/item/restraints/handcuffs,
/obj/machinery/door/airlock/security)),
"clowns" = typecacheof(list(/obj/item/clothing/under/rank/clown, /obj/item/clothing/shoes/clown_shoes,
/obj/item/clothing/mask/gas/clown_hat, /obj/item/device/instrument/bikehorn,
/obj/item/device/pda/clown, /obj/item/grown/bananapeel)),
"greytide" = typecacheof(list(/obj/item/clothing/under/color/grey, /obj/item/melee/baton/cattleprod,
/obj/item/twohanded/spear, /obj/item/clothing/mask/gas)),
"lizards" = typecacheof(list(/obj/item/toy/plush/lizardplushie, /obj/item/reagent_containers/food/snacks/kebab/tail,
/obj/item/organ/tail/lizard, /obj/item/reagent_containers/food/drinks/bottle/lizardwine)),
"skeletons" = typecacheof(list(/obj/item/organ/tongue/bone, /obj/item/clothing/suit/armor/bone, /obj/item/stack/sheet/bone,
/obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/skeleton,
/obj/effect/decal/remains/human))
)
phobia_turfs = list("space" = typecacheof(list(/turf/open/space, /turf/open/floor/holofloor/space, /turf/open/floor/fakespace)))
phobia_species = list("lizards" = typecacheof(list(/datum/species/lizard)),
"skeletons" = typecacheof(list(/datum/species/skeleton, /datum/species/plasmaman))
)
#undef PHOBIA_FILE
+9
View File
@@ -41,5 +41,14 @@ SUBSYSTEM_DEF(weather)
if(W.name == weather_name && W.target_z == Z)
W.telegraph()
/datum/controller/subsystem/weather/proc/is_weather_affecting_area(area/A, weather_datum_type)
for(var/V in processing)
var/datum/weather/W = V
if(!istype(W, weather_datum_type))
continue
if(A in W.impacted_areas)
return TRUE
return FALSE
/datum/controller/subsystem/weather/proc/make_z_eligible(zlevel)
eligible_zlevels |= zlevel
+19 -1
View File
@@ -43,10 +43,27 @@
return
Remove(owner)
owner = M
//button id generation
var/counter = 0
var/bitfield = 0
for(var/datum/action/A in M.actions)
if(A.name == name && A.button.id)
counter += 1
bitfield |= A.button.id
bitfield = ~bitfield
var/bitflag = 1
for(var/i in 1 to (counter + 1))
if(bitfield & bitflag)
button.id = bitflag
break
bitflag *= 2
M.actions += src
if(M.client)
M.client.screen += button
button.locked = M.client.prefs.buttons_locked
button.locked = M.client.prefs.buttons_locked || button.id ? M.client.prefs.action_buttons_screen_locs["[name]_[button.id]"] : FALSE //even if it's not defaultly locked we should remember we locked it before
button.moved = button.id ? M.client.prefs.action_buttons_screen_locs["[name]_[button.id]"] : FALSE
M.update_action_buttons()
else
Remove(owner)
@@ -60,6 +77,7 @@
owner = null
button.moved = FALSE //so the button appears in its normal position when given to another owner.
button.locked = FALSE
button.id = null
/datum/action/proc/Trigger()
if(!IsAvailable())
+8 -7
View File
@@ -71,7 +71,7 @@
var/datum/objective/escape/escape_objective = new
escape_objective.owner = owner
objectives += escape_objective
if(31 to 60)
var/datum/objective/steal/steal_objective = new
steal_objective.owner = owner
@@ -103,8 +103,8 @@
if (!(locate(/datum/objective/hijack) in owner.objectives))
var/datum/objective/hijack/hijack_objective = new
hijack_objective.owner = owner
objectives += hijack_objective
objectives += hijack_objective
for(var/datum/objective/O in objectives)
owner.objectives += O
@@ -128,7 +128,7 @@
if(H.age < wiz_age)
H.age = wiz_age
H.equipOutfit(outfit_type)
/datum/antagonist/wizard/greet()
to_chat(owner, "<span class='boldannounce'>You are the Space Wizard!</span>")
to_chat(owner, "<B>The Space Wizards Federation has given you the following tasks:</B>")
@@ -208,7 +208,7 @@
owner.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/knock(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/mind_transfer(null))
to_chat(owner, "<B>Your service has not gone unrewarded, however. Studying under [master.current.real_name], you have learned stealthy, robeless spells. You are able to cast knock and mindswap.")
/datum/antagonist/wizard/apprentice/create_objectives()
var/datum/objective/protect/new_objective = new /datum/objective/protect
new_objective.owner = owner
@@ -221,6 +221,7 @@
/datum/antagonist/wizard/apprentice/imposter
name = "Wizard Imposter"
allow_rename = FALSE
move_to_lair = FALSE
/datum/antagonist/wizard/apprentice/imposter/greet()
to_chat(owner, "<B>You are an imposter! Trick and confuse the crew to misdirect malice from your handsome original!</B>")
@@ -266,7 +267,7 @@
/datum/antagonist/wizard/academy/equip_wizard()
. = ..()
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt)
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/projectile/magic_missile)
owner.AddSpell(new /obj/effect/proc_holder/spell/aimed/fireball)
@@ -274,7 +275,7 @@
var/mob/living/M = owner.current
if(!istype(M))
return
var/obj/item/implant/exile/Implant = new/obj/item/implant/exile(M)
Implant.implant(M)
+49
View File
@@ -0,0 +1,49 @@
//Brain Traumas are the new actual brain damage. Brain damage itself acts as a way to acquire traumas: every time brain damage is dealt, there's a chance of receiving a trauma.
//This chance gets higher the higher the mob's brainloss is. Removing traumas is a separate thing from removing brain damage: you can get restored to full brain operativity,
//but keep the quirks, until repaired by mannitol (for mild/special ones) or brain surgery (for severe ones).
/datum/brain_trauma
var/name = "Brain Trauma"
var/desc = "A trauma caused by brain damage, which causes issues to the patient."
var/scan_desc = "a generic brain trauma" //description when detected by a health scanner
var/mob/living/carbon/owner //the poor bastard
var/obj/item/organ/brain/brain //the poor bastard's brain
var/gain_text = "<span class='notice'>You feel traumatized.</span>"
var/lose_text = "<span class='notice'>You no longer feel traumatized.</span>"
var/can_gain = TRUE //can this be gained through random traumas?
var/permanent = FALSE //can this be cured?
/datum/brain_trauma/New(obj/item/organ/brain/B, _permanent)
brain = B
owner = B.owner
permanent = _permanent
if(owner)
on_gain()
/datum/brain_trauma/Destroy()
brain.traumas -= src
if(owner)
on_lose()
brain = null
owner = null
return ..()
//Called on life ticks
/datum/brain_trauma/proc/on_life()
return
//Called when given to a mob
/datum/brain_trauma/proc/on_gain()
to_chat(owner, gain_text)
//Called when removed from a mob
/datum/brain_trauma/proc/on_lose(silent)
if(!silent)
to_chat(owner, lose_text)
//Called when hearing a spoken message
/datum/brain_trauma/proc/on_hear(message, speaker, message_language, raw_message, radio_freq)
return message
//Called when speaking
/datum/brain_trauma/proc/on_say(message)
return message
+135
View File
@@ -0,0 +1,135 @@
//Mild traumas are the most common; they are generally minor annoyances.
//They can be cured with mannitol and patience, although brain surgery still works.
//Most of the old brain damage effects have been transferred to the dumbness trauma.
/datum/brain_trauma/mild
/datum/brain_trauma/mild/hallucinations
name = "Hallucinations"
desc = "Patient suffers constant hallucinations."
scan_desc = "schizophrenia"
gain_text = "<span class='warning'>You feel your grip on reality slipping...</span>"
lose_text = "<span class='notice'>You feel more grounded.</span>"
/datum/brain_trauma/mild/hallucinations/on_life()
owner.hallucination = min(owner.hallucination + 10, 50)
..()
/datum/brain_trauma/mild/hallucinations/on_lose()
owner.hallucination = 0
..()
/datum/brain_trauma/mild/stuttering
name = "Stuttering"
desc = "Patient can't speak properly."
scan_desc = "reduced mouth coordination"
gain_text = "<span class='warning'>Speaking clearly is getting harder.</span>"
lose_text = "<span class='notice'>You feel in control of your speech.</span>"
/datum/brain_trauma/mild/stuttering/on_life()
owner.stuttering = min(owner.stuttering + 5, 25)
..()
/datum/brain_trauma/mild/stuttering/on_lose()
owner.stuttering = 0
..()
/datum/brain_trauma/mild/dumbness
name = "Dumbness"
desc = "Patient has reduced brain activity, making them less intelligent."
scan_desc = "reduced brain activity"
gain_text = "<span class='warning'>You feel dumber.</span>"
lose_text = "<span class='notice'>You feel smart again.</span>"
/datum/brain_trauma/mild/dumbness/on_gain()
owner.disabilities |= DUMB
..()
/datum/brain_trauma/mild/dumbness/on_life()
owner.derpspeech = min(owner.derpspeech + 5, 25)
if(prob(3))
owner.emote("drool")
else if(owner.stat == CONSCIOUS && prob(3))
owner.say(pick_list_replacements(BRAIN_DAMAGE_FILE, "brain_damage"))
..()
/datum/brain_trauma/mild/dumbness/on_lose()
owner.disabilities &= ~DUMB
owner.derpspeech = 0
..()
/datum/brain_trauma/mild/speech_impediment
name = "Speech Impediment"
desc = "Patient is unable to form coherent sentences."
scan_desc = "communication disorder"
gain_text = "" //mutation will handle the text
lose_text = ""
/datum/brain_trauma/mild/speech_impediment/on_gain()
owner.dna.add_mutation(UNINTELLIGIBLE)
..()
//no fiddling with genetics to get out of this one
/datum/brain_trauma/mild/speech_impediment/on_life()
if(!(GLOB.mutations_list[UNINTELLIGIBLE] in owner.dna.mutations))
on_gain()
..()
/datum/brain_trauma/mild/speech_impediment/on_lose()
owner.dna.remove_mutation(UNINTELLIGIBLE)
..()
/datum/brain_trauma/mild/concussion
name = "Concussion"
desc = "Patient's brain is concussed."
scan_desc = "a concussion"
gain_text = "<span class='warning'>Your head hurts!</span>"
lose_text = "<span class='notice'>The pressure inside your head starts fading.</span>"
/datum/brain_trauma/mild/concussion/on_life()
if(prob(5))
switch(rand(1,11))
if(1)
owner.vomit()
if(2,3)
owner.dizziness += 10
if(4,5)
owner.confused += 10
owner.blur_eyes(10)
if(6 to 9)
owner.slurring += 30
if(10)
to_chat(owner, "<span class='notice'>You forget for a moment what you were doing.</span>")
owner.Stun(20)
if(11)
to_chat(owner, "<span class='warning'>You faint.</span>")
owner.Unconscious(80)
..()
/datum/brain_trauma/mild/muscle_weakness
name = "Muscle Weakness"
desc = "Patient experiences occasional bouts of muscle weakness."
scan_desc = "weak motor nerve signal"
gain_text = "<span class='warning'>Your muscles feel oddly faint.</span>"
lose_text = "<span class='notice'>You feel in control of your muscles again.</span>"
/datum/brain_trauma/mild/muscle_weakness/on_life()
var/fall_chance = 1
if(owner.m_intent == MOVE_INTENT_RUN)
fall_chance += 2
if(prob(fall_chance) && !owner.lying && !owner.buckled)
to_chat(owner, "<span class='warning'>Your leg gives out!</span>")
owner.Knockdown(35)
else if(owner.get_active_held_item())
var/drop_chance = 1
var/obj/item/I = owner.get_active_held_item()
drop_chance += I.w_class
if(prob(drop_chance) && owner.dropItemToGround(I))
to_chat(owner, "<span class='warning'>You drop [I]!</span>")
else if(prob(3))
to_chat(owner, "<span class='warning'>You feel a sudden weakness in your muscles!</span>")
owner.adjustStaminaLoss(50)
..()
+115
View File
@@ -0,0 +1,115 @@
/datum/brain_trauma/mild/phobia
name = "Phobia"
desc = "Patient is unreasonably afraid of something."
scan_desc = "phobia"
gain_text = ""
lose_text = ""
var/phobia_type
var/next_check = 0
var/next_scare = 0
var/list/trigger_words
//instead of cycling every atom, only cycle the relevant types
var/list/trigger_mobs
var/list/trigger_objs //also checked in mob equipment
var/list/trigger_turfs
var/list/trigger_species
/datum/brain_trauma/mild/phobia/New(mob/living/carbon/C, _permanent, specific_type)
phobia_type = specific_type
if(!phobia_type)
phobia_type = pick(SStraumas.phobia_types)
gain_text = "<span class='warning'>You start finding [phobia_type] very unnerving...</span>"
lose_text = "<span class='notice'>You no longer feel afraid of [phobia_type].</span>"
scan_desc += " of [phobia_type]"
trigger_words = SStraumas.phobia_words[phobia_type]
trigger_mobs = SStraumas.phobia_mobs[phobia_type]
trigger_objs = SStraumas.phobia_objs[phobia_type]
trigger_turfs = SStraumas.phobia_turfs[phobia_type]
trigger_species = SStraumas.phobia_species[phobia_type]
..()
/datum/brain_trauma/mild/phobia/on_life()
..()
if(owner.eye_blind)
return
if(world.time > next_check && world.time > next_scare)
next_check = world.time + 50
var/list/seen_atoms = view(7, owner)
if(LAZYLEN(trigger_objs))
for(var/obj/O in seen_atoms)
if(is_type_in_typecache(O, trigger_objs))
freak_out(O)
return
if(LAZYLEN(trigger_turfs))
for(var/turf/T in seen_atoms)
if(is_type_in_typecache(T, trigger_turfs))
freak_out(T)
return
if(LAZYLEN(trigger_mobs) || LAZYLEN(trigger_objs))
for(var/mob/M in seen_atoms)
if(is_type_in_typecache(M, trigger_mobs))
freak_out(M)
return
else if(ishuman(M)) //check their equipment for trigger items
var/mob/living/carbon/human/H = M
if(LAZYLEN(trigger_species) && H.dna && H.dna.species && is_type_in_typecache(H.dna.species, trigger_species))
freak_out(H)
for(var/X in H.get_all_slots() | H.held_items)
var/obj/I = X
if(!QDELETED(I) && is_type_in_typecache(I, trigger_objs))
freak_out(I)
return
/datum/brain_trauma/mild/phobia/on_hear(message, speaker, message_language, raw_message, radio_freq)
if(owner.disabilities & DEAF || world.time < next_scare) //words can't trigger you if you can't hear them *taps head*
return message
for(var/word in trigger_words)
if(findtext(message, word))
addtimer(CALLBACK(src, .proc/freak_out, null, word), 10) //to react AFTER the chat message
break
return message
/datum/brain_trauma/mild/phobia/on_say(message)
for(var/word in trigger_words)
if(findtext(message, word))
to_chat(owner, "<span class='warning'>You can't bring yourself to say the word \"[word]\"!</span>")
return ""
return message
/datum/brain_trauma/mild/phobia/proc/freak_out(atom/reason, trigger_word)
next_scare = world.time + 120
var/message = pick("spooks you to the bone", "shakes you up", "terrifies you", "sends you into a panic", "sends chills down your spine")
if(reason)
to_chat(owner, "<span class='userdanger'>Seeing [reason] [message]!</span>")
else if(trigger_word)
to_chat(owner, "<span class='userdanger'>Hearing \"[trigger_word]\" [message]!</span>")
else
to_chat(owner, "<span class='userdanger'>Something [message]!</span>")
var/reaction = rand(1,4)
switch(reaction)
if(1)
to_chat(owner, "<span class='warning'>You are paralyzed with fear!</span>")
owner.Stun(70)
owner.Jitter(8)
if(2)
owner.emote("scream")
owner.Jitter(5)
owner.say("AAAAH!!")
if(reason)
owner.pointed(reason)
if(3)
to_chat(owner, "<span class='warning'>You shut your eyes in terror!</span>")
owner.Jitter(5)
owner.blind_eyes(10)
if(4)
owner.dizziness += 10
owner.confused += 10
owner.Jitter(10)
owner.stuttering += 10
+179
View File
@@ -0,0 +1,179 @@
//Severe traumas, when your brain gets abused way too much.
//These range from very annoying to completely debilitating.
//They cannot be cured with chemicals, and require brain surgery to solve.
/datum/brain_trauma/severe
/datum/brain_trauma/severe/mute
name = "Mutism"
desc = "Patient is completely unable to speak."
scan_desc = "extensive damage to the brain's language center"
gain_text = "<span class='warning'>You forget how to speak!</span>"
lose_text = "<span class='notice'>You suddenly remember how to speak.</span>"
/datum/brain_trauma/severe/mute/on_gain()
owner.disabilities |= MUTE
..()
//no fiddling with genetics to get out of this one
/datum/brain_trauma/severe/mute/on_life()
if(!(owner.disabilities & MUTE))
on_gain()
..()
/datum/brain_trauma/severe/mute/on_lose()
owner.disabilities &= ~MUTE
..()
/datum/brain_trauma/severe/blindness
name = "Cerebral Blindness"
desc = "Patient's brain is no longer connected to its eyes."
scan_desc = "extensive damage to the brain's occipital lobe"
gain_text = "<span class='warning'>You can't see!</span>"
lose_text = "<span class='notice'>Your vision returns.</span>"
/datum/brain_trauma/severe/blindness/on_gain()
owner.become_blind()
..()
//no fiddling with genetics to get out of this one
/datum/brain_trauma/severe/blindness/on_life()
if(!(owner.disabilities & BLIND))
on_gain()
..()
/datum/brain_trauma/severe/blindness/on_lose()
owner.cure_blind()
..()
/datum/brain_trauma/severe/paralysis
name = "Paralysis"
desc = "Patient's brain can no longer control its motor functions."
scan_desc = "cerebral paralysis"
gain_text = "<span class='warning'>You can't feel your body anymore!</span>"
lose_text = "<span class='notice'>You can feel your limbs again!</span>"
/datum/brain_trauma/severe/paralysis/on_life()
owner.Knockdown(200, ignore_canknockdown = TRUE)
..()
/datum/brain_trauma/severe/paralysis/on_lose()
owner.SetKnockdown(0)
..()
/datum/brain_trauma/severe/narcolepsy
name = "Narcolepsy"
desc = "Patient may involuntarily fall asleep during normal activities."
scan_desc = "traumatic narcolepsy"
gain_text = "<span class='warning'>You have a constant feeling of drowsiness...</span>"
lose_text = "<span class='notice'>You feel awake and aware again.</span>"
/datum/brain_trauma/severe/narcolepsy/on_life()
..()
if(owner.IsSleeping())
return
var/sleep_chance = 1
if(owner.m_intent == MOVE_INTENT_RUN)
sleep_chance += 2
if(owner.drowsyness)
sleep_chance += 3
if(prob(sleep_chance))
to_chat(owner, "<span class='warning'>You fall asleep.</span>")
owner.Sleeping(60)
else if(!owner.drowsyness && prob(sleep_chance * 2))
to_chat(owner, "<span class='warning'>You feel tired...</span>")
owner.drowsyness += 10
/datum/brain_trauma/severe/monophobia
name = "Monophobia"
desc = "Patient feels sick and distressed when not around other people, leading to potentially lethal levels of stress."
scan_desc = "severe monophobia"
gain_text = ""
lose_text = "<span class='notice'>You feel like you could be safe on your own.</span>"
var/stress = 0
/datum/brain_trauma/severe/monophobia/on_gain()
..()
if(check_alone())
to_chat(owner, "<span class='warning'>You feel really lonely...</span>")
else
to_chat(owner, "<span class='notice'>You feel safe, as long as you have people around you.</span>")
/datum/brain_trauma/severe/monophobia/on_life()
..()
if(check_alone())
stress = min(stress + 0.5, 100)
if(stress > 10 && (prob(5)))
stress_reaction()
else
stress -= 4
/datum/brain_trauma/severe/monophobia/proc/check_alone()
if(owner.disabilities & BLIND)
return TRUE
for(var/mob/M in oview(owner, 7))
if(!isliving(M)) //ghosts ain't people
continue
if((istype(M, /mob/living/simple_animal/pet)) || M.ckey)
return FALSE
return TRUE
/datum/brain_trauma/severe/monophobia/proc/stress_reaction()
if(owner.stat != CONSCIOUS)
return
var/high_stress = (stress > 60) //things get psychosomatic from here on
switch(rand(1,6))
if(1)
if(!high_stress)
to_chat(owner, "<span class='warning'>You feel sick...</span>")
else
to_chat(owner, "<span class='warning'>You feel really sick at the thought of being alone!</span>")
addtimer(CALLBACK(owner, /mob/living/carbon.proc/vomit, high_stress), 50) //blood vomit if high stress
if(2)
if(!high_stress)
to_chat(owner, "<span class='warning'>You can't stop shaking...</span>")
owner.dizziness += 20
owner.confused += 20
owner.Jitter(20)
else
to_chat(owner, "<span class='warning'>You feel weak and scared! If only you weren't alone...</span>")
owner.dizziness += 20
owner.confused += 20
owner.Jitter(20)
owner.adjustStaminaLoss(50)
if(3, 4)
if(!high_stress)
to_chat(owner, "<span class='warning'>You feel really lonely...</span>")
else
to_chat(owner, "<span class='warning'>You're going mad with loneliness!</span>")
owner.hallucination += 20
if(5)
if(!high_stress)
to_chat(owner, "<span class='warning'>Your heart skips a beat.</span>")
owner.adjustOxyLoss(8)
else
if(prob(15) && ishuman(owner))
var/mob/living/carbon/human/H = owner
H.set_heartattack(TRUE)
to_chat(H, "<span class='userdanger'>You feel a stabbing pain in your heart!</span>")
else
to_chat(owner, "<span class='userdanger'>You feel your heart lurching in your chest...</span>")
owner.adjustOxyLoss(8)
/datum/brain_trauma/severe/discoordination
name = "Discoordination"
desc = "Patient is unable to use complex tools or machinery."
scan_desc = "extreme discoordination"
gain_text = "<span class='warning'>You can barely control your hands!</span>"
lose_text = "<span class='notice'>You feel in control of your hands again.</span>"
/datum/brain_trauma/severe/discoordination/on_gain()
owner.disabilities |= MONKEYLIKE
..()
/datum/brain_trauma/severe/discoordination/on_lose()
owner.disabilities &= ~MONKEYLIKE
..()
+122
View File
@@ -0,0 +1,122 @@
//Brain traumas that are rare and/or somewhat beneficial;
//they are the easiest to cure, which means that if you want
//to keep them, you can't cure your other traumas
/datum/brain_trauma/special
/datum/brain_trauma/special/godwoken
name = "Godwoken Syndrome"
desc = "Patient occasionally and uncontrollably channels an eldritch god when speaking."
scan_desc = "god delusion"
gain_text = "<span class='notice'>You feel a higher power inside your mind...</span>"
lose_text = "<span class='warning'>The divine presence leaves your head, no longer interested.</span>"
var/next_speech = 0
var/inspiration = FALSE
/datum/brain_trauma/special/godwoken/on_life()
..()
if(!inspiration && world.time > next_speech && prob(4))
to_chat(owner, "<span class='notice'>[pick("You feel inspired!","You feel power course through you...","You feel something within you itching to speak...")]</span>")
inspiration = TRUE
/datum/brain_trauma/special/godwoken/on_say(message)
if(world.time > next_speech && inspiration)
playsound(get_turf(owner), 'sound/magic/clockwork/invoke_general.ogg', 300, 1, 5)
var/cooldown = voice_of_god(message, owner, list("colossus","yell"), 2)
cooldown *= 0.33
next_speech = world.time + cooldown
inspiration = FALSE
return ""
else
return message
/datum/brain_trauma/special/bluespace_prophet
name = "Bluespace Prophecy"
desc = "Patient can sense the bob and weave of bluespace around them, showing them passageways no one else can see."
scan_desc = "bluespace attunement"
gain_text = "<span class='notice'>You feel the bluespace pulsing around you...</span>"
lose_text = "<span class='warning'>The faint pulsing of bluespace fades into silence.</span>"
var/next_portal = 0
/datum/brain_trauma/special/bluespace_prophet/on_life()
if(world.time > next_portal)
next_portal = world.time + 100
var/list/turf/possible_turfs = list()
for(var/turf/T in range(owner, 8))
if(!T.density)
var/clear = TRUE
for(var/obj/O in T)
if(O.density)
clear = FALSE
break
if(clear)
possible_turfs += T
if(!LAZYLEN(possible_turfs))
return
var/turf/first_turf = pick(possible_turfs)
if(!first_turf)
return
possible_turfs -= (possible_turfs & range(first_turf, 3))
var/turf/second_turf = pick(possible_turfs)
if(!second_turf)
return
var/obj/effect/hallucination/simple/bluespace_stream/first = new(first_turf, owner)
var/obj/effect/hallucination/simple/bluespace_stream/second = new(second_turf, owner)
first.linked_to = second
second.linked_to = first
first.seer = owner
second.seer = owner
/obj/effect/hallucination/simple/bluespace_stream
name = "bluespace stream"
desc = "You see a hidden pathway through bluespace..."
image_icon = 'icons/effects/effects.dmi'
image_state = "bluestream"
image_layer = ABOVE_MOB_LAYER
var/obj/effect/hallucination/simple/bluespace_stream/linked_to
var/mob/living/carbon/seer
/obj/effect/hallucination/simple/bluespace_stream/Initialize()
. = ..()
QDEL_IN(src, 300)
/obj/effect/hallucination/simple/bluespace_stream/attack_hand(mob/user)
if(user != seer || !linked_to)
return
var/slip_in_message = pick("slides sideways in an odd way, and disappears", "jumps into an unseen dimension",\
"sticks one leg straight out, wiggles [user.p_their()] foot, and is suddenly gone", "stops, then blinks out of reality", \
"is pulled into an invisible vortex, vanishing from sight")
var/slip_out_message = pick("silently fades in", "leaps out of thin air","appears", "walks out of an invisible doorway",\
"slides out of a fold in spacetime")
to_chat(user, "<span class='notice'>You try to align with the bluespace stream...</span>")
if(do_after(user, 20, target = src))
new /obj/effect/temp_visual/bluespace_fissure(get_turf(src))
new /obj/effect/temp_visual/bluespace_fissure(get_turf(linked_to))
user.forceMove(get_turf(linked_to))
user.visible_message("<span class='warning'>[user] [slip_in_message].</span>", ignored_mob = user)
user.visible_message("<span class='warning'>[user] [slip_out_message].</span>", "<span class='notice'>...and find your way to the other side.</span>")
/datum/brain_trauma/special/psychotic_brawling
name = "Violent Psychosis"
desc = "Patient fights in unpredictable ways, ranging from helping his target to hitting them with brutal strength."
scan_desc = "violent psychosis"
gain_text = "<span class='warning'>You feel unhinged...</span>"
lose_text = "<span class='notice'>You feel more balanced.</span>"
var/datum/martial_art/psychotic_brawling/psychotic_brawling
/datum/brain_trauma/special/psychotic_brawling/on_gain()
..()
psychotic_brawling = new(null)
if(!psychotic_brawling.teach(owner, TRUE))
to_chat(owner, "<span class='notice'>But your martial knowledge keeps you grounded.</span>")
qdel(src)
/datum/brain_trauma/special/psychotic_brawling/on_lose()
..()
psychotic_brawling.remove(owner)
QDEL_NULL(psychotic_brawling)
@@ -0,0 +1,218 @@
#define OWNER 0
#define STRANGER 1
/datum/brain_trauma/severe/split_personality
name = "Split Personality"
desc = "Patient's brain is split into two personalities, which randomly switch control of the body."
scan_desc = "complete lobe separation"
gain_text = "<span class='warning'>You feel like your mind was split in two.</span>"
lose_text = "<span class='notice'>You feel alone again.</span>"
var/current_controller = OWNER
var/initialized = FALSE //to prevent personalities deleting themselves while we wait for ghosts
var/mob/living/split_personality/stranger_backseat //there's two so they can swap without overwriting
var/mob/living/split_personality/owner_backseat
/datum/brain_trauma/severe/split_personality/on_gain()
..()
make_backseats()
get_ghost()
/datum/brain_trauma/severe/split_personality/proc/make_backseats()
stranger_backseat = new(owner, src)
owner_backseat = new(owner, src)
/datum/brain_trauma/severe/split_personality/proc/get_ghost()
set waitfor = FALSE
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s split personality?", null, null, null, 75, stranger_backseat)
if(LAZYLEN(candidates))
var/client/C = pick(candidates)
stranger_backseat.key = C.key
else
qdel(src)
/datum/brain_trauma/severe/split_personality/on_life()
if(owner.stat == DEAD)
if(current_controller != OWNER)
switch_personalities()
qdel(src)
else if(prob(3))
switch_personalities()
..()
/datum/brain_trauma/severe/split_personality/on_lose()
if(current_controller != OWNER) //it would be funny to cure a guy only to be left with the other personality, but it seems too cruel
switch_personalities()
QDEL_NULL(stranger_backseat)
QDEL_NULL(owner_backseat)
..()
/datum/brain_trauma/severe/split_personality/proc/switch_personalities()
if(QDELETED(owner) || owner.stat == DEAD || QDELETED(stranger_backseat) || QDELETED(owner_backseat))
return
var/mob/living/split_personality/current_backseat
var/mob/living/split_personality/free_backseat
if(current_controller == OWNER)
current_backseat = stranger_backseat
free_backseat = owner_backseat
else
current_backseat = owner_backseat
free_backseat = stranger_backseat
log_game("[current_backseat]/([current_backseat.ckey]) assumed control of [owner]/([owner.ckey] due to [src]. (Original owner: [current_controller == OWNER ? owner.ckey : current_backseat.ckey])")
to_chat(owner, "<span class='userdanger'>You feel your control being taken away... your other personality is in charge now!</span>")
to_chat(current_backseat, "<span class='userdanger'>You manage to take control of your body!</span>")
//Body to backseat
var/h2b_id = owner.computer_id
var/h2b_ip= owner.lastKnownIP
owner.computer_id = null
owner.lastKnownIP = null
free_backseat.ckey = owner.ckey
free_backseat.name = owner.name
if(owner.mind)
free_backseat.mind = owner.mind
if(!free_backseat.computer_id)
free_backseat.computer_id = h2b_id
if(!free_backseat.lastKnownIP)
free_backseat.lastKnownIP = h2b_ip
//Backseat to body
var/s2h_id = current_backseat.computer_id
var/s2h_ip= current_backseat.lastKnownIP
current_backseat.computer_id = null
current_backseat.lastKnownIP = null
owner.ckey = current_backseat.ckey
owner.mind = current_backseat.mind
if(!owner.computer_id)
owner.computer_id = s2h_id
if(!owner.lastKnownIP)
owner.lastKnownIP = s2h_ip
current_controller = !current_controller
/mob/living/split_personality
name = "split personality"
real_name = "unknown conscience"
var/mob/living/carbon/body
var/datum/brain_trauma/severe/split_personality/trauma
/mob/living/split_personality/Initialize(mapload, _trauma)
if(iscarbon(loc))
body = loc
name = body.real_name
real_name = body.real_name
trauma = _trauma
return ..()
/mob/living/split_personality/Life()
if(QDELETED(body))
qdel(src) //in case trauma deletion doesn't already do it
if((body.stat == DEAD && trauma.owner_backseat == src))
trauma.switch_personalities()
qdel(trauma)
//if one of the two ghosts, the other one stays permanently
if(!body.client && trauma.initialized)
trauma.switch_personalities()
qdel(trauma)
..()
/mob/living/split_personality/Login()
..()
to_chat(src, "<span class='notice'>As a split personality, you cannot do anything but observe. However, you will eventually gain control of your body, switching places with the current personality.</span>")
/mob/living/split_personality/say(message)
to_chat(src, "<span class='warning'>You cannot speak, your other self is controlling your body!</span>")
return FALSE
/mob/living/split_personality/emote(message)
return
///////////////BRAINWASHING////////////////////
/datum/brain_trauma/severe/split_personality/brainwashing
name = "Split Personality"
desc = "Patient's brain is split into two personalities, which randomly switch control of the body."
scan_desc = "complete lobe separation"
gain_text = ""
lose_text = "<span class='notice'>You are free of your brainwashing.</span>"
can_gain = FALSE
var/codeword
var/objective
/datum/brain_trauma/severe/split_personality/brainwashing/New(obj/item/organ/brain/B, _permanent, _codeword, _objective)
..()
if(_codeword)
codeword = _codeword
else
codeword = pick(strings("ion_laws.json", "ionabstract")\
| strings("ion_laws.json", "ionobjects")\
| strings("ion_laws.json", "ionadjectives")\
| strings("ion_laws.json", "ionthreats")\
| strings("ion_laws.json", "ionfood")\
| strings("ion_laws.json", "iondrinks"))
/datum/brain_trauma/severe/split_personality/brainwashing/on_gain()
..()
var/mob/living/split_personality/traitor/traitor_backseat = stranger_backseat
traitor_backseat.codeword = codeword
traitor_backseat.objective = objective
/datum/brain_trauma/severe/split_personality/brainwashing/make_backseats()
stranger_backseat = new /mob/living/split_personality/traitor(owner, src, codeword, objective)
owner_backseat = new(owner, src)
/datum/brain_trauma/severe/split_personality/brainwashing/get_ghost()
set waitfor = FALSE
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s brainwashed mind?", null, null, null, 75, stranger_backseat)
if(LAZYLEN(candidates))
var/client/C = pick(candidates)
stranger_backseat.key = C.key
else
qdel(src)
/datum/brain_trauma/severe/split_personality/brainwashing/on_life()
return //no random switching
/datum/brain_trauma/severe/split_personality/brainwashing/on_hear(message, speaker, message_language, raw_message, radio_freq)
if(owner.disabilities & DEAF || owner == speaker)
return message
if(findtext(message, codeword))
message = replacetext(message, codeword, "<span class='warning'>[codeword]</span>")
addtimer(CALLBACK(src, /datum/brain_trauma/severe/split_personality.proc/switch_personalities), 10)
return message
/datum/brain_trauma/severe/split_personality/brainwashing/on_say(message)
if(findtext(message, codeword))
return "" //oh hey did you want to tell people about the secret word to bring you back?
return message
/mob/living/split_personality/traitor
name = "split personality"
real_name = "unknown conscience"
var/objective
var/codeword
/mob/living/split_personality/traitor/Login()
..()
to_chat(src, "<span class='notice'>As a brainwashed personality, you cannot do anything yet but observe. However, you may gain control of your body if you hear the special codeword, switching places with the current personality.</span>")
to_chat(src, "<span class='notice'>Your activation codeword is: <b>[codeword]</b></span>")
if(objective)
to_chat(src, "<span class='notice'>Your master left you an objective: <b>[objective]</b>. Follow it at all costs when in control.</span>")
#undef OWNER
#undef STRANGER
+60
View File
@@ -0,0 +1,60 @@
/datum/component/caltrop
var/min_damage
var/max_damage
var/probability
var/flags
var/cooldown = 0
/datum/component/caltrop/Initialize(_min_damage = 0, _max_damage = 0, _probability = 100, _flags = NONE)
min_damage = _min_damage
max_damage = max(_min_damage, _max_damage)
probability = _probability
flags = _flags
RegisterSignal(list(COMSIG_MOVABLE_CROSSED), .proc/Crossed)
/datum/component/caltrop/proc/Crossed(atom/movable/AM)
var/atom/A = parent
if(!A.has_gravity())
return
if(!prob(probability))
return
if(ishuman(AM))
var/mob/living/carbon/human/H = AM
if(PIERCEIMMUNE in H.dna.species.species_traits)
return
if((flags & CALTROP_IGNORE_WALKERS) && H.m_intent == MOVE_INTENT_WALK)
return
var/picked_def_zone = pick("l_leg", "r_leg")
var/obj/item/bodypart/O = H.get_bodypart(picked_def_zone)
if(!istype(O))
return
if(O.status == BODYPART_ROBOTIC)
return
var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET))
if(!(flags & CALTROP_BYPASS_SHOES) && (H.shoes || feetCover))
return
if((H.movement_type & FLYING) || H.buckled)
return
var/damage = rand(min_damage, max_damage)
H.apply_damage(damage, BRUTE, picked_def_zone)
if(cooldown < world.time - 10) //cooldown to avoid message spam.
if(!H.incapacitated(ignore_restraints = TRUE))
H.visible_message("<span class='danger'>[H] steps on [A].</span>", \
"<span class='userdanger'>You step on [A]!</span>")
else
H.visible_message("<span class='danger'>[H] slides on [A]!</span>", \
"<span class='userdanger'>You slide on [A]!</span>")
cooldown = world.time
H.Knockdown(60)
+1 -1
View File
@@ -58,7 +58,7 @@
return
. = COMPONENT_NO_AFTERATTACK
var/datum/callback/pc = precondition
if(pc && !pc.Invoke())
if(pc && !pc.Invoke(user))
return
var/material_amount = get_item_material_amount(I)
if(!material_amount)
+326 -326
View File
@@ -1,326 +1,326 @@
/datum/component/riding
var/next_vehicle_move = 0 //used for move delays
var/vehicle_move_delay = 2 //tick delay between movements, lower = faster, higher = slower
var/keytype
var/slowed = FALSE
var/slowvalue = 1
var/list/riding_offsets = list() //position_of_user = list(dir = list(px, py)), or RIDING_OFFSET_ALL for a generic one.
var/list/directional_vehicle_layers = list() //["[DIRECTION]"] = layer. Don't set it for a direction for default, set a direction to null for no change.
var/list/directional_vehicle_offsets = list() //same as above but instead of layer you have a list(px, py)
var/list/allowed_turf_typecache
var/list/forbid_turf_typecache //allow typecache for only certain turfs, forbid to allow all but those. allow only certain turfs will take precedence.
var/allow_one_away_from_valid_turf = TRUE //allow moving one tile away from a valid turf but not more.
var/override_allow_spacemove = FALSE
var/drive_verb = "drive"
var/ride_check_rider_incapacitated = FALSE
var/ride_check_rider_restrained = FALSE
var/ride_check_ridden_incapacitated = FALSE
/datum/component/riding/Initialize()
if(!ismovableatom(parent))
. = COMPONENT_INCOMPATIBLE
CRASH("RIDING COMPONENT ASSIGNED TO NON ATOM MOVABLE!")
RegisterSignal(COMSIG_MOVABLE_BUCKLE, .proc/vehicle_mob_buckle)
RegisterSignal(COMSIG_MOVABLE_UNBUCKLE, .proc/vehicle_mob_unbuckle)
RegisterSignal(COMSIG_MOVABLE_MOVED, .proc/vehicle_moved)
/datum/component/riding/proc/vehicle_mob_unbuckle(mob/living/M, force = FALSE)
restore_position(M)
unequip_buckle_inhands(M)
/datum/component/riding/proc/vehicle_mob_buckle(mob/living/M, force = FALSE)
handle_vehicle_offsets()
/datum/component/riding/proc/handle_vehicle_layer()
var/atom/movable/AM = parent
var/static/list/defaults = list(TEXT_NORTH = OBJ_LAYER, TEXT_SOUTH = ABOVE_MOB_LAYER, TEXT_EAST = ABOVE_MOB_LAYER, TEXT_WEST = ABOVE_MOB_LAYER)
. = defaults["[AM.dir]"]
if(directional_vehicle_layers["[AM.dir]"])
. = directional_vehicle_layers["[AM.dir]"]
if(isnull(.)) //you can set it to null to not change it.
. = AM.layer
AM.layer = .
/datum/component/riding/proc/set_vehicle_dir_layer(dir, layer)
directional_vehicle_layers["[dir]"] = layer
/datum/component/riding/proc/vehicle_moved()
var/atom/movable/AM = parent
for(var/i in AM.buckled_mobs)
ride_check(i)
handle_vehicle_offsets()
handle_vehicle_layer()
/datum/component/riding/proc/ride_check(mob/living/M)
var/atom/movable/AM = parent
var/mob/AMM = AM
if((ride_check_rider_restrained && M.restrained(TRUE)) || (ride_check_rider_incapacitated && M.incapacitated(FALSE, TRUE)) || (ride_check_ridden_incapacitated && istype(AMM) && AMM.incapacitated(FALSE, TRUE)))
AM.visible_message("<span class='warning'>[M] falls off of [AM]!</span>")
AM.unbuckle_mob(M)
return TRUE
/datum/component/riding/proc/force_dismount(mob/living/M)
var/atom/movable/AM = parent
AM.unbuckle_mob(M)
/datum/component/riding/proc/handle_vehicle_offsets()
var/atom/movable/AM = parent
var/AM_dir = "[AM.dir]"
var/passindex = 0
if(AM.has_buckled_mobs())
for(var/m in AM.buckled_mobs)
passindex++
var/mob/living/buckled_mob = m
var/list/offsets = get_offsets(passindex)
var/rider_dir = get_rider_dir(passindex)
buckled_mob.setDir(rider_dir)
dir_loop:
for(var/offsetdir in offsets)
if(offsetdir == AM_dir)
var/list/diroffsets = offsets[offsetdir]
buckled_mob.pixel_x = diroffsets[1]
if(diroffsets.len >= 2)
buckled_mob.pixel_y = diroffsets[2]
if(diroffsets.len == 3)
buckled_mob.layer = diroffsets[3]
break dir_loop
var/list/static/default_vehicle_pixel_offsets = list(TEXT_NORTH = list(0, 0), TEXT_SOUTH = list(0, 0), TEXT_EAST = list(0, 0), TEXT_WEST = list(0, 0))
var/px = default_vehicle_pixel_offsets[AM_dir]
var/py = default_vehicle_pixel_offsets[AM_dir]
if(directional_vehicle_offsets[AM_dir])
if(isnull(directional_vehicle_offsets[AM_dir]))
px = AM.pixel_x
py = AM.pixel_y
else
px = directional_vehicle_offsets[AM_dir][1]
py = directional_vehicle_offsets[AM_dir][2]
AM.pixel_x = px
AM.pixel_y = py
/datum/component/riding/proc/set_vehicle_dir_offsets(dir, x, y)
directional_vehicle_offsets["[dir]"] = list(x, y)
//Override this to set your vehicle's various pixel offsets
/datum/component/riding/proc/get_offsets(pass_index) // list(dir = x, y, layer)
. = list(TEXT_NORTH = list(0, 0), TEXT_SOUTH = list(0, 0), TEXT_EAST = list(0, 0), TEXT_WEST = list(0, 0))
if(riding_offsets["[pass_index]"])
. = riding_offsets["[pass_index]"]
else if(riding_offsets["[RIDING_OFFSET_ALL]"])
. = riding_offsets["[RIDING_OFFSET_ALL]"]
/datum/component/riding/proc/set_riding_offsets(index, list/offsets)
if(!islist(offsets))
return FALSE
riding_offsets["[index]"] = offsets
//Override this to set the passengers/riders dir based on which passenger they are.
//ie: rider facing the vehicle's dir, but passenger 2 facing backwards, etc.
/datum/component/riding/proc/get_rider_dir(pass_index)
var/atom/movable/AM = parent
return AM.dir
//KEYS
/datum/component/riding/proc/keycheck(mob/user)
return !keytype || user.is_holding_item_of_type(keytype)
//BUCKLE HOOKS
/datum/component/riding/proc/restore_position(mob/living/buckled_mob)
if(buckled_mob)
buckled_mob.pixel_x = 0
buckled_mob.pixel_y = 0
if(buckled_mob.client)
buckled_mob.client.change_view(world.view)
//MOVEMENT
/datum/component/riding/proc/turf_check(turf/next, turf/current)
if(allowed_turf_typecache && !allowed_turf_typecache[next.type])
return (allow_one_away_from_valid_turf && allowed_turf_typecache[current.type])
else if(forbid_turf_typecache && forbid_turf_typecache[next.type])
return (allow_one_away_from_valid_turf && !forbid_turf_typecache[current.type])
return TRUE
/datum/component/riding/proc/handle_ride(mob/user, direction)
var/atom/movable/AM = parent
if(user.incapacitated())
Unbuckle(user)
return
if(world.time < next_vehicle_move)
return
next_vehicle_move = world.time + vehicle_move_delay
if(keycheck(user))
var/turf/next = get_step(AM, direction)
var/turf/current = get_turf(AM)
if(!istype(next) || !istype(current))
return //not happening.
if(!turf_check(next, current))
to_chat(user, "Your \the [AM] can not go onto [next]!")
return
if(!Process_Spacemove(direction) || !isturf(AM.loc))
return
step(AM, direction)
handle_vehicle_layer()
handle_vehicle_offsets()
else
to_chat(user, "<span class='notice'>You'll need the keys in one of your hands to [drive_verb] [AM].</span>")
/datum/component/riding/proc/Unbuckle(atom/movable/M)
addtimer(CALLBACK(parent, /atom/movable/.proc/unbuckle_mob, M), 0, TIMER_UNIQUE)
/datum/component/riding/proc/Process_Spacemove(direction)
var/atom/movable/AM = parent
return override_allow_spacemove || AM.has_gravity()
/datum/component/riding/proc/account_limbs(mob/living/M)
if(M.get_num_legs() < 2 && !slowed)
vehicle_move_delay = vehicle_move_delay + slowvalue
slowed = TRUE
else if(slowed)
vehicle_move_delay = vehicle_move_delay - slowvalue
slowed = FALSE
///////Yes, I said humans. No, this won't end well...//////////
/datum/component/riding/human
/datum/component/riding/human/Initialize()
. = ..()
RegisterSignal(COMSIG_HUMAN_MELEE_UNARMED_ATTACK, .proc/on_host_unarmed_melee)
/datum/component/riding/human/proc/on_host_unarmed_melee(atom/target)
var/mob/living/carbon/human/AM = parent
if(AM.a_intent == INTENT_DISARM && (target in AM.buckled_mobs))
force_dismount(target)
/datum/component/riding/human/handle_vehicle_layer()
var/atom/movable/AM = parent
if(AM.buckled_mobs && AM.buckled_mobs.len)
if(AM.dir == SOUTH)
AM.layer = ABOVE_MOB_LAYER
else
AM.layer = OBJ_LAYER
else
AM.layer = MOB_LAYER
/datum/component/riding/human/force_dismount(mob/living/user)
var/atom/movable/AM = parent
AM.unbuckle_mob(user)
user.Knockdown(60)
user.visible_message("<span class='warning'>[AM] pushes [user] off of them!</span>")
/datum/component/riding/cyborg
/datum/component/riding/cyborg/ride_check(mob/user)
var/atom/movable/AM = parent
if(user.incapacitated())
var/kick = TRUE
if(iscyborg(AM))
var/mob/living/silicon/robot/R = AM
if(R.module && R.module.ride_allow_incapacitated)
kick = FALSE
if(kick)
to_chat(user, "<span class='userdanger'>You fall off of [AM]!</span>")
Unbuckle(user)
return
if(iscarbon(user))
var/mob/living/carbon/carbonuser = user
if(!carbonuser.get_num_arms())
Unbuckle(user)
to_chat(user, "<span class='userdanger'>You can't grab onto [AM] with no hands!</span>")
return
/datum/component/riding/cyborg/handle_vehicle_layer()
var/atom/movable/AM = parent
if(AM.buckled_mobs && AM.buckled_mobs.len)
if(AM.dir == SOUTH)
AM.layer = ABOVE_MOB_LAYER
else
AM.layer = OBJ_LAYER
else
AM.layer = MOB_LAYER
/datum/component/riding/cyborg/get_offsets(pass_index) // list(dir = x, y, layer)
return list(TEXT_NORTH = list(0, 4), TEXT_SOUTH = list(0, 4), TEXT_EAST = list(-6, 3), TEXT_WEST = list( 6, 3))
/datum/component/riding/cyborg/handle_vehicle_offsets()
var/atom/movable/AM = parent
if(AM.has_buckled_mobs())
for(var/mob/living/M in AM.buckled_mobs)
M.setDir(AM.dir)
if(iscyborg(AM))
var/mob/living/silicon/robot/R = AM
if(istype(R.module))
M.pixel_x = R.module.ride_offset_x[dir2text(AM.dir)]
M.pixel_y = R.module.ride_offset_y[dir2text(AM.dir)]
else
..()
/datum/component/riding/cyborg/force_dismount(mob/living/M)
var/atom/movable/AM = parent
AM.unbuckle_mob(M)
var/turf/target = get_edge_target_turf(AM, AM.dir)
var/turf/targetm = get_step(get_turf(AM), AM.dir)
M.Move(targetm)
M.visible_message("<span class='warning'>[M] is thrown clear of [AM]!</span>")
M.throw_at(target, 14, 5, AM)
M.Knockdown(60)
/datum/component/riding/proc/equip_buckle_inhands(mob/living/carbon/human/user, amount_required = 1)
var/atom/movable/AM = parent
var/amount_equipped = 0
for(var/amount_needed = amount_required, amount_needed > 0, amount_needed--)
var/obj/item/riding_offhand/inhand = new /obj/item/riding_offhand(user)
inhand.rider = user
inhand.parent = AM
if(user.put_in_hands(inhand, TRUE))
amount_equipped++
else
break
if(amount_equipped >= amount_required)
return TRUE
else
unequip_buckle_inhands(user)
return FALSE
/datum/component/riding/proc/unequip_buckle_inhands(mob/living/carbon/user)
var/atom/movable/AM = parent
for(var/obj/item/riding_offhand/O in user.contents)
if(O.parent != AM)
CRASH("RIDING OFFHAND ON WRONG MOB")
continue
if(O.selfdeleting)
continue
else
qdel(O)
return TRUE
/obj/item/riding_offhand
name = "offhand"
icon = 'icons/obj/items_and_weapons.dmi'
icon_state = "offhand"
w_class = WEIGHT_CLASS_HUGE
flags_1 = ABSTRACT_1 | DROPDEL_1 | NOBLUDGEON_1
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
var/mob/living/carbon/rider
var/mob/living/parent
var/selfdeleting = FALSE
/obj/item/riding_offhand/dropped()
selfdeleting = TRUE
. = ..()
/obj/item/riding_offhand/equipped()
if(loc != rider)
selfdeleting = TRUE
qdel(src)
. = ..()
/obj/item/riding_offhand/Destroy()
var/atom/movable/AM = parent
if(selfdeleting)
if(rider in AM.buckled_mobs)
AM.unbuckle_mob(rider)
. = ..()
/datum/component/riding
var/next_vehicle_move = 0 //used for move delays
var/vehicle_move_delay = 2 //tick delay between movements, lower = faster, higher = slower
var/keytype
var/slowed = FALSE
var/slowvalue = 1
var/list/riding_offsets = list() //position_of_user = list(dir = list(px, py)), or RIDING_OFFSET_ALL for a generic one.
var/list/directional_vehicle_layers = list() //["[DIRECTION]"] = layer. Don't set it for a direction for default, set a direction to null for no change.
var/list/directional_vehicle_offsets = list() //same as above but instead of layer you have a list(px, py)
var/list/allowed_turf_typecache
var/list/forbid_turf_typecache //allow typecache for only certain turfs, forbid to allow all but those. allow only certain turfs will take precedence.
var/allow_one_away_from_valid_turf = TRUE //allow moving one tile away from a valid turf but not more.
var/override_allow_spacemove = FALSE
var/drive_verb = "drive"
var/ride_check_rider_incapacitated = FALSE
var/ride_check_rider_restrained = FALSE
var/ride_check_ridden_incapacitated = FALSE
/datum/component/riding/Initialize()
if(!ismovableatom(parent))
. = COMPONENT_INCOMPATIBLE
CRASH("RIDING COMPONENT ASSIGNED TO NON ATOM MOVABLE!")
RegisterSignal(COMSIG_MOVABLE_BUCKLE, .proc/vehicle_mob_buckle)
RegisterSignal(COMSIG_MOVABLE_UNBUCKLE, .proc/vehicle_mob_unbuckle)
RegisterSignal(COMSIG_MOVABLE_MOVED, .proc/vehicle_moved)
/datum/component/riding/proc/vehicle_mob_unbuckle(mob/living/M, force = FALSE)
restore_position(M)
unequip_buckle_inhands(M)
/datum/component/riding/proc/vehicle_mob_buckle(mob/living/M, force = FALSE)
handle_vehicle_offsets()
/datum/component/riding/proc/handle_vehicle_layer()
var/atom/movable/AM = parent
var/static/list/defaults = list(TEXT_NORTH = OBJ_LAYER, TEXT_SOUTH = ABOVE_MOB_LAYER, TEXT_EAST = ABOVE_MOB_LAYER, TEXT_WEST = ABOVE_MOB_LAYER)
. = defaults["[AM.dir]"]
if(directional_vehicle_layers["[AM.dir]"])
. = directional_vehicle_layers["[AM.dir]"]
if(isnull(.)) //you can set it to null to not change it.
. = AM.layer
AM.layer = .
/datum/component/riding/proc/set_vehicle_dir_layer(dir, layer)
directional_vehicle_layers["[dir]"] = layer
/datum/component/riding/proc/vehicle_moved()
var/atom/movable/AM = parent
for(var/i in AM.buckled_mobs)
ride_check(i)
handle_vehicle_offsets()
handle_vehicle_layer()
/datum/component/riding/proc/ride_check(mob/living/M)
var/atom/movable/AM = parent
var/mob/AMM = AM
if((ride_check_rider_restrained && M.restrained(TRUE)) || (ride_check_rider_incapacitated && M.incapacitated(FALSE, TRUE)) || (ride_check_ridden_incapacitated && istype(AMM) && AMM.incapacitated(FALSE, TRUE)))
AM.visible_message("<span class='warning'>[M] falls off of [AM]!</span>")
AM.unbuckle_mob(M)
return TRUE
/datum/component/riding/proc/force_dismount(mob/living/M)
var/atom/movable/AM = parent
AM.unbuckle_mob(M)
/datum/component/riding/proc/handle_vehicle_offsets()
var/atom/movable/AM = parent
var/AM_dir = "[AM.dir]"
var/passindex = 0
if(AM.has_buckled_mobs())
for(var/m in AM.buckled_mobs)
passindex++
var/mob/living/buckled_mob = m
var/list/offsets = get_offsets(passindex)
var/rider_dir = get_rider_dir(passindex)
buckled_mob.setDir(rider_dir)
dir_loop:
for(var/offsetdir in offsets)
if(offsetdir == AM_dir)
var/list/diroffsets = offsets[offsetdir]
buckled_mob.pixel_x = diroffsets[1]
if(diroffsets.len >= 2)
buckled_mob.pixel_y = diroffsets[2]
if(diroffsets.len == 3)
buckled_mob.layer = diroffsets[3]
break dir_loop
var/list/static/default_vehicle_pixel_offsets = list(TEXT_NORTH = list(0, 0), TEXT_SOUTH = list(0, 0), TEXT_EAST = list(0, 0), TEXT_WEST = list(0, 0))
var/px = default_vehicle_pixel_offsets[AM_dir]
var/py = default_vehicle_pixel_offsets[AM_dir]
if(directional_vehicle_offsets[AM_dir])
if(isnull(directional_vehicle_offsets[AM_dir]))
px = AM.pixel_x
py = AM.pixel_y
else
px = directional_vehicle_offsets[AM_dir][1]
py = directional_vehicle_offsets[AM_dir][2]
AM.pixel_x = px
AM.pixel_y = py
/datum/component/riding/proc/set_vehicle_dir_offsets(dir, x, y)
directional_vehicle_offsets["[dir]"] = list(x, y)
//Override this to set your vehicle's various pixel offsets
/datum/component/riding/proc/get_offsets(pass_index) // list(dir = x, y, layer)
. = list(TEXT_NORTH = list(0, 0), TEXT_SOUTH = list(0, 0), TEXT_EAST = list(0, 0), TEXT_WEST = list(0, 0))
if(riding_offsets["[pass_index]"])
. = riding_offsets["[pass_index]"]
else if(riding_offsets["[RIDING_OFFSET_ALL]"])
. = riding_offsets["[RIDING_OFFSET_ALL]"]
/datum/component/riding/proc/set_riding_offsets(index, list/offsets)
if(!islist(offsets))
return FALSE
riding_offsets["[index]"] = offsets
//Override this to set the passengers/riders dir based on which passenger they are.
//ie: rider facing the vehicle's dir, but passenger 2 facing backwards, etc.
/datum/component/riding/proc/get_rider_dir(pass_index)
var/atom/movable/AM = parent
return AM.dir
//KEYS
/datum/component/riding/proc/keycheck(mob/user)
return !keytype || user.is_holding_item_of_type(keytype)
//BUCKLE HOOKS
/datum/component/riding/proc/restore_position(mob/living/buckled_mob)
if(buckled_mob)
buckled_mob.pixel_x = 0
buckled_mob.pixel_y = 0
if(buckled_mob.client)
buckled_mob.client.change_view(CONFIG_GET(string/default_view))
//MOVEMENT
/datum/component/riding/proc/turf_check(turf/next, turf/current)
if(allowed_turf_typecache && !allowed_turf_typecache[next.type])
return (allow_one_away_from_valid_turf && allowed_turf_typecache[current.type])
else if(forbid_turf_typecache && forbid_turf_typecache[next.type])
return (allow_one_away_from_valid_turf && !forbid_turf_typecache[current.type])
return TRUE
/datum/component/riding/proc/handle_ride(mob/user, direction)
var/atom/movable/AM = parent
if(user.incapacitated())
Unbuckle(user)
return
if(world.time < next_vehicle_move)
return
next_vehicle_move = world.time + vehicle_move_delay
if(keycheck(user))
var/turf/next = get_step(AM, direction)
var/turf/current = get_turf(AM)
if(!istype(next) || !istype(current))
return //not happening.
if(!turf_check(next, current))
to_chat(user, "Your \the [AM] can not go onto [next]!")
return
if(!Process_Spacemove(direction) || !isturf(AM.loc))
return
step(AM, direction)
handle_vehicle_layer()
handle_vehicle_offsets()
else
to_chat(user, "<span class='notice'>You'll need the keys in one of your hands to [drive_verb] [AM].</span>")
/datum/component/riding/proc/Unbuckle(atom/movable/M)
addtimer(CALLBACK(parent, /atom/movable/.proc/unbuckle_mob, M), 0, TIMER_UNIQUE)
/datum/component/riding/proc/Process_Spacemove(direction)
var/atom/movable/AM = parent
return override_allow_spacemove || AM.has_gravity()
/datum/component/riding/proc/account_limbs(mob/living/M)
if(M.get_num_legs() < 2 && !slowed)
vehicle_move_delay = vehicle_move_delay + slowvalue
slowed = TRUE
else if(slowed)
vehicle_move_delay = vehicle_move_delay - slowvalue
slowed = FALSE
///////Yes, I said humans. No, this won't end well...//////////
/datum/component/riding/human
/datum/component/riding/human/Initialize()
. = ..()
RegisterSignal(COMSIG_HUMAN_MELEE_UNARMED_ATTACK, .proc/on_host_unarmed_melee)
/datum/component/riding/human/proc/on_host_unarmed_melee(atom/target)
var/mob/living/carbon/human/AM = parent
if(AM.a_intent == INTENT_DISARM && (target in AM.buckled_mobs))
force_dismount(target)
/datum/component/riding/human/handle_vehicle_layer()
var/atom/movable/AM = parent
if(AM.buckled_mobs && AM.buckled_mobs.len)
if(AM.dir == SOUTH)
AM.layer = ABOVE_MOB_LAYER
else
AM.layer = OBJ_LAYER
else
AM.layer = MOB_LAYER
/datum/component/riding/human/force_dismount(mob/living/user)
var/atom/movable/AM = parent
AM.unbuckle_mob(user)
user.Knockdown(60)
user.visible_message("<span class='warning'>[AM] pushes [user] off of them!</span>")
/datum/component/riding/cyborg
/datum/component/riding/cyborg/ride_check(mob/user)
var/atom/movable/AM = parent
if(user.incapacitated())
var/kick = TRUE
if(iscyborg(AM))
var/mob/living/silicon/robot/R = AM
if(R.module && R.module.ride_allow_incapacitated)
kick = FALSE
if(kick)
to_chat(user, "<span class='userdanger'>You fall off of [AM]!</span>")
Unbuckle(user)
return
if(iscarbon(user))
var/mob/living/carbon/carbonuser = user
if(!carbonuser.get_num_arms())
Unbuckle(user)
to_chat(user, "<span class='userdanger'>You can't grab onto [AM] with no hands!</span>")
return
/datum/component/riding/cyborg/handle_vehicle_layer()
var/atom/movable/AM = parent
if(AM.buckled_mobs && AM.buckled_mobs.len)
if(AM.dir == SOUTH)
AM.layer = ABOVE_MOB_LAYER
else
AM.layer = OBJ_LAYER
else
AM.layer = MOB_LAYER
/datum/component/riding/cyborg/get_offsets(pass_index) // list(dir = x, y, layer)
return list(TEXT_NORTH = list(0, 4), TEXT_SOUTH = list(0, 4), TEXT_EAST = list(-6, 3), TEXT_WEST = list( 6, 3))
/datum/component/riding/cyborg/handle_vehicle_offsets()
var/atom/movable/AM = parent
if(AM.has_buckled_mobs())
for(var/mob/living/M in AM.buckled_mobs)
M.setDir(AM.dir)
if(iscyborg(AM))
var/mob/living/silicon/robot/R = AM
if(istype(R.module))
M.pixel_x = R.module.ride_offset_x[dir2text(AM.dir)]
M.pixel_y = R.module.ride_offset_y[dir2text(AM.dir)]
else
..()
/datum/component/riding/cyborg/force_dismount(mob/living/M)
var/atom/movable/AM = parent
AM.unbuckle_mob(M)
var/turf/target = get_edge_target_turf(AM, AM.dir)
var/turf/targetm = get_step(get_turf(AM), AM.dir)
M.Move(targetm)
M.visible_message("<span class='warning'>[M] is thrown clear of [AM]!</span>")
M.throw_at(target, 14, 5, AM)
M.Knockdown(60)
/datum/component/riding/proc/equip_buckle_inhands(mob/living/carbon/human/user, amount_required = 1)
var/atom/movable/AM = parent
var/amount_equipped = 0
for(var/amount_needed = amount_required, amount_needed > 0, amount_needed--)
var/obj/item/riding_offhand/inhand = new /obj/item/riding_offhand(user)
inhand.rider = user
inhand.parent = AM
if(user.put_in_hands(inhand, TRUE))
amount_equipped++
else
break
if(amount_equipped >= amount_required)
return TRUE
else
unequip_buckle_inhands(user)
return FALSE
/datum/component/riding/proc/unequip_buckle_inhands(mob/living/carbon/user)
var/atom/movable/AM = parent
for(var/obj/item/riding_offhand/O in user.contents)
if(O.parent != AM)
CRASH("RIDING OFFHAND ON WRONG MOB")
continue
if(O.selfdeleting)
continue
else
qdel(O)
return TRUE
/obj/item/riding_offhand
name = "offhand"
icon = 'icons/obj/items_and_weapons.dmi'
icon_state = "offhand"
w_class = WEIGHT_CLASS_HUGE
flags_1 = ABSTRACT_1 | DROPDEL_1 | NOBLUDGEON_1
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
var/mob/living/carbon/rider
var/mob/living/parent
var/selfdeleting = FALSE
/obj/item/riding_offhand/dropped()
selfdeleting = TRUE
. = ..()
/obj/item/riding_offhand/equipped()
if(loc != rider)
selfdeleting = TRUE
qdel(src)
. = ..()
/obj/item/riding_offhand/Destroy()
var/atom/movable/AM = parent
if(selfdeleting)
if(rider in AM.buckled_mobs)
AM.unbuckle_mob(rider)
. = ..()
+37 -9
View File
@@ -104,15 +104,7 @@
else
atomsnowflake += "<b>[D]</b>"
var/formatted_type = "[type]"
if(length(formatted_type) > 25)
var/middle_point = length(formatted_type) / 2
var/splitpoint = findtext(formatted_type,"/",middle_point)
if(splitpoint)
formatted_type = "[copytext(formatted_type,1,splitpoint)]<br>[copytext(formatted_type,splitpoint)]"
else
formatted_type = "Type too long" //No suitable splitpoint (/) found.
var/formatted_type = replacetext("[type]", "/", "<wbr>/")
var/marked
if(holder && holder.marked_datum && holder.marked_datum == D)
marked = "<br><font size='1' color='red'><b>Marked Object</b></font>"
@@ -962,6 +954,42 @@
manipulate_organs(C)
href_list["datumrefresh"] = href_list["editorgans"]
else if(href_list["givetrauma"])
if(!check_rights(0))
return
var/mob/living/carbon/C = locate(href_list["givetrauma"]) in GLOB.mob_list
if(!istype(C))
to_chat(usr, "This can only be done to instances of type /mob/living/carbon")
return
var/list/traumas = subtypesof(/datum/brain_trauma)
var/result = input(usr, "Choose the brain trauma to apply","Traumatize") as null|anything in traumas
var/permanent = alert("Do you want to make the trauma unhealable?", "Permanently Traumatize", "Yes", "No")
if(!usr)
return
if(QDELETED(C))
to_chat(usr, "Mob doesn't exist anymore")
return
if(result)
C.gain_trauma(result, permanent)
href_list["datumrefresh"] = href_list["givetrauma"]
else if(href_list["curetraumas"])
if(!check_rights(0))
return
var/mob/living/carbon/C = locate(href_list["curetraumas"]) in GLOB.mob_list
if(!istype(C))
to_chat(usr, "This can only be done to instances of type /mob/living/carbon")
return
C.cure_all_traumas(TRUE, TRUE)
href_list["datumrefresh"] = href_list["curetraumas"]
else if(href_list["hallucinate"])
if(!check_rights(0))
return
@@ -54,8 +54,8 @@ Bonus
else
to_chat(M, "<span class='userdanger'>You can't think straight!</span>")
M.confused = min(100 * power, M.confused + 8)
if(brain_damage && M.getBrainLoss()<=80)
M.adjustBrainLoss(5 * power)
if(brain_damage)
M.adjustBrainLoss(3 * power, 80)
M.updatehealth()
return
@@ -27,7 +27,9 @@ Bonus
symptom_delay_max = 10
var/purge_alcohol = FALSE
var/brain_heal = FALSE
var/trauma_heal = FALSE
threshold_desc = "<b>Resistance 6:</b> Heals brain damage.<br>\
<b>Resistance 9:</b> Heals brain traumas.<br>\
<b>Transmission 8:</b> Purges alcohol in the bloodstream."
/datum/symptom/mind_restoration/Start(datum/disease/advance/A)
@@ -35,6 +37,8 @@ Bonus
return
if(A.properties["resistance"] >= 6) //heal brain damage
brain_heal = TRUE
if(A.properties["resistance"] >= 9) //heal brain traumas
trauma_heal = TRUE
if(A.properties["transmittable"] >= 8) //purge alcohol
purge_alcohol = TRUE
@@ -66,3 +70,9 @@ Bonus
if(brain_heal && A.stage >= 5)
M.adjustBrainLoss(-3)
if(trauma_heal && iscarbon(M))
var/mob/living/carbon/C = M
if(prob(30) && C.has_trauma_type(BRAIN_TRAUMA_SPECIAL))
C.cure_trauma_type(BRAIN_TRAUMA_SPECIAL)
if(prob(10) && C.has_trauma_type(BRAIN_TRAUMA_MILD))
C.cure_trauma_type(BRAIN_TRAUMA_MILD)
+5 -5
View File
@@ -24,15 +24,15 @@
if(prob(2))
to_chat(affected_mob, "<span class='danger'>You don't feel like yourself.</span>")
if(prob(5))
affected_mob.adjustBrainLoss(1)
affected_mob.adjustBrainLoss(1, 170)
affected_mob.updatehealth()
if(3)
if(prob(2))
affected_mob.emote("stare")
if(prob(2))
affected_mob.emote("drool")
if(prob(10) && affected_mob.getBrainLoss()<=98)//shouldn't retard you to death now
affected_mob.adjustBrainLoss(2)
if(prob(10))
affected_mob.adjustBrainLoss(2, 170)
affected_mob.updatehealth()
if(prob(2))
to_chat(affected_mob, "<span class='danger'>Your try to remember something important...but can't.</span>")
@@ -42,8 +42,8 @@
affected_mob.emote("stare")
if(prob(2))
affected_mob.emote("drool")
if(prob(15) && affected_mob.getBrainLoss()<=98) //shouldn't retard you to death now
affected_mob.adjustBrainLoss(3)
if(prob(15))
affected_mob.adjustBrainLoss(3, 170)
affected_mob.updatehealth()
if(prob(2))
to_chat(affected_mob, "<span class='danger'>Strange buzzing fills your head, removing all thoughts.</span>")
+1 -1
View File
@@ -58,7 +58,7 @@
"<span class='userdanger'>[A] kicks your head, knocking you out!</span>")
playsound(get_turf(A), 'sound/weapons/genhit1.ogg', 50, 1, -1)
D.SetSleeping(300)
D.adjustBrainLoss(25)
D.adjustBrainLoss(15, 150)
return 1
/datum/martial_art/cqc/proc/Pressure(mob/living/carbon/human/A, mob/living/carbon/human/D)
+68
View File
@@ -0,0 +1,68 @@
/datum/martial_art/psychotic_brawling
name = "Psychotic Brawling"
/datum/martial_art/psychotic_brawling/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
return psycho_attack(A,D)
/datum/martial_art/psychotic_brawling/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
return psycho_attack(A,D)
/datum/martial_art/psychotic_brawling/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
return psycho_attack(A,D)
/datum/martial_art/psychotic_brawling/proc/psycho_attack(mob/living/carbon/human/A, mob/living/carbon/human/D)
var/atk_verb
switch(rand(1,8))
if(1)
D.help_shake_act(A)
atk_verb = "helped"
if(2)
A.emote("cry")
A.Stun(20)
atk_verb = "cried looking at"
if(3)
if(A.grab_state >= GRAB_AGGRESSIVE)
D.grabbedby(A, 1)
else
A.start_pulling(D, 1)
if(A.pulling)
D.drop_all_held_items()
D.stop_pulling()
if(A.a_intent == INTENT_GRAB)
add_logs(A, D, "grabbed", addition="aggressively")
D.visible_message("<span class='warning'>[A] violently grabs [D]!</span>", \
"<span class='userdanger'>[A] violently grabs you!</span>")
A.grab_state = GRAB_AGGRESSIVE //Instant aggressive grab
else
add_logs(A, D, "grabbed", addition="passively")
A.grab_state = GRAB_PASSIVE
if(4)
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
atk_verb = "headbutts"
D.visible_message("<span class='danger'>[A] [atk_verb] [D]!</span>", \
"<span class='userdanger'>[A] [atk_verb] you!</span>")
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 40, 1, -1)
D.apply_damage(rand(5,10), BRUTE, "head")
A.apply_damage(rand(5,10), BRUTE, "head")
if(!istype(A.head,/obj/item/clothing/head/helmet/) && !istype(A.head,/obj/item/clothing/head/hardhat))
A.adjustBrainLoss(5)
if(!istype(D.head,/obj/item/clothing/head/helmet/) && !istype(D.head,/obj/item/clothing/head/hardhat))
D.adjustBrainLoss(5)
A.Stun(rand(5,30))
D.Stun(rand(5,30))
if(5,6)
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
atk_verb = pick("punches", "kicks", "hits", "slams into")
D.visible_message("<span class='danger'>[A] [atk_verb] [D] with inhuman strength, sending [D.p_them()] flying backwards!</span>", \
"<span class='userdanger'>[A] [atk_verb] you with inhuman strength, sending you flying backwards!</span>")
D.apply_damage(rand(15,30), BRUTE)
playsound(get_turf(D), 'sound/effects/meteorimpact.ogg', 25, 1, -1)
var/throwtarget = get_edge_target_turf(A, get_dir(A, get_step_away(D, A)))
D.throw_at(throwtarget, 4, 2, A)//So stuff gets tossed around at the same time.
D.Knockdown(60)
if(7,8)
basic_hit(A,D)
if(atk_verb)
add_logs(A, D, "[atk_verb] (Psychotic Brawling)")
return 1
+1 -1
View File
@@ -240,7 +240,7 @@
H.visible_message("<span class='warning'>[user] delivers a heavy hit to [H]'s head, knocking them out cold!</span>", \
"<span class='userdanger'>[user] knocks you unconscious!</span>")
H.SetSleeping(600)
H.adjustBrainLoss(25)
H.adjustBrainLoss(15, 150)
else
return ..()
+1 -1
View File
@@ -299,7 +299,7 @@
to_chat(traitor_mob, "Unfortunately, [employer] wasn't able to get you an Uplink.")
. = 0
else
uplink_loc.LoadComponent(/datum/component/uplink, traitor_mob.key)
uplink_loc.AddComponent(/datum/component/uplink, traitor_mob.key)
if(uplink_loc == R)
R.traitor_frequency = sanitize_frequency(rand(MIN_FREQ, MAX_FREQ))
+4 -4
View File
@@ -95,13 +95,13 @@
return trim(message)
/datum/mutation/human/unintelligable
name = "Unintelligable"
/datum/mutation/human/unintelligible
name = "Unintelligible"
quality = NEGATIVE
text_gain_indication = "<span class='danger'>You can't seem to form any coherent thoughts!</span>"
text_lose_indication = "<span class='danger'>Your mind feels more clear.</span>"
/datum/mutation/human/unintelligable/say_mod(message)
/datum/mutation/human/unintelligible/say_mod(message)
if(message)
var/prefix=copytext(message,1,2)
if(prefix == ";")
@@ -123,7 +123,7 @@
suffix = copytext(cword,length(cword)-1,length(cword) )
if(length(cword))
rearranged += cword
message = "[prefix][uppertext(jointext(rearranged," "))]!!"
message ="[prefix][jointext(rearranged," ")]"
return message
+1
View File
@@ -171,6 +171,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
/area/maintenance/department/science/xenobiology
name = "Xenobiology Maintenance"
icon_state = "xenomaint"
xenobiology_compatible = TRUE
//Maintenance - Generic
+1
View File
@@ -61,6 +61,7 @@
var/list/cameras
var/list/firealarms
var/firedoors_last_closed_on = 0
var/xenobiology_compatible = FALSE //Can the Xenobio management console transverse this area by default?
/*Adding a wizard area teleport list because motherfucking lag -- Urist*/
/*I am far too lazy to make it a proper list of areas so I'll just make it run the usual telepot routine at the start of the game*/
+36 -19
View File
@@ -44,10 +44,10 @@ Credit where due:
// PROCS //
///////////
/proc/is_servant_of_ratvar(mob/living/M)
/proc/is_servant_of_ratvar(mob/M)
return istype(M) && M.mind && M.mind.has_antag_datum(ANTAG_DATUM_CLOCKCULT)
/proc/is_eligible_servant(mob/living/M)
/proc/is_eligible_servant(mob/M)
if(!istype(M))
return FALSE
if(M.mind)
@@ -61,11 +61,11 @@ Credit where due:
return FALSE
if(iscultist(M) || isconstruct(M) || M.isloyal() || ispAI(M))
return FALSE
if(ishuman(M) || isbrain(M) || isguardian(M) || issilicon(M) || isclockmob(M) || istype(M, /mob/living/simple_animal/drone/cogscarab))
if(ishuman(M) || isbrain(M) || isguardian(M) || issilicon(M) || isclockmob(M) || istype(M, /mob/living/simple_animal/drone/cogscarab) || istype(M, /mob/camera/eminence))
return TRUE
return FALSE
/proc/add_servant_of_ratvar(mob/living/L, silent = FALSE)
/proc/add_servant_of_ratvar(mob/L, silent = FALSE)
if(!L || !L.mind)
return
var/update_type = ANTAG_DATUM_CLOCKCULT
@@ -73,7 +73,7 @@ Credit where due:
update_type = ANTAG_DATUM_CLOCKCULT_SILENT
. = L.mind.add_antag_datum(update_type)
/proc/remove_servant_of_ratvar(mob/living/L, silent = FALSE)
/proc/remove_servant_of_ratvar(mob/L, silent = FALSE)
if(!L || !L.mind)
return
var/datum/antagonist/clockcult/clock_datum = L.mind.has_antag_datum(ANTAG_DATUM_CLOCKCULT)
@@ -88,6 +88,7 @@ Credit where due:
///////////////
/datum/game_mode
var/datum/mind/eminence //The clockwork Eminence
var/list/servants_of_ratvar = list() //The Enlightened servants of Ratvar
var/clockwork_explanation = "Defend the Ark of the Clockwork Justiciar and free Ratvar." //The description of the current objective
@@ -176,7 +177,7 @@ Credit where due:
if(!S.forceMove(get_turf(L)))
qdel(S)
if(S && !QDELETED(S))
to_chat(L, "<span class='bold large_brass'>There is a paper in your backpack! Read it!</span>")
to_chat(L, "<span class='bold large_brass'>There is a paper in your backpack! It'll tell you if anything's changed, as well as what to expect.</span>")
to_chat(L, "<span class='alloy'>[slot] is a <b>clockwork slab</b>, a multipurpose tool used to construct machines and invoke ancient words of power. If this is your first time \
as a servant, you can find a concise tutorial in the Recollection category of its interface.</span>")
to_chat(L, "<span class='alloy italics'>If you want more information, you can find a wiki link here!</span> https://tgstation13.org/wiki/Clockwork_Cult")
@@ -202,11 +203,12 @@ Credit where due:
return //Doesn't end until the round does
/datum/game_mode/clockwork_cult/generate_report()
return "We have lost contact with multiple stations in your sector. They have gone dark and do not respond to all transmissions, although they appear intact and the crew's life \
signs remain uninterrupted. Those that have managed to send a transmission or have had some of their crew escape tell tales of a machine cult creating sapient automatons and seeking \
to brainwash the crew to summon their god, Ratvar. If evidence of this cult is dicovered aboard your station, extreme caution and extreme vigilance must be taken going forward, and \
all resources should be devoted to stopping this cult. Note that holy water seems to weaken and eventually return the minds of cultists that ingest it, and mindshield implants will \
prevent conversion altogether."
return "Bluespace monitors near your sector have detected a continuous stream of patterned fluctuations since the station was completed. It is most probable that a powerful entity \
from a very far distance away is using to the station as a vector to cross that distance through bluespace. The theoretical power required for this would be monumental, and if \
the entity is hostile, it would need to rely on a single central power source - disrupting or destroying that power source would be the best way to prevent said entity from causing \
harm to company personnel or property.<br><br>Keep a sharp on any crew that appear to be oddly-dressed or using what appear to be magical powers, as these crew may be defectors \
working for this entity and utilizing highly-advanced technology to cross the great distance at will. If they should turn out to be a credible threat, the task falls on you and \
your crew to dispatch it in a timely manner."
/datum/game_mode/proc/auto_declare_completion_clockwork_cult()
var/text = ""
@@ -224,9 +226,11 @@ Credit where due:
for(var/i in SSticker.scripture_states)
if(i != SCRIPTURE_DRIVER)
text += "<br><b>[i] scripture</b> was: <b>[SSticker.scripture_states[i] ? "UN":""]LOCKED</b>"
if(SSticker.mode.eminence)
text += "<br><b>The Eminence was:</b> [printplayer(SSticker.mode.eminence)]"
if(servants_of_ratvar.len)
text += "<br><b>Ratvar's servants were:</b>"
for(var/datum/mind/M in servants_of_ratvar)
for(var/datum/mind/M in servants_of_ratvar - SSticker.mode.eminence)
text += printplayer(M)
to_chat(world, text)
@@ -246,14 +250,14 @@ Credit where due:
/datum/outfit/servant_of_ratvar
name = "Servant of Ratvar"
uniform = /obj/item/clothing/under/chameleon/ratvar
shoes = /obj/item/clothing/shoes/workboots
shoes = /obj/item/clothing/shoes/sneakers/black
back = /obj/item/storage/backpack
ears = /obj/item/device/radio/headset
gloves = /obj/item/clothing/gloves/color/yellow
belt = /obj/item/storage/belt/utility/servant
backpack_contents = list(/obj/item/storage/box/engineer = 1, \
/obj/item/clockwork/replica_fabricator = 1, /obj/item/stack/tile/brass/fifty = 1, /obj/item/paper/servant_primer = 1)
id = /obj/item/card/id
id = /obj/item/device/pda
var/plasmaman //We use this to determine if we should activate internals in post_equip()
/datum/outfit/servant_of_ratvar/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
@@ -265,7 +269,8 @@ Credit where due:
plasmaman = TRUE
/datum/outfit/servant_of_ratvar/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
var/obj/item/card/id/W = H.wear_id
var/obj/item/card/id/W = new(H)
var/obj/item/device/pda/PDA = H.wear_id
W.assignment = "Assistant"
W.access += ACCESS_MAINT_TUNNELS
W.registered_name = H.real_name
@@ -273,8 +278,15 @@ Credit where due:
if(plasmaman && !visualsOnly) //If we need to breathe from the plasma tank, we should probably start doing that
H.internal = H.get_item_for_held_index(2)
H.update_internals_hud_icon(1)
PDA.owner = H.real_name
PDA.ownjob = "Assistant"
PDA.update_label()
PDA.id_check(H, W)
H.sec_hud_set_ID()
//This paper serves as a quick run-down to the cult as well as a changelog to refer to.
//Check strings/clockwork_cult_changelog.txt for the changelog, and update it when you can!
/obj/item/paper/servant_primer
name = "The Ark And You: A Primer On Servitude"
color = "#DAAA18"
@@ -304,14 +316,19 @@ Credit where due:
<hr>\
<h2>Things that have changed:</h2>\
<ul>\
<li><b><i>Scripture no longer requires components, and instead uses power.</i></b></li>\
<li>Added a <b>5-minute grace period</b> for the crew to prepare for the assault when the Ark activates.</li>\
<li>Script and Application scriptures can now be unlocked with enough power.</li>\
<li><b>Added the Hateful Manacles scripture</b>, which handcuffs targets!</li>\
CLOCKCULTCHANGELOG\
</ul>\
<hr>\
<b>Good luck!</b>"
/obj/item/paper/servant_primer/Initialize()
. = ..()
var/changelog = world.file2list("strings/clockwork_cult_changelog.txt")
var/changelog_contents = ""
for(var/entry in changelog)
changelog_contents += "<li>[entry]</li>"
info = replacetext(info, "CLOCKCULTCHANGELOG", changelog_contents)
/obj/item/paper/servant_primer/examine(mob/user)
if(!is_servant_of_ratvar(user) && !isobserver(user))
to_chat(user, "<span class='danger'>You can't understand any of the words on [src].</span>")
@@ -43,7 +43,9 @@
//changes construction value
/proc/change_construction_value(amount)
GLOB.clockwork_construction_value += amount
if(!SSticker.current_state != GAME_STATE_PLAYING) //This is primarily so that structures added pre-roundstart don't contribute to construction value
return
GLOB.clockwork_construction_value = max(0, GLOB.clockwork_construction_value + amount)
/proc/can_recite_scripture(mob/living/L, can_potentially)
return (is_servant_of_ratvar(L) && (can_potentially || (L.stat == CONSCIOUS && L.can_speak_vocal())) && (GLOB.ratvar_awakens || (ishuman(L) || issilicon(L))))
@@ -65,7 +65,8 @@
/obj/item/restraints/handcuffs/clockwork
name = "replicant manacles"
desc = "Cold, heavy manacles made out of some strange black metal."
desc = "Heavy manacles made out of freezing-cold metal. It looks like brass, but feels much more solid."
icon_state = "brass_manacles"
origin_tech = "materials=2;magnets=5"
flags_1 = DROPDEL_1
@@ -1,23 +1,31 @@
/obj/item/clockwork/slab //Clockwork slab: The most important tool in Ratvar's arsenal. Allows scripture recital, tutorials, and generates components.
name = "clockwork slab"
desc = "A strange metal tablet. A clock in the center turns around and around."
clockwork_desc = "A link between you and the Celestial Derelict. It contains information, recites scripture, and is your most vital tool as a Servant."
clockwork_desc = "A link between you and the Celestial Derelict. It contains information, recites scripture, and is your most vital tool as a Servant.<br>\
It can be used to link traps and triggers by attacking them with the slab. Keep in mind that traps linked with one another will activate in tandem!"
icon_state = "dread_ipad"
lefthand_file = 'icons/mob/inhands/antag/clockwork_lefthand.dmi'
righthand_file = 'icons/mob/inhands/antag/clockwork_righthand.dmi'
var/inhand_overlay //If applicable, this overlay will be applied to the slab's inhand
slot_flags = SLOT_BELT
w_class = WEIGHT_CLASS_SMALL
var/busy //If the slab is currently being used by something
var/no_cost = FALSE //If the slab is admin-only and needs no components and has no scripture locks
var/speed_multiplier = 1 //multiples how fast this slab recites scripture
var/selected_scripture = SCRIPTURE_DRIVER
var/recollecting = FALSE //if we're looking at fancy recollection
var/obj/effect/proc_holder/slab/slab_ability //the slab's current bound ability, for certain scripture
var/recollecting = FALSE //if we're looking at fancy recollection
var/recollection_category = "Default"
var/list/quickbound = list(/datum/clockwork_scripture/abscond, \
/datum/clockwork_scripture/ranged_ability/kindle, /datum/clockwork_scripture/ranged_ability/hateful_manacles) //quickbound scripture, accessed by index
var/maximum_quickbound = 5 //how many quickbound scriptures we can have
var/recollection_category = "Default"
var/obj/structure/destructible/clockwork/trap/linking //If we're linking traps together, which ones we're doing
/obj/item/clockwork/slab/internal //an internal motor for mobs running scripture
name = "scripture motor"
@@ -34,8 +42,7 @@
add_servant_of_ratvar(user)
/obj/item/clockwork/slab/cyborg //three scriptures, plus a spear and fabricator
clockwork_desc = "A divine link to the Celestial Derelict, allowing for limited recital of scripture.\n\
Hitting a slab, a Servant with a slab, or a cache will <b>transfer</b> this slab's components into the target, the target's slab, or the global cache, respectively."
clockwork_desc = "A divine link to the Celestial Derelict, allowing for limited recital of scripture."
quickbound = list(/datum/clockwork_scripture/ranged_ability/judicial_marker, /datum/clockwork_scripture/ranged_ability/linked_vanguard, \
/datum/clockwork_scripture/create_object/stargazer)
maximum_quickbound = 6 //we usually have one or two unique scriptures, so if ratvar is up let us bind one more
@@ -46,7 +53,7 @@
/obj/item/clockwork/slab/cyborg/medical //five scriptures, plus a spear
quickbound = list(/datum/clockwork_scripture/abscond, /datum/clockwork_scripture/ranged_ability/linked_vanguard, /datum/clockwork_scripture/ranged_ability/sentinels_compromise, \
/datum/clockwork_scripture/create_object/vitality_matrix, /datum/clockwork_scripture/channeled/mending_mantra)
/datum/clockwork_scripture/create_object/vitality_matrix)
/obj/item/clockwork/slab/cyborg/security //twoscriptures, plus a spear
quickbound = list(/datum/clockwork_scripture/abscond, /datum/clockwork_scripture/ranged_ability/hateful_manacles, /datum/clockwork_scripture/ranged_ability/judicial_marker)
@@ -153,6 +160,11 @@
return 0
access_display(user)
/obj/item/clockwork/slab/AltClick(mob/living/user)
if(is_servant_of_ratvar(user) && linking)
linking = null
to_chat(user, "<span class='notice'>Object link canceled.</span>")
/obj/item/clockwork/slab/proc/access_display(mob/living/user)
if(!is_servant_of_ratvar(user))
return FALSE
@@ -410,7 +422,10 @@
data["tier_info"] = "<font color=#B18B25><i>Unlock these optional scriptures by converting another servant or if [DisplayPower(APPLICATION_UNLOCK_THRESHOLD)] of power is reached..</i></font>"
data["selected"] = selected_scripture
data["scripturecolors"] = "<font color=#DAAA18>Scriptures in <b>yellow</b> are related to construction and building.</font><br>\
<font color=#6E001A>Scriptures in <b>red</b> are related to attacking and offense.</font><br>\
<font color=#1E8CE1>Scriptures in <b>blue</b> are related to healing and defense.</font><br>\
<font color=#AF0AAF>Scriptures in <b>purple</b> are niche but still important!</font>"
generate_all_scripture()
data["scripture"] = list()
@@ -184,7 +184,7 @@
sleep(13)
name = "judicial explosion"
var/targetsjudged = 0
playsound(src, 'sound/effects/explosionfar.ogg', 100, 1, 1, 1)
playsound(src, 'sound/effects/explosion_distant.ogg', 100, 1, 1, 1)
set_light(0)
for(var/mob/living/L in range(1, src))
if(is_servant_of_ratvar(L))
@@ -0,0 +1,264 @@
//The Eminence is a unique mob that functions like the leader of the cult. It's incorporeal but can interact with the world in several ways.
/mob/camera/eminence
name = "\the Emininence"
real_name = "\the Eminence"
desc = "The leader-elect of the servants of Ratvar."
icon = 'icons/effects/clockwork_effects.dmi'
icon_state = "eminence"
mouse_opacity = MOUSE_OPACITY_OPAQUE
move_on_shuttle = TRUE
see_in_dark = 8
invisibility = INVISIBILITY_OBSERVER
layer = FLY_LAYER
faction = list("ratvar")
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
var/static/superheated_walls = 0
/mob/camera/eminence/Initialize()
if(SSticker.mode.eminence)
return INITIALIZE_HINT_QDEL
. = ..()
/mob/camera/eminence/Destroy(force)
if(!force && mind && SSticker.mode.eminence == mind)
return QDEL_HINT_LETMELIVE
return ..()
/mob/camera/eminence/CanPass(atom/movable/mover, turf/target)
return TRUE
/mob/camera/eminence/Move(NewLoc, direct)
var/OldLoc = loc
if(NewLoc && !istype(NewLoc, /turf/open/indestructible/reebe_void))
forceMove(get_turf(NewLoc))
Moved(OldLoc, direct)
if(GLOB.ratvar_awakens)
for(var/turf/T in range(5, src))
if(prob(166 - (get_dist(src, T) * 33)))
T.ratvar_act() //Causes moving to leave a swath of proselytized area behind the Eminence
/mob/camera/eminence/Login()
..()
add_servant_of_ratvar(src, TRUE)
to_chat(src, "<span class='bold large_brass'>You have been selected as the Eminence!</span>")
to_chat(src, "<span class='brass'>As the Eminence, you lead the servants. Anything you say will be heard by the entire cult.</span>")
to_chat(src, "<span class='brass'>Though you can move through walls, you're also incorporeal, and largely can't interact with the world except for a few ways.</span>")
to_chat(src, "<span class='brass'>Additionally, unless the herald's beacon is activated, you can't understand any speech while away from Reebe.</span>")
SSticker.mode.eminence = mind
eminence_help()
for(var/V in actions)
var/datum/action/A = V
A.Remove(src) //So we get rid of duplicate actions; this also removes Hierophant network, since our say() goes across it anyway
var/datum/action/innate/eminence/E
for(var/V in subtypesof(/datum/action/innate/eminence))
E = new V
E.Grant(src)
/mob/camera/eminence/say(message)
message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
if(!message)
return
log_talk(src, "[key_name(src)] : [message]", LOGSAY)
if(GLOB.ratvar_awakens)
visible_message("<span class='brass'><b>You feel light slam into your mind and form words:</b> \"[capitalize(message)]\"</span>")
playsound(src, 'sound/machines/clockcult/ark_scream.ogg', 50, FALSE)
hierophant_message("<span class='large_brass'><b>The Eminence:</b> \"[message]\"</span>")
/mob/camera/eminence/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
if(z == ZLEVEL_CITYOFCOGS || is_servant_of_ratvar(speaker) || GLOB.ratvar_approaches || GLOB.ratvar_awakens) //Away from Reebe, the Eminence can't hear anything
to_chat(src, message)
return
to_chat(src, "<i>[speaker] says something, but you can't understand any of it...</i>")
/mob/camera/eminence/ClickOn(atom/A, params)
var/list/modifiers = params2list(params)
if(modifiers["shift"])
A.examine(src)
return
if(modifiers["alt"] && istype(A, /turf/closed/wall/clockwork))
superheat_wall(A)
return
if(modifiers["middle"] || modifiers["ctrl"])
issue_command(A)
return
if(GLOB.ark_of_the_clockwork_justiciar == A)
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
if(G.recalling)
return
if(!G.recalls_remaining)
to_chat(src, "<span class='warning'>The Ark can no longer recall!</span>")
return
if(alert(src, "Initiate mass recall?", "Mass Recall", "Yes", "No") != "Yes" || QDELETED(src) || QDELETED(G) || !G.obj_integrity)
return
G.initiate_mass_recall() //wHOOPS LOOKS LIKE A HULK GOT THROUGH
else if(istype(A, /obj/structure/destructible/clockwork/trap/trigger))
var/obj/structure/destructible/clockwork/trap/trigger/T = A
T.visible_message("<span class='danger'>[T] clunks as it's activated remotely.</span>")
to_chat(src, "<span class='brass'>You activate [T].</span>")
T.activate()
/mob/camera/eminence/ratvar_act()
name = "\improper Radiance"
real_name = "\improper Radiance"
desc = "The light, forgotten."
transform = matrix() * 2
invisibility = SEE_INVISIBLE_MINIMUM
/mob/camera/eminence/proc/issue_command(atom/movable/A)
var/list/commands
var/atom/movable/command_location
if(A == src)
commands = list("Defend the Ark!", "Advance!", "Retreat!", "Generate Power", "Build Defenses (Bottom-Up)", "Build Defenses (Top-Down)")
else
command_location = A
commands = list("Rally Here", "Regroup Here", "Avoid This Area", "Reinforce This Area")
if(istype(A, /obj/structure/destructible/clockwork/powered))
var/obj/structure/destructible/clockwork/powered/P = A
if(!can_access_clockwork_power(P))
commands += "Power This Structure"
if(P.obj_integrity < P.max_integrity)
commands += "Repair This Structure"
var/roma_invicta = input(src, "Choose a command to issue to your cult!", "Issue Commands") as null|anything in commands
if(!roma_invicta)
return
var/command_text = ""
var/marker_icon
switch(roma_invicta)
if("Rally Here")
command_text = "The Eminence orders an offensive rally at [command_location] to the GETDIR!"
marker_icon = "eminence_rally"
if("Regroup Here")
command_text = "The Eminence orders a regroup to [command_location] to the GETDIR!"
marker_icon = "eminence_rally"
if("Avoid This Area")
command_text = "The Eminence has designated the area to your GETDIR as dangerous and to be avoided!"
marker_icon = "eminence_avoid"
if("Reinforce This Area")
command_text = "The Eminence orders the defense and fortification of the area to your GETDIR!"
marker_icon = "eminence_reinforce"
if("Power This Structure")
command_text = "[command_location] to your GETDIR has no power! Turn it on and make sure there's a sigil of transmission nearby!"
marker_icon = "eminence_unlimited_power"
if("Repair This Structure")
command_text = "The Eminence orders that [command_location] to your GETDIR should be repaired ASAP!"
marker_icon = "eminence_repair"
if("Defend the Ark!")
command_text = "The Eminence orders immediate defense of the Ark!"
if("Advance!")
command_text = "The Eminence commands you push forward!"
if("Retreat!")
command_text = "The Eminence has sounded the retreat! Fall back!"
if("Generate Power")
command_text = "The Eminence orders more power! Build power generations on the station!"
if("Build Defenses (Bottom-Up)")
command_text = "The Eminence orders that defenses should be built starting from the bottom of Reebe!"
if("Build Defenses (Top-Down)")
command_text = "The Eminence orders that defenses should be built starting from the top of Reebe!"
if(marker_icon)
new/obj/effect/temp_visual/ratvar/command_point(get_turf(A), marker_icon)
for(var/mob/M in servants_and_ghosts())
to_chat(M, "<span class='large_brass'>[replacetext(command_text, "GETDIR", dir2text(get_dir(M, command_location)))]</span>")
M.playsound_local(M, 'sound/machines/clockcult/eminence_command.ogg', 75, FALSE, pressure_affected = FALSE)
else
hierophant_message("<span class='bold large_brass'>[command_text]</span>")
for(var/mob/M in servants_and_ghosts())
M.playsound_local(M, 'sound/machines/clockcult/eminence_command.ogg', 75, FALSE, pressure_affected = FALSE)
/mob/camera/eminence/proc/superheat_wall(turf/closed/wall/clockwork/wall)
if(!istype(wall))
return
if(superheated_walls >= SUPERHEATED_CLOCKWORK_WALL_LIMIT && !wall.heated)
to_chat(src, "<span class='warning'>You're exerting all of your power superheating this many walls already! Cool some down first!</span>")
return
wall.turn_up_the_heat()
if(wall.heated)
superheated_walls++
to_chat(src, "<span class='neovgre_small'>You superheat [wall]. <b>Superheated walls:</b> [superheated_walls]/[SUPERHEATED_CLOCKWORK_WALL_LIMIT]")
else
superheated_walls--
to_chat(src, "<span class='neovgre_small'>You cool [wall]. <b>Superheated walls:</b> [superheated_walls]/[SUPERHEATED_CLOCKWORK_WALL_LIMIT]")
/mob/camera/eminence/proc/eminence_help()
to_chat(src, "<span class='bold alloy'>You can make use of certain shortcuts to perform different actions:</span>")
to_chat(src, "<span class='alloy'><b>Alt-Click a clockwork wall</b> to superheat or cool it down. \
Superheated walls can't be destroyed by hulks or mechs and are much slower to deconstruct, and are marked by a bright red glow. \
This lasts indefinitely, but only [SUPERHEATED_CLOCKWORK_WALL_LIMIT] clockwork walls can be superheated at once.</span>")
to_chat(src, "<span class='alloy'><b>Interact with the Ark</b> to initiate an emergency recall that teleports all servants directly to its location after a short delay. \
This can only be used a single time, or twice if the herald's beacon was activated,</span>")
to_chat(src, "<span class='alloy'><b>Middle or Ctrl-Click anywhere</b> to allow you to issue a variety of contextual commands to your cult. Different objects allow for different \
commands. <i>Doing this on yourself will provide commands that tell the entire cult a goal.</i></span>")
//Eminence actions below this point
/datum/action/innate/eminence
name = "Eminence Action"
desc = "You shouldn't see this. File a bug report!"
icon_icon = 'icons/mob/actions/actions_clockcult.dmi'
background_icon_state = "bg_clock"
buttontooltipstyle = "clockcult"
/datum/action/innate/eminence/IsAvailable()
if(!iseminence(owner))
qdel(src)
return
return ..()
//Lists available powers
/datum/action/innate/eminence/power_list
name = "Eminence Powers"
desc = "Forgot what you can do? This refreshes you on your powers as Eminence."
button_icon_state = "eminence_rally"
/datum/action/innate/eminence/power_list/Activate()
var/mob/camera/eminence/E = owner
E.eminence_help()
//Returns to the Ark
/datum/action/innate/eminence/ark_jump
name = "Return to Ark"
desc = "Warps you to the Ark."
button_icon_state = "Abscond"
/datum/action/innate/eminence/ark_jump/Activate()
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
if(G)
owner.forceMove(get_turf(G))
owner.playsound_local(owner, 'sound/magic/magic_missile.ogg', 50, TRUE)
flash_color(owner, flash_color = "#AF0AAF", flash_time = 25)
else
to_chat(owner, "<span class='warning'>There is no Ark!</span>")
//Warps to the Station
/datum/action/innate/eminence/station_jump
name = "Warp to Station"
desc = "Warps to Space Station 13. You cannot hear anything while there!</span>"
button_icon_state = "warp_down"
/datum/action/innate/eminence/station_jump/Activate()
if(owner.z == ZLEVEL_CITYOFCOGS)
owner.forceMove(get_turf(pick(GLOB.generic_event_spawns)))
owner.playsound_local(owner, 'sound/magic/magic_missile.ogg', 50, TRUE)
flash_color(owner, flash_color = "#AF0AAF", flash_time = 25)
else
to_chat(owner, "<span class='warning'>You're already on the station!</span>")
//A quick-use button for recalling the servants to the Ark
/datum/action/innate/eminence/mass_recall
name = "Mass Recall"
desc = "Initiates a mass recall, warping all servants to the Ark after a short delay. This can only be used once."
button_icon_state = "Spatial Gateway"
/datum/action/innate/eminence/mass_recall/IsAvailable()
. = ..()
if(.)
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
if(G)
return G.recalls_remaining && !G.recalling
return FALSE
/datum/action/innate/eminence/mass_recall/Activate()
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
if(G && !G.recalling && G.recalls_remaining)
if(alert(owner, "Initiate mass recall?", "Mass Recall", "Yes", "No") != "Yes" || QDELETED(owner) || QDELETED(G) || !G.obj_integrity)
return
G.initiate_mass_recall()
@@ -3,6 +3,70 @@
//////////////////
//Sigil of Transmission: Creates a sigil of transmission that can drain and store power for clockwork structures.
/datum/clockwork_scripture/create_object/sigil_of_transmission
descname = "Powers Nearby Structures - Important!"
name = "Sigil of Transmission"
desc = "Places a sigil that can drain and will store energy to power clockwork structures."
invocations = list("Divinity...", "...power our creations!")
channel_time = 70
power_cost = 200
whispered = TRUE
object_path = /obj/effect/clockwork/sigil/transmission
creator_message = "<span class='brass'>A sigil silently appears below you. It will automatically power clockwork structures near it and will drain power when activated.</span>"
usage_tip = "Cyborgs can charge from this sigil by remaining over it for 5 seconds."
tier = SCRIPTURE_APPLICATION
one_per_tile = TRUE
primary_component = HIEROPHANT_ANSIBLE
sort_priority = 1
quickbind = TRUE
quickbind_desc = "Creates a Sigil of Transmission, which can drain and will store power for clockwork structures."
//Mania Motor: Creates a malevolent transmitter that will broadcast the whispers of Sevtug into the minds of nearby nonservants, causing a variety of mental effects at a power cost.
/datum/clockwork_scripture/create_object/mania_motor
descname = "Powered Structure, Area Denial"
name = "Mania Motor"
desc = "Creates a mania motor which causes minor damage and a variety of negative mental effects in nearby non-Servant humans, potentially up to and including conversion."
invocations = list("May this transmitter...", "...break the will of all who oppose us!")
channel_time = 80
power_cost = 750
object_path = /obj/structure/destructible/clockwork/powered/mania_motor
creator_message = "<span class='brass'>You form a mania motor, which causes minor damage and negative mental effects in non-Servants.</span>"
observer_message = "<span class='warning'>A two-pronged machine rises from the ground!</span>"
invokers_required = 2
multiple_invokers_used = TRUE
usage_tip = "It will also cure hallucinations and brain damage in nearby Servants."
tier = SCRIPTURE_APPLICATION
one_per_tile = TRUE
primary_component = HIEROPHANT_ANSIBLE
sort_priority = 2
quickbind = TRUE
quickbind_desc = "Creates a Mania Motor, which causes minor damage and negative mental effects in non-Servants."
//Clockwork Obelisk: Creates a powerful obelisk that can be used to broadcast messages or open a gateway to any servant or clockwork obelisk at a power cost.
/datum/clockwork_scripture/create_object/clockwork_obelisk
descname = "Powered Structure, Teleportation Hub"
name = "Clockwork Obelisk"
desc = "Creates a clockwork obelisk that can broadcast messages over the Hierophant Network or open a Spatial Gateway to any living Servant or clockwork obelisk."
invocations = list("May this obelisk...", "...take us to all places!")
channel_time = 80
power_cost = 300
object_path = /obj/structure/destructible/clockwork/powered/clockwork_obelisk
creator_message = "<span class='brass'>You form a clockwork obelisk which can broadcast messages or produce Spatial Gateways.</span>"
observer_message = "<span class='warning'>A brass obelisk appears hanging in midair!</span>"
invokers_required = 2
multiple_invokers_used = TRUE
usage_tip = "Producing a gateway has a high power cost. Gateways to or between clockwork obelisks receive double duration and uses."
tier = SCRIPTURE_APPLICATION
one_per_tile = TRUE
primary_component = HIEROPHANT_ANSIBLE
sort_priority = 3
quickbind = TRUE
quickbind_desc = "Creates a Clockwork Obelisk, which can send messages or open Spatial Gateways with power."
//Clockwork Marauder: Creates a construct shell for a clockwork marauder, a well-rounded frontline fighter.
/datum/clockwork_scripture/create_object/construct/clockwork_marauder
descname = "Well-Rounded Combat Construct"
@@ -16,7 +80,7 @@
tier = SCRIPTURE_APPLICATION
one_per_tile = TRUE
primary_component = BELLIGERENT_EYE
sort_priority = 1
sort_priority = 4
quickbind = TRUE
quickbind_desc = "Creates a clockwork marauder, used for frontline combat."
object_path = /obj/item/clockwork/construct_chassis/clockwork_marauder
@@ -59,67 +123,3 @@
time_since_last_marauder = world.time //So that it can't be spammed to make the marauder exclusion plummet; this emulates "ticking"
recent_marauders = max(0, recent_marauders - marauders_to_exclude)
scaled_recital_time = min(recent_marauders * MARAUDER_SCRIPTURE_SCALING_TIME, MARAUDER_SCRIPTURE_SCALING_MAX)
//Mania Motor: Creates a malevolent transmitter that will broadcast the whispers of Sevtug into the minds of nearby nonservants, causing a variety of mental effects at a power cost.
/datum/clockwork_scripture/create_object/mania_motor
descname = "Powered Structure, Area Denial"
name = "Mania Motor"
desc = "Creates a mania motor which causes minor damage and a variety of negative mental effects in nearby non-Servant humans, potentially up to and including conversion."
invocations = list("May this transmitter...", "...break the will of all who oppose us!")
channel_time = 80
power_cost = 750
object_path = /obj/structure/destructible/clockwork/powered/mania_motor
creator_message = "<span class='brass'>You form a mania motor, which causes minor damage and negative mental effects in non-Servants.</span>"
observer_message = "<span class='warning'>A two-pronged machine rises from the ground!</span>"
invokers_required = 2
multiple_invokers_used = TRUE
usage_tip = "It will also cure hallucinations and brain damage in nearby Servants."
tier = SCRIPTURE_APPLICATION
one_per_tile = TRUE
primary_component = GEIS_CAPACITOR
sort_priority = 2
quickbind = TRUE
quickbind_desc = "Creates a Mania Motor, which causes minor damage and negative mental effects in non-Servants."
//Sigil of Transmission: Creates a sigil of transmission that can drain and store power for clockwork structures.
/datum/clockwork_scripture/create_object/sigil_of_transmission
descname = "Structure Power Generator & Battery"
name = "Sigil of Transmission"
desc = "Places a sigil that can drain and will store energy to power clockwork structures."
invocations = list("Divinity...", "...power our creations!")
channel_time = 70
power_cost = 200
whispered = TRUE
object_path = /obj/effect/clockwork/sigil/transmission
creator_message = "<span class='brass'>A sigil silently appears below you. It will automatically power clockwork structures near it and will drain power when activated.</span>"
usage_tip = "Cyborgs can charge from this sigil by remaining over it for 5 seconds."
tier = SCRIPTURE_APPLICATION
one_per_tile = TRUE
primary_component = HIEROPHANT_ANSIBLE
sort_priority = 3
quickbind = TRUE
quickbind_desc = "Creates a Sigil of Transmission, which can drain and will store power for clockwork structures."
//Clockwork Obelisk: Creates a powerful obelisk that can be used to broadcast messages or open a gateway to any servant or clockwork obelisk at a power cost.
/datum/clockwork_scripture/create_object/clockwork_obelisk
descname = "Powered Structure, Teleportation Hub"
name = "Clockwork Obelisk"
desc = "Creates a clockwork obelisk that can broadcast messages over the Hierophant Network or open a Spatial Gateway to any living Servant or clockwork obelisk."
invocations = list("May this obelisk...", "...take us to all places!")
channel_time = 80
power_cost = 300
object_path = /obj/structure/destructible/clockwork/powered/clockwork_obelisk
creator_message = "<span class='brass'>You form a clockwork obelisk which can broadcast messages or produce Spatial Gateways.</span>"
observer_message = "<span class='warning'>A brass obelisk appears hanging in midair!</span>"
invokers_required = 2
multiple_invokers_used = TRUE
usage_tip = "Producing a gateway has a high power cost. Gateways to or between clockwork obelisks receive double duration and uses."
tier = SCRIPTURE_APPLICATION
one_per_tile = TRUE
primary_component = HIEROPHANT_ANSIBLE
sort_priority = 4
quickbind = TRUE
quickbind_desc = "Creates a Clockwork Obelisk, which can send messages or open Spatial Gateways with power."
@@ -2,27 +2,52 @@
// DRIVERS //
/////////////
//Hateful Manacles: Applies restraints from melee over several seconds. The restraints function like handcuffs and break on removal.
/datum/clockwork_scripture/ranged_ability/hateful_manacles
descname = "Handcuffs"
name = "Hateful Manacles"
desc = "Forms replicant manacles around a target's wrists that function like handcuffs."
invocations = list("Shackle the heretic!", "Break them in body and spirit!")
channel_time = 15
power_cost = 25
whispered = TRUE
usage_tip = "The manacles are about as strong as zipties, and break when removed."
//Stargazer: Creates a stargazer, a cheap power generator that utilizes starlight.
/datum/clockwork_scripture/create_object/stargazer
descname = "Generates Power From Starlight - Important!"
name = "Stargazer"
desc = "Forms a weak structure that generates power every second while within three tiles of starlight."
invocations = list("Capture their inferior light for us!")
channel_time = 50
power_cost = 50
object_path = /obj/structure/destructible/clockwork/stargazer
creator_message = "<span class='brass'>You form a stargazer, which will generate power near starlight.</span>"
observer_message = "<span class='warning'>A large lantern-shaped machine forms!</span>"
usage_tip = "For obvious reasons, make sure to place this near a window or somewhere else that can see space!"
tier = SCRIPTURE_DRIVER
primary_component = BELLIGERENT_EYE
one_per_tile = TRUE
primary_component = HIEROPHANT_ANSIBLE
sort_priority = 1
ranged_type = /obj/effect/proc_holder/slab/hateful_manacles
slab_overlay = "hateful_manacles"
ranged_message = "<span class='neovgre_small'><i>You charge the clockwork slab with divine energy.</i>\n\
<b>Left-click a target within melee range to shackle!\n\
Click your slab to cancel.</b></span>"
timeout_time = 200
quickbind = TRUE
quickbind_desc = "Applies handcuffs to a struck target."
quickbind_desc = "Creates a stargazer, which generates power when near starlight."
/datum/clockwork_scripture/create_object/stargazer/check_special_requirements()
var/area/A = get_area(invoker)
if(A.outdoors || A.map_name == "Space" || !A.blob_allowed)
to_chat(invoker, "<span class='danger'>Stargazers can't be built off-station.</span>")
return
return ..()
//Integration Cog: Creates an integration cog that can be inserted into APCs to passively siphon power.
/datum/clockwork_scripture/create_object/integration_cog
descname = "APC Power Siphoner"
name = "Integration Cog"
desc = "Fabricates an integration cog, which can be used on an open APC to replace its innards and passively siphon its power."
invocations = list("Take that which sustains them!")
channel_time = 10
power_cost = 10
whispered = TRUE
object_path = /obj/item/clockwork/integration_cog
creator_message = "<span class='brass'>You form an integration cog, which can be inserted into an open APC to passively siphon power.</span>"
usage_tip = "Tampering isn't visible unless the APC is opened."
tier = SCRIPTURE_DRIVER
space_allowed = TRUE
primary_component = HIEROPHANT_ANSIBLE
sort_priority = 2
quickbind = TRUE
quickbind_desc = "Creates an integration cog, which can be used to siphon power from an open APC."
//Sigil of Transgression: Creates a sigil of transgression, which briefly stuns and applies Belligerent to the first non-servant to cross it.
@@ -39,12 +64,78 @@
usage_tip = "The sigil does not silence its victim, and is generally used to soften potential converts or would-be invaders."
tier = SCRIPTURE_DRIVER
one_per_tile = TRUE
primary_component = BELLIGERENT_EYE
sort_priority = 2
primary_component = HIEROPHANT_ANSIBLE
sort_priority = 3
quickbind = TRUE
quickbind_desc = "Creates a Sigil of Transgression, which will briefly stun and slow the next non-Servant to cross it."
//Sigil of Submission: Creates a sigil of submission, which converts one heretic above it after a delay.
/datum/clockwork_scripture/create_object/sigil_of_submission
descname = "Trap, Conversion"
name = "Sigil of Submission"
desc = "Places a luminous sigil that will convert any non-Servants that remain on it for 8 seconds."
invocations = list("Divinity, enlighten...", "...those who trespass here!")
channel_time = 60
power_cost = 125
whispered = TRUE
object_path = /obj/effect/clockwork/sigil/submission
creator_message = "<span class='brass'>A luminous sigil appears below you. Any non-Servants to cross it will be converted after 8 seconds if they do not move.</span>"
usage_tip = "This is the primary conversion method, though it will not penetrate mindshield implants."
tier = SCRIPTURE_DRIVER
one_per_tile = TRUE
primary_component = HIEROPHANT_ANSIBLE
sort_priority = 4
quickbind = TRUE
quickbind_desc = "Creates a Sigil of Submission, which will convert non-Servants that remain on it."
//Kindle: Charges the slab with blazing energy. It can be released to stun and silence a target.
/datum/clockwork_scripture/ranged_ability/kindle
descname = "Short-Range Single-Target Stun"
name = "Kindle"
desc = "Charges your slab with divine energy, allowing you to overwhelm a target with Ratvar's light."
invocations = list("Divinity, show them your light!")
whispered = TRUE
channel_time = 30
power_cost = 125
usage_tip = "The light can be used from up to two tiles away. Damage taken will GREATLY REDUCE the stun's duration."
tier = SCRIPTURE_DRIVER
primary_component = BELLIGERENT_EYE
sort_priority = 5
slab_overlay = "volt"
ranged_type = /obj/effect/proc_holder/slab/kindle
ranged_message = "<span class='brass'><i>You charge the clockwork slab with divine energy.</i>\n\
<b>Left-click a target within melee range to stun!\n\
Click your slab to cancel.</b></span>"
timeout_time = 150
quickbind = TRUE
quickbind_desc = "Stuns and mutes a target from a short range."
//Hateful Manacles: Applies restraints from melee over several seconds. The restraints function like handcuffs and break on removal.
/datum/clockwork_scripture/ranged_ability/hateful_manacles
descname = "Handcuffs"
name = "Hateful Manacles"
desc = "Forms replicant manacles around a target's wrists that function like handcuffs."
invocations = list("Shackle the heretic!", "Break them in body and spirit!")
channel_time = 15
power_cost = 25
whispered = TRUE
usage_tip = "The manacles are about as strong as zipties, and break when removed."
tier = SCRIPTURE_DRIVER
primary_component = BELLIGERENT_EYE
sort_priority = 6
ranged_type = /obj/effect/proc_holder/slab/hateful_manacles
slab_overlay = "hateful_manacles"
ranged_message = "<span class='neovgre_small'><i>You charge the clockwork slab with divine energy.</i>\n\
<b>Left-click a target within melee range to shackle!\n\
Click your slab to cancel.</b></span>"
timeout_time = 200
quickbind = TRUE
quickbind_desc = "Applies handcuffs to a struck target."
//Vanguard: Provides twenty seconds of stun immunity. At the end of the twenty seconds, 25% of all stuns absorbed are applied to the invoker.
/datum/clockwork_scripture/vanguard
descname = "Self Stun Immunity"
@@ -57,7 +148,7 @@
usage_tip = "You cannot reactivate Vanguard while still shielded by it."
tier = SCRIPTURE_DRIVER
primary_component = VANGUARD_COGWHEEL
sort_priority = 3
sort_priority = 7
quickbind = TRUE
quickbind_desc = "Allows you to temporarily absorb stuns. All stuns absorbed will affect you when disabled."
@@ -89,7 +180,7 @@
usage_tip = "The Compromise is very fast to invoke, and will remove holy water from the target Servant."
tier = SCRIPTURE_DRIVER
primary_component = VANGUARD_COGWHEEL
sort_priority = 4
sort_priority = 8
quickbind = TRUE
quickbind_desc = "Allows you to convert a Servant's brute, burn, and oxygen damage to half toxin damage.<br><b>Click your slab to disable.</b>"
slab_overlay = "compromise"
@@ -101,7 +192,7 @@
//Abscond: Used to return to Reebe.
/datum/clockwork_scripture/abscond
descname = "Return to Reebe"
descname = "Return to Reebe - Important!"
name = "Abscond"
desc = "Yanks you through space, returning you to home base."
invocations = list("As we bid farewell, and return to the stars...", "...we shall find our way home.")
@@ -113,7 +204,7 @@
usage_tip = "This can't be used while on Reebe, for obvious reasons."
tier = SCRIPTURE_DRIVER
primary_component = GEIS_CAPACITOR
sort_priority = 5
sort_priority = 9
quickbind = TRUE
quickbind_desc = "Returns you to Reebe."
@@ -153,52 +244,9 @@
animate(invoker.client, color = initial(invoker.client.color), time = 10)
//Kindle: Charges the slab with blazing energy. It can be released to stun and silence a target.
/datum/clockwork_scripture/ranged_ability/kindle
descname = "Short-Range Single-Target Stun"
name = "Kindle"
desc = "Charges your slab with divine energy, allowing you to overwhelm a target with Ratvar's light."
invocations = list("Divinity, show them your light!")
whispered = TRUE
channel_time = 30
power_cost = 125
usage_tip = "The light can be used from up to two tiles away. Damage taken will GREATLY REDUCE the stun's duration."
tier = SCRIPTURE_DRIVER
primary_component = GEIS_CAPACITOR
sort_priority = 6
slab_overlay = "volt"
ranged_type = /obj/effect/proc_holder/slab/kindle
ranged_message = "<span class='brass'><i>You charge the clockwork slab with divine energy.</i>\n\
<b>Left-click a target within melee range to stun!\n\
Click your slab to cancel.</b></span>"
timeout_time = 150
quickbind = TRUE
quickbind_desc = "Stuns and mutes a target from a short range."
//Sigil of Submission: Creates a sigil of submission, which converts one heretic above it after a delay.
/datum/clockwork_scripture/create_object/sigil_of_submission
descname = "Trap, Conversion"
name = "Sigil of Submission"
desc = "Places a luminous sigil that will convert any non-Servants that remain on it for 8 seconds."
invocations = list("Divinity, enlighten...", "...those who trespass here!")
channel_time = 60
power_cost = 125
whispered = TRUE
object_path = /obj/effect/clockwork/sigil/submission
creator_message = "<span class='brass'>A luminous sigil appears below you. Any non-Servants to cross it will be converted after 8 seconds if they do not move.</span>"
usage_tip = "This is the primary conversion method, though it will not penetrate mindshield implants."
tier = SCRIPTURE_DRIVER
one_per_tile = TRUE
primary_component = GEIS_CAPACITOR
sort_priority = 6
quickbind = TRUE
quickbind_desc = "Creates a Sigil of Submission, which will convert non-Servants that remain on it."
//Replicant: Creates a new clockwork slab.
/datum/clockwork_scripture/create_object/replicant
descname = "New Clockwork Slab"
descname = "New Clockwork Slab - Important!"
name = "Replicant"
desc = "Creates a new clockwork slab."
invocations = list("Metal, become greater!")
@@ -210,59 +258,12 @@
usage_tip = "This is inefficient as a way to produce components, as the slab produced must be held by someone with no other slabs to produce components."
tier = SCRIPTURE_DRIVER
space_allowed = TRUE
primary_component = REPLICANT_ALLOY
sort_priority = 7
primary_component = GEIS_CAPACITOR
sort_priority = 10
quickbind = TRUE
quickbind_desc = "Creates a new Clockwork Slab."
//Stargazer: Creates a stargazer, a cheap power generator that utilizes starlight.
/datum/clockwork_scripture/create_object/stargazer
descname = "Necessary Structure, Generates Power From Starlight"
name = "Stargazer"
desc = "Forms a weak structure that generates power every second while within three tiles of starlight."
invocations = list("Capture their inferior light for us!")
channel_time = 50
power_cost = 50
object_path = /obj/structure/destructible/clockwork/stargazer
creator_message = "<span class='brass'>You form a stargazer, which will generate power near starlight.</span>"
observer_message = "<span class='warning'>A large lantern-shaped machine forms!</span>"
usage_tip = "For obvious reasons, make sure to place this near a window or somewhere else that can see space!"
tier = SCRIPTURE_DRIVER
one_per_tile = TRUE
primary_component = REPLICANT_ALLOY
sort_priority = 8
quickbind = TRUE
quickbind_desc = "Creates a stargazer, which generates power when near starlight."
/datum/clockwork_scripture/create_object/stargazer/check_special_requirements()
var/area/A = get_area(invoker)
if(A.outdoors || A.map_name == "Space" || !A.blob_allowed)
to_chat(invoker, "<span class='danger'>Stargazers can't be built off-station.</span>")
return
return ..()
//Integration Cog: Creates an integration cog that can be inserted into APCs to passively siphon power.
/datum/clockwork_scripture/create_object/integration_cog
descname = "APC Power Siphoner"
name = "Integration Cog"
desc = "Fabricates an integration cog, which can be used on an open APC to replace its innards and passively siphon its power."
invocations = list("Take that which sustains them!")
channel_time = 10
power_cost = 10
whispered = TRUE
object_path = /obj/item/clockwork/integration_cog
creator_message = "<span class='brass'>You form an integration cog, which can be inserted into an open APC to passively siphon power.</span>"
usage_tip = "Tampering isn't visible unless the APC is opened."
tier = SCRIPTURE_DRIVER
space_allowed = TRUE
primary_component = HIEROPHANT_ANSIBLE
sort_priority = 9
quickbind = TRUE
quickbind_desc = "Creates an integration cog, which can be used to siphon power from an open APC."
//Wraith Spectacles: Creates a pair of wraith spectacles, which grant xray vision but damage vision slowly.
/datum/clockwork_scripture/create_object/wraith_spectacles
descname = "Limited Xray Vision Glasses"
@@ -277,7 +278,7 @@
usage_tip = "\"True sight\" means that you are able to see through walls and in darkness."
tier = SCRIPTURE_DRIVER
space_allowed = TRUE
primary_component = HIEROPHANT_ANSIBLE
sort_priority = 10
primary_component = GEIS_CAPACITOR
sort_priority = 11
quickbind = TRUE
quickbind_desc = "Creates a pair of Wraith Spectacles, which grant true sight but cause gradual vision loss."
@@ -2,6 +2,27 @@
// SCRIPTS //
/////////////
//Replica Fabricator: Creates a replica fabricator, used to convert objects and repair clockwork structures.
/datum/clockwork_scripture/create_object/replica_fabricator
descname = "Creates Brass and Converts Objects - Important!"
name = "Replica Fabricator"
desc = "Forms a device that, when used on certain objects, replaces them with their Ratvarian equivalents. It requires power to function."
invocations = list("With this device...", "...his presence shall be made known.")
channel_time = 20
power_cost = 250
whispered = TRUE
object_path = /obj/item/clockwork/replica_fabricator
creator_message = "<span class='brass'>You form a replica fabricator.</span>"
usage_tip = "Clockwork Walls cause nearby Tinkerer's Caches to generate components passively, making this a vital tool. Clockwork Floors heal toxin damage in Servants standing on them."
tier = SCRIPTURE_SCRIPT
space_allowed = TRUE
primary_component = HIEROPHANT_ANSIBLE
sort_priority = 1
quickbind = TRUE
quickbind_desc = "Creates a Replica Fabricator, which can convert various objects to Ratvarian variants."
//Ocular Warden: Creates an ocular warden, which defends a small area near it.
/datum/clockwork_scripture/create_object/ocular_warden
descname = "Structure, Turret"
@@ -17,8 +38,8 @@
tier = SCRIPTURE_SCRIPT
one_per_tile = TRUE
space_allowed = TRUE
primary_component = BELLIGERENT_EYE
sort_priority = 1
primary_component = HIEROPHANT_ANSIBLE
sort_priority = 2
quickbind = TRUE
quickbind_desc = "Creates an Ocular Warden, which will automatically attack nearby unrestrained non-Servants that can see it."
@@ -29,26 +50,6 @@
return ..()
//Judicial Visor: Creates a judicial visor, which can smite an area.
/datum/clockwork_scripture/create_object/judicial_visor
descname = "Delayed Area Knockdown Glasses"
name = "Judicial Visor"
desc = "Creates a visor that can smite an area, applying Belligerent and briefly stunning. The smote area will explode after 3 seconds."
invocations = list("Grant me the flames of Engine!")
channel_time = 10
power_cost = 400
whispered = TRUE
object_path = /obj/item/clothing/glasses/judicial_visor
creator_message = "<span class='brass'>You form a judicial visor, which is capable of smiting a small area.</span>"
usage_tip = "The visor has a thirty-second cooldown once used."
tier = SCRIPTURE_SCRIPT
space_allowed = TRUE
primary_component = BELLIGERENT_EYE
sort_priority = 2
quickbind = TRUE
quickbind_desc = "Creates a Judicial Visor, which can smite an area, applying Belligerent and briefly stunning."
//Vitality Matrix: Creates a sigil which will drain health from nonservants and can use that health to heal or even revive servants.
/datum/clockwork_scripture/create_object/vitality_matrix
descname = "Trap, Damage to Healing"
@@ -64,147 +65,35 @@
usage_tip = "The sigil will be consumed upon reviving a Servant."
tier = SCRIPTURE_SCRIPT
one_per_tile = TRUE
primary_component = VANGUARD_COGWHEEL
primary_component = HIEROPHANT_ANSIBLE
sort_priority = 3
quickbind = TRUE
quickbind_desc = "Creates a Vitality Matrix, which drains non-Servants on it to heal Servants that cross it."
//Mending Mantra: Channeled for up to ten times over twenty seconds to repair structures and heal allies
/datum/clockwork_scripture/channeled/mending_mantra
descname = "Channeled, Area Healing and Repair"
name = "Mending Mantra"
desc = "Repairs nearby structures and constructs. Servants wearing clockwork armor will also be healed. Channeled every two seconds for a maximum of twenty seconds."
chant_invocations = list("Mend our dents!", "Heal our scratches!", "Repair our gears!")
chant_amount = 10
chant_interval = 20
power_cost = 1000
usage_tip = "This is a very effective way to rapidly reinforce a base after an attack."
tier = SCRIPTURE_SCRIPT
primary_component = VANGUARD_COGWHEEL
sort_priority = 4
quickbind = TRUE
quickbind_desc = "Repairs nearby structures and constructs. Servants wearing clockwork armor will also be healed.<br><b>Maximum 10 chants.</b>"
var/heal_attempts = 4
var/heal_amount = 2.5
var/static/list/damage_heal_order = list(BRUTE, BURN, OXY)
var/static/list/heal_finish_messages = list("There, all mended!", "Try not to get too damaged.", "No more dents and scratches for you!", "Champions never die.", "All patched up.", \
"Ah, child, it's okay now.", "Pain is temporary.", "What you do for the Justiciar is eternal.", "Bear this for me.", "Be strong, child.", "Please, be careful!", \
"If you die, you will be remembered.")
var/static/list/heal_target_typecache = typecacheof(list(
/obj/structure/destructible/clockwork,
/obj/machinery/door/airlock/clockwork,
/obj/machinery/door/window/clockwork,
/obj/structure/window/reinforced/clockwork,
/obj/structure/table/reinforced/brass))
var/static/list/ratvarian_armor_typecache = typecacheof(list(
/obj/item/clothing/suit/armor/clockwork,
/obj/item/clothing/head/helmet/clockwork,
/obj/item/clothing/gloves/clockwork,
/obj/item/clothing/shoes/clockwork))
/datum/clockwork_scripture/channeled/mending_mantra/chant_effects(chant_number)
var/turf/T
for(var/atom/movable/M in range(7, invoker))
if(isliving(M))
if(isclockmob(M) || istype(M, /mob/living/simple_animal/drone/cogscarab))
var/mob/living/simple_animal/S = M
if(S.health == S.maxHealth || S.stat == DEAD)
continue
T = get_turf(M)
for(var/i in 1 to heal_attempts)
if(S.health < S.maxHealth)
S.adjustHealth(-heal_amount)
new /obj/effect/temp_visual/heal(T, "#1E8CE1")
if(i == heal_attempts && S.health >= S.maxHealth) //we finished healing on the last tick, give them the message
to_chat(S, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
break
else
to_chat(S, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
break
else if(issilicon(M))
var/mob/living/silicon/S = M
if(S.health == S.maxHealth || S.stat == DEAD || !is_servant_of_ratvar(S))
continue
T = get_turf(M)
for(var/i in 1 to heal_attempts)
if(S.health < S.maxHealth)
S.heal_ordered_damage(heal_amount, damage_heal_order)
new /obj/effect/temp_visual/heal(T, "#1E8CE1")
if(i == heal_attempts && S.health >= S.maxHealth)
to_chat(S, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
break
else
to_chat(S, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
break
else if(ishuman(M))
var/mob/living/carbon/human/H = M
if(H.health == H.maxHealth || H.stat == DEAD || !is_servant_of_ratvar(H))
continue
T = get_turf(M)
var/heal_ticks = 0 //one heal tick for each piece of ratvarian armor worn
var/obj/item/I = H.get_item_by_slot(slot_wear_suit)
if(is_type_in_typecache(I, ratvarian_armor_typecache))
heal_ticks++
I = H.get_item_by_slot(slot_head)
if(is_type_in_typecache(I, ratvarian_armor_typecache))
heal_ticks++
I = H.get_item_by_slot(slot_gloves)
if(is_type_in_typecache(I, ratvarian_armor_typecache))
heal_ticks++
I = H.get_item_by_slot(slot_shoes)
if(is_type_in_typecache(I, ratvarian_armor_typecache))
heal_ticks++
if(heal_ticks)
for(var/i in 1 to heal_ticks)
if(H.health < H.maxHealth)
H.heal_ordered_damage(heal_amount, damage_heal_order)
new /obj/effect/temp_visual/heal(T, "#1E8CE1")
if(i == heal_ticks && H.health >= H.maxHealth)
to_chat(H, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
break
else
to_chat(H, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
break
else if(is_type_in_typecache(M, heal_target_typecache))
var/obj/structure/destructible/clockwork/C = M
if(C.obj_integrity == C.max_integrity || (istype(C) && !C.can_be_repaired))
continue
T = get_turf(M)
for(var/i in 1 to heal_attempts)
if(C.obj_integrity < C.max_integrity)
C.obj_integrity = min(C.obj_integrity + 5, C.max_integrity)
C.update_icon()
new /obj/effect/temp_visual/heal(T, "#1E8CE1")
else
break
new /obj/effect/temp_visual/ratvar/mending_mantra(get_turf(invoker))
return TRUE
//Replica Fabricator: Creates a replica fabricator, used to convert objects and repair clockwork structures.
/datum/clockwork_scripture/create_object/replica_fabricator
descname = "Replaces Objects with Ratvarian Versions"
name = "Replica Fabricator"
desc = "Forms a device that, when used on certain objects, replaces them with their Ratvarian equivalents. It requires power to function."
invocations = list("With this device...", "...his presence shall be made known.")
channel_time = 20
power_cost = 250
//Judicial Visor: Creates a judicial visor, which can smite an area.
/datum/clockwork_scripture/create_object/judicial_visor
descname = "Delayed Area Knockdown Glasses"
name = "Judicial Visor"
desc = "Creates a visor that can smite an area, applying Belligerent and briefly stunning. The smote area will explode after 3 seconds."
invocations = list("Grant me the flames of Engine!")
channel_time = 10
power_cost = 400
whispered = TRUE
object_path = /obj/item/clockwork/replica_fabricator
creator_message = "<span class='brass'>You form a replica fabricator.</span>"
usage_tip = "Clockwork Walls cause nearby Tinkerer's Caches to generate components passively, making this a vital tool. Clockwork Floors heal toxin damage in Servants standing on them."
object_path = /obj/item/clothing/glasses/judicial_visor
creator_message = "<span class='brass'>You form a judicial visor, which is capable of smiting a small area.</span>"
usage_tip = "The visor has a thirty-second cooldown once used."
tier = SCRIPTURE_SCRIPT
space_allowed = TRUE
primary_component = REPLICANT_ALLOY
sort_priority = 5
primary_component = BELLIGERENT_EYE
sort_priority = 4
quickbind = TRUE
quickbind_desc = "Creates a Replica Fabricator, which can convert various objects to Ratvarian variants."
quickbind_desc = "Creates a Judicial Visor, which can smite an area, applying Belligerent and briefly stunning."
//Clockwork Arnaments: Grants the invoker the ability to call forth a Ratvarian spear and clockwork armor.
/datum/clockwork_scripture/clockwork_arnaments
descname = "Summonable Armor and Weapons"
descname = "Summonable Armor and Weapons - Important!"
name = "Clockwork Arnaments"
desc = "Allows the invoker to summon clockwork armor and a Ratvarian spear at will. The spear's attacks will generate Vitality, used for healing."
invocations = list("Grant me arnaments...", "...from the forge of Armorer!")
@@ -213,8 +102,8 @@
whispered = TRUE
usage_tip = "Throwing the spear at a mob will do massive damage and knock them down, but break the spear. You will need to wait for 30 seconds before resummoning it."
tier = SCRIPTURE_SCRIPT
primary_component = REPLICANT_ALLOY
sort_priority = 6
primary_component = VANGUARD_COGWHEEL
sort_priority = 5
quickbind = TRUE
quickbind_desc = "Permanently binds clockwork armor and a Ratvarian spear to you."
@@ -312,8 +201,8 @@
multiple_invokers_optional = TRUE
usage_tip = "This gateway is strictly one-way and will only allow things through the invoker's portal."
tier = SCRIPTURE_SCRIPT
primary_component = HIEROPHANT_ANSIBLE
sort_priority = 9
primary_component = GEIS_CAPACITOR
sort_priority = 6
quickbind = TRUE
quickbind_desc = "Allows you to create a one-way Spatial Gateway to a living Servant or Clockwork Obelisk."
@@ -0,0 +1,86 @@
//No, not that kind.
/obj/structure/destructible/clockwork/trap
name = "base clockwork trap"
desc = "You shouldn't see this. File a bug report!"
clockwork_desc = "A trap that shouldn't exist, and you should report this as a bug."
var/list/wired_to
/obj/structure/destructible/clockwork/trap/Initialize()
. = ..()
wired_to = list()
/obj/structure/destructible/clockwork/trap/Destroy()
for(var/V in wired_to)
var/obj/structure/destructible/clockwork/trap/T = V
T.wired_to -= src
return ..()
/obj/structure/destructible/clockwork/trap/examine(mob/user)
..()
if(is_servant_of_ratvar(user) || isobserver(user))
to_chat(user, "It's wired to:")
if(!wired_to.len)
to_chat(user, "Nothing.")
else
for(var/V in wired_to)
var/obj/O = V
var/distance = get_dist(src, O)
to_chat(user, "[O] ([distance == 0 ? "same tile" : "[distance] tiles [dir2text(get_dir(src, O))]"])")
/obj/structure/destructible/clockwork/trap/wrench_act(mob/living/user, obj/item/wrench)
if(!is_servant_of_ratvar(user))
return ..()
to_chat(user, "<span class='notice'>You break down the delicate components of [src] into brass.</span>")
playsound(src, wrench.usesound, 50, TRUE)
new/obj/item/stack/tile/brass(get_turf(src))
qdel(src)
return TRUE
/obj/structure/destructible/clockwork/trap/attackby(obj/item/I, mob/living/user, params)
if(istype(I, /obj/item/clockwork/slab) && is_servant_of_ratvar(user))
var/obj/item/clockwork/slab/F = I
if(!F.linking)
to_chat(user, "<span class='notice'>Beginning link. Alt-click the slab to cancel, or use it on another trap object to link the two.</span>")
F.linking = src
else
if(F.linking in wired_to)
to_chat(user, "<span class='warning'>These two objects are already connected!</span>")
return
if(F.linking.z != z)
to_chat(user, "<span class='warning'>You'd need a <b>much</b> tougher slab to link two objects in different sectors.</span>")
return
to_chat(user, "<span class='notice'>You link [F.linking] with [src].</span>")
wired_to += F.linking
F.linking.wired_to += src
F.linking = null
return
..()
/obj/structure/destructible/clockwork/trap/wirecutter_act(mob/living/user, obj/item/wirecutters)
if(!is_servant_of_ratvar(user))
return
if(!wired_to.len)
to_chat(user, "<span class='warning'>[src] has no connections!</span>")
return
to_chat(user, "<span class='notice'>You sever all connections to [src].</span>")
playsound(src, wirecutters.usesound, 50, TRUE)
for(var/V in wired_to)
var/obj/structure/destructible/clockwork/trap/T = V
T.wired_to -= src
wired_to -= T
return TRUE
/obj/structure/destructible/clockwork/trap/proc/activate()
//These objects send signals to normal traps to activate
/obj/structure/destructible/clockwork/trap/trigger
name = "base trap trigger"
max_integrity = 5
break_message = "<span class='warning'>The trigger breaks apart!</span>"
density = FALSE
/obj/structure/destructible/clockwork/trap/trigger/activate()
for(var/obj/structure/destructible/clockwork/trap/T in wired_to)
if(istype(T, /obj/structure/destructible/clockwork/trap/trigger)) //Triggers don't go off multiple times
continue
T.activate()
@@ -26,6 +26,9 @@
var/fourth_sound_played = FALSE
var/obj/effect/clockwork/overlay/gateway_glow/glow
var/obj/effect/countdown/clockworkgate/countdown
var/last_scream = 0
var/recalls_remaining = 1
var/recalling
/obj/structure/destructible/clockwork/massive/celestial_gateway/Initialize()
. = ..()
@@ -34,7 +37,21 @@
GLOB.ark_of_the_clockwork_justiciar = src
START_PROCESSING(SSprocessing, src)
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/final_countdown(ark_time)
/obj/structure/destructible/clockwork/massive/celestial_gateway/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
. = ..()
if(.)
flick("clockwork_gateway_damaged", glow)
playsound(src, 'sound/machines/clockcult/ark_damage.ogg', 75, FALSE)
if(last_scream < world.time)
audible_message("<span class='boldwarning'>An unearthly screaming sound resonates throughout Reebe!</span>")
for(var/V in GLOB.player_list)
var/mob/M = V
if(M.z == z || is_servant_of_ratvar(M) || isobserver(M))
M.playsound_local(M, 'sound/machines/clockcult/ark_scream.ogg', 100, FALSE, pressure_affected = FALSE)
hierophant_message("<span class='big boldwarning'>The Ark is taking damage!</span>")
last_scream = world.time + ARK_SCREAM_COOLDOWN
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/final_countdown(ark_time) //WE'RE LEAVING TOGETHEEEEEEEEER
if(!ark_time)
ark_time = 30 //minutes
initial_activation_delay = ark_time * 60
@@ -58,13 +75,17 @@
active = TRUE
priority_announce("Massive [Gibberish("bluespace", 100)] anomaly detected on all frequencies. All crew are directed to \
@!$, [text2ratvar("PURGE ALL UNTRUTHS")] <&. the anomalies and destroy their source to prevent further damage to corporate property. This is \
not a drill.[grace_period ? " Estimated time of appearance: [grace_period] seconds. Use this time to prepare." : ""]", \
not a drill.[grace_period ? " Estimated time of appearance: [grace_period] seconds. Use this time to prepare for an attack on [station_name()]." : ""]", \
"Central Command Higher Dimensional Affairs", 'sound/magic/clockwork/ark_activation.ogg')
set_security_level("delta")
for(var/V in SSticker.mode.servants_of_ratvar)
var/datum/mind/M = V
if(ishuman(M.current))
M.current.add_overlay(mutable_appearance('icons/effects/genetics.dmi', "servitude", -MUTATIONS_LAYER))
for(var/V in GLOB.brass_recipes)
var/datum/stack_recipe/R = V
if(R.title == "wall gear")
R.time *= 2 //Building walls becomes slower when the Ark activates
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/open_portal(turf/T)
new/obj/effect/clockwork/city_of_cogs_rift(T)
@@ -83,6 +104,25 @@
seconds_until_activation = 0
SSshuttle.registerHostileEnvironment(src)
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/initiate_mass_recall()
recalling = TRUE
sound_to_playing_players('sound/machines/clockcult/ark_recall.ogg', 75, FALSE)
hierophant_message("<span class='bold large_brass'>The Eminence has initiated a mass recall! You are being transported to the Ark!</span>")
addtimer(CALLBACK(src, .proc/mass_recall), 100)
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/mass_recall()
for(var/V in SSticker.mode.servants_of_ratvar)
var/datum/mind/M = V
if(!M.current.stat)
M.current.forceMove(get_turf(src))
M.current.overlay_fullscreen("flash", /obj/screen/fullscreen/flash)
M.current.clear_fullscreen("flash", 5)
playsound(src, 'sound/magic/clockwork/invoke_general.ogg', 50, FALSE)
recalls_remaining--
recalling = FALSE
transform = matrix() * 2
animate(src, transform = matrix() * 0.5, time = 30, flags = ANIMATION_END_NOW)
/obj/structure/destructible/clockwork/massive/celestial_gateway/Destroy()
STOP_PROCESSING(SSprocessing, src)
SSshuttle.clearHostileEnvironment(src)
@@ -117,6 +157,9 @@
countdown.stop()
visible_message("<span class='userdanger'>[src] begins to pulse uncontrollably... you might want to run!</span>")
sound_to_playing_players(volume = 50, channel = CHANNEL_JUSTICAR_ARK, S = sound('sound/effects/clockcult_gateway_disrupted.ogg'))
for(var/mob/M in GLOB.player_list)
if(M.z == z || is_servant_of_ratvar(M))
M.playsound_local(M, 'sound/machines/clockcult/ark_deathrattle.ogg', 100, FALSE, pressure_affected = FALSE)
make_glow()
glow.icon_state = "clockwork_gateway_disrupted"
resistance_flags |= INDESTRUCTIBLE
@@ -0,0 +1,126 @@
//Used to nominate oneself or ghosts for the role of Eminence.
/obj/structure/destructible/clockwork/eminence_spire
name = "eminence spire"
desc = "A hulking machine made of powerful alloy, with three small obelisks and a huge plate in the center."
clockwork_desc = "This spire is used to become the Eminence, who functions as an invisible leader of the cult. Activate it to nominate yourself or propose that the Eminence should be \
selected from available ghosts. Once an Eminence is selected, they can't normally be changed."
icon_state = "tinkerers_daemon"
break_message = "<span class='warning'>The spire screeches with crackling power and collapses into scrap!</span>"
max_integrity = 400
var/mob/eminence_nominee
var/selection_timer //Timer ID; this is canceled if the vote is canceled
var/kingmaking
/obj/structure/destructible/clockwork/eminence_spire/attack_hand(mob/living/user)
if(!is_servant_of_ratvar(user))
to_chat(user, "<span class='notice'>You can tell how powerful [src] is; you know better than to touch it.</span>")
return
if(kingmaking)
return
if(SSticker.mode.eminence)
to_chat(user, "<span class='warning'>There's already an Eminence!</span>")
return
if(!GLOB.servants_active)
to_chat(user, "<span class='warning'>The Ark isn't active!</span>")
return
if(eminence_nominee) //This could be one large proc, but is split into three for ease of reading
if(eminence_nominee == user)
cancelation(user)
else
objection(user)
else
nomination(user)
/obj/structure/destructible/clockwork/eminence_spire/attack_ghost(mob/user)
if(!IsAdminGhost(user))
return
if(SSticker.mode.eminence)
to_chat(user, "<span class='warning'>There's already an Eminence - too late!</span>")
return
if(!GLOB.servants_active)
to_chat(user, "<span class='warning'>The Ark must be active first!</span>")
return
if(alert(user, "Become the Eminence using admin?", "Become Eminence", "Yes", "No") != "Yes")
return
message_admins("<span class='danger'>Admin [key_name_admin(user)] directly became the Eminence of the cult!</span>")
log_admin("Admin [key_name(user)] made themselves the Eminence.")
var/mob/camera/eminence/eminence = new(get_turf(src))
eminence.key = user.key
hierophant_message("<span class='bold large_brass'>Ratvar has directly assigned the Eminence!</span>")
for(var/mob/M in servants_and_ghosts())
M.playsound_local(M, 'sound/machines/clockcult/eminence_selected.ogg', 50, FALSE)
/obj/structure/destructible/clockwork/eminence_spire/proc/nomination(mob/living/nominee) //A user is nominating themselves or ghosts to become Eminence
var/nomination_choice = alert(nominee, "Who would you like to nominate?", "Eminence Nomination", "Nominate Yourself", "Nominate Ghosts", "Cancel")
if(!is_servant_of_ratvar(nominee) || !nominee.canUseTopic(src) || eminence_nominee)
return
switch(nomination_choice)
if("Cancel")
return
if("Nominate Yourself")
eminence_nominee = nominee
hierophant_message("<span class='brass'><b>[nominee] nominates themselves as the Eminence!</b> You may object by interacting with the eminence spire. The vote will otherwise pass in 30 seconds.</span>")
if("Nominate Ghosts")
eminence_nominee = "ghosts"
hierophant_message("<span class='brass'><b>[nominee] proposes selecting an Eminence from ghosts!</b> You may object by interacting with the eminence spire. The vote will otherwise pass in 30 seconds.</span>")
for(var/mob/M in servants_and_ghosts())
M.playsound_local(M, 'sound/machines/clockcult/ocularwarden-target.ogg', 50, FALSE)
selection_timer = addtimer(CALLBACK(src, .proc/kingmaker), 300, TIMER_STOPPABLE)
/obj/structure/destructible/clockwork/eminence_spire/proc/objection(mob/living/wright)
if(alert(wright, "Object to the selection of [eminence_nominee] as Eminence?", "Objection!", "Object", "Cancel") == "Cancel" || !is_servant_of_ratvar(wright) || !wright.canUseTopic(src) || !eminence_nominee)
return
hierophant_message("<span class='brass'><b>[wright] objects to the nomination of [eminence_nominee]!</b> The eminence spire has been reset.</span>")
for(var/mob/M in servants_and_ghosts())
M.playsound_local(M, 'sound/machines/clockcult/integration_cog_install.ogg', 50, FALSE)
eminence_nominee = null
deltimer(selection_timer)
/obj/structure/destructible/clockwork/eminence_spire/proc/cancelation(mob/living/cold_feet)
if(alert(cold_feet, "Cancel your nomination?", "Cancel Nomination", "Withdraw Nomination", "Cancel") == "Cancel" || !is_servant_of_ratvar(cold_feet) || !cold_feet.canUseTopic(src) || !eminence_nominee)
return
hierophant_message("<span class='brass'><b>[eminence_nominee] has withdrawn their nomination!</b> The eminence spire has been reset.</span>")
for(var/mob/M in servants_and_ghosts())
M.playsound_local(M, 'sound/machines/clockcult/integration_cog_install.ogg', 50, FALSE)
eminence_nominee = null
deltimer(selection_timer)
/obj/structure/destructible/clockwork/eminence_spire/proc/kingmaker()
if(!eminence_nominee)
return
if(ismob(eminence_nominee))
if(!eminence_nominee.client || !eminence_nominee.mind)
hierophant_message("<span class='brass'><b>[eminence_nominee] somehow lost their sentience!</b> The eminence spire has been reset.</span>")
for(var/mob/M in servants_and_ghosts())
M.playsound_local(M, 'sound/machines/clockcult/integration_cog_install.ogg', 50, FALSE)
eminence_nominee = null
return
playsound(eminence_nominee, 'sound/machines/clockcult/ark_damage.ogg', 50, FALSE)
eminence_nominee.visible_message("<span class='warning'>A blast of white-hot light flows into [eminence_nominee], vaporizing them in an instant!</span>", \
"<span class='userdanger'>allthelightintheuniverseflowing.into.YOU</span>")
for(var/obj/item/I in eminence_nominee)
eminence_nominee.dropItemToGround(I)
var/mob/camera/eminence/eminence = new(get_turf(src))
eminence_nominee.mind.transfer_to(eminence)
eminence_nominee.dust()
hierophant_message("<span class='bold large_brass'>[eminence_nominee] has ascended into the Eminence!</span>")
else if(eminence_nominee == "ghosts")
kingmaking = TRUE
hierophant_message("<span class='brass'><b>The eminence spire is now selecting a ghost to be the Eminence...</b></span>")
var/list/candidates = pollGhostCandidates("Would you like to play as the servants' Eminence?", "Servant of Ratvar", null, ROLE_SERVANT_OF_RATVAR, poll_time = 100)
kingmaking = FALSE
if(!candidates.len)
for(var/mob/M in servants_and_ghosts())
M.playsound_local(M, 'sound/machines/clockcult/integration_cog_install.ogg', 50, FALSE)
hierophant_message("<span class='brass'><b>No ghosts accepted the offer!</b> The eminence spire has been reset.</span>")
eminence_nominee = null
return
visible_message("<span class='warning'>A blast of white-hot light spirals from [src] in waves!</span>")
playsound(src, 'sound/machines/clockcult/ark_damage.ogg', 50, FALSE)
var/mob/camera/eminence/eminence = new(get_turf(src))
eminence_nominee = pick(candidates)
eminence.key = eminence_nominee.key
hierophant_message("<span class='bold large_brass'>A ghost has ascended into the Eminence!</span>")
for(var/mob/M in servants_and_ghosts())
M.playsound_local(M, 'sound/machines/clockcult/eminence_selected.ogg', 50, FALSE)
eminence_nominee = null
@@ -106,3 +106,4 @@
H.set_species(/datum/species/golem/clockwork/no_scrap)
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
G.grace_period = FALSE //no grace period if we've declared war
G.recalls_remaining++
@@ -0,0 +1,14 @@
//Lever: Do I really need to explain this?
/obj/structure/destructible/clockwork/trap/trigger/lever
name = "lever"
desc = "A fancy lever made of wood and capped with brass."
clockwork_desc = "A fancy lever.that activates when pulled."
max_integrity = 75
icon_state = "lever"
/obj/structure/destructible/clockwork/trap/trigger/lever/attack_hand(mob/living/user)
user.visible_message("<span class='notice'>[user] pulls [src]!</span>", "<span class='notice'>You pull [src]. It clicks, then lifts back upwards.</span>")
if(wired_to.len)
audible_message("<i>You hear gears clanking.</i>")
playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE)
activate()
@@ -0,0 +1,26 @@
//Pressure sensor: Activates when stepped on.
/obj/structure/destructible/clockwork/trap/trigger/pressure_sensor
name = "pressure sensor"
desc = "A thin plate of brass, barely visible but clearly distinct."
clockwork_desc = "A trigger that will activate when a non-servant runs across it."
max_integrity = 25
icon_state = "pressure_sensor"
alpha = 80
layer = LOW_ITEM_LAYER
/obj/structure/destructible/clockwork/trap/trigger/Initialize()
. = ..()
for(var/obj/structure/destructible/clockwork/trap/T in get_turf(src))
if(!istype(T, /obj/structure/destructible/clockwork/trap/trigger))
wired_to += T
T.wired_to += src
to_chat(usr, "<span class='alloy'>[src] automatically links with [T] beneath it.</span>")
/obj/structure/destructible/clockwork/trap/trigger/pressure_sensor/Crossed(atom/movable/AM)
if(isliving(AM) && !is_servant_of_ratvar(AM))
var/mob/living/L = AM
if(L.stat || L.m_intent == MOVE_INTENT_WALK || L.lying)
return
audible_message("<i>*click*</i>")
playsound(src, 'sound/items/screwdriver2.ogg', 50, TRUE)
activate()
@@ -0,0 +1,27 @@
//Repeater: Activates every second.
/obj/structure/destructible/clockwork/trap/trigger/repeater
name = "repeater"
desc = "A small black prism with a gem in the center."
clockwork_desc = "A repeater that will send an activation signal every second."
max_integrity = 15 //Fragile!
icon_state = "repeater"
/obj/structure/destructible/clockwork/trap/trigger/repeater/attack_hand(mob/living/user)
if(!is_servant_of_ratvar(user))
return
if(!isprocessing)
START_PROCESSING(SSprocessing, src)
to_chat(user, "<span class='notice'>You activate [src].</span>")
icon_state = "[icon_state]_on"
else
STOP_PROCESSING(SSprocessing, src)
to_chat(user, "<span class='notice'>You halt [src]'s ticking.</span>")
icon_state = initial(icon_state)
/obj/structure/destructible/clockwork/trap/trigger/repeater/process()
activate()
playsound(src, 'sound/items/screwdriver2.ogg', 25, FALSE)
/obj/structure/destructible/clockwork/trap/trigger/repeater/Destroy()
STOP_PROCESSING(SSprocessing, src)
return ..()
@@ -0,0 +1,106 @@
//Non-servants standing over this will get spikes through the feet, immobilizing them until they're freed.
/obj/structure/destructible/clockwork/trap/brass_skewer
name = "brass skewer"
desc = "A deadly brass spike, cleverly concealed in the floor. You think you should be safe if you disarm whatever's meant to set it off."
clockwork_desc = "A barbaric but undeniably effective weapon: a spear through the chest. It immobilizes anyone unlucky enough to step on it and keeps them in place until they get help.."
icon_state = "brass_skewer"
break_message = "<span class='warning'>The skewer snaps in two!</span>"
max_integrity = 40
density = FALSE
can_buckle = TRUE
buckle_prevents_pull = TRUE
buckle_lying = FALSE
var/wiggle_wiggle
var/mutable_appearance/impale_overlay //This is applied to any mob impaled so that they visibly have the skewer coming through their chest
/obj/structure/destructible/clockwork/trap/brass_skewer/Initialize()
. = ..()
START_PROCESSING(SSfastprocess, src)
/obj/structure/destructible/clockwork/trap/brass_skewer/Destroy()
STOP_PROCESSING(SSfastprocess, src)
if(buckled_mobs && buckled_mobs.len)
var/mob/living/L = buckled_mobs[1]
L.Knockdown(100)
L.visible_message("<span class='warning'>[L] is maimed as the skewer shatters while still in their body!</span>")
L.adjustBruteLoss(15)
unbuckle_mob(L)
return ..()
/obj/structure/destructible/clockwork/trap/brass_skewer/process()
if(density)
if(buckled_mobs.len)
var/mob/living/spitroast = buckled_mobs[1]
spitroast.adjustBruteLoss(0.1)
/obj/structure/destructible/clockwork/trap/attackby(obj/item/I, mob/living/user, params)
if(user in buckled_mobs)
to_chat(user, "<span class='warning'>You can't reach!</span>")
return
..()
/obj/structure/destructible/clockwork/trap/brass_skewer/bullet_act(obj/item/projectile/P)
if(buckled_mobs.len)
var/mob/living/L = buckled_mobs[1]
return L.bullet_act(P)
return ..()
/obj/structure/destructible/clockwork/trap/brass_skewer/activate()
if(density)
return
var/mob/living/carbon/squirrel = locate() in get_turf(src)
if(squirrel)
squirrel.visible_message("<span class='boldwarning'>A massive brass spike erupts from the ground, impaling [squirrel]!</span>", \
"<span class='userdanger'>A massive brass spike rams through your chest, hoisting you into the air!</span>")
squirrel.emote("scream")
playsound(squirrel, 'sound/effects/splat.ogg', 50, TRUE)
playsound(squirrel, 'sound/misc/desceration-03.ogg', 50, TRUE)
squirrel.apply_damage(20, BRUTE, "chest")
mouse_opacity = MOUSE_OPACITY_OPAQUE //So players can interact with the tile it's on to pull them off
buckle_mob(squirrel, TRUE)
else
visible_message("<span class='danger'>A massive brass spike erupts from the ground!</span>")
playsound(src, 'sound/machines/clockcult/brass_skewer.ogg', 75, FALSE)
icon_state = "[initial(icon_state)]_extended"
density = TRUE //Skewers are one-use only
desc = "A vicious brass spike protruding from the ground like a stala[pick("gm", "ct")]ite. It makes you sick to look at." //is stalagmite the ground one? or the ceiling one? who can ever remember?
/obj/structure/destructible/clockwork/trap/brass_skewer/user_buckle_mob()
return
/obj/structure/destructible/clockwork/trap/brass_skewer/post_buckle_mob(mob/living/L)
if(L in buckled_mobs)
L.pixel_y = 3
impale_overlay = mutable_appearance('icons/obj/clockwork_objects.dmi', "brass_skewer_pokeybit", ABOVE_MOB_LAYER)
add_overlay(impale_overlay)
else
L.pixel_y = initial(L.pixel_y)
L.cut_overlay(impale_overlay)
/obj/structure/destructible/clockwork/trap/brass_skewer/user_unbuckle_mob(mob/living/skewee, mob/living/user)
if(user == skewee)
if(wiggle_wiggle)
return
user.visible_message("<span class='warning'>[user] starts wriggling off of [src]!</span>", \
"<span class='danger'>You start agonizingly working your way off of [src]...</span>")
wiggle_wiggle = TRUE
if(!do_after(user, 300, target = user))
user.visible_message("<span class='warning'>[user] slides back down [src]!</span>")
user.emote("scream")
user.apply_damage(10, BRUTE, "chest")
playsound(user, 'sound/misc/desceration-03.ogg', 50, TRUE)
wiggle_wiggle = FALSE
return
wiggle_wiggle = FALSE
else
user.visible_message("<span class='danger'>You start tenderly lifting [user] off of [src]...</span>", \
"<span class='danger'>You start tenderly lifting [user] off of [src]...</span>")
if(!do_after(user, 60, target = skewee))
skewee.visible_message("<span class='warning'>[skewee] painfully slides back down [src].</span>")
skewee.emote("moan")
return
skewee.visible_message("<span class='danger'>[skewee] comes free of [src] with a squelching pop!</span>", \
"<span class='boldannounce'>You come free of [src]!</span>")
skewee.Knockdown(30)
playsound(skewee, 'sound/misc/desceration-03.ogg', 50, TRUE)
unbuckle_mob(skewee)
@@ -0,0 +1,23 @@
//This doesn't function like a "trap" in of itself, but obscures vision when active.
/obj/structure/destructible/clockwork/trap/steam_vent
name = "steam vent"
desc = "Some wired slats embedded in the floor. They feel warm to the touch."
icon_state = "steam_vent_0"
clockwork_desc = "When active, these vents will billow out clouds of excess steam from Reebe, obscuring vision."
break_message = "<span class='warning'>The vent snaps and collapses!</span>"
max_integrity = 100
density = FALSE
/obj/structure/destructible/clockwork/trap/steam_vent/activate()
opacity = !opacity
icon_state = "steam_vent_[opacity]"
if(opacity)
playsound(src, 'sound/machines/clockcult/steam_whoosh.ogg', 50, TRUE)
else
playsound(src, 'sound/machines/clockcult/integration_cog_install.ogg', 50, TRUE)
/obj/structure/destructible/clockwork/trap/steam_vent/Crossed(atom/movable/AM)
if(isliving(AM) && opacity)
var/mob/living/L = AM
L.adjust_fire_stacks(-1) //It's wet!
@@ -698,31 +698,8 @@ Congratulations! You are now trained for invasive xenobiology research!"}
/obj/structure/door_assembly/door_assembly_abductor
name = "alien airlock assembly"
icon = 'icons/obj/doors/airlocks/abductor/abductor_airlock.dmi'
base_name = "alien airlock"
overlays_file = 'icons/obj/doors/airlocks/abductor/overlays.dmi'
typetext = "abductor"
icontext = "abductor"
airlock_type = /obj/machinery/door/airlock/abductor
anchored = TRUE
state = 1
/obj/structure/door_assembly/door_assembly_abductor/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/weldingtool) && !anchored )
var/obj/item/weldingtool/WT = W
if(WT.remove_fuel(0,user))
user.visible_message("<span class='warning'>[user] disassembles the airlock assembly.</span>", \
"You start to disassemble the airlock assembly...")
playsound(src.loc, 'sound/items/welder2.ogg', 50, 1)
if(do_after(user, 40*W.toolspeed, target = src))
if( !WT.isOn() )
return
to_chat(user, "<span class='notice'>You disassemble the airlock assembly.</span>")
new /obj/item/stack/sheet/mineral/abductor(get_turf(src), 4)
qdel(src)
else
return
else if(istype(W, /obj/item/airlock_painter))
return // no repainting
else if(istype(W, /obj/item/stack/sheet))
return // no material modding
else
..()
material_type = /obj/item/stack/sheet/mineral/abductor
noglass = TRUE
@@ -183,6 +183,7 @@
to_chat(H, "<span class='warning'>You feel intensely watched.</span>")
sleep(5)
to_chat(H, "<span class='warning'><b>Your mind snaps!</b></span>")
H.gain_trauma_type(BRAIN_TRAUMA_MILD)
to_chat(H, "<big><span class='warning'><b>You can't remember how you got here...</b></span></big>")
var/objtype = (prob(75) ? /datum/objective/abductee/random : pick(subtypesof(/datum/objective/abductee/) - /datum/objective/abductee/random))
var/datum/objective/abductee/O = new objtype()
@@ -40,7 +40,7 @@
to_chat(src, "<span class='danger'>You begin doggedly resisting the parasite's control (this will take approximately 40 seconds).</span>")
to_chat(B.victim, "<span class='danger'>You feel the captive mind of [src] begin to resist your control.</span>")
var/delay = rand(150,250) + B.victim.brainloss
var/delay = rand(150,250) + B.victim.getBrainLoss()
addtimer(CALLBACK(src, .proc/return_control, src.loc), delay)
/mob/living/captive_brain/proc/return_control(mob/living/simple_animal/borer/B)
@@ -315,7 +315,7 @@ GLOBAL_VAR_INIT(total_borer_hosts_needed, 10)
if(prob(5))
victim.adjustBrainLoss(rand(1,2))
if(prob(victim.brainloss/10))
if(prob(victim.getBrainLoss()/10))
victim.say("*[pick(list("blink","blink_r","choke","aflap","drool","twitch","twitch_s","gasp"))]")
/mob/living/simple_animal/borer/proc/wakeup()
@@ -669,7 +669,7 @@ GLOBAL_VAR_INIT(total_borer_hosts_needed, 10)
bonding = TRUE
var/delay = 200+(victim.brainloss*5)
var/delay = 200+(victim.getBrainLoss()*5)
addtimer(CALLBACK(src, .proc/assume_control), delay)
/mob/living/simple_animal/borer/proc/assume_control()
@@ -1,8 +1,8 @@
/datum/round_event_control/borer
name = "Borer"
typepath = /datum/round_event/borer
weight = 10 //Default weight
max_occurrences = 1
weight = 0
max_occurrences = 0
min_players = 20 //10 is MINIMUM needed, but this is not a gamemode that does well in lowpop
earliest_start = 24000 //40 min, double default timer
@@ -411,6 +411,11 @@
revenant = null
qdel(src)
/obj/item/ectoplasm/revenant/suicide_act(mob/user)
user.visible_message("<span class='suicide'>[user] is inhaling [src]! It looks like [user.p_theyre()] trying to visit the shadow realm!</span>")
scatter()
return (OXYLOSS)
/obj/item/ectoplasm/revenant/Destroy()
if(!QDELETED(revenant))
qdel(revenant)
+14 -5
View File
@@ -551,16 +551,25 @@ This is here to make the tiles around the station mininuke change when it's arme
/obj/item/disk/nuclear/suicide_act(mob/user)
user.visible_message("<span class='suicide'>[user] is going delta! It looks like [user.p_theyre()] trying to commit suicide!</span>")
playsound(user.loc, 'sound/machines/alarm.ogg', 50, -1, 1)
playsound(src, 'sound/machines/alarm.ogg', 50, -1, 1)
for(var/i in 1 to 100)
addtimer(CALLBACK(user, /atom/proc/add_atom_colour, (i % 2)? "#00FF00" : "#FF0000", ADMIN_COLOUR_PRIORITY), i)
addtimer(CALLBACK(user, /atom/proc/remove_atom_colour, ADMIN_COLOUR_PRIORITY), 101)
addtimer(CALLBACK(user, /atom/proc/visible_message, "<span class='suicide'>[user] was destroyed by the nuclear blast!</span>"), 101)
addtimer(CALLBACK(user, /mob/living/proc/adjustOxyLoss, 200), 101)
addtimer(CALLBACK(user, /mob/proc/death, 0), 101)
addtimer(CALLBACK(src, .proc/manual_suicide, user), 101)
return MANUAL_SUICIDE
/obj/item/disk/proc/manual_suicide(mob/living/user)
user.remove_atom_colour(ADMIN_COLOUR_PRIORITY)
user.visible_message("<span class='suicide'>[user] was destroyed by the nuclear blast!</span>")
user.adjustOxyLoss(200)
user.death(0)
/obj/item/disk/fakenucleardisk
name = "cheap plastic imitation of the nuclear authentication disk"
desc = "Broken dreams and a faint odor of cheese."
icon_state = "nucleardisk"
/obj/item/disk/fakenucleardisk/suicide_act(mob/user)
user.visible_message("<span class='suicide'>[user] is pretending to go delta! It looks like [user.p_theyre()] trying to commit suicide!</span>")
playsound(src, 'sound/machines/alarm.ogg', 30, -1, 1)
addtimer(CALLBACK(src, .proc/manual_suicide, user), 101)
return MANUAL_SUICIDE
+3
View File
@@ -897,6 +897,9 @@
to_chat(user,"<span class='warning'>[src] suddenly vanishes!</span>")
qdel(src)
/obj/item/spellbook/oneuse/random
icon_state = "random_book"
/obj/item/spellbook/oneuse/random/Initialize()
..()
var/static/banned_spells = list(/obj/item/spellbook/oneuse/mimery_blockade, /obj/item/spellbook/oneuse/mimery_guns)
+33 -23
View File
@@ -64,7 +64,7 @@
var/obj/machinery/door/airlock/closeOther = null
var/closeOtherId = null
var/lockdownbyai = FALSE
assemblytype = /obj/structure/door_assembly/door_assembly_0
assemblytype = /obj/structure/door_assembly
var/justzap = FALSE
normalspeed = 1
var/obj/item/electronics/airlock/electronics = null
@@ -80,7 +80,7 @@
var/boltUp = 'sound/machines/boltsup.ogg'
var/boltDown = 'sound/machines/boltsdown.ogg'
var/noPower = 'sound/machines/doorclick.ogg'
var/previous_airlock //what airlock assembly mineral plating was applied to
var/airlock_material = null //material of inner filling; if its an airlock with glass, this should be set to "glass"
var/overlays_file = 'icons/obj/doors/airlocks/station/overlays.dmi'
var/note_overlay_file = 'icons/obj/doors/airlocks/station/overlays.dmi' //Used for papers and photos pinned to the airlock
@@ -680,7 +680,7 @@
if(ishuman(user) && prob(40) && src.density)
var/mob/living/carbon/human/H = user
if(H.getBrainLoss() >= 60 && Adjacent(user))
if((H.disabilities & DUMB) && Adjacent(user))
playsound(src.loc, 'sound/effects/bang.ogg', 25, 1)
if(!istype(H.head, /obj/item/clothing/head/helmet))
H.visible_message("<span class='danger'>[user] headbutts the airlock.</span>", \
@@ -1026,14 +1026,6 @@
if(density && !open(2))
to_chat(user, "<span class='warning'>Despite your attempts, [src] refuses to open.</span>")
/obj/machinery/door/airlock/plasma/attackby(obj/item/C, mob/user, params)
if(C.is_hot() > 300)//If the temperature of the object is over 300, then ignite
message_admins("Plasma airlock ignited by [ADMIN_LOOKUPFLW(user)] in [ADMIN_COORDJMP(src)]")
log_game("Plasma wall ignited by [key_name(user)] in [COORD(src)]")
ignite(C.is_hot())
else
return ..()
/obj/machinery/door/airlock/open(forced=0)
if( operating || welded || locked )
return FALSE
@@ -1154,22 +1146,22 @@
var/list/optionlist
if(airlock_material == "glass")
optionlist = list("Public", "Public2", "Engineering", "Atmospherics", "Security", "Command", "Medical", "Research", "Mining", "Maintenance")
optionlist = list("Standard", "Public", "Engineering", "Atmospherics", "Security", "Command", "Medical", "Research", "Science", "Virology", "Mining", "Maintenance", "External", "External Maintenance")
else
optionlist = list("Public", "Engineering", "Atmospherics", "Security", "Command", "Medical", "Research", "Mining", "Maintenance", "External", "High Security")
optionlist = list("Standard", "Public", "Engineering", "Atmospherics", "Security", "Command", "Medical", "Research", "Freezer", "Science", "Virology", "Mining", "Maintenance", "External", "External Maintenance")
var/paintjob = input(user, "Please select a paintjob for this airlock.") in optionlist
if((!in_range(src, usr) && src.loc != usr) || !W.use(user))
return
switch(paintjob)
if("Public")
if("Standard")
icon = 'icons/obj/doors/airlocks/station/public.dmi'
overlays_file = 'icons/obj/doors/airlocks/station/overlays.dmi'
assemblytype = /obj/structure/door_assembly/door_assembly_0
if("Public2")
assemblytype = /obj/structure/door_assembly
if("Public")
icon = 'icons/obj/doors/airlocks/station2/glass.dmi'
overlays_file = 'icons/obj/doors/airlocks/station2/overlays.dmi'
assemblytype = /obj/structure/door_assembly/door_assembly_glass
assemblytype = /obj/structure/door_assembly/door_assembly_public
if("Engineering")
icon = 'icons/obj/doors/airlocks/station/engineering.dmi'
overlays_file = 'icons/obj/doors/airlocks/station/overlays.dmi'
@@ -1194,6 +1186,18 @@
icon = 'icons/obj/doors/airlocks/station/research.dmi'
overlays_file = 'icons/obj/doors/airlocks/station/overlays.dmi'
assemblytype = /obj/structure/door_assembly/door_assembly_research
if("Freezer")
icon = 'icons/obj/doors/airlocks/station/freezer.dmi'
overlays_file = 'icons/obj/doors/airlocks/station/overlays.dmi'
assemblytype = /obj/structure/door_assembly/door_assembly_fre
if("Science")
icon = 'icons/obj/doors/airlocks/station/science.dmi'
overlays_file = 'icons/obj/doors/airlocks/station/overlays.dmi'
assemblytype = /obj/structure/door_assembly/door_assembly_science
if("Virology")
icon = 'icons/obj/doors/airlocks/station/virology.dmi'
overlays_file = 'icons/obj/doors/airlocks/station/overlays.dmi'
assemblytype = /obj/structure/door_assembly/door_assembly_viro
if("Mining")
icon = 'icons/obj/doors/airlocks/station/mining.dmi'
overlays_file = 'icons/obj/doors/airlocks/station/overlays.dmi'
@@ -1206,10 +1210,10 @@
icon = 'icons/obj/doors/airlocks/external/external.dmi'
overlays_file = 'icons/obj/doors/airlocks/external/overlays.dmi'
assemblytype = /obj/structure/door_assembly/door_assembly_ext
if("High Security")
icon = 'icons/obj/doors/airlocks/highsec/highsec.dmi'
overlays_file = 'icons/obj/doors/airlocks/highsec/overlays.dmi'
assemblytype = /obj/structure/door_assembly/door_assembly_highsecurity
if("External Maintenance")
icon = 'icons/obj/doors/airlocks/station/maintenanceexternal.dmi'
overlays_file = 'icons/obj/doors/airlocks/station/overlays.dmi'
assemblytype = /obj/structure/door_assembly/door_assembly_extmai
update_icon()
/obj/machinery/door/airlock/CanAStarPass(obj/item/card/id/ID)
@@ -1302,11 +1306,17 @@
var/obj/structure/door_assembly/A
if(assemblytype)
A = new assemblytype(src.loc)
A.heat_proof_finished = src.heat_proof //tracks whether there's rglass in
else
A = new /obj/structure/door_assembly/door_assembly_0(src.loc)
A = new /obj/structure/door_assembly(loc)
//If you come across a null assemblytype, it will produce the default assembly instead of disintegrating.
A.heat_proof_finished = src.heat_proof //tracks whether there's rglass in
A.anchored = TRUE
A.glass = src.glass
A.state = AIRLOCK_ASSEMBLY_NEEDS_ELECTRONICS
A.created_name = name
A.previous_assembly = previous_airlock
A.update_name()
A.update_icon()
if(!disassembled)
if(A)
+84 -50
View File
@@ -1,6 +1,7 @@
/*
Station Airlocks Regular
*/
/obj/machinery/door/airlock/abandoned
abandoned = TRUE
@@ -17,7 +18,7 @@
/obj/machinery/door/airlock/engineering
icon = 'icons/obj/doors/airlocks/station/engineering.dmi'
assemblytype = /obj/structure/door_assembly/door_assembly_eng
/obj/machinery/door/airlock/engineering/abandoned
abandoned = TRUE
@@ -37,8 +38,7 @@
/obj/machinery/door/airlock/maintenance/external
name = "external airlock access"
icon = 'icons/obj/doors/airlocks/station/maintenanceexternal.dmi'
assemblytype = /obj/structure/door_assembly/door_assembly_mai
normal_integrity = 250
assemblytype = /obj/structure/door_assembly/door_assembly_extmai
/obj/machinery/door/airlock/mining
name = "mining airlock"
@@ -75,23 +75,27 @@
Station Airlocks Glass
*/
/obj/machinery/door/airlock/glass
opacity = 0
glass = TRUE
/obj/machinery/door/airlock/glass_command
icon = 'icons/obj/doors/airlocks/station/command.dmi'
opacity = 0
assemblytype = /obj/structure/door_assembly/door_assembly_com/glass
assemblytype = /obj/structure/door_assembly/door_assembly_com
glass = TRUE
normal_integrity = 400
/obj/machinery/door/airlock/glass_engineering
icon = 'icons/obj/doors/airlocks/station/engineering.dmi'
opacity = 0
assemblytype = /obj/structure/door_assembly/door_assembly_eng/glass
assemblytype = /obj/structure/door_assembly/door_assembly_eng
glass = TRUE
/obj/machinery/door/airlock/glass_security
icon = 'icons/obj/doors/airlocks/station/security.dmi'
opacity = 0
assemblytype = /obj/structure/door_assembly/door_assembly_sec/glass
assemblytype = /obj/structure/door_assembly/door_assembly_sec
glass = TRUE
normal_integrity = 400
@@ -101,45 +105,50 @@
/obj/machinery/door/airlock/glass_medical
icon = 'icons/obj/doors/airlocks/station/medical.dmi'
opacity = 0
assemblytype = /obj/structure/door_assembly/door_assembly_med/glass
assemblytype = /obj/structure/door_assembly/door_assembly_med
glass = TRUE
/obj/machinery/door/airlock/glass_research
icon = 'icons/obj/doors/airlocks/station/research.dmi'
opacity = 0
assemblytype = /obj/structure/door_assembly/door_assembly_research/glass
assemblytype = /obj/structure/door_assembly/door_assembly_research
glass = TRUE
/obj/machinery/door/airlock/glass_mining
icon = 'icons/obj/doors/airlocks/station/mining.dmi'
opacity = 0
assemblytype = /obj/structure/door_assembly/door_assembly_min/glass
assemblytype = /obj/structure/door_assembly/door_assembly_min
glass = TRUE
/obj/machinery/door/airlock/glass_atmos
icon = 'icons/obj/doors/airlocks/station/atmos.dmi'
opacity = 0
assemblytype = /obj/structure/door_assembly/door_assembly_atmo/glass
assemblytype = /obj/structure/door_assembly/door_assembly_atmo
glass = TRUE
/obj/machinery/door/airlock/glass_science
icon = 'icons/obj/doors/airlocks/station/science.dmi'
opacity = 0
assemblytype = /obj/structure/door_assembly/door_assembly_science/glass
assemblytype = /obj/structure/door_assembly/door_assembly_science
glass = TRUE
/obj/machinery/door/airlock/glass_virology
icon = 'icons/obj/doors/airlocks/station/virology.dmi'
opacity = 0
assemblytype = /obj/structure/door_assembly/door_assembly_viro/glass
assemblytype = /obj/structure/door_assembly/door_assembly_viro
glass = TRUE
/obj/machinery/door/airlock/glass_maintenance
icon = 'icons/obj/doors/airlocks/station/maintenance.dmi'
opacity = 0
assemblytype = /obj/structure/door_assembly/door_assembly_mai/glass
assemblytype = /obj/structure/door_assembly/door_assembly_mai
glass = TRUE
/obj/machinery/door/airlock/maintenance/external/glass
opacity = 0
glass = TRUE
normal_integrity = 200
//////////////////////////////////
/*
Station Airlocks Mineral
@@ -148,27 +157,36 @@
/obj/machinery/door/airlock/gold
name = "gold airlock"
icon = 'icons/obj/doors/airlocks/station/gold.dmi'
var/mineral = "gold"
assemblytype = /obj/structure/door_assembly/door_assembly_gold
/obj/machinery/door/airlock/gold/glass
opacity = 0
glass = TRUE
/obj/machinery/door/airlock/silver
name = "silver airlock"
icon = 'icons/obj/doors/airlocks/station/silver.dmi'
var/mineral = "silver"
assemblytype = /obj/structure/door_assembly/door_assembly_silver
/obj/machinery/door/airlock/silver/glass
opacity = 0
glass = TRUE
/obj/machinery/door/airlock/diamond
name = "diamond airlock"
icon = 'icons/obj/doors/airlocks/station/diamond.dmi'
var/mineral = "diamond"
assemblytype = /obj/structure/door_assembly/door_assembly_diamond
normal_integrity = 1000
explosion_block = 2
/obj/machinery/door/airlock/diamond/glass
normal_integrity = 950
opacity = 0
glass = TRUE
/obj/machinery/door/airlock/uranium
name = "uranium airlock"
icon = 'icons/obj/doors/airlocks/station/uranium.dmi'
var/mineral = "uranium"
assemblytype = /obj/structure/door_assembly/door_assembly_uranium
var/last_event = 0
@@ -183,11 +201,14 @@
radiation_pulse(get_turf(src), 150)
return
/obj/machinery/door/airlock/uranium/glass
opacity = 0
glass = TRUE
/obj/machinery/door/airlock/plasma
name = "plasma airlock"
desc = "No way this can end badly."
icon = 'icons/obj/doors/airlocks/station/plasma.dmi'
var/mineral = "plasma"
assemblytype = /obj/structure/door_assembly/door_assembly_plasma
/obj/machinery/door/airlock/plasma/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
@@ -200,62 +221,84 @@
/obj/machinery/door/airlock/plasma/proc/PlasmaBurn(temperature)
atmos_spawn_air("plasma=500;TEMP=1000")
new/obj/structure/door_assembly/door_assembly_0( src.loc )
var/obj/structure/door_assembly/DA
DA = new /obj/structure/door_assembly(loc)
if(glass)
DA.glass = TRUE
if(heat_proof)
DA.heat_proof_finished = TRUE
DA.update_icon()
DA.update_name()
qdel(src)
/obj/machinery/door/airlock/plasma/BlockSuperconductivity() //we don't stop the heat~
return 0
/obj/machinery/door/airlock/plasma/attackby(obj/item/C, mob/user, params)
if(C.is_hot() > 300)//If the temperature of the object is over 300, then ignite
message_admins("Plasma airlock ignited by [ADMIN_LOOKUPFLW(user)] in [ADMIN_COORDJMP(src)]")
log_game("Plasma airlock ignited by [key_name(user)] in [COORD(src)]")
ignite(C.is_hot())
else
return ..()
/obj/machinery/door/airlock/plasma/glass
opacity = 0
glass = TRUE
/obj/machinery/door/airlock/clown
name = "bananium airlock"
desc = "Honkhonkhonk"
icon = 'icons/obj/doors/airlocks/station/bananium.dmi'
var/mineral = "bananium"
assemblytype = /obj/structure/door_assembly/door_assembly_bananium
doorOpen = 'sound/items/bikehorn.ogg'
assemblytype = /obj/structure/door_assembly/door_assembly_clown
/obj/machinery/door/airlock/clown/glass
opacity = 0
glass = TRUE
/obj/machinery/door/airlock/sandstone
name = "sandstone airlock"
icon = 'icons/obj/doors/airlocks/station/sandstone.dmi'
var/mineral = "sandstone"
assemblytype = /obj/structure/door_assembly/door_assembly_sandstone
/obj/machinery/door/airlock/sandstone/glass
opacity = 0
glass = TRUE
/obj/machinery/door/airlock/wood
name = "wooden airlock"
icon = 'icons/obj/doors/airlocks/station/wood.dmi'
var/mineral = "wood"
assemblytype = /obj/structure/door_assembly/door_assembly_wood
/obj/machinery/door/airlock/wood/glass
opacity = 0
glass = TRUE
/obj/machinery/door/airlock/titanium
name = "shuttle airlock"
var/mineral = "titanium"
assemblytype = /obj/structure/door_assembly/door_assembly_titanium
icon = 'icons/obj/doors/airlocks/shuttle/shuttle.dmi'
overlays_file = 'icons/obj/doors/airlocks/shuttle/overlays.dmi'
assemblytype = /obj/structure/door_assembly/door_assembly_titanium
normal_integrity = 400
/obj/machinery/door/airlock/glass_titanium
name = "shuttle airlock"
var/mineral = "titanium"
icon = 'icons/obj/doors/airlocks/shuttle/shuttle.dmi'
overlays_file = 'icons/obj/doors/airlocks/shuttle/overlays.dmi'
opacity = 0
assemblytype = /obj/structure/door_assembly/door_assembly_titanium/glass
glass = TRUE
/obj/machinery/door/airlock/titanium/glass
normal_integrity = 350
opacity = 0
glass = TRUE
//////////////////////////////////
/*
Station2 Airlocks
*/
/obj/machinery/door/airlock/glass
name = "glass airlock"
/obj/machinery/door/airlock/public
icon = 'icons/obj/doors/airlocks/station2/glass.dmi'
overlays_file = 'icons/obj/doors/airlocks/station2/overlays.dmi'
assemblytype = /obj/structure/door_assembly/door_assembly_public
/obj/machinery/door/airlock/public/glass
opacity = 0
assemblytype = /obj/structure/door_assembly/door_assembly_glass
glass = TRUE
//////////////////////////////////
@@ -269,13 +312,8 @@
overlays_file = 'icons/obj/doors/airlocks/external/overlays.dmi'
note_overlay_file = 'icons/obj/doors/airlocks/external/overlays.dmi'
assemblytype = /obj/structure/door_assembly/door_assembly_ext
explosion_block = 1
/obj/machinery/door/airlock/glass_external
name = "external airlock"
icon = 'icons/obj/doors/airlocks/external/external.dmi'
overlays_file = 'icons/obj/doors/airlocks/external/overlays.dmi'
assemblytype = /obj/structure/door_assembly/door_assembly_ext/glass
/obj/machinery/door/airlock/external/glass
opacity = 0
glass = TRUE
@@ -287,7 +325,6 @@
/obj/machinery/door/airlock/centcom
icon = 'icons/obj/doors/airlocks/centcom/centcom.dmi'
overlays_file = 'icons/obj/doors/airlocks/centcom/overlays.dmi'
opacity = 1
assemblytype = /obj/structure/door_assembly/door_assembly_centcom
normal_integrity = 1000
security_level = 6
@@ -305,7 +342,6 @@
name = "vault door"
icon = 'icons/obj/doors/airlocks/vault/vault.dmi'
overlays_file = 'icons/obj/doors/airlocks/vault/overlays.dmi'
opacity = 1
assemblytype = /obj/structure/door_assembly/door_assembly_vault
explosion_block = 2
normal_integrity = 400 // reverse engieneerd: 400 * 1.5 (sec lvl 6) = 600 = original
@@ -321,7 +357,6 @@
icon = 'icons/obj/doors/airlocks/hatch/centcom.dmi'
overlays_file = 'icons/obj/doors/airlocks/hatch/overlays.dmi'
note_overlay_file = 'icons/obj/doors/airlocks/hatch/overlays.dmi'
opacity = 1
assemblytype = /obj/structure/door_assembly/door_assembly_hatch
/obj/machinery/door/airlock/maintenance_hatch
@@ -329,7 +364,6 @@
icon = 'icons/obj/doors/airlocks/hatch/maintenance.dmi'
overlays_file = 'icons/obj/doors/airlocks/hatch/overlays.dmi'
note_overlay_file = 'icons/obj/doors/airlocks/hatch/overlays.dmi'
opacity = 1
assemblytype = /obj/structure/door_assembly/door_assembly_mhatch
/obj/machinery/door/airlock/maintenance_hatch/abandoned
@@ -361,6 +395,10 @@
overlays_file = 'icons/obj/doors/airlocks/shuttle/overlays.dmi'
assemblytype = /obj/structure/door_assembly/door_assembly_shuttle
/obj/machinery/door/airlock/shuttle/glass
opacity = 0
glass = TRUE
/obj/machinery/door/airlock/abductor
name = "alien airlock"
desc = "With humanity's current technological level, it could take years to hack this advanced airlock... or maybe we should give a screwdriver a try?"
@@ -369,7 +407,6 @@
assemblytype = /obj/structure/door_assembly/door_assembly_abductor
note_overlay_file = 'icons/obj/doors/airlocks/external/overlays.dmi'
damage_deflection = 30
opacity = 1
explosion_block = 3
hackProof = TRUE
aiControlDisabled = 1
@@ -422,7 +459,6 @@
friendly = TRUE
/obj/machinery/door/airlock/cult/glass
assemblytype = /obj/structure/door_assembly/door_assembly_cult/glass
glass = TRUE
opacity = 0
@@ -439,7 +475,6 @@
friendly = TRUE
/obj/machinery/door/airlock/cult/unruned/glass
assemblytype = /obj/structure/door_assembly/door_assembly_cult/unruned/glass
glass = TRUE
opacity = 0
@@ -452,7 +487,6 @@
desc = "A massive cogwheel set into two heavy slabs of brass."
icon = 'icons/obj/doors/airlocks/clockwork/pinion_airlock.dmi'
overlays_file = 'icons/obj/doors/airlocks/clockwork/overlays.dmi'
opacity = 1
hackProof = TRUE
aiControlDisabled = TRUE
req_access = list(ACCESS_CLOCKCULT)
+38 -39
View File
@@ -1,45 +1,44 @@
/obj/machinery/door/airlock/alarmlock
name = "glass alarm airlock"
icon = 'icons/obj/doors/airlocks/station2/glass.dmi'
overlays_file = 'icons/obj/doors/airlocks/station2/overlays.dmi'
opacity = 0
assemblytype = /obj/structure/door_assembly/door_assembly_glass
/obj/machinery/door/airlock/alarmlock
name = "glass alarm airlock"
icon = 'icons/obj/doors/airlocks/station2/glass.dmi'
overlays_file = 'icons/obj/doors/airlocks/station2/overlays.dmi'
opacity = 0
assemblytype = /obj/structure/door_assembly/door_assembly_public
glass = TRUE
var/datum/radio_frequency/air_connection
var/air_frequency = 1437
var/datum/radio_frequency/air_connection
var/air_frequency = 1437
autoclose = FALSE
/obj/machinery/door/airlock/alarmlock/New()
..()
air_connection = new
/obj/machinery/door/airlock/alarmlock/Destroy()
/obj/machinery/door/airlock/alarmlock/New()
..()
air_connection = new
/obj/machinery/door/airlock/alarmlock/Destroy()
SSradio.remove_object(src,air_frequency)
air_connection = null
return ..()
/obj/machinery/door/airlock/alarmlock/Initialize()
air_connection = null
return ..()
/obj/machinery/door/airlock/alarmlock/Initialize()
. = ..()
SSradio.remove_object(src, air_frequency)
air_connection = SSradio.add_object(src, air_frequency, GLOB.RADIO_TO_AIRALARM)
open()
/obj/machinery/door/airlock/alarmlock/receive_signal(datum/signal/signal)
..()
if(stat & (NOPOWER|BROKEN))
return
var/alarm_area = signal.data["zone"]
var/alert = signal.data["alert"]
var/area/our_area = get_area(src)
if(alarm_area == our_area.name)
switch(alert)
if("severe")
SSradio.remove_object(src, air_frequency)
air_connection = SSradio.add_object(src, air_frequency, GLOB.RADIO_TO_AIRALARM)
open()
/obj/machinery/door/airlock/alarmlock/receive_signal(datum/signal/signal)
..()
if(stat & (NOPOWER|BROKEN))
return
var/alarm_area = signal.data["zone"]
var/alert = signal.data["alert"]
var/area/our_area = get_area(src)
if(alarm_area == our_area.name)
switch(alert)
if("severe")
autoclose = TRUE
close()
if("minor", "clear")
close()
if("minor", "clear")
autoclose = FALSE
open()
open()
+5 -5
View File
@@ -138,7 +138,7 @@
if(isnull(amount))
amount = 0
var/atom/temp = new typepath(null)
var/atom/temp = typepath
var/datum/data/vending_product/R = new /datum/data/vending_product()
R.product_name = initial(temp.name)
R.product_path = typepath
@@ -638,7 +638,8 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
/obj/item/reagent_containers/food/drinks/bottle/cream = 4, /obj/item/reagent_containers/food/drinks/soda_cans/tonic = 8,
/obj/item/reagent_containers/food/drinks/soda_cans/cola = 8, /obj/item/reagent_containers/food/drinks/soda_cans/sodawater = 15,
/obj/item/reagent_containers/food/drinks/drinkingglass = 30, /obj/item/reagent_containers/food/drinks/ice = 10,
/obj/item/reagent_containers/food/drinks/drinkingglass/shotglass = 12, /obj/item/reagent_containers/food/drinks/flask = 3)
/obj/item/reagent_containers/food/drinks/drinkingglass/shotglass = 12, /obj/item/reagent_containers/food/drinks/flask = 3,
/obj/item/reagent_containers/food/drinks/beer = 6)
contraband = list(/obj/item/reagent_containers/food/drinks/mug/tea = 12)
product_slogans = "I hope nobody asks me for a bloody cup o' tea...;Alcohol is humanity's friend. Would you abandon a friend?;Quite delighted to serve you!;Is nobody thirsty on this station?"
product_ads = "Drink up!;Booze is good for you!;Alcohol is humanity's best friend.;Quite delighted to serve you!;Care for a nice, cold beer?;Nothing cures you like booze!;Have a sip!;Have a drink!;Have a beer!;Beer is good for you!;Only the finest alcohol!;Best quality booze since 2053!;Award-winning wine!;Maximum alcohol!;Man loves beer.;A toast for progress!"
@@ -678,6 +679,7 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
/obj/machinery/vending/snack/random
name = "\improper Random Snackies"
icon_state = "random_snack"
desc = "Uh oh!"
/obj/machinery/vending/snack/random/Initialize()
@@ -730,6 +732,7 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
/obj/machinery/vending/cola/random
name = "\improper Random Drinkies"
icon_state = "random_cola"
desc = "Uh oh!"
/obj/machinery/vending/cola/random/Initialize()
@@ -1172,8 +1175,6 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
resistance_flags = FIRE_PROOF
refill_canister = /obj/item/vending_refill/donksoft
<<<<<<< HEAD
=======
/obj/machinery/vending/games
name = "\improper Good Clean Fun"
desc = "Vends things that the Captain and Head of Personnel are probably not going to appreciate you fiddling with instead of your job..."
@@ -1188,7 +1189,6 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
refill_canister = /obj/item/vending_refill/games
>>>>>>> 9460277... Merge pull request #33316 from ShizCalev/games-vendor
#undef STANDARD_CHARGE
#undef CONTRABAND_CHARGE
#undef COIN_CHARGE
@@ -169,6 +169,7 @@
<font color="[patient.getFireLoss() < 60 ? "blue" : "red"]"><b>Burn Severity:</b> [patient.getFireLoss()]%</font><br />
<font color="red">[patient.getCloneLoss() ? "Subject appears to have cellular damage." : ""]</font><br />
<font color="red">[patient.getBrainLoss() ? "Significant brain damage detected." : ""]</font><br />
<font color="red">[length(patient.get_traumas()) ? "Brain Traumas detected." : ""]</font><br />
"}
/obj/item/mecha_parts/mecha_equipment/medical/sleeper/proc/get_patient_reagents()
+4 -2
View File
@@ -34,9 +34,11 @@
"Misc"
)
var/datum/component/material_container/materials
/obj/machinery/mecha_part_fabricator/Initialize()
var/datum/component/material_container/materials = AddComponent(/datum/component/material_container,
list(MAT_METAL, MAT_GLASS, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_PLASMA, MAT_URANIUM, MAT_BANANIUM, MAT_TITANIUM, MAT_BLUESPACE),
materials = AddComponent(/datum/component/material_container,
list(MAT_METAL, MAT_GLASS, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_PLASMA, MAT_URANIUM, MAT_BANANIUM, MAT_TITANIUM, MAT_BLUESPACE), 0,
FALSE, list(/obj/item/stack, /obj/item/ore/bluespace_crystal), CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert))
materials.precise_insertion = TRUE
return ..()
+2 -2
View File
@@ -970,7 +970,7 @@
setDir(dir_in)
if(L && L.client)
L.client.change_view(world.view)
L.client.change_view(CONFIG_GET(string/default_view))
zoom_mode = 0
/////////////////////////
@@ -1042,4 +1042,4 @@ GLOBAL_VAR_INIT(year_integer, text2num(year)) // = 2013???
/obj/mecha/update_remote_sight(mob/living/user)
if(occupant_sight_flags)
if(user == occupant)
user.sight |= occupant_sight_flags
user.sight |= occupant_sight_flags
+1 -1
View File
@@ -244,7 +244,7 @@
owner.client.change_view(12)
SEND_SOUND(owner, sound('sound/mecha/imag_enh.ogg',volume=50))
else
owner.client.change_view(world.view) //world.view - default mob view size
owner.client.change_view(CONFIG_GET(string/default_view)) //world.view - default mob view size
UpdateButtonIcon()
/datum/action/innate/mecha/mech_switch_damtype
@@ -253,3 +253,17 @@
. = ..()
animate(src, alpha = 255, time = 50)
//Used by the Eminence to coordinate the cult
/obj/effect/temp_visual/ratvar/command_point
name = "command marker"
desc = "An area of importance marked by the Eminence."
icon = 'icons/mob/actions/actions_clockcult.dmi'
icon_state = "eminence"
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
resistance_flags = INDESTRUCTIBLE
layer = MASSIVE_OBJ_LAYER
duration = 300
/obj/effect/temp_visual/ratvar/command_point/Initialize(mapload, appearance)
. = ..()
icon_state = appearance
@@ -246,6 +246,11 @@
duration = 8
randomdir = 0
/obj/effect/temp_visual/bluespace_fissure
name = "bluespace fissure"
icon_state = "bluestream_fade"
duration = 9
/obj/effect/temp_visual/gib_animation
icon = 'icons/mob/mob.dmi'
duration = 15
+30 -10
View File
@@ -165,10 +165,6 @@ ARCD
if (!ishuman(usr) && !usr.has_unlimited_silicon_privilege)
return ..(usr)
var/mob/living/carbon/human/H = usr
if(H.getBrainLoss() >= 60)
return
var/t1 = text("")
@@ -246,10 +242,12 @@ ARCD
switch(airlockcat)
if("Solid")
if(advanced_airlock_setting == 1)
var/airlockpaint = input(usr, "Select the paintjob of the airlock.") in list("Default", "Engineering", "Atmospherics", "Security", "Command", "Medical", "Research", "Mining", "Maintenance", "External", "High Security")
var/airlockpaint = input(usr, "Select the type of the airlock.") in list("Standard", "Public", "Engineering", "Atmospherics", "Security", "Command", "Medical", "Research", "Freezer", "Science", "Virology", "Mining", "Maintenance", "External", "External Maintenance", "Airtight Hatch", "Maintenance Hatch")
switch(airlockpaint)
if("Default")
if("Standard")
airlock_type = /obj/machinery/door/airlock
if("Public")
airlock_type = /obj/machinery/door/airlock/public
if("Engineering")
airlock_type = /obj/machinery/door/airlock/engineering
if("Atmospherics")
@@ -262,14 +260,24 @@ ARCD
airlock_type = /obj/machinery/door/airlock/medical
if("Research")
airlock_type = /obj/machinery/door/airlock/research
if("Freezer")
airlock_type = /obj/machinery/door/airlock/freezer
if("Science")
airlock_type = /obj/machinery/door/airlock/science
if("Virology")
airlock_type = /obj/machinery/door/airlock/virology
if("Mining")
airlock_type = /obj/machinery/door/airlock/mining
if("Maintenance")
airlock_type = /obj/machinery/door/airlock/maintenance
if("External")
airlock_type = /obj/machinery/door/airlock/external
if("High Security")
airlock_type = /obj/machinery/door/airlock/highsecurity
if("External Maintenance")
airlock_type = /obj/machinery/door/airlock/maintenance/external
if("Airtight Hatch")
airlock_type = /obj/machinery/door/airlock/hatch
if("Maintenance Hatch")
airlock_type = /obj/machinery/door/airlock/maintenance_hatch
airlock_glass = FALSE
else
airlock_type = /obj/machinery/door/airlock
@@ -277,10 +285,12 @@ ARCD
if("Glass")
if(advanced_airlock_setting == 1)
var/airlockpaint = input(usr, "Select the paintjob of the airlock.") in list("Default", "Engineering", "Atmospherics", "Security", "Command", "Medical", "Research", "Mining")
var/airlockpaint = input(usr, "Select the type of the airlock.") in list("Standard", "Public", "Engineering", "Atmospherics", "Security", "Command", "Medical", "Research", "Science", "Virology", "Mining", "Maintenance", "External", "External Maintenance")
switch(airlockpaint)
if("Default")
if("Standard")
airlock_type = /obj/machinery/door/airlock/glass
if("Public")
airlock_type = /obj/machinery/door/airlock/public/glass
if("Engineering")
airlock_type = /obj/machinery/door/airlock/glass_engineering
if("Atmospherics")
@@ -293,8 +303,18 @@ ARCD
airlock_type = /obj/machinery/door/airlock/glass_medical
if("Research")
airlock_type = /obj/machinery/door/airlock/glass_research
if("Science")
airlock_type = /obj/machinery/door/airlock/glass_science
if("Virology")
airlock_type = /obj/machinery/door/airlock/glass_virology
if("Mining")
airlock_type = /obj/machinery/door/airlock/glass_mining
if("Maintenance")
airlock_type = /obj/machinery/door/airlock/glass_maintenance
if("External")
airlock_type = /obj/machinery/door/airlock/external/glass
if("External Maintenance")
airlock_type = /obj/machinery/door/airlock/maintenance/external/glass
airlock_glass = TRUE
else
airlock_type = /obj/machinery/door/airlock/glass
+10
View File
@@ -20,6 +20,16 @@
R.add_fingerprint(user)
qdel(src)
/obj/item/bodybag/suicide_act(mob/user)
if(isopenturf(user.loc))
user.visible_message("<span class='suicide'>[user] is crawling into [src]! It looks like [user.p_theyre()] trying to commit suicide!</span>")
var/obj/structure/closet/body_bag/R = new unfoldedbag_path(user.loc)
R.add_fingerprint(user)
qdel(src)
user.forceMove(R)
playsound(src, 'sound/items/zip.ogg', 15, 1, -3)
return (OXYLOSS)
..()
// Bluespace bodybag
+2
View File
@@ -25,9 +25,11 @@
/obj/item/lipstick/random
name = "lipstick"
icon_state = "random_lipstick"
/obj/item/lipstick/random/New()
..()
icon_state = "lipstick"
colour = pick("red","purple","lime","black","green","blue","white")
name = "[colour] lipstick"
+64 -56
View File
@@ -18,11 +18,11 @@
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 50)
var/on = FALSE //if the paddles are equipped (1) or on the defib (0)
var/safety = 1 //if you can zap people with the defibs on harm mode
var/powered = 0 //if there's a cell in the defib with enough power for a revive, blocks paddles from reviving otherwise
var/safety = TRUE //if you can zap people with the defibs on harm mode
var/powered = FALSE //if there's a cell in the defib with enough power for a revive, blocks paddles from reviving otherwise
var/obj/item/twohanded/shockpaddles/paddles
var/obj/item/stock_parts/cell/high/cell
var/combat = 0 //can we revive through space suits?
var/combat = FALSE //can we revive through space suits?
var/grab_ghost = FALSE // Do we pull the ghost back into their body?
/obj/item/defibrillator/get_cell()
@@ -49,11 +49,11 @@
/obj/item/defibrillator/proc/update_power()
if(cell)
if(cell.charge < paddles.revivecost)
powered = 0
powered = FALSE
else
powered = 1
else
powered = 0
powered = FALSE
/obj/item/defibrillator/proc/update_overlays()
cut_overlays()
@@ -98,8 +98,8 @@
..()
/obj/item/defibrillator/MouseDrop(obj/over_object)
if(ismob(src.loc))
var/mob/M = src.loc
if(ismob(loc))
var/mob/M = loc
if(!M.incapacitated() && istype(over_object, /obj/screen/inventory/hand))
var/obj/screen/inventory/hand/H = over_object
M.putItemFromInventoryInHandIfPossible(src, H.held_index)
@@ -134,23 +134,23 @@
/obj/item/defibrillator/emag_act(mob/user)
if(safety)
safety = 0
safety = FALSE
to_chat(user, "<span class='warning'>You silently disable [src]'s safety protocols with the cryptographic sequencer.</span>")
else
safety = 1
safety = TRUE
to_chat(user, "<span class='notice'>You silently enable [src]'s safety protocols with the cryptographic sequencer.</span>")
/obj/item/defibrillator/emp_act(severity)
if(cell)
deductcharge(1000 / severity)
if(safety)
safety = 0
src.visible_message("<span class='notice'>[src] beeps: Safety protocols disabled!</span>")
playsound(get_turf(src), 'sound/machines/defib_saftyOff.ogg', 50, 0)
safety = FALSE
visible_message("<span class='notice'>[src] beeps: Safety protocols disabled!</span>")
playsound(src, 'sound/machines/defib_saftyOff.ogg', 50, 0)
else
safety = 1
src.visible_message("<span class='notice'>[src] beeps: Safety protocols enabled!</span>")
playsound(get_turf(src), 'sound/machines/defib_saftyOn.ogg', 50, 0)
safety = TRUE
visible_message("<span class='notice'>[src] beeps: Safety protocols enabled!</span>")
playsound(src, 'sound/machines/defib_saftyOn.ogg', 50, 0)
update_icon()
..()
@@ -167,7 +167,7 @@
to_chat(user, "<span class='warning'>You need a free hand to hold the paddles!</span>")
update_icon()
return
paddles.loc = user
paddles.forceMove(user)
else
//Remove from their hands and back onto the defib unit
paddles.unwield()
@@ -207,25 +207,25 @@
/obj/item/defibrillator/proc/deductcharge(chrgdeductamt)
if(cell)
if(cell.charge < (paddles.revivecost+chrgdeductamt))
powered = 0
powered = FALSE
update_icon()
if(cell.use(chrgdeductamt))
update_icon()
return 1
return TRUE
else
update_icon()
return 0
return FALSE
/obj/item/defibrillator/proc/cooldowncheck(mob/user)
spawn(50)
if(cell)
if(cell.charge >= paddles.revivecost)
user.visible_message("<span class='notice'>[src] beeps: Unit ready.</span>")
playsound(get_turf(src), 'sound/machines/defib_ready.ogg', 50, 0)
playsound(src, 'sound/machines/defib_ready.ogg', 50, 0)
else
user.visible_message("<span class='notice'>[src] beeps: Charge depleted.</span>")
playsound(get_turf(src), 'sound/machines/defib_failed.ogg', 50, 0)
paddles.cooldown = 0
playsound(src, 'sound/machines/defib_failed.ogg', 50, 0)
paddles.cooldown = FALSE
paddles.update_icon()
update_icon()
@@ -240,7 +240,7 @@
/obj/item/defibrillator/compact/item_action_slot_check(slot, mob/user)
if(slot == user.getBeltSlot())
return 1
return TRUE
/obj/item/defibrillator/compact/loaded/Initialize()
. = ..()
@@ -251,8 +251,8 @@
/obj/item/defibrillator/compact/combat
name = "combat defibrillator"
desc = "A belt-equipped blood-red defibrillator that can be rapidly deployed. Does not have the restrictions or safeties of conventional defibrillators and can revive through space suits."
combat = 1
safety = 0
combat = TRUE
safety = FALSE
/obj/item/defibrillator/compact/combat/loaded/Initialize()
. = ..()
@@ -280,24 +280,24 @@
w_class = WEIGHT_CLASS_BULKY
var/revivecost = 1000
var/cooldown = 0
var/cooldown = FALSE
var/busy = FALSE
var/obj/item/defibrillator/defib
var/req_defib = 1
var/combat = 0 //If it penetrates armor and gives additional functionality
var/req_defib = TRUE
var/combat = FALSE //If it penetrates armor and gives additional functionality
var/grab_ghost = FALSE
var/tlimit = DEFIB_TIME_LIMIT * 10
/obj/item/twohanded/shockpaddles/proc/recharge(var/time)
if(req_defib || !time)
return
cooldown = 1
cooldown = TRUE
update_icon()
sleep(time)
var/turf/T = get_turf(src)
T.audible_message("<span class='notice'>[src] beeps: Unit is recharged.</span>")
playsound(T, 'sound/machines/defib_ready.ogg', 50, 0)
cooldown = 0
playsound(src, 'sound/machines/defib_ready.ogg', 50, 0)
cooldown = FALSE
update_icon()
/obj/item/twohanded/shockpaddles/New(mainunit)
@@ -318,7 +318,7 @@
user.visible_message("<span class='danger'>[user] is putting the live paddles on [user.p_their()] chest! It looks like [user.p_theyre()] trying to commit suicide!</span>")
if(req_defib)
defib.deductcharge(revivecost)
playsound(get_turf(src), 'sound/machines/defib_zap.ogg', 50, 1, -1)
playsound(src, 'sound/machines/defib_zap.ogg', 50, 1, -1)
return (OXYLOSS)
/obj/item/twohanded/shockpaddles/dropped(mob/user)
@@ -336,12 +336,12 @@
/obj/item/twohanded/shockpaddles/proc/check_defib_exists(mainunit, mob/living/carbon/human/M, obj/O)
if(!req_defib)
return 1 //If it doesn't need a defib, just say it exists
return TRUE //If it doesn't need a defib, just say it exists
if (!mainunit || !istype(mainunit, /obj/item/defibrillator)) //To avoid weird issues from admin spawns
qdel(O)
return 0
return FALSE
else
return 1
return TRUE
/obj/item/twohanded/shockpaddles/attack(mob/M, mob/user)
@@ -349,7 +349,7 @@
return
if(req_defib && !defib.powered)
user.visible_message("<span class='notice'>[defib] beeps: Unit is unpowered.</span>")
playsound(get_turf(src), 'sound/machines/defib_failed.ogg', 50, 0)
playsound(src, 'sound/machines/defib_failed.ogg', 50, 0)
return
if(!wielded)
if(iscyborg(user))
@@ -397,6 +397,13 @@
var/obj/item/organ/brain/BR = H.getorgan(/obj/item/organ/brain)
return (!H.suiciding && !(H.disabilities & NOCLONE) && !H.hellbound && ((world.time - H.timeofdeath) < tlimit) && (H.getBruteLoss() < 180) && (H.getFireLoss() < 180) && H.getorgan(/obj/item/organ/heart) && BR && !BR.damaged_brain)
/obj/item/twohanded/shockpaddles/proc/shock_touching(dmg, mob/H)
if(isliving(H.pulledby)) //CLEAR!
var/mob/living/M = H.pulledby
if(M.electrocute_act(30, src))
M.visible_message("<span class='danger'>[M] is electrocuted by their contact with [H]!</span>")
M.emote("scream")
/obj/item/twohanded/shockpaddles/proc/do_disarm(mob/living/M, mob/living/user)
if(req_defib && defib.safety)
return
@@ -408,12 +415,12 @@
M.adjustStaminaLoss(50)
M.Knockdown(100)
M.updatehealth() //forces health update before next life tick
playsound(get_turf(src), 'sound/machines/defib_zap.ogg', 50, 1, -1)
playsound(src, 'sound/machines/defib_zap.ogg', 50, 1, -1)
M.emote("gasp")
add_logs(user, M, "stunned", src)
if(req_defib)
defib.deductcharge(revivecost)
cooldown = 1
cooldown = TRUE
busy = FALSE
update_icon()
if(req_defib)
@@ -434,7 +441,7 @@
user.visible_message("<span class='notice'>[user] places [src] on [H]'s chest.</span>",
"<span class='warning'>You place [src] on [H]'s chest and begin to charge them.</span>")
var/turf/T = get_turf(defib)
playsound(get_turf(src), 'sound/machines/defib_charge.ogg', 50, 0)
playsound(src, 'sound/machines/defib_charge.ogg', 50, 0)
if(req_defib)
T.audible_message("<span class='warning'>\The [defib] lets out an urgent beep and lets out a steadily rising hum...</span>")
else
@@ -446,14 +453,15 @@
return
if(H && H.stat == DEAD)
to_chat(user, "<span class='warning'>[H] is dead.</span>")
playsound(get_turf(src), 'sound/machines/defib_failed.ogg', 50, 0)
playsound(src, 'sound/machines/defib_failed.ogg', 50, 0)
busy = FALSE
update_icon()
return
user.visible_message("<span class='boldannounce'><i>[user] shocks [H] with \the [src]!</span>", "<span class='warning'>You shock [H] with \the [src]!</span>")
playsound(get_turf(src), 'sound/machines/defib_zap.ogg', 100, 1, -1)
playsound(loc, 'sound/weapons/egloves.ogg', 100, 1, -1)
playsound(src, 'sound/machines/defib_zap.ogg', 100, 1, -1)
playsound(src, 'sound/weapons/egloves.ogg', 100, 1, -1)
H.emote("scream")
shock_touching(45, H)
if(H.can_heartattack() && !H.undergoing_cardiac_arrest())
if(!H.stat)
H.visible_message("<span class='warning'>[H] thrashes wildly, clutching at their chest!</span>",
@@ -465,7 +473,7 @@
H.Jitter(100)
if(req_defib)
defib.deductcharge(revivecost)
cooldown = 1
cooldown = TRUE
busy = FALSE
update_icon()
if(!req_defib)
@@ -481,7 +489,7 @@
update_icon()
if(do_after(user, 30, target = H)) //beginning to place the paddles on patient's chest to allow some time for people to move away to stop the process
user.visible_message("<span class='notice'>[user] places [src] on [H]'s chest.</span>", "<span class='warning'>You place [src] on [H]'s chest.</span>")
playsound(get_turf(src), 'sound/machines/defib_charge.ogg', 50, 0)
playsound(src, 'sound/machines/defib_charge.ogg', 75, 0)
var/tplus = world.time - H.timeofdeath
// past this much time the patient is unrecoverable
// (in deciseconds)
@@ -493,20 +501,20 @@
if(do_after(user, 20, target = H)) //placed on chest and short delay to shock for dramatic effect, revive time is 5sec total
for(var/obj/item/carried_item in H.contents)
if(istype(carried_item, /obj/item/clothing/suit/space))
if((!src.combat && !req_defib) || (req_defib && !defib.combat))
if((!combat && !req_defib) || (req_defib && !defib.combat))
user.audible_message("<span class='warning'>[req_defib ? "[defib]" : "[src]"] buzzes: Patient's chest is obscured. Operation aborted.</span>")
playsound(get_turf(src), 'sound/machines/defib_failed.ogg', 50, 0)
playsound(src, 'sound/machines/defib_failed.ogg', 50, 0)
busy = FALSE
update_icon()
return
if(H.stat == DEAD)
H.visible_message("<span class='warning'>[H]'s body convulses a bit.</span>")
playsound(get_turf(src), "bodyfall", 50, 1)
playsound(get_turf(src), 'sound/machines/defib_zap.ogg', 50, 1, -1)
playsound(src, "bodyfall", 50, 1)
playsound(src, 'sound/machines/defib_zap.ogg', 75, 1, -1)
total_brute = H.getBruteLoss()
total_burn = H.getFireLoss()
var/failed = null
shock_touching(30, H)
var/failed
if (H.suiciding || (H.disabilities & NOCLONE))
failed = "<span class='warning'>[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Recovery of patient impossible. Further attempts futile.</span>"
@@ -527,7 +535,7 @@
if(failed)
user.visible_message(failed)
playsound(get_turf(src), 'sound/machines/defib_failed.ogg', 50, 0)
playsound(src, 'sound/machines/defib_failed.ogg', 50, 0)
else
//If the body has been fixed so that they would not be in crit when defibbed, give them oxyloss to put them back into crit
if (H.health > HALFWAYCRITDEATH)
@@ -541,13 +549,13 @@
H.adjustBruteLoss((mobhealth - HALFWAYCRITDEATH) * (total_brute / overall_damage), 0)
H.updatehealth() // Previous "adjust" procs don't update health, so we do it manually.
user.visible_message("<span class='notice'>[req_defib ? "[defib]" : "[src]"] pings: Resuscitation successful.</span>")
playsound(get_turf(src), 'sound/machines/defib_success.ogg', 50, 0)
playsound(src, 'sound/machines/defib_success.ogg', 50, 0)
H.set_heartattack(FALSE)
H.revive()
H.emote("gasp")
H.Jitter(100)
if(tplus > tloss)
H.setBrainLoss( max(0, min(99, ((tlimit - tplus) / tlimit * 100))))
H.adjustBrainLoss( max(0, min(99, ((tlimit - tplus) / tlimit * 100))), 150)
add_logs(user, H, "revived", defib)
if(req_defib)
defib.deductcharge(revivecost)
@@ -559,16 +567,16 @@
recharge(60)
else if (!H.getorgan(/obj/item/organ/heart))
user.visible_message("<span class='warning'>[req_defib ? "[defib]" : "[src]"] buzzes: Patient's heart is missing. Operation aborted.</span>")
playsound(get_turf(src), 'sound/machines/defib_failed.ogg', 50, 0)
playsound(src, 'sound/machines/defib_failed.ogg', 50, 0)
else if(H.undergoing_cardiac_arrest())
H.set_heartattack(FALSE)
user.visible_message("<span class='notice'>[req_defib ? "[defib]" : "[src]"] pings: Patient's heart is now beating again.</span>")
playsound(get_turf(src), 'sound/machines/defib_zap.ogg', 50, 1, -1)
playsound(src, 'sound/machines/defib_zap.ogg', 50, 1, -1)
else
user.visible_message("<span class='warning'>[req_defib ? "[defib]" : "[src]"] buzzes: Patient is not in a valid state. Operation aborted.</span>")
playsound(get_turf(src), 'sound/machines/defib_failed.ogg', 50, 0)
playsound(src, 'sound/machines/defib_failed.ogg', 50, 0)
busy = FALSE
update_icon()
@@ -95,7 +95,7 @@
to_chat(U, "<span class='notice'>Virus Sent! The unlock code to the target is: [lock_code]</span>")
GET_COMPONENT_FROM(hidden_uplink, /datum/component/uplink, target)
if(!hidden_uplink)
hidden_uplink = target.LoadComponent(/datum/component/uplink)
hidden_uplink = target.AddComponent(/datum/component/uplink)
target.lock_code = lock_code
else
hidden_uplink.hidden_crystals += hidden_uplink.telecrystals //Temporarially hide the PDA's crystals, so you can't steal telecrystals.
@@ -48,7 +48,7 @@
add_fingerprint(user)
if(istype(M) && on && user.zone_selected in list("eyes", "mouth"))
if((user.disabilities & CLUMSY || user.getBrainLoss() >= 60) && prob(50)) //too dumb to use flashlight properly
if((user.disabilities & (CLUMSY | DUMB)) && prob(50)) //too dumb to use flashlight properly
return ..() //just hit them in the head
if(!user.IsAdvancedToolUser())
@@ -488,16 +488,14 @@
/obj/item/device/flashlight/glowstick/random
name = "random colored glowstick"
icon_state = "random_glowstick"
color = null
/obj/item/device/flashlight/glowstick/random/Initialize()
var/list/glowtypes = typesof(/obj/item/device/flashlight/glowstick)
glowtypes -= /obj/item/device/flashlight/glowstick/random
var/obj/item/device/flashlight/glowstick/glowtype = pick(glowtypes)
name = initial(glowtype.name)
color = initial(glowtype.color)
. = ..()
var/T = pick(typesof(/obj/item/device/flashlight/glowstick) - /obj/item/device/flashlight/glowstick/random)
new T(loc)
return INITIALIZE_HINT_QDEL
/obj/item/device/flashlight/spotlight //invisible lighting source
name = "disco light"
+14 -7
View File
@@ -87,7 +87,7 @@ GAS ANALYZER
/obj/item/device/healthanalyzer/attack(mob/living/M, mob/living/carbon/human/user)
// Clumsiness/brain damage check
if ((user.disabilities & CLUMSY || user.getBrainLoss() >= 60) && prob(50))
if ((user.disabilities & (CLUMSY | DUMB)) && prob(50))
to_chat(user, "<span class='notice'>You stupidly try to analyze the floor's vitals!</span>")
user.visible_message("<span class='warning'>[user] has analyzed the floor's vitals!</span>")
to_chat(user, "<span class='info'>Analyzing results for The floor:\n\tOverall status: <b>Healthy</b>")
@@ -152,14 +152,21 @@ GAS ANALYZER
to_chat(user, "\t<span class='alert'>Subject appears to have [M.getCloneLoss() > 30 ? "severe" : "minor"] cellular damage.</span>")
if(advanced)
to_chat(user, "\t<span class='info'>Cellular Damage Level: [M.getCloneLoss()].</span>")
if (M.getBrainLoss() >= 100 || !M.getorgan(/obj/item/organ/brain))
if (M.getBrainLoss() >= 200 || !M.getorgan(/obj/item/organ/brain))
to_chat(user, "\t<span class='alert'>Subject brain function is non-existent.</span>")
else if (M.getBrainLoss() >= 60)
to_chat(user, "\t<span class='alert'>Severe brain damage detected. Subject likely to have mental retardation.</span>")
else if (M.getBrainLoss() >= 10)
to_chat(user, "\t<span class='alert'>Brain damage detected. Subject may have had a concussion.</span>")
else if (M.getBrainLoss() >= 120)
to_chat(user, "\t<span class='alert'>Severe brain damage detected. Subject likely to have mental traumas.</span>")
else if (M.getBrainLoss() >= 45)
to_chat(user, "\t<span class='alert'>Brain damage detected.</span>")
if(iscarbon(M))
var/mob/living/carbon/C = M
if(LAZYLEN(C.get_traumas()))
var/list/trauma_text = list()
for(var/datum/brain_trauma/B in C.get_traumas())
trauma_text += B.scan_desc
to_chat(user, "\t<span class='alert'>Cerebral traumas detected: subjects appears to be suffering from [english_list(trauma_text)].</span>")
if(advanced)
to_chat(user, "\t<span class='info'>Brain Activity Level: [100 - M.getBrainLoss()]%.</span>")
to_chat(user, "\t<span class='info'>Brain Activity Level: [(200 - M.getBrainLoss())/2]%.</span>")
if (M.radiation)
to_chat(user, "\t<span class='alert'>Subject is irradiated.</span>")
if(advanced)
@@ -289,6 +289,9 @@
fix()
//Random colour tapes
/obj/item/device/tape/random
icon_state = "random_tape"
/obj/item/device/tape/random/New()
icon_state = "tape_[pick("white", "blue", "red", "yellow", "purple")]"
..()
+12 -8
View File
@@ -30,6 +30,10 @@
if(special_die == "100")
new /obj/item/dice/d100(src)
/obj/item/storage/pill_bottle/dice/suicide_act(mob/user)
user.visible_message("<span class='suicide'>[user] is gambling with death! It looks like [user.p_theyre()] trying to commit suicide!</span>")
return (OXYLOSS)
/obj/item/dice //depreciated d6, use /obj/item/dice/d6 if you actually want a d6
name = "die"
desc = "A die with six sides. Basic and servicable."
@@ -47,6 +51,10 @@
update_icon()
..()
/obj/item/dice/suicide_act(mob/user)
user.visible_message("<span class='suicide'>[user] is gambling with death! It looks like [user.p_theyre()] trying to commit suicide!</span>")
return (OXYLOSS)
/obj/item/dice/d1
name = "d1"
desc = "A die with one side. Deterministic!"
@@ -65,6 +73,10 @@
icon_state = "d4"
sides = 4
/obj/item/dice/d4/Initialize(mapload)
. = ..()
AddComponent(/datum/component/caltrop, 4)
/obj/item/dice/d6
name = "d6"
@@ -174,14 +186,6 @@
else if(!src.throwing) //Dice was thrown and is coming to rest
visible_message("<span class='notice'>[src] rolls to a stop, landing on [result]. [comment]</span>")
/obj/item/dice/d4/Crossed(mob/living/carbon/human/H)
if(istype(H) && !H.shoes)
if(PIERCEIMMUNE in H.dna.species.species_traits)
return 0
to_chat(H, "<span class='userdanger'>You step on the D4!</span>")
H.apply_damage(4,BRUTE,(pick("l_leg", "r_leg")))
H.Knockdown(60)
/obj/item/dice/update_icon()
cut_overlays()
add_overlay("[src.icon_state][src.result]")
+6 -6
View File
@@ -265,13 +265,13 @@
name = "\improper DNA injector (Smile)"
add_mutations_static = list(SMILE)
/obj/item/dnainjector/unintelligablemut
name = "\improper DNA injector (Unintelligable)"
add_mutations_static = list(UNINTELLIGABLE)
/obj/item/dnainjector/unintelligiblemut
name = "\improper DNA injector (Unintelligible)"
add_mutations_static = list(UNINTELLIGIBLE)
/obj/item/dnainjector/antiunintelligable
name = "\improper DNA injector (Anti-Unintelligable)"
remove_mutations_static = list(UNINTELLIGABLE)
/obj/item/dnainjector/antiunintelligible
name = "\improper DNA injector (Anti-Unintelligible)"
remove_mutations_static = list(UNINTELLIGIBLE)
/obj/item/dnainjector/swedishmut
name = "\improper DNA injector (Swedish)"
@@ -129,6 +129,9 @@
//random clusterbuster spawner
/obj/item/grenade/clusterbuster/random
icon_state = "random_clusterbang"
/obj/item/grenade/clusterbuster/random/New()
var/real_type = pick(subtypesof(/obj/item/grenade/clusterbuster))
new real_type(loc)

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