Merge remote-tracking branch 'citadel/master' into mobility_flags
This commit is contained in:
@@ -14,7 +14,8 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
var/list/objectives = list()
|
||||
var/antag_memory = ""//These will be removed with antag datum
|
||||
var/antag_moodlet //typepath of moodlet that the mob will gain with their status
|
||||
var/can_hijack = HIJACK_NEUTRAL //If these antags are alone on shuttle hijack happens.
|
||||
/// If above 0, this is the multiplier for the speed at which we hijack the shuttle. Do not directly read, use hijack_speed().
|
||||
var/hijack_speed = 0
|
||||
|
||||
//Antag panel properties
|
||||
var/show_in_antagpanel = TRUE //This will hide adding this antag type in antag panel, use only for internal subtypes that shouldn't be added directly but still show if possessed by mind
|
||||
@@ -229,6 +230,13 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
return
|
||||
antag_memory = new_memo
|
||||
|
||||
/// Gets how fast we can hijack the shuttle, return 0 for can not hijack. Defaults to hijack_speed var, override for custom stuff like buffing hijack speed for hijack objectives or something.
|
||||
/datum/antagonist/proc/hijack_speed()
|
||||
var/datum/objective/hijack/H = locate() in objectives
|
||||
if(!isnull(H?.hijack_speed_override))
|
||||
return H.hijack_speed_override
|
||||
return hijack_speed
|
||||
|
||||
//This one is created by admin tools for custom objectives
|
||||
/datum/antagonist/custom
|
||||
antagpanel_category = "Custom"
|
||||
|
||||
@@ -286,10 +286,10 @@
|
||||
var/mob/living/L = owner.current
|
||||
level_bloodcost = maxBloodVolume * 0.2
|
||||
//If the blood volume of the bloodsucker is lower than the cost to level up, return and inform the bloodsucker
|
||||
|
||||
|
||||
//TODO: Make this into a radial, or perhaps a tgui next UI
|
||||
// Purchase Power Prompt
|
||||
var/list/options = list()
|
||||
var/list/options = list()
|
||||
for(var/pickedpower in typesof(/datum/action/bloodsucker))
|
||||
var/datum/action/bloodsucker/power = pickedpower
|
||||
// If I don't own it, and I'm allowed to buy it.
|
||||
|
||||
+38
-31
@@ -14,6 +14,9 @@
|
||||
message_Trigger = ""//"Whom will you subvert to your will?"
|
||||
bloodsucker_can_buy = TRUE
|
||||
must_be_capacitated = TRUE
|
||||
var/list/hit //current hit, set while power is in use as we can't pass the list as an extra calling argument in registersignal.
|
||||
/// If set, uses this speed in deciseconds instead of world.tick_lag
|
||||
var/speed_override
|
||||
|
||||
/datum/action/bloodsucker/targeted/haste/CheckCanUse(display_error)
|
||||
. = ..()
|
||||
@@ -43,42 +46,46 @@
|
||||
return TRUE
|
||||
|
||||
/datum/action/bloodsucker/targeted/haste/FireTargetedPower(atom/A)
|
||||
// set waitfor = FALSE <---- DONT DO THIS!We WANT this power to hold up ClickWithPower(), so that we can unlock the power when it's done.
|
||||
// This is a non-async proc to make sure the power is "locked" until this finishes.
|
||||
hit = list()
|
||||
RegisterSignal(owner, COMSIG_MOVABLE_MOVED, .proc/on_move)
|
||||
var/mob/living/user = owner
|
||||
var/turf/T = isturf(A) ? A : get_turf(A)
|
||||
// Pulled? Not anymore.
|
||||
owner.pulledby = null
|
||||
// Step One: Heatseek toward Target's Turf
|
||||
walk_to(owner, T, 0, 0.01, 20) // NOTE: this runs in the background! to cancel it, you need to use walk(owner.current,0), or give them a new path.
|
||||
user.pulledby?.stop_pulling()
|
||||
// Go to target turf
|
||||
// DO NOT USE WALK TO.
|
||||
playsound(get_turf(owner), 'sound/weapons/punchmiss.ogg', 25, 1, -1)
|
||||
var/safety = 20
|
||||
while(get_turf(owner) != T && safety > 0 && !(isliving(target) && target.Adjacent(owner)))
|
||||
user.mobility_flags = NONE
|
||||
safety --
|
||||
// Did I get knocked down?
|
||||
if(owner && owner.incapacitated(ignore_restraints=TRUE, ignore_grab=TRUE))// owner.incapacitated())
|
||||
// We're gonna cancel. But am I on the ground? Spin me!
|
||||
if(!CHECK_MOBILITY(user, MOBILITY_STAND))
|
||||
var/send_dir = get_dir(owner, T)
|
||||
new /datum/forced_movement(owner, get_ranged_target_turf(owner, send_dir, 1), 1, FALSE)
|
||||
owner.spin(10)
|
||||
var/safety = get_dist(user, T) * 3 + 1
|
||||
var/consequetive_failures = 0
|
||||
var/speed = isnull(speed_override)? world.tick_lag : speed_override
|
||||
while(--safety && (get_turf(user) != T))
|
||||
var/success = step_towards(user, T) //This does not try to go around obstacles.
|
||||
if(!success)
|
||||
success = step_to(user, T) //this does
|
||||
if(!success)
|
||||
if(++consequetive_failures >= 3) //if 3 steps don't work
|
||||
break //just stop
|
||||
else
|
||||
consequetive_failures = 0
|
||||
if(user.resting)
|
||||
user.setDir(turn(user.dir, 90)) //down? spin2win :^)
|
||||
if(user.incapacitated(ignore_restraints = TRUE, ignore_grab = TRUE)) //actually down? stop.
|
||||
break
|
||||
// Spin/Stun people we pass.
|
||||
//var/mob/living/newtarget = locate(/mob/living) in oview(1, owner)
|
||||
var/list/mob/living/foundtargets = list()
|
||||
for(var/mob/living/newtarget in oview(1, owner))
|
||||
if (newtarget && newtarget != target && !(newtarget in foundtargets))//!newtarget.IsKnockdown())
|
||||
if (rand(0, 5) < level_current)
|
||||
playsound(get_turf(newtarget), "sound/weapons/punch[rand(1,4)].ogg", 15, 1, -1)
|
||||
newtarget.DefaultCombatKnockdown(10 + level_current * 5)
|
||||
if(newtarget.IsStun())
|
||||
newtarget.spin(10,1)
|
||||
if (rand(0,4))
|
||||
newtarget.drop_all_held_items()
|
||||
foundtargets += newtarget
|
||||
sleep(1)
|
||||
user?.update_mobility() //Let the poor guy move again
|
||||
if(success) //don't sleep if we failed to move.
|
||||
sleep(speed)
|
||||
UnregisterSignal(owner, COMSIG_MOVABLE_MOVED)
|
||||
hit = null
|
||||
user.update_canmove()
|
||||
|
||||
/datum/action/bloodsucker/targeted/haste/DeactivatePower(mob/living/user = owner, mob/living/target)
|
||||
..() // activate = FALSE
|
||||
user.update_mobility()
|
||||
user.update_canmove()
|
||||
|
||||
/datum/action/bloodsucker/targeted/haste/proc/on_move()
|
||||
for(var/mob/living/L in dview(1, get_turf(owner)))
|
||||
if(!hit[L] && (L != owner))
|
||||
hit[L] = TRUE
|
||||
playsound(L, "sound/weapons/punch[rand(1,4)].ogg", 15, 1, -1)
|
||||
L.Knockdown(10 + level_current * 5, override_hardstun = 0.1)
|
||||
L.spin(10, 1)
|
||||
+2
-2
@@ -54,8 +54,8 @@
|
||||
REMOVE_TRAIT(user, TRAIT_VIRUSIMMUNE, "bloodsucker")
|
||||
var/obj/item/organ/heart/vampheart/H = user.getorganslot(ORGAN_SLOT_HEART)
|
||||
var/obj/item/organ/eyes/vassal/bloodsucker/E = user.getorganslot(ORGAN_SLOT_EYES)
|
||||
E.flash_protect = 0
|
||||
|
||||
E.flash_protect = 0
|
||||
|
||||
// WE ARE ALIVE! //
|
||||
bloodsuckerdatum.poweron_masquerade = TRUE
|
||||
while(bloodsuckerdatum && ContinueActive(user))
|
||||
@@ -5,7 +5,6 @@
|
||||
var/special_role = ROLE_BROTHER
|
||||
var/datum/team/brother_team/team
|
||||
antag_moodlet = /datum/mood_event/focused
|
||||
can_hijack = HIJACK_HIJACKER
|
||||
|
||||
/datum/antagonist/brother/create_team(datum/team/brother_team/new_team)
|
||||
if(!new_team)
|
||||
|
||||
@@ -5,49 +5,49 @@ is currently following.
|
||||
*/
|
||||
|
||||
GLOBAL_LIST_INIT(disease_ability_singletons, list(
|
||||
new /datum/disease_ability/action/cough,
|
||||
new /datum/disease_ability/action/sneeze,
|
||||
new /datum/disease_ability/action/infect,
|
||||
new /datum/disease_ability/symptom/mild/cough,
|
||||
new /datum/disease_ability/symptom/mild/sneeze,
|
||||
new /datum/disease_ability/symptom/medium/shedding,
|
||||
new /datum/disease_ability/symptom/medium/beard,
|
||||
new /datum/disease_ability/symptom/medium/hallucigen,
|
||||
new /datum/disease_ability/symptom/medium/choking,
|
||||
new /datum/disease_ability/symptom/medium/confusion,
|
||||
new /datum/disease_ability/symptom/medium/vomit,
|
||||
new /datum/disease_ability/symptom/medium/voice_change,
|
||||
new /datum/disease_ability/symptom/medium/visionloss,
|
||||
new /datum/disease_ability/symptom/medium/deafness,
|
||||
new /datum/disease_ability/symptom/powerful/narcolepsy,
|
||||
new /datum/disease_ability/symptom/medium/fever,
|
||||
new /datum/disease_ability/symptom/medium/shivering,
|
||||
new /datum/disease_ability/symptom/medium/headache,
|
||||
new /datum/disease_ability/symptom/medium/nano_boost,
|
||||
new /datum/disease_ability/symptom/medium/nano_destroy,
|
||||
new /datum/disease_ability/symptom/medium/viraladaptation,
|
||||
new /datum/disease_ability/symptom/medium/viralevolution,
|
||||
new /datum/disease_ability/symptom/medium/vitiligo,
|
||||
new /datum/disease_ability/symptom/medium/revitiligo,
|
||||
new /datum/disease_ability/symptom/medium/itching,
|
||||
new /datum/disease_ability/symptom/medium/heal/weight_loss,
|
||||
new /datum/disease_ability/symptom/medium/heal/sensory_restoration,
|
||||
new /datum/disease_ability/symptom/medium/heal/mind_restoration,
|
||||
new /datum/disease_ability/symptom/powerful/fire,
|
||||
new /datum/disease_ability/symptom/powerful/flesh_eating,
|
||||
// new /datum/disease_ability/symptom/powerful/genetic_mutation,
|
||||
new /datum/disease_ability/symptom/powerful/inorganic_adaptation,
|
||||
new /datum/disease_ability/symptom/powerful/heal/starlight,
|
||||
new /datum/disease_ability/symptom/powerful/heal/oxygen,
|
||||
new /datum/disease_ability/symptom/powerful/heal/chem,
|
||||
new /datum/disease_ability/symptom/powerful/heal/metabolism,
|
||||
new /datum/disease_ability/symptom/powerful/heal/dark,
|
||||
new /datum/disease_ability/symptom/powerful/heal/water,
|
||||
new /datum/disease_ability/symptom/powerful/heal/plasma,
|
||||
new /datum/disease_ability/symptom/powerful/heal/radiation,
|
||||
new /datum/disease_ability/symptom/powerful/heal/coma,
|
||||
new /datum/disease_ability/symptom/powerful/youth
|
||||
))
|
||||
new /datum/disease_ability/action/cough,
|
||||
new /datum/disease_ability/action/sneeze,
|
||||
new /datum/disease_ability/action/infect,
|
||||
new /datum/disease_ability/symptom/mild/cough,
|
||||
new /datum/disease_ability/symptom/mild/sneeze,
|
||||
new /datum/disease_ability/symptom/medium/shedding,
|
||||
new /datum/disease_ability/symptom/medium/beard,
|
||||
new /datum/disease_ability/symptom/medium/hallucigen,
|
||||
new /datum/disease_ability/symptom/medium/choking,
|
||||
new /datum/disease_ability/symptom/medium/confusion,
|
||||
new /datum/disease_ability/symptom/medium/vomit,
|
||||
new /datum/disease_ability/symptom/medium/voice_change,
|
||||
new /datum/disease_ability/symptom/medium/visionloss,
|
||||
new /datum/disease_ability/symptom/medium/deafness,
|
||||
new /datum/disease_ability/symptom/powerful/narcolepsy,
|
||||
new /datum/disease_ability/symptom/medium/fever,
|
||||
new /datum/disease_ability/symptom/medium/shivering,
|
||||
new /datum/disease_ability/symptom/medium/headache,
|
||||
new /datum/disease_ability/symptom/medium/nano_boost,
|
||||
new /datum/disease_ability/symptom/medium/nano_destroy,
|
||||
new /datum/disease_ability/symptom/medium/viraladaptation,
|
||||
new /datum/disease_ability/symptom/medium/viralevolution,
|
||||
new /datum/disease_ability/symptom/medium/disfiguration,
|
||||
new /datum/disease_ability/symptom/medium/polyvitiligo,
|
||||
new /datum/disease_ability/symptom/medium/itching,
|
||||
new /datum/disease_ability/symptom/medium/heal/weight_loss,
|
||||
new /datum/disease_ability/symptom/medium/heal/sensory_restoration,
|
||||
new /datum/disease_ability/symptom/medium/heal/mind_restoration,
|
||||
new /datum/disease_ability/symptom/powerful/fire,
|
||||
new /datum/disease_ability/symptom/powerful/flesh_eating,
|
||||
new /datum/disease_ability/symptom/powerful/genetic_mutation,
|
||||
new /datum/disease_ability/symptom/powerful/inorganic_adaptation,
|
||||
new /datum/disease_ability/symptom/powerful/heal/starlight,
|
||||
new /datum/disease_ability/symptom/powerful/heal/oxygen,
|
||||
new /datum/disease_ability/symptom/powerful/heal/chem,
|
||||
new /datum/disease_ability/symptom/powerful/heal/metabolism,
|
||||
new /datum/disease_ability/symptom/powerful/heal/dark,
|
||||
new /datum/disease_ability/symptom/powerful/heal/water,
|
||||
new /datum/disease_ability/symptom/powerful/heal/plasma,
|
||||
new /datum/disease_ability/symptom/powerful/heal/radiation,
|
||||
new /datum/disease_ability/symptom/powerful/heal/coma,
|
||||
new /datum/disease_ability/symptom/powerful/youth
|
||||
))
|
||||
|
||||
/datum/disease_ability
|
||||
var/name
|
||||
@@ -57,7 +57,7 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list(
|
||||
var/short_desc = ""
|
||||
var/long_desc = ""
|
||||
var/stat_block = ""
|
||||
var/threshold_block = list()
|
||||
var/threshold_block = ""
|
||||
var/category = ""
|
||||
|
||||
var/list/symptoms
|
||||
@@ -76,7 +76,7 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list(
|
||||
resistance += initial(S.resistance)
|
||||
stage_speed += initial(S.stage_speed)
|
||||
transmittable += initial(S.transmittable)
|
||||
threshold_block += initial(S.threshold_desc)
|
||||
threshold_block += "<br><br>[initial(S.threshold_desc)]"
|
||||
stat_block = "Resistance: [resistance]<br>Stealth: [stealth]<br>Stage Speed: [stage_speed]<br>Transmissibility: [transmittable]<br><br>"
|
||||
if(symptoms.len == 1) //lazy boy's dream
|
||||
name = initial(S.name)
|
||||
@@ -106,10 +106,8 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list(
|
||||
for(var/T in symptoms)
|
||||
var/datum/symptom/S = new T()
|
||||
SD.symptoms += S
|
||||
S.OnAdd(SD)
|
||||
if(SD.processing)
|
||||
if(S.Start(SD))
|
||||
S.next_activation = world.time + rand(S.symptom_delay_min * 10, S.symptom_delay_max * 10)
|
||||
S.Start(SD)
|
||||
SD.Refresh()
|
||||
for(var/T in actions)
|
||||
var/datum/action/A = new T()
|
||||
@@ -136,7 +134,6 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list(
|
||||
var/datum/symptom/S = locate(T) in SD.symptoms
|
||||
if(S)
|
||||
SD.symptoms -= S
|
||||
S.OnRemove(SD)
|
||||
if(SD.processing)
|
||||
S.End(SD)
|
||||
qdel(S)
|
||||
@@ -296,7 +293,6 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list(
|
||||
cost = 8
|
||||
category = "Symptom (Strong+)"
|
||||
|
||||
|
||||
/******MILD******/
|
||||
|
||||
/datum/disease_ability/symptom/mild/cough
|
||||
@@ -377,11 +373,11 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list(
|
||||
/datum/disease_ability/symptom/medium/viralevolution
|
||||
symptoms = list(/datum/symptom/viralevolution)
|
||||
|
||||
/datum/disease_ability/symptom/medium/vitiligo
|
||||
symptoms = list(/datum/symptom/vitiligo)
|
||||
/datum/disease_ability/symptom/medium/polyvitiligo
|
||||
symptoms = list(/datum/symptom/polyvitiligo)
|
||||
|
||||
/datum/disease_ability/symptom/medium/revitiligo
|
||||
symptoms = list(/datum/symptom/revitiligo)
|
||||
/datum/disease_ability/symptom/medium/disfiguration
|
||||
symptoms = list(/datum/symptom/disfiguration)
|
||||
|
||||
/datum/disease_ability/symptom/medium/itching
|
||||
symptoms = list(/datum/symptom/itching)
|
||||
@@ -409,11 +405,9 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list(
|
||||
/datum/disease_ability/symptom/powerful/flesh_eating
|
||||
symptoms = list(/datum/symptom/flesh_eating)
|
||||
|
||||
/*
|
||||
/datum/disease_ability/symptom/powerful/genetic_mutation
|
||||
symptoms = list(/datum/symptom/genetic_mutation)
|
||||
cost = 8
|
||||
*/
|
||||
|
||||
/datum/disease_ability/symptom/powerful/inorganic_adaptation
|
||||
symptoms = list(/datum/symptom/inorganic_adaptation)
|
||||
@@ -457,4 +451,4 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list(
|
||||
/datum/disease_ability/symptom/powerful/heal/coma
|
||||
symptoms = list(/datum/symptom/heal/coma)
|
||||
short_desc = "Cause victims to fall into a healing coma when hurt."
|
||||
long_desc = "Cause victims to fall into a healing coma when hurt."
|
||||
long_desc = "Cause victims to fall into a healing coma when hurt."
|
||||
@@ -12,7 +12,6 @@
|
||||
var/list/name_source
|
||||
show_in_antagpanel = FALSE
|
||||
antag_moodlet = /datum/mood_event/focused
|
||||
can_hijack = HIJACK_PREVENT
|
||||
|
||||
/datum/antagonist/ert/on_gain()
|
||||
update_name()
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
var/obj/item/claymore/highlander/sword
|
||||
show_in_antagpanel = FALSE
|
||||
show_name_in_check_antagonists = TRUE
|
||||
can_hijack = HIJACK_HIJACKER
|
||||
hijack_speed = 2 //if you kill everyone and actually haev a hand to hijack with, you win??
|
||||
|
||||
/datum/antagonist/highlander/apply_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/L = owner.current || mob_override
|
||||
|
||||
@@ -8,11 +8,6 @@
|
||||
var/give_objectives = TRUE
|
||||
var/give_equipment = TRUE
|
||||
|
||||
/datum/antagonist/ninja/New()
|
||||
if(helping_station)
|
||||
can_hijack = HIJACK_PREVENT
|
||||
. = ..()
|
||||
|
||||
/datum/antagonist/ninja/apply_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/M = mob_override || owner.current
|
||||
update_ninja_icons_added(M)
|
||||
@@ -135,8 +130,6 @@
|
||||
adj = "objectiveless"
|
||||
else
|
||||
return
|
||||
if(helping_station)
|
||||
can_hijack = HIJACK_PREVENT
|
||||
new_owner.assigned_role = ROLE_NINJA
|
||||
new_owner.special_role = ROLE_NINJA
|
||||
new_owner.add_antag_datum(src)
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
var/always_new_team = FALSE //If not assigned a team by default ops will try to join existing ones, set this to TRUE to always create new team.
|
||||
var/send_to_spawnpoint = TRUE //Should the user be moved to default spawnpoint.
|
||||
var/nukeop_outfit = /datum/outfit/syndicate
|
||||
can_hijack = HIJACK_HIJACKER //Alternative way to wipe out the station.
|
||||
|
||||
/datum/antagonist/nukeop/proc/update_synd_icons_added(mob/living/M)
|
||||
var/datum/atom_hud/antag/opshud = GLOB.huds[ANTAG_HUD_OPS]
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
show_in_antagpanel = FALSE
|
||||
var/datum/objective/mission
|
||||
var/datum/team/ert/ert_team
|
||||
can_hijack = HIJACK_PREVENT
|
||||
|
||||
/datum/antagonist/official/greet()
|
||||
to_chat(owner, "<B><font size=3 color=red>You are a CentCom Official.</font></B>")
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
var/should_give_codewords = TRUE
|
||||
var/should_equip = TRUE
|
||||
var/traitor_kind = TRAITOR_HUMAN //Set on initial assignment
|
||||
can_hijack = HIJACK_HIJACKER
|
||||
hijack_speed = 0.5 //10 seconds per hijack stage by default
|
||||
|
||||
/datum/antagonist/traitor/on_gain()
|
||||
if(owner.current && isAI(owner.current))
|
||||
@@ -60,6 +60,7 @@
|
||||
message = GLOB.syndicate_code_response_regex.Replace(message, "<span class='red'>$1</span>")
|
||||
hearing_args[HEARING_RAW_MESSAGE] = message
|
||||
|
||||
// needs to be refactored to base /datum/antagonist sometime..
|
||||
/datum/antagonist/traitor/proc/add_objective(datum/objective/O)
|
||||
objectives += O
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
name = "Wishgranter Avatar"
|
||||
show_in_antagpanel = FALSE
|
||||
show_name_in_check_antagonists = TRUE
|
||||
can_hijack = HIJACK_HIJACKER
|
||||
|
||||
/datum/antagonist/wishgranter/proc/forge_objectives()
|
||||
var/datum/objective/hijack/hijack = new
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
var/move_to_lair = TRUE
|
||||
var/outfit_type = /datum/outfit/wizard
|
||||
var/wiz_age = WIZARD_AGE_MIN /* Wizards by nature cannot be too young. */
|
||||
can_hijack = HIJACK_HIJACKER
|
||||
|
||||
/datum/antagonist/wizard/on_gain()
|
||||
register()
|
||||
|
||||
@@ -53,7 +53,8 @@
|
||||
H.adjust_blurriness(1)
|
||||
H.visible_message("<span class='warning'>[H] is creamed by [src]!</span>", "<span class='userdanger'>You've been creamed by [src]!</span>")
|
||||
playsound(H, "desceration", 50, TRUE)
|
||||
reagents.trans_to(H,15) //Cream pie combat
|
||||
if(!H.is_mouth_covered())
|
||||
reagents.trans_to(H,15) //Cream pie combat
|
||||
if(!H.creamed) // one layer at a time
|
||||
H.add_overlay(creamoverlay)
|
||||
H.creamed = TRUE
|
||||
|
||||
@@ -122,13 +122,10 @@
|
||||
to_chat(usr, "<span class='warning'>Error: Insufficient credits for [prize.equipment_name] on [I]!</span>")
|
||||
flick(icon_deny, src)
|
||||
else
|
||||
if (I.mining_points -= prize.cost)
|
||||
to_chat(usr, "<span class='notice'>[src] clanks to life briefly before vending [prize.equipment_name]!</span>")
|
||||
new prize.equipment_path(src.loc)
|
||||
SSblackbox.record_feedback("nested tally", "mining_equipment_bought", 1, list("[type]", "[prize.equipment_path]"))
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>Error: Transaction failure, please try again later!</span>")
|
||||
flick(icon_deny, src)
|
||||
I.mining_points -= prize.cost
|
||||
to_chat(usr, "<span class='notice'>[src] clanks to life briefly before vending [prize.equipment_name]!</span>")
|
||||
new prize.equipment_path(src.loc)
|
||||
SSblackbox.record_feedback("nested tally", "mining_equipment_bought", 1, list("[type]", "[prize.equipment_path]"))
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>Error: An ID with a registered account is required!</span>")
|
||||
flick(icon_deny, src)
|
||||
|
||||
@@ -834,12 +834,31 @@
|
||||
update_inv_handcuffed()
|
||||
update_hud_handcuffed()
|
||||
|
||||
/mob/living/carbon/proc/can_defib()
|
||||
var/tlimit = DEFIB_TIME_LIMIT * 10
|
||||
var/obj/item/organ/heart = getorgan(/obj/item/organ/heart)
|
||||
if(suiciding || hellbound || HAS_TRAIT(src, TRAIT_HUSK))
|
||||
return
|
||||
if((world.time - timeofdeath) > tlimit)
|
||||
return
|
||||
if((getBruteLoss() >= MAX_REVIVE_BRUTE_DAMAGE) || (getFireLoss() >= MAX_REVIVE_FIRE_DAMAGE))
|
||||
return
|
||||
if(!heart || (heart.organ_flags & ORGAN_FAILING))
|
||||
return
|
||||
var/obj/item/organ/brain/BR = getorgan(/obj/item/organ/brain)
|
||||
if(QDELETED(BR) || BR.brain_death || (BR.organ_flags & ORGAN_FAILING) || suiciding)
|
||||
return
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/fully_heal(admin_revive = FALSE)
|
||||
if(reagents)
|
||||
reagents.clear_reagents()
|
||||
var/obj/item/organ/brain/B = getorgan(/obj/item/organ/brain)
|
||||
if(B)
|
||||
B.brain_death = FALSE
|
||||
for(var/O in internal_organs)
|
||||
var/obj/item/organ/organ = O
|
||||
organ.setOrganDamage(0)
|
||||
for(var/thing in diseases)
|
||||
var/datum/disease/D = thing
|
||||
if(D.severity != DISEASE_SEVERITY_POSITIVE)
|
||||
@@ -852,7 +871,8 @@
|
||||
qdel(R)
|
||||
update_handcuffed()
|
||||
if(reagents)
|
||||
reagents.addiction_list = list()
|
||||
for(var/addi in reagents.addiction_list)
|
||||
reagents.remove_addiction(addi)
|
||||
cure_all_traumas(TRAUMA_RESILIENCE_MAGIC)
|
||||
..()
|
||||
// heal ears after healing traits, since ears check TRAIT_DEAF trait
|
||||
|
||||
@@ -803,7 +803,7 @@
|
||||
hud_used.staminas?.update_icon_state()
|
||||
hud_used.staminabuffer?.update_icon_state()
|
||||
|
||||
/mob/living/carbon/human/fully_heal(admin_revive = 0)
|
||||
/mob/living/carbon/human/fully_heal(admin_revive = FALSE)
|
||||
if(admin_revive)
|
||||
regenerate_limbs()
|
||||
regenerate_organs()
|
||||
|
||||
@@ -135,7 +135,7 @@
|
||||
RegisterSignal(owner, COMSIG_CLICK_SHIFT, .proc/examinate_check)
|
||||
RegisterSignal(src, COMSIG_ATOM_HEARER_IN_VIEW, .proc/include_owner)
|
||||
RegisterSignal(owner, COMSIG_LIVING_REGENERATE_LIMBS, .proc/unlist_head)
|
||||
RegisterSignal(owner, COMSIG_LIVING_FULLY_HEAL, .proc/retrieve_head)
|
||||
RegisterSignal(owner, COMSIG_LIVING_REVIVE, .proc/retrieve_head)
|
||||
|
||||
/obj/item/dullahan_relay/proc/examinate_check(atom/source, mob/user)
|
||||
if(user.client.eye == src)
|
||||
@@ -148,8 +148,9 @@
|
||||
/obj/item/dullahan_relay/proc/unlist_head(datum/source, noheal = FALSE, list/excluded_limbs)
|
||||
excluded_limbs |= BODY_ZONE_HEAD // So we don't gib when regenerating limbs.
|
||||
|
||||
/obj/item/dullahan_relay/proc/retrieve_head(datum/source, admin_revive = FALSE)
|
||||
if(admin_revive) //retrieving the owner's head for ahealing purposes.
|
||||
//Retrieving the owner's head for better ahealing.
|
||||
/obj/item/dullahan_relay/proc/retrieve_head(datum/source, full_heal, admin_revive)
|
||||
if(admin_revive)
|
||||
var/obj/item/bodypart/head/H = loc
|
||||
var/turf/T = get_turf(owner)
|
||||
if(H && istype(H) && T && !(H in owner.GetAllContents()))
|
||||
|
||||
@@ -213,6 +213,16 @@
|
||||
PDA.f_lum = 0
|
||||
PDA.update_icon()
|
||||
visible_message("<span class='danger'>The light in [PDA] shorts out!</span>")
|
||||
else if(istype(O, /obj/item/gun))
|
||||
var/obj/item/gun/weapon = O
|
||||
if(weapon.gun_light)
|
||||
var/obj/item/flashlight/seclite/light = weapon.gun_light
|
||||
light.forceMove(get_turf(weapon))
|
||||
light.burn()
|
||||
weapon.gun_light = null
|
||||
weapon.update_gunlight()
|
||||
QDEL_NULL(weapon.alight)
|
||||
visible_message("<span class='danger'>[light] on [O] flickers out and disintegrates!</span>")
|
||||
else
|
||||
visible_message("<span class='danger'>[O] is disintegrated by [src]!</span>")
|
||||
O.burn()
|
||||
|
||||
@@ -481,7 +481,8 @@
|
||||
med_hud_set_status()
|
||||
|
||||
//proc used to ressuscitate a mob
|
||||
/mob/living/proc/revive(full_heal = 0, admin_revive = 0)
|
||||
/mob/living/proc/revive(full_heal = FALSE, admin_revive = FALSE)
|
||||
SEND_SIGNAL(src, COMSIG_LIVING_REVIVE, full_heal, admin_revive)
|
||||
if(full_heal)
|
||||
fully_heal(admin_revive)
|
||||
if(stat == DEAD && can_be_revived()) //in some cases you can't revive (e.g. no brain)
|
||||
@@ -526,11 +527,6 @@
|
||||
fire_stacks = 0
|
||||
confused = 0
|
||||
update_mobility()
|
||||
var/datum/component/mood/mood = GetComponent(/datum/component/mood)
|
||||
if (mood)
|
||||
QDEL_LIST_ASSOC_VAL(mood.mood_events)
|
||||
mood.sanity = SANITY_GREAT
|
||||
mood.update_mood()
|
||||
//Heal all organs
|
||||
if(iscarbon(src))
|
||||
var/mob/living/carbon/C = src
|
||||
@@ -538,8 +534,6 @@
|
||||
for(var/organ in C.internal_organs)
|
||||
var/obj/item/organ/O = organ
|
||||
O.setOrganDamage(0)
|
||||
SEND_SIGNAL(src, COMSIG_LIVING_FULLY_HEAL, admin_revive)
|
||||
|
||||
|
||||
//proc called by revive(), to check if we can actually ressuscitate the mob (we don't want to revive him and have him instantly die again)
|
||||
/mob/living/proc/can_be_revived()
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
name = "pAI"
|
||||
icon = 'icons/mob/pai.dmi'
|
||||
icon_state = "repairbot"
|
||||
mouse_opacity = MOUSE_OPACITY_OPAQUE
|
||||
density = FALSE
|
||||
pass_flags = PASSTABLE | PASSMOB
|
||||
mob_size = MOB_SIZE_TINY
|
||||
@@ -75,7 +74,7 @@
|
||||
var/emitteroverloadcd = 100
|
||||
|
||||
var/radio_short = FALSE
|
||||
var/radio_short_cooldown = 5 MINUTES
|
||||
var/radio_short_cooldown = 3 MINUTES
|
||||
var/radio_short_timerid
|
||||
|
||||
mobility_flags = NONE
|
||||
|
||||
@@ -56,7 +56,8 @@
|
||||
if(P.stun)
|
||||
fold_in(force = TRUE)
|
||||
visible_message("<span class='warning'>The electrically-charged projectile disrupts [src]'s holomatrix, forcing [src] to fold in!</span>")
|
||||
return ..()
|
||||
. = ..()
|
||||
return BULLET_ACT_FORCE_PIERCE
|
||||
|
||||
/mob/living/silicon/pai/stripPanelUnequip(obj/item/what, mob/who, where) //prevents stripping
|
||||
to_chat(src, "<span class='warning'>Your holochassis stutters and warps intensely as you attempt to interact with the object, forcing you to cease lest the field fail.</span>")
|
||||
|
||||
@@ -596,8 +596,8 @@
|
||||
|
||||
/obj/item/robot_module/peacekeeper/do_transform_animation()
|
||||
..()
|
||||
to_chat(loc, "<span class='userdanger'>Under ASIMOV/CREWSIMOV, you are an enforcer of the PEACE and preventer of HUMAN/CREW HARM. \
|
||||
You are not a security module and you are expected to follow orders and prevent harm above all else. Space law means nothing to you.</span>")
|
||||
to_chat(loc, "<span class='userdanger'>Under ASIMOV/CREWSIMOV, you are an enforcer of the PEACE. \
|
||||
You are not a security module and you are expected to follow orders to the best of your abilities without causing harm. Space law means nothing to you.</span>")
|
||||
|
||||
/obj/item/robot_module/peacekeeper/be_transformed_to(obj/item/robot_module/old_module)
|
||||
var/mob/living/silicon/robot/R = loc
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
//shameless copies of carps.
|
||||
|
||||
/mob/living/simple_animal/hostile/shark
|
||||
name = "Space Shark"
|
||||
desc = "The best terror of the seas, next to the kraken."
|
||||
icon_state = "shark"
|
||||
icon_living = "shark"
|
||||
icon = 'icons/mob/sharks.dmi'
|
||||
icon_dead = "shark_dead"
|
||||
icon_gib = "carp_gib"
|
||||
environment_smash = 0
|
||||
speak_chance = 0
|
||||
turns_per_move = 3
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/carpmeat = 3)
|
||||
response_help = "pets"
|
||||
response_disarm = "gently pushes aside"
|
||||
response_harm = "hits"
|
||||
speed = 0
|
||||
maxHealth = 75
|
||||
health = 75
|
||||
harm_intent_damage = 18
|
||||
melee_damage_lower = 18
|
||||
melee_damage_upper = 18
|
||||
attacktext = "maims"
|
||||
attack_sound = 'sound/weapons/bite.ogg'
|
||||
gold_core_spawnable = 1
|
||||
//Space shark aren't affected by cold.
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
minbodytemp = 0
|
||||
maxbodytemp = 1500
|
||||
|
||||
faction = list("shark")
|
||||
|
||||
/mob/living/simple_animal/hostile/shark/Process_Spacemove(var/movement_dir = 0)
|
||||
return 1 //No drifting in space for space sharks....either!
|
||||
|
||||
/mob/living/simple_animal/hostile/shark/FindTarget()
|
||||
. = ..()
|
||||
if(.)
|
||||
emote("me", 1, "growls at [.]!")
|
||||
|
||||
/mob/living/simple_animal/hostile/shark/AttackingTarget()
|
||||
. =..()
|
||||
var/mob/living/carbon/L = .
|
||||
if(istype(L))
|
||||
if(prob(25))
|
||||
L.Knockdown(20)
|
||||
L.visible_message("<span class='danger'>\the [src] knocks down \the [L]!</span>")
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/shark/laser
|
||||
name = "Laser-Shark"
|
||||
desc = "NOW we've jumped the shark."
|
||||
icon_state = "lasershark"
|
||||
icon_living = "lasershark"
|
||||
icon_dead = "lasershark_dead"
|
||||
icon_gib = "carp_gib"
|
||||
ranged = 1
|
||||
retreat_distance = 3
|
||||
minimum_distance = 0 //Between shots they can and will close in to nash
|
||||
projectiletype = /obj/item/projectile/beam/laser/heavylaser
|
||||
projectilesound = 'sound/weapons/lasercannonfire.ogg'
|
||||
maxHealth = 50
|
||||
health = 50
|
||||
|
||||
/mob/living/simple_animal/hostile/shark/kawaii
|
||||
name = "Kawaii Shark"
|
||||
desc = "Senpai~ Notice me.."
|
||||
icon_state = "kawaiishark"
|
||||
icon_living = "kawaiishark"
|
||||
icon_dead = "kawaiishark_dead"
|
||||
speak = list("Oh Senpai","Notice me senpai!","Oh my...","Kawaii~")
|
||||
speak_emote = list("lovingly says","says")
|
||||
speak_chance = 2
|
||||
turns_per_move = 3
|
||||
butcher_results = list(/mob/living/simple_animal/butterfly = 3)
|
||||
maxHealth = 50
|
||||
health = 50
|
||||
maxbodytemp = INFINITY
|
||||
|
||||
harm_intent_damage = 0
|
||||
melee_damage_lower = 0
|
||||
melee_damage_upper = 0
|
||||
attacktext = "violently hugs"
|
||||
vision_range = 0
|
||||
|
||||
/mob/living/simple_animal/hostile/shark/kawaii/death()
|
||||
say("Senpai, you noticed~!")
|
||||
LoseAggro()
|
||||
..()
|
||||
walk(src, 0)
|
||||
@@ -0,0 +1,422 @@
|
||||
#define POOL_NO_OVERDOSE_MEDICINE_MAX 5 //max units of no-overdose medicine to allow mobs to have through duplication
|
||||
|
||||
//Originally stolen from paradise. Credits to tigercat2000.
|
||||
//Modified a lot by Kokojo and Tortellini Tony for hippiestation.
|
||||
//Heavily refactored by tgstation
|
||||
/obj/machinery/pool
|
||||
icon = 'icons/obj/machines/pool.dmi'
|
||||
anchored = TRUE
|
||||
resistance_flags = INDESTRUCTIBLE
|
||||
|
||||
/obj/machinery/pool/controller
|
||||
name = "\improper Pool Controller"
|
||||
desc = "An advanced substance generation and fluid tank management system that can refill the contents of a pool to a completely different substance in minutes."
|
||||
icon_state = "poolc_3"
|
||||
density = TRUE
|
||||
use_power = TRUE
|
||||
idle_power_usage = 75
|
||||
/// How far it scans for pool objects
|
||||
var/scan_range = 6
|
||||
/// Is pool mist currently on?
|
||||
var/mist_state = FALSE
|
||||
/// Linked mist effects
|
||||
var/list/obj/effect/mist/linked_mist = list()
|
||||
/// Pool turfs
|
||||
var/list/turf/open/pool/linked_turfs = list()
|
||||
/// All mobs in pool
|
||||
var/list/mob/living/mobs_in_pool = list()
|
||||
/// Is the pool bloody?
|
||||
var/bloody = 0
|
||||
/// Last time we process_reagents()'d
|
||||
var/last_reagent_process = 0
|
||||
/// Maximum amount we will take from a beaker
|
||||
var/max_beaker_transfer = 100
|
||||
/// Minimum amount of a reagent for it to work on us
|
||||
var/min_reagent_amount = 10
|
||||
/// ADMINBUS ONLY - WHETHER OR NOT WE HAVE NOREACT ;)
|
||||
var/noreact_reagents = FALSE
|
||||
/// how fast in deciseconds between reagent processes
|
||||
var/reagent_tick_interval = 5
|
||||
/// Can we use unsafe temperatures
|
||||
var/temperature_unlocked = FALSE
|
||||
/// See __DEFINES/pool.dm, temperature defines
|
||||
var/temperature = POOL_NORMAL
|
||||
/// Whether or not the pool can be drained
|
||||
var/drainable = FALSE
|
||||
// Whether or not the pool is drained
|
||||
var/drained = FALSE
|
||||
/// Pool drain
|
||||
var/obj/machinery/pool/drain/linked_drain
|
||||
/// Pool filter
|
||||
var/obj/machinery/pool/filter/linked_filter
|
||||
/// Next world.time you can interact with settings
|
||||
var/interact_delay = 0
|
||||
/// Airlock style shocks
|
||||
var/shocked = FALSE
|
||||
/// Old reagent color, used to determine if update_color needs to reset colors.
|
||||
var/old_rcolor
|
||||
/// Just to prevent spam
|
||||
var/draining = FALSE
|
||||
/// Reagent blacklisting
|
||||
var/respect_reagent_blacklist = TRUE
|
||||
|
||||
/obj/machinery/pool/controller/examine(mob/user)
|
||||
. = ..()
|
||||
. += "<span class='boldnotice'>Alt click to drain reagents.</span>"
|
||||
|
||||
/obj/machinery/pool/controller/Initialize()
|
||||
. = ..()
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
create_reagents(1000)
|
||||
if(noreact_reagents)
|
||||
reagents.reagents_holder_flags |= NO_REACT
|
||||
wires = new /datum/wires/poolcontroller(src)
|
||||
scan_things()
|
||||
|
||||
/obj/machinery/pool/controller/Destroy()
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
linked_drain = null
|
||||
linked_filter = null
|
||||
linked_turfs.Cut()
|
||||
mobs_in_pool.Cut()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/pool/controller/proc/scan_things()
|
||||
var/list/cached = range(scan_range, src)
|
||||
for(var/turf/open/pool/W in cached)
|
||||
linked_turfs += W
|
||||
W.controller = src
|
||||
for(var/obj/machinery/pool/drain/pooldrain in cached)
|
||||
linked_drain = pooldrain
|
||||
linked_drain.controller = src
|
||||
break
|
||||
for(var/obj/machinery/pool/filter/F in cached)
|
||||
linked_filter = F
|
||||
linked_filter.controller = src
|
||||
break
|
||||
|
||||
/obj/machinery/pool/controller/emag_act(mob/user)
|
||||
. = ..()
|
||||
if(!(obj_flags & EMAGGED)) //If it is not already emagged, emag it.
|
||||
to_chat(user, "<span class='warning'>You disable the [src]'s safety features.</span>")
|
||||
do_sparks(5, TRUE, src)
|
||||
obj_flags |= EMAGGED
|
||||
temperature_unlocked = TRUE
|
||||
drainable = TRUE
|
||||
log_game("[key_name(user)] emagged [src]")
|
||||
message_admins("[key_name_admin(user)] emagged [src]")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>The interface on [src] is already too damaged to short it again.</span>")
|
||||
return
|
||||
|
||||
/obj/machinery/pool/controller/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(!isliving(user) || !user.Adjacent(src) || !user.CanReach(src) || user.IsStun() || user.IsKnockdown() || user.incapacitated())
|
||||
return FALSE
|
||||
visible_message("<span class='boldwarning'>[user] starts to drain [src]!</span>")
|
||||
draining = TRUE
|
||||
if(!do_after(user, 50, target = src))
|
||||
draining = FALSE
|
||||
return TRUE
|
||||
reagents.remove_all(INFINITY)
|
||||
visible_message("<span class='boldnotice'>[user] drains [src].</span>")
|
||||
say("Reagents cleared.")
|
||||
update_color()
|
||||
draining = FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/pool/controller/attackby(obj/item/W, mob/user)
|
||||
if(shocked && !(stat & NOPOWER))
|
||||
shock(user,50)
|
||||
if(stat & (BROKEN))
|
||||
return
|
||||
if(istype(W,/obj/item/reagent_containers))
|
||||
if(W.reagents.total_volume) //check if there's reagent
|
||||
user.visible_message("<span class='boldwarning'>[user] is feeding [src] some chemicals from [W].</span>")
|
||||
if(do_after(user, 50, target = src))
|
||||
for(var/datum/reagent/R in W.reagents.reagent_list)
|
||||
if(R.type in GLOB.blacklisted_pool_reagents)
|
||||
to_chat(user, "[src] cannot accept [R.name].")
|
||||
return
|
||||
if(R.reagent_state == SOLID)
|
||||
to_chat(user, "The pool cannot accept reagents in solid form!.")
|
||||
return
|
||||
reagents.clear_reagents()
|
||||
// This also reacts them. No nitroglycerin deathpools, sorry gamers :(
|
||||
W.reagents.trans_to(reagents, max_beaker_transfer)
|
||||
user.visible_message("<span class='notice'>[src] makes a slurping noise.</span>", "<span class='notice'>All of the contents of [W] are quickly suctioned out by the machine!</span")
|
||||
updateUsrDialog()
|
||||
var/list/reagent_names = list()
|
||||
var/list/rejected = list()
|
||||
for(var/datum/reagent/R in reagents.reagent_list)
|
||||
if((R.volume >= min_reagent_amount) && (!respect_reagent_blacklist || R.can_synth))
|
||||
reagent_names += R.name
|
||||
else
|
||||
reagents.remove_reagent(R.type, INFINITY)
|
||||
rejected += R.name
|
||||
if(length(reagent_names))
|
||||
reagent_names = english_list(reagent_names)
|
||||
var/msg = "POOL: [key_name(user)] has changed [src]'s chems to [reagent_names]"
|
||||
log_game(msg)
|
||||
message_admins(msg)
|
||||
if(length(rejected))
|
||||
rejected = english_list(rejected)
|
||||
to_chat(user, "<span class='warning'>[src] rejects the following chemicals as they do not have at least [min_reagent_amount] units of volume: [rejected]</span>")
|
||||
update_color()
|
||||
else
|
||||
to_chat(user, "<span class='notice'>[src] beeps unpleasantly as it rejects the beaker. Why are you trying to feed it an empty beaker?</span>")
|
||||
return
|
||||
else if(panel_open && is_wire_tool(W))
|
||||
wires.interact(user)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/machinery/pool/controller/screwdriver_act(mob/living/user, obj/item/W)
|
||||
. = ..()
|
||||
if(.)
|
||||
return TRUE
|
||||
cut_overlays()
|
||||
panel_open = !panel_open
|
||||
to_chat(user, "You [panel_open ? "open" : "close"] the maintenance panel.")
|
||||
W.play_tool_sound(src)
|
||||
if(panel_open)
|
||||
add_overlay("wires")
|
||||
return TRUE
|
||||
|
||||
//procs
|
||||
/obj/machinery/pool/controller/proc/shock(mob/user, prb)
|
||||
if(stat & (BROKEN|NOPOWER)) // unpowered, no shock
|
||||
return FALSE
|
||||
if(!prob(prb))
|
||||
return FALSE
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(5, 1, src)
|
||||
s.start()
|
||||
if(electrocute_mob(user, get_area(src), src, 0.7))
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/pool/controller/proc/process_reagents()
|
||||
if(last_reagent_process > world.time + reagent_tick_interval)
|
||||
return
|
||||
if(!length(reagents.reagent_list))
|
||||
return
|
||||
for(var/turf/open/pool/W in linked_turfs)
|
||||
for(var/mob/living/carbon/human/swimee in W)
|
||||
for(var/datum/reagent/R in reagents.reagent_list)
|
||||
if(R.reagent_state == SOLID)
|
||||
R.reagent_state = LIQUID
|
||||
if(!swimee.reagents.has_reagent(POOL_NO_OVERDOSE_MEDICINE_MAX))
|
||||
swimee.reagents.add_reagent(R.type, 0.5) //osmosis
|
||||
reagents.reaction(swimee, VAPOR, 0.03) //3 percent. Need to find a way to prevent this from stacking chems at some point like the above.
|
||||
for(var/obj/objects in W)
|
||||
if(W.reagents)
|
||||
W.reagents.reaction(objects, VAPOR, 1)
|
||||
last_reagent_process = world.time
|
||||
|
||||
/obj/machinery/pool/controller/process()
|
||||
updateUsrDialog()
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if(drained)
|
||||
return
|
||||
process_pool()
|
||||
process_reagents()
|
||||
|
||||
/obj/machinery/pool/controller/proc/process_pool()
|
||||
if(drained)
|
||||
return
|
||||
for(var/mob/living/M in mobs_in_pool)
|
||||
switch(temperature) //Apply different effects based on what the temperature is set to.
|
||||
if(POOL_SCALDING) //Scalding
|
||||
M.adjust_bodytemperature(50,0,500)
|
||||
if(POOL_WARM) //Warm
|
||||
M.adjust_bodytemperature(20,0,360) //Heats up mobs till the termometer shows up
|
||||
//Normal temp does nothing, because it's just room temperature water.
|
||||
if(POOL_COOL)
|
||||
M.adjust_bodytemperature(-20,250) //Cools mobs till the termometer shows up
|
||||
if(POOL_FRIGID) //Freezing
|
||||
M.adjust_bodytemperature(-60) //cool mob at -35k per cycle, less would not affect the mob enough.
|
||||
if(M.bodytemperature <= 50 && !M.stat)
|
||||
M.apply_status_effect(/datum/status_effect/freon)
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/drownee = M
|
||||
if(!drownee || drownee.stat == DEAD)
|
||||
return
|
||||
if(drownee.resting && !drownee.internal)
|
||||
if(drownee.stat != CONSCIOUS)
|
||||
drownee.adjustOxyLoss(9)
|
||||
else
|
||||
drownee.adjustOxyLoss(4)
|
||||
if(prob(35))
|
||||
to_chat(drownee, "<span class='danger'>You're drowning!</span>")
|
||||
|
||||
/obj/machinery/pool/controller/proc/set_bloody(state)
|
||||
if(bloody == state)
|
||||
return
|
||||
bloody = state
|
||||
update_color()
|
||||
|
||||
/obj/machinery/pool/controller/proc/update_color()
|
||||
if(drained)
|
||||
return
|
||||
var/rcolor
|
||||
if(reagents.reagent_list.len)
|
||||
rcolor = mix_color_from_reagents(reagents.reagent_list)
|
||||
if(rcolor == old_rcolor)
|
||||
return // small performance upgrade hopefully?
|
||||
old_rcolor = rcolor
|
||||
for(var/X in linked_turfs)
|
||||
var/turf/open/pool/color1 = X
|
||||
if(bloody)
|
||||
if(rcolor)
|
||||
var/thecolor = BlendRGB(rgb(150, 20, 20), rcolor, 0.5)
|
||||
color1.watereffect.add_atom_colour(thecolor, FIXED_COLOUR_PRIORITY)
|
||||
color1.watertop.add_atom_colour(thecolor, FIXED_COLOUR_PRIORITY)
|
||||
else
|
||||
var/thecolor = rgb(150, 20, 20)
|
||||
color1.watereffect.add_atom_colour(thecolor, FIXED_COLOUR_PRIORITY)
|
||||
color1.watertop.add_atom_colour(thecolor, FIXED_COLOUR_PRIORITY)
|
||||
else if(!bloody && rcolor)
|
||||
color1.watereffect.add_atom_colour(rcolor, FIXED_COLOUR_PRIORITY)
|
||||
color1.watertop.add_atom_colour(rcolor, FIXED_COLOUR_PRIORITY)
|
||||
else
|
||||
color1.watereffect.remove_atom_colour(FIXED_COLOUR_PRIORITY)
|
||||
color1.watertop.remove_atom_colour(FIXED_COLOUR_PRIORITY)
|
||||
|
||||
/obj/machinery/pool/controller/proc/update_temp()
|
||||
if(mist_state)
|
||||
if(temperature < POOL_SCALDING)
|
||||
mist_off()
|
||||
else
|
||||
if(temperature == POOL_SCALDING)
|
||||
mist_on()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/pool/controller/update_icon()
|
||||
. = ..()
|
||||
icon_state = "poolc_[temperature]"
|
||||
|
||||
/obj/machinery/pool/controller/proc/CanUpTemp(mob/user)
|
||||
if(temperature == POOL_WARM && (temperature_unlocked || issilicon(user) || IsAdminGhost(user)) || temperature < POOL_WARM)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/pool/controller/proc/CanDownTemp(mob/user)
|
||||
if(temperature == POOL_COOL && (temperature_unlocked || issilicon(user) || IsAdminGhost(user)) || temperature > POOL_COOL)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/pool/controller/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
if(interact_delay > world.time)
|
||||
return
|
||||
if(href_list["IncreaseTemp"])
|
||||
if(CanUpTemp(usr))
|
||||
visible_message("<span class='warning'>[usr] presses a button on [src].</span>")
|
||||
temperature++
|
||||
update_temp()
|
||||
var/msg = "POOL: [key_name(usr)] increased [src]'s pool temperature at [COORD(src)] to [temperature]"
|
||||
log_game(msg)
|
||||
message_admins(msg)
|
||||
interact_delay = world.time + 15
|
||||
if(href_list["DecreaseTemp"])
|
||||
if(CanDownTemp(usr))
|
||||
visible_message("<span class='warning'>[usr] presses a button on [src].</span>")
|
||||
temperature--
|
||||
update_temp()
|
||||
var/msg = "POOL: [key_name(usr)] decreased [src]'s pool temperature at [COORD(src)] to [temperature]"
|
||||
log_game(msg)
|
||||
message_admins(msg)
|
||||
interact_delay = world.time + 15
|
||||
if(href_list["Activate Drain"])
|
||||
if((drainable || issilicon(usr) || IsAdminGhost(usr)) && !linked_drain.active)
|
||||
var/msg = "POOL: [key_name(usr)] activated [src]'s pool drain in [linked_drain.filling? "FILLING" : "DRAINING"] mode at [COORD(src)]"
|
||||
log_game(msg)
|
||||
message_admins(msg)
|
||||
visible_message("<span class='warning'>[usr] presses a button on [src].</span>")
|
||||
mist_off()
|
||||
interact_delay = world.time + 60
|
||||
linked_drain.active = TRUE
|
||||
linked_drain.cycles_left = 75
|
||||
if(!linked_drain.filling)
|
||||
new /obj/effect/whirlpool(linked_drain.loc)
|
||||
temperature = POOL_NORMAL
|
||||
else
|
||||
new /obj/effect/waterspout(linked_drain.loc)
|
||||
temperature = POOL_NORMAL
|
||||
update_temp()
|
||||
bloody = FALSE
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/pool/controller/proc/temp2text()
|
||||
switch(temperature)
|
||||
if(POOL_FRIGID)
|
||||
return "<span class='boldwarning'>Frigid</span>"
|
||||
if(POOL_COOL)
|
||||
return "<span class='boldnotice'>Cool</span>"
|
||||
if(POOL_NORMAL)
|
||||
return "<span class='notice'>Normal</span>"
|
||||
if(POOL_WARM)
|
||||
return "<span class='boldnotice'>Warm</span>"
|
||||
if(POOL_SCALDING)
|
||||
return "<span class='boldwarning'>Scalding</span>"
|
||||
else
|
||||
return "Outside of possible range."
|
||||
|
||||
/obj/machinery/pool/controller/ui_interact(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(shocked && !(stat & NOPOWER))
|
||||
shock(user,50)
|
||||
if(panel_open && !isAI(user))
|
||||
return wires.interact(user)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
var/datum/browser/popup = new(user, "Pool Controller", name, 300, 450)
|
||||
var/dat = ""
|
||||
if(interact_delay > world.time)
|
||||
dat += "<span class='notice'>[round((interact_delay - world.time)/10, 0.1)] seconds left until [src] can operate again.</span><BR>"
|
||||
dat += text({"
|
||||
<h3>Temperature</h3>
|
||||
<div class='statusDisplay'>
|
||||
<B>Current temperature:</B> [temp2text()]<BR>
|
||||
[CanUpTemp(user) ? "<a href='?src=\ref[src];IncreaseTemp=1'>Increase Temperature</a><br>" : "<span class='linkOff'>Increase Temperature</span><br>"]
|
||||
[CanDownTemp(user) ? "<a href='?src=\ref[src];DecreaseTemp=1'>Decrease Temperature</a><br>" : "<span class='linkOff'>Decrease Temperature</span><br>"]
|
||||
</div>
|
||||
<h3>Drain</h3>
|
||||
<div class='statusDisplay'>
|
||||
<B>Drain status:</B> [(issilicon(user) || IsAdminGhost(user) || drainable) ? "<span class='bad'>Enabled</span>" : "<span class='good'>Disabled</span>"]
|
||||
<br><b>Pool status:</b> "})
|
||||
if(!drained)
|
||||
dat += "<span class='good'>Full</span><BR>"
|
||||
else
|
||||
dat += "<span class='bad'>Drained</span><BR>"
|
||||
if((issilicon(user) || IsAdminGhost(user) || drainable) && !linked_drain.active)
|
||||
dat += "<a href='?src=\ref[src];Activate Drain=1'>[drained ? "Fill" : "Drain"] Pool</a><br>"
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/pool/controller/proc/reset(wire)
|
||||
switch(wire)
|
||||
if(WIRE_SHOCK)
|
||||
if(!wires.is_cut(wire))
|
||||
shocked = FALSE
|
||||
|
||||
/obj/machinery/pool/controller/proc/mist_on() //Spawn /obj/effect/mist (from the shower) on all linked pool tiles
|
||||
if(mist_state)
|
||||
return
|
||||
mist_state = TRUE
|
||||
for(var/X in linked_turfs)
|
||||
var/turf/open/pool/W = X
|
||||
if(W.filled)
|
||||
var/M = new /obj/effect/mist(W)
|
||||
linked_mist += M
|
||||
|
||||
/obj/machinery/pool/controller/proc/mist_off() //Delete all /obj/effect/mist from all linked pool tiles.
|
||||
for(var/M in linked_mist)
|
||||
qdel(M)
|
||||
mist_state = FALSE
|
||||
@@ -0,0 +1,160 @@
|
||||
/obj/machinery/pool/drain
|
||||
name = "drain"
|
||||
icon_state = "drain"
|
||||
desc = "A suction system to remove the contents of the pool, and sometimes small objects. Do not insert fingers."
|
||||
anchored = TRUE
|
||||
/// Active/on?
|
||||
var/active = FALSE
|
||||
/// Filling or draining
|
||||
var/filling = FALSE
|
||||
/// Drain item suction range
|
||||
var/item_suction_range = 2
|
||||
/// Fill mode knock away range
|
||||
var/fill_push_range = 6
|
||||
/// Drain mode suction range
|
||||
var/drain_suck_range = 6
|
||||
/// Parent controller
|
||||
var/obj/machinery/pool/controller/controller
|
||||
/// Cycles left for fill/drain while active
|
||||
var/cycles_left = 0
|
||||
/// Mobs we are swirling around
|
||||
var/list/whirling_mobs
|
||||
/// Suck in once per x ticks
|
||||
var/suck_in_once_per = 3
|
||||
|
||||
var/cooldown
|
||||
|
||||
/obj/machinery/pool/drain/Initialize()
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
whirling_mobs = list()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/pool/drain/Destroy()
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
controller.linked_drain = null
|
||||
controller = null
|
||||
whirling_mobs = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/pool/drain/proc/is_in_our_pool(atom/A)
|
||||
. = FALSE
|
||||
if(istype(A.loc, /turf/open/pool))
|
||||
var/turf/open/pool/P = A.loc
|
||||
if(P.controller == controller)
|
||||
. = TRUE
|
||||
|
||||
// This should probably start using move force sometime in the future but I'm lazy.
|
||||
/obj/machinery/pool/drain/process()
|
||||
if(!filling)
|
||||
for(var/obj/item/I in range(min(item_suction_range, 10), src))
|
||||
if(!I.anchored && (I.w_class <= WEIGHT_CLASS_SMALL))
|
||||
step_towards(I, src)
|
||||
if((I.w_class <= WEIGHT_CLASS_TINY) && (get_dist(I, src) == 0))
|
||||
I.forceMove(controller.linked_filter)
|
||||
if(active)
|
||||
if(filling)
|
||||
if(cycles_left-- > 0)
|
||||
playsound(src, 'sound/effects/fillingwatter.ogg', 100, TRUE)
|
||||
for(var/obj/O in orange(min(fill_push_range, 10), src))
|
||||
if(!O.anchored && is_in_our_pool(O))
|
||||
step_away(O, src)
|
||||
for(var/mob/M in orange(min(fill_push_range, 10), src)) //compiler fastpath apparently?
|
||||
if(!M.anchored && isliving(M) && is_in_our_pool(M))
|
||||
step_away(M, src)
|
||||
else
|
||||
for(var/turf/open/pool/P in controller.linked_turfs)
|
||||
P.filled = TRUE
|
||||
P.update_icon()
|
||||
for(var/obj/effect/waterspout/S in range(1, src))
|
||||
qdel(S)
|
||||
controller.drained = FALSE
|
||||
if(controller.bloody < 1000)
|
||||
controller.bloody /= 2
|
||||
else
|
||||
controller.bloody /= 4
|
||||
controller.update_color()
|
||||
filling = FALSE
|
||||
active = FALSE
|
||||
else
|
||||
if(cycles_left-- > 0)
|
||||
playsound(src, 'sound/effects/pooldrain.ogg', 100, TRUE)
|
||||
playsound(src, "water_wade", 60, TRUE)
|
||||
for(var/obj/O in orange(min(drain_suck_range, 10), src))
|
||||
if(!O.anchored && is_in_our_pool(O))
|
||||
step_towards(O, src)
|
||||
for(var/mob/M in orange(min(drain_suck_range, 10), src))
|
||||
if(isliving(M) && !M.anchored && is_in_our_pool(M))
|
||||
if(!(cycles_left % suck_in_once_per))
|
||||
step_towards(M, src)
|
||||
whirl_mob(M)
|
||||
if(ishuman(M) && (get_dist(M, src) <= 1))
|
||||
var/mob/living/carbon/human/H = M
|
||||
playsound(src, pick('sound/misc/crack.ogg','sound/misc/crunch.ogg'), 50, TRUE)
|
||||
if(H.lying) //down for any reason
|
||||
H.adjustBruteLoss(2)
|
||||
to_chat(H, "<span class='danger'>You're caught in the drain!</span>")
|
||||
else
|
||||
H.apply_damage(2.5, BRUTE, pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)) //drain should only target the legs
|
||||
to_chat(H, "<span class='danger'>Your legs are caught in the drain!</span>")
|
||||
else
|
||||
for(var/turf/open/pool/P in controller.linked_turfs)
|
||||
P.filled = FALSE
|
||||
P.update_icon()
|
||||
for(var/obj/effect/whirlpool/W in range(1, src))
|
||||
qdel(W)
|
||||
controller.drained = TRUE
|
||||
controller.mist_off()
|
||||
active = FALSE
|
||||
filling = TRUE
|
||||
|
||||
/// dangerous proc don't fuck with, admins
|
||||
/obj/machinery/pool/drain/proc/whirl_mob(mob/living/L, duration = 8, delay = 1)
|
||||
set waitfor = FALSE
|
||||
if(whirling_mobs[L])
|
||||
return
|
||||
whirling_mobs[L] = TRUE
|
||||
for(var/i in 1 to min(duration, 100))
|
||||
L.setDir(turn(L.dir, 90))
|
||||
sleep(delay)
|
||||
if(QDELETED(L))
|
||||
break
|
||||
if(QDELETED(src))
|
||||
return
|
||||
whirling_mobs -= L
|
||||
|
||||
/obj/machinery/pool/filter
|
||||
name = "Filter"
|
||||
icon_state = "filter"
|
||||
desc = "The part of the pool where all the IDs, ATV keys, and pens, and other dangerous things get trapped."
|
||||
var/obj/machinery/pool/controller/controller
|
||||
|
||||
/obj/machinery/pool/filter/Destroy()
|
||||
controller.linked_filter = null
|
||||
controller = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/pool/filter/emag_act(mob/living/user)
|
||||
. = ..()
|
||||
if(!(obj_flags & EMAGGED))
|
||||
to_chat(user, "<span class='warning'>You disable the [src]'s shark filter! Run!</span>")
|
||||
obj_flags |= EMAGGED
|
||||
do_sparks(5, TRUE, src)
|
||||
icon_state = "filter_b"
|
||||
addtimer(CALLBACK(src, /obj/machinery/pool/filter/proc/spawn_shark), 50)
|
||||
var/msg = "[key_name(user)] emagged the pool filter and spawned a shark"
|
||||
log_game(msg)
|
||||
message_admins(msg)
|
||||
|
||||
/obj/machinery/pool/filter/proc/spawn_shark()
|
||||
if(prob(50))
|
||||
new /mob/living/simple_animal/hostile/shark(loc)
|
||||
else
|
||||
if(prob(50))
|
||||
new /mob/living/simple_animal/hostile/shark/kawaii(loc)
|
||||
else
|
||||
new /mob/living/simple_animal/hostile/shark/laser(loc)
|
||||
|
||||
/obj/machinery/pool/filter/attack_hand(mob/user)
|
||||
to_chat(user, "You search the filter.")
|
||||
for(var/obj/O in contents)
|
||||
O.forceMove(loc)
|
||||
@@ -0,0 +1,29 @@
|
||||
/obj/effect/splash
|
||||
name = "splash"
|
||||
desc = "Wataaa!."
|
||||
icon = 'icons/turf/pool.dmi'
|
||||
icon_state = "splash"
|
||||
layer = ABOVE_ALL_MOB_LAYER
|
||||
|
||||
/obj/effect/whirlpool
|
||||
name = "Whirlpool"
|
||||
icon = 'icons/effects/96x96.dmi'
|
||||
icon_state = "whirlpool"
|
||||
layer = 5
|
||||
anchored = TRUE
|
||||
mouse_opacity = 0
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
alpha = 90
|
||||
|
||||
/obj/effect/waterspout
|
||||
name = "Waterspout"
|
||||
icon = 'icons/effects/96x96.dmi'
|
||||
icon_state = "waterspout"
|
||||
color = "#3399AA"
|
||||
layer = 5
|
||||
anchored = TRUE
|
||||
mouse_opacity = 0
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
alpha = 120
|
||||
@@ -0,0 +1,191 @@
|
||||
/turf/open/pool
|
||||
icon = 'icons/turf/pool.dmi'
|
||||
name = "poolwater"
|
||||
desc = "You're safer here than in the deep."
|
||||
icon_state = "pool_tile"
|
||||
heat_capacity = INFINITY
|
||||
var/filled = TRUE
|
||||
var/next_splash = 0
|
||||
var/obj/machinery/pool/controller/controller
|
||||
var/obj/effect/overlay/water/watereffect
|
||||
var/obj/effect/overlay/water/top/watertop
|
||||
|
||||
/turf/open/pool/Initialize(mapload)
|
||||
. = ..()
|
||||
update_icon()
|
||||
|
||||
/turf/open/pool/Destroy()
|
||||
if(controller)
|
||||
controller.linked_turfs -= src
|
||||
controller = null
|
||||
QDEL_NULL(watereffect)
|
||||
QDEL_NULL(watertop)
|
||||
return ..()
|
||||
|
||||
/turf/open/pool/update_icon()
|
||||
. = ..()
|
||||
if(!filled)
|
||||
name = "drained pool"
|
||||
desc = "No diving!"
|
||||
QDEL_NULL(watereffect)
|
||||
QDEL_NULL(watertop)
|
||||
else
|
||||
name = "poolwater"
|
||||
desc = "You're safer here than in the deep."
|
||||
watereffect = new /obj/effect/overlay/water(src)
|
||||
watertop = new /obj/effect/overlay/water/top(src)
|
||||
|
||||
/obj/effect/overlay/water
|
||||
name = "water"
|
||||
icon = 'icons/turf/pool.dmi'
|
||||
icon_state = "bottom"
|
||||
density = FALSE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
layer = ABOVE_MOB_LAYER
|
||||
anchored = TRUE
|
||||
resistance_flags = INDESTRUCTIBLE
|
||||
|
||||
/obj/effect/overlay/water/top
|
||||
icon_state = "top"
|
||||
layer = BELOW_MOB_LAYER
|
||||
|
||||
// Mousedrop hook to normal turfs to get out of pools.
|
||||
/turf/open/MouseDrop_T(atom/from, mob/user)
|
||||
// I could make this /open/floor and not have the !istype but ehh - kev
|
||||
if(isliving(from) && HAS_TRAIT(from, TRAIT_SWIMMING) && isliving(user) && ((user == from) || user.CanReach(from)) && !user.IsStun() && !user.IsKnockdown() && !user.incapacitated() && !istype(src, /turf/open/pool))
|
||||
var/mob/living/L = from
|
||||
//The element only exists if you're on water and a living mob, so let's skip those checks.
|
||||
var/pre_msg
|
||||
var/post_msg
|
||||
if(user == from)
|
||||
pre_msg = "<span class='notice'>[L] is getting out of the pool.</span>"
|
||||
post_msg = "<span class='notice'>[L] gets out of the pool.</span>"
|
||||
else
|
||||
pre_msg = "<span class='notice'>[L] is being pulled out of the pool by [user].</span>"
|
||||
post_msg = "<span class='notice'>[user] pulls [L] out of the pool.</span>"
|
||||
L.visible_message(pre_msg)
|
||||
if(do_mob(user, L, 20))
|
||||
L.visible_message(post_msg)
|
||||
L.forceMove(src)
|
||||
else
|
||||
return ..()
|
||||
|
||||
// Exit check
|
||||
/turf/open/pool/Exit(atom/movable/AM, atom/newloc)
|
||||
if(!AM.has_gravity(src))
|
||||
return ..()
|
||||
if(isliving(AM) || isstructure(AM))
|
||||
if(AM.throwing)
|
||||
return ..() //WHEEEEEEEEEEE
|
||||
if(istype(AM, /obj/structure) && isliving(AM.pulledby))
|
||||
return ..() //people pulling stuff out of pool
|
||||
if(!ishuman(AM))
|
||||
return ..() //human weak, monkey (and anyone else) ook ook eek eek strong
|
||||
if(isliving(AM) && (locate(/obj/structure/pool/ladder) in src))
|
||||
return ..() //climbing out
|
||||
return istype(newloc, /turf/open/pool)
|
||||
return ..()
|
||||
|
||||
// Exited logic
|
||||
/turf/open/pool/Exited(atom/A, atom/newLoc)
|
||||
. = ..()
|
||||
if(isliving(A))
|
||||
var/turf/open/pool/P = newLoc
|
||||
if(!istype(P) || (P.controller != controller))
|
||||
controller?.mobs_in_pool -= A
|
||||
|
||||
// Entered logic
|
||||
/turf/open/pool/Entered(atom/movable/AM, atom/oldloc)
|
||||
if(istype(AM, /obj/effect/decal/cleanable))
|
||||
var/obj/effect/decal/cleanable/C = AM
|
||||
if(prob(C.bloodiness))
|
||||
controller.set_bloody(TRUE)
|
||||
QDEL_IN(AM, 25)
|
||||
animate(AM, alpha = 10, time = 20)
|
||||
return ..()
|
||||
if(!AM.has_gravity(src))
|
||||
return ..()
|
||||
if(isliving(AM))
|
||||
var/mob/living/victim = AM
|
||||
if(!HAS_TRAIT(victim, TRAIT_SWIMMING)) //poor guy not swimming time to dunk them!
|
||||
victim.AddElement(/datum/element/swimming)
|
||||
controller.mobs_in_pool += victim
|
||||
if(locate(/obj/structure/pool/ladder) in src) //safe climbing
|
||||
return
|
||||
if(iscarbon(AM)) //FUN TIME!
|
||||
var/mob/living/carbon/H = victim
|
||||
if(filled)
|
||||
if (H.wear_mask && H.wear_mask.flags_cover & MASKCOVERSMOUTH)
|
||||
H.visible_message("<span class='danger'>[H] falls in the water!</span>",
|
||||
"<span class='userdanger'>You fall in the water!</span>")
|
||||
playsound(src, 'sound/effects/splash.ogg', 60, TRUE, 1)
|
||||
H.Knockdown(20)
|
||||
return
|
||||
else
|
||||
H.Knockdown(60)
|
||||
H.adjustOxyLoss(5)
|
||||
H.emote("cough")
|
||||
H.visible_message("<span class='danger'>[H] falls in and takes a drink!</span>",
|
||||
"<span class='userdanger'>You fall in and swallow some water!</span>")
|
||||
playsound(src, 'sound/effects/splash.ogg', 60, TRUE, 1)
|
||||
else if(!H.head || !(H.head.armor.getRating("melee") > 20))
|
||||
if(prob(75))
|
||||
H.visible_message("<span class='danger'>[H] falls in the drained pool!</span>",
|
||||
"<span class='userdanger'>You fall in the drained pool!</span>")
|
||||
H.adjustBruteLoss(7)
|
||||
H.Knockdown(80)
|
||||
playsound(src, 'sound/effects/woodhit.ogg', 60, TRUE, 1)
|
||||
else
|
||||
H.visible_message("<span class='danger'>[H] falls in the drained pool, and cracks his skull!</span>",
|
||||
"<span class='userdanger'>You fall in the drained pool, and crack your skull!</span>")
|
||||
H.apply_damage(15, BRUTE, "head")
|
||||
H.Knockdown(200) // This should hurt. And it does.
|
||||
playsound(src, 'sound/effects/woodhit.ogg', 60, TRUE, 1)
|
||||
playsound(src, 'sound/misc/crack.ogg', 100, TRUE)
|
||||
else
|
||||
H.visible_message("<span class='danger'>[H] falls in the drained pool, but had an helmet!</span>",
|
||||
"<span class='userdanger'>You fall in the drained pool, but you had an helmet!</span>")
|
||||
H.Knockdown(40)
|
||||
playsound(src, 'sound/effects/woodhit.ogg', 60, TRUE, 1)
|
||||
else if(filled)
|
||||
victim.adjustStaminaLoss(1)
|
||||
playsound(src, "water_wade", 20, TRUE)
|
||||
return ..()
|
||||
|
||||
/turf/open/pool/MouseDrop_T(atom/from, mob/user)
|
||||
. = ..()
|
||||
if(!isliving(from))
|
||||
return
|
||||
var/mob/living/victim = from
|
||||
if(user.stat || user.lying || !Adjacent(user) || !from.Adjacent(user) || !iscarbon(user) || !victim.has_gravity(src) || HAS_TRAIT(victim, TRAIT_SWIMMING))
|
||||
return
|
||||
var/victimname = victim == user? "themselves" : "[victim]"
|
||||
var/starttext = victim == user? "[user] is descending into [src]." : "[user] is lowering [victim] into [src]."
|
||||
user.visible_message("<span class='notice'>[starttext]</span>")
|
||||
if(do_mob(user, victim, 20))
|
||||
user.visible_message("<span class='notice'>[user] lowers [victimname] into [src].</span>")
|
||||
victim.AddElement(/datum/element/swimming) //make sure they have it so they don't fall/whatever
|
||||
victim.forceMove(src)
|
||||
|
||||
/turf/open/pool/attackby(obj/item/W, mob/living/user)
|
||||
if(istype(W, /obj/item/mop) && filled)
|
||||
W.reagents.add_reagent("water", 5)
|
||||
to_chat(user, "<span class='notice'>You wet [W] in [src].</span>")
|
||||
playsound(loc, 'sound/effects/slosh.ogg', 25, TRUE)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/turf/open/pool/attack_hand(mob/living/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if((user.loc != src) && !user.IsStun() && !user.IsKnockdown() && !user.incapacitated() && Adjacent(user) && HAS_TRAIT(user, TRAIT_SWIMMING) && filled && (next_splash < world.time))
|
||||
playsound(src, 'sound/effects/watersplash.ogg', 8, TRUE, 1)
|
||||
next_splash = world.time + 25
|
||||
var/obj/effect/splash/S = new(src)
|
||||
animate(S, alpha = 0, time = 8)
|
||||
QDEL_IN(S, 10)
|
||||
for(var/mob/living/carbon/human/H in src)
|
||||
if(!H.wear_mask && (H.stat == CONSCIOUS))
|
||||
H.emote("cough")
|
||||
H.adjustStaminaLoss(4)
|
||||
@@ -0,0 +1,32 @@
|
||||
//Pool noodles
|
||||
|
||||
/obj/item/toy/poolnoodle
|
||||
icon = 'icons/obj/toy.dmi'
|
||||
icon_state = "noodle"
|
||||
name = "pool noodle"
|
||||
desc = "A strange, bulky, bendable toy that can annoy people."
|
||||
force = 0
|
||||
color = "#000000"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
throwforce = 1
|
||||
throw_speed = 10 //weeee
|
||||
hitsound = 'sound/weapons/tap.ogg'
|
||||
attack_verb = list("flogged", "poked", "jabbed", "slapped", "annoyed")
|
||||
lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/items_righthand.dmi'
|
||||
|
||||
/obj/item/toy/poolnoodle/attack(target as mob, mob/living/user as mob)
|
||||
. = ..()
|
||||
user.spin(prob(20)? 16 : 8, 1)
|
||||
|
||||
/obj/item/toy/poolnoodle/red
|
||||
item_state = "noodlered"
|
||||
color = "#ff4c4c"
|
||||
|
||||
/obj/item/toy/poolnoodle/blue
|
||||
item_state = "noodleblue"
|
||||
color = "#3232ff"
|
||||
|
||||
/obj/item/toy/poolnoodle/yellow
|
||||
item_state = "noodleyellow"
|
||||
color = "#ffff66"
|
||||
@@ -0,0 +1,159 @@
|
||||
/obj/structure/pool
|
||||
name = "pool"
|
||||
icon = 'icons/obj/machines/pool.dmi'
|
||||
anchored = TRUE
|
||||
resistance_flags = UNACIDABLE|INDESTRUCTIBLE
|
||||
|
||||
/obj/structure/pool/ladder
|
||||
name = "Ladder"
|
||||
icon_state = "ladder"
|
||||
desc = "Are you getting in or are you getting out?."
|
||||
layer = ABOVE_MOB_LAYER
|
||||
dir = EAST
|
||||
|
||||
/obj/structure/pool/ladder/attack_hand(mob/living/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(!HAS_TRAIT(user, TRAIT_SWIMMING))
|
||||
if(user.CanReach(src))
|
||||
user.AddElement(/datum/element/swimming)
|
||||
user.forceMove(get_step(src, dir))
|
||||
else
|
||||
if(user.loc == loc)
|
||||
user.forceMove(get_step(src, turn(dir, 180))) //If this moves them out the element cleans up after itself.
|
||||
|
||||
/obj/structure/pool/Rboard
|
||||
name = "JumpBoard"
|
||||
density = FALSE
|
||||
icon_state = "boardright"
|
||||
desc = "The less-loved portion of the jumping board."
|
||||
dir = EAST
|
||||
|
||||
/obj/structure/pool/Lboard
|
||||
name = "JumpBoard"
|
||||
icon_state = "boardleft"
|
||||
desc = "Get on there to jump!"
|
||||
layer = FLY_LAYER
|
||||
dir = WEST
|
||||
var/jumping = FALSE
|
||||
var/timer
|
||||
|
||||
/obj/structure/pool/Lboard/proc/backswim()
|
||||
if(jumping)
|
||||
for(var/mob/living/jumpee in loc) //hackzors.
|
||||
playsound(jumpee, 'sound/effects/splash.ogg', 60, TRUE, 1)
|
||||
if(!HAS_TRAIT(jumpee, TRAIT_SWIMMING))
|
||||
jumpee.AddElement(/datum/element/swimming)
|
||||
jumpee.Stun(2)
|
||||
|
||||
/obj/structure/pool/Lboard/proc/reset_position(mob/user, initial_layer, initial_px, initial_py)
|
||||
user.layer = initial_layer
|
||||
user.pixel_x = initial_px
|
||||
user.pixel_y = initial_py
|
||||
|
||||
/obj/structure/pool/Lboard/attack_hand(mob/living/user)
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/jumper = user
|
||||
if(jumping)
|
||||
to_chat(user, "<span class='notice'>Someone else is already making a jump!</span>")
|
||||
return
|
||||
var/turf/T = get_turf(src)
|
||||
if(HAS_TRAIT(user, TRAIT_SWIMMING))
|
||||
return
|
||||
else
|
||||
if(Adjacent(jumper))
|
||||
jumper.visible_message("<span class='notice'>[user] climbs up \the [src]!</span>", \
|
||||
"<span class='notice'>You climb up \the [src] and prepares to jump!</span>")
|
||||
jumper.Stun(40)
|
||||
jumping = TRUE
|
||||
var/original_layer = jumper.layer
|
||||
var/original_px = jumper.pixel_x
|
||||
var/original_py = jumper.pixel_y
|
||||
jumper.layer = RIPPLE_LAYER
|
||||
jumper.pixel_x = 3
|
||||
jumper.pixel_y = 7
|
||||
jumper.dir = WEST
|
||||
jumper.AddElement(/datum/element/swimming)
|
||||
sleep(1)
|
||||
jumper.forceMove(T)
|
||||
addtimer(CALLBACK(src, .proc/dive, jumper, original_layer, original_px, original_py), 10)
|
||||
|
||||
/obj/structure/pool/Lboard/proc/dive(mob/living/carbon/jumper, original_layer, original_px, original_py)
|
||||
switch(rand(1, 100))
|
||||
if(1 to 20)
|
||||
jumper.visible_message("<span class='notice'>[jumper] goes for a small dive!</span>", \
|
||||
"<span class='notice'>You go for a small dive.</span>")
|
||||
sleep(15)
|
||||
backswim()
|
||||
var/atom/throw_target = get_edge_target_turf(src, dir)
|
||||
jumper.throw_at(throw_target, 1, 1, callback = CALLBACK(src, .proc/on_finish_jump, jumper))
|
||||
|
||||
if(21 to 40)
|
||||
jumper.visible_message("<span class='notice'>[jumper] goes for a dive!</span>", \
|
||||
"<span class='notice'>You're going for a dive!</span>")
|
||||
sleep(20)
|
||||
backswim()
|
||||
var/atom/throw_target = get_edge_target_turf(src, dir)
|
||||
jumper.throw_at(throw_target, 2, 1, callback = CALLBACK(src, .proc/on_finish_jump, jumper))
|
||||
|
||||
if(41 to 60)
|
||||
jumper.visible_message("<span class='notice'>[jumper] goes for a long dive! Stay far away!</span>", \
|
||||
"<span class='notice'>You're going for a long dive!!</span>")
|
||||
sleep(25)
|
||||
backswim()
|
||||
var/atom/throw_target = get_edge_target_turf(src, dir)
|
||||
jumper.throw_at(throw_target, 3, 1, callback = CALLBACK(src, .proc/on_finish_jump, jumper))
|
||||
|
||||
if(61 to 80)
|
||||
jumper.visible_message("<span class='notice'>[jumper] goes for an awesome dive! Don't stand in [jumper.p_their()] way!</span>", \
|
||||
"<span class='notice'>You feel like this dive will be awesome</span>")
|
||||
sleep(30)
|
||||
backswim()
|
||||
var/atom/throw_target = get_edge_target_turf(src, dir)
|
||||
jumper.throw_at(throw_target, 4, 1, callback = CALLBACK(src, .proc/on_finish_jump, jumper))
|
||||
if(81 to 91)
|
||||
sleep(20)
|
||||
backswim()
|
||||
jumper.visible_message("<span class='danger'>[jumper] misses [jumper.p_their()] step!</span>", \
|
||||
"<span class='userdanger'>You misstep!</span>")
|
||||
var/atom/throw_target = get_edge_target_turf(src, dir)
|
||||
jumper.throw_at(throw_target, 0, 1, callback = CALLBACK(src, .proc/on_finish_jump, jumper))
|
||||
jumper.Knockdown(100)
|
||||
jumper.adjustBruteLoss(10)
|
||||
|
||||
if(91 to 100)
|
||||
jumper.visible_message("<span class='notice'>[jumper] is preparing for the legendary dive! Can [jumper.p_they()] make it?</span>", \
|
||||
"<span class='userdanger'>You start preparing for a legendary dive!</span>")
|
||||
jumper.SpinAnimation(7,1)
|
||||
|
||||
sleep(30)
|
||||
if(prob(75))
|
||||
backswim()
|
||||
jumper.visible_message("<span class='notice'>[jumper] fails!</span>", \
|
||||
"<span class='userdanger'>You can't quite do it!</span>")
|
||||
var/atom/throw_target = get_edge_target_turf(src, dir)
|
||||
jumper.throw_at(throw_target, 1, 1, callback = CALLBACK(src, .proc/on_finish_jump, jumper))
|
||||
else
|
||||
jumper.fire_stacks = min(1,jumper.fire_stacks + 1)
|
||||
jumper.IgniteMob()
|
||||
sleep(5)
|
||||
backswim()
|
||||
jumper.visible_message("<span class='danger'>[jumper] bursts into flames of pure awesomness!</span>", \
|
||||
"<span class='userdanger'>No one can stop you now!</span>")
|
||||
var/atom/throw_target = get_edge_target_turf(src, dir)
|
||||
jumper.throw_at(throw_target, 6, 1, callback = CALLBACK(src, .proc/on_finish_jump, jumper))
|
||||
addtimer(CALLBACK(src, .proc/togglejumping), 35)
|
||||
reset_position(jumper, original_layer, original_px, original_py)
|
||||
|
||||
/obj/structure/pool/Lboard/proc/togglejumping()
|
||||
jumping = FALSE
|
||||
|
||||
/obj/structure/pool/Lboard/proc/on_finish_jump(mob/living/victim)
|
||||
if(istype(victim.loc, /turf/open/pool))
|
||||
var/turf/open/pool/P = victim.loc
|
||||
if(!P.filled) //you dun fucked up now
|
||||
to_chat(victim, "<span class='warning'>That was stupid of you..</span>")
|
||||
victim.visible_message("<span class='danger'>[victim] smashes into the ground!</span>")
|
||||
victim.apply_damage(50)
|
||||
victim.Knockdown(200)
|
||||
@@ -0,0 +1,59 @@
|
||||
#define POOL_WIRE_DRAIN "drain"
|
||||
#define POOL_WIRE_TEMP "temp"
|
||||
|
||||
|
||||
/datum/wires/poolcontroller
|
||||
holder_type = /obj/machinery/pool/controller
|
||||
proper_name = "Pool"
|
||||
|
||||
/datum/wires/poolcontroller/New(atom/holder)
|
||||
wires = list(
|
||||
POOL_WIRE_DRAIN, WIRE_SHOCK, WIRE_ZAP, POOL_WIRE_TEMP
|
||||
)
|
||||
add_duds(3)
|
||||
..()
|
||||
|
||||
/datum/wires/poolcontroller/interactable(mob/user)
|
||||
var/obj/machinery/pool/controller/P = holder
|
||||
if(P.panel_open)
|
||||
return TRUE
|
||||
|
||||
/datum/wires/poolcontroller/get_status()
|
||||
var/obj/machinery/pool/controller/P = holder
|
||||
var/list/status = list()
|
||||
status += "The blue light is [P.drainable ? "on" : "off"]."
|
||||
status += "The red light is [P.temperature_unlocked ? "on" : "off"]."
|
||||
status += "The yellow light is [P.shocked ? "on" : "off"]."
|
||||
return status
|
||||
|
||||
/datum/wires/poolcontroller/on_pulse(wire)
|
||||
var/obj/machinery/pool/controller/P = holder
|
||||
switch(wire)
|
||||
if(POOL_WIRE_DRAIN)
|
||||
P.drainable = FALSE
|
||||
if(POOL_WIRE_TEMP)
|
||||
P.temperature_unlocked = FALSE
|
||||
if(WIRE_SHOCK)
|
||||
P.shocked = !P.shocked
|
||||
addtimer(CALLBACK(P, /obj/machinery/autolathe.proc/reset, wire), 60)
|
||||
|
||||
/datum/wires/poolcontroller/on_cut(wire, mend)
|
||||
var/obj/machinery/pool/controller/P = holder
|
||||
switch(wire)
|
||||
if(POOL_WIRE_DRAIN)
|
||||
if(mend)
|
||||
P.drainable = FALSE
|
||||
else
|
||||
P.drainable = TRUE
|
||||
if(POOL_WIRE_TEMP)
|
||||
if(mend)
|
||||
P.temperature_unlocked = FALSE
|
||||
else
|
||||
P.temperature_unlocked = TRUE
|
||||
if(WIRE_ZAP)
|
||||
P.shock(usr, 50)
|
||||
if(WIRE_SHOCK)
|
||||
if(mend)
|
||||
P.stat &= ~NOPOWER
|
||||
else
|
||||
P.stat |= NOPOWER
|
||||
@@ -346,6 +346,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
|
||||
// Pass all the gas related code an empty gas container
|
||||
removed = new()
|
||||
|
||||
damage = min(damage_archived + (DAMAGE_HARDCAP * explosion_point),damage) // hardcap any direct damage taken before doing atmos damage
|
||||
damage_archived = damage
|
||||
if(!removed || !removed.total_moles() || isspaceturf(T)) //we're in space or there is no gas to process
|
||||
if(takes_damage)
|
||||
|
||||
@@ -77,6 +77,8 @@
|
||||
|
||||
/datum/reagents/Destroy()
|
||||
. = ..()
|
||||
//We're about to delete all reagents, so lets cleanup
|
||||
addiction_list.Cut()
|
||||
var/list/cached_reagents = reagent_list
|
||||
for(var/reagent in cached_reagents)
|
||||
var/datum/reagent/R = reagent
|
||||
@@ -332,9 +334,7 @@
|
||||
if(R.addiction_stage3_end to R.addiction_stage4_end)
|
||||
need_mob_update += R.addiction_act_stage4(C)
|
||||
if(R.addiction_stage4_end to INFINITY)
|
||||
to_chat(C, "<span class='notice'>You feel like you've gotten over your need for [R.name].</span>")
|
||||
SEND_SIGNAL(C, COMSIG_CLEAR_MOOD_EVENT, "[R.type]_addiction")
|
||||
cached_addictions.Remove(R)
|
||||
remove_addiction(R)
|
||||
else
|
||||
SEND_SIGNAL(C, COMSIG_CLEAR_MOOD_EVENT, "[R.type]_overdose")
|
||||
addiction_tick++
|
||||
@@ -344,6 +344,12 @@
|
||||
C.update_stamina()
|
||||
update_total()
|
||||
|
||||
/datum/reagents/proc/remove_addiction(datum/reagent/R)
|
||||
to_chat(my_atom, "<span class='notice'>You feel like you've gotten over your need for [R.name].</span>")
|
||||
SEND_SIGNAL(my_atom, COMSIG_CLEAR_MOOD_EVENT, "[R.type]_overdose")
|
||||
addiction_list.Remove(R)
|
||||
qdel(R)
|
||||
|
||||
//Signals that metabolization has stopped, triggering the end of trait-based effects
|
||||
/datum/reagents/proc/end_metabolization(mob/living/carbon/C, keep_liverless = TRUE)
|
||||
var/list/cached_reagents = reagent_list
|
||||
@@ -762,6 +768,8 @@
|
||||
R.metabolizing = FALSE
|
||||
R.on_mob_end_metabolize(M)
|
||||
R.on_mob_delete(M)
|
||||
//Clear from relevant lists
|
||||
addiction_list -= R
|
||||
qdel(R)
|
||||
reagent_list -= R
|
||||
update_total()
|
||||
|
||||
@@ -168,7 +168,7 @@ GLOBAL_LIST_INIT(food_reagents, build_reagents_to_food()) //reagentid = related
|
||||
|
||||
/obj/item/paper/secretrecipe
|
||||
name = "old recipe"
|
||||
var/recipe_id = "secretsauce"
|
||||
var/recipe_id = /datum/reagent/consumable/secretsauce
|
||||
|
||||
/obj/item/paper/secretrecipe/examine(mob/user) //Extra secret
|
||||
if(isobserver(user))
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
SEND_SIGNAL(A, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_MEDIUM)
|
||||
return
|
||||
|
||||
/obj/item/reagent_containers/rag/pre_altattackby(mob/living/M, mob/living/user, params)
|
||||
/obj/item/reagent_containers/rag/alt_pre_attack(mob/living/M, mob/living/user, params)
|
||||
if(istype(M) && user.a_intent == INTENT_HELP)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
if(M.on_fire)
|
||||
|
||||
@@ -289,6 +289,16 @@
|
||||
////////////Janitor Designs//////////////
|
||||
/////////////////////////////////////////
|
||||
|
||||
/datum/design/broom
|
||||
name = "Broom"
|
||||
desc = "Just your everyday standard broom."
|
||||
id = "broom"
|
||||
build_type = PROTOLATHE
|
||||
materials = list(MAT_METAL = 1000, MAT_GLASS = 600)
|
||||
build_path = /obj/item/twohanded/broom
|
||||
category = list("Equipment")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_SERVICE
|
||||
|
||||
/datum/design/mop
|
||||
name = "Mop"
|
||||
desc = "Just your everyday standard mop."
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
name = "Host Scan"
|
||||
desc = "The nanites display a detailed readout of a body scan to the host."
|
||||
id = "selfscan_nanites"
|
||||
program_type = /datum/nanite_program/triggered/self_scan
|
||||
program_type = /datum/nanite_program/self_scan
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/dermal_button
|
||||
@@ -67,7 +67,6 @@
|
||||
program_type = /datum/nanite_program/stealth
|
||||
category = list("Utility Nanites")
|
||||
|
||||
|
||||
/datum/design/nanites/reduced_diagnostics
|
||||
name = "Reduced Diagnostics"
|
||||
desc = "Disables some high-cost diagnostics in the nanites, making them unable to communicate their program list to portable scanners. \
|
||||
@@ -80,7 +79,7 @@
|
||||
name = "Subdermal ID"
|
||||
desc = "The nanites store the host's ID access rights in a subdermal magnetic strip. Updates when triggered, copying the host's current access."
|
||||
id = "access_nanites"
|
||||
program_type = /datum/nanite_program/triggered/access
|
||||
program_type = /datum/nanite_program/access
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/relay
|
||||
@@ -106,9 +105,9 @@
|
||||
|
||||
/datum/design/nanites/emp
|
||||
name = "Electromagnetic Resonance"
|
||||
desc = "The nanites cause an elctromagnetic pulse around the host when triggered. Will corrupt other nanite programs!"
|
||||
desc = "The nanites cause an electromagnetic pulse around the host when triggered. Will corrupt other nanite programs!"
|
||||
id = "emp_nanites"
|
||||
program_type = /datum/nanite_program/triggered/emp
|
||||
program_type = /datum/nanite_program/emp
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/spreading
|
||||
@@ -119,6 +118,13 @@
|
||||
program_type = /datum/nanite_program/spreading
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/nanite_sting
|
||||
name = "Nanite Sting"
|
||||
desc = "When triggered, projects a nearly invisible spike of nanites that attempts to infect a nearby non-host with a copy of the host's nanites cluster."
|
||||
id = "nanite_sting_nanites"
|
||||
program_type = /datum/nanite_program/nanite_sting
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/mitosis
|
||||
name = "Mitosis"
|
||||
desc = "The nanites gain the ability to self-replicate, using bluespace to power the process, instead of drawing from a template. This rapidly speeds up the replication rate,\
|
||||
@@ -197,7 +203,7 @@
|
||||
name = "Defibrillation"
|
||||
desc = "The nanites, when triggered, send a defibrillating shock to the host's heart."
|
||||
id = "defib_nanites"
|
||||
program_type = /datum/nanite_program/triggered/defib
|
||||
program_type = /datum/nanite_program/defib
|
||||
category = list("Medical Nanites")
|
||||
|
||||
|
||||
@@ -242,7 +248,7 @@
|
||||
name = "Adrenaline Burst"
|
||||
desc = "The nanites cause a burst of adrenaline when triggered, waking the host from stuns and temporarily increasing their speed."
|
||||
id = "adrenaline_nanites"
|
||||
program_type = /datum/nanite_program/triggered/adrenaline
|
||||
program_type = /datum/nanite_program/adrenaline
|
||||
category = list("Augmentation Nanites")
|
||||
|
||||
/datum/design/nanites/mindshield
|
||||
@@ -366,21 +372,21 @@
|
||||
name = "Heart-Stopper"
|
||||
desc = "Stops the host's heart when triggered; restarts it if triggered again."
|
||||
id = "heartstop_nanites"
|
||||
program_type = /datum/nanite_program/triggered/heart_stop
|
||||
program_type = /datum/nanite_program/heart_stop
|
||||
category = list("Weaponized Nanites")
|
||||
|
||||
/datum/design/nanites/explosive
|
||||
name = "Chain Detonation"
|
||||
desc = "Blows up all the nanites inside the host in a chain reaction when triggered."
|
||||
id = "explosive_nanites"
|
||||
program_type = /datum/nanite_program/triggered/explosive
|
||||
program_type = /datum/nanite_program/explosive
|
||||
category = list("Weaponized Nanites")
|
||||
|
||||
/datum/design/nanites/mind_control
|
||||
name = "Mind Control"
|
||||
desc = "The nanites imprint an absolute directive onto the host's brain while they're active."
|
||||
id = "mindcontrol_nanites"
|
||||
program_type = /datum/nanite_program/triggered/comm/mind_control
|
||||
program_type = /datum/nanite_program/comm/mind_control
|
||||
category = list("Weaponized Nanites")
|
||||
|
||||
////////////////////SUPPRESSION NANITES//////////////////////////////////////
|
||||
@@ -389,21 +395,21 @@
|
||||
name = "Electric Shock"
|
||||
desc = "The nanites shock the host when triggered. Destroys a large amount of nanites!"
|
||||
id = "shock_nanites"
|
||||
program_type = /datum/nanite_program/triggered/shocking
|
||||
program_type = /datum/nanite_program/shocking
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/stun
|
||||
name = "Neural Shock"
|
||||
desc = "The nanites pulse the host's nerves when triggered, inapacitating them for a short period."
|
||||
id = "stun_nanites"
|
||||
program_type = /datum/nanite_program/triggered/stun
|
||||
program_type = /datum/nanite_program/stun
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/sleepy
|
||||
name = "Sleep Induction"
|
||||
desc = "The nanites cause rapid narcolepsy when triggered."
|
||||
id = "sleep_nanites"
|
||||
program_type = /datum/nanite_program/triggered/sleepy
|
||||
program_type = /datum/nanite_program/sleepy
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/paralyzing
|
||||
@@ -445,21 +451,21 @@
|
||||
name = "Skull Echo"
|
||||
desc = "The nanites echo a synthesized message inside the host's skull."
|
||||
id = "voice_nanites"
|
||||
program_type = /datum/nanite_program/triggered/comm/voice
|
||||
program_type = /datum/nanite_program/comm/voice
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/speech
|
||||
name = "Forced Speech"
|
||||
desc = "The nanites force the host to say a pre-programmed sentence when triggered."
|
||||
id = "speech_nanites"
|
||||
program_type = /datum/nanite_program/triggered/comm/speech
|
||||
program_type = /datum/nanite_program/comm/speech
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/hallucination
|
||||
name = "Hallucination"
|
||||
desc = "The nanites make the host see and hear things that aren't real."
|
||||
id = "hallucination_nanites"
|
||||
program_type = /datum/nanite_program/triggered/comm/hallucination
|
||||
program_type = /datum/nanite_program/comm/hallucination
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/good_mood
|
||||
@@ -513,9 +519,42 @@
|
||||
program_type = /datum/nanite_program/sensor/voice
|
||||
category = list("Sensor Nanites")
|
||||
|
||||
/datum/design/nanites/sensor__nanite_volume
|
||||
/datum/design/nanites/sensor_nanite_volume
|
||||
name = "Nanite Volume Sensor"
|
||||
desc = "The nanites receive a signal when the nanite supply is above/below a certain percentage."
|
||||
id = "sensor_nanite_volume"
|
||||
program_type = /datum/nanite_program/sensor/nanite_volume
|
||||
category = list("Sensor Nanites")
|
||||
category = list("Sensor Nanites")
|
||||
|
||||
////////////////////NANITE PROTOCOLS//////////////////////////////////////
|
||||
//Note about the category name: The UI cuts the last 8 characters from the category name to remove the " Nanites" in the other categories
|
||||
//Because of this, Protocols was getting cut down to "P", so i had to add some padding
|
||||
/*
|
||||
/datum/design/nanites/kickstart
|
||||
name = "Kickstart Protocol"
|
||||
desc = "Replication Protocol: the nanites focus on early growth, heavily boosting replication rate for a few minutes after the initial implantation."
|
||||
id = "kickstart_nanites"
|
||||
program_type = /datum/nanite_program/protocol/kickstart
|
||||
category = list("Protocols_Nanites")
|
||||
|
||||
/datum/design/nanites/factory
|
||||
name = "Factory Protocol"
|
||||
desc = "Replication Protocol: the nanites build a factory matrix within the host, gradually increasing replication speed over time. The factory decays if the protocol is not active."
|
||||
id = "factory_nanites"
|
||||
program_type = /datum/nanite_program/protocol/factory
|
||||
category = list("Protocols_Nanites")
|
||||
|
||||
/datum/design/nanites/tinker
|
||||
name = "Tinker Protocol"
|
||||
desc = "Replication Protocol: the nanites learn to use metallic material in the host's bloodstream to speed up the replication process."
|
||||
id = "tinker_nanites"
|
||||
program_type = /datum/nanite_program/protocol/tinker
|
||||
category = list("Protocols_Nanites")
|
||||
|
||||
/datum/design/nanites/offline
|
||||
name = "Offline Production Protocol"
|
||||
desc = "Replication Protocol: while the host is asleep or otherwise unconcious, the nanites exploit the reduced interference to replicate more quickly."
|
||||
id = "offline_nanites"
|
||||
program_type = /datum/nanite_program/protocol/offline
|
||||
category = list("Protocols_Nanites")
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/datum/nanite_extra_setting
|
||||
var/setting_type
|
||||
var/value
|
||||
|
||||
/datum/nanite_extra_setting/proc/get_value()
|
||||
return value
|
||||
|
||||
/datum/nanite_extra_setting/proc/set_value(value)
|
||||
src.value = value
|
||||
|
||||
/datum/nanite_extra_setting/proc/get_copy()
|
||||
return
|
||||
|
||||
//I made the choice to send the name as part of the parameter instead of storing it directly on
|
||||
//this datum as a way of avoiding duplication of data between the containing assoc list
|
||||
//and this datum.
|
||||
//Also make sure to double wrap the list when implementing this as
|
||||
//+= is interpreted as a combine on lists, so the outer list gets unwrapped
|
||||
/datum/nanite_extra_setting/proc/get_frontend_list(name)
|
||||
return
|
||||
@@ -0,0 +1,27 @@
|
||||
/datum/nanite_extra_setting/boolean
|
||||
setting_type = NESTYPE_BOOLEAN
|
||||
var/true_text
|
||||
var/false_text
|
||||
|
||||
/datum/nanite_extra_setting/boolean/New(initial, true_text, false_text)
|
||||
value = initial
|
||||
src.true_text = true_text
|
||||
src.false_text = false_text
|
||||
|
||||
/datum/nanite_extra_setting/boolean/set_value(value)
|
||||
if(isnull(value))
|
||||
src.value = !src.value
|
||||
return
|
||||
. = ..()
|
||||
|
||||
/datum/nanite_extra_setting/boolean/get_copy()
|
||||
return new /datum/nanite_extra_setting/boolean(value, true_text, false_text)
|
||||
|
||||
/datum/nanite_extra_setting/boolean/get_frontend_list(name)
|
||||
return list(list(
|
||||
"name" = name,
|
||||
"type" = setting_type,
|
||||
"value" = value,
|
||||
"true_text" = true_text,
|
||||
"false_text" = false_text
|
||||
))
|
||||
@@ -0,0 +1,32 @@
|
||||
/datum/nanite_extra_setting/number
|
||||
setting_type = NESTYPE_NUMBER
|
||||
var/min
|
||||
var/max
|
||||
var/unit = ""
|
||||
|
||||
/datum/nanite_extra_setting/number/New(initial, min, max, unit)
|
||||
value = initial
|
||||
src.min = min
|
||||
src.max = max
|
||||
if(unit)
|
||||
src.unit = unit
|
||||
|
||||
/datum/nanite_extra_setting/number/set_value(value)
|
||||
if(istext(value))
|
||||
value = text2num(value)
|
||||
if(!value || !isnum(value))
|
||||
return
|
||||
src.value = CLAMP(value, min, max)
|
||||
|
||||
/datum/nanite_extra_setting/number/get_copy()
|
||||
return new /datum/nanite_extra_setting/number(value, min, max, unit)
|
||||
|
||||
/datum/nanite_extra_setting/number/get_frontend_list(name)
|
||||
return list(list(
|
||||
"name" = name,
|
||||
"type" = setting_type,
|
||||
"value" = value,
|
||||
"min" = min,
|
||||
"max" = max,
|
||||
"unit" = unit
|
||||
))
|
||||
@@ -0,0 +1,18 @@
|
||||
/datum/nanite_extra_setting/text
|
||||
setting_type = NESTYPE_TEXT
|
||||
|
||||
/datum/nanite_extra_setting/text/New(initial)
|
||||
value = initial
|
||||
|
||||
/datum/nanite_extra_setting/text/set_value(value)
|
||||
src.value = trim(value)
|
||||
|
||||
/datum/nanite_extra_setting/text/get_copy()
|
||||
return new /datum/nanite_extra_setting/text(value)
|
||||
|
||||
/datum/nanite_extra_setting/text/get_frontend_list(name)
|
||||
return list(list(
|
||||
"name" = name,
|
||||
"type" = setting_type,
|
||||
"value" = value
|
||||
))
|
||||
@@ -0,0 +1,18 @@
|
||||
/datum/nanite_extra_setting/type
|
||||
setting_type = NESTYPE_TYPE
|
||||
var/list/types
|
||||
|
||||
/datum/nanite_extra_setting/type/New(initial, types)
|
||||
value = initial
|
||||
src.types = types
|
||||
|
||||
/datum/nanite_extra_setting/type/get_copy()
|
||||
return new /datum/nanite_extra_setting/type(value, types)
|
||||
|
||||
/datum/nanite_extra_setting/type/get_frontend_list(name)
|
||||
return list(list(
|
||||
"name" = name,
|
||||
"type" = setting_type,
|
||||
"value" = value,
|
||||
"types" = types
|
||||
))
|
||||
@@ -77,7 +77,7 @@
|
||||
return
|
||||
occupant.AddComponent(/datum/component/nanites, 100)
|
||||
|
||||
/obj/machinery/nanite_chamber/proc/install_program(datum/nanite_program/NP)
|
||||
/obj/machinery/nanite_chamber/proc/remove_nanites(datum/nanite_program/NP)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if((stat & MAINT) || panel_open)
|
||||
@@ -88,74 +88,46 @@
|
||||
var/locked_state = locked
|
||||
locked = TRUE
|
||||
|
||||
//TODO COMPUTERY MACHINE SOUNDS
|
||||
set_busy(TRUE, "Initializing installation protocol...", "[initial(icon_state)]_raising")
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Connecting to nanite framework...", "[initial(icon_state)]_active"),20)
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Installing program...", "[initial(icon_state)]_falling"),35)
|
||||
addtimer(CALLBACK(src, .proc/complete_installation, locked_state, NP),55)
|
||||
//TODO OMINOUS MACHINE SOUNDS
|
||||
set_busy(TRUE, "Initializing cleanup protocol...", "[initial(icon_state)]_raising")
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Analyzing host bio-structure...", "[initial(icon_state)]_active"),20)
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Pinging nanites...", "[initial(icon_state)]_active"),40)
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Initiating graceful self-destruct sequence...", "[initial(icon_state)]_active"),70)
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Removing debris...", "[initial(icon_state)]_falling"),110)
|
||||
addtimer(CALLBACK(src, .proc/complete_removal, locked_state),130)
|
||||
|
||||
/obj/machinery/nanite_chamber/proc/complete_installation(locked_state, datum/nanite_program/NP)
|
||||
/obj/machinery/nanite_chamber/proc/complete_removal(locked_state)
|
||||
//TODO MACHINE DING
|
||||
locked = locked_state
|
||||
set_busy(FALSE)
|
||||
if(!occupant)
|
||||
return
|
||||
SEND_SIGNAL(occupant, COMSIG_NANITE_DELETE)
|
||||
|
||||
SEND_SIGNAL(occupant, COMSIG_NANITE_ADD_PROGRAM, NP.copy())
|
||||
|
||||
/obj/machinery/nanite_chamber/proc/uninstall_program(datum/nanite_program/NP)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if((stat & MAINT) || panel_open)
|
||||
return
|
||||
if(!occupant || busy)
|
||||
return
|
||||
|
||||
var/locked_state = locked
|
||||
locked = TRUE
|
||||
|
||||
//TODO COMPUTERY MACHINE SOUNDS
|
||||
set_busy(TRUE, "Initializing uninstallation protocol...", "[initial(icon_state)]_raising")
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Connecting to nanite framework...", "[initial(icon_state)]_active"),20)
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Uninstalling program...", "[initial(icon_state)]_falling"),35)
|
||||
addtimer(CALLBACK(src, .proc/complete_uninstallation, locked_state, NP),55)
|
||||
|
||||
/obj/machinery/nanite_chamber/proc/complete_uninstallation(locked_state, datum/nanite_program/NP)
|
||||
//TODO MACHINE DING
|
||||
locked = locked_state
|
||||
set_busy(FALSE)
|
||||
if(!occupant)
|
||||
return
|
||||
qdel(NP)
|
||||
|
||||
/obj/machinery/nanite_chamber/update_icon()
|
||||
cut_overlays()
|
||||
|
||||
if((stat & MAINT) || panel_open)
|
||||
add_overlay("maint")
|
||||
|
||||
else if(!(stat & (NOPOWER|BROKEN)))
|
||||
if(busy || locked)
|
||||
add_overlay("red")
|
||||
if(locked)
|
||||
add_overlay("bolted")
|
||||
else
|
||||
add_overlay("green")
|
||||
|
||||
/obj/machinery/nanite_chamber/update_icon_state()
|
||||
//running and someone in there
|
||||
if(occupant)
|
||||
if(busy)
|
||||
icon_state = busy_icon_state
|
||||
else
|
||||
icon_state = initial(icon_state)+ "_occupied"
|
||||
return
|
||||
icon_state = initial(icon_state) + "_occupied"
|
||||
else
|
||||
//running
|
||||
icon_state = initial(icon_state) + (state_open ? "_open" : "")
|
||||
|
||||
//running
|
||||
icon_state = initial(icon_state)+ (state_open ? "_open" : "")
|
||||
/obj/machinery/nanite_chamber/update_overlays()
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/nanite_chamber/power_change()
|
||||
..()
|
||||
update_icon()
|
||||
if((stat & MAINT) || panel_open)
|
||||
. += "maint"
|
||||
|
||||
else if(!(stat & (NOPOWER|BROKEN)))
|
||||
if(busy || locked)
|
||||
. += "red"
|
||||
if(locked)
|
||||
. += "bolted"
|
||||
else
|
||||
. += "green"
|
||||
|
||||
/obj/machinery/nanite_chamber/proc/toggle_open(mob/user)
|
||||
if(panel_open)
|
||||
@@ -182,7 +154,7 @@
|
||||
user.last_special = world.time + CLICK_CD_BREAKOUT
|
||||
user.visible_message("<span class='notice'>You see [user] kicking against the door of [src]!</span>", \
|
||||
"<span class='notice'>You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)</span>", \
|
||||
"<span class='italics'>You hear a metallic creaking from [src].</span>")
|
||||
"<span class='hear'>You hear a metallic creaking from [src].</span>")
|
||||
if(do_after(user,(breakout_time), target = src))
|
||||
if(!user || user.stat != CONSCIOUS || user.loc != src || state_open || !locked || busy)
|
||||
return
|
||||
@@ -231,6 +203,8 @@
|
||||
toggle_open(user)
|
||||
|
||||
/obj/machinery/nanite_chamber/MouseDrop_T(mob/target, mob/user)
|
||||
if(user.stat || user.lying || !Adjacent(user) || !user.Adjacent(target) || !iscarbon(target) || !user.IsAdvancedToolUser())
|
||||
if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK) || !Adjacent(target) || !user.Adjacent(target) || !iscarbon(target))
|
||||
return
|
||||
close_machine(target)
|
||||
if(close_machine(target))
|
||||
log_combat(user, target, "inserted", null, "into [src].")
|
||||
add_fingerprint(user)
|
||||
|
||||
@@ -5,30 +5,13 @@
|
||||
var/obj/item/disk/nanite_program/disk
|
||||
circuit = /obj/item/circuitboard/computer/nanite_chamber_control
|
||||
icon_screen = "nanite_chamber_control"
|
||||
ui_x = 380
|
||||
ui_y = 570
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/Initialize()
|
||||
. = ..()
|
||||
find_chamber()
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/attackby(obj/item/I, mob/user)
|
||||
if(istype(I, /obj/item/disk/nanite_program))
|
||||
var/obj/item/disk/nanite_program/N = I
|
||||
if(disk)
|
||||
eject(user)
|
||||
if(user.transferItemToLoc(N, src))
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src]</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
|
||||
disk = N
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/proc/eject(mob/living/user)
|
||||
if(!disk)
|
||||
return
|
||||
if(!istype(user) || !Adjacent(user) || !user.put_in_active_hand(disk))
|
||||
disk.forceMove(drop_location())
|
||||
disk = null
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/proc/find_chamber()
|
||||
for(var/direction in GLOB.cardinals)
|
||||
var/C = locate(/obj/machinery/nanite_chamber, get_step(src, direction))
|
||||
@@ -43,41 +26,13 @@
|
||||
..()
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "nanite_chamber_control", name, 550, 800, master_ui, state)
|
||||
ui = new(user, src, ui_key, "nanite_chamber_control", name, ui_x, ui_y, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/ui_data()
|
||||
var/list/data = list()
|
||||
if(disk)
|
||||
data["has_disk"] = TRUE
|
||||
var/list/disk_data = list()
|
||||
var/datum/nanite_program/P = disk.program
|
||||
if(P)
|
||||
data["has_program"] = TRUE
|
||||
disk_data["name"] = P.name
|
||||
disk_data["desc"] = P.desc
|
||||
|
||||
disk_data["activated"] = P.activated
|
||||
disk_data["activation_delay"] = P.activation_delay
|
||||
disk_data["timer"] = P.timer
|
||||
disk_data["activation_code"] = P.activation_code
|
||||
disk_data["deactivation_code"] = P.deactivation_code
|
||||
disk_data["kill_code"] = P.kill_code
|
||||
disk_data["trigger_code"] = P.trigger_code
|
||||
disk_data["timer_type"] = P.get_timer_type_text()
|
||||
|
||||
var/list/extra_settings = list()
|
||||
for(var/X in P.extra_settings)
|
||||
var/list/setting = list()
|
||||
setting["name"] = X
|
||||
setting["value"] = P.get_extra_setting(X)
|
||||
extra_settings += list(setting)
|
||||
disk_data["extra_settings"] = extra_settings
|
||||
if(LAZYLEN(extra_settings))
|
||||
disk_data["has_extra_settings"] = TRUE
|
||||
data["disk"] = disk_data
|
||||
|
||||
if(!chamber)
|
||||
data["status_msg"] = "No chamber detected."
|
||||
@@ -97,6 +52,7 @@
|
||||
data["status_msg"] = chamber.busy_message
|
||||
return data
|
||||
|
||||
data["status_msg"] = null
|
||||
data["scan_level"] = chamber.scan_level
|
||||
data["locked"] = chamber.locked
|
||||
data["occupant_name"] = chamber.occupant.name
|
||||
@@ -113,46 +69,32 @@
|
||||
chamber.locked = !chamber.locked
|
||||
chamber.update_icon()
|
||||
. = TRUE
|
||||
if("eject")
|
||||
eject(usr)
|
||||
. = TRUE
|
||||
if("set_safety")
|
||||
var/threshold = input("Set safety threshold (0-500):", name, null) as null|num
|
||||
var/threshold = text2num(params["value"])
|
||||
if(!isnull(threshold))
|
||||
chamber.set_safety(CLAMP(round(threshold, 1),0,500))
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
investigate_log("[key_name(chamber.occupant)]'s nanites' safety threshold was set to [threshold] by [key_name(usr)].", INVESTIGATE_NANITES)
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
chamber.occupant.investigate_log("'s nanites' safety threshold was set to [threshold] by [key_name(usr)] via [src] at [AREACOORD(src)].", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("set_cloud")
|
||||
var/cloud_id = input("Set cloud ID (1-100, 0 to disable):", name, null) as null|num
|
||||
var/cloud_id = text2num(params["value"])
|
||||
if(!isnull(cloud_id))
|
||||
chamber.set_cloud(CLAMP(round(cloud_id, 1),0,100))
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
investigate_log("[key_name(chamber.occupant)]'s nanites' cloud id was set to [cloud_id] by [key_name(usr)].", INVESTIGATE_NANITES)
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
chamber.occupant.investigate_log("'s nanites' cloud id was set to [cloud_id] by [key_name(usr)] via [src] at [AREACOORD(src)].", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("connect_chamber")
|
||||
find_chamber()
|
||||
. = TRUE
|
||||
if("remove_nanites")
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, FALSE)
|
||||
chamber.remove_nanites()
|
||||
log_combat(usr, chamber.occupant, "cleared nanites from", null, "via [src]")
|
||||
chamber.occupant.investigate_log("'s nanites were cleared by [key_name(usr)] via [src] at [AREACOORD(src)].", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("nanite_injection")
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, 0)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, FALSE)
|
||||
chamber.inject_nanites()
|
||||
investigate_log("[key_name(chamber.occupant)] was injected with nanites by [key_name(usr)] using a nanite chamber.", INVESTIGATE_NANITES)
|
||||
log_combat(usr, chamber.occupant, "injected", null, "with nanites via [src]")
|
||||
chamber.occupant.investigate_log("was injected with nanites by [key_name(usr)] via [src] at [AREACOORD(src)].", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("add_program")
|
||||
if(!disk || !chamber || !chamber.occupant)
|
||||
return
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, 0)
|
||||
chamber.install_program(disk.program)
|
||||
investigate_log("Program of type [disk.program.type] was installed into [key_name(chamber.occupant)]'s nanites with a nanite chamber by [key_name(usr)].", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("remove_program")
|
||||
if(!chamber || !chamber.occupant)
|
||||
return
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, 0)
|
||||
var/list/nanite_programs = list()
|
||||
SEND_SIGNAL(chamber.occupant, COMSIG_NANITE_GET_PROGRAMS, nanite_programs)
|
||||
if(LAZYLEN(nanite_programs))
|
||||
var/datum/nanite_program/P = nanite_programs[text2num(params["program_id"])]
|
||||
chamber.uninstall_program(P)
|
||||
investigate_log("Program of type [P.type] was uninstalled from [key_name(chamber.occupant)]'s nanites with a nanite chamber by [key_name(usr)].", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
@@ -4,9 +4,13 @@
|
||||
circuit = /obj/item/circuitboard/computer/nanite_cloud_controller
|
||||
icon = 'icons/obj/machines/research.dmi'
|
||||
icon_state = "nanite_cloud_controller"
|
||||
ui_x = 375
|
||||
ui_y = 700
|
||||
|
||||
var/obj/item/disk/nanite_program/disk
|
||||
var/list/datum/nanite_cloud_backup/cloud_backups = list()
|
||||
var/current_view = 0 //0 is the main menu, any other number is the page of the backup with that ID
|
||||
var/new_backup_id = 1
|
||||
|
||||
/obj/machinery/computer/nanite_cloud_controller/Destroy()
|
||||
QDEL_LIST(cloud_backups) //rip backups
|
||||
@@ -19,8 +23,8 @@
|
||||
if(disk)
|
||||
eject(user)
|
||||
if(user.transferItemToLoc(N, src))
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src]</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src].</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
|
||||
disk = N
|
||||
else
|
||||
..()
|
||||
@@ -50,13 +54,14 @@
|
||||
investigate_log("[key_name(user)] created a new nanite cloud backup with id #[cloud_id]", INVESTIGATE_NANITES)
|
||||
|
||||
/obj/machinery/computer/nanite_cloud_controller/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "nanite_cloud_control", name, 600, 800, master_ui, state)
|
||||
ui = new(user, src, ui_key, "nanite_cloud_control", name, ui_x, ui_y, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/nanite_cloud_controller/ui_data()
|
||||
var/list/data = list()
|
||||
|
||||
if(disk)
|
||||
data["has_disk"] = TRUE
|
||||
var/list/disk_data = list()
|
||||
@@ -71,24 +76,28 @@
|
||||
disk_data["trigger_cooldown"] = P.trigger_cooldown / 10
|
||||
|
||||
disk_data["activated"] = P.activated
|
||||
disk_data["activation_delay"] = P.activation_delay
|
||||
disk_data["timer"] = P.timer
|
||||
disk_data["activation_code"] = P.activation_code
|
||||
disk_data["deactivation_code"] = P.deactivation_code
|
||||
disk_data["kill_code"] = P.kill_code
|
||||
disk_data["trigger_code"] = P.trigger_code
|
||||
disk_data["timer_type"] = P.get_timer_type_text()
|
||||
disk_data["timer_restart"] = P.timer_restart / 10
|
||||
disk_data["timer_shutdown"] = P.timer_shutdown / 10
|
||||
disk_data["timer_trigger"] = P.timer_trigger / 10
|
||||
disk_data["timer_trigger_delay"] = P.timer_trigger_delay / 10
|
||||
|
||||
var/list/extra_settings = list()
|
||||
for(var/X in P.extra_settings)
|
||||
var/list/setting = list()
|
||||
setting["name"] = X
|
||||
setting["value"] = P.get_extra_setting(X)
|
||||
extra_settings += list(setting)
|
||||
var/list/extra_settings = P.get_extra_settings_frontend()
|
||||
disk_data["extra_settings"] = extra_settings
|
||||
if(LAZYLEN(extra_settings))
|
||||
disk_data["has_extra_settings"] = TRUE
|
||||
if(istype(P, /datum/nanite_program/sensor))
|
||||
var/datum/nanite_program/sensor/sensor = P
|
||||
if(sensor.can_rule)
|
||||
disk_data["can_rule"] = TRUE
|
||||
data["disk"] = disk_data
|
||||
else
|
||||
data["has_disk"] = FALSE
|
||||
|
||||
data["new_backup_id"] = new_backup_id
|
||||
|
||||
data["current_view"] = current_view
|
||||
if(current_view)
|
||||
@@ -108,19 +117,30 @@
|
||||
cloud_program["trigger_cost"] = P.trigger_cost
|
||||
cloud_program["trigger_cooldown"] = P.trigger_cooldown / 10
|
||||
cloud_program["activated"] = P.activated
|
||||
cloud_program["activation_delay"] = P.activation_delay
|
||||
cloud_program["timer"] = P.timer
|
||||
cloud_program["timer_type"] = P.get_timer_type_text()
|
||||
cloud_program["timer_restart"] = P.timer_restart / 10
|
||||
cloud_program["timer_shutdown"] = P.timer_shutdown / 10
|
||||
cloud_program["timer_trigger"] = P.timer_trigger / 10
|
||||
cloud_program["timer_trigger_delay"] = P.timer_trigger_delay / 10
|
||||
|
||||
cloud_program["activation_code"] = P.activation_code
|
||||
cloud_program["deactivation_code"] = P.deactivation_code
|
||||
cloud_program["kill_code"] = P.kill_code
|
||||
cloud_program["trigger_code"] = P.trigger_code
|
||||
var/list/extra_settings = list()
|
||||
for(var/X in P.extra_settings)
|
||||
var/list/setting = list()
|
||||
setting["name"] = X
|
||||
setting["value"] = P.get_extra_setting(X)
|
||||
extra_settings += list(setting)
|
||||
var/list/rules = list()
|
||||
var/rule_id = 1
|
||||
for(var/X in P.rules)
|
||||
var/datum/nanite_rule/nanite_rule = X
|
||||
var/list/rule = list()
|
||||
rule["display"] = nanite_rule.display()
|
||||
rule["program_id"] = id
|
||||
rule["id"] = rule_id
|
||||
rules += list(rule)
|
||||
rule_id++
|
||||
cloud_program["rules"] = rules
|
||||
if(LAZYLEN(rules))
|
||||
cloud_program["has_rules"] = TRUE
|
||||
|
||||
var/list/extra_settings = P.get_extra_settings_frontend()
|
||||
cloud_program["extra_settings"] = extra_settings
|
||||
if(LAZYLEN(extra_settings))
|
||||
cloud_program["has_extra_settings"] = TRUE
|
||||
@@ -147,17 +167,20 @@
|
||||
if("set_view")
|
||||
current_view = text2num(params["view"])
|
||||
. = TRUE
|
||||
if("update_new_backup_value")
|
||||
var/backup_value = text2num(params["value"])
|
||||
new_backup_id = backup_value
|
||||
if("create_backup")
|
||||
var/cloud_id = input("Choose a cloud ID (1-100):", name, null) as null|num
|
||||
var/cloud_id = new_backup_id
|
||||
if(!isnull(cloud_id))
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE)
|
||||
cloud_id = CLAMP(round(cloud_id, 1),1,100)
|
||||
generate_backup(cloud_id, usr)
|
||||
. = TRUE
|
||||
if("delete_backup")
|
||||
var/datum/nanite_cloud_backup/backup = get_backup(current_view)
|
||||
if(backup)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE)
|
||||
qdel(backup)
|
||||
investigate_log("[key_name(usr)] deleted the nanite cloud backup #[current_view]", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
@@ -165,7 +188,7 @@
|
||||
if(disk && disk.program)
|
||||
var/datum/nanite_cloud_backup/backup = get_backup(current_view)
|
||||
if(backup)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE)
|
||||
var/datum/component/nanites/nanites = backup.nanites
|
||||
nanites.add_program(null, disk.program.copy())
|
||||
investigate_log("[key_name(usr)] uploaded program [disk.program.name] to cloud #[current_view]", INVESTIGATE_NANITES)
|
||||
@@ -173,12 +196,37 @@
|
||||
if("remove_program")
|
||||
var/datum/nanite_cloud_backup/backup = get_backup(current_view)
|
||||
if(backup)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE)
|
||||
var/datum/component/nanites/nanites = backup.nanites
|
||||
var/datum/nanite_program/P = nanites.programs[text2num(params["program_id"])]
|
||||
investigate_log("[key_name(usr)] deleted program [P.name] from cloud #[current_view]", INVESTIGATE_NANITES)
|
||||
qdel(P)
|
||||
. = TRUE
|
||||
if("add_rule")
|
||||
if(disk && disk.program && istype(disk.program, /datum/nanite_program/sensor))
|
||||
var/datum/nanite_program/sensor/rule_template = disk.program
|
||||
if(!rule_template.can_rule)
|
||||
return
|
||||
var/datum/nanite_cloud_backup/backup = get_backup(current_view)
|
||||
if(backup)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
var/datum/component/nanites/nanites = backup.nanites
|
||||
var/datum/nanite_program/P = nanites.programs[text2num(params["program_id"])]
|
||||
var/datum/nanite_rule/rule = rule_template.make_rule(P)
|
||||
|
||||
investigate_log("[key_name(usr)] added rule [rule.display()] to program [P.name] in cloud #[current_view]", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("remove_rule")
|
||||
var/datum/nanite_cloud_backup/backup = get_backup(current_view)
|
||||
if(backup)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
var/datum/component/nanites/nanites = backup.nanites
|
||||
var/datum/nanite_program/P = nanites.programs[text2num(params["program_id"])]
|
||||
var/datum/nanite_rule/rule = P.rules[text2num(params["rule_id"])]
|
||||
rule.remove()
|
||||
|
||||
investigate_log("[key_name(usr)] removed rule [rule.display()] from program [P.name] in cloud #[current_view]", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
|
||||
/datum/nanite_cloud_backup
|
||||
var/cloud_id = 0
|
||||
@@ -193,4 +241,4 @@
|
||||
/datum/nanite_cloud_backup/Destroy()
|
||||
storage.cloud_backups -= src
|
||||
SSnanites.cloud_backups -= src
|
||||
return ..()
|
||||
return ..()
|
||||
|
||||
@@ -1,157 +0,0 @@
|
||||
/obj/item/nanite_hijacker
|
||||
name = "nanite remote control" //fake name
|
||||
desc = "A device that can load nanite programming disks, edit them at will, and imprint them to nanites remotely."
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "nanite_remote"
|
||||
item_flags = NOBLUDGEON
|
||||
var/obj/item/disk/nanite_program/disk
|
||||
var/datum/nanite_program/program
|
||||
|
||||
/obj/item/nanite_hijacker/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(!user.canUseTopic(src, BE_CLOSE))
|
||||
return
|
||||
if(disk)
|
||||
eject()
|
||||
return TRUE
|
||||
|
||||
/obj/item/nanite_hijacker/examine(mob/user)
|
||||
. = ..()
|
||||
if(disk)
|
||||
. += "<span class='notice'>Alt-click [src] to eject the disk.</span>"
|
||||
|
||||
/obj/item/nanite_hijacker/attackby(obj/item/I, mob/user)
|
||||
if(istype(I, /obj/item/disk/nanite_program))
|
||||
var/obj/item/disk/nanite_program/N = I
|
||||
if(disk)
|
||||
eject()
|
||||
if(user.transferItemToLoc(N, src))
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src]</span>")
|
||||
disk = N
|
||||
program = N.program
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/nanite_hijacker/proc/eject(mob/living/user)
|
||||
if(!disk)
|
||||
return
|
||||
if(!istype(user) || !Adjacent(user) || !user.put_in_hand(disk))
|
||||
disk.forceMove(drop_location())
|
||||
disk = null
|
||||
program = null
|
||||
|
||||
/obj/item/nanite_hijacker/afterattack(atom/target, mob/user, etc)
|
||||
if(!disk || !disk.program)
|
||||
return
|
||||
if(isliving(target))
|
||||
var/success = SEND_SIGNAL(target, COMSIG_NANITE_ADD_PROGRAM, program.copy())
|
||||
switch(success)
|
||||
if(NONE)
|
||||
to_chat(user, "<span class='notice'>You don't detect any nanites in [target].</span>")
|
||||
if(COMPONENT_PROGRAM_INSTALLED)
|
||||
to_chat(user, "<span class='notice'>You insert the currently loaded program into [target]'s nanites.</span>")
|
||||
if(COMPONENT_PROGRAM_NOT_INSTALLED)
|
||||
to_chat(user, "<span class='warning'>You try to insert the currently loaded program into [target]'s nanites, but the installation fails.</span>")
|
||||
|
||||
//Same UI as the nanite programmer, as it pretty much does the same
|
||||
/obj/item/nanite_hijacker/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
|
||||
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "nanite_programmer", "Internal Nanite Programmer", 420, 800, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/item/nanite_hijacker/ui_data()
|
||||
var/list/data = list()
|
||||
data["has_disk"] = istype(disk)
|
||||
data["has_program"] = istype(program)
|
||||
if(program)
|
||||
data["name"] = program.name
|
||||
data["desc"] = program.desc
|
||||
data["use_rate"] = program.use_rate
|
||||
data["can_trigger"] = program.can_trigger
|
||||
data["trigger_cost"] = program.trigger_cost
|
||||
data["trigger_cooldown"] = program.trigger_cooldown / 10
|
||||
|
||||
data["activated"] = program.activated
|
||||
data["activation_delay"] = program.activation_delay
|
||||
data["timer"] = program.timer
|
||||
data["activation_code"] = program.activation_code
|
||||
data["deactivation_code"] = program.deactivation_code
|
||||
data["kill_code"] = program.kill_code
|
||||
data["trigger_code"] = program.trigger_code
|
||||
data["timer_type"] = program.get_timer_type_text()
|
||||
|
||||
var/list/extra_settings = list()
|
||||
for(var/X in program.extra_settings)
|
||||
var/list/setting = list()
|
||||
setting["name"] = X
|
||||
setting["value"] = program.get_extra_setting(X)
|
||||
extra_settings += list(setting)
|
||||
data["extra_settings"] = extra_settings
|
||||
if(LAZYLEN(extra_settings))
|
||||
data["has_extra_settings"] = TRUE
|
||||
|
||||
return data
|
||||
|
||||
/obj/item/nanite_hijacker/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("eject")
|
||||
eject(usr)
|
||||
. = TRUE
|
||||
if("toggle_active")
|
||||
program.activated = !program.activated //we don't use the activation procs since we aren't in a mob
|
||||
if(program.activated)
|
||||
program.activation_delay = 0
|
||||
. = TRUE
|
||||
if("set_code")
|
||||
var/new_code = input("Set code (0000-9999):", name, null) as null|num
|
||||
if(!isnull(new_code))
|
||||
new_code = CLAMP(round(new_code, 1),0,9999)
|
||||
else
|
||||
return
|
||||
|
||||
var/target_code = params["target_code"]
|
||||
switch(target_code)
|
||||
if("activation")
|
||||
program.activation_code = CLAMP(round(new_code, 1),0,9999)
|
||||
if("deactivation")
|
||||
program.deactivation_code = CLAMP(round(new_code, 1),0,9999)
|
||||
if("kill")
|
||||
program.kill_code = CLAMP(round(new_code, 1),0,9999)
|
||||
if("trigger")
|
||||
program.trigger_code = CLAMP(round(new_code, 1),0,9999)
|
||||
. = TRUE
|
||||
if("set_extra_setting")
|
||||
program.set_extra_setting(usr, params["target_setting"])
|
||||
. = TRUE
|
||||
if("set_activation_delay")
|
||||
var/delay = input("Set activation delay in seconds (0-1800):", name, program.activation_delay) as null|num
|
||||
if(!isnull(delay))
|
||||
delay = CLAMP(round(delay, 1),0,1800)
|
||||
program.activation_delay = delay
|
||||
if(delay)
|
||||
program.activated = FALSE
|
||||
. = TRUE
|
||||
if("set_timer")
|
||||
var/timer = input("Set timer in seconds (10-3600):", name, program.timer) as null|num
|
||||
if(!isnull(timer))
|
||||
if(!timer == 0)
|
||||
timer = CLAMP(round(timer, 1),10,3600)
|
||||
program.timer = timer
|
||||
. = TRUE
|
||||
if("set_timer_type")
|
||||
var/new_type = input("Choose the timer effect","Timer Effect") as null|anything in list("Deactivate","Self-Delete","Trigger","Reset Activation Timer")
|
||||
if(new_type)
|
||||
switch(new_type)
|
||||
if("Deactivate")
|
||||
program.timer_type = NANITE_TIMER_DEACTIVATE
|
||||
if("Self-Delete")
|
||||
program.timer_type = NANITE_TIMER_SELFDELETE
|
||||
if("Trigger")
|
||||
program.timer_type = NANITE_TIMER_TRIGGER
|
||||
if("Reset Activation Timer")
|
||||
program.timer_type = NANITE_TIMER_RESET
|
||||
. = TRUE
|
||||
@@ -6,4 +6,4 @@
|
||||
icon_state = "nanite_remote"
|
||||
|
||||
/obj/item/nanite_injector/attack_self(mob/user)
|
||||
user.AddComponent(/datum/component/nanites, 150)
|
||||
user.AddComponent(/datum/component/nanites, 150)
|
||||
|
||||
@@ -7,18 +7,21 @@
|
||||
use_power = IDLE_POWER_USE
|
||||
anchored = TRUE
|
||||
density = TRUE
|
||||
ui_x = 500
|
||||
ui_y = 700
|
||||
|
||||
var/obj/item/disk/nanite_program/disk
|
||||
var/datum/techweb/linked_techweb
|
||||
var/current_category = "Main"
|
||||
var/detail_view = FALSE
|
||||
var/detail_view = TRUE
|
||||
var/categories = list(
|
||||
list(name = "Utility Nanites"),
|
||||
list(name = "Medical Nanites"),
|
||||
list(name = "Sensor Nanites"),
|
||||
list(name = "Augmentation Nanites"),
|
||||
list(name = "Suppression Nanites"),
|
||||
list(name = "Weaponized Nanites")
|
||||
list(name = "Weaponized Nanites"),
|
||||
//list(name = "Protocols") B.E.P.I.S Content, which we dont have
|
||||
)
|
||||
|
||||
/obj/machinery/nanite_program_hub/Initialize()
|
||||
@@ -31,8 +34,8 @@
|
||||
if(disk)
|
||||
eject(user)
|
||||
if(user.transferItemToLoc(N, src))
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src]</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src].</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
|
||||
disk = N
|
||||
else
|
||||
..()
|
||||
@@ -45,10 +48,9 @@
|
||||
disk = null
|
||||
|
||||
/obj/machinery/nanite_program_hub/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "nanite_program_hub", name, 500, 700, master_ui, state)
|
||||
ui.set_autoupdate(FALSE) //to avoid making the whole program list every second
|
||||
ui = new(user, src, ui_key, "nanite_program_hub", name, ui_x, ui_y, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/nanite_program_hub/ui_data()
|
||||
@@ -62,25 +64,31 @@
|
||||
disk_data["name"] = P.name
|
||||
disk_data["desc"] = P.desc
|
||||
data["disk"] = disk_data
|
||||
else
|
||||
data["has_disk"] = FALSE
|
||||
|
||||
data["detail_view"] = detail_view
|
||||
data["category"] = current_category
|
||||
|
||||
if(current_category != "Main")
|
||||
var/list/program_list = list()
|
||||
for(var/i in linked_techweb.researched_designs)
|
||||
var/datum/design/nanites/D = SSresearch.techweb_design_by_id(i)
|
||||
if(!istype(D))
|
||||
continue
|
||||
if(current_category in D.category)
|
||||
var/list/program_design = list()
|
||||
program_design["id"] = D.id
|
||||
program_design["name"] = D.name
|
||||
program_design["desc"] = D.desc
|
||||
program_list += list(program_design)
|
||||
data["program_list"] = program_list
|
||||
else
|
||||
data["categories"] = categories
|
||||
return data
|
||||
|
||||
/obj/machinery/nanite_program_hub/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["programs"] = list()
|
||||
for(var/i in linked_techweb.researched_designs)
|
||||
var/datum/design/nanites/D = SSresearch.techweb_design_by_id(i)
|
||||
if(!istype(D))
|
||||
continue
|
||||
var/cat_name = D.category[1] //just put them in the first category fuck it
|
||||
if(isnull(data["programs"][cat_name]))
|
||||
data["programs"][cat_name] = list()
|
||||
var/list/program_design = list()
|
||||
program_design["id"] = D.id
|
||||
program_design["name"] = D.name
|
||||
program_design["desc"] = D.desc
|
||||
data["programs"][cat_name] += list(program_design)
|
||||
|
||||
if(!length(data["programs"]))
|
||||
data["programs"] = null
|
||||
|
||||
return data
|
||||
|
||||
@@ -101,11 +109,10 @@
|
||||
qdel(disk.program)
|
||||
disk.program = new downloaded.program_type
|
||||
disk.name = "[initial(disk.name)] \[[disk.program.name]\]"
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, 0)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, FALSE)
|
||||
. = TRUE
|
||||
if("set_category")
|
||||
var/new_category = params["category"]
|
||||
current_category = new_category
|
||||
if("refresh")
|
||||
update_static_data(usr)
|
||||
. = TRUE
|
||||
if("toggle_details")
|
||||
detail_view = !detail_view
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
use_power = IDLE_POWER_USE
|
||||
anchored = TRUE
|
||||
density = TRUE
|
||||
flags_1 = HEAR_1
|
||||
ui_x = 420
|
||||
ui_y = 550
|
||||
|
||||
/obj/machinery/nanite_programmer/attackby(obj/item/I, mob/user)
|
||||
if(istype(I, /obj/item/disk/nanite_program))
|
||||
@@ -17,7 +20,7 @@
|
||||
eject(user)
|
||||
if(user.transferItemToLoc(N, src))
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src]</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
|
||||
disk = N
|
||||
program = N.program
|
||||
else
|
||||
@@ -32,9 +35,9 @@
|
||||
program = null
|
||||
|
||||
/obj/machinery/nanite_programmer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "nanite_programmer", name, 600, 800, master_ui, state)
|
||||
ui = new(user, src, ui_key, "nanite_programmer", name, ui_x, ui_y, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/nanite_programmer/ui_data()
|
||||
@@ -50,20 +53,16 @@
|
||||
data["trigger_cooldown"] = program.trigger_cooldown / 10
|
||||
|
||||
data["activated"] = program.activated
|
||||
data["activation_delay"] = program.activation_delay
|
||||
data["timer"] = program.timer
|
||||
data["activation_code"] = program.activation_code
|
||||
data["deactivation_code"] = program.deactivation_code
|
||||
data["kill_code"] = program.kill_code
|
||||
data["trigger_code"] = program.trigger_code
|
||||
data["timer_type"] = program.get_timer_type_text()
|
||||
data["timer_restart"] = program.timer_restart / 10
|
||||
data["timer_shutdown"] = program.timer_shutdown / 10
|
||||
data["timer_trigger"] = program.timer_trigger / 10
|
||||
data["timer_trigger_delay"] = program.timer_trigger_delay / 10
|
||||
|
||||
var/list/extra_settings = list()
|
||||
for(var/X in program.extra_settings)
|
||||
var/list/setting = list()
|
||||
setting["name"] = X
|
||||
setting["value"] = program.get_extra_setting(X)
|
||||
extra_settings += list(setting)
|
||||
var/list/extra_settings = program.get_extra_settings_frontend()
|
||||
data["extra_settings"] = extra_settings
|
||||
if(LAZYLEN(extra_settings))
|
||||
data["has_extra_settings"] = TRUE
|
||||
@@ -78,20 +77,12 @@
|
||||
eject(usr)
|
||||
. = TRUE
|
||||
if("toggle_active")
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
program.activated = !program.activated //we don't use the activation procs since we aren't in a mob
|
||||
if(program.activated)
|
||||
program.activation_delay = 0
|
||||
. = TRUE
|
||||
if("set_code")
|
||||
var/new_code = input("Set code (0000-9999):", name, null) as null|num
|
||||
if(!isnull(new_code))
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
new_code = CLAMP(round(new_code, 1),0,9999)
|
||||
else
|
||||
return
|
||||
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
var/new_code = text2num(params["code"])
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
var/target_code = params["target_code"]
|
||||
switch(target_code)
|
||||
if("activation")
|
||||
@@ -104,37 +95,44 @@
|
||||
program.trigger_code = CLAMP(round(new_code, 1),0,9999)
|
||||
. = TRUE
|
||||
if("set_extra_setting")
|
||||
program.set_extra_setting(usr, params["target_setting"])
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
program.set_extra_setting(params["target_setting"], params["value"])
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
. = TRUE
|
||||
if("set_activation_delay")
|
||||
var/delay = input("Set activation delay in seconds (0-1800):", name, program.activation_delay) as null|num
|
||||
if(!isnull(delay))
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
delay = CLAMP(round(delay, 1),0,1800)
|
||||
program.activation_delay = delay
|
||||
if(delay)
|
||||
program.activated = FALSE
|
||||
. = TRUE
|
||||
if("set_timer")
|
||||
var/timer = input("Set timer in seconds (10-3600):", name, program.timer) as null|num
|
||||
if("set_restart_timer")
|
||||
var/timer = text2num(params["delay"])
|
||||
if(!isnull(timer))
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
if(!timer == 0)
|
||||
timer = CLAMP(round(timer, 1),10,3600)
|
||||
program.timer = timer
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
timer = CLAMP(round(timer, 1), 0, 3600)
|
||||
timer *= 10 //convert to deciseconds
|
||||
program.timer_restart = timer
|
||||
. = TRUE
|
||||
if("set_timer_type")
|
||||
var/new_type = input("Choose the timer effect","Timer Effect") as null|anything in list("Deactivate","Self-Delete","Trigger","Reset Activation Timer")
|
||||
if(new_type)
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
switch(new_type)
|
||||
if("Deactivate")
|
||||
program.timer_type = NANITE_TIMER_DEACTIVATE
|
||||
if("Self-Delete")
|
||||
program.timer_type = NANITE_TIMER_SELFDELETE
|
||||
if("Trigger")
|
||||
program.timer_type = NANITE_TIMER_TRIGGER
|
||||
if("Reset Activation Timer")
|
||||
program.timer_type = NANITE_TIMER_RESET
|
||||
. = TRUE
|
||||
if("set_shutdown_timer")
|
||||
var/timer = text2num(params["delay"])
|
||||
if(!isnull(timer))
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
timer = CLAMP(round(timer, 1), 0, 3600)
|
||||
timer *= 10 //convert to deciseconds
|
||||
program.timer_shutdown = timer
|
||||
. = TRUE
|
||||
if("set_trigger_timer")
|
||||
var/timer = text2num(params["delay"])
|
||||
if(!isnull(timer))
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
timer = CLAMP(round(timer, 1), 0, 3600)
|
||||
timer *= 10 //convert to deciseconds
|
||||
program.timer_trigger = timer
|
||||
. = TRUE
|
||||
if("set_timer_trigger_delay")
|
||||
var/timer = text2num(params["delay"])
|
||||
if(!isnull(timer))
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
timer = CLAMP(round(timer, 1), 0, 3600)
|
||||
timer *= 10 //convert to deciseconds
|
||||
program.timer_trigger_delay = timer
|
||||
. = TRUE
|
||||
|
||||
/obj/machinery/nanite_programmer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
|
||||
. = ..()
|
||||
var/static/regex/when = regex("(?:^\\W*when|when\\W*$)", "i") //starts or ends with when
|
||||
if(findtext(raw_message, when) && !istype(speaker, /obj/machinery/nanite_programmer))
|
||||
say("When you code it!!")
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
var/trigger_cost = 0 //Amount of nanites required to trigger
|
||||
var/trigger_cooldown = 50 //Deciseconds required between each trigger activation
|
||||
var/next_trigger = 0 //World time required for the next trigger activation
|
||||
var/timer_counter = 0 //Counts up while active. Used for the timer and the activation delay.
|
||||
|
||||
var/program_flags = NONE
|
||||
var/passive_enabled = FALSE //If the nanites have an on/off-style effect, it's tracked by this var
|
||||
|
||||
@@ -28,9 +28,17 @@
|
||||
|
||||
//The following vars are customizable
|
||||
var/activated = TRUE //If FALSE, the program won't process, disables passive effects, can't trigger and doesn't consume nanites
|
||||
var/activation_delay = 0 //Seconds before the program self-activates.
|
||||
var/timer = 0 //Seconds before the timer effect activates. Starts counting AFTER the activation delay
|
||||
var/timer_type = NANITE_TIMER_DEACTIVATE //What happens when the timer runs out
|
||||
|
||||
var/timer_restart = 0 //When deactivated, the program will wait X deciseconds before self-reactivating. Also works if the program begins deactivated.
|
||||
var/timer_shutdown = 0 //When activated, the program will wait X deciseconds before self-deactivating. Also works if the program begins activated.
|
||||
var/timer_trigger = 0 //[Trigger only] While active, the program will attempt to trigger once every x deciseconds.
|
||||
var/timer_trigger_delay = 0 //[Trigger only] While active, the program will delay trigger signals by X deciseconds.
|
||||
|
||||
//Indicates the next world.time tick where these timers will act
|
||||
var/timer_restart_next = 0
|
||||
var/timer_shutdown_next = 0
|
||||
var/timer_trigger_next = 0
|
||||
var/timer_trigger_delay_next = 0
|
||||
|
||||
//Signal codes, these handle remote input to the nanites. If set to 0 they'll ignore signals.
|
||||
var/activation_code = 0 //Code that activates the program [1-9999]
|
||||
@@ -39,19 +47,19 @@
|
||||
var/trigger_code = 0 //Code that triggers the program (if available) [1-9999]
|
||||
|
||||
//Extra settings
|
||||
//Must be listed in text form, with the same title they'll be displayed in the programmer UI
|
||||
//Changing these values is handled by set_extra_setting()
|
||||
//Viewing these values is handled by get_extra_setting()
|
||||
//Copying these values is handled by copy_extra_settings_to()
|
||||
///Don't ever override this or I will come to your house and stand menacingly behind a bush
|
||||
var/list/extra_settings = list()
|
||||
|
||||
/datum/nanite_program/triggered
|
||||
use_rate = 0
|
||||
trigger_cost = 5
|
||||
trigger_cooldown = 50
|
||||
can_trigger = TRUE
|
||||
//Rules
|
||||
//Rules that automatically manage if the program's active without requiring separate sensor programs
|
||||
var/list/datum/nanite_rule/rules = list()
|
||||
|
||||
/datum/nanite_program/New()
|
||||
. = ..()
|
||||
register_extra_settings()
|
||||
|
||||
/datum/nanite_program/Destroy()
|
||||
extra_settings = null
|
||||
if(host_mob)
|
||||
if(activated)
|
||||
deactivate()
|
||||
@@ -64,39 +72,60 @@
|
||||
|
||||
/datum/nanite_program/proc/copy()
|
||||
var/datum/nanite_program/new_program = new type()
|
||||
|
||||
new_program.activated = activated
|
||||
new_program.activation_delay = activation_delay
|
||||
new_program.timer = timer
|
||||
new_program.timer_type = timer_type
|
||||
new_program.activation_code = activation_code
|
||||
new_program.deactivation_code = deactivation_code
|
||||
new_program.kill_code = kill_code
|
||||
new_program.trigger_code = trigger_code
|
||||
copy_extra_settings_to(new_program)
|
||||
copy_programming(new_program, TRUE)
|
||||
|
||||
return new_program
|
||||
|
||||
/datum/nanite_program/proc/copy_programming(datum/nanite_program/target, copy_activated = TRUE)
|
||||
if(copy_activated)
|
||||
target.activated = activated
|
||||
target.activation_delay = activation_delay
|
||||
target.timer = timer
|
||||
target.timer_type = timer_type
|
||||
target.timer_restart = timer_restart
|
||||
target.timer_shutdown = timer_shutdown
|
||||
target.timer_trigger = timer_trigger
|
||||
target.timer_trigger_delay = timer_trigger_delay
|
||||
target.activation_code = activation_code
|
||||
target.deactivation_code = deactivation_code
|
||||
target.kill_code = kill_code
|
||||
target.trigger_code = trigger_code
|
||||
copy_extra_settings_to(target)
|
||||
|
||||
/datum/nanite_program/proc/set_extra_setting(user, setting)
|
||||
target.rules = list()
|
||||
for(var/R in rules)
|
||||
var/datum/nanite_rule/rule = R
|
||||
rule.copy_to(target)
|
||||
|
||||
if(istype(target,src))
|
||||
copy_extra_settings_to(target)
|
||||
|
||||
///Register extra settings by overriding this.
|
||||
///extra_settings[name] = new typepath() for each extra setting
|
||||
/datum/nanite_program/proc/register_extra_settings()
|
||||
return
|
||||
|
||||
/datum/nanite_program/proc/get_extra_setting(setting)
|
||||
return
|
||||
///You can override this if you need to have special behavior after setting certain settings.
|
||||
/datum/nanite_program/proc/set_extra_setting(setting, value)
|
||||
var/datum/nanite_extra_setting/ES = extra_settings[setting]
|
||||
return ES.set_value(value)
|
||||
|
||||
///You probably shouldn't be overriding this one, but I'm not a cop.
|
||||
/datum/nanite_program/proc/get_extra_setting_value(setting)
|
||||
var/datum/nanite_extra_setting/ES = extra_settings[setting]
|
||||
return ES.get_value()
|
||||
|
||||
///Used for getting information about the extra settings to the frontend
|
||||
/datum/nanite_program/proc/get_extra_settings_frontend()
|
||||
var/list/out = list()
|
||||
for(var/name in extra_settings)
|
||||
var/datum/nanite_extra_setting/ES = extra_settings[name]
|
||||
out += ES.get_frontend_list(name)
|
||||
return out
|
||||
|
||||
///Copy of the list instead of direct reference for obvious reasons
|
||||
/datum/nanite_program/proc/copy_extra_settings_to(datum/nanite_program/target)
|
||||
return
|
||||
var/list/copy_list = list()
|
||||
for(var/ns_name in extra_settings)
|
||||
var/datum/nanite_extra_setting/extra_setting = extra_settings[ns_name]
|
||||
copy_list[ns_name] = extra_setting.get_copy()
|
||||
target.extra_settings = copy_list
|
||||
|
||||
/datum/nanite_program/proc/on_add(datum/component/nanites/_nanites)
|
||||
nanites = _nanites
|
||||
@@ -105,10 +134,12 @@
|
||||
|
||||
/datum/nanite_program/proc/on_mob_add()
|
||||
host_mob = nanites.host_mob
|
||||
if(activated) //apply activation effects if it starts active
|
||||
if(activated) //apply activation effects depending on initial status; starts the restart and shutdown timers
|
||||
activate()
|
||||
else
|
||||
deactivate()
|
||||
|
||||
datum/nanite_program/proc/on_mob_remove()
|
||||
/datum/nanite_program/proc/on_mob_remove()
|
||||
return
|
||||
|
||||
/datum/nanite_program/proc/toggle()
|
||||
@@ -119,36 +150,35 @@ datum/nanite_program/proc/on_mob_remove()
|
||||
|
||||
/datum/nanite_program/proc/activate()
|
||||
activated = TRUE
|
||||
timer_counter = activation_delay
|
||||
if(timer_shutdown)
|
||||
timer_shutdown_next = world.time + timer_shutdown
|
||||
|
||||
/datum/nanite_program/proc/deactivate()
|
||||
if(passive_enabled)
|
||||
disable_passive_effect()
|
||||
activated = FALSE
|
||||
if(timer_restart)
|
||||
timer_restart_next = world.time + timer_restart
|
||||
|
||||
/datum/nanite_program/proc/on_process()
|
||||
timer_counter++
|
||||
|
||||
if(activation_delay)
|
||||
if(activated && timer_counter < activation_delay)
|
||||
deactivate()
|
||||
else if(!activated && timer_counter >= activation_delay)
|
||||
activate()
|
||||
if(!activated)
|
||||
if(timer_restart_next && world.time > timer_restart_next)
|
||||
activate()
|
||||
timer_restart_next = 0
|
||||
return
|
||||
|
||||
if(timer && timer_counter > timer)
|
||||
if(timer_type == NANITE_TIMER_DEACTIVATE)
|
||||
deactivate()
|
||||
return
|
||||
else if(timer_type == NANITE_TIMER_SELFDELETE)
|
||||
qdel(src)
|
||||
return
|
||||
else if(can_trigger && timer_type == NANITE_TIMER_TRIGGER)
|
||||
trigger()
|
||||
timer_counter = activation_delay
|
||||
else if(timer_type == NANITE_TIMER_RESET)
|
||||
timer_counter = 0
|
||||
if(timer_shutdown_next && world.time > timer_shutdown_next)
|
||||
deactivate()
|
||||
timer_shutdown_next = 0
|
||||
|
||||
if(timer_trigger && world.time > timer_trigger_next)
|
||||
trigger()
|
||||
timer_trigger_next = world.time + timer_trigger
|
||||
|
||||
if(timer_trigger_delay_next && world.time > timer_trigger_delay_next)
|
||||
trigger(delayed = TRUE)
|
||||
timer_trigger_delay_next = 0
|
||||
|
||||
if(check_conditions() && consume_nanites(use_rate))
|
||||
if(!passive_enabled)
|
||||
enable_passive_effect()
|
||||
@@ -160,6 +190,10 @@ datum/nanite_program/proc/on_mob_remove()
|
||||
//If false, disables active and passive effects, but doesn't consume nanites
|
||||
//Can be used to avoid consuming nanites for nothing
|
||||
/datum/nanite_program/proc/check_conditions()
|
||||
for(var/R in rules)
|
||||
var/datum/nanite_rule/rule = R
|
||||
if(!rule.check_rule())
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
//Constantly procs as long as the program is active
|
||||
@@ -174,15 +208,25 @@ datum/nanite_program/proc/on_mob_remove()
|
||||
/datum/nanite_program/proc/disable_passive_effect()
|
||||
passive_enabled = FALSE
|
||||
|
||||
/datum/nanite_program/proc/trigger()
|
||||
//Checks conditions then fires the nanite trigger effect
|
||||
/datum/nanite_program/proc/trigger(delayed = FALSE, comm_message)
|
||||
if(!can_trigger)
|
||||
return
|
||||
if(!activated)
|
||||
return FALSE
|
||||
return
|
||||
if(timer_trigger_delay && !delayed)
|
||||
timer_trigger_delay_next = world.time + timer_trigger_delay
|
||||
return
|
||||
if(world.time < next_trigger)
|
||||
return FALSE
|
||||
return
|
||||
if(!consume_nanites(trigger_cost))
|
||||
return FALSE
|
||||
return
|
||||
next_trigger = world.time + trigger_cooldown
|
||||
return TRUE
|
||||
on_trigger(comm_message)
|
||||
|
||||
//Nanite trigger effect, requires can_trigger to be used
|
||||
/datum/nanite_program/proc/on_trigger(comm_message)
|
||||
return
|
||||
|
||||
/datum/nanite_program/proc/consume_nanites(amount, force = FALSE)
|
||||
return nanites.consume_nanites(amount, force)
|
||||
@@ -234,24 +278,36 @@ datum/nanite_program/proc/on_mob_remove()
|
||||
/datum/nanite_program/proc/receive_signal(code, source)
|
||||
if(activation_code && code == activation_code && !activated)
|
||||
activate()
|
||||
host_mob.investigate_log("[host_mob]'s [name] nanite program was activated by [source] with code [code].", INVESTIGATE_NANITES)
|
||||
host_mob.investigate_log("'s [name] nanite program was activated by [source] with code [code].", INVESTIGATE_NANITES)
|
||||
else if(deactivation_code && code == deactivation_code && activated)
|
||||
deactivate()
|
||||
host_mob.investigate_log("[host_mob]'s [name] nanite program was deactivated by [source] with code [code].", INVESTIGATE_NANITES)
|
||||
if(kill_code && code == kill_code)
|
||||
host_mob.investigate_log("[host_mob]'s [name] nanite program was deleted by [source] with code [code].", INVESTIGATE_NANITES)
|
||||
qdel(src)
|
||||
else if(can_trigger && trigger_code && code == trigger_code)
|
||||
host_mob.investigate_log("'s [name] nanite program was deactivated by [source] with code [code].", INVESTIGATE_NANITES)
|
||||
if(can_trigger && trigger_code && code == trigger_code)
|
||||
trigger()
|
||||
host_mob.investigate_log("[host_mob]'s [name] nanite program was triggered by [source] with code [code].", INVESTIGATE_NANITES)
|
||||
host_mob.investigate_log("'s [name] nanite program was triggered by [source] with code [code].", INVESTIGATE_NANITES)
|
||||
if(kill_code && code == kill_code)
|
||||
host_mob.investigate_log("'s [name] nanite program was deleted by [source] with code [code].", INVESTIGATE_NANITES)
|
||||
qdel(src)
|
||||
|
||||
///A nanite program containing a behaviour protocol. Only one protocol of each class can be active at once.
|
||||
//Currently unused due to us lacking the B.E.P.I.S
|
||||
/datum/nanite_program/protocol
|
||||
name = "Nanite Protocol"
|
||||
var/protocol_class = NONE
|
||||
|
||||
/datum/nanite_program/protocol/check_conditions()
|
||||
. = ..()
|
||||
for(var/protocol in nanites.protocols)
|
||||
var/datum/nanite_program/protocol/P = protocol
|
||||
if(P != src && P.activated && P.protocol_class == protocol_class)
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_program/protocol/on_add(datum/component/nanites/_nanites)
|
||||
..()
|
||||
nanites.protocols += src
|
||||
|
||||
/datum/nanite_program/protocol/Destroy()
|
||||
if(nanites)
|
||||
nanites.protocols -= src
|
||||
return ..()
|
||||
|
||||
/datum/nanite_program/proc/get_timer_type_text()
|
||||
switch(timer_type)
|
||||
if(NANITE_TIMER_DEACTIVATE)
|
||||
return "Deactivate"
|
||||
if(NANITE_TIMER_SELFDELETE)
|
||||
return "Self-Delete"
|
||||
if(NANITE_TIMER_TRIGGER)
|
||||
return "Trigger"
|
||||
if(NANITE_TIMER_RESET)
|
||||
return "Reset Activation Timer"
|
||||
|
||||
@@ -18,23 +18,16 @@
|
||||
var/mob/living/carbon/human/H = host_mob
|
||||
H.physiology.stun_mod *= 2
|
||||
|
||||
/datum/nanite_program/triggered/adrenaline
|
||||
/datum/nanite_program/adrenaline
|
||||
name = "Adrenaline Burst"
|
||||
desc = "The nanites cause a burst of adrenaline when triggered, waking the host from stuns and temporarily increasing their speed."
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 25
|
||||
trigger_cooldown = 1200
|
||||
rogue_types = list(/datum/nanite_program/toxic, /datum/nanite_program/nerve_decay)
|
||||
|
||||
/datum/nanite_program/triggered/adrenaline/trigger()
|
||||
if(!..())
|
||||
return
|
||||
to_chat(host_mob, "<span class='notice'>You feel a sudden surge of energy!</span>")
|
||||
host_mob.SetAllImmobility(0, FALSE)
|
||||
host_mob.SetUnconscious(0, FALSE)
|
||||
host_mob.adjustStaminaLoss(-10) //stimulants give stamina heal now
|
||||
host_mob.set_resting(FALSE, TRUE, FALSE)
|
||||
host_mob.update_mobility()
|
||||
host_mob.reagents.add_reagent(/datum/reagent/medicine/stimulants, 1.5)
|
||||
/datum/nanite_program/adrenaline/on_trigger()
|
||||
host_mob.do_adrenaline(-10, TRUE, TRUE, FALSE, TRUE, list(/datum/reagent/medicine/stimulants = 1.5), "<span class='notice'>You feel a sudden surge of energy!</span>", FALSE, FALSE, FALSE)
|
||||
|
||||
/datum/nanite_program/hardening
|
||||
name = "Dermal Hardening"
|
||||
@@ -119,7 +112,7 @@
|
||||
|
||||
/datum/nanite_program/mindshield/enable_passive_effect()
|
||||
. = ..()
|
||||
if(!host_mob.mind.has_antag_datum(/datum/antagonist/rev)) //won't work if on a rev, to avoid having implanted revs
|
||||
if(!host_mob.mind.has_antag_datum(/datum/antagonist/rev, TRUE)) //won't work if on a rev, to avoid having implanted revs.
|
||||
ADD_TRAIT(host_mob, TRAIT_MINDSHIELD, "nanites")
|
||||
host_mob.sec_hud_set_implants()
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
if(!parts.len)
|
||||
return
|
||||
for(var/obj/item/bodypart/L in parts)
|
||||
if(L.heal_damage(0.5/parts.len, 0.5/parts.len, null, BODYPART_ORGANIC))
|
||||
if(L.heal_damage(0.5/parts.len, 0.5/parts.len))
|
||||
host_mob.update_damage_overlays()
|
||||
else
|
||||
host_mob.adjustBruteLoss(-0.5, TRUE)
|
||||
@@ -48,12 +48,12 @@
|
||||
|
||||
/datum/nanite_program/purging
|
||||
name = "Blood Purification"
|
||||
desc = "The nanites purge toxins and chemicals from the host's bloodstream, however it is dangerous to slimepeople biology due to inaccuracy."
|
||||
desc = "The nanites purge toxins and chemicals from the host's bloodstream, however it is dangerous to slime biology due to inaccuracy."
|
||||
use_rate = 1
|
||||
rogue_types = list(/datum/nanite_program/suffocating, /datum/nanite_program/necrotic)
|
||||
|
||||
/datum/nanite_program/purging/check_conditions()
|
||||
var/foreign_reagent = LAZYLEN(host_mob.reagents.reagent_list)
|
||||
var/foreign_reagent = length(host_mob.reagents?.reagent_list)
|
||||
if(!host_mob.getToxLoss() && !foreign_reagent)
|
||||
return FALSE
|
||||
return ..()
|
||||
@@ -73,18 +73,17 @@
|
||||
rogue_types = list(/datum/nanite_program/brain_decay)
|
||||
|
||||
/datum/nanite_program/brain_heal/check_conditions()
|
||||
var/problems = FALSE
|
||||
if(iscarbon(host_mob))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
for(var/X in C.get_traumas())
|
||||
var/datum/brain_trauma/BT = X
|
||||
if(BT.resilience <= TRAUMA_RESILIENCE_BASIC)
|
||||
return ..()
|
||||
if(host_mob.getOrganLoss(ORGAN_SLOT_BRAIN))
|
||||
return ..()
|
||||
return FALSE
|
||||
if(length(C.get_traumas()))
|
||||
problems = TRUE
|
||||
if(host_mob.getOrganLoss(ORGAN_SLOT_BRAIN) > 0)
|
||||
problems = TRUE
|
||||
return problems ? ..() : FALSE
|
||||
|
||||
/datum/nanite_program/brain_heal/active_effect()
|
||||
host_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, -1, TRUE)
|
||||
host_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, -1)
|
||||
if(iscarbon(host_mob) && prob(10))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
C.cure_trauma_type(resilience = TRAUMA_RESILIENCE_BASIC)
|
||||
@@ -137,7 +136,7 @@
|
||||
return
|
||||
var/update = FALSE
|
||||
for(var/obj/item/bodypart/L in parts)
|
||||
if(L.heal_damage(1.5/parts.len, 1.5/parts.len, null, BODYPART_ROBOTIC)) //much faster than organic healing
|
||||
if(L.heal_damage(1.5/parts.len, 1.5/parts.len, null, TRUE, FALSE)) //much faster than organic healing
|
||||
update = TRUE
|
||||
if(update)
|
||||
host_mob.update_damage_overlays()
|
||||
@@ -148,7 +147,7 @@
|
||||
/datum/nanite_program/purging_advanced
|
||||
name = "Selective Blood Purification"
|
||||
desc = "The nanites purge toxins and dangerous chemicals from the host's bloodstream, while ignoring beneficial chemicals. \
|
||||
The added processing power required to analyze the chemicals severely increases the nanite consumption rate. Due to added complexity, it is safe with slimepeople biology."
|
||||
The added processing power required to analyze the chemicals severely increases the nanite consumption rate. This program is safe with slime biology due to the increased precision."
|
||||
use_rate = 2
|
||||
rogue_types = list(/datum/nanite_program/suffocating, /datum/nanite_program/necrotic)
|
||||
|
||||
@@ -181,7 +180,7 @@
|
||||
return
|
||||
var/update = FALSE
|
||||
for(var/obj/item/bodypart/L in parts)
|
||||
if(L.heal_damage(3/parts.len, 3/parts.len))
|
||||
if(L.heal_damage(3/parts.len, 3/parts.len, FALSE))
|
||||
update = TRUE
|
||||
if(update)
|
||||
host_mob.update_damage_overlays()
|
||||
@@ -196,70 +195,54 @@
|
||||
rogue_types = list(/datum/nanite_program/brain_decay, /datum/nanite_program/brain_misfire)
|
||||
|
||||
/datum/nanite_program/brain_heal_advanced/check_conditions()
|
||||
var/problems = FALSE
|
||||
if(iscarbon(host_mob))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
for(var/X in C.get_traumas())
|
||||
var/datum/brain_trauma/BT = X
|
||||
if(BT.resilience <= TRAUMA_RESILIENCE_LOBOTOMY)
|
||||
return ..()
|
||||
if(host_mob.getOrganLoss(ORGAN_SLOT_BRAIN))
|
||||
return ..()
|
||||
return FALSE
|
||||
if(length(C.get_traumas()))
|
||||
problems = TRUE
|
||||
if(host_mob.getOrganLoss(ORGAN_SLOT_BRAIN) > 0)
|
||||
problems = TRUE
|
||||
return problems ? ..() : FALSE
|
||||
|
||||
/datum/nanite_program/brain_heal_advanced/active_effect()
|
||||
host_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, -2, TRUE)
|
||||
host_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, -2)
|
||||
if(iscarbon(host_mob) && prob(10))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
C.cure_trauma_type(resilience = TRAUMA_RESILIENCE_LOBOTOMY)
|
||||
|
||||
/datum/nanite_program/triggered/defib
|
||||
/datum/nanite_program/defib
|
||||
name = "Defibrillation"
|
||||
desc = "The nanites shock the host's heart when triggered, bringing them back to life if the body can sustain it."
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 25
|
||||
trigger_cooldown = 120
|
||||
rogue_types = list(/datum/nanite_program/triggered/shocking)
|
||||
|
||||
/datum/nanite_program/triggered/defib/trigger()
|
||||
if(!..())
|
||||
return
|
||||
rogue_types = list(/datum/nanite_program/shocking)
|
||||
|
||||
/datum/nanite_program/defib/on_trigger(comm_message)
|
||||
host_mob.notify_ghost_cloning("Your heart is being defibrillated by nanites. Re-enter your corpse if you want to be revived!")
|
||||
addtimer(CALLBACK(src, .proc/zap), 50)
|
||||
|
||||
/datum/nanite_program/triggered/defib/proc/check_revivable()
|
||||
/datum/nanite_program/defib/proc/check_revivable()
|
||||
if(!iscarbon(host_mob)) //nonstandard biology
|
||||
return FALSE
|
||||
var/mob/living/carbon/C = host_mob
|
||||
if(C.suiciding || HAS_TRAIT(C, TRAIT_NOCLONE) || C.hellbound) //can't revive
|
||||
return FALSE
|
||||
if((world.time - C.timeofdeath) > 1800) //too late
|
||||
return FALSE
|
||||
if((C.getBruteLoss() > 180) || (C.getFireLoss() > 180) || !C.can_be_revived()) //too damaged
|
||||
return FALSE
|
||||
if(!C.getorgan(/obj/item/organ/heart)) //what are we even shocking
|
||||
return FALSE
|
||||
var/obj/item/organ/brain/BR = C.getorgan(/obj/item/organ/brain)
|
||||
if(QDELETED(BR) || BR.brain_death || (BR.organ_flags & ORGAN_FAILING) || C.suiciding)
|
||||
return FALSE
|
||||
if(C.get_ghost())
|
||||
return FALSE
|
||||
return TRUE
|
||||
return C.can_defib()
|
||||
|
||||
/datum/nanite_program/triggered/defib/proc/zap()
|
||||
/datum/nanite_program/defib/proc/zap()
|
||||
var/mob/living/carbon/C = host_mob
|
||||
playsound(C, 'sound/machines/defib_charge.ogg', 50, 0)
|
||||
playsound(C, 'sound/machines/defib_charge.ogg', 50, FALSE)
|
||||
sleep(30)
|
||||
playsound(C, 'sound/machines/defib_zap.ogg', 50, 0)
|
||||
playsound(C, 'sound/machines/defib_zap.ogg', 50, FALSE)
|
||||
if(check_revivable())
|
||||
playsound(C, 'sound/machines/defib_success.ogg', 50, 0)
|
||||
playsound(C, 'sound/machines/defib_success.ogg', 50, FALSE)
|
||||
C.set_heartattack(FALSE)
|
||||
C.revive()
|
||||
C.revive(full_heal = FALSE, admin_revive = FALSE)
|
||||
C.emote("gasp")
|
||||
C.Jitter(100)
|
||||
SEND_SIGNAL(C, COMSIG_LIVING_MINOR_SHOCK)
|
||||
var/tplus = world.time - C.timeofdeath
|
||||
if(tplus > 600)
|
||||
C.adjustOrganLoss(ORGAN_SLOT_BRAIN, max(0, ((1800 - tplus) / 1800 * 150)), 150)
|
||||
log_game("[C] has been successfully defibrillated by nanites.")
|
||||
else
|
||||
playsound(C, 'sound/machines/defib_failed.ogg', 50, 0)
|
||||
playsound(C, 'sound/machines/defib_failed.ogg', 50, FALSE)
|
||||
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
//Replication Protocols
|
||||
/datum/nanite_program/protocol/kickstart
|
||||
name = "Kickstart Protocol"
|
||||
desc = "Replication Protocol: the nanites focus on early growth, heavily boosting replication rate for a few minutes after the initial implantation."
|
||||
use_rate = 0
|
||||
rogue_types = list(/datum/nanite_program/necrotic)
|
||||
protocol_class = NANITE_PROTOCOL_REPLICATION
|
||||
var/boost_duration = 1200
|
||||
|
||||
/datum/nanite_program/protocol/kickstart/check_conditions()
|
||||
if(!(world.time < nanites.start_time + boost_duration))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/nanite_program/protocol/kickstart/active_effect()
|
||||
nanites.adjust_nanites(null, 3.5)
|
||||
|
||||
/datum/nanite_program/protocol/factory
|
||||
name = "Factory Protocol"
|
||||
desc = "Replication Protocol: the nanites build a factory matrix within the host, gradually increasing replication speed over time. \
|
||||
The factory decays if the protocol is not active, or if the nanites are disrupted by shocks or EMPs."
|
||||
use_rate = 0
|
||||
rogue_types = list(/datum/nanite_program/necrotic)
|
||||
protocol_class = NANITE_PROTOCOL_REPLICATION
|
||||
var/factory_efficiency = 0
|
||||
var/max_efficiency = 1000 //Goes up to 2 bonus regen per tick after 16 minutes and 40 seconds
|
||||
|
||||
/datum/nanite_program/protocol/factory/on_process()
|
||||
if(!activated || !check_conditions())
|
||||
factory_efficiency = max(0, factory_efficiency - 5)
|
||||
..()
|
||||
|
||||
/datum/nanite_program/protocol/factory/on_emp(severity)
|
||||
..()
|
||||
factory_efficiency = max(0, factory_efficiency - 300)
|
||||
|
||||
/datum/nanite_program/protocol/factory/on_shock(shock_damage)
|
||||
..()
|
||||
factory_efficiency = max(0, factory_efficiency - 200)
|
||||
|
||||
/datum/nanite_program/protocol/factory/on_minor_shock()
|
||||
..()
|
||||
factory_efficiency = max(0, factory_efficiency - 100)
|
||||
|
||||
/datum/nanite_program/protocol/factory/active_effect()
|
||||
factory_efficiency = min(factory_efficiency + 1, max_efficiency)
|
||||
nanites.adjust_nanites(null, round(0.002 * factory_efficiency, 0.1))
|
||||
|
||||
/datum/nanite_program/protocol/tinker
|
||||
name = "Tinker Protocol"
|
||||
desc = "Replication Protocol: the nanites learn to use metallic material in the host's bloodstream to speed up the replication process."
|
||||
use_rate = 0
|
||||
rogue_types = list(/datum/nanite_program/necrotic)
|
||||
protocol_class = NANITE_PROTOCOL_REPLICATION
|
||||
var/boost = 2
|
||||
var/list/valid_reagents = list(
|
||||
/datum/reagent/iron,
|
||||
/datum/reagent/copper,
|
||||
/datum/reagent/gold,
|
||||
/datum/reagent/silver,
|
||||
/datum/reagent/mercury,
|
||||
/datum/reagent/aluminium,
|
||||
/datum/reagent/silicon)
|
||||
|
||||
/datum/nanite_program/protocol/tinker/check_conditions()
|
||||
if(!nanites.host_mob.reagents)
|
||||
return FALSE
|
||||
|
||||
var/found_reagent = FALSE
|
||||
|
||||
var/datum/reagents/R = nanites.host_mob.reagents
|
||||
for(var/VR in valid_reagents)
|
||||
if(R.has_reagent(VR, 0.5))
|
||||
R.remove_reagent(VR, 0.5)
|
||||
found_reagent = TRUE
|
||||
break
|
||||
if(!found_reagent)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/nanite_program/protocol/tinker/active_effect()
|
||||
nanites.adjust_nanites(null, boost)
|
||||
|
||||
/datum/nanite_program/protocol/offline
|
||||
name = "Offline Production Protocol"
|
||||
desc = "Replication Protocol: while the host is asleep or otherwise unconcious, the nanites exploit the reduced interference to replicate more quickly."
|
||||
use_rate = 0
|
||||
rogue_types = list(/datum/nanite_program/necrotic)
|
||||
protocol_class = NANITE_PROTOCOL_REPLICATION
|
||||
var/boost = 3
|
||||
|
||||
/datum/nanite_program/protocol/offline/check_conditions()
|
||||
var/is_offline = FALSE
|
||||
if(nanites.host_mob.IsSleeping() || nanites.host_mob.IsUnconscious())
|
||||
is_offline = TRUE
|
||||
if(nanites.host_mob.stat == DEAD || HAS_TRAIT(nanites.host_mob, TRAIT_DEATHCOMA))
|
||||
is_offline = TRUE
|
||||
if(nanites.host_mob.InCritical() && !HAS_TRAIT(nanites.host_mob, TRAIT_NOSOFTCRIT))
|
||||
is_offline = TRUE
|
||||
if(nanites.host_mob.InFullCritical() && !HAS_TRAIT(nanites.host_mob, TRAIT_NOHARDCRIT))
|
||||
is_offline = TRUE
|
||||
if(!is_offline)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/nanite_program/protocol/offline/active_effect()
|
||||
nanites.adjust_nanites(null, boost)
|
||||
@@ -2,71 +2,41 @@
|
||||
name = "Sensor Nanites"
|
||||
desc = "These nanites send a signal code when a certain condition is met."
|
||||
unique = FALSE
|
||||
extra_settings = list("Sent Code")
|
||||
var/can_rule = FALSE
|
||||
|
||||
var/sent_code = 0
|
||||
|
||||
/datum/nanite_program/sensor/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
|
||||
/datum/nanite_program/sensor/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
|
||||
/datum/nanite_program/sensor/copy_extra_settings_to(datum/nanite_program/sensor/target)
|
||||
target.sent_code = sent_code
|
||||
/datum/nanite_program/sensor/register_extra_settings()
|
||||
extra_settings[NES_SENT_CODE] = new /datum/nanite_extra_setting/number(0, 1, 9999)
|
||||
|
||||
/datum/nanite_program/sensor/proc/check_event()
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_program/sensor/proc/send_code()
|
||||
if(activated)
|
||||
SEND_SIGNAL(host_mob, COMSIG_NANITE_SIGNAL, sent_code, "a [name] program")
|
||||
var/datum/nanite_extra_setting/ES = extra_settings[NES_SENT_CODE]
|
||||
SEND_SIGNAL(host_mob, COMSIG_NANITE_SIGNAL, ES.value, "a [name] program")
|
||||
|
||||
/datum/nanite_program/sensor/active_effect()
|
||||
if(sent_code && check_event())
|
||||
if(check_event())
|
||||
send_code()
|
||||
|
||||
/datum/nanite_program/sensor/proc/make_rule(datum/nanite_program/target)
|
||||
return
|
||||
|
||||
/datum/nanite_program/sensor/repeat
|
||||
name = "Signal Repeater"
|
||||
desc = "When triggered, sends another signal to the nanites, optionally with a delay."
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 0
|
||||
trigger_cooldown = 10
|
||||
extra_settings = list("Sent Code","Delay")
|
||||
var/spent = FALSE
|
||||
var/delay = 0
|
||||
|
||||
/datum/nanite_program/sensor/repeat/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
if(setting == "Delay")
|
||||
var/new_delay = input(user, "Set the delay in seconds:", name, null) as null|num
|
||||
if(isnull(new_delay))
|
||||
return
|
||||
delay = (CLAMP(round(new_delay, 1), 0, 3600)) * 10 //max 1 hour
|
||||
/datum/nanite_program/sensor/repeat/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_DELAY] = new /datum/nanite_extra_setting/number(0, 0, 3600, "s")
|
||||
|
||||
/datum/nanite_program/sensor/repeat/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
if(setting == "Delay")
|
||||
return "[delay/10] seconds"
|
||||
|
||||
/datum/nanite_program/sensor/repeat/copy_extra_settings_to(datum/nanite_program/sensor/repeat/target)
|
||||
target.sent_code = sent_code
|
||||
target.delay = delay
|
||||
|
||||
/datum/nanite_program/sensor/repeat/trigger()
|
||||
if(!..())
|
||||
return
|
||||
addtimer(CALLBACK(src, .proc/send_code), delay)
|
||||
/datum/nanite_program/sensor/repeat/on_trigger(comm_message)
|
||||
var/datum/nanite_extra_setting/ES = extra_settings[NES_DELAY]
|
||||
addtimer(CALLBACK(src, .proc/send_code), ES.get_value() * 10)
|
||||
|
||||
/datum/nanite_program/sensor/relay_repeat
|
||||
name = "Relay Signal Repeater"
|
||||
@@ -74,98 +44,46 @@
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 0
|
||||
trigger_cooldown = 10
|
||||
extra_settings = list("Sent Code","Relay Channel","Delay")
|
||||
var/spent = FALSE
|
||||
var/delay = 0
|
||||
var/relay_channel = 0
|
||||
|
||||
/datum/nanite_program/sensor/relay_repeat/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
if(setting == "Relay Channel")
|
||||
var/new_channel = input(user, "Set the relay channel (1-9999):", name, null) as null|num
|
||||
if(isnull(new_channel))
|
||||
return
|
||||
relay_channel = CLAMP(round(new_channel, 1), 1, 9999)
|
||||
if(setting == "Delay")
|
||||
var/new_delay = input(user, "Set the delay in seconds:", name, null) as null|num
|
||||
if(isnull(new_delay))
|
||||
return
|
||||
delay = (CLAMP(round(new_delay, 1), 0, 3600)) * 10 //max 1 hour
|
||||
/datum/nanite_program/sensor/relay_repeat/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_RELAY_CHANNEL] = new /datum/nanite_extra_setting/number(1, 1, 9999)
|
||||
extra_settings[NES_DELAY] = new /datum/nanite_extra_setting/number(0, 0, 3600, "s")
|
||||
|
||||
/datum/nanite_program/sensor/relay_repeat/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
if(setting == "Relay Channel")
|
||||
return relay_channel
|
||||
if(setting == "Delay")
|
||||
return "[delay/10] seconds"
|
||||
|
||||
/datum/nanite_program/sensor/relay_repeat/copy_extra_settings_to(datum/nanite_program/sensor/relay_repeat/target)
|
||||
target.sent_code = sent_code
|
||||
target.delay = delay
|
||||
target.relay_channel = relay_channel
|
||||
|
||||
/datum/nanite_program/sensor/relay_repeat/trigger()
|
||||
if(!..())
|
||||
return
|
||||
addtimer(CALLBACK(src, .proc/send_code), delay)
|
||||
/datum/nanite_program/sensor/relay_repeat/on_trigger(comm_message)
|
||||
var/datum/nanite_extra_setting/ES = extra_settings[NES_DELAY]
|
||||
addtimer(CALLBACK(src, .proc/send_code), ES.get_value() * 10)
|
||||
|
||||
/datum/nanite_program/sensor/relay_repeat/send_code()
|
||||
if(activated && relay_channel)
|
||||
var/datum/nanite_extra_setting/relay = extra_settings[NES_RELAY_CHANNEL]
|
||||
if(activated && relay.get_value())
|
||||
for(var/X in SSnanites.nanite_relays)
|
||||
var/datum/nanite_program/relay/N = X
|
||||
N.relay_signal(sent_code, relay_channel, "a [name] program")
|
||||
var/datum/nanite_extra_setting/code = extra_settings[NES_SENT_CODE]
|
||||
N.relay_signal(code.get_value(), relay.get_value(), "a [name] program")
|
||||
|
||||
/datum/nanite_program/sensor/health
|
||||
name = "Health Sensor"
|
||||
desc = "The nanites receive a signal when the host's health is above/below a target percentage."
|
||||
extra_settings = list("Sent Code","Health Percent","Direction")
|
||||
can_rule = TRUE
|
||||
var/spent = FALSE
|
||||
var/percent = 50
|
||||
var/direction = "Above"
|
||||
|
||||
/datum/nanite_program/sensor/health/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
if(setting == "Health Percent")
|
||||
var/new_percent = input(user, "Set the health percentage:", name, null) as null|num
|
||||
if(isnull(new_percent))
|
||||
return
|
||||
percent = CLAMP(round(new_percent, 1), -99, 100)
|
||||
if(setting == "Direction")
|
||||
if(direction == "Above")
|
||||
direction = "Below"
|
||||
else
|
||||
direction = "Above"
|
||||
|
||||
/datum/nanite_program/sensor/health/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
if(setting == "Health Percent")
|
||||
return "[percent]%"
|
||||
if(setting == "Direction")
|
||||
return direction
|
||||
|
||||
/datum/nanite_program/sensor/health/copy_extra_settings_to(datum/nanite_program/sensor/health/target)
|
||||
target.sent_code = sent_code
|
||||
target.percent = percent
|
||||
target.direction = direction
|
||||
/datum/nanite_program/sensor/health/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_HEALTH_PERCENT] = new /datum/nanite_extra_setting/number(50, -99, 100, "%")
|
||||
extra_settings[NES_DIRECTION] = new /datum/nanite_extra_setting/boolean(TRUE, "Above", "Below")
|
||||
|
||||
/datum/nanite_program/sensor/health/check_event()
|
||||
var/health_percent = host_mob.health / host_mob.maxHealth * 100
|
||||
var/datum/nanite_extra_setting/percent = extra_settings[NES_HEALTH_PERCENT]
|
||||
var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION]
|
||||
var/detected = FALSE
|
||||
if(direction == "Above")
|
||||
if(health_percent >= percent)
|
||||
if(direction.get_value())
|
||||
if(health_percent >= percent.get_value())
|
||||
detected = TRUE
|
||||
else
|
||||
if(health_percent < percent)
|
||||
if(health_percent < percent.get_value())
|
||||
detected = TRUE
|
||||
|
||||
if(detected)
|
||||
@@ -177,9 +95,18 @@
|
||||
spent = FALSE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_program/sensor/health/make_rule(datum/nanite_program/target)
|
||||
var/datum/nanite_rule/health/rule = new(target)
|
||||
var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION]
|
||||
var/datum/nanite_extra_setting/percent = extra_settings[NES_HEALTH_PERCENT]
|
||||
rule.above = direction.get_value()
|
||||
rule.threshold = percent.get_value()
|
||||
return rule
|
||||
|
||||
/datum/nanite_program/sensor/crit
|
||||
name = "Critical Health Sensor"
|
||||
desc = "The nanites receive a signal when the host first reaches critical health."
|
||||
can_rule = TRUE
|
||||
var/spent = FALSE
|
||||
|
||||
/datum/nanite_program/sensor/crit/check_event()
|
||||
@@ -192,61 +119,44 @@
|
||||
spent = FALSE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_program/sensor/crit/make_rule(datum/nanite_program/target)
|
||||
var/datum/nanite_rule/crit/rule = new(target)
|
||||
return rule
|
||||
|
||||
/datum/nanite_program/sensor/death
|
||||
name = "Death Sensor"
|
||||
desc = "The nanites receive a signal when they detect the host is dead."
|
||||
can_rule = TRUE
|
||||
var/spent = FALSE
|
||||
|
||||
/datum/nanite_program/sensor/death/on_death()
|
||||
send_code()
|
||||
|
||||
/datum/nanite_program/sensor/death/make_rule(datum/nanite_program/target)
|
||||
var/datum/nanite_rule/death/rule = new(target)
|
||||
return rule
|
||||
|
||||
/datum/nanite_program/sensor/nanite_volume
|
||||
name = "Nanite Volume Sensor"
|
||||
desc = "The nanites receive a signal when the nanite supply is above/below a certain percentage."
|
||||
extra_settings = list("Sent Code","Nanite Percent","Direction")
|
||||
can_rule = TRUE
|
||||
var/spent = FALSE
|
||||
var/percent = 50
|
||||
var/direction = "Above"
|
||||
|
||||
/datum/nanite_program/sensor/nanite_volume/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
if(setting == "Nanite Percent")
|
||||
var/new_percent = input(user, "Set the nanite percentage:", name, null) as null|num
|
||||
if(isnull(new_percent))
|
||||
return
|
||||
percent = CLAMP(round(new_percent, 1), 1, 100)
|
||||
if(setting == "Direction")
|
||||
if(direction == "Above")
|
||||
direction = "Below"
|
||||
else
|
||||
direction = "Above"
|
||||
|
||||
/datum/nanite_program/sensor/nanite_volume/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
if(setting == "Nanite Percent")
|
||||
return "[percent]%"
|
||||
if(setting == "Direction")
|
||||
return direction
|
||||
|
||||
/datum/nanite_program/sensor/nanite_volume/copy_extra_settings_to(datum/nanite_program/sensor/nanite_volume/target)
|
||||
target.sent_code = sent_code
|
||||
target.percent = percent
|
||||
target.direction = direction
|
||||
/datum/nanite_program/sensor/nanite_volume/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_NANITE_PERCENT] = new /datum/nanite_extra_setting/number(50, -99, 100, "%")
|
||||
extra_settings[NES_DIRECTION] = new /datum/nanite_extra_setting/boolean(TRUE, "Above", "Below")
|
||||
|
||||
/datum/nanite_program/sensor/nanite_volume/check_event()
|
||||
var/nanite_percent = (nanites.nanite_volume - nanites.safety_threshold)/(nanites.max_nanites - nanites.safety_threshold)*100
|
||||
var/datum/nanite_extra_setting/percent = extra_settings[NES_NANITE_PERCENT]
|
||||
var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION]
|
||||
var/detected = FALSE
|
||||
|
||||
if(direction == "Above")
|
||||
if(nanite_percent >= percent)
|
||||
if(direction.get_value())
|
||||
if(nanite_percent >= percent.get_value())
|
||||
detected = TRUE
|
||||
else
|
||||
if(nanite_percent < percent)
|
||||
if(nanite_percent < percent.get_value())
|
||||
detected = TRUE
|
||||
|
||||
if(detected)
|
||||
@@ -258,75 +168,51 @@
|
||||
spent = FALSE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_program/sensor/nanite_volume/make_rule(datum/nanite_program/target)
|
||||
var/datum/nanite_rule/nanites/rule = new(target)
|
||||
var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION]
|
||||
var/datum/nanite_extra_setting/percent = extra_settings[NES_NANITE_PERCENT]
|
||||
rule.above = direction.get_value()
|
||||
rule.threshold = percent.get_value()
|
||||
return rule
|
||||
|
||||
/datum/nanite_program/sensor/damage
|
||||
name = "Damage Sensor"
|
||||
desc = "The nanites receive a signal when a host's specific damage type is above/below a target value."
|
||||
extra_settings = list("Sent Code","Damage Type","Damage","Direction")
|
||||
can_rule = TRUE
|
||||
var/spent = FALSE
|
||||
var/damage_type = "Brute"
|
||||
var/damage = 50
|
||||
var/direction = "Above"
|
||||
|
||||
/datum/nanite_program/sensor/damage/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
if(setting == "Damage")
|
||||
var/new_damage = input(user, "Set the damage threshold:", name, null) as null|num
|
||||
if(isnull(new_damage))
|
||||
return
|
||||
damage = CLAMP(round(new_damage, 1), 0, 500)
|
||||
if(setting == "Damage Type")
|
||||
var/list/damage_types = list("Brute","Burn","Toxin","Oxygen","Cellular")
|
||||
var/new_damage_type = input("Choose the damage type", name) as null|anything in damage_types
|
||||
if(!new_damage_type)
|
||||
return
|
||||
damage_type = new_damage_type
|
||||
if(setting == "Direction")
|
||||
if(direction == "Above")
|
||||
direction = "Below"
|
||||
else
|
||||
direction = "Above"
|
||||
|
||||
/datum/nanite_program/sensor/damage/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
if(setting == "Damage")
|
||||
return damage
|
||||
if(setting == "Damage Type")
|
||||
return damage_type
|
||||
if(setting == "Direction")
|
||||
return direction
|
||||
|
||||
/datum/nanite_program/sensor/damage/copy_extra_settings_to(datum/nanite_program/sensor/damage/target)
|
||||
target.sent_code = sent_code
|
||||
target.damage = damage
|
||||
target.damage_type = damage_type
|
||||
target.direction = direction
|
||||
/datum/nanite_program/sensor/damage/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_DAMAGE_TYPE] = new /datum/nanite_extra_setting/type(BRUTE, list(BRUTE, BURN, TOX, OXY, CLONE))
|
||||
extra_settings[NES_DAMAGE] = new /datum/nanite_extra_setting/number(50, 0, 500)
|
||||
extra_settings[NES_DIRECTION] = new /datum/nanite_extra_setting/boolean(TRUE, "Above", "Below")
|
||||
|
||||
/datum/nanite_program/sensor/damage/check_event()
|
||||
var/reached_threshold = FALSE
|
||||
var/check_above = (direction == "Above")
|
||||
var/datum/nanite_extra_setting/type = extra_settings[NES_DAMAGE_TYPE]
|
||||
var/datum/nanite_extra_setting/damage = extra_settings[NES_DAMAGE]
|
||||
var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION]
|
||||
var/check_above = direction.get_value()
|
||||
var/damage_amt = 0
|
||||
switch(damage_type)
|
||||
if("Brute")
|
||||
switch(type.get_value())
|
||||
if(BRUTE)
|
||||
damage_amt = host_mob.getBruteLoss()
|
||||
if("Burn")
|
||||
if(BURN)
|
||||
damage_amt = host_mob.getFireLoss()
|
||||
if("Toxin")
|
||||
if(TOX)
|
||||
damage_amt = host_mob.getToxLoss()
|
||||
if("Oxygen")
|
||||
if(OXY)
|
||||
damage_amt = host_mob.getOxyLoss()
|
||||
if("Cellular")
|
||||
if(CLONE)
|
||||
damage_amt = host_mob.getCloneLoss()
|
||||
|
||||
if(damage_amt >= damage)
|
||||
if(check_above)
|
||||
if(check_above)
|
||||
if(damage_amt >= damage.get_value())
|
||||
reached_threshold = TRUE
|
||||
else
|
||||
if(damage_amt < damage.get_value())
|
||||
reached_threshold = TRUE
|
||||
else if(!check_above)
|
||||
reached_threshold = TRUE
|
||||
|
||||
if(reached_threshold)
|
||||
if(!spent)
|
||||
@@ -337,14 +223,25 @@
|
||||
spent = FALSE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_program/sensor/damage/make_rule(datum/nanite_program/target)
|
||||
var/datum/nanite_rule/damage/rule = new(target)
|
||||
var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION]
|
||||
var/datum/nanite_extra_setting/damage_type = extra_settings[NES_DAMAGE_TYPE]
|
||||
var/datum/nanite_extra_setting/damage = extra_settings[NES_DAMAGE]
|
||||
rule.above = direction.get_value()
|
||||
rule.threshold = damage.get_value()
|
||||
rule.damage_type = damage_type.get_value()
|
||||
return rule
|
||||
|
||||
/datum/nanite_program/sensor/voice
|
||||
name = "Voice Sensor"
|
||||
desc = "Sends a signal when the nanites hear a determined word or sentence."
|
||||
extra_settings = list("Sent Code","Sentence","Inclusive Mode")
|
||||
var/spent = FALSE
|
||||
var/sentence = ""
|
||||
var/inclusive = TRUE
|
||||
|
||||
/datum/nanite_program/sensor/voice/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_SENTENCE] = new /datum/nanite_extra_setting/text("")
|
||||
extra_settings[NES_INCLUSIVE_MODE] = new /datum/nanite_extra_setting/boolean(TRUE, "Inclusive", "Exclusive")
|
||||
|
||||
/datum/nanite_program/sensor/voice/on_mob_add()
|
||||
. = ..()
|
||||
@@ -353,45 +250,14 @@
|
||||
/datum/nanite_program/sensor/voice/on_mob_remove()
|
||||
UnregisterSignal(host_mob, COMSIG_MOVABLE_HEAR, .proc/on_hear)
|
||||
|
||||
/datum/nanite_program/sensor/voice/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
if(setting == "Sentence")
|
||||
var/new_sentence = stripped_input(user, "Choose the sentence that triggers the sensor.", "Sentence", sentence, MAX_MESSAGE_LEN)
|
||||
if(!new_sentence)
|
||||
return
|
||||
sentence = new_sentence
|
||||
if(setting == "Inclusive Mode")
|
||||
var/new_inclusive = input("Should the sensor detect the sentence if contained within another sentence?", name) as null|anything in list("Inclusive","Exclusive")
|
||||
if(!new_inclusive)
|
||||
return
|
||||
inclusive = (new_inclusive == "Inclusive")
|
||||
|
||||
/datum/nanite_program/sensor/voice/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
if(setting == "Sentence")
|
||||
return sentence
|
||||
if(setting == "Inclusive Mode")
|
||||
if(inclusive)
|
||||
return "Inclusive"
|
||||
else
|
||||
return "Exclusive"
|
||||
|
||||
/datum/nanite_program/sensor/voice/copy_extra_settings_to(datum/nanite_program/sensor/voice/target)
|
||||
target.sent_code = sent_code
|
||||
target.sentence = sentence
|
||||
target.inclusive = inclusive
|
||||
|
||||
/datum/nanite_program/sensor/voice/proc/on_hear(datum/source, list/hearing_args)
|
||||
if(!sentence)
|
||||
var/datum/nanite_extra_setting/sentence = extra_settings[NES_SENTENCE]
|
||||
var/datum/nanite_extra_setting/inclusive = extra_settings[NES_INCLUSIVE_MODE]
|
||||
if(!sentence.get_value())
|
||||
return
|
||||
if(inclusive)
|
||||
if(inclusive.get_value())
|
||||
if(findtextEx(hearing_args[HEARING_RAW_MESSAGE], sentence))
|
||||
send_code()
|
||||
else
|
||||
if(hearing_args[HEARING_RAW_MESSAGE] == sentence)
|
||||
send_code()
|
||||
send_code()
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
//Programs that are generally useful for population control and non-harmful suppression.
|
||||
|
||||
/datum/nanite_program/triggered/sleepy
|
||||
/datum/nanite_program/sleepy
|
||||
name = "Sleep Induction"
|
||||
desc = "The nanites cause rapid narcolepsy when triggered."
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 15
|
||||
trigger_cooldown = 1200
|
||||
rogue_types = list(/datum/nanite_program/brain_misfire, /datum/nanite_program/brain_decay)
|
||||
|
||||
/datum/nanite_program/triggered/sleepy/trigger()
|
||||
if(!..())
|
||||
return
|
||||
/datum/nanite_program/sleepy/on_trigger(comm_message)
|
||||
to_chat(host_mob, "<span class='warning'>You start to feel very sleepy...</span>")
|
||||
host_mob.drowsyness += 20
|
||||
addtimer(CALLBACK(host_mob, /mob/living.proc/Sleeping, 200), rand(60,200))
|
||||
@@ -31,31 +30,31 @@
|
||||
. = ..()
|
||||
to_chat(host_mob, "<span class='notice'>Your muscles relax, and you can move again.</span>")
|
||||
|
||||
/datum/nanite_program/triggered/shocking
|
||||
/datum/nanite_program/shocking
|
||||
name = "Electric Shock"
|
||||
desc = "The nanites shock the host when triggered. Destroys a large amount of nanites!"
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 10
|
||||
trigger_cooldown = 300
|
||||
program_flags = NANITE_SHOCK_IMMUNE
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
|
||||
/datum/nanite_program/triggered/shocking/trigger()
|
||||
if(!..())
|
||||
return
|
||||
/datum/nanite_program/shocking/on_trigger(comm_message)
|
||||
host_mob.electrocute_act(rand(5,10), "shock nanites", TRUE, TRUE)
|
||||
|
||||
/datum/nanite_program/triggered/stun
|
||||
/datum/nanite_program/stun
|
||||
name = "Neural Shock"
|
||||
desc = "The nanites pulse the host's nerves when triggered, inapacitating them for a short period."
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 4
|
||||
trigger_cooldown = 300
|
||||
rogue_types = list(/datum/nanite_program/triggered/shocking, /datum/nanite_program/nerve_decay)
|
||||
rogue_types = list(/datum/nanite_program/shocking, /datum/nanite_program/nerve_decay)
|
||||
|
||||
/datum/nanite_program/triggered/stun/trigger()
|
||||
if(!..())
|
||||
return
|
||||
playsound(host_mob, "sparks", 75, 1, -1)
|
||||
host_mob.DefaultCombatKnockdown(80)
|
||||
playsound(host_mob, "sparks", 75, TRUE, -1)
|
||||
|
||||
/datum/nanite_program/pacifying
|
||||
name = "Pacification"
|
||||
@@ -115,64 +114,50 @@
|
||||
host_mob.cure_fakedeath("nanites")
|
||||
|
||||
//Can receive transmissions from a nanite communication remote for customized messages
|
||||
/datum/nanite_program/triggered/comm
|
||||
/datum/nanite_program/comm
|
||||
can_trigger = TRUE
|
||||
var/comm_code = 0
|
||||
var/comm_message = ""
|
||||
|
||||
/datum/nanite_program/triggered/comm/proc/receive_comm_signal(signal_comm_code, comm_message, comm_source)
|
||||
/datum/nanite_program/comm/register_extra_settings()
|
||||
extra_settings[NES_COMM_CODE] = new /datum/nanite_extra_setting/number(0, 0, 9999)
|
||||
|
||||
/datum/nanite_program/comm/proc/receive_comm_signal(signal_comm_code, comm_message, comm_source)
|
||||
if(!activated || !comm_code)
|
||||
return
|
||||
if(signal_comm_code == comm_code)
|
||||
host_mob.investigate_log("'s [name] nanite program was messaged by [comm_source] with comm code [signal_comm_code] and message '[comm_message]'.", INVESTIGATE_NANITES)
|
||||
trigger(comm_message)
|
||||
|
||||
/datum/nanite_program/triggered/comm/speech
|
||||
/datum/nanite_program/comm/speech
|
||||
name = "Forced Speech"
|
||||
desc = "The nanites force the host to say a pre-programmed sentence when triggered."
|
||||
unique = FALSE
|
||||
trigger_cost = 3
|
||||
trigger_cooldown = 20
|
||||
rogue_types = list(/datum/nanite_program/brain_misfire, /datum/nanite_program/brain_decay)
|
||||
var/static/list/blacklist = list(
|
||||
"*surrender",
|
||||
"*collapse"
|
||||
)
|
||||
|
||||
extra_settings = list("Sentence","Comm Code")
|
||||
var/sentence = ""
|
||||
/datum/nanite_program/comm/speech/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_SENTENCE] = new /datum/nanite_extra_setting/text("")
|
||||
|
||||
/datum/nanite_program/triggered/comm/speech/set_extra_setting(user, setting)
|
||||
if(setting == "Sentence")
|
||||
var/new_sentence = stripped_input(user, "Choose the sentence that the host will be forced to say.", "Sentence", sentence, MAX_MESSAGE_LEN)
|
||||
if(!new_sentence)
|
||||
return
|
||||
if(new_sentence[1] == "*") //emotes are abusable, like surrender
|
||||
return
|
||||
sentence = new_sentence
|
||||
if(setting == "Comm Code")
|
||||
var/new_code = input(user, "Set the communication code (1-9999) or set to 0 to disable external signals.", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
comm_code = CLAMP(round(new_code, 1), 0, 9999)
|
||||
|
||||
/datum/nanite_program/triggered/comm/speech/get_extra_setting(setting)
|
||||
if(setting == "Sentence")
|
||||
return sentence
|
||||
if(setting == "Comm Code")
|
||||
return comm_code
|
||||
|
||||
/datum/nanite_program/triggered/comm/speech/copy_extra_settings_to(datum/nanite_program/triggered/comm/speech/target)
|
||||
target.sentence = sentence
|
||||
target.comm_code = comm_code
|
||||
|
||||
/datum/nanite_program/triggered/comm/speech/trigger(comm_message)
|
||||
if(!..())
|
||||
return
|
||||
/datum/nanite_program/comm/speech/on_trigger(comm_message)
|
||||
var/sent_message = comm_message
|
||||
if(!comm_message)
|
||||
sent_message = sentence
|
||||
var/datum/nanite_extra_setting/sentence = extra_settings[NES_SENTENCE]
|
||||
sent_message = sentence.get_value()
|
||||
if(sent_message in blacklist)
|
||||
return
|
||||
if(host_mob.stat == DEAD)
|
||||
return
|
||||
to_chat(host_mob, "<span class='warning'>You feel compelled to speak...</span>")
|
||||
host_mob.say(sent_message, forced = "nanite speech")
|
||||
|
||||
/datum/nanite_program/triggered/comm/voice
|
||||
/datum/nanite_program/comm/voice
|
||||
name = "Skull Echo"
|
||||
desc = "The nanites echo a synthesized message inside the host's skull."
|
||||
unique = FALSE
|
||||
@@ -180,56 +165,50 @@
|
||||
trigger_cooldown = 20
|
||||
rogue_types = list(/datum/nanite_program/brain_misfire, /datum/nanite_program/brain_decay)
|
||||
|
||||
extra_settings = list("Message","Comm Code")
|
||||
var/message = ""
|
||||
/datum/nanite_program/comm/voice/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_MESSAGE] = new /datum/nanite_extra_setting/text("")
|
||||
|
||||
/datum/nanite_program/triggered/comm/voice/set_extra_setting(user, setting)
|
||||
if(setting == "Message")
|
||||
var/new_message = stripped_input(user, "Choose the message sent to the host.", "Message", message, MAX_MESSAGE_LEN)
|
||||
if(!new_message)
|
||||
return
|
||||
message = new_message
|
||||
if(setting == "Comm Code")
|
||||
var/new_code = input(user, "Set the communication code (1-9999) or set to 0 to disable external signals.", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
comm_code = CLAMP(round(new_code, 1), 0, 9999)
|
||||
|
||||
/datum/nanite_program/triggered/comm/voice/get_extra_setting(setting)
|
||||
if(setting == "Message")
|
||||
return message
|
||||
if(setting == "Comm Code")
|
||||
return comm_code
|
||||
|
||||
/datum/nanite_program/triggered/comm/voice/copy_extra_settings_to(datum/nanite_program/triggered/comm/voice/target)
|
||||
target.message = message
|
||||
target.comm_code = comm_code
|
||||
|
||||
/datum/nanite_program/triggered/comm/voice/trigger(comm_message)
|
||||
if(!..())
|
||||
return
|
||||
/datum/nanite_program/comm/voice/on_trigger(comm_message)
|
||||
var/sent_message = comm_message
|
||||
if(!comm_message)
|
||||
sent_message = message
|
||||
var/datum/nanite_extra_setting/message_setting = extra_settings[NES_MESSAGE]
|
||||
sent_message = message_setting.get_value()
|
||||
if(host_mob.stat == DEAD)
|
||||
return
|
||||
to_chat(host_mob, "<i>You hear a strange, robotic voice in your head...</i> \"<span class='robot'>[sent_message]</span>\"")
|
||||
|
||||
/datum/nanite_program/triggered/comm/hallucination
|
||||
/datum/nanite_program/comm/hallucination
|
||||
name = "Hallucination"
|
||||
desc = "The nanites make the host hallucinate something when triggered."
|
||||
trigger_cost = 4
|
||||
trigger_cooldown = 80
|
||||
unique = FALSE
|
||||
rogue_types = list(/datum/nanite_program/brain_misfire)
|
||||
extra_settings = list("Hallucination Type", "Comm Code")
|
||||
var/hal_type
|
||||
var/hal_details
|
||||
|
||||
/datum/nanite_program/triggered/comm/hallucination/trigger(comm_message)
|
||||
if(!..())
|
||||
return
|
||||
/datum/nanite_program/comm/hallucination/register_extra_settings()
|
||||
. = ..()
|
||||
var/list/options = list(
|
||||
"Message",
|
||||
"Battle",
|
||||
"Sound",
|
||||
"Weird Sound",
|
||||
"Station Message",
|
||||
"Health",
|
||||
"Alert",
|
||||
"Fire",
|
||||
"Shock",
|
||||
"Plasma Flood",
|
||||
"Random"
|
||||
)
|
||||
extra_settings[NES_HALLUCINATION_TYPE] = new /datum/nanite_extra_setting/type("Message", options)
|
||||
extra_settings[NES_HALLUCINATION_DETAIL] = new /datum/nanite_extra_setting/text("")
|
||||
|
||||
/datum/nanite_program/comm/hallucination/on_trigger(comm_message)
|
||||
var/datum/nanite_extra_setting/hal_setting = extra_settings[NES_HALLUCINATION_TYPE]
|
||||
var/hal_type = hal_setting.get_value()
|
||||
var/datum/nanite_extra_setting/hal_detail_setting = extra_settings[NES_HALLUCINATION_DETAIL]
|
||||
var/hal_details = hal_detail_setting.get_value()
|
||||
if(comm_message && (hal_type != "Message")) //Triggered via comm remote, but not set to a message hallucination
|
||||
return
|
||||
var/sent_message = comm_message //Comm remotes can send custom hallucination messages for the chat hallucination
|
||||
@@ -239,7 +218,9 @@
|
||||
if(!iscarbon(host_mob))
|
||||
return
|
||||
var/mob/living/carbon/C = host_mob
|
||||
if(!hal_type)
|
||||
if(hal_details == "random")
|
||||
hal_details = null
|
||||
if(hal_type == "Random")
|
||||
C.hallucination += 15
|
||||
else
|
||||
switch(hal_type)
|
||||
@@ -254,6 +235,13 @@
|
||||
if("Station Message")
|
||||
new /datum/hallucination/stationmessage(C, TRUE, hal_details)
|
||||
if("Health")
|
||||
switch(hal_details)
|
||||
if("critical")
|
||||
hal_details = SCREWYHUD_CRIT
|
||||
if("dead")
|
||||
hal_details = SCREWYHUD_DEAD
|
||||
if("healthy")
|
||||
hal_details = SCREWYHUD_HEALTHY
|
||||
new /datum/hallucination/hudscrew(C, TRUE, hal_details)
|
||||
if("Alert")
|
||||
new /datum/hallucination/fake_alert(C, TRUE, hal_details)
|
||||
@@ -264,127 +252,40 @@
|
||||
if("Plasma Flood")
|
||||
new /datum/hallucination/fake_flood(C, TRUE)
|
||||
|
||||
/datum/nanite_program/triggered/comm/hallucination/set_extra_setting(user, setting)
|
||||
if(setting == "Comm Code")
|
||||
var/new_code = input(user, "(Only for Message) Set the communication code (1-9999) or set to 0 to disable external signals.", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
comm_code = CLAMP(round(new_code, 1), 0, 9999)
|
||||
|
||||
if(setting == "Hallucination Type")
|
||||
var/list/possible_hallucinations = list("Random","Message","Battle","Sound","Weird Sound","Station Message","Health","Alert","Fire","Shock","Plasma Flood")
|
||||
var/hal_type_choice = input("Choose the hallucination type", name) as null|anything in possible_hallucinations
|
||||
if(!hal_type_choice)
|
||||
return
|
||||
switch(hal_type_choice)
|
||||
if("Random")
|
||||
hal_type = null
|
||||
hal_details = null
|
||||
/datum/nanite_program/comm/hallucination/set_extra_setting(setting, value)
|
||||
. = ..()
|
||||
if(setting == NES_HALLUCINATION_TYPE)
|
||||
switch(value)
|
||||
if("Message")
|
||||
hal_type = "Message"
|
||||
var/hal_chat = stripped_input(user, "Choose the message the host will hear, or leave empty for random messages.", "Message", hal_details, MAX_MESSAGE_LEN)
|
||||
if(hal_chat)
|
||||
hal_details = hal_chat
|
||||
extra_settings[NES_HALLUCINATION_DETAIL] = new /datum/nanite_extra_setting/text("")
|
||||
if("Battle")
|
||||
hal_type = "Battle"
|
||||
var/sound_list = list("random","laser","disabler","esword","gun","stunprod","harmbaton","bomb")
|
||||
var/hal_choice = input("Choose the hallucination battle type", name) as null|anything in sound_list
|
||||
if(!hal_choice || hal_choice == "random")
|
||||
hal_details = null
|
||||
else
|
||||
hal_details = hal_choice
|
||||
extra_settings[NES_HALLUCINATION_DETAIL] = new /datum/nanite_extra_setting/type("random", list("random","laser","disabler","esword","gun","stunprod","harmbaton","bomb"))
|
||||
if("Sound")
|
||||
hal_type = "Sound"
|
||||
var/sound_list = list("random","airlock","airlock pry","console","explosion","far explosion","mech","glass","alarm","beepsky","mech","wall decon","door hack")
|
||||
var/hal_choice = input("Choose the hallucination sound", name) as null|anything in sound_list
|
||||
if(!hal_choice || hal_choice == "random")
|
||||
hal_details = null
|
||||
else
|
||||
hal_details = hal_choice
|
||||
extra_settings[NES_HALLUCINATION_DETAIL] = new /datum/nanite_extra_setting/type("random", list("random","airlock","airlock pry","console","explosion","far explosion","mech","glass","alarm","beepsky","mech","wall decon","door hack"))
|
||||
if("Weird Sound")
|
||||
hal_type = "Weird Sound"
|
||||
var/sound_list = list("random","phone","hallelujah","highlander","laughter","hyperspace","game over","creepy","tesla")
|
||||
var/hal_choice = input("Choose the hallucination sound", name) as null|anything in sound_list
|
||||
if(!hal_choice || hal_choice == "random")
|
||||
hal_details = null
|
||||
else
|
||||
hal_details = hal_choice
|
||||
extra_settings[NES_HALLUCINATION_DETAIL] = new /datum/nanite_extra_setting/type("random", list("random","phone","hallelujah","highlander","laughter","hyperspace","game over","creepy","tesla"))
|
||||
if("Station Message")
|
||||
hal_type = "Station Message"
|
||||
var/msg_list = list("random","ratvar","shuttle dock","blob alert","malf ai","meteors","supermatter")
|
||||
var/hal_choice = input("Choose the hallucination station message", name) as null|anything in msg_list
|
||||
if(!hal_choice || hal_choice == "random")
|
||||
hal_details = null
|
||||
else
|
||||
hal_details = hal_choice
|
||||
extra_settings[NES_HALLUCINATION_DETAIL] = new /datum/nanite_extra_setting/type("random", list("random","ratvar","shuttle dock","blob alert","malf ai","meteors","supermatter"))
|
||||
if("Health")
|
||||
hal_type = "Health"
|
||||
var/health_list = list("random","critical","dead","healthy")
|
||||
var/hal_choice = input("Choose the health status", name) as null|anything in health_list
|
||||
if(!hal_choice || hal_choice == "random")
|
||||
hal_details = null
|
||||
else
|
||||
switch(hal_choice)
|
||||
if("critical")
|
||||
hal_details = SCREWYHUD_CRIT
|
||||
if("dead")
|
||||
hal_details = SCREWYHUD_DEAD
|
||||
if("healthy")
|
||||
hal_details = SCREWYHUD_HEALTHY
|
||||
extra_settings[NES_HALLUCINATION_DETAIL] = new /datum/nanite_extra_setting/type("random", list("random","critical","dead","healthy"))
|
||||
if("Alert")
|
||||
hal_type = "Alert"
|
||||
var/alert_list = list("random","not_enough_oxy","not_enough_tox","not_enough_co2","too_much_oxy","too_much_co2","too_much_tox","newlaw","nutrition","charge","gravity","fire","locked","hacked","temphot","tempcold","pressure")
|
||||
var/hal_choice = input("Choose the alert", name) as null|anything in alert_list
|
||||
if(!hal_choice || hal_choice == "random")
|
||||
hal_details = null
|
||||
else
|
||||
hal_details = hal_choice
|
||||
if("Fire")
|
||||
hal_type = "Fire"
|
||||
if("Shock")
|
||||
hal_type = "Shock"
|
||||
if("Plasma Flood")
|
||||
hal_type = "Plasma Flood"
|
||||
|
||||
/datum/nanite_program/triggered/comm/hallucination/get_extra_setting(setting)
|
||||
if(setting == "Hallucination Type")
|
||||
if(!hal_type)
|
||||
return "Random"
|
||||
else
|
||||
return hal_type
|
||||
if(setting == "Comm Code")
|
||||
return comm_code
|
||||
|
||||
/datum/nanite_program/triggered/comm/hallucination/copy_extra_settings_to(datum/nanite_program/triggered/comm/hallucination/target)
|
||||
target.hal_type = hal_type
|
||||
target.hal_details = hal_details
|
||||
target.comm_code = comm_code
|
||||
extra_settings[NES_HALLUCINATION_DETAIL] = new /datum/nanite_extra_setting/type("random", list("random","not_enough_oxy","not_enough_tox","not_enough_co2","too_much_oxy","too_much_co2","too_much_tox","newlaw","nutrition","charge","gravity","fire","locked","hacked","temphot","tempcold","pressure"))
|
||||
else
|
||||
extra_settings.Remove(NES_HALLUCINATION_DETAIL)
|
||||
|
||||
/datum/nanite_program/good_mood
|
||||
name = "Happiness Enhancer"
|
||||
desc = "The nanites synthesize serotonin inside the host's brain, creating an artificial sense of happiness."
|
||||
use_rate = 0.1
|
||||
rogue_types = list(/datum/nanite_program/brain_decay)
|
||||
extra_settings = list("Mood Message")
|
||||
var/message = "HAPPINESS ENHANCEMENT"
|
||||
|
||||
/datum/nanite_program/good_mood/set_extra_setting(user, setting)
|
||||
if(setting == "Mood Message")
|
||||
var/new_message = stripped_input(user, "Choose the message visible on the mood effect.", "Message", message, MAX_NAME_LEN)
|
||||
if(!new_message)
|
||||
return
|
||||
message = new_message
|
||||
|
||||
/datum/nanite_program/good_mood/get_extra_setting(setting)
|
||||
if(setting == "Mood Message")
|
||||
return message
|
||||
|
||||
/datum/nanite_program/good_mood/copy_extra_settings_to(datum/nanite_program/good_mood/target)
|
||||
target.message = message
|
||||
/datum/nanite_program/good_mood/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_MOOD_MESSAGE] = new /datum/nanite_extra_setting/text("HAPPINESS ENHANCEMENT")
|
||||
|
||||
/datum/nanite_program/good_mood/enable_passive_effect()
|
||||
. = ..()
|
||||
SEND_SIGNAL(host_mob, COMSIG_ADD_MOOD_EVENT, "nanite_happy", /datum/mood_event/nanite_happiness, message)
|
||||
SEND_SIGNAL(host_mob, COMSIG_ADD_MOOD_EVENT, "nanite_happy", /datum/mood_event/nanite_happiness, get_extra_setting_value(NES_MOOD_MESSAGE))
|
||||
|
||||
/datum/nanite_program/good_mood/disable_passive_effect()
|
||||
. = ..()
|
||||
@@ -395,26 +296,14 @@
|
||||
desc = "The nanites suppress the production of serotonin inside the host's brain, creating an artificial state of depression."
|
||||
use_rate = 0.1
|
||||
rogue_types = list(/datum/nanite_program/brain_decay)
|
||||
extra_settings = list("Mood Message")
|
||||
var/message = "HAPPINESS SUPPRESSION"
|
||||
|
||||
/datum/nanite_program/bad_mood/set_extra_setting(user, setting)
|
||||
if(setting == "Mood Message")
|
||||
var/new_message = stripped_input(user, "Choose the message visible on the mood effect.", "Message", message, MAX_NAME_LEN)
|
||||
if(!new_message)
|
||||
return
|
||||
message = new_message
|
||||
|
||||
/datum/nanite_program/bad_mood/get_extra_setting(setting)
|
||||
if(setting == "Mood Message")
|
||||
return message
|
||||
|
||||
/datum/nanite_program/bad_mood/copy_extra_settings_to(datum/nanite_program/bad_mood/target)
|
||||
target.message = message
|
||||
/datum/nanite_program/bad_mood/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_MOOD_MESSAGE] = new /datum/nanite_extra_setting/text("HAPPINESS SUPPRESSION")
|
||||
|
||||
/datum/nanite_program/bad_mood/enable_passive_effect()
|
||||
. = ..()
|
||||
SEND_SIGNAL(host_mob, COMSIG_ADD_MOOD_EVENT, "nanite_sadness", /datum/mood_event/nanite_sadness, message)
|
||||
SEND_SIGNAL(host_mob, COMSIG_ADD_MOOD_EVENT, "nanite_sadness", /datum/mood_event/nanite_sadness, get_extra_setting_value(NES_MOOD_MESSAGE))
|
||||
|
||||
/datum/nanite_program/bad_mood/disable_passive_effect()
|
||||
. = ..()
|
||||
|
||||
@@ -1,82 +1,29 @@
|
||||
//Programs that interact with other programs or nanites directly, or have other special purposes.
|
||||
/datum/nanite_program/viral
|
||||
name = "Viral Replica"
|
||||
desc = "The nanites constantly send encrypted signals attempting to forcefully copy their own programming into other nanite clusters."
|
||||
desc = "The nanites constantly send encrypted signals attempting to forcefully copy their own programming into other nanite clusters, also overriding or disabling their cloud sync."
|
||||
use_rate = 0.5
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
extra_settings = list("Program Overwrite","Cloud Overwrite")
|
||||
|
||||
var/pulse_cooldown = 0
|
||||
var/sync_programs = TRUE
|
||||
var/sync_overwrite = FALSE
|
||||
var/overwrite_cloud = FALSE
|
||||
var/set_cloud = 0
|
||||
|
||||
/datum/nanite_program/viral/set_extra_setting(user, setting)
|
||||
if(setting == "Program Overwrite")
|
||||
var/overwrite_type = input("Choose what to do with the target's programs", name) as null|anything in list("Overwrite","Add To","Ignore")
|
||||
if(!overwrite_type)
|
||||
return
|
||||
switch(overwrite_type)
|
||||
if("Ignore") //Do not affect programs (if you only want to set the cloud ID)
|
||||
sync_programs = FALSE
|
||||
sync_overwrite = FALSE
|
||||
if("Add To") //Add to existing programs (so the target does not notice theirs are missing)
|
||||
sync_programs = TRUE
|
||||
sync_overwrite = FALSE
|
||||
if("Overwrite") //Replace target's programs with the source
|
||||
sync_programs = TRUE
|
||||
sync_overwrite = TRUE
|
||||
if(setting == "Cloud Overwrite")
|
||||
var/overwrite_type = input("Choose what to do with the target's Cloud ID", name) as null|anything in list("Overwrite","Disable","Keep")
|
||||
if(!overwrite_type)
|
||||
return
|
||||
switch(overwrite_type)
|
||||
if("Keep") //Don't change the cloud ID
|
||||
overwrite_cloud = FALSE
|
||||
set_cloud = 0
|
||||
if("Disable") //Set the cloud ID to disabled
|
||||
overwrite_cloud = TRUE
|
||||
set_cloud = 0
|
||||
if("Overwrite") //Set the cloud ID to what we choose
|
||||
var/new_cloud = input(user, "Choose the Cloud ID to set on infected nanites (1-100)", name, null) as null|num
|
||||
if(isnull(new_cloud))
|
||||
return
|
||||
overwrite_cloud = TRUE
|
||||
set_cloud = CLAMP(round(new_cloud, 1), 1, 100)
|
||||
|
||||
/datum/nanite_program/viral/get_extra_setting(setting)
|
||||
if(setting == "Program Overwrite")
|
||||
if(!sync_programs)
|
||||
return "Ignore"
|
||||
else if(sync_overwrite)
|
||||
return "Overwrite"
|
||||
else
|
||||
return "Add To"
|
||||
if(setting == "Cloud Overwrite")
|
||||
if(!overwrite_cloud)
|
||||
return "None"
|
||||
else if(set_cloud == 0)
|
||||
return "Disable"
|
||||
else
|
||||
return set_cloud
|
||||
|
||||
/datum/nanite_program/viral/copy_extra_settings_to(datum/nanite_program/viral/target)
|
||||
target.overwrite_cloud = overwrite_cloud
|
||||
target.set_cloud = set_cloud
|
||||
target.sync_programs = sync_programs
|
||||
target.sync_overwrite = sync_overwrite
|
||||
/datum/nanite_program/viral/register_extra_settings()
|
||||
extra_settings[NES_PROGRAM_OVERWRITE] = new /datum/nanite_extra_setting/type("Add To", list("Overwrite", "Add To", "Ignore"))
|
||||
extra_settings[NES_CLOUD_OVERWRITE] = new /datum/nanite_extra_setting/number(0, 0, 100)
|
||||
|
||||
/datum/nanite_program/viral/active_effect()
|
||||
if(world.time < pulse_cooldown)
|
||||
return
|
||||
var/datum/nanite_extra_setting/program = extra_settings[NES_PROGRAM_OVERWRITE]
|
||||
var/datum/nanite_extra_setting/cloud = extra_settings[NES_CLOUD_OVERWRITE]
|
||||
for(var/mob/M in orange(host_mob, 5))
|
||||
if(SEND_SIGNAL(M, COMSIG_NANITE_IS_STEALTHY))
|
||||
continue
|
||||
if(sync_programs)
|
||||
SEND_SIGNAL(M, COMSIG_NANITE_SYNC, nanites, sync_overwrite)
|
||||
if(overwrite_cloud)
|
||||
SEND_SIGNAL(M, COMSIG_NANITE_SET_CLOUD, set_cloud)
|
||||
switch(program.get_value())
|
||||
if("Overwrite")
|
||||
SEND_SIGNAL(M, COMSIG_NANITE_SYNC, nanites, TRUE)
|
||||
if("Add To")
|
||||
SEND_SIGNAL(M, COMSIG_NANITE_SYNC, nanites, FALSE)
|
||||
SEND_SIGNAL(M, COMSIG_NANITE_SET_CLOUD, cloud.get_value())
|
||||
pulse_cooldown = world.time + 75
|
||||
|
||||
/datum/nanite_program/monitoring
|
||||
@@ -94,38 +41,23 @@
|
||||
SSnanites.nanite_monitored_mobs -= host_mob
|
||||
host_mob.hud_set_nanite_indicator()
|
||||
|
||||
/datum/nanite_program/triggered/self_scan
|
||||
/datum/nanite_program/self_scan
|
||||
name = "Host Scan"
|
||||
desc = "The nanites display a detailed readout of a body scan to the host."
|
||||
unique = FALSE
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 3
|
||||
trigger_cooldown = 50
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
|
||||
extra_settings = list("Scan Type")
|
||||
var/scan_type = "Medical"
|
||||
/datum/nanite_program/self_scan/register_extra_settings()
|
||||
extra_settings[NES_SCAN_TYPE] = new /datum/nanite_extra_setting/type("Medical", list("Medical", "Chemical", "Nanite"))
|
||||
|
||||
/datum/nanite_program/triggered/self_scan/set_extra_setting(user, setting)
|
||||
if(setting == "Scan Type")
|
||||
var/list/scan_types = list("Medical","Chemical","Nanite")
|
||||
var/new_scan_type = input("Choose the scan type", name) as null|anything in scan_types
|
||||
if(!new_scan_type)
|
||||
return
|
||||
scan_type = new_scan_type
|
||||
|
||||
/datum/nanite_program/triggered/self_scan/get_extra_setting(setting)
|
||||
if(setting == "Scan Type")
|
||||
return scan_type
|
||||
|
||||
/datum/nanite_program/triggered/self_scan/copy_extra_settings_to(datum/nanite_program/triggered/self_scan/target)
|
||||
target.scan_type = scan_type
|
||||
|
||||
/datum/nanite_program/triggered/self_scan/trigger()
|
||||
if(!..())
|
||||
return
|
||||
/datum/nanite_program/self_scan/on_trigger(comm_message)
|
||||
if(host_mob.stat == DEAD)
|
||||
return
|
||||
switch(scan_type)
|
||||
var/datum/nanite_extra_setting/NS = extra_settings[NES_SCAN_TYPE]
|
||||
switch(NS.get_value())
|
||||
if("Medical")
|
||||
healthscan(host_mob, host_mob)
|
||||
if("Chemical")
|
||||
@@ -162,28 +94,13 @@
|
||||
. = ..()
|
||||
nanites.diagnostics = TRUE
|
||||
|
||||
|
||||
/datum/nanite_program/relay
|
||||
name = "Relay"
|
||||
desc = "The nanites receive and relay long-range nanite signals."
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
|
||||
extra_settings = list("Relay Channel")
|
||||
var/relay_channel = 1
|
||||
|
||||
/datum/nanite_program/relay/set_extra_setting(user, setting)
|
||||
if(setting == "Relay Channel")
|
||||
var/new_channel = input(user, "Set the relay channel (1-9999):", name, null) as null|num
|
||||
if(isnull(new_channel))
|
||||
return
|
||||
relay_channel = CLAMP(round(new_channel, 1), 1, 9999)
|
||||
|
||||
/datum/nanite_program/relay/get_extra_setting(setting)
|
||||
if(setting == "Relay Channel")
|
||||
return relay_channel
|
||||
|
||||
/datum/nanite_program/relay/copy_extra_settings_to(datum/nanite_program/relay/target)
|
||||
target.relay_channel = relay_channel
|
||||
/datum/nanite_program/relay/register_extra_settings()
|
||||
extra_settings[NES_RELAY_CHANNEL] = new /datum/nanite_extra_setting/number(1, 1, 9999)
|
||||
|
||||
/datum/nanite_program/relay/enable_passive_effect()
|
||||
. = ..()
|
||||
@@ -198,7 +115,8 @@
|
||||
return
|
||||
if(!host_mob)
|
||||
return
|
||||
if(relay_code != relay_channel)
|
||||
var/datum/nanite_extra_setting/NS = extra_settings[NES_RELAY_CHANNEL]
|
||||
if(relay_code != NS.get_value())
|
||||
return
|
||||
SEND_SIGNAL(host_mob, COMSIG_NANITE_SIGNAL, code, source)
|
||||
|
||||
@@ -207,7 +125,8 @@
|
||||
return
|
||||
if(!host_mob)
|
||||
return
|
||||
if(relay_code != relay_channel)
|
||||
var/datum/nanite_extra_setting/NS = extra_settings[NES_RELAY_CHANNEL]
|
||||
if(relay_code != NS.get_value())
|
||||
return
|
||||
SEND_SIGNAL(host_mob, COMSIG_NANITE_COMM_SIGNAL, comm_code, comm_message)
|
||||
|
||||
@@ -228,14 +147,64 @@
|
||||
host_mob.nutrition -= 0.5
|
||||
nanites.adjust_nanites(src, 0.5)
|
||||
|
||||
/datum/nanite_program/triggered/access
|
||||
/datum/nanite_program/research
|
||||
name = "Distributed Computing"
|
||||
desc = "The nanites aid the research servers by performing a portion of its calculations, increasing research point generation."
|
||||
use_rate = 0.2
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
|
||||
/datum/nanite_program/research/active_effect()
|
||||
if(!iscarbon(host_mob))
|
||||
return
|
||||
var/points = 1
|
||||
if(!host_mob.client) //less brainpower
|
||||
points *= 0.25
|
||||
SSresearch.science_tech.add_point_list(list(TECHWEB_POINT_TYPE_GENERIC = points))
|
||||
|
||||
/datum/nanite_program/researchplus
|
||||
name = "Neural Network"
|
||||
desc = "The nanites link the host's brains together forming a neural research network, that becomes more efficient with the amount of total hosts."
|
||||
use_rate = 0.3
|
||||
rogue_types = list(/datum/nanite_program/brain_decay)
|
||||
|
||||
/datum/nanite_program/researchplus/enable_passive_effect()
|
||||
. = ..()
|
||||
if(!iscarbon(host_mob))
|
||||
return
|
||||
if(host_mob.client)
|
||||
SSnanites.neural_network_count++
|
||||
else
|
||||
SSnanites.neural_network_count += 0.25
|
||||
|
||||
/datum/nanite_program/researchplus/disable_passive_effect()
|
||||
. = ..()
|
||||
if(!iscarbon(host_mob))
|
||||
return
|
||||
if(host_mob.client)
|
||||
SSnanites.neural_network_count--
|
||||
else
|
||||
SSnanites.neural_network_count -= 0.25
|
||||
|
||||
/datum/nanite_program/researchplus/active_effect()
|
||||
if(!iscarbon(host_mob))
|
||||
return
|
||||
var/mob/living/carbon/C = host_mob
|
||||
var/points = round(SSnanites.neural_network_count / 12, 0.1)
|
||||
if(!C.client) //less brainpower
|
||||
points *= 0.25
|
||||
SSresearch.science_tech.add_point_list(list(TECHWEB_POINT_TYPE_GENERIC = points))
|
||||
|
||||
/datum/nanite_program/access
|
||||
name = "Subdermal ID"
|
||||
desc = "The nanites store the host's ID access rights in a subdermal magnetic strip. Updates when triggered, copying the host's current access."
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 3
|
||||
trigger_cooldown = 30
|
||||
rogue_types = list(/datum/nanite_program/skin_decay)
|
||||
var/access = list()
|
||||
|
||||
//Syncs the nanites with the cumulative current mob's access level. Can potentially wipe existing access.
|
||||
/datum/nanite_program/triggered/access/trigger()
|
||||
/datum/nanite_program/access/on_trigger(comm_message)
|
||||
var/list/new_access = list()
|
||||
var/obj/item/current_item
|
||||
current_item = host_mob.get_active_held_item()
|
||||
@@ -284,19 +253,42 @@
|
||||
SEND_SIGNAL(infectee, COMSIG_NANITE_SYNC, nanites)
|
||||
infectee.investigate_log("was infected by spreading nanites by [key_name(host_mob)] at [AREACOORD(infectee)].", INVESTIGATE_NANITES)
|
||||
|
||||
/datum/nanite_program/nanite_sting
|
||||
name = "Nanite Sting"
|
||||
desc = "When triggered, projects a nearly invisible spike of nanites that attempts to infect a nearby non-host with a copy of the host's nanites cluster."
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 5
|
||||
trigger_cooldown = 100
|
||||
rogue_types = list(/datum/nanite_program/glitch, /datum/nanite_program/toxic)
|
||||
|
||||
/datum/nanite_program/nanite_sting/on_trigger(comm_message)
|
||||
var/list/mob/living/target_hosts = list()
|
||||
for(var/mob/living/L in oview(1, host_mob))
|
||||
if(!(L.mob_biotypes & (MOB_ORGANIC|MOB_UNDEAD)) || SEND_SIGNAL(L, COMSIG_HAS_NANITES) || !L.Adjacent(host_mob))
|
||||
continue
|
||||
target_hosts += L
|
||||
if(!target_hosts.len)
|
||||
consume_nanites(-5)
|
||||
return
|
||||
var/mob/living/infectee = pick(target_hosts)
|
||||
if(prob(100 - (infectee.get_permeability_protection() * 100)))
|
||||
//unlike with Infective Exo-Locomotion, this can't take over existing nanites, because Nanite Sting only targets non-hosts.
|
||||
infectee.AddComponent(/datum/component/nanites, 5)
|
||||
SEND_SIGNAL(infectee, COMSIG_NANITE_SYNC, nanites)
|
||||
infectee.investigate_log("was infected by a nanite cluster by [key_name(host_mob)] at [AREACOORD(infectee)].", INVESTIGATE_NANITES)
|
||||
to_chat(infectee, "<span class='warning'>You feel a tiny prick.</span>")
|
||||
|
||||
/datum/nanite_program/mitosis
|
||||
name = "Mitosis"
|
||||
desc = "The nanites gain the ability to self-replicate, using bluespace to power the process, instead of drawing from a template. This rapidly speeds up the replication rate,\
|
||||
but it causes occasional software errors due to faulty copies. Not compatible with cloud sync."
|
||||
desc = "The nanites gain the ability to self-replicate, using bluespace to power the process. Becomes more effective the more nanites are already in the host.\
|
||||
The replication has also a chance to corrupt the nanite programming due to copy faults - cloud sync is highly recommended."
|
||||
use_rate = 0
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
|
||||
/datum/nanite_program/mitosis/active_effect()
|
||||
if(nanites.cloud_id)
|
||||
return
|
||||
var/rep_rate = round(nanites.nanite_volume / 50, 1) //0.5 per 50 nanite volume
|
||||
rep_rate *= 0.5
|
||||
nanites.adjust_nanites(rep_rate)
|
||||
nanites.adjust_nanites(null, rep_rate)
|
||||
if(prob(rep_rate))
|
||||
var/datum/nanite_program/fault = pick(nanites.programs)
|
||||
if(fault == src)
|
||||
@@ -306,56 +298,22 @@
|
||||
/datum/nanite_program/dermal_button
|
||||
name = "Dermal Button"
|
||||
desc = "Displays a button on the host's skin, which can be used to send a signal to the nanites."
|
||||
extra_settings = list("Sent Code","Button Name","Icon","Color")
|
||||
unique = FALSE
|
||||
var/datum/action/innate/nanite_button/button
|
||||
var/button_name = "Button"
|
||||
var/icon = "power"
|
||||
var/color = "green"
|
||||
var/sent_code = 0
|
||||
|
||||
/datum/nanite_program/dermal_button/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
if(setting == "Button Name")
|
||||
var/new_button_name = stripped_input(user, "Choose the name for the button.", "Button Name", button_name, MAX_NAME_LEN)
|
||||
if(!new_button_name)
|
||||
return
|
||||
button_name = new_button_name
|
||||
if(setting == "Icon")
|
||||
var/new_icon = input("Select the icon to display on the button:", name) as null|anything in list("one","two","three","four","five","plus","minus","power")
|
||||
if(!new_icon)
|
||||
return
|
||||
icon = new_icon
|
||||
if(setting == "Color")
|
||||
var/new_color = input("Select the color of the button's icon:", name) as null|anything in list("green","red","yellow","blue")
|
||||
if(!new_color)
|
||||
return
|
||||
color = new_color
|
||||
|
||||
/datum/nanite_program/dermal_button/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
if(setting == "Button Name")
|
||||
return button_name
|
||||
if(setting == "Icon")
|
||||
return capitalize(icon)
|
||||
if(setting == "Color")
|
||||
return capitalize(color)
|
||||
|
||||
/datum/nanite_program/dermal_button/copy_extra_settings_to(datum/nanite_program/dermal_button/target)
|
||||
target.sent_code = sent_code
|
||||
target.button_name = button_name
|
||||
target.icon = icon
|
||||
target.color = color
|
||||
/datum/nanite_program/dermal_button/register_extra_settings()
|
||||
extra_settings[NES_SENT_CODE] = new /datum/nanite_extra_setting/number(1, 1, 9999)
|
||||
extra_settings[NES_BUTTON_NAME] = new /datum/nanite_extra_setting/text("Button")
|
||||
extra_settings[NES_ICON] = new /datum/nanite_extra_setting/type("power", list("one","two","three","four","five","plus","minus","power"))
|
||||
extra_settings[NES_COLOR] = new /datum/nanite_extra_setting/type("green", list("green","red","yellow","blue"))
|
||||
|
||||
/datum/nanite_program/dermal_button/enable_passive_effect()
|
||||
. = ..()
|
||||
var/datum/nanite_extra_setting/bn_name = extra_settings[NES_BUTTON_NAME]
|
||||
var/datum/nanite_extra_setting/bn_icon = extra_settings[NES_ICON]
|
||||
var/datum/nanite_extra_setting/bn_color = extra_settings[NES_COLOR]
|
||||
if(!button)
|
||||
button = new(src, button_name, icon, color)
|
||||
button = new(src, bn_name.get_value(), bn_icon.get_value(), bn_color.get_value())
|
||||
button.target = host_mob
|
||||
button.Grant(host_mob)
|
||||
|
||||
@@ -372,7 +330,8 @@
|
||||
if(activated)
|
||||
host_mob.visible_message("<span class='notice'>[host_mob] presses a button on [host_mob.p_their()] forearm.</span>",
|
||||
"<span class='notice'>You press the nanite button on your forearm.</span>", null, 2)
|
||||
SEND_SIGNAL(host_mob, COMSIG_NANITE_SIGNAL, sent_code, "a [name] program")
|
||||
var/datum/nanite_extra_setting/sent_code = extra_settings[NES_SENT_CODE]
|
||||
SEND_SIGNAL(host_mob, COMSIG_NANITE_SIGNAL, sent_code.get_value(), "a [name] program")
|
||||
|
||||
/datum/action/innate/nanite_button
|
||||
name = "Button"
|
||||
@@ -389,51 +348,3 @@
|
||||
|
||||
/datum/action/innate/nanite_button/Activate()
|
||||
program.press()
|
||||
|
||||
/datum/nanite_program/research
|
||||
name = "Distributed Computing"
|
||||
desc = "The nanites aid the research servers by performing a portion of its calculations, increasing research point generation."
|
||||
use_rate = 0.2
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
|
||||
/datum/nanite_program/research/active_effect()
|
||||
if(!iscarbon(host_mob))
|
||||
return
|
||||
var/points = 1
|
||||
if(!host_mob.client) //less brainpower
|
||||
points *= 0.25
|
||||
SSresearch.science_tech.add_point_list(list(TECHWEB_POINT_TYPE_GENERIC = points))
|
||||
|
||||
/datum/nanite_program/researchplus
|
||||
name = "Neural Network"
|
||||
desc = "The nanites link the host's brains together forming a neural research network, that becomes more efficient with the amount of total hosts."
|
||||
use_rate = 0.3
|
||||
rogue_types = list(/datum/nanite_program/brain_decay)
|
||||
|
||||
/datum/nanite_program/researchplus/enable_passive_effect()
|
||||
. = ..()
|
||||
if(!iscarbon(host_mob))
|
||||
return
|
||||
if(host_mob.client)
|
||||
SSnanites.neural_network_count++
|
||||
else
|
||||
SSnanites.neural_network_count += 0.25
|
||||
|
||||
/datum/nanite_program/researchplus/disable_passive_effect()
|
||||
. = ..()
|
||||
if(!iscarbon(host_mob))
|
||||
return
|
||||
if(host_mob.client)
|
||||
SSnanites.neural_network_count--
|
||||
else
|
||||
SSnanites.neural_network_count -= 0.25
|
||||
|
||||
/datum/nanite_program/researchplus/active_effect()
|
||||
if(!iscarbon(host_mob))
|
||||
return
|
||||
var/mob/living/carbon/C = host_mob
|
||||
var/points = round(SSnanites.neural_network_count / 12, 0.1)
|
||||
if(!C.client) //less brainpower
|
||||
points *= 0.25
|
||||
SSresearch.science_tech.add_point_list(list(TECHWEB_POINT_TYPE_GENERIC = points))
|
||||
|
||||
|
||||
@@ -73,21 +73,20 @@
|
||||
. = ..()
|
||||
to_chat(host_mob, "<span class='warning'>Your blood cools down, and the pain gradually fades.</span>")
|
||||
|
||||
/datum/nanite_program/triggered/explosive
|
||||
/datum/nanite_program/explosive
|
||||
name = "Chain Detonation"
|
||||
desc = "Detonates all the nanites inside the host in a chain reaction when triggered."
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 25 //plus every idle nanite left afterwards
|
||||
trigger_cooldown = 100 //Just to avoid double-triggering
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
|
||||
/datum/nanite_program/triggered/explosive/trigger()
|
||||
if(!..())
|
||||
return
|
||||
/datum/nanite_program/explosive/on_trigger(comm_message)
|
||||
host_mob.visible_message("<span class='warning'>[host_mob] starts emitting a high-pitched buzzing, and [host_mob.p_their()] skin begins to glow...</span>",\
|
||||
"<span class='userdanger'>You start emitting a high-pitched buzzing, and your skin begins to glow...</span>")
|
||||
addtimer(CALLBACK(src, .proc/boom), CLAMP((nanites.nanite_volume * 0.35), 25, 150))
|
||||
|
||||
/datum/nanite_program/triggered/explosive/proc/boom()
|
||||
/datum/nanite_program/explosive/proc/boom()
|
||||
var/nanite_amount = nanites.nanite_volume
|
||||
var/heavy_range = FLOOR(nanite_amount/100, 1) - 1
|
||||
var/light_range = FLOOR(nanite_amount/50, 1) - 1
|
||||
@@ -96,16 +95,15 @@
|
||||
|
||||
//TODO make it defuse if triggered again
|
||||
|
||||
/datum/nanite_program/triggered/heart_stop
|
||||
/datum/nanite_program/heart_stop
|
||||
name = "Heart-Stopper"
|
||||
desc = "Stops the host's heart when triggered; restarts it if triggered again."
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 12
|
||||
trigger_cooldown = 10
|
||||
rogue_types = list(/datum/nanite_program/nerve_decay)
|
||||
|
||||
/datum/nanite_program/triggered/heart_stop/trigger()
|
||||
if(!..())
|
||||
return
|
||||
/datum/nanite_program/heart_stop/on_trigger(comm_message)
|
||||
if(iscarbon(host_mob))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
var/obj/item/organ/heart/heart = C.getorganslot(ORGAN_SLOT_HEART)
|
||||
@@ -115,16 +113,16 @@
|
||||
else
|
||||
heart.Restart()
|
||||
|
||||
/datum/nanite_program/triggered/emp
|
||||
/datum/nanite_program/emp
|
||||
name = "Electromagnetic Resonance"
|
||||
desc = "The nanites cause an elctromagnetic pulse around the host when triggered. Will corrupt other nanite programs!"
|
||||
desc = "The nanites cause an electromagnetic pulse around the host when triggered. Will corrupt other nanite programs!"
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 10
|
||||
trigger_cooldown = 50
|
||||
program_flags = NANITE_EMP_IMMUNE
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
|
||||
/datum/nanite_program/triggered/emp/trigger()
|
||||
if(!..())
|
||||
return
|
||||
/datum/nanite_program/emp/on_trigger(comm_message)
|
||||
empulse(host_mob, 1, 2)
|
||||
|
||||
/datum/nanite_program/pyro/active_effect()
|
||||
@@ -148,7 +146,7 @@
|
||||
|
||||
/datum/nanite_program/cryo
|
||||
name = "Cryogenic Treatment"
|
||||
desc = "The nanites rapidly skin heat through the host's skin, lowering their temperature."
|
||||
desc = "The nanites rapidly sink heat through the host's skin, lowering their temperature."
|
||||
use_rate = 1
|
||||
rogue_types = list(/datum/nanite_program/skin_decay, /datum/nanite_program/pyro)
|
||||
|
||||
@@ -160,55 +158,33 @@
|
||||
/datum/nanite_program/cryo/active_effect()
|
||||
host_mob.adjust_bodytemperature(-rand(15,25), 50)
|
||||
|
||||
/datum/nanite_program/triggered/comm/mind_control
|
||||
/datum/nanite_program/comm/mind_control
|
||||
name = "Mind Control"
|
||||
desc = "The nanites imprint an absolute directive onto the host's brain for one minute when triggered."
|
||||
trigger_cost = 30
|
||||
trigger_cooldown = 1800
|
||||
rogue_types = list(/datum/nanite_program/brain_decay, /datum/nanite_program/brain_misfire)
|
||||
|
||||
extra_settings = list("Directive","Comm Code")
|
||||
var/directive = "..."
|
||||
/datum/nanite_program/comm/mind_control/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_DIRECTIVE] = new /datum/nanite_extra_setting/text("...")
|
||||
|
||||
/datum/nanite_program/triggered/comm/mind_control/set_extra_setting(user, setting)
|
||||
if(setting == "Directive")
|
||||
var/new_directive = stripped_input(user, "Choose the directive to imprint with mind control.", "Directive", directive, MAX_MESSAGE_LEN)
|
||||
if(!new_directive)
|
||||
return
|
||||
directive = new_directive
|
||||
if(setting == "Comm Code")
|
||||
var/new_code = input(user, "Set the communication code (1-9999) or set to 0 to disable external signals.", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
comm_code = CLAMP(round(new_code, 1), 0, 9999)
|
||||
|
||||
/datum/nanite_program/triggered/comm/mind_control/get_extra_setting(setting)
|
||||
if(setting == "Directive")
|
||||
return directive
|
||||
if(setting == "Comm Code")
|
||||
return comm_code
|
||||
|
||||
/datum/nanite_program/triggered/comm/mind_control/copy_extra_settings_to(datum/nanite_program/triggered/comm/mind_control/target)
|
||||
target.directive = directive
|
||||
target.comm_code = comm_code
|
||||
|
||||
/datum/nanite_program/triggered/comm/mind_control/trigger(comm_message)
|
||||
if(!..())
|
||||
return
|
||||
/datum/nanite_program/comm/mind_control/on_trigger(comm_message)
|
||||
if(host_mob.stat == DEAD)
|
||||
return
|
||||
var/sent_directive = comm_message
|
||||
if(!comm_message)
|
||||
sent_directive = directive
|
||||
var/datum/nanite_extra_setting/ES = extra_settings[NES_DIRECTIVE]
|
||||
sent_directive = ES.get_value()
|
||||
brainwash(host_mob, sent_directive)
|
||||
log_game("A mind control nanite program brainwashed [key_name(host_mob)] with the objective '[directive]'.")
|
||||
log_game("A mind control nanite program brainwashed [key_name(host_mob)] with the objective '[sent_directive]'.")
|
||||
addtimer(CALLBACK(src, .proc/end_brainwashing), 600)
|
||||
|
||||
/datum/nanite_program/triggered/comm/mind_control/proc/end_brainwashing()
|
||||
/datum/nanite_program/comm/mind_control/proc/end_brainwashing()
|
||||
if(host_mob.mind && host_mob.mind.has_antag_datum(/datum/antagonist/brainwashed))
|
||||
host_mob.mind.remove_antag_datum(/datum/antagonist/brainwashed)
|
||||
log_game("[key_name(host_mob)] is no longer brainwashed by nanites.")
|
||||
|
||||
/datum/nanite_program/triggered/comm/mind_control/disable_passive_effect()
|
||||
|
||||
/datum/nanite_program/comm/mind_control/disable_passive_effect()
|
||||
. = ..()
|
||||
end_brainwashing()
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
var/last_id = 0
|
||||
var/code = 0
|
||||
var/relay_code = 0
|
||||
var/current_program_name = "Program"
|
||||
|
||||
/obj/item/nanite_remote/examine(mob/user)
|
||||
. = ..()
|
||||
@@ -35,10 +36,8 @@
|
||||
update_icon()
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Access denied.</span>")
|
||||
return TRUE
|
||||
|
||||
/obj/item/nanite_remote/emag_act(mob/user)
|
||||
. = ..()
|
||||
if(obj_flags & EMAGGED)
|
||||
return
|
||||
to_chat(user, "<span class='warning'>You override [src]'s ID lock.</span>")
|
||||
@@ -46,33 +45,31 @@
|
||||
if(locked)
|
||||
locked = FALSE
|
||||
update_icon()
|
||||
return TRUE
|
||||
|
||||
/obj/item/nanite_remote/update_icon()
|
||||
/obj/item/nanite_remote/update_overlays()
|
||||
. = ..()
|
||||
cut_overlays()
|
||||
if(obj_flags & EMAGGED)
|
||||
add_overlay("nanite_remote_emagged")
|
||||
. += "nanite_remote_emagged"
|
||||
if(locked)
|
||||
add_overlay("nanite_remote_locked")
|
||||
. += "nanite_remote_locked"
|
||||
|
||||
/obj/item/nanite_remote/afterattack(atom/target, mob/user, etc)
|
||||
switch(mode)
|
||||
if(REMOTE_MODE_OFF)
|
||||
return
|
||||
if(REMOTE_MODE_SELF)
|
||||
to_chat(user, "<span class='notice'>You activate [src], signaling the nanites in your bloodstream.<span>")
|
||||
to_chat(user, "<span class='notice'>You activate [src], signaling the nanites in your bloodstream.</span>")
|
||||
signal_mob(user, code, key_name(user))
|
||||
if(REMOTE_MODE_TARGET)
|
||||
if(isliving(target) && (get_dist(target, get_turf(src)) <= 7))
|
||||
to_chat(user, "<span class='notice'>You activate [src], signaling the nanites inside [target].<span>")
|
||||
to_chat(user, "<span class='notice'>You activate [src], signaling the nanites inside [target].</span>")
|
||||
signal_mob(target, code, key_name(user))
|
||||
if(REMOTE_MODE_AOE)
|
||||
to_chat(user, "<span class='notice'>You activate [src], signaling the nanites inside every host around you.<span>")
|
||||
to_chat(user, "<span class='notice'>You activate [src], signaling the nanites inside every host around you.</span>")
|
||||
for(var/mob/living/L in view(user, 7))
|
||||
signal_mob(L, code, key_name(user))
|
||||
if(REMOTE_MODE_RELAY)
|
||||
to_chat(user, "<span class='notice'>You activate [src], signaling all connected relay nanites.<span>")
|
||||
to_chat(user, "<span class='notice'>You activate [src], signaling all connected relay nanites.</span>")
|
||||
signal_relay(code, relay_code, key_name(user))
|
||||
|
||||
/obj/item/nanite_remote/proc/signal_mob(mob/living/M, code, source)
|
||||
@@ -84,9 +81,9 @@
|
||||
N.relay_signal(code, relay_code, source)
|
||||
|
||||
/obj/item/nanite_remote/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
|
||||
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "nanite_remote", name, 420, 800, master_ui, state)
|
||||
ui = new(user, src, ui_key, "nanite_remote", name, 420, 500, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/item/nanite_remote/ui_data()
|
||||
@@ -96,6 +93,7 @@
|
||||
data["mode"] = mode
|
||||
data["locked"] = locked
|
||||
data["saved_settings"] = saved_settings
|
||||
data["program_name"] = current_program_name
|
||||
|
||||
return data
|
||||
|
||||
@@ -106,7 +104,7 @@
|
||||
if("set_code")
|
||||
if(locked)
|
||||
return
|
||||
var/new_code = input("Set code (0000-9999):", name, code) as null|num
|
||||
var/new_code = text2num(params["code"])
|
||||
if(!isnull(new_code))
|
||||
new_code = CLAMP(round(new_code, 1),0,9999)
|
||||
code = new_code
|
||||
@@ -114,21 +112,21 @@
|
||||
if("set_relay_code")
|
||||
if(locked)
|
||||
return
|
||||
var/new_code = input("Set relay code (0000-9999):", name, code) as null|num
|
||||
var/new_code = text2num(params["code"])
|
||||
if(!isnull(new_code))
|
||||
new_code = CLAMP(round(new_code, 1),0,9999)
|
||||
relay_code = new_code
|
||||
. = TRUE
|
||||
if("update_name")
|
||||
current_program_name = params["name"]
|
||||
. = TRUE
|
||||
if("save")
|
||||
if(locked)
|
||||
return
|
||||
var/code_name = stripped_input(usr, "Set the setting name", "Set Name", null , 15)
|
||||
if(!code_name)
|
||||
return
|
||||
var/new_save = list()
|
||||
new_save["id"] = last_id + 1
|
||||
last_id++
|
||||
new_save["name"] = code_name
|
||||
new_save["name"] = current_program_name
|
||||
new_save["code"] = code
|
||||
new_save["mode"] = mode
|
||||
new_save["relay_code"] = relay_code
|
||||
@@ -172,7 +170,6 @@
|
||||
name = "nanite communication remote"
|
||||
desc = "A device that can send text messages to specific programs."
|
||||
icon_state = "nanite_comm_remote"
|
||||
var/comm_code = 0
|
||||
var/comm_message = ""
|
||||
|
||||
/obj/item/nanite_remote/comm/afterattack(atom/target, mob/user, etc)
|
||||
@@ -180,42 +177,38 @@
|
||||
if(REMOTE_MODE_OFF)
|
||||
return
|
||||
if(REMOTE_MODE_SELF)
|
||||
to_chat(user, "<span class='notice'>You activate [src], signaling the nanites in your bloodstream.<span>")
|
||||
signal_mob(user, comm_code, comm_message)
|
||||
to_chat(user, "<span class='notice'>You activate [src], signaling the nanites in your bloodstream.</span>")
|
||||
signal_mob(user, code, comm_message)
|
||||
if(REMOTE_MODE_TARGET)
|
||||
if(isliving(target) && (get_dist(target, get_turf(src)) <= 7))
|
||||
to_chat(user, "<span class='notice'>You activate [src], signaling the nanites inside [target].<span>")
|
||||
to_chat(user, "<span class='notice'>You activate [src], signaling the nanites inside [target].</span>")
|
||||
signal_mob(target, code, comm_message, key_name(user))
|
||||
if(REMOTE_MODE_AOE)
|
||||
to_chat(user, "<span class='notice'>You activate [src], signaling the nanites inside every host around you.<span>")
|
||||
to_chat(user, "<span class='notice'>You activate [src], signaling the nanites inside every host around you.</span>")
|
||||
for(var/mob/living/L in view(user, 7))
|
||||
signal_mob(L, code, comm_message, key_name(user))
|
||||
if(REMOTE_MODE_RELAY)
|
||||
to_chat(user, "<span class='notice'>You activate [src], signaling all connected relay nanites.<span>")
|
||||
to_chat(user, "<span class='notice'>You activate [src], signaling all connected relay nanites.</span>")
|
||||
signal_relay(code, relay_code, comm_message, key_name(user))
|
||||
|
||||
/obj/item/nanite_remote/comm/signal_mob(mob/living/M, code, source)
|
||||
SEND_SIGNAL(M, COMSIG_NANITE_COMM_SIGNAL, comm_code, comm_message)
|
||||
SEND_SIGNAL(M, COMSIG_NANITE_COMM_SIGNAL, code, comm_message)
|
||||
|
||||
/obj/item/nanite_remote/comm/signal_relay(code, relay_code, source)
|
||||
for(var/X in SSnanites.nanite_relays)
|
||||
var/datum/nanite_program/relay/N = X
|
||||
N.relay_comm_signal(comm_code, relay_code, comm_message)
|
||||
|
||||
/obj/item/nanite_remote/comm/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
|
||||
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "nanite_comm_remote", name, 420, 800, master_ui, state)
|
||||
ui.open()
|
||||
N.relay_comm_signal(code, relay_code, comm_message)
|
||||
|
||||
/obj/item/nanite_remote/comm/ui_data()
|
||||
var/list/data = list()
|
||||
data["comm_code"] = comm_code
|
||||
data["comms"] = TRUE
|
||||
data["code"] = code
|
||||
data["relay_code"] = relay_code
|
||||
data["comm_message"] = comm_message
|
||||
data["message"] = comm_message
|
||||
data["mode"] = mode
|
||||
data["locked"] = locked
|
||||
data["saved_settings"] = saved_settings
|
||||
data["program_name"] = current_program_name
|
||||
|
||||
return data
|
||||
|
||||
@@ -223,56 +216,17 @@
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("set_comm_code")
|
||||
if(locked)
|
||||
return
|
||||
var/new_code = input("Set comm code (0000-9999):", name, code) as null|num
|
||||
if(!isnull(new_code))
|
||||
new_code = CLAMP(round(new_code, 1),0,9999)
|
||||
comm_code = new_code
|
||||
. = TRUE
|
||||
if("set_message")
|
||||
if(locked)
|
||||
return
|
||||
var/new_message = stripped_input(usr, "Set the message (Max 300 characters):", "Set Message", null , 300)
|
||||
var/new_message = html_encode(params["value"])
|
||||
if(!new_message)
|
||||
return
|
||||
comm_message = new_message
|
||||
. = TRUE
|
||||
if("comm_save")
|
||||
if(locked)
|
||||
return
|
||||
var/code_name = stripped_input(usr, "Set the setting name", "Set Name", null , 15)
|
||||
if(!code_name)
|
||||
return
|
||||
var/new_save = list()
|
||||
new_save["id"] = last_id + 1
|
||||
last_id++
|
||||
new_save["name"] = code_name
|
||||
new_save["code"] = comm_code
|
||||
new_save["mode"] = mode
|
||||
new_save["relay_code"] = relay_code
|
||||
new_save["message"] = comm_message
|
||||
|
||||
saved_settings += list(new_save)
|
||||
. = TRUE
|
||||
if("comm_load")
|
||||
var/code_id = params["save_id"]
|
||||
var/list/setting
|
||||
for(var/list/X in saved_settings)
|
||||
if(X["id"] == text2num(code_id))
|
||||
setting = X
|
||||
break
|
||||
if(setting)
|
||||
comm_code = setting["code"]
|
||||
mode = setting["mode"]
|
||||
relay_code = setting["relay_code"]
|
||||
comm_message = setting["message"]
|
||||
. = TRUE
|
||||
|
||||
|
||||
#undef REMOTE_MODE_OFF
|
||||
#undef REMOTE_MODE_SELF
|
||||
#undef REMOTE_MODE_TARGET
|
||||
#undef REMOTE_MODE_AOE
|
||||
#undef REMOTE_MODE_RELAY
|
||||
#undef REMOTE_MODE_RELAY
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
program_type = /datum/nanite_program/relay
|
||||
|
||||
/obj/item/disk/nanite_program/emp
|
||||
program_type = /datum/nanite_program/triggered/emp
|
||||
program_type = /datum/nanite_program/emp
|
||||
|
||||
/obj/item/disk/nanite_program/spreading
|
||||
program_type = /datum/nanite_program/spreading
|
||||
@@ -91,16 +91,16 @@
|
||||
program_type = /datum/nanite_program/suffocating
|
||||
|
||||
/obj/item/disk/nanite_program/heart_stop
|
||||
program_type = /datum/nanite_program/triggered/heart_stop
|
||||
program_type = /datum/nanite_program/heart_stop
|
||||
|
||||
/obj/item/disk/nanite_program/explosive
|
||||
program_type = /datum/nanite_program/triggered/explosive
|
||||
program_type = /datum/nanite_program/explosive
|
||||
|
||||
/obj/item/disk/nanite_program/shock
|
||||
program_type = /datum/nanite_program/triggered/shocking
|
||||
program_type = /datum/nanite_program/shocking
|
||||
|
||||
/obj/item/disk/nanite_program/sleepy
|
||||
program_type = /datum/nanite_program/triggered/sleepy
|
||||
program_type = /datum/nanite_program/sleepy
|
||||
|
||||
/obj/item/disk/nanite_program/paralyzing
|
||||
program_type = /datum/nanite_program/paralyzing
|
||||
@@ -130,7 +130,7 @@
|
||||
program_type = /datum/nanite_program/pacifying
|
||||
|
||||
/obj/item/disk/nanite_program/stun
|
||||
program_type = /datum/nanite_program/triggered/stun
|
||||
program_type = /datum/nanite_program/stun
|
||||
|
||||
/obj/item/disk/nanite_program/dermal_button
|
||||
program_type = /datum/nanite_program/dermal_button
|
||||
@@ -149,3 +149,4 @@
|
||||
|
||||
/obj/item/disk/nanite_program/bad_mood
|
||||
program_type = /datum/nanite_program/bad_mood
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
busy_icon_state = working_icon
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/public_nanite_chamber/proc/inject_nanites()
|
||||
/obj/machinery/public_nanite_chamber/proc/inject_nanites(mob/living/attacker)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if((stat & MAINT) || panel_open)
|
||||
@@ -47,46 +47,67 @@
|
||||
set_busy(TRUE, "[initial(icon_state)]_raising")
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "[initial(icon_state)]_active"),20)
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "[initial(icon_state)]_falling"),60)
|
||||
addtimer(CALLBACK(src, .proc/complete_injection, locked_state),80)
|
||||
addtimer(CALLBACK(src, .proc/complete_injection, locked_state, attacker),80)
|
||||
|
||||
/obj/machinery/public_nanite_chamber/proc/complete_injection(locked_state)
|
||||
/obj/machinery/public_nanite_chamber/proc/complete_injection(locked_state, mob/living/attacker)
|
||||
//TODO MACHINE DING
|
||||
locked = locked_state
|
||||
set_busy(FALSE)
|
||||
if(!occupant)
|
||||
return
|
||||
if(attacker)
|
||||
occupant.investigate_log("was injected with nanites by [key_name(attacker)] using [src] at [AREACOORD(src)].", INVESTIGATE_NANITES)
|
||||
log_combat(attacker, occupant, "injected", null, "with nanites via [src]")
|
||||
occupant.AddComponent(/datum/component/nanites, 75, cloud_id)
|
||||
|
||||
/obj/machinery/public_nanite_chamber/update_icon()
|
||||
cut_overlays()
|
||||
|
||||
/obj/machinery/public_nanite_chamber/proc/change_cloud(mob/living/attacker)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if((stat & MAINT) || panel_open)
|
||||
add_overlay("maint")
|
||||
return
|
||||
if(!occupant || busy)
|
||||
return
|
||||
|
||||
else if(!(stat & (NOPOWER|BROKEN)))
|
||||
if(busy || locked)
|
||||
add_overlay("red")
|
||||
if(locked)
|
||||
add_overlay("bolted")
|
||||
else
|
||||
add_overlay("green")
|
||||
var/locked_state = locked
|
||||
locked = TRUE
|
||||
|
||||
set_busy(TRUE, "[initial(icon_state)]_raising")
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "[initial(icon_state)]_active"),20)
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "[initial(icon_state)]_falling"),40)
|
||||
addtimer(CALLBACK(src, .proc/complete_cloud_change, locked_state, attacker),60)
|
||||
|
||||
/obj/machinery/public_nanite_chamber/proc/complete_cloud_change(locked_state, mob/living/attacker)
|
||||
locked = locked_state
|
||||
set_busy(FALSE)
|
||||
if(!occupant)
|
||||
return
|
||||
if(attacker)
|
||||
occupant.investigate_log("had their nanite cloud ID changed into [cloud_id] by [key_name(attacker)] using [src] at [AREACOORD(src)].", INVESTIGATE_NANITES)
|
||||
SEND_SIGNAL(occupant, COMSIG_NANITE_SET_CLOUD, cloud_id)
|
||||
|
||||
/obj/machinery/public_nanite_chamber/update_icon_state()
|
||||
//running and someone in there
|
||||
if(occupant)
|
||||
if(busy)
|
||||
icon_state = busy_icon_state
|
||||
else
|
||||
icon_state = initial(icon_state)+ "_occupied"
|
||||
return
|
||||
else
|
||||
//running
|
||||
icon_state = initial(icon_state)+ (state_open ? "_open" : "")
|
||||
|
||||
//running
|
||||
icon_state = initial(icon_state)+ (state_open ? "_open" : "")
|
||||
|
||||
/obj/machinery/public_nanite_chamber/power_change()
|
||||
/obj/machinery/public_nanite_chamber/update_overlays()
|
||||
. = ..()
|
||||
update_icon()
|
||||
if((stat & MAINT) || panel_open)
|
||||
. += "maint"
|
||||
|
||||
else if(!(stat & (NOPOWER|BROKEN)))
|
||||
if(busy || locked)
|
||||
. += "red"
|
||||
if(locked)
|
||||
. += "bolted"
|
||||
else
|
||||
. += "green"
|
||||
|
||||
/obj/machinery/public_nanite_chamber/proc/toggle_open(mob/user)
|
||||
if(panel_open)
|
||||
@@ -94,7 +115,7 @@
|
||||
return
|
||||
|
||||
if(state_open)
|
||||
close_machine()
|
||||
close_machine(null, user)
|
||||
return
|
||||
|
||||
else if(locked)
|
||||
@@ -113,7 +134,7 @@
|
||||
user.last_special = world.time + CLICK_CD_BREAKOUT
|
||||
user.visible_message("<span class='notice'>You see [user] kicking against the door of [src]!</span>", \
|
||||
"<span class='notice'>You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)</span>", \
|
||||
"<span class='italics'>You hear a metallic creaking from [src].</span>")
|
||||
"<span class='hear'>You hear a metallic creaking from [src].</span>")
|
||||
if(do_after(user,(breakout_time), target = src))
|
||||
if(!user || user.stat != CONSCIOUS || user.loc != src || state_open || !locked || busy)
|
||||
return
|
||||
@@ -122,7 +143,7 @@
|
||||
"<span class='notice'>You successfully break out of [src]!</span>")
|
||||
open_machine()
|
||||
|
||||
/obj/machinery/public_nanite_chamber/close_machine(mob/living/carbon/user)
|
||||
/obj/machinery/public_nanite_chamber/close_machine(mob/living/carbon/user, mob/living/attacker)
|
||||
if(!state_open)
|
||||
return FALSE
|
||||
|
||||
@@ -130,15 +151,18 @@
|
||||
|
||||
. = TRUE
|
||||
|
||||
addtimer(CALLBACK(src, .proc/try_inject_nanites), 30) //If someone is shoved in give them a chance to get out before the injection starts
|
||||
addtimer(CALLBACK(src, .proc/try_inject_nanites, attacker), 30) //If someone is shoved in give them a chance to get out before the injection starts
|
||||
|
||||
/obj/machinery/public_nanite_chamber/proc/try_inject_nanites()
|
||||
/obj/machinery/public_nanite_chamber/proc/try_inject_nanites(mob/living/attacker)
|
||||
if(occupant)
|
||||
var/mob/living/L = occupant
|
||||
if(SEND_SIGNAL(L, COMSIG_HAS_NANITES))
|
||||
var/datum/component/nanites/nanites = L.GetComponent(/datum/component/nanites)
|
||||
if(nanites && nanites.cloud_id != cloud_id)
|
||||
change_cloud(attacker)
|
||||
return
|
||||
if(L.mob_biotypes & (MOB_ORGANIC | MOB_UNDEAD))
|
||||
inject_nanites()
|
||||
inject_nanites(attacker)
|
||||
|
||||
/obj/machinery/public_nanite_chamber/open_machine()
|
||||
if(state_open)
|
||||
@@ -173,6 +197,8 @@
|
||||
toggle_open(user)
|
||||
|
||||
/obj/machinery/public_nanite_chamber/MouseDrop_T(mob/target, mob/user)
|
||||
if(user.stat || user.lying || !Adjacent(user) || !user.Adjacent(target) || !iscarbon(target) || !user.IsAdvancedToolUser())
|
||||
if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK) || !Adjacent(target) || !user.Adjacent(target) || !iscarbon(target))
|
||||
return
|
||||
close_machine(target)
|
||||
if(close_machine(target, user))
|
||||
log_combat(user, target, "inserted", null, "into [src].")
|
||||
add_fingerprint(user)
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
/datum/nanite_rule
|
||||
var/name = "Generic Condition"
|
||||
var/desc = "When triggered, the program is active"
|
||||
var/datum/nanite_program/program
|
||||
|
||||
/datum/nanite_rule/New(datum/nanite_program/new_program)
|
||||
program = new_program
|
||||
if(LAZYLEN(new_program.rules) <= 5) //Avoid infinite stacking rules
|
||||
new_program.rules += src
|
||||
else
|
||||
qdel(src)
|
||||
|
||||
/datum/nanite_rule/proc/remove()
|
||||
program.rules -= src
|
||||
program = null
|
||||
qdel(src)
|
||||
|
||||
/datum/nanite_rule/proc/check_rule()
|
||||
return TRUE
|
||||
|
||||
/datum/nanite_rule/proc/display()
|
||||
return name
|
||||
|
||||
/datum/nanite_rule/proc/copy_to(datum/nanite_program/new_program)
|
||||
new type(new_program)
|
||||
|
||||
/datum/nanite_rule/health
|
||||
name = "Health"
|
||||
desc = "Checks the host's health status."
|
||||
|
||||
var/threshold = 50
|
||||
var/above = TRUE
|
||||
|
||||
/datum/nanite_rule/health/check_rule()
|
||||
var/health_percent = program.host_mob.health / program.host_mob.maxHealth * 100
|
||||
if(above)
|
||||
if(health_percent >= threshold)
|
||||
return TRUE
|
||||
else
|
||||
if(health_percent < threshold)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_rule/health/display()
|
||||
return "[name] [above ? ">" : "<"] [threshold]%"
|
||||
|
||||
/datum/nanite_rule/health/copy_to(datum/nanite_program/new_program)
|
||||
var/datum/nanite_rule/health/rule = new(new_program)
|
||||
rule.above = above
|
||||
rule.threshold = threshold
|
||||
|
||||
//TODO allow inversion
|
||||
/datum/nanite_rule/crit
|
||||
name = "Crit"
|
||||
desc = "Checks if the host is in critical condition."
|
||||
|
||||
/datum/nanite_rule/crit/check_rule()
|
||||
if(program.host_mob.InCritical())
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_rule/death
|
||||
name = "Death"
|
||||
desc = "Checks if the host is dead."
|
||||
|
||||
/datum/nanite_rule/death/check_rule()
|
||||
if(program.host_mob.stat == DEAD || HAS_TRAIT(program.host_mob, TRAIT_FAKEDEATH))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_rule/cloud_sync
|
||||
name = "Cloud Sync"
|
||||
desc = "Checks if the nanites have cloud sync enabled or disabled."
|
||||
var/check_type = "Enabled"
|
||||
|
||||
/datum/nanite_rule/cloud_sync/check_rule()
|
||||
if(check_type == "Enabled")
|
||||
return program.nanites.cloud_active
|
||||
else
|
||||
return !program.nanites.cloud_active
|
||||
|
||||
/datum/nanite_rule/cloud_sync/copy_to(datum/nanite_program/new_program)
|
||||
var/datum/nanite_rule/cloud_sync/rule = new(new_program)
|
||||
rule.check_type = check_type
|
||||
|
||||
/datum/nanite_rule/cloud_sync/display()
|
||||
return "[name]:[check_type]"
|
||||
|
||||
/datum/nanite_rule/nanites
|
||||
name = "Nanite Volume"
|
||||
desc = "Checks the host's nanite volume."
|
||||
|
||||
var/threshold = 50
|
||||
var/above = TRUE
|
||||
|
||||
/datum/nanite_rule/nanites/check_rule()
|
||||
var/nanite_percent = (program.nanites.nanite_volume - program.nanites.safety_threshold)/(program.nanites.max_nanites - program.nanites.safety_threshold)*100
|
||||
if(above)
|
||||
if(nanite_percent >= threshold)
|
||||
return TRUE
|
||||
else
|
||||
if(nanite_percent < threshold)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_rule/nanites/copy_to(datum/nanite_program/new_program)
|
||||
var/datum/nanite_rule/nanites/rule = new(new_program)
|
||||
rule.above = above
|
||||
rule.threshold = threshold
|
||||
|
||||
/datum/nanite_rule/nanites/display()
|
||||
return "[name] [above ? ">" : "<"] [threshold]%"
|
||||
|
||||
/datum/nanite_rule/damage
|
||||
name = "Damage"
|
||||
desc = "Checks the host's damage."
|
||||
|
||||
var/threshold = 50
|
||||
var/above = TRUE
|
||||
var/damage_type = BRUTE
|
||||
|
||||
/datum/nanite_rule/damage/check_rule()
|
||||
var/damage_amt = 0
|
||||
switch(damage_type)
|
||||
if(BRUTE)
|
||||
damage_amt = program.host_mob.getBruteLoss()
|
||||
if(BURN)
|
||||
damage_amt = program.host_mob.getFireLoss()
|
||||
if(TOX)
|
||||
damage_amt = program.host_mob.getToxLoss()
|
||||
if(OXY)
|
||||
damage_amt = program.host_mob.getOxyLoss()
|
||||
if(CLONE)
|
||||
damage_amt = program.host_mob.getCloneLoss()
|
||||
|
||||
if(above)
|
||||
if(damage_amt >= threshold)
|
||||
return TRUE
|
||||
else
|
||||
if(damage_amt < threshold)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_rule/damage/copy_to(datum/nanite_program/new_program)
|
||||
var/datum/nanite_rule/damage/rule = new(new_program)
|
||||
rule.above = above
|
||||
rule.threshold = threshold
|
||||
rule.damage_type = damage_type
|
||||
|
||||
/datum/nanite_rule/damage/display()
|
||||
return "[damage_type] [above ? ">" : "<"] [threshold]"
|
||||
@@ -602,7 +602,7 @@
|
||||
display_name = "Basic Tools"
|
||||
description = "Basic mechanical, electronic, surgical and botanical tools."
|
||||
prereq_ids = list("base")
|
||||
design_ids = list("screwdriver", "wrench", "wirecutters", "crowbar", "multitool", "welding_tool", "tscanner", "analyzer", "cable_coil", "pipe_painter", "airlock_painter", "scalpel", "circular_saw", "surgicaldrill", "retractor", "cautery", "hemostat", "cultivator", "plant_analyzer", "shovel", "spade", "hatchet", "mop")
|
||||
design_ids = list("screwdriver", "wrench", "wirecutters", "crowbar", "multitool", "welding_tool", "tscanner", "analyzer", "cable_coil", "pipe_painter", "airlock_painter", "scalpel", "circular_saw", "surgicaldrill", "retractor", "cautery", "hemostat", "cultivator", "plant_analyzer", "shovel", "spade", "hatchet", "mop", "broom")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 500)
|
||||
export_price = 5000
|
||||
|
||||
|
||||
@@ -3,13 +3,38 @@
|
||||
#define ENGINES_STARTED (SSshuttle.emergency.mode == SHUTTLE_IGNITING)
|
||||
#define IS_DOCKED (SSshuttle.emergency.mode == SHUTTLE_DOCKED || (ENGINES_STARTED))
|
||||
|
||||
#define NOT_BEGUN 0
|
||||
#define STAGE_1 1
|
||||
#define STAGE_2 2
|
||||
#define STAGE_3 3
|
||||
#define STAGE_4 4
|
||||
#define HIJACKED 5
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle
|
||||
name = "emergency shuttle console"
|
||||
desc = "For shuttle control."
|
||||
icon_screen = "shuttle"
|
||||
icon_keyboard = "tech_key"
|
||||
resistance_flags = INDESTRUCTIBLE
|
||||
var/auth_need = 3
|
||||
var/list/authorized = list()
|
||||
var/hijack_last_stage_increase = 0
|
||||
var/hijack_stage_time = 50
|
||||
var/hijack_stage_cooldown = 50
|
||||
var/hijack_flight_time_increase = 300
|
||||
var/hijack_completion_flight_time_set = 100 //How long in deciseconds to set shuttle's timer after hijack is done.
|
||||
var/hijack_hacking = FALSE
|
||||
var/hijack_announce = TRUE
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle/examine(mob/user)
|
||||
. = ..()
|
||||
if(hijack_announce)
|
||||
. += "<span class='danger'>Security systems present on console. Any unauthorized tampering will result in an emergency announcement.</span>"
|
||||
if(user?.mind?.get_hijack_speed())
|
||||
. += "<span class='danger'>Alt click on this to attempt to hijack the shuttle. This will take multiple tries (current: stage [SSshuttle.emergency.hijack_status]/[HIJACKED]).</span>"
|
||||
. += "<span class='notice'>It will take you [(hijack_stage_time * user.mind.get_hijack_speed()) / 10] seconds to reprogram a stage of the shuttle's navigational firmware, and the console will undergo automated timed lockout for [hijack_stage_cooldown/10] seconds after each stage.</span>"
|
||||
if(hijack_announce)
|
||||
. += "<span class='warning'>It is probably best to fortify your position as to be uninterrupted during the attempt, given the automatic announcements..</span>"
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle/attackby(obj/item/I, mob/user,params)
|
||||
if(istype(I, /obj/item/card/id))
|
||||
@@ -133,6 +158,71 @@
|
||||
[TIME_LEFT] seconds", system_error, alert=TRUE)
|
||||
. = TRUE
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle/proc/increase_hijack_stage()
|
||||
var/obj/docking_port/mobile/emergency/shuttle = SSshuttle.emergency
|
||||
shuttle.hijack_status++
|
||||
if(hijack_announce)
|
||||
announce_hijack_stage()
|
||||
hijack_last_stage_increase = world.time
|
||||
say("Navigational protocol error! Rebooting systems.")
|
||||
if(shuttle.mode == SHUTTLE_ESCAPE)
|
||||
if(shuttle.hijack_status == HIJACKED)
|
||||
shuttle.setTimer(hijack_completion_flight_time_set)
|
||||
else
|
||||
shuttle.setTimer(shuttle.timeLeft(1) + hijack_flight_time_increase) //give the guy more time to hijack if it's already in flight.
|
||||
return shuttle.hijack_status
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle/AltClick(user)
|
||||
attempt_hijack_stage(user)
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle/proc/attempt_hijack_stage(mob/living/user)
|
||||
if(!user.CanReach(src))
|
||||
return
|
||||
if(!user?.mind?.get_hijack_speed())
|
||||
to_chat(user, "<span class='warning'>You manage to open a user-mode shell on [src], and hundreds of lines of debugging output fly through your vision. It is probably best to leave this alone.</span.")
|
||||
return
|
||||
if(hijack_hacking == TRUE)
|
||||
return
|
||||
if(SSshuttle.emergency.hijack_status >= HIJACKED)
|
||||
to_chat(user, "<span class='warning'>The emergency shuttle is already loaded with a corrupt navigational payload. What more do you want from it?</span>")
|
||||
return
|
||||
if(hijack_last_stage_increase >= world.time + hijack_stage_cooldown)
|
||||
say("Error - Catastrophic software error detected. Input is currently on timeout.")
|
||||
return
|
||||
hijack_hacking = TRUE
|
||||
to_chat(user, "<span class='boldwarning'>You [SSshuttle.emergency.hijack_status == NOT_BEGUN? "begin" : "continue"] to override [src]'s navigational protocols.</span>")
|
||||
say("Software override initiated.")
|
||||
. = FALSE
|
||||
if(do_after(user, hijack_stage_time * (1 / user.mind.get_hijack_speed()), target = src))
|
||||
increase_hijack_stage()
|
||||
. = TRUE
|
||||
to_chat(user, "<span class='notice'>You reprogram some of [src]'s programming, putting it on timeout for [hijack_stage_cooldown/10] seconds.</span>")
|
||||
hijack_hacking = FALSE
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle/proc/announce_hijack_stage()
|
||||
var/msg
|
||||
switch(SSshuttle.emergency.hijack_status)
|
||||
if(NOT_BEGUN)
|
||||
return
|
||||
if(STAGE_1)
|
||||
var/datum/species/S = new
|
||||
msg = "AUTHENTICATING - FAIL. AUTHENTICATING - FAIL. AUTHENTICATING - FAI###### Welcome, technician JOHN DOE."
|
||||
qdel(S)
|
||||
if(STAGE_2)
|
||||
msg = "Warning: Navigational route fails \"IS_AUTHORIZED\". Please try againNN[scramble_message_replace_chars("againagainagainagainagain", 70)]."
|
||||
if(STAGE_3)
|
||||
var/hex = ""
|
||||
for(var/i in 1 to 8)
|
||||
hex += num2hex(rand(1,16))
|
||||
msg = "CRC mismatch at 0x[hex] in calculated route buffer. Full reset initiated of FTL_NAVIGATION_SERVICES. Memory decrypted for automatic repair."
|
||||
if(STAGE_4)
|
||||
msg = "~ACS_directive module_load(cyberdyne.exploit.nanotrasen.shuttlenav)... NT key mismatch. Confirm load? Y...###Reboot complete. $SET transponder_state = 0; System link initiated with connected engines..."
|
||||
if(HIJACKED)
|
||||
msg = "<font color='red'>SYSTEM OVERRIDE - Resetting course to \[[scramble_message_replace_chars("###########", 100)]\] \
|
||||
([scramble_message_replace_chars("#######", 100)]/[scramble_message_replace_chars("#######", 100)]/[scramble_message_replace_chars("#######", 100)]) \
|
||||
{AUTH - ROOT (uid: 0)}.</font>[SSshuttle.emergency.mode == SHUTTLE_ESCAPE? "Diverting from existing route - Bluespace exit in [hijack_completion_flight_time_set/10] seconds." : ""]"
|
||||
minor_announce(scramble_message_replace_chars(msg, replaceprob = 10), "Emergency Shuttle", TRUE)
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle/emag_act(mob/user)
|
||||
. = ..()
|
||||
|
||||
@@ -185,6 +275,7 @@
|
||||
dir = EAST
|
||||
port_direction = WEST
|
||||
var/sound_played = 0 //If the launch sound has been sent to all players on the shuttle itself
|
||||
var/hijack_status = NOT_BEGUN
|
||||
|
||||
/obj/docking_port/mobile/emergency/canDock(obj/docking_port/stationary/S)
|
||||
return SHUTTLE_CAN_DOCK //If the emergency shuttle can't move, the whole game breaks, so it will force itself to land even if it has to crush a few departments in the process
|
||||
@@ -250,37 +341,7 @@
|
||||
priority_announce("The emergency shuttle has been recalled.[SSshuttle.emergencyLastCallLoc ? " Recall signal traced. Results can be viewed on any communications console." : "" ]", null, "shuttlerecalled", "Priority")
|
||||
|
||||
/obj/docking_port/mobile/emergency/proc/is_hijacked()
|
||||
var/has_people = FALSE
|
||||
var/hijacker_present = FALSE
|
||||
for(var/mob/living/player in GLOB.player_list)
|
||||
if(player.mind)
|
||||
if(player.stat != DEAD)
|
||||
if(issilicon(player)) //Borgs are technically dead anyways
|
||||
continue
|
||||
if(isanimal(player)) //animals don't count
|
||||
continue
|
||||
if(isbrain(player)) //also technically dead
|
||||
continue
|
||||
if(shuttle_areas[get_area(player)])
|
||||
has_people = TRUE
|
||||
var/location = get_turf(player.mind.current)
|
||||
//Non-antag present. Can't hijack.
|
||||
if(!(player.mind.has_antag_datum(/datum/antagonist)) && !istype(location, /turf/open/floor/plasteel/shuttle/red) && !istype(location, /turf/open/floor/mineral/plastitanium/red/brig))
|
||||
return FALSE
|
||||
//Antag present, doesn't stop but let's see if we actually want to hijack
|
||||
var/prevent = FALSE
|
||||
for(var/datum/antagonist/A in player.mind.antag_datums)
|
||||
if(A.can_hijack == HIJACK_HIJACKER)
|
||||
hijacker_present = TRUE
|
||||
prevent = FALSE
|
||||
break //If we have both prevent and hijacker antags assume we want to hijack.
|
||||
else if(A.can_hijack == HIJACK_PREVENT)
|
||||
prevent = TRUE
|
||||
if(prevent)
|
||||
return FALSE
|
||||
|
||||
|
||||
return has_people && hijacker_present
|
||||
return hijack_status == HIJACKED
|
||||
|
||||
/obj/docking_port/mobile/emergency/proc/ShuttleDBStuff()
|
||||
set waitfor = FALSE
|
||||
@@ -422,7 +483,7 @@
|
||||
mode = SHUTTLE_ESCAPE
|
||||
launch_status = ENDGAME_LAUNCHED
|
||||
setTimer(SSshuttle.emergencyEscapeTime)
|
||||
priority_announce("The Emergency Shuttle preparing for direct jump. Estimate [timeLeft(600)] minutes until the shuttle docks at Central Command.", null, null, "Priority")
|
||||
priority_announce("The Emergency Shuttle is preparing for direct jump. Estimate [timeLeft(600)] minutes until the shuttle docks at Central Command.", null, null, "Priority")
|
||||
|
||||
|
||||
/obj/docking_port/mobile/pod
|
||||
@@ -567,3 +628,10 @@
|
||||
#undef ENGINES_START_TIME
|
||||
#undef ENGINES_STARTED
|
||||
#undef IS_DOCKED
|
||||
|
||||
#undef NOT_BEGUN
|
||||
#undef STAGE_1
|
||||
#undef STAGE_2
|
||||
#undef STAGE_3
|
||||
#undef STAGE_4
|
||||
#undef HIJACKED
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "enhancement surgery"
|
||||
var/bioware_target = BIOWARE_GENERIC
|
||||
|
||||
/datum/surgery/advanced/bioware/can_start(mob/user, mob/living/carbon/human/target)
|
||||
/datum/surgery/advanced/bioware/can_start(mob/user, mob/living/carbon/human/target, obj/item/tool)
|
||||
if(!..())
|
||||
return FALSE
|
||||
if(!istype(target))
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
target_mobtypes = list(/mob/living/carbon/human)
|
||||
possible_locs = list(BODY_ZONE_HEAD)
|
||||
|
||||
/datum/surgery/advanced/brainwashing/can_start(mob/user, mob/living/carbon/target)
|
||||
/datum/surgery/advanced/brainwashing/can_start(mob/user, mob/living/carbon/target, obj/item/tool)
|
||||
if(!..())
|
||||
return FALSE
|
||||
var/obj/item/organ/brain/B = target.getorganslot(ORGAN_SLOT_BRAIN)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
|
||||
possible_locs = list(BODY_ZONE_HEAD)
|
||||
requires_bodypart_type = 0
|
||||
/datum/surgery/advanced/lobotomy/can_start(mob/user, mob/living/carbon/target)
|
||||
/datum/surgery/advanced/lobotomy/can_start(mob/user, mob/living/carbon/target, obj/item/tool)
|
||||
if(!..())
|
||||
return FALSE
|
||||
var/obj/item/organ/brain/B = target.getorganslot(ORGAN_SLOT_BRAIN)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
/datum/surgery_step/bionecrosis,
|
||||
/datum/surgery_step/close)
|
||||
possible_locs = list(BODY_ZONE_HEAD)
|
||||
/datum/surgery/advanced/necrotic_revival/can_start(mob/user, mob/living/carbon/target)
|
||||
/datum/surgery/advanced/necrotic_revival/can_start(mob/user, mob/living/carbon/target, obj/item/tool)
|
||||
. = ..()
|
||||
var/obj/item/organ/zombie_infection/ZI = target.getorganslot(ORGAN_SLOT_ZOMBIE)
|
||||
if(ZI)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
|
||||
possible_locs = list(BODY_ZONE_HEAD)
|
||||
requires_bodypart_type = 0
|
||||
/datum/surgery/advanced/pacify/can_start(mob/user, mob/living/carbon/target)
|
||||
/datum/surgery/advanced/pacify/can_start(mob/user, mob/living/carbon/target, obj/item/tool)
|
||||
. = ..()
|
||||
var/obj/item/organ/brain/B = target.getorganslot(ORGAN_SLOT_BRAIN)
|
||||
if(!B)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
|
||||
possible_locs = list(BODY_ZONE_HEAD)
|
||||
requires_bodypart_type = 0
|
||||
/datum/surgery/advanced/revival/can_start(mob/user, mob/living/carbon/target)
|
||||
/datum/surgery/advanced/revival/can_start(mob/user, mob/living/carbon/target, obj/item/tool)
|
||||
if(!..())
|
||||
return FALSE
|
||||
if(target.stat != DEAD)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
|
||||
possible_locs = list(BODY_ZONE_CHEST)
|
||||
/datum/surgery/advanced/viral_bonding/can_start(mob/user, mob/living/carbon/target)
|
||||
/datum/surgery/advanced/viral_bonding/can_start(mob/user, mob/living/carbon/target, obj/item/tool)
|
||||
if(!..())
|
||||
return FALSE
|
||||
if(!LAZYLEN(target.diseases))
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
name = "fix brain"
|
||||
implements = list(TOOL_HEMOSTAT = 85, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15) //don't worry, pouring some alcohol on their open brain will get that chance to 100
|
||||
time = 120 //long and complicated
|
||||
/datum/surgery/brain_surgery/can_start(mob/user, mob/living/carbon/target)
|
||||
/datum/surgery/brain_surgery/can_start(mob/user, mob/living/carbon/target, obj/item/tool)
|
||||
var/obj/item/organ/brain/B = target.getorganslot(ORGAN_SLOT_BRAIN)
|
||||
if(!B)
|
||||
return FALSE
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
lying_required = FALSE
|
||||
ignore_clothes = TRUE
|
||||
|
||||
/datum/surgery/core_removal/can_start(mob/user, mob/living/target)
|
||||
/datum/surgery/core_removal/can_start(mob/user, mob/living/target, obj/item/tool)
|
||||
if(target.stat == DEAD)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
/datum/surgery_step/incise_heart, /datum/surgery_step/coronary_bypass, /datum/surgery_step/close)
|
||||
possible_locs = list(BODY_ZONE_CHEST)
|
||||
|
||||
/datum/surgery/coronary_bypass/can_start(mob/user, mob/living/carbon/target)
|
||||
/datum/surgery/coronary_bypass/can_start(mob/user, mob/living/carbon/target, obj/item/tool)
|
||||
var/obj/item/organ/heart/H = target.getorganslot(ORGAN_SLOT_HEART)
|
||||
if(H)
|
||||
if(H.damage > 60 && !H.operated)
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
requires_tech = FALSE
|
||||
var/value_multiplier = 1
|
||||
|
||||
/datum/surgery/advanced/experimental_dissection/can_start(mob/user, mob/living/target)
|
||||
/datum/surgery/advanced/experimental_dissection/can_start(mob/user, mob/living/target, obj/item/tool)
|
||||
. = ..()
|
||||
if(HAS_TRAIT_FROM(target, TRAIT_DISSECTED,"[name]"))
|
||||
return FALSE
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
name = "fix eyes"
|
||||
implements = list(TOOL_HEMOSTAT = 100, TOOL_SCREWDRIVER = 45, /obj/item/pen = 25)
|
||||
time = 64
|
||||
/datum/surgery/eye_surgery/can_start(mob/user, mob/living/carbon/target)
|
||||
/datum/surgery/eye_surgery/can_start(mob/user, mob/living/carbon/target, obj/item/tool)
|
||||
var/obj/item/organ/eyes/E = target.getorganslot(ORGAN_SLOT_EYES)
|
||||
if(!E)
|
||||
to_chat(user, "It's hard to do surgery on someone's eyes when [target.p_they()] [target.p_do()]n't have any.")
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
continue
|
||||
if(S.lying_required && !(M.lying))
|
||||
continue
|
||||
if(!S.can_start(user, M))
|
||||
if(!S.can_start(user, M, I))
|
||||
continue
|
||||
for(var/path in S.target_mobtypes)
|
||||
if(istype(M, path))
|
||||
@@ -64,7 +64,7 @@
|
||||
return
|
||||
if(S.lying_required && !(M.lying))
|
||||
return
|
||||
if(!S.can_start(user, M))
|
||||
if(!S.can_start(user, M, I))
|
||||
return
|
||||
|
||||
if(S.ignore_clothes || get_location_accessible(M, selected_zone))
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "Lipoplasty"
|
||||
steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/cut_fat, /datum/surgery_step/remove_fat, /datum/surgery_step/close)
|
||||
possible_locs = list(BODY_ZONE_CHEST)
|
||||
/datum/surgery/lipoplasty/can_start(mob/user, mob/living/carbon/target)
|
||||
/datum/surgery/lipoplasty/can_start(mob/user, mob/living/carbon/target, obj/item/tool)
|
||||
if(HAS_TRAIT(target, TRAIT_FAT))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
/datum/surgery_step/lobectomy, /datum/surgery_step/close)
|
||||
possible_locs = list(BODY_ZONE_CHEST)
|
||||
|
||||
/datum/surgery/lobectomy/can_start(mob/user, mob/living/carbon/target)
|
||||
/datum/surgery/lobectomy/can_start(mob/user, mob/living/carbon/target, obj/item/tool)
|
||||
var/obj/item/organ/lungs/L = target.getorganslot(ORGAN_SLOT_LUNGS)
|
||||
if(L)
|
||||
if(L.damage > 60 && !L.operated)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
possible_locs = list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG, BODY_ZONE_HEAD)
|
||||
requires_bodypart = FALSE //need a missing limb
|
||||
requires_bodypart_type = 0
|
||||
/datum/surgery/prosthetic_replacement/can_start(mob/user, mob/living/carbon/target)
|
||||
/datum/surgery/prosthetic_replacement/can_start(mob/user, mob/living/carbon/target, obj/item/tool)
|
||||
if(!iscarbon(target))
|
||||
return 0
|
||||
var/mob/living/carbon/C = target
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/surgery/proc/can_start(mob/user, mob/living/patient) //FALSE to not show in list
|
||||
/datum/surgery/proc/can_start(mob/user, mob/living/patient, obj/item/tool) //FALSE to not show in list
|
||||
. = TRUE
|
||||
if(replaced_by == /datum/surgery)
|
||||
return FALSE
|
||||
@@ -55,27 +55,26 @@
|
||||
if(requires_tech)
|
||||
. = FALSE
|
||||
|
||||
var/list/advanced_surgeries = list()
|
||||
if(iscyborg(user))
|
||||
var/mob/living/silicon/robot/R = user
|
||||
var/obj/item/surgical_processor/SP = locate() in R.module.modules
|
||||
if(SP)
|
||||
if (replaced_by in SP.advanced_surgeries)
|
||||
return .
|
||||
if(type in SP.advanced_surgeries)
|
||||
return TRUE
|
||||
|
||||
advanced_surgeries |= SP.advanced_surgeries
|
||||
|
||||
var/turf/T = get_turf(patient)
|
||||
var/obj/structure/table/optable/table = locate(/obj/structure/table/optable, T)
|
||||
if(table)
|
||||
if(!table.computer)
|
||||
return .
|
||||
if(table.computer.stat & (NOPOWER|BROKEN))
|
||||
return .
|
||||
if(replaced_by in table.computer.advanced_surgeries)
|
||||
return FALSE
|
||||
if(type in table.computer.advanced_surgeries)
|
||||
return TRUE
|
||||
if(table?.computer && !CHECK_BITFIELD(table.computer.stat, NOPOWER|BROKEN))
|
||||
advanced_surgeries |= table.computer.advanced_surgeries
|
||||
|
||||
if(istype(tool, /obj/item/surgical_drapes/advanced))
|
||||
var/obj/item/surgical_drapes/advanced/A = tool
|
||||
advanced_surgeries |= A.get_advanced_surgeries()
|
||||
|
||||
if(replaced_by in advanced_surgeries)
|
||||
return FALSE
|
||||
if(type in advanced_surgeries)
|
||||
return TRUE
|
||||
|
||||
/datum/surgery/proc/next_step(mob/user, intent)
|
||||
if(step_in_progress)
|
||||
|
||||
@@ -287,6 +287,26 @@
|
||||
if(!attempt_initiate_surgery(src, M, user))
|
||||
..()
|
||||
|
||||
/obj/item/surgical_drapes/advanced
|
||||
name = "smart surgical drapes"
|
||||
desc = "A quite quirky set of drapes with wireless synchronization to the station's research networks, with an integrated display allowing users to execute advanced surgeries without the aid of an operating computer."
|
||||
var/datum/techweb/linked_techweb
|
||||
|
||||
/obj/item/surgical_drapes/advanced/Initialize(mapload)
|
||||
. = ..()
|
||||
linked_techweb = SSresearch.science_tech
|
||||
|
||||
/obj/item/surgical_drapes/advanced/proc/get_advanced_surgeries()
|
||||
. = list()
|
||||
if(!linked_techweb)
|
||||
return
|
||||
for(var/subtype in subtypesof(/datum/design/surgery))
|
||||
var/datum/design/surgery/prototype = subtype
|
||||
var/id = initial(prototype.id)
|
||||
if(id in linked_techweb.researched_designs)
|
||||
prototype = SSresearch.techweb_design_by_id(id)
|
||||
. |= prototype.surgery
|
||||
|
||||
/obj/item/organ_storage //allows medical cyborgs to manipulate organs without hands
|
||||
name = "organ storage bag"
|
||||
desc = "A container for holding body parts."
|
||||
|
||||
@@ -266,16 +266,17 @@
|
||||
/obj/item/cartridge/janitor = 3,
|
||||
/obj/item/clothing/gloves/color/black = 2,
|
||||
/obj/item/clothing/head/soft/purple = 2,
|
||||
/obj/item/twohanded/broom = 2,
|
||||
/obj/item/paint/paint_remover = 2,
|
||||
/obj/item/melee/flyswatter = 1,
|
||||
/obj/item/melee/flyswatter = 2,
|
||||
/obj/item/flashlight = 2,
|
||||
/obj/item/caution = 8,
|
||||
/obj/item/holosign_creator = 1,
|
||||
/obj/item/lightreplacer = 1,
|
||||
/obj/item/soap = 1,
|
||||
/obj/item/storage/bag/trash = 1,
|
||||
/obj/item/clothing/shoes/galoshes = 1,
|
||||
/obj/item/watertank/janitor = 1,
|
||||
/obj/item/holosign_creator = 2,
|
||||
/obj/item/lightreplacer = 2,
|
||||
/obj/item/soap = 2,
|
||||
/obj/item/storage/bag/trash = 2,
|
||||
/obj/item/clothing/shoes/galoshes = 2,
|
||||
/obj/item/watertank/janitor = 2,
|
||||
/obj/item/storage/belt/janitor = 2,
|
||||
/obj/item/screwdriver = 2,
|
||||
/obj/item/stack/cable_coil/random = 4)
|
||||
|
||||
@@ -384,6 +384,9 @@
|
||||
if(!istype(tasted))
|
||||
return
|
||||
|
||||
if(!tasted.client?.prefs_vr.lickable)
|
||||
return
|
||||
|
||||
if(src == stat)
|
||||
return
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ GLOBAL_LIST_EMPTY(vore_preferences_datums)
|
||||
var/digestable = FALSE
|
||||
var/devourable = FALSE
|
||||
var/feeding = FALSE
|
||||
var/lickable = FALSE
|
||||
// var/allowmobvore = TRUE
|
||||
var/list/belly_prefs = list()
|
||||
var/vore_taste = "nothing in particular"
|
||||
|
||||
@@ -242,22 +242,13 @@
|
||||
dat += "<a href='?src=\ref[src];applyprefs=1'>Reload Slot Prefs</a>"
|
||||
|
||||
dat += "<HR>"
|
||||
switch(user.digestable)
|
||||
if(TRUE)
|
||||
dat += "<br><a style='background:#173d15;' href='?src=\ref[src];toggledg=1'>Toggle Digestable (Currently: ON)</a>"
|
||||
if(FALSE)
|
||||
dat += "<br><a style='background:#990000;' href='?src=\ref[src];toggledg=1'>Toggle Digestable (Currently: OFF)</a>"
|
||||
switch(user.devourable)
|
||||
if(TRUE)
|
||||
dat += "<br><a style='background:#173d15;' href='?src=\ref[src];toggledvor=1'>Toggle Devourable (Currently: ON)</a>"
|
||||
if(FALSE)
|
||||
dat += "<br><a style='background:#990000;' href='?src=\ref[src];toggledvor=1'>Toggle Devourable (Currently: OFF)</a>"
|
||||
switch(user.feeding)
|
||||
if(TRUE)
|
||||
dat += "<br><a style='background:#173d15;' href='?src=\ref[src];toggledfeed=1'>Toggle Feeding (Currently: ON)</a>"
|
||||
if(FALSE)
|
||||
dat += "<br><a style='background:#990000;' href='?src=\ref[src];toggledfeed=1'>Toggle Feeding (Currently: OFF)</a>"
|
||||
|
||||
var/pref_on = "#173d15"
|
||||
var/pref_off = "#990000"
|
||||
dat += "<br><a style='background:[user.digestable ? pref_on : pref_off];' href='?src=\ref[src];toggledg=1'>Toggle Digestable (Currently: [user.digestable ? "ON" : "OFF"])</a>"
|
||||
dat += "<br><a style='background:[user.devourable ? pref_on : pref_off];' href='?src=\ref[src];toggledvor=1'>Toggle Devourable (Currently: [user.devourable ? "ON" : "OFF"])</a>"
|
||||
dat += "<br><a style='background:[user.feeding ? pref_on : pref_off];' href='?src=\ref[src];toggledfeed=1'>Toggle Feeding (Currently: [user.feeding ? "ON" : "OFF"])</a>"
|
||||
if(user.client.prefs_vr)
|
||||
dat += "<br><a style='background:[user.client.prefs_vr.lickable ? pref_on : pref_off];' href='?src=\ref[src];toggledlickable=1'>Toggle Licking (Currently: [user.client.prefs_vr.lickable ? "ON" : "OFF"])</a>"
|
||||
//Returns the dat html to the vore_look
|
||||
return dat
|
||||
|
||||
@@ -734,5 +725,16 @@
|
||||
if(user.client.prefs_vr)
|
||||
user.client.prefs_vr.feeding = user.feeding
|
||||
|
||||
if(href_list["toggledlickable"])
|
||||
if(user.client.prefs_vr)
|
||||
var/choice = alert(user, "This button is to toggle your ability to be licked. Being licked is currently: [user.client.prefs_vr.lickable ? "Allowed" : "Prevented"]", "", "Allow Licking", "Cancel", "Prevent Licking")
|
||||
switch(choice)
|
||||
if("Cancel")
|
||||
return FALSE
|
||||
if("Allow Licking")
|
||||
user.client.prefs_vr.lickable = TRUE
|
||||
if("Prevent Licking")
|
||||
user.client.prefs_vr.lickable = FALSE
|
||||
|
||||
//Refresh when interacted with, returning 1 makes vore_look.Topic update
|
||||
return TRUE
|
||||
return TRUE
|
||||
|
||||
Reference in New Issue
Block a user