Merge branch 'master' into silicons-patch-1

This commit is contained in:
silicons
2021-09-19 15:00:30 -07:00
committed by GitHub
145 changed files with 5779 additions and 4125 deletions
+5
View File
@@ -76,3 +76,8 @@
//Chemical reaction flags, for determining reaction specialties
#define REACTION_CLEAR_IMPURE (1<<0) //Convert into impure/pure on reaction completion
#define REACTION_CLEAR_INVERSE (1<<1) //Convert into inverse on reaction completion when purity is low enough
//Chemical blacklists for smartdarts
GLOBAL_LIST_INIT(blacklisted_medchems, list(
/datum/reagent/medicine/morphine, /datum/reagent/medicine/haloperidol, //harmful chemicals in medicine
))
+2 -2
View File
@@ -154,8 +154,8 @@
if(hud?.mymob && slot_id)
var/obj/item/inv_item = hud.mymob.get_item_by_slot(slot_id)
if(inv_item)
if(hud?.mymob.incapacitated())
inv_item.apply_outline(COLOR_RED_GRAY)
if(hud?.mymob.incapacitated() || (slot_id in hud?.mymob.check_obscured_slots()) || !hud?.mymob.canUnEquip(inv_item))
inv_item.apply_outline(_size = 3)
else
inv_item.apply_outline()
@@ -342,3 +342,6 @@
/datum/config_entry/number/hard_deletes_overrun_limit
default = 0
min_val = 0
/datum/config_entry/flag/atmos_equalize_enabled
default = FALSE
+1
View File
@@ -108,6 +108,7 @@ SUBSYSTEM_DEF(air)
setup_atmos_machinery()
setup_pipenets()
gas_reactions = init_gas_reactions()
should_do_equalization = CONFIG_GET(flag/atmos_equalize_enabled)
auxtools_update_reactions()
return ..()
-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'
+33
View File
@@ -264,3 +264,36 @@
speak_dejavu += speech_args[SPEECH_MESSAGE]
else
speak_dejavu += speech_args[SPEECH_MESSAGE]
/datum/brain_trauma/mild/redacted
name = "Confidentiality Trauma"
desc = "Patient's language neurons seem to be warped in a strange manner, resulting in them being unable to speak properly."
scan_desc = "<b>\[REDACTED]</b>"
gain_text = "<span class='warning'>You feel the need to <b>\[REDACTED]</b></span>"
lose_text = "<span class='notice'>You no longer feel the need to <b>\[REDACTED]</b>.</span>"
/datum/brain_trauma/mild/redacted/handle_speech(datum/source, list/speech_args)
var/message = speech_args[SPEECH_MESSAGE]
if(message)
var/list/message_split = splittext(message, " ")
var/list/new_message = list()
for(var/word in message_split)
var/suffix = ""
var/suffix_foundon = 0
for(var/potential_suffix in list("." , "," , ";" , "!" , ":" , "?"))
suffix_foundon = findtext(word, potential_suffix, -length(potential_suffix))
if(suffix_foundon)
suffix = potential_suffix
break
if(suffix_foundon)
word = copytext(word, 1, suffix_foundon)
word = html_decode(word)
if(prob(25))
word = pick(list("<b>\[REDACTED]</b>", "<b>\[CLASSIFIED]</b>", "<b>\[EXPUNGED]</b>"))
new_message += word + suffix
message = jointext(new_message, " ")
speech_args[SPEECH_MESSAGE] = trim(message)
+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!
+16 -2
View File
@@ -160,12 +160,14 @@ If not set, defaults to check_completion instead. Set it. It's used by cryo.
/datum/objective/proc/give_special_equipment(special_equipment)
var/datum/mind/receiver = pick(get_owners())
. = list()
if(receiver && receiver.current)
if(ishuman(receiver.current))
var/mob/living/carbon/human/H = receiver.current
var/list/slots = list("backpack" = SLOT_IN_BACKPACK)
for(var/eq_path in special_equipment)
var/obj/O = new eq_path
. += O
H.equip_in_one_of_slots(O, slots, critical = TRUE)
/datum/objective/assassinate
@@ -560,6 +562,7 @@ GLOBAL_LIST_EMPTY(possible_items)
name = "steal"
var/datum/objective_item/targetinfo = null //Save the chosen item datum so we can access it later.
var/obj/item/steal_target = null //Needed for custom objectives (they're just items, not datums).
var/list/special_items_given = list()
martyr_compatible = 0
/datum/objective/steal/get_target()
@@ -571,6 +574,11 @@ GLOBAL_LIST_EMPTY(possible_items)
for(var/I in subtypesof(/datum/objective_item/steal))
new I
/datum/objective/steal/Destroy(force, ...)
if(length(special_items_given))
QDEL_LIST(special_items_given)
. = ..()
/datum/objective/steal/find_target(dupe_search_range, blacklist)
var/list/datum/mind/owners = get_owners()
var/approved_targets = list()
@@ -589,7 +597,7 @@ GLOBAL_LIST_EMPTY(possible_items)
targetinfo = item
steal_target = targetinfo.targetitem
explanation_text = "Steal [targetinfo.name]"
give_special_equipment(targetinfo.special_equipment)
special_items_given = give_special_equipment(targetinfo.special_equipment)
return steal_target
else
explanation_text = "Free objective"
@@ -1180,6 +1188,7 @@ GLOBAL_LIST_EMPTY(possible_sabotages)
/datum/objective/sabotage
name = "sabotage"
var/datum/sabotage_objective/targetinfo = null //composition > inheritance.
var/list/special_items_given = list()
/datum/objective/sabotage/get_target()
return targetinfo.sabotage_type
@@ -1190,6 +1199,11 @@ GLOBAL_LIST_EMPTY(possible_sabotages)
for(var/I in subtypesof(/datum/sabotage_objective))
new I
/datum/objective/sabotage/Destroy()
if(length(special_items_given))
QDEL_LIST(special_items_given)
. = ..()
/datum/objective/sabotage/find_target(dupe_search_range, blacklist)
var/list/datum/mind/owners = get_owners()
var/approved_targets = list()
@@ -1207,7 +1221,7 @@ GLOBAL_LIST_EMPTY(possible_sabotages)
if(sabo)
targetinfo = sabo
explanation_text = "[targetinfo.name]"
give_special_equipment(targetinfo.special_equipment)
special_items_given = give_special_equipment(targetinfo.special_equipment)
return sabo
else
explanation_text = "Free objective"
+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 -3
View File
@@ -6,6 +6,7 @@
anchored = FALSE
density = TRUE
interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN
use_power = NO_POWER_USE
icon = 'icons/obj/atmos.dmi'
icon_state = "sheater-off"
name = "space heater"
@@ -72,7 +73,7 @@
on = FALSE
return PROCESS_KILL
if(cell && cell.charge > 0)
if(cell && cell.charge > 1 / efficiency)
var/turf/L = loc
PerformHeating(L)
@@ -112,7 +113,9 @@
var/requiredPower = abs(env.return_temperature() - targetTemperature) * heat_capacity
requiredPower = min(requiredPower, heatingPower)
if(requiredPower < 1)
if(requiredPower < 1 || !cell.use(requiredPower / efficiency))
on = FALSE
update_icon()
return
var/deltaTemperature = requiredPower / heat_capacity
@@ -121,7 +124,6 @@
if(deltaTemperature)
env.set_temperature(env.return_temperature() + deltaTemperature)
air_update_turf()
cell.use(requiredPower / efficiency)
/obj/machinery/space_heater/RefreshParts()
var/laser = 2
+4 -4
View File
@@ -890,8 +890,8 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
var/user = usr
tip_timer = addtimer(CALLBACK(src, .proc/openTip, location, control, params, user), timedelay, TIMER_STOPPABLE)//timer takes delay in deciseconds, but the pref is in milliseconds. dividing by 100 converts it.
var/mob/living/L = usr
if(istype(L) && L.incapacitated())
apply_outline(COLOR_RED_GRAY)
if(istype(L) && (L.incapacitated() || (current_equipped_slot in L.check_obscured_slots()) || !L.canUnEquip(src)))
apply_outline(_size = 3)
else
apply_outline()
@@ -905,7 +905,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
closeToolTip(usr)
remove_outline()
/obj/item/proc/apply_outline(colour = null)
/obj/item/proc/apply_outline(colour = null, _size=1)
if(!(item_flags & IN_INVENTORY || item_flags & IN_STORAGE) || QDELETED(src) || isobserver(usr))
return
if(usr.client)
@@ -920,7 +920,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
colour = COLOR_BLUE_GRAY
if(outline_filter)
filters -= outline_filter
outline_filter = filter(type="outline", size=1, color=colour)
outline_filter = filter(type="outline", size=_size, color=colour)
filters += outline_filter
/obj/item/proc/remove_outline()
@@ -172,7 +172,7 @@
/obj/item/dogborg/sleeper/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "dogborg_sleeper", name, 375, 550) //UI DOES NOT EXIST
ui = new(user, src, "Sleeper", name)
ui.open()
/obj/item/dogborg/sleeper/ui_data()
+11 -11
View File
@@ -13,8 +13,8 @@
* Glass sheets
*/
GLOBAL_LIST_INIT(glass_recipes, list ( \
new/datum/stack_recipe("directional window", /obj/structure/window/unanchored, time = 0, on_floor = TRUE, window_checks = TRUE), \
new/datum/stack_recipe("fulltile window", /obj/structure/window/fulltile/unanchored, 2, time = 0, on_floor = TRUE, window_checks = TRUE), \
new/datum/stack_recipe("directional window", /obj/structure/window/unanchored, time = 10, on_floor = TRUE, window_checks = TRUE), \
new/datum/stack_recipe("fulltile window", /obj/structure/window/fulltile/unanchored, 2, time = 20, on_floor = TRUE, window_checks = TRUE), \
null, \
new/datum/stack_recipe_list("glass working bases", list( \
new/datum/stack_recipe("chem dish", /obj/item/glasswork/glass_base/dish, 10), \
@@ -95,8 +95,8 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \
GLOBAL_LIST_INIT(pglass_recipes, list ( \
new/datum/stack_recipe("directional window", /obj/structure/window/plasma/unanchored, time = 0, on_floor = TRUE, window_checks = TRUE), \
new/datum/stack_recipe("fulltile window", /obj/structure/window/plasma/fulltile/unanchored, 2, time = 0, on_floor = TRUE, window_checks = TRUE) \
new/datum/stack_recipe("directional window", /obj/structure/window/plasma/unanchored, time = 10, on_floor = TRUE, window_checks = TRUE), \
new/datum/stack_recipe("fulltile window", /obj/structure/window/plasma/fulltile/unanchored, 2, time = 20, on_floor = TRUE, window_checks = TRUE) \
))
/obj/item/stack/sheet/plasmaglass
@@ -147,10 +147,10 @@ GLOBAL_LIST_INIT(pglass_recipes, list ( \
* Reinforced glass sheets
*/
GLOBAL_LIST_INIT(reinforced_glass_recipes, list ( \
new/datum/stack_recipe("windoor frame", /obj/structure/windoor_assembly, 5, time = 0, on_floor = TRUE, window_checks = TRUE), \
new/datum/stack_recipe("windoor frame", /obj/structure/windoor_assembly, 5, time = 20, on_floor = TRUE, window_checks = TRUE), \
null, \
new/datum/stack_recipe("directional reinforced window", /obj/structure/window/reinforced/unanchored, time = 0, on_floor = TRUE, window_checks = TRUE), \
new/datum/stack_recipe("fulltile reinforced window", /obj/structure/window/reinforced/fulltile/unanchored, 2, time = 0, on_floor = TRUE, window_checks = TRUE) \
new/datum/stack_recipe("directional reinforced window", /obj/structure/window/reinforced/unanchored, time = 10, on_floor = TRUE, window_checks = TRUE), \
new/datum/stack_recipe("fulltile reinforced window", /obj/structure/window/reinforced/fulltile/unanchored, 2, time = 20, on_floor = TRUE, window_checks = TRUE) \
))
@@ -198,8 +198,8 @@ GLOBAL_LIST_INIT(reinforced_glass_recipes, list ( \
. += GLOB.reinforced_glass_recipes
GLOBAL_LIST_INIT(prglass_recipes, list ( \
new/datum/stack_recipe("directional reinforced window", /obj/structure/window/plasma/reinforced/unanchored, time = 0, on_floor = TRUE, window_checks = TRUE), \
new/datum/stack_recipe("fulltile reinforced window", /obj/structure/window/plasma/reinforced/fulltile/unanchored, 2, time = 0, on_floor = TRUE, window_checks = TRUE) \
new/datum/stack_recipe("directional reinforced window", /obj/structure/window/plasma/reinforced/unanchored, time = 10, on_floor = TRUE, window_checks = TRUE), \
new/datum/stack_recipe("fulltile reinforced window", /obj/structure/window/plasma/reinforced/fulltile/unanchored, 2, time = 20, on_floor = TRUE, window_checks = TRUE) \
))
/obj/item/stack/sheet/plasmarglass
@@ -226,7 +226,7 @@ GLOBAL_LIST_INIT(prglass_recipes, list ( \
S.efficiency *= 1.2
GLOBAL_LIST_INIT(titaniumglass_recipes, list(
new/datum/stack_recipe("shuttle window", /obj/structure/window/shuttle/unanchored, 2, time = 0, on_floor = TRUE, window_checks = TRUE)
new/datum/stack_recipe("shuttle window", /obj/structure/window/shuttle/unanchored, 2, time = 20, on_floor = TRUE, window_checks = TRUE)
))
/obj/item/stack/sheet/titaniumglass
@@ -250,7 +250,7 @@ GLOBAL_LIST_INIT(titaniumglass_recipes, list(
S.efficiency *= 1.5
GLOBAL_LIST_INIT(plastitaniumglass_recipes, list(
new/datum/stack_recipe("plastitanium window", /obj/structure/window/plastitanium/unanchored, 2, time = 0, on_floor = TRUE, window_checks = TRUE)
new/datum/stack_recipe("plastitanium window", /obj/structure/window/plastitanium/unanchored, 2, time = 20, on_floor = TRUE, window_checks = TRUE)
))
/obj/item/stack/sheet/plastitaniumglass
+2 -2
View File
@@ -259,8 +259,8 @@
/obj/item/storage/backpack/satchel/bone
name = "bone satchel"
desc = "A grotesque satchel made of sinews and bones."
icon = 'icons/obj/mining.dmi'
icon_state = "goliath_saddle"
icon_state = "satchel-bone"
item_state = "satchel-bone"
slot_flags = ITEM_SLOT_BACK
/obj/item/storage/backpack/satchel/bone/ComponentInitialize()
+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)
+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()
@@ -111,6 +111,19 @@
sigil_name = "Sigil of Submission"
var/glow_type = /obj/effect/temp_visual/ratvar/sigil/submission
/obj/effect/clockwork/sigil/submission/Crossed(atom/movable/AM)
. = ..()
if(istype(AM, /obj/item/aicard))
var/obj/item/aicard/cardy = AM
if(!cardy.AI)
return
var/mob/living/silicon/ai/aiconvert = cardy.AI
if(aiconvert.stat > stat_affected)
return
if(is_servant_of_ratvar(aiconvert) || !(aiconvert.mind || aiconvert.has_status_effect(STATUS_EFFECT_SIGILMARK)))
return
sigil_effects(aiconvert)
/obj/effect/clockwork/sigil/submission/sigil_effects(mob/living/L)
var/turf/T = get_turf(src)
var/has_sigil = FALSE
-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
..()
+41 -26
View File
@@ -35,9 +35,9 @@
healable = 0
environment_smash = ENVIRONMENT_SMASH_STRUCTURES
obj_damage = 50
melee_damage_lower = 22.5 // reduced from 30 to 22.5 with wounds since they get big buffs to slicing wounds
melee_damage_upper = 22.5
wound_bonus = -10
melee_damage_lower = 30 // buffed back to 30, the wounds don't do much
melee_damage_upper = 30
wound_bonus = 0
bare_wound_bonus = 0
sharpness = SHARP_EDGED
see_in_dark = 8
@@ -49,17 +49,13 @@
Pulling a dead or unconscious mob while you enter a pool will pull them in with you, allowing you to feast and regain your health. \
You move quickly upon leaving a pool of blood, but the material world will soon sap your strength and leave you sluggish. \
You gain strength the more attacks you land on live humanoids, though this resets when you return to the blood zone. You can also \
launch a devastating slam attack with ctrl+shift+click, capable of smashing bones in one strike.</B>"
launch a devastating slam attack, capable of smashing bones in one strike.</B>"
loot = list(/obj/effect/decal/cleanable/blood, \
/obj/effect/decal/cleanable/blood/innards, \
/obj/item/organ/heart/demon)
del_on_death = 1
deathmessage = "screams in anger as it collapses into a puddle of viscera!"
// How long it takes for the alt-click slam attack to come off cooldown
var/slam_cooldown_time = 45 SECONDS
// The actual instance var for the cooldown
var/slam_cooldown = 0
// How many times we have hit humanoid targets since we last bloodcrawled, scaling wounding power
var/current_hitstreak = 0
// How much both our wound_bonus and bare_wound_bonus go up per hitstreak hit
@@ -70,37 +66,56 @@
var/list/consumed_mobs = list()
//buffs only happen when hearts are eaten, so this needs to be kept track separately
var/consumed_buff = 0
//slam mode for action button
var/slam_mode = FALSE
var/datum/action/cooldown/slam
/mob/living/simple_animal/slaughter/Initialize()
..()
var/obj/effect/proc_holder/spell/bloodcrawl/bloodspell = new
AddSpell(bloodspell)
slam = new /datum/action/cooldown/slam
slam.Grant(src)
if(istype(loc, /obj/effect/dummy/phased_mob/slaughter))
bloodspell.phased = TRUE
/mob/living/simple_animal/slaughter/CtrlShiftClickOn(atom/A)
if(!isliving(A))
return ..()
if(slam_cooldown + slam_cooldown_time > world.time)
to_chat(src, "<span class='warning'>Your slam ability is still on cooldown!</span>")
return
if(!isopenturf(loc))
to_chat(src, "<span class='warning'>You need to be on open flooring to do that!")
return
/datum/action/cooldown/slam
name = "Slaughter Slam"
desc = "Launch enemies and break bones in one strike."
icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
background_icon_state = "bg_demon"
button_icon_state = "slam"
cooldown_time = 45 SECONDS
face_atom(A)
var/mob/living/victim = A
victim.take_bodypart_damage(brute=20, wound_bonus=wound_bonus) // don't worry, there's more punishment when they hit something
visible_message("<span class='danger'>[src] slams into [victim] with monstrous strength!</span>", "<span class='danger'>You slam into [victim] with monstrous strength!</span>", ignored_mobs=victim)
to_chat(victim, "<span class='userdanger'>[src] slams into you with monstrous strength, sending you flying like a ragdoll!</span>")
var/turf/yeet_target = get_edge_target_turf(victim, dir)
victim.throw_at(yeet_target, 10, 5, src)
slam_cooldown = world.time
log_combat(src, victim, "slaughter slammed")
/datum/action/cooldown/slam/Trigger()
. = ..()
if(!.)
return
var/mob/living/simple_animal/slaughter/user = owner
user.slam_mode = !user.slam_mode
to_chat(user, user.slam_mode ? "Ready to slam!" : "Maybe not now.")
/mob/living/simple_animal/slaughter/UnarmedAttack(atom/A, proximity)
if(iscarbon(A))
var/mob/living/carbon/target = A
if(slam_mode)
if(!isopenturf(loc))
to_chat(src, "<span class='warning'>You need to be on open flooring to do that!")
return
face_atom(A)
var/mob/living/victim = A
var/body_pick = pick(BODY_ZONE_CHEST, BODY_ZONE_HEAD, BODY_ZONE_L_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_ARM, BODY_ZONE_R_LEG)
var/datum/wound/blunt/critical/wound_major = new
var/obj/item/bodypart/body_wound = victim.get_bodypart(body_pick)
wound_major.apply_wound(body_wound)
visible_message("<span class='danger'>[src] slams into [victim] with monstrous strength!</span>", "<span class='danger'>You slam into [victim] with monstrous strength!</span>", ignored_mobs=victim)
to_chat(victim, "<span class='userdanger'>[src] slams into you with monstrous strength, sending you flying like a ragdoll!</span>")
var/turf/yeet_target = get_edge_target_turf(victim, dir)
victim.throw_at(yeet_target, 10, 14, src)
slam_mode = FALSE
slam.StartCooldown()
log_combat(src, victim, "slaughter slammed")
if(target.stat != DEAD && target.mind && current_hitstreak < wound_bonus_hitstreak_max)
current_hitstreak++
wound_bonus += wound_bonus_per_hit
@@ -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()
. = ..()
@@ -446,6 +446,42 @@
icon_state = "flannel_brown"
item_state = "flannel_brown"
/obj/item/clothing/suit/jacket/purplehoodie
name = "purple hoodie"
desc = "A soft purple hoodie with a TailorCo brand on the tag."
icon_state = "purplehoodie"
item_state = "purplehoodie"
/obj/item/clothing/suit/jacket/bluehoodie
name = "blue hoodie"
desc = "A soft blue hoodie with a TailorCo brand on the tag."
icon_state = "bluehoodie"
item_state = "bluehoodie"
/obj/item/clothing/suit/jacket/heartcoat
name = "heart coat"
desc = "A soft winter coat with a TailorCo brand on the tag."
icon_state = "heartcoat"
item_state = "heartcoat"
/obj/item/clothing/suit/jacket/gothiccoat
name = "long black jacket"
desc = "A rugged looking coat with a TailorCo brand on the tag."
icon_state = "gothic_coat"
item_state = "gothic_coat"
/obj/item/clothing/suit/jacket/gothicshirt
name = "black shirt with cuffs"
desc = "A black shirt with a collar and cuffs in a gothic style. A TailorCo brand is listed on the tag."
icon_state = "gothic_shirt"
item_state = "gothic_shirt"
/obj/item/clothing/suit/jacket/gothicshirtcross
name = "elegant black shirt"
desc = "A black shirt with finely woven cross on the back. A TailorCo brand is listed on the tag."
icon_state = "gothic_shirtcross"
item_state = "gothic_shirtcross"
/obj/item/clothing/suit/jacket/leather
name = "leather jacket"
desc = "Pompadour not included."
+21 -1
View File
@@ -10,8 +10,28 @@
/datum/round_event/cat_surgeon/start()
var/list/spawn_locs = list()
var/list/unsafe_spawn_locs = list()
for(var/X in GLOB.xeno_spawn)
spawn_locs += X
if(!isfloorturf(X))
unsafe_spawn_locs += X
continue
var/turf/open/floor/F = X
var/datum/gas_mixture/A = F.air
var/oxy_moles = A.get_moles(GAS_O2)
if((oxy_moles < 16 || oxy_moles > 50) || A.get_moles(GAS_PLASMA) || A.get_moles(GAS_CO2) >= 10)
unsafe_spawn_locs += F
continue
if((A.return_temperature() <= 270) || (A.return_temperature() >= 360))
unsafe_spawn_locs += F
continue
var/pressure = A.return_pressure()
if((pressure <= 20) || (pressure >= 550))
unsafe_spawn_locs += F
continue
spawn_locs += F
if(!spawn_locs.len)
spawn_locs += unsafe_spawn_locs
if(!spawn_locs.len)
message_admins("No valid spawn locations found, aborting...")
+2 -2
View File
@@ -9,7 +9,7 @@
/datum/round_event_control/mass_hallucination/admin_setup()
if(!check_rights(R_FUN))
return
forced_hallucination = input(usr, "Choose the hallucination to apply","Send Hallucination") as null|anything in subtypesof(/datum/hallucination)
/datum/round_event/mass_hallucination
@@ -26,7 +26,7 @@
switch(rand(1,4))
if(1) //same sound for everyone
var/sound = pick("airlock","airlock_pry","console","explosion","far_explosion","mech","glass","alarm","beepsky","mech","wall_decon","door_hack","tesla")
var/sound = pick("airlock","airlock_pry","console","explosion","far_explosion","mech","glass","alarm","beepsky","mech","wall_decon","door_hack","tesla","seth")
for(var/mob/living/carbon/C in GLOB.alive_mob_list)
new /datum/hallucination/sounds(C, TRUE, sound)
if(2)
+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
+4 -1
View File
@@ -778,7 +778,7 @@ GLOBAL_LIST_INIT(hallucination_list, list(
..()
var/turf/source = random_far_turf()
if(!sound_type)
sound_type = pick("airlock","airlock pry","console","flash","explosion","far explosion","mech","glass","alarm","beepsky","mech","wall decon","door hack")
sound_type = pick("airlock","airlock pry","console","flash","explosion","far explosion","mech","glass","alarm","beepsky","mech","wall decon","door hack","seth")
feedback_details += "Type: [sound_type]"
//Strange audio
switch(sound_type)
@@ -827,6 +827,9 @@ GLOBAL_LIST_INIT(hallucination_list, list(
target.playsound_local(source, 'sound/items/screwdriver.ogg', 50, 1)
sleep(rand(40,80))
target.playsound_local(source, 'sound/machines/airlockforced.ogg', 30, 1)
//funny announcement man
if("seth")
target.playsound_local(source,'sound/misc/seth.ogg', 50, 1)
qdel(src)
/datum/hallucination/weird_sounds
+1 -1
View File
@@ -226,7 +226,7 @@
var/turf/open/O = loc
if(O.air)
var/datum/gas_mixture/loc_air = O.air
if(loc_air.get_moles(GAS_O2) > 13)
if(loc_air.get_moles(GAS_O2) > 3)
return TRUE
return FALSE
@@ -8,7 +8,6 @@
outputs = list(
"registered name" = IC_PINTYPE_STRING,
"assignment" = IC_PINTYPE_STRING,
"passkey" = IC_PINTYPE_STRING
)
activators = list(
"on read" = IC_PINTYPE_PULSE_OUT
@@ -17,7 +16,6 @@
/obj/item/integrated_circuit/input/card_reader/attackby_react(obj/item/I, mob/living/user, intent)
var/obj/item/card/id/card = I.GetID()
var/list/access = I.GetAccess()
var/passkey = strtohex(XorEncrypt(json_encode(access), SScircuit.cipherkey))
if(assembly)
assembly.access_card.access |= access
@@ -33,8 +31,6 @@
else
return FALSE
set_pin_data(IC_OUTPUT, 3, passkey)
push_data()
activate_pin(1)
return TRUE
@@ -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)
@@ -807,11 +807,11 @@
/datum/species/golem/plastic/on_species_gain(mob/living/carbon/C, datum/species/old_species)
. = ..()
C.AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
C.AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_NUDE)
/datum/species/golem/plastic/on_species_loss(mob/living/carbon/C)
. = ..()
C.RemoveElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
C.RemoveElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_NUDE)
/datum/species/golem/bronze
name = "Bronze Golem"
@@ -322,6 +322,17 @@
else
to_chat(user, "Encryption Key ports not configured.")
/obj/item/paicard/emag_act(mob/user) // Emag to wipe the master DNA and supplemental directive
. = ..()
if(!pai)
return
to_chat(user, "<span class='notice'>You override [pai]'s directive system, clearing its master string and supplied directive.</span>")
to_chat(pai, "<span class='danger'>Warning: System override detected, check directive sub-system for any changes.'</span>")
log_game("[key_name(user)] emagged [key_name(pai)], wiping their master DNA and supplemental directive.")
pai.master = null
pai.master_dna = null
pai.laws.supplied[1] = "None." // Sets supplemental directive to this
/mob/living/silicon/pai/proc/short_radio()
if(radio_short_timerid)
deltimer(radio_short_timerid)
@@ -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"
@@ -99,15 +99,17 @@
evolve()
return
for(var/obj/item/trash/garbage in range(1, src))
if(prob(2))
qdel(garbage)
evolve_plague()
return
if(is_station_level(z))
if(prob(2))
qdel(garbage)
evolve_plague()
return
for(var/obj/effect/decal/cleanable/blood/gibs/leftovers in range(1, src))
if(prob(2))
qdel(leftovers)
evolve_plague()
return
if(is_station_level(z))
if(prob(2))
qdel(leftovers)
evolve_plague()
return
/**
*Checks the mouse cap, if it's above the cap, doesn't spawn a mouse. If below, spawns a mouse and adds it to cheeserats.
@@ -134,11 +136,15 @@
qdel(src)
/mob/living/simple_animal/mouse/proc/evolve_plague()
return
/*
var/mob/living/simple_animal/hostile/plaguerat = new /mob/living/simple_animal/hostile/plaguerat(loc)
visible_message("<span class='warning'>[src] devours the food! He rots into something worse!</span>")
if(mind)
mind.transfer_to(plaguerat)
qdel(src)
*/
/*
* Mouse types
@@ -198,4 +204,5 @@ GLOBAL_VAR(tom_existed)
/mob/living/simple_animal/mouse/handle_environment(datum/gas_mixture/environment)
. = ..()
miasma()
if(is_station_level(z))
miasma()
@@ -60,6 +60,7 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
var/magic_fluff_string = "<span class='holoparasite'>You draw the Coder, symbolizing bugs and errors. This shouldn't happen! Submit a bug report!</span>"
var/tech_fluff_string = "<span class='holoparasite'>BOOT SEQUENCE COMPLETE. ERROR MODULE LOADED. THIS SHOULDN'T HAPPEN. Submit a bug report!</span>"
var/carp_fluff_string = "<span class='holoparasite'>CARP CARP CARP SOME SORT OF HORRIFIC BUG BLAME THE CODERS CARP CARP CARP</span>"
var/customized
/// sigh, fine.
var/datum/song/holoparasite/music_datum
@@ -142,11 +143,13 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
to_chat(src, "<span class='holoparasite'>You are capable of manifesting or recalling to your master with the buttons on your HUD. You will also find a button to communicate with [summoner.p_them()] privately there.</span>")
to_chat(src, "<span class='holoparasite'>While personally invincible, you will die if [summoner.real_name] does, and any damage dealt to you will have a portion passed on to [summoner.p_them()] as you feed upon [summoner.p_them()] to sustain yourself.</span>")
to_chat(src, playstyle_string)
guardiancustomize()
if(!customized)
guardiancustomize()
/mob/living/simple_animal/hostile/guardian/proc/guardiancustomize()
guardianrecolor()
guardianrename()
customized = TRUE
/mob/living/simple_animal/hostile/guardian/proc/guardianrecolor()
guardiancolor = input(src,"What would you like your color to be?","Choose Your Color","#ffffff") as color|null
@@ -1,3 +1,6 @@
#define RAT_VENT_CHANCE 1.75
GLOBAL_LIST_EMPTY(plague_rats)
/mob/living/simple_animal/hostile/plaguerat
name = "plague rat"
desc = "A large decaying rat. It spreads its filth and emits a putrid odor to create more of its kind."
@@ -11,8 +14,8 @@
gender = NEUTER
speak_chance = 1
turns_per_move = 5
maxHealth = 15
health = 15
maxHealth = 100
health = 100
see_in_dark = 6
obj_damage = 10
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 1)
@@ -22,8 +25,8 @@
response_disarm_simple = "skoff at"
response_harm_continuous = "slashes"
response_harm_simple = "slash"
melee_damage_lower = 5
melee_damage_upper = 7
melee_damage_lower = 6
melee_damage_upper = 8
attack_verb_continuous = "slashes"
attack_verb_simple = "slash"
attack_sound = 'sound/weapons/punch1.ogg'
@@ -34,27 +37,69 @@
mob_biotypes = MOB_ORGANIC|MOB_BEAST
var/datum/action/cooldown/scavenge
var/last_spawn_time = 0
///Number assigned to rats and mice, checked when determining infighting.
var/in_vent = FALSE
var/min_next_vent = 0
var/obj/machinery/atmospherics/components/unary/entry_vent
var/obj/machinery/atmospherics/components/unary/exit_vent
/mob/living/simple_animal/hostile/plaguerat/Initialize()
. = ..()
SSmobs.cheeserats += src
GLOB.plague_rats += src
AddComponent(/datum/component/swarming)
AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
scavenge = new /datum/action/cooldown/scavenge
scavenge.Grant(src)
/mob/living/simple_animal/hostile/plaguerat/Destroy()
SSmobs.cheeserats -= src
GLOB.plague_rats -= src
return ..()
/mob/living/simple_animal/hostile/plaguerat/Life(seconds, times_fired)
. = ..()
//Don't try to path to one target for too long. If it takes longer than a certain amount of time, assume it can't be reached and find a new one
//Literally only here to prevent farming and that's it.
if(!client) //don't do this shit if there's a client, they're capable of ventcrawling manually
if(in_vent)
target = null
if(entry_vent && get_dist(src, entry_vent) <= 1)
var/list/vents = list()
var/datum/pipeline/entry_vent_parent = entry_vent.parents[1]
for(var/obj/machinery/atmospherics/components/unary/temp_vent in entry_vent_parent.other_atmosmch)
vents += temp_vent
if(!vents.len)
entry_vent = null
in_vent = FALSE
return
exit_vent = pick(vents)
visible_message("<span class='notice'>[src] crawls into the ventilation ducts!</span>")
loc = exit_vent
var/travel_time = round(get_dist(loc, exit_vent.loc) / 2)
addtimer(CALLBACK(src, .proc/exit_vents), travel_time) //come out at exit vent in 2 to 20 seconds
if(world.time > min_next_vent && !entry_vent && !in_vent && prob(RAT_VENT_CHANCE)) //small chance to go into a vent
for(var/obj/machinery/atmospherics/components/unary/v in view(7,src))
if(!v.welded)
entry_vent = v
in_vent = TRUE
walk_to(src, entry_vent)
break
/mob/living/simple_animal/hostile/plaguerat/BiologicalLife(seconds, times_fired)
if(!(. = ..()))
return
if(isopenturf(loc))
var/turf/open/T = src.loc
var/datum/gas_mixture/stank = new
var/miasma_moles = T.air.get_moles(GAS_MIASMA)
stank.set_moles(GAS_MIASMA,5)
stank.set_temperature(BODYTEMP_NORMAL)
if(T.air)
T.atmos_spawn_air("miasma=5;TEMP=293.15")
if(miasma_moles < 200)
T.assume_air(stank)
T.air_update_turf()
if(prob(40))
scavenge.Trigger()
if(prob(50))
@@ -66,9 +111,10 @@
playsound(src, 'sound/effects/sparks2.ogg', 100, TRUE)
C.deconstruct()
for(var/obj/O in range(1,src))
if(istype(O, /obj/item/trash) || istype(O, /obj/effect/decal/cleanable/blood/gibs))
if((world.time - last_spawn_time) > 10 SECONDS && istype(O, /obj/item/trash) || istype(O, /obj/effect/decal/cleanable/blood/gibs))
qdel(O)
be_fruitful()
last_spawn_time = world.time
/mob/living/simple_animal/hostile/plaguerat/CanAttack(atom/the_target)
if(istype(the_target,/mob/living/simple_animal))
@@ -86,14 +132,29 @@
*/
/mob/living/simple_animal/hostile/plaguerat/proc/be_fruitful()
var/cap = CONFIG_GET(number/ratcap)
if(LAZYLEN(SSmobs.cheeserats) >= cap)
var/cap = 10
if(LAZYLEN(GLOB.plague_rats) >= cap)
visible_message("<span class='warning'>[src] gnaws into its food, [cap] rats are now on the station!</span>")
return
var/mob/living/newmouse = new /mob/living/simple_animal/hostile/plaguerat(loc)
SSmobs.cheeserats += newmouse
visible_message("<span class='notice'>[src] gnaws into its food, attracting another rat!</span>")
/mob/living/simple_animal/hostile/plaguerat/proc/exit_vents()
if(!exit_vent || exit_vent.welded)
loc = entry_vent
entry_vent = null
return
loc = exit_vent.loc
entry_vent = null
exit_vent = null
in_vent = FALSE
var/area/new_area = get_area(loc)
message_admins("[src] came out at [new_area][ADMIN_JMP(loc)]!")
if(new_area)
new_area.Entered(src)
visible_message("<span class='notice'>[src] climbs out of the ventilation ducts!</span>")
min_next_vent = world.time + 900 //90 seconds between ventcrawls
/**
*Creates a chance to spawn more trash or gibs to repopulate. Otherwise, spawns a corpse or dirt.
*/
@@ -116,16 +177,12 @@
if(1 to 3)
var/pickedtrash = pick(GLOB.ratking_trash)
to_chat(owner, "<span class='notice'>Excellent, you find more trash to spread your filth!</span>")
new /obj/effect/decal/cleanable/dirt(T)
new pickedtrash(T)
if(4 to 6)
to_chat(owner, "<span class='notice'>You find blood and gibs to feed your young!</span>")
new /obj/effect/decal/cleanable/blood/gibs(T)
new /obj/effect/decal/cleanable/blood/(T)
if(7 to 18)
to_chat(owner, "<span class='notice'>A corpse rises from the ground. Best to leave it alone.</span>")
new /obj/effect/mob_spawn/human/corpse/assistant(T)
if(19 to 100)
if(!locate(/obj/effect/decal/cleanable/blood) in T)
new /obj/effect/decal/cleanable/blood/(T)
if(7 to 100)
to_chat(owner, "<span class='notice'>Drat. Nothing.</span>")
new /obj/effect/decal/cleanable/dirt(T)
StartCooldown()
+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()
+1 -1
View File
@@ -79,7 +79,7 @@
return 0
if(charge < amount)
return 0
charge = (charge - amount)
charge -= amount
if(!istype(loc, /obj/machinery/power/apc))
SSblackbox.record_feedback("tally", "cell_used", 1, type)
return 1
@@ -525,9 +525,11 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
temp_factor = 30
icon_state = base_icon_state
var/effective_temperature = min(removed.return_temperature(), 2500 * dynamic_heat_modifier)
//if there is more pluox and n2 then anything else, we receive no power increase from heat
if(power_changes)
power = max((removed.return_temperature() * temp_factor / T0C) * gasmix_power_ratio + power, 0)
power = max((effective_temperature * temp_factor / T0C) * gasmix_power_ratio + power, 0)
if(prob(50))
//(1 + (tritRad + pluoxDampen * bzDampen * o2Rad * plasmaRad / (10 - bzrads))) * freonbonus
@@ -538,8 +540,6 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
//Power * 0.55 * a value between 1 and 0.8
var/device_energy = power * REACTION_POWER_MODIFIER
var/effective_temperature = min(removed.return_temperature(), 2500 * dynamic_heat_modifier)
var/max_temp_increase = effective_temperature + ((device_energy * dynamic_heat_modifier) / THERMAL_RELEASE_CAP_MODIFIER)
//Calculate how much gas to release
//Varies based on power and gas content
@@ -60,6 +60,8 @@
if(M.can_inject(null, FALSE, def_zone, piercing)) // Pass the hit zone to see if it can inject by whether it hit the head or the body.
..(target, blocked, TRUE)
for(var/datum/reagent/medicine/R in reagents.reagent_list) //OD prevention time!
if(R.type in GLOB.blacklisted_medchems)
continue
if(M.reagents.has_reagent(R.type))
if(R.overdose_threshold == 0 || emptrig == TRUE) //Is there a possible OD?
M.reagents.add_reagent(R.type, R.volume)
@@ -147,8 +147,8 @@
/obj/item/reagent_containers/hypospray/medipen/ekit
name = "emergency first-aid autoinjector"
desc = "An epinephrine medipen with extra coagulant and antibiotics to help stabilize bad cuts and burns."
icon_state = "firstaid"
item_state = "firstaid"
icon_state = "healthpen"
item_state = "healthpen"
volume = 15
amount_per_transfer_from_this = 15
list_reagents = list(/datum/reagent/medicine/epinephrine = 12, /datum/reagent/medicine/coagulant = 2.5, /datum/reagent/medicine/spaceacillin = 0.5)
+1 -1
View File
@@ -142,7 +142,7 @@
if(unlock_hidden)
for(var/i in receiver.hidden_nodes)
CHECK_TICK
if(!hidden_nodes[i])
if(available_nodes[i] || researched_nodes[i] || visible_nodes[i])
receiver.hidden_nodes -= i //We can see it so let them see it too.
for(var/i in researched_nodes)
CHECK_TICK
@@ -60,6 +60,16 @@
hidden = TRUE
experimental = TRUE
/datum/techweb_node/nanite_storage_protocols
id = "nanite_storage_protocols"
display_name = "Nanite Storage Protocols"
description = "Advanced behaviours that allow nanites to increase their maximum volume at variable cost."
prereq_ids = list("nanite_smart")
design_ids = list("hive_nanites", "zip_nanites", "free_range_nanites", "unsafe_storage_nanites")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000)
hidden = TRUE
experimental = TRUE
/datum/techweb_node/interrogation
id = "interrogation"
display_name = "Enhanced Interrogation Technology"
@@ -14,25 +14,62 @@ Regenerative extracts:
/obj/item/slimecross/regenerative/proc/core_effect_before(mob/living/carbon/human/target, mob/user)
return
/obj/item/slimecross/regenerative/pre_attack(atom/A, mob/living/user, params, attackchain_flags, damage_multiplier)
if(isliving(A))
var/mob/living/M = A
if(M.stat == DEAD)
to_chat(user, "<span class='warning'>[src] will not work on the dead!</span>")
return TRUE //returning TRUE preemptively ends the attack chain and thus doesn't call afterattack, this is noteworthy for below as well
//inform the target that they're about to have a regenerative extract used on them
if(M != user) //targeting someone else
M.visible_message("<span class='notice'>[user] readies [src], holding it steady near [M] and guiding it to the center of [M.p_their()] mass...</span>",
"<span class='notice'>[user] readies [src], holding it steady near you and guiding it to the center of your mass...</span>")
if(!do_after(user, 50, target = M)) //5 seconds
return TRUE
else //targeting self
M.visible_message("<span class='notice'>[user] readies [src], holding it steady near [user.p_them()]self and guiding it to the center of [user.p_their()] mass...</span>",
"<span class='notice'>You ready [src], holding it steady near you and guiding it to the center of your mass...</span>")
if(!do_after(user, 10, target = M)) //1 second
return TRUE
. = ..()
else
. = ..()
/obj/item/slimecross/regenerative/afterattack(atom/target,mob/user,prox)
. = ..()
if(!prox || !isliving(target))
return
var/mob/living/H = target
if(H.stat == DEAD)
to_chat(user, "<span class='warning'>[src] will not work on the dead!</span>")
var/mob/living/M = target
if(M.stat == DEAD)
to_chat(user, "<span class='warning'>[M] died before you could apply [src]!</span>")
return
if(H != user)
user.visible_message("<span class='notice'>[user] crushes the [src] over [H], the milky goo quickly regenerating all of [H.p_their()] injuries!</span>",
"<span class='notice'>You squeeze the [src], and it bursts over [H], the milky goo regenerating [H.p_their()] injuries.</span>")
if(M != user)
user.visible_message("<span class='notice'>[user] crushes the [src] over [M], the milky goo quickly regenerating all of [M.p_their()] injuries!</span>",
"<span class='notice'>You squeeze the [src], and it bursts over [M], the milky goo regenerating [M.p_their()] injuries.</span>")
else
user.visible_message("<span class='notice'>[user] crushes the [src] over [user.p_them()]self, the milky goo quickly regenerating all of [user.p_their()] injuries!</span>",
"<span class='notice'>You squeeze the [src], and it bursts in your hand, splashing you with milky goo which quickly regenerates your injuries!</span>")
core_effect_before(H, user)
H.revive(full_heal = 1)
core_effect(H, user)
core_effect_before(M, user)
var/new_disgust_level = 0
if(iscarbon(M)) //simpler mobs don't have a disgust variable and we need to grab that.
var/mob/living/carbon/C = M
new_disgust_level = C.disgust + DISGUST_LEVEL_GROSS
M.revive(full_heal = 1)
M.set_disgust(new_disgust_level)
core_effect(M, user)
playsound(target, 'sound/effects/splat.ogg', 40, 1)
//warn receivers of the extract about the disgust if they're carbon, making it clear that the regenerative extract is causing this.
if(iscarbon(M))
var/obj/item/organ/stomach/S = M.getorganslot(ORGAN_SLOT_STOMACH) //for getting the stummy name
switch(new_disgust_level)
if(0 to DISGUST_LEVEL_GROSS)
to_chat(M,"<span class='warning'>While you recovered from [src], you feel a little nauseous.</span>")
if(DISGUST_LEVEL_GROSS to DISGUST_LEVEL_VERYGROSS)
to_chat(M,"<span class='warning'>While you recovered from [src], you feel quite queasy.</span>")
if(DISGUST_LEVEL_VERYGROSS to DISGUST_LEVEL_DISGUSTED)
to_chat(M,"<span class='warning'>While you recovered from [src], you feel like you're about to vomit!</span>")
if(DISGUST_LEVEL_DISGUSTED to INFINITY)
to_chat(M,"<span class='userdanger'>You feel absolutely sick. Maybe you should lay off the regenerative extracts until your [(S ? S.name : "stomach")] settles!</span>")
qdel(src)
/obj/item/slimecross/regenerative/grey
@@ -44,6 +44,13 @@
to_chat(user, "<span class='warning'>The devilish contract doesn't include the 'mind swappable' package, please try again another lifetime.</span>")
return
// lets not have people be mindswapped to/from people who have people currently in their vore bellies
if(has_vore_belly(user))
user.release_vore_contents(include_absorbed = TRUE, silent = TRUE)
if(has_vore_belly(victim))
victim.release_vore_contents(include_absorbed = TRUE, silent = TRUE)
//MIND TRANSFER BEGIN
var/mob/dead/observer/ghost = victim.ghostize()
user.mind.transfer_to(victim)