Merge branch 'Citadel-Station-13:master' into master

This commit is contained in:
WanderingFox95
2021-09-21 14:56:38 +02:00
committed by GitHub
106 changed files with 1599 additions and 1356 deletions
+8
View File
@@ -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"
+13
View File
@@ -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]
-51
View File
@@ -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'
+1
View File
@@ -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
@@ -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!
+11
View File
@@ -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 = "<span class='userdanger'>Network Alert: Hacking attempt detected[get_area(src)?" in [get_area_name(src, TRUE)]":". Unable to pinpoint location"].</span>"
for(var/mob/living/silicon/ai/AI in GLOB.player_list)
to_chat(AI, alertstr)
+5
View File
@@ -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)
+6 -4
View File
@@ -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)
+1 -1
View File
@@ -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)
+2 -2
View File
@@ -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()
-146
View File
@@ -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 <font color='red'><B>SPACE NINJA</B></font>!<br>"
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)!<br>"
antag_memory += "Officially, [helping_station?"Nanotrasen":"The Syndicate"] are my employer.<br>"
/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 <font color='red'><B>SPACE NINJA</B></font>!")
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)
@@ -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
..()
@@ -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 <font color='red'><B>SPACE NINJA</B></font>!<br>"
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)!<br>"
/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 <font color='red'><B>SPACE NINJA</B></font>!")
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)].")
@@ -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()
. = ..()
+51
View File
@@ -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
+10 -1
View File
@@ -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, "<br><span class='userdanger'>!!READ THIS!!</span><br><span class='warning'>The following is server-specific policy configuration and overrides anything said above if conflicting.</span>")
to_chat(found, "<br><br>")
to_chat(found, "<span class='boldnotice'>[policy]</span>")
/datum/outfit/job/prisoner
name = "Prisoner"
jobtype = /datum/job/prisoner
@@ -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)
@@ -811,6 +811,32 @@
<i>Help the operatives secure the disk at all costs!</i></b>"
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 = "<span class='big bold'>You are a Spider Clan assault cyborg!</span><br>\
<b>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.</b>"
set_module = /obj/item/robot_module/syndicate/spider
/mob/living/silicon/robot/modules/syndicate_medical/spider// ditto
bubble_icon = "spider"
var/playstyle_string = "<span class='big bold'>You are a Spider Clan medical cyborg!</span><br>\
<b>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.</b>"
set_module = /obj/item/robot_module/syndicate_medical/spider
/mob/living/silicon/robot/modules/saboteur/spider// ditto
bubble_icon = "spider"
var/playstyle_string = "<span class='big bold'>You are a Spider Clan saboteur cyborg!</span><br>\
<b>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.</b>"
set_module = /obj/item/robot_module/saboteur/spider
/mob/living/silicon/robot/proc/notify_ai(notifytype, oldname, newname)
if(!connected_ai)
return
@@ -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"
@@ -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, "<b>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!</b>")
var/list/policies = CONFIG_GET(keyed_list/policy)
var/policy = policies[POLICYCONFIG_ELITE_SPAWN]
if(policy)
to_chat(elitemind, "<br><span class='userdanger'>!!READ THIS!!</span><br><span class='warning'>The following is server-specific policy configuration and overrides anything said above if conflicting.</span>")
to_chat(elitemind, "<br><br>")
to_chat(elitemind, "<span class='boldnotice'>[policy]</span>")
addtimer(CALLBACK(src, .proc/spawn_elite, elitemind), 100)
else
visible_message("<span class='boldwarning'>The stirring stops, and nothing emerges. Perhaps try again later.</span>")
@@ -304,6 +310,12 @@ While using this makes the system rely on OnFire, it still gives options for tim
to_chat(mychild, "<span class='boldwarning'>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.</span>")
to_chat(mychild, "<b>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!</b>")
to_chat(mychild, "<span class='big bold'>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!</span>")
var/list/policies = CONFIG_GET(keyed_list/policy)
var/policy = policies[POLICYCONFIG_ELITE_WIN]
if(policy)
to_chat(mychild, "<br><span class='userdanger'>!!READ THIS!!</span><br><span class='warning'>The following is server-specific policy configuration and overrides anything said above if conflicting.</span>")
to_chat(mychild, "<br><br>")
to_chat(mychild, "<span class='boldnotice'>[policy]</span>")
/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, "<span class='userdanger'>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.</span")
to_chat(E, "<span class='big bold'>Note that you now share the loyalties of [user]. You are expected not to intentionally sabotage their faction unless commanded to!</span>")
var/list/policies = CONFIG_GET(keyed_list/policy)
var/policy = policies[POLICYCONFIG_ELITE_SENTIENCE]
if(policy)
to_chat(E, "<br><span class='userdanger'>!!READ THIS!!</span><br><span class='warning'>The following is server-specific policy configuration and overrides anything said above if conflicting.</span>")
to_chat(E, "<br><br>")
to_chat(E, "<span class='boldnotice'>[policy]</span>")
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."
+1
View File
@@ -113,6 +113,7 @@
multiplicative_slowdown = CRAWLING_ADD_SLOWDOWN
movetypes = CRAWLING
flags = IGNORE_NOSLOW
priority = 20000
/datum/movespeed_modifier/mob_config_speedmod
variable = TRUE
+15 -14
View File
@@ -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))
+48 -22
View File
@@ -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, "<span class='warning'><b>ERROR</b>: garments incompatible with carbon material jaunt. Please suit up in compatible garments.</span>")
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, "<span class='warning'><b>ERROR</b>: suit is on cooldown.</span>")
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, "<span class='notice'>[msg]</span>")
/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
-93
View File
@@ -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
+45
View File
@@ -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, "<span class='notice'>You fiddle with the charge, but nothing happens.</span>")
return
var/datum/objective/plant_explosive/objective = locate() in ninja_antag.objectives
if(!objective)
to_chat(user, "<span class='notice'>You can't seem to activate the charge. It's location-locked, but you don't know where to detonate it.</span>")
return
if(objective.detonation_location != get_area(user))
to_chat(user, "<span class='notice'>This isn't the location you're supposed to use this!</span>")
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, "<span class='notice'>The wire panel is locked in place, clearly you aren't supposed to be opening it!</span>")
return
+4 -6
View File
@@ -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()
+38 -36
View File
@@ -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, "<span class='notice'>Gained <B>[DisplayEnergy(.)]</B> of energy from [A].</span>")
to_chat(wearer, "<span class='notice'>Gained <B>[DisplayEnergy(.)]</B> of energy from [A].</span>")
else
to_chat(H, "<span class='danger'>\The [A] has run dry of energy, you must find another source!</span>")
to_chat(wearer, "<span class='danger'>\The [A] has run dry of energy, you must find another source!</span>")
. = 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 <b>[candrain?"disable":"enable"]</b> 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 <B>[candrain?"active":"inactive"]</B>."
/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
+10 -5
View File
@@ -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)
+8 -12
View File
@@ -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."
@@ -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!", "<span class='italics'>You hear a grunt.</span>")
if(!QDELETED(master))//As long as they still exist.
to_chat(master, "<span class='userdanger'>ERROR</span>: 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, "<span class='danger'>You appear in a strange place!</span>")
if(!QDELETED(master))//As long as they still exist.
to_chat(master, "<span class='notice'><b>SUCCESS</b>: transport procedure of [affecting] complete.</span>")
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
@@ -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), "<span class='boldnotice'>You feel a sudden surge of energy!</span>")
H.say(pick("A CORNERED FOX IS MORE DANGEROUS THAN A JACKAL!","HURT ME MOOORRREEE!","IMPRESSIVE!"), forced = "ninjaboost")
a_boost--
to_chat(H, "<span class='notice'>There are <B>[a_boost]</B> adrenaline boosts remaining.</span>")
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, "<span class='danger'>You are beginning to feel the after-effect of the injection.</span>")
@@ -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, "<span class='danger'>Not enough energy.</span>")
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, "<span class='danger'>There are no more smoke bombs remaining.</span>")
return 1
if(N_ADRENALINE)
if(!a_boost)
to_chat(H, "<span class='danger'>You do not have any more adrenaline boosters.</span>")
return 1
return (s_coold)//Returns the value of the variable which counts down to zero.
@@ -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
@@ -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("<span class='danger'>[H] caught [C] with an energy net!</span>","<span class='notice'>You caught [C] with an energy net!</span>")
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)
@@ -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, "<span class='notice'>There are <B>[s_bombs]</B> smoke bombs remaining.</span>")
s_coold = 1
@@ -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, "<span class='notice'>A throwing star has been created in your hand!</span>")
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)
@@ -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, "<span class='warning'>You don't have enough power to enable Stealth!</span>")
return
stealth = TRUE
stealth_cooldown = world.time + 5 SECONDS
animate(affecting, alpha = 15, time = 3 SECONDS)
affecting.visible_message("<span class='warning'>[affecting.name] vanishes into thin air!</span>", \
"<span class='notice'>You are now mostly invisible to normal detection.</span>")
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("<span class='warning'>[affecting.name] appears from thin air!</span>", \
"<span class='notice'>You are now visible.</span>")
return TRUE
/obj/item/clothing/suit/space/space_ninja/proc/stealth()
if(!s_busy)
toggle_stealth()
else
to_chat(affecting, "<span class='danger'>Stealth does not appear to work!</span>")
@@ -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, "<span class='warning'>Could not locate Energy Katana!</span>")
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("<span class='danger'>\the [energyKatana] flies towards [H]!</span>","<span class='warning'>You hold out your hand and \the [energyKatana] flies towards you!</span>")
energyKatana.throw_at(H, distance+1, energyKatana.throw_speed,H)
else //Else just TP it to us.
energyKatana.returnToOwner(H,1)
+193 -141
View File
@@ -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 = "<span class='userdanger'>Network Alert: Hacking attempt detected[location?" in [location]":". Unable to pinpoint location"]</span>."
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, "<span class='notice'>Hacking \the [src]...</span>")
to_chat(ninja, "<span class='notice'>Hacking \the [src]...</span>")
AI_notify_hack()
if(stored_research)
to_chat(H, "<span class='notice'>Copying files...</span>")
if(do_after(H, S.s_delay, target = src) && G.candrain && src)
stored_research.copy_research_to(S.stored_research)
to_chat(H, "<span class='notice'>Data analyzed. Process finished.</span>")
to_chat(ninja, "<span class='notice'>Copying files...</span>")
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, "<span class='notice'>Data analyzed. Process finished.</span>")
//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, "<span class='notice'>Hacking \the [src]...</span>")
to_chat(ninja, "<span class='notice'>Hacking \the [src]...</span>")
AI_notify_hack()
if(stored_research)
to_chat(H, "<span class='notice'>Copying files...</span>")
if(do_after(H, S.s_delay, target = src) && G.candrain && src)
stored_research.copy_research_to(S.stored_research)
to_chat(H, "<span class='notice'>Data analyzed. Process finished.</span>")
to_chat(ninja, "<span class='notice'>Copying files...</span>")
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, "<span class='notice'>Data analyzed. Process finished.</span>")
//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, "<span class='notice'>Hacking \the [src]...</span>")
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, "<span class='notice'>Security record corruption malware uploaded. Process finished; objective completed.</span>")
//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, "<span class='notice'>Hacking \the [src]...</span>")
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, "<span class='notice'>Signal decryption malware uploaded. Process finished; objective completed.</span>")
//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("<span class='danger'>Warning: Unauthorized access through sub-route 4, block H, detected.</span>")
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, "<span class='danger'>Warni-***BZZZZZZZZZRT*** UPLOADING SPYDERPATCHER VERSION 9.5.2...</span>")
if (do_after(ninja, 60, target = src))
spark_system.start()
playsound(loc, "sparks", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
to_chat(src, "<span class='danger'>UPLOAD COMPLETE. NEW CYBORG MODULE DETECTED. INSTALLING...</span>")
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, "<span class='danger'>Warning: Unauthorized access through sub-route 12, block C, detected.</span>")
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("<span class='danger'>[H] electrocutes [src] with [H.p_their()] touch!</span>", "<span class='userdanger'>[H] electrocutes you with [H.p_their()] touch!</span>")
electrocute_act(15, H, flags = SHOCK_NOSTUN)
visible_message("<span class='danger'>[ninja] electrocutes [src] with [ninja.p_their()] touch!</span>", "<span class='userdanger'>[ninja] electrocutes you with [ninja.p_their()] touch!</span>")
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)
@@ -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("<span class='notice'>[affecting.name] is recovered from the energy net!</span>", "<span class='notice'>You are recovered from the energy net!</span>", "<span class='hear'>You hear a grunt.</span>")
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
@@ -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), "<span class='boldnotice'>You feel a sudden surge of energy!</span>")
ninja.say(pick("A CORNERED FOX IS MORE DANGEROUS THAN A JACKAL!","HURT ME MOOORRREEE!","IMPRESSIVE!"), forced = "ninjaboost")
a_boost = FALSE
to_chat(ninja, "<span class='notice'>You have used the adrenaline boost.</span>")
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, "<span class='danger'>You are beginning to feel the after-effect of the injection.</span>")
@@ -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, "<span class='warning'>Not enough energy!</span>")
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, "<span class='warning'>You do not have any more adrenaline boosters!</span>")
return TRUE
return (s_coold)//Returns the value of the variable which counts down to zero.
@@ -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
@@ -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, "<span class='notice'>You [candrain?"disable":"enable"] special interaction.</span>")
candrain=!candrain
@@ -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, "<span class='warning'>[net_target.p_they(TRUE)] are already trapped inside an energy net!</span>")
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, "<span class='warning'>You may not use an energy net through solid obstacles!</span>")
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("<span class='danger'>[ninja] caught [net_target] with an energy net!</span>","<span class='notice'>You caught [net_target] with an energy net!</span>")
if(net_target.buckled)
net_target.buckled.unbuckle_mob(affecting,TRUE)
net.buckle_mob(net_target, TRUE) //No moving for you!
@@ -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, "<span class='notice'>A throwing star has been created in your hand!</span>")
else
qdel(ninja_star)
to_chat(ninja, "<span class='notice'>You can't create a throwing star, your hands are full!</span>")
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)
@@ -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 += "<span class='info'>SpiderOS Status: [s_initialized ? "Initialized" : "Disabled"]</span>\n"
//Ninja status
info_list += "<span class='info'>Fingerprints: [md5(ninja.dna.uni_identity)]</span>\n"
info_list += "<span class='info'>Unique Identity: [ninja.dna.unique_enzymes]</span>\n"
info_list += "<span class='info'>Overall Status: [ninja.stat > 1 ? "dead" : "[ninja.health]% healthy"]</span>\n"
info_list += "<span class='info'>Nutrition Status: [ninja.nutrition]</span>\n"
info_list += "<span class='info'>Oxygen Loss: [ninja.getOxyLoss()]</span>\n"
info_list += "<span class='info'>Toxin Levels: [ninja.getToxLoss()]</span>\n"
info_list += "<span class='info'>Burn Severity: [ninja.getFireLoss()]</span>\n"
info_list += "<span class='info'>Brute Trauma: [ninja.getBruteLoss()]</span>\n"
info_list += "<span class='info'>Radiation Levels: [ninja.radiation] rad</span>\n"
info_list += "<span class='info'>Body Temperature: [ninja.bodytemperature-T0C] degrees C ([ninja.bodytemperature*1.8-459.67] degrees F)</span>\n"
//Diseases
if(length(ninja.diseases))
info_list += "Viruses:"
for(var/datum/disease/ninja_disease in ninja.diseases)
info_list += "<span class='info'>* [ninja_disease.name], Type: [ninja_disease.spread_text], Stage: [ninja_disease.stage]/[ninja_disease.max_stages], Possible Cure: [ninja_disease.cure_text]</span>\n"
to_chat(ninja, "[info_list.Join()]")
@@ -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, "<span class='warning'>You don't have enough power to enable Stealth!</span>")
return
stealth = !stealth
animate(ninja, alpha = 20,time = 12)
ninja.visible_message("<span class='warning'>[ninja.name] vanishes into thin air!</span>", \
"<span class='notice'>You are now mostly invisible to normal detection.</span>")
/**
* 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("<span class='warning'>[ninja.name] appears from thin air!</span>", \
"<span class='notice'>You are now visible.</span>")
return TRUE
return FALSE
@@ -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 <b class='nicegreen'>GREEN</b>, continuing operation.",
"VOID-shift device status: <B>ONLINE</B>.\nCLOAK-tech device status: <B>ONLINE</B>.",
"Primary system status: <B>ONLINE</B>.\nBackup system status: <B>ONLINE</B>.\nCurrent energy capacity: ",
"All systems operational. Welcome to <B>SpiderOS</B>, "
))
GLOBAL_LIST_INIT(ninja_deinitialize_messages, list(
"Now de-initializing...",
"Shutting down <B>SpiderOS</B>.",
"Primary system status: <B>OFFLINE</B>.\nBackup system status: <B>OFFLINE</B>.",
"VOID-shift device status: <B>OFFLINE</B>.\nCLOAK-tech device status: <B>OFFLINE</B>.",
"Disconnecting neural-net interface...<b class='nicegreen'>Success</b>.",
"Disengaging neural-net interface... <b class='nicegreen'>Success</b>.",
"Unsecuring external locking mechanism...\nNeural-net abolished.\nOperation status: <B>FINISHED</B>."
))
/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, "<span class='warning'>ERROR</span>: 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, "<span class='danger'><B>FĆAL �Rr�R</B>: 344--93#�&&21 BR��N |/|/aV� PATT$RN <B>RED</B>\nA-A-aB�rT�NG...</span>")
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 += "<B>[DisplayEnergy(cell.charge)]</B>."
if (NINJA_COMPLETE_PHASE)
message += "[ninja.real_name]."
ninja.regenerate_icons()
s_initialized = TRUE
s_busy = FALSE
to_chat(ninja, "<span class='notice'>[message]</span>")
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, "<span class='notice'>[message]</span>")
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
@@ -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, "<span class='warning'>Could not locate Energy Katana!</span>")
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("<span class='danger'>\the [energyKatana] flies towards [ninja]!</span>","<span class='warning'>You hold out your hand and \the [energyKatana] flies towards you!</span>")
energyKatana.throw_at(ninja, distance+1, energyKatana.throw_speed, ninja)
else //Else just TP it to us.
energyKatana.returnToOwner(ninja, 1)
s_coold = 4
+10 -2
View File
@@ -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
+191 -142
View File
@@ -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: <B>[DisplayEnergy(cell.charge)]</B>.\n"+\
"The CLOAK-tech device is <B>[stealth?"active":"inactive"]</B>.\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, "<span class='warning'><b>ERROR</b>: suit offline. Please activate suit.</span>")
return FALSE
if(s_coold > 0)
to_chat(user, "<span class='warning'><b>ERROR</b>: suit is on cooldown.</span>")
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, "<span class='danger'><B>fÄTaL ÈÈRRoR</B>: 382200-*#00CÖDE <B>RED</B>\nUNAU†HORIZED USÈ DETÈC†††eD\nCoMMÈNCING SUB-R0U†IN3 13...\nTÈRMInATING U-U-USÈR...</span>")
ninja.gib()
return FALSE
if(!istype(ninja.head, /obj/item/clothing/head/helmet/space/space_ninja))
to_chat(ninja, "<span class='userdanger'>ERROR</span>: 100113 UNABLE TO LOCATE HEAD GEAR\nABORTING...")
return FALSE
if(!istype(ninja.shoes, /obj/item/clothing/shoes/space_ninja))
to_chat(ninja, "<span class='userdanger'>ERROR</span>: 122011 UNABLE TO LOCATE FOOT GEAR\nABORTING...")
return FALSE
if(!istype(ninja.gloves, /obj/item/clothing/gloves/space_ninja))
to_chat(ninja, "<span class='userdanger'>ERROR</span>: 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, "<span class='danger'><B>fÄTaL ÈÈRRoR</B>: 382200-*#00CÖDE <B>RED</B>\nUNAU†HORIZED USÈ DETÈC†††eD\nCoMMÈNCING SUB-R0U†IN3 13...\nTÈRMInATING U-U-USÈR...</span>")
H.gib()
return FALSE
if(!istype(H.head, /obj/item/clothing/head/helmet/space/space_ninja))
to_chat(H, "<span class='userdanger'>ERROR</span>: 100113 UNABLE TO LOCATE HEAD GEAR\nABORTING...")
return FALSE
if(!istype(H.shoes, /obj/item/clothing/shoes/space_ninja))
to_chat(H, "<span class='userdanger'>ERROR</span>: 122011 UNABLE TO LOCATE FOOT GEAR\nABORTING...")
return FALSE
if(!istype(H.gloves, /obj/item/clothing/gloves/space_ninja))
to_chat(H, "<span class='userdanger'>ERROR</span>: 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: <B>[DisplayEnergy(cell.charge)]</B>.\n\
The CLOAK-tech device is <B>[stealth?"active":"inactive"]</B>.\n\
There are <B>[s_bombs]</B> smoke bomb\s remaining.\n\
There are <B>[a_boost]</B> 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, "<span class='warning'><b>ERROR</b>: suit offline. Please activate suit.</span>")
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
+19 -27
View File
@@ -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, "<span class='notice'>There are now [a_boost] adrenaline boosts remaining.</span>")
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, "<span class='notice'>There are now [s_bombs] smoke bombs remaining.</span>")
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, "<span class='notice'>The suit's adrenaline boost is now reloaded.</span>")
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, "<span class='notice'>Higher maximum capacity detected.\nUpgrading...</span>")
if (n_gloves && n_gloves.candrain && do_after(U,s_delay, target = src))
U.transferItemToLoc(CELL, src)
to_chat(ninja, "<span class='notice'>Higher maximum capacity detected.\nUpgrading...</span>")
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, "<span class='notice'>Upgrade complete. Maximum capacity: <b>[round(cell.maxcharge/100)]</b>%</span>")
to_chat(ninja, "<span class='notice'>Upgrade complete. Maximum capacity: <b>[round(cell.maxcharge/100)]</b>%</span>")
else
to_chat(U, "<span class='danger'>Procedure interrupted. Protocol terminated.</span>")
to_chat(ninja, "<span class='danger'>Procedure interrupted. Protocol terminated.</span>")
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, "<span class='notice'>Data analyzed and updated. Disk erased.</span>")
to_chat(ninja, "<span class='notice'>Data analyzed and updated. Disk erased.</span>")
else
to_chat(U, "<span class='userdanger'>ERROR</span>: Procedure interrupted. Process terminated.")
to_chat(ninja, "<span class='userdanger'>ERROR</span>: Procedure interrupted. Process terminated.")
else
to_chat(U, "<span class='notice'>No research information detected.</span>")
to_chat(ninja, "<span class='notice'>No research information detected.</span>")
return
return ..()
@@ -1,95 +0,0 @@
/obj/item/clothing/suit/space/space_ninja/proc/toggle_on_off()
if(s_busy)
to_chat(loc, "<span class='userdanger'>ERROR</span>: 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, "<span class='notice'>Now initializing...</span>")
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, "<span class='notice'>Securing external locking mechanism...\nNeural-net established.</span>")
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, "<span class='notice'>Extending neural-net interface...\nNow monitoring brain wave pattern...</span>")
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, "<span class='danger'><B>FĆAL �Rr�R</B>: 344--93#�&&21 BR��N |/|/aV� PATT$RN <B>RED</B>\nA-A-aB�rT�NG...</span>")
unlock_suit()
s_busy = FALSE
return
lockIcons(U)//Check for icons.
U.regenerate_icons()
to_chat(U, "<span class='notice'>Linking neural-net interface...\nPattern</span>\green <B>GREEN</B><span class='notice'>, continuing operation.</span>")
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, "<span class='notice'>VOID-shift device status: <B>ONLINE</B>.\nCLOAK-tech device status: <B>ONLINE</B>.</span>")
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, "<span class='notice'>Primary system status: <B>ONLINE</B>.\nBackup system status: <B>ONLINE</B>.\nCurrent energy capacity: <B>[DisplayEnergy(cell.charge)]</B>.</span>")
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, "<span class='notice'>All systems operational. Welcome to <B>SpiderOS</B>, [U.real_name].</span>")
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, "<span class='notice'>Now de-initializing...</span>")
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, "<span class='notice'>Logging off, [U.real_name]. Shutting down <B>SpiderOS</B>.</span>")
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, "<span class='notice'>Primary system status: <B>OFFLINE</B>.\nBackup system status: <B>OFFLINE</B>.</span>")
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, "<span class='notice'>VOID-shift device status: <B>OFFLINE</B>.\nCLOAK-tech device status: <B>OFFLINE</B>.</span>")
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, "<span class='notice'>Disconnecting neural-net interface...</span>\green<B>Success</B><span class='notice'>.</span>")
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, "<span class='notice'>Disengaging neural-net interface...</span>\green<B>Success</B><span class='notice'>.</span>")
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, "<span class='notice'>Unsecuring external locking mechanism...\nNeural-net abolished.\nOperation status: <B>FINISHED</B>.</span>")
unlock_suit()
U.regenerate_icons()
s_initialized = FALSE
STOP_PROCESSING(SSprocessing, src)
s_busy = FALSE
-17
View File
@@ -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()
+8 -9
View File
@@ -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
+64 -38
View File
@@ -50,6 +50,70 @@
-->
<div class="commit sansserif">
<h2 class="date">20 September 2021</h2>
<h3 class="author">BlueWildrose updated:</h3>
<ul class="changes bgimages16">
<li class="balance">Slime regenerative extracts now require five seconds of wait before they are used. They add 25 disgust when used.</li>
</ul>
<h3 class="author">DeltaFire15 updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">Catsurgeons should now spawn at more reasonable locations if possible.</li>
<li class="balance">carded AIs can now be converted by conversion sigils (clockcult)</li>
<li class="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.</li>
<li class="bugfix">Plastic golems are back to ventcrawler_nude instead of ventcrawler_always</li>
</ul>
<h3 class="author">Putnam3145 updated:</h3>
<ul class="changes bgimages16">
<li class="config">monstermos config added, disabled</li>
</ul>
<h3 class="author">buffyuwu updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">fixed medihound sleeper ui display</li>
<li class="rscadd">Adds 4 redesigned jackets and 2 redesigned shirts to loadout</li>
<li class="bugfix">Holoparasites no long rename and recolor on relog</li>
</ul>
<h3 class="author">dapnee updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">attaches an air vent that was just there on the AI sat, changes some areas to what they'd logically be</li>
</ul>
<h3 class="author">keronshb updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">Plague Rats will no longer spawn thousands of dirt decals</li>
<li class="bugfix">Plague Rats will no longer spawn thousands of corpses</li>
<li class="bugfix">Plague Rats can't spawn or transform off station z anymore</li>
<li class="bugfix">Plague Rats shouldn't explosively grow instantly</li>
<li class="bugfix">Plague Rats won't spawn infinite miasma anymore.</li>
<li class="balance">Plague Rats health is now 100.</li>
<li class="balance">Plague Rats can now ventcrawl through everything to prevent farming.</li>
<li class="bugfix">Slaughter Demons Slam will now wound again on hit.</li>
<li class="balance">Damage for demons back up to 30</li>
<li class="balance">Wound Bonus for demons now at 0. image_add: Adds a sprite for the action bar</li>
<li class="refactor">Changed the CTRL+SHIFT Click to an action button. People can see the cooldown now too.</li>
<li class="rscadd">PAIs can be emagged to reset master</li>
</ul>
<h3 class="author">qweq12yt updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">Fixed space heaters not being able to be interacted/turned on in non powered areas</li>
</ul>
<h3 class="author">timothyteakettle updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">removes passkey from access circuits as its not used anymore</li>
<li class="rscadd">a new mild trauma, **[REDACTED]**</li>
</ul>
<h3 class="author">zeroisthebiggay updated:</h3>
<ul class="changes bgimages16">
<li class="balance">glass has do_after</li>
<li class="bugfix">box perma has power</li>
<li class="bugfix">missing madness mask sprites</li>
<li class="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.</li>
<li class="bugfix">prisoners cannot latejoin anymore</li>
<li class="bugfix">bone satchel onmob sprites</li>
<li class="rscadd">new tips</li>
<li class="rscdel">old tips</li>
<li class="imageadd">all medipens get inhands</li>
<li class="rscadd">some more brainhurt lines</li>
</ul>
<h2 class="date">18 September 2021</h2>
<h3 class="author">kiwedespars updated:</h3>
<ul class="changes bgimages16">
@@ -472,44 +536,6 @@
<ul class="changes bgimages16">
<li class="balance">Batons are slightly more powerful.</li>
</ul>
<h2 class="date">19 July 2021</h2>
<h3 class="author">Arturlang updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">The crafting button should no longer silently make more copies of itself on reconects</li>
<li class="code_imp">There are no longer two copies of the crafting component.</li>
<li class="code_imp">There is no longer a rogue d in tracer.dm tweak: Everything in Misc was moved to Miscelanious in the crafting menu, and Misc was nuked from orbit. Nobody will miss you.</li>
</ul>
<h3 class="author">MrJWhit updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">Fixes a memory leak, there's a good chance that it's the same one that killed kilo.</li>
</ul>
<h3 class="author">SandPoot updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Put back mob vore with a pref.</li>
<li class="code_imp">Taken some stuff from tg for tgui_alert.</li>
<li class="refactor">Refactored a lot of code on vore panel.</li>
</ul>
<h3 class="author">WanderingFox95 updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">custom plasteel kegs</li>
</ul>
<h3 class="author">YakumoChen updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">You can now wear the suffering of others on your head with just a sheet of human skin!</li>
<li class="imageadd">Human skin hats</li>
</ul>
<h3 class="author">keronshb updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Stripping/equipping things to a conscious braindead person (AKA a human owned by a disconnected player) will now give them a message with your visible name and roughly how long ago you touched their stuff when they login again. Touching someone's pockets or adjusting their gear other than equipping/unequipping is not logged. After 5 minutes, you'll have forgotten both their name and exactly how long ago past those 5 minutes it happened. (Credit to Ryll-Ryll)</li>
<li class="rscadd">LAZYNULL</li>
<li class="rscadd">Breaking mirrors now gives you a bad omen</li>
</ul>
<h3 class="author">timothyteakettle updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">anthros can now select the cow tail</li>
<li class="rscadd">new quirk that allows you to eat trash</li>
</ul>
</div>
<b>GoonStation 13 Development Team</b>
+55
View File
@@ -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
@@ -1,4 +0,0 @@
author: "keronshb"
delete-after: True
changes:
- rscadd: "PAIs can be emagged to reset master"
@@ -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."
@@ -1,4 +0,0 @@
author: "zeroisthebiggay"
delete-after: True
changes:
- balance: "glass has do_after"
@@ -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."
@@ -1,5 +0,0 @@
author: "zeroisthebiggay"
delete-after: True
changes:
- rscadd: "new tips"
- rscdel: "old tips"
@@ -1,4 +0,0 @@
author: "zeroisthebiggay"
delete-after: True
changes:
- rscadd: "some more brainhurt lines"
@@ -1,4 +0,0 @@
author: "DeltaFire15"
delete-after: True
changes:
- balance: "carded AIs can now be converted by conversion sigils (clockcult)"
@@ -1,4 +0,0 @@
author: "DeltaFire15"
delete-after: True
changes:
- bugfix: "Catsurgeons should now spawn at more reasonable locations if possible."
@@ -1,4 +0,0 @@
author: "zeroisthebiggay"
delete-after: True
changes:
- bugfix: "box perma has power"
@@ -1,4 +0,0 @@
author: "zeroisthebiggay"
delete-after: True
changes:
- bugfix: "bone satchel onmob sprites"
@@ -1,4 +0,0 @@
author: "Putnam3145"
delete-after: True
changes:
- config: "monstermos config added, disabled"
@@ -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"
@@ -1,4 +0,0 @@
author: "zeroisthebiggay"
delete-after: True
changes:
- bugfix: "missing madness mask sprites"
@@ -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."
@@ -1,4 +0,0 @@
author: "timothyteakettle"
delete-after: True
changes:
- bugfix: "removes passkey from access circuits as its not used anymore"
@@ -1,4 +0,0 @@
author: "zeroisthebiggay"
delete-after: True
changes:
- bugfix: "prisoners cannot latejoin anymore"
@@ -1,4 +0,0 @@
author: "buffyuwu"
delete-after: True
changes:
- rscadd: "Adds 4 redesigned jackets and 2 redesigned shirts to loadout"
@@ -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."
@@ -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"
@@ -1,4 +0,0 @@
author: "timothyteakettle"
delete-after: True
changes:
- rscadd: "a new mild trauma, **[REDACTED]**"
@@ -1,4 +0,0 @@
author: "DeltaFire15"
delete-after: True
changes:
- bugfix: "Plastic golems are back to ventcrawler_nude instead of ventcrawler_always"
@@ -1,4 +0,0 @@
author: "buffyuwu"
delete-after: True
changes:
- bugfix: "Holoparasites no long rename and recolor on relog"
@@ -1,4 +0,0 @@
author: "buffyuwu"
delete-after: True
changes:
- bugfix: "fixed medihound sleeper ui display"
@@ -1,4 +0,0 @@
author: "zeroisthebiggay"
delete-after: True
changes:
- imageadd: "all medipens get inhands"
@@ -0,0 +1,4 @@
author: "silicons"
delete-after: True
changes:
- bugfix: "dice bags can only hold dice"
@@ -0,0 +1,4 @@
author: "silicons"
delete-after: True
changes:
- rscdel: "limb damage changes reverted"
@@ -0,0 +1,4 @@
author: "silicons"
delete-after: True
changes:
- bugfix: "crawling can't be adrenals'd"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 226 KiB

After

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 480 KiB

After

Width:  |  Height:  |  Size: 473 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 291 KiB

After

Width:  |  Height:  |  Size: 289 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 KiB

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Some files were not shown because too many files have changed in this diff Show More