From 85886f563f24a3de129375813e6ba3e9f81f9b6e Mon Sep 17 00:00:00 2001 From: zerothebigboy Date: Mon, 8 Feb 2021 16:59:54 -0500 Subject: [PATCH] f --- .../dynamic/dynamic_rulesets_midround.dm | 1 - code/game/machinery/_machinery.dm | 11 + code/modules/admin/verbs/one_click_antag.dm | 4 +- code/modules/antagonists/ninja/ninja.dm | 146 -------- .../antagonists/space_ninja/space_ninja.dm | 128 +++++++ code/modules/events/space_ninja.dm | 51 +++ code/modules/mob/living/carbon/human/human.dm | 28 -- code/modules/ninja/__ninjaDefines.dm | 29 +- code/modules/ninja/energy_katana.dm | 53 ++- code/modules/ninja/ninja_event.dm | 93 ----- code/modules/ninja/ninja_explosive.dm | 37 ++ code/modules/ninja/outfit.dm | 4 +- code/modules/ninja/suit/gloves.dm | 73 ++-- code/modules/ninja/suit/head.dm | 15 +- code/modules/ninja/suit/mask.dm | 20 +- .../suit/n_suit_verbs/energy_net_nets.dm | 117 ------ .../suit/n_suit_verbs/ninja_adrenaline.dm | 19 - .../suit/n_suit_verbs/ninja_cost_check.dm | 25 -- .../ninja/suit/n_suit_verbs/ninja_empulse.dm | 10 - .../ninja/suit/n_suit_verbs/ninja_net.dm | 44 --- .../ninja/suit/n_suit_verbs/ninja_smoke.dm | 14 - .../ninja/suit/n_suit_verbs/ninja_stars.dm | 18 - .../ninja/suit/n_suit_verbs/ninja_stealth.dm | 54 --- .../suit/n_suit_verbs/ninja_sword_recall.dm | 39 -- code/modules/ninja/suit/ninjaDrainAct.dm | 346 +++++++++--------- .../energy_net_nets.dm | 45 +++ .../ninja_adrenaline.dm | 45 +++ .../ninja_cost_check.dm | 28 ++ .../ninja_equipment_actions/ninja_empulse.dm | 21 ++ .../ninja_glove_toggle.dm | 15 + .../suit/ninja_equipment_actions/ninja_net.dm | 36 ++ .../ninja_equipment_actions/ninja_stars.dm | 43 +++ .../ninja_status_read.dm | 39 ++ .../ninja_equipment_actions/ninja_stealth.dm | 46 +++ .../ninja_suit_initialisation.dm | 125 +++++++ .../ninja_sword_recall.dm | 47 +++ code/modules/ninja/suit/shoes.dm | 12 +- code/modules/ninja/suit/suit.dm | 267 ++++++++------ code/modules/ninja/suit/suit_attackby.dm | 44 +-- .../modules/ninja/suit/suit_initialisation.dm | 95 ----- code/modules/ninja/suit/suit_process.dm | 17 - tgstation.dme | 27 +- 42 files changed, 1199 insertions(+), 1132 deletions(-) delete mode 100644 code/modules/antagonists/ninja/ninja.dm create mode 100644 code/modules/antagonists/space_ninja/space_ninja.dm create mode 100644 code/modules/events/space_ninja.dm delete mode 100644 code/modules/ninja/ninja_event.dm create mode 100644 code/modules/ninja/ninja_explosive.dm delete mode 100644 code/modules/ninja/suit/n_suit_verbs/energy_net_nets.dm delete mode 100644 code/modules/ninja/suit/n_suit_verbs/ninja_adrenaline.dm delete mode 100644 code/modules/ninja/suit/n_suit_verbs/ninja_cost_check.dm delete mode 100644 code/modules/ninja/suit/n_suit_verbs/ninja_empulse.dm delete mode 100644 code/modules/ninja/suit/n_suit_verbs/ninja_net.dm delete mode 100644 code/modules/ninja/suit/n_suit_verbs/ninja_smoke.dm delete mode 100644 code/modules/ninja/suit/n_suit_verbs/ninja_stars.dm delete mode 100644 code/modules/ninja/suit/n_suit_verbs/ninja_stealth.dm delete mode 100644 code/modules/ninja/suit/n_suit_verbs/ninja_sword_recall.dm create mode 100644 code/modules/ninja/suit/ninja_equipment_actions/energy_net_nets.dm create mode 100644 code/modules/ninja/suit/ninja_equipment_actions/ninja_adrenaline.dm create mode 100644 code/modules/ninja/suit/ninja_equipment_actions/ninja_cost_check.dm create mode 100644 code/modules/ninja/suit/ninja_equipment_actions/ninja_empulse.dm create mode 100644 code/modules/ninja/suit/ninja_equipment_actions/ninja_glove_toggle.dm create mode 100644 code/modules/ninja/suit/ninja_equipment_actions/ninja_net.dm create mode 100644 code/modules/ninja/suit/ninja_equipment_actions/ninja_stars.dm create mode 100644 code/modules/ninja/suit/ninja_equipment_actions/ninja_status_read.dm create mode 100644 code/modules/ninja/suit/ninja_equipment_actions/ninja_stealth.dm create mode 100644 code/modules/ninja/suit/ninja_equipment_actions/ninja_suit_initialisation.dm create mode 100644 code/modules/ninja/suit/ninja_equipment_actions/ninja_sword_recall.dm delete mode 100644 code/modules/ninja/suit/suit_initialisation.dm delete mode 100644 code/modules/ninja/suit/suit_process.dm diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index 7ce6e74cc1..61732b30eb 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -669,7 +669,6 @@ var/mob/living/carbon/human/Ninja = create_space_ninja(spawn_loc) Mind.transfer_to(Ninja) var/datum/antagonist/ninja/ninjadatum = new - ninjadatum.helping_station = pick(TRUE,FALSE) Mind.add_antag_datum(ninjadatum) if(Ninja.mind != Mind) //something has gone wrong! diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 8d7a8c047a..5b5964f0f6 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -553,3 +553,14 @@ Class Procs: /obj/machinery/rust_heretic_act() take_damage(500, BRUTE, "melee", 1) + +/** + * Alerts the AI that a hack is in progress. + * + * Sends all AIs a message that a hack is occurring. Specifically used for space ninja tampering as this proc was originally in the ninja files. + * However, the proc may also be used elsewhere. + */ +/obj/machinery/proc/AI_notify_hack() + var/alertstr = "Network Alert: Hacking attempt detected[get_area(src)?" in [get_area_name(src, TRUE)]":". Unable to pinpoint location"]." + for(var/mob/living/silicon/ai/AI in GLOB.player_list) + to_chat(AI, alertstr) diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm index 2379ee22bc..6c43d61cce 100644 --- a/code/modules/admin/verbs/one_click_antag.dm +++ b/code/modules/admin/verbs/one_click_antag.dm @@ -266,8 +266,8 @@ return TRUE /datum/admins/proc/makeSpaceNinja() - new /datum/round_event/ghost_role/ninja() - return 1 + new /datum/round_event/ghost_role/space_ninja() + return TRUE // DEATH SQUADS /datum/admins/proc/makeDeathsquad() diff --git a/code/modules/antagonists/ninja/ninja.dm b/code/modules/antagonists/ninja/ninja.dm deleted file mode 100644 index 414f7dd6b0..0000000000 --- a/code/modules/antagonists/ninja/ninja.dm +++ /dev/null @@ -1,146 +0,0 @@ -/datum/antagonist/ninja - name = "Ninja" - antagpanel_category = "Ninja" - job_rank = ROLE_NINJA - show_name_in_check_antagonists = TRUE - show_to_ghosts = TRUE - antag_moodlet = /datum/mood_event/focused - threat = 8 - var/helping_station = FALSE - var/give_objectives = TRUE - var/give_equipment = TRUE - -/datum/antagonist/ninja/threat() - return helping_station ? -(..()) : ..() - -/datum/antagonist/ninja/apply_innate_effects(mob/living/mob_override) - var/mob/living/M = mob_override || owner.current - update_ninja_icons_added(M) - -/datum/antagonist/ninja/remove_innate_effects(mob/living/mob_override) - var/mob/living/M = mob_override || owner.current - update_ninja_icons_removed(M) - -/datum/antagonist/ninja/proc/equip_space_ninja(mob/living/carbon/human/H = owner.current) - return H.equipOutfit(/datum/outfit/ninja) - -/datum/antagonist/ninja/proc/addMemories() - antag_memory += "I am an elite mercenary assassin of the mighty Spider Clan. A SPACE NINJA!
" - antag_memory += "Surprise is my weapon. Shadows are my armor. Without them, I am nothing. (//initialize your suit by clicking the initialize UI button, to use abilities like stealth)!
" - antag_memory += "Officially, [helping_station?"Nanotrasen":"The Syndicate"] are my employer.
" - -/datum/antagonist/ninja/proc/addObjectives(quantity = 6) - var/list/possible_targets = list() - for(var/datum/mind/M in SSticker.minds) - if(M.current && M.current.stat != DEAD) - if(ishuman(M.current)) - if(M.special_role) - possible_targets[M] = 0 //bad-guy - else if(M.assigned_role in GLOB.command_positions) - possible_targets[M] = 1 //good-guy - - var/list/possible_objectives = list(1,2,3,4) - - while(objectives.len < quantity) - switch(pick_n_take(possible_objectives)) - if(1) //research - var/datum/objective/download/O = new /datum/objective/download() - O.owner = owner - O.gen_amount_goal() - objectives += O - - if(2) //steal - var/datum/objective/steal/special/O = new /datum/objective/steal/special() - O.owner = owner - O.find_target() - objectives += O - - if(3) //protect/kill - if(!possible_targets.len) continue - var/index = rand(1,possible_targets.len) - var/datum/mind/M = possible_targets[index] - var/is_bad_guy = possible_targets[M] - possible_targets.Cut(index,index+1) - - if(is_bad_guy ^ helping_station) //kill (good-ninja + bad-guy or bad-ninja + good-guy) - var/datum/objective/assassinate/once/O = new /datum/objective/assassinate() - O.owner = owner - O.target = M - O.explanation_text = "Slay \the [M.current.real_name], the [M.assigned_role]. You may let [M.p_they()] live, if they come back from death." - objectives += O - else //protect - var/datum/objective/protect/O = new /datum/objective/protect() - O.owner = owner - O.target = M - O.explanation_text = "Protect \the [M.current.real_name], the [M.assigned_role], from harm." - objectives += O - if(4) //flavor - var/datum/objective/flavor/O = helping_station ? new /datum/objective/flavor/ninja_helping : new /datum/objective/flavor/ninja_syndie - O.owner = owner - O.forge_objective() - objectives += O - else - break - var/datum/objective/O = new /datum/objective/survive() - O.owner = owner - objectives += O - -/proc/remove_ninja(mob/living/L) - if(!L || !L.mind) - return FALSE - var/datum/antagonist/datum = L.mind.has_antag_datum(/datum/antagonist/ninja) - datum.on_removal() - return TRUE - -/proc/is_ninja(mob/living/M) - return M && M.mind && M.mind.has_antag_datum(/datum/antagonist/ninja) - - -/datum/antagonist/ninja/greet() - SEND_SOUND(owner.current, sound('sound/effects/ninja_greeting.ogg')) - to_chat(owner.current, "I am an elite mercenary assassin of the mighty Spider Clan. A SPACE NINJA!") - to_chat(owner.current, "Surprise is my weapon. Shadows are my armor. Without them, I am nothing. (//initialize your suit by right clicking on it, to use abilities like stealth)!") - to_chat(owner.current, "Officially, [helping_station?"Nanotrasen":"The Syndicate"] are my employer.") - owner.announce_objectives() - return - -/datum/antagonist/ninja/on_gain() - if(give_objectives) - addObjectives() - addMemories() - if(give_equipment) - equip_space_ninja(owner.current) - . = ..() - -/datum/antagonist/ninja/admin_add(datum/mind/new_owner,mob/admin) - var/adj - switch(input("What kind of ninja?", "Ninja") as null|anything in list("Random","Syndicate","Nanotrasen","No objectives")) - if("Random") - helping_station = pick(TRUE,FALSE) - adj = "" - if("Syndicate") - helping_station = FALSE - adj = "syndie" - if("Nanotrasen") - helping_station = TRUE - adj = "friendly" - if("No objectives") - give_objectives = FALSE - adj = "objectiveless" - else - return - new_owner.assigned_role = ROLE_NINJA - new_owner.special_role = ROLE_NINJA - new_owner.add_antag_datum(src) - message_admins("[key_name_admin(admin)] has [adj] ninja'ed [new_owner.current].") - log_admin("[key_name(admin)] has [adj] ninja'ed [new_owner.current].") - -/datum/antagonist/ninja/proc/update_ninja_icons_added(var/mob/living/carbon/human/ninja) - var/datum/atom_hud/antag/ninjahud = GLOB.huds[ANTAG_HUD_NINJA] - ninjahud.join_hud(ninja) - set_antag_hud(ninja, "ninja") - -/datum/antagonist/ninja/proc/update_ninja_icons_removed(var/mob/living/carbon/human/ninja) - var/datum/atom_hud/antag/ninjahud = GLOB.huds[ANTAG_HUD_NINJA] - ninjahud.leave_hud(ninja) - set_antag_hud(ninja, null) diff --git a/code/modules/antagonists/space_ninja/space_ninja.dm b/code/modules/antagonists/space_ninja/space_ninja.dm new file mode 100644 index 0000000000..e6fa612de9 --- /dev/null +++ b/code/modules/antagonists/space_ninja/space_ninja.dm @@ -0,0 +1,128 @@ +/datum/antagonist/ninja + name = "Space Ninja" + antagpanel_category = "Space Ninja" + job_rank = ROLE_NINJA + antag_hud_type = ANTAG_HUD_NINJA + antag_hud_name = "space_ninja" + show_name_in_check_antagonists = TRUE + show_to_ghosts = TRUE + antag_moodlet = /datum/mood_event/focused + ///Whether or not this ninja will obtain objectives + var/give_objectives = TRUE + ///Whether or not this ninja receives the standard equipment + var/give_equipment = TRUE + +/datum/antagonist/ninja/apply_innate_effects(mob/living/mob_override) + var/mob/living/ninja = mob_override || owner.current + add_antag_hud(antag_hud_type, antag_hud_name, ninja) + +/datum/antagonist/ninja/remove_innate_effects(mob/living/mob_override) + var/mob/living/ninja = mob_override || owner.current + remove_antag_hud(antag_hud_type, ninja) + +/** + * Proc that equips the space ninja outfit on a given individual. By default this is the owner of the antagonist datum. + * + * Proc that equips the space ninja outfit on a given individual. By default this is the owner of the antagonist datum. + * Arguments: + * * ninja - The human to receive the gear + * * Returns a proc call on the given human which will equip them with all the gear. + */ +/datum/antagonist/ninja/proc/equip_space_ninja(mob/living/carbon/human/ninja = owner.current) + return ninja.equipOutfit(/datum/outfit/ninja) + +/** + * Proc that adds the proper memories to the antag datum + * + * Proc that adds the ninja starting memories to the owner of the antagonist datum. + */ +/datum/antagonist/ninja/proc/addMemories() + antag_memory += "I am an elite mercenary of the mighty Spider Clan. A SPACE NINJA!
" + antag_memory += "Surprise is my weapon. Shadows are my armor. Without them, I am nothing. (//initialize your suit by clicking the initialize UI button, to use abilities like stealth)!
" + +/datum/objective/cyborg_hijack + explanation_text = "Use your gloves to convert at least one cyborg to aide you in sabotaging the station." + +/datum/objective/door_jack + ///How many doors that need to be opened using the gloves to pass the objective + var/doors_required = 0 + +/datum/objective/plant_explosive + var/area/detonation_location + +/datum/objective/security_scramble + explanation_text = "Use your gloves on a security console to set everyone to arrest at least once. Note that the AI will be alerted once you begin!" + +/datum/objective/terror_message + explanation_text = "Use your gloves on a communication console in order to bring another threat to the station. Note that the AI will be alerted once you begin!" + +/** + * Proc that adds all the ninja's objectives to the antag datum. + * + * Proc that adds all the ninja's objectives to the antag datum. Called when the datum is gained. + */ +/datum/antagonist/ninja/proc/addObjectives() + //Cyborg Hijack: Flag set to complete in the DrainAct in ninjaDrainAct.dm + var/datum/objective/hijack = new /datum/objective/cyborg_hijack() + objectives += hijack + + //Research stealing + var/datum/objective/download/research = new /datum/objective/download() + research.owner = owner + research.gen_amount_goal() + objectives += research + + //Door jacks, flag will be set to complete on when the last door is hijacked + var/datum/objective/door_jack/doorobjective = new /datum/objective/door_jack() + doorobjective.doors_required = rand(15,40) + doorobjective.explanation_text = "Use your gloves to doorjack [doorobjective.doors_required] airlocks on the station." + objectives += doorobjective + + //Explosive plant, the bomb will register its completion on priming + var/datum/objective/plant_explosive/bombobjective = new /datum/objective/plant_explosive() + for(var/sanity in 1 to 100) // 100 checks at most. + var/area/selected_area = pick(GLOB.sortedAreas) + if(!is_station_level(selected_area.z) || !(selected_area.area_flags & VALID_TERRITORY)) + continue + bombobjective.detonation_location = selected_area + break + if(bombobjective.detonation_location) + bombobjective.explanation_text = "Detonate your starter bomb in [bombobjective.detonation_location]. Note that the bomb will not work anywhere else!" + objectives += bombobjective + + //Security Scramble, set to complete upon using your gloves on a security console + var/datum/objective/securityobjective = new /datum/objective/security_scramble() + objectives += securityobjective + + //Message of Terror, set to complete upon using your gloves a communication console + var/datum/objective/communicationobjective = new /datum/objective/terror_message() + objectives += communicationobjective + + //Survival until end + var/datum/objective/survival = new /datum/objective/survive() + survival.owner = owner + objectives += survival + +/datum/antagonist/ninja/greet() + SEND_SOUND(owner.current, sound('sound/effects/ninja_greeting.ogg')) + to_chat(owner.current, "I am an elite mercenary of the mighty Spider Clan. A SPACE NINJA!") + to_chat(owner.current, "Surprise is my weapon. Shadows are my armor. Without them, I am nothing. (//initialize your suit by right clicking on it, to use abilities like stealth)!") + owner.announce_objectives() + +/datum/antagonist/ninja/on_gain() + if(give_objectives) + addObjectives() + addMemories() + if(give_equipment) + equip_space_ninja(owner.current) + + owner.current.mind.assigned_role = ROLE_NINJA + owner.current.mind.special_role = ROLE_NINJA + return ..() + +/datum/antagonist/ninja/admin_add(datum/mind/new_owner,mob/admin) + new_owner.assigned_role = ROLE_NINJA + new_owner.special_role = ROLE_NINJA + new_owner.add_antag_datum(src) + message_admins("[key_name_admin(admin)] has ninja'ed [key_name_admin(new_owner)].") + log_admin("[key_name(admin)] has ninja'ed [key_name(new_owner)].") \ No newline at end of file diff --git a/code/modules/events/space_ninja.dm b/code/modules/events/space_ninja.dm new file mode 100644 index 0000000000..ca57326988 --- /dev/null +++ b/code/modules/events/space_ninja.dm @@ -0,0 +1,51 @@ +/datum/round_event_control/space_ninja + name = "Spawn Space Ninja" + typepath = /datum/round_event/ghost_role/space_ninja + max_occurrences = 1 + weight = 10 + earliest_start = 20 MINUTES + min_players = 20 + +/datum/round_event/ghost_role/space_ninja + minimum_required = 1 + role_name = "Space Ninja" + +/datum/round_event/ghost_role/space_ninja/spawn_role() + var/list/spawn_locs = list() + for(var/obj/effect/landmark/carpspawn/carp_spawn in GLOB.landmarks_list) + if(!isturf(carp_spawn.loc)) + stack_trace("Carp spawn found not on a turf: [carp_spawn.type] on [isnull(carp_spawn.loc) ? "null" : carp_spawn.loc.type]") + continue + spawn_locs += carp_spawn.loc + if(!spawn_locs.len) + message_admins("No valid spawn locations found, aborting...") + return MAP_ERROR + + //selecting a candidate player + var/list/candidates = get_candidates(ROLE_NINJA, null, ROLE_NINJA) + if(!candidates.len) + return NOT_ENOUGH_PLAYERS + + var/mob/dead/selected_candidate = pick(candidates) + var/key = selected_candidate.key + + //spawn the ninja and assign the candidate + var/mob/living/carbon/human/ninja = create_space_ninja(pick(spawn_locs)) + ninja.key = key + ninja.mind.add_antag_datum(/datum/antagonist/ninja) + spawned_mobs += ninja + message_admins("[ADMIN_LOOKUPFLW(ninja)] has been made into a space ninja by an event.") + log_game("[key_name(ninja)] was spawned as a ninja by an event.") + + return SUCCESSFUL_SPAWN + + +//=======//NINJA CREATION PROCS//=======// + +/proc/create_space_ninja(spawn_loc) + var/mob/living/carbon/human/new_ninja = new(spawn_loc) + var/datum/preferences/random_human_options = new()//Randomize appearance for the ninja. + random_human_options.real_name = "[pick(GLOB.ninja_titles)] [pick(GLOB.ninja_names)]" + random_human_options.copy_to(new_ninja) + new_ninja.dna.update_dna_identity() + return new_ninja \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index f653c96cbc..303afa2598 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -80,34 +80,6 @@ . += "" . += "Chemical Storage: [changeling.chem_charges]/[changeling.chem_storage]" . += "Absorbed DNA: [changeling.absorbedcount]" - //NINJACODE - if(istype(wear_suit, /obj/item/clothing/suit/space/space_ninja)) //Only display if actually a ninja. - var/obj/item/clothing/suit/space/space_ninja/SN = wear_suit - . += "SpiderOS Status: [SN.s_initialized ? "Initialized" : "Disabled"]" - . += "Current Time: [STATION_TIME_TIMESTAMP("hh:mm:ss", world.time)]" - if(SN.s_initialized) - //Suit gear - . += "Energy Charge: [round(SN.cell.charge/100)]%" - . += "Smoke Bombs: \Roman [SN.s_bombs]" - //Ninja status - . += "Fingerprints: [md5(dna.uni_identity)]" - . += "Unique Identity: [dna.unique_enzymes]" - . += "Overall Status: [stat > 1 ? "dead" : "[health]% healthy"]" - . += "Nutrition Status: [nutrition]" - . += "Oxygen Loss: [getOxyLoss()]" - . += "Toxin Levels: [getToxLoss()]" - . += "Burn Severity: [getFireLoss()]" - . += "Brute Trauma: [getBruteLoss()]" - . += "Radiation Levels: [radiation] rad" - . += "Body Temperature: [bodytemperature-T0C] degrees C ([bodytemperature*1.8-459.67] degrees F)" - - //Diseases - if(length(diseases)) - . += "Viruses:" - for(var/thing in diseases) - var/datum/disease/D = thing - . += "* [D.name], Type: [D.spread_text], Stage: [D.stage]/[D.max_stages], Possible Cure: [D.cure_text]" - /mob/living/carbon/human/show_inv(mob/user) user.set_machine(src) diff --git a/code/modules/ninja/__ninjaDefines.dm b/code/modules/ninja/__ninjaDefines.dm index d6cdb55840..3f5db48407 100644 --- a/code/modules/ninja/__ninjaDefines.dm +++ b/code/modules/ninja/__ninjaDefines.dm @@ -1,23 +1,24 @@ - -/* - -Contents: -- Definitions, because the original Ninja code has so much magic. - -*/ - - //ninjacost() specificCheck defines #define N_STEALTH_CANCEL 1 -#define N_SMOKE_BOMB 2 -#define N_ADRENALINE 3 +#define N_ADRENALINE 2 //ninjaDrainAct() defines for non numerical returns -//While not strictly needed, it's nicer than them just returning "twat" -//Which was my original intention. #define INVALID_DRAIN "INVALID" //This one is if the drain proc needs to cancel, eg missing variables, etc, it's important. - #define DRAIN_RD_HACK_FAILED "RDHACKFAIL" #define DRAIN_MOB_SHOCK "MOBSHOCK" #define DRAIN_MOB_SHOCK_FAILED "MOBSHOCKFAIL" + + +//Tells whether or not someone is a space ninja +#define IS_SPACE_NINJA(ninja) (ninja.mind && ninja.mind.has_antag_datum(/datum/antagonist/ninja)) + +//Defines for the suit's unique abilities +#define IS_NINJA_SUIT_INITIALIZATION(action) (istype(action, /datum/action/item_action/initialize_ninja_suit)) +#define IS_NINJA_SUIT_STATUS(action) (istype(action, /datum/action/item_action/ninjastatus)) +#define IS_NINJA_SUIT_BOOST(action) (istype(action, /datum/action/item_action/ninjaboost)) +#define IS_NINJA_SUIT_EMP(action) (istype(action, /datum/action/item_action/ninjapulse)) +#define IS_NINJA_SUIT_STAR_CREATION(action) (istype(action, /datum/action/item_action/ninjastar)) +#define IS_NINJA_SUIT_NET_CREATION(action) (istype(action, /datum/action/item_action/ninjanet)) +#define IS_NINJA_SUIT_SWORD_RECALL(action) (istype(action, /datum/action/item_action/ninja_sword_recall)) +#define IS_NINJA_SUIT_STEALTH(action) (istype(action, /datum/action/item_action/ninja_stealth)) diff --git a/code/modules/ninja/energy_katana.dm b/code/modules/ninja/energy_katana.dm index 00cfa94893..e9ef4703a3 100644 --- a/code/modules/ninja/energy_katana.dm +++ b/code/modules/ninja/energy_katana.dm @@ -1,3 +1,14 @@ +/** + * # Energy Katana + * + * The space ninja's katana. + * + * The katana that only space ninja spawns with. Comes with 30 force and throwforce, along with a signature special jaunting system. + * Upon clicking on a tile with the dash on, the user will teleport to that tile, assuming their target was not dense. + * The katana has 3 dashes stored at maximum, and upon using the dash, it will return 20 seconds after it was used. + * It also has a special feature where if it is tossed at a space ninja who owns it (determined by the ninja suit), the ninja will catch the katana instead of being hit by it. + * + */ /obj/item/energy_katana name = "energy katana" desc = "A katana infused with strong energy." @@ -5,8 +16,8 @@ item_state = "energy_katana" lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' - force = 40 - throwforce = 20 + force = 30 + throwforce = 30 block_chance = 50 armour_penetration = 50 w_class = WEIGHT_CLASS_NORMAL @@ -34,13 +45,8 @@ /obj/item/energy_katana/afterattack(atom/target, mob/user, proximity_flag, click_parameters) . = ..() - if(dash_toggled) + if(dash_toggled && !Adjacent(target) && !target.density) jaunt.Teleport(user, target) - if(proximity_flag && (isobj(target) || issilicon(target))) - spark_system.start() - playsound(user, "sparks", 50, 1) - playsound(user, 'sound/weapons/blade1.ogg', 50, 1) - target.emag_act(user) /obj/item/energy_katana/pickup(mob/living/user) . = ..() @@ -58,16 +64,30 @@ //To throw it at the ninja /obj/item/energy_katana/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) if(ishuman(hit_atom)) - var/mob/living/carbon/human/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 == src) - returnToOwner(H, 0, 1) + var/mob/living/carbon/human/hit_human = hit_atom + if(istype(hit_human.wear_suit, /obj/item/clothing/suit/space/space_ninja)) + var/obj/item/clothing/suit/space/space_ninja/ninja_suit = hit_human.wear_suit + if(ninja_suit.energyKatana == src) + returnToOwner(hit_human, 0, 1) return ..() -/obj/item/energy_katana/proc/returnToOwner(mob/living/carbon/human/user, doSpark = 1, caught = 0) +/obj/item/energy_katana/Destroy() + QDEL_NULL(spark_system) + QDEL_NULL(jaunt) + return ..() + +/** + * Proc called when the katana is recalled to its space ninja. + * + * Proc called when space ninja is hit with its suit's katana or the recall ability is used. + * Arguments: + * * user - To whom the katana is returning to. + * * doSpark - whether or not the katana will spark when it returns. + * * caught - boolean for whether or not the katana was caught or was teleported back. + */ +/obj/item/energy_katana/proc/returnToOwner(mob/living/carbon/human/user, doSpark = TRUE, caught = FALSE) if(!istype(user)) return forceMove(get_turf(user)) @@ -95,12 +115,9 @@ to_chat(user, "[msg]") -/obj/item/energy_katana/Destroy() - QDEL_NULL(spark_system) - return ..() /datum/action/innate/dash/ninja current_charges = 3 max_charges = 3 - charge_rate = 30 + charge_rate = 200 recharge_sound = null diff --git a/code/modules/ninja/ninja_event.dm b/code/modules/ninja/ninja_event.dm deleted file mode 100644 index bc3c445731..0000000000 --- a/code/modules/ninja/ninja_event.dm +++ /dev/null @@ -1,93 +0,0 @@ -//Note to future generations: I didn't write this god-awful code I just ported it to the event system and tried to make it less moon-speaky. -//Don't judge me D; ~Carn //Maximum judging occuring - Remie. -// Tut tut Remie, let's keep our comments constructive. - coiax - -/* - -Contents: -- The Ninja "Random" Event -- Ninja creation code -*/ - -/datum/round_event_control/ninja - name = "Space Ninja" - typepath = /datum/round_event/ghost_role/ninja - max_occurrences = 1 - earliest_start = 40 MINUTES - gamemode_blacklist = list("dynamic") - min_players = 15 - -/datum/round_event/ghost_role/ninja - var/success_spawn = 0 - role_name = "space ninja" - minimum_required = 1 - - var/helping_station - var/spawn_loc - var/give_objectives = TRUE - -/datum/round_event/ghost_role/ninja/setup() - helping_station = rand(0,1) - -/datum/round_event/ghost_role/ninja/kill() - if(!success_spawn && control) - control.occurrences-- - return ..() - -/datum/round_event/ghost_role/ninja/spawn_role() - //selecting a spawn_loc - if(!spawn_loc) - var/list/spawn_locs = list() - for(var/obj/effect/landmark/carpspawn/L in GLOB.landmarks_list) - if(isturf(L.loc)) - spawn_locs += L.loc - for(var/obj/effect/landmark/loneopspawn/L in GLOB.landmarks_list) - if(isturf(L.loc)) - spawn_locs += L.loc - if(!spawn_locs.len) - return kill() - spawn_loc = pick(spawn_locs) - if(!spawn_loc) - return MAP_ERROR - - //selecting a candidate player - var/list/candidates = get_candidates(ROLE_NINJA, null, ROLE_NINJA) - if(!candidates.len) - return NOT_ENOUGH_PLAYERS - - var/mob/dead/selected_candidate = pick_n_take(candidates) - var/key = selected_candidate.key - - //Prepare ninja player mind - var/datum/mind/Mind = new /datum/mind(key) - Mind.assigned_role = ROLE_NINJA - Mind.special_role = ROLE_NINJA - Mind.active = 1 - - //spawn the ninja and assign the candidate - var/mob/living/carbon/human/Ninja = create_space_ninja(spawn_loc) - Mind.transfer_to(Ninja) - var/datum/antagonist/ninja/ninjadatum = new - ninjadatum.helping_station = pick(TRUE,FALSE) - Mind.add_antag_datum(ninjadatum) - - if(Ninja.mind != Mind) //something has gone wrong! - stack_trace("Ninja created with incorrect mind") - - spawned_mobs += Ninja - message_admins("[ADMIN_LOOKUPFLW(Ninja)] has been made into a ninja by an event.") - log_game("[key_name(Ninja)] was spawned as a ninja by an event.") - success_spawn = TRUE - - return SUCCESSFUL_SPAWN - - -//=======//NINJA CREATION PROCS//=======// - -/proc/create_space_ninja(spawn_loc) - var/mob/living/carbon/human/new_ninja = new(spawn_loc) - var/datum/preferences/A = new()//Randomize appearance for the ninja. - A.real_name = "[pick(GLOB.ninja_titles)] [pick(GLOB.ninja_names)]" - A.copy_to(new_ninja) - new_ninja.dna.update_dna_identity() - return new_ninja diff --git a/code/modules/ninja/ninja_explosive.dm b/code/modules/ninja/ninja_explosive.dm new file mode 100644 index 0000000000..1590f35b18 --- /dev/null +++ b/code/modules/ninja/ninja_explosive.dm @@ -0,0 +1,37 @@ +/** + * # Spider Charge + * + * A unique version of c4 possessed only by the space ninja. Has a stronger blast radius. + * Can only be detonated by space ninjas with the bombing objective. Can only be set up where the objective says it can. + * When it primes, the space ninja responsible will have their objective set to complete. + * + */ +/obj/item/grenade/plastic/ninja + name = "spider charge" + desc = "A modified C-4 charge supplied to you by the Spider Clan. Its explosive power has been juiced up, but only works in one specific area." + boom_sizes = list(4, 8, 12) + var/mob/detonator = null + +/obj/item/grenade/c4/ninja/afterattack(atom/movable/AM, mob/user, flag) + var/datum/antagonist/ninja/ninja_antag = user.mind.has_antag_datum(/datum/antagonist/ninja) + if(!ninja_antag) + to_chat(user, "While it appears normal, you can't seem to detonate the charge.") + return + var/datum/objective/plant_explosive/objective = locate() in ninja_antag.objectives + if(!objective) + to_chat(user, "You can't seem to activate the charge. It's location-locked, but you don't know where to detonate it.") + return + if(objective.detonation_location != get_area(user)) + to_chat(user, "This isn't the location you're supposed to use this!") + return + detonator = user + return ..() + +/obj/item/grenade/c4/ninja/prime(mob/living/lanced_by) + . = ..() + //Since we already did the checks in afterattack, the denonator must be a ninja with the bomb objective. + if(!detonator) + return + var/datum/antagonist/ninja/ninja_antag = detonator.mind.has_antag_datum(/datum/antagonist/ninja) + var/datum/objective/plant_explosive/objective = locate() in ninja_antag.objectives + objective.completed = TRUE diff --git a/code/modules/ninja/outfit.dm b/code/modules/ninja/outfit.dm index 983ef0585a..2c10a8c10f 100644 --- a/code/modules/ninja/outfit.dm +++ b/code/modules/ninja/outfit.dm @@ -9,7 +9,7 @@ shoes = /obj/item/clothing/shoes/space_ninja gloves = /obj/item/clothing/gloves/space_ninja back = /obj/item/tank/jetpack/carbondioxide - l_pocket = /obj/item/grenade/plastic/x4 + l_pocket = /obj/item/grenade/plastic/ninja r_pocket = /obj/item/tank/internals/emergency_oxygen internals_slot = SLOT_R_STORE belt = /obj/item/energy_katana @@ -21,5 +21,3 @@ var/obj/item/clothing/suit/space/space_ninja/S = H.wear_suit if(istype(H.belt, belt)) S.energyKatana = H.belt - S.randomize_param() - diff --git a/code/modules/ninja/suit/gloves.dm b/code/modules/ninja/suit/gloves.dm index a06b753402..17cc5fc391 100644 --- a/code/modules/ninja/suit/gloves.dm +++ b/code/modules/ninja/suit/gloves.dm @@ -1,30 +1,18 @@ - - - -/* - Dear ninja gloves - - This isn't because I like you - this is because your father is a bastard - - ... - I guess you're a little cool. - -Sayu - - - see ninjaDrainAct.dm for ninjadrain_act() - Touch() simply calls this on it's target now - Ninja's electricuting people when? - -Remie - -*/ - - +/** + * # Ninja Gloves + * + * Space ninja's gloves. Gives access to a number of special interactions. + * + * Gloves only found from space ninjas. Allows the wearer to access special interactions with various objects. + * These interactions are detailed in ninjaDrainAct.dm in the suit file. + * These interactions are toggled by an action tied to the gloves. The interactions will not activate if the user is also not wearing a ninja suit. + * + */ /obj/item/clothing/gloves/space_ninja desc = "These nano-enhanced gloves insulate from electricity and provide fire resistance." name = "ninja gloves" - icon_state = "s-ninja" - item_state = "s-ninja" + icon_state = "black" + item_state = "s-ninjan" siemens_coefficient = 0 cold_protection = HANDS min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT @@ -32,11 +20,19 @@ max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT strip_delay = 120 resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF - var/draining = 0 - var/candrain = 0 + actions_types = list(/datum/action/item_action/toggle_glove) + ///Whether or not we're currently draining something + var/draining = FALSE + ///Whether or not we can currently drain something + var/candrain = FALSE + ///Minimum amount of power we can drain in a single drain action var/mindrain = 200 + ///Maximum amount of power we can drain in a single drain action var/maxdrain = 400 - + ///Whether or not the communication console hack was used to summon another antagonist + var/communication_console_hack_success = FALSE + ///How many times the gloves have been used to force open doors. + var/door_hack_counter = 0 var/stunforce = 100 /obj/item/clothing/gloves/space_ninja/Touch(atom/A,proximity) @@ -45,9 +41,9 @@ if(!ishuman(loc)) return FALSE //Only works while worn - var/mob/living/carbon/human/H = loc + var/mob/living/carbon/human/wearer = loc - var/obj/item/clothing/suit/space/space_ninja/suit = H.wear_suit + var/obj/item/clothing/suit/space/space_ninja/suit = wearer.wear_suit if(!istype(suit)) return FALSE if(isturf(A)) @@ -56,17 +52,17 @@ if(!proximity) return FALSE - A.add_fingerprint(H) + A.add_fingerprint(wearer) draining = TRUE - . = A.ninjadrain_act(suit,H,src) + . = A.ninjadrain_act(suit,wearer,src) draining = FALSE if(isnum(.)) //Numerical values of drained handle their feedback here, Alpha values handle it themselves (Research hacking) if(.) - to_chat(H, "Gained [DisplayEnergy(.)] of energy from [A].") + to_chat(wearer, "Gained [DisplayEnergy(.)] of energy from [A].") else - to_chat(H, "\The [A] has run dry of energy, you must find another source!") + to_chat(wearer, "\The [A] has run dry of energy, you must find another source!") . = INTERRUPT_UNARMED_ATTACK else . = FALSE //as to not cancel attack_hand() @@ -75,12 +71,13 @@ . = ..() REMOVE_TRAIT(src, TRAIT_NODROP, NINJA_SUIT_TRAIT) -/obj/item/clothing/gloves/space_ninja/proc/toggledrain() - var/mob/living/carbon/human/U = loc - to_chat(U, "You [candrain?"disable":"enable"] special interaction.") - candrain=!candrain - /obj/item/clothing/gloves/space_ninja/examine(mob/user) . = ..() if(HAS_TRAIT_FROM(src, TRAIT_NODROP, NINJA_SUIT_TRAIT)) . += "The energy drain mechanism is [candrain?"active":"inactive"]." + +/obj/item/clothing/gloves/space_ninja/ui_action_click(mob/user, action) + if(istype(action, /datum/action/item_action/toggle_glove)) + toggledrain() + return TRUE + return FALSE diff --git a/code/modules/ninja/suit/head.dm b/code/modules/ninja/suit/head.dm index 9a65dabc1e..6f9bc7ef4c 100644 --- a/code/modules/ninja/suit/head.dm +++ b/code/modules/ninja/suit/head.dm @@ -1,14 +1,19 @@ - - +/** + * # Ninja Hood + * + * Space ninja's hood. Provides armor and blocks AI tracking. + * + * A hood that only exists as a part of space ninja's starting kit. Provides armor equal of space ninja's suit and disallows an AI to track the wearer. + * + */ /obj/item/clothing/head/helmet/space/space_ninja desc = "What may appear to be a simple black garment is in fact a highly sophisticated nano-weave helmet. Standard issue ninja gear." name = "ninja hood" icon_state = "s-ninja" item_state = "s-ninja_mask" - armor = list("melee" = 60, "bullet" = 50, "laser" = 30,"energy" = 15, "bomb" = 30, "bio" = 30, "rad" = 25, "fire" = 100, "acid" = 100) - strip_delay = 12 + armor = list(MELEE = 40, BULLET = 30, LASER = 20,ENERGY = 15, BOMB = 30, BIO = 30, RAD = 25, FIRE = 100, ACID = 100) resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF - blockTracking = 1//Roughly the only unique thing about this helmet. + blockTracking = TRUE//Roughly the only unique thing about this helmet. flags_inv = HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR /obj/item/clothing/head/helmet/space/space_ninja/dropped(mob/user) diff --git a/code/modules/ninja/suit/mask.dm b/code/modules/ninja/suit/mask.dm index 421c13f9eb..111f76ae65 100644 --- a/code/modules/ninja/suit/mask.dm +++ b/code/modules/ninja/suit/mask.dm @@ -1,15 +1,11 @@ - -/* - -Contents: -- The Ninja Space Mask -- Ninja Space Mask speech modification - -*/ - - - - +/** + * # Ninja Mask + * + * Space ninja's mask. Makes you sound like a real anime girl. Barely able to be considered a real upside. + * + * A mask which only spawns as a part of space ninja's starting kit. Functions as a gas mask. + * + */ /obj/item/clothing/mask/gas/space_ninja name = "ninja mask" desc = "A close-fitting mask that acts both as an air filter and a post-modern fashion statement." diff --git a/code/modules/ninja/suit/n_suit_verbs/energy_net_nets.dm b/code/modules/ninja/suit/n_suit_verbs/energy_net_nets.dm deleted file mode 100644 index c0ee68cdee..0000000000 --- a/code/modules/ninja/suit/n_suit_verbs/energy_net_nets.dm +++ /dev/null @@ -1,117 +0,0 @@ -/* -It will teleport people to a holding facility after 30 seconds. (Check the process() proc to change where teleport goes) -It is possible to destroy the net by the occupant or someone else. -*/ - -/obj/structure/energy_net - name = "energy net" - desc = "It's a net made of green energy." - icon = 'icons/effects/effects.dmi' - icon_state = "energynet" - - density = TRUE//Can't pass through. - opacity = 0//Can see through. - mouse_opacity = MOUSE_OPACITY_ICON//So you can hit it with stuff. - anchored = TRUE//Can't drag/grab the net. - layer = ABOVE_ALL_MOB_LAYER - max_integrity = 50 //How much health it has. - can_buckle = 1 - buckle_lying = 0 - buckle_prevents_pull = TRUE - var/mob/living/carbon/affecting //Who it is currently affecting, if anyone. - var/mob/living/carbon/master //Who shot web. Will let this person know if the net was successful or failed. - var/check = 15//30 seconds before teleportation. Could be extended I guess. - var/success = FALSE - - -/obj/structure/energy_net/play_attack_sound(damage, damage_type = BRUTE, damage_flag = 0) - switch(damage_type) - if(BRUTE) - playsound(src, 'sound/weapons/slash.ogg', 80, 1) - if(BURN) - playsound(src, 'sound/weapons/slash.ogg', 80, 1) - -/obj/structure/energy_net/Destroy() - if(!success) - if(!QDELETED(affecting)) - affecting.visible_message("[affecting.name] was recovered from the energy net!", "You were recovered from the energy net!", "You hear a grunt.") - if(!QDELETED(master))//As long as they still exist. - to_chat(master, "ERROR: unable to initiate transport protocol. Procedure terminated.") - return ..() - -/obj/structure/energy_net/process() - if(QDELETED(affecting)||affecting.loc!=loc) - qdel(src)//Get rid of the net. - return - - if(check>0) - check-- - return - - success = TRUE - qdel(src) - if(ishuman(affecting)) - var/mob/living/carbon/human/H = affecting - for(var/obj/item/W in H) - if(W == H.w_uniform || W == H.shoes) - continue//So all they're left with are shoes and uniform. - H.dropItemToGround(W) - H.dna.species.give_important_for_life(H) // After we remove items, at least give them what they need to live. -/* - var/datum/antagonist/antag_datum - for(var/datum/antagonist/ninja/AD in GLOB.antagonists) //Because only ninjas get capture objectives; They're not doable without the suit. - if(AD.owner == master) - antag_datum = AD - break - for(var/datum/objective/capture/capture in antag_datum) - if(istype(affecting, /mob/living/carbon/human)) //Humans. - if(affecting.stat == DEAD)//Dead folks are worth less. - capture.captured_amount+=0.5 - continue - capture.captured_amount+=1 - if(istype(affecting, /mob/living/carbon/monkey)) //Monkeys are almost worthless, you failure. - capture.captured_amount+=0.1 - if(istype(affecting, /mob/living/carbon/alien/larva)) //Larva are important for research. - if(affecting.stat == DEAD) - capture.captured_amount+=0.5 - continue - capture.captured_amount+=1 - if(istype(affecting, /mob/living/carbon/alien/humanoid)) //Aliens are worth twice as much as humans. - if(istype(affecting, /mob/living/carbon/alien/humanoid/royal/queen)) //Queens are worth three times as much as humans. - if(affecting.stat == DEAD) - capture.captured_amount+=1.5 - else - capture.captured_amount+=3 - continue - if(affecting.stat == DEAD) - capture.captured_amount+=1 - continue - capture.captured_amount+=2 -*/ - - affecting.revive(1, 1) //Basically a revive and full heal, including limbs/organs - //In case people who have been captured dead want to hang out at the holding area - - playsound(affecting, 'sound/effects/sparks4.ogg', 50, 1) - new /obj/effect/temp_visual/dir_setting/ninja/phase/out(affecting.drop_location(), affecting.dir) - - visible_message("[affecting] suddenly vanishes!") - affecting.forceMove(pick(GLOB.holdingfacility)) //Throw mob in to the holding facility. - to_chat(affecting, "You appear in a strange place!") - - if(!QDELETED(master))//As long as they still exist. - to_chat(master, "SUCCESS: transport procedure of [affecting] complete.") - do_sparks(5, FALSE, affecting) - playsound(affecting, 'sound/effects/phasein.ogg', 25, 1) - playsound(affecting, 'sound/effects/sparks2.ogg', 50, 1) - new /obj/effect/temp_visual/dir_setting/ninja/phase(affecting.drop_location(), affecting.dir) - -/obj/structure/energy_net/attack_alien(mob/living/carbon/alien/humanoid/user) - if(attack_generic(user, 15, BRUTE, "melee", 0)) //Aliens normally deal 60 damage to structures. They'd one-shot nets without this. - playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1) - -/obj/structure/energy_net/user_buckle_mob(mob/living/M, mob/living/user) - return//We only want our target to be buckled - -/obj/structure/energy_net/user_unbuckle_mob(mob/living/buckled_mob, mob/living/user) - return//The net must be destroyed to free the target diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_adrenaline.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_adrenaline.dm deleted file mode 100644 index 89f5d20e70..0000000000 --- a/code/modules/ninja/suit/n_suit_verbs/ninja_adrenaline.dm +++ /dev/null @@ -1,19 +0,0 @@ -//Wakes the user so they are able to do their thing. Also injects a decent dose of radium. -//Movement impairing would indicate drugs and the like. -/obj/item/clothing/suit/space/space_ninja/proc/ninjaboost() - - if(!ninjacost(0,N_ADRENALINE)) - var/mob/living/carbon/human/H = affecting - H.do_adrenaline(150, TRUE, 0, 0, TRUE, list(/datum/reagent/medicine/inaprovaline = 3, /datum/reagent/medicine/synaptizine = 10, /datum/reagent/medicine/omnizine = 10), "You feel a sudden surge of energy!") - - H.say(pick("A CORNERED FOX IS MORE DANGEROUS THAN A JACKAL!","HURT ME MOOORRREEE!","IMPRESSIVE!"), forced = "ninjaboost") - - a_boost-- - to_chat(H, "There are [a_boost] adrenaline boosts remaining.") - s_coold = 3 - addtimer(CALLBACK(src, .proc/ninjaboost_after), 70) - -/obj/item/clothing/suit/space/space_ninja/proc/ninjaboost_after() - var/mob/living/carbon/human/H = affecting - H.reagents.add_reagent(/datum/reagent/radium, a_transfer) - to_chat(H, "You are beginning to feel the after-effect of the injection.") diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_cost_check.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_cost_check.dm deleted file mode 100644 index 12fea51815..0000000000 --- a/code/modules/ninja/suit/n_suit_verbs/ninja_cost_check.dm +++ /dev/null @@ -1,25 +0,0 @@ - - -//Cost function for suit Procs/Verbs/Abilities -/obj/item/clothing/suit/space/space_ninja/proc/ninjacost(cost = 0, specificCheck = 0) - var/mob/living/carbon/human/H = affecting - var/actualCost = cost*10 - if(cost && cell.charge < actualCost) - to_chat(H, "Not enough energy.") - return 1 - else - //This shit used to be handled individually on every proc.. why even bother with a universal check proc then? - cell.charge-=(actualCost) - - switch(specificCheck) - if(N_STEALTH_CANCEL) - cancel_stealth()//Get rid of it. - if(N_SMOKE_BOMB) - if(!s_bombs) - to_chat(H, "There are no more smoke bombs remaining.") - return 1 - if(N_ADRENALINE) - if(!a_boost) - to_chat(H, "You do not have any more adrenaline boosters.") - return 1 - return (s_coold)//Returns the value of the variable which counts down to zero. diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_empulse.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_empulse.dm deleted file mode 100644 index 29dc78e5f3..0000000000 --- a/code/modules/ninja/suit/n_suit_verbs/ninja_empulse.dm +++ /dev/null @@ -1,10 +0,0 @@ - - -//Disables nearby tech equipment. -/obj/item/clothing/suit/space/space_ninja/proc/ninjapulse() - - if(!ninjacost(250,N_STEALTH_CANCEL)) - var/mob/living/carbon/human/H = affecting - playsound(H.loc, 'sound/effects/empulse.ogg', 60, 2) - empulse_using_range(H, 9) //Procs sure are nice. Slightly weaker than wizard's disable tch. - s_coold = 2 diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_net.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_net.dm deleted file mode 100644 index 61355ca89b..0000000000 --- a/code/modules/ninja/suit/n_suit_verbs/ninja_net.dm +++ /dev/null @@ -1,44 +0,0 @@ - -//Allows the ninja to kidnap people -/obj/item/clothing/suit/space/space_ninja/proc/ninjanet() - var/mob/living/carbon/human/H = affecting - var/mob/living/carbon/C - - //If there's only one valid target, let's actually try to capture it, rather than forcing - //the user to fiddle with the dialog displaying a list of one - //Also, let's make this smarter and not list mobs you can't currently net. - var/list/candidates - for(var/mob/M in oview(H)) - if(!M.client)//Monkeys without a client can still step_to() and bypass the net. Also, netting inactive people is lame. - continue - for(var/obj/structure/energy_net/E in get_turf(M))//Check if they are already being affected by an energy net. - if(E.affecting == M) - continue - LAZYADD(candidates, M) - - if(!LAZYLEN(candidates)) - return FALSE - - if(candidates.len == 1) - C = candidates[1] - else - C = input("Select who to capture:","Capture who?",null) as null|mob in candidates - - - if(QDELETED(C)||!(C in oview(H))) - return FALSE - - if(!ninjacost(200,N_STEALTH_CANCEL)) - H.Beam(C,"n_beam",time=15) - H.say("Get over here!", forced = "ninja net") - var/obj/structure/energy_net/E = new /obj/structure/energy_net(C.drop_location()) - E.affecting = C - E.master = H - H.visible_message("[H] caught [C] with an energy net!","You caught [C] with an energy net!") - - if(C.buckled) - C.buckled.unbuckle_mob(affecting,TRUE) - E.buckle_mob(C, TRUE) //No moving for you! - //The person can still try and attack the net when inside. - - START_PROCESSING(SSobj, E) diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_smoke.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_smoke.dm deleted file mode 100644 index 3c19162048..0000000000 --- a/code/modules/ninja/suit/n_suit_verbs/ninja_smoke.dm +++ /dev/null @@ -1,14 +0,0 @@ - - -//Smoke bomb -/obj/item/clothing/suit/space/space_ninja/proc/ninjasmoke() - - if(!ninjacost(0,N_SMOKE_BOMB)) - var/mob/living/carbon/human/H = affecting - var/datum/effect_system/smoke_spread/bad/smoke = new - smoke.set_up(4, H.loc) - smoke.start() - playsound(H.loc, 'sound/effects/bamf.ogg', 50, 2) - s_bombs-- - to_chat(H, "There are [s_bombs] smoke bombs remaining.") - s_coold = 1 diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_stars.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_stars.dm deleted file mode 100644 index 57faad9493..0000000000 --- a/code/modules/ninja/suit/n_suit_verbs/ninja_stars.dm +++ /dev/null @@ -1,18 +0,0 @@ - - -//Creates a throwing star -/obj/item/clothing/suit/space/space_ninja/proc/ninjastar() - if(!ninjacost(10)) - var/mob/living/carbon/human/H = affecting - var/obj/item/throwing_star/ninja/N = new(H) - if(H.put_in_hands(N)) - to_chat(H, "A throwing star has been created in your hand!") - else - qdel(N) - H.throw_mode_on() //So they can quickly throw it. - - -/obj/item/throwing_star/ninja - name = "ninja throwing star" - throwforce = 20 - embedding = list("pain_mult" = 6, "embed_chance" = 100, "fall_chance" = 0, "embed_chance_turf_mod" = 15) diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_stealth.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_stealth.dm deleted file mode 100644 index 56c50078c1..0000000000 --- a/code/modules/ninja/suit/n_suit_verbs/ninja_stealth.dm +++ /dev/null @@ -1,54 +0,0 @@ - -/* - -Contents: -- Stealth Verbs - -*/ - - -/obj/item/clothing/suit/space/space_ninja/proc/toggle_stealth() - if(!affecting || stealth_cooldown > world.time) - return - if(stealth) - cancel_stealth() - else - if(cell.charge <= 0) - to_chat(affecting, "You don't have enough power to enable Stealth!") - return - stealth = TRUE - stealth_cooldown = world.time + 5 SECONDS - animate(affecting, alpha = 15, time = 3 SECONDS) - affecting.visible_message("[affecting.name] vanishes into thin air!", \ - "You are now mostly invisible to normal detection.") - addtimer(CALLBACK(src, .proc/enable_signals), 3 SECONDS) - -/obj/item/clothing/suit/space/space_ninja/proc/enable_signals() - if(!affecting) - return - RegisterSignal(affecting, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_MOB_ATTACK_RANGED, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_MOB_ATTACK_HAND, COMSIG_MOB_THROW, COMSIG_PARENT_ATTACKBY, COMSIG_MOVABLE_TELEPORTED, COMSIG_LIVING_GUN_PROCESS_FIRE), .proc/reduce_stealth) - RegisterSignal(affecting, COMSIG_MOVABLE_BUMP, .proc/bumping_stealth) - -/obj/item/clothing/suit/space/space_ninja/proc/reduce_stealth(datum/source) - affecting.alpha = min(affecting.alpha + 40, 100) - -/obj/item/clothing/suit/space/space_ninja/proc/bumping_stealth(datum/source, atom/A) - if(isliving(A)) - affecting.alpha = min(affecting.alpha + 20, 100) - -/obj/item/clothing/suit/space/space_ninja/proc/cancel_stealth() - if(!affecting || !stealth) - return FALSE - stealth = !stealth - stealth_cooldown = world.time + 5 SECONDS - UnregisterSignal(affecting, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_MOB_ATTACK_RANGED, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_MOB_ATTACK_HAND, COMSIG_MOB_THROW, COMSIG_PARENT_ATTACKBY, COMSIG_MOVABLE_BUMP, COMSIG_MOVABLE_TELEPORTED, COMSIG_LIVING_GUN_PROCESS_FIRE)) - animate(affecting, alpha = 255, time = 3 SECONDS) - affecting.visible_message("[affecting.name] appears from thin air!", \ - "You are now visible.") - return TRUE - -/obj/item/clothing/suit/space/space_ninja/proc/stealth() - if(!s_busy) - toggle_stealth() - else - to_chat(affecting, "Stealth does not appear to work!") diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_sword_recall.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_sword_recall.dm deleted file mode 100644 index 7a192c427c..0000000000 --- a/code/modules/ninja/suit/n_suit_verbs/ninja_sword_recall.dm +++ /dev/null @@ -1,39 +0,0 @@ - -/obj/item/clothing/suit/space/space_ninja/proc/ninja_sword_recall() - var/mob/living/carbon/human/H = affecting - - var/cost = 0 - var/inview = 1 - - if(!energyKatana) - to_chat(H, "Could not locate Energy Katana!") - return - - if(energyKatana in H) - return - - var/distance = get_dist(H,energyKatana) - - if(!(energyKatana in view(H))) - cost = distance //Actual cost is cost x 10, so 5 turfs is 50 cost. - inview = 0 - - if(!ninjacost(cost)) - if(iscarbon(energyKatana.loc)) - var/mob/living/carbon/C = energyKatana.loc - C.transferItemToLoc(energyKatana, get_turf(energyKatana), TRUE) - - //Somebody swollowed my sword, probably the clown doing a circus act. - if(energyKatana in C.stomach_contents) - C.stomach_contents -= energyKatana - else - energyKatana.forceMove(get_turf(energyKatana)) - - if(inview) //If we can see the katana, throw it towards ourselves, damaging people as we go. - energyKatana.spark_system.start() - playsound(H, "sparks", 50, 1) - H.visible_message("\the [energyKatana] flies towards [H]!","You hold out your hand and \the [energyKatana] flies towards you!") - energyKatana.throw_at(H, distance+1, energyKatana.throw_speed,H) - - else //Else just TP it to us. - energyKatana.returnToOwner(H,1) diff --git a/code/modules/ninja/suit/ninjaDrainAct.dm b/code/modules/ninja/suit/ninjaDrainAct.dm index 4462987cbf..5a8cfccf9b 100644 --- a/code/modules/ninja/suit/ninjaDrainAct.dm +++ b/code/modules/ninja/suit/ninjaDrainAct.dm @@ -1,278 +1,288 @@ - -/* - -Contents: -- Assorted ninjadrain_act() procs -- What is Object Oriented Programming - -They *could* go in their appropriate files, but this is supposed to be modular - -*/ - - -//Needs to return the amount drained from the atom, if no drain on a power object, return FALSE, otherwise, return a define. -/atom/proc/ninjadrain_act() +/** + * Atom level proc for space ninja's glove interactions. + * + * Proc which only occurs when space ninja uses his gloves on an atom. + * Does nothing by default, but effects will vary. + * Arguments: + * * ninja_suit - The offending space ninja's suit. + * * ninja - The human mob wearing the suit. + * * ninja_gloves - The offending space ninja's gloves. + */ +/atom/proc/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves) return INVALID_DRAIN - - - //APC// -/obj/machinery/power/apc/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/S, mob/living/carbon/human/H, obj/item/clothing/gloves/space_ninja/G) - if(!S || !H || !G) +/obj/machinery/power/apc/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves) + if(!ninja_suit || !ninja || !ninja_gloves) return INVALID_DRAIN - var/maxcapacity = 0 //Safety check for batteries + var/maxcapacity = FALSE //Safety check for batteries var/drain = 0 //Drain amount from batteries + var/drain_total = 0 - . = 0 - - if(cell && cell.charge) + if(cell?.charge) var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread() spark_system.set_up(5, 0, loc) - while(G.candrain && cell.charge> 0 && !maxcapacity) - drain = rand(G.mindrain, G.maxdrain) + while(ninja_gloves.candrain && cell.charge> 0 && !maxcapacity) + drain = rand(ninja_gloves.mindrain, ninja_gloves.maxdrain) if(cell.charge < drain) drain = cell.charge - if(S.cell.charge + drain > S.cell.maxcharge) - drain = S.cell.maxcharge - S.cell.charge - maxcapacity = 1//Reached maximum battery capacity. + if(ninja_suit.cell.charge + drain > ninja_suit.cell.maxcharge) + drain = ninja_suit.cell.maxcharge - ninja_suit.cell.charge + maxcapacity = TRUE//Reached maximum battery capacity. - if (do_after(H,10, target = src)) + if (do_after(ninja ,10, target = src)) spark_system.start() - playsound(loc, "sparks", 50, 1) - cell.charge -= drain - S.cell.charge += drain - . += drain + playsound(loc, "sparks", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + cell.use(drain) + ninja_suit.cell.give(drain) + drain_total += drain else break if(!(obj_flags & EMAGGED)) - flick("apc-spark", G) - playsound(loc, "sparks", 50, 1) + flick("apc-spark", ninja_gloves) + playsound(loc, "sparks", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) obj_flags |= EMAGGED locked = FALSE update_icon() - - - + return drain_total //SMES// -/obj/machinery/power/smes/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/S, mob/living/carbon/human/H, obj/item/clothing/gloves/space_ninja/G) - if(!S || !H || !G) +/obj/machinery/power/smes/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves) + if(!ninja_suit || !ninja || !ninja_gloves) return INVALID_DRAIN - var/maxcapacity = 0 //Safety check for batteries + var/maxcapacity = FALSE //Safety check for batteries var/drain = 0 //Drain amount from batteries - - . = 0 + var/drain_total = 0 if(charge) var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread() spark_system.set_up(5, 0, loc) - while(G.candrain && charge > 0 && !maxcapacity) - drain = rand(G.mindrain, G.maxdrain) + while(ninja_gloves.candrain && charge > 0 && !maxcapacity) + drain = rand(ninja_gloves.mindrain, ninja_gloves.maxdrain) if(charge < drain) drain = charge - if(S.cell.charge + drain > S.cell.maxcharge) - drain = S.cell.maxcharge - S.cell.charge - maxcapacity = 1 + if(ninja_suit.cell.charge + drain > ninja_suit.cell.maxcharge) + drain = ninja_suit.cell.maxcharge - ninja_suit.cell.charge + maxcapacity = TRUE - if (do_after(H,10, target = src)) + if (do_after(ninja,10, target = src)) spark_system.start() - playsound(loc, "sparks", 50, 1) + playsound(loc, "sparks", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) charge -= drain - S.cell.charge += drain - . += drain + ninja_suit.cell.give(drain) + drain_total += drain else break + return drain_total //CELL// -/obj/item/stock_parts/cell/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/S, mob/living/carbon/human/H, obj/item/clothing/gloves/space_ninja/G) - if(!S || !H || !G) +/obj/item/stock_parts/cell/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves) + if(!ninja_suit || !ninja || !ninja_gloves) return INVALID_DRAIN - . = 0 + var/drain_total = 0 if(charge) - if(G.candrain && do_after(H,30, target = src)) - . = charge - if(S.cell.charge + charge > S.cell.maxcharge) - S.cell.charge = S.cell.maxcharge + if(ninja_gloves.candrain && do_after(ninja, 30, target = src)) + drain_total = charge + if(ninja_suit.cell.charge + charge > ninja_suit.cell.maxcharge) + ninja_suit.cell.charge = ninja_suit.cell.maxcharge else - S.cell.charge += charge + ninja_suit.cell.give(charge) charge = 0 corrupt() update_icon() -/obj/machinery/proc/AI_notify_hack() - var/turf/location = get_turf(src) - var/alertstr = "Network Alert: Hacking attempt detected[location?" in [location]":". Unable to pinpoint location"]." - for(var/mob/living/silicon/ai/AI in GLOB.player_list) - to_chat(AI, alertstr) + return drain_total //RDCONSOLE// -/obj/machinery/computer/rdconsole/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/S, mob/living/carbon/human/H, obj/item/clothing/gloves/space_ninja/G) - if(!S || !H || !G) +/obj/machinery/computer/rdconsole/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves) + if(!ninja_suit || !ninja || !ninja_gloves) return INVALID_DRAIN . = DRAIN_RD_HACK_FAILED - to_chat(H, "Hacking \the [src]...") + to_chat(ninja, "Hacking \the [src]...") AI_notify_hack() if(stored_research) - to_chat(H, "Copying files...") - if(do_after(H, S.s_delay, target = src) && G.candrain && src) - stored_research.copy_research_to(S.stored_research) - to_chat(H, "Data analyzed. Process finished.") + to_chat(ninja, "Copying files...") + if(do_after(ninja, ninja_suit.s_delay, target = src) && ninja_gloves.candrain && src) + stored_research.copy_research_to(ninja_suit.stored_research) + to_chat(ninja, "Data analyzed. Process finished.") //RD SERVER// -//Shamelessly copypasted from above, since these two used to be the same proc, but with MANY colon operators -/obj/machinery/rnd/server/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/S, mob/living/carbon/human/H, obj/item/clothing/gloves/space_ninja/G) - if(!S || !H || !G) +/obj/machinery/rnd/server/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves) + if(!ninja_suit || !ninja || !ninja_gloves) return INVALID_DRAIN . = DRAIN_RD_HACK_FAILED - to_chat(H, "Hacking \the [src]...") + to_chat(ninja, "Hacking \the [src]...") AI_notify_hack() if(stored_research) - to_chat(H, "Copying files...") - if(do_after(H, S.s_delay, target = src) && G.candrain && src) - stored_research.copy_research_to(S.stored_research) - to_chat(H, "Data analyzed. Process finished.") + to_chat(ninja, "Copying files...") + if(do_after(ninja, ninja_suit.s_delay, target = src) && ninja_gloves.candrain && src) + stored_research.copy_research_to(ninja_suit.stored_research) + to_chat(ninja, "Data analyzed. Process finished.") +//SECURITY CONSOLE// +/obj/machinery/computer/secure_data/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves) + if(!ninja_suit || !ninja || !ninja_gloves) + return INVALID_DRAIN + AI_notify_hack() + if(do_after(ninja, 200)) + for(var/datum/data/record/rec in sortRecord(GLOB.data_core.general, sortBy, order)) + for(var/datum/data/record/security_record in GLOB.data_core.security) + security_record.fields["criminal"] = "*Arrest*" + var/datum/antagonist/ninja/ninja_antag = ninja.mind.has_antag_datum(/datum/antagonist/ninja) + if(!ninja_antag) + return + var/datum/objective/security_scramble/objective = locate() in ninja_antag.objectives + if(objective) + objective.completed = TRUE -//WIRE// -/obj/structure/cable/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/S, mob/living/carbon/human/H, obj/item/clothing/gloves/space_ninja/G) - if(!S || !H || !G) +//COMMUNICATIONS CONSOLE// +/obj/machinery/computer/communications/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves) + if(!ninja_suit || !ninja || !ninja_gloves) + return INVALID_DRAIN + if(ninja_gloves.communication_console_hack_success) + return + AI_notify_hack() + if(do_after(ninja, 300)) + var/announcement_pick = rand(0, 1) + switch(announcement_pick) + if(0) + priority_announce("Attention crew, it appears that someone on your station has made unexpected communication with an alien device in nearby space.", "[command_name()] High-Priority Update") + var/datum/round_event_control/spawn_swarmer/swarmer_event = new/datum/round_event_control/spawn_swarmer + swarmer_event.runEvent() + if(1) + priority_announce("Attention crew, it appears that someone on your station has made unexpected communication with a syndicate ship in nearby space.", "[command_name()] High-Priority Update") + var/datum/round_event_control/pirates/pirate_event = new/datum/round_event_control/pirates + pirate_event.runEvent() + ninja_gloves.communication_console_hack_success = TRUE + var/datum/antagonist/ninja/ninja_antag = ninja.mind.has_antag_datum(/datum/antagonist/ninja) + if(!ninja_antag) + return + var/datum/objective/terror_message/objective = locate() in ninja_antag.objectives + if(objective) + objective.completed = TRUE + +//AIRLOCK// +/obj/machinery/door/airlock/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves) + if(!ninja_suit || !ninja || !ninja_gloves) return INVALID_DRAIN - var/maxcapacity = 0 //Safety check + if(!operating && density && hasPower() && !(obj_flags & EMAGGED)) + emag_act() + ninja_gloves.door_hack_counter++ + var/datum/antagonist/ninja/ninja_antag = ninja.mind.has_antag_datum(/datum/antagonist/ninja) + if(!ninja_antag) + return + var/datum/objective/door_jack/objective = locate() in ninja_antag.objectives + if(objective && objective.doors_required <= ninja_gloves.door_hack_counter) + objective.completed = TRUE + +//WIRE// +/obj/structure/cable/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves) + if(!ninja_suit || !ninja || !ninja_gloves) + return INVALID_DRAIN + + var/maxcapacity = FALSE //Safety check var/drain = 0 //Drain amount - . = 0 + var/drain_total = 0 - var/datum/powernet/PN = powernet - while(G.candrain && !maxcapacity && src) - drain = (round((rand(G.mindrain, G.maxdrain))/2)) + var/datum/powernet/wire_powernet = powernet + while(ninja_gloves.candrain && !maxcapacity && src) + drain = (round((rand(ninja_gloves.mindrain, ninja_gloves.maxdrain))/2)) var/drained = 0 - if(PN && do_after(H,10, target = src)) + if(wire_powernet && do_after(ninja ,10, target = src)) drained = min(drain, delayed_surplus()) add_delayedload(drained) if(drained < drain)//if no power on net, drain apcs - for(var/obj/machinery/power/terminal/T in PN.nodes) - if(istype(T.master, /obj/machinery/power/apc)) - var/obj/machinery/power/apc/AP = T.master + for(var/obj/machinery/power/terminal/affected_terminal in wire_powernet.nodes) + if(istype(affected_terminal.master, /obj/machinery/power/apc)) + var/obj/machinery/power/apc/AP = affected_terminal.master if(AP.operating && AP.cell && AP.cell.charge > 0) AP.cell.charge = max(0, AP.cell.charge - 5) drained += 5 else break - S.cell.charge += drained - if(S.cell.charge > S.cell.maxcharge) - . += (drained-(S.cell.charge - S.cell.maxcharge)) - S.cell.charge = S.cell.maxcharge - maxcapacity = 1 + ninja_suit.cell.give(drain) + if(ninja_suit.cell.charge > ninja_suit.cell.maxcharge) + drain_total += (drained-(ninja_suit.cell.charge - ninja_suit.cell.maxcharge)) + ninja_suit.cell.charge = ninja_suit.cell.maxcharge + maxcapacity = TRUE else - . += drained - S.spark_system.start() + drain_total += drained + ninja_suit.spark_system.start() + + return drain_total //MECH// -/obj/mecha/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/S, mob/living/carbon/human/H, obj/item/clothing/gloves/space_ninja/G) - if(!S || !H || !G) +/obj/vehicle/sealed/mecha/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves) + if(!ninja_suit || !ninja || !ninja_gloves) return INVALID_DRAIN - var/maxcapacity = 0 //Safety check + var/maxcapacity = FALSE //Safety check var/drain = 0 //Drain amount - . = 0 + var/drain_total = 0 - occupant_message("Warning: Unauthorized access through sub-route 4, block H, detected.") + to_chat(occupants, "[icon2html(src, occupants)]Warning: Unauthorized access through sub-route 4, block H, detected.") if(get_charge()) - while(G.candrain && cell.charge > 0 && !maxcapacity) - drain = rand(G.mindrain,G.maxdrain) + while(ninja_gloves.candrain && cell.charge > 0 && !maxcapacity) + drain = rand(ninja_gloves.mindrain, ninja_gloves.maxdrain) if(cell.charge < drain) drain = cell.charge - if(S.cell.charge + drain > S.cell.maxcharge) - drain = S.cell.maxcharge - S.cell.charge - maxcapacity = 1 - if (do_after(H,10, target = src)) + if(ninja_suit.cell.charge + drain > ninja_suit.cell.maxcharge) + drain = ninja_suit.cell.maxcharge - ninja_suit.cell.charge + maxcapacity = TRUE + if (do_after(ninja, 10, target = src)) spark_system.start() - playsound(loc, "sparks", 50, 1) + playsound(loc, "sparks", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) cell.use(drain) - S.cell.charge += drain - . += drain + ninja_suit.cell.give(drain) + drain_total += drain else break + return drain_total + //BORG// -/mob/living/silicon/robot/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/S, mob/living/carbon/human/H, obj/item/clothing/gloves/space_ninja/G) - if(!S || !H || !G) +/mob/living/silicon/robot/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves) + if(!ninja_suit || !ninja || !ninja_gloves || (ROLE_NINJA in faction)) return INVALID_DRAIN - var/maxcapacity = 0 //Safety check - var/drain = 0 //Drain amount - . = 0 + to_chat(src, "Warni-***BZZZZZZZZZRT*** UPLOADING SPYDERPATCHER VERSION 9.5.2...") + if (do_after(ninja, 60, target = src)) + spark_system.start() + playsound(loc, "sparks", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + to_chat(src, "UPLOAD COMPLETE. NEW CYBORG MODEL DETECTED. INSTALLING...") + faction = list(ROLE_NINJA) + bubble_icon = "syndibot" + UnlinkSelf() + ionpulse = TRUE + laws = new /datum/ai_laws/ninja_override() + model.transform_to(pick(/obj/item/robot_model/syndicate, /obj/item/robot_model/syndicate_medical, /obj/item/robot_model/saboteur)) - to_chat(src, "Warning: Unauthorized access through sub-route 12, block C, detected.") - - if(cell && cell.charge) - while(G.candrain && cell.charge > 0 && !maxcapacity) - drain = rand(G.mindrain,G.maxdrain) - if(cell.charge < drain) - drain = cell.charge - if(S.cell.charge+drain > S.cell.maxcharge) - drain = S.cell.maxcharge - S.cell.charge - maxcapacity = 1 - if (do_after(H,10)) - spark_system.start() - playsound(loc, "sparks", 50, 1) - cell.charge -= drain - S.cell.charge += drain - . += drain - else - break - - -//CARBON MOBS// -/mob/living/carbon/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/S, mob/living/carbon/human/H, obj/item/clothing/gloves/space_ninja/G) - if(!S || !H || !G) - return INVALID_DRAIN - - . = DRAIN_MOB_SHOCK_FAILED - - //Default cell = 10,000 charge, 10,000/1000 = 10 uses without charging/upgrading - if(S.cell && S.cell.charge && S.cell.use(500)) - . = DRAIN_MOB_SHOCK - //Got that electric touch - var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread() - spark_system.set_up(5, 0, loc) - playsound(src, "sparks", 50, 1) - visible_message("[H] electrocutes [src] with [H.p_their()] touch!", "[H] electrocutes you with [H.p_their()] touch!") - electrocute_act(15, H, flags = SHOCK_NOSTUN) - - DefaultCombatKnockdown(G.stunforce, override_hardstun = 0) - apply_effect(EFFECT_STUTTER, G.stunforce) - SEND_SIGNAL(src, COMSIG_LIVING_MINOR_SHOCK) - - lastattacker = H.real_name - lastattackerckey = H.ckey - log_combat(H, src, "stunned") - - playsound(loc, 'sound/weapons/egloves.ogg', 50, 1, -1) - - if(ishuman(src)) - var/mob/living/carbon/human/Hsrc = src - Hsrc.forcesay(GLOB.hit_appends) + var/datum/antagonist/ninja/ninja_antag = ninja.mind.has_antag_datum(/datum/antagonist/ninja) + if(!ninja_antag) + return + var/datum/objective/cyborg_hijack/objective = locate() in ninja_antag.objectives + if(objective) + objective.completed = TRUE diff --git a/code/modules/ninja/suit/ninja_equipment_actions/energy_net_nets.dm b/code/modules/ninja/suit/ninja_equipment_actions/energy_net_nets.dm new file mode 100644 index 0000000000..3d4ce44350 --- /dev/null +++ b/code/modules/ninja/suit/ninja_equipment_actions/energy_net_nets.dm @@ -0,0 +1,45 @@ +/** + * # Energy Net + * + * Energy net which ensnares prey until it is destroyed. Used by space ninjas. + * + * Energy net which keeps its target from moving until it is destroyed. Used to send + * players to a holding area in which they could never leave, but such feature has since + * been removed. + */ +/obj/structure/energy_net + name = "energy net" + desc = "It's a net made of green energy." + icon = 'icons/effects/effects.dmi' + icon_state = "energynet" + + density = TRUE//Can't pass through. + opacity = FALSE //Can see through. + mouse_opacity = MOUSE_OPACITY_ICON//So you can hit it with stuff. + anchored = TRUE//Can't drag/grab the net. + layer = ABOVE_ALL_MOB_LAYER + max_integrity = 60 //How much health it has. + can_buckle = 1 + buckle_lying = 0 + buckle_prevents_pull = TRUE + ///The creature currently caught in the net + var/mob/living/affecting + +/obj/structure/energy_net/play_attack_sound(damage, damage_type = BRUTE, damage_flag = 0) + if(damage_type == BRUTE || damage_type == BURN) + playsound(src, 'sound/weapons/slash.ogg', 80, TRUE) + +/obj/structure/energy_net/Destroy() + if(!QDELETED(affecting)) + affecting.visible_message("[affecting.name] is recovered from the energy net!", "You are recovered from the energy net!", "You hear a grunt.") + affecting = null + return ..() + +/obj/structure/energy_net/attack_paw(mob/user) + return attack_hand() + +/obj/structure/energy_net/user_buckle_mob(mob/living/M, mob/user, check_loc = TRUE) + return//We only want our target to be buckled + +/obj/structure/energy_net/user_unbuckle_mob(mob/living/buckled_mob, mob/living/user) + return//The net must be destroyed to free the target diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_adrenaline.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_adrenaline.dm new file mode 100644 index 0000000000..d5d1a52678 --- /dev/null +++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_adrenaline.dm @@ -0,0 +1,45 @@ +//Wakes the user so they are able to do their thing. Also injects a decent dose of radium. +//Movement impairing would indicate drugs and the like. + +/datum/action/item_action/ninjaboost + check_flags = NONE + name = "Adrenaline Boost" + desc = "Inject a secret chemical that will counteract all movement-impairing effect." + button_icon_state = "repulse" + icon_icon = 'icons/mob/actions/actions_spells.dmi' + +/** + * Proc called to activate space ninja's adrenaline. + * + * Proc called to use space ninja's adrenaline. Gets the ninja out of almost any stun. + * Also makes them shout MGS references when used. After a bit, it injects the user with + * radium by calling a different proc. + */ +/obj/item/clothing/suit/space/space_ninja/proc/ninjaboost() + if(ninjacost(0,N_ADRENALINE)) + return + var/mob/living/carbon/human/ninja = affecting + ninja.SetUnconscious(0) + ninja.SetStun(0) + ninja.SetKnockdown(0) + ninja.SetImmobilized(0) + ninja.SetParalyzed(0) + ninja.adjustStaminaLoss(-200) + ninja.stuttering = 0 + ninja.reagents.add_reagent(/datum/reagent/medicine/stimulants, 5) + ninja.say(pick("A CORNERED FOX IS MORE DANGEROUS THAN A JACKAL!","HURT ME MOOORRREEE!","IMPRESSIVE!"), forced = "ninjaboost") + a_boost = FALSE + to_chat(ninja, "You have used the adrenaline boost.") + s_coold = 6 + addtimer(CALLBACK(src, .proc/ninjaboost_after), 70) + +/** + * Proc called to inject the ninja with radium. + * + * Used after 7 seconds of using the ninja's adrenaline. + * Injects the user with how much radium the suit needs to refill an adrenaline boost. + */ +/obj/item/clothing/suit/space/space_ninja/proc/ninjaboost_after() + var/mob/living/carbon/human/ninja = affecting + ninja.reagents.add_reagent(/datum/reagent/uranium/radium, a_transfer * 0.25) + to_chat(ninja, "You are beginning to feel the after-effect of the injection.") diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_cost_check.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_cost_check.dm new file mode 100644 index 0000000000..7fb9d9dbf6 --- /dev/null +++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_cost_check.dm @@ -0,0 +1,28 @@ +/** + * Proc called to check if the ninja can afford an ability's cost. + * + * Proc which determine whether or not a space ninja can afford to use a specific ability. + * It can also cancel stealth if the ability requested it. + * Arguments: + * * cost - the energy cost of the ability + * * specificCheck - Determines if the check is a normal one, an adrenaline one, or a stealth cancel check. + * * Returns TRUE or the current cooldown timer if we can't perform the ability, and FALSE if we can. + */ +/obj/item/clothing/suit/space/space_ninja/proc/ninjacost(cost = 0, specificCheck = 0) + var/mob/living/carbon/human/ninja = affecting + var/actualCost = cost*10 + if(cost && cell.charge < actualCost) + to_chat(ninja, "Not enough energy!") + return TRUE + else + //This shit used to be handled individually on every proc.. why even bother with a universal check proc then? + cell.charge-=(actualCost) + + switch(specificCheck) + if(N_STEALTH_CANCEL) + cancel_stealth()//Get rid of it. + if(N_ADRENALINE) + if(!a_boost) + to_chat(ninja, "You do not have any more adrenaline boosters!") + return TRUE + return (s_coold)//Returns the value of the variable which counts down to zero. diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_empulse.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_empulse.dm new file mode 100644 index 0000000000..ea2341a132 --- /dev/null +++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_empulse.dm @@ -0,0 +1,21 @@ +//Disables nearby tech equipment. + +/datum/action/item_action/ninjapulse + name = "EM Burst (50E)" + desc = "Disable any nearby technology with an electro-magnetic pulse." + button_icon_state = "emp" + icon_icon = 'icons/mob/actions/actions_spells.dmi' + +/** + * Proc called to allow the ninja to EMP the nearby area. + * + * Proc called to allow the ninja to EMP the nearby area. By default, costs 500E, which is half of the default battery's max charge. + * Also affects the ninja as well. + */ +/obj/item/clothing/suit/space/space_ninja/proc/ninjapulse() + if(ninjacost(500,N_STEALTH_CANCEL)) + return + var/mob/living/carbon/human/H = affecting + playsound(H.loc, 'sound/effects/empulse.ogg', 60, 2) + empulse(H, 4, 6) //Procs sure are nice. Slightly weaker than wizard's disable tch. + s_coold = 4 diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_glove_toggle.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_glove_toggle.dm new file mode 100644 index 0000000000..ec5bf078a5 --- /dev/null +++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_glove_toggle.dm @@ -0,0 +1,15 @@ +/datum/action/item_action/toggle_glove + name = "Toggle interaction" + desc = "Switch between normal interaction and drain mode." + button_icon_state = "s-ninjan" + icon_icon = 'icons/obj/clothing/gloves.dmi' + +/** + * Proc called to toggle the ninja glove's special abilities. + * + * Used to toggle whether or not the ninja glove's abilities will activate on touch. + */ +/obj/item/clothing/gloves/space_ninja/proc/toggledrain() + var/mob/living/carbon/human/ninja = loc + to_chat(ninja, "You [candrain?"disable":"enable"] special interaction.") + candrain=!candrain diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_net.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_net.dm new file mode 100644 index 0000000000..ab52f3e018 --- /dev/null +++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_net.dm @@ -0,0 +1,36 @@ +/datum/action/item_action/ninjanet + name = "Energy Net (40E)" + desc = "Captures a fallen opponent in a net of energy." + button_icon_state = "energynet" + icon_icon = 'icons/effects/effects.dmi' + +/** + * Proc called to ensnare a person in a energy net. + * + * Used to ensnare a target in an energy net, preventing them from moving until the net is broken. + * Costs 40E, which is 40% of the default battery's max charge. Intended as a means of reliably locking down an opponent when ninja stars won't suffice. + */ +/obj/item/clothing/suit/space/space_ninja/proc/ninjanet() + var/mob/living/carbon/human/ninja = affecting + var/mob/living/net_target = input("Select who to capture:","Capture who?",null) as null|mob in sortNames(oview(ninja)) + + if(QDELETED(net_target)||!(net_target in oview(ninja))) + return + + if(locate(/obj/structure/energy_net) in get_turf(net_target))//Check if they are already being affected by an energy net. + to_chat(ninja, "[net_target.p_they(TRUE)] are already trapped inside an energy net!") + return + for(var/turf/between_turf in getline(get_turf(ninja), get_turf(net_target))) + if(between_turf.density)//Don't want them shooting nets through walls. It's kind of cheesy. + to_chat(ninja, "You may not use an energy net through solid obstacles!") + return + if(!ninjacost(400,N_STEALTH_CANCEL)) + ninja.Beam(net_target, "n_beam", time = 15) + ninja.say("Get over here!", forced = "ninja net") + var/obj/structure/energy_net/net = new /obj/structure/energy_net(net_target.drop_location()) + net.affecting = net_target + ninja.visible_message("[ninja] caught [net_target] with an energy net!","You caught [net_target] with an energy net!") + + if(net_target.buckled) + net_target.buckled.unbuckle_mob(affecting,TRUE) + net.buckle_mob(net_target, TRUE) //No moving for you! diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_stars.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_stars.dm new file mode 100644 index 0000000000..38c5c25447 --- /dev/null +++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_stars.dm @@ -0,0 +1,43 @@ +/datum/action/item_action/ninjastar + name = "Create Throwing Stars (1E)" + desc = "Creates a throwing star in your hand, if possible." + button_icon_state = "throwingstar" + icon_icon = 'icons/obj/items_and_weapons.dmi' + +/** + * Proc called to create a ninja star in the ninja's hands. + * + * Called to create a ninja star in the wearer's hand. The ninja + * star doesn't do much up-front damage, but deals stamina damage + * as the target moves around, forcing a finish or flee scenario. + */ +/obj/item/clothing/suit/space/space_ninja/proc/ninjastar() + if(ninjacost(10)) + return + var/mob/living/carbon/human/ninja = affecting + var/obj/item/throwing_star/stamina/ninja/ninja_star = new(ninja) + if(ninja.put_in_hands(ninja_star)) + to_chat(ninja, "A throwing star has been created in your hand!") + else + qdel(ninja_star) + to_chat(ninja, "You can't create a throwing star, your hands are full!") + ninja.throw_mode_on() //So they can quickly throw it. + +/** + * # Ninja Throwing Star + * + * a throwing star which specifically makes sure you know it came from a real ninja. + * + * The most important item in the entire codebase, as without it we would all cease to exist. + * Inherits everything that makes it interesting the stamina throwing star, but the most + * important change made is that its name specifically has the prefix, 'ninja' in it. + * This provides the detective role with information to play off of by ensuring that his + * assumption that a space ninja is aboard the ship to be true when he find 20 of these in + * the captain's back. Along with this, its throwforce is 10 instead of the 5 of the stamina + * throwing star, meaning it'll do a little more damage than the stamina throwing star does as well. + * Changes to this item need to be approved by all maintainers, so if you do change it, make sure + * you go through the proper channels, lest you get permabanned. Do I make myself clear? + */ +/obj/item/throwing_star/stamina/ninja + name = "ninja throwing star" + throwforce = 10 diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_status_read.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_status_read.dm new file mode 100644 index 0000000000..7ab3bedaaf --- /dev/null +++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_status_read.dm @@ -0,0 +1,39 @@ +/datum/action/item_action/ninjastatus + check_flags = NONE + name = "Status Readout" + desc = "Gives a detailed readout about your current status." + button_icon_state = "health" + icon_icon = 'icons/obj/device.dmi' + +/** + * Proc called to put a status readout to the ninja in chat. + * + * Called put some information about the ninja's current status into chat. + * This information used to be displayed constantly on the status tab screen + * when the suit was on, but was turned into this as to remove the code from + * human.dm + */ +/obj/item/clothing/suit/space/space_ninja/proc/ninjastatus() + var/mob/living/carbon/human/ninja = affecting + var/list/info_list = list() + info_list += "SpiderOS Status: [s_initialized ? "Initialized" : "Disabled"]\n" + info_list += "Current Time: [station_time_timestamp()]\n" + //Ninja status + info_list += "Fingerprints: [md5(ninja.dna.uni_identity)]\n" + info_list += "Unique Identity: [ninja.dna.unique_enzymes]\n" + info_list += "Overall Status: [ninja.stat > 1 ? "dead" : "[ninja.health]% healthy"]\n" + info_list += "Nutrition Status: [ninja.nutrition]\n" + info_list += "Oxygen Loss: [ninja.getOxyLoss()]\n" + info_list += "Toxin Levels: [ninja.getToxLoss()]\n" + info_list += "Burn Severity: [ninja.getFireLoss()]\n" + info_list += "Brute Trauma: [ninja.getBruteLoss()]\n" + info_list += "Radiation Levels: [ninja.radiation] rad\n" + info_list += "Body Temperature: [ninja.bodytemperature-T0C] degrees C ([ninja.bodytemperature*1.8-459.67] degrees F)\n" + + //Diseases + if(length(ninja.diseases)) + info_list += "Viruses:" + for(var/datum/disease/ninja_disease in ninja.diseases) + info_list += "* [ninja_disease.name], Type: [ninja_disease.spread_text], Stage: [ninja_disease.stage]/[ninja_disease.max_stages], Possible Cure: [ninja_disease.cure_text]\n" + + to_chat(ninja, "[info_list.Join()]") diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_stealth.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_stealth.dm new file mode 100644 index 0000000000..079f0c53e9 --- /dev/null +++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_stealth.dm @@ -0,0 +1,46 @@ +/datum/action/item_action/ninja_stealth + name = "Toggle Stealth" + desc = "Toggles stealth mode on and off." + button_icon_state = "ninja_cloak" + icon_icon = 'icons/mob/actions/actions_minor_antag.dmi' + +/** + * Proc called to toggle ninja stealth. + * + * Proc called to toggle whether or not the ninja is in stealth mode. + * If cancelling, calls a separate proc in case something else needs to quickly cancel stealth. + */ +/obj/item/clothing/suit/space/space_ninja/proc/toggle_stealth() + var/mob/living/carbon/human/ninja = affecting + if(!ninja) + return + if(stealth) + cancel_stealth() + else + if(cell.charge <= 0) + to_chat(ninja, "You don't have enough power to enable Stealth!") + return + stealth = !stealth + animate(ninja, alpha = 20,time = 12) + ninja.visible_message("[ninja.name] vanishes into thin air!", \ + "You are now mostly invisible to normal detection.") + +/** + * Proc called to cancel stealth. + * + * Called to cancel the stealth effect if it is ongoing. + * Does nothing otherwise. + * Arguments: + * * Returns false if either the ninja no longer exists or is already visible, returns true if we successfully made the ninja visible. + */ +/obj/item/clothing/suit/space/space_ninja/proc/cancel_stealth() + var/mob/living/carbon/human/ninja = affecting + if(!ninja) + return FALSE + if(stealth) + stealth = !stealth + animate(ninja, alpha = 255, time = 12) + ninja.visible_message("[ninja.name] appears from thin air!", \ + "You are now visible.") + return TRUE + return FALSE diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_suit_initialisation.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_suit_initialisation.dm new file mode 100644 index 0000000000..51167b0e0d --- /dev/null +++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_suit_initialisation.dm @@ -0,0 +1,125 @@ +#define NINJA_LOCK_PHASE 1 +#define NINJA_ICON_GENERATE_PHASE 3 +#define NINJA_COMPLETE_PHASE 6 +#define NINJA_DEINIT_LOGOFF_PHASE 1 +#define NINJA_DEINIT_STEALTH_PHASE 5 + +GLOBAL_LIST_INIT(ninja_initialize_messages, list( + "Now initializing...", + "Securing external locking mechanism...\nNeural-net established.", + "Extending neural-net interface...\nNow monitoring brain wave pattern...", + "Linking neural-net interface...\nPattern GREEN, continuing operation.", + "VOID-shift device status: ONLINE.\nCLOAK-tech device status: ONLINE.", + "Primary system status: ONLINE.\nBackup system status: ONLINE.\nCurrent energy capacity: ", + "All systems operational. Welcome to SpiderOS, " +)) + +GLOBAL_LIST_INIT(ninja_deinitialize_messages, list( + "Now de-initializing...", + "Shutting down SpiderOS.", + "Primary system status: OFFLINE.\nBackup system status: OFFLINE.", + "VOID-shift device status: OFFLINE.\nCLOAK-tech device status: OFFLINE.", + "Disconnecting neural-net interface...Success.", + "Disengaging neural-net interface... Success.", + "Unsecuring external locking mechanism...\nNeural-net abolished.\nOperation status: FINISHED." +)) + +/datum/action/item_action/initialize_ninja_suit + name = "Toggle Ninja Suit" + +/** + * Toggles the ninja suit on/off + * + * Attempts to initialize or deinitialize the ninja suit + */ +/obj/item/clothing/suit/space/space_ninja/proc/toggle_on_off() + . = TRUE + if(s_busy) + to_chat(loc, "ERROR: You cannot use this function at this time.") + return FALSE + s_busy = TRUE + if(s_initialized) + deinitialize() + else + ninitialize() + +/** + * Initializes the ninja suit + * + * Initializes the ninja suit through seven phases, each of which calls this proc with an incremented phase + * Arguments: + * * delay - The delay between each phase of initialization + * * ninja - The human who is being affected by the suit + * * phase - The phase of initialization + */ +/obj/item/clothing/suit/space/space_ninja/proc/ninitialize(delay = s_delay, mob/living/carbon/human/ninja = loc, phase = 0) + if(!ninja || !ninja.mind) + s_busy = FALSE + return + if (phase > NINJA_LOCK_PHASE && (ninja.stat == DEAD || ninja.health <= 0)) + to_chat(ninja, "FĆAL �Rr�R: 344--93#�&&21 BR��N |/|/aV� PATT$RN RED\nA-A-aB�rT�NG...") + unlock_suit(ninja) + s_busy = FALSE + return + + var/message = GLOB.ninja_initialize_messages[phase + 1] + switch(phase) + if (NINJA_LOCK_PHASE) + if(!lock_suit(ninja))//To lock the suit onto wearer. + s_busy = FALSE + return + if (NINJA_ICON_GENERATE_PHASE) + lockIcons(ninja)//Check for icons. + ninja.regenerate_icons() + if (NINJA_COMPLETE_PHASE - 1) + message += "[DisplayEnergy(cell.charge)]." + if (NINJA_COMPLETE_PHASE) + message += "[ninja.real_name]." + s_initialized = TRUE + s_busy = FALSE + + to_chat(ninja, "[message]") + playsound(ninja, 'sound/effects/sparks1.ogg', 10, TRUE) + + if (phase < NINJA_COMPLETE_PHASE) + addtimer(CALLBACK(src, .proc/ninitialize, delay, ninja, phase + 1), delay) + +/** + * Deinitializes the ninja suit + * + * Deinitializes the ninja suit through eight phases, each of which calls this proc with an incremented phase + * Arguments: + * * delay - The delay between each phase of deinitialization + * * ninja - The human who is being affected by the suit + * * phase - The phase of deinitialization + */ +/obj/item/clothing/suit/space/space_ninja/proc/deinitialize(delay = s_delay, mob/living/carbon/human/ninja = affecting == loc ? affecting : null, phase = 0) + if (!ninja || !ninja.mind) + s_busy = FALSE + return + if (phase == 0 && alert("Are you certain you wish to remove the suit? This will take time and remove all abilities.",,"Yes","No") == "No") + s_busy = FALSE + return + + var/message = GLOB.ninja_deinitialize_messages[phase + 1] + switch(phase) + if(NINJA_DEINIT_LOGOFF_PHASE) + message = "Logging off, [ninja.real_name]. " + message + if(NINJA_DEINIT_STEALTH_PHASE) + cancel_stealth() + to_chat(ninja, "[message]") + playsound(ninja, 'sound/items/deconstruct.ogg', 10, TRUE) + + if (phase < NINJA_COMPLETE_PHASE) + addtimer(CALLBACK(src, .proc/deinitialize, delay, ninja, phase + 1), delay) + else + unlock_suit(ninja) + ninja.regenerate_icons() + s_initialized = FALSE + s_busy = FALSE + +#undef NINJA_LOCK_PHASE +#undef NINJA_ICON_GENERATE_PHASE +#undef NINJA_COMPLETE_PHASE +#undef NINJA_DEINIT_LOGOFF_PHASE +#undef NINJA_DEINIT_STEALTH_PHASE diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_sword_recall.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_sword_recall.dm new file mode 100644 index 0000000000..22fdf86ccd --- /dev/null +++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_sword_recall.dm @@ -0,0 +1,47 @@ +/datum/action/item_action/ninja_sword_recall + name = "Recall Energy Katana (Variable Cost)" + desc = "Teleports the Energy Katana linked to this suit to its wearer, cost based on distance." + button_icon_state = "energy_katana" + icon_icon = 'icons/obj/items_and_weapons.dmi' + +/** + * Proc called to recall the ninja's sword. + * + * Called to summon the ninja's katana back to them + * If the katana can see the ninja, it will throw itself towards them. + * If not, the katana will teleport itself to the ninja. + */ +/obj/item/clothing/suit/space/space_ninja/proc/ninja_sword_recall() + var/mob/living/carbon/human/ninja = affecting + var/cost = 0 + var/inview = TRUE + + if(!energyKatana) + to_chat(ninja, "Could not locate Energy Katana!") + return + + if(energyKatana in ninja) + return + + var/distance = get_dist(ninja,energyKatana) + + if(!(energyKatana in view(ninja))) + cost = distance //Actual cost is cost x 10, so 5 turfs is 50 cost. + inview = FALSE + + if(!ninjacost(cost)) + if(iscarbon(energyKatana.loc)) + var/mob/living/carbon/sword_holder = energyKatana.loc + sword_holder.transferItemToLoc(energyKatana, get_turf(energyKatana), TRUE) + + else + energyKatana.forceMove(get_turf(energyKatana)) + + if(inview) //If we can see the katana, throw it towards ourselves, damaging people as we go. + energyKatana.spark_system.start() + playsound(ninja, "sparks", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + ninja.visible_message("\the [energyKatana] flies towards [ninja]!","You hold out your hand and \the [energyKatana] flies towards you!") + energyKatana.throw_at(ninja, distance+1, energyKatana.throw_speed, ninja) + + else //Else just TP it to us. + energyKatana.returnToOwner(ninja, 1) diff --git a/code/modules/ninja/suit/shoes.dm b/code/modules/ninja/suit/shoes.dm index f2227b5f9f..9fa094f092 100644 --- a/code/modules/ninja/suit/shoes.dm +++ b/code/modules/ninja/suit/shoes.dm @@ -1,3 +1,12 @@ +/** + * # Ninja Shoes + * + * Space ninja's shoes. Gives him armor on his feet. + * + * Space ninja's ninja shoes. How mousey. Gives him slip protection and protection against attacks. + * Also are temperature resistant. + * + */ /obj/item/clothing/shoes/space_ninja name = "ninja shoes" desc = "A pair of running shoes. Excellent for running and even better for smashing skulls." @@ -5,8 +14,7 @@ permeability_coefficient = 0.01 clothing_flags = NOSLIP resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF - armor = list("melee" = 60, "bullet" = 50, "laser" = 30,"energy" = 15, "bomb" = 30, "bio" = 30, "rad" = 30, "fire" = 100, "acid" = 100) - strip_delay = 120 + armor = list(MELEE = 40, BULLET = 30, LASER = 20,ENERGY = 15, BOMB = 30, BIO = 30, RAD = 30, FIRE = 100, ACID = 100) cold_protection = FEET min_cold_protection_temperature = SHOES_MIN_TEMP_PROTECT heat_protection = FEET diff --git a/code/modules/ninja/suit/suit.dm b/code/modules/ninja/suit/suit.dm index b46f30b4fb..a504b6c322 100644 --- a/code/modules/ninja/suit/suit.dm +++ b/code/modules/ninja/suit/suit.dm @@ -1,16 +1,13 @@ - -/* - -Contents: -- The Ninja Space Suit -- Ninja Space Suit Procs - -*/ - - -// /obj/item/clothing/suit/space/space_ninja - - +/** + * # Ninja Suit + * + * Space ninja's suit. Provides him with most of his powers. + * + * Space ninja's suit. Gives space ninja all his iconic powers, which are mostly kept in + * the folder ninja_equipment_actions. Has a lot of unique stuff going on, so make sure to check + * the variables. Check suit_attackby to see radium interaction, disk copying, and cell replacement. + * + */ /obj/item/clothing/suit/space/space_ninja name = "ninja suit" desc = "A unique, vacuum-proof suit of nano-enhanced armor designed specifically for Spider Clan assassins." @@ -19,12 +16,11 @@ Contents: allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/restraints/handcuffs, /obj/item/tank/internals, /obj/item/stock_parts/cell) slowdown = 1 resistance_flags = LAVA_PROOF | ACID_PROOF - armor = list("melee" = 60, "bullet" = 50, "laser" = 30,"energy" = 15, "bomb" = 30, "bio" = 30, "rad" = 30, "fire" = 100, "acid" = 100) - strip_delay = 12 + armor = list(MELEE = 40, BULLET = 30, LASER = 20,ENERGY = 30, BOMB = 30, BIO = 30, RAD = 30, FIRE = 100, ACID = 100) - actions_types = list(/datum/action/item_action/initialize_ninja_suit, /datum/action/item_action/ninjasmoke, /datum/action/item_action/ninjaboost, /datum/action/item_action/ninjapulse, /datum/action/item_action/ninjastar, /datum/action/item_action/ninja_sword_recall, /datum/action/item_action/ninja_stealth, /datum/action/item_action/toggle_glove) + actions_types = list(/datum/action/item_action/initialize_ninja_suit, /datum/action/item_action/ninjastatus, /datum/action/item_action/ninjaboost, /datum/action/item_action/ninjapulse, /datum/action/item_action/ninjastar, /datum/action/item_action/ninjanet, /datum/action/item_action/ninja_sword_recall, /datum/action/item_action/ninja_stealth) - //Important parts of the suit. + ///The person wearing the suit var/mob/living/carbon/human/affecting = null var/obj/item/stock_parts/cell/cell var/datum/effect_system/spark_spread/spark_system @@ -37,28 +33,36 @@ Contents: var/obj/item/clothing/shoes/space_ninja/n_shoes var/obj/item/clothing/gloves/space_ninja/n_gloves - //Main function variables. - var/s_initialized = 0//Suit starts off. - var/s_coold = 0//If the suit is on cooldown. Can be used to attach different cooldowns to abilities. Ticks down every second based on suit ntick(). - var/s_cost = 5//Base energy cost each ntick. - var/s_acost = 25//Additional cost for additional powers active. - var/s_delay = 40//How fast the suit does certain things, lower is faster. Can be overridden in specific procs. Also determines adverse probability. - var/a_transfer = 20//How much radium is used per adrenaline boost. - var/a_maxamount = 7//Maximum number of adrenaline boosts. - var/s_maxamount = 20//Maximum number of smoke bombs. + ///The space ninja's mask. + var/obj/item/clothing/mask/gas/space_ninja/n_mask - //Support function variables. + ///Whether or not the suit is currently booted up. Starts off. + var/s_initialized = FALSE//Suit starts off. + ///The suit's current cooldown. If not 0, blocks usage of most abilities, and decrements its value by 1 every process + var/s_coold = 0 + ///How much energy the suit expends in a single process + var/s_cost = 1 + ///Additional energy cost for cloaking per process + var/s_acost = 4 + ///How fast the suit is at certain actions, like draining power from things + var/s_delay = 40 + ///Units of radium required to refill the adrenaline boost + var/a_transfer = 20//How much radium is required to refill the adrenaline boost. + ///Whether or not the suit is currently in stealth mode. var/stealth = FALSE//Stealth off. - var/stealth_cooldown = 0 - var/s_busy = FALSE//Is the suit busy with a process? Like AI hacking. Used for safety functions. - - //Ability function variables. - var/s_bombs = 10//Number of smoke bombs. - var/a_boost = 3//Number of adrenaline boosters. - - -/obj/item/clothing/suit/space/space_ninja/get_cell() - return cell + ///Whether or not the wearer is in the middle of an action, like hacking. + var/s_busy = FALSE + ///Whether or not the adrenaline boost ability is available + var/a_boost = TRUE +/obj/item/clothing/suit/space/space_ninja/examine(mob/user) + . = ..() + if(!s_initialized) + return + if(!user == affecting) + return + . += "All systems operational. Current energy capacity: [DisplayEnergy(cell.charge)].\n"+\ + "The CLOAK-tech device is [stealth?"active":"inactive"].\n"+\ + "[a_boost?"An adrenaline boost is available to use.":"There is no adrenaline boost available. Try refilling the suit with 20 units of radium."]" /obj/item/clothing/suit/space/space_ninja/Initialize() . = ..() @@ -82,106 +86,147 @@ Contents: qdel(n_hood) qdel(n_gloves) qdel(n_shoes) - qdel(src) +/obj/item/clothing/suit/space/space_ninja/ui_action_click(mob/user, action) + if(IS_NINJA_SUIT_INITIALIZATION(action)) + toggle_on_off() + return TRUE + if(!s_initialized) + to_chat(user, "ERROR: suit offline. Please activate suit.") + return FALSE + if(s_coold != 0) + to_chat(user, "ERROR: suit is on cooldown.") + return FALSE + if(IS_NINJA_SUIT_STATUS(action)) + ninjastatus() + return TRUE + if(IS_NINJA_SUIT_BOOST(action)) + ninjaboost() + return TRUE + if(IS_NINJA_SUIT_EMP(action)) + ninjapulse() + return TRUE + if(IS_NINJA_SUIT_STAR_CREATION(action)) + ninjastar() + return TRUE + if(IS_NINJA_SUIT_NET_CREATION(action)) + ninjanet() + return TRUE + if(IS_NINJA_SUIT_SWORD_RECALL(action)) + ninja_sword_recall() + return TRUE + if(IS_NINJA_SUIT_STEALTH(action)) + toggle_stealth() + return TRUE + return FALSE + +/obj/item/clothing/suit/space/space_ninja/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) + . = ..() + if(stealth) + cancel_stealth() + s_coold = 5 + +/** + * Proc for changing the suit's appearance upon locking. + * + * Proc for when space ninja's suit locks. If the user selects Original, gives it glowing lights, along with having an alternate sprite for female body types. + * Yes, we do have nipLEDs, how could you tell? + * If the user selects New Age, it applies new sprites to all the gear. + * Arguments: + * * ninja - The person wearing the suit. + */ +/obj/item/clothing/suit/space/space_ninja/proc/lockIcons(mob/living/carbon/human/ninja) + var/design_choice = alert(ninja, "Please choose your desired suit design.",,"Original","New Age") + switch(design_choice) + if("Original") + icon_state = ninja.body_type == "female" ? "s-ninjanf" : "s-ninjan" + ninja.gloves.icon_state = "s-ninjan" + ninja.gloves.inhand_icon_state = "s-ninjan" + if("New Age") + icon_state ="ninja_new" + n_hood.icon_state = "ninja_newcowl" + n_gloves.icon_state = "ninja_new" + if(n_mask) + n_mask.icon_state = "ninja_new" -//Randomizes suit parameters. -/obj/item/clothing/suit/space/space_ninja/proc/randomize_param() - s_cost = rand(1,20) - s_acost = rand(20,100) - s_delay = rand(10,100) - s_bombs = rand(5,20) - a_boost = rand(1,7) - - -//This proc prevents the suit from being taken off. -/obj/item/clothing/suit/space/space_ninja/proc/lock_suit(mob/living/carbon/human/H) - if(!istype(H)) +/** + * Proc called to lock the important gear pieces onto space ninja's body. + * + * Called during the suit startup to lock all gear pieces onto space ninja. + * Terminates if a gear piece is not being worn. Also gives the ninja the inability to use firearms. + * If the person in the suit isn't a ninja when this is called, this proc just gibs them instead. + * Arguments: + * * ninja - The person wearing the suit. + * * Returns false if the locking fails due to lack of all suit parts, and true if it succeeds. + */ +/obj/item/clothing/suit/space/space_ninja/proc/lock_suit(mob/living/carbon/human/ninja) + if(!istype(ninja)) return FALSE - if(!is_ninja(H)) - to_chat(H, "fÄTaL ÈÈRRoR: 382200-*#00CÖDE RED\nUNAU†HORIZED USÈ DETÈC†††eD\nCoMMÈNCING SUB-R0U†IN3 13...\nTÈRMInATING U-U-USÈR...") - H.gib() + if(!IS_SPACE_NINJA(ninja)) + to_chat(ninja, "fÄTaL ÈÈRRoR: 382200-*#00CÖDE RED\nUNAU†HORIZED USÈ DETÈC†††eD\nCoMMÈNCING SUB-R0U†IN3 13...\nTÈRMInATING U-U-USÈR...") + ninja.gib() return FALSE - if(!istype(H.head, /obj/item/clothing/head/helmet/space/space_ninja)) - to_chat(H, "ERROR: 100113 UNABLE TO LOCATE HEAD GEAR\nABORTING...") + if(!istype(ninja.head, /obj/item/clothing/head/helmet/space/space_ninja)) + to_chat(ninja, "ERROR: 100113 UNABLE TO LOCATE HEAD GEAR\nABORTING...") return FALSE - if(!istype(H.shoes, /obj/item/clothing/shoes/space_ninja)) - to_chat(H, "ERROR: 122011 UNABLE TO LOCATE FOOT GEAR\nABORTING...") + if(!istype(ninja.shoes, /obj/item/clothing/shoes/space_ninja)) + to_chat(ninja, "ERROR: 122011 UNABLE TO LOCATE FOOT GEAR\nABORTING...") return FALSE - if(!istype(H.gloves, /obj/item/clothing/gloves/space_ninja)) - to_chat(H, "ERROR: 110223 UNABLE TO LOCATE HAND GEAR\nABORTING...") + if(!istype(ninja.gloves, /obj/item/clothing/gloves/space_ninja)) + to_chat(ninja, "ERROR: 110223 UNABLE TO LOCATE HAND GEAR\nABORTING...") return FALSE - affecting = H + affecting = ninja ADD_TRAIT(src, TRAIT_NODROP, NINJA_SUIT_TRAIT) //colons make me go all |= slowdown = 0 - n_hood = H.head + n_hood = ninja.head ADD_TRAIT(n_hood, TRAIT_NODROP, NINJA_SUIT_TRAIT) - n_shoes = H.shoes + n_shoes = ninja.shoes ADD_TRAIT(n_shoes, TRAIT_NODROP, NINJA_SUIT_TRAIT) n_shoes.slowdown-- - n_gloves = H.gloves + n_gloves = ninja.gloves ADD_TRAIT(n_gloves, TRAIT_NODROP, NINJA_SUIT_TRAIT) + n_mask = ninja.wear_mask + + ADD_TRAIT(ninja, TRAIT_NOGUNS, NINJA_SUIT_TRAIT) return TRUE -/obj/item/clothing/suit/space/space_ninja/proc/lockIcons(mob/living/carbon/human/H) - icon_state = H.dna.features["body_model"] == FEMALE ? "s-ninjanf" : "s-ninjan" - H.gloves.icon_state = "s-ninjan" - H.gloves.item_state = "s-ninjan" - -//This proc allows the suit to be taken off. -/obj/item/clothing/suit/space/space_ninja/proc/unlock_suit() +/** + * Proc called to unlock all the gear off space ninja's body. + * + * Proc which is essentially the opposite of lock_suit. Lets you take off all the suit parts. + * Also gets rid of the objection to using firearms from the wearer. + * Arguments: + * * ninja - The person wearing the suit. + */ +/obj/item/clothing/suit/space/space_ninja/proc/unlock_suit(mob/living/carbon/human/ninja) affecting = null REMOVE_TRAIT(src, TRAIT_NODROP, NINJA_SUIT_TRAIT) slowdown = 1 icon_state = "s-ninja" if(n_hood)//Should be attached, might not be attached. REMOVE_TRAIT(n_hood, TRAIT_NODROP, NINJA_SUIT_TRAIT) + n_hood.icon_state = "s-ninja" if(n_shoes) REMOVE_TRAIT(n_shoes, TRAIT_NODROP, NINJA_SUIT_TRAIT) n_shoes.slowdown++ if(n_gloves) - n_gloves.icon_state = "s-ninja" - n_gloves.item_state = "s-ninja" + n_gloves.icon_state = "black" REMOVE_TRAIT(n_gloves, TRAIT_NODROP, NINJA_SUIT_TRAIT) - n_gloves.candrain=0 - n_gloves.draining=0 + n_gloves.candrain = FALSE + n_gloves.draining = FALSE + REMOVE_TRAIT(ninja, TRAIT_NOGUNS, NINJA_SUIT_TRAIT) + if(n_mask) + n_mask.icon_state = "s-ninja" -/obj/item/clothing/suit/space/space_ninja/examine(mob/user) - . = ..() - if(s_initialized && user == affecting) - . += "All systems operational. Current energy capacity: [DisplayEnergy(cell.charge)].\n\ - The CLOAK-tech device is [stealth?"active":"inactive"].\n\ - There are [s_bombs] smoke bomb\s remaining.\n\ - There are [a_boost] adrenaline booster\s remaining." - -/obj/item/clothing/suit/space/space_ninja/ui_action_click(mob/user, action) - if(istype(action, /datum/action/item_action/initialize_ninja_suit)) - toggle_on_off() - return TRUE - if(!s_initialized) - to_chat(user, "ERROR: suit offline. Please activate suit.") - return FALSE - if(istype(action, /datum/action/item_action/ninjasmoke)) - ninjasmoke() - return TRUE - if(istype(action, /datum/action/item_action/ninjaboost)) - ninjaboost() - return TRUE - if(istype(action, /datum/action/item_action/ninjapulse)) - ninjapulse() - return TRUE - if(istype(action, /datum/action/item_action/ninjastar)) - ninjastar() - return TRUE - if(istype(action, /datum/action/item_action/ninja_sword_recall)) - ninja_sword_recall() - return TRUE - if(istype(action, /datum/action/item_action/ninja_stealth)) - stealth() - return TRUE - if(istype(action, /datum/action/item_action/toggle_glove)) - n_gloves.toggledrain() - return TRUE - return FALSE +/** + * Proc used to delete all the attachments and itself. + * + * Can be called to entire rid of the suit pieces and the suit itself. + */ +/obj/item/clothing/suit/space/space_ninja/proc/terminate() + QDEL_NULL(n_hood) + QDEL_NULL(n_gloves) + QDEL_NULL(n_shoes) + QDEL_NULL(src) diff --git a/code/modules/ninja/suit/suit_attackby.dm b/code/modules/ninja/suit/suit_attackby.dm index ed920a57d1..613d172182 100644 --- a/code/modules/ninja/suit/suit_attackby.dm +++ b/code/modules/ninja/suit/suit_attackby.dm @@ -1,51 +1,43 @@ - - -/obj/item/clothing/suit/space/space_ninja/attackby(obj/item/I, mob/U, params) - if(U!=affecting)//Safety, in case you try doing this without wearing the suit/being the person with the suit. +/obj/item/clothing/suit/space/space_ninja/attackby(obj/item/I, mob/ninja, params) + if(ninja!=affecting)//Safety, in case you try doing this without wearing the suit/being the person with the suit. return ..() - if(istype(I, /obj/item/reagent_containers/glass))//If it's a glass beaker. - if(I.reagents.has_reagent(/datum/reagent/radium, a_transfer) && a_boost < a_maxamount) - I.reagents.remove_reagent(/datum/reagent/radium, a_transfer) - a_boost++; - to_chat(U, "There are now [a_boost] adrenaline boosts remaining.") - return - if(I.reagents.has_reagent(/datum/reagent/smoke_powder, a_transfer) && s_bombs < s_maxamount) - I.reagents.remove_reagent(/datum/reagent/smoke_powder, a_transfer) - s_bombs++; - to_chat(U, "There are now [s_bombs] smoke bombs remaining.") - return + if(istype(I, /obj/item/reagent_containers/glass) && I.reagents.has_reagent(/datum/reagent/uranium/radium, a_transfer) && a_boost != TRUE)//If it's a glass beaker, and what we're transferring is radium. + I.reagents.remove_reagent(/datum/reagent/uranium/radium, a_transfer) + a_boost = TRUE; + to_chat(ninja, "The suit's adrenaline boost is now reloaded.") + return else if(istype(I, /obj/item/stock_parts/cell)) var/obj/item/stock_parts/cell/CELL = I if(CELL.maxcharge > cell.maxcharge && n_gloves && n_gloves.candrain) - to_chat(U, "Higher maximum capacity detected.\nUpgrading...") - if (n_gloves && n_gloves.candrain && do_after(U,s_delay, target = src)) - U.transferItemToLoc(CELL, src) + to_chat(ninja, "Higher maximum capacity detected.\nUpgrading...") + if (n_gloves?.candrain && do_after(ninja,s_delay, target = src)) + ninja.transferItemToLoc(CELL, src) CELL.charge = min(CELL.charge+cell.charge, CELL.maxcharge) var/obj/item/stock_parts/cell/old_cell = cell old_cell.charge = 0 - U.put_in_hands(old_cell) - old_cell.add_fingerprint(U) + ninja.put_in_hands(old_cell) + old_cell.add_fingerprint(ninja) old_cell.corrupt() old_cell.update_icon() cell = CELL - to_chat(U, "Upgrade complete. Maximum capacity: [round(cell.maxcharge/100)]%") + to_chat(ninja, "Upgrade complete. Maximum capacity: [round(cell.maxcharge/100)]%") else - to_chat(U, "Procedure interrupted. Protocol terminated.") + to_chat(ninja, "Procedure interrupted. Protocol terminated.") return else if(istype(I, /obj/item/disk/tech_disk))//If it's a data disk, we want to copy the research on to the suit. var/obj/item/disk/tech_disk/TD = I var/has_research = 0 if(has_research)//If it has something on it. - to_chat(U, "Research information detected, processing...") - if(do_after(U,s_delay, target = src)) + to_chat(ninja, "Research information detected, processing...") + if(do_after(ninja,s_delay, target = src)) TD.stored_research.copy_research_to(stored_research) - to_chat(U, "Data analyzed and updated. Disk erased.") + to_chat(ninja, "Data analyzed and updated. Disk erased.") else - to_chat(U, "ERROR: Procedure interrupted. Process terminated.") + to_chat(ninja, "ERROR: Procedure interrupted. Process terminated.") else to_chat(U, "No research information detected.") return diff --git a/code/modules/ninja/suit/suit_initialisation.dm b/code/modules/ninja/suit/suit_initialisation.dm deleted file mode 100644 index 3d80282fe7..0000000000 --- a/code/modules/ninja/suit/suit_initialisation.dm +++ /dev/null @@ -1,95 +0,0 @@ -/obj/item/clothing/suit/space/space_ninja/proc/toggle_on_off() - if(s_busy) - to_chat(loc, "ERROR: You cannot use this function at this time.") - return FALSE - if(s_initialized) - deinitialize() - else - ninitialize() - . = TRUE - -/obj/item/clothing/suit/space/space_ninja/proc/ninitialize(delay = s_delay, mob/living/carbon/human/U = loc) - if(!U.mind) - return //Not sure how this could happen. - s_busy = TRUE - to_chat(U, "Now initializing...") - addtimer(CALLBACK(src, .proc/ninitialize_two, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/ninitialize_two(delay, mob/living/carbon/human/U) - if(!lock_suit(U))//To lock the suit onto wearer. - s_busy = FALSE - return - to_chat(U, "Securing external locking mechanism...\nNeural-net established.") - addtimer(CALLBACK(src, .proc/ninitialize_three, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/ninitialize_three(delay, mob/living/carbon/human/U) - to_chat(U, "Extending neural-net interface...\nNow monitoring brain wave pattern...") - addtimer(CALLBACK(src, .proc/ninitialize_four, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/ninitialize_four(delay, mob/living/carbon/human/U) - if(U.stat == DEAD|| U.health <= 0) - to_chat(U, "FĆAL �Rr�R: 344--93#�&&21 BR��N |/|/aV� PATT$RN RED\nA-A-aB�rT�NG...") - unlock_suit() - s_busy = FALSE - return - lockIcons(U)//Check for icons. - U.regenerate_icons() - to_chat(U, "Linking neural-net interface...\nPattern\green GREEN, continuing operation.") - addtimer(CALLBACK(src, .proc/ninitialize_five, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/ninitialize_five(delay, mob/living/carbon/human/U) - to_chat(U, "VOID-shift device status: ONLINE.\nCLOAK-tech device status: ONLINE.") - addtimer(CALLBACK(src, .proc/ninitialize_six, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/ninitialize_six(delay, mob/living/carbon/human/U) - to_chat(U, "Primary system status: ONLINE.\nBackup system status: ONLINE.\nCurrent energy capacity: [DisplayEnergy(cell.charge)].") - addtimer(CALLBACK(src, .proc/ninitialize_seven, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/ninitialize_seven(delay, mob/living/carbon/human/U) - to_chat(U, "All systems operational. Welcome to SpiderOS, [U.real_name].") - s_initialized = TRUE - START_PROCESSING(SSprocessing, src) - s_busy = FALSE - - - -/obj/item/clothing/suit/space/space_ninja/proc/deinitialize(delay = s_delay) - if(affecting==loc) - var/mob/living/carbon/human/U = affecting - if(alert("Are you certain you wish to remove the suit? This will take time and remove all abilities.",,"Yes","No")=="No") - return - s_busy = TRUE - addtimer(CALLBACK(src, .proc/deinitialize_two, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/deinitialize_two(delay, mob/living/carbon/human/U) - to_chat(U, "Now de-initializing...") - addtimer(CALLBACK(src, .proc/deinitialize_three, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/deinitialize_three(delay, mob/living/carbon/human/U) - to_chat(U, "Logging off, [U.real_name]. Shutting down SpiderOS.") - addtimer(CALLBACK(src, .proc/deinitialize_four, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/deinitialize_four(delay, mob/living/carbon/human/U) - to_chat(U, "Primary system status: OFFLINE.\nBackup system status: OFFLINE.") - addtimer(CALLBACK(src, .proc/deinitialize_five, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/deinitialize_five(delay, mob/living/carbon/human/U) - to_chat(U, "VOID-shift device status: OFFLINE.\nCLOAK-tech device status: OFFLINE.") - cancel_stealth()//Shutdowns stealth. - addtimer(CALLBACK(src, .proc/deinitialize_six, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/deinitialize_six(delay, mob/living/carbon/human/U) - to_chat(U, "Disconnecting neural-net interface...\greenSuccess.") - addtimer(CALLBACK(src, .proc/deinitialize_seven, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/deinitialize_seven(delay, mob/living/carbon/human/U) - to_chat(U, "Disengaging neural-net interface...\greenSuccess.") - addtimer(CALLBACK(src, .proc/deinitialize_eight, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/deinitialize_eight(delay, mob/living/carbon/human/U) - to_chat(U, "Unsecuring external locking mechanism...\nNeural-net abolished.\nOperation status: FINISHED.") - unlock_suit() - U.regenerate_icons() - s_initialized = FALSE - STOP_PROCESSING(SSprocessing, src) - s_busy = FALSE diff --git a/code/modules/ninja/suit/suit_process.dm b/code/modules/ninja/suit/suit_process.dm deleted file mode 100644 index 5c1276e29a..0000000000 --- a/code/modules/ninja/suit/suit_process.dm +++ /dev/null @@ -1,17 +0,0 @@ -/obj/item/clothing/suit/space/space_ninja/process() - if(!affecting || !s_initialized) - return PROCESS_KILL - - if(cell.charge > 0) - if(s_coold) - s_coold--//Checks for ability s_cooldown first. - - cell.charge -= s_cost//s_cost is the default energy cost each tick, usually 5. - if(stealth && stealth_cooldown <= world.time)//If stealth is active. - cell.charge -= s_acost - affecting.alpha = max(affecting.alpha - 10, 15) - - else - cell.charge = 0 - if(stealth) - cancel_stealth() diff --git a/tgstation.dme b/tgstation.dme index f733aee27c..0c9ae166d6 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1676,7 +1676,6 @@ #include "code\modules\antagonists\morph\morph.dm" #include "code\modules\antagonists\morph\morph_antag.dm" #include "code\modules\antagonists\nightmare\nightmare.dm" -#include "code\modules\antagonists\ninja\ninja.dm" #include "code\modules\antagonists\nukeop\clownop.dm" #include "code\modules\antagonists\nukeop\nukeop.dm" #include "code\modules\antagonists\nukeop\equipment\borgchameleon.dm" @@ -1699,6 +1698,7 @@ #include "code\modules\antagonists\slaughter\slaughter.dm" #include "code\modules\antagonists\slaughter\slaughter_antag.dm" #include "code\modules\antagonists\slaughter\slaughterevent.dm" +#include "code\modules\antagonists\space_ninja\space_ninja.dm" #include "code\modules\antagonists\survivalist\survivalist.dm" #include "code\modules\antagonists\swarmer\swarmer.dm" #include "code\modules\antagonists\swarmer\swarmer_event.dm" @@ -2054,6 +2054,7 @@ #include "code\modules\events\radiation_storm.dm" #include "code\modules\events\sentience.dm" #include "code\modules\events\shuttle_loan.dm" +#include "code\modules\events\space_ninja.dm" #include "code\modules\events\spacevine.dm" #include "code\modules\events\spider_infestation.dm" #include "code\modules\events\spontaneous_appendicitis.dm" @@ -2882,7 +2883,7 @@ #include "code\modules\newscaster\wanted_message.dm" #include "code\modules\ninja\__ninjaDefines.dm" #include "code\modules\ninja\energy_katana.dm" -#include "code\modules\ninja\ninja_event.dm" +#include "code\modules\ninja\ninja_explosive.dm" #include "code\modules\ninja\outfit.dm" #include "code\modules\ninja\suit\gloves.dm" #include "code\modules\ninja\suit\head.dm" @@ -2891,17 +2892,17 @@ #include "code\modules\ninja\suit\shoes.dm" #include "code\modules\ninja\suit\suit.dm" #include "code\modules\ninja\suit\suit_attackby.dm" -#include "code\modules\ninja\suit\suit_initialisation.dm" -#include "code\modules\ninja\suit\suit_process.dm" -#include "code\modules\ninja\suit\n_suit_verbs\energy_net_nets.dm" -#include "code\modules\ninja\suit\n_suit_verbs\ninja_adrenaline.dm" -#include "code\modules\ninja\suit\n_suit_verbs\ninja_cost_check.dm" -#include "code\modules\ninja\suit\n_suit_verbs\ninja_empulse.dm" -#include "code\modules\ninja\suit\n_suit_verbs\ninja_net.dm" -#include "code\modules\ninja\suit\n_suit_verbs\ninja_smoke.dm" -#include "code\modules\ninja\suit\n_suit_verbs\ninja_stars.dm" -#include "code\modules\ninja\suit\n_suit_verbs\ninja_stealth.dm" -#include "code\modules\ninja\suit\n_suit_verbs\ninja_sword_recall.dm" +#include "code\modules\ninja\suit\ninja_equipment_actions\energy_net_nets.dm" +#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_adrenaline.dm" +#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_cost_check.dm" +#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_empulse.dm" +#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_glove_toggle.dm" +#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_net.dm" +#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_stars.dm" +#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_status_read.dm" +#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_stealth.dm" +#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_suit_initialisation.dm" +#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_sword_recall.dm" #include "code\modules\NTNet\netdata.dm" #include "code\modules\NTNet\network.dm" #include "code\modules\NTNet\relays.dm"