Adds the Ninja MODsuit (#67220)
Why It's Good For The Game Ninja code is pretty bad, I think it's best to move away into nice modular stuff instead. Changelog cl Fikou, PositiveEntropy, Nerevar, InfraRedBaron refactor: the ninja space suit is now a modsuit fix: fixes dash beams not working /cl
@@ -196,6 +196,9 @@ GLOBAL_LIST_INIT(ai_employers, list(
|
||||
/// Checks if the given mob is a nuclear operative
|
||||
#define IS_NUKE_OP(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/nukeop))
|
||||
|
||||
//Tells whether or not someone is a space ninja
|
||||
#define IS_SPACE_NINJA(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/ninja))
|
||||
|
||||
/// Checks if the given mob is a heretic.
|
||||
#define IS_HERETIC(mob) (mob.mind?.has_antag_datum(/datum/antagonist/heretic))
|
||||
/// Check if the given mob is a heretic monster.
|
||||
|
||||
@@ -57,3 +57,5 @@
|
||||
#define CULT_SHUTTLE_CURSE "cult_shuttle_curse.json"
|
||||
/// File location for eigenstasium lines
|
||||
#define EIGENSTASIUM_FILE "eigenstasium.json"
|
||||
/// File location for ninja lines
|
||||
#define NINJA_FILE "ninja.json"
|
||||
|
||||
@@ -367,11 +367,9 @@ GLOBAL_LIST_INIT(phobia_objs, list(
|
||||
)),
|
||||
|
||||
"anime" = typecacheof(list(
|
||||
/obj/item/clothing/gloves/space_ninja,
|
||||
/obj/item/clothing/head/kitty/genuine,
|
||||
/obj/item/clothing/mask/gas/space_ninja,
|
||||
/obj/item/clothing/shoes/space_ninja,
|
||||
/obj/item/clothing/suit/space/space_ninja,
|
||||
/obj/item/clothing/mask/gas/ninja,
|
||||
/obj/item/clothing/under/syndicate/ninja,
|
||||
/obj/item/clothing/under/costume/schoolgirl,
|
||||
/obj/item/energy_katana,
|
||||
/obj/item/food/chawanmushi,
|
||||
@@ -428,27 +426,6 @@ GLOBAL_LIST_INIT(phobia_objs, list(
|
||||
/obj/structure/beebox,
|
||||
)),
|
||||
|
||||
"anime" = typecacheof(list(
|
||||
/obj/item/clothing/gloves/space_ninja,
|
||||
/obj/item/clothing/head/kitty/genuine,
|
||||
/obj/item/clothing/mask/gas/space_ninja,
|
||||
/obj/item/clothing/shoes/space_ninja,
|
||||
/obj/item/clothing/suit/space/space_ninja,
|
||||
/obj/item/clothing/under/costume/schoolgirl,
|
||||
/obj/item/energy_katana,
|
||||
/obj/item/food/chawanmushi,
|
||||
/obj/item/food/sashimi,
|
||||
/obj/item/highfrequencyblade,
|
||||
/obj/item/katana,
|
||||
/obj/item/nullrod/claymore/katana,
|
||||
/obj/item/nullrod/scythe/vibro,
|
||||
/obj/item/reagent_containers/food/drinks/bottle/sake,
|
||||
/obj/item/throwing_star,
|
||||
/obj/item/toy/katana,
|
||||
/obj/structure/mineral_door/paperframe,
|
||||
/obj/structure/window/paperframe,
|
||||
)),
|
||||
|
||||
"blood" = typecacheof(list(
|
||||
/obj/effect/decal/cleanable/blood,
|
||||
/obj/item/reagent_containers/blood,
|
||||
|
||||
@@ -29,12 +29,6 @@
|
||||
to_chat(src, span_notice("You look at your arm and sigh."))
|
||||
return
|
||||
|
||||
// Special glove functions:
|
||||
// If the gloves do anything, have them return 1 to stop
|
||||
// normal attack_hand() here.
|
||||
var/obj/item/clothing/gloves/G = gloves // not typecast specifically enough in defines
|
||||
if(proximity_flag && istype(G) && G.Touch(A,1,modifiers))
|
||||
return
|
||||
//This signal is needed to prevent gloves of the north star + hulk.
|
||||
if(SEND_SIGNAL(src, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, A, proximity_flag, modifiers) & COMPONENT_CANCEL_ATTACK_CHAIN)
|
||||
return
|
||||
@@ -114,10 +108,6 @@
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(gloves)
|
||||
var/obj/item/clothing/gloves/G = gloves
|
||||
if(istype(G) && G.Touch(A,0,modifiers)) // for magic gloves
|
||||
return TRUE
|
||||
|
||||
if(isturf(A) && get_dist(src,A) <= 1)
|
||||
Move_Pulled(A)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
var/dash_sound = 'sound/magic/blink.ogg'
|
||||
var/recharge_sound = 'sound/magic/charge.ogg'
|
||||
var/beam_effect = "blur"
|
||||
var/beam_length = 2 SECONDS
|
||||
var/phasein = /obj/effect/temp_visual/dir_setting/ninja/phase
|
||||
var/phaseout = /obj/effect/temp_visual/dir_setting/ninja/phase/out
|
||||
|
||||
@@ -33,18 +34,19 @@
|
||||
/// Teleports user to target using do_teleport. Returns TRUE if teleport successful, FALSE otherwise.
|
||||
/datum/action/innate/dash/proc/teleport(mob/user, atom/target)
|
||||
if(!IsAvailable())
|
||||
user.balloon_alert(user, "no charges!")
|
||||
return FALSE
|
||||
|
||||
var/turf/current_turf = get_turf(user)
|
||||
var/turf/target_turf = get_turf(target)
|
||||
if(target in view(user.client.view, user))
|
||||
if(!do_teleport(user, target_turf, no_effects = TRUE))
|
||||
user.balloon_alert(user, "dash blocked by location!")
|
||||
return FALSE
|
||||
|
||||
var/obj/spot1 = new phaseout(get_turf(user), user.dir)
|
||||
var/obj/spot1 = new phaseout(current_turf, user.dir)
|
||||
var/obj/spot2 = new phasein(target_turf, user.dir)
|
||||
spot1.Beam(spot2,beam_effect, time = beam_length)
|
||||
playsound(target_turf, dash_sound, 25, TRUE)
|
||||
var/obj/spot2 = new phasein(get_turf(user), user.dir)
|
||||
spot1.Beam(spot2,beam_effect,time=2 SECONDS)
|
||||
current_charges--
|
||||
owner.update_action_buttons_icon()
|
||||
addtimer(CALLBACK(src, .proc/charge), charge_rate)
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
to_chat(M, span_warning("[source.p_their()] skin seems to be shifting like something is moving below it."))
|
||||
|
||||
/datum/element/digitalcamo/proc/can_track(datum/source)
|
||||
/datum/element/digitalcamo/proc/can_track(datum/source, mob/user)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
return COMPONENT_CANT_TRACK
|
||||
|
||||
@@ -707,29 +707,31 @@ GLOBAL_DATUM_INIT(fire_overlay, /mutable_appearance, mutable_appearance('icons/e
|
||||
do_drop_animation(location)
|
||||
|
||||
/obj/item/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
|
||||
if(hit_atom && !QDELETED(hit_atom))
|
||||
SEND_SIGNAL(src, COMSIG_MOVABLE_IMPACT, hit_atom, throwingdatum)
|
||||
if(get_temperature() && isliving(hit_atom))
|
||||
var/mob/living/L = hit_atom
|
||||
L.ignite_mob()
|
||||
var/itempush = 1
|
||||
if(w_class < 4)
|
||||
itempush = 0 //too light to push anything
|
||||
if(istype(hit_atom, /mob/living)) //Living mobs handle hit sounds differently.
|
||||
var/volume = get_volume_by_throwforce_and_or_w_class()
|
||||
if (throwforce > 0)
|
||||
if (mob_throw_hit_sound)
|
||||
playsound(hit_atom, mob_throw_hit_sound, volume, TRUE, -1)
|
||||
else if(hitsound)
|
||||
playsound(hit_atom, hitsound, volume, TRUE, -1)
|
||||
else
|
||||
playsound(hit_atom, 'sound/weapons/genhit.ogg',volume, TRUE, -1)
|
||||
if(QDELETED(hit_atom))
|
||||
return
|
||||
if(SEND_SIGNAL(src, COMSIG_MOVABLE_IMPACT, hit_atom, throwingdatum) & COMPONENT_MOVABLE_IMPACT_NEVERMIND)
|
||||
return
|
||||
if(get_temperature() && isliving(hit_atom))
|
||||
var/mob/living/L = hit_atom
|
||||
L.ignite_mob()
|
||||
var/itempush = 1
|
||||
if(w_class < 4)
|
||||
itempush = 0 //too light to push anything
|
||||
if(istype(hit_atom, /mob/living)) //Living mobs handle hit sounds differently.
|
||||
var/volume = get_volume_by_throwforce_and_or_w_class()
|
||||
if (throwforce > 0)
|
||||
if (mob_throw_hit_sound)
|
||||
playsound(hit_atom, mob_throw_hit_sound, volume, TRUE, -1)
|
||||
else if(hitsound)
|
||||
playsound(hit_atom, hitsound, volume, TRUE, -1)
|
||||
else
|
||||
playsound(hit_atom, 'sound/weapons/throwtap.ogg', 1, volume, -1)
|
||||
|
||||
playsound(hit_atom, 'sound/weapons/genhit.ogg',volume, TRUE, -1)
|
||||
else
|
||||
playsound(src, drop_sound, YEET_SOUND_VOLUME, ignore_walls = FALSE)
|
||||
return hit_atom.hitby(src, 0, itempush, throwingdatum=throwingdatum)
|
||||
playsound(hit_atom, 'sound/weapons/throwtap.ogg', 1, volume, -1)
|
||||
|
||||
else
|
||||
playsound(src, drop_sound, YEET_SOUND_VOLUME, ignore_walls = FALSE)
|
||||
return hit_atom.hitby(src, 0, itempush, throwingdatum=throwingdatum)
|
||||
|
||||
/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, gentle = FALSE, quickstart = TRUE)
|
||||
if(HAS_TRAIT(src, TRAIT_NODROP))
|
||||
|
||||
@@ -733,9 +733,24 @@ Congratulations! You are now trained for invasive xenobiology research!"}
|
||||
desc = "Abduct with style - spiky style. Prevents digital tracking."
|
||||
icon_state = "alienhelmet"
|
||||
inhand_icon_state = "alienhelmet"
|
||||
blockTracking = TRUE
|
||||
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT
|
||||
|
||||
/obj/item/clothing/head/helmet/abductor/equipped(mob/living/user, slot)
|
||||
. = ..()
|
||||
if(slot_flags & slot)
|
||||
RegisterSignal(user, COMSIG_LIVING_CAN_TRACK, .proc/can_track)
|
||||
else
|
||||
UnregisterSignal(user, COMSIG_LIVING_CAN_TRACK)
|
||||
|
||||
/obj/item/clothing/head/helmet/abductor/dropped(mob/living/user)
|
||||
. = ..()
|
||||
UnregisterSignal(user, COMSIG_LIVING_CAN_TRACK)
|
||||
|
||||
/obj/item/clothing/head/helmet/abductor/proc/can_track(datum/source, mob/user)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
return COMPONENT_CANT_TRACK
|
||||
|
||||
// Operating Table / Beds / Lockers
|
||||
|
||||
/obj/structure/bed/abductor
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
/datum/outfit/clown_operative
|
||||
name = "Clown Operative (Preview only)"
|
||||
|
||||
back = /obj/item/mod/control/pre_equipped/syndicate_empty/honkerative
|
||||
back = /obj/item/mod/control/pre_equipped/empty/syndicate/honkerative
|
||||
uniform = /obj/item/clothing/under/syndicate
|
||||
|
||||
/datum/outfit/clown_operative/post_equip(mob/living/carbon/human/H, visualsOnly)
|
||||
@@ -79,7 +79,7 @@
|
||||
/datum/outfit/clown_operative_elite
|
||||
name = "Clown Operative (Elite, Preview only)"
|
||||
|
||||
back = /obj/item/mod/control/pre_equipped/syndicate_empty/honkerative
|
||||
back = /obj/item/mod/control/pre_equipped/empty/syndicate/honkerative
|
||||
uniform = /obj/item/clothing/under/syndicate
|
||||
|
||||
/datum/outfit/clown_operative_elite/post_equip(mob/living/carbon/human/H, visualsOnly)
|
||||
|
||||
@@ -191,7 +191,7 @@
|
||||
/datum/outfit/nuclear_operative
|
||||
name = "Nuclear Operative (Preview only)"
|
||||
|
||||
back = /obj/item/mod/control/pre_equipped/syndicate_empty
|
||||
back = /obj/item/mod/control/pre_equipped/empty/syndicate
|
||||
uniform = /obj/item/clothing/under/syndicate
|
||||
|
||||
/datum/outfit/nuclear_operative/post_equip(mob/living/carbon/human/H, visualsOnly)
|
||||
@@ -202,7 +202,7 @@
|
||||
/datum/outfit/nuclear_operative_elite
|
||||
name = "Nuclear Operative (Elite, Preview only)"
|
||||
|
||||
back = /obj/item/mod/control/pre_equipped/syndicate_empty/elite
|
||||
back = /obj/item/mod/control/pre_equipped/empty/elite
|
||||
uniform = /obj/item/clothing/under/syndicate
|
||||
l_hand = /obj/item/modular_computer/tablet/nukeops
|
||||
r_hand = /obj/item/shield/energy
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
show_to_ghosts = TRUE
|
||||
antag_moodlet = /datum/mood_event/focused
|
||||
suicide_cry = "FOR THE SPIDER CLAN!!"
|
||||
preview_outfit = /datum/outfit/ninja
|
||||
preview_outfit = /datum/outfit/ninja_preview
|
||||
///Whether or not this ninja will obtain objectives
|
||||
var/give_objectives = TRUE
|
||||
///Whether or not this ninja receives the standard equipment
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
/datum/market_item/clothing/ninja_mask
|
||||
name = "Space Ninja Mask"
|
||||
desc = "Apart from being acid, lava, fireproof and being hard to take off someone it does nothing special on it's own."
|
||||
item = /obj/item/clothing/mask/gas/space_ninja
|
||||
item = /obj/item/clothing/mask/gas/ninja
|
||||
|
||||
price_min = CARGO_CRATE_VALUE
|
||||
price_max = CARGO_CRATE_VALUE * 2.5
|
||||
|
||||
@@ -41,10 +41,6 @@
|
||||
var/mob/M = loc
|
||||
M.update_inv_gloves()
|
||||
|
||||
// Called just before an attack_hand(), in mob/UnarmedAttack()
|
||||
/obj/item/clothing/gloves/proc/Touch(atom/A, proximity, mouseparams)
|
||||
return FALSE // return 1 to cancel attack_hand()
|
||||
|
||||
/obj/item/clothing/gloves/wirecutter_act(mob/living/user, obj/item/I)
|
||||
. = ..()
|
||||
if(!cut_type)
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
icon = 'icons/obj/clothing/hats.dmi'
|
||||
body_parts_covered = HEAD
|
||||
slot_flags = ITEM_SLOT_HEAD
|
||||
var/blockTracking = 0 //For AI tracking
|
||||
var/can_toggle = null
|
||||
|
||||
///Special throw_impact for hats to frisbee hats at people to place them on their heads/attempt to de-hat them.
|
||||
|
||||
@@ -418,6 +418,8 @@
|
||||
/datum/outfit/chrono_agent/post_equip(mob/living/carbon/human/agent, visualsOnly)
|
||||
. = ..()
|
||||
var/obj/item/mod/control/mod = agent.back
|
||||
if(!istype(mod))
|
||||
return
|
||||
var/obj/item/mod/module/eradication_lock/lock = locate(/obj/item/mod/module/eradication_lock) in mod.modules
|
||||
lock.true_owner_ckey = agent.ckey
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@
|
||||
var/turf/T = pick_n_take(empty_shuttle_turfs)
|
||||
|
||||
new /obj/effect/decal/remains/human(T)
|
||||
new /obj/item/clothing/shoes/space_ninja(T)
|
||||
new /obj/item/clothing/shoes/jackboots/fast(T)
|
||||
new /obj/item/clothing/mask/balaclava(T)
|
||||
|
||||
for(var/i in 1 to 5)
|
||||
|
||||
@@ -85,15 +85,6 @@
|
||||
return dna.species.handle_chemicals(R, src, delta_time, times_fired)
|
||||
// if it returns 0, it will run the usual on_mob_life for that reagent. otherwise, it will stop after running handle_chemicals for the species.
|
||||
|
||||
|
||||
/mob/living/carbon/human/can_track(mob/living/user)
|
||||
if(istype(head, /obj/item/clothing/head))
|
||||
var/obj/item/clothing/head/hat = head
|
||||
if(hat.blockTracking)
|
||||
return 0
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/can_use_guns(obj/item/G)
|
||||
. = ..()
|
||||
if(G.trigger_guard == TRIGGER_GUARD_NORMAL)
|
||||
|
||||
@@ -1130,7 +1130,7 @@
|
||||
|
||||
/mob/living/proc/can_track(mob/living/user)
|
||||
//basic fast checks go first. When overriding this proc, I recommend calling ..() at the end.
|
||||
if(SEND_SIGNAL(src, COMSIG_LIVING_CAN_TRACK, args) & COMPONENT_CANT_TRACK)
|
||||
if(SEND_SIGNAL(src, COMSIG_LIVING_CAN_TRACK, user) & COMPONENT_CANT_TRACK)
|
||||
return FALSE
|
||||
var/turf/T = get_turf(src)
|
||||
if(!T)
|
||||
|
||||
@@ -216,6 +216,7 @@
|
||||
. += span_notice("You could remove [ai] with an <b>intellicard</b>.")
|
||||
else
|
||||
. += span_notice("You could install an AI with an <b>intellicard</b>.")
|
||||
. += span_notice("<i>You could examine it more thoroughly...</i>")
|
||||
|
||||
/obj/item/mod/control/examine_more(mob/user)
|
||||
. = ..()
|
||||
@@ -507,7 +508,7 @@
|
||||
return
|
||||
var/module_reference = display_names[pick]
|
||||
var/obj/item/mod/module/picked_module = locate(module_reference) in modules
|
||||
if(!istype(picked_module) || user.incapacitated())
|
||||
if(!istype(picked_module))
|
||||
return
|
||||
picked_module.on_select()
|
||||
|
||||
@@ -592,6 +593,9 @@
|
||||
/obj/item/mod/control/proc/subtract_charge(amount)
|
||||
return core?.subtract_charge(amount) || FALSE
|
||||
|
||||
/obj/item/mod/control/proc/check_charge(amount)
|
||||
return core?.check_charge(amount) || FALSE
|
||||
|
||||
/obj/item/mod/control/proc/update_charge_alert()
|
||||
if(!wearer)
|
||||
return
|
||||
|
||||
@@ -38,6 +38,9 @@
|
||||
/obj/item/mod/core/proc/subtract_charge(amount)
|
||||
return FALSE
|
||||
|
||||
/obj/item/mod/core/proc/check_charge(amount)
|
||||
return FALSE
|
||||
|
||||
/obj/item/mod/core/proc/update_charge_alert()
|
||||
mod.wearer.clear_alert(ALERT_MODSUIT_CHARGE)
|
||||
|
||||
@@ -62,6 +65,9 @@
|
||||
/obj/item/mod/core/infinite/subtract_charge(amount)
|
||||
return TRUE
|
||||
|
||||
/obj/item/mod/core/infinite/check_charge(amount)
|
||||
return TRUE
|
||||
|
||||
/obj/item/mod/core/standard
|
||||
name = "MOD standard core"
|
||||
icon_state = "mod-core-standard"
|
||||
@@ -120,6 +126,9 @@
|
||||
return FALSE
|
||||
return charge_source.use(amount, TRUE)
|
||||
|
||||
/obj/item/mod/core/standard/check_charge(amount)
|
||||
return charge_amount() >= amount
|
||||
|
||||
/obj/item/mod/core/standard/update_charge_alert()
|
||||
var/obj/item/stock_parts/cell/charge_source = charge_source()
|
||||
if(!charge_source)
|
||||
@@ -260,6 +269,9 @@
|
||||
charge_source.adjust_charge(-amount*charge_modifier)
|
||||
return TRUE
|
||||
|
||||
/obj/item/mod/core/ethereal/check_charge(amount)
|
||||
return charge_amount() >= amount*charge_modifier
|
||||
|
||||
/obj/item/mod/core/ethereal/update_charge_alert()
|
||||
var/obj/item/organ/internal/stomach/ethereal/charge_source = charge_source()
|
||||
if(charge_source)
|
||||
@@ -309,6 +321,9 @@
|
||||
charge = max(0, charge - amount)
|
||||
return TRUE
|
||||
|
||||
/obj/item/mod/core/plasma/check_charge(amount)
|
||||
return charge_amount() >= amount
|
||||
|
||||
/obj/item/mod/core/plasma/update_charge_alert()
|
||||
var/remaining_plasma = charge_amount() / max_charge_amount()
|
||||
switch(remaining_plasma)
|
||||
|
||||
@@ -1012,6 +1012,61 @@
|
||||
),
|
||||
)
|
||||
|
||||
/datum/mod_theme/ninja
|
||||
name = "ninja"
|
||||
desc = "A unique, vacuum-proof suit of nano-enhanced armor designed specifically for Spider Clan assassins."
|
||||
extended_desc = "A suit of nano-enhanced armor designed specifically for Spider Clan assassin-saboteurs. \
|
||||
This MODsuit employs the cutting edge of stealth and combat technology, built skin-tight but just as durable as \
|
||||
suits two or three times as thick. The nanomachines making up the outermost layer of armor \
|
||||
are capable of shifting their form into almost-microscopic radiating fins, rendering the suit itself \
|
||||
nigh-immune to even volcanic heat. It's entirely sealed against even the strongest acids, \
|
||||
and the myoelectric artifical muscles of the suit leave it light as a feather during movement."
|
||||
default_skin = "ninja"
|
||||
armor = list(MELEE = 40, BULLET = 30, LASER = 20, ENERGY = 30, BOMB = 30, BIO = 100, FIRE = 100, ACID = 100, WOUND = 10)
|
||||
resistance_flags = LAVA_PROOF|FIRE_PROOF|ACID_PROOF
|
||||
charge_drain = DEFAULT_CHARGE_DRAIN * 0.5
|
||||
siemens_coefficient = 0
|
||||
slowdown_inactive = 0.5
|
||||
slowdown_active = 0
|
||||
ui_theme = "hackerman"
|
||||
inbuilt_modules = list(/obj/item/mod/module/welding/camera_vision, /obj/item/mod/module/hacker, /obj/item/mod/module/weapon_recall, /obj/item/mod/module/adrenaline_boost, /obj/item/mod/module/energy_net)
|
||||
allowed_suit_storage = list(
|
||||
/obj/item/flashlight,
|
||||
/obj/item/tank/internals,
|
||||
/obj/item/gun,
|
||||
/obj/item/ammo_box,
|
||||
/obj/item/ammo_casing,
|
||||
/obj/item/melee/baton,
|
||||
/obj/item/restraints/handcuffs,
|
||||
)
|
||||
skins = list(
|
||||
"ninja" = list(
|
||||
HELMET_FLAGS = list(
|
||||
UNSEALED_LAYER = null,
|
||||
UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL,
|
||||
SEALED_CLOTHING = STOPSPRESSUREDAMAGE,
|
||||
UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR,
|
||||
SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEYES|HIDEFACE|HIDESNOUT,
|
||||
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF,
|
||||
),
|
||||
CHESTPLATE_FLAGS = list(
|
||||
UNSEALED_CLOTHING = THICKMATERIAL,
|
||||
SEALED_CLOTHING = STOPSPRESSUREDAMAGE,
|
||||
SEALED_INVISIBILITY = HIDEJUMPSUIT,
|
||||
),
|
||||
GAUNTLETS_FLAGS = list(
|
||||
UNSEALED_CLOTHING = THICKMATERIAL,
|
||||
SEALED_CLOTHING = STOPSPRESSUREDAMAGE,
|
||||
CAN_OVERSLOT = TRUE,
|
||||
),
|
||||
BOOTS_FLAGS = list(
|
||||
UNSEALED_CLOTHING = THICKMATERIAL,
|
||||
SEALED_CLOTHING = STOPSPRESSUREDAMAGE,
|
||||
CAN_OVERSLOT = TRUE,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
/datum/mod_theme/prototype
|
||||
name = "prototype"
|
||||
desc = "A prototype modular suit powered by locomotives. While it is comfortable and has a big capacity, it remains very bulky and power-inefficient."
|
||||
|
||||
@@ -214,6 +214,18 @@
|
||||
/obj/item/mod/module/emp_shield/advanced,
|
||||
)
|
||||
|
||||
/obj/item/mod/control/pre_equipped/ninja
|
||||
theme = /datum/mod_theme/ninja
|
||||
applied_cell = /obj/item/stock_parts/cell/ninja
|
||||
initial_modules = list(
|
||||
/obj/item/mod/module/noslip,
|
||||
/obj/item/mod/module/stealth/ninja,
|
||||
/obj/item/mod/module/dispenser/ninja,
|
||||
/obj/item/mod/module/dna_lock/reinforced,
|
||||
/obj/item/mod/module/emp_shield/pulse,
|
||||
/obj/item/mod/module/status_readout,
|
||||
)
|
||||
|
||||
/obj/item/mod/control/pre_equipped/prototype
|
||||
theme = /datum/mod_theme/prototype
|
||||
req_access = list(ACCESS_AWAY_GENERAL)
|
||||
@@ -365,13 +377,18 @@
|
||||
)
|
||||
|
||||
//these exist for the prefs menu
|
||||
/obj/item/mod/control/pre_equipped/syndicate_empty
|
||||
/obj/item/mod/control/pre_equipped/empty
|
||||
|
||||
/obj/item/mod/control/pre_equipped/empty/syndicate
|
||||
theme = /datum/mod_theme/syndicate
|
||||
|
||||
/obj/item/mod/control/pre_equipped/syndicate_empty/honkerative
|
||||
/obj/item/mod/control/pre_equipped/empty/syndicate/honkerative
|
||||
applied_skin = "honkerative"
|
||||
|
||||
/obj/item/mod/control/pre_equipped/syndicate_empty/elite
|
||||
/obj/item/mod/control/pre_equipped/empty/elite
|
||||
theme = /datum/mod_theme/elite
|
||||
|
||||
INITIALIZE_IMMEDIATE(/obj/item/mod/control/pre_equipped/syndicate_empty)
|
||||
/obj/item/mod/control/pre_equipped/empty/ninja
|
||||
theme = /datum/mod_theme/ninja
|
||||
|
||||
INITIALIZE_IMMEDIATE(/obj/item/mod/control/pre_equipped/empty)
|
||||
|
||||
@@ -21,20 +21,20 @@
|
||||
data["modules"] = list()
|
||||
for(var/obj/item/mod/module/module as anything in modules)
|
||||
var/list/module_data = list(
|
||||
name = module.name,
|
||||
description = module.desc,
|
||||
module_type = module.module_type,
|
||||
active = module.active,
|
||||
pinned = module.pinned_to[user],
|
||||
idle_power = module.idle_power_cost,
|
||||
active_power = module.active_power_cost,
|
||||
use_power = module.use_power_cost,
|
||||
complexity = module.complexity,
|
||||
cooldown_time = module.cooldown_time,
|
||||
cooldown = round(COOLDOWN_TIMELEFT(module, cooldown_timer), 1 SECONDS),
|
||||
id = module.tgui_id,
|
||||
ref = REF(module),
|
||||
configuration_data = module.get_configuration()
|
||||
"module_name" = module.name,
|
||||
"description" = module.desc,
|
||||
"module_type" = module.module_type,
|
||||
"module_active" = module.active,
|
||||
"pinned" = module.pinned_to[user],
|
||||
"idle_power" = module.idle_power_cost,
|
||||
"active_power" = module.active_power_cost,
|
||||
"use_power" = module.use_power_cost,
|
||||
"module_complexity" = module.complexity,
|
||||
"cooldown_time" = module.cooldown_time,
|
||||
"cooldown" = round(COOLDOWN_TIMELEFT(module, cooldown_timer), 1 SECONDS),
|
||||
"id" = module.tgui_id,
|
||||
"ref" = REF(module),
|
||||
"configuration_data" = module.get_configuration()
|
||||
)
|
||||
module_data += module.add_ui_data()
|
||||
data["modules"] += list(module_data)
|
||||
|
||||
@@ -225,9 +225,7 @@
|
||||
|
||||
/// Checks if there is enough power in the suit
|
||||
/obj/item/mod/module/proc/check_power(amount)
|
||||
if(mod.get_charge() < amount)
|
||||
return FALSE
|
||||
return TRUE
|
||||
return mod.check_charge(amount)
|
||||
|
||||
/// Adds additional things to the MODsuit ui_data()
|
||||
/obj/item/mod/module/proc/add_ui_data()
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
immunity against extremities such as spot and arc welding, solar eclipses, and handheld flashlights."
|
||||
icon_state = "welding"
|
||||
complexity = 1
|
||||
incompatible_modules = list(/obj/item/mod/module/welding)
|
||||
incompatible_modules = list(/obj/item/mod/module/welding, /obj/item/mod/module/armor_booster)
|
||||
overlay_state_inactive = "module_welding"
|
||||
|
||||
/obj/item/mod/module/welding/on_suit_activation()
|
||||
@@ -168,9 +168,9 @@
|
||||
|
||||
/obj/item/mod/module/rad_protection/add_ui_data()
|
||||
. = ..()
|
||||
.["userradiated"] = mod.wearer ? HAS_TRAIT(mod.wearer, TRAIT_IRRADIATED) : 0
|
||||
.["usertoxins"] = mod.wearer ? mod.wearer.getToxLoss() : 0
|
||||
.["usermaxtoxins"] = mod.wearer ? mod.wearer.getMaxHealth() : 0
|
||||
.["userradiated"] = mod.wearer ? HAS_TRAIT(mod.wearer, TRAIT_IRRADIATED) : FALSE
|
||||
.["usertoxins"] = mod.wearer?.getToxLoss() || 0
|
||||
.["usermaxtoxins"] = mod.wearer?.getMaxHealth() || 0
|
||||
.["threatlevel"] = perceived_threat_level
|
||||
|
||||
/obj/item/mod/module/rad_protection/proc/on_pre_potential_irradiation(datum/source, datum/radiation_pulse_information/pulse_information, insulation_to_target)
|
||||
|
||||
@@ -178,7 +178,7 @@
|
||||
icon_state = "bloon"
|
||||
module_type = MODULE_USABLE
|
||||
complexity = 1
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN*0.5
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 0.5
|
||||
incompatible_modules = list(/obj/item/mod/module/balloon)
|
||||
cooldown_time = 15 SECONDS
|
||||
|
||||
|
||||
@@ -25,12 +25,12 @@
|
||||
|
||||
/obj/item/mod/module/health_analyzer/add_ui_data()
|
||||
. = ..()
|
||||
.["userhealth"] = mod.wearer ? mod.wearer.health : 0
|
||||
.["usermaxhealth"] = mod.wearer ? mod.wearer.getMaxHealth() : 0
|
||||
.["userbrute"] = mod.wearer ? mod.wearer.getBruteLoss() : 0
|
||||
.["userburn"] = mod.wearer ? mod.wearer.getFireLoss() : 0
|
||||
.["usertoxin"] = mod.wearer ? mod.wearer.getToxLoss() : 0
|
||||
.["useroxy"] = mod.wearer ? mod.wearer.getOxyLoss() : 0
|
||||
.["userhealth"] = mod.wearer?.health || 0
|
||||
.["usermaxhealth"] = mod.wearer?.getMaxHealth() || 0
|
||||
.["userbrute"] = mod.wearer?.getBruteLoss() || 0
|
||||
.["userburn"] = mod.wearer?.getFireLoss() || 0
|
||||
.["usertoxin"] = mod.wearer?.getToxLoss() || 0
|
||||
.["useroxy"] = mod.wearer?.getOxyLoss() || 0
|
||||
|
||||
/obj/item/mod/module/health_analyzer/on_select_use(atom/target)
|
||||
. = ..()
|
||||
|
||||
@@ -0,0 +1,444 @@
|
||||
//Ninja modules for MODsuits
|
||||
|
||||
///Cloaking - Lowers the user's visibility, can be interrupted by being touched or attacked.
|
||||
/obj/item/mod/module/stealth
|
||||
name = "MOD prototype cloaking module"
|
||||
desc = "A complete retrofitting of the suit, this is a form of visual concealment tech employing esoteric technology \
|
||||
to bend light around the user, as well as mimetic materials to make the surface of the suit match the \
|
||||
surroundings based off sensor data. For some reason, this tech is rarely seen."
|
||||
icon_state = "cloak"
|
||||
module_type = MODULE_TOGGLE
|
||||
complexity = 4
|
||||
active_power_cost = DEFAULT_CHARGE_DRAIN * 2
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 10
|
||||
incompatible_modules = list(/obj/item/mod/module/stealth)
|
||||
cooldown_time = 5 SECONDS
|
||||
/// Whether or not the cloak turns off on bumping.
|
||||
var/bumpoff = TRUE
|
||||
/// The alpha applied when the cloak is on.
|
||||
var/stealth_alpha = 50
|
||||
|
||||
/obj/item/mod/module/stealth/on_activation()
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(bumpoff)
|
||||
RegisterSignal(mod.wearer, COMSIG_LIVING_MOB_BUMP, .proc/unstealth)
|
||||
RegisterSignal(mod.wearer, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, .proc/on_unarmed_attack)
|
||||
RegisterSignal(mod.wearer, COMSIG_ATOM_BULLET_ACT, .proc/on_bullet_act)
|
||||
RegisterSignal(mod.wearer, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_PARENT_ATTACKBY, COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_HITBY, COMSIG_ATOM_HULK_ATTACK, COMSIG_ATOM_ATTACK_PAW, COMSIG_CARBON_CUFF_ATTEMPTED), .proc/unstealth)
|
||||
animate(mod.wearer, alpha = stealth_alpha, time = 1.5 SECONDS)
|
||||
drain_power(use_power_cost)
|
||||
|
||||
/obj/item/mod/module/stealth/on_deactivation(display_message = TRUE, deleting = FALSE)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(bumpoff)
|
||||
UnregisterSignal(mod.wearer, COMSIG_LIVING_MOB_BUMP)
|
||||
UnregisterSignal(mod.wearer, list(COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_MOB_ITEM_ATTACK, COMSIG_PARENT_ATTACKBY, COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_BULLET_ACT, COMSIG_ATOM_HITBY, COMSIG_ATOM_HULK_ATTACK, COMSIG_ATOM_ATTACK_PAW, COMSIG_CARBON_CUFF_ATTEMPTED))
|
||||
animate(mod.wearer, alpha = 255, time = 1.5 SECONDS)
|
||||
|
||||
/obj/item/mod/module/stealth/proc/unstealth(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
to_chat(mod.wearer, span_warning("[src] gets discharged from contact!"))
|
||||
do_sparks(2, TRUE, src)
|
||||
drain_power(use_power_cost)
|
||||
on_deactivation(display_message = TRUE, deleting = FALSE)
|
||||
|
||||
/obj/item/mod/module/stealth/proc/on_unarmed_attack(datum/source, atom/target)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!isliving(target))
|
||||
return
|
||||
unstealth(source)
|
||||
|
||||
/obj/item/mod/module/stealth/proc/on_bullet_act(datum/source, obj/projectile/projectile)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(projectile.nodamage)
|
||||
return
|
||||
unstealth(source)
|
||||
|
||||
//Advanced Cloaking - Doesn't turf off on bump, less power drain, more stealthy.
|
||||
/obj/item/mod/module/stealth/ninja
|
||||
name = "MOD advanced cloaking module"
|
||||
desc = "The latest in stealth technology, this module is a definite upgrade over previous versions. \
|
||||
The field has been tuned to be even more responsive and fast-acting, with enough stability to \
|
||||
continue operation of the field even if the user bumps into others. \
|
||||
The power draw has been reduced drastically, making this perfect for activities like \
|
||||
standing near sentry turrets for extended periods of time."
|
||||
icon_state = "cloak_ninja"
|
||||
bumpoff = FALSE
|
||||
stealth_alpha = 20
|
||||
active_power_cost = DEFAULT_CHARGE_DRAIN
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 5
|
||||
cooldown_time = 3 SECONDS
|
||||
|
||||
///Camera Vision - Prevents flashes, blocks tracking.
|
||||
/obj/item/mod/module/welding/camera_vision
|
||||
name = "MOD camera vision module"
|
||||
desc = "A module installed into the suit's helmet. This specialized piece of technology is built for subterfuge, \
|
||||
replacing the standard visor with a nanotech display; capable of displaying specialized imagery at \
|
||||
just the right frequency to jam all known forms of camera tracking and facial recognition, \
|
||||
as well as automatically dimming incoming flashes of light to protect the user's eyes. Become the unseen."
|
||||
icon_state = "welding_camera"
|
||||
removable = FALSE
|
||||
complexity = 0
|
||||
overlay_state_inactive = null
|
||||
|
||||
/obj/item/mod/module/welding/camera_vision/on_suit_activation()
|
||||
. = ..()
|
||||
RegisterSignal(mod.wearer, COMSIG_LIVING_CAN_TRACK, .proc/can_track)
|
||||
|
||||
/obj/item/mod/module/welding/camera_vision/on_suit_deactivation(deleting = FALSE)
|
||||
. = ..()
|
||||
UnregisterSignal(mod.wearer, COMSIG_LIVING_CAN_TRACK)
|
||||
|
||||
/obj/item/mod/module/welding/camera_vision/proc/can_track(datum/source, mob/user)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
return COMPONENT_CANT_TRACK
|
||||
|
||||
//Ninja Star Dispenser - Dispenses ninja stars.
|
||||
/obj/item/mod/module/dispenser/ninja
|
||||
name = "MOD ninja star dispenser module"
|
||||
desc = "This piece of Spider Clan technology can exploit known energy-matter equivalence principles, \
|
||||
using the nanites already hosted in the wearer's suit to transmute into monomolecular shuriken. \
|
||||
While these lack the intense bleeding edge of conventional throwing stars, \
|
||||
they have been set to electrify fleeing targets; and branded with the Spider Clan symbol."
|
||||
dispense_type = /obj/item/throwing_star/stamina/ninja
|
||||
cooldown_time = 0.5 SECONDS
|
||||
|
||||
///Hacker - This module hooks onto your right-clicks with empty hands and causes ninja actions.
|
||||
/obj/item/mod/module/hacker
|
||||
name = "MOD hacker module"
|
||||
desc = "Built for one purpose, electronic warfare, this module is built into the hands. \
|
||||
Using near-field communication alongside precise electro-stimulation of the wires in machines, \
|
||||
this decker's dream is normally used to pass through doors like a phantom. \
|
||||
It's also capable of non-precise electro-stimulation of an assassin-saboteur's opponents on disarming attacks."
|
||||
icon_state = "hacker"
|
||||
removable = FALSE
|
||||
incompatible_modules = list(/obj/item/mod/module/hacker)
|
||||
/// Minimum amount of power we can drain in a single drain action
|
||||
var/mindrain = 200
|
||||
/// Maximum amount of power we can drain in a single drain action
|
||||
var/maxdrain = 400
|
||||
/// Whether or not the communication console hack was used to summon another antagonist.
|
||||
var/communication_console_hack_success = FALSE
|
||||
/// How many times the module has been used to force open doors.
|
||||
var/door_hack_counter = 0
|
||||
|
||||
/obj/item/mod/module/hacker/on_suit_activation()
|
||||
RegisterSignal(mod.wearer, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, .proc/hack)
|
||||
|
||||
/obj/item/mod/module/hacker/on_suit_deactivation(deleting = FALSE)
|
||||
UnregisterSignal(mod.wearer, COMSIG_HUMAN_EARLY_UNARMED_ATTACK)
|
||||
|
||||
/obj/item/mod/module/hacker/proc/hack(mob/living/carbon/human/source, atom/target, proximity, modifiers)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!LAZYACCESS(modifiers, RIGHT_CLICK) || !proximity)
|
||||
return NONE
|
||||
target.add_fingerprint(mod.wearer)
|
||||
return target.ninjadrain_act(mod.wearer, src)
|
||||
|
||||
/obj/item/mod/module/hacker/proc/charge_message(atom/drained_atom, drain_amount)
|
||||
if(drain_amount)
|
||||
to_chat(mod.wearer, span_notice("Gained <B>[drain_amount]</B> units of energy from [drained_atom]."))
|
||||
else
|
||||
to_chat(mod.wearer, span_warning("[drained_atom] has run dry of energy, you must find another source!"))
|
||||
|
||||
///Weapon Recall - Teleports your katana to you, prevents gun use.
|
||||
/obj/item/mod/module/weapon_recall
|
||||
name = "MOD weapon recall module"
|
||||
desc = "The cornerstone of a clanmember's life as a blademaster, and a module symbolizing their eternal bond with their weapon. \
|
||||
This hooks to the micro bluespace drive inside an energy katana's handle, capable of recalling it to the user's \
|
||||
skilled hands wherever they are. However, those that make such a bond with their weapon are cursed to \
|
||||
fusing their existence with acts of combat, with a singular purpose; Cutting Down Their Opponent. \
|
||||
Their hand a hand that is cutting, their body a body that is cutting, their mind, a mind that is cutting. \
|
||||
Ranged weapons are forbidden."
|
||||
icon_state = "recall"
|
||||
removable = FALSE
|
||||
module_type = MODULE_USABLE
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 2
|
||||
incompatible_modules = list(/obj/item/mod/module/weapon_recall)
|
||||
cooldown_time = 0.5 SECONDS
|
||||
/// The item linked to the module that will get recalled.
|
||||
var/obj/item/linked_weapon
|
||||
/// The accepted typepath we can link to.
|
||||
var/accepted_type = /obj/item/energy_katana
|
||||
|
||||
/obj/item/mod/module/weapon_recall/on_suit_activation()
|
||||
ADD_TRAIT(mod.wearer, TRAIT_NOGUNS, MOD_TRAIT)
|
||||
|
||||
/obj/item/mod/module/weapon_recall/on_suit_deactivation(deleting = FALSE)
|
||||
REMOVE_TRAIT(mod.wearer, TRAIT_NOGUNS, MOD_TRAIT)
|
||||
|
||||
/obj/item/mod/module/weapon_recall/on_use()
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(!linked_weapon)
|
||||
var/obj/item/weapon_to_link = mod.wearer.is_holding_item_of_type(accepted_type)
|
||||
if(!weapon_to_link)
|
||||
balloon_alert(mod.wearer, "can't locate weapon!")
|
||||
return
|
||||
set_weapon(weapon_to_link)
|
||||
balloon_alert(mod.wearer, "[linked_weapon.name] linked")
|
||||
return
|
||||
if(linked_weapon in mod.wearer.get_all_contents())
|
||||
balloon_alert(mod.wearer, "already on self!")
|
||||
return
|
||||
var/distance = get_dist(mod.wearer, linked_weapon)
|
||||
var/in_view = (linked_weapon in view(mod.wearer))
|
||||
if(!in_view && !drain_power(use_power_cost * distance))
|
||||
balloon_alert(mod.wearer, "not enough charge!")
|
||||
return
|
||||
linked_weapon.forceMove(linked_weapon.drop_location())
|
||||
if(in_view)
|
||||
do_sparks(5, FALSE, linked_weapon)
|
||||
mod.wearer.visible_message(span_danger("[linked_weapon] flies towards [mod.wearer]!"),span_warning("You hold out your hand and [linked_weapon] flies towards you!"))
|
||||
linked_weapon.throw_at(mod.wearer, distance+1, linked_weapon.throw_speed, mod.wearer)
|
||||
else
|
||||
recall_weapon()
|
||||
|
||||
/obj/item/mod/module/weapon_recall/proc/set_weapon(obj/item/weapon)
|
||||
linked_weapon = weapon
|
||||
RegisterSignal(linked_weapon, COMSIG_MOVABLE_IMPACT, .proc/catch_weapon)
|
||||
RegisterSignal(linked_weapon, COMSIG_PARENT_QDELETING, .proc/deleted_weapon)
|
||||
|
||||
/obj/item/mod/module/weapon_recall/proc/recall_weapon(caught = FALSE)
|
||||
linked_weapon.forceMove(get_turf(src))
|
||||
var/alert = ""
|
||||
if(mod.wearer.put_in_hands(linked_weapon))
|
||||
alert = "[linked_weapon.name] teleports to your hand"
|
||||
else if(mod.wearer.equip_to_slot_if_possible(linked_weapon, ITEM_SLOT_BELT, disable_warning = TRUE))
|
||||
alert = "[linked_weapon.name] sheathes itself in your belt"
|
||||
else
|
||||
alert = "[linked_weapon.name] teleports under you"
|
||||
if(caught)
|
||||
if(mod.wearer.is_holding(linked_weapon))
|
||||
alert = "you catch [linked_weapon.name]"
|
||||
else
|
||||
alert = "[linked_weapon.name] lands under you"
|
||||
else
|
||||
do_sparks(5, FALSE, linked_weapon)
|
||||
if(alert)
|
||||
balloon_alert(mod.wearer, alert)
|
||||
|
||||
/obj/item/mod/module/weapon_recall/proc/catch_weapon(obj/item/source, atom/hit_atom, datum/thrownthing/thrownthing)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!mod)
|
||||
return
|
||||
if(hit_atom != mod.wearer)
|
||||
return
|
||||
INVOKE_ASYNC(src, .proc/recall_weapon, TRUE)
|
||||
return COMPONENT_MOVABLE_IMPACT_NEVERMIND
|
||||
|
||||
/obj/item/mod/module/weapon_recall/proc/deleted_weapon(obj/item/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
linked_weapon = null
|
||||
|
||||
//Reinforced DNA Lock - Gibs if wrong DNA, emp-proof.
|
||||
/obj/item/mod/module/dna_lock/reinforced
|
||||
name = "MOD reinforced DNA lock module"
|
||||
desc = "A module which engages with the various locks and seals tied to the suit's systems, \
|
||||
enabling it to only be worn by someone corresponding with the user's exact DNA profile. \
|
||||
Due to utilizing a skintight dampening shield, this one is entirely sealed against electromagnetic interference; \
|
||||
it also dutifully protects the secrets of the Spider Clan from unknowing outsiders."
|
||||
icon_state = "dnalock_ninja"
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 0.5
|
||||
|
||||
/obj/item/mod/module/dna_lock/reinforced/on_mod_activation(datum/source, mob/user)
|
||||
. = ..()
|
||||
if(. != MOD_CANCEL_ACTIVATE || !isliving(user))
|
||||
return
|
||||
var/mob/living/living_user = user
|
||||
to_chat(living_user, span_danger("<B>fATaL EERRoR</B>: 382200-*#00CODE <B>RED</B>\nUNAUTHORIZED USE DETECteD\nCoMMENCING SUB-R0UTIN3 13...\nTERMInATING U-U-USER..."))
|
||||
living_user.gib()
|
||||
|
||||
/obj/item/mod/module/dna_lock/reinforced/on_emp(datum/source, severity)
|
||||
return
|
||||
|
||||
//EMP Pulse - In addition to normal shielding, can also launch an EMP itself.
|
||||
/obj/item/mod/module/emp_shield/pulse
|
||||
name = "MOD EMP pulse module"
|
||||
desc = "This module is normally set to activate on dramatic gestures, inverting and expanding the suit's \
|
||||
EMP dampening shield to cause an electromagnetic pulse of its own. While this won't interfere with the wearer, \
|
||||
it will piss off everyone around them."
|
||||
icon_state = "emp_pulse"
|
||||
module_type = MODULE_USABLE
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 10
|
||||
cooldown_time = 8 SECONDS
|
||||
|
||||
/obj/item/mod/module/emp_shield/pulse/on_use()
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
playsound(src, 'sound/effects/empulse.ogg', 60, TRUE)
|
||||
empulse(src, heavy_range = 4, light_range = 6)
|
||||
drain_power(use_power_cost)
|
||||
|
||||
///Status Readout - Puts a lot of information including health, nutrition, fingerprints, temperature to the suit TGUI.
|
||||
/obj/item/mod/module/status_readout
|
||||
name = "MOD status readout module"
|
||||
desc = "A once-common module, this technology went unfortunately out of fashion; \
|
||||
and right into the arachnid grip of the Spider Clan. This hooks into the suit's spine, \
|
||||
capable of capturing and displaying all possible biometric data of the wearer; sleep, nutrition, fitness, fingerprints, \
|
||||
and even useful information such as their overall health and wellness."
|
||||
icon_state = "status"
|
||||
complexity = 1
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 0.1
|
||||
incompatible_modules = list(/obj/item/mod/module/status_readout)
|
||||
tgui_id = "status_readout"
|
||||
|
||||
/obj/item/mod/module/status_readout/add_ui_data()
|
||||
. = ..()
|
||||
.["statustime"] = station_time_timestamp()
|
||||
.["statusid"] = GLOB.round_id
|
||||
.["statushealth"] = mod.wearer?.health || 0
|
||||
.["statusmaxhealth"] = mod.wearer?.getMaxHealth() || 0
|
||||
.["statusbrute"] = mod.wearer?.getBruteLoss() || 0
|
||||
.["statusburn"] = mod.wearer?.getFireLoss() || 0
|
||||
.["statustoxin"] = mod.wearer?.getToxLoss() || 0
|
||||
.["statusoxy"] = mod.wearer?.getOxyLoss() || 0
|
||||
.["statustemp"] = mod.wearer?.bodytemperature || 0
|
||||
.["statusnutrition"] = mod.wearer?.nutrition || 0
|
||||
.["statusfingerprints"] = mod.wearer ? md5(mod.wearer.dna.unique_identity) : null
|
||||
.["statusdna"] = mod.wearer?.dna.unique_enzymes
|
||||
.["statusviruses"] = null
|
||||
if(!length(mod.wearer?.diseases))
|
||||
return
|
||||
var/list/viruses = list()
|
||||
for(var/datum/disease/virus as anything in mod.wearer.diseases)
|
||||
var/list/virus_data = list()
|
||||
virus_data["name"] = virus.name
|
||||
virus_data["type"] = virus.spread_text
|
||||
virus_data["stage"] = virus.stage
|
||||
virus_data["maxstage"] = virus.max_stages
|
||||
virus_data["cure"] = virus.cure_text
|
||||
viruses += list(virus_data)
|
||||
.["statusviruses"] = viruses
|
||||
|
||||
///Energy Net - Ensnares enemies in a net that prevents movement.
|
||||
/obj/item/mod/module/energy_net
|
||||
name = "MOD energy net module"
|
||||
desc = "A custom-built net-thrower. While conventional implementations of this capturing device \
|
||||
tilize monomolecular fibers or cutting razorwire, this uses hardlight technology to deploy a \
|
||||
trapping field capable of immobilizing even the strongest opponents."
|
||||
icon_state = "energy_net"
|
||||
removable = FALSE
|
||||
module_type = MODULE_ACTIVE
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 6
|
||||
incompatible_modules = list(/obj/item/mod/module/energy_net)
|
||||
cooldown_time = 1.5 SECONDS
|
||||
|
||||
/obj/item/mod/module/energy_net/on_select_use(atom/target)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(!isliving(target))
|
||||
balloon_alert(mod.wearer, "invalid target!")
|
||||
return
|
||||
var/mob/living/living_target = target
|
||||
if(locate(/obj/structure/energy_net) in get_turf(living_target))
|
||||
balloon_alert(mod.wearer, "already trapped!")
|
||||
return
|
||||
for(var/turf/between_turf as anything in get_line(get_turf(mod.wearer), get_turf(living_target)))
|
||||
if(between_turf.density)
|
||||
balloon_alert(mod.wearer, "not through obstacles!")
|
||||
return
|
||||
if(IS_SPACE_NINJA(mod.wearer))
|
||||
mod.wearer.say("Get over here!", forced = type)
|
||||
mod.wearer.Beam(living_target, "n_beam", time = 1.5 SECONDS)
|
||||
var/obj/structure/energy_net/net = new /obj/structure/energy_net(living_target.drop_location())
|
||||
net.affected_mob = living_target
|
||||
mod.wearer.visible_message(span_danger("[mod.wearer] caught [living_target] with an energy net!"), span_notice("You caught [living_target] with an energy net!"))
|
||||
if(living_target.buckled)
|
||||
living_target.buckled.unbuckle_mob(living_target, force = TRUE)
|
||||
net.buckle_mob(living_target, force = TRUE)
|
||||
drain_power(use_power_cost)
|
||||
|
||||
///Adrenaline Boost - Stops all stuns the ninja is affected with, increases his speed.
|
||||
/obj/item/mod/module/adrenaline_boost
|
||||
name = "MOD adrenaline boost module"
|
||||
desc = "The secrets of the Spider Clan are many. The exact specifications of their suits, \
|
||||
the techniques they use to make every singular cut make their enemies weep with admiration, \
|
||||
but one of their greatest mysteries is the chemical compound their assassin-saboteurs use in times of need. \
|
||||
It's capable of clearing any fatigue whatsoever from the user, any immobilizing effect, and can even \
|
||||
cure total paralysis. All that's known is that the fluid requires radiation to properly 'cook,' \
|
||||
so this module demands radium to be refilled with."
|
||||
icon_state = "adrenaline_boost"
|
||||
removable = FALSE
|
||||
module_type = MODULE_USABLE
|
||||
incompatible_modules = list(/obj/item/mod/module/adrenaline_boost)
|
||||
cooldown_time = 12 SECONDS
|
||||
/// What reagent we need to refill?
|
||||
var/reagent_required = /datum/reagent/uranium/radium
|
||||
/// How much of a reagent we need to refill the boost.
|
||||
var/reagent_required_amount = 20
|
||||
|
||||
/obj/item/mod/module/adrenaline_boost/Initialize(mapload)
|
||||
. = ..()
|
||||
create_reagents(reagent_required_amount)
|
||||
reagents.add_reagent(reagent_required, reagent_required_amount)
|
||||
|
||||
/obj/item/mod/module/adrenaline_boost/on_use()
|
||||
if(!reagents.has_reagent(reagent_required, reagent_required_amount))
|
||||
balloon_alert(mod.wearer, "no charge!")
|
||||
return
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(IS_SPACE_NINJA(mod.wearer))
|
||||
mod.wearer.say(pick_list_replacements(NINJA_FILE, "lines"), forced = type)
|
||||
to_chat(mod.wearer, span_notice("You have used the adrenaline boost."))
|
||||
mod.wearer.SetUnconscious(0)
|
||||
mod.wearer.SetStun(0)
|
||||
mod.wearer.SetKnockdown(0)
|
||||
mod.wearer.SetImmobilized(0)
|
||||
mod.wearer.SetParalyzed(0)
|
||||
mod.wearer.adjustStaminaLoss(-200)
|
||||
mod.wearer.remove_status_effect(/datum/status_effect/speech/stutter)
|
||||
mod.wearer.reagents.add_reagent(/datum/reagent/medicine/stimulants, 5)
|
||||
reagents.remove_reagent(reagent_required, reagents.total_volume * 0.75)
|
||||
addtimer(CALLBACK(src, .proc/boost_aftereffects, mod.wearer), 7 SECONDS)
|
||||
|
||||
/obj/item/mod/module/adrenaline_boost/on_install()
|
||||
RegisterSignal(mod, COMSIG_PARENT_ATTACKBY, .proc/on_attackby)
|
||||
|
||||
/obj/item/mod/module/adrenaline_boost/on_uninstall(deleting)
|
||||
UnregisterSignal(mod, COMSIG_PARENT_ATTACKBY)
|
||||
|
||||
/obj/item/mod/module/adrenaline_boost/attackby(obj/item/attacking_item, mob/user, params)
|
||||
if(charge_boost(attacking_item, user))
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/obj/item/mod/module/adrenaline_boost/proc/on_attackby(datum/source, obj/item/attacking_item, mob/user)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(charge_boost(attacking_item, user))
|
||||
return COMPONENT_NO_AFTERATTACK
|
||||
return NONE
|
||||
|
||||
/obj/item/mod/module/adrenaline_boost/proc/charge_boost(obj/item/attacking_item, mob/user)
|
||||
if(!attacking_item.is_open_container())
|
||||
return FALSE
|
||||
if(reagents.has_reagent(reagent_required, reagent_required_amount))
|
||||
balloon_alert(mod.wearer, "already charged!")
|
||||
return FALSE
|
||||
if(!attacking_item.reagents.trans_id_to(src, reagent_required, reagent_required_amount))
|
||||
return FALSE
|
||||
balloon_alert(mod.wearer, "charge [reagents.has_reagent(reagent_required, reagent_required_amount) ? "fully" : "partially"] reloaded")
|
||||
return TRUE
|
||||
|
||||
/obj/item/mod/module/adrenaline_boost/proc/boost_aftereffects(mob/affected_mob)
|
||||
if(!affected_mob)
|
||||
return
|
||||
reagents.trans_to(affected_mob, reagents.total_volume)
|
||||
to_chat(affected_mob, span_danger("You are beginning to feel the after-effect of the injection."))
|
||||
@@ -1,80 +1,5 @@
|
||||
//Security modules for MODsuits
|
||||
|
||||
///Cloaking - Lowers the user's visibility, can be interrupted by being touched or attacked.
|
||||
/obj/item/mod/module/stealth
|
||||
name = "MOD prototype cloaking module"
|
||||
desc = "A complete retrofitting of the suit, this is a form of visual concealment tech employing esoteric technology \
|
||||
to bend light around the user, as well as mimetic materials to make the surface of the suit match the \
|
||||
surroundings based off sensor data. For some reason, this tech is rarely seen."
|
||||
icon_state = "cloak"
|
||||
module_type = MODULE_TOGGLE
|
||||
complexity = 4
|
||||
active_power_cost = DEFAULT_CHARGE_DRAIN * 2
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 10
|
||||
incompatible_modules = list(/obj/item/mod/module/stealth)
|
||||
cooldown_time = 5 SECONDS
|
||||
/// Whether or not the cloak turns off on bumping.
|
||||
var/bumpoff = TRUE
|
||||
/// The alpha applied when the cloak is on.
|
||||
var/stealth_alpha = 50
|
||||
|
||||
/obj/item/mod/module/stealth/on_activation()
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(bumpoff)
|
||||
RegisterSignal(mod.wearer, COMSIG_LIVING_MOB_BUMP, .proc/unstealth)
|
||||
RegisterSignal(mod.wearer, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, .proc/on_unarmed_attack)
|
||||
RegisterSignal(mod.wearer, COMSIG_ATOM_BULLET_ACT, .proc/on_bullet_act)
|
||||
RegisterSignal(mod.wearer, list(COMSIG_ITEM_ATTACK, COMSIG_PARENT_ATTACKBY, COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_HITBY, COMSIG_ATOM_HULK_ATTACK, COMSIG_ATOM_ATTACK_PAW, COMSIG_CARBON_CUFF_ATTEMPTED), .proc/unstealth)
|
||||
animate(mod.wearer, alpha = stealth_alpha, time = 1.5 SECONDS)
|
||||
drain_power(use_power_cost)
|
||||
|
||||
/obj/item/mod/module/stealth/on_deactivation(display_message = TRUE, deleting = FALSE)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(bumpoff)
|
||||
UnregisterSignal(mod.wearer, COMSIG_LIVING_MOB_BUMP)
|
||||
UnregisterSignal(mod.wearer, list(COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_ITEM_ATTACK, COMSIG_PARENT_ATTACKBY, COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_BULLET_ACT, COMSIG_ATOM_HITBY, COMSIG_ATOM_HULK_ATTACK, COMSIG_ATOM_ATTACK_PAW, COMSIG_CARBON_CUFF_ATTEMPTED))
|
||||
animate(mod.wearer, alpha = 255, time = 1.5 SECONDS)
|
||||
|
||||
/obj/item/mod/module/stealth/proc/unstealth(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
to_chat(mod.wearer, span_warning("[src] gets discharged from contact!"))
|
||||
do_sparks(2, TRUE, src)
|
||||
drain_power(use_power_cost)
|
||||
on_deactivation(display_message = TRUE, deleting = FALSE)
|
||||
|
||||
/obj/item/mod/module/stealth/proc/on_unarmed_attack(datum/source, atom/target)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!isliving(target))
|
||||
return
|
||||
unstealth(source)
|
||||
|
||||
/obj/item/mod/module/stealth/proc/on_bullet_act(datum/source, obj/projectile/projectile)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(projectile.nodamage)
|
||||
return
|
||||
unstealth(source)
|
||||
|
||||
/obj/item/mod/module/stealth/ninja
|
||||
name = "MOD advanced cloaking module"
|
||||
desc = "The latest in stealth technology, this module is a definite upgrade over previous versions. \
|
||||
The field has been tuned to be even more responsive and fast-acting, with enough stability to \
|
||||
continue operation of the field even if the user bumps into others. \
|
||||
The power draw has been reduced drastically, making this perfect for activities like \
|
||||
standing near sentry turrets for extended periods of time."
|
||||
icon_state = "cloak_ninja"
|
||||
bumpoff = FALSE
|
||||
stealth_alpha = 20
|
||||
active_power_cost = DEFAULT_CHARGE_DRAIN
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 5
|
||||
cooldown_time = 3 SECONDS
|
||||
|
||||
///Magnetic Harness - Automatically puts guns in your suit storage when you drop them.
|
||||
/obj/item/mod/module/magnetic_harness
|
||||
name = "MOD magnetic harness module"
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
//ninjacost() specificCheck defines
|
||||
#define N_STEALTH_CANCEL 1
|
||||
#define N_ADRENALINE 2
|
||||
|
||||
//ninjaDrainAct() defines for non numerical returns
|
||||
#define INVALID_DRAIN "INVALID" //This one is if the drain proc needs to cancel, eg missing variables, etc, it's important.
|
||||
#define DRAIN_RD_HACK_FAILED "RDHACKFAIL"
|
||||
#define DRAIN_MOB_SHOCK "MOBSHOCK"
|
||||
#define DRAIN_MOB_SHOCK_FAILED "MOBSHOCKFAIL"
|
||||
|
||||
//Tells whether or not someone is a space ninja
|
||||
#define IS_SPACE_NINJA(ninja) (ninja.mind && ninja.mind.has_antag_datum(/datum/antagonist/ninja))
|
||||
|
||||
//Defines for the suit's unique abilities
|
||||
#define IS_NINJA_SUIT_INITIALIZATION(action) (istype(action, /datum/action/item_action/initialize_ninja_suit))
|
||||
#define IS_NINJA_SUIT_STATUS(action) (istype(action, /datum/action/item_action/ninjastatus))
|
||||
#define IS_NINJA_SUIT_BOOST(action) (istype(action, /datum/action/item_action/ninjaboost))
|
||||
#define IS_NINJA_SUIT_EMP(action) (istype(action, /datum/action/item_action/ninjapulse))
|
||||
#define IS_NINJA_SUIT_STAR_CREATION(action) (istype(action, /datum/action/item_action/ninjastar))
|
||||
#define IS_NINJA_SUIT_NET_CREATION(action) (istype(action, /datum/action/item_action/ninjanet))
|
||||
#define IS_NINJA_SUIT_SWORD_RECALL(action) (istype(action, /datum/action/item_action/ninja_sword_recall))
|
||||
#define IS_NINJA_SUIT_STEALTH(action) (istype(action, /datum/action/item_action/ninja_stealth))
|
||||
@@ -23,6 +23,8 @@
|
||||
armour_penetration = 50
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
pickup_sound = 'sound/items/unsheath.ogg'
|
||||
drop_sound = 'sound/items/sheath.ogg'
|
||||
attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts")
|
||||
attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut")
|
||||
slot_flags = ITEM_SLOT_BACK|ITEM_SLOT_BELT
|
||||
@@ -39,82 +41,37 @@
|
||||
spark_system.set_up(5, 0, src)
|
||||
spark_system.attach(src)
|
||||
|
||||
/obj/item/energy_katana/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
|
||||
/obj/item/energy_katana/afterattack_secondary(atom/target, mob/user, proximity_flag, click_parameters)
|
||||
. = ..()
|
||||
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
|
||||
return
|
||||
if(!target.density)
|
||||
jaunt?.teleport(user, target)
|
||||
|
||||
var/list/modifiers = params2list(click_parameters)
|
||||
|
||||
if(LAZYACCESS(modifiers, RIGHT_CLICK) && !target.density)
|
||||
jaunt.teleport(user, target)
|
||||
|
||||
/obj/item/energy_katana/pickup(mob/living/user)
|
||||
/obj/item/energy_katana/equipped(mob/user, slot, initial)
|
||||
. = ..()
|
||||
jaunt.Grant(user, src)
|
||||
user.update_icons()
|
||||
playsound(src, 'sound/items/unsheath.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
||||
if(!QDELETED(jaunt))
|
||||
jaunt.Grant(user, src)
|
||||
|
||||
/obj/item/energy_katana/dropped(mob/user)
|
||||
. = ..()
|
||||
jaunt.Remove(user)
|
||||
user.update_icons()
|
||||
|
||||
//If we hit the Ninja who owns this Katana, they catch it.
|
||||
//Works for if the Ninja throws it or it throws itself or someone tries
|
||||
//To throw it at the ninja
|
||||
/obj/item/energy_katana/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
|
||||
if(ishuman(hit_atom))
|
||||
var/mob/living/carbon/human/hit_human = hit_atom
|
||||
if(istype(hit_human.wear_suit, /obj/item/clothing/suit/space/space_ninja))
|
||||
var/obj/item/clothing/suit/space/space_ninja/ninja_suit = hit_human.wear_suit
|
||||
if(ninja_suit.energyKatana == src)
|
||||
returnToOwner(hit_human, 0, 1)
|
||||
return
|
||||
|
||||
..()
|
||||
if(!QDELETED(jaunt))
|
||||
jaunt.Remove(user)
|
||||
|
||||
/obj/item/energy_katana/Destroy()
|
||||
QDEL_NULL(spark_system)
|
||||
QDEL_NULL(jaunt)
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Proc called when the katana is recalled to its space ninja.
|
||||
*
|
||||
* Proc called when space ninja is hit with its suit's katana or the recall ability is used.
|
||||
* Arguments:
|
||||
* * user - To whom the katana is returning to.
|
||||
* * doSpark - whether or not the katana will spark when it returns.
|
||||
* * caught - boolean for whether or not the katana was caught or was teleported back.
|
||||
*/
|
||||
/obj/item/energy_katana/proc/returnToOwner(mob/living/carbon/human/user, doSpark = TRUE, caught = FALSE)
|
||||
if(!istype(user))
|
||||
return
|
||||
forceMove(get_turf(user))
|
||||
|
||||
if(doSpark)
|
||||
spark_system.start()
|
||||
playsound(get_turf(src), SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
||||
|
||||
var/msg = ""
|
||||
|
||||
if(user.put_in_hands(src))
|
||||
msg = "Your Energy Katana teleports into your hand!"
|
||||
else if(user.equip_to_slot_if_possible(src, ITEM_SLOT_BELT, 0, 1, 1))
|
||||
msg = "Your Energy Katana teleports back to you, sheathing itself as it does so!</span>"
|
||||
else
|
||||
msg = "Your Energy Katana teleports to your location!"
|
||||
|
||||
if(caught)
|
||||
if(loc == user)
|
||||
msg = "You catch your Energy Katana!"
|
||||
else
|
||||
msg = "Your Energy Katana lands at your feet!"
|
||||
|
||||
if(msg)
|
||||
to_chat(user, span_notice("[msg]"))
|
||||
|
||||
/datum/action/innate/dash/ninja
|
||||
current_charges = 3
|
||||
max_charges = 3
|
||||
charge_rate = 200
|
||||
beam_length = 1 SECONDS
|
||||
recharge_sound = null
|
||||
|
||||
/datum/action/innate/dash/ninja/GiveAction(mob/viewer) //this action should be invisible, as its handled by right-click
|
||||
return
|
||||
|
||||
/datum/action/innate/dash/ninja/HideFrom(mob/viewer)
|
||||
return
|
||||
|
||||
@@ -0,0 +1,311 @@
|
||||
/**
|
||||
* Atom level proc for space ninja's glove interactions.
|
||||
*
|
||||
* Proc which only occurs when space ninja uses his gloves on an atom.
|
||||
* Does nothing by default, but effects will vary.
|
||||
* Arguments:
|
||||
* * ninja_suit - The offending space ninja's suit.
|
||||
* * ninja - The human mob wearing the suit.
|
||||
* * hacking_module - The offending space ninja's gloves.
|
||||
*/
|
||||
/atom/proc/ninjadrain_act(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module)
|
||||
return NONE
|
||||
|
||||
//APC//
|
||||
/obj/machinery/power/apc/ninjadrain_act(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module)
|
||||
if(!ninja || !hacking_module)
|
||||
return NONE
|
||||
INVOKE_ASYNC(src, .proc/ninjadrain_charge, ninja, hacking_module)
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/obj/machinery/power/apc/proc/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module)
|
||||
var/maxcapacity = FALSE //Safety check for batteries
|
||||
var/drain = 0 //Drain amount from batteries
|
||||
var/drain_total = 0
|
||||
if(cell?.charge)
|
||||
var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread()
|
||||
spark_system.set_up(5, 0, loc)
|
||||
while(cell.charge> 0 && !maxcapacity)
|
||||
drain = rand(hacking_module.mindrain, hacking_module.maxdrain)
|
||||
if(cell.charge < drain)
|
||||
drain = cell.charge
|
||||
if(hacking_module.mod.get_charge() + drain > hacking_module.mod.get_max_charge())
|
||||
drain = hacking_module.mod.get_max_charge() - hacking_module.mod.get_charge()
|
||||
maxcapacity = TRUE//Reached maximum battery capacity.
|
||||
if (do_after(ninja, 1 SECONDS, target = src))
|
||||
spark_system.start()
|
||||
playsound(loc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
||||
cell.use(drain)
|
||||
hacking_module.mod.add_charge(drain)
|
||||
drain_total += drain
|
||||
else
|
||||
break
|
||||
if(!(obj_flags & EMAGGED))
|
||||
flick("apc-spark", hacking_module)
|
||||
playsound(loc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
||||
obj_flags |= EMAGGED
|
||||
locked = FALSE
|
||||
update_appearance()
|
||||
hacking_module.charge_message(src, drain_total)
|
||||
|
||||
//SMES//
|
||||
/obj/machinery/power/smes/ninjadrain_act(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module)
|
||||
if(!ninja || !hacking_module)
|
||||
return NONE
|
||||
INVOKE_ASYNC(src, .proc/ninjadrain_charge, ninja, hacking_module)
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/obj/machinery/power/smes/proc/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module)
|
||||
var/maxcapacity = FALSE //Safety check for batteries
|
||||
var/drain = 0 //Drain amount from batteries
|
||||
var/drain_total = 0
|
||||
var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread()
|
||||
spark_system.set_up(5, 0, loc)
|
||||
while(charge > 0 && !maxcapacity)
|
||||
drain = rand(hacking_module.mindrain, hacking_module.maxdrain)
|
||||
if(charge < drain)
|
||||
drain = charge
|
||||
if(hacking_module.mod.get_charge() + drain > hacking_module.mod.get_max_charge())
|
||||
drain = hacking_module.mod.get_max_charge() - hacking_module.mod.get_charge()
|
||||
maxcapacity = TRUE
|
||||
if (do_after(ninja, 1 SECONDS, target = src))
|
||||
spark_system.start()
|
||||
playsound(loc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
||||
charge -= drain
|
||||
hacking_module.mod.add_charge(drain)
|
||||
drain_total += drain
|
||||
maxcapacity = TRUE//Reached maximum battery capacity.
|
||||
else
|
||||
break
|
||||
hacking_module.charge_message(src, drain_total)
|
||||
|
||||
//CELL//
|
||||
/obj/item/stock_parts/cell/ninjadrain_act(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module)
|
||||
if(!ninja || !hacking_module)
|
||||
return NONE
|
||||
INVOKE_ASYNC(src, .proc/ninjadrain_charge, ninja, hacking_module)
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/obj/item/stock_parts/cell/proc/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module)
|
||||
var/drain_total = 0
|
||||
if(charge && !do_after(ninja, 3 SECONDS, target = src))
|
||||
drain_total = charge
|
||||
if(hacking_module.mod.get_charge() + charge > hacking_module.mod.get_max_charge())
|
||||
drain_total = hacking_module.mod.get_max_charge() - hacking_module.mod.get_charge()
|
||||
hacking_module.mod.add_charge(drain_total)
|
||||
use(drain_total)
|
||||
corrupt()
|
||||
update_appearance()
|
||||
hacking_module.charge_message(src, drain_total)
|
||||
|
||||
//RD SERVER//
|
||||
/obj/machinery/rnd/server/master/ninjadrain_act(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module)
|
||||
if(!ninja || !hacking_module)
|
||||
return NONE
|
||||
// If the traitor theft objective is still present, this will destroy it...
|
||||
if(!source_code_hdd)
|
||||
return ..()
|
||||
to_chat(ninja, span_notice("Hacking \the [src]..."))
|
||||
AI_notify_hack()
|
||||
to_chat(ninja, span_notice("Encrypted source code detected. Overloading storage device..."))
|
||||
INVOKE_ASYNC(src, .proc/ninjadrain_charge, ninja, hacking_module)
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/obj/machinery/rnd/server/master/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module)
|
||||
if(!do_after(ninja, 30 SECONDS, target = src))
|
||||
return
|
||||
overload_source_code_hdd()
|
||||
to_chat(ninja, span_notice("Sabotage complete. Storage device overloaded."))
|
||||
var/datum/antagonist/ninja/ninja_antag = ninja.mind.has_antag_datum(/datum/antagonist/ninja)
|
||||
if(!ninja_antag)
|
||||
return
|
||||
var/datum/objective/research_secrets/objective = locate() in ninja_antag.objectives
|
||||
if(objective)
|
||||
objective.completed = TRUE
|
||||
|
||||
/obj/machinery/rnd/server/ninjadrain_act(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module)
|
||||
if(!ninja || !hacking_module)
|
||||
return NONE
|
||||
to_chat(ninja, span_notice("Research notes detected. Corrupting data..."))
|
||||
INVOKE_ASYNC(src, .proc/ninjadrain_charge, ninja, hacking_module)
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/obj/machinery/rnd/server/proc/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module)
|
||||
if(!do_after(ninja, 30 SECONDS, target = src))
|
||||
return
|
||||
SSresearch.science_tech.modify_points_all(0)
|
||||
to_chat(ninja, span_notice("Sabotage complete. Research notes corrupted."))
|
||||
var/datum/antagonist/ninja/ninja_antag = ninja.mind.has_antag_datum(/datum/antagonist/ninja)
|
||||
if(!ninja_antag)
|
||||
return
|
||||
var/datum/objective/research_secrets/objective = locate() in ninja_antag.objectives
|
||||
if(objective)
|
||||
objective.completed = TRUE
|
||||
|
||||
//SECURITY CONSOLE//
|
||||
/obj/machinery/computer/secure_data/ninjadrain_act(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module)
|
||||
if(!ninja || !hacking_module)
|
||||
return NONE
|
||||
AI_notify_hack()
|
||||
INVOKE_ASYNC(src, .proc/ninjadrain_charge, ninja, hacking_module)
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/obj/machinery/computer/secure_data/proc/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module)
|
||||
if(!do_after(ninja, 20 SECONDS))
|
||||
return
|
||||
for(var/datum/data/record/rec in sort_record(GLOB.data_core.general, sortBy, order))
|
||||
for(var/datum/data/record/security_record in GLOB.data_core.security)
|
||||
security_record.fields["criminal"] = "*Arrest*"
|
||||
var/datum/antagonist/ninja/ninja_antag = ninja.mind.has_antag_datum(/datum/antagonist/ninja)
|
||||
if(!ninja_antag)
|
||||
return
|
||||
var/datum/objective/security_scramble/objective = locate() in ninja_antag.objectives
|
||||
if(objective)
|
||||
objective.completed = TRUE
|
||||
|
||||
//COMMUNICATIONS CONSOLE//
|
||||
/obj/machinery/computer/communications/ninjadrain_act(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module)
|
||||
if(!ninja || !hacking_module)
|
||||
return NONE
|
||||
if(hacking_module.communication_console_hack_success)
|
||||
return NONE
|
||||
if(machine_stat & (NOPOWER|BROKEN))
|
||||
return NONE
|
||||
AI_notify_hack()
|
||||
INVOKE_ASYNC(src, .proc/ninjadrain_charge, ninja, hacking_module)
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/obj/machinery/computer/communications/proc/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module)
|
||||
if(!do_after(ninja, 30 SECONDS, src))
|
||||
return
|
||||
hack_console(ninja)
|
||||
hacking_module.communication_console_hack_success = TRUE
|
||||
var/datum/antagonist/ninja/ninja_antag = ninja.mind.has_antag_datum(/datum/antagonist/ninja)
|
||||
if(!ninja_antag)
|
||||
return
|
||||
var/datum/objective/terror_message/objective = locate() in ninja_antag.objectives
|
||||
if(objective)
|
||||
objective.completed = TRUE
|
||||
|
||||
//AIRLOCK//
|
||||
/obj/machinery/door/airlock/ninjadrain_act(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module)
|
||||
if(!ninja || !hacking_module)
|
||||
return NONE
|
||||
if(!operating && density && hasPower() && !(obj_flags & EMAGGED))
|
||||
INVOKE_ASYNC(src, /atom.proc/emag_act)
|
||||
hacking_module.door_hack_counter++
|
||||
var/datum/antagonist/ninja/ninja_antag = ninja.mind.has_antag_datum(/datum/antagonist/ninja)
|
||||
if(!ninja_antag)
|
||||
return NONE
|
||||
var/datum/objective/door_jack/objective = locate() in ninja_antag.objectives
|
||||
if(objective && objective.doors_required <= hacking_module.door_hack_counter)
|
||||
objective.completed = TRUE
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
//WIRE//
|
||||
/obj/structure/cable/ninjadrain_act(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module)
|
||||
if(!ninja || !hacking_module)
|
||||
return NONE
|
||||
INVOKE_ASYNC(src, .proc/ninjadrain_charge, ninja, hacking_module)
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/obj/structure/cable/proc/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module)
|
||||
var/maxcapacity = FALSE //Safety check
|
||||
var/drain = 0 //Drain amount
|
||||
var/drain_total = 0
|
||||
var/datum/powernet/wire_powernet = powernet
|
||||
while(!maxcapacity && src)
|
||||
drain = (round((rand(hacking_module.mindrain, hacking_module.maxdrain))/2))
|
||||
var/drained = 0
|
||||
if(wire_powernet && do_after(ninja, 1 SECONDS, target = src))
|
||||
drained = min(drain, delayed_surplus())
|
||||
add_delayedload(drained)
|
||||
if(drained < drain)//if no power on net, drain apcs
|
||||
for(var/obj/machinery/power/terminal/affected_terminal in wire_powernet.nodes)
|
||||
if(istype(affected_terminal.master, /obj/machinery/power/apc))
|
||||
var/obj/machinery/power/apc/AP = affected_terminal.master
|
||||
if(AP.operating && AP.cell && AP.cell.charge > 0)
|
||||
AP.cell.charge = max(0, AP.cell.charge - 5)
|
||||
drained += 5
|
||||
else
|
||||
break
|
||||
if(hacking_module.mod.get_charge() + drain > hacking_module.mod.get_max_charge())
|
||||
drain = hacking_module.mod.get_max_charge() - hacking_module.mod.get_charge()
|
||||
maxcapacity = TRUE
|
||||
drain_total += drain
|
||||
hacking_module.mod.add_charge(drain)
|
||||
do_sparks(5, cardinal_only = FALSE, source = hacking_module.mod)
|
||||
hacking_module.charge_message(src, drain_total)
|
||||
|
||||
//MECH//
|
||||
/obj/vehicle/sealed/mecha/ninjadrain_act(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module)
|
||||
if(!ninja || !hacking_module)
|
||||
return NONE
|
||||
to_chat(occupants, "[icon2html(src, occupants)][span_danger("Warning: Unauthorized access through sub-route 4, block H, detected.")]")
|
||||
INVOKE_ASYNC(src, .proc/ninjadrain_charge, ninja, hacking_module)
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/obj/vehicle/sealed/mecha/proc/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module)
|
||||
var/maxcapacity = FALSE //Safety check
|
||||
var/drain = 0 //Drain amount
|
||||
var/drain_total = 0
|
||||
if(get_charge())
|
||||
while(cell.charge > 0 && !maxcapacity)
|
||||
drain = rand(hacking_module.mindrain, hacking_module.maxdrain)
|
||||
if(cell.charge < drain)
|
||||
drain = cell.charge
|
||||
if(hacking_module.mod.get_charge() + drain > hacking_module.mod.get_max_charge())
|
||||
drain = hacking_module.mod.get_max_charge() - hacking_module.mod.get_charge()
|
||||
maxcapacity = TRUE
|
||||
if (do_after(ninja, 1 SECONDS, target = src))
|
||||
spark_system.start()
|
||||
playsound(loc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
||||
cell.use(drain)
|
||||
hacking_module.mod.add_charge(drain)
|
||||
drain_total += drain
|
||||
else
|
||||
break
|
||||
hacking_module.charge_message(src, drain_total)
|
||||
|
||||
//BORG//
|
||||
/mob/living/silicon/robot/ninjadrain_act(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module)
|
||||
if(!ninja || !hacking_module || (ROLE_NINJA in faction))
|
||||
return NONE
|
||||
|
||||
to_chat(src, span_danger("Warni-***BZZZZZZZZZRT*** UPLOADING SPYDERPATCHER VERSION 9.5.2..."))
|
||||
INVOKE_ASYNC(src, .proc/ninjadrain_charge, ninja, hacking_module)
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/mob/living/silicon/robot/proc/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module)
|
||||
if(!do_after(ninja, 6 SECONDS, target = src))
|
||||
return
|
||||
spark_system.start()
|
||||
playsound(loc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
||||
to_chat(src, span_danger("UPLOAD COMPLETE. NEW CYBORG MODEL DETECTED. INSTALLING..."))
|
||||
faction = list(ROLE_NINJA)
|
||||
bubble_icon = "syndibot"
|
||||
UnlinkSelf()
|
||||
ionpulse = TRUE
|
||||
laws = new /datum/ai_laws/ninja_override()
|
||||
model.transform_to(pick(/obj/item/robot_model/syndicate, /obj/item/robot_model/syndicate_medical, /obj/item/robot_model/saboteur))
|
||||
|
||||
var/datum/antagonist/ninja/ninja_antag = ninja.mind.has_antag_datum(/datum/antagonist/ninja)
|
||||
if(!ninja_antag)
|
||||
return
|
||||
var/datum/objective/cyborg_hijack/objective = locate() in ninja_antag.objectives
|
||||
if(objective)
|
||||
objective.completed = TRUE
|
||||
|
||||
//CARBON MOBS//
|
||||
/mob/living/carbon/ninjadrain_act(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module)
|
||||
if(!ninja || !hacking_module)
|
||||
return NONE
|
||||
//Default cell = 10,000 charge, 10,000/1000 = 10 uses without charging/upgrading
|
||||
if(hacking_module.mod.subtract_charge(DEFAULT_CHARGE_DRAIN*10))
|
||||
//Got that electric touch
|
||||
var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread()
|
||||
spark_system.set_up(5, 0, loc)
|
||||
playsound(src, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
||||
visible_message(span_danger("[ninja] electrocutes [src] with [ninja.p_their()] touch!"), span_userdanger("[ninja] electrocutes you with [ninja.p_their()] touch!"))
|
||||
Knockdown(3 SECONDS)
|
||||
return NONE
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* # Ninja Mask
|
||||
*
|
||||
* Space ninja's mask. Other than looking cool, doesn't do anything.
|
||||
*
|
||||
* A mask which only spawns as a part of space ninja's starting kit. Functions as a gas mask.
|
||||
*
|
||||
*/
|
||||
/obj/item/clothing/mask/gas/ninja
|
||||
name = "ninja mask"
|
||||
desc = "A close-fitting nano-enhanced mask that acts both as an air filter and a post-modern fashion statement."
|
||||
icon_state = "ninja"
|
||||
strip_delay = 12 SECONDS
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
flags_inv = HIDEFACIALHAIR | HIDEFACE | HIDESNOUT
|
||||
flags_cover = MASKCOVERSMOUTH | PEPPERPROOF
|
||||
has_fov = FALSE
|
||||
|
||||
/obj/item/clothing/under/syndicate/ninja
|
||||
name = "ninja suit"
|
||||
desc = "A nano-enhanced jumpsuit designed for maximum comfort and tacticality."
|
||||
icon_state = "ninja_suit"
|
||||
strip_delay = 12 SECONDS
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
can_adjust = FALSE
|
||||
@@ -60,7 +60,6 @@
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
if (isnull(ninja))
|
||||
return
|
||||
var/datum/antagonist/ninja/ninja_antag = ninja.mind.has_antag_datum(/datum/antagonist/ninja)
|
||||
|
||||
@@ -1,27 +1,3 @@
|
||||
/datum/action/item_action/ninjastar
|
||||
name = "Create Throwing Stars (1E)"
|
||||
desc = "Creates a throwing star in your hand, if possible."
|
||||
button_icon_state = "throwingstar"
|
||||
icon_icon = 'icons/obj/items_and_weapons.dmi'
|
||||
|
||||
/**
|
||||
* Proc called to create a ninja star in the ninja's hands.
|
||||
*
|
||||
* Called to create a ninja star in the wearer's hand. The ninja
|
||||
* star doesn't do much up-front damage, but deals stamina damage
|
||||
* as the target moves around, forcing a finish or flee scenario.
|
||||
*/
|
||||
/obj/item/clothing/suit/space/space_ninja/proc/ninjastar()
|
||||
if(ninjacost(10))
|
||||
return
|
||||
var/mob/living/carbon/human/ninja = affecting
|
||||
var/obj/item/throwing_star/stamina/ninja/ninja_star = new(ninja)
|
||||
if(ninja.put_in_hands(ninja_star))
|
||||
to_chat(ninja, span_notice("A throwing star has been created in your hand!"))
|
||||
else
|
||||
qdel(ninja_star)
|
||||
to_chat(ninja, span_notice("You can't create a throwing star, your hands are full!"))
|
||||
|
||||
/**
|
||||
* # Ninja Throwing Star
|
||||
*
|
||||
@@ -1,25 +1,33 @@
|
||||
/datum/outfit/ninja
|
||||
name = "Space Ninja"
|
||||
uniform = /obj/item/clothing/under/color/black
|
||||
suit = /obj/item/clothing/suit/space/space_ninja
|
||||
uniform = /obj/item/clothing/under/syndicate/ninja
|
||||
glasses = /obj/item/clothing/glasses/night
|
||||
mask = /obj/item/clothing/mask/gas/space_ninja
|
||||
head = /obj/item/clothing/head/helmet/space/space_ninja
|
||||
mask = /obj/item/clothing/mask/gas/ninja
|
||||
ears = /obj/item/radio/headset
|
||||
shoes = /obj/item/clothing/shoes/space_ninja
|
||||
gloves = /obj/item/clothing/gloves/space_ninja
|
||||
shoes = /obj/item/clothing/shoes/jackboots
|
||||
l_pocket = /obj/item/grenade/c4/ninja
|
||||
r_pocket = /obj/item/tank/internals/emergency_oxygen
|
||||
internals_slot = ITEM_SLOT_RPOCKET
|
||||
belt = /obj/item/energy_katana
|
||||
back = /obj/item/mod/control/pre_equipped/ninja
|
||||
implants = list(/obj/item/implant/explosive)
|
||||
|
||||
/datum/outfit/ninja/post_equip(mob/living/carbon/human/ninja)
|
||||
var/obj/item/grenade/c4/ninja/charge = ninja.l_store
|
||||
if(istype(charge))
|
||||
charge.set_detonation_area(ninja.mind?.has_antag_datum(/datum/antagonist/ninja))
|
||||
var/obj/item/mod/control/mod = ninja.back
|
||||
if(!istype(mod))
|
||||
return
|
||||
var/obj/item/mod/module/dna_lock/reinforced/lock = locate(/obj/item/mod/module/dna_lock/reinforced) in mod.modules
|
||||
lock.dna = ninja.dna.unique_enzymes
|
||||
var/obj/item/mod/module/weapon_recall/recall = locate(/obj/item/mod/module/weapon_recall) in mod.modules
|
||||
var/obj/item/weapon = ninja.belt
|
||||
if(!istype(weapon, recall.accepted_type))
|
||||
return
|
||||
recall.set_weapon(weapon)
|
||||
|
||||
/datum/outfit/ninja/post_equip(mob/living/carbon/human/human)
|
||||
if(istype(human.wear_suit, suit))
|
||||
var/obj/item/clothing/suit/space/space_ninja/ninja_suit = human.wear_suit
|
||||
if(istype(human.belt, belt))
|
||||
ninja_suit.energyKatana = human.belt
|
||||
if(istype(human.l_store, l_pocket))
|
||||
var/obj/item/grenade/c4/ninja/charge = human.l_store
|
||||
charge.set_detonation_area(human.mind?.has_antag_datum(/datum/antagonist/ninja))
|
||||
/datum/outfit/ninja_preview
|
||||
uniform = /obj/item/clothing/under/syndicate/ninja
|
||||
back = /obj/item/mod/control/pre_equipped/empty/ninja
|
||||
belt = /obj/item/energy_katana
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
/**
|
||||
* # Ninja Gloves
|
||||
*
|
||||
* Space ninja's gloves. Gives access to a number of special interactions.
|
||||
*
|
||||
* Gloves only found from space ninjas. Allows the wearer to access special interactions with various objects.
|
||||
* These interactions are detailed in ninjaDrainAct.dm in the suit file.
|
||||
* These interactions are toggled by an action tied to the gloves. The interactions will not activate if the user is also not wearing a ninja suit.
|
||||
*
|
||||
*/
|
||||
/obj/item/clothing/gloves/space_ninja
|
||||
desc = "These nano-enhanced gloves insulate from electricity and provide fire resistance."
|
||||
name = "ninja gloves"
|
||||
icon_state = "black"
|
||||
inhand_icon_state = "s-ninjan"
|
||||
siemens_coefficient = 0
|
||||
cold_protection = HANDS
|
||||
min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT
|
||||
heat_protection = HANDS
|
||||
max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
|
||||
strip_delay = 120
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
armor = list(MELEE = 40, BULLET = 30, LASER = 20, ENERGY = 15, BOMB = 30, BIO = 100, FIRE = 100, ACID = 100)
|
||||
///Whether or not we're currently draining something
|
||||
var/draining = FALSE
|
||||
///Minimum amount of power we can drain in a single drain action
|
||||
var/mindrain = 200
|
||||
///Maximum amount of power we can drain in a single drain action
|
||||
var/maxdrain = 400
|
||||
///Whether or not the communication console hack was used to summon another antagonist
|
||||
var/communication_console_hack_success = FALSE
|
||||
///How many times the gloves have been used to force open doors.
|
||||
var/door_hack_counter = 0
|
||||
|
||||
|
||||
/obj/item/clothing/gloves/space_ninja/Touch(atom/A,proximity,modifiers)
|
||||
if(!LAZYACCESS(modifiers, RIGHT_CLICK) || draining)
|
||||
return FALSE
|
||||
if(!ishuman(loc))
|
||||
return FALSE //Only works while worn
|
||||
|
||||
var/mob/living/carbon/human/wearer = loc
|
||||
|
||||
var/obj/item/clothing/suit/space/space_ninja/suit = wearer.wear_suit
|
||||
if(!istype(suit))
|
||||
return FALSE
|
||||
if(isturf(A))
|
||||
return FALSE
|
||||
|
||||
if(!proximity)
|
||||
return FALSE
|
||||
|
||||
A.add_fingerprint(wearer)
|
||||
|
||||
draining = TRUE
|
||||
. = A.ninjadrain_act(suit,wearer,src)
|
||||
draining = FALSE
|
||||
|
||||
if(isnum(.)) //Numerical values of drained handle their feedback here, Alpha values handle it themselves (Research hacking)
|
||||
if(.)
|
||||
to_chat(wearer, span_notice("Gained <B>[display_energy(.)]</B> of energy from [A]."))
|
||||
else
|
||||
to_chat(wearer, span_danger("\The [A] has run dry of energy, you must find another source!"))
|
||||
else
|
||||
. = FALSE //as to not cancel attack_hand()
|
||||
|
||||
/obj/item/clothing/gloves/space_ninja/examine(mob/user)
|
||||
. = ..() + "[p_their(TRUE)] energy drain mechanism is activated by touching objects in a disarming manner."
|
||||
@@ -1,18 +0,0 @@
|
||||
/**
|
||||
* # Ninja Hood
|
||||
*
|
||||
* Space ninja's hood. Provides armor and blocks AI tracking.
|
||||
*
|
||||
* A hood that only exists as a part of space ninja's starting kit. Provides armor equal of space ninja's suit and disallows an AI to track the wearer.
|
||||
*
|
||||
*/
|
||||
/obj/item/clothing/head/helmet/space/space_ninja
|
||||
desc = "What may appear to be a simple black garment is in fact a highly sophisticated nano-weave helmet. Standard issue ninja gear."
|
||||
name = "ninja hood"
|
||||
icon_state = "s-ninja"
|
||||
inhand_icon_state = "s-ninja_mask"
|
||||
armor = list(MELEE = 40, BULLET = 30, LASER = 20,ENERGY = 15, BOMB = 30, BIO = 100, FIRE = 100, ACID = 100)
|
||||
strip_delay = 12
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
blockTracking = TRUE//Roughly the only unique thing about this helmet.
|
||||
flags_inv = HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR
|
||||
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* # Ninja Mask
|
||||
*
|
||||
* Space ninja's mask. Other than looking cool, doesn't do anything.
|
||||
*
|
||||
* A mask which only spawns as a part of space ninja's starting kit. Functions as a gas mask.
|
||||
*
|
||||
*/
|
||||
/obj/item/clothing/mask/gas/space_ninja
|
||||
name = "ninja mask"
|
||||
desc = "A close-fitting mask that acts both as an air filter and a post-modern fashion statement."
|
||||
icon_state = "s-ninja"
|
||||
inhand_icon_state = "s-ninja_mask"
|
||||
strip_delay = 120
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
has_fov = FALSE
|
||||
@@ -1,311 +0,0 @@
|
||||
/**
|
||||
* Atom level proc for space ninja's glove interactions.
|
||||
*
|
||||
* Proc which only occurs when space ninja uses his gloves on an atom.
|
||||
* Does nothing by default, but effects will vary.
|
||||
* Arguments:
|
||||
* * ninja_suit - The offending space ninja's suit.
|
||||
* * ninja - The human mob wearing the suit.
|
||||
* * ninja_gloves - The offending space ninja's gloves.
|
||||
*/
|
||||
/atom/proc/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves)
|
||||
return INVALID_DRAIN
|
||||
|
||||
//APC//
|
||||
/obj/machinery/power/apc/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves)
|
||||
if(!ninja_suit || !ninja || !ninja_gloves)
|
||||
return INVALID_DRAIN
|
||||
|
||||
var/maxcapacity = FALSE //Safety check for batteries
|
||||
var/drain = 0 //Drain amount from batteries
|
||||
var/drain_total = 0
|
||||
|
||||
if(cell?.charge)
|
||||
var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread()
|
||||
spark_system.set_up(5, 0, loc)
|
||||
|
||||
while(cell.charge> 0 && !maxcapacity)
|
||||
drain = rand(ninja_gloves.mindrain, ninja_gloves.maxdrain)
|
||||
|
||||
if(cell.charge < drain)
|
||||
drain = cell.charge
|
||||
|
||||
if(ninja_suit.cell.charge + drain > ninja_suit.cell.maxcharge)
|
||||
drain = ninja_suit.cell.maxcharge - ninja_suit.cell.charge
|
||||
maxcapacity = TRUE//Reached maximum battery capacity.
|
||||
|
||||
if (do_after(ninja ,10, target = src))
|
||||
spark_system.start()
|
||||
playsound(loc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
||||
cell.use(drain)
|
||||
ninja_suit.cell.give(drain)
|
||||
drain_total += drain
|
||||
else
|
||||
break
|
||||
|
||||
if(!(obj_flags & EMAGGED))
|
||||
flick("apc-spark", ninja_gloves)
|
||||
playsound(loc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
||||
obj_flags |= EMAGGED
|
||||
locked = FALSE
|
||||
update_appearance()
|
||||
|
||||
return drain_total
|
||||
|
||||
//SMES//
|
||||
/obj/machinery/power/smes/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves)
|
||||
if(!ninja_suit || !ninja || !ninja_gloves)
|
||||
return INVALID_DRAIN
|
||||
|
||||
var/maxcapacity = FALSE //Safety check for batteries
|
||||
var/drain = 0 //Drain amount from batteries
|
||||
var/drain_total = 0
|
||||
|
||||
if(charge)
|
||||
var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread()
|
||||
spark_system.set_up(5, 0, loc)
|
||||
|
||||
while(charge > 0 && !maxcapacity)
|
||||
drain = rand(ninja_gloves.mindrain, ninja_gloves.maxdrain)
|
||||
|
||||
if(charge < drain)
|
||||
drain = charge
|
||||
|
||||
if(ninja_suit.cell.charge + drain > ninja_suit.cell.maxcharge)
|
||||
drain = ninja_suit.cell.maxcharge - ninja_suit.cell.charge
|
||||
maxcapacity = TRUE
|
||||
|
||||
if (do_after(ninja,10, target = src))
|
||||
spark_system.start()
|
||||
playsound(loc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
||||
charge -= drain
|
||||
ninja_suit.cell.give(drain)
|
||||
drain_total += drain
|
||||
|
||||
else
|
||||
break
|
||||
|
||||
return drain_total
|
||||
|
||||
//CELL//
|
||||
/obj/item/stock_parts/cell/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves)
|
||||
if(!ninja_suit || !ninja || !ninja_gloves)
|
||||
return INVALID_DRAIN
|
||||
|
||||
var/drain_total = 0
|
||||
|
||||
if(charge)
|
||||
if(do_after(ninja, 30, target = src))
|
||||
drain_total = charge
|
||||
if(ninja_suit.cell.charge + charge > ninja_suit.cell.maxcharge)
|
||||
ninja_suit.cell.charge = ninja_suit.cell.maxcharge
|
||||
else
|
||||
ninja_suit.cell.give(charge)
|
||||
charge = 0
|
||||
corrupt()
|
||||
update_appearance()
|
||||
|
||||
return drain_total
|
||||
|
||||
//RD SERVER//
|
||||
/obj/machinery/rnd/server/master/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves)
|
||||
if(!ninja_suit || !ninja || !ninja_gloves)
|
||||
return INVALID_DRAIN
|
||||
|
||||
. = DRAIN_RD_HACK_FAILED
|
||||
|
||||
// If the traitor theft objective is still present, this will destroy it...
|
||||
if(!source_code_hdd)
|
||||
return ..()
|
||||
|
||||
to_chat(ninja, span_notice("Hacking \the [src]..."))
|
||||
AI_notify_hack()
|
||||
to_chat(ninja, span_notice("Encrypted source code detected. Overloading storage device..."))
|
||||
if(do_after(ninja, 30 SECONDS, target = src))
|
||||
overload_source_code_hdd()
|
||||
to_chat(ninja, span_notice("Sabotage complete. Storage device overloaded."))
|
||||
var/datum/antagonist/ninja/ninja_antag = ninja.mind.has_antag_datum(/datum/antagonist/ninja)
|
||||
if(!ninja_antag)
|
||||
return
|
||||
var/datum/objective/research_secrets/objective = locate() in ninja_antag.objectives
|
||||
if(objective)
|
||||
objective.completed = TRUE
|
||||
|
||||
/obj/machinery/rnd/server/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves)
|
||||
if(!ninja_suit || !ninja || !ninja_gloves)
|
||||
return INVALID_DRAIN
|
||||
|
||||
. = DRAIN_RD_HACK_FAILED
|
||||
|
||||
to_chat(ninja, span_notice("Research notes detected. Corrupting data..."))
|
||||
|
||||
if(!do_after(ninja, 30 SECONDS, target = src))
|
||||
return
|
||||
|
||||
SSresearch.science_tech.modify_points_all(0)
|
||||
to_chat(ninja, span_notice("Sabotage complete. Research notes corrupted."))
|
||||
var/datum/antagonist/ninja/ninja_antag = ninja.mind.has_antag_datum(/datum/antagonist/ninja)
|
||||
if(!ninja_antag)
|
||||
return
|
||||
var/datum/objective/research_secrets/objective = locate() in ninja_antag.objectives
|
||||
if(objective)
|
||||
objective.completed = TRUE
|
||||
|
||||
//SECURITY CONSOLE//
|
||||
/obj/machinery/computer/secure_data/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves)
|
||||
if(!ninja_suit || !ninja || !ninja_gloves)
|
||||
return INVALID_DRAIN
|
||||
AI_notify_hack()
|
||||
if(do_after(ninja, 200))
|
||||
for(var/datum/data/record/rec in sort_record(GLOB.data_core.general, sortBy, order))
|
||||
for(var/datum/data/record/security_record in GLOB.data_core.security)
|
||||
security_record.fields["criminal"] = "*Arrest*"
|
||||
var/datum/antagonist/ninja/ninja_antag = ninja.mind.has_antag_datum(/datum/antagonist/ninja)
|
||||
if(!ninja_antag)
|
||||
return
|
||||
var/datum/objective/security_scramble/objective = locate() in ninja_antag.objectives
|
||||
if(objective)
|
||||
objective.completed = TRUE
|
||||
|
||||
//COMMUNICATIONS CONSOLE//
|
||||
/obj/machinery/computer/communications/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves)
|
||||
if(!ninja_suit || !ninja || !ninja_gloves)
|
||||
return INVALID_DRAIN
|
||||
if(ninja_gloves.communication_console_hack_success)
|
||||
return
|
||||
if(machine_stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
AI_notify_hack()
|
||||
if(!do_after(ninja, 30 SECONDS, src))
|
||||
return
|
||||
hack_console(ninja)
|
||||
ninja_gloves.communication_console_hack_success = TRUE
|
||||
var/datum/antagonist/ninja/ninja_antag = ninja.mind.has_antag_datum(/datum/antagonist/ninja)
|
||||
if(!ninja_antag)
|
||||
return
|
||||
var/datum/objective/terror_message/objective = locate() in ninja_antag.objectives
|
||||
if(objective)
|
||||
objective.completed = TRUE
|
||||
|
||||
//AIRLOCK//
|
||||
/obj/machinery/door/airlock/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves)
|
||||
if(!ninja_suit || !ninja || !ninja_gloves)
|
||||
return INVALID_DRAIN
|
||||
|
||||
if(!operating && density && hasPower() && !(obj_flags & EMAGGED))
|
||||
emag_act()
|
||||
ninja_gloves.door_hack_counter++
|
||||
var/datum/antagonist/ninja/ninja_antag = ninja.mind.has_antag_datum(/datum/antagonist/ninja)
|
||||
if(!ninja_antag)
|
||||
return
|
||||
var/datum/objective/door_jack/objective = locate() in ninja_antag.objectives
|
||||
if(objective && objective.doors_required <= ninja_gloves.door_hack_counter)
|
||||
objective.completed = TRUE
|
||||
|
||||
//WIRE//
|
||||
/obj/structure/cable/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves)
|
||||
if(!ninja_suit || !ninja || !ninja_gloves)
|
||||
return INVALID_DRAIN
|
||||
|
||||
var/maxcapacity = FALSE //Safety check
|
||||
var/drain = 0 //Drain amount
|
||||
|
||||
var/drain_total = 0
|
||||
|
||||
var/datum/powernet/wire_powernet = powernet
|
||||
while(!maxcapacity && src)
|
||||
drain = (round((rand(ninja_gloves.mindrain, ninja_gloves.maxdrain))/2))
|
||||
var/drained = 0
|
||||
if(wire_powernet && do_after(ninja ,10, target = src))
|
||||
drained = min(drain, delayed_surplus())
|
||||
add_delayedload(drained)
|
||||
if(drained < drain)//if no power on net, drain apcs
|
||||
for(var/obj/machinery/power/terminal/affected_terminal in wire_powernet.nodes)
|
||||
if(istype(affected_terminal.master, /obj/machinery/power/apc))
|
||||
var/obj/machinery/power/apc/AP = affected_terminal.master
|
||||
if(AP.operating && AP.cell && AP.cell.charge > 0)
|
||||
AP.cell.charge = max(0, AP.cell.charge - 5)
|
||||
drained += 5
|
||||
else
|
||||
break
|
||||
|
||||
ninja_suit.cell.give(drain)
|
||||
if(ninja_suit.cell.charge > ninja_suit.cell.maxcharge)
|
||||
drain_total += (drained-(ninja_suit.cell.charge - ninja_suit.cell.maxcharge))
|
||||
ninja_suit.cell.charge = ninja_suit.cell.maxcharge
|
||||
maxcapacity = TRUE
|
||||
else
|
||||
drain_total += drained
|
||||
ninja_suit.spark_system.start()
|
||||
|
||||
return drain_total
|
||||
|
||||
//MECH//
|
||||
/obj/vehicle/sealed/mecha/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves)
|
||||
if(!ninja_suit || !ninja || !ninja_gloves)
|
||||
return INVALID_DRAIN
|
||||
|
||||
var/maxcapacity = FALSE //Safety check
|
||||
var/drain = 0 //Drain amount
|
||||
var/drain_total = 0
|
||||
|
||||
to_chat(occupants, "[icon2html(src, occupants)][span_danger("Warning: Unauthorized access through sub-route 4, block H, detected.")]")
|
||||
if(get_charge())
|
||||
while(cell.charge > 0 && !maxcapacity)
|
||||
drain = rand(ninja_gloves.mindrain, ninja_gloves.maxdrain)
|
||||
if(cell.charge < drain)
|
||||
drain = cell.charge
|
||||
if(ninja_suit.cell.charge + drain > ninja_suit.cell.maxcharge)
|
||||
drain = ninja_suit.cell.maxcharge - ninja_suit.cell.charge
|
||||
maxcapacity = TRUE
|
||||
if (do_after(ninja, 10, target = src))
|
||||
spark_system.start()
|
||||
playsound(loc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
||||
cell.use(drain)
|
||||
ninja_suit.cell.give(drain)
|
||||
drain_total += drain
|
||||
else
|
||||
break
|
||||
|
||||
return drain_total
|
||||
|
||||
//BORG//
|
||||
/mob/living/silicon/robot/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves)
|
||||
if(!ninja_suit || !ninja || !ninja_gloves || (ROLE_NINJA in faction))
|
||||
return INVALID_DRAIN
|
||||
|
||||
to_chat(src, span_danger("Warni-***BZZZZZZZZZRT*** UPLOADING SPYDERPATCHER VERSION 9.5.2..."))
|
||||
if (do_after(ninja, 60, target = src))
|
||||
spark_system.start()
|
||||
playsound(loc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
||||
to_chat(src, span_danger("UPLOAD COMPLETE. NEW CYBORG MODEL DETECTED. INSTALLING..."))
|
||||
faction = list(ROLE_NINJA)
|
||||
bubble_icon = "syndibot"
|
||||
UnlinkSelf()
|
||||
ionpulse = TRUE
|
||||
laws = new /datum/ai_laws/ninja_override()
|
||||
model.transform_to(pick(/obj/item/robot_model/syndicate, /obj/item/robot_model/syndicate_medical, /obj/item/robot_model/saboteur))
|
||||
|
||||
var/datum/antagonist/ninja/ninja_antag = ninja.mind.has_antag_datum(/datum/antagonist/ninja)
|
||||
if(!ninja_antag)
|
||||
return
|
||||
var/datum/objective/cyborg_hijack/objective = locate() in ninja_antag.objectives
|
||||
if(objective)
|
||||
objective.completed = TRUE
|
||||
|
||||
//CARBON MOBS//
|
||||
/mob/living/carbon/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves)
|
||||
if(!ninja_suit || !ninja || !ninja_gloves)
|
||||
return INVALID_DRAIN
|
||||
|
||||
. = DRAIN_MOB_SHOCK_FAILED
|
||||
|
||||
//Default cell = 10,000 charge, 10,000/1000 = 10 uses without charging/upgrading
|
||||
if(ninja_suit.cell?.charge && ninja_suit.cell.use(1000))
|
||||
. = DRAIN_MOB_SHOCK
|
||||
//Got that electric touch
|
||||
var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread()
|
||||
spark_system.set_up(5, 0, loc)
|
||||
playsound(src, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
||||
visible_message(span_danger("[ninja] electrocutes [src] with [ninja.p_their()] touch!"), span_userdanger("[ninja] electrocutes you with [ninja.p_their()] touch!"))
|
||||
Knockdown(3 SECONDS)
|
||||
@@ -1,45 +0,0 @@
|
||||
//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.
|
||||
|
||||
/datum/action/item_action/ninjaboost
|
||||
check_flags = NONE
|
||||
name = "Adrenaline Boost"
|
||||
desc = "Inject a secret chemical that will counteract all movement-impairing effect."
|
||||
button_icon_state = "repulse"
|
||||
icon_icon = 'icons/mob/actions/actions_spells.dmi'
|
||||
|
||||
/**
|
||||
* Proc called to activate space ninja's adrenaline.
|
||||
*
|
||||
* Proc called to use space ninja's adrenaline. Gets the ninja out of almost any stun.
|
||||
* Also makes them shout MGS references when used. After a bit, it injects the user with
|
||||
* radium by calling a different proc.
|
||||
*/
|
||||
/obj/item/clothing/suit/space/space_ninja/proc/ninjaboost()
|
||||
if(ninjacost(0,N_ADRENALINE))
|
||||
return
|
||||
var/mob/living/carbon/human/ninja = affecting
|
||||
ninja.SetUnconscious(0)
|
||||
ninja.SetStun(0)
|
||||
ninja.SetKnockdown(0)
|
||||
ninja.SetImmobilized(0)
|
||||
ninja.SetParalyzed(0)
|
||||
ninja.adjustStaminaLoss(-200)
|
||||
ninja.remove_status_effect(/datum/status_effect/speech/stutter)
|
||||
ninja.reagents.add_reagent(/datum/reagent/medicine/stimulants, 5)
|
||||
ninja.say(pick("A CORNERED FOX IS MORE DANGEROUS THAN A JACKAL!","HURT ME MOOORRREEE!","IMPRESSIVE!"), forced = "ninjaboost")
|
||||
a_boost = FALSE
|
||||
to_chat(ninja, span_notice("You have used the adrenaline boost."))
|
||||
s_coold = 6
|
||||
addtimer(CALLBACK(src, .proc/ninjaboost_after), 70)
|
||||
|
||||
/**
|
||||
* Proc called to inject the ninja with radium.
|
||||
*
|
||||
* Used after 7 seconds of using the ninja's adrenaline.
|
||||
* Injects the user with how much radium the suit needs to refill an adrenaline boost.
|
||||
*/
|
||||
/obj/item/clothing/suit/space/space_ninja/proc/ninjaboost_after()
|
||||
var/mob/living/carbon/human/ninja = affecting
|
||||
ninja.reagents.add_reagent(/datum/reagent/uranium/radium, a_transfer * 0.25)
|
||||
to_chat(ninja, span_danger("You are beginning to feel the after-effect of the injection."))
|
||||
@@ -1,28 +0,0 @@
|
||||
/**
|
||||
* Proc called to check if the ninja can afford an ability's cost.
|
||||
*
|
||||
* Proc which determine whether or not a space ninja can afford to use a specific ability.
|
||||
* It can also cancel stealth if the ability requested it.
|
||||
* Arguments:
|
||||
* * cost - the energy cost of the ability
|
||||
* * specificCheck - Determines if the check is a normal one, an adrenaline one, or a stealth cancel check.
|
||||
* * Returns TRUE or the current cooldown timer if we can't perform the ability, and FALSE if we can.
|
||||
*/
|
||||
/obj/item/clothing/suit/space/space_ninja/proc/ninjacost(cost = 0, specificCheck = 0)
|
||||
var/mob/living/carbon/human/ninja = affecting
|
||||
var/actualCost = cost*10
|
||||
if(cost && cell.charge < actualCost)
|
||||
to_chat(ninja, span_warning("Not enough energy!"))
|
||||
return TRUE
|
||||
else
|
||||
//This shit used to be handled individually on every proc.. why even bother with a universal check proc then?
|
||||
cell.charge-=(actualCost)
|
||||
|
||||
switch(specificCheck)
|
||||
if(N_STEALTH_CANCEL)
|
||||
cancel_stealth()//Get rid of it.
|
||||
if(N_ADRENALINE)
|
||||
if(!a_boost)
|
||||
to_chat(ninja, span_warning("You do not have any more adrenaline boosters!"))
|
||||
return TRUE
|
||||
return (s_coold)//Returns the value of the variable which counts down to zero.
|
||||
@@ -1,21 +0,0 @@
|
||||
//Disables nearby tech equipment.
|
||||
|
||||
/datum/action/item_action/ninjapulse
|
||||
name = "EM Burst (50E)"
|
||||
desc = "Disable any nearby technology with an electro-magnetic pulse."
|
||||
button_icon_state = "emp"
|
||||
icon_icon = 'icons/mob/actions/actions_spells.dmi'
|
||||
|
||||
/**
|
||||
* Proc called to allow the ninja to EMP the nearby area.
|
||||
*
|
||||
* Proc called to allow the ninja to EMP the nearby area. By default, costs 500E, which is half of the default battery's max charge.
|
||||
* Also affects the ninja as well.
|
||||
*/
|
||||
/obj/item/clothing/suit/space/space_ninja/proc/ninjapulse()
|
||||
if(ninjacost(500,N_STEALTH_CANCEL))
|
||||
return
|
||||
var/mob/living/carbon/human/H = affecting
|
||||
playsound(H.loc, 'sound/effects/empulse.ogg', 60, 2)
|
||||
empulse(H, 4, 6) //Procs sure are nice. Slightly weaker than wizard's disable tch.
|
||||
s_coold = 4
|
||||
@@ -1,42 +0,0 @@
|
||||
/datum/action/item_action/ninjanet
|
||||
name = "Energy Net (40E)"
|
||||
desc = "Captures a fallen opponent in a net of energy."
|
||||
button_icon_state = "energynet"
|
||||
icon_icon = 'icons/effects/effects.dmi'
|
||||
|
||||
/**
|
||||
* Proc called to ensnare a person in a energy net.
|
||||
*
|
||||
* Used to ensnare a target in an energy net, preventing them from moving until the net is broken.
|
||||
* Costs 40E, which is 40% of the default battery's max charge. Intended as a means of reliably locking down an opponent when ninja stars won't suffice.
|
||||
*/
|
||||
/obj/item/clothing/suit/space/space_ninja/proc/ninjanet()
|
||||
var/mob/living/carbon/human/ninja = affecting
|
||||
var/list/nearby_targets = list()
|
||||
for(var/mob/living/target in oview(ninja))
|
||||
nearby_targets.Add(target)
|
||||
if(!length(nearby_targets))
|
||||
to_chat(ninja, span_warning("You see no one nearby to ensnare."))
|
||||
return
|
||||
var/mob/living/net_target = tgui_input_list(ninja, "Select who to capture", "Capture Target", sort_names(nearby_targets))
|
||||
if(isnull(net_target))
|
||||
return
|
||||
if(QDELETED(net_target) || !(net_target in oview(ninja)) || !isliving(net_target) || ninja.incapacitated())
|
||||
return
|
||||
if(locate(/obj/structure/energy_net) in get_turf(net_target))//Check if they are already being affected by an energy net.
|
||||
to_chat(ninja, span_warning("[net_target.p_they(TRUE)] are already trapped inside an energy net!"))
|
||||
return
|
||||
for(var/turf/between_turf in get_line(get_turf(ninja), get_turf(net_target)))
|
||||
if(between_turf.density)//Don't want them shooting nets through walls. It's kind of cheesy.
|
||||
to_chat(ninja, span_warning("You may not use an energy net through solid obstacles!"))
|
||||
return
|
||||
if(!ninjacost(400,N_STEALTH_CANCEL))
|
||||
ninja.Beam(net_target, "n_beam", time = 15)
|
||||
ninja.say("Get over here!", forced = "ninja net")
|
||||
var/obj/structure/energy_net/net = new /obj/structure/energy_net(net_target.drop_location())
|
||||
net.affected_mob = net_target
|
||||
ninja.visible_message(span_danger("[ninja] caught [net_target] with an energy net!"),span_notice("You caught [net_target] with an energy net!"))
|
||||
|
||||
if(net_target.buckled)
|
||||
net_target.buckled.unbuckle_mob(affecting,TRUE)
|
||||
net.buckle_mob(net_target, TRUE) //No moving for you!
|
||||
@@ -1,38 +0,0 @@
|
||||
/datum/action/item_action/ninjastatus
|
||||
check_flags = NONE
|
||||
name = "Status Readout"
|
||||
desc = "Gives a detailed readout about your current status."
|
||||
button_icon_state = "health"
|
||||
icon_icon = 'icons/obj/device.dmi'
|
||||
|
||||
/**
|
||||
* Proc called to put a status readout to the ninja in chat.
|
||||
*
|
||||
* Called put some information about the ninja's current status into chat.
|
||||
* This information used to be displayed constantly on the status tab screen
|
||||
* when the suit was on, but was turned into this as to remove the code from
|
||||
* human.dm
|
||||
*/
|
||||
/obj/item/clothing/suit/space/space_ninja/proc/ninjastatus()
|
||||
var/mob/living/carbon/human/ninja = affecting
|
||||
var/list/info_list = list()
|
||||
info_list += "[span_info("SpiderOS Status: [s_initialized ? "Initialized" : "Disabled"]")]\n"
|
||||
info_list += "[span_info("Current Time: [station_time_timestamp()]")]\n"
|
||||
//Ninja status
|
||||
info_list += "[span_info("Fingerprints: [md5(ninja.dna.unique_identity)]")]\n"
|
||||
info_list += "[span_info("Unique Identity: [ninja.dna.unique_enzymes]")]\n"
|
||||
info_list += "[span_info("Overall Status: [ninja.stat > 1 ? "dead" : "[ninja.health]% healthy"]")]\n"
|
||||
info_list += "[span_info("Nutrition Status: [ninja.nutrition]")]\n"
|
||||
info_list += "[span_info("Oxygen Loss: [ninja.getOxyLoss()]")]\n"
|
||||
info_list += "[span_info("Toxin Levels: [ninja.getToxLoss()]")]\n"
|
||||
info_list += "[span_info("Burn Severity: [ninja.getFireLoss()]")]\n"
|
||||
info_list += "[span_info("Brute Trauma: [ninja.getBruteLoss()]")]\n"
|
||||
info_list += "[span_info("Body Temperature: [ninja.bodytemperature-T0C] degrees C ([ninja.bodytemperature*1.8-459.67] degrees F)")]\n"
|
||||
|
||||
//Diseases
|
||||
if(length(ninja.diseases))
|
||||
info_list += "Viruses:"
|
||||
for(var/datum/disease/ninja_disease in ninja.diseases)
|
||||
info_list += "[span_info("* [ninja_disease.name], Type: [ninja_disease.spread_text], Stage: [ninja_disease.stage]/[ninja_disease.max_stages], Possible Cure: [ninja_disease.cure_text]")]\n"
|
||||
|
||||
to_chat(ninja, "[info_list.Join()]")
|
||||
@@ -1,46 +0,0 @@
|
||||
/datum/action/item_action/ninja_stealth
|
||||
name = "Toggle Stealth"
|
||||
desc = "Toggles stealth mode on and off."
|
||||
button_icon_state = "ninja_cloak"
|
||||
icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
|
||||
|
||||
/**
|
||||
* Proc called to toggle ninja stealth.
|
||||
*
|
||||
* Proc called to toggle whether or not the ninja is in stealth mode.
|
||||
* If cancelling, calls a separate proc in case something else needs to quickly cancel stealth.
|
||||
*/
|
||||
/obj/item/clothing/suit/space/space_ninja/proc/toggle_stealth()
|
||||
var/mob/living/carbon/human/ninja = affecting
|
||||
if(!ninja)
|
||||
return
|
||||
if(stealth)
|
||||
cancel_stealth()
|
||||
else
|
||||
if(cell.charge <= 0)
|
||||
to_chat(ninja, span_warning("You don't have enough power to enable Stealth!"))
|
||||
return
|
||||
stealth = !stealth
|
||||
animate(ninja, alpha = 20,time = 12)
|
||||
ninja.visible_message(span_warning("[ninja.name] vanishes into thin air!"), \
|
||||
span_notice("You are now mostly invisible to normal detection."))
|
||||
|
||||
/**
|
||||
* Proc called to cancel stealth.
|
||||
*
|
||||
* Called to cancel the stealth effect if it is ongoing.
|
||||
* Does nothing otherwise.
|
||||
* Arguments:
|
||||
* * Returns false if either the ninja no longer exists or is already visible, returns true if we successfully made the ninja visible.
|
||||
*/
|
||||
/obj/item/clothing/suit/space/space_ninja/proc/cancel_stealth()
|
||||
var/mob/living/carbon/human/ninja = affecting
|
||||
if(!ninja)
|
||||
return FALSE
|
||||
if(stealth)
|
||||
stealth = !stealth
|
||||
animate(ninja, alpha = 255, time = 12)
|
||||
ninja.visible_message(span_warning("[ninja.name] appears from thin air!"), \
|
||||
span_notice("You are now visible."))
|
||||
return TRUE
|
||||
return FALSE
|
||||
@@ -1,125 +0,0 @@
|
||||
#define NINJA_LOCK_PHASE 1
|
||||
#define NINJA_ICON_GENERATE_PHASE 3
|
||||
#define NINJA_COMPLETE_PHASE 6
|
||||
#define NINJA_DEINIT_LOGOFF_PHASE 1
|
||||
#define NINJA_DEINIT_STEALTH_PHASE 5
|
||||
|
||||
GLOBAL_LIST_INIT(ninja_initialize_messages, list(
|
||||
"Now initializing...",
|
||||
"Securing external locking mechanism...\nNeural-net established.",
|
||||
"Extending neural-net interface...\nNow monitoring brain wave pattern...",
|
||||
"Linking neural-net interface...\nPattern <b class='nicegreen'>GREEN</b>, continuing operation.",
|
||||
"VOID-shift device status: <B>ONLINE</B>.\nCLOAK-tech device status: <B>ONLINE</B>.",
|
||||
"Primary system status: <B>ONLINE</B>.\nBackup system status: <B>ONLINE</B>.\nCurrent energy capacity: ",
|
||||
"All systems operational. Welcome to <B>SpiderOS</B>, "
|
||||
))
|
||||
|
||||
GLOBAL_LIST_INIT(ninja_deinitialize_messages, list(
|
||||
"Now de-initializing...",
|
||||
"Shutting down <B>SpiderOS</B>.",
|
||||
"Primary system status: <B>OFFLINE</B>.\nBackup system status: <B>OFFLINE</B>.",
|
||||
"VOID-shift device status: <B>OFFLINE</B>.\nCLOAK-tech device status: <B>OFFLINE</B>.",
|
||||
"Disconnecting neural-net interface...<b class='nicegreen'>Success</b>.",
|
||||
"Disengaging neural-net interface... <b class='nicegreen'>Success</b>.",
|
||||
"Unsecuring external locking mechanism...\nNeural-net abolished.\nOperation status: <B>FINISHED</B>."
|
||||
))
|
||||
|
||||
/datum/action/item_action/initialize_ninja_suit
|
||||
name = "Toggle Ninja Suit"
|
||||
|
||||
/**
|
||||
* Toggles the ninja suit on/off
|
||||
*
|
||||
* Attempts to initialize or deinitialize the ninja suit
|
||||
*/
|
||||
/obj/item/clothing/suit/space/space_ninja/proc/toggle_on_off()
|
||||
. = TRUE
|
||||
if(s_busy)
|
||||
to_chat(loc, "[span_warning("ERROR")]: You cannot use this function at this time.")
|
||||
return FALSE
|
||||
s_busy = TRUE
|
||||
if(s_initialized)
|
||||
deinitialize()
|
||||
else
|
||||
ninitialize()
|
||||
|
||||
/**
|
||||
* Initializes the ninja suit
|
||||
*
|
||||
* Initializes the ninja suit through seven phases, each of which calls this proc with an incremented phase
|
||||
* Arguments:
|
||||
* * delay - The delay between each phase of initialization
|
||||
* * ninja - The human who is being affected by the suit
|
||||
* * phase - The phase of initialization
|
||||
*/
|
||||
/obj/item/clothing/suit/space/space_ninja/proc/ninitialize(delay = s_delay, mob/living/carbon/human/ninja = loc, phase = 0)
|
||||
if(!ninja || !ninja.mind)
|
||||
s_busy = FALSE
|
||||
return
|
||||
if (phase > NINJA_LOCK_PHASE && (ninja.stat == DEAD || ninja.health <= 0))
|
||||
to_chat(ninja, span_danger("<B>FÄAL �Rr�R</B>: 344--93#�&&21 BR��N |/|/aV� PATT$RN <B>RED</B>\nA-A-aB�rT�NG..."))
|
||||
unlock_suit(ninja)
|
||||
s_busy = FALSE
|
||||
return
|
||||
|
||||
var/message = GLOB.ninja_initialize_messages[phase + 1]
|
||||
switch(phase)
|
||||
if (NINJA_LOCK_PHASE)
|
||||
if(!lock_suit(ninja))//To lock the suit onto wearer.
|
||||
s_busy = FALSE
|
||||
return
|
||||
if (NINJA_ICON_GENERATE_PHASE)
|
||||
lockIcons(ninja)//Check for icons.
|
||||
ninja.regenerate_icons()
|
||||
if (NINJA_COMPLETE_PHASE - 1)
|
||||
message += "<B>[display_energy(cell.charge)]</B>."
|
||||
if (NINJA_COMPLETE_PHASE)
|
||||
message += "[ninja.real_name]."
|
||||
s_initialized = TRUE
|
||||
s_busy = FALSE
|
||||
|
||||
to_chat(ninja, span_notice("[message]"))
|
||||
playsound(ninja, 'sound/effects/sparks1.ogg', 10, TRUE)
|
||||
|
||||
if (phase < NINJA_COMPLETE_PHASE)
|
||||
addtimer(CALLBACK(src, .proc/ninitialize, delay, ninja, phase + 1), delay)
|
||||
|
||||
/**
|
||||
* Deinitializes the ninja suit
|
||||
*
|
||||
* Deinitializes the ninja suit through eight phases, each of which calls this proc with an incremented phase
|
||||
* Arguments:
|
||||
* * delay - The delay between each phase of deinitialization
|
||||
* * ninja - The human who is being affected by the suit
|
||||
* * phase - The phase of deinitialization
|
||||
*/
|
||||
/obj/item/clothing/suit/space/space_ninja/proc/deinitialize(delay = s_delay, mob/living/carbon/human/ninja = affecting == loc ? affecting : null, phase = 0)
|
||||
if (!ninja || !ninja.mind)
|
||||
s_busy = FALSE
|
||||
return
|
||||
if (phase == 0 && tgui_alert(usr, "Are you certain you wish to remove the suit? This will take time and remove all abilities.",,list("Yes","No")) == "No")
|
||||
s_busy = FALSE
|
||||
return
|
||||
|
||||
var/message = GLOB.ninja_deinitialize_messages[phase + 1]
|
||||
switch(phase)
|
||||
if(NINJA_DEINIT_LOGOFF_PHASE)
|
||||
message = "Logging off, [ninja.real_name]. " + message
|
||||
if(NINJA_DEINIT_STEALTH_PHASE)
|
||||
cancel_stealth()
|
||||
to_chat(ninja, span_notice("[message]"))
|
||||
playsound(ninja, 'sound/items/deconstruct.ogg', 10, TRUE)
|
||||
|
||||
if (phase < NINJA_COMPLETE_PHASE)
|
||||
addtimer(CALLBACK(src, .proc/deinitialize, delay, ninja, phase + 1), delay)
|
||||
else
|
||||
unlock_suit(ninja)
|
||||
ninja.regenerate_icons()
|
||||
s_initialized = FALSE
|
||||
s_busy = FALSE
|
||||
|
||||
#undef NINJA_LOCK_PHASE
|
||||
#undef NINJA_ICON_GENERATE_PHASE
|
||||
#undef NINJA_COMPLETE_PHASE
|
||||
#undef NINJA_DEINIT_LOGOFF_PHASE
|
||||
#undef NINJA_DEINIT_STEALTH_PHASE
|
||||
@@ -1,47 +0,0 @@
|
||||
/datum/action/item_action/ninja_sword_recall
|
||||
name = "Recall Energy Katana (Variable Cost)"
|
||||
desc = "Teleports the Energy Katana linked to this suit to its wearer, cost based on distance."
|
||||
button_icon_state = "energy_katana"
|
||||
icon_icon = 'icons/obj/items_and_weapons.dmi'
|
||||
|
||||
/**
|
||||
* Proc called to recall the ninja's sword.
|
||||
*
|
||||
* Called to summon the ninja's katana back to them
|
||||
* If the katana can see the ninja, it will throw itself towards them.
|
||||
* If not, the katana will teleport itself to the ninja.
|
||||
*/
|
||||
/obj/item/clothing/suit/space/space_ninja/proc/ninja_sword_recall()
|
||||
var/mob/living/carbon/human/ninja = affecting
|
||||
var/cost = 0
|
||||
var/inview = TRUE
|
||||
|
||||
if(!energyKatana)
|
||||
to_chat(ninja, span_warning("Could not locate Energy Katana!"))
|
||||
return
|
||||
|
||||
if(energyKatana in ninja)
|
||||
return
|
||||
|
||||
var/distance = get_dist(ninja,energyKatana)
|
||||
|
||||
if(!(energyKatana in view(ninja)))
|
||||
cost = distance //Actual cost is cost x 10, so 5 turfs is 50 cost.
|
||||
inview = FALSE
|
||||
|
||||
if(!ninjacost(cost))
|
||||
if(iscarbon(energyKatana.loc))
|
||||
var/mob/living/carbon/sword_holder = energyKatana.loc
|
||||
sword_holder.transferItemToLoc(energyKatana, get_turf(energyKatana), TRUE)
|
||||
|
||||
else
|
||||
energyKatana.forceMove(get_turf(energyKatana))
|
||||
|
||||
if(inview) //If we can see the katana, throw it towards ourselves, damaging people as we go.
|
||||
energyKatana.spark_system.start()
|
||||
playsound(ninja, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
||||
ninja.visible_message(span_danger("\the [energyKatana] flies towards [ninja]!"),span_warning("You hold out your hand and \the [energyKatana] flies towards you!"))
|
||||
energyKatana.throw_at(ninja, distance+1, energyKatana.throw_speed, ninja)
|
||||
|
||||
else //Else just TP it to us.
|
||||
energyKatana.returnToOwner(ninja, 1)
|
||||
@@ -1,23 +0,0 @@
|
||||
/**
|
||||
* # Ninja Shoes
|
||||
*
|
||||
* Space ninja's shoes. Gives him armor on his feet.
|
||||
*
|
||||
* Space ninja's ninja shoes. How mousey. Gives him slip protection and protection against attacks.
|
||||
* Also are temperature resistant.
|
||||
*
|
||||
*/
|
||||
/obj/item/clothing/shoes/space_ninja
|
||||
name = "ninja shoes"
|
||||
desc = "A pair of running shoes. Excellent for running and even better for smashing skulls."
|
||||
icon_state = "s-ninja"
|
||||
inhand_icon_state = "secshoes"
|
||||
clothing_flags = NOSLIP
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
armor = list(MELEE = 40, BULLET = 30, LASER = 20, ENERGY = 15, BOMB = 30, BIO = 100, FIRE = 100, ACID = 100)
|
||||
strip_delay = 120
|
||||
cold_protection = FEET
|
||||
min_cold_protection_temperature = SHOES_MIN_TEMP_PROTECT
|
||||
heat_protection = FEET
|
||||
max_heat_protection_temperature = SHOES_MAX_TEMP_PROTECT
|
||||
slowdown = -1
|
||||
@@ -1,255 +0,0 @@
|
||||
/**
|
||||
* # Ninja Suit
|
||||
*
|
||||
* Space ninja's suit. Provides him with most of his powers.
|
||||
*
|
||||
* Space ninja's suit. Gives space ninja all his iconic powers, which are mostly kept in
|
||||
* the folder ninja_equipment_actions. Has a lot of unique stuff going on, so make sure to check
|
||||
* the variables. Check suit_attackby to see radium interaction, disk copying, and cell replacement.
|
||||
*
|
||||
*/
|
||||
/obj/item/clothing/suit/space/space_ninja
|
||||
name = "ninja suit"
|
||||
desc = "A unique, vacuum-proof suit of nano-enhanced armor designed specifically for Spider Clan assassins."
|
||||
icon_state = "s-ninja"
|
||||
inhand_icon_state = "s-ninja_suit"
|
||||
allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/restraints/handcuffs, /obj/item/tank/internals, /obj/item/stock_parts/cell)
|
||||
resistance_flags = LAVA_PROOF | ACID_PROOF
|
||||
armor = list(MELEE = 40, BULLET = 30, LASER = 20,ENERGY = 30, BOMB = 30, BIO = 100, FIRE = 100, ACID = 100)
|
||||
strip_delay = 12
|
||||
min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT
|
||||
actions_types = list(/datum/action/item_action/initialize_ninja_suit, /datum/action/item_action/ninjastatus, /datum/action/item_action/ninjaboost, /datum/action/item_action/ninjapulse, /datum/action/item_action/ninjastar, /datum/action/item_action/ninjanet, /datum/action/item_action/ninja_sword_recall, /datum/action/item_action/ninja_stealth)
|
||||
|
||||
///The person wearing the suit
|
||||
var/mob/living/carbon/human/affecting = null
|
||||
///The suit's spark system, used for... sparking.
|
||||
var/datum/effect_system/spark_spread/spark_system
|
||||
///The suit's stored research. Used for the research objective (see antagonist file)
|
||||
var/datum/techweb/stored_research
|
||||
///The katana registered with the suit, used for recalling and catching the katana. Set when the ninja outfit is created.
|
||||
var/obj/item/energy_katana/energyKatana
|
||||
|
||||
///The space ninja's hood.
|
||||
var/obj/item/clothing/head/helmet/space/space_ninja/n_hood
|
||||
///The space ninja's shoes.
|
||||
var/obj/item/clothing/shoes/space_ninja/n_shoes
|
||||
///The space ninja's gloves.
|
||||
var/obj/item/clothing/gloves/space_ninja/n_gloves
|
||||
///The space ninja's mask.
|
||||
var/obj/item/clothing/mask/gas/space_ninja/n_mask
|
||||
|
||||
///Whether or not the suit is currently booted up. Starts off.
|
||||
var/s_initialized = FALSE//Suit starts off.
|
||||
///The suit's current cooldown. If not 0, blocks usage of most abilities, and decrements its value by 1 every process
|
||||
var/s_coold = 0
|
||||
///How much energy the suit expends in a single process
|
||||
var/s_cost = 1
|
||||
///Additional energy cost for cloaking per process
|
||||
var/s_acost = 4
|
||||
///How fast the suit is at certain actions, like draining power from things
|
||||
var/s_delay = 40
|
||||
///Units of radium required to refill the adrenaline boost
|
||||
var/a_transfer = 20//How much radium is required to refill the adrenaline boost.
|
||||
///Whether or not the suit is currently in stealth mode.
|
||||
var/stealth = FALSE//Stealth off.
|
||||
///Whether or not the wearer is in the middle of an action, like hacking.
|
||||
var/s_busy = FALSE
|
||||
///Whether or not the adrenaline boost ability is available
|
||||
var/a_boost = TRUE
|
||||
|
||||
/obj/item/clothing/suit/space/space_ninja/examine(mob/user)
|
||||
. = ..()
|
||||
if(!s_initialized)
|
||||
return
|
||||
if(!user == affecting)
|
||||
return
|
||||
. += "All systems operational. Current energy capacity: <B>[display_energy(cell.charge)]</B>.\n"+\
|
||||
"The CLOAK-tech device is <B>[stealth?"active":"inactive"]</B>.\n"+\
|
||||
"[a_boost?"An adrenaline boost is available to use.":"There is no adrenaline boost available. Try refilling the suit with 20 units of radium."]"
|
||||
|
||||
/obj/item/clothing/suit/space/space_ninja/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
//Spark Init
|
||||
spark_system = new
|
||||
spark_system.set_up(5, 0, src)
|
||||
spark_system.attach(src)
|
||||
|
||||
//Research Init
|
||||
stored_research = new()
|
||||
|
||||
//Cell Init
|
||||
cell = new/obj/item/stock_parts/cell/high
|
||||
cell.charge = 9000
|
||||
cell.name = "black power cell"
|
||||
cell.icon_state = "bscell"
|
||||
|
||||
/obj/item/clothing/suit/space/space_ninja/Destroy()
|
||||
QDEL_NULL(spark_system)
|
||||
QDEL_NULL(cell)
|
||||
return ..()
|
||||
|
||||
// seal the cell in the ninja outfit
|
||||
/obj/item/clothing/suit/space/space_ninja/toggle_spacesuit_cell(mob/user)
|
||||
return
|
||||
|
||||
// Space Suit temperature regulation and power usage
|
||||
/obj/item/clothing/suit/space/space_ninja/process(delta_time)
|
||||
var/mob/living/carbon/human/user = src.loc
|
||||
if(!user || !ishuman(user) || !(user.wear_suit == src))
|
||||
return
|
||||
|
||||
// Check for energy usage
|
||||
if(s_initialized)
|
||||
if(!affecting)
|
||||
terminate() // Kills the suit and attached objects.
|
||||
else if(cell.charge > 0)
|
||||
if(s_coold > 0)
|
||||
s_coold = max(s_coold - delta_time, 0) // Checks for ability s_cooldown first.
|
||||
cell.charge -= s_cost * delta_time // s_cost is the default energy cost each ntick, usually 5.
|
||||
if(stealth) // If stealth is active.
|
||||
cell.charge -= s_acost * delta_time
|
||||
else
|
||||
cell.charge = 0
|
||||
cancel_stealth()
|
||||
|
||||
user.adjust_bodytemperature(BODYTEMP_NORMAL - user.bodytemperature)
|
||||
|
||||
/obj/item/clothing/suit/space/space_ninja/ui_action_click(mob/user, action)
|
||||
if(IS_NINJA_SUIT_INITIALIZATION(action))
|
||||
toggle_on_off()
|
||||
return TRUE
|
||||
if(!s_initialized)
|
||||
to_chat(user, span_warning("<b>ERROR</b>: suit offline. Please activate suit."))
|
||||
return FALSE
|
||||
if(s_coold > 0)
|
||||
to_chat(user, span_warning("<b>ERROR</b>: suit is on cooldown."))
|
||||
return FALSE
|
||||
if(IS_NINJA_SUIT_STATUS(action))
|
||||
ninjastatus()
|
||||
return TRUE
|
||||
if(IS_NINJA_SUIT_BOOST(action))
|
||||
ninjaboost()
|
||||
return TRUE
|
||||
if(IS_NINJA_SUIT_EMP(action))
|
||||
ninjapulse()
|
||||
return TRUE
|
||||
if(IS_NINJA_SUIT_STAR_CREATION(action))
|
||||
ninjastar()
|
||||
return TRUE
|
||||
if(IS_NINJA_SUIT_NET_CREATION(action))
|
||||
ninjanet()
|
||||
return TRUE
|
||||
if(IS_NINJA_SUIT_SWORD_RECALL(action))
|
||||
ninja_sword_recall()
|
||||
return TRUE
|
||||
if(IS_NINJA_SUIT_STEALTH(action))
|
||||
toggle_stealth()
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/clothing/suit/space/space_ninja/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
|
||||
. = ..()
|
||||
if(stealth)
|
||||
cancel_stealth()
|
||||
s_coold = 5
|
||||
|
||||
/**
|
||||
* Proc for changing the suit's appearance upon locking.
|
||||
*
|
||||
* Proc for when space ninja's suit locks. If the user selects Original, gives it glowing lights, along with having an alternate sprite for female body types.
|
||||
* Yes, we do have nipLEDs, how could you tell?
|
||||
* If the user selects New Age, it applies new sprites to all the gear.
|
||||
* Arguments:
|
||||
* * ninja - The person wearing the suit.
|
||||
*/
|
||||
/obj/item/clothing/suit/space/space_ninja/proc/lockIcons(mob/living/carbon/human/ninja)
|
||||
var/design_choice = tgui_alert(ninja, "Please choose your desired suit design.",,list("Original","New Age"))
|
||||
switch(design_choice)
|
||||
if("Original")
|
||||
icon_state = ninja.physique == "female" ? "s-ninjanf" : "s-ninjan"
|
||||
ninja.gloves.icon_state = "s-ninjan"
|
||||
ninja.gloves.inhand_icon_state = "s-ninjan"
|
||||
if("New Age")
|
||||
icon_state ="ninja_new"
|
||||
n_hood.icon_state = "ninja_newcowl"
|
||||
n_gloves.icon_state = "ninja_new"
|
||||
if(n_mask)
|
||||
n_mask.icon_state = "ninja_new"
|
||||
|
||||
|
||||
/**
|
||||
* Proc called to lock the important gear pieces onto space ninja's body.
|
||||
*
|
||||
* Called during the suit startup to lock all gear pieces onto space ninja.
|
||||
* Terminates if a gear piece is not being worn. Also gives the ninja the inability to use firearms.
|
||||
* If the person in the suit isn't a ninja when this is called, this proc just gibs them instead.
|
||||
* Arguments:
|
||||
* * ninja - The person wearing the suit.
|
||||
* * Returns false if the locking fails due to lack of all suit parts, and true if it succeeds.
|
||||
*/
|
||||
/obj/item/clothing/suit/space/space_ninja/proc/lock_suit(mob/living/carbon/human/ninja)
|
||||
if(!istype(ninja))
|
||||
return FALSE
|
||||
if(!IS_SPACE_NINJA(ninja))
|
||||
to_chat(ninja, span_danger("<B>fÄTaL ÈÈRRoR</B>: 382200-*#00CÖDE <B>RED</B>\nUNAUHORIZED USÈ DETÈCeD\nCoMMÈNCING SUB-R0UIN3 13...\nTÈRMInATING U-U-USÈR..."))
|
||||
ninja.gib()
|
||||
return FALSE
|
||||
if(!istype(ninja.head, /obj/item/clothing/head/helmet/space/space_ninja))
|
||||
to_chat(ninja, "[span_userdanger("ERROR")]: 100113 UNABLE TO LOCATE HEAD GEAR\nABORTING...")
|
||||
return FALSE
|
||||
if(!istype(ninja.shoes, /obj/item/clothing/shoes/space_ninja))
|
||||
to_chat(ninja, "[span_userdanger("ERROR")]: 122011 UNABLE TO LOCATE FOOT GEAR\nABORTING...")
|
||||
return FALSE
|
||||
if(!istype(ninja.gloves, /obj/item/clothing/gloves/space_ninja))
|
||||
to_chat(ninja, "[span_userdanger("ERROR")]: 110223 UNABLE TO LOCATE HAND GEAR\nABORTING...")
|
||||
return FALSE
|
||||
affecting = ninja
|
||||
ADD_TRAIT(src, TRAIT_NODROP, NINJA_SUIT_TRAIT)
|
||||
n_hood = ninja.head
|
||||
ADD_TRAIT(n_hood, TRAIT_NODROP, NINJA_SUIT_TRAIT)
|
||||
n_shoes = ninja.shoes
|
||||
ADD_TRAIT(n_shoes, TRAIT_NODROP, NINJA_SUIT_TRAIT)
|
||||
n_gloves = ninja.gloves
|
||||
ADD_TRAIT(n_gloves, TRAIT_NODROP, NINJA_SUIT_TRAIT)
|
||||
n_mask = ninja.wear_mask
|
||||
|
||||
ADD_TRAIT(ninja, TRAIT_NOGUNS, NINJA_SUIT_TRAIT)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Proc called to unlock all the gear off space ninja's body.
|
||||
*
|
||||
* Proc which is essentially the opposite of lock_suit. Lets you take off all the suit parts.
|
||||
* Also gets rid of the objection to using firearms from the wearer.
|
||||
* Arguments:
|
||||
* * ninja - The person wearing the suit.
|
||||
*/
|
||||
/obj/item/clothing/suit/space/space_ninja/proc/unlock_suit(mob/living/carbon/human/ninja)
|
||||
affecting = null
|
||||
REMOVE_TRAIT(src, TRAIT_NODROP, NINJA_SUIT_TRAIT)
|
||||
icon_state = "s-ninja"
|
||||
if(n_hood)//Should be attached, might not be attached.
|
||||
REMOVE_TRAIT(n_hood, TRAIT_NODROP, NINJA_SUIT_TRAIT)
|
||||
n_hood.icon_state = "s-ninja"
|
||||
if(n_shoes)
|
||||
REMOVE_TRAIT(n_shoes, TRAIT_NODROP, NINJA_SUIT_TRAIT)
|
||||
if(n_gloves)
|
||||
n_gloves.icon_state = "black"
|
||||
REMOVE_TRAIT(n_gloves, TRAIT_NODROP, NINJA_SUIT_TRAIT)
|
||||
n_gloves.draining = FALSE
|
||||
|
||||
REMOVE_TRAIT(ninja, TRAIT_NOGUNS, NINJA_SUIT_TRAIT)
|
||||
if(n_mask)
|
||||
n_mask.icon_state = "s-ninja"
|
||||
|
||||
/**
|
||||
* Proc used to delete all the attachments and itself.
|
||||
*
|
||||
* Can be called to entire rid of the suit pieces and the suit itself.
|
||||
*/
|
||||
/obj/item/clothing/suit/space/space_ninja/proc/terminate()
|
||||
QDEL_NULL(n_hood)
|
||||
QDEL_NULL(n_gloves)
|
||||
QDEL_NULL(n_shoes)
|
||||
QDEL_NULL(src)
|
||||
@@ -1,50 +0,0 @@
|
||||
/obj/item/clothing/suit/space/space_ninja/attackby(obj/item/I, mob/ninja, params)
|
||||
if(ninja!=affecting)//Safety, in case you try doing this without wearing the suit/being the person with the suit.
|
||||
return ..()
|
||||
|
||||
if(istype(I, /obj/item/reagent_containers/glass) && I.reagents.has_reagent(/datum/reagent/uranium/radium, a_transfer) && a_boost != TRUE)//If it's a glass beaker, and what we're transferring is radium.
|
||||
I.reagents.remove_reagent(/datum/reagent/uranium/radium, a_transfer)
|
||||
a_boost = TRUE;
|
||||
to_chat(ninja, span_notice("The suit's adrenaline boost is now reloaded."))
|
||||
return
|
||||
|
||||
|
||||
else if(istype(I, /obj/item/stock_parts/cell))
|
||||
var/obj/item/stock_parts/cell/CELL = I
|
||||
if(CELL.maxcharge > cell.maxcharge)
|
||||
to_chat(ninja, span_notice("Higher maximum capacity detected.\nUpgrading..."))
|
||||
if (do_after(ninja,s_delay, target = src))
|
||||
ninja.transferItemToLoc(CELL, src)
|
||||
CELL.charge = min(CELL.charge+cell.charge, CELL.maxcharge)
|
||||
var/obj/item/stock_parts/cell/old_cell = cell
|
||||
old_cell.charge = 0
|
||||
ninja.put_in_hands(old_cell)
|
||||
old_cell.add_fingerprint(ninja)
|
||||
old_cell.corrupt()
|
||||
old_cell.update_appearance()
|
||||
cell = CELL
|
||||
to_chat(ninja, span_notice("Upgrade complete. Maximum capacity: <b>[round(cell.maxcharge/100)]</b>%"))
|
||||
else
|
||||
to_chat(ninja, span_danger("Procedure interrupted. Protocol terminated."))
|
||||
return
|
||||
|
||||
else if(istype(I, /obj/item/disk/tech_disk))//If it's a data disk, we want to copy the research on to the suit.
|
||||
var/obj/item/disk/tech_disk/TD = I
|
||||
var/has_research = FALSE
|
||||
for(var/node in TD.stored_research.researched_nodes)
|
||||
if(!stored_research.researched_nodes[node])
|
||||
has_research = TRUE
|
||||
break
|
||||
if(has_research)//If it has something on it.
|
||||
to_chat(ninja, span_notice("Research information detected, processing..."))
|
||||
if(do_after(ninja,s_delay, target = src))
|
||||
TD.stored_research.copy_research_to(stored_research)
|
||||
qdel(TD.stored_research)
|
||||
TD.stored_research = new
|
||||
to_chat(ninja, span_notice("Data analyzed and updated. Disk erased."))
|
||||
else
|
||||
to_chat(ninja, "[span_userdanger("ERROR")]: Procedure interrupted. Process terminated.")
|
||||
else
|
||||
to_chat(ninja, span_notice("No new research information detected."))
|
||||
return
|
||||
return ..()
|
||||
@@ -313,6 +313,13 @@
|
||||
name = "pulse pistol power cell"
|
||||
maxcharge = 2000
|
||||
|
||||
/obj/item/stock_parts/cell/ninja
|
||||
name = "black power cell"
|
||||
icon_state = "bscell"
|
||||
maxcharge = 10000
|
||||
custom_materials = list(/datum/material/glass=60)
|
||||
chargerate = 2000
|
||||
|
||||
/obj/item/stock_parts/cell/high
|
||||
name = "high-capacity power cell"
|
||||
icon_state = "hcell"
|
||||
|
||||
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 151 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 123 KiB |
|
Before Width: | Height: | Size: 318 KiB After Width: | Height: | Size: 320 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 115 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 5.4 KiB |
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"lines": [
|
||||
"A CORNERED FOX IS MORE DANGEROUS THAN A JACKAL!",
|
||||
"HURT ME MOOORRREEE!",
|
||||
"IMPRESSIVE!",
|
||||
"LET'S DANCE!",
|
||||
"I'M SAYING JACK IS BACK!",
|
||||
"I'M FUCKING INVINCIBLE!",
|
||||
"AHH. BETTER THAN ACUPUNCTURE!",
|
||||
"NO PAIN, NO GAIN. HAHAHAHAHA!",
|
||||
"BANZAI!!!"
|
||||
]
|
||||
}
|
||||
@@ -3607,6 +3607,7 @@
|
||||
#include "code\modules\mod\modules\modules_general.dm"
|
||||
#include "code\modules\mod\modules\modules_maint.dm"
|
||||
#include "code\modules\mod\modules\modules_medical.dm"
|
||||
#include "code\modules\mod\modules\modules_ninja.dm"
|
||||
#include "code\modules\mod\modules\modules_science.dm"
|
||||
#include "code\modules\mod\modules\modules_security.dm"
|
||||
#include "code\modules\mod\modules\modules_service.dm"
|
||||
@@ -3688,27 +3689,13 @@
|
||||
#include "code\modules\movespeed\modifiers\mobs.dm"
|
||||
#include "code\modules\movespeed\modifiers\reagent.dm"
|
||||
#include "code\modules\movespeed\modifiers\status_effects.dm"
|
||||
#include "code\modules\ninja\__ninjaDefines.dm"
|
||||
#include "code\modules\ninja\energy_katana.dm"
|
||||
#include "code\modules\ninja\energy_net_nets.dm"
|
||||
#include "code\modules\ninja\ninja_clothing.dm"
|
||||
#include "code\modules\ninja\ninja_explosive.dm"
|
||||
#include "code\modules\ninja\ninja_stars.dm"
|
||||
#include "code\modules\ninja\ninjaDrainAct.dm"
|
||||
#include "code\modules\ninja\outfit.dm"
|
||||
#include "code\modules\ninja\suit\gloves.dm"
|
||||
#include "code\modules\ninja\suit\head.dm"
|
||||
#include "code\modules\ninja\suit\mask.dm"
|
||||
#include "code\modules\ninja\suit\ninjaDrainAct.dm"
|
||||
#include "code\modules\ninja\suit\shoes.dm"
|
||||
#include "code\modules\ninja\suit\suit.dm"
|
||||
#include "code\modules\ninja\suit\suit_attackby.dm"
|
||||
#include "code\modules\ninja\suit\ninja_equipment_actions\energy_net_nets.dm"
|
||||
#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_adrenaline.dm"
|
||||
#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_cost_check.dm"
|
||||
#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_empulse.dm"
|
||||
#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_net.dm"
|
||||
#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_stars.dm"
|
||||
#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_status_read.dm"
|
||||
#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_stealth.dm"
|
||||
#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_suit_initialisation.dm"
|
||||
#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_sword_recall.dm"
|
||||
#include "code\modules\NTNet\netdata.dm"
|
||||
#include "code\modules\NTNet\network.dm"
|
||||
#include "code\modules\NTNet\relays.dm"
|
||||
|
||||
@@ -141,10 +141,10 @@ const HealthAnalyzer = (props, context) => {
|
||||
average: [0.2, 0.5],
|
||||
bad: [-Infinity, 0.2],
|
||||
}} >
|
||||
<AnimatedNumber value={userhealth} />
|
||||
<AnimatedNumber value={active ? userhealth : 0} />
|
||||
</ProgressBar>
|
||||
</Section>
|
||||
<Stack fill textAlign="center">
|
||||
<Stack textAlign="center">
|
||||
<Stack.Item grow>
|
||||
<Section title="Brute">
|
||||
<ProgressBar
|
||||
@@ -154,7 +154,7 @@ const HealthAnalyzer = (props, context) => {
|
||||
average: [0.2, 0.5],
|
||||
bad: [0.5, Infinity],
|
||||
}} >
|
||||
<AnimatedNumber value={userbrute} />
|
||||
<AnimatedNumber value={active ? userbrute : 0} />
|
||||
</ProgressBar>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
@@ -167,7 +167,7 @@ const HealthAnalyzer = (props, context) => {
|
||||
average: [0.2, 0.5],
|
||||
bad: [0.5, Infinity],
|
||||
}} >
|
||||
<AnimatedNumber value={userburn} />
|
||||
<AnimatedNumber value={active ? userburn : 0} />
|
||||
</ProgressBar>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
@@ -180,7 +180,7 @@ const HealthAnalyzer = (props, context) => {
|
||||
average: [0.2, 0.5],
|
||||
bad: [0.5, Infinity],
|
||||
}} >
|
||||
<AnimatedNumber value={usertoxin} />
|
||||
<AnimatedNumber value={active ? usertoxin : 0} />
|
||||
</ProgressBar>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
@@ -193,7 +193,7 @@ const HealthAnalyzer = (props, context) => {
|
||||
average: [0.2, 0.5],
|
||||
bad: [0.5, Infinity],
|
||||
}} >
|
||||
<AnimatedNumber value={useroxy} />
|
||||
<AnimatedNumber value={active ? useroxy : 0} />
|
||||
</ProgressBar>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
@@ -202,9 +202,191 @@ const HealthAnalyzer = (props, context) => {
|
||||
);
|
||||
};
|
||||
|
||||
const StatusReadout = (props, context) => {
|
||||
const {
|
||||
active,
|
||||
statustime,
|
||||
statusid,
|
||||
statushealth,
|
||||
statusmaxhealth,
|
||||
statusbrute,
|
||||
statusburn,
|
||||
statustoxin,
|
||||
statusoxy,
|
||||
statustemp,
|
||||
statusnutrition,
|
||||
statusfingerprints,
|
||||
statusdna,
|
||||
statusviruses,
|
||||
} = props;
|
||||
return (
|
||||
<>
|
||||
<Stack textAlign="center">
|
||||
<Stack.Item grow>
|
||||
<Section title="Operation Time">
|
||||
{active ? statustime : '00:00:00'}
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
<Stack.Item grow>
|
||||
<Section title="Operation Number">
|
||||
{active ? (statusid || '0') : '???'}
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
<Section title="Health">
|
||||
<ProgressBar
|
||||
value={active ? statushealth / statusmaxhealth : 0}
|
||||
ranges={{
|
||||
good: [0.5, Infinity],
|
||||
average: [0.2, 0.5],
|
||||
bad: [-Infinity, 0.2],
|
||||
}} >
|
||||
<AnimatedNumber value={active ? statushealth : 0} />
|
||||
</ProgressBar>
|
||||
</Section>
|
||||
<Stack textAlign="center">
|
||||
<Stack.Item grow>
|
||||
<Section title="Brute">
|
||||
<ProgressBar
|
||||
value={active ? statusbrute / statusmaxhealth : 0}
|
||||
ranges={{
|
||||
good: [-Infinity, 0.2],
|
||||
average: [0.2, 0.5],
|
||||
bad: [0.5, Infinity],
|
||||
}} >
|
||||
<AnimatedNumber value={active ? statusbrute : 0} />
|
||||
</ProgressBar>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
<Stack.Item grow>
|
||||
<Section title="Burn">
|
||||
<ProgressBar
|
||||
value={active ? statusburn / statusmaxhealth : 0}
|
||||
ranges={{
|
||||
good: [-Infinity, 0.2],
|
||||
average: [0.2, 0.5],
|
||||
bad: [0.5, Infinity],
|
||||
}} >
|
||||
<AnimatedNumber value={active ? statusburn : 0} />
|
||||
</ProgressBar>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
<Stack.Item grow>
|
||||
<Section title="Toxin">
|
||||
<ProgressBar
|
||||
value={active ? statustoxin / statusmaxhealth : 0}
|
||||
ranges={{
|
||||
good: [-Infinity, 0.2],
|
||||
average: [0.2, 0.5],
|
||||
bad: [0.5, Infinity],
|
||||
}} >
|
||||
<AnimatedNumber value={statustoxin} />
|
||||
</ProgressBar>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
<Stack.Item grow>
|
||||
<Section title="Suffocation">
|
||||
<ProgressBar
|
||||
value={active ? statusoxy / statusmaxhealth : 0}
|
||||
ranges={{
|
||||
good: [-Infinity, 0.2],
|
||||
average: [0.2, 0.5],
|
||||
bad: [0.5, Infinity],
|
||||
}} >
|
||||
<AnimatedNumber value={statusoxy} />
|
||||
</ProgressBar>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
<Stack textAlign="center">
|
||||
<Stack.Item grow>
|
||||
<Section title="Body Temperature">
|
||||
{active ? statustemp : 0}
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
<Stack.Item grow>
|
||||
<Section title="Nutrition Status">
|
||||
{active ? statusnutrition : 0}
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
<Section title="DNA">
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Fingerprints">
|
||||
{active ? statusfingerprints : "???"}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Unique Enzymes">
|
||||
{active ? statusdna : "???"}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
{!!active && !!statusviruses && (
|
||||
<Section title="Diseases">
|
||||
<Table>
|
||||
<Table.Row
|
||||
header>
|
||||
<Table.Cell
|
||||
textAlign="center">
|
||||
<Button
|
||||
color="transparent"
|
||||
icon="signature"
|
||||
tooltip="Name"
|
||||
tooltipPosition="top" />
|
||||
</Table.Cell>
|
||||
<Table.Cell
|
||||
textAlign="center">
|
||||
<Button
|
||||
color="transparent"
|
||||
icon="wind"
|
||||
tooltip="Type"
|
||||
tooltipPosition="top" />
|
||||
</Table.Cell>
|
||||
<Table.Cell
|
||||
textAlign="center">
|
||||
<Button
|
||||
color="transparent"
|
||||
icon="bolt"
|
||||
tooltip="Stage"
|
||||
tooltipPosition="top" />
|
||||
</Table.Cell>
|
||||
<Table.Cell
|
||||
textAlign="center">
|
||||
<Button
|
||||
color="transparent"
|
||||
icon="flask"
|
||||
tooltip="Cure"
|
||||
tooltipPosition="top" />
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{statusviruses.map(virus => {
|
||||
return (
|
||||
<Table.Row key={virus.name}>
|
||||
<Table.Cell textAlign="center">
|
||||
{virus.name}
|
||||
</Table.Cell>
|
||||
<Table.Cell textAlign="center">
|
||||
{virus.type}
|
||||
</Table.Cell>
|
||||
<Table.Cell textAlign="center">
|
||||
{virus.stage}/{virus.maxstage}
|
||||
</Table.Cell>
|
||||
<Table.Cell textAlign="center">
|
||||
{virus.cure}
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
);
|
||||
})}
|
||||
</Table>
|
||||
</Section>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const ID2MODULE = {
|
||||
rad_counter: RadCounter,
|
||||
health_analyzer: HealthAnalyzer,
|
||||
status_readout: StatusReadout,
|
||||
};
|
||||
|
||||
const LockedInterface = () => (
|
||||
@@ -440,7 +622,7 @@ const ModuleSection = (props, context) => {
|
||||
return (
|
||||
<Flex.Item key={module.ref} >
|
||||
<Collapsible
|
||||
title={module.name} >
|
||||
title={module.module_name} >
|
||||
<Section>
|
||||
{configureState === module.ref && (
|
||||
<ConfigureScreen
|
||||
@@ -501,7 +683,7 @@ const ModuleSection = (props, context) => {
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell textAlign="center">
|
||||
{module.complexity}/{complexity_max}
|
||||
{module.module_complexity}/{complexity_max}
|
||||
</Table.Cell>
|
||||
<Table.Cell textAlign="center">
|
||||
{module.idle_power}
|
||||
@@ -523,7 +705,7 @@ const ModuleSection = (props, context) => {
|
||||
<Button
|
||||
onClick={() => act('select', { "ref": module.ref })}
|
||||
icon="bullseye"
|
||||
selected={module.active}
|
||||
selected={module.module_active}
|
||||
tooltip={displayText(module.module_type)}
|
||||
tooltipPosition="left"
|
||||
disabled={!module.module_type} />
|
||||
|
||||