Merge branch 'master' into upstream-merge-33627

This commit is contained in:
LetterJay
2017-12-27 04:41:27 -06:00
committed by GitHub
758 changed files with 9514 additions and 7191 deletions
+1
View File
@@ -145,6 +145,7 @@
#define ADMIN_PUNISHMENT_GIB "Gib"
#define ADMIN_PUNISHMENT_BSA "Bluespace Artillery Device"
#define ADMIN_PUNISHMENT_FIREBALL "Fireball"
#define ADMIN_PUNISHMENT_ROD "Immovable Rod"
#define AHELP_ACTIVE 1
#define AHELP_CLOSED 2
+6 -4
View File
@@ -9,10 +9,12 @@
#define ANTAG_DATUM_TRAITOR /datum/antagonist/traitor
#define ANTAG_DATUM_TRAITOR_HUMAN /datum/antagonist/traitor/human
#define ANTAG_DATUM_TRAITOR_AI /datum/antagonist/traitor/AI
#define ANTAG_DATUM_IAA /datum/antagonist/traitor/internal_affairs
#define ANTAG_DATUM_IAA /datum/antagonist/traitor/internal_affairs
#define ANTAG_DATUM_IAA_HUMAN /datum/antagonist/traitor/human/internal_affairs
#define ANTAG_DATUM_IAA_AI /datum/antagonist/traitor/AI/internal_affairs
#define ANTAG_DATUM_IAA_AI /datum/antagonist/traitor/AI/internal_affairs
#define ANTAG_DATUM_BROTHER /datum/antagonist/brother
#define ANTAG_DATUM_ABDUCTOR /datum/antagonist/abductor
#define ANTAG_DATUM_ABDUCTOR_SCIENTIST /datum/antagonist/abductor/scientist
#define ANTAG_DATUM_ABDUCTOR_AGENT /datum/antagonist/abductor/agent
#define ANTAG_DATUM_ABDUCTOR_SCIENTIST /datum/antagonist/abductor/scientist
#define ANTAG_DATUM_ABDUCTOR_AGENT /datum/antagonist/abductor/agent
#define ANTAG_DATUM_MONKEY /datum/antagonist/monkey
#define ANTAG_DATUM_MONKEY_LEADER /datum/antagonist/monkey/leader
+6 -2
View File
@@ -12,6 +12,12 @@
//ATMOS
//stuff you should probably leave well alone!
#define R_IDEAL_GAS_EQUATION 8.31 //kPa*L/(K*mol)
#define ONE_ATMOSPHERE 101.325 //kPa
#define T0C 273.15 // 0degC
#define T20C 293.15 // 20degC
#define TCMB 2.7 // -270.3degC
#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
@@ -196,6 +202,4 @@
#define ADD_GAS(gas_id, out_list)\
var/list/tmp_gaslist = GLOB.gaslist_cache[gas_id]; out_list[gas_id] = tmp_gaslist.Copy();
//ASSERT_GAS(gas_id, gas_mixture) - used to guarantee that the gas list for this id exists in gas_mixture.gases.
//Must be used before adding to a gas. May be used before reading from a gas.
#define ASSERT_GAS(gas_id, gas_mixture) if (!gas_mixture.gases[gas_id]) { ADD_GAS(gas_id, gas_mixture.gases) };
-1
View File
@@ -6,7 +6,6 @@
#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)
GLOBAL_VAR_INIT(clockwork_vitality, 0) //How much Vitality is stored, total
GLOBAL_VAR_INIT(clockwork_power, 0) //How many watts of power are globally available to the clockwork cult
+7 -4
View File
@@ -6,9 +6,10 @@
// How multiple components of the exact same type are handled in the same datum
#define COMPONENT_DUPE_HIGHLANDER 0 //old component is deleted (default)
#define COMPONENT_DUPE_ALLOWED 1 //duplicates allowed
#define COMPONENT_DUPE_UNIQUE 2 //new component is deleted
#define COMPONENT_DUPE_HIGHLANDER 0 //old component is deleted (default)
#define COMPONENT_DUPE_ALLOWED 1 //duplicates allowed
#define COMPONENT_DUPE_UNIQUE 2 //new component is deleted
#define COMPONENT_DUPE_UNIQUE_PASSARGS 4 //old component is given the initialization args of the new
// All signals. Format:
// When the signal is called: (signal arguments)
@@ -61,6 +62,8 @@
#define COMSIG_ITEM_ATTACK "item_attack" //from base of obj/item/attack(): (/mob/living/target, /mob/living/user)
#define COMSIG_ITEM_ATTACK_SELF "item_attack_self" //from base of obj/item/attack_self(): (/mob)
#define COMSIG_ITEM_ATTACK_OBJ "item_attack_obj" //from base of obj/item/attack_obj(): (/obj, /mob)
#define COMSIG_ITEM_EQUIPPED "item_equip" //from base of obj/item/equipped(): (/mob/equipper, slot)
#define COMSIG_ITEM_DROPPED "item_drop" //from base of obj/item/dropped(): (/mob/dropper)
// /obj/item/clothing signals
#define COMSIG_SHOES_STEP_ACTION "shoes_step_action" //from base of obj/item/clothing/shoes/proc/step_action(): ()
@@ -77,10 +80,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 COMSIG_HUMAN_DISARM_HIT "human_disarm_hit" //Hit by successful disarm attack (mob/living/carbon/human/attacker,zone_targeted)
#define CALTROP_BYPASS_SHOES 1
#define CALTROP_IGNORE_WALKERS 2
-2
View File
@@ -1,8 +1,6 @@
//config files
#define CONFIG_DEF(X) /datum/config_entry/##X { resident_file = CURRENT_RESIDENT_FILE }; /datum/config_entry/##X
#define CONFIG_GET(X) global.config.Get(/datum/config_entry/##X)
#define CONFIG_SET(X, Y) global.config.Set(/datum/config_entry/##X, ##Y)
#define CONFIG_TWEAK(X) /datum/config_entry/##X
#define CONFIG_MAPS_FILE "maps.txt"
+1 -1
View File
@@ -22,7 +22,7 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
#define ON_BORDER_1 512 // item has priority to check when entering or leaving
#define NOSLIP_1 1024 //prevents from slipping on wet floors, in space etc
#define CLEAN_ON_MOVE_1 2048
#define _UNUSED_1 2048
// BLOCK_GAS_SMOKE_EFFECT_1 only used in masks at the moment.
#define BLOCK_GAS_SMOKE_EFFECT_1 4096 // blocks the effect that chemical clouds would have on a mob --glasses, mask and helmets ONLY!
-27
View File
@@ -1,27 +0,0 @@
#define PI 3.1415
#define SPEED_OF_LIGHT 3e8 //not exact but hey!
#define SPEED_OF_LIGHT_SQ 9e+16
#define INFINITY 1e31 //closer then enough
//atmos
#define R_IDEAL_GAS_EQUATION 8.31 //kPa*L/(K*mol)
#define ONE_ATMOSPHERE 101.325 //kPa
#define T0C 273.15 // 0degC
#define T20C 293.15 // 20degC
#define TCMB 2.7 // -270.3degC
#define SHORT_REAL_LIMIT 16777216
//"fancy" math for calculating time in ms from tick_usage percentage and the length of ticks
//percent_of_tick_used * (ticklag * 100(to convert to ms)) / 100(percent ratio)
//collapsed to percent_of_tick_used * tick_lag
#define TICK_DELTA_TO_MS(percent_of_tick_used) ((percent_of_tick_used) * world.tick_lag)
#define TICK_USAGE_TO_MS(starting_tickusage) (TICK_DELTA_TO_MS(TICK_USAGE_REAL - starting_tickusage))
#define PERCENT(val) (round(val*100, 0.1))
#define CLAMP01(x) (Clamp(x, 0, 1))
//time of day but automatically adjusts to the server going into the next day within the same round.
//for when you need a reliable time number that doesn't depend on byond time.
#define REALTIMEOFDAY (world.timeofday + (MIDNIGHT_ROLLOVER * MIDNIGHT_ROLLOVER_CHECK))
#define MIDNIGHT_ROLLOVER_CHECK ( GLOB.rollovercheck_last_timeofday != world.timeofday ? update_midnight_rollover() : GLOB.midnight_rollovers )
+209
View File
@@ -0,0 +1,209 @@
// Credits to Nickr5 for the useful procs I've taken from his library resource.
// This file is quadruple wrapped for your pleasure
// (
#define NUM_E 2.71828183
#define NUM_SQRT2 1.41421356
#define PI 3.1415
#define SPEED_OF_LIGHT 3e8 //not exact but hey!
#define SPEED_OF_LIGHT_SQ 9e+16
#define INFINITY 1e31 //closer then enough
#define SHORT_REAL_LIMIT 16777216
//"fancy" math for calculating time in ms from tick_usage percentage and the length of ticks
//percent_of_tick_used * (ticklag * 100(to convert to ms)) / 100(percent ratio)
//collapsed to percent_of_tick_used * tick_lag
#define TICK_DELTA_TO_MS(percent_of_tick_used) ((percent_of_tick_used) * world.tick_lag)
#define TICK_USAGE_TO_MS(starting_tickusage) (TICK_DELTA_TO_MS(TICK_USAGE_REAL - starting_tickusage))
#define PERCENT(val) (round((val)*100, 0.1))
#define CLAMP01(x) (CLAMP(x, 0, 1))
//time of day but automatically adjusts to the server going into the next day within the same round.
//for when you need a reliable time number that doesn't depend on byond time.
#define REALTIMEOFDAY (world.timeofday + (MIDNIGHT_ROLLOVER * MIDNIGHT_ROLLOVER_CHECK))
#define MIDNIGHT_ROLLOVER_CHECK ( GLOB.rollovercheck_last_timeofday != world.timeofday ? update_midnight_rollover() : GLOB.midnight_rollovers )
#define SIGN(x) ( (x)!=0 ? (x) / abs(x) : 0 )
#define CEILING(x, y) ( -round(-(x) / (y)) * (y) )
// round() acts like floor(x, 1) by default but can't handle other values
#define FLOOR(x, y) ( round((x) / (y)) * (y) )
#define CLAMP(CLVALUE,CLMIN,CLMAX) ( max( (CLMIN), min((CLVALUE), (CLMAX)) ) )
// Similar to clamp but the bottom rolls around to the top and vice versa. min is inclusive, max is exclusive
#define WRAP(val, min, max) ( min == max ? min : (val) - (round(((val) - (min))/((max) - (min))) * ((max) - (min))) )
// Real modulus that handles decimals
#define MODULUS(x, y) ( (x) - (y) * round((x) / (y)) )
// Tangent
#define TAN(x) (sin(x) / cos(x))
// Cotangent
#define COT(x) (1 / TAN(x))
// Secant
#define SEC(x) (1 / cos(x))
// Cosecant
#define CSC(x) (1 / sin(x))
#define ATAN2(x, y) ( !(x) && !(y) ? 0 : (y) >= 0 ? arccos((x) / sqrt((x)*(x) + (y)*(y))) : -arccos((x) / sqrt((x)*(x) + (y)*(y))) )
// Greatest Common Divisor - Euclid's algorithm
/proc/Gcd(a, b)
return b ? Gcd(b, (a) % (b)) : a
// Least Common Multiple
#define Lcm(a, b) (abs(a) / Gcd(a, b) * abs(b))
#define INVERSE(x) ( 1/(x) )
// Used for calculating the radioactive strength falloff
#define INVERSE_SQUARE(initial_strength,cur_distance,initial_distance) ( (initial_strength)*((initial_distance)**2/(cur_distance)**2) )
#define ISABOUTEQUAL(a, b, deviation) (deviation ? abs((a) - (b)) <= deviation : abs((a) - (b)) <= 0.1)
#define ISEVEN(x) (x % 2 == 0)
#define ISODD(x) (x % 2 != 0)
// Returns true if val is from min to max, inclusive.
#define ISINRANGE(val, min, max) (min <= val && val <= max)
// Same as above, exclusive.
#define ISINRANGE_EX(val, min, max) (min < val && val > max)
#define ISINTEGER(x) (round(x) == x)
#define ISMULTIPLE(x, y) ((x) % (y) == 0)
// Performs a linear interpolation between a and b.
// Note that amount=0 returns a, amount=1 returns b, and
// amount=0.5 returns the mean of a and b.
#define LERP(a, b, amount) (amount ? ((a) + ((b) - (a)) * (amount)) : ((a) + ((b) - (a)) * 0.5)
// Returns the nth root of x.
#define ROOT(n, x) ((x) ** (1 / (n)))
// The quadratic formula. Returns a list with the solutions, or an empty list
// if they are imaginary.
/proc/SolveQuadratic(a, b, c)
ASSERT(a)
. = list()
var/d = b*b - 4 * a * c
var/bottom = 2 * a
if(d < 0)
return
var/root = sqrt(d)
. += (-b + root) / bottom
if(!d)
return
. += (-b - root) / bottom
#define TODEGREES(radians) ((radians) * 57.2957795)
#define TORADIANS(degrees) ((degrees) * 0.0174532925)
// Will filter out extra rotations and negative rotations
// E.g: 540 becomes 180. -180 becomes 180.
#define SIMPLIFY_DEGREES(degrees) (MODULUS((degrees), 360))
#define GET_ANGLE_OF_INCIDENCE(face, input) (MODULUS((face) - (input), 360))
//A logarithm that converts an integer to a number scaled between 0 and 1.
//Currently, this is used for hydroponics-produce sprite transforming, but could be useful for other transform functions.
#define TRANSFORM_USING_VARIABLE(input, max) ( sin((90*(input))/(max))**2 )
//converts a uniform distributed random number into a normal distributed one
//since this method produces two random numbers, one is saved for subsequent calls
//(making the cost negligble for every second call)
//This will return +/- decimals, situated about mean with standard deviation stddev
//68% chance that the number is within 1stddev
//95% chance that the number is within 2stddev
//98% chance that the number is within 3stddev...etc
#define ACCURACY 10000
/proc/gaussian(mean, stddev)
var/static/gaussian_next
var/R1;var/R2;var/working
if(gaussian_next != null)
R1 = gaussian_next
gaussian_next = null
else
do
R1 = rand(-ACCURACY,ACCURACY)/ACCURACY
R2 = rand(-ACCURACY,ACCURACY)/ACCURACY
working = R1*R1 + R2*R2
while(working >= 1 || working==0)
working = sqrt(-2 * log(working) / working)
R1 *= working
gaussian_next = R2 * working
return (mean + stddev * R1)
#undef ACCURACY
/proc/mouse_angle_from_client(client/client)
var/list/mouse_control = params2list(client.mouseParams)
if(mouse_control["screen-loc"] && client)
var/list/screen_loc_params = splittext(mouse_control["screen-loc"], ",")
var/list/screen_loc_X = splittext(screen_loc_params[1],":")
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.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
var/oy = round(screenviewY/2) - client.pixel_y //"origin" y
var/angle = SIMPLIFY_DEGREES(ATAN2(y - oy, x - ox))
return angle
/proc/get_turf_in_angle(angle, turf/starting, increments)
var/pixel_x = 0
var/pixel_y = 0
for(var/i in 1 to increments)
pixel_x += sin(angle)+16*sin(angle)*2
pixel_y += cos(angle)+16*cos(angle)*2
var/new_x = starting.x
var/new_y = starting.y
while(pixel_x > 16)
pixel_x -= 32
new_x++
while(pixel_x < -16)
pixel_x += 32
new_x--
while(pixel_y > 16)
pixel_y -= 32
new_y++
while(pixel_y < -16)
pixel_y += 32
new_y--
new_x = CLAMP(new_x, 0, world.maxx)
new_y = CLAMP(new_y, 0, world.maxy)
return locate(new_x, new_y, starting.z)
// Returns a list where [1] is all x values and [2] is all y values that overlap between the given pair of rectangles
/proc/get_overlap(x1, y1, x2, y2, x3, y3, x4, y4)
var/list/region_x1 = list()
var/list/region_y1 = list()
var/list/region_x2 = list()
var/list/region_y2 = list()
// These loops create loops filled with x/y values that the boundaries inhabit
// ex: list(5, 6, 7, 8, 9)
for(var/i in min(x1, x2) to max(x1, x2))
region_x1["[i]"] = TRUE
for(var/i in min(y1, y2) to max(y1, y2))
region_y1["[i]"] = TRUE
for(var/i in min(x3, x4) to max(x3, x4))
region_x2["[i]"] = TRUE
for(var/i in min(y3, y4) to max(y3, y4))
region_y2["[i]"] = TRUE
return list(region_x1 & region_x2, region_y1 & region_y2)
// )
+4 -8
View File
@@ -334,9 +334,9 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
#endif
#endif
// Consider these images/atoms as part of the UI/HUD
// Consider these images/atoms as part of the UI/HUD
#define APPEARANCE_UI_IGNORE_ALPHA RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|RESET_ALPHA|PIXEL_SCALE
#define APPEARANCE_UI RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR
#define APPEARANCE_UI RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|PIXEL_SCALE
//Just space
#define SPACE_ICON_STATE "[((x + y) ^ ~(x * y) + z) % 25]"
@@ -444,6 +444,7 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
#define GIBTONITE_ACTIVE 1
#define GIBTONITE_STABLE 2
#define GIBTONITE_DETONATE 3
//for obj explosion block calculation
#define EXPLOSION_BLOCK_PROC -1
@@ -452,8 +453,6 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
#define BEAT_SLOW 2
#define BEAT_NONE 0
#define BEAT_CHANNEL 150
//http://www.byond.com/docs/ref/info.html#/atom/var/mouse_opacity
#define MOUSE_OPACITY_TRANSPARENT 0
#define MOUSE_OPACITY_ICON 1
@@ -484,9 +483,6 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
#define SYRINGE_DRAW 0
#define SYRINGE_INJECT 1
#define RESEARCH_MATERIAL_RECLAMATION_ID "0"
//gold slime core spawning
#define NO_SPAWN 0
#define HOSTILE_SPAWN 1
@@ -495,7 +491,7 @@ 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"
#define BRAIN_DAMAGE_FILE "traumas.json"
//Fullscreen overlay resolution in tiles.
#define FULLSCREEN_OVERLAY_RESOLUTION_X 15
+2 -2
View File
@@ -52,8 +52,8 @@
/*see __DEFINES/inventory.dm for bodypart bitflag defines*/
//Brain Damage defines
#define BRAIN_DAMAGE_MILD 50
#define BRAIN_DAMAGE_SEVERE 120
#define BRAIN_DAMAGE_MILD 20
#define BRAIN_DAMAGE_SEVERE 100
#define BRAIN_DAMAGE_DEATH 200
#define BRAIN_TRAUMA_MILD /datum/brain_trauma/mild
+26 -15
View File
@@ -1,19 +1,30 @@
#define SOLID 1
#define LIQUID 2
#define GAS 3
#define SOLID 1
#define LIQUID 2
#define GAS 3
#define INJECTABLE_1 1024 //Makes reagents addable through droppers and syringes
#define DRAWABLE_1 2048 //If a syringe can draw from it
#define OPENCONTAINER_1 4096 //Is an open container for chemistry purposes
#define TRANSPARENT_1 8192 //Used for non-open containers which you still want to be able to see the reagents off.
#define TOUCH 1 //splashing
#define INGEST 2 //ingestion
#define VAPOR 3 //foam, spray, blob attack
#define PATCH 4 //patches
#define INJECT 5 //injection
// container_type defines
#define INJECTABLE 1 // Makes it possible to add reagents through droppers and syringes.
#define DRAWABLE 2 // Makes it possible to remove reagents through syringes.
#define REFILLABLE 4 // Makes it possible to add reagents through any reagent container.
#define DRAINABLE 8 // Makes it possible to remove reagents through any reagent container.
#define TRANSPARENT 16 // Used on containers which you want to be able to see the reagents off.
#define AMOUNT_VISIBLE 32 // For non-transparent containers that still have the general amount of reagents in them visible.
// Is an open container for all intents and purposes.
#define OPENCONTAINER REFILLABLE | DRAINABLE | TRANSPARENT
#define TOUCH 1 // splashing
#define INGEST 2 // ingestion
#define VAPOR 3 // foam, spray, blob attack
#define PATCH 4 // patches
#define INJECT 5 // injection
//defines passed through to the on_reagent_change proc
#define DEL_REAGENT 1 //reagent deleted (fully cleared)
#define ADD_REAGENT 2 // reagent added
#define REM_REAGENT 3 // reagent removed (may still exist)
#define DEL_REAGENT 1 // reagent deleted (fully cleared)
#define ADD_REAGENT 2 // reagent added
#define REM_REAGENT 3 // reagent removed (may still exist)
+6
View File
@@ -1,4 +1,8 @@
#define RDCONSOLE_UI_MODE_NORMAL 1
#define RDCONSOLE_UI_MODE_EXPERT 2
#define RDCONSOLE_UI_MODE_LIST 3
//RDSCREEN screens
#define RDSCREEN_MENU 0
#define RDSCREEN_TECHDISK 1
@@ -59,3 +63,5 @@
//#define DEPARTMENTAL_FLAG_MINING 128
#define DESIGN_ID_IGNORE "IGNORE_THIS_DESIGN"
#define RESEARCH_MATERIAL_RECLAMATION_ID "__materials"
+1
View File
@@ -17,6 +17,7 @@
#define MODE_HOLOPAD "holopad"
#define MODE_CHANGELING "changeling"
#define MODE_VOCALCORDS "cords"
#define MODE_MONKEY "monkeyhive"
//Spans. Robot speech, italics, etc. Applied in compose_message().
#define SPAN_ROBOT "robot"
+23 -10
View File
@@ -10,16 +10,29 @@
//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
#define BLIND "blind"
#define MUTE "mute"
#define DEAF "deaf"
#define NEARSIGHT "nearsighted"
#define FAT "fat"
#define HUSK "husk"
#define NOCLONE "noclone"
#define CLUMSY "clumsy"
#define DUMB "dumb"
#define MONKEYLIKE "monkeylike" //sets IsAdvancedToolUser to FALSE
#define PACIFISM "pacifism"
// common disability sources
#define EYE_DAMAGE "eye_damage"
#define GENETIC_MUTATION "genetic"
#define STATUE_MUTE "statue"
#define CHANGELING_DRAIN "drain"
#define OBESITY "obesity"
#define MAGIC_DISABILITY "magic"
#define STASIS_MUTE "stasis"
#define GENETICS_SPELL "genetics_spell"
#define TRAUMA_DISABILITY "trauma"
// bitflags for machine stat variable
#define BROKEN 1
+2 -2
View File
@@ -43,8 +43,8 @@
//Returns list element or null. Should prevent "index out of bounds" error.
/proc/listgetindex(list/L, index)
if(LAZYLEN(L))
if(isnum(index) && IsInteger(index))
if(IsInRange(index,1,L.len))
if(isnum(index) && ISINTEGER(index))
if(ISINRANGE(index,1,L.len))
return L[index]
else if(index in L)
return L[index]
-257
View File
@@ -1,257 +0,0 @@
// Credits to Nickr5 for the useful procs I've taken from his library resource.
GLOBAL_VAR_INIT(E, 2.71828183)
GLOBAL_VAR_INIT(Sqrt2, 1.41421356)
// List of square roots for the numbers 1-100.
GLOBAL_LIST_INIT(sqrtTable, list(1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10))
/proc/sign(x)
return x!=0?x/abs(x):0
/proc/Atan2(x, y)
if(!x && !y)
return 0
var/a = arccos(x / sqrt(x*x + y*y))
return y >= 0 ? a : -a
/proc/Ceiling(x, y=1)
return -round(-x / y) * y
/proc/Floor(x, y=1)
return round(x / y) * y
#define Clamp(CLVALUE,CLMIN,CLMAX) ( max( (CLMIN), min((CLVALUE), (CLMAX)) ) )
/proc/Modulus(x, y) //Byond's modulus doesn't work with decimals.
return x - y * round(x / y)
// cotangent
/proc/Cot(x)
return 1 / Tan(x)
// cosecant
/proc/Csc(x)
return 1 / sin(x)
/proc/Default(a, b)
return a ? a : b
// Greatest Common Divisor - Euclid's algorithm
/proc/Gcd(a, b)
return b ? Gcd(b, a % b) : a
/proc/Inverse(x)
return 1 / x
#define InverseSquareLaw(initial_strength,cur_distance,initial_distance) (initial_strength*(initial_distance**2/cur_distance**2))
/proc/IsAboutEqual(a, b, deviation = 0.1)
return abs(a - b) <= deviation
/proc/IsEven(x)
return x % 2 == 0
// Returns true if val is from min to max, inclusive.
/proc/IsInRange(val, min, max)
return min <= val && val <= max
/proc/IsInteger(x)
return round(x) == x
/proc/IsOdd(x)
return !IsEven(x)
/proc/IsMultiple(x, y)
return x % y == 0
// Least Common Multiple
/proc/Lcm(a, b)
return abs(a) / Gcd(a, b) * abs(b)
// Performs a linear interpolation between a and b.
// Note that amount=0 returns a, amount=1 returns b, and
// amount=0.5 returns the mean of a and b.
/proc/Lerp(a, b, amount = 0.5)
return a + (b - a) * amount
//Calculates the sum of a list of numbers.
/proc/Sum(var/list/data)
. = 0
for(var/val in data)
.+= val
//Calculates the mean of a list of numbers.
/proc/Mean(var/list/data)
. = Sum(data) / (data.len)
// Returns the nth root of x.
/proc/Root(n, x)
return x ** (1 / n)
// secant
/proc/Sec(x)
return 1 / cos(x)
// The quadratic formula. Returns a list with the solutions, or an empty list
// if they are imaginary.
/proc/SolveQuadratic(a, b, c)
ASSERT(a)
. = list()
var/d = b*b - 4 * a * c
var/bottom = 2 * a
if(d < 0)
return
var/root = sqrt(d)
. += (-b + root) / bottom
if(!d)
return
. += (-b - root) / bottom
// tangent
/proc/Tan(x)
return sin(x) / cos(x)
/proc/ToDegrees(radians)
// 180 / Pi
return radians * 57.2957795
/proc/ToRadians(degrees)
// Pi / 180
return degrees * 0.0174532925
// Will filter out extra rotations and negative rotations
// E.g: 540 becomes 180. -180 becomes 180.
/proc/SimplifyDegrees(degrees)
degrees = degrees % 360
if(degrees < 0)
degrees += 360
return degrees
// min is inclusive, max is exclusive
/proc/Wrap(val, min, max)
var/d = max - min
var/t = round((val - min) / d)
return val - (t * d)
#define NORM_ROT(rot) ((((rot % 360) + (rot - round(rot, 1))) >= 0) ? ((rot % 360) + (rot - round(rot, 1))) : (((rot % 360) + (rot - round(rot, 1))) + 360))
/proc/get_angle_of_incidence(face_angle, angle_in, auto_normalize = TRUE)
var/angle_in_s = NORM_ROT(angle_in)
var/face_angle_s = NORM_ROT(face_angle)
var/incidence = face_angle_s - angle_in_s
var/incidence_s = incidence
while(incidence_s < -90)
incidence_s += 180
while(incidence_s > 90)
incidence_s -= 180
if(auto_normalize)
return incidence_s
else
return incidence
//A logarithm that converts an integer to a number scaled between 0 and 1 (can be tweaked to be higher).
//Currently, this is used for hydroponics-produce sprite transforming, but could be useful for other transform functions.
/proc/TransformUsingVariable(input, inputmaximum, scaling_modifier = 0)
var/inputToDegrees = (input/inputmaximum)*180 //Converting from a 0 -> 100 scale to a 0 -> 180 scale. The 0 -> 180 scale corresponds to degrees
var/size_factor = ((-cos(inputToDegrees) +1) /2) //returns a value from 0 to 1
return size_factor + scaling_modifier //scale mod of 0 results in a number from 0 to 1. A scale modifier of +0.5 returns 0.5 to 1.5
//converts a uniform distributed random number into a normal distributed one
//since this method produces two random numbers, one is saved for subsequent calls
//(making the cost negligble for every second call)
//This will return +/- decimals, situated about mean with standard deviation stddev
//68% chance that the number is within 1stddev
//95% chance that the number is within 2stddev
//98% chance that the number is within 3stddev...etc
#define ACCURACY 10000
/proc/gaussian(mean, stddev)
var/static/gaussian_next
var/R1;var/R2;var/working
if(gaussian_next != null)
R1 = gaussian_next
gaussian_next = null
else
do
R1 = rand(-ACCURACY,ACCURACY)/ACCURACY
R2 = rand(-ACCURACY,ACCURACY)/ACCURACY
working = R1*R1 + R2*R2
while(working >= 1 || working==0)
working = sqrt(-2 * log(working) / working)
R1 *= working
gaussian_next = R2 * working
return (mean + stddev * R1)
#undef ACCURACY
/proc/mouse_angle_from_client(client/client)
var/list/mouse_control = params2list(client.mouseParams)
if(mouse_control["screen-loc"] && client)
var/list/screen_loc_params = splittext(mouse_control["screen-loc"], ",")
var/list/screen_loc_X = splittext(screen_loc_params[1],":")
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.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
var/oy = round(screenviewY/2) - client.pixel_y //"origin" y
var/angle = NORM_ROT(Atan2(y - oy, x - ox))
return angle
/proc/get_turf_in_angle(angle, turf/starting, increments)
var/pixel_x = 0
var/pixel_y = 0
for(var/i in 1 to increments)
pixel_x += sin(angle)+16*sin(angle)*2
pixel_y += cos(angle)+16*cos(angle)*2
var/new_x = starting.x
var/new_y = starting.y
while(pixel_x > 16)
pixel_x -= 32
new_x++
while(pixel_x < -16)
pixel_x += 32
new_x--
while(pixel_y > 16)
pixel_y -= 32
new_y++
while(pixel_y < -16)
pixel_y += 32
new_y--
new_x = Clamp(new_x, 0, world.maxx)
new_y = Clamp(new_y, 0, world.maxy)
return locate(new_x, new_y, starting.z)
/proc/round_down(num)
if(round(num) != num)
return round(num--)
else return num
//proc/get_overlap()
// Returns a list where [1] is all x values and [2] is all y values that overlap between the given pair of rectangles
/proc/get_overlap(x1, y1, x2, y2, x3, y3, x4, y4)
var/list/region_x1 = list()
var/list/region_y1 = list()
var/list/region_x2 = list()
var/list/region_y2 = list()
// These loops create loops filled with x/y values that the boundaries inhabit
// ex: list(5, 6, 7, 8, 9)
for(var/i in min(x1, x2) to max(x1, x2))
region_x1["[i]"] = TRUE
for(var/i in min(y1, y2) to max(y1, y2))
region_y1["[i]"] = TRUE
for(var/i in min(x3, x4) to max(x3, x4))
region_x2["[i]"] = TRUE
for(var/i in min(y3, y4) to max(y3, y4))
region_y2["[i]"] = TRUE
return list(region_x1 & region_x2, region_y1 & region_y2)
+1 -5
View File
@@ -121,9 +121,6 @@ GLOBAL_VAR(command_name)
return new_station_name
/proc/syndicate_name()
var/static/syndicate_name
if (syndicate_name)
return syndicate_name
var/name = ""
@@ -146,8 +143,7 @@ GLOBAL_VAR(command_name)
else
name += pick("-", "*", "")
name += pick("Tech", "Sun", "Co", "Tek", "X", "Inc", "Gen", "Star", "Dyne", "Code", "Hive")
syndicate_name = name
return name
+14 -14
View File
@@ -1,14 +1,14 @@
// Ensure the frequency is within bounds of what it should be sending/recieving at
/proc/sanitize_frequency(frequency, free = FALSE)
. = round(frequency)
if(free)
. = Clamp(frequency, MIN_FREE_FREQ, MAX_FREE_FREQ)
else
. = Clamp(frequency, MIN_FREQ, MAX_FREQ)
if(!(. % 2)) // Ensure the last digit is an odd number
. += 1
// Format frequency by moving the decimal.
/proc/format_frequency(frequency)
frequency = text2num(frequency)
return "[round(frequency / 10)].[frequency % 10]"
// Ensure the frequency is within bounds of what it should be sending/recieving at
/proc/sanitize_frequency(frequency, free = FALSE)
. = round(frequency)
if(free)
. = CLAMP(frequency, MIN_FREE_FREQ, MAX_FREE_FREQ)
else
. = CLAMP(frequency, MIN_FREQ, MAX_FREQ)
if(!(. % 2)) // Ensure the last digit is an odd number
. += 1
// Format frequency by moving the decimal.
/proc/format_frequency(frequency)
frequency = text2num(frequency)
return "[round(frequency / 10)].[frequency % 10]"
+420
View File
@@ -0,0 +1,420 @@
/datum/controller/subsystem/ticker/proc/gather_roundend_feedback()
var/clients = GLOB.player_list.len
var/surviving_humans = 0
var/surviving_total = 0
var/ghosts = 0
var/escaped_humans = 0
var/escaped_total = 0
for(var/mob/M in GLOB.player_list)
if(ishuman(M))
if(!M.stat)
surviving_humans++
if(M.z == ZLEVEL_CENTCOM)
escaped_humans++
if(!M.stat)
surviving_total++
if(M.z == ZLEVEL_CENTCOM)
escaped_total++
if(isobserver(M))
ghosts++
if(clients)
SSblackbox.record_feedback("nested tally", "round_end_stats", clients, list("clients"))
if(ghosts)
SSblackbox.record_feedback("nested tally", "round_end_stats", ghosts, list("ghosts"))
if(surviving_humans)
SSblackbox.record_feedback("nested tally", "round_end_stats", surviving_humans, list("survivors", "human"))
if(surviving_total)
SSblackbox.record_feedback("nested tally", "round_end_stats", surviving_total, list("survivors", "total"))
if(escaped_humans)
SSblackbox.record_feedback("nested tally", "round_end_stats", escaped_humans, list("escapees", "human"))
if(escaped_total)
SSblackbox.record_feedback("nested tally", "round_end_stats", escaped_total, list("escapees", "total"))
gather_antag_success_rate()
/datum/controller/subsystem/ticker/proc/gather_antag_success_rate()
var/team_gid = 1
var/list/team_ids = list()
for(var/datum/antagonist/A in GLOB.antagonists)
var/list/antag_info = list()
antag_info["key"] = A.owner.key
antag_info["name"] = A.owner.name
antag_info["antagonist_type"] = A.type
antag_info["antagonist_name"] = A.name //For auto and custom roles
antag_info["objectives"] = list()
antag_info["team"] = list()
var/datum/team/T = A.get_team()
if(T)
antag_info["team"]["type"] = T.type
antag_info["team"]["name"] = T.name
if(!team_ids[T])
team_ids[T] = team_gid++
antag_info["team"]["id"] = team_ids[T]
if(!A.owner)
continue
if(A.objectives.len)
for(var/datum/objective/O in A.objectives)
var/result = O.check_completion() ? "SUCCESS" : "FAIL"
antag_info["objectives"] += list(list("objective_type"=O.type,"text"=O.explanation_text,"result"=result))
SSblackbox.record_feedback("associative", "antagonists", 1, antag_info)
/datum/controller/subsystem/ticker/proc/declare_completion()
set waitfor = FALSE
to_chat(world, "<BR><BR><BR><FONT size=3><B>The round has ended.</B></FONT>")
if(LAZYLEN(GLOB.round_end_notifiees))
send2irc("Notice", "[GLOB.round_end_notifiees.Join(", ")] the round has ended.")
/*for(var/client/C in GLOB.clients)
if(!C.credits)
C.RollCredits()
C.playtitlemusic(40)*/
display_report()
gather_roundend_feedback()
CHECK_TICK
// Add AntagHUD to everyone, see who was really evil the whole time!
for(var/datum/atom_hud/antag/H in GLOB.huds)
for(var/m in GLOB.player_list)
var/mob/M = m
H.add_hud_to(M)
CHECK_TICK
//Set news report and mode result
mode.set_round_result()
send2irc("Server", "Round just ended.")
if(CONFIG_GET(string/cross_server_address))
send_news_report()
CHECK_TICK
//These need update to actually reflect the real antagonists
//Print a list of antagonists to the server log
var/list/total_antagonists = list()
//Look into all mobs in world, dead or alive
for(var/datum/mind/Mind in minds)
var/temprole = Mind.special_role
if(temprole) //if they are an antagonist of some sort.
if(temprole in total_antagonists) //If the role exists already, add the name to it
total_antagonists[temprole] += ", [Mind.name]([Mind.key])"
else
total_antagonists.Add(temprole) //If the role doesnt exist in the list, create it and add the mob
total_antagonists[temprole] += ": [Mind.name]([Mind.key])"
CHECK_TICK
//Now print them all into the log!
log_game("Antagonists at round end were...")
for(var/i in total_antagonists)
log_game("[i]s[total_antagonists[i]].")
CHECK_TICK
//Collects persistence features
if(mode.allow_persistence_save)
SSpersistence.CollectData()
//stop collecting feedback during grifftime
SSblackbox.Seal()
sleep(50)
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
CRASH("Attempted standard reboot without ticker roundend completion")
//Common part of the report
/datum/controller/subsystem/ticker/proc/build_roundend_report()
var/list/parts = list()
//Gamemode specific things. Should be empty most of the time.
parts += mode.special_report()
CHECK_TICK
//AI laws
parts += law_report()
CHECK_TICK
//Antagonists
parts += antag_report()
CHECK_TICK
//Medals
parts += medal_report()
//Station Goals
parts += goal_report()
listclearnulls(parts)
return parts.Join()
/datum/controller/subsystem/ticker/proc/survivor_report()
var/list/parts = list()
var/station_evacuated = EMERGENCY_ESCAPED_OR_ENDGAMED
var/num_survivors = 0
var/num_escapees = 0
var/num_shuttle_escapees = 0
//Player status report
for(var/i in GLOB.mob_list)
var/mob/Player = i
if(Player.mind && !isnewplayer(Player))
if(Player.stat != DEAD && !isbrain(Player))
num_survivors++
if(station_evacuated) //If the shuttle has already left the station
var/list/area/shuttle_areas
if(SSshuttle && SSshuttle.emergency)
shuttle_areas = SSshuttle.emergency.shuttle_areas
if(Player.onCentCom() || Player.onSyndieBase())
num_escapees++
if(shuttle_areas[get_area(Player)])
num_shuttle_escapees++
//Round statistics report
var/datum/station_state/end_state = new /datum/station_state()
end_state.count()
var/station_integrity = min(PERCENT(GLOB.start_state.score(end_state)), 100)
parts += "[GLOB.TAB]Shift Duration: <B>[DisplayTimeText(world.time - SSticker.round_start_time)]</B>"
parts += "[GLOB.TAB]Station Integrity: <B>[mode.station_was_nuked ? "<span class='redtext'>Destroyed</span>" : "[station_integrity]%"]</B>"
var/total_players = GLOB.joined_player_list.len
if(total_players)
parts+= "[GLOB.TAB]Total Population: <B>[total_players]</B>"
if(station_evacuated)
parts += "<BR>[GLOB.TAB]Evacuation Rate: <B>[num_escapees] ([PERCENT(num_escapees/total_players)]%)</B>"
parts += "[GLOB.TAB](on emergency shuttle): <B>[num_shuttle_escapees] ([PERCENT(num_shuttle_escapees/total_players)]%)</B>"
parts += "[GLOB.TAB]Survival Rate: <B>[num_survivors] ([PERCENT(num_survivors/total_players)]%)</B>"
return parts.Join("<br>")
/datum/controller/subsystem/ticker/proc/show_roundend_report(client/C,common_report)
var/list/report_parts = list()
report_parts += personal_report(C)
report_parts += common_report
var/datum/browser/roundend_report = new(C, "roundend")
roundend_report.width = 800
roundend_report.height = 600
roundend_report.set_content(report_parts.Join())
roundend_report.stylesheets = list()
roundend_report.add_stylesheet("roundend",'html/browser/roundend.css')
roundend_report.open(0)
/datum/controller/subsystem/ticker/proc/personal_report(client/C)
var/list/parts = list()
var/mob/M = C.mob
if(M.mind && !isnewplayer(M))
if(M.stat != DEAD && !isbrain(M))
if(EMERGENCY_ESCAPED_OR_ENDGAMED)
if(!M.onCentCom() || !M.onSyndieBase())
parts += "<div class='panel stationborder'>"
parts += "<span class='marooned'>You managed to survive, but were marooned on [station_name()]...</span>"
else
parts += "<div class='panel greenborder'>"
parts += "<span class='greentext'>You managed to survive the events on [station_name()] as [M.real_name].</span>"
else
parts += "<div class='panel greenborder'>"
parts += "<span class='greentext'>You managed to survive the events on [station_name()] as [M.real_name].</span>"
else
parts += "<div class='panel redborder'>"
parts += "<span class='redtext'>You did not survive the events on [station_name()]...</span>"
else
parts += "<div class='panel stationborder'>"
parts += "<br>"
if(GLOB.survivor_report)
parts += GLOB.survivor_report
else
parts += survivor_report()
parts += "</div>"
return parts.Join()
/datum/controller/subsystem/ticker/proc/display_report()
GLOB.common_report = build_roundend_report()
for(var/client/C in GLOB.clients)
show_roundend_report(C,GLOB.common_report)
give_show_report_button(C)
CHECK_TICK
/datum/controller/subsystem/ticker/proc/law_report()
var/list/parts = list()
//Silicon laws report
for (var/i in GLOB.ai_list)
var/mob/living/silicon/ai/aiPlayer = i
if(aiPlayer.mind)
parts += "<b>[aiPlayer.name] (Played by: [aiPlayer.mind.key])'s laws [aiPlayer.stat != DEAD ? "at the end of the round" : "when it was deactivated"] were:</b>"
parts += aiPlayer.laws.get_law_list(include_zeroth=TRUE)
parts += "<b>Total law changes: [aiPlayer.law_change_counter]</b>"
if (aiPlayer.connected_robots.len)
var/robolist = "<b>[aiPlayer.real_name]'s minions were:</b> "
for(var/mob/living/silicon/robot/robo in aiPlayer.connected_robots)
if(robo.mind)
robolist += "[robo.name][robo.stat?" (Deactivated) (Played by: [robo.mind.key]), ":" (Played by: [robo.mind.key]), "]"
parts += "[robolist]"
for (var/mob/living/silicon/robot/robo in GLOB.silicon_mobs)
if (!robo.connected_ai && robo.mind)
if (robo.stat != DEAD)
parts += "<b>[robo.name] (Played by: [robo.mind.key]) survived as an AI-less borg! Its laws were:</b>"
else
parts += "<b>[robo.name] (Played by: [robo.mind.key]) was unable to survive the rigors of being a cyborg without an AI. Its laws were:</b>"
if(robo) //How the hell do we lose robo between here and the world messages directly above this?
parts += robo.laws.get_law_list(include_zeroth=TRUE)
if(parts.len)
return "<div class='panel stationborder'>[parts.Join("<br>")]</div>"
else
return ""
/datum/controller/subsystem/ticker/proc/goal_report()
var/list/parts = list()
if(mode.station_goals.len)
for(var/V in mode.station_goals)
var/datum/station_goal/G = V
parts += G.get_result()
return "<div class='panel stationborder'><ul>[parts.Join()]</ul></div>"
/datum/controller/subsystem/ticker/proc/medal_report()
if(GLOB.commendations.len)
var/list/parts = list()
parts += "<span class='header'>Medal Commendations:</span>"
for (var/com in GLOB.commendations)
parts += com
return "<div class='panel stationborder'>[parts.Join("<br>")]</div>"
return ""
/datum/controller/subsystem/ticker/proc/antag_report()
var/list/result = list()
var/list/all_teams = list()
var/list/all_antagonists = list()
for(var/datum/antagonist/A in GLOB.antagonists)
all_teams |= A.get_team()
all_antagonists += A
for(var/datum/team/T in all_teams)
result += T.roundend_report()
for(var/datum/antagonist/X in all_antagonists)
if(X.get_team() == T)
all_antagonists -= X
result += " "//newline between teams
var/currrent_category
var/datum/antagonist/previous_category
sortTim(all_antagonists, /proc/cmp_antag_category)
for(var/datum/antagonist/A in all_antagonists)
if(!A.show_in_roundend)
continue
if(A.roundend_category != currrent_category)
if(previous_category)
result += previous_category.roundend_report_footer()
result += "</div>"
result += "<div class='panel redborder'>"
result += A.roundend_report_header()
currrent_category = A.roundend_category
previous_category = A
result += A.roundend_report()
result += "<br>"
if(all_antagonists.len)
var/datum/antagonist/last = all_antagonists[all_antagonists.len]
result += last.roundend_report_footer()
result += "</div>"
return result.Join()
/proc/cmp_antag_category(datum/antagonist/A,datum/antagonist/B)
return sorttext(B.roundend_category,A.roundend_category)
/datum/controller/subsystem/ticker/proc/give_show_report_button(client/C)
var/datum/action/report/R = new
C.player_details.player_actions += R
R.Grant(C.mob)
to_chat(C,"<a href='?src=[REF(R)];report=1'>Show roundend report again</a>")
/datum/action/report
name = "Show roundend report"
button_icon_state = "vote"
/datum/action/report/Trigger()
if(owner && GLOB.common_report && SSticker.current_state == GAME_STATE_FINISHED)
SSticker.show_roundend_report(owner.client,GLOB.common_report)
/datum/action/report/IsAvailable()
return 1
/datum/action/report/Topic(href,href_list)
if(usr != owner)
return
if(href_list["report"])
Trigger()
return
/proc/printplayer(datum/mind/ply, fleecheck)
var/text = "<b>[ply.key]</b> was <b>[ply.name]</b> the <b>[ply.assigned_role]</b> and"
if(ply.current)
if(ply.current.stat == DEAD)
text += " <span class='redtext'>died</span>"
else
text += " <span class='greentext'>survived</span>"
if(fleecheck)
var/turf/T = get_turf(ply.current)
if(!T || !(T.z in GLOB.station_z_levels))
text += " while <span class='redtext'>fleeing the station</span>"
if(ply.current.real_name != ply.name)
text += " as <b>[ply.current.real_name]</b>"
else
text += " <span class='redtext'>had their body destroyed</span>"
return text
/proc/printplayerlist(list/players,fleecheck)
var/list/parts = list()
parts += "<ul class='playerlist'>"
for(var/datum/mind/M in players)
parts += "<li>[printplayer(M,fleecheck)]</li>"
parts += "</ul>"
return parts.Join()
/proc/printobjectives(datum/mind/ply)
var/list/objective_parts = list()
var/count = 1
for(var/datum/objective/objective in ply.objectives)
if(objective.check_completion())
objective_parts += "<b>Objective #[count]</b>: [objective.explanation_text] <span class='greentext'>Success!</span>"
else
objective_parts += "<b>Objective #[count]</b>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
count++
return objective_parts.Join("<br>")
+3 -3
View File
@@ -60,7 +60,7 @@ GLOBAL_VAR_INIT(rollovercheck_last_timeofday, 0)
if(!second)
return "0 seconds"
if(second >= 60)
minute = round_down(second/60)
minute = FLOOR(second/60, 1)
second = round(second - (minute*60), 0.1)
second_rounded = TRUE
if(second) //check if we still have seconds remaining to format, or if everything went into minute.
@@ -91,7 +91,7 @@ GLOBAL_VAR_INIT(rollovercheck_last_timeofday, 0)
if(!minute)
return "[second]"
if(minute >= 60)
hour = round_down(minute/60,1)
hour = FLOOR(minute/60, 1)
minute = (minute - (hour*60))
if(minute) //alot simpler from here since you don't have to worry about fractions
if(minute != 1)
@@ -114,7 +114,7 @@ GLOBAL_VAR_INIT(rollovercheck_last_timeofday, 0)
if(!hour)
return "[minute][second]"
if(hour >= 24)
day = round_down(hour/24,1)
day = FLOOR(hour/24, 1)
hour = (hour - (day*24))
if(hour)
if(hour != 1)
+1 -1
View File
@@ -117,7 +117,7 @@
//Converts an angle (degrees) into an ss13 direction
/proc/angle2dir(degree)
degree = SimplifyDegrees(degree)
degree = SIMPLIFY_DEGREES(degree)
switch(degree)
if(0 to 22.5) //north requires two angle ranges
return NORTH
+34 -9
View File
@@ -147,10 +147,10 @@ Turf and target are separate in case you want to teleport some distance from a t
var/line[] = list(locate(px,py,M.z))
var/dx=N.x-px //x distance
var/dy=N.y-py
var/dxabs=abs(dx)//Absolute value of x distance
var/dyabs=abs(dy)
var/sdx=sign(dx) //Sign of x distance (+ or -)
var/sdy=sign(dy)
var/dxabs = abs(dx)//Absolute value of x distance
var/dyabs = abs(dy)
var/sdx = SIGN(dx) //Sign of x distance (+ or -)
var/sdy = SIGN(dy)
var/x=dxabs>>1 //Counters for steps taken, setting to distance/2
var/y=dyabs>>1 //Bit-shifting makes me l33t. It also makes getline() unnessecarrily fast.
var/j //Generic integer for counting
@@ -953,8 +953,8 @@ GLOBAL_LIST_INIT(WALLITEMS_INVERSE, typecacheof(list(
tY = tY[1]
tX = splittext(tX[1], ":")
tX = tX[1]
tX = Clamp(origin.x + text2num(tX) - world.view - 1, 1, world.maxx)
tY = Clamp(origin.y + text2num(tY) - world.view - 1, 1, world.maxy)
tX = CLAMP(origin.x + text2num(tX) - world.view - 1, 1, world.maxx)
tY = CLAMP(origin.y + text2num(tY) - world.view - 1, 1, world.maxy)
return locate(tX, tY, tZ)
/proc/screen_loc2turf(text, turf/origin)
@@ -966,8 +966,8 @@ GLOBAL_LIST_INIT(WALLITEMS_INVERSE, typecacheof(list(
tX = splittext(tZ[2], "-")
tX = text2num(tX[2])
tZ = origin.z
tX = Clamp(origin.x + 7 - tX, 1, world.maxx)
tY = Clamp(origin.y + 7 - tY, 1, world.maxy)
tX = CLAMP(origin.x + 7 - tX, 1, world.maxx)
tY = CLAMP(origin.y + 7 - tY, 1, world.maxy)
return locate(tX, tY, tZ)
/proc/IsValidSrc(datum/D)
@@ -1272,7 +1272,7 @@ proc/pick_closest_path(value, list/matches = get_fancy_list_of_atom_types())
. = 0
var/i = DS2TICKS(initial_delay)
do
. += Ceiling(i*DELTA_CALC)
. += CEILING(i*DELTA_CALC, 1)
sleep(i*world.tick_lag*DELTA_CALC)
i *= 2
while (TICK_USAGE > min(TICK_LIMIT_TO_RUN, Master.current_ticklimit))
@@ -1508,9 +1508,34 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
return "\[[url_encode(thing.tag)]\]"
return "\ref[input]"
// Makes a call in the context of a different usr
// Use sparingly
/world/proc/PushUsr(mob/M, datum/callback/CB)
var/temp = usr
usr = M
. = CB.Invoke()
usr = temp
//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
//datum may be null, but it does need to be a typed var
#define NAMEOF(datum, X) (list(##datum.##X, #X)[2])
#define VARSET_LIST_CALLBACK(target, var_name, var_value) CALLBACK(GLOBAL_PROC, /proc/___callbackvarset, ##target, ##var_name, ##var_value)
//dupe code because dm can't handle 3 level deep macros
#define VARSET_CALLBACK(datum, var, var_value) CALLBACK(GLOBAL_PROC, /proc/___callbackvarset, ##datum, NAMEOF(##datum, ##var), ##var_value)
/proc/___callbackvarset(list_or_datum, var_name, var_value)
if(length(list_or_datum))
list_or_datum[var_name] = var_value
return
var/datum/D = list_or_datum
if(IsAdminAdvancedProcCall())
D.vv_edit_var(var_name, var_value) //same result generally, unless badmemes
else
D.vars[var_name] = var_value
+6 -12
View File
@@ -1,18 +1,12 @@
GLOBAL_VAR_INIT(master_mode, "traitor") //"extended"
GLOBAL_VAR_INIT(secret_force_mode, "secret") // if this is anything but "secret", the secret rotation will forceably choose this mode
GLOBAL_VAR(common_report) //Contains commmon part of roundend report
GLOBAL_VAR(survivor_report) //Contains shared surivor report for roundend report (part of personal report)
GLOBAL_VAR_INIT(wavesecret, 0) // meteor mode, delays wave progression, terrible name
GLOBAL_DATUM(start_state, /datum/station_state) // Used in round-end report
// Cult, needs to be global so admin cultists are functional
GLOBAL_VAR_INIT(blood_target, null) // Cult Master's target or Construct's Master
GLOBAL_DATUM(blood_target_image, /image)
GLOBAL_VAR_INIT(blood_target_reset_timer, null)
GLOBAL_DATUM(sac_mind, /datum/mind)
GLOBAL_VAR_INIT(sac_image, null)
GLOBAL_VAR_INIT(cult_vote_called, FALSE)
GLOBAL_VAR_INIT(cult_mastered, FALSE)
GLOBAL_VAR_INIT(reckoning_complete, FALSE)
GLOBAL_VAR_INIT(sac_complete, FALSE)
GLOBAL_DATUM(cult_narsie, /obj/singularity/narsie/large/cult)
GLOBAL_LIST_EMPTY(summon_spots)
//TODO clear this one up too
GLOBAL_DATUM(cult_narsie, /obj/singularity/narsie/large/cult)
+2
View File
@@ -16,3 +16,5 @@ GLOBAL_VAR_INIT(CHARGELEVEL, 0.001) // Cap for how fast cells charge, as a perce
GLOBAL_LIST_EMPTY(powernets)
GLOBAL_VAR_INIT(bsa_unlock, FALSE) //BSA unlocked by head ID swipes
GLOBAL_LIST_EMPTY(player_details) // ckey -> /datum/player_details
+21 -10
View File
@@ -302,32 +302,41 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
/obj/screen/alert/bloodsense/process()
var/atom/blood_target
if(GLOB.blood_target)
if(!get_turf(GLOB.blood_target))
GLOB.blood_target = null
var/datum/antagonist/cult/antag = mob_viewer.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!antag)
return
var/datum/objective/sacrifice/sac_objective = locate() in antag.cult_team.objectives
if(antag.cult_team.blood_target)
if(!get_turf(antag.cult_team.blood_target))
antag.cult_team.blood_target = null
else
blood_target = GLOB.blood_target
blood_target = antag.cult_team.blood_target
if(Cviewer && Cviewer.seeking && Cviewer.master)
blood_target = Cviewer.master
desc = "Your blood sense is leading you to [Cviewer.master]"
if(!blood_target)
if(!GLOB.sac_complete)
if(sac_objective && !sac_objective.check_completion())
if(icon_state == "runed_sense0")
return
animate(src, transform = null, time = 1, loop = 0)
angle = 0
cut_overlays()
icon_state = "runed_sense0"
desc = "Nar-Sie demands that [GLOB.sac_mind] be sacrificed before the summoning ritual can begin."
add_overlay(GLOB.sac_image)
desc = "Nar-Sie demands that [sac_objective.target] be sacrificed before the summoning ritual can begin."
add_overlay(sac_objective.sac_image)
else
var/datum/objective/eldergod/summon_objective = locate() in antag.cult_team.objectives
if(!summon_objective)
return
if(icon_state == "runed_sense1")
return
animate(src, transform = null, time = 1, loop = 0)
angle = 0
cut_overlays()
icon_state = "runed_sense1"
desc = "The sacrifice is complete, summon Nar-Sie! The summoning can only take place in [english_list(GLOB.summon_spots)]!"
desc = "The sacrifice is complete, summon Nar-Sie! The summoning can only take place in [english_list(summon_objective.summon_spots)]!"
add_overlay(narnar)
return
var/turf/P = get_turf(blood_target)
@@ -388,11 +397,13 @@ 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/list/textlist
var/list/textlist = list()
for(var/mob/living/L in GLOB.alive_mob_list)
if(is_servant_of_ratvar(L))
servants++
textlist = list("[SSticker.mode.eminence ? "There is an Eminence." : "<b>There is no Eminence! Get one ASAP!</b>"]<br>")
var/datum/antagonist/clockcult/C = mob_viewer.mind.has_antag_datum(/datum/antagonist/clockcult,TRUE)
if(C && C.clock_team)
textlist += "[C.clock_team.eminence ? "There is an Eminence." : "<b>There is no Eminence! Get one ASAP!</b>"]<br>"
textlist += "There are currently <b>[servants]</b> servant[servants > 1 ? "s" : ""] of Ratvar.<br>"
for(var/i in SSticker.scripture_states)
if(i != SCRIPTURE_DRIVER) //ignore the always-unlocked stuff
+2 -4
View File
@@ -60,8 +60,6 @@
var/pref = C.prefs.parallax
if (isnull(pref))
pref = PARALLAX_HIGH
if (C.byond_version < 511)
pref = PARALLAX_DISABLE
switch(C.prefs.parallax)
if (PARALLAX_INSANE)
C.parallax_throttle = FALSE
@@ -257,8 +255,8 @@
view = world.view
var/list/viewscales = getviewsize(view)
var/countx = Ceiling((viewscales[1]/2)/(480/world.icon_size))+1
var/county = Ceiling((viewscales[2]/2)/(480/world.icon_size))+1
var/countx = CEILING((viewscales[1]/2)/(480/world.icon_size), 1)+1
var/county = CEILING((viewscales[2]/2)/(480/world.icon_size), 1)+1
var/list/new_overlays = new
for(var/x in -countx to countx)
for(var/y in -county to county)
+277 -277
View File
@@ -1,277 +1,277 @@
/obj/screen/robot
icon = 'icons/mob/screen_cyborg.dmi'
/obj/screen/robot/module
name = "cyborg module"
icon_state = "nomod"
/obj/screen/robot/Click()
if(isobserver(usr))
return 1
/obj/screen/robot/module/Click()
if(..())
return
var/mob/living/silicon/robot/R = usr
if(R.module.type != /obj/item/robot_module)
R.hud_used.toggle_show_robot_modules()
return 1
R.pick_module()
/obj/screen/robot/module1
name = "module1"
icon_state = "inv1"
/obj/screen/robot/module1/Click()
if(..())
return
var/mob/living/silicon/robot/R = usr
R.toggle_module(1)
/obj/screen/robot/module2
name = "module2"
icon_state = "inv2"
/obj/screen/robot/module2/Click()
if(..())
return
var/mob/living/silicon/robot/R = usr
R.toggle_module(2)
/obj/screen/robot/module3
name = "module3"
icon_state = "inv3"
/obj/screen/robot/module3/Click()
if(..())
return
var/mob/living/silicon/robot/R = usr
R.toggle_module(3)
/obj/screen/robot/radio
name = "radio"
icon_state = "radio"
/obj/screen/robot/radio/Click()
if(..())
return
var/mob/living/silicon/robot/R = usr
R.radio.interact(R)
/obj/screen/robot/store
name = "store"
icon_state = "store"
/obj/screen/robot/store/Click()
if(..())
return
var/mob/living/silicon/robot/R = usr
R.uneq_active()
/obj/screen/robot/lamp
name = "headlamp"
icon_state = "lamp0"
/obj/screen/robot/lamp/Click()
if(..())
return
var/mob/living/silicon/robot/R = usr
R.control_headlamp()
/obj/screen/robot/thrusters
name = "ion thrusters"
icon_state = "ionpulse0"
/obj/screen/robot/thrusters/Click()
if(..())
return
var/mob/living/silicon/robot/R = usr
R.toggle_ionpulse()
/datum/hud/robot
ui_style_icon = 'icons/mob/screen_cyborg.dmi'
/datum/hud/robot/New(mob/owner, ui_style = 'icons/mob/screen_cyborg.dmi')
..()
var/mob/living/silicon/robot/mymobR = mymob
var/obj/screen/using
using = new/obj/screen/language_menu
using.screen_loc = ui_borg_language_menu
static_inventory += using
//Radio
using = new /obj/screen/robot/radio()
using.screen_loc = ui_borg_radio
static_inventory += using
//Module select
using = new /obj/screen/robot/module1()
using.screen_loc = ui_inv1
static_inventory += using
mymobR.inv1 = using
using = new /obj/screen/robot/module2()
using.screen_loc = ui_inv2
static_inventory += using
mymobR.inv2 = using
using = new /obj/screen/robot/module3()
using.screen_loc = ui_inv3
static_inventory += using
mymobR.inv3 = using
//End of module select
//Photography stuff
using = new /obj/screen/ai/image_take()
using.screen_loc = ui_borg_camera
static_inventory += using
using = new /obj/screen/ai/image_view()
using.screen_loc = ui_borg_album
static_inventory += using
//Sec/Med HUDs
using = new /obj/screen/ai/sensors()
using.screen_loc = ui_borg_sensor
static_inventory += using
//Headlamp control
using = new /obj/screen/robot/lamp()
using.screen_loc = ui_borg_lamp
static_inventory += using
mymobR.lamp_button = using
//Thrusters
using = new /obj/screen/robot/thrusters()
using.screen_loc = ui_borg_thrusters
static_inventory += using
mymobR.thruster_button = using
//Intent
action_intent = new /obj/screen/act_intent/robot()
action_intent.icon_state = mymob.a_intent
static_inventory += action_intent
//Health
healths = new /obj/screen/healths/robot()
infodisplay += healths
//Installed Module
mymobR.hands = new /obj/screen/robot/module()
mymobR.hands.screen_loc = ui_borg_module
static_inventory += mymobR.hands
//Store
module_store_icon = new /obj/screen/robot/store()
module_store_icon.screen_loc = ui_borg_store
pull_icon = new /obj/screen/pull()
pull_icon.icon = 'icons/mob/screen_cyborg.dmi'
pull_icon.update_icon(mymob)
pull_icon.screen_loc = ui_borg_pull
hotkeybuttons += pull_icon
zone_select = new /obj/screen/zone_sel/robot()
zone_select.update_icon(mymob)
static_inventory += zone_select
/datum/hud/proc/toggle_show_robot_modules()
if(!iscyborg(mymob))
return
var/mob/living/silicon/robot/R = mymob
R.shown_robot_modules = !R.shown_robot_modules
update_robot_modules_display()
/datum/hud/proc/update_robot_modules_display(mob/viewer)
if(!iscyborg(mymob))
return
var/mob/living/silicon/robot/R = mymob
var/mob/screenmob = viewer || R
if(!R.module)
return
if(!R.client)
return
if(R.shown_robot_modules && screenmob.hud_used.hud_shown)
//Modules display is shown
screenmob.client.screen += module_store_icon //"store" icon
if(!R.module.modules)
to_chat(usr, "<span class='danger'>Selected module has no modules to select</span>")
return
if(!R.robot_modules_background)
return
var/display_rows = Ceiling(length(R.module.get_inactive_modules()) / 8)
R.robot_modules_background.screen_loc = "CENTER-4:16,SOUTH+1:7 to CENTER+3:16,SOUTH+[display_rows]:7"
screenmob.client.screen += R.robot_modules_background
var/x = -4 //Start at CENTER-4,SOUTH+1
var/y = 1
for(var/atom/movable/A in R.module.get_inactive_modules())
//Module is not currently active
screenmob.client.screen += A
if(x < 0)
A.screen_loc = "CENTER[x]:16,SOUTH+[y]:7"
else
A.screen_loc = "CENTER+[x]:16,SOUTH+[y]:7"
A.layer = ABOVE_HUD_LAYER
A.plane = ABOVE_HUD_PLANE
x++
if(x == 4)
x = -4
y++
else
//Modules display is hidden
screenmob.client.screen -= module_store_icon //"store" icon
for(var/atom/A in R.module.get_inactive_modules())
//Module is not currently active
screenmob.client.screen -= A
R.shown_robot_modules = 0
screenmob.client.screen -= R.robot_modules_background
/mob/living/silicon/robot/create_mob_hud()
if(client && !hud_used)
hud_used = new /datum/hud/robot(src)
/datum/hud/robot/persistent_inventory_update(mob/viewer)
if(!mymob)
return
var/mob/living/silicon/robot/R = mymob
var/mob/screenmob = viewer || R
if(screenmob.hud_used)
if(screenmob.hud_used.hud_shown)
for(var/i in 1 to R.held_items.len)
var/obj/item/I = R.held_items[i]
if(I)
switch(i)
if(1)
I.screen_loc = ui_inv1
if(2)
I.screen_loc = ui_inv2
if(3)
I.screen_loc = ui_inv3
else
return
screenmob.client.screen += I
else
for(var/obj/item/I in R.held_items)
screenmob.client.screen -= I
/obj/screen/robot
icon = 'icons/mob/screen_cyborg.dmi'
/obj/screen/robot/module
name = "cyborg module"
icon_state = "nomod"
/obj/screen/robot/Click()
if(isobserver(usr))
return 1
/obj/screen/robot/module/Click()
if(..())
return
var/mob/living/silicon/robot/R = usr
if(R.module.type != /obj/item/robot_module)
R.hud_used.toggle_show_robot_modules()
return 1
R.pick_module()
/obj/screen/robot/module1
name = "module1"
icon_state = "inv1"
/obj/screen/robot/module1/Click()
if(..())
return
var/mob/living/silicon/robot/R = usr
R.toggle_module(1)
/obj/screen/robot/module2
name = "module2"
icon_state = "inv2"
/obj/screen/robot/module2/Click()
if(..())
return
var/mob/living/silicon/robot/R = usr
R.toggle_module(2)
/obj/screen/robot/module3
name = "module3"
icon_state = "inv3"
/obj/screen/robot/module3/Click()
if(..())
return
var/mob/living/silicon/robot/R = usr
R.toggle_module(3)
/obj/screen/robot/radio
name = "radio"
icon_state = "radio"
/obj/screen/robot/radio/Click()
if(..())
return
var/mob/living/silicon/robot/R = usr
R.radio.interact(R)
/obj/screen/robot/store
name = "store"
icon_state = "store"
/obj/screen/robot/store/Click()
if(..())
return
var/mob/living/silicon/robot/R = usr
R.uneq_active()
/obj/screen/robot/lamp
name = "headlamp"
icon_state = "lamp0"
/obj/screen/robot/lamp/Click()
if(..())
return
var/mob/living/silicon/robot/R = usr
R.control_headlamp()
/obj/screen/robot/thrusters
name = "ion thrusters"
icon_state = "ionpulse0"
/obj/screen/robot/thrusters/Click()
if(..())
return
var/mob/living/silicon/robot/R = usr
R.toggle_ionpulse()
/datum/hud/robot
ui_style_icon = 'icons/mob/screen_cyborg.dmi'
/datum/hud/robot/New(mob/owner, ui_style = 'icons/mob/screen_cyborg.dmi')
..()
var/mob/living/silicon/robot/mymobR = mymob
var/obj/screen/using
using = new/obj/screen/language_menu
using.screen_loc = ui_borg_language_menu
static_inventory += using
//Radio
using = new /obj/screen/robot/radio()
using.screen_loc = ui_borg_radio
static_inventory += using
//Module select
using = new /obj/screen/robot/module1()
using.screen_loc = ui_inv1
static_inventory += using
mymobR.inv1 = using
using = new /obj/screen/robot/module2()
using.screen_loc = ui_inv2
static_inventory += using
mymobR.inv2 = using
using = new /obj/screen/robot/module3()
using.screen_loc = ui_inv3
static_inventory += using
mymobR.inv3 = using
//End of module select
//Photography stuff
using = new /obj/screen/ai/image_take()
using.screen_loc = ui_borg_camera
static_inventory += using
using = new /obj/screen/ai/image_view()
using.screen_loc = ui_borg_album
static_inventory += using
//Sec/Med HUDs
using = new /obj/screen/ai/sensors()
using.screen_loc = ui_borg_sensor
static_inventory += using
//Headlamp control
using = new /obj/screen/robot/lamp()
using.screen_loc = ui_borg_lamp
static_inventory += using
mymobR.lamp_button = using
//Thrusters
using = new /obj/screen/robot/thrusters()
using.screen_loc = ui_borg_thrusters
static_inventory += using
mymobR.thruster_button = using
//Intent
action_intent = new /obj/screen/act_intent/robot()
action_intent.icon_state = mymob.a_intent
static_inventory += action_intent
//Health
healths = new /obj/screen/healths/robot()
infodisplay += healths
//Installed Module
mymobR.hands = new /obj/screen/robot/module()
mymobR.hands.screen_loc = ui_borg_module
static_inventory += mymobR.hands
//Store
module_store_icon = new /obj/screen/robot/store()
module_store_icon.screen_loc = ui_borg_store
pull_icon = new /obj/screen/pull()
pull_icon.icon = 'icons/mob/screen_cyborg.dmi'
pull_icon.update_icon(mymob)
pull_icon.screen_loc = ui_borg_pull
hotkeybuttons += pull_icon
zone_select = new /obj/screen/zone_sel/robot()
zone_select.update_icon(mymob)
static_inventory += zone_select
/datum/hud/proc/toggle_show_robot_modules()
if(!iscyborg(mymob))
return
var/mob/living/silicon/robot/R = mymob
R.shown_robot_modules = !R.shown_robot_modules
update_robot_modules_display()
/datum/hud/proc/update_robot_modules_display(mob/viewer)
if(!iscyborg(mymob))
return
var/mob/living/silicon/robot/R = mymob
var/mob/screenmob = viewer || R
if(!R.module)
return
if(!R.client)
return
if(R.shown_robot_modules && screenmob.hud_used.hud_shown)
//Modules display is shown
screenmob.client.screen += module_store_icon //"store" icon
if(!R.module.modules)
to_chat(usr, "<span class='danger'>Selected module has no modules to select</span>")
return
if(!R.robot_modules_background)
return
var/display_rows = CEILING(length(R.module.get_inactive_modules()) / 8, 1)
R.robot_modules_background.screen_loc = "CENTER-4:16,SOUTH+1:7 to CENTER+3:16,SOUTH+[display_rows]:7"
screenmob.client.screen += R.robot_modules_background
var/x = -4 //Start at CENTER-4,SOUTH+1
var/y = 1
for(var/atom/movable/A in R.module.get_inactive_modules())
//Module is not currently active
screenmob.client.screen += A
if(x < 0)
A.screen_loc = "CENTER[x]:16,SOUTH+[y]:7"
else
A.screen_loc = "CENTER+[x]:16,SOUTH+[y]:7"
A.layer = ABOVE_HUD_LAYER
A.plane = ABOVE_HUD_PLANE
x++
if(x == 4)
x = -4
y++
else
//Modules display is hidden
screenmob.client.screen -= module_store_icon //"store" icon
for(var/atom/A in R.module.get_inactive_modules())
//Module is not currently active
screenmob.client.screen -= A
R.shown_robot_modules = 0
screenmob.client.screen -= R.robot_modules_background
/mob/living/silicon/robot/create_mob_hud()
if(client && !hud_used)
hud_used = new /datum/hud/robot(src)
/datum/hud/robot/persistent_inventory_update(mob/viewer)
if(!mymob)
return
var/mob/living/silicon/robot/R = mymob
var/mob/screenmob = viewer || R
if(screenmob.hud_used)
if(screenmob.hud_used.hud_shown)
for(var/i in 1 to R.held_items.len)
var/obj/item/I = R.held_items[i]
if(I)
switch(i)
if(1)
I.screen_loc = ui_inv1
if(2)
I.screen_loc = ui_inv2
if(3)
I.screen_loc = ui_inv3
else
return
screenmob.client.screen += I
else
for(var/obj/item/I in R.held_items)
screenmob.client.screen -= I
+4 -2
View File
@@ -58,6 +58,8 @@
SendSignal(COMSIG_ITEM_ATTACK, M, user)
if(flags_1 & NOBLUDGEON_1)
return
if(user.disabilities & PACIFISM)
return
if(!force)
playsound(loc, 'sound/weapons/tap.ogg', get_clamped_volume(), 1, -1)
else if(hitsound)
@@ -119,9 +121,9 @@
/obj/item/proc/get_clamped_volume()
if(w_class)
if(force)
return Clamp((force + w_class) * 4, 30, 100)// Add the item's force to its weight class and multiply by 4, then clamp the value between 30 and 100
return CLAMP((force + w_class) * 4, 30, 100)// Add the item's force to its weight class and multiply by 4, then clamp the value between 30 and 100
else
return Clamp(w_class * 6, 10, 100) // Multiply the item's weight class by 6, then clamp the value between 10 and 100
return CLAMP(w_class * 6, 10, 100) // Multiply the item's weight class by 6, then clamp the value between 10 and 100
/mob/living/proc/send_item_attack_message(obj/item/I, mob/living/user, hit_area)
var/message_verb = "attacked"
+1
View File
@@ -63,6 +63,7 @@
/atom/proc/attack_animal(mob/user)
return
/mob/living/RestrainedClickOn(atom/A)
return
+2 -2
View File
@@ -62,14 +62,14 @@
/mob/living/proc/adjustArousalLoss(amount, updating_arousal=1)
if(status_flags & GODMODE || !canbearoused)
return 0
arousalloss = Clamp(arousalloss + amount, min_arousal, max_arousal)
arousalloss = CLAMP(arousalloss + amount, min_arousal, max_arousal)
if(updating_arousal)
updatearousal()
/mob/living/proc/setArousalLoss(amount, updating_arousal=1)
if(status_flags & GODMODE || !canbearoused)
return 0
arousalloss = Clamp(amount, min_arousal, max_arousal)
arousalloss = CLAMP(amount, min_arousal, max_arousal)
if(updating_arousal)
updatearousal()
@@ -9,7 +9,7 @@
var/value
var/default //read-only, just set value directly
var/resident_file //the file which this belongs to, must be set
var/resident_file //the file which this was loaded from, if any
var/modified = FALSE //set to TRUE if the default has been overridden by a config entry
var/protection = NONE
@@ -18,8 +18,6 @@
var/dupes_allowed = FALSE
/datum/config_entry/New()
if(!resident_file)
CRASH("Config entry [type] has no resident_file set")
if(type == abstract_type)
CRASH("Abstract config entry [type] instatiated!")
name = lowertext(type2top(type))
@@ -110,7 +108,7 @@
/datum/config_entry/number/ValidateAndSet(str_val)
var/temp = text2num(trim(str_val))
if(!isnull(temp))
value = Clamp(integer ? round(temp) : temp, min_val, max_val)
value = CLAMP(integer ? round(temp) : temp, min_val, max_val)
if(value != temp && !var_edited)
log_config("Changing [name] from [temp] to [value]!")
return TRUE
+36 -15
View File
@@ -20,10 +20,13 @@ GLOBAL_PROTECT(config_dir)
/datum/controller/configuration/New()
config = src
var/list/config_files = InitEntries()
InitEntries()
LoadModes()
for(var/I in config_files)
LoadEntries(I)
if(LoadEntries("config.txt") <= 1)
log_config("No $include directives found in config.txt! Loading legacy game_options/dbconfig/comms files...")
LoadEntries("game_options.txt")
LoadEntries("dbconfig.txt")
LoadEntries("comms.txt")
loadmaplist(CONFIG_MAPS_FILE)
/datum/controller/configuration/Destroy()
@@ -42,8 +45,6 @@ GLOBAL_PROTECT(config_dir)
var/list/_entries_by_type = list()
entries_by_type = _entries_by_type
. = list()
for(var/I in typesof(/datum/config_entry)) //typesof is faster in this case
var/datum/config_entry/E = I
if(initial(E.abstract_type) == I)
@@ -57,24 +58,30 @@ GLOBAL_PROTECT(config_dir)
continue
_entries[esname] = E
_entries_by_type[I] = E
.[E.resident_file] = TRUE
/datum/controller/configuration/proc/RemoveEntry(datum/config_entry/CE)
entries -= CE.name
entries_by_type -= CE.type
/datum/controller/configuration/proc/LoadEntries(filename)
/datum/controller/configuration/proc/LoadEntries(filename, list/stack = list())
var/filename_to_test = world.system_type == MS_WINDOWS ? lowertext(filename) : filename
if(filename_to_test in stack)
log_config("Warning: Config recursion detected ([english_list(stack)]), breaking!")
return
stack = stack + filename_to_test
log_config("Loading config file [filename]...")
var/list/lines = world.file2list("[GLOB.config_dir][filename]")
var/list/_entries = entries
for(var/L in lines)
if(!L)
continue
if(copytext(L, 1, 2) == "#")
var/firstchar = copytext(L, 1, 2)
if(firstchar == "#")
continue
var/lockthis = copytext(L, 1, 2) == "@"
var/lockthis = firstchar == "@"
if(lockthis)
L = copytext(L, 2)
@@ -90,15 +97,25 @@ GLOBAL_PROTECT(config_dir)
if(!entry)
continue
if(entry == "$include")
if(!value)
log_config("Warning: Invalid $include directive: [value]")
else
LoadEntries(value, stack)
++.
continue
if(entry == "$include")
if(!value)
log_config("Warning: Invalid $include directive: [value]")
else
LoadEntries(value, stack)
continue
var/datum/config_entry/E = _entries[entry]
if(!E)
log_config("Unknown setting in configuration: '[entry]'")
continue
if(filename != E.resident_file)
log_config("Found [entry] in [filename] when it should have been in [E.resident_file]! Ignoring.")
continue
if(lockthis)
E.protection |= CONFIG_ENTRY_LOCKED
@@ -107,10 +124,14 @@ GLOBAL_PROTECT(config_dir)
if(!validated)
log_config("Failed to validate setting \"[value]\" for [entry]")
else if(E.modified && !E.dupes_allowed)
log_config("Duplicate setting for [entry] ([value]) detected! Using latest.")
log_config("Duplicate setting for [entry] ([value], [E.resident_file]) detected! Using latest.")
E.resident_file = filename
if(validated)
E.modified = TRUE
++.
/datum/controller/configuration/can_vv_get(var_name)
return (var_name != "entries_by_type" || !hiding_entries_by_type) && ..()
@@ -1,22 +1,20 @@
#define CURRENT_RESIDENT_FILE "comms.txt"
CONFIG_DEF(string/comms_key)
/datum/config_entry/string/comms_key
protection = CONFIG_ENTRY_HIDDEN
/datum/config_entry/string/comms_key/ValidateAndSet(str_val)
return str_val != "default_pwd" && length(str_val) > 6 && ..()
CONFIG_DEF(string/cross_server_address)
/datum/config_entry/keyed_string_list/cross_server
protection = CONFIG_ENTRY_LOCKED
/datum/config_entry/string/cross_server_address/ValidateAndSet(str_val)
return str_val != "byond:\\address:port" && ..()
CONFIG_DEF(string/cross_comms_name)
/datum/config_entry/string/cross_comms_name
GLOBAL_VAR_INIT(medals_enabled, TRUE) //will be auto set to false if the game fails contacting the medal hub to prevent unneeded calls.
CONFIG_DEF(string/medal_hub_address)
/datum/config_entry/string/medal_hub_address
CONFIG_DEF(string/medal_hub_password)
protection = CONFIG_ENTRY_HIDDEN
/datum/config_entry/string/medal_hub_password
protection = CONFIG_ENTRY_HIDDEN
@@ -1,390 +0,0 @@
#define CURRENT_RESIDENT_FILE "config.txt"
CONFIG_DEF(flag/autoadmin) // if autoadmin is enabled
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(string/autoadmin_rank) // the rank for autoadmins
value = "Game Master"
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(string/servername) // server name (the name of the game window)
CONFIG_DEF(string/serversqlname) // short form server name used for the DB
CONFIG_DEF(string/stationname) // station name (the name of the station in-game)
CONFIG_DEF(number/lobby_countdown) // In between round countdown.
value = 120
min_val = 0
CONFIG_DEF(number/round_end_countdown) // Post round murder death kill countdown
value = 25
min_val = 0
CONFIG_DEF(flag/hub) // if the game appears on the hub or not
CONFIG_DEF(flag/log_ooc) // log OOC channel
CONFIG_DEF(flag/log_access) // log login/logout
CONFIG_DEF(flag/log_say) // log client say
CONFIG_DEF(flag/log_admin) // log admin actions
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_prayer) // log prayers
CONFIG_DEF(flag/log_law) // log lawchanges
CONFIG_DEF(flag/log_game) // log game events
CONFIG_DEF(flag/log_vote) // log voting
CONFIG_DEF(flag/log_whisper) // log client whisper
CONFIG_DEF(flag/log_attack) // log attack messages
CONFIG_DEF(flag/log_emote) // log emotes
CONFIG_DEF(flag/log_adminchat) // log admin chat messages
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_pda) // log pda messages
CONFIG_DEF(flag/log_twitter) // log certain expliotable parrots and other such fun things in a JSON file of twitter valid phrases.
CONFIG_DEF(flag/log_world_topic) // log all world.Topic() calls
CONFIG_DEF(flag/log_manifest) // log crew manifest to seperate file
CONFIG_DEF(flag/allow_admin_ooccolor) // Allows admins with relevant permissions to have their own ooc colour
CONFIG_DEF(flag/allow_vote_restart) // allow votes to restart
CONFIG_DEF(flag/allow_vote_mode) // allow votes to change mode
CONFIG_DEF(number/vote_delay) // minimum time between voting sessions (deciseconds, 10 minute default)
value = 6000
min_val = 0
CONFIG_DEF(number/vote_period) // length of voting period (deciseconds, default 1 minute)
value = 600
min_val = 0
CONFIG_DEF(flag/default_no_vote) // vote does not default to nochange/norestart
CONFIG_DEF(flag/no_dead_vote) // dead people can't vote
CONFIG_DEF(flag/allow_metadata) // Metadata is supported.
CONFIG_DEF(flag/popup_admin_pm) // adminPMs to non-admins show in a pop-up 'reply' window when set
CONFIG_DEF(number/fps)
value = 20
min_val = 1
max_val = 100 //byond will start crapping out at 50, so this is just ridic
var/sync_validate = FALSE
/datum/config_entry/number/fps/ValidateAndSet(str_val)
. = ..()
if(.)
sync_validate = TRUE
var/datum/config_entry/number/ticklag/TL = config.entries_by_type[/datum/config_entry/number/ticklag]
if(!TL.sync_validate)
TL.ValidateAndSet(10 / value)
sync_validate = FALSE
CONFIG_DEF(number/ticklag)
integer = FALSE
var/sync_validate = FALSE
/datum/config_entry/number/ticklag/New() //ticklag weirdly just mirrors fps
var/datum/config_entry/CE = /datum/config_entry/number/fps
value = 10 / initial(CE.value)
..()
/datum/config_entry/number/ticklag/ValidateAndSet(str_val)
. = text2num(str_val) > 0 && ..()
if(.)
sync_validate = TRUE
var/datum/config_entry/number/fps/FPS = config.entries_by_type[/datum/config_entry/number/fps]
if(!FPS.sync_validate)
FPS.ValidateAndSet(10 / value)
sync_validate = FALSE
CONFIG_DEF(flag/allow_holidays)
CONFIG_DEF(number/tick_limit_mc_init) //SSinitialization throttling
value = TICK_LIMIT_MC_INIT_DEFAULT
min_val = 0 //oranges warned us
integer = FALSE
CONFIG_DEF(flag/admin_legacy_system) //Defines whether the server uses the legacy admin system with admins.txt or the SQL system
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(string/hostedby)
CONFIG_DEF(flag/norespawn)
CONFIG_DEF(flag/guest_jobban)
CONFIG_DEF(flag/usewhitelist)
CONFIG_DEF(flag/ban_legacy_system) //Defines whether the server uses the legacy banning system with the files in /data or the SQL system.
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/use_age_restriction_for_jobs) //Do jobs use account age restrictions? --requires database
CONFIG_DEF(flag/use_account_age_for_jobs) //Uses the time they made the account for the job restriction stuff. New player joining alerts should be unaffected.
CONFIG_DEF(flag/use_exp_tracking)
CONFIG_DEF(flag/use_exp_restrictions_heads)
CONFIG_DEF(number/use_exp_restrictions_heads_hours)
value = 0
min_val = 0
CONFIG_DEF(flag/use_exp_restrictions_heads_department)
CONFIG_DEF(flag/use_exp_restrictions_other)
CONFIG_DEF(flag/use_exp_restrictions_admin_bypass)
CONFIG_DEF(string/server)
CONFIG_DEF(string/banappeals)
CONFIG_DEF(string/wikiurl)
value = "http://www.tgstation13.org/wiki"
CONFIG_DEF(string/forumurl)
value = "http://tgstation13.org/phpBB/index.php"
CONFIG_DEF(string/rulesurl)
value = "http://www.tgstation13.org/wiki/Rules"
CONFIG_DEF(string/githuburl)
value = "https://www.github.com/tgstation/-tg-station"
CONFIG_DEF(number/githubrepoid)
value = null
min_val = 0
CONFIG_DEF(flag/guest_ban)
CONFIG_DEF(number/id_console_jobslot_delay)
value = 30
min_val = 0
CONFIG_DEF(number/inactivity_period) //time in ds until a player is considered inactive)
value = 3000
min_val = 0
/datum/config_entry/number/inactivity_period/ValidateAndSet(str_val)
. = ..()
if(.)
value *= 10 //documented as seconds in config.txt
CONFIG_DEF(number/afk_period) //time in ds until a player is considered inactive)
value = 3000
min_val = 0
/datum/config_entry/number/afk_period/ValidateAndSet(str_val)
. = ..()
if(.)
value *= 10 //documented as seconds in config.txt
CONFIG_DEF(flag/kick_inactive) //force disconnect for inactive players
CONFIG_DEF(flag/load_jobs_from_txt)
CONFIG_DEF(flag/forbid_singulo_possession)
CONFIG_DEF(flag/automute_on) //enables automuting/spam prevention
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_server_address) //Reconnect a player this linked server if this server isn't accepting new players
/datum/config_entry/string/panic_server_address/ValidateAndSet(str_val)
return str_val != "byond://address:port" && ..()
CONFIG_DEF(string/invoke_youtubedl)
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
CONFIG_DEF(flag/show_irc_name)
CONFIG_DEF(flag/see_own_notes) //Can players see their own admin notes (read-only)?
CONFIG_DEF(number/note_fresh_days)
value = null
min_val = 0
integer = FALSE
CONFIG_DEF(number/note_stale_days)
value = null
min_val = 0
integer = FALSE
CONFIG_DEF(flag/maprotation)
CONFIG_DEF(number/maprotatechancedelta)
value = 0.75
min_val = 0
max_val = 1
integer = FALSE
CONFIG_DEF(number/soft_popcap)
value = null
min_val = 0
CONFIG_DEF(number/hard_popcap)
value = null
min_val = 0
CONFIG_DEF(number/extreme_popcap)
value = null
min_val = 0
CONFIG_DEF(string/soft_popcap_message)
value = "Be warned that the server is currently serving a high number of users, consider using alternative game servers."
CONFIG_DEF(string/hard_popcap_message)
value = "The server is currently serving a high number of users, You cannot currently join. You may wait for the number of living crew to decline, observe, or find alternative servers."
CONFIG_DEF(string/extreme_popcap_message)
value = "The server is currently serving a high number of users, find alternative servers."
CONFIG_DEF(flag/panic_bunker) // prevents people the server hasn't seen before from connecting
CONFIG_DEF(number/notify_new_player_age) // how long do we notify admins of a new player
min_val = -1
CONFIG_DEF(number/notify_new_player_account_age) // how long do we notify admins of a new byond account
min_val = 0
CONFIG_DEF(flag/irc_first_connection_alert) // do we notify the irc channel when somebody is connecting for the first time?
CONFIG_DEF(flag/check_randomizer)
CONFIG_DEF(string/ipintel_email)
/datum/config_entry/string/ipintel_email/ValidateAndSet(str_val)
return str_val != "ch@nge.me" && ..()
CONFIG_DEF(number/ipintel_rating_bad)
value = 1
integer = FALSE
min_val = 0
max_val = 1
CONFIG_DEF(number/ipintel_save_good)
value = 12
min_val = 0
CONFIG_DEF(number/ipintel_save_bad)
value = 1
min_val = 0
CONFIG_DEF(string/ipintel_domain)
value = "check.getipintel.net"
CONFIG_DEF(flag/aggressive_changelog)
CONFIG_DEF(flag/autoconvert_notes) //if all connecting player's notes should attempt to be converted to the database
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/allow_webclient)
CONFIG_DEF(flag/webclient_only_byond_members)
CONFIG_DEF(flag/announce_admin_logout)
CONFIG_DEF(flag/announce_admin_login)
CONFIG_DEF(flag/allow_map_voting)
CONFIG_DEF(flag/generate_minimaps)
CONFIG_DEF(number/client_warn_version)
value = null
min_val = 500
max_val = DM_VERSION - 1
CONFIG_DEF(string/client_warn_message)
value = "Your version of byond may have issues or be blocked from accessing this server in the future."
CONFIG_DEF(flag/client_warn_popup)
CONFIG_DEF(number/client_error_version)
value = null
min_val = 500
max_val = DM_VERSION - 1
CONFIG_DEF(string/client_error_message)
value = "Your version of byond is too old, may have issues, and is blocked from accessing this server."
CONFIG_DEF(number/minute_topic_limit)
value = null
min_val = 0
CONFIG_DEF(number/second_topic_limit)
value = null
min_val = 0
CONFIG_DEF(number/error_cooldown) // The "cooldown" time for each occurrence of a unique error)
value = 600
min_val = 0
CONFIG_DEF(number/error_limit) // How many occurrences before the next will silence them
value = 50
CONFIG_DEF(number/error_silence_time) // How long a unique error will be silenced for
value = 6000
CONFIG_DEF(number/error_msg_delay) // How long to wait between messaging admins about occurrences of a unique error
value = 50
CONFIG_DEF(flag/irc_announce_new_game)
CONFIG_DEF(flag/debug_admin_hrefs)
CONFIG_DEF(number/mc_tick_rate/base_mc_tick_rate)
integer = FALSE
value = 1
CONFIG_DEF(number/mc_tick_rate/high_pop_mc_tick_rate)
integer = FALSE
value = 1.1
CONFIG_DEF(number/mc_tick_rate/high_pop_mc_mode_amount)
value = 65
CONFIG_DEF(number/mc_tick_rate/disable_high_pop_mc_mode_amount)
value = 60
CONFIG_TWEAK(number/mc_tick_rate)
abstract_type = /datum/config_entry/number/mc_tick_rate
CONFIG_TWEAK(number/mc_tick_rate/ValidateAndSet(str_val))
. = ..()
if (.)
Master.UpdateTickRate()
CONFIG_DEF(flag/resume_after_initializations)
CONFIG_TWEAK(flag/resume_after_initializations/ValidateAndSet(str_val))
. = ..()
if(. && Master.current_runlevel)
world.sleep_offline = !value
CONFIG_DEF(number/rounds_until_hard_restart)
value = -1
min_val = 0
CONFIG_DEF(string/default_view)
value = "15x15"
@@ -1,28 +1,26 @@
#define CURRENT_RESIDENT_FILE "dbconfig.txt"
CONFIG_DEF(flag/sql_enabled) // for sql switching
/datum/config_entry/flag/sql_enabled // for sql switching
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(string/address)
/datum/config_entry/string/address
value = "localhost"
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
CONFIG_DEF(number/port)
/datum/config_entry/number/port
value = 3306
min_val = 0
max_val = 65535
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
CONFIG_DEF(string/feedback_database)
/datum/config_entry/string/feedback_database
value = "test"
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
CONFIG_DEF(string/feedback_login)
/datum/config_entry/string/feedback_login
value = "root"
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
CONFIG_DEF(string/feedback_password)
/datum/config_entry/string/feedback_password
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
CONFIG_DEF(string/feedback_tableprefix)
/datum/config_entry/string/feedback_tableprefix
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
@@ -1,253 +1,255 @@
#define CURRENT_RESIDENT_FILE "game_options.txt"
/datum/config_entry/number_list/repeated_mode_adjust
CONFIG_DEF(number_list/repeated_mode_adjust)
CONFIG_DEF(keyed_number_list/probability)
/datum/config_entry/keyed_number_list/probability
/datum/config_entry/keyed_number_list/probability/ValidateKeyName(key_name)
return key_name in config.modes
CONFIG_DEF(keyed_number_list/max_pop)
/datum/config_entry/keyed_number_list/max_pop
/datum/config_entry/keyed_number_list/max_pop/ValidateKeyName(key_name)
return key_name in config.modes
CONFIG_DEF(keyed_number_list/min_pop)
/datum/config_entry/keyed_number_list/min_pop
/datum/config_entry/keyed_number_list/min_pop/ValidateKeyName(key_name)
return key_name in config.modes
CONFIG_DEF(keyed_flag_list/continuous) // which roundtypes continue if all antagonists die
/datum/config_entry/keyed_flag_list/continuous // which roundtypes continue if all antagonists die
/datum/config_entry/keyed_flag_list/continuous/ValidateKeyName(key_name)
return key_name in config.modes
CONFIG_DEF(keyed_flag_list/midround_antag) // which roundtypes use the midround antagonist system
/datum/config_entry/keyed_flag_list/midround_antag // which roundtypes use the midround antagonist system
/datum/config_entry/keyed_flag_list/midround_antag/ValidateKeyName(key_name)
return key_name in config.modes
CONFIG_DEF(keyed_string_list/policy)
/datum/config_entry/keyed_string_list/policy
CONFIG_DEF(number/damage_multiplier)
/datum/config_entry/number/damage_multiplier
value = 1
integer = FALSE
CONFIG_DEF(number/minimal_access_threshold) //If the number of players is larger than this threshold, minimal access will be turned on.
/datum/config_entry/number/minimal_access_threshold //If the number of players is larger than this threshold, minimal access will be turned on.
min_val = 0
CONFIG_DEF(flag/jobs_have_minimal_access) //determines whether jobs use minimal access or expanded access.
/datum/config_entry/flag/jobs_have_minimal_access //determines whether jobs use minimal access or expanded access.
CONFIG_DEF(flag/assistants_have_maint_access)
/datum/config_entry/flag/assistants_have_maint_access
CONFIG_DEF(flag/security_has_maint_access)
/datum/config_entry/flag/security_has_maint_access
CONFIG_DEF(flag/everyone_has_maint_access)
/datum/config_entry/flag/everyone_has_maint_access
CONFIG_DEF(flag/sec_start_brig) //makes sec start in brig instead of dept sec posts
/datum/config_entry/flag/sec_start_brig //makes sec start in brig instead of dept sec posts
CONFIG_DEF(flag/force_random_names)
/datum/config_entry/flag/force_random_names
CONFIG_DEF(flag/humans_need_surnames)
/datum/config_entry/flag/humans_need_surnames
CONFIG_DEF(flag/allow_ai) // allow ai job
/datum/config_entry/flag/allow_ai // allow ai job
CONFIG_DEF(flag/disable_secborg) // disallow secborg module to be chosen.
/datum/config_entry/flag/disable_secborg // disallow secborg module to be chosen.
CONFIG_DEF(flag/disable_peaceborg)
/datum/config_entry/flag/disable_peaceborg
CONFIG_DEF(number/traitor_scaling_coeff) //how much does the amount of players get divided by to determine traitors
/datum/config_entry/number/traitor_scaling_coeff //how much does the amount of players get divided by to determine traitors
value = 6
min_val = 1
CONFIG_DEF(number/brother_scaling_coeff) //how many players per brother team
/datum/config_entry/number/brother_scaling_coeff //how many players per brother team
value = 25
min_val = 1
CONFIG_DEF(number/changeling_scaling_coeff) //how much does the amount of players get divided by to determine changelings
/datum/config_entry/number/changeling_scaling_coeff //how much does the amount of players get divided by to determine changelings
value = 6
min_val = 1
CONFIG_DEF(number/security_scaling_coeff) //how much does the amount of players get divided by to determine open security officer positions
/datum/config_entry/number/security_scaling_coeff //how much does the amount of players get divided by to determine open security officer positions
value = 8
min_val = 1
CONFIG_DEF(number/abductor_scaling_coeff) //how many players per abductor team
/datum/config_entry/number/abductor_scaling_coeff //how many players per abductor team
value = 15
min_val = 1
CONFIG_DEF(number/traitor_objectives_amount)
/datum/config_entry/number/traitor_objectives_amount
value = 2
min_val = 0
CONFIG_DEF(number/brother_objectives_amount)
/datum/config_entry/number/brother_objectives_amount
value = 2
min_val = 0
CONFIG_DEF(flag/reactionary_explosions) //If we use reactionary explosions, explosions that react to walls and doors
/datum/config_entry/flag/reactionary_explosions //If we use reactionary explosions, explosions that react to walls and doors
CONFIG_DEF(flag/protect_roles_from_antagonist) //If security and such can be traitor/cult/other
/datum/config_entry/flag/protect_roles_from_antagonist //If security and such can be traitor/cult/other
CONFIG_DEF(flag/protect_assistant_from_antagonist) //If assistants can be traitor/cult/other
/datum/config_entry/flag/protect_assistant_from_antagonist //If assistants can be traitor/cult/other
CONFIG_DEF(flag/enforce_human_authority) //If non-human species are barred from joining as a head of staff
/datum/config_entry/flag/enforce_human_authority //If non-human species are barred from joining as a head of staff
CONFIG_DEF(flag/allow_latejoin_antagonists) // If late-joining players can be traitor/changeling
/datum/config_entry/flag/allow_latejoin_antagonists // If late-joining players can be traitor/changeling
CONFIG_DEF(number/midround_antag_time_check) // How late (in minutes) you want the midround antag system to stay on, setting this to 0 will disable the system
/datum/config_entry/number/midround_antag_time_check // How late (in minutes you want the midround antag system to stay on, setting this to 0 will disable the system)
value = 60
min_val = 0
CONFIG_DEF(number/midround_antag_life_check) // A ratio of how many people need to be alive in order for the round not to immediately end in midround antagonist
/datum/config_entry/number/midround_antag_life_check // A ratio of how many people need to be alive in order for the round not to immediately end in midround antagonist
value = 0.7
integer = FALSE
min_val = 0
max_val = 1
CONFIG_DEF(number/shuttle_refuel_delay)
/datum/config_entry/number/shuttle_refuel_delay
value = 12000
min_val = 0
CONFIG_DEF(flag/show_game_type_odds) //if set this allows players to see the odds of each roundtype on the get revision screen
/datum/config_entry/flag/show_game_type_odds //if set this allows players to see the odds of each roundtype on the get revision screen
CONFIG_DEF(keyed_flag_list/roundstart_races) //races you can play as from the get go.
/datum/config_entry/keyed_flag_list/roundstart_races //races you can play as from the get go.
CONFIG_DEF(flag/join_with_mutant_humans) //players can pick mutant bodyparts for humans before joining the game
/datum/config_entry/flag/join_with_mutant_humans //players can pick mutant bodyparts for humans before joining the game
CONFIG_DEF(flag/no_summon_guns) //No
/datum/config_entry/flag/no_summon_guns //No
CONFIG_DEF(flag/no_summon_magic) //Fun
/datum/config_entry/flag/no_summon_magic //Fun
CONFIG_DEF(flag/no_summon_events) //Allowed
/datum/config_entry/flag/no_summon_events //Allowed
CONFIG_DEF(flag/no_intercept_report) //Whether or not to send a communications intercept report roundstart. This may be overriden by gamemodes.
/datum/config_entry/flag/no_intercept_report //Whether or not to send a communications intercept report roundstart. This may be overriden by gamemodes.
CONFIG_DEF(number/arrivals_shuttle_dock_window) //Time from when a player late joins on the arrivals shuttle to when the shuttle docks on the station
/datum/config_entry/number/arrivals_shuttle_dock_window //Time from when a player late joins on the arrivals shuttle to when the shuttle docks on the station
value = 55
min_val = 30
CONFIG_DEF(flag/arrivals_shuttle_require_undocked) //Require the arrivals shuttle to be undocked before latejoiners can join
/datum/config_entry/flag/arrivals_shuttle_require_undocked //Require the arrivals shuttle to be undocked before latejoiners can join
CONFIG_DEF(flag/arrivals_shuttle_require_safe_latejoin) //Require the arrivals shuttle to be operational in order for latejoiners to join
/datum/config_entry/flag/arrivals_shuttle_require_safe_latejoin //Require the arrivals shuttle to be operational in order for latejoiners to join
CONFIG_DEF(string/alert_green)
/datum/config_entry/string/alert_green
value = "All threats to the station have passed. Security may not have weapons visible, privacy laws are once again fully enforced."
CONFIG_DEF(string/alert_blue_upto)
/datum/config_entry/string/alert_blue_upto
value = "The station has received reliable information about possible hostile activity on the station. Security staff may have weapons visible, random searches are permitted."
CONFIG_DEF(string/alert_blue_downto)
/datum/config_entry/string/alert_blue_downto
value = "The immediate threat has passed. Security may no longer have weapons drawn at all times, but may continue to have them visible. Random searches are still allowed."
CONFIG_DEF(string/alert_red_upto)
/datum/config_entry/string/alert_red_upto
value = "There is an immediate serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised."
CONFIG_DEF(string/alert_red_downto)
/datum/config_entry/string/alert_red_downto
value = "The station's destruction has been averted. There is still however an immediate serious threat to the station. Security may have weapons unholstered at all times, random searches are allowed and advised."
CONFIG_DEF(string/alert_delta)
/datum/config_entry/string/alert_delta
value = "Destruction of the station is imminent. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill."
CONFIG_DEF(flag/revival_pod_plants)
/datum/config_entry/flag/revival_pod_plants
CONFIG_DEF(flag/revival_cloning)
/datum/config_entry/flag/revival_cloning
CONFIG_DEF(number/revival_brain_life)
/datum/config_entry/number/revival_brain_life
value = -1
min_val = -1
CONFIG_DEF(flag/rename_cyborg)
/datum/config_entry/flag/rename_cyborg
CONFIG_DEF(flag/ooc_during_round)
/datum/config_entry/flag/ooc_during_round
CONFIG_DEF(flag/emojis)
/datum/config_entry/flag/emojis
CONFIG_DEF(number/run_delay) //Used for modifying movement speed for mobs.
/datum/config_entry/number/run_delay //Used for modifying movement speed for mobs.
var/static/value_cache = 0
CONFIG_TWEAK(number/run_delay/ValidateAndSet())
/datum/config_entry/number/run_delay/ValidateAndSet()
. = ..()
if(.)
value_cache = value
CONFIG_DEF(number/walk_delay)
/datum/config_entry/number/walk_delay
var/static/value_cache = 0
CONFIG_TWEAK(number/walk_delay/ValidateAndSet())
/datum/config_entry/number/walk_delay/ValidateAndSet()
. = ..()
if(.)
value_cache = value
CONFIG_DEF(number/human_delay) //Mob specific modifiers. NOTE: These will affect different mob types in different ways
CONFIG_DEF(number/robot_delay)
CONFIG_DEF(number/monkey_delay)
CONFIG_DEF(number/alien_delay)
CONFIG_DEF(number/slime_delay)
CONFIG_DEF(number/animal_delay)
/datum/config_entry/number/human_delay //Mob specific modifiers. NOTE: These will affect different mob types in different ways
/datum/config_entry/number/robot_delay
/datum/config_entry/number/monkey_delay
/datum/config_entry/number/alien_delay
/datum/config_entry/number/slime_delay
/datum/config_entry/number/animal_delay
CONFIG_DEF(number/gateway_delay) //How long the gateway takes before it activates. Default is half an hour.
/datum/config_entry/number/gateway_delay //How long the gateway takes before it activates. Default is half an hour.
value = 18000
min_val = 0
CONFIG_DEF(flag/ghost_interaction)
/datum/config_entry/flag/ghost_interaction
CONFIG_DEF(flag/silent_ai)
CONFIG_DEF(flag/silent_borg)
/datum/config_entry/flag/silent_ai
/datum/config_entry/flag/silent_borg
CONFIG_DEF(flag/sandbox_autoclose) // close the sandbox panel after spawning an item, potentially reducing griff
/datum/config_entry/flag/sandbox_autoclose // close the sandbox panel after spawning an item, potentially reducing griff
CONFIG_DEF(number/default_laws) //Controls what laws the AI spawns with.
/datum/config_entry/number/default_laws //Controls what laws the AI spawns with.
value = 0
min_val = 0
max_val = 3
CONFIG_DEF(number/silicon_max_law_amount)
/datum/config_entry/number/silicon_max_law_amount
value = 12
min_val = 0
CONFIG_DEF(keyed_flag_list/random_laws)
/datum/config_entry/keyed_flag_list/random_laws
CONFIG_DEF(keyed_number_list/law_weight)
/datum/config_entry/keyed_number_list/law_weight
splitter = ","
CONFIG_DEF(number/assistant_cap)
/datum/config_entry/number/assistant_cap
value = -1
min_val = -1
CONFIG_DEF(flag/starlight)
CONFIG_DEF(flag/grey_assistants)
/datum/config_entry/flag/starlight
/datum/config_entry/flag/grey_assistants
CONFIG_DEF(number/lavaland_budget)
/datum/config_entry/number/lavaland_budget
value = 60
min_val = 0
CONFIG_DEF(number/space_budget)
/datum/config_entry/number/space_budget
value = 16
min_val = 0
CONFIG_DEF(flag/allow_random_events) // Enables random events mid-round when set
/datum/config_entry/flag/allow_random_events // Enables random events mid-round when set
CONFIG_DEF(number/events_min_time_mul) // Multipliers for random events minimal starting time and minimal players amounts
/datum/config_entry/number/events_min_time_mul // Multipliers for random events minimal starting time and minimal players amounts
value = 1
min_val = 0
integer = FALSE
CONFIG_DEF(number/events_min_players_mul)
/datum/config_entry/number/events_min_players_mul
value = 1
min_val = 0
integer = FALSE
CONFIG_DEF(number/mice_roundstart)
/datum/config_entry/number/mice_roundstart
value = 10
min_val = 0
CONFIG_DEF(number/bombcap)
/datum/config_entry/number/bombcap
value = 14
min_val = 4
CONFIG_DEF(flag/allow_crew_objectives)
CONFIG_DEF(flag/allow_miscreants)
CONFIG_DEF(flag/allow_extended_miscreants)
//Cit changes - Adds config options for crew objectives and miscreants
/datum/config_entry/flag/allow_crew_objectives
/datum/config_entry/flag/allow_miscreants
/datum/config_entry/flag/allow_extended_miscreants
//End of Cit changes
/datum/config_entry/number/bombcap/ValidateAndSet(str_val)
. = ..()
@@ -258,9 +260,9 @@ CONFIG_DEF(flag/allow_extended_miscreants)
GLOB.MAX_EX_FLASH_RANGE = value
GLOB.MAX_EX_FLAME_RANGE = value
CONFIG_DEF(number/emergency_shuttle_autocall_threshold)
/datum/config_entry/number/emergency_shuttle_autocall_threshold
min_val = 0
max_val = 1
integer = FALSE
CONFIG_DEF(flag/ic_printing)
/datum/config_entry/flag/ic_printing
@@ -0,0 +1,388 @@
/datum/config_entry/flag/autoadmin // if autoadmin is enabled
protection = CONFIG_ENTRY_LOCKED
/datum/config_entry/string/autoadmin_rank // the rank for autoadmins
value = "Game Master"
protection = CONFIG_ENTRY_LOCKED
/datum/config_entry/string/servername // server name (the name of the game window)
/datum/config_entry/string/serversqlname // short form server name used for the DB
/datum/config_entry/string/stationname // station name (the name of the station in-game)
/datum/config_entry/number/lobby_countdown // In between round countdown.
value = 120
min_val = 0
/datum/config_entry/number/round_end_countdown // Post round murder death kill countdown
value = 25
min_val = 0
/datum/config_entry/flag/hub // if the game appears on the hub or not
/datum/config_entry/flag/log_ooc // log OOC channel
/datum/config_entry/flag/log_access // log login/logout
/datum/config_entry/flag/log_say // log client say
/datum/config_entry/flag/log_admin // log admin actions
protection = CONFIG_ENTRY_LOCKED
/datum/config_entry/flag/log_prayer // log prayers
/datum/config_entry/flag/log_law // log lawchanges
/datum/config_entry/flag/log_game // log game events
/datum/config_entry/flag/log_vote // log voting
/datum/config_entry/flag/log_whisper // log client whisper
/datum/config_entry/flag/log_attack // log attack messages
/datum/config_entry/flag/log_emote // log emotes
/datum/config_entry/flag/log_adminchat // log admin chat messages
protection = CONFIG_ENTRY_LOCKED
/datum/config_entry/flag/log_pda // log pda messages
/datum/config_entry/flag/log_twitter // log certain expliotable parrots and other such fun things in a JSON file of twitter valid phrases.
/datum/config_entry/flag/log_world_topic // log all world.Topic() calls
/datum/config_entry/flag/log_manifest // log crew manifest to seperate file
/datum/config_entry/flag/allow_admin_ooccolor // Allows admins with relevant permissions to have their own ooc colour
/datum/config_entry/flag/allow_vote_restart // allow votes to restart
/datum/config_entry/flag/allow_vote_mode // allow votes to change mode
/datum/config_entry/number/vote_delay // minimum time between voting sessions (deciseconds, 10 minute default)
value = 6000
min_val = 0
/datum/config_entry/number/vote_period // length of voting period (deciseconds, default 1 minute)
value = 600
min_val = 0
/datum/config_entry/flag/default_no_vote // vote does not default to nochange/norestart
/datum/config_entry/flag/no_dead_vote // dead people can't vote
/datum/config_entry/flag/allow_metadata // Metadata is supported.
/datum/config_entry/flag/popup_admin_pm // adminPMs to non-admins show in a pop-up 'reply' window when set
/datum/config_entry/number/fps
value = 20
min_val = 1
max_val = 100 //byond will start crapping out at 50, so this is just ridic
var/sync_validate = FALSE
/datum/config_entry/number/fps/ValidateAndSet(str_val)
. = ..()
if(.)
sync_validate = TRUE
var/datum/config_entry/number/ticklag/TL = config.entries_by_type[/datum/config_entry/number/ticklag]
if(!TL.sync_validate)
TL.ValidateAndSet(10 / value)
sync_validate = FALSE
/datum/config_entry/number/ticklag
integer = FALSE
var/sync_validate = FALSE
/datum/config_entry/number/ticklag/New() //ticklag weirdly just mirrors fps
var/datum/config_entry/CE = /datum/config_entry/number/fps
value = 10 / initial(CE.value)
..()
/datum/config_entry/number/ticklag/ValidateAndSet(str_val)
. = text2num(str_val) > 0 && ..()
if(.)
sync_validate = TRUE
var/datum/config_entry/number/fps/FPS = config.entries_by_type[/datum/config_entry/number/fps]
if(!FPS.sync_validate)
FPS.ValidateAndSet(10 / value)
sync_validate = FALSE
/datum/config_entry/flag/allow_holidays
/datum/config_entry/number/tick_limit_mc_init //SSinitialization throttling
value = TICK_LIMIT_MC_INIT_DEFAULT
min_val = 0 //oranges warned us
integer = FALSE
/datum/config_entry/flag/admin_legacy_system //Defines whether the server uses the legacy admin system with admins.txt or the SQL system
protection = CONFIG_ENTRY_LOCKED
/datum/config_entry/string/hostedby
/datum/config_entry/flag/norespawn
/datum/config_entry/flag/guest_jobban
/datum/config_entry/flag/usewhitelist
/datum/config_entry/flag/ban_legacy_system //Defines whether the server uses the legacy banning system with the files in /data or the SQL system.
protection = CONFIG_ENTRY_LOCKED
/datum/config_entry/flag/use_age_restriction_for_jobs //Do jobs use account age restrictions? --requires database
/datum/config_entry/flag/use_account_age_for_jobs //Uses the time they made the account for the job restriction stuff. New player joining alerts should be unaffected.
/datum/config_entry/flag/use_exp_tracking
/datum/config_entry/flag/use_exp_restrictions_heads
/datum/config_entry/number/use_exp_restrictions_heads_hours
value = 0
min_val = 0
/datum/config_entry/flag/use_exp_restrictions_heads_department
/datum/config_entry/flag/use_exp_restrictions_other
/datum/config_entry/flag/use_exp_restrictions_admin_bypass
/datum/config_entry/string/server
/datum/config_entry/string/banappeals
/datum/config_entry/string/wikiurl
value = "http://www.tgstation13.org/wiki"
/datum/config_entry/string/forumurl
value = "http://tgstation13.org/phpBB/index.php"
/datum/config_entry/string/rulesurl
value = "http://www.tgstation13.org/wiki/Rules"
/datum/config_entry/string/githuburl
value = "https://www.github.com/tgstation/-tg-station"
/datum/config_entry/number/githubrepoid
value = null
min_val = 0
/datum/config_entry/flag/guest_ban
/datum/config_entry/number/id_console_jobslot_delay
value = 30
min_val = 0
/datum/config_entry/number/inactivity_period //time in ds until a player is considered inactive
value = 3000
min_val = 0
/datum/config_entry/number/inactivity_period/ValidateAndSet(str_val)
. = ..()
if(.)
value *= 10 //documented as seconds in config.txt
/datum/config_entry/number/afk_period //time in ds until a player is considered inactive
value = 3000
min_val = 0
/datum/config_entry/number/afk_period/ValidateAndSet(str_val)
. = ..()
if(.)
value *= 10 //documented as seconds in config.txt
/datum/config_entry/flag/kick_inactive //force disconnect for inactive players
/datum/config_entry/flag/load_jobs_from_txt
/datum/config_entry/flag/forbid_singulo_possession
/datum/config_entry/flag/automute_on //enables automuting/spam prevention
/datum/config_entry/string/panic_server_name
/datum/config_entry/string/panic_server_name/ValidateAndSet(str_val)
return str_val != "\[Put the name here\]" && ..()
/datum/config_entry/string/panic_server_address //Reconnect a player this linked server if this server isn't accepting new players
/datum/config_entry/string/panic_server_address/ValidateAndSet(str_val)
return str_val != "byond://address:port" && ..()
/datum/config_entry/string/invoke_youtubedl
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
/datum/config_entry/flag/show_irc_name
/datum/config_entry/flag/see_own_notes //Can players see their own admin notes
/datum/config_entry/number/note_fresh_days
value = null
min_val = 0
integer = FALSE
/datum/config_entry/number/note_stale_days
value = null
min_val = 0
integer = FALSE
/datum/config_entry/flag/maprotation
/datum/config_entry/number/maprotatechancedelta
value = 0.75
min_val = 0
max_val = 1
integer = FALSE
/datum/config_entry/number/soft_popcap
value = null
min_val = 0
/datum/config_entry/number/hard_popcap
value = null
min_val = 0
/datum/config_entry/number/extreme_popcap
value = null
min_val = 0
/datum/config_entry/string/soft_popcap_message
value = "Be warned that the server is currently serving a high number of users, consider using alternative game servers."
/datum/config_entry/string/hard_popcap_message
value = "The server is currently serving a high number of users, You cannot currently join. You may wait for the number of living crew to decline, observe, or find alternative servers."
/datum/config_entry/string/extreme_popcap_message
value = "The server is currently serving a high number of users, find alternative servers."
/datum/config_entry/flag/panic_bunker // prevents people the server hasn't seen before from connecting
/datum/config_entry/number/notify_new_player_age // how long do we notify admins of a new player
min_val = -1
/datum/config_entry/number/notify_new_player_account_age // how long do we notify admins of a new byond account
min_val = 0
/datum/config_entry/flag/irc_first_connection_alert // do we notify the irc channel when somebody is connecting for the first time?
/datum/config_entry/flag/check_randomizer
/datum/config_entry/string/ipintel_email
/datum/config_entry/string/ipintel_email/ValidateAndSet(str_val)
return str_val != "ch@nge.me" && ..()
/datum/config_entry/number/ipintel_rating_bad
value = 1
integer = FALSE
min_val = 0
max_val = 1
/datum/config_entry/number/ipintel_save_good
value = 12
min_val = 0
/datum/config_entry/number/ipintel_save_bad
value = 1
min_val = 0
/datum/config_entry/string/ipintel_domain
value = "check.getipintel.net"
/datum/config_entry/flag/aggressive_changelog
/datum/config_entry/flag/autoconvert_notes //if all connecting player's notes should attempt to be converted to the database
protection = CONFIG_ENTRY_LOCKED
/datum/config_entry/flag/allow_webclient
/datum/config_entry/flag/webclient_only_byond_members
/datum/config_entry/flag/announce_admin_logout
/datum/config_entry/flag/announce_admin_login
/datum/config_entry/flag/allow_map_voting
/datum/config_entry/flag/generate_minimaps
/datum/config_entry/number/client_warn_version
value = null
min_val = 500
max_val = DM_VERSION - 1
/datum/config_entry/string/client_warn_message
value = "Your version of byond may have issues or be blocked from accessing this server in the future."
/datum/config_entry/flag/client_warn_popup
/datum/config_entry/number/client_error_version
value = null
min_val = 500
max_val = DM_VERSION - 1
/datum/config_entry/string/client_error_message
value = "Your version of byond is too old, may have issues, and is blocked from accessing this server."
/datum/config_entry/number/minute_topic_limit
value = null
min_val = 0
/datum/config_entry/number/second_topic_limit
value = null
min_val = 0
/datum/config_entry/number/error_cooldown // The "cooldown" time for each occurrence of a unique error
value = 600
min_val = 0
/datum/config_entry/number/error_limit // How many occurrences before the next will silence them
value = 50
/datum/config_entry/number/error_silence_time // How long a unique error will be silenced for
value = 6000
/datum/config_entry/number/error_msg_delay // How long to wait between messaging admins about occurrences of a unique error
value = 50
/datum/config_entry/flag/irc_announce_new_game
/datum/config_entry/flag/debug_admin_hrefs
/datum/config_entry/number/mc_tick_rate/base_mc_tick_rate
integer = FALSE
value = 1
/datum/config_entry/number/mc_tick_rate/high_pop_mc_tick_rate
integer = FALSE
value = 1.1
/datum/config_entry/number/mc_tick_rate/high_pop_mc_mode_amount
value = 65
/datum/config_entry/number/mc_tick_rate/disable_high_pop_mc_mode_amount
value = 60
/datum/config_entry/number/mc_tick_rate
abstract_type = /datum/config_entry/number/mc_tick_rate
/datum/config_entry/number/mc_tick_rate/ValidateAndSet(str_val)
. = ..()
if (.)
Master.UpdateTickRate()
/datum/config_entry/flag/resume_after_initializations
/datum/config_entry/flag/resume_after_initializations/ValidateAndSet(str_val)
. = ..()
if(. && Master.current_runlevel)
world.sleep_offline = !value
/datum/config_entry/number/rounds_until_hard_restart
value = -1
min_val = 0
/datum/config_entry/string/default_view
value = "15x15"
+1 -1
View File
@@ -301,7 +301,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
continue
//Byond resumed us late. assume it might have to do the same next tick
if (last_run + Ceiling(world.tick_lag * (processing * sleep_delta), world.tick_lag) < world.time)
if (last_run + CEILING(world.tick_lag * (processing * sleep_delta), world.tick_lag) < world.time)
sleep_delta += 1
sleep_delta = MC_AVERAGE_FAST(sleep_delta, 1) //decay sleep_delta
+6 -2
View File
@@ -10,7 +10,8 @@ SUBSYSTEM_DEF(blackbox)
var/sealed = FALSE //time to stop tracking stats?
var/list/research_levels = list() //list of highest tech levels attained that isn't lost lost by destruction of RD computers
var/list/versions = list("time_dilation_current" = 2,
"science_techweb_unlock" = 2) //associative list of any feedback variables that have had their format changed since creation and their current version, remember to update this
"science_techweb_unlock" = 2,
"antagonists" = 3) //associative list of any feedback variables that have had their format changed since creation and their current version, remember to update this
/datum/controller/subsystem/blackbox/Initialize()
@@ -225,7 +226,10 @@ Versioning
var/pos = length(FV.json["data"]) + 1
FV.json["data"]["[pos]"] = list() //in 512 "pos" can be replaced with "[FV.json["data"].len+1]"
for(var/i in data)
FV.json["data"]["[pos]"]["[i]"] = "[data[i]]" //and here with "[FV.json["data"].len]"
if(islist(data[i]))
FV.json["data"]["[pos]"]["[i]"] = data[i] //and here with "[FV.json["data"].len]"
else
FV.json["data"]["[pos]"]["[i]"] = "[data[i]]"
else
CRASH("Invalid feedback key_type: [key_type]")
+1 -1
View File
@@ -80,7 +80,7 @@ SUBSYSTEM_DEF(throwing)
last_move = world.time
//calculate how many tiles to move, making up for any missed ticks.
var/tilestomove = Ceiling(min(((((world.time+world.tick_lag) - start_time + delayed_time) * speed) - (dist_travelled ? dist_travelled : -1)), speed*MAX_TICKS_TO_MAKE_UP) * (world.tick_lag * SSthrowing.wait))
var/tilestomove = CEILING(min(((((world.time+world.tick_lag) - start_time + delayed_time) * speed) - (dist_travelled ? dist_travelled : -1)), speed*MAX_TICKS_TO_MAKE_UP) * (world.tick_lag * SSthrowing.wait), 1)
while (tilestomove-- > 0)
if ((dist_travelled >= maxrange || AM.loc == target_turf) && AM.has_gravity(AM.loc))
finalize()
-198
View File
@@ -398,204 +398,6 @@ SUBSYSTEM_DEF(ticker)
var/mob/living/L = I
L.notransform = FALSE
/datum/controller/subsystem/ticker/proc/declare_completion()
set waitfor = FALSE
var/station_evacuated = EMERGENCY_ESCAPED_OR_ENDGAMED
var/num_survivors = 0
var/num_escapees = 0
var/num_shuttle_escapees = 0
var/list/successfulCrew = list()
var/list/miscreants = list()
to_chat(world, "<BR><BR><BR><FONT size=3><B>The round has ended.</B></FONT>")
if(LAZYLEN(GLOB.round_end_notifiees))
send2irc("Notice", "[GLOB.round_end_notifiees.Join(", ")] the round has ended.")
/* var/nocredits = config.no_credits_round_end
for(var/client/C in GLOB.clients)
if(!C.credits && !nocredits)
C.RollCredits()
C.playtitlemusic(40)*/
//Player status report
for(var/i in GLOB.mob_list)
var/mob/Player = i
if(Player.mind && !isnewplayer(Player))
if(Player.stat != DEAD && !isbrain(Player))
num_survivors++
if(station_evacuated) //If the shuttle has already left the station
var/list/area/shuttle_areas
if(SSshuttle && SSshuttle.emergency)
shuttle_areas = SSshuttle.emergency.shuttle_areas
if(!Player.onCentCom() && !Player.onSyndieBase())
to_chat(Player, "<font color='blue'><b>You managed to survive, but were marooned on [station_name()]...</b></FONT>")
else
num_escapees++
to_chat(Player, "<font color='green'><b>You managed to survive the events on [station_name()] as [Player.real_name].</b></FONT>")
if(shuttle_areas[get_area(Player)])
num_shuttle_escapees++
else
to_chat(Player, "<font color='green'><b>You managed to survive the events on [station_name()] as [Player.real_name].</b></FONT>")
else
to_chat(Player, "<font color='red'><b>You did not survive the events on [station_name()]...</b></FONT>")
CHECK_TICK
//Round statistics report
var/datum/station_state/end_state = new /datum/station_state()
end_state.count()
var/station_integrity = min(PERCENT(GLOB.start_state.score(end_state)), 100)
to_chat(world, "<BR>[GLOB.TAB]Shift Duration: <B>[DisplayTimeText(world.time - SSticker.round_start_time)]</B>")
to_chat(world, "<BR>[GLOB.TAB]Station Integrity: <B>[mode.station_was_nuked ? "<font color='red'>Destroyed</font>" : "[station_integrity]%"]</B>")
if(mode.station_was_nuked)
SSticker.news_report = STATION_DESTROYED_NUKE
var/total_players = GLOB.joined_player_list.len
if(total_players)
to_chat(world, "<BR>[GLOB.TAB]Total Population: <B>[total_players]</B>")
if(station_evacuated)
to_chat(world, "<BR>[GLOB.TAB]Evacuation Rate: <B>[num_escapees] ([PERCENT(num_escapees/total_players)]%)</B>")
to_chat(world, "<BR>[GLOB.TAB](on emergency shuttle): <B>[num_shuttle_escapees] ([PERCENT(num_shuttle_escapees/total_players)]%)</B>")
news_report = STATION_EVACUATED
if(SSshuttle.emergency.is_hijacked())
news_report = SHUTTLE_HIJACK
to_chat(world, "<BR>[GLOB.TAB]Survival Rate: <B>[num_survivors] ([PERCENT(num_survivors/total_players)]%)</B>")
to_chat(world, "<BR>")
CHECK_TICK
//Silicon laws report
for (var/i in GLOB.ai_list)
var/mob/living/silicon/ai/aiPlayer = i
if (aiPlayer.stat != DEAD && aiPlayer.mind)
to_chat(world, "<b>[aiPlayer.name] (Played by: [aiPlayer.mind.key])'s laws at the end of the round were:</b>")
aiPlayer.show_laws(1)
else if (aiPlayer.mind) //if the dead ai has a mind, use its key instead
to_chat(world, "<b>[aiPlayer.name] (Played by: [aiPlayer.mind.key])'s laws when it was deactivated were:</b>")
aiPlayer.show_laws(1)
to_chat(world, "<b>Total law changes: [aiPlayer.law_change_counter]</b>")
if (aiPlayer.connected_robots.len)
var/robolist = "<b>[aiPlayer.real_name]'s minions were:</b> "
for(var/mob/living/silicon/robot/robo in aiPlayer.connected_robots)
if(robo.mind)
robolist += "[robo.name][robo.stat?" (Deactivated) (Played by: [robo.mind.key]), ":" (Played by: [robo.mind.key]), "]"
to_chat(world, "[robolist]")
CHECK_TICK
for (var/mob/living/silicon/robot/robo in GLOB.silicon_mobs)
if (!robo.connected_ai && robo.mind)
if (robo.stat != DEAD)
to_chat(world, "<b>[robo.name] (Played by: [robo.mind.key]) survived as an AI-less borg! Its laws were:</b>")
else
to_chat(world, "<b>[robo.name] (Played by: [robo.mind.key]) was unable to survive the rigors of being a cyborg without an AI. Its laws were:</b>")
if(robo) //How the hell do we lose robo between here and the world messages directly above this?
robo.laws.show_laws(world)
CHECK_TICK
mode.declare_completion()//To declare normal completion.
CHECK_TICK
//calls auto_declare_completion_* for all modes
for(var/handler in typesof(/datum/game_mode/proc))
if (findtext("[handler]","auto_declare_completion_"))
call(mode, handler)(force_ending)
CHECK_TICK
if(CONFIG_GET(string/cross_server_address))
send_news_report()
CHECK_TICK
//Print a list of antagonists to the server log
var/list/total_antagonists = list()
//Look into all mobs in world, dead or alive
for(var/datum/mind/Mind in minds)
var/temprole = Mind.special_role
if(temprole) //if they are an antagonist of some sort.
if(temprole in total_antagonists) //If the role exists already, add the name to it
total_antagonists[temprole] += ", [Mind.name]([Mind.key])"
else
total_antagonists.Add(temprole) //If the role doesnt exist in the list, create it and add the mob
total_antagonists[temprole] += ": [Mind.name]([Mind.key])"
CHECK_TICK
//Now print them all into the log!
log_game("Antagonists at round end were...")
for(var/i in total_antagonists)
log_game("[i]s[total_antagonists[i]].")
CHECK_TICK
for(var/datum/mind/crewMind in minds)
if(!crewMind.current || !crewMind.objectives.len)
continue
for(var/datum/objective/miscreant/MO in crewMind.objectives)
miscreants += "<B>[crewMind.current.real_name]</B> (Played by: <B>[crewMind.key]</B>)<BR><B>Objective</B>: [MO.explanation_text] <font color='grey'>(Optional)</font>"
for(var/datum/objective/crew/CO in crewMind.objectives)
if(CO.check_completion())
to_chat(crewMind.current, "<br><B>Your optional objective</B>: [CO.explanation_text] <font color='green'><B>Success!</B></font>")
successfulCrew += "<B>[crewMind.current.real_name]</B> (Played by: <B>[crewMind.key]</B>)<BR><B>Objective</B>: [CO.explanation_text] <font color='green'><B>Success!</B></font> <font color='grey'>(Optional)</font>"
else
to_chat(crewMind.current, "<br><B>Your optional objective</B>: [CO.explanation_text] <font color='red'><B>Failed.</B></font>")
if (successfulCrew.len)
var/completedObjectives = "<B>The following crew members completed their Crew Objectives:</B><BR>"
for(var/i in successfulCrew)
completedObjectives += "[i]<BR>"
to_chat(world, "[completedObjectives]<BR>")
else
if(CONFIG_GET(flag/allow_crew_objectives))
to_chat(world, "<B>Nobody completed their Crew Objectives!</B><BR>")
CHECK_TICK
if (miscreants.len)
var/miscreantObjectives = "<B>The following crew members were miscreants:</B><BR>"
for(var/i in miscreants)
miscreantObjectives += "[i]<BR>"
to_chat(world, "[miscreantObjectives]<BR>")
CHECK_TICK
mode.declare_station_goal_completion()
CHECK_TICK
//medals, placed far down so that people can actually see the commendations.
if(GLOB.commendations.len)
to_chat(world, "<b><font size=3>Medal Commendations:</font></b>")
for (var/com in GLOB.commendations)
to_chat(world, com)
CHECK_TICK
//Collects persistence features
if(mode.allow_persistence_save)
SSpersistence.CollectData()
//stop collecting feedback during grifftime
SSblackbox.Seal()
sleep(50)
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
CRASH("Attempted standard reboot without ticker roundend completion")
/datum/controller/subsystem/ticker/proc/send_tip_of_the_round()
var/m
if(selected_tip)
+11
View File
@@ -206,6 +206,7 @@ SUBSYSTEM_DEF(vote)
var/datum/action/vote/V = new
if(question)
V.name = "Vote: [question]"
C.player_details.player_actions += V
V.Grant(C.mob)
generated_actions += V
return 1
@@ -299,6 +300,7 @@ SUBSYSTEM_DEF(vote)
for(var/v in generated_actions)
var/datum/action/vote/V = v
if(!QDELETED(V))
V.remove_from_client()
V.Remove(V.owner)
generated_actions = list()
@@ -318,7 +320,16 @@ SUBSYSTEM_DEF(vote)
/datum/action/vote/Trigger()
if(owner)
owner.vote()
remove_from_client()
Remove(owner)
/datum/action/vote/IsAvailable()
return 1
/datum/action/vote/proc/remove_from_client()
if(owner.client)
owner.client.player_details.player_actions -= src
else if(owner.ckey)
var/datum/player_details/P = GLOB.player_details[owner.ckey]
if(P)
P.player_actions -= src
+13
View File
@@ -344,6 +344,19 @@
/datum/action/item_action/change
name = "Change"
/datum/action/item_action/nano_picket_sign
name = "Retext Nano Picket Sign"
var/obj/item/picket_sign/S
/datum/action/item_action/nano_picket_sign/New(Target)
..()
if(istype(Target, /obj/item/picket_sign))
S = Target
/datum/action/item_action/nano_picket_sign/Trigger()
if(istype(S))
S.retext(owner)
/datum/action/item_action/adjust
/datum/action/item_action/adjust/New(Target)
+12
View File
@@ -0,0 +1,12 @@
/datum/action/item_action/zoom_speed_action
name = "Toggle Zooming Speed"
icon_icon = 'icons/mob/actions/actions_spells.dmi'
button_icon_state = "projectile"
background_icon_state = "bg_tech"
/datum/action/item_action/zoom_lock_action
name = "Switch Zoom Mode"
icon_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "zoom_mode"
background_icon_state = "bg_tech"
-2
View File
@@ -1,5 +1,3 @@
/datum/action/item_action/flightsuit
icon_icon = 'icons/mob/actions/actions_flightsuit.dmi'
+3 -26
View File
@@ -373,32 +373,9 @@
ion = list()
/datum/ai_laws/proc/show_laws(who)
if (devillaws && devillaws.len) //Yes, devil laws go in FRONT of zeroth laws, as the devil must still obey it's ban/obligation.
for(var/i in devillaws)
to_chat(who, "666. [i]")
if (zeroth)
to_chat(who, "0. [zeroth]")
for (var/index = 1, index <= ion.len, index++)
var/law = ion[index]
var/num = ionnum()
to_chat(who, "[num]. [law]")
var/number = 1
for (var/index = 1, index <= inherent.len, index++)
var/law = inherent[index]
if (length(law) > 0)
to_chat(who, "[number]. [law]")
number++
for (var/index = 1, index <= supplied.len, index++)
var/law = supplied[index]
if (length(law) > 0)
to_chat(who, "[number]. [law]")
number++
var/list/printable_laws = get_law_list(include_zeroth = TRUE)
for(var/law in printable_laws)
to_chat(who,law)
/datum/ai_laws/proc/clear_zeroth_law(force) //only removes zeroth from antag ai if force is 1
if(force)
+65 -2
View File
@@ -1,7 +1,8 @@
/datum/antagonist/abductor
name = "Abductor"
roundend_category = "abductors"
job_rank = ROLE_ABDUCTOR
var/datum/objective_team/abductor_team/team
var/datum/team/abductor_team/team
var/sub_role
var/outfit
var/landmark_type
@@ -19,7 +20,7 @@
landmark_type = /obj/effect/landmark/abductor/scientist
greet_text = "Use your stealth technology and equipment to incapacitate humans for your scientist to retrieve."
/datum/antagonist/abductor/create_team(datum/objective_team/abductor_team/new_team)
/datum/antagonist/abductor/create_team(datum/team/abductor_team/new_team)
if(!new_team)
return
if(!istype(new_team))
@@ -70,3 +71,65 @@
var/mob/living/carbon/human/H = owner.current
var/datum/species/abductor/A = H.dna.species
A.scientist = TRUE
/datum/team/abductor_team
member_name = "abductor"
var/team_number
var/list/datum/mind/abductees = list()
/datum/team/abductor_team/is_solo()
return FALSE
/datum/team/abductor_team/proc/add_objective(datum/objective/O)
O.team = src
O.update_explanation_text()
objectives += O
/datum/team/abductor_team/roundend_report()
var/list/result = list()
var/won = TRUE
for(var/datum/objective/O in objectives)
if(!O.check_completion())
won = FALSE
if(won)
result += "<span class='greentext big'>[name] team fulfilled its mission!</span>"
else
result += "<span class='redtext big'>[name] team failed its mission.</span>"
result += "<span class='header'>The abductors of [name] were:</span>"
for(var/datum/mind/abductor_mind in members)
result += printplayer(abductor_mind)
result += printobjectives(abductor_mind)
return result.Join("<br>")
/datum/antagonist/abductee
name = "Abductee"
roundend_category = "abductees"
/datum/antagonist/abductee/on_gain()
give_objective()
. = ..()
/datum/antagonist/abductee/greet()
to_chat(owner, "<span class='warning'><b>Your mind snaps!</b></span>")
to_chat(owner, "<big><span class='warning'><b>You can't remember how you got here...</b></span></big>")
owner.announce_objectives()
/datum/antagonist/abductee/proc/give_objective()
var/mob/living/carbon/human/H = owner.current
if(istype(H))
H.gain_trauma_type(BRAIN_TRAUMA_MILD)
var/objtype = (prob(75) ? /datum/objective/abductee/random : pick(subtypesof(/datum/objective/abductee/) - /datum/objective/abductee/random))
var/datum/objective/abductee/O = new objtype()
objectives += O
owner.objectives += objectives
/datum/antagonist/abductee/apply_innate_effects(mob/living/mob_override)
SSticker.mode.update_abductor_icons_added(mob_override ? mob_override.mind : owner)
/datum/antagonist/abductee/remove_innate_effects(mob/living/mob_override)
SSticker.mode.update_abductor_icons_removed(mob_override ? mob_override.mind : owner)
+59 -3
View File
@@ -2,6 +2,8 @@ GLOBAL_LIST_EMPTY(antagonists)
/datum/antagonist
var/name = "Antagonist"
var/roundend_category = "other antagonists" //Section of roundend report, datums with same category will be displayed together, also default header for the section
var/show_in_roundend = TRUE //Set to false to hide the antagonists from roundend report
var/datum/mind/owner //Mind that owns this datum
var/silent = FALSE //Silent will prevent the gain/lose texts to show
var/can_coexist_with_others = TRUE //Whether or not the person will be able to have more than one datum
@@ -9,6 +11,7 @@ GLOBAL_LIST_EMPTY(antagonists)
var/delete_on_mind_deletion = TRUE
var/job_rank
var/replace_banned = TRUE //Should replace jobbaned player with ghosts if granted.
var/list/objectives = list()
/datum/antagonist/New(datum/mind/new_owner)
GLOB.antagonists += src
@@ -46,7 +49,7 @@ GLOBAL_LIST_EMPTY(antagonists)
return
//Assign default team and creates one for one of a kind team antagonists
/datum/antagonist/proc/create_team(datum/objective_team/team)
/datum/antagonist/proc/create_team(datum/team/team)
return
//Proc called when the datum is given to a mind.
@@ -81,7 +84,7 @@ GLOBAL_LIST_EMPTY(antagonists)
LAZYREMOVE(owner.antag_datums, src)
if(!silent && owner.current)
farewell()
var/datum/objective_team/team = get_team()
var/datum/team/team = get_team()
if(team)
team.remove_member(owner)
qdel(src)
@@ -96,9 +99,62 @@ GLOBAL_LIST_EMPTY(antagonists)
/datum/antagonist/proc/get_team()
return
//Individual roundend report
/datum/antagonist/proc/roundend_report()
var/list/report = list()
if(!owner)
CRASH("antagonist datum without owner")
report += printplayer(owner)
var/objectives_complete = TRUE
if(owner.objectives.len)
report += printobjectives(owner)
for(var/datum/objective/objective in owner.objectives)
if(!objective.check_completion())
objectives_complete = FALSE
break
if(owner.objectives.len == 0 || objectives_complete)
report += "<span class='greentext big'>The [name] was successful!</span>"
else
report += "<span class='redtext big'>The [name] has failed!</span>"
return report.Join("<br>")
//Displayed at the start of roundend_category section, default to roundend_category header
/datum/antagonist/proc/roundend_report_header()
return "<span class='header'>The [roundend_category] were:</span><br>"
//Displayed at the end of roundend_category section
/datum/antagonist/proc/roundend_report_footer()
return
//Should probably be on ticker or job ss ?
/proc/get_antagonists(antag_type,specific = FALSE)
. = list()
for(var/datum/antagonist/A in GLOB.antagonists)
if(!specific && istype(A,antag_type) || specific && A.type == antag_type)
. += A.owner
. += A.owner
//This datum will autofill the name with special_role
//Used as placeholder for minor antagonists, please create proper datums for these
/datum/antagonist/auto_custom
/datum/antagonist/auto_custom/on_gain()
..()
name = owner.special_role
//Add all objectives not already owned by other datums to this one.
var/list/already_registered_objectives = list()
for(var/datum/antagonist/A in owner.antag_datums)
if(A == src)
continue
else
already_registered_objectives |= A.objectives
objectives = owner.objectives - already_registered_objectives
//This one is created by admin tools for custom objectives
/datum/antagonist/custom
+70 -2
View File
@@ -2,12 +2,12 @@
name = "Brother"
job_rank = ROLE_BROTHER
var/special_role = "blood brother"
var/datum/objective_team/brother_team/team
var/datum/team/brother_team/team
/datum/antagonist/brother/New(datum/mind/new_owner)
return ..()
/datum/antagonist/brother/create_team(datum/objective_team/brother_team/new_team)
/datum/antagonist/brother/create_team(datum/team/brother_team/new_team)
if(!new_team)
return
if(!istype(new_team))
@@ -55,3 +55,71 @@
/datum/antagonist/brother/proc/finalize_brother()
SSticker.mode.update_brother_icons_added(owner)
/datum/team/brother_team
name = "brotherhood"
member_name = "blood brother"
var/meeting_area
/datum/team/brother_team/is_solo()
return FALSE
/datum/team/brother_team/proc/update_name()
var/list/last_names = list()
for(var/datum/mind/M in members)
var/list/split_name = splittext(M.name," ")
last_names += split_name[split_name.len]
name = last_names.Join(" & ")
/datum/team/brother_team/roundend_report()
var/list/parts = list()
parts += "<span class='header'>The blood brothers of [name] were:</span>"
for(var/datum/mind/M in members)
parts += printplayer(M)
var/win = TRUE
var/objective_count = 1
for(var/datum/objective/objective in objectives)
if(objective.check_completion())
parts += "<B>Objective #[objective_count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</span>"
else
parts += "<B>Objective #[objective_count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
win = FALSE
objective_count++
if(win)
parts += "<span class='greentext'>The blood brothers were successful!</span>"
else
parts += "<span class='redtext'>The blood brothers have failed!</span>"
return "<div class='panel redborder'>[parts.Join("<br>")]</div>"
/datum/team/brother_team/proc/add_objective(datum/objective/O, needs_target = FALSE)
O.team = src
if(needs_target)
O.find_target()
O.update_explanation_text()
objectives += O
/datum/team/brother_team/proc/forge_brother_objectives()
objectives = list()
var/is_hijacker = prob(10)
for(var/i = 1 to max(1, CONFIG_GET(number/brother_objectives_amount) + (members.len > 2) - is_hijacker))
forge_single_objective()
if(is_hijacker)
if(!locate(/datum/objective/hijack) in objectives)
add_objective(new/datum/objective/hijack)
else if(!locate(/datum/objective/escape) in objectives)
add_objective(new/datum/objective/escape)
/datum/team/brother_team/proc/forge_single_objective()
if(prob(50))
if(LAZYLEN(active_ais()) && prob(100/GLOB.joined_player_list.len))
add_objective(new/datum/objective/destroy, TRUE)
else if(prob(30))
add_objective(new/datum/objective/maroon, TRUE)
else
add_objective(new/datum/objective/assassinate, TRUE)
else
add_objective(new/datum/objective/steal, TRUE)
+33 -2
View File
@@ -4,11 +4,11 @@
/datum/antagonist/changeling
name = "Changeling"
roundend_category = "changelings"
job_rank = ROLE_CHANGELING
var/you_are_greet = TRUE
var/give_objectives = TRUE
var/list/objectives = list()
var/team_mode = FALSE //Should assign team objectives ?
//Changeling Stuff
@@ -223,7 +223,7 @@
if(verbose)
to_chat(user, "<span class='warning'>[target] is not compatible with our biology.</span>")
return
if((target.disabilities & NOCLONE) || (target.disabilities & HUSK))
if((target.has_disability(NOCLONE)) || (target.has_disability(NOCLONE)))
if(verbose)
to_chat(user, "<span class='warning'>DNA of [target] is ruined beyond usability!</span>")
return
@@ -478,4 +478,35 @@
/datum/antagonist/changeling/xenobio
name = "Xenobio Changeling"
give_objectives = FALSE
show_in_roundend = FALSE //These are here for admin tracking purposes only
you_are_greet = FALSE
/datum/antagonist/changeling/roundend_report()
var/list/parts = list()
var/changelingwin = 1
if(!owner.current)
changelingwin = 0
parts += printplayer(owner)
//Removed sanity if(changeling) because we -want- a runtime to inform us that the changelings list is incorrect and needs to be fixed.
parts += "<b>Changeling ID:</b> [changelingID]."
parts += "<b>Genomes Extracted:</b> [absorbedcount]"
parts += " "
if(objectives.len)
var/count = 1
for(var/datum/objective/objective in objectives)
if(objective.check_completion())
parts += "<b>Objective #[count]</b>: [objective.explanation_text] <span class='greentext'>Success!</b></span>"
else
parts += "<b>Objective #[count]</b>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
changelingwin = 0
count++
if(changelingwin)
parts += "<span class='greentext'>The changeling was successful!</span>"
else
parts += "<span class='redtext'>The changeling has failed.</span>"
return parts.Join("<br>")
+53 -2
View File
@@ -1,8 +1,11 @@
//CLOCKCULT PROOF OF CONCEPT
/datum/antagonist/clockcult
name = "Clock Cultist"
var/datum/action/innate/hierophant/hierophant_network = new()
roundend_category = "clock cultists"
job_rank = ROLE_SERVANT_OF_RATVAR
var/datum/action/innate/hierophant/hierophant_network = new()
var/datum/team/clockcult/clock_team
var/make_team = TRUE //This should be only false for tutorial scarabs
/datum/antagonist/clockcult/silent
silent = TRUE
@@ -11,6 +14,22 @@
qdel(hierophant_network)
return ..()
/datum/antagonist/clockcult/get_team()
return clock_team
/datum/antagonist/clockcult/create_team(datum/team/clockcult/new_team)
if(!new_team && make_team)
//TODO blah blah same as the others, allow multiple
for(var/datum/antagonist/clockcult/H in GLOB.antagonists)
if(H.clock_team)
clock_team = H.clock_team
return
clock_team = new /datum/team/clockcult
return
if(make_team && !istype(new_team))
stack_trace("Wrong team type passed to [type] initialization.")
clock_team = new_team
/datum/antagonist/clockcult/can_be_owned(datum/mind/new_owner)
. = ..()
if(.)
@@ -156,7 +175,7 @@
SSticker.mode.servants_of_ratvar -= owner
SSticker.mode.update_servant_icons_removed(owner)
if(!silent)
owner.current.visible_message("<span class='big'>[owner] seems to have remembered their true allegiance!</span>", ignored_mob = owner.current)
owner.current.visible_message("<span class='deconversion_message'>[owner] seems to have remembered their true allegiance!</span>", ignored_mob = owner.current)
to_chat(owner, "<span class='userdanger'>A cold, cold darkness flows through your mind, extinguishing the Justiciar's light and all of your memories as his servant.</span>")
owner.current.log_message("<font color=#BE8700>Has renounced the cult of Ratvar!</font>", INDIVIDUAL_ATTACK_LOG)
owner.wipe_memory()
@@ -164,3 +183,35 @@
if(iscyborg(owner.current))
to_chat(owner.current, "<span class='warning'>Despite your freedom from Ratvar's influence, you are still irreparably damaged and no longer possess certain functions such as AI linking.</span>")
. = ..()
/datum/team/clockcult
name = "Clockcult"
var/list/objective
var/datum/mind/eminence
/datum/team/clockcult/proc/check_clockwork_victory()
if(GLOB.clockwork_gateway_activated)
return TRUE
return FALSE
/datum/team/clockcult/roundend_report()
var/list/parts = list()
if(check_clockwork_victory())
parts += "<span class='greentext big'>Ratvar's servants defended the Ark until its activation!</span>"
else
parts += "<span class='redtext big'>The Ark was destroyed! Ratvar will rust away for all eternity!</span>"
parts += " "
parts += "<b>The servants' objective was:</b> [CLOCKCULT_OBJECTIVE]."
parts += "<b>Construction Value(CV)</b> was: <b>[GLOB.clockwork_construction_value]</b>"
for(var/i in SSticker.scripture_states)
if(i != SCRIPTURE_DRIVER)
parts += "<b>[i] scripture</b> was: <b>[SSticker.scripture_states[i] ? "UN":""]LOCKED</b>"
if(eminence)
parts += "<span class='header'>The Eminence was:</span> [printplayer(eminence)]"
if(members.len)
parts += "<span class='header'>Ratvar's servants were:</span>"
parts += printplayerlist(members - eminence)
return "<div class='panel clockborder'>[parts.Join("<br>")]</div>"
+197 -62
View File
@@ -2,84 +2,103 @@
/datum/antagonist/cult
name = "Cultist"
roundend_category = "cultists"
var/datum/action/innate/cult/comm/communion = new
var/datum/action/innate/cult/mastervote/vote = new
job_rank = ROLE_CULTIST
var/ignore_implant = FALSE
var/give_equipment = FALSE
var/datum/team/cult/cult_team
/datum/antagonist/cult/get_team()
return cult_team
/datum/antagonist/cult/create_team(datum/team/cult/new_team)
if(!new_team)
//todo remove this and allow admin buttons to create more than one cult
for(var/datum/antagonist/cult/H in GLOB.antagonists)
if(H.cult_team)
cult_team = H.cult_team
return
cult_team = new /datum/team/cult
cult_team.setup_objectives()
return
if(!istype(new_team))
stack_trace("Wrong team type passed to [type] initialization.")
cult_team = new_team
/datum/antagonist/cult/proc/add_objectives()
objectives |= cult_team.objectives
owner.objectives |= objectives
/datum/antagonist/cult/proc/remove_objectives()
owner.objectives -= objectives
/datum/antagonist/cult/Destroy()
QDEL_NULL(communion)
QDEL_NULL(vote)
return ..()
/datum/antagonist/cult/proc/add_objectives()
var/list/target_candidates = list()
for(var/mob/living/carbon/human/player in GLOB.player_list)
if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && !is_convertable_to_cult(player) && (player != owner) && player.stat != DEAD)
target_candidates += player.mind
if(target_candidates.len == 0)
message_admins("Cult Sacrifice: Could not find unconvertable target, checking for convertable target.")
for(var/mob/living/carbon/human/player in GLOB.player_list)
if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && (player != owner) && player.stat != DEAD)
target_candidates += player.mind
listclearnulls(target_candidates)
if(LAZYLEN(target_candidates))
GLOB.sac_mind = pick(target_candidates)
if(!GLOB.sac_mind)
message_admins("Cult Sacrifice: ERROR - Null target chosen!")
else
var/datum/job/sacjob = SSjob.GetJob(GLOB.sac_mind.assigned_role)
var/datum/preferences/sacface = GLOB.sac_mind.current.client.prefs
var/icon/reshape = get_flat_human_icon(null, sacjob, sacface)
reshape.Shift(SOUTH, 4)
reshape.Shift(EAST, 1)
reshape.Crop(7,4,26,31)
reshape.Crop(-5,-3,26,30)
GLOB.sac_image = reshape
else
message_admins("Cult Sacrifice: Could not find unconvertable or convertable target. WELP!")
GLOB.sac_complete = TRUE
SSticker.mode.cult_objectives += "sacrifice"
if(!GLOB.summon_spots.len)
while(GLOB.summon_spots.len < SUMMON_POSSIBILITIES)
var/area/summon = pick(GLOB.sortedAreas - GLOB.summon_spots)
if(summon && (summon.z in GLOB.station_z_levels) && summon.valid_territory)
GLOB.summon_spots += summon
SSticker.mode.cult_objectives += "eldergod"
/datum/antagonist/cult/proc/cult_memorization(datum/mind/cult_mind)
var/mob/living/current = cult_mind.current
for(var/obj_count = 1,obj_count <= SSticker.mode.cult_objectives.len,obj_count++)
var/explanation
switch(SSticker.mode.cult_objectives[obj_count])
if("sacrifice")
if(GLOB.sac_mind)
explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role] via invoking a Sacrifice rune with them on it and three acolytes around it."
else
explanation = "The veil has already been weakened here, proceed to the final objective."
GLOB.sac_complete = TRUE
if("eldergod")
explanation = "Summon Nar-Sie by invoking the rune 'Summon Nar-Sie'. <b>The summoning can only be accomplished in [english_list(GLOB.summon_spots)] - where the veil is weak enough for the ritual to begin.</b>"
if(!silent)
to_chat(current, "<B>Objective #[obj_count]</B>: [explanation]")
cult_mind.memory += "<B>Objective #[obj_count]</B>: [explanation]<BR>"
/datum/antagonist/cult/can_be_owned(datum/mind/new_owner)
. = ..()
if(. && !ignore_implant)
. = is_convertable_to_cult(new_owner.current)
. = is_convertable_to_cult(new_owner.current,cult_team)
/datum/antagonist/cult/greet()
to_chat(owner, "<span class='userdanger'>You are a member of the cult!</span>")
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/bloodcult.ogg', 100, FALSE, pressure_affected = FALSE)//subject to change
owner.announce_objectives()
/datum/antagonist/cult/on_gain()
. = ..()
var/mob/living/current = owner.current
if(!LAZYLEN(SSticker.mode.cult_objectives))
add_objectives()
add_objectives()
if(give_equipment)
equip_cultist()
SSticker.mode.cult += owner // Only add after they've been given objectives
cult_memorization(owner)
SSticker.mode.update_cult_icons_added(owner)
current.log_message("<font color=#960000>Has been converted to the cult of Nar'Sie!</font>", INDIVIDUAL_ATTACK_LOG)
if(GLOB.blood_target && GLOB.blood_target_image && current.client)
current.client.images += GLOB.blood_target_image
if(cult_team.blood_target && cult_team.blood_target_image && current.client)
current.client.images += cult_team.blood_target_image
/datum/antagonist/cult/proc/equip_cultist(tome=FALSE)
var/mob/living/carbon/H = owner.current
if(!istype(H))
return
if (owner.assigned_role == "Clown")
to_chat(owner, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
H.dna.remove_mutation(CLOWNMUT)
if(tome)
. += cult_give_item(/obj/item/tome, H)
else
. += cult_give_item(/obj/item/paper/talisman/supply, H)
to_chat(owner, "These will help you start the cult on this station. Use them well, and remember - you are not the only one.</span>")
/datum/antagonist/cult/proc/cult_give_item(obj/item/item_path, mob/living/carbon/human/mob)
var/list/slots = list(
"backpack" = slot_in_backpack,
"left pocket" = slot_l_store,
"right pocket" = slot_r_store
)
var/T = new item_path(mob)
var/item_name = initial(item_path.name)
var/where = mob.equip_in_one_of_slots(T, slots)
if(!where)
to_chat(mob, "<span class='userdanger'>Unfortunately, you weren't able to get a [item_name]. This is very bad and you should adminhelp immediately (press F1).</span>")
return 0
else
to_chat(mob, "<span class='danger'>You have a [item_name] in your [where].</span>")
if(where == "backpack")
var/obj/item/storage/B = mob.back
B.orient2hud(mob)
B.show_to(mob)
return 1
/datum/antagonist/cult/apply_innate_effects(mob/living/mob_override)
. = ..()
@@ -89,7 +108,7 @@
current.faction |= "cult"
current.grant_language(/datum/language/narsie)
current.verbs += /mob/living/proc/cult_help
if(!GLOB.cult_mastered)
if(!cult_team.cult_mastered)
vote.Grant(current)
communion.Grant(current)
current.throw_alert("bloodsense", /obj/screen/alert/bloodsense)
@@ -107,6 +126,7 @@
current.clear_alert("bloodsense")
/datum/antagonist/cult/on_removal()
remove_objectives()
owner.wipe_memory()
SSticker.mode.cult -= owner
SSticker.mode.update_cult_icons_removed(owner)
@@ -114,8 +134,8 @@
owner.current.visible_message("<span class='big'>[owner.current] looks like [owner.current.p_they()] just reverted to their old faith!</span>", ignored_mob = owner.current)
to_chat(owner.current, "<span class='userdanger'>An unfamiliar white light flashes through your mind, cleansing the taint of the Geometer and all your memories as her servant.</span>")
owner.current.log_message("<font color=#960000>Has renounced the cult of Nar'Sie!</font>", INDIVIDUAL_ATTACK_LOG)
if(GLOB.blood_target && GLOB.blood_target_image && owner.current.client)
owner.current.client.images -= GLOB.blood_target_image
if(cult_team.blood_target && cult_team.blood_target_image && owner.current.client)
owner.current.client.images -= cult_team.blood_target_image
. = ..()
/datum/antagonist/cult/master
@@ -145,7 +165,7 @@
var/mob/living/current = owner.current
if(mob_override)
current = mob_override
if(!GLOB.reckoning_complete)
if(!cult_team.reckoning_complete)
reckoning.Grant(current)
bloodmark.Grant(current)
throwing.Grant(current)
@@ -162,3 +182,118 @@
throwing.Remove(current)
current.update_action_buttons_icon()
current.remove_status_effect(/datum/status_effect/cult_master)
/datum/team/cult
name = "Cult"
var/blood_target
var/image/blood_target_image
var/blood_target_reset_timer
var/cult_vote_called = FALSE
var/cult_mastered = FALSE
var/reckoning_complete = FALSE
/datum/team/cult/proc/setup_objectives()
//SAC OBJECTIVE , todo: move this to objective internals
var/list/target_candidates = list()
var/datum/objective/sacrifice/sac_objective = new
sac_objective.team = src
for(var/mob/living/carbon/human/player in GLOB.player_list)
if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && !is_convertable_to_cult(player) && player.stat != DEAD)
target_candidates += player.mind
if(target_candidates.len == 0)
message_admins("Cult Sacrifice: Could not find unconvertable target, checking for convertable target.")
for(var/mob/living/carbon/human/player in GLOB.player_list)
if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && player.stat != DEAD)
target_candidates += player.mind
listclearnulls(target_candidates)
if(LAZYLEN(target_candidates))
sac_objective.target = pick(target_candidates)
sac_objective.update_explanation_text()
var/datum/job/sacjob = SSjob.GetJob(sac_objective.target.assigned_role)
var/datum/preferences/sacface = sac_objective.target.current.client.prefs
var/icon/reshape = get_flat_human_icon(null, sacjob, sacface)
reshape.Shift(SOUTH, 4)
reshape.Shift(EAST, 1)
reshape.Crop(7,4,26,31)
reshape.Crop(-5,-3,26,30)
sac_objective.sac_image = reshape
objectives += sac_objective
else
message_admins("Cult Sacrifice: Could not find unconvertable or convertable target. WELP!")
//SUMMON OBJECTIVE
var/datum/objective/eldergod/summon_objective = new()
summon_objective.team = src
objectives += summon_objective
/datum/objective/sacrifice
var/sacced = FALSE
var/sac_image
/datum/objective/sacrifice/check_completion()
return sacced || completed
/datum/objective/sacrifice/update_explanation_text()
if(target && !sacced)
explanation_text = "Sacrifice [target], the [target.assigned_role] via invoking a Sacrifice rune with them on it and three acolytes around it."
else
explanation_text = "The veil has already been weakened here, proceed to the final objective."
/datum/objective/eldergod
var/summoned = FALSE
var/list/summon_spots = list()
/datum/objective/eldergod/New()
..()
var/sanity = 0
while(summon_spots.len < SUMMON_POSSIBILITIES && sanity < 100)
var/area/summon = pick(GLOB.sortedAreas - summon_spots)
if(summon && (summon.z in GLOB.station_z_levels) && summon.valid_territory)
summon_spots += summon
sanity++
update_explanation_text()
/datum/objective/eldergod/update_explanation_text()
explanation_text = "Summon Nar-Sie by invoking the rune 'Summon Nar-Sie'. <b>The summoning can only be accomplished in [english_list(summon_spots)] - where the veil is weak enough for the ritual to begin.</b>"
/datum/objective/eldergod/check_completion()
return summoned || completed
/datum/team/cult/proc/check_cult_victory()
for(var/datum/objective/O in objectives)
if(!O.check_completion())
return FALSE
return TRUE
/datum/team/cult/roundend_report()
var/list/parts = list()
if(check_cult_victory())
parts += "<span class='greentext big'>The cult has succeeded! Nar-sie has snuffed out another torch in the void!</span>"
else
parts += "<span class='redtext big'>The staff managed to stop the cult! Dark words and heresy are no match for Nanotrasen's finest!</span>"
if(objectives.len)
parts += "<b>The cultists' objectives were:</b>"
var/count = 1
for(var/datum/objective/objective in objectives)
if(objective.check_completion())
parts += "<b>Objective #[count]</b>: [objective.explanation_text] <span class='greentext'>Success!</span>"
else
parts += "<b>Objective #[count]</b>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
count++
if(members.len)
parts += "<span class='header'>The cultists were:</span>"
parts += printplayerlist(members)
return "<div class='panel redborder'>[parts.Join("<br>")]</div>"
+55 -5
View File
@@ -1,5 +1,6 @@
/datum/antagonist/traitor
name = "Traitor"
roundend_category = "traitors"
job_rank = ROLE_TRAITOR
var/should_specialise = FALSE //do we split into AI and human, set to true on inital assignment only
var/ai_datum = ANTAG_DATUM_TRAITOR_AI
@@ -8,7 +9,6 @@
var/employer = "The Syndicate"
var/give_objectives = TRUE
var/should_give_codewords = TRUE
var/list/objectives_given = list()
/datum/antagonist/traitor/human
var/should_equip = TRUE
@@ -52,9 +52,9 @@
if(should_specialise)
return ..()//we never did any of this anyway
SSticker.mode.traitors -= owner
for(var/O in objectives_given)
for(var/O in objectives)
owner.objectives -= O
objectives_given = list()
objectives = list()
if(!silent && owner.current)
to_chat(owner.current,"<span class='userdanger'> You are no longer the [special_role]! </span>")
owner.special_role = null
@@ -71,11 +71,11 @@
/datum/antagonist/traitor/proc/add_objective(var/datum/objective/O)
owner.objectives += O
objectives_given += O
objectives += O
/datum/antagonist/traitor/proc/remove_objective(var/datum/objective/O)
owner.objectives -= O
objectives_given -= O
objectives -= O
/datum/antagonist/traitor/proc/forge_traitor_objectives()
return
@@ -294,3 +294,53 @@
where = "In your [equipped_slot]"
to_chat(mob, "<BR><BR><span class='info'>[where] is a folder containing <b>secret documents</b> that another Syndicate group wants. We have set up a meeting with one of their agents on station to make an exchange. Exercise extreme caution as they cannot be trusted and may be hostile.</span><BR>")
//TODO Collate
/datum/antagonist/traitor/roundend_report()
var/list/result = list()
var/traitorwin = TRUE
result += printplayer(owner)
var/TC_uses = 0
var/uplink_true = FALSE
var/purchases = ""
for(var/datum/component/uplink/H in GLOB.uplinks)
if(H && H.owner && H.owner == owner.key)
TC_uses += H.spent_telecrystals
uplink_true = TRUE
purchases += H.purchase_log.generate_render(FALSE)
var/objectives_text = ""
if(objectives.len)//If the traitor had no objectives, don't need to process this.
var/count = 1
for(var/datum/objective/objective in objectives)
if(objective.check_completion())
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'>Success!</span>"
else
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
traitorwin = FALSE
count++
if(uplink_true)
var/uplink_text = "(used [TC_uses] TC) [purchases]"
if(TC_uses==0 && traitorwin)
var/static/icon/badass = icon('icons/badass.dmi', "badass")
uplink_text += "<BIG>[icon2html(badass, world)]</BIG>"
result += uplink_text
result += objectives_text
var/special_role_text = lowertext(name)
if(traitorwin)
result += "<span class='greentext'>The [special_role_text] was successful!</span>"
else
result += "<span class='redtext'>The [special_role_text] has failed!</span>"
SEND_SOUND(owner.current, 'sound/ambience/ambifailure.ogg')
return result.Join("<br>")
/datum/antagonist/traitor/roundend_report_footer()
return "<br><b>The code phrases were:</b> <span class='codephrase'>[GLOB.syndicate_code_phrase]</span><br>\
<b>The code responses were:</b> <span class='codephrase'>[GLOB.syndicate_code_response]</span><br>"
+30
View File
@@ -86,6 +86,7 @@ GLOBAL_LIST_INIT(devil_syllable, list("hal", "ve", "odr", "neit", "ci", "quon",
GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master", ", the Lord of all things", ", Jr."))
/datum/antagonist/devil
name = "Devil"
roundend_category = "devils"
job_rank = ROLE_DEVIL
//Don't delete upon mind destruction, otherwise soul re-selling will break.
delete_on_mind_deletion = FALSE
@@ -508,6 +509,35 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
owner.RemoveSpell(S)
.=..()
/datum/antagonist/devil/proc/printdevilinfo()
var/list/parts = list()
parts += "The devil's true name is: [truename]"
parts += "The devil's bans were:"
parts += "[GLOB.TAB][GLOB.lawlorify[LORE][ban]]"
parts += "[GLOB.TAB][GLOB.lawlorify[LORE][bane]]"
parts += "[GLOB.TAB][GLOB.lawlorify[LORE][obligation]]"
parts += "[GLOB.TAB][GLOB.lawlorify[LORE][banish]]"
return parts.Join("<br>")
/datum/antagonist/devil/roundend_report()
var/list/parts = list()
parts += printplayer(owner)
parts += printdevilinfo()
parts += printobjectives(owner)
return parts.Join("<br>")
/datum/antagonist/devil/roundend_report_footer()
//sintouched go here for now as a hack , TODO proper antag datum for these
var/list/parts = list()
if(SSticker.mode.sintouched.len)
parts += "<span class='header'>The sintouched were:</span>"
var/list/sintouchedUnique = uniqueList(SSticker.mode.sintouched)
for(var/S in sintouchedUnique)
var/datum/mind/sintouched_mind = S
parts += printplayer(sintouched_mind)
parts += printobjectives(sintouched_mind)
return parts.Join("<br>")
//A simple super light weight datum for the codex gigas.
/datum/fakeDevil
var/truename
+170
View File
@@ -0,0 +1,170 @@
#define MONKEYS_ESCAPED 1
#define MONKEYS_LIVED 2
#define MONKEYS_DIED 3
#define DISEASE_LIVED 4
/datum/antagonist/monkey
name = "Monkey"
job_rank = ROLE_MONKEY
roundend_category = "monkeys"
var/datum/objective_team/monkey/monkey_team
/datum/antagonist/monkey/on_gain()
. = ..()
SSticker.mode.ape_infectees += owner
owner.special_role = "Infected Monkey"
var/datum/disease/D = new /datum/disease/transformation/jungle_fever
if(!owner.current.HasDisease(D))
D.affected_mob = owner
owner.current.viruses += D
else
QDEL_NULL(D)
/datum/antagonist/monkey/greet()
to_chat(owner, "<b>You are a monkey now!</b>")
to_chat(owner, "<b>Bite humans to infect them, follow the orders of the monkey leaders, and help fellow monkeys!</b>")
to_chat(owner, "<b>Ensure at least one infected monkey escapes on the Emergency Shuttle!</b>")
to_chat(owner, "<b><i>As an intelligent monkey, you know how to use technology and how to ventcrawl while wearing things.</i></b>")
to_chat(owner, "<b>You can use :k to talk to fellow monkeys!</b>")
SEND_SOUND(owner.current, sound('sound/ambience/antag/monkey.ogg'))
/datum/antagonist/monkey/on_removal()
. = ..()
owner.special_role = null
SSticker.mode.ape_infectees -= owner
var/datum/disease/D = (/datum/disease/transformation/jungle_fever in owner.current.viruses)
if(D)
D.cure()
/datum/antagonist/monkey/create_team(datum/objective_team/monkey/new_team)
if(!new_team)
for(var/datum/antagonist/monkey/N in get_antagonists(/datum/antagonist/monkey, TRUE))
if(N.monkey_team)
monkey_team = N.monkey_team
return
monkey_team = new /datum/objective_team/monkey
monkey_team.update_objectives()
return
if(!istype(new_team))
stack_trace("Wrong team type passed to [type] initialization.")
monkey_team = new_team
/datum/antagonist/monkey/proc/forge_objectives()
if(monkey_team)
owner.objectives |= monkey_team.objectives
/datum/antagonist/monkey/leader
name = "Monkey Leader"
/datum/antagonist/monkey/leader/on_gain()
. = ..()
var/datum/disease/D = (/datum/disease/transformation/jungle_fever in owner.current.viruses)
if(D)
D.visibility_flags = HIDDEN_SCANNER|HIDDEN_PANDEMIC
var/obj/item/organ/heart/freedom/F = new
F.Insert(owner.current, drop_if_replaced = FALSE)
SSticker.mode.ape_leaders += owner
owner.special_role = "Monkey Leader"
/datum/antagonist/monkey/leader/on_removal()
. = ..()
SSticker.mode.ape_leaders -= owner
var/obj/item/organ/heart/H = new
H.Insert(owner.current, drop_if_replaced = FALSE) //replace freedom heart with normal heart
/datum/antagonist/monkey/leader/greet()
to_chat(owner, "<B><span class='notice'>You are the Jungle Fever patient zero!!</B></span>")
to_chat(owner, "<b>You have been planted onto this station by the Animal Rights Consortium.</b>")
to_chat(owner, "<b>Soon the disease will transform you into an ape. Afterwards, you will be able spread the infection to others with a bite.</b>")
to_chat(owner, "<b>While your infection strain is undetectable by scanners, any other infectees will show up on medical equipment.</b>")
to_chat(owner, "<b>Your mission will be deemed a success if any of the live infected monkeys reach CentCom.</b>")
to_chat(owner, "<b>As an initial infectee, you will be considered a 'leader' by your fellow monkeys.</b>")
to_chat(owner, "<b>You can use :k to talk to fellow monkeys!</b>")
SEND_SOUND(owner.current, sound('sound/ambience/antag/monkey.ogg'))
/datum/objective/monkey
explanation_text = "Ensure that infected monkeys escape on the emergency shuttle!"
martyr_compatible = TRUE
var/monkeys_to_win = 1
var/escaped_monkeys = 0
/datum/objective/monkey/check_completion()
var/datum/disease/D = new /datum/disease/transformation/jungle_fever()
for(var/mob/living/carbon/monkey/M in GLOB.alive_mob_list)
if (M.HasDisease(D) && (M.onCentCom() || M.onSyndieBase()))
escaped_monkeys++
if(escaped_monkeys >= monkeys_to_win)
return TRUE
return FALSE
/datum/objective_team/monkey
name = "Monkeys"
/datum/objective_team/monkey/proc/update_objectives()
objectives = list()
var/datum/objective/monkey/O = new /datum/objective/monkey()
O.team = src
objectives += O
return
/datum/objective_team/monkey/proc/infected_monkeys_alive()
var/datum/disease/D = new /datum/disease/transformation/jungle_fever()
for(var/mob/living/carbon/monkey/M in GLOB.alive_mob_list)
if(M.HasDisease(D))
return TRUE
return FALSE
/datum/objective_team/monkey/proc/infected_monkeys_escaped()
var/datum/disease/D = new /datum/disease/transformation/jungle_fever()
for(var/mob/living/carbon/monkey/M in GLOB.alive_mob_list)
if(M.HasDisease(D) && (M.onCentCom() || M.onSyndieBase()))
return TRUE
return FALSE
/datum/objective_team/monkey/proc/infected_humans_escaped()
var/datum/disease/D = new /datum/disease/transformation/jungle_fever()
for(var/mob/living/carbon/human/M in GLOB.alive_mob_list)
if(M.HasDisease(D) && (M.onCentCom() || M.onSyndieBase()))
return TRUE
return FALSE
/datum/objective_team/monkey/proc/infected_humans_alive()
var/datum/disease/D = new /datum/disease/transformation/jungle_fever()
for(var/mob/living/carbon/human/M in GLOB.alive_mob_list)
if(M.HasDisease(D))
return TRUE
return FALSE
/datum/objective_team/monkey/proc/get_result()
if(infected_monkeys_escaped())
return MONKEYS_ESCAPED
if(infected_monkeys_alive())
return MONKEYS_LIVED
if(infected_humans_alive() || infected_humans_escaped())
return DISEASE_LIVED
return MONKEYS_DIED
/datum/objective_team/monkey/roundend_report()
var/list/parts = list()
switch(get_result())
if(MONKEYS_ESCAPED)
parts += "<span class='greentext big'><B>Monkey Major Victory!</B></span>"
parts += "<span class='greentext'><B>Central Command and [station_name()] were taken over by the monkeys! Ook ook!</B></span>"
if(MONKEYS_LIVED)
parts += "<FONT size = 3><B>Monkey Minor Victory!</B></FONT>"
parts += "<span class='greentext'><B>[station_name()] was taken over by the monkeys! Ook ook!</B></span>"
if(DISEASE_LIVED)
parts += "<span class='redtext big'><B>Monkey Minor Defeat!</B></span>"
parts += "<span class='redtext'><B>All the monkeys died, but the disease lives on! The future is uncertain.</B></span>"
if(MONKEYS_DIED)
parts += "<span class='redtext big'><B>Monkey Major Defeat!</B></span>"
parts += "<span class='redtext'><B>All the monkeys died, and Jungle Fever was wiped out!</B></span>"
if(LAZYLEN(SSticker.mode.ape_leaders))
parts += "<span class='header'>The monkey leaders were:</span>"
parts += printplayerlist(SSticker.mode.ape_leaders)
if(LAZYLEN(SSticker.mode.ape_infectees))
parts += "<span class='header'>The monkeys were:</span>"
parts += printplayerlist(SSticker.mode.ape_infectees)
return "<div class='panel redborder'>[parts.Join("<br>")]</div>"
+11 -10
View File
@@ -37,19 +37,20 @@
else if(M.assigned_role in GLOB.command_positions)
possible_targets[M] = 1 //good-guy
var/list/objectives = list(1,2,3,4)
while(owner.objectives.len < quantity)
switch(pick_n_take(objectives))
var/list/possible_objectives = list(1,2,3,4)
while(objectives.len < quantity)
switch(pick_n_take(possible_objectives))
if(1) //research
var/datum/objective/download/O = new /datum/objective/download()
O.owner = owner
O.gen_amount_goal()
owner.objectives += O
objectives += O
if(2) //steal
var/datum/objective/steal/special/O = new /datum/objective/steal/special()
O.owner = owner
owner.objectives += O
objectives += O
if(3) //protect/kill
if(!possible_targets.len) continue
@@ -63,13 +64,13 @@
O.owner = owner
O.target = M
O.explanation_text = "Slay \the [M.current.real_name], the [M.assigned_role]."
owner.objectives += O
objectives += O
else //protect
var/datum/objective/protect/O = new /datum/objective/protect()
O.owner = owner
O.target = M
O.explanation_text = "Protect \the [M.current.real_name], the [M.assigned_role], from harm."
owner.objectives += O
objectives += O
if(4) //debrain/capture
if(!possible_targets.len) continue
var/selected = rand(1,possible_targets.len)
@@ -82,17 +83,17 @@
O.owner = owner
O.target = M
O.explanation_text = "Steal the brain of [M.current.real_name]."
owner.objectives += O
objectives += O
else //capture
var/datum/objective/capture/O = new /datum/objective/capture()
O.owner = owner
O.gen_amount_goal()
owner.objectives += O
objectives += O
else
break
var/datum/objective/O = new /datum/objective/survive()
O.owner = owner
owner.objectives += O
owner.objectives |= objectives
/proc/remove_ninja(mob/living/L)
+322
View File
@@ -0,0 +1,322 @@
#define NUKE_RESULT_FLUKE 0
#define NUKE_RESULT_NUKE_WIN 1
#define NUKE_RESULT_CREW_WIN 2
#define NUKE_RESULT_CREW_WIN_SYNDIES_DEAD 3
#define NUKE_RESULT_DISK_LOST 4
#define NUKE_RESULT_DISK_STOLEN 5
#define NUKE_RESULT_NOSURVIVORS 6
#define NUKE_RESULT_WRONG_STATION 7
#define NUKE_RESULT_WRONG_STATION_DEAD 8
/datum/antagonist/nukeop
name = "Nuclear Operative"
roundend_category = "syndicate operatives" //just in case
job_rank = ROLE_OPERATIVE
var/datum/team/nuclear/nuke_team
var/always_new_team = FALSE //If not assigned a team by default ops will try to join existing ones, set this to TRUE to always create new team.
var/send_to_spawnpoint = TRUE //Should the user be moved to default spawnpoint.
var/nukeop_outfit = /datum/outfit/syndicate
/datum/antagonist/nukeop/proc/update_synd_icons_added(mob/living/M)
var/datum/atom_hud/antag/opshud = GLOB.huds[ANTAG_HUD_OPS]
opshud.join_hud(M)
set_antag_hud(M, "synd")
/datum/antagonist/nukeop/proc/update_synd_icons_removed(mob/living/M)
var/datum/atom_hud/antag/opshud = GLOB.huds[ANTAG_HUD_OPS]
opshud.leave_hud(M)
set_antag_hud(M, null)
/datum/antagonist/nukeop/apply_innate_effects(mob/living/mob_override)
var/mob/living/M = mob_override || owner.current
update_synd_icons_added(M)
/datum/antagonist/nukeop/remove_innate_effects(mob/living/mob_override)
var/mob/living/M = mob_override || owner.current
update_synd_icons_removed(M)
/datum/antagonist/nukeop/proc/equip_op()
if(!ishuman(owner.current))
return
var/mob/living/carbon/human/H = owner.current
H.set_species(/datum/species/human) //Plasamen burn up otherwise, and lizards are vulnerable to asimov AIs
H.equipOutfit(nukeop_outfit)
return TRUE
/datum/antagonist/nukeop/greet()
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ops.ogg',100,0)
to_chat(owner, "<span class='notice'>You are a [nuke_team ? nuke_team.syndicate_name : "syndicate"] agent!</span>")
owner.announce_objectives()
return
/datum/antagonist/nukeop/on_gain()
give_alias()
forge_objectives()
. = ..()
equip_op()
memorize_code()
if(send_to_spawnpoint)
move_to_spawnpoint()
/datum/antagonist/nukeop/get_team()
return nuke_team
/datum/antagonist/nukeop/proc/assign_nuke()
if(nuke_team && !nuke_team.tracked_nuke)
nuke_team.memorized_code = random_nukecode()
var/obj/machinery/nuclearbomb/nuke = locate("syndienuke") in GLOB.nuke_list
if(nuke)
nuke_team.tracked_nuke = nuke
if(nuke.r_code == "ADMIN")
nuke.r_code = nuke_team.memorized_code
else //Already set by admins/something else?
nuke_team.memorized_code = nuke.r_code
else
stack_trace("Syndicate nuke not found during nuke team creation.")
nuke_team.memorized_code = null
/datum/antagonist/nukeop/proc/give_alias()
if(nuke_team && nuke_team.syndicate_name)
var/number = 1
number = nuke_team.members.Find(owner)
owner.current.real_name = "[nuke_team.syndicate_name] Operative #[number]"
/datum/antagonist/nukeop/proc/memorize_code()
if(nuke_team && nuke_team.tracked_nuke && nuke_team.memorized_code)
owner.store_memory("<B>[nuke_team.tracked_nuke] Code</B>: [nuke_team.memorized_code]", 0, 0)
to_chat(owner, "The nuclear authorization code is: <B>[nuke_team.memorized_code]</B>")
else
to_chat(owner, "Unfortunately the syndicate was unable to provide you with nuclear authorization code.")
/datum/antagonist/nukeop/proc/forge_objectives()
if(nuke_team)
owner.objectives |= nuke_team.objectives
/datum/antagonist/nukeop/proc/move_to_spawnpoint()
var/team_number = 1
if(nuke_team)
team_number = nuke_team.members.Find(owner)
owner.current.forceMove(GLOB.nukeop_start[((team_number - 1) % GLOB.nukeop_start.len) + 1])
/datum/antagonist/nukeop/leader/move_to_spawnpoint()
owner.current.forceMove(pick(GLOB.nukeop_leader_start))
/datum/antagonist/nukeop/create_team(datum/team/nuclear/new_team)
if(!new_team)
if(!always_new_team)
for(var/datum/antagonist/nukeop/N in GLOB.antagonists)
if(N.nuke_team)
nuke_team = N.nuke_team
return
nuke_team = new /datum/team/nuclear
nuke_team.update_objectives()
assign_nuke() //This is bit ugly
return
if(!istype(new_team))
stack_trace("Wrong team type passed to [type] initialization.")
nuke_team = new_team
/datum/antagonist/nukeop/leader
name = "Nuclear Operative Leader"
nukeop_outfit = /datum/outfit/syndicate/leader
always_new_team = TRUE
var/title
/datum/antagonist/nukeop/leader/memorize_code()
..()
if(nuke_team && nuke_team.memorized_code)
var/obj/item/paper/P = new
P.info = "The nuclear authorization code is: <b>[nuke_team.memorized_code]</b>"
P.name = "nuclear bomb code"
var/mob/living/carbon/human/H = owner.current
if(!istype(H))
P.forceMove(get_turf(H))
else
H.put_in_hands(P, TRUE)
H.update_icons()
/datum/antagonist/nukeop/leader/give_alias()
title = pick("Czar", "Boss", "Commander", "Chief", "Kingpin", "Director", "Overlord")
if(nuke_team && nuke_team.syndicate_name)
owner.current.real_name = "[nuke_team.syndicate_name] [title]"
else
owner.current.real_name = "Syndicate [title]"
/datum/antagonist/nukeop/leader/greet()
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ops.ogg',100,0)
to_chat(owner, "<B>You are the Syndicate [title] for this mission. You are responsible for the distribution of telecrystals and your ID is the only one who can open the launch bay doors.</B>")
to_chat(owner, "<B>If you feel you are not up to this task, give your ID to another operative.</B>")
to_chat(owner, "<B>In your hand you will find a special item capable of triggering a greater challenge for your team. Examine it carefully and consult with your fellow operatives before activating it.</B>")
owner.announce_objectives()
addtimer(CALLBACK(src, .proc/nuketeam_name_assign), 1)
/datum/antagonist/nukeop/leader/proc/nuketeam_name_assign()
if(!nuke_team)
return
nuke_team.rename_team(ask_name())
/datum/team/nuclear/proc/rename_team(new_name)
syndicate_name = new_name
name = "[syndicate_name] Team"
for(var/I in members)
var/datum/mind/synd_mind = I
var/mob/living/carbon/human/H = synd_mind.current
if(!istype(H))
continue
var/chosen_name = H.dna.species.random_name(H.gender,0,syndicate_name)
H.fully_replace_character_name(H.real_name,chosen_name)
/datum/antagonist/nukeop/leader/proc/ask_name()
var/randomname = pick(GLOB.last_names)
var/newname = stripped_input(owner.current,"You are the nuke operative [title]. Please choose a last name for your family.", "Name change",randomname)
if (!newname)
newname = randomname
else
newname = reject_bad_name(newname)
if(!newname)
newname = randomname
return capitalize(newname)
/datum/antagonist/nukeop/lone
name = "Lone Operative"
always_new_team = TRUE
send_to_spawnpoint = FALSE //Handled by event
nukeop_outfit = /datum/outfit/syndicate/full
/datum/antagonist/nukeop/lone/assign_nuke()
if(nuke_team && !nuke_team.tracked_nuke)
nuke_team.memorized_code = random_nukecode()
var/obj/machinery/nuclearbomb/selfdestruct/nuke = locate() in GLOB.nuke_list
if(nuke)
nuke_team.tracked_nuke = nuke
if(nuke.r_code == "ADMIN")
nuke.r_code = nuke_team.memorized_code
else //Already set by admins/something else?
nuke_team.memorized_code = nuke.r_code
else
stack_trace("Station self destruct ot found during lone op team creation.")
nuke_team.memorized_code = null
/datum/team/nuclear
var/syndicate_name
var/obj/machinery/nuclearbomb/tracked_nuke
var/core_objective = /datum/objective/nuclear
var/memorized_code
/datum/team/nuclear/New()
..()
syndicate_name = syndicate_name()
/datum/team/nuclear/proc/update_objectives()
if(core_objective)
var/datum/objective/O = new core_objective
O.team = src
objectives += O
/datum/team/nuclear/proc/disk_rescued()
for(var/obj/item/disk/nuclear/D in GLOB.poi_list)
if(!D.onCentCom())
return FALSE
return TRUE
/datum/team/nuclear/proc/operatives_dead()
for(var/I in members)
var/datum/mind/operative_mind = I
if(ishuman(operative_mind.current) && (operative_mind.current.stat != DEAD))
return FALSE
return TRUE
/datum/team/nuclear/proc/syndies_escaped()
var/obj/docking_port/mobile/S = SSshuttle.getShuttle("syndicate")
return (S && (S.z == ZLEVEL_CENTCOM || S.z == ZLEVEL_TRANSIT))
/datum/team/nuclear/proc/get_result()
var/evacuation = SSshuttle.emergency.mode == SHUTTLE_ENDGAME
var/disk_rescued = disk_rescued()
var/syndies_didnt_escape = !syndies_escaped()
var/station_was_nuked = SSticker.mode.station_was_nuked
var/nuke_off_station = SSticker.mode.nuke_off_station
if(nuke_off_station == NUKE_SYNDICATE_BASE)
return NUKE_RESULT_FLUKE
else if(!disk_rescued && station_was_nuked && !syndies_didnt_escape)
return NUKE_RESULT_NUKE_WIN
else if (!disk_rescued && station_was_nuked && syndies_didnt_escape)
return NUKE_RESULT_NOSURVIVORS
else if (!disk_rescued && !station_was_nuked && nuke_off_station && !syndies_didnt_escape)
return NUKE_RESULT_WRONG_STATION
else if (!disk_rescued && !station_was_nuked && nuke_off_station && syndies_didnt_escape)
return NUKE_RESULT_WRONG_STATION_DEAD
else if ((disk_rescued || evacuation) && operatives_dead())
return NUKE_RESULT_CREW_WIN_SYNDIES_DEAD
else if (disk_rescued)
return NUKE_RESULT_CREW_WIN
else if (!disk_rescued && operatives_dead())
return NUKE_RESULT_DISK_LOST
else if (!disk_rescued && evacuation)
return NUKE_RESULT_DISK_STOLEN
else
return //Undefined result
/datum/team/nuclear/roundend_report()
var/list/parts = list()
parts += "<span class='header'>[syndicate_name] Operatives:</span>"
switch(get_result())
if(NUKE_RESULT_FLUKE)
parts += "<span class='redtext big'>Humiliating Syndicate Defeat</span>"
parts += "<B>The crew of [station_name()] gave [syndicate_name] operatives back their bomb! The syndicate base was destroyed!</B> Next time, don't lose the nuke!"
if(NUKE_RESULT_NUKE_WIN)
parts += "<span class='greentext big'>Syndicate Major Victory!</span>"
parts += "<B>[syndicate_name] operatives have destroyed [station_name()]!</B>"
if(NUKE_RESULT_NOSURVIVORS)
parts += "<span class='neutraltext big'>Total Annihilation</span>"
parts += "<B>[syndicate_name] operatives destroyed [station_name()] but did not leave the area in time and got caught in the explosion.</B> Next time, don't lose the disk!"
if(NUKE_RESULT_WRONG_STATION)
parts += "<span class='redtext big'>Crew Minor Victory</span>"
parts += "<B>[syndicate_name] operatives secured the authentication disk but blew up something that wasn't [station_name()].</B> Next time, don't do that!"
if(NUKE_RESULT_WRONG_STATION_DEAD)
parts += "<span class='redtext big'>[syndicate_name] operatives have earned Darwin Award!</span>"
parts += "<B>[syndicate_name] operatives blew up something that wasn't [station_name()] and got caught in the explosion.</B> Next time, don't do that!"
if(NUKE_RESULT_CREW_WIN_SYNDIES_DEAD)
parts += "<span class='redtext big'>Crew Major Victory!</span>"
parts += "<B>The Research Staff has saved the disk and killed the [syndicate_name] Operatives</B>"
if(NUKE_RESULT_CREW_WIN)
parts += "<span class='redtext big'>Crew Major Victory</span>"
parts += "<B>The Research Staff has saved the disk and stopped the [syndicate_name] Operatives!</B>"
if(NUKE_RESULT_DISK_LOST)
parts += "<span class='neutraltext big'>Neutral Victory!</span>"
parts += "<B>The Research Staff failed to secure the authentication disk but did manage to kill most of the [syndicate_name] Operatives!</B>"
if(NUKE_RESULT_DISK_STOLEN)
parts += "<span class='greentext big'>Syndicate Minor Victory!</span>"
parts += "<B>[syndicate_name] operatives survived the assault but did not achieve the destruction of [station_name()].</B> Next time, don't lose the disk!"
else
parts += "<span class='neutraltext big'>Neutral Victory</span>"
parts += "<B>Mission aborted!</B>"
var/text = "<br><span class='header'>The syndicate operatives were:</span>"
var/purchases = ""
var/TC_uses = 0
for(var/I in members)
var/datum/mind/syndicate = I
for(var/U in GLOB.uplinks)
var/datum/component/uplink/H = U
if(H.owner == syndicate.key)
TC_uses += H.purchase_log.total_spent
if(H.purchase_log)
purchases += H.purchase_log.generate_render(show_key = FALSE)
else
stack_trace("WARNING: Nuke Op uplink with no purchase_log Owner: [H.owner]")
text += printplayerlist(members)
text += "<br>"
text += "(Syndicates used [TC_uses] TC) [purchases]"
if(TC_uses == 0 && SSticker.mode.station_was_nuked && !operatives_dead())
text += "<BIG>[icon2html('icons/badass.dmi', world, "badass")]</BIG>"
parts += text
return "<div class='panel redborder'>[parts.Join("<br>")]</div>"
+32 -38
View File
@@ -1,7 +1,8 @@
/datum/antagonist/pirate
name = "Space Pirate"
job_rank = ROLE_TRAITOR
var/datum/objective_team/pirate/crew
roundend_category = "space pirates"
var/datum/team/pirate/crew
/datum/antagonist/pirate/greet()
to_chat(owner, "<span class='boldannounce'>You are a Space Pirate!</span>")
@@ -11,15 +12,16 @@
/datum/antagonist/pirate/get_team()
return crew
/datum/antagonist/pirate/create_team(datum/objective_team/pirate/new_team)
/datum/antagonist/pirate/create_team(datum/team/pirate/new_team)
if(!new_team)
for(var/datum/antagonist/pirate/P in GLOB.antagonists)
if(P.crew)
new_team = P.crew
crew = P.crew
return
if(!new_team)
crew = new /datum/objective_team/pirate
crew = new /datum/team/pirate
crew.forge_objectives()
return
return
if(!istype(new_team))
stack_trace("Wrong team type passed to [type] initialization.")
crew = new_team
@@ -34,11 +36,10 @@
owner.objectives -= crew.objectives
. = ..()
/datum/objective_team/pirate
/datum/team/pirate
name = "Pirate crew"
var/list/objectives = list()
/datum/objective_team/pirate/proc/forge_objectives()
/datum/team/pirate/proc/forge_objectives()
var/datum/objective/loot/getbooty = new()
getbooty.team = src
getbooty.storage_area = locate(/area/shuttle/pirate/vault) in GLOB.sortedAreas
@@ -84,11 +85,11 @@ GLOBAL_LIST_INIT(pirate_loot_cache, typecacheof(list(
loot_table[lootname] = count
else
loot_table[lootname] += count
var/text = ""
var/list/loot_texts = list()
for(var/key in loot_table)
var/amount = loot_table[key]
text += "[amount] [key][amount > 1 ? "s":""], "
return text
loot_texts += "[amount] [key][amount > 1 ? "s":""]"
return loot_texts.Join(", ")
/datum/objective/loot/proc/get_loot_value()
if(!storage_area)
@@ -104,32 +105,25 @@ GLOBAL_LIST_INIT(pirate_loot_cache, typecacheof(list(
/datum/objective/loot/check_completion()
return ..() || get_loot_value() >= target_value
/datum/team/pirate/roundend_report()
var/list/parts = list()
//These need removal ASAP as everything is converted to datum antags.
/datum/game_mode/proc/auto_declare_completion_pirates()
var/list/datum/mind/pirates = get_antagonists(/datum/antagonist/pirate)
var/datum/objective_team/pirate/crew
var/text = ""
if(pirates.len)
text += "<br><b>Space Pirates were:</b>"
for(var/datum/mind/M in pirates)
text += printplayer(M)
if(!crew)
var/datum/antagonist/pirate/P = M.has_antag_datum(/datum/antagonist/pirate)
crew = P.crew
if(crew)
text += "<br>Loot stolen: "
var/datum/objective/loot/L = locate() in crew.objectives
text += L.loot_listing()
text += "<br>Total loot value : [L.get_loot_value()]/[L.target_value] credits"
parts += "<span class='header'>Space Pirates were:</span>"
var/all_dead = TRUE
for(var/datum/mind/M in crew.members)
if(considered_alive(M))
all_dead = FALSE
break
if(L.check_completion() && !all_dead)
text += "<br><font color='green'><b>The pirate crew was successful!</b></font>"
else
text += "<br><span class='boldannounce'>The pirate crew has failed.</span>"
to_chat(world, text)
var/all_dead = TRUE
for(var/datum/mind/M in members)
if(considered_alive(M))
all_dead = FALSE
parts += printplayerlist(members)
parts += "Loot stolen: "
var/datum/objective/loot/L = locate() in objectives
parts += L.loot_listing()
parts += "Total loot value : [L.get_loot_value()]/[L.target_value] credits"
if(L.check_completion() && !all_dead)
parts += "<span class='greentext big'>The pirate crew was successful!</span>"
else
parts += "<span class='redtext big'>The pirate crew has failed.</span>"
return "<div class='panel redborder'>[parts.Join("<br>")]</div>"
+71 -18
View File
@@ -3,9 +3,10 @@
/datum/antagonist/rev
name = "Revolutionary"
roundend_category = "revolutionaries" // if by some miracle revolutionaries without revolution happen
job_rank = ROLE_REV
var/hud_type = "rev"
var/datum/objective_team/revolution/rev_team
var/datum/team/revolution/rev_team
/datum/antagonist/rev/can_be_owned(datum/mind/new_owner)
. = ..()
@@ -39,17 +40,17 @@
. = ..()
/datum/antagonist/rev/greet()
to_chat(owner, "<span class='danger'><FONT size = 3> You are now a revolutionary! Help your cause. Do not harm your fellow freedom fighters. You can identify your comrades by the red \"R\" icons, and your leaders by the blue \"R\" icons. Help them kill the heads to win the revolution!</FONT></span>")
to_chat(owner, "<span class='userdanger'>You are now a revolutionary! Help your cause. Do not harm your fellow freedom fighters. You can identify your comrades by the red \"R\" icons, and your leaders by the blue \"R\" icons. Help them kill the heads to win the revolution!</span>")
owner.announce_objectives()
/datum/antagonist/rev/create_team(datum/objective_team/revolution/new_team)
/datum/antagonist/rev/create_team(datum/team/revolution/new_team)
if(!new_team)
//For now only one revolution at a time
for(var/datum/antagonist/rev/head/H in GLOB.antagonists)
if(H.rev_team)
rev_team = H.rev_team
return
rev_team = new /datum/objective_team/revolution
rev_team = new /datum/team/revolution
rev_team.update_objectives()
rev_team.update_heads()
return
@@ -77,7 +78,7 @@
old_owner.add_antag_datum(new_revhead,old_team)
new_revhead.silent = FALSE
to_chat(old_owner, "<span class='userdanger'>You have proved your devotion to revolution! You are a head revolutionary now!</span>")
/datum/antagonist/rev/head
name = "Head Revolutionary"
@@ -131,14 +132,14 @@
old_owner.add_antag_datum(new_rev,old_team)
new_rev.silent = FALSE
to_chat(old_owner, "<span class='userdanger'>Revolution has been disappointed of your leader traits! You are a regular revolutionary now!</span>")
/datum/antagonist/rev/farewell()
if(ishuman(owner.current))
owner.current.visible_message("[owner.current] looks like they just remembered their real allegiance!")
to_chat(owner, "<span class='userdanger'><FONT size = 3>You are no longer a brainwashed revolutionary! Your memory is hazy from the time you were a rebel...the only thing you remember is the name of the one who brainwashed you...</FONT></span>")
owner.current.visible_message("<span class='deconversion_message'>[owner.current] looks like they just remembered their real allegiance!</span>", ignored_mob = owner.current)
to_chat(owner, "<span class='userdanger'>You are no longer a brainwashed revolutionary! Your memory is hazy from the time you were a rebel...the only thing you remember is the name of the one who brainwashed you...</span>")
else if(issilicon(owner.current))
owner.current.visible_message("The frame beeps contentedly, purging the hostile memory engram from the MMI before initalizing it.")
to_chat(owner, "<span class='userdanger'><FONT size = 3>The frame's firmware detects and deletes your neural reprogramming! You remember nothing but the name of the one who flashed you.</FONT></span>")
owner.current.visible_message("<span class='deconversion_message'>The frame beeps contentedly, purging the hostile memory engram from the MMI before initalizing it.</span>", ignored_mob = owner.current)
to_chat(owner, "<span class='userdanger'>The frame's firmware detects and deletes your neural reprogramming! You remember nothing but the name of the one who flashed you.</span>")
/datum/antagonist/rev/proc/remove_revolutionary(borged, deconverter)
log_attack("[owner.current] (Key: [key_name(owner.current)]) has been deconverted from the revolution by [deconverter] (Key: [key_name(deconverter)])!")
@@ -163,7 +164,7 @@
if(remove_clumsy && owner.assigned_role == "Clown")
to_chat(owner, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
H.dna.remove_mutation(CLOWNMUT)
if(give_flash)
var/obj/item/device/assembly/flash/T = new(H)
var/list/slots = list (
@@ -176,18 +177,17 @@
to_chat(H, "The Syndicate were unfortunately unable to get you a flash.")
else
to_chat(H, "The flash in your [where] will help you to persuade the crew to join your cause.")
if(give_hud)
var/obj/item/organ/cyberimp/eyes/hud/security/syndicate/S = new(H)
S.Insert(H, special = FALSE, drop_if_replaced = FALSE)
to_chat(H, "Your eyes have been implanted with a cybernetic security HUD which will help you keep track of who is mindshield-implanted, and therefore unable to be recruited.")
/datum/objective_team/revolution
/datum/team/revolution
name = "Revolution"
var/list/objectives = list()
var/max_headrevs = 3
/datum/objective_team/revolution/proc/update_objectives(initial = FALSE)
/datum/team/revolution/proc/update_objectives(initial = FALSE)
var/untracked_heads = SSjob.get_all_heads()
for(var/datum/objective/mutiny/O in objectives)
untracked_heads -= O.target
@@ -199,16 +199,16 @@
objectives += new_target
for(var/datum/mind/M in members)
M.objectives |= objectives
addtimer(CALLBACK(src,.proc/update_objectives),HEAD_UPDATE_PERIOD,TIMER_UNIQUE)
/datum/objective_team/revolution/proc/head_revolutionaries()
/datum/team/revolution/proc/head_revolutionaries()
. = list()
for(var/datum/mind/M in members)
if(M.has_antag_datum(/datum/antagonist/rev/head))
. += M
/datum/objective_team/revolution/proc/update_heads()
/datum/team/revolution/proc/update_heads()
if(SSticker.HasRoundStarted())
var/list/datum/mind/head_revolutionaries = head_revolutionaries()
var/list/datum/mind/heads = SSjob.get_all_heads()
@@ -227,3 +227,56 @@
rev.promote()
addtimer(CALLBACK(src,.proc/update_heads),HEAD_UPDATE_PERIOD,TIMER_UNIQUE)
/datum/team/revolution/roundend_report()
if(!members.len)
return
var/list/result = list()
result += "<div class='panel redborder'>"
var/num_revs = 0
var/num_survivors = 0
for(var/mob/living/carbon/survivor in GLOB.alive_mob_list)
if(survivor.ckey)
num_survivors++
if(survivor.mind)
if(is_revolutionary(survivor))
num_revs++
if(num_survivors)
result += "Command's Approval Rating: <B>[100 - round((num_revs/num_survivors)*100, 0.1)]%</B><br>"
var/list/targets = list()
var/list/datum/mind/headrevs = get_antagonists(/datum/antagonist/rev/head)
var/list/datum/mind/revs = get_antagonists(/datum/antagonist/rev,TRUE)
if(headrevs.len)
var/list/headrev_part = list()
headrev_part += "<span class='header'>The head revolutionaries were:</span>"
headrev_part += printplayerlist(headrevs,TRUE)
result += headrev_part.Join("<br>")
if(revs.len)
var/list/rev_part = list()
rev_part += "<span class='header'>The revolutionaries were:</span>"
rev_part += printplayerlist(revs,TRUE)
result += rev_part.Join("<br>")
var/list/heads = SSjob.get_all_heads()
if(heads.len)
var/head_text = "<span class='header'>The heads of staff were:</span>"
head_text += "<ul class='playerlist'>"
for(var/datum/mind/head in heads)
var/target = (head in targets)
head_text += "<li>"
if(target)
head_text += "<span class='redtext'>Target</span>"
head_text += "[printplayer(head, 1)]</li>"
head_text += "</ul><br>"
result += head_text
result += "</div>"
return result.Join()
+49 -5
View File
@@ -5,13 +5,13 @@
/datum/antagonist/wizard
name = "Space Wizard"
roundend_category = "wizards/witches"
job_rank = ROLE_WIZARD
var/give_objectives = TRUE
var/strip = TRUE //strip before equipping
var/allow_rename = TRUE
var/hud_version = "wizard"
var/datum/objective_team/wizard/wiz_team //Only created if wizard summons apprentices
var/list/objectives = list() //this should be base datum antag proc and list, todo make lazy
var/datum/team/wizard/wiz_team //Only created if wizard summons apprentices
var/move_to_lair = TRUE
var/outfit_type = /datum/outfit/wizard
var/wiz_age = WIZARD_AGE_MIN /* Wizards by nature cannot be too young. */
@@ -33,7 +33,7 @@
/datum/antagonist/wizard/proc/unregister()
SSticker.mode.wizards -= src
/datum/antagonist/wizard/create_team(datum/objective_team/wizard/new_team)
/datum/antagonist/wizard/create_team(datum/team/wizard/new_team)
if(!new_team)
return
if(!istype(new_team))
@@ -43,12 +43,14 @@
/datum/antagonist/wizard/get_team()
return wiz_team
/datum/objective_team/wizard
/datum/team/wizard
name = "wizard team"
var/datum/antagonist/wizard/master_wizard
/datum/antagonist/wizard/proc/create_wiz_team()
wiz_team = new(owner)
wiz_team.name = "[owner.current.real_name] team"
wiz_team.master_wizard = src
update_wiz_icons_added(owner.current)
/datum/antagonist/wizard/proc/send_to_lair()
@@ -283,4 +285,46 @@
var/datum/objective/new_objective = new("Protect Wizard Academy from the intruders")
new_objective.owner = owner
owner.objectives += new_objective
objectives += new_objective
objectives += new_objective
//Solo wizard report
/datum/antagonist/wizard/roundend_report()
var/list/parts = list()
parts += printplayer(owner)
var/count = 1
var/wizardwin = 1
for(var/datum/objective/objective in objectives)
if(objective.check_completion())
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'>Success!</span>"
else
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
wizardwin = 0
count++
if(wizardwin)
parts += "<span class='greentext'>The wizard was successful!</span>"
else
parts += "<span class='redtext'>The wizard has failed!</span>"
if(owner.spell_list.len>0)
parts += "<B>[owner.name] used the following spells: </B>"
var/list/spell_names = list()
for(var/obj/effect/proc_holder/spell/S in owner.spell_list)
spell_names += S.name
parts += spell_names.Join(", ")
return parts.Join("<br>")
//Wizard with apprentices report
/datum/team/wizard/roundend_report()
var/list/parts = list()
parts += "<span class='header'>Wizards/witches of [master_wizard.owner.name] team were:</span>"
parts += master_wizard.roundend_report()
parts += " "
parts += "<span class='header'>[master_wizard.owner.name] apprentices were:</span>"
parts += printplayerlist(members - master_wizard.owner)
return "<div class='panel redborder'>[parts.Join("<br>")]</div>"
+2 -2
View File
@@ -128,11 +128,11 @@
//Position the effect so the beam is one continous line
var/a
if(abs(Pixel_x)>32)
a = Pixel_x > 0 ? round(Pixel_x/32) : Ceiling(Pixel_x/32)
a = Pixel_x > 0 ? round(Pixel_x/32) : CEILING(Pixel_x/32, 1)
X.x += a
Pixel_x %= 32
if(abs(Pixel_y)>32)
a = Pixel_y > 0 ? round(Pixel_y/32) : Ceiling(Pixel_y/32)
a = Pixel_y > 0 ? round(Pixel_y/32) : CEILING(Pixel_y/32, 1)
X.y += a
Pixel_y %= 32
@@ -0,0 +1,157 @@
/datum/brain_trauma/special/imaginary_friend
name = "Imaginary Friend"
desc = "Patient can see and hear an imaginary person."
scan_desc = "partial schizophrenia"
gain_text = "<span class='notice'>You feel in good company, for some reason.</span>"
lose_text = "<span class='warning'>You feel lonely again.</span>"
var/mob/camera/imaginary_friend/friend
var/friend_initialized = FALSE
/datum/brain_trauma/special/imaginary_friend/on_gain()
..()
make_friend()
get_ghost()
/datum/brain_trauma/special/imaginary_friend/on_life()
if(get_dist(owner, friend) > 9)
friend.yank()
if(!friend)
qdel(src)
return
if(!friend.client && friend_initialized)
addtimer(CALLBACK(src, .proc/reroll_friend), 600)
/datum/brain_trauma/special/imaginary_friend/on_lose()
..()
QDEL_NULL(friend)
//If the friend goes afk, make a brand new friend. Plenty of fish in the sea of imagination.
/datum/brain_trauma/special/imaginary_friend/proc/reroll_friend()
if(friend.client) //reconnected
return
friend_initialized = FALSE
QDEL_NULL(friend)
make_friend()
get_ghost()
/datum/brain_trauma/special/imaginary_friend/proc/make_friend()
friend = new(get_turf(src), src)
/datum/brain_trauma/special/imaginary_friend/proc/get_ghost()
set waitfor = FALSE
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s imaginary friend?", ROLE_PAI, null, null, 75, friend)
if(LAZYLEN(candidates))
var/client/C = pick(candidates)
friend.key = C.key
friend_initialized = TRUE
else
qdel(src)
/mob/camera/imaginary_friend
name = "imaginary friend"
real_name = "imaginary friend"
move_on_shuttle = TRUE
desc = "A wonderful yet fake friend."
see_in_dark = 0
lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE
sight = NONE
see_invisible = SEE_INVISIBLE_LIVING
var/icon/human_image
var/image/current_image
var/mob/living/carbon/owner
var/datum/brain_trauma/special/imaginary_friend/trauma
/mob/camera/imaginary_friend/Login()
..()
to_chat(src, "<span class='notice'><b>You are the imaginary friend of [owner]!</b></span>")
to_chat(src, "<span class='notice'>You are absolutely loyal to your friend, no matter what.</span>")
to_chat(src, "<span class='notice'>You cannot directly influence the world around you, but you can see what [owner] cannot.</span>")
/mob/camera/imaginary_friend/Initialize(mapload, _trauma)
. = ..()
var/gender = pick(MALE, FEMALE)
real_name = random_unique_name(gender)
name = real_name
trauma = _trauma
owner = trauma.owner
human_image = get_flat_human_icon(null, pick(SSjob.occupations))
Show()
/mob/camera/imaginary_friend/proc/Show()
if(!client) //nobody home
return
//Remove old image from owner and friend
if(owner.client)
owner.client.images.Remove(current_image)
client.images.Remove(current_image)
//Generate image from the static icon and the current dir
current_image = image(human_image, src, , MOB_LAYER, dir=src.dir)
current_image.override = TRUE
current_image.name = name
//Add new image to owner and friend
if(owner.client)
owner.client.images |= current_image
client.images |= current_image
/mob/camera/imaginary_friend/Destroy()
if(owner.client)
owner.client.images.Remove(human_image)
if(client)
client.images.Remove(human_image)
return ..()
/mob/camera/imaginary_friend/proc/yank()
if(!client) //don't bother if the friend is braindead
return
forceMove(get_turf(owner))
Show()
/mob/camera/imaginary_friend/say(message)
if (!message)
return
if (src.client)
if(client.prefs.muted & MUTE_IC)
to_chat(src, "You cannot send IC messages (muted).")
return
if (src.client.handle_spam_prevention(message,MUTE_IC))
return
friend_talk(message)
/mob/camera/imaginary_friend/proc/friend_talk(message)
message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
if(!message)
return
log_talk(src,"[key_name(src)] : [message]",LOGSAY)
var/rendered = "<span class='game say'><span class='name'>[name]</span> <span class='message'>[say_quote(message)]</span></span>"
var/dead_rendered = "<span class='game say'><span class='name'>[name] (Imaginary friend of [owner])</span> <span class='message'>[say_quote(message)]</span></span>"
to_chat(owner, "[rendered]")
to_chat(src, "[rendered]")
for(var/mob/M in GLOB.dead_mob_list)
var/link = FOLLOW_LINK(M, owner)
to_chat(M, "[link] [dead_rendered]")
/mob/camera/imaginary_friend/emote(act,m_type=1,message = null)
return
/mob/camera/imaginary_friend/forceMove(atom/destination)
dir = get_dir(get_turf(src), destination)
loc = destination
if(get_dist(src, owner) > 9)
yank()
return
Show()
/mob/camera/imaginary_friend/movement_delay()
return 2
+81 -2
View File
@@ -42,7 +42,7 @@
lose_text = "<span class='notice'>You feel smart again.</span>"
/datum/brain_trauma/mild/dumbness/on_gain()
owner.disabilities |= DUMB
owner.add_disability(DUMB, TRAUMA_DISABILITY)
..()
/datum/brain_trauma/mild/dumbness/on_life()
@@ -54,7 +54,7 @@
..()
/datum/brain_trauma/mild/dumbness/on_lose()
owner.disabilities &= ~DUMB
owner.remove_disability(DUMB, TRAUMA_DISABILITY)
owner.derpspeech = 0
..()
@@ -107,6 +107,26 @@
..()
/datum/brain_trauma/mild/healthy
name = "Anosognosia"
desc = "Patient always feels healthy, regardless of their condition."
scan_desc = "self-awareness deficit"
gain_text = "<span class='notice'>You feel great!</span>"
lose_text = "<span class='warning'>You no longer feel perfectly healthy.</span>"
/datum/brain_trauma/mild/healthy/on_gain()
owner.set_screwyhud(SCREWYHUD_HEALTHY)
..()
/datum/brain_trauma/mild/healthy/on_life()
owner.set_screwyhud(SCREWYHUD_HEALTHY) //just in case of hallucinations
owner.adjustStaminaLoss(-5) //no pain, no fatigue
..()
/datum/brain_trauma/mild/healthy/on_lose()
owner.set_screwyhud(SCREWYHUD_NONE)
..()
/datum/brain_trauma/mild/muscle_weakness
name = "Muscle Weakness"
desc = "Patient experiences occasional bouts of muscle weakness."
@@ -133,3 +153,62 @@
to_chat(owner, "<span class='warning'>You feel a sudden weakness in your muscles!</span>")
owner.adjustStaminaLoss(50)
..()
/datum/brain_trauma/mild/muscle_spasms
name = "Muscle Spasms"
desc = "Patient has occasional muscle spasms, causing them to move unintentionally."
scan_desc = "nervous fits"
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_spasms/on_life()
if(prob(7))
switch(rand(1,5))
if(1)
if(owner.canmove && !isspaceturf(owner.loc))
to_chat(owner, "<span class='warning'>Your leg spasms!</span>")
step(owner, pick(GLOB.cardinals))
if(2)
if(owner.incapacitated())
return
var/obj/item/I = owner.get_active_held_item()
if(I)
to_chat(owner, "<span class='warning'>Your fingers spasm!</span>")
log_attack("[key_name(owner)] used [I] due to a Muscle Spasm.")
I.attack_self(owner)
if(3)
var/prev_intent = owner.a_intent
owner.a_intent = INTENT_HARM
var/range = 1
if(istype(owner.get_active_held_item(), /obj/item/gun)) //get targets to shoot at
range = 7
var/list/mob/living/targets = list()
for(var/mob/M in oview(owner, range))
if(isliving(M))
targets += M
if(LAZYLEN(targets))
to_chat(owner, "<span class='warning'>Your arm spasms!</span>")
log_attack("[key_name(owner)] attacked someone due to a Muscle Spasm.") //the following attack will log itself
owner.ClickOn(pick(targets))
owner.a_intent = prev_intent
if(4)
var/prev_intent = owner.a_intent
owner.a_intent = INTENT_HARM
to_chat(owner, "<span class='warning'>Your arm spasms!</span>")
log_attack("[key_name(owner)] attacked himself to a Muscle Spasm.")
owner.ClickOn(owner)
owner.a_intent = prev_intent
if(5)
if(owner.incapacitated())
return
var/obj/item/I = owner.get_active_held_item()
var/list/turf/targets = list()
for(var/turf/T in oview(owner, 3))
targets += T
if(LAZYLEN(targets) && I)
to_chat(owner, "<span class='warning'>Your arm spasms!</span>")
log_attack("[key_name(owner)] threw [I] due to a Muscle Spasm.")
owner.throw_item(pick(targets))
..()
+61 -20
View File
@@ -7,22 +7,39 @@
/datum/brain_trauma/severe/mute
name = "Mutism"
desc = "Patient is completely unable to speak."
scan_desc = "extensive damage to the brain's language center"
scan_desc = "extensive damage to the brain's speech 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()
owner.add_disability(MUTE, TRAUMA_DISABILITY)
..()
/datum/brain_trauma/severe/mute/on_lose()
owner.disabilities &= ~MUTE
owner.remove_disability(MUTE, TRAUMA_DISABILITY)
..()
/datum/brain_trauma/severe/aphasia
name = "Aphasia"
desc = "Patient is unable to speak or understand any language."
scan_desc = "extensive damage to the brain's language center"
gain_text = "<span class='warning'>You have trouble forming words in your head...</span>"
lose_text = "<span class='notice'>You suddenly remember how languages work.</span>"
var/datum/language_holder/prev_language
var/datum/language_holder/mob_language
/datum/brain_trauma/severe/aphasia/on_gain()
mob_language = owner.get_language_holder()
prev_language = mob_language.copy()
mob_language.remove_all_languages()
mob_language.grant_language(/datum/language/aphasia)
..()
/datum/brain_trauma/severe/aphasia/on_lose()
mob_language.remove_language(/datum/language/aphasia)
mob_language.copy_known_languages_from(prev_language) //this will also preserve languages learned during the trauma
QDEL_NULL(prev_language)
mob_language = null
..()
/datum/brain_trauma/severe/blindness
@@ -33,17 +50,11 @@
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()
owner.become_blind(TRAUMA_DISABILITY)
..()
/datum/brain_trauma/severe/blindness/on_lose()
owner.cure_blind()
owner.cure_blind(TRAUMA_DISABILITY)
..()
/datum/brain_trauma/severe/paralysis
@@ -109,7 +120,7 @@
stress -= 4
/datum/brain_trauma/severe/monophobia/proc/check_alone()
if(owner.disabilities & BLIND)
if(owner.has_disability(BLIND))
return TRUE
for(var/mob/M in oview(owner, 7))
if(!isliving(M)) //ghosts ain't people
@@ -171,9 +182,39 @@
lose_text = "<span class='notice'>You feel in control of your hands again.</span>"
/datum/brain_trauma/severe/discoordination/on_gain()
owner.disabilities |= MONKEYLIKE
owner.add_disability(MONKEYLIKE, TRAUMA_DISABILITY)
..()
/datum/brain_trauma/severe/discoordination/on_lose()
owner.disabilities &= ~MONKEYLIKE
owner.remove_disability(MONKEYLIKE, TRAUMA_DISABILITY)
..()
/datum/brain_trauma/severe/pacifism
name = "Traumatic Non-Violence"
desc = "Patient is extremely unwilling to harm others in violent ways."
scan_desc = "pacific syndrome"
gain_text = "<span class='notice'>You feel oddly peaceful.</span>"
lose_text = "<span class='notice'>You no longer feel compelled to not harm.</span>"
/datum/brain_trauma/severe/pacifism/on_gain()
owner.add_disability(PACIFISM, TRAUMA_DISABILITY)
..()
/datum/brain_trauma/severe/pacifism/on_lose()
owner.remove_disability(PACIFISM, TRAUMA_DISABILITY)
..()
/datum/brain_trauma/severe/pacifism
name = "Traumatic Non-Violence"
desc = "Patient is extremely unwilling to harm others in violent ways."
scan_desc = "pacific syndrome"
gain_text = "<span class='notice'>You feel oddly peaceful.</span>"
lose_text = "<span class='notice'>You no longer feel compelled to not harm.</span>"
/datum/brain_trauma/severe/pacifism/on_gain()
owner.disabilities |= PACIFISM
..()
/datum/brain_trauma/severe/pacifism/on_lose()
owner.disabilities &= ~PACIFISM
..()
+25 -15
View File
@@ -9,25 +9,35 @@
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
if(prob(4))
if(prob(33) && (owner.IsStun() || owner.IsKnockdown() || owner.IsUnconscious()))
speak("unstun", TRUE)
else if(prob(60) && owner.health <= HEALTH_THRESHOLD_CRIT)
speak("heal", TRUE)
else if(prob(30) && owner.a_intent == INTENT_HARM)
speak("aggressive")
else
speak("neutral", prob(25))
/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/godwoken/proc/speak(type, include_owner = FALSE)
var/message
switch(type)
if("unstun")
message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_unstun")
if("heal")
message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_heal")
if("neutral")
message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_neutral")
if("aggressive")
message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_aggressive")
else
message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_neutral")
playsound(get_turf(owner), 'sound/magic/clockwork/invoke_general.ogg', 200, 1, 5)
voice_of_god(message, owner, list("colossus","yell"), 2.5, include_owner, FALSE)
/datum/brain_trauma/special/bluespace_prophet
name = "Bluespace Prophecy"
@@ -23,7 +23,7 @@
/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)
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s split personality?", ROLE_PAI, null, null, 75, stranger_backseat)
if(LAZYLEN(candidates))
var/client/C = pick(candidates)
stranger_backseat.key = C.key
@@ -136,6 +136,7 @@
/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>")
to_chat(src, "<span class='warning'><b>Do not commit suicide or put the body in a deadly position. Behave like you care about it as much as the owner.</b></span>")
/mob/living/split_personality/say(message)
to_chat(src, "<span class='warning'>You cannot speak, your other self is controlling your body!</span>")
+20
View File
@@ -48,6 +48,7 @@
var/datum/object = GLOBAL_PROC
var/delegate
var/list/arguments
var/datum/weakref/user
/datum/callback/New(thingtocall, proctocall, ...)
if (thingtocall)
@@ -55,6 +56,8 @@
delegate = proctocall
if (length(args) > 2)
arguments = args.Copy(3)
if(usr)
user = WEAKREF(usr)
/world/proc/ImmediateInvokeAsync(thingtocall, proctocall, ...)
set waitfor = FALSE
@@ -70,8 +73,16 @@
call(thingtocall, proctocall)(arglist(calling_arguments))
/datum/callback/proc/Invoke(...)
if(!usr)
var/datum/weakref/W = user
if(W)
var/mob/M = W.resolve()
if(M)
return world.PushUsr(M, src)
if (!object)
return
var/list/calling_arguments = arguments
if (length(args))
if (length(arguments))
@@ -87,8 +98,17 @@
//copy and pasted because fuck proc overhead
/datum/callback/proc/InvokeAsync(...)
set waitfor = FALSE
if(!usr)
var/datum/weakref/W = user
if(W)
var/mob/M = W.resolve()
if(M)
return world.PushUsr(M, src)
if (!object)
return
var/list/calling_arguments = arguments
if (length(args))
if (length(arguments))
+3 -2
View File
@@ -40,6 +40,7 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
* `COMPONENT_DUPE_HIGHLANDER` (default): Old component will be deleted, new component will first have `/datum/component/proc/InheritComponent(datum/component/old, FALSE)` on it
* `COMPONENT_DUPE_ALLOWED`: The components will be treated as separate, `GetComponent()` will return the first added
* `COMPONENT_DUPE_UNIQUE`: New component will be deleted, old component will first have `/datum/component/proc/InheritComponent(datum/component/new, TRUE)` on it
* `COMPONENT_DUPE_UNIQUE_PASSARGS`: New component will never exist and instead its initialization arguments will be passed on to the old component.
1. `/datum/component/var/dupe_type` (protected, type)
* Definition of a duplicate component type
* `null` means exact match on `type` (default)
@@ -66,6 +67,7 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
* All components a datum owns are deleted with the datum
* Returns the component that was created. Or the old component in a dupe situation where `COMPONENT_DUPE_UNIQUE` was set
* If this tries to add an component to an incompatible type, the component will be deleted and the result will be `null`. This is very unperformant, try not to do it
* Properly handles duplicate situations based on the `dupe_mode` var
1. `/datum/proc/LoadComponent(component_type(type), ...) -> datum/component` (public, final)
* Equivalent to calling `GetComponent(component_type)` where, if the result would be `null`, returns `AddComponent(component_type, ...)` instead
1. `/datum/proc/ComponentActivated(datum/component/C)` (abstract, async)
@@ -104,9 +106,8 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
* Allows the component to react to ownership transfers
1. `/datum/component/proc/_RemoveFromParent()` (private, final)
* Clears `parent` and removes the component from it's component list
1. `/datum/component/proc/_CheckDupesAndJoinParent` (private, final)
1. `/datum/component/proc/_JoinParent` (private, final)
* Tries to add the component to it's `parent`s `datum_components` list
* Properly handles duplicate situations based on the `dupe_mode` var
1. `/datum/component/proc/RegisterSignal(signal(string/list of strings), proc_ref(type), override(boolean))` (protected, final) (Consider removing for performance gainz)
* If signal is a list it will be as if RegisterSignal was called for each of the entries with the same following arguments
* Makes a component listen for the specified `signal` on it's `parent` datum.
+56 -44
View File
@@ -6,54 +6,16 @@
var/datum/parent
/datum/component/New(datum/P, ...)
if(type == /datum/component)
qdel(src)
CRASH("[type] instantiated!")
//check for common mishaps
if(!isnum(dupe_mode))
qdel(src)
CRASH("[type]: Invalid dupe_mode!")
var/dt = dupe_type
if(dt && !ispath(dt))
qdel(src)
CRASH("[type]: Invalid dupe_type!")
parent = P
var/list/arguments = args.Copy(2)
if(Initialize(arglist(arguments)) == COMPONENT_INCOMPATIBLE)
qdel(src, TRUE, TRUE)
return
_CheckDupesAndJoinParent(P)
_JoinParent(P)
/datum/component/proc/_CheckDupesAndJoinParent()
/datum/component/proc/_JoinParent()
var/datum/P = parent
var/dm = dupe_mode
var/datum/component/old
if(dm != COMPONENT_DUPE_ALLOWED)
var/dt = dupe_type
if(!dt)
old = P.GetExactComponent(type)
else
old = P.GetComponent(dt)
if(old)
//One or the other has to die
switch(dm)
if(COMPONENT_DUPE_UNIQUE)
old.InheritComponent(src, TRUE)
qdel(src, TRUE, TRUE)
return
if(COMPONENT_DUPE_HIGHLANDER)
InheritComponent(old, FALSE)
qdel(old, FALSE, TRUE)
//provided we didn't eat someone
if(!old)
//let the others know
P.SendSignal(COMSIG_COMPONENT_ADDED, src)
//lazy init the parent's dc list
var/list/dc = P.datum_components
if(!dc)
@@ -212,10 +174,59 @@
return list(.)
/datum/proc/AddComponent(new_type, ...)
var/nt = new_type
var/datum/component/nt = new_type
var/dm = initial(nt.dupe_mode)
var/dt = initial(nt.dupe_type)
var/datum/component/old_comp
var/datum/component/new_comp
if(ispath(nt))
if(nt == /datum/component)
CRASH("[nt] attempted instantiation!")
if(!isnum(dm))
CRASH("[nt]: Invalid dupe_mode ([dm])!")
if(dt && !ispath(dt))
CRASH("[nt]: Invalid dupe_type ([dt])!")
else
new_comp = nt
args[1] = src
var/datum/component/C = new nt(arglist(args))
return QDELING(C) ? GetExactComponent(new_type) : C
if(dm != COMPONENT_DUPE_ALLOWED)
if(!dt)
old_comp = GetExactComponent(nt)
else
old_comp = GetComponent(dt)
if(old_comp)
switch(dm)
if(COMPONENT_DUPE_UNIQUE)
if(!new_comp)
new_comp = new nt(arglist(args))
if(!QDELETED(new_comp))
old_comp.InheritComponent(new_comp, TRUE)
qdel(new_comp)
if(COMPONENT_DUPE_HIGHLANDER)
if(!new_comp)
new_comp = new nt(arglist(args))
if(!QDELETED(new_comp))
new_comp.InheritComponent(old_comp, FALSE)
qdel(old_comp)
if(COMPONENT_DUPE_UNIQUE_PASSARGS)
if(!new_comp)
var/list/arguments = args.Copy(2)
old_comp.InheritComponent(null, TRUE, arguments)
else
old_comp.InheritComponent(new_comp, TRUE)
else if(!new_comp)
new_comp = new nt(arglist(args)) // There's a valid dupe mode but there's no old component, act like normal
else if(!new_comp)
new_comp = new nt(arglist(args)) // Dupes are allowed, act like normal
if(!old_comp && !QDELETED(new_comp)) // Nothing related to duplicate components happened and the new component is healthy
SendSignal(COMSIG_COMPONENT_ADDED, new_comp)
return new_comp
return old_comp
/datum/proc/LoadComponent(component_type, ...)
. = GetComponent(component_type)
@@ -235,7 +246,8 @@
C._RemoveFromParent()
helicopter.SendSignal(COMSIG_COMPONENT_REMOVING, C)
C.parent = src
C._CheckDupesAndJoinParent()
if(C == AddComponent(C))
C._JoinParent()
/datum/proc/TransferComponents(datum/target)
var/list/dc = datum_components
+1 -1
View File
@@ -6,7 +6,7 @@
var/datum/callback/callback
/datum/component/archaeology/Initialize(_prob2drop, list/_archdrops = list(), datum/callback/_callback)
prob2drop = Clamp(_prob2drop, 0, 100)
prob2drop = CLAMP(_prob2drop, 0, 100)
archdrops = _archdrops
callback = _callback
RegisterSignal(COMSIG_PARENT_ATTACKBY,.proc/Dig)
+40
View File
@@ -0,0 +1,40 @@
/datum/component/cleaning
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
/datum/component/cleaning/Initialize()
if(!ismovableatom(parent))
. = COMPONENT_INCOMPATIBLE
CRASH("[type] added to a [parent.type]")
RegisterSignal(list(COMSIG_MOVABLE_MOVED), .proc/Clean)
/datum/component/cleaning/proc/Clean()
var/atom/movable/AM = parent
var/turf/tile = AM.loc
if(!isturf(tile))
return
tile.clean_blood()
for(var/A in tile)
if(is_cleanable(A))
qdel(A)
else if(istype(A, /obj/item))
var/obj/item/cleaned_item = A
cleaned_item.clean_blood()
else if(ishuman(A))
var/mob/living/carbon/human/cleaned_human = A
if(cleaned_human.lying)
if(cleaned_human.head)
cleaned_human.head.clean_blood()
cleaned_human.update_inv_head()
if(cleaned_human.wear_suit)
cleaned_human.wear_suit.clean_blood()
cleaned_human.update_inv_wear_suit()
else if(cleaned_human.w_uniform)
cleaned_human.w_uniform.clean_blood()
cleaned_human.update_inv_w_uniform()
if(cleaned_human.shoes)
cleaned_human.shoes.clean_blood()
cleaned_human.update_inv_shoes()
cleaned_human.clean_blood()
cleaned_human.wash_cream()
to_chat(cleaned_human, "<span class='danger'>[AM] cleans your face!</span>")
+2 -3
View File
@@ -48,8 +48,7 @@
if(old_dir == new_dir)
return
remove()
var/rotation = SimplifyDegrees(dir2angle(new_dir)-dir2angle(old_dir))
pic.dir = turn(pic.dir, rotation)
pic.dir = turn(pic.dir, dir2angle(old_dir) - dir2angle(new_dir))
apply()
/datum/component/decal/proc/clean_react(strength)
@@ -57,4 +56,4 @@
qdel(src)
/datum/component/decal/proc/examine(mob/user)
to_chat(user, description)
to_chat(user, description)
+81
View File
@@ -0,0 +1,81 @@
/datum/component/jousting
var/current_direction = NONE
var/max_tile_charge = 5
var/min_tile_charge = 2 //tiles before this code gets into effect.
var/current_tile_charge = 0
var/movement_reset_tolerance = 2 //deciseconds
var/unmounted_damage_boost_per_tile = 0
var/unmounted_knockdown_chance_per_tile = 0
var/unmounted_knockdown_time = 0
var/mounted_damage_boost_per_tile = 2
var/mounted_knockdown_chance_per_tile = 20
var/mounted_knockdown_time = 20
var/requires_mob_riding = TRUE //whether this only works if the attacker is riding a mob, rather than anything they can buckle to.
var/requires_mount = TRUE //kinda defeats the point of jousting if you're not mounted but whatever.
var/mob/current_holder
var/datum/component/redirect/listener
var/current_timerid
/datum/component/jousting/Initialize()
if(!isitem(parent))
. = COMPONENT_INCOMPATIBLE
stack_trace("Warning: Jousting component incorrectly applied to invalid parent type [parent.type]")
RegisterSignal(COMSIG_ITEM_EQUIPPED, .proc/on_equip)
RegisterSignal(COMSIG_ITEM_DROPPED, .proc/on_drop)
RegisterSignal(COMSIG_ITEM_ATTACK, .proc/on_attack)
/datum/component/jousting/Destroy()
QDEL_NULL(listener)
return ..()
/datum/component/jousting/proc/on_equip(mob/user, slot)
QDEL_NULL(listener)
current_holder = user
listener = new(user, COMSIG_MOVABLE_MOVED, CALLBACK(src, .proc/mob_move))
/datum/component/jousting/proc/on_drop(mob/user)
QDEL_NULL(listener)
current_holder = null
current_direction = NONE
current_tile_charge = 0
/datum/component/jousting/proc/on_attack(mob/living/target, mob/user)
if(user != current_holder)
return
var/current = current_tile_charge
var/obj/item/I = parent
var/target_buckled = target.buckled ? TRUE : FALSE //we don't need the reference of what they're buckled to, just whether they are.
if((requires_mount && ((requires_mob_riding && !ismob(user.buckled)) || (!user.buckled))) || !current_direction || (current_tile_charge < min_tile_charge))
return
var/turf/target_turf = get_step(user, current_direction)
if(target in range(1, target_turf))
var/knockdown_chance = (target_buckled? mounted_knockdown_chance_per_tile : unmounted_knockdown_chance_per_tile) * current
var/knockdown_time = (target_buckled? mounted_knockdown_time : unmounted_knockdown_time)
var/damage = (target_buckled? mounted_damage_boost_per_tile : unmounted_damage_boost_per_tile) * current
var/sharp = I.is_sharp()
var/msg
if(damage)
msg += "[user] [sharp? "impales" : "slams into"] [target] [sharp? "on" : "with"] their [parent]"
target.apply_damage(damage, BRUTE, user.zone_selected, 0)
if(prob(knockdown_chance))
msg += " and knocks [target] [target_buckled? "off of [target.buckled]" : "down"]"
if(target_buckled)
target.buckled.unbuckle_mob(target)
target.Knockdown(knockdown_time)
if(length(msg))
user.visible_message("<span class='danger'>[msg]!</span>")
/datum/component/jousting/proc/mob_move(newloc, dir)
if(!current_holder || (requires_mount && ((requires_mob_riding && !ismob(current_holder.buckled)) || (!current_holder.buckled))))
return
if(dir != current_direction)
current_tile_charge = 0
current_direction = dir
if(current_tile_charge < max_tile_charge)
current_tile_charge++
if(current_timerid)
deltimer(current_timerid)
current_timerid = addtimer(CALLBACK(src, .proc/reset_charge), movement_reset_tolerance, TIMER_STOPPABLE)
/datum/component/jousting/proc/reset_charge()
current_tile_charge = 0
+53
View File
@@ -0,0 +1,53 @@
//Items with these will have a chance to get knocked off when disarming
/datum/component/knockoff
var/knockoff_chance = 100 //Chance to knockoff
var/list/target_zones //Aiming for these zones will cause the knockoff, null means all zones allowed
var/list/slots_knockoffable //Can be only knocked off from these slots, null means all slots allowed
var/datum/component/redirect/disarm_redirect
/datum/component/knockoff/Initialize(knockoff_chance,zone_override,slots_knockoffable)
if(!isitem(parent))
. = COMPONENT_INCOMPATIBLE
CRASH("Knockoff component misuse")
RegisterSignal(COMSIG_ITEM_EQUIPPED,.proc/OnEquipped)
RegisterSignal(COMSIG_ITEM_DROPPED,.proc/OnDropped)
src.knockoff_chance = knockoff_chance
if(zone_override)
target_zones = zone_override
if(slots_knockoffable)
src.slots_knockoffable = slots_knockoffable
/datum/component/knockoff/proc/Knockoff(mob/living/attacker,zone)
var/obj/item/I = parent
var/mob/living/carbon/human/wearer = I.loc
if(!istype(wearer))
return
if(target_zones && !(zone in target_zones))
return
if(!prob(knockoff_chance))
return
if(!wearer.dropItemToGround(I))
return
wearer.visible_message("<span class='warning'>[attacker] knocks off [wearer]'s [I.name]!</span>","<span class='userdanger'>[attacker] knocks off your [I.name]!</span>")
/datum/component/knockoff/proc/OnEquipped(mob/living/carbon/human/H,slot)
if(!istype(H))
return
if(slots_knockoffable && !(slot in slots_knockoffable))
if(disarm_redirect)
QDEL_NULL(disarm_redirect)
return
if(!disarm_redirect)
disarm_redirect = H.AddComponent(/datum/component/redirect,list(COMSIG_HUMAN_DISARM_HIT),CALLBACK(src,.proc/Knockoff))
/datum/component/knockoff/proc/OnDropped(mob/living/M)
if(disarm_redirect)
QDEL_NULL(disarm_redirect)
/datum/component/knockoff/Destroy()
QDEL_NULL(disarm_redirect)
. = ..()
+7 -4
View File
@@ -4,7 +4,7 @@
#define RAD_AMOUNT_EXTREME 1000
/datum/component/radioactive
dupe_mode = COMPONENT_DUPE_UNIQUE
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
var/source
@@ -47,13 +47,16 @@
if(strength <= RAD_BACKGROUND_RADIATION)
return PROCESS_KILL
/datum/component/radioactive/InheritComponent(datum/component/C, i_am_original)
/datum/component/radioactive/InheritComponent(datum/component/C, i_am_original, list/arguments)
if(!i_am_original)
return
if(!hl3_release_date) // Permanently radioactive things don't get to grow stronger
return
var/datum/component/radioactive/other = C
strength = max(strength, other.strength)
if(C)
var/datum/component/radioactive/other = C
strength = max(strength, other.strength)
else
strength = max(strength, arguments[1])
/datum/component/radioactive/proc/rad_examine(mob/user, atom/thing)
var/atom/master = parent
+6 -3
View File
@@ -1,5 +1,5 @@
/datum/component/thermite
dupe_mode = COMPONENT_DUPE_UNIQUE
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
var/amount
var/overlay
@@ -46,10 +46,13 @@
master.cut_overlay(overlay)
return ..()
/datum/component/thermite/InheritComponent(datum/component/thermite/newC, i_am_original)
/datum/component/thermite/InheritComponent(datum/component/thermite/newC, i_am_original, list/arguments)
if(!i_am_original)
return
amount += newC.amount
if(newC)
amount += newC.amount
else
amount += arguments[1]
/datum/component/thermite/proc/thermite_melt(mob/user)
var/turf/master = parent
+1 -1
View File
@@ -43,7 +43,7 @@
addtimer(CALLBACK(src, .proc/charge), charge_rate)
/datum/action/innate/dash/proc/charge()
current_charges = Clamp(current_charges + 1, 0, max_charges)
current_charges = CLAMP(current_charges + 1, 0, max_charges)
holder.update_action_buttons_icon()
if(recharge_sound)
playsound(dashing_item, recharge_sound, 50, 1)
+4 -4
View File
@@ -185,10 +185,10 @@
if(properties["stealth"] >= 2)
visibility_flags = HIDDEN_SCANNER
SetSpread(Clamp(2 ** (properties["transmittable"] - symptoms.len), VIRUS_SPREAD_BLOOD, VIRUS_SPREAD_AIRBORNE))
SetSpread(CLAMP(2 ** (properties["transmittable"] - symptoms.len), VIRUS_SPREAD_BLOOD, VIRUS_SPREAD_AIRBORNE))
permeability_mod = max(Ceiling(0.4 * properties["transmittable"]), 1)
cure_chance = 15 - Clamp(properties["resistance"], -5, 5) // can be between 10 and 20
permeability_mod = max(CEILING(0.4 * properties["transmittable"], 1), 1)
cure_chance = 15 - CLAMP(properties["resistance"], -5, 5) // can be between 10 and 20
stage_prob = max(properties["stage_rate"], 2)
SetSeverity(properties["severity"])
GenerateCure(properties)
@@ -243,7 +243,7 @@
// Will generate a random cure, the less resistance the symptoms have, the harder the cure.
/datum/disease/advance/proc/GenerateCure()
if(properties && properties.len)
var/res = Clamp(properties["resistance"] - (symptoms.len / 2), 1, advance_cures.len)
var/res = CLAMP(properties["resistance"] - (symptoms.len / 2), 1, advance_cures.len)
cures = list(advance_cures[res])
// Get the cure name from the cure_id
+77 -75
View File
@@ -1,10 +1,10 @@
/datum/symptom/heal
name = "Basic Healing (does nothing)" //warning for adminspawn viruses
desc = "You should not be seeing this."
stealth = 1
resistance = -4
stage_speed = -4
transmittable = -4
stealth = 0
resistance = 0
stage_speed = 0
transmittable = 0
level = 0 //not obtainable
base_message_chance = 20 //here used for the overlays
symptom_delay_min = 1
@@ -22,7 +22,6 @@
/datum/symptom/heal/Activate(datum/disease/advance/A)
if(!..())
return
//100% chance to activate for slow but consistent healing
var/mob/living/M = A.affected_mob
switch(A.stage)
if(4, 5)
@@ -45,20 +44,20 @@
return TRUE
/datum/symptom/heal/toxin
/datum/symptom/heal/starlight
name = "Starlight Condensation"
desc = "The virus reacts to direct starlight, producing regenerative chemicals that can cure toxin damage."
stealth = 1
resistance = -3
stage_speed = -3
transmittable = -3
desc = "The virus reacts to direct starlight, producing regenerative chemicals. Works best against toxin-based damage."
stealth = -1
resistance = -2
stage_speed = 0
transmittable = 1
level = 6
passive_message = "<span class='notice'>You miss the feeling of starlight on your skin.</span>"
var/nearspace_penalty = 0.3
threshold_desc = "<b>Stage Speed 6:</b> Increases healing speed.<br>\
<b>Transmission 6:</b> Removes penalty for only being close to space."
/datum/symptom/heal/toxin/Start(datum/disease/advance/A)
/datum/symptom/heal/starlight/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["transmission"] >= 6)
@@ -66,7 +65,7 @@
if(A.properties["stage_rate"] >= 6)
power = 2
/datum/symptom/heal/toxin/CanHeal(datum/disease/advance/A)
/datum/symptom/heal/starlight/CanHeal(datum/disease/advance/A)
var/mob/living/M = A.affected_mob
if(istype(get_turf(M), /turf/open/space))
return power
@@ -75,15 +74,25 @@
if(istype(T, /turf/open/space))
return power * nearspace_penalty
/datum/symptom/heal/toxin/Heal(mob/living/M, datum/disease/advance/A, actual_power)
/datum/symptom/heal/starlight/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
var/heal_amt = actual_power
if(M.getToxLoss() && prob(5))
to_chat(M, "<span class='notice'>Your skin tingles as the starlight purges toxins from your bloodstream.</span>")
M.adjustToxLoss(-heal_amt)
to_chat(M, "<span class='notice'>Your skin tingles as the starlight seems to heal you.</span>")
M.adjustToxLoss(-(4 * heal_amt)) //most effective on toxins
var/list/parts = M.get_damaged_bodyparts(1,1)
if(!parts.len)
return
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len))
M.update_damage_overlays()
return 1
/datum/symptom/heal/toxin/passive_message_condition(mob/living/M)
if(M.getToxLoss())
/datum/symptom/heal/starlight/passive_message_condition(mob/living/M)
if(M.getBruteLoss() || M.getFireLoss() || M.getToxLoss())
return TRUE
return FALSE
@@ -91,7 +100,7 @@
name = "Toxolysis"
stealth = 0
resistance = -2
stage_speed = -2
stage_speed = 2
transmittable = -2
level = 7
var/food_conversion = FALSE
@@ -153,58 +162,50 @@
to_chat(C, "<span class='notice'>You feel an odd gurgle in your stomach, as if it was working much faster than normal.</span>")
return 1
/datum/symptom/heal/brute
name = "Cellular Molding"
desc = "The virus is able to shift cells around when in conditions of high heat, repairing existing physical damage."
stealth = 1
resistance = -3
stage_speed = -3
transmittable = -3
/datum/symptom/heal/darkness
name = "Nocturnal Regeneration"
desc = "The virus is able to mend the host's flesh when in conditions of low light, repairing physical damage. More effective against brute damage."
stealth = 2
resistance = -1
stage_speed = -2
transmittable = -1
level = 6
passive_message = "<span class='notice'>You feel the flesh pulsing under your skin for a moment, but it's too cold to move.</span>"
passive_message = "<span class='notice'>You feel tingling on your skin as light passes over it.</span>"
threshold_desc = "<b>Stage Speed 8:</b> Doubles healing speed."
/datum/symptom/heal/brute/Start(datum/disease/advance/A)
/datum/symptom/heal/darkness/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stage_rate"] >= 8)
power = 2
/datum/symptom/heal/brute/CanHeal(datum/disease/advance/A)
/datum/symptom/heal/darkness/CanHeal(datum/disease/advance/A)
var/mob/living/M = A.affected_mob
switch(M.bodytemperature)
if(0 to 340)
return FALSE
if(340 to BODYTEMP_HEAT_DAMAGE_LIMIT)
. = 0.3 * power
if(BODYTEMP_HEAT_DAMAGE_LIMIT to 400)
. = 0.75 * power
if(400 to 460)
. = power
else
. = 1.5 * power
var/light_amount = 0
if(isturf(M.loc)) //else, there's considered to be no light
var/turf/T = M.loc
light_amount = min(1,T.get_lumcount()) - 0.5
if(light_amount < SHADOW_SPECIES_LIGHT_THRESHOLD)
return power
if(M.on_fire)
. *= 2
/datum/symptom/heal/brute/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
/datum/symptom/heal/darkness/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
var/heal_amt = 2 * actual_power
var/list/parts = M.get_damaged_bodyparts(1,0) //brute only
var/list/parts = M.get_damaged_bodyparts(1,1)
if(!parts.len)
return
if(prob(5))
to_chat(M, "<span class='notice'>You feel your flesh moving beneath your heated skin, mending your wounds.</span>")
to_chat(M, "<span class='notice'>The darkness soothes and mends your wounds.</span>")
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(heal_amt/parts.len, 0))
if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len * 0.5)) //more effective on brute
M.update_damage_overlays()
return 1
/datum/symptom/heal/brute/passive_message_condition(mob/living/M)
if(M.getBruteLoss())
/datum/symptom/heal/darkness/passive_message_condition(mob/living/M)
if(M.getBruteLoss() || M.getFireLoss())
return TRUE
return FALSE
@@ -212,8 +213,8 @@
name = "Regenerative Coma"
desc = "The virus causes the host to fall into a death-like coma when severely damaged, then rapidly fixes the damage."
stealth = 0
resistance = 0
stage_speed = -2
resistance = 2
stage_speed = -3
transmittable = -2
level = 8
passive_message = "<span class='notice'>The pain from your wounds makes you feel oddly sleepy...</span>"
@@ -283,20 +284,20 @@
return TRUE
return FALSE
/datum/symptom/heal/burn
/datum/symptom/heal/water
name = "Tissue Hydration"
desc = "The virus uses excess water inside and outside the body to repair burned tisue cells."
stealth = 1
resistance = -3
stage_speed = -3
transmittable = -3
desc = "The virus uses excess water inside and outside the body to repair damaged tissue cells. More effective against burns."
stealth = 0
resistance = -1
stage_speed = 0
transmittable = 1
level = 6
passive_message = "<span class='notice'>Your burned skin feels oddly dry...</span>"
passive_message = "<span class='notice'>Your skin feels oddly dry...</span>"
var/absorption_coeff = 1
threshold_desc = "<b>Resistance 5:</b> Water is consumed at a much slower rate.<br>\
<b>Stage Speed 7:</b> Increases healing speed."
/datum/symptom/heal/burn/Start(datum/disease/advance/A)
/datum/symptom/heal/water/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stage_rate"] >= 7)
@@ -304,7 +305,7 @@
if(A.properties["stealth"] >= 2)
absorption_coeff = 0.25
/datum/symptom/heal/burn/CanHeal(datum/disease/advance/A)
/datum/symptom/heal/water/CanHeal(datum/disease/advance/A)
. = 0
var/mob/living/M = A.affected_mob
if(M.fire_stacks < 0)
@@ -317,33 +318,33 @@
M.reagents.remove_reagent("water", 0.5 * absorption_coeff)
. += power * 0.5
/datum/symptom/heal/burn/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
/datum/symptom/heal/water/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
var/heal_amt = 2 * actual_power
var/list/parts = M.get_damaged_bodyparts(0,1) //burn only
var/list/parts = M.get_damaged_bodyparts(1,1) //more effective on burns
if(!parts.len)
return
if(prob(5))
to_chat(M, "<span class='notice'>You feel yourself absorbing the water around you to soothe your burned skin.</span>")
to_chat(M, "<span class='notice'>You feel yourself absorbing the water around you to soothe your damaged skin.</span>")
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(0, heal_amt/parts.len))
if(L.heal_damage(heal_amt/parts.len * 0.5, heal_amt/parts.len))
M.update_damage_overlays()
return 1
/datum/symptom/heal/burn/passive_message_condition(mob/living/M)
if(M.getFireLoss())
/datum/symptom/heal/water/passive_message_condition(mob/living/M)
if(M.getBruteLoss() || M.getFireLoss())
return TRUE
return FALSE
/datum/symptom/heal/plasma
name = "Plasma Fixation"
desc = "The virus draws plasma from the atmosphere and from inside the body to stabilize body temperature and heal burns."
desc = "The virus draws plasma from the atmosphere and from inside the body to heal and stabilize body temperature."
stealth = 0
resistance = 0
resistance = 3
stage_speed = -2
transmittable = -2
level = 8
@@ -379,8 +380,6 @@
/datum/symptom/heal/plasma/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
var/heal_amt = 4 * actual_power
var/list/parts = M.get_damaged_bodyparts(0,1) //burn only
if(prob(5))
to_chat(M, "<span class='notice'>You feel yourself absorbing plasma inside and around you...</span>")
@@ -393,24 +392,25 @@
if(prob(5))
to_chat(M, "<span class='notice'>You feel warmer.</span>")
M.adjustToxLoss(-heal_amt)
var/list/parts = M.get_damaged_bodyparts(1,1)
if(!parts.len)
return
if(prob(5))
to_chat(M, "<span class='notice'>The pain from your burns fades rapidly.</span>")
to_chat(M, "<span class='notice'>The pain from your wounds fades rapidly.</span>")
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(0, heal_amt/parts.len))
if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len))
M.update_damage_overlays()
return 1
/datum/symptom/heal/radiation
name = "Radioactive Resonance"
desc = "The virus uses radiation to fix damage through dna mutations."
stealth = -1
resistance = -2
stage_speed = 0
stage_speed = 2
transmittable = -3
level = 6
symptom_delay_min = 1
@@ -450,6 +450,8 @@
if(cellular_damage)
M.adjustCloneLoss(-heal_amt * 0.5)
M.adjustToxLoss(-(2 * heal_amt))
var/list/parts = M.get_damaged_bodyparts(1,1)
if(!parts.len)
@@ -58,11 +58,12 @@ Bonus
M.blur_eyes(20)
M.adjust_eye_damage(5)
if(eyes.eye_damage >= 10)
M.become_nearsighted()
M.become_nearsighted(EYE_DAMAGE)
if(prob(eyes.eye_damage - 10 + 1))
if(!remove_eyes)
if(M.become_blind())
if(!M.has_disability(BLIND))
to_chat(M, "<span class='userdanger'>You go blind!</span>")
M.become_blind(EYE_DAMAGE)
else
M.visible_message("<span class='warning'>[M]'s eyes fall off their sockets!</span>", "<span class='userdanger'>Your eyes fall off their sockets!</span>")
eyes.Remove(M)
@@ -111,16 +112,16 @@ Bonus
return
switch(A.stage)
if(4, 5) //basically oculine
if(M.disabilities & BLIND)
if(M.has_disability(BLIND, EYE_DAMAGE))
if(prob(20))
to_chat(M, "<span class='warning'>Your vision slowly returns...</span>")
M.cure_blind()
M.cure_nearsighted()
M.cure_blind(EYE_DAMAGE)
M.cure_nearsighted(EYE_DAMAGE)
M.blur_eyes(35)
else if(M.disabilities & NEARSIGHT)
else if(M.has_disability(NEARSIGHT, EYE_DAMAGE))
to_chat(M, "<span class='warning'>The blackness in your peripheral vision fades.</span>")
M.cure_nearsighted()
M.cure_nearsighted(EYE_DAMAGE)
M.blur_eyes(10)
else if(M.eye_blind || M.eye_blurry)
+5 -15
View File
@@ -1,6 +1,6 @@
/datum/disease/gbs
name = "GBS"
max_stages = 5
max_stages = 4
spread_text = "On contact"
spread_flags = VIRUS_SPREAD_BLOOD | VIRUS_SPREAD_CONTACT_SKIN | VIRUS_SPREAD_CONTACT_FLUIDS
cure_text = "Synaptizine & Sulfur"
@@ -16,25 +16,15 @@
..()
switch(stage)
if(2)
if(prob(45))
affected_mob.adjustToxLoss(5)
affected_mob.updatehealth()
if(prob(1))
affected_mob.emote("sneeze")
if(3)
if(prob(5))
affected_mob.emote("cough")
else if(prob(5))
if(3)
if(prob(5))
affected_mob.emote("gasp")
if(prob(10))
to_chat(affected_mob, "<span class='danger'>You're starting to feel very weak...</span>")
to_chat(affected_mob, "<span class='danger'>Your body hurts all over!</span>")
if(4)
if(prob(10))
affected_mob.emote("cough")
affected_mob.adjustToxLoss(5)
affected_mob.updatehealth()
if(5)
to_chat(affected_mob, "<span class='danger'>Your body feels as if it's trying to rip itself open...</span>")
to_chat(affected_mob, "<span class='userdanger'>Your body feels as if it's trying to rip itself apart!</span>")
if(prob(50))
affected_mob.gib()
else
+7 -4
View File
@@ -88,9 +88,12 @@
stage5 = list("<span class='warning'>You feel like monkeying around.</span>")
/datum/disease/transformation/jungle_fever/do_disease_transformation(mob/living/carbon/affected_mob)
if(!ismonkey(affected_mob))
SSticker.mode.add_monkey(affected_mob.mind)
affected_mob.monkeyize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_KEEPSE)
if(affected_mob.mind && !is_monkey(affected_mob))
add_monkey(affected_mob.mind)
if(ishuman(affected_mob))
var/mob/living/carbon/monkey/M = affected_mob.monkeyize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_KEEPSE)
M.ventcrawler = VENTCRAWLER_ALWAYS
/datum/disease/transformation/jungle_fever/stage_act()
..()
@@ -107,7 +110,7 @@
affected_mob.say(pick("Eeek, ook ook!", "Eee-eeek!", "Eeee!", "Ungh, ungh."))
/datum/disease/transformation/jungle_fever/cure()
SSticker.mode.remove_monkey(affected_mob.mind)
remove_monkey(affected_mob.mind)
..()
+8 -5
View File
@@ -16,8 +16,9 @@
var/emote_type = EMOTE_VISIBLE //Whether the emote is visible or audible
var/restraint_check = FALSE //Checks if the mob is restrained before performing the emote
var/muzzle_ignore = FALSE //Will only work if the emote is EMOTE_AUDIBLE
var/list/mob_type_allowed_typecache //Types that are allowed to use that emote
var/list/mob_type_allowed_typecache = list(/mob) //Types that are allowed to use that emote
var/list/mob_type_blacklist_typecache //Types that are NOT allowed to use that emote
var/list/mob_type_ignore_stat_typecache
var/stat_allowed = CONSCIOUS
var/static/list/emote_list = list()
@@ -26,6 +27,7 @@
emote_list[key_third_person] = src
mob_type_allowed_typecache = typecacheof(mob_type_allowed_typecache)
mob_type_blacklist_typecache = typecacheof(mob_type_blacklist_typecache)
mob_type_ignore_stat_typecache = typecacheof(mob_type_ignore_stat_typecache)
/datum/emote/proc/run_emote(mob/user, params, type_override)
. = TRUE
@@ -37,9 +39,10 @@
msg = replace_pronoun(user, msg)
var/mob/living/L = user
for(var/obj/item/implant/I in L.implants)
I.trigger(key, L)
if(isliving(user))
var/mob/living/L = user
for(var/obj/item/implant/I in L.implants)
I.trigger(key, L)
if(!msg)
return
@@ -97,7 +100,7 @@
return FALSE
if(is_type_in_typecache(user, mob_type_blacklist_typecache))
return FALSE
if(status_check)
if(status_check && !is_type_in_typecache(user, mob_type_ignore_stat_typecache))
if(user.stat > stat_allowed || (user.status_flags & FAKEDEATH))
to_chat(user, "<span class='notice'>You cannot [key] while unconscious.</span>")
return FALSE
+1 -1
View File
@@ -121,7 +121,7 @@ GLOBAL_LIST_EMPTY(explosions)
M.playsound_local(epicenter, null, 100, 1, frequency, falloff = 5, S = explosion_sound)
// You hear a far explosion if you're outside the blast radius. Small bombs shouldn't be heard all over the station.
else if(dist <= far_dist)
var/far_volume = Clamp(far_dist, 30, 50) // Volume is based on explosion size and dist
var/far_volume = CLAMP(far_dist, 30, 50) // Volume is based on explosion size and dist
far_volume += (dist <= far_dist * 0.5 ? 50 : 0) // add 50 volume if the mob is pretty close to the explosion
M.playsound_local(epicenter, null, far_volume, 1, frequency, falloff = 5, S = far_explosion_sound)
EX_PREPROCESS_CHECK_TICK
+2
View File
@@ -45,6 +45,8 @@
set name = "Show Server Revision"
set desc = "Check the current server code revision"
if(GLOB.round_id)
to_chat(src, "<b>Round ID:</b> [GLOB.round_id]")
if(GLOB.revdata.originmastercommit)
to_chat(src, "<b>Server revision compiled on:</b> [GLOB.revdata.date]")
var/prefix = ""
+2 -2
View File
@@ -101,7 +101,7 @@
"<span class='userdanger'>[A] slams your chest! You can't breathe!</span>")
playsound(get_turf(A), 'sound/effects/hit_punch.ogg', 50, 1, -1)
if(D.losebreath <= 10)
D.losebreath = Clamp(D.losebreath + 5, 0, 10)
D.losebreath = CLAMP(D.losebreath + 5, 0, 10)
D.adjustOxyLoss(10)
add_logs(A, D, "quickchoked")
return 1
@@ -112,7 +112,7 @@
playsound(get_turf(A), 'sound/effects/hit_punch.ogg', 50, 1, -1)
D.apply_damage(5, BRUTE)
if(D.silent <= 10)
D.silent = Clamp(D.silent + 10, 0, 10)
D.silent = CLAMP(D.silent + 10, 0, 10)
add_logs(A, D, "neck chopped")
return 1
+1 -3
View File
@@ -44,11 +44,9 @@
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))
A.Stun(rand(10,45))
D.Stun(rand(5,30))
if(5,6)
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
+1 -1
View File
@@ -197,7 +197,7 @@
/obj/item/twohanded/bostaff/attack(mob/target, mob/living/user)
add_fingerprint(user)
if((CLUMSY in user.disabilities) && prob(50))
if((user.has_disability(CLUMSY)) && prob(50))
to_chat(user, "<span class ='warning'>You club yourself over the head with [src].</span>")
user.Knockdown(60)
if(ishuman(user))
+83 -104
View File
@@ -149,7 +149,7 @@
return
LAZYADD(antag_datums, A)
A.create_team(team)
var/datum/objective_team/antag_team = A.get_team()
var/datum/team/antag_team = A.get_team()
if(antag_team)
antag_team.add_member(src)
A.on_gain()
@@ -185,12 +185,6 @@
objectives, uplinks, powers etc are all handled.
*/
/datum/mind/proc/remove_objectives()
if(objectives.len)
for(var/datum/objective/O in objectives)
objectives -= O
qdel(O)
/datum/mind/proc/remove_changeling()
var/datum/antagonist/changeling/C = has_antag_datum(/datum/antagonist/changeling)
if(C)
@@ -207,13 +201,12 @@
remove_antag_datum(ANTAG_DATUM_BROTHER)
SSticker.mode.update_brother_icons_removed(src)
/datum/mind/proc/remove_nukeop()
if(src in SSticker.mode.syndicates)
SSticker.mode.syndicates -= src
SSticker.mode.update_synd_icons_removed(src)
special_role = null
remove_objectives()
remove_antag_equip()
var/datum/antagonist/nukeop/nuke = has_antag_datum(/datum/antagonist/nukeop,TRUE)
if(nuke)
remove_antag_datum(nuke.type)
special_role = null
/datum/mind/proc/remove_wizard()
remove_antag_datum(/datum/antagonist/wizard)
@@ -223,7 +216,6 @@
if(src in SSticker.mode.cult)
SSticker.mode.remove_cultist(src, 0, 0)
special_role = null
remove_objectives()
remove_antag_equip()
/datum/mind/proc/remove_rev()
@@ -329,14 +321,19 @@
SSticker.mode.add_cultist(src)
else if(is_revolutionary(creator))
var/datum/antagonist/rev/converter = creator.mind.has_antag_datum(/datum/antagonist/rev)
var/datum/antagonist/rev/converter = creator.mind.has_antag_datum(/datum/antagonist/rev,TRUE)
converter.add_revolutionary(src,FALSE)
else if(is_servant_of_ratvar(creator))
add_servant_of_ratvar(current)
else if(is_nuclear_operative(creator))
make_Nuke(null, null, 0, FALSE)
var/datum/antagonist/nukeop/converter = creator.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE)
var/datum/antagonist/nukeop/N = new(src)
N.send_to_spawnpoint = FALSE
N.nukeop_outfit = null
add_antag_datum(N,converter.nuke_team)
enslaved_to = creator
@@ -464,20 +461,27 @@
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if (ishuman(current))
text += "<a href='?src=[REF(src)];monkey=healthy'>healthy</a> | <a href='?src=[REF(src)];monkey=infected'>infected</a> | <b>HUMAN</b> | other"
if(is_monkey_leader(src))
text += "<a href='?src=[REF(src)];monkey=healthy'>healthy</a> | <a href='?src=[REF(src)];monkey=infected'>infected</a> <b>LEADER</b> | <a href='?src=[REF(src)];monkey=human'>human</a> | other"
else
text += "<a href='?src=[REF(src)];monkey=healthy'>healthy</a> | <a href='?src=[REF(src)];monkey=infected'>infected</a> | <a href='?src=[REF(src)];monkey=leader'>leader</a> | <b>HUMAN</b> | other"
else if(ismonkey(current))
var/found = FALSE
for(var/datum/disease/transformation/jungle_fever/JF in current.viruses)
found = TRUE
break
if(found)
text += "<a href='?src=[REF(src)];monkey=healthy'>healthy</a> | <b>INFECTED</b> | <a href='?src=[REF(src)];monkey=human'>human</a> | other"
var/isLeader = is_monkey_leader(src)
if(isLeader)
text += "<a href='?src=[REF(src)];monkey=healthy'>healthy</a> | <a href='?src=[REF(src)];monkey=infected'>infected</a> <b>LEADER</b> | <a href='?src=[REF(src)];monkey=human'>human</a> | other"
else if(found)
text += "<a href='?src=[REF(src)];monkey=healthy'>healthy</a> | <b>INFECTED</b> | <a href='?src=[REF(src)];monkey=leader'>leader</a> | <a href='?src=[REF(src)];monkey=human'>human</a> | other"
else
text += "<b>HEALTHY</b> | <a href='?src=[REF(src)];monkey=infected'>infected</a> | <a href='?src=[REF(src)];monkey=human'>human</a> | other"
text += "<b>HEALTHY</b> | <a href='?src=[REF(src)];monkey=infected'>infected</a> | <a href='?src=[REF(src)];monkey=leader'>leader</a> | <a href='?src=[REF(src)];monkey=human'>human</a> | other"
else
text += "healthy | infected | human | <b>OTHER</b>"
text += "healthy | infected | leader | human | <b>OTHER</b>"
if(current && current.client && (ROLE_MONKEY in current.client.prefs.be_special))
text += " | Enabled in Prefs"
@@ -493,7 +497,8 @@
if (SSticker.mode.config_tag=="nuclear")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if (src in SSticker.mode.syndicates)
var/datum/antagonist/nukeop/N = has_antag_datum(/datum/antagonist/nukeop,TRUE)
if(N)
text += "<b>OPERATIVE</b> | <a href='?src=[REF(src)];nuclear=clear'>nanotrasen</a>"
text += "<br><a href='?src=[REF(src)];nuclear=lair'>To shuttle</a>, <a href='?src=[REF(src)];common=undress'>undress</a>, <a href='?src=[REF(src)];nuclear=dressup'>dress up</a>."
var/code
@@ -713,7 +718,7 @@
out += sections[i]+"<br>"
if(((src in SSticker.mode.traitors) || (src in SSticker.mode.syndicates)) && ishuman(current))
if(((src in SSticker.mode.traitors) || is_nuclear_operative(current)) && ishuman(current))
text = "Uplink: <a href='?src=[REF(src)];common=uplink'>give</a>"
var/datum/component/uplink/U = find_syndicate_uplink()
if(U)
@@ -769,17 +774,44 @@
var/objective_pos
var/def_value
var/datum/antagonist/target_antag
if (href_list["obj_edit"])
objective = locate(href_list["obj_edit"])
if (!objective)
return
objective_pos = objectives.Find(objective)
for(var/datum/antagonist/A in antag_datums)
if(objective in A.objectives)
target_antag = A
objective_pos = A.objectives.Find(objective)
break
if(!target_antag) //Shouldn't happen
stack_trace("objective without antagonist found")
objective_pos = objectives.Find(objective)
//Text strings are easy to manipulate. Revised for simplicity.
var/temp_obj_type = "[objective.type]"//Convert path into a text string.
def_value = copytext(temp_obj_type, 19)//Convert last part of path into an objective keyword.
if(!def_value)//If it's a custom objective, it will be an empty string.
def_value = "custom"
else
switch(antag_datums.len)
if(0)
target_antag = add_antag_datum(/datum/antagonist/custom)
if(1)
target_antag = antag_datums[1]
else
var/datum/antagonist/target = input("Which antagonist gets the objective:", "Antagonist", def_value) as null|anything in antag_datums + "(new custom antag)"
if (QDELETED(target))
return
else if(target == "(new custom antag)")
target_antag = add_antag_datum(/datum/antagonist/custom)
else
target_antag = target
var/new_obj_type = input("Select objective type:", "Objective type", def_value) as null|anything in list("assassinate", "late-assassinate", "maroon", "debrain", "protect", "destroy", "prevent", "hijack", "escape", "survive", "martyr", "steal", "download", "nuclear", "capture", "absorb", "custom")
if (!new_obj_type)
@@ -901,11 +933,15 @@
return
if (objective)
if(target_antag)
target_antag.objectives -= objective
objectives -= objective
objectives.Insert(objective_pos, new_objective)
target_antag.objectives.Insert(objective_pos, new_objective)
message_admins("[key_name_admin(usr)] edited [current]'s objective to [new_objective.explanation_text]")
log_admin("[key_name(usr)] edited [current]'s objective to [new_objective.explanation_text]")
else
if(target_antag)
target_antag.objectives += new_objective
objectives += new_objective
message_admins("[key_name_admin(usr)] added a new objective for [current]: [new_objective.explanation_text]")
log_admin("[key_name(usr)] added a new objective for [current]: [new_objective.explanation_text]")
@@ -914,6 +950,11 @@
var/datum/objective/objective = locate(href_list["obj_delete"])
if(!istype(objective))
return
for(var/datum/antagonist/A in antag_datums)
if(objective in A.objectives)
A.objectives -= objective
break
objectives -= objective
message_admins("[key_name_admin(usr)] removed an objective for [current]: [objective.explanation_text]")
log_admin("[key_name(usr)] removed an objective for [current]: [objective.explanation_text]")
@@ -996,11 +1037,13 @@
message_admins("[key_name_admin(usr)] has cult'ed [current].")
log_admin("[key_name(usr)] has cult'ed [current].")
if("tome")
if (!SSticker.mode.equip_cultist(current,1))
var/datum/antagonist/cult/C = has_antag_datum(/datum/antagonist/cult,TRUE)
if (C.equip_cultist(current,1))
to_chat(usr, "<span class='danger'>Spawning tome failed!</span>")
if("amulet")
if (!SSticker.mode.equip_cultist(current))
var/datum/antagonist/cult/C = has_antag_datum(/datum/antagonist/cult,TRUE)
if (C.equip_cultist(current))
to_chat(usr, "<span class='danger'>Spawning amulet failed!</span>")
else if(href_list["clockcult"])
@@ -1071,36 +1114,14 @@
message_admins("[key_name_admin(usr)] has de-nuke op'ed [current].")
log_admin("[key_name(usr)] has de-nuke op'ed [current].")
if("nuclear")
if(!(src in SSticker.mode.syndicates))
SSticker.mode.syndicates += src
SSticker.mode.update_synd_icons_added(src)
if (SSticker.mode.syndicates.len==1)
SSticker.mode.prepare_syndicate_leader(src)
else
current.real_name = "[syndicate_name()] Operative #[SSticker.mode.syndicates.len-1]"
if(!has_antag_datum(/datum/antagonist/nukeop,TRUE))
add_antag_datum(/datum/antagonist/nukeop)
special_role = "Syndicate"
assigned_role = "Syndicate"
to_chat(current, "<span class='notice'>You are a [syndicate_name()] agent!</span>")
SSticker.mode.forge_syndicate_objectives(src)
SSticker.mode.greet_syndicate(src)
message_admins("[key_name_admin(usr)] has nuke op'ed [current].")
log_admin("[key_name(usr)] has nuke op'ed [current].")
if("lair")
current.forceMove(pick(GLOB.nukeop_start))
if("dressup")
var/mob/living/carbon/human/H = current
qdel(H.belt)
qdel(H.back)
qdel(H.ears)
qdel(H.gloves)
qdel(H.head)
qdel(H.shoes)
qdel(H.wear_id)
qdel(H.wear_suit)
qdel(H.w_uniform)
if (!SSticker.mode.equip_syndicate(current))
to_chat(usr, "<span class='danger'>Equipping a syndicate failed!</span>")
if("tellcode")
var/code
for (var/obj/machinery/nuclearbomb/bombue in GLOB.machines)
@@ -1241,11 +1262,17 @@
else if (istype(M) && length(M.viruses))
for(var/thing in M.viruses)
var/datum/disease/D = thing
D.cure(0)
D.cure(FALSE)
if("leader")
if(check_rights(R_ADMIN, 0))
add_monkey_leader(src)
log_admin("[key_name(usr)] made [key_name(current)] a monkey leader!")
message_admins("[key_name_admin(usr)] made [key_name_admin(current)] a monkey leader!")
if("infected")
if (check_rights(R_ADMIN, 0))
if(check_rights(R_ADMIN, 0))
var/mob/living/carbon/human/H = current
var/mob/living/carbon/monkey/M = current
add_monkey(src)
if (istype(H))
log_admin("[key_name(usr)] attempting to monkeyize and infect [key_name(current)]")
message_admins("<span class='notice'>[key_name_admin(usr)] attempting to monkeyize and infect [key_name_admin(current)]</span>")
@@ -1263,6 +1290,7 @@
for(var/datum/disease/transformation/jungle_fever/JF in M.viruses)
JF.cure(0)
stoplag() //because deleting of virus is doing throught spawn(0) //What
remove_monkey(src)
log_admin("[key_name(usr)] attempting to humanize [key_name(current)]")
message_admins("<span class='notice'>[key_name_admin(usr)] attempting to humanize [key_name_admin(current)]</span>")
H = M.humanize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_DEFAULTMSG)
@@ -1348,50 +1376,6 @@
T.should_specialise = TRUE
add_antag_datum(T)
/datum/mind/proc/make_Nuke(turf/spawnloc, nuke_code, leader=0, telecrystals = TRUE)
if(!(src in SSticker.mode.syndicates))
SSticker.mode.syndicates += src
SSticker.mode.update_synd_icons_added(src)
assigned_role = "Syndicate"
special_role = "Syndicate"
SSticker.mode.forge_syndicate_objectives(src)
SSticker.mode.greet_syndicate(src)
current.faction |= "syndicate"
if(spawnloc)
current.forceMove(spawnloc)
if(ishuman(current))
var/mob/living/carbon/human/H = current
qdel(H.belt)
qdel(H.back)
qdel(H.ears)
qdel(H.gloves)
qdel(H.head)
qdel(H.shoes)
qdel(H.wear_id)
qdel(H.wear_suit)
qdel(H.w_uniform)
SSticker.mode.equip_syndicate(current, telecrystals)
if (nuke_code)
store_memory("<B>Syndicate Nuclear Bomb Code</B>: [nuke_code]", 0, 0)
to_chat(current, "The nuclear authorization code is: <B>[nuke_code]</B>")
else
var/obj/machinery/nuclearbomb/nuke = locate("syndienuke") in GLOB.nuke_list
if(nuke)
store_memory("<B>Syndicate Nuclear Bomb Code</B>: [nuke.r_code]", 0, 0)
to_chat(current, "The nuclear authorization code is: <B>nuke.r_code</B>")
else
to_chat(current, "You were not provided with a nuclear code. Trying asking your team leader or contacting syndicate command.</B>")
if (leader)
SSticker.mode.prepare_syndicate_leader(src,nuke_code)
else
current.real_name = "[syndicate_name()] Operative #[SSticker.mode.syndicates.len-1]"
/datum/mind/proc/make_Changling()
var/datum/antagonist/changeling/C = has_antag_datum(/datum/antagonist/changeling)
if(!C)
@@ -1407,16 +1391,11 @@
/datum/mind/proc/make_Cultist()
if(!(src in SSticker.mode.cult))
SSticker.mode.add_cultist(src,FALSE)
if(!has_antag_datum(/datum/antagonist/cult,TRUE))
SSticker.mode.add_cultist(src,FALSE,equip=TRUE)
special_role = "Cultist"
to_chat(current, "<font color=\"purple\"><b><i>You catch a glimpse of the Realm of Nar-Sie, The Geometer of Blood. You now see how flimsy your world is, you see that it should be open to the knowledge of Nar-Sie.</b></i></font>")
to_chat(current, "<font color=\"purple\"><b><i>Assist your new bretheren in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back.</b></i></font>")
var/datum/antagonist/cult/C
C.cult_memorization(src)
var/mob/living/carbon/human/H = current
if (!SSticker.mode.equip_cultist(current))
to_chat(H, "Spawning an amulet from your Master failed.")
/datum/mind/proc/make_Rev()
var/datum/antagonist/rev/head/head = new(src)
-1
View File
@@ -8,7 +8,6 @@ GLOBAL_LIST_EMPTY(mutations_list)
GLOB.mutations_list[name] = src
/datum/mutation/human
var/dna_block
var/quality
var/get_chance = 100
+4 -4
View File
@@ -85,12 +85,12 @@
/datum/mutation/human/clumsy/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
owner.disabilities |= CLUMSY
owner.add_disability(CLUMSY, GENETIC_MUTATION)
/datum/mutation/human/clumsy/on_losing(mob/living/carbon/human/owner)
if(..())
return
owner.disabilities &= ~CLUMSY
owner.remove_disability(CLUMSY, GENETIC_MUTATION)
//Tourettes causes you to randomly stand in place and shout.
@@ -124,12 +124,12 @@
/datum/mutation/human/deaf/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
owner.disabilities |= DEAF
owner.add_disability(DEAF, GENETIC_MUTATION)
/datum/mutation/human/deaf/on_losing(mob/living/carbon/human/owner)
if(..())
return
owner.disabilities &= ~DEAF
owner.remove_disability(DEAF, GENETIC_MUTATION)
//Monified turns you into a monkey.
+4 -4
View File
@@ -7,12 +7,12 @@
/datum/mutation/human/nearsight/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
owner.become_nearsighted()
owner.become_nearsighted(GENETIC_MUTATION)
/datum/mutation/human/nearsight/on_losing(mob/living/carbon/human/owner)
if(..())
return
owner.cure_nearsighted()
owner.cure_nearsighted(GENETIC_MUTATION)
//Blind makes you blind. Who knew?
@@ -24,12 +24,12 @@
/datum/mutation/human/blind/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
owner.become_blind()
owner.become_blind(GENETIC_MUTATION)
/datum/mutation/human/blind/on_losing(mob/living/carbon/human/owner)
if(..())
return
owner.cure_blind()
owner.cure_blind(GENETIC_MUTATION)
//X-Ray Vision lets you see through walls.
+2 -2
View File
@@ -30,12 +30,12 @@
/datum/mutation/human/mute/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
owner.disabilities |= MUTE
owner.add_disability(MUTE, GENETIC_MUTATION)
/datum/mutation/human/mute/on_losing(mob/living/carbon/human/owner)
if(..())
return
owner.disabilities &= ~MUTE
owner.remove_disability(MUTE, GENETIC_MUTATION)
/datum/mutation/human/smile
+239
View File
@@ -0,0 +1,239 @@
//Designed for things that need precision trajectories like projectiles.
//Don't use this for anything that you don't absolutely have to use this with (like projectiles!) because it isn't worth using a datum unless you need accuracy down to decimal places in pixels.
#define RETURN_PRECISE_POSITION(A) new /datum/position(A)
#define RETURN_PRECISE_POINT(A) new /datum/point(A)
/datum/position //For positions with map x/y/z and pixel x/y so you don't have to return lists. Could use addition/subtraction in the future I guess.
var/x = 0
var/y = 0
var/z = 0
var/pixel_x = 0
var/pixel_y = 0
/datum/position/proc/valid()
return x && y && z && !isnull(pixel_x) && !isnull(pixel_y)
/datum/position/New(_x = 0, _y = 0, _z = 0, _pixel_x = 0, _pixel_y = 0) //first argument can also be a /datum/point.
if(istype(_x, /datum/point))
var/datum/point/P = _x
var/turf/T = P.return_turf()
_x = T.x
_y = T.y
_z = T.z
_pixel_x = P.return_px()
_pixel_y = P.return_py()
else if(isatom(_x))
var/atom/A = _x
_x = A.x
_y = A.y
_z = A.z
_pixel_x = A.pixel_x
_pixel_y = A.pixel_y
x = _x
y = _y
z = _z
pixel_x = _pixel_x
pixel_y = _pixel_y
/datum/position/proc/return_turf()
return locate(x, y, z)
/datum/position/proc/return_px()
return pixel_x
/datum/position/proc/return_py()
return pixel_y
/datum/position/proc/return_point()
return new /datum/point(src)
/proc/point_midpoint_points(datum/point/a, datum/point/b) //Obviously will not support multiZ calculations! Same for the two below.
var/datum/point/P = new
P.x = round(a.x + (b.x - a.x) / 2, 1)
P.y = round(a.y + (b.y - a.y) / 2, 1)
P.z = a.z
return P
/proc/pixel_length_between_points(datum/point/a, datum/point/b)
return sqrt(((b.x - a.x) ** 2) + ((b.y - a.y) ** 2))
/proc/angle_between_points(datum/point/a, datum/point/b)
return ATAN2((b.y - a.y), (b.x - a.x))
/datum/point //A precise point on the map in absolute pixel locations based on world.icon_size. Pixels are FROM THE EDGE OF THE MAP!
var/x = 0
var/y = 0
var/z = 0
/datum/point/proc/valid()
return x && y && z
/datum/point/proc/copy_to(datum/point/p = new)
p.x = x
p.y = y
p.z = z
return p
/datum/point/New(_x, _y, _z, _pixel_x = 0, _pixel_y = 0) //first argument can also be a /datum/position or /atom.
if(istype(_x, /datum/position))
var/datum/position/P = _x
_x = P.x
_y = P.y
_z = P.z
_pixel_x = P.pixel_x
_pixel_y = P.pixel_y
else if(istype(_x, /atom))
var/atom/A = _x
_x = A.x
_y = A.y
_z = A.z
_pixel_x = A.pixel_x
_pixel_y = A.pixel_y
initialize_location(_x, _y, _z, _pixel_x, _pixel_y)
/datum/point/proc/initialize_location(tile_x, tile_y, tile_z, p_x = 0, p_y = 0)
if(!isnull(tile_x))
x = ((tile_x - 1) * world.icon_size) + world.icon_size / 2 + p_x
if(!isnull(tile_y))
y = ((tile_y - 1) * world.icon_size) + world.icon_size / 2+ p_y
if(!isnull(tile_z))
z = tile_z
/datum/point/proc/return_turf()
return locate(CEILING(x / world.icon_size, 1), CEILING(y / world.icon_size, 1), z)
/datum/point/proc/return_coordinates() //[turf_x, turf_y, z]
return list(CEILING(x / world.icon_size, 1), CEILING(y / world.icon_size, 1), z)
/datum/point/proc/return_position()
return new /datum/position(src)
/datum/point/proc/return_px()
return MODULUS(x, world.icon_size) - 16
/datum/point/proc/return_py()
return MODULUS(y, world.icon_size) - 16
/datum/point/proc/mapcheck()
. = FALSE
var/maxx = world.icon_size * world.maxx
var/maxy = world.icon_size * world.maxy
var/move_zx = 0
var/move_zy = 0
if(x < 0)
x += maxx
move_zx -= 1
if(y < 0)
y += maxy
move_zy -= 1
if(x > maxx)
x -= maxx
move_zx += 1
if(y > maxy)
y -= maxy
move_zy += 1
var/datum/space_level/S = GLOB.z_levels_list["[z]"]
if(move_zx != 0)
var/datum/space_level/L = S.neigbours["[move_zx < 0? WEST : EAST]"]
z = L.z_value
. = TRUE
if(move_zy != 0)
var/datum/space_level/L = S.neigbours["[move_zy < 0? SOUTH : NORTH]"]
z = L.z_value
. = TRUE
/datum/point/vector
var/speed = 32 //pixels per iteration
var/iteration = 0
var/angle = 0
var/mpx = 0 //calculated x/y movement amounts to prevent having to do trig every step.
var/mpy = 0
var/starting_x = 0 //just like before, pixels from EDGE of map! This is set in initialize_location().
var/starting_y = 0
var/starting_z = 0
/datum/point/vector/New(_x, _y, _z, _pixel_x = 0, _pixel_y = 0, _angle, _speed)
..()
initialize_trajectory(_speed, _angle)
/datum/point/vector/initialize_location(tile_x, tile_y, tile_z, p_x = 0, p_y = 0)
. = ..()
starting_x = x
starting_y = y
starting_z = z
/datum/point/vector/copy_to(datum/point/vector/v = new)
..(v)
v.speed = speed
v.iteration = iteration
v.angle = angle
v.mpx = mpx
v.mpy = mpy
v.starting_x = starting_x
v.starting_y = starting_y
v.starting_z = starting_z
return v
/datum/point/vector/proc/initialize_trajectory(pixel_speed, new_angle)
if(!isnull(pixel_speed))
speed = pixel_speed
set_angle(new_angle)
/datum/point/vector/proc/set_angle(new_angle) //calculations use "byond angle" where north is 0 instead of 90, and south is 180 instead of 270.
if(isnull(angle))
return
angle = new_angle
update_offsets()
/datum/point/vector/proc/update_offsets()
mpx = sin(angle) * speed
mpy = cos(angle) * speed
/datum/point/vector/proc/set_speed(new_speed)
if(isnull(new_speed) || speed == new_speed)
return
speed = new_speed
update_offsets()
/datum/point/vector/proc/increment(multiplier = 1)
iteration++
x += mpx * 1
y += mpy * 1
if(mapcheck())
on_z_change()
/datum/point/vector/proc/return_vector_after_increments(amount = 7, multiplier = 1, force_simulate = FALSE)
var/datum/point/vector/v = copy_to()
if(force_simulate)
for(var/i in 1 to amount)
v.increment(multiplier)
else
v.increment(multiplier * amount)
return v
/datum/point/vector/proc/on_z_change()
return
/datum/point/vector/processed //pixel_speed is per decisecond.
var/last_process = 0
var/last_move = 0
var/paused = FALSE
/datum/point/vector/processed/Destroy()
STOP_PROCESSING(SSprojectiles, src)
/datum/point/vector/processed/proc/start()
last_process = world.time
last_move = world.time
START_PROCESSING(SSprojectiles, src)
/datum/point/vector/processed/process()
if(paused)
last_move += world.time - last_process
last_process = world.time
return
var/needed_time = world.time - last_move
last_process = world.time
last_move = world.time
increment(needed_time)
+1 -1
View File
@@ -38,7 +38,7 @@
if (user.client)
user.client.images += bar
progress = Clamp(progress, 0, goal)
progress = CLAMP(progress, 0, goal)
bar.icon_state = "prog_bar_[round(((progress / goal) * 100), 5)]"
if (!shown)
user.client.images += bar
+2 -2
View File
@@ -34,7 +34,7 @@
var/strength
if(steps>1)
strength = InverseSquareLaw(intensity, max(range_modifier*steps, 1), 1)
strength = INVERSE_SQUARE(intensity, max(range_modifier*steps, 1), 1)
else
strength = intensity
@@ -42,7 +42,7 @@
qdel(src)
return
radiate(atoms, Floor(strength))
radiate(atoms, FLOOR(strength, 1))
check_obstructions(atoms) // reduce our overall strength if there are radiation insulators
+23 -1
View File
@@ -33,7 +33,7 @@
if(LINGHIVE_LING)
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
var/msg = "<i><font color=#800080><b>[changeling.changelingID]:</b> [message]</font></i>"
log_talk(src,"[changeling.changelingID]/[user.key] : [message]",LOGSAY)
log_talk(user,"[changeling.changelingID]/[user.key] : [message]",LOGSAY)
for(var/_M in GLOB.mob_list)
var/mob/M = _M
if(M in GLOB.dead_mob_list)
@@ -110,3 +110,25 @@
AI.holopad_talk(message, language)
return FALSE
return TRUE
/datum/saymode/monkey
key = "k"
mode = MODE_MONKEY
/datum/saymode/monkey/handle_message(mob/living/user, message, datum/language/language)
var/datum/mind = user.mind
if(!mind)
return TRUE
if(is_monkey_leader(mind) || (ismonkey(user) && is_monkey(mind)))
log_talk(user, "(MONKEY) [user]/[user.key]: [message]",LOGSAY)
if(prob(75) && ismonkey(user))
user.visible_message("<span class='notice'>\The [user] chimpers.</span>")
var/msg = "<span class='[is_monkey_leader(mind) ? "monkeylead" : "monkeyhive"]'><b><font size=2>\[[is_monkey_leader(mind) ? "Monkey Leader" : "Monkey"]\]</font> [user]</b>: [message]</span>"
for(var/_M in GLOB.mob_list)
var/mob/M = _M
if(M in GLOB.dead_mob_list)
var/link = FOLLOW_LINK(M, user)
to_chat(M, "[link] [msg]")
if((is_monkey_leader(M.mind) || ismonkey(M)) && (M.mind in SSticker.mode.ape_infectees))
to_chat(M, msg)
return FALSE
+3 -3
View File
@@ -60,8 +60,8 @@
if(istype(L)) //this is probably more safety than actually needed
var/vanguard = L.stun_absorption["vanguard"]
desc = initial(desc)
desc += "<br><b>[Floor(vanguard["stuns_absorbed"] * 0.1)]</b> seconds of stuns held back.\
[GLOB.ratvar_awakens ? "":"<br><b>[Floor(min(vanguard["stuns_absorbed"] * 0.025, 20))]</b> seconds of stun will affect you."]"
desc += "<br><b>[FLOOR(vanguard["stuns_absorbed"] * 0.1, 1)]</b> seconds of stuns held back.\
[GLOB.ratvar_awakens ? "":"<br><b>[FLOOR(min(vanguard["stuns_absorbed"] * 0.025, 20), 1)]</b> seconds of stun will affect you."]"
..()
/datum/status_effect/vanguard_shield/Destroy()
@@ -87,7 +87,7 @@
var/vanguard = owner.stun_absorption["vanguard"]
var/stuns_blocked = 0
if(vanguard)
stuns_blocked = Floor(min(vanguard["stuns_absorbed"] * 0.25, 400))
stuns_blocked = FLOOR(min(vanguard["stuns_absorbed"] * 0.25, 400), 1)
vanguard["end_time"] = 0 //so it doesn't absorb the stuns we're about to apply
if(owner.stat != DEAD)
var/message_to_owner = "<span class='warning'>You feel your Vanguard quietly fade...</span>"
+2 -2
View File
@@ -230,7 +230,7 @@
if(prob(severity * 0.15))
to_chat(owner, "<span class='sevtug[span_part]'>\"[text2ratvar(pick(mania_messages))]\"</span>")
owner.playsound_local(get_turf(motor), hum, severity, 1)
owner.adjust_drugginess(Clamp(max(severity * 0.075, 1), 0, max(0, 50 - owner.druggy))) //7.5% of severity per second, minimum 1
owner.adjust_drugginess(CLAMP(max(severity * 0.075, 1), 0, max(0, 50 - owner.druggy))) //7.5% of severity per second, minimum 1
if(owner.hallucination < 50)
owner.hallucination = min(owner.hallucination + max(severity * 0.075, 1), 50) //7.5% of severity per second, minimum 1
if(owner.dizziness < 50)
@@ -310,7 +310,7 @@
var/icon/I = icon(owner.icon, owner.icon_state, owner.dir)
var/icon_height = I.Height()
bleed_overlay.pixel_x = -owner.pixel_x
bleed_overlay.pixel_y = Floor(icon_height * 0.25)
bleed_overlay.pixel_y = FLOOR(icon_height * 0.25, 1)
bleed_overlay.transform = matrix() * (icon_height/world.icon_size) //scale the bleed overlay's size based on the target's icon size
bleed_underlay.pixel_x = -owner.pixel_x
bleed_underlay.transform = matrix() * (icon_height/world.icon_size) * 3

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