Stealth and Steel: The Space Ninja (#31497)

* Space Ninja Antag Datum

* Small fixes

* Ninja outfit, ekatana, actions

* Ninja scanner and spans

* Ninja uplink implant

* Ninja bombs

* Ninja bomb flare grants

* Ninja modsuit, objective payouts

* Fixes objectives

* Ninja stealth fix, modsuit sprites and final implementations

* Lints

* Ninja scanner sprites

* Ninja Suit and Energy Shuriken Sprites

* Fixes config, Adjusts stim ability, adds shuriken printer and e-shurikens, uplink stuff

* Fixes a duplicate icon

* Attack chain

* Energy katana item sprite

* Ninja net gun

* Brazil

* Spawning ninjas, ninja on traitor panel, ninja spawn sound

* Linter

* Objective stuff

* Fixes n grey suits

* Objectives

* Trim intro sound

* Event, spawn point

* Ninja Outfits, Vox Check, Bug Fixes, Mirror at ninja spawn

* Address code review

* Oops

* Uncomments an important thingy

* Update: Gave space ninjas access to maints and an agent ID card. Updated net description.

* Update scanner examine

* Removes excess file

* Makes ninja scanner fit in belts and ninja suits. Gives them NV goggles

* Fixes modsuit sprite issue

* Energy shuriken fixes

* Scanner fix

* Printer fix

* Fixes some runtimes

* Fixes capture teleport

* Clothes rename

* Buffs energy katana, adds soft no-drop to ekatana, buffs ninja modsuit, fixes equip bug

* Adds research levels to ninja gear

* Fixes ninja capture issue

* Remaps ninja dojo

* Better cuff removal

* Forgor

* Fixes action availability

* Updates walls at dojo

* Improves ninja modsuit

* Windoors can now be opened with the katana

* Adds advanced pinpointer to ninja uplink

* Fixed energy nets sticking

* Fixes slime people ninjas

* Adds reroll to ninja capture if target is DNR. Prevents off Z-level targets

* Oop

* Adds reactor sabotage objective.

* Fixes ninja cuffs

* Removes Carp scroll from uplink. Adds Krav Implant to uplink
This commit is contained in:
PollardTheDragon
2026-03-25 23:11:10 +00:00
committed by GitHub
parent 3e8f140498
commit 394c3b0108
120 changed files with 2616 additions and 1184 deletions
+2
View File
@@ -74,6 +74,8 @@
var/list/datum/mind/wizards = list()
/// A list of all minds that are wizard apprentices
var/list/datum/mind/apprentices = list()
/// A list of all minds that are ninjas
var/list/datum/mind/ninjas = list()
/// The cult team datum
var/datum/team/cult/cult_team
+352
View File
@@ -0,0 +1,352 @@
#define NINJA_OBJECTIVE_EASY 10
#define NINJA_OBJECTIVE_NORMAL 20
#define NINJA_OBJECTIVE_HARD 40
/datum/objective/ninja
/// Can you only roll this objective once?
var/onlyone = FALSE
/// Does this objective come with special gear
var/special_equipment_path
/// Rewarded currency for objective completion
var/reward_tc = NINJA_OBJECTIVE_EASY
/datum/objective/ninja/New(text, datum/team/team_to_join, datum/mind/_owner)
. = ..()
if(special_equipment_path)
addtimer(CALLBACK(src, PROC_REF(hand_out_equipment)), 3 SECONDS, TIMER_DELETE_ME)
/datum/objective/ninja/proc/hand_out_equipment()
give_kit(special_equipment_path)
/datum/objective/ninja/is_invalid_target(datum/mind/possible_target)
. = ..()
if(possible_target.current)
var/turf/current_location = get_turf(possible_target.current)
if(current_location && !is_station_level(current_location.z))
return TARGET_INVALID_UNREACHABLE
/datum/objective/ninja/proc/complete_objective()
for(var/datum/mind/M in get_owners())
var/mob/living/carbon/human/H = M.current
if(!ishuman(H))
continue
var/obj/item/bio_chip/uplink/ninja/nuplink = locate(/obj/item/bio_chip/uplink/ninja) in H
if(!nuplink)
continue
nuplink.hidden_uplink.uses += reward_tc
completed = TRUE
/datum/objective/ninja/proc/check_objective_conditions()
return TRUE
/datum/objective/ninja/kill
name = "Kill a Target"
reward_tc = NINJA_OBJECTIVE_NORMAL
/datum/objective/ninja/kill/update_explanation_text()
if(target?.current)
explanation_text = "Kill [target.current.real_name], the [target.assigned_role]. Scan the corpse with your scanner to verify that the deed is done."
var/datum/job/target_job = SSjobs.GetJob(target.assigned_role)
if(target_job.job_department_flags & DEP_FLAG_COMMAND || target_job.job_department_flags & DEP_FLAG_SECURITY)
reward_tc = NINJA_OBJECTIVE_HARD
/datum/objective/ninja/capture
name = "Capture a Target"
reward_tc = NINJA_OBJECTIVE_NORMAL
/// The kidnapee's belongings. Set upon capture.
var/list/obj/item/victim_belongings = null
/// Temporary objects that are available to the kidnapee during their time in jail. These are deleted when the victim is returned.
var/list/obj/temp_objs = null
/// Prisoner jail timer handle. On completion, returns the prisoner back to station.
var/prisoner_timer_handle = null
/datum/objective/ninja/capture/update_explanation_text()
if(target?.current)
explanation_text = "Capture [target.current.real_name], the [target.assigned_role]. Use your energy net to capture them so that we can interrogate them at one of our many secret dojos."
var/datum/job/target_job = SSjobs.GetJob(target.assigned_role)
if(target_job.job_department_flags & DEP_FLAG_COMMAND || target_job.job_department_flags & DEP_FLAG_SECURITY)
reward_tc = NINJA_OBJECTIVE_HARD
if(target_job.job_department_flags & DEP_FLAG_SERVICE)
reward_tc = NINJA_OBJECTIVE_EASY
/datum/objective/ninja/capture/proc/handle_capture(mob/living/sucker, turf/T)
var/mob/living/carbon/human/H = sucker
// Prepare their return
prisoner_timer_handle = addtimer(CALLBACK(src, PROC_REF(handle_target_return), sucker, T), rand(3 MINUTES, 5 MINUTES), TIMER_STOPPABLE)
LAZYSET(GLOB.prisoner_belongings.prisoners, sucker, src)
// Shove all of the victim's items in the secure locker.
victim_belongings = list()
var/list/obj/item/stuff_to_transfer = list()
// Cybernetic implants get removed first (to deal with NODROP stuff)
for(var/obj/item/organ/internal/cyberimp/I in H.internal_organs)
// Greys get to keep their implant
if(isgrey(H) && istype(I, /obj/item/organ/internal/cyberimp/brain/speech_translator))
continue
// IPCs keep this implant, free of charge!
if(ismachineperson(H) && istype(I, /obj/item/organ/internal/cyberimp/arm/power_cord))
continue
// Try removing it
I = I.remove(H)
if(I)
stuff_to_transfer += I
// Skrell headpocket. They already have a check in place to limit what's placed in them.
var/obj/item/organ/internal/headpocket/C = H.get_int_organ(/obj/item/organ/internal/headpocket)
if(C?.held_item)
GLOB.prisoner_belongings.give_item(C.held_item)
victim_belongings += C.held_item
C.held_item = null
if(sucker.back) // Lets not bork modsuits in funny ways.
var/obj/modsuit_safety = sucker.back
sucker.drop_item_to_ground(modsuit_safety)
stuff_to_transfer += modsuit_safety
// Regular items get removed in second
for(var/obj/item/I in sucker)
// Keep their uniform and shoes
if(I == H.w_uniform || I == H.shoes)
continue
// Plasmamen are no use if they're crispy
if(isplasmaman(H) && I == H.head)
continue
// Any kind of implant gets potentially removed (mindshield, freedoms, etc)
if(istype(I, /obj/item/bio_chip))
if(istype(I, /obj/item/bio_chip/storage)) // Storage items are removed and placed in the confiscation locker before the implant is taken.
var/obj/item/bio_chip/storage/storage_chip = I
for(var/it in storage_chip.storage)
storage_chip.storage.remove_from_storage(it)
stuff_to_transfer += it
qdel(I)
continue
if(sucker.drop_item_to_ground(I))
stuff_to_transfer += I
// Remove accessories from the suit if present
if(length(H.w_uniform?.accessories))
for(var/obj/item/clothing/accessory/A in H.w_uniform.accessories)
H.w_uniform.detach_accessory(A, null)
H.drop_item_to_ground(A)
stuff_to_transfer += A
// Transfer it all (or drop it if not possible)
for(var/obj/item/i as anything in stuff_to_transfer)
if(GLOB.prisoner_belongings.give_item(i))
victim_belongings += i
else if(!((ABSTRACT|NODROP) in i.flags)) // Anything that can't be put on hold, just drop it on the ground
i.forceMove(T)
// Give some species the necessary to survive. Courtesy of the Syndicate.
if(istype(H))
var/obj/item/tank/internals/emergency_oxygen/tank
var/obj/item/clothing/mask/breath/mask
if(isvox(H))
tank = new /obj/item/tank/internals/emergency_oxygen/nitrogen(H)
mask = new /obj/item/clothing/mask/breath/vox(H)
else if(isplasmaman(H))
tank = new /obj/item/tank/internals/emergency_oxygen/plasma(H)
mask = new /obj/item/clothing/mask/breath(H)
if(tank)
H.equip_to_appropriate_slot(tank)
H.equip_to_appropriate_slot(mask)
tank.toggle_internals(H, TRUE)
sucker.reagents.add_reagent("mutadone", 1) // 1u of mutadone for the Hulk:tm: experience
sucker.update_icons()
// Supply them with some chow. How generous is the Syndicate?
var/obj/item/food/sliced/bread/food = new(get_turf(sucker))
food.name = "stale bread"
food.desc = "Looks like your captors care for their prisoners as much as their bread."
food.trash = null
if(prob(10))
// Mold adds a bit of spice to it
food.name = "moldy bread"
food.reagents.add_reagent("fungus", 1)
var/obj/item/reagent_containers/drinks/drinkingglass/drink = new(get_turf(sucker))
drink.reagents.add_reagent("tea", 25) // British coders beware, tea in glasses
var/obj/item/coin/antagtoken/passingtime = new(get_turf(sucker))
temp_objs = list(food, drink, passingtime)
// Narrate their kidnapping and torturing experience.
if(sucker.stat != DEAD)
// Heal them up - gets them out of crit/soft crit.
sucker.reagents.add_reagent("omnizine", 10)
to_chat(sucker, SPAN_WARNING("You feel strange..."))
sucker.Paralyse(30 SECONDS)
sucker.EyeBlind(35 SECONDS)
sucker.EyeBlurry(35 SECONDS)
sucker.AdjustConfused(35 SECONDS)
for(var/mob/living/simple_animal/hostile/guardian/G in GLOB.alive_mob_list)
if(G.summoner == sucker)
sucker.remove_guardian_actions()
to_chat(G, SPAN_DANGER("You feel your body ripped to shreds as you're forcibly removed from your summoner!"))
to_chat(sucker, SPAN_WARNING("You feel some part of you missing, you're not who you used to be..."))
G.ghostize()
qdel(G)
sleep(6 SECONDS)
to_chat(sucker, SPAN_WARNING("That portal did something to you..."))
sleep(6.5 SECONDS)
to_chat(sucker, SPAN_WARNING("Your head pounds... It feels like it's going to burst out your skull!"))
sleep(3 SECONDS)
to_chat(sucker, SPAN_WARNING("Your head pounds..."))
sleep(10 SECONDS)
to_chat(sucker, "<span class='specialnotice'>A million voices echo in your head... <i>\"Your mind held many valuable secrets - \
we thank you for providing them. Your value is expended, and you will be ransomed back to your station. We always get paid, \
so it's only a matter of time before we send you back...\"</i></span>")
to_chat(sucker, SPAN_DANGER("<font size=3>You have been kidnapped and interrogated for valuable information! You will be sent back to the station in a few minutes...</font>"))
/datum/objective/ninja/capture/proc/handle_target_return(mob/living/M, turf/T)
// Make a closet to return the target and their items neatly
var/obj/structure/closet/closet = new(T)
// Return their items
for(var/i in victim_belongings)
var/obj/item/I = GLOB.prisoner_belongings.remove_item(i)
if(!I)
continue
I.forceMove(closet)
victim_belongings = list()
// Clean up
var/obj/item/bio_chip/uplink/uplink_implant = locate() in M
uplink_implant?.hidden_uplink?.is_jammed = FALSE
QDEL_LIST_CONTENTS(temp_objs)
// Injuries due to questioning
injure_target(M)
// Return them a bit confused.
M.visible_message(SPAN_NOTICE("[M] vanishes..."))
M.forceMove(closet)
M.Paralyse(3 SECONDS)
M.EyeBlurry(5 SECONDS)
M.AdjustConfused(5 SECONDS)
M.Dizzy(70 SECONDS)
do_sparks(4, FALSE, T)
prisoner_timer_handle = null
GLOB.prisoner_belongings.prisoners[M] = null
/datum/objective/ninja/capture/proc/injure_target(mob/living/M)
var/obj/item/organ/external/injury_target
if(prob(20)) // See if they're !!!lucky!!! enough to just chop a hand or foot off first, or even !!LUCKIER!! that it chose an already amputated limb
injury_target = M.get_organ(pick(BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_FOOT, BODY_ZONE_PRECISE_L_FOOT))
if(!injury_target)
return
default_damage(M)
injury_target.droplimb()
to_chat(M, SPAN_WARNING("You were interrogated by your captors before being sent back! Oh god, something's missing!"))
return
// Species specific punishments first
if(ismachineperson(M))
M.emp_act(EMP_HEAVY)
M.adjustBrainLoss(30)
to_chat(M, SPAN_WARNING("You were interrogated by your captors before being sent back! You feel like some of your components are loose!"))
return
default_damage(M) // Now that we won't accidentally kill an IPC we can make everyone take damage
if(isslimeperson(M))
injury_target = M.get_organ(pick(BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_FOOT, BODY_ZONE_PRECISE_L_FOOT))
if(!injury_target)
return
injury_target.cause_internal_bleeding()
injury_target = M.get_organ(BODY_ZONE_CHEST)
injury_target.cause_internal_bleeding()
to_chat(M, SPAN_WARNING("You were interrogated by your captors before being sent back! You feel like your inner membrane has been punctured!"))
return
if(prob(25)) // You either get broken ribs, or a broken limb and IB if you made it this far
injury_target = M.get_organ(BODY_ZONE_CHEST)
injury_target.fracture()
else
injury_target = M.get_organ(pick(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_R_LEG))
if(!injury_target)
return
injury_target.fracture()
injury_target.cause_internal_bleeding()
/datum/objective/ninja/capture/proc/default_damage(mob/living/M)
M.adjustBruteLoss(40)
M.adjustBrainLoss(25)
/datum/objective/ninja/hack_rnd
name = "Hack RnD"
explanation_text = "A client wants access to Nanotrasen's research databank. Use your scanner on their servers to give them a way inside."
needs_target = FALSE
onlyone = TRUE
/datum/objective/ninja/interrogate_ai
name = "Interrogate AI"
explanation_text = "We wish to expunge some data from their AI system. Use your scanner on an active AI core to wirelessly transfer it to us for interrogation."
needs_target = FALSE
onlyone = TRUE
reward_tc = NINJA_OBJECTIVE_HARD
/datum/objective/ninja/interrogate_ai/check_objective_conditions() // If there is no AI, you don't get the objective.
if(!length(GLOB.ai_list))
return FALSE
return TRUE
/datum/objective/ninja/steal_supermatter
name = "Steal Supermatter"
explanation_text = "Steal the supermatter crystal, using the net gun we have modified for you. The crystal will sell well to the highest bidder."
needs_target = FALSE
onlyone = TRUE
reward_tc = NINJA_OBJECTIVE_HARD
/datum/objective/ninja/steal_supermatter/check_objective_conditions() // If there is no supermatter, you don't get the objective.
return !isnull(GLOB.main_supermatter_engine)
/datum/objective/ninja/insert_spider_rod
name = "Sabotage Fission Reactor"
explanation_text = "Insert a spider-clan uranium 238 fuel rod into the station's fission reactor, then scan the reactor chamber while it is active."
needs_target = FALSE
onlyone = TRUE
reward_tc = NINJA_OBJECTIVE_HARD
special_equipment_path = /obj/item/beacon/ninja_rod_spawner
/datum/objective/ninja/insert_spider_rod/check_objective_conditions() // If there is no reactor, you don't get the objective.
return !isnull(GLOB.main_fission_reactor)
/datum/objective/ninja/bomb_department
name = "Bomb Department"
needs_target = FALSE
special_equipment_path = /obj/item/wormhole_jaunter/ninja_bomb
explanation_text = "Use the special flare provided to call down and arm a spider bomb. The target department is inscribed on the flare."
reward_tc = NINJA_OBJECTIVE_NORMAL
/datum/objective/ninja/bomb_department/emp
name = "EMP Department"
explanation_text = "Use the special flare provided to call down and arm an EMP bomb. The target department is inscribed on the flare."
special_equipment_path = /obj/item/wormhole_jaunter/ninja_bomb/emp
/datum/objective/ninja/bomb_department/spiders
name = "Spider Bomb Department"
explanation_text = "Use the special flare provided to call down and arm a Spider bomb. The target department is inscribed on the flare."
special_equipment_path = /obj/item/wormhole_jaunter/ninja_bomb/spiders
/datum/objective/ninja_exfiltrate
name = "Exfiltrate"
explanation_text = "Use your exfiltration flare to escape the station when your work is done."
needs_target = FALSE
#undef NINJA_OBJECTIVE_EASY
#undef NINJA_OBJECTIVE_NORMAL
#undef NINJA_OBJECTIVE_HARD
+11
View File
@@ -1014,6 +1014,17 @@ GLOBAL_LIST_EMPTY(airlock_emissive_underlays)
add_fingerprint(user)
if(!headbutt_shock_check(user))
return ITEM_INTERACT_COMPLETE
if(istype(used, /obj/item/katana/energy) && user.a_intent == INTENT_HELP)
if(locked)
if(!do_after_once(user, 5 SECONDS, TRUE, src, allow_moving = FALSE, must_be_held = FALSE))
return ITEM_INTERACT_COMPLETE
unlock()
return ITEM_INTERACT_COMPLETE
else
if(!do_after_once(user, 2.5 SECONDS, TRUE, src, allow_moving = FALSE, must_be_held = FALSE))
return ITEM_INTERACT_COMPLETE
open()
return ITEM_INTERACT_COMPLETE
if(panel_open)
if(istype(used, /obj/item/kitchen/utensil/fork))
return NONE
+5 -1
View File
@@ -317,7 +317,11 @@
//If it's in the process of opening/closing, ignore the click
if(operating)
return ITEM_INTERACT_COMPLETE
if(istype(used, /obj/item/katana/energy) && user.a_intent == INTENT_HELP)
if(!do_after_once(user, 2.5 SECONDS, TRUE, src, allow_moving = FALSE, must_be_held = FALSE))
return ITEM_INTERACT_COMPLETE
open()
return ITEM_INTERACT_COMPLETE
add_fingerprint(user)
return ..()
+10 -10
View File
@@ -104,6 +104,9 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/newplayer_start) //Without this you sp
name = "revenantspawn"
icon_state = "Rev"
/obj/effect/landmark/spawner/ninja
name = "ninjaspawn"
/obj/effect/landmark/spawner/bubblegum_arena
name = "bubblegum_arena_human"
icon_state = "Explorer"
@@ -142,13 +145,6 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/newplayer_start) //Without this you sp
spawner_list = GLOB.ertdirector
return ..()
/obj/effect/landmark/spawner/ninjastart
name = "ninjastart"
/obj/effect/landmark/spawner/ninjastart/Initialize(mapload)
spawner_list = GLOB.ninjastart
return ..()
/obj/effect/landmark/spawner/aroomwarp
name = "aroomwarp"
@@ -198,6 +194,13 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/newplayer_start) //Without this you sp
spawner_list = GLOB.syndieprisonwarp
return ..()
/obj/effect/landmark/spawner/ninja_prison_warp
name = "ninja prison warp"
/obj/effect/landmark/spawner/ninja_prison_warp/Initialize(mapload)
spawner_list = GLOB.ninjaprisonwarp
return ..()
/obj/effect/landmark/spawner/antag_extract_warp
name = "antagextractwarp"
@@ -230,9 +233,6 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/newplayer_start) //Without this you sp
/obj/effect/landmark/spawner/commando_manual
name = "Deathsquad Commando Manual"
/obj/effect/landmark/spawner/holding_facility
name = "Holding Facility"
/obj/effect/landmark/spawner/holocarp
name = "Holocarp Spawn"
@@ -44,6 +44,19 @@
syndicate = TRUE
emagged = TRUE
// Spawns a spider fuel rod for ninja objectives
/obj/item/beacon/ninja_rod_spawner
name = "spider clan beacon"
desc = "A label on it reads: <i>Activate to have a spider clan brand fuel rod teleported to your location</i>."
origin_tech = "bluespace=6;syndicate=3"
/obj/item/beacon/ninja_rod_spawner/attack_self__legacy__attackchain(mob/user)
if(!user)
return
var/obj/item/nuclear_rod/fuel/uranium_238/spiders/new_rod = new(user.loc)
qdel(src)
user.put_in_hands(new_rod)
// SINGULO BEACON SPAWNER
/obj/item/beacon/syndicate
name = "suspicious beacon"
@@ -594,3 +594,34 @@
playsound(src, pick('sound/weapons/bulletflyby.ogg','sound/weapons/bulletflyby2.ogg','sound/weapons/bulletflyby3.ogg'), 75, 1)
return TRUE
return FALSE
// MARK: KATANA
/obj/item/katana
name = "katana"
desc = "Woefully underpowered in D20."
icon = 'icons/obj/weapons/melee.dmi'
icon_state = "katana"
lefthand_file = 'icons/mob/inhands/weapons_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons_righthand.dmi'
flags = CONDUCT
slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_BACK
flags_2 = ALLOW_BELT_NO_JUMPSUIT_2 // Look, you can strap it to your back. You can strap it to your waist too.
force = 40
throwforce = 10
sharp = TRUE
w_class = WEIGHT_CLASS_BULKY
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, RAD = 0, FIRE = 100, ACID = 50)
resistance_flags = FIRE_PROOF
needs_permit = TRUE
new_attack_chain = TRUE
/obj/item/katana/Initialize(mapload)
. = ..()
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.5, _parryable_attack_types = ALL_ATTACK_TYPES)
/obj/item/katana/suicide_act(mob/user)
user.visible_message("<span class='suicide'>[user] is slitting [user.p_their()] stomach open with [src]! It looks like [user.p_theyre()] trying to commit seppuku!</span>")
return BRUTELOSS
@@ -78,34 +78,6 @@
desc = "An engraved and fancy version of the claymore. It appears to be less sharp than it's more functional cousin."
force = 20
/obj/item/katana
name = "katana"
desc = "Woefully underpowered in D20."
icon = 'icons/obj/weapons/melee.dmi'
icon_state = "katana"
lefthand_file = 'icons/mob/inhands/weapons_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons_righthand.dmi'
flags = CONDUCT
slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_BACK
flags_2 = ALLOW_BELT_NO_JUMPSUIT_2 //Look, you can strap it to your back. You can strap it to your waist too.
force = 40
throwforce = 10
sharp = TRUE
w_class = WEIGHT_CLASS_BULKY
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, RAD = 0, FIRE = 100, ACID = 50)
resistance_flags = FIRE_PROOF
needs_permit = TRUE
/obj/item/katana/Initialize(mapload)
. = ..()
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.5, _parryable_attack_types = ALL_ATTACK_TYPES)
/obj/item/katana/suicide_act(mob/user)
user.visible_message(SPAN_SUICIDE("[user] is slitting [user.p_their()] stomach open with [src]! It looks like [user.p_theyre()] trying to commit seppuku!"))
return BRUTELOSS
/obj/item/harpoon
name = "harpoon"
desc = "Tharr she blows!"
@@ -76,35 +76,6 @@
else
icon_state = "signpost_wood"
/obj/structure/ninjatele
name = "Long-Distance Teleportation Console"
desc = "A console used to send a Spider Clan operative long distances rapidly."
icon = 'icons/obj/ninjaobjects.dmi'
icon_state = "teleconsole"
anchored = TRUE
/obj/structure/ninjatele/attack_hand(mob/user as mob)
if(user.mind.special_role=="Ninja")
switch(tgui_alert(user, "Phase Jaunt relay primed, target locked as [station_name()], initiate VOID-shift translocation? (Warning! Internals required!)", "Void Shift", list("Yes", "No")))
if("Yes")
if(user.z != src.z)
return
user.loc.loc.Exited(user)
user.loc = pick(GLOB.carplist) // In the future, possibly make specific NinjaTele landmarks, and give him an option to teleport to North/South/East/West of SS13 instead of just hijacking a carpspawn.
playsound(user.loc, 'sound/effects/phasein.ogg', 25, 1)
playsound(user.loc, 'sound/effects/sparks2.ogg', 50, 1)
new /obj/effect/temp_visual/dir_setting/ninja/phase(get_turf(user), user.dir)
to_chat(user, "[SPAN_BOLDNOTICE("VOID-Shift")] translocation successful")
if("No")
to_chat(user, SPAN_DANGER("Process aborted!"))
return
else
to_chat(user, "[SPAN_DANGER("FĆAL RrR")]: ŧer nt recgnized, c-cntr-r䣧-ç äcked.")
/obj/structure/respawner
name = "\improper Long-Distance Cloning Machine"
desc = "Top-of-the-line Nanotrasen technology allows for cloning of crew members from off-station upon bluespace request."