Merge branch 'master' into upstream-merge-33470
This commit is contained in:
@@ -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) };
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -61,6 +61,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 +79,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
|
||||
|
||||
@@ -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,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 )
|
||||
@@ -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)
|
||||
|
||||
// )
|
||||
@@ -495,7 +495,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -18,8 +18,9 @@
|
||||
#define HUSK 64
|
||||
#define NOCLONE 128
|
||||
#define CLUMSY 256
|
||||
#define DUMB 512
|
||||
#define MONKEYLIKE 1024 //sets IsAdvancedToolUser to FALSE
|
||||
#define DUMB 512
|
||||
#define MONKEYLIKE 1024 //sets IsAdvancedToolUser to FALSE
|
||||
#define PACIFISM 2048
|
||||
|
||||
// bitflags for machine stat variable
|
||||
#define BROKEN 1
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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)
|
||||
@@ -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
@@ -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]"
|
||||
|
||||
@@ -0,0 +1,412 @@
|
||||
/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
|
||||
|
||||
//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>")
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -257,8 +257,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
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
|
||||
/atom/proc/attack_animal(mob/user)
|
||||
return
|
||||
|
||||
/mob/living/RestrainedClickOn(atom/A)
|
||||
return
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"))
|
||||
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)
|
||||
|
||||
@@ -91,14 +98,17 @@ GLOBAL_PROTECT(config_dir)
|
||||
if(!entry)
|
||||
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 +117,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
|
||||
|
||||
. = 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"
|
||||
@@ -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
|
||||
|
||||
@@ -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]")
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
+3
-26
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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>")
|
||||
@@ -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
@@ -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>"
|
||||
@@ -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>"
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>"
|
||||
@@ -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>"
|
||||
@@ -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()
|
||||
@@ -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
@@ -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
|
||||
@@ -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))
|
||||
..()
|
||||
@@ -7,7 +7,7 @@
|
||||
/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>"
|
||||
|
||||
@@ -25,6 +25,29 @@
|
||||
owner.disabilities &= ~MUTE
|
||||
..()
|
||||
|
||||
/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
|
||||
name = "Cerebral Blindness"
|
||||
desc = "Patient's brain is no longer connected to its eyes."
|
||||
@@ -177,3 +200,18 @@
|
||||
/datum/brain_trauma/severe/discoordination/on_lose()
|
||||
owner.disabilities &= ~MONKEYLIKE
|
||||
..()
|
||||
|
||||
/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
|
||||
..()
|
||||
@@ -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>")
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
if(old_dir == new_dir)
|
||||
return
|
||||
remove()
|
||||
var/rotation = SimplifyDegrees(dir2angle(new_dir)-dir2angle(old_dir))
|
||||
var/rotation = SIMPLIFY_DEGREES(dir2angle(new_dir)-dir2angle(old_dir))
|
||||
pic.dir = turn(pic.dir, rotation)
|
||||
apply()
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
. = ..()
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
+62
-97
@@ -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
|
||||
|
||||
@@ -493,7 +490,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 +711,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 +767,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 +926,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 +943,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 +1030,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 +1107,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)
|
||||
@@ -1348,50 +1362,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 +1377,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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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>"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -516,7 +516,7 @@
|
||||
. = ..()
|
||||
. -= "Jump to"
|
||||
.["Follow"] = "?_src_=holder;[HrefToken()];adminplayerobservefollow=[REF(src)]"
|
||||
.["Get"] = "?_src=holder;[HrefToken()];admingetmovable=[REF(src)]"
|
||||
.["Get"] = "?_src_=holder;[HrefToken()];admingetmovable=[REF(src)]"
|
||||
|
||||
/atom/movable/proc/ex_check(ex_id)
|
||||
if(!ex_id)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
var/used = 0
|
||||
|
||||
/obj/item/antag_spawner/proc/spawn_antag(client/C, turf/T, type = "")
|
||||
/obj/item/antag_spawner/proc/spawn_antag(client/C, turf/T, kind = "", datum/mind/user)
|
||||
return
|
||||
|
||||
/obj/item/antag_spawner/proc/equip_antag(mob/target)
|
||||
@@ -67,18 +67,16 @@
|
||||
else
|
||||
to_chat(H, "Unable to reach your apprentice! You can either attack the spellbook with the contract to refund your points, or wait and try again later.")
|
||||
|
||||
/obj/item/antag_spawner/contract/spawn_antag(client/C, turf/T, school,datum/mind/user)
|
||||
/obj/item/antag_spawner/contract/spawn_antag(client/C, turf/T, kind ,datum/mind/user)
|
||||
new /obj/effect/particle_effect/smoke(T)
|
||||
var/mob/living/carbon/human/M = new/mob/living/carbon/human(T)
|
||||
C.prefs.copy_to(M)
|
||||
M.key = C.key
|
||||
var/datum/mind/app_mind = M.mind
|
||||
|
||||
|
||||
|
||||
|
||||
var/datum/antagonist/wizard/apprentice/app = new(app_mind)
|
||||
app.master = user
|
||||
app.school = school
|
||||
app.school = kind
|
||||
|
||||
var/datum/antagonist/wizard/master_wizard = user.has_antag_datum(/datum/antagonist/wizard)
|
||||
if(master_wizard)
|
||||
@@ -107,7 +105,7 @@
|
||||
if(used)
|
||||
to_chat(user, "<span class='warning'>[src] is out of power!</span>")
|
||||
return FALSE
|
||||
if(!(user.mind in SSticker.mode.syndicates))
|
||||
if(!user.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE))
|
||||
to_chat(user, "<span class='danger'>AUTHENTICATION FAILURE. ACCESS DENIED.</span>")
|
||||
return FALSE
|
||||
if(user.z != ZLEVEL_CENTCOM)
|
||||
@@ -127,25 +125,25 @@
|
||||
return
|
||||
used = TRUE
|
||||
var/mob/dead/observer/theghost = pick(nuke_candidates)
|
||||
spawn_antag(theghost.client, get_turf(src), "syndieborg", user.mind)
|
||||
spawn_antag(theghost.client, get_turf(src), "syndieborg")
|
||||
do_sparks(4, TRUE, src)
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Unable to connect to Syndicate command. Please wait and try again later or use the teleporter on your uplink to get your points refunded.</span>")
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/spawn_antag(client/C, turf/T)
|
||||
/obj/item/antag_spawner/nuke_ops/spawn_antag(client/C, turf/T, kind, datum/mind/user)
|
||||
var/mob/living/carbon/human/M = new/mob/living/carbon/human(T)
|
||||
C.prefs.copy_to(M)
|
||||
M.key = C.key
|
||||
var/code = "BOMB-NOT-FOUND"
|
||||
var/obj/machinery/nuclearbomb/nuke = locate("syndienuke") in GLOB.nuke_list
|
||||
if(nuke)
|
||||
code = nuke.r_code
|
||||
M.mind.make_Nuke(null, code, 0, FALSE)
|
||||
var/newname = M.dna.species.random_name(M.gender,0,SSticker.mode.nukeops_lastname)
|
||||
M.mind.name = newname
|
||||
M.real_name = newname
|
||||
M.name = newname
|
||||
|
||||
var/datum/antagonist/nukeop/new_op = new(M.mind)
|
||||
new_op.send_to_spawnpoint = FALSE
|
||||
new_op.nukeop_outfit = /datum/outfit/syndicate/no_crystals
|
||||
|
||||
var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop,TRUE)
|
||||
if(creator_op)
|
||||
M.mind.add_antag_datum(new_op,creator_op.nuke_team)
|
||||
M.mind.special_role = "Nuclear Operative"
|
||||
|
||||
//////SYNDICATE BORG
|
||||
/obj/item/antag_spawner/nuke_ops/borg_tele
|
||||
@@ -162,8 +160,12 @@
|
||||
name = "syndicate medical teleporter"
|
||||
borg_to_spawn = "Medical"
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/borg_tele/spawn_antag(client/C, turf/T)
|
||||
/obj/item/antag_spawner/nuke_ops/borg_tele/spawn_antag(client/C, turf/T, kind, datum/mind/user)
|
||||
var/mob/living/silicon/robot/R
|
||||
var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop,TRUE)
|
||||
if(!creator_op)
|
||||
return
|
||||
|
||||
switch(borg_to_spawn)
|
||||
if("Medical")
|
||||
R = new /mob/living/silicon/robot/modules/syndicate/medical(T)
|
||||
@@ -174,8 +176,8 @@
|
||||
if(prob(50))
|
||||
brainfirstname = pick(GLOB.first_names_female)
|
||||
var/brainopslastname = pick(GLOB.last_names)
|
||||
if(SSticker.mode.nukeops_lastname) //the brain inside the syndiborg has the same last name as the other ops.
|
||||
brainopslastname = SSticker.mode.nukeops_lastname
|
||||
if(creator_op.nuke_team.syndicate_name) //the brain inside the syndiborg has the same last name as the other ops.
|
||||
brainopslastname = creator_op.nuke_team.syndicate_name
|
||||
var/brainopsname = "[brainfirstname] [brainopslastname]"
|
||||
|
||||
R.mmi.name = "Man-Machine Interface: [brainopsname]"
|
||||
@@ -185,7 +187,11 @@
|
||||
R.real_name = R.name
|
||||
|
||||
R.key = C.key
|
||||
R.mind.make_Nuke(null, nuke_code = null,leader=0, telecrystals = TRUE)
|
||||
|
||||
var/datum/antagonist/nukeop/new_borg = new(R.mind)
|
||||
new_borg.send_to_spawnpoint = FALSE
|
||||
R.mind.add_antag_datum(new_borg,creator_op.nuke_team)
|
||||
R.mind.special_role = "Syndicate Cyborg"
|
||||
|
||||
///////////SLAUGHTER DEMON
|
||||
|
||||
@@ -213,7 +219,7 @@
|
||||
return
|
||||
used = 1
|
||||
var/mob/dead/observer/theghost = pick(demon_candidates)
|
||||
spawn_antag(theghost.client, get_turf(src), initial(demon_type.name),user.mind)
|
||||
spawn_antag(theghost.client, get_turf(src), initial(demon_type.name))
|
||||
to_chat(user, shatter_msg)
|
||||
to_chat(user, veil_msg)
|
||||
playsound(user.loc, 'sound/effects/glassbr1.ogg', 100, 1)
|
||||
@@ -222,8 +228,7 @@
|
||||
to_chat(user, "<span class='notice'>You can't seem to work up the nerve to shatter the bottle. Perhaps you should try again later.</span>")
|
||||
|
||||
|
||||
/obj/item/antag_spawner/slaughter_demon/spawn_antag(client/C, turf/T, type = "", datum/mind/user)
|
||||
|
||||
/obj/item/antag_spawner/slaughter_demon/spawn_antag(client/C, turf/T, kind = "", datum/mind/user)
|
||||
var/obj/effect/dummy/slaughter/holder = new /obj/effect/dummy/slaughter(T)
|
||||
var/mob/living/simple_animal/slaughter/S = new demon_type(holder)
|
||||
S.holder = holder
|
||||
@@ -232,16 +237,17 @@
|
||||
S.mind.special_role = S.name
|
||||
SSticker.mode.traitors += S.mind
|
||||
var/datum/objective/assassinate/new_objective
|
||||
if(user)
|
||||
if(usr)
|
||||
new_objective = new /datum/objective/assassinate
|
||||
new_objective.owner = S.mind
|
||||
new_objective.target = user
|
||||
new_objective.explanation_text = "[objective_verb] [user.name], the one who summoned you."
|
||||
new_objective.target = usr.mind
|
||||
new_objective.explanation_text = "[objective_verb] [usr.real_name], the one who summoned you."
|
||||
S.mind.objectives += new_objective
|
||||
var/datum/objective/new_objective2 = new /datum/objective
|
||||
new_objective2.owner = S.mind
|
||||
new_objective2.explanation_text = "[objective_verb] everyone[user ? " else while you're at it":""]."
|
||||
new_objective2.explanation_text = "[objective_verb] everyone[usr ? " else while you're at it":""]."
|
||||
S.mind.objectives += new_objective2
|
||||
S.mind.add_antag_datum(/datum/antagonist/auto_custom)
|
||||
to_chat(S, S.playstyle_string)
|
||||
to_chat(S, "<B>You are currently not currently in the same plane of existence as the station. \
|
||||
Ctrl+Click a blood pool to manifest.</B>")
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
//A barebones antagonist team.
|
||||
/datum/team
|
||||
var/list/datum/mind/members = list()
|
||||
var/name = "team"
|
||||
var/member_name = "member"
|
||||
var/list/objectives = list() //common objectives, these won't be added or removed automatically, subtypes handle this, this is here for bookkeeping purposes.
|
||||
|
||||
/datum/team/New(starting_members)
|
||||
. = ..()
|
||||
if(starting_members)
|
||||
if(islist(starting_members))
|
||||
for(var/datum/mind/M in starting_members)
|
||||
add_member(M)
|
||||
else
|
||||
add_member(starting_members)
|
||||
|
||||
/datum/team/proc/is_solo()
|
||||
return members.len == 1
|
||||
|
||||
/datum/team/proc/add_member(datum/mind/new_member)
|
||||
members |= new_member
|
||||
|
||||
/datum/team/proc/remove_member(datum/mind/member)
|
||||
members -= member
|
||||
|
||||
//Display members/victory/failure/objectives for the team
|
||||
/datum/team/proc/roundend_report()
|
||||
var/list/report = list()
|
||||
|
||||
report += "<b>[name]:</b>"
|
||||
report += "The [member_name]s were:"
|
||||
report += printplayerlist(members)
|
||||
|
||||
return report.Join("<br>")
|
||||
@@ -42,7 +42,7 @@
|
||||
/mob/living/simple_animal/hostile/blob/fire_act(exposed_temperature, exposed_volume)
|
||||
..()
|
||||
if(exposed_temperature)
|
||||
adjustFireLoss(Clamp(0.01 * exposed_temperature, 1, 5))
|
||||
adjustFireLoss(CLAMP(0.01 * exposed_temperature, 1, 5))
|
||||
else
|
||||
adjustFireLoss(5)
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
|
||||
B.hud_used.blobpwrdisplay.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#82ed00'>[round(blob_core.obj_integrity)]</font></div>"
|
||||
|
||||
/mob/camera/blob/proc/add_points(points)
|
||||
blob_points = Clamp(blob_points + points, 0, max_blob_points)
|
||||
blob_points = CLAMP(blob_points + points, 0, max_blob_points)
|
||||
hud_used.blobpwrdisplay.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#82ed00'>[round(blob_points)]</font></div>"
|
||||
|
||||
/mob/camera/blob/say(message)
|
||||
|
||||
@@ -1,44 +1,6 @@
|
||||
/datum/objective_team/brother_team
|
||||
name = "brotherhood"
|
||||
member_name = "blood brother"
|
||||
var/list/objectives = list()
|
||||
var/meeting_area
|
||||
|
||||
/datum/objective_team/brother_team/is_solo()
|
||||
return FALSE
|
||||
|
||||
/datum/objective_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/objective_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/objective_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)
|
||||
|
||||
/datum/game_mode
|
||||
var/list/datum/mind/brothers = list()
|
||||
var/list/datum/objective_team/brother_team/brother_teams = list()
|
||||
var/list/datum/team/brother_team/brother_teams = list()
|
||||
|
||||
/datum/game_mode/traitor/bros
|
||||
name = "traitor+brothers"
|
||||
@@ -51,9 +13,10 @@
|
||||
<span class='danger'>Blood Brothers</span>: Accomplish your objectives.\n\
|
||||
<span class='notice'>Crew</span>: Do not let the traitors or brothers succeed!"
|
||||
|
||||
var/list/datum/objective_team/brother_team/pre_brother_teams = list()
|
||||
var/list/datum/team/brother_team/pre_brother_teams = list()
|
||||
var/const/team_amount = 2 //hard limit on brother teams if scaling is turned off
|
||||
var/const/min_team_size = 2
|
||||
traitors_required = FALSE //Only teams are possible
|
||||
|
||||
var/meeting_areas = list("The Bar", "Dorms", "Escape Dock", "Arrivals", "Holodeck", "Primary Tool Storage", "Recreation Area", "Chapel", "Library")
|
||||
|
||||
@@ -73,7 +36,7 @@
|
||||
for(var/j = 1 to num_teams)
|
||||
if(possible_brothers.len < min_team_size || antag_candidates.len <= required_enemies)
|
||||
break
|
||||
var/datum/objective_team/brother_team/team = new
|
||||
var/datum/team/brother_team/team = new
|
||||
var/team_size = prob(10) ? min(3, possible_brothers.len) : 2
|
||||
for(var/k = 1 to team_size)
|
||||
var/datum/mind/bro = pick(possible_brothers)
|
||||
@@ -86,50 +49,19 @@
|
||||
return ..()
|
||||
|
||||
/datum/game_mode/traitor/bros/post_setup()
|
||||
for(var/datum/objective_team/brother_team/team in pre_brother_teams)
|
||||
for(var/datum/team/brother_team/team in pre_brother_teams)
|
||||
team.meeting_area = pick(meeting_areas)
|
||||
meeting_areas -= team.meeting_area
|
||||
team.forge_brother_objectives()
|
||||
for(var/datum/mind/M in team.members)
|
||||
M.add_antag_datum(ANTAG_DATUM_BROTHER, team)
|
||||
team.update_name()
|
||||
brother_teams += pre_brother_teams
|
||||
return ..()
|
||||
|
||||
/datum/game_mode/traitor/bros/generate_report()
|
||||
return "It's Syndicate recruiting season. Be alert for potential Syndicate infiltrators, but also watch out for disgruntled employees trying to defect. Unlike Nanotrasen, the Syndicate prides itself in teamwork and will only recruit pairs that share a brotherly trust."
|
||||
|
||||
/datum/game_mode/proc/auto_declare_completion_brother()
|
||||
if(!LAZYLEN(brother_teams))
|
||||
return
|
||||
var/text = "<br><font size=4><b>The blood brothers were:</b></font>"
|
||||
var/teamnumber = 1
|
||||
for(var/datum/objective_team/brother_team/team in brother_teams)
|
||||
if(!team.members.len)
|
||||
continue
|
||||
text += "<br><font size=3><b>Team #[teamnumber++]</b></font>"
|
||||
for(var/datum/mind/M in team.members)
|
||||
text += printplayer(M)
|
||||
var/win = TRUE
|
||||
var/objective_count = 1
|
||||
for(var/datum/objective/objective in team.objectives)
|
||||
if(objective.check_completion())
|
||||
text += "<br><B>Objective #[objective_count]</B>: [objective.explanation_text] <font color='green'><B>Success!</B></font> [istype(objective, /datum/objective/crew) ? "<font color='grey'>(Optional)</font>" : ""]"
|
||||
SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[objective.type]", "SUCCESS"))
|
||||
else
|
||||
text += "<br><B>Objective #[objective_count]</B>: [objective.explanation_text] <font color='red'>Fail.</font> [istype(objective, /datum/objective/crew) ? "<font color='grey'>(Optional)</font>" : ""]"
|
||||
SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[objective.type]", "FAIL"))
|
||||
if(!(istype(objective, /datum/objective/crew)))
|
||||
win = FALSE
|
||||
objective_count++
|
||||
if(win)
|
||||
text += "<br><font color='green'><B>The blood brothers were successful!</B></font>"
|
||||
SSblackbox.record_feedback("tally", "brother_success", 1, "SUCCESS")
|
||||
else
|
||||
text += "<br><font color='red'><B>The blood brothers have failed!</B></font>"
|
||||
SSblackbox.record_feedback("tally", "brother_success", 1, "FAIL")
|
||||
text += "<br>"
|
||||
to_chat(world, text)
|
||||
|
||||
/datum/game_mode/proc/update_brother_icons_added(datum/mind/brother_mind)
|
||||
var/datum/atom_hud/antag/brotherhud = GLOB.huds[ANTAG_HUD_BROTHER]
|
||||
brotherhud.join_hud(brother_mind.current)
|
||||
|
||||
@@ -94,47 +94,6 @@ GLOBAL_VAR(changeling_team_objective_type) //If this is not null, we hand our th
|
||||
of the Thing being sent to a station in this sector is highly likely. It may be in the guise of any crew member. Trust nobody - suspect everybody. Do not announce this to the crew, \
|
||||
as paranoia may spread and inhibit workplace efficiency."
|
||||
|
||||
/datum/game_mode/proc/auto_declare_completion_changeling()
|
||||
var/list/changelings = get_antagonists(/datum/antagonist/changeling,TRUE) //Only real lings get a mention
|
||||
if(changelings.len)
|
||||
var/text = "<br><font size=3><b>The changelings were:</b></font>"
|
||||
for(var/datum/mind/changeling in changelings)
|
||||
var/datum/antagonist/changeling/ling = changeling.has_antag_datum(/datum/antagonist/changeling)
|
||||
var/changelingwin = 1
|
||||
if(!changeling.current)
|
||||
changelingwin = 0
|
||||
|
||||
text += printplayer(changeling)
|
||||
|
||||
//Removed sanity if(changeling) because we -want- a runtime to inform us that the changelings list is incorrect and needs to be fixed.
|
||||
text += "<br><b>Changeling ID:</b> [ling.changelingID]."
|
||||
text += "<br><b>Genomes Extracted:</b> [ling.absorbedcount]"
|
||||
|
||||
if(changeling.objectives.len)
|
||||
var/count = 1
|
||||
for(var/datum/objective/objective in changeling.objectives)
|
||||
if(objective.check_completion())
|
||||
text += "<br><b>Objective #[count]</b>: [objective.explanation_text] <font color='green'><b>Success!</b></font> [istype(objective, /datum/objective/crew) ? "<font color='grey'>(Optional)</font>" : ""]"
|
||||
SSblackbox.record_feedback("nested tally", "changeling_objective", 1, list("[objective.type]", "SUCCESS"))
|
||||
else
|
||||
text += "<br><b>Objective #[count]</b>: [objective.explanation_text] <span class='danger'>Fail.</span> [istype(objective, /datum/objective/crew) ? "<font color='grey'>(Optional)</font>" : ""]"
|
||||
SSblackbox.record_feedback("nested tally", "changeling_objective", 1, list("[objective.type]", "FAIL"))
|
||||
if(!(istype(objective, /datum/objective/crew)))
|
||||
changelingwin = 0
|
||||
count++
|
||||
|
||||
if(changelingwin)
|
||||
text += "<br><font color='green'><b>The changeling was successful!</b></font>"
|
||||
SSblackbox.record_feedback("tally", "changeling_success", 1, "SUCCESS")
|
||||
else
|
||||
text += "<br><span class='boldannounce'>The changeling has failed.</span>"
|
||||
SSblackbox.record_feedback("tally", "changeling_success", 1, "FAIL")
|
||||
text += "<br>"
|
||||
|
||||
to_chat(world, text)
|
||||
|
||||
return 1
|
||||
|
||||
/proc/changeling_transform(mob/living/carbon/human/user, datum/changelingprofile/chosen_prof)
|
||||
var/datum/dna/chosen_dna = chosen_prof.dna
|
||||
user.real_name = chosen_prof.name
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
user.nutrition = min((user.nutrition + target.nutrition), NUTRITION_LEVEL_WELL_FED)
|
||||
|
||||
if(target.mind)//if the victim has got a mind
|
||||
// Absorb a lizard, speak Draconic.
|
||||
user.copy_known_languages_from(target)
|
||||
|
||||
target.mind.show_memory(user, 0) //I can read your mind, kekeke. Output all their notes.
|
||||
|
||||
|
||||
@@ -65,13 +65,16 @@ Credit where due:
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/proc/add_servant_of_ratvar(mob/L, silent = FALSE)
|
||||
/proc/add_servant_of_ratvar(mob/L, silent = FALSE, create_team = TRUE)
|
||||
if(!L || !L.mind)
|
||||
return
|
||||
var/update_type = ANTAG_DATUM_CLOCKCULT
|
||||
if(silent)
|
||||
update_type = ANTAG_DATUM_CLOCKCULT_SILENT
|
||||
. = L.mind.add_antag_datum(update_type)
|
||||
var/datum/antagonist/clockcult/C = new update_type(L.mind)
|
||||
C.make_team = create_team
|
||||
C.show_in_roundend = create_team //tutorial scarabs begone
|
||||
. = L.mind.add_antag_datum(C)
|
||||
|
||||
/proc/remove_servant_of_ratvar(mob/L, silent = FALSE)
|
||||
if(!L || !L.mind)
|
||||
@@ -88,7 +91,6 @@ Credit where due:
|
||||
///////////////
|
||||
|
||||
/datum/game_mode
|
||||
var/datum/mind/eminence //The clockwork Eminence
|
||||
var/list/servants_of_ratvar = list() //The Enlightened servants of Ratvar
|
||||
var/clockwork_explanation = "Defend the Ark of the Clockwork Justiciar and free Ratvar." //The description of the current objective
|
||||
|
||||
@@ -111,6 +113,8 @@ Credit where due:
|
||||
var/roundstart_player_count
|
||||
var/ark_time //In minutes, how long the Ark waits before activation; this is equal to 30 + (number of players / 5) (max 40 mins.)
|
||||
|
||||
var/datum/team/clockcult/main_clockcult
|
||||
|
||||
/datum/game_mode/clockwork_cult/pre_setup()
|
||||
if(CONFIG_GET(flag/protect_roles_from_antagonist))
|
||||
restricted_jobs += protected_jobs
|
||||
@@ -185,22 +189,21 @@ Credit where due:
|
||||
return FALSE
|
||||
|
||||
/datum/game_mode/clockwork_cult/check_finished()
|
||||
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
|
||||
if(G && !GLOB.ratvar_awakens) // Doesn't end until the Ark is destroyed or completed
|
||||
if(GLOB.ark_of_the_clockwork_justiciar && !GLOB.ratvar_awakens) // Doesn't end until the Ark is destroyed or completed
|
||||
return FALSE
|
||||
. = ..()
|
||||
return ..()
|
||||
|
||||
/datum/game_mode/clockwork_cult/proc/check_clockwork_victory()
|
||||
return main_clockcult.check_clockwork_victory()
|
||||
|
||||
/datum/game_mode/clock_cult/set_round_result()
|
||||
..()
|
||||
if(GLOB.clockwork_gateway_activated)
|
||||
SSticker.news_report = CLOCK_SUMMON
|
||||
return TRUE
|
||||
SSticker.mode_result = "win - servants completed their objective (summon ratvar)"
|
||||
else
|
||||
SSticker.news_report = CULT_FAILURE
|
||||
return FALSE
|
||||
|
||||
/datum/game_mode/clockwork_cult/declare_completion()
|
||||
..()
|
||||
return //Doesn't end until the round does
|
||||
SSticker.mode_result = "loss - servants failed their objective (summon ratvar)"
|
||||
|
||||
/datum/game_mode/clockwork_cult/generate_report()
|
||||
return "Bluespace monitors near your sector have detected a continuous stream of patterned fluctuations since the station was completed. It is most probable that a powerful entity \
|
||||
@@ -210,30 +213,6 @@ Credit where due:
|
||||
working for this entity and utilizing highly-advanced technology to cross the great distance at will. If they should turn out to be a credible threat, the task falls on you and \
|
||||
your crew to dispatch it in a timely manner."
|
||||
|
||||
/datum/game_mode/proc/auto_declare_completion_clockwork_cult()
|
||||
var/text = ""
|
||||
if(istype(SSticker.mode, /datum/game_mode/clockwork_cult)) //Possibly hacky?
|
||||
var/datum/game_mode/clockwork_cult/C = SSticker.mode
|
||||
if(C.check_clockwork_victory())
|
||||
text += "<span class='bold large_brass'>Ratvar's servants defended the Ark until its activation!</span>"
|
||||
SSticker.mode_result = "win - servants completed their objective (summon ratvar)"
|
||||
else
|
||||
text += "<span class='userdanger'>The Ark was destroyed! Ratvar will rust away for all eternity!</span>"
|
||||
SSticker.mode_result = "loss - servants failed their objective (summon ratvar)"
|
||||
text += "<br><b>The servants' objective was:</b> [CLOCKCULT_OBJECTIVE]."
|
||||
text += "<br>Ratvar's servants had <b>[GLOB.clockwork_caches]</b> Tinkerer's Caches."
|
||||
text += "<br><b>Construction Value(CV)</b> was: <b>[GLOB.clockwork_construction_value]</b>"
|
||||
for(var/i in SSticker.scripture_states)
|
||||
if(i != SCRIPTURE_DRIVER)
|
||||
text += "<br><b>[i] scripture</b> was: <b>[SSticker.scripture_states[i] ? "UN":""]LOCKED</b>"
|
||||
if(SSticker.mode.eminence)
|
||||
text += "<br><b>The Eminence was:</b> [printplayer(SSticker.mode.eminence)]"
|
||||
if(servants_of_ratvar.len)
|
||||
text += "<br><b>Ratvar's servants were:</b>"
|
||||
for(var/datum/mind/M in servants_of_ratvar - SSticker.mode.eminence)
|
||||
text += printplayer(M)
|
||||
to_chat(world, text)
|
||||
|
||||
/datum/game_mode/proc/update_servant_icons_added(datum/mind/M)
|
||||
var/datum/atom_hud/antag/A = GLOB.huds[ANTAG_HUD_CLOCKWORK]
|
||||
A.join_hud(M.current)
|
||||
|
||||
@@ -207,7 +207,7 @@
|
||||
to_chat(cyborg, "<span class='brass'>You start to charge from the [sigil_name]...</span>")
|
||||
if(!do_after(cyborg, 50, target = src, extra_checks = CALLBACK(src, .proc/cyborg_checks, cyborg, TRUE)))
|
||||
return
|
||||
var/giving_power = min(Floor(cyborg.cell.maxcharge - cyborg.cell.charge, MIN_CLOCKCULT_POWER), get_clockwork_power()) //give the borg either all our power or their missing power floored to MIN_CLOCKCULT_POWER
|
||||
var/giving_power = min(FLOOR(cyborg.cell.maxcharge - cyborg.cell.charge, MIN_CLOCKCULT_POWER), get_clockwork_power()) //give the borg either all our power or their missing power floored to MIN_CLOCKCULT_POWER
|
||||
if(adjust_clockwork_power(-giving_power))
|
||||
cyborg.visible_message("<span class='warning'>[cyborg] glows a brilliant orange!</span>")
|
||||
var/previous_color = cyborg.color
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
if(amount_temp < 2)
|
||||
to_chat(user, "<span class='warning'>You need at least <b>2</b> floor tiles to convert into power.</span>")
|
||||
return TRUE
|
||||
if(IsOdd(amount_temp))
|
||||
if(ISODD(amount_temp))
|
||||
amount_temp--
|
||||
no_delete = TRUE
|
||||
use(amount_temp)
|
||||
@@ -239,7 +239,7 @@
|
||||
if(!do_after(user, repair_values["healing_for_cycle"] * fabricator.speed_multiplier, target = src, \
|
||||
extra_checks = CALLBACK(fabricator, /obj/item/clockwork/replica_fabricator.proc/fabricator_repair_checks, repair_values, src, user, TRUE)))
|
||||
break
|
||||
obj_integrity = Clamp(obj_integrity + repair_values["healing_for_cycle"], 0, max_integrity)
|
||||
obj_integrity = CLAMP(obj_integrity + repair_values["healing_for_cycle"], 0, max_integrity)
|
||||
adjust_clockwork_power(-repair_values["power_required"])
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
|
||||
|
||||
@@ -91,7 +91,8 @@
|
||||
|
||||
/obj/item/clockwork/construct_chassis/cogscarab/pre_spawn()
|
||||
if(infinite_resources)
|
||||
construct_type = /mob/living/simple_animal/drone/cogscarab/ratvar //During rounds where they can't interact with the station, let them experiment with builds
|
||||
//During rounds where they can't interact with the station, let them experiment with builds
|
||||
construct_type = /mob/living/simple_animal/drone/cogscarab/ratvar
|
||||
|
||||
/obj/item/clockwork/construct_chassis/cogscarab/post_spawn(mob/living/construct)
|
||||
if(infinite_resources) //Allow them to build stuff and recite scripture
|
||||
|
||||
@@ -14,16 +14,6 @@
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
var/static/superheated_walls = 0
|
||||
|
||||
/mob/camera/eminence/Initialize()
|
||||
if(SSticker.mode.eminence)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
. = ..()
|
||||
|
||||
/mob/camera/eminence/Destroy(force)
|
||||
if(!force && mind && SSticker.mode.eminence == mind)
|
||||
return QDEL_HINT_LETMELIVE
|
||||
return ..()
|
||||
|
||||
/mob/camera/eminence/CanPass(atom/movable/mover, turf/target)
|
||||
return TRUE
|
||||
|
||||
@@ -39,12 +29,20 @@
|
||||
|
||||
/mob/camera/eminence/Login()
|
||||
..()
|
||||
add_servant_of_ratvar(src, TRUE)
|
||||
var/datum/antagonist/clockcult/C = mind.has_antag_datum(/datum/antagonist/clockcult,TRUE)
|
||||
if(!C)
|
||||
add_servant_of_ratvar(src, TRUE)
|
||||
C = mind.has_antag_datum(/datum/antagonist/clockcult,TRUE)
|
||||
if(C && C.clock_team)
|
||||
if(C.clock_team.eminence)
|
||||
remove_servant_of_ratvar(src,TRUE)
|
||||
qdel(src)
|
||||
else
|
||||
C.clock_team.eminence = src
|
||||
to_chat(src, "<span class='bold large_brass'>You have been selected as the Eminence!</span>")
|
||||
to_chat(src, "<span class='brass'>As the Eminence, you lead the servants. Anything you say will be heard by the entire cult.</span>")
|
||||
to_chat(src, "<span class='brass'>Though you can move through walls, you're also incorporeal, and largely can't interact with the world except for a few ways.</span>")
|
||||
to_chat(src, "<span class='brass'>Additionally, unless the herald's beacon is activated, you can't understand any speech while away from Reebe.</span>")
|
||||
SSticker.mode.eminence = mind
|
||||
eminence_help()
|
||||
for(var/V in actions)
|
||||
var/datum/action/A = V
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
if(ishuman(M.current))
|
||||
human_servants++
|
||||
construct_limit = human_servants / 4 //1 per 4 human servants, and a maximum of 3 marauders
|
||||
construct_limit = Clamp(construct_limit, 1, 3)
|
||||
construct_limit = CLAMP(construct_limit, 1, 3)
|
||||
|
||||
/datum/clockwork_scripture/create_object/construct/clockwork_marauder/pre_recital()
|
||||
channel_time = initial(channel_time)
|
||||
|
||||
@@ -17,7 +17,11 @@
|
||||
return
|
||||
if(kingmaking)
|
||||
return
|
||||
if(SSticker.mode.eminence)
|
||||
|
||||
var/datum/antagonist/clockcult/C = user.mind.has_antag_datum(/datum/antagonist/clockcult)
|
||||
if(!C || !C.clock_team)
|
||||
return
|
||||
if(C.clock_team.eminence)
|
||||
to_chat(user, "<span class='warning'>There's already an Eminence!</span>")
|
||||
return
|
||||
if(!GLOB.servants_active)
|
||||
@@ -34,7 +38,9 @@
|
||||
/obj/structure/destructible/clockwork/eminence_spire/attack_ghost(mob/user)
|
||||
if(!IsAdminGhost(user))
|
||||
return
|
||||
if(SSticker.mode.eminence)
|
||||
|
||||
var/datum/antagonist/clockcult/random_cultist = locate() in GLOB.antagonists //if theres no cultists new team without eminence will be created anyway.
|
||||
if(random_cultist && random_cultist.clock_team && random_cultist.clock_team.eminence)
|
||||
to_chat(user, "<span class='warning'>There's already an Eminence - too late!</span>")
|
||||
return
|
||||
if(!GLOB.servants_active)
|
||||
|
||||
@@ -60,4 +60,4 @@
|
||||
break
|
||||
if(!M)
|
||||
M = H.apply_status_effect(STATUS_EFFECT_MANIAMOTOR, src)
|
||||
M.severity = Clamp(M.severity + ((11 - get_dist(src, H)) * efficiency * efficiency), 0, MAX_MANIA_SEVERITY)
|
||||
M.severity = CLAMP(M.severity + ((11 - get_dist(src, H)) * efficiency * efficiency), 0, MAX_MANIA_SEVERITY)
|
||||
|
||||
@@ -57,5 +57,5 @@
|
||||
L.confused = min(L.confused + 15, 50)
|
||||
L.dizziness = min(L.dizziness + 15, 50)
|
||||
if(L.confused >= 25)
|
||||
L.Knockdown(Floor(L.confused * 0.8))
|
||||
L.Knockdown(FLOOR(L.confused * 0.8, 1))
|
||||
take_damage(max_integrity)
|
||||
|
||||
@@ -2,24 +2,23 @@
|
||||
|
||||
/datum/game_mode
|
||||
var/list/datum/mind/cult = list()
|
||||
var/list/cult_objectives = list()
|
||||
var/eldergod = 1 //for the summon god objective
|
||||
|
||||
/proc/iscultist(mob/living/M)
|
||||
return istype(M) && M.mind && M.mind.has_antag_datum(ANTAG_DATUM_CULT)
|
||||
|
||||
/proc/is_sacrifice_target(datum/mind/mind)
|
||||
if(mind == GLOB.sac_mind)
|
||||
return TRUE
|
||||
/datum/team/cult/proc/is_sacrifice_target(datum/mind/mind)
|
||||
for(var/datum/objective/sacrifice/sac_objective in objectives)
|
||||
if(mind == sac_objective.target)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/proc/is_convertable_to_cult(mob/living/M)
|
||||
/proc/is_convertable_to_cult(mob/living/M,datum/team/cult/specific_cult)
|
||||
if(!istype(M))
|
||||
return FALSE
|
||||
if(M.mind)
|
||||
if(ishuman(M) && (M.mind.assigned_role in list("Captain", "Chaplain")))
|
||||
return FALSE
|
||||
if(is_sacrifice_target(M.mind))
|
||||
if(specific_cult && specific_cult.is_sacrifice_target(M.mind))
|
||||
return FALSE
|
||||
if(M.mind.enslaved_to && !iscultist(M.mind.enslaved_to))
|
||||
return FALSE
|
||||
@@ -55,10 +54,10 @@
|
||||
|
||||
var/list/cultists_to_cult = list() //the cultists we'll convert
|
||||
|
||||
var/datum/team/cult/main_cult
|
||||
|
||||
|
||||
/datum/game_mode/cult/pre_setup()
|
||||
cult_objectives += "sacrifice"
|
||||
|
||||
if(CONFIG_GET(flag/protect_roles_from_antagonist))
|
||||
restricted_jobs += protected_jobs
|
||||
|
||||
@@ -86,82 +85,19 @@
|
||||
|
||||
|
||||
/datum/game_mode/cult/post_setup()
|
||||
if("sacrifice" in cult_objectives)
|
||||
var/list/possible_targets = get_unconvertables()
|
||||
if(!possible_targets.len)
|
||||
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 in cultists_to_cult))
|
||||
possible_targets += player.mind
|
||||
if(possible_targets.len > 0)
|
||||
GLOB.sac_mind = pick(possible_targets)
|
||||
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!")
|
||||
if(!GLOB.summon_spots.len)
|
||||
while(GLOB.summon_spots.len < SUMMON_POSSIBILITIES)
|
||||
var/area/summon = pick(GLOB.sortedAreas - GLOB.summon_spots)
|
||||
if((summon.z in GLOB.station_z_levels) && summon.valid_territory)
|
||||
GLOB.summon_spots += summon
|
||||
cult_objectives += "eldergod"
|
||||
|
||||
for(var/datum/mind/cult_mind in cultists_to_cult)
|
||||
equip_cultist(cult_mind.current)
|
||||
update_cult_icons_added(cult_mind)
|
||||
to_chat(cult_mind.current, "<span class='userdanger'>You are a member of the cult!</span>")
|
||||
cult_mind.current.playsound_local(get_turf(cult_mind.current), 'sound/ambience/antag/bloodcult.ogg', 100, FALSE, pressure_affected = FALSE)//subject to change
|
||||
add_cultist(cult_mind, 0)
|
||||
add_cultist(cult_mind, 0, equip=TRUE)
|
||||
..()
|
||||
|
||||
/datum/game_mode/proc/equip_cultist(mob/living/carbon/human/mob,tome = 0)
|
||||
if(!istype(mob))
|
||||
return
|
||||
if (mob.mind)
|
||||
if (mob.mind.assigned_role == "Clown")
|
||||
to_chat(mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
|
||||
mob.dna.remove_mutation(CLOWNMUT)
|
||||
|
||||
if(tome)
|
||||
. += cult_give_item(/obj/item/tome, mob)
|
||||
else
|
||||
. += cult_give_item(/obj/item/paper/talisman/supply, mob)
|
||||
to_chat(mob, "These will help you start the cult on this station. Use them well, and remember - you are not the only one.</span>")
|
||||
|
||||
/datum/game_mode/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/game_mode/proc/add_cultist(datum/mind/cult_mind, stun) //BASE
|
||||
/datum/game_mode/proc/add_cultist(datum/mind/cult_mind, stun , equip = FALSE) //BASE
|
||||
if (!istype(cult_mind))
|
||||
return 0
|
||||
if(cult_mind.add_antag_datum(ANTAG_DATUM_CULT))
|
||||
|
||||
var/datum/antagonist/cult/new_cultist = new(cult_mind)
|
||||
new_cultist.give_equipment = equip
|
||||
|
||||
if(cult_mind.add_antag_datum(new_cultist))
|
||||
if(stun)
|
||||
cult_mind.current.Unconscious(100)
|
||||
return 1
|
||||
@@ -187,25 +123,19 @@
|
||||
culthud.leave_hud(cult_mind.current)
|
||||
set_antag_hud(cult_mind.current, null)
|
||||
|
||||
/datum/game_mode/cult/proc/get_unconvertables()
|
||||
var/list/ucs = list()
|
||||
for(var/mob/living/carbon/human/player in GLOB.player_list)
|
||||
if(player.mind && !is_convertable_to_cult(player) && !(player.mind in cultists_to_cult))
|
||||
ucs += player.mind
|
||||
return ucs
|
||||
|
||||
/datum/game_mode/cult/proc/check_cult_victory()
|
||||
var/cult_fail = 0
|
||||
if(cult_objectives.Find("survive"))
|
||||
cult_fail += check_survive() //the proc returns 1 if there are not enough cultists on the shuttle, 0 otherwise
|
||||
if(cult_objectives.Find("eldergod"))
|
||||
cult_fail += eldergod //1 by default, 0 if the elder god has been summoned at least once
|
||||
if(cult_objectives.Find("sacrifice"))
|
||||
if(GLOB.sac_mind && !GLOB.sac_complete) //if the target has been GLOB.sacrificed, ignore this step. otherwise, add 1 to cult_fail
|
||||
cult_fail++
|
||||
return cult_fail //if any objectives aren't met, failure
|
||||
return main_cult.check_cult_victory()
|
||||
|
||||
|
||||
/datum/game_mode/cult/set_round_result()
|
||||
..()
|
||||
if(check_cult_victory())
|
||||
SSticker.mode_result = "win - cult win"
|
||||
SSticker.news_report = CULT_SUMMON
|
||||
else
|
||||
SSticker.mode_result = "loss - staff stopped the cult"
|
||||
SSticker.news_report = CULT_FAILURE
|
||||
|
||||
/datum/game_mode/cult/proc/check_survive()
|
||||
var/acolytes_survived = 0
|
||||
for(var/datum/mind/cult_mind in cult)
|
||||
@@ -218,57 +148,6 @@
|
||||
return 1
|
||||
|
||||
|
||||
/datum/game_mode/cult/declare_completion()
|
||||
|
||||
if(!check_cult_victory())
|
||||
SSticker.mode_result = "win - cult win"
|
||||
to_chat(world, "<span class='greentext'>The cult has succeeded! Nar-sie has snuffed out another torch in the void!</span>")
|
||||
else
|
||||
SSticker.mode_result = "loss - staff stopped the cult"
|
||||
to_chat(world, "<span class='redtext'>The staff managed to stop the cult! Dark words and heresy are no match for Nanotrasen's finest!</span>")
|
||||
|
||||
var/text = ""
|
||||
|
||||
if(cult_objectives.len)
|
||||
text += "<br><b>The cultists' objectives were:</b>"
|
||||
for(var/obj_count=1, obj_count <= cult_objectives.len, obj_count++)
|
||||
var/explanation
|
||||
switch(cult_objectives[obj_count])
|
||||
if("survive")
|
||||
if(!check_survive())
|
||||
explanation = "Make sure at least [acolytes_needed] acolytes escape on the shuttle. ([acolytes_survived] escaped) <span class='greenannounce'>Success!</span>"
|
||||
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_survive", "SUCCESS"))
|
||||
SSticker.news_report = CULT_ESCAPE
|
||||
else
|
||||
explanation = "Make sure at least [acolytes_needed] acolytes escape on the shuttle. ([acolytes_survived] escaped) <span class='boldannounce'>Fail.</span>"
|
||||
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_survive", "FAIL"))
|
||||
SSticker.news_report = CULT_FAILURE
|
||||
if("sacrifice")
|
||||
if(GLOB.sac_complete)
|
||||
explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role]. <span class='greenannounce'>Success!</span>"
|
||||
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_sacrifice", "SUCCESS"))
|
||||
else
|
||||
explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role]. <span class='boldannounce'>Fail.</span>"
|
||||
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_sacrifice", "FAIL"))
|
||||
if("eldergod")
|
||||
if(!eldergod)
|
||||
explanation = "Summon Nar-Sie. The summoning can only be accomplished in [english_list(GLOB.summon_spots)].<span class='greenannounce'>Success!</span>"
|
||||
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_narsie", "SUCCESS"))
|
||||
SSticker.news_report = CULT_SUMMON
|
||||
else
|
||||
explanation = "Summon Nar-Sie. The summoning can only be accomplished in [english_list(GLOB.summon_spots)]<span class='boldannounce'>Fail.</span>"
|
||||
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_narsie", "FAIL"))
|
||||
SSticker.news_report = CULT_FAILURE
|
||||
|
||||
text += "<br><B>Objective #[obj_count]</B>: [explanation]"
|
||||
if(cult.len)
|
||||
text += "<br><b>The cultists were:</b>"
|
||||
for(var/datum/mind/M in cult)
|
||||
text += printplayer(M)
|
||||
to_chat(world, text)
|
||||
..()
|
||||
return 1
|
||||
|
||||
/datum/game_mode/cult/generate_report()
|
||||
return "Some stations in your sector have reported evidence of blood sacrifice and strange magic. Ties to the Wizards' Federation have been proven not to exist, and many employees \
|
||||
have disappeared; even Central Command employees light-years away have felt strange presences and at times hysterical compulsions. Interrogations point towards this being the work of \
|
||||
@@ -276,41 +155,4 @@
|
||||
devoted to stopping this cult. Note that holy water seems to weaken and eventually return the minds of cultists that ingest it, and mindshield implants will prevent conversion \
|
||||
altogether."
|
||||
|
||||
/datum/game_mode/proc/datum_cult_completion()
|
||||
var/text = ""
|
||||
var/cult_fail = 0
|
||||
cult_fail += eldergod
|
||||
if(!GLOB.sac_complete)
|
||||
cult_fail++
|
||||
if(!cult_fail)
|
||||
SSticker.mode_result = "win - cult win"
|
||||
to_chat(world, "<span class='greentext'>The cult has succeeded! Nar-sie has snuffed out another torch in the void!</span>")
|
||||
else
|
||||
SSticker.mode_result = "loss - staff stopped the cult"
|
||||
to_chat(world, "<span class='redtext'>The staff managed to stop the cult! Dark words and heresy are no match for Nanotrasen's finest!</span>")
|
||||
if(cult_objectives.len)
|
||||
text += "<br><b>The cultists' objectives were:</b>"
|
||||
for(var/obj_count in 1 to 2)
|
||||
var/explanation
|
||||
switch(cult_objectives[obj_count])
|
||||
if("sacrifice")
|
||||
if(GLOB.sac_mind)
|
||||
if(GLOB.sac_complete)
|
||||
explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role]. <span class='greenannounce'>Success!</span>"
|
||||
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_sacrifice", "SUCCESS"))
|
||||
else
|
||||
explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role]. <span class='boldannounce'>Fail.</span>"
|
||||
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_sacrifice", "FAIL"))
|
||||
if("eldergod")
|
||||
if(!eldergod)
|
||||
explanation = "Summon Nar-Sie. <span class='greenannounce'>Success!</span>"
|
||||
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_narsie", "SUCCESS"))
|
||||
SSticker.news_report = CULT_SUMMON
|
||||
else
|
||||
explanation = "Summon Nar-Sie. <span class='boldannounce'>Fail.</span>"
|
||||
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_narsie", "FAIL"))
|
||||
SSticker.news_report = CULT_FAILURE
|
||||
text += "<br><B>Objective #[obj_count]</B>: [explanation]"
|
||||
to_chat(world, text)
|
||||
|
||||
#undef CULT_SCALING_COEFFICIENT
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
user.whisper("O bidai nabora se[pick("'","`")]sma!", language = /datum/language/common)
|
||||
user.whisper(html_decode(message))
|
||||
var/title = "Acolyte"
|
||||
var/span = "cultitalic"
|
||||
var/span = "cult italic"
|
||||
if(user.mind && user.mind.has_antag_datum(ANTAG_DATUM_CULT_MASTER))
|
||||
span = "cultlarge"
|
||||
if(ishuman(user))
|
||||
@@ -88,19 +88,21 @@
|
||||
button_icon_state = "cultvote"
|
||||
|
||||
/datum/action/innate/cult/mastervote/IsAvailable()
|
||||
if(GLOB.cult_vote_called || !ishuman(owner))
|
||||
var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
|
||||
if(!C || C.cult_team.cult_vote_called || !ishuman(owner))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/cult/mastervote/Activate()
|
||||
pollCultists(owner)
|
||||
var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
|
||||
pollCultists(owner,C.cult_team)
|
||||
|
||||
/proc/pollCultists(var/mob/living/Nominee) //Cult Master Poll
|
||||
/proc/pollCultists(var/mob/living/Nominee,datum/team/cult/team) //Cult Master Poll
|
||||
if(world.time < CULT_POLL_WAIT)
|
||||
to_chat(Nominee, "It would be premature to select a leader while everyone is still settling in, try again in [DisplayTimeText(CULT_POLL_WAIT-world.time)].")
|
||||
return
|
||||
GLOB.cult_vote_called = TRUE //somebody's trying to be a master, make sure we don't let anyone else try
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
team.cult_vote_called = TRUE //somebody's trying to be a master, make sure we don't let anyone else try
|
||||
for(var/datum/mind/B in team.members)
|
||||
if(B.current)
|
||||
B.current.update_action_buttons_icon()
|
||||
if(!B.current.incapacitated())
|
||||
@@ -108,39 +110,39 @@
|
||||
to_chat(B.current, "<span class='cultlarge'>Acolyte [Nominee] has asserted that they are worthy of leading the cult. A vote will be called shortly.</span>")
|
||||
sleep(100)
|
||||
var/list/asked_cultists = list()
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
for(var/datum/mind/B in team.members)
|
||||
if(B.current && B.current != Nominee && !B.current.incapacitated())
|
||||
SEND_SOUND(B.current, 'sound/magic/exit_blood.ogg')
|
||||
asked_cultists += B.current
|
||||
var/list/yes_voters = pollCandidates("[Nominee] seeks to lead your cult, do you support [Nominee.p_them()]?", poll_time = 300, group = asked_cultists)
|
||||
if(QDELETED(Nominee) || Nominee.incapacitated())
|
||||
GLOB.cult_vote_called = FALSE
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
team.cult_vote_called = FALSE
|
||||
for(var/datum/mind/B in team.members)
|
||||
if(B.current)
|
||||
B.current.update_action_buttons_icon()
|
||||
if(!B.current.incapacitated())
|
||||
to_chat(B.current,"<span class='cultlarge'>[Nominee] has died in the process of attempting to win the cult's support!</span>")
|
||||
return FALSE
|
||||
if(!Nominee.mind)
|
||||
GLOB.cult_vote_called = FALSE
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
team.cult_vote_called = FALSE
|
||||
for(var/datum/mind/B in team.members)
|
||||
if(B.current)
|
||||
B.current.update_action_buttons_icon()
|
||||
if(!B.current.incapacitated())
|
||||
to_chat(B.current,"<span class='cultlarge'>[Nominee] has gone catatonic in the process of attempting to win the cult's support!</span>")
|
||||
return FALSE
|
||||
if(LAZYLEN(yes_voters) <= LAZYLEN(asked_cultists) * 0.5)
|
||||
GLOB.cult_vote_called = FALSE
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
team.cult_vote_called = FALSE
|
||||
for(var/datum/mind/B in team.members)
|
||||
if(B.current)
|
||||
B.current.update_action_buttons_icon()
|
||||
if(!B.current.incapacitated())
|
||||
to_chat(B.current, "<span class='cultlarge'>[Nominee] could not win the cult's support and shall continue to serve as an acolyte.</span>")
|
||||
return FALSE
|
||||
GLOB.cult_mastered = TRUE
|
||||
team.cult_mastered = TRUE
|
||||
SSticker.mode.remove_cultist(Nominee.mind, TRUE)
|
||||
Nominee.mind.add_antag_datum(ANTAG_DATUM_CULT_MASTER)
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
for(var/datum/mind/B in team.members)
|
||||
if(B.current)
|
||||
for(var/datum/action/innate/cult/mastervote/vote in B.current.actions)
|
||||
vote.Remove(B.current)
|
||||
@@ -159,6 +161,9 @@
|
||||
button_icon_state = "sintouch"
|
||||
|
||||
/datum/action/innate/cult/master/finalreck/Activate()
|
||||
var/datum/antagonist/cult/antag = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
|
||||
if(!antag)
|
||||
return
|
||||
for(var/i in 1 to 4)
|
||||
chant(i)
|
||||
var/list/destinations = list()
|
||||
@@ -169,7 +174,7 @@
|
||||
to_chat(owner, "<span class='warning'>You need more space to summon the cult!</span>")
|
||||
return
|
||||
if(do_after(owner, 30, target = owner))
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
for(var/datum/mind/B in antag.cult_team.members)
|
||||
if(B.current && B.current.stat != DEAD)
|
||||
var/turf/mobloc = get_turf(B.current)
|
||||
switch(i)
|
||||
@@ -194,7 +199,7 @@
|
||||
addtimer(CALLBACK(B.current, /mob/.proc/reckon, final), 10)
|
||||
else
|
||||
return
|
||||
GLOB.reckoning_complete = TRUE
|
||||
antag.cult_team.reckoning_complete = TRUE
|
||||
Remove(owner)
|
||||
|
||||
/mob/proc/reckon(turf/final)
|
||||
@@ -269,34 +274,37 @@
|
||||
var/turf/T = get_turf(ranged_ability_user)
|
||||
if(!isturf(T))
|
||||
return FALSE
|
||||
|
||||
var/datum/antagonist/cult/C = caller.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
|
||||
|
||||
if(target in view(7, get_turf(ranged_ability_user)))
|
||||
GLOB.blood_target = target
|
||||
C.cult_team.blood_target = target
|
||||
var/area/A = get_area(target)
|
||||
attached_action.cooldown = world.time + attached_action.base_cooldown
|
||||
addtimer(CALLBACK(attached_action.owner, /mob.proc/update_action_buttons_icon), attached_action.base_cooldown)
|
||||
GLOB.blood_target_image = image('icons/effects/cult_target.dmi', target, "glow", ABOVE_MOB_LAYER)
|
||||
GLOB.blood_target_image.appearance_flags = RESET_COLOR
|
||||
GLOB.blood_target_image.pixel_x = -target.pixel_x
|
||||
GLOB.blood_target_image.pixel_y = -target.pixel_y
|
||||
C.cult_team.blood_target_image = image('icons/effects/cult_target.dmi', target, "glow", ABOVE_MOB_LAYER)
|
||||
C.cult_team.blood_target_image.appearance_flags = RESET_COLOR
|
||||
C.cult_team.blood_target_image.pixel_x = -target.pixel_x
|
||||
C.cult_team.blood_target_image.pixel_y = -target.pixel_y
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
if(B.current && B.current.stat != DEAD && B.current.client)
|
||||
to_chat(B.current, "<span class='cultlarge'><b>Master [ranged_ability_user] has marked [GLOB.blood_target] in the [A.name] as the cult's top priority, get there immediately!</b></span>")
|
||||
to_chat(B.current, "<span class='cultlarge'><b>Master [ranged_ability_user] has marked [C.cult_team.blood_target] in the [A.name] as the cult's top priority, get there immediately!</b></span>")
|
||||
SEND_SOUND(B.current, sound(pick('sound/hallucinations/over_here2.ogg','sound/hallucinations/over_here3.ogg'),0,1,75))
|
||||
B.current.client.images += GLOB.blood_target_image
|
||||
B.current.client.images += C.cult_team.blood_target_image
|
||||
attached_action.owner.update_action_buttons_icon()
|
||||
remove_ranged_ability("<span class='cult'>The marking rite is complete! It will last for 90 seconds.</span>")
|
||||
GLOB.blood_target_reset_timer = addtimer(CALLBACK(GLOBAL_PROC, .proc/reset_blood_target), 900, TIMER_STOPPABLE)
|
||||
C.cult_team.blood_target_reset_timer = addtimer(CALLBACK(GLOBAL_PROC, .proc/reset_blood_target,C.cult_team), 900, TIMER_STOPPABLE)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/proc/reset_blood_target()
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
/proc/reset_blood_target(datum/team/cult/team)
|
||||
for(var/datum/mind/B in team.members)
|
||||
if(B.current && B.current.stat != DEAD && B.current.client)
|
||||
if(GLOB.blood_target)
|
||||
if(team.blood_target)
|
||||
to_chat(B.current,"<span class='cultlarge'><b>The blood mark has expired!</b></span>")
|
||||
B.current.client.images -= GLOB.blood_target_image
|
||||
QDEL_NULL(GLOB.blood_target_image)
|
||||
GLOB.blood_target = null
|
||||
B.current.client.images -= team.blood_target_image
|
||||
QDEL_NULL(team.blood_target_image)
|
||||
team.blood_target = null
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -179,6 +179,13 @@ This file contains the arcane tome files.
|
||||
var/list/shields = list()
|
||||
var/area/A = get_area(src)
|
||||
|
||||
var/datum/antagonist/cult/user_antag = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
|
||||
if(!user_antag)
|
||||
return
|
||||
|
||||
var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives
|
||||
var/datum/objective/sacrifice/sac_objective = locate() in user_antag.cult_team.objectives
|
||||
|
||||
if(!check_rune_turf(Turf, user))
|
||||
return
|
||||
entered_rune_name = input(user, "Choose a rite to scribe.", "Sigils of Power") as null|anything in GLOB.rune_types
|
||||
@@ -196,18 +203,20 @@ This file contains the arcane tome files.
|
||||
A = get_area(src)
|
||||
if(!src || QDELETED(src) || !Adjacent(user) || user.incapacitated() || !check_rune_turf(Turf, user))
|
||||
return
|
||||
|
||||
//AAAAAAAAAAAAAAAH, i'm rewriting enough for now so TODO: remove this shit
|
||||
if(ispath(rune_to_scribe, /obj/effect/rune/narsie))
|
||||
if(!("eldergod" in SSticker.mode.cult_objectives))
|
||||
if(!summon_objective)
|
||||
to_chat(user, "<span class='warning'>Nar-Sie does not wish to be summoned!</span>")
|
||||
return
|
||||
if(!GLOB.sac_complete)
|
||||
if(sac_objective && !sac_objective.check_completion())
|
||||
to_chat(user, "<span class='warning'>The sacrifice is not complete. The portal would lack the power to open if you tried!</span>")
|
||||
return
|
||||
if(!SSticker.mode.eldergod)
|
||||
if(summon_objective.check_completion())
|
||||
to_chat(user, "<span class='cultlarge'>\"I am already here. There is no need to try to summon me now.\"</span>")
|
||||
return
|
||||
if(!(A in GLOB.summon_spots))
|
||||
to_chat(user, "<span class='cultlarge'>The Geometer can only be summoned where the veil is weak - in [english_list(GLOB.summon_spots)]!</span>")
|
||||
if(!(A in summon_objective.summon_spots))
|
||||
to_chat(user, "<span class='cultlarge'>The Geometer can only be summoned where the veil is weak - in [english_list(summon_objective.summon_spots)]!</span>")
|
||||
return
|
||||
var/confirm_final = alert(user, "This is the FINAL step to summon Nar-Sie; it is a long, painful ritual and the crew will be alerted to your presence", "Are you prepared for the final battle?", "My life for Nar-Sie!", "No")
|
||||
if(confirm_final == "No")
|
||||
@@ -215,8 +224,8 @@ This file contains the arcane tome files.
|
||||
return
|
||||
Turf = get_turf(user)
|
||||
A = get_area(src)
|
||||
if(!(A in GLOB.summon_spots)) // Check again to make sure they didn't move
|
||||
to_chat(user, "<span class='cultlarge'>The Geometer can only be summoned where the veil is weak - in [english_list(GLOB.summon_spots)]!</span>")
|
||||
if(!(A in summon_objective.summon_spots)) // Check again to make sure they didn't move
|
||||
to_chat(user, "<span class='cultlarge'>The Geometer can only be summoned where the veil is weak - in [english_list(summon_objective.summon_spots)]!</span>")
|
||||
return
|
||||
priority_announce("Figments from an eldritch god are being summoned by [user] into [A.map_name] from an unknown dimension. Disrupt the ritual at all costs!","Central Command Higher Dimensional Affairs", 'sound/ai/spanomalies.ogg')
|
||||
for(var/B in spiral_range_turfs(1, user, 1))
|
||||
|
||||
@@ -349,7 +349,11 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
color = RUNE_COLOR_DARKRED
|
||||
var/mob/living/L = pick(myriad_targets)
|
||||
var/is_clock = is_servant_of_ratvar(L)
|
||||
var/is_convertable = is_convertable_to_cult(L)
|
||||
|
||||
var/mob/living/F = invokers[1]
|
||||
var/datum/antagonist/cult/C = F.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
|
||||
|
||||
var/is_convertable = is_convertable_to_cult(L,C.cult_team)
|
||||
if(L.stat != DEAD && (is_clock || is_convertable))
|
||||
invocation = "Mah'weyh pleggh at e'ntrath!"
|
||||
..()
|
||||
@@ -397,17 +401,27 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
return 1
|
||||
|
||||
/obj/effect/rune/convert/proc/do_sacrifice(mob/living/sacrificial, list/invokers)
|
||||
var/mob/living/first_invoker = invokers[1]
|
||||
if(!first_invoker)
|
||||
return FALSE
|
||||
var/datum/antagonist/cult/C = first_invoker.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
|
||||
if(!C)
|
||||
return
|
||||
|
||||
|
||||
var/big_sac = FALSE
|
||||
if((((ishuman(sacrificial) || iscyborg(sacrificial)) && sacrificial.stat != DEAD) || is_sacrifice_target(sacrificial.mind)) && invokers.len < 3)
|
||||
if((((ishuman(sacrificial) || iscyborg(sacrificial)) && sacrificial.stat != DEAD) || C.cult_team.is_sacrifice_target(sacrificial.mind)) && invokers.len < 3)
|
||||
for(var/M in invokers)
|
||||
to_chat(M, "<span class='cultitalic'>[sacrificial] is too greatly linked to the world! You need three acolytes!</span>")
|
||||
log_game("Offer rune failed - not enough acolytes and target is living or sac target")
|
||||
return FALSE
|
||||
if(sacrificial.mind)
|
||||
GLOB.sacrificed += sacrificial.mind
|
||||
if(is_sacrifice_target(sacrificial.mind))
|
||||
GLOB.sac_complete = TRUE
|
||||
big_sac = TRUE
|
||||
for(var/datum/objective/sacrifice/sac_objective in C.cult_team.objectives)
|
||||
if(sac_objective.target == sacrificial.mind)
|
||||
sac_objective.sacced = TRUE
|
||||
sac_objective.update_explanation_text()
|
||||
big_sac = TRUE
|
||||
else
|
||||
GLOB.sacrificed += sacrificial
|
||||
|
||||
@@ -481,7 +495,6 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
sleep(40)
|
||||
if(src)
|
||||
color = RUNE_COLOR_RED
|
||||
SSticker.mode.eldergod = FALSE
|
||||
new /obj/singularity/narsie/large/cult(T) //Causes Nar-Sie to spawn even if the rune has been removed
|
||||
|
||||
/obj/effect/rune/narsie/attackby(obj/I, mob/user, params) //Since the narsie rune takes a long time to make, add logging to removal.
|
||||
@@ -497,10 +510,10 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
message_admins("[key_name_admin(user)] erased a Narsie rune with a null rod")
|
||||
..()
|
||||
|
||||
//Rite of Resurrection: Requires a dead or inactive cultist. When reviving the dead, you can only perform one revival for every sacrifice your cult has carried out.
|
||||
//Rite of Resurrection: Requires the corpse of a cultist and that there have been less revives than the number of people GLOB.sacrificed
|
||||
/obj/effect/rune/raise_dead
|
||||
cultist_name = "Revive Cultist"
|
||||
cultist_desc = "requires a dead, mindless, or inactive cultist placed upon the rune. Provided there have been sufficient sacrifices, they will be given a new life."
|
||||
cultist_name = "Resurrect Cultist"
|
||||
cultist_desc = "requires the corpse of a cultist placed upon the rune. Provided there have been sufficient sacrifices, they will be revived."
|
||||
invocation = "Pasnar val'keriam usinar. Savrae ines amutan. Yam'toth remium il'tarat!" //Depends on the name of the user - see below
|
||||
icon_state = "1"
|
||||
color = RUNE_COLOR_MEDIUMRED
|
||||
@@ -521,11 +534,16 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
return
|
||||
rune_in_use = TRUE
|
||||
for(var/mob/living/M in T.contents)
|
||||
if(iscultist(M) && (M.stat == DEAD || !M.client || M.client.is_afk()))
|
||||
if(iscultist(M) && M.stat == DEAD)
|
||||
potential_revive_mobs |= M
|
||||
if(!potential_revive_mobs.len)
|
||||
to_chat(user, "<span class='cultitalic'>There are no dead cultists on the rune!</span>")
|
||||
log_game("Raise Dead rune failed - no cultists to revive")
|
||||
log_game("Raise Dead rune failed - no corpses to revive")
|
||||
fail_invoke()
|
||||
rune_in_use = FALSE
|
||||
return
|
||||
if(LAZYLEN(GLOB.sacrificed) <= revives_used)
|
||||
to_chat(user, "<span class='warning'>You have sacrificed too few people to revive a cultist!</span>")
|
||||
fail_invoke()
|
||||
rune_in_use = FALSE
|
||||
return
|
||||
@@ -541,25 +559,9 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
else
|
||||
invocation = initial(invocation)
|
||||
..()
|
||||
if(mob_to_revive.stat == DEAD)
|
||||
if(LAZYLEN(GLOB.sacrificed) <= revives_used)
|
||||
to_chat(user, "<span class='warning'>Your cult must carry out another sacrifice before it can revive a cultist!</span>")
|
||||
fail_invoke()
|
||||
rune_in_use = FALSE
|
||||
return
|
||||
revives_used++
|
||||
mob_to_revive.revive(1, 1) //This does remove disabilities and such, but the rune might actually see some use because of it!
|
||||
mob_to_revive.grab_ghost()
|
||||
else if(!mob_to_revive.client || mob_to_revive.client.is_afk())
|
||||
set waitfor = FALSE
|
||||
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [mob_to_revive.name], an inactive blood cultist?", "[name]", null, "Blood Cultist", 50, mob_to_revive)
|
||||
var/mob/dead/observer/theghost = null
|
||||
if(candidates.len)
|
||||
theghost = pick(candidates)
|
||||
to_chat(mob_to_revive.mind, "Your physical form has been taken over by another soul due to your inactivity! Ahelp if you wish to regain your form.")
|
||||
message_admins("[key_name_admin(theghost)] has taken control of ([key_name_admin(mob_to_revive)]) to replace an AFK player.")
|
||||
mob_to_revive.ghostize(0)
|
||||
mob_to_revive.key = theghost.key
|
||||
revives_used++
|
||||
mob_to_revive.revive(1, 1) //This does remove disabilities and such, but the rune might actually see some use because of it!
|
||||
mob_to_revive.grab_ghost()
|
||||
to_chat(mob_to_revive, "<span class='cultlarge'>\"PASNAR SAVRAE YAM'TOTH. Arise.\"</span>")
|
||||
mob_to_revive.visible_message("<span class='warning'>[mob_to_revive] draws in a huge breath, red light shining from [mob_to_revive.p_their()] eyes.</span>", \
|
||||
"<span class='cultlarge'>You awaken suddenly from the void. You're alive!</span>")
|
||||
|
||||
@@ -3,32 +3,6 @@
|
||||
var/list/datum/mind/devils = list()
|
||||
var/devil_ascended = 0 // Number of arch devils on station
|
||||
|
||||
/datum/game_mode/proc/auto_declare_completion_sintouched()
|
||||
var/text = ""
|
||||
if(sintouched.len)
|
||||
text += "<br><span class='big'><b>The sintouched were:</b></span>"
|
||||
var/list/sintouchedUnique = uniqueList(sintouched)
|
||||
for(var/S in sintouchedUnique)
|
||||
var/datum/mind/sintouched_mind = S
|
||||
text += printplayer(sintouched_mind)
|
||||
text += printobjectives(sintouched_mind)
|
||||
text += "<br>"
|
||||
text += "<br>"
|
||||
to_chat(world, text)
|
||||
|
||||
/datum/game_mode/proc/auto_declare_completion_devils()
|
||||
/var/text = ""
|
||||
if(devils.len)
|
||||
text += "<br><span class='big'><b>The devils were:</b></span>"
|
||||
for(var/D in devils)
|
||||
var/datum/mind/devil = D
|
||||
text += printplayer(devil)
|
||||
text += printdevilinfo(devil.current)
|
||||
text += printobjectives(devil)
|
||||
text += "<br>"
|
||||
text += "<br>"
|
||||
to_chat(world, text)
|
||||
|
||||
/datum/game_mode/proc/add_devil_objectives(datum/mind/devil_mind, quantity)
|
||||
var/list/validtypes = list(/datum/objective/devil/soulquantity, /datum/objective/devil/soulquality, /datum/objective/devil/sintouch, /datum/objective/devil/buy_target)
|
||||
for(var/i = 1 to quantity)
|
||||
@@ -41,18 +15,6 @@
|
||||
else
|
||||
objective.find_target()
|
||||
|
||||
/datum/game_mode/proc/printdevilinfo(mob/living/ply)
|
||||
var/datum/antagonist/devil/devilinfo = is_devil(ply)
|
||||
if(!devilinfo)
|
||||
return "Target is not a devil."
|
||||
var/text = "</br>The devil's true name is: [devilinfo.truename]</br>"
|
||||
text += "The devil's bans were:</br>"
|
||||
text += " [GLOB.lawlorify[LORE][devilinfo.ban]]</br>"
|
||||
text += " [GLOB.lawlorify[LORE][devilinfo.bane]]</br>"
|
||||
text += " [GLOB.lawlorify[LORE][devilinfo.obligation]]</br>"
|
||||
text += " [GLOB.lawlorify[LORE][devilinfo.banish]]</br></br>"
|
||||
return text
|
||||
|
||||
/datum/game_mode/proc/update_devil_icons_added(datum/mind/devil_mind)
|
||||
var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_DEVIL]
|
||||
hud.join_hud(devil_mind.current)
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
var/probability = 0
|
||||
var/false_report_weight = 0 //How often will this show up incorrectly in a centcom report?
|
||||
var/station_was_nuked = 0 //see nuclearbomb.dm and malfunction.dm
|
||||
var/nuke_off_station = 0 //Used for tracking where the nuke hit
|
||||
var/round_ends_with_antag_death = 0 //flags the "one verse the station" antags as such
|
||||
var/list/datum/mind/antag_candidates = list() // List of possible starting antags goes here
|
||||
var/list/restricted_jobs = list() // Jobs it doesn't make sense to be. I.E chaplain or AI cultist
|
||||
@@ -73,7 +74,6 @@
|
||||
/datum/game_mode/proc/pre_setup()
|
||||
return 1
|
||||
|
||||
|
||||
///Everyone should now be on the station and have their normal gear. This is the place to give the special roles extra things
|
||||
/datum/game_mode/proc/post_setup(report) //Gamemodes can override the intercept report. Passing TRUE as the argument will force a report.
|
||||
if(!report)
|
||||
@@ -241,55 +241,9 @@
|
||||
return 0
|
||||
|
||||
|
||||
/datum/game_mode/proc/declare_completion()
|
||||
var/clients = 0
|
||||
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(M.client)
|
||||
clients++
|
||||
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"))
|
||||
|
||||
send2irc("Server", "Round just ended.")
|
||||
if(cult.len && !istype(SSticker.mode, /datum/game_mode/cult))
|
||||
datum_cult_completion()
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
/datum/game_mode/proc/check_win() //universal trigger to be called at mob death, nuke explosion, etc. To be called from everywhere.
|
||||
return 0
|
||||
|
||||
|
||||
/datum/game_mode/proc/send_intercept()
|
||||
var/intercepttext = "<b><i>Central Command Status Summary</i></b><hr>"
|
||||
intercepttext += "<b>Central Command has intercepted and partially decoded a Syndicate transmission with vital information regarding their movements. The following report outlines the most \
|
||||
@@ -451,34 +405,6 @@
|
||||
for (var/C in GLOB.admins)
|
||||
to_chat(C, msg)
|
||||
|
||||
/datum/game_mode/proc/printplayer(datum/mind/ply, fleecheck)
|
||||
var/text = "<br><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='boldannounce'>died</span>"
|
||||
else
|
||||
text += " <span class='greenannounce'>survived</span>"
|
||||
if(fleecheck)
|
||||
var/turf/T = get_turf(ply.current)
|
||||
if(!T || !(T.z in GLOB.station_z_levels))
|
||||
text += " while <span class='boldannounce'>fleeing the station</span>"
|
||||
if(ply.current.real_name != ply.name)
|
||||
text += " as <b>[ply.current.real_name]</b>"
|
||||
else
|
||||
text += " <span class='boldannounce'>had their body destroyed</span>"
|
||||
return text
|
||||
|
||||
/datum/game_mode/proc/printobjectives(datum/mind/ply)
|
||||
var/text = ""
|
||||
var/count = 1
|
||||
for(var/datum/objective/objective in ply.objectives)
|
||||
if(objective.check_completion())
|
||||
text += "<br><b>Objective #[count]</b>: [objective.explanation_text] <span class='greenannounce'>Success!</span>"
|
||||
else
|
||||
text += "<br><b>Objective #[count]</b>: [objective.explanation_text] <span class='boldannounce'>Fail.</span>"
|
||||
count++
|
||||
return text
|
||||
|
||||
//If the configuration option is set to require players to be logged as old enough to play certain jobs, then this proc checks that they are, otherwise it just returns 1
|
||||
/datum/game_mode/proc/age_check(client/C)
|
||||
if(get_remaining_days(C) == 0)
|
||||
@@ -518,15 +444,25 @@
|
||||
station_goals += new picked
|
||||
|
||||
|
||||
/datum/game_mode/proc/declare_station_goal_completion()
|
||||
for(var/V in station_goals)
|
||||
var/datum/station_goal/G = V
|
||||
G.print_result()
|
||||
|
||||
/datum/game_mode/proc/generate_report() //Generates a small text blurb for the gamemode in centcom report
|
||||
return "Gamemode report for [name] not set. Contact a coder."
|
||||
|
||||
//By default nuke just ends the round
|
||||
/datum/game_mode/proc/OnNukeExplosion(off_station)
|
||||
nuke_off_station = off_station
|
||||
if(off_station < 2)
|
||||
station_was_nuked = TRUE //Will end the round on next check.
|
||||
|
||||
//Additional report section in roundend report
|
||||
/datum/game_mode/proc/special_report()
|
||||
return
|
||||
|
||||
//Set result and news report here
|
||||
/datum/game_mode/proc/set_round_result()
|
||||
SSticker.mode_result = "undefined"
|
||||
if(station_was_nuked)
|
||||
SSticker.news_report = STATION_DESTROYED_NUKE
|
||||
if(EMERGENCY_ESCAPED_OR_ENDGAMED)
|
||||
SSticker.news_report = STATION_EVACUATED
|
||||
if(SSshuttle.emergency.is_hijacked())
|
||||
SSticker.news_report = SHUTTLE_HIJACK
|
||||
@@ -25,35 +25,34 @@
|
||||
if (prob(meteorminutes/2))
|
||||
wavetype = GLOB.meteors_catastrophic
|
||||
|
||||
var/ramp_up_final = Clamp(round(meteorminutes/rampupdelta), 1, 10)
|
||||
var/ramp_up_final = CLAMP(round(meteorminutes/rampupdelta), 1, 10)
|
||||
|
||||
spawn_meteors(ramp_up_final, wavetype)
|
||||
|
||||
|
||||
/datum/game_mode/meteor/declare_completion()
|
||||
var/text
|
||||
/datum/game_mode/meteor/special_report()
|
||||
var/survivors = 0
|
||||
var/list/survivor_list = list()
|
||||
|
||||
for(var/mob/living/player in GLOB.player_list)
|
||||
if(player.stat != DEAD)
|
||||
++survivors
|
||||
|
||||
if(player.onCentCom())
|
||||
text += "<br><b><font size=2>[player.real_name] escaped to the safety of CentCom.</font></b>"
|
||||
survivor_list += "<span class='greentext'>[player.real_name] escaped to the safety of CentCom.</span>"
|
||||
else if(player.onSyndieBase())
|
||||
text += "<br><b><font size=2>[player.real_name] escaped to the (relative) safety of Syndicate Space.</font></b>"
|
||||
survivor_list += "<span class='greentext'>[player.real_name] escaped to the (relative) safety of Syndicate Space.</span>"
|
||||
else
|
||||
text += "<br><font size=1>[player.real_name] survived but is stranded without any hope of rescue.</font>"
|
||||
|
||||
survivor_list += "<span class='neutraltext'>[player.real_name] survived but is stranded without any hope of rescue.</span>"
|
||||
|
||||
if(survivors)
|
||||
to_chat(world, "<span class='boldnotice'>The following survived the meteor storm</span>:[text]")
|
||||
return "<span class='header'>The following survived the meteor storm:</span><br>[survivor_list.Join("<br>")]"
|
||||
else
|
||||
to_chat(world, "<span class='boldnotice'>Nobody survived the meteor storm!</span>")
|
||||
return "<span class='redtext big'>Nobody survived the meteor storm!</span>"
|
||||
|
||||
SSticker.mode_result = "end - evacuation"
|
||||
/datum/game_mode/meteor/set_round_result()
|
||||
..()
|
||||
return 1
|
||||
SSticker.mode_result = "end - evacuation"
|
||||
|
||||
/datum/game_mode/meteor/generate_report()
|
||||
return "[pick("Asteroids have", "Meteors have", "Large rocks have", "Stellar minerals have", "Space hail has", "Debris has")] been detected near your station, and a collision is possible, \
|
||||
|
||||
@@ -1,19 +1,5 @@
|
||||
/datum/objective_team/abductor_team
|
||||
member_name = "abductor"
|
||||
var/list/objectives = list()
|
||||
var/team_number
|
||||
|
||||
/datum/objective_team/abductor_team/is_solo()
|
||||
return FALSE
|
||||
|
||||
/datum/objective_team/abductor_team/proc/add_objective(datum/objective/O)
|
||||
O.team = src
|
||||
O.update_explanation_text()
|
||||
objectives += O
|
||||
|
||||
/datum/game_mode
|
||||
var/list/datum/mind/abductors = list()
|
||||
var/list/datum/mind/abductees = list()
|
||||
|
||||
/datum/game_mode/abduction
|
||||
name = "abduction"
|
||||
@@ -24,7 +10,7 @@
|
||||
required_players = 15
|
||||
maximum_players = 50
|
||||
var/max_teams = 4
|
||||
var/list/datum/objective_team/abductor_team/abductor_teams = list()
|
||||
var/list/datum/team/abductor_team/abductor_teams = list()
|
||||
var/finished = FALSE
|
||||
var/static/team_count = 0
|
||||
|
||||
@@ -51,7 +37,7 @@
|
||||
if(team_number > max_teams)
|
||||
return //or should it try to stuff them in anway ?
|
||||
|
||||
var/datum/objective_team/abductor_team/team = new
|
||||
var/datum/team/abductor_team/team = new
|
||||
team.team_number = team_number
|
||||
team.name = "Mothership [pick(GLOB.possible_changeling_IDs)]" //TODO Ensure unique and actual alieny names
|
||||
team.add_objective(new/datum/objective/experiment)
|
||||
@@ -64,6 +50,7 @@
|
||||
antag_candidates -= scientist
|
||||
team.members |= scientist
|
||||
scientist.assigned_role = "Abductor Scientist"
|
||||
scientist.special_role = "Abductor Scientist"
|
||||
log_game("[scientist.key] (ckey) has been selected as [team.name] abductor scientist.")
|
||||
|
||||
if(!agent)
|
||||
@@ -71,18 +58,19 @@
|
||||
antag_candidates -= agent
|
||||
team.members |= agent
|
||||
agent.assigned_role = "Abductor Agent"
|
||||
agent.special_role = "Abductor Agent"
|
||||
log_game("[agent.key] (ckey) has been selected as [team.name] abductor agent.")
|
||||
|
||||
abductor_teams += team
|
||||
return team
|
||||
|
||||
/datum/game_mode/abduction/post_setup()
|
||||
for(var/datum/objective_team/abductor_team/team in abductor_teams)
|
||||
for(var/datum/team/abductor_team/team in abductor_teams)
|
||||
post_setup_team(team)
|
||||
return ..()
|
||||
|
||||
//Used for create antag buttons
|
||||
/datum/game_mode/abduction/proc/post_setup_team(datum/objective_team/abductor_team/team)
|
||||
/datum/game_mode/abduction/proc/post_setup_team(datum/team/abductor_team/team)
|
||||
for(var/datum/mind/M in team.members)
|
||||
if(M.assigned_role == "Abductor Scientist")
|
||||
M.add_antag_datum(ANTAG_DATUM_ABDUCTOR_SCIENTIST, team)
|
||||
@@ -91,7 +79,7 @@
|
||||
|
||||
/datum/game_mode/abduction/check_finished()
|
||||
if(!finished)
|
||||
for(var/datum/objective_team/abductor_team/team in abductor_teams)
|
||||
for(var/datum/team/abductor_team/team in abductor_teams)
|
||||
for(var/datum/objective/O in team.objectives)
|
||||
if(O.check_completion())
|
||||
SSshuttle.emergency.request(null, set_coefficient = 0.5)
|
||||
@@ -99,35 +87,6 @@
|
||||
return ..()
|
||||
return ..()
|
||||
|
||||
/datum/game_mode/abduction/declare_completion()
|
||||
for(var/datum/objective_team/abductor_team/team in abductor_teams)
|
||||
var/won = TRUE
|
||||
for(var/datum/objective/O in team.objectives)
|
||||
if(!O.check_completion())
|
||||
won = FALSE
|
||||
if(won)
|
||||
to_chat(world, "<span class='greenannounce'>[team.name] team fulfilled its mission!</span>")
|
||||
else
|
||||
to_chat(world, "<span class='boldannounce'>[team.name] team failed its mission.</span>")
|
||||
..()
|
||||
return TRUE
|
||||
|
||||
/datum/game_mode/proc/auto_declare_completion_abduction()
|
||||
var/text = ""
|
||||
if(abductors.len)
|
||||
text += "<br><span class='big'><b>The abductors were:</b></span>"
|
||||
for(var/datum/mind/abductor_mind in abductors)
|
||||
text += printplayer(abductor_mind)
|
||||
text += printobjectives(abductor_mind)
|
||||
text += "<br>"
|
||||
if(abductees.len)
|
||||
text += "<br><span class='big'><b>The abductees were:</b></span>"
|
||||
for(var/datum/mind/abductee_mind in abductees)
|
||||
text += printplayer(abductee_mind)
|
||||
text += printobjectives(abductee_mind)
|
||||
text += "<br>"
|
||||
to_chat(world, text)
|
||||
|
||||
// LANDMARKS
|
||||
/obj/effect/landmark/abductor
|
||||
var/team_number = 1
|
||||
@@ -144,9 +103,9 @@
|
||||
|
||||
/datum/objective/experiment/check_completion()
|
||||
for(var/obj/machinery/abductor/experiment/E in GLOB.machines)
|
||||
if(!istype(team, /datum/objective_team/abductor_team))
|
||||
if(!istype(team, /datum/team/abductor_team))
|
||||
return FALSE
|
||||
var/datum/objective_team/abductor_team/T = team
|
||||
var/datum/team/abductor_team/T = team
|
||||
if(E.team_number == T.team_number)
|
||||
return E.points >= target_amount
|
||||
return FALSE
|
||||
|
||||
@@ -151,13 +151,18 @@
|
||||
var/mob/living/mob_occupant = occupant
|
||||
if(mob_occupant.stat != DEAD)
|
||||
if(href_list["experiment"])
|
||||
flash = Experiment(occupant,href_list["experiment"])
|
||||
flash = Experiment(occupant,href_list["experiment"],usr)
|
||||
updateUsrDialog()
|
||||
add_fingerprint(usr)
|
||||
|
||||
/obj/machinery/abductor/experiment/proc/Experiment(mob/occupant,type)
|
||||
/obj/machinery/abductor/experiment/proc/Experiment(mob/occupant,type,mob/user)
|
||||
LAZYINITLIST(history)
|
||||
var/mob/living/carbon/human/H = occupant
|
||||
|
||||
var/datum/antagonist/abductor/user_abductor = user.mind.has_antag_datum(/datum/antagonist/abductor)
|
||||
if(!user_abductor)
|
||||
return "<span class='bad'>Authorization failure. Contact mothership immidiately.</span>"
|
||||
|
||||
var/point_reward = 0
|
||||
if(H in history)
|
||||
return "<span class='bad'>Specimen already in database.</span>"
|
||||
@@ -182,15 +187,8 @@
|
||||
if(3)
|
||||
to_chat(H, "<span class='warning'>You feel intensely watched.</span>")
|
||||
sleep(5)
|
||||
to_chat(H, "<span class='warning'><b>Your mind snaps!</b></span>")
|
||||
H.gain_trauma_type(BRAIN_TRAUMA_MILD)
|
||||
to_chat(H, "<big><span class='warning'><b>You can't remember how you got here...</b></span></big>")
|
||||
var/objtype = (prob(75) ? /datum/objective/abductee/random : pick(subtypesof(/datum/objective/abductee/) - /datum/objective/abductee/random))
|
||||
var/datum/objective/abductee/O = new objtype()
|
||||
SSticker.mode.abductees += H.mind
|
||||
H.mind.objectives += O
|
||||
H.mind.announce_objectives()
|
||||
SSticker.mode.update_abductor_icons_added(H.mind)
|
||||
user_abductor.team.abductees += H.mind
|
||||
H.mind.add_antag_datum(/datum/antagonist/abductee)
|
||||
|
||||
for(var/obj/item/organ/heart/gland/G in H.internal_organs)
|
||||
G.Start()
|
||||
|
||||
@@ -105,13 +105,18 @@
|
||||
monkey_mind.special_role = null
|
||||
|
||||
|
||||
/datum/game_mode/monkey/declare_completion()
|
||||
/datum/game_mode/monkey/set_round_result()
|
||||
..()
|
||||
if(check_monkey_victory())
|
||||
SSticker.mode_result = "win - monkey win"
|
||||
to_chat(world, "<span class='userdanger'>The monkeys have overthrown their captors! Eeek eeeek!!</span>")
|
||||
else
|
||||
SSticker.mode_result = "loss - staff stopped the monkeys"
|
||||
to_chat(world, "<span class='userdanger'>The staff managed to contain the monkey infestation!</span>")
|
||||
|
||||
/datum/game_mode/monkey/special_report()
|
||||
if(check_monkey_victory())
|
||||
return "<span class='redtext big'>The monkeys have overthrown their captors! Eeek eeeek!!</span>"
|
||||
else
|
||||
return "<span class='redtext big'>The staff managed to contain the monkey infestation!</span>"
|
||||
|
||||
/datum/game_mode/monkey/generate_report()
|
||||
return "Reports of an ancient [pick("retrovirus", "flesh eating bacteria", "disease", "magical curse blamed on viruses", "banana blight")] outbreak that turn humans into monkeys has been reported in your quadrant. Any such infections may be treated with banana juice. If an outbreak occurs, ensure the station is quarantined to prevent a largescale outbreak at CentCom."
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
player_mind.assigned_role = "Morph"
|
||||
player_mind.special_role = "Morph"
|
||||
SSticker.mode.traitors |= player_mind
|
||||
player_mind.add_antag_datum(/datum/antagonist/auto_custom)
|
||||
to_chat(S, S.playstyle_string)
|
||||
SEND_SOUND(S, sound('sound/magic/mutate.ogg'))
|
||||
message_admins("[key_name_admin(S)] has been made into a morph by an event.")
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user