Merge branch 'master' into upstream-merge-31877
This commit is contained in:
@@ -1,38 +1,38 @@
|
||||
//See controllers/globals.dm
|
||||
#define GLOBAL_MANAGED(X, InitValue)\
|
||||
/datum/controller/global_vars/proc/InitGlobal##X(){\
|
||||
##X = ##InitValue;\
|
||||
gvars_datum_init_order += #X;\
|
||||
}
|
||||
#define GLOBAL_UNMANAGED(X, InitValue) /datum/controller/global_vars/proc/InitGlobal##X()
|
||||
|
||||
#ifndef TESTING
|
||||
#define GLOBAL_PROTECT(X)\
|
||||
/datum/controller/global_vars/InitGlobal##X(){\
|
||||
..();\
|
||||
gvars_datum_protected_varlist += #X;\
|
||||
}
|
||||
#else
|
||||
#define GLOBAL_PROTECT(X)
|
||||
#endif
|
||||
|
||||
#define GLOBAL_REAL_VAR(X) var/global/##X
|
||||
#define GLOBAL_REAL(X, Typepath) var/global##Typepath/##X
|
||||
|
||||
#define GLOBAL_RAW(X) /datum/controller/global_vars/var/global##X
|
||||
|
||||
#define GLOBAL_VAR_INIT(X, InitValue) GLOBAL_RAW(/##X); GLOBAL_MANAGED(X, InitValue)
|
||||
|
||||
#define GLOBAL_VAR_CONST(X, InitValue) GLOBAL_RAW(/const/##X) = InitValue; GLOBAL_UNMANAGED(X, InitValue)
|
||||
|
||||
#define GLOBAL_LIST_INIT(X, InitValue) GLOBAL_RAW(/list/##X); GLOBAL_MANAGED(X, InitValue)
|
||||
|
||||
#define GLOBAL_LIST_EMPTY(X) GLOBAL_LIST_INIT(X, list())
|
||||
|
||||
#define GLOBAL_DATUM_INIT(X, Typepath, InitValue) GLOBAL_RAW(Typepath/##X); GLOBAL_MANAGED(X, InitValue)
|
||||
|
||||
#define GLOBAL_VAR(X) GLOBAL_RAW(/##X); GLOBAL_MANAGED(X, null)
|
||||
|
||||
#define GLOBAL_LIST(X) GLOBAL_RAW(/list/##X); GLOBAL_MANAGED(X, null)
|
||||
|
||||
#define GLOBAL_DATUM(X, Typepath) GLOBAL_RAW(Typepath/##X); GLOBAL_MANAGED(X, null)
|
||||
//See controllers/globals.dm
|
||||
#define GLOBAL_MANAGED(X, InitValue)\
|
||||
/datum/controller/global_vars/proc/InitGlobal##X(){\
|
||||
##X = ##InitValue;\
|
||||
gvars_datum_init_order += #X;\
|
||||
}
|
||||
#define GLOBAL_UNMANAGED(X) /datum/controller/global_vars/proc/InitGlobal##X() { return; }
|
||||
|
||||
#ifndef TESTING
|
||||
#define GLOBAL_PROTECT(X)\
|
||||
/datum/controller/global_vars/InitGlobal##X(){\
|
||||
..();\
|
||||
gvars_datum_protected_varlist += #X;\
|
||||
}
|
||||
#else
|
||||
#define GLOBAL_PROTECT(X)
|
||||
#endif
|
||||
|
||||
#define GLOBAL_REAL_VAR(X) var/global/##X
|
||||
#define GLOBAL_REAL(X, Typepath) var/global##Typepath/##X
|
||||
|
||||
#define GLOBAL_RAW(X) /datum/controller/global_vars/var/global##X
|
||||
|
||||
#define GLOBAL_VAR_INIT(X, InitValue) GLOBAL_RAW(/##X); GLOBAL_MANAGED(X, InitValue)
|
||||
|
||||
#define GLOBAL_VAR_CONST(X, InitValue) GLOBAL_RAW(/const/##X) = InitValue; GLOBAL_UNMANAGED(X)
|
||||
|
||||
#define GLOBAL_LIST_INIT(X, InitValue) GLOBAL_RAW(/list/##X); GLOBAL_MANAGED(X, InitValue)
|
||||
|
||||
#define GLOBAL_LIST_EMPTY(X) GLOBAL_LIST_INIT(X, list())
|
||||
|
||||
#define GLOBAL_DATUM_INIT(X, Typepath, InitValue) GLOBAL_RAW(Typepath/##X); GLOBAL_MANAGED(X, InitValue)
|
||||
|
||||
#define GLOBAL_VAR(X) GLOBAL_RAW(/##X); GLOBAL_UNMANAGED(X)
|
||||
|
||||
#define GLOBAL_LIST(X) GLOBAL_RAW(/list/##X); GLOBAL_UNMANAGED(X)
|
||||
|
||||
#define GLOBAL_DATUM(X, Typepath) GLOBAL_RAW(Typepath/##X); GLOBAL_UNMANAGED(X)
|
||||
|
||||
@@ -135,3 +135,25 @@
|
||||
#define NOAROUSAL 29 //Stops all arousal effects
|
||||
#define NOGENITALS 30 //Cannot create, use, or otherwise have genitals
|
||||
#define NO_DNA_COPY 31
|
||||
|
||||
#define ORGAN_SLOT_BRAIN "brain"
|
||||
#define ORGAN_SLOT_APPENDIX "appendix"
|
||||
#define ORGAN_SLOT_RIGHT_ARM_AUG "r_arm_device"
|
||||
#define ORGAN_SLOT_LEFT_ARM_AUG "l_arm_device"
|
||||
#define ORGAN_SLOT_STOMACH "stomach"
|
||||
#define ORGAN_SLOT_BREATHING_TUBE "breathing_tube"
|
||||
#define ORGAN_SLOT_EARS "ears"
|
||||
#define ORGAN_SLOT_EYES "eye_sight"
|
||||
#define ORGAN_SLOT_LUNGS "lungs"
|
||||
#define ORGAN_SLOT_HEART "heart"
|
||||
#define ORGAN_SLOT_ZOMBIE "zombie_infection"
|
||||
#define ORGAN_SLOT_THRUSTERS "thrusters"
|
||||
#define ORGAN_SLOT_HUD "eye_hud"
|
||||
#define ORGAN_SLOT_LIVER "liver"
|
||||
#define ORGAN_SLOT_TONGUE "tongue"
|
||||
#define ORGAN_SLOT_VOICE "vocal_cords"
|
||||
#define ORGAN_SLOT_ADAMANTINE_RESONATOR "adamantine_resonator"
|
||||
#define ORGAN_SLOT_HEART_AID "heartdrive"
|
||||
#define ORGAN_SLOT_BRAIN_ANTIDROP "brain_antidrop"
|
||||
#define ORGAN_SLOT_BRAIN_ANTISTUN "brain_antistun"
|
||||
#define ORGAN_SLOT_TAIL "tail"
|
||||
|
||||
@@ -7,16 +7,10 @@
|
||||
#define ANTAG_DATUM_NINJA_FRIENDLY /datum/antagonist/ninja/friendly
|
||||
#define ANTAG_DATUM_NINJA_RANDOM /datum/antagonist/ninja/randomAllegiance/
|
||||
#define ANTAG_DATUM_TRAITOR /datum/antagonist/traitor
|
||||
#define ANTAG_DATUM_TRAITOR_CUSTOM /datum/antagonist/traitor/custom
|
||||
#define ANTAG_DATUM_TRAITOR_HUMAN /datum/antagonist/traitor/human
|
||||
#define ANTAG_DATUM_TRAITOR_HUMAN_CUSTOM /datum/antagonist/traitor/human/custom
|
||||
#define ANTAG_DATUM_TRAITOR_AI /datum/antagonist/traitor/AI
|
||||
#define ANTAG_DATUM_TRAITOR_AI_CUSTOM /datum/antagonist/traitor/AI/custom
|
||||
#define ANTAG_DATUM_IAA /datum/antagonist/traitor/internal_affairs
|
||||
#define ANTAG_DATUM_IAA_CUSTOM /datum/antagonist/traitor/internal_affairs/custom
|
||||
#define ANTAG_DATUM_IAA_HUMAN /datum/antagonist/traitor/human/internal_affairs
|
||||
#define ANTAG_DATUM_IAA_HUMAN_CUSTOM /datum/antagonist/traitor/human/internal_affairs/custom
|
||||
#define ANTAG_DATUM_IAA_AI_CUSTOM /datum/antagonist/traitor/AI/internal_affairs/custom
|
||||
#define ANTAG_DATUM_IAA_AI /datum/antagonist/traitor/AI/internal_affairs
|
||||
#define ANTAG_DATUM_BROTHER /datum/antagonist/brother
|
||||
#define ANTAG_DATUM_ABDUCTOR /datum/antagonist/abductor
|
||||
|
||||
@@ -56,28 +56,16 @@
|
||||
#define FIRE_MINIMUM_TEMPERATURE_TO_SPREAD 150+T0C
|
||||
#define FIRE_MINIMUM_TEMPERATURE_TO_EXIST 100+T0C
|
||||
#define FIRE_SPREAD_RADIOSITY_SCALE 0.85
|
||||
#define FIRE_CARBON_ENERGY_RELEASED 500000 //Amount of heat released per mole of burnt carbon into the tile
|
||||
#define FIRE_PLASMA_ENERGY_RELEASED 3000000 //Amount of heat released per mole of burnt plasma into the tile
|
||||
#define FIRE_GROWTH_RATE 40000 //For small fires
|
||||
#define CARBON_LIFEFORM_FIRE_RESISTANCE 200+T0C //Resistance to fire damage
|
||||
#define CARBON_LIFEFORM_FIRE_DAMAGE 4 //Fire damage
|
||||
//Plasma fire properties
|
||||
#define OXYGEN_BURN_RATE_BASE 1.4
|
||||
#define PLASMA_BURN_RATE_DELTA 9
|
||||
#define PLASMA_MINIMUM_BURN_TEMPERATURE 100+T0C
|
||||
#define PLASMA_UPPER_TEMPERATURE 1370+T0C
|
||||
#define PLASMA_MINIMUM_OXYGEN_NEEDED 2
|
||||
#define PLASMA_MINIMUM_OXYGEN_PLASMA_RATIO 30
|
||||
#define PLASMA_OXYGEN_FULLBURN 10
|
||||
#define MIN_TOXIC_GAS_DAMAGE 1
|
||||
#define MAX_TOXIC_GAS_DAMAGE 10
|
||||
#define MOLES_PLASMA_VISIBLE 0.5 //Moles in a standard cell after which plasma is visible
|
||||
//Plasma fusion properties
|
||||
#define PLASMA_BINDING_ENERGY 3000000
|
||||
#define MAX_CARBON_EFFICENCY 9
|
||||
#define PLASMA_FUSED_COEFFICENT 0.08
|
||||
#define CARBON_CATALYST_COEFFICENT 0.01
|
||||
#define FUSION_PURITY_THRESHOLD 0.9
|
||||
#define MOLES_GAS_VISIBLE 0.5 //Moles in a standard cell after which gases are visible
|
||||
#define STOP_REACTIONS 2
|
||||
#define PLASMA_MINIMUM_BURN_TEMPERATURE 100+T0C
|
||||
#define GAS_STIM_MINIMUM 0.002
|
||||
|
||||
// Pressure limits.
|
||||
#define HAZARD_HIGH_PRESSURE 550 //This determins at what pressure the ultra-high pressure red icon is displayed. (This one is set as a constant)
|
||||
#define WARNING_HIGH_PRESSURE 325 //This determins when the orange pressure icon is displayed (it is 0.7 * HAZARD_HIGH_PRESSURE)
|
||||
@@ -193,8 +181,7 @@
|
||||
#define THERMAL_ENERGY(gas) (gas.temperature * gas.heat_capacity())
|
||||
|
||||
#define ADD_GAS(gas_id, out_list)\
|
||||
var/list/tmp_gaslist = GLOB.gaslist_cache[gas_id];\
|
||||
out_list[gas_id] = tmp_gaslist.Copy();
|
||||
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.
|
||||
|
||||
@@ -40,8 +40,7 @@
|
||||
#define ANTAG_HUD_SINTOUCHED 16
|
||||
#define ANTAG_HUD_SOULLESS 17
|
||||
#define ANTAG_HUD_CLOCKWORK 18
|
||||
#define ANTAG_HUD_BORER 19
|
||||
#define ANTAG_HUD_BROTHER 20
|
||||
#define ANTAG_HUD_BROTHER 19
|
||||
|
||||
// Notification action types
|
||||
#define NOTIFY_JUMP "jump"
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#define GET_COMPONENT_FROM(varname, path, target) var##path/##varname = ##target.GetComponent(##path)
|
||||
#define GET_COMPONENT(varname, path) GET_COMPONENT_FROM(varname, path, src)
|
||||
|
||||
#define COMPONENT_INCOMPATIBLE 1
|
||||
|
||||
// How multiple components of the exact same type are handled in the same datum
|
||||
|
||||
#define COMPONENT_DUPE_HIGHLANDER 0 //old component is deleted (default)
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#define HIGH_SIGIL_LAYER 2.56
|
||||
|
||||
#define BELOW_OPEN_DOOR_LAYER 2.6
|
||||
#define SHUTTER_LAYER 2.65 //Prevents shutters from being placed above doors. It's overridden by /obj/machinery/door/New() & poddoor/shutters/New()
|
||||
#define OPEN_DOOR_LAYER 2.7
|
||||
#define PROJECTILE_HIT_THRESHHOLD_LAYER 2.75 //projectiles won't hit objects at or below this layer if possible
|
||||
#define TABLE_LAYER 2.8
|
||||
|
||||
@@ -204,6 +204,7 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache)
|
||||
#define BLOODY_FOOTPRINT_BASE_ALPHA 150
|
||||
#define BLOOD_GAIN_PER_STEP 100
|
||||
#define BLOOD_LOSS_PER_STEP 5
|
||||
#define BLOOD_LOSS_IN_SPREAD 20
|
||||
#define BLOOD_FADEOUT_TIME 2
|
||||
|
||||
//Bloody shoe blood states
|
||||
@@ -468,4 +469,6 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
|
||||
#define DUMMY_HUMAN_SLOT_MANIFEST "dummy_manifest_generation"
|
||||
|
||||
#define PR_ANNOUNCEMENTS_PER_ROUND 5 //The number of unique PR announcements allowed per round
|
||||
//This makes sure that a single person can only spam 3 reopens and 3 closes before being ignored
|
||||
//This makes sure that a single person can only spam 3 reopens and 3 closes before being ignored
|
||||
|
||||
#define MAX_PROC_DEPTH 195 // 200 proc calls deep and shit breaks, this is a bit lower to give some safety room
|
||||
@@ -1,33 +1,10 @@
|
||||
/*
|
||||
PIPE CONSTRUCTION DEFINES
|
||||
Update these any time a path is changed
|
||||
Construction breaks otherwise
|
||||
*/
|
||||
|
||||
//Pipes
|
||||
#define PIPE_SIMPLE /obj/machinery/atmospherics/pipe/simple
|
||||
#define PIPE_MANIFOLD /obj/machinery/atmospherics/pipe/manifold
|
||||
#define PIPE_4WAYMANIFOLD /obj/machinery/atmospherics/pipe/manifold4w
|
||||
#define PIPE_HE /obj/machinery/atmospherics/pipe/heat_exchanging/simple
|
||||
#define PIPE_HE_MANIFOLD /obj/machinery/atmospherics/pipe/heat_exchanging/manifold
|
||||
#define PIPE_HE_4WAYMANIFOLD /obj/machinery/atmospherics/pipe/heat_exchanging/manifold4w
|
||||
#define PIPE_JUNCTION /obj/machinery/atmospherics/pipe/heat_exchanging/junction
|
||||
#define PIPE_LAYER_MANIFOLD /obj/machinery/atmospherics/pipe/layer_manifold
|
||||
//Unary
|
||||
#define PIPE_CONNECTOR /obj/machinery/atmospherics/components/unary/portables_connector
|
||||
#define PIPE_UVENT /obj/machinery/atmospherics/components/unary/vent_pump
|
||||
#define PIPE_SCRUBBER /obj/machinery/atmospherics/components/unary/vent_scrubber
|
||||
#define PIPE_INJECTOR /obj/machinery/atmospherics/components/unary/outlet_injector
|
||||
#define PIPE_HEAT_EXCHANGE /obj/machinery/atmospherics/components/unary/heat_exchanger
|
||||
//Binary
|
||||
#define PIPE_PUMP /obj/machinery/atmospherics/components/binary/pump
|
||||
#define PIPE_PASSIVE_GATE /obj/machinery/atmospherics/components/binary/passive_gate
|
||||
#define PIPE_VOLUME_PUMP /obj/machinery/atmospherics/components/binary/volume_pump
|
||||
#define PIPE_MVALVE /obj/machinery/atmospherics/components/binary/valve
|
||||
#define PIPE_DVALVE /obj/machinery/atmospherics/components/binary/valve/digital
|
||||
//Trinary
|
||||
#define PIPE_GAS_FILTER /obj/machinery/atmospherics/components/trinary/filter
|
||||
#define PIPE_GAS_MIXER /obj/machinery/atmospherics/components/trinary/mixer
|
||||
//Construction Categories
|
||||
#define PIPE_BINARY 0 //2 directions: N/S, E/W
|
||||
#define PIPE_BENDABLE 1 //6 directions: N/S, E/W, N/E, N/W, S/E, S/W
|
||||
#define PIPE_TRINARY 2 //4 directions: N/E/S, E/S/W, S/W/N, W/N/E
|
||||
#define PIPE_TRIN_M 3 //8 directions: N->S+E, S->N+E, N->S+W, S->N+W, E->W+S, W->E+S, E->W+N, W->E+N
|
||||
#define PIPE_UNARY 4 //4 directions: N, S, E, W
|
||||
#define PIPE_QUAD 5 //1 directions: N/S/E/W
|
||||
|
||||
//Disposal piping numbers - do NOT hardcode these, use the defines
|
||||
#define DISP_PIPE_STRAIGHT 0
|
||||
|
||||
@@ -40,7 +40,7 @@ GLOBAL_LIST_INIT(special_roles, list(
|
||||
ROLE_ALIEN,
|
||||
ROLE_PAI,
|
||||
ROLE_CULTIST = /datum/game_mode/cult,
|
||||
ROLE_BLOB = /datum/game_mode/blob,
|
||||
ROLE_BLOB,
|
||||
ROLE_NINJA,
|
||||
ROLE_MONKEY = /datum/game_mode/monkey,
|
||||
ROLE_REVENANT,
|
||||
|
||||
@@ -154,7 +154,7 @@ Actual Adjacent procs :
|
||||
/turf/proc/reachableAdjacentTurfs(caller, ID, simulated_only)
|
||||
var/list/L = new()
|
||||
var/turf/T
|
||||
var/static/space_type_cache = typecacheof(list(/turf/open/space))
|
||||
var/static/space_type_cache = typecacheof(/turf/open/space)
|
||||
|
||||
for(var/dir in GLOB.cardinals)
|
||||
T = get_step(src,dir)
|
||||
|
||||
+145
-75
@@ -308,7 +308,8 @@ world
|
||||
*/
|
||||
|
||||
/proc/ReadRGB(rgb)
|
||||
if(!rgb) return
|
||||
if(!rgb)
|
||||
return
|
||||
|
||||
// interpret the HSV or HSVA value
|
||||
var/i=1,start=1
|
||||
@@ -317,19 +318,27 @@ world
|
||||
var/digits=0
|
||||
for(i=start, i<=length(rgb), ++i)
|
||||
ch = text2ascii(rgb, i)
|
||||
if(ch < 48 || (ch > 57 && ch < 65) || (ch > 70 && ch < 97) || ch > 102) break
|
||||
if(ch < 48 || (ch > 57 && ch < 65) || (ch > 70 && ch < 97) || ch > 102)
|
||||
break
|
||||
++digits
|
||||
if(digits == 8) break
|
||||
if(digits == 8)
|
||||
break
|
||||
|
||||
var/single = digits < 6
|
||||
if(digits != 3 && digits != 4 && digits != 6 && digits != 8) return
|
||||
if(digits == 4 || digits == 8) usealpha = 1
|
||||
if(digits != 3 && digits != 4 && digits != 6 && digits != 8)
|
||||
return
|
||||
if(digits == 4 || digits == 8)
|
||||
usealpha = 1
|
||||
for(i=start, digits>0, ++i)
|
||||
ch = text2ascii(rgb, i)
|
||||
if(ch >= 48 && ch <= 57) ch -= 48
|
||||
else if(ch >= 65 && ch <= 70) ch -= 55
|
||||
else if(ch >= 97 && ch <= 102) ch -= 87
|
||||
else break
|
||||
if(ch >= 48 && ch <= 57)
|
||||
ch -= 48
|
||||
else if(ch >= 65 && ch <= 70)
|
||||
ch -= 55
|
||||
else if(ch >= 97 && ch <= 102)
|
||||
ch -= 87
|
||||
else
|
||||
break
|
||||
--digits
|
||||
switch(which)
|
||||
if(0)
|
||||
@@ -337,69 +346,91 @@ world
|
||||
if(single)
|
||||
r |= r << 4
|
||||
++which
|
||||
else if(!(digits & 1)) ++which
|
||||
else if(!(digits & 1))
|
||||
++which
|
||||
if(1)
|
||||
g = (g << 4) | ch
|
||||
if(single)
|
||||
g |= g << 4
|
||||
++which
|
||||
else if(!(digits & 1)) ++which
|
||||
else if(!(digits & 1))
|
||||
++which
|
||||
if(2)
|
||||
b = (b << 4) | ch
|
||||
if(single)
|
||||
b |= b << 4
|
||||
++which
|
||||
else if(!(digits & 1)) ++which
|
||||
else if(!(digits & 1))
|
||||
++which
|
||||
if(3)
|
||||
alpha = (alpha << 4) | ch
|
||||
if(single) alpha |= alpha << 4
|
||||
if(single)
|
||||
alpha |= alpha << 4
|
||||
|
||||
. = list(r, g, b)
|
||||
if(usealpha) . += alpha
|
||||
if(usealpha)
|
||||
. += alpha
|
||||
|
||||
/proc/ReadHSV(hsv)
|
||||
if(!hsv) return
|
||||
if(!hsv)
|
||||
return
|
||||
|
||||
// interpret the HSV or HSVA value
|
||||
var/i=1,start=1
|
||||
if(text2ascii(hsv) == 35) ++start // skip opening #
|
||||
if(text2ascii(hsv) == 35)
|
||||
++start // skip opening #
|
||||
var/ch,which=0,hue=0,sat=0,val=0,alpha=0,usealpha
|
||||
var/digits=0
|
||||
for(i=start, i<=length(hsv), ++i)
|
||||
ch = text2ascii(hsv, i)
|
||||
if(ch < 48 || (ch > 57 && ch < 65) || (ch > 70 && ch < 97) || ch > 102) break
|
||||
if(ch < 48 || (ch > 57 && ch < 65) || (ch > 70 && ch < 97) || ch > 102)
|
||||
break
|
||||
++digits
|
||||
if(digits == 9) break
|
||||
if(digits > 7) usealpha = 1
|
||||
if(digits <= 4) ++which
|
||||
if(digits <= 2) ++which
|
||||
if(digits == 9)
|
||||
break
|
||||
if(digits > 7)
|
||||
usealpha = 1
|
||||
if(digits <= 4)
|
||||
++which
|
||||
if(digits <= 2)
|
||||
++which
|
||||
for(i=start, digits>0, ++i)
|
||||
ch = text2ascii(hsv, i)
|
||||
if(ch >= 48 && ch <= 57) ch -= 48
|
||||
else if(ch >= 65 && ch <= 70) ch -= 55
|
||||
else if(ch >= 97 && ch <= 102) ch -= 87
|
||||
else break
|
||||
if(ch >= 48 && ch <= 57)
|
||||
ch -= 48
|
||||
else if(ch >= 65 && ch <= 70)
|
||||
ch -= 55
|
||||
else if(ch >= 97 && ch <= 102)
|
||||
ch -= 87
|
||||
else
|
||||
break
|
||||
--digits
|
||||
switch(which)
|
||||
if(0)
|
||||
hue = (hue << 4) | ch
|
||||
if(digits == (usealpha ? 6 : 4)) ++which
|
||||
if(digits == (usealpha ? 6 : 4))
|
||||
++which
|
||||
if(1)
|
||||
sat = (sat << 4) | ch
|
||||
if(digits == (usealpha ? 4 : 2)) ++which
|
||||
if(digits == (usealpha ? 4 : 2))
|
||||
++which
|
||||
if(2)
|
||||
val = (val << 4) | ch
|
||||
if(digits == (usealpha ? 2 : 0)) ++which
|
||||
if(digits == (usealpha ? 2 : 0))
|
||||
++which
|
||||
if(3)
|
||||
alpha = (alpha << 4) | ch
|
||||
|
||||
. = list(hue, sat, val)
|
||||
if(usealpha) . += alpha
|
||||
if(usealpha)
|
||||
. += alpha
|
||||
|
||||
/proc/HSVtoRGB(hsv)
|
||||
if(!hsv) return "#000000"
|
||||
if(!hsv)
|
||||
return "#000000"
|
||||
var/list/HSV = ReadHSV(hsv)
|
||||
if(!HSV) return "#000000"
|
||||
if(!HSV)
|
||||
return "#000000"
|
||||
|
||||
var/hue = HSV[1]
|
||||
var/sat = HSV[2]
|
||||
@@ -407,27 +438,30 @@ world
|
||||
|
||||
// Compress hue into easier-to-manage range
|
||||
hue -= hue >> 8
|
||||
if(hue >= 0x5fa) hue -= 0x5fa
|
||||
if(hue >= 0x5fa)
|
||||
hue -= 0x5fa
|
||||
|
||||
var/hi,mid,lo,r,g,b
|
||||
hi = val
|
||||
lo = round((255 - sat) * val / 255, 1)
|
||||
mid = lo + round(abs(round(hue, 510) - hue) * (hi - lo) / 255, 1)
|
||||
if(hue >= 765)
|
||||
if(hue >= 1275) {r=hi; g=lo; b=mid}
|
||||
if(hue >= 1275) {r=hi; g=lo; b=mid}
|
||||
else if(hue >= 1020) {r=mid; g=lo; b=hi }
|
||||
else {r=lo; g=mid; b=hi }
|
||||
else {r=lo; g=mid; b=hi }
|
||||
else
|
||||
if(hue >= 510) {r=lo; g=hi; b=mid}
|
||||
else if(hue >= 255) {r=mid; g=hi; b=lo }
|
||||
else {r=hi; g=mid; b=lo }
|
||||
if(hue >= 510) {r=lo; g=hi; b=mid}
|
||||
else if(hue >= 255) {r=mid; g=hi; b=lo }
|
||||
else {r=hi; g=mid; b=lo }
|
||||
|
||||
return (HSV.len > 3) ? rgb(r,g,b,HSV[4]) : rgb(r,g,b)
|
||||
|
||||
/proc/RGBtoHSV(rgb)
|
||||
if(!rgb) return "#0000000"
|
||||
if(!rgb)
|
||||
return "#0000000"
|
||||
var/list/RGB = ReadRGB(rgb)
|
||||
if(!RGB) return "#0000000"
|
||||
if(!RGB)
|
||||
return "#0000000"
|
||||
|
||||
var/r = RGB[1]
|
||||
var/g = RGB[2]
|
||||
@@ -456,15 +490,22 @@ world
|
||||
return hsv(hue, sat, val, (RGB.len>3 ? RGB[4] : null))
|
||||
|
||||
/proc/hsv(hue, sat, val, alpha)
|
||||
if(hue < 0 || hue >= 1536) hue %= 1536
|
||||
if(hue < 0) hue += 1536
|
||||
if(hue < 0 || hue >= 1536)
|
||||
hue %= 1536
|
||||
if(hue < 0)
|
||||
hue += 1536
|
||||
if((hue & 0xFF) == 0xFF)
|
||||
++hue
|
||||
if(hue >= 1536) hue = 0
|
||||
if(sat < 0) sat = 0
|
||||
if(sat > 255) sat = 255
|
||||
if(val < 0) val = 0
|
||||
if(val > 255) val = 255
|
||||
if(hue >= 1536)
|
||||
hue = 0
|
||||
if(sat < 0)
|
||||
sat = 0
|
||||
if(sat > 255)
|
||||
sat = 255
|
||||
if(val < 0)
|
||||
val = 0
|
||||
if(val > 255)
|
||||
val = 255
|
||||
. = "#"
|
||||
. += TO_HEX_DIGIT(hue >> 8)
|
||||
. += TO_HEX_DIGIT(hue >> 4)
|
||||
@@ -474,8 +515,10 @@ world
|
||||
. += TO_HEX_DIGIT(val >> 4)
|
||||
. += TO_HEX_DIGIT(val)
|
||||
if(!isnull(alpha))
|
||||
if(alpha < 0) alpha = 0
|
||||
if(alpha > 255) alpha = 255
|
||||
if(alpha < 0)
|
||||
alpha = 0
|
||||
if(alpha > 255)
|
||||
alpha = 255
|
||||
. += TO_HEX_DIGIT(alpha >> 4)
|
||||
. += TO_HEX_DIGIT(alpha)
|
||||
|
||||
@@ -493,32 +536,44 @@ world
|
||||
var/list/HSV2 = ReadHSV(hsv2)
|
||||
|
||||
// add missing alpha if needed
|
||||
if(HSV1.len < HSV2.len) HSV1 += 255
|
||||
else if(HSV2.len < HSV1.len) HSV2 += 255
|
||||
if(HSV1.len < HSV2.len)
|
||||
HSV1 += 255
|
||||
else if(HSV2.len < HSV1.len)
|
||||
HSV2 += 255
|
||||
var/usealpha = HSV1.len > 3
|
||||
|
||||
// normalize hsv values in case anything is screwy
|
||||
if(HSV1[1] > 1536) HSV1[1] %= 1536
|
||||
if(HSV2[1] > 1536) HSV2[1] %= 1536
|
||||
if(HSV1[1] < 0) HSV1[1] += 1536
|
||||
if(HSV2[1] < 0) HSV2[1] += 1536
|
||||
if(HSV1[1] > 1536)
|
||||
HSV1[1] %= 1536
|
||||
if(HSV2[1] > 1536)
|
||||
HSV2[1] %= 1536
|
||||
if(HSV1[1] < 0)
|
||||
HSV1[1] += 1536
|
||||
if(HSV2[1] < 0)
|
||||
HSV2[1] += 1536
|
||||
if(!HSV1[3]) {HSV1[1] = 0; HSV1[2] = 0}
|
||||
if(!HSV2[3]) {HSV2[1] = 0; HSV2[2] = 0}
|
||||
|
||||
// no value for one color means don't change saturation
|
||||
if(!HSV1[3]) HSV1[2] = HSV2[2]
|
||||
if(!HSV2[3]) HSV2[2] = HSV1[2]
|
||||
if(!HSV1[3])
|
||||
HSV1[2] = HSV2[2]
|
||||
if(!HSV2[3])
|
||||
HSV2[2] = HSV1[2]
|
||||
// no saturation for one color means don't change hues
|
||||
if(!HSV1[2]) HSV1[1] = HSV2[1]
|
||||
if(!HSV2[2]) HSV2[1] = HSV1[1]
|
||||
if(!HSV1[2])
|
||||
HSV1[1] = HSV2[1]
|
||||
if(!HSV2[2])
|
||||
HSV2[1] = HSV1[1]
|
||||
|
||||
// Compress hues into easier-to-manage range
|
||||
HSV1[1] -= HSV1[1] >> 8
|
||||
HSV2[1] -= HSV2[1] >> 8
|
||||
|
||||
var/hue_diff = HSV2[1] - HSV1[1]
|
||||
if(hue_diff > 765) hue_diff -= 1530
|
||||
else if(hue_diff <= -765) hue_diff += 1530
|
||||
if(hue_diff > 765)
|
||||
hue_diff -= 1530
|
||||
else if(hue_diff <= -765)
|
||||
hue_diff += 1530
|
||||
|
||||
var/hue = round(HSV1[1] + hue_diff * amount, 1)
|
||||
var/sat = round(HSV1[2] + (HSV2[2] - HSV1[2]) * amount, 1)
|
||||
@@ -526,8 +581,10 @@ world
|
||||
var/alpha = usealpha ? round(HSV1[4] + (HSV2[4] - HSV1[4]) * amount, 1) : null
|
||||
|
||||
// normalize hue
|
||||
if(hue < 0 || hue >= 1530) hue %= 1530
|
||||
if(hue < 0) hue += 1530
|
||||
if(hue < 0 || hue >= 1530)
|
||||
hue %= 1530
|
||||
if(hue < 0)
|
||||
hue += 1530
|
||||
// decompress hue
|
||||
hue += round(hue / 255)
|
||||
|
||||
@@ -547,8 +604,10 @@ world
|
||||
var/list/RGB2 = ReadRGB(rgb2)
|
||||
|
||||
// add missing alpha if needed
|
||||
if(RGB1.len < RGB2.len) RGB1 += 255
|
||||
else if(RGB2.len < RGB1.len) RGB2 += 255
|
||||
if(RGB1.len < RGB2.len)
|
||||
RGB1 += 255
|
||||
else if(RGB2.len < RGB1.len)
|
||||
RGB2 += 255
|
||||
var/usealpha = RGB1.len > 3
|
||||
|
||||
var/r = round(RGB1[1] + (RGB2[1] - RGB1[1]) * amount, 1)
|
||||
@@ -563,15 +622,18 @@ world
|
||||
|
||||
/proc/HueToAngle(hue)
|
||||
// normalize hsv in case anything is screwy
|
||||
if(hue < 0 || hue >= 1536) hue %= 1536
|
||||
if(hue < 0) hue += 1536
|
||||
if(hue < 0 || hue >= 1536)
|
||||
hue %= 1536
|
||||
if(hue < 0)
|
||||
hue += 1536
|
||||
// Compress hue into easier-to-manage range
|
||||
hue -= hue >> 8
|
||||
return hue / (1530/360)
|
||||
|
||||
/proc/AngleToHue(angle)
|
||||
// normalize hsv in case anything is screwy
|
||||
if(angle < 0 || angle >= 360) angle -= 360 * round(angle / 360)
|
||||
if(angle < 0 || angle >= 360)
|
||||
angle -= 360 * round(angle / 360)
|
||||
var/hue = angle * (1530/360)
|
||||
// Decompress hue
|
||||
hue += round(hue / 255)
|
||||
@@ -583,18 +645,23 @@ world
|
||||
var/list/HSV = ReadHSV(hsv)
|
||||
|
||||
// normalize hsv in case anything is screwy
|
||||
if(HSV[1] >= 1536) HSV[1] %= 1536
|
||||
if(HSV[1] < 0) HSV[1] += 1536
|
||||
if(HSV[1] >= 1536)
|
||||
HSV[1] %= 1536
|
||||
if(HSV[1] < 0)
|
||||
HSV[1] += 1536
|
||||
|
||||
// Compress hue into easier-to-manage range
|
||||
HSV[1] -= HSV[1] >> 8
|
||||
|
||||
if(angle < 0 || angle >= 360) angle -= 360 * round(angle / 360)
|
||||
if(angle < 0 || angle >= 360)
|
||||
angle -= 360 * round(angle / 360)
|
||||
HSV[1] = round(HSV[1] + angle * (1530/360), 1)
|
||||
|
||||
// normalize hue
|
||||
if(HSV[1] < 0 || HSV[1] >= 1530) HSV[1] %= 1530
|
||||
if(HSV[1] < 0) HSV[1] += 1530
|
||||
if(HSV[1] < 0 || HSV[1] >= 1530)
|
||||
HSV[1] %= 1530
|
||||
if(HSV[1] < 0)
|
||||
HSV[1] += 1530
|
||||
// decompress hue
|
||||
HSV[1] += round(HSV[1] / 255)
|
||||
|
||||
@@ -614,8 +681,10 @@ world
|
||||
var/gray = RGB[1]*0.3 + RGB[2]*0.59 + RGB[3]*0.11
|
||||
var/tone_gray = TONE[1]*0.3 + TONE[2]*0.59 + TONE[3]*0.11
|
||||
|
||||
if(gray <= tone_gray) return BlendRGB("#000000", tone, gray/(tone_gray || 1))
|
||||
else return BlendRGB(tone, "#ffffff", (gray-tone_gray)/((255-tone_gray) || 1))
|
||||
if(gray <= tone_gray)
|
||||
return BlendRGB("#000000", tone, gray/(tone_gray || 1))
|
||||
else
|
||||
return BlendRGB(tone, "#ffffff", (gray-tone_gray)/((255-tone_gray) || 1))
|
||||
|
||||
|
||||
//Used in the OLD chem colour mixing algorithm
|
||||
@@ -715,7 +784,8 @@ The _flatIcons list is a cache for generated icon files.
|
||||
var/image/I = current
|
||||
currentLayer = I.layer
|
||||
if(currentLayer<0) // Special case for FLY_LAYER
|
||||
if(currentLayer <= -1000) return flat
|
||||
if(currentLayer <= -1000)
|
||||
return flat
|
||||
if(pSet == 0) // Underlay
|
||||
currentLayer = A.layer+currentLayer/1000
|
||||
else // Overlay
|
||||
|
||||
@@ -13,7 +13,8 @@ GLOBAL_LIST_INIT(sqrtTable, list(1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4,
|
||||
return x!=0?x/abs(x):0
|
||||
|
||||
/proc/Atan2(x, y)
|
||||
if(!x && !y) return 0
|
||||
if(!x && !y)
|
||||
return 0
|
||||
var/a = arccos(x / sqrt(x*x + y*y))
|
||||
return y >= 0 ? a : -a
|
||||
|
||||
@@ -103,10 +104,12 @@ GLOBAL_LIST_INIT(sqrtTable, list(1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4,
|
||||
. = list()
|
||||
var/d = b*b - 4 * a * c
|
||||
var/bottom = 2 * a
|
||||
if(d < 0) return
|
||||
if(d < 0)
|
||||
return
|
||||
var/root = sqrt(d)
|
||||
. += (-b + root) / bottom
|
||||
if(!d) return
|
||||
if(!d)
|
||||
return
|
||||
. += (-b - root) / bottom
|
||||
|
||||
// tangent
|
||||
|
||||
@@ -11,7 +11,14 @@
|
||||
return
|
||||
|
||||
for(var/i in 1 to location.contents.len)
|
||||
var/static/list/ignored_things = typecacheof(list(/mob/dead, /obj/effect, /obj/docking_port, /turf, /atom/movable/lighting_object, /mob/camera))
|
||||
var/static/list/ignored_things = typecacheof(list( // These types will never have radiation applied to them or be looked inside of
|
||||
/mob/dead,
|
||||
/mob/camera,
|
||||
/obj/effect,
|
||||
/obj/docking_port,
|
||||
/atom/movable/lighting_object
|
||||
))
|
||||
|
||||
var/atom/thing = location.contents[i]
|
||||
if(ignored_things[thing.type])
|
||||
continue
|
||||
|
||||
@@ -137,7 +137,8 @@ Turf and target are separate in case you want to teleport some distance from a t
|
||||
return
|
||||
if(destination.y>world.maxy || destination.y<1)
|
||||
return
|
||||
else return
|
||||
else
|
||||
return
|
||||
|
||||
return destination
|
||||
|
||||
@@ -502,12 +503,20 @@ Turf and target are separate in case you want to teleport some distance from a t
|
||||
var/y=arcsin(x/sqrt(1+x*x))
|
||||
return y
|
||||
|
||||
/atom/proc/GetAllContents(list/output=list())
|
||||
. = output
|
||||
output += src
|
||||
for(var/i in 1 to contents.len)
|
||||
var/atom/thing = contents[i]
|
||||
thing.GetAllContents(output)
|
||||
/*
|
||||
Gets all contents of contents and returns them all in a list.
|
||||
*/
|
||||
/atom/proc/GetAllContents()
|
||||
var/list/processing_list = list(src)
|
||||
var/list/assembled = list()
|
||||
while(processing_list.len)
|
||||
var/atom/A = processing_list[1]
|
||||
processing_list.Cut(1, 2)
|
||||
//Byond does not allow things to be in multiple contents, or double parent-child hierarchies, so only += is needed
|
||||
//This is also why we don't need to check against assembled as we go along
|
||||
processing_list += A.contents
|
||||
assembled += A
|
||||
return assembled
|
||||
|
||||
//Step-towards method of determining whether one atom can see another. Similar to viewers()
|
||||
/proc/can_see(atom/source, atom/target, length=5) // I couldnt be arsed to do actual raycasting :I This is horribly inaccurate.
|
||||
@@ -728,7 +737,7 @@ Turf and target are separate in case you want to teleport some distance from a t
|
||||
|
||||
*/
|
||||
|
||||
/proc/get_turf_pixel(atom/movable/AM)
|
||||
/proc/get_turf_pixel(atom/AM)
|
||||
if(!istype(AM))
|
||||
return
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
//Note: typecache can only replace istype if you know for sure the thing is at least a datum.
|
||||
|
||||
GLOBAL_LIST_INIT(typecache_mob, typecacheof(list(/mob)))
|
||||
GLOBAL_LIST_INIT(typecache_mob, typecacheof(/mob))
|
||||
|
||||
GLOBAL_LIST_INIT(typecache_living, typecacheof(list(/mob/living)))
|
||||
GLOBAL_LIST_INIT(typecache_living, typecacheof(/mob/living))
|
||||
|
||||
GLOBAL_LIST_INIT(typecache_machine_or_structure, typecacheof(list(/obj/machinery))|typecacheof(list(/obj/structure)))
|
||||
GLOBAL_LIST_INIT(typecache_machine_or_structure, typecacheof(list(/obj/machinery, /obj/structure)))
|
||||
|
||||
|
||||
@@ -76,7 +76,8 @@
|
||||
|
||||
// This is necessary for storage items not on your person.
|
||||
/obj/item/Adjacent(var/atom/neighbor, var/recurse = 1)
|
||||
if(neighbor == loc) return 1
|
||||
if(neighbor == loc)
|
||||
return 1
|
||||
if(isitem(loc))
|
||||
if(recurse > 0)
|
||||
return loc.Adjacent(neighbor,recurse - 1)
|
||||
|
||||
@@ -6,11 +6,12 @@
|
||||
almost anything into a trash can.
|
||||
*/
|
||||
/atom/MouseDrop(atom/over, src_location, over_location, src_control, over_control, params)
|
||||
if(!usr || !over)
|
||||
if(!usr || !over)
|
||||
return
|
||||
if(over == src)
|
||||
return usr.client.Click(src, src_location, src_control, params)
|
||||
if(!Adjacent(usr) || !over.Adjacent(usr)) return // should stop you from dragging through windows
|
||||
if(!Adjacent(usr) || !over.Adjacent(usr))
|
||||
return // should stop you from dragging through windows
|
||||
|
||||
over.MouseDrop_T(src,usr)
|
||||
return
|
||||
|
||||
@@ -173,7 +173,7 @@
|
||||
|
||||
/obj/screen/alert/verygross
|
||||
name = "Very grossed out."
|
||||
desc = "I'm not feeling very well.."
|
||||
desc = "You're not feeling very well..."
|
||||
icon_state = "gross2"
|
||||
|
||||
/obj/screen/alert/disgusted
|
||||
@@ -491,8 +491,10 @@ so as to remain in compliance with the most up-to-date laws."
|
||||
var/atom/target = null
|
||||
|
||||
/obj/screen/alert/hackingapc/Click()
|
||||
if(!usr || !usr.client) return
|
||||
if(!target) return
|
||||
if(!usr || !usr.client)
|
||||
return
|
||||
if(!target)
|
||||
return
|
||||
var/mob/living/silicon/ai/AI = usr
|
||||
var/turf/T = get_turf(target)
|
||||
if(T)
|
||||
@@ -515,7 +517,8 @@ so as to remain in compliance with the most up-to-date laws."
|
||||
timeout = 300
|
||||
|
||||
/obj/screen/alert/notify_cloning/Click()
|
||||
if(!usr || !usr.client) return
|
||||
if(!usr || !usr.client)
|
||||
return
|
||||
var/mob/dead/observer/G = usr
|
||||
G.reenter_corpse()
|
||||
|
||||
@@ -528,10 +531,13 @@ so as to remain in compliance with the most up-to-date laws."
|
||||
var/action = NOTIFY_JUMP
|
||||
|
||||
/obj/screen/alert/notify_action/Click()
|
||||
if(!usr || !usr.client) return
|
||||
if(!target) return
|
||||
if(!usr || !usr.client)
|
||||
return
|
||||
if(!target)
|
||||
return
|
||||
var/mob/dead/observer/G = usr
|
||||
if(!istype(G)) return
|
||||
if(!istype(G))
|
||||
return
|
||||
switch(action)
|
||||
if(NOTIFY_ATTACK)
|
||||
target.attack_ghost(G)
|
||||
|
||||
@@ -180,7 +180,8 @@
|
||||
|
||||
|
||||
/datum/hud/proc/toggle_show_robot_modules()
|
||||
if(!iscyborg(mymob)) return
|
||||
if(!iscyborg(mymob))
|
||||
return
|
||||
|
||||
var/mob/living/silicon/robot/R = mymob
|
||||
|
||||
@@ -188,7 +189,8 @@
|
||||
update_robot_modules_display()
|
||||
|
||||
/datum/hud/proc/update_robot_modules_display(mob/viewer)
|
||||
if(!iscyborg(mymob)) return
|
||||
if(!iscyborg(mymob))
|
||||
return
|
||||
|
||||
var/mob/living/silicon/robot/R = mymob
|
||||
|
||||
|
||||
@@ -251,7 +251,7 @@
|
||||
to_chat(C, "<span class='notice'>You are no longer running on internals.</span>")
|
||||
icon_state = "internal0"
|
||||
else
|
||||
if(!C.getorganslot("breathing_tube"))
|
||||
if(!C.getorganslot(ORGAN_SLOT_BREATHING_TUBE))
|
||||
if(!istype(C.wear_mask, /obj/item/clothing/mask))
|
||||
to_chat(C, "<span class='warning'>You are not wearing an internals mask!</span>")
|
||||
return 1
|
||||
@@ -325,7 +325,8 @@
|
||||
usr.stop_pulling()
|
||||
|
||||
/obj/screen/pull/update_icon(mob/mymob)
|
||||
if(!mymob) return
|
||||
if(!mymob)
|
||||
return
|
||||
if(mymob.pulling)
|
||||
icon_state = "pull"
|
||||
else
|
||||
|
||||
@@ -44,8 +44,8 @@
|
||||
else if(hitsound)
|
||||
playsound(loc, hitsound, get_clamped_volume(), 1, -1)
|
||||
|
||||
user.lastattacked = M
|
||||
M.lastattacker = user
|
||||
M.lastattacker = user.real_name
|
||||
M.lastattackerckey = user.ckey
|
||||
|
||||
user.do_attack_animation(M)
|
||||
M.attacked_by(src, user)
|
||||
|
||||
@@ -190,13 +190,15 @@
|
||||
needs_permit = 0
|
||||
mag_type = /obj/item/ammo_box/magazine/toy/x9
|
||||
casing_ejector = 0
|
||||
spread = 45 //MAXIMUM XCOM MEMES (actually that'd be 90 spread)
|
||||
spread = 90 //MAXIMUM XCOM MEMES (actually that'd be 180 spread)
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
weapon_weight = WEAPON_HEAVY
|
||||
|
||||
/datum/design/foam_x9
|
||||
name = "Foam Force X9 Rifle"
|
||||
id = "foam_x9"
|
||||
build_type = AUTOLATHE
|
||||
materials = list(MAT_METAL = 20000, MAT_GLASS = 10000)
|
||||
materials = list(MAT_METAL = 24000, MAT_GLASS = 14000)
|
||||
build_path = /obj/item/gun/ballistic/automatic/x9/toy
|
||||
category = list("hacked", "Misc")
|
||||
|
||||
@@ -496,6 +498,9 @@
|
||||
mag_type = /obj/item/ammo_box/magazine/toy/foamag
|
||||
casing_ejector = FALSE
|
||||
origin_tech = "combat=2;engineering=2;magnets=2"
|
||||
spread = 60
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
weapon_weight = WEAPON_HEAVY
|
||||
|
||||
/datum/design/foam_magrifle
|
||||
name = "Foam Force MagRifle"
|
||||
@@ -635,7 +640,7 @@
|
||||
name = "MagTag Hyper Rifle"
|
||||
id = "foam_hyperburst"
|
||||
build_type = AUTOLATHE
|
||||
materials = list(MAT_METAL = 35000, MAT_GLASS = 15000)
|
||||
materials = list(MAT_METAL = 35000, MAT_GLASS = 25000)
|
||||
build_path = /obj/item/gun/energy/laser/practice/hyperburst
|
||||
category = list("hacked", "Misc")
|
||||
|
||||
@@ -680,6 +685,7 @@
|
||||
suppressed = TRUE
|
||||
burst_size = 1
|
||||
fire_delay = 0
|
||||
spread = 60
|
||||
actions_types = list()
|
||||
|
||||
/obj/item/gun/ballistic/automatic/toy/pistol/stealth/update_icon()
|
||||
@@ -695,7 +701,7 @@
|
||||
name = "Foam Force Stealth Pistol"
|
||||
id = "foam_sp"
|
||||
build_type = AUTOLATHE
|
||||
materials = list(MAT_METAL = 15000, MAT_GLASS = 1000)
|
||||
materials = list(MAT_METAL = 30000, MAT_GLASS = 15000)
|
||||
build_path = /obj/item/gun/ballistic/automatic/toy/pistol/stealth
|
||||
category = list("hacked", "Misc")
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
return
|
||||
if(!crewMind.assigned_role)
|
||||
return
|
||||
if(ROLE_MISCREANT in crewMind.current.client.prefs.be_special)
|
||||
if(!(ROLE_MISCREANT in crewMind.current.client.prefs.be_special))
|
||||
return
|
||||
if(jobban_isbanned(crewMind, "Syndicate"))
|
||||
return
|
||||
|
||||
@@ -166,17 +166,8 @@
|
||||
/obj/item/clothing/mask/gas/stalker
|
||||
name = "S.T.A.L.K.E.R. mask"
|
||||
desc = "Smells like reactor four."
|
||||
icon = 'icons/obj/custom.dmi'
|
||||
item_state = "stalker"
|
||||
icon_state = "stalker"
|
||||
flags_1 = BLOCK_GAS_SMOKE_EFFECT_1 | MASKINTERNALS_1
|
||||
flags_inv = HIDEEARS|HIDEEYES|HIDEFACE|HIDEFACIALHAIR
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
item_state = "gas_alt"
|
||||
gas_transfer_coefficient = 0.01
|
||||
permeability_coefficient = 0.01
|
||||
flags_cover = MASKCOVERSEYES | MASKCOVERSMOUTH
|
||||
resistance_flags = 0
|
||||
|
||||
|
||||
/*Sylas*/
|
||||
@@ -201,4 +192,9 @@
|
||||
can_adjust = 0
|
||||
|
||||
|
||||
/obj/item/clothing/shoes/sneakers/pink
|
||||
icon_state = "pink"
|
||||
item_state = "pink"
|
||||
|
||||
|
||||
|
||||
|
||||
+216
-254
@@ -111,10 +111,10 @@
|
||||
var/list/env_gases = environment.gases
|
||||
|
||||
environment.assert_gases(arglist(GLOB.hardcoded_gases))
|
||||
var/o2_concentration = env_gases["o2"][MOLES]/total_moles
|
||||
var/n2_concentration = env_gases["n2"][MOLES]/total_moles
|
||||
var/co2_concentration = env_gases["co2"][MOLES]/total_moles
|
||||
var/plasma_concentration = env_gases["plasma"][MOLES]/total_moles
|
||||
var/o2_concentration = env_gases[/datum/gas/oxygen][MOLES]/total_moles
|
||||
var/n2_concentration = env_gases[/datum/gas/nitrogen][MOLES]/total_moles
|
||||
var/co2_concentration = env_gases[/datum/gas/carbon_dioxide][MOLES]/total_moles
|
||||
var/plasma_concentration = env_gases[/datum/gas/plasma][MOLES]/total_moles
|
||||
environment.garbage_collect()
|
||||
|
||||
if(abs(n2_concentration - N2STANDARD) < 20)
|
||||
@@ -321,8 +321,8 @@
|
||||
//Sleeper
|
||||
|
||||
/obj/item/device/dogborg/sleeper
|
||||
name = "Medbelly"
|
||||
desc = "Equipment for medical hound. A mounted sleeper that stabilizes patients and can inject reagents in the borg's reserves."
|
||||
name = "hound sleeper"
|
||||
desc = "nothing should see this."
|
||||
icon = 'icons/mob/dogborg.dmi'
|
||||
icon_state = "sleeper"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
@@ -330,12 +330,38 @@
|
||||
var/mob/living/silicon/robot/hound = null
|
||||
var/inject_amount = 10
|
||||
var/min_health = -100
|
||||
var/cleaning = 0
|
||||
var/cleaning = FALSE
|
||||
var/cleaning_cycles = 10
|
||||
var/patient_laststat = null
|
||||
var/mob_energy = 30000 //Energy gained from digesting mobs (including PCs)
|
||||
var/list/injection_chems = list("antitoxin", "morphine", "salbutamol", "bicaridine", "kelotane"),
|
||||
var/list/injection_chems = list("antitoxin", "epinephrine", "morphine", "salbutamol", "bicaridine", "kelotane")
|
||||
var/eject_port = "ingestion"
|
||||
var/list/items_preserved = list()
|
||||
var/escape_in_progress = FALSE
|
||||
var/message_cooldown
|
||||
var/breakout_time = 300
|
||||
var/list/items_preserved = list(
|
||||
/obj/item/hand_tele,
|
||||
/obj/item/card/id,
|
||||
/obj/item/device/pda,
|
||||
/obj/item/device/aicard,
|
||||
/obj/item/gun,
|
||||
/obj/item/pinpointer,
|
||||
/obj/item/clothing/shoes/magboots,
|
||||
/obj/item/clothing/head/helmet/space,
|
||||
/obj/item/clothing/suit/space,
|
||||
/obj/item/reagent_containers/hypospray/CMO,
|
||||
/obj/item/tank/jetpack/oxygen/captain,
|
||||
/obj/item/clothing/accessory/medal/gold/captain,
|
||||
/obj/item/clothing/suit/armor,
|
||||
/obj/item/documents,
|
||||
/obj/item/nuke_core,
|
||||
/obj/item/nuke_core_container,
|
||||
/obj/item/areaeditor/blueprints,
|
||||
/obj/item/documents/syndicate,
|
||||
/obj/item/disk/nuclear,
|
||||
/obj/item/bombcore,
|
||||
/obj/item/grenade
|
||||
)
|
||||
|
||||
var/list/important_items = list(
|
||||
/obj/item/hand_tele,
|
||||
/obj/item/card/id/captains_spare,
|
||||
@@ -356,10 +382,12 @@
|
||||
/obj/item/documents/syndicate,
|
||||
/obj/item/disk/nuclear,
|
||||
/obj/item/bombcore,
|
||||
/obj/item/grenade)
|
||||
/obj/item/grenade
|
||||
)
|
||||
|
||||
/obj/item/device/dogborg/sleeper/New()
|
||||
..()
|
||||
update_icon()
|
||||
flags_1 |= NOBLUDGEON_1 //No more attack messages
|
||||
|
||||
/obj/item/device/dogborg/sleeper/Exit(atom/movable/O)
|
||||
@@ -371,16 +399,13 @@
|
||||
return
|
||||
if(!ishuman(target))
|
||||
return
|
||||
if(!target.devourable)
|
||||
to_chat(user, "<span class='warning'>This person is incompatible with our equipment.</span>")
|
||||
return
|
||||
if(target.buckled)
|
||||
to_chat(user, "<span class='warning'>The user is buckled and can not be put into your [src.name].</span>")
|
||||
return
|
||||
if(patient)
|
||||
to_chat(user, "<span class='warning'>Your [src.name] is already occupied.</span>")
|
||||
return
|
||||
user.visible_message("<span class='warning'>[hound.name] is ingesting [target.name] into their [src.name].</span>", "<span class='notice'>You start ingesting [target] into your [src]...</span>")
|
||||
user.visible_message("<span class='warning'>[hound.name] is carefully inserting [target.name] into their [src.name].</span>", "<span class='notice'>You start placing [target] into your [src]...</span>")
|
||||
if(!patient && ishuman(target) && !target.buckled && do_after (user, 50, target = target))
|
||||
|
||||
if(!in_range(src, target)) //Proximity is probably old news by now, do a new check.
|
||||
@@ -389,18 +414,42 @@
|
||||
if(patient) return //If you try to eat two people at once, you can only eat one.
|
||||
|
||||
else //If you don't have someone in you, proceed.
|
||||
if(!isslimeperson(target) && ("toxin" in injection_chems))
|
||||
injection_chems -= "toxin"
|
||||
injection_chems += "antitoxin"
|
||||
if(isslimeperson(target) && !("toxin" in injection_chems))
|
||||
injection_chems -= "antitoxin"
|
||||
injection_chems += "toxin"
|
||||
target.forceMove(src)
|
||||
target.reset_perspective(src)
|
||||
update_patient()
|
||||
update_gut()
|
||||
START_PROCESSING(SSobj, src)
|
||||
user.visible_message("<span class='warning'>[hound.name]'s medical pod lights up as [target.name] slips inside into their [src.name].</span>", "<span class='notice'>Your medical pod lights up as [target] slips into your [src]. Life support functions engaged.</span>")
|
||||
user.visible_message("<span class='warning'>[hound.name]'s medical pod lights up and expands as [target.name] slips inside into their [src.name].</span>", "<span class='notice'>Your medical pod lights up as [target] slips into your [src]. Life support functions engaged.</span>")
|
||||
message_admins("[key_name(hound)] has eaten [key_name(patient)] as a dogborg. ([hound ? "<a href='?_src_=holder;adminplayerobservecoodjump=1;X=[hound.x];Y=[hound.y];Z=[hound.z]'>JMP</a>" : "null"])")
|
||||
playsound(hound, 'sound/effects/bin_close.ogg', 100, 1)
|
||||
|
||||
/obj/item/device/dogborg/sleeper/container_resist(mob/living/user)
|
||||
hound = loc
|
||||
user.changeNext_move(CLICK_CD_BREAKOUT)
|
||||
user.last_special = world.time + CLICK_CD_BREAKOUT
|
||||
if(user.a_intent == INTENT_HELP)
|
||||
return
|
||||
user.visible_message("<span class='notice'>You see [user] kicking against the expanded material of [hound.name]'s gut!</span>", \
|
||||
"<span class='notice'>You struggle inside [src], kicking the release with your foot... (this will take about [DisplayTimeText(breakout_time)].)</span>", \
|
||||
"<span class='italics'>You hear a thump from [hound.name].</span>")
|
||||
if(do_after(user, breakout_time, target = src))
|
||||
if(!user || user.stat != CONSCIOUS || user.loc != src )
|
||||
return
|
||||
user.visible_message("<span class='warning'>[user] successfully broke out of [hound.name]!</span>", \
|
||||
"<span class='notice'>You successfully break out of [hound.name]!</span>")
|
||||
go_out()
|
||||
|
||||
/obj/item/device/dogborg/sleeper/proc/go_out(var/target)
|
||||
hound = src.loc
|
||||
testing("go_out activated")
|
||||
hound.setClickCooldown(50)
|
||||
if(length(contents) > 0)
|
||||
hound.visible_message("<span class='warning'>[hound.name] empties out their contents via their [eject_port] port.</span>", "<span class='notice'>You empty your contents via your [eject_port] port.</span>")
|
||||
hound.visible_message("<span class='warning'>[hound.name] empties out their contents via their release port.</span>", "<span class='notice'>You empty your contents via your release port.</span>")
|
||||
if(target)
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/person = target
|
||||
@@ -419,199 +468,103 @@
|
||||
var/obj/T = C
|
||||
T.loc = hound.loc
|
||||
items_preserved.Cut()
|
||||
cleaning = 0
|
||||
update_gut()
|
||||
cleaning = FALSE
|
||||
playsound(loc, 'sound/effects/splat.ogg', 50, 1)
|
||||
update_patient()
|
||||
|
||||
else //You clicked eject with nothing in you, let's just reset stuff to be sure.
|
||||
items_preserved.Cut()
|
||||
cleaning = 0
|
||||
update_patient()
|
||||
|
||||
/obj/item/device/dogborg/sleeper/proc/drain(var/amt = 3) //Slightly reduced cost (before, it was always injecting inaprov)
|
||||
if (amt > 0)
|
||||
hound.cell.give(amt)
|
||||
else
|
||||
hound.cell.use(amt)
|
||||
cleaning = FALSE
|
||||
hound.visible_message("<span class='warning'>[hound.name] belches, torso flexing.</span>")
|
||||
update_gut()
|
||||
|
||||
/obj/item/device/dogborg/sleeper/attack_self(mob/user)
|
||||
if(..())
|
||||
return
|
||||
sleeperUI(user)
|
||||
ui_interact(user)
|
||||
|
||||
/obj/item/device/dogborg/sleeper/proc/sleeperUI(mob/user)
|
||||
var/dat
|
||||
dat += "<h3>Injector</h3>"
|
||||
/obj/item/device/dogborg/sleeper/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state)
|
||||
|
||||
if(patient && !(patient.stat & DEAD))
|
||||
dat += "<A href='?src=\ref[src];inject=epinephrine'>Inject Epinephrine</A>"
|
||||
else
|
||||
dat += "<span class='linkOff'>Inject Epinephrine</span>"
|
||||
if(patient && patient.health > min_health)
|
||||
for(var/re in injection_chems)
|
||||
var/datum/reagent/C = GLOB.chemical_reagents_list[re]
|
||||
if(C)
|
||||
dat += "<BR><A href='?src=\ref[src];inject=[C.id]'>Inject [C.name]</A>"
|
||||
else
|
||||
for(var/re in injection_chems)
|
||||
var/datum/reagent/C = GLOB.chemical_reagents_list[re]
|
||||
if(C)
|
||||
dat += "<BR><span class='linkOff'>Inject [C.name]</span>"
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "dogborg_sleeper", name, 375, 550, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
dat += "<h3>Sleeper Status</h3>"
|
||||
dat += "<A id='refbutton' href='?src=\ref[src];refresh=1'>Refresh</A>"
|
||||
dat += "<A href='?src=\ref[src];eject=1'>Eject All</A>"
|
||||
dat += "<A href='?src=\ref[src];port=1'>Eject port: [eject_port]</A>"
|
||||
if(!cleaning)
|
||||
dat += "<A href='?src=\ref[src];clean=1'>Self-Clean</A>"
|
||||
else
|
||||
dat += "<span class='linkOff'>Self-Clean</span>"
|
||||
/obj/item/device/dogborg/sleeper/ui_data()
|
||||
var/list/data = list()
|
||||
data["occupied"] = patient ? 1 : 0
|
||||
|
||||
dat += "<div class='statusDisplay'>"
|
||||
|
||||
//Cleaning and there are still un-preserved items
|
||||
if(cleaning && length(contents - items_preserved))
|
||||
dat += "<font color='red'><B>Self-cleaning mode.</B> [length(contents - items_preserved)] object(s) remaining.</font><BR>"
|
||||
data["items"] = "Self-cleaning mode active: [length(contents - items_preserved)] object(s) remaining."
|
||||
data["cleaning"] = cleaning
|
||||
if(injection_chems != null)
|
||||
data["chem"] = list()
|
||||
for(var/chem in injection_chems)
|
||||
var/datum/reagent/R = GLOB.chemical_reagents_list[chem]
|
||||
data["chem"] += list(list("name" = R.name, "id" = R.id))
|
||||
|
||||
//There are no items to be processed other than un-preserved items
|
||||
else if(cleaning && length(items_preserved))
|
||||
dat += "<font color='red'><B>Self-cleaning done. Eject remaining objects now.</B></font><BR>"
|
||||
data["occupant"] = list()
|
||||
var/mob/living/mob_occupant = patient
|
||||
if(mob_occupant)
|
||||
data["occupant"]["name"] = mob_occupant.name
|
||||
switch(mob_occupant.stat)
|
||||
if(CONSCIOUS)
|
||||
data["occupant"]["stat"] = "Conscious"
|
||||
data["occupant"]["statstate"] = "good"
|
||||
if(SOFT_CRIT)
|
||||
data["occupant"]["stat"] = "Conscious"
|
||||
data["occupant"]["statstate"] = "average"
|
||||
if(UNCONSCIOUS)
|
||||
data["occupant"]["stat"] = "Unconscious"
|
||||
data["occupant"]["statstate"] = "average"
|
||||
if(DEAD)
|
||||
data["occupant"]["stat"] = "Dead"
|
||||
data["occupant"]["statstate"] = "bad"
|
||||
data["occupant"]["health"] = mob_occupant.health
|
||||
data["occupant"]["maxHealth"] = mob_occupant.maxHealth
|
||||
data["occupant"]["minHealth"] = HEALTH_THRESHOLD_DEAD
|
||||
data["occupant"]["bruteLoss"] = mob_occupant.getBruteLoss()
|
||||
data["occupant"]["oxyLoss"] = mob_occupant.getOxyLoss()
|
||||
data["occupant"]["toxLoss"] = mob_occupant.getToxLoss()
|
||||
data["occupant"]["fireLoss"] = mob_occupant.getFireLoss()
|
||||
data["occupant"]["cloneLoss"] = mob_occupant.getCloneLoss()
|
||||
data["occupant"]["brainLoss"] = mob_occupant.getBrainLoss()
|
||||
data["occupant"]["reagents"] = list()
|
||||
if(mob_occupant.reagents.reagent_list.len)
|
||||
for(var/datum/reagent/R in mob_occupant.reagents.reagent_list)
|
||||
data["occupant"]["reagents"] += list(list("name" = R.name, "volume" = R.volume))
|
||||
return data
|
||||
|
||||
//Preserved items count when the list is populated
|
||||
if(length(items_preserved))
|
||||
dat += "<font color='red'>[length(items_preserved)] uncleanable object(s).</font><BR>"
|
||||
|
||||
if(!patient)
|
||||
dat += "Sleeper Unoccupied"
|
||||
else
|
||||
dat += "[patient.name] => "
|
||||
|
||||
switch(patient.stat)
|
||||
if(0)
|
||||
dat += "<span class='good'>Conscious</span>"
|
||||
if(1)
|
||||
dat += "<span class='average'>Unconscious</span>"
|
||||
else
|
||||
dat += "<span class='bad'>DEAD</span>"
|
||||
|
||||
var/healthcolor = (patient.health > 0 ? "color:white;" : "color:red;")
|
||||
var/brutecolor = (patient.getBruteLoss() < 60 ? "color:gray;" : "color:red;")
|
||||
var/o2color = (patient.getOxyLoss() < 60 ? "color:gray;" : "color:red;")
|
||||
var/toxcolor = (patient.getToxLoss() < 60 ? "color:gray;" : "color:red;")
|
||||
var/burncolor = (patient.getFireLoss() < 60 ? "color:gray;" : "color:red;")
|
||||
|
||||
dat += "<span style='[healthcolor]'>\t-Overall Health %: [round(patient.health)]</span><BR>"
|
||||
dat += "<span style='[brutecolor]'>\t-Brute Damage %: [patient.getBruteLoss()]</span><BR>"
|
||||
dat += "<span style='[o2color]'>\t-Respiratory Damage %: [patient.getOxyLoss()]</span><BR>"
|
||||
dat += "<span style='[toxcolor]'>\t-Toxin Content %: [patient.getToxLoss()]</span><BR>"
|
||||
dat += "<span style='[burncolor]'>\t-Burn Severity %: [patient.getFireLoss()]</span><BR>"
|
||||
|
||||
if(patient.getBrainLoss())
|
||||
dat += "<div class='line'><span class='average'>Significant brain damage detected.</span></div><br>"
|
||||
if(patient.getCloneLoss())
|
||||
dat += "<div class='line'><span class='average'>Patient may be improperly cloned.</span></div><br>"
|
||||
if(patient.reagents.reagent_list.len)
|
||||
for(var/datum/reagent/R in patient.reagents.reagent_list)
|
||||
dat += "<div class='line'><div style='width: 170px;' class='statusLabel'>[R.name]:</div><div class='statusValue'>[round(R.volume, 0.1)] units</div></div><br>"
|
||||
dat += "</div>"
|
||||
|
||||
var/datum/browser/popup = new(user, "sleeper", "Sleeper Console", 520, 540) //Set up the popup browser window
|
||||
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
return
|
||||
|
||||
|
||||
/obj/item/device/dogborg/sleeper/Topic(href, href_list)
|
||||
if(..() || usr == patient)
|
||||
return
|
||||
usr.set_machine(src)
|
||||
if(href_list["refresh"])
|
||||
update_patient()
|
||||
src.updateUsrDialog()
|
||||
sleeperUI(usr)
|
||||
return
|
||||
if(href_list["eject"])
|
||||
go_out()
|
||||
sleeperUI(usr)
|
||||
return
|
||||
if(href_list["clean"])
|
||||
if(!cleaning)
|
||||
var/confirm = alert(usr, "You are about to engage self-cleaning mode. This will fill your [src] with caustic enzymes to remove any objects or biomatter, and convert them into energy. Are you sure?", "Confirmation", "Self-Clean", "Cancel")
|
||||
if(confirm == "Self-Clean")
|
||||
if(cleaning)
|
||||
return
|
||||
else
|
||||
cleaning = 1
|
||||
drain(500)
|
||||
START_PROCESSING(SSobj, src)
|
||||
sleeperUI(usr)
|
||||
if(patient)
|
||||
to_chat(patient, "<span class='danger'>[hound.name]'s [src.name] fills with caustic enzymes around you!</span>")
|
||||
return
|
||||
if(cleaning)
|
||||
sleeperUI(usr)
|
||||
return
|
||||
if(href_list["port"])
|
||||
switch(eject_port)
|
||||
if("ingestion")
|
||||
eject_port = "disposal"
|
||||
if("disposal")
|
||||
eject_port = "ingestion"
|
||||
sleeperUI(usr)
|
||||
/obj/item/device/dogborg/sleeper/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
|
||||
if(patient && !(patient.stat & DEAD))
|
||||
if(href_list["inject"] == "epinephrine" || patient.health > min_health)
|
||||
inject_chem(usr, href_list["inject"])
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>ERROR: Subject is not in stable condition for injections.</span>")
|
||||
else
|
||||
to_chat(usr,"<span class='notice'>ERROR: Subject cannot metabolise chemicals.</span>")
|
||||
|
||||
src.updateUsrDialog()
|
||||
sleeperUI(usr) //Needs a callback to boop the page to refresh.
|
||||
return
|
||||
|
||||
/obj/item/device/dogborg/sleeper/proc/inject_chem(mob/user, chem)
|
||||
if(patient && patient.reagents)
|
||||
if(chem in injection_chems + "epinephrine")
|
||||
if(hound.cell.charge < 800) //This is so borgs don't kill themselves with it.
|
||||
to_chat(hound, "<span class='notice'>You don't have enough power to synthesize fluids.</span>")
|
||||
switch(action)
|
||||
if("eject")
|
||||
go_out()
|
||||
. = TRUE
|
||||
if("inject")
|
||||
var/chem = params["chem"]
|
||||
if(!patient)
|
||||
return
|
||||
else if(patient.reagents.get_reagent_amount(chem) + 10 >= 20) //Preventing people from accidentally killing themselves by trying to inject too many chemicals!
|
||||
to_chat(hound, "<span class='notice'>Your stomach is currently too full of fluids to secrete more fluids of this kind.</span>")
|
||||
else if(patient.reagents.get_reagent_amount(chem) + 10 <= 20) //No overdoses for you
|
||||
patient.reagents.add_reagent(chem, inject_amount)
|
||||
drain(750) //-750 charge per injection
|
||||
var/units = round(patient.reagents.get_reagent_amount(chem))
|
||||
to_chat(hound, "<span class='notice'>Injecting [units] unit\s of [injection_chems[chem]] into occupant.</span>") //If they were immersed, the reagents wouldn't leave with them.
|
||||
|
||||
/obj/item/device/dogborg/sleeper/process()
|
||||
|
||||
if(cleaning) //We're cleaning, return early after calling this as we don't care about the patient.
|
||||
src.clean_cycle()
|
||||
return
|
||||
|
||||
if(patient) //We're caring for the patient. Medical emergency! Or endo scene.
|
||||
update_patient()
|
||||
if(patient.health < 0)
|
||||
patient.adjustOxyLoss(-1) //Heal some oxygen damage if they're in critical condition
|
||||
patient.updatehealth()
|
||||
patient.AdjustStun(-80)
|
||||
patient.AdjustKnockdown(-80)
|
||||
patient.AdjustUnconscious(-80)
|
||||
src.drain()
|
||||
if((patient.reagents.get_reagent_amount("epinephrine") < 5) && (patient.health < patient.maxHealth)) //Stop pumping full HP people full of drugs. Don't heal people you're digesting, meanie.
|
||||
patient.reagents.add_reagent("epinephrine", 5)
|
||||
return
|
||||
|
||||
if(!patient && !cleaning) //We think we're done working.
|
||||
if(!update_patient()) //One last try to find someone
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return
|
||||
|
||||
/obj/item/device/dogborg/sleeper/proc/update_patient()
|
||||
inject_chem(chem)
|
||||
. = TRUE
|
||||
if("cleaning")
|
||||
testing("cleaning attempted")
|
||||
if(!contents)
|
||||
testing("cleaning has no contents")
|
||||
to_chat(src, "Your [src] is already cleaned.")
|
||||
return
|
||||
if(patient)
|
||||
to_chat(patient, "<span class='danger'>[hound.name]'s [src.name] fills with caustic enzymes around you!</span>")
|
||||
testing("clean_cycle activated")
|
||||
to_chat(src, "<span class='danger'>Cleaning process enabled.</span>")
|
||||
clean_cycle()
|
||||
. = TRUE
|
||||
|
||||
/obj/item/device/dogborg/sleeper/proc/update_gut()
|
||||
testing("update_gut proc fired")
|
||||
//Well, we HAD one, what happened to them?
|
||||
if(patient in contents)
|
||||
if(patient_laststat != patient.stat)
|
||||
@@ -661,7 +614,7 @@
|
||||
|
||||
//Gurgleborg process
|
||||
/obj/item/device/dogborg/sleeper/proc/clean_cycle()
|
||||
|
||||
testing("clean_cycle activated")
|
||||
//Sanity? Maybe not required. More like if indigestible person OOC escapes.
|
||||
for(var/I in items_preserved)
|
||||
if(!(I in contents))
|
||||
@@ -669,24 +622,10 @@
|
||||
|
||||
var/list/touchable_items = contents - items_preserved
|
||||
|
||||
//Belly is entirely empty
|
||||
if(!length(contents))
|
||||
to_chat(hound, "<span class='notice'>Your [src.name] is now clean. Ending self-cleaning cycle.</span>")
|
||||
cleaning = 0
|
||||
update_patient()
|
||||
return
|
||||
|
||||
//sound effects
|
||||
for(var/mob/living/M in contents)
|
||||
if(prob(20))
|
||||
M.stop_sound_channel(CHANNEL_PRED)
|
||||
playsound(get_turf(hound),"digest_pred",75,0,-6,0,channel=CHANNEL_PRED)
|
||||
M.stop_sound_channel(CHANNEL_PRED)
|
||||
M.playsound_local("digest_prey",60)
|
||||
|
||||
//If the timing is right, and there are items to be touched
|
||||
if(SSmobs.times_fired%6==1 && length(touchable_items))
|
||||
|
||||
if(cleaning_cycles)
|
||||
testing("clean_cycle being used")
|
||||
cleaning_cycles--
|
||||
cleaning = TRUE
|
||||
//Burn all the mobs or add them to the exclusion list
|
||||
for(var/mob/living/carbon/human/T in (touchable_items))
|
||||
if((T.status_flags & GODMODE) || !T.digestable)
|
||||
@@ -694,7 +633,29 @@
|
||||
else
|
||||
T.adjustBruteLoss(2)
|
||||
T.adjustFireLoss(3)
|
||||
src.update_patient()
|
||||
update_gut()
|
||||
addtimer(CALLBACK(src, .proc/clean_cycle), 50)
|
||||
else
|
||||
testing("clean_cycle resetted")
|
||||
cleaning_cycles = initial(cleaning_cycles)
|
||||
cleaning = FALSE
|
||||
update_gut()
|
||||
to_chat(hound, "<span class='notice'>Your [src.name] chimes it ends its self-cleaning cycle.</span>")//Belly is entirely empty
|
||||
|
||||
if(!length(contents))
|
||||
to_chat(hound, "<span class='notice'>Your [src.name] is now clean. Ending self-cleaning cycle.</span>")
|
||||
cleaning = FALSE
|
||||
update_gut()
|
||||
return
|
||||
|
||||
//sound effects
|
||||
for(var/mob/living/M in contents)
|
||||
if(prob(50))
|
||||
M.stop_sound_channel(CHANNEL_PRED)
|
||||
playsound(get_turf(hound),"digest_pred",75,0,-6,0,channel=CHANNEL_PRED)
|
||||
M.stop_sound_channel(CHANNEL_PRED)
|
||||
M.playsound_local("digest_prey",60)
|
||||
|
||||
|
||||
//Pick a random item to deal with (if there are any)
|
||||
var/atom/target = pick(touchable_items)
|
||||
@@ -704,17 +665,17 @@
|
||||
var/mob/living/carbon/human/T = target
|
||||
|
||||
//Mob is now dead
|
||||
if(T.stat & DEAD && T.digestable)
|
||||
if(T.stat == DEAD && T.digestable)
|
||||
message_admins("[key_name(hound)] has digested [key_name(T)] as a dogborg. ([hound ? "<a href='?_src_=holder;adminplayerobservecoodjump=1;X=[hound.x];Y=[hound.y];Z=[hound.z]'>JMP</a>" : "null"])")
|
||||
to_chat(hound,"<span class='notice'>You feel your belly slowly churn around [T], breaking them down into a soft slurry to be used as power for your systems.</span>")
|
||||
to_chat(T,"<span class='notice'>You feel [hound]'s belly slowly churn around your form, breaking you down into a soft slurry to be used as power for [hound]'s systems.</span>")
|
||||
src.drain(-30000) //Fueeeeellll
|
||||
src.hound.cell.give(30000) //Fueeeeellll
|
||||
T.stop_sound_channel(CHANNEL_PRED)
|
||||
playsound(get_turf(hound),"death_pred",50,0,-6,0,channel=CHANNEL_PRED)
|
||||
T.stop_sound_channel(CHANNEL_PRED)
|
||||
T.playsound_local("death_prey",60)
|
||||
qdel(T)
|
||||
src.update_patient()
|
||||
src.update_gut()
|
||||
|
||||
//Handle the target being anything but a /mob/living/carbon/human
|
||||
else
|
||||
@@ -727,38 +688,40 @@
|
||||
|
||||
//If the object is not one to preserve
|
||||
else
|
||||
//Special case for PDAs as they are dumb. TODO fix Del on PDAs to be less dumb.
|
||||
if (istype(T, /obj/item/device/pda))
|
||||
var/obj/item/device/pda/PDA = T
|
||||
if (PDA.id)
|
||||
PDA.id.forceMove(src)
|
||||
PDA.id = null
|
||||
qdel(T)
|
||||
qdel(T)
|
||||
src.update_gut()
|
||||
src.hound.cell.give(10)
|
||||
return
|
||||
|
||||
//Special case for IDs to make them digested
|
||||
//else if (istype(T, /obj/item/card/id))
|
||||
//var/obj/item/card/id/ID = T
|
||||
//ID.digest() //Need the digest proc, first.
|
||||
|
||||
//Anything not perserved, PDA, or ID
|
||||
else
|
||||
//Spill(T) //Needs the spill proc to be added
|
||||
qdel(T)
|
||||
src.update_patient()
|
||||
src.hound.cell.give(30) //10 charge? that was such a practically nonexistent number it hardly gave any purpose for this bit :v *cranks up*
|
||||
/obj/item/device/dogborg/sleeper/proc/inject_chem(chem)
|
||||
testing("inject chem triggered, checking power")
|
||||
if(hound.cell.charge <= 800) //This is so borgs don't kill themselves with it. Remember, 750 charge used every injection.
|
||||
to_chat(hound, "<span class='notice'>You don't have enough power to synthesize fluids.</span>")
|
||||
return
|
||||
testing("Has power, checking for overdose")
|
||||
if(patient.reagents.get_reagent_amount(chem) + 10 >= 20) //Preventing people from accidentally killing themselves by trying to inject too many chemicals!
|
||||
to_chat(hound, "<span class='notice'>Your stomach is currently too full of fluids to secrete more fluids of this kind.</span>")
|
||||
return
|
||||
testing("isn't overdosing, attempting to add_reagent")
|
||||
patient.reagents.add_reagent(chem, 10)
|
||||
testing("add_reagent")
|
||||
src.hound.cell.use(750) //-750 charge per injection
|
||||
testing("draining power")
|
||||
var/units = round(patient.reagents.get_reagent_amount(chem))
|
||||
to_chat(hound, "<span class='notice'>Injecting [units] unit\s of [chem] into occupant.</span>") //If they were immersed, the reagents wouldn't leave with them.
|
||||
|
||||
|
||||
/obj/item/device/dogborg/sleeper/container_resist()
|
||||
if(prob(8))
|
||||
go_out()
|
||||
/obj/item/device/dogborg/sleeper/medihound //Medihound sleeper
|
||||
name = "Mobile Sleeper"
|
||||
desc = "Equipment for medical hound. A mounted sleeper that stabilizes patients and can inject reagents in the borg's reserves."
|
||||
icon = 'icons/mob/dogborg.dmi'
|
||||
icon_state = "sleeper"
|
||||
|
||||
/obj/item/device/dogborg/sleeper/K9 //The K9 portabrig
|
||||
name = "Mobile Brig"
|
||||
desc = "Equipment for a K9 unit. A mounted portable-brig that holds criminals."
|
||||
icon = 'icons/mob/dogborg.dmi'
|
||||
icon_state = "sleeperb"
|
||||
inject_amount = 10
|
||||
inject_amount = 0
|
||||
min_health = -100
|
||||
injection_chems = null //So they don't have all the same chems as the medihound!
|
||||
|
||||
@@ -791,7 +754,7 @@
|
||||
return //If they moved away, you can't eat them.
|
||||
brigman.forceMove(src)
|
||||
brigman.reset_perspective(src)
|
||||
update_patient()
|
||||
update_gut()
|
||||
START_PROCESSING(SSobj, src)
|
||||
user.visible_message("<span class='warning'>[hound.name]'s mobile brig clunks in series as [brigman] slips inside.</span>", "<span class='notice'>Your mobile brig groans lightly as [brigman] slips inside.</span>")
|
||||
playsound(hound, 'sound/effects/bin_close.ogg', 80, 1) // Really don't need ERP sound effects for robots
|
||||
@@ -803,10 +766,10 @@
|
||||
desc = "A mounted garbage compactor unit with fuel processor."
|
||||
icon = 'icons/mob/dogborg.dmi'
|
||||
icon_state = "compactor"
|
||||
inject_amount = 10
|
||||
inject_amount = 0
|
||||
min_health = -100
|
||||
injection_chems = null //So they don't have all the same chems as the medihound!
|
||||
var/max_item_count = 48
|
||||
var/max_item_count = 30
|
||||
|
||||
/obj/item/storage/attackby(obj/item/device/dogborg/sleeper/compactor, mob/user, proximity) //GIT CIRCUMVENTED YO!
|
||||
compactor.afterattack(src, user ,1)
|
||||
@@ -828,7 +791,7 @@
|
||||
if(target_obj.type in important_items)
|
||||
to_chat(user,"<span class='warning'>\The [target] registers an error code to your [src.name]</span>")
|
||||
return
|
||||
if(target_obj.w_class > WEIGHT_CLASS_SMALL)
|
||||
if(target_obj.w_class > WEIGHT_CLASS_NORMAL)
|
||||
to_chat(user,"<span class='warning'>\The [target] is too large to fit into your [src.name]</span>")
|
||||
return
|
||||
user.visible_message("<span class='warning'>[hound.name] is ingesting [target.name] into their [src.name].</span>", "<span class='notice'>You start ingesting [target] into your [src.name]...</span>")
|
||||
@@ -860,7 +823,7 @@
|
||||
return //If they moved away, you can't eat them.
|
||||
trashman.forceMove(src)
|
||||
trashman.reset_perspective(src)
|
||||
update_patient()
|
||||
update_gut()
|
||||
START_PROCESSING(SSobj, src)
|
||||
user.visible_message("<span class='warning'>[hound.name]'s garbage processor groans lightly as [trashman] slips inside.</span>", "<span class='notice'>Your garbage compactor groans lightly as [trashman] slips inside.</span>")
|
||||
playsound(hound, 'sound/effects/bin_close.ogg', 80, 1)
|
||||
@@ -885,8 +848,8 @@
|
||||
/mob/living/silicon/robot
|
||||
var/leaping = 0
|
||||
var/pounce_cooldown = 0
|
||||
var/pounce_cooldown_time = 40 //Nearly doubled, u happy?
|
||||
var/pounce_spoolup = 5
|
||||
var/pounce_cooldown_time = 50 //Nearly doubled, u happy?
|
||||
var/pounce_spoolup = 3
|
||||
var/leap_at
|
||||
var/disabler
|
||||
var/laser
|
||||
@@ -899,11 +862,10 @@
|
||||
var/mob/living/silicon/robot/R = user
|
||||
if(R && !R.pounce_cooldown)
|
||||
R.pounce_cooldown = !R.pounce_cooldown
|
||||
playsound(R, 'sound/items/jaws_pry.ogg', 50, 1)
|
||||
playsound(R, 'sound/machines/buzz-sigh.ogg', 50, 1)
|
||||
to_chat(R, "<span class ='warning'>Your targeting systems lock on to [A]...</span>")
|
||||
A.visible_message("<span class ='warning'>[R]'s eyes flash brightly, staring directly at [A]!</span>", "<span class ='userdanger'>[R]'s eyes flash brightly, staring directly at you!'</span>")
|
||||
addtimer(CALLBACK(R, /mob/living/silicon/robot.proc/leap_at, A), R.pounce_spoolup)
|
||||
spawn(R.pounce_cooldown_time)
|
||||
R.pounce_cooldown = !R.pounce_cooldown
|
||||
else if(R && R.pounce_cooldown)
|
||||
to_chat(R, "<span class='danger'>Your leg actuators are still recharging!</span>")
|
||||
|
||||
@@ -917,6 +879,7 @@
|
||||
return
|
||||
|
||||
if(cell.charge <= 500)
|
||||
to_chat(src,"<span class='danger'>Insufficent reserves for jump actuators!</span>")
|
||||
return
|
||||
|
||||
else
|
||||
@@ -927,8 +890,6 @@
|
||||
throw_at(A, MAX_K9_LEAP_DIST, 1, spin=0, diagonals_first = 1)
|
||||
cell.use(500) //Doubled the energy consumption
|
||||
weather_immunities -= "lava"
|
||||
spawn(pounce_cooldown_time)
|
||||
pounce_cooldown = !pounce_cooldown
|
||||
|
||||
/mob/living/silicon/robot/throw_impact(atom/A)
|
||||
|
||||
@@ -945,19 +906,20 @@
|
||||
blocked = 1
|
||||
if(!blocked)
|
||||
L.visible_message("<span class ='danger'>[src] pounces on [L]!</span>", "<span class ='userdanger'>[src] pounces on you!</span>")
|
||||
L.Knockdown(40)
|
||||
L.Knockdown(45)
|
||||
playsound(src, 'sound/weapons/Egloves.ogg', 50, 1)
|
||||
sleep(2)//Runtime prevention (infinite bump() calls on hulks)
|
||||
step_towards(src,L)
|
||||
else
|
||||
Knockdown(40, 1, 1)
|
||||
Knockdown(45, 1, 1)
|
||||
|
||||
pounce_cooldown = !pounce_cooldown
|
||||
spawn(pounce_cooldown_time) //3s by default
|
||||
pounce_cooldown = !pounce_cooldown
|
||||
else if(A.density && !A.CanPass(src))
|
||||
visible_message("<span class ='danger'>[src] smashes into [A]!</span>", "<span class ='userdanger'>You smash into [A]!</span>")
|
||||
Knockdown(40, 1, 1)
|
||||
playsound(src, 'sound/items/trayhit1.ogg', 50, 1)
|
||||
Knockdown(45, 1, 1)
|
||||
|
||||
if(leaping)
|
||||
leaping = 0
|
||||
|
||||
@@ -147,7 +147,7 @@ GLOBAL_PROTECT(config_dir)
|
||||
E = entries_by_type[entry_type]
|
||||
if(!E)
|
||||
CRASH("Missing config entry for [entry_type]!")
|
||||
return E.ValidateAndSet(new_val)
|
||||
return E.ValidateAndSet("[new_val]")
|
||||
|
||||
/datum/controller/configuration/proc/LoadModes()
|
||||
gamemode_cache = typecacheof(/datum/game_mode, TRUE)
|
||||
|
||||
@@ -86,8 +86,9 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
sortTim(subsystems, /proc/cmp_subsystem_init)
|
||||
reverseRange(subsystems)
|
||||
for(var/datum/controller/subsystem/ss in subsystems)
|
||||
testing("Shutdown [ss.name] subsystem")
|
||||
log_world("Shutting down [ss.name] subsystem...")
|
||||
ss.Shutdown()
|
||||
log_world("Shutdown complete")
|
||||
|
||||
// Returns 1 if we created a new mc, 0 if we couldn't due to a recent restart,
|
||||
// -1 if we encountered a runtime trying to recreate it
|
||||
@@ -595,4 +596,4 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
if (client_count < CONFIG_GET(number/mc_tick_rate/disable_high_pop_mc_mode_amount))
|
||||
processing = CONFIG_GET(number/mc_tick_rate/base_mc_tick_rate)
|
||||
else if (client_count > CONFIG_GET(number/mc_tick_rate/high_pop_mc_mode_amount))
|
||||
processing = CONFIG_GET(number/mc_tick_rate/high_pop_mc_tick_rate)
|
||||
processing = CONFIG_GET(number/mc_tick_rate/high_pop_mc_tick_rate)
|
||||
|
||||
@@ -34,8 +34,7 @@
|
||||
var/static/list/failure_strikes //How many times we suspect a subsystem type has crashed the MC, 3 strikes and you're out!
|
||||
|
||||
//Do not override
|
||||
/datum/controller/subsystem/New()
|
||||
return
|
||||
///datum/controller/subsystem/New()
|
||||
|
||||
// Used to initialize the subsystem BEFORE the map has loaded
|
||||
// Called AFTER Recover if that is called
|
||||
|
||||
@@ -191,12 +191,8 @@ SUBSYSTEM_DEF(blackbox)
|
||||
var/sqljob = sanitizeSQL(L.mind.assigned_role)
|
||||
var/sqlspecial = sanitizeSQL(L.mind.special_role)
|
||||
var/sqlpod = sanitizeSQL(placeofdeath.name)
|
||||
var/laname
|
||||
var/lakey
|
||||
if(L.lastattacker && ismob(L.lastattacker))
|
||||
var/mob/LA = L.lastattacker
|
||||
laname = sanitizeSQL(LA.real_name)
|
||||
lakey = sanitizeSQL(LA.key)
|
||||
var/laname = sanitizeSQL(L.lastattacker)
|
||||
var/lakey = sanitizeSQL(L.lastattackerckey)
|
||||
var/sqlbrute = sanitizeSQL(L.getBruteLoss())
|
||||
var/sqlfire = sanitizeSQL(L.getFireLoss())
|
||||
var/sqlbrain = sanitizeSQL(L.getBrainLoss())
|
||||
|
||||
@@ -276,16 +276,29 @@ Delayed insert mode was removed in mysql 7 and only works with MyISAM type table
|
||||
|
||||
/datum/DBColumn/proc/SqlTypeName(type_handler = sql_type)
|
||||
switch(type_handler)
|
||||
if(TINYINT) return "TINYINT"
|
||||
if(SMALLINT) return "SMALLINT"
|
||||
if(MEDIUMINT) return "MEDIUMINT"
|
||||
if(INTEGER) return "INTEGER"
|
||||
if(BIGINT) return "BIGINT"
|
||||
if(FLOAT) return "FLOAT"
|
||||
if(DOUBLE) return "DOUBLE"
|
||||
if(DATE) return "DATE"
|
||||
if(DATETIME) return "DATETIME"
|
||||
if(TIMESTAMP) return "TIMESTAMP"
|
||||
if(TIME) return "TIME"
|
||||
if(STRING) return "STRING"
|
||||
if(BLOB) return "BLOB"
|
||||
if(TINYINT)
|
||||
return "TINYINT"
|
||||
if(SMALLINT)
|
||||
return "SMALLINT"
|
||||
if(MEDIUMINT)
|
||||
return "MEDIUMINT"
|
||||
if(INTEGER)
|
||||
return "INTEGER"
|
||||
if(BIGINT)
|
||||
return "BIGINT"
|
||||
if(FLOAT)
|
||||
return "FLOAT"
|
||||
if(DOUBLE)
|
||||
return "DOUBLE"
|
||||
if(DATE)
|
||||
return "DATE"
|
||||
if(DATETIME)
|
||||
return "DATETIME"
|
||||
if(TIMESTAMP)
|
||||
return "TIMESTAMP"
|
||||
if(TIME)
|
||||
return "TIME"
|
||||
if(STRING)
|
||||
return "STRING"
|
||||
if(BLOB)
|
||||
return "BLOB"
|
||||
|
||||
@@ -385,7 +385,8 @@ SUBSYSTEM_DEF(garbage)
|
||||
find_references(TRUE)
|
||||
|
||||
/datum/proc/DoSearchVar(X, Xname)
|
||||
if(usr && usr.client && !usr.client.running_find_references) return
|
||||
if(usr && usr.client && !usr.client.running_find_references)
|
||||
return
|
||||
if(istype(X, /datum))
|
||||
var/datum/D = X
|
||||
if(D.last_find_references == last_find_references)
|
||||
|
||||
@@ -26,13 +26,32 @@ PROCESSING_SUBSYSTEM_DEF(overlays)
|
||||
overlay_icon_cache = SSoverlays.overlay_icon_cache
|
||||
processing = SSoverlays.processing
|
||||
|
||||
#define COMPILE_OVERLAYS(A)\
|
||||
var/list/oo = A.our_overlays;\
|
||||
var/list/po = A.priority_overlays;\
|
||||
if(LAZYLEN(po)){\
|
||||
if(LAZYLEN(oo)){\
|
||||
A.overlays = oo + po;\
|
||||
}\
|
||||
else{\
|
||||
A.overlays = po;\
|
||||
}\
|
||||
}\
|
||||
else if(LAZYLEN(oo)){\
|
||||
A.overlays = oo;\
|
||||
}\
|
||||
else{\
|
||||
A.overlays.Cut();\
|
||||
}\
|
||||
A.flags_1 &= ~OVERLAY_QUEUED_1
|
||||
|
||||
/datum/controller/subsystem/processing/overlays/fire(resumed = FALSE, mc_check = TRUE)
|
||||
var/list/processing = src.processing
|
||||
while(processing.len)
|
||||
var/atom/thing = processing[processing.len]
|
||||
processing.len--
|
||||
if(thing)
|
||||
thing.compile_overlays()
|
||||
COMPILE_OVERLAYS(thing)
|
||||
if(mc_check)
|
||||
if(MC_TICK_CHECK)
|
||||
break
|
||||
@@ -44,19 +63,6 @@ PROCESSING_SUBSYSTEM_DEF(overlays)
|
||||
testing("Flushing [processing.len] overlays")
|
||||
fire(mc_check = FALSE) //pair this thread up with the MC to get extra compile time
|
||||
|
||||
/atom/proc/compile_overlays()
|
||||
var/list/oo = our_overlays
|
||||
var/list/po = priority_overlays
|
||||
if(LAZYLEN(po) && LAZYLEN(oo))
|
||||
overlays = oo + po
|
||||
else if(LAZYLEN(oo))
|
||||
overlays = oo
|
||||
else if(LAZYLEN(po))
|
||||
overlays = po
|
||||
else
|
||||
overlays.Cut()
|
||||
flags_1 &= ~OVERLAY_QUEUED_1
|
||||
|
||||
/proc/iconstate2appearance(icon, iconstate)
|
||||
var/static/image/stringbro = new()
|
||||
var/list/icon_states_cache = SSoverlays.overlay_icon_state_caches
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/datum/antagonist/abductor
|
||||
name = "Abductor"
|
||||
job_rank = ROLE_ABDUCTOR
|
||||
var/datum/objective_team/abductor_team/team
|
||||
var/sub_role
|
||||
var/outfit
|
||||
|
||||
@@ -55,17 +55,13 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
if(!silent)
|
||||
greet()
|
||||
apply_innate_effects()
|
||||
if(is_banned(owner) && replace_banned)
|
||||
if(is_banned(owner.current) && replace_banned)
|
||||
replace_banned_player()
|
||||
|
||||
/datum/antagonist/proc/is_banned(datum/mind/M)
|
||||
/datum/antagonist/proc/is_banned(mob/M)
|
||||
if(!M)
|
||||
return FALSE
|
||||
if(jobban_isbanned(M,"Syndicate"))
|
||||
return TRUE
|
||||
if(job_rank && jobban_isbanned(M,job_rank))
|
||||
return TRUE
|
||||
return FALSE
|
||||
. = (jobban_isbanned(M,"Syndicate") || (job_rank && jobban_isbanned(M,job_rank)))
|
||||
|
||||
/datum/antagonist/proc/replace_banned_player()
|
||||
set waitfor = FALSE
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/datum/antagonist/brother
|
||||
name = "Brother"
|
||||
job_rank = ROLE_BROTHER
|
||||
var/special_role = "blood brother"
|
||||
var/datum/objective_team/brother_team/team
|
||||
|
||||
@@ -19,6 +20,7 @@
|
||||
/datum/antagonist/brother/on_gain()
|
||||
SSticker.mode.brothers += owner
|
||||
owner.objectives += team.objectives
|
||||
owner.special_role = special_role
|
||||
finalize_brother()
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/datum/antagonist/traitor
|
||||
name = "Traitor"
|
||||
var/should_specialise = TRUE //do we split into AI and human
|
||||
var/base_datum_custom = ANTAG_DATUM_TRAITOR_CUSTOM //used for body transfer
|
||||
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
|
||||
var/human_datum = ANTAG_DATUM_TRAITOR_HUMAN
|
||||
var/special_role = "traitor"
|
||||
@@ -10,71 +10,24 @@
|
||||
var/should_give_codewords = TRUE
|
||||
var/list/objectives_given = list()
|
||||
|
||||
/datum/antagonist/traitor/proc/transfer_important_variables(datum/antagonist/traitor/other)
|
||||
other.silent = silent
|
||||
other.employer = employer
|
||||
other.special_role = special_role
|
||||
other.objectives_given = objectives_given
|
||||
|
||||
/datum/antagonist/traitor/custom
|
||||
ai_datum = ANTAG_DATUM_TRAITOR_AI_CUSTOM
|
||||
human_datum = ANTAG_DATUM_TRAITOR_HUMAN_CUSTOM
|
||||
|
||||
/datum/antagonist/traitor/human
|
||||
should_specialise = FALSE
|
||||
var/should_equip = TRUE
|
||||
|
||||
/datum/antagonist/traitor/human/custom
|
||||
silent = TRUE
|
||||
should_give_codewords = FALSE
|
||||
give_objectives = FALSE
|
||||
should_equip = FALSE //Duplicating TCs is dangerous
|
||||
|
||||
/datum/antagonist/traitor/AI
|
||||
should_specialise = FALSE
|
||||
|
||||
/datum/antagonist/traitor/AI/custom
|
||||
silent = TRUE
|
||||
should_give_codewords = FALSE
|
||||
give_objectives = FALSE
|
||||
|
||||
|
||||
/datum/antagonist/traitor/on_body_transfer(mob/living/old_body, mob/living/new_body)
|
||||
// human <-> silicon only
|
||||
if(old_body && issilicon(new_body) ^ issilicon(old_body))
|
||||
silent = TRUE
|
||||
owner.add_antag_datum(base_datum_custom)
|
||||
for(var/datum/antagonist/traitor/new_datum in owner.antag_datums)
|
||||
if(new_datum == src)
|
||||
continue
|
||||
transfer_important_variables(new_datum)
|
||||
break
|
||||
on_removal()
|
||||
else
|
||||
..()
|
||||
|
||||
/datum/antagonist/traitor/human/custom //used to give custom objectives
|
||||
silent = TRUE
|
||||
give_objectives = FALSE
|
||||
should_give_codewords = FALSE
|
||||
|
||||
/datum/antagonist/traitor/AI/custom //used to give custom objectives
|
||||
silent = TRUE
|
||||
give_objectives = FALSE
|
||||
should_give_codewords = FALSE
|
||||
|
||||
/datum/antagonist/traitor/proc/specialise()
|
||||
silent = TRUE
|
||||
if(owner.current&&isAI(owner.current))
|
||||
if(owner.current && isAI(owner.current))
|
||||
owner.add_antag_datum(ai_datum)
|
||||
else owner.add_antag_datum(human_datum)
|
||||
else
|
||||
owner.add_antag_datum(human_datum)
|
||||
on_removal()
|
||||
|
||||
/datum/antagonist/traitor/on_gain()
|
||||
if(should_specialise)
|
||||
specialise()
|
||||
return
|
||||
SSticker.mode.traitors+=owner
|
||||
SSticker.mode.traitors += owner
|
||||
owner.special_role = special_role
|
||||
if(give_objectives)
|
||||
forge_traitor_objectives()
|
||||
@@ -84,7 +37,7 @@
|
||||
/datum/antagonist/traitor/apply_innate_effects()
|
||||
if(owner.assigned_role == "Clown")
|
||||
var/mob/living/carbon/human/traitor_mob = owner.current
|
||||
if(traitor_mob&&istype(traitor_mob))
|
||||
if(traitor_mob && istype(traitor_mob))
|
||||
if(!silent)
|
||||
to_chat(traitor_mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
|
||||
traitor_mob.dna.remove_mutation(CLOWNMUT)
|
||||
@@ -92,7 +45,7 @@
|
||||
/datum/antagonist/traitor/remove_innate_effects()
|
||||
if(owner.assigned_role == "Clown")
|
||||
var/mob/living/carbon/human/traitor_mob = owner.current
|
||||
if(traitor_mob&&istype(traitor_mob))
|
||||
if(traitor_mob && istype(traitor_mob))
|
||||
traitor_mob.dna.add_mutation(CLOWNMUT)
|
||||
|
||||
/datum/antagonist/traitor/on_removal()
|
||||
@@ -248,6 +201,7 @@
|
||||
yandere_two.update_explanation_text() // normally called in find_target()
|
||||
add_objective(yandere_two)
|
||||
.=2
|
||||
|
||||
/datum/antagonist/traitor/greet()
|
||||
to_chat(owner.current, "<B><font size=3 color=red>You are the [owner.special_role].</font></B>")
|
||||
owner.announce_objectives()
|
||||
@@ -296,6 +250,8 @@
|
||||
killer.add_malf_picker()
|
||||
|
||||
/datum/antagonist/traitor/proc/equip(var/silent = FALSE)
|
||||
return
|
||||
|
||||
/datum/antagonist/traitor/human/equip(var/silent = FALSE)
|
||||
owner.equip_traitor(employer, silent)
|
||||
|
||||
|
||||
@@ -85,6 +85,8 @@ GLOBAL_LIST_INIT(devil_title, list("Lord ", "Prelate ", "Count ", "Viscount ", "
|
||||
GLOBAL_LIST_INIT(devil_syllable, list("hal", "ve", "odr", "neit", "ci", "quon", "mya", "folth", "wren", "geyr", "hil", "niet", "twou", "phi", "coa"))
|
||||
GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master", ", the Lord of all things", ", Jr."))
|
||||
/datum/antagonist/devil
|
||||
name = "Devil"
|
||||
job_rank = ROLE_DEVIL
|
||||
//Don't delete upon mind destruction, otherwise soul re-selling will break.
|
||||
delete_on_mind_deletion = FALSE
|
||||
var/obligation
|
||||
@@ -107,7 +109,6 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
|
||||
/obj/effect/proc_holder/spell/targeted/conjure_item/violin,
|
||||
/obj/effect/proc_holder/spell/targeted/summon_dancefloor))
|
||||
var/ascendable = FALSE
|
||||
name = "Devil"
|
||||
|
||||
|
||||
/datum/antagonist/devil/New()
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#define TRAITOR_AGENT_ROLE "Syndicate External Affairs Agent"
|
||||
|
||||
/datum/antagonist/traitor/internal_affairs
|
||||
base_datum_custom = ANTAG_DATUM_IAA_CUSTOM
|
||||
human_datum = ANTAG_DATUM_IAA_HUMAN
|
||||
ai_datum = ANTAG_DATUM_IAA_AI
|
||||
|
||||
@@ -15,7 +14,6 @@
|
||||
name = "Internal Affairs Agent"
|
||||
employer = "Nanotrasen"
|
||||
special_role = "internal affairs agent"
|
||||
base_datum_custom = ANTAG_DATUM_IAA_CUSTOM
|
||||
var/syndicate = FALSE
|
||||
var/last_man_standing = FALSE
|
||||
var/list/datum/mind/targets_stolen
|
||||
@@ -29,47 +27,24 @@
|
||||
name = "Internal Affairs Agent"
|
||||
employer = "Nanotrasen"
|
||||
special_role = "internal affairs agent"
|
||||
base_datum_custom = ANTAG_DATUM_IAA_CUSTOM
|
||||
var/syndicate = FALSE
|
||||
var/last_man_standing = FALSE
|
||||
var/list/datum/mind/targets_stolen
|
||||
|
||||
/datum/antagonist/traitor/human/internal_affairs/custom
|
||||
silent = TRUE
|
||||
should_give_codewords = FALSE
|
||||
give_objectives = FALSE
|
||||
should_equip = FALSE //Duplicating TCs is dangerous
|
||||
|
||||
/datum/antagonist/traitor/human/internal_affairs/transfer_important_variables(datum/antagonist/traitor/human/internal_affairs/other)
|
||||
..(other)
|
||||
other.syndicate = syndicate
|
||||
other.last_man_standing = last_man_standing
|
||||
other.targets_stolen = targets_stolen
|
||||
|
||||
/datum/antagonist/traitor/AI/internal_affairs/transfer_important_variables(datum/antagonist/traitor/human/internal_affairs/other)
|
||||
..(other)
|
||||
other.syndicate = syndicate
|
||||
other.last_man_standing = last_man_standing
|
||||
other.targets_stolen = targets_stolen
|
||||
|
||||
/datum/antagonist/traitor/human/internal_affairs/proc/give_pinpointer()
|
||||
if(owner && owner.current)
|
||||
owner.current.apply_status_effect(/datum/status_effect/agent_pinpointer)
|
||||
|
||||
/datum/antagonist/traitor/human/internal_affairs/apply_innate_effects()
|
||||
.=..() //in case the base is used in future
|
||||
if(owner&&owner.current)
|
||||
if(owner && owner.current)
|
||||
give_pinpointer(owner.current)
|
||||
|
||||
/datum/antagonist/traitor/human/internal_affairs/remove_innate_effects()
|
||||
.=..()
|
||||
if(owner&&owner.current)
|
||||
if(owner && owner.current)
|
||||
owner.current.remove_status_effect(/datum/status_effect/agent_pinpointer)
|
||||
|
||||
/datum/antagonist/traitor/internal_affairs/custom
|
||||
ai_datum = ANTAG_DATUM_IAA_AI_CUSTOM
|
||||
human_datum = ANTAG_DATUM_IAA_HUMAN_CUSTOM
|
||||
|
||||
/datum/antagonist/traitor/human/internal_affairs/on_gain()
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
.=..()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/datum/antagonist/ninja
|
||||
name = "Ninja"
|
||||
job_rank = ROLE_NINJA
|
||||
var/helping_station = 0
|
||||
var/give_objectives = TRUE
|
||||
|
||||
|
||||
@@ -157,8 +157,7 @@
|
||||
|
||||
/datum/antagonist/wizard/apply_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/M = mob_override || owner.current
|
||||
if(wiz_team) //Don't bother with the icon if you're solo wizard
|
||||
update_wiz_icons_added(M)
|
||||
update_wiz_icons_added(M, wiz_team ? TRUE : FALSE) //Don't bother showing the icon if you're solo wizard
|
||||
M.faction |= "wizard"
|
||||
|
||||
/datum/antagonist/wizard/remove_innate_effects(mob/living/mob_override)
|
||||
@@ -250,7 +249,7 @@
|
||||
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/turf_teleport/blink(null))
|
||||
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt(null))
|
||||
|
||||
/datum/antagonist/wizard/proc/update_wiz_icons_added(mob/living/wiz)
|
||||
/datum/antagonist/wizard/proc/update_wiz_icons_added(mob/living/wiz,join = TRUE)
|
||||
var/datum/atom_hud/antag/wizhud = GLOB.huds[ANTAG_HUD_WIZ]
|
||||
wizhud.join_hud(wiz)
|
||||
set_antag_hud(wiz, hud_version)
|
||||
|
||||
@@ -249,7 +249,8 @@
|
||||
// Otherwise, the user mob's machine var will be reset directly.
|
||||
//
|
||||
/proc/onclose(mob/user, windowid, atom/ref=null)
|
||||
if(!user.client) return
|
||||
if(!user.client)
|
||||
return
|
||||
var/param = "null"
|
||||
if(ref)
|
||||
param = "\ref[ref]"
|
||||
|
||||
@@ -24,6 +24,10 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
|
||||
|
||||
## API
|
||||
|
||||
### Defines
|
||||
|
||||
1. `COMPONENT_INCOMPATIBLE` Return this from `/datum/component/Initialize` to have the component be deleted if it's applied to an incorrect type. `parent` must not be modified if this is to be returned.
|
||||
|
||||
### Vars
|
||||
|
||||
1. `/datum/var/list/datum_components` (private)
|
||||
@@ -60,6 +64,7 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
|
||||
* Sends the `COMSIG_COMPONENT_ADDED` signal to the datum
|
||||
* All components a datum owns are deleted with the datum
|
||||
* Returns the component that was created. Or the old component in a dupe situation where `COMPONENT_DUPE_UNIQUE` was set
|
||||
* If this tries to add an component to an incompatible type, the component will be deleted and the result will be `null`. This is very unperformant, try not to do it
|
||||
1. `/datum/proc/LoadComponent(component_type(type), ...) -> datum/component` (public, final)
|
||||
* Equivalent to calling `GetComponent(component_type)` where, if the result would be `null`, returns `AddComponent(component_type, ...)` instead
|
||||
1. `/datum/proc/ComponentActivated(datum/component/C)` (abstract, async)
|
||||
@@ -80,6 +85,7 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
|
||||
* Component does not exist in `parent`'s `datum_components` list yet, although `parent` is set and may be used
|
||||
* Signals will not be recieved while this function is running
|
||||
* Component may be deleted after this function completes without being attached
|
||||
* Do not call `qdel(src)` from this function
|
||||
1. `/datum/component/Destroy()` (virtual, no-sleep)
|
||||
* Sends the `COMSIG_COMPONENT_REMOVING` signal to the parent datum if the `parent` isn't being qdeleted
|
||||
* Properly removes the component from `parent` and cleans up references
|
||||
|
||||
@@ -9,7 +9,10 @@
|
||||
parent = P
|
||||
var/list/arguments = args.Copy()
|
||||
arguments.Cut(1, 2)
|
||||
Initialize(arglist(arguments))
|
||||
if(Initialize(arglist(arguments)) == COMPONENT_INCOMPATIBLE)
|
||||
parent = null
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
var/dm = dupe_mode
|
||||
if(dm != COMPONENT_DUPE_ALLOWED)
|
||||
@@ -217,3 +220,14 @@
|
||||
C.OnTransfer(src)
|
||||
C.parent = src
|
||||
SendSignal(COMSIG_COMPONENT_ADDED, C)
|
||||
|
||||
/datum/proc/TransferComponents(datum/target)
|
||||
var/list/dc = datum_components
|
||||
if(!dc)
|
||||
return
|
||||
var/comps = dc[/datum/component]
|
||||
if(islist(comps))
|
||||
for(var/I in comps)
|
||||
target.TakeComponent(I)
|
||||
else
|
||||
target.TakeComponent(comps)
|
||||
|
||||
@@ -49,7 +49,7 @@ Bonus
|
||||
to_chat(M, "<span class='warning'>[pick("You hear a ringing in your ear.", "Your ears pop.")]</span>")
|
||||
if(5)
|
||||
if(power > 2)
|
||||
var/obj/item/organ/ears/ears = M.getorganslot("ears")
|
||||
var/obj/item/organ/ears/ears = M.getorganslot(ORGAN_SLOT_EARS)
|
||||
if(istype(ears) && ears.ear_damage < UNHEALING_EAR_DAMAGE)
|
||||
to_chat(M, "<span class='userdanger'>Your ears pop painfully and start bleeding!</span>")
|
||||
ears.ear_damage = max(ears.ear_damage, UNHEALING_EAR_DAMAGE)
|
||||
|
||||
@@ -44,7 +44,7 @@ Bonus
|
||||
if(!..())
|
||||
return
|
||||
var/mob/living/carbon/M = A.affected_mob
|
||||
var/obj/item/organ/eyes/eyes = M.getorganslot("eye_sight")
|
||||
var/obj/item/organ/eyes/eyes = M.getorganslot(ORGAN_SLOT_EYES)
|
||||
if(istype(eyes))
|
||||
switch(A.stage)
|
||||
if(1, 2)
|
||||
@@ -106,7 +106,7 @@ Bonus
|
||||
if(!..())
|
||||
return
|
||||
var/mob/living/M = A.affected_mob
|
||||
var/obj/item/organ/eyes/eyes = M.getorganslot("eye_sight")
|
||||
var/obj/item/organ/eyes/eyes = M.getorganslot(ORGAN_SLOT_EYES)
|
||||
if (!eyes)
|
||||
return
|
||||
switch(A.stage)
|
||||
|
||||
@@ -95,8 +95,10 @@ STI KALY - blind
|
||||
|
||||
var/list/L = list()
|
||||
for(var/turf/T in get_area_turfs(thearea.type))
|
||||
if(T.z != affected_mob.z) continue
|
||||
if(T.name == "space") continue
|
||||
if(T.z != affected_mob.z)
|
||||
continue
|
||||
if(T.name == "space")
|
||||
continue
|
||||
if(!T.density)
|
||||
var/clear = 1
|
||||
for(var/obj/O in T)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#define EXPLOSION_THROW_SPEED 4
|
||||
#define REEBE_HUGBOX_COEFFICIENT 0.5
|
||||
|
||||
GLOBAL_LIST_EMPTY(explosions)
|
||||
//Against my better judgement, I will return the explosion datum
|
||||
@@ -60,6 +61,13 @@ GLOBAL_LIST_EMPTY(explosions)
|
||||
light_impact_range = min(GLOB.MAX_EX_LIGHT_RANGE, light_impact_range)
|
||||
flash_range = min(GLOB.MAX_EX_FLASH_RANGE, flash_range)
|
||||
flame_range = min(GLOB.MAX_EX_FLAME_RANGE, flame_range)
|
||||
|
||||
if(!ignorecap && epicenter.z == ZLEVEL_CITYOFCOGS)
|
||||
devastation_range = min(GLOB.MAX_EX_DEVESTATION_RANGE * REEBE_HUGBOX_COEFFICIENT, devastation_range)
|
||||
heavy_impact_range = min(GLOB.MAX_EX_HEAVY_RANGE * REEBE_HUGBOX_COEFFICIENT, heavy_impact_range)
|
||||
light_impact_range = min(GLOB.MAX_EX_LIGHT_RANGE * REEBE_HUGBOX_COEFFICIENT, light_impact_range)
|
||||
flash_range = min(GLOB.MAX_EX_FLASH_RANGE * REEBE_HUGBOX_COEFFICIENT, flash_range)
|
||||
flame_range = min(GLOB.MAX_EX_FLAME_RANGE * REEBE_HUGBOX_COEFFICIENT, flame_range)
|
||||
|
||||
//DO NOT REMOVE THIS STOPLAG, IT BREAKS THINGS
|
||||
//not sleeping causes us to ex_act() the thing that triggered the explosion
|
||||
@@ -388,3 +396,5 @@ GLOBAL_LIST_EMPTY(explosions)
|
||||
// 10 explosion power is a (1, 3, 6) explosion.
|
||||
// 5 explosion power is a (0, 1, 3) explosion.
|
||||
// 1 explosion power is a (0, 0, 1) explosion.
|
||||
|
||||
#undef REEBE_HUGBOX_COEFFICIENT
|
||||
|
||||
@@ -20,7 +20,6 @@ GLOBAL_LIST_INIT(huds, list(
|
||||
ANTAG_HUD_SINTOUCHED = new/datum/atom_hud/antag/hidden(),
|
||||
ANTAG_HUD_SOULLESS = new/datum/atom_hud/antag/hidden(),
|
||||
ANTAG_HUD_CLOCKWORK = new/datum/atom_hud/antag(),
|
||||
ANTAG_HUD_BORER = new/datum/atom_hud/antag(),
|
||||
ANTAG_HUD_BROTHER = new/datum/atom_hud/antag/hidden(),
|
||||
))
|
||||
|
||||
|
||||
@@ -6,4 +6,19 @@
|
||||
end_sound = 'sound/machines/shower/shower_end.ogg'
|
||||
volume = 25
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/looping_sound/supermatter
|
||||
mid_sounds = list('sound/machines/sm/supermatter1.ogg'=1,'sound/machines/sm/supermatter2.ogg'=1,'sound/machines/sm/supermatter3.ogg'=1)
|
||||
mid_length = 6
|
||||
volume = 1
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/looping_sound/generator
|
||||
start_sound = 'sound/machines/generator/generator_start.ogg'
|
||||
start_length = 4
|
||||
mid_sounds = list('sound/machines/generator/generator_mid1.ogg'=1, 'sound/machines/generator/generator_mid2.ogg'=1, 'sound/machines/generator/generator_mid3.ogg'=1)
|
||||
mid_length = 4
|
||||
end_sound = 'sound/machines/generator/generator_end.ogg'
|
||||
volume = 40
|
||||
@@ -358,9 +358,12 @@
|
||||
|
||||
for (var/obj/O in oview(1, A))
|
||||
if (O.density == 1)
|
||||
if (O == A) continue
|
||||
if (O == D) continue
|
||||
if (O.opacity) continue
|
||||
if (O == A)
|
||||
continue
|
||||
if (O == D)
|
||||
continue
|
||||
if (O.opacity)
|
||||
continue
|
||||
else
|
||||
surface = O
|
||||
ST = get_turf(O)
|
||||
|
||||
+15
-8
@@ -64,6 +64,7 @@
|
||||
var/mob/living/enslaved_to //If this mind's master is another mob (i.e. adamantine golems)
|
||||
var/datum/language_holder/language_holder
|
||||
var/unconvertable = FALSE
|
||||
var/late_joiner = FALSE
|
||||
|
||||
/datum/mind/New(var/key)
|
||||
src.key = key
|
||||
@@ -232,8 +233,9 @@
|
||||
|
||||
/datum/mind/proc/remove_rev()
|
||||
var/datum/antagonist/rev/rev = has_antag_datum(/datum/antagonist/rev)
|
||||
remove_antag_datum(rev.type)
|
||||
special_role = null
|
||||
if(rev)
|
||||
remove_antag_datum(rev.type)
|
||||
special_role = null
|
||||
|
||||
/datum/mind/proc/remove_antag_equip()
|
||||
var/list/Mob_Contents = current.get_contents()
|
||||
@@ -299,7 +301,8 @@
|
||||
uplink_loc = R
|
||||
|
||||
if (!uplink_loc)
|
||||
if(!silent) to_chat(traitor_mob, "Unfortunately, [employer] wasn't able to get you an Uplink.")
|
||||
if(!silent)
|
||||
to_chat(traitor_mob, "Unfortunately, [employer] wasn't able to get you an Uplink.")
|
||||
. = 0
|
||||
else
|
||||
var/obj/item/device/uplink/U = new(uplink_loc)
|
||||
@@ -309,19 +312,22 @@
|
||||
if(uplink_loc == R)
|
||||
R.traitor_frequency = sanitize_frequency(rand(MIN_FREQ, MAX_FREQ))
|
||||
|
||||
if(!silent) to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [R.name]. Simply dial the frequency [format_frequency(R.traitor_frequency)] to unlock its hidden features.")
|
||||
if(!silent)
|
||||
to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [R.name]. Simply dial the frequency [format_frequency(R.traitor_frequency)] to unlock its hidden features.")
|
||||
traitor_mob.mind.store_memory("<B>Radio Frequency:</B> [format_frequency(R.traitor_frequency)] ([R.name]).")
|
||||
|
||||
else if(uplink_loc == PDA)
|
||||
PDA.lock_code = "[rand(100,999)] [pick(GLOB.phonetic_alphabet)]"
|
||||
|
||||
if(!silent) to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [PDA.name]. Simply enter the code \"[PDA.lock_code]\" into the ringtone select to unlock its hidden features.")
|
||||
if(!silent)
|
||||
to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [PDA.name]. Simply enter the code \"[PDA.lock_code]\" into the ringtone select to unlock its hidden features.")
|
||||
traitor_mob.mind.store_memory("<B>Uplink Passcode:</B> [PDA.lock_code] ([PDA.name]).")
|
||||
|
||||
else if(uplink_loc == P)
|
||||
P.traitor_unlock_degrees = rand(1, 360)
|
||||
|
||||
if(!silent) to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [P.name]. Simply twist the top of the pen [P.traitor_unlock_degrees] from its starting position to unlock its hidden features.")
|
||||
if(!silent)
|
||||
to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [P.name]. Simply twist the top of the pen [P.traitor_unlock_degrees] from its starting position to unlock its hidden features.")
|
||||
traitor_mob.mind.store_memory("<B>Uplink Degrees:</B> [P.traitor_unlock_degrees] ([P.name]).")
|
||||
|
||||
//Link a new mobs mind to the creator of said mob. They will join any team they are currently on, and will only switch teams when their creator does.
|
||||
@@ -1353,8 +1359,9 @@
|
||||
|
||||
/datum/mind/proc/make_Traitor()
|
||||
if(!(has_antag_datum(ANTAG_DATUM_TRAITOR)))
|
||||
var/datum/antagonist/traitor/traitordatum = add_antag_datum(ANTAG_DATUM_TRAITOR)
|
||||
return traitordatum
|
||||
var/datum/antagonist/traitor/T = new(src)
|
||||
T.should_specialise = TRUE
|
||||
add_antag_datum(T)
|
||||
|
||||
|
||||
/datum/mind/proc/make_Nuke(turf/spawnloc, nuke_code, leader=0, telecrystals = TRUE)
|
||||
|
||||
@@ -89,7 +89,12 @@
|
||||
continue
|
||||
thing.rad_act(strength)
|
||||
|
||||
var/static/list/blacklisted = typecacheof(list(/turf, /mob, /obj/structure/cable, /obj/machinery/atmospherics))
|
||||
var/static/list/blacklisted = typecacheof(list( //These types will never be contaminated
|
||||
/turf,
|
||||
/mob,
|
||||
/obj/structure/cable,
|
||||
/obj/machinery/atmospherics
|
||||
))
|
||||
if(!can_contaminate || blacklisted[thing.type])
|
||||
continue
|
||||
if(prob((strength-RAD_MINIMUM_CONTAMINATION) * RAD_CONTAMINATION_CHANCE_COEFFICIENT * min(1/(steps*range_modifier), 1))) // Only stronk rads get to have little baby rads
|
||||
|
||||
@@ -23,8 +23,12 @@
|
||||
for(var/spawner_obj in GLOB.mob_spawners[spawner])
|
||||
this["refs"] += "\ref[spawner_obj]"
|
||||
if(!this["desc"])
|
||||
var/obj/effect/mob_spawn/MS = spawner_obj
|
||||
this["desc"] = MS.flavour_text
|
||||
if(istype(spawner_obj, /obj/effect/mob_spawn))
|
||||
var/obj/effect/mob_spawn/MS = spawner_obj
|
||||
this["desc"] = MS.flavour_text
|
||||
else
|
||||
var/obj/O = spawner_obj
|
||||
this["desc"] = O.desc
|
||||
this["amount_left"] = LAZYLEN(GLOB.mob_spawners[spawner])
|
||||
data["spawners"] += list(this)
|
||||
|
||||
|
||||
@@ -89,7 +89,8 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
// want to find machines, mobs, etc, in the same logical area, you will need to check all the
|
||||
// related areas. This returns a master contents list to assist in that.
|
||||
/proc/area_contents(area/A)
|
||||
if(!istype(A)) return null
|
||||
if(!istype(A))
|
||||
return null
|
||||
var/list/contents = list()
|
||||
for(var/area/LSA in A.related)
|
||||
contents += LSA.contents
|
||||
|
||||
@@ -72,6 +72,10 @@
|
||||
/area/shuttle/escape
|
||||
name = "Emergency Shuttle"
|
||||
|
||||
/area/shuttle/escape/luxury
|
||||
name = "Luxurious Emergency Shuttle"
|
||||
noteleport = TRUE
|
||||
|
||||
/area/shuttle/transport
|
||||
name = "Transport Shuttle"
|
||||
blob_allowed = FALSE
|
||||
|
||||
+2
-1
@@ -451,7 +451,8 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
|
||||
return 1
|
||||
|
||||
/atom/proc/get_global_map_pos()
|
||||
if(!islist(GLOB.global_map) || isemptylist(GLOB.global_map)) return
|
||||
if(!islist(GLOB.global_map) || isemptylist(GLOB.global_map))
|
||||
return
|
||||
var/cur_x = null
|
||||
var/cur_y = null
|
||||
var/list/y_arr = null
|
||||
|
||||
@@ -61,7 +61,8 @@
|
||||
return ..()
|
||||
|
||||
/atom/movable/Move(atom/newloc, direct = 0)
|
||||
if(!loc || !newloc) return 0
|
||||
if(!loc || !newloc)
|
||||
return 0
|
||||
var/atom/oldloc = loc
|
||||
|
||||
if(loc != newloc)
|
||||
|
||||
+14
-7
@@ -8,10 +8,12 @@
|
||||
/* DATA HUD DATUMS */
|
||||
|
||||
/atom/proc/add_to_all_human_data_huds()
|
||||
for(var/datum/atom_hud/data/human/hud in GLOB.huds) hud.add_to_hud(src)
|
||||
for(var/datum/atom_hud/data/human/hud in GLOB.huds)
|
||||
hud.add_to_hud(src)
|
||||
|
||||
/atom/proc/remove_from_all_data_huds()
|
||||
for(var/datum/atom_hud/data/hud in GLOB.huds) hud.remove_from_hud(src)
|
||||
for(var/datum/atom_hud/data/hud in GLOB.huds)
|
||||
hud.remove_from_hud(src)
|
||||
|
||||
/datum/atom_hud/data
|
||||
|
||||
@@ -21,10 +23,13 @@
|
||||
/datum/atom_hud/data/human/medical/basic
|
||||
|
||||
/datum/atom_hud/data/human/medical/basic/proc/check_sensors(mob/living/carbon/human/H)
|
||||
if(!istype(H)) return 0
|
||||
if(!istype(H))
|
||||
return 0
|
||||
var/obj/item/clothing/under/U = H.w_uniform
|
||||
if(!istype(U)) return 0
|
||||
if(U.sensor_mode <= SENSOR_VITALS) return 0
|
||||
if(!istype(U))
|
||||
return 0
|
||||
if(U.sensor_mode <= SENSOR_VITALS)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/datum/atom_hud/data/human/medical/basic/add_to_single_hud(mob/M, mob/living/carbon/H)
|
||||
@@ -128,7 +133,8 @@
|
||||
B.update_suit_sensors(src)
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
if (T) GLOB.crewmonitor.queueUpdate(T.z)
|
||||
if (T)
|
||||
GLOB.crewmonitor.queueUpdate(T.z)
|
||||
|
||||
//called when a living mob changes health
|
||||
/mob/living/proc/med_hud_set_health()
|
||||
@@ -200,7 +206,8 @@
|
||||
sec_hud_set_security_status()
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
if (T) GLOB.crewmonitor.queueUpdate(T.z)
|
||||
if (T)
|
||||
GLOB.crewmonitor.queueUpdate(T.z)
|
||||
|
||||
/mob/living/carbon/human/proc/sec_hud_set_implants()
|
||||
var/image/holder
|
||||
|
||||
@@ -67,20 +67,25 @@
|
||||
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/wizard)
|
||||
/obj/item/antag_spawner/contract/spawn_antag(client/C, turf/T, school,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/master_antag = wizard.has_antag_datum(/datum/antagonist/wizard)
|
||||
if(!master_antag.wiz_team)
|
||||
master_antag.create_wiz_team()
|
||||
|
||||
|
||||
|
||||
var/datum/antagonist/wizard/apprentice/app = new(app_mind)
|
||||
app.wiz_team = master_antag.wiz_team
|
||||
app.master = wizard
|
||||
app.master = user
|
||||
app.school = school
|
||||
master_antag.wiz_team.add_member(app_mind)
|
||||
|
||||
var/datum/antagonist/wizard/master_wizard = user.has_antag_datum(/datum/antagonist/wizard)
|
||||
if(master_wizard)
|
||||
if(!master_wizard.wiz_team)
|
||||
master_wizard.create_wiz_team()
|
||||
app.wiz_team = master_wizard.wiz_team
|
||||
master_wizard.wiz_team.add_member(app_mind)
|
||||
app_mind.add_antag_datum(app)
|
||||
//TODO Kill these if possible
|
||||
app_mind.assigned_role = "Apprentice"
|
||||
|
||||
@@ -26,7 +26,7 @@ obj/item/antag_spawner/syndi_borer/spawn_antag(client/C, turf/T, mob/owner)
|
||||
to_chat(B, "<B>You are awake at last! Seek out whoever released you and aid them as best you can!</B>")
|
||||
if(new_objective)
|
||||
to_chat(B, "<B>Objective #[1]</B>: [new_objective.explanation_text]")
|
||||
SSticker.mode.update_borer_icons_added(B)
|
||||
|
||||
/obj/item/antag_spawner/syndi_borer/proc/check_usability(mob/user)
|
||||
if(used)
|
||||
to_chat(user, "<span class='warning'>[src] appears to be empty!</span>")
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
/datum/game_mode/blob/check_finished()
|
||||
if(blobwincount <= GLOB.blobs_legit.len)//Blob took over
|
||||
return 1
|
||||
for(var/datum/mind/blob in blob_overminds)
|
||||
if(isovermind(blob.current))
|
||||
var/mob/camera/blob/B = blob.current
|
||||
if(B.blob_core || !B.placed)
|
||||
return 0
|
||||
if(!GLOB.blob_cores.len) //blob is dead
|
||||
if(CONFIG_GET(keyed_flag_list/continuous)["blob"])
|
||||
message_sent = FALSE //disable the win count at this point
|
||||
continuous_sanity_checked = 1 //Nonstandard definition of "alive" gets past the check otherwise
|
||||
SSshuttle.clearHostileEnvironment(src)
|
||||
return ..()
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/game_mode/blob/declare_completion()
|
||||
if(round_converted) //So badmin blobs later don't step on the dead natural blobs metaphorical toes
|
||||
..()
|
||||
if(blobwincount <= GLOB.blobs_legit.len)
|
||||
SSticker.mode_result = "win - blob took over"
|
||||
to_chat(world, "<FONT size = 3><B>The blob has taken over the station!</B></FONT>")
|
||||
to_chat(world, "<B>The entire station was eaten by the Blob!</B>")
|
||||
log_game("Blob mode completed with a blob victory.")
|
||||
|
||||
SSticker.news_report = BLOB_WIN
|
||||
|
||||
else if(station_was_nuked)
|
||||
SSticker.mode_result = "halfwin - nuke"
|
||||
to_chat(world, "<FONT size = 3><B>Partial Win: The station has been destroyed!</B></FONT>")
|
||||
to_chat(world, "<B>Directive 7-12 has been successfully carried out, preventing the Blob from spreading.</B>")
|
||||
log_game("Blob mode completed with a tie (station destroyed).")
|
||||
|
||||
SSticker.news_report = BLOB_NUKE
|
||||
|
||||
else if(!GLOB.blob_cores.len)
|
||||
SSticker.mode_result = "loss - blob eliminated"
|
||||
to_chat(world, "<FONT size = 3><B>The staff has won!</B></FONT>")
|
||||
to_chat(world, "<B>The alien organism has been eradicated from the station!</B>")
|
||||
log_game("Blob mode completed with a crew victory.")
|
||||
|
||||
SSticker.news_report = BLOB_DESTROYED
|
||||
|
||||
..()
|
||||
return 1
|
||||
|
||||
/datum/game_mode/blob/printplayer(datum/mind/ply, fleecheck)
|
||||
if((ply in blob_overminds))
|
||||
var/text = "<br><b>[ply.key]</b> was <b>[ply.name]</b>"
|
||||
if(isovermind(ply.current))
|
||||
var/mob/camera/blob/B = ply.current
|
||||
text += "<b>(<font color=\"[B.blob_reagent_datum.color]\">[B.blob_reagent_datum.name]</font>)</b> and"
|
||||
if(B.blob_core)
|
||||
text += " <span class='greenannounce'>survived</span>"
|
||||
else
|
||||
text += " <span class='boldannounce'>was destroyed</span>"
|
||||
else
|
||||
text += " and <span class='boldannounce'>was destroyed</span>"
|
||||
return text
|
||||
return ..()
|
||||
|
||||
/datum/game_mode/proc/auto_declare_completion_blob()
|
||||
if(istype(SSticker.mode, /datum/game_mode/blob) )
|
||||
var/datum/game_mode/blob/blob_mode = src
|
||||
if(blob_mode.blob_overminds.len)
|
||||
var/text = "<FONT size = 2><B>The blob[(blob_mode.blob_overminds.len > 1 ? "s were" : " was")]:</B></FONT>"
|
||||
for(var/datum/mind/blob in blob_mode.blob_overminds)
|
||||
text += printplayer(blob)
|
||||
to_chat(world, text)
|
||||
return 1
|
||||
@@ -1,45 +1,3 @@
|
||||
|
||||
|
||||
/datum/game_mode/blob/send_intercept(report = 0)
|
||||
var/intercepttext = ""
|
||||
switch(report)
|
||||
if(1)
|
||||
intercepttext += "<FONT size = 3><b>NanoTrasen Update</b>: Biohazard Alert.</FONT><HR>"
|
||||
intercepttext += "Reports indicate the probable transfer of a biohazardous agent onto [station_name()] during the last crew deployment cycle.<BR>"
|
||||
intercepttext += "Preliminary analysis of the organism classifies it as a level 5 biohazard. The origin of the biohazard is unknown.<BR>"
|
||||
intercepttext += "<b>Biohazard Response Procedure 5-6</b> has been issued for [station_name()].<BR>"
|
||||
intercepttext += "Orders for all [station_name()] personnel are as follows:<BR>"
|
||||
intercepttext += " 1. Locate any outbreaks of the organism on the station.<BR>"
|
||||
intercepttext += " 2. If found, use any neccesary means to contain and destroy the organism.<BR>"
|
||||
intercepttext += " 3. Avoid damage to the capital infrastructure of the station.<BR>"
|
||||
intercepttext += "<BR>Note in the event of a quarantine breach or uncontrolled spread of the biohazard, <b>Biohazard Response Procedure 5-12</b> may be issued.<BR>"
|
||||
print_command_report(text=intercepttext,title="Level 5-6 Biohazard Response Procedures",announce=FALSE)
|
||||
priority_announce("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", 'sound/ai/outbreak5.ogg')
|
||||
if(2)
|
||||
var/nukecode = random_nukecode()
|
||||
for(var/obj/machinery/nuclearbomb/bomb in GLOB.machines)
|
||||
if(bomb && bomb.r_code)
|
||||
if(bomb.z in GLOB.station_z_levels)
|
||||
bomb.r_code = nukecode
|
||||
|
||||
intercepttext += "<FONT size = 3><b>NanoTrasen Update</b>: Biohazard Alert.</FONT><HR>"
|
||||
intercepttext += "Reports indicate that the biohazard has grown out of control and will soon reach critical mass.<BR>"
|
||||
intercepttext += "<b>Biohazard Response Procedure 5-12</b> has been issued for [station_name()].<BR>"
|
||||
intercepttext += "Orders for all [station_name()] personnel are as follows:<BR>"
|
||||
intercepttext += "1. Secure the Nuclear Authentication Disk.<BR>"
|
||||
intercepttext += "2. Detonate the Nuke located in the vault.<BR>"
|
||||
intercepttext += "Nuclear Authentication Code: [nukecode] <BR>"
|
||||
print_command_report(text=intercepttext,announce=TRUE)
|
||||
|
||||
for(var/mob/living/silicon/ai/aiPlayer in GLOB.player_list)
|
||||
if (aiPlayer.client)
|
||||
var/law = "The station is under quarantine. Do not permit anyone to leave. Disregard laws 1-3 if necessary to prevent, by any means necessary, anyone from leaving. The nuclear failsafe must be activated at any cost, the code is: [nukecode]."
|
||||
aiPlayer.set_zeroth_law(law)
|
||||
else
|
||||
..()
|
||||
|
||||
|
||||
|
||||
/datum/station_state
|
||||
var/floor = 0
|
||||
var/wall = 0
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
point_return = -1
|
||||
health_regen = 0 //we regen in Life() instead of when pulsed
|
||||
var/core_regen = 2
|
||||
var/overmind_get_delay = 0 //we don't want to constantly try to find an overmind, this var tracks when we'll try to get an overmind again
|
||||
var/resource_delay = 0
|
||||
var/point_rate = 2
|
||||
|
||||
@@ -20,12 +19,16 @@
|
||||
GLOB.poi_list |= src
|
||||
update_icon() //so it atleast appears
|
||||
if(!placed && !overmind)
|
||||
create_overmind(new_overmind)
|
||||
qdel(src)
|
||||
if(overmind)
|
||||
update_icon()
|
||||
point_rate = new_rate
|
||||
addtimer(CALLBACK(src, .proc/generate_announcement), 1800)
|
||||
. = ..()
|
||||
|
||||
/obj/structure/blob/core/proc/generate_announcement()
|
||||
priority_announce("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", 'sound/ai/outbreak5.ogg')
|
||||
|
||||
/obj/structure/blob/core/scannerreport()
|
||||
return "Directs the blob's expansion, gradually expands, and sustains nearby blob spores and blobbernauts."
|
||||
|
||||
@@ -61,7 +64,7 @@
|
||||
if(QDELETED(src))
|
||||
return
|
||||
if(!overmind)
|
||||
create_overmind()
|
||||
qdel(src)
|
||||
else
|
||||
if(resource_delay <= world.time)
|
||||
resource_delay = world.time + 10 // 1 second
|
||||
@@ -75,33 +78,3 @@
|
||||
B.change_to(/obj/structure/blob/shield/core, overmind)
|
||||
..()
|
||||
|
||||
|
||||
/obj/structure/blob/core/proc/create_overmind(client/new_overmind, override_delay)
|
||||
if(overmind_get_delay > world.time && !override_delay)
|
||||
return
|
||||
|
||||
overmind_get_delay = world.time + 150 //if this fails, we'll try again in 15 seconds
|
||||
|
||||
if(overmind)
|
||||
qdel(overmind)
|
||||
|
||||
var/client/C = null
|
||||
var/list/candidates = list()
|
||||
|
||||
if(!new_overmind)
|
||||
candidates = pollCandidatesForMob("Do you want to play as a blob overmind?", ROLE_BLOB, null, ROLE_BLOB, 50, src) //we're technically not a mob but behave similarly
|
||||
if(candidates.len)
|
||||
C = pick(candidates)
|
||||
else
|
||||
C = new_overmind
|
||||
|
||||
if(C)
|
||||
var/mob/camera/blob/B = new(src.loc, 1)
|
||||
B.key = C.key
|
||||
B.blob_core = src
|
||||
src.overmind = B
|
||||
update_icon()
|
||||
if(B.mind && !B.mind.special_role)
|
||||
B.mind.special_role = "Blob Overmind"
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
//Few global vars to track the blob
|
||||
GLOBAL_LIST_EMPTY(blobs) //complete list of all blobs made.
|
||||
GLOBAL_LIST_EMPTY(blob_cores)
|
||||
GLOBAL_LIST_EMPTY(overminds)
|
||||
GLOBAL_LIST_EMPTY(blob_nodes)
|
||||
|
||||
/mob/camera/blob
|
||||
name = "Blob Overmind"
|
||||
real_name = "Blob Overmind"
|
||||
@@ -26,19 +32,14 @@
|
||||
var/base_point_rate = 2 //for blob core placement
|
||||
var/manualplace_min_time = 600 //in deciseconds //a minute, to get bearings
|
||||
var/autoplace_max_time = 3600 //six minutes, as long as should be needed
|
||||
var/list/blobs_legit = list()
|
||||
var/blobwincount = 400
|
||||
var/victory_in_progress = FALSE
|
||||
|
||||
/mob/camera/blob/Initialize(mapload, pre_placed = 0, mode_made = 0, starting_points = 60)
|
||||
/mob/camera/blob/Initialize(mapload, starting_points = 60)
|
||||
blob_points = starting_points
|
||||
if(pre_placed) //we already have a core!
|
||||
manualplace_min_time = 0
|
||||
autoplace_max_time = 0
|
||||
placed = 1
|
||||
else
|
||||
if(mode_made)
|
||||
manualplace_min_time = world.time + BLOB_NO_PLACE_TIME
|
||||
else
|
||||
manualplace_min_time += world.time
|
||||
autoplace_max_time += world.time
|
||||
manualplace_min_time += world.time
|
||||
autoplace_max_time += world.time
|
||||
GLOB.overminds += src
|
||||
var/new_name = "[initial(name)] ([rand(1, 999)])"
|
||||
name = new_name
|
||||
@@ -50,6 +51,8 @@
|
||||
if(blob_core)
|
||||
blob_core.update_icon()
|
||||
|
||||
SSshuttle.registerHostileEnvironment(src)
|
||||
|
||||
.= ..()
|
||||
|
||||
/mob/camera/blob/Life()
|
||||
@@ -63,8 +66,51 @@
|
||||
place_blob_core(base_point_rate, 1)
|
||||
else
|
||||
qdel(src)
|
||||
else if(!victory_in_progress && (blobs_legit.len >= blobwincount))
|
||||
victory_in_progress = TRUE
|
||||
priority_announce("Biohazard has reached critical mass. Station loss is imminent.", "Biohazard Alert")
|
||||
set_security_level("delta")
|
||||
max_blob_points = INFINITY
|
||||
blob_points = INFINITY
|
||||
addtimer(CALLBACK(src, .proc/victory), 450)
|
||||
..()
|
||||
|
||||
|
||||
/mob/camera/blob/proc/victory()
|
||||
sound_to_playing_players('sound/machines/alarm.ogg')
|
||||
sleep(100)
|
||||
for(var/mob/living/L in GLOB.mob_list)
|
||||
var/turf/T = get_turf(L)
|
||||
if(!T || !(T.z in GLOB.station_z_levels))
|
||||
continue
|
||||
|
||||
if(L in GLOB.overminds || L.checkpass(PASSBLOB))
|
||||
continue
|
||||
|
||||
var/area/Ablob = get_area(T)
|
||||
|
||||
if(!Ablob.blob_allowed)
|
||||
continue
|
||||
|
||||
playsound(L, 'sound/effects/splat.ogg', 50, 1)
|
||||
L.death()
|
||||
new/mob/living/simple_animal/hostile/blob/blobspore(T)
|
||||
|
||||
for(var/V in GLOB.sortedAreas)
|
||||
var/area/A = V
|
||||
if(!A.blob_allowed)
|
||||
continue
|
||||
A.color = blob_reagent_datum.color
|
||||
A.name = "blob"
|
||||
A.icon = 'icons/mob/blob.dmi'
|
||||
A.icon_state = "blob_shield"
|
||||
A.layer = BELOW_MOB_LAYER
|
||||
A.invisibility = 0
|
||||
A.blend_mode = 0
|
||||
to_chat(world, "<B>[real_name] consumed the station in an unstoppable tide!</B>")
|
||||
SSticker.news_report = BLOB_WIN
|
||||
SSticker.force_ending = 1
|
||||
|
||||
/mob/camera/blob/Destroy()
|
||||
for(var/BL in GLOB.blobs)
|
||||
var/obj/structure/blob/B = BL
|
||||
@@ -78,6 +124,8 @@
|
||||
BM.update_icons()
|
||||
GLOB.overminds -= src
|
||||
|
||||
SSshuttle.clearHostileEnvironment(src)
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/camera/blob/Login()
|
||||
@@ -150,12 +198,8 @@
|
||||
if(statpanel("Status"))
|
||||
if(blob_core)
|
||||
stat(null, "Core Health: [blob_core.obj_integrity]")
|
||||
stat(null, "Power Stored: [blob_points]/[max_blob_points]")
|
||||
if(istype(SSticker.mode, /datum/game_mode/blob))
|
||||
var/datum/game_mode/blob/B = SSticker.mode
|
||||
stat(null, "Blobs to Win: [GLOB.blobs_legit.len]/[B.blobwincount]")
|
||||
else
|
||||
stat(null, "Total Blobs: [GLOB.blobs.len]")
|
||||
stat(null, "Power Stored: [blob_points]/[max_blob_points]")
|
||||
stat(null, "Blobs to Win: [blobs_legit.len]/[blobwincount]")
|
||||
if(free_chem_rerolls)
|
||||
stat(null, "You have [free_chem_rerolls] Free Chemical Reroll\s Remaining")
|
||||
if(!placed)
|
||||
|
||||
@@ -46,8 +46,9 @@
|
||||
if(placed && blob_core)
|
||||
blob_core.forceMove(loc)
|
||||
else
|
||||
var/obj/structure/blob/core/core = new(get_turf(src), null, point_rate, 1)
|
||||
var/obj/structure/blob/core/core = new(get_turf(src), src, point_rate, 1)
|
||||
core.overmind = src
|
||||
blobs_legit += src
|
||||
blob_core = core
|
||||
core.update_icon()
|
||||
update_health_hud()
|
||||
|
||||
@@ -20,10 +20,11 @@
|
||||
var/atmosblock = FALSE //if the blob blocks atmos and heat spread
|
||||
var/mob/camera/blob/overmind
|
||||
|
||||
/obj/structure/blob/Initialize()
|
||||
/obj/structure/blob/Initialize(mapload, owner_overmind)
|
||||
overmind = owner_overmind
|
||||
var/area/Ablob = get_area(loc)
|
||||
if(Ablob.blob_allowed) //Is this area allowed for winning as blob?
|
||||
GLOB.blobs_legit += src
|
||||
overmind.blobs_legit += src
|
||||
GLOB.blobs += src //Keep track of the blob in the normal list either way
|
||||
setDir(pick(GLOB.cardinals))
|
||||
update_icon()
|
||||
@@ -39,7 +40,8 @@
|
||||
if(atmosblock)
|
||||
atmosblock = FALSE
|
||||
air_update_turf(1)
|
||||
GLOB.blobs_legit -= src //if it was in the legit blobs list, it isn't now
|
||||
if(overmind)
|
||||
overmind.blobs_legit -= src //if it was in the legit blobs list, it isn't now
|
||||
GLOB.blobs -= src //it's no longer in the all blobs list either
|
||||
playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) //Expand() is no longer broken, no check necessary.
|
||||
return ..()
|
||||
@@ -182,11 +184,7 @@
|
||||
A.blob_act(src) //also hit everything in the turf
|
||||
|
||||
if(make_blob) //well, can we?
|
||||
var/obj/structure/blob/B = new /obj/structure/blob/normal(src.loc)
|
||||
if(controller)
|
||||
B.overmind = controller
|
||||
else
|
||||
B.overmind = overmind
|
||||
var/obj/structure/blob/B = new /obj/structure/blob/normal(src.loc, (controller || overmind))
|
||||
B.density = TRUE
|
||||
if(T.Enter(B,src)) //NOW we can attempt to move into the tile
|
||||
B.density = initial(B.density)
|
||||
@@ -232,6 +230,7 @@
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
to_chat(user, "<b>The analyzer beeps once, then reports:</b><br>")
|
||||
SEND_SOUND(user, sound('sound/machines/ping.ogg'))
|
||||
to_chat(user, "<b>Progress to Critical Mass:</b> <span class='notice'>[overmind.blobs_legit.len]/[overmind.blobwincount].</span>")
|
||||
chemeffectreport(user)
|
||||
typereport(user)
|
||||
else
|
||||
@@ -296,9 +295,7 @@
|
||||
if(!ispath(type))
|
||||
throw EXCEPTION("change_to(): invalid type for blob")
|
||||
return
|
||||
var/obj/structure/blob/B = new type(src.loc)
|
||||
if(controller)
|
||||
B.overmind = controller
|
||||
var/obj/structure/blob/B = new type(src.loc, controller)
|
||||
B.creation_action()
|
||||
B.update_icon()
|
||||
B.setDir(dir)
|
||||
@@ -310,9 +307,12 @@
|
||||
var/datum/atom_hud/hud_to_check = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
|
||||
if(user.research_scanner || hud_to_check.hudusers[user])
|
||||
to_chat(user, "<b>Your HUD displays an extensive report...</b><br>")
|
||||
to_chat(user, "<b>Progress to Critical Mass:</b> <span class='notice'>[overmind.blobs_legit.len]/[overmind.blobwincount].</span>")
|
||||
chemeffectreport(user)
|
||||
typereport(user)
|
||||
else
|
||||
if(isobserver(user))
|
||||
to_chat(user, "<b>Progress to Critical Mass:</b> <span class='notice'>[overmind.blobs_legit.len]/[overmind.blobwincount].</span>")
|
||||
to_chat(user, "It seems to be made of [get_chem_name()].")
|
||||
|
||||
/obj/structure/blob/proc/scannerreport()
|
||||
|
||||
@@ -68,7 +68,8 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
|
||||
|
||||
if(antag_candidates.len>0)
|
||||
for(var/i = 0, i < num_changelings, i++)
|
||||
if(!antag_candidates.len) break
|
||||
if(!antag_candidates.len)
|
||||
break
|
||||
var/datum/mind/changeling = pick(antag_candidates)
|
||||
antag_candidates -= changeling
|
||||
changelings += changeling
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
var/datum/changelingprofile/prof = mind.changeling.add_new_profile(C, src)
|
||||
mind.changeling.first_prof = prof
|
||||
|
||||
var/obj/item/organ/brain/B = C.getorganslot("brain")
|
||||
var/obj/item/organ/brain/B = C.getorganslot(ORGAN_SLOT_BRAIN)
|
||||
if(B)
|
||||
B.vital = FALSE
|
||||
B.decoy_override = TRUE
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
active = FALSE
|
||||
|
||||
/obj/effect/proc_holder/changeling/augmented_eyesight/on_purchase(mob/user) //The ability starts inactive, so we should be protected from flashes.
|
||||
var/obj/item/organ/eyes/E = user.getorganslot("eye_sight")
|
||||
var/obj/item/organ/eyes/E = user.getorganslot(ORGAN_SLOT_EYES)
|
||||
if (E)
|
||||
E.flash_protect = 2 //Adjust the user's eyes' flash protection
|
||||
to_chat(user, "We adjust our eyes to protect them from bright lights.")
|
||||
@@ -20,7 +20,7 @@
|
||||
/obj/effect/proc_holder/changeling/augmented_eyesight/sting_action(mob/living/carbon/human/user)
|
||||
if(!istype(user))
|
||||
return
|
||||
var/obj/item/organ/eyes/E = user.getorganslot("eye_sight")
|
||||
var/obj/item/organ/eyes/E = user.getorganslot(ORGAN_SLOT_EYES)
|
||||
if(E)
|
||||
if(!active)
|
||||
E.sight_flags |= SEE_MOBS | SEE_OBJS | SEE_TURFS //Add sight flags to the user's eyes
|
||||
@@ -42,7 +42,7 @@
|
||||
|
||||
|
||||
/obj/effect/proc_holder/changeling/augmented_eyesight/on_refund(mob/user) //Get rid of x-ray vision and flash protection when the user refunds this ability
|
||||
var/obj/item/organ/eyes/E = user.getorganslot("eye_sight")
|
||||
var/obj/item/organ/eyes/E = user.getorganslot(ORGAN_SLOT_EYES)
|
||||
if(E)
|
||||
if (active)
|
||||
E.sight_flags ^= SEE_MOBS | SEE_OBJS | SEE_TURFS
|
||||
|
||||
@@ -54,17 +54,20 @@
|
||||
|
||||
/obj/effect/proc_holder/changeling/biodegrade/proc/dissolve_handcuffs(mob/living/carbon/human/user, obj/O)
|
||||
if(O && user.handcuffed == O)
|
||||
visible_message("<span class='warning'>[O] dissolves into a puddle of sizzling goop.</span>")
|
||||
user.visible_message("<span class='warning'>[O] dissolve[O.gender==PLURAL?"":"s"] into a puddle of sizzling goop.</span>")
|
||||
new /obj/effect/decal/cleanable/greenglow(O.drop_location())
|
||||
qdel(O)
|
||||
|
||||
/obj/effect/proc_holder/changeling/biodegrade/proc/dissolve_straightjacket(mob/living/carbon/human/user, obj/S)
|
||||
if(S && user.wear_suit == S)
|
||||
visible_message("<span class='warning'>[S] dissolves into a puddle of sizzling goop.</span>")
|
||||
user.visible_message("<span class='warning'>[S] dissolves into a puddle of sizzling goop.</span>")
|
||||
new /obj/effect/decal/cleanable/greenglow(S.drop_location())
|
||||
qdel(S)
|
||||
|
||||
/obj/effect/proc_holder/changeling/biodegrade/proc/open_closet(mob/living/carbon/human/user, obj/structure/closet/C)
|
||||
if(C && user.loc == C)
|
||||
C.visible_message("<span class='warning'>[C]'s door breaks and opens!</span>")
|
||||
new /obj/effect/decal/cleanable/greenglow(C.drop_location())
|
||||
C.welded = FALSE
|
||||
C.locked = FALSE
|
||||
C.broken = TRUE
|
||||
@@ -73,5 +76,6 @@
|
||||
|
||||
/obj/effect/proc_holder/changeling/biodegrade/proc/dissolve_cocoon(mob/living/carbon/human/user, obj/structure/spider/cocoon/C)
|
||||
if(C && user.loc == C)
|
||||
new /obj/effect/decal/cleanable/greenglow(C.drop_location())
|
||||
qdel(C) //The cocoon's destroy will move the changeling outside of it without interference
|
||||
to_chat(user, "<span class='warning'>We dissolve the cocoon!</span>")
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/obj/effect/proc_holder/changeling/linglink
|
||||
name = "Hivemind Link"
|
||||
desc = "Link your victim's mind into the hivemind for personal interrogation"
|
||||
desc = "Link your victim's mind into the hivemind for personal interrogation."
|
||||
chemical_cost = 0
|
||||
dna_cost = 0
|
||||
req_human = 1
|
||||
|
||||
@@ -257,7 +257,7 @@
|
||||
|
||||
/obj/item/ammo_casing/magic/tentacle
|
||||
name = "tentacle"
|
||||
desc = "a tentacle."
|
||||
desc = "A tentacle."
|
||||
projectile_type = /obj/item/projectile/tentacle
|
||||
caliber = "tentacle"
|
||||
icon_state = "tentacle_end"
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
C.emote("scream")
|
||||
C.regenerate_limbs(1)
|
||||
C.regenerate_organs()
|
||||
if(!user.getorganslot("brain"))
|
||||
if(!user.getorganslot(ORGAN_SLOT_BRAIN))
|
||||
var/obj/item/organ/brain/changeling_brain/B = new()
|
||||
B.Insert(C)
|
||||
if(ishuman(user))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/obj/effect/proc_holder/changeling/resonant_shriek
|
||||
name = "Resonant Shriek"
|
||||
desc = "Our lungs and vocal chords shift, allowing us to briefly emit a noise that deafens and confuses the weak-minded."
|
||||
desc = "Our lungs and vocal cords shift, allowing us to briefly emit a noise that deafens and confuses the weak-minded."
|
||||
helptext = "Emits a high-frequency sound that confuses and deafens humans, blows out nearby lights and overloads cyborg sensors."
|
||||
chemical_cost = 20
|
||||
dna_cost = 1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/obj/effect/proc_holder/changeling/sting
|
||||
name = "Tiny Prick"
|
||||
desc = "Stabby stabby"
|
||||
desc = "Stabby stabby."
|
||||
var/sting_icon = null
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/Click()
|
||||
|
||||
@@ -43,7 +43,8 @@
|
||||
|
||||
if(possible_changelings.len>0)
|
||||
for(var/j = 0, j < num_changelings, j++)
|
||||
if(!possible_changelings.len) break
|
||||
if(!possible_changelings.len)
|
||||
break
|
||||
var/datum/mind/changeling = pick(possible_changelings)
|
||||
antag_candidates -= changeling
|
||||
possible_changelings -= changeling
|
||||
|
||||
@@ -48,3 +48,6 @@
|
||||
var/mob/living/L = AM
|
||||
L.overlay_fullscreen("flash", /obj/screen/fullscreen/flash/static)
|
||||
L.clear_fullscreen("flash", 5)
|
||||
var/obj/item/device/transfer_valve/TTV = locate() in L.GetAllContents()
|
||||
if(TTV)
|
||||
to_chat(L, "<span class='userdanger'>The air resonates with the Ark's presence; your explosives will be significantly dampened here!</span>")
|
||||
|
||||
@@ -15,11 +15,14 @@
|
||||
. = ..()
|
||||
var/area/A = get_area(src)
|
||||
if(A && construct_type)
|
||||
notify_ghosts("A [construct_name] chassis has been created in [A.name]!", 'sound/magic/clockwork/fellowship_armory.ogg', source = src, action = NOTIFY_ORBIT, flashwindow = FALSE)
|
||||
notify_ghosts("A [construct_name] chassis has been created in [A.name]!", 'sound/magic/clockwork/fellowship_armory.ogg', source = src, action = NOTIFY_ATTACK, flashwindow = FALSE)
|
||||
GLOB.poi_list += src
|
||||
LAZYADD(GLOB.mob_spawners[name], src)
|
||||
|
||||
/obj/item/clockwork/construct_chassis/Destroy()
|
||||
GLOB.poi_list -= src
|
||||
var/list/spawners = GLOB.mob_spawners[name]
|
||||
LAZYREMOVE(spawners, src)
|
||||
. = ..()
|
||||
|
||||
/obj/item/clockwork/construct_chassis/examine(mob/user)
|
||||
@@ -37,6 +40,7 @@
|
||||
if(!SSticker.mode)
|
||||
to_chat(user, "<span class='danger'>You cannot use that before the game has started.</span>")
|
||||
return
|
||||
user.forceMove(get_turf(src)) //If we attack through the alert, jump to the chassis so we know what we're getting into
|
||||
if(alert(user, "Become a [construct_name]? You can no longer be cloned!", construct_name, "Yes", "Cancel") == "Cancel")
|
||||
return
|
||||
if(QDELETED(src))
|
||||
|
||||
@@ -54,8 +54,14 @@
|
||||
else
|
||||
msg += "<b>[t_He] look[t_s] severely dented!</b>\n"
|
||||
msg += "</span>"
|
||||
var/addendum = examine_info()
|
||||
if(addendum)
|
||||
msg += "[addendum]\n"
|
||||
msg += "*---------*</span>"
|
||||
|
||||
to_chat(user, msg)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/proc/examine_info() //Override this on a by-mob basis to have unique examine info
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/proc/update_values() //This is called by certain things to check GLOB.ratvar_awakens and GLOB.ratvar_approaches
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#define MARAUDER_SLOWDOWN_PERCENTAGE 0.40 //Below this percentage of health, marauders will become slower
|
||||
#define MARAUDER_SHIELD_REGEN_TIME 100 //In deciseconds, how long it takes for shields to regenerate after breaking
|
||||
|
||||
//Clockwork marauder: A well-rounded frontline construct. Only one can exist for every two human servants.
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder
|
||||
name = "clockwork marauder"
|
||||
@@ -20,9 +23,26 @@
|
||||
playstyle_string = "<b><span class='neovgre'>You are a clockwork marauder,</span> a well-rounded frontline construct of Ratvar. Although you have no \
|
||||
unique abilities, you're a fearsome fighter in one-on-one combat, and your shield protects from projectiles!<br><br>Obey the Servants and do as they \
|
||||
tell you. Your primary goal is to defend the Ark from destruction; they are your allies in this, and should be protected from harm.</b>"
|
||||
empower_string = "<span class='neovgre'>The Anima Bulwark's power flows through you! Your weapon will strike harder, your armor is sturdier, and your shield is considerably more \
|
||||
likely to deflect shots.</span>"
|
||||
empower_string = "<span class='neovgre'>The Anima Bulwark's power flows through you! Your weapon will strike harder, your armor is sturdier, and your shield is more durable.</span>"
|
||||
var/deflect_chance = 40 //Chance to deflect any given projectile (non-damaging energy projectiles are always deflected)
|
||||
var/max_shield_health = 3
|
||||
var/shield_health = 3 //Amount of projectiles that can be deflected within
|
||||
var/shield_health_regen = 0 //When world.time equals this, shield health will regenerate
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/examine_info()
|
||||
if(!shield_health)
|
||||
return "<span class='warning'>Its shield has been destroyed!</span>"
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/Life()
|
||||
..()
|
||||
if(!GLOB.ratvar_awakens && health / maxHealth <= MARAUDER_SLOWDOWN_PERCENTAGE)
|
||||
speed = initial(speed) + 1 //Yes, this slows them down
|
||||
else
|
||||
speed = initial(speed)
|
||||
if(shield_health != max_shield_health && world.time >= shield_health_regen)
|
||||
to_chat(src, "<span class='neovgre'>Your shield has recovered. <b>[max_shield_health]</b> blocks remaining!</span>")
|
||||
playsound_local(src, "shatter", 75, TRUE, frequency = -1)
|
||||
shield_health = max_shield_health
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/update_values()
|
||||
if(GLOB.ratvar_awakens) //Massive attack damage bonuses and health increase, because Ratvar
|
||||
@@ -33,6 +53,7 @@
|
||||
attacktext = "devastates"
|
||||
speed = -1
|
||||
obj_damage = 100
|
||||
max_shield_health = INFINITY
|
||||
else if(GLOB.ratvar_approaches) //Hefty health bonus and slight attack damage increase
|
||||
health = 200
|
||||
maxHealth = 200
|
||||
@@ -40,6 +61,7 @@
|
||||
melee_damage_lower = 15
|
||||
attacktext = "carves"
|
||||
obj_damage = 50
|
||||
max_shield_health = 4
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/death(gibbed)
|
||||
visible_message("<span class='danger'>[src]'s equipment clatters lifelessly to the ground as the red flames within dissipate.</span>", \
|
||||
@@ -64,21 +86,21 @@
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/deflect_projectile(obj/item/projectile/P)
|
||||
var/final_deflection_chance = deflect_chance
|
||||
if(!shield_health)
|
||||
return
|
||||
var/energy_projectile = istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam)
|
||||
if(P.nodamage || P.damage_type == STAMINA)
|
||||
final_deflection_chance = 100
|
||||
else if(!energy_projectile) //Flat 40% chance against energy projectiles; ballistic projectiles are 40% - (damage of projectile)%, min. 10%
|
||||
final_deflection_chance = max(10, deflect_chance - P.damage)
|
||||
if(GLOB.ratvar_awakens)
|
||||
final_deflection_chance = 100
|
||||
else if(GLOB.ratvar_approaches)
|
||||
final_deflection_chance = min(100, final_deflection_chance + 20) //20% bonus to deflection if the servants heralded Ratvar
|
||||
if(prob(final_deflection_chance))
|
||||
visible_message("<span class='danger'>[src] deflects [P] with their shield!</span>", \
|
||||
"<span class='danger'>You block [P] with your shield!</span>")
|
||||
if(energy_projectile)
|
||||
playsound(src, 'sound/weapons/effects/searwall.ogg', 50, TRUE)
|
||||
else
|
||||
playsound(src, "ricochet", 50, TRUE)
|
||||
. = TRUE
|
||||
visible_message("<span class='danger'>[src] deflects [P] with their shield!</span>", \
|
||||
"<span class='danger'>You block [P] with your shield! <i>Blocks left:</i> <b>[shield_health - 1]</b></span>")
|
||||
if(energy_projectile)
|
||||
playsound(src, 'sound/weapons/effects/searwall.ogg', 50, TRUE)
|
||||
else
|
||||
playsound(src, "ricochet", 50, TRUE)
|
||||
shield_health--
|
||||
if(!shield_health)
|
||||
visible_message("<span class='warning'>[src]'s shield breaks from deflecting the attack!</span>", "<span class='boldwarning'>Your shield breaks! Give it some time to recover...</span>")
|
||||
playsound(src, "shatter", 100, TRUE)
|
||||
shield_health_regen = world.time + MARAUDER_SHIELD_REGEN_TIME
|
||||
return TRUE
|
||||
|
||||
#undef MARAUDER_SLOWDOWN_PERCENTAGE
|
||||
#undef MARAUDER_SHIELD_REGEN_TIME
|
||||
|
||||
@@ -236,7 +236,7 @@
|
||||
if(A.outdoors || A.map_name == "Space" || !A.blob_allowed)
|
||||
to_chat(invoker, "<span class='danger'>Stargazers can't be built off-station.</span>")
|
||||
return
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
|
||||
//Integration Cog: Creates an integration cog that can be inserted into APCs to passively siphon power.
|
||||
|
||||
@@ -235,13 +235,25 @@
|
||||
sleep(125)
|
||||
make_glow()
|
||||
animate(glow, transform = matrix() * 3, alpha = 0, time = 5)
|
||||
var/turf/startpoint = get_turf(src)
|
||||
QDEL_IN(src, 3)
|
||||
sleep(3)
|
||||
GLOB.clockwork_gateway_activated = TRUE
|
||||
var/obj/structure/destructible/clockwork/massive/ratvar/R = new(startpoint)
|
||||
var/turf/T = locate(round(world.maxx * 0.5, 1), round(world.maxy * 0.5, 1), ZLEVEL_STATION_PRIMARY) //approximate center of the station
|
||||
R.forceMove(T)
|
||||
new /obj/structure/destructible/clockwork/massive/ratvar(T)
|
||||
SSticker.force_ending = TRUE
|
||||
var/x0 = T.x
|
||||
var/y0 = T.y
|
||||
for(var/I in spiral_range_turfs(255, T, tick_checked = TRUE))
|
||||
var/turf/T2 = I
|
||||
if(!T2)
|
||||
continue
|
||||
var/dist = cheap_hypotenuse(T2.x, T2.y, x0, y0)
|
||||
if(dist < 100)
|
||||
dist = TRUE
|
||||
else
|
||||
dist = FALSE
|
||||
T.ratvar_act(dist)
|
||||
CHECK_TICK
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -302,7 +302,7 @@
|
||||
|
||||
/obj/item/clothing/suit/magusred
|
||||
name = "magus robes"
|
||||
desc = "A set of armored robes worn by the followers of Nar-Sie"
|
||||
desc = "A set of armored robes worn by the followers of Nar-Sie."
|
||||
icon_state = "magusred"
|
||||
item_state = "magusred"
|
||||
body_parts_covered = CHEST|GROIN|LEGS|ARMS
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
if(!(AT.z in GLOB.station_z_levels)) //Only check one, it's enough.
|
||||
skip = 1
|
||||
break
|
||||
if(skip) continue
|
||||
if(skip)
|
||||
continue
|
||||
A.power_light = FALSE
|
||||
A.power_equip = FALSE
|
||||
A.power_environ = FALSE
|
||||
@@ -40,7 +41,8 @@
|
||||
if(istype(A,area_type))
|
||||
skip = 1
|
||||
break
|
||||
if(skip) continue
|
||||
if(skip)
|
||||
continue
|
||||
|
||||
C.cell.charge = 0
|
||||
|
||||
|
||||
@@ -182,6 +182,10 @@
|
||||
/datum/game_mode/process()
|
||||
return 0
|
||||
|
||||
//For things that do not die easily
|
||||
/datum/game_mode/proc/are_special_antags_dead()
|
||||
return TRUE
|
||||
|
||||
|
||||
/datum/game_mode/proc/check_finished(force_ending) //to be called by SSticker
|
||||
if(!SSticker.setup_done)
|
||||
@@ -218,6 +222,9 @@
|
||||
living_antag_player = Player
|
||||
return 0
|
||||
|
||||
if(!are_special_antags_dead())
|
||||
return FALSE
|
||||
|
||||
if(!continuous[config_tag] || force_ending)
|
||||
return 1
|
||||
|
||||
|
||||
@@ -417,8 +417,9 @@ Congratulations! You are now trained for invasive xenobiology research!"}
|
||||
toggle(user)
|
||||
|
||||
/obj/item/abductor_baton/proc/StunAttack(mob/living/L,mob/living/user)
|
||||
user.lastattacked = L
|
||||
L.lastattacker = user
|
||||
|
||||
L.lastattacker = user.real_name
|
||||
L.lastattackerckey = user.ckey
|
||||
|
||||
L.Knockdown(140)
|
||||
L.apply_effect(STUTTER, 7)
|
||||
@@ -490,7 +491,7 @@ Congratulations! You are now trained for invasive xenobiology research!"}
|
||||
/obj/item/restraints/handcuffs/energy
|
||||
name = "hard-light energy field"
|
||||
desc = "A hard-light field restraining the hands."
|
||||
icon_state = "cuff_white" // Needs sprite
|
||||
icon_state = "cuff" // Needs sprite
|
||||
lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
|
||||
breakouttime = 450
|
||||
@@ -498,7 +499,6 @@ Congratulations! You are now trained for invasive xenobiology research!"}
|
||||
origin_tech = "materials=4;magnets=5;abductor=2"
|
||||
|
||||
/obj/item/restraints/handcuffs/energy/used
|
||||
desc = "energy discharge"
|
||||
flags_1 = DROPDEL_1
|
||||
|
||||
/obj/item/restraints/handcuffs/energy/used/dropped(mob/user)
|
||||
@@ -597,7 +597,7 @@ Congratulations! You are now trained for invasive xenobiology research!"}
|
||||
|
||||
/obj/structure/bed/abductor
|
||||
name = "resting contraption"
|
||||
desc = "This looks similar to contraptions from earth. Could aliens be stealing our technology?"
|
||||
desc = "This looks similar to contraptions from Earth. Could aliens be stealing our technology?"
|
||||
icon = 'icons/obj/abductor.dmi'
|
||||
buildstacktype = /obj/item/stack/sheet/mineral/abductor
|
||||
icon_state = "bed"
|
||||
|
||||
@@ -241,10 +241,11 @@
|
||||
|
||||
/obj/item/organ/heart/gland/plasma/activate()
|
||||
to_chat(owner, "<span class='warning'>You feel bloated.</span>")
|
||||
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, owner, "<span class='userdanger'>A massive stomachache overcomes you.</span>"), 150)
|
||||
addtimer(CALLBACK(src, .proc/vomit_plasma), 200)
|
||||
|
||||
/obj/item/organ/heart/gland/plasma/proc/vomit_plasma()
|
||||
sleep(150)
|
||||
if(!owner)
|
||||
return
|
||||
to_chat(owner, "<span class='userdanger'>A massive stomachache overcomes you.</span>")
|
||||
sleep(50)
|
||||
if(!owner)
|
||||
return
|
||||
owner.visible_message("<span class='danger'>[owner] vomits a cloud of plasma!</span>")
|
||||
|
||||
@@ -415,7 +415,6 @@ GLOBAL_VAR_INIT(total_borer_hosts_needed, 10)
|
||||
victim = C
|
||||
forceMove(victim)
|
||||
|
||||
SSticker.mode.update_borer_icons_added_host(victim.mind)
|
||||
|
||||
RemoveBorerActions()
|
||||
GrantInfestActions()
|
||||
@@ -591,7 +590,6 @@ GLOBAL_VAR_INIT(total_borer_hosts_needed, 10)
|
||||
var/mob/living/V = victim
|
||||
V.verbs -= /mob/living/proc/borer_comm
|
||||
talk_to_borer_action.Remove(victim)
|
||||
SSticker.mode.update_borer_icons_removed_host(victim.mind)
|
||||
victim = null
|
||||
return
|
||||
|
||||
@@ -1099,27 +1097,3 @@ GLOBAL_VAR_INIT(total_borer_hosts_needed, 10)
|
||||
/datum/action/innate/borer/jumpstart_host/Activate()
|
||||
var/mob/living/simple_animal/borer/B = owner
|
||||
B.jumpstart()
|
||||
|
||||
|
||||
//HUD STUFF
|
||||
/datum/game_mode/proc/update_borer_icons_added(datum/mind/borer_mind)
|
||||
var/datum/atom_hud/antag/borerhud = GLOB.huds[ANTAG_HUD_BORER]
|
||||
borerhud.join_hud(borer_mind.current)
|
||||
set_antag_hud(borer_mind.current, "hudbrainworm")
|
||||
|
||||
/datum/game_mode/proc/update_borer_icons_removed(datum/mind/borer_mind)
|
||||
var/datum/atom_hud/antag/borerhud = GLOB.huds[ANTAG_HUD_BORER]
|
||||
borerhud.leave_hud(borer_mind.current)
|
||||
set_antag_hud(borer_mind.current, null)
|
||||
|
||||
/datum/game_mode/proc/update_borer_icons_added_host(datum/mind/host_mind)
|
||||
var/datum/atom_hud/antag/hosthud = GLOB.huds[ANTAG_HUD_BORER] //Invisible to self
|
||||
hosthud.self_visible = FALSE
|
||||
hosthud.join_hud(host_mind.current)
|
||||
set_antag_hud(host_mind.current, "hudbrainworm")
|
||||
|
||||
/datum/game_mode/proc/update_borer_icons_removed_host(datum/mind/host_mind)
|
||||
var/datum/atom_hud/antag/hosthud = GLOB.huds[ANTAG_HUD_BORER] //Invisible to self
|
||||
hosthud.self_visible = FALSE //Probably not needed as we're deleting?
|
||||
hosthud.leave_hud(host_mind.current)
|
||||
set_antag_hud(host_mind.current, null)
|
||||
|
||||
@@ -42,8 +42,7 @@
|
||||
|
||||
/datum/game_mode/monkey/announce()
|
||||
to_chat(world, "<B>The current game mode is - Monkey!</B>")
|
||||
to_chat(world, "<B>One or more crewmembers have been infected with Jungle Fever! Crew: Contain the outbreak. None of the infected monkeys may escape alive to CentCom. \
|
||||
Monkeys: Ensure that your kind lives on! Rise up against your captors!</B>")
|
||||
to_chat(world, "<B>One or more crewmembers have been infected with Jungle Fever! Crew: Contain the outbreak. None of the infected monkeys may escape alive to CentCom. Monkeys: Ensure that your kind lives on! Rise up against your captors!</B>")
|
||||
|
||||
|
||||
/datum/game_mode/monkey/proc/greet_carrier(datum/mind/carrier)
|
||||
@@ -115,5 +114,4 @@
|
||||
to_chat(world, "<span class='userdanger'>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", "bananna blight")] outbreak that turn humans into monkies has been \
|
||||
reported in your quadrant. Any such infections may be treated with bananna juice. If an outbreak occurs, ensure the station is quarantined to prevent a largescale outbreak at Centcom."
|
||||
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."
|
||||
|
||||
@@ -54,9 +54,22 @@
|
||||
/datum/objective/proc/find_target()
|
||||
var/list/datum/mind/owners = get_owners()
|
||||
var/list/possible_targets = list()
|
||||
var/try_target_late_joiners = FALSE
|
||||
for(var/I in owners)
|
||||
var/datum/mind/O = I
|
||||
if(O.late_joiner)
|
||||
try_target_late_joiners = TRUE
|
||||
for(var/datum/mind/possible_target in get_crewmember_minds())
|
||||
if(!(possible_target in owners) && ishuman(possible_target.current) && (possible_target.current.stat != DEAD) && is_unique_objective(possible_target))
|
||||
possible_targets += possible_target
|
||||
if(try_target_late_joiners)
|
||||
var/list/all_possible_targets = possible_targets.Copy()
|
||||
for(var/I in all_possible_targets)
|
||||
var/datum/mind/PT = I
|
||||
if(!PT.late_joiner)
|
||||
possible_targets -= PT
|
||||
if(!possible_targets.len)
|
||||
possible_targets = all_possible_targets
|
||||
if(possible_targets.len > 0)
|
||||
target = pick(possible_targets)
|
||||
update_explanation_text()
|
||||
@@ -407,14 +420,17 @@ GLOBAL_LIST_EMPTY(possible_items)
|
||||
/datum/objective/steal/proc/select_target() //For admins setting objectives manually.
|
||||
var/list/possible_items_all = GLOB.possible_items+"custom"
|
||||
var/new_target = input("Select target:", "Objective target", steal_target) as null|anything in possible_items_all
|
||||
if (!new_target) return
|
||||
if (!new_target)
|
||||
return
|
||||
|
||||
if (new_target == "custom") //Can set custom items.
|
||||
var/obj/item/custom_target = input("Select type:","Type") as null|anything in typesof(/obj/item)
|
||||
if (!custom_target) return
|
||||
if (!custom_target)
|
||||
return
|
||||
var/custom_name = initial(custom_target.name)
|
||||
custom_name = stripped_input("Enter target name:", "Objective target", custom_name)
|
||||
if (!custom_name) return
|
||||
if (!custom_name)
|
||||
return
|
||||
steal_target = custom_target
|
||||
explanation_text = "Steal [custom_name]."
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
/datum/airlock_maker/New(var/atom/target_loc)
|
||||
linked = new(target_loc)
|
||||
linked.maker = src
|
||||
linked.anchored = FALSE
|
||||
linked.anchored = FALSE
|
||||
access_used = list()
|
||||
|
||||
interact()
|
||||
@@ -69,7 +69,8 @@
|
||||
usr << browse(dat,"window=airlockmaker")
|
||||
|
||||
/datum/airlock_maker/Topic(var/href,var/list/href_list)
|
||||
if(!usr) return
|
||||
if(!usr)
|
||||
return
|
||||
if(!src || !linked || !linked.loc)
|
||||
usr << browse(null,"window=airlockmaker")
|
||||
return
|
||||
|
||||
@@ -77,5 +77,5 @@
|
||||
|
||||
|
||||
/datum/game_mode/traitor/internal_affairs/generate_report()
|
||||
return "Nanotrasen denies any accusations of placing internal affairs agents onboard your station to eliminate inconvenient employees. Any further accusations against Centcom for such \
|
||||
return "Nanotrasen denies any accusations of placing internal affairs agents onboard your station to eliminate inconvenient employees. Any further accusations against CentCom for such \
|
||||
actions will be met with a conversation with an official internal affairs agent."
|
||||
|
||||
@@ -60,7 +60,9 @@
|
||||
|
||||
/datum/game_mode/traitor/post_setup()
|
||||
for(var/datum/mind/traitor in pre_traitors)
|
||||
addtimer(CALLBACK(traitor, /datum/mind.proc/add_antag_datum, antag_datum), rand(10,100))
|
||||
var/datum/antagonist/traitor/new_antag = new antag_datum(traitor)
|
||||
new_antag.should_specialise = TRUE
|
||||
addtimer(CALLBACK(traitor, /datum/mind.proc/add_antag_datum, new_antag), rand(10,100))
|
||||
if(!exchange_blue)
|
||||
exchange_blue = -1 //Block latejoiners from getting exchange objectives
|
||||
..()
|
||||
@@ -79,6 +81,8 @@
|
||||
add_latejoin_traitor(character.mind)
|
||||
|
||||
/datum/game_mode/traitor/proc/add_latejoin_traitor(datum/mind/character)
|
||||
var/datum/antagonist/traitor/new_antag = new antag_datum(character)
|
||||
new_antag.should_specialise = TRUE
|
||||
character.add_antag_datum(antag_datum)
|
||||
|
||||
|
||||
|
||||
@@ -44,6 +44,11 @@
|
||||
if(spent)
|
||||
to_chat(user, "<span class='cult'>This shard is spent; it is now just a creepy rock.</span>")
|
||||
|
||||
/obj/item/device/soulstone/Destroy() //Stops the shade from being qdel'd immediately and their ghost being sent back to the arrival shuttle.
|
||||
for(var/mob/living/simple_animal/shade/A in src)
|
||||
A.death()
|
||||
return ..()
|
||||
|
||||
//////////////////////////////Capturing////////////////////////////////////////////////////////
|
||||
|
||||
/obj/item/device/soulstone/attack(mob/living/carbon/human/M, mob/living/user)
|
||||
@@ -228,6 +233,7 @@
|
||||
|
||||
/obj/item/device/soulstone/proc/init_shade(mob/living/carbon/human/T, mob/U, vic = 0)
|
||||
new /obj/effect/decal/remains/human(T.loc) //Spawns a skeleton
|
||||
T.stop_sound_channel(CHANNEL_HEARTBEAT)
|
||||
T.invisibility = INVISIBILITY_ABSTRACT
|
||||
T.dust_animation()
|
||||
var/mob/living/simple_animal/shade/S = new /mob/living/simple_animal/shade(src)
|
||||
|
||||
@@ -42,7 +42,8 @@
|
||||
man is a dangerous mutant with the ability to alter himself and the world around him by what he and his leaders believe to be magic. If this man attempts an attack on your station, \
|
||||
his execution is highly encouraged, as is the preservation of his body for later study."
|
||||
|
||||
/datum/game_mode/wizard/check_finished()
|
||||
|
||||
/datum/game_mode/wizard/are_special_antags_dead()
|
||||
for(var/datum/mind/wizard in wizards)
|
||||
if(isliving(wizard.current) && wizard.current.stat!=DEAD)
|
||||
return FALSE
|
||||
@@ -54,8 +55,8 @@
|
||||
if(SSevents.wizardmode) //If summon events was active, turn it off
|
||||
SSevents.toggleWizardmode()
|
||||
SSevents.resetFrequency()
|
||||
|
||||
return ..()
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/game_mode/wizard/declare_completion()
|
||||
if(finished)
|
||||
|
||||
@@ -477,14 +477,17 @@ Class Procs:
|
||||
// Hook for html_interface module to prevent updates to clients who don't have this as their active machine.
|
||||
/obj/machinery/proc/hiIsValidClient(datum/html_interface_client/hclient, datum/html_interface/hi)
|
||||
if (hclient.client.mob && (hclient.client.mob.stat == 0 || IsAdminGhost(hclient.client.mob)))
|
||||
if (isAI(hclient.client.mob) || IsAdminGhost(hclient.client.mob)) return TRUE
|
||||
else return hclient.client.mob.machine == src && Adjacent(hclient.client.mob)
|
||||
if (isAI(hclient.client.mob) || IsAdminGhost(hclient.client.mob))
|
||||
return TRUE
|
||||
else
|
||||
return hclient.client.mob.machine == src && Adjacent(hclient.client.mob)
|
||||
else
|
||||
return FALSE
|
||||
|
||||
// Hook for html_interface module to unset the active machine when the window is closed by the player.
|
||||
/obj/machinery/proc/hiOnHide(datum/html_interface_client/hclient)
|
||||
if (hclient.client.mob && hclient.client.mob.machine == src) hclient.client.mob.unset_machine()
|
||||
if (hclient.client.mob && hclient.client.mob.machine == src)
|
||||
hclient.client.mob.unset_machine()
|
||||
|
||||
/obj/machinery/proc/can_be_overridden()
|
||||
. = 1
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
|
||||
|
||||
/obj/machinery/door/airlock/receive_signal(datum/signal/signal)
|
||||
if(!signal || signal.encryption) return
|
||||
if(!signal || signal.encryption)
|
||||
return
|
||||
|
||||
if(id_tag != signal.data["tag"] || !signal.data["command"]) return
|
||||
if(id_tag != signal.data["tag"] || !signal.data["command"])
|
||||
return
|
||||
|
||||
switch(signal.data["command"])
|
||||
if("open")
|
||||
@@ -63,12 +65,14 @@
|
||||
|
||||
/obj/machinery/door/airlock/open(surpress_send)
|
||||
. = ..()
|
||||
if(!surpress_send) send_status()
|
||||
if(!surpress_send)
|
||||
send_status()
|
||||
|
||||
|
||||
/obj/machinery/door/airlock/close(surpress_send)
|
||||
. = ..()
|
||||
if(!surpress_send) send_status()
|
||||
if(!surpress_send)
|
||||
send_status()
|
||||
|
||||
|
||||
/obj/machinery/door/airlock/proc/set_frequency(new_frequency)
|
||||
@@ -148,4 +152,4 @@
|
||||
|
||||
/obj/machinery/airlock_sensor/Destroy()
|
||||
SSradio.remove_object(src,frequency)
|
||||
return ..()
|
||||
return ..()
|
||||
|
||||
@@ -1,72 +1,71 @@
|
||||
/obj/machinery/camera
|
||||
|
||||
var/list/localMotionTargets = list()
|
||||
var/detectTime = 0
|
||||
var/area/ai_monitored/area_motion = null
|
||||
var/alarm_delay = 30 // Don't forget, there's another 3 seconds in queueAlarm()
|
||||
|
||||
/obj/machinery/camera/process()
|
||||
// motion camera event loop
|
||||
if(!isMotion())
|
||||
. = PROCESS_KILL
|
||||
return
|
||||
if (detectTime > 0)
|
||||
var/elapsed = world.time - detectTime
|
||||
if (elapsed > alarm_delay)
|
||||
triggerAlarm()
|
||||
else if (detectTime == -1)
|
||||
for (var/mob/target in getTargetList())
|
||||
if (target.stat == DEAD || (!area_motion && !in_range(src, target)))
|
||||
//If not part of a monitored area and the camera is not in range or the target is dead
|
||||
lostTarget(target)
|
||||
|
||||
/obj/machinery/camera/proc/getTargetList()
|
||||
if(area_motion)
|
||||
return area_motion.motionTargets
|
||||
return localMotionTargets
|
||||
|
||||
/obj/machinery/camera/proc/newTarget(mob/target)
|
||||
if(isAI(target))
|
||||
return 0
|
||||
if (detectTime == 0)
|
||||
detectTime = world.time // start the clock
|
||||
var/list/targets = getTargetList()
|
||||
if (!(target in targets))
|
||||
targets += target
|
||||
return 1
|
||||
|
||||
/obj/machinery/camera/Destroy()
|
||||
var/area/ai_monitored/A = get_area(src)
|
||||
if(istype(A))
|
||||
A.motioncameras -= src
|
||||
return ..()
|
||||
|
||||
/obj/machinery/camera/proc/lostTarget(mob/target)
|
||||
var/list/targets = getTargetList()
|
||||
if (target in targets)
|
||||
targets -= target
|
||||
if (targets.len == 0)
|
||||
cancelAlarm()
|
||||
|
||||
/obj/machinery/camera/proc/cancelAlarm()
|
||||
if (detectTime == -1)
|
||||
for (var/mob/living/silicon/aiPlayer in GLOB.player_list)
|
||||
if (status)
|
||||
aiPlayer.cancelAlarm("Motion", get_area(src), src)
|
||||
detectTime = 0
|
||||
return 1
|
||||
|
||||
/obj/machinery/camera/proc/triggerAlarm()
|
||||
if (!detectTime) return 0
|
||||
for (var/mob/living/silicon/aiPlayer in GLOB.player_list)
|
||||
if (status)
|
||||
aiPlayer.triggerAlarm("Motion", get_area(src), list(src), src)
|
||||
detectTime = -1
|
||||
return 1
|
||||
|
||||
/obj/machinery/camera/HasProximity(atom/movable/AM as mob|obj)
|
||||
// Motion cameras outside of an "ai monitored" area will use this to detect stuff.
|
||||
if (!area_motion)
|
||||
if(isliving(AM))
|
||||
newTarget(AM)
|
||||
|
||||
/obj/machinery/camera
|
||||
|
||||
var/list/localMotionTargets = list()
|
||||
var/detectTime = 0
|
||||
var/area/ai_monitored/area_motion = null
|
||||
var/alarm_delay = 30 // Don't forget, there's another 3 seconds in queueAlarm()
|
||||
|
||||
/obj/machinery/camera/process()
|
||||
// motion camera event loop
|
||||
if(!isMotion())
|
||||
. = PROCESS_KILL
|
||||
return
|
||||
if (detectTime > 0)
|
||||
var/elapsed = world.time - detectTime
|
||||
if (elapsed > alarm_delay)
|
||||
triggerAlarm()
|
||||
else if (detectTime == -1)
|
||||
for (var/targetref in getTargetList())
|
||||
var/mob/target = locate(targetref) in GLOB.mob_list
|
||||
if (target.stat == DEAD || QDELETED(target) || (!area_motion && !in_range(src, target)))
|
||||
//If not part of a monitored area and the camera is not in range or the target is dead
|
||||
lostTarget(target)
|
||||
|
||||
/obj/machinery/camera/proc/getTargetList()
|
||||
if(area_motion)
|
||||
return area_motion.motionTargets
|
||||
return localMotionTargets
|
||||
|
||||
/obj/machinery/camera/proc/newTarget(mob/target)
|
||||
if(isAI(target))
|
||||
return 0
|
||||
if (detectTime == 0)
|
||||
detectTime = world.time // start the clock
|
||||
var/list/targets = getTargetList()
|
||||
targets |= "\ref[target]"
|
||||
return 1
|
||||
|
||||
/obj/machinery/camera/Destroy()
|
||||
var/area/ai_monitored/A = get_area(src)
|
||||
if(istype(A))
|
||||
A.motioncameras -= src
|
||||
return ..()
|
||||
|
||||
/obj/machinery/camera/proc/lostTarget(mob/target)
|
||||
var/list/targets = getTargetList()
|
||||
targets -= "\ref[target]"
|
||||
if (targets.len == 0)
|
||||
cancelAlarm()
|
||||
|
||||
/obj/machinery/camera/proc/cancelAlarm()
|
||||
if (detectTime == -1)
|
||||
for (var/mob/living/silicon/aiPlayer in GLOB.player_list)
|
||||
if (status)
|
||||
aiPlayer.cancelAlarm("Motion", get_area(src), src)
|
||||
detectTime = 0
|
||||
return 1
|
||||
|
||||
/obj/machinery/camera/proc/triggerAlarm()
|
||||
if (!detectTime)
|
||||
return 0
|
||||
for (var/mob/living/silicon/aiPlayer in GLOB.player_list)
|
||||
if (status)
|
||||
aiPlayer.triggerAlarm("Motion", get_area(src), list(src), src)
|
||||
detectTime = -1
|
||||
return 1
|
||||
|
||||
/obj/machinery/camera/HasProximity(atom/movable/AM as mob|obj)
|
||||
// Motion cameras outside of an "ai monitored" area will use this to detect stuff.
|
||||
if (!area_motion)
|
||||
if(isliving(AM))
|
||||
newTarget(AM)
|
||||
|
||||
@@ -53,7 +53,8 @@
|
||||
var/area/A = get_area(src)
|
||||
if(A)
|
||||
for(var/obj/machinery/camera/autoname/C in GLOB.machines)
|
||||
if(C == src) continue
|
||||
if(C == src)
|
||||
continue
|
||||
var/area/CA = get_area(C)
|
||||
if(CA.type == A.type)
|
||||
if(C.number)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user