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 -2
View File
@@ -433,8 +433,8 @@
if(length(SSticker.mode.apprentices))
dat += check_role_table("Apprentices", SSticker.mode.apprentices)
/*if(length(ticker.mode.ninjas))
dat += check_role_table("Ninjas", ticker.mode.ninjas)*/
if(length(SSticker.mode.ninjas))
dat += check_role_table("Ninjas", SSticker.mode.ninjas)
if(SSticker.mode.cult_team)
dat += check_role_table("Cultists", SSticker.mode.cult_team.members)
@@ -0,0 +1,95 @@
RESTRICT_TYPE(/datum/antagonist/space_ninja)
// Spider Clan Space Ninja
/datum/antagonist/space_ninja
name = "Space Ninja"
roundend_category = "ninjas"
job_rank = ROLE_NINJA
special_role = SPECIAL_ROLE_NINJA
antag_hud_name = "hud_ninja"
antag_hud_type = ANTAG_HUD_NINJA
clown_gain_text = "Your spider clan training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself."
clown_removal_text = "You lose your spider clan training and return to your own clumsy, clownish self."
wiki_page_name = "Space Ninja"
var/give_uplink = TRUE
blurb_r = 200
blurb_a = 0.75
boss_title = "Spider Clan Daimyo"
/// Number of missions needed to complete
var/mission_goal = 4
/datum/antagonist/space_ninja/on_gain()
..()
mission_goal = 4 + (length(GLOB.crew_list) / 10)
SEND_SOUND(owner.current, sound('sound/ambience/antag/ninjaalert.ogg'))
/datum/antagonist/space_ninja/give_objectives()
forge_objectives()
/datum/antagonist/space_ninja/exfiltrate(mob/living/carbon/human/extractor, obj/item/radio/radio)
extractor.equipOutfit(/datum/outfit/admin/ghostbar_antag/space_ninja)
radio.autosay("<b>--ZZZT!- Domo Ar!g@to, [extractor.real_name]. Your training paid -^%&!-ZZT!-</b>", "Spider Clan HQ", "Security")
SSblackbox.record_feedback("tally", "successful_extraction", 1, "Space Ninja")
/datum/antagonist/space_ninja/finalize_antag()
. = ..()
equip_ninja()
/datum/antagonist/space_ninja/add_owner_to_gamemode()
SSticker.mode.ninjas |= owner
/datum/antagonist/space_ninja/remove_owner_from_gamemode()
SSticker.mode.ninjas -= owner
/datum/antagonist/space_ninja/proc/equip_ninja()
if(!ishuman(owner.current))
return
var/mob/living/carbon/human/new_ninja = owner.current
new_ninja.delete_equipment()
if(isvox(new_ninja))
new_ninja.equipOutfit(/datum/outfit/space_ninja/vox)
else
new_ninja.equipOutfit(/datum/outfit/space_ninja)
/datum/antagonist/space_ninja/proc/forge_objectives()
var/list/moderate_objectives = list(
/datum/objective/ninja/capture = 8,
/datum/objective/ninja/kill = 8,
/datum/objective/ninja/hack_rnd = 5,
/datum/objective/ninja/bomb_department/emp = 3,
/datum/objective/ninja/bomb_department/spiders = 3,
)
var/list/all_ninja_objectives = list(
/datum/objective/ninja/capture = 8,
/datum/objective/ninja/kill = 8,
/datum/objective/ninja/hack_rnd = 4,
/datum/objective/ninja/bomb_department = 3,
/datum/objective/ninja/bomb_department/emp = 3,
/datum/objective/ninja/bomb_department/spiders = 3,
/datum/objective/ninja/steal_supermatter = 3,
/datum/objective/ninja/insert_spider_rod = 3,
/datum/objective/ninja/interrogate_ai = 3,
)
for(var/i in 1 to mission_goal)
if(i <= mission_goal / 2) // This ensures some easier objectives are rolled to allow ninjas to work up to harder ones.
forge_objective(moderate_objectives)
continue
forge_objective(all_ninja_objectives)
add_antag_objective(/datum/objective/ninja_exfiltrate)
/datum/antagonist/space_ninja/proc/forge_objective(list/objective_list)
var/datum/objective/ninja/new_objective = pickweight(objective_list)
var/datum/objective/ninja/obj_item = new new_objective() // Needed to do to check validity and reroll
if(!obj_item.check_objective_conditions())
forge_objective(objective_list)
qdel(obj_item)
return
qdel(obj_item)
if(new_objective.onlyone)
var/list/current_objectives = get_antag_objectives()
for(var/datum/objective/ninja/c_objective in current_objectives)
if(istype(c_objective, new_objective))
forge_objective(objective_list)
return
add_antag_objective(new_objective)
@@ -7,6 +7,7 @@ GLOBAL_LIST_INIT(special_role_times, list(
ROLE_TRAITOR = 7,
ROLE_CHANGELING = 14,
ROLE_WIZARD = 14,
ROLE_NINJA = 14,
ROLE_REV = 14,
ROLE_VAMPIRE = 14,
ROLE_BLOB = 14,
@@ -46,7 +46,7 @@
var/can_be_cut = 1
sprite_sheets = list(
"Vox" = 'icons/mob/clothing/species/vox/gloves.dmi',
"Skkulakin" = 'icons/mob/clothing/species/skkulakin/gloves.dmi',
"Skkulakin" = 'icons/mob/clothing/species/vox/gloves.dmi',
"Drask" = 'icons/mob/clothing/species/drask/gloves.dmi',
"Grey" = 'icons/mob/clothing/species/grey/gloves.dmi',
"Kidan" = 'icons/mob/clothing/species/kidan/gloves.dmi',
+1 -1
View File
@@ -177,7 +177,6 @@ GLOBAL_LIST_EMPTY(event_last_fired)
new /datum/event_meta(EVENT_LEVEL_MODERATE, /datum/event/radiation_storm, 10, TRUE),
new /datum/event_meta(EVENT_LEVEL_MODERATE, /datum/event/spider_infestation, 10, TRUE),
new /datum/event_meta(EVENT_LEVEL_MODERATE, /datum/event/ion_storm, 10),
//new /datum/event_meta/ninja(EVENT_LEVEL_MODERATE, "Space Ninja", /datum/event/space_ninja, 0, list(ASSIGNMENT_SECURITY = 15), TRUE),
// NON-BAY EVENTS
new /datum/event_meta(EVENT_LEVEL_MODERATE, /datum/event/mass_hallucination, 10),
new /datum/event_meta(EVENT_LEVEL_MODERATE, /datum/event/brand_intelligence, 5, TRUE),
@@ -216,6 +215,7 @@ GLOBAL_LIST_EMPTY(event_last_fired)
new /datum/event_meta(EVENT_LEVEL_MAJOR, /datum/event/demon_incursion, 10, TRUE, _first_run_time = 35 MINUTES),
new /datum/event_meta(EVENT_LEVEL_MAJOR, /datum/event/disease_outbreak, 8, TRUE),
new /datum/event_meta(EVENT_LEVEL_MAJOR, /datum/event/revenant, 9),
new /datum/event_meta(EVENT_LEVEL_MAJOR, /datum/event/space_ninja, 9),
new /datum/event_meta(EVENT_LEVEL_MAJOR, /datum/event/spawn_morph, 16, is_one_shot = TRUE),
//new /datum/event_meta(EVENT_LEVEL_MAJOR, /datum/event/spawn_floor_cluwne, 15, is_one_shot = TRUE)
//new /datum/event_meta(EVENT_LEVEL_MAJOR, /datum/event/spawn_pulsedemon, 20, is_one_shot = TRUE)
+86
View File
@@ -0,0 +1,86 @@
/datum/event/space_ninja
name = "Space Ninja"
role_weights = list(ASSIGNMENT_SECURITY = 2)
role_requirements = list(ASSIGNMENT_CREW = 20, ASSIGNMENT_SECURITY = 2)
nominal_severity = EVENT_LEVEL_MAJOR
/datum/event/space_ninja/start()
INVOKE_ASYNC(src, PROC_REF(poll_ninja))
/datum/event/space_ninja/proc/poll_ninja(list/potential_ninjas)
var/list/candidates = list()
if(!potential_ninjas)
candidates = SSghost_spawns.poll_candidates("Do you want to play as a space ninja?", ROLE_NINJA, TRUE)
else
candidates = potential_ninjas
if(!length(candidates))
kill()
return
var/mob/new_ninja
while(length(candidates))
new_ninja = pick_n_take(candidates)
if(jobban_isbanned(new_ninja, ROLE_TRAITOR))
continue
break
if(!new_ninja)
kill()
return
var/gender_pref = input_async(new_ninja, "Please select a gender (10 seconds):", list("Male", "Female"))
addtimer(CALLBACK(src, PROC_REF(get_species), candidates, new_ninja, gender_pref), 10 SECONDS)
/datum/event/space_ninja/proc/get_species(list/potential_ninjas, mob/new_ninja, datum/async_input/gender_pref)
gender_pref.close()
var/sel_gender = gender_pref.result
if(!sel_gender) // Player was AFK and did not select a gender
poll_ninja(potential_ninjas)
return
var/species_pref = input_async(new_ninja, "Please select a species (10 seconds):", list("Human", "Tajaran", "Skrell", "Unathi", "Diona", "Vulpkanin", "Nian", "Drask", "Kidan", "Grey", "Skkulakin", "Vox", "Slime", "Machine", "Random"))
addtimer(CALLBACK(src, PROC_REF(create_ninja), potential_ninjas, new_ninja, sel_gender, species_pref), 10 SECONDS)
/datum/event/space_ninja/proc/create_ninja(list/potential_ninjas, mob/new_ninja, sel_gender, datum/async_input/species_pref)
species_pref.close()
var/sel_species = species_pref.result
if(!sel_species) // Player was AFK and did not select a species
poll_ninja(potential_ninjas)
return
if(!new_ninja || !new_ninja.client)
poll_ninja(potential_ninjas)
return
var/list/spawn_locs = list()
for(var/obj/effect/landmark/spawner/ninja/N in GLOB.landmarks_list)
spawn_locs += get_turf(N)
if(!length(spawn_locs))
message_admins("Unable to spawn ninja - no valid spawn locations.")
return
var/mob/living/carbon/human/M = new(pick(spawn_locs))
M.ckey = new_ninja.ckey
dust_if_respawnable(new_ninja)
if(sel_gender == "Male")
M.change_gender(MALE)
M.change_body_type(MALE)
else
M.change_gender(FEMALE)
M.change_body_type(FEMALE)
if(sel_species == "Random")
sel_species = pick("Human", "Tajaran", "Skrell", "Unathi", "Diona", "Vulpkanin", "Nian", "Drask", "Kidan", "Grey", "Skkulakin", "Vox", "Slime", "Machine")
if(sel_species == "Slime")
sel_species = "Slime People"
var/datum/species/S = GLOB.all_species[sel_species]
var/species = S.type
M.set_species(species, TRUE)
M.dna.ready_dna(M)
M.cleanSE()
M.overeatduration = 0
M.age = rand(23, 35)
M.regenerate_icons()
M.mind = new
M.mind.bind_to(M)
M.mind.set_original_mob(M)
M.mind.make_space_ninja()
+20 -2
View File
@@ -11,6 +11,11 @@
permeability_coefficient = 0.01
sprite_sheets = list(
"Grey" = 'icons/mob/clothing/modsuit/species/grey_helmets.dmi',
"Skrell" = 'icons/mob/clothing/modsuit/species/skrell_modsuits.dmi',
"Nian" = 'icons/mob/clothing/modsuit/species/nian_modsuits.dmi',
"Diona" = 'icons/mob/clothing/modsuit/species/diona_modsuits.dmi',
"Kidan" = 'icons/mob/clothing/modsuit/species/kidan_modsuits.dmi',
"Drask" = 'icons/mob/clothing/modsuit/species/drask_modsuits.dmi',
"Vulpkanin" = 'icons/mob/clothing/modsuit/species/vulp_modsuits.dmi',
"Tajaran" = 'icons/mob/clothing/modsuit/species/taj_modsuits.dmi',
"Unathi" = 'icons/mob/clothing/modsuit/species/unathi_modsuits.dmi',
@@ -37,13 +42,17 @@
insert_max = 0
hide_tail_by_species = list("modsuit")
sprite_sheets = list(
"Skrell" = 'icons/mob/clothing/modsuit/species/skrell_modsuits.dmi',
"Nian" = 'icons/mob/clothing/modsuit/species/nian_modsuits.dmi',
"Diona" = 'icons/mob/clothing/modsuit/species/diona_modsuits.dmi',
"Kidan" = 'icons/mob/clothing/modsuit/species/kidan_modsuits.dmi',
"Drask" = 'icons/mob/clothing/modsuit/species/drask_modsuits.dmi',
"Vulpkanin" = 'icons/mob/clothing/modsuit/species/vulp_modsuits.dmi',
"Tajaran" = 'icons/mob/clothing/modsuit/species/taj_modsuits.dmi',
"Unathi" = 'icons/mob/clothing/modsuit/species/unathi_modsuits.dmi',
"Vox" = 'icons/mob/clothing/modsuit/species/vox_modsuits.dmi'
)
/obj/item/clothing/gloves/mod
name = "MOD gauntlets"
desc = "A pair of gauntlets for a MODsuit."
@@ -56,13 +65,17 @@
cold_protection = HANDS|ARMS
permeability_coefficient = 0.01
sprite_sheets = list(
"Skrell" = 'icons/mob/clothing/modsuit/species/skrell_modsuits.dmi',
"Nian" = 'icons/mob/clothing/modsuit/species/nian_modsuits.dmi',
"Diona" = 'icons/mob/clothing/modsuit/species/diona_modsuits.dmi',
"Kidan" = 'icons/mob/clothing/modsuit/species/kidan_modsuits.dmi',
"Drask" = 'icons/mob/clothing/modsuit/species/drask_modsuits.dmi',
"Vulpkanin" = 'icons/mob/clothing/modsuit/species/vulp_modsuits.dmi',
"Tajaran" = 'icons/mob/clothing/modsuit/species/taj_modsuits.dmi',
"Unathi" = 'icons/mob/clothing/modsuit/species/unathi_modsuits.dmi',
"Vox" = 'icons/mob/clothing/modsuit/species/vox_modsuits.dmi'
)
/obj/item/clothing/shoes/mod
name = "MOD boots"
desc = "A pair of boots for a MODsuit."
@@ -75,6 +88,11 @@
cold_protection = FEET|LEGS
permeability_coefficient = 0.01
sprite_sheets = list(
"Skrell" = 'icons/mob/clothing/modsuit/species/skrell_modsuits.dmi',
"Nian" = 'icons/mob/clothing/modsuit/species/nian_modsuits.dmi',
"Diona" = 'icons/mob/clothing/modsuit/species/diona_modsuits.dmi',
"Kidan" = 'icons/mob/clothing/modsuit/species/kidan_modsuits.dmi',
"Drask" = 'icons/mob/clothing/modsuit/species/drask_modsuits.dmi',
"Vulpkanin" = 'icons/mob/clothing/modsuit/species/vulp_modsuits.dmi',
"Tajaran" = 'icons/mob/clothing/modsuit/species/taj_modsuits.dmi',
"Unathi" = 'icons/mob/clothing/modsuit/species/unathi_modsuits.dmi',
+55
View File
@@ -1384,3 +1384,58 @@
/// considering this should not be used, it's getting just DS armor, not infinity in everything.
/obj/item/mod/armor/mod_theme_administrative
armor = list(MELEE = 200, BULLET = 200, LASER = 50, ENERGY = 50, BOMB = INFINITY, RAD = INFINITY, FIRE = INFINITY, ACID = INFINITY)
/datum/mod_theme/ninja
name = "'Shinobi' stealthsuit"
desc = "A specialized modsuit worn by the spider clan's elite ninja operatives."
default_skin = "ninja"
armor_type_1 = /obj/item/mod/armor/mod_theme_ninja
resistance_flags = FIRE_PROOF | ACID_PROOF
flag_2_flags = RAD_PROTECT_CONTENTS_2
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
siemens_coefficient = 0
slowdown_inactive = 1
slowdown_active = 0.3
ui_theme = "syndicate"
allowed_suit_storage = list(
/obj/item/katana/energy,
/obj/item/wormhole_jaunter/ninja_bomb,
/obj/item/throwing_star,
/obj/item/restraints/legcuffs/bola,
/obj/item/gun,
/obj/item/ninja_scanner,
)
skins = list(
"ninja" = list(
HELMET_FLAGS = list(
UNSEALED_LAYER = null,
UNSEALED_CLOTHING = THICKMATERIAL,
SEALED_CLOTHING = STOPSPRESSUREDMAGE | BLOCKHAIR,
UNSEALED_INVISIBILITY = HIDEFACE,
SEALED_INVISIBILITY = HIDEMASK | HIDEEYES | HIDEEARS | HIDEFACE,
UNSEALED_COVER = HEADCOVERSMOUTH,
SEALED_COVER = HEADCOVERSEYES,
CAN_OVERSLOT = TRUE,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
SEALED_CLOTHING = STOPSPRESSUREDMAGE,
SEALED_INVISIBILITY = HIDEJUMPSUIT | HIDETAIL,
CAN_OVERSLOT = TRUE,
),
GAUNTLETS_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
SEALED_CLOTHING = STOPSPRESSUREDMAGE,
CAN_OVERSLOT = TRUE,
),
BOOTS_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
SEALED_CLOTHING = STOPSPRESSUREDMAGE,
CAN_OVERSLOT = TRUE,
),
),
)
/obj/item/mod/armor/mod_theme_ninja
armor = list(MELEE = 50, BULLET = 35, LASER = 35, ENERGY = 30, BOMB = 25, RAD = 200, FIRE = INFINITY, ACID = INFINITY)
+19
View File
@@ -569,6 +569,25 @@
/obj/item/mod/module/jetpack/advanced,
)
/obj/item/mod/control/pre_equipped/ninja
icon_state = "ninja-control"
theme = /datum/mod_theme/ninja
starting_frequency = MODLINK_FREQ_SYNDICATE
applied_cell = /obj/item/stock_parts/cell/bluespace
applied_modules = list(
/obj/item/mod/module/storage/syndicate,
/obj/item/mod/module/jetpack/advanced,
/obj/item/mod/module/dispenser/smoke,
/obj/item/mod/module/shinobi_stealth,
/obj/item/mod/module/shinobi_freedom,
/obj/item/mod/module/shinobi_stims,
/obj/item/mod/module/noslip,
)
default_pins = list(
/obj/item/mod/module/jetpack/advanced,
/obj/item/mod/module/dispenser/smoke,
)
//these exist for the prefs menu
/obj/item/mod/control/pre_equipped/empty
starting_frequency = null
+74
View File
@@ -641,3 +641,77 @@
/obj/item/mod/module/anomaly_locked/teslawall/prebuilt
prebuilt = TRUE
removable = FALSE // No switching it into another suit / no free anomaly core
/obj/item/mod/module/shinobi_stealth
name = "MOD shinobi stealth module"
desc = "An advanced module, designed by the Spider Clan, that replicates the advanced stealth technology in the classic ninja scarf."
icon_state = "armor_booster"
origin_tech = "combat=5;bluespace=6;syndicate=4"
active_power_cost = DEFAULT_CHARGE_DRAIN * 0.2
removable = FALSE
/// Linked sneaking action
var/datum/action/cooldown/ninja/ninja_cloak/cloak_action
/obj/item/mod/module/shinobi_stealth/Initialize(mapload)
. = ..()
cloak_action = new(src)
/obj/item/mod/module/shinobi_stealth/on_suit_activation()
. = ..()
cloak_action.Grant(mod.wearer)
/obj/item/mod/module/shinobi_stealth/on_suit_deactivation(deleting = FALSE)
if(deleting)
return
cloak_action.stop_sneaking()
cloak_action.Remove(mod.wearer)
/obj/item/mod/module/shinobi_freedom
name = "MOD shinobi escape module"
desc = "An advanced module, designed by the Spider Clan, that replicates the advanced escaping technology in the classic ninja boots."
icon_state = "armor_booster"
origin_tech = "combat=5;bluespace=6;syndicate=4"
active_power_cost = DEFAULT_CHARGE_DRAIN * 0.2
removable = FALSE
/// Linked freedom action
var/datum/action/cooldown/ninja/freedom_shoes/freedoms_action
/obj/item/mod/module/shinobi_freedom/Initialize(mapload)
. = ..()
freedoms_action = new(src)
/obj/item/mod/module/shinobi_freedom/on_suit_activation()
. = ..()
ADD_TRAIT(mod.wearer, TRAIT_GOTTAGONOTSOFAST, src)
freedoms_action.Grant(mod.wearer)
/obj/item/mod/module/shinobi_freedom/on_suit_deactivation(deleting = FALSE)
if(deleting)
return
REMOVE_TRAIT(mod.wearer, TRAIT_GOTTAGONOTSOFAST, src)
freedoms_action.Remove(mod.wearer)
/obj/item/mod/module/shinobi_stims
name = "MOD shinobi stimulant module"
desc = "An advanced module, designed by the Spider Clan, that replicates the advanced stimulants technology in the classic ninja kabuto."
icon_state = "armor_booster"
origin_tech = "combat=5;bluespace=6;syndicate=4"
active_power_cost = DEFAULT_CHARGE_DRAIN * 0.2
removable = FALSE
/// Linked stims action
var/datum/action/cooldown/ninja/stim_suit/antistun_action
/obj/item/mod/module/shinobi_stims/Initialize(mapload)
. = ..()
antistun_action = new(src)
/obj/item/mod/module/shinobi_stims/on_suit_activation()
. = ..()
ADD_TRAIT(mod.wearer, TRAIT_GOTTAGONOTSOFAST, src)
antistun_action.Grant(mod.wearer)
/obj/item/mod/module/shinobi_stims/on_suit_deactivation(deleting = FALSE)
if(deleting)
return
REMOVE_TRAIT(mod.wearer, TRAIT_GOTTAGONOTSOFAST, src)
antistun_action.Remove(mod.wearer)
-76
View File
@@ -1,76 +0,0 @@
/obj/item/katana/energy
name = "energy katana"
desc = "A katana infused with a strong energy."
icon = 'icons/obj/weapons/energy_melee.dmi'
icon_state = "energy_katana"
throwforce = 20
armor_penetration_percentage = 50
armor_penetration_flat = 10
var/cooldown = 0 // Because spam aint cool, yo.
var/datum/effect_system/spark_spread/spark_system
/obj/item/katana/energy/attack__legacy__attackchain(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
playsound(user, 'sound/weapons/blade1.ogg', 50, TRUE, -1)
return ..()
/obj/item/katana/energy/afterattack__legacy__attackchain(atom/target, mob/user, proximity_flag, click_parameters)
if(!user || !target)
return
if(proximity_flag && user.mind.special_role == "Ninja" && !cooldown && isobj(target))
cooldown = 1
spark_system.start()
playsound(user, "sparks", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
playsound(user, 'sound/weapons/blade1.ogg', 50, 1)
user.visible_message(SPAN_DANGER("[user] masterfully slices [target]!"), SPAN_NOTICE("You masterfully slice [target]!"))
target.emag_act(user)
sleep(15)
cooldown = 0
/*/obj/item/katana/energy/throw_impact(atom/hit_atom)
if(ishuman(hit_atom))
var/mob/living/carbon/human/H = hit_atom
if(istype(H.wear_suit, /obj/item/clothing/suit/space/space_ninja))
var/obj/item/clothing/suit/space/space_ninja/SN = H.wear_suit
if(SN.energyKatana && SN.energyKatana == src)
returnToOwner(H, 0, 1)
return
..()*/
/obj/item/katana/energy/proc/returnToOwner(mob/living/carbon/human/user, doSpark = 1, caught = 0)
if(!istype(user))
return
loc = get_turf(src)
if(doSpark)
spark_system.start()
playsound(get_turf(src), "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, FALSE, TRUE))
msg = "Your Energy Katana teleports back to you, sheathing itself as it does so!</span>"
else
loc = get_turf(user)
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]"))
/obj/item/katana/energy/Initialize(mapload)
. = ..()
spark_system = new /datum/effect_system/spark_spread()
spark_system.set_up(5, 0, src)
spark_system.attach(src)
/obj/item/katana/energy/Destroy()
QDEL_NULL(spark_system)
return ..()
+101
View File
@@ -0,0 +1,101 @@
/datum/action/cooldown/ninja
background_icon_state = "bg_ninja"
button_icon_state = "genetic_view"
/datum/action/cooldown/ninja/ninja_cloak
name = "Ninja's Stealth"
desc = "Toggles whether you are currently sneaking, reducing your visibility and movement speed. Enhanced effects in darkness."
button_icon_state = "vampire_cloak"
cooldown_time = 2 SECONDS
var/sneaking = FALSE
/datum/action/cooldown/ninja/ninja_cloak/proc/update_action_name()
name = "[initial(name)] ([sneaking ? "Deactivate" : "Activate"])"
SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_NAME)
build_all_button_icons()
/datum/action/cooldown/ninja/ninja_cloak/proc/stop_sneaking()
if(!ishuman(owner))
return
var/mob/living/carbon/human/H = owner
sneaking = FALSE
STOP_PROCESSING(SSobj, src)
UnregisterSignal(H, COMSIG_ATTACK)
UnregisterSignal(H, COMSIG_ATTACK_BY)
H.set_alpha_tracking(ALPHA_VISIBLE, src)
REMOVE_TRAIT(owner, TRAIT_GOTTAGOSLOW, src)
/datum/action/cooldown/ninja/ninja_cloak/process()
. = ..()
if(!ishuman(owner))
return
var/mob/living/carbon/human/H = owner
if(H.stat)
stop_sneaking()
return
if(!sneaking)
stop_sneaking()
return
var/turf/simulated/T = get_turf(H)
var/light_available = T.get_lumcount() * 10
if(light_available <= 2)
H.set_alpha_tracking(ALPHA_VISIBLE * 0.1, src)
return
H.set_alpha_tracking(ALPHA_VISIBLE * 0.5, src)
/datum/action/cooldown/ninja/ninja_cloak/Activate(atom/target)
if(!ishuman(owner))
return
var/mob/living/carbon/human/H = owner
sneaking = !sneaking
update_action_name()
if(sneaking)
to_chat(H, "<span class='notice'>You are now sneaking around. Stick to the darkness to conceal yourself better.</span>")
START_PROCESSING(SSobj, src)
RegisterSignal(owner, COMSIG_ATTACK, PROC_REF(stop_sneaking))
RegisterSignal(owner, COMSIG_ATTACK_BY, PROC_REF(stop_sneaking))
ADD_TRAIT(owner, TRAIT_GOTTAGOSLOW, src)
else
to_chat(H, "<span class='notice'>You are no longer sneaking around.</span>")
stop_sneaking()
StartCooldown()
/datum/action/cooldown/ninja/freedom_shoes
name = "Ninja's Mobility"
desc = "Breaks free of leg restraints. 2 Minute cooldown."
button_icon = 'icons/obj/bio_chips.dmi'
button_icon_state = "freedom"
cooldown_time = 2 MINUTES
/datum/action/cooldown/ninja/freedom_shoes/Activate(atom/target)
if(!ishuman(owner))
return
var/mob/living/carbon/human/H = owner
H.clear_legcuffs(TRUE)
H.SetKnockDown(0)
H.stand_up(TRUE)
StartCooldown()
/datum/action/cooldown/ninja/stim_suit
name = "Ninja's Tenacity"
desc = "Activates an injector within your suit, pumping you with a small hit of stimulants. 2 Minute cooldown."
button_icon = 'icons/obj/bio_chips.dmi'
button_icon_state = "adrenal"
cooldown_time = 2 MINUTES
/datum/action/cooldown/ninja/stim_suit/Activate(atom/target)
if(!ishuman(owner))
return
var/mob/living/carbon/human/H = owner
H.SetStunned(0)
H.SetWeakened(0)
H.SetKnockDown(0)
H.SetParalysis(0)
H.adjustStaminaLoss(-75)
H.stand_up(TRUE)
SEND_SIGNAL(H, COMSIG_LIVING_CLEAR_STUNS)
H.reagents.add_reagent("stimulative_agent", 1) // 10 Seconds.
StartCooldown()
+195
View File
@@ -0,0 +1,195 @@
/obj/item/clothing/head/helmet/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 fukumen"
icon_state = "s-ninja"
inhand_icon_state = "s-ninja_hood"
flags = BLOCKHAIR
flags_inv = HIDEEARS|HIDEEYES|HIDEFACE
armor = list(MELEE = 30, BULLET = 35, LASER = 25, ENERGY = 25, BOMB = 20, RAD = 100, FIRE = INFINITY, ACID = INFINITY)
origin_tech = "combat=5;materials=5;syndicate=2"
blockTracking = 1
icon_monitor = 'icons/mob/clothing/species/machine/monitor/hood.dmi'
sprite_sheets = list(
"Unathi" = 'icons/mob/clothing/species/unathi/head.dmi',
"Tajaran" = 'icons/mob/clothing/species/tajaran/head.dmi',
"Skrell" = 'icons/mob/clothing/species/skrell/head.dmi',
"Vox" = 'icons/mob/clothing/species/vox/head.dmi',
"Vulpkanin" = 'icons/mob/clothing/species/vulpkanin/head.dmi',
"Drask" = 'icons/mob/clothing/species/drask/head.dmi',
"Grey" = 'icons/mob/clothing/species/grey/head.dmi',
"Nian" = 'icons/mob/clothing/species/nian/head.dmi',
"Diona" = 'icons/mob/clothing/species/diona/head.dmi',
"Kidan" = 'icons/mob/clothing/species/kidan/head.dmi',
"Skkulakin" = 'icons/mob/clothing/species/vox/head.dmi',
)
/// Tracking the cloak action
var/datum/action/cooldown/ninja/ninja_cloak/cloak_action
/obj/item/clothing/head/helmet/space_ninja/Initialize(mapload)
. = ..()
cloak_action = new(src)
/obj/item/clothing/head/helmet/space_ninja/equipped(mob/user, slot, initial)
. = ..()
if(!ishuman(user))
return
if(slot != ITEM_SLOT_HEAD)
return
cloak_action.Grant(user)
/obj/item/clothing/head/helmet/space_ninja/dropped(mob/user, silent)
. = ..()
cloak_action.stop_sneaking()
cloak_action.Remove(user)
/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"
flash_protect = FLASH_PROTECTION_FLASH
origin_tech = "combat=4;materials=4;syndicate=1"
icon_monitor = 'icons/mob/clothing/species/machine/monitor/mask.dmi'
sprite_sheets = list(
"Unathi" = 'icons/mob/clothing/species/unathi/mask.dmi',
"Tajaran" = 'icons/mob/clothing/species/tajaran/mask.dmi',
"Skrell" = 'icons/mob/clothing/species/skrell/mask.dmi',
"Vox" = 'icons/mob/clothing/species/vox/mask.dmi',
"Vulpkanin" = 'icons/mob/clothing/species/vulpkanin/mask.dmi',
"Drask" = 'icons/mob/clothing/species/drask/mask.dmi',
"Grey" = 'icons/mob/clothing/species/grey/mask.dmi',
"Nian" = 'icons/mob/clothing/species/nian/mask.dmi',
"Diona" = 'icons/mob/clothing/species/diona/mask.dmi',
"Kidan" = 'icons/mob/clothing/species/kidan/mask.dmi',
"Skkulakin" = 'icons/mob/clothing/species/skkulakin/mask.dmi',
)
var/obj/item/voice_changer/voice_changer
/obj/item/clothing/mask/gas/space_ninja/Initialize(mapload)
. = ..()
voice_changer = new(src)
/obj/item/clothing/mask/gas/space_ninja/Destroy()
QDEL_NULL(voice_changer)
return ..()
/obj/item/clothing/gloves/space_ninja
desc = "These nano-enhanced gloves insulate from electricity and provide fire resistance."
name = "ninja tekko"
icon_state = "s-ninja"
siemens_coefficient = 0
pickpocket = TRUE // Master of stealth, you can pick a pocket
armor = list(MELEE = 30, BULLET = 35, LASER = 25, ENERGY = 25, BOMB = 20, RAD = 100, FIRE = INFINITY, ACID = INFINITY)
cold_protection = HANDS
min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT
heat_protection = HANDS
max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
origin_tech = "combat=5;materials=5;syndicate=2"
sprite_sheets = list(
"Vox" = 'icons/mob/clothing/species/vox/gloves.dmi',
"Skkulakin" = 'icons/mob/clothing/species/vox/gloves.dmi',
"Drask" = 'icons/mob/clothing/species/drask/gloves.dmi',
"Diona" = 'icons/mob/clothing/species/diona/gloves.dmi',
"Kidan" = 'icons/mob/clothing/species/kidan/gloves.dmi',
)
/obj/item/clothing/shoes/space_ninja
name = "ninja jaka-tabi"
desc = "A pair of split-toed rubber-soled shoes. Excellent for running and even better for smashing skulls."
icon_state = "s-ninja"
permeability_coefficient = 0.01
no_slip = TRUE
armor = list(MELEE = 30, BULLET = 35, LASER = 25, ENERGY = 25, BOMB = 20, RAD = 100, FIRE = INFINITY, ACID = INFINITY)
cold_protection = FEET
min_cold_protection_temperature = SHOES_MIN_TEMP_PROTECT
heat_protection = FEET
max_heat_protection_temperature = SHOES_MAX_TEMP_PROTECT
origin_tech = "combat=5;materials=5;syndicate=2"
sprite_sheets = list(
"Vox" = 'icons/mob/clothing/species/vox/shoes.dmi',
"Drask" = 'icons/mob/clothing/species/drask/shoes.dmi',
"Diona" = 'icons/mob/clothing/species/diona/shoes.dmi',
"Kidan" = 'icons/mob/clothing/species/kidan/shoes.dmi',
"Skkulakin" = 'icons/mob/clothing/species/vox/shoes.dmi',
)
/// Linked freedoms action
var/datum/action/cooldown/ninja/freedom_shoes/freedoms_action
/obj/item/clothing/shoes/space_ninja/Initialize(mapload)
. = ..()
freedoms_action = new(src)
/obj/item/clothing/shoes/space_ninja/equipped(mob/user, slot, initial)
. = ..()
if(!ishuman(user))
return
if(slot != ITEM_SLOT_SHOES)
return
ADD_TRAIT(user, TRAIT_GOTTAGONOTSOFAST, src)
freedoms_action.Grant(user)
/obj/item/clothing/shoes/space_ninja/dropped(mob/user, silent)
. = ..()
REMOVE_TRAIT(user, TRAIT_GOTTAGONOTSOFAST, src)
freedoms_action.Remove(user)
/obj/item/clothing/suit/space_ninja
name = "ninja uwagi"
desc = "A unique 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/melee/baton,
/obj/item/tank/internals,
/obj/item/katana/energy,
/obj/item/restraints/handcuffs,
/obj/item/ninja_scanner
)
flags_inv = HIDEJUMPSUIT
armor = list(MELEE = 30, BULLET = 35, LASER = 25, ENERGY = 25, BOMB = 20, RAD = 100, FIRE = INFINITY, ACID = INFINITY)
origin_tech = "combat=5;materials=5;syndicate=2"
sprite_sheets = list(
"Vox" = 'icons/mob/clothing/species/vox/suit.dmi',
"Drask" = 'icons/mob/clothing/species/drask/suit.dmi',
"Grey" = 'icons/mob/clothing/species/grey/suit.dmi',
"Nian" = 'icons/mob/clothing/species/nian/suit.dmi',
"Diona" = 'icons/mob/clothing/species/diona/suit.dmi',
"Kidan" = 'icons/mob/clothing/species/kidan/suit.dmi',
"Skkulakin" = 'icons/mob/clothing/species/vox/suit.dmi',
)
/// Linked stims action
var/datum/action/cooldown/ninja/stim_suit/antistun_action
/obj/item/clothing/suit/space_ninja/Initialize(mapload)
. = ..()
antistun_action = new(src)
/obj/item/clothing/suit/space_ninja/equipped(mob/user, slot, initial)
. = ..()
if(!ishuman(user))
return
if(slot != ITEM_SLOT_OUTER_SUIT)
return
antistun_action.Grant(user)
/obj/item/clothing/suit/space_ninja/dropped(mob/user, silent)
. = ..()
antistun_action.Remove(user)
/obj/item/storage/bag/garment/syndie/ninja_suit
name = "ninja suit garment bag"
/obj/item/storage/bag/garment/syndie/ninja_suit/populate_contents()
new /obj/item/clothing/under/syndicate(src)
new /obj/item/clothing/shoes/space_ninja(src)
new /obj/item/clothing/gloves/space_ninja(src)
new /obj/item/clothing/head/helmet/space_ninja(src)
new /obj/item/clothing/mask/gas/space_ninja(src)
new /obj/item/clothing/suit/space_ninja(src)
/obj/item/card/id/syndicate/ninja
name = "ninja card"
initial_access = list(ACCESS_MAINT_TUNNELS)
icon_state = "data"
+181
View File
@@ -0,0 +1,181 @@
/obj/machinery/syndicatebomb/ninja
name = "spider clan bomb"
payload = /obj/item/bombcore/ninja
/obj/machinery/syndicatebomb/ninja/emp
name = "spider clan EMP bomb"
payload = /obj/item/bombcore/emp/ninja
/obj/machinery/syndicatebomb/ninja/spiders
name = "spider bomb"
payload = /obj/item/bombcore/badmin/summon/ninja_spiders
/obj/item/bombcore/ninja
desc = "A powerful secondary explosive of spider clan design and unknown composition, it should be stable under normal conditions..."
range_heavy = 3
range_medium = 8
range_light = 15
range_flame = 17
/obj/item/bombcore/emp/ninja
light_emp = 24
heavy_emp = 12
/obj/item/bombcore/badmin/summon/ninja_spiders
summon_path = /mob/living/basic/giant_spider
amt_summon = 12
/obj/item/wormhole_jaunter/ninja_bomb
name = "spider clan bomb deployment flare"
icon = 'icons/obj/lighting.dmi'
desc = "A single-use flare that will bring a high-yield payload to the location it was lit at."
icon_state = "flare-contractor"
inhand_icon_state = "flare"
/// What area should be blow up?
var/area/bomb_target
/// What kind of bomb is it
var/obj/machinery/syndicatebomb/bomb_type = /obj/machinery/syndicatebomb/ninja
/obj/item/wormhole_jaunter/ninja_bomb/Initialize(mapload)
. = ..()
var/list/possible_areas = list(
// Rooms
/area/station/hallway/primary/aft,
/area/station/engineering/atmos,
/area/station/public/arcade,
/area/station/maintenance/assembly_line,
/area/station/public/storage/tools/auxiliary,
/area/station/command/office/blueshield,
/area/station/supply/storage,
/area/station/service/chapel,
/area/station/service/chapel/office,
/area/station/service/clown,
/area/station/legal/courtroom,
/area/station/public/toilet,
/area/station/engineering/control,
/area/station/engineering/controlroom,
/area/station/hallway/secondary/exit,
/area/holodeck/alphadeck,
/area/station/service/hydroponics,
/area/station/service/library,
/area/station/service/mime,
/area/station/supply/miningdock,
/area/station/medical/morgue,
/area/station/public/storage/office,
/area/station/public/pet_store,
/area/station/public/storage/tools,
/area/station/public/mrchangs,
/area/station/science/research,
/area/station/security/checkpoint,
/area/station/engineering/tech_storage,
/area/station/command/teleporter,
/area/station/science/storage,
/area/station/science/misc_lab,
/area/station/science/xenobiology,
/area/station/turret_protected/aisat/interior,
/area/station/aisat/atmos,
/area/station/aisat/hall,
/area/station/aisat/service,
/area/station/service/bar,
/area/station/supply/office,
/area/station/medical/chemistry,
/area/station/command/office/ce,
/area/station/command/office/cmo,
/area/station/medical/cloning,
/area/station/medical/cryo,
/area/station/public/dorms,
/area/station/engineering/equipmentstorage,
/area/station/engineering/break_room,
/area/station/ai_monitored/storage/eva,
/area/station/supply/expedition,
/area/station/science/genetics,
/area/station/engineering/gravitygenerator,
/area/station/command/office/hop,
/area/station/command/meeting_room,
/area/station/service/kitchen,
/area/station/science/robotics/chargebay,
/area/station/medical/medbay,
/area/station/medical/medbay2,
/area/station/medical/medbay3,
/area/station/medical/reception,
/area/station/medical/storage,
/area/station/medical/sleeper,
/area/station/command/server,
/area/station/command/office/ntrep,
/area/station/medical/paramedic,
/area/station/hallway/primary/port,
/area/station/supply/qm,
/area/station/command/office/rd,
/area/station/science/rnd,
/area/station/science/robotics,
/area/station/medical/surgery/primary,
/area/station/medical/surgery/secondary,
/area/station/telecomms/chamber,
/area/station/engineering/secure_storage
)
while(!bomb_target)
var/area/selected_area = pick_n_take(possible_areas)
for(var/area/potential in SSmapping.existing_station_areas)
if(potential.type != selected_area)
continue
bomb_target = potential
break
/obj/item/wormhole_jaunter/ninja_bomb/examine(mob/user)
. = ..()
if(isAntag(user))
. += SPAN_WARNING("The target bomb location is: [bomb_target.name]")
/obj/item/wormhole_jaunter/ninja_bomb/activate(mob/user)
if(!turf_check(user))
return
var/obj/effect/temp_visual/ninja_bomb/F = new /obj/effect/temp_visual/ninja_bomb(get_turf(src))
user.drop_item()
forceMove(F)
log_and_message_admins("[user] activated a ninja bomb flare.")
addtimer(CALLBACK(src, PROC_REF(spawn_bomb), user), 5 SECONDS)
/obj/item/wormhole_jaunter/ninja_bomb/proc/spawn_bomb(mob/user)
new /obj/effect/decal/cleanable/ash(get_turf(src))
var/obj/machinery/syndicatebomb/new_bomb = new bomb_type(get_turf(src))
new_bomb.anchored = TRUE
new_bomb.activate()
var/objectives = user.mind.get_all_objectives()
for(var/datum/objective/ninja/bomb_department/bomb_dep in objectives)
if(!bomb_dep.completed)
to_chat(user, SPAN_NOTICE("Contract complete. Good work - your cut of the pay has been forwarded to your uplink."))
bomb_dep.complete_objective()
qdel(src)
/obj/item/wormhole_jaunter/ninja_bomb/turf_check(mob/user)
var/turf/device_turf = get_turf(user)
if(!device_turf)
to_chat(user, "<span class='notice'>You're having difficulties getting the [name] to work.</span>")
return FALSE
var/area/our_area = get_area(device_turf)
if(!istype(our_area, bomb_target))
to_chat(user, "<span class='notice'>You're having difficulties getting the [name] to work.</span>")
return FALSE
return TRUE
/obj/item/wormhole_jaunter/ninja_bomb/emp
bomb_type = /obj/machinery/syndicatebomb/ninja/emp
/obj/item/wormhole_jaunter/ninja_bomb/spiders
bomb_type = /obj/machinery/syndicatebomb/ninja/spiders
/obj/effect/temp_visual/ninja_bomb
name = "spider clan bomb deployment flare"
layer = BELOW_MOB_LAYER
icon = 'icons/obj/lighting.dmi'
icon_state = "flare-contractor-on"
duration = 5.1 SECONDS
/// Sound that plays when activated
var/activation_sound = 'sound/goonstation/misc/matchstick_light.ogg'
/// Light emitted when activated
var/emitted_color = "#1faf2b"
/obj/effect/temp_visual/ninja_bomb/Initialize(mapload)
. = ..()
playsound(loc, activation_sound, 50, TRUE)
set_light(8, l_color = emitted_color)
+54
View File
@@ -0,0 +1,54 @@
/datum/outfit/space_ninja
name = "Space Ninja"
uniform = /obj/item/clothing/under/syndicate
shoes = /obj/item/clothing/shoes/space_ninja
gloves = /obj/item/clothing/gloves/space_ninja
head = /obj/item/clothing/head/helmet/space_ninja
mask = /obj/item/clothing/mask/gas/space_ninja
glasses = /obj/item/clothing/glasses/night
suit = /obj/item/clothing/suit/space_ninja
belt = /obj/item/katana/energy
id = /obj/item/card/id/syndicate/ninja
back = /obj/item/storage/backpack/satchel
l_ear = /obj/item/radio/headset
box = /obj/item/storage/box/survival_syndie
backpack_contents = list(
/obj/item/storage/box/syndie_kit/throwing_weapons,
/obj/item/ninja_scanner,
/obj/item/gun/energy/kinetic_accelerator/energy_net,
/obj/item/wormhole_jaunter/extraction,
/obj/item/teleportation_scroll/apprentice,
)
bio_chips = list(
/obj/item/bio_chip/dust,
/obj/item/bio_chip/uplink/ninja
)
/datum/outfit/space_ninja/vox
name = "Space Ninja - Vox"
/datum/outfit/space_ninja/vox/post_equip(mob/living/carbon/human/H, visualsOnly)
. = ..()
var/obj/item/tank/internal_tank = new /obj/item/tank/internals/emergency_oxygen/double/vox(H)
if(!H.equip_to_appropriate_slot(internal_tank))
if(!H.put_in_any_hand_if_possible(internal_tank))
H.drop_item_to_ground(H.l_hand)
H.equip_or_collect(internal_tank, ITEM_SLOT_LEFT_HAND)
to_chat(H, "<span class='boldannounceooc'>Could not find an empty slot for internals! Please report this as a bug</span>")
H.internal = internal_tank
/datum/outfit/admin/ghostbar_antag/space_ninja
name = "Ghostbar Space Ninja"
uniform = /obj/item/clothing/under/syndicate
shoes = /obj/item/clothing/shoes/space_ninja
gloves = /obj/item/clothing/gloves/space_ninja
head = /obj/item/clothing/head/helmet/space_ninja
mask = /obj/item/clothing/mask/gas/space_ninja
suit = /obj/item/clothing/suit/space_ninja
belt = /obj/item/toy/katana
back = /obj/item/storage/backpack/satchel
backpack_contents = list(
/obj/item/storage/box/engineer = 1,
/obj/item/flashlight = 1,
/obj/item/food/syndidonkpocket = 1,
)
+143
View File
@@ -0,0 +1,143 @@
/obj/item/ninja_scanner
name = "spider scanner"
desc = "Advanced multi-use scanning device used by the spider clan to confirm bounty completion. Scan the corpses of dead or netted crew to redeem your bounties."
icon = 'icons/obj/device.dmi'
icon_state = "ninja_scanner"
slot_flags = ITEM_SLOT_BELT
force = 9 // Can be used as a weapon in an emergency
hitsound = 'sound/weapons/genhit1.ogg'
new_attack_chain = TRUE
/obj/item/ninja_scanner/attack(mob/living/target, mob/living/user, params)
if(user.a_intent == INTENT_HARM)
return ..()
if(!user.mind)
return ..()
var/list/obj_list = user.mind.get_all_objectives()
if(!length(obj_list))
to_chat(user, SPAN_WARNING("You have no objectives!"))
return TRUE
for(var/datum/objective/ninja/ninja_obj in obj_list)
if(ninja_obj.completed)
continue
if(istype(ninja_obj, /datum/objective/ninja/kill))
if(target.stat != DEAD)
continue
if(!ninja_obj.target.current || target != ninja_obj.target.current)
continue
user.visible_message(SPAN_DANGER("[user] begins to use [src] to scan [target]!"), \
SPAN_NOTICE("You begin to scan [target]!"))
if(!do_after_once(user, 8 SECONDS, target = target, allow_moving = FALSE, attempt_cancel_message = "You stop scanning [target] before completing the scan."))
return TRUE
ninja_obj.completed = TRUE
to_chat(user, SPAN_NOTICE("Contract complete. Good work - your cut of the pay has been forwarded to your uplink."))
ninja_obj.complete_objective()
return TRUE
if(istype(ninja_obj, /datum/objective/ninja/capture))
var/datum/objective/ninja/capture/cap_obj = ninja_obj
if(target != ninja_obj.target.current)
continue
if(target.stat == DEAD)
if(!target.ghost_can_reenter()) // Target is DNR. Reroll.
to_chat(user, SPAN_NOTICE("Target is unrecoverable. Finding a new target..."))
ninja_obj.on_target_cryo()
else
to_chat(user, SPAN_NOTICE("Target is dead. Dead people don't talk. Esnure they are revived, then send them to us."))
continue
if(!target.buckled)
continue
var/obj/structure/bed/energy_net/trapped_net
for(var/obj/structure/bed/energy_net/net in target.loc)
trapped_net = net
break
if(!trapped_net)
continue
user.visible_message(SPAN_DANGER("[user] begins to use [src] to scan [target]!"), \
SPAN_NOTICE("You begin to scan [target]!"))
if(!do_after_once(user, 5 SECONDS, target = target, allow_moving = FALSE, attempt_cancel_message = "You stop scanning [target] before completing the scan."))
return TRUE
target.unbuckle(TRUE)
trapped_net.Destroy()
var/target_loc = target.loc
do_teleport(target, pick(GLOB.ninjaprisonwarp), 0, TRUE, bypass_area_flag = TRUE)
var/mob/living/carbon/c_target = target
if(istype(c_target))
var/obj/item/restraints/handcuffs/cuffs = target.get_item_by_slot(ITEM_SLOT_HANDCUFFED)
qdel(cuffs)
c_target.handcuffed = FALSE
c_target.update_handcuffed()
cap_obj.handle_capture(target, target_loc)
ninja_obj.completed = TRUE
to_chat(user, SPAN_NOTICE("Contract complete. Good work - your cut of the pay has been forwarded to your uplink."))
ninja_obj.complete_objective()
return TRUE
if(istype(ninja_obj, /datum/objective/ninja/interrogate_ai))
if(!is_ai(target))
return TRUE
var/mob/living/silicon/ai/AI = target
user.visible_message(SPAN_DANGER("[user] begins to use [src] to upload [AI]!"), \
SPAN_NOTICE("You begin to upload [AI]!"))
if(!do_after_once(user, 8 SECONDS, target = AI, allow_moving = FALSE, attempt_cancel_message = "You stop uploading [AI] before completing the upload."))
return TRUE
var/obj/item/aicard/card = new()
AI.take_overall_damage(50)
AI.transfer_ai(AI_TRANS_TO_CARD, user, null, card)
var/list/possible_spawns = GLOB.maints_loot_spawns
while(length(possible_spawns))
var/turf/current_turf = pick_n_take(possible_spawns)
if(!is_station_level(current_turf))
continue
if(!current_turf.density)
do_teleport(card, current_turf)
break
// Someone built a wall over it, check the surroundings
var/list/open_turfs = current_turf.AdjacentTurfs(open_only = TRUE)
if(length(open_turfs))
do_teleport(card, pick(open_turfs))
break
ninja_obj.completed = TRUE
to_chat(user, SPAN_NOTICE("Contract complete. Good work - your cut of the pay has been forwarded to your uplink."))
ninja_obj.complete_objective()
return TRUE
return ..()
/obj/item/ninja_scanner/attack_obj(obj/attacked_obj, mob/living/user, params)
if(user.a_intent == INTENT_HARM)
return ..()
if(!user.mind)
return ..()
var/list/obj_list = user.mind.get_all_objectives()
if(!length(obj_list))
to_chat(user, SPAN_WARNING("You have no objectives!"))
return TRUE
for(var/datum/objective/ninja/ninja_obj in obj_list)
if(ninja_obj.completed)
continue
if(istype(ninja_obj, /datum/objective/ninja/hack_rnd) && istype(attacked_obj, /obj/machinery/computer/rnd_network_controller))
if(!do_after_once(user, 12 SECONDS, target = attacked_obj, allow_moving = FALSE, attempt_cancel_message = "You stop hacking [attacked_obj] before completing the download."))
return TRUE
to_chat(user, SPAN_NOTICE("Contract complete. Good work - your cut of the pay has been forwarded to your uplink."))
var/obj/machinery/computer/rnd_network_controller/rnd = attacked_obj
rnd.research_files.known_tech = list()
ninja_obj.completed = TRUE
ninja_obj.complete_objective()
return TRUE
if(istype(ninja_obj, /datum/objective/ninja/insert_spider_rod) && istype(attacked_obj, /obj/machinery/atmospherics/reactor_chamber))
var/obj/machinery/atmospherics/reactor_chamber/r_chamber = attacked_obj
if(!r_chamber.held_rod)
to_chat(user, SPAN_NOTICE("There is no rod in [r_chamber]."))
return TRUE
if(!istype(r_chamber.held_rod, /obj/item/nuclear_rod/fuel/uranium_238/spiders))
to_chat(user, SPAN_NOTICE("The rod in [r_chamber] is not one of ours."))
return TRUE
if(r_chamber.linked_reactor.offline)
to_chat(user, SPAN_NOTICE("[r_chamber.linked_reactor] is not online."))
return TRUE
to_chat(user, SPAN_NOTICE("Contract complete. Good work - your cut of the pay has been forwarded to your uplink."))
ninja_obj.completed = TRUE
ninja_obj.complete_objective()
return TRUE
return ..()
+91
View File
@@ -0,0 +1,91 @@
/obj/item/bio_chip/uplink/ninja
name = "spider clan uplink bio-chip"
desc = "Purchase things from the spider clan with earned currency."
/obj/item/bio_chip/uplink/ninja/Initialize(mapload)
. = ..()
if(hidden_uplink)
hidden_uplink.update_uplink_type(UPLINK_TYPE_NINJA)
hidden_uplink.uses = 0
/datum/uplink_item/ninja
category = "Spider Clan Provisions"
surplus = 0
uplinktypes = list(UPLINK_TYPE_NINJA)
/datum/uplink_item/ninja/shuriken_printer
name = "Shuriken Printer"
desc = "An advanced, tiny autofabricator that slowly creates and stores energy shurikens."
reference = "SPR"
item = /obj/item/shuriken_printer
cost = 25
/datum/uplink_item/ninja/ninja_modsuit
name = "'Shinobi' Stealth Modsuit"
desc = "A specialized modsuit worn by the spider clan's elite ninja operatives."
reference = "SNBMOD"
item = /obj/item/mod/control/pre_equipped/ninja
cost = 45
/datum/uplink_item/ninja/energy_katana
name = "Energy Katana"
desc = "A plastitanium katana with a reinforced emitter edge. A ninja's most reliable tool."
reference = "EKAT"
item = /obj/item/katana/energy
cost = 20
/datum/uplink_item/ninja/energy_net
name = "Energy Net Projector"
desc = "A non-lethal weapon favored by the Spider Clan. Targets struck will find themselves trapped in an energy net."
reference = "ENET"
item = /obj/item/gun/energy/kinetic_accelerator/energy_net
cost = 30
/datum/uplink_item/ninja/spider_bomb
name = "Spider Bomb"
desc = "An evil device fabricated by the Spider Clan. This bomb contains a large number of dehydrated spider-cubes that will all activate upon detonation. These spiders do not discern friend from foe - all non-spiders make for good food."
reference = "SPBM"
item = /obj/machinery/syndicatebomb/ninja/spiders
cost = 65
/datum/uplink_item/ninja/hood
name = "Ninja Scarf"
desc = "What may appear to be a simple black garment is in fact a highly sophisticated nano-weave helmet. Standard issue ninja gear."
reference = "NJSC"
item = /obj/item/clothing/head/helmet/space_ninja
cost = 10
/datum/uplink_item/ninja/mask
name = "Ninja Mask"
desc = "A close-fitting mask that acts both as an air filter and a post-modern fashion statement."
reference = "NJMSK"
item = /obj/item/clothing/mask/gas/space_ninja
cost = 10
/datum/uplink_item/ninja/gloves
name = "Ninja Gloves"
desc = "These nano-enhanced gloves insulate from electricity and provide fire resistance."
reference = "NJGL"
item = /obj/item/clothing/gloves/space_ninja
cost = 10
/datum/uplink_item/ninja/shoes
name = "Ninja Shoes"
desc = "A pair of running shoes. Excellent for running and even better for smashing skulls."
reference = "NJSH"
item = /obj/item/clothing/shoes/space_ninja
cost = 10
/datum/uplink_item/ninja/suit
name = "Ninja Kabuto"
desc = "A unique suit of nano-enhanced armor designed specifically for Spider Clan assassins."
reference = "NJKB"
item = /obj/item/clothing/suit/space_ninja
cost = 10
/datum/uplink_item/ninja/suit_bundle
name = "Full Ninja Outfit"
desc = "A bulk purchase of a full ninja outfit. Good for if you somehow lost the other set of highly advanced Spider Clan equipment."
reference = "NJST"
item = /obj/item/clothing/suit/space_ninja
cost = 40
+227
View File
@@ -0,0 +1,227 @@
/obj/item/katana/energy
name = "energy katana"
desc = "A plastitanium katana with a reinforced emitter edge. A ninja's most reliable tool."
icon = 'icons/obj/weapons/energy_melee.dmi'
icon_state = "energy_katana"
force = 30
embed_chance = 75
throwforce = 20
armor_penetration_percentage = 50
armor_penetration_flat = 10
origin_tech = "combat=6;syndicate=4"
hitsound = 'sound/weapons/blade1.ogg'
/// Is the weapon gripped or not?
var/gripped = FALSE
/obj/item/katana/energy/activate_self(mob/living/carbon/human/user)
. = ..()
if(!ishuman(user))
return
var/is_proper_modsuit = FALSE
if(istype(user.gloves, /obj/item/clothing/gloves/mod))
var/obj/item/mod/control/modsuit = user.get_item_by_slot(ITEM_SLOT_BACK)
if(istype(modsuit) && istype(modsuit.theme, /datum/mod_theme/ninja))
is_proper_modsuit = TRUE
if(!istype(user.gloves, /obj/item/clothing/gloves/space_ninja) && !is_proper_modsuit)
return
if(!gripped)
gripped = TRUE
to_chat(user, SPAN_NOTICE("You tighten your grip on [src], ensuring you won't drop it."))
set_nodrop(TRUE, user)
return
gripped = FALSE
to_chat(user, SPAN_NOTICE("You relax your grip on [src]."))
set_nodrop(FALSE, user)
/obj/item/katana/energy/dropped(mob/user, silent)
. = ..()
gripped = FALSE
to_chat(user, SPAN_WARNING("Your grip on [src] is loosened!"))
set_nodrop(FALSE, user)
/obj/item/katana/energy/equipped(mob/user, slot, initial)
. = ..()
if(gripped)
gripped = FALSE
to_chat(user, SPAN_NOTICE("You relax your grip on [src]."))
set_nodrop(FALSE, user)
/obj/item/katana/energy/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(!.) // they did not block the attack
return
if(isprojectile(hitby))
var/obj/projectile/P = hitby
if(P.reflectability == REFLECTABILITY_ENERGY)
owner.visible_message(SPAN_DANGER("[owner] parries [attack_text] with [src]!"))
add_attack_logs(P.firer, src, "hit by [P.type] but got parried by [src]")
return -1
owner.visible_message(SPAN_DANGER("[owner] blocks [attack_text] with [src]!"))
playsound(src, 'sound/weapons/effects/ric3.ogg', 100, TRUE)
return TRUE
return TRUE
/obj/item/energy_shuriken
name = "energy shuriken"
desc = "An ancient weapon, redefined. The blade hums with an electric edge, using itself as fuel."
icon = 'icons/obj/weapons/melee.dmi'
icon_state = "energy-shuriken"
inhand_icon_state = "eshield0"
lefthand_file = 'icons/mob/inhands/weapons_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons_righthand.dmi'
force = 5
throwforce = 30 // This is never used on mobs since this has a 100% embed chance.
throw_speed = 4
embedded_pain_multiplier = 4
w_class = WEIGHT_CLASS_SMALL
embed_chance = 100
embedded_fall_chance = 0
sharp = TRUE
resistance_flags = FIRE_PROOF
/obj/item/energy_shuriken/Initialize(mapload)
. = ..()
// Only lasts so long. Delete self after some time.
addtimer(CALLBACK(src, PROC_REF(qdel), src), 30 SECONDS)
/obj/item/energy_shuriken/throw_impact(atom/target)
. = ..()
if(!ishuman(target))
return
var/mob/living/carbon/human/H = target
H.apply_damage(60, STAMINA)
/obj/item/shuriken_printer
name = "shuriken printer"
desc = "An advanced, tiny autofabricator that slowly creates and stores energy shurikens."
icon = 'icons/obj/weapons/melee.dmi'
icon_state = "shuriken-pouch"
inhand_icon_state = "eshield0"
lefthand_file = 'icons/mob/inhands/weapons_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons_righthand.dmi'
origin_tech = "combat=6;syndicate=5"
force = 5
slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_SMALL
resistance_flags = FIRE_PROOF
new_attack_chain = TRUE
/// What is the maximum number of energy shurikens the printer can hold?
var/maximum_stars = 4
/// What is the current number of energy shurikens the printer is holding?
var/current_stars = 2
/// How long the cooldown is to print more shurikens
var/printing_time = 30 SECONDS
/// Timer used to print stars
var/fabrication_timer
/obj/item/shuriken_printer/Initialize(mapload)
. = ..()
fabrication_timer = addtimer(CALLBACK(src, PROC_REF(print_star)), 30 SECONDS, TIMER_LOOP | TIMER_STOPPABLE)
/obj/item/shuriken_printer/examine(mob/user)
. = ..()
. += SPAN_NOTICE("Alt-click to draw an energy shuriken!")
. += SPAN_NOTICE("It has [current_stars] stored.")
/obj/item/shuriken_printer/AltClick(mob/living/carbon/user, modifiers)
if(!iscarbon(user))
return ..()
if(current_stars < 1)
return ..()
current_stars--
var/obj/item/energy_shuriken/star = new /obj/item/energy_shuriken(get_turf(src), src)
user.put_in_hands(star)
to_chat(user, SPAN_NOTICE("You draw [star] from [src]."))
user.throw_mode_on()
/obj/item/shuriken_printer/proc/print_star()
if(current_stars < maximum_stars)
current_stars++
/obj/item/gun/energy/kinetic_accelerator/energy_net
name = "energy net projector"
desc = "A non-lethal weapon favored by the Spider Clan. Targets stunned by this weapon will be trapped in an energy net for extraction."
icon_state = "energy-net-gun"
inhand_icon_state = "energy-net-gun"
w_class = WEIGHT_CLASS_SMALL
materials = list(MAT_METAL=2000)
origin_tech = "combat=6;magnets=4;syndicate=4"
suppressed = TRUE
ammo_type = list(/obj/item/ammo_casing/energy/net)
unique_rename = FALSE
overheat_time = 3 SECONDS
holds_charge = TRUE
unique_frequency = TRUE
can_flashlight = FALSE
max_mod_capacity = 0
empty_state = "energy-net-gun_empty"
can_holster = TRUE
/obj/item/gun/energy/kinetic_accelerator/energy_net/Initialize(mapload)
. = ..()
ADD_TRAIT(src, TRAIT_SILENT_INSERTION, ROUNDSTART_TRAIT)
/obj/item/ammo_casing/energy/net
projectile_type = /obj/projectile/energy/net
muzzle_flash_color = null
muzzle_flash_effect = /obj/effect/temp_visual/target_angled/muzzle_flash
select_name = "energy net"
e_cost = 500
fire_sound = 'sound/weapons/bolathrow.ogg'
/obj/projectile/energy/net
name = "energy net"
icon_state = "net-end"
nodamage = 1
stamina = 60
knockdown = 4 SECONDS
speed = 1.5
/obj/projectile/energy/net/fire(setAngle)
if(firer)
firer.Beam(src, icon_state = "net-beam", time = INFINITY, maxdistance = INFINITY, beam_type = /obj/effect/ebeam/floor)
return ..()
/obj/projectile/energy/net/on_hit(atom/target, blocked, hit_zone)
. = ..()
if(!firer)
return
if(!ishuman(target))
return
var/mob/living/carbon/human/H = target
if(!H.stam_paralyzed)
return
var/obj/item/restraints/handcuffs/cable/zipties/cuff = new()
cuff.apply_cuffs(H, firer)
var/obj/structure/bed/energy_net/net = new(H.loc)
net.buckle_mob(H, TRUE)
/obj/structure/bed/energy_net
name = "energy net"
desc = "A pulsing array of green energy that can securely hold a victim in place."
icon = 'icons/effects/effects.dmi'
icon_state = "e-net"
/obj/structure/bed/energy_net/user_unbuckle_mob(mob/living/buckled_mob, mob/user)
if(!has_buckled_mobs())
Destroy() // We don't exist if nothing is being held
for(var/buck in buckled_mobs) // No net, no buckles
var/mob/living/M = buck
if(M != user)
if(!do_after(user, 10 SECONDS, target = src))
if(M && M.buckled)
to_chat(user, SPAN_WARNING("You fail to release [M] from \the [src]!"))
return
M.visible_message(SPAN_NOTICE("[user.name] pulls [M.name] free from the energy net!"),\
SPAN_NOTICE("[user.name] pulls you free from the energy net."),\
SPAN_ITALICS("You hear a small zap..."))
unbuckle_mob(M)
Destroy()
if(!M.buckled)
return
M.visible_message(SPAN_WARNING("[M.name] breaks free from the energy net!"),\
SPAN_NOTICE("You break free from the energy net!"),\
SPAN_ITALICS("You hear a small zap..."))
unbuckle_mob(M)
Destroy()
-12
View File
@@ -1,12 +0,0 @@
/obj/item/clothing/gloves/space_ninja
desc = "These nano-enhanced gloves insulate from electricity and provide fire resistance."
name = "ninja gloves"
icon_state = "s-ninja"
siemens_coefficient = 0
pickpocket = 1
cold_protection = HANDS
min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT
heat_protection = HANDS
max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
-10
View File
@@ -1,10 +0,0 @@
/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_hood"
flags_inv = HIDEEARS|HIDEEYES|HIDEFACE
armor = list(MELEE = 75, BULLET = 50, LASER = 20, ENERGY = 10, BOMB = 20, RAD = 15, FIRE = INFINITY, ACID = INFINITY)
blockTracking = 1
-28
View File
@@ -1,28 +0,0 @@
/*
Contents:
- The Ninja Space 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(norm)"
inhand_icon_state = "s-ninja_mask"
sprite_sheets = list(
"Vox" = 'icons/mob/clothing/species/vox/mask.dmi',
"Unathi" = 'icons/mob/clothing/species/unathi/mask.dmi',
"Tajaran" = 'icons/mob/clothing/species/tajaran/mask.dmi',
"Vulpkanin" = 'icons/mob/clothing/species/vulpkanin/mask.dmi'
)
var/obj/item/voice_changer/voice_changer
/obj/item/clothing/mask/gas/space_ninja/Initialize(mapload)
. = ..()
voice_changer = new(src)
/obj/item/clothing/mask/gas/space_ninja/Destroy()
QDEL_NULL(voice_changer)
return ..()
-12
View File
@@ -1,12 +0,0 @@
/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"
permeability_coefficient = 0.01
no_slip = TRUE
armor = list(MELEE = 75, BULLET = 50, LASER = 20, ENERGY = 10, BOMB = 20, RAD = 15, FIRE = INFINITY, ACID = INFINITY)
cold_protection = FEET
min_cold_protection_temperature = SHOES_MIN_TEMP_PROTECT
heat_protection = FEET
max_heat_protection_temperature = SHOES_MAX_TEMP_PROTECT
-87
View File
@@ -1,87 +0,0 @@
/*
Contents:
- The Ninja Space Suit
- Ninja Space Suit Procs
*/
/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/melee/baton, /obj/item/tank/internals, /obj/item/stock_parts/cell)
slowdown = 0
flags_inv = HIDEJUMPSUIT|HIDETAIL
armor = list(MELEE = 75, BULLET = 50, LASER = 20, ENERGY = 10, BOMB = 20, RAD = 15, FIRE = INFINITY, ACID = INFINITY)
var/suitActive = 0
var/suitBusy = 0
var/obj/item/stock_parts/cell/suitCell
var/obj/item/clothing/head/helmet/space/space_ninja/suitHood
var/obj/item/clothing/gloves/space_ninja/suitGloves
var/obj/item/clothing/shoes/space_ninja/suitShoes
var/obj/item/clothing/mask/gas/space_ninja/suitMask
var/mob/living/carbon/human/suitOccupant
/obj/item/clothing/suit/space/space_ninja/get_cell()
return suitCell
/obj/item/clothing/suit/space/space_ninja/proc/toggle_suit_lock(mob/living/carbon/human/user)
if(!suitActive)
if(!istype(user.wear_suit, /obj/item/clothing/suit/space/space_ninja))
to_chat(user, "<span style='color: #ff0000;'><b>ERROR:</b> Unable to locate user.\nABORTING...</span>")
return 0
if(!istype(user.head, /obj/item/clothing/head/helmet/space/space_ninja))
to_chat(user, "<span style='color: #ff0000;'><b>ERROR:</b> Unable to locate hood.\nABORTING...</span>")
return 0
if(!istype(user.gloves, /obj/item/clothing/gloves/space_ninja))
to_chat(user, "<span style='color: #ff0000;'><b>ERROR:</b> Unable to locate gloves.\nABORTING...</span>")
return 0
if(!istype(user.shoes, /obj/item/clothing/shoes/space_ninja))
to_chat(user, "<span style='color: #ff0000;'><b>ERROR:</b> Unable to locate foot gear.\nABORTING...</span>")
return 0
if(!istype(user.wear_mask, /obj/item/clothing/mask/gas/space_ninja))
to_chat(user, "<span style='color: #ff0000;'><b>ERROR:</b> Unable to locate mask.\nABORTING...</span>")
return 0
suitHood = user.head
suitMask = user.wear_mask
suitGloves = user.gloves
suitShoes = user.shoes
suitOccupant = user
set_nodrop(TRUE)
suitHood.set_nodrop(TRUE)
suitMask.set_nodrop(TRUE)
suitGloves.set_nodrop(TRUE)
suitGloves.pickpocket = 1
suitShoes.set_nodrop(TRUE)
suitShoes.slowdown = -2
icon_state = (user.gender == MALE ? "s-ninjan" : "s-ninjanf")
suitGloves.icon_state = "s-ninjan"
return 1
else
set_nodrop(FALSE)
suitHood.set_nodrop(FALSE)
suitMask.set_nodrop(FALSE)
suitGloves.set_nodrop(FALSE)
suitGloves.pickpocket = 0
suitShoes.set_nodrop(FALSE)
suitShoes.slowdown = -1
icon_state = "s-ninja"
suitGloves.icon_state = "s-ninja"
suitHood = null
suitMask = null
suitGloves = null
suitShoes = null
suitOccupant = null
return 1
@@ -1,92 +0,0 @@
//Verbs link to procs because verb-like procs have a bug which prevents their use if the arguments are not readily referenced.
//^ Old coder words may be false these days, Not taking the risk for now.
/obj/item/clothing/suit/space/space_ninja/verb/toggle_suit()
set category = "Space Ninja - Equipment"
set name = "Toggle Suit"
if(usr.mind.special_role == "Ninja")
if(suitBusy)
to_chat(usr, "<span style='color: #ff0000;'><b>ERROR: </b>Suit systems busy, cannot initiate [suitActive ? "de-activation" : "activation"] protocols at this time.</span>")
return
suitBusy = 1
if(suitActive && (tgui_alert(usr, "Confirm suit systems shutdown? This cannot be halted once it has started.", "Confirm Shutdown", list("Yes", "No")) == "Yes"))
to_chat(usr, SPAN_DARKMBLUE("Now de-initializing..."))
sleep(15)
to_chat(usr, SPAN_DARKMBLUE("Logging off, [usr.real_name]. Shutting down <b>SpiderOS</b>."))
sleep(10)
to_chat(usr, SPAN_DARKMBLUE("Primary system status: <B>OFFLINE</B>.\nBackup system status: <b>OFFLINE</b>."))
sleep(5)
to_chat(usr, SPAN_DARKMBLUE("VOID-shift device status: <B>OFFLINE</B>.\nCLOAK-tech device status: <B>OFFLINE</B>."))
//TODO: Shut down any active abilities
sleep(10)
to_chat(usr, SPAN_DARKMBLUE("Disconnecting neural-net interface...</span> <span style='color: #32CD32'><b>Success</b>."))
QDEL_NULL(usr.hud_used)
usr.create_mob_hud()
usr.regenerate_icons()
sleep(5)
to_chat(usr, SPAN_DARKMBLUE("Disengaging neural-net interface...</span> <span style='color: #32CD32'><b>Success</b>."))
sleep(10)
to_chat(usr, SPAN_DARKMBLUE("Unsecuring external locking mechanism...\nNeural-net abolished.\nOperation status: <B>FINISHED</B>."))
//TODO: Grant verbs
toggle_suit_lock(usr)
usr.regenerate_icons()
suitBusy = 0
suitActive = 0
else if(!suitActive) // Activate the suit.
to_chat(usr, SPAN_DARKMBLUE("Now initializing..."))
sleep(15)
to_chat(usr, "<span class='darkmblue'>Now establishing neural-net interface...")
if(usr.mind.special_role != "Ninja")
to_chat(usr, "<span style='color: #ff0000;'><b>FĆAL RrR</b>: ŧer nt recgnized, c-cntr-r䣧-ç äcked.")
return
sleep(10)
to_chat(usr, SPAN_DARKMBLUE("Neural-net established. Now monitoring brainwave pattern. \nBrainwave pattern</span> <span style='color: #32CD32;'><b>GREEN</b></span><span class='darkmblue'>, proceeding."))
sleep(10)
to_chat(usr, SPAN_DARKMBLUE("Securing external locking mechanism..."))
if(!toggle_suit_lock(usr))
return
sleep(5)
to_chat(usr, SPAN_DARKMBLUE("Suit secured, extending neural-net interface..."))
QDEL_NULL(usr.hud_used)
usr.hud_used = new /datum/hud/human(usr, 'icons/mob/screen_ninja.dmi', "#ffffff", 255)
if(usr.hud_used)
usr.hud_used.show_hud(usr.hud_used.hud_version)
usr.regenerate_icons()
sleep(10)
to_chat(usr, SPAN_DARKMBLUE("VOID-shift device status: <b>ONLINE</b>.\nCLOAK-tech device status:<b>ONLINE</b>"))
sleep(5)
to_chat(usr, SPAN_DARKMBLUE("Primary system status: <b>ONLINE</b>.\nBackup system status: <b>ONLINE</b>."))
if(suitCell)
to_chat(usr, SPAN_DARKMBLUE("Current energy capacity: <b>[suitCell.charge]/[suitCell.maxcharge]</b>."))
sleep(10)
to_chat(usr, SPAN_DARKMBLUE("All systems operational. Welcome to <b>SpiderOS</b>, [usr.real_name]."))
//TODO: Grant ninja verbs here.
suitBusy = 0
suitActive = 1
else
suitBusy = 0
to_chat(usr, SPAN_DARKMBLUE("<b>NOTICE: </b>Suit de-activation protocols aborted."))
else
to_chat(usr, "<span style='color: #ff0000;'><b>FĆAL RrR</b>: ŧer nt recgnized, c-cntr-r䣧-ç äcked.")
return
@@ -105,6 +105,9 @@
else if(!rad_component)
start_rads()
/obj/item/nuclear_rod/proc/do_special_effect()
return
/obj/item/nuclear_rod/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change)
. = ..()
check_rad_shield()
@@ -164,6 +167,17 @@
craftable = TRUE
materials = list(MAT_METAL = 2000, MAT_URANIUM = 1000)
/obj/item/nuclear_rod/fuel/uranium_238/spiders
name = "spider-clan uranium 238 fuel rod"
desc = "A small fuel rod for most NGCR reactors. This one was green webs coating its surface, with tiny spiders skittering along them."
w_class = WEIGHT_CLASS_NORMAL
craftable = FALSE
adjacent_requirements = list()
/obj/item/nuclear_rod/fuel/uranium_238/spiders/do_special_effect()
if(prob(5))
new /mob/living/basic/spiderling(get_turf(src))
/obj/item/nuclear_rod/fuel/weak_thorium
name = "weak thorium fuel rod"
desc = "A specialized fuel rod refined from uranium 238. This rod will last longer than normal, and won't generate as much heat."
@@ -605,6 +605,7 @@
final_heat += heat_total
final_power += power_total
chamber.held_rod.durability -= durability_loss
chamber.held_rod.do_special_effect()
if(final_heat)
average_heatgen = final_heat / active_chambers
@@ -245,6 +245,9 @@
/// How long has it been since we processed the crystal?
var/tick_counter = 0
/// Are we being stolen?
var/being_stolen = FALSE
/obj/machinery/atmospherics/supermatter_crystal/Initialize(mapload)
. = ..()
@@ -697,12 +700,31 @@
countdown()
return 1
/obj/machinery/atmospherics/supermatter_crystal/update_overlays()
. = ..()
overlays.Cut()
if(being_stolen)
. += "causality_field"
color = COLOR_GREEN
else
color = COLOR_WHITE
/obj/machinery/atmospherics/supermatter_crystal/bullet_act(obj/projectile/proj)
var/turf/L = loc
if(!istype(L))
return FALSE
if(!istype(proj, /obj/projectile/beam/emitter/hitscan) && power_changes)
investigate_log("has been hit by [proj] fired by [key_name(proj.firer)]", INVESTIGATE_SUPERMATTER)
if(istype(proj, /obj/projectile/energy/net))
var/mob/living/carbon/user = proj.firer
var/list/obj_list = user.mind.get_all_objectives()
for(var/datum/objective/ninja/ninja_obj in obj_list)
if(ninja_obj.completed)
continue
if(!istype(ninja_obj, /datum/objective/ninja/steal_supermatter))
continue
begin_theft()
return FALSE
if(proj.flag != BULLET)
if(power_changes) //This needs to be here I swear
power += proj.damage * bullet_energy
@@ -712,6 +734,32 @@
damage += proj.damage * bullet_energy
return FALSE
/obj/machinery/atmospherics/supermatter_crystal/proc/begin_theft(mob/living/carbon/thief)
if(being_stolen)
return
message_admins("Ninja [thief] is beginning to steal the Supermatter Crystal.")
addtimer(src, CALLBACK(PROC_REF(complete_theft), thief), 3 MINUTES)
being_stolen = TRUE
update_icon()
/obj/machinery/atmospherics/supermatter_crystal/proc/complete_theft(mob/living/carbon/thief)
if(!being_stolen)
return
if(!thief.mind)
return
var/list/obj_list = thief.mind.get_all_objectives()
if(!length(obj_list))
return
for(var/datum/objective/ninja/ninja_obj in obj_list)
if(ninja_obj.completed)
continue
if(!istype(ninja_obj, /datum/objective/ninja/steal_supermatter))
continue
ninja_obj.complete_objective()
break
message_admins("Ninja [thief] has stolen the Supermatter Crystal.")
qdel(src)
/obj/machinery/atmospherics/supermatter_crystal/singularity_act()
var/gain = 100
investigate_log("Supermatter shard consumed by singularity.", INVESTIGATE_SINGULO)
@@ -796,6 +844,15 @@
/obj/machinery/atmospherics/supermatter_crystal/item_interaction(mob/living/user, obj/item/used, list/modifiers)
if(!istype(used) || (used.flags & ABSTRACT) || !istype(user))
return ITEM_INTERACT_COMPLETE
if(being_stolen)
to_chat(user, SPAN_WARNING("You begin to very carefully unfasten the net tangled around [src]!"))
if(!do_after_once(user, 5 SECONDS, TRUE, src))
return ITEM_INTERACT_COMPLETE
being_stolen = FALSE
update_icon()
return ITEM_INTERACT_COMPLETE
if(moveable && default_unfasten_wrench(user, used, time = 20))
return ITEM_INTERACT_COMPLETE