diff --git a/code/datums/actions/ninja.dm b/code/datums/actions/ninja.dm deleted file mode 100644 index b655078349d..00000000000 --- a/code/datums/actions/ninja.dm +++ /dev/null @@ -1,51 +0,0 @@ -/datum/action/item_action/initialize_ninja_suit - name = "Toggle ninja suit" - -/datum/action/item_action/ninjasmoke - name = "Smoke Bomb" - desc = "Blind your enemies momentarily with a well-placed smoke bomb." - button_icon_state = "smoke" - icon_icon = 'icons/mob/actions/actions_spells.dmi' - -/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' - -/datum/action/item_action/ninjapulse - name = "EM Burst (25E)" - desc = "Disable any nearby technology with an electro-magnetic pulse." - button_icon_state = "emp" - icon_icon = 'icons/mob/actions/actions_spells.dmi' - -/datum/action/item_action/ninjastar - name = "Create Throwing Stars (1E)" - desc = "Creates some throwing stars" - button_icon_state = "throwingstar" - icon_icon = 'icons/obj/items_and_weapons.dmi' - -/datum/action/item_action/ninjanet - name = "Energy Net (20E)" - desc = "Captures a fallen opponent in a net of energy. Will teleport them to a holding facility after 30 seconds." - button_icon_state = "energynet" - icon_icon = 'icons/effects/effects.dmi' - -/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' - -/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' - -/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' diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index 0239b15f64e..d2c35685e9a 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -621,7 +621,47 @@ if(!spawn_locs.len) message_admins("No valid spawn locations found in GLOB.xeno_spawn, aborting swarmer spawning...") return MAP_ERROR - var/obj/structure/swarmer_beacon/new_beacon = new /obj/structure/swarmer_beacon(pick(spawn_locs)) + var/obj/structure/swarmer_beacon/new_beacon = new(pick(spawn_locs)) log_game("A Swarmer Beacon was spawned via Dynamic Mode.") notify_ghosts("\A Swarmer Beacon has spawned!", source = new_beacon, action = NOTIFY_ORBIT, flashwindow = FALSE, header = "Swarmer Beacon Spawned") return ..() + +////////////////////////////////////////////// +// // +// SPACE NINJA (GHOST) // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/midround/from_ghosts/space_ninja + name = "Space Ninja" + antag_datum = /datum/antagonist/ninja + antag_flag = "Space Ninja" + antag_flag_override = ROLE_NINJA + enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain") + required_enemies = list(2,2,1,1,1,1,1,0,0,0) + required_candidates = 1 + weight = 4 + cost = 10 + requirements = list(101,101,101,80,60,50,30,20,10,10) + repeatable = TRUE + var/list/spawn_locs = list() + +/datum/dynamic_ruleset/midround/from_ghosts/space_ninja/execute() + 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 + return ..() + +/datum/dynamic_ruleset/midround/from_ghosts/space_ninja/generate_ruleset_body(mob/applicant) + var/mob/living/carbon/human/ninja = create_space_ninja(pick(spawn_locs)) + ninja.key = applicant.key + ninja.mind.add_antag_datum(/datum/antagonist/ninja) + + message_admins("[ADMIN_LOOKUPFLW(ninja)] has been made into a Space Ninja by the midround ruleset.") + log_game("DYNAMIC: [key_name(ninja)] was spawned as a Space Ninja by the midround ruleset.") + return ninja diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index f59c94f0f7f..1eae2e9e1d8 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -729,3 +729,14 @@ Class Procs: if(3) new_name += ascii2text(rand(48, 57)) // 0 - 9 return new_name.Join() + +/** + * 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 992bc0f05de..fefba6ef918 100644 --- a/code/modules/admin/verbs/one_click_antag.dm +++ b/code/modules/admin/verbs/one_click_antag.dm @@ -230,8 +230,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 8807898bf1b..00000000000 --- a/code/modules/antagonists/ninja/ninja.dm +++ /dev/null @@ -1,153 +0,0 @@ -/datum/antagonist/ninja - name = "Ninja" - antagpanel_category = "Ninja" - job_rank = ROLE_NINJA - antag_hud_type = ANTAG_HUD_NINJA - antag_hud_name = "ninja" - show_name_in_check_antagonists = TRUE - show_to_ghosts = TRUE - antag_moodlet = /datum/mood_event/focused - var/helping_station = FALSE - var/give_objectives = TRUE - var/give_equipment = TRUE - -/datum/antagonist/ninja/New() - if(helping_station) - can_elimination_hijack = ELIMINATION_PREVENT - . = ..() - -/datum/antagonist/ninja/apply_innate_effects(mob/living/mob_override) - var/mob/living/M = mob_override || owner.current - add_antag_hud(antag_hud_type, antag_hud_name, M) - -/datum/antagonist/ninja/remove_innate_effects(mob/living/mob_override) - var/mob/living/M = mob_override || owner.current - remove_antag_hud(antag_hud_type, 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] = FALSE //bad-guy - else if(M.assigned_role in GLOB.command_positions) - possible_targets[M] = TRUE //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 - 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/O = new /datum/objective/assassinate() - O.owner = owner - O.target = M - O.explanation_text = "Slay \the [M.current.real_name], the [M.assigned_role]." - 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) //debrain/capture - if(!possible_targets.len) continue - var/selected = rand(1,possible_targets.len) - var/datum/mind/M = possible_targets[selected] - var/is_bad_guy = possible_targets[M] - possible_targets.Cut(selected,selected+1) - - if(is_bad_guy ^ helping_station) //debrain (good-ninja + bad-guy or bad-ninja + good-guy) - var/datum/objective/debrain/O = new /datum/objective/debrain() - O.owner = owner - O.target = M - O.explanation_text = "Steal the brain of [M.current.real_name]." - objectives += O - else //capture - var/datum/objective/capture/O = new /datum/objective/capture() - O.owner = owner - O.gen_amount_goal() - 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 - if(helping_station) - can_elimination_hijack = ELIMINATION_PREVENT - 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 [key_name_admin(new_owner)].") - log_admin("[key_name(admin)] has [adj] ninja'ed [key_name(new_owner)].") 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 00000000000..23d7e1ff972 --- /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)].") diff --git a/code/modules/events/space_ninja.dm b/code/modules/events/space_ninja.dm new file mode 100644 index 00000000000..19ac7d1c8e6 --- /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 diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index bb951f31f3b..df427638a00 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -81,34 +81,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()]" - 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 d6cdb558409..b02389207d8 100644 --- a/code/modules/ninja/__ninjaDefines.dm +++ b/code/modules/ninja/__ninjaDefines.dm @@ -1,23 +1,22 @@ - -/* - -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 7c16bb58354..52ac682b9cf 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." @@ -6,8 +17,8 @@ worn_icon_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 @@ -32,22 +43,17 @@ /obj/item/energy_katana/attack_self(mob/user) dash_toggled = !dash_toggled to_chat(user, "You [dash_toggled ? "enable" : "disable"] the dash function on [src].") - + /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, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) - playsound(user, 'sound/weapons/blade1.ogg', 50, TRUE) - target.emag_act(user) /obj/item/energy_katana/pickup(mob/living/user) . = ..() jaunt.Grant(user, src) user.update_icons() - playsound(src, 'sound/items/unsheath.ogg', 25, TRUE) + playsound(src, 'sound/items/unsheath.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) /obj/item/energy_katana/dropped(mob/user) . = ..() @@ -59,16 +65,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,13 +115,8 @@ if(msg) 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 = 150 + 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 beec8aa88c6..00000000000 --- a/code/modules/ninja/ninja_event.dm +++ /dev/null @@ -1,89 +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 - 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 - 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 = TRUE - - //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! - CRASH("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.") - - 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 00000000000..329a95e5e2c --- /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/c4/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 2b5976db4d5..8fc07803478 100644 --- a/code/modules/ninja/outfit.dm +++ b/code/modules/ninja/outfit.dm @@ -8,8 +8,7 @@ ears = /obj/item/radio/headset 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/c4/x4 + l_pocket = /obj/item/grenade/c4/ninja r_pocket = /obj/item/tank/internals/emergency_oxygen internals_slot = ITEM_SLOT_RPOCKET belt = /obj/item/energy_katana @@ -21,5 +20,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 839bdcfb0e8..b4c945b5be1 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" - inhand_icon_state = "s-ninja" + icon_state = "black" + inhand_icon_state = "s-ninjan" siemens_coefficient = 0 cold_protection = HANDS min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT @@ -32,10 +20,19 @@ max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT strip_delay = 120 resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF + 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 /obj/item/clothing/gloves/space_ninja/Touch(atom/A,proximity) @@ -44,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)) @@ -55,27 +52,27 @@ 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!") else . = FALSE //as to not cancel attack_hand() - -/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)) . += "[p_their(TRUE)] 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 d7c61e38155..ca35ca5237b 100644 --- a/code/modules/ninja/suit/head.dm +++ b/code/modules/ninja/suit/head.dm @@ -1,12 +1,18 @@ - - +/** + * # Ninja Hood + * + * Space ninja's hood. Provides armor and blocks AI tracking. + * + * A hood that only exists as a part of space ninja's starting kit. Provides armor equal of space ninja's suit and disallows an AI to track the wearer. + * + */ /obj/item/clothing/head/helmet/space/space_ninja desc = "What may appear to be a simple black garment is in fact a highly sophisticated nano-weave helmet. Standard issue ninja gear." name = "ninja hood" icon_state = "s-ninja" inhand_icon_state = "s-ninja_mask" - armor = list(MELEE = 60, BULLET = 50, LASER = 30,ENERGY = 15, BOMB = 30, BIO = 30, RAD = 25, FIRE = 100, ACID = 100) + armor = list(MELEE = 40, BULLET = 30, LASER = 20,ENERGY = 15, BOMB = 30, BIO = 30, RAD = 25, FIRE = 100, ACID = 100) strip_delay = 12 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 diff --git a/code/modules/ninja/suit/mask.dm b/code/modules/ninja/suit/mask.dm index 120e8bbf371..aac1375f69c 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. Other than looking cool, doesn't do anything. + * + * A mask which only spawns as a part of space ninja's starting kit. Functions as a gas mask. + * + */ /obj/item/clothing/mask/gas/space_ninja name = "ninja mask" desc = "A close-fitting mask that acts both as an air filter and a post-modern fashion statement." 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 2e64535b12a..00000000000 --- a/code/modules/ninja/suit/n_suit_verbs/energy_net_nets.dm +++ /dev/null @@ -1,86 +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 = 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 = 25 //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 = 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, TRUE) - if(BURN) - playsound(src, 'sound/weapons/slash.ogg', 80, TRUE) - -/obj/structure/energy_net/Destroy() - if(!success) - 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.") - 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(delta_time) - if(QDELETED(affecting)||affecting.loc!=loc) - qdel(src)//Get rid of the net. - return - - if(check > 0) - check -= delta_time - 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) - continue//So all they're left with are shoes and uniform. - if(W == H.shoes) - continue - H.dropItemToGround(W) - - // After we remove items, at least give them what they need to live. - H.dna.species.give_important_for_life(H) - - playsound(affecting, 'sound/effects/sparks4.ogg', 50, TRUE) - 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, TRUE) - playsound(affecting, 'sound/effects/sparks2.ogg', 50, TRUE) - new /obj/effect/temp_visual/dir_setting/ninja/phase(affecting.drop_location(), affecting.dir) - -/obj/structure/energy_net/attack_paw(mob/user) - return attack_hand() - -/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 4f5c69e5fb0..00000000000 --- a/code/modules/ninja/suit/n_suit_verbs/ninja_adrenaline.dm +++ /dev/null @@ -1,24 +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.SetUnconscious(0) - H.SetStun(0) - H.SetKnockdown(0) - H.SetImmobilized(0) - H.SetParalyzed(0) - H.adjustStaminaLoss(-75) - H.stuttering = 0 - H.reagents.add_reagent(/datum/reagent/medicine/stimulants, 5) - 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 = 6 - 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/uranium/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 da0c28346a7..00000000000 --- 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 3d77ac911cb..00000000000 --- 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(H, 4, 6) //Procs sure are nice. Slightly weaker than wizard's disable tch. - s_coold = 4 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 629b2f1d674..00000000000 --- a/code/modules/ninja/suit/n_suit_verbs/ninja_net.dm +++ /dev/null @@ -1,33 +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 = input("Select who to capture:","Capture who?",null) as null|mob in sortNames(oview(H)) - - if(QDELETED(C)||!(C in oview(H))) - return - - if(!C.client)//Monkeys without a client can still step_to() and bypass the net. Also, netting inactive people is lame. - to_chat(H, "[C.p_they(TRUE)] will bring no honor to your Clan!") - return - if(locate(/obj/structure/energy_net) in get_turf(C))//Check if they are already being affected by an energy net. - to_chat(H, "[C.p_they(TRUE)] are already trapped inside an energy net!") - return - for(var/turf/T in getline(get_turf(H), get_turf(C))) - if(T.density)//Don't want them shooting nets through walls. It's kind of cheesy. - to_chat(H, "You may not use an energy net through solid obstacles!") - return - 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 2f4954928a3..00000000000 --- 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 = 2 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 a0c6073281a..00000000000 --- 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) 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 4d9b97d8cf8..00000000000 --- a/code/modules/ninja/suit/n_suit_verbs/ninja_stealth.dm +++ /dev/null @@ -1,43 +0,0 @@ - -/* - -Contents: -- Stealth Verbs - -*/ - - -/obj/item/clothing/suit/space/space_ninja/proc/toggle_stealth() - var/mob/living/carbon/human/U = affecting - if(!U) - return - if(stealth) - cancel_stealth() - else - if(cell.charge <= 0) - to_chat(U, "You don't have enough power to enable Stealth!") - return - stealth = !stealth - animate(U, alpha = 50,time = 15) - U.visible_message("[U.name] vanishes into thin air!", \ - "You are now mostly invisible to normal detection.") - - -/obj/item/clothing/suit/space/space_ninja/proc/cancel_stealth() - var/mob/living/carbon/human/U = affecting - if(!U) - return FALSE - if(stealth) - stealth = !stealth - animate(U, alpha = 255, time = 15) - U.visible_message("[U.name] appears from thin air!", \ - "You are now visible.") - return TRUE - return FALSE - - -/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 a68dc0dce25..00000000000 --- a/code/modules/ninja/suit/n_suit_verbs/ninja_sword_recall.dm +++ /dev/null @@ -1,36 +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) - - 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, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) - 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 460061a7ef1..f31cd10c901 100644 --- a/code/modules/ninja/suit/ninjaDrainAct.dm +++ b/code/modules/ninja/suit/ninjaDrainAct.dm @@ -1,263 +1,306 @@ - -/* - -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 - - . = 0 + var/drain_total = 0 if(cell?.charge) var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread() spark_system.set_up(5, 0, loc) - while(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, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) cell.use(drain) - S.cell.give(drain) - . += drain + ninja_suit.cell.give(drain) + drain_total += drain else break if(!(obj_flags & EMAGGED)) - flick("apc-spark", G) + 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, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) charge -= drain - S.cell.give(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.give(charge) + ninja_suit.cell.give(charge) charge = 0 corrupt() update_icon() - -/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) + + 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, 2) + 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.give(drain) - 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/vehicle/sealed/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 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, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) cell.use(drain) - S.cell.give(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) return INVALID_DRAIN - var/maxcapacity = 0 //Safety check - var/drain = 0 //Drain amount - . = 0 - - to_chat(src, "Warning: Unauthorized access through sub-route 12, block C, detected.") - - if(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, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) - cell.use(drain) - S.cell.give(drain) - . += drain - else - break - + 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 MODULE DETECTED. INSTALLING...") + faction = list(ROLE_NINJA) + bubble_icon = "syndibot" + lawupdate = FALSE + scrambledcodes = TRUE + ionpulse = TRUE + laws = new /datum/ai_laws/ninja_override() + module.transform_to(pick(/obj/item/robot_module/syndicate, /obj/item/robot_module/syndicate_medical, /obj/item/robot_module/saboteur)) + + var/datum/antagonist/ninja/ninja_antag = ninja.mind.has_antag_datum(/datum/antagonist/ninja) + if(!ninja_antag) + return + var/datum/objective/cyborg_hijack/objective = locate() in ninja_antag.objectives + if(objective) + objective.completed = TRUE //CARBON MOBS// -/mob/living/carbon/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/S, mob/living/carbon/human/H, obj/item/clothing/gloves/space_ninja/G) - if(!S || !H || !G) +/mob/living/carbon/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves) + if(!ninja_suit || !ninja || !ninja_gloves) return INVALID_DRAIN . = DRAIN_MOB_SHOCK_FAILED //Default cell = 10,000 charge, 10,000/1000 = 10 uses without charging/upgrading - if(S.cell && S.cell.charge && S.cell.use(1000)) + if(ninja_suit.cell?.charge && ninja_suit.cell.use(1000)) . = DRAIN_MOB_SHOCK //Got that electric touch var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread() spark_system.set_up(5, 0, loc) playsound(src, "sparks", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) - visible_message("[H] electrocutes [src] with [H.p_their()] touch!", "[H] electrocutes you with [H.p_their()] touch!") - electrocute_act(25, H) + visible_message("[ninja] electrocutes [src] with [ninja.p_their()] touch!", "[ninja] electrocutes you with [ninja.p_their()] touch!") + Knockdown(3 SECONDS) 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 00000000000..bae82aaa2dc --- /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/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/ninja_equipment_actions/ninja_adrenaline.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_adrenaline.dm new file mode 100644 index 00000000000..7cd8ef8f0bc --- /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 00000000000..b142751403b --- /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 00000000000..d6f0132c4f3 --- /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 00000000000..f65edbac541 --- /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 00000000000..1538b2ca0c3 --- /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 00000000000..d68d290e25c --- /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 00000000000..76aa540510b --- /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 00000000000..aaa52943dbb --- /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/suit_initialisation.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_suit_initialisation.dm similarity index 71% rename from code/modules/ninja/suit/suit_initialisation.dm rename to code/modules/ninja/suit/ninja_equipment_actions/ninja_suit_initialisation.dm index cd1625afb89..d9ea681443f 100644 --- a/code/modules/ninja/suit/suit_initialisation.dm +++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_suit_initialisation.dm @@ -24,6 +24,9 @@ GLOBAL_LIST_INIT(ninja_deinitialize_messages, list( "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 * @@ -46,40 +49,40 @@ GLOBAL_LIST_INIT(ninja_deinitialize_messages, list( * 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 - * * U - The human who is being affected by the suit + * * 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/U = loc, phase = 0) - if(!U || !U.mind) +/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 && (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() + 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(U))//To lock the suit onto wearer. + if(!lock_suit(ninja))//To lock the suit onto wearer. s_busy = FALSE return if (NINJA_ICON_GENERATE_PHASE) - lockIcons(U)//Check for icons. - U.regenerate_icons() + lockIcons(ninja)//Check for icons. + ninja.regenerate_icons() if (NINJA_COMPLETE_PHASE - 1) message += "[DisplayEnergy(cell.charge)]." if (NINJA_COMPLETE_PHASE) - message += "[U.real_name]." + message += "[ninja.real_name]." s_initialized = TRUE s_busy = FALSE - to_chat(U, "[message]") - playsound(U, 'sound/effects/sparks1.ogg', 10, TRUE) + to_chat(ninja, "[message]") + playsound(ninja, 'sound/effects/sparks1.ogg', 10, TRUE) if (phase < NINJA_COMPLETE_PHASE) - addtimer(CALLBACK(src, .proc/ninitialize, delay, U, phase + 1), delay) + addtimer(CALLBACK(src, .proc/ninitialize, delay, ninja, phase + 1), delay) /** * Deinitializes the ninja suit @@ -87,11 +90,11 @@ GLOBAL_LIST_INIT(ninja_deinitialize_messages, list( * 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 - * * U - The human who is being affected by the suit + * * 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/U = affecting == loc ? affecting : null, phase = 0) - if (!U || !U.mind) +/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") @@ -101,17 +104,17 @@ GLOBAL_LIST_INIT(ninja_deinitialize_messages, list( var/message = GLOB.ninja_deinitialize_messages[phase + 1] switch(phase) if(NINJA_DEINIT_LOGOFF_PHASE) - message = "Logging off, [U.real_name]. " + message + message = "Logging off, [ninja.real_name]. " + message if(NINJA_DEINIT_STEALTH_PHASE) cancel_stealth() - to_chat(U, "[message]") - playsound(U, 'sound/items/deconstruct.ogg', 10, TRUE) + to_chat(ninja, "[message]") + playsound(ninja, 'sound/items/deconstruct.ogg', 10, TRUE) if (phase < NINJA_COMPLETE_PHASE) - addtimer(CALLBACK(src, .proc/deinitialize, delay, U, phase + 1), delay) + addtimer(CALLBACK(src, .proc/deinitialize, delay, ninja, phase + 1), delay) else - unlock_suit() - U.regenerate_icons() + unlock_suit(ninja) + ninja.regenerate_icons() s_initialized = FALSE s_busy = FALSE 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 00000000000..69367e807fb --- /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 c006840b628..fe4cb9bd401 100644 --- a/code/modules/ninja/suit/shoes.dm +++ b/code/modules/ninja/suit/shoes.dm @@ -1,4 +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." @@ -7,7 +15,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) + armor = list(MELEE = 40, BULLET = 30, LASER = 20,ENERGY = 15, BOMB = 30, BIO = 30, RAD = 30, FIRE = 100, ACID = 100) strip_delay = 120 cold_protection = FEET min_cold_protection_temperature = SHOES_MIN_TEMP_PROTECT diff --git a/code/modules/ninja/suit/suit.dm b/code/modules/ninja/suit/suit.dm index eca5fee785d..2614c8ed386 100644 --- a/code/modules/ninja/suit/suit.dm +++ b/code/modules/ninja/suit/suit.dm @@ -1,12 +1,13 @@ - -/* - -Contents: -- The Ninja Space Suit -- Ninja Space Suit Procs - -*/ - +/** + * # 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." @@ -14,44 +15,57 @@ Contents: inhand_icon_state = "s-ninja_suit" allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/restraints/handcuffs, /obj/item/tank/internals, /obj/item/stock_parts/cell) resistance_flags = LAVA_PROOF | ACID_PROOF - armor = list(MELEE = 60, BULLET = 50, LASER = 30,ENERGY = 40, BOMB = 30, BIO = 30, RAD = 30, FIRE = 100, ACID = 100) + armor = list(MELEE = 40, BULLET = 30, LASER = 20,ENERGY = 30, BOMB = 30, BIO = 30, RAD = 30, FIRE = 100, ACID = 100) strip_delay = 12 min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT - actions_types = list(/datum/action/item_action/initialize_ninja_suit, /datum/action/item_action/ninjasmoke, /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, /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 + ///The suit's spark system, used for... sparking. var/datum/effect_system/spark_spread/spark_system + ///The suit's stored research. Used for the research objective (see antagonist file) var/datum/techweb/stored_research - var/obj/item/disk/tech_disk/t_disk//To copy design onto disk. - var/obj/item/energy_katana/energyKatana //For teleporting the katana back to the ninja (It's an ability) + ///The katana registered with the suit, used for recalling and catching the katana. Set when the ninja outfit is created. + var/obj/item/energy_katana/energyKatana - //Other articles of ninja gear worn together, used to easily reference them after initializing. + ///The space ninja's hood. var/obj/item/clothing/head/helmet/space/space_ninja/n_hood + ///The space ninja's shoes. var/obj/item/clothing/shoes/space_ninja/n_shoes + ///The space ninja's gloves. var/obj/item/clothing/gloves/space_ninja/n_gloves + ///The space ninja's mask. + var/obj/item/clothing/mask/gas/space_ninja/n_mask - //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 = 2.5//Base energy cost each ntick. - var/s_acost = 12.5//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. - - //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/s_busy = FALSE//Is the suit busy with a process? Like AI hacking. Used for safety functions. + ///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 - //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 +/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() . = ..() @@ -96,113 +110,144 @@ Contents: user.adjust_bodytemperature(BODYTEMP_NORMAL - user.bodytemperature) -//Simply deletes all the attachments and self, killing all related procs. -/obj/item/clothing/suit/space/space_ninja/proc/terminate() - qdel(n_hood) - qdel(n_gloves) - qdel(n_shoes) - qdel(src) - - -//Randomizes suit parameters. -/obj/item/clothing/suit/space/space_ninja/proc/randomize_param() - s_cost = rand(1,10) - s_acost = rand(10,50) - 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)) - 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() - 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...") - return FALSE - if(!istype(H.shoes, /obj/item/clothing/shoes/space_ninja)) - to_chat(H, "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...") - return FALSE - affecting = H - ADD_TRAIT(src, TRAIT_NODROP, NINJA_SUIT_TRAIT) - n_hood = H.head - ADD_TRAIT(n_hood, TRAIT_NODROP, NINJA_SUIT_TRAIT) - n_shoes = H.shoes - ADD_TRAIT(n_shoes, TRAIT_NODROP, NINJA_SUIT_TRAIT) - n_shoes.slowdown-- - n_gloves = H.gloves - ADD_TRAIT(n_gloves, TRAIT_NODROP, NINJA_SUIT_TRAIT) - return TRUE - -/obj/item/clothing/suit/space/space_ninja/proc/lockIcons(mob/living/carbon/human/H) - icon_state = H.gender==FEMALE ? "s-ninjanf" : "s-ninjan" - H.gloves.icon_state = "s-ninjan" - H.gloves.inhand_icon_state = "s-ninjan" - - -//This proc allows the suit to be taken off. -/obj/item/clothing/suit/space/space_ninja/proc/unlock_suit() - affecting = null - REMOVE_TRAIT(src, TRAIT_NODROP, NINJA_SUIT_TRAIT) - icon_state = "s-ninja" - if(n_hood)//Should be attached, might not be attached. - REMOVE_TRAIT(n_hood, TRAIT_NODROP, NINJA_SUIT_TRAIT) - 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.inhand_icon_state = "s-ninja" - REMOVE_TRAIT(n_gloves, TRAIT_NODROP, NINJA_SUIT_TRAIT) - n_gloves.candrain = FALSE - n_gloves.draining = FALSE - - -/obj/item/clothing/suit/space/space_ninja/examine(mob/user) - . = ..() - if(s_initialized) - if(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)) + 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(istype(action, /datum/action/item_action/ninjasmoke)) - ninjasmoke() + if(s_coold != 0) + to_chat(user, "ERROR: suit is on cooldown.") + return FALSE + if(IS_NINJA_SUIT_STATUS(action)) + ninjastatus() return TRUE - if(istype(action, /datum/action/item_action/ninjaboost)) + if(IS_NINJA_SUIT_BOOST(action)) ninjaboost() return TRUE - if(istype(action, /datum/action/item_action/ninjapulse)) + if(IS_NINJA_SUIT_EMP(action)) ninjapulse() return TRUE - if(istype(action, /datum/action/item_action/ninjastar)) + if(IS_NINJA_SUIT_STAR_CREATION(action)) ninjastar() return TRUE - if(istype(action, /datum/action/item_action/ninjanet)) + if(IS_NINJA_SUIT_NET_CREATION(action)) ninjanet() return TRUE - if(istype(action, /datum/action/item_action/ninja_sword_recall)) + if(IS_NINJA_SUIT_SWORD_RECALL(action)) 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() + 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" + + +/** + * Proc called to lock the important gear pieces onto space ninja's body. + * + * Called during the suit startup to lock all gear pieces onto space ninja. + * Terminates if a gear piece is not being worn. Also gives the ninja the inability to use firearms. + * If the person in the suit isn't a ninja when this is called, this proc just gibs them instead. + * Arguments: + * * ninja - The person wearing the suit. + * * Returns false if the locking fails due to lack of all suit parts, and true if it succeeds. + */ +/obj/item/clothing/suit/space/space_ninja/proc/lock_suit(mob/living/carbon/human/ninja) + if(!istype(ninja)) + return FALSE + if(!IS_SPACE_NINJA(ninja)) + to_chat(ninja, "fÄTaL ÈÈRRoR: 382200-*#00CÖDE RED\nUNAU†HORIZED USÈ DETÈC†††eD\nCoMMÈNCING SUB-R0U†IN3 13...\nTÈRMInATING U-U-USÈR...") + ninja.gib() + return FALSE + if(!istype(ninja.head, /obj/item/clothing/head/helmet/space/space_ninja)) + to_chat(ninja, "ERROR: 100113 UNABLE TO LOCATE HEAD GEAR\nABORTING...") + return FALSE + 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(ninja.gloves, /obj/item/clothing/gloves/space_ninja)) + to_chat(ninja, "ERROR: 110223 UNABLE TO LOCATE HAND GEAR\nABORTING...") + return FALSE + affecting = ninja + ADD_TRAIT(src, TRAIT_NODROP, NINJA_SUIT_TRAIT) + n_hood = ninja.head + ADD_TRAIT(n_hood, TRAIT_NODROP, NINJA_SUIT_TRAIT) + n_shoes = ninja.shoes + ADD_TRAIT(n_shoes, TRAIT_NODROP, NINJA_SUIT_TRAIT) + n_shoes.slowdown-- + n_gloves = ninja.gloves + ADD_TRAIT(n_gloves, TRAIT_NODROP, NINJA_SUIT_TRAIT) + n_mask = ninja.wear_mask + + ADD_TRAIT(ninja, TRAIT_NOGUNS, NINJA_SUIT_TRAIT) + return TRUE + +/** + * Proc called to unlock all the gear off space ninja's body. + * + * Proc which is essentially the opposite of lock_suit. Lets you take off all the suit parts. + * Also gets rid of the objection to using firearms from the wearer. + * Arguments: + * * ninja - The person wearing the suit. + */ +/obj/item/clothing/suit/space/space_ninja/proc/unlock_suit(mob/living/carbon/human/ninja) + affecting = null + REMOVE_TRAIT(src, TRAIT_NODROP, NINJA_SUIT_TRAIT) + icon_state = "s-ninja" + if(n_hood)//Should be attached, might not be attached. + REMOVE_TRAIT(n_hood, TRAIT_NODROP, NINJA_SUIT_TRAIT) + n_hood.icon_state = "s-ninja" + if(n_shoes) + REMOVE_TRAIT(n_shoes, TRAIT_NODROP, NINJA_SUIT_TRAIT) + n_shoes.slowdown++ + if(n_gloves) + n_gloves.icon_state = "black" + REMOVE_TRAIT(n_gloves, TRAIT_NODROP, NINJA_SUIT_TRAIT) + 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" + +/** + * 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 fbad289fc32..f00d2f49750 100644 --- a/code/modules/ninja/suit/suit_attackby.dm +++ b/code/modules/ninja/suit/suit_attackby.dm @@ -1,39 +1,31 @@ - - -/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/uranium/radium, a_transfer) && a_boost < a_maxamount) - I.reagents.remove_reagent(/datum/reagent/uranium/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?.candrain) - to_chat(U, "Higher maximum capacity detected.\nUpgrading...") - if (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. @@ -44,15 +36,15 @@ has_research = TRUE break 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) qdel(TD.stored_research) TD.stored_research = new - 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 new research information detected.") + to_chat(ninja, "No new research information detected.") return return ..() diff --git a/icons/mob/clothing/feet.dmi b/icons/mob/clothing/feet.dmi index 5bee32e205c..c6f09b7840c 100644 Binary files a/icons/mob/clothing/feet.dmi and b/icons/mob/clothing/feet.dmi differ diff --git a/icons/mob/clothing/hands.dmi b/icons/mob/clothing/hands.dmi index 4fbe9361b5d..d14a35fccd0 100644 Binary files a/icons/mob/clothing/hands.dmi and b/icons/mob/clothing/hands.dmi differ diff --git a/icons/mob/clothing/head.dmi b/icons/mob/clothing/head.dmi index a350cafebe5..132bae640ac 100644 Binary files a/icons/mob/clothing/head.dmi and b/icons/mob/clothing/head.dmi differ diff --git a/icons/mob/clothing/mask.dmi b/icons/mob/clothing/mask.dmi index cda43a65cda..c8e171f9df9 100644 Binary files a/icons/mob/clothing/mask.dmi and b/icons/mob/clothing/mask.dmi differ diff --git a/icons/mob/clothing/suit.dmi b/icons/mob/clothing/suit.dmi index 3f13eb510a4..d5ba711fd59 100644 Binary files a/icons/mob/clothing/suit.dmi and b/icons/mob/clothing/suit.dmi differ diff --git a/icons/mob/inhands/weapons/swords_lefthand.dmi b/icons/mob/inhands/weapons/swords_lefthand.dmi index 1645ec66c8f..5057a666a48 100644 Binary files a/icons/mob/inhands/weapons/swords_lefthand.dmi and b/icons/mob/inhands/weapons/swords_lefthand.dmi differ diff --git a/icons/mob/inhands/weapons/swords_righthand.dmi b/icons/mob/inhands/weapons/swords_righthand.dmi index 7fd3b1daf58..db8aeaeb66b 100644 Binary files a/icons/mob/inhands/weapons/swords_righthand.dmi and b/icons/mob/inhands/weapons/swords_righthand.dmi differ diff --git a/icons/obj/clothing/gloves.dmi b/icons/obj/clothing/gloves.dmi index 86b52db72f0..1e38f1a8900 100644 Binary files a/icons/obj/clothing/gloves.dmi and b/icons/obj/clothing/gloves.dmi differ diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi index 97e3af4767a..df2caeccfd5 100644 Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ diff --git a/icons/obj/clothing/masks.dmi b/icons/obj/clothing/masks.dmi index 7bd01df740a..fb68a984646 100644 Binary files a/icons/obj/clothing/masks.dmi and b/icons/obj/clothing/masks.dmi differ diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi index a4b58489d6a..63e4ccc9c97 100644 Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ diff --git a/icons/obj/items_and_weapons.dmi b/icons/obj/items_and_weapons.dmi index 95f6288b2a3..88772a52b34 100644 Binary files a/icons/obj/items_and_weapons.dmi and b/icons/obj/items_and_weapons.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 9b1f2937a59..554112ee8ab 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -391,7 +391,6 @@ #include "code\datums\achievements\misc_achievements.dm" #include "code\datums\achievements\skill_achievements.dm" #include "code\datums\actions\beam_rifle.dm" -#include "code\datums\actions\ninja.dm" #include "code\datums\atmosphere\_atmosphere.dm" #include "code\datums\atmosphere\planetary.dm" #include "code\datums\brain_damage\brain_trauma.dm" @@ -1542,7 +1541,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" @@ -1563,6 +1561,7 @@ #include "code\modules\antagonists\slaughter\slaughter_antag.dm" #include "code\modules\antagonists\slaughter\slaughterevent.dm" #include "code\modules\antagonists\space_dragon\space_dragon.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\traitor\datum_traitor.dm" @@ -1899,6 +1898,7 @@ #include "code\modules\events\shuttle_catastrophe.dm" #include "code\modules\events\shuttle_loan.dm" #include "code\modules\events\space_dragon.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" @@ -2595,7 +2595,7 @@ #include "code\modules\movespeed\modifiers\status_effects.dm" #include "code\modules\ninja\__ninjaDefines.dm" #include "code\modules\ninja\energy_katana.dm" -#include "code\modules\ninja\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" @@ -2604,16 +2604,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\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"