diff --git a/code/__DEFINES/configuration.dm b/code/__DEFINES/configuration.dm index 9915563cab..8c9b270f43 100644 --- a/code/__DEFINES/configuration.dm +++ b/code/__DEFINES/configuration.dm @@ -24,3 +24,11 @@ #define POLICYCONFIG_ON_PYROCLASTIC_SENTIENT "PYROCLASTIC_SLIME" /// Displayed to pAIs on spawn #define POLICYCONFIG_PAI "PAI_SPAWN" +/// displayed to lavaland elites on spawn, overriding the default if set +#define POLICYCONFIG_ELITE_SPAWN "ELITE_FAUNA_SPAWN" +/// displayed to lavaland elites on sentience potion, overriding the default if set +#define POLICYCONFIG_ELITE_SENTIENCE "ELITE_FAUNA_SENTIENCE" +/// displayed to lavaland elites on winning the fight, overriding the default if set +#define POLICYCONFIG_ELITE_WIN "ELITE_FAUNA_WIN" +/// displayed to prisoners on spawn, overriding the default if set +#define POLICYCONFIG_JOB_PRISONER "JOB_PRISONER" diff --git a/code/_globalvars/lists/typecache.dm b/code/_globalvars/lists/typecache.dm index 1ec3de0bc5..d380816bbf 100644 --- a/code/_globalvars/lists/typecache.dm +++ b/code/_globalvars/lists/typecache.dm @@ -12,3 +12,16 @@ GLOBAL_LIST_INIT(typecache_stack, typecacheof(/obj/item/stack)) GLOBAL_LIST_INIT(typecache_machine_or_structure, typecacheof(list(/obj/machinery, /obj/structure))) GLOBAL_LIST_INIT(freezing_objects, typecacheof(list(/obj/structure/closet/crate/freezer, /obj/structure/closet/secure_closet/freezer, /obj/structure/bodycontainer, /obj/item/autosurgeon, /obj/machinery/smartfridge/organ))) //list of all cold objects, that freeze organs when inside + +GLOBAL_LIST_EMPTY(typecaches) + +/** + * Makes a typecache of a single typecache + * + * Obviously in BYOND we don't have the efficiency around here to have proper enforcement so + * If you use this you better know what you're doing. The list you get back is globally cached and if it's modified, you might break multiple things. + */ +/proc/single_path_typecache_immutable(path) + if(!GLOB.typecaches[path]) + GLOB.typecaches[path] = typecacheof(path) + return GLOB.typecaches[path] diff --git a/code/datums/actions/ninja.dm b/code/datums/actions/ninja.dm deleted file mode 100644 index c0314b9c48..0000000000 --- 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 - 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' - required_mobility_flags = NONE - -/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/area/areas/ruins/_ruins.dm b/code/game/area/areas/ruins/_ruins.dm index 17ba4f7721..6699e94129 100644 --- a/code/game/area/areas/ruins/_ruins.dm +++ b/code/game/area/areas/ruins/_ruins.dm @@ -8,6 +8,7 @@ dynamic_lighting = DYNAMIC_LIGHTING_FORCED ambientsounds = RUINS sound_environment = SOUND_ENVIRONMENT_STONEROOM + var/valid_territory = FALSE // hey so what if we did not allow things like cult summons to appear on ruins /area/ruin/unpowered diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index 7ce6e74cc1..61732b30eb 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -669,7 +669,6 @@ var/mob/living/carbon/human/Ninja = create_space_ninja(spawn_loc) Mind.transfer_to(Ninja) var/datum/antagonist/ninja/ninjadatum = new - ninjadatum.helping_station = pick(TRUE,FALSE) Mind.add_antag_datum(ninjadatum) if(Ninja.mind != Mind) //something has gone wrong! diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 133fec28b3..e05991dd8a 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -582,3 +582,14 @@ Class Procs: /obj/machinery/rust_heretic_act() take_damage(500, BRUTE, "melee", 1) + +/** + * Alerts the AI that a hack is in progress. + * + * Sends all AIs a message that a hack is occurring. Specifically used for space ninja tampering as this proc was originally in the ninja files. + * However, the proc may also be used elsewhere. + */ +/obj/machinery/proc/AI_notify_hack() + var/alertstr = "Network Alert: Hacking attempt detected[get_area(src)?" in [get_area_name(src, TRUE)]":". Unable to pinpoint location"]." + for(var/mob/living/silicon/ai/AI in GLOB.player_list) + to_chat(AI, alertstr) diff --git a/code/game/objects/items/dice.dm b/code/game/objects/items/dice.dm index bbc493672f..53b0860def 100644 --- a/code/game/objects/items/dice.dm +++ b/code/game/objects/items/dice.dm @@ -17,6 +17,11 @@ /obj/item/dice/d100 ) +/obj/item/storage/dice/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.can_hold = single_path_typecache_immutable(/obj/item/dice) + /obj/item/storage/dice/PopulateContents() new /obj/item/dice/d4(src) new /obj/item/dice/d6(src) diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index fe63e313de..902b1eaa13 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -615,9 +615,9 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 name = "throwing star" desc = "An ancient weapon still used to this day, due to its ease of lodging itself into its victim's body parts." icon_state = "throwingstar" - item_state = "eshield0" - lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi' + item_state = "throwingstar" + lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' force = 2 throwforce = 10 //10 + 2 (WEIGHT_CLASS_SMALL) * 4 (EMBEDDED_IMPACT_PAIN_MULTIPLIER) = 18 damage on hit due to guaranteed embedding throw_speed = 4 @@ -630,8 +630,10 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 resistance_flags = FIRE_PROOF /obj/item/throwing_star/stamina - name = "shock throwing star" + name = "energy throwing star" desc = "An aerodynamic disc designed to cause excruciating pain when stuck inside fleeing targets, hopefully without causing fatal harm." + icon_state = "energystar" + item_state = "energystar" throwforce = 5 embedding = list("pain_chance" = 5, "embed_chance" = 100, "fall_chance" = 0, "jostle_chance" = 10, "pain_stam_pct" = 0.8, "jostle_pain_mult" = 3) diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index 78a5c9ece9..15fd102878 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -22,7 +22,7 @@ //returns the damage value of the attack after processing the obj's various armor protections /obj/proc/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir, armour_penetration = 0) - if(damage_flag == MELEE && damage_amount < damage_deflection) + if(damage_flag == "melee" && damage_amount < damage_deflection) // TODO: Refactor armor datums and types entirely jfc return 0 switch(damage_type) if(BRUTE) diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm index 2379ee22bc..6c43d61cce 100644 --- a/code/modules/admin/verbs/one_click_antag.dm +++ b/code/modules/admin/verbs/one_click_antag.dm @@ -266,8 +266,8 @@ return TRUE /datum/admins/proc/makeSpaceNinja() - new /datum/round_event/ghost_role/ninja() - return 1 + new /datum/round_event/ghost_role/space_ninja() + return TRUE // DEATH SQUADS /datum/admins/proc/makeDeathsquad() diff --git a/code/modules/antagonists/ninja/ninja.dm b/code/modules/antagonists/ninja/ninja.dm deleted file mode 100644 index 414f7dd6b0..0000000000 --- a/code/modules/antagonists/ninja/ninja.dm +++ /dev/null @@ -1,146 +0,0 @@ -/datum/antagonist/ninja - name = "Ninja" - antagpanel_category = "Ninja" - job_rank = ROLE_NINJA - show_name_in_check_antagonists = TRUE - show_to_ghosts = TRUE - antag_moodlet = /datum/mood_event/focused - threat = 8 - var/helping_station = FALSE - var/give_objectives = TRUE - var/give_equipment = TRUE - -/datum/antagonist/ninja/threat() - return helping_station ? -(..()) : ..() - -/datum/antagonist/ninja/apply_innate_effects(mob/living/mob_override) - var/mob/living/M = mob_override || owner.current - update_ninja_icons_added(M) - -/datum/antagonist/ninja/remove_innate_effects(mob/living/mob_override) - var/mob/living/M = mob_override || owner.current - update_ninja_icons_removed(M) - -/datum/antagonist/ninja/proc/equip_space_ninja(mob/living/carbon/human/H = owner.current) - return H.equipOutfit(/datum/outfit/ninja) - -/datum/antagonist/ninja/proc/addMemories() - antag_memory += "I am an elite mercenary assassin of the mighty Spider Clan. A SPACE NINJA!
" - antag_memory += "Surprise is my weapon. Shadows are my armor. Without them, I am nothing. (//initialize your suit by clicking the initialize UI button, to use abilities like stealth)!
" - antag_memory += "Officially, [helping_station?"Nanotrasen":"The Syndicate"] are my employer.
" - -/datum/antagonist/ninja/proc/addObjectives(quantity = 6) - var/list/possible_targets = list() - for(var/datum/mind/M in SSticker.minds) - if(M.current && M.current.stat != DEAD) - if(ishuman(M.current)) - if(M.special_role) - possible_targets[M] = 0 //bad-guy - else if(M.assigned_role in GLOB.command_positions) - possible_targets[M] = 1 //good-guy - - var/list/possible_objectives = list(1,2,3,4) - - while(objectives.len < quantity) - switch(pick_n_take(possible_objectives)) - if(1) //research - var/datum/objective/download/O = new /datum/objective/download() - O.owner = owner - O.gen_amount_goal() - objectives += O - - if(2) //steal - var/datum/objective/steal/special/O = new /datum/objective/steal/special() - O.owner = owner - O.find_target() - objectives += O - - if(3) //protect/kill - if(!possible_targets.len) continue - var/index = rand(1,possible_targets.len) - var/datum/mind/M = possible_targets[index] - var/is_bad_guy = possible_targets[M] - possible_targets.Cut(index,index+1) - - if(is_bad_guy ^ helping_station) //kill (good-ninja + bad-guy or bad-ninja + good-guy) - var/datum/objective/assassinate/once/O = new /datum/objective/assassinate() - O.owner = owner - O.target = M - O.explanation_text = "Slay \the [M.current.real_name], the [M.assigned_role]. You may let [M.p_they()] live, if they come back from death." - objectives += O - else //protect - var/datum/objective/protect/O = new /datum/objective/protect() - O.owner = owner - O.target = M - O.explanation_text = "Protect \the [M.current.real_name], the [M.assigned_role], from harm." - objectives += O - if(4) //flavor - var/datum/objective/flavor/O = helping_station ? new /datum/objective/flavor/ninja_helping : new /datum/objective/flavor/ninja_syndie - O.owner = owner - O.forge_objective() - objectives += O - else - break - var/datum/objective/O = new /datum/objective/survive() - O.owner = owner - objectives += O - -/proc/remove_ninja(mob/living/L) - if(!L || !L.mind) - return FALSE - var/datum/antagonist/datum = L.mind.has_antag_datum(/datum/antagonist/ninja) - datum.on_removal() - return TRUE - -/proc/is_ninja(mob/living/M) - return M && M.mind && M.mind.has_antag_datum(/datum/antagonist/ninja) - - -/datum/antagonist/ninja/greet() - SEND_SOUND(owner.current, sound('sound/effects/ninja_greeting.ogg')) - to_chat(owner.current, "I am an elite mercenary assassin of the mighty Spider Clan. A SPACE NINJA!") - to_chat(owner.current, "Surprise is my weapon. Shadows are my armor. Without them, I am nothing. (//initialize your suit by right clicking on it, to use abilities like stealth)!") - to_chat(owner.current, "Officially, [helping_station?"Nanotrasen":"The Syndicate"] are my employer.") - owner.announce_objectives() - return - -/datum/antagonist/ninja/on_gain() - if(give_objectives) - addObjectives() - addMemories() - if(give_equipment) - equip_space_ninja(owner.current) - . = ..() - -/datum/antagonist/ninja/admin_add(datum/mind/new_owner,mob/admin) - var/adj - switch(input("What kind of ninja?", "Ninja") as null|anything in list("Random","Syndicate","Nanotrasen","No objectives")) - if("Random") - helping_station = pick(TRUE,FALSE) - adj = "" - if("Syndicate") - helping_station = FALSE - adj = "syndie" - if("Nanotrasen") - helping_station = TRUE - adj = "friendly" - if("No objectives") - give_objectives = FALSE - adj = "objectiveless" - else - return - new_owner.assigned_role = ROLE_NINJA - new_owner.special_role = ROLE_NINJA - new_owner.add_antag_datum(src) - message_admins("[key_name_admin(admin)] has [adj] ninja'ed [new_owner.current].") - log_admin("[key_name(admin)] has [adj] ninja'ed [new_owner.current].") - -/datum/antagonist/ninja/proc/update_ninja_icons_added(var/mob/living/carbon/human/ninja) - var/datum/atom_hud/antag/ninjahud = GLOB.huds[ANTAG_HUD_NINJA] - ninjahud.join_hud(ninja) - set_antag_hud(ninja, "ninja") - -/datum/antagonist/ninja/proc/update_ninja_icons_removed(var/mob/living/carbon/human/ninja) - var/datum/atom_hud/antag/ninjahud = GLOB.huds[ANTAG_HUD_NINJA] - ninjahud.leave_hud(ninja) - set_antag_hud(ninja, null) diff --git a/code/modules/antagonists/nukeop/equipment/pinpointer.dm b/code/modules/antagonists/nukeop/equipment/pinpointer.dm index d3fe235f49..5b48951ed5 100644 --- a/code/modules/antagonists/nukeop/equipment/pinpointer.dm +++ b/code/modules/antagonists/nukeop/equipment/pinpointer.dm @@ -68,6 +68,11 @@ desc = "An integrated tracking device, jury-rigged to search for living Syndicate operatives." flags_1 = NONE +/obj/item/pinpointer/spider_cyborg // Cyborg pinpointers just look for a random space ninja. + name = "cyborg spider clan pinpointer" + desc = "An integrated tracking device, jury-rigged to search for living Spider Clan members." + flags_1 = NONE + /obj/item/pinpointer/syndicate_cyborg/Initialize() . = ..() @@ -85,3 +90,20 @@ if(closest_operative) target = closest_operative ..() + +/obj/item/pinpointer/spider_cyborg/Initialize() + . = ..() + ADD_TRAIT(src, TRAIT_NODROP, CYBORG_ITEM_TRAIT) + +/obj/item/pinpointer/spider_cyborg/scan_for_target() + target = null + var/list/possible_targets = list() + var/turf/here = get_turf(src) + for(var/V in get_antag_minds(/datum/antagonist/ninja)) + var/datum/mind/M = V + if(ishuman(M.current) && M.current.stat != DEAD) + possible_targets |= M.current + var/mob/living/closest_weeaboo = get_closest_atom(/mob/living/carbon/human, possible_targets, here) + if(closest_weeaboo) + target = closest_weeaboo + ..() diff --git a/code/modules/antagonists/space_ninja/space_ninja.dm b/code/modules/antagonists/space_ninja/space_ninja.dm new file mode 100644 index 0000000000..1deb37eb56 --- /dev/null +++ b/code/modules/antagonists/space_ninja/space_ninja.dm @@ -0,0 +1,131 @@ +/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 + +/proc/is_ninja(mob/living/M) + return M && M.mind && M.mind.has_antag_datum(/datum/antagonist/ninja) + +/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/clothing/glasses/phantomthief.dm b/code/modules/clothing/glasses/phantomthief.dm index 6d209ec695..ba3ea2830e 100644 --- a/code/modules/clothing/glasses/phantomthief.dm +++ b/code/modules/clothing/glasses/phantomthief.dm @@ -3,8 +3,8 @@ desc = "A cheap, Syndicate-branded paper face mask. They'll never see it coming." mob_overlay_icon = 'icons/mob/clothing/mask.dmi' icon = 'icons/obj/clothing/masks.dmi' - icon_state = "s-ninja" - item_state = "s-ninja" + icon_state = "ninjaOLD" + item_state = "ninjaOLD" /obj/item/clothing/glasses/phantomthief/ComponentInitialize() . = ..() diff --git a/code/modules/events/space_ninja.dm b/code/modules/events/space_ninja.dm new file mode 100644 index 0000000000..0a24fecd44 --- /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 = 15 + +/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/jobs/job_types/prisoner.dm b/code/modules/jobs/job_types/prisoner.dm index 2ad2f32537..48c7afe304 100644 --- a/code/modules/jobs/job_types/prisoner.dm +++ b/code/modules/jobs/job_types/prisoner.dm @@ -1,4 +1,4 @@ -datum/job/prisoner +/datum/job/prisoner title = "Prisoner" flag = PRISONER department_head = list("The Security Team") @@ -13,6 +13,15 @@ datum/job/prisoner display_order = JOB_DISPLAY_ORDER_PRISONER +/datum/job/prisoner/after_spawn(mob/living/carbon/human/H, mob/M) + var/list/policies = CONFIG_GET(keyed_list/policy) + var/policy = policies[POLICYCONFIG_JOB_PRISONER] + if(policy) + var/mob/found = (M?.client && M) || (H?.client && H) + to_chat(found, "
!!READ THIS!!
The following is server-specific policy configuration and overrides anything said above if conflicting.") + to_chat(found, "

") + to_chat(found, "[policy]") + /datum/outfit/job/prisoner name = "Prisoner" jobtype = /datum/job/prisoner diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index e3af31ae96..d13a0f1149 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -82,34 +82,6 @@ . += "" . += "Chemical Storage: [changeling.chem_charges]/[changeling.chem_storage]" . += "Absorbed DNA: [changeling.absorbedcount]" - //NINJACODE - if(istype(wear_suit, /obj/item/clothing/suit/space/space_ninja)) //Only display if actually a ninja. - var/obj/item/clothing/suit/space/space_ninja/SN = wear_suit - . += "SpiderOS Status: [SN.s_initialized ? "Initialized" : "Disabled"]" - . += "Current Time: [STATION_TIME_TIMESTAMP("hh:mm:ss", world.time)]" - if(SN.s_initialized) - //Suit gear - . += "Energy Charge: [round(SN.cell.charge/100)]%" - . += "Smoke Bombs: \Roman [SN.s_bombs]" - //Ninja status - . += "Fingerprints: [md5(dna.uni_identity)]" - . += "Unique Identity: [dna.unique_enzymes]" - . += "Overall Status: [stat > 1 ? "dead" : "[health]% healthy"]" - . += "Nutrition Status: [nutrition]" - . += "Oxygen Loss: [getOxyLoss()]" - . += "Toxin Levels: [getToxLoss()]" - . += "Burn Severity: [getFireLoss()]" - . += "Brute Trauma: [getBruteLoss()]" - . += "Radiation Levels: [radiation] rad" - . += "Body Temperature: [bodytemperature-T0C] degrees C ([bodytemperature*1.8-459.67] degrees F)" - - //Diseases - if(length(diseases)) - . += "Viruses:" - for(var/thing in diseases) - var/datum/disease/D = thing - . += "* [D.name], Type: [D.spread_text], Stage: [D.stage]/[D.max_stages], Possible Cure: [D.cure_text]" - /mob/living/carbon/human/show_inv(mob/user) user.set_machine(src) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 9658247da3..7ab826cae3 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -811,6 +811,32 @@ Help the operatives secure the disk at all costs!" set_module = /obj/item/robot_module/saboteur +/mob/living/silicon/robot/modules/syndicate/spider// used for space ninja and their cyborg hacking special objective + bubble_icon = "spider" + playstyle_string = "You are a Spider Clan assault cyborg!
\ + You are armed with powerful offensive tools to aid you in your mission: obey your ninja masters by any means necessary. \ + Your cyborg LMG will slowly produce ammunition from your power supply, and your pinpointer will find and locate fellow members of the Spider Clan." + set_module = /obj/item/robot_module/syndicate/spider + +/mob/living/silicon/robot/modules/syndicate_medical/spider// ditto + bubble_icon = "spider" + var/playstyle_string = "You are a Spider Clan medical cyborg!
\ + You are armed with powerful medical tools to aid you in your mission: obey your ninja masters by any means necessary. \ + Your hypospray will produce Restorative Nanites, a wonder-drug that will heal most types of bodily damages, including clone and brain damage. It also produces morphine for offense. \ + Your defibrillator paddles can revive allies through their hardsuits, or can be used on harm intent to shock enemies! \ + Your energy saw functions as a circular saw, but can be activated to deal more damage, and your pinpointer will find and locate fellow members of the Spider Clan." + set_module = /obj/item/robot_module/syndicate_medical/spider + +/mob/living/silicon/robot/modules/saboteur/spider// ditto + bubble_icon = "spider" + var/playstyle_string = "You are a Spider Clan saboteur cyborg!
\ + You are armed with robust engineering tools to aid you in your mission: obey your ninja masters by any means necessary. \ + Your destination tagger will allow you to stealthily traverse the disposal network across the station. \ + Your welder will can be used to repair yourself or any allied silicon units, while serving as an impromptu melee weapon. \ + Your cyborg chameleon projector allows you to assume the appearance and registered name of a Nanotrasen engineering borg, and undertake covert actions on the station, \ + be aware that almost any physical contact or incidental damage will break your camouflage." + set_module = /obj/item/robot_module/saboteur/spider + /mob/living/silicon/robot/proc/notify_ai(notifytype, oldname, newname) if(!connected_ai) return diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 7ecc714b56..b9c6f4e2c4 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -1034,6 +1034,7 @@ /obj/item/extinguisher/mini, /obj/item/crowbar/cyborg, /obj/item/reagent_containers/borghypo/syndicate, + /obj/item/gripper/medical, /obj/item/shockpaddles/syndicate, /obj/item/healthanalyzer/advanced, /obj/item/surgical_drapes/advanced, @@ -1147,3 +1148,73 @@ max_energy = 30 recharge_rate = 1 name = "Wrapping Paper Storage" + +/obj/item/robot_module/syndicate/spider// used for space ninja and their cyborg hacking special objective + name = "Spider Assault" + basic_modules = list( + /obj/item/assembly/flash/cyborg, + /obj/item/extinguisher/mini, + /obj/item/crowbar/cyborg, + /obj/item/melee/transforming/energy/sword/cyborg, + /obj/item/gun/energy/printer, + /obj/item/pinpointer/spider_cyborg) + + cyborg_base_icon = "spider_sec" + +/obj/item/robot_module/syndicate_medical/spider// ditto + name = "Spider Medical" + basic_modules = list( + /obj/item/assembly/flash/cyborg, + /obj/item/extinguisher/mini, + /obj/item/crowbar/cyborg, + /obj/item/reagent_containers/borghypo/syndicate, + /obj/item/gripper/medical, + /obj/item/shockpaddles/syndicate, + /obj/item/healthanalyzer/advanced, + /obj/item/surgical_drapes/advanced, + /obj/item/retractor, + /obj/item/hemostat, + /obj/item/cautery, + /obj/item/surgicaldrill, + /obj/item/scalpel, + /obj/item/bonesetter, + /obj/item/stack/medical/bone_gel, + /obj/item/melee/transforming/energy/sword/cyborg/saw, + /obj/item/roller/robo, + /obj/item/stack/medical/gauze/cyborg, + /obj/item/gun/medbeam, + /obj/item/organ_storage, + /obj/item/pinpointer/spider_cyborg) + + cyborg_base_icon = "spider_medical" + +/obj/item/robot_module/saboteur/spider// ditto + name = "Spider Saboteur" + basic_modules = list( + /obj/item/assembly/flash/cyborg, + /obj/item/borg/sight/thermal, + /obj/item/construction/rcd/borg/syndicate, + /obj/item/pipe_dispenser, + /obj/item/restraints/handcuffs/cable/zipties, + /obj/item/extinguisher, + /obj/item/weldingtool/largetank/cyborg, + /obj/item/screwdriver/nuke, + /obj/item/wrench/cyborg, + /obj/item/crowbar/cyborg, + /obj/item/wirecutters/cyborg, + /obj/item/multitool/cyborg, + /obj/item/storage/part_replacer/cyborg, + /obj/item/holosign_creator/atmos, + /obj/item/gripper, + /obj/item/lightreplacer/cyborg, + /obj/item/stack/sheet/metal/cyborg, + /obj/item/stack/sheet/glass/cyborg, + /obj/item/stack/sheet/rglass/cyborg, + /obj/item/stack/rods/cyborg, + /obj/item/stack/tile/plasteel/cyborg, + /obj/item/destTagger/borg, + /obj/item/stack/cable_coil/cyborg, + /obj/item/borg_chameleon, + /obj/item/pinpointer/spider_cyborg) + + cyborg_base_icon = "spider_engi" diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm index d677f59440..de6b858f79 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm @@ -176,6 +176,12 @@ While using this makes the system rely on OnFire, it still gives options for tim elitemind = pick(candidates) elitemind.playsound_local(get_turf(elitemind), 'sound/effects/magic.ogg', 40, 0) to_chat(elitemind, "You have been chosen to play as a Lavaland Elite.\nIn a few seconds, you will be summoned on Lavaland as a monster to fight your activator, in a fight to the death.\nYour attacks can be switched using the buttons on the top left of the HUD, and used by clicking on targets or tiles similar to a gun.\nWhile the opponent might have an upper hand with powerful mining equipment and tools, you have great power normally limited by AI mobs.\nIf you want to win, you'll have to use your powers in creative ways to ensure the kill. It's suggested you try using them all as soon as possible.\nShould you win, you'll receive extra information regarding what to do after. Good luck!") + var/list/policies = CONFIG_GET(keyed_list/policy) + var/policy = policies[POLICYCONFIG_ELITE_SPAWN] + if(policy) + to_chat(elitemind, "
!!READ THIS!!
The following is server-specific policy configuration and overrides anything said above if conflicting.") + to_chat(elitemind, "

") + to_chat(elitemind, "[policy]") addtimer(CALLBACK(src, .proc/spawn_elite, elitemind), 100) else visible_message("The stirring stops, and nothing emerges. Perhaps try again later.") @@ -304,6 +310,12 @@ While using this makes the system rely on OnFire, it still gives options for tim to_chat(mychild, "As the life in the activator's eyes fade, the forcefield around you dies out and you feel your power subside.\nDespite this inferno being your home, you feel as if you aren't welcome here anymore.\nWithout any guidance, your purpose is now for you to decide.") to_chat(mychild, "Your max health has been halved, but can now heal by standing on your tumor. Note, it's your only way to heal.\nBear in mind, if anyone interacts with your tumor, you'll be resummoned here to carry out another fight. In such a case, you will regain your full max health.\nAlso, be weary of your fellow inhabitants, they likely won't be happy to see you!") to_chat(mychild, "Note that you are a lavaland monster, and thus not allied to the station. You should not cooperate or act friendly with any station crew unless under extreme circumstances!") + var/list/policies = CONFIG_GET(keyed_list/policy) + var/policy = policies[POLICYCONFIG_ELITE_WIN] + if(policy) + to_chat(mychild, "
!!READ THIS!!
The following is server-specific policy configuration and overrides anything said above if conflicting.") + to_chat(mychild, "

") + to_chat(mychild, "[policy]") /obj/item/tumor_shard name = "tumor shard" @@ -332,6 +344,12 @@ While using this makes the system rely on OnFire, it still gives options for tim E.playsound_local(get_turf(E), 'sound/effects/magic.ogg', 40, 0) to_chat(E, "You have been revived by [user]. While you can't speak to them, you owe [user] a great debt. Assist [user.p_them()] in achieving [user.p_their()] goals, regardless of risk.Note that you now share the loyalties of [user]. You are expected not to intentionally sabotage their faction unless commanded to!") + var/list/policies = CONFIG_GET(keyed_list/policy) + var/policy = policies[POLICYCONFIG_ELITE_SENTIENCE] + if(policy) + to_chat(E, "
!!READ THIS!!
The following is server-specific policy configuration and overrides anything said above if conflicting.") + to_chat(E, "

") + to_chat(E, "[policy]") E.maxHealth = E.maxHealth * 0.5 E.health = E.maxHealth E.desc = "[E.desc] However, this one appears appears less wild in nature, and calmer around people." diff --git a/code/modules/movespeed/modifiers/mobs.dm b/code/modules/movespeed/modifiers/mobs.dm index 7e857a4e0d..153d7dd973 100644 --- a/code/modules/movespeed/modifiers/mobs.dm +++ b/code/modules/movespeed/modifiers/mobs.dm @@ -113,6 +113,7 @@ multiplicative_slowdown = CRAWLING_ADD_SLOWDOWN movetypes = CRAWLING flags = IGNORE_NOSLOW + priority = 20000 /datum/movespeed_modifier/mob_config_speedmod variable = TRUE diff --git a/code/modules/ninja/__ninjaDefines.dm b/code/modules/ninja/__ninjaDefines.dm index d6cdb55840..3f5db48407 100644 --- a/code/modules/ninja/__ninjaDefines.dm +++ b/code/modules/ninja/__ninjaDefines.dm @@ -1,23 +1,24 @@ - -/* - -Contents: -- Definitions, because the original Ninja code has so much magic. - -*/ - - //ninjacost() specificCheck defines #define N_STEALTH_CANCEL 1 -#define N_SMOKE_BOMB 2 -#define N_ADRENALINE 3 +#define N_ADRENALINE 2 //ninjaDrainAct() defines for non numerical returns -//While not strictly needed, it's nicer than them just returning "twat" -//Which was my original intention. #define INVALID_DRAIN "INVALID" //This one is if the drain proc needs to cancel, eg missing variables, etc, it's important. - #define DRAIN_RD_HACK_FAILED "RDHACKFAIL" #define DRAIN_MOB_SHOCK "MOBSHOCK" #define DRAIN_MOB_SHOCK_FAILED "MOBSHOCKFAIL" + + +//Tells whether or not someone is a space ninja +#define IS_SPACE_NINJA(ninja) (ninja.mind && ninja.mind.has_antag_datum(/datum/antagonist/ninja)) + +//Defines for the suit's unique abilities +#define IS_NINJA_SUIT_INITIALIZATION(action) (istype(action, /datum/action/item_action/initialize_ninja_suit)) +#define IS_NINJA_SUIT_STATUS(action) (istype(action, /datum/action/item_action/ninjastatus)) +#define IS_NINJA_SUIT_BOOST(action) (istype(action, /datum/action/item_action/ninjaboost)) +#define IS_NINJA_SUIT_EMP(action) (istype(action, /datum/action/item_action/ninjapulse)) +#define IS_NINJA_SUIT_STAR_CREATION(action) (istype(action, /datum/action/item_action/ninjastar)) +#define IS_NINJA_SUIT_NET_CREATION(action) (istype(action, /datum/action/item_action/ninjanet)) +#define IS_NINJA_SUIT_SWORD_RECALL(action) (istype(action, /datum/action/item_action/ninja_sword_recall)) +#define IS_NINJA_SUIT_STEALTH(action) (istype(action, /datum/action/item_action/ninja_stealth)) diff --git a/code/modules/ninja/energy_katana.dm b/code/modules/ninja/energy_katana.dm index 00cfa94893..cf895924b0 100644 --- a/code/modules/ninja/energy_katana.dm +++ b/code/modules/ninja/energy_katana.dm @@ -1,3 +1,14 @@ +/** + * # Energy Katana + * + * The space ninja's katana. + * + * The katana that only space ninja spawns with. Comes with 30 force and throwforce, along with a signature special jaunting system. + * Upon clicking on a tile with the dash on, the user will teleport to that tile, assuming their target was not dense. + * The katana has 3 dashes stored at maximum, and upon using the dash, it will return 20 seconds after it was used. + * It also has a special feature where if it is tossed at a space ninja who owns it (determined by the ninja suit), the ninja will catch the katana instead of being hit by it. + * + */ /obj/item/energy_katana name = "energy katana" desc = "A katana infused with strong energy." @@ -5,16 +16,16 @@ item_state = "energy_katana" lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' - force = 40 - throwforce = 20 + force = 30 + throwforce = 30 block_chance = 50 armour_penetration = 50 w_class = WEIGHT_CLASS_NORMAL hitsound = 'sound/weapons/bladeslice.ogg' attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") - block_chance = 50 slot_flags = ITEM_SLOT_BELT sharpness = SHARP_EDGED + obj_flags = UNIQUE_RENAME // here is a shitpost and i cannot wait for ninjas naming their sword very rude things max_integrity = 200 resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF var/datum/effect_system/spark_spread/spark_system @@ -34,13 +45,19 @@ /obj/item/energy_katana/afterattack(atom/target, mob/user, proximity_flag, click_parameters) . = ..() - if(dash_toggled) - jaunt.Teleport(user, target) - if(proximity_flag && (isobj(target) || issilicon(target))) - spark_system.start() - playsound(user, "sparks", 50, 1) - playsound(user, 'sound/weapons/blade1.ogg', 50, 1) - target.emag_act(user) + if(!ishuman(user)) + return + var/mob/living/carbon/human/H = user + var/obj/item/clothing/suit/space/space_ninja/ninja_suit = H.wear_suit + if(!istype(ninja_suit))// do you actually have a ninja suit on + to_chat(user, "ERROR: garments incompatible with carbon material jaunt. Please suit up in compatible garments.") + return + if(!dash_toggled || Adjacent(target) || target.density)// is where you are going not a wall + return + if(!ninja_suit.s_coold == 0)// are you not currently on the ability cooldown + to_chat(user, "ERROR: suit is on cooldown.") + return + jaunt.Teleport(user, target)// okay you can now go my good sir /obj/item/energy_katana/pickup(mob/living/user) . = ..() @@ -58,16 +75,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)) @@ -94,13 +125,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 = 30 + charge_rate = 200 recharge_sound = null diff --git a/code/modules/ninja/ninja_event.dm b/code/modules/ninja/ninja_event.dm deleted file mode 100644 index bc3c445731..0000000000 --- a/code/modules/ninja/ninja_event.dm +++ /dev/null @@ -1,93 +0,0 @@ -//Note to future generations: I didn't write this god-awful code I just ported it to the event system and tried to make it less moon-speaky. -//Don't judge me D; ~Carn //Maximum judging occuring - Remie. -// Tut tut Remie, let's keep our comments constructive. - coiax - -/* - -Contents: -- The Ninja "Random" Event -- Ninja creation code -*/ - -/datum/round_event_control/ninja - name = "Space Ninja" - typepath = /datum/round_event/ghost_role/ninja - max_occurrences = 1 - earliest_start = 40 MINUTES - gamemode_blacklist = list("dynamic") - min_players = 15 - -/datum/round_event/ghost_role/ninja - var/success_spawn = 0 - role_name = "space ninja" - minimum_required = 1 - - var/helping_station - var/spawn_loc - var/give_objectives = TRUE - -/datum/round_event/ghost_role/ninja/setup() - helping_station = rand(0,1) - -/datum/round_event/ghost_role/ninja/kill() - if(!success_spawn && control) - control.occurrences-- - return ..() - -/datum/round_event/ghost_role/ninja/spawn_role() - //selecting a spawn_loc - if(!spawn_loc) - var/list/spawn_locs = list() - for(var/obj/effect/landmark/carpspawn/L in GLOB.landmarks_list) - if(isturf(L.loc)) - spawn_locs += L.loc - for(var/obj/effect/landmark/loneopspawn/L in GLOB.landmarks_list) - if(isturf(L.loc)) - spawn_locs += L.loc - if(!spawn_locs.len) - return kill() - spawn_loc = pick(spawn_locs) - if(!spawn_loc) - return MAP_ERROR - - //selecting a candidate player - var/list/candidates = get_candidates(ROLE_NINJA, null, ROLE_NINJA) - if(!candidates.len) - return NOT_ENOUGH_PLAYERS - - var/mob/dead/selected_candidate = pick_n_take(candidates) - var/key = selected_candidate.key - - //Prepare ninja player mind - var/datum/mind/Mind = new /datum/mind(key) - Mind.assigned_role = ROLE_NINJA - Mind.special_role = ROLE_NINJA - Mind.active = 1 - - //spawn the ninja and assign the candidate - var/mob/living/carbon/human/Ninja = create_space_ninja(spawn_loc) - Mind.transfer_to(Ninja) - var/datum/antagonist/ninja/ninjadatum = new - ninjadatum.helping_station = pick(TRUE,FALSE) - Mind.add_antag_datum(ninjadatum) - - if(Ninja.mind != Mind) //something has gone wrong! - stack_trace("Ninja created with incorrect mind") - - spawned_mobs += Ninja - message_admins("[ADMIN_LOOKUPFLW(Ninja)] has been made into a ninja by an event.") - log_game("[key_name(Ninja)] was spawned as a ninja by an event.") - success_spawn = TRUE - - return SUCCESSFUL_SPAWN - - -//=======//NINJA CREATION PROCS//=======// - -/proc/create_space_ninja(spawn_loc) - var/mob/living/carbon/human/new_ninja = new(spawn_loc) - var/datum/preferences/A = new()//Randomize appearance for the ninja. - A.real_name = "[pick(GLOB.ninja_titles)] [pick(GLOB.ninja_names)]" - A.copy_to(new_ninja) - new_ninja.dna.update_dna_identity() - return new_ninja diff --git a/code/modules/ninja/ninja_explosive.dm b/code/modules/ninja/ninja_explosive.dm new file mode 100644 index 0000000000..e87ff2b6d6 --- /dev/null +++ b/code/modules/ninja/ninja_explosive.dm @@ -0,0 +1,45 @@ +/** + * # Spider Charge + * + * A unique version of c4 possessed only by the space ninja. Has a stronger blast radius. + * Can only be detonated by space ninjas with the bombing objective. Can only be set up where the objective says it can. + * When it primes, the space ninja responsible will have their objective set to complete. + * + */ +/obj/item/grenade/plastic/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." + icon_state = "plasticspider0" + item_state = "plasticspider" + boom_sizes = list(2, 4, 6) + var/mob/detonator = null + +/obj/item/grenade/plastic/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, "You fiddle with the charge, but nothing happens.") + 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/plastic/c4/ninja/prime(mob/living/lanced_by) + . = ..() + anchored = TRUE + //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 + +/obj/item/grenade/plastic/c4/ninja/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/screwdriver)) + to_chat(user, "The wire panel is locked in place, clearly you aren't supposed to be opening it!") + return diff --git a/code/modules/ninja/outfit.dm b/code/modules/ninja/outfit.dm index 983ef0585a..a6faa9a3d5 100644 --- a/code/modules/ninja/outfit.dm +++ b/code/modules/ninja/outfit.dm @@ -8,10 +8,10 @@ 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/plastic/x4 - r_pocket = /obj/item/tank/internals/emergency_oxygen - internals_slot = SLOT_R_STORE + l_pocket = /obj/item/grenade/plastic/c4/ninja + r_pocket = /obj/item/hypospray/mkii/CMO/combat + suit_store = /obj/item/tank/internals/oxygen + internals_slot = SLOT_S_STORE belt = /obj/item/energy_katana implants = list(/obj/item/implant/explosive) @@ -21,5 +21,3 @@ var/obj/item/clothing/suit/space/space_ninja/S = H.wear_suit if(istype(H.belt, belt)) S.energyKatana = H.belt - S.randomize_param() - diff --git a/code/modules/ninja/suit/gloves.dm b/code/modules/ninja/suit/gloves.dm index a06b753402..15abf0936e 100644 --- a/code/modules/ninja/suit/gloves.dm +++ b/code/modules/ninja/suit/gloves.dm @@ -1,25 +1,13 @@ - - - -/* - 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" @@ -32,11 +20,24 @@ max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT strip_delay = 120 resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF - var/draining = 0 - var/candrain = 0 + actions_types = list(/datum/action/item_action/toggle_glove) + var/datum/action/innate/doorjack/ninja/hack + ///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 security console hack was used to set everyone to arrest + var/security_console_hack_success = FALSE + ///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 + ///Whether or not the cyborg hack was used to syndify a cyborg + var/borg_hack_success = FALSE var/stunforce = 100 /obj/item/clothing/gloves/space_ninja/Touch(atom/A,proximity) @@ -45,9 +46,9 @@ if(!ishuman(loc)) return FALSE //Only works while worn - var/mob/living/carbon/human/H = loc + var/mob/living/carbon/human/wearer = loc - var/obj/item/clothing/suit/space/space_ninja/suit = H.wear_suit + var/obj/item/clothing/suit/space/space_ninja/suit = wearer.wear_suit if(!istype(suit)) return FALSE if(isturf(A)) @@ -56,17 +57,17 @@ if(!proximity) return FALSE - A.add_fingerprint(H) + A.add_fingerprint(wearer) draining = TRUE - . = A.ninjadrain_act(suit,H,src) + . = A.ninjadrain_act(suit,wearer,src) draining = FALSE if(isnum(.)) //Numerical values of drained handle their feedback here, Alpha values handle it themselves (Research hacking) if(.) - to_chat(H, "Gained [DisplayEnergy(.)] of energy from [A].") + to_chat(wearer, "Gained [DisplayEnergy(.)] of energy from [A].") else - to_chat(H, "\The [A] has run dry of energy, you must find another source!") + to_chat(wearer, "\The [A] has run dry of energy, you must find another source!") . = INTERRUPT_UNARMED_ATTACK else . = FALSE //as to not cancel attack_hand() @@ -75,12 +76,13 @@ . = ..() REMOVE_TRAIT(src, TRAIT_NODROP, NINJA_SUIT_TRAIT) -/obj/item/clothing/gloves/space_ninja/proc/toggledrain() - var/mob/living/carbon/human/U = loc - to_chat(U, "You [candrain?"disable":"enable"] special interaction.") - candrain=!candrain - /obj/item/clothing/gloves/space_ninja/examine(mob/user) . = ..() if(HAS_TRAIT_FROM(src, TRAIT_NODROP, NINJA_SUIT_TRAIT)) . += "The energy drain mechanism is [candrain?"active":"inactive"]." + +/obj/item/clothing/gloves/space_ninja/ui_action_click(mob/user, action) + if(istype(action, /datum/action/item_action/toggle_glove)) + toggledrain() + return TRUE + return FALSE diff --git a/code/modules/ninja/suit/head.dm b/code/modules/ninja/suit/head.dm index 9a65dabc1e..99dde98f09 100644 --- a/code/modules/ninja/suit/head.dm +++ b/code/modules/ninja/suit/head.dm @@ -1,14 +1,19 @@ - - +/** + * # Ninja Hood + * + * Space ninja's hood. Provides armor and blocks AI tracking. + * + * A hood that only exists as a part of space ninja's starting kit. Provides armor equal of space ninja's suit and disallows an AI to track the wearer. + * + */ /obj/item/clothing/head/helmet/space/space_ninja desc = "What may appear to be a simple black garment is in fact a highly sophisticated nano-weave helmet. Standard issue ninja gear." name = "ninja hood" icon_state = "s-ninja" item_state = "s-ninja_mask" - armor = list("melee" = 60, "bullet" = 50, "laser" = 30,"energy" = 15, "bomb" = 30, "bio" = 30, "rad" = 25, "fire" = 100, "acid" = 100) - strip_delay = 12 + armor = list("melee" = 40, "bullet" = 30, "laser" = 20,"energy" = 30, "bomb" = 30, "bio" = 30, "rad" = 30, "fire" = 100, "acid" = 100) resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF - blockTracking = 1//Roughly the only unique thing about this helmet. + blockTracking = TRUE//Roughly the only unique thing about this helmet. flags_inv = HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR /obj/item/clothing/head/helmet/space/space_ninja/dropped(mob/user) diff --git a/code/modules/ninja/suit/mask.dm b/code/modules/ninja/suit/mask.dm index 421c13f9eb..111f76ae65 100644 --- a/code/modules/ninja/suit/mask.dm +++ b/code/modules/ninja/suit/mask.dm @@ -1,15 +1,11 @@ - -/* - -Contents: -- The Ninja Space Mask -- Ninja Space Mask speech modification - -*/ - - - - +/** + * # Ninja Mask + * + * Space ninja's mask. Makes you sound like a real anime girl. Barely able to be considered a real upside. + * + * A mask which only spawns as a part of space ninja's starting kit. Functions as a gas mask. + * + */ /obj/item/clothing/mask/gas/space_ninja name = "ninja mask" desc = "A close-fitting mask that acts both as an air filter and a post-modern fashion statement." diff --git a/code/modules/ninja/suit/n_suit_verbs/energy_net_nets.dm b/code/modules/ninja/suit/n_suit_verbs/energy_net_nets.dm deleted file mode 100644 index c0ee68cdee..0000000000 --- a/code/modules/ninja/suit/n_suit_verbs/energy_net_nets.dm +++ /dev/null @@ -1,117 +0,0 @@ -/* -It will teleport people to a holding facility after 30 seconds. (Check the process() proc to change where teleport goes) -It is possible to destroy the net by the occupant or someone else. -*/ - -/obj/structure/energy_net - name = "energy net" - desc = "It's a net made of green energy." - icon = 'icons/effects/effects.dmi' - icon_state = "energynet" - - density = TRUE//Can't pass through. - opacity = 0//Can see through. - mouse_opacity = MOUSE_OPACITY_ICON//So you can hit it with stuff. - anchored = TRUE//Can't drag/grab the net. - layer = ABOVE_ALL_MOB_LAYER - max_integrity = 50 //How much health it has. - can_buckle = 1 - buckle_lying = 0 - buckle_prevents_pull = TRUE - var/mob/living/carbon/affecting //Who it is currently affecting, if anyone. - var/mob/living/carbon/master //Who shot web. Will let this person know if the net was successful or failed. - var/check = 15//30 seconds before teleportation. Could be extended I guess. - var/success = FALSE - - -/obj/structure/energy_net/play_attack_sound(damage, damage_type = BRUTE, damage_flag = 0) - switch(damage_type) - if(BRUTE) - playsound(src, 'sound/weapons/slash.ogg', 80, 1) - if(BURN) - playsound(src, 'sound/weapons/slash.ogg', 80, 1) - -/obj/structure/energy_net/Destroy() - if(!success) - if(!QDELETED(affecting)) - affecting.visible_message("[affecting.name] was recovered from the energy net!", "You were recovered from the energy net!", "You hear a grunt.") - if(!QDELETED(master))//As long as they still exist. - to_chat(master, "ERROR: unable to initiate transport protocol. Procedure terminated.") - return ..() - -/obj/structure/energy_net/process() - if(QDELETED(affecting)||affecting.loc!=loc) - qdel(src)//Get rid of the net. - return - - if(check>0) - check-- - return - - success = TRUE - qdel(src) - if(ishuman(affecting)) - var/mob/living/carbon/human/H = affecting - for(var/obj/item/W in H) - if(W == H.w_uniform || W == H.shoes) - continue//So all they're left with are shoes and uniform. - H.dropItemToGround(W) - H.dna.species.give_important_for_life(H) // After we remove items, at least give them what they need to live. -/* - var/datum/antagonist/antag_datum - for(var/datum/antagonist/ninja/AD in GLOB.antagonists) //Because only ninjas get capture objectives; They're not doable without the suit. - if(AD.owner == master) - antag_datum = AD - break - for(var/datum/objective/capture/capture in antag_datum) - if(istype(affecting, /mob/living/carbon/human)) //Humans. - if(affecting.stat == DEAD)//Dead folks are worth less. - capture.captured_amount+=0.5 - continue - capture.captured_amount+=1 - if(istype(affecting, /mob/living/carbon/monkey)) //Monkeys are almost worthless, you failure. - capture.captured_amount+=0.1 - if(istype(affecting, /mob/living/carbon/alien/larva)) //Larva are important for research. - if(affecting.stat == DEAD) - capture.captured_amount+=0.5 - continue - capture.captured_amount+=1 - if(istype(affecting, /mob/living/carbon/alien/humanoid)) //Aliens are worth twice as much as humans. - if(istype(affecting, /mob/living/carbon/alien/humanoid/royal/queen)) //Queens are worth three times as much as humans. - if(affecting.stat == DEAD) - capture.captured_amount+=1.5 - else - capture.captured_amount+=3 - continue - if(affecting.stat == DEAD) - capture.captured_amount+=1 - continue - capture.captured_amount+=2 -*/ - - affecting.revive(1, 1) //Basically a revive and full heal, including limbs/organs - //In case people who have been captured dead want to hang out at the holding area - - playsound(affecting, 'sound/effects/sparks4.ogg', 50, 1) - new /obj/effect/temp_visual/dir_setting/ninja/phase/out(affecting.drop_location(), affecting.dir) - - visible_message("[affecting] suddenly vanishes!") - affecting.forceMove(pick(GLOB.holdingfacility)) //Throw mob in to the holding facility. - to_chat(affecting, "You appear in a strange place!") - - if(!QDELETED(master))//As long as they still exist. - to_chat(master, "SUCCESS: transport procedure of [affecting] complete.") - do_sparks(5, FALSE, affecting) - playsound(affecting, 'sound/effects/phasein.ogg', 25, 1) - playsound(affecting, 'sound/effects/sparks2.ogg', 50, 1) - new /obj/effect/temp_visual/dir_setting/ninja/phase(affecting.drop_location(), affecting.dir) - -/obj/structure/energy_net/attack_alien(mob/living/carbon/alien/humanoid/user) - if(attack_generic(user, 15, BRUTE, "melee", 0)) //Aliens normally deal 60 damage to structures. They'd one-shot nets without this. - playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1) - -/obj/structure/energy_net/user_buckle_mob(mob/living/M, mob/living/user) - return//We only want our target to be buckled - -/obj/structure/energy_net/user_unbuckle_mob(mob/living/buckled_mob, mob/living/user) - return//The net must be destroyed to free the target diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_adrenaline.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_adrenaline.dm deleted file mode 100644 index 89f5d20e70..0000000000 --- a/code/modules/ninja/suit/n_suit_verbs/ninja_adrenaline.dm +++ /dev/null @@ -1,19 +0,0 @@ -//Wakes the user so they are able to do their thing. Also injects a decent dose of radium. -//Movement impairing would indicate drugs and the like. -/obj/item/clothing/suit/space/space_ninja/proc/ninjaboost() - - if(!ninjacost(0,N_ADRENALINE)) - var/mob/living/carbon/human/H = affecting - H.do_adrenaline(150, TRUE, 0, 0, TRUE, list(/datum/reagent/medicine/inaprovaline = 3, /datum/reagent/medicine/synaptizine = 10, /datum/reagent/medicine/omnizine = 10), "You feel a sudden surge of energy!") - - H.say(pick("A CORNERED FOX IS MORE DANGEROUS THAN A JACKAL!","HURT ME MOOORRREEE!","IMPRESSIVE!"), forced = "ninjaboost") - - a_boost-- - to_chat(H, "There are [a_boost] adrenaline boosts remaining.") - s_coold = 3 - addtimer(CALLBACK(src, .proc/ninjaboost_after), 70) - -/obj/item/clothing/suit/space/space_ninja/proc/ninjaboost_after() - var/mob/living/carbon/human/H = affecting - H.reagents.add_reagent(/datum/reagent/radium, a_transfer) - to_chat(H, "You are beginning to feel the after-effect of the injection.") diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_cost_check.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_cost_check.dm deleted file mode 100644 index 12fea51815..0000000000 --- a/code/modules/ninja/suit/n_suit_verbs/ninja_cost_check.dm +++ /dev/null @@ -1,25 +0,0 @@ - - -//Cost function for suit Procs/Verbs/Abilities -/obj/item/clothing/suit/space/space_ninja/proc/ninjacost(cost = 0, specificCheck = 0) - var/mob/living/carbon/human/H = affecting - var/actualCost = cost*10 - if(cost && cell.charge < actualCost) - to_chat(H, "Not enough energy.") - return 1 - else - //This shit used to be handled individually on every proc.. why even bother with a universal check proc then? - cell.charge-=(actualCost) - - switch(specificCheck) - if(N_STEALTH_CANCEL) - cancel_stealth()//Get rid of it. - if(N_SMOKE_BOMB) - if(!s_bombs) - to_chat(H, "There are no more smoke bombs remaining.") - return 1 - if(N_ADRENALINE) - if(!a_boost) - to_chat(H, "You do not have any more adrenaline boosters.") - return 1 - return (s_coold)//Returns the value of the variable which counts down to zero. diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_empulse.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_empulse.dm deleted file mode 100644 index 29dc78e5f3..0000000000 --- a/code/modules/ninja/suit/n_suit_verbs/ninja_empulse.dm +++ /dev/null @@ -1,10 +0,0 @@ - - -//Disables nearby tech equipment. -/obj/item/clothing/suit/space/space_ninja/proc/ninjapulse() - - if(!ninjacost(250,N_STEALTH_CANCEL)) - var/mob/living/carbon/human/H = affecting - playsound(H.loc, 'sound/effects/empulse.ogg', 60, 2) - empulse_using_range(H, 9) //Procs sure are nice. Slightly weaker than wizard's disable tch. - s_coold = 2 diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_net.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_net.dm deleted file mode 100644 index 61355ca89b..0000000000 --- a/code/modules/ninja/suit/n_suit_verbs/ninja_net.dm +++ /dev/null @@ -1,44 +0,0 @@ - -//Allows the ninja to kidnap people -/obj/item/clothing/suit/space/space_ninja/proc/ninjanet() - var/mob/living/carbon/human/H = affecting - var/mob/living/carbon/C - - //If there's only one valid target, let's actually try to capture it, rather than forcing - //the user to fiddle with the dialog displaying a list of one - //Also, let's make this smarter and not list mobs you can't currently net. - var/list/candidates - for(var/mob/M in oview(H)) - if(!M.client)//Monkeys without a client can still step_to() and bypass the net. Also, netting inactive people is lame. - continue - for(var/obj/structure/energy_net/E in get_turf(M))//Check if they are already being affected by an energy net. - if(E.affecting == M) - continue - LAZYADD(candidates, M) - - if(!LAZYLEN(candidates)) - return FALSE - - if(candidates.len == 1) - C = candidates[1] - else - C = input("Select who to capture:","Capture who?",null) as null|mob in candidates - - - if(QDELETED(C)||!(C in oview(H))) - return FALSE - - if(!ninjacost(200,N_STEALTH_CANCEL)) - H.Beam(C,"n_beam",time=15) - H.say("Get over here!", forced = "ninja net") - var/obj/structure/energy_net/E = new /obj/structure/energy_net(C.drop_location()) - E.affecting = C - E.master = H - H.visible_message("[H] caught [C] with an energy net!","You caught [C] with an energy net!") - - if(C.buckled) - C.buckled.unbuckle_mob(affecting,TRUE) - E.buckle_mob(C, TRUE) //No moving for you! - //The person can still try and attack the net when inside. - - START_PROCESSING(SSobj, E) diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_smoke.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_smoke.dm deleted file mode 100644 index 3c19162048..0000000000 --- a/code/modules/ninja/suit/n_suit_verbs/ninja_smoke.dm +++ /dev/null @@ -1,14 +0,0 @@ - - -//Smoke bomb -/obj/item/clothing/suit/space/space_ninja/proc/ninjasmoke() - - if(!ninjacost(0,N_SMOKE_BOMB)) - var/mob/living/carbon/human/H = affecting - var/datum/effect_system/smoke_spread/bad/smoke = new - smoke.set_up(4, H.loc) - smoke.start() - playsound(H.loc, 'sound/effects/bamf.ogg', 50, 2) - s_bombs-- - to_chat(H, "There are [s_bombs] smoke bombs remaining.") - s_coold = 1 diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_stars.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_stars.dm deleted file mode 100644 index 57faad9493..0000000000 --- a/code/modules/ninja/suit/n_suit_verbs/ninja_stars.dm +++ /dev/null @@ -1,18 +0,0 @@ - - -//Creates a throwing star -/obj/item/clothing/suit/space/space_ninja/proc/ninjastar() - if(!ninjacost(10)) - var/mob/living/carbon/human/H = affecting - var/obj/item/throwing_star/ninja/N = new(H) - if(H.put_in_hands(N)) - to_chat(H, "A throwing star has been created in your hand!") - else - qdel(N) - H.throw_mode_on() //So they can quickly throw it. - - -/obj/item/throwing_star/ninja - name = "ninja throwing star" - throwforce = 20 - embedding = list("pain_mult" = 6, "embed_chance" = 100, "fall_chance" = 0, "embed_chance_turf_mod" = 15) diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_stealth.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_stealth.dm deleted file mode 100644 index 56c50078c1..0000000000 --- a/code/modules/ninja/suit/n_suit_verbs/ninja_stealth.dm +++ /dev/null @@ -1,54 +0,0 @@ - -/* - -Contents: -- Stealth Verbs - -*/ - - -/obj/item/clothing/suit/space/space_ninja/proc/toggle_stealth() - if(!affecting || stealth_cooldown > world.time) - return - if(stealth) - cancel_stealth() - else - if(cell.charge <= 0) - to_chat(affecting, "You don't have enough power to enable Stealth!") - return - stealth = TRUE - stealth_cooldown = world.time + 5 SECONDS - animate(affecting, alpha = 15, time = 3 SECONDS) - affecting.visible_message("[affecting.name] vanishes into thin air!", \ - "You are now mostly invisible to normal detection.") - addtimer(CALLBACK(src, .proc/enable_signals), 3 SECONDS) - -/obj/item/clothing/suit/space/space_ninja/proc/enable_signals() - if(!affecting) - return - RegisterSignal(affecting, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_MOB_ATTACK_RANGED, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_MOB_ATTACK_HAND, COMSIG_MOB_THROW, COMSIG_PARENT_ATTACKBY, COMSIG_MOVABLE_TELEPORTED, COMSIG_LIVING_GUN_PROCESS_FIRE), .proc/reduce_stealth) - RegisterSignal(affecting, COMSIG_MOVABLE_BUMP, .proc/bumping_stealth) - -/obj/item/clothing/suit/space/space_ninja/proc/reduce_stealth(datum/source) - affecting.alpha = min(affecting.alpha + 40, 100) - -/obj/item/clothing/suit/space/space_ninja/proc/bumping_stealth(datum/source, atom/A) - if(isliving(A)) - affecting.alpha = min(affecting.alpha + 20, 100) - -/obj/item/clothing/suit/space/space_ninja/proc/cancel_stealth() - if(!affecting || !stealth) - return FALSE - stealth = !stealth - stealth_cooldown = world.time + 5 SECONDS - UnregisterSignal(affecting, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_MOB_ATTACK_RANGED, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_MOB_ATTACK_HAND, COMSIG_MOB_THROW, COMSIG_PARENT_ATTACKBY, COMSIG_MOVABLE_BUMP, COMSIG_MOVABLE_TELEPORTED, COMSIG_LIVING_GUN_PROCESS_FIRE)) - animate(affecting, alpha = 255, time = 3 SECONDS) - affecting.visible_message("[affecting.name] appears from thin air!", \ - "You are now visible.") - return TRUE - -/obj/item/clothing/suit/space/space_ninja/proc/stealth() - if(!s_busy) - toggle_stealth() - else - to_chat(affecting, "Stealth does not appear to work!") diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_sword_recall.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_sword_recall.dm deleted file mode 100644 index 7a192c427c..0000000000 --- a/code/modules/ninja/suit/n_suit_verbs/ninja_sword_recall.dm +++ /dev/null @@ -1,39 +0,0 @@ - -/obj/item/clothing/suit/space/space_ninja/proc/ninja_sword_recall() - var/mob/living/carbon/human/H = affecting - - var/cost = 0 - var/inview = 1 - - if(!energyKatana) - to_chat(H, "Could not locate Energy Katana!") - return - - if(energyKatana in H) - return - - var/distance = get_dist(H,energyKatana) - - if(!(energyKatana in view(H))) - cost = distance //Actual cost is cost x 10, so 5 turfs is 50 cost. - inview = 0 - - if(!ninjacost(cost)) - if(iscarbon(energyKatana.loc)) - var/mob/living/carbon/C = energyKatana.loc - C.transferItemToLoc(energyKatana, get_turf(energyKatana), TRUE) - - //Somebody swollowed my sword, probably the clown doing a circus act. - if(energyKatana in C.stomach_contents) - C.stomach_contents -= energyKatana - else - energyKatana.forceMove(get_turf(energyKatana)) - - if(inview) //If we can see the katana, throw it towards ourselves, damaging people as we go. - energyKatana.spark_system.start() - playsound(H, "sparks", 50, 1) - H.visible_message("\the [energyKatana] flies towards [H]!","You hold out your hand and \the [energyKatana] flies towards you!") - energyKatana.throw_at(H, distance+1, energyKatana.throw_speed,H) - - else //Else just TP it to us. - energyKatana.returnToOwner(H,1) diff --git a/code/modules/ninja/suit/ninjaDrainAct.dm b/code/modules/ninja/suit/ninjaDrainAct.dm index af0ca809da..4f287fc81b 100644 --- a/code/modules/ninja/suit/ninjaDrainAct.dm +++ b/code/modules/ninja/suit/ninjaDrainAct.dm @@ -1,274 +1,326 @@ - -/* - -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 && cell.charge) var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread() spark_system.set_up(5, 0, loc) - while(G.candrain && cell.charge> 0 && !maxcapacity) - drain = rand(G.mindrain, G.maxdrain) + while(ninja_gloves.candrain && cell.charge> 0 && !maxcapacity) + drain = rand(ninja_gloves.mindrain, ninja_gloves.maxdrain) if(cell.charge < drain) drain = cell.charge - if(S.cell.charge + drain > S.cell.maxcharge) - drain = S.cell.maxcharge - S.cell.charge - maxcapacity = 1//Reached maximum battery capacity. + if(ninja_suit.cell.charge + drain > ninja_suit.cell.maxcharge) + drain = ninja_suit.cell.maxcharge - ninja_suit.cell.charge + maxcapacity = TRUE//Reached maximum battery capacity. - if (do_after(H,10, target = src)) + if (do_after(ninja ,10, target = src)) spark_system.start() playsound(loc, "sparks", 50, 1) cell.charge -= drain - S.cell.charge += drain - . += drain + ninja_suit.cell.charge += drain + drain_total += drain else break if(!(obj_flags & EMAGGED)) - flick("apc-spark", G) + flick("apc-spark", ninja_gloves) playsound(loc, "sparks", 50, 1) 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/drain = 0 //Drain amount from batteries - - . = 0 + var/drain = FALSE //Drain amount from batteries + var/drain_total = 0 if(charge) var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread() spark_system.set_up(5, 0, loc) - while(G.candrain && charge > 0 && !maxcapacity) - drain = rand(G.mindrain, G.maxdrain) + while(ninja_gloves.candrain && charge > 0 && !maxcapacity) + drain = rand(ninja_gloves.mindrain, ninja_gloves.maxdrain) if(charge < drain) drain = charge - if(S.cell.charge + drain > S.cell.maxcharge) - drain = S.cell.maxcharge - S.cell.charge - maxcapacity = 1 + if(ninja_suit.cell.charge + drain > ninja_suit.cell.maxcharge) + drain = ninja_suit.cell.maxcharge - ninja_suit.cell.charge + maxcapacity = TRUE - if (do_after(H,10, target = src)) + if (do_after(ninja,10, target = src)) spark_system.start() playsound(loc, "sparks", 50, 1) charge -= drain - S.cell.charge += drain - . += drain + ninja_suit.cell.charge += drain + drain_total += drain else break + return drain_total //CELL// -/obj/item/stock_parts/cell/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/S, mob/living/carbon/human/H, obj/item/clothing/gloves/space_ninja/G) - if(!S || !H || !G) +/obj/item/stock_parts/cell/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves) + if(!ninja_suit || !ninja || !ninja_gloves) return INVALID_DRAIN - . = 0 + var/drain_total = 0 if(charge) - if(G.candrain && do_after(H,30, target = src)) - . = charge - if(S.cell.charge + charge > S.cell.maxcharge) - S.cell.charge = S.cell.maxcharge + if(ninja_gloves.candrain && do_after(ninja,30, target = src)) + drain_total = charge + if(ninja_suit.cell.charge + charge > ninja_suit.cell.maxcharge) + ninja_suit.cell.charge = ninja_suit.cell.maxcharge else - S.cell.charge += charge + ninja_suit.cell.charge += charge charge = 0 corrupt() update_icon() -/obj/machinery/proc/AI_notify_hack() - var/turf/location = get_turf(src) - var/alertstr = "Network Alert: Hacking attempt detected[location?" in [location]":". Unable to pinpoint location"]." - for(var/mob/living/silicon/ai/AI in GLOB.player_list) - to_chat(AI, alertstr) + return drain_total //RDCONSOLE// -/obj/machinery/computer/rdconsole/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/S, mob/living/carbon/human/H, obj/item/clothing/gloves/space_ninja/G) - if(!S || !H || !G) +/obj/machinery/computer/rdconsole/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves) + if(!ninja_suit || !ninja || !ninja_gloves) return INVALID_DRAIN . = DRAIN_RD_HACK_FAILED - to_chat(H, "Hacking \the [src]...") + to_chat(ninja, "Hacking \the [src]...") AI_notify_hack() if(stored_research) - to_chat(H, "Copying files...") - if(do_after(H, S.s_delay, target = src) && G.candrain && src) - stored_research.copy_research_to(S.stored_research) - to_chat(H, "Data analyzed. Process finished.") + to_chat(ninja, "Copying files...") + if(do_after(ninja, ninja_suit.s_delay, target = src) && ninja_gloves.candrain && src) + stored_research.copy_research_to( ninja_suit.stored_research) + to_chat(ninja, "Data analyzed. Process finished.") //RD SERVER// -//Shamelessly copypasted from above, since these two used to be the same proc, but with MANY colon operators -/obj/machinery/rnd/server/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/S, mob/living/carbon/human/H, obj/item/clothing/gloves/space_ninja/G) - if(!S || !H || !G) +//obj/machinery/rnd/server/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves) + if(!ninja_suit || !ninja || !ninja_gloves) return INVALID_DRAIN . = DRAIN_RD_HACK_FAILED - to_chat(H, "Hacking \the [src]...") + to_chat(ninja, "Hacking \the [src]...") AI_notify_hack() if(stored_research) - to_chat(H, "Copying files...") - if(do_after(H, S.s_delay, target = src) && G.candrain && src) - stored_research.copy_research_to(S.stored_research) - to_chat(H, "Data analyzed. Process finished.") + to_chat(ninja, "Copying files...") + if(do_after(ninja, ninja_suit.s_delay, target = src) && ninja_gloves.candrain && src) + stored_research.copy_research_to(ninja_suit.stored_research) + to_chat(ninja, "Data analyzed. Process finished.") +//SECURITY CONSOLE// +/obj/machinery/computer/secure_data/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves) + if(!ninja_suit || !ninja || !ninja_gloves) + return INVALID_DRAIN + if(ninja_gloves.security_console_hack_success) + return + to_chat(ninja, "Hacking \the [src]...") + AI_notify_hack() + if(do_after(ninja, ninja_suit.s_longdelay, target = src) && ninja_gloves.candrain && src) + 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 + ninja_gloves.security_console_hack_success = TRUE + var/datum/objective/security_scramble/objective = locate() in ninja_antag.objectives + if(objective) + objective.completed = TRUE + to_chat(ninja, "Security record corruption malware uploaded. Process finished; objective completed.") -//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 + to_chat(ninja, "Hacking \the [src]...") + AI_notify_hack() + if(do_after(ninja, ninja_suit.s_longdelay, target = src) && ninja_gloves.candrain && src) + var/announcement_pick = rand(0, 1) + switch(announcement_pick) + if(0) + priority_announce("Attention crew, it appears that something on your station has caused an unexpected disruption with the station's airlock network.", "[command_name()] High-Priority Update") + var/datum/round_event_control/grey_tide/greytide_event = new/datum/round_event_control/grey_tide + greytide_event.runEvent() + if(1) + priority_announce("Attention crew, it appears that something 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 + to_chat(ninja, "Signal decryption malware uploaded. Process finished; objective completed.") + +//AIRLOCK// +/obj/machinery/door/airlock/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves) + if(!ninja_suit || !ninja || !ninja_gloves) return INVALID_DRAIN - var/maxcapacity = 0 //Safety check + if(!operating && density && hasPower() && !(obj_flags & EMAGGED)) + emag_act() + ninja_gloves.door_hack_counter++ + var/datum/antagonist/ninja/ninja_antag = ninja.mind.has_antag_datum(/datum/antagonist/ninja) + if(!ninja_antag) + return + var/datum/objective/door_jack/objective = locate() in ninja_antag.objectives + if(objective && objective.doors_required <= ninja_gloves.door_hack_counter) + objective.completed = TRUE + +//WIRE// +/obj/structure/cable/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves) + if(!ninja_suit || !ninja || !ninja_gloves) + return INVALID_DRAIN + + var/maxcapacity = FALSE //Safety check var/drain = 0 //Drain amount - . = 0 + var/drain_total = 0 - var/datum/powernet/PN = powernet - while(G.candrain && !maxcapacity && src) - drain = (round((rand(G.mindrain, G.maxdrain))/2)) + var/datum/powernet/wire_powernet = powernet + while(ninja_gloves.candrain && !maxcapacity && src) + drain = (round((rand(ninja_gloves.mindrain, ninja_gloves.maxdrain))/2)) var/drained = 0 - if(PN && do_after(H,10, target = src)) + if(wire_powernet && do_after(ninja,10, target = src)) drained = min(drain, delayed_surplus()) add_delayedload(drained) if(drained < drain)//if no power on net, drain apcs - for(var/obj/machinery/power/terminal/T in PN.nodes) - if(istype(T.master, /obj/machinery/power/apc)) - var/obj/machinery/power/apc/AP = T.master + for(var/obj/machinery/power/terminal/affected_terminal in wire_powernet.nodes) + if(istype(affected_terminal.master, /obj/machinery/power/apc)) + var/obj/machinery/power/apc/AP = affected_terminal.master if(AP.operating && AP.cell && AP.cell.charge > 0) AP.cell.charge = max(0, AP.cell.charge - 5) drained += 5 else break - S.cell.charge += drained - if(S.cell.charge > S.cell.maxcharge) - . += (drained-(S.cell.charge - S.cell.maxcharge)) - S.cell.charge = S.cell.maxcharge - maxcapacity = 1 + ninja_suit.cell.charge += drained + if(ninja_suit.cell.charge > ninja_suit.cell.maxcharge) + . += (drained-(ninja_suit.cell.charge - ninja_suit.cell.maxcharge)) + ninja_suit.cell.charge = ninja_suit.cell.maxcharge + maxcapacity = TRUE else - . += drained - S.spark_system.start() + drain_total += drained + ninja_suit.spark_system.start() + + return drain_total //MECH// -/obj/mecha/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/S, mob/living/carbon/human/H, obj/item/clothing/gloves/space_ninja/G) - if(!S || !H || !G) +/obj/mecha/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves) + if(!ninja_suit || !ninja || !ninja_gloves) return INVALID_DRAIN - var/maxcapacity = 0 //Safety check + var/maxcapacity = FALSE //Safety check var/drain = 0 //Drain amount - . = 0 + var/drain_total = 0 occupant_message("Warning: Unauthorized access through sub-route 4, block H, detected.") if(get_charge()) - while(G.candrain && cell.charge > 0 && !maxcapacity) - drain = rand(G.mindrain,G.maxdrain) + while(ninja_gloves.candrain && cell.charge > 0 && !maxcapacity) + drain = rand(ninja_gloves.mindrain, ninja_gloves.maxdrain) if(cell.charge < drain) drain = cell.charge - if(S.cell.charge + drain > S.cell.maxcharge) - drain = S.cell.maxcharge - S.cell.charge - maxcapacity = 1 - if (do_after(H,10, target = src)) + if(ninja_suit.cell.charge + drain > ninja_suit.cell.maxcharge) + drain = ninja_suit.cell.maxcharge - ninja_suit.cell.charge + maxcapacity = TRUE + if (do_after(ninja, 10, target = src)) spark_system.start() playsound(loc, "sparks", 50, 1) cell.use(drain) - S.cell.charge += drain - . += drain + ninja_suit.cell.give(drain) + drain_total += drain else break + return drain_total + //BORG// -/mob/living/silicon/robot/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/S, mob/living/carbon/human/H, obj/item/clothing/gloves/space_ninja/G) - if(!S || !H || !G) +/mob/living/silicon/robot/ninjadrain_act(obj/item/clothing/suit/space/space_ninja/ninja_suit, mob/living/carbon/human/ninja, obj/item/clothing/gloves/space_ninja/ninja_gloves) + if(!ninja_suit || !ninja || !ninja_gloves || (ROLE_NINJA in faction)) return INVALID_DRAIN + if(ninja_gloves.borg_hack_success) + return + 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" + UnlinkSelf() + ionpulse = TRUE + laws = new /datum/ai_laws/ninja_override() + module.transform_to(pick(/obj/item/robot_module/syndicate/spider, /obj/item/robot_module/syndicate_medical/spider, /obj/item/robot_module/saboteur/spider)) - 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 && cell.charge) - while(G.candrain && cell.charge > 0 && !maxcapacity) - drain = rand(G.mindrain,G.maxdrain) - if(cell.charge < drain) - drain = cell.charge - if(S.cell.charge+drain > S.cell.maxcharge) - drain = S.cell.maxcharge - S.cell.charge - maxcapacity = 1 - if (do_after(H,10)) - spark_system.start() - playsound(loc, "sparks", 50, 1) - cell.charge -= drain - S.cell.charge += drain - . += drain - else - break - + var/datum/antagonist/ninja/ninja_antag = ninja.mind.has_antag_datum(/datum/antagonist/ninja) + if(!ninja_antag) + return + ninja_gloves.borg_hack_success = TRUE + 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(500)) + 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, 1) - visible_message("[H] electrocutes [src] with [H.p_their()] touch!", "[H] electrocutes you with [H.p_their()] touch!") - electrocute_act(15, H, flags = SHOCK_NOSTUN) + visible_message("[ninja] electrocutes [src] with [ninja.p_their()] touch!", "[ninja] electrocutes you with [ninja.p_their()] touch!") + electrocute_act(15, ninja, flags = SHOCK_NOSTUN) - DefaultCombatKnockdown(G.stunforce, override_hardstun = 0) - apply_effect(EFFECT_STUTTER, G.stunforce) + DefaultCombatKnockdown(ninja_gloves.stunforce, override_hardstun = 0) + apply_effect(EFFECT_STUTTER, ninja_gloves.stunforce) SEND_SIGNAL(src, COMSIG_LIVING_MINOR_SHOCK) - - set_last_attacker(H) - log_combat(H, src, "stunned") + lastattacker = ninja.real_name + lastattackerckey = ninja.ckey + log_combat(ninja, src, "stunned") + set_last_attacker(ninja) + log_combat(ninja, src, "stunned") playsound(loc, 'sound/weapons/egloves.ogg', 50, 1, -1) diff --git a/code/modules/ninja/suit/ninja_equipment_actions/energy_net_nets.dm b/code/modules/ninja/suit/ninja_equipment_actions/energy_net_nets.dm new file mode 100644 index 0000000000..bc0828242e --- /dev/null +++ b/code/modules/ninja/suit/ninja_equipment_actions/energy_net_nets.dm @@ -0,0 +1,46 @@ +/** + * # Energy Net + * + * Energy net which ensnares prey until it is destroyed. Used by space ninjas. + * + * Energy net which keeps its target from moving until it is destroyed. Used to send + * players to a holding area in which they could never leave, but such feature has since + * been removed. + */ +/obj/structure/energy_net + name = "energy net" + desc = "It's a net made of green energy." + icon = 'icons/effects/effects.dmi' + icon_state = "energynet" + + + density = TRUE//Can't pass through. + opacity = FALSE //Can see through. + mouse_opacity = MOUSE_OPACITY_ICON//So you can hit it with stuff. + anchored = TRUE//Can't drag/grab the net. + layer = ABOVE_ALL_MOB_LAYER + max_integrity = 60 //How much health it has. + can_buckle = 1 + buckle_lying = 0 + buckle_prevents_pull = TRUE + ///The creature currently caught in the net + var/mob/living/affecting + +/obj/structure/energy_net/play_attack_sound(damage, damage_type = BRUTE, damage_flag = 0) + if(damage_type == BRUTE || damage_type == BURN) + playsound(src, 'sound/weapons/slash.ogg', 80, TRUE) + +/obj/structure/energy_net/Destroy() + if(!QDELETED(affecting)) + affecting.visible_message("[affecting.name] is recovered from the energy net!", "You are recovered from the energy net!", "You hear a grunt.") + affecting = null + return ..() + +/obj/structure/energy_net/attack_paw(mob/user) + return attack_hand() + +/obj/structure/energy_net/user_buckle_mob(mob/living/M, mob/user, check_loc = TRUE) + return//We only want our target to be buckled + +/obj/structure/energy_net/user_unbuckle_mob(mob/living/buckled_mob, mob/living/user) + return//The net must be destroyed to free the target diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_adrenaline.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_adrenaline.dm new file mode 100644 index 0000000000..0b64f35f0c --- /dev/null +++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_adrenaline.dm @@ -0,0 +1,38 @@ +//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 = "adrenal" + icon_icon = 'icons/obj/implants.dmi' + required_mobility_flags = NONE + +/** + * 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.do_adrenaline(150, TRUE, 0, 0, TRUE, list(/datum/reagent/medicine/epinephrine = 3, /datum/reagent/medicine/regen_jelly = 10, /datum/reagent/medicine/stimulants = 2), "You feel a sudden surge of energy!") + 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.") + 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/radium, a_transfer * 0.25) + to_chat(ninja, "You are beginning to feel the after-effect of the injection.") diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_cost_check.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_cost_check.dm new file mode 100644 index 0000000000..7fb9d9dbf6 --- /dev/null +++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_cost_check.dm @@ -0,0 +1,28 @@ +/** + * Proc called to check if the ninja can afford an ability's cost. + * + * Proc which determine whether or not a space ninja can afford to use a specific ability. + * It can also cancel stealth if the ability requested it. + * Arguments: + * * cost - the energy cost of the ability + * * specificCheck - Determines if the check is a normal one, an adrenaline one, or a stealth cancel check. + * * Returns TRUE or the current cooldown timer if we can't perform the ability, and FALSE if we can. + */ +/obj/item/clothing/suit/space/space_ninja/proc/ninjacost(cost = 0, specificCheck = 0) + var/mob/living/carbon/human/ninja = affecting + var/actualCost = cost*10 + if(cost && cell.charge < actualCost) + to_chat(ninja, "Not enough energy!") + return TRUE + else + //This shit used to be handled individually on every proc.. why even bother with a universal check proc then? + cell.charge-=(actualCost) + + switch(specificCheck) + if(N_STEALTH_CANCEL) + cancel_stealth()//Get rid of it. + if(N_ADRENALINE) + if(!a_boost) + to_chat(ninja, "You do not have any more adrenaline boosters!") + return TRUE + return (s_coold)//Returns the value of the variable which counts down to zero. diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_empulse.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_empulse.dm new file mode 100644 index 0000000000..ea2341a132 --- /dev/null +++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_empulse.dm @@ -0,0 +1,21 @@ +//Disables nearby tech equipment. + +/datum/action/item_action/ninjapulse + name = "EM Burst (50E)" + desc = "Disable any nearby technology with an electro-magnetic pulse." + button_icon_state = "emp" + icon_icon = 'icons/mob/actions/actions_spells.dmi' + +/** + * Proc called to allow the ninja to EMP the nearby area. + * + * Proc called to allow the ninja to EMP the nearby area. By default, costs 500E, which is half of the default battery's max charge. + * Also affects the ninja as well. + */ +/obj/item/clothing/suit/space/space_ninja/proc/ninjapulse() + if(ninjacost(500,N_STEALTH_CANCEL)) + return + var/mob/living/carbon/human/H = affecting + playsound(H.loc, 'sound/effects/empulse.ogg', 60, 2) + empulse(H, 4, 6) //Procs sure are nice. Slightly weaker than wizard's disable tch. + s_coold = 4 diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_glove_toggle.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_glove_toggle.dm new file mode 100644 index 0000000000..ec5bf078a5 --- /dev/null +++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_glove_toggle.dm @@ -0,0 +1,15 @@ +/datum/action/item_action/toggle_glove + name = "Toggle interaction" + desc = "Switch between normal interaction and drain mode." + button_icon_state = "s-ninjan" + icon_icon = 'icons/obj/clothing/gloves.dmi' + +/** + * Proc called to toggle the ninja glove's special abilities. + * + * Used to toggle whether or not the ninja glove's abilities will activate on touch. + */ +/obj/item/clothing/gloves/space_ninja/proc/toggledrain() + var/mob/living/carbon/human/ninja = loc + to_chat(ninja, "You [candrain?"disable":"enable"] special interaction.") + candrain=!candrain diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_net.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_net.dm new file mode 100644 index 0000000000..ab52f3e018 --- /dev/null +++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_net.dm @@ -0,0 +1,36 @@ +/datum/action/item_action/ninjanet + name = "Energy Net (40E)" + desc = "Captures a fallen opponent in a net of energy." + button_icon_state = "energynet" + icon_icon = 'icons/effects/effects.dmi' + +/** + * Proc called to ensnare a person in a energy net. + * + * Used to ensnare a target in an energy net, preventing them from moving until the net is broken. + * Costs 40E, which is 40% of the default battery's max charge. Intended as a means of reliably locking down an opponent when ninja stars won't suffice. + */ +/obj/item/clothing/suit/space/space_ninja/proc/ninjanet() + var/mob/living/carbon/human/ninja = affecting + var/mob/living/net_target = input("Select who to capture:","Capture who?",null) as null|mob in sortNames(oview(ninja)) + + if(QDELETED(net_target)||!(net_target in oview(ninja))) + return + + if(locate(/obj/structure/energy_net) in get_turf(net_target))//Check if they are already being affected by an energy net. + to_chat(ninja, "[net_target.p_they(TRUE)] are already trapped inside an energy net!") + return + for(var/turf/between_turf in getline(get_turf(ninja), get_turf(net_target))) + if(between_turf.density)//Don't want them shooting nets through walls. It's kind of cheesy. + to_chat(ninja, "You may not use an energy net through solid obstacles!") + return + if(!ninjacost(400,N_STEALTH_CANCEL)) + ninja.Beam(net_target, "n_beam", time = 15) + ninja.say("Get over here!", forced = "ninja net") + var/obj/structure/energy_net/net = new /obj/structure/energy_net(net_target.drop_location()) + net.affecting = net_target + ninja.visible_message("[ninja] caught [net_target] with an energy net!","You caught [net_target] with an energy net!") + + if(net_target.buckled) + net_target.buckled.unbuckle_mob(affecting,TRUE) + net.buckle_mob(net_target, TRUE) //No moving for you! diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_stars.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_stars.dm new file mode 100644 index 0000000000..ef897d5bb9 --- /dev/null +++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_stars.dm @@ -0,0 +1,46 @@ +/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" + icon_state = "ninjastar" + item_state = "ninjastar" + throwforce = 10 + embedding = list("pain_chance" = 5, "embed_chance" = 100, "fall_chance" = 10, "jostle_chance" = 10, "pain_stam_pct" = 2.5, "jostle_pain_mult" = 3) diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_status_read.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_status_read.dm new file mode 100644 index 0000000000..0bedd31c72 --- /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' + var/action_background_icon_state = "bg_default_on" + +/** + * 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" + //Ninja status + info_list += "Fingerprints: [md5(ninja.dna.uni_identity)]\n" + info_list += "Unique Identity: [ninja.dna.unique_enzymes]\n" + info_list += "Overall Status: [ninja.stat > 1 ? "dead" : "[ninja.health]% healthy"]\n" + info_list += "Nutrition Status: [ninja.nutrition]\n" + info_list += "Oxygen Loss: [ninja.getOxyLoss()]\n" + info_list += "Toxin Levels: [ninja.getToxLoss()]\n" + info_list += "Burn Severity: [ninja.getFireLoss()]\n" + info_list += "Brute Trauma: [ninja.getBruteLoss()]\n" + info_list += "Radiation Levels: [ninja.radiation] rad\n" + info_list += "Body Temperature: [ninja.bodytemperature-T0C] degrees C ([ninja.bodytemperature*1.8-459.67] degrees F)\n" + + //Diseases + if(length(ninja.diseases)) + info_list += "Viruses:" + for(var/datum/disease/ninja_disease in ninja.diseases) + info_list += "* [ninja_disease.name], Type: [ninja_disease.spread_text], Stage: [ninja_disease.stage]/[ninja_disease.max_stages], Possible Cure: [ninja_disease.cure_text]\n" + + to_chat(ninja, "[info_list.Join()]") diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_stealth.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_stealth.dm new file mode 100644 index 0000000000..079f0c53e9 --- /dev/null +++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_stealth.dm @@ -0,0 +1,46 @@ +/datum/action/item_action/ninja_stealth + name = "Toggle Stealth" + desc = "Toggles stealth mode on and off." + button_icon_state = "ninja_cloak" + icon_icon = 'icons/mob/actions/actions_minor_antag.dmi' + +/** + * Proc called to toggle ninja stealth. + * + * Proc called to toggle whether or not the ninja is in stealth mode. + * If cancelling, calls a separate proc in case something else needs to quickly cancel stealth. + */ +/obj/item/clothing/suit/space/space_ninja/proc/toggle_stealth() + var/mob/living/carbon/human/ninja = affecting + if(!ninja) + return + if(stealth) + cancel_stealth() + else + if(cell.charge <= 0) + to_chat(ninja, "You don't have enough power to enable Stealth!") + return + stealth = !stealth + animate(ninja, alpha = 20,time = 12) + ninja.visible_message("[ninja.name] vanishes into thin air!", \ + "You are now mostly invisible to normal detection.") + +/** + * Proc called to cancel stealth. + * + * Called to cancel the stealth effect if it is ongoing. + * Does nothing otherwise. + * Arguments: + * * Returns false if either the ninja no longer exists or is already visible, returns true if we successfully made the ninja visible. + */ +/obj/item/clothing/suit/space/space_ninja/proc/cancel_stealth() + var/mob/living/carbon/human/ninja = affecting + if(!ninja) + return FALSE + if(stealth) + stealth = !stealth + animate(ninja, alpha = 255, time = 12) + ninja.visible_message("[ninja.name] appears from thin air!", \ + "You are now visible.") + return TRUE + return FALSE diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_suit_initialisation.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_suit_initialisation.dm new file mode 100644 index 0000000000..c1a3c77814 --- /dev/null +++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_suit_initialisation.dm @@ -0,0 +1,123 @@ +#define NINJA_LOCK_PHASE 1 +#define NINJA_ICON_GENERATE_PHASE 3 +#define NINJA_COMPLETE_PHASE 6 +#define NINJA_DEINIT_LOGOFF_PHASE 1 +#define NINJA_DEINIT_STEALTH_PHASE 5 + +GLOBAL_LIST_INIT(ninja_initialize_messages, list( + "Now initializing...", + "Securing external locking mechanism...\nNeural-net established.", + "Extending neural-net interface...\nNow monitoring brain wave pattern...", + "Linking neural-net interface...\nPattern GREEN, continuing operation.", + "VOID-shift device status: ONLINE.\nCLOAK-tech device status: ONLINE.", + "Primary system status: ONLINE.\nBackup system status: ONLINE.\nCurrent energy capacity: ", + "All systems operational. Welcome to SpiderOS, " +)) + +GLOBAL_LIST_INIT(ninja_deinitialize_messages, list( + "Now de-initializing...", + "Shutting down SpiderOS.", + "Primary system status: OFFLINE.\nBackup system status: OFFLINE.", + "VOID-shift device status: OFFLINE.\nCLOAK-tech device status: OFFLINE.", + "Disconnecting neural-net interface...Success.", + "Disengaging neural-net interface... Success.", + "Unsecuring external locking mechanism...\nNeural-net abolished.\nOperation status: FINISHED." +)) + +/datum/action/item_action/initialize_ninja_suit + name = "Toggle Ninja Suit" + +/** + * Toggles the ninja suit on/off + * + * Attempts to initialize or deinitialize the ninja suit + */ +/obj/item/clothing/suit/space/space_ninja/proc/toggle_on_off() + . = TRUE + if(s_busy) + to_chat(loc, "ERROR: You cannot use this function at this time.") + return FALSE + s_busy = TRUE + if(s_initialized) + deinitialize() + else + ninitialize() + +/** + * Initializes the ninja suit + * + * Initializes the ninja suit through seven phases, each of which calls this proc with an incremented phase + * Arguments: + * * delay - The delay between each phase of initialization + * * ninja - The human who is being affected by the suit + * * phase - The phase of initialization + */ +/obj/item/clothing/suit/space/space_ninja/proc/ninitialize(delay = s_delay, mob/living/carbon/human/ninja = loc, phase = 0) + if(!ninja || !ninja.mind) + s_busy = FALSE + return + if (phase > NINJA_LOCK_PHASE && (ninja.stat == DEAD || ninja.health <= 0)) + to_chat(ninja, "FĆAL �Rr�R: 344--93#�&&21 BR��N |/|/aV� PATT$RN RED\nA-A-aB�rT�NG...") + unlock_suit(ninja) + s_busy = FALSE + return + + var/message = GLOB.ninja_initialize_messages[phase + 1] + switch(phase) + if (NINJA_LOCK_PHASE) + if(!lock_suit(ninja))//To lock the suit onto wearer. + s_busy = FALSE + return + if (NINJA_COMPLETE_PHASE - 1) + message += "[DisplayEnergy(cell.charge)]." + if (NINJA_COMPLETE_PHASE) + message += "[ninja.real_name]." + ninja.regenerate_icons() + s_initialized = TRUE + s_busy = FALSE + + to_chat(ninja, "[message]") + playsound(ninja, 'sound/effects/sparks1.ogg', 10, TRUE) + + if (phase < NINJA_COMPLETE_PHASE) + addtimer(CALLBACK(src, .proc/ninitialize, delay, ninja, phase + 1), delay) + +/** + * Deinitializes the ninja suit + * + * Deinitializes the ninja suit through eight phases, each of which calls this proc with an incremented phase + * Arguments: + * * delay - The delay between each phase of deinitialization + * * ninja - The human who is being affected by the suit + * * phase - The phase of deinitialization + */ +/obj/item/clothing/suit/space/space_ninja/proc/deinitialize(delay = s_delay, mob/living/carbon/human/ninja = affecting == loc ? affecting : null, phase = 0) + if (!ninja || !ninja.mind) + s_busy = FALSE + return + if (phase == 0 && alert("Are you certain you wish to remove the suit? This will take time and remove all abilities.",,"Yes","No") == "No") + s_busy = FALSE + return + + var/message = GLOB.ninja_deinitialize_messages[phase + 1] + switch(phase) + if(NINJA_DEINIT_LOGOFF_PHASE) + message = "Logging off, [ninja.real_name]. " + message + if(NINJA_DEINIT_STEALTH_PHASE) + cancel_stealth() + to_chat(ninja, "[message]") + playsound(ninja, 'sound/items/deconstruct.ogg', 10, TRUE) + + if (phase < NINJA_COMPLETE_PHASE) + addtimer(CALLBACK(src, .proc/deinitialize, delay, ninja, phase + 1), delay) + else + unlock_suit(ninja) + ninja.regenerate_icons() + s_initialized = FALSE + s_busy = FALSE + +#undef NINJA_LOCK_PHASE +#undef NINJA_ICON_GENERATE_PHASE +#undef NINJA_COMPLETE_PHASE +#undef NINJA_DEINIT_LOGOFF_PHASE +#undef NINJA_DEINIT_STEALTH_PHASE diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_sword_recall.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_sword_recall.dm new file mode 100644 index 0000000000..dd6ca61f88 --- /dev/null +++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_sword_recall.dm @@ -0,0 +1,48 @@ +/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) + s_coold = 4 diff --git a/code/modules/ninja/suit/shoes.dm b/code/modules/ninja/suit/shoes.dm index f2227b5f9f..6fba60a6ef 100644 --- a/code/modules/ninja/suit/shoes.dm +++ b/code/modules/ninja/suit/shoes.dm @@ -1,3 +1,12 @@ +/** + * # Ninja Shoes + * + * Space ninja's shoes. Gives him armor on his feet. + * + * Space ninja's ninja shoes. How mousey. Gives him slip protection and protection against attacks. + * Also are temperature resistant. + * + */ /obj/item/clothing/shoes/space_ninja name = "ninja shoes" desc = "A pair of running shoes. Excellent for running and even better for smashing skulls." @@ -5,8 +14,7 @@ permeability_coefficient = 0.01 clothing_flags = NOSLIP resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF - armor = list("melee" = 60, "bullet" = 50, "laser" = 30,"energy" = 15, "bomb" = 30, "bio" = 30, "rad" = 30, "fire" = 100, "acid" = 100) - strip_delay = 120 + armor = list("melee" = 40, "bullet" = 30, "laser" = 20,"energy" = 30, "bomb" = 30, "bio" = 30, "rad" = 30, "fire" = 100, "acid" = 100) cold_protection = FEET min_cold_protection_temperature = SHOES_MIN_TEMP_PROTECT heat_protection = FEET diff --git a/code/modules/ninja/suit/suit.dm b/code/modules/ninja/suit/suit.dm index 15071a186f..66d9a85290 100644 --- a/code/modules/ninja/suit/suit.dm +++ b/code/modules/ninja/suit/suit.dm @@ -1,16 +1,13 @@ - -/* - -Contents: -- The Ninja Space Suit -- Ninja Space Suit Procs - -*/ - - -// /obj/item/clothing/suit/space/space_ninja - - +/** + * # Ninja Suit + * + * Space ninja's suit. Provides him with most of his powers. + * + * Space ninja's suit. Gives space ninja all his iconic powers, which are mostly kept in + * the folder ninja_equipment_actions. Has a lot of unique stuff going on, so make sure to check + * the variables. Check suit_attackby to see radium interaction, disk copying, and cell replacement. + * + */ /obj/item/clothing/suit/space/space_ninja name = "ninja suit" desc = "A unique, vacuum-proof suit of nano-enhanced armor designed specifically for Spider Clan assassins." @@ -19,12 +16,11 @@ Contents: allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/restraints/handcuffs, /obj/item/tank/internals, /obj/item/stock_parts/cell) slowdown = 1 resistance_flags = LAVA_PROOF | ACID_PROOF - armor = list("melee" = 60, "bullet" = 50, "laser" = 30,"energy" = 15, "bomb" = 30, "bio" = 30, "rad" = 30, "fire" = 100, "acid" = 100) - strip_delay = 12 + armor = list("melee" = 40, "bullet" = 30, "laser" = 20,"energy" = 30, "bomb" = 30, "bio" = 30, "rad" = 30, "fire" = 100, "acid" = 100) - actions_types = list(/datum/action/item_action/initialize_ninja_suit, /datum/action/item_action/ninjasmoke, /datum/action/item_action/ninjaboost, /datum/action/item_action/ninjapulse, /datum/action/item_action/ninjastar, /datum/action/item_action/ninja_sword_recall, /datum/action/item_action/ninja_stealth, /datum/action/item_action/toggle_glove) + actions_types = list(/datum/action/item_action/initialize_ninja_suit, /datum/action/item_action/ninjastatus, /datum/action/item_action/ninjaboost, /datum/action/item_action/ninjapulse, /datum/action/item_action/ninjastar, /datum/action/item_action/ninjanet, /datum/action/item_action/ninja_sword_recall, /datum/action/item_action/ninja_stealth) - //Important parts of the suit. + ///The person wearing the suit var/mob/living/carbon/human/affecting = null var/obj/item/stock_parts/cell/cell var/datum/effect_system/spark_spread/spark_system @@ -37,28 +33,38 @@ Contents: var/obj/item/clothing/shoes/space_ninja/n_shoes var/obj/item/clothing/gloves/space_ninja/n_gloves - //Main function variables. - var/s_initialized = 0//Suit starts off. - var/s_coold = 0//If the suit is on cooldown. Can be used to attach different cooldowns to abilities. Ticks down every second based on suit ntick(). - var/s_cost = 5//Base energy cost each ntick. - var/s_acost = 25//Additional cost for additional powers active. - var/s_delay = 40//How fast the suit does certain things, lower is faster. Can be overridden in specific procs. Also determines adverse probability. - var/a_transfer = 20//How much radium is used per adrenaline boost. - var/a_maxamount = 7//Maximum number of adrenaline boosts. - var/s_maxamount = 20//Maximum number of smoke bombs. + ///The space ninja's mask. + var/obj/item/clothing/mask/gas/space_ninja/n_mask - //Support function variables. + ///Whether or not the suit is currently booted up. Starts off. + var/s_initialized = FALSE//Suit starts off. + ///The suit's current cooldown. If not 0, blocks usage of most abilities, and decrements its value by 1 every process + var/s_coold = 0 + ///How much energy the suit expends in a single process + var/s_cost = 1 + ///Additional energy cost for cloaking per process + var/s_acost = 20 + ///How fast the suit is at certain actions, like draining power from things + var/s_delay = 40 + ///How fast the suit is at certain riskier actions, like hacking communications consoles. + var/s_longdelay = 200 + ///Units of radium required to refill the adrenaline boost + var/a_transfer = 20//How much radium is required to refill the adrenaline boost. + ///Whether or not the suit is currently in stealth mode. var/stealth = FALSE//Stealth off. - var/stealth_cooldown = 0 - var/s_busy = FALSE//Is the suit busy with a process? Like AI hacking. Used for safety functions. - - //Ability function variables. - var/s_bombs = 10//Number of smoke bombs. - var/a_boost = 3//Number of adrenaline boosters. - - -/obj/item/clothing/suit/space/space_ninja/get_cell() - return cell + ///Whether or not the wearer is in the middle of an action, like hacking. + var/s_busy = FALSE + ///Whether or not the adrenaline boost ability is available + var/a_boost = TRUE +/obj/item/clothing/suit/space/space_ninja/examine(mob/user) + . = ..() + if(!s_initialized) + return + if(!user == affecting) + return + . += "All systems operational. Current energy capacity: [DisplayEnergy(cell.charge)].\n"+\ + "The CLOAK-tech device is [stealth?"active":"inactive"].\n"+\ + "[a_boost?"An adrenaline boost is available to use.":"There is no adrenaline boost available. Try refilling the suit with 20 units of radium."]" /obj/item/clothing/suit/space/space_ninja/Initialize() . = ..() @@ -77,114 +83,157 @@ Contents: cell.name = "black power cell" cell.icon_state = "bscell" -/obj/item/clothing/suit/space/space_ninja/Destroy() - if(affecting) - unlock_suit() - return ..() +/obj/item/clothing/suit/space/space_ninja/Initialize(mapload) + START_PROCESSING(SSobj, src) + return ..() -//Simply deletes all the attachments and self, killing all related procs. +/obj/item/clothing/suit/space/space_ninja/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +// Power usage +/obj/item/clothing/suit/space/space_ninja/process(delta_time) + var/mob/living/carbon/human/user = src.loc + if(!user || !ishuman(user) || !(user.wear_suit == src)) + return + + // Check for energy usage + if(s_initialized) + if(!affecting) + terminate() // Kills the suit and attached objects. + else if(cell.charge > 0) + if(s_coold > 0) + s_coold = max(s_coold - delta_time, 0) // Checks for ability s_cooldown first. + cell.charge -= s_cost * delta_time // s_cost is the default energy cost each ntick, usually 5. + if(stealth) // If stealth is active. + cell.charge -= s_acost * delta_time + else + cell.charge = 0 + cancel_stealth() + +/obj/item/clothing/suit/space/space_ninja/ui_action_click(mob/user, action) + if(IS_NINJA_SUIT_INITIALIZATION(action)) + toggle_on_off() + return TRUE + if(!s_initialized) + to_chat(user, "ERROR: suit offline. Please activate suit.") + return FALSE + if(s_coold > 0) + to_chat(user, "ERROR: suit is on cooldown.") + return FALSE + if(IS_NINJA_SUIT_STATUS(action)) + ninjastatus() + return TRUE + if(IS_NINJA_SUIT_BOOST(action)) + ninjaboost() + return TRUE + if(IS_NINJA_SUIT_EMP(action)) + ninjapulse() + return TRUE + if(IS_NINJA_SUIT_STAR_CREATION(action)) + ninjastar() + return TRUE + if(IS_NINJA_SUIT_NET_CREATION(action)) + ninjanet() + return TRUE + if(IS_NINJA_SUIT_SWORD_RECALL(action)) + ninja_sword_recall() + return TRUE + if(IS_NINJA_SUIT_STEALTH(action)) + toggle_stealth() + return TRUE + return FALSE + +/obj/item/clothing/suit/space/space_ninja/run_block(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = ATTACK_TYPE_MELEE) + . = ..() + if(stealth) + cancel_stealth() + s_coold = 5 + +/** + * 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) //colons make me go all |= + slowdown = 0 + icon_state = "s-ninjan" + 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_gloves.icon_state = "s-ninjan" + n_gloves.item_state = "s-ninjan" + n_mask = ninja.wear_mask + n_mask.icon_state = "s-ninjan" + n_mask.item_state = "s-ninjan" + + 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) + slowdown = 1 + icon_state = "s-ninja" + if(n_hood)//Should be attached, might not be attached. + REMOVE_TRAIT(n_hood, TRAIT_NODROP, NINJA_SUIT_TRAIT) + n_hood.icon_state = "s-ninja" + if(n_shoes) + REMOVE_TRAIT(n_shoes, TRAIT_NODROP, NINJA_SUIT_TRAIT) + n_shoes.slowdown++ + if(n_gloves) + n_gloves.icon_state = "s-ninja" + n_gloves.item_state = "s-ninja" + REMOVE_TRAIT(n_gloves, TRAIT_NODROP, NINJA_SUIT_TRAIT) + n_gloves.candrain = FALSE + n_gloves.draining = FALSE + if(n_mask) + n_mask.icon_state = "s-ninja" + n_mask.item_state = "s-ninja" + + REMOVE_TRAIT(ninja, TRAIT_NOGUNS, NINJA_SUIT_TRAIT) + +/** + * 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(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,20) - s_acost = rand(20,100) - s_delay = rand(10,100) - s_bombs = rand(5,20) - a_boost = rand(1,7) - -//This proc prevents the suit from being taken off. -/obj/item/clothing/suit/space/space_ninja/proc/lock_suit(mob/living/carbon/human/H) - if(!istype(H)) - 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) //colons make me go all |= - 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 = -0.25 - n_gloves = H.gloves - ADD_TRAIT(n_gloves, TRAIT_NODROP, NINJA_SUIT_TRAIT) - ADD_TRAIT(affecting, TRAIT_TASED_RESISTANCE, NINJA_SUIT_TRAIT) - return TRUE - -/obj/item/clothing/suit/space/space_ninja/proc/lockIcons(mob/living/carbon/human/H) - icon_state = H.dna.features["body_model"] == FEMALE ? "s-ninjanf" : "s-ninjan" - H.gloves.icon_state = "s-ninjan" - H.gloves.item_state = "s-ninjan" - - -//This proc allows the suit to be taken off. -/obj/item/clothing/suit/space/space_ninja/proc/unlock_suit() - 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 = 0.25 - if(n_gloves) - n_gloves.icon_state = "s-ninja" - n_gloves.item_state = "s-ninja" - REMOVE_TRAIT(n_gloves, TRAIT_NODROP, NINJA_SUIT_TRAIT) - n_gloves.candrain=0 - n_gloves.draining=0 - REMOVE_TRAIT(affecting, TRAIT_TASED_RESISTANCE, NINJA_SUIT_TRAIT) - - -/obj/item/clothing/suit/space/space_ninja/examine(mob/user) - . = ..() - if(s_initialized && user == affecting) - . += "All systems operational. Current energy capacity: [DisplayEnergy(cell.charge)].\n\ - The CLOAK-tech device is [stealth?"active":"inactive"].\n\ - There are [s_bombs] smoke bomb\s remaining.\n\ - There are [a_boost] adrenaline booster\s remaining." - -/obj/item/clothing/suit/space/space_ninja/ui_action_click(mob/user, action) - if(istype(action, /datum/action/item_action/initialize_ninja_suit)) - toggle_on_off() - return TRUE - if(!s_initialized) - to_chat(user, "ERROR: suit offline. Please activate suit.") - return FALSE - if(istype(action, /datum/action/item_action/ninjasmoke)) - ninjasmoke() - return TRUE - if(istype(action, /datum/action/item_action/ninjaboost)) - ninjaboost() - return TRUE - if(istype(action, /datum/action/item_action/ninjapulse)) - ninjapulse() - return TRUE - if(istype(action, /datum/action/item_action/ninjastar)) - ninjastar() - return TRUE - if(istype(action, /datum/action/item_action/ninja_sword_recall)) - ninja_sword_recall() - return TRUE - if(istype(action, /datum/action/item_action/ninja_stealth)) - stealth() - return TRUE - if(istype(action, /datum/action/item_action/toggle_glove)) - n_gloves.toggledrain() - return TRUE - return FALSE diff --git a/code/modules/ninja/suit/suit_attackby.dm b/code/modules/ninja/suit/suit_attackby.dm index ed920a57d1..75d438a35f 100644 --- a/code/modules/ninja/suit/suit_attackby.dm +++ b/code/modules/ninja/suit/suit_attackby.dm @@ -1,52 +1,44 @@ - - -/obj/item/clothing/suit/space/space_ninja/attackby(obj/item/I, mob/U, params) - if(U!=affecting)//Safety, in case you try doing this without wearing the suit/being the person with the suit. +/obj/item/clothing/suit/space/space_ninja/attackby(obj/item/I, mob/ninja, params) + if(ninja!=affecting)//Safety, in case you try doing this without wearing the suit/being the person with the suit. return ..() - if(istype(I, /obj/item/reagent_containers/glass))//If it's a glass beaker. - if(I.reagents.has_reagent(/datum/reagent/radium, a_transfer) && a_boost < a_maxamount) - I.reagents.remove_reagent(/datum/reagent/radium, a_transfer) - a_boost++; - to_chat(U, "There are now [a_boost] adrenaline boosts remaining.") - return - if(I.reagents.has_reagent(/datum/reagent/smoke_powder, a_transfer) && s_bombs < s_maxamount) - I.reagents.remove_reagent(/datum/reagent/smoke_powder, a_transfer) - s_bombs++; - to_chat(U, "There are now [s_bombs] smoke bombs remaining.") - return + if(istype(I, /obj/item/reagent_containers/glass) && I.reagents.has_reagent(/datum/reagent/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/radium, a_transfer) + a_boost = TRUE; + to_chat(ninja, "The suit's adrenaline boost is now reloaded.") + return else if(istype(I, /obj/item/stock_parts/cell)) var/obj/item/stock_parts/cell/CELL = I if(CELL.maxcharge > cell.maxcharge && n_gloves && n_gloves.candrain) - to_chat(U, "Higher maximum capacity detected.\nUpgrading...") - if (n_gloves && n_gloves.candrain && do_after(U,s_delay, target = src)) - U.transferItemToLoc(CELL, src) + to_chat(ninja, "Higher maximum capacity detected.\nUpgrading...") + if (n_gloves?.candrain && do_after(ninja,s_delay, target = src)) + ninja.transferItemToLoc(CELL, src) CELL.charge = min(CELL.charge+cell.charge, CELL.maxcharge) var/obj/item/stock_parts/cell/old_cell = cell old_cell.charge = 0 - U.put_in_hands(old_cell) - old_cell.add_fingerprint(U) + ninja.put_in_hands(old_cell) + old_cell.add_fingerprint(ninja) old_cell.corrupt() old_cell.update_icon() cell = CELL - to_chat(U, "Upgrade complete. Maximum capacity: [round(cell.maxcharge/100)]%") + to_chat(ninja, "Upgrade complete. Maximum capacity: [round(cell.maxcharge/100)]%") else - to_chat(U, "Procedure interrupted. Protocol terminated.") + to_chat(ninja, "Procedure interrupted. Protocol terminated.") return else if(istype(I, /obj/item/disk/tech_disk))//If it's a data disk, we want to copy the research on to the suit. var/obj/item/disk/tech_disk/TD = I var/has_research = 0 if(has_research)//If it has something on it. - to_chat(U, "Research information detected, processing...") - if(do_after(U,s_delay, target = src)) + to_chat(ninja, "Research information detected, processing...") + if(do_after(ninja,s_delay, target = src)) TD.stored_research.copy_research_to(stored_research) - to_chat(U, "Data analyzed and updated. Disk erased.") + to_chat(ninja, "Data analyzed and updated. Disk erased.") else - to_chat(U, "ERROR: Procedure interrupted. Process terminated.") + to_chat(ninja, "ERROR: Procedure interrupted. Process terminated.") else - to_chat(U, "No research information detected.") + to_chat(ninja, "No research information detected.") return return ..() diff --git a/code/modules/ninja/suit/suit_initialisation.dm b/code/modules/ninja/suit/suit_initialisation.dm deleted file mode 100644 index 3d80282fe7..0000000000 --- a/code/modules/ninja/suit/suit_initialisation.dm +++ /dev/null @@ -1,95 +0,0 @@ -/obj/item/clothing/suit/space/space_ninja/proc/toggle_on_off() - if(s_busy) - to_chat(loc, "ERROR: You cannot use this function at this time.") - return FALSE - if(s_initialized) - deinitialize() - else - ninitialize() - . = TRUE - -/obj/item/clothing/suit/space/space_ninja/proc/ninitialize(delay = s_delay, mob/living/carbon/human/U = loc) - if(!U.mind) - return //Not sure how this could happen. - s_busy = TRUE - to_chat(U, "Now initializing...") - addtimer(CALLBACK(src, .proc/ninitialize_two, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/ninitialize_two(delay, mob/living/carbon/human/U) - if(!lock_suit(U))//To lock the suit onto wearer. - s_busy = FALSE - return - to_chat(U, "Securing external locking mechanism...\nNeural-net established.") - addtimer(CALLBACK(src, .proc/ninitialize_three, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/ninitialize_three(delay, mob/living/carbon/human/U) - to_chat(U, "Extending neural-net interface...\nNow monitoring brain wave pattern...") - addtimer(CALLBACK(src, .proc/ninitialize_four, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/ninitialize_four(delay, mob/living/carbon/human/U) - if(U.stat == DEAD|| U.health <= 0) - to_chat(U, "FĆAL �Rr�R: 344--93#�&&21 BR��N |/|/aV� PATT$RN RED\nA-A-aB�rT�NG...") - unlock_suit() - s_busy = FALSE - return - lockIcons(U)//Check for icons. - U.regenerate_icons() - to_chat(U, "Linking neural-net interface...\nPattern\green GREEN, continuing operation.") - addtimer(CALLBACK(src, .proc/ninitialize_five, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/ninitialize_five(delay, mob/living/carbon/human/U) - to_chat(U, "VOID-shift device status: ONLINE.\nCLOAK-tech device status: ONLINE.") - addtimer(CALLBACK(src, .proc/ninitialize_six, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/ninitialize_six(delay, mob/living/carbon/human/U) - to_chat(U, "Primary system status: ONLINE.\nBackup system status: ONLINE.\nCurrent energy capacity: [DisplayEnergy(cell.charge)].") - addtimer(CALLBACK(src, .proc/ninitialize_seven, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/ninitialize_seven(delay, mob/living/carbon/human/U) - to_chat(U, "All systems operational. Welcome to SpiderOS, [U.real_name].") - s_initialized = TRUE - START_PROCESSING(SSprocessing, src) - s_busy = FALSE - - - -/obj/item/clothing/suit/space/space_ninja/proc/deinitialize(delay = s_delay) - if(affecting==loc) - var/mob/living/carbon/human/U = affecting - if(alert("Are you certain you wish to remove the suit? This will take time and remove all abilities.",,"Yes","No")=="No") - return - s_busy = TRUE - addtimer(CALLBACK(src, .proc/deinitialize_two, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/deinitialize_two(delay, mob/living/carbon/human/U) - to_chat(U, "Now de-initializing...") - addtimer(CALLBACK(src, .proc/deinitialize_three, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/deinitialize_three(delay, mob/living/carbon/human/U) - to_chat(U, "Logging off, [U.real_name]. Shutting down SpiderOS.") - addtimer(CALLBACK(src, .proc/deinitialize_four, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/deinitialize_four(delay, mob/living/carbon/human/U) - to_chat(U, "Primary system status: OFFLINE.\nBackup system status: OFFLINE.") - addtimer(CALLBACK(src, .proc/deinitialize_five, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/deinitialize_five(delay, mob/living/carbon/human/U) - to_chat(U, "VOID-shift device status: OFFLINE.\nCLOAK-tech device status: OFFLINE.") - cancel_stealth()//Shutdowns stealth. - addtimer(CALLBACK(src, .proc/deinitialize_six, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/deinitialize_six(delay, mob/living/carbon/human/U) - to_chat(U, "Disconnecting neural-net interface...\greenSuccess.") - addtimer(CALLBACK(src, .proc/deinitialize_seven, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/deinitialize_seven(delay, mob/living/carbon/human/U) - to_chat(U, "Disengaging neural-net interface...\greenSuccess.") - addtimer(CALLBACK(src, .proc/deinitialize_eight, delay, U), delay) - -/obj/item/clothing/suit/space/space_ninja/proc/deinitialize_eight(delay, mob/living/carbon/human/U) - to_chat(U, "Unsecuring external locking mechanism...\nNeural-net abolished.\nOperation status: FINISHED.") - unlock_suit() - U.regenerate_icons() - s_initialized = FALSE - STOP_PROCESSING(SSprocessing, src) - s_busy = FALSE diff --git a/code/modules/ninja/suit/suit_process.dm b/code/modules/ninja/suit/suit_process.dm deleted file mode 100644 index 5c1276e29a..0000000000 --- a/code/modules/ninja/suit/suit_process.dm +++ /dev/null @@ -1,17 +0,0 @@ -/obj/item/clothing/suit/space/space_ninja/process() - if(!affecting || !s_initialized) - return PROCESS_KILL - - if(cell.charge > 0) - if(s_coold) - s_coold--//Checks for ability s_cooldown first. - - cell.charge -= s_cost//s_cost is the default energy cost each tick, usually 5. - if(stealth && stealth_cooldown <= world.time)//If stealth is active. - cell.charge -= s_acost - affecting.alpha = max(affecting.alpha - 10, 15) - - else - cell.charge = 0 - if(stealth) - cancel_stealth() diff --git a/code/modules/surgery/bodyparts/parts.dm b/code/modules/surgery/bodyparts/parts.dm index 3a08a764d3..e66f14da93 100644 --- a/code/modules/surgery/bodyparts/parts.dm +++ b/code/modules/surgery/bodyparts/parts.dm @@ -59,13 +59,13 @@ one though." icon_state = "default_human_l_arm" attack_verb = list("slapped", "punched") - max_damage = 150 + max_damage = 50 disable_threshold = 75 max_stamina_damage = 50 body_zone = BODY_ZONE_L_ARM body_part = ARM_LEFT aux_icons = list(BODY_ZONE_PRECISE_L_HAND = HANDS_PART_LAYER, "l_hand_behind" = BODY_BEHIND_LAYER) - body_damage_coeff = 0.25 + body_damage_coeff = 0.75 held_index = 1 px_x = -6 px_y = 0 @@ -121,12 +121,12 @@ among humans missing their right arm." icon_state = "default_human_r_arm" attack_verb = list("slapped", "punched") - max_damage = 150 + max_damage = 50 disable_threshold = 75 body_zone = BODY_ZONE_R_ARM body_part = ARM_RIGHT aux_icons = list(BODY_ZONE_PRECISE_R_HAND = HANDS_PART_LAYER, "r_hand_behind" = BODY_BEHIND_LAYER) - body_damage_coeff = 0.25 + body_damage_coeff = 0.75 held_index = 2 px_x = 6 px_y = 0 @@ -184,11 +184,11 @@ luck. In this instance, it probably would not have helped." icon_state = "default_human_l_leg" attack_verb = list("kicked", "stomped") - max_damage = 150 + max_damage = 50 disable_threshold = 75 body_zone = BODY_ZONE_L_LEG body_part = LEG_LEFT - body_damage_coeff = 0.25 + body_damage_coeff = 0.75 px_x = -2 px_y = 12 stam_heal_tick = STAM_RECOVERY_LIMB @@ -243,11 +243,10 @@ // alternative spellings of 'pokey' are availible icon_state = "default_human_r_leg" attack_verb = list("kicked", "stomped") - max_damage = 150 - disable_threshold = 75 + max_damage = 50 body_zone = BODY_ZONE_R_LEG body_part = LEG_RIGHT - body_damage_coeff = 0.25 + body_damage_coeff = 0.75 px_x = 2 px_y = 12 max_stamina_damage = 50 diff --git a/html/changelog.html b/html/changelog.html index dabd4e7704..6cf78fb190 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -50,6 +50,70 @@ -->
+

20 September 2021

+

BlueWildrose updated:

+ +

DeltaFire15 updated:

+ +

Putnam3145 updated:

+ +

buffyuwu updated:

+ +

dapnee updated:

+ +

keronshb updated:

+ +

qweq12yt updated:

+ +

timothyteakettle updated:

+ +

zeroisthebiggay updated:

+ +

18 September 2021

kiwedespars updated:

GoonStation 13 Development Team diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index e4e1fba1c6..46d15762db 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -30003,3 +30003,58 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. 2021-09-18: kiwedespars: - balance: blacklisted morphine and haloperidol from dart guns +2021-09-20: + BlueWildrose: + - balance: Slime regenerative extracts now require five seconds of wait before they + are used. They add 25 disgust when used. + DeltaFire15: + - bugfix: Catsurgeons should now spawn at more reasonable locations if possible. + - balance: carded AIs can now be converted by conversion sigils (clockcult) + - bugfix: There is now a way to acquire nanite storage protocols (bepis, like the + other protocols), as opposed to them existing with no way to acquire them. + - bugfix: Plastic golems are back to ventcrawler_nude instead of ventcrawler_always + Putnam3145: + - config: monstermos config added, disabled + buffyuwu: + - bugfix: fixed medihound sleeper ui display + - rscadd: Adds 4 redesigned jackets and 2 redesigned shirts to loadout + - bugfix: Holoparasites no long rename and recolor on relog + dapnee: + - bugfix: attaches an air vent that was just there on the AI sat, changes some areas + to what they'd logically be + keronshb: + - bugfix: Plague Rats will no longer spawn thousands of dirt decals + - bugfix: Plague Rats will no longer spawn thousands of corpses + - bugfix: Plague Rats can't spawn or transform off station z anymore + - bugfix: Plague Rats shouldn't explosively grow instantly + - bugfix: Plague Rats won't spawn infinite miasma anymore. + - balance: Plague Rats health is now 100. + - balance: Plague Rats can now ventcrawl through everything to prevent farming. + - bugfix: Slaughter Demons Slam will now wound again on hit. + - balance: Damage for demons back up to 30 + - balance: 'Wound Bonus for demons now at 0. image_add: Adds a sprite for the action + bar' + - refactor: Changed the CTRL+SHIFT Click to an action button. People can see the + cooldown now too. + - rscadd: PAIs can be emagged to reset master + qweq12yt: + - bugfix: Fixed space heaters not being able to be interacted/turned on in non powered + areas + timothyteakettle: + - bugfix: removes passkey from access circuits as its not used anymore + - rscadd: a new mild trauma, **[REDACTED]** + zeroisthebiggay: + - balance: glass has do_after + - bugfix: box perma has power + - bugfix: missing madness mask sprites + - balance: The Spider Clan has recently taken up the Space Ninja project again along + with the Syndicate. Space Ninjas have been drastically changed as a result, + becoming much weaker and more stealth oriented. As a result of cutting costs + per ninja, more ninjas were able to be hired. Expect to see them around more + often. + - bugfix: prisoners cannot latejoin anymore + - bugfix: bone satchel onmob sprites + - rscadd: new tips + - rscdel: old tips + - imageadd: all medipens get inhands + - rscadd: some more brainhurt lines diff --git a/html/changelogs/AutoChangeLog-pr-15074.yml b/html/changelogs/AutoChangeLog-pr-15074.yml deleted file mode 100644 index 5da0c10a10..0000000000 --- a/html/changelogs/AutoChangeLog-pr-15074.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "keronshb" -delete-after: True -changes: - - rscadd: "PAIs can be emagged to reset master" diff --git a/html/changelogs/AutoChangeLog-pr-15084.yml b/html/changelogs/AutoChangeLog-pr-15084.yml deleted file mode 100644 index 6c99cc159d..0000000000 --- a/html/changelogs/AutoChangeLog-pr-15084.yml +++ /dev/null @@ -1,10 +0,0 @@ -author: "keronshb" -delete-after: True -changes: - - bugfix: "Plague Rats will no longer spawn thousands of dirt decals" - - bugfix: "Plague Rats will no longer spawn thousands of corpses" - - bugfix: "Plague Rats can't spawn or transform off station z anymore" - - bugfix: "Plague Rats shouldn't explosively grow instantly" - - bugfix: "Plague Rats won't spawn infinite miasma anymore." - - balance: "Plague Rats health is now 100." - - balance: "Plague Rats can now ventcrawl through everything to prevent farming." diff --git a/html/changelogs/AutoChangeLog-pr-15094.yml b/html/changelogs/AutoChangeLog-pr-15094.yml deleted file mode 100644 index 21dcf75960..0000000000 --- a/html/changelogs/AutoChangeLog-pr-15094.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "zeroisthebiggay" -delete-after: True -changes: - - balance: "glass has do_after" diff --git a/html/changelogs/AutoChangeLog-pr-15119.yml b/html/changelogs/AutoChangeLog-pr-15119.yml deleted file mode 100644 index ee7100fd9b..0000000000 --- a/html/changelogs/AutoChangeLog-pr-15119.yml +++ /dev/null @@ -1,8 +0,0 @@ -author: "keronshb" -delete-after: True -changes: - - bugfix: "Slaughter Demons Slam will now wound again on hit." - - balance: "Damage for demons back up to 30" - - balance: "Wound Bonus for demons now at 0. -image_add: Adds a sprite for the action bar" - - refactor: "Changed the CTRL+SHIFT Click to an action button. People can see the cooldown now too." diff --git a/html/changelogs/AutoChangeLog-pr-15133.yml b/html/changelogs/AutoChangeLog-pr-15133.yml deleted file mode 100644 index 3bc023735f..0000000000 --- a/html/changelogs/AutoChangeLog-pr-15133.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "zeroisthebiggay" -delete-after: True -changes: - - rscadd: "new tips" - - rscdel: "old tips" diff --git a/html/changelogs/AutoChangeLog-pr-15134.yml b/html/changelogs/AutoChangeLog-pr-15134.yml deleted file mode 100644 index 2a71bd9aa0..0000000000 --- a/html/changelogs/AutoChangeLog-pr-15134.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "zeroisthebiggay" -delete-after: True -changes: - - rscadd: "some more brainhurt lines" diff --git a/html/changelogs/AutoChangeLog-pr-15137.yml b/html/changelogs/AutoChangeLog-pr-15137.yml deleted file mode 100644 index eef278a6ea..0000000000 --- a/html/changelogs/AutoChangeLog-pr-15137.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - balance: "carded AIs can now be converted by conversion sigils (clockcult)" diff --git a/html/changelogs/AutoChangeLog-pr-15139.yml b/html/changelogs/AutoChangeLog-pr-15139.yml deleted file mode 100644 index 001897e223..0000000000 --- a/html/changelogs/AutoChangeLog-pr-15139.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "Catsurgeons should now spawn at more reasonable locations if possible." diff --git a/html/changelogs/AutoChangeLog-pr-15143.yml b/html/changelogs/AutoChangeLog-pr-15143.yml deleted file mode 100644 index d4e2141937..0000000000 --- a/html/changelogs/AutoChangeLog-pr-15143.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "zeroisthebiggay" -delete-after: True -changes: - - bugfix: "box perma has power" diff --git a/html/changelogs/AutoChangeLog-pr-15144.yml b/html/changelogs/AutoChangeLog-pr-15144.yml deleted file mode 100644 index 860f1a60cc..0000000000 --- a/html/changelogs/AutoChangeLog-pr-15144.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "zeroisthebiggay" -delete-after: True -changes: - - bugfix: "bone satchel onmob sprites" diff --git a/html/changelogs/AutoChangeLog-pr-15147.yml b/html/changelogs/AutoChangeLog-pr-15147.yml deleted file mode 100644 index 09f98404fd..0000000000 --- a/html/changelogs/AutoChangeLog-pr-15147.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - config: "monstermos config added, disabled" diff --git a/html/changelogs/AutoChangeLog-pr-15154.yml b/html/changelogs/AutoChangeLog-pr-15154.yml deleted file mode 100644 index 756cc2bfb7..0000000000 --- a/html/changelogs/AutoChangeLog-pr-15154.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "qweq12yt" -delete-after: True -changes: - - bugfix: "Fixed space heaters not being able to be interacted/turned on in non powered areas" diff --git a/html/changelogs/AutoChangeLog-pr-15156.yml b/html/changelogs/AutoChangeLog-pr-15156.yml deleted file mode 100644 index 4d74820ca3..0000000000 --- a/html/changelogs/AutoChangeLog-pr-15156.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "zeroisthebiggay" -delete-after: True -changes: - - bugfix: "missing madness mask sprites" diff --git a/html/changelogs/AutoChangeLog-pr-15157.yml b/html/changelogs/AutoChangeLog-pr-15157.yml deleted file mode 100644 index b3f0b8eaba..0000000000 --- a/html/changelogs/AutoChangeLog-pr-15157.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "There is now a way to acquire nanite storage protocols (bepis, like the other protocols), as opposed to them existing with no way to acquire them." diff --git a/html/changelogs/AutoChangeLog-pr-15160.yml b/html/changelogs/AutoChangeLog-pr-15160.yml deleted file mode 100644 index da0d68f52f..0000000000 --- a/html/changelogs/AutoChangeLog-pr-15160.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - bugfix: "removes passkey from access circuits as its not used anymore" diff --git a/html/changelogs/AutoChangeLog-pr-15162.yml b/html/changelogs/AutoChangeLog-pr-15162.yml deleted file mode 100644 index 926f0898d1..0000000000 --- a/html/changelogs/AutoChangeLog-pr-15162.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "zeroisthebiggay" -delete-after: True -changes: - - bugfix: "prisoners cannot latejoin anymore" diff --git a/html/changelogs/AutoChangeLog-pr-15163.yml b/html/changelogs/AutoChangeLog-pr-15163.yml deleted file mode 100644 index 3fe5ba69ee..0000000000 --- a/html/changelogs/AutoChangeLog-pr-15163.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "buffyuwu" -delete-after: True -changes: - - rscadd: "Adds 4 redesigned jackets and 2 redesigned shirts to loadout" diff --git a/html/changelogs/AutoChangeLog-pr-15167.yml b/html/changelogs/AutoChangeLog-pr-15167.yml deleted file mode 100644 index 1c13dfc56f..0000000000 --- a/html/changelogs/AutoChangeLog-pr-15167.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "BlueWildrose" -delete-after: True -changes: - - balance: "Slime regenerative extracts now require five seconds of wait before they are used. They add 25 disgust when used." diff --git a/html/changelogs/AutoChangeLog-pr-15168.yml b/html/changelogs/AutoChangeLog-pr-15168.yml deleted file mode 100644 index 4f040b4580..0000000000 --- a/html/changelogs/AutoChangeLog-pr-15168.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "dapnee" -delete-after: True -changes: - - bugfix: "attaches an air vent that was just there on the AI sat, changes some areas to what they'd logically be" diff --git a/html/changelogs/AutoChangeLog-pr-15169.yml b/html/changelogs/AutoChangeLog-pr-15169.yml deleted file mode 100644 index f3af23ac39..0000000000 --- a/html/changelogs/AutoChangeLog-pr-15169.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - rscadd: "a new mild trauma, **[REDACTED]**" diff --git a/html/changelogs/AutoChangeLog-pr-15171.yml b/html/changelogs/AutoChangeLog-pr-15171.yml deleted file mode 100644 index 958d61e87c..0000000000 --- a/html/changelogs/AutoChangeLog-pr-15171.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "Plastic golems are back to ventcrawler_nude instead of ventcrawler_always" diff --git a/html/changelogs/AutoChangeLog-pr-15174.yml b/html/changelogs/AutoChangeLog-pr-15174.yml deleted file mode 100644 index 79b3b9400f..0000000000 --- a/html/changelogs/AutoChangeLog-pr-15174.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "buffyuwu" -delete-after: True -changes: - - bugfix: "Holoparasites no long rename and recolor on relog" diff --git a/html/changelogs/AutoChangeLog-pr-15176.yml b/html/changelogs/AutoChangeLog-pr-15176.yml deleted file mode 100644 index 3335997a85..0000000000 --- a/html/changelogs/AutoChangeLog-pr-15176.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "buffyuwu" -delete-after: True -changes: - - bugfix: "fixed medihound sleeper ui display" diff --git a/html/changelogs/AutoChangeLog-pr-15178.yml b/html/changelogs/AutoChangeLog-pr-15178.yml deleted file mode 100644 index 3f4debbc45..0000000000 --- a/html/changelogs/AutoChangeLog-pr-15178.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "zeroisthebiggay" -delete-after: True -changes: - - imageadd: "all medipens get inhands" diff --git a/html/changelogs/AutoChangeLog-pr-15181.yml b/html/changelogs/AutoChangeLog-pr-15181.yml new file mode 100644 index 0000000000..9b8e2d63a7 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-15181.yml @@ -0,0 +1,4 @@ +author: "silicons" +delete-after: True +changes: + - bugfix: "dice bags can only hold dice" diff --git a/html/changelogs/AutoChangeLog-pr-15182.yml b/html/changelogs/AutoChangeLog-pr-15182.yml new file mode 100644 index 0000000000..c6e05740b6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-15182.yml @@ -0,0 +1,4 @@ +author: "silicons" +delete-after: True +changes: + - rscdel: "limb damage changes reverted" diff --git a/html/changelogs/AutoChangeLog-pr-15184.yml b/html/changelogs/AutoChangeLog-pr-15184.yml new file mode 100644 index 0000000000..0e4115ec31 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-15184.yml @@ -0,0 +1,4 @@ +author: "silicons" +delete-after: True +changes: + - bugfix: "crawling can't be adrenals'd" diff --git a/icons/mob/clothing/belt.dmi b/icons/mob/clothing/belt.dmi index a40a8a72dd..2338fa37a0 100644 Binary files a/icons/mob/clothing/belt.dmi and b/icons/mob/clothing/belt.dmi differ diff --git a/icons/mob/clothing/feet.dmi b/icons/mob/clothing/feet.dmi index df40636049..4b732f13fe 100644 Binary files a/icons/mob/clothing/feet.dmi and b/icons/mob/clothing/feet.dmi differ diff --git a/icons/mob/clothing/feet_digi.dmi b/icons/mob/clothing/feet_digi.dmi index 7215875f2c..e82ae468e2 100644 Binary files a/icons/mob/clothing/feet_digi.dmi and b/icons/mob/clothing/feet_digi.dmi differ diff --git a/icons/mob/clothing/hands.dmi b/icons/mob/clothing/hands.dmi index 556bc4fd9d..28f28edaca 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 1596672ac3..3b6af60828 100644 Binary files a/icons/mob/clothing/head.dmi and b/icons/mob/clothing/head.dmi differ diff --git a/icons/mob/clothing/head_muzzled.dmi b/icons/mob/clothing/head_muzzled.dmi index 2fce92ee81..d3f05135c1 100644 Binary files a/icons/mob/clothing/head_muzzled.dmi and b/icons/mob/clothing/head_muzzled.dmi differ diff --git a/icons/mob/clothing/mask.dmi b/icons/mob/clothing/mask.dmi index 075464ace5..17a49ea751 100644 Binary files a/icons/mob/clothing/mask.dmi and b/icons/mob/clothing/mask.dmi differ diff --git a/icons/mob/clothing/mask_muzzled.dmi b/icons/mob/clothing/mask_muzzled.dmi index 9da3545c65..9f483c8d47 100644 Binary files a/icons/mob/clothing/mask_muzzled.dmi and b/icons/mob/clothing/mask_muzzled.dmi differ diff --git a/icons/mob/clothing/suit.dmi b/icons/mob/clothing/suit.dmi index b4ecbdfb2a..48759bf81c 100644 Binary files a/icons/mob/clothing/suit.dmi and b/icons/mob/clothing/suit.dmi differ diff --git a/icons/mob/clothing/suit_digi.dmi b/icons/mob/clothing/suit_digi.dmi index 80259e2832..13840507a6 100644 Binary files a/icons/mob/clothing/suit_digi.dmi and b/icons/mob/clothing/suit_digi.dmi differ diff --git a/icons/mob/inhands/weapons/swords_lefthand.dmi b/icons/mob/inhands/weapons/swords_lefthand.dmi index 4be0df2300..62e48f626b 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 57308ffb76..658e7304df 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/mob/robots.dmi b/icons/mob/robots.dmi index 082bfb3c3e..21af40ff8f 100644 Binary files a/icons/mob/robots.dmi and b/icons/mob/robots.dmi differ diff --git a/icons/mob/talk.dmi b/icons/mob/talk.dmi index 0a56321037..beb38f01cc 100644 Binary files a/icons/mob/talk.dmi and b/icons/mob/talk.dmi differ diff --git a/icons/obj/clothing/gloves.dmi b/icons/obj/clothing/gloves.dmi index 9df096d19b..4d2ddcf6bd 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 7d4ae79957..3ebd15a511 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 1e2449329d..b6839de219 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 77d1d026b2..ab6cea5a3b 100644 Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ diff --git a/icons/obj/grenade.dmi b/icons/obj/grenade.dmi index d6dd4c1b00..e2f06621e4 100644 Binary files a/icons/obj/grenade.dmi and b/icons/obj/grenade.dmi differ diff --git a/icons/obj/items_and_weapons.dmi b/icons/obj/items_and_weapons.dmi index 39f1845f43..454e174550 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 c4de2a1799..204b69a11b 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -463,7 +463,6 @@ #include "code\datums\achievements\misc_scores.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" @@ -1738,7 +1737,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" @@ -1761,6 +1759,7 @@ #include "code\modules\antagonists\slaughter\slaughter.dm" #include "code\modules\antagonists\slaughter\slaughter_antag.dm" #include "code\modules\antagonists\slaughter\slaughterevent.dm" +#include "code\modules\antagonists\space_ninja\space_ninja.dm" #include "code\modules\antagonists\space_dragon\space_dragon.dm" #include "code\modules\antagonists\survivalist\survivalist.dm" #include "code\modules\antagonists\swarmer\swarmer.dm" @@ -2133,6 +2132,7 @@ #include "code\modules\events\radiation_storm.dm" #include "code\modules\events\sentience.dm" #include "code\modules\events\shuttle_loan.dm" +#include "code\modules\events\space_ninja.dm" #include "code\modules\events\space_dragon.dm" #include "code\modules\events\spacevine.dm" #include "code\modules\events\spider_infestation.dm" @@ -2977,7 +2977,7 @@ #include "code\modules\newscaster\wanted_message.dm" #include "code\modules\ninja\__ninjaDefines.dm" #include "code\modules\ninja\energy_katana.dm" -#include "code\modules\ninja\ninja_event.dm" +#include "code\modules\ninja\ninja_explosive.dm" #include "code\modules\ninja\outfit.dm" #include "code\modules\ninja\suit\gloves.dm" #include "code\modules\ninja\suit\head.dm" @@ -2986,17 +2986,17 @@ #include "code\modules\ninja\suit\shoes.dm" #include "code\modules\ninja\suit\suit.dm" #include "code\modules\ninja\suit\suit_attackby.dm" -#include "code\modules\ninja\suit\suit_initialisation.dm" -#include "code\modules\ninja\suit\suit_process.dm" -#include "code\modules\ninja\suit\n_suit_verbs\energy_net_nets.dm" -#include "code\modules\ninja\suit\n_suit_verbs\ninja_adrenaline.dm" -#include "code\modules\ninja\suit\n_suit_verbs\ninja_cost_check.dm" -#include "code\modules\ninja\suit\n_suit_verbs\ninja_empulse.dm" -#include "code\modules\ninja\suit\n_suit_verbs\ninja_net.dm" -#include "code\modules\ninja\suit\n_suit_verbs\ninja_smoke.dm" -#include "code\modules\ninja\suit\n_suit_verbs\ninja_stars.dm" -#include "code\modules\ninja\suit\n_suit_verbs\ninja_stealth.dm" -#include "code\modules\ninja\suit\n_suit_verbs\ninja_sword_recall.dm" +#include "code\modules\ninja\suit\ninja_equipment_actions\energy_net_nets.dm" +#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_adrenaline.dm" +#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_cost_check.dm" +#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_empulse.dm" +#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_glove_toggle.dm" +#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_net.dm" +#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_stars.dm" +#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_status_read.dm" +#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_stealth.dm" +#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_suit_initialisation.dm" +#include "code\modules\ninja\suit\ninja_equipment_actions\ninja_sword_recall.dm" #include "code\modules\NTNet\netdata.dm" #include "code\modules\NTNet\network.dm" #include "code\modules\NTNet\relays.dm"