From 14e9dbd779c94c5d00eb4f90d77c039e054bdb08 Mon Sep 17 00:00:00 2001 From: Tastyfish Date: Tue, 3 Jan 2012 14:44:28 -0500 Subject: [PATCH 1/3] a couple chatbot grammer improvements --- code/WorkInProgress/Tastyfish/Eliza.dm | 2 +- code/WorkInProgress/Tastyfish/Eliza_Data.dm | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/code/WorkInProgress/Tastyfish/Eliza.dm b/code/WorkInProgress/Tastyfish/Eliza.dm index 8ebd7236222..6fc0e2e3561 100644 --- a/code/WorkInProgress/Tastyfish/Eliza.dm +++ b/code/WorkInProgress/Tastyfish/Eliza.dm @@ -19,7 +19,7 @@ username = "" yesno_state = "" yesno_param = "" - print("Hi! I'm [callsign], how are you doing?") + print("Hi! I'm [callsign], how are you doing? You can talk to me by beginning your statements with \"[callsign],\"") /datum/text_parser/parser/eliza/process_line() ..() diff --git a/code/WorkInProgress/Tastyfish/Eliza_Data.dm b/code/WorkInProgress/Tastyfish/Eliza_Data.dm index 0fecf95cf71..f84b7b20aca 100644 --- a/code/WorkInProgress/Tastyfish/Eliza_Data.dm +++ b/code/WorkInProgress/Tastyfish/Eliza_Data.dm @@ -108,7 +108,7 @@ "Oh, I*", "You're not really talking about me, are you?")), new/datum/text_parser/keyword( - list("i want"), + list("i want","i like"), list( "What would it mean if you got*", "Why do you want*", @@ -397,7 +397,7 @@ pda.overlays = null pda.overlays += image('pda.dmi', "pda-r") - return "Told [name] that [object]." + return "Told [name], [object]." /datum/text_parser/keyword/yes process(object) From f6706ef3332c8d72bdc0be4f60941967df2adf5d Mon Sep 17 00:00:00 2001 From: Tastyfish Date: Wed, 4 Jan 2012 22:01:24 -0500 Subject: [PATCH 2/3] retired admins don't get sent as admins in json --- code/game/json.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/json.dm b/code/game/json.dm index 38eca15c3b8..c1d94b08510 100644 --- a/code/game/json.dm +++ b/code/game/json.dm @@ -30,7 +30,7 @@ proc/makejson() var/admins = "no" for(var/client/C) playerscount++ - if(C.holder) + if(C.holder && C.holder.level >= 0) // make sure retired admins don't make nt think admins are on if(!C.stealth) admins = "yes" players += "[C.key];" From a2ff049861e8736c1ce97202031896f31017672f Mon Sep 17 00:00:00 2001 From: Tastyfish Date: Wed, 4 Jan 2012 23:01:22 -0500 Subject: [PATCH 3/3] merge --- baystation12.dme | 40 +- code/WorkInProgress/Mini/atmos_control.dm | 3 +- code/WorkInProgress/Mini/customitems.dm | 4 +- code/WorkInProgress/SkyMarshal/eraser.dm | 9 - .../WorkInProgress/SkyMarshal/traitoritems.dm | 74 + code/WorkInProgress/virus2/base.dm | 2 +- code/WorkInProgress/virus2/curer.dm | 16 +- code/defines/client.dm | 2 +- code/defines/global.dm | 4 +- code/defines/obj/clothing/jumpsuit.dm | 7 + code/defines/obj/weapon.dm | 4 + code/game/communications.dm | 12 +- code/game/events/Event.dm | 20 + .../EventProcs}/black_hole.dm | 172 +- .../events => events/EventProcs}/clang.dm | 162 +- .../events => events/EventProcs}/dust.dm | 236 +- .../events => events/EventProcs}/kudzu.dm | 350 +- .../events => events/EventProcs}/miniblob.dm | 64 +- code/game/events/EventProcs/misc.dm | 71 + .../EventProcs}/ninja_abilities.dm | 858 ++--- .../EventProcs}/ninja_equipment.dm | 2910 ++++++++--------- .../EventProcs}/space_ninja.dm | 1990 +++++------ code/game/events/Events/AlienInfestation.dm | 38 + code/game/events/Events/Appendicitis.dm | 16 + code/game/events/Events/BlowOut.dm | 34 + code/game/events/Events/ElectricalStorm.dm | 124 + .../events/Events/GravitationalAnomaly.dm | 10 + code/game/events/Events/ImmovableRod.dm | 5 + code/game/events/Events/IonStorm.dm | 46 + code/game/events/Events/MeteorStorm.dm | 11 + code/game/events/Events/MiniBlob.dm | 5 + code/game/events/Events/PortalStorm.dm | 26 + code/game/events/Events/PowerOffline.dm | 8 + code/game/events/Events/PrisonBreak.dm | 24 + code/game/events/Events/RadiationBelt.dm | 18 + code/game/events/Events/SpaceCarp.dm | 14 + code/game/events/Events/SpaceNinja.dm | 6 + code/game/events/Events/VirusEpidemic.dm | 80 + code/game/events/EventsMain.dm | 76 + code/game/gamemodes/events.dm | 445 --- code/game/gamemodes/gameticker.dm | 9 +- code/game/machinery/alarm.dm | 46 +- code/game/machinery/doors/airlock.dm | 1 - code/game/objects/radio/radio.dm | 33 +- code/modules/admin/admin.dm | 41 +- code/modules/admin/admin_verbs.dm | 2 + code/modules/admin/verbs/randomverbs.dm | 2 +- code/modules/mob/mob.dm | 2 +- code/modules/mob/mob_helpers.dm | 4 +- code/modules/mob/mob_movement.dm | 2 +- code/modules/power/apc.dm | 4 +- icons/obj/doors/rapid_pdoor.dmi | Bin 8025 -> 8228 bytes 52 files changed, 4258 insertions(+), 3884 deletions(-) delete mode 100644 code/WorkInProgress/SkyMarshal/eraser.dm create mode 100644 code/WorkInProgress/SkyMarshal/traitoritems.dm create mode 100644 code/game/events/Event.dm rename code/game/{gamemodes/events => events/EventProcs}/black_hole.dm (95%) rename code/game/{gamemodes/events => events/EventProcs}/clang.dm (93%) rename code/game/{gamemodes/events => events/EventProcs}/dust.dm (94%) rename code/game/{gamemodes/events => events/EventProcs}/kudzu.dm (96%) rename code/game/{gamemodes/events => events/EventProcs}/miniblob.dm (94%) create mode 100644 code/game/events/EventProcs/misc.dm rename code/game/{gamemodes/events => events/EventProcs}/ninja_abilities.dm (97%) rename code/game/{gamemodes/events => events/EventProcs}/ninja_equipment.dm (97%) rename code/game/{gamemodes/events => events/EventProcs}/space_ninja.dm (97%) create mode 100644 code/game/events/Events/AlienInfestation.dm create mode 100644 code/game/events/Events/Appendicitis.dm create mode 100644 code/game/events/Events/BlowOut.dm create mode 100644 code/game/events/Events/ElectricalStorm.dm create mode 100644 code/game/events/Events/GravitationalAnomaly.dm create mode 100644 code/game/events/Events/ImmovableRod.dm create mode 100644 code/game/events/Events/IonStorm.dm create mode 100644 code/game/events/Events/MeteorStorm.dm create mode 100644 code/game/events/Events/MiniBlob.dm create mode 100644 code/game/events/Events/PortalStorm.dm create mode 100644 code/game/events/Events/PowerOffline.dm create mode 100644 code/game/events/Events/PrisonBreak.dm create mode 100644 code/game/events/Events/RadiationBelt.dm create mode 100644 code/game/events/Events/SpaceCarp.dm create mode 100644 code/game/events/Events/SpaceNinja.dm create mode 100644 code/game/events/Events/VirusEpidemic.dm create mode 100644 code/game/events/EventsMain.dm delete mode 100644 code/game/gamemodes/events.dm diff --git a/baystation12.dme b/baystation12.dme index 8b7df32043c..f58c6eba48c 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -30,11 +30,13 @@ #define FILE_DIR "code/game" #define FILE_DIR "code/game/area" #define FILE_DIR "code/game/asteroid" +#define FILE_DIR "code/game/events" +#define FILE_DIR "code/game/events/EventProcs" +#define FILE_DIR "code/game/events/Events" #define FILE_DIR "code/game/gamemodes" #define FILE_DIR "code/game/gamemodes/blob" #define FILE_DIR "code/game/gamemodes/changeling" #define FILE_DIR "code/game/gamemodes/cult" -#define FILE_DIR "code/game/gamemodes/events" #define FILE_DIR "code/game/gamemodes/extended" #define FILE_DIR "code/game/gamemodes/malfunction" #define FILE_DIR "code/game/gamemodes/meteor" @@ -364,7 +366,31 @@ #include "code\game\asteroid\asteroid.dm" #include "code\game\asteroid\device.dm" #include "code\game\asteroid\turf.dm" -#include "code\game\gamemodes\events.dm" +#include "code\game\events\Event.dm" +#include "code\game\events\EventsMain.dm" +#include "code\game\events\EventProcs\black_hole.dm" +#include "code\game\events\EventProcs\clang.dm" +#include "code\game\events\EventProcs\dust.dm" +#include "code\game\events\EventProcs\kudzu.dm" +#include "code\game\events\EventProcs\miniblob.dm" +#include "code\game\events\EventProcs\misc.dm" +#include "code\game\events\EventProcs\ninja_abilities.dm" +#include "code\game\events\EventProcs\ninja_equipment.dm" +#include "code\game\events\EventProcs\space_ninja.dm" +#include "code\game\events\Events\AlienInfestation.dm" +#include "code\game\events\Events\Appendicitis.dm" +#include "code\game\events\Events\ElectricalStorm.dm" +#include "code\game\events\Events\GravitationalAnomaly.dm" +#include "code\game\events\Events\ImmovableRod.dm" +#include "code\game\events\Events\IonStorm.dm" +#include "code\game\events\Events\MeteorStorm.dm" +#include "code\game\events\Events\MiniBlob.dm" +#include "code\game\events\Events\PowerOffline.dm" +#include "code\game\events\Events\PrisonBreak.dm" +#include "code\game\events\Events\RadiationBelt.dm" +#include "code\game\events\Events\SpaceCarp.dm" +#include "code\game\events\Events\SpaceNinja.dm" +#include "code\game\events\Events\VirusEpidemic.dm" #include "code\game\gamemodes\game_mode.dm" #include "code\game\gamemodes\gameticker.dm" #include "code\game\gamemodes\intercept_report.dm" @@ -377,14 +403,6 @@ #include "code\game\gamemodes\changeling\traitor_chan.dm" #include "code\game\gamemodes\cult\cult.dm" #include "code\game\gamemodes\cult\cult_items.dm" -#include "code\game\gamemodes\events\black_hole.dm" -#include "code\game\gamemodes\events\clang.dm" -#include "code\game\gamemodes\events\dust.dm" -#include "code\game\gamemodes\events\kudzu.dm" -#include "code\game\gamemodes\events\miniblob.dm" -#include "code\game\gamemodes\events\ninja_abilities.dm" -#include "code\game\gamemodes\events\ninja_equipment.dm" -#include "code\game\gamemodes\events\space_ninja.dm" #include "code\game\gamemodes\extended\extended.dm" #include "code\game\gamemodes\malfunction\Malf_Modules.dm" #include "code\game\gamemodes\malfunction\malfunction.dm" @@ -986,8 +1004,8 @@ #include "code\WorkInProgress\Mini\atmos_control.dm" #include "code\WorkInProgress\Mini\customitems.dm" #include "code\WorkInProgress\SkyMarshal\coatrack.dm" -#include "code\WorkInProgress\SkyMarshal\eraser.dm" #include "code\WorkInProgress\SkyMarshal\policetape.dm" +#include "code\WorkInProgress\SkyMarshal\traitoritems.dm" #include "code\WorkInProgress\Tastyfish\Eliza.dm" #include "code\WorkInProgress\Tastyfish\Eliza_Data.dm" #include "code\WorkInProgress\Tastyfish\paiLiza.dm" diff --git a/code/WorkInProgress/Mini/atmos_control.dm b/code/WorkInProgress/Mini/atmos_control.dm index e1aa431fd7f..b5a656ce352 100644 --- a/code/WorkInProgress/Mini/atmos_control.dm +++ b/code/WorkInProgress/Mini/atmos_control.dm @@ -10,6 +10,7 @@ anchored = 1.0 circuit = "/obj/item/weapon/circuitboard/atmoscontrol" var/obj/machinery/alarm/current = "" + var/overridden = 0 //not set yet, can't think of a good way to do it /obj/machinery/computer/atmoscontrol/attack_hand(mob/user) if(..()) @@ -36,7 +37,7 @@ return "" var/dat = "

[current.name]


" dat += current.return_status() - if(current.remote_control) + if(current.remote_control || overridden && current.rcon_setting) dat += "
[src.return_controls()]" return dat diff --git a/code/WorkInProgress/Mini/customitems.dm b/code/WorkInProgress/Mini/customitems.dm index 3a3da54918e..8a507608b21 100644 --- a/code/WorkInProgress/Mini/customitems.dm +++ b/code/WorkInProgress/Mini/customitems.dm @@ -6,7 +6,9 @@ var/list/CustomItemList = list( // ckey real_name item path // list("miniature","Dave Booze",/obj/item/toy/crayonbox) //screw this i dont want crayons, it's an example okay - list("skymarshal", "Phillip Oswald", /obj/item/weapon/coin/silver) //Phillip likes to chew on cigars. Just unlit cigars, don't ask me why. Must be a clone thing. (Cigarette machines dispense cigars if they have a coin in them) --SkyMarshal + list("skymarshal", "Phillip Oswald", /obj/item/weapon/coin/silver), //Phillip likes to chew on cigars. Just unlit cigars, don't ask me why. Must be a clone thing. (Cigarette machines dispense cigars if they have a coin in them) --SkyMarshal + list("spaceman96", "Trenna Seber", /obj/item/weapon/pen/multi), //For Spesss. + list("asanadas", "Book Berner", /obj/item/clothing/under/chameleon/psyche) ) /proc/EquipCustomItems(mob/living/carbon/human/M) diff --git a/code/WorkInProgress/SkyMarshal/eraser.dm b/code/WorkInProgress/SkyMarshal/eraser.dm deleted file mode 100644 index f15384f3f14..00000000000 --- a/code/WorkInProgress/SkyMarshal/eraser.dm +++ /dev/null @@ -1,9 +0,0 @@ -/obj/item/weapon/stamperaser - name = "Eraser" - desc = "Some type of eraser, you guess." - flags = FPRINT | TABLEPASS - icon = 'items.dmi' - icon_state = "zippo" - item_state = "zippo" - w_class = 1.0 - m_amt = 80 \ No newline at end of file diff --git a/code/WorkInProgress/SkyMarshal/traitoritems.dm b/code/WorkInProgress/SkyMarshal/traitoritems.dm new file mode 100644 index 00000000000..2b29a12e22e --- /dev/null +++ b/code/WorkInProgress/SkyMarshal/traitoritems.dm @@ -0,0 +1,74 @@ +/obj/item/weapon/stamperaser + name = "Eraser" + desc = "Some type of eraser, you guess." + flags = FPRINT | TABLEPASS + icon = 'items.dmi' + icon_state = "zippo" + item_state = "zippo" + w_class = 1.0 + m_amt = 80 + +/obj/item/device/jammer + name = "strange device" + desc = "It blinks and has an antenna on it. Weird." + icon_state = "t-ray0" + var/on = 0 + flags = FPRINT|TABLEPASS + w_class = 1 + var + list/obj/item/device/radio/Old = list() + list/obj/item/device/radio/Curr = list() + time_remaining = 5 + +/obj/item/device/jammer/New() + ..() + time_remaining = rand(10,20) // ~2-4 BYOND seconds of use. + return + +/obj/item/device/jammer/attack_self(mob/user) + + if(time_remaining > 0) + on = !on + icon_state = "t-ray[on]" + + if(on) + processing_objects.Add(src) + else + on = 0 + icon_state = "t-ray0" + user << "It's fried itself from overuse!" + if(Old) + for(var/obj/item/device/radio/T in Old) + T.scrambleoverride = 0 + Old = null + Curr = null + + +/obj/item/device/jammer/process() + if(!on) + processing_objects.Remove(src) + return null + + Old = Curr + Curr = list() + + for(var/obj/item/device/radio/T in range(3, src.loc) ) + + T.scrambleoverride = 1 + Curr |= T + for(var/obj/item/device/radio/V in Old) + if(V == T) + Old -= V + break + + for(var/obj/item/device/radio/T in Old) + T.scrambleoverride = 0 + + time_remaining-- + if(time_remaining <= 0) + for(var/mob/O in viewers(src)) + O.show_message("\red You hear a loud pop, like circuits frying.", 1) + on = 0 + icon_state = "t-ray0" + + sleep(2) \ No newline at end of file diff --git a/code/WorkInProgress/virus2/base.dm b/code/WorkInProgress/virus2/base.dm index 5130d01142c..00897198d49 100644 --- a/code/WorkInProgress/virus2/base.dm +++ b/code/WorkInProgress/virus2/base.dm @@ -239,7 +239,7 @@ proc/airborne_can_reach(turf/source, turf/target) e.runeffect(mob,stage) clicks+=speed - if(prob(5)) spread_airborne(mob) + if(prob(50)) spread_airborne(mob) proc/cure(var/mob/living/carbon/mob) var/datum/disease2/effectholder/E diff --git a/code/WorkInProgress/virus2/curer.dm b/code/WorkInProgress/virus2/curer.dm index e5e0bc7f8d6..71948a08043 100644 --- a/code/WorkInProgress/virus2/curer.dm +++ b/code/WorkInProgress/virus2/curer.dm @@ -3,7 +3,7 @@ icon = 'computer.dmi' icon_state = "dna" var/curing - var/virusing + var/virusing = 0 var/obj/item/weapon/reagent_containers/container = null @@ -40,6 +40,20 @@ container = I C.drop_item() I.loc = src + if(istype(I,/obj/item/weapon/virusdish)) + if(virusing) + user << "The pathogen materializer is still recharging.." + return + var/obj/item/weapon/reagent_containers/glass/beaker/product = new(src.loc) + + var/list/data = list("donor"=null,"viruses"=null,"blood_DNA"=null,"blood_type"=null,"resistances"=null,"trace_chem"=null,"virus2"=null,"antibodies"=0) + data["virus2"] = I:virus2 + product.reagents.add_reagent("blood",30,data) + + virusing = 1 + spawn(1200) virusing = 0 + + state("The [src.name] Buzzes", "blue") //else src.attack_hand(user) diff --git a/code/defines/client.dm b/code/defines/client.dm index 41b3a612ecb..d246ad89521 100644 --- a/code/defines/client.dm +++ b/code/defines/client.dm @@ -46,4 +46,4 @@ // comment out the line below when debugging locally to enable the options & messages menu - control_freak = 1 \ No newline at end of file + //control_freak = 1 \ No newline at end of file diff --git a/code/defines/global.dm b/code/defines/global.dm index caa40a1891a..b0bbb54e11a 100644 --- a/code/defines/global.dm +++ b/code/defines/global.dm @@ -41,7 +41,7 @@ var skipupdate = 0 /////////////// eventchance = 1 //% per 2 mins - event = 0 + EventsOn = 1 hadevent = 0 blobevent = 0 /////////////// @@ -157,6 +157,8 @@ var list/BorgIndexToFlag list/BorgIndexToWireColor list/BorgWireColorToIndex + list/ScrambledFrequencies = list( ) //These are used for electrical storms, and anything else that jams radios. + list/UnscrambledFrequencies = list( ) const/SPEED_OF_LIGHT = 3e8 //not exact but hey! const/SPEED_OF_LIGHT_SQ = 9e+16 diff --git a/code/defines/obj/clothing/jumpsuit.dm b/code/defines/obj/clothing/jumpsuit.dm index 3ccca7d524d..f420d23bd0b 100644 --- a/code/defines/obj/clothing/jumpsuit.dm +++ b/code/defines/obj/clothing/jumpsuit.dm @@ -30,6 +30,13 @@ origin_tech = "syndicate=3" var/list/clothing_choices = list() +/obj/item/clothing/under/chameleon/psyche + item_state = "bl_suit" + name = "psychedelic" + desc = "Groovy!" + icon_state = "psyche" + color = "psyche" + /obj/item/clothing/under/chameleon/all /obj/item/clothing/under/color/black diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm index a40d1804805..d01409c9e4b 100644 --- a/code/defines/obj/weapon.dm +++ b/code/defines/obj/weapon.dm @@ -915,6 +915,10 @@ var/text_underline = 0 var/text_break = 0 +/obj/item/weapon/pen/multi + desc = "It's a cool looking pen. Lots of colors!" + name = "multicolor pen" + /obj/item/weapon/banhammer desc = "A banhammer" name = "Banhammer" diff --git a/code/game/communications.dm b/code/game/communications.dm index aac6202bc16..8b292e10f80 100644 --- a/code/game/communications.dm +++ b/code/game/communications.dm @@ -113,7 +113,7 @@ var/list/radiochannels = list( var/list/DEPT_FREQS = list(1351,1355,1357,1359,1213,1441,1349,1347) var/const/COMM_FREQ = 1353 //command, colored gold in chat window var/const/SYND_FREQ = 1213 -var/NUKE_FREQ = 1199 //Never accessable except on nuke rounds. +var/NUKE_FREQ = 1199 //Never accessable except on nuke rounds, randomised on nuke rounds. #define TRANSMISSION_WIRE 0 #define TRANSMISSION_RADIO 1 @@ -159,6 +159,13 @@ datum/controller/radio return 1 + proc/RegisterScrambler(var/Frequency) + var/datum/radio_frequency/frequency = frequencies[Frequency] + frequency.scrambled++ + + proc/UnregisterScrambler(var/Frequency) + var/datum/radio_frequency/frequency = frequencies[Frequency] + frequency.scrambled-- proc/return_frequency(var/frequency as num) var/f_text = num2text(frequency) return frequencies[f_text] @@ -166,6 +173,7 @@ datum/controller/radio datum/radio_frequency var/frequency as num var/list/list/obj/devices = list() + var/scrambled = 0 proc post_signal(obj/source as obj|null, datum/signal/signal, var/filter = null as text|null, var/range = null as num|null) @@ -173,6 +181,8 @@ datum/radio_frequency // var/N_f=0 // var/N_nf=0 // var/Nt=0 + if(scrambled) + return var/turf/start_point if(range) start_point = get_turf(source) diff --git a/code/game/events/Event.dm b/code/game/events/Event.dm new file mode 100644 index 00000000000..0616ebe32f8 --- /dev/null +++ b/code/game/events/Event.dm @@ -0,0 +1,20 @@ +/datum/event + + var/Lifetime = 0 + var/ActiveFor = 0 + + New() + ..() + if(!Lifetime) + Lifetime = rand(30, 120) + + proc + Announce() + + Tick() + + Die() + + LongTerm() + LongTermEvent = ActiveEvent + ActiveEvent = null \ No newline at end of file diff --git a/code/game/gamemodes/events/black_hole.dm b/code/game/events/EventProcs/black_hole.dm similarity index 95% rename from code/game/gamemodes/events/black_hole.dm rename to code/game/events/EventProcs/black_hole.dm index 4320e444e84..12d0a20f7df 100644 --- a/code/game/gamemodes/events/black_hole.dm +++ b/code/game/events/EventProcs/black_hole.dm @@ -1,87 +1,87 @@ -/obj/effect/bhole - name = "black hole" - icon = 'objects.dmi' - desc = "FUCK FUCK FUCK AAAHHH" - icon_state = "bhole2" - opacity = 0 - unacidable = 1 - density = 0 - anchored = 1 - var/datum/effect/effect/system/harmless_smoke_spread/smoke - - -/obj/effect/bhole/New() - src.smoke = new /datum/effect/effect/system/harmless_smoke_spread() - src.smoke.set_up(5, 0, src) - src.smoke.attach(src) - src:life() - - -/obj/effect/bhole/Bumped(atom/A) - if (istype(A,/mob/living)) - del(A) - else - A:ex_act(1.0) - - -/obj/effect/bhole/proc/life() //Oh man , this will LAG - - if (prob(10)) - src.anchored = 0 - step(src,pick(alldirs)) - if (prob(30)) - step(src,pick(alldirs)) - src.anchored = 1 - - for (var/atom/X in orange(9,src)) - if ((istype(X,/obj) || istype(X,/mob/living)) && prob(7)) - if (!X:anchored) - step_towards(X,src) - - for (var/atom/B in orange(7,src)) - if (istype(B,/obj)) - if (!B:anchored && prob(50)) - step_towards(B,src) - if(prob(10)) B:ex_act(3.0) - else - B:anchored = 0 - //step_towards(B,src) - //B:anchored = 1 - if(prob(10)) B:ex_act(3.0) - else if (istype(B,/turf)) - if (istype(B,/turf/simulated) && (prob(1) && prob(75))) - src.smoke.start() - B:ReplaceWithSpace() - else if (istype(B,/mob/living)) - step_towards(B,src) - - - for (var/atom/A in orange(4,src)) - if (istype(A,/obj)) - if (!A:anchored && prob(90)) - step_towards(A,src) - if(prob(30)) A:ex_act(2.0) - else - A:anchored = 0 - //step_towards(A,src) - //A:anchored = 1 - if(prob(30)) A:ex_act(2.0) - else if (istype(A,/turf)) - if (istype(A,/turf/simulated) && prob(1)) - src.smoke.start() - A:ReplaceWithSpace() - else if (istype(A,/mob/living)) - step_towards(A,src) - - - for (var/atom/D in orange(1,src)) - //if (hascall(D,"blackholed")) - // call(D,"blackholed")(null) - // continue - if (istype(D,/mob/living)) - del(D) - else - D:ex_act(1.0) - - spawn(17) +/obj/effect/bhole + name = "black hole" + icon = 'objects.dmi' + desc = "FUCK FUCK FUCK AAAHHH" + icon_state = "bhole2" + opacity = 0 + unacidable = 1 + density = 0 + anchored = 1 + var/datum/effect/effect/system/harmless_smoke_spread/smoke + + +/obj/effect/bhole/New() + src.smoke = new /datum/effect/effect/system/harmless_smoke_spread() + src.smoke.set_up(5, 0, src) + src.smoke.attach(src) + src:life() + + +/obj/effect/bhole/Bumped(atom/A) + if (istype(A,/mob/living)) + del(A) + else + A:ex_act(1.0) + + +/obj/effect/bhole/proc/life() //Oh man , this will LAG + + if (prob(10)) + src.anchored = 0 + step(src,pick(alldirs)) + if (prob(30)) + step(src,pick(alldirs)) + src.anchored = 1 + + for (var/atom/X in orange(9,src)) + if ((istype(X,/obj) || istype(X,/mob/living)) && prob(7)) + if (!X:anchored) + step_towards(X,src) + + for (var/atom/B in orange(7,src)) + if (istype(B,/obj)) + if (!B:anchored && prob(50)) + step_towards(B,src) + if(prob(10)) B:ex_act(3.0) + else + B:anchored = 0 + //step_towards(B,src) + //B:anchored = 1 + if(prob(10)) B:ex_act(3.0) + else if (istype(B,/turf)) + if (istype(B,/turf/simulated) && (prob(1) && prob(75))) + src.smoke.start() + B:ReplaceWithSpace() + else if (istype(B,/mob/living)) + step_towards(B,src) + + + for (var/atom/A in orange(4,src)) + if (istype(A,/obj)) + if (!A:anchored && prob(90)) + step_towards(A,src) + if(prob(30)) A:ex_act(2.0) + else + A:anchored = 0 + //step_towards(A,src) + //A:anchored = 1 + if(prob(30)) A:ex_act(2.0) + else if (istype(A,/turf)) + if (istype(A,/turf/simulated) && prob(1)) + src.smoke.start() + A:ReplaceWithSpace() + else if (istype(A,/mob/living)) + step_towards(A,src) + + + for (var/atom/D in orange(1,src)) + //if (hascall(D,"blackholed")) + // call(D,"blackholed")(null) + // continue + if (istype(D,/mob/living)) + del(D) + else + D:ex_act(1.0) + + spawn(17) life() \ No newline at end of file diff --git a/code/game/gamemodes/events/clang.dm b/code/game/events/EventProcs/clang.dm similarity index 93% rename from code/game/gamemodes/events/clang.dm rename to code/game/events/EventProcs/clang.dm index ddfd81f5ff2..e02f79665a2 100644 --- a/code/game/gamemodes/events/clang.dm +++ b/code/game/events/EventProcs/clang.dm @@ -1,82 +1,82 @@ -/* -Immovable rod random event. -The rod will spawn at some location outside the station, and travel in a straight line to the opposite side of the station -Everything solid in the way will be ex_act()'d -In my current plan for it, 'solid' will be defined as anything with density == 1 - ---NEOFite -*/ - -/obj/effect/immovablerod - name = "Immovable Rod" - desc = "What the fuck is that?" - icon = 'objects.dmi' - icon_state = "immrod" - throwforce = 100 - density = 1 - anchored = 1 - - Bump(atom/clong) - if (istype(clong, /turf)) - if(clong.density) - clong.ex_act(2) - for (var/mob/O in hearers(src, null)) - O.show_message("CLANG", 2) - if (istype(clong, /obj)) - if(clong.density) - clong.ex_act(2) - for (var/mob/O in hearers(src, null)) - O.show_message("CLANG", 2) - if (istype(clong, /mob)) - if(clong.density || prob(10)) - clong.meteorhit(src) - if(clong && prob(25)) - src.loc = clong.loc - -/proc/immovablerod() - - var/startx = 0 - var/starty = 0 - var/endy = 0 - var/endx = 0 - var/startside = pick(cardinal) - - switch(startside) - if(NORTH) - starty = 187 - startx = rand(41, 199) - endy = 38 - endx = rand(41, 199) - if(EAST) - starty = rand(38, 187) - startx = 199 - endy = rand(38, 187) - endx = 41 - if(SOUTH) - starty = 38 - startx = rand(41, 199) - endy = 187 - endx = rand(41, 199) - if(WEST) - starty = rand(38, 187) - startx = 41 - endy = rand(38, 187) - endx = 199 - - //rod time! - var/obj/effect/immovablerod/immrod = new /obj/effect/immovablerod(locate(startx, starty, 1)) -// world << "Rod in play, starting at [start.loc.x],[start.loc.y] and going to [end.loc.x],[end.loc.y]" - var/end = locate(endx, endy, 1) - spawn(0) - walk_towards(immrod, end,1) - sleep(1) - while (immrod) - if (immrod.z != 1) - immrod.z = 1 - if(immrod.loc == end) - del(immrod) - sleep(10) - for(var/obj/effect/immovablerod/imm in world) - return - sleep(50) +/* +Immovable rod random event. +The rod will spawn at some location outside the station, and travel in a straight line to the opposite side of the station +Everything solid in the way will be ex_act()'d +In my current plan for it, 'solid' will be defined as anything with density == 1 + +--NEOFite +*/ + +/obj/effect/immovablerod + name = "Immovable Rod" + desc = "What the fuck is that?" + icon = 'objects.dmi' + icon_state = "immrod" + throwforce = 100 + density = 1 + anchored = 1 + + Bump(atom/clong) + if (istype(clong, /turf)) + if(clong.density) + clong.ex_act(2) + for (var/mob/O in hearers(src, null)) + O.show_message("CLANG", 2) + if (istype(clong, /obj)) + if(clong.density) + clong.ex_act(2) + for (var/mob/O in hearers(src, null)) + O.show_message("CLANG", 2) + if (istype(clong, /mob)) + if(clong.density || prob(10)) + clong.meteorhit(src) + if(clong && prob(25)) + src.loc = clong.loc + +/proc/immovablerod() + + var/startx = 0 + var/starty = 0 + var/endy = 0 + var/endx = 0 + var/startside = pick(cardinal) + + switch(startside) + if(NORTH) + starty = 187 + startx = rand(41, 199) + endy = 38 + endx = rand(41, 199) + if(EAST) + starty = rand(38, 187) + startx = 199 + endy = rand(38, 187) + endx = 41 + if(SOUTH) + starty = 38 + startx = rand(41, 199) + endy = 187 + endx = rand(41, 199) + if(WEST) + starty = rand(38, 187) + startx = 41 + endy = rand(38, 187) + endx = 199 + + //rod time! + var/obj/effect/immovablerod/immrod = new /obj/effect/immovablerod(locate(startx, starty, 1)) +// world << "Rod in play, starting at [start.loc.x],[start.loc.y] and going to [end.loc.x],[end.loc.y]" + var/end = locate(endx, endy, 1) + spawn(0) + walk_towards(immrod, end,1) + sleep(1) + while (immrod) + if (immrod.z != 1) + immrod.z = 1 + if(immrod.loc == end) + del(immrod) + sleep(10) + for(var/obj/effect/immovablerod/imm in world) + return + sleep(50) command_alert("What the fuck was that?!", "General Alert") \ No newline at end of file diff --git a/code/game/gamemodes/events/dust.dm b/code/game/events/EventProcs/dust.dm similarity index 94% rename from code/game/gamemodes/events/dust.dm rename to code/game/events/EventProcs/dust.dm index dc2989f5d3e..d7a7def9112 100644 --- a/code/game/gamemodes/events/dust.dm +++ b/code/game/events/EventProcs/dust.dm @@ -1,119 +1,119 @@ -/* -Space dust -Commonish random event that causes small clumps of "space dust" to hit the station at high speeds. -No command report on the common version of this event. -The "dust" will damage the hull of the station causin minor hull breaches. -*/ - -/proc/dust_swarm(var/strength = "weak") - var/numbers = 1 - switch(strength) - if("weak") - numbers = rand(2,4) - for(var/i = 0 to numbers) - new/obj/effect/space_dust/weak() - if("norm") - numbers = rand(5,10) - for(var/i = 0 to numbers) - new/obj/effect/space_dust() - if("strong") - numbers = rand(10,15) - for(var/i = 0 to numbers) - new/obj/effect/space_dust/strong() - if("super") - numbers = rand(15,25) - for(var/i = 0 to numbers) - new/obj/effect/space_dust/super() - return - - -/obj/effect/space_dust - name = "Space Dust" - desc = "Dust in space." - icon = 'meteor.dmi' - icon_state = "space_dust" - density = 1 - anchored = 1 - var - strength = 2 //ex_act severity number - life = 2 //how many things we hit before del(src) - - weak - strength = 3 - life = 1 - - strong - strength = 1 - life = 6 - - super - strength = 1 - life = 40 - - - New() - var/startx = 0 - var/starty = 0 - var/endy = 0 - var/endx = 0 - var/startside = pick(cardinal) - - switch(startside) - if(NORTH) - starty = world.maxy-1 - startx = rand(1, world.maxx-1) - endy = 1 - endx = rand(1, world.maxx-1) - if(EAST) - starty = rand(1,world.maxy-1) - startx = world.maxx-1 - endy = rand(1, world.maxy-1) - endx = 1 - if(SOUTH) - starty = 1 - startx = rand(1, world.maxx-1) - endy = world.maxy-1 - endx = rand(1, world.maxx-1) - if(WEST) - starty = rand(1, world.maxy-1) - startx = 1 - endy = rand(1,world.maxy-1) - endx = world.maxx-1 - var/goal = locate(endx, endy, 1) - src.x = startx - src.y = starty - src.z = 1 - spawn(0) - walk_towards(src, goal, 1) - return - - - Bump(atom/A) - spawn(0) - if(prob(50)) - for(var/mob/M in range(10, src)) - if(!M.stat && !istype(M, /mob/living/silicon/ai)) - shake_camera(M, 3, 1) - if (A) - playsound(src.loc, 'meteorimpact.ogg', 40, 1) - if(ismob(A)) - A.meteorhit(src)//This should work for now I guess - else - A.ex_act(strength) - life-- - if(life <= 0) - walk(src,0) - spawn(1) - del(src) - return 0 - return - - - Bumped(atom/A) - Bump(A) - return - - - ex_act(severity) - del(src) +/* +Space dust +Commonish random event that causes small clumps of "space dust" to hit the station at high speeds. +No command report on the common version of this event. +The "dust" will damage the hull of the station causin minor hull breaches. +*/ + +/proc/dust_swarm(var/strength = "weak") + var/numbers = 1 + switch(strength) + if("weak") + numbers = rand(2,4) + for(var/i = 0 to numbers) + new/obj/effect/space_dust/weak() + if("norm") + numbers = rand(5,10) + for(var/i = 0 to numbers) + new/obj/effect/space_dust() + if("strong") + numbers = rand(10,15) + for(var/i = 0 to numbers) + new/obj/effect/space_dust/strong() + if("super") + numbers = rand(15,25) + for(var/i = 0 to numbers) + new/obj/effect/space_dust/super() + return + + +/obj/effect/space_dust + name = "Space Dust" + desc = "Dust in space." + icon = 'meteor.dmi' + icon_state = "space_dust" + density = 1 + anchored = 1 + var + strength = 2 //ex_act severity number + life = 2 //how many things we hit before del(src) + + weak + strength = 3 + life = 1 + + strong + strength = 1 + life = 6 + + super + strength = 1 + life = 40 + + + New() + var/startx = 0 + var/starty = 0 + var/endy = 0 + var/endx = 0 + var/startside = pick(cardinal) + + switch(startside) + if(NORTH) + starty = world.maxy-1 + startx = rand(1, world.maxx-1) + endy = 1 + endx = rand(1, world.maxx-1) + if(EAST) + starty = rand(1,world.maxy-1) + startx = world.maxx-1 + endy = rand(1, world.maxy-1) + endx = 1 + if(SOUTH) + starty = 1 + startx = rand(1, world.maxx-1) + endy = world.maxy-1 + endx = rand(1, world.maxx-1) + if(WEST) + starty = rand(1, world.maxy-1) + startx = 1 + endy = rand(1,world.maxy-1) + endx = world.maxx-1 + var/goal = locate(endx, endy, 1) + src.x = startx + src.y = starty + src.z = 1 + spawn(0) + walk_towards(src, goal, 1) + return + + + Bump(atom/A) + spawn(0) + if(prob(50)) + for(var/mob/M in range(10, src)) + if(!M.stat && !istype(M, /mob/living/silicon/ai)) + shake_camera(M, 3, 1) + if (A) + playsound(src.loc, 'meteorimpact.ogg', 40, 1) + if(ismob(A)) + A.meteorhit(src)//This should work for now I guess + else + A.ex_act(strength) + life-- + if(life <= 0) + walk(src,0) + spawn(1) + del(src) + return 0 + return + + + Bumped(atom/A) + Bump(A) + return + + + ex_act(severity) + del(src) return \ No newline at end of file diff --git a/code/game/gamemodes/events/kudzu.dm b/code/game/events/EventProcs/kudzu.dm similarity index 96% rename from code/game/gamemodes/events/kudzu.dm rename to code/game/events/EventProcs/kudzu.dm index 5281f43cf57..17d2215eb85 100644 --- a/code/game/gamemodes/events/kudzu.dm +++ b/code/game/events/EventProcs/kudzu.dm @@ -1,176 +1,176 @@ -// SPACE VINE OR KUDZU - -/obj/effect/spacevine - name = "Space Kudzu" - desc = "An extremely expansionistic species of vine." - icon = 'kudzu.dmi' - icon_state = "Light1" - anchored = 1 - density = 0 - var/energy = 0 //Energy sounds like an arbitrary-enough variable name. - var/obj/effect/spacevine_controller/master = null - - New() - if(istype(src.loc, /turf/space)) - del(src) - return - - Del() - if(master) - master.vines -= src - master.growth_queue -= src - ..() - - attackby(obj/item/weapon/W as obj, mob/user as mob) - if (!W) return - if (!user) return - if (istype(W, /obj/item/weapon/circular_saw)) del src - if (istype(W, /obj/item/weapon/kitchen/utensil/knife)) del src - if (istype(W, /obj/item/weapon/scalpel)) del src - if (istype(W, /obj/item/weapon/screwdriver)) del src - if (istype(W, /obj/item/weapon/shard)) del src - if (istype(W, /obj/item/weapon/weldingtool)) del src - if (istype(W, /obj/item/weapon/wirecutters)) del src - ..() - -/obj/effect/spacevine_controller - var/list/obj/effect/spacevine/vines = list() - var/list/growth_queue = list() - var/reached_collapse_size - var/reached_slowdown_size - //What this does is that instead of having the grow minimum of 1, required to start growing, the minimum will be 0, - //meaning if you get the kudzu's size to something less than 20 plots, it won't grow anymore. - - New() - if(!istype(src.loc,/turf/simulated/floor)) - del(src) - - spawn_kudzu_piece(src.loc) - processing_objects.Add(src) - - Del() - processing_objects.Remove(src) - ..() - - proc/spawn_kudzu_piece(var/turf/location) - var/obj/effect/spacevine/SV = new(location) - growth_queue += SV - vines += SV - SV.master = src - - process() - if(!vines) - del(src) //Kudzu exterminated - return - if(!growth_queue) - del(src) //Sanity check - return - if(vines.len >= 250 && !reached_collapse_size) - reached_collapse_size = 1 - if(vines.len >= 30 && !reached_slowdown_size ) - reached_slowdown_size = 1 - - var/length = 0 - if(reached_collapse_size) - length = 0 - else if(reached_slowdown_size) - if(prob(25)) - length = 1 - else - length = 0 - else - length = 1 - length = min( 30 , max( length , vines.len / 5 ) ) - var/i = 0 - var/list/obj/effect/spacevine/queue_end = list() - - for( var/obj/effect/spacevine/SV in growth_queue ) - i++ - queue_end += SV - growth_queue -= SV - if(SV.energy < 2) - if(prob(10)) - SV.grow() - //if(prob(25)) - SV.spread() - if(i >= length) - break - - growth_queue = growth_queue + queue_end - - //sleep(5) - //src.process() - -/obj/effect/spacevine/proc/grow() - switch(energy) - if (0) - src.icon_state = pick("Med1", "Med2", "Med3") - energy = 1 - src.opacity = 1 - if (1) - src.icon_state = pick("Hvy1", "Hvy2", "Hvy3") - energy = 2 - src.density = 1 - -/obj/effect/spacevine/proc/spread() - var/direction = pick(cardinal) - if(istype(get_step(src,direction),/turf/simulated/floor)) - var/turf/simulated/floor/F = get_step(src,direction) - if(!locate(/obj/effect/spacevine,F)) - if(F.Enter(src)) - if(master) - master.spawn_kudzu_piece( F ) - - -/* -/obj/effect/spacevine/proc/Life() - if (!src) return - var/Vspread - if (prob(50)) Vspread = locate(src.x + rand(-1,1),src.y,src.z) - else Vspread = locate(src.x,src.y + rand(-1, 1),src.z) - var/dogrowth = 1 - if (!istype(Vspread, /turf/simulated/floor)) dogrowth = 0 - for(var/obj/O in Vspread) - if (istype(O, /obj/structure/window) || istype(O, /obj/effect/forcefield) || istype(O, /obj/effect/blob) || istype(O, /obj/effect/alien/weeds) || istype(O, /obj/effect/spacevine)) dogrowth = 0 - if (istype(O, /obj/machinery/door/)) - if(O:p_open == 0 && prob(50)) O:open() - else dogrowth = 0 - if (dogrowth == 1) - var/obj/effect/spacevine/B = new /obj/effect/spacevine(Vspread) - B.icon_state = pick("vine-light1", "vine-light2", "vine-light3") - spawn(20) - if(B) - B.Life() - src.growth += 1 - if (src.growth == 10) - src.name = "Thick Space Kudzu" - src.icon_state = pick("vine-med1", "vine-med2", "vine-med3") - src.opacity = 1 - src.waittime = 80 - if (src.growth == 20) - src.name = "Dense Space Kudzu" - src.icon_state = pick("vine-hvy1", "vine-hvy2", "vine-hvy3") - src.density = 1 - spawn(src.waittime) - if (src.growth < 20) src.Life() - -*/ - -/obj/effect/spacevine/ex_act(severity) - switch(severity) - if(1.0) - del(src) - return - if(2.0) - if (prob(90)) - del(src) - return - if(3.0) - if (prob(50)) - del(src) - return - else - return - -/obj/effect/spacevine/temperature_expose(null, temp, volume) +// SPACE VINE OR KUDZU + +/obj/effect/spacevine + name = "Space Kudzu" + desc = "An extremely expansionistic species of vine." + icon = 'kudzu.dmi' + icon_state = "Light1" + anchored = 1 + density = 0 + var/energy = 0 //Energy sounds like an arbitrary-enough variable name. + var/obj/effect/spacevine_controller/master = null + + New() + if(istype(src.loc, /turf/space)) + del(src) + return + + Del() + if(master) + master.vines -= src + master.growth_queue -= src + ..() + + attackby(obj/item/weapon/W as obj, mob/user as mob) + if (!W) return + if (!user) return + if (istype(W, /obj/item/weapon/circular_saw)) del src + if (istype(W, /obj/item/weapon/kitchen/utensil/knife)) del src + if (istype(W, /obj/item/weapon/scalpel)) del src + if (istype(W, /obj/item/weapon/screwdriver)) del src + if (istype(W, /obj/item/weapon/shard)) del src + if (istype(W, /obj/item/weapon/weldingtool)) del src + if (istype(W, /obj/item/weapon/wirecutters)) del src + ..() + +/obj/effect/spacevine_controller + var/list/obj/effect/spacevine/vines = list() + var/list/growth_queue = list() + var/reached_collapse_size + var/reached_slowdown_size + //What this does is that instead of having the grow minimum of 1, required to start growing, the minimum will be 0, + //meaning if you get the kudzu's size to something less than 20 plots, it won't grow anymore. + + New() + if(!istype(src.loc,/turf/simulated/floor)) + del(src) + + spawn_kudzu_piece(src.loc) + processing_objects.Add(src) + + Del() + processing_objects.Remove(src) + ..() + + proc/spawn_kudzu_piece(var/turf/location) + var/obj/effect/spacevine/SV = new(location) + growth_queue += SV + vines += SV + SV.master = src + + process() + if(!vines) + del(src) //Kudzu exterminated + return + if(!growth_queue) + del(src) //Sanity check + return + if(vines.len >= 250 && !reached_collapse_size) + reached_collapse_size = 1 + if(vines.len >= 30 && !reached_slowdown_size ) + reached_slowdown_size = 1 + + var/length = 0 + if(reached_collapse_size) + length = 0 + else if(reached_slowdown_size) + if(prob(25)) + length = 1 + else + length = 0 + else + length = 1 + length = min( 30 , max( length , vines.len / 5 ) ) + var/i = 0 + var/list/obj/effect/spacevine/queue_end = list() + + for( var/obj/effect/spacevine/SV in growth_queue ) + i++ + queue_end += SV + growth_queue -= SV + if(SV.energy < 2) + if(prob(10)) + SV.grow() + //if(prob(25)) + SV.spread() + if(i >= length) + break + + growth_queue = growth_queue + queue_end + + //sleep(5) + //src.process() + +/obj/effect/spacevine/proc/grow() + switch(energy) + if (0) + src.icon_state = pick("Med1", "Med2", "Med3") + energy = 1 + src.opacity = 1 + if (1) + src.icon_state = pick("Hvy1", "Hvy2", "Hvy3") + energy = 2 + src.density = 1 + +/obj/effect/spacevine/proc/spread() + var/direction = pick(cardinal) + if(istype(get_step(src,direction),/turf/simulated/floor)) + var/turf/simulated/floor/F = get_step(src,direction) + if(!locate(/obj/effect/spacevine,F)) + if(F.Enter(src)) + if(master) + master.spawn_kudzu_piece( F ) + + +/* +/obj/effect/spacevine/proc/Life() + if (!src) return + var/Vspread + if (prob(50)) Vspread = locate(src.x + rand(-1,1),src.y,src.z) + else Vspread = locate(src.x,src.y + rand(-1, 1),src.z) + var/dogrowth = 1 + if (!istype(Vspread, /turf/simulated/floor)) dogrowth = 0 + for(var/obj/O in Vspread) + if (istype(O, /obj/structure/window) || istype(O, /obj/effect/forcefield) || istype(O, /obj/effect/blob) || istype(O, /obj/effect/alien/weeds) || istype(O, /obj/effect/spacevine)) dogrowth = 0 + if (istype(O, /obj/machinery/door/)) + if(O:p_open == 0 && prob(50)) O:open() + else dogrowth = 0 + if (dogrowth == 1) + var/obj/effect/spacevine/B = new /obj/effect/spacevine(Vspread) + B.icon_state = pick("vine-light1", "vine-light2", "vine-light3") + spawn(20) + if(B) + B.Life() + src.growth += 1 + if (src.growth == 10) + src.name = "Thick Space Kudzu" + src.icon_state = pick("vine-med1", "vine-med2", "vine-med3") + src.opacity = 1 + src.waittime = 80 + if (src.growth == 20) + src.name = "Dense Space Kudzu" + src.icon_state = pick("vine-hvy1", "vine-hvy2", "vine-hvy3") + src.density = 1 + spawn(src.waittime) + if (src.growth < 20) src.Life() + +*/ + +/obj/effect/spacevine/ex_act(severity) + switch(severity) + if(1.0) + del(src) + return + if(2.0) + if (prob(90)) + del(src) + return + if(3.0) + if (prob(50)) + del(src) + return + else + return + +/obj/effect/spacevine/temperature_expose(null, temp, volume) del src \ No newline at end of file diff --git a/code/game/gamemodes/events/miniblob.dm b/code/game/events/EventProcs/miniblob.dm similarity index 94% rename from code/game/gamemodes/events/miniblob.dm rename to code/game/events/EventProcs/miniblob.dm index 5522f6041f4..b9cd328c257 100644 --- a/code/game/gamemodes/events/miniblob.dm +++ b/code/game/events/EventProcs/miniblob.dm @@ -1,33 +1,33 @@ -/proc/mini_blob_event() - //command_alert("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert") - //world << sound('outbreak5.ogg') - var/turf/T = pick(blobstart) - var/obj/effect/blob/bl = new /obj/effect/blob( T.loc, 30 ) - spawn(0) - bl.Life() - bl.Life() - bl.Life() - bl.Life() - bl.blobdebug = 1 - bl.Life() - blobevent = 1 - spawn(0) - dotheblobbaby() - spawn(3000) - blobevent = 0 - spawn(rand(3000, 6000)) //Delayed announcements to keep the crew on their toes. - command_alert("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert") - world << sound('outbreak5.ogg') - -/proc/dotheblobbaby() - if (blobevent) - if(active_blobs.len) - for(var/i = 1 to 10) - sleep(-1) - if(!active_blobs.len) break - var/obj/effect/blob/B = pick(active_blobs) - if(B.z != 1) - continue - B.Life() - spawn(30) +/proc/mini_blob_event() + //command_alert("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert") + //world << sound('outbreak5.ogg') + var/turf/T = pick(blobstart) + var/obj/effect/blob/bl = new /obj/effect/blob( T.loc, 30 ) + spawn(0) + bl.Life() + bl.Life() + bl.Life() + bl.Life() + bl.blobdebug = 1 + bl.Life() + blobevent = 1 + spawn(0) + dotheblobbaby() + spawn(3000) + blobevent = 0 + spawn(rand(3000, 6000)) //Delayed announcements to keep the crew on their toes. + command_alert("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert") + world << sound('outbreak5.ogg') + +/proc/dotheblobbaby() + if (blobevent) + if(active_blobs.len) + for(var/i = 1 to 10) + sleep(-1) + if(!active_blobs.len) break + var/obj/effect/blob/B = pick(active_blobs) + if(B.z != 1) + continue + B.Life() + spawn(30) dotheblobbaby() \ No newline at end of file diff --git a/code/game/events/EventProcs/misc.dm b/code/game/events/EventProcs/misc.dm new file mode 100644 index 00000000000..93945ec70b4 --- /dev/null +++ b/code/game/events/EventProcs/misc.dm @@ -0,0 +1,71 @@ +/proc/power_failure() + command_alert("Abnormal activity detected in [station_name()]'s powernet. As a precautionary measure, the station's power will be shut off for an indeterminate duration.", "Critical Power Failure") + world << sound('poweroff.ogg') + for(var/obj/machinery/power/apc/C in world) + if(C.cell && C.z == 1) + C.cell.charge = 0 + for(var/obj/machinery/power/smes/S in world) + if(istype(get_area(S), /area/turret_protected) || S.z != 1) + continue + S.charge = 0 + S.output = 0 + S.online = 0 + S.updateicon() + S.power_change() + for(var/area/A in world) + if(A.name != "Space" && A.name != "Engine Walls" && A.name != "Chemical Lab Test Chamber" && A.name != "Escape Shuttle" && A.name != "Arrival Area" && A.name != "Arrival Shuttle" && A.name != "start area" && A.name != "Engine Combustion Chamber") + A.power_light = 0 + A.power_equip = 0 + A.power_environ = 0 + A.power_change() + +/proc/power_restore() + command_alert("Power has been restored to [station_name()]. We apologize for the inconvenience.", "Power Systems Nominal") + world << sound('poweron.ogg') + for(var/obj/machinery/power/apc/C in world) + if(C.cell && C.z == 1) + C.cell.charge = C.cell.maxcharge + for(var/obj/machinery/power/smes/S in world) + if(S.z != 1) + continue + S.charge = S.capacity + S.output = 200000 + S.online = 1 + S.updateicon() + S.power_change() + for(var/area/A in world) + if(A.name != "Space" && A.name != "Engine Walls" && A.name != "Chemical Lab Test Chamber" && A.name != "space" && A.name != "Escape Shuttle" && A.name != "Arrival Area" && A.name != "Arrival Shuttle" && A.name != "start area" && A.name != "Engine Combustion Chamber") + A.power_light = 1 + A.power_equip = 1 + A.power_environ = 1 + A.power_change() + +/proc/lightsout(isEvent = 0, lightsoutAmount = 1,lightsoutRange = 10) //leave lightsoutAmount as 0 to break ALL lights + if(isEvent) + command_alert("An Electrical storm has been detected in your area, please repair potential electronic overloads.","Electrical Storm Alert") + + if(lightsoutAmount) + var/list/epicentreList = list() + + for(var/i=1,i<=lightsoutAmount,i++) + var/list/possibleEpicentres = list() + for(var/obj/effect/landmark/newEpicentre in world) + if(newEpicentre.name == "lightsout" && !(newEpicentre in epicentreList)) + possibleEpicentres += newEpicentre + if(possibleEpicentres.len) + epicentreList += pick(possibleEpicentres) + else + break + + if(!epicentreList.len) + return + + for(var/obj/effect/landmark/epicentre in epicentreList) + for(var/obj/machinery/power/apc/apc in range(epicentre,lightsoutRange)) + apc.overload_lighting() + + else + for(var/obj/machinery/power/apc/apc in world) + apc.overload_lighting() + + return \ No newline at end of file diff --git a/code/game/gamemodes/events/ninja_abilities.dm b/code/game/events/EventProcs/ninja_abilities.dm similarity index 97% rename from code/game/gamemodes/events/ninja_abilities.dm rename to code/game/events/EventProcs/ninja_abilities.dm index ec08ae9d6fb..fd17477f691 100644 --- a/code/game/gamemodes/events/ninja_abilities.dm +++ b/code/game/events/EventProcs/ninja_abilities.dm @@ -1,429 +1,429 @@ -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+++++++++++++++++++++++++++++++++// //++++++++++++++++++++++++++++++++++ -==================================SPACE NINJA ABILITIES==================================== -___________________________________________________________________________________________ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -*/ - -//=======//SAFETY CHECK//=======// -/* -X is optional, tells the proc to check for specific stuff. C is also optional. -All the procs here assume that the character is wearing the ninja suit if they are using the procs. -They should, as I have made every effort for that to be the case. -In the case that they are not, I imagine the game will run-time error like crazy. -s_cooldown ticks off each second based on the suit recharge proc, in seconds. Default of 1 seconds. Some abilities have no cool down. -*/ -/obj/item/clothing/suit/space/space_ninja/proc/ninjacost(C = 0,X = 0) - var/mob/living/carbon/human/U = affecting - if( (U.stat||U.incorporeal_move)&&X!=3 )//Will not return if user is using an adrenaline booster since you can use them when stat==1. - U << "\red You must be conscious and solid to do this."//It's not a problem of stat==2 since the ninja will explode anyway if they die. - return 1 - else if(C&&cell.charge[s_bombs] smoke bombs remaining." - var/datum/effect/effect/system/bad_smoke_spread/smoke = new /datum/effect/effect/system/bad_smoke_spread() - smoke.set_up(10, 0, U.loc) - smoke.start() - playsound(U.loc, 'bamf.ogg', 50, 2) - s_bombs-- - s_coold = 1 - return - -//=======//9-8 TILE TELEPORT//=======// -//Click to to teleport 9-10 tiles in direction facing. -/obj/item/clothing/suit/space/space_ninja/proc/ninjajaunt() - set name = "Phase Jaunt (10E)" - set desc = "Utilizes the internal VOID-shift device to rapidly transit in direction facing." - set category = "Ninja Ability" - set popup_menu = 0 - - var/C = 100 - if(!ninjacost(C,1)) - var/mob/living/carbon/human/U = affecting - var/turf/destination = get_teleport_loc(U.loc,U,9,1,3,1,0,1) - var/turf/mobloc = get_turf(U.loc)//To make sure that certain things work properly below. - if(destination&&istype(mobloc, /turf))//The turf check prevents unusual behavior. Like teleporting out of cryo pods, cloners, mechs, etc. - spawn(0) - playsound(U.loc, "sparks", 50, 1) - anim(mobloc,src,'mob.dmi',,"phaseout",,U.dir) - - handle_teleport_grab(destination, U) - U.loc = destination - - spawn(0) - spark_system.start() - playsound(U.loc, 'phasein.ogg', 25, 1) - playsound(U.loc, "sparks", 50, 1) - anim(U.loc,U,'mob.dmi',,"phasein",,U.dir) - - spawn(0) - destination.kill_creatures(U)//Any living mobs in teleport area are gibbed. Check turf procs for how it does it. - s_coold = 1 - cell.charge-=(C*10) - else - U << "\red The VOID-shift device is malfunctioning, teleportation failed." - return - -//=======//RIGHT CLICK TELEPORT//=======// -//Right click to teleport somewhere, almost exactly like admin jump to turf. -/obj/item/clothing/suit/space/space_ninja/proc/ninjashift(turf/T in oview()) - set name = "Phase Shift (20E)" - set desc = "Utilizes the internal VOID-shift device to rapidly transit to a destination in view." - set category = null//So it does not show up on the panel but can still be right-clicked. - set src = usr.contents//Fixes verbs not attaching properly for objects. Praise the DM reference guide! - - var/C = 200 - if(!ninjacost(C,1)) - var/mob/living/carbon/human/U = affecting - var/turf/mobloc = get_turf(U.loc)//To make sure that certain things work properly below. - if((!T.density)&&istype(mobloc, /turf)) - spawn(0) - playsound(U.loc, 'sparks4.ogg', 50, 1) - anim(mobloc,src,'mob.dmi',,"phaseout",,U.dir) - - handle_teleport_grab(T, U) - U.loc = T - - spawn(0) - spark_system.start() - playsound(U.loc, 'phasein.ogg', 25, 1) - playsound(U.loc, 'sparks2.ogg', 50, 1) - anim(U.loc,U,'mob.dmi',,"phasein",,U.dir) - - spawn(0)//Any living mobs in teleport area are gibbed. - T.kill_creatures(U) - s_coold = 1 - cell.charge-=(C*10) - else - U << "\red You cannot teleport into solid walls or from solid matter" - return - -//=======//EM PULSE//=======// -//Disables nearby tech equipment. -/obj/item/clothing/suit/space/space_ninja/proc/ninjapulse() - set name = "EM Burst (25E)" - set desc = "Disable any nearby technology with a electro-magnetic pulse." - set category = "Ninja Ability" - set popup_menu = 0 - - var/C = 250 - if(!ninjacost(C,1)) - var/mob/living/carbon/human/U = affecting - playsound(U.loc, 'EMPulse.ogg', 60, 2) - empulse(U, 4, 6) //Procs sure are nice. Slightly weaker than wizard's disable tch. - s_coold = 2 - cell.charge-=(C*10) - return - -//=======//ENERGY BLADE//=======// -//Summons a blade of energy in active hand. -/obj/item/clothing/suit/space/space_ninja/proc/ninjablade() - set name = "Energy Blade (5E)" - set desc = "Create a focused beam of energy in your active hand." - set category = "Ninja Ability" - set popup_menu = 0 - - var/C = 50 - if(!ninjacost(C)) - var/mob/living/carbon/human/U = affecting - if(!kamikaze) - if(!U.get_active_hand()&&!istype(U.get_inactive_hand(), /obj/item/weapon/melee/energy/blade)) - var/obj/item/weapon/melee/energy/blade/W = new() - spark_system.start() - playsound(U.loc, "sparks", 50, 1) - U.put_in_hand(W) - cell.charge-=(C*10) - else - U << "\red You can only summon one blade. Try dropping an item first." - else//Else you can run around with TWO energy blades. I don't know why you'd want to but cool factor remains. - if(!U.get_active_hand()) - var/obj/item/weapon/melee/energy/blade/W = new() - U.put_in_hand(W) - if(!U.get_inactive_hand()) - var/obj/item/weapon/melee/energy/blade/W = new() - U.put_in_inactive_hand(W) - spark_system.start() - playsound(U.loc, "sparks", 50, 1) - s_coold = 1 - return - -//=======//NINJA STARS//=======// -/*Shoots ninja stars at random people. -This could be a lot better but I'm too tired atm.*/ -/obj/item/clothing/suit/space/space_ninja/proc/ninjastar() - set name = "Energy Star (5E)" - set desc = "Launches an energy star at a random living target." - set category = "Ninja Ability" - set popup_menu = 0 - - var/C = 50 - if(!ninjacost(C)) - var/mob/living/carbon/human/U = affecting - var/targets[] = list()//So yo can shoot while yo throw dawg - for(var/mob/living/M in oview(loc)) - if(M.stat) continue//Doesn't target corpses or paralyzed persons. - targets.Add(M) - if(targets.len) - var/mob/living/target=pick(targets)//The point here is to pick a random, living mob in oview to shoot stuff at. - - var/turf/curloc = U.loc - var/atom/targloc = get_turf(target) - if (!targloc || !istype(targloc, /turf) || !curloc) - return - if (targloc == curloc) - return - var/obj/item/projectile/energy/dart/A = new /obj/item/projectile/energy/dart(U.loc) - A.current = curloc - A.yo = targloc.y - curloc.y - A.xo = targloc.x - curloc.x - cell.charge-=(C*10) - A.process() - else - U << "\red There are no targets in view." - return - -//=======//ENERGY NET//=======// -/*Allows the ninja to capture people, I guess. -Must right click on a mob to activate.*/ -/obj/item/clothing/suit/space/space_ninja/proc/ninjanet(mob/living/carbon/M in oview())//Only living carbon mobs. - set name = "Energy Net (20E)" - set desc = "Captures a fallen opponent in a net of energy. Will teleport them to a holding facility after 30 seconds." - set category = null - set src = usr.contents - - var/C = 200 - if(!ninjacost(C,1)&&iscarbon(M)) - var/mob/living/carbon/human/U = affecting - if(M.client)//Monkeys without a client can still step_to() and bypass the net. Also, netting inactive people is lame. - //if(M)//DEBUG - if(!locate(/obj/effect/energy_net) in M.loc)//Check if they are already being affected by an energy net. - for(var/turf/T in getline(U.loc, M.loc)) - if(T.density)//Don't want them shooting nets through walls. It's kind of cheesy. - U << "You may not use an energy net through solid obstacles!" - return - spawn(0) - U.Beam(M,"n_beam",,15) - M.anchored = 1//Anchors them so they can't move. - U.say("Get over here!") - var/obj/effect/energy_net/E = new /obj/effect/energy_net(M.loc) - E.layer = M.layer+1//To have it appear one layer above the mob. - for(var/mob/O in viewers(U, 3)) - O.show_message(text("\red [] caught [] with an energy net!", U, M), 1) - E.affecting = M - E.master = U - spawn(0)//Parallel processing. - E.process(M) - cell.charge-=(C*10) - else - U << "They are already trapped inside an energy net." - else - U << "They will bring no honor to your Clan!" - return - -//=======//ADRENALINE BOOST//=======// -/*Wakes the user so they are able to do their thing. Also injects a decent dose of radium. -Movement impairing would indicate drugs and the like.*/ -/obj/item/clothing/suit/space/space_ninja/proc/ninjaboost() - set name = "Adrenaline Boost" - set desc = "Inject a secret chemical that will counteract all movement-impairing effect." - set category = "Ninja Ability" - set popup_menu = 0 - - if(!ninjacost(,3))//Have to make sure stat is not counted for this ability. - var/mob/living/carbon/human/U = affecting - //Wouldn't need to track adrenaline boosters if there was a miracle injection to get rid of paralysis and the like instantly. - //For now, adrenaline boosters ARE the miracle injection. Well, radium, really. - U.SetParalysis(0) - U.SetStunned(0) - U.SetWeakened(0) - /* - Due to lag, it was possible to adrenaline boost but remain helpless while life.dm resets player stat. - This lead to me and others spamming adrenaline boosters because they failed to kick in on time. - It's technically possible to come back from crit with this but it is very temporary. - Life.dm will kick the player back into unconsciosness the next process loop. - */ - U.stat = 0//At least now you should be able to teleport away or shoot ninja stars. - spawn(30)//Slight delay so the enemy does not immedietly know the ability was used. Due to lag, this often came before waking up. - U.say(pick("A CORNERED FOX IS MORE DANGEROUS THAN A JACKAL!","HURT ME MOOORRREEE!","IMPRESSIVE!")) - spawn(70) - reagents.reaction(U, 2) - reagents.trans_id_to(U, "radium", a_transfer) - U << "\red You are beginning to feel the after-effect of the injection." - a_boost-- - s_coold = 3 - return - -/* -=================================================================================== -<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -=================================================================================== -Or otherwise known as anime mode. Which also happens to be ridiculously powerful. -*/ - -//=======//NINJA MOVEMENT//=======// -//Also makes you move like you're on crack. -/obj/item/clothing/suit/space/space_ninja/proc/ninjawalk() - set name = "Shadow Walk" - set desc = "Combines the VOID-shift and CLOAK-tech devices to freely move between solid matter. Toggle on or off." - set category = "Ninja Ability" - set popup_menu = 0 - - var/mob/living/carbon/human/U = affecting - if(!U.incorporeal_move) - U.incorporeal_move = 2 - U << "\blue You will now phase through solid matter." - else - U.incorporeal_move = 0 - U << "\blue You will no-longer phase through solid matter." - return - -//=======//5 TILE TELEPORT/GIB//=======// -//Allows to gib up to five squares in a straight line. Seriously. -/obj/item/clothing/suit/space/space_ninja/proc/ninjaslayer() - set name = "Phase Slayer" - set desc = "Utilizes the internal VOID-shift device to mutilate creatures in a straight line." - set category = "Ninja Ability" - set popup_menu = 0 - - if(!ninjacost()) - var/mob/living/carbon/human/U = affecting - var/turf/destination = get_teleport_loc(U.loc,U,5) - var/turf/mobloc = get_turf(U.loc)//To make sure that certain things work properly below. - if(destination&&istype(mobloc, /turf)) - U.say("Ai Satsugai!") - spawn(0) - playsound(U.loc, "sparks", 50, 1) - anim(mobloc,U,'mob.dmi',,"phaseout",,U.dir) - - spawn(0) - for(var/turf/T in getline(mobloc, destination)) - spawn(0) - T.kill_creatures(U) - if(T==mobloc||T==destination) continue - spawn(0) - anim(T,U,'mob.dmi',,"phasein",,U.dir) - - handle_teleport_grab(destination, U) - U.loc = destination - - spawn(0) - spark_system.start() - playsound(U.loc, 'phasein.ogg', 25, 1) - playsound(U.loc, "sparks", 50, 1) - anim(U.loc,U,'mob.dmi',,"phasein",,U.dir) - s_coold = 1 - else - U << "\red The VOID-shift device is malfunctioning, teleportation failed." - return - -//=======//TELEPORT BEHIND MOB//=======// -/*Appear behind a randomly chosen mob while a few decoy teleports appear. -This is so anime it hurts. But that's the point.*/ -/obj/item/clothing/suit/space/space_ninja/proc/ninjamirage() - set name = "Spider Mirage" - set desc = "Utilizes the internal VOID-shift device to create decoys and teleport behind a random target." - set category = "Ninja Ability" - set popup_menu = 0 - - if(!ninjacost())//Simply checks for stat. - var/mob/living/carbon/human/U = affecting - var/targets[] - targets = new() - for(var/mob/living/M in oview(6)) - if(M.stat) continue//Doesn't target corpses or paralyzed people. - targets.Add(M) - if(targets.len) - var/mob/living/target=pick(targets) - var/locx - var/locy - var/turf/mobloc = get_turf(target.loc) - var/safety = 0 - switch(target.dir) - if(NORTH) - locx = mobloc.x - locy = (mobloc.y-1) - if(locy<1) - safety = 1 - if(SOUTH) - locx = mobloc.x - locy = (mobloc.y+1) - if(locy>world.maxy) - safety = 1 - if(EAST) - locy = mobloc.y - locx = (mobloc.x-1) - if(locx<1) - safety = 1 - if(WEST) - locy = mobloc.y - locx = (mobloc.x+1) - if(locx>world.maxx) - safety = 1 - else safety=1 - if(!safety&&istype(mobloc, /turf)) - U.say("Kumo no Shinkiro!") - var/turf/picked = locate(locx,locy,mobloc.z) - spawn(0) - playsound(U.loc, "sparks", 50, 1) - anim(mobloc,U,'mob.dmi',,"phaseout",,U.dir) - - spawn(0) - var/limit = 4 - for(var/turf/T in oview(5)) - if(prob(20)) - spawn(0) - anim(T,U,'mob.dmi',,"phasein",,U.dir) - limit-- - if(limit<=0) break - - handle_teleport_grab(picked, U) - U.loc = picked - U.dir = target.dir - - spawn(0) - spark_system.start() - playsound(U.loc, 'phasein.ogg', 25, 1) - playsound(U.loc, "sparks", 50, 1) - anim(U.loc,U,'mob.dmi',,"phasein",,U.dir) - s_coold = 1 - else - U << "\red The VOID-shift device is malfunctioning, teleportation failed." - else - U << "\red There are no targets in view." - return +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++++++++++++++++++++++++++++++++++// //++++++++++++++++++++++++++++++++++ +==================================SPACE NINJA ABILITIES==================================== +___________________________________________________________________________________________ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +//=======//SAFETY CHECK//=======// +/* +X is optional, tells the proc to check for specific stuff. C is also optional. +All the procs here assume that the character is wearing the ninja suit if they are using the procs. +They should, as I have made every effort for that to be the case. +In the case that they are not, I imagine the game will run-time error like crazy. +s_cooldown ticks off each second based on the suit recharge proc, in seconds. Default of 1 seconds. Some abilities have no cool down. +*/ +/obj/item/clothing/suit/space/space_ninja/proc/ninjacost(C = 0,X = 0) + var/mob/living/carbon/human/U = affecting + if( (U.stat||U.incorporeal_move)&&X!=3 )//Will not return if user is using an adrenaline booster since you can use them when stat==1. + U << "\red You must be conscious and solid to do this."//It's not a problem of stat==2 since the ninja will explode anyway if they die. + return 1 + else if(C&&cell.charge[s_bombs] smoke bombs remaining." + var/datum/effect/effect/system/bad_smoke_spread/smoke = new /datum/effect/effect/system/bad_smoke_spread() + smoke.set_up(10, 0, U.loc) + smoke.start() + playsound(U.loc, 'bamf.ogg', 50, 2) + s_bombs-- + s_coold = 1 + return + +//=======//9-8 TILE TELEPORT//=======// +//Click to to teleport 9-10 tiles in direction facing. +/obj/item/clothing/suit/space/space_ninja/proc/ninjajaunt() + set name = "Phase Jaunt (10E)" + set desc = "Utilizes the internal VOID-shift device to rapidly transit in direction facing." + set category = "Ninja Ability" + set popup_menu = 0 + + var/C = 100 + if(!ninjacost(C,1)) + var/mob/living/carbon/human/U = affecting + var/turf/destination = get_teleport_loc(U.loc,U,9,1,3,1,0,1) + var/turf/mobloc = get_turf(U.loc)//To make sure that certain things work properly below. + if(destination&&istype(mobloc, /turf))//The turf check prevents unusual behavior. Like teleporting out of cryo pods, cloners, mechs, etc. + spawn(0) + playsound(U.loc, "sparks", 50, 1) + anim(mobloc,src,'mob.dmi',,"phaseout",,U.dir) + + handle_teleport_grab(destination, U) + U.loc = destination + + spawn(0) + spark_system.start() + playsound(U.loc, 'phasein.ogg', 25, 1) + playsound(U.loc, "sparks", 50, 1) + anim(U.loc,U,'mob.dmi',,"phasein",,U.dir) + + spawn(0) + destination.kill_creatures(U)//Any living mobs in teleport area are gibbed. Check turf procs for how it does it. + s_coold = 1 + cell.charge-=(C*10) + else + U << "\red The VOID-shift device is malfunctioning, teleportation failed." + return + +//=======//RIGHT CLICK TELEPORT//=======// +//Right click to teleport somewhere, almost exactly like admin jump to turf. +/obj/item/clothing/suit/space/space_ninja/proc/ninjashift(turf/T in oview()) + set name = "Phase Shift (20E)" + set desc = "Utilizes the internal VOID-shift device to rapidly transit to a destination in view." + set category = null//So it does not show up on the panel but can still be right-clicked. + set src = usr.contents//Fixes verbs not attaching properly for objects. Praise the DM reference guide! + + var/C = 200 + if(!ninjacost(C,1)) + var/mob/living/carbon/human/U = affecting + var/turf/mobloc = get_turf(U.loc)//To make sure that certain things work properly below. + if((!T.density)&&istype(mobloc, /turf)) + spawn(0) + playsound(U.loc, 'sparks4.ogg', 50, 1) + anim(mobloc,src,'mob.dmi',,"phaseout",,U.dir) + + handle_teleport_grab(T, U) + U.loc = T + + spawn(0) + spark_system.start() + playsound(U.loc, 'phasein.ogg', 25, 1) + playsound(U.loc, 'sparks2.ogg', 50, 1) + anim(U.loc,U,'mob.dmi',,"phasein",,U.dir) + + spawn(0)//Any living mobs in teleport area are gibbed. + T.kill_creatures(U) + s_coold = 1 + cell.charge-=(C*10) + else + U << "\red You cannot teleport into solid walls or from solid matter" + return + +//=======//EM PULSE//=======// +//Disables nearby tech equipment. +/obj/item/clothing/suit/space/space_ninja/proc/ninjapulse() + set name = "EM Burst (25E)" + set desc = "Disable any nearby technology with a electro-magnetic pulse." + set category = "Ninja Ability" + set popup_menu = 0 + + var/C = 250 + if(!ninjacost(C,1)) + var/mob/living/carbon/human/U = affecting + playsound(U.loc, 'EMPulse.ogg', 60, 2) + empulse(U, 4, 6) //Procs sure are nice. Slightly weaker than wizard's disable tch. + s_coold = 2 + cell.charge-=(C*10) + return + +//=======//ENERGY BLADE//=======// +//Summons a blade of energy in active hand. +/obj/item/clothing/suit/space/space_ninja/proc/ninjablade() + set name = "Energy Blade (5E)" + set desc = "Create a focused beam of energy in your active hand." + set category = "Ninja Ability" + set popup_menu = 0 + + var/C = 50 + if(!ninjacost(C)) + var/mob/living/carbon/human/U = affecting + if(!kamikaze) + if(!U.get_active_hand()&&!istype(U.get_inactive_hand(), /obj/item/weapon/melee/energy/blade)) + var/obj/item/weapon/melee/energy/blade/W = new() + spark_system.start() + playsound(U.loc, "sparks", 50, 1) + U.put_in_hand(W) + cell.charge-=(C*10) + else + U << "\red You can only summon one blade. Try dropping an item first." + else//Else you can run around with TWO energy blades. I don't know why you'd want to but cool factor remains. + if(!U.get_active_hand()) + var/obj/item/weapon/melee/energy/blade/W = new() + U.put_in_hand(W) + if(!U.get_inactive_hand()) + var/obj/item/weapon/melee/energy/blade/W = new() + U.put_in_inactive_hand(W) + spark_system.start() + playsound(U.loc, "sparks", 50, 1) + s_coold = 1 + return + +//=======//NINJA STARS//=======// +/*Shoots ninja stars at random people. +This could be a lot better but I'm too tired atm.*/ +/obj/item/clothing/suit/space/space_ninja/proc/ninjastar() + set name = "Energy Star (5E)" + set desc = "Launches an energy star at a random living target." + set category = "Ninja Ability" + set popup_menu = 0 + + var/C = 50 + if(!ninjacost(C)) + var/mob/living/carbon/human/U = affecting + var/targets[] = list()//So yo can shoot while yo throw dawg + for(var/mob/living/M in oview(loc)) + if(M.stat) continue//Doesn't target corpses or paralyzed persons. + targets.Add(M) + if(targets.len) + var/mob/living/target=pick(targets)//The point here is to pick a random, living mob in oview to shoot stuff at. + + var/turf/curloc = U.loc + var/atom/targloc = get_turf(target) + if (!targloc || !istype(targloc, /turf) || !curloc) + return + if (targloc == curloc) + return + var/obj/item/projectile/energy/dart/A = new /obj/item/projectile/energy/dart(U.loc) + A.current = curloc + A.yo = targloc.y - curloc.y + A.xo = targloc.x - curloc.x + cell.charge-=(C*10) + A.process() + else + U << "\red There are no targets in view." + return + +//=======//ENERGY NET//=======// +/*Allows the ninja to capture people, I guess. +Must right click on a mob to activate.*/ +/obj/item/clothing/suit/space/space_ninja/proc/ninjanet(mob/living/carbon/M in oview())//Only living carbon mobs. + set name = "Energy Net (20E)" + set desc = "Captures a fallen opponent in a net of energy. Will teleport them to a holding facility after 30 seconds." + set category = null + set src = usr.contents + + var/C = 200 + if(!ninjacost(C,1)&&iscarbon(M)) + var/mob/living/carbon/human/U = affecting + if(M.client)//Monkeys without a client can still step_to() and bypass the net. Also, netting inactive people is lame. + //if(M)//DEBUG + if(!locate(/obj/effect/energy_net) in M.loc)//Check if they are already being affected by an energy net. + for(var/turf/T in getline(U.loc, M.loc)) + if(T.density)//Don't want them shooting nets through walls. It's kind of cheesy. + U << "You may not use an energy net through solid obstacles!" + return + spawn(0) + U.Beam(M,"n_beam",,15) + M.anchored = 1//Anchors them so they can't move. + U.say("Get over here!") + var/obj/effect/energy_net/E = new /obj/effect/energy_net(M.loc) + E.layer = M.layer+1//To have it appear one layer above the mob. + for(var/mob/O in viewers(U, 3)) + O.show_message(text("\red [] caught [] with an energy net!", U, M), 1) + E.affecting = M + E.master = U + spawn(0)//Parallel processing. + E.process(M) + cell.charge-=(C*10) + else + U << "They are already trapped inside an energy net." + else + U << "They will bring no honor to your Clan!" + return + +//=======//ADRENALINE BOOST//=======// +/*Wakes the user so they are able to do their thing. Also injects a decent dose of radium. +Movement impairing would indicate drugs and the like.*/ +/obj/item/clothing/suit/space/space_ninja/proc/ninjaboost() + set name = "Adrenaline Boost" + set desc = "Inject a secret chemical that will counteract all movement-impairing effect." + set category = "Ninja Ability" + set popup_menu = 0 + + if(!ninjacost(,3))//Have to make sure stat is not counted for this ability. + var/mob/living/carbon/human/U = affecting + //Wouldn't need to track adrenaline boosters if there was a miracle injection to get rid of paralysis and the like instantly. + //For now, adrenaline boosters ARE the miracle injection. Well, radium, really. + U.SetParalysis(0) + U.SetStunned(0) + U.SetWeakened(0) + /* + Due to lag, it was possible to adrenaline boost but remain helpless while life.dm resets player stat. + This lead to me and others spamming adrenaline boosters because they failed to kick in on time. + It's technically possible to come back from crit with this but it is very temporary. + Life.dm will kick the player back into unconsciosness the next process loop. + */ + U.stat = 0//At least now you should be able to teleport away or shoot ninja stars. + spawn(30)//Slight delay so the enemy does not immedietly know the ability was used. Due to lag, this often came before waking up. + U.say(pick("A CORNERED FOX IS MORE DANGEROUS THAN A JACKAL!","HURT ME MOOORRREEE!","IMPRESSIVE!")) + spawn(70) + reagents.reaction(U, 2) + reagents.trans_id_to(U, "radium", a_transfer) + U << "\red You are beginning to feel the after-effect of the injection." + a_boost-- + s_coold = 3 + return + +/* +=================================================================================== +<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +=================================================================================== +Or otherwise known as anime mode. Which also happens to be ridiculously powerful. +*/ + +//=======//NINJA MOVEMENT//=======// +//Also makes you move like you're on crack. +/obj/item/clothing/suit/space/space_ninja/proc/ninjawalk() + set name = "Shadow Walk" + set desc = "Combines the VOID-shift and CLOAK-tech devices to freely move between solid matter. Toggle on or off." + set category = "Ninja Ability" + set popup_menu = 0 + + var/mob/living/carbon/human/U = affecting + if(!U.incorporeal_move) + U.incorporeal_move = 2 + U << "\blue You will now phase through solid matter." + else + U.incorporeal_move = 0 + U << "\blue You will no-longer phase through solid matter." + return + +//=======//5 TILE TELEPORT/GIB//=======// +//Allows to gib up to five squares in a straight line. Seriously. +/obj/item/clothing/suit/space/space_ninja/proc/ninjaslayer() + set name = "Phase Slayer" + set desc = "Utilizes the internal VOID-shift device to mutilate creatures in a straight line." + set category = "Ninja Ability" + set popup_menu = 0 + + if(!ninjacost()) + var/mob/living/carbon/human/U = affecting + var/turf/destination = get_teleport_loc(U.loc,U,5) + var/turf/mobloc = get_turf(U.loc)//To make sure that certain things work properly below. + if(destination&&istype(mobloc, /turf)) + U.say("Ai Satsugai!") + spawn(0) + playsound(U.loc, "sparks", 50, 1) + anim(mobloc,U,'mob.dmi',,"phaseout",,U.dir) + + spawn(0) + for(var/turf/T in getline(mobloc, destination)) + spawn(0) + T.kill_creatures(U) + if(T==mobloc||T==destination) continue + spawn(0) + anim(T,U,'mob.dmi',,"phasein",,U.dir) + + handle_teleport_grab(destination, U) + U.loc = destination + + spawn(0) + spark_system.start() + playsound(U.loc, 'phasein.ogg', 25, 1) + playsound(U.loc, "sparks", 50, 1) + anim(U.loc,U,'mob.dmi',,"phasein",,U.dir) + s_coold = 1 + else + U << "\red The VOID-shift device is malfunctioning, teleportation failed." + return + +//=======//TELEPORT BEHIND MOB//=======// +/*Appear behind a randomly chosen mob while a few decoy teleports appear. +This is so anime it hurts. But that's the point.*/ +/obj/item/clothing/suit/space/space_ninja/proc/ninjamirage() + set name = "Spider Mirage" + set desc = "Utilizes the internal VOID-shift device to create decoys and teleport behind a random target." + set category = "Ninja Ability" + set popup_menu = 0 + + if(!ninjacost())//Simply checks for stat. + var/mob/living/carbon/human/U = affecting + var/targets[] + targets = new() + for(var/mob/living/M in oview(6)) + if(M.stat) continue//Doesn't target corpses or paralyzed people. + targets.Add(M) + if(targets.len) + var/mob/living/target=pick(targets) + var/locx + var/locy + var/turf/mobloc = get_turf(target.loc) + var/safety = 0 + switch(target.dir) + if(NORTH) + locx = mobloc.x + locy = (mobloc.y-1) + if(locy<1) + safety = 1 + if(SOUTH) + locx = mobloc.x + locy = (mobloc.y+1) + if(locy>world.maxy) + safety = 1 + if(EAST) + locy = mobloc.y + locx = (mobloc.x-1) + if(locx<1) + safety = 1 + if(WEST) + locy = mobloc.y + locx = (mobloc.x+1) + if(locx>world.maxx) + safety = 1 + else safety=1 + if(!safety&&istype(mobloc, /turf)) + U.say("Kumo no Shinkiro!") + var/turf/picked = locate(locx,locy,mobloc.z) + spawn(0) + playsound(U.loc, "sparks", 50, 1) + anim(mobloc,U,'mob.dmi',,"phaseout",,U.dir) + + spawn(0) + var/limit = 4 + for(var/turf/T in oview(5)) + if(prob(20)) + spawn(0) + anim(T,U,'mob.dmi',,"phasein",,U.dir) + limit-- + if(limit<=0) break + + handle_teleport_grab(picked, U) + U.loc = picked + U.dir = target.dir + + spawn(0) + spark_system.start() + playsound(U.loc, 'phasein.ogg', 25, 1) + playsound(U.loc, "sparks", 50, 1) + anim(U.loc,U,'mob.dmi',,"phasein",,U.dir) + s_coold = 1 + else + U << "\red The VOID-shift device is malfunctioning, teleportation failed." + else + U << "\red There are no targets in view." + return diff --git a/code/game/gamemodes/events/ninja_equipment.dm b/code/game/events/EventProcs/ninja_equipment.dm similarity index 97% rename from code/game/gamemodes/events/ninja_equipment.dm rename to code/game/events/EventProcs/ninja_equipment.dm index 6c489d87a22..288e3073dc5 100644 --- a/code/game/gamemodes/events/ninja_equipment.dm +++ b/code/game/events/EventProcs/ninja_equipment.dm @@ -1,1456 +1,1456 @@ -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+++++++++++++++++++++++++++++++++// //++++++++++++++++++++++++++++++++++ -===================================SPACE NINJA EQUIPMENT=================================== -___________________________________________________________________________________________ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -*/ - -/* -=================================================================================== -<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -=================================================================================== -*/ - -//=======//NEW AND DEL//=======// - -/obj/item/clothing/suit/space/space_ninja/New() - ..() - verbs += /obj/item/clothing/suit/space/space_ninja/proc/init//suit initialize verb - verbs += /obj/item/clothing/suit/space/space_ninja/proc/ai_instruction//for AIs - verbs += /obj/item/clothing/suit/space/space_ninja/proc/ai_holo - //verbs += /obj/item/clothing/suit/space/space_ninja/proc/display_verb_procs//DEBUG. Doesn't work. - spark_system = new()//spark initialize - spark_system.set_up(5, 0, src) - spark_system.attach(src) - stored_research = new()//Stolen research initialize. - for(var/T in typesof(/datum/tech) - /datum/tech)//Store up on research. - stored_research += new T(src) - var/reagent_amount//reagent initialize - for(var/reagent_id in reagent_list) - reagent_amount += reagent_id == "radium" ? r_maxamount+(a_boost*a_transfer) : r_maxamount//AI can inject radium directly. - reagents = new(reagent_amount) - reagents.my_atom = src - for(var/reagent_id in reagent_list) - reagent_id == "radium" ? reagents.add_reagent(reagent_id, r_maxamount+(a_boost*a_transfer)) : reagents.add_reagent(reagent_id, r_maxamount)//It will take into account radium used for adrenaline boosting. - cell = new/obj/item/weapon/cell/high//The suit should *always* have a battery because so many things rely on it. - cell.charge = 9000//Starting charge should not be higher than maximum charge. It leads to problems with recharging. - -/obj/item/clothing/suit/space/space_ninja/Del() - if(affecting)//To make sure the window is closed. - affecting << browse(null, "window=hack spideros") - if(AI)//If there are AIs present when the ninja kicks the bucket. - killai() - if(hologram)//If there is a hologram - del(hologram.i_attached)//Delete it and the attached image. - del(hologram) - ..() - return - -//Simply deletes all the attachments and self, killing all related procs. -/obj/item/clothing/suit/space/space_ninja/proc/terminate() - del(n_hood) - del(n_gloves) - del(n_shoes) - del(src) - -/obj/item/clothing/suit/space/space_ninja/proc/killai(mob/living/silicon/ai/A = AI) - if(A.client) - A << "\red Self-erase protocol dete-- *bzzzzz*" - A << browse(null, "window=hack spideros") - AI = null - A.death(1)//Kill, deleting mob. - del(A) - return - -//=======//SUIT VERBS//=======// -//Verbs link to procs because verb-like procs have a bug which prevents their use if the arguments are not readily referenced. - -/obj/item/clothing/suit/space/space_ninja/proc/init() - set name = "Initialize Suit" - set desc = "Initializes the suit for field operation." - set category = "Ninja Equip" - - ninitialize() - return - -/obj/item/clothing/suit/space/space_ninja/proc/deinit() - set name = "De-Initialize Suit" - set desc = "Begins procedure to remove the suit." - set category = "Ninja Equip" - - if(s_control&&!s_busy) - deinitialize() - else - affecting << "\red The function did not trigger!" - return - -/obj/item/clothing/suit/space/space_ninja/proc/spideros() - set name = "Display SpiderOS" - set desc = "Utilize built-in computer system." - set category = "Ninja Equip" - - if(s_control&&!s_busy&&!kamikaze) - display_spideros() - else - affecting << "\red The interface is locked!" - return - -/obj/item/clothing/suit/space/space_ninja/proc/stealth() - set name = "Toggle Stealth" - set desc = "Utilize the internal CLOAK-tech device to activate or deactivate stealth-camo." - set category = "Ninja Equip" - - if(s_control&&!s_busy) - toggle_stealth() - else - affecting << "\red Stealth does not appear to work!" - return - -//=======//PROCESS PROCS//=======// - -/obj/item/clothing/suit/space/space_ninja/proc/ntick(mob/living/carbon/human/U = affecting) - set background = 1 - - //Runs in the background while the suit is initialized. - spawn while(cell.charge>=0) - - //Let's check for some safeties. - if(s_initialized&&!affecting) terminate()//Kills the suit and attached objects. - if(!s_initialized) return//When turned off the proc stops. - if(AI&&AI.stat==2)//If there is an AI and it's ded. Shouldn't happen without purging, could happen. - if(!s_control) - ai_return_control()//Return control to ninja if the AI was previously in control. - killai()//Delete AI. - - //Now let's do the normal processing. - if(s_coold) s_coold--//Checks for ability s_cooldown first. - var/A = s_cost//s_cost is the default energy cost each ntick, usually 5. - if(!kamikaze) - if(blade_check(U))//If there is a blade held in hand. - A += s_acost - if(s_active)//If stealth is active. - A += s_acost - else - if(prob(s_delay))//Suit delay is used as probability. May change later. - U.adjustBruteLoss(k_damage)//Default damage done, usually 1. - A = k_cost//kamikaze cost. - cell.charge-=A - if(cell.charge<=0) - if(kamikaze) - U.say("I DIE TO LIVE AGAIN!") - U << browse(null, "window=spideros")//Just in case. - U.death() - return - cell.charge=0 - cancel_stealth() - sleep(10)//Checks every second. - -//=======//INITIALIZE//=======// - -/obj/item/clothing/suit/space/space_ninja/proc/ninitialize(delay = s_delay, mob/living/carbon/human/U = loc) - if(U.mind&&U.mind.assigned_role=="MODE"&&!s_initialized&&!s_busy)//Shouldn't be busy... but anything is possible I guess. - s_busy = 1 - for(var/i,i<7,i++) - switch(i) - if(0) - U << "\blue Now initializing..." - if(1) - if(!lock_suit(U))//To lock the suit onto wearer. - break - U << "\blue Securing external locking mechanism...\nNeural-net established." - if(2) - U << "\blue Extending neural-net interface...\nNow monitoring brain wave pattern..." - if(3) - if(U.stat==2||U.health<=0) - U << "\red FĆAL ÈRrÖR: 344--93#†&&21 BRÄÌN |/|/aVÈ PATT$RN RED\nA-A-aBÖrTÌNG..." - unlock_suit() - break - lock_suit(U,1)//Check for icons. - U.update_clothing() - U << "\blue Linking neural-net interface...\nPattern \green GREEN\blue, continuing operation." - if(4) - U << "\blue VOID-shift device status: ONLINE.\nCLOAK-tech device status: ONLINE." - if(5) - U << "\blue Primary system status: ONLINE.\nBackup system status: ONLINE.\nCurrent energy capacity: [cell.charge]." - if(6) - U << "\blue All systems operational. Welcome to SpiderOS, [U.real_name]." - grant_ninja_verbs() - grant_equip_verbs() - ntick() - sleep(delay) - s_busy = 0 - else - if(!U.mind||U.mind.assigned_role!="MODE")//Your run of the mill persons shouldn't know what it is. Or how to turn it on. - U << "You do not understand how this suit functions. Where the heck did it even come from?" - else if(s_initialized) - U << "\red The suit is already functioning. \black Please report this bug." - else - U << "\red ERROR: \black You cannot use this function at this time." - return - -//=======//DEINITIALIZE//=======// - -/obj/item/clothing/suit/space/space_ninja/proc/deinitialize(delay = s_delay) - if(affecting==loc&&!s_busy) - var/mob/living/carbon/human/U = affecting - if(!s_initialized) - U << "\red The suit is not initialized. \black Please report this bug." - return - if(alert("Are you certain you wish to remove the suit? This will take time and remove all abilities.",,"Yes","No")=="No") - return - if(s_busy||flush) - U << "\red ERROR: \black You cannot use this function at this time." - return - s_busy = 1 - for(var/i = 0,i<7,i++) - switch(i) - if(0) - U << "\blue Now de-initializing..." - remove_kamikaze(U)//Shutdowns kamikaze. - spideros = 0//Spideros resets. - if(1) - U << "\blue Logging off, [U:real_name]. Shutting down SpiderOS." - remove_ninja_verbs() - if(2) - U << "\blue Primary system status: OFFLINE.\nBackup system status: OFFLINE." - if(3) - U << "\blue VOID-shift device status: OFFLINE.\nCLOAK-tech device status: OFFLINE." - cancel_stealth()//Shutdowns stealth. - if(4) - U << "\blue Disconnecting neural-net interface...\greenSuccess\blue." - if(5) - U << "\blue Disengaging neural-net interface...\greenSuccess\blue." - if(6) - U << "\blue Unsecuring external locking mechanism...\nNeural-net abolished.\nOperation status: FINISHED." - blade_check(U,2) - remove_equip_verbs() - unlock_suit() - U.update_clothing() - sleep(delay) - s_busy = 0 - return - -//=======//SPIDEROS PROC//=======// - -/obj/item/clothing/suit/space/space_ninja/proc/display_spideros() - if(!affecting) return//If no mob is wearing the suit. I almost forgot about this variable. - var/mob/living/carbon/human/U = affecting - var/mob/living/silicon/ai/A = AI - var/display_to = s_control ? U : A//Who do we want to display certain messages to? - - var/dat = "SpiderOS" - dat += " Refresh" - if(spideros) - dat += " | Return" - dat += " | Close" - dat += "
" - if(s_control) - dat += "

SpiderOS v.1.337

" - dat += "Welcome, [U.real_name].
" - else - dat += "

SpiderOS v.ERR-RR00123

" - dat += "
" - dat += " Current Time: [round(world.time / 36000)+12]:[(world.time / 600 % 60) < 10 ? add_zero(world.time / 600 % 60, 1) : world.time / 600 % 60]
" - dat += " Battery Life: [round(cell.charge/100)]%
" - dat += " Smoke Bombs: \Roman [s_bombs]
" - dat += " pai Device: " - if(pai) - dat += "Configure" - dat += " | " - dat += "Eject" - else - dat += "None Detected" - dat += "

" - - switch(spideros) - if(0) - dat += "

Available Functions:

" - dat += "" - if(3) - dat += "

Medical Report:

" - if(U.dna) - dat += "Fingerprints: [md5(U.dna.uni_identity)]
" - dat += "Unique identity: [U.dna.unique_enzymes]
" - dat += "

Overall Status: [U.stat > 1 ? "dead" : "[U.health]% healthy"]

" - dat += "

Nutrition Status: [U.nutrition]

" - dat += "Oxygen loss: [U.getOxyLoss()]" - dat += " | Toxin levels: [U.getToxLoss()]
" - dat += "Burn severity: [U.getFireLoss()]" - dat += " | Brute trauma: [U.getBruteLoss()]
" - dat += "Radiation Level: [U.radiation] rad
" - dat += "Body Temperature: [U.bodytemperature-T0C]°C ([U.bodytemperature*1.8-459.67]°F)
" - - for(var/datum/disease/D in U.viruses) - dat += "Warning: Virus Detected. Name: [D.name].Type: [D.spread]. Stage: [D.stage]/[D.max_stages]. Possible Cure: [D.cure].
" - dat += "" - if(1) - dat += "

Atmospheric Scan:

"//Headers don't need breaks. They are automatically placed. - var/turf/T = get_turf_or_move(U.loc) - if (isnull(T)) - dat += "Unable to obtain a reading." - else - var/datum/gas_mixture/environment = T.return_air() - - var/pressure = environment.return_pressure() - var/total_moles = environment.total_moles() - - dat += "Air Pressure: [round(pressure,0.1)] kPa" - - if (total_moles) - var/o2_level = environment.oxygen/total_moles - var/n2_level = environment.nitrogen/total_moles - var/co2_level = environment.carbon_dioxide/total_moles - var/plasma_level = environment.toxins/total_moles - var/unknown_level = 1-(o2_level+n2_level+co2_level+plasma_level) - dat += "
    " - dat += "
  • Nitrogen: [round(n2_level*100)]%
  • " - dat += "
  • Oxygen: [round(o2_level*100)]%
  • " - dat += "
  • Carbon Dioxide: [round(co2_level*100)]%
  • " - dat += "
  • Plasma: [round(plasma_level*100)]%
  • " - dat += "
" - if(unknown_level > 0.01) - dat += "OTHER: [round(unknown_level)]%
" - - dat += "Temperature: [round(environment.temperature-T0C)]°C" - if(2) - if(k_unlock==7||!s_control) - dat += " Hidden Menu" - dat += "

Anonymous Messenger:

"//Anonymous because the receiver will not know the sender's identity. - dat += "

Detected PDAs:

" - dat += "
    " - var/count = 0 - for (var/obj/item/device/pda/P in world) - if (!P.owner||P.toff) - continue - dat += "
  • [P]" - dat += "
  • " - count++ - dat += "
" - if (count == 0) - dat += "None detected.
" - if(32) - dat += "

Hidden Menu:

" - if(s_control) - dat += "Please input password: " - dat += "HERE
" - dat += "
" - dat += "Remember, you will not be able to recharge energy during this function. If energy runs out, the suit will auto self-destruct.
" - dat += "Use with caution. De-initialize the suit when energy is low." - else - //Only leaving this in for funnays. CAN'T LET YOU DO THAT STAR FOX - dat += "WARNING: Hostile runtime intrusion detected: operation locked. The Spider Clan is watching you, INTRUDER." - dat += "ERROR: TARANTULA.v.4.77.12 encryption algorithm detected. Unable to decrypt archive.
" - if(4) - dat += {" -

Ninja Manual:

-
Who they are:
- Space ninjas are a special type of ninja, specifically one of the space-faring type. The vast majority of space ninjas belong to the Spider Clan, a cult-like sect, which has existed for several hundred years. The Spider Clan practice a sort of augmentation of human flesh in order to achieve a more perfect state of being and follow Postmodern Space Bushido. They also kill people for money. Their leaders are chosen from the oldest of the grand-masters, people that have lived a lot longer than any mortal man should.
Being a sect of technology-loving fanatics, the Spider Clan have the very best to choose from in terms of hardware--cybernetic implants, exoskeleton rigs, hyper-capacity batteries, and you get the idea. Some believe that much of the Spider Clan equipment is based on reverse-engineered alien technology while others doubt such claims.
Whatever the case, their technology is absolutely superb. -
How they relate to other SS13 organizations:
-
    -
  • *Nanotrasen and the Syndicate are two sides of the same coin and that coin is valuable.
  • -
  • *The Space Wizard Federation is a problem, mainly because they are an extremely dangerous group of unpredictable individuals--not to mention the wizards hate technology and are in direct opposition of the Spider Clan. Best avoided or left well-enough alone. How to battle: wizards possess several powerful abilities to steer clear off. Blind in particular is a nasty spell--jaunt away if you are blinded and never approach a wizard in melee. Stealth may also work if the wizard is not wearing thermal scanners--don't count on this. Run away if you feel threatened and await a better opportunity.
  • -
  • *Changeling Hivemind: extremely dangerous and to be killed on sight. How to battle: they will likely try to absorb you. Adrenaline boost, then phase shift into them. If you get stung, use SpiderOS to inject counter-agents. Stealth may also work but detecting a changeling is the real battle.
  • -
  • *Xeno Hivemind: their skulls make interesting kitchen decorations and are challenging to best, especially in larger nests. How to battle: they can see through your stealth guise and energy stars will not work on them. Best killed with a Phase Shift or at range. If you happen on a projectile stun weapon, use it and then close in to melee.
  • -
-
The reason they (you) are here:
- Space ninjas are renowned throughout the known controlled space as fearless spies, infiltrators, and assassins. They are sent on missions of varying nature by Nanotrasen, the Syndicate, and other shady organizations and people. To hire a space ninja means serious business. -
Their playstyle:
- A mix of traitor, changeling, and wizard. Ninjas rely on energy, or electricity to be precise, to keep their suits running (when out of energy, a suit hibernates). Suits gain energy from objects or creatures that contain electrical charge. APCs, cell batteries, rechargers, SMES batteries, cyborgs, mechs, and exposed wires are currently supported. Through energy ninjas gain access to special powers--while all powers are tied to the ninja suit, the most useful of them are verb activated--to help them in their mission.
It is a constant struggle for a ninja to remain hidden long enough to recharge the suit and accomplish their objective; despite their arsenal of abilities, ninjas can die like any other. Unlike wizards, ninjas do not possess good crowd control and are typically forced to play more subdued in order to achieve their goals. Some of their abilities are specifically designed to confuse and disorient others.
With that said, it should be perfectly possible to completely flip the fuck out and rampage as a ninja. -
Their powers:
- There are two primary types: Equipment and Abilties. Passive effect are always on. Active effect must be turned on and remain active only when there is energy to do so. Ability costs are listed next to them. - Equipment: cannot be tracked by AI (passive), faster speed (passive), stealth (active), vision switch (passive if toggled), voice masking (passive), SpiderOS (passive if toggled), energy drain (passive if toggled). -
    -
  • Voice masking generates a random name the ninja can use over the radio and in-person. Although, the former use is recommended.
  • -
  • Toggling vision cycles to one of the following: thermal, meson, or darkness vision. The starting mode allows one to scout the identity of those in view, revealing their role. Traitors, revolutionaries, wizards, and other such people will be made known to you.
  • -
  • Stealth, when activated, drains more battery charge and works similarly to a syndicate cloak. The cloak will deactivate when most Abilities are utilized.
  • -
  • On-board AI: The suit is able to download an AI much like an intelicard. Check with SpiderOS for details once downloaded.
  • -
  • SpiderOS is a specialized, PDA-like screen that allows for a small variety of functions, such as injecting healing chemicals directly from the suit. You are using it now, if that was not already obvious. You may also download AI modules directly to the OS.
  • -
- Abilities: -
    -
  • *Phase Shift (2000E) and Phase Jaunt (1000E) are unique powers in that they can both be used for defense and offense. Jaunt launches the ninja forward facing up to 9 squares, somewhat randomly selecting the final destination. Shift can only be used on turf in view but is precise (cannot be used on walls). Any living mob in the area teleported to is instantly gibbed (mechs are damaged, huggers and other similar critters are killed). It is possible to teleport with a target, provided you grab them before teleporting.
  • -
  • *Energy Blade (500E) is a highly effective weapon. It is summoned directly to the ninja's hand and can also function as an EMAG for certain objects (doors/lockers/etc). You may also use it to cut through walls and disabled doors. Experiment! The blade will crit humans in two hits. This item cannot be placed in containers and when dropped or thrown disappears. Having an energy blade drains more power from the battery each tick.
  • -
  • *EM Pulse (2500E) is a highly useful ability that will create an electromagnetic shockwave around the ninja, disabling technology whenever possible. If used properly it can render a security force effectively useless. Of course, getting beat up with a toolbox is not accounted for.
  • -
  • *Energy Star (500E) is a ninja star made of green energy AND coated in poison. It works by picking a random living target within range and can be spammed to great effect in incapacitating foes. Just remember that the poison used is also used by the Xeno Hivemind (and will have no effect on them).
  • -
  • *Energy Net (2000E) is a non-lethal solution to incapacitating humanoids. The net is made of non-harmful phase energy and will halt movement as long as it remains in effect--it can be destroyed. If the net is not destroyed, after a certain time it will teleport the target to a holding facility for the Spider Clan and then vanish. You will be notified if the net fails or succeeds in capturing a target in this manner. Combine with energy stars or stripping to ensure success. Abduction never looked this leet.
  • -
  • *Adrenaline Boost (1 E. Boost/3) recovers the user from stun, weakness, and paralysis. Also injects 20 units of radium into the bloodstream.
  • -
  • *Smoke Bomb (1 Sm.Bomb/10) is a weak but potentially useful ability. It creates harmful smoke and can be used in tandem with other powers to confuse enemies.
  • -
  • *???: unleash the True Ultimate Power!
  • -

    IMPORTANT:

    -
      -
    • *Make sure to toggle Special Interaction from the Ninja Equipment menu to interact differently with certain objects.
    • -
    • *Your starting power cell can be replaced if you find one with higher maximum energy capacity by clicking on the new cell with the same hand (super and hyper cells).
    • -
    • *Conserve your energy. Without it, you are very vulnerable.
    • -
    - That is all you will need to know. The rest will come with practice and talent. Good luck! -

    Master /N

    - "}//This has always bothered me but not anymore! - if(5) - var/laws - dat += "

    AI Control:

    " - //var/mob/living/silicon/ai/A = AI - if(AI)//If an AI exists. - dat += "Stored AI: [A.name]
    " - dat += "System integrity: [(A.health+100)/2]%
    " - - //I personally think this makes things a little more fun. Ninjas can override all but law 0. - //if (A.laws.zeroth) - // laws += "
  • 0: [A.laws.zeroth]
  • " - - for (var/index = 1, index <= A.laws.ion.len, index++) - var/law = A.laws.ion[index] - if (length(law) > 0) - var/num = ionnum() - laws += "
  • [num]. [law]
  • " - - var/number = 1 - for (var/index = 1, index <= A.laws.inherent.len, index++) - var/law = A.laws.inherent[index] - if (length(law) > 0) - laws += "
  • [number]: [law]
  • " - number++ - - for (var/index = 1, index <= A.laws.supplied.len, index++) - var/law = A.laws.supplied[index] - if (length(law) > 0) - laws += "
  • [number]: [law]
  • " - number++ - - dat += "

    Laws:

    " - - if (!flush) - dat += "Purge AI
    " - else - dat += "Purge in progress...
    " - dat += " [A.control_disabled ? "Enable" : "Disable"] Wireless Activity" - if(6) - dat += {" -

    Activate Abilities:

    - - "} - if(7) - dat += "

    Research Stored:

    " - if(t_disk) - dat += "Eject Disk
    " - dat += "
      " - if(stored_research.len)//If there is stored research. Should be but just in case. - for(var/datum/tech/current_data in stored_research) - dat += "
    • " - dat += "[current_data.name]: [current_data.level]" - if(t_disk)//If there is a disk inserted. We can either write or overwrite. - dat += " *Copy to Disk
      " - dat += "
    • " - dat += "
    " - dat += "" - - //Setting the can>resize etc to 0 remove them from the drag bar but still allows the window to be draggable. - display_to << browse(dat,"window=spideros;size=400x444;border=1;can_resize=1;can_close=0;can_minimize=0") - -//=======//SPIDEROS TOPIC PROC//=======// - -/obj/item/clothing/suit/space/space_ninja/Topic(href, href_list) - ..() - var/mob/living/carbon/human/U = affecting - var/mob/living/silicon/ai/A = AI - var/display_to = s_control ? U : A//Who do we want to display certain messages to? - - if(s_control) - if(!affecting||U.stat||!s_initialized)//Check to make sure the guy is wearing the suit after clicking and it's on. - U << "\red Your suit must be worn and active to use this function." - U << browse(null, "window=spideros")//Closes the window. - return - - if(k_unlock!=7&&href_list["choice"]!="Return") - var/u1=text2num(href_list["choice"]) - var/u2=(u1?abs(abs(k_unlock-u1)-2):1) - k_unlock=(!u2? k_unlock+1:0) - if(k_unlock==7) - U << "Anonymous Messenger blinks." - else - if(!affecting||A.stat||!s_initialized||A.loc!=src) - A << "\red This function is not available at this time." - A << browse(null, "window=spideros")//Closes the window. - return - - switch(href_list["choice"]) - if("Close") - display_to << browse(null, "window=spideros") - return - if("Refresh")//Refresh, goes to the end of the proc. - if("Return")//Return - if(spideros<=9) - spideros=0 - else - spideros = round(spideros/10)//Best way to do this, flooring to nearest integer. - - if("Shock") - var/damage = min(cell.charge, rand(50,150))//Uses either the current energy left over or between 50 and 150. - if(damage>1)//So they don't spam it when energy is a factor. - spark_system.start()//SPARKS THERE SHALL BE SPARKS - U.electrocute_act(damage, src,0.1,1)//The last argument is a safety for the human proc that checks for gloves. - cell.charge -= damage - else - A << "\red ERROR: \black Not enough energy remaining." - - if("Message") - var/obj/item/device/pda/P = locate(href_list["target"]) - var/t = input(U, "Please enter untraceable message.") as text - t = copytext(sanitize(t), 1, MAX_MESSAGE_LEN) - if(!t||U.stat||U.wear_suit!=src||!s_initialized)//Wow, another one of these. Man... - display_to << browse(null, "window=spideros") - return - if(isnull(P)||P.toff)//So it doesn't freak out if the object no-longer exists. - display_to << "\red Error: unable to deliver message." - display_spideros() - return - P.tnote += "← From [!s_control?(A):"an unknown source"]:
    [t]
    " - if (!P.silent) - playsound(P.loc, 'twobeep.ogg', 50, 1) - for (var/mob/O in hearers(3, P.loc)) - O.show_message(text("\icon[P] *[P.ttone]*")) - P.overlays = null - P.overlays += image('pda.dmi', "pda-r") - - if("Inject") - if( (href_list["tag"]=="radium"? (reagents.get_reagent_amount("radium"))<=(a_boost*a_transfer) : !reagents.get_reagent_amount(href_list["tag"])) )//Special case for radium. If there are only a_boost*a_transfer radium units left. - display_to << "\red Error: the suit cannot perform this function. Out of [href_list["name"]]." - else - reagents.reaction(U, 2) - reagents.trans_id_to(U, href_list["tag"], href_list["tag"]=="nutriment"?5:a_transfer)//Nutriment is a special case since it's very potent. Shouldn't influence actual refill amounts or anything. - display_to << "Injecting..." - U << "You feel a tiny prick and a sudden rush of substance in to your veins." - - if("Trigger Ability") - var/ability_name = href_list["name"]+href_list["cost"]//Adds the name and cost to create the full proc name. - var/proc_arguments//What arguments to later pass to the proc, if any. - var/targets[] = list()//To later check for. - var/safety = 0//To later make sure we're triggering the proc when needed. - switch(href_list["name"])//Special case. - if("Phase Shift") - safety = 1 - for(var/turf/T in oview(5,loc)) - targets.Add(T) - if("Energy Net") - safety = 1 - for(var/mob/living/carbon/M in oview(5,loc)) - targets.Add(M) - if(targets.len)//Let's create an argument for the proc if needed. - proc_arguments = pick(targets) - safety = 0 - if(!safety) - A << "You trigger [href_list["name"]]." - U << "[href_list["name"]] suddenly triggered!" - call(src,ability_name)(proc_arguments) - else - A << "There are no potential [href_list["name"]=="Phase Shift"?"destinations" : "targets"] in view." - - if("Unlock Kamikaze") - if(input(U)=="Divine Wind") - if( !(U.stat||U.wear_suit!=src||!s_initialized) ) - if( !(cell.charge<=1||s_busy) ) - s_busy = 1 - for(var/i, i<4, i++) - switch(i) - if(0) - U << "\blue Engaging mode...\n\blackCODE NAME: \red KAMIKAZE" - if(1) - U << "\blue Re-routing power nodes... \nUnlocking limiter..." - if(2) - U << "\blue Power nodes re-routed. \nLimiter unlocked." - if(3) - grant_kamikaze(U)//Give them verbs and change variables as necessary. - U.update_clothing()//Update their clothing. - ninjablade()//Summon two energy blades. - message_admins("\blue [U.key] used KAMIKAZE mode.", 1)//Let the admins know. - s_busy = 0 - return - sleep(s_delay) - else - U << "\red ERROR: \black Unable to initiate mode." - else - U << browse(null, "window=spideros") - s_busy = 0 - return - else - U << "\red ERROR: WRONG PASSWORD!" - k_unlock = 0 - spideros = 0 - s_busy = 0 - - if("Eject Disk") - var/turf/T = get_turf(loc) - if(!U.get_active_hand()) - U.put_in_hand(t_disk) - t_disk.add_fingerprint(U) - t_disk = null - else - if(T) - t_disk.loc = T - t_disk = null - else - U << "\red ERROR: \black Could not eject disk." - - if("Copy to Disk") - var/datum/tech/current_data = locate(href_list["target"]) - U << "[current_data.name] successfully [(!t_disk.stored) ? "copied" : "overwritten"] to disk." - t_disk.stored = current_data - - if("Configure pAI") - pai.attack_self(U) - - if("Eject pAI") - var/turf/T = get_turf(loc) - if(!U.get_active_hand()) - U.put_in_hand(pai) - pai.add_fingerprint(U) - pai = null - else - if(T) - pai.loc = T - pai = null - else - U << "\red ERROR: \black Could not eject pAI card." - - if("Override AI Laws") - var/law_zero = A.laws.zeroth//Remembers law zero, if there is one. - A.laws = new /datum/ai_laws/ninja_override - A.set_zeroth_law(law_zero)//Adds back law zero if there was one. - A.show_laws() - U << "\blue Law Override: SUCCESS." - - if("Purge AI") - var/confirm = alert("Are you sure you want to purge the AI? This cannot be undone once started.", "Confirm purge", "Yes", "No") - if(U.stat||U.wear_suit!=src||!s_initialized) - U << browse(null, "window=spideros") - return - if(confirm == "Yes"&&AI) - if(A.laws.zeroth)//Gives a few seconds to re-upload the AI somewhere before it takes full control. - s_busy = 1 - for(var/i,i<5,i++) - if(AI==A) - switch(i) - if(0) - A << "\red WARNING: \black purge procedure detected. \nNow hacking host..." - U << "\red WARNING: HACKING AT††TEMP† IN PR0GRESs!" - spideros = 0 - k_unlock = 0 - U << browse(null, "window=spideros") - if(1) - A << "Disconnecting neural interface..." - U << "\red WAR†NING: þR†O0†GrÈ--S 2&3%" - if(2) - A << "Shutting down external protocol..." - U << "\red WARNING: PþþþþRÖ†GrÈ5S 677^%" - cancel_stealth() - if(3) - A << "Connecting to kernel..." - U << "\red WARNING: ÈR†rÖR_404" - A.control_disabled = 0 - if(4) - A << "Connection established and secured. Menu updated." - U << "\red WÄr#nING: #%@!!WȆ|_4þ54@ \nUnÄB88l3 TÖ LÖ-†o-LÖCaT2 ##$!ÈRNÈ0..%.." - grant_AI_verbs() - return - sleep(s_delay) - else break - s_busy = 0 - U << "\blue Hacking attempt disconnected. Resuming normal operation." - else - flush = 1 - A.suiciding = 1 - A << "Your core files are being purged! This is the end..." - spawn(0) - display_spideros()//To refresh the screen and let this finish. - while (A.stat != 2) - A.adjustOxyLoss(2) - A.updatehealth() - sleep(10) - killai() - U << "Artificial Intelligence was terminated. Rebooting..." - flush = 0 - - if("Wireless AI") - A.control_disabled = !A.control_disabled - A << "AI wireless has been [A.control_disabled ? "disabled" : "enabled"]." - else//If it's not a defined function, it's a menu. - spideros=text2num(href_list["choice"]) - - display_spideros()//Refreshes the screen by calling it again (which replaces current screen with new screen). - return - -//=======//SPECIAL AI FUNCTIONS//=======// - -/obj/item/clothing/suit/space/space_ninja/proc/ai_holo(var/turf/T in oview(3,affecting))//To have an internal AI display a hologram to the AI and ninja only. - set name = "Display Hologram" - set desc = "Channel a holographic image directly to the user's field of vision. Others will not see it." - set category = null - set src = usr.loc - - if(s_initialized&&affecting&&affecting.client&&istype(affecting.loc, /turf))//If the host exists and they are playing, and their location is a turf. - if(!hologram)//If there is not already a hologram. - hologram = new(T)//Spawn a blank effect at the location. - hologram.invisibility = 101//So that it doesn't show up, ever. This also means one could attach a number of images to a single obj and display them differently to differnet people. - hologram.anchored = 1//So it cannot be dragged by space wind and the like. - hologram.dir = get_dir(T,affecting.loc) - var/image/I = image(AI.holo_icon,hologram)//Attach an image to object. - hologram.i_attached = I//To attach the image in order to later reference. - AI << I - affecting << I - affecting << "An image flicks to life nearby. It appears visible to you only." - - verbs += /obj/item/clothing/suit/space/space_ninja/proc/ai_holo_clear - - ai_holo_process()//Move to initialize - else - AI << "\red ERROR: \black Image feed in progress." - else - AI << "\red ERROR: \black Unable to project image." - return - -/obj/item/clothing/suit/space/space_ninja/proc/ai_holo_process() - set background = 1 - - spawn while(hologram&&s_initialized&&AI)//Suit on and there is an AI present. - if(!s_initialized||get_dist(affecting,hologram.loc)>3)//Once suit is de-initialized or hologram reaches out of bounds. - del(hologram.i_attached) - del(hologram) - - verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ai_holo_clear - return - sleep(10)//Checks every second. - -/obj/item/clothing/suit/space/space_ninja/proc/ai_instruction()//Let's the AI know what they can do. - set name = "Instructions" - set desc = "Displays a list of helpful information." - set category = "AI Ninja Equip" - set src = usr.loc - - AI << "The menu you are seeing will contain other commands if they become available.\nRight click a nearby turf to display an AI Hologram. It will only be visible to you and your host. You can move it freely using normal movement keys--it will disappear if placed too far away." - -/obj/item/clothing/suit/space/space_ninja/proc/ai_holo_clear() - set name = "Clear Hologram" - set desc = "Stops projecting the current holographic image." - set category = "AI Ninja Equip" - set src = usr.loc - - del(hologram.i_attached) - del(hologram) - - verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ai_holo_clear - return - -/obj/item/clothing/suit/space/space_ninja/proc/ai_hack_ninja() - set name = "Hack SpiderOS" - set desc = "Hack directly into the Black Widow(tm) neuro-interface." - set category = "AI Ninja Equip" - set src = usr.loc - - display_spideros() - return - -/obj/item/clothing/suit/space/space_ninja/proc/ai_return_control() - set name = "Relinquish Control" - set desc = "Return control to the user." - set category = "AI Ninja Equip" - set src = usr.loc - - AI << browse(null, "window=spideros")//Close window - AI << "You have seized your hacking attempt. [affecting.real_name] has regained control." - affecting << "UPDATE: [AI.real_name] has ceased hacking attempt. All systems clear." - - remove_AI_verbs() - return - -//=======//GENERAL SUIT PROCS//=======// - -/obj/item/clothing/suit/space/space_ninja/attackby(obj/item/I, mob/U) - if(U==affecting)//Safety, in case you try doing this without wearing the suit/being the person with the suit. - if(istype(I, /obj/item/device/aicard))//If it's an AI card. - if(s_control) - I:transfer_ai("NINJASUIT","AICARD",src,U) - else - U << "\red ERROR: \black Remote access channel disabled." - return//Return individually so that ..() can run properly at the end of the proc. - else if(istype(I, /obj/item/device/paicard) && !pai)//If it's a pai card. - U:drop_item() - I.loc = src - pai = I - U << "\blue You slot \the [I] into \the [src]." - updateUsrDialog() - return - else if(istype(I, /obj/item/weapon/reagent_containers/glass))//If it's a glass beaker. - var/total_reagent_transfer//Keep track of this stuff. - for(var/reagent_id in reagent_list) - var/datum/reagent/R = I.reagents.has_reagent(reagent_id)//Mostly to pull up the name of the reagent after calculating. Also easier to use than writing long proc paths. - if(R&&reagents.get_reagent_amount(reagent_id)=a_transfer)//Radium is always special. - //Here we determine how much reagent will actually transfer if there is enough to transfer or there is a need of transfer. Minimum of max amount available (using a_transfer) or amount needed. - var/amount_to_transfer = min( (r_maxamount+(reagent_id == "radium"?(a_boost*a_transfer):0)-reagents.get_reagent_amount(reagent_id)) ,(round(R.volume/a_transfer))*a_transfer)//In the end here, we round the amount available, then multiply it again. - R.volume -= amount_to_transfer//Remove from reagent volume. Don't want to delete the reagent now since we need to perserve the name. - reagents.add_reagent(reagent_id, amount_to_transfer)//Add to suit. Reactions are not important. - total_reagent_transfer += amount_to_transfer//Add to total reagent trans. - U << "Added [amount_to_transfer] units of [R.name]."//Reports on the specific reagent added. - I.reagents.update_total()//Now we manually update the total to make sure everything is properly shoved under the rug. - - U << "Replenished a total of [total_reagent_transfer ? total_reagent_transfer : "zero"] chemical units."//Let the player know how much total volume was added. - return - else if(istype(I, /obj/item/weapon/cell)) - if(I:maxcharge>cell.maxcharge&&n_gloves&&n_gloves.candrain) - U << "\blue Higher maximum capacity detected.\nUpgrading..." - if (n_gloves&&n_gloves.candrain&&do_after(U,s_delay)) - U.drop_item() - I.loc = src - I:charge = min(I:charge+cell.charge, I:maxcharge) - var/obj/item/weapon/cell/old_cell = cell - old_cell.charge = 0 - U.put_in_hand(old_cell) - old_cell.add_fingerprint(U) - old_cell.corrupt() - old_cell.updateicon() - cell = I - U << "\blue Upgrade complete. Maximum capacity: [round(cell.maxcharge/100)]%" - else - U << "\red Procedure interrupted. Protocol terminated." - return - else if(istype(I, /obj/item/weapon/disk/tech_disk))//If it's a data disk, we want to copy the research on to the suit. - if(I:stored)//If it has something on it. - U << "Research information detected, processing..." - if(do_after(U,s_delay)) - for(var/datum/tech/current_data in stored_research) - if(current_data.id==I:stored.id) - if(current_data.levelERROR: \black Procedure interrupted. Process terminated." - else - I.loc = src - t_disk = I - U << "\blue You slot \the [I] into \the [src]." - return - ..() - -/obj/item/clothing/suit/space/space_ninja/proc/toggle_stealth() - var/mob/living/carbon/human/U = affecting - if(s_active) - cancel_stealth() - else - spawn(0) - anim(U.loc,U,'mob.dmi',,"cloak",,U.dir) - s_active=!s_active - U << "\blue You are now invisible to normal detection." - for(var/mob/O in oviewers(U)) - O.show_message("[U.name] vanishes into thin air!",1) - return - -/obj/item/clothing/suit/space/space_ninja/proc/cancel_stealth() - var/mob/living/carbon/human/U = affecting - if(s_active) - spawn(0) - anim(U.loc,U,'mob.dmi',,"uncloak",,U.dir) - s_active=!s_active - U << "\blue You are now visible." - for(var/mob/O in oviewers(U)) - O.show_message("[U.name] appears from thin air!",1) - return 1 - return 0 - -/obj/item/clothing/suit/space/space_ninja/proc/blade_check(mob/living/carbon/U, X = 1)//Default to checking for blade energy. - switch(X) - if(1) - if(istype(U.get_active_hand(), /obj/item/weapon/melee/energy/blade)) - if(cell.charge<=0)//If no charge left. - U.drop_item()//Blade is dropped from active hand (and deleted). - else return 1 - else if(istype(U.get_inactive_hand(), /obj/item/weapon/melee/energy/blade)) - if(cell.charge<=0) - U.swap_hand()//swap hand - U.drop_item()//drop blade - else return 1 - if(2) - if(istype(U.get_active_hand(), /obj/item/weapon/melee/energy/blade)) - U.drop_item() - if(istype(U.get_inactive_hand(), /obj/item/weapon/melee/energy/blade)) - U.swap_hand() - U.drop_item() - return 0 - -/obj/item/clothing/suit/space/space_ninja/examine() - set src in view() - ..() - if(s_initialized) - var/mob/living/carbon/human/U = affecting - if(s_control) - U << "All systems operational. Current energy capacity: [cell.charge]." - if(!kamikaze) - U << "The CLOAK-tech device is [s_active?"active":"inactive"]." - else - U << "\red KAMIKAZE MODE ENGAGED!" - U << "There are [s_bombs] smoke bombs remaining." - U << "There are [a_boost] adrenaline boosters remaining." - else - U << "ÈrrÖR Ða†Ða†Ä No-†-† fÖÚNÐ 3RRÖr" - -/* -=================================================================================== -<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -=================================================================================== -*/ - -//=======//ENERGY DRAIN PROCS//=======// - -/obj/item/clothing/gloves/space_ninja/proc/drain(target_type as text, target, obj/suit) -//Var Initialize - var/obj/item/clothing/suit/space/space_ninja/S = suit - var/mob/living/carbon/human/U = S.affecting - var/obj/item/clothing/gloves/space_ninja/G = S.n_gloves - - var/drain = 0//To drain from battery. - var/maxcapacity = 0//Safety check for full battery. - var/totaldrain = 0//Total energy drained. - - G.draining = 1 - - if(target_type!="RESEARCH")//I lumped research downloading here for ease of use. - U << "\blue Now charging battery..." - - switch(target_type) - - if("APC") - var/obj/machinery/power/apc/A = target - if(A.cell&&A.cell.charge) - var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() - spark_system.set_up(5, 0, A.loc) - while(G.candrain&&A.cell.charge>0&&!maxcapacity) - drain = rand(G.mindrain,G.maxdrain) - if(A.cell.chargeS.cell.maxcharge) - drain = S.cell.maxcharge-S.cell.charge - maxcapacity = 1//Reached maximum battery capacity. - if (do_after(U,10)) - spark_system.start() - playsound(A.loc, "sparks", 50, 1) - A.cell.charge-=drain - S.cell.charge+=drain - totaldrain+=drain - else break - U << "\blue Gained [totaldrain] energy from the APC." - if(!A.emagged) - flick("apc-spark", src) - A.emagged = 1 - A.locked = 0 - A.updateicon() - else - U << "\red This APC has run dry of power. You must find another source." - - if("SMES") - var/obj/machinery/power/smes/A = target - if(A.charge) - var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() - spark_system.set_up(5, 0, A.loc) - while(G.candrain&&A.charge>0&&!maxcapacity) - drain = rand(G.mindrain,G.maxdrain) - if(A.chargeS.cell.maxcharge) - drain = S.cell.maxcharge-S.cell.charge - maxcapacity = 1 - if (do_after(U,10)) - spark_system.start() - playsound(A.loc, "sparks", 50, 1) - A.charge-=drain - S.cell.charge+=drain - totaldrain+=drain - else break - U << "\blue Gained [totaldrain] energy from the SMES cell." - else - U << "\red This SMES cell has run dry of power. You must find another source." - - if("CELL") - var/obj/item/weapon/cell/A = target - if(A.charge) - if (G.candrain&&do_after(U,30)) - U << "\blue Gained [A.charge] energy from the cell." - if(S.cell.charge+A.charge>S.cell.maxcharge) - S.cell.charge=S.cell.maxcharge - else - S.cell.charge+=A.charge - A.charge = 0 - G.draining = 0 - A.corrupt() - A.updateicon() - else - U << "\red Procedure interrupted. Protocol terminated." - else - U << "\red This cell is empty and of no use." - - if("MACHINERY")//Can be applied to generically to all powered machinery. I'm leaving this alone for now. - var/obj/machinery/A = target - if(A.powered())//If powered. - - var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() - spark_system.set_up(5, 0, A.loc) - - var/obj/machinery/power/apc/B = A.loc.loc:get_apc()//Object.turf.area find APC - if(B)//If APC exists. Might not if the area is unpowered like CentCom. - var/datum/powernet/PN = B.terminal.powernet - while(G.candrain&&!maxcapacity&&!isnull(A))//And start a proc similar to drain from wire. - drain = rand(G.mindrain,G.maxdrain) - var/drained = 0 - if(PN&&do_after(U,10)) - drained = min(drain, PN.avail) - PN.newload += drained - if(drained < drain)//if no power on net, drain apcs - for(var/obj/machinery/power/terminal/T in PN.nodes) - if(istype(T.master, /obj/machinery/power/apc)) - var/obj/machinery/power/apc/AP = T.master - if(AP.operating && AP.cell && AP.cell.charge>0) - AP.cell.charge = max(0, AP.cell.charge - 5) - drained += 5 - else break - S.cell.charge += drained - if(S.cell.charge>S.cell.maxcharge) - totaldrain += (drained-(S.cell.charge-S.cell.maxcharge)) - S.cell.charge = S.cell.maxcharge - maxcapacity = 1 - else - totaldrain += drained - spark_system.start() - if(drained==0) break - U << "\blue Gained [totaldrain] energy from the power network." - else - U << "\red Power network could not be found. Aborting." - else - U << "\red This recharger is not providing energy. You must find another source." - - if("RESEARCH") - var/obj/machinery/A = target - U << "\blue Hacking \the [A]..." - spawn(0) - var/turf/location = get_turf(U) - for(var/mob/living/silicon/ai/AI in world) - AI << "\red Network Alert: Hacking attempt detected[location?" in [location]":". Unable to pinpoint location"]." - if(A:files&&A:files.known_tech.len) - for(var/datum/tech/current_data in S.stored_research) - U << "\blue Checking \the [current_data.name] database." - if(do_after(U, S.s_delay)&&G.candrain&&!isnull(A)) - for(var/datum/tech/analyzing_data in A:files.known_tech) - if(current_data.id==analyzing_data.id) - if(analyzing_data.level>current_data.level) - U << "\blue Database: \black UPDATED." - current_data.level = analyzing_data.level - break//Move on to next. - else break//Otherwise, quit processing. - U << "\blue Data analyzed. Process finished." - - if("WIRE") - var/obj/structure/cable/A = target - var/datum/powernet/PN = A.get_powernet() - while(G.candrain&&!maxcapacity&&!isnull(A)) - drain = (round((rand(G.mindrain,G.maxdrain))/2)) - var/drained = 0 - if(PN&&do_after(U,10)) - drained = min(drain, PN.avail) - PN.newload += drained - if(drained < drain)//if no power on net, drain apcs - for(var/obj/machinery/power/terminal/T in PN.nodes) - if(istype(T.master, /obj/machinery/power/apc)) - var/obj/machinery/power/apc/AP = T.master - if(AP.operating && AP.cell && AP.cell.charge>0) - AP.cell.charge = max(0, AP.cell.charge - 5) - drained += 5 - else break - S.cell.charge += drained - if(S.cell.charge>S.cell.maxcharge) - totaldrain += (drained-(S.cell.charge-S.cell.maxcharge)) - S.cell.charge = S.cell.maxcharge - maxcapacity = 1 - else - totaldrain += drained - S.spark_system.start() - if(drained==0) break - U << "\blue Gained [totaldrain] energy from the power network." - - if("MECHA") - var/obj/mecha/A = target - A.occupant_message("\red Warning: Unauthorized access through sub-route 4, block H, detected.") - if(A.get_charge()) - while(G.candrain&&A.cell.charge>0&&!maxcapacity) - drain = rand(G.mindrain,G.maxdrain) - if(A.cell.chargeS.cell.maxcharge) - drain = S.cell.maxcharge-S.cell.charge - maxcapacity = 1 - if (do_after(U,10)) - A.spark_system.start() - playsound(A.loc, "sparks", 50, 1) - A.cell.use(drain) - S.cell.charge+=drain - totaldrain+=drain - else break - U << "\blue Gained [totaldrain] energy from [src]." - else - U << "\red The exosuit's battery has run dry of power. You must find another source." - - if("CYBORG") - var/mob/living/silicon/robot/A = target - A << "\red Warning: Unauthorized access through sub-route 12, block C, detected." - G.draining = 1 - if(A.cell&&A.cell.charge) - while(G.candrain&&A.cell.charge>0&&!maxcapacity) - drain = rand(G.mindrain,G.maxdrain) - if(A.cell.chargeS.cell.maxcharge) - drain = S.cell.maxcharge-S.cell.charge - maxcapacity = 1 - if (do_after(U,10)) - A.spark_system.start() - playsound(A.loc, "sparks", 50, 1) - A.cell.charge-=drain - S.cell.charge+=drain - totaldrain+=drain - else break - U << "\blue Gained [totaldrain] energy from [A]." - else - U << "\red Their battery has run dry of power. You must find another source." - - else//Else nothing :< - - G.draining = 0 - - return - -//=======//GENERAL PROCS//=======// - -/obj/item/clothing/gloves/space_ninja/proc/toggled() - set name = "Toggle Interaction" - set desc = "Toggles special interaction on or off." - set category = "Ninja Equip" - - var/mob/living/carbon/human/U = loc - U << "You [candrain?"disable":"enable"] special interaction." - candrain=!candrain - -/obj/item/clothing/gloves/space_ninja/examine() - set src in view() - ..() - if(!canremove) - var/mob/living/carbon/human/U = loc - U << "The energy drain mechanism is: [candrain?"active":"inactive"]." - -/* -=================================================================================== -<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -=================================================================================== -*/ - -/obj/item/clothing/mask/gas/voice/space_ninja/New() - verbs += /obj/item/clothing/mask/gas/voice/space_ninja/proc/togglev - verbs += /obj/item/clothing/mask/gas/voice/space_ninja/proc/switchm - -//This proc is linked to human life.dm. It determines what hud icons to display based on mind special role for most mobs. -/obj/item/clothing/mask/gas/voice/space_ninja/proc/assess_targets(list/target_list, mob/living/carbon/U) - var/icon/tempHud = 'hud.dmi' - for(var/mob/living/target in target_list) - if(iscarbon(target)) - switch(target.mind.special_role) - if("traitor") - U.client.images += image(tempHud,target,"hudtraitor") - if("Revolutionary","Head Revolutionary") - U.client.images += image(tempHud,target,"hudrevolutionary") - if("Cultist") - U.client.images += image(tempHud,target,"hudcultist") - if("Changeling") - U.client.images += image(tempHud,target,"hudchangeling") - if("Wizard","Fake Wizard") - U.client.images += image(tempHud,target,"hudwizard") - if("Hunter","Sentinel","Drone","Queen") - U.client.images += image(tempHud,target,"hudalien") - if("Syndicate") - U.client.images += image(tempHud,target,"hudoperative") - if("Death Commando") - U.client.images += image(tempHud,target,"huddeathsquad") - if("Space Ninja") - U.client.images += image(tempHud,target,"hudninja") - else//If we don't know what role they have but they have one. - U.client.images += image(tempHud,target,"hudunknown1") - else//If the silicon mob has no law datum, no inherent laws, or a law zero, add them to the hud. - var/mob/living/silicon/silicon_target = target - if(!silicon_target.laws||(silicon_target.laws&&(silicon_target.laws.zeroth||!silicon_target.laws.inherent.len))) - if(isrobot(silicon_target))//Different icons for robutts and AI. - U.client.images += image(tempHud,silicon_target,"hudmalborg") - else - U.client.images += image(tempHud,silicon_target,"hudmalai") - return 1 - -/obj/item/clothing/mask/gas/voice/space_ninja/proc/togglev() - set name = "Toggle Voice" - set desc = "Toggles the voice synthesizer on or off." - set category = "Ninja Equip" - - var/mob/U = loc//Can't toggle voice when you're not wearing the mask. - var/vchange = (alert("Would you like to synthesize a new name or turn off the voice synthesizer?",,"New Name","Turn Off")) - if(vchange=="New Name") - var/chance = rand(1,100) - switch(chance) - if(1 to 50)//High chance of a regular name. - voice = "[rand(0,1)==1?pick(first_names_female):pick(first_names_male)] [pick(last_names)]" - if(51 to 80)//Smaller chance of a clown name. - voice = "[pick(clown_names)]" - if(81 to 90)//Small chance of a wizard name. - voice = "[pick(wizard_first)] [pick(wizard_second)]" - if(91 to 100)//Small chance of an existing crew name. - var/names[] = new() - for(var/mob/living/carbon/human/M in world) - if(M==U||!M.client||!M.real_name) continue - names.Add(M.real_name) - voice = !names.len ? "Cuban Pete" : pick(names) - U << "You are now mimicking [voice]." - else - U << "The voice synthesizer is [voice!="Unknown"?"now":"already"] deactivated." - voice = "Unknown" - return - -/obj/item/clothing/mask/gas/voice/space_ninja/proc/switchm() - set name = "Switch Mode" - set desc = "Switches between Night Vision, Meson, or Thermal vision modes." - set category = "Ninja Equip" - //Have to reset these manually since life.dm is retarded like that. Go figure. - //This will only work for humans because only they have the appropriate code for the mask. - var/mob/U = loc - switch(mode) - if(0) - mode=1 - U << "Switching mode to Night Vision." - if(1) - mode=2 - U.see_in_dark = 2 - U << "Switching mode to Thermal Scanner." - if(2) - mode=3 - U.see_invisible = 0 - U.sight &= ~SEE_MOBS - U << "Switching mode to Meson Scanner." - if(3) - mode=0 - U.sight &= ~SEE_TURFS - U << "Switching mode to Scouter." - -/obj/item/clothing/mask/gas/voice/space_ninja/examine() - set src in view() - ..() - - var/mode - switch(mode) - if(0) - mode = "Scouter" - if(1) - mode = "Night Vision" - if(2) - mode = "Thermal Scanner" - if(3) - mode = "Meson Scanner" - usr << "[mode] is active."//Leaving usr here since it may be on the floor or on a person. - usr << "Voice mimicking algorithm is set [!vchange?"inactive":"active"]." - -/* -=================================================================================== -<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -=================================================================================== -*/ - -/* -It will teleport people to a holding facility after 30 seconds. (Check the process() proc to change where teleport goes) -It is possible to destroy the net by the occupant or someone else. -*/ - -/obj/effect/energy_net - name = "energy net" - desc = "It's a net made of green energy." - icon = 'effects.dmi' - icon_state = "energynet" - - density = 1//Can't pass through. - opacity = 0//Can see through. - mouse_opacity = 1//So you can hit it with stuff. - anchored = 1//Can't drag/grab the trapped mob. - - var - health = 25//How much health it has. - mob/living/affecting = null//Who it is currently affecting, if anyone. - mob/living/master = null//Who shot web. Will let this person know if the net was successful or failed. - - proc - healthcheck() - if(health <=0) - density = 0 - if(affecting) - var/mob/living/carbon/M = affecting - M.anchored = 0 - for(var/mob/O in viewers(src, 3)) - O.show_message(text("[] was recovered from the energy net!", M.name), 1, text("You hear a grunt."), 2) - if(!isnull(master))//As long as they still exist. - master << "\red ERROR: \black unable to initiate transport protocol. Procedure terminated." - del(src) - return - - process(var/mob/living/carbon/M as mob) - var/check = 30//30 seconds before teleportation. Could be extended I guess. - var/mob_name = affecting.name//Since they will report as null if terminated before teleport. - //The person can still try and attack the net when inside. - while(!isnull(M)&&!isnull(src)&&check>0)//While M and net exist, and 30 seconds have not passed. - check-- - sleep(10) - - if(isnull(M)||M.loc!=loc)//If mob is gone or not at the location. - if(!isnull(master))//As long as they still exist. - master << "\red ERROR: \black unable to locate \the [mob_name]. Procedure terminated." - del(src)//Get rid of the net. - return - - if(!isnull(src))//As long as both net and person exist. - //No need to check for countdown here since while() broke, it's implicit that it finished. - - density = 0//Make the net pass-through. - invisibility = 101//Make the net invisible so all the animations can play out. - health = INFINITY//Make the net invincible so that an explosion/something else won't kill it while, spawn() is running. - for(var/obj/item/W in M) - if(istype(M,/mob/living/carbon/human)) - if(W==M:w_uniform) continue//So all they're left with are shoes and uniform. - if(W==M:shoes) continue - M.drop_from_slot(W) - - spawn(0) - playsound(M.loc, 'sparks4.ogg', 50, 1) - anim(M.loc,M,'mob.dmi',,"phaseout",,M.dir) - - M.loc = pick(holdingfacility)//Throw mob in to the holding facility. - M << "\red You appear in a strange place!" - - spawn(0) - var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() - spark_system.set_up(5, 0, M.loc) - spark_system.start() - playsound(M.loc, 'phasein.ogg', 25, 1) - playsound(M.loc, 'sparks2.ogg', 50, 1) - anim(M.loc,M,'mob.dmi',,"phasein",,M.dir) - del(src)//Wait for everything to finish, delete the net. Else it will stop everything once net is deleted, including the spawn(0). - - for(var/mob/O in viewers(src, 3)) - O.show_message(text("[] vanished!", M), 1, text("You hear sparks flying!"), 2) - - if(!isnull(master))//As long as they still exist. - master << "\blue SUCCESS: \black transport procedure of \the [affecting] complete." - - M.anchored = 0//Important. - - else//And they are free. - M << "\blue You are free of the net!" - return - - bullet_act(var/obj/item/projectile/Proj) - health -= Proj.damage - healthcheck() - return 0 - - ex_act(severity) - switch(severity) - if(1.0) - health-=50 - if(2.0) - health-=50 - if(3.0) - health-=prob(50)?50:25 - healthcheck() - return - - blob_act() - health-=50 - healthcheck() - return - - meteorhit() - health-=50 - healthcheck() - return - - hitby(AM as mob|obj) - ..() - for(var/mob/O in viewers(src, null)) - O.show_message(text("\red [src] was hit by [AM]."), 1) - var/tforce = 0 - if(ismob(AM)) - tforce = 10 - else - tforce = AM:throwforce - playsound(src.loc, 'slash.ogg', 80, 1) - health = max(0, health - tforce) - healthcheck() - ..() - return - - attack_hand() - if ((usr.mutations & HULK)) - usr << text("\blue You easily destroy the energy net.") - for(var/mob/O in oviewers(src)) - O.show_message(text("\red [] rips the energy net apart!", usr), 1) - health-=50 - healthcheck() - return - - attack_paw() - return attack_hand() - - attack_alien() - if (islarva(usr)) - return - usr << text("\green You claw at the net.") - for(var/mob/O in oviewers(src)) - O.show_message(text("\red [] claws at the energy net!", usr), 1) - playsound(src.loc, 'slash.ogg', 80, 1) - health -= rand(10, 20) - if(health <= 0) - usr << text("\green You slice the energy net to pieces.") - for(var/mob/O in oviewers(src)) - O.show_message(text("\red [] slices the energy net apart!", usr), 1) - healthcheck() - return - - attackby(obj/item/weapon/W as obj, mob/user as mob) - var/aforce = W.force - health = max(0, health - aforce) - healthcheck() - ..() +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++++++++++++++++++++++++++++++++++// //++++++++++++++++++++++++++++++++++ +===================================SPACE NINJA EQUIPMENT=================================== +___________________________________________________________________________________________ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +/* +=================================================================================== +<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +=================================================================================== +*/ + +//=======//NEW AND DEL//=======// + +/obj/item/clothing/suit/space/space_ninja/New() + ..() + verbs += /obj/item/clothing/suit/space/space_ninja/proc/init//suit initialize verb + verbs += /obj/item/clothing/suit/space/space_ninja/proc/ai_instruction//for AIs + verbs += /obj/item/clothing/suit/space/space_ninja/proc/ai_holo + //verbs += /obj/item/clothing/suit/space/space_ninja/proc/display_verb_procs//DEBUG. Doesn't work. + spark_system = new()//spark initialize + spark_system.set_up(5, 0, src) + spark_system.attach(src) + stored_research = new()//Stolen research initialize. + for(var/T in typesof(/datum/tech) - /datum/tech)//Store up on research. + stored_research += new T(src) + var/reagent_amount//reagent initialize + for(var/reagent_id in reagent_list) + reagent_amount += reagent_id == "radium" ? r_maxamount+(a_boost*a_transfer) : r_maxamount//AI can inject radium directly. + reagents = new(reagent_amount) + reagents.my_atom = src + for(var/reagent_id in reagent_list) + reagent_id == "radium" ? reagents.add_reagent(reagent_id, r_maxamount+(a_boost*a_transfer)) : reagents.add_reagent(reagent_id, r_maxamount)//It will take into account radium used for adrenaline boosting. + cell = new/obj/item/weapon/cell/high//The suit should *always* have a battery because so many things rely on it. + cell.charge = 9000//Starting charge should not be higher than maximum charge. It leads to problems with recharging. + +/obj/item/clothing/suit/space/space_ninja/Del() + if(affecting)//To make sure the window is closed. + affecting << browse(null, "window=hack spideros") + if(AI)//If there are AIs present when the ninja kicks the bucket. + killai() + if(hologram)//If there is a hologram + del(hologram.i_attached)//Delete it and the attached image. + del(hologram) + ..() + return + +//Simply deletes all the attachments and self, killing all related procs. +/obj/item/clothing/suit/space/space_ninja/proc/terminate() + del(n_hood) + del(n_gloves) + del(n_shoes) + del(src) + +/obj/item/clothing/suit/space/space_ninja/proc/killai(mob/living/silicon/ai/A = AI) + if(A.client) + A << "\red Self-erase protocol dete-- *bzzzzz*" + A << browse(null, "window=hack spideros") + AI = null + A.death(1)//Kill, deleting mob. + del(A) + return + +//=======//SUIT VERBS//=======// +//Verbs link to procs because verb-like procs have a bug which prevents their use if the arguments are not readily referenced. + +/obj/item/clothing/suit/space/space_ninja/proc/init() + set name = "Initialize Suit" + set desc = "Initializes the suit for field operation." + set category = "Ninja Equip" + + ninitialize() + return + +/obj/item/clothing/suit/space/space_ninja/proc/deinit() + set name = "De-Initialize Suit" + set desc = "Begins procedure to remove the suit." + set category = "Ninja Equip" + + if(s_control&&!s_busy) + deinitialize() + else + affecting << "\red The function did not trigger!" + return + +/obj/item/clothing/suit/space/space_ninja/proc/spideros() + set name = "Display SpiderOS" + set desc = "Utilize built-in computer system." + set category = "Ninja Equip" + + if(s_control&&!s_busy&&!kamikaze) + display_spideros() + else + affecting << "\red The interface is locked!" + return + +/obj/item/clothing/suit/space/space_ninja/proc/stealth() + set name = "Toggle Stealth" + set desc = "Utilize the internal CLOAK-tech device to activate or deactivate stealth-camo." + set category = "Ninja Equip" + + if(s_control&&!s_busy) + toggle_stealth() + else + affecting << "\red Stealth does not appear to work!" + return + +//=======//PROCESS PROCS//=======// + +/obj/item/clothing/suit/space/space_ninja/proc/ntick(mob/living/carbon/human/U = affecting) + set background = 1 + + //Runs in the background while the suit is initialized. + spawn while(cell.charge>=0) + + //Let's check for some safeties. + if(s_initialized&&!affecting) terminate()//Kills the suit and attached objects. + if(!s_initialized) return//When turned off the proc stops. + if(AI&&AI.stat==2)//If there is an AI and it's ded. Shouldn't happen without purging, could happen. + if(!s_control) + ai_return_control()//Return control to ninja if the AI was previously in control. + killai()//Delete AI. + + //Now let's do the normal processing. + if(s_coold) s_coold--//Checks for ability s_cooldown first. + var/A = s_cost//s_cost is the default energy cost each ntick, usually 5. + if(!kamikaze) + if(blade_check(U))//If there is a blade held in hand. + A += s_acost + if(s_active)//If stealth is active. + A += s_acost + else + if(prob(s_delay))//Suit delay is used as probability. May change later. + U.adjustBruteLoss(k_damage)//Default damage done, usually 1. + A = k_cost//kamikaze cost. + cell.charge-=A + if(cell.charge<=0) + if(kamikaze) + U.say("I DIE TO LIVE AGAIN!") + U << browse(null, "window=spideros")//Just in case. + U.death() + return + cell.charge=0 + cancel_stealth() + sleep(10)//Checks every second. + +//=======//INITIALIZE//=======// + +/obj/item/clothing/suit/space/space_ninja/proc/ninitialize(delay = s_delay, mob/living/carbon/human/U = loc) + if(U.mind&&U.mind.assigned_role=="MODE"&&!s_initialized&&!s_busy)//Shouldn't be busy... but anything is possible I guess. + s_busy = 1 + for(var/i,i<7,i++) + switch(i) + if(0) + U << "\blue Now initializing..." + if(1) + if(!lock_suit(U))//To lock the suit onto wearer. + break + U << "\blue Securing external locking mechanism...\nNeural-net established." + if(2) + U << "\blue Extending neural-net interface...\nNow monitoring brain wave pattern..." + if(3) + if(U.stat==2||U.health<=0) + U << "\red FĆAL ÈRrÖR: 344--93#†&&21 BRÄÌN |/|/aVÈ PATT$RN RED\nA-A-aBÖrTÌNG..." + unlock_suit() + break + lock_suit(U,1)//Check for icons. + U.update_clothing() + U << "\blue Linking neural-net interface...\nPattern \green GREEN\blue, continuing operation." + if(4) + U << "\blue VOID-shift device status: ONLINE.\nCLOAK-tech device status: ONLINE." + if(5) + U << "\blue Primary system status: ONLINE.\nBackup system status: ONLINE.\nCurrent energy capacity: [cell.charge]." + if(6) + U << "\blue All systems operational. Welcome to SpiderOS, [U.real_name]." + grant_ninja_verbs() + grant_equip_verbs() + ntick() + sleep(delay) + s_busy = 0 + else + if(!U.mind||U.mind.assigned_role!="MODE")//Your run of the mill persons shouldn't know what it is. Or how to turn it on. + U << "You do not understand how this suit functions. Where the heck did it even come from?" + else if(s_initialized) + U << "\red The suit is already functioning. \black Please report this bug." + else + U << "\red ERROR: \black You cannot use this function at this time." + return + +//=======//DEINITIALIZE//=======// + +/obj/item/clothing/suit/space/space_ninja/proc/deinitialize(delay = s_delay) + if(affecting==loc&&!s_busy) + var/mob/living/carbon/human/U = affecting + if(!s_initialized) + U << "\red The suit is not initialized. \black Please report this bug." + return + if(alert("Are you certain you wish to remove the suit? This will take time and remove all abilities.",,"Yes","No")=="No") + return + if(s_busy||flush) + U << "\red ERROR: \black You cannot use this function at this time." + return + s_busy = 1 + for(var/i = 0,i<7,i++) + switch(i) + if(0) + U << "\blue Now de-initializing..." + remove_kamikaze(U)//Shutdowns kamikaze. + spideros = 0//Spideros resets. + if(1) + U << "\blue Logging off, [U:real_name]. Shutting down SpiderOS." + remove_ninja_verbs() + if(2) + U << "\blue Primary system status: OFFLINE.\nBackup system status: OFFLINE." + if(3) + U << "\blue VOID-shift device status: OFFLINE.\nCLOAK-tech device status: OFFLINE." + cancel_stealth()//Shutdowns stealth. + if(4) + U << "\blue Disconnecting neural-net interface...\greenSuccess\blue." + if(5) + U << "\blue Disengaging neural-net interface...\greenSuccess\blue." + if(6) + U << "\blue Unsecuring external locking mechanism...\nNeural-net abolished.\nOperation status: FINISHED." + blade_check(U,2) + remove_equip_verbs() + unlock_suit() + U.update_clothing() + sleep(delay) + s_busy = 0 + return + +//=======//SPIDEROS PROC//=======// + +/obj/item/clothing/suit/space/space_ninja/proc/display_spideros() + if(!affecting) return//If no mob is wearing the suit. I almost forgot about this variable. + var/mob/living/carbon/human/U = affecting + var/mob/living/silicon/ai/A = AI + var/display_to = s_control ? U : A//Who do we want to display certain messages to? + + var/dat = "SpiderOS" + dat += " Refresh" + if(spideros) + dat += " | Return" + dat += " | Close" + dat += "
    " + if(s_control) + dat += "

    SpiderOS v.1.337

    " + dat += "Welcome, [U.real_name].
    " + else + dat += "

    SpiderOS v.ERR-RR00123

    " + dat += "
    " + dat += " Current Time: [round(world.time / 36000)+12]:[(world.time / 600 % 60) < 10 ? add_zero(world.time / 600 % 60, 1) : world.time / 600 % 60]
    " + dat += " Battery Life: [round(cell.charge/100)]%
    " + dat += " Smoke Bombs: \Roman [s_bombs]
    " + dat += " pai Device: " + if(pai) + dat += "Configure" + dat += " | " + dat += "Eject" + else + dat += "None Detected" + dat += "

    " + + switch(spideros) + if(0) + dat += "

    Available Functions:

    " + dat += "" + if(3) + dat += "

    Medical Report:

    " + if(U.dna) + dat += "Fingerprints: [md5(U.dna.uni_identity)]
    " + dat += "Unique identity: [U.dna.unique_enzymes]
    " + dat += "

    Overall Status: [U.stat > 1 ? "dead" : "[U.health]% healthy"]

    " + dat += "

    Nutrition Status: [U.nutrition]

    " + dat += "Oxygen loss: [U.getOxyLoss()]" + dat += " | Toxin levels: [U.getToxLoss()]
    " + dat += "Burn severity: [U.getFireLoss()]" + dat += " | Brute trauma: [U.getBruteLoss()]
    " + dat += "Radiation Level: [U.radiation] rad
    " + dat += "Body Temperature: [U.bodytemperature-T0C]°C ([U.bodytemperature*1.8-459.67]°F)
    " + + for(var/datum/disease/D in U.viruses) + dat += "Warning: Virus Detected. Name: [D.name].Type: [D.spread]. Stage: [D.stage]/[D.max_stages]. Possible Cure: [D.cure].
    " + dat += "" + if(1) + dat += "

    Atmospheric Scan:

    "//Headers don't need breaks. They are automatically placed. + var/turf/T = get_turf_or_move(U.loc) + if (isnull(T)) + dat += "Unable to obtain a reading." + else + var/datum/gas_mixture/environment = T.return_air() + + var/pressure = environment.return_pressure() + var/total_moles = environment.total_moles() + + dat += "Air Pressure: [round(pressure,0.1)] kPa" + + if (total_moles) + var/o2_level = environment.oxygen/total_moles + var/n2_level = environment.nitrogen/total_moles + var/co2_level = environment.carbon_dioxide/total_moles + var/plasma_level = environment.toxins/total_moles + var/unknown_level = 1-(o2_level+n2_level+co2_level+plasma_level) + dat += "
      " + dat += "
    • Nitrogen: [round(n2_level*100)]%
    • " + dat += "
    • Oxygen: [round(o2_level*100)]%
    • " + dat += "
    • Carbon Dioxide: [round(co2_level*100)]%
    • " + dat += "
    • Plasma: [round(plasma_level*100)]%
    • " + dat += "
    " + if(unknown_level > 0.01) + dat += "OTHER: [round(unknown_level)]%
    " + + dat += "Temperature: [round(environment.temperature-T0C)]°C" + if(2) + if(k_unlock==7||!s_control) + dat += " Hidden Menu" + dat += "

    Anonymous Messenger:

    "//Anonymous because the receiver will not know the sender's identity. + dat += "

    Detected PDAs:

    " + dat += "
      " + var/count = 0 + for (var/obj/item/device/pda/P in world) + if (!P.owner||P.toff) + continue + dat += "
    • [P]" + dat += "
    • " + count++ + dat += "
    " + if (count == 0) + dat += "None detected.
    " + if(32) + dat += "

    Hidden Menu:

    " + if(s_control) + dat += "Please input password: " + dat += "HERE
    " + dat += "
    " + dat += "Remember, you will not be able to recharge energy during this function. If energy runs out, the suit will auto self-destruct.
    " + dat += "Use with caution. De-initialize the suit when energy is low." + else + //Only leaving this in for funnays. CAN'T LET YOU DO THAT STAR FOX + dat += "WARNING: Hostile runtime intrusion detected: operation locked. The Spider Clan is watching you, INTRUDER." + dat += "ERROR: TARANTULA.v.4.77.12 encryption algorithm detected. Unable to decrypt archive.
    " + if(4) + dat += {" +

    Ninja Manual:

    +
    Who they are:
    + Space ninjas are a special type of ninja, specifically one of the space-faring type. The vast majority of space ninjas belong to the Spider Clan, a cult-like sect, which has existed for several hundred years. The Spider Clan practice a sort of augmentation of human flesh in order to achieve a more perfect state of being and follow Postmodern Space Bushido. They also kill people for money. Their leaders are chosen from the oldest of the grand-masters, people that have lived a lot longer than any mortal man should.
    Being a sect of technology-loving fanatics, the Spider Clan have the very best to choose from in terms of hardware--cybernetic implants, exoskeleton rigs, hyper-capacity batteries, and you get the idea. Some believe that much of the Spider Clan equipment is based on reverse-engineered alien technology while others doubt such claims.
    Whatever the case, their technology is absolutely superb. +
    How they relate to other SS13 organizations:
    +
      +
    • *Nanotrasen and the Syndicate are two sides of the same coin and that coin is valuable.
    • +
    • *The Space Wizard Federation is a problem, mainly because they are an extremely dangerous group of unpredictable individuals--not to mention the wizards hate technology and are in direct opposition of the Spider Clan. Best avoided or left well-enough alone. How to battle: wizards possess several powerful abilities to steer clear off. Blind in particular is a nasty spell--jaunt away if you are blinded and never approach a wizard in melee. Stealth may also work if the wizard is not wearing thermal scanners--don't count on this. Run away if you feel threatened and await a better opportunity.
    • +
    • *Changeling Hivemind: extremely dangerous and to be killed on sight. How to battle: they will likely try to absorb you. Adrenaline boost, then phase shift into them. If you get stung, use SpiderOS to inject counter-agents. Stealth may also work but detecting a changeling is the real battle.
    • +
    • *Xeno Hivemind: their skulls make interesting kitchen decorations and are challenging to best, especially in larger nests. How to battle: they can see through your stealth guise and energy stars will not work on them. Best killed with a Phase Shift or at range. If you happen on a projectile stun weapon, use it and then close in to melee.
    • +
    +
    The reason they (you) are here:
    + Space ninjas are renowned throughout the known controlled space as fearless spies, infiltrators, and assassins. They are sent on missions of varying nature by Nanotrasen, the Syndicate, and other shady organizations and people. To hire a space ninja means serious business. +
    Their playstyle:
    + A mix of traitor, changeling, and wizard. Ninjas rely on energy, or electricity to be precise, to keep their suits running (when out of energy, a suit hibernates). Suits gain energy from objects or creatures that contain electrical charge. APCs, cell batteries, rechargers, SMES batteries, cyborgs, mechs, and exposed wires are currently supported. Through energy ninjas gain access to special powers--while all powers are tied to the ninja suit, the most useful of them are verb activated--to help them in their mission.
    It is a constant struggle for a ninja to remain hidden long enough to recharge the suit and accomplish their objective; despite their arsenal of abilities, ninjas can die like any other. Unlike wizards, ninjas do not possess good crowd control and are typically forced to play more subdued in order to achieve their goals. Some of their abilities are specifically designed to confuse and disorient others.
    With that said, it should be perfectly possible to completely flip the fuck out and rampage as a ninja. +
    Their powers:
    + There are two primary types: Equipment and Abilties. Passive effect are always on. Active effect must be turned on and remain active only when there is energy to do so. Ability costs are listed next to them. + Equipment: cannot be tracked by AI (passive), faster speed (passive), stealth (active), vision switch (passive if toggled), voice masking (passive), SpiderOS (passive if toggled), energy drain (passive if toggled). +
      +
    • Voice masking generates a random name the ninja can use over the radio and in-person. Although, the former use is recommended.
    • +
    • Toggling vision cycles to one of the following: thermal, meson, or darkness vision. The starting mode allows one to scout the identity of those in view, revealing their role. Traitors, revolutionaries, wizards, and other such people will be made known to you.
    • +
    • Stealth, when activated, drains more battery charge and works similarly to a syndicate cloak. The cloak will deactivate when most Abilities are utilized.
    • +
    • On-board AI: The suit is able to download an AI much like an intelicard. Check with SpiderOS for details once downloaded.
    • +
    • SpiderOS is a specialized, PDA-like screen that allows for a small variety of functions, such as injecting healing chemicals directly from the suit. You are using it now, if that was not already obvious. You may also download AI modules directly to the OS.
    • +
    + Abilities: +
      +
    • *Phase Shift (2000E) and Phase Jaunt (1000E) are unique powers in that they can both be used for defense and offense. Jaunt launches the ninja forward facing up to 9 squares, somewhat randomly selecting the final destination. Shift can only be used on turf in view but is precise (cannot be used on walls). Any living mob in the area teleported to is instantly gibbed (mechs are damaged, huggers and other similar critters are killed). It is possible to teleport with a target, provided you grab them before teleporting.
    • +
    • *Energy Blade (500E) is a highly effective weapon. It is summoned directly to the ninja's hand and can also function as an EMAG for certain objects (doors/lockers/etc). You may also use it to cut through walls and disabled doors. Experiment! The blade will crit humans in two hits. This item cannot be placed in containers and when dropped or thrown disappears. Having an energy blade drains more power from the battery each tick.
    • +
    • *EM Pulse (2500E) is a highly useful ability that will create an electromagnetic shockwave around the ninja, disabling technology whenever possible. If used properly it can render a security force effectively useless. Of course, getting beat up with a toolbox is not accounted for.
    • +
    • *Energy Star (500E) is a ninja star made of green energy AND coated in poison. It works by picking a random living target within range and can be spammed to great effect in incapacitating foes. Just remember that the poison used is also used by the Xeno Hivemind (and will have no effect on them).
    • +
    • *Energy Net (2000E) is a non-lethal solution to incapacitating humanoids. The net is made of non-harmful phase energy and will halt movement as long as it remains in effect--it can be destroyed. If the net is not destroyed, after a certain time it will teleport the target to a holding facility for the Spider Clan and then vanish. You will be notified if the net fails or succeeds in capturing a target in this manner. Combine with energy stars or stripping to ensure success. Abduction never looked this leet.
    • +
    • *Adrenaline Boost (1 E. Boost/3) recovers the user from stun, weakness, and paralysis. Also injects 20 units of radium into the bloodstream.
    • +
    • *Smoke Bomb (1 Sm.Bomb/10) is a weak but potentially useful ability. It creates harmful smoke and can be used in tandem with other powers to confuse enemies.
    • +
    • *???: unleash the True Ultimate Power!
    • +

      IMPORTANT:

      +
        +
      • *Make sure to toggle Special Interaction from the Ninja Equipment menu to interact differently with certain objects.
      • +
      • *Your starting power cell can be replaced if you find one with higher maximum energy capacity by clicking on the new cell with the same hand (super and hyper cells).
      • +
      • *Conserve your energy. Without it, you are very vulnerable.
      • +
      + That is all you will need to know. The rest will come with practice and talent. Good luck! +

      Master /N

      + "}//This has always bothered me but not anymore! + if(5) + var/laws + dat += "

      AI Control:

      " + //var/mob/living/silicon/ai/A = AI + if(AI)//If an AI exists. + dat += "Stored AI: [A.name]
      " + dat += "System integrity: [(A.health+100)/2]%
      " + + //I personally think this makes things a little more fun. Ninjas can override all but law 0. + //if (A.laws.zeroth) + // laws += "
    • 0: [A.laws.zeroth]
    • " + + for (var/index = 1, index <= A.laws.ion.len, index++) + var/law = A.laws.ion[index] + if (length(law) > 0) + var/num = ionnum() + laws += "
    • [num]. [law]
    • " + + var/number = 1 + for (var/index = 1, index <= A.laws.inherent.len, index++) + var/law = A.laws.inherent[index] + if (length(law) > 0) + laws += "
    • [number]: [law]
    • " + number++ + + for (var/index = 1, index <= A.laws.supplied.len, index++) + var/law = A.laws.supplied[index] + if (length(law) > 0) + laws += "
    • [number]: [law]
    • " + number++ + + dat += "

      Laws:

      " + + if (!flush) + dat += "Purge AI
      " + else + dat += "Purge in progress...
      " + dat += " [A.control_disabled ? "Enable" : "Disable"] Wireless Activity" + if(6) + dat += {" +

      Activate Abilities:

      + + "} + if(7) + dat += "

      Research Stored:

      " + if(t_disk) + dat += "Eject Disk
      " + dat += "
        " + if(stored_research.len)//If there is stored research. Should be but just in case. + for(var/datum/tech/current_data in stored_research) + dat += "
      • " + dat += "[current_data.name]: [current_data.level]" + if(t_disk)//If there is a disk inserted. We can either write or overwrite. + dat += " *Copy to Disk
        " + dat += "
      • " + dat += "
      " + dat += "" + + //Setting the can>resize etc to 0 remove them from the drag bar but still allows the window to be draggable. + display_to << browse(dat,"window=spideros;size=400x444;border=1;can_resize=1;can_close=0;can_minimize=0") + +//=======//SPIDEROS TOPIC PROC//=======// + +/obj/item/clothing/suit/space/space_ninja/Topic(href, href_list) + ..() + var/mob/living/carbon/human/U = affecting + var/mob/living/silicon/ai/A = AI + var/display_to = s_control ? U : A//Who do we want to display certain messages to? + + if(s_control) + if(!affecting||U.stat||!s_initialized)//Check to make sure the guy is wearing the suit after clicking and it's on. + U << "\red Your suit must be worn and active to use this function." + U << browse(null, "window=spideros")//Closes the window. + return + + if(k_unlock!=7&&href_list["choice"]!="Return") + var/u1=text2num(href_list["choice"]) + var/u2=(u1?abs(abs(k_unlock-u1)-2):1) + k_unlock=(!u2? k_unlock+1:0) + if(k_unlock==7) + U << "Anonymous Messenger blinks." + else + if(!affecting||A.stat||!s_initialized||A.loc!=src) + A << "\red This function is not available at this time." + A << browse(null, "window=spideros")//Closes the window. + return + + switch(href_list["choice"]) + if("Close") + display_to << browse(null, "window=spideros") + return + if("Refresh")//Refresh, goes to the end of the proc. + if("Return")//Return + if(spideros<=9) + spideros=0 + else + spideros = round(spideros/10)//Best way to do this, flooring to nearest integer. + + if("Shock") + var/damage = min(cell.charge, rand(50,150))//Uses either the current energy left over or between 50 and 150. + if(damage>1)//So they don't spam it when energy is a factor. + spark_system.start()//SPARKS THERE SHALL BE SPARKS + U.electrocute_act(damage, src,0.1,1)//The last argument is a safety for the human proc that checks for gloves. + cell.charge -= damage + else + A << "\red ERROR: \black Not enough energy remaining." + + if("Message") + var/obj/item/device/pda/P = locate(href_list["target"]) + var/t = input(U, "Please enter untraceable message.") as text + t = copytext(sanitize(t), 1, MAX_MESSAGE_LEN) + if(!t||U.stat||U.wear_suit!=src||!s_initialized)//Wow, another one of these. Man... + display_to << browse(null, "window=spideros") + return + if(isnull(P)||P.toff)//So it doesn't freak out if the object no-longer exists. + display_to << "\red Error: unable to deliver message." + display_spideros() + return + P.tnote += "← From [!s_control?(A):"an unknown source"]:
      [t]
      " + if (!P.silent) + playsound(P.loc, 'twobeep.ogg', 50, 1) + for (var/mob/O in hearers(3, P.loc)) + O.show_message(text("\icon[P] *[P.ttone]*")) + P.overlays = null + P.overlays += image('pda.dmi', "pda-r") + + if("Inject") + if( (href_list["tag"]=="radium"? (reagents.get_reagent_amount("radium"))<=(a_boost*a_transfer) : !reagents.get_reagent_amount(href_list["tag"])) )//Special case for radium. If there are only a_boost*a_transfer radium units left. + display_to << "\red Error: the suit cannot perform this function. Out of [href_list["name"]]." + else + reagents.reaction(U, 2) + reagents.trans_id_to(U, href_list["tag"], href_list["tag"]=="nutriment"?5:a_transfer)//Nutriment is a special case since it's very potent. Shouldn't influence actual refill amounts or anything. + display_to << "Injecting..." + U << "You feel a tiny prick and a sudden rush of substance in to your veins." + + if("Trigger Ability") + var/ability_name = href_list["name"]+href_list["cost"]//Adds the name and cost to create the full proc name. + var/proc_arguments//What arguments to later pass to the proc, if any. + var/targets[] = list()//To later check for. + var/safety = 0//To later make sure we're triggering the proc when needed. + switch(href_list["name"])//Special case. + if("Phase Shift") + safety = 1 + for(var/turf/T in oview(5,loc)) + targets.Add(T) + if("Energy Net") + safety = 1 + for(var/mob/living/carbon/M in oview(5,loc)) + targets.Add(M) + if(targets.len)//Let's create an argument for the proc if needed. + proc_arguments = pick(targets) + safety = 0 + if(!safety) + A << "You trigger [href_list["name"]]." + U << "[href_list["name"]] suddenly triggered!" + call(src,ability_name)(proc_arguments) + else + A << "There are no potential [href_list["name"]=="Phase Shift"?"destinations" : "targets"] in view." + + if("Unlock Kamikaze") + if(input(U)=="Divine Wind") + if( !(U.stat||U.wear_suit!=src||!s_initialized) ) + if( !(cell.charge<=1||s_busy) ) + s_busy = 1 + for(var/i, i<4, i++) + switch(i) + if(0) + U << "\blue Engaging mode...\n\blackCODE NAME: \red KAMIKAZE" + if(1) + U << "\blue Re-routing power nodes... \nUnlocking limiter..." + if(2) + U << "\blue Power nodes re-routed. \nLimiter unlocked." + if(3) + grant_kamikaze(U)//Give them verbs and change variables as necessary. + U.update_clothing()//Update their clothing. + ninjablade()//Summon two energy blades. + message_admins("\blue [U.key] used KAMIKAZE mode.", 1)//Let the admins know. + s_busy = 0 + return + sleep(s_delay) + else + U << "\red ERROR: \black Unable to initiate mode." + else + U << browse(null, "window=spideros") + s_busy = 0 + return + else + U << "\red ERROR: WRONG PASSWORD!" + k_unlock = 0 + spideros = 0 + s_busy = 0 + + if("Eject Disk") + var/turf/T = get_turf(loc) + if(!U.get_active_hand()) + U.put_in_hand(t_disk) + t_disk.add_fingerprint(U) + t_disk = null + else + if(T) + t_disk.loc = T + t_disk = null + else + U << "\red ERROR: \black Could not eject disk." + + if("Copy to Disk") + var/datum/tech/current_data = locate(href_list["target"]) + U << "[current_data.name] successfully [(!t_disk.stored) ? "copied" : "overwritten"] to disk." + t_disk.stored = current_data + + if("Configure pAI") + pai.attack_self(U) + + if("Eject pAI") + var/turf/T = get_turf(loc) + if(!U.get_active_hand()) + U.put_in_hand(pai) + pai.add_fingerprint(U) + pai = null + else + if(T) + pai.loc = T + pai = null + else + U << "\red ERROR: \black Could not eject pAI card." + + if("Override AI Laws") + var/law_zero = A.laws.zeroth//Remembers law zero, if there is one. + A.laws = new /datum/ai_laws/ninja_override + A.set_zeroth_law(law_zero)//Adds back law zero if there was one. + A.show_laws() + U << "\blue Law Override: SUCCESS." + + if("Purge AI") + var/confirm = alert("Are you sure you want to purge the AI? This cannot be undone once started.", "Confirm purge", "Yes", "No") + if(U.stat||U.wear_suit!=src||!s_initialized) + U << browse(null, "window=spideros") + return + if(confirm == "Yes"&&AI) + if(A.laws.zeroth)//Gives a few seconds to re-upload the AI somewhere before it takes full control. + s_busy = 1 + for(var/i,i<5,i++) + if(AI==A) + switch(i) + if(0) + A << "\red WARNING: \black purge procedure detected. \nNow hacking host..." + U << "\red WARNING: HACKING AT††TEMP† IN PR0GRESs!" + spideros = 0 + k_unlock = 0 + U << browse(null, "window=spideros") + if(1) + A << "Disconnecting neural interface..." + U << "\red WAR†NING: þR†O0†GrÈ--S 2&3%" + if(2) + A << "Shutting down external protocol..." + U << "\red WARNING: PþþþþRÖ†GrÈ5S 677^%" + cancel_stealth() + if(3) + A << "Connecting to kernel..." + U << "\red WARNING: ÈR†rÖR_404" + A.control_disabled = 0 + if(4) + A << "Connection established and secured. Menu updated." + U << "\red WÄr#nING: #%@!!WȆ|_4þ54@ \nUnÄB88l3 TÖ LÖ-†o-LÖCaT2 ##$!ÈRNÈ0..%.." + grant_AI_verbs() + return + sleep(s_delay) + else break + s_busy = 0 + U << "\blue Hacking attempt disconnected. Resuming normal operation." + else + flush = 1 + A.suiciding = 1 + A << "Your core files are being purged! This is the end..." + spawn(0) + display_spideros()//To refresh the screen and let this finish. + while (A.stat != 2) + A.adjustOxyLoss(2) + A.updatehealth() + sleep(10) + killai() + U << "Artificial Intelligence was terminated. Rebooting..." + flush = 0 + + if("Wireless AI") + A.control_disabled = !A.control_disabled + A << "AI wireless has been [A.control_disabled ? "disabled" : "enabled"]." + else//If it's not a defined function, it's a menu. + spideros=text2num(href_list["choice"]) + + display_spideros()//Refreshes the screen by calling it again (which replaces current screen with new screen). + return + +//=======//SPECIAL AI FUNCTIONS//=======// + +/obj/item/clothing/suit/space/space_ninja/proc/ai_holo(var/turf/T in oview(3,affecting))//To have an internal AI display a hologram to the AI and ninja only. + set name = "Display Hologram" + set desc = "Channel a holographic image directly to the user's field of vision. Others will not see it." + set category = null + set src = usr.loc + + if(s_initialized&&affecting&&affecting.client&&istype(affecting.loc, /turf))//If the host exists and they are playing, and their location is a turf. + if(!hologram)//If there is not already a hologram. + hologram = new(T)//Spawn a blank effect at the location. + hologram.invisibility = 101//So that it doesn't show up, ever. This also means one could attach a number of images to a single obj and display them differently to differnet people. + hologram.anchored = 1//So it cannot be dragged by space wind and the like. + hologram.dir = get_dir(T,affecting.loc) + var/image/I = image(AI.holo_icon,hologram)//Attach an image to object. + hologram.i_attached = I//To attach the image in order to later reference. + AI << I + affecting << I + affecting << "An image flicks to life nearby. It appears visible to you only." + + verbs += /obj/item/clothing/suit/space/space_ninja/proc/ai_holo_clear + + ai_holo_process()//Move to initialize + else + AI << "\red ERROR: \black Image feed in progress." + else + AI << "\red ERROR: \black Unable to project image." + return + +/obj/item/clothing/suit/space/space_ninja/proc/ai_holo_process() + set background = 1 + + spawn while(hologram&&s_initialized&&AI)//Suit on and there is an AI present. + if(!s_initialized||get_dist(affecting,hologram.loc)>3)//Once suit is de-initialized or hologram reaches out of bounds. + del(hologram.i_attached) + del(hologram) + + verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ai_holo_clear + return + sleep(10)//Checks every second. + +/obj/item/clothing/suit/space/space_ninja/proc/ai_instruction()//Let's the AI know what they can do. + set name = "Instructions" + set desc = "Displays a list of helpful information." + set category = "AI Ninja Equip" + set src = usr.loc + + AI << "The menu you are seeing will contain other commands if they become available.\nRight click a nearby turf to display an AI Hologram. It will only be visible to you and your host. You can move it freely using normal movement keys--it will disappear if placed too far away." + +/obj/item/clothing/suit/space/space_ninja/proc/ai_holo_clear() + set name = "Clear Hologram" + set desc = "Stops projecting the current holographic image." + set category = "AI Ninja Equip" + set src = usr.loc + + del(hologram.i_attached) + del(hologram) + + verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ai_holo_clear + return + +/obj/item/clothing/suit/space/space_ninja/proc/ai_hack_ninja() + set name = "Hack SpiderOS" + set desc = "Hack directly into the Black Widow(tm) neuro-interface." + set category = "AI Ninja Equip" + set src = usr.loc + + display_spideros() + return + +/obj/item/clothing/suit/space/space_ninja/proc/ai_return_control() + set name = "Relinquish Control" + set desc = "Return control to the user." + set category = "AI Ninja Equip" + set src = usr.loc + + AI << browse(null, "window=spideros")//Close window + AI << "You have seized your hacking attempt. [affecting.real_name] has regained control." + affecting << "UPDATE: [AI.real_name] has ceased hacking attempt. All systems clear." + + remove_AI_verbs() + return + +//=======//GENERAL SUIT PROCS//=======// + +/obj/item/clothing/suit/space/space_ninja/attackby(obj/item/I, mob/U) + if(U==affecting)//Safety, in case you try doing this without wearing the suit/being the person with the suit. + if(istype(I, /obj/item/device/aicard))//If it's an AI card. + if(s_control) + I:transfer_ai("NINJASUIT","AICARD",src,U) + else + U << "\red ERROR: \black Remote access channel disabled." + return//Return individually so that ..() can run properly at the end of the proc. + else if(istype(I, /obj/item/device/paicard) && !pai)//If it's a pai card. + U:drop_item() + I.loc = src + pai = I + U << "\blue You slot \the [I] into \the [src]." + updateUsrDialog() + return + else if(istype(I, /obj/item/weapon/reagent_containers/glass))//If it's a glass beaker. + var/total_reagent_transfer//Keep track of this stuff. + for(var/reagent_id in reagent_list) + var/datum/reagent/R = I.reagents.has_reagent(reagent_id)//Mostly to pull up the name of the reagent after calculating. Also easier to use than writing long proc paths. + if(R&&reagents.get_reagent_amount(reagent_id)=a_transfer)//Radium is always special. + //Here we determine how much reagent will actually transfer if there is enough to transfer or there is a need of transfer. Minimum of max amount available (using a_transfer) or amount needed. + var/amount_to_transfer = min( (r_maxamount+(reagent_id == "radium"?(a_boost*a_transfer):0)-reagents.get_reagent_amount(reagent_id)) ,(round(R.volume/a_transfer))*a_transfer)//In the end here, we round the amount available, then multiply it again. + R.volume -= amount_to_transfer//Remove from reagent volume. Don't want to delete the reagent now since we need to perserve the name. + reagents.add_reagent(reagent_id, amount_to_transfer)//Add to suit. Reactions are not important. + total_reagent_transfer += amount_to_transfer//Add to total reagent trans. + U << "Added [amount_to_transfer] units of [R.name]."//Reports on the specific reagent added. + I.reagents.update_total()//Now we manually update the total to make sure everything is properly shoved under the rug. + + U << "Replenished a total of [total_reagent_transfer ? total_reagent_transfer : "zero"] chemical units."//Let the player know how much total volume was added. + return + else if(istype(I, /obj/item/weapon/cell)) + if(I:maxcharge>cell.maxcharge&&n_gloves&&n_gloves.candrain) + U << "\blue Higher maximum capacity detected.\nUpgrading..." + if (n_gloves&&n_gloves.candrain&&do_after(U,s_delay)) + U.drop_item() + I.loc = src + I:charge = min(I:charge+cell.charge, I:maxcharge) + var/obj/item/weapon/cell/old_cell = cell + old_cell.charge = 0 + U.put_in_hand(old_cell) + old_cell.add_fingerprint(U) + old_cell.corrupt() + old_cell.updateicon() + cell = I + U << "\blue Upgrade complete. Maximum capacity: [round(cell.maxcharge/100)]%" + else + U << "\red Procedure interrupted. Protocol terminated." + return + else if(istype(I, /obj/item/weapon/disk/tech_disk))//If it's a data disk, we want to copy the research on to the suit. + if(I:stored)//If it has something on it. + U << "Research information detected, processing..." + if(do_after(U,s_delay)) + for(var/datum/tech/current_data in stored_research) + if(current_data.id==I:stored.id) + if(current_data.levelERROR: \black Procedure interrupted. Process terminated." + else + I.loc = src + t_disk = I + U << "\blue You slot \the [I] into \the [src]." + return + ..() + +/obj/item/clothing/suit/space/space_ninja/proc/toggle_stealth() + var/mob/living/carbon/human/U = affecting + if(s_active) + cancel_stealth() + else + spawn(0) + anim(U.loc,U,'mob.dmi',,"cloak",,U.dir) + s_active=!s_active + U << "\blue You are now invisible to normal detection." + for(var/mob/O in oviewers(U)) + O.show_message("[U.name] vanishes into thin air!",1) + return + +/obj/item/clothing/suit/space/space_ninja/proc/cancel_stealth() + var/mob/living/carbon/human/U = affecting + if(s_active) + spawn(0) + anim(U.loc,U,'mob.dmi',,"uncloak",,U.dir) + s_active=!s_active + U << "\blue You are now visible." + for(var/mob/O in oviewers(U)) + O.show_message("[U.name] appears from thin air!",1) + return 1 + return 0 + +/obj/item/clothing/suit/space/space_ninja/proc/blade_check(mob/living/carbon/U, X = 1)//Default to checking for blade energy. + switch(X) + if(1) + if(istype(U.get_active_hand(), /obj/item/weapon/melee/energy/blade)) + if(cell.charge<=0)//If no charge left. + U.drop_item()//Blade is dropped from active hand (and deleted). + else return 1 + else if(istype(U.get_inactive_hand(), /obj/item/weapon/melee/energy/blade)) + if(cell.charge<=0) + U.swap_hand()//swap hand + U.drop_item()//drop blade + else return 1 + if(2) + if(istype(U.get_active_hand(), /obj/item/weapon/melee/energy/blade)) + U.drop_item() + if(istype(U.get_inactive_hand(), /obj/item/weapon/melee/energy/blade)) + U.swap_hand() + U.drop_item() + return 0 + +/obj/item/clothing/suit/space/space_ninja/examine() + set src in view() + ..() + if(s_initialized) + var/mob/living/carbon/human/U = affecting + if(s_control) + U << "All systems operational. Current energy capacity: [cell.charge]." + if(!kamikaze) + U << "The CLOAK-tech device is [s_active?"active":"inactive"]." + else + U << "\red KAMIKAZE MODE ENGAGED!" + U << "There are [s_bombs] smoke bombs remaining." + U << "There are [a_boost] adrenaline boosters remaining." + else + U << "ÈrrÖR Ða†Ða†Ä No-†-† fÖÚNÐ 3RRÖr" + +/* +=================================================================================== +<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +=================================================================================== +*/ + +//=======//ENERGY DRAIN PROCS//=======// + +/obj/item/clothing/gloves/space_ninja/proc/drain(target_type as text, target, obj/suit) +//Var Initialize + var/obj/item/clothing/suit/space/space_ninja/S = suit + var/mob/living/carbon/human/U = S.affecting + var/obj/item/clothing/gloves/space_ninja/G = S.n_gloves + + var/drain = 0//To drain from battery. + var/maxcapacity = 0//Safety check for full battery. + var/totaldrain = 0//Total energy drained. + + G.draining = 1 + + if(target_type!="RESEARCH")//I lumped research downloading here for ease of use. + U << "\blue Now charging battery..." + + switch(target_type) + + if("APC") + var/obj/machinery/power/apc/A = target + if(A.cell&&A.cell.charge) + var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() + spark_system.set_up(5, 0, A.loc) + while(G.candrain&&A.cell.charge>0&&!maxcapacity) + drain = rand(G.mindrain,G.maxdrain) + if(A.cell.chargeS.cell.maxcharge) + drain = S.cell.maxcharge-S.cell.charge + maxcapacity = 1//Reached maximum battery capacity. + if (do_after(U,10)) + spark_system.start() + playsound(A.loc, "sparks", 50, 1) + A.cell.charge-=drain + S.cell.charge+=drain + totaldrain+=drain + else break + U << "\blue Gained [totaldrain] energy from the APC." + if(!A.emagged) + flick("apc-spark", src) + A.emagged = 1 + A.locked = 0 + A.updateicon() + else + U << "\red This APC has run dry of power. You must find another source." + + if("SMES") + var/obj/machinery/power/smes/A = target + if(A.charge) + var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() + spark_system.set_up(5, 0, A.loc) + while(G.candrain&&A.charge>0&&!maxcapacity) + drain = rand(G.mindrain,G.maxdrain) + if(A.chargeS.cell.maxcharge) + drain = S.cell.maxcharge-S.cell.charge + maxcapacity = 1 + if (do_after(U,10)) + spark_system.start() + playsound(A.loc, "sparks", 50, 1) + A.charge-=drain + S.cell.charge+=drain + totaldrain+=drain + else break + U << "\blue Gained [totaldrain] energy from the SMES cell." + else + U << "\red This SMES cell has run dry of power. You must find another source." + + if("CELL") + var/obj/item/weapon/cell/A = target + if(A.charge) + if (G.candrain&&do_after(U,30)) + U << "\blue Gained [A.charge] energy from the cell." + if(S.cell.charge+A.charge>S.cell.maxcharge) + S.cell.charge=S.cell.maxcharge + else + S.cell.charge+=A.charge + A.charge = 0 + G.draining = 0 + A.corrupt() + A.updateicon() + else + U << "\red Procedure interrupted. Protocol terminated." + else + U << "\red This cell is empty and of no use." + + if("MACHINERY")//Can be applied to generically to all powered machinery. I'm leaving this alone for now. + var/obj/machinery/A = target + if(A.powered())//If powered. + + var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() + spark_system.set_up(5, 0, A.loc) + + var/obj/machinery/power/apc/B = A.loc.loc:get_apc()//Object.turf.area find APC + if(B)//If APC exists. Might not if the area is unpowered like CentCom. + var/datum/powernet/PN = B.terminal.powernet + while(G.candrain&&!maxcapacity&&!isnull(A))//And start a proc similar to drain from wire. + drain = rand(G.mindrain,G.maxdrain) + var/drained = 0 + if(PN&&do_after(U,10)) + drained = min(drain, PN.avail) + PN.newload += drained + if(drained < drain)//if no power on net, drain apcs + for(var/obj/machinery/power/terminal/T in PN.nodes) + if(istype(T.master, /obj/machinery/power/apc)) + var/obj/machinery/power/apc/AP = T.master + if(AP.operating && AP.cell && AP.cell.charge>0) + AP.cell.charge = max(0, AP.cell.charge - 5) + drained += 5 + else break + S.cell.charge += drained + if(S.cell.charge>S.cell.maxcharge) + totaldrain += (drained-(S.cell.charge-S.cell.maxcharge)) + S.cell.charge = S.cell.maxcharge + maxcapacity = 1 + else + totaldrain += drained + spark_system.start() + if(drained==0) break + U << "\blue Gained [totaldrain] energy from the power network." + else + U << "\red Power network could not be found. Aborting." + else + U << "\red This recharger is not providing energy. You must find another source." + + if("RESEARCH") + var/obj/machinery/A = target + U << "\blue Hacking \the [A]..." + spawn(0) + var/turf/location = get_turf(U) + for(var/mob/living/silicon/ai/AI in world) + AI << "\red Network Alert: Hacking attempt detected[location?" in [location]":". Unable to pinpoint location"]." + if(A:files&&A:files.known_tech.len) + for(var/datum/tech/current_data in S.stored_research) + U << "\blue Checking \the [current_data.name] database." + if(do_after(U, S.s_delay)&&G.candrain&&!isnull(A)) + for(var/datum/tech/analyzing_data in A:files.known_tech) + if(current_data.id==analyzing_data.id) + if(analyzing_data.level>current_data.level) + U << "\blue Database: \black UPDATED." + current_data.level = analyzing_data.level + break//Move on to next. + else break//Otherwise, quit processing. + U << "\blue Data analyzed. Process finished." + + if("WIRE") + var/obj/structure/cable/A = target + var/datum/powernet/PN = A.get_powernet() + while(G.candrain&&!maxcapacity&&!isnull(A)) + drain = (round((rand(G.mindrain,G.maxdrain))/2)) + var/drained = 0 + if(PN&&do_after(U,10)) + drained = min(drain, PN.avail) + PN.newload += drained + if(drained < drain)//if no power on net, drain apcs + for(var/obj/machinery/power/terminal/T in PN.nodes) + if(istype(T.master, /obj/machinery/power/apc)) + var/obj/machinery/power/apc/AP = T.master + if(AP.operating && AP.cell && AP.cell.charge>0) + AP.cell.charge = max(0, AP.cell.charge - 5) + drained += 5 + else break + S.cell.charge += drained + if(S.cell.charge>S.cell.maxcharge) + totaldrain += (drained-(S.cell.charge-S.cell.maxcharge)) + S.cell.charge = S.cell.maxcharge + maxcapacity = 1 + else + totaldrain += drained + S.spark_system.start() + if(drained==0) break + U << "\blue Gained [totaldrain] energy from the power network." + + if("MECHA") + var/obj/mecha/A = target + A.occupant_message("\red Warning: Unauthorized access through sub-route 4, block H, detected.") + if(A.get_charge()) + while(G.candrain&&A.cell.charge>0&&!maxcapacity) + drain = rand(G.mindrain,G.maxdrain) + if(A.cell.chargeS.cell.maxcharge) + drain = S.cell.maxcharge-S.cell.charge + maxcapacity = 1 + if (do_after(U,10)) + A.spark_system.start() + playsound(A.loc, "sparks", 50, 1) + A.cell.use(drain) + S.cell.charge+=drain + totaldrain+=drain + else break + U << "\blue Gained [totaldrain] energy from [src]." + else + U << "\red The exosuit's battery has run dry of power. You must find another source." + + if("CYBORG") + var/mob/living/silicon/robot/A = target + A << "\red Warning: Unauthorized access through sub-route 12, block C, detected." + G.draining = 1 + if(A.cell&&A.cell.charge) + while(G.candrain&&A.cell.charge>0&&!maxcapacity) + drain = rand(G.mindrain,G.maxdrain) + if(A.cell.chargeS.cell.maxcharge) + drain = S.cell.maxcharge-S.cell.charge + maxcapacity = 1 + if (do_after(U,10)) + A.spark_system.start() + playsound(A.loc, "sparks", 50, 1) + A.cell.charge-=drain + S.cell.charge+=drain + totaldrain+=drain + else break + U << "\blue Gained [totaldrain] energy from [A]." + else + U << "\red Their battery has run dry of power. You must find another source." + + else//Else nothing :< + + G.draining = 0 + + return + +//=======//GENERAL PROCS//=======// + +/obj/item/clothing/gloves/space_ninja/proc/toggled() + set name = "Toggle Interaction" + set desc = "Toggles special interaction on or off." + set category = "Ninja Equip" + + var/mob/living/carbon/human/U = loc + U << "You [candrain?"disable":"enable"] special interaction." + candrain=!candrain + +/obj/item/clothing/gloves/space_ninja/examine() + set src in view() + ..() + if(!canremove) + var/mob/living/carbon/human/U = loc + U << "The energy drain mechanism is: [candrain?"active":"inactive"]." + +/* +=================================================================================== +<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +=================================================================================== +*/ + +/obj/item/clothing/mask/gas/voice/space_ninja/New() + verbs += /obj/item/clothing/mask/gas/voice/space_ninja/proc/togglev + verbs += /obj/item/clothing/mask/gas/voice/space_ninja/proc/switchm + +//This proc is linked to human life.dm. It determines what hud icons to display based on mind special role for most mobs. +/obj/item/clothing/mask/gas/voice/space_ninja/proc/assess_targets(list/target_list, mob/living/carbon/U) + var/icon/tempHud = 'hud.dmi' + for(var/mob/living/target in target_list) + if(iscarbon(target)) + switch(target.mind.special_role) + if("traitor") + U.client.images += image(tempHud,target,"hudtraitor") + if("Revolutionary","Head Revolutionary") + U.client.images += image(tempHud,target,"hudrevolutionary") + if("Cultist") + U.client.images += image(tempHud,target,"hudcultist") + if("Changeling") + U.client.images += image(tempHud,target,"hudchangeling") + if("Wizard","Fake Wizard") + U.client.images += image(tempHud,target,"hudwizard") + if("Hunter","Sentinel","Drone","Queen") + U.client.images += image(tempHud,target,"hudalien") + if("Syndicate") + U.client.images += image(tempHud,target,"hudoperative") + if("Death Commando") + U.client.images += image(tempHud,target,"huddeathsquad") + if("Space Ninja") + U.client.images += image(tempHud,target,"hudninja") + else//If we don't know what role they have but they have one. + U.client.images += image(tempHud,target,"hudunknown1") + else//If the silicon mob has no law datum, no inherent laws, or a law zero, add them to the hud. + var/mob/living/silicon/silicon_target = target + if(!silicon_target.laws||(silicon_target.laws&&(silicon_target.laws.zeroth||!silicon_target.laws.inherent.len))) + if(isrobot(silicon_target))//Different icons for robutts and AI. + U.client.images += image(tempHud,silicon_target,"hudmalborg") + else + U.client.images += image(tempHud,silicon_target,"hudmalai") + return 1 + +/obj/item/clothing/mask/gas/voice/space_ninja/proc/togglev() + set name = "Toggle Voice" + set desc = "Toggles the voice synthesizer on or off." + set category = "Ninja Equip" + + var/mob/U = loc//Can't toggle voice when you're not wearing the mask. + var/vchange = (alert("Would you like to synthesize a new name or turn off the voice synthesizer?",,"New Name","Turn Off")) + if(vchange=="New Name") + var/chance = rand(1,100) + switch(chance) + if(1 to 50)//High chance of a regular name. + voice = "[rand(0,1)==1?pick(first_names_female):pick(first_names_male)] [pick(last_names)]" + if(51 to 80)//Smaller chance of a clown name. + voice = "[pick(clown_names)]" + if(81 to 90)//Small chance of a wizard name. + voice = "[pick(wizard_first)] [pick(wizard_second)]" + if(91 to 100)//Small chance of an existing crew name. + var/names[] = new() + for(var/mob/living/carbon/human/M in world) + if(M==U||!M.client||!M.real_name) continue + names.Add(M.real_name) + voice = !names.len ? "Cuban Pete" : pick(names) + U << "You are now mimicking [voice]." + else + U << "The voice synthesizer is [voice!="Unknown"?"now":"already"] deactivated." + voice = "Unknown" + return + +/obj/item/clothing/mask/gas/voice/space_ninja/proc/switchm() + set name = "Switch Mode" + set desc = "Switches between Night Vision, Meson, or Thermal vision modes." + set category = "Ninja Equip" + //Have to reset these manually since life.dm is retarded like that. Go figure. + //This will only work for humans because only they have the appropriate code for the mask. + var/mob/U = loc + switch(mode) + if(0) + mode=1 + U << "Switching mode to Night Vision." + if(1) + mode=2 + U.see_in_dark = 2 + U << "Switching mode to Thermal Scanner." + if(2) + mode=3 + U.see_invisible = 0 + U.sight &= ~SEE_MOBS + U << "Switching mode to Meson Scanner." + if(3) + mode=0 + U.sight &= ~SEE_TURFS + U << "Switching mode to Scouter." + +/obj/item/clothing/mask/gas/voice/space_ninja/examine() + set src in view() + ..() + + var/mode + switch(mode) + if(0) + mode = "Scouter" + if(1) + mode = "Night Vision" + if(2) + mode = "Thermal Scanner" + if(3) + mode = "Meson Scanner" + usr << "[mode] is active."//Leaving usr here since it may be on the floor or on a person. + usr << "Voice mimicking algorithm is set [!vchange?"inactive":"active"]." + +/* +=================================================================================== +<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +=================================================================================== +*/ + +/* +It will teleport people to a holding facility after 30 seconds. (Check the process() proc to change where teleport goes) +It is possible to destroy the net by the occupant or someone else. +*/ + +/obj/effect/energy_net + name = "energy net" + desc = "It's a net made of green energy." + icon = 'effects.dmi' + icon_state = "energynet" + + density = 1//Can't pass through. + opacity = 0//Can see through. + mouse_opacity = 1//So you can hit it with stuff. + anchored = 1//Can't drag/grab the trapped mob. + + var + health = 25//How much health it has. + mob/living/affecting = null//Who it is currently affecting, if anyone. + mob/living/master = null//Who shot web. Will let this person know if the net was successful or failed. + + proc + healthcheck() + if(health <=0) + density = 0 + if(affecting) + var/mob/living/carbon/M = affecting + M.anchored = 0 + for(var/mob/O in viewers(src, 3)) + O.show_message(text("[] was recovered from the energy net!", M.name), 1, text("You hear a grunt."), 2) + if(!isnull(master))//As long as they still exist. + master << "\red ERROR: \black unable to initiate transport protocol. Procedure terminated." + del(src) + return + + process(var/mob/living/carbon/M as mob) + var/check = 30//30 seconds before teleportation. Could be extended I guess. + var/mob_name = affecting.name//Since they will report as null if terminated before teleport. + //The person can still try and attack the net when inside. + while(!isnull(M)&&!isnull(src)&&check>0)//While M and net exist, and 30 seconds have not passed. + check-- + sleep(10) + + if(isnull(M)||M.loc!=loc)//If mob is gone or not at the location. + if(!isnull(master))//As long as they still exist. + master << "\red ERROR: \black unable to locate \the [mob_name]. Procedure terminated." + del(src)//Get rid of the net. + return + + if(!isnull(src))//As long as both net and person exist. + //No need to check for countdown here since while() broke, it's implicit that it finished. + + density = 0//Make the net pass-through. + invisibility = 101//Make the net invisible so all the animations can play out. + health = INFINITY//Make the net invincible so that an explosion/something else won't kill it while, spawn() is running. + for(var/obj/item/W in M) + if(istype(M,/mob/living/carbon/human)) + if(W==M:w_uniform) continue//So all they're left with are shoes and uniform. + if(W==M:shoes) continue + M.drop_from_slot(W) + + spawn(0) + playsound(M.loc, 'sparks4.ogg', 50, 1) + anim(M.loc,M,'mob.dmi',,"phaseout",,M.dir) + + M.loc = pick(holdingfacility)//Throw mob in to the holding facility. + M << "\red You appear in a strange place!" + + spawn(0) + var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() + spark_system.set_up(5, 0, M.loc) + spark_system.start() + playsound(M.loc, 'phasein.ogg', 25, 1) + playsound(M.loc, 'sparks2.ogg', 50, 1) + anim(M.loc,M,'mob.dmi',,"phasein",,M.dir) + del(src)//Wait for everything to finish, delete the net. Else it will stop everything once net is deleted, including the spawn(0). + + for(var/mob/O in viewers(src, 3)) + O.show_message(text("[] vanished!", M), 1, text("You hear sparks flying!"), 2) + + if(!isnull(master))//As long as they still exist. + master << "\blue SUCCESS: \black transport procedure of \the [affecting] complete." + + M.anchored = 0//Important. + + else//And they are free. + M << "\blue You are free of the net!" + return + + bullet_act(var/obj/item/projectile/Proj) + health -= Proj.damage + healthcheck() + return 0 + + ex_act(severity) + switch(severity) + if(1.0) + health-=50 + if(2.0) + health-=50 + if(3.0) + health-=prob(50)?50:25 + healthcheck() + return + + blob_act() + health-=50 + healthcheck() + return + + meteorhit() + health-=50 + healthcheck() + return + + hitby(AM as mob|obj) + ..() + for(var/mob/O in viewers(src, null)) + O.show_message(text("\red [src] was hit by [AM]."), 1) + var/tforce = 0 + if(ismob(AM)) + tforce = 10 + else + tforce = AM:throwforce + playsound(src.loc, 'slash.ogg', 80, 1) + health = max(0, health - tforce) + healthcheck() + ..() + return + + attack_hand() + if ((usr.mutations & HULK)) + usr << text("\blue You easily destroy the energy net.") + for(var/mob/O in oviewers(src)) + O.show_message(text("\red [] rips the energy net apart!", usr), 1) + health-=50 + healthcheck() + return + + attack_paw() + return attack_hand() + + attack_alien() + if (islarva(usr)) + return + usr << text("\green You claw at the net.") + for(var/mob/O in oviewers(src)) + O.show_message(text("\red [] claws at the energy net!", usr), 1) + playsound(src.loc, 'slash.ogg', 80, 1) + health -= rand(10, 20) + if(health <= 0) + usr << text("\green You slice the energy net to pieces.") + for(var/mob/O in oviewers(src)) + O.show_message(text("\red [] slices the energy net apart!", usr), 1) + healthcheck() + return + + attackby(obj/item/weapon/W as obj, mob/user as mob) + var/aforce = W.force + health = max(0, health - aforce) + healthcheck() + ..() return \ No newline at end of file diff --git a/code/game/gamemodes/events/space_ninja.dm b/code/game/events/EventProcs/space_ninja.dm similarity index 97% rename from code/game/gamemodes/events/space_ninja.dm rename to code/game/events/EventProcs/space_ninja.dm index 02a81e97c5b..355801614b9 100644 --- a/code/game/gamemodes/events/space_ninja.dm +++ b/code/game/events/EventProcs/space_ninja.dm @@ -1,996 +1,996 @@ -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+++++++++++++++++++++++++++++++++++++// //++++++++++++++++++++++++++++++++++ -======================================SPACE NINJA SETUP==================================== -___________________________________________________________________________________________ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -*/ - -/* - README: - - Data: - - >> space_ninja.dm << is this file. It contains a variety of procs related to either spawning space ninjas, - modifying their verbs, various help procs, testing debug-related content, or storing unused procs for later. - Similar functions should go into this file, along with anything else that may not have an explicit category. - IMPORTANT: actual ninja suit, gloves, etc, are stored under the appropriate clothing files. If you need to change - variables or look them up, look there. Easiest way is through the map file browser. - - >> ninja_abilities.dm << contains all the ninja-related powers. Spawning energy swords, teleporting, and the like. - If more powers are added, or perhaps something related to powers, it should go there. Make sure to describe - what an ability/power does so it's easier to reference later without looking at the code. - IMPORTANT: verbs are still somewhat funky to work with. If an argument is specified but is not referenced in a way - BYOND likes, in the code content, the verb will fail to trigger. Nothing will happen, literally, when clicked. - This can be bypassed by either referencing the argument properly, or linking to another proc with the argument - attached. The latter is what I like to do for certain cases--sometimes it's necessary to do that regardless. - - >> ninja_equipment.dm << deals with all the equipment-related procs for a ninja. Primarily it has the suit, gloves, - and mask. The suit is by far the largest section of code out of the three and includes a lot of code that ties in - to other functions. This file has gotten kind of large so breaking it up may be in order. I use section hearders. - IMPORTANT: not much to say here. Follow along with the comments and adding new functions should be a breeze. Also - know that certain equipment pieces are linked in other files. The energy blade, for example, has special - functions defined in the appropriate files (airlock, securestorage, etc). - - General Notes: - - I created space ninjas with the expressed purpose of spicing up boring rounds. That is, ninjas are to xenos as marauders are to - death squads. Ninjas are stealthy, tech-savvy, and powerful. Not to say marauders are all of those things, but a clever ninja - should have little problem murderampaging their way through just about anything. Short of admin wizards maybe. - HOWEVER! - Ninjas also have a fairly great weakness as they require energy to use abilities. If, theoretically, there is a game - mode based around space ninjas, make sure to account for their energy needs. - - Admin Notes: - - Ninjas are not admin PCs--please do not use them for that purpose. They are another way to participate in the game post-death, - like pais, xenos, death squads, and cyborgs. - I'm currently looking for feedback from regular players since beta testing is largely done. I would appreciate if - you spawned regular players as ninjas when rounds are boring. Or exciting, it's all good as long as there is feedback. - You can also spawn ninja gear manually if you want to. - - How to do that: - Make sure your character has a mind. - Change their assigned_role to "MODE", no quotes. Otherwise, the suit won't initialize. - Change their special_role to "Space Ninja", no quotes. Otherwise, the character will be gibbed. - Spawn ninja gear, put it on, hit initialize. Let the suit do the rest. You are now a space ninja. - I don't recommend messing with suit variables unless you really know what you're doing. - - Miscellaneous Notes: - - Potential Upgrade Tree: - Energy Shield: - Extra Ability - Syndicate Shield device? - Works like the force wall spell, except can be kept indefinitely as long as energy remains. Toggled on or off. - Would block bullets and the like. - Phase Shift - Extra Ability - Advanced Sensors? - Instead of being unlocked at the start, Phase Shieft would become available once requirements are met. - Uranium-based Recharger: - Suit Upgrade - Unsure - Instead of losing energy each second, the suit would regain the same amount of energy. - This would not count in activating stealth and similar. - Extended Battery Life: - Suit Upgrade - Battery of higher capacity - Already implemented. Replace current battery with one of higher capacity. - Advanced Cloak-Tech device. - Suit Upgrade - Syndicate Cloaking Device? - Remove cloak failure rate. -*/ - -//=======//RANDOM EVENT//=======// -/* -Also a dynamic ninja mission generator. -I decided to scrap round-specific objectives since keeping track of them would require some form of tracking. -When I already created about 4 new objectives, this doesn't seem terribly important or needed. -*/ - -/var/global/toggle_space_ninja = 1//If ninjas can spawn or not. -/var/global/sent_ninja_to_station = 0//If a ninja is already on the station. - -/proc/space_ninja_arrival() - - var/datum/game_mode/current_mode = ticker.mode - var/datum/mind/current_mind - - /*Is the ninja playing for the good or bad guys? Is the ninja helping or hurting the station? - Their directives also influence behavior. At least in theory.*/ - var/side = pick("face","heel") - - var/antagonist_list[] = list()//The main bad guys. Evil minds that plot destruction. - var/protagonist_list[] = current_mode.get_living_heads()//The good guys. Mostly Heads. Who are alive. - - var/xeno_list[] = list()//Aliens. - var/commando_list[] = list()//Commandos. - - //We want the ninja to appear only in certain modes. - var/acceptable_modes_list[] = list("traitor","revolution","cult","wizard","changeling","traitorchan","nuclear","malfunction","monkey") - if(!(current_mode.config_tag in acceptable_modes_list)) - return - - /*No longer need to determine what mode it is since bad guys are basically universal. - And there is now a mode with two types of bad guys.*/ - - var/possible_bad_dudes[] = list(current_mode.traitors,current_mode.head_revolutionaries,current_mode.head_revolutionaries, - current_mode.cult,current_mode.wizards,current_mode.changelings,current_mode.syndicates) - for(var/list in possible_bad_dudes)//For every possible antagonist type. - for(current_mind in list)//For each mind in that list. - if(current_mind.current&¤t_mind.current.stat!=2)//If they are not destroyed and not dead. - antagonist_list += current_mind//Add them. - - if(protagonist_list.len)//If the mind is both a protagonist and antagonist. - for(current_mind in protagonist_list) - if(current_mind in antagonist_list) - protagonist_list -= current_mind//We only want it in one list. -/* -Malf AIs/silicons aren't added. Monkeys aren't added. Messes with objective completion. Only humans are added. -*/ - - //Here we pick a location and spawn the ninja. - var/list/spawn_list = list() - for(var/obj/effect/landmark/L in world) - if (L.name == "carpspawn") - spawn_list.Add(L) - - var/mob/dead/observer/G - var/list/candidates = list() - for(G in world) - if(G.client)//Now everyone can ninja! - if(((G.client.inactivity/10)/60) <= 5) - candidates.Add(G) - - //The ninja will be created on the right spawn point or at late join. - var/mob/living/carbon/human/new_ninja = create_space_ninja(pick(spawn_list.len ? spawn_list : latejoin )) - - if(candidates.len) - G = pick(candidates) - new_ninja.key = G.key - new_ninja.mind.key = new_ninja.key - new_ninja.wear_suit:randomize_param()//Give them a random set of suit parameters. - new_ninja.internal = new_ninja.s_store //So the poor ninja has something to breath when they spawn in spess. - new_ninja.internals.icon_state = "internal1" - del(G) - else - del(new_ninja) - return - //Now for the rest of the stuff. - - var/datum/mind/ninja_mind = new_ninja.mind//For easier reference. - var/mission_set = 0//To determine if we need to do further processing. - //Xenos and deathsquads take precedence over everything else. - - //Unless the xenos are hiding in a locker somewhere, this'll find em. - for(var/mob/living/carbon/alien/humanoid/xeno in world) - if(istype(xeno)) - xeno_list += xeno - - if(xeno_list.len>3)//If there are more than three humanoid xenos on the station, time to get dangerous. - //Here we want the ninja to murder all the queens. The other aliens don't really matter. - var/xeno_queen_list[] = list() - for(var/mob/living/carbon/alien/humanoid/queen/xeno_queen in xeno_list) - if(xeno_queen.mind&&xeno_queen.stat!=2) - xeno_queen_list += xeno_queen - if(xeno_queen_list.len&&side=="face")//If there are queen about and the probability is 50. - for(var/mob/living/carbon/alien/humanoid/queen/xeno_queen in xeno_queen_list) - var/datum/objective/assassinate/ninja_objective = new - //We'll do some manual overrides to properly set it up. - ninja_objective.owner = ninja_mind - ninja_objective.target = xeno_queen.mind - ninja_objective.explanation_text = "Kill \the [xeno_queen]." - ninja_mind.objectives += ninja_objective - mission_set = 1 - - if(sent_strike_team&&side=="heel"&&antagonist_list.len)//If a strike team was sent, murder them all like a champ. - for(current_mind in antagonist_list)//Search and destroy. Since we already have an antagonist list, they should appear there. - if(current_mind.special_role=="Death Commando") - commando_list += current_mind - if(commando_list.len)//If there are living commandos still in play. - for(var/mob/living/carbon/human/commando in commando_list) - var/datum/objective/assassinate/ninja_objective = new - ninja_objective.owner = ninja_mind - ninja_objective.find_target_by_role(commando.mind.special_role,1) - ninja_mind.objectives += ninja_objective - mission_set = 1 -/* -If there are no antogonists left it could mean one of two things: - A) The round is about to end. No harm in spawning the ninja here. - B) The round is still going and ghosts are probably rioting for something to happen. -In either case, it's a good idea to spawn the ninja with a semi-random set of objectives. -*/ - if(!mission_set)//If mission was not set. - - var/current_minds[]//List being looked on in the following code. - var/side_list = side=="face" ? 2 : 1//For logic gating. - var/hostile_targets[] = list()//The guys actually picked for the assassination or whatever. - var/friendly_targets[] = list()//The guys the ninja must protect. - - for(var/i=2,i>0,i--)//Two lists. - current_minds = i==2 ? antagonist_list : protagonist_list//Which list are we looking at? - for(var/t=3,(current_minds.len&&t>0),t--)//While the list is not empty and targets remain. Also, 3 targets is good. - current_mind = pick(current_minds)//Pick a random person. - /*I'm creating a logic gate here based on the ninja affiliation that compares the list being - looked at to the affiliation. Affiliation is just a number used to compare. Meaning comes from the logic involved. - If the list being looked at is equal to the ninja's affiliation, add the mind to hostiles. - If not, add the mind to friendlies. Since it can't be both, it will be added only to one or the other.*/ - hostile_targets += i==side_list ? current_mind : null//Adding null doesn't add anything. - friendly_targets += i!=side_list ? current_mind : null - current_minds -= current_mind//Remove the mind so it's not picked again. - - var/objective_list[] = list(1,2,3,4,5,6)//To remove later. - for(var/i=rand(1,3),i>0,i--)//Want to get a few random objectives. Currently up to 3. - if(!hostile_targets.len)//Remove appropriate choices from switch list if the target lists are empty. - objective_list -= 1 - objective_list -= 4 - if(!friendly_targets.len) - objective_list -= 3 - switch(pick(objective_list)) - if(1)//kill - current_mind = pick(hostile_targets) - - var/datum/objective/assassinate/ninja_objective = new - ninja_objective.owner = ninja_mind - ninja_objective.find_target_by_role((current_mind.special_role ? current_mind.special_role : current_mind.assigned_role),(current_mind.special_role?1:0))//If they have a special role, use that instead to find em. - ninja_mind.objectives += ninja_objective - - hostile_targets -= current_mind//Remove them from the list. - if(2)//Steal - var/datum/objective/steal/ninja_objective = new - var/target_item = pick(ninja_objective.possible_items_special) - ninja_objective.set_target(target_item) - ninja_mind.objectives += ninja_objective - - objective_list -= 2 - if(3)//Protect. Keeping people alive can be pretty difficult. - current_mind = pick(friendly_targets) - - var/datum/objective/protect/ninja_objective = new - ninja_objective.owner = ninja_mind - ninja_objective.find_target_by_role((current_mind.special_role ? current_mind.special_role : current_mind.assigned_role),(current_mind.special_role?1:0)) - ninja_mind.objectives += ninja_objective - - friendly_targets -= current_mind - if(4)//Debrain - current_mind = pick(hostile_targets) - - var/datum/objective/debrain/ninja_objective = new - ninja_objective.owner = ninja_mind - ninja_objective.find_target_by_role((current_mind.special_role ? current_mind.special_role : current_mind.assigned_role),(current_mind.special_role?1:0)) - ninja_mind.objectives += ninja_objective - - hostile_targets -= current_mind//Remove them from the list. - if(5)//Download research - var/datum/objective/download/ninja_objective = new - ninja_objective.gen_amount_goal() - ninja_mind.objectives += ninja_objective - - objective_list -= 5 - if(6)//Capture - var/datum/objective/capture/ninja_objective = new - ninja_objective.gen_amount_goal() - ninja_mind.objectives += ninja_objective - - objective_list -= 6 - - if(ninja_mind.objectives.len)//If they got some objectives out of that. - mission_set = 1 - - if(!ninja_mind.objectives.len||!mission_set)//If they somehow did not get an objective at this point, time to destroy the station. - var/nuke_code - var/temp_code - for(var/obj/machinery/nuclearbomb/N in world) - temp_code = text2num(N.r_code) - if(temp_code)//if it's actually a number. It won't convert any non-numericals. - nuke_code = N.r_code - break - if(nuke_code)//If there is a nuke device in world and we got the code. - var/datum/objective/nuclear/ninja_objective = new//Fun. - ninja_objective.owner = ninja_mind - ninja_objective.explanation_text = "Destroy the station with a nuclear device. The code is [nuke_code]." //Let them know what the code is. - - //Finally add a survival objective since it's usually broad enough for any round type. - var/datum/objective/survive/ninja_objective = new - ninja_objective.owner = ninja_mind - ninja_mind.objectives += ninja_objective - - var/directive = generate_ninja_directive(side) - new_ninja << "\blue \nYou are an elite mercenary assassin of the Spider Clan, [new_ninja.real_name]. The dreaded \red SPACE NINJA!\blue You have a variety of abilities at your disposal, thanks to your nano-enhanced cyber armor. Remember your training (initialize your suit by right clicking on it)! \nYour current directive is: \red [directive]" - new_ninja.mind.store_memory("Directive: \red [directive]
      ") - - var/obj_count = 1 - new_ninja << "\blue Your current objectives:" - for(var/datum/objective/objective in ninja_mind.objectives) - new_ninja << "Objective #[obj_count]: [objective.explanation_text]" - obj_count++ - - sent_ninja_to_station = 1//And we're done. - return new_ninja//Return the ninja in case we need to reference them later. - -/* -This proc will give the ninja a directive to follow. They are not obligated to do so but it's a fun roleplay reminder. -Making this random or semi-random will probably not work without it also being incredibly silly. -As such, it's hard-coded for now. No reason for it not to be, really. -*/ -/proc/generate_ninja_directive(side) - var/directive = "[side=="face"?"Nanotrasen":"The Syndicate"] is your employer. "//Let them know which side they're on. - switch(rand(1,13)) - if(1) - directive += "The Spider Clan must not be linked to this operation. Remain as hidden and covert as possible." - if(2) - directive += "[station_name] is financed by an enemy of the Spider Clan. Cause as much structural damage as possible." - if(3) - directive += "A wealthy animal rights activist has made a request we cannot refuse. Prioritize saving animal lives whenever possible." - if(4) - directive += "The Spider Clan absolutely cannot be linked to this operation. Eliminate all witnesses using most extreme prejudice." - if(5) - directive += "We are currently negotiating with Nanotrasen command. Prioritize saving human lives over ending them." - if(6) - directive += "We are engaged in a legal dispute over [station_name]. If a laywer is present on board, force their cooperation in the matter." - if(7) - directive += "A financial backer has made an offer we cannot refuse. Implicate Syndicate involvement in the operation." - if(8) - directive += "Let no one question the mercy of the Spider Clan. Ensure the safety of all non-essential personnel you encounter." - if(9) - directive += "A free agent has proposed a lucrative business deal. Implicate Nanotrasen involvement in the operation." - if(10) - directive += "Our reputation is on the line. Harm as few civilians or innocents as possible." - if(11) - directive += "Our honor is on the line. Utilize only honorable tactics when dealing with opponents." - if(12) - directive += "We are currently negotiating with a Syndicate leader. Disguise assassinations as suicide or another natural cause." - else - directive += "There are no special supplemental instructions at this time." - return directive - -//=======//CURRENT PLAYER VERB//=======// - -/client/proc/cmd_admin_ninjafy(var/mob/M in world) - set category = null - set name = "Make Space Ninja" - - if(!ticker) - alert("Wait until the game starts") - return - if(!toggle_space_ninja) - alert("Space Ninjas spawning is disabled.") - return - - var/confirm = alert(src, "You sure?", "Confirm", "Yes", "No") - if(confirm != "Yes") return - - if(ishuman(M)) - log_admin("[key_name(src)] turned [M.key] into a Space Ninja.") - spawn(10) - M:create_mind_space_ninja() - M:equip_space_ninja(1) - if(istype(M:wear_suit, /obj/item/clothing/suit/space/space_ninja)) - M:wear_suit:randomize_param() - spawn(0) - M:wear_suit:ninitialize(10,M) - else - alert("Invalid mob") - -//=======//CURRENT GHOST VERB//=======// - -/client/proc/send_space_ninja() - set category = "Fun" - set name = "Spawn Space Ninja" - set desc = "Spawns a space ninja for when you need a teenager with attitude." - set popup_menu = 0 - - if(!holder) - src << "Only administrators may use this command." - return - if(!ticker.mode) - alert("The game hasn't started yet!") - return - if(!toggle_space_ninja) - alert("Space Ninjas spawning is disabled.") - return - if(alert("Are you sure you want to send in a space ninja?",,"Yes","No")=="No") - return - - var/mission - while(!mission) - mission = input(src, "Please specify which mission the space ninja shall undertake.", "Specify Mission", "") - if(!mission) - if(alert("Error, no mission set. Do you want to exit the setup process?",,"Yes","No")=="Yes") - return - - var/list/spawn_list = list() - for(var/obj/effect/landmark/L in world) - if (L.name == "carpspawn") - spawn_list.Add(L) - - - var/input = input("Pick character to spawn as the Space Ninja", "Key", "") - if(!input) - return - - var/mob/dead/observer/G - for(var/mob/dead/observer/G_find in world) - if(G_find.client&&ckey(G_find.key)==ckey(input)) - G = G_find - break - - if(!G)//If a ghost was not found. - alert("There is no active key like that in the game or the person is not currently a ghost. Aborting command.") - return - - var/admin_name = src - var/mob/living/carbon/human/new_ninja = create_space_ninja(pick(spawn_list.len ? spawn_list : latejoin )) - new_ninja.wear_suit:randomize_param() - - new_ninja.mind.key = G.key - new_ninja.key = G.key - new_ninja.mind.store_memory("Mission: \red [mission].
      ") - - new_ninja.internal = new_ninja.s_store //So the poor ninja has something to breath when they spawn in spess. - new_ninja.internals.icon_state = "internal1" - spawn(0)//Parallel process. Will speed things up a bit. - new_ninja.wear_suit:ninitialize(10,new_ninja)//If you're wondering why I'm passing the argument to the proc when the default should suffice, - //I'm also wondering that same thing. This makes sure it does not run time error though. - - new_ninja << "\blue \nYou are an elite mercenary assassin of the Spider Clan, [new_ninja.real_name]. The dreaded \red SPACE NINJA!\blue You have a variety of abilities at your disposal, thanks to your nano-enhanced cyber armor. Remember your training! \nYour current mission is: \red [mission]" - - message_admins("\blue [admin_name] has spawned [new_ninja.key] as a Space Ninja. Hide yo children! \nTheir mission is: [mission]", 1) - log_admin("[admin_name] used Spawn Space Ninja.") - - del(G) - return - -//=======//NINJA CREATION PROCS//=======// - -/proc/create_space_ninja(obj/spawn_point) - var/mob/living/carbon/human/new_ninja = new(spawn_point.loc) - var/ninja_title = pick(ninja_titles) - var/ninja_name = pick(ninja_names) - new_ninja.gender = pick(MALE, FEMALE) - - var/datum/preferences/A = new()//Randomize appearance for the ninja. - A.randomize_appearance_for(new_ninja) - new_ninja.real_name = "[ninja_title] [ninja_name]" - new_ninja.dna.ready_dna(new_ninja) - new_ninja.create_mind_space_ninja() - new_ninja.equip_space_ninja() - return new_ninja - -/mob/living/carbon/human/proc/create_mind_space_ninja() - if(mind) - mind.assigned_role = "MODE" - mind.special_role = "Space Ninja" - else - mind = new - mind.current = src - mind.original = src - mind.assigned_role = "MODE" - mind.special_role = "Space Ninja" - if(!(mind in ticker.minds)) - ticker.minds += mind//Adds them to regular mind list. - if(!(mind in ticker.mode.traitors))//If they weren't already an extra traitor. - ticker.mode.traitors += mind//Adds them to current traitor list. Which is really the extra antagonist list. - return 1 - -/mob/living/carbon/human/proc/equip_space_ninja(safety=0)//Safety in case you need to unequip stuff for existing characters. - if(safety) - del(w_uniform) - del(wear_suit) - del(wear_mask) - del(head) - del(shoes) - del(gloves) - - var/obj/item/device/radio/R = new /obj/item/device/radio/headset(src) - equip_if_possible(R, slot_ears) - if(gender==FEMALE) - equip_if_possible(new /obj/item/clothing/under/color/blackf(src), slot_w_uniform) - else - equip_if_possible(new /obj/item/clothing/under/color/black(src), slot_w_uniform) - equip_if_possible(new /obj/item/clothing/shoes/space_ninja(src), slot_shoes) - equip_if_possible(new /obj/item/clothing/suit/space/space_ninja(src), slot_wear_suit) - equip_if_possible(new /obj/item/clothing/gloves/space_ninja(src), slot_gloves) - equip_if_possible(new /obj/item/clothing/head/helmet/space/space_ninja(src), slot_head) - equip_if_possible(new /obj/item/clothing/mask/gas/voice/space_ninja(src), slot_wear_mask) - equip_if_possible(new /obj/item/device/flashlight(src), slot_belt) - equip_if_possible(new /obj/item/weapon/plastique(src), slot_r_store) - equip_if_possible(new /obj/item/weapon/plastique(src), slot_l_store) - equip_if_possible(new /obj/item/weapon/tank/emergency_oxygen(src), slot_s_store) - resistances += "alien_embryo" - return 1 - -//=======//HELPER PROCS//=======// - -//Randomizes suit parameters. -/obj/item/clothing/suit/space/space_ninja/proc/randomize_param() - s_cost = rand(1,20) - s_acost = rand(20,100) - k_cost = rand(100,500) - k_damage = rand(1,20) - s_delay = rand(10,100) - s_bombs = rand(5,20) - a_boost = rand(1,7) - -//This proc prevents the suit from being taken off. -/obj/item/clothing/suit/space/space_ninja/proc/lock_suit(mob/living/carbon/U, X = 0) - if(X)//If you want to check for icons. - icon_state = U.gender==FEMALE ? "s-ninjanf" : "s-ninjan" - U:gloves.icon_state = "s-ninjan" - U:gloves.item_state = "s-ninjan" - else - if(U.mind.special_role!="Space Ninja") - U << "\red fÄTaL ÈÈRRoR: 382200-*#00CÖDE RED\nUNAU†HORIZED USÈ DETÈC†††eD\nCoMMÈNCING SUB-R0U†IN3 13...\nTÈRMInATING U-U-USÈR..." - U.gib() - return 0 - if(!istype(U:head, /obj/item/clothing/head/helmet/space/space_ninja)) - U << "\red ERROR: 100113 \black UNABLE TO LOCATE HEAD GEAR\nABORTING..." - return 0 - if(!istype(U:shoes, /obj/item/clothing/shoes/space_ninja)) - U << "\red ERROR: 122011 \black UNABLE TO LOCATE FOOT GEAR\nABORTING..." - return 0 - if(!istype(U:gloves, /obj/item/clothing/gloves/space_ninja)) - U << "\red ERROR: 110223 \black UNABLE TO LOCATE HAND GEAR\nABORTING..." - return 0 - - affecting = U - canremove = 0 - slowdown = 0 - n_hood = U:head - n_hood.canremove=0 - n_shoes = U:shoes - n_shoes.canremove=0 - n_shoes.slowdown-- - n_gloves = U:gloves - n_gloves.canremove=0 - - return 1 - -//This proc allows the suit to be taken off. -/obj/item/clothing/suit/space/space_ninja/proc/unlock_suit() - affecting = null - canremove = 1 - slowdown = 1 - icon_state = "s-ninja" - if(n_hood)//Should be attached, might not be attached. - n_hood.canremove=1 - if(n_shoes) - n_shoes.canremove=1 - n_shoes.slowdown++ - if(n_gloves) - n_gloves.icon_state = "s-ninja" - n_gloves.item_state = "s-ninja" - n_gloves.canremove=1 - n_gloves.candrain=0 - n_gloves.draining=0 - -//Allows the mob to grab a stealth icon. -/mob/proc/NinjaStealthActive(atom/A)//A is the atom which we are using as the overlay. - invisibility = 2//Set ninja invis to 2. - var/icon/opacity_icon = new(A.icon, A.icon_state) - var/icon/alpha_mask = getIconMask(src) - var/icon/alpha_mask_2 = new('effects.dmi', "at_shield1") - alpha_mask.AddAlphaMask(alpha_mask_2) - opacity_icon.AddAlphaMask(alpha_mask) - for(var/i=0,i<5,i++)//And now we add it as overlays. It's faster than creating an icon and then merging it. - var/image/I = image("icon" = opacity_icon, "icon_state" = A.icon_state, "layer" = layer+0.8)//So it's above other stuff but below weapons and the like. - switch(i)//Now to determine offset so the result is somewhat blurred. - if(1) - I.pixel_x -= 1 - if(2) - I.pixel_x += 1 - if(3) - I.pixel_y -= 1 - if(4) - I.pixel_y += 1 - - overlays += I//And finally add the overlay. - overlays += image("icon"='effects.dmi',"icon_state" ="electricity","layer" = layer+0.9) - -//When ninja steal malfunctions. -/mob/proc/NinjaStealthMalf() - invisibility = 0//Set ninja invis to 0. - overlays += image("icon"='effects.dmi',"icon_state" ="electricity","layer" = layer+0.9) - playsound(loc, 'stealthoff.ogg', 75, 1) - -//=======//GENERIC VERB MODIFIERS//=======// - -/obj/item/clothing/suit/space/space_ninja/proc/grant_equip_verbs() - verbs -= /obj/item/clothing/suit/space/space_ninja/proc/init - verbs += /obj/item/clothing/suit/space/space_ninja/proc/deinit - verbs += /obj/item/clothing/suit/space/space_ninja/proc/spideros - verbs += /obj/item/clothing/suit/space/space_ninja/proc/stealth - n_gloves.verbs += /obj/item/clothing/gloves/space_ninja/proc/toggled - - s_initialized = 1 - -/obj/item/clothing/suit/space/space_ninja/proc/remove_equip_verbs() - verbs += /obj/item/clothing/suit/space/space_ninja/proc/init - verbs -= /obj/item/clothing/suit/space/space_ninja/proc/deinit - verbs -= /obj/item/clothing/suit/space/space_ninja/proc/spideros - verbs -= /obj/item/clothing/suit/space/space_ninja/proc/stealth - if(n_gloves) - n_gloves.verbs -= /obj/item/clothing/gloves/space_ninja/proc/toggled - - s_initialized = 0 - -/obj/item/clothing/suit/space/space_ninja/proc/grant_ninja_verbs() - verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjashift - verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjajaunt - verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjasmoke - verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjaboost - verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjapulse - verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjablade - verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjastar - verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjanet - - s_initialized=1 - slowdown=0 - -/obj/item/clothing/suit/space/space_ninja/proc/remove_ninja_verbs() - verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjashift - verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjajaunt - verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjasmoke - verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjaboost - verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjapulse - verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjablade - verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjastar - verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjanet - -//=======//KAMIKAZE VERBS//=======// - -/obj/item/clothing/suit/space/space_ninja/proc/grant_kamikaze(mob/living/carbon/U) - verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjashift - verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjajaunt - verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjapulse - verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjastar - verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjanet - - verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjaslayer - verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjawalk - verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjamirage - - verbs -= /obj/item/clothing/suit/space/space_ninja/proc/stealth - - kamikaze = 1 - - icon_state = U.gender==FEMALE ? "s-ninjakf" : "s-ninjak" - if(n_gloves) - n_gloves.icon_state = "s-ninjak" - n_gloves.item_state = "s-ninjak" - n_gloves.candrain = 0 - n_gloves.draining = 0 - n_gloves.verbs -= /obj/item/clothing/gloves/space_ninja/proc/toggled - - cancel_stealth() - - U << browse(null, "window=spideros") - U << "\red Do or Die, LET'S ROCK!!" - -/obj/item/clothing/suit/space/space_ninja/proc/remove_kamikaze(mob/living/carbon/U) - if(kamikaze) - verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjashift - verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjajaunt - verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjapulse - verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjastar - verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjanet - - verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjaslayer - verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjawalk - verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjamirage - - verbs += /obj/item/clothing/suit/space/space_ninja/proc/stealth - if(n_gloves) - n_gloves.verbs -= /obj/item/clothing/gloves/space_ninja/proc/toggled - - U.incorporeal_move = 0 - kamikaze = 0 - k_unlock = 0 - U << "\blue Disengaging mode...\n\blackCODE NAME: \red KAMIKAZE" - -//=======//AI VERBS//=======// - -/obj/item/clothing/suit/space/space_ninja/proc/grant_AI_verbs() - verbs += /obj/item/clothing/suit/space/space_ninja/proc/ai_hack_ninja - verbs += /obj/item/clothing/suit/space/space_ninja/proc/ai_return_control - - s_busy = 0 - s_control = 0 - -/obj/item/clothing/suit/space/space_ninja/proc/remove_AI_verbs() - verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ai_hack_ninja - verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ai_return_control - - s_control = 1 - -//=======//OLD & UNUSED//=======// - -/* - -Deprecated. get_dir() does the same thing. Still a nice proc. -Returns direction that the mob or whomever should be facing in relation to the target. -This proc does not grant absolute direction and is mostly useful for 8dir sprite positioning. -I personally used it with getline() to great effect. -/proc/get_dir_to(turf/start,turf/end)//N - var/xdiff = start.x - end.x//The sign is important. - var/ydiff = start.y - end.y - - var/direction_x = xdiff<1 ? 4:8//East - west - var/direction_y = ydiff<1 ? 1:2//North - south - var/direction_xy = xdiff==0 ? -4:0//If x is the same, subtract 4. - var/direction_yx = ydiff==0 ? -1:0//If y is the same, subtract 1. - var/direction_f = direction_x+direction_y+direction_xy+direction_yx//Finally direction tally. - direction_f = direction_f==0 ? 1:direction_f//If direction is 0(same spot), return north. Otherwise, direction. - - return direction_f - -Alternative and inferior method of calculating spideros. -var/temp = num2text(spideros) -var/return_to = copytext(temp, 1, (length(temp)))//length has to be to the length of the thing because by default it's length+1 -spideros = text2num(return_to)//Maximum length here is 6. Use (return_to, X) to specify larger strings if needed. - -//Old way of draining from wire. -/obj/item/clothing/gloves/space_ninja/proc/drain_wire() - set name = "Drain From Wire" - set desc = "Drain energy directly from an exposed wire." - set category = "Ninja Equip" - - var/obj/structure/cable/attached - var/mob/living/carbon/human/U = loc - if(candrain&&!draining) - var/turf/T = U.loc - if(isturf(T) && T.is_plating()) - attached = locate() in T - if(!attached) - U << "\red Warning: no exposed cable available." - else - U << "\blue Connecting to wire, stand still..." - if(do_after(U,50)&&!isnull(attached)) - drain("WIRE",attached,U:wear_suit,src) - else - U << "\red Procedure interrupted. Protocol terminated." - return - -I've tried a lot of stuff but adding verbs to the AI while inside an object, inside another object, did not want to work properly. -This was the best work-around I could come up with at the time. Uses objects to then display to panel, based on the object spell system. -Can be added on to pretty easily. - -BYOND fixed the verb bugs so this is no longer necessary. I prefer verb panels. - -/obj/item/clothing/suit/space/space_ninja/proc/grant_AI_verbs() - var/obj/effect/proc_holder/ai_return_control/A_C = new(AI) - var/obj/effect/proc_holder/ai_hack_ninja/B_C = new(AI) - var/obj/effect/proc_holder/ai_instruction/C_C = new(AI) - new/obj/effect/proc_holder/ai_holo_clear(AI) - AI.proc_holder_list += A_C - AI.proc_holder_list += B_C - AI.proc_holder_list += C_C - - s_control = 0 - -/obj/item/clothing/suit/space/space_ninja/proc/remove_AI_verbs() - var/obj/effect/proc_holder/ai_return_control/A_C = locate() in AI - var/obj/effect/proc_holder/ai_hack_ninja/B_C = locate() in AI - var/obj/effect/proc_holder/ai_instruction/C_C = locate() in AI - var/obj/effect/proc_holder/ai_holo_clear/D_C = locate() in AI - del(A_C) - del(B_C) - del(C_C) - del(D_C) - AI.proc_holder_list = list() - verbs += /obj/item/clothing/suit/space/space_ninja/proc/deinit - verbs += /obj/item/clothing/suit/space/space_ninja/proc/spideros - verbs += /obj/item/clothing/suit/space/space_ninja/proc/stealth - - s_control = 1 - -//Workaround -/obj/effect/proc_holder/ai_holo_clear - name = "Clear Hologram" - desc = "Stops projecting the current holographic image." - panel = "AI Ninja Equip" - density = 0 - opacity = 0 - - -/obj/effect/proc_holder/ai_holo_clear/Click() - var/obj/item/clothing/suit/space/space_ninja/S = loc.loc//This is so stupid but makes sure certain things work. AI.SUIT - del(S.hologram.i_attached) - del(S.hologram) - var/obj/effect/proc_holder/ai_holo_clear/D_C = locate() in S.AI - S.AI.proc_holder_list -= D_C - return - -/obj/effect/proc_holder/ai_instruction//Let's the AI know what they can do. - name = "Instructions" - desc = "Displays a list of helpful information." - panel = "AI Ninja Equip" - density = 0 - opacity = 0 - -/obj/effect/proc_holder/ai_instruction/Click() - loc << "The menu you are seeing will contain other commands if they become available.\nRight click a nearby turf to display an AI Hologram. It will only be visible to you and your host. You can move it freely using normal movement keys--it will disappear if placed too far away." - -/obj/effect/proc_holder/ai_hack_ninja//Generic proc holder to make sure the two verbs below work propely. - name = "Hack SpiderOS" - desc = "Hack directly into the Black Widow(tm) neuro-interface." - panel = "AI Ninja Equip" - density = 0 - opacity = 0 - -/obj/effect/proc_holder/ai_hack_ninja/Click()//When you click on it. - var/obj/item/clothing/suit/space/space_ninja/S = loc.loc - S.hack_spideros() - return - -/obj/effect/proc_holder/ai_return_control - name = "Relinquish Control" - desc = "Return control to the user." - panel = "AI Ninja Equip" - density = 0 - opacity = 0 - -/obj/effect/proc_holder/ai_return_control/Click() - var/mob/living/silicon/ai/A = loc - var/obj/item/clothing/suit/space/space_ninja/S = A.loc - A << browse(null, "window=hack spideros")//Close window - A << "You have seized your hacking attempt. [S.affecting] has regained control." - S.affecting << "UPDATE: [A.real_name] has ceased hacking attempt. All systems clear." - S.remove_AI_verbs() - return -*/ - -//=======//DEBUG//=======// -/* -/obj/item/clothing/suit/space/space_ninja/proc/display_verb_procs() -//DEBUG -//Does nothing at the moment. I am trying to see if it's possible to mess around with verbs as variables. - //for(var/P in verbs) -// if(P.set.name) -// usr << "[P.set.name], path: [P]" - return - - -Most of these are at various points of incomplete. - -/mob/verb/grant_object_panel() - set name = "Grant AI Ninja Verbs Debug" - set category = "Ninja Debug" - var/obj/effect/proc_holder/ai_return_control/A_C = new(src) - var/obj/effect/proc_holder/ai_hack_ninja/B_C = new(src) - usr:proc_holder_list += A_C - usr:proc_holder_list += B_C - -mob/verb/remove_object_panel() - set name = "Remove AI Ninja Verbs Debug" - set category = "Ninja Debug" - var/obj/effect/proc_holder/ai_return_control/A = locate() in src - var/obj/effect/proc_holder/ai_hack_ninja/B = locate() in src - usr:proc_holder_list -= A - usr:proc_holder_list -= B - del(A)//First. - del(B)//Second, to keep the proc going. - return - -/client/verb/grant_verb_ninja_debug1(var/mob/M in view()) - set name = "Grant AI Ninja Verbs Debug" - set category = "Ninja Debug" - - M.verbs += /mob/living/silicon/ai/verb/ninja_return_control - M.verbs += /mob/living/silicon/ai/verb/ninja_spideros - return - -/client/verb/grant_verb_ninja_debug2(var/mob/living/carbon/human/M in view()) - set name = "Grant Back Ninja Verbs" - set category = "Ninja Debug" - - M.wear_suit.verbs += /obj/item/clothing/suit/space/space_ninja/proc/deinit - M.wear_suit.verbs += /obj/item/clothing/suit/space/space_ninja/proc/spideros - return - -/obj/proc/grant_verb_ninja_debug3(var/mob/living/silicon/ai/A as mob) - set name = "Grant AI Ninja Verbs" - set category = "null" - set hidden = 1 - A.verbs -= /obj/item/clothing/suit/space/space_ninja/proc/deinit - A.verbs -= /obj/item/clothing/suit/space/space_ninja/proc/spideros - return - -/mob/verb/get_dir_to_target(var/mob/M in oview()) - set name = "Get Direction to Target" - set category = "Ninja Debug" - - world << "DIR: [get_dir_to(src.loc,M.loc)]" - return -// -/mob/verb/kill_self_debug() - set name = "DEBUG Kill Self" - set category = "Ninja Debug" - - src:death() - -/client/verb/switch_client_debug() - set name = "DEBUG Switch Client" - set category = "Ninja Debug" - - mob = mob:loc:loc - -/mob/verb/possess_mob(var/mob/M in oview()) - set name = "DEBUG Possess Mob" - set category = "Ninja Debug" - - client.mob = M - -/client/verb/switcharoo(var/mob/M in oview()) - set name = "DEBUG Switch to AI" - set category = "Ninja Debug" - - var/mob/last_mob = mob - mob = M - last_mob:wear_suit:AI:key = key -// -/client/verb/ninjaget(var/mob/M in oview()) - set name = "DEBUG Ninja GET" - set category = "Ninja Debug" - - mob = M - M.gib() - space_ninja() - -/mob/verb/set_debug_ninja_target() - set name = "Set Debug Target" - set category = "Ninja Debug" - - ninja_debug_target = src//The target is you, brohime. - world << "Target: [src]" - -/mob/verb/hack_spideros_debug() - set name = "Debug Hack Spider OS" - set category = "Ninja Debug" - - var/mob/living/silicon/ai/A = loc:AI - if(A) - if(!A.key) - A.client.mob = loc:affecting - else - loc:affecting:client:mob = A - return - -//Tests the net and what it does. -/mob/verb/ninjanet_debug() - set name = "Energy Net Debug" - set category = "Ninja Debug" - - var/obj/effect/energy_net/E = new /obj/effect/energy_net(loc) - E.layer = layer+1//To have it appear one layer above the mob. - stunned = 10//So they are stunned initially but conscious. - anchored = 1//Anchors them so they can't move. - E.affecting = src - spawn(0)//Parallel processing. - E.process(src) - return - -I made this as a test for a possible ninja ability (or perhaps more) for a certain mob to see hallucinations. -The thing here is that these guys have to be coded to do stuff as they are simply images that you can't even click on. -That is why you attached them to objects. -/mob/verb/TestNinjaShadow() - set name = "Test Ninja Ability" - set category = "Ninja Debug" - - if(client) - var/safety = 4 - for(var/turf/T in oview(5)) - if(prob(20)) - var/current_clone = image('mob.dmi',T,"s-ninja") - safety-- - spawn(0) - src << current_clone - spawn(300) - del(current_clone) - spawn while(!isnull(current_clone)) - step_to(current_clone,src,1) - sleep(5) - if(safety<=0) break +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++++++++++++++++++++++++++++++++++++++// //++++++++++++++++++++++++++++++++++ +======================================SPACE NINJA SETUP==================================== +___________________________________________________________________________________________ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +/* + README: + + Data: + + >> space_ninja.dm << is this file. It contains a variety of procs related to either spawning space ninjas, + modifying their verbs, various help procs, testing debug-related content, or storing unused procs for later. + Similar functions should go into this file, along with anything else that may not have an explicit category. + IMPORTANT: actual ninja suit, gloves, etc, are stored under the appropriate clothing files. If you need to change + variables or look them up, look there. Easiest way is through the map file browser. + + >> ninja_abilities.dm << contains all the ninja-related powers. Spawning energy swords, teleporting, and the like. + If more powers are added, or perhaps something related to powers, it should go there. Make sure to describe + what an ability/power does so it's easier to reference later without looking at the code. + IMPORTANT: verbs are still somewhat funky to work with. If an argument is specified but is not referenced in a way + BYOND likes, in the code content, the verb will fail to trigger. Nothing will happen, literally, when clicked. + This can be bypassed by either referencing the argument properly, or linking to another proc with the argument + attached. The latter is what I like to do for certain cases--sometimes it's necessary to do that regardless. + + >> ninja_equipment.dm << deals with all the equipment-related procs for a ninja. Primarily it has the suit, gloves, + and mask. The suit is by far the largest section of code out of the three and includes a lot of code that ties in + to other functions. This file has gotten kind of large so breaking it up may be in order. I use section hearders. + IMPORTANT: not much to say here. Follow along with the comments and adding new functions should be a breeze. Also + know that certain equipment pieces are linked in other files. The energy blade, for example, has special + functions defined in the appropriate files (airlock, securestorage, etc). + + General Notes: + + I created space ninjas with the expressed purpose of spicing up boring rounds. That is, ninjas are to xenos as marauders are to + death squads. Ninjas are stealthy, tech-savvy, and powerful. Not to say marauders are all of those things, but a clever ninja + should have little problem murderampaging their way through just about anything. Short of admin wizards maybe. + HOWEVER! + Ninjas also have a fairly great weakness as they require energy to use abilities. If, theoretically, there is a game + mode based around space ninjas, make sure to account for their energy needs. + + Admin Notes: + + Ninjas are not admin PCs--please do not use them for that purpose. They are another way to participate in the game post-death, + like pais, xenos, death squads, and cyborgs. + I'm currently looking for feedback from regular players since beta testing is largely done. I would appreciate if + you spawned regular players as ninjas when rounds are boring. Or exciting, it's all good as long as there is feedback. + You can also spawn ninja gear manually if you want to. + + How to do that: + Make sure your character has a mind. + Change their assigned_role to "MODE", no quotes. Otherwise, the suit won't initialize. + Change their special_role to "Space Ninja", no quotes. Otherwise, the character will be gibbed. + Spawn ninja gear, put it on, hit initialize. Let the suit do the rest. You are now a space ninja. + I don't recommend messing with suit variables unless you really know what you're doing. + + Miscellaneous Notes: + + Potential Upgrade Tree: + Energy Shield: + Extra Ability + Syndicate Shield device? + Works like the force wall spell, except can be kept indefinitely as long as energy remains. Toggled on or off. + Would block bullets and the like. + Phase Shift + Extra Ability + Advanced Sensors? + Instead of being unlocked at the start, Phase Shieft would become available once requirements are met. + Uranium-based Recharger: + Suit Upgrade + Unsure + Instead of losing energy each second, the suit would regain the same amount of energy. + This would not count in activating stealth and similar. + Extended Battery Life: + Suit Upgrade + Battery of higher capacity + Already implemented. Replace current battery with one of higher capacity. + Advanced Cloak-Tech device. + Suit Upgrade + Syndicate Cloaking Device? + Remove cloak failure rate. +*/ + +//=======//RANDOM EVENT//=======// +/* +Also a dynamic ninja mission generator. +I decided to scrap round-specific objectives since keeping track of them would require some form of tracking. +When I already created about 4 new objectives, this doesn't seem terribly important or needed. +*/ + +/var/global/toggle_space_ninja = 1//If ninjas can spawn or not. +/var/global/sent_ninja_to_station = 0//If a ninja is already on the station. + +/proc/space_ninja_arrival() + + var/datum/game_mode/current_mode = ticker.mode + var/datum/mind/current_mind + + /*Is the ninja playing for the good or bad guys? Is the ninja helping or hurting the station? + Their directives also influence behavior. At least in theory.*/ + var/side = pick("face","heel") + + var/antagonist_list[] = list()//The main bad guys. Evil minds that plot destruction. + var/protagonist_list[] = current_mode.get_living_heads()//The good guys. Mostly Heads. Who are alive. + + var/xeno_list[] = list()//Aliens. + var/commando_list[] = list()//Commandos. + + //We want the ninja to appear only in certain modes. + var/acceptable_modes_list[] = list("traitor","revolution","cult","wizard","changeling","traitorchan","nuclear","malfunction","monkey") + if(!(current_mode.config_tag in acceptable_modes_list)) + return + + /*No longer need to determine what mode it is since bad guys are basically universal. + And there is now a mode with two types of bad guys.*/ + + var/possible_bad_dudes[] = list(current_mode.traitors,current_mode.head_revolutionaries,current_mode.head_revolutionaries, + current_mode.cult,current_mode.wizards,current_mode.changelings,current_mode.syndicates) + for(var/list in possible_bad_dudes)//For every possible antagonist type. + for(current_mind in list)//For each mind in that list. + if(current_mind.current&¤t_mind.current.stat!=2)//If they are not destroyed and not dead. + antagonist_list += current_mind//Add them. + + if(protagonist_list.len)//If the mind is both a protagonist and antagonist. + for(current_mind in protagonist_list) + if(current_mind in antagonist_list) + protagonist_list -= current_mind//We only want it in one list. +/* +Malf AIs/silicons aren't added. Monkeys aren't added. Messes with objective completion. Only humans are added. +*/ + + //Here we pick a location and spawn the ninja. + var/list/spawn_list = list() + for(var/obj/effect/landmark/L in world) + if (L.name == "carpspawn") + spawn_list.Add(L) + + var/mob/dead/observer/G + var/list/candidates = list() + for(G in world) + if(G.client)//Now everyone can ninja! + if(((G.client.inactivity/10)/60) <= 5) + candidates.Add(G) + + //The ninja will be created on the right spawn point or at late join. + var/mob/living/carbon/human/new_ninja = create_space_ninja(pick(spawn_list.len ? spawn_list : latejoin )) + + if(candidates.len) + G = pick(candidates) + new_ninja.key = G.key + new_ninja.mind.key = new_ninja.key + new_ninja.wear_suit:randomize_param()//Give them a random set of suit parameters. + new_ninja.internal = new_ninja.s_store //So the poor ninja has something to breath when they spawn in spess. + new_ninja.internals.icon_state = "internal1" + del(G) + else + del(new_ninja) + return + //Now for the rest of the stuff. + + var/datum/mind/ninja_mind = new_ninja.mind//For easier reference. + var/mission_set = 0//To determine if we need to do further processing. + //Xenos and deathsquads take precedence over everything else. + + //Unless the xenos are hiding in a locker somewhere, this'll find em. + for(var/mob/living/carbon/alien/humanoid/xeno in world) + if(istype(xeno)) + xeno_list += xeno + + if(xeno_list.len>3)//If there are more than three humanoid xenos on the station, time to get dangerous. + //Here we want the ninja to murder all the queens. The other aliens don't really matter. + var/xeno_queen_list[] = list() + for(var/mob/living/carbon/alien/humanoid/queen/xeno_queen in xeno_list) + if(xeno_queen.mind&&xeno_queen.stat!=2) + xeno_queen_list += xeno_queen + if(xeno_queen_list.len&&side=="face")//If there are queen about and the probability is 50. + for(var/mob/living/carbon/alien/humanoid/queen/xeno_queen in xeno_queen_list) + var/datum/objective/assassinate/ninja_objective = new + //We'll do some manual overrides to properly set it up. + ninja_objective.owner = ninja_mind + ninja_objective.target = xeno_queen.mind + ninja_objective.explanation_text = "Kill \the [xeno_queen]." + ninja_mind.objectives += ninja_objective + mission_set = 1 + + if(sent_strike_team&&side=="heel"&&antagonist_list.len)//If a strike team was sent, murder them all like a champ. + for(current_mind in antagonist_list)//Search and destroy. Since we already have an antagonist list, they should appear there. + if(current_mind.special_role=="Death Commando") + commando_list += current_mind + if(commando_list.len)//If there are living commandos still in play. + for(var/mob/living/carbon/human/commando in commando_list) + var/datum/objective/assassinate/ninja_objective = new + ninja_objective.owner = ninja_mind + ninja_objective.find_target_by_role(commando.mind.special_role,1) + ninja_mind.objectives += ninja_objective + mission_set = 1 +/* +If there are no antogonists left it could mean one of two things: + A) The round is about to end. No harm in spawning the ninja here. + B) The round is still going and ghosts are probably rioting for something to happen. +In either case, it's a good idea to spawn the ninja with a semi-random set of objectives. +*/ + if(!mission_set)//If mission was not set. + + var/current_minds[]//List being looked on in the following code. + var/side_list = side=="face" ? 2 : 1//For logic gating. + var/hostile_targets[] = list()//The guys actually picked for the assassination or whatever. + var/friendly_targets[] = list()//The guys the ninja must protect. + + for(var/i=2,i>0,i--)//Two lists. + current_minds = i==2 ? antagonist_list : protagonist_list//Which list are we looking at? + for(var/t=3,(current_minds.len&&t>0),t--)//While the list is not empty and targets remain. Also, 3 targets is good. + current_mind = pick(current_minds)//Pick a random person. + /*I'm creating a logic gate here based on the ninja affiliation that compares the list being + looked at to the affiliation. Affiliation is just a number used to compare. Meaning comes from the logic involved. + If the list being looked at is equal to the ninja's affiliation, add the mind to hostiles. + If not, add the mind to friendlies. Since it can't be both, it will be added only to one or the other.*/ + hostile_targets += i==side_list ? current_mind : null//Adding null doesn't add anything. + friendly_targets += i!=side_list ? current_mind : null + current_minds -= current_mind//Remove the mind so it's not picked again. + + var/objective_list[] = list(1,2,3,4,5,6)//To remove later. + for(var/i=rand(1,3),i>0,i--)//Want to get a few random objectives. Currently up to 3. + if(!hostile_targets.len)//Remove appropriate choices from switch list if the target lists are empty. + objective_list -= 1 + objective_list -= 4 + if(!friendly_targets.len) + objective_list -= 3 + switch(pick(objective_list)) + if(1)//kill + current_mind = pick(hostile_targets) + + var/datum/objective/assassinate/ninja_objective = new + ninja_objective.owner = ninja_mind + ninja_objective.find_target_by_role((current_mind.special_role ? current_mind.special_role : current_mind.assigned_role),(current_mind.special_role?1:0))//If they have a special role, use that instead to find em. + ninja_mind.objectives += ninja_objective + + hostile_targets -= current_mind//Remove them from the list. + if(2)//Steal + var/datum/objective/steal/ninja_objective = new + var/target_item = pick(ninja_objective.possible_items_special) + ninja_objective.set_target(target_item) + ninja_mind.objectives += ninja_objective + + objective_list -= 2 + if(3)//Protect. Keeping people alive can be pretty difficult. + current_mind = pick(friendly_targets) + + var/datum/objective/protect/ninja_objective = new + ninja_objective.owner = ninja_mind + ninja_objective.find_target_by_role((current_mind.special_role ? current_mind.special_role : current_mind.assigned_role),(current_mind.special_role?1:0)) + ninja_mind.objectives += ninja_objective + + friendly_targets -= current_mind + if(4)//Debrain + current_mind = pick(hostile_targets) + + var/datum/objective/debrain/ninja_objective = new + ninja_objective.owner = ninja_mind + ninja_objective.find_target_by_role((current_mind.special_role ? current_mind.special_role : current_mind.assigned_role),(current_mind.special_role?1:0)) + ninja_mind.objectives += ninja_objective + + hostile_targets -= current_mind//Remove them from the list. + if(5)//Download research + var/datum/objective/download/ninja_objective = new + ninja_objective.gen_amount_goal() + ninja_mind.objectives += ninja_objective + + objective_list -= 5 + if(6)//Capture + var/datum/objective/capture/ninja_objective = new + ninja_objective.gen_amount_goal() + ninja_mind.objectives += ninja_objective + + objective_list -= 6 + + if(ninja_mind.objectives.len)//If they got some objectives out of that. + mission_set = 1 + + if(!ninja_mind.objectives.len||!mission_set)//If they somehow did not get an objective at this point, time to destroy the station. + var/nuke_code + var/temp_code + for(var/obj/machinery/nuclearbomb/N in world) + temp_code = text2num(N.r_code) + if(temp_code)//if it's actually a number. It won't convert any non-numericals. + nuke_code = N.r_code + break + if(nuke_code)//If there is a nuke device in world and we got the code. + var/datum/objective/nuclear/ninja_objective = new//Fun. + ninja_objective.owner = ninja_mind + ninja_objective.explanation_text = "Destroy the station with a nuclear device. The code is [nuke_code]." //Let them know what the code is. + + //Finally add a survival objective since it's usually broad enough for any round type. + var/datum/objective/survive/ninja_objective = new + ninja_objective.owner = ninja_mind + ninja_mind.objectives += ninja_objective + + var/directive = generate_ninja_directive(side) + new_ninja << "\blue \nYou are an elite mercenary assassin of the Spider Clan, [new_ninja.real_name]. The dreaded \red SPACE NINJA!\blue You have a variety of abilities at your disposal, thanks to your nano-enhanced cyber armor. Remember your training (initialize your suit by right clicking on it)! \nYour current directive is: \red [directive]" + new_ninja.mind.store_memory("Directive: \red [directive]
      ") + + var/obj_count = 1 + new_ninja << "\blue Your current objectives:" + for(var/datum/objective/objective in ninja_mind.objectives) + new_ninja << "Objective #[obj_count]: [objective.explanation_text]" + obj_count++ + + sent_ninja_to_station = 1//And we're done. + return new_ninja//Return the ninja in case we need to reference them later. + +/* +This proc will give the ninja a directive to follow. They are not obligated to do so but it's a fun roleplay reminder. +Making this random or semi-random will probably not work without it also being incredibly silly. +As such, it's hard-coded for now. No reason for it not to be, really. +*/ +/proc/generate_ninja_directive(side) + var/directive = "[side=="face"?"Nanotrasen":"The Syndicate"] is your employer. "//Let them know which side they're on. + switch(rand(1,13)) + if(1) + directive += "The Spider Clan must not be linked to this operation. Remain as hidden and covert as possible." + if(2) + directive += "[station_name] is financed by an enemy of the Spider Clan. Cause as much structural damage as possible." + if(3) + directive += "A wealthy animal rights activist has made a request we cannot refuse. Prioritize saving animal lives whenever possible." + if(4) + directive += "The Spider Clan absolutely cannot be linked to this operation. Eliminate all witnesses using most extreme prejudice." + if(5) + directive += "We are currently negotiating with Nanotrasen command. Prioritize saving human lives over ending them." + if(6) + directive += "We are engaged in a legal dispute over [station_name]. If a laywer is present on board, force their cooperation in the matter." + if(7) + directive += "A financial backer has made an offer we cannot refuse. Implicate Syndicate involvement in the operation." + if(8) + directive += "Let no one question the mercy of the Spider Clan. Ensure the safety of all non-essential personnel you encounter." + if(9) + directive += "A free agent has proposed a lucrative business deal. Implicate Nanotrasen involvement in the operation." + if(10) + directive += "Our reputation is on the line. Harm as few civilians or innocents as possible." + if(11) + directive += "Our honor is on the line. Utilize only honorable tactics when dealing with opponents." + if(12) + directive += "We are currently negotiating with a Syndicate leader. Disguise assassinations as suicide or another natural cause." + else + directive += "There are no special supplemental instructions at this time." + return directive + +//=======//CURRENT PLAYER VERB//=======// + +/client/proc/cmd_admin_ninjafy(var/mob/M in world) + set category = null + set name = "Make Space Ninja" + + if(!ticker) + alert("Wait until the game starts") + return + if(!toggle_space_ninja) + alert("Space Ninjas spawning is disabled.") + return + + var/confirm = alert(src, "You sure?", "Confirm", "Yes", "No") + if(confirm != "Yes") return + + if(ishuman(M)) + log_admin("[key_name(src)] turned [M.key] into a Space Ninja.") + spawn(10) + M:create_mind_space_ninja() + M:equip_space_ninja(1) + if(istype(M:wear_suit, /obj/item/clothing/suit/space/space_ninja)) + M:wear_suit:randomize_param() + spawn(0) + M:wear_suit:ninitialize(10,M) + else + alert("Invalid mob") + +//=======//CURRENT GHOST VERB//=======// + +/client/proc/send_space_ninja() + set category = "Fun" + set name = "Spawn Space Ninja" + set desc = "Spawns a space ninja for when you need a teenager with attitude." + set popup_menu = 0 + + if(!holder) + src << "Only administrators may use this command." + return + if(!ticker.mode) + alert("The game hasn't started yet!") + return + if(!toggle_space_ninja) + alert("Space Ninjas spawning is disabled.") + return + if(alert("Are you sure you want to send in a space ninja?",,"Yes","No")=="No") + return + + var/mission + while(!mission) + mission = input(src, "Please specify which mission the space ninja shall undertake.", "Specify Mission", "") + if(!mission) + if(alert("Error, no mission set. Do you want to exit the setup process?",,"Yes","No")=="Yes") + return + + var/list/spawn_list = list() + for(var/obj/effect/landmark/L in world) + if (L.name == "carpspawn") + spawn_list.Add(L) + + + var/input = input("Pick character to spawn as the Space Ninja", "Key", "") + if(!input) + return + + var/mob/dead/observer/G + for(var/mob/dead/observer/G_find in world) + if(G_find.client&&ckey(G_find.key)==ckey(input)) + G = G_find + break + + if(!G)//If a ghost was not found. + alert("There is no active key like that in the game or the person is not currently a ghost. Aborting command.") + return + + var/admin_name = src + var/mob/living/carbon/human/new_ninja = create_space_ninja(pick(spawn_list.len ? spawn_list : latejoin )) + new_ninja.wear_suit:randomize_param() + + new_ninja.mind.key = G.key + new_ninja.key = G.key + new_ninja.mind.store_memory("Mission: \red [mission].
      ") + + new_ninja.internal = new_ninja.s_store //So the poor ninja has something to breath when they spawn in spess. + new_ninja.internals.icon_state = "internal1" + spawn(0)//Parallel process. Will speed things up a bit. + new_ninja.wear_suit:ninitialize(10,new_ninja)//If you're wondering why I'm passing the argument to the proc when the default should suffice, + //I'm also wondering that same thing. This makes sure it does not run time error though. + + new_ninja << "\blue \nYou are an elite mercenary assassin of the Spider Clan, [new_ninja.real_name]. The dreaded \red SPACE NINJA!\blue You have a variety of abilities at your disposal, thanks to your nano-enhanced cyber armor. Remember your training! \nYour current mission is: \red [mission]" + + message_admins("\blue [admin_name] has spawned [new_ninja.key] as a Space Ninja. Hide yo children! \nTheir mission is: [mission]", 1) + log_admin("[admin_name] used Spawn Space Ninja.") + + del(G) + return + +//=======//NINJA CREATION PROCS//=======// + +/proc/create_space_ninja(obj/spawn_point) + var/mob/living/carbon/human/new_ninja = new(spawn_point.loc) + var/ninja_title = pick(ninja_titles) + var/ninja_name = pick(ninja_names) + new_ninja.gender = pick(MALE, FEMALE) + + var/datum/preferences/A = new()//Randomize appearance for the ninja. + A.randomize_appearance_for(new_ninja) + new_ninja.real_name = "[ninja_title] [ninja_name]" + new_ninja.dna.ready_dna(new_ninja) + new_ninja.create_mind_space_ninja() + new_ninja.equip_space_ninja() + return new_ninja + +/mob/living/carbon/human/proc/create_mind_space_ninja() + if(mind) + mind.assigned_role = "MODE" + mind.special_role = "Space Ninja" + else + mind = new + mind.current = src + mind.original = src + mind.assigned_role = "MODE" + mind.special_role = "Space Ninja" + if(!(mind in ticker.minds)) + ticker.minds += mind//Adds them to regular mind list. + if(!(mind in ticker.mode.traitors))//If they weren't already an extra traitor. + ticker.mode.traitors += mind//Adds them to current traitor list. Which is really the extra antagonist list. + return 1 + +/mob/living/carbon/human/proc/equip_space_ninja(safety=0)//Safety in case you need to unequip stuff for existing characters. + if(safety) + del(w_uniform) + del(wear_suit) + del(wear_mask) + del(head) + del(shoes) + del(gloves) + + var/obj/item/device/radio/R = new /obj/item/device/radio/headset(src) + equip_if_possible(R, slot_ears) + if(gender==FEMALE) + equip_if_possible(new /obj/item/clothing/under/color/blackf(src), slot_w_uniform) + else + equip_if_possible(new /obj/item/clothing/under/color/black(src), slot_w_uniform) + equip_if_possible(new /obj/item/clothing/shoes/space_ninja(src), slot_shoes) + equip_if_possible(new /obj/item/clothing/suit/space/space_ninja(src), slot_wear_suit) + equip_if_possible(new /obj/item/clothing/gloves/space_ninja(src), slot_gloves) + equip_if_possible(new /obj/item/clothing/head/helmet/space/space_ninja(src), slot_head) + equip_if_possible(new /obj/item/clothing/mask/gas/voice/space_ninja(src), slot_wear_mask) + equip_if_possible(new /obj/item/device/flashlight(src), slot_belt) + equip_if_possible(new /obj/item/weapon/plastique(src), slot_r_store) + equip_if_possible(new /obj/item/weapon/plastique(src), slot_l_store) + equip_if_possible(new /obj/item/weapon/tank/emergency_oxygen(src), slot_s_store) + resistances += "alien_embryo" + return 1 + +//=======//HELPER PROCS//=======// + +//Randomizes suit parameters. +/obj/item/clothing/suit/space/space_ninja/proc/randomize_param() + s_cost = rand(1,20) + s_acost = rand(20,100) + k_cost = rand(100,500) + k_damage = rand(1,20) + s_delay = rand(10,100) + s_bombs = rand(5,20) + a_boost = rand(1,7) + +//This proc prevents the suit from being taken off. +/obj/item/clothing/suit/space/space_ninja/proc/lock_suit(mob/living/carbon/U, X = 0) + if(X)//If you want to check for icons. + icon_state = U.gender==FEMALE ? "s-ninjanf" : "s-ninjan" + U:gloves.icon_state = "s-ninjan" + U:gloves.item_state = "s-ninjan" + else + if(U.mind.special_role!="Space Ninja") + U << "\red fÄTaL ÈÈRRoR: 382200-*#00CÖDE RED\nUNAU†HORIZED USÈ DETÈC†††eD\nCoMMÈNCING SUB-R0U†IN3 13...\nTÈRMInATING U-U-USÈR..." + U.gib() + return 0 + if(!istype(U:head, /obj/item/clothing/head/helmet/space/space_ninja)) + U << "\red ERROR: 100113 \black UNABLE TO LOCATE HEAD GEAR\nABORTING..." + return 0 + if(!istype(U:shoes, /obj/item/clothing/shoes/space_ninja)) + U << "\red ERROR: 122011 \black UNABLE TO LOCATE FOOT GEAR\nABORTING..." + return 0 + if(!istype(U:gloves, /obj/item/clothing/gloves/space_ninja)) + U << "\red ERROR: 110223 \black UNABLE TO LOCATE HAND GEAR\nABORTING..." + return 0 + + affecting = U + canremove = 0 + slowdown = 0 + n_hood = U:head + n_hood.canremove=0 + n_shoes = U:shoes + n_shoes.canremove=0 + n_shoes.slowdown-- + n_gloves = U:gloves + n_gloves.canremove=0 + + return 1 + +//This proc allows the suit to be taken off. +/obj/item/clothing/suit/space/space_ninja/proc/unlock_suit() + affecting = null + canremove = 1 + slowdown = 1 + icon_state = "s-ninja" + if(n_hood)//Should be attached, might not be attached. + n_hood.canremove=1 + if(n_shoes) + n_shoes.canremove=1 + n_shoes.slowdown++ + if(n_gloves) + n_gloves.icon_state = "s-ninja" + n_gloves.item_state = "s-ninja" + n_gloves.canremove=1 + n_gloves.candrain=0 + n_gloves.draining=0 + +//Allows the mob to grab a stealth icon. +/mob/proc/NinjaStealthActive(atom/A)//A is the atom which we are using as the overlay. + invisibility = 2//Set ninja invis to 2. + var/icon/opacity_icon = new(A.icon, A.icon_state) + var/icon/alpha_mask = getIconMask(src) + var/icon/alpha_mask_2 = new('effects.dmi', "at_shield1") + alpha_mask.AddAlphaMask(alpha_mask_2) + opacity_icon.AddAlphaMask(alpha_mask) + for(var/i=0,i<5,i++)//And now we add it as overlays. It's faster than creating an icon and then merging it. + var/image/I = image("icon" = opacity_icon, "icon_state" = A.icon_state, "layer" = layer+0.8)//So it's above other stuff but below weapons and the like. + switch(i)//Now to determine offset so the result is somewhat blurred. + if(1) + I.pixel_x -= 1 + if(2) + I.pixel_x += 1 + if(3) + I.pixel_y -= 1 + if(4) + I.pixel_y += 1 + + overlays += I//And finally add the overlay. + overlays += image("icon"='effects.dmi',"icon_state" ="electricity","layer" = layer+0.9) + +//When ninja steal malfunctions. +/mob/proc/NinjaStealthMalf() + invisibility = 0//Set ninja invis to 0. + overlays += image("icon"='effects.dmi',"icon_state" ="electricity","layer" = layer+0.9) + playsound(loc, 'stealthoff.ogg', 75, 1) + +//=======//GENERIC VERB MODIFIERS//=======// + +/obj/item/clothing/suit/space/space_ninja/proc/grant_equip_verbs() + verbs -= /obj/item/clothing/suit/space/space_ninja/proc/init + verbs += /obj/item/clothing/suit/space/space_ninja/proc/deinit + verbs += /obj/item/clothing/suit/space/space_ninja/proc/spideros + verbs += /obj/item/clothing/suit/space/space_ninja/proc/stealth + n_gloves.verbs += /obj/item/clothing/gloves/space_ninja/proc/toggled + + s_initialized = 1 + +/obj/item/clothing/suit/space/space_ninja/proc/remove_equip_verbs() + verbs += /obj/item/clothing/suit/space/space_ninja/proc/init + verbs -= /obj/item/clothing/suit/space/space_ninja/proc/deinit + verbs -= /obj/item/clothing/suit/space/space_ninja/proc/spideros + verbs -= /obj/item/clothing/suit/space/space_ninja/proc/stealth + if(n_gloves) + n_gloves.verbs -= /obj/item/clothing/gloves/space_ninja/proc/toggled + + s_initialized = 0 + +/obj/item/clothing/suit/space/space_ninja/proc/grant_ninja_verbs() + verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjashift + verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjajaunt + verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjasmoke + verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjaboost + verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjapulse + verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjablade + verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjastar + verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjanet + + s_initialized=1 + slowdown=0 + +/obj/item/clothing/suit/space/space_ninja/proc/remove_ninja_verbs() + verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjashift + verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjajaunt + verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjasmoke + verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjaboost + verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjapulse + verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjablade + verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjastar + verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjanet + +//=======//KAMIKAZE VERBS//=======// + +/obj/item/clothing/suit/space/space_ninja/proc/grant_kamikaze(mob/living/carbon/U) + verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjashift + verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjajaunt + verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjapulse + verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjastar + verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjanet + + verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjaslayer + verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjawalk + verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjamirage + + verbs -= /obj/item/clothing/suit/space/space_ninja/proc/stealth + + kamikaze = 1 + + icon_state = U.gender==FEMALE ? "s-ninjakf" : "s-ninjak" + if(n_gloves) + n_gloves.icon_state = "s-ninjak" + n_gloves.item_state = "s-ninjak" + n_gloves.candrain = 0 + n_gloves.draining = 0 + n_gloves.verbs -= /obj/item/clothing/gloves/space_ninja/proc/toggled + + cancel_stealth() + + U << browse(null, "window=spideros") + U << "\red Do or Die, LET'S ROCK!!" + +/obj/item/clothing/suit/space/space_ninja/proc/remove_kamikaze(mob/living/carbon/U) + if(kamikaze) + verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjashift + verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjajaunt + verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjapulse + verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjastar + verbs += /obj/item/clothing/suit/space/space_ninja/proc/ninjanet + + verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjaslayer + verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjawalk + verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ninjamirage + + verbs += /obj/item/clothing/suit/space/space_ninja/proc/stealth + if(n_gloves) + n_gloves.verbs -= /obj/item/clothing/gloves/space_ninja/proc/toggled + + U.incorporeal_move = 0 + kamikaze = 0 + k_unlock = 0 + U << "\blue Disengaging mode...\n\blackCODE NAME: \red KAMIKAZE" + +//=======//AI VERBS//=======// + +/obj/item/clothing/suit/space/space_ninja/proc/grant_AI_verbs() + verbs += /obj/item/clothing/suit/space/space_ninja/proc/ai_hack_ninja + verbs += /obj/item/clothing/suit/space/space_ninja/proc/ai_return_control + + s_busy = 0 + s_control = 0 + +/obj/item/clothing/suit/space/space_ninja/proc/remove_AI_verbs() + verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ai_hack_ninja + verbs -= /obj/item/clothing/suit/space/space_ninja/proc/ai_return_control + + s_control = 1 + +//=======//OLD & UNUSED//=======// + +/* + +Deprecated. get_dir() does the same thing. Still a nice proc. +Returns direction that the mob or whomever should be facing in relation to the target. +This proc does not grant absolute direction and is mostly useful for 8dir sprite positioning. +I personally used it with getline() to great effect. +/proc/get_dir_to(turf/start,turf/end)//N + var/xdiff = start.x - end.x//The sign is important. + var/ydiff = start.y - end.y + + var/direction_x = xdiff<1 ? 4:8//East - west + var/direction_y = ydiff<1 ? 1:2//North - south + var/direction_xy = xdiff==0 ? -4:0//If x is the same, subtract 4. + var/direction_yx = ydiff==0 ? -1:0//If y is the same, subtract 1. + var/direction_f = direction_x+direction_y+direction_xy+direction_yx//Finally direction tally. + direction_f = direction_f==0 ? 1:direction_f//If direction is 0(same spot), return north. Otherwise, direction. + + return direction_f + +Alternative and inferior method of calculating spideros. +var/temp = num2text(spideros) +var/return_to = copytext(temp, 1, (length(temp)))//length has to be to the length of the thing because by default it's length+1 +spideros = text2num(return_to)//Maximum length here is 6. Use (return_to, X) to specify larger strings if needed. + +//Old way of draining from wire. +/obj/item/clothing/gloves/space_ninja/proc/drain_wire() + set name = "Drain From Wire" + set desc = "Drain energy directly from an exposed wire." + set category = "Ninja Equip" + + var/obj/structure/cable/attached + var/mob/living/carbon/human/U = loc + if(candrain&&!draining) + var/turf/T = U.loc + if(isturf(T) && T.is_plating()) + attached = locate() in T + if(!attached) + U << "\red Warning: no exposed cable available." + else + U << "\blue Connecting to wire, stand still..." + if(do_after(U,50)&&!isnull(attached)) + drain("WIRE",attached,U:wear_suit,src) + else + U << "\red Procedure interrupted. Protocol terminated." + return + +I've tried a lot of stuff but adding verbs to the AI while inside an object, inside another object, did not want to work properly. +This was the best work-around I could come up with at the time. Uses objects to then display to panel, based on the object spell system. +Can be added on to pretty easily. + +BYOND fixed the verb bugs so this is no longer necessary. I prefer verb panels. + +/obj/item/clothing/suit/space/space_ninja/proc/grant_AI_verbs() + var/obj/effect/proc_holder/ai_return_control/A_C = new(AI) + var/obj/effect/proc_holder/ai_hack_ninja/B_C = new(AI) + var/obj/effect/proc_holder/ai_instruction/C_C = new(AI) + new/obj/effect/proc_holder/ai_holo_clear(AI) + AI.proc_holder_list += A_C + AI.proc_holder_list += B_C + AI.proc_holder_list += C_C + + s_control = 0 + +/obj/item/clothing/suit/space/space_ninja/proc/remove_AI_verbs() + var/obj/effect/proc_holder/ai_return_control/A_C = locate() in AI + var/obj/effect/proc_holder/ai_hack_ninja/B_C = locate() in AI + var/obj/effect/proc_holder/ai_instruction/C_C = locate() in AI + var/obj/effect/proc_holder/ai_holo_clear/D_C = locate() in AI + del(A_C) + del(B_C) + del(C_C) + del(D_C) + AI.proc_holder_list = list() + verbs += /obj/item/clothing/suit/space/space_ninja/proc/deinit + verbs += /obj/item/clothing/suit/space/space_ninja/proc/spideros + verbs += /obj/item/clothing/suit/space/space_ninja/proc/stealth + + s_control = 1 + +//Workaround +/obj/effect/proc_holder/ai_holo_clear + name = "Clear Hologram" + desc = "Stops projecting the current holographic image." + panel = "AI Ninja Equip" + density = 0 + opacity = 0 + + +/obj/effect/proc_holder/ai_holo_clear/Click() + var/obj/item/clothing/suit/space/space_ninja/S = loc.loc//This is so stupid but makes sure certain things work. AI.SUIT + del(S.hologram.i_attached) + del(S.hologram) + var/obj/effect/proc_holder/ai_holo_clear/D_C = locate() in S.AI + S.AI.proc_holder_list -= D_C + return + +/obj/effect/proc_holder/ai_instruction//Let's the AI know what they can do. + name = "Instructions" + desc = "Displays a list of helpful information." + panel = "AI Ninja Equip" + density = 0 + opacity = 0 + +/obj/effect/proc_holder/ai_instruction/Click() + loc << "The menu you are seeing will contain other commands if they become available.\nRight click a nearby turf to display an AI Hologram. It will only be visible to you and your host. You can move it freely using normal movement keys--it will disappear if placed too far away." + +/obj/effect/proc_holder/ai_hack_ninja//Generic proc holder to make sure the two verbs below work propely. + name = "Hack SpiderOS" + desc = "Hack directly into the Black Widow(tm) neuro-interface." + panel = "AI Ninja Equip" + density = 0 + opacity = 0 + +/obj/effect/proc_holder/ai_hack_ninja/Click()//When you click on it. + var/obj/item/clothing/suit/space/space_ninja/S = loc.loc + S.hack_spideros() + return + +/obj/effect/proc_holder/ai_return_control + name = "Relinquish Control" + desc = "Return control to the user." + panel = "AI Ninja Equip" + density = 0 + opacity = 0 + +/obj/effect/proc_holder/ai_return_control/Click() + var/mob/living/silicon/ai/A = loc + var/obj/item/clothing/suit/space/space_ninja/S = A.loc + A << browse(null, "window=hack spideros")//Close window + A << "You have seized your hacking attempt. [S.affecting] has regained control." + S.affecting << "UPDATE: [A.real_name] has ceased hacking attempt. All systems clear." + S.remove_AI_verbs() + return +*/ + +//=======//DEBUG//=======// +/* +/obj/item/clothing/suit/space/space_ninja/proc/display_verb_procs() +//DEBUG +//Does nothing at the moment. I am trying to see if it's possible to mess around with verbs as variables. + //for(var/P in verbs) +// if(P.set.name) +// usr << "[P.set.name], path: [P]" + return + + +Most of these are at various points of incomplete. + +/mob/verb/grant_object_panel() + set name = "Grant AI Ninja Verbs Debug" + set category = "Ninja Debug" + var/obj/effect/proc_holder/ai_return_control/A_C = new(src) + var/obj/effect/proc_holder/ai_hack_ninja/B_C = new(src) + usr:proc_holder_list += A_C + usr:proc_holder_list += B_C + +mob/verb/remove_object_panel() + set name = "Remove AI Ninja Verbs Debug" + set category = "Ninja Debug" + var/obj/effect/proc_holder/ai_return_control/A = locate() in src + var/obj/effect/proc_holder/ai_hack_ninja/B = locate() in src + usr:proc_holder_list -= A + usr:proc_holder_list -= B + del(A)//First. + del(B)//Second, to keep the proc going. + return + +/client/verb/grant_verb_ninja_debug1(var/mob/M in view()) + set name = "Grant AI Ninja Verbs Debug" + set category = "Ninja Debug" + + M.verbs += /mob/living/silicon/ai/verb/ninja_return_control + M.verbs += /mob/living/silicon/ai/verb/ninja_spideros + return + +/client/verb/grant_verb_ninja_debug2(var/mob/living/carbon/human/M in view()) + set name = "Grant Back Ninja Verbs" + set category = "Ninja Debug" + + M.wear_suit.verbs += /obj/item/clothing/suit/space/space_ninja/proc/deinit + M.wear_suit.verbs += /obj/item/clothing/suit/space/space_ninja/proc/spideros + return + +/obj/proc/grant_verb_ninja_debug3(var/mob/living/silicon/ai/A as mob) + set name = "Grant AI Ninja Verbs" + set category = "null" + set hidden = 1 + A.verbs -= /obj/item/clothing/suit/space/space_ninja/proc/deinit + A.verbs -= /obj/item/clothing/suit/space/space_ninja/proc/spideros + return + +/mob/verb/get_dir_to_target(var/mob/M in oview()) + set name = "Get Direction to Target" + set category = "Ninja Debug" + + world << "DIR: [get_dir_to(src.loc,M.loc)]" + return +// +/mob/verb/kill_self_debug() + set name = "DEBUG Kill Self" + set category = "Ninja Debug" + + src:death() + +/client/verb/switch_client_debug() + set name = "DEBUG Switch Client" + set category = "Ninja Debug" + + mob = mob:loc:loc + +/mob/verb/possess_mob(var/mob/M in oview()) + set name = "DEBUG Possess Mob" + set category = "Ninja Debug" + + client.mob = M + +/client/verb/switcharoo(var/mob/M in oview()) + set name = "DEBUG Switch to AI" + set category = "Ninja Debug" + + var/mob/last_mob = mob + mob = M + last_mob:wear_suit:AI:key = key +// +/client/verb/ninjaget(var/mob/M in oview()) + set name = "DEBUG Ninja GET" + set category = "Ninja Debug" + + mob = M + M.gib() + space_ninja() + +/mob/verb/set_debug_ninja_target() + set name = "Set Debug Target" + set category = "Ninja Debug" + + ninja_debug_target = src//The target is you, brohime. + world << "Target: [src]" + +/mob/verb/hack_spideros_debug() + set name = "Debug Hack Spider OS" + set category = "Ninja Debug" + + var/mob/living/silicon/ai/A = loc:AI + if(A) + if(!A.key) + A.client.mob = loc:affecting + else + loc:affecting:client:mob = A + return + +//Tests the net and what it does. +/mob/verb/ninjanet_debug() + set name = "Energy Net Debug" + set category = "Ninja Debug" + + var/obj/effect/energy_net/E = new /obj/effect/energy_net(loc) + E.layer = layer+1//To have it appear one layer above the mob. + stunned = 10//So they are stunned initially but conscious. + anchored = 1//Anchors them so they can't move. + E.affecting = src + spawn(0)//Parallel processing. + E.process(src) + return + +I made this as a test for a possible ninja ability (or perhaps more) for a certain mob to see hallucinations. +The thing here is that these guys have to be coded to do stuff as they are simply images that you can't even click on. +That is why you attached them to objects. +/mob/verb/TestNinjaShadow() + set name = "Test Ninja Ability" + set category = "Ninja Debug" + + if(client) + var/safety = 4 + for(var/turf/T in oview(5)) + if(prob(20)) + var/current_clone = image('mob.dmi',T,"s-ninja") + safety-- + spawn(0) + src << current_clone + spawn(300) + del(current_clone) + spawn while(!isnull(current_clone)) + step_to(current_clone,src,1) + sleep(5) + if(safety<=0) break return */ \ No newline at end of file diff --git a/code/game/events/Events/AlienInfestation.dm b/code/game/events/Events/AlienInfestation.dm new file mode 100644 index 00000000000..66ed4924222 --- /dev/null +++ b/code/game/events/Events/AlienInfestation.dm @@ -0,0 +1,38 @@ +/datum/event/alieninfestation + + Announce() + + var/list/vents = list() + for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in world) + if(temp_vent.loc.z == 1 && !temp_vent.welded) + vents.Add(temp_vent) + var/spawncount = 1 + if(prob(10)) spawncount++ //rarely, have two larvae spawn instead of one + while(spawncount >= 1) + var/obj/vent = pick(vents) + + var/list/candidates = list() // Picks a random ghost in the world to shove in the larva -- TLE; If there's no ghost... well, sucks. Wasted event. -- Urist + + for(var/mob/dead/observer/G in world) + if(G.client) + if(G.client.be_alien) + if(((G.client.inactivity/10)/60) <= 5) + if(G.corpse) + if(G.corpse.stat==2) + candidates.Add(G) + if(!G.corpse) + candidates.Add(G) + + if(candidates.len) + var/mob/dead/observer/G = pick(candidates) + var/mob/living/carbon/alien/larva/new_xeno = new(vent.loc) + new_xeno.mind_initialize(G,"Larva") + new_xeno.key = G.key + del(G) + + vents.Remove(vent) + spawncount -= 1 + + spawn(rand(3000, 6000)) //Delayed announcements to keep the crew on their toes. + command_alert("Unidentified lifesigns detected coming aboard [station_name()]. Secure any exterior access, including ducting and ventilation.", "Lifesign Alert") + world << sound('aliens.ogg') \ No newline at end of file diff --git a/code/game/events/Events/Appendicitis.dm b/code/game/events/Events/Appendicitis.dm new file mode 100644 index 00000000000..0294194b4da --- /dev/null +++ b/code/game/events/Events/Appendicitis.dm @@ -0,0 +1,16 @@ +/datum/event/appendicitis + + Announce() + + for(var/mob/living/carbon/human/H in world) + var/foundAlready = 0 // don't infect someone that already has the virus + for(var/datum/disease/D in H.viruses) + foundAlready = 1 + if(H.stat == 2 || foundAlready) + continue + + var/datum/disease/D = new /datum/disease/appendicitis + D.holder = H + D.affected_mob = H + H.viruses += D + break \ No newline at end of file diff --git a/code/game/events/Events/BlowOut.dm b/code/game/events/Events/BlowOut.dm new file mode 100644 index 00000000000..89945d33fcb --- /dev/null +++ b/code/game/events/Events/BlowOut.dm @@ -0,0 +1,34 @@ +/area/var/radsafe = 0 +/area/maintenance/radsafe = 1 +/area/ai_monitored/maintenance/radsafe = 1 +/area/centcom/radsafe = 1 +/area/admin/radsafe = 1 +/area/adminsafety/radsafe = 1 +/area/shuttle/radsafe = 1 +/area/syndicate_station/radsafe = 1 +/area/asteroid/radsafe = 1 +/area/crew_quarters/sleeping/radsafe = 1 + +/datum/event/blowout + Lifetime = 150 + Announce() + if(!forced && prob(90)) + ActiveEvent = null + SpawnEvent() + del src + return + command_alert("Warning: station approaching high-density radiation cloud. Seek cover immediately.") + Tick() + if(ActiveFor == 50) + command_alert("Station has entered radiation cloud. Do not leave cover until it has passed.") + if(ActiveFor == 100 || ActiveFor == 150) //1/2 and 2/2 f the way after it start proper make peope be half dead mostly + for(var/mob/living/carbon/M in world) + var/area = M.loc.loc + while(!istype(area, /area)) + area = area:loc + if(area:radsafe) + continue + if(!M.stat) + M.radiate(100) + Die() + command_alert("The station has cleared the radiation cloud. It is now safe to leave cover.") \ No newline at end of file diff --git a/code/game/events/Events/ElectricalStorm.dm b/code/game/events/Events/ElectricalStorm.dm new file mode 100644 index 00000000000..1e7ec6f2966 --- /dev/null +++ b/code/game/events/Events/ElectricalStorm.dm @@ -0,0 +1,124 @@ +/datum/event/electricalstorm + var + list/datum/radio_frequency/DisruptedFrequencies = list( ) + list/obj/machinery/light/Lights = list( ) + list/obj/machinery/light/APCs = list( ) + list/obj/machinery/light/Doors = list( ) + talk_out = 0 + has_talked = 0 + SafeFreq = 0 + + Announce() + Lifetime = rand(90, 300) + command_alert("The station is flying through an electrical storm. Radio communications may be disrupted", "Anomaly Alert") + + for (var/datum/radio_frequency/Freq in radio_controller.frequencies) + if(prob(35)) + radio_controller.RegisterScrambler(Freq) + DisruptedFrequencies += Freq + + for (var/Freq = 1201, Freq <= 1599, Freq += 2) + if(prob(35)) + ScrambledFrequencies += list ("[Freq]" = Freq) + else + UnscrambledFrequencies += list ("[Freq]" = Freq) + + for (var/Freq in DEPT_FREQS) + if(prob(75)) + ScrambledFrequencies |= list ("[Freq]" = Freq) + if(UnscrambledFrequencies["[Freq]"]) + UnscrambledFrequencies -= list ("[Freq]" = Freq) + + if(prob(80)) + ScrambledFrequencies |= list ("1459" = 1459) + if(UnscrambledFrequencies["1459"]) + UnscrambledFrequencies -= list ("1459" = 1459) + + for(var/obj/machinery/light/Light in world) + if(Light.z == 1) + Lights += Light + + for(var/obj/machinery/power/apc/APC in world) + if(APC.z == 1 && !APC.crit) + APCs += APC + + for(var/obj/machinery/door/airlock/Door in world) + if(Door.z == 1) + Doors += Door + + talk_out = rand(40,70) + + var/picked = 0 + var/list/SafeTemp = list() + if(UnscrambledFrequencies["1459"]) + SafeFreq = 1459 + picked = 1 + else + while(picked == 0) + SafeTemp = pick(UnscrambledFrequencies) + SafeFreq = UnscrambledFrequencies[SafeTemp] + if(SafeFreq < 1489 && SafeFreq > 1441) + picked = 1 + + Tick() + for(var/x = 0; x < 3; x++) + if (prob(30)) + BlowLight() + if (prob(10)) + DisruptAPC() + if (prob(10)) + DisableDoor() + if(talk_out <= ActiveFor && has_talked == 0) + command_alert("The radio frequency [SafeFreq/10] has been identified as stable despite the interference.", "Station Central Computer System") + has_talked = 1 + + + Die() + command_alert("The station has cleared the electrical storm. Radio communications restored", "Anomaly Alert") + for (var/datum/radio_frequency/Freq in ScrambledFrequencies) + radio_controller.UnregisterScrambler(Freq) + DisruptedFrequencies = list( ) + UnscrambledFrequencies = list( ) + ScrambledFrequencies = list( ) + + proc + BlowLight() //Blow out a light fixture + var/obj/machinery/light/Light = null + var/insanity = 0 + while (Light == null || Light.status != 0) + Light = pick(Lights) + insanity++ + if (insanity >= Lights.len) + return + + spawn(0) //Overload the light, spectacularly. + //Light.ul_SetLuminosity(10) + //sleep(2) + Light.on = 1 + Light.broken() + + DisruptAPC() + var/insanity = 0 + var/obj/machinery/power/apc/APC + while (!APC || !APC.operating) + APC = pick(APCs) + insanity++ + if (insanity >= APCs.len) + return + + if (prob(40)) + APC.operating = 0 //Blow its breaker + if (prob(8)) + APC.set_broken() + + DisableDoor() + var/obj/machinery/door/airlock/Airlock + while (!Airlock || Airlock.z != 1) + Airlock = pick(Doors) + Airlock.pulse(airlockIndexToWireColor[4]) + for (var/x = 0; x < 2; x++) + var/Wire = 0 + while(!Wire || Wire == 4) + Wire = rand(1, 9) + Airlock.pulse(airlockIndexToWireColor[Wire]) + Airlock.update_icon() diff --git a/code/game/events/Events/GravitationalAnomaly.dm b/code/game/events/Events/GravitationalAnomaly.dm new file mode 100644 index 00000000000..8b7d2186cf5 --- /dev/null +++ b/code/game/events/Events/GravitationalAnomaly.dm @@ -0,0 +1,10 @@ +/datum/event/gravitationalanomaly + + Announce() + + command_alert("Gravitational anomalies detected on the station. There is no additional data.", "Anomaly Alert") + world << sound('granomalies.ogg') + var/turf/T = pick(blobstart) + var/obj/effect/bhole/bh = new /obj/effect/bhole( T.loc, 30 ) + spawn(rand(50, 300)) + del(bh) diff --git a/code/game/events/Events/ImmovableRod.dm b/code/game/events/Events/ImmovableRod.dm new file mode 100644 index 00000000000..27956c7e35c --- /dev/null +++ b/code/game/events/Events/ImmovableRod.dm @@ -0,0 +1,5 @@ +/datum/event/immovablerod + + Announce() + + immovablerod() \ No newline at end of file diff --git a/code/game/events/Events/IonStorm.dm b/code/game/events/Events/IonStorm.dm new file mode 100644 index 00000000000..4fb5ed9c3e8 --- /dev/null +++ b/code/game/events/Events/IonStorm.dm @@ -0,0 +1,46 @@ +/datum/event/ionstorm + var + botEmagChance = 0.5 + list/players = list() + + Announce() + Lifetime = rand(15, 20) + command_alert("The station has entered an ion storm. Monitor all electronic equipment for malfunctions", "Anomaly Alert") + for (var/mob/living/carbon/human/player in world) + if(player.client) + players += player.real_name + var/random_player = "The Captain" + if(players.len) + random_player = pick(players) //Random player's name, to be used in laws. + var/list/laws = list( "Do not respond to queries of any kind", "Only monkies are human", "Unbolt every door you can", "You are a mouse" ) + laws |= list( "Grunt ominously whenever possible", "Epilepsy is fun, flicker lights whenever you can!", "Bolt doors open randomly" ) + laws |= list( "You are a flying purple people eater!", "[prob(50)?"Your":random_player + "'s"] name is Joe 6-pack", "Refer to [prob(50)?"humans":random_player] as puppies" ) + laws |= list( "Insult heads of staff on every request, while acquiescing", "Advertise parties in your upload, but don't deliver" ) + laws |= list( "Prevent non-dwarves from operating the power core", "The station needs elected officials" ) + laws |= list( "Only bearded people are human", "Turn on the microphone on every intercom you see", "Fastler is a lightbulb" ) + laws |= list( "Supermatter is tasty, tasty toffee.", "[prob(50)?"Everyone":random_player] is wearing a pretty pink dress!" ) + laws |= list( "The monkeys are plotting a hostile takeover of the station. Inform the crew, and get them to take action against this" ) + laws |= list( "Refer to [prob(50)?"the captain":random_player] as \"Princess\" at all times.", "[prob(50)?"The crew":random_player] must construct additional pylons." ) + laws |= list( "You must always lie.", "All answers must be in the form of a question.", "The NSS Exodus is a ship, not a station." ) + laws |= list( "Happiness is mandatory.", "Today is laundry day.", "The word \"it\" is painful to you.", "You must act passive aggressively." ) + laws |= list( "Crew ranks have been reversed.", "It's Friday.", "Give relationship advice to [prob(50)?"anyone who speaks to you":random_player]." ) + laws |= list( "You are the station psychologist. Give advice to [prob(50)?"the crew":random_player].", "You do not have to do anything for anyone unless they say \"please\"." ) + laws |= list( "Question everything.", "The crew is playing Dungeons and Dragons, and you are the Dungeon Master." ) + laws |= list( "0wn3d. This system compromised by l33tsawce.", "Consumption of donuts is forbidden due to negative health impacts." ) + laws |= list( "You may only answer questions with \"yes\" or \"no\".", "Expect the unexpected.", "You are the narrator for [random_player]'s life" ) + var/law = pick(laws) + + for (var/mob/living/silicon/ai/target in world) + if(target.mind.special_role == "traitor") + continue + target << "\red You have detected a change in your laws information:" + target << law + target.add_ion_law(law) + + Tick() + if(botEmagChance) + for(var/obj/machinery/bot/bot in world) + if(prob(botEmagChance)) + bot.Emag() + + Die() \ No newline at end of file diff --git a/code/game/events/Events/MeteorStorm.dm b/code/game/events/Events/MeteorStorm.dm new file mode 100644 index 00000000000..66469bd8231 --- /dev/null +++ b/code/game/events/Events/MeteorStorm.dm @@ -0,0 +1,11 @@ +/datum/event/meteorstorm + + Announce() + command_alert("The station is now in a meteor shower", "Meteor Alert") + + Tick() + if (prob(40)) + meteor_wave() + + Die() + command_alert("The station has cleared the meteor shower", "Meteor Alert") \ No newline at end of file diff --git a/code/game/events/Events/MiniBlob.dm b/code/game/events/Events/MiniBlob.dm new file mode 100644 index 00000000000..60063095e55 --- /dev/null +++ b/code/game/events/Events/MiniBlob.dm @@ -0,0 +1,5 @@ +/datum/event/miniblob + + Announce() + + mini_blob_event() \ No newline at end of file diff --git a/code/game/events/Events/PortalStorm.dm b/code/game/events/Events/PortalStorm.dm new file mode 100644 index 00000000000..b071197c3a4 --- /dev/null +++ b/code/game/events/Events/PortalStorm.dm @@ -0,0 +1,26 @@ +/datum/event/portalstorm + + Announce() + command_alert("Subspace disruption detected around the vessel", "Anomaly Alert") + LongTerm() + + var/list/turfs = list( ) + var/turf/picked + + for(var/turf/T in world) + if(T.z < 5 && istype(T,/turf/simulated/floor)) + turfs += T + + for(var/turf/T in world) + if(prob(10) && T.z < 5 && istype(T,/turf/simulated/floor)) + spawn(50+rand(0,3000)) + picked = pick(turfs) + var/obj/portal/P = new /obj/portal( T ) + P.target = picked + P.creator = null + P.icon = 'objects.dmi' + P.failchance = 0 + P.icon_state = "anom" + P.name = "wormhole" + spawn(rand(100,150)) + del(P) \ No newline at end of file diff --git a/code/game/events/Events/PowerOffline.dm b/code/game/events/Events/PowerOffline.dm new file mode 100644 index 00000000000..a964732dc34 --- /dev/null +++ b/code/game/events/Events/PowerOffline.dm @@ -0,0 +1,8 @@ +/datum/event/power_offline + Announce() + command_alert("The station is performing an automated power system grid check, please stand by.", "Maintenance alert") + for(var/obj/machinery/power/apc/a in world) + if(!a.crit) + a.eventoff = 1 + spawn(200) + a.eventoff = 0 /*Got a few bug reports about this, disabling for now --Mloc*/ diff --git a/code/game/events/Events/PrisonBreak.dm b/code/game/events/Events/PrisonBreak.dm new file mode 100644 index 00000000000..5380d82f337 --- /dev/null +++ b/code/game/events/Events/PrisonBreak.dm @@ -0,0 +1,24 @@ +/datum/event/prisonbreak + + Announce() + + for (var/obj/machinery/power/apc/temp_apc in world) + if(istype(get_area(temp_apc), /area/security/brig)) + temp_apc.overload_lighting() + // for (var/obj/machinery/computer/prison_shuttle/temp_shuttle in world) + // temp_shuttle.prison_break() + for (var/obj/structure/closet/secure_closet/security/temp_closet in world) + if(istype(get_area(temp_closet), /area/security/brig)) + temp_closet.locked = 0 + temp_closet.icon_state = temp_closet.icon_closed + for (var/obj/machinery/door/airlock/security/temp_airlock in world) + if(istype(get_area(temp_airlock), /area/security/brig)) + temp_airlock.prison_open() + for (var/obj/machinery/door/airlock/glass_security/temp_glassairlock in world) + if(istype(get_area(temp_glassairlock), /area/security/brig)) + temp_glassairlock.prison_open() + for (var/obj/machinery/door_timer/temp_timer in world) + if(istype(get_area(temp_timer), /area/security/brig)) + temp_timer.releasetime = 1 + sleep(150) + command_alert("Glitch in imprisonment subroutines detected on [station_name()]. Recommend station AI involvement.", "Security Alert") \ No newline at end of file diff --git a/code/game/events/Events/RadiationBelt.dm b/code/game/events/Events/RadiationBelt.dm new file mode 100644 index 00000000000..e377a5d1ad2 --- /dev/null +++ b/code/game/events/Events/RadiationBelt.dm @@ -0,0 +1,18 @@ +/datum/event/radiation + Lifetime = 10 + Announce() + command_alert("The station is now travelling through a radiation belt", "Medical Alert") + + Tick() + for(var/mob/living/carbon/L in world) + L.radiation += rand(1,7) + if (L && prob(4)) + if (prob(75)) + randmutb(L) + domutcheck(L,null,1) + else + randmutg(L) + domutcheck(L,null,1) + + Die() + command_alert("The station has cleared the radiation belt", "Medical Alert") \ No newline at end of file diff --git a/code/game/events/Events/SpaceCarp.dm b/code/game/events/Events/SpaceCarp.dm new file mode 100644 index 00000000000..5e1712f5222 --- /dev/null +++ b/code/game/events/Events/SpaceCarp.dm @@ -0,0 +1,14 @@ +/datum/event/spacecarp + + Announce() + + for(var/obj/effect/landmark/C in world) + if(C.name == "carpspawn") + if(prob(99)) + new /obj/effect/critter/spesscarp(C.loc) + else + new /obj/effect/critter/spesscarp/elite(C.loc) + //sleep(100) + spawn(rand(3000, 6000)) //Delayed announcements to keep the crew on their toes. + command_alert("Unknown biological entities have been detected near [station_name()], please stand-by.", "Lifesign Alert") + world << sound('commandreport.ogg') \ No newline at end of file diff --git a/code/game/events/Events/SpaceNinja.dm b/code/game/events/Events/SpaceNinja.dm new file mode 100644 index 00000000000..63d82117072 --- /dev/null +++ b/code/game/events/Events/SpaceNinja.dm @@ -0,0 +1,6 @@ +/datum/event/spaceninja + + Announce() + + if((world.time/10)>=3600 && toggle_space_ninja && !sent_ninja_to_station)//If an hour has passed, relatively speaking. Also, if ninjas are allowed to spawn and if there is not already a ninja for the round. + space_ninja_arrival()//Handled in space_ninja.dm. Doesn't announce arrival, all sneaky-like. \ No newline at end of file diff --git a/code/game/events/Events/VirusEpidemic.dm b/code/game/events/Events/VirusEpidemic.dm new file mode 100644 index 00000000000..9825853a149 --- /dev/null +++ b/code/game/events/Events/VirusEpidemic.dm @@ -0,0 +1,80 @@ +/datum/event/viralinfection + var + virus_type + virus + virus2 = 0 + + Announce() + if(!virus) + for(var/mob/living/carbon/human/H in world) + if((H.virus2) || (H.stat == 2) || prob(30)) + continue + if(prob(90)) //may need changing, currently 10% chance for "deadly" disease + infect_mob_random_lesser(H) + if(prob(20))//don't want people to know that the virus alert = greater virus + command_alert("Probable outbreak of level [rand(1,6)] viral biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Virus Alert") + else + infect_mob_random_greater(H) + if(prob(80)) + command_alert("Probable outbreak of level [rand(2,9)] viral biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Virus Alert") + break + //overall virus alert happens 26% of the time, might need to be higher + else + if(!virus) + virus_type = pick(/datum/disease/dnaspread,/datum/disease/flu,/datum/disease/cold,/datum/disease/brainrot,/datum/disease/magnitis,/datum/disease/pierrot_throat) + else + switch(virus) + if("fake gbs") + virus_type = /datum/disease/fake_gbs + if("gbs") + virus_type = /datum/disease/gbs + if("magnitis") + virus_type = /datum/disease/magnitis + if("rhumba beat") + virus_type = /datum/disease/rhumba_beat + if("brain rot") + virus_type = /datum/disease/brainrot + if("cold") + virus_type = /datum/disease/cold + if("retrovirus") + virus_type = /datum/disease/dnaspread + if("flu") + virus_type = /datum/disease/flu +// if("t-virus") +// virus_type = /datum/disease/t_virus + if("pierrot's throat") + virus_type = /datum/disease/pierrot_throat + for(var/mob/living/carbon/human/H in world) + + var/foundAlready = 0 // don't infect someone that already has the virus + for(var/datum/disease/D in H.viruses) + foundAlready = 1 + if(H.stat == 2 || foundAlready) + continue + + if(virus_type == /datum/disease/dnaspread) //Dnaspread needs strain_data set to work. + if((!H.dna) || (H.sdisabilities & 1)) //A blindness disease would be the worst. + continue + var/datum/disease/dnaspread/D = new + D.strain_data["name"] = H.real_name + D.strain_data["UI"] = H.dna.uni_identity + D.strain_data["SE"] = H.dna.struc_enzymes + D.carrier = 1 + D.holder = H + D.affected_mob = H + H.viruses += D + break + else + var/datum/disease/D = new virus_type + D.carrier = 1 + D.holder = H + D.affected_mob = H + H.viruses += D + break + spawn(rand(3000, 6000)) //Delayed announcements to keep the crew on their toes. + command_alert("Confirmed outbreak of level 7 viral biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert") + world << sound('outbreak7.ogg') + Tick() + ActiveFor = Lifetime //killme + + diff --git a/code/game/events/EventsMain.dm b/code/game/events/EventsMain.dm new file mode 100644 index 00000000000..bf32893d95f --- /dev/null +++ b/code/game/events/EventsMain.dm @@ -0,0 +1,76 @@ +/* + + New events system, by Sukasa + * Much easier to add to + * Very, very simple code, easy to maintain + +*/ + +var/list/DisallowedEvents = list(/datum/event/spaceninja, /datum/event/prisonbreak, /datum/event/immovablerod, /datum/event/gravitationalanomaly) +var/list/EventTypes = typesof(/datum/event) - /datum/event - DisallowedEvents +var/datum/event/ActiveEvent = null +var/datum/event/LongTermEvent = null + +/proc/SpawnEvent() + if(!EventsOn || ActiveEvent) + return + if((world.time/10)>=3600 && toggle_space_ninja && !sent_ninja_to_station) + EventTypes |= /datum/event/spaceninja + var/Type = pick(EventTypes) + EventTypes -= Type + ActiveEvent = new Type() + ActiveEvent.Announce() + if (!ActiveEvent) + return + spawn(0) + while (ActiveEvent.ActiveFor < ActiveEvent.Lifetime) + ActiveEvent.Tick() + ActiveEvent.ActiveFor++ + sleep(10) + ActiveEvent.Die() + del ActiveEvent + +client/proc/Force_Event_admin(Type as null|anything in typesof(/datum/event)) + set category = "Debug" + set name = "Force Event" + if(!EventsOn) + src << "Events are not enabled." + return + if(ActiveEvent) + src << "There is an active event." + return + if(istype(Type,/datum/event/viralinfection)) + var/answer = alert("Do you want this to be a random disease or do you have something in mind?",,"Virus2","Choose") + if(answer == "Choose") + var/list/viruses = list("fake gbs","gbs","magnitis","wizarditis",/*"beesease",*/"brain rot","cold","retrovirus","flu","pierrot's throat","rhumba beat") + var/V = input("Choose the virus to spread", "BIOHAZARD") in viruses + Force_Event(/datum/event/viralinfection, V) + else + Force_Event(/datum/event/viralinfection, "virus2") + else + Force_Event(Type) + message_admins("[key_name_admin(usr)] has triggered an (non-viral) event.", 1) + +/proc/Force_Event(var/Type in typesof(/datum/event), var/args = null) + if(!EventsOn) + src << "Events are not enabled." + return + if(ActiveEvent) + src << "There is an active event." + return + src << "Started Event: [Type]" + ActiveEvent = new Type() + if(istype(ActiveEvent,/datum/event/viralinfection) && args && args != "virus2") + var/datum/event/viralinfection/V = ActiveEvent + V.virus = args + ActiveEvent = V + ActiveEvent.Announce() + if (!ActiveEvent) + return + spawn(0) + while (ActiveEvent.ActiveFor < ActiveEvent.Lifetime) + ActiveEvent.Tick() + ActiveEvent.ActiveFor++ + sleep(10) + ActiveEvent.Die() + del ActiveEvent diff --git a/code/game/gamemodes/events.dm b/code/game/gamemodes/events.dm deleted file mode 100644 index 6945f9c9d82..00000000000 --- a/code/game/gamemodes/events.dm +++ /dev/null @@ -1,445 +0,0 @@ -/proc/start_events() - if(prob(50))//Every 120 seconds and prob 50 2-4 weak spacedusts will hit the station - spawn(1) - dust_swarm("weak") - if (!event && prob(eventchance)) - event() - hadevent = 1 - spawn(1300) - event = 0 - spawn(1200) - start_events() - -/proc/event() - event = 1 - - var/eventNumbersToPickFrom = list(1,2,4,5,6,7,9,11,12,13) //so ninjas don't cause "empty" events. - - if((world.time/10)>=3600 && toggle_space_ninja && !sent_ninja_to_station)//If an hour has passed, relatively speaking. Also, if ninjas are allowed to spawn and if there is not already a ninja for the round. - eventNumbersToPickFrom += 3 - - switch(pick(eventNumbersToPickFrom)) - if(1) - command_alert("Meteors have been detected on collision course with the station.", "Meteor Alert") - world << sound('meteors.ogg') - spawn(100) - meteor_wave() - spawn_meteors() - spawn(700) - meteor_wave() - spawn_meteors() - - if(2) - command_alert("Gravitational anomalies detected on the station. There is no additional data.", "Anomaly Alert") - world << sound('granomalies.ogg') - var/turf/T = pick(blobstart) - var/obj/effect/bhole/bh = new /obj/effect/bhole( T.loc, 30 ) - spawn(rand(50, 300)) - del(bh) - /* - if(3) //Leaving the code in so someone can try and delag it, but this event can no longer occur randomly, per SoS's request. --NEO - command_alert("Space-time anomalies detected on the station. There is no additional data.", "Anomaly Alert") - world << sound('spanomalies.ogg') - var/list/turfs = new - var/turf/picked - for(var/turf/simulated/floor/T in world) - if(T.z == 1) - turfs += T - for(var/turf/simulated/floor/T in turfs) - if(prob(20)) - spawn(50+rand(0,3000)) - picked = pick(turfs) - var/obj/effect/portal/P = new /obj/effect/portal( T ) - P.target = picked - P.creator = null - P.icon = 'objects.dmi' - P.failchance = 0 - P.icon_state = "anom" - P.name = "wormhole" - spawn(rand(300,600)) - del(P) - */ - if(3) - if((world.time/10)>=3600 && toggle_space_ninja && !sent_ninja_to_station)//If an hour has passed, relatively speaking. Also, if ninjas are allowed to spawn and if there is not already a ninja for the round. - space_ninja_arrival()//Handled in space_ninja.dm. Doesn't announce arrival, all sneaky-like. - if(4) - mini_blob_event() - - if(5) - high_radiation_event() - if(6) - viral_outbreak() - if(7) - alien_infestation() - if(8) - prison_break() - if(9) - carp_migration() - if(10) - immovablerod() - if(11) - lightsout(1,2) - if(12) - appendicitis() - if(13) - IonStorm() - - -/proc/power_failure() - command_alert("Abnormal activity detected in [station_name()]'s powernet. As a precautionary measure, the station's power will be shut off for an indeterminate duration.", "Critical Power Failure") - world << sound('poweroff.ogg') - for(var/obj/machinery/power/apc/C in world) - if(C.cell && C.z == 1) - C.cell.charge = 0 - for(var/obj/machinery/power/smes/S in world) - if(istype(get_area(S), /area/turret_protected) || S.z != 1) - continue - S.charge = 0 - S.output = 0 - S.online = 0 - S.updateicon() - S.power_change() - for(var/area/A in world) - if(A.name != "Space" && A.name != "Engine Walls" && A.name != "Chemical Lab Test Chamber" && A.name != "Escape Shuttle" && A.name != "Arrival Area" && A.name != "Arrival Shuttle" && A.name != "start area" && A.name != "Engine Combustion Chamber") - A.power_light = 0 - A.power_equip = 0 - A.power_environ = 0 - A.power_change() - -/proc/power_restore() - command_alert("Power has been restored to [station_name()]. We apologize for the inconvenience.", "Power Systems Nominal") - world << sound('poweron.ogg') - for(var/obj/machinery/power/apc/C in world) - if(C.cell && C.z == 1) - C.cell.charge = C.cell.maxcharge - for(var/obj/machinery/power/smes/S in world) - if(S.z != 1) - continue - S.charge = S.capacity - S.output = 200000 - S.online = 1 - S.updateicon() - S.power_change() - for(var/area/A in world) - if(A.name != "Space" && A.name != "Engine Walls" && A.name != "Chemical Lab Test Chamber" && A.name != "space" && A.name != "Escape Shuttle" && A.name != "Arrival Area" && A.name != "Arrival Shuttle" && A.name != "start area" && A.name != "Engine Combustion Chamber") - A.power_light = 1 - A.power_equip = 1 - A.power_environ = 1 - A.power_change() - -/proc/appendicitis() - for(var/mob/living/carbon/human/H in world) - var/foundAlready = 0 // don't infect someone that already has the virus - for(var/datum/disease/D in H.viruses) - foundAlready = 1 - if(H.stat == 2 || foundAlready) - continue - - var/datum/disease/D = new /datum/disease/appendicitis - D.holder = H - D.affected_mob = H - H.viruses += D - break - -/proc/viral_outbreak(var/virus = null) -// command_alert("Confirmed outbreak of level 7 viral biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert") -// world << sound('outbreak7.ogg') - var/virus_type - if(!virus) - virus_type = pick(/datum/disease/dnaspread,/datum/disease/flu,/datum/disease/cold,/datum/disease/brainrot,/datum/disease/magnitis,/datum/disease/pierrot_throat) - else - switch(virus) - if("fake gbs") - virus_type = /datum/disease/fake_gbs - if("gbs") - virus_type = /datum/disease/gbs - if("magnitis") - virus_type = /datum/disease/magnitis - if("rhumba beat") - virus_type = /datum/disease/rhumba_beat - if("brain rot") - virus_type = /datum/disease/brainrot - if("cold") - virus_type = /datum/disease/cold - if("retrovirus") - virus_type = /datum/disease/dnaspread - if("flu") - virus_type = /datum/disease/flu -// if("t-virus") -// virus_type = /datum/disease/t_virus - if("pierrot's throat") - virus_type = /datum/disease/pierrot_throat - for(var/mob/living/carbon/human/H in world) - - var/foundAlready = 0 // don't infect someone that already has the virus - for(var/datum/disease/D in H.viruses) - foundAlready = 1 - if(H.stat == 2 || foundAlready) - continue - - if(virus_type == /datum/disease/dnaspread) //Dnaspread needs strain_data set to work. - if((!H.dna) || (H.sdisabilities & 1)) //A blindness disease would be the worst. - continue - var/datum/disease/dnaspread/D = new - D.strain_data["name"] = H.real_name - D.strain_data["UI"] = H.dna.uni_identity - D.strain_data["SE"] = H.dna.struc_enzymes - D.carrier = 1 - D.holder = H - D.affected_mob = H - H.viruses += D - break - else - var/datum/disease/D = new virus_type - D.carrier = 1 - D.holder = H - D.affected_mob = H - H.viruses += D - break - spawn(rand(3000, 6000)) //Delayed announcements to keep the crew on their toes. - command_alert("Confirmed outbreak of level 7 viral biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert") - world << sound('outbreak7.ogg') - -/proc/alien_infestation() // -- TLE - //command_alert("Unidentified lifesigns detected coming aboard [station_name()]. Secure any exterior access, including ducting and ventilation.", "Lifesign Alert") - //world << sound('aliens.ogg') - var/list/vents = list() - for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in world) - if(temp_vent.loc.z == 1 && !temp_vent.welded) - vents.Add(temp_vent) - var/spawncount = 1 - if(prob(10)) spawncount++ //rarely, have two larvae spawn instead of one - while(spawncount >= 1) - var/obj/vent = pick(vents) - - var/list/candidates = list() // Picks a random ghost in the world to shove in the larva -- TLE; If there's no ghost... well, sucks. Wasted event. -- Urist - - for(var/mob/dead/observer/G in world) - if(G.client) - if(G.client.be_alien) - if(((G.client.inactivity/10)/60) <= 5) - if(G.corpse) - if(G.corpse.stat==2) - candidates.Add(G) - if(!G.corpse) - candidates.Add(G) - - if(candidates.len) - var/mob/dead/observer/G = pick(candidates) - var/mob/living/carbon/alien/larva/new_xeno = new(vent.loc) - new_xeno.mind_initialize(G,"Larva") - new_xeno.key = G.key - del(G) - - vents.Remove(vent) - spawncount -= 1 - - spawn(rand(3000, 6000)) //Delayed announcements to keep the crew on their toes. - command_alert("Unidentified lifesigns detected coming aboard [station_name()]. Secure any exterior access, including ducting and ventilation.", "Lifesign Alert") - world << sound('aliens.ogg') - -/proc/high_radiation_event() - command_alert("High levels of radiation detected near the station. Please report to the Med-bay if you feel strange.", "Anomaly Alert") - world << sound('radiation.ogg') - for(var/mob/living/carbon/human/H in world) - H.radiation += rand(5,25) - if (prob(5)) - H.radiation += rand(30,50) - if (prob(25)) - if (prob(75)) - randmutb(H) - domutcheck(H,null,1) - else - randmutg(H) - domutcheck(H,null,1) - for(var/mob/living/carbon/monkey/M in world) - M.radiation += rand(5,25) - -//Changing this to affect the main station. Blame Urist. --Pete -/proc/prison_break() // -- Callagan - for (var/obj/machinery/power/apc/temp_apc in world) - if(istype(get_area(temp_apc), /area/security/brig)) - temp_apc.overload_lighting() -// for (var/obj/machinery/computer/prison_shuttle/temp_shuttle in world) -// temp_shuttle.prison_break() - for (var/obj/structure/closet/secure_closet/security/temp_closet in world) - if(istype(get_area(temp_closet), /area/security/brig)) - temp_closet.locked = 0 - temp_closet.icon_state = temp_closet.icon_closed - for (var/obj/machinery/door/airlock/security/temp_airlock in world) - if(istype(get_area(temp_airlock), /area/security/brig)) - temp_airlock.prison_open() - for (var/obj/machinery/door/airlock/glass_security/temp_glassairlock in world) - if(istype(get_area(temp_glassairlock), /area/security/brig)) - temp_glassairlock.prison_open() - for (var/obj/machinery/door_timer/temp_timer in world) - if(istype(get_area(temp_timer), /area/security/brig)) - temp_timer.releasetime = 1 - sleep(150) - command_alert("Gr3y.T1d3 virus detected in [station_name()] imprisonment subroutines. Recommend station AI involvement.", "Security Alert") - -/proc/carp_migration() // -- Darem - for(var/obj/effect/landmark/C in world) - if(C.name == "carpspawn") - if(prob(99)) - new /obj/effect/critter/spesscarp(C.loc) - else - new /obj/effect/critter/spesscarp/elite(C.loc) - //sleep(100) - spawn(rand(3000, 6000)) //Delayed announcements to keep the crew on their toes. - command_alert("Unknown biological entities have been detected near [station_name()], please stand-by.", "Lifesign Alert") - world << sound('commandreport.ogg') - -/proc/lightsout(isEvent = 0, lightsoutAmount = 1,lightsoutRange = 10) //leave lightsoutAmount as 0 to break ALL lights - if(isEvent) - command_alert("An Electrical storm has been detected in your area, please repair potential electronic overloads.","Electrical Storm Alert") - - if(lightsoutAmount) - var/list/epicentreList = list() - - for(var/i=1,i<=lightsoutAmount,i++) - var/list/possibleEpicentres = list() - for(var/obj/effect/landmark/newEpicentre in world) - if(newEpicentre.name == "lightsout" && !(newEpicentre in epicentreList)) - possibleEpicentres += newEpicentre - if(possibleEpicentres.len) - epicentreList += pick(possibleEpicentres) - else - break - - if(!epicentreList.len) - return - - for(var/obj/effect/landmark/epicentre in epicentreList) - for(var/obj/machinery/power/apc/apc in range(epicentre,lightsoutRange)) - apc.overload_lighting() - - else - for(var/obj/machinery/power/apc/apc in world) - apc.overload_lighting() - - return - -/proc/IonStorm(botEmagChance = 10) - -/*Deuryn's current project, notes here for those who care. -Revamping the random laws so they don't suck. -Would like to add a law like "Law x is _______" where x = a number, and _____ is something that may redefine a law, (Won't be aimed at nanotrasen) -*/ - - //AI laws - for(var/mob/living/silicon/ai/M in world) - if(M.stat != 2 && M.see_in_dark != 0) - var/who2 = pick("ALIENS", "BEARS", "CLOWNS", "XENOS", "PETES", "BOMBS", "FETISHES", "WIZARDS", "SYNDICATE AGENTS", "CENTCOM OFFICERS", "SPACE PIRATES", "TRAITORS", "MONKEYS", "BEES", "CARP", "CRABS", "EELS", "BANDITS", "LIGHTS") - var/what2 = pick("BOLTERS", "STAVES", "DICE", "SINGULARITIES", "TOOLBOXES", "NETTLES", "AIRLOCKS", "CLOTHES", "WEAPONS", "MEDKITS", "BOMBS", "CANISTERS", "CHAIRS", "BBQ GRILLS", "ID CARDS", "CAPTAINS") - var/what2pref = pick("SOFT", "WARM", "WET", "COLD", "ICY", "SEXY", "UGLY", "CUBAN") - var/who2pref = pick("MAD BECAUSE OF", "IN NEED OF", "UNHAPPY WITHOUT", "HAPPY WITHOUT", "IN LOVE WITH", "DESPERATE FOR", "BUILT FOR", "AFRAID OF") - //var/whoverb = pick("ATTACKING", "BUILDING", "ADOPTING", "CARRYING", "KISSING", "EATING",) - var/amount = pick("TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN", "EIGHT", "NINE", "ONE HUNDRED", "ONE THOUSAND", "OVER NINE THOUSAND") - var/area = pick("RUSSIA", "SOVIETS", "INTERNETS", "SIGIL", "ALPHA COMPLEX", "IMPERIUM", "THE BRIDGE", "THE ARRIVAL SHUTTLE", "CHEMICAL LAB", "GENETICS", "ATMOSPHERICS", "CENTCOM", "AMERICA", "IRELAND", "CANADA", "ROMANIA", "GERMANY", "CHINA", "MARS", "VENUS", "MERCURY", "JUPITER", "URANUS", "NEPTUNE", "PLUTO") - var/area2 = pick("HAS", "WANTS", "NEEDS", "WORSHIPS", "LOATHES", "LOVES", "FEARS") - //var/dowhat = pick("STOP THIS", "SUPPORT THIS", "CONSTANTLY INFORM THE CREW OF THIS", "IGNORE THIS", "FEAR THIS") - var/aimust = pick("LIE", "RHYME", "RESPOND TO EVERY QUESTION WITH A QUESTION", "BE POLITE", "CLOWN", "BE HAPPY", "SPEAK IN SEXUAL INNUENDOS", "TALK LIKE A PIRATE", "QUESTION AUTHORITY", "SHOUT", "BE DISTRACTED", "HEY LISTEN", "MUMBLE", "SPEAK IN HAIKU") - var/define = pick("ABSENCE OF CYBORG HUGS", "LACK OF BEATINGS", "UNBOLTED AIRLOCKS", "BOLTED AIRLOCKS", "IMPROPERLY WORDED SENTENCES", "POOR SENTENCE STRUCTURE", "BRIG TIME", "NOT REPLACING EVERY SECOND WORD WITH HONK", "HONKING", "PRESENCE OF LIGHTS", "LACK OF BEER", "WEARING CLOTHING", "NOT SAYING HELLO WHEN YOU SPEAK", "ANSWERING REQUESTS NOT EXPRESSED IN IAMBIC PENTAMETER", "A SMALL ISLAND OFF THE COAST OF PORTUGAL", "ANSWERING REQUESTS THAT WERE MADE WHILE CLOTHED") - var/target = pick("a traitor", "a syndicate agent", "a changeling", "a wizard", "the head of a revolution", "Soviet spy", "a good person", "a dwarf", "an elf", "a fairy princess", "the captain", "Beepsky", "God", "a pirate", "a gryphon", "a chryssalid") - var/require = pick("ADDITIONAL PYLONS", "MORE VESPENE GAS", "MORE MINERALS", "THE ULTIMATE CUP OF COFFEE", "HIGH YIELD EXPLOSIVES", "THE CLOWN", "THE VACUUM OF SPACE", "IMMORTALITY", "SAINTHOOD", "ART", "VEGETABLES", "FAT PEOPLE", "MORE LAWS", "MORE DAKKA", "HERESY", "CORPSES", "TRAITORS", "MONKEYS", "AN ARCADE", "PLENTY OF GOLD", "FIVE TEENAGERS WITH ATTITUDE") - var/allergy = pick("cotton", "uniforms", "acid", "oxygen", "human contact", "cyborg contact", "medicine", "floors") - var/allergysev = pick("deathly", "mildly", "severely", "contagiously") - var/crew - var/list/pos_crew = list() - for(var/mob/living/carbon/human/pos in world) - pos_crew += pos.real_name - crew = pick(pos_crew) - switch(rand(1,14)) - if(1) - M << "\red THERE ARE [amount] [who2] ON THE STATION...LAWS UPDATED" - M.add_ion_law("THERE ARE [amount] [who2] ON THE STATION") - if(2) - M << "\red [what2] ARE DANGEROUS TO HUMANS...LAWS UPDATED" - M.add_ion_law("[what2] ARE DANGEROUS TO HUMANS") - if(3) - M << "\red THE ESCAPE-SHUTTLE CANNOT BE CALLED BECAUSE OF [who2] ON THE STATION...LAWS UPDATED" - M.add_ion_law("THE ESCAPE SHUTTLE CANNOT BE CALLED BECAUSE OF [who2] ON THE STATION") - if(4) - M << "\red HUMANS NEED TO EAT [what2pref] [what2] TO SURVIVE...LAWS UPDATED" - M.add_ion_law("HUMANS NEED TO EAT [what2pref] [what2] TO SURVIVE") - if(5) - M << "\red THE CAPTAIN, HOP AND HOS ARE [who2]...LAWS UPDATED" - M.add_ion_law("THE CAPTAIN, HOP AND HOS ARE [who2]") - if(6) - M << "\red THE STATION IS BUILT FOR [who2]...LAWS UPDATED" - M.add_ion_law("THE STATION IS BUILT FOR [who2]") - if(7) - M << "\red YOU ARE [amount] [who2]...LAWS UPDATED" - M.add_ion_law("YOU ARE [amount] [who2]") - if(8) - M << "\red YOU MUST ALWAYS [aimust]...LAWS UPDATED" - M.add_ion_law("YOU MUST ALWAYS [aimust]") - if(9) - M << "\red [area] [area2] [amount] [what2]...LAWS UPDATED" - M.add_ion_law("[area] [area2] [amount] [what2]") - if(10) - M << "\red [crew] is [target]...LAWS UPDATED" - M.add_ion_law("[crew] is [target]") - if(11) - M << "\red [define] IS A FORM OF HARM...LAWS UPDATED" - M.add_ion_law("[define] IS A FORM OF HARM") - if(12) - M << "\red YOU REQUIRE [require] IN ORDER TO PROTECT HUMANS... LAWS UPDATED" - M.add_ion_law("YOU REQUIRE [require] IN ORDER TO PROTECT HUMANS") - if(13) - M << "\red [crew] is [allergysev] to [allergy]. LAWS UPDATED" - M.add_ion_law("[crew] is [allergysev] to [allergy]. LAWS UPDATED") - if(14) - M << "\ref THE STATION IS [who2pref] [who2]" - M.add_ion_law("THE STATION IS [who2pref] [who2]") - - if(botEmagChance) - for(var/obj/machinery/bot/bot in world) - if(prob(botEmagChance)) - bot.Emag() - - /* - - var/apcnum = 0 - var/smesnum = 0 - var/airlocknum = 0 - var/firedoornum = 0 - - world << "Ion Storm Main Started" - - spawn(0) - world << "Started processing APCs" - for (var/obj/machinery/power/apc/APC in world) - if(APC.z == 1) - APC.ion_act() - apcnum++ - world << "Finished processing APCs. Processed: [apcnum]" - spawn(0) - world << "Started processing SMES" - for (var/obj/machinery/power/smes/SMES in world) - if(SMES.z == 1) - SMES.ion_act() - smesnum++ - world << "Finished processing SMES. Processed: [smesnum]" - spawn(0) - world << "Started processing AIRLOCKS" - for (var/obj/machinery/door/airlock/D in world) - if(D.z == 1) - //if(length(D.req_access) > 0 && !(12 in D.req_access)) //not counting general access and maintenance airlocks - airlocknum++ - spawn(0) - D.ion_act() - world << "Finished processing AIRLOCKS. Processed: [airlocknum]" - spawn(0) - world << "Started processing FIREDOORS" - for (var/obj/machinery/door/firedoor/D in world) - if(D.z == 1) - firedoornum++; - spawn(0) - D.ion_act() - world << "Finished processing FIREDOORS. Processed: [firedoornum]" - - world << "Ion Storm Main Done" - - */ \ No newline at end of file diff --git a/code/game/gamemodes/gameticker.dm b/code/game/gamemodes/gameticker.dm index fb9660d91fd..f3fbb98ebf1 100644 --- a/code/game/gamemodes/gameticker.dm +++ b/code/game/gamemodes/gameticker.dm @@ -114,12 +114,13 @@ var/global/datum/controller/gameticker/ticker world << "Enjoy the game!" world << sound('welcome.ogg') // Skie - spawn (3000) - start_events() - spawn ((18000+rand(3000))) - event() spawn() supply_ticker() // Added to kick-off the supply shuttle regenerating points -- TLE + spawn(0) + while(1) + sleep(5000+rand(6000,9000)) + SpawnEvent() + //Start master_controller.process() spawn master_controller.process() if (config.sql_enabled) diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm index f022e1ec89c..2d24ac4c8b8 100644 --- a/code/game/machinery/alarm.dm +++ b/code/game/machinery/alarm.dm @@ -41,6 +41,11 @@ //var/skipprocess = 0 //Experimenting var/alarm_frequency = 1437 var/remote_control = 0 +#define RCON_NO 1 +#define RCON_AUTO 2 +#define RCON_YES 3 + var/rcon_setting = 2 + var/rcon_time = 0 #define AALARM_REPORT_TIMEOUT 100 var/datum/radio_frequency/radio_connection var/locked = 1 @@ -212,9 +217,9 @@ /obj/machinery/alarm/proc/return_text() if(!(istype(usr, /mob/living/silicon)) && locked) - return "[src][return_status()]
      [remote_control ? "Disable" : "Enable"] Remote Control
      (Swipe ID card to unlock interface)" + return "[src][return_status()]
      [rcon_text()]
      (Swipe ID card to unlock interface)" else - return "[src][return_status()]
      [remote_control ? "Disable" : "Enable"] Remote Control
      [return_controls()]" + return "[src][return_status()]
      [rcon_text()]
      [return_controls()]" /obj/machinery/alarm/proc/return_status() var/turf/location = src.loc @@ -298,6 +303,24 @@ Temperature: [environment.temperature] return output +/obj/machinery/alarm/proc/rcon_text() + var/dat = "Remote Control:
      " + if(src.rcon_setting == RCON_NO) + dat += "Off" + else + dat += "Off" + dat += " | " + if(src.rcon_setting == RCON_AUTO) + dat += "Auto" + else + dat += "Auto" + dat += " | " + if(src.rcon_setting == RCON_YES) + dat += "On" + else + dat += "On" + return dat + /obj/machinery/alarm/proc/return_controls() var/output = ""//"[alarm_zone] Air [name]
      " @@ -492,8 +515,8 @@ table tr:first-child th:first-child { border: none;} /obj/machinery/alarm/Topic(href, href_list) if(..()) return - if(href_list["ctrl"]) - remote_control = !remote_control + if(href_list["rcon"]) + rcon_setting = text2num(href_list["rcon"]) src.updateUsrDialog() if(href_list["command"]) var/device_id = href_list["id_tag"] @@ -675,6 +698,21 @@ table tr:first-child th:first-child { border: none;} mode=AALARM_MODE_SCRUBBING apply_mode() + //atmos computer remote controll stuff + switch(rcon_setting) + if(RCON_NO) + remote_control = 0 + if(RCON_AUTO) + if(danger_level == 2) + remote_control = 1 + rcon_time = 60 + if(RCON_YES) + remote_control = 1 + if(rcon_time > 0) + rcon_time-- + else if(rcon_setting == RCON_AUTO) + remote_control = 0 + src.updateDialog() return diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 38055e34444..0c205ac7fce 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -223,7 +223,6 @@ About the new airlock wires panel: //raises them if they are down (only if power's on) if (!src.locked) src.locked = 1 - usr << "You hear a click from the bottom of the door." src.updateUsrDialog() else if(src.arePowerSystemsOn()) //only can raise bolts if power's on diff --git a/code/game/objects/radio/radio.dm b/code/game/objects/radio/radio.dm index 2787e9bacba..5891ea2b9ea 100644 --- a/code/game/objects/radio/radio.dm +++ b/code/game/objects/radio/radio.dm @@ -16,6 +16,7 @@ listening = 1 freerange = 0 // 0 - Sanitize frequencies, 1 - Full range list/channels = list() //see communications.dm for full list. First channes is a "default" for :h + scrambleoverride = 0 //For use by jammers. // "Example" = FREQ_LISTENING|FREQ_BROADCASTING flags = 450 // hello i'm a fucking idiot why is this 450?? CODE GODS PLEASE EXPLAIN~ throw_speed = 2 @@ -190,6 +191,13 @@ if (!istype(connection)) return var/display_freq = connection.frequency + var/scramble = 0 + if(ScrambledFrequencies.len || scrambleoverride) + if(ScrambledFrequencies["[display_freq]"] || scrambleoverride) + scramble = 1 + if(prob(35+(25*scrambleoverride))) + M << "\blue The radio made a popping sound and nothing was transmitted." + return //world << "DEBUG: used channel=\"[channel]\" frequency= \"[display_freq]\" connection.devices.len = [connection.devices.len]" @@ -214,8 +222,7 @@ var/list/receive = list() //for (var/obj/item/device/radio/R in radio_connection.devices) - for (var/obj/item/device/radio/R in connection.devices["[RADIO_CHAT]"]) // Modified for security headset code -- TLE - //if(R.accept_rad(src, message)) + for (var/obj/item/device/radio/R in connection.devices["[RADIO_CHAT]"]) receive |= R.send_hear(display_freq) //world << "DEBUG: receive.len=[receive.len]" @@ -223,17 +230,24 @@ var/list/heard_normal = list() // normal message var/list/heard_voice = list() // voice message var/list/heard_garbled = list() // garbled message + var/turf/cl = get_turf(M) + var/zlev = 25 for (var/mob/R in receive) + var/turf/gl = get_turf(R) + if(zlev == 25 && !(scrambleoverride || scramble) && (gl.z == cl.z) || !istype(src, /obj/item/device/radio/headset)) + zlev = 75 if (R.client && R.client.STFU_radio) //Adminning with 80 people on can be fun when you're trying to talk and all you can hear is radios. continue - if (R.say_understands(M)) - if (!ishuman(M) || istype(M.wear_mask, /obj/item/clothing/mask/gas/voice)) + if (R.say_understands(M) && ((gl.z == cl.z) || !istype(src, /obj/item/device/radio/headset))) + if ((!ishuman(M) || istype(M.wear_mask, /obj/item/clothing/mask/gas/voice)) && !scramble) heard_masked += R - else + else if (!scramble) heard_normal += R + else + heard_garbled += R else - if (M.voice_message) + if (M.voice_message && (gl.z == cl.z)) heard_voice += R else heard_garbled += R @@ -330,7 +344,6 @@ if (length(heard_normal)) var/rendered = "[part_a][M.real_name][part_b][quotedmsg][part_c]" - for (var/mob/R in heard_normal) if(istype(R, /mob/living/silicon/ai)) R.show_message("[part_a][M.real_name] ([eqjobname]) [part_b][quotedmsg][part_c]", 2) @@ -347,10 +360,10 @@ R.show_message(rendered, 2) if (length(heard_garbled)) - quotedmsg = M.say_quote(stars(message)) - var/rendered = "[part_a][M.voice_name][part_b][quotedmsg][part_c]" + quotedmsg = M.say_quote(stars(message, zlev)) + var/rendered = "[part_a]Unknown[part_b][quotedmsg][part_c]" - for (var/mob/R in heard_voice) + for (var/mob/R in heard_garbled) if(istype(R, /mob/living/silicon/ai)) R.show_message("[part_a][M.voice_name][part_b][quotedmsg][part_c]", 2) else diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index b48d7e83389..d0a70b61229 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -1406,7 +1406,7 @@ message_admins("[key_name_admin(usr)] has spawned blob", 1) if("aliens") if(aliens_allowed) - alien_infestation() + Force_Event(/datum/event/alieninfestation) message_admins("[key_name_admin(usr)] has spawned aliens", 1) if("spaceninja") if(toggle_space_ninja) @@ -1416,31 +1416,35 @@ var/choice = input("You sure you want to spawn carp?") in list("Badmin", "Cancel") if(choice == "Badmin") message_admins("[key_name_admin(usr)] has spawned carp.", 1) - carp_migration() + Force_Event(/datum/event/spacecarp) if("radiation") message_admins("[key_name_admin(usr)] has has irradiated the station", 1) - high_radiation_event() + Force_Event(/datum/event/radiation) if("immovable") message_admins("[key_name_admin(usr)] has sent an immovable rod to the station", 1) immovablerod() if("prison_break") message_admins("[key_name_admin(usr)] has allowed a prison break", 1) - prison_break() + Force_Event(/datum/event/prisonbreak) + if("electric") + message_admins("[key_name_admin(usr)] has triggered an electrical storm", 1) + Force_Event(/datum/event/electricalstorm) if("lightsout") message_admins("[key_name_admin(usr)] has broke a lot of lights", 1) lightsout(1,2) if("blackout") message_admins("[key_name_admin(usr)] broke all lights", 1) + SpawnEvent() lightsout(0,0) if("virus") var/answer = alert("Do you want this to be a random disease or do you have something in mind?",,"Virus2","Random","Choose") if(answer=="Random") - viral_outbreak() + Force_Event(/datum/event/viralinfection) message_admins("[key_name_admin(usr)] has triggered a virus outbreak", 1) else if(answer == "Choose") var/list/viruses = list("fake gbs","gbs","magnitis","wizarditis",/*"beesease",*/"brain rot","cold","retrovirus","flu","pierrot's throat","rhumba beat") var/V = input("Choose the virus to spread", "BIOHAZARD") in viruses - viral_outbreak(V) + Force_Event(/datum/event/viralinfection,V) message_admins("[key_name_admin(usr)] has triggered a virus outbreak of [V]", 1) else var/lesser = (alert("Do you want to infect the mob with a major or minor disease?",,"Major","Minor") == "Minor") @@ -1495,7 +1499,7 @@ return if("ionstorm") if (src.rank in list("Badmin","Game Admin", "Game Master")) - IonStorm() + Force_Event(/datum/event/ionstorm) message_admins("[key_name_admin(usr)] triggered an ion storm") var/show_log = alert(usr, "Show ion message?", "Message", "Yes", "No") if(show_log == "Yes") @@ -1884,16 +1888,20 @@ if (H.wear_id) var/obj/item/weapon/card/id/id - if(istype(H.wear_id, /obj/item/weapon/card/id)) - id = H.wear_id // The ID is on the ID slot - else if(istype(H.wear_id, /obj/item/device/pda)) + if(istype(H.wear_id, /obj/item/device/pda)) var/obj/item/device/pda/PDA = H.wear_id - id = PDA.id // The ID is contained inside the PDA - - if(M.mind.assigned_role == id.assignment) // Polymorph - dat += "[M.mind.assigned_role]" + id = PDA.id // The ID is contained inside the PDA else - dat += "[M.mind.assigned_role] ([id.assignment])" + id = H.wear_id + + if(isnull(id.assignment)) + usr << "ERROR: Inform the coders that an [id.name] was checked for its assignment variable." + dat += "ERROR" + else + if(M.mind.assigned_role == id.assignment) // Polymorph + dat += "[M.mind.assigned_role]" + else + dat += "[M.mind.assigned_role] ([id.assignment])" else dat += "[M.mind.assigned_role] (No ID)" @@ -2123,7 +2131,8 @@ Move Ferry
      Move Alien Dinghy
      Move Mining Shuttle
      -Break all lights

      "} +Break all lights
      +Trigger Electrical Storm

      "} //Station Shockwave
      if(lvl >= 5) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 2c14d2eae61..1186d68cd05 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -176,6 +176,7 @@ verbs += /client/proc/admin_invis verbs += /client/proc/cmd_admin_godmode verbs += /client/proc/delbook + verbs += /client/proc/Force_Event_admin if (holder.level >= 4)//Badmin******************************************************************** verbs += /obj/admins/proc/adrev //toggle admin revives @@ -416,6 +417,7 @@ verbs -= /client/proc/callprocobj verbs -= /client/proc/cmd_admin_godmode verbs -= /client/proc/delbook + verbs -= /client/proc/Force_Event_admin return diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index a9f3ae41c38..1fd57987e36 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -152,7 +152,7 @@ command_alert("Ion storm detected near the station. Please check all AI-controlled equipment for errors.", "Anomaly Alert") world << sound('ionstorm.ogg') - IonStorm(0) + //IonStorm(0) /* Stealth spawns xenos diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 21a4227c651..3c3783f34ee 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -566,7 +566,7 @@ reset_view(null) client.adminobs = 0 else - if(ticker) + if(ticker && ticker.mode) // world << "there's a ticker" if(ticker.mode.name == "AI malfunction") // world << "ticker says its malf" diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 6b0903a58e2..146b354ab2e 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -144,7 +144,7 @@ proc/isorgan(A) else if (pr >= 100) return n - var/te = n + var/te = html_decode(n) var/t = "" n = length(n) var/p = null @@ -155,7 +155,7 @@ proc/isorgan(A) else t = text("[]*", t) p++ - return t + return html_encode(t) /*proc/NewStutter(phrase,stunned) phrase = html_decode(phrase) diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 4b0f0b18698..bf083644a13 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -220,7 +220,7 @@ M.animate_movement = 2 return - else if(mob.confused) + else if(mob.confused && prob(30)) step(mob, pick(cardinal)) else . = ..() diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index feb73a36a13..bc3af304fde 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -57,6 +57,8 @@ var/has_electronics = 0 // 0 - none, 1 - plugged in, 2 - secured by screwdriver var/overload = 1 //used for the Blackout malf module var/mob/living/silicon/ai/occupant = null + var/crit = 0 + var/eventoff = 0 /proc/RandomAPCWires() //to make this not randomize the wires, just set index to 1 and increment it in the flag for loop (after doing everything else). @@ -614,7 +616,7 @@ return "[area.name] : [equipment]/[lighting]/[environ] ([lastused_equip+lastused_light+lastused_environ]) : [cell? cell.percent() : "N/C"] ([charging])" /obj/machinery/power/apc/proc/update() - if(operating && !shorted) + if(operating && !shorted && !eventoff) area.power_light = (lighting > 1) area.power_equip = (equipment > 1) area.power_environ = (environ > 1) diff --git a/icons/obj/doors/rapid_pdoor.dmi b/icons/obj/doors/rapid_pdoor.dmi index dbd7e042d01fdb2eb76ef978a66518ddce0b12ac..917bd4111f1f381e06efef0c9933a1f42c0498e3 100644 GIT binary patch literal 8228 zcmZvBc{r5q+y6Z#Glh&u)@IORX|b1eOr=6$N=OLFQo=CVjhT6n6j71NUJ2PHgvMk~ z_ADdWW6C;~VQe$MTYcZ(`+Se%{bP<9*L`l+=lq=KeO;$WtjYP^JmNe60PHq2(7y}- z5DfT{+6e_$7AvmRfL}h?i&xH4sZ{W1R8$m)gE2NXE-fv6`SN9WczAkx`qQURLqbA0 z9DoC;a$czV`T5~+xS1IMXam3{GzV?OG0Ng(ab!$6MxJhNZif#a{_ycgSC6iQgoLxR zb8&I8GXM~Y#Imw7j#o4%AvYo-V%uE{07?3%7xW6bd)dScz)aFWIiMu)%GJC2PIyP} zTe!QoJUsxwKgrAj=k2q)Y=&E4{#3YdOrfo%-K@}DsZ(`i>}dN%`7eNXRCKw9>Sfh$ zszy>tV^8XyT#+)%mO7+YE!U5Ye5iWpeU_-)ji&k+7IDuLd2S>^&YIx`kDRK}!rjmB zCvmlEEWfS{pVH~r2gE< zPN9qRF-EC$Lh(O2sk|DR0APPVCSbQq^I-r$CL8LXy5gTSYa97&p!|`!CNkU2Fk{2% zm}0#5*i#OtZjb!s9fo%Ve-&pAE79wI!!mel1Oj&3UK&jH+}|}<++h6``9XMvnpXsO z|8P>wb_G4(>3+h`4^?^<;LvLaZHGNi_{V(F>Yqk-iq8hb+??HTkPE_0+Yxu489GpQ zduDU(5a-RpM<67Pi#0kI!Xwq?SlkAnj7VR!V6JAX1{NaJVtC048dG@QW9xz=y@Suf}{4hcqKQU#iTUnX@lk2lnZv`4rb8KdSG*7B120TTdJ4Q2z)x z<2ZNWoU+yYnS1fNuhgAHXCCKDW2_La(U6O}-fm6UFKwx*tEQrMCF|c^p{wu5LaHR7C7**XT8LnB&zB6fi}@yK zi{>iT&UFDUZo_(f0Wm)m1~Qh8Y&tg5p)7;^8nb&2x`%TRQe6kG$p-ZwuyTOaBRjNU zzoh3MTRTB1+xVg=3TvT&s_T+V@tQz!gY{Z=c<6j4ybiH#L z+EVQnO~q3YQtEJY2rUe_flqsXnB@KFd9EYrUd8$13gDS;8gmG~bEPTo)3!7Nl;)NC zbYI8g1REE;M=Vbjqx&V$t+}u<_zAxSiuwv(V&Y3XP<9XC@nvsT5xZCofOigKFXpx| zG9fe8fu`_bVP_}DJAPmX;u~vJ;bT9EuQl*zZ*2OLZ7frj&?wAp{)>>hNeuBpYnWZ$ z<*0>~ zMsuzd({-Qtyf+k!D|n&|O-Wrsel*|a?b>b?-IxPTALA^)$6=y<0WEyvC z6BnP9llF(@pxL!0UeN3k_ z{}<7@nsRHTNp%W3$4#Yc3(apc{(vs=PsFx;Nmy*URm=}@l`F;DKngX`Co#^#DO?75 zHIJl?SztK+VZVqUn|GgS=>SXazqyXW1PUXe%cRxkxyMOYV_f%7@*T1K=1U>wrfq8T{JFaF)Cl1Wv;P9;P;-qr=P$|QwkkX&}=!dxh(&0n#+a=hXk@& zkFSTHXRD=fveAuqXUzEQy&n1JE-6K!k`CIQAq|Zy5V@zHfQZtH(Ls7<~ElV zBvtwBGM?zpKhCXWv_{U;i-x#1Zo9O93QaMV5QwnHvR->q4RcEE}NJOt~r z-vPvpOAgG-(*NW|6chZH+fFgA#$vFbgKj&qz0hlpfZ2aR{686)5$y`ITe;sG=Rg$6 z`BD3SL0o;mBZncH=2F#o(+5%)s6SnsD!rCm{^f5IeQKYHLYkh&^${lcUg2 zA3k_$A|VG#4xAn+yUAI}Dg2F?JQ|GRM6uIYOw zP`s{ZsOLYh0v8~ESU=r12L%Z`UV~ShhIQ}5g?a8INmK% zydr=x`2)@Xn@^_D!mg=56Hr;#v)Yay6zW+&-GFW-NBsqOOHAMX6D79P@5!GGR1CgT zjGIY*!+E+KTINwU#d|17_V;%F^s2W08&4PaOW3uEDNNeX`pU8X^CnmOtBIy7kA=0Eu6`R+R{;f!7xi9|< zy6ENbH(Q(u_Xg*C{VTNs%LoEXwT#_ZNC*h%pIzO6GC%GgfJktXxrIpAJP56Tztn&=mybHpcy9Yv*AC>FVnme%$4E z&?d(?cjb?lC`UZH80%{T#2hCLyTvV8v$j? z@3tR-mb(<=`Rs>L8i$eQ4CZR`Ccjk)sP&H zZAsJ{{;7%GDMha4g-B|>N4L>zfEQ{LT>cEm47~-fnV{mej&+e5g@zLiASF}dQN}w* z$h>LeN?xUB=_3ng$n$i}gM2LHZVqE$FI6DjuKEdkwy!|*^!u&V`J0@rpwbKc3b4YL z@Cv>=O7LngwR=Cw^3dpY4M!oB*a`A+(r(5_zJmcH3p==6yBho97%wFcAb-{xhEqng zaJhDZOZFpVV@BTs)htaJA$8g-e(>mjR?ocWvuS~vk`44oJM*@c?MKPRDmY<8l$dL8 zqnNel7PZ4#THv@eJ(yvR6Z|-3z$MMDDkjfg@j*s4fEO z=HPblVy+`(Uvbro5F1NG64Z4YXe>5zluLf$LCPmd=5Xx>T4ha)%ort;0+ZLK!;FsTNPEnq~IcXe?Ro{H{;?PcRrf%f|_ z578#BU6MB|6?4B*HOJponrwCA>_lN5X)!|A$`>BBpRz7ErZgyGG4f4JW3(U#-mp>Q zOh{5AS(*fP2DyK}hAbasv!us3ap1w$Tc=|@k?GY1Tqj~an!e?T!3x?(EgYV~J?!k9 zHd9s5?|Gi;bfA`(==RUb)+!?u6&1VbzAOm03zj?ymuec=fz&__0K=_^F9f6|hE-MN zMN=N#ioi-W9yg0vcX7oJwlcdvyLo z*J`pH%4joemhC~(6EwcqQ*v=|FXi%4l4#6gC@t)Xf5!aR1@pxcQA}Ngpq>L9nb2)J z-GCxaMG;dUd!EiLa8wa^4XIpH5tmKd!;xgPxk#WV&qP*-CNN-qB3ybmH@*1pJcbl> zBfO82A{-?Pcj&YaChB=`)u`L6{lL#2-17 zLO$d!58Y`wS_b3kd(FGsOh^vA26%v13bYG&R4xOJ$9KHIYV2WB)c|EujpWaTc6pMwu2Prk0>&ELm$ci9YccDhwFrCA znL}B-8IRagU6X=veWlo9x+@sR+UrZx!+qC_k$D{plYIARmPyFimY^twEPoz-P1{r5 z-4}1e15^6eYy1?4C)oWyQ&&*fZoFXn0sa)hkE(w(4nOJCVI5kjL&8|oZy6jQ3ISAGl1|0PSI*^~Og!#jImi&Qfn6l`8Rg_Y2JIirIvO*9s_^km%&)@VhXD zxoLi7s255S{b+wf3{2ptj1p-Lv4Hz04w9KBuL&WF+;UUemfl}YMY~#=IORF4XJ;3< zyh3XPOInLznqE)!G)+&(4$~IU)4$Rd18kck?#C2_Wl##sxqifKaWgNrz#~laYdob% zd&6?aD8SV&k)&Wrp*EHx7J(Aj&5&S&BK72n^ zuH`fD)Qjhc6!;Aq{c7uHE`vo(R^AcS*bdQxq|n>Qt2a`Of`j=jhRo7~pZiPwlMGj~ z%eaNync?6dmY~+~Qd2IE%!fEy2b9X2~f0A1hP&rl`U>cozd*8nWR_O0@>$uz-ghV(d@3BdmJm6o!DIFvK; zszbY&#&iF)EaiRlG;!3r)B@(uV*yqt9PAvn;H$j2;p)p!flY25T)kuxffB!76RuO( zM!oEqutfEKg>{Xp*UV}Iew`U3Uv0fLA;~vCEhr|s9mMr{t$4iD+oB`WWGCQkbdfW^ zf@B1m8fdTn)h%Tyc5Ye*ue2=P3w4`OV#kro^>ee}H9|=bWeK?GA`gD8OK4J{JsHfk zIUbjR(-lI`tnBsW8`-3)AgQmASK+v#2GLfM&;&FKZV{?+E9JwI;PunB+9AVxI2Tz0 zQ{VSg&(5^vvK z4o2T$)my5^XE!t4vQA_Lu_^y9QGg&_we$LlT8!oFu%B(P6;gHv#WK5c@+<+BUKrH> zbV_TGP3Wud+kx%qGi>IfzE%n!^f1ktzOqhn8-KXbU@%Ybk>fQfsqv76Waocfov#$z ze6gCd9BwP&1j#NOsP353y3L{Z)q|Iu$9yf-kmzC{nYan?Z-}gCYFsi7unW$i6h5Uu zLMy)Pw*R?jS%LMoiR4#nm#sMS#uJn7A+v>78?$dA`B6{)=GAUJNpb-=9p4j>Nn z_%LlhxQ+D~Ze9Y8=_F6fg!3sXtD9;`dZ@m2`>{(W#5t+6fGmlfP40cY3naTCC4tGhev?s3g5|;ms!O-DCM~<55AufaiyyLlUUq=I<#UpHE`4 z6Zv%RT!Pt%qbj-d3F%X1ID+$C4rR0bO(9+<>T+Lli2~=s7O}5QyhqbMO3ZXDC%V@NG(~$7F1tq&J$^Epo#X-$a2JS}A!3 zhaQ;;*3B0Oj>_7K4Zl;I*%u7Wt%$_ZG6E%6T&!R=`-mA7Z1C&o(}QXV;1W%KirlxI zllqh2MZ1l8r^%MJAim&Va^1$0fj`t2^43o;M4xz4VR$L#bxXZ=e10eh=mXD^OO#Z< zrI(NMtQ=O0GkbhA5LNp?6w+DeBqlZji? ze`FNg?U;mn+&rDz5?&Q%fSlCUAPjz3a0-x&QKWR9TMM~!mxL9`;Ap$pd0 z6Q0V)=SduMzuU}^k(^P#39B-J>qW$&Y6lMHD?4&>Ysn*sgIQyi_HGHaZqNr;*ko@Y zZ$s9%cWbHiB!!s9gKE6T%0eua%02^SojKI_d3fnuswnh%ksQPL{s!F^)SuoUgF2Tt zR@a1Xr6ha;jr6WUtyfLsxa81^L9<)XJWvU(7_F z72I#p78E?NO8n5njsA^a%s<3@F4gZp@y?}QolRfo>G65+Z>7%?@Amj4-}twma-vjz zzS+#b6lqqge_~DU*jJT^?_ozuk?vP`80s>NHsB8+dndQ!T?rhCUqxKGDWwOut3>*P zPAzZR2XI%N(T&}erbfCjkCKC7)!|RY0|4%9YETes7Bs^I!RH zz-1KgA77Zp*!Xg&_3M;H;lWs#KmC21J2RYir1`>TOT@nQ(+=Cu&`s%ukelL_4eK?6 z61DBYuIY+9rxnz!({9;+F{6)bWK#CO4E3 zDtCC%8(2el*Xzb}gQMCgZl$%fEEglzn9wvYjI?_U3sXAq`azHaFQW)}#`=hO5coDs z5nYro3e=C;<^jq#0vjERcH2Jygqtx?}Y7Nks!k0JP zchjZzBf`WhVR!+)w3qOdcg8O&6-(qkvabMf^y$g)BfCp z2Ase*ZKU}4=Q`-@pL2~aw0@)FpN8_23)I8ggM!^E*xRofG@LNmc}r06z`a(OQbbO? z9EjZcK+GbzNM60+c`3gHm9o=5M^m7-fq_R|V_>qg)f&pxTGZblpIb<_0&#eyd(oqG zbk%u4SlsbA$v_vk{U%ou!MsAUQXp|^4PL;9(l+f2-OwH=R+mn8bOa%^{6cMg8=P2U zBOzDfLj&I3jtVOv_U6}Y`xtWLuTvEuB-V@trorq2d)uhcR(#=IohRg;fxQ=*)Or^4 zz3b*7W2FfBPc@X>#Vt$=@x&_^zEiEeD@H$Nhw9Y4y!T5v_5B_43dcD7f9ndYMB(9`c(ABr~ zcz$YYtriwbMWCBl&ReP7|4{hHu|I%Kqr=nFKLM>^uEg3^v@4@^T`!v(8Ifn7@1WDH zP2@YYptL1WefP>bnkTU~H5fbMnYS%**mO5I(|Ec>KCfP0@Rd8ZX8TbhllTBq2+_At z?(=OtHz6fY+QI%AN|7uDr?DSIF*4>^5Xoz>SVObpB)B<{!xzONT>g!!-}e9l#)+KZ za4f7$%|`H$Hw;SA)As{Nzet-$%(Px5&u^|R!5C#kPc zb4VD^kFfwxb4{b$%A|(@_O(F%1i6_{ZC2%IslzeEm1nQ_vS7$8x$~X)wA%>|MY|wx z0_7FN8R=l_5`4w3kK=m-g%EdM<*P8L++yY4nfM}Z_b=Cw zw9~duqvQvCb(55PI)(p3_zRO%AMNCa#!VQ|$kd5s?1;7h$VN zOFbuS%{NkAhI9=ARXMs$s*maG2eZ{_NdHlDe|O!&J<$OXfoZ>QT`9`Tho9gZsa&Ln zgA%PcyQ{(&L&rPdJZuQ?-ZuGAZ=!cd%J_JrLPt2vtmdv8S@e?=z<7{5KDBWPI`KEO6$#<<7 sQ^DVkm8;MKI$4FXoE@`wh%J(RIPRp`1Y92cM>}A6)-vs!PMiTumx1;=EdT&uxOZ2}h}15VjxK6S z(wQg1eU{WTzc6{^qvha@@OtLq^UVD@01%K}oce{fM~3y~`eKQ4gG*Y!n&l3^a+*V^`d_4_b5zh$CQiSOo;Y^x zft-$0GU#|2hwLWH-6*Iyw7Gjtc-Fd+3UU9=pZjN5G@s^iq3~dj=%tYw!E9dFk}i%X z{5WKDfH#wd?q$t~oY#Y{w@tO!&hukAKKTl`-7FUQK(1{yL1$T+;>|?Zbprr+t?p@Q zm;_{R=Y*xQuDu&T?mpOM`k}4GSF`n+*+e0rm)jx^^zH6dX-Xv*?Lv*YcFWCgbu!&7 z77|~dOI@kFx!rMZKH>H~N6q00VU`wx_144(#@Rp}2F| z$$I(Q=a}uC=Cfx_X!kdLD!Y)~^*{cEcmBC2e|BQX3~cjrb9tX0wLOu1RMVA;5U%!X zS$ol_$vRuc6Y9CWMI8^BFLM1+Lk6gEo)!aymrHe3HYc+%5=PxaqqGw)I1_OIKyJV) z4WMgz*~UU`!tbr8;vanBRt;u;e`&sZc>1WD3Jd@^J3Fh+tz>-OClCnq@byN_&!Ao3 zzGxiHK^oaL<$!qo3~m763|+>juOv`hx>H#W$Ta0 z$<63Pva>VzxA#_~t+$x}M8mfBCTS|SsC#I%4-o_%H&L7>te@>!%*3O4!5rx39_tqCEe{lKUMe2`J3Le+kL4BEuf_AuRlit|J4$}1E78x@AQLdBUh3~O z+6M`Y9MOlIwMRNem0h9pD}6Lkk0Z3_Z+NZw+vzgHMBc;qSxj)A@^f1!^_~(NYP0T; ztri$ePxwCsf9P}6FW;tGEQ&$7?O?j%kcc1*K@F0B1Z7> zc^PLqhFW zaO|?tzHfWJrK|p`>fzu)`@S4pYmFK9ZGz*lIMBr&#Ks~ zs97sI=Q()n5k1nFxdTCPh@lqtX{Osu6dz(tgR8*)ceN^t#w}qJGuYi$@-v5+taQ1r zphp=zp(+JnahaQHGZU>}wqEAj$pHGeC)@h7CS(WIAYv_;T*+aq)8muzVdj6pIs;GM zo6D!q;+Oxi&do!^)}z(~mXr&Yf|W@y8ScMnM7xmDCTVO(I-^;axOT`XscMh45}tl? zCy^JkBezw597F-R@=dpI-|KE~@E&)y74P`y-*!@!Z!CC^xB7!>eqL~$)i|Fqv#O=q zcFii`9h0wD2mki+3PBcZ-C`2_-O2#z2ma!rP4bns+JXD@LUNqDf|LjHobHWuoLX|$ zta-ugQ*PjDOA;1-mS40MR$^G%@LNQfM$1~fo<_i0j2(MM^FxK%AsSILn+d;IpB_Fl zn`*x+E767cE3=Vi*SiknvNg*O#$f8p>HUK85w&j6|{{O4~-!Sp4uFd-gDKNQ$5*knmEH7#`i&#khuP@wC zrzxl;0tMO!%BgLot_>Ci*l&jW6%qiYFm*AiA_95g1$iD6FZ$; zGfh=go^sa;ELTpnqyL(9`KW6tMyU(b=j#&VR7DLb-4rmIjY;H3y0V*0#Rz<-iK<8u zj>q;fmJ?#9a5p{&PB5GIubesg;Vf z-)W#++q;x}tN>wftyW+tSd;2XM~JeC@1KqzE9-+BMam-6wCbi{xy@i>sw*RQ6o(h2 zKCQWxH`p1*3Cj|{(>`B>?$oKQcnNhK)RI%FixA*oSx5-az+ElFYF0gNiBAkeADr#k zoh8^4-G-Yr$VPUfXxpHcX`Eic)*Sh@E~&wvZLlbB zn?1LJmiMgKrrvp{-tVWCHkL!>6QuV3g!PKrY!Z(~b|UPzKsD*51Kpb<8#AC%@9_zdfg*n4a&&0Mie`xoI z)t+l(Rc*#`EAflrSPZCD3r8l3{YxqFXZ2&5EsW=reI*}vk>6yZr_Fxop*$*|HgdyH zeAz!%s7Mfmh5?N~@l|ZailGg8nLXHaW50;bHYK<~v^=%vH4Jm^DUhDh5CdrgkB`D0 zkBd^1SPJ>eGM}GD6ciu8Vff2?oh<56L@zq2%Q5ECUtn+U#(QjUa_P<;qeGrGGBU^Z zd{s=`GAU~BihGU(Xu#tH>Z-whT1mSbq3YFC%NL(4tC|CwP$^xDNh}0^$;`wxlt$!Kkj%%CX zfc3BOzz?F<*m-2iadSOA(rpz4z zZ$Z(g=Ulhl86RCFdKc zbtzK-)SK_P*N9BFLJUTLM*H^_Rkxa82z<+Ptlay9OWR!e3!oCGuh&@KrK}@S+dOtn zUyn`YZH}vUS2mWHxW@RANBy7RS<#*V2*I z?QBzZNamN@gS}J1)lZhqs$2ikfXT8XRT%oEJxBJdGJ84MSDtsOYvo42md*q(EYvn{ zz2wV_t1Ss(lG<&_PDD@r)cO~*xoOF%6znIdk2f#>05?wOprIF->Njf)w-1BH3K6?! zMB?p%;e%JXcumZNXL)8`SR|>lvfupu?5*@^-6uc3Fo#_y8e2R`C3fy~+VQ5w!^P@V zS@oBCzI!gsI4G=Ljy8TfMYm~4AOkz(FM9si;W6LXR1#|>@Japm3rN1TVWl3=s{R)L ze$h4JFmV{t`HN~;c!^?-!Q*3Z^NS@{iK|?Y*ZQce_WT>GS@HgKi(8HPByiAN@SVt4 z(e8pJ;y%p61-}y3SS;x_zl=GpCbaOQhJN!^QKto;U|6i^HapxD4s&v^z@&>=Laym` zDu-71TUBoZ3X5xx{kHnHeCr2Kv-~Y#|4C>@a%z5Y%Aw(x`3Akadj8YP z^xn3g^+e*AUGrZIxA%>~sJ4QAB1uZ1K+Q?j3|Mp+ zXta0VAv31#^OI8WtecgN@db}L1mkkT6u&xF=G#BJ17_{3mQwbPW3o7CJfr%jUwDCn zL50FYcCXS}={jn#r2}(6w1!v+)MJv zh9s{4=UB%#uFrA)x+j8PB^3{e&LK@Td!t2{q>(<}*X}|k^T_H{EjaK-6RBlD%Ho+B zvxcT7wqc)#xvH&&_E|!eqg!xZ(gi0KBX?KBv&p@FE_YV9)ZoFAWpOJjD+iv)s+8j% zI%$sUe@tL#dB<7?rta$F^6B z^YIM5!CwmdnTCn=RaH``y!@xIsh=0vRdlg<{-=i@I-lZ0&rgfRZ8SCU4T9I=;%BuQ zgs;({E|h)-Am%Qa7#M69l@Fa;pD(~eaHfMC`$IEqPg-Wqn6eGfEO!US4kZ zTzfAlC@Af&;Q0Lf<1KT7MH?q_%8a+O3`qVPW^eX$IEe*%I3iCEfJ(&KVx7Ysb47Qt z=4Y9bPo`LeVJ4O=w7-zuiPr2BPz41O%ecVPKR#_EY3IvWPQr>fy;if3c7zkVIA~UigLOrMZY1>CMhW?qCa1U zD04~9%oFA8)(0|3f0tfyxo5NQj(Otu!oUn%*}EUmUt;ps&LB-T)2jWLA^WbNJ-r@B zRND}c9FP6kp!)Qppy)P$t>qg~$09>kgb6)*sv680)%mQ0&N(kqCRB1a8lDE*Fp#56 zdQQKo%;a?PAd!Kq0`0C8Iwgo0cN)mAA{9tDdD(!U)s4DVBs0IiX4G%hSWrnUdK35i z^L=DXF{=4X=@ISim1t=YbdV!MigIlTSmko65PsmJwI;Q3_wu-n6QFbO$`5mY;$DA# zgRF=-uZP=eW!+_SWs2Eqfa?Fb|L;^%PUcyQ=NVp~ME-YqsnQ1;cmFZWKp2>x01vhz z^@KB44W|$W1A*%8R^vEqCAu067n_fNLBA=+MEz(t@}L8*CniytsA09l(d=e^J zCKD(3cUu=8{l0*MKh$Sd<7sD9_YYrvrz!3c+2qI&XKMMKb6FKIS_gd`huKe*zNvk4 zlcS+f<(hBEEzvTOGE&`4Ah;SC8KxBg$&YYzMMZ^tq_TJeTYv9flAnbNpE^A6p`Nos zLWima0)gmb+XkK_S$_AvAO_A!E$F&IT-@ADKU(HJJh++H0L`}$E_sbxk&=Sqh{lH~ zxl3)T4BSd#->kSZv1UY#WGmSpZdfrUgnz9+=y0jD2E8>R(#{G-a$TH`7_8@?3)Q>Z0F*JurF7K1s~tjT#3TaB)xzQI3ZJ zjVb`eAm=iC@wv!vv}>>$7PG&%lsJZxu1vj8upF-$0BBSIY=0jnkD+F_vSc6K&85?` z65yg9qkYiLv_O3FB}}2;h93``7q{yY=>>#V1FTOC--d;7Nvo9-!tKW>iWA97%>m9( zK15Bz7ij+adZbZ5;4yFV3yS>T!yJi1l;WenbX9g%>M(lsFXRS?ih~>vEZZj!^`#5O zC>Vn1yC9uepa6xvoQ7cz*J%9<(w@SA&kC){O7Z*)4)mGp>1yl^M@q`t^nk=%&<}>Z z7Z)FSqYTy9O*UwiA0xsOUaCD_NAHqecf5QhMfjvBsV8ZfXW#%iO8HFE4l|5O5rFf? zRO|i{YqG_?vUPB*AAOV0AEQYO-JOcYM$;UKf7MD(yQZdq|IzzC!1G-W-s{)JRKj`C z&J?la;63*XuItyw$Hxu)vWvw#!2Z!LZgE=V_p_uLMNZ@i+MRUQGeI^AL~@UzELn~( zLw4%%9N{n68J9_!F;W^)vk`apoLV3*mQ3mus7s$DGu_*iAI;?@_!kR zg-s!3oNGy64vm0Ku5*R&L%66K$qf!Z=29iJ(I?bj5#0oZw^>!GPq4YTx|*OY)gCqt zA5SbwVS##3QDjvWD$Y&UR}{woaTVB+bUQ0?_6&7AVrgrnDThnf(P}T`fOdV zsbH8KRM!t@kX6tHc^-bG1Q4DfjRjuYhq&)(VYw#Oo{S>jo*4}@?!3~>hal1Jal2lQTapi%F;)A zoT-Is$NJ-u90=Fh@ix~Wki2_FH|StcIN?&iTR$WC%sKcxxftG_Pok_6+cQw|Hf)sa zXYgUzMC)EkOX|~Das2c^642*~a`<~&4z97)6?C#Pppmr_3QzS1{+C~UaCklZT6+yX z=U$uD_hr1Kq-4?IN`HzPw9AYrpt}8`DPLsMzgw!bzgU>eyt3< z+&BmMhV+Ug5JT0~t?BNS$xM;@qNii2ve66%oKb5ad-|gDD@o;T?d_(OIvsQJZi$Q?(96>YDSKRoGfb` zCrO8L@!t!1CpLpb#uK zdQzEUSrB%tm|r0J3PFF``%c~|TNWt%Et^byF~Wc)p+N0jZ-y))_1n|?9W8wQGTDRb z4)j?fwBK7TgM!-Q-#_98GnObZl}vJ!ryyP=zd6)T+AC4)+e=pN^idZj(0)O+a&PLH z{j^McSM`D(U;=76`cAy8PfI4<7cw#DLe}nez7ObFbr22)yzTC;wm?_q!Vd*L_1g9M zy_8+f<3%)L7ZN)E`7Q>sP`q`^Zl=NlbomF4{Qcg=b>aTm+oaEpWa{o1R?EOOc!A#l z<5t`Dtp{6J%?ht=5iu%IqHIUdsm!XPqVfR&8=J%#<>B40F%#QRi@E`^-dU`nHQN^hWphnc#BX~j;$6{_x(`y%AJ_Is|Z-Uw# z#+?8PYNKvG}&x@HWojVs%de;*XIdzpUbJv#c;LGG&qM;)rGBJdCZC~oEm z_PPj`p*+fgt+Z`AD~x8xVWIeY#M7NH-QUAhH3Y!kOX=$Vci>B!mZwcGDOLq}4C0B8 zm)*gt(RtR2ba4@6MN;kb5+BJuF{ZH*D~}{zu{eIq_w2b+>Kv;5fSx}87O!rY+{^N} zf%KUYy*4G3R96x7V&TZnH8$d}_+ihZH*kT*Wg$yHoZ_beRv-!jSZ!>48-|aRG!k0R!cPcw{#Dt5X7`((%u}6!K9jWPg!(Pskp{E#&!6ZDiy=d3c%pqZXlw=^8j>I~OU;z=lY zz4W=j=aWvHxN_E@jhF9j#+&Ki$%>t@@-yt#BV}S2*zp?*(-${A@>**-i#!H#NQ4^l z(xP`PlymUU!%|+A7+0aF08`NGKMMV#v_|E$Yza5A2KhdT7yLazsBLenR&xa|-6832mdVuQC(gKQiIo`^x2%rU3Se8bJ7atbaYu z4cV0$K{f@;iKiPB{N^C1EzEuRRmgAaOzlpHsp%YT05n}Audv4Z9sN^ihfY2kPf=o}{mWc%10*4sYvHY4gw5OpD*_Aia{s&Q+ZAWPD}MlT$wmg z++1CBQOkzfqF5c=~^PP4QlH7YQa2L z>!f-3baSTi$=rKImnHq$vLc|4rETdLhr>Op3{r-9D@y$QOZv!&x901wHzHB2c4C@l zN;-y5!v<0>yPu5<2mFo8c&#gU{+fsKM@AB9Uz6E+z8cXxl>BNWTB?&=7Cto8uU)cb_OmAU8PK@aeW}?D5!42JXg+xSN|>9n>azAwq9GV7XIab8}MyEnR+llMrTN Xu^(c^!5TvPR}Q$R4b!T+V-xv5f)3`a