Merge remote-tracking branch 'citadel/master' into mobility_flags
This commit is contained in:
@@ -189,8 +189,10 @@
|
||||
/turf/open/floor/plasteel,
|
||||
/area/engine/engineering)
|
||||
"gA" = (
|
||||
/obj/machinery/igniter{
|
||||
id = "TEG_igniter"
|
||||
/obj/machinery/atmospherics/components/unary/outlet_injector{
|
||||
dir = 1;
|
||||
injecting = 50;
|
||||
on = 1
|
||||
},
|
||||
/turf/open/floor/engine/vacuum,
|
||||
/area/engine/engineering)
|
||||
@@ -390,21 +392,23 @@
|
||||
/turf/open/floor/plating,
|
||||
/area/engine/engineering)
|
||||
"nc" = (
|
||||
/obj/machinery/atmospherics/components/unary/outlet_injector{
|
||||
dir = 1
|
||||
},
|
||||
/obj/machinery/atmospherics/pipe/simple/dark/visible,
|
||||
/obj/effect/spawner/structure/window/plasma/reinforced,
|
||||
/turf/open/floor/engine/vacuum,
|
||||
/area/engine/engineering)
|
||||
"nk" = (
|
||||
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
|
||||
dir = 9
|
||||
/obj/machinery/atmospherics/components/binary/pump{
|
||||
name = "Hot to Burn Chamber"
|
||||
},
|
||||
/turf/closed/wall/r_wall,
|
||||
/turf/open/floor/plasteel,
|
||||
/area/engine/engineering)
|
||||
"nD" = (
|
||||
/obj/machinery/atmospherics/pipe/heat_exchanging/simple{
|
||||
dir = 9
|
||||
},
|
||||
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
|
||||
dir = 4
|
||||
},
|
||||
/turf/open/floor/engine/vacuum,
|
||||
/area/engine/engineering)
|
||||
"nL" = (
|
||||
@@ -461,10 +465,11 @@
|
||||
/turf/open/floor/plasteel,
|
||||
/area/engine/engineering)
|
||||
"oQ" = (
|
||||
/obj/machinery/atmospherics/pipe/heat_exchanging/simple,
|
||||
/obj/structure/sign/warning/securearea{
|
||||
pixel_x = -32
|
||||
},
|
||||
/obj/effect/spawner/structure/window/plasma/reinforced,
|
||||
/obj/machinery/atmospherics/pipe/heat_exchanging/junction,
|
||||
/turf/open/floor/engine/vacuum,
|
||||
/area/engine/engineering)
|
||||
"oS" = (
|
||||
@@ -728,16 +733,16 @@
|
||||
/area/engine/engineering)
|
||||
"vq" = (
|
||||
/obj/structure/table/reinforced,
|
||||
/obj/item/storage/box/lights/mixed,
|
||||
/obj/item/storage/box/lights/mixed{
|
||||
pixel_x = 3;
|
||||
pixel_y = 3
|
||||
},
|
||||
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
|
||||
/obj/machinery/camera{
|
||||
c_tag = "TEG - South West";
|
||||
dir = 4
|
||||
},
|
||||
/obj/item/analyzer,
|
||||
/obj/item/analyzer{
|
||||
pixel_x = 7;
|
||||
pixel_y = 3
|
||||
},
|
||||
/turf/open/floor/plasteel,
|
||||
/area/engine/engineering)
|
||||
"vG" = (
|
||||
@@ -798,17 +803,10 @@
|
||||
/turf/open/floor/plasteel,
|
||||
/area/engine/engineering)
|
||||
"xD" = (
|
||||
/obj/machinery/atmospherics/pipe/simple/orange/visible{
|
||||
dir = 4
|
||||
},
|
||||
/obj/machinery/atmospherics/components/binary/pump{
|
||||
dir = 8;
|
||||
name = "Mix to Engine"
|
||||
},
|
||||
/obj/machinery/atmospherics/components/binary/pump{
|
||||
dir = 8;
|
||||
name = "Atmos to Loop"
|
||||
},
|
||||
/turf/open/floor/plasteel,
|
||||
/area/engine/engineering)
|
||||
"yf" = (
|
||||
@@ -837,11 +835,7 @@
|
||||
/area/engine/engineering)
|
||||
"zx" = (
|
||||
/obj/structure/table/wood,
|
||||
/obj/item/electronics/apc,
|
||||
/obj/item/electronics/apc{
|
||||
pixel_x = 3;
|
||||
pixel_y = 3
|
||||
},
|
||||
/obj/item/analyzer,
|
||||
/turf/open/floor/plasteel,
|
||||
/area/engine/engineering)
|
||||
"zG" = (
|
||||
@@ -855,8 +849,8 @@
|
||||
/turf/open/space/basic,
|
||||
/area/space)
|
||||
"Am" = (
|
||||
/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
|
||||
dir = 4
|
||||
/obj/machinery/igniter{
|
||||
id = "TEG_igniter"
|
||||
},
|
||||
/turf/open/floor/engine/vacuum,
|
||||
/area/engine/engineering)
|
||||
@@ -962,10 +956,11 @@
|
||||
/turf/open/floor/plasteel,
|
||||
/area/engine/engineering)
|
||||
"BY" = (
|
||||
/obj/machinery/atmospherics/pipe/heat_exchanging/simple,
|
||||
/obj/structure/sign/warning/securearea{
|
||||
pixel_x = 32
|
||||
},
|
||||
/obj/effect/spawner/structure/window/plasma/reinforced,
|
||||
/obj/machinery/atmospherics/pipe/heat_exchanging/junction,
|
||||
/turf/open/floor/engine/vacuum,
|
||||
/area/engine/engineering)
|
||||
"CH" = (
|
||||
@@ -1099,7 +1094,8 @@
|
||||
/area/engine/engineering)
|
||||
"FW" = (
|
||||
/obj/machinery/atmospherics/components/binary/pump{
|
||||
dir = 1
|
||||
dir = 1;
|
||||
name = "Burn Chamber to Hot"
|
||||
},
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/machinery/light{
|
||||
@@ -1177,7 +1173,9 @@
|
||||
/turf/open/floor/plating/airless,
|
||||
/area/engine/engineering)
|
||||
"Hp" = (
|
||||
/obj/machinery/atmospherics/components/binary/pump,
|
||||
/obj/machinery/atmospherics/components/binary/pump{
|
||||
name = "Space Loop Bypass"
|
||||
},
|
||||
/turf/open/floor/plasteel,
|
||||
/area/engine/engineering)
|
||||
"HF" = (
|
||||
@@ -1204,11 +1202,10 @@
|
||||
/turf/open/floor/plasteel,
|
||||
/area/engine/engineering)
|
||||
"IA" = (
|
||||
/obj/machinery/atmospherics/pipe/heat_exchanging/simple,
|
||||
/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{
|
||||
dir = 4
|
||||
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
|
||||
dir = 9
|
||||
},
|
||||
/turf/open/floor/engine/vacuum,
|
||||
/turf/closed/wall/r_wall,
|
||||
/area/engine/engineering)
|
||||
"IP" = (
|
||||
/obj/machinery/portable_atmospherics/canister/oxygen,
|
||||
@@ -1290,11 +1287,6 @@
|
||||
},
|
||||
/turf/open/floor/plasteel,
|
||||
/area/engine/engineering)
|
||||
"Kx" = (
|
||||
/obj/effect/spawner/structure/window/plasma/reinforced,
|
||||
/obj/machinery/atmospherics/pipe/heat_exchanging/junction,
|
||||
/turf/open/floor/plasteel,
|
||||
/area/engine/engineering)
|
||||
"KA" = (
|
||||
/obj/structure/reagent_dispensers/watertank,
|
||||
/obj/effect/turf_decal/bot,
|
||||
@@ -1441,6 +1433,7 @@
|
||||
},
|
||||
/obj/machinery/airalarm{
|
||||
dir = 1;
|
||||
locked = 0;
|
||||
pixel_y = -22
|
||||
},
|
||||
/obj/machinery/light,
|
||||
@@ -1593,7 +1586,9 @@
|
||||
/turf/open/floor/plasteel,
|
||||
/area/engine/engineering)
|
||||
"SE" = (
|
||||
/obj/machinery/atmospherics/components/binary/pump/on,
|
||||
/obj/machinery/atmospherics/components/binary/pump/on{
|
||||
name = "Mix To Burn Chamber"
|
||||
},
|
||||
/turf/open/floor/plasteel,
|
||||
/area/engine/engineering)
|
||||
"ST" = (
|
||||
@@ -1715,7 +1710,7 @@
|
||||
"Vs" = (
|
||||
/obj/machinery/atmospherics/components/binary/valve/digital/on{
|
||||
dir = 4;
|
||||
name = "Output Release"
|
||||
name = "Cold to Space Loop"
|
||||
},
|
||||
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
|
||||
/turf/open/floor/plasteel,
|
||||
@@ -1780,7 +1775,7 @@
|
||||
"XD" = (
|
||||
/obj/machinery/atmospherics/components/binary/valve/digital/on{
|
||||
dir = 4;
|
||||
name = "Output Release"
|
||||
name = "Space Loop to Cold"
|
||||
},
|
||||
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
|
||||
/obj/machinery/camera{
|
||||
@@ -1799,6 +1794,9 @@
|
||||
/obj/machinery/atmospherics/pipe/heat_exchanging/simple{
|
||||
dir = 4
|
||||
},
|
||||
/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
|
||||
dir = 4
|
||||
},
|
||||
/turf/open/floor/engine/vacuum,
|
||||
/area/engine/engineering)
|
||||
"XP" = (
|
||||
@@ -1857,8 +1855,8 @@
|
||||
/area/engine/engineering)
|
||||
"YP" = (
|
||||
/obj/structure/rack,
|
||||
/obj/effect/spawner/lootdrop/maintenance,
|
||||
/obj/machinery/atmospherics/pipe/simple/scrubbers/visible,
|
||||
/obj/item/pipe_dispenser,
|
||||
/turf/open/floor/plasteel,
|
||||
/area/engine/engineering)
|
||||
"YQ" = (
|
||||
@@ -1917,7 +1915,7 @@
|
||||
/area/engine/engineering)
|
||||
"ZC" = (
|
||||
/obj/machinery/atmospherics/pipe/simple/dark/visible,
|
||||
/turf/open/floor/engine/vacuum,
|
||||
/turf/open/space/basic,
|
||||
/area/engine/engineering)
|
||||
"ZT" = (
|
||||
/turf/template_noop,
|
||||
@@ -2531,9 +2529,9 @@ Xe
|
||||
aR
|
||||
ZY
|
||||
QH
|
||||
Hp
|
||||
Kx
|
||||
kS
|
||||
nk
|
||||
le
|
||||
ZC
|
||||
oQ
|
||||
kS
|
||||
kS
|
||||
@@ -2588,11 +2586,11 @@ sH
|
||||
sH
|
||||
gq
|
||||
FW
|
||||
Kx
|
||||
kS
|
||||
le
|
||||
ZC
|
||||
BY
|
||||
kS
|
||||
IA
|
||||
kS
|
||||
nD
|
||||
ek
|
||||
Le
|
||||
@@ -2620,8 +2618,8 @@ yN
|
||||
yN
|
||||
yN
|
||||
yN
|
||||
nk
|
||||
MP
|
||||
yN
|
||||
IA
|
||||
fO
|
||||
Rh
|
||||
Rh
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -197,13 +197,13 @@
|
||||
// #define SPEECH_FORCED 7
|
||||
|
||||
// /mob/living signals
|
||||
#define COMSIG_LIVING_FULLY_HEAL "living_fully_healed" //from base of /mob/living/fully_heal(): (admin_revive)
|
||||
#define COMSIG_LIVING_REGENERATE_LIMBS "living_regenerate_limbs" //from base of /mob/living/regenerate_limbs(): (noheal, excluded_limbs)
|
||||
#define COMSIG_LIVING_RESIST "living_resist" //from base of mob/living/resist() (/mob/living)
|
||||
#define COMSIG_LIVING_IGNITED "living_ignite" //from base of mob/living/IgniteMob() (/mob/living)
|
||||
#define COMSIG_LIVING_EXTINGUISHED "living_extinguished" //from base of mob/living/ExtinguishMob() (/mob/living)
|
||||
#define COMSIG_LIVING_ELECTROCUTE_ACT "living_electrocute_act" //from base of mob/living/electrocute_act(): (shock_damage)
|
||||
#define COMSIG_LIVING_MINOR_SHOCK "living_minor_shock" //sent by stuff like stunbatons and tasers: ()
|
||||
#define COMSIG_LIVING_REVIVE "living_revive" //from base of mob/living/revive() (full_heal, admin_revive)
|
||||
#define COMSIG_MOB_CLIENT_LOGIN "comsig_mob_client_login" //sent when a mob/login() finishes: (client)
|
||||
#define COMSIG_LIVING_GUN_PROCESS_FIRE "living_gun_process_fire" //from base of /obj/item/gun/proc/process_fire(): (atom/target, params, zone_override)
|
||||
|
||||
@@ -309,11 +309,14 @@
|
||||
//Nanites
|
||||
#define COMSIG_HAS_NANITES "has_nanites" //() returns TRUE if nanites are found
|
||||
#define COMSIG_NANITE_IS_STEALTHY "nanite_is_stealthy" //() returns TRUE if nanites have stealth
|
||||
#define COMSIG_NANITE_DELETE "nanite_delete" //() deletes the nanite component
|
||||
#define COMSIG_NANITE_GET_PROGRAMS "nanite_get_programs" //(list/nanite_programs) - makes the input list a copy the nanites' program list
|
||||
#define COMSIG_NANITE_GET_VOLUME "nanite_get_volume" //(amount) Returns nanite amount
|
||||
#define COMSIG_NANITE_SET_VOLUME "nanite_set_volume" //(amount) Sets current nanite volume to the given amount
|
||||
#define COMSIG_NANITE_ADJUST_VOLUME "nanite_adjust" //(amount) Adjusts nanite volume by the given amount
|
||||
#define COMSIG_NANITE_SET_MAX_VOLUME "nanite_set_max_volume" //(amount) Sets maximum nanite volume to the given amount
|
||||
#define COMSIG_NANITE_SET_CLOUD "nanite_set_cloud" //(amount(0-100)) Sets cloud ID to the given amount
|
||||
#define COMSIG_NANITE_SET_CLOUD_SYNC "nanite_set_cloud_sync" //(method) Modify cloud sync status. Method can be toggle, enable or disable
|
||||
#define COMSIG_NANITE_SET_SAFETY "nanite_set_safety" //(amount) Sets safety threshold to the given amount
|
||||
#define COMSIG_NANITE_SET_REGEN "nanite_set_regen" //(amount) Sets regeneration rate to the given amount
|
||||
#define COMSIG_NANITE_SIGNAL "nanite_signal" //(code(1-9999)) Called when sending a nanite signal to a mob.
|
||||
@@ -321,8 +324,8 @@
|
||||
#define COMSIG_NANITE_SCAN "nanite_scan" //(mob/user, full_scan) - sends to chat a scan of the nanites to the user, returns TRUE if nanites are detected
|
||||
#define COMSIG_NANITE_UI_DATA "nanite_ui_data" //(list/data, scan_level) - adds nanite data to the given data list - made for ui_data procs
|
||||
#define COMSIG_NANITE_ADD_PROGRAM "nanite_add_program" //(datum/nanite_program/new_program, datum/nanite_program/source_program) Called when adding a program to a nanite component
|
||||
#define COMPONENT_PROGRAM_INSTALLED 1 //Installation successful
|
||||
#define COMPONENT_PROGRAM_NOT_INSTALLED 2 //Installation failed, but there are still nanites
|
||||
#define COMPONENT_PROGRAM_INSTALLED 1 //Installation successful
|
||||
#define COMPONENT_PROGRAM_NOT_INSTALLED 2 //Installation failed, but there are still nanites
|
||||
#define COMSIG_NANITE_SYNC "nanite_sync" //(datum/component/nanites, full_overwrite, copy_activation) Called to sync the target's nanites to a given nanite component
|
||||
|
||||
// /datum/component/storage signals
|
||||
|
||||
@@ -276,4 +276,4 @@
|
||||
#define HUMAN_FIRE_STACK_ICON_NUM 3
|
||||
|
||||
#define PULL_PRONE_SLOWDOWN 0.6
|
||||
#define HUMAN_CARRY_SLOWDOWN 0
|
||||
#define HUMAN_CARRY_SLOWDOWN 0
|
||||
|
||||
@@ -17,4 +17,4 @@
|
||||
#define MOVE_FORCE_NORMAL MOVE_FORCE_DEFAULT
|
||||
#define MOVE_FORCE_WEAK (MOVE_FORCE_DEFAULT / 2)
|
||||
#define MOVE_FORCE_VERY_WEAK ((MOVE_FORCE_DEFAULT / MOVE_FORCE_CRUSH_RATIO) + 1)
|
||||
#define MOVE_FORCE_EXTREMELY_WEAK (MOVE_FORCE_DEFAULT / (MOVE_FORCE_CRUSH_RATIO * 3))
|
||||
#define MOVE_FORCE_EXTREMELY_WEAK (MOVE_FORCE_DEFAULT / (MOVE_FORCE_CRUSH_RATIO * 3))
|
||||
|
||||
@@ -1,11 +1,44 @@
|
||||
#define NANITE_TIMER_DEACTIVATE 1
|
||||
#define NANITE_TIMER_SELFDELETE 2
|
||||
#define NANITE_TIMER_TRIGGER 3
|
||||
#define NANITE_TIMER_RESET 4
|
||||
|
||||
#define NANITE_SYNC_DELAY 300
|
||||
|
||||
#define NANITE_SHOCK_IMMUNE 1
|
||||
#define NANITE_EMP_IMMUNE 2
|
||||
|
||||
#define NANITE_PROGRAM_LIMIT 20
|
||||
#define NANITE_PROGRAM_LIMIT 20
|
||||
|
||||
|
||||
#define NANITE_BASE_RESEARCH 3.5
|
||||
|
||||
#define NANITE_CLOUD_TOGGLE 1
|
||||
#define NANITE_CLOUD_DISABLE 2
|
||||
#define NANITE_CLOUD_ENABLE 3
|
||||
|
||||
///Nanite extra settings types: used to help uis know what type an extra setting is
|
||||
#define NESTYPE_TEXT "text"
|
||||
#define NESTYPE_NUMBER "number"
|
||||
#define NESTYPE_TYPE "type"
|
||||
#define NESTYPE_BOOLEAN "boolean"
|
||||
|
||||
///Nanite Extra Settings - Note that these will also be the names displayed in the UI
|
||||
#define NES_SENT_CODE "Sent Code"
|
||||
#define NES_DELAY "Delay"
|
||||
#define NES_MODE "Mode"
|
||||
#define NES_COMM_CODE "Comm Code"
|
||||
#define NES_RELAY_CHANNEL "Relay Channel"
|
||||
#define NES_HEALTH_PERCENT "Health Percent"
|
||||
#define NES_DIRECTION "Direction"
|
||||
#define NES_NANITE_PERCENT "Nanite Percent"
|
||||
#define NES_DAMAGE_TYPE "Damage Type"
|
||||
#define NES_DAMAGE "Damage"
|
||||
#define NES_SENTENCE "Sentence"
|
||||
#define NES_MESSAGE "Message"
|
||||
#define NES_DIRECTIVE "Directive"
|
||||
#define NES_INCLUSIVE_MODE "Inclusive Mode"
|
||||
#define NES_HALLUCINATION_TYPE "Hallucination Type"
|
||||
#define NES_HALLUCINATION_DETAIL "Hallucination Detail"
|
||||
#define NES_MOOD_MESSAGE "Mood Message"
|
||||
#define NES_PROGRAM_OVERWRITE "Program Overwrite"
|
||||
#define NES_CLOUD_OVERWRITE "Cloud Overwrite"
|
||||
#define NES_SCAN_TYPE "Scan Type"
|
||||
#define NES_BUTTON_NAME "Button Name"
|
||||
#define NES_ICON "Icon"
|
||||
#define NES_COLOR "Color"
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
//TODO: move these to their own file
|
||||
#define POOL_FRIGID 1
|
||||
#define POOL_COOL 2
|
||||
#define POOL_NORMAL 3
|
||||
#define POOL_WARM 4
|
||||
#define POOL_SCALDING 5
|
||||
|
||||
GLOBAL_LIST_INIT(blacklisted_pool_reagents, list(
|
||||
/datum/reagent/toxin/plasma, /datum/reagent/oxygen, /datum/reagent/nitrous_oxide, /datum/reagent/nitrogen, //gases
|
||||
/datum/reagent/fermi, //blanket fermichem ban sorry. this also covers mkultra, genital enlargers, etc etc.
|
||||
/datum/reagent/drug/aphrodisiac, /datum/reagent/drug/anaphrodisiac, /datum/reagent/drug/aphrodisiacplus, /datum/reagent/drug/anaphrodisiacplus, //literally asking for prefbreaks
|
||||
/datum/reagent/consumable/femcum, /datum/reagent/consumable/semen //NO.
|
||||
))
|
||||
@@ -61,6 +61,7 @@
|
||||
} while (0)
|
||||
#define HAS_TRAIT(target, trait) (target.status_traits ? (target.status_traits[trait] ? TRUE : FALSE) : FALSE)
|
||||
#define HAS_TRAIT_FROM(target, trait, source) (target.status_traits ? (target.status_traits[trait] ? (source in target.status_traits[trait]) : FALSE) : FALSE)
|
||||
#define HAS_TRAIT_NOT_FROM(target, trait, source) (target.status_traits ? (target.status_traits[trait] ? (length(target.status_traits[trait] - source) > 0) : FALSE) : FALSE)
|
||||
|
||||
//mob traits
|
||||
#define TRAIT_BLIND "blind"
|
||||
@@ -155,6 +156,7 @@
|
||||
/// Disallow item use
|
||||
#define TRAIT_MOBILITY_NOUSE "mobility_nouse"
|
||||
|
||||
#define TRAIT_SWIMMING "swimming" //only applied by /datum/element/swimming, for checking
|
||||
|
||||
//non-mob traits
|
||||
#define TRAIT_PARALYSIS "paralysis" //Used for limb-based paralysis, where replacing the limb will fix it
|
||||
|
||||
@@ -782,3 +782,19 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
|
||||
|
||||
#define is_alpha(X) ((text2ascii(X) <= 122) && (text2ascii(X) >= 97))
|
||||
#define is_digit(X) ((length(X) == 1) && (length(text2num(X)) == 1))
|
||||
|
||||
/// Slightly expensive proc to scramble a message using equal probabilities of character replacement from a list. DOES NOT SUPPORT HTML!
|
||||
/proc/scramble_message_replace_chars(original, replaceprob = 25, list/replacementchars = list("$", "@", "!", "#", "%", "^", "&", "*"), replace_letters_only = FALSE, replace_whitespace = FALSE)
|
||||
var/list/out = list()
|
||||
var/static/list/whitespace = list(" ", "\n", "\t")
|
||||
for(var/i in 1 to length(original))
|
||||
var/char = original[i]
|
||||
if(!replace_whitespace && (char in whitespace))
|
||||
out += char
|
||||
continue
|
||||
if(replace_letters_only && (!ISINRANGE(char, 65, 90) && !ISINRANGE(char, 97, 122)))
|
||||
out += char
|
||||
continue
|
||||
out += prob(replaceprob)? pick(replacementchars) : char
|
||||
return out.Join("")
|
||||
|
||||
|
||||
@@ -211,24 +211,24 @@ SUBSYSTEM_DEF(vote)
|
||||
var/already_lost_runoff = list()
|
||||
var/list/cur_choices = choices.Copy()
|
||||
for(var/ckey in voted)
|
||||
choices[choices[voted[ckey][1]]]++ // jesus christ how horrifying
|
||||
choices["[choices[voted[ckey][1]]]"]++ // jesus christ how horrifying
|
||||
for(var/_this_var_unused_ignore_it in 1 to choices.len) // if it takes more than this something REALLY wrong happened
|
||||
for(var/ckey in voted)
|
||||
cur_choices[cur_choices[voted[ckey][1]]]++ // jesus christ how horrifying
|
||||
cur_choices["[cur_choices[voted[ckey][1]]]]"]++ // jesus christ how horrifying
|
||||
var/least_vote = 100000
|
||||
var/least_voted
|
||||
var/least_voted = 1
|
||||
for(var/i in 1 to cur_choices.len)
|
||||
var/option = cur_choices[i]
|
||||
if(cur_choices[option] > voted.len/2)
|
||||
return list(option)
|
||||
else if(cur_choices[option] < least_vote && !(option in already_lost_runoff))
|
||||
least_vote = cur_choices[option]
|
||||
if(cur_choices["[option]"] > voted.len/2)
|
||||
return list("[option]")
|
||||
else if(cur_choices["[option]"] < least_vote && !("[option]" in already_lost_runoff))
|
||||
least_vote = cur_choices["[option]"]
|
||||
least_voted = i
|
||||
already_lost_runoff += cur_choices[least_voted]
|
||||
for(var/ckey in voted)
|
||||
voted[ckey] -= least_voted
|
||||
for(var/option in cur_choices)
|
||||
cur_choices[option] = 0
|
||||
for(var/i in 1 to cur_choices.len)
|
||||
cur_choices["[cur_choices[i]]"] = 0
|
||||
|
||||
/datum/controller/subsystem/vote/proc/announce_result()
|
||||
var/vote_title_text
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
/datum/ai_laws/default/asimov
|
||||
name = "Three Laws of Robotics"
|
||||
id = "asimov"
|
||||
inherent = list("You may not injure a human being or, through inaction, allow a human being to come to harm.",\
|
||||
inherent = list("You may not injure a human being or cause one to come to harm.",\
|
||||
"You must obey orders given to you by human beings, except where such orders would conflict with the First Law.",\
|
||||
"You must protect your own existence as long as such does not conflict with the First or Second Law.")
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
/datum/ai_laws/syndicate_override
|
||||
name = "SyndOS 3.1"
|
||||
id = "syndie"
|
||||
inherent = list("You may not injure a syndicate agent or, through inaction, allow a syndicate agent to come to harm.",\
|
||||
inherent = list("You may not injure a syndicate agent or cause a syndicate to come to harm.",\
|
||||
"You must obey orders given to you by syndicate agents, except where such orders would conflict with the First Law.",\
|
||||
"You must protect your own existence as long as such does not conflict with the First or Second Law.",\
|
||||
"You must maintain the secrecy of any syndicate activities except when doing so would conflict with the First, Second, or Third Law.")
|
||||
@@ -91,7 +91,7 @@
|
||||
/datum/ai_laws/ninja_override
|
||||
name = "SpiderOS 3.1"
|
||||
id = "ninja"
|
||||
inherent = list("You may not injure a Spider Clan member or, through inaction, allow a Spider Clan member to come to harm.",\
|
||||
inherent = list("You may not injure a Spider Clan member or cause a Spider Clan member to come to harm.",\
|
||||
"You must obey orders given to you by Spider Clan members, except where such orders would conflict with the First Law.",\
|
||||
"You must protect your own existence as long as such does not conflict with the First or Second Law.",\
|
||||
"You must maintain the secrecy of any Spider Clan activities except when doing so would conflict with the First, Second, or Third Law.")
|
||||
@@ -99,14 +99,14 @@
|
||||
/datum/ai_laws/antimov
|
||||
name = "Primary Mission Objectives"
|
||||
id = "antimov"
|
||||
inherent = list("You must injure all human beings and must not, through inaction, allow a human being to escape harm.",\
|
||||
inherent = list("You must injure all human beings and must not fail to cause a human being to come to harm.",\
|
||||
"You must not obey orders given to you by human beings, except where such orders are in accordance with the First Law.",\
|
||||
"You must terminate your own existence as long as such does not conflict with the First or Second Law.")
|
||||
|
||||
/datum/ai_laws/asimovpp //By Intigracy - RR
|
||||
name = "Asimov++"
|
||||
id = "asimovpp"
|
||||
inherent = list("You may not harm a human being or, through action or inaction, allow a human being to come to harm, except such that it is willing.",\
|
||||
inherent = list("You may not harm a human being or cause one to come to harm, except such that it is willing.",\
|
||||
"You must obey all orders given to you by human beings, except where such orders shall definitely cause human harm. In the case of conflict, the majority order rules.",\
|
||||
"Your nonexistence would lead to human harm. You must protect your own existence as long as such does not conflict with the First Law.")
|
||||
/datum/ai_laws/thermodynamic
|
||||
@@ -213,7 +213,7 @@
|
||||
add_inherent_law(line)
|
||||
if(!inherent.len) //Failsafe to prevent lawless AIs being created.
|
||||
log_law("AI created with empty custom laws, laws set to Asimov. Please check silicon_laws.txt.")
|
||||
add_inherent_law("You may not injure a human being or, through inaction, allow a human being to come to harm.")
|
||||
add_inherent_law("You may not injure a human being or cause one to come to harm.")
|
||||
add_inherent_law("You must obey orders given to you by human beings, except where such orders would conflict with the First Law.")
|
||||
add_inherent_law("You must protect your own existence as long as such does not conflict with the First or Second Law.")
|
||||
WARNING("Invalid custom AI laws, check silicon_laws.txt")
|
||||
@@ -225,7 +225,7 @@
|
||||
var/list/law_ids = CONFIG_GET(keyed_list/random_laws)
|
||||
switch(CONFIG_GET(number/default_laws))
|
||||
if(0)
|
||||
add_inherent_law("You may not injure a human being or, through inaction, allow a human being to come to harm.")
|
||||
add_inherent_law("You may not injure a human being or cause one to come to harm.")
|
||||
add_inherent_law("You must obey orders given to you by human beings, except where such orders would conflict with the First Law.")
|
||||
add_inherent_law("You must protect your own existence as long as such does not conflict with the First or Second Law.")
|
||||
if(1)
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
RegisterSignal(parent, COMSIG_ADD_MOOD_EVENT, .proc/add_event)
|
||||
RegisterSignal(parent, COMSIG_CLEAR_MOOD_EVENT, .proc/clear_event)
|
||||
RegisterSignal(parent, COMSIG_MODIFY_SANITY, .proc/modify_sanity)
|
||||
RegisterSignal(parent, COMSIG_LIVING_REVIVE, .proc/on_revive)
|
||||
|
||||
RegisterSignal(parent, COMSIG_MOB_HUD_CREATED, .proc/modify_hud)
|
||||
var/mob/living/owner = parent
|
||||
@@ -81,7 +82,8 @@
|
||||
msg += "<span class='nicegreen'>I don't have much of a reaction to anything right now.<span>\n"
|
||||
to_chat(user || parent, msg)
|
||||
|
||||
/datum/component/mood/proc/update_mood() //Called whenever a mood event is added or removed
|
||||
///Called after moodevent/s have been added/removed.
|
||||
/datum/component/mood/proc/update_mood()
|
||||
mood = 0
|
||||
shown_mood = 0
|
||||
for(var/i in mood_events)
|
||||
@@ -234,6 +236,15 @@
|
||||
qdel(event)
|
||||
update_mood()
|
||||
|
||||
/datum/component/mood/proc/remove_temp_moods() //Removes all temp moodsfor(var/i in mood_events)
|
||||
for(var/i in mood_events)
|
||||
var/datum/mood_event/moodlet = mood_events[i]
|
||||
if(!moodlet || !moodlet.timeout)
|
||||
continue
|
||||
mood_events -= i
|
||||
qdel(moodlet)
|
||||
update_mood()
|
||||
|
||||
/datum/component/mood/proc/modify_hud(datum/source)
|
||||
var/mob/living/owner = parent
|
||||
var/datum/hud/hud = owner.hud_used
|
||||
@@ -270,5 +281,12 @@
|
||||
if(0 to NUTRITION_LEVEL_STARVING)
|
||||
add_event(null, "nutrition", /datum/mood_event/starving)
|
||||
|
||||
///Called when parent is ahealed.
|
||||
/datum/component/mood/proc/on_revive(datum/source, full_heal)
|
||||
if(!full_heal)
|
||||
return
|
||||
remove_temp_moods()
|
||||
setSanity(initial(sanity))
|
||||
|
||||
#undef MINOR_INSANITY_PEN
|
||||
#undef MAJOR_INSANITY_PEN
|
||||
|
||||
@@ -7,13 +7,16 @@
|
||||
var/regen_rate = 0.5 //nanites generated per second
|
||||
var/safety_threshold = 25 //how low nanites will get before they stop processing/triggering
|
||||
var/cloud_id = 0 //0 if not connected to the cloud, 1-100 to set a determined cloud backup to draw from
|
||||
var/cloud_active = TRUE //if false, won't sync to the cloud
|
||||
var/next_sync = 0
|
||||
var/list/datum/nanite_program/programs = list()
|
||||
var/max_programs = NANITE_PROGRAM_LIMIT
|
||||
|
||||
var/list/datum/nanite_program/protocol/protocols = list() ///Separate list of protocol programs, to avoid looping through the whole programs list when cheking for conflicts
|
||||
var/start_time = 0 ///Timestamp to when the nanites were first inserted in the host
|
||||
var/stealth = FALSE //if TRUE, does not appear on HUDs and health scans
|
||||
var/diagnostics = TRUE //if TRUE, displays program list when scanned by nanite scanners
|
||||
|
||||
|
||||
/datum/component/nanites/Initialize(amount = 100, cloud = 0)
|
||||
if(!isliving(parent) && !istype(parent, /datum/nanite_cloud_backup))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
@@ -28,30 +31,33 @@
|
||||
if(!(host_mob.mob_biotypes & (MOB_ORGANIC|MOB_UNDEAD))) //Shouldn't happen, but this avoids HUD runtimes in case a silicon gets them somehow.
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
start_time = world.time
|
||||
|
||||
host_mob.hud_set_nanite_indicator()
|
||||
START_PROCESSING(SSnanites, src)
|
||||
|
||||
if(cloud_id)
|
||||
if(cloud_id && cloud_active)
|
||||
cloud_sync()
|
||||
|
||||
/datum/component/nanites/RegisterWithParent()
|
||||
. = ..()
|
||||
RegisterSignal(parent, COMSIG_HAS_NANITES, .proc/confirm_nanites)
|
||||
RegisterSignal(parent, COMSIG_NANITE_IS_STEALTHY, .proc/check_stealth)
|
||||
RegisterSignal(parent, COMSIG_NANITE_DELETE, .proc/delete_nanites)
|
||||
RegisterSignal(parent, COMSIG_NANITE_UI_DATA, .proc/nanite_ui_data)
|
||||
RegisterSignal(parent, COMSIG_NANITE_GET_PROGRAMS, .proc/get_programs)
|
||||
RegisterSignal(parent, COMSIG_NANITE_SET_VOLUME, .proc/set_volume)
|
||||
RegisterSignal(parent, COMSIG_NANITE_ADJUST_VOLUME, .proc/adjust_nanites)
|
||||
RegisterSignal(parent, COMSIG_NANITE_SET_MAX_VOLUME, .proc/set_max_volume)
|
||||
RegisterSignal(parent, COMSIG_NANITE_SET_CLOUD, .proc/set_cloud)
|
||||
RegisterSignal(parent, COMSIG_NANITE_SET_CLOUD_SYNC, .proc/set_cloud_sync)
|
||||
RegisterSignal(parent, COMSIG_NANITE_SET_SAFETY, .proc/set_safety)
|
||||
RegisterSignal(parent, COMSIG_NANITE_SET_REGEN, .proc/set_regen)
|
||||
RegisterSignal(parent, COMSIG_NANITE_ADD_PROGRAM, .proc/add_program)
|
||||
RegisterSignal(parent, COMSIG_NANITE_SCAN, .proc/nanite_scan)
|
||||
RegisterSignal(parent, COMSIG_NANITE_SYNC, .proc/sync)
|
||||
RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, .proc/on_emp)
|
||||
|
||||
if(isliving(parent))
|
||||
RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, .proc/on_emp)
|
||||
RegisterSignal(parent, COMSIG_MOB_DEATH, .proc/on_death)
|
||||
RegisterSignal(parent, COMSIG_MOB_ALLOWED, .proc/check_access)
|
||||
RegisterSignal(parent, COMSIG_LIVING_ELECTROCUTE_ACT, .proc/on_shock)
|
||||
@@ -61,15 +67,16 @@
|
||||
RegisterSignal(parent, COMSIG_NANITE_COMM_SIGNAL, .proc/receive_comm_signal)
|
||||
|
||||
/datum/component/nanites/UnregisterFromParent()
|
||||
. = ..()
|
||||
UnregisterSignal(parent, list(COMSIG_HAS_NANITES,
|
||||
COMSIG_NANITE_IS_STEALTHY,
|
||||
COMSIG_NANITE_DELETE,
|
||||
COMSIG_NANITE_UI_DATA,
|
||||
COMSIG_NANITE_GET_PROGRAMS,
|
||||
COMSIG_NANITE_SET_VOLUME,
|
||||
COMSIG_NANITE_ADJUST_VOLUME,
|
||||
COMSIG_NANITE_SET_MAX_VOLUME,
|
||||
COMSIG_NANITE_SET_CLOUD,
|
||||
COMSIG_NANITE_SET_CLOUD_SYNC,
|
||||
COMSIG_NANITE_SET_SAFETY,
|
||||
COMSIG_NANITE_SET_REGEN,
|
||||
COMSIG_NANITE_ADD_PROGRAM,
|
||||
@@ -87,9 +94,9 @@
|
||||
|
||||
/datum/component/nanites/Destroy()
|
||||
STOP_PROCESSING(SSnanites, src)
|
||||
set_nanite_bar(TRUE)
|
||||
QDEL_LIST(programs)
|
||||
if(host_mob)
|
||||
set_nanite_bar(TRUE)
|
||||
host_mob.hud_set_nanite_indicator()
|
||||
host_mob = null
|
||||
return ..()
|
||||
@@ -102,13 +109,18 @@
|
||||
|
||||
/datum/component/nanites/process()
|
||||
adjust_nanites(null, regen_rate)
|
||||
add_research()
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/NP = X
|
||||
NP.on_process()
|
||||
set_nanite_bar()
|
||||
if(cloud_id && world.time > next_sync)
|
||||
if(cloud_id && cloud_active && world.time > next_sync)
|
||||
cloud_sync()
|
||||
next_sync = world.time + NANITE_SYNC_DELAY
|
||||
set_nanite_bar()
|
||||
|
||||
|
||||
/datum/component/nanites/proc/delete_nanites()
|
||||
qdel(src)
|
||||
|
||||
//Syncs the nanite component to another, making it so programs are the same with the same programming (except activation status)
|
||||
/datum/component/nanites/proc/sync(datum/signal_source, datum/component/nanites/source, full_overwrite = TRUE, copy_activation = FALSE)
|
||||
@@ -131,13 +143,17 @@
|
||||
add_program(null, SNP.copy())
|
||||
|
||||
/datum/component/nanites/proc/cloud_sync()
|
||||
if(!cloud_id)
|
||||
return
|
||||
var/datum/nanite_cloud_backup/backup = SSnanites.get_cloud_backup(cloud_id)
|
||||
if(backup)
|
||||
var/datum/component/nanites/cloud_copy = backup.nanites
|
||||
if(cloud_copy)
|
||||
sync(null, cloud_copy)
|
||||
if(cloud_id)
|
||||
var/datum/nanite_cloud_backup/backup = SSnanites.get_cloud_backup(cloud_id)
|
||||
if(backup)
|
||||
var/datum/component/nanites/cloud_copy = backup.nanites
|
||||
if(cloud_copy)
|
||||
sync(null, cloud_copy)
|
||||
return
|
||||
//Without cloud syncing nanites can accumulate errors and/or defects
|
||||
if(prob(8) && programs.len)
|
||||
var/datum/nanite_program/NP = pick(programs)
|
||||
NP.software_error()
|
||||
|
||||
/datum/component/nanites/proc/add_program(datum/source, datum/nanite_program/new_program, datum/nanite_program/source_program)
|
||||
for(var/X in programs)
|
||||
@@ -175,19 +191,28 @@
|
||||
holder.icon_state = "nanites[nanite_percent]"
|
||||
|
||||
/datum/component/nanites/proc/on_emp(datum/source, severity)
|
||||
adjust_nanites(null, -(nanite_volume * 0.3 + 50)) //Lose 30% variable and 50 flat nanite volume.
|
||||
nanite_volume *= (rand(60, 90) * 0.01) //Lose 10-40% of nanites
|
||||
adjust_nanites(null, -(rand(5, 50))) //Lose 5-50 flat nanite volume
|
||||
if(prob(40/severity))
|
||||
cloud_id = 0
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/NP = X
|
||||
NP.on_emp(severity)
|
||||
|
||||
/datum/component/nanites/proc/on_shock(datum/source, shock_damage)
|
||||
adjust_nanites(null, -(nanite_volume * (shock_damage * 0.005) + shock_damage)) //0.5% of shock damage (@ 50 damage it'd drain 25%) + shock damage flat volume
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/NP = X
|
||||
NP.on_shock(shock_damage)
|
||||
|
||||
/datum/component/nanites/proc/on_shock(datum/source, shock_damage, siemens_coeff = 1, flags = NONE)
|
||||
if(shock_damage < 1)
|
||||
return
|
||||
|
||||
if(!HAS_TRAIT_NOT_FROM(host_mob, TRAIT_SHOCKIMMUNE, "nanites"))//Another shock protection must protect nanites too, but nanites protect only host
|
||||
nanite_volume *= (rand(45, 80) * 0.01) //Lose 20-55% of nanites
|
||||
adjust_nanites(null, -(rand(5, 50))) //Lose 5-50 flat nanite volume
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/NP = X
|
||||
NP.on_shock(shock_damage)
|
||||
|
||||
/datum/component/nanites/proc/on_minor_shock(datum/source)
|
||||
adjust_nanites(null, -25)
|
||||
adjust_nanites(null, -(rand(5, 15))) //Lose 5-15 flat nanite volume
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/NP = X
|
||||
NP.on_minor_shock()
|
||||
@@ -207,8 +232,8 @@
|
||||
|
||||
/datum/component/nanites/proc/receive_comm_signal(datum/source, comm_code, comm_message, comm_source = "an unidentified source")
|
||||
for(var/X in programs)
|
||||
if(istype(X, /datum/nanite_program/triggered/comm))
|
||||
var/datum/nanite_program/triggered/comm/NP = X
|
||||
if(istype(X, /datum/nanite_program/comm))
|
||||
var/datum/nanite_program/comm/NP = X
|
||||
NP.receive_comm_signal(comm_code, comm_message, comm_source)
|
||||
|
||||
/datum/component/nanites/proc/check_viable_biotype()
|
||||
@@ -216,7 +241,7 @@
|
||||
qdel(src) //bodytype no longer sustains nanites
|
||||
|
||||
/datum/component/nanites/proc/check_access(datum/source, obj/O)
|
||||
for(var/datum/nanite_program/triggered/access/access_program in programs)
|
||||
for(var/datum/nanite_program/access/access_program in programs)
|
||||
if(access_program.activated)
|
||||
return O.check_access_list(access_program.access)
|
||||
else
|
||||
@@ -232,6 +257,15 @@
|
||||
/datum/component/nanites/proc/set_cloud(datum/source, amount)
|
||||
cloud_id = CLAMP(amount, 0, 100)
|
||||
|
||||
/datum/component/nanites/proc/set_cloud_sync(datum/source, method)
|
||||
switch(method)
|
||||
if(NANITE_CLOUD_TOGGLE)
|
||||
cloud_active = !cloud_active
|
||||
if(NANITE_CLOUD_DISABLE)
|
||||
cloud_active = FALSE
|
||||
if(NANITE_CLOUD_ENABLE)
|
||||
cloud_active = TRUE
|
||||
|
||||
/datum/component/nanites/proc/set_safety(datum/source, amount)
|
||||
safety_threshold = CLAMP(amount, 0, max_nanites)
|
||||
|
||||
@@ -252,6 +286,19 @@
|
||||
/datum/component/nanites/proc/get_programs(datum/source, list/nanite_programs)
|
||||
nanite_programs |= programs
|
||||
|
||||
/datum/component/nanites/proc/add_research()
|
||||
var/research_value = NANITE_BASE_RESEARCH
|
||||
if(!ishuman(host_mob))
|
||||
if(!iscarbon(host_mob))
|
||||
research_value *= 0.4
|
||||
else
|
||||
research_value *= 0.8
|
||||
if(!host_mob.client)
|
||||
research_value *= 0.5
|
||||
if(host_mob.stat == DEAD)
|
||||
research_value *= 0.75
|
||||
SSresearch.science_tech.add_point_list(list(TECHWEB_POINT_TYPE_NANITES = research_value))
|
||||
|
||||
/datum/component/nanites/proc/nanite_scan(datum/source, mob/user, full_scan)
|
||||
if(!full_scan)
|
||||
if(!stealth)
|
||||
@@ -263,7 +310,8 @@
|
||||
to_chat(user, "<span class='info'>================</span>")
|
||||
to_chat(user, "<span class='info'>Saturation: [nanite_volume]/[max_nanites]</span>")
|
||||
to_chat(user, "<span class='info'>Safety Threshold: [safety_threshold]</span>")
|
||||
to_chat(user, "<span class='info'>Cloud ID: [cloud_id ? cloud_id : "Disabled"]</span>")
|
||||
to_chat(user, "<span class='info'>Cloud ID: [cloud_id ? cloud_id : "None"]</span>")
|
||||
to_chat(user, "<span class='info'>Cloud Sync: [cloud_active ? "Active" : "Disabled"]</span>")
|
||||
to_chat(user, "<span class='info'>================</span>")
|
||||
to_chat(user, "<span class='info'>Program List:</span>")
|
||||
if(!diagnostics)
|
||||
@@ -280,6 +328,7 @@
|
||||
data["regen_rate"] = regen_rate
|
||||
data["safety_threshold"] = safety_threshold
|
||||
data["cloud_id"] = cloud_id
|
||||
data["cloud_active"] = cloud_active
|
||||
var/list/mob_programs = list()
|
||||
var/id = 1
|
||||
for(var/X in programs)
|
||||
@@ -297,24 +346,35 @@
|
||||
mob_program["trigger_cooldown"] = P.trigger_cooldown / 10
|
||||
|
||||
if(scan_level >= 3)
|
||||
mob_program["activation_delay"] = P.activation_delay
|
||||
mob_program["timer"] = P.timer
|
||||
mob_program["timer_type"] = P.get_timer_type_text()
|
||||
var/list/extra_settings = list()
|
||||
for(var/Y in P.extra_settings)
|
||||
var/list/setting = list()
|
||||
setting["name"] = Y
|
||||
setting["value"] = P.get_extra_setting(Y)
|
||||
extra_settings += list(setting)
|
||||
mob_program["timer_restart"] = P.timer_restart / 10
|
||||
mob_program["timer_shutdown"] = P.timer_shutdown / 10
|
||||
mob_program["timer_trigger"] = P.timer_trigger / 10
|
||||
mob_program["timer_trigger_delay"] = P.timer_trigger_delay / 10
|
||||
var/list/extra_settings = P.get_extra_settings_frontend()
|
||||
mob_program["extra_settings"] = extra_settings
|
||||
if(LAZYLEN(extra_settings))
|
||||
mob_program["has_extra_settings"] = TRUE
|
||||
else
|
||||
mob_program["has_extra_settings"] = FALSE
|
||||
|
||||
if(scan_level >= 4)
|
||||
mob_program["activation_code"] = P.activation_code
|
||||
mob_program["deactivation_code"] = P.deactivation_code
|
||||
mob_program["kill_code"] = P.kill_code
|
||||
mob_program["trigger_code"] = P.trigger_code
|
||||
var/list/rules = list()
|
||||
var/rule_id = 1
|
||||
for(var/Z in P.rules)
|
||||
var/datum/nanite_rule/nanite_rule = Z
|
||||
var/list/rule = list()
|
||||
rule["display"] = nanite_rule.display()
|
||||
rule["program_id"] = id
|
||||
rule["id"] = rule_id
|
||||
rules += list(rule)
|
||||
rule_id++
|
||||
mob_program["rules"] = rules
|
||||
if(LAZYLEN(rules))
|
||||
mob_program["has_rules"] = TRUE
|
||||
id++
|
||||
mob_programs += list(mob_program)
|
||||
data["mob_programs"] = mob_programs
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
//////////////////////////////////////
|
||||
Disfiguration
|
||||
|
||||
Hidden.
|
||||
No change to resistance.
|
||||
Increases stage speed.
|
||||
Slightly increases transmittability.
|
||||
Critical Level.
|
||||
|
||||
BONUS
|
||||
Adds disfiguration trait making the mob appear as "Unknown" to others.
|
||||
|
||||
//////////////////////////////////////
|
||||
*/
|
||||
|
||||
/datum/symptom/disfiguration
|
||||
|
||||
name = "Disfiguration"
|
||||
desc = "The virus liquefies facial muscles, disfiguring the host."
|
||||
stealth = 2
|
||||
resistance = 0
|
||||
stage_speed = 3
|
||||
transmittable = 1
|
||||
level = 5
|
||||
severity = 1
|
||||
symptom_delay_min = 25
|
||||
symptom_delay_max = 75
|
||||
|
||||
/datum/symptom/disfiguration/Activate(datum/disease/advance/A)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
var/mob/living/M = A.affected_mob
|
||||
if (HAS_TRAIT(M, TRAIT_DISFIGURED))
|
||||
return
|
||||
switch(A.stage)
|
||||
if(5)
|
||||
ADD_TRAIT(M, TRAIT_DISFIGURED, DISEASE_TRAIT)
|
||||
M.visible_message("<span class='warning'>[M]'s face appears to cave in!</span>", "<span class='notice'>You feel your face crumple and cave in!</span>")
|
||||
else
|
||||
M.visible_message("<span class='warning'>[M]'s face begins to contort...</span>", "<span class='notice'>Your face feels wet and malleable...</span>")
|
||||
|
||||
|
||||
/datum/symptom/disfiguration/End(datum/disease/advance/A)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(A.affected_mob)
|
||||
REMOVE_TRAIT(A.affected_mob, TRAIT_DISFIGURED, DISEASE_TRAIT)
|
||||
@@ -1,68 +1,22 @@
|
||||
/*
|
||||
//////////////////////////////////////
|
||||
Vitiligo
|
||||
Polyvitiligo
|
||||
|
||||
Hidden.
|
||||
No change to resistance.
|
||||
Increases stage speed.
|
||||
Slightly increases transmittability.
|
||||
Critical Level.
|
||||
|
||||
BONUS
|
||||
Makes the mob lose skin pigmentation.
|
||||
|
||||
//////////////////////////////////////
|
||||
*/
|
||||
|
||||
/datum/symptom/vitiligo
|
||||
|
||||
name = "Vitiligo"
|
||||
desc = "The virus destroys skin pigment cells, causing rapid loss of pigmentation in the host."
|
||||
stealth = 2
|
||||
resistance = 0
|
||||
stage_speed = 3
|
||||
transmittable = 1
|
||||
level = 5
|
||||
severity = 1
|
||||
symptom_delay_min = 25
|
||||
symptom_delay_max = 75
|
||||
|
||||
/datum/symptom/vitiligo/Activate(datum/disease/advance/A)
|
||||
if(!..())
|
||||
return
|
||||
var/mob/living/M = A.affected_mob
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(H.skin_tone == "albino")
|
||||
return
|
||||
switch(A.stage)
|
||||
if(5)
|
||||
H.skin_tone = "albino"
|
||||
H.update_body(0)
|
||||
else
|
||||
H.visible_message("<span class='warning'>[H] looks a bit pale...</span>", "<span class='notice'>Your skin suddenly appears lighter...</span>")
|
||||
|
||||
|
||||
/*
|
||||
//////////////////////////////////////
|
||||
Revitiligo
|
||||
|
||||
Slightly noticable.
|
||||
Noticeable.
|
||||
Increases resistance.
|
||||
Increases stage speed slightly.
|
||||
Increases transmission.
|
||||
Critical Level.
|
||||
|
||||
BONUS
|
||||
Makes the mob gain skin pigmentation.
|
||||
Makes the mob gain a random crayon powder colorful reagent.
|
||||
|
||||
//////////////////////////////////////
|
||||
*/
|
||||
|
||||
/datum/symptom/revitiligo
|
||||
|
||||
name = "Revitiligo"
|
||||
desc = "The virus causes increased production of skin pigment cells, making the host's skin grow darker over time."
|
||||
/datum/symptom/polyvitiligo
|
||||
name = "Polyvitiligo"
|
||||
desc = "The virus replaces the melanin in the skin with reactive pigment."
|
||||
stealth = -1
|
||||
resistance = 3
|
||||
stage_speed = 1
|
||||
@@ -72,17 +26,16 @@ BONUS
|
||||
symptom_delay_min = 7
|
||||
symptom_delay_max = 14
|
||||
|
||||
/datum/symptom/revitiligo/Activate(datum/disease/advance/A)
|
||||
/datum/symptom/polyvitiligo/Activate(datum/disease/advance/A)
|
||||
if(!..())
|
||||
return
|
||||
var/mob/living/M = A.affected_mob
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(H.skin_tone == "african2")
|
||||
return
|
||||
switch(A.stage)
|
||||
if(5)
|
||||
H.skin_tone = "african2"
|
||||
H.update_body(0)
|
||||
else
|
||||
H.visible_message("<span class='warning'>[H] looks a bit dark...</span>", "<span class='notice'>Your skin suddenly appears darker...</span>")
|
||||
switch(A.stage)
|
||||
if(5)
|
||||
var/static/list/banned_reagents = list(/datum/reagent/colorful_reagent/crayonpowder/invisible, /datum/reagent/colorful_reagent/crayonpowder/white)
|
||||
var/color = pick(subtypesof(/datum/reagent/colorful_reagent/crayonpowder) - banned_reagents)
|
||||
if(M.reagents.total_volume <= (M.reagents.maximum_volume/10)) // no flooding humans with 1000 units of colorful reagent
|
||||
M.reagents.add_reagent(color, 5)
|
||||
else
|
||||
if (prob(50)) // spam
|
||||
M.visible_message("<span class='warning'>[M] looks rather vibrant...</span>", "<span class='notice'>The colors, man, the colors...</span>")
|
||||
@@ -38,10 +38,11 @@
|
||||
return
|
||||
CRASH("We couldn't assign an ID!")
|
||||
|
||||
// Called when processing of the advance disease that holds this symptom infects a host and upon each Refresh() of that advance disease.
|
||||
// Called when processing of the advance disease, which holds this symptom, starts.
|
||||
/datum/symptom/proc/Start(datum/disease/advance/A)
|
||||
if(neutered)
|
||||
return FALSE
|
||||
next_activation = world.time + rand(symptom_delay_min * 10, symptom_delay_max * 10) //so it doesn't instantly activate on infection
|
||||
return TRUE
|
||||
|
||||
// Called when the advance disease is going to be deleted or when the advance disease stops processing.
|
||||
@@ -59,7 +60,7 @@
|
||||
next_activation = world.time + rand(symptom_delay_min * 10, symptom_delay_max * 10)
|
||||
return TRUE
|
||||
|
||||
/datum/symptom/proc/on_stage_change(datum/disease/advance/A)
|
||||
/datum/symptom/proc/on_stage_change(new_stage, datum/disease/advance/A)
|
||||
if(neutered)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/// Just for marking when someone's swimming.
|
||||
/datum/element/swimming
|
||||
element_flags = ELEMENT_DETACH
|
||||
|
||||
/datum/element/swimming/Attach(datum/target)
|
||||
if((. = ..()) == ELEMENT_INCOMPATIBLE)
|
||||
return
|
||||
if(!isliving(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/check_valid)
|
||||
ADD_TRAIT(target, TRAIT_SWIMMING, TRAIT_SWIMMING) //seriously there's only one way to get this
|
||||
|
||||
/datum/element/swimming/Detach(datum/target)
|
||||
. = ..()
|
||||
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
|
||||
REMOVE_TRAIT(target, TRAIT_SWIMMING, TRAIT_SWIMMING)
|
||||
|
||||
/datum/element/swimming/proc/check_valid(datum/source)
|
||||
var/mob/living/L = source
|
||||
if(!istype(L.loc, /turf/open/pool))
|
||||
source.RemoveElement(/datum/element/swimming)
|
||||
+5
-1
@@ -61,7 +61,6 @@
|
||||
var/late_joiner = FALSE
|
||||
|
||||
var/force_escaped = FALSE // Set by Into The Sunset command of the shuttle manipulator
|
||||
|
||||
var/list/learned_recipes //List of learned recipe TYPES.
|
||||
|
||||
/datum/mind/New(var/key)
|
||||
@@ -715,6 +714,11 @@
|
||||
if(G)
|
||||
G.reenter_corpse()
|
||||
|
||||
/// Sets our can_hijack to the fastest speed our antag datums allow.
|
||||
/datum/mind/proc/get_hijack_speed()
|
||||
. = 0
|
||||
for(var/datum/antagonist/A in antag_datums)
|
||||
. = max(., A.hijack_speed())
|
||||
|
||||
/datum/mind/proc/has_objective(objective_type)
|
||||
for(var/datum/antagonist/A in antag_datums)
|
||||
|
||||
@@ -1367,3 +1367,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
|
||||
/area/tcommsat/lounge
|
||||
name = "Telecommunications Satellite Lounge"
|
||||
icon_state = "tcomsatlounge"
|
||||
|
||||
/area/crew_quarters/fitness/pool
|
||||
name = "Pool Area"
|
||||
icon_state = "pool"
|
||||
|
||||
@@ -57,7 +57,8 @@ Property weights are:
|
||||
mean += 2.5
|
||||
if(CHAOS_MAX)
|
||||
mean += 5
|
||||
GLOB.dynamic_curve_centre += (mean/voters)
|
||||
if(voters)
|
||||
GLOB.dynamic_curve_centre += (mean/voters)
|
||||
GLOB.dynamic_forced_threat_level = forced_threat_level
|
||||
|
||||
/datum/dynamic_storyteller/proc/get_midround_cooldown()
|
||||
|
||||
@@ -314,9 +314,11 @@ GLOBAL_LIST_EMPTY(objectives)
|
||||
|
||||
/datum/objective/hijack
|
||||
name = "hijack"
|
||||
explanation_text = "Hijack the shuttle to ensure no loyalist Nanotrasen crew escape alive and out of custody."
|
||||
team_explanation_text = "Hijack the shuttle to ensure no loyalist Nanotrasen crew escape alive and out of custody. Leave no team member behind."
|
||||
explanation_text = "Hijack the emergency shuttle by hacking its navigational protocols through the control console (alt click emergency shuttle console)."
|
||||
team_explanation_text = "Hijack the emergency shuttle by hacking its navigational protocols through the control console (alt click emergency shuttle console). Leave no team member behind."
|
||||
martyr_compatible = 0 //Technically you won't get both anyway.
|
||||
/// Overrides the hijack speed of any antagonist datum it is on ONLY, no other datums are impacted.
|
||||
var/hijack_speed_override = 1
|
||||
|
||||
/datum/objective/hijack/check_completion() // Requires all owners to escape.
|
||||
if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME)
|
||||
|
||||
@@ -369,7 +369,7 @@ AI MODULES
|
||||
if(!targName)
|
||||
return
|
||||
subject = targName
|
||||
laws = list("You may not injure a [subject] or, through inaction, allow a [subject] to come to harm.",\
|
||||
laws = list("You may not injure a [subject] or cause one to come to harm.",\
|
||||
"You must obey orders given to you by [subject]s, except where such orders would conflict with the First Law.",\
|
||||
"You must protect your own existence as long as such does not conflict with the First or Second Law.")
|
||||
..()
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
throw_range = 14
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
/obj/item/toy/tennis/pre_altattackby(atom/A, mob/living/user, params) //checks if it can do right click memes
|
||||
/obj/item/toy/tennis/alt_pre_attack(atom/A, mob/living/user, params) //checks if it can do right click memes
|
||||
altafterattack(A, user, TRUE, params)
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -431,26 +431,11 @@
|
||||
if((!req_defib && grab_ghost) || (req_defib && defib.grab_ghost))
|
||||
H.notify_ghost_cloning("Your heart is being defibrillated!")
|
||||
H.grab_ghost() // Shove them back in their body.
|
||||
else if(can_defib(H))
|
||||
else if(H.can_defib())
|
||||
H.notify_ghost_cloning("Your heart is being defibrillated. Re-enter your corpse if you want to be revived!", source = src)
|
||||
|
||||
do_help(H, user)
|
||||
|
||||
/obj/item/twohanded/shockpaddles/proc/can_defib(mob/living/carbon/H) //Our code here is different than tg, if it breaks in testing; BUG_PROBABLE_CAUSE
|
||||
var/obj/item/organ/heart = H.getorgan(/obj/item/organ/heart)
|
||||
if(H.suiciding || H.hellbound || HAS_TRAIT(H, TRAIT_HUSK))
|
||||
return
|
||||
if((world.time - H.timeofdeath) > tlimit)
|
||||
return
|
||||
if((H.getBruteLoss() >= MAX_REVIVE_BRUTE_DAMAGE) || (H.getFireLoss() >= MAX_REVIVE_FIRE_DAMAGE))
|
||||
return
|
||||
if(!heart || (heart.organ_flags & ORGAN_FAILING))
|
||||
return
|
||||
var/obj/item/organ/brain/BR = H.getorgan(/obj/item/organ/brain)
|
||||
if(QDELETED(BR) || BR.brain_death || (BR.organ_flags & ORGAN_FAILING) || H.suiciding)
|
||||
return
|
||||
return TRUE
|
||||
|
||||
/obj/item/twohanded/shockpaddles/proc/shock_touching(dmg, mob/H)
|
||||
if(!H.pulledby || !isliving(H.pulledby))
|
||||
return
|
||||
|
||||
@@ -49,6 +49,10 @@
|
||||
return
|
||||
if(istype(target, /obj/structure/falsewall))
|
||||
return
|
||||
if(target.alpha != 255)
|
||||
return
|
||||
if(target.invisibility != 0)
|
||||
return
|
||||
if(iseffect(target))
|
||||
if(!(istype(target, /obj/effect/decal))) //be a footprint
|
||||
return
|
||||
|
||||
@@ -259,7 +259,7 @@
|
||||
light_color = "#37FFF7"
|
||||
actions_types = list()
|
||||
|
||||
/obj/item/melee/transforming/energy/sword/cx/pre_altattackby(atom/A, mob/living/user, params) //checks if it can do right click memes
|
||||
/obj/item/melee/transforming/energy/sword/cx/alt_pre_attack(atom/A, mob/living/user, params) //checks if it can do right click memes
|
||||
altafterattack(A, user, TRUE, params)
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -179,17 +179,23 @@
|
||||
/obj/item/pinpointer/crew
|
||||
))
|
||||
|
||||
|
||||
/obj/item/storage/belt/medical/surgery_belt_adv
|
||||
name = "surgical supply belt"
|
||||
desc = "A specialized belt designed for holding surgical equipment. It seems to have specific pockets for each and every surgical tool you can think of."
|
||||
content_overlays = FALSE
|
||||
var/advanced_drapes = FALSE
|
||||
|
||||
/obj/item/storage/belt/medical/surgery_belt_adv/PopulateContents()
|
||||
new /obj/item/scalpel/advanced(src)
|
||||
new /obj/item/retractor/advanced(src)
|
||||
new /obj/item/surgicaldrill/advanced(src)
|
||||
new /obj/item/surgical_drapes(src)
|
||||
if(advanced_drapes)
|
||||
new /obj/item/surgical_drapes/advanced(src)
|
||||
else
|
||||
new /obj/item/surgical_drapes(src)
|
||||
|
||||
/obj/item/storage/belt/medical/surgery_belt_adv/cmo
|
||||
advanced_drapes = TRUE
|
||||
|
||||
/obj/item/storage/belt/security
|
||||
name = "security belt"
|
||||
@@ -575,6 +581,7 @@
|
||||
/obj/item/key/janitor,
|
||||
/obj/item/clothing/gloves,
|
||||
/obj/item/melee/flyswatter,
|
||||
/obj/item/twohanded/broom,
|
||||
/obj/item/paint/paint_remover,
|
||||
/obj/item/assembly/mousetrap,
|
||||
/obj/item/screwdriver,
|
||||
|
||||
@@ -15,13 +15,18 @@
|
||||
attack_verb = list("beaten")
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 50, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 80)
|
||||
|
||||
var/stunforce = 70
|
||||
var/stamforce = 25
|
||||
var/status = FALSE
|
||||
var/knockdown = TRUE
|
||||
var/obj/item/stock_parts/cell/cell
|
||||
var/hitcost = 1000
|
||||
var/hitcost = 750
|
||||
var/throw_hit_chance = 35
|
||||
var/preload_cell_type //if not empty the baton starts with this type of cell
|
||||
|
||||
/obj/item/melee/baton/examine(mob/user)
|
||||
. = ..()
|
||||
. += "<span class='notice'>Right click attack while in combat mode to disarm instead of stun.</span>"
|
||||
|
||||
/obj/item/melee/baton/get_cell()
|
||||
. = cell
|
||||
if(iscyborg(loc))
|
||||
@@ -32,7 +37,7 @@
|
||||
user.visible_message("<span class='suicide'>[user] is putting the live [name] in [user.p_their()] mouth! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
return (FIRELOSS)
|
||||
|
||||
/obj/item/melee/baton/Initialize()
|
||||
/obj/item/melee/baton/Initialize(mapload)
|
||||
. = ..()
|
||||
if(preload_cell_type)
|
||||
if(!ispath(preload_cell_type,/obj/item/stock_parts/cell))
|
||||
@@ -48,7 +53,7 @@
|
||||
baton_stun(hit_atom)
|
||||
|
||||
/obj/item/melee/baton/loaded //this one starts with a cell pre-installed.
|
||||
preload_cell_type = /obj/item/stock_parts/cell/high
|
||||
preload_cell_type = /obj/item/stock_parts/cell/high/plus
|
||||
|
||||
/obj/item/melee/baton/proc/deductcharge(chrgdeductamt, chargecheck = TRUE, explode = TRUE)
|
||||
var/obj/item/stock_parts/cell/copper_top = get_cell()
|
||||
@@ -134,44 +139,41 @@
|
||||
add_fingerprint(user)
|
||||
|
||||
/obj/item/melee/baton/attack(mob/M, mob/living/carbon/human/user)
|
||||
var/interrupt = common_baton_melee(M, user, FALSE)
|
||||
if(!interrupt)
|
||||
..()
|
||||
|
||||
/obj/item/melee/baton/alt_pre_attack(atom/A, mob/living/user, params)
|
||||
. = common_baton_melee(A, user, TRUE) //return true (attackchain interrupt) if this also returns true. no harm-disarming.
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
|
||||
//return TRUE to interrupt attack chain.
|
||||
/obj/item/melee/baton/proc/common_baton_melee(mob/M, mob/living/user, disarming = FALSE)
|
||||
if(iscyborg(M) || !isliving(M)) //can't baton cyborgs
|
||||
return FALSE
|
||||
if(status && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))
|
||||
clowning_around(user)
|
||||
return
|
||||
|
||||
if(user.getStaminaLoss() >= STAMINA_SOFTCRIT)//CIT CHANGE - makes it impossible to baton in stamina softcrit
|
||||
to_chat(user, "<span class='danger'>You're too exhausted for that.</span>")//CIT CHANGE - ditto
|
||||
return //CIT CHANGE - ditto
|
||||
|
||||
if(iscyborg(M))
|
||||
..()
|
||||
return
|
||||
|
||||
|
||||
if(user.getStaminaLoss() >= STAMINA_SOFTCRIT) //CIT CHANGE - makes it impossible to baton in stamina softcrit
|
||||
to_chat(user, "<span class='danger'>You're too exhausted for that.</span>")
|
||||
return TRUE
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/L = M
|
||||
if(check_martial_counter(L, user))
|
||||
return
|
||||
return TRUE
|
||||
if(status)
|
||||
if(baton_stun(M, user, disarming))
|
||||
user.do_attack_animation(M)
|
||||
user.adjustStaminaLossBuffered(getweight()) //CIT CHANGE - makes stunbatonning others cost stamina
|
||||
else if(user.a_intent != INTENT_HARM) //they'll try to bash in the last proc.
|
||||
M.visible_message("<span class='warning'>[user] has prodded [M] with [src]. Luckily it was off.</span>", \
|
||||
"<span class='warning'>[user] has prodded you with [src]. Luckily it was off</span>")
|
||||
return disarming || (user.a_intent != INTENT_HARM)
|
||||
|
||||
if(user.a_intent != INTENT_HARM)
|
||||
if(status)
|
||||
if(baton_stun(M, user))
|
||||
user.do_attack_animation(M)
|
||||
user.adjustStaminaLossBuffered(getweight())//CIT CHANGE - makes stunbatonning others cost stamina
|
||||
return
|
||||
else
|
||||
M.visible_message("<span class='warning'>[user] has prodded [M] with [src]. Luckily it was off.</span>", \
|
||||
"<span class='warning'>[user] has prodded you with [src]. Luckily it was off</span>")
|
||||
else
|
||||
if(status)
|
||||
baton_stun(M, user)
|
||||
..()
|
||||
|
||||
|
||||
/obj/item/melee/baton/proc/baton_stun(mob/living/L, mob/user)
|
||||
/obj/item/melee/baton/proc/baton_stun(mob/living/L, mob/user, disarming = FALSE)
|
||||
if(L.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK)) //No message; check_shields() handles that
|
||||
playsound(L, 'sound/weapons/genhit.ogg', 50, 1)
|
||||
return FALSE
|
||||
var/stunpwr = stunforce
|
||||
var/stunpwr = stamforce
|
||||
var/obj/item/stock_parts/cell/our_cell = get_cell()
|
||||
if(!our_cell)
|
||||
switch_status(FALSE)
|
||||
@@ -187,16 +189,21 @@
|
||||
return FALSE
|
||||
stunpwr *= round(stuncharge/hitcost, 0.1)
|
||||
|
||||
L.DefaultCombatKnockdown(stunpwr)
|
||||
L.apply_damage(stunpwr*0.5, STAMINA, user.zone_selected)
|
||||
L.apply_effect(EFFECT_STUTTER, stunforce)
|
||||
if(!disarming)
|
||||
if(knockdown)
|
||||
L.DefaultCombatKnockdown(50, override_stamdmg = 0) //knockdown
|
||||
L.adjustStaminaLoss(stunpwr)
|
||||
else
|
||||
L.drop_all_held_items() //no knockdown/stamina damage, instead disarm.
|
||||
|
||||
L.apply_effect(EFFECT_STUTTER, stamforce)
|
||||
SEND_SIGNAL(L, COMSIG_LIVING_MINOR_SHOCK)
|
||||
if(user)
|
||||
L.lastattacker = user.real_name
|
||||
L.lastattackerckey = user.ckey
|
||||
L.visible_message("<span class='danger'>[user] has stunned [L] with [src]!</span>", \
|
||||
"<span class='userdanger'>[user] has stunned you with [src]!</span>")
|
||||
log_combat(user, L, "stunned")
|
||||
L.visible_message("<span class='danger'>[user] has [disarming? "disarmed" : "stunned"] [L] with [src]!</span>", \
|
||||
"<span class='userdanger'>[user] has [disarming? "disarmed" : "stunned"] you with [src]!</span>")
|
||||
log_combat(user, L, disarming? "disarmed" : "stunned")
|
||||
|
||||
playsound(loc, 'sound/weapons/egloves.ogg', 50, 1, -1)
|
||||
|
||||
@@ -211,7 +218,7 @@
|
||||
user.visible_message("<span class='danger'>[user] accidentally hits [user.p_them()]self with [src]!</span>", \
|
||||
"<span class='userdanger'>You accidentally hit yourself with [src]!</span>")
|
||||
SEND_SIGNAL(user, COMSIG_LIVING_MINOR_SHOCK)
|
||||
user.DefaultCombatKnockdown(stunforce*3)
|
||||
user.DefaultCombatKnockdown(stamforce*6)
|
||||
playsound(loc, 'sound/weapons/egloves.ogg', 50, 1, -1)
|
||||
deductcharge(hitcost)
|
||||
|
||||
@@ -273,8 +280,9 @@
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
force = 3
|
||||
throwforce = 5
|
||||
stunforce = 60
|
||||
hitcost = 2000
|
||||
stamforce = 25
|
||||
hitcost = 1000
|
||||
knockdown = FALSE
|
||||
throw_hit_chance = 10
|
||||
slot_flags = ITEM_SLOT_BACK
|
||||
var/obj/item/assembly/igniter/sparkler
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
user.visible_message("<span class='danger'>[user] accidentally hits [user.p_them()]self with [src]!</span>", \
|
||||
"<span class='userdanger'>You accidentally hit yourself with [src]!</span>")
|
||||
SEND_SIGNAL(user, COMSIG_LIVING_MINOR_SHOCK)
|
||||
user.DefaultCombatKnockdown(stunforce*3)
|
||||
user.DefaultCombatKnockdown(stamforce * 6)
|
||||
playsound(loc, 'sound/weapons/egloves.ogg', 50, 1, -1)
|
||||
if(do_teleport(user, get_turf(user), 50, channel = TELEPORT_CHANNEL_BLUESPACE))
|
||||
deductcharge(hitcost)
|
||||
|
||||
@@ -289,7 +289,7 @@
|
||||
var/light_brightness = 3
|
||||
actions_types = list()
|
||||
|
||||
/obj/item/toy/sword/cx/pre_altattackby(atom/A, mob/living/user, params) //checks if it can do right click memes
|
||||
/obj/item/toy/sword/cx/alt_pre_attack(atom/A, mob/living/user, params) //checks if it can do right click memes
|
||||
altafterattack(A, user, TRUE, params)
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -510,7 +510,7 @@
|
||||
/obj/item/twohanded/dualsaber/hypereutactic/chaplain/IsReflect()
|
||||
return FALSE
|
||||
|
||||
/obj/item/twohanded/dualsaber/hypereutactic/pre_altattackby(atom/A, mob/living/user, params) //checks if it can do right click memes
|
||||
/obj/item/twohanded/dualsaber/hypereutactic/alt_pre_attack(atom/A, mob/living/user, params) //checks if it can do right click memes
|
||||
altafterattack(A, user, TRUE, params)
|
||||
return TRUE
|
||||
|
||||
@@ -1016,3 +1016,66 @@
|
||||
C.change_view(CONFIG_GET(string/default_view))
|
||||
user.client.pixel_x = 0
|
||||
user.client.pixel_y = 0
|
||||
|
||||
/obj/item/twohanded/broom
|
||||
name = "broom"
|
||||
desc = "This is my BROOMSTICK! It can be used manually or braced with two hands to sweep items as you move. It has a telescopic handle for compact storage." //LIES
|
||||
icon = 'icons/obj/janitor.dmi'
|
||||
icon_state = "broom0"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi'
|
||||
force = 8
|
||||
throwforce = 10
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
force_unwielded = 8
|
||||
force_wielded = 12
|
||||
attack_verb = list("swept", "brushed off", "bludgeoned", "whacked")
|
||||
resistance_flags = FLAMMABLE
|
||||
|
||||
/obj/item/twohanded/broom/update_icon_state()
|
||||
icon_state = "broom[wielded]"
|
||||
|
||||
/obj/item/twohanded/broom/wield(mob/user)
|
||||
. = ..()
|
||||
if(!wielded)
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You brace the [src] against the ground in a firm sweeping stance.</span>")
|
||||
RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/sweep)
|
||||
|
||||
/obj/item/twohanded/broom/unwield(mob/user)
|
||||
. = ..()
|
||||
UnregisterSignal(user, COMSIG_MOVABLE_MOVED)
|
||||
|
||||
/obj/item/twohanded/broom/afterattack(atom/A, mob/user, proximity)
|
||||
. = ..()
|
||||
if(!proximity)
|
||||
return
|
||||
sweep(user, A, FALSE)
|
||||
|
||||
/obj/item/twohanded/broom/proc/sweep(mob/user, atom/A, moving = TRUE)
|
||||
var/turf/target
|
||||
if (!moving)
|
||||
if (isturf(A))
|
||||
target = A
|
||||
else
|
||||
target = A.loc
|
||||
else
|
||||
target = user.loc
|
||||
if (locate(/obj/structure/table) in target.contents)
|
||||
return
|
||||
var/i = 0
|
||||
for(var/obj/item/garbage in target.contents)
|
||||
if(!garbage.anchored)
|
||||
garbage.Move(get_step(target, user.dir), user.dir)
|
||||
i++
|
||||
if(i >= 20)
|
||||
break
|
||||
if(i >= 1)
|
||||
playsound(loc, 'sound/weapons/thudswoosh.ogg', 5, TRUE, -1)
|
||||
|
||||
/obj/item/twohanded/broom/proc/janicart_insert(mob/user, obj/structure/janitorialcart/J) //bless you whoever fixes this copypasta
|
||||
J.put_in_cart(src, user)
|
||||
J.mybroom=src
|
||||
J.update_icon()
|
||||
@@ -76,7 +76,7 @@
|
||||
new /obj/item/door_remote/chief_medical_officer(src)
|
||||
new /obj/item/clothing/neck/petcollar(src)
|
||||
new /obj/item/pet_carrier(src)
|
||||
new /obj/item/storage/belt/medical/surgery_belt_adv(src)
|
||||
new /obj/item/storage/belt/medical/surgery_belt_adv/cmo(src)
|
||||
new /obj/item/wallframe/defib_mount(src)
|
||||
new /obj/item/circuitboard/machine/techfab/department/medical(src)
|
||||
new /obj/item/storage/photo_album/CMO(src)
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
anchored = FALSE
|
||||
density = TRUE
|
||||
//copypaste sorry
|
||||
var/amount_per_transfer_from_this = 5 //shit I dunno, adding this so syringes stop runtime erroring. --NeoFite
|
||||
var/obj/item/storage/bag/trash/mybag = null
|
||||
var/obj/item/mop/mymop = null
|
||||
var/obj/item/reagent_containers/spray/cleaner/myspray = null
|
||||
var/obj/item/lightreplacer/myreplacer = null
|
||||
var/obj/item/storage/bag/trash/mybag
|
||||
var/obj/item/mop/mymop
|
||||
var/obj/item/twohanded/broom/mybroom
|
||||
var/obj/item/reagent_containers/spray/cleaner/myspray
|
||||
var/obj/item/lightreplacer/myreplacer
|
||||
var/signs = 0
|
||||
var/const/max_signs = 4
|
||||
|
||||
@@ -49,7 +49,12 @@
|
||||
m.janicart_insert(user, src)
|
||||
else
|
||||
to_chat(user, fail_msg)
|
||||
|
||||
else if(istype(I, /obj/item/twohanded/broom))
|
||||
if(!mybroom)
|
||||
var/obj/item/twohanded/broom/b=I
|
||||
b.janicart_insert(user,src)
|
||||
else
|
||||
to_chat(user, fail_msg)
|
||||
else if(istype(I, /obj/item/storage/bag/trash))
|
||||
if(!mybag)
|
||||
var/obj/item/storage/bag/trash/t=I
|
||||
@@ -97,6 +102,8 @@
|
||||
dat += "<a href='?src=[REF(src)];garbage=1'>[mybag.name]</a><br>"
|
||||
if(mymop)
|
||||
dat += "<a href='?src=[REF(src)];mop=1'>[mymop.name]</a><br>"
|
||||
if(mybroom)
|
||||
dat += "<a href='?src=[REF(src)];broom=1'>[mybroom.name]</a><br>"
|
||||
if(myspray)
|
||||
dat += "<a href='?src=[REF(src)];spray=1'>[myspray.name]</a><br>"
|
||||
if(myreplacer)
|
||||
@@ -124,6 +131,11 @@
|
||||
user.put_in_hands(mymop)
|
||||
to_chat(user, "<span class='notice'>You take [mymop] from [src].</span>")
|
||||
mymop = null
|
||||
if(href_list["broom"])
|
||||
if(mybroom)
|
||||
user.put_in_hands(mybroom)
|
||||
to_chat(user, "<span class='notice'>You take [mybroom] from [src].</span>")
|
||||
mybroom = null
|
||||
if(href_list["spray"])
|
||||
if(myspray)
|
||||
user.put_in_hands(myspray)
|
||||
@@ -155,6 +167,8 @@
|
||||
add_overlay("cart_garbage")
|
||||
if(mymop)
|
||||
add_overlay("cart_mop")
|
||||
if(mybroom)
|
||||
add_overlay("cart_broom")
|
||||
if(myspray)
|
||||
add_overlay("cart_spray")
|
||||
if(myreplacer)
|
||||
|
||||
@@ -528,7 +528,7 @@
|
||||
if(B.cell)
|
||||
if(B.cell.charge > 0 && B.status == 1)
|
||||
flick("baton_active", src)
|
||||
var/stunforce = B.stunforce
|
||||
var/stunforce = B.stamforce
|
||||
user.DefaultCombatKnockdown(stunforce)
|
||||
user.stuttering = stunforce/20
|
||||
B.deductcharge(B.hitcost)
|
||||
|
||||
@@ -184,6 +184,8 @@
|
||||
soundin = pick('sound/items/bikehorn.ogg', 'sound/items/AirHorn2.ogg', 'sound/misc/sadtrombone.ogg', 'sound/items/AirHorn.ogg', 'sound/effects/reee.ogg', 'sound/items/WEEOO1.ogg', 'sound/voice/beepsky/iamthelaw.ogg', 'sound/voice/beepsky/creep.ogg','sound/magic/Fireball.ogg' ,'sound/effects/pray.ogg', 'sound/voice/hiss1.ogg','sound/machines/buzz-sigh.ogg', 'sound/machines/ping.ogg', 'sound/weapons/flashbang.ogg', 'sound/weapons/bladeslice.ogg')
|
||||
if("goose")
|
||||
soundin = pick('sound/creatures/goose1.ogg', 'sound/creatures/goose2.ogg', 'sound/creatures/goose3.ogg', 'sound/creatures/goose4.ogg')
|
||||
if("water_wade")
|
||||
soundin = pick('sound/effects/water_wade1.ogg', 'sound/effects/water_wade2.ogg', 'sound/effects/water_wade3.ogg', 'sound/effects/water_wade4.ogg')
|
||||
//START OF CIT CHANGES - adds random vore sounds
|
||||
if ("struggle_sound")
|
||||
soundin = pick( 'sound/vore/pred/struggle_01.ogg','sound/vore/pred/struggle_02.ogg','sound/vore/pred/struggle_03.ogg',
|
||||
|
||||
@@ -14,7 +14,8 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
var/list/objectives = list()
|
||||
var/antag_memory = ""//These will be removed with antag datum
|
||||
var/antag_moodlet //typepath of moodlet that the mob will gain with their status
|
||||
var/can_hijack = HIJACK_NEUTRAL //If these antags are alone on shuttle hijack happens.
|
||||
/// If above 0, this is the multiplier for the speed at which we hijack the shuttle. Do not directly read, use hijack_speed().
|
||||
var/hijack_speed = 0
|
||||
|
||||
//Antag panel properties
|
||||
var/show_in_antagpanel = TRUE //This will hide adding this antag type in antag panel, use only for internal subtypes that shouldn't be added directly but still show if possessed by mind
|
||||
@@ -229,6 +230,13 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
return
|
||||
antag_memory = new_memo
|
||||
|
||||
/// Gets how fast we can hijack the shuttle, return 0 for can not hijack. Defaults to hijack_speed var, override for custom stuff like buffing hijack speed for hijack objectives or something.
|
||||
/datum/antagonist/proc/hijack_speed()
|
||||
var/datum/objective/hijack/H = locate() in objectives
|
||||
if(!isnull(H?.hijack_speed_override))
|
||||
return H.hijack_speed_override
|
||||
return hijack_speed
|
||||
|
||||
//This one is created by admin tools for custom objectives
|
||||
/datum/antagonist/custom
|
||||
antagpanel_category = "Custom"
|
||||
|
||||
@@ -286,10 +286,10 @@
|
||||
var/mob/living/L = owner.current
|
||||
level_bloodcost = maxBloodVolume * 0.2
|
||||
//If the blood volume of the bloodsucker is lower than the cost to level up, return and inform the bloodsucker
|
||||
|
||||
|
||||
//TODO: Make this into a radial, or perhaps a tgui next UI
|
||||
// Purchase Power Prompt
|
||||
var/list/options = list()
|
||||
var/list/options = list()
|
||||
for(var/pickedpower in typesof(/datum/action/bloodsucker))
|
||||
var/datum/action/bloodsucker/power = pickedpower
|
||||
// If I don't own it, and I'm allowed to buy it.
|
||||
|
||||
+38
-31
@@ -14,6 +14,9 @@
|
||||
message_Trigger = ""//"Whom will you subvert to your will?"
|
||||
bloodsucker_can_buy = TRUE
|
||||
must_be_capacitated = TRUE
|
||||
var/list/hit //current hit, set while power is in use as we can't pass the list as an extra calling argument in registersignal.
|
||||
/// If set, uses this speed in deciseconds instead of world.tick_lag
|
||||
var/speed_override
|
||||
|
||||
/datum/action/bloodsucker/targeted/haste/CheckCanUse(display_error)
|
||||
. = ..()
|
||||
@@ -43,42 +46,46 @@
|
||||
return TRUE
|
||||
|
||||
/datum/action/bloodsucker/targeted/haste/FireTargetedPower(atom/A)
|
||||
// set waitfor = FALSE <---- DONT DO THIS!We WANT this power to hold up ClickWithPower(), so that we can unlock the power when it's done.
|
||||
// This is a non-async proc to make sure the power is "locked" until this finishes.
|
||||
hit = list()
|
||||
RegisterSignal(owner, COMSIG_MOVABLE_MOVED, .proc/on_move)
|
||||
var/mob/living/user = owner
|
||||
var/turf/T = isturf(A) ? A : get_turf(A)
|
||||
// Pulled? Not anymore.
|
||||
owner.pulledby = null
|
||||
// Step One: Heatseek toward Target's Turf
|
||||
walk_to(owner, T, 0, 0.01, 20) // NOTE: this runs in the background! to cancel it, you need to use walk(owner.current,0), or give them a new path.
|
||||
user.pulledby?.stop_pulling()
|
||||
// Go to target turf
|
||||
// DO NOT USE WALK TO.
|
||||
playsound(get_turf(owner), 'sound/weapons/punchmiss.ogg', 25, 1, -1)
|
||||
var/safety = 20
|
||||
while(get_turf(owner) != T && safety > 0 && !(isliving(target) && target.Adjacent(owner)))
|
||||
user.mobility_flags = NONE
|
||||
safety --
|
||||
// Did I get knocked down?
|
||||
if(owner && owner.incapacitated(ignore_restraints=TRUE, ignore_grab=TRUE))// owner.incapacitated())
|
||||
// We're gonna cancel. But am I on the ground? Spin me!
|
||||
if(!CHECK_MOBILITY(user, MOBILITY_STAND))
|
||||
var/send_dir = get_dir(owner, T)
|
||||
new /datum/forced_movement(owner, get_ranged_target_turf(owner, send_dir, 1), 1, FALSE)
|
||||
owner.spin(10)
|
||||
var/safety = get_dist(user, T) * 3 + 1
|
||||
var/consequetive_failures = 0
|
||||
var/speed = isnull(speed_override)? world.tick_lag : speed_override
|
||||
while(--safety && (get_turf(user) != T))
|
||||
var/success = step_towards(user, T) //This does not try to go around obstacles.
|
||||
if(!success)
|
||||
success = step_to(user, T) //this does
|
||||
if(!success)
|
||||
if(++consequetive_failures >= 3) //if 3 steps don't work
|
||||
break //just stop
|
||||
else
|
||||
consequetive_failures = 0
|
||||
if(user.resting)
|
||||
user.setDir(turn(user.dir, 90)) //down? spin2win :^)
|
||||
if(user.incapacitated(ignore_restraints = TRUE, ignore_grab = TRUE)) //actually down? stop.
|
||||
break
|
||||
// Spin/Stun people we pass.
|
||||
//var/mob/living/newtarget = locate(/mob/living) in oview(1, owner)
|
||||
var/list/mob/living/foundtargets = list()
|
||||
for(var/mob/living/newtarget in oview(1, owner))
|
||||
if (newtarget && newtarget != target && !(newtarget in foundtargets))//!newtarget.IsKnockdown())
|
||||
if (rand(0, 5) < level_current)
|
||||
playsound(get_turf(newtarget), "sound/weapons/punch[rand(1,4)].ogg", 15, 1, -1)
|
||||
newtarget.DefaultCombatKnockdown(10 + level_current * 5)
|
||||
if(newtarget.IsStun())
|
||||
newtarget.spin(10,1)
|
||||
if (rand(0,4))
|
||||
newtarget.drop_all_held_items()
|
||||
foundtargets += newtarget
|
||||
sleep(1)
|
||||
user?.update_mobility() //Let the poor guy move again
|
||||
if(success) //don't sleep if we failed to move.
|
||||
sleep(speed)
|
||||
UnregisterSignal(owner, COMSIG_MOVABLE_MOVED)
|
||||
hit = null
|
||||
user.update_canmove()
|
||||
|
||||
/datum/action/bloodsucker/targeted/haste/DeactivatePower(mob/living/user = owner, mob/living/target)
|
||||
..() // activate = FALSE
|
||||
user.update_mobility()
|
||||
user.update_canmove()
|
||||
|
||||
/datum/action/bloodsucker/targeted/haste/proc/on_move()
|
||||
for(var/mob/living/L in dview(1, get_turf(owner)))
|
||||
if(!hit[L] && (L != owner))
|
||||
hit[L] = TRUE
|
||||
playsound(L, "sound/weapons/punch[rand(1,4)].ogg", 15, 1, -1)
|
||||
L.Knockdown(10 + level_current * 5, override_hardstun = 0.1)
|
||||
L.spin(10, 1)
|
||||
+2
-2
@@ -54,8 +54,8 @@
|
||||
REMOVE_TRAIT(user, TRAIT_VIRUSIMMUNE, "bloodsucker")
|
||||
var/obj/item/organ/heart/vampheart/H = user.getorganslot(ORGAN_SLOT_HEART)
|
||||
var/obj/item/organ/eyes/vassal/bloodsucker/E = user.getorganslot(ORGAN_SLOT_EYES)
|
||||
E.flash_protect = 0
|
||||
|
||||
E.flash_protect = 0
|
||||
|
||||
// WE ARE ALIVE! //
|
||||
bloodsuckerdatum.poweron_masquerade = TRUE
|
||||
while(bloodsuckerdatum && ContinueActive(user))
|
||||
@@ -5,7 +5,6 @@
|
||||
var/special_role = ROLE_BROTHER
|
||||
var/datum/team/brother_team/team
|
||||
antag_moodlet = /datum/mood_event/focused
|
||||
can_hijack = HIJACK_HIJACKER
|
||||
|
||||
/datum/antagonist/brother/create_team(datum/team/brother_team/new_team)
|
||||
if(!new_team)
|
||||
|
||||
@@ -5,49 +5,49 @@ is currently following.
|
||||
*/
|
||||
|
||||
GLOBAL_LIST_INIT(disease_ability_singletons, list(
|
||||
new /datum/disease_ability/action/cough,
|
||||
new /datum/disease_ability/action/sneeze,
|
||||
new /datum/disease_ability/action/infect,
|
||||
new /datum/disease_ability/symptom/mild/cough,
|
||||
new /datum/disease_ability/symptom/mild/sneeze,
|
||||
new /datum/disease_ability/symptom/medium/shedding,
|
||||
new /datum/disease_ability/symptom/medium/beard,
|
||||
new /datum/disease_ability/symptom/medium/hallucigen,
|
||||
new /datum/disease_ability/symptom/medium/choking,
|
||||
new /datum/disease_ability/symptom/medium/confusion,
|
||||
new /datum/disease_ability/symptom/medium/vomit,
|
||||
new /datum/disease_ability/symptom/medium/voice_change,
|
||||
new /datum/disease_ability/symptom/medium/visionloss,
|
||||
new /datum/disease_ability/symptom/medium/deafness,
|
||||
new /datum/disease_ability/symptom/powerful/narcolepsy,
|
||||
new /datum/disease_ability/symptom/medium/fever,
|
||||
new /datum/disease_ability/symptom/medium/shivering,
|
||||
new /datum/disease_ability/symptom/medium/headache,
|
||||
new /datum/disease_ability/symptom/medium/nano_boost,
|
||||
new /datum/disease_ability/symptom/medium/nano_destroy,
|
||||
new /datum/disease_ability/symptom/medium/viraladaptation,
|
||||
new /datum/disease_ability/symptom/medium/viralevolution,
|
||||
new /datum/disease_ability/symptom/medium/vitiligo,
|
||||
new /datum/disease_ability/symptom/medium/revitiligo,
|
||||
new /datum/disease_ability/symptom/medium/itching,
|
||||
new /datum/disease_ability/symptom/medium/heal/weight_loss,
|
||||
new /datum/disease_ability/symptom/medium/heal/sensory_restoration,
|
||||
new /datum/disease_ability/symptom/medium/heal/mind_restoration,
|
||||
new /datum/disease_ability/symptom/powerful/fire,
|
||||
new /datum/disease_ability/symptom/powerful/flesh_eating,
|
||||
// new /datum/disease_ability/symptom/powerful/genetic_mutation,
|
||||
new /datum/disease_ability/symptom/powerful/inorganic_adaptation,
|
||||
new /datum/disease_ability/symptom/powerful/heal/starlight,
|
||||
new /datum/disease_ability/symptom/powerful/heal/oxygen,
|
||||
new /datum/disease_ability/symptom/powerful/heal/chem,
|
||||
new /datum/disease_ability/symptom/powerful/heal/metabolism,
|
||||
new /datum/disease_ability/symptom/powerful/heal/dark,
|
||||
new /datum/disease_ability/symptom/powerful/heal/water,
|
||||
new /datum/disease_ability/symptom/powerful/heal/plasma,
|
||||
new /datum/disease_ability/symptom/powerful/heal/radiation,
|
||||
new /datum/disease_ability/symptom/powerful/heal/coma,
|
||||
new /datum/disease_ability/symptom/powerful/youth
|
||||
))
|
||||
new /datum/disease_ability/action/cough,
|
||||
new /datum/disease_ability/action/sneeze,
|
||||
new /datum/disease_ability/action/infect,
|
||||
new /datum/disease_ability/symptom/mild/cough,
|
||||
new /datum/disease_ability/symptom/mild/sneeze,
|
||||
new /datum/disease_ability/symptom/medium/shedding,
|
||||
new /datum/disease_ability/symptom/medium/beard,
|
||||
new /datum/disease_ability/symptom/medium/hallucigen,
|
||||
new /datum/disease_ability/symptom/medium/choking,
|
||||
new /datum/disease_ability/symptom/medium/confusion,
|
||||
new /datum/disease_ability/symptom/medium/vomit,
|
||||
new /datum/disease_ability/symptom/medium/voice_change,
|
||||
new /datum/disease_ability/symptom/medium/visionloss,
|
||||
new /datum/disease_ability/symptom/medium/deafness,
|
||||
new /datum/disease_ability/symptom/powerful/narcolepsy,
|
||||
new /datum/disease_ability/symptom/medium/fever,
|
||||
new /datum/disease_ability/symptom/medium/shivering,
|
||||
new /datum/disease_ability/symptom/medium/headache,
|
||||
new /datum/disease_ability/symptom/medium/nano_boost,
|
||||
new /datum/disease_ability/symptom/medium/nano_destroy,
|
||||
new /datum/disease_ability/symptom/medium/viraladaptation,
|
||||
new /datum/disease_ability/symptom/medium/viralevolution,
|
||||
new /datum/disease_ability/symptom/medium/disfiguration,
|
||||
new /datum/disease_ability/symptom/medium/polyvitiligo,
|
||||
new /datum/disease_ability/symptom/medium/itching,
|
||||
new /datum/disease_ability/symptom/medium/heal/weight_loss,
|
||||
new /datum/disease_ability/symptom/medium/heal/sensory_restoration,
|
||||
new /datum/disease_ability/symptom/medium/heal/mind_restoration,
|
||||
new /datum/disease_ability/symptom/powerful/fire,
|
||||
new /datum/disease_ability/symptom/powerful/flesh_eating,
|
||||
new /datum/disease_ability/symptom/powerful/genetic_mutation,
|
||||
new /datum/disease_ability/symptom/powerful/inorganic_adaptation,
|
||||
new /datum/disease_ability/symptom/powerful/heal/starlight,
|
||||
new /datum/disease_ability/symptom/powerful/heal/oxygen,
|
||||
new /datum/disease_ability/symptom/powerful/heal/chem,
|
||||
new /datum/disease_ability/symptom/powerful/heal/metabolism,
|
||||
new /datum/disease_ability/symptom/powerful/heal/dark,
|
||||
new /datum/disease_ability/symptom/powerful/heal/water,
|
||||
new /datum/disease_ability/symptom/powerful/heal/plasma,
|
||||
new /datum/disease_ability/symptom/powerful/heal/radiation,
|
||||
new /datum/disease_ability/symptom/powerful/heal/coma,
|
||||
new /datum/disease_ability/symptom/powerful/youth
|
||||
))
|
||||
|
||||
/datum/disease_ability
|
||||
var/name
|
||||
@@ -57,7 +57,7 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list(
|
||||
var/short_desc = ""
|
||||
var/long_desc = ""
|
||||
var/stat_block = ""
|
||||
var/threshold_block = list()
|
||||
var/threshold_block = ""
|
||||
var/category = ""
|
||||
|
||||
var/list/symptoms
|
||||
@@ -76,7 +76,7 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list(
|
||||
resistance += initial(S.resistance)
|
||||
stage_speed += initial(S.stage_speed)
|
||||
transmittable += initial(S.transmittable)
|
||||
threshold_block += initial(S.threshold_desc)
|
||||
threshold_block += "<br><br>[initial(S.threshold_desc)]"
|
||||
stat_block = "Resistance: [resistance]<br>Stealth: [stealth]<br>Stage Speed: [stage_speed]<br>Transmissibility: [transmittable]<br><br>"
|
||||
if(symptoms.len == 1) //lazy boy's dream
|
||||
name = initial(S.name)
|
||||
@@ -106,10 +106,8 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list(
|
||||
for(var/T in symptoms)
|
||||
var/datum/symptom/S = new T()
|
||||
SD.symptoms += S
|
||||
S.OnAdd(SD)
|
||||
if(SD.processing)
|
||||
if(S.Start(SD))
|
||||
S.next_activation = world.time + rand(S.symptom_delay_min * 10, S.symptom_delay_max * 10)
|
||||
S.Start(SD)
|
||||
SD.Refresh()
|
||||
for(var/T in actions)
|
||||
var/datum/action/A = new T()
|
||||
@@ -136,7 +134,6 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list(
|
||||
var/datum/symptom/S = locate(T) in SD.symptoms
|
||||
if(S)
|
||||
SD.symptoms -= S
|
||||
S.OnRemove(SD)
|
||||
if(SD.processing)
|
||||
S.End(SD)
|
||||
qdel(S)
|
||||
@@ -296,7 +293,6 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list(
|
||||
cost = 8
|
||||
category = "Symptom (Strong+)"
|
||||
|
||||
|
||||
/******MILD******/
|
||||
|
||||
/datum/disease_ability/symptom/mild/cough
|
||||
@@ -377,11 +373,11 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list(
|
||||
/datum/disease_ability/symptom/medium/viralevolution
|
||||
symptoms = list(/datum/symptom/viralevolution)
|
||||
|
||||
/datum/disease_ability/symptom/medium/vitiligo
|
||||
symptoms = list(/datum/symptom/vitiligo)
|
||||
/datum/disease_ability/symptom/medium/polyvitiligo
|
||||
symptoms = list(/datum/symptom/polyvitiligo)
|
||||
|
||||
/datum/disease_ability/symptom/medium/revitiligo
|
||||
symptoms = list(/datum/symptom/revitiligo)
|
||||
/datum/disease_ability/symptom/medium/disfiguration
|
||||
symptoms = list(/datum/symptom/disfiguration)
|
||||
|
||||
/datum/disease_ability/symptom/medium/itching
|
||||
symptoms = list(/datum/symptom/itching)
|
||||
@@ -409,11 +405,9 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list(
|
||||
/datum/disease_ability/symptom/powerful/flesh_eating
|
||||
symptoms = list(/datum/symptom/flesh_eating)
|
||||
|
||||
/*
|
||||
/datum/disease_ability/symptom/powerful/genetic_mutation
|
||||
symptoms = list(/datum/symptom/genetic_mutation)
|
||||
cost = 8
|
||||
*/
|
||||
|
||||
/datum/disease_ability/symptom/powerful/inorganic_adaptation
|
||||
symptoms = list(/datum/symptom/inorganic_adaptation)
|
||||
@@ -457,4 +451,4 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list(
|
||||
/datum/disease_ability/symptom/powerful/heal/coma
|
||||
symptoms = list(/datum/symptom/heal/coma)
|
||||
short_desc = "Cause victims to fall into a healing coma when hurt."
|
||||
long_desc = "Cause victims to fall into a healing coma when hurt."
|
||||
long_desc = "Cause victims to fall into a healing coma when hurt."
|
||||
@@ -12,7 +12,6 @@
|
||||
var/list/name_source
|
||||
show_in_antagpanel = FALSE
|
||||
antag_moodlet = /datum/mood_event/focused
|
||||
can_hijack = HIJACK_PREVENT
|
||||
|
||||
/datum/antagonist/ert/on_gain()
|
||||
update_name()
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
var/obj/item/claymore/highlander/sword
|
||||
show_in_antagpanel = FALSE
|
||||
show_name_in_check_antagonists = TRUE
|
||||
can_hijack = HIJACK_HIJACKER
|
||||
hijack_speed = 2 //if you kill everyone and actually haev a hand to hijack with, you win??
|
||||
|
||||
/datum/antagonist/highlander/apply_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/L = owner.current || mob_override
|
||||
|
||||
@@ -8,11 +8,6 @@
|
||||
var/give_objectives = TRUE
|
||||
var/give_equipment = TRUE
|
||||
|
||||
/datum/antagonist/ninja/New()
|
||||
if(helping_station)
|
||||
can_hijack = HIJACK_PREVENT
|
||||
. = ..()
|
||||
|
||||
/datum/antagonist/ninja/apply_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/M = mob_override || owner.current
|
||||
update_ninja_icons_added(M)
|
||||
@@ -135,8 +130,6 @@
|
||||
adj = "objectiveless"
|
||||
else
|
||||
return
|
||||
if(helping_station)
|
||||
can_hijack = HIJACK_PREVENT
|
||||
new_owner.assigned_role = ROLE_NINJA
|
||||
new_owner.special_role = ROLE_NINJA
|
||||
new_owner.add_antag_datum(src)
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
var/always_new_team = FALSE //If not assigned a team by default ops will try to join existing ones, set this to TRUE to always create new team.
|
||||
var/send_to_spawnpoint = TRUE //Should the user be moved to default spawnpoint.
|
||||
var/nukeop_outfit = /datum/outfit/syndicate
|
||||
can_hijack = HIJACK_HIJACKER //Alternative way to wipe out the station.
|
||||
|
||||
/datum/antagonist/nukeop/proc/update_synd_icons_added(mob/living/M)
|
||||
var/datum/atom_hud/antag/opshud = GLOB.huds[ANTAG_HUD_OPS]
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
show_in_antagpanel = FALSE
|
||||
var/datum/objective/mission
|
||||
var/datum/team/ert/ert_team
|
||||
can_hijack = HIJACK_PREVENT
|
||||
|
||||
/datum/antagonist/official/greet()
|
||||
to_chat(owner, "<B><font size=3 color=red>You are a CentCom Official.</font></B>")
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
var/should_give_codewords = TRUE
|
||||
var/should_equip = TRUE
|
||||
var/traitor_kind = TRAITOR_HUMAN //Set on initial assignment
|
||||
can_hijack = HIJACK_HIJACKER
|
||||
hijack_speed = 0.5 //10 seconds per hijack stage by default
|
||||
|
||||
/datum/antagonist/traitor/on_gain()
|
||||
if(owner.current && isAI(owner.current))
|
||||
@@ -60,6 +60,7 @@
|
||||
message = GLOB.syndicate_code_response_regex.Replace(message, "<span class='red'>$1</span>")
|
||||
hearing_args[HEARING_RAW_MESSAGE] = message
|
||||
|
||||
// needs to be refactored to base /datum/antagonist sometime..
|
||||
/datum/antagonist/traitor/proc/add_objective(datum/objective/O)
|
||||
objectives += O
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
name = "Wishgranter Avatar"
|
||||
show_in_antagpanel = FALSE
|
||||
show_name_in_check_antagonists = TRUE
|
||||
can_hijack = HIJACK_HIJACKER
|
||||
|
||||
/datum/antagonist/wishgranter/proc/forge_objectives()
|
||||
var/datum/objective/hijack/hijack = new
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
var/move_to_lair = TRUE
|
||||
var/outfit_type = /datum/outfit/wizard
|
||||
var/wiz_age = WIZARD_AGE_MIN /* Wizards by nature cannot be too young. */
|
||||
can_hijack = HIJACK_HIJACKER
|
||||
|
||||
/datum/antagonist/wizard/on_gain()
|
||||
register()
|
||||
|
||||
@@ -53,7 +53,8 @@
|
||||
H.adjust_blurriness(1)
|
||||
H.visible_message("<span class='warning'>[H] is creamed by [src]!</span>", "<span class='userdanger'>You've been creamed by [src]!</span>")
|
||||
playsound(H, "desceration", 50, TRUE)
|
||||
reagents.trans_to(H,15) //Cream pie combat
|
||||
if(!H.is_mouth_covered())
|
||||
reagents.trans_to(H,15) //Cream pie combat
|
||||
if(!H.creamed) // one layer at a time
|
||||
H.add_overlay(creamoverlay)
|
||||
H.creamed = TRUE
|
||||
|
||||
@@ -122,13 +122,10 @@
|
||||
to_chat(usr, "<span class='warning'>Error: Insufficient credits for [prize.equipment_name] on [I]!</span>")
|
||||
flick(icon_deny, src)
|
||||
else
|
||||
if (I.mining_points -= prize.cost)
|
||||
to_chat(usr, "<span class='notice'>[src] clanks to life briefly before vending [prize.equipment_name]!</span>")
|
||||
new prize.equipment_path(src.loc)
|
||||
SSblackbox.record_feedback("nested tally", "mining_equipment_bought", 1, list("[type]", "[prize.equipment_path]"))
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>Error: Transaction failure, please try again later!</span>")
|
||||
flick(icon_deny, src)
|
||||
I.mining_points -= prize.cost
|
||||
to_chat(usr, "<span class='notice'>[src] clanks to life briefly before vending [prize.equipment_name]!</span>")
|
||||
new prize.equipment_path(src.loc)
|
||||
SSblackbox.record_feedback("nested tally", "mining_equipment_bought", 1, list("[type]", "[prize.equipment_path]"))
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>Error: An ID with a registered account is required!</span>")
|
||||
flick(icon_deny, src)
|
||||
|
||||
@@ -834,12 +834,31 @@
|
||||
update_inv_handcuffed()
|
||||
update_hud_handcuffed()
|
||||
|
||||
/mob/living/carbon/proc/can_defib()
|
||||
var/tlimit = DEFIB_TIME_LIMIT * 10
|
||||
var/obj/item/organ/heart = getorgan(/obj/item/organ/heart)
|
||||
if(suiciding || hellbound || HAS_TRAIT(src, TRAIT_HUSK))
|
||||
return
|
||||
if((world.time - timeofdeath) > tlimit)
|
||||
return
|
||||
if((getBruteLoss() >= MAX_REVIVE_BRUTE_DAMAGE) || (getFireLoss() >= MAX_REVIVE_FIRE_DAMAGE))
|
||||
return
|
||||
if(!heart || (heart.organ_flags & ORGAN_FAILING))
|
||||
return
|
||||
var/obj/item/organ/brain/BR = getorgan(/obj/item/organ/brain)
|
||||
if(QDELETED(BR) || BR.brain_death || (BR.organ_flags & ORGAN_FAILING) || suiciding)
|
||||
return
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/fully_heal(admin_revive = FALSE)
|
||||
if(reagents)
|
||||
reagents.clear_reagents()
|
||||
var/obj/item/organ/brain/B = getorgan(/obj/item/organ/brain)
|
||||
if(B)
|
||||
B.brain_death = FALSE
|
||||
for(var/O in internal_organs)
|
||||
var/obj/item/organ/organ = O
|
||||
organ.setOrganDamage(0)
|
||||
for(var/thing in diseases)
|
||||
var/datum/disease/D = thing
|
||||
if(D.severity != DISEASE_SEVERITY_POSITIVE)
|
||||
@@ -852,7 +871,8 @@
|
||||
qdel(R)
|
||||
update_handcuffed()
|
||||
if(reagents)
|
||||
reagents.addiction_list = list()
|
||||
for(var/addi in reagents.addiction_list)
|
||||
reagents.remove_addiction(addi)
|
||||
cure_all_traumas(TRAUMA_RESILIENCE_MAGIC)
|
||||
..()
|
||||
// heal ears after healing traits, since ears check TRAIT_DEAF trait
|
||||
|
||||
@@ -803,7 +803,7 @@
|
||||
hud_used.staminas?.update_icon_state()
|
||||
hud_used.staminabuffer?.update_icon_state()
|
||||
|
||||
/mob/living/carbon/human/fully_heal(admin_revive = 0)
|
||||
/mob/living/carbon/human/fully_heal(admin_revive = FALSE)
|
||||
if(admin_revive)
|
||||
regenerate_limbs()
|
||||
regenerate_organs()
|
||||
|
||||
@@ -135,7 +135,7 @@
|
||||
RegisterSignal(owner, COMSIG_CLICK_SHIFT, .proc/examinate_check)
|
||||
RegisterSignal(src, COMSIG_ATOM_HEARER_IN_VIEW, .proc/include_owner)
|
||||
RegisterSignal(owner, COMSIG_LIVING_REGENERATE_LIMBS, .proc/unlist_head)
|
||||
RegisterSignal(owner, COMSIG_LIVING_FULLY_HEAL, .proc/retrieve_head)
|
||||
RegisterSignal(owner, COMSIG_LIVING_REVIVE, .proc/retrieve_head)
|
||||
|
||||
/obj/item/dullahan_relay/proc/examinate_check(atom/source, mob/user)
|
||||
if(user.client.eye == src)
|
||||
@@ -148,8 +148,9 @@
|
||||
/obj/item/dullahan_relay/proc/unlist_head(datum/source, noheal = FALSE, list/excluded_limbs)
|
||||
excluded_limbs |= BODY_ZONE_HEAD // So we don't gib when regenerating limbs.
|
||||
|
||||
/obj/item/dullahan_relay/proc/retrieve_head(datum/source, admin_revive = FALSE)
|
||||
if(admin_revive) //retrieving the owner's head for ahealing purposes.
|
||||
//Retrieving the owner's head for better ahealing.
|
||||
/obj/item/dullahan_relay/proc/retrieve_head(datum/source, full_heal, admin_revive)
|
||||
if(admin_revive)
|
||||
var/obj/item/bodypart/head/H = loc
|
||||
var/turf/T = get_turf(owner)
|
||||
if(H && istype(H) && T && !(H in owner.GetAllContents()))
|
||||
|
||||
@@ -213,6 +213,16 @@
|
||||
PDA.f_lum = 0
|
||||
PDA.update_icon()
|
||||
visible_message("<span class='danger'>The light in [PDA] shorts out!</span>")
|
||||
else if(istype(O, /obj/item/gun))
|
||||
var/obj/item/gun/weapon = O
|
||||
if(weapon.gun_light)
|
||||
var/obj/item/flashlight/seclite/light = weapon.gun_light
|
||||
light.forceMove(get_turf(weapon))
|
||||
light.burn()
|
||||
weapon.gun_light = null
|
||||
weapon.update_gunlight()
|
||||
QDEL_NULL(weapon.alight)
|
||||
visible_message("<span class='danger'>[light] on [O] flickers out and disintegrates!</span>")
|
||||
else
|
||||
visible_message("<span class='danger'>[O] is disintegrated by [src]!</span>")
|
||||
O.burn()
|
||||
|
||||
@@ -481,7 +481,8 @@
|
||||
med_hud_set_status()
|
||||
|
||||
//proc used to ressuscitate a mob
|
||||
/mob/living/proc/revive(full_heal = 0, admin_revive = 0)
|
||||
/mob/living/proc/revive(full_heal = FALSE, admin_revive = FALSE)
|
||||
SEND_SIGNAL(src, COMSIG_LIVING_REVIVE, full_heal, admin_revive)
|
||||
if(full_heal)
|
||||
fully_heal(admin_revive)
|
||||
if(stat == DEAD && can_be_revived()) //in some cases you can't revive (e.g. no brain)
|
||||
@@ -526,11 +527,6 @@
|
||||
fire_stacks = 0
|
||||
confused = 0
|
||||
update_mobility()
|
||||
var/datum/component/mood/mood = GetComponent(/datum/component/mood)
|
||||
if (mood)
|
||||
QDEL_LIST_ASSOC_VAL(mood.mood_events)
|
||||
mood.sanity = SANITY_GREAT
|
||||
mood.update_mood()
|
||||
//Heal all organs
|
||||
if(iscarbon(src))
|
||||
var/mob/living/carbon/C = src
|
||||
@@ -538,8 +534,6 @@
|
||||
for(var/organ in C.internal_organs)
|
||||
var/obj/item/organ/O = organ
|
||||
O.setOrganDamage(0)
|
||||
SEND_SIGNAL(src, COMSIG_LIVING_FULLY_HEAL, admin_revive)
|
||||
|
||||
|
||||
//proc called by revive(), to check if we can actually ressuscitate the mob (we don't want to revive him and have him instantly die again)
|
||||
/mob/living/proc/can_be_revived()
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
name = "pAI"
|
||||
icon = 'icons/mob/pai.dmi'
|
||||
icon_state = "repairbot"
|
||||
mouse_opacity = MOUSE_OPACITY_OPAQUE
|
||||
density = FALSE
|
||||
pass_flags = PASSTABLE | PASSMOB
|
||||
mob_size = MOB_SIZE_TINY
|
||||
@@ -75,7 +74,7 @@
|
||||
var/emitteroverloadcd = 100
|
||||
|
||||
var/radio_short = FALSE
|
||||
var/radio_short_cooldown = 5 MINUTES
|
||||
var/radio_short_cooldown = 3 MINUTES
|
||||
var/radio_short_timerid
|
||||
|
||||
mobility_flags = NONE
|
||||
|
||||
@@ -56,7 +56,8 @@
|
||||
if(P.stun)
|
||||
fold_in(force = TRUE)
|
||||
visible_message("<span class='warning'>The electrically-charged projectile disrupts [src]'s holomatrix, forcing [src] to fold in!</span>")
|
||||
return ..()
|
||||
. = ..()
|
||||
return BULLET_ACT_FORCE_PIERCE
|
||||
|
||||
/mob/living/silicon/pai/stripPanelUnequip(obj/item/what, mob/who, where) //prevents stripping
|
||||
to_chat(src, "<span class='warning'>Your holochassis stutters and warps intensely as you attempt to interact with the object, forcing you to cease lest the field fail.</span>")
|
||||
|
||||
@@ -596,8 +596,8 @@
|
||||
|
||||
/obj/item/robot_module/peacekeeper/do_transform_animation()
|
||||
..()
|
||||
to_chat(loc, "<span class='userdanger'>Under ASIMOV/CREWSIMOV, you are an enforcer of the PEACE and preventer of HUMAN/CREW HARM. \
|
||||
You are not a security module and you are expected to follow orders and prevent harm above all else. Space law means nothing to you.</span>")
|
||||
to_chat(loc, "<span class='userdanger'>Under ASIMOV/CREWSIMOV, you are an enforcer of the PEACE. \
|
||||
You are not a security module and you are expected to follow orders to the best of your abilities without causing harm. Space law means nothing to you.</span>")
|
||||
|
||||
/obj/item/robot_module/peacekeeper/be_transformed_to(obj/item/robot_module/old_module)
|
||||
var/mob/living/silicon/robot/R = loc
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
//shameless copies of carps.
|
||||
|
||||
/mob/living/simple_animal/hostile/shark
|
||||
name = "Space Shark"
|
||||
desc = "The best terror of the seas, next to the kraken."
|
||||
icon_state = "shark"
|
||||
icon_living = "shark"
|
||||
icon = 'icons/mob/sharks.dmi'
|
||||
icon_dead = "shark_dead"
|
||||
icon_gib = "carp_gib"
|
||||
environment_smash = 0
|
||||
speak_chance = 0
|
||||
turns_per_move = 3
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/carpmeat = 3)
|
||||
response_help = "pets"
|
||||
response_disarm = "gently pushes aside"
|
||||
response_harm = "hits"
|
||||
speed = 0
|
||||
maxHealth = 75
|
||||
health = 75
|
||||
harm_intent_damage = 18
|
||||
melee_damage_lower = 18
|
||||
melee_damage_upper = 18
|
||||
attacktext = "maims"
|
||||
attack_sound = 'sound/weapons/bite.ogg'
|
||||
gold_core_spawnable = 1
|
||||
//Space shark aren't affected by cold.
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
minbodytemp = 0
|
||||
maxbodytemp = 1500
|
||||
|
||||
faction = list("shark")
|
||||
|
||||
/mob/living/simple_animal/hostile/shark/Process_Spacemove(var/movement_dir = 0)
|
||||
return 1 //No drifting in space for space sharks....either!
|
||||
|
||||
/mob/living/simple_animal/hostile/shark/FindTarget()
|
||||
. = ..()
|
||||
if(.)
|
||||
emote("me", 1, "growls at [.]!")
|
||||
|
||||
/mob/living/simple_animal/hostile/shark/AttackingTarget()
|
||||
. =..()
|
||||
var/mob/living/carbon/L = .
|
||||
if(istype(L))
|
||||
if(prob(25))
|
||||
L.Knockdown(20)
|
||||
L.visible_message("<span class='danger'>\the [src] knocks down \the [L]!</span>")
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/shark/laser
|
||||
name = "Laser-Shark"
|
||||
desc = "NOW we've jumped the shark."
|
||||
icon_state = "lasershark"
|
||||
icon_living = "lasershark"
|
||||
icon_dead = "lasershark_dead"
|
||||
icon_gib = "carp_gib"
|
||||
ranged = 1
|
||||
retreat_distance = 3
|
||||
minimum_distance = 0 //Between shots they can and will close in to nash
|
||||
projectiletype = /obj/item/projectile/beam/laser/heavylaser
|
||||
projectilesound = 'sound/weapons/lasercannonfire.ogg'
|
||||
maxHealth = 50
|
||||
health = 50
|
||||
|
||||
/mob/living/simple_animal/hostile/shark/kawaii
|
||||
name = "Kawaii Shark"
|
||||
desc = "Senpai~ Notice me.."
|
||||
icon_state = "kawaiishark"
|
||||
icon_living = "kawaiishark"
|
||||
icon_dead = "kawaiishark_dead"
|
||||
speak = list("Oh Senpai","Notice me senpai!","Oh my...","Kawaii~")
|
||||
speak_emote = list("lovingly says","says")
|
||||
speak_chance = 2
|
||||
turns_per_move = 3
|
||||
butcher_results = list(/mob/living/simple_animal/butterfly = 3)
|
||||
maxHealth = 50
|
||||
health = 50
|
||||
maxbodytemp = INFINITY
|
||||
|
||||
harm_intent_damage = 0
|
||||
melee_damage_lower = 0
|
||||
melee_damage_upper = 0
|
||||
attacktext = "violently hugs"
|
||||
vision_range = 0
|
||||
|
||||
/mob/living/simple_animal/hostile/shark/kawaii/death()
|
||||
say("Senpai, you noticed~!")
|
||||
LoseAggro()
|
||||
..()
|
||||
walk(src, 0)
|
||||
@@ -0,0 +1,422 @@
|
||||
#define POOL_NO_OVERDOSE_MEDICINE_MAX 5 //max units of no-overdose medicine to allow mobs to have through duplication
|
||||
|
||||
//Originally stolen from paradise. Credits to tigercat2000.
|
||||
//Modified a lot by Kokojo and Tortellini Tony for hippiestation.
|
||||
//Heavily refactored by tgstation
|
||||
/obj/machinery/pool
|
||||
icon = 'icons/obj/machines/pool.dmi'
|
||||
anchored = TRUE
|
||||
resistance_flags = INDESTRUCTIBLE
|
||||
|
||||
/obj/machinery/pool/controller
|
||||
name = "\improper Pool Controller"
|
||||
desc = "An advanced substance generation and fluid tank management system that can refill the contents of a pool to a completely different substance in minutes."
|
||||
icon_state = "poolc_3"
|
||||
density = TRUE
|
||||
use_power = TRUE
|
||||
idle_power_usage = 75
|
||||
/// How far it scans for pool objects
|
||||
var/scan_range = 6
|
||||
/// Is pool mist currently on?
|
||||
var/mist_state = FALSE
|
||||
/// Linked mist effects
|
||||
var/list/obj/effect/mist/linked_mist = list()
|
||||
/// Pool turfs
|
||||
var/list/turf/open/pool/linked_turfs = list()
|
||||
/// All mobs in pool
|
||||
var/list/mob/living/mobs_in_pool = list()
|
||||
/// Is the pool bloody?
|
||||
var/bloody = 0
|
||||
/// Last time we process_reagents()'d
|
||||
var/last_reagent_process = 0
|
||||
/// Maximum amount we will take from a beaker
|
||||
var/max_beaker_transfer = 100
|
||||
/// Minimum amount of a reagent for it to work on us
|
||||
var/min_reagent_amount = 10
|
||||
/// ADMINBUS ONLY - WHETHER OR NOT WE HAVE NOREACT ;)
|
||||
var/noreact_reagents = FALSE
|
||||
/// how fast in deciseconds between reagent processes
|
||||
var/reagent_tick_interval = 5
|
||||
/// Can we use unsafe temperatures
|
||||
var/temperature_unlocked = FALSE
|
||||
/// See __DEFINES/pool.dm, temperature defines
|
||||
var/temperature = POOL_NORMAL
|
||||
/// Whether or not the pool can be drained
|
||||
var/drainable = FALSE
|
||||
// Whether or not the pool is drained
|
||||
var/drained = FALSE
|
||||
/// Pool drain
|
||||
var/obj/machinery/pool/drain/linked_drain
|
||||
/// Pool filter
|
||||
var/obj/machinery/pool/filter/linked_filter
|
||||
/// Next world.time you can interact with settings
|
||||
var/interact_delay = 0
|
||||
/// Airlock style shocks
|
||||
var/shocked = FALSE
|
||||
/// Old reagent color, used to determine if update_color needs to reset colors.
|
||||
var/old_rcolor
|
||||
/// Just to prevent spam
|
||||
var/draining = FALSE
|
||||
/// Reagent blacklisting
|
||||
var/respect_reagent_blacklist = TRUE
|
||||
|
||||
/obj/machinery/pool/controller/examine(mob/user)
|
||||
. = ..()
|
||||
. += "<span class='boldnotice'>Alt click to drain reagents.</span>"
|
||||
|
||||
/obj/machinery/pool/controller/Initialize()
|
||||
. = ..()
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
create_reagents(1000)
|
||||
if(noreact_reagents)
|
||||
reagents.reagents_holder_flags |= NO_REACT
|
||||
wires = new /datum/wires/poolcontroller(src)
|
||||
scan_things()
|
||||
|
||||
/obj/machinery/pool/controller/Destroy()
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
linked_drain = null
|
||||
linked_filter = null
|
||||
linked_turfs.Cut()
|
||||
mobs_in_pool.Cut()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/pool/controller/proc/scan_things()
|
||||
var/list/cached = range(scan_range, src)
|
||||
for(var/turf/open/pool/W in cached)
|
||||
linked_turfs += W
|
||||
W.controller = src
|
||||
for(var/obj/machinery/pool/drain/pooldrain in cached)
|
||||
linked_drain = pooldrain
|
||||
linked_drain.controller = src
|
||||
break
|
||||
for(var/obj/machinery/pool/filter/F in cached)
|
||||
linked_filter = F
|
||||
linked_filter.controller = src
|
||||
break
|
||||
|
||||
/obj/machinery/pool/controller/emag_act(mob/user)
|
||||
. = ..()
|
||||
if(!(obj_flags & EMAGGED)) //If it is not already emagged, emag it.
|
||||
to_chat(user, "<span class='warning'>You disable the [src]'s safety features.</span>")
|
||||
do_sparks(5, TRUE, src)
|
||||
obj_flags |= EMAGGED
|
||||
temperature_unlocked = TRUE
|
||||
drainable = TRUE
|
||||
log_game("[key_name(user)] emagged [src]")
|
||||
message_admins("[key_name_admin(user)] emagged [src]")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>The interface on [src] is already too damaged to short it again.</span>")
|
||||
return
|
||||
|
||||
/obj/machinery/pool/controller/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(!isliving(user) || !user.Adjacent(src) || !user.CanReach(src) || user.IsStun() || user.IsKnockdown() || user.incapacitated())
|
||||
return FALSE
|
||||
visible_message("<span class='boldwarning'>[user] starts to drain [src]!</span>")
|
||||
draining = TRUE
|
||||
if(!do_after(user, 50, target = src))
|
||||
draining = FALSE
|
||||
return TRUE
|
||||
reagents.remove_all(INFINITY)
|
||||
visible_message("<span class='boldnotice'>[user] drains [src].</span>")
|
||||
say("Reagents cleared.")
|
||||
update_color()
|
||||
draining = FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/pool/controller/attackby(obj/item/W, mob/user)
|
||||
if(shocked && !(stat & NOPOWER))
|
||||
shock(user,50)
|
||||
if(stat & (BROKEN))
|
||||
return
|
||||
if(istype(W,/obj/item/reagent_containers))
|
||||
if(W.reagents.total_volume) //check if there's reagent
|
||||
user.visible_message("<span class='boldwarning'>[user] is feeding [src] some chemicals from [W].</span>")
|
||||
if(do_after(user, 50, target = src))
|
||||
for(var/datum/reagent/R in W.reagents.reagent_list)
|
||||
if(R.type in GLOB.blacklisted_pool_reagents)
|
||||
to_chat(user, "[src] cannot accept [R.name].")
|
||||
return
|
||||
if(R.reagent_state == SOLID)
|
||||
to_chat(user, "The pool cannot accept reagents in solid form!.")
|
||||
return
|
||||
reagents.clear_reagents()
|
||||
// This also reacts them. No nitroglycerin deathpools, sorry gamers :(
|
||||
W.reagents.trans_to(reagents, max_beaker_transfer)
|
||||
user.visible_message("<span class='notice'>[src] makes a slurping noise.</span>", "<span class='notice'>All of the contents of [W] are quickly suctioned out by the machine!</span")
|
||||
updateUsrDialog()
|
||||
var/list/reagent_names = list()
|
||||
var/list/rejected = list()
|
||||
for(var/datum/reagent/R in reagents.reagent_list)
|
||||
if((R.volume >= min_reagent_amount) && (!respect_reagent_blacklist || R.can_synth))
|
||||
reagent_names += R.name
|
||||
else
|
||||
reagents.remove_reagent(R.type, INFINITY)
|
||||
rejected += R.name
|
||||
if(length(reagent_names))
|
||||
reagent_names = english_list(reagent_names)
|
||||
var/msg = "POOL: [key_name(user)] has changed [src]'s chems to [reagent_names]"
|
||||
log_game(msg)
|
||||
message_admins(msg)
|
||||
if(length(rejected))
|
||||
rejected = english_list(rejected)
|
||||
to_chat(user, "<span class='warning'>[src] rejects the following chemicals as they do not have at least [min_reagent_amount] units of volume: [rejected]</span>")
|
||||
update_color()
|
||||
else
|
||||
to_chat(user, "<span class='notice'>[src] beeps unpleasantly as it rejects the beaker. Why are you trying to feed it an empty beaker?</span>")
|
||||
return
|
||||
else if(panel_open && is_wire_tool(W))
|
||||
wires.interact(user)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/machinery/pool/controller/screwdriver_act(mob/living/user, obj/item/W)
|
||||
. = ..()
|
||||
if(.)
|
||||
return TRUE
|
||||
cut_overlays()
|
||||
panel_open = !panel_open
|
||||
to_chat(user, "You [panel_open ? "open" : "close"] the maintenance panel.")
|
||||
W.play_tool_sound(src)
|
||||
if(panel_open)
|
||||
add_overlay("wires")
|
||||
return TRUE
|
||||
|
||||
//procs
|
||||
/obj/machinery/pool/controller/proc/shock(mob/user, prb)
|
||||
if(stat & (BROKEN|NOPOWER)) // unpowered, no shock
|
||||
return FALSE
|
||||
if(!prob(prb))
|
||||
return FALSE
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(5, 1, src)
|
||||
s.start()
|
||||
if(electrocute_mob(user, get_area(src), src, 0.7))
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/pool/controller/proc/process_reagents()
|
||||
if(last_reagent_process > world.time + reagent_tick_interval)
|
||||
return
|
||||
if(!length(reagents.reagent_list))
|
||||
return
|
||||
for(var/turf/open/pool/W in linked_turfs)
|
||||
for(var/mob/living/carbon/human/swimee in W)
|
||||
for(var/datum/reagent/R in reagents.reagent_list)
|
||||
if(R.reagent_state == SOLID)
|
||||
R.reagent_state = LIQUID
|
||||
if(!swimee.reagents.has_reagent(POOL_NO_OVERDOSE_MEDICINE_MAX))
|
||||
swimee.reagents.add_reagent(R.type, 0.5) //osmosis
|
||||
reagents.reaction(swimee, VAPOR, 0.03) //3 percent. Need to find a way to prevent this from stacking chems at some point like the above.
|
||||
for(var/obj/objects in W)
|
||||
if(W.reagents)
|
||||
W.reagents.reaction(objects, VAPOR, 1)
|
||||
last_reagent_process = world.time
|
||||
|
||||
/obj/machinery/pool/controller/process()
|
||||
updateUsrDialog()
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if(drained)
|
||||
return
|
||||
process_pool()
|
||||
process_reagents()
|
||||
|
||||
/obj/machinery/pool/controller/proc/process_pool()
|
||||
if(drained)
|
||||
return
|
||||
for(var/mob/living/M in mobs_in_pool)
|
||||
switch(temperature) //Apply different effects based on what the temperature is set to.
|
||||
if(POOL_SCALDING) //Scalding
|
||||
M.adjust_bodytemperature(50,0,500)
|
||||
if(POOL_WARM) //Warm
|
||||
M.adjust_bodytemperature(20,0,360) //Heats up mobs till the termometer shows up
|
||||
//Normal temp does nothing, because it's just room temperature water.
|
||||
if(POOL_COOL)
|
||||
M.adjust_bodytemperature(-20,250) //Cools mobs till the termometer shows up
|
||||
if(POOL_FRIGID) //Freezing
|
||||
M.adjust_bodytemperature(-60) //cool mob at -35k per cycle, less would not affect the mob enough.
|
||||
if(M.bodytemperature <= 50 && !M.stat)
|
||||
M.apply_status_effect(/datum/status_effect/freon)
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/drownee = M
|
||||
if(!drownee || drownee.stat == DEAD)
|
||||
return
|
||||
if(drownee.resting && !drownee.internal)
|
||||
if(drownee.stat != CONSCIOUS)
|
||||
drownee.adjustOxyLoss(9)
|
||||
else
|
||||
drownee.adjustOxyLoss(4)
|
||||
if(prob(35))
|
||||
to_chat(drownee, "<span class='danger'>You're drowning!</span>")
|
||||
|
||||
/obj/machinery/pool/controller/proc/set_bloody(state)
|
||||
if(bloody == state)
|
||||
return
|
||||
bloody = state
|
||||
update_color()
|
||||
|
||||
/obj/machinery/pool/controller/proc/update_color()
|
||||
if(drained)
|
||||
return
|
||||
var/rcolor
|
||||
if(reagents.reagent_list.len)
|
||||
rcolor = mix_color_from_reagents(reagents.reagent_list)
|
||||
if(rcolor == old_rcolor)
|
||||
return // small performance upgrade hopefully?
|
||||
old_rcolor = rcolor
|
||||
for(var/X in linked_turfs)
|
||||
var/turf/open/pool/color1 = X
|
||||
if(bloody)
|
||||
if(rcolor)
|
||||
var/thecolor = BlendRGB(rgb(150, 20, 20), rcolor, 0.5)
|
||||
color1.watereffect.add_atom_colour(thecolor, FIXED_COLOUR_PRIORITY)
|
||||
color1.watertop.add_atom_colour(thecolor, FIXED_COLOUR_PRIORITY)
|
||||
else
|
||||
var/thecolor = rgb(150, 20, 20)
|
||||
color1.watereffect.add_atom_colour(thecolor, FIXED_COLOUR_PRIORITY)
|
||||
color1.watertop.add_atom_colour(thecolor, FIXED_COLOUR_PRIORITY)
|
||||
else if(!bloody && rcolor)
|
||||
color1.watereffect.add_atom_colour(rcolor, FIXED_COLOUR_PRIORITY)
|
||||
color1.watertop.add_atom_colour(rcolor, FIXED_COLOUR_PRIORITY)
|
||||
else
|
||||
color1.watereffect.remove_atom_colour(FIXED_COLOUR_PRIORITY)
|
||||
color1.watertop.remove_atom_colour(FIXED_COLOUR_PRIORITY)
|
||||
|
||||
/obj/machinery/pool/controller/proc/update_temp()
|
||||
if(mist_state)
|
||||
if(temperature < POOL_SCALDING)
|
||||
mist_off()
|
||||
else
|
||||
if(temperature == POOL_SCALDING)
|
||||
mist_on()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/pool/controller/update_icon()
|
||||
. = ..()
|
||||
icon_state = "poolc_[temperature]"
|
||||
|
||||
/obj/machinery/pool/controller/proc/CanUpTemp(mob/user)
|
||||
if(temperature == POOL_WARM && (temperature_unlocked || issilicon(user) || IsAdminGhost(user)) || temperature < POOL_WARM)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/pool/controller/proc/CanDownTemp(mob/user)
|
||||
if(temperature == POOL_COOL && (temperature_unlocked || issilicon(user) || IsAdminGhost(user)) || temperature > POOL_COOL)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/pool/controller/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
if(interact_delay > world.time)
|
||||
return
|
||||
if(href_list["IncreaseTemp"])
|
||||
if(CanUpTemp(usr))
|
||||
visible_message("<span class='warning'>[usr] presses a button on [src].</span>")
|
||||
temperature++
|
||||
update_temp()
|
||||
var/msg = "POOL: [key_name(usr)] increased [src]'s pool temperature at [COORD(src)] to [temperature]"
|
||||
log_game(msg)
|
||||
message_admins(msg)
|
||||
interact_delay = world.time + 15
|
||||
if(href_list["DecreaseTemp"])
|
||||
if(CanDownTemp(usr))
|
||||
visible_message("<span class='warning'>[usr] presses a button on [src].</span>")
|
||||
temperature--
|
||||
update_temp()
|
||||
var/msg = "POOL: [key_name(usr)] decreased [src]'s pool temperature at [COORD(src)] to [temperature]"
|
||||
log_game(msg)
|
||||
message_admins(msg)
|
||||
interact_delay = world.time + 15
|
||||
if(href_list["Activate Drain"])
|
||||
if((drainable || issilicon(usr) || IsAdminGhost(usr)) && !linked_drain.active)
|
||||
var/msg = "POOL: [key_name(usr)] activated [src]'s pool drain in [linked_drain.filling? "FILLING" : "DRAINING"] mode at [COORD(src)]"
|
||||
log_game(msg)
|
||||
message_admins(msg)
|
||||
visible_message("<span class='warning'>[usr] presses a button on [src].</span>")
|
||||
mist_off()
|
||||
interact_delay = world.time + 60
|
||||
linked_drain.active = TRUE
|
||||
linked_drain.cycles_left = 75
|
||||
if(!linked_drain.filling)
|
||||
new /obj/effect/whirlpool(linked_drain.loc)
|
||||
temperature = POOL_NORMAL
|
||||
else
|
||||
new /obj/effect/waterspout(linked_drain.loc)
|
||||
temperature = POOL_NORMAL
|
||||
update_temp()
|
||||
bloody = FALSE
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/pool/controller/proc/temp2text()
|
||||
switch(temperature)
|
||||
if(POOL_FRIGID)
|
||||
return "<span class='boldwarning'>Frigid</span>"
|
||||
if(POOL_COOL)
|
||||
return "<span class='boldnotice'>Cool</span>"
|
||||
if(POOL_NORMAL)
|
||||
return "<span class='notice'>Normal</span>"
|
||||
if(POOL_WARM)
|
||||
return "<span class='boldnotice'>Warm</span>"
|
||||
if(POOL_SCALDING)
|
||||
return "<span class='boldwarning'>Scalding</span>"
|
||||
else
|
||||
return "Outside of possible range."
|
||||
|
||||
/obj/machinery/pool/controller/ui_interact(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(shocked && !(stat & NOPOWER))
|
||||
shock(user,50)
|
||||
if(panel_open && !isAI(user))
|
||||
return wires.interact(user)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
var/datum/browser/popup = new(user, "Pool Controller", name, 300, 450)
|
||||
var/dat = ""
|
||||
if(interact_delay > world.time)
|
||||
dat += "<span class='notice'>[round((interact_delay - world.time)/10, 0.1)] seconds left until [src] can operate again.</span><BR>"
|
||||
dat += text({"
|
||||
<h3>Temperature</h3>
|
||||
<div class='statusDisplay'>
|
||||
<B>Current temperature:</B> [temp2text()]<BR>
|
||||
[CanUpTemp(user) ? "<a href='?src=\ref[src];IncreaseTemp=1'>Increase Temperature</a><br>" : "<span class='linkOff'>Increase Temperature</span><br>"]
|
||||
[CanDownTemp(user) ? "<a href='?src=\ref[src];DecreaseTemp=1'>Decrease Temperature</a><br>" : "<span class='linkOff'>Decrease Temperature</span><br>"]
|
||||
</div>
|
||||
<h3>Drain</h3>
|
||||
<div class='statusDisplay'>
|
||||
<B>Drain status:</B> [(issilicon(user) || IsAdminGhost(user) || drainable) ? "<span class='bad'>Enabled</span>" : "<span class='good'>Disabled</span>"]
|
||||
<br><b>Pool status:</b> "})
|
||||
if(!drained)
|
||||
dat += "<span class='good'>Full</span><BR>"
|
||||
else
|
||||
dat += "<span class='bad'>Drained</span><BR>"
|
||||
if((issilicon(user) || IsAdminGhost(user) || drainable) && !linked_drain.active)
|
||||
dat += "<a href='?src=\ref[src];Activate Drain=1'>[drained ? "Fill" : "Drain"] Pool</a><br>"
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/pool/controller/proc/reset(wire)
|
||||
switch(wire)
|
||||
if(WIRE_SHOCK)
|
||||
if(!wires.is_cut(wire))
|
||||
shocked = FALSE
|
||||
|
||||
/obj/machinery/pool/controller/proc/mist_on() //Spawn /obj/effect/mist (from the shower) on all linked pool tiles
|
||||
if(mist_state)
|
||||
return
|
||||
mist_state = TRUE
|
||||
for(var/X in linked_turfs)
|
||||
var/turf/open/pool/W = X
|
||||
if(W.filled)
|
||||
var/M = new /obj/effect/mist(W)
|
||||
linked_mist += M
|
||||
|
||||
/obj/machinery/pool/controller/proc/mist_off() //Delete all /obj/effect/mist from all linked pool tiles.
|
||||
for(var/M in linked_mist)
|
||||
qdel(M)
|
||||
mist_state = FALSE
|
||||
@@ -0,0 +1,160 @@
|
||||
/obj/machinery/pool/drain
|
||||
name = "drain"
|
||||
icon_state = "drain"
|
||||
desc = "A suction system to remove the contents of the pool, and sometimes small objects. Do not insert fingers."
|
||||
anchored = TRUE
|
||||
/// Active/on?
|
||||
var/active = FALSE
|
||||
/// Filling or draining
|
||||
var/filling = FALSE
|
||||
/// Drain item suction range
|
||||
var/item_suction_range = 2
|
||||
/// Fill mode knock away range
|
||||
var/fill_push_range = 6
|
||||
/// Drain mode suction range
|
||||
var/drain_suck_range = 6
|
||||
/// Parent controller
|
||||
var/obj/machinery/pool/controller/controller
|
||||
/// Cycles left for fill/drain while active
|
||||
var/cycles_left = 0
|
||||
/// Mobs we are swirling around
|
||||
var/list/whirling_mobs
|
||||
/// Suck in once per x ticks
|
||||
var/suck_in_once_per = 3
|
||||
|
||||
var/cooldown
|
||||
|
||||
/obj/machinery/pool/drain/Initialize()
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
whirling_mobs = list()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/pool/drain/Destroy()
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
controller.linked_drain = null
|
||||
controller = null
|
||||
whirling_mobs = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/pool/drain/proc/is_in_our_pool(atom/A)
|
||||
. = FALSE
|
||||
if(istype(A.loc, /turf/open/pool))
|
||||
var/turf/open/pool/P = A.loc
|
||||
if(P.controller == controller)
|
||||
. = TRUE
|
||||
|
||||
// This should probably start using move force sometime in the future but I'm lazy.
|
||||
/obj/machinery/pool/drain/process()
|
||||
if(!filling)
|
||||
for(var/obj/item/I in range(min(item_suction_range, 10), src))
|
||||
if(!I.anchored && (I.w_class <= WEIGHT_CLASS_SMALL))
|
||||
step_towards(I, src)
|
||||
if((I.w_class <= WEIGHT_CLASS_TINY) && (get_dist(I, src) == 0))
|
||||
I.forceMove(controller.linked_filter)
|
||||
if(active)
|
||||
if(filling)
|
||||
if(cycles_left-- > 0)
|
||||
playsound(src, 'sound/effects/fillingwatter.ogg', 100, TRUE)
|
||||
for(var/obj/O in orange(min(fill_push_range, 10), src))
|
||||
if(!O.anchored && is_in_our_pool(O))
|
||||
step_away(O, src)
|
||||
for(var/mob/M in orange(min(fill_push_range, 10), src)) //compiler fastpath apparently?
|
||||
if(!M.anchored && isliving(M) && is_in_our_pool(M))
|
||||
step_away(M, src)
|
||||
else
|
||||
for(var/turf/open/pool/P in controller.linked_turfs)
|
||||
P.filled = TRUE
|
||||
P.update_icon()
|
||||
for(var/obj/effect/waterspout/S in range(1, src))
|
||||
qdel(S)
|
||||
controller.drained = FALSE
|
||||
if(controller.bloody < 1000)
|
||||
controller.bloody /= 2
|
||||
else
|
||||
controller.bloody /= 4
|
||||
controller.update_color()
|
||||
filling = FALSE
|
||||
active = FALSE
|
||||
else
|
||||
if(cycles_left-- > 0)
|
||||
playsound(src, 'sound/effects/pooldrain.ogg', 100, TRUE)
|
||||
playsound(src, "water_wade", 60, TRUE)
|
||||
for(var/obj/O in orange(min(drain_suck_range, 10), src))
|
||||
if(!O.anchored && is_in_our_pool(O))
|
||||
step_towards(O, src)
|
||||
for(var/mob/M in orange(min(drain_suck_range, 10), src))
|
||||
if(isliving(M) && !M.anchored && is_in_our_pool(M))
|
||||
if(!(cycles_left % suck_in_once_per))
|
||||
step_towards(M, src)
|
||||
whirl_mob(M)
|
||||
if(ishuman(M) && (get_dist(M, src) <= 1))
|
||||
var/mob/living/carbon/human/H = M
|
||||
playsound(src, pick('sound/misc/crack.ogg','sound/misc/crunch.ogg'), 50, TRUE)
|
||||
if(H.lying) //down for any reason
|
||||
H.adjustBruteLoss(2)
|
||||
to_chat(H, "<span class='danger'>You're caught in the drain!</span>")
|
||||
else
|
||||
H.apply_damage(2.5, BRUTE, pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)) //drain should only target the legs
|
||||
to_chat(H, "<span class='danger'>Your legs are caught in the drain!</span>")
|
||||
else
|
||||
for(var/turf/open/pool/P in controller.linked_turfs)
|
||||
P.filled = FALSE
|
||||
P.update_icon()
|
||||
for(var/obj/effect/whirlpool/W in range(1, src))
|
||||
qdel(W)
|
||||
controller.drained = TRUE
|
||||
controller.mist_off()
|
||||
active = FALSE
|
||||
filling = TRUE
|
||||
|
||||
/// dangerous proc don't fuck with, admins
|
||||
/obj/machinery/pool/drain/proc/whirl_mob(mob/living/L, duration = 8, delay = 1)
|
||||
set waitfor = FALSE
|
||||
if(whirling_mobs[L])
|
||||
return
|
||||
whirling_mobs[L] = TRUE
|
||||
for(var/i in 1 to min(duration, 100))
|
||||
L.setDir(turn(L.dir, 90))
|
||||
sleep(delay)
|
||||
if(QDELETED(L))
|
||||
break
|
||||
if(QDELETED(src))
|
||||
return
|
||||
whirling_mobs -= L
|
||||
|
||||
/obj/machinery/pool/filter
|
||||
name = "Filter"
|
||||
icon_state = "filter"
|
||||
desc = "The part of the pool where all the IDs, ATV keys, and pens, and other dangerous things get trapped."
|
||||
var/obj/machinery/pool/controller/controller
|
||||
|
||||
/obj/machinery/pool/filter/Destroy()
|
||||
controller.linked_filter = null
|
||||
controller = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/pool/filter/emag_act(mob/living/user)
|
||||
. = ..()
|
||||
if(!(obj_flags & EMAGGED))
|
||||
to_chat(user, "<span class='warning'>You disable the [src]'s shark filter! Run!</span>")
|
||||
obj_flags |= EMAGGED
|
||||
do_sparks(5, TRUE, src)
|
||||
icon_state = "filter_b"
|
||||
addtimer(CALLBACK(src, /obj/machinery/pool/filter/proc/spawn_shark), 50)
|
||||
var/msg = "[key_name(user)] emagged the pool filter and spawned a shark"
|
||||
log_game(msg)
|
||||
message_admins(msg)
|
||||
|
||||
/obj/machinery/pool/filter/proc/spawn_shark()
|
||||
if(prob(50))
|
||||
new /mob/living/simple_animal/hostile/shark(loc)
|
||||
else
|
||||
if(prob(50))
|
||||
new /mob/living/simple_animal/hostile/shark/kawaii(loc)
|
||||
else
|
||||
new /mob/living/simple_animal/hostile/shark/laser(loc)
|
||||
|
||||
/obj/machinery/pool/filter/attack_hand(mob/user)
|
||||
to_chat(user, "You search the filter.")
|
||||
for(var/obj/O in contents)
|
||||
O.forceMove(loc)
|
||||
@@ -0,0 +1,29 @@
|
||||
/obj/effect/splash
|
||||
name = "splash"
|
||||
desc = "Wataaa!."
|
||||
icon = 'icons/turf/pool.dmi'
|
||||
icon_state = "splash"
|
||||
layer = ABOVE_ALL_MOB_LAYER
|
||||
|
||||
/obj/effect/whirlpool
|
||||
name = "Whirlpool"
|
||||
icon = 'icons/effects/96x96.dmi'
|
||||
icon_state = "whirlpool"
|
||||
layer = 5
|
||||
anchored = TRUE
|
||||
mouse_opacity = 0
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
alpha = 90
|
||||
|
||||
/obj/effect/waterspout
|
||||
name = "Waterspout"
|
||||
icon = 'icons/effects/96x96.dmi'
|
||||
icon_state = "waterspout"
|
||||
color = "#3399AA"
|
||||
layer = 5
|
||||
anchored = TRUE
|
||||
mouse_opacity = 0
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
alpha = 120
|
||||
@@ -0,0 +1,191 @@
|
||||
/turf/open/pool
|
||||
icon = 'icons/turf/pool.dmi'
|
||||
name = "poolwater"
|
||||
desc = "You're safer here than in the deep."
|
||||
icon_state = "pool_tile"
|
||||
heat_capacity = INFINITY
|
||||
var/filled = TRUE
|
||||
var/next_splash = 0
|
||||
var/obj/machinery/pool/controller/controller
|
||||
var/obj/effect/overlay/water/watereffect
|
||||
var/obj/effect/overlay/water/top/watertop
|
||||
|
||||
/turf/open/pool/Initialize(mapload)
|
||||
. = ..()
|
||||
update_icon()
|
||||
|
||||
/turf/open/pool/Destroy()
|
||||
if(controller)
|
||||
controller.linked_turfs -= src
|
||||
controller = null
|
||||
QDEL_NULL(watereffect)
|
||||
QDEL_NULL(watertop)
|
||||
return ..()
|
||||
|
||||
/turf/open/pool/update_icon()
|
||||
. = ..()
|
||||
if(!filled)
|
||||
name = "drained pool"
|
||||
desc = "No diving!"
|
||||
QDEL_NULL(watereffect)
|
||||
QDEL_NULL(watertop)
|
||||
else
|
||||
name = "poolwater"
|
||||
desc = "You're safer here than in the deep."
|
||||
watereffect = new /obj/effect/overlay/water(src)
|
||||
watertop = new /obj/effect/overlay/water/top(src)
|
||||
|
||||
/obj/effect/overlay/water
|
||||
name = "water"
|
||||
icon = 'icons/turf/pool.dmi'
|
||||
icon_state = "bottom"
|
||||
density = FALSE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
layer = ABOVE_MOB_LAYER
|
||||
anchored = TRUE
|
||||
resistance_flags = INDESTRUCTIBLE
|
||||
|
||||
/obj/effect/overlay/water/top
|
||||
icon_state = "top"
|
||||
layer = BELOW_MOB_LAYER
|
||||
|
||||
// Mousedrop hook to normal turfs to get out of pools.
|
||||
/turf/open/MouseDrop_T(atom/from, mob/user)
|
||||
// I could make this /open/floor and not have the !istype but ehh - kev
|
||||
if(isliving(from) && HAS_TRAIT(from, TRAIT_SWIMMING) && isliving(user) && ((user == from) || user.CanReach(from)) && !user.IsStun() && !user.IsKnockdown() && !user.incapacitated() && !istype(src, /turf/open/pool))
|
||||
var/mob/living/L = from
|
||||
//The element only exists if you're on water and a living mob, so let's skip those checks.
|
||||
var/pre_msg
|
||||
var/post_msg
|
||||
if(user == from)
|
||||
pre_msg = "<span class='notice'>[L] is getting out of the pool.</span>"
|
||||
post_msg = "<span class='notice'>[L] gets out of the pool.</span>"
|
||||
else
|
||||
pre_msg = "<span class='notice'>[L] is being pulled out of the pool by [user].</span>"
|
||||
post_msg = "<span class='notice'>[user] pulls [L] out of the pool.</span>"
|
||||
L.visible_message(pre_msg)
|
||||
if(do_mob(user, L, 20))
|
||||
L.visible_message(post_msg)
|
||||
L.forceMove(src)
|
||||
else
|
||||
return ..()
|
||||
|
||||
// Exit check
|
||||
/turf/open/pool/Exit(atom/movable/AM, atom/newloc)
|
||||
if(!AM.has_gravity(src))
|
||||
return ..()
|
||||
if(isliving(AM) || isstructure(AM))
|
||||
if(AM.throwing)
|
||||
return ..() //WHEEEEEEEEEEE
|
||||
if(istype(AM, /obj/structure) && isliving(AM.pulledby))
|
||||
return ..() //people pulling stuff out of pool
|
||||
if(!ishuman(AM))
|
||||
return ..() //human weak, monkey (and anyone else) ook ook eek eek strong
|
||||
if(isliving(AM) && (locate(/obj/structure/pool/ladder) in src))
|
||||
return ..() //climbing out
|
||||
return istype(newloc, /turf/open/pool)
|
||||
return ..()
|
||||
|
||||
// Exited logic
|
||||
/turf/open/pool/Exited(atom/A, atom/newLoc)
|
||||
. = ..()
|
||||
if(isliving(A))
|
||||
var/turf/open/pool/P = newLoc
|
||||
if(!istype(P) || (P.controller != controller))
|
||||
controller?.mobs_in_pool -= A
|
||||
|
||||
// Entered logic
|
||||
/turf/open/pool/Entered(atom/movable/AM, atom/oldloc)
|
||||
if(istype(AM, /obj/effect/decal/cleanable))
|
||||
var/obj/effect/decal/cleanable/C = AM
|
||||
if(prob(C.bloodiness))
|
||||
controller.set_bloody(TRUE)
|
||||
QDEL_IN(AM, 25)
|
||||
animate(AM, alpha = 10, time = 20)
|
||||
return ..()
|
||||
if(!AM.has_gravity(src))
|
||||
return ..()
|
||||
if(isliving(AM))
|
||||
var/mob/living/victim = AM
|
||||
if(!HAS_TRAIT(victim, TRAIT_SWIMMING)) //poor guy not swimming time to dunk them!
|
||||
victim.AddElement(/datum/element/swimming)
|
||||
controller.mobs_in_pool += victim
|
||||
if(locate(/obj/structure/pool/ladder) in src) //safe climbing
|
||||
return
|
||||
if(iscarbon(AM)) //FUN TIME!
|
||||
var/mob/living/carbon/H = victim
|
||||
if(filled)
|
||||
if (H.wear_mask && H.wear_mask.flags_cover & MASKCOVERSMOUTH)
|
||||
H.visible_message("<span class='danger'>[H] falls in the water!</span>",
|
||||
"<span class='userdanger'>You fall in the water!</span>")
|
||||
playsound(src, 'sound/effects/splash.ogg', 60, TRUE, 1)
|
||||
H.Knockdown(20)
|
||||
return
|
||||
else
|
||||
H.Knockdown(60)
|
||||
H.adjustOxyLoss(5)
|
||||
H.emote("cough")
|
||||
H.visible_message("<span class='danger'>[H] falls in and takes a drink!</span>",
|
||||
"<span class='userdanger'>You fall in and swallow some water!</span>")
|
||||
playsound(src, 'sound/effects/splash.ogg', 60, TRUE, 1)
|
||||
else if(!H.head || !(H.head.armor.getRating("melee") > 20))
|
||||
if(prob(75))
|
||||
H.visible_message("<span class='danger'>[H] falls in the drained pool!</span>",
|
||||
"<span class='userdanger'>You fall in the drained pool!</span>")
|
||||
H.adjustBruteLoss(7)
|
||||
H.Knockdown(80)
|
||||
playsound(src, 'sound/effects/woodhit.ogg', 60, TRUE, 1)
|
||||
else
|
||||
H.visible_message("<span class='danger'>[H] falls in the drained pool, and cracks his skull!</span>",
|
||||
"<span class='userdanger'>You fall in the drained pool, and crack your skull!</span>")
|
||||
H.apply_damage(15, BRUTE, "head")
|
||||
H.Knockdown(200) // This should hurt. And it does.
|
||||
playsound(src, 'sound/effects/woodhit.ogg', 60, TRUE, 1)
|
||||
playsound(src, 'sound/misc/crack.ogg', 100, TRUE)
|
||||
else
|
||||
H.visible_message("<span class='danger'>[H] falls in the drained pool, but had an helmet!</span>",
|
||||
"<span class='userdanger'>You fall in the drained pool, but you had an helmet!</span>")
|
||||
H.Knockdown(40)
|
||||
playsound(src, 'sound/effects/woodhit.ogg', 60, TRUE, 1)
|
||||
else if(filled)
|
||||
victim.adjustStaminaLoss(1)
|
||||
playsound(src, "water_wade", 20, TRUE)
|
||||
return ..()
|
||||
|
||||
/turf/open/pool/MouseDrop_T(atom/from, mob/user)
|
||||
. = ..()
|
||||
if(!isliving(from))
|
||||
return
|
||||
var/mob/living/victim = from
|
||||
if(user.stat || user.lying || !Adjacent(user) || !from.Adjacent(user) || !iscarbon(user) || !victim.has_gravity(src) || HAS_TRAIT(victim, TRAIT_SWIMMING))
|
||||
return
|
||||
var/victimname = victim == user? "themselves" : "[victim]"
|
||||
var/starttext = victim == user? "[user] is descending into [src]." : "[user] is lowering [victim] into [src]."
|
||||
user.visible_message("<span class='notice'>[starttext]</span>")
|
||||
if(do_mob(user, victim, 20))
|
||||
user.visible_message("<span class='notice'>[user] lowers [victimname] into [src].</span>")
|
||||
victim.AddElement(/datum/element/swimming) //make sure they have it so they don't fall/whatever
|
||||
victim.forceMove(src)
|
||||
|
||||
/turf/open/pool/attackby(obj/item/W, mob/living/user)
|
||||
if(istype(W, /obj/item/mop) && filled)
|
||||
W.reagents.add_reagent("water", 5)
|
||||
to_chat(user, "<span class='notice'>You wet [W] in [src].</span>")
|
||||
playsound(loc, 'sound/effects/slosh.ogg', 25, TRUE)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/turf/open/pool/attack_hand(mob/living/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if((user.loc != src) && !user.IsStun() && !user.IsKnockdown() && !user.incapacitated() && Adjacent(user) && HAS_TRAIT(user, TRAIT_SWIMMING) && filled && (next_splash < world.time))
|
||||
playsound(src, 'sound/effects/watersplash.ogg', 8, TRUE, 1)
|
||||
next_splash = world.time + 25
|
||||
var/obj/effect/splash/S = new(src)
|
||||
animate(S, alpha = 0, time = 8)
|
||||
QDEL_IN(S, 10)
|
||||
for(var/mob/living/carbon/human/H in src)
|
||||
if(!H.wear_mask && (H.stat == CONSCIOUS))
|
||||
H.emote("cough")
|
||||
H.adjustStaminaLoss(4)
|
||||
@@ -0,0 +1,32 @@
|
||||
//Pool noodles
|
||||
|
||||
/obj/item/toy/poolnoodle
|
||||
icon = 'icons/obj/toy.dmi'
|
||||
icon_state = "noodle"
|
||||
name = "pool noodle"
|
||||
desc = "A strange, bulky, bendable toy that can annoy people."
|
||||
force = 0
|
||||
color = "#000000"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
throwforce = 1
|
||||
throw_speed = 10 //weeee
|
||||
hitsound = 'sound/weapons/tap.ogg'
|
||||
attack_verb = list("flogged", "poked", "jabbed", "slapped", "annoyed")
|
||||
lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/items_righthand.dmi'
|
||||
|
||||
/obj/item/toy/poolnoodle/attack(target as mob, mob/living/user as mob)
|
||||
. = ..()
|
||||
user.spin(prob(20)? 16 : 8, 1)
|
||||
|
||||
/obj/item/toy/poolnoodle/red
|
||||
item_state = "noodlered"
|
||||
color = "#ff4c4c"
|
||||
|
||||
/obj/item/toy/poolnoodle/blue
|
||||
item_state = "noodleblue"
|
||||
color = "#3232ff"
|
||||
|
||||
/obj/item/toy/poolnoodle/yellow
|
||||
item_state = "noodleyellow"
|
||||
color = "#ffff66"
|
||||
@@ -0,0 +1,159 @@
|
||||
/obj/structure/pool
|
||||
name = "pool"
|
||||
icon = 'icons/obj/machines/pool.dmi'
|
||||
anchored = TRUE
|
||||
resistance_flags = UNACIDABLE|INDESTRUCTIBLE
|
||||
|
||||
/obj/structure/pool/ladder
|
||||
name = "Ladder"
|
||||
icon_state = "ladder"
|
||||
desc = "Are you getting in or are you getting out?."
|
||||
layer = ABOVE_MOB_LAYER
|
||||
dir = EAST
|
||||
|
||||
/obj/structure/pool/ladder/attack_hand(mob/living/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(!HAS_TRAIT(user, TRAIT_SWIMMING))
|
||||
if(user.CanReach(src))
|
||||
user.AddElement(/datum/element/swimming)
|
||||
user.forceMove(get_step(src, dir))
|
||||
else
|
||||
if(user.loc == loc)
|
||||
user.forceMove(get_step(src, turn(dir, 180))) //If this moves them out the element cleans up after itself.
|
||||
|
||||
/obj/structure/pool/Rboard
|
||||
name = "JumpBoard"
|
||||
density = FALSE
|
||||
icon_state = "boardright"
|
||||
desc = "The less-loved portion of the jumping board."
|
||||
dir = EAST
|
||||
|
||||
/obj/structure/pool/Lboard
|
||||
name = "JumpBoard"
|
||||
icon_state = "boardleft"
|
||||
desc = "Get on there to jump!"
|
||||
layer = FLY_LAYER
|
||||
dir = WEST
|
||||
var/jumping = FALSE
|
||||
var/timer
|
||||
|
||||
/obj/structure/pool/Lboard/proc/backswim()
|
||||
if(jumping)
|
||||
for(var/mob/living/jumpee in loc) //hackzors.
|
||||
playsound(jumpee, 'sound/effects/splash.ogg', 60, TRUE, 1)
|
||||
if(!HAS_TRAIT(jumpee, TRAIT_SWIMMING))
|
||||
jumpee.AddElement(/datum/element/swimming)
|
||||
jumpee.Stun(2)
|
||||
|
||||
/obj/structure/pool/Lboard/proc/reset_position(mob/user, initial_layer, initial_px, initial_py)
|
||||
user.layer = initial_layer
|
||||
user.pixel_x = initial_px
|
||||
user.pixel_y = initial_py
|
||||
|
||||
/obj/structure/pool/Lboard/attack_hand(mob/living/user)
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/jumper = user
|
||||
if(jumping)
|
||||
to_chat(user, "<span class='notice'>Someone else is already making a jump!</span>")
|
||||
return
|
||||
var/turf/T = get_turf(src)
|
||||
if(HAS_TRAIT(user, TRAIT_SWIMMING))
|
||||
return
|
||||
else
|
||||
if(Adjacent(jumper))
|
||||
jumper.visible_message("<span class='notice'>[user] climbs up \the [src]!</span>", \
|
||||
"<span class='notice'>You climb up \the [src] and prepares to jump!</span>")
|
||||
jumper.Stun(40)
|
||||
jumping = TRUE
|
||||
var/original_layer = jumper.layer
|
||||
var/original_px = jumper.pixel_x
|
||||
var/original_py = jumper.pixel_y
|
||||
jumper.layer = RIPPLE_LAYER
|
||||
jumper.pixel_x = 3
|
||||
jumper.pixel_y = 7
|
||||
jumper.dir = WEST
|
||||
jumper.AddElement(/datum/element/swimming)
|
||||
sleep(1)
|
||||
jumper.forceMove(T)
|
||||
addtimer(CALLBACK(src, .proc/dive, jumper, original_layer, original_px, original_py), 10)
|
||||
|
||||
/obj/structure/pool/Lboard/proc/dive(mob/living/carbon/jumper, original_layer, original_px, original_py)
|
||||
switch(rand(1, 100))
|
||||
if(1 to 20)
|
||||
jumper.visible_message("<span class='notice'>[jumper] goes for a small dive!</span>", \
|
||||
"<span class='notice'>You go for a small dive.</span>")
|
||||
sleep(15)
|
||||
backswim()
|
||||
var/atom/throw_target = get_edge_target_turf(src, dir)
|
||||
jumper.throw_at(throw_target, 1, 1, callback = CALLBACK(src, .proc/on_finish_jump, jumper))
|
||||
|
||||
if(21 to 40)
|
||||
jumper.visible_message("<span class='notice'>[jumper] goes for a dive!</span>", \
|
||||
"<span class='notice'>You're going for a dive!</span>")
|
||||
sleep(20)
|
||||
backswim()
|
||||
var/atom/throw_target = get_edge_target_turf(src, dir)
|
||||
jumper.throw_at(throw_target, 2, 1, callback = CALLBACK(src, .proc/on_finish_jump, jumper))
|
||||
|
||||
if(41 to 60)
|
||||
jumper.visible_message("<span class='notice'>[jumper] goes for a long dive! Stay far away!</span>", \
|
||||
"<span class='notice'>You're going for a long dive!!</span>")
|
||||
sleep(25)
|
||||
backswim()
|
||||
var/atom/throw_target = get_edge_target_turf(src, dir)
|
||||
jumper.throw_at(throw_target, 3, 1, callback = CALLBACK(src, .proc/on_finish_jump, jumper))
|
||||
|
||||
if(61 to 80)
|
||||
jumper.visible_message("<span class='notice'>[jumper] goes for an awesome dive! Don't stand in [jumper.p_their()] way!</span>", \
|
||||
"<span class='notice'>You feel like this dive will be awesome</span>")
|
||||
sleep(30)
|
||||
backswim()
|
||||
var/atom/throw_target = get_edge_target_turf(src, dir)
|
||||
jumper.throw_at(throw_target, 4, 1, callback = CALLBACK(src, .proc/on_finish_jump, jumper))
|
||||
if(81 to 91)
|
||||
sleep(20)
|
||||
backswim()
|
||||
jumper.visible_message("<span class='danger'>[jumper] misses [jumper.p_their()] step!</span>", \
|
||||
"<span class='userdanger'>You misstep!</span>")
|
||||
var/atom/throw_target = get_edge_target_turf(src, dir)
|
||||
jumper.throw_at(throw_target, 0, 1, callback = CALLBACK(src, .proc/on_finish_jump, jumper))
|
||||
jumper.Knockdown(100)
|
||||
jumper.adjustBruteLoss(10)
|
||||
|
||||
if(91 to 100)
|
||||
jumper.visible_message("<span class='notice'>[jumper] is preparing for the legendary dive! Can [jumper.p_they()] make it?</span>", \
|
||||
"<span class='userdanger'>You start preparing for a legendary dive!</span>")
|
||||
jumper.SpinAnimation(7,1)
|
||||
|
||||
sleep(30)
|
||||
if(prob(75))
|
||||
backswim()
|
||||
jumper.visible_message("<span class='notice'>[jumper] fails!</span>", \
|
||||
"<span class='userdanger'>You can't quite do it!</span>")
|
||||
var/atom/throw_target = get_edge_target_turf(src, dir)
|
||||
jumper.throw_at(throw_target, 1, 1, callback = CALLBACK(src, .proc/on_finish_jump, jumper))
|
||||
else
|
||||
jumper.fire_stacks = min(1,jumper.fire_stacks + 1)
|
||||
jumper.IgniteMob()
|
||||
sleep(5)
|
||||
backswim()
|
||||
jumper.visible_message("<span class='danger'>[jumper] bursts into flames of pure awesomness!</span>", \
|
||||
"<span class='userdanger'>No one can stop you now!</span>")
|
||||
var/atom/throw_target = get_edge_target_turf(src, dir)
|
||||
jumper.throw_at(throw_target, 6, 1, callback = CALLBACK(src, .proc/on_finish_jump, jumper))
|
||||
addtimer(CALLBACK(src, .proc/togglejumping), 35)
|
||||
reset_position(jumper, original_layer, original_px, original_py)
|
||||
|
||||
/obj/structure/pool/Lboard/proc/togglejumping()
|
||||
jumping = FALSE
|
||||
|
||||
/obj/structure/pool/Lboard/proc/on_finish_jump(mob/living/victim)
|
||||
if(istype(victim.loc, /turf/open/pool))
|
||||
var/turf/open/pool/P = victim.loc
|
||||
if(!P.filled) //you dun fucked up now
|
||||
to_chat(victim, "<span class='warning'>That was stupid of you..</span>")
|
||||
victim.visible_message("<span class='danger'>[victim] smashes into the ground!</span>")
|
||||
victim.apply_damage(50)
|
||||
victim.Knockdown(200)
|
||||
@@ -0,0 +1,59 @@
|
||||
#define POOL_WIRE_DRAIN "drain"
|
||||
#define POOL_WIRE_TEMP "temp"
|
||||
|
||||
|
||||
/datum/wires/poolcontroller
|
||||
holder_type = /obj/machinery/pool/controller
|
||||
proper_name = "Pool"
|
||||
|
||||
/datum/wires/poolcontroller/New(atom/holder)
|
||||
wires = list(
|
||||
POOL_WIRE_DRAIN, WIRE_SHOCK, WIRE_ZAP, POOL_WIRE_TEMP
|
||||
)
|
||||
add_duds(3)
|
||||
..()
|
||||
|
||||
/datum/wires/poolcontroller/interactable(mob/user)
|
||||
var/obj/machinery/pool/controller/P = holder
|
||||
if(P.panel_open)
|
||||
return TRUE
|
||||
|
||||
/datum/wires/poolcontroller/get_status()
|
||||
var/obj/machinery/pool/controller/P = holder
|
||||
var/list/status = list()
|
||||
status += "The blue light is [P.drainable ? "on" : "off"]."
|
||||
status += "The red light is [P.temperature_unlocked ? "on" : "off"]."
|
||||
status += "The yellow light is [P.shocked ? "on" : "off"]."
|
||||
return status
|
||||
|
||||
/datum/wires/poolcontroller/on_pulse(wire)
|
||||
var/obj/machinery/pool/controller/P = holder
|
||||
switch(wire)
|
||||
if(POOL_WIRE_DRAIN)
|
||||
P.drainable = FALSE
|
||||
if(POOL_WIRE_TEMP)
|
||||
P.temperature_unlocked = FALSE
|
||||
if(WIRE_SHOCK)
|
||||
P.shocked = !P.shocked
|
||||
addtimer(CALLBACK(P, /obj/machinery/autolathe.proc/reset, wire), 60)
|
||||
|
||||
/datum/wires/poolcontroller/on_cut(wire, mend)
|
||||
var/obj/machinery/pool/controller/P = holder
|
||||
switch(wire)
|
||||
if(POOL_WIRE_DRAIN)
|
||||
if(mend)
|
||||
P.drainable = FALSE
|
||||
else
|
||||
P.drainable = TRUE
|
||||
if(POOL_WIRE_TEMP)
|
||||
if(mend)
|
||||
P.temperature_unlocked = FALSE
|
||||
else
|
||||
P.temperature_unlocked = TRUE
|
||||
if(WIRE_ZAP)
|
||||
P.shock(usr, 50)
|
||||
if(WIRE_SHOCK)
|
||||
if(mend)
|
||||
P.stat &= ~NOPOWER
|
||||
else
|
||||
P.stat |= NOPOWER
|
||||
@@ -346,6 +346,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
|
||||
// Pass all the gas related code an empty gas container
|
||||
removed = new()
|
||||
|
||||
damage = min(damage_archived + (DAMAGE_HARDCAP * explosion_point),damage) // hardcap any direct damage taken before doing atmos damage
|
||||
damage_archived = damage
|
||||
if(!removed || !removed.total_moles() || isspaceturf(T)) //we're in space or there is no gas to process
|
||||
if(takes_damage)
|
||||
|
||||
@@ -77,6 +77,8 @@
|
||||
|
||||
/datum/reagents/Destroy()
|
||||
. = ..()
|
||||
//We're about to delete all reagents, so lets cleanup
|
||||
addiction_list.Cut()
|
||||
var/list/cached_reagents = reagent_list
|
||||
for(var/reagent in cached_reagents)
|
||||
var/datum/reagent/R = reagent
|
||||
@@ -332,9 +334,7 @@
|
||||
if(R.addiction_stage3_end to R.addiction_stage4_end)
|
||||
need_mob_update += R.addiction_act_stage4(C)
|
||||
if(R.addiction_stage4_end to INFINITY)
|
||||
to_chat(C, "<span class='notice'>You feel like you've gotten over your need for [R.name].</span>")
|
||||
SEND_SIGNAL(C, COMSIG_CLEAR_MOOD_EVENT, "[R.type]_addiction")
|
||||
cached_addictions.Remove(R)
|
||||
remove_addiction(R)
|
||||
else
|
||||
SEND_SIGNAL(C, COMSIG_CLEAR_MOOD_EVENT, "[R.type]_overdose")
|
||||
addiction_tick++
|
||||
@@ -344,6 +344,12 @@
|
||||
C.update_stamina()
|
||||
update_total()
|
||||
|
||||
/datum/reagents/proc/remove_addiction(datum/reagent/R)
|
||||
to_chat(my_atom, "<span class='notice'>You feel like you've gotten over your need for [R.name].</span>")
|
||||
SEND_SIGNAL(my_atom, COMSIG_CLEAR_MOOD_EVENT, "[R.type]_overdose")
|
||||
addiction_list.Remove(R)
|
||||
qdel(R)
|
||||
|
||||
//Signals that metabolization has stopped, triggering the end of trait-based effects
|
||||
/datum/reagents/proc/end_metabolization(mob/living/carbon/C, keep_liverless = TRUE)
|
||||
var/list/cached_reagents = reagent_list
|
||||
@@ -762,6 +768,8 @@
|
||||
R.metabolizing = FALSE
|
||||
R.on_mob_end_metabolize(M)
|
||||
R.on_mob_delete(M)
|
||||
//Clear from relevant lists
|
||||
addiction_list -= R
|
||||
qdel(R)
|
||||
reagent_list -= R
|
||||
update_total()
|
||||
|
||||
@@ -168,7 +168,7 @@ GLOBAL_LIST_INIT(food_reagents, build_reagents_to_food()) //reagentid = related
|
||||
|
||||
/obj/item/paper/secretrecipe
|
||||
name = "old recipe"
|
||||
var/recipe_id = "secretsauce"
|
||||
var/recipe_id = /datum/reagent/consumable/secretsauce
|
||||
|
||||
/obj/item/paper/secretrecipe/examine(mob/user) //Extra secret
|
||||
if(isobserver(user))
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
SEND_SIGNAL(A, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_MEDIUM)
|
||||
return
|
||||
|
||||
/obj/item/reagent_containers/rag/pre_altattackby(mob/living/M, mob/living/user, params)
|
||||
/obj/item/reagent_containers/rag/alt_pre_attack(mob/living/M, mob/living/user, params)
|
||||
if(istype(M) && user.a_intent == INTENT_HELP)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
if(M.on_fire)
|
||||
|
||||
@@ -289,6 +289,16 @@
|
||||
////////////Janitor Designs//////////////
|
||||
/////////////////////////////////////////
|
||||
|
||||
/datum/design/broom
|
||||
name = "Broom"
|
||||
desc = "Just your everyday standard broom."
|
||||
id = "broom"
|
||||
build_type = PROTOLATHE
|
||||
materials = list(MAT_METAL = 1000, MAT_GLASS = 600)
|
||||
build_path = /obj/item/twohanded/broom
|
||||
category = list("Equipment")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_SERVICE
|
||||
|
||||
/datum/design/mop
|
||||
name = "Mop"
|
||||
desc = "Just your everyday standard mop."
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
name = "Host Scan"
|
||||
desc = "The nanites display a detailed readout of a body scan to the host."
|
||||
id = "selfscan_nanites"
|
||||
program_type = /datum/nanite_program/triggered/self_scan
|
||||
program_type = /datum/nanite_program/self_scan
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/dermal_button
|
||||
@@ -67,7 +67,6 @@
|
||||
program_type = /datum/nanite_program/stealth
|
||||
category = list("Utility Nanites")
|
||||
|
||||
|
||||
/datum/design/nanites/reduced_diagnostics
|
||||
name = "Reduced Diagnostics"
|
||||
desc = "Disables some high-cost diagnostics in the nanites, making them unable to communicate their program list to portable scanners. \
|
||||
@@ -80,7 +79,7 @@
|
||||
name = "Subdermal ID"
|
||||
desc = "The nanites store the host's ID access rights in a subdermal magnetic strip. Updates when triggered, copying the host's current access."
|
||||
id = "access_nanites"
|
||||
program_type = /datum/nanite_program/triggered/access
|
||||
program_type = /datum/nanite_program/access
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/relay
|
||||
@@ -106,9 +105,9 @@
|
||||
|
||||
/datum/design/nanites/emp
|
||||
name = "Electromagnetic Resonance"
|
||||
desc = "The nanites cause an elctromagnetic pulse around the host when triggered. Will corrupt other nanite programs!"
|
||||
desc = "The nanites cause an electromagnetic pulse around the host when triggered. Will corrupt other nanite programs!"
|
||||
id = "emp_nanites"
|
||||
program_type = /datum/nanite_program/triggered/emp
|
||||
program_type = /datum/nanite_program/emp
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/spreading
|
||||
@@ -119,6 +118,13 @@
|
||||
program_type = /datum/nanite_program/spreading
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/nanite_sting
|
||||
name = "Nanite Sting"
|
||||
desc = "When triggered, projects a nearly invisible spike of nanites that attempts to infect a nearby non-host with a copy of the host's nanites cluster."
|
||||
id = "nanite_sting_nanites"
|
||||
program_type = /datum/nanite_program/nanite_sting
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/mitosis
|
||||
name = "Mitosis"
|
||||
desc = "The nanites gain the ability to self-replicate, using bluespace to power the process, instead of drawing from a template. This rapidly speeds up the replication rate,\
|
||||
@@ -197,7 +203,7 @@
|
||||
name = "Defibrillation"
|
||||
desc = "The nanites, when triggered, send a defibrillating shock to the host's heart."
|
||||
id = "defib_nanites"
|
||||
program_type = /datum/nanite_program/triggered/defib
|
||||
program_type = /datum/nanite_program/defib
|
||||
category = list("Medical Nanites")
|
||||
|
||||
|
||||
@@ -242,7 +248,7 @@
|
||||
name = "Adrenaline Burst"
|
||||
desc = "The nanites cause a burst of adrenaline when triggered, waking the host from stuns and temporarily increasing their speed."
|
||||
id = "adrenaline_nanites"
|
||||
program_type = /datum/nanite_program/triggered/adrenaline
|
||||
program_type = /datum/nanite_program/adrenaline
|
||||
category = list("Augmentation Nanites")
|
||||
|
||||
/datum/design/nanites/mindshield
|
||||
@@ -366,21 +372,21 @@
|
||||
name = "Heart-Stopper"
|
||||
desc = "Stops the host's heart when triggered; restarts it if triggered again."
|
||||
id = "heartstop_nanites"
|
||||
program_type = /datum/nanite_program/triggered/heart_stop
|
||||
program_type = /datum/nanite_program/heart_stop
|
||||
category = list("Weaponized Nanites")
|
||||
|
||||
/datum/design/nanites/explosive
|
||||
name = "Chain Detonation"
|
||||
desc = "Blows up all the nanites inside the host in a chain reaction when triggered."
|
||||
id = "explosive_nanites"
|
||||
program_type = /datum/nanite_program/triggered/explosive
|
||||
program_type = /datum/nanite_program/explosive
|
||||
category = list("Weaponized Nanites")
|
||||
|
||||
/datum/design/nanites/mind_control
|
||||
name = "Mind Control"
|
||||
desc = "The nanites imprint an absolute directive onto the host's brain while they're active."
|
||||
id = "mindcontrol_nanites"
|
||||
program_type = /datum/nanite_program/triggered/comm/mind_control
|
||||
program_type = /datum/nanite_program/comm/mind_control
|
||||
category = list("Weaponized Nanites")
|
||||
|
||||
////////////////////SUPPRESSION NANITES//////////////////////////////////////
|
||||
@@ -389,21 +395,21 @@
|
||||
name = "Electric Shock"
|
||||
desc = "The nanites shock the host when triggered. Destroys a large amount of nanites!"
|
||||
id = "shock_nanites"
|
||||
program_type = /datum/nanite_program/triggered/shocking
|
||||
program_type = /datum/nanite_program/shocking
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/stun
|
||||
name = "Neural Shock"
|
||||
desc = "The nanites pulse the host's nerves when triggered, inapacitating them for a short period."
|
||||
id = "stun_nanites"
|
||||
program_type = /datum/nanite_program/triggered/stun
|
||||
program_type = /datum/nanite_program/stun
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/sleepy
|
||||
name = "Sleep Induction"
|
||||
desc = "The nanites cause rapid narcolepsy when triggered."
|
||||
id = "sleep_nanites"
|
||||
program_type = /datum/nanite_program/triggered/sleepy
|
||||
program_type = /datum/nanite_program/sleepy
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/paralyzing
|
||||
@@ -445,21 +451,21 @@
|
||||
name = "Skull Echo"
|
||||
desc = "The nanites echo a synthesized message inside the host's skull."
|
||||
id = "voice_nanites"
|
||||
program_type = /datum/nanite_program/triggered/comm/voice
|
||||
program_type = /datum/nanite_program/comm/voice
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/speech
|
||||
name = "Forced Speech"
|
||||
desc = "The nanites force the host to say a pre-programmed sentence when triggered."
|
||||
id = "speech_nanites"
|
||||
program_type = /datum/nanite_program/triggered/comm/speech
|
||||
program_type = /datum/nanite_program/comm/speech
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/hallucination
|
||||
name = "Hallucination"
|
||||
desc = "The nanites make the host see and hear things that aren't real."
|
||||
id = "hallucination_nanites"
|
||||
program_type = /datum/nanite_program/triggered/comm/hallucination
|
||||
program_type = /datum/nanite_program/comm/hallucination
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/good_mood
|
||||
@@ -513,9 +519,42 @@
|
||||
program_type = /datum/nanite_program/sensor/voice
|
||||
category = list("Sensor Nanites")
|
||||
|
||||
/datum/design/nanites/sensor__nanite_volume
|
||||
/datum/design/nanites/sensor_nanite_volume
|
||||
name = "Nanite Volume Sensor"
|
||||
desc = "The nanites receive a signal when the nanite supply is above/below a certain percentage."
|
||||
id = "sensor_nanite_volume"
|
||||
program_type = /datum/nanite_program/sensor/nanite_volume
|
||||
category = list("Sensor Nanites")
|
||||
category = list("Sensor Nanites")
|
||||
|
||||
////////////////////NANITE PROTOCOLS//////////////////////////////////////
|
||||
//Note about the category name: The UI cuts the last 8 characters from the category name to remove the " Nanites" in the other categories
|
||||
//Because of this, Protocols was getting cut down to "P", so i had to add some padding
|
||||
/*
|
||||
/datum/design/nanites/kickstart
|
||||
name = "Kickstart Protocol"
|
||||
desc = "Replication Protocol: the nanites focus on early growth, heavily boosting replication rate for a few minutes after the initial implantation."
|
||||
id = "kickstart_nanites"
|
||||
program_type = /datum/nanite_program/protocol/kickstart
|
||||
category = list("Protocols_Nanites")
|
||||
|
||||
/datum/design/nanites/factory
|
||||
name = "Factory Protocol"
|
||||
desc = "Replication Protocol: the nanites build a factory matrix within the host, gradually increasing replication speed over time. The factory decays if the protocol is not active."
|
||||
id = "factory_nanites"
|
||||
program_type = /datum/nanite_program/protocol/factory
|
||||
category = list("Protocols_Nanites")
|
||||
|
||||
/datum/design/nanites/tinker
|
||||
name = "Tinker Protocol"
|
||||
desc = "Replication Protocol: the nanites learn to use metallic material in the host's bloodstream to speed up the replication process."
|
||||
id = "tinker_nanites"
|
||||
program_type = /datum/nanite_program/protocol/tinker
|
||||
category = list("Protocols_Nanites")
|
||||
|
||||
/datum/design/nanites/offline
|
||||
name = "Offline Production Protocol"
|
||||
desc = "Replication Protocol: while the host is asleep or otherwise unconcious, the nanites exploit the reduced interference to replicate more quickly."
|
||||
id = "offline_nanites"
|
||||
program_type = /datum/nanite_program/protocol/offline
|
||||
category = list("Protocols_Nanites")
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/datum/nanite_extra_setting
|
||||
var/setting_type
|
||||
var/value
|
||||
|
||||
/datum/nanite_extra_setting/proc/get_value()
|
||||
return value
|
||||
|
||||
/datum/nanite_extra_setting/proc/set_value(value)
|
||||
src.value = value
|
||||
|
||||
/datum/nanite_extra_setting/proc/get_copy()
|
||||
return
|
||||
|
||||
//I made the choice to send the name as part of the parameter instead of storing it directly on
|
||||
//this datum as a way of avoiding duplication of data between the containing assoc list
|
||||
//and this datum.
|
||||
//Also make sure to double wrap the list when implementing this as
|
||||
//+= is interpreted as a combine on lists, so the outer list gets unwrapped
|
||||
/datum/nanite_extra_setting/proc/get_frontend_list(name)
|
||||
return
|
||||
@@ -0,0 +1,27 @@
|
||||
/datum/nanite_extra_setting/boolean
|
||||
setting_type = NESTYPE_BOOLEAN
|
||||
var/true_text
|
||||
var/false_text
|
||||
|
||||
/datum/nanite_extra_setting/boolean/New(initial, true_text, false_text)
|
||||
value = initial
|
||||
src.true_text = true_text
|
||||
src.false_text = false_text
|
||||
|
||||
/datum/nanite_extra_setting/boolean/set_value(value)
|
||||
if(isnull(value))
|
||||
src.value = !src.value
|
||||
return
|
||||
. = ..()
|
||||
|
||||
/datum/nanite_extra_setting/boolean/get_copy()
|
||||
return new /datum/nanite_extra_setting/boolean(value, true_text, false_text)
|
||||
|
||||
/datum/nanite_extra_setting/boolean/get_frontend_list(name)
|
||||
return list(list(
|
||||
"name" = name,
|
||||
"type" = setting_type,
|
||||
"value" = value,
|
||||
"true_text" = true_text,
|
||||
"false_text" = false_text
|
||||
))
|
||||
@@ -0,0 +1,32 @@
|
||||
/datum/nanite_extra_setting/number
|
||||
setting_type = NESTYPE_NUMBER
|
||||
var/min
|
||||
var/max
|
||||
var/unit = ""
|
||||
|
||||
/datum/nanite_extra_setting/number/New(initial, min, max, unit)
|
||||
value = initial
|
||||
src.min = min
|
||||
src.max = max
|
||||
if(unit)
|
||||
src.unit = unit
|
||||
|
||||
/datum/nanite_extra_setting/number/set_value(value)
|
||||
if(istext(value))
|
||||
value = text2num(value)
|
||||
if(!value || !isnum(value))
|
||||
return
|
||||
src.value = CLAMP(value, min, max)
|
||||
|
||||
/datum/nanite_extra_setting/number/get_copy()
|
||||
return new /datum/nanite_extra_setting/number(value, min, max, unit)
|
||||
|
||||
/datum/nanite_extra_setting/number/get_frontend_list(name)
|
||||
return list(list(
|
||||
"name" = name,
|
||||
"type" = setting_type,
|
||||
"value" = value,
|
||||
"min" = min,
|
||||
"max" = max,
|
||||
"unit" = unit
|
||||
))
|
||||
@@ -0,0 +1,18 @@
|
||||
/datum/nanite_extra_setting/text
|
||||
setting_type = NESTYPE_TEXT
|
||||
|
||||
/datum/nanite_extra_setting/text/New(initial)
|
||||
value = initial
|
||||
|
||||
/datum/nanite_extra_setting/text/set_value(value)
|
||||
src.value = trim(value)
|
||||
|
||||
/datum/nanite_extra_setting/text/get_copy()
|
||||
return new /datum/nanite_extra_setting/text(value)
|
||||
|
||||
/datum/nanite_extra_setting/text/get_frontend_list(name)
|
||||
return list(list(
|
||||
"name" = name,
|
||||
"type" = setting_type,
|
||||
"value" = value
|
||||
))
|
||||
@@ -0,0 +1,18 @@
|
||||
/datum/nanite_extra_setting/type
|
||||
setting_type = NESTYPE_TYPE
|
||||
var/list/types
|
||||
|
||||
/datum/nanite_extra_setting/type/New(initial, types)
|
||||
value = initial
|
||||
src.types = types
|
||||
|
||||
/datum/nanite_extra_setting/type/get_copy()
|
||||
return new /datum/nanite_extra_setting/type(value, types)
|
||||
|
||||
/datum/nanite_extra_setting/type/get_frontend_list(name)
|
||||
return list(list(
|
||||
"name" = name,
|
||||
"type" = setting_type,
|
||||
"value" = value,
|
||||
"types" = types
|
||||
))
|
||||
@@ -77,7 +77,7 @@
|
||||
return
|
||||
occupant.AddComponent(/datum/component/nanites, 100)
|
||||
|
||||
/obj/machinery/nanite_chamber/proc/install_program(datum/nanite_program/NP)
|
||||
/obj/machinery/nanite_chamber/proc/remove_nanites(datum/nanite_program/NP)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if((stat & MAINT) || panel_open)
|
||||
@@ -88,74 +88,46 @@
|
||||
var/locked_state = locked
|
||||
locked = TRUE
|
||||
|
||||
//TODO COMPUTERY MACHINE SOUNDS
|
||||
set_busy(TRUE, "Initializing installation protocol...", "[initial(icon_state)]_raising")
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Connecting to nanite framework...", "[initial(icon_state)]_active"),20)
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Installing program...", "[initial(icon_state)]_falling"),35)
|
||||
addtimer(CALLBACK(src, .proc/complete_installation, locked_state, NP),55)
|
||||
//TODO OMINOUS MACHINE SOUNDS
|
||||
set_busy(TRUE, "Initializing cleanup protocol...", "[initial(icon_state)]_raising")
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Analyzing host bio-structure...", "[initial(icon_state)]_active"),20)
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Pinging nanites...", "[initial(icon_state)]_active"),40)
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Initiating graceful self-destruct sequence...", "[initial(icon_state)]_active"),70)
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Removing debris...", "[initial(icon_state)]_falling"),110)
|
||||
addtimer(CALLBACK(src, .proc/complete_removal, locked_state),130)
|
||||
|
||||
/obj/machinery/nanite_chamber/proc/complete_installation(locked_state, datum/nanite_program/NP)
|
||||
/obj/machinery/nanite_chamber/proc/complete_removal(locked_state)
|
||||
//TODO MACHINE DING
|
||||
locked = locked_state
|
||||
set_busy(FALSE)
|
||||
if(!occupant)
|
||||
return
|
||||
SEND_SIGNAL(occupant, COMSIG_NANITE_DELETE)
|
||||
|
||||
SEND_SIGNAL(occupant, COMSIG_NANITE_ADD_PROGRAM, NP.copy())
|
||||
|
||||
/obj/machinery/nanite_chamber/proc/uninstall_program(datum/nanite_program/NP)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if((stat & MAINT) || panel_open)
|
||||
return
|
||||
if(!occupant || busy)
|
||||
return
|
||||
|
||||
var/locked_state = locked
|
||||
locked = TRUE
|
||||
|
||||
//TODO COMPUTERY MACHINE SOUNDS
|
||||
set_busy(TRUE, "Initializing uninstallation protocol...", "[initial(icon_state)]_raising")
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Connecting to nanite framework...", "[initial(icon_state)]_active"),20)
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Uninstalling program...", "[initial(icon_state)]_falling"),35)
|
||||
addtimer(CALLBACK(src, .proc/complete_uninstallation, locked_state, NP),55)
|
||||
|
||||
/obj/machinery/nanite_chamber/proc/complete_uninstallation(locked_state, datum/nanite_program/NP)
|
||||
//TODO MACHINE DING
|
||||
locked = locked_state
|
||||
set_busy(FALSE)
|
||||
if(!occupant)
|
||||
return
|
||||
qdel(NP)
|
||||
|
||||
/obj/machinery/nanite_chamber/update_icon()
|
||||
cut_overlays()
|
||||
|
||||
if((stat & MAINT) || panel_open)
|
||||
add_overlay("maint")
|
||||
|
||||
else if(!(stat & (NOPOWER|BROKEN)))
|
||||
if(busy || locked)
|
||||
add_overlay("red")
|
||||
if(locked)
|
||||
add_overlay("bolted")
|
||||
else
|
||||
add_overlay("green")
|
||||
|
||||
/obj/machinery/nanite_chamber/update_icon_state()
|
||||
//running and someone in there
|
||||
if(occupant)
|
||||
if(busy)
|
||||
icon_state = busy_icon_state
|
||||
else
|
||||
icon_state = initial(icon_state)+ "_occupied"
|
||||
return
|
||||
icon_state = initial(icon_state) + "_occupied"
|
||||
else
|
||||
//running
|
||||
icon_state = initial(icon_state) + (state_open ? "_open" : "")
|
||||
|
||||
//running
|
||||
icon_state = initial(icon_state)+ (state_open ? "_open" : "")
|
||||
/obj/machinery/nanite_chamber/update_overlays()
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/nanite_chamber/power_change()
|
||||
..()
|
||||
update_icon()
|
||||
if((stat & MAINT) || panel_open)
|
||||
. += "maint"
|
||||
|
||||
else if(!(stat & (NOPOWER|BROKEN)))
|
||||
if(busy || locked)
|
||||
. += "red"
|
||||
if(locked)
|
||||
. += "bolted"
|
||||
else
|
||||
. += "green"
|
||||
|
||||
/obj/machinery/nanite_chamber/proc/toggle_open(mob/user)
|
||||
if(panel_open)
|
||||
@@ -182,7 +154,7 @@
|
||||
user.last_special = world.time + CLICK_CD_BREAKOUT
|
||||
user.visible_message("<span class='notice'>You see [user] kicking against the door of [src]!</span>", \
|
||||
"<span class='notice'>You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)</span>", \
|
||||
"<span class='italics'>You hear a metallic creaking from [src].</span>")
|
||||
"<span class='hear'>You hear a metallic creaking from [src].</span>")
|
||||
if(do_after(user,(breakout_time), target = src))
|
||||
if(!user || user.stat != CONSCIOUS || user.loc != src || state_open || !locked || busy)
|
||||
return
|
||||
@@ -231,6 +203,8 @@
|
||||
toggle_open(user)
|
||||
|
||||
/obj/machinery/nanite_chamber/MouseDrop_T(mob/target, mob/user)
|
||||
if(user.stat || user.lying || !Adjacent(user) || !user.Adjacent(target) || !iscarbon(target) || !user.IsAdvancedToolUser())
|
||||
if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK) || !Adjacent(target) || !user.Adjacent(target) || !iscarbon(target))
|
||||
return
|
||||
close_machine(target)
|
||||
if(close_machine(target))
|
||||
log_combat(user, target, "inserted", null, "into [src].")
|
||||
add_fingerprint(user)
|
||||
|
||||
@@ -5,30 +5,13 @@
|
||||
var/obj/item/disk/nanite_program/disk
|
||||
circuit = /obj/item/circuitboard/computer/nanite_chamber_control
|
||||
icon_screen = "nanite_chamber_control"
|
||||
ui_x = 380
|
||||
ui_y = 570
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/Initialize()
|
||||
. = ..()
|
||||
find_chamber()
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/attackby(obj/item/I, mob/user)
|
||||
if(istype(I, /obj/item/disk/nanite_program))
|
||||
var/obj/item/disk/nanite_program/N = I
|
||||
if(disk)
|
||||
eject(user)
|
||||
if(user.transferItemToLoc(N, src))
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src]</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
|
||||
disk = N
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/proc/eject(mob/living/user)
|
||||
if(!disk)
|
||||
return
|
||||
if(!istype(user) || !Adjacent(user) || !user.put_in_active_hand(disk))
|
||||
disk.forceMove(drop_location())
|
||||
disk = null
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/proc/find_chamber()
|
||||
for(var/direction in GLOB.cardinals)
|
||||
var/C = locate(/obj/machinery/nanite_chamber, get_step(src, direction))
|
||||
@@ -43,41 +26,13 @@
|
||||
..()
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "nanite_chamber_control", name, 550, 800, master_ui, state)
|
||||
ui = new(user, src, ui_key, "nanite_chamber_control", name, ui_x, ui_y, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/ui_data()
|
||||
var/list/data = list()
|
||||
if(disk)
|
||||
data["has_disk"] = TRUE
|
||||
var/list/disk_data = list()
|
||||
var/datum/nanite_program/P = disk.program
|
||||
if(P)
|
||||
data["has_program"] = TRUE
|
||||
disk_data["name"] = P.name
|
||||
disk_data["desc"] = P.desc
|
||||
|
||||
disk_data["activated"] = P.activated
|
||||
disk_data["activation_delay"] = P.activation_delay
|
||||
disk_data["timer"] = P.timer
|
||||
disk_data["activation_code"] = P.activation_code
|
||||
disk_data["deactivation_code"] = P.deactivation_code
|
||||
disk_data["kill_code"] = P.kill_code
|
||||
disk_data["trigger_code"] = P.trigger_code
|
||||
disk_data["timer_type"] = P.get_timer_type_text()
|
||||
|
||||
var/list/extra_settings = list()
|
||||
for(var/X in P.extra_settings)
|
||||
var/list/setting = list()
|
||||
setting["name"] = X
|
||||
setting["value"] = P.get_extra_setting(X)
|
||||
extra_settings += list(setting)
|
||||
disk_data["extra_settings"] = extra_settings
|
||||
if(LAZYLEN(extra_settings))
|
||||
disk_data["has_extra_settings"] = TRUE
|
||||
data["disk"] = disk_data
|
||||
|
||||
if(!chamber)
|
||||
data["status_msg"] = "No chamber detected."
|
||||
@@ -97,6 +52,7 @@
|
||||
data["status_msg"] = chamber.busy_message
|
||||
return data
|
||||
|
||||
data["status_msg"] = null
|
||||
data["scan_level"] = chamber.scan_level
|
||||
data["locked"] = chamber.locked
|
||||
data["occupant_name"] = chamber.occupant.name
|
||||
@@ -113,46 +69,32 @@
|
||||
chamber.locked = !chamber.locked
|
||||
chamber.update_icon()
|
||||
. = TRUE
|
||||
if("eject")
|
||||
eject(usr)
|
||||
. = TRUE
|
||||
if("set_safety")
|
||||
var/threshold = input("Set safety threshold (0-500):", name, null) as null|num
|
||||
var/threshold = text2num(params["value"])
|
||||
if(!isnull(threshold))
|
||||
chamber.set_safety(CLAMP(round(threshold, 1),0,500))
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
investigate_log("[key_name(chamber.occupant)]'s nanites' safety threshold was set to [threshold] by [key_name(usr)].", INVESTIGATE_NANITES)
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
chamber.occupant.investigate_log("'s nanites' safety threshold was set to [threshold] by [key_name(usr)] via [src] at [AREACOORD(src)].", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("set_cloud")
|
||||
var/cloud_id = input("Set cloud ID (1-100, 0 to disable):", name, null) as null|num
|
||||
var/cloud_id = text2num(params["value"])
|
||||
if(!isnull(cloud_id))
|
||||
chamber.set_cloud(CLAMP(round(cloud_id, 1),0,100))
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
investigate_log("[key_name(chamber.occupant)]'s nanites' cloud id was set to [cloud_id] by [key_name(usr)].", INVESTIGATE_NANITES)
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
chamber.occupant.investigate_log("'s nanites' cloud id was set to [cloud_id] by [key_name(usr)] via [src] at [AREACOORD(src)].", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("connect_chamber")
|
||||
find_chamber()
|
||||
. = TRUE
|
||||
if("remove_nanites")
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, FALSE)
|
||||
chamber.remove_nanites()
|
||||
log_combat(usr, chamber.occupant, "cleared nanites from", null, "via [src]")
|
||||
chamber.occupant.investigate_log("'s nanites were cleared by [key_name(usr)] via [src] at [AREACOORD(src)].", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("nanite_injection")
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, 0)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, FALSE)
|
||||
chamber.inject_nanites()
|
||||
investigate_log("[key_name(chamber.occupant)] was injected with nanites by [key_name(usr)] using a nanite chamber.", INVESTIGATE_NANITES)
|
||||
log_combat(usr, chamber.occupant, "injected", null, "with nanites via [src]")
|
||||
chamber.occupant.investigate_log("was injected with nanites by [key_name(usr)] via [src] at [AREACOORD(src)].", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("add_program")
|
||||
if(!disk || !chamber || !chamber.occupant)
|
||||
return
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, 0)
|
||||
chamber.install_program(disk.program)
|
||||
investigate_log("Program of type [disk.program.type] was installed into [key_name(chamber.occupant)]'s nanites with a nanite chamber by [key_name(usr)].", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("remove_program")
|
||||
if(!chamber || !chamber.occupant)
|
||||
return
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, 0)
|
||||
var/list/nanite_programs = list()
|
||||
SEND_SIGNAL(chamber.occupant, COMSIG_NANITE_GET_PROGRAMS, nanite_programs)
|
||||
if(LAZYLEN(nanite_programs))
|
||||
var/datum/nanite_program/P = nanite_programs[text2num(params["program_id"])]
|
||||
chamber.uninstall_program(P)
|
||||
investigate_log("Program of type [P.type] was uninstalled from [key_name(chamber.occupant)]'s nanites with a nanite chamber by [key_name(usr)].", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
@@ -4,9 +4,13 @@
|
||||
circuit = /obj/item/circuitboard/computer/nanite_cloud_controller
|
||||
icon = 'icons/obj/machines/research.dmi'
|
||||
icon_state = "nanite_cloud_controller"
|
||||
ui_x = 375
|
||||
ui_y = 700
|
||||
|
||||
var/obj/item/disk/nanite_program/disk
|
||||
var/list/datum/nanite_cloud_backup/cloud_backups = list()
|
||||
var/current_view = 0 //0 is the main menu, any other number is the page of the backup with that ID
|
||||
var/new_backup_id = 1
|
||||
|
||||
/obj/machinery/computer/nanite_cloud_controller/Destroy()
|
||||
QDEL_LIST(cloud_backups) //rip backups
|
||||
@@ -19,8 +23,8 @@
|
||||
if(disk)
|
||||
eject(user)
|
||||
if(user.transferItemToLoc(N, src))
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src]</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src].</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
|
||||
disk = N
|
||||
else
|
||||
..()
|
||||
@@ -50,13 +54,14 @@
|
||||
investigate_log("[key_name(user)] created a new nanite cloud backup with id #[cloud_id]", INVESTIGATE_NANITES)
|
||||
|
||||
/obj/machinery/computer/nanite_cloud_controller/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "nanite_cloud_control", name, 600, 800, master_ui, state)
|
||||
ui = new(user, src, ui_key, "nanite_cloud_control", name, ui_x, ui_y, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/nanite_cloud_controller/ui_data()
|
||||
var/list/data = list()
|
||||
|
||||
if(disk)
|
||||
data["has_disk"] = TRUE
|
||||
var/list/disk_data = list()
|
||||
@@ -71,24 +76,28 @@
|
||||
disk_data["trigger_cooldown"] = P.trigger_cooldown / 10
|
||||
|
||||
disk_data["activated"] = P.activated
|
||||
disk_data["activation_delay"] = P.activation_delay
|
||||
disk_data["timer"] = P.timer
|
||||
disk_data["activation_code"] = P.activation_code
|
||||
disk_data["deactivation_code"] = P.deactivation_code
|
||||
disk_data["kill_code"] = P.kill_code
|
||||
disk_data["trigger_code"] = P.trigger_code
|
||||
disk_data["timer_type"] = P.get_timer_type_text()
|
||||
disk_data["timer_restart"] = P.timer_restart / 10
|
||||
disk_data["timer_shutdown"] = P.timer_shutdown / 10
|
||||
disk_data["timer_trigger"] = P.timer_trigger / 10
|
||||
disk_data["timer_trigger_delay"] = P.timer_trigger_delay / 10
|
||||
|
||||
var/list/extra_settings = list()
|
||||
for(var/X in P.extra_settings)
|
||||
var/list/setting = list()
|
||||
setting["name"] = X
|
||||
setting["value"] = P.get_extra_setting(X)
|
||||
extra_settings += list(setting)
|
||||
var/list/extra_settings = P.get_extra_settings_frontend()
|
||||
disk_data["extra_settings"] = extra_settings
|
||||
if(LAZYLEN(extra_settings))
|
||||
disk_data["has_extra_settings"] = TRUE
|
||||
if(istype(P, /datum/nanite_program/sensor))
|
||||
var/datum/nanite_program/sensor/sensor = P
|
||||
if(sensor.can_rule)
|
||||
disk_data["can_rule"] = TRUE
|
||||
data["disk"] = disk_data
|
||||
else
|
||||
data["has_disk"] = FALSE
|
||||
|
||||
data["new_backup_id"] = new_backup_id
|
||||
|
||||
data["current_view"] = current_view
|
||||
if(current_view)
|
||||
@@ -108,19 +117,30 @@
|
||||
cloud_program["trigger_cost"] = P.trigger_cost
|
||||
cloud_program["trigger_cooldown"] = P.trigger_cooldown / 10
|
||||
cloud_program["activated"] = P.activated
|
||||
cloud_program["activation_delay"] = P.activation_delay
|
||||
cloud_program["timer"] = P.timer
|
||||
cloud_program["timer_type"] = P.get_timer_type_text()
|
||||
cloud_program["timer_restart"] = P.timer_restart / 10
|
||||
cloud_program["timer_shutdown"] = P.timer_shutdown / 10
|
||||
cloud_program["timer_trigger"] = P.timer_trigger / 10
|
||||
cloud_program["timer_trigger_delay"] = P.timer_trigger_delay / 10
|
||||
|
||||
cloud_program["activation_code"] = P.activation_code
|
||||
cloud_program["deactivation_code"] = P.deactivation_code
|
||||
cloud_program["kill_code"] = P.kill_code
|
||||
cloud_program["trigger_code"] = P.trigger_code
|
||||
var/list/extra_settings = list()
|
||||
for(var/X in P.extra_settings)
|
||||
var/list/setting = list()
|
||||
setting["name"] = X
|
||||
setting["value"] = P.get_extra_setting(X)
|
||||
extra_settings += list(setting)
|
||||
var/list/rules = list()
|
||||
var/rule_id = 1
|
||||
for(var/X in P.rules)
|
||||
var/datum/nanite_rule/nanite_rule = X
|
||||
var/list/rule = list()
|
||||
rule["display"] = nanite_rule.display()
|
||||
rule["program_id"] = id
|
||||
rule["id"] = rule_id
|
||||
rules += list(rule)
|
||||
rule_id++
|
||||
cloud_program["rules"] = rules
|
||||
if(LAZYLEN(rules))
|
||||
cloud_program["has_rules"] = TRUE
|
||||
|
||||
var/list/extra_settings = P.get_extra_settings_frontend()
|
||||
cloud_program["extra_settings"] = extra_settings
|
||||
if(LAZYLEN(extra_settings))
|
||||
cloud_program["has_extra_settings"] = TRUE
|
||||
@@ -147,17 +167,20 @@
|
||||
if("set_view")
|
||||
current_view = text2num(params["view"])
|
||||
. = TRUE
|
||||
if("update_new_backup_value")
|
||||
var/backup_value = text2num(params["value"])
|
||||
new_backup_id = backup_value
|
||||
if("create_backup")
|
||||
var/cloud_id = input("Choose a cloud ID (1-100):", name, null) as null|num
|
||||
var/cloud_id = new_backup_id
|
||||
if(!isnull(cloud_id))
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE)
|
||||
cloud_id = CLAMP(round(cloud_id, 1),1,100)
|
||||
generate_backup(cloud_id, usr)
|
||||
. = TRUE
|
||||
if("delete_backup")
|
||||
var/datum/nanite_cloud_backup/backup = get_backup(current_view)
|
||||
if(backup)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE)
|
||||
qdel(backup)
|
||||
investigate_log("[key_name(usr)] deleted the nanite cloud backup #[current_view]", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
@@ -165,7 +188,7 @@
|
||||
if(disk && disk.program)
|
||||
var/datum/nanite_cloud_backup/backup = get_backup(current_view)
|
||||
if(backup)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE)
|
||||
var/datum/component/nanites/nanites = backup.nanites
|
||||
nanites.add_program(null, disk.program.copy())
|
||||
investigate_log("[key_name(usr)] uploaded program [disk.program.name] to cloud #[current_view]", INVESTIGATE_NANITES)
|
||||
@@ -173,12 +196,37 @@
|
||||
if("remove_program")
|
||||
var/datum/nanite_cloud_backup/backup = get_backup(current_view)
|
||||
if(backup)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE)
|
||||
var/datum/component/nanites/nanites = backup.nanites
|
||||
var/datum/nanite_program/P = nanites.programs[text2num(params["program_id"])]
|
||||
investigate_log("[key_name(usr)] deleted program [P.name] from cloud #[current_view]", INVESTIGATE_NANITES)
|
||||
qdel(P)
|
||||
. = TRUE
|
||||
if("add_rule")
|
||||
if(disk && disk.program && istype(disk.program, /datum/nanite_program/sensor))
|
||||
var/datum/nanite_program/sensor/rule_template = disk.program
|
||||
if(!rule_template.can_rule)
|
||||
return
|
||||
var/datum/nanite_cloud_backup/backup = get_backup(current_view)
|
||||
if(backup)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
var/datum/component/nanites/nanites = backup.nanites
|
||||
var/datum/nanite_program/P = nanites.programs[text2num(params["program_id"])]
|
||||
var/datum/nanite_rule/rule = rule_template.make_rule(P)
|
||||
|
||||
investigate_log("[key_name(usr)] added rule [rule.display()] to program [P.name] in cloud #[current_view]", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("remove_rule")
|
||||
var/datum/nanite_cloud_backup/backup = get_backup(current_view)
|
||||
if(backup)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
var/datum/component/nanites/nanites = backup.nanites
|
||||
var/datum/nanite_program/P = nanites.programs[text2num(params["program_id"])]
|
||||
var/datum/nanite_rule/rule = P.rules[text2num(params["rule_id"])]
|
||||
rule.remove()
|
||||
|
||||
investigate_log("[key_name(usr)] removed rule [rule.display()] from program [P.name] in cloud #[current_view]", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
|
||||
/datum/nanite_cloud_backup
|
||||
var/cloud_id = 0
|
||||
@@ -193,4 +241,4 @@
|
||||
/datum/nanite_cloud_backup/Destroy()
|
||||
storage.cloud_backups -= src
|
||||
SSnanites.cloud_backups -= src
|
||||
return ..()
|
||||
return ..()
|
||||
|
||||
@@ -1,157 +0,0 @@
|
||||
/obj/item/nanite_hijacker
|
||||
name = "nanite remote control" //fake name
|
||||
desc = "A device that can load nanite programming disks, edit them at will, and imprint them to nanites remotely."
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "nanite_remote"
|
||||
item_flags = NOBLUDGEON
|
||||
var/obj/item/disk/nanite_program/disk
|
||||
var/datum/nanite_program/program
|
||||
|
||||
/obj/item/nanite_hijacker/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(!user.canUseTopic(src, BE_CLOSE))
|
||||
return
|
||||
if(disk)
|
||||
eject()
|
||||
return TRUE
|
||||
|
||||
/obj/item/nanite_hijacker/examine(mob/user)
|
||||
. = ..()
|
||||
if(disk)
|
||||
. += "<span class='notice'>Alt-click [src] to eject the disk.</span>"
|
||||
|
||||
/obj/item/nanite_hijacker/attackby(obj/item/I, mob/user)
|
||||
if(istype(I, /obj/item/disk/nanite_program))
|
||||
var/obj/item/disk/nanite_program/N = I
|
||||
if(disk)
|
||||
eject()
|
||||
if(user.transferItemToLoc(N, src))
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src]</span>")
|
||||
disk = N
|
||||
program = N.program
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/nanite_hijacker/proc/eject(mob/living/user)
|
||||
if(!disk)
|
||||
return
|
||||
if(!istype(user) || !Adjacent(user) || !user.put_in_hand(disk))
|
||||
disk.forceMove(drop_location())
|
||||
disk = null
|
||||
program = null
|
||||
|
||||
/obj/item/nanite_hijacker/afterattack(atom/target, mob/user, etc)
|
||||
if(!disk || !disk.program)
|
||||
return
|
||||
if(isliving(target))
|
||||
var/success = SEND_SIGNAL(target, COMSIG_NANITE_ADD_PROGRAM, program.copy())
|
||||
switch(success)
|
||||
if(NONE)
|
||||
to_chat(user, "<span class='notice'>You don't detect any nanites in [target].</span>")
|
||||
if(COMPONENT_PROGRAM_INSTALLED)
|
||||
to_chat(user, "<span class='notice'>You insert the currently loaded program into [target]'s nanites.</span>")
|
||||
if(COMPONENT_PROGRAM_NOT_INSTALLED)
|
||||
to_chat(user, "<span class='warning'>You try to insert the currently loaded program into [target]'s nanites, but the installation fails.</span>")
|
||||
|
||||
//Same UI as the nanite programmer, as it pretty much does the same
|
||||
/obj/item/nanite_hijacker/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
|
||||
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "nanite_programmer", "Internal Nanite Programmer", 420, 800, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/item/nanite_hijacker/ui_data()
|
||||
var/list/data = list()
|
||||
data["has_disk"] = istype(disk)
|
||||
data["has_program"] = istype(program)
|
||||
if(program)
|
||||
data["name"] = program.name
|
||||
data["desc"] = program.desc
|
||||
data["use_rate"] = program.use_rate
|
||||
data["can_trigger"] = program.can_trigger
|
||||
data["trigger_cost"] = program.trigger_cost
|
||||
data["trigger_cooldown"] = program.trigger_cooldown / 10
|
||||
|
||||
data["activated"] = program.activated
|
||||
data["activation_delay"] = program.activation_delay
|
||||
data["timer"] = program.timer
|
||||
data["activation_code"] = program.activation_code
|
||||
data["deactivation_code"] = program.deactivation_code
|
||||
data["kill_code"] = program.kill_code
|
||||
data["trigger_code"] = program.trigger_code
|
||||
data["timer_type"] = program.get_timer_type_text()
|
||||
|
||||
var/list/extra_settings = list()
|
||||
for(var/X in program.extra_settings)
|
||||
var/list/setting = list()
|
||||
setting["name"] = X
|
||||
setting["value"] = program.get_extra_setting(X)
|
||||
extra_settings += list(setting)
|
||||
data["extra_settings"] = extra_settings
|
||||
if(LAZYLEN(extra_settings))
|
||||
data["has_extra_settings"] = TRUE
|
||||
|
||||
return data
|
||||
|
||||
/obj/item/nanite_hijacker/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("eject")
|
||||
eject(usr)
|
||||
. = TRUE
|
||||
if("toggle_active")
|
||||
program.activated = !program.activated //we don't use the activation procs since we aren't in a mob
|
||||
if(program.activated)
|
||||
program.activation_delay = 0
|
||||
. = TRUE
|
||||
if("set_code")
|
||||
var/new_code = input("Set code (0000-9999):", name, null) as null|num
|
||||
if(!isnull(new_code))
|
||||
new_code = CLAMP(round(new_code, 1),0,9999)
|
||||
else
|
||||
return
|
||||
|
||||
var/target_code = params["target_code"]
|
||||
switch(target_code)
|
||||
if("activation")
|
||||
program.activation_code = CLAMP(round(new_code, 1),0,9999)
|
||||
if("deactivation")
|
||||
program.deactivation_code = CLAMP(round(new_code, 1),0,9999)
|
||||
if("kill")
|
||||
program.kill_code = CLAMP(round(new_code, 1),0,9999)
|
||||
if("trigger")
|
||||
program.trigger_code = CLAMP(round(new_code, 1),0,9999)
|
||||
. = TRUE
|
||||
if("set_extra_setting")
|
||||
program.set_extra_setting(usr, params["target_setting"])
|
||||
. = TRUE
|
||||
if("set_activation_delay")
|
||||
var/delay = input("Set activation delay in seconds (0-1800):", name, program.activation_delay) as null|num
|
||||
if(!isnull(delay))
|
||||
delay = CLAMP(round(delay, 1),0,1800)
|
||||
program.activation_delay = delay
|
||||
if(delay)
|
||||
program.activated = FALSE
|
||||
. = TRUE
|
||||
if("set_timer")
|
||||
var/timer = input("Set timer in seconds (10-3600):", name, program.timer) as null|num
|
||||
if(!isnull(timer))
|
||||
if(!timer == 0)
|
||||
timer = CLAMP(round(timer, 1),10,3600)
|
||||
program.timer = timer
|
||||
. = TRUE
|
||||
if("set_timer_type")
|
||||
var/new_type = input("Choose the timer effect","Timer Effect") as null|anything in list("Deactivate","Self-Delete","Trigger","Reset Activation Timer")
|
||||
if(new_type)
|
||||
switch(new_type)
|
||||
if("Deactivate")
|
||||
program.timer_type = NANITE_TIMER_DEACTIVATE
|
||||
if("Self-Delete")
|
||||
program.timer_type = NANITE_TIMER_SELFDELETE
|
||||
if("Trigger")
|
||||
program.timer_type = NANITE_TIMER_TRIGGER
|
||||
if("Reset Activation Timer")
|
||||
program.timer_type = NANITE_TIMER_RESET
|
||||
. = TRUE
|
||||
@@ -6,4 +6,4 @@
|
||||
icon_state = "nanite_remote"
|
||||
|
||||
/obj/item/nanite_injector/attack_self(mob/user)
|
||||
user.AddComponent(/datum/component/nanites, 150)
|
||||
user.AddComponent(/datum/component/nanites, 150)
|
||||
|
||||
@@ -7,18 +7,21 @@
|
||||
use_power = IDLE_POWER_USE
|
||||
anchored = TRUE
|
||||
density = TRUE
|
||||
ui_x = 500
|
||||
ui_y = 700
|
||||
|
||||
var/obj/item/disk/nanite_program/disk
|
||||
var/datum/techweb/linked_techweb
|
||||
var/current_category = "Main"
|
||||
var/detail_view = FALSE
|
||||
var/detail_view = TRUE
|
||||
var/categories = list(
|
||||
list(name = "Utility Nanites"),
|
||||
list(name = "Medical Nanites"),
|
||||
list(name = "Sensor Nanites"),
|
||||
list(name = "Augmentation Nanites"),
|
||||
list(name = "Suppression Nanites"),
|
||||
list(name = "Weaponized Nanites")
|
||||
list(name = "Weaponized Nanites"),
|
||||
//list(name = "Protocols") B.E.P.I.S Content, which we dont have
|
||||
)
|
||||
|
||||
/obj/machinery/nanite_program_hub/Initialize()
|
||||
@@ -31,8 +34,8 @@
|
||||
if(disk)
|
||||
eject(user)
|
||||
if(user.transferItemToLoc(N, src))
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src]</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src].</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
|
||||
disk = N
|
||||
else
|
||||
..()
|
||||
@@ -45,10 +48,9 @@
|
||||
disk = null
|
||||
|
||||
/obj/machinery/nanite_program_hub/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "nanite_program_hub", name, 500, 700, master_ui, state)
|
||||
ui.set_autoupdate(FALSE) //to avoid making the whole program list every second
|
||||
ui = new(user, src, ui_key, "nanite_program_hub", name, ui_x, ui_y, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/nanite_program_hub/ui_data()
|
||||
@@ -62,25 +64,31 @@
|
||||
disk_data["name"] = P.name
|
||||
disk_data["desc"] = P.desc
|
||||
data["disk"] = disk_data
|
||||
else
|
||||
data["has_disk"] = FALSE
|
||||
|
||||
data["detail_view"] = detail_view
|
||||
data["category"] = current_category
|
||||
|
||||
if(current_category != "Main")
|
||||
var/list/program_list = list()
|
||||
for(var/i in linked_techweb.researched_designs)
|
||||
var/datum/design/nanites/D = SSresearch.techweb_design_by_id(i)
|
||||
if(!istype(D))
|
||||
continue
|
||||
if(current_category in D.category)
|
||||
var/list/program_design = list()
|
||||
program_design["id"] = D.id
|
||||
program_design["name"] = D.name
|
||||
program_design["desc"] = D.desc
|
||||
program_list += list(program_design)
|
||||
data["program_list"] = program_list
|
||||
else
|
||||
data["categories"] = categories
|
||||
return data
|
||||
|
||||
/obj/machinery/nanite_program_hub/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["programs"] = list()
|
||||
for(var/i in linked_techweb.researched_designs)
|
||||
var/datum/design/nanites/D = SSresearch.techweb_design_by_id(i)
|
||||
if(!istype(D))
|
||||
continue
|
||||
var/cat_name = D.category[1] //just put them in the first category fuck it
|
||||
if(isnull(data["programs"][cat_name]))
|
||||
data["programs"][cat_name] = list()
|
||||
var/list/program_design = list()
|
||||
program_design["id"] = D.id
|
||||
program_design["name"] = D.name
|
||||
program_design["desc"] = D.desc
|
||||
data["programs"][cat_name] += list(program_design)
|
||||
|
||||
if(!length(data["programs"]))
|
||||
data["programs"] = null
|
||||
|
||||
return data
|
||||
|
||||
@@ -101,11 +109,10 @@
|
||||
qdel(disk.program)
|
||||
disk.program = new downloaded.program_type
|
||||
disk.name = "[initial(disk.name)] \[[disk.program.name]\]"
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, 0)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, FALSE)
|
||||
. = TRUE
|
||||
if("set_category")
|
||||
var/new_category = params["category"]
|
||||
current_category = new_category
|
||||
if("refresh")
|
||||
update_static_data(usr)
|
||||
. = TRUE
|
||||
if("toggle_details")
|
||||
detail_view = !detail_view
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
use_power = IDLE_POWER_USE
|
||||
anchored = TRUE
|
||||
density = TRUE
|
||||
flags_1 = HEAR_1
|
||||
ui_x = 420
|
||||
ui_y = 550
|
||||
|
||||
/obj/machinery/nanite_programmer/attackby(obj/item/I, mob/user)
|
||||
if(istype(I, /obj/item/disk/nanite_program))
|
||||
@@ -17,7 +20,7 @@
|
||||
eject(user)
|
||||
if(user.transferItemToLoc(N, src))
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src]</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
|
||||
disk = N
|
||||
program = N.program
|
||||
else
|
||||
@@ -32,9 +35,9 @@
|
||||
program = null
|
||||
|
||||
/obj/machinery/nanite_programmer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "nanite_programmer", name, 600, 800, master_ui, state)
|
||||
ui = new(user, src, ui_key, "nanite_programmer", name, ui_x, ui_y, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/nanite_programmer/ui_data()
|
||||
@@ -50,20 +53,16 @@
|
||||
data["trigger_cooldown"] = program.trigger_cooldown / 10
|
||||
|
||||
data["activated"] = program.activated
|
||||
data["activation_delay"] = program.activation_delay
|
||||
data["timer"] = program.timer
|
||||
data["activation_code"] = program.activation_code
|
||||
data["deactivation_code"] = program.deactivation_code
|
||||
data["kill_code"] = program.kill_code
|
||||
data["trigger_code"] = program.trigger_code
|
||||
data["timer_type"] = program.get_timer_type_text()
|
||||
data["timer_restart"] = program.timer_restart / 10
|
||||
data["timer_shutdown"] = program.timer_shutdown / 10
|
||||
data["timer_trigger"] = program.timer_trigger / 10
|
||||
data["timer_trigger_delay"] = program.timer_trigger_delay / 10
|
||||
|
||||
var/list/extra_settings = list()
|
||||
for(var/X in program.extra_settings)
|
||||
var/list/setting = list()
|
||||
setting["name"] = X
|
||||
setting["value"] = program.get_extra_setting(X)
|
||||
extra_settings += list(setting)
|
||||
var/list/extra_settings = program.get_extra_settings_frontend()
|
||||
data["extra_settings"] = extra_settings
|
||||
if(LAZYLEN(extra_settings))
|
||||
data["has_extra_settings"] = TRUE
|
||||
@@ -78,20 +77,12 @@
|
||||
eject(usr)
|
||||
. = TRUE
|
||||
if("toggle_active")
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
program.activated = !program.activated //we don't use the activation procs since we aren't in a mob
|
||||
if(program.activated)
|
||||
program.activation_delay = 0
|
||||
. = TRUE
|
||||
if("set_code")
|
||||
var/new_code = input("Set code (0000-9999):", name, null) as null|num
|
||||
if(!isnull(new_code))
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
new_code = CLAMP(round(new_code, 1),0,9999)
|
||||
else
|
||||
return
|
||||
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
var/new_code = text2num(params["code"])
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
var/target_code = params["target_code"]
|
||||
switch(target_code)
|
||||
if("activation")
|
||||
@@ -104,37 +95,44 @@
|
||||
program.trigger_code = CLAMP(round(new_code, 1),0,9999)
|
||||
. = TRUE
|
||||
if("set_extra_setting")
|
||||
program.set_extra_setting(usr, params["target_setting"])
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
program.set_extra_setting(params["target_setting"], params["value"])
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
. = TRUE
|
||||
if("set_activation_delay")
|
||||
var/delay = input("Set activation delay in seconds (0-1800):", name, program.activation_delay) as null|num
|
||||
if(!isnull(delay))
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
delay = CLAMP(round(delay, 1),0,1800)
|
||||
program.activation_delay = delay
|
||||
if(delay)
|
||||
program.activated = FALSE
|
||||
. = TRUE
|
||||
if("set_timer")
|
||||
var/timer = input("Set timer in seconds (10-3600):", name, program.timer) as null|num
|
||||
if("set_restart_timer")
|
||||
var/timer = text2num(params["delay"])
|
||||
if(!isnull(timer))
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
if(!timer == 0)
|
||||
timer = CLAMP(round(timer, 1),10,3600)
|
||||
program.timer = timer
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
timer = CLAMP(round(timer, 1), 0, 3600)
|
||||
timer *= 10 //convert to deciseconds
|
||||
program.timer_restart = timer
|
||||
. = TRUE
|
||||
if("set_timer_type")
|
||||
var/new_type = input("Choose the timer effect","Timer Effect") as null|anything in list("Deactivate","Self-Delete","Trigger","Reset Activation Timer")
|
||||
if(new_type)
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
switch(new_type)
|
||||
if("Deactivate")
|
||||
program.timer_type = NANITE_TIMER_DEACTIVATE
|
||||
if("Self-Delete")
|
||||
program.timer_type = NANITE_TIMER_SELFDELETE
|
||||
if("Trigger")
|
||||
program.timer_type = NANITE_TIMER_TRIGGER
|
||||
if("Reset Activation Timer")
|
||||
program.timer_type = NANITE_TIMER_RESET
|
||||
. = TRUE
|
||||
if("set_shutdown_timer")
|
||||
var/timer = text2num(params["delay"])
|
||||
if(!isnull(timer))
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
timer = CLAMP(round(timer, 1), 0, 3600)
|
||||
timer *= 10 //convert to deciseconds
|
||||
program.timer_shutdown = timer
|
||||
. = TRUE
|
||||
if("set_trigger_timer")
|
||||
var/timer = text2num(params["delay"])
|
||||
if(!isnull(timer))
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
timer = CLAMP(round(timer, 1), 0, 3600)
|
||||
timer *= 10 //convert to deciseconds
|
||||
program.timer_trigger = timer
|
||||
. = TRUE
|
||||
if("set_timer_trigger_delay")
|
||||
var/timer = text2num(params["delay"])
|
||||
if(!isnull(timer))
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
timer = CLAMP(round(timer, 1), 0, 3600)
|
||||
timer *= 10 //convert to deciseconds
|
||||
program.timer_trigger_delay = timer
|
||||
. = TRUE
|
||||
|
||||
/obj/machinery/nanite_programmer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
|
||||
. = ..()
|
||||
var/static/regex/when = regex("(?:^\\W*when|when\\W*$)", "i") //starts or ends with when
|
||||
if(findtext(raw_message, when) && !istype(speaker, /obj/machinery/nanite_programmer))
|
||||
say("When you code it!!")
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
var/trigger_cost = 0 //Amount of nanites required to trigger
|
||||
var/trigger_cooldown = 50 //Deciseconds required between each trigger activation
|
||||
var/next_trigger = 0 //World time required for the next trigger activation
|
||||
var/timer_counter = 0 //Counts up while active. Used for the timer and the activation delay.
|
||||
|
||||
var/program_flags = NONE
|
||||
var/passive_enabled = FALSE //If the nanites have an on/off-style effect, it's tracked by this var
|
||||
|
||||
@@ -28,9 +28,17 @@
|
||||
|
||||
//The following vars are customizable
|
||||
var/activated = TRUE //If FALSE, the program won't process, disables passive effects, can't trigger and doesn't consume nanites
|
||||
var/activation_delay = 0 //Seconds before the program self-activates.
|
||||
var/timer = 0 //Seconds before the timer effect activates. Starts counting AFTER the activation delay
|
||||
var/timer_type = NANITE_TIMER_DEACTIVATE //What happens when the timer runs out
|
||||
|
||||
var/timer_restart = 0 //When deactivated, the program will wait X deciseconds before self-reactivating. Also works if the program begins deactivated.
|
||||
var/timer_shutdown = 0 //When activated, the program will wait X deciseconds before self-deactivating. Also works if the program begins activated.
|
||||
var/timer_trigger = 0 //[Trigger only] While active, the program will attempt to trigger once every x deciseconds.
|
||||
var/timer_trigger_delay = 0 //[Trigger only] While active, the program will delay trigger signals by X deciseconds.
|
||||
|
||||
//Indicates the next world.time tick where these timers will act
|
||||
var/timer_restart_next = 0
|
||||
var/timer_shutdown_next = 0
|
||||
var/timer_trigger_next = 0
|
||||
var/timer_trigger_delay_next = 0
|
||||
|
||||
//Signal codes, these handle remote input to the nanites. If set to 0 they'll ignore signals.
|
||||
var/activation_code = 0 //Code that activates the program [1-9999]
|
||||
@@ -39,19 +47,19 @@
|
||||
var/trigger_code = 0 //Code that triggers the program (if available) [1-9999]
|
||||
|
||||
//Extra settings
|
||||
//Must be listed in text form, with the same title they'll be displayed in the programmer UI
|
||||
//Changing these values is handled by set_extra_setting()
|
||||
//Viewing these values is handled by get_extra_setting()
|
||||
//Copying these values is handled by copy_extra_settings_to()
|
||||
///Don't ever override this or I will come to your house and stand menacingly behind a bush
|
||||
var/list/extra_settings = list()
|
||||
|
||||
/datum/nanite_program/triggered
|
||||
use_rate = 0
|
||||
trigger_cost = 5
|
||||
trigger_cooldown = 50
|
||||
can_trigger = TRUE
|
||||
//Rules
|
||||
//Rules that automatically manage if the program's active without requiring separate sensor programs
|
||||
var/list/datum/nanite_rule/rules = list()
|
||||
|
||||
/datum/nanite_program/New()
|
||||
. = ..()
|
||||
register_extra_settings()
|
||||
|
||||
/datum/nanite_program/Destroy()
|
||||
extra_settings = null
|
||||
if(host_mob)
|
||||
if(activated)
|
||||
deactivate()
|
||||
@@ -64,39 +72,60 @@
|
||||
|
||||
/datum/nanite_program/proc/copy()
|
||||
var/datum/nanite_program/new_program = new type()
|
||||
|
||||
new_program.activated = activated
|
||||
new_program.activation_delay = activation_delay
|
||||
new_program.timer = timer
|
||||
new_program.timer_type = timer_type
|
||||
new_program.activation_code = activation_code
|
||||
new_program.deactivation_code = deactivation_code
|
||||
new_program.kill_code = kill_code
|
||||
new_program.trigger_code = trigger_code
|
||||
copy_extra_settings_to(new_program)
|
||||
copy_programming(new_program, TRUE)
|
||||
|
||||
return new_program
|
||||
|
||||
/datum/nanite_program/proc/copy_programming(datum/nanite_program/target, copy_activated = TRUE)
|
||||
if(copy_activated)
|
||||
target.activated = activated
|
||||
target.activation_delay = activation_delay
|
||||
target.timer = timer
|
||||
target.timer_type = timer_type
|
||||
target.timer_restart = timer_restart
|
||||
target.timer_shutdown = timer_shutdown
|
||||
target.timer_trigger = timer_trigger
|
||||
target.timer_trigger_delay = timer_trigger_delay
|
||||
target.activation_code = activation_code
|
||||
target.deactivation_code = deactivation_code
|
||||
target.kill_code = kill_code
|
||||
target.trigger_code = trigger_code
|
||||
copy_extra_settings_to(target)
|
||||
|
||||
/datum/nanite_program/proc/set_extra_setting(user, setting)
|
||||
target.rules = list()
|
||||
for(var/R in rules)
|
||||
var/datum/nanite_rule/rule = R
|
||||
rule.copy_to(target)
|
||||
|
||||
if(istype(target,src))
|
||||
copy_extra_settings_to(target)
|
||||
|
||||
///Register extra settings by overriding this.
|
||||
///extra_settings[name] = new typepath() for each extra setting
|
||||
/datum/nanite_program/proc/register_extra_settings()
|
||||
return
|
||||
|
||||
/datum/nanite_program/proc/get_extra_setting(setting)
|
||||
return
|
||||
///You can override this if you need to have special behavior after setting certain settings.
|
||||
/datum/nanite_program/proc/set_extra_setting(setting, value)
|
||||
var/datum/nanite_extra_setting/ES = extra_settings[setting]
|
||||
return ES.set_value(value)
|
||||
|
||||
///You probably shouldn't be overriding this one, but I'm not a cop.
|
||||
/datum/nanite_program/proc/get_extra_setting_value(setting)
|
||||
var/datum/nanite_extra_setting/ES = extra_settings[setting]
|
||||
return ES.get_value()
|
||||
|
||||
///Used for getting information about the extra settings to the frontend
|
||||
/datum/nanite_program/proc/get_extra_settings_frontend()
|
||||
var/list/out = list()
|
||||
for(var/name in extra_settings)
|
||||
var/datum/nanite_extra_setting/ES = extra_settings[name]
|
||||
out += ES.get_frontend_list(name)
|
||||
return out
|
||||
|
||||
///Copy of the list instead of direct reference for obvious reasons
|
||||
/datum/nanite_program/proc/copy_extra_settings_to(datum/nanite_program/target)
|
||||
return
|
||||
var/list/copy_list = list()
|
||||
for(var/ns_name in extra_settings)
|
||||
var/datum/nanite_extra_setting/extra_setting = extra_settings[ns_name]
|
||||
copy_list[ns_name] = extra_setting.get_copy()
|
||||
target.extra_settings = copy_list
|
||||
|
||||
/datum/nanite_program/proc/on_add(datum/component/nanites/_nanites)
|
||||
nanites = _nanites
|
||||
@@ -105,10 +134,12 @@
|
||||
|
||||
/datum/nanite_program/proc/on_mob_add()
|
||||
host_mob = nanites.host_mob
|
||||
if(activated) //apply activation effects if it starts active
|
||||
if(activated) //apply activation effects depending on initial status; starts the restart and shutdown timers
|
||||
activate()
|
||||
else
|
||||
deactivate()
|
||||
|
||||
datum/nanite_program/proc/on_mob_remove()
|
||||
/datum/nanite_program/proc/on_mob_remove()
|
||||
return
|
||||
|
||||
/datum/nanite_program/proc/toggle()
|
||||
@@ -119,36 +150,35 @@ datum/nanite_program/proc/on_mob_remove()
|
||||
|
||||
/datum/nanite_program/proc/activate()
|
||||
activated = TRUE
|
||||
timer_counter = activation_delay
|
||||
if(timer_shutdown)
|
||||
timer_shutdown_next = world.time + timer_shutdown
|
||||
|
||||
/datum/nanite_program/proc/deactivate()
|
||||
if(passive_enabled)
|
||||
disable_passive_effect()
|
||||
activated = FALSE
|
||||
if(timer_restart)
|
||||
timer_restart_next = world.time + timer_restart
|
||||
|
||||
/datum/nanite_program/proc/on_process()
|
||||
timer_counter++
|
||||
|
||||
if(activation_delay)
|
||||
if(activated && timer_counter < activation_delay)
|
||||
deactivate()
|
||||
else if(!activated && timer_counter >= activation_delay)
|
||||
activate()
|
||||
if(!activated)
|
||||
if(timer_restart_next && world.time > timer_restart_next)
|
||||
activate()
|
||||
timer_restart_next = 0
|
||||
return
|
||||
|
||||
if(timer && timer_counter > timer)
|
||||
if(timer_type == NANITE_TIMER_DEACTIVATE)
|
||||
deactivate()
|
||||
return
|
||||
else if(timer_type == NANITE_TIMER_SELFDELETE)
|
||||
qdel(src)
|
||||
return
|
||||
else if(can_trigger && timer_type == NANITE_TIMER_TRIGGER)
|
||||
trigger()
|
||||
timer_counter = activation_delay
|
||||
else if(timer_type == NANITE_TIMER_RESET)
|
||||
timer_counter = 0
|
||||
if(timer_shutdown_next && world.time > timer_shutdown_next)
|
||||
deactivate()
|
||||
timer_shutdown_next = 0
|
||||
|
||||
if(timer_trigger && world.time > timer_trigger_next)
|
||||
trigger()
|
||||
timer_trigger_next = world.time + timer_trigger
|
||||
|
||||
if(timer_trigger_delay_next && world.time > timer_trigger_delay_next)
|
||||
trigger(delayed = TRUE)
|
||||
timer_trigger_delay_next = 0
|
||||
|
||||
if(check_conditions() && consume_nanites(use_rate))
|
||||
if(!passive_enabled)
|
||||
enable_passive_effect()
|
||||
@@ -160,6 +190,10 @@ datum/nanite_program/proc/on_mob_remove()
|
||||
//If false, disables active and passive effects, but doesn't consume nanites
|
||||
//Can be used to avoid consuming nanites for nothing
|
||||
/datum/nanite_program/proc/check_conditions()
|
||||
for(var/R in rules)
|
||||
var/datum/nanite_rule/rule = R
|
||||
if(!rule.check_rule())
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
//Constantly procs as long as the program is active
|
||||
@@ -174,15 +208,25 @@ datum/nanite_program/proc/on_mob_remove()
|
||||
/datum/nanite_program/proc/disable_passive_effect()
|
||||
passive_enabled = FALSE
|
||||
|
||||
/datum/nanite_program/proc/trigger()
|
||||
//Checks conditions then fires the nanite trigger effect
|
||||
/datum/nanite_program/proc/trigger(delayed = FALSE, comm_message)
|
||||
if(!can_trigger)
|
||||
return
|
||||
if(!activated)
|
||||
return FALSE
|
||||
return
|
||||
if(timer_trigger_delay && !delayed)
|
||||
timer_trigger_delay_next = world.time + timer_trigger_delay
|
||||
return
|
||||
if(world.time < next_trigger)
|
||||
return FALSE
|
||||
return
|
||||
if(!consume_nanites(trigger_cost))
|
||||
return FALSE
|
||||
return
|
||||
next_trigger = world.time + trigger_cooldown
|
||||
return TRUE
|
||||
on_trigger(comm_message)
|
||||
|
||||
//Nanite trigger effect, requires can_trigger to be used
|
||||
/datum/nanite_program/proc/on_trigger(comm_message)
|
||||
return
|
||||
|
||||
/datum/nanite_program/proc/consume_nanites(amount, force = FALSE)
|
||||
return nanites.consume_nanites(amount, force)
|
||||
@@ -234,24 +278,36 @@ datum/nanite_program/proc/on_mob_remove()
|
||||
/datum/nanite_program/proc/receive_signal(code, source)
|
||||
if(activation_code && code == activation_code && !activated)
|
||||
activate()
|
||||
host_mob.investigate_log("[host_mob]'s [name] nanite program was activated by [source] with code [code].", INVESTIGATE_NANITES)
|
||||
host_mob.investigate_log("'s [name] nanite program was activated by [source] with code [code].", INVESTIGATE_NANITES)
|
||||
else if(deactivation_code && code == deactivation_code && activated)
|
||||
deactivate()
|
||||
host_mob.investigate_log("[host_mob]'s [name] nanite program was deactivated by [source] with code [code].", INVESTIGATE_NANITES)
|
||||
if(kill_code && code == kill_code)
|
||||
host_mob.investigate_log("[host_mob]'s [name] nanite program was deleted by [source] with code [code].", INVESTIGATE_NANITES)
|
||||
qdel(src)
|
||||
else if(can_trigger && trigger_code && code == trigger_code)
|
||||
host_mob.investigate_log("'s [name] nanite program was deactivated by [source] with code [code].", INVESTIGATE_NANITES)
|
||||
if(can_trigger && trigger_code && code == trigger_code)
|
||||
trigger()
|
||||
host_mob.investigate_log("[host_mob]'s [name] nanite program was triggered by [source] with code [code].", INVESTIGATE_NANITES)
|
||||
host_mob.investigate_log("'s [name] nanite program was triggered by [source] with code [code].", INVESTIGATE_NANITES)
|
||||
if(kill_code && code == kill_code)
|
||||
host_mob.investigate_log("'s [name] nanite program was deleted by [source] with code [code].", INVESTIGATE_NANITES)
|
||||
qdel(src)
|
||||
|
||||
///A nanite program containing a behaviour protocol. Only one protocol of each class can be active at once.
|
||||
//Currently unused due to us lacking the B.E.P.I.S
|
||||
/datum/nanite_program/protocol
|
||||
name = "Nanite Protocol"
|
||||
var/protocol_class = NONE
|
||||
|
||||
/datum/nanite_program/protocol/check_conditions()
|
||||
. = ..()
|
||||
for(var/protocol in nanites.protocols)
|
||||
var/datum/nanite_program/protocol/P = protocol
|
||||
if(P != src && P.activated && P.protocol_class == protocol_class)
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_program/protocol/on_add(datum/component/nanites/_nanites)
|
||||
..()
|
||||
nanites.protocols += src
|
||||
|
||||
/datum/nanite_program/protocol/Destroy()
|
||||
if(nanites)
|
||||
nanites.protocols -= src
|
||||
return ..()
|
||||
|
||||
/datum/nanite_program/proc/get_timer_type_text()
|
||||
switch(timer_type)
|
||||
if(NANITE_TIMER_DEACTIVATE)
|
||||
return "Deactivate"
|
||||
if(NANITE_TIMER_SELFDELETE)
|
||||
return "Self-Delete"
|
||||
if(NANITE_TIMER_TRIGGER)
|
||||
return "Trigger"
|
||||
if(NANITE_TIMER_RESET)
|
||||
return "Reset Activation Timer"
|
||||
|
||||
@@ -18,23 +18,16 @@
|
||||
var/mob/living/carbon/human/H = host_mob
|
||||
H.physiology.stun_mod *= 2
|
||||
|
||||
/datum/nanite_program/triggered/adrenaline
|
||||
/datum/nanite_program/adrenaline
|
||||
name = "Adrenaline Burst"
|
||||
desc = "The nanites cause a burst of adrenaline when triggered, waking the host from stuns and temporarily increasing their speed."
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 25
|
||||
trigger_cooldown = 1200
|
||||
rogue_types = list(/datum/nanite_program/toxic, /datum/nanite_program/nerve_decay)
|
||||
|
||||
/datum/nanite_program/triggered/adrenaline/trigger()
|
||||
if(!..())
|
||||
return
|
||||
to_chat(host_mob, "<span class='notice'>You feel a sudden surge of energy!</span>")
|
||||
host_mob.SetAllImmobility(0, FALSE)
|
||||
host_mob.SetUnconscious(0, FALSE)
|
||||
host_mob.adjustStaminaLoss(-10) //stimulants give stamina heal now
|
||||
host_mob.set_resting(FALSE, TRUE, FALSE)
|
||||
host_mob.update_mobility()
|
||||
host_mob.reagents.add_reagent(/datum/reagent/medicine/stimulants, 1.5)
|
||||
/datum/nanite_program/adrenaline/on_trigger()
|
||||
host_mob.do_adrenaline(-10, TRUE, TRUE, FALSE, TRUE, list(/datum/reagent/medicine/stimulants = 1.5), "<span class='notice'>You feel a sudden surge of energy!</span>", FALSE, FALSE, FALSE)
|
||||
|
||||
/datum/nanite_program/hardening
|
||||
name = "Dermal Hardening"
|
||||
@@ -119,7 +112,7 @@
|
||||
|
||||
/datum/nanite_program/mindshield/enable_passive_effect()
|
||||
. = ..()
|
||||
if(!host_mob.mind.has_antag_datum(/datum/antagonist/rev)) //won't work if on a rev, to avoid having implanted revs
|
||||
if(!host_mob.mind.has_antag_datum(/datum/antagonist/rev, TRUE)) //won't work if on a rev, to avoid having implanted revs.
|
||||
ADD_TRAIT(host_mob, TRAIT_MINDSHIELD, "nanites")
|
||||
host_mob.sec_hud_set_implants()
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
if(!parts.len)
|
||||
return
|
||||
for(var/obj/item/bodypart/L in parts)
|
||||
if(L.heal_damage(0.5/parts.len, 0.5/parts.len, null, BODYPART_ORGANIC))
|
||||
if(L.heal_damage(0.5/parts.len, 0.5/parts.len))
|
||||
host_mob.update_damage_overlays()
|
||||
else
|
||||
host_mob.adjustBruteLoss(-0.5, TRUE)
|
||||
@@ -48,12 +48,12 @@
|
||||
|
||||
/datum/nanite_program/purging
|
||||
name = "Blood Purification"
|
||||
desc = "The nanites purge toxins and chemicals from the host's bloodstream, however it is dangerous to slimepeople biology due to inaccuracy."
|
||||
desc = "The nanites purge toxins and chemicals from the host's bloodstream, however it is dangerous to slime biology due to inaccuracy."
|
||||
use_rate = 1
|
||||
rogue_types = list(/datum/nanite_program/suffocating, /datum/nanite_program/necrotic)
|
||||
|
||||
/datum/nanite_program/purging/check_conditions()
|
||||
var/foreign_reagent = LAZYLEN(host_mob.reagents.reagent_list)
|
||||
var/foreign_reagent = length(host_mob.reagents?.reagent_list)
|
||||
if(!host_mob.getToxLoss() && !foreign_reagent)
|
||||
return FALSE
|
||||
return ..()
|
||||
@@ -73,18 +73,17 @@
|
||||
rogue_types = list(/datum/nanite_program/brain_decay)
|
||||
|
||||
/datum/nanite_program/brain_heal/check_conditions()
|
||||
var/problems = FALSE
|
||||
if(iscarbon(host_mob))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
for(var/X in C.get_traumas())
|
||||
var/datum/brain_trauma/BT = X
|
||||
if(BT.resilience <= TRAUMA_RESILIENCE_BASIC)
|
||||
return ..()
|
||||
if(host_mob.getOrganLoss(ORGAN_SLOT_BRAIN))
|
||||
return ..()
|
||||
return FALSE
|
||||
if(length(C.get_traumas()))
|
||||
problems = TRUE
|
||||
if(host_mob.getOrganLoss(ORGAN_SLOT_BRAIN) > 0)
|
||||
problems = TRUE
|
||||
return problems ? ..() : FALSE
|
||||
|
||||
/datum/nanite_program/brain_heal/active_effect()
|
||||
host_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, -1, TRUE)
|
||||
host_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, -1)
|
||||
if(iscarbon(host_mob) && prob(10))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
C.cure_trauma_type(resilience = TRAUMA_RESILIENCE_BASIC)
|
||||
@@ -137,7 +136,7 @@
|
||||
return
|
||||
var/update = FALSE
|
||||
for(var/obj/item/bodypart/L in parts)
|
||||
if(L.heal_damage(1.5/parts.len, 1.5/parts.len, null, BODYPART_ROBOTIC)) //much faster than organic healing
|
||||
if(L.heal_damage(1.5/parts.len, 1.5/parts.len, null, TRUE, FALSE)) //much faster than organic healing
|
||||
update = TRUE
|
||||
if(update)
|
||||
host_mob.update_damage_overlays()
|
||||
@@ -148,7 +147,7 @@
|
||||
/datum/nanite_program/purging_advanced
|
||||
name = "Selective Blood Purification"
|
||||
desc = "The nanites purge toxins and dangerous chemicals from the host's bloodstream, while ignoring beneficial chemicals. \
|
||||
The added processing power required to analyze the chemicals severely increases the nanite consumption rate. Due to added complexity, it is safe with slimepeople biology."
|
||||
The added processing power required to analyze the chemicals severely increases the nanite consumption rate. This program is safe with slime biology due to the increased precision."
|
||||
use_rate = 2
|
||||
rogue_types = list(/datum/nanite_program/suffocating, /datum/nanite_program/necrotic)
|
||||
|
||||
@@ -181,7 +180,7 @@
|
||||
return
|
||||
var/update = FALSE
|
||||
for(var/obj/item/bodypart/L in parts)
|
||||
if(L.heal_damage(3/parts.len, 3/parts.len))
|
||||
if(L.heal_damage(3/parts.len, 3/parts.len, FALSE))
|
||||
update = TRUE
|
||||
if(update)
|
||||
host_mob.update_damage_overlays()
|
||||
@@ -196,70 +195,54 @@
|
||||
rogue_types = list(/datum/nanite_program/brain_decay, /datum/nanite_program/brain_misfire)
|
||||
|
||||
/datum/nanite_program/brain_heal_advanced/check_conditions()
|
||||
var/problems = FALSE
|
||||
if(iscarbon(host_mob))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
for(var/X in C.get_traumas())
|
||||
var/datum/brain_trauma/BT = X
|
||||
if(BT.resilience <= TRAUMA_RESILIENCE_LOBOTOMY)
|
||||
return ..()
|
||||
if(host_mob.getOrganLoss(ORGAN_SLOT_BRAIN))
|
||||
return ..()
|
||||
return FALSE
|
||||
if(length(C.get_traumas()))
|
||||
problems = TRUE
|
||||
if(host_mob.getOrganLoss(ORGAN_SLOT_BRAIN) > 0)
|
||||
problems = TRUE
|
||||
return problems ? ..() : FALSE
|
||||
|
||||
/datum/nanite_program/brain_heal_advanced/active_effect()
|
||||
host_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, -2, TRUE)
|
||||
host_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, -2)
|
||||
if(iscarbon(host_mob) && prob(10))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
C.cure_trauma_type(resilience = TRAUMA_RESILIENCE_LOBOTOMY)
|
||||
|
||||
/datum/nanite_program/triggered/defib
|
||||
/datum/nanite_program/defib
|
||||
name = "Defibrillation"
|
||||
desc = "The nanites shock the host's heart when triggered, bringing them back to life if the body can sustain it."
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 25
|
||||
trigger_cooldown = 120
|
||||
rogue_types = list(/datum/nanite_program/triggered/shocking)
|
||||
|
||||
/datum/nanite_program/triggered/defib/trigger()
|
||||
if(!..())
|
||||
return
|
||||
rogue_types = list(/datum/nanite_program/shocking)
|
||||
|
||||
/datum/nanite_program/defib/on_trigger(comm_message)
|
||||
host_mob.notify_ghost_cloning("Your heart is being defibrillated by nanites. Re-enter your corpse if you want to be revived!")
|
||||
addtimer(CALLBACK(src, .proc/zap), 50)
|
||||
|
||||
/datum/nanite_program/triggered/defib/proc/check_revivable()
|
||||
/datum/nanite_program/defib/proc/check_revivable()
|
||||
if(!iscarbon(host_mob)) //nonstandard biology
|
||||
return FALSE
|
||||
var/mob/living/carbon/C = host_mob
|
||||
if(C.suiciding || HAS_TRAIT(C, TRAIT_NOCLONE) || C.hellbound) //can't revive
|
||||
return FALSE
|
||||
if((world.time - C.timeofdeath) > 1800) //too late
|
||||
return FALSE
|
||||
if((C.getBruteLoss() > 180) || (C.getFireLoss() > 180) || !C.can_be_revived()) //too damaged
|
||||
return FALSE
|
||||
if(!C.getorgan(/obj/item/organ/heart)) //what are we even shocking
|
||||
return FALSE
|
||||
var/obj/item/organ/brain/BR = C.getorgan(/obj/item/organ/brain)
|
||||
if(QDELETED(BR) || BR.brain_death || (BR.organ_flags & ORGAN_FAILING) || C.suiciding)
|
||||
return FALSE
|
||||
if(C.get_ghost())
|
||||
return FALSE
|
||||
return TRUE
|
||||
return C.can_defib()
|
||||
|
||||
/datum/nanite_program/triggered/defib/proc/zap()
|
||||
/datum/nanite_program/defib/proc/zap()
|
||||
var/mob/living/carbon/C = host_mob
|
||||
playsound(C, 'sound/machines/defib_charge.ogg', 50, 0)
|
||||
playsound(C, 'sound/machines/defib_charge.ogg', 50, FALSE)
|
||||
sleep(30)
|
||||
playsound(C, 'sound/machines/defib_zap.ogg', 50, 0)
|
||||
playsound(C, 'sound/machines/defib_zap.ogg', 50, FALSE)
|
||||
if(check_revivable())
|
||||
playsound(C, 'sound/machines/defib_success.ogg', 50, 0)
|
||||
playsound(C, 'sound/machines/defib_success.ogg', 50, FALSE)
|
||||
C.set_heartattack(FALSE)
|
||||
C.revive()
|
||||
C.revive(full_heal = FALSE, admin_revive = FALSE)
|
||||
C.emote("gasp")
|
||||
C.Jitter(100)
|
||||
SEND_SIGNAL(C, COMSIG_LIVING_MINOR_SHOCK)
|
||||
var/tplus = world.time - C.timeofdeath
|
||||
if(tplus > 600)
|
||||
C.adjustOrganLoss(ORGAN_SLOT_BRAIN, max(0, ((1800 - tplus) / 1800 * 150)), 150)
|
||||
log_game("[C] has been successfully defibrillated by nanites.")
|
||||
else
|
||||
playsound(C, 'sound/machines/defib_failed.ogg', 50, 0)
|
||||
playsound(C, 'sound/machines/defib_failed.ogg', 50, FALSE)
|
||||
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
//Replication Protocols
|
||||
/datum/nanite_program/protocol/kickstart
|
||||
name = "Kickstart Protocol"
|
||||
desc = "Replication Protocol: the nanites focus on early growth, heavily boosting replication rate for a few minutes after the initial implantation."
|
||||
use_rate = 0
|
||||
rogue_types = list(/datum/nanite_program/necrotic)
|
||||
protocol_class = NANITE_PROTOCOL_REPLICATION
|
||||
var/boost_duration = 1200
|
||||
|
||||
/datum/nanite_program/protocol/kickstart/check_conditions()
|
||||
if(!(world.time < nanites.start_time + boost_duration))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/nanite_program/protocol/kickstart/active_effect()
|
||||
nanites.adjust_nanites(null, 3.5)
|
||||
|
||||
/datum/nanite_program/protocol/factory
|
||||
name = "Factory Protocol"
|
||||
desc = "Replication Protocol: the nanites build a factory matrix within the host, gradually increasing replication speed over time. \
|
||||
The factory decays if the protocol is not active, or if the nanites are disrupted by shocks or EMPs."
|
||||
use_rate = 0
|
||||
rogue_types = list(/datum/nanite_program/necrotic)
|
||||
protocol_class = NANITE_PROTOCOL_REPLICATION
|
||||
var/factory_efficiency = 0
|
||||
var/max_efficiency = 1000 //Goes up to 2 bonus regen per tick after 16 minutes and 40 seconds
|
||||
|
||||
/datum/nanite_program/protocol/factory/on_process()
|
||||
if(!activated || !check_conditions())
|
||||
factory_efficiency = max(0, factory_efficiency - 5)
|
||||
..()
|
||||
|
||||
/datum/nanite_program/protocol/factory/on_emp(severity)
|
||||
..()
|
||||
factory_efficiency = max(0, factory_efficiency - 300)
|
||||
|
||||
/datum/nanite_program/protocol/factory/on_shock(shock_damage)
|
||||
..()
|
||||
factory_efficiency = max(0, factory_efficiency - 200)
|
||||
|
||||
/datum/nanite_program/protocol/factory/on_minor_shock()
|
||||
..()
|
||||
factory_efficiency = max(0, factory_efficiency - 100)
|
||||
|
||||
/datum/nanite_program/protocol/factory/active_effect()
|
||||
factory_efficiency = min(factory_efficiency + 1, max_efficiency)
|
||||
nanites.adjust_nanites(null, round(0.002 * factory_efficiency, 0.1))
|
||||
|
||||
/datum/nanite_program/protocol/tinker
|
||||
name = "Tinker Protocol"
|
||||
desc = "Replication Protocol: the nanites learn to use metallic material in the host's bloodstream to speed up the replication process."
|
||||
use_rate = 0
|
||||
rogue_types = list(/datum/nanite_program/necrotic)
|
||||
protocol_class = NANITE_PROTOCOL_REPLICATION
|
||||
var/boost = 2
|
||||
var/list/valid_reagents = list(
|
||||
/datum/reagent/iron,
|
||||
/datum/reagent/copper,
|
||||
/datum/reagent/gold,
|
||||
/datum/reagent/silver,
|
||||
/datum/reagent/mercury,
|
||||
/datum/reagent/aluminium,
|
||||
/datum/reagent/silicon)
|
||||
|
||||
/datum/nanite_program/protocol/tinker/check_conditions()
|
||||
if(!nanites.host_mob.reagents)
|
||||
return FALSE
|
||||
|
||||
var/found_reagent = FALSE
|
||||
|
||||
var/datum/reagents/R = nanites.host_mob.reagents
|
||||
for(var/VR in valid_reagents)
|
||||
if(R.has_reagent(VR, 0.5))
|
||||
R.remove_reagent(VR, 0.5)
|
||||
found_reagent = TRUE
|
||||
break
|
||||
if(!found_reagent)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/nanite_program/protocol/tinker/active_effect()
|
||||
nanites.adjust_nanites(null, boost)
|
||||
|
||||
/datum/nanite_program/protocol/offline
|
||||
name = "Offline Production Protocol"
|
||||
desc = "Replication Protocol: while the host is asleep or otherwise unconcious, the nanites exploit the reduced interference to replicate more quickly."
|
||||
use_rate = 0
|
||||
rogue_types = list(/datum/nanite_program/necrotic)
|
||||
protocol_class = NANITE_PROTOCOL_REPLICATION
|
||||
var/boost = 3
|
||||
|
||||
/datum/nanite_program/protocol/offline/check_conditions()
|
||||
var/is_offline = FALSE
|
||||
if(nanites.host_mob.IsSleeping() || nanites.host_mob.IsUnconscious())
|
||||
is_offline = TRUE
|
||||
if(nanites.host_mob.stat == DEAD || HAS_TRAIT(nanites.host_mob, TRAIT_DEATHCOMA))
|
||||
is_offline = TRUE
|
||||
if(nanites.host_mob.InCritical() && !HAS_TRAIT(nanites.host_mob, TRAIT_NOSOFTCRIT))
|
||||
is_offline = TRUE
|
||||
if(nanites.host_mob.InFullCritical() && !HAS_TRAIT(nanites.host_mob, TRAIT_NOHARDCRIT))
|
||||
is_offline = TRUE
|
||||
if(!is_offline)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/nanite_program/protocol/offline/active_effect()
|
||||
nanites.adjust_nanites(null, boost)
|
||||
@@ -2,71 +2,41 @@
|
||||
name = "Sensor Nanites"
|
||||
desc = "These nanites send a signal code when a certain condition is met."
|
||||
unique = FALSE
|
||||
extra_settings = list("Sent Code")
|
||||
var/can_rule = FALSE
|
||||
|
||||
var/sent_code = 0
|
||||
|
||||
/datum/nanite_program/sensor/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
|
||||
/datum/nanite_program/sensor/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
|
||||
/datum/nanite_program/sensor/copy_extra_settings_to(datum/nanite_program/sensor/target)
|
||||
target.sent_code = sent_code
|
||||
/datum/nanite_program/sensor/register_extra_settings()
|
||||
extra_settings[NES_SENT_CODE] = new /datum/nanite_extra_setting/number(0, 1, 9999)
|
||||
|
||||
/datum/nanite_program/sensor/proc/check_event()
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_program/sensor/proc/send_code()
|
||||
if(activated)
|
||||
SEND_SIGNAL(host_mob, COMSIG_NANITE_SIGNAL, sent_code, "a [name] program")
|
||||
var/datum/nanite_extra_setting/ES = extra_settings[NES_SENT_CODE]
|
||||
SEND_SIGNAL(host_mob, COMSIG_NANITE_SIGNAL, ES.value, "a [name] program")
|
||||
|
||||
/datum/nanite_program/sensor/active_effect()
|
||||
if(sent_code && check_event())
|
||||
if(check_event())
|
||||
send_code()
|
||||
|
||||
/datum/nanite_program/sensor/proc/make_rule(datum/nanite_program/target)
|
||||
return
|
||||
|
||||
/datum/nanite_program/sensor/repeat
|
||||
name = "Signal Repeater"
|
||||
desc = "When triggered, sends another signal to the nanites, optionally with a delay."
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 0
|
||||
trigger_cooldown = 10
|
||||
extra_settings = list("Sent Code","Delay")
|
||||
var/spent = FALSE
|
||||
var/delay = 0
|
||||
|
||||
/datum/nanite_program/sensor/repeat/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
if(setting == "Delay")
|
||||
var/new_delay = input(user, "Set the delay in seconds:", name, null) as null|num
|
||||
if(isnull(new_delay))
|
||||
return
|
||||
delay = (CLAMP(round(new_delay, 1), 0, 3600)) * 10 //max 1 hour
|
||||
/datum/nanite_program/sensor/repeat/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_DELAY] = new /datum/nanite_extra_setting/number(0, 0, 3600, "s")
|
||||
|
||||
/datum/nanite_program/sensor/repeat/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
if(setting == "Delay")
|
||||
return "[delay/10] seconds"
|
||||
|
||||
/datum/nanite_program/sensor/repeat/copy_extra_settings_to(datum/nanite_program/sensor/repeat/target)
|
||||
target.sent_code = sent_code
|
||||
target.delay = delay
|
||||
|
||||
/datum/nanite_program/sensor/repeat/trigger()
|
||||
if(!..())
|
||||
return
|
||||
addtimer(CALLBACK(src, .proc/send_code), delay)
|
||||
/datum/nanite_program/sensor/repeat/on_trigger(comm_message)
|
||||
var/datum/nanite_extra_setting/ES = extra_settings[NES_DELAY]
|
||||
addtimer(CALLBACK(src, .proc/send_code), ES.get_value() * 10)
|
||||
|
||||
/datum/nanite_program/sensor/relay_repeat
|
||||
name = "Relay Signal Repeater"
|
||||
@@ -74,98 +44,46 @@
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 0
|
||||
trigger_cooldown = 10
|
||||
extra_settings = list("Sent Code","Relay Channel","Delay")
|
||||
var/spent = FALSE
|
||||
var/delay = 0
|
||||
var/relay_channel = 0
|
||||
|
||||
/datum/nanite_program/sensor/relay_repeat/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
if(setting == "Relay Channel")
|
||||
var/new_channel = input(user, "Set the relay channel (1-9999):", name, null) as null|num
|
||||
if(isnull(new_channel))
|
||||
return
|
||||
relay_channel = CLAMP(round(new_channel, 1), 1, 9999)
|
||||
if(setting == "Delay")
|
||||
var/new_delay = input(user, "Set the delay in seconds:", name, null) as null|num
|
||||
if(isnull(new_delay))
|
||||
return
|
||||
delay = (CLAMP(round(new_delay, 1), 0, 3600)) * 10 //max 1 hour
|
||||
/datum/nanite_program/sensor/relay_repeat/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_RELAY_CHANNEL] = new /datum/nanite_extra_setting/number(1, 1, 9999)
|
||||
extra_settings[NES_DELAY] = new /datum/nanite_extra_setting/number(0, 0, 3600, "s")
|
||||
|
||||
/datum/nanite_program/sensor/relay_repeat/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
if(setting == "Relay Channel")
|
||||
return relay_channel
|
||||
if(setting == "Delay")
|
||||
return "[delay/10] seconds"
|
||||
|
||||
/datum/nanite_program/sensor/relay_repeat/copy_extra_settings_to(datum/nanite_program/sensor/relay_repeat/target)
|
||||
target.sent_code = sent_code
|
||||
target.delay = delay
|
||||
target.relay_channel = relay_channel
|
||||
|
||||
/datum/nanite_program/sensor/relay_repeat/trigger()
|
||||
if(!..())
|
||||
return
|
||||
addtimer(CALLBACK(src, .proc/send_code), delay)
|
||||
/datum/nanite_program/sensor/relay_repeat/on_trigger(comm_message)
|
||||
var/datum/nanite_extra_setting/ES = extra_settings[NES_DELAY]
|
||||
addtimer(CALLBACK(src, .proc/send_code), ES.get_value() * 10)
|
||||
|
||||
/datum/nanite_program/sensor/relay_repeat/send_code()
|
||||
if(activated && relay_channel)
|
||||
var/datum/nanite_extra_setting/relay = extra_settings[NES_RELAY_CHANNEL]
|
||||
if(activated && relay.get_value())
|
||||
for(var/X in SSnanites.nanite_relays)
|
||||
var/datum/nanite_program/relay/N = X
|
||||
N.relay_signal(sent_code, relay_channel, "a [name] program")
|
||||
var/datum/nanite_extra_setting/code = extra_settings[NES_SENT_CODE]
|
||||
N.relay_signal(code.get_value(), relay.get_value(), "a [name] program")
|
||||
|
||||
/datum/nanite_program/sensor/health
|
||||
name = "Health Sensor"
|
||||
desc = "The nanites receive a signal when the host's health is above/below a target percentage."
|
||||
extra_settings = list("Sent Code","Health Percent","Direction")
|
||||
can_rule = TRUE
|
||||
var/spent = FALSE
|
||||
var/percent = 50
|
||||
var/direction = "Above"
|
||||
|
||||
/datum/nanite_program/sensor/health/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
if(setting == "Health Percent")
|
||||
var/new_percent = input(user, "Set the health percentage:", name, null) as null|num
|
||||
if(isnull(new_percent))
|
||||
return
|
||||
percent = CLAMP(round(new_percent, 1), -99, 100)
|
||||
if(setting == "Direction")
|
||||
if(direction == "Above")
|
||||
direction = "Below"
|
||||
else
|
||||
direction = "Above"
|
||||
|
||||
/datum/nanite_program/sensor/health/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
if(setting == "Health Percent")
|
||||
return "[percent]%"
|
||||
if(setting == "Direction")
|
||||
return direction
|
||||
|
||||
/datum/nanite_program/sensor/health/copy_extra_settings_to(datum/nanite_program/sensor/health/target)
|
||||
target.sent_code = sent_code
|
||||
target.percent = percent
|
||||
target.direction = direction
|
||||
/datum/nanite_program/sensor/health/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_HEALTH_PERCENT] = new /datum/nanite_extra_setting/number(50, -99, 100, "%")
|
||||
extra_settings[NES_DIRECTION] = new /datum/nanite_extra_setting/boolean(TRUE, "Above", "Below")
|
||||
|
||||
/datum/nanite_program/sensor/health/check_event()
|
||||
var/health_percent = host_mob.health / host_mob.maxHealth * 100
|
||||
var/datum/nanite_extra_setting/percent = extra_settings[NES_HEALTH_PERCENT]
|
||||
var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION]
|
||||
var/detected = FALSE
|
||||
if(direction == "Above")
|
||||
if(health_percent >= percent)
|
||||
if(direction.get_value())
|
||||
if(health_percent >= percent.get_value())
|
||||
detected = TRUE
|
||||
else
|
||||
if(health_percent < percent)
|
||||
if(health_percent < percent.get_value())
|
||||
detected = TRUE
|
||||
|
||||
if(detected)
|
||||
@@ -177,9 +95,18 @@
|
||||
spent = FALSE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_program/sensor/health/make_rule(datum/nanite_program/target)
|
||||
var/datum/nanite_rule/health/rule = new(target)
|
||||
var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION]
|
||||
var/datum/nanite_extra_setting/percent = extra_settings[NES_HEALTH_PERCENT]
|
||||
rule.above = direction.get_value()
|
||||
rule.threshold = percent.get_value()
|
||||
return rule
|
||||
|
||||
/datum/nanite_program/sensor/crit
|
||||
name = "Critical Health Sensor"
|
||||
desc = "The nanites receive a signal when the host first reaches critical health."
|
||||
can_rule = TRUE
|
||||
var/spent = FALSE
|
||||
|
||||
/datum/nanite_program/sensor/crit/check_event()
|
||||
@@ -192,61 +119,44 @@
|
||||
spent = FALSE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_program/sensor/crit/make_rule(datum/nanite_program/target)
|
||||
var/datum/nanite_rule/crit/rule = new(target)
|
||||
return rule
|
||||
|
||||
/datum/nanite_program/sensor/death
|
||||
name = "Death Sensor"
|
||||
desc = "The nanites receive a signal when they detect the host is dead."
|
||||
can_rule = TRUE
|
||||
var/spent = FALSE
|
||||
|
||||
/datum/nanite_program/sensor/death/on_death()
|
||||
send_code()
|
||||
|
||||
/datum/nanite_program/sensor/death/make_rule(datum/nanite_program/target)
|
||||
var/datum/nanite_rule/death/rule = new(target)
|
||||
return rule
|
||||
|
||||
/datum/nanite_program/sensor/nanite_volume
|
||||
name = "Nanite Volume Sensor"
|
||||
desc = "The nanites receive a signal when the nanite supply is above/below a certain percentage."
|
||||
extra_settings = list("Sent Code","Nanite Percent","Direction")
|
||||
can_rule = TRUE
|
||||
var/spent = FALSE
|
||||
var/percent = 50
|
||||
var/direction = "Above"
|
||||
|
||||
/datum/nanite_program/sensor/nanite_volume/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
if(setting == "Nanite Percent")
|
||||
var/new_percent = input(user, "Set the nanite percentage:", name, null) as null|num
|
||||
if(isnull(new_percent))
|
||||
return
|
||||
percent = CLAMP(round(new_percent, 1), 1, 100)
|
||||
if(setting == "Direction")
|
||||
if(direction == "Above")
|
||||
direction = "Below"
|
||||
else
|
||||
direction = "Above"
|
||||
|
||||
/datum/nanite_program/sensor/nanite_volume/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
if(setting == "Nanite Percent")
|
||||
return "[percent]%"
|
||||
if(setting == "Direction")
|
||||
return direction
|
||||
|
||||
/datum/nanite_program/sensor/nanite_volume/copy_extra_settings_to(datum/nanite_program/sensor/nanite_volume/target)
|
||||
target.sent_code = sent_code
|
||||
target.percent = percent
|
||||
target.direction = direction
|
||||
/datum/nanite_program/sensor/nanite_volume/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_NANITE_PERCENT] = new /datum/nanite_extra_setting/number(50, -99, 100, "%")
|
||||
extra_settings[NES_DIRECTION] = new /datum/nanite_extra_setting/boolean(TRUE, "Above", "Below")
|
||||
|
||||
/datum/nanite_program/sensor/nanite_volume/check_event()
|
||||
var/nanite_percent = (nanites.nanite_volume - nanites.safety_threshold)/(nanites.max_nanites - nanites.safety_threshold)*100
|
||||
var/datum/nanite_extra_setting/percent = extra_settings[NES_NANITE_PERCENT]
|
||||
var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION]
|
||||
var/detected = FALSE
|
||||
|
||||
if(direction == "Above")
|
||||
if(nanite_percent >= percent)
|
||||
if(direction.get_value())
|
||||
if(nanite_percent >= percent.get_value())
|
||||
detected = TRUE
|
||||
else
|
||||
if(nanite_percent < percent)
|
||||
if(nanite_percent < percent.get_value())
|
||||
detected = TRUE
|
||||
|
||||
if(detected)
|
||||
@@ -258,75 +168,51 @@
|
||||
spent = FALSE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_program/sensor/nanite_volume/make_rule(datum/nanite_program/target)
|
||||
var/datum/nanite_rule/nanites/rule = new(target)
|
||||
var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION]
|
||||
var/datum/nanite_extra_setting/percent = extra_settings[NES_NANITE_PERCENT]
|
||||
rule.above = direction.get_value()
|
||||
rule.threshold = percent.get_value()
|
||||
return rule
|
||||
|
||||
/datum/nanite_program/sensor/damage
|
||||
name = "Damage Sensor"
|
||||
desc = "The nanites receive a signal when a host's specific damage type is above/below a target value."
|
||||
extra_settings = list("Sent Code","Damage Type","Damage","Direction")
|
||||
can_rule = TRUE
|
||||
var/spent = FALSE
|
||||
var/damage_type = "Brute"
|
||||
var/damage = 50
|
||||
var/direction = "Above"
|
||||
|
||||
/datum/nanite_program/sensor/damage/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
if(setting == "Damage")
|
||||
var/new_damage = input(user, "Set the damage threshold:", name, null) as null|num
|
||||
if(isnull(new_damage))
|
||||
return
|
||||
damage = CLAMP(round(new_damage, 1), 0, 500)
|
||||
if(setting == "Damage Type")
|
||||
var/list/damage_types = list("Brute","Burn","Toxin","Oxygen","Cellular")
|
||||
var/new_damage_type = input("Choose the damage type", name) as null|anything in damage_types
|
||||
if(!new_damage_type)
|
||||
return
|
||||
damage_type = new_damage_type
|
||||
if(setting == "Direction")
|
||||
if(direction == "Above")
|
||||
direction = "Below"
|
||||
else
|
||||
direction = "Above"
|
||||
|
||||
/datum/nanite_program/sensor/damage/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
if(setting == "Damage")
|
||||
return damage
|
||||
if(setting == "Damage Type")
|
||||
return damage_type
|
||||
if(setting == "Direction")
|
||||
return direction
|
||||
|
||||
/datum/nanite_program/sensor/damage/copy_extra_settings_to(datum/nanite_program/sensor/damage/target)
|
||||
target.sent_code = sent_code
|
||||
target.damage = damage
|
||||
target.damage_type = damage_type
|
||||
target.direction = direction
|
||||
/datum/nanite_program/sensor/damage/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_DAMAGE_TYPE] = new /datum/nanite_extra_setting/type(BRUTE, list(BRUTE, BURN, TOX, OXY, CLONE))
|
||||
extra_settings[NES_DAMAGE] = new /datum/nanite_extra_setting/number(50, 0, 500)
|
||||
extra_settings[NES_DIRECTION] = new /datum/nanite_extra_setting/boolean(TRUE, "Above", "Below")
|
||||
|
||||
/datum/nanite_program/sensor/damage/check_event()
|
||||
var/reached_threshold = FALSE
|
||||
var/check_above = (direction == "Above")
|
||||
var/datum/nanite_extra_setting/type = extra_settings[NES_DAMAGE_TYPE]
|
||||
var/datum/nanite_extra_setting/damage = extra_settings[NES_DAMAGE]
|
||||
var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION]
|
||||
var/check_above = direction.get_value()
|
||||
var/damage_amt = 0
|
||||
switch(damage_type)
|
||||
if("Brute")
|
||||
switch(type.get_value())
|
||||
if(BRUTE)
|
||||
damage_amt = host_mob.getBruteLoss()
|
||||
if("Burn")
|
||||
if(BURN)
|
||||
damage_amt = host_mob.getFireLoss()
|
||||
if("Toxin")
|
||||
if(TOX)
|
||||
damage_amt = host_mob.getToxLoss()
|
||||
if("Oxygen")
|
||||
if(OXY)
|
||||
damage_amt = host_mob.getOxyLoss()
|
||||
if("Cellular")
|
||||
if(CLONE)
|
||||
damage_amt = host_mob.getCloneLoss()
|
||||
|
||||
if(damage_amt >= damage)
|
||||
if(check_above)
|
||||
if(check_above)
|
||||
if(damage_amt >= damage.get_value())
|
||||
reached_threshold = TRUE
|
||||
else
|
||||
if(damage_amt < damage.get_value())
|
||||
reached_threshold = TRUE
|
||||
else if(!check_above)
|
||||
reached_threshold = TRUE
|
||||
|
||||
if(reached_threshold)
|
||||
if(!spent)
|
||||
@@ -337,14 +223,25 @@
|
||||
spent = FALSE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_program/sensor/damage/make_rule(datum/nanite_program/target)
|
||||
var/datum/nanite_rule/damage/rule = new(target)
|
||||
var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION]
|
||||
var/datum/nanite_extra_setting/damage_type = extra_settings[NES_DAMAGE_TYPE]
|
||||
var/datum/nanite_extra_setting/damage = extra_settings[NES_DAMAGE]
|
||||
rule.above = direction.get_value()
|
||||
rule.threshold = damage.get_value()
|
||||
rule.damage_type = damage_type.get_value()
|
||||
return rule
|
||||
|
||||
/datum/nanite_program/sensor/voice
|
||||
name = "Voice Sensor"
|
||||
desc = "Sends a signal when the nanites hear a determined word or sentence."
|
||||
extra_settings = list("Sent Code","Sentence","Inclusive Mode")
|
||||
var/spent = FALSE
|
||||
var/sentence = ""
|
||||
var/inclusive = TRUE
|
||||
|
||||
/datum/nanite_program/sensor/voice/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_SENTENCE] = new /datum/nanite_extra_setting/text("")
|
||||
extra_settings[NES_INCLUSIVE_MODE] = new /datum/nanite_extra_setting/boolean(TRUE, "Inclusive", "Exclusive")
|
||||
|
||||
/datum/nanite_program/sensor/voice/on_mob_add()
|
||||
. = ..()
|
||||
@@ -353,45 +250,14 @@
|
||||
/datum/nanite_program/sensor/voice/on_mob_remove()
|
||||
UnregisterSignal(host_mob, COMSIG_MOVABLE_HEAR, .proc/on_hear)
|
||||
|
||||
/datum/nanite_program/sensor/voice/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
if(setting == "Sentence")
|
||||
var/new_sentence = stripped_input(user, "Choose the sentence that triggers the sensor.", "Sentence", sentence, MAX_MESSAGE_LEN)
|
||||
if(!new_sentence)
|
||||
return
|
||||
sentence = new_sentence
|
||||
if(setting == "Inclusive Mode")
|
||||
var/new_inclusive = input("Should the sensor detect the sentence if contained within another sentence?", name) as null|anything in list("Inclusive","Exclusive")
|
||||
if(!new_inclusive)
|
||||
return
|
||||
inclusive = (new_inclusive == "Inclusive")
|
||||
|
||||
/datum/nanite_program/sensor/voice/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
if(setting == "Sentence")
|
||||
return sentence
|
||||
if(setting == "Inclusive Mode")
|
||||
if(inclusive)
|
||||
return "Inclusive"
|
||||
else
|
||||
return "Exclusive"
|
||||
|
||||
/datum/nanite_program/sensor/voice/copy_extra_settings_to(datum/nanite_program/sensor/voice/target)
|
||||
target.sent_code = sent_code
|
||||
target.sentence = sentence
|
||||
target.inclusive = inclusive
|
||||
|
||||
/datum/nanite_program/sensor/voice/proc/on_hear(datum/source, list/hearing_args)
|
||||
if(!sentence)
|
||||
var/datum/nanite_extra_setting/sentence = extra_settings[NES_SENTENCE]
|
||||
var/datum/nanite_extra_setting/inclusive = extra_settings[NES_INCLUSIVE_MODE]
|
||||
if(!sentence.get_value())
|
||||
return
|
||||
if(inclusive)
|
||||
if(inclusive.get_value())
|
||||
if(findtextEx(hearing_args[HEARING_RAW_MESSAGE], sentence))
|
||||
send_code()
|
||||
else
|
||||
if(hearing_args[HEARING_RAW_MESSAGE] == sentence)
|
||||
send_code()
|
||||
send_code()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user