diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index 2fd41985569..6a50ffababc 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -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. diff --git a/code/__DEFINES/text.dm b/code/__DEFINES/text.dm index 89bf025b2d3..0b00b7dfc4b 100644 --- a/code/__DEFINES/text.dm +++ b/code/__DEFINES/text.dm @@ -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" diff --git a/code/_globalvars/phobias.dm b/code/_globalvars/phobias.dm index 5745f3bc8bb..453819c37cd 100644 --- a/code/_globalvars/phobias.dm +++ b/code/_globalvars/phobias.dm @@ -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, diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index c65e7aef65e..b618a313076 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -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) diff --git a/code/datums/dash_weapon.dm b/code/datums/dash_weapon.dm index d4251b414c9..f0062228e4b 100644 --- a/code/datums/dash_weapon.dm +++ b/code/datums/dash_weapon.dm @@ -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) diff --git a/code/datums/elements/digitalcamo.dm b/code/datums/elements/digitalcamo.dm index dcfbbd3b650..ccd82b9c8be 100644 --- a/code/datums/elements/digitalcamo.dm +++ b/code/datums/elements/digitalcamo.dm @@ -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 diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index a379108a77b..cf18d34f47f 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -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)) diff --git a/code/modules/antagonists/abductor/equipment/abduction_gear.dm b/code/modules/antagonists/abductor/equipment/abduction_gear.dm index 631226b25b3..47b89abbd87 100644 --- a/code/modules/antagonists/abductor/equipment/abduction_gear.dm +++ b/code/modules/antagonists/abductor/equipment/abduction_gear.dm @@ -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 diff --git a/code/modules/antagonists/nukeop/clownop.dm b/code/modules/antagonists/nukeop/clownop.dm index f0c476c2838..3bed41d605d 100644 --- a/code/modules/antagonists/nukeop/clownop.dm +++ b/code/modules/antagonists/nukeop/clownop.dm @@ -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) diff --git a/code/modules/antagonists/nukeop/nukeop.dm b/code/modules/antagonists/nukeop/nukeop.dm index 28e063d00dd..6658f62fe46 100644 --- a/code/modules/antagonists/nukeop/nukeop.dm +++ b/code/modules/antagonists/nukeop/nukeop.dm @@ -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 diff --git a/code/modules/antagonists/space_ninja/space_ninja.dm b/code/modules/antagonists/space_ninja/space_ninja.dm index 367214ef1f4..dfadacde7d0 100644 --- a/code/modules/antagonists/space_ninja/space_ninja.dm +++ b/code/modules/antagonists/space_ninja/space_ninja.dm @@ -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 diff --git a/code/modules/cargo/markets/market_items/clothing.dm b/code/modules/cargo/markets/market_items/clothing.dm index d750d66431d..fe715a5903c 100644 --- a/code/modules/cargo/markets/market_items/clothing.dm +++ b/code/modules/cargo/markets/market_items/clothing.dm @@ -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 diff --git a/code/modules/clothing/gloves/_gloves.dm b/code/modules/clothing/gloves/_gloves.dm index f1111075c2b..269a8541695 100644 --- a/code/modules/clothing/gloves/_gloves.dm +++ b/code/modules/clothing/gloves/_gloves.dm @@ -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) diff --git a/code/modules/clothing/head/_head.dm b/code/modules/clothing/head/_head.dm index fd298f3bb88..1dabbf0ee5d 100644 --- a/code/modules/clothing/head/_head.dm +++ b/code/modules/clothing/head/_head.dm @@ -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. diff --git a/code/modules/clothing/outfits/standard.dm b/code/modules/clothing/outfits/standard.dm index dc6bdacf739..40f8aba297c 100644 --- a/code/modules/clothing/outfits/standard.dm +++ b/code/modules/clothing/outfits/standard.dm @@ -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 diff --git a/code/modules/events/shuttle_loan.dm b/code/modules/events/shuttle_loan.dm index 50ee3ae8d03..8cadb3390ec 100644 --- a/code/modules/events/shuttle_loan.dm +++ b/code/modules/events/shuttle_loan.dm @@ -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) diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index 412556f42d4..fadb1f25482 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -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) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 17547597943..e665e40f84d 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -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) diff --git a/code/modules/mod/mod_control.dm b/code/modules/mod/mod_control.dm index d4bf56f5803..51c0a6924d8 100644 --- a/code/modules/mod/mod_control.dm +++ b/code/modules/mod/mod_control.dm @@ -216,6 +216,7 @@ . += span_notice("You could remove [ai] with an intellicard.") else . += span_notice("You could install an AI with an intellicard.") + . += span_notice("You could examine it more thoroughly...") /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 diff --git a/code/modules/mod/mod_core.dm b/code/modules/mod/mod_core.dm index 9d238ed0e2a..f72247f847e 100644 --- a/code/modules/mod/mod_core.dm +++ b/code/modules/mod/mod_core.dm @@ -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) diff --git a/code/modules/mod/mod_theme.dm b/code/modules/mod/mod_theme.dm index eddc7ab7f2a..d6ca4f8303b 100644 --- a/code/modules/mod/mod_theme.dm +++ b/code/modules/mod/mod_theme.dm @@ -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." diff --git a/code/modules/mod/mod_types.dm b/code/modules/mod/mod_types.dm index 9bc81a1246d..05943ab7ae3 100644 --- a/code/modules/mod/mod_types.dm +++ b/code/modules/mod/mod_types.dm @@ -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) diff --git a/code/modules/mod/mod_ui.dm b/code/modules/mod/mod_ui.dm index 9d70bef64d6..eda05225a85 100644 --- a/code/modules/mod/mod_ui.dm +++ b/code/modules/mod/mod_ui.dm @@ -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) diff --git a/code/modules/mod/modules/_module.dm b/code/modules/mod/modules/_module.dm index 1cf5b66269b..8296ac3a11e 100644 --- a/code/modules/mod/modules/_module.dm +++ b/code/modules/mod/modules/_module.dm @@ -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() diff --git a/code/modules/mod/modules/modules_engineering.dm b/code/modules/mod/modules/modules_engineering.dm index 87a5c18885a..6c0dc01610f 100644 --- a/code/modules/mod/modules/modules_engineering.dm +++ b/code/modules/mod/modules/modules_engineering.dm @@ -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) diff --git a/code/modules/mod/modules/modules_maint.dm b/code/modules/mod/modules/modules_maint.dm index dbaa539b696..da8d5e5578d 100644 --- a/code/modules/mod/modules/modules_maint.dm +++ b/code/modules/mod/modules/modules_maint.dm @@ -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 diff --git a/code/modules/mod/modules/modules_medical.dm b/code/modules/mod/modules/modules_medical.dm index 19284a966fc..0894caa103c 100644 --- a/code/modules/mod/modules/modules_medical.dm +++ b/code/modules/mod/modules/modules_medical.dm @@ -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) . = ..() diff --git a/code/modules/mod/modules/modules_ninja.dm b/code/modules/mod/modules/modules_ninja.dm new file mode 100644 index 00000000000..896d8cba86e --- /dev/null +++ b/code/modules/mod/modules/modules_ninja.dm @@ -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 [drain_amount] 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("fATaL EERRoR: 382200-*#00CODE RED\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.")) diff --git a/code/modules/mod/modules/modules_security.dm b/code/modules/mod/modules/modules_security.dm index 32376ec10d2..3055c242cbd 100644 --- a/code/modules/mod/modules/modules_security.dm +++ b/code/modules/mod/modules/modules_security.dm @@ -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" diff --git a/code/modules/ninja/__ninjaDefines.dm b/code/modules/ninja/__ninjaDefines.dm deleted file mode 100644 index 8414f9e4244..00000000000 --- a/code/modules/ninja/__ninjaDefines.dm +++ /dev/null @@ -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)) diff --git a/code/modules/ninja/energy_katana.dm b/code/modules/ninja/energy_katana.dm index b8d54857677..07200061ecd 100644 --- a/code/modules/ninja/energy_katana.dm +++ b/code/modules/ninja/energy_katana.dm @@ -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!" - 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 diff --git a/code/modules/ninja/suit/ninja_equipment_actions/energy_net_nets.dm b/code/modules/ninja/energy_net_nets.dm similarity index 100% rename from code/modules/ninja/suit/ninja_equipment_actions/energy_net_nets.dm rename to code/modules/ninja/energy_net_nets.dm diff --git a/code/modules/ninja/ninjaDrainAct.dm b/code/modules/ninja/ninjaDrainAct.dm new file mode 100644 index 00000000000..02e66652792 --- /dev/null +++ b/code/modules/ninja/ninjaDrainAct.dm @@ -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 diff --git a/code/modules/ninja/ninja_clothing.dm b/code/modules/ninja/ninja_clothing.dm new file mode 100644 index 00000000000..b093aa80016 --- /dev/null +++ b/code/modules/ninja/ninja_clothing.dm @@ -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 diff --git a/code/modules/ninja/ninja_explosive.dm b/code/modules/ninja/ninja_explosive.dm index b1a74baf73c..fc7e1e304ed 100644 --- a/code/modules/ninja/ninja_explosive.dm +++ b/code/modules/ninja/ninja_explosive.dm @@ -60,7 +60,6 @@ . = ..() if(!.) return - if (isnull(ninja)) return var/datum/antagonist/ninja/ninja_antag = ninja.mind.has_antag_datum(/datum/antagonist/ninja) diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_stars.dm b/code/modules/ninja/ninja_stars.dm similarity index 53% rename from code/modules/ninja/suit/ninja_equipment_actions/ninja_stars.dm rename to code/modules/ninja/ninja_stars.dm index 2c8adbc5770..2e5817f05df 100644 --- a/code/modules/ninja/suit/ninja_equipment_actions/ninja_stars.dm +++ b/code/modules/ninja/ninja_stars.dm @@ -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 * diff --git a/code/modules/ninja/outfit.dm b/code/modules/ninja/outfit.dm index dca30db4324..7d96a446389 100644 --- a/code/modules/ninja/outfit.dm +++ b/code/modules/ninja/outfit.dm @@ -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 diff --git a/code/modules/ninja/suit/gloves.dm b/code/modules/ninja/suit/gloves.dm deleted file mode 100644 index dbe227f077f..00000000000 --- a/code/modules/ninja/suit/gloves.dm +++ /dev/null @@ -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 [display_energy(.)] 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." diff --git a/code/modules/ninja/suit/head.dm b/code/modules/ninja/suit/head.dm deleted file mode 100644 index ba8436d4c49..00000000000 --- a/code/modules/ninja/suit/head.dm +++ /dev/null @@ -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 diff --git a/code/modules/ninja/suit/mask.dm b/code/modules/ninja/suit/mask.dm deleted file mode 100644 index cb02bff1680..00000000000 --- a/code/modules/ninja/suit/mask.dm +++ /dev/null @@ -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 diff --git a/code/modules/ninja/suit/ninjaDrainAct.dm b/code/modules/ninja/suit/ninjaDrainAct.dm deleted file mode 100644 index 8ae0020c6c8..00000000000 --- a/code/modules/ninja/suit/ninjaDrainAct.dm +++ /dev/null @@ -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) diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_adrenaline.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_adrenaline.dm deleted file mode 100644 index 06fad9c95fb..00000000000 --- a/code/modules/ninja/suit/ninja_equipment_actions/ninja_adrenaline.dm +++ /dev/null @@ -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.")) diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_cost_check.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_cost_check.dm deleted file mode 100644 index eee581e0885..00000000000 --- a/code/modules/ninja/suit/ninja_equipment_actions/ninja_cost_check.dm +++ /dev/null @@ -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. diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_empulse.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_empulse.dm deleted file mode 100644 index ea2341a1323..00000000000 --- a/code/modules/ninja/suit/ninja_equipment_actions/ninja_empulse.dm +++ /dev/null @@ -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 diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_net.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_net.dm deleted file mode 100644 index 66eb50438fe..00000000000 --- a/code/modules/ninja/suit/ninja_equipment_actions/ninja_net.dm +++ /dev/null @@ -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! diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_status_read.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_status_read.dm deleted file mode 100644 index 0a9a7ef9387..00000000000 --- a/code/modules/ninja/suit/ninja_equipment_actions/ninja_status_read.dm +++ /dev/null @@ -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()]") diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_stealth.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_stealth.dm deleted file mode 100644 index 49c3ebdd54e..00000000000 --- a/code/modules/ninja/suit/ninja_equipment_actions/ninja_stealth.dm +++ /dev/null @@ -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 diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_suit_initialisation.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_suit_initialisation.dm deleted file mode 100644 index 4220cca57df..00000000000 --- a/code/modules/ninja/suit/ninja_equipment_actions/ninja_suit_initialisation.dm +++ /dev/null @@ -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 GREEN, continuing operation.", - "VOID-shift device status: ONLINE.\nCLOAK-tech device status: ONLINE.", - "Primary system status: ONLINE.\nBackup system status: ONLINE.\nCurrent energy capacity: ", - "All systems operational. Welcome to SpiderOS, " -)) - -GLOBAL_LIST_INIT(ninja_deinitialize_messages, list( - "Now de-initializing...", - "Shutting down SpiderOS.", - "Primary system status: OFFLINE.\nBackup system status: OFFLINE.", - "VOID-shift device status: OFFLINE.\nCLOAK-tech device status: OFFLINE.", - "Disconnecting neural-net interface...Success.", - "Disengaging neural-net interface... Success.", - "Unsecuring external locking mechanism...\nNeural-net abolished.\nOperation status: FINISHED." -)) - -/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("FĆAL �Rr�R: 344--93#�&&21 BR��N |/|/aV� PATT$RN RED\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 += "[display_energy(cell.charge)]." - 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 diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_sword_recall.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_sword_recall.dm deleted file mode 100644 index 702a7a964c2..00000000000 --- a/code/modules/ninja/suit/ninja_equipment_actions/ninja_sword_recall.dm +++ /dev/null @@ -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) diff --git a/code/modules/ninja/suit/shoes.dm b/code/modules/ninja/suit/shoes.dm deleted file mode 100644 index cb1e745ea45..00000000000 --- a/code/modules/ninja/suit/shoes.dm +++ /dev/null @@ -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 diff --git a/code/modules/ninja/suit/suit.dm b/code/modules/ninja/suit/suit.dm deleted file mode 100644 index 7a2e153d0b4..00000000000 --- a/code/modules/ninja/suit/suit.dm +++ /dev/null @@ -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: [display_energy(cell.charge)].\n"+\ - "The CLOAK-tech device is [stealth?"active":"inactive"].\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("ERROR: suit offline. Please activate suit.")) - return FALSE - if(s_coold > 0) - to_chat(user, span_warning("ERROR: 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("fÄTaL ÈÈRRoR: 382200-*#00CÖDE RED\nUNAU†HORIZED USÈ DETÈC†††eD\nCoMMÈNCING SUB-R0U†IN3 13...\nTÈRMInATING U-U-USÈR...")) - 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) diff --git a/code/modules/ninja/suit/suit_attackby.dm b/code/modules/ninja/suit/suit_attackby.dm deleted file mode 100644 index 509c6a2652b..00000000000 --- a/code/modules/ninja/suit/suit_attackby.dm +++ /dev/null @@ -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: [round(cell.maxcharge/100)]%")) - 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 ..() diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm index 02db057735a..d68aca06d6c 100644 --- a/code/modules/power/cell.dm +++ b/code/modules/power/cell.dm @@ -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" diff --git a/icons/mob/clothing/feet.dmi b/icons/mob/clothing/feet.dmi index d767ca35932..3c61d0f31a4 100644 Binary files a/icons/mob/clothing/feet.dmi and b/icons/mob/clothing/feet.dmi differ diff --git a/icons/mob/clothing/hands.dmi b/icons/mob/clothing/hands.dmi index 7350c9a03a8..6db0a3b8193 100644 Binary files a/icons/mob/clothing/hands.dmi and b/icons/mob/clothing/hands.dmi differ diff --git a/icons/mob/clothing/head.dmi b/icons/mob/clothing/head.dmi index 12a2bbac177..9694491fd09 100644 Binary files a/icons/mob/clothing/head.dmi and b/icons/mob/clothing/head.dmi differ diff --git a/icons/mob/clothing/mask.dmi b/icons/mob/clothing/mask.dmi index cb0ed57241f..8b8c8e55a0c 100644 Binary files a/icons/mob/clothing/mask.dmi and b/icons/mob/clothing/mask.dmi differ diff --git a/icons/mob/clothing/modsuit/mod_clothing.dmi b/icons/mob/clothing/modsuit/mod_clothing.dmi index 5f51f618276..39db9061b06 100644 Binary files a/icons/mob/clothing/modsuit/mod_clothing.dmi and b/icons/mob/clothing/modsuit/mod_clothing.dmi differ diff --git a/icons/mob/clothing/suit.dmi b/icons/mob/clothing/suit.dmi index b157afc3ef9..fedf63c7f59 100644 Binary files a/icons/mob/clothing/suit.dmi and b/icons/mob/clothing/suit.dmi differ diff --git a/icons/mob/clothing/under/syndicate.dmi b/icons/mob/clothing/under/syndicate.dmi index 07319d6da9e..ecd124fce46 100644 Binary files a/icons/mob/clothing/under/syndicate.dmi and b/icons/mob/clothing/under/syndicate.dmi differ diff --git a/icons/mob/inhands/__inhand_template.dmi b/icons/mob/inhands/__inhand_template.dmi index e864275d0a8..6111157c593 100644 Binary files a/icons/mob/inhands/__inhand_template.dmi and b/icons/mob/inhands/__inhand_template.dmi differ diff --git a/icons/mob/inhands/clothing_lefthand.dmi b/icons/mob/inhands/clothing_lefthand.dmi index 742b676e372..5ad9ec35b94 100644 Binary files a/icons/mob/inhands/clothing_lefthand.dmi and b/icons/mob/inhands/clothing_lefthand.dmi differ diff --git a/icons/mob/inhands/clothing_righthand.dmi b/icons/mob/inhands/clothing_righthand.dmi index ebfaa0d189f..bd298e3d7e7 100644 Binary files a/icons/mob/inhands/clothing_righthand.dmi and b/icons/mob/inhands/clothing_righthand.dmi differ diff --git a/icons/obj/clothing/gloves.dmi b/icons/obj/clothing/gloves.dmi index dc5ed59e029..e7fbfef9e8b 100644 Binary files a/icons/obj/clothing/gloves.dmi and b/icons/obj/clothing/gloves.dmi differ diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi index 40fd2ccc8d5..e839d4f4ea9 100644 Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ diff --git a/icons/obj/clothing/masks.dmi b/icons/obj/clothing/masks.dmi index 53ce2527249..85e79bb0902 100644 Binary files a/icons/obj/clothing/masks.dmi and b/icons/obj/clothing/masks.dmi differ diff --git a/icons/obj/clothing/modsuit/mod_clothing.dmi b/icons/obj/clothing/modsuit/mod_clothing.dmi index aebff91268f..ca4e8c32736 100644 Binary files a/icons/obj/clothing/modsuit/mod_clothing.dmi and b/icons/obj/clothing/modsuit/mod_clothing.dmi differ diff --git a/icons/obj/clothing/modsuit/mod_modules.dmi b/icons/obj/clothing/modsuit/mod_modules.dmi index 5840b69721c..0e0121b33d9 100644 Binary files a/icons/obj/clothing/modsuit/mod_modules.dmi and b/icons/obj/clothing/modsuit/mod_modules.dmi differ diff --git a/icons/obj/clothing/shoes.dmi b/icons/obj/clothing/shoes.dmi index af1b9cb7419..ce83b93c6b4 100644 Binary files a/icons/obj/clothing/shoes.dmi and b/icons/obj/clothing/shoes.dmi differ diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi index 6120d5819aa..cc24947bb4d 100644 Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ diff --git a/icons/obj/clothing/under/syndicate.dmi b/icons/obj/clothing/under/syndicate.dmi index 7c9ce6631ba..9fa30b4b00f 100644 Binary files a/icons/obj/clothing/under/syndicate.dmi and b/icons/obj/clothing/under/syndicate.dmi differ diff --git a/strings/ninja.json b/strings/ninja.json new file mode 100644 index 00000000000..8dfe297be7a --- /dev/null +++ b/strings/ninja.json @@ -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!!!" + ] +} diff --git a/tgstation.dme b/tgstation.dme index 409de04578a..5b20769628b 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -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" diff --git a/tgui/packages/tgui/interfaces/MODsuit.js b/tgui/packages/tgui/interfaces/MODsuit.js index 76c7f927d7c..d45abdae4b8 100644 --- a/tgui/packages/tgui/interfaces/MODsuit.js +++ b/tgui/packages/tgui/interfaces/MODsuit.js @@ -141,10 +141,10 @@ const HealthAnalyzer = (props, context) => { average: [0.2, 0.5], bad: [-Infinity, 0.2], }} > - + - +
{ average: [0.2, 0.5], bad: [0.5, Infinity], }} > - +
@@ -167,7 +167,7 @@ const HealthAnalyzer = (props, context) => { average: [0.2, 0.5], bad: [0.5, Infinity], }} > - + @@ -180,7 +180,7 @@ const HealthAnalyzer = (props, context) => { average: [0.2, 0.5], bad: [0.5, Infinity], }} > - + @@ -193,7 +193,7 @@ const HealthAnalyzer = (props, context) => { average: [0.2, 0.5], bad: [0.5, Infinity], }} > - + @@ -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 ( + <> + + +
+ {active ? statustime : '00:00:00'} +
+
+ +
+ {active ? (statusid || '0') : '???'} +
+
+
+
+ + + +
+ + +
+ + + +
+
+ +
+ + + +
+
+ +
+ + + +
+
+ +
+ + + +
+
+
+ + +
+ {active ? statustemp : 0} +
+
+ +
+ {active ? statusnutrition : 0} +
+
+
+
+ + + {active ? statusfingerprints : "???"} + + + {active ? statusdna : "???"} + + +
+ {!!active && !!statusviruses && ( +
+ + + +
+
+ )} + + ); +}; + const ID2MODULE = { rad_counter: RadCounter, health_analyzer: HealthAnalyzer, + status_readout: StatusReadout, }; const LockedInterface = () => ( @@ -440,7 +622,7 @@ const ModuleSection = (props, context) => { return ( + title={module.module_name} >
{configureState === module.ref && ( { - {module.complexity}/{complexity_max} + {module.module_complexity}/{complexity_max} {module.idle_power} @@ -523,7 +705,7 @@ const ModuleSection = (props, context) => {