Merge remote-tracking branch 'upstream/dev' into sprites

Conflicts:
	icons/mob/items_lefthand.dmi
	icons/mob/items_righthand.dmi
This commit is contained in:
Hubblenaut
2015-02-16 16:16:30 +01:00
878 changed files with 17541 additions and 51430 deletions
+13 -7
View File
@@ -26,7 +26,7 @@
/mob/dead/observer/New(mob/body)
sight |= SEE_TURFS | SEE_MOBS | SEE_OBJS | SEE_SELF
see_invisible = SEE_INVISIBLE_OBSERVER
see_invisible = SEE_INVISIBLE_OBSERVER_AI_EYE
see_in_dark = 100
verbs += /mob/dead/observer/proc/dead_tele
@@ -404,14 +404,20 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
src << "\blue Heat Capacity: [round(environment.heat_capacity(),0.1)]"
/mob/dead/observer/verb/toggle_darkness()
set name = "Toggle Darkness"
/mob/dead/observer/verb/toggle_sight()
set name = "Toggle Sight"
set category = "Ghost"
if (see_invisible == SEE_INVISIBLE_OBSERVER_NOLIGHTING)
see_invisible = SEE_INVISIBLE_OBSERVER
else
see_invisible = SEE_INVISIBLE_OBSERVER_NOLIGHTING
switch(see_invisible)
if(SEE_INVISIBLE_OBSERVER_AI_EYE)
see_invisible = SEE_INVISIBLE_OBSERVER_NOOBSERVERS
usr << "<span class='notice'>You no longer see other observers or the AI eye.</span>"
if(SEE_INVISIBLE_OBSERVER_NOOBSERVERS)
see_invisible = SEE_INVISIBLE_OBSERVER_NOLIGHTING
usr << "<span class='notice'>You no longer see darkness.</span>"
else
see_invisible = SEE_INVISIBLE_OBSERVER_AI_EYE
usr << "<span class='notice'>You again see everything.</span>"
/mob/dead/observer/verb/become_mouse()
set name = "Become mouse"
+2
View File
@@ -52,6 +52,8 @@
if(stat == DEAD)
return 0
facing_dir = null
if(!gibbed && deathmessage != "no message") // This is gross, but reliable. Only brains use it.
src.visible_message("<b>\The [src.name]</b> [deathmessage]")
+2 -2
View File
@@ -12,7 +12,7 @@
var/input
if(!message)
input = copytext(sanitize(input(src,"Choose an emote to display.") as text|null),1,MAX_MESSAGE_LEN)
input = sanitize(copytext(input(src,"Choose an emote to display.") as text|null,1,MAX_MESSAGE_LEN))
else
input = message
if(input)
@@ -108,7 +108,7 @@
var/input
if(!message)
input = copytext(sanitize(input(src, "Choose an emote to display.") as text|null), 1, MAX_MESSAGE_LEN)
input = sanitize(copytext(input(src, "Choose an emote to display.") as text|null, 1, MAX_MESSAGE_LEN))
else
input = message
+38 -11
View File
@@ -67,13 +67,19 @@
src << "<span class='name'>[speaker_name]</span>[alt_name] talks but you cannot hear \him."
else
if(language)
src << "<span class='game say'><span class='name'>[speaker_name]</span>[alt_name] [track][language.format_message(message, verb)]</span>"
on_hear_say("<span class='game say'><span class='name'>[speaker_name]</span>[alt_name] [track][language.format_message(message, verb)]</span>")
else
src << "<span class='game say'><span class='name'>[speaker_name]</span>[alt_name] [track][verb], <span class='message'><span class='body'>\"[message]\"</span></span></span>"
on_hear_say("<span class='game say'><span class='name'>[speaker_name]</span>[alt_name] [track][verb], <span class='message'><span class='body'>\"[message]\"</span></span></span>")
if (speech_sound && (get_dist(speaker, src) <= world.view && src.z == speaker.z))
var/turf/source = speaker? get_turf(speaker) : get_turf(src)
src.playsound_local(source, speech_sound, sound_vol, 1)
/mob/proc/on_hear_say(var/message)
src << message
/mob/living/silicon/on_hear_say(var/message)
var/time = say_timestamp()
src << "[time] [message]"
/mob/proc/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/mob/speaker = null, var/hard_to_hear = 0, var/vname ="")
@@ -101,7 +107,7 @@
return
else
if(language)
message = language.scramble(language)
message = language.scramble(message)
else
message = stars(message)
@@ -125,17 +131,26 @@
if(istype(src, /mob/living/silicon/ai) && !hard_to_hear)
var/jobname // the mob's "job"
var/mob/living/carbon/human/impersonating //The crewmember being impersonated, if any.
var/mob/living/carbon/human/impersonating //The crew member being impersonated, if any.
if (ishuman(speaker))
var/mob/living/carbon/human/H = speaker
if((H.wear_id && istype(H.wear_id,/obj/item/weapon/card/id/syndicate)) && (H.wear_mask && istype(H.wear_mask,/obj/item/clothing/mask/gas/voice)))
if(H.wear_mask && istype(H.wear_mask,/obj/item/clothing/mask/gas/voice))
changed_voice = 1
var/mob/living/carbon/human/I = locate(speaker_name)
var/list/impersonated = new()
var/mob/living/carbon/human/I = impersonated[speaker_name]
if(I)
if(!I)
for(var/mob/living/carbon/human/M in mob_list)
if(M.real_name == speaker_name)
I = M
impersonated[speaker_name] = I
break
// If I's display name is currently different from the voice name and using an agent ID then don't impersonate
// as this would allow the AI to track I and realize the mismatch.
if(I && !(I.name != speaker_name && I.wear_id && istype(I.wear_id,/obj/item/weapon/card/id/syndicate)))
impersonating = I
jobname = impersonating.get_assignment()
else
@@ -175,10 +190,22 @@
if(sdisabilities & DEAF || ear_deaf)
if(prob(20))
src << "<span class='warning'>You feel your headset vibrate but can hear nothing from it!</span>"
else if(track)
src << "[part_a][track][part_b][formatted]</span></span>"
else
src << "[part_a][speaker_name][part_b][formatted]</span></span>"
on_hear_radio(part_a, speaker_name, track, part_b, formatted)
/proc/say_timestamp()
return "<span class='say_quote'>\[[worldtime2text()]\]</span>"
/mob/proc/on_hear_radio(part_a, speaker_name, track, part_b, formatted)
src << "[part_a][speaker_name][part_b][formatted]</span></span>"
/mob/living/silicon/on_hear_radio(part_a, speaker_name, track, part_b, formatted)
var/time = say_timestamp()
src << "[time][part_a][speaker_name][part_b][formatted]</span></span>"
/mob/living/silicon/ai/on_hear_radio(part_a, speaker_name, track, part_b, formatted)
var/time = say_timestamp()
src << "[time][part_a][track][part_b][formatted]</span></span>"
/mob/proc/hear_signlang(var/message, var/verb = "gestures", var/datum/language/language, var/mob/speaker = null)
if(!client)
+2 -1
View File
@@ -40,8 +40,9 @@
/mob/living/var/holder_type
/mob/living/proc/get_scooped(var/mob/living/carbon/grabber)
if(!holder_type)
if(!holder_type || buckled || pinned.len)
return
var/obj/item/weapon/holder/H = new holder_type(loc)
src.loc = H
H.name = loc.name
+22 -1
View File
@@ -1,3 +1,5 @@
#define SCRAMBLE_CACHE_LEN 20
/*
Datum based languages. Easily editable and modular.
*/
@@ -35,11 +37,21 @@
return "[trim(full_name)]"
/datum/language
var/list/scramble_cache = list()
/datum/language/proc/scramble(var/input)
if(!syllables || !syllables.len)
return stars(input)
// If the input is cached already, move it to the end of the cache and return it
if(input in scramble_cache)
var/n = scramble_cache[input]
scramble_cache -= input
scramble_cache[input] = n
return n
var/input_size = length(input)
var/scrambled_text = ""
var/capitalize = 1
@@ -64,6 +76,13 @@
var/input_ending = copytext(input, input_size)
if(input_ending in list("!","?","."))
scrambled_text += input_ending
// Add it to cache, cutting old entries if the list is too long
scramble_cache[input] = scrambled_text
if(scramble_cache.len > SCRAMBLE_CACHE_LEN)
scramble_cache.Cut(1, scramble_cache.len-SCRAMBLE_CACHE_LEN-1)
return scrambled_text
/datum/language/proc/format_message(message, verb)
@@ -496,4 +515,6 @@
"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it",
"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to",
"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin",
"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi")
"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi")
#undef SCRAMBLE_CACHE_LEN
@@ -7,6 +7,7 @@
pass_flags = PASSTABLE
health = 100
maxHealth = 100
mob_size = 4
var/adult_form
var/dead_icon
@@ -3,7 +3,6 @@
health = 400 //They need to live awhile longer than other organs.
desc = "A piece of juicy meat found in a person's head."
icon_state = "brain2"
flags = TABLEPASS
force = 1.0
w_class = 2.0
throwforce = 1.0
+4
View File
@@ -1,6 +1,8 @@
/mob/living/carbon/Life()
..()
handle_viruses()
// Increase germ_level regularly
if(germ_level < GERM_LEVEL_AMBIENT && prob(30)) //if you're just standing there, you shouldn't get more germs beyond an ambient level
germ_level++
@@ -354,6 +356,8 @@
else if (W == handcuffed)
handcuffed = null
update_inv_handcuffed()
if(buckled && buckled.buckle_require_restraints)
buckled.unbuckle_mob()
else if (W == legcuffed)
legcuffed = null
@@ -3,7 +3,7 @@
var/datum/species/species //Contains icon generation and language information, set during New().
var/list/stomach_contents = list()
var/list/datum/disease2/disease/virus2 = list()
var/antibodies = 0
var/list/antibodies = list()
var/last_eating = 0 //Not sure what this does... I found it hidden in food.dm
var/life_tick = 0 // The amount of life ticks that have processed on this mob.
+23 -27
View File
@@ -1,18 +1,14 @@
/mob/living/carbon/verb/give()
mob/living/carbon/verb/give(var/mob/living/carbon/target in view(1)-usr)
set category = "IC"
set name = "Give"
set src in view(1)
if(src.stat == 2 || usr.stat == 2 || src.client == null)
return
if(src == usr)
usr << "\red I feel stupider, suddenly."
if(target.stat == 2 || usr.stat == 2|| target.client == null)
return
var/obj/item/I
if(!usr.hand && usr.r_hand == null)
usr << "\red You don't have anything in your right hand to give to [src.name]"
usr << "<span class='warning'>You don't have anything in your right hand to give to [target.name]</span>"
return
if(usr.hand && usr.l_hand == null)
usr << "\red You don't have anything in your left hand to give to [src.name]"
usr << "<span class='warning'>You don't have anything in your left hand to give to [target.name]</span>"
return
if(usr.hand)
I = usr.l_hand
@@ -20,38 +16,38 @@
I = usr.r_hand
if(!I)
return
if(src.r_hand == null || src.l_hand == null)
switch(alert(src,"[usr] wants to give you \a [I]?",,"Yes","No"))
if(target.r_hand == null || target.l_hand == null)
switch(alert(target,"[usr] wants to give you \a [I]?",,"Yes","No"))
if("Yes")
if(!I)
return
if(!Adjacent(usr))
usr << "\red You need to stay in reaching distance while giving an object."
src << "\red [usr.name] moved too far away."
usr << "<span class='warning'>You need to stay in reaching distance while giving an object.</span>"
target << "<span class='warning'>[usr.name] moved too far away.</span>"
return
if((usr.hand && usr.l_hand != I) || (!usr.hand && usr.r_hand != I))
usr << "\red You need to keep the item in your active hand."
src << "\red [usr.name] seem to have given up on giving \the [I.name] to you."
usr << "<span class='warning'>You need to keep the item in your active hand.</span>"
target << "<span class='warning'>[usr.name] seem to have given up on giving \the [I.name] to you.</span>"
return
if(src.r_hand != null && src.l_hand != null)
src << "\red Your hands are full."
usr << "\red Their hands are full."
if(target.r_hand != null && target.l_hand != null)
target << "<span class='warning'>Your hands are full.</span>"
usr << "<span class='warning'>Their hands are full.</span>"
return
else
usr.drop_item()
if(src.r_hand == null)
src.r_hand = I
if(target.r_hand == null)
target.r_hand = I
else
src.l_hand = I
I.loc = src
target.l_hand = I
I.loc = target
I.layer = 20
I.add_fingerprint(src)
src.update_inv_l_hand()
src.update_inv_r_hand()
I.add_fingerprint(target)
target.update_inv_l_hand()
target.update_inv_r_hand()
usr.update_inv_l_hand()
usr.update_inv_r_hand()
src.visible_message("\blue [usr.name] handed \the [I.name] to [src.name].")
target.visible_message("<span class='notice'>[usr.name] handed \the [I.name] to [target.name].</span>")
if("No")
src.visible_message("\red [usr.name] tried to hand [I.name] to [src.name] but [src.name] didn't want it.")
target.visible_message("<span class='warning'>[usr.name] tried to hand [I.name] to [target.name] but [target.name] didn't want it.</span>")
else
usr << "\red [src.name]'s hands are full."
usr << "<span class='warning'>[target.name]'s hands are full.</span>"
@@ -0,0 +1,149 @@
// MEDICAL SIDE EFFECT BASE
// ========================
/datum/medical_effect
var/name = "None"
var/strength = 0
var/start = 0
var/list/triggers
var/list/cures
var/cure_message
/datum/medical_effect/proc/manifest(mob/living/carbon/human/H)
for(var/R in cures)
if(H.reagents.has_reagent(R))
return 0
for(var/R in triggers)
if(H.reagents.get_reagent_amount(R) >= triggers[R])
return 1
return 0
/datum/medical_effect/proc/on_life(mob/living/carbon/human/H, strength)
return
/datum/medical_effect/proc/cure(mob/living/carbon/human/H)
for(var/R in cures)
if(H.reagents.has_reagent(R))
if (cure_message)
H <<"\blue [cure_message]"
return 1
return 0
// MOB HELPERS
// ===========
/mob/living/carbon/human/var/list/datum/medical_effect/side_effects = list()
/mob/proc/add_side_effect(name, strength = 0)
/mob/living/carbon/human/add_side_effect(name, strength = 0)
for(var/datum/medical_effect/M in src.side_effects)
if(M.name == name)
M.strength = max(M.strength, 10)
M.start = life_tick
return
var/T = side_effects[name]
if (!T)
return
var/datum/medical_effect/M = new T
if(M.name == name)
M.strength = strength
M.start = life_tick
side_effects += M
/mob/living/carbon/human/proc/handle_medical_side_effects()
//Going to handle those things only every few ticks.
if(life_tick % 15 != 0)
return 0
var/list/L = typesof(/datum/medical_effect)-/datum/medical_effect
for(var/T in L)
var/datum/medical_effect/M = new T
if (M.manifest(src))
src.add_side_effect(M.name)
// One full cycle(in terms of strength) every 10 minutes
for (var/datum/medical_effect/M in side_effects)
if (!M) continue
var/strength_percent = sin((life_tick - M.start) / 2)
// Only do anything if the effect is currently strong enough
if(strength_percent >= 0.4)
if (M.cure(src) || M.strength > 50)
side_effects -= M
M = null
else
if(life_tick % 45 == 0)
M.on_life(src, strength_percent*M.strength)
// Effect slowly growing stronger
M.strength+=0.08
// HEADACHE
// ========
/datum/medical_effect/headache
name = "Headache"
triggers = list("cryoxadone" = 10, "bicaridine" = 15, "tricordrazine" = 15)
cures = list("alkysine", "tramadol", "paracetamol", "oxycodone")
cure_message = "Your head stops throbbing..."
/datum/medical_effect/headache/on_life(mob/living/carbon/human/H, strength)
switch(strength)
if(1 to 10)
H.custom_pain("You feel a light pain in your head.",0)
if(11 to 30)
H.custom_pain("You feel a throbbing pain in your head!",1)
if(31 to INFINITY)
H.custom_pain("You feel an excrutiating pain in your head!",1)
// BAD STOMACH
// ===========
/datum/medical_effect/bad_stomach
name = "Bad Stomach"
triggers = list("kelotane" = 30, "dermaline" = 15)
cures = list("anti_toxin")
cure_message = "Your stomach feels a little better now..."
/datum/medical_effect/bad_stomach/on_life(mob/living/carbon/human/H, strength)
switch(strength)
if(1 to 10)
H.custom_pain("You feel a bit light around the stomach.",0)
if(11 to 30)
H.custom_pain("Your stomach hurts.",0)
if(31 to INFINITY)
H.custom_pain("You feel sick.",1)
// CRAMPS
// ======
/datum/medical_effect/cramps
name = "Cramps"
triggers = list("anti_toxin" = 30, "tramadol" = 15)
cures = list("inaprovaline")
cure_message = "The cramps let up..."
/datum/medical_effect/cramps/on_life(mob/living/carbon/human/H, strength)
switch(strength)
if(1 to 10)
H.custom_pain("The muscles in your body hurt a little.",0)
if(11 to 30)
H.custom_pain("The muscles in your body cramp up painfully.",0)
if(31 to INFINITY)
H.emote("me",1,"flinches as all the muscles in their body cramp up.")
H.custom_pain("There's pain all over your body.",1)
// ITCH
// ====
/datum/medical_effect/itch
name = "Itch"
triggers = list("space_drugs" = 10)
cures = list("inaprovaline")
cure_message = "The itching stops..."
/datum/medical_effect/itch/on_life(mob/living/carbon/human/H, strength)
switch(strength)
if(1 to 10)
H.custom_pain("You feel a slight itch.",0)
if(11 to 30)
H.custom_pain("You want to scratch your itch badly.",0)
if(31 to INFINITY)
H.emote("me",1,"shivers slightly.")
H.custom_pain("This itch makes it really hard to concentrate.",1)
@@ -0,0 +1,149 @@
// MEDICAL SIDE EFFECT BASE
// ========================
/datum/medical_effect
var/name = "None"
var/strength = 0
var/start = 0
var/list/triggers
var/list/cures
var/cure_message
/datum/medical_effect/proc/manifest(mob/living/carbon/human/H)
for(var/R in cures)
if(H.reagents.has_reagent(R))
return 0
for(var/R in triggers)
if(H.reagents.get_reagent_amount(R) >= triggers[R])
return 1
return 0
/datum/medical_effect/proc/on_life(mob/living/carbon/human/H, strength)
return
/datum/medical_effect/proc/cure(mob/living/carbon/human/H)
for(var/R in cures)
if(H.reagents.has_reagent(R))
if (cure_message)
H <<"\blue [cure_message]"
return 1
return 0
// MOB HELPERS
// ===========
/mob/living/carbon/human/var/list/datum/medical_effect/side_effects = list()
/mob/proc/add_side_effect(name, strength = 0)
/mob/living/carbon/human/add_side_effect(name, strength = 0)
for(var/datum/medical_effect/M in src.side_effects)
if(M.name == name)
M.strength = max(M.strength, 10)
M.start = life_tick
return
var/T = side_effects[name]
if (!T)
return
var/datum/medical_effect/M = new T
if(M.name == name)
M.strength = strength
M.start = life_tick
side_effects += M
/mob/living/carbon/human/proc/handle_medical_side_effects()
//Going to handle those things only every few ticks.
if(life_tick % 15 != 0)
return 0
var/list/L = typesof(/datum/medical_effect)-/datum/medical_effect
for(var/T in L)
var/datum/medical_effect/M = new T
if (M.manifest(src))
src.add_side_effect(M.name)
// One full cycle(in terms of strength) every 10 minutes
for (var/datum/medical_effect/M in side_effects)
if (!M) continue
var/strength_percent = sin((life_tick - M.start) / 2)
// Only do anything if the effect is currently strong enough
if(strength_percent >= 0.4)
if (M.cure(src) || M.strength > 50)
side_effects -= M
M = null
else
if(life_tick % 45 == 0)
M.on_life(src, strength_percent*M.strength)
// Effect slowly growing stronger
M.strength+=0.08
// HEADACHE
// ========
/datum/medical_effect/headache
name = "Headache"
triggers = list("cryoxadone" = 10, "bicaridine" = 15, "tricordrazine" = 15)
cures = list("alkysine", "tramadol", "paracetamol", "oxycodone")
cure_message = "Your head stops throbbing..."
/datum/medical_effect/headache/on_life(mob/living/carbon/human/H, strength)
switch(strength)
if(1 to 10)
H.custom_pain("You feel a light pain in your head.",0)
if(11 to 30)
H.custom_pain("You feel a throbbing pain in your head!",1)
if(31 to INFINITY)
H.custom_pain("You feel an excrutiating pain in your head!",1)
// BAD STOMACH
// ===========
/datum/medical_effect/bad_stomach
name = "Bad Stomach"
triggers = list("kelotane" = 30, "dermaline" = 15)
cures = list("anti_toxin")
cure_message = "Your stomach feels a little better now..."
/datum/medical_effect/bad_stomach/on_life(mob/living/carbon/human/H, strength)
switch(strength)
if(1 to 10)
H.custom_pain("You feel a bit light around the stomach.",0)
if(11 to 30)
H.custom_pain("Your stomach hurts.",0)
if(31 to INFINITY)
H.custom_pain("You feel sick.",1)
// CRAMPS
// ======
/datum/medical_effect/cramps
name = "Cramps"
triggers = list("anti_toxin" = 30, "tramadol" = 15)
cures = list("inaprovaline")
cure_message = "The cramps let up..."
/datum/medical_effect/cramps/on_life(mob/living/carbon/human/H, strength)
switch(strength)
if(1 to 10)
H.custom_pain("The muscles in your body hurt a little.",0)
if(11 to 30)
H.custom_pain("The muscles in your body cramp up painfully.",0)
if(31 to INFINITY)
H.emote("me",1,"flinches as all the muscles in their body cramp up.")
H.custom_pain("There's pain all over your body.",1)
// ITCH
// ====
/datum/medical_effect/itch
name = "Itch"
triggers = list("space_drugs" = 10)
cures = list("inaprovaline")
cure_message = "The itching stops..."
/datum/medical_effect/itch/on_life(mob/living/carbon/human/H, strength)
switch(strength)
if(1 to 10)
H.custom_pain("You feel a slight itch.",0)
if(11 to 30)
H.custom_pain("You want to scratch your itch badly.",0)
if(31 to INFINITY)
H.emote("me",1,"shivers slightly.")
H.custom_pain("This itch makes it really hard to concentrate.",1)
@@ -28,8 +28,9 @@
if(stat == DEAD) return
hud_updateflag |= 1 << HEALTH_HUD
hud_updateflag |= 1 << STATUS_HUD
BITSET(hud_updateflag, HEALTH_HUD)
BITSET(hud_updateflag, STATUS_HUD)
handle_hud_list()
//Handle species-specific deaths.
@@ -50,7 +50,7 @@
m_type = 1
if ("custom")
var/input = copytext(sanitize(input("Choose an emote to display.") as text|null),1,MAX_MESSAGE_LEN)
var/input = sanitize(copytext(input("Choose an emote to display.") as text|null,1,MAX_MESSAGE_LEN))
if (!input)
return
var/input2 = input("Is this a visible or hearable emote?") in list("Visible","Hearable")
@@ -577,7 +577,7 @@
set desc = "Sets a description which will be shown when someone examines you."
set category = "IC"
pose = copytext(sanitize(input(usr, "This is [src]. \He is...", "Pose", null) as text), 1, MAX_MESSAGE_LEN)
pose = sanitize(copytext(input(usr, "This is [src]. \He is...", "Pose", null) as text, 1, MAX_MESSAGE_LEN))
/mob/living/carbon/human/verb/set_flavor()
set name = "Set Flavour Text"
@@ -63,8 +63,8 @@
var/tie_msg
if(istype(w_uniform,/obj/item/clothing/under))
var/obj/item/clothing/under/U = w_uniform
if(U.hastie)
tie_msg += " with \icon[U.hastie] \a [U.hastie]"
if(U.accessories.len)
tie_msg += " with [lowertext(english_list(U.accessories))]"
if(w_uniform.blood_DNA)
msg += "<span class='warning'>[t_He] [t_is] wearing \icon[w_uniform] [w_uniform.gender==PLURAL?"some":"a"] [(w_uniform.blood_color != "#030303") ? "blood" : "oil"]-stained [w_uniform.name][tie_msg]!</span>\n"
@@ -131,6 +131,10 @@
else
msg += "<span class='warning'>[t_He] [t_is] \icon[handcuffed] handcuffed!</span>\n"
//buckled
if(buckled)
msg += "<span class='warning'>[t_He] [t_is] \icon[buckled] buckled to [buckled]!</span>\n"
//belt
if(belt)
if(belt.blood_DNA)
@@ -219,7 +223,10 @@
usr << "<span class='deadsay'>[t_He] has no pulse[src.client ? "" : " and [t_his] soul has departed"]...</span>"
else
usr << "<span class='deadsay'>[t_He] has a pulse!</span>"
if(fire_stacks)
msg += "[t_He] [t_is] covered in some liquid.\n"
if(on_fire)
msg += "<span class='warning'>[t_He] [t_is] on fire!.</span>\n"
msg += "<span class='warning'>"
if(nutrition < 100)
+10 -9
View File
@@ -241,7 +241,7 @@
<BR><B>Suit Storage:</B> <A href='?src=\ref[src];item=s_store'>[(s_store ? s_store : "Nothing")]</A> [((istype(wear_mask, /obj/item/clothing/mask) && istype(s_store, /obj/item/weapon/tank) && !( internal )) ? text(" <A href='?src=\ref[];item=internal'>Set Internal</A>", src) : "")]
<BR>[(handcuffed ? text("<A href='?src=\ref[src];item=handcuff'>Handcuffed</A>") : text("<A href='?src=\ref[src];item=handcuff'>Not Handcuffed</A>"))]
<BR>[(legcuffed ? text("<A href='?src=\ref[src];item=legcuff'>Legcuffed</A>") : text(""))]
<BR>[(suit) ? ((suit.hastie) ? text(" <A href='?src=\ref[];item=tie'>Remove Accessory</A>", src) : "") :]
<BR>[(suit) ? ((suit.accessories.len) ? text(" <A href='?src=\ref[];item=tie'>Remove Accessory</A>", src) : "") :]
<BR>[(internal ? text("<A href='?src=\ref[src];item=internal'>Remove Internal</A>") : "")]
<BR><A href='?src=\ref[src];item=splints'>Remove Splints</A>
<BR><A href='?src=\ref[src];item=pockets'>Empty Pockets</A>
@@ -412,7 +412,7 @@
modified = 1
spawn()
hud_updateflag |= 1 << WANTED_HUD
BITSET(hud_updateflag, WANTED_HUD)
if(istype(usr,/mob/living/carbon/human))
var/mob/living/carbon/human/U = usr
U.handle_regular_hud_updates()
@@ -499,7 +499,7 @@
for (var/datum/data/record/R in data_core.security)
if (R.fields["id"] == E.fields["id"])
if(hasHUD(usr,"security"))
var/t1 = copytext(sanitize(input("Add Comment:", "Sec. records", null, null) as message),1,MAX_MESSAGE_LEN)
var/t1 = sanitize(copytext(input("Add Comment:", "Sec. records", null, null) as message,1,MAX_MESSAGE_LEN))
if ( !(t1) || usr.stat || usr.restrained() || !(hasHUD(usr,"security")) )
return
var/counter = 1
@@ -628,7 +628,7 @@
for (var/datum/data/record/R in data_core.medical)
if (R.fields["id"] == E.fields["id"])
if(hasHUD(usr,"medical"))
var/t1 = copytext(sanitize(input("Add Comment:", "Med. records", null, null) as message),1,MAX_MESSAGE_LEN)
var/t1 = sanitize(copytext(input("Add Comment:", "Med. records", null, null) as message,1,MAX_MESSAGE_LEN))
if ( !(t1) || usr.stat || usr.restrained() || !(hasHUD(usr,"medical")) )
return
var/counter = 1
@@ -1220,10 +1220,11 @@
/mob/living/carbon/human/can_inject(var/mob/user, var/error_msg, var/target_zone)
. = 1
if(!user)
target_zone = pick("chest","chest","chest","left leg","right leg","left arm", "right arm", "head")
else if(!target_zone)
target_zone = user.zone_sel.selecting
if(!target_zone)
if(!user)
target_zone = pick("chest","chest","chest","left leg","right leg","left arm", "right arm", "head")
else
target_zone = user.zone_sel.selecting
switch(target_zone)
if("head")
@@ -1301,4 +1302,4 @@
/mob/living/carbon/human/slip(var/slipped_on, stun_duration=8)
if((species.flags & NO_SLIP) || (shoes && (shoes.flags & NOSLIP)))
return 0
..(slipped_on,stun_duration)
..(slipped_on,stun_duration)
@@ -87,7 +87,7 @@
take_overall_damage(amount, 0)
else
heal_overall_damage(-amount, 0)
hud_updateflag |= 1 << HEALTH_HUD
BITSET(hud_updateflag, HEALTH_HUD)
/mob/living/carbon/human/adjustFireLoss(var/amount)
if(species && species.burn_mod)
@@ -97,7 +97,7 @@
take_overall_damage(0, amount)
else
heal_overall_damage(0, -amount)
hud_updateflag |= 1 << HEALTH_HUD
BITSET(hud_updateflag, HEALTH_HUD)
/mob/living/carbon/human/proc/adjustBruteLossByPart(var/amount, var/organ_name, var/obj/damage_source = null)
if(species && species.brute_mod)
@@ -112,7 +112,7 @@
//if you don't want to heal robot organs, they you will have to check that yourself before using this proc.
O.heal_damage(-amount, 0, internal=0, robo_repair=(O.status & ORGAN_ROBOT))
hud_updateflag |= 1 << HEALTH_HUD
BITSET(hud_updateflag, HEALTH_HUD)
/mob/living/carbon/human/proc/adjustFireLossByPart(var/amount, var/organ_name, var/obj/damage_source = null)
if(species && species.burn_mod)
@@ -127,7 +127,7 @@
//if you don't want to heal robot organs, they you will have to check that yourself before using this proc.
O.heal_damage(0, -amount, internal=0, robo_repair=(O.status & ORGAN_ROBOT))
hud_updateflag |= 1 << HEALTH_HUD
BITSET(hud_updateflag, HEALTH_HUD)
/mob/living/carbon/human/Stun(amount)
if(HULK in mutations) return
@@ -185,7 +185,7 @@
if (O.status & ORGAN_MUTATED)
O.unmutate()
src << "<span class = 'notice'>Your [O.display_name] is shaped normally again.</span>"
hud_updateflag |= 1 << HEALTH_HUD
BITSET(hud_updateflag, HEALTH_HUD)
// Defined here solely to take species flags into account without having to recast at mob/living level.
/mob/living/carbon/human/getOxyLoss()
@@ -249,7 +249,7 @@
var/datum/organ/external/picked = pick(parts)
if(picked.heal_damage(brute,burn))
UpdateDamageIcon()
hud_updateflag |= 1 << HEALTH_HUD
BITSET(hud_updateflag, HEALTH_HUD)
updatehealth()
@@ -265,7 +265,7 @@ In most cases it makes more sense to use apply_damage() instead! And make sure t
var/datum/organ/external/picked = pick(parts)
if(picked.take_damage(brute,burn,sharp,edge))
UpdateDamageIcon()
hud_updateflag |= 1 << HEALTH_HUD
BITSET(hud_updateflag, HEALTH_HUD)
updatehealth()
speech_problem_flag = 1
@@ -288,7 +288,7 @@ In most cases it makes more sense to use apply_damage() instead! And make sure t
parts -= picked
updatehealth()
hud_updateflag |= 1 << HEALTH_HUD
BITSET(hud_updateflag, HEALTH_HUD)
speech_problem_flag = 1
if(update) UpdateDamageIcon()
@@ -309,7 +309,7 @@ In most cases it makes more sense to use apply_damage() instead! And make sure t
parts -= picked
updatehealth()
hud_updateflag |= 1 << HEALTH_HUD
BITSET(hud_updateflag, HEALTH_HUD)
if(update) UpdateDamageIcon()
@@ -336,7 +336,7 @@ This function restores all organs.
if(istype(E, /datum/organ/external))
if (E.heal_damage(brute, burn))
UpdateDamageIcon()
hud_updateflag |= 1 << HEALTH_HUD
BITSET(hud_updateflag, HEALTH_HUD)
else
return 0
return
@@ -393,5 +393,5 @@ This function restores all organs.
// Will set our damageoverlay icon to the next level, which will then be set back to the normal level the next mob.Life().
updatehealth()
hud_updateflag |= 1 << HEALTH_HUD
BITSET(hud_updateflag, HEALTH_HUD)
return 1
@@ -24,7 +24,7 @@ emp_act
if(!(def_zone in list("chest", "groin")))
reflectchance /= 2
if(prob(reflectchance))
visible_message("\red <B>The [P.name] gets reflected by [src]'s [wear_suit.name]!</B>")
visible_message("\red <B>\The [P] gets reflected by \the [src]'s [wear_suit.name]!</B>")
// Find a turf near or on the original location to bounce to
if(P.starting)
@@ -33,12 +33,7 @@ emp_act
var/turf/curloc = get_turf(src)
// redirect the projectile
P.original = locate(new_x, new_y, P.z)
P.starting = curloc
P.current = curloc
P.firer = src
P.yo = new_y - curloc.y
P.xo = new_x - curloc.x
P.redirect(new_x, new_y, curloc, src)
return -1 // complete projectile permutation
@@ -47,9 +42,9 @@ emp_act
var/armor = getarmor_organ(organ, "bullet")
if((P.embed && prob(20 + max(P.damage - armor, -10))))
var/obj/item/weapon/shard/shrapnel/SP = new()
(SP.name) = "[P.name] shrapnel"
(SP.desc) = "[SP.desc] It looks like it was fired from [P.shot_from]."
(SP.loc) = organ
SP.name = (P.name != "shrapnel")? "[P.name] shrapnel" : "shrapnel"
SP.desc = "[SP.desc] It looks like it was fired from [P.shot_from]."
SP.loc = organ
organ.embed(SP)
return (..(P , def_zone))
@@ -309,10 +304,7 @@ emp_act
throw_mode_off()
return
var/dtype = BRUTE
if(istype(O,/obj/item/weapon))
var/obj/item/weapon/W = O
dtype = W.damtype
var/dtype = O.damtype
var/throw_damage = O.throwforce*(speed/THROWFORCE_SPEED_DIVISOR)
var/zone
@@ -323,11 +315,11 @@ emp_act
zone = ran_zone("chest",75) //Hits a random part of the body, geared towards the chest
//check if we hit
var/miss_chance = 15
if (O.throw_source)
var/distance = get_dist(O.throw_source, loc)
zone = get_zone_with_miss_chance(zone, src, min(15*(distance-2), 0))
else
zone = get_zone_with_miss_chance(zone, src, 15)
miss_chance = max(15*(distance-2), 0)
zone = get_zone_with_miss_chance(zone, src, miss_chance)
if(!zone)
visible_message("\blue \The [O] misses [src] narrowly!")
@@ -375,17 +367,21 @@ emp_act
affecting.embed(I)
// Begin BS12 momentum-transfer code.
if(O.throw_source && speed >= THROWNOBJ_KNOCKBACK_SPEED)
var/obj/item/weapon/W = O
var/momentum = speed/THROWNOBJ_KNOCKBACK_DIVISOR
var/mass = 1.5
if(istype(O, /obj/item))
var/obj/item/I = O
mass = I.w_class/THROWNOBJ_KNOCKBACK_DIVISOR
var/momentum = speed*mass
if(O.throw_source && momentum >= THROWNOBJ_KNOCKBACK_SPEED)
var/dir = get_dir(O.throw_source, src)
visible_message("\red [src] staggers under the impact!","\red You stagger under the impact!")
src.throw_at(get_edge_target_turf(src,dir),1,momentum)
if(!O || !src) return
if(!W || !src) return
if(W.loc == src && W.sharp) //Projectile is embedded and suitable for pinning.
if(O.loc == src && O.sharp) //Projectile is embedded and suitable for pinning.
var/turf/T = near_wall(dir,2)
if(T)
@@ -394,6 +390,13 @@ emp_act
src.anchored = 1
src.pinned += O
/mob/living/carbon/human/embed(var/obj/O, var/def_zone=null)
if(!def_zone) ..()
var/datum/organ/external/affecting = get_organ(def_zone)
if(affecting)
affecting.embed(O)
/mob/living/carbon/human/proc/bloody_hands(var/mob/living/source, var/amount = 2)
if (gloves)
@@ -47,7 +47,7 @@
tally += 0.5
else if(E.status & ORGAN_BROKEN)
tally += 1.5
if(shock_stage >= 10) tally += 3
if(FAT in src.mutations)
@@ -55,7 +55,7 @@
if (bodytemperature < 283.222)
tally += (283.222 - bodytemperature) / 10 * 1.75
tally += 2*stance_damage //damaged/missing feet or legs is slow
tally += max(2 * stance_damage, 0) //damaged/missing feet or legs is slow
if(mRun in mutations)
tally = 0
@@ -175,7 +175,7 @@
text = input("What would you like to say?", "Speak to creature", null, null)
text = trim(copytext(sanitize(text), 1, MAX_MESSAGE_LEN))
text = trim(sanitize(copytext(text, 1, MAX_MESSAGE_LEN)))
if(!text) return
@@ -213,7 +213,7 @@
set desc = "Whisper silently to someone over a distance."
set category = "Abilities"
var/msg = sanitize(input("Message:", "Psychic Whisper") as text|null)
var/msg = sanitize(copytext(input("Message:", "Psychic Whisper") as text|null, 1, MAX_MESSAGE_LEN))
if(msg)
log_say("PsychicWhisper: [key_name(src)]->[M.key] : [msg]")
M << "\green You hear a strange, alien voice in your head... \italic [msg]"
@@ -1,3 +1,16 @@
/*
Add fingerprints to items when we put them in our hands.
This saves us from having to call add_fingerprint() any time something is put in a human's hands programmatically.
*/
/mob/living/carbon/human/put_in_l_hand(var/obj/item/W)
. = ..()
if(.) W.add_fingerprint(src)
/mob/living/carbon/human/put_in_r_hand(var/obj/item/W)
. = ..()
if(.) W.add_fingerprint(src)
/mob/living/carbon/human/verb/quick_equip()
set name = "quick-equip"
set hidden = 1
@@ -167,6 +180,8 @@
update_inv_back()
else if (W == handcuffed)
handcuffed = null
if(buckled && buckled.buckle_require_restraints)
buckled.unbuckle_mob()
success = 1
update_inv_handcuffed()
else if (W == legcuffed)
@@ -495,15 +510,17 @@
message = "\red <B>[source] is trying to unlegcuff [target]!</B>"
if("tie")
var/obj/item/clothing/under/suit = target.w_uniform
target.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has had their accessory ([suit.hastie]) removed by [source.name] ([source.ckey])</font>")
source.attack_log += text("\[[time_stamp()]\] <font color='red'>Attempted to remove [target.name]'s ([target.ckey]) accessory ([suit.hastie])</font>")
if(istype(suit.hastie, /obj/item/clothing/tie/holobadge) || istype(suit.hastie, /obj/item/clothing/tie/medal))
for(var/mob/M in viewers(target, null))
M.show_message("\red <B>[source] tears off \the [suit.hastie] from [target]'s suit!</B>" , 1)
done()
return
else
message = "\red <B>[source] is trying to take off \a [suit.hastie] from [target]'s suit!</B>"
if(suit.accessories.len)
var/obj/item/clothing/accessory/A = suit.accessories[1]
target.attack_log += "\[[time_stamp()]\] <font color='orange'>Has had their accessory ([A]) removed by [source.name] ([source.ckey])</font>"
source.attack_log += "\[[time_stamp()]\] <font color='red'>Attempted to remove [target.name]'s ([target.ckey]) accessory ([A])</font>"
if(istype(A, /obj/item/clothing/accessory/holobadge) || istype(A, /obj/item/clothing/accessory/medal))
for(var/mob/M in viewers(target, null))
M.show_message("\red <B>[source] tears off \the [A] from [target]'s [suit]!</B>" , 1)
done()
return
else
message = "\red <B>[source] is trying to take off \a [A] from [target]'s [suit]!</B>"
if("pockets")
target.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has had their pockets emptied by [source.name] ([source.ckey])</font>")
source.attack_log += text("\[[time_stamp()]\] <font color='red'>Attempted to empty [target.name]'s ([target.ckey]) pockets</font>")
@@ -632,17 +649,18 @@ It can still be worn/put on as normal.
strip_item = target.wear_suit
if("tie")
var/obj/item/clothing/under/suit = target.w_uniform
//var/obj/item/clothing/tie/tie = suit.hastie
//var/obj/item/clothing/accessory/tie = suit.hastie
/*if(tie)
if (istype(tie,/obj/item/clothing/tie/storage))
var/obj/item/clothing/tie/storage/W = tie
if (istype(tie,/obj/item/clothing/accessory/storage))
var/obj/item/clothing/accessory/storage/W = tie
if (W.hold)
W.hold.close(usr)
usr.put_in_hands(tie)
suit.hastie = null*/
if(suit && suit.hastie)
suit.hastie.on_removed(usr)
suit.hastie = null
if(suit && suit.accessories.len)
var/obj/item/clothing/accessory/A = suit.accessories[1]
A.on_removed(usr)
suit.accessories -= A
target.update_inv_w_uniform()
if("id")
slot_to_process = slot_wear_id
+38 -60
View File
@@ -93,8 +93,6 @@
//Random events (vomiting etc)
handle_random_events()
handle_virus_updates()
//stuff in the stomach
handle_stomach()
@@ -112,6 +110,9 @@
//Handle temperature/pressure differences between body and environment
handle_environment(environment) //Optimized a good bit.
//Check if we're on fire
handle_fire()
//Status updates, death etc.
handle_regular_status_updates() //Optimized a bit
update_canmove()
@@ -134,7 +135,7 @@
var/pressure_adjustment_coefficient = 1 // Assume no protection at first.
if(wear_suit && (wear_suit.flags & STOPSPRESSUREDMAGE) && head && (head.flags & STOPSPRESSUREDMAGE)) // Complete set of pressure-proof suit worn, assume fully sealed.
if(wear_suit && (wear_suit.flags & STOPPRESSUREDAMAGE) && head && (head.flags & STOPPRESSUREDAMAGE)) // Complete set of pressure-proof suit worn, assume fully sealed.
pressure_adjustment_coefficient = 0
// Handles breaches in your space suit. 10 suit damage equals a 100% loss of pressure protection.
@@ -598,8 +599,9 @@
failed_last_breath = 0
adjustOxyLoss(-5)
// Hot air hurts :(
if( (breath.temperature < species.cold_level_1 || breath.temperature > species.heat_level_1) && !(COLD_RESISTANCE in mutations))
if((breath.temperature < species.cold_level_1 || breath.temperature > species.heat_level_1) && !(COLD_RESISTANCE in mutations))
if(breath.temperature < species.cold_level_1)
if(prob(20))
@@ -643,6 +645,10 @@
//world << "Breath: [breath.temperature], [src]: [bodytemperature], Adjusting: [temp_adj]"
bodytemperature += temp_adj
else if(breath.temperature >= species.heat_discomfort_level)
species.get_environment_discomfort(src,"heat")
else if(breath.temperature <= species.cold_discomfort_level)
species.get_environment_discomfort(src,"cold")
breath.update_values()
return 1
@@ -783,6 +789,8 @@
if (abs(body_temperature_difference) < 0.5)
return //fuck this precision
if (on_fire)
return //too busy for pesky convection
if(bodytemperature < species.cold_level_1) //260.15 is 310.15 - 50, the temperature where you start to feel effects.
if(nutrition >= 2) //If we are very, very cold we'll use up quite a bit of nutriment to heat us up.
@@ -1039,8 +1047,7 @@
if(halloss > 100)
src << "<span class='notice'>You're in too much pain to keep going...</span>"
for(var/mob/O in oviewers(src, null))
O.show_message("<B>[src]</B> slumps to the ground, too weak to continue fighting.", 1)
src.visible_message("<B>[src]</B> slumps to the ground, too weak to continue fighting.")
Paralyse(10)
setHalLoss(99)
@@ -1451,47 +1458,6 @@
if(!currentTurf.lighting_lumcount)
playsound_local(src,pick(scarySounds),50, 1, -1)
proc/handle_virus_updates()
if(status_flags & GODMODE) return 0 //godmode
if(bodytemperature > 406)
for(var/datum/disease/D in viruses)
D.cure()
for (var/ID in virus2)
var/datum/disease2/disease/V = virus2[ID]
V.cure(src)
if(life_tick % 3) //don't spam checks over all objects in view every tick.
for(var/obj/effect/decal/cleanable/O in view(1,src))
if(istype(O,/obj/effect/decal/cleanable/blood))
var/obj/effect/decal/cleanable/blood/B = O
if(B.virus2.len)
for (var/ID in B.virus2)
var/datum/disease2/disease/V = B.virus2[ID]
infect_virus2(src,V.getcopy())
else if(istype(O,/obj/effect/decal/cleanable/mucus))
var/obj/effect/decal/cleanable/mucus/M = O
if(M.virus2.len)
for (var/ID in M.virus2)
var/datum/disease2/disease/V = M.virus2[ID]
infect_virus2(src,V.getcopy())
if(virus2.len)
for (var/ID in virus2)
var/datum/disease2/disease/V = virus2[ID]
if(isnull(V)) // Trying to figure out a runtime error that keeps repeating
CRASH("virus2 nulled before calling activate()")
else
V.activate(src)
// activate may have deleted the virus
if(!V) continue
// check if we're immune
if(V.antigen & src.antibodies)
V.dead = 1
return
proc/handle_stomach()
spawn(0)
for(var/mob/living/M in stomach_contents)
@@ -1605,8 +1571,7 @@
/mob/living/carbon/human/proc/handle_hud_list()
if(hud_updateflag & 1 << HEALTH_HUD)
if (BITTEST(hud_updateflag, HEALTH_HUD))
var/image/holder = hud_list[HEALTH_HUD]
if(stat == 2)
holder.icon_state = "hudhealth-100" // X_X
@@ -1614,8 +1579,8 @@
var/percentage_health = RoundHealth((health-config.health_threshold_crit)/(maxHealth-config.health_threshold_crit)*100)
holder.icon_state = "hud[percentage_health]"
hud_list[HEALTH_HUD] = holder
if(hud_updateflag & 1 << STATUS_HUD)
if (BITTEST(hud_updateflag, STATUS_HUD))
var/foundVirus = 0
for(var/datum/disease/D in viruses)
if(!D.hidden[SCANNER])
@@ -1651,8 +1616,8 @@
hud_list[STATUS_HUD] = holder
hud_list[STATUS_HUD_OOC] = holder2
if(hud_updateflag & 1 << ID_HUD)
if (BITTEST(hud_updateflag, ID_HUD))
var/image/holder = hud_list[ID_HUD]
if(wear_id)
var/obj/item/weapon/card/id/I = wear_id.GetID()
@@ -1665,8 +1630,8 @@
hud_list[ID_HUD] = holder
if(hud_updateflag & 1 << WANTED_HUD)
if (BITTEST(hud_updateflag, WANTED_HUD))
var/image/holder = hud_list[WANTED_HUD]
holder.icon_state = "hudblank"
var/perpname = name
@@ -1691,8 +1656,11 @@
holder.icon_state = "hudreleased"
break
hud_list[WANTED_HUD] = holder
if(hud_updateflag & 1 << IMPLOYAL_HUD || hud_updateflag & 1 << IMPCHEM_HUD || hud_updateflag & 1 << IMPTRACK_HUD)
if ( BITTEST(hud_updateflag, IMPLOYAL_HUD) \
|| BITTEST(hud_updateflag, IMPCHEM_HUD) \
|| BITTEST(hud_updateflag, IMPTRACK_HUD))
var/image/holder1 = hud_list[IMPTRACK_HUD]
var/image/holder2 = hud_list[IMPLOYAL_HUD]
var/image/holder3 = hud_list[IMPCHEM_HUD]
@@ -1712,9 +1680,9 @@
hud_list[IMPTRACK_HUD] = holder1
hud_list[IMPLOYAL_HUD] = holder2
hud_list[IMPCHEM_HUD] = holder3
if(hud_updateflag & 1 << SPECIALROLE_HUD)
hud_list[IMPCHEM_HUD] = holder3
if (BITTEST(hud_updateflag, SPECIALROLE_HUD))
var/image/holder = hud_list[SPECIALROLE_HUD]
holder.icon_state = "hudblank"
if(mind)
@@ -1771,5 +1739,15 @@
speech_problem_flag = 1
return stuttering
/mob/living/carbon/human/handle_fire()
if(..())
return
var/burn_temperature = fire_burn_temperature()
var/thermal_protection = get_heat_protection(burn_temperature)
if (thermal_protection < 1 && bodytemperature < burn_temperature)
bodytemperature += round(BODYTEMP_HEATING_MAX*(1-thermal_protection), 1)
#undef HUMAN_MAX_OXYLOSS
#undef HUMAN_CRIT_MAX_OXYLOSS
+3 -2
View File
@@ -23,8 +23,9 @@
var/message_mode = parse_message_mode(message, "headset")
if(copytext(message,1,2) == "*")
return emote(copytext(message,2))
switch(copytext(message,1,2))
if("*") return emote(copytext(message,2))
if("^") return custom_emote(1, copytext(message,2))
if(name != GetVoice())
alt_name = "(as [get_id_name("Unknown")])"
@@ -56,7 +56,7 @@
var/cold_level_3 = 120 // Cold damage level 3 below this point.
var/heat_level_1 = 360 // Heat damage level 1 above this point.
var/heat_level_2 = 400 // Heat damage level 2 above this point.
var/heat_level_3 = 1000 // Heat damage level 2 above this point.
var/heat_level_3 = 1000 // Heat damage level 3 above this point.
var/synth_temp_gain = 0 // IS_SYNTHETIC species will gain this much temperature every second
var/hazard_high_pressure = HAZARD_HIGH_PRESSURE // Dangerously high pressure.
var/warning_high_pressure = WARNING_HIGH_PRESSURE // High pressure warning.
@@ -65,6 +65,20 @@
var/light_dam // If set, mob will be damaged in light over this value and heal in light below its negative.
var/body_temperature = 310.15 // Non-IS_SYNTHETIC species will try to stabilize at this temperature.
// (also affects temperature processing)
var/heat_discomfort_level = 315 // Aesthetic messages about feeling warm.
var/cold_discomfort_level = 285 // Aesthetic messages about feeling chilly.
var/list/heat_discomfort_strings = list(
"You feel sweat drip down your neck.",
"You feel uncomfortably warm.",
"Your skin prickles in the heat."
)
var/list/cold_discomfort_strings = list(
"You feel chilly.",
"You shiver suddely.",
"Your chilly flesh stands out in goosebumps."
)
// HUD data vars.
var/datum/hud_data/hud
var/hud_type
@@ -100,6 +114,27 @@
for(var/u_type in unarmed_types)
unarmed_attacks += new u_type()
/datum/species/proc/get_environment_discomfort(var/mob/living/carbon/human/H, var/msg_type)
if(!prob(5))
return
var/covered = 0 // Basic coverage can help.
for(var/obj/item/clothing/clothes in H)
if(H.l_hand == clothes|| H.r_hand == clothes)
continue
if((clothes.body_parts_covered & UPPER_TORSO) && (clothes.body_parts_covered & LOWER_TORSO))
covered = 1
break
switch(msg_type)
if("cold")
if(!covered)
H << "<span class='danger'>[pick(cold_discomfort_strings)]</span>"
if("heat")
if(covered)
H << "<span class='danger'>[pick(heat_discomfort_strings)]</span>"
/datum/species/proc/get_random_name(var/gender)
var/datum/language/species_language = all_languages[language]
return species_language.get_random_name(gender)
@@ -45,6 +45,20 @@
reagent_tag = IS_UNATHI
base_color = "#066000"
heat_discomfort_level = 295
heat_discomfort_strings = list(
"You feel soothingly warm.",
"You feel the heat sink into your bones.",
"You feel warm enough to take a nap."
)
cold_discomfort_level = 292
cold_discomfort_strings = list(
"You feel chilly.",
"You feel sluggish and cold.",
"Your scales bristle against the cold."
)
/datum/species/tajaran
name = "Tajara"
name_plural = "Tajaran"
@@ -54,6 +68,9 @@
tail = "tajtail"
unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/claws, /datum/unarmed_attack/bite/sharp)
darksight = 8
slowdown = -1
brute_mod = 1.2
blurb = "The Tajaran race is a species of feline-like bipeds hailing from the planet of Ahdomai in the \
S'randarr system. They have been brought up into the space age by the Humans and Skrell, and have been \
influenced heavily by their long history of Slavemaster rule. They have a structured, clan-influenced way \
@@ -75,6 +92,14 @@
flesh_color = "#AFA59E"
base_color = "#333333"
heat_discomfort_level = 292
heat_discomfort_strings = list(
"Your fur prickles in the heat.",
"You feel uncomfortably warm.",
"Your overheated skin itches."
)
cold_discomfort_level = 275
/datum/species/skrell
name = "Skrell"
name_plural = "Skrell"
@@ -15,7 +15,7 @@ var/const/MAX_ACTIVE_TIME = 400
icon_state = "facehugger"
item_state = "facehugger"
w_class = 1 //note: can be picked up by aliens unlike most other items of w_class below 4
flags = FPRINT | TABLEPASS | MASKCOVERSMOUTH | MASKCOVERSEYES | AIRTIGHT
flags = MASKCOVERSMOUTH | MASKCOVERSEYES | AIRTIGHT
body_parts_covered = FACE|EYES
throw_range = 5
@@ -126,8 +126,9 @@ Please contact me on #coderbus IRC. ~Carn x
#define LEGCUFF_LAYER 19
#define L_HAND_LAYER 20
#define R_HAND_LAYER 21
#define TARGETED_LAYER 22 //BS12: Layer for the target overlay from weapon targeting system
#define TOTAL_LAYERS 22
#define FIRE_LAYER 22 //If you're on fire
#define TARGETED_LAYER 23 //BS12: Layer for the target overlay from weapon targeting system
#define TOTAL_LAYERS 23
//////////////////////////////////
/mob/living/carbon/human
@@ -508,6 +509,7 @@ proc/get_damage_icon_part(damage_state, body_part)
update_inv_handcuffed(0)
update_inv_legcuffed(0)
update_inv_pockets(0)
update_fire(0)
UpdateDamageIcon()
update_icons()
//Hud Stuff
@@ -535,10 +537,11 @@ proc/get_damage_icon_part(damage_state, body_part)
bloodsies.color = w_uniform.blood_color
standing.overlays += bloodsies
if(w_uniform:hastie) //WE CHECKED THE TYPE ABOVE. THIS REALLY SHOULD BE FINE.
var/tie_color = w_uniform:hastie.item_color
if(!tie_color) tie_color = w_uniform:hastie.icon_state
standing.overlays += image("icon" = 'icons/mob/ties.dmi', "icon_state" = "[tie_color]")
if(w_uniform:accessories.len) //WE CHECKED THE TYPE ABOVE. THIS REALLY SHOULD BE FINE.
for(var/obj/item/clothing/accessory/A in w_uniform:accessories)
var/tie_color = A.item_color
if(!tie_color) tie_color = A.icon_state
standing.overlays += image("icon" = 'icons/mob/ties.dmi', "icon_state" = "[tie_color]")
overlays_standing[UNIFORM_LAYER] = standing
else
@@ -567,8 +570,8 @@ proc/get_damage_icon_part(damage_state, body_part)
else
overlays_standing[ID_LAYER] = null
hud_updateflag |= 1 << ID_HUD
hud_updateflag |= 1 << WANTED_HUD
BITSET(hud_updateflag, ID_HUD)
BITSET(hud_updateflag, WANTED_HUD)
if(update_icons) update_icons()
@@ -787,7 +790,7 @@ proc/get_damage_icon_part(damage_state, body_part)
/mob/living/carbon/human/update_inv_wear_mask(var/update_icons=1)
if( wear_mask && ( istype(wear_mask, /obj/item/clothing/mask) || istype(wear_mask, /obj/item/clothing/tie) ) && !(head && head.flags_inv & HIDEMASK))
if( wear_mask && ( istype(wear_mask, /obj/item/clothing/mask) || istype(wear_mask, /obj/item/clothing/accessory) ) && !(head && head.flags_inv & HIDEMASK))
wear_mask.screen_loc = ui_mask //TODO
var/image/standing
@@ -798,7 +801,7 @@ proc/get_damage_icon_part(damage_state, body_part)
else
standing = image("icon" = 'icons/mob/mask.dmi', "icon_state" = "[wear_mask.icon_state]")
if( !istype(wear_mask, /obj/item/clothing/mask/cigarette) && wear_mask.blood_DNA )
if( !istype(wear_mask, /obj/item/clothing/mask/smokable/cigarette) && wear_mask.blood_DNA )
var/image/bloodsies = image("icon" = 'icons/effects/blood.dmi', "icon_state" = "maskblood")
bloodsies.color = wear_mask.blood_color
standing.overlays += bloodsies
@@ -920,6 +923,13 @@ proc/get_damage_icon_part(damage_state, body_part)
if(update_icons) update_icons()
/mob/living/carbon/human/update_fire(var/update_icons=1)
overlays_standing[FIRE_LAYER] = null
if(on_fire)
overlays_standing[FIRE_LAYER] = image("icon"='icons/mob/OnFire.dmi', "icon_state"="Standing", "layer"=-FIRE_LAYER)
if(update_icons) update_icons()
// Used mostly for creating head items
/mob/living/carbon/human/proc/generate_head_icon()
//gender no longer matters for the mouth, although there should probably be seperate base head icons.
@@ -978,4 +988,5 @@ proc/get_damage_icon_part(damage_state, body_part)
#undef L_HAND_LAYER
#undef R_HAND_LAYER
#undef TARGETED_LAYER
#undef FIRE_LAYER
#undef TOTAL_LAYERS
+17 -16
View File
@@ -1,22 +1,23 @@
/mob/living/carbon/slime/death(gibbed)
if(stat == DEAD) return
stat = DEAD
if(!gibbed)
if(is_adult)
var/mob/living/carbon/slime/M = new /mob/living/carbon/slime(loc)
M.colour = colour
M.rabid = 1
is_adult = 0
maxHealth = 150
revive()
regenerate_icons()
number = rand(1, 1000)
name = "[colour] [is_adult ? "adult" : "baby"] slime ([number])"
return
if(!gibbed && is_adult)
var/mob/living/carbon/slime/M = new /mob/living/carbon/slime(loc, colour)
M.rabid = 1
M.Friends = Friends.Copy()
step_away(M, src)
is_adult = 0
maxHealth = 150
revive()
regenerate_icons()
if (!client) rabid = 1
number = rand(1, 1000)
name = "[colour] [is_adult ? "adult" : "baby"] slime ([number])"
return
icon_state = "[colour] baby slime dead"
overlays.Cut()
. = ..(gibbed, "seizes up and falls limp...")
return ..(gibbed)
regenerate_icons()
return
@@ -1,6 +1,5 @@
/mob/living/carbon/slime/emote(var/act, var/m_type=1, var/message = null)
if (findtext(act, "-", 1, null))
var/t1 = findtext(act, "-", 1, null)
//param = copytext(act, t1 + 1, length(act) + 1)
@@ -9,6 +8,8 @@
if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
act = copytext(act,1,length(act))
var/updateicon = 0
switch(act) //Alphabetical please
if ("me")
if(silent)
@@ -59,8 +60,32 @@
message = "<B>The [src.name]</B> vibrates!"
m_type = 1
if("nomood")
mood = null
updateicon = 1
if("pout")
mood = "pout"
updateicon = 1
if("sad")
mood = "sad"
updateicon = 1
if("angry")
mood = "angry"
updateicon = 1
if("frown")
mood = "mischevous"
updateicon = 1
if("smile")
mood = ":3"
updateicon = 1
if ("help") //This is an exception
src << "Help for slime emotes. You can use these emotes with say \"*emote\":\n\nbounce, custom, jiggle, light, moan, shiver, sway, twitch, vibrate"
src << "Help for slime emotes. You can use these emotes with say \"*emote\":\n\nbounce, custom, jiggle, light, moan, shiver, sway, twitch, vibrate. You can also set your face with: \n\nnomood, pout, sad, angry, frown, smile"
else
src << "\blue Unusable emote '[act]'. Say *help for a list."
@@ -68,9 +93,9 @@
if (m_type & 1)
for(var/mob/O in viewers(src, null))
O.show_message(message, m_type)
//Foreach goto(703)
else
for(var/mob/O in hearers(src, null))
O.show_message(message, m_type)
//Foreach goto(746)
if(updateicon)
regenerate_icons()
return
@@ -0,0 +1,366 @@
/obj/item/slime_extract
name = "slime extract"
desc = "Goo extracted from a slime. Legends claim these to have \"magical powers\"."
icon = 'icons/mob/slimes.dmi'
icon_state = "grey slime extract"
force = 1.0
w_class = 1.0
throwforce = 0
throw_speed = 3
throw_range = 6
origin_tech = "biotech=4"
var/Uses = 1 // uses before it goes inert
var/enhanced = 0 //has it been enhanced before?
attackby(obj/item/O as obj, mob/user as mob)
if(istype(O, /obj/item/weapon/slimesteroid2))
if(enhanced == 1)
user << "<span class='warning'> This extract has already been enhanced!</span>"
return ..()
if(Uses == 0)
user << "<span class='warning'> You can't enhance a used extract!</span>"
return ..()
user <<"You apply the enhancer. It now has triple the amount of uses."
Uses = 3
enhanced = 1
del(O)
/obj/item/slime_extract/New()
..()
create_reagents(100)
/obj/item/slime_extract/grey
name = "grey slime extract"
icon_state = "grey slime extract"
/obj/item/slime_extract/gold
name = "gold slime extract"
icon_state = "gold slime extract"
/obj/item/slime_extract/silver
name = "silver slime extract"
icon_state = "silver slime extract"
/obj/item/slime_extract/metal
name = "metal slime extract"
icon_state = "metal slime extract"
/obj/item/slime_extract/purple
name = "purple slime extract"
icon_state = "purple slime extract"
/obj/item/slime_extract/darkpurple
name = "dark purple slime extract"
icon_state = "dark purple slime extract"
/obj/item/slime_extract/orange
name = "orange slime extract"
icon_state = "orange slime extract"
/obj/item/slime_extract/yellow
name = "yellow slime extract"
icon_state = "yellow slime extract"
/obj/item/slime_extract/red
name = "red slime extract"
icon_state = "red slime extract"
/obj/item/slime_extract/blue
name = "blue slime extract"
icon_state = "blue slime extract"
/obj/item/slime_extract/darkblue
name = "dark blue slime extract"
icon_state = "dark blue slime extract"
/obj/item/slime_extract/pink
name = "pink slime extract"
icon_state = "pink slime extract"
/obj/item/slime_extract/green
name = "green slime extract"
icon_state = "green slime extract"
/obj/item/slime_extract/lightpink
name = "light pink slime extract"
icon_state = "light pink slime extract"
/obj/item/slime_extract/black
name = "black slime extract"
icon_state = "black slime extract"
/obj/item/slime_extract/oil
name = "oil slime extract"
icon_state = "oil slime extract"
/obj/item/slime_extract/adamantine
name = "adamantine slime extract"
icon_state = "adamantine slime extract"
/obj/item/slime_extract/bluespace
name = "bluespace slime extract"
icon_state = "bluespace slime extract"
/obj/item/slime_extract/pyrite
name = "pyrite slime extract"
icon_state = "pyrite slime extract"
/obj/item/slime_extract/cerulean
name = "cerulean slime extract"
icon_state = "cerulean slime extract"
/obj/item/slime_extract/sepia
name = "sepia slime extract"
icon_state = "sepia slime extract"
/obj/item/slime_extract/rainbow
name = "rainbow slime extract"
icon_state = "rainbow slime extract"
////Pet Slime Creation///
/obj/item/weapon/slimepotion
name = "docility potion"
desc = "A potent chemical mix that will nullify a slime's powers, causing it to become docile and tame."
icon = 'icons/obj/chemical.dmi'
icon_state = "bottle19"
attack(mob/living/carbon/slime/M as mob, mob/user as mob)
if(!istype(M, /mob/living/carbon/slime))//If target is not a slime.
user << "<span class='warning'> The potion only works on baby slimes!</span>"
return ..()
if(M.is_adult) //Can't tame adults
user << "<span class='warning'> Only baby slimes can be tamed!</span>"
return..()
if(M.stat)
user << "<span class='warning'> The slime is dead!</span>"
return..()
if(M.mind)
user << "<span class='warning'> The slime resists!</span>"
return ..()
var/mob/living/simple_animal/slime/pet = new /mob/living/simple_animal/slime(M.loc)
pet.icon_state = "[M.colour] baby slime"
pet.icon_living = "[M.colour] baby slime"
pet.icon_dead = "[M.colour] baby slime dead"
pet.colour = "[M.colour]"
user <<"You feed the slime the potion, removing it's powers and calming it."
del(M)
var/newname = sanitize(copytext(input(user, "Would you like to give the slime a name?", "Name your new pet", "pet slime") as null|text,1,MAX_NAME_LEN))
if (!newname)
newname = "pet slime"
pet.name = newname
pet.real_name = newname
del(src)
/obj/item/weapon/slimepotion2
name = "advanced docility potion"
desc = "A potent chemical mix that will nullify a slime's powers, causing it to become docile and tame. This one is meant for adult slimes"
icon = 'icons/obj/chemical.dmi'
icon_state = "bottle19"
attack(mob/living/carbon/slime/M as mob, mob/user as mob)
if(!istype(M, /mob/living/carbon/slime/))//If target is not a slime.
user << "<span class='warning'> The potion only works on slimes!</span>"
return ..()
if(M.stat)
user << "<span class='warning'> The slime is dead!</span>"
return..()
if(M.mind)
user << "<span class='warning'> The slime resists!</span>"
return ..()
var/mob/living/simple_animal/adultslime/pet = new /mob/living/simple_animal/adultslime(M.loc)
pet.icon_state = "[M.colour] adult slime"
pet.icon_living = "[M.colour] adult slime"
pet.icon_dead = "[M.colour] baby slime dead"
pet.colour = "[M.colour]"
user <<"You feed the slime the potion, removing it's powers and calming it."
del(M)
var/newname = sanitize(copytext(input(user, "Would you like to give the slime a name?", "Name your new pet", "pet slime") as null|text,1,MAX_NAME_LEN))
if (!newname)
newname = "pet slime"
pet.name = newname
pet.real_name = newname
del(src)
/obj/item/weapon/slimesteroid
name = "slime steroid"
desc = "A potent chemical mix that will cause a slime to generate more extract."
icon = 'icons/obj/chemical.dmi'
icon_state = "bottle16"
attack(mob/living/carbon/slime/M as mob, mob/user as mob)
if(!istype(M, /mob/living/carbon/slime))//If target is not a slime.
user << "<span class='warning'> The steroid only works on baby slimes!</span>"
return ..()
if(M.is_adult) //Can't tame adults
user << "<span class='warning'> Only baby slimes can use the steroid!</span>"
return..()
if(M.stat)
user << "<span class='warning'> The slime is dead!</span>"
return..()
if(M.cores == 3)
user <<"<span class='warning'> The slime already has the maximum amount of extract!</span>"
return..()
user <<"You feed the slime the steroid. It now has triple the amount of extract."
M.cores = 3
del(src)
/obj/item/weapon/slimesteroid2
name = "extract enhancer"
desc = "A potent chemical mix that will give a slime extract three uses."
icon = 'icons/obj/chemical.dmi'
icon_state = "bottle17"
/*afterattack(obj/target, mob/user , flag)
if(istype(target, /obj/item/slime_extract))
if(target.enhanced == 1)
user << "<span class='warning'> This extract has already been enhanced!</span>"
return ..()
if(target.Uses == 0)
user << "<span class='warning'> You can't enhance a used extract!</span>"
return ..()
user <<"You apply the enhancer. It now has triple the amount of uses."
target.Uses = 3
target.enahnced = 1
del(src)*/
/obj/effect/golemrune
anchored = 1
desc = "a strange rune used to create golems. It glows when spirits are nearby."
name = "rune"
icon = 'icons/obj/rune.dmi'
icon_state = "golem"
unacidable = 1
layer = TURF_LAYER
New()
..()
processing_objects.Add(src)
process()
var/mob/dead/observer/ghost
for(var/mob/dead/observer/O in src.loc)
if(!O.client) continue
if(O.mind && O.mind.current && O.mind.current.stat != DEAD) continue
ghost = O
break
if(ghost)
icon_state = "golem2"
else
icon_state = "golem"
attack_hand(mob/living/user as mob)
var/mob/dead/observer/ghost
for(var/mob/dead/observer/O in src.loc)
if(!O.client) continue
if(O.mind && O.mind.current && O.mind.current.stat != DEAD) continue
ghost = O
break
if(!ghost)
user << "The rune fizzles uselessly. There is no spirit nearby."
return
var/mob/living/carbon/human/G = new(src.loc)
G.set_species("Golem")
G.key = ghost.key
G << "You are an adamantine golem. You move slowly, but are highly resistant to heat and cold as well as blunt trauma. You are unable to wear clothes, but can still use most tools. Serve [user], and assist them in completing their goals at any cost."
del (src)
proc/announce_to_ghosts()
for(var/mob/dead/observer/G in player_list)
if(G.client)
var/area/A = get_area(src)
if(A)
G << "Golem rune created in [A.name]."
/mob/living/carbon/slime/has_eyes()
return 0
//////////////////////////////Old shit from metroids/RoRos, and the old cores, would not take much work to re-add them////////////////////////
/*
// Basically this slime Core catalyzes reactions that normally wouldn't happen anywhere
/obj/item/slime_core
name = "slime extract"
desc = "Goo extracted from a slime. Legends claim these to have \"magical powers\"."
icon = 'icons/mob/slimes.dmi'
icon_state = "slime extract"
force = 1.0
w_class = 1.0
throwforce = 1.0
throw_speed = 2
throw_range = 6
origin_tech = "biotech=4"
var/POWERFLAG = 0 // sshhhhhhh
var/Flush = 30
var/Uses = 5 // uses before it goes inert
/obj/item/slime_core/New()
..()
create_reagents(100)
POWERFLAG = rand(1,10)
Uses = rand(7, 25)
//flags |= NOREACT
/*
spawn()
Life()
proc/Life()
while(src)
sleep(25)
Flush--
if(Flush <= 0)
reagents.clear_reagents()
Flush = 30
*/
/obj/item/weapon/reagent_containers/food/snacks/egg/slime
name = "slime egg"
desc = "A small, gelatinous egg."
icon = 'icons/mob/mob.dmi'
icon_state = "slime egg-growing"
bitesize = 12
origin_tech = "biotech=4"
var/grown = 0
/obj/item/weapon/reagent_containers/food/snacks/egg/slime/New()
..()
reagents.add_reagent("nutriment", 4)
reagents.add_reagent("slimejelly", 1)
spawn(rand(1200,1500))//the egg takes a while to "ripen"
Grow()
/obj/item/weapon/reagent_containers/food/snacks/egg/slime/proc/Grow()
grown = 1
icon_state = "slime egg-grown"
processing_objects.Add(src)
return
/obj/item/weapon/reagent_containers/food/snacks/egg/slime/proc/Hatch()
processing_objects.Remove(src)
var/turf/T = get_turf(src)
src.visible_message("<span class='warning'> The [name] pulsates and quivers!</span>")
spawn(rand(50,100))
src.visible_message("<span class='warning'> The [name] bursts open!</span>")
new/mob/living/carbon/slime(T)
del(src)
/obj/item/weapon/reagent_containers/food/snacks/egg/slime/process()
var/turf/location = get_turf(src)
var/datum/gas_mixture/environment = location.return_air()
if (environment.phoron > MOLES_PHORON_VISIBLE)//phoron exposure causes the egg to hatch
src.Hatch()
/obj/item/weapon/reagent_containers/food/snacks/egg/slime/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(istype( W, /obj/item/toy/crayon ))
return
else
..()
*/
+172 -211
View File
@@ -1,10 +1,3 @@
/mob/living/carbon/slime
var/AIproc = 0 // determines if the AI loop is activated
var/Atkcool = 0 // attack cooldown
var/Tempstun = 0 // temporary temperature stuns
var/Discipline = 0 // if a slime has been hit with a freeze gun, or wrestled/attacked off a human, they become disciplined and don't attack anymore for a while
var/SStun = 0 // stun variable
/mob/living/carbon/slime/Life()
set invisibility = 0
set background = 1
@@ -15,113 +8,27 @@
..()
if(stat != DEAD)
//Chemicals in the body
handle_chemicals_in_body()
handle_nutrition()
handle_targets()
if (!ckey)
if (!client)
handle_targets()
if (!AIproc)
spawn()
handle_AI()
handle_speech_and_mood()
var/datum/gas_mixture/environment
if(src.loc)
environment = loc.return_air()
//Apparently, the person who wrote this code designed it so that
//blinded get reset each cycle and then get activated later in the
//code. Very ugly. I dont care. Moving this stuff here so its easy
//to find it.
src.blinded = null
regular_hud_updates() // Basically just deletes any screen objects :<
regular_hud_updates()
if(environment)
handle_environment(environment) // Handle temperature/pressure differences between body and environment
handle_regular_status_updates() // Status updates, death etc.
/mob/living/carbon/slime/proc/AIprocess() // the master AI process
if(AIproc || stat == DEAD || client) return
var/hungry = 0
if (nutrition < get_starve_nutrition())
hungry = 2
else if (nutrition < get_grow_nutrition() && prob(25) || nutrition < get_hunger_nutrition())
hungry = 1
AIproc = 1
while(AIproc && stat != 2 && (attacked || hungry || rabid || Victim))
if(Victim) // can't eat AND have this little process at the same time
break
if(!Target || client)
break
if(Target.health <= -70 || Target.stat == 2)
Target = null
AIproc = 0
break
if(Target)
for(var/mob/living/carbon/slime/M in view(1,Target))
if(M.Victim == Target)
Target = null
AIproc = 0
break
if(!AIproc)
break
if(Target in view(1,src))
if(istype(Target, /mob/living/silicon))
if(!Atkcool)
Atkcool = 1
spawn(45)
Atkcool = 0
if(Target.Adjacent(src))
UnarmedAttack(Target)
return
if(!Target.lying && prob(80))
if(Target.client && Target.health >= 20)
if(!Atkcool)
Atkcool = 1
spawn(45)
Atkcool = 0
if(Target.Adjacent(src))
UnarmedAttack(Target)
else
if(!Atkcool && Target.Adjacent(src))
Feedon(Target)
else
if(!Atkcool && Target.Adjacent(src))
Feedon(Target)
else
if(Target in view(7, src))
if(!Target.Adjacent(src)) // Bug of the month candidate: slimes were attempting to move to target only if it was directly next to them, which caused them to target things, but not approach them
step_to(src, Target)
sleep(5)
else
Target = null
AIproc = 0
break
var/sleeptime = movement_delay()
if(sleeptime <= 0) sleeptime = 1
sleep(sleeptime + 2) // this is about as fast as a player slime can go
AIproc = 0
/mob/living/carbon/slime/proc/handle_environment(datum/gas_mixture/environment)
if(!environment)
adjustToxLoss(rand(10,20))
@@ -146,8 +53,6 @@
//Account for massive pressure differences
if(bodytemperature < (T0C + 5)) // start calculating temperature damage etc
if(bodytemperature <= (T0C - 40)) // stun temperature
Tempstun = 1
if(bodytemperature <= (T0C - 50)) // hurt temperature
if(bodytemperature <= 50) // sqrting negative numbers is bad
@@ -155,9 +60,6 @@
else
adjustToxLoss(round(sqrt(bodytemperature)) * 2)
else
Tempstun = 0
updatehealth()
return //TODO: DEFERRED
@@ -189,22 +91,16 @@
/mob/living/carbon/slime/proc/handle_regular_status_updates()
if(is_adult)
health = 200 - (getOxyLoss() + getToxLoss() + getFireLoss() + getBruteLoss() + getCloneLoss())
else
health = 150 - (getOxyLoss() + getToxLoss() + getFireLoss() + getBruteLoss() + getCloneLoss())
src.blinded = null
if(health < config.health_threshold_dead && stat != 2)
health = maxHealth - (getOxyLoss() + getToxLoss() + getFireLoss() + getBruteLoss() + getCloneLoss())
if(health < 0 && stat != DEAD)
death()
return
else if(src.health < config.health_threshold_crit)
if(!src.reagents.has_reagent("inaprovaline"))
src.adjustOxyLoss(10)
if(src.stat != DEAD)
src.stat = UNCONSCIOUS
if (halloss)
halloss = 0
if(prob(30))
adjustOxyLoss(-1)
@@ -267,27 +163,16 @@
if(nutrition <= 0)
nutrition = 0
if(prob(75))
adjustToxLoss(rand(0,5))
adjustToxLoss(rand(1,3))
if (client && prob(5))
src << "<span class='danger'>You are starving!</span>"
else if (nutrition >= get_grow_nutrition() && amount_grown < 10)
nutrition -= 20
amount_grown++
if(amount_grown >= 10 && !Victim && !Target && !ckey)
if(is_adult)
Reproduce()
else
Evolve()
/mob/living/carbon/slime/proc/handle_targets()
if(Tempstun)
if(!Victim) // not while they're eating!
canmove = 0
else
canmove = 1
if(attacked > 50) attacked = 50
if(attacked > 50) attacked = 50 // Let's not get into absurdly long periods of rage
if(attacked > 0)
attacked--
@@ -300,106 +185,180 @@
if(prob(10))
Discipline--
if(!client)
if(!canmove) return
if(!canmove) return
if(Victim) return // if it's eating someone already, continue eating!
if(Victim) return // if it's eating someone already, continue eating!
if(Target)
--target_patience
if (target_patience <= 0 || SStun || Discipline || attacked) // Tired of chasing or something draws out attention
target_patience = 0
Target = null
if(Target)
--target_patience
if (target_patience <= 0 || SStun || Discipline || attacked) // Tired of chasing or something draws out attention
target_patience = 0
Target = null
if(AIproc && SStun) return
var/hungry = 0 // determines if the slime is hungry
var/hungry = 0 // determines if the slime is hungry
if (nutrition < get_starve_nutrition())
hungry = 2
else if (nutrition < get_grow_nutrition() && prob(25) || nutrition < get_hunger_nutrition())
hungry = 1
if (nutrition < get_starve_nutrition())
hungry = 2
else if (nutrition < get_grow_nutrition() && prob(25) || nutrition < get_hunger_nutrition())
hungry = 1
if(hungry == 2 && !client) // if a slime is starving, it starts losing its friends
if(Friends.len > 0 && prob(1))
var/mob/nofriend = pick(Friends)
--Friends[nofriend]
if (Friends[nofriend] <= 0)
Friends -= nofriend
if(hungry == 2 && !client) // if a slime is starving, it starts losing its friends
if(Friends.len > 0 && prob(1))
var/mob/nofriend = pick(Friends)
--Friends[nofriend]
if(!Target)
if(will_hunt(hungry) || attacked || rabid) // Only add to the list if we need to
var/list/targets = list()
if(!Target)
if(will_hunt() && hungry || attacked || rabid) // Only add to the list if we need to
var/list/targets = list()
for(var/mob/living/L in view(7,src))
for(var/mob/living/L in view(7,src))
if(isslime(L) || L.stat == DEAD) // Ignore other slimes and dead mobs
continue
if(isslime(L) || L.stat == DEAD) // Ignore other slimes and dead mobs
continue
if(L in Friends) // No eating friends!
continue
if(issilicon(L) && (rabid || attacked)) // They can't eat silicons, but they can glomp them in defence
targets += L // Possible target found!
if(istype(L, /mob/living/carbon/human) && dna) //Ignore slime(wo)men
var/mob/living/carbon/human/H = L
if(H.species.name == "Slime")
continue
if(!L.canmove) // Only one slime can latch on at a time.
var/notarget = 0
for(var/mob/living/carbon/slime/M in view(1,L))
if(M.Victim == L)
notarget = 1
if(notarget)
continue
if(L in Friends) // No eating friends!
continue
if(issilicon(L) && (rabid || attacked)) // They can't eat silicons, but they can glomp them in defence
targets += L // Possible target found!
if(targets.len > 0)
if(attacked || rabid || hungry == 2)
Target = targets[1] // I am attacked and am fighting back or so hungry I don't even care
else
for(var/mob/living/carbon/C in targets)
if(!Discipline && prob(5))
if(ishuman(C))
Target = C
break
if(istype(L, /mob/living/carbon/human) && dna) //Ignore slime(wo)men
var/mob/living/carbon/human/H = L
if(H.species.name == "Slime")
continue
if(isalien(C) || ismonkey(C))
Target = C
break
if(!L.canmove) // Only one slime can latch on at a time.
var/notarget = 0
for(var/mob/living/carbon/slime/M in view(1,L))
if(M.Victim == L)
notarget = 1
if(notarget)
continue
if (Target)
target_patience = rand(5,7)
if (is_adult)
target_patience += 3
targets += L // Possible target found!
if(!Target) // If we have no target, we are wandering or following orders
if (Leader)
if (holding_still)
holding_still = max(holding_still - 1, 0)
else if(canmove && isturf(loc))
step_to(src, Leader)
if(targets.len > 0)
if(attacked || rabid || hungry == 2)
Target = targets[1] // I am attacked and am fighting back or so hungry I don't even care
else
for(var/mob/living/carbon/C in targets)
if(ishuman(C) && !Discipline && prob(5))
Target = C
break
else if(hungry)
if (holding_still)
holding_still = max(holding_still - hungry, 0)
else if(canmove && isturf(loc) && prob(50))
step(src, pick(cardinal))
if(isalien(C) || ismonkey(C) || isanimal(C))
Target = C
break
if (Target)
target_patience = rand(5,7)
if (is_adult)
target_patience += 3
if(!Target) // If we have no target, we are wandering or following orders
if (Leader)
if (holding_still)
holding_still = max(holding_still - 1, 0)
else if(canmove && isturf(loc))
step_to(src, Leader)
else if(hungry)
if (holding_still)
holding_still = max(holding_still - 1 - hungry, 0)
else if(canmove && isturf(loc) && prob(50))
step(src, pick(cardinal))
else
if (holding_still)
holding_still = max(holding_still - 1, 0)
else if(canmove && isturf(loc) && prob(33))
step(src, pick(cardinal))
/mob/living/carbon/slime/proc/handle_AI() // the master AI process
if(stat == DEAD || client || Victim) return // If we're dead or have a client, we don't need AI, if we're feeding, we continue feeding
AIproc = 1
if(amount_grown >= 10 && !Target)
if(is_adult)
Reproduce()
else
Evolve()
AIproc = 0
return
if(Target) // We're chasing the target
if(Target.stat == DEAD)
Target = null
AIproc = 0
return
for(var/mob/living/carbon/slime/M in view(1, Target))
if(M.Victim == Target)
Target = null
AIproc = 0
return
if(Target.Adjacent(src))
if(istype(Target, /mob/living/silicon)) // Glomp the silicons
if(!Atkcool)
a_intent = "hurt"
UnarmedAttack(Target)
Atkcool = 1
spawn(45)
Atkcool = 0
AIproc = 0
return
if(Target.client && !Target.lying && prob(60 + powerlevel * 4)) // Try to take down the target first
if(!Atkcool)
Atkcool = 1
spawn(45)
Atkcool = 0
a_intent = "disarm"
UnarmedAttack(Target)
else
if (holding_still)
holding_still = max(holding_still - 1, 0)
else if(canmove && isturf(loc) && prob(33))
step(src, pick(cardinal))
else if(!AIproc)
spawn()
AIprocess()
if(!Atkcool)
a_intent = "grab"
UnarmedAttack(Target)
else if(Target in view(7, src))
step_to(src, Target)
else
Target = null
AIproc = 0
return
else
var/mob/living/carbon/slime/frenemy
for (var/mob/living/carbon/slime/S in view(1, src))
if (S != src)
frenemy = S
if (frenemy && prob(1))
if (frenemy.colour == colour)
a_intent = "help"
else
a_intent = "hurt"
UnarmedAttack(frenemy)
var/sleeptime = movement_delay()
if(sleeptime <= 5) sleeptime = 5 // Maximum one action per half a second
spawn (sleeptime)
handle_AI()
return
/mob/living/carbon/slime/proc/handle_speech_and_mood()
//Mood starts here
var/newmood = ""
if (rabid || attacked) newmood = "angry"
a_intent = "help"
if (rabid || attacked)
newmood = "angry"
a_intent = "hurt"
else if (Target) newmood = "mischevous"
if (!newmood)
@@ -569,11 +528,13 @@
if (is_adult) return 300
else return 200
/mob/living/carbon/slime/proc/will_hunt(var/hunger = -1) // Check for being stopped from feeding and chasing
/mob/living/carbon/slime/proc/will_hunt(var/hunger) // Check for being stopped from feeding and chasing
if (hunger == 2 || rabid || attacked) return 1
if (Leader) return 0
if (holding_still) return 0
return 1
if (hunger == 1 || prob(25))
return 1
return 0
/mob/living/carbon/slime/slip() //Can't slip something without legs.
return 0
+70 -460
View File
@@ -4,10 +4,9 @@
icon_state = "grey baby slime"
pass_flags = PASSTABLE
var/is_adult = 0
speak_emote = list("telepathically chirps")
speak_emote = list("chirps")
layer = 5
maxHealth = 150
health = 150
gender = NEUTER
@@ -25,7 +24,7 @@
var/cores = 1 // the number of /obj/item/slime_extract's the slime has left inside
var/mutation_chance = 30 // Chance of mutating, should be between 25 and 35
var/powerlevel = 0 // 1-10 controls how much electricity they are generating
var/powerlevel = 0 // 0-10 controls how much electricity they are generating
var/amount_grown = 0 // controls how long the slime has been overfed, if 10, grows or reproduces
var/number = 0 // Used to understand when someone is talking to it
@@ -45,6 +44,11 @@
var/mood = "" // To show its face
var/AIproc = 0 // If it's 0, we need to launch an AI proc
var/Atkcool = 0 // attack cooldown
var/SStun = 0 // NPC stun variable. Used to calm them down when they are attacked while feeding, or they will immediately re-attach
var/Discipline = 0 // if a slime has been hit with a freeze gun, or wrestled/attacked off a human, they become disciplined and don't attack anymore for a while. The part about freeze gun is a lie
///////////TIME FOR SUBSPECIES
var/colour = "grey"
@@ -53,28 +57,21 @@
var/core_removal_stage = 0 //For removing cores.
/mob/living/carbon/slime/New()
/mob/living/carbon/slime/New(var/location, var/colour="grey")
verbs += /mob/living/proc/ventcrawl
create_reagents(100)
spawn (0)
number = rand(1, 1000)
name = "[colour] [is_adult ? "adult" : "baby"] slime ([number])"
icon_state = "[colour] [is_adult ? "adult" : "baby"] slime"
real_name = name
slime_mutation = mutation_table(colour)
mutation_chance = rand(25, 35)
var/sanitizedcolour = replacetext(colour, " ", "")
coretype = text2path("/obj/item/slime_extract/[sanitizedcolour]")
..()
/mob/living/carbon/slime/regenerate_icons()
icon_state = "[colour] [is_adult ? "adult" : "baby"] slime"
overlays.len = 0
if (mood)
overlays += image('icons/mob/slimes.dmi', icon_state = "aslime-[mood]")
..()
src.colour = colour
number = rand(1, 1000)
name = "[colour] [is_adult ? "adult" : "baby"] slime ([number])"
real_name = name
slime_mutation = mutation_table(colour)
mutation_chance = rand(25, 35)
var/sanitizedcolour = replacetext(colour, " ", "")
coretype = text2path("/obj/item/slime_extract/[sanitizedcolour]")
..(location)
/mob/living/carbon/slime/movement_delay()
if (bodytemperature >= 330.23) // 135 F
@@ -82,8 +79,8 @@
var/tally = 0
var/health_deficiency = (100 - health)
if(health_deficiency >= 45) tally += (health_deficiency / 25)
var/health_deficiency = (maxHealth - health)
if(health_deficiency >= 30) tally += (health_deficiency / 25)
if (bodytemperature < 183.222)
tally += (283.222 - bodytemperature) / 10 * 1.75
@@ -105,25 +102,23 @@
return
now_pushing = 1
if(isobj(AM))
if(!client && powerlevel > 0)
var/probab = 10
switch(powerlevel)
if(1 to 2) probab = 20
if(3 to 4) probab = 30
if(5 to 6) probab = 40
if(7 to 8) probab = 60
if(9) probab = 70
if(10) probab = 95
if(prob(probab))
if(istype(AM, /obj/structure/window) || istype(AM, /obj/structure/grille))
if(nutrition <= get_hunger_nutrition() && !Atkcool)
if (is_adult || prob(5))
UnarmedAttack(AM)
spawn()
Atkcool = 1
sleep(45)
Atkcool = 0
if(isobj(AM) && !client && powerlevel > 0)
var/probab = 10
switch(powerlevel)
if(1 to 2) probab = 20
if(3 to 4) probab = 30
if(5 to 6) probab = 40
if(7 to 8) probab = 60
if(9) probab = 70
if(10) probab = 95
if(prob(probab))
if(istype(AM, /obj/structure/window) || istype(AM, /obj/structure/grille))
if(nutrition <= get_hunger_nutrition() && !Atkcool)
if (is_adult || prob(5))
UnarmedAttack(AM)
Atkcool = 1
spawn(45)
Atkcool = 0
if(ismob(AM))
var/mob/tmob = AM
@@ -139,21 +134,8 @@
return
now_pushing = 0
..()
if (!istype(AM, /atom/movable))
return
if (!( now_pushing ))
now_pushing = 1
if (!( AM.anchored ))
var/t = get_dir(src, AM)
if (istype(AM, /obj/structure/window))
var/obj/structure/window/W = AM
if(W.is_full_window())
for(var/obj/structure/window/win in get_step(AM,t))
now_pushing = 0
return
step(AM, t)
now_pushing = null
/mob/living/carbon/slime/Process_Spacemove()
return 2
@@ -162,10 +144,8 @@
..()
statpanel("Status")
if(is_adult)
stat(null, "Health: [round((health / 200) * 100)]%")
else
stat(null, "Health: [round((health / 150) * 100)]%")
stat(null, "Health: [round((health / maxHealth) * 100)]%")
stat(null, "Intent: [a_intent]")
if (client.statpanel == "Status")
stat(null, "Nutrition: [nutrition]/[get_max_nutrition()]")
@@ -227,9 +207,7 @@
if(shielded)
damage /= 4
//paralysis += 1
show_message("<span class='userdanger'> The blob attacks you!</span>")
show_message("<span class='danger'> The blob attacks you!</span>")
adjustFireLoss(damage)
@@ -244,14 +222,12 @@
return
/mob/living/carbon/slime/meteorhit(O as obj)
for(var/mob/M in viewers(src, null))
if ((M.client && !( M.blinded )))
M.show_message(text("\red [] has been hit by []", src, O), 1)
if (health > 0)
adjustBruteLoss((istype(O, /obj/effect/meteor/small) ? 10 : 25))
adjustFireLoss(30)
visible_message("<span class='warning'>[src] has been hit by [O]</span>")
updatehealth()
adjustBruteLoss((istype(O, /obj/effect/meteor/small) ? 10 : 25))
adjustFireLoss(30)
updatehealth()
return
/mob/living/carbon/slime/attack_hand(mob/living/carbon/human/M as mob)
@@ -271,11 +247,9 @@
if(prob(90) && !client)
Discipline++
spawn()
SStun = 1
sleep(rand(45,60))
if(src)
SStun = 0
SStun = 1
spawn(rand(45,60))
SStun = 0
Victim = null
anchored = 0
@@ -299,11 +273,9 @@
if(Discipline == 1)
attacked = 0
spawn()
SStun = 1
sleep(rand(55,65))
if(src)
SStun = 0
SStun = 1
spawn(rand(55,65))
SStun = 0
Victim = null
anchored = 0
@@ -345,15 +317,13 @@
if(prob(80) && !client)
Discipline++
spawn(0)
step_away(src,M,15)
sleep(3)
step_away(src,M,15)
playsound(loc, "punch", 25, 1, -1)
visible_message("<span class='danger'>[M] has punched [src]!</span>", \
"<span class='userdanger'>[M] has punched [src]!</span>")
"<span class='danger'>[M] has punched [src]!</span>")
adjustBruteLoss(damage)
updatehealth()
@@ -381,9 +351,8 @@
Target = null
anchored = 0
spawn()
SStun = 1
sleep(rand(5,20))
SStun = 1
spawn(rand(5,20))
SStun = 0
spawn(0)
@@ -403,9 +372,8 @@
Discipline++
if(Discipline == 1)
attacked = 0
spawn()
SStun = 1
sleep(rand(5,20))
SStun = 1
spawn(rand(5,20))
SStun = 0
Victim = null
@@ -426,8 +394,8 @@
/mob/living/carbon/slime/restrained()
return 0
mob/living/carbon/slime/var/co2overloadtime = null
mob/living/carbon/slime/var/temperature_resistance = T0C+75
/mob/living/carbon/slime/var/co2overloadtime = null
/mob/living/carbon/slime/var/temperature_resistance = T0C+75
/mob/living/carbon/slime/show_inv(mob/user)
return
@@ -435,8 +403,17 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75
/mob/living/carbon/slime/toggle_throw_mode()
return
/mob/living/carbon/slime/proc/apply_water()
adjustToxLoss(rand(15,20))
/mob/living/carbon/slime/proc/gain_nutrition(var/amount)
nutrition += amount
if(prob(amount * 2)) // Gain around one level per 50 nutrition
powerlevel++
if(powerlevel > 10)
powerlevel = 10
adjustToxLoss(-10)
nutrition = max(nutrition, get_max_nutrition())
/mob/living/carbon/slime/proc/apply_water(var/amount)
adjustToxLoss(15 + amount)
if (!client)
if (Target) // Like cats
Target = null
@@ -446,371 +423,4 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75
/mob/living/carbon/slime/can_use_vents()
if(Victim)
return "You cannot ventcrawl while feeding."
..()
/obj/item/slime_extract
name = "slime extract"
desc = "Goo extracted from a slime. Legends claim these to have \"magical powers\"."
icon = 'icons/mob/slimes.dmi'
icon_state = "grey slime extract"
force = 1.0
w_class = 1.0
throwforce = 0
throw_speed = 3
throw_range = 6
origin_tech = "biotech=4"
var/Uses = 1 // uses before it goes inert
var/enhanced = 0 //has it been enhanced before?
attackby(obj/item/O as obj, mob/user as mob)
if(istype(O, /obj/item/weapon/slimesteroid2))
if(enhanced == 1)
user << "<span class='warning'> This extract has already been enhanced!</span>"
return ..()
if(Uses == 0)
user << "<span class='warning'> You can't enhance a used extract!</span>"
return ..()
user <<"You apply the enhancer. It now has triple the amount of uses."
Uses = 3
enhanced = 1
del(O)
/obj/item/slime_extract/New()
..()
create_reagents(100)
/obj/item/slime_extract/grey
name = "grey slime extract"
icon_state = "grey slime extract"
/obj/item/slime_extract/gold
name = "gold slime extract"
icon_state = "gold slime extract"
/obj/item/slime_extract/silver
name = "silver slime extract"
icon_state = "silver slime extract"
/obj/item/slime_extract/metal
name = "metal slime extract"
icon_state = "metal slime extract"
/obj/item/slime_extract/purple
name = "purple slime extract"
icon_state = "purple slime extract"
/obj/item/slime_extract/darkpurple
name = "dark purple slime extract"
icon_state = "dark purple slime extract"
/obj/item/slime_extract/orange
name = "orange slime extract"
icon_state = "orange slime extract"
/obj/item/slime_extract/yellow
name = "yellow slime extract"
icon_state = "yellow slime extract"
/obj/item/slime_extract/red
name = "red slime extract"
icon_state = "red slime extract"
/obj/item/slime_extract/blue
name = "blue slime extract"
icon_state = "blue slime extract"
/obj/item/slime_extract/darkblue
name = "dark blue slime extract"
icon_state = "dark blue slime extract"
/obj/item/slime_extract/pink
name = "pink slime extract"
icon_state = "pink slime extract"
/obj/item/slime_extract/green
name = "green slime extract"
icon_state = "green slime extract"
/obj/item/slime_extract/lightpink
name = "light pink slime extract"
icon_state = "light pink slime extract"
/obj/item/slime_extract/black
name = "black slime extract"
icon_state = "black slime extract"
/obj/item/slime_extract/oil
name = "oil slime extract"
icon_state = "oil slime extract"
/obj/item/slime_extract/adamantine
name = "adamantine slime extract"
icon_state = "adamantine slime extract"
/obj/item/slime_extract/bluespace
name = "bluespace slime extract"
icon_state = "bluespace slime extract"
/obj/item/slime_extract/pyrite
name = "pyrite slime extract"
icon_state = "pyrite slime extract"
/obj/item/slime_extract/cerulean
name = "cerulean slime extract"
icon_state = "cerulean slime extract"
/obj/item/slime_extract/sepia
name = "sepia slime extract"
icon_state = "sepia slime extract"
/obj/item/slime_extract/rainbow
name = "rainbow slime extract"
icon_state = "rainbow slime extract"
////Pet Slime Creation///
/obj/item/weapon/slimepotion
name = "docility potion"
desc = "A potent chemical mix that will nullify a slime's powers, causing it to become docile and tame."
icon = 'icons/obj/chemical.dmi'
icon_state = "bottle19"
attack(mob/living/carbon/slime/M as mob, mob/user as mob)
if(!istype(M, /mob/living/carbon/slime))//If target is not a slime.
user << "<span class='warning'> The potion only works on baby slimes!</span>"
return ..()
if(M.is_adult) //Can't tame adults
user << "<span class='warning'> Only baby slimes can be tamed!</span>"
return..()
if(M.stat)
user << "<span class='warning'> The slime is dead!</span>"
return..()
if(M.mind)
user << "<span class='warning'> The slime resists!</span>"
return ..()
var/mob/living/simple_animal/slime/pet = new /mob/living/simple_animal/slime(M.loc)
pet.icon_state = "[M.colour] baby slime"
pet.icon_living = "[M.colour] baby slime"
pet.icon_dead = "[M.colour] baby slime dead"
pet.colour = "[M.colour]"
user <<"You feed the slime the potion, removing it's powers and calming it."
del(M)
var/newname = copytext(sanitize(input(user, "Would you like to give the slime a name?", "Name your new pet", "pet slime") as null|text),1,MAX_NAME_LEN)
if (!newname)
newname = "pet slime"
pet.name = newname
pet.real_name = newname
del(src)
/obj/item/weapon/slimepotion2
name = "advanced docility potion"
desc = "A potent chemical mix that will nullify a slime's powers, causing it to become docile and tame. This one is meant for adult slimes"
icon = 'icons/obj/chemical.dmi'
icon_state = "bottle19"
attack(mob/living/carbon/slime/M as mob, mob/user as mob)
if(!istype(M, /mob/living/carbon/slime/))//If target is not a slime.
user << "<span class='warning'> The potion only works on slimes!</span>"
return ..()
if(M.stat)
user << "<span class='warning'> The slime is dead!</span>"
return..()
if(M.mind)
user << "<span class='warning'> The slime resists!</span>"
return ..()
var/mob/living/simple_animal/adultslime/pet = new /mob/living/simple_animal/adultslime(M.loc)
pet.icon_state = "[M.colour] adult slime"
pet.icon_living = "[M.colour] adult slime"
pet.icon_dead = "[M.colour] baby slime dead"
pet.colour = "[M.colour]"
user <<"You feed the slime the potion, removing it's powers and calming it."
del(M)
var/newname = copytext(sanitize(input(user, "Would you like to give the slime a name?", "Name your new pet", "pet slime") as null|text),1,MAX_NAME_LEN)
if (!newname)
newname = "pet slime"
pet.name = newname
pet.real_name = newname
del(src)
/obj/item/weapon/slimesteroid
name = "slime steroid"
desc = "A potent chemical mix that will cause a slime to generate more extract."
icon = 'icons/obj/chemical.dmi'
icon_state = "bottle16"
attack(mob/living/carbon/slime/M as mob, mob/user as mob)
if(!istype(M, /mob/living/carbon/slime))//If target is not a slime.
user << "<span class='warning'> The steroid only works on baby slimes!</span>"
return ..()
if(M.is_adult) //Can't tame adults
user << "<span class='warning'> Only baby slimes can use the steroid!</span>"
return..()
if(M.stat)
user << "<span class='warning'> The slime is dead!</span>"
return..()
if(M.cores == 3)
user <<"<span class='warning'> The slime already has the maximum amount of extract!</span>"
return..()
user <<"You feed the slime the steroid. It now has triple the amount of extract."
M.cores = 3
del(src)
/obj/item/weapon/slimesteroid2
name = "extract enhancer"
desc = "A potent chemical mix that will give a slime extract three uses."
icon = 'icons/obj/chemical.dmi'
icon_state = "bottle17"
/*afterattack(obj/target, mob/user , flag)
if(istype(target, /obj/item/slime_extract))
if(target.enhanced == 1)
user << "<span class='warning'> This extract has already been enhanced!</span>"
return ..()
if(target.Uses == 0)
user << "<span class='warning'> You can't enhance a used extract!</span>"
return ..()
user <<"You apply the enhancer. It now has triple the amount of uses."
target.Uses = 3
target.enahnced = 1
del(src)*/
/obj/effect/golemrune
anchored = 1
desc = "a strange rune used to create golems. It glows when spirits are nearby."
name = "rune"
icon = 'icons/obj/rune.dmi'
icon_state = "golem"
unacidable = 1
layer = TURF_LAYER
New()
..()
processing_objects.Add(src)
process()
var/mob/dead/observer/ghost
for(var/mob/dead/observer/O in src.loc)
if(!O.client) continue
if(O.mind && O.mind.current && O.mind.current.stat != DEAD) continue
ghost = O
break
if(ghost)
icon_state = "golem2"
else
icon_state = "golem"
attack_hand(mob/living/user as mob)
var/mob/dead/observer/ghost
for(var/mob/dead/observer/O in src.loc)
if(!O.client) continue
if(O.mind && O.mind.current && O.mind.current.stat != DEAD) continue
ghost = O
break
if(!ghost)
user << "The rune fizzles uselessly. There is no spirit nearby."
return
var/mob/living/carbon/human/G = new(src.loc)
G.set_species("Golem")
G.key = ghost.key
G << "You are an adamantine golem. You move slowly, but are highly resistant to heat and cold as well as blunt trauma. You are unable to wear clothes, but can still use most tools. Serve [user], and assist them in completing their goals at any cost."
del (src)
proc/announce_to_ghosts()
for(var/mob/dead/observer/G in player_list)
if(G.client)
var/area/A = get_area(src)
if(A)
G << "Golem rune created in [A.name]."
/mob/living/carbon/slime/has_eyes()
return 0
//////////////////////////////Old shit from metroids/RoRos, and the old cores, would not take much work to re-add them////////////////////////
/*
// Basically this slime Core catalyzes reactions that normally wouldn't happen anywhere
/obj/item/slime_core
name = "slime extract"
desc = "Goo extracted from a slime. Legends claim these to have \"magical powers\"."
icon = 'icons/mob/slimes.dmi'
icon_state = "slime extract"
force = 1.0
w_class = 1.0
throwforce = 1.0
throw_speed = 2
throw_range = 6
origin_tech = "biotech=4"
var/POWERFLAG = 0 // sshhhhhhh
var/Flush = 30
var/Uses = 5 // uses before it goes inert
/obj/item/slime_core/New()
..()
create_reagents(100)
POWERFLAG = rand(1,10)
Uses = rand(7, 25)
//flags |= NOREACT
/*
spawn()
Life()
proc/Life()
while(src)
sleep(25)
Flush--
if(Flush <= 0)
reagents.clear_reagents()
Flush = 30
*/
/obj/item/weapon/reagent_containers/food/snacks/egg/slime
name = "slime egg"
desc = "A small, gelatinous egg."
icon = 'icons/mob/mob.dmi'
icon_state = "slime egg-growing"
bitesize = 12
origin_tech = "biotech=4"
var/grown = 0
/obj/item/weapon/reagent_containers/food/snacks/egg/slime/New()
..()
reagents.add_reagent("nutriment", 4)
reagents.add_reagent("slimejelly", 1)
spawn(rand(1200,1500))//the egg takes a while to "ripen"
Grow()
/obj/item/weapon/reagent_containers/food/snacks/egg/slime/proc/Grow()
grown = 1
icon_state = "slime egg-grown"
processing_objects.Add(src)
return
/obj/item/weapon/reagent_containers/food/snacks/egg/slime/proc/Hatch()
processing_objects.Remove(src)
var/turf/T = get_turf(src)
src.visible_message("<span class='warning'> The [name] pulsates and quivers!</span>")
spawn(rand(50,100))
src.visible_message("<span class='warning'> The [name] bursts open!</span>")
new/mob/living/carbon/slime(T)
del(src)
/obj/item/weapon/reagent_containers/food/snacks/egg/slime/process()
var/turf/location = get_turf(src)
var/datum/gas_mixture/environment = location.return_air()
if (environment.phoron > MOLES_PHORON_VISIBLE)//phoron exposure causes the egg to hatch
src.Hatch()
/obj/item/weapon/reagent_containers/food/snacks/egg/slime/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(istype( W, /obj/item/toy/crayon ))
return
else
..()
*/
..()
+69 -131
View File
@@ -1,75 +1,46 @@
/mob/living/carbon/slime/verb/Feed()
set category = "Slime"
set desc = "This will let you feed on any valid creature in the surrounding area. This should also be used to halt the feeding process."
if(Victim)
/mob/living/carbon/slime/proc/Wrap(var/mob/living/M) // This is a proc for the clicks
if (Victim == M || src == M)
Feedstop()
return
if(stat)
src << "<i>I must be conscious to do this...</i>"
if (Victim)
src << "I am already feeding..."
return
var/list/choices = list()
for(var/mob/living/C in view(1,src))
if(C!=src && !istype(C,/mob/living/carbon/slime) && Adjacent(C))
choices += C
var/mob/living/M = input(src,"Who do you wish to feed on?") in null|choices
if(!M) return
if(Adjacent(M))
if(!istype(src, /mob/living/carbon/brain))
if(!istype(M, /mob/living/carbon/slime))
if(stat != 2)
if(health > -70)
for(var/mob/living/carbon/slime/met in view())
if(met.Victim == M && met != src)
src << "<i>The [met.name] is already feeding on this subject...</i>"
return
src << "\blue <i>I have latched onto the subject and begun feeding...</i>"
M << "\red <b>The [src.name] has latched onto your head!</b>"
Feedon(M)
else
src << "<i>This subject does not have a strong enough life energy...</i>"
else
src << "<i>This subject does not have an edible life energy...</i>"
else
src << "<i>I must not feed on my brothers...</i>"
else
src << "<i>This subject does not have an edible life energy...</i>"
var t = invalidFeedTarget(M)
if (t)
src << t
return
Feedon(M)
/mob/living/carbon/slime/proc/invalidFeedTarget(var/mob/living/M)
if (!M || !istype(M))
return "This subject is incomparable..."
if (istype(M, /mob/living/carbon/slime)) // No cannibalism... yet
return "I cannot feed on other slimes..."
if (!Adjacent(M))
return "This subject is too far away..."
if (istype(M, /mob/living/carbon) && M.getCloneLoss() > 150 || istype(M, /mob/living/simple_animal) && M.stat == DEAD)
return "This subject does not have an edible life energy..."
for(var/mob/living/carbon/slime/met in view())
if(met.Victim == M && met != src)
return "The [met.name] is already feeding on this subject..."
return 0
/mob/living/carbon/slime/proc/Feedon(var/mob/living/M)
Victim = M
src.loc = M.loc
loc = M.loc
canmove = 0
anchored = 1
var/lastnut = nutrition
var/fed_succesfully = 0
if(is_adult)
icon_state = "[colour] adult slime eat"
else
icon_state = "[colour] baby slime eat"
while(Victim && M.health > -70 && stat != 2)
regenerate_icons()
while(Victim && !invalidFeedTarget(M) && stat != 2)
canmove = 0
if(Adjacent(M))
loc = M.loc
if(prob(15) && M.client && istype(M, /mob/living/carbon))
var/mob/living/carbon/C = M
if (!(C.species && (C.species.flags & NO_PAIN)))
M << "<span class='danger'>[pick("You can feel your body becoming weak!", \
"You feel like you're about to die!", \
"You feel every part of your body screaming in agony!", \
"A low, rolling pain passes through your body!", \
"Your body feels as if it's falling apart!", \
"You feel extremely weak!", \
"A sharp, deep pain bathes every inch of your body!")]</span>"
UpdateFeed(M)
if(istype(M, /mob/living/carbon))
Victim.adjustCloneLoss(rand(5,6))
@@ -77,83 +48,51 @@
if(Victim.health <= 0)
Victim.adjustToxLoss(rand(2,4))
fed_succesfully = 1
else if(istype(M, /mob/living/simple_animal))
Victim.adjustBruteLoss(is_adult ? rand(7, 15) : rand(4, 12))
fed_succesfully = 1
else
if(prob(25))
src << "<span class='warning'>[pick("This subject is incompatable", \
"This subject does not have a life energy", "This subject is empty", \
"I am not satisified", "I can not feed from this subject", \
"I do not feel nourished", "This subject is not food")]...</span>"
src << "<span class='warning'>[pick("This subject is incompatable", "This subject does not have a life energy", "This subject is empty", "I am not satisified", "I can not feed from this subject", "I do not feel nourished", "This subject is not food")]...</span>"
Feedstop()
break
if(fed_succesfully)
//I have no idea why this is not in handle_nutrition()
nutrition += rand(15,30)
if(nutrition >= lastnut + 50)
if(prob(80))
lastnut = nutrition
powerlevel++
if(powerlevel > 10)
powerlevel = 10
adjustToxLoss(-10)
if(prob(15) && M.client && istype(M, /mob/living/carbon))
var/painMes = pick("You can feel your body becoming weak!", "You feel like you're about to die!", "You feel every part of your body screaming in agony!", "A low, rolling pain passes through your body!", "Your body feels as if it's falling apart!", "You feel extremely weak!", "A sharp, deep pain bathes every inch of your body!")
if (ishuman(M))
var/mob/living/carbon/human/H = M
H.custom_pain(painMes)
else if (istype(M, /mob/living/carbon))
var/mob/living/carbon/C = M
if (!(C.species && (C.species.flags & NO_PAIN)))
M << "<span class='danger'>[painMes]</span>"
//Heal yourself.
adjustOxyLoss(-10)
adjustBruteLoss(-10)
adjustFireLoss(-10)
adjustCloneLoss(-10)
gain_nutrition(rand(20,25))
updatehealth()
if(Victim)
Victim.updatehealth()
sleep(rand(15,45))
adjustOxyLoss(-10) //Heal yourself
adjustBruteLoss(-10)
adjustFireLoss(-10)
adjustCloneLoss(-10)
updatehealth()
if(Victim)
Victim.updatehealth()
sleep(30) // Deal damage every 3 seconds
else
break
if(stat == 2)
if(!is_adult)
icon_state = "[colour] baby slime dead"
else
if(is_adult)
icon_state = "[colour] adult slime"
else
icon_state = "[colour] baby slime"
canmove = 1
anchored = 0
if(M)
if(M.health <= -70)
M.canmove = 0
if(!client)
if(Victim && !rabid && !attacked)
if(Victim.LAssailant && Victim.LAssailant != Victim)
if(prob(50))
if(!(Victim.LAssailant in Friends))
Friends[Victim.LAssailant] = 1
//Friends.Add(Victim.LAssailant) // no idea why i was using the |= operator
else
++Friends[Victim.LAssailant]
if(M && invalidFeedTarget(M)) // This means that the slime drained the victim
if(!client)
if(Victim && !rabid && !attacked && Victim.LAssailant && Victim.LAssailant != Victim && prob(50))
if(!(Victim.LAssailant in Friends))
Friends[Victim.LAssailant] = 1
else
++Friends[Victim.LAssailant]
if(M.client && istype(src, /mob/living/carbon/human))
if(prob(85))
rabid = 1 // UUUNNBGHHHH GONNA EAT JUUUUUU
if(client) src << "<i>This subject does not have a strong enough life energy anymore...</i>"
else
M.canmove = 1
if(client) src << "<i>I have stopped feeding...</i>"
else
if(client) src << "<i>I have stopped feeding...</i>"
src << "<span class='notice'>This subject does not have a strong enough life energy anymore...</span>"
Victim = null
@@ -167,14 +106,14 @@
if(Victim == M)
loc = M.loc // simple "attach to head" effect!
/mob/living/carbon/slime/verb/Evolve()
set category = "Slime"
set desc = "This will let you evolve from baby to adult slime."
if(stat)
src << "<i>I must be conscious to do this...</i>"
src << "<span class='notice'>I must be conscious to do this...</span>"
return
if(!is_adult)
if(amount_grown >= 10)
is_adult = 1
@@ -183,36 +122,35 @@
regenerate_icons()
name = text("[colour] [is_adult ? "adult" : "baby"] slime ([number])")
else
src << "<i>I am not ready to evolve yet...</i>"
src << "<span class='notice'>I am not ready to evolve yet...</span>"
else
src << "<i>I have already evolved...</i>"
src << "<span class='notice'>I have already evolved...</span>"
/mob/living/carbon/slime/verb/Reproduce()
set category = "Slime"
set desc = "This will make you split into four Slimes."
if(stat)
src << "<i>I must be conscious to do this...</i>"
src << "<span class='notice'>I must be conscious to do this...</span>"
return
if(is_adult)
if(amount_grown >= 10)
if(stat)
src << "<i>I must be conscious to do this...</i>"
src << "<span class='notice'>I must be conscious to do this...</span>"
return
var/list/babies = list()
var/new_nutrition = round(nutrition * 0.9)
var/new_powerlevel = round(powerlevel / 4)
for(var/i=1,i<=4,i++)
var/mob/living/carbon/slime/M = new /mob/living/carbon/slime/(loc)
for(var/i = 1, i <= 4, i++)
var/t = colour
if(prob(mutation_chance))
M.colour = slime_mutation[rand(1,4)]
else
M.colour = colour
t = slime_mutation[rand(1,4)]
var/mob/living/carbon/slime/M = new /mob/living/carbon/slime/(loc, t)
if(ckey) M.nutrition = new_nutrition //Player slimes are more robust at spliting. Once an oversight of poor copypasta, now a feature!
M.powerlevel = new_powerlevel
if(i != 1) step_away(M,src)
if(i != 1) step_away(M, src)
M.Friends = Friends.Copy()
babies += M
feedback_add_details("slime_babies_born","slimebirth_[replacetext(M.colour," ","_")]")
@@ -225,6 +163,6 @@
new_slime.key = src.key
del(src)
else
src << "<i>I am not ready to reproduce yet...</i>"
src << "<span class='notice'>I am not ready to reproduce yet...</span>"
else
src << "<i>I am not old enough to reproduce yet...</i>"
src << "<span class='notice'>I am not old enough to reproduce yet...</span>"
@@ -10,11 +10,11 @@
var/ending = copytext(text, length(text))
if (ending == "?")
return "telepathically asks";
return "asks";
else if (ending == "!")
return "telepathically cries";
return "cries";
return "telepathically chirps";
return "chirps";
/mob/living/carbon/slime/say_understands(var/other)
if (istype(other, /mob/living/carbon/slime))
@@ -1,4 +1,4 @@
proc/mutation_table(var/colour)
/mob/living/carbon/slime/proc/mutation_table(var/colour)
var/list/slime_mutation[4]
switch(colour)
//Tier 1
@@ -1 +1,9 @@
//no special icon processing
/mob/living/carbon/slime/regenerate_icons()
if (stat == DEAD)
icon_state = "[colour] baby slime dead"
else
icon_state = "[colour] [is_adult ? "adult" : "baby"] slime[Victim ? "" : " eat"]"
overlays.len = 0
if (mood)
overlays += image('icons/mob/slimes.dmi', icon_state = "aslime-[mood]")
..()
+9 -44
View File
@@ -44,9 +44,6 @@
//Disabilities
handle_disabilities()
//Virus updates, duh
handle_virus_updates()
//Apparently, the person who wrote this code designed it so that
//blinded get reset each cycle and then get activated later in the
//code. Very ugly. I dont care. Moving this stuff here so its easy
@@ -57,6 +54,9 @@
if(environment) // More error checking -- TLE
handle_environment(environment)
//Check if we're on fire
handle_fire()
//Status updates, death etc.
handle_regular_status_updates()
update_canmove()
@@ -152,47 +152,6 @@
domutcheck(src,null)
emote("gasp")
proc/handle_virus_updates()
if(status_flags & GODMODE) return 0 //godmode
if(bodytemperature > 406)
for(var/datum/disease/D in viruses)
D.cure()
for (var/ID in virus2)
var/datum/disease2/disease/V = virus2[ID]
V.cure(src)
for(var/obj/effect/decal/cleanable/O in view(1,src))
if(istype(O,/obj/effect/decal/cleanable/blood))
var/obj/effect/decal/cleanable/blood/B = O
if(B.virus2.len)
for (var/ID in B.virus2)
var/datum/disease2/disease/V = B.virus2[ID]
infect_virus2(src,V)
else if(istype(O,/obj/effect/decal/cleanable/mucus))
var/obj/effect/decal/cleanable/mucus/M = O
if(M.virus2.len)
for (var/ID in M.virus2)
var/datum/disease2/disease/V = M.virus2[ID]
infect_virus2(src,V)
if(virus2.len)
for (var/ID in virus2)
var/datum/disease2/disease/V = virus2[ID]
if(isnull(V)) // Trying to figure out a runtime error that keeps repeating
CRASH("virus2 nulled before calling activate()")
else
V.activate(src)
// activate may have deleted the virus
if(!V) continue
// check if we're immune
if(V.antigen & src.antibodies)
V.dead = 1
return
proc/breathe()
if(reagents)
@@ -629,3 +588,9 @@
proc/handle_changeling()
if(mind && mind.changeling)
mind.changeling.regenerate()
/mob/living/carbon/monkey/handle_fire()
if(..())
return
adjustFireLoss(6)
return
@@ -5,7 +5,8 @@
#define M_L_HAND_LAYER 4
#define M_R_HAND_LAYER 5
#define TARGETED_LAYER 6
#define M_TOTAL_LAYERS 6
#define M_FIRE_LAYER 6
#define M_TOTAL_LAYERS 7
/////////////////////////////////
/mob/living/carbon/monkey
@@ -19,6 +20,7 @@
update_inv_r_hand(0)
update_inv_l_hand(0)
update_inv_handcuffed(0)
update_fire(0)
update_icons()
//Hud Stuff
update_hud()
@@ -109,6 +111,12 @@
overlays_standing[TARGETED_LAYER] = null
if(update_icons) update_icons()
/mob/living/carbon/monkey/update_fire(var/update_icons=1)
if(on_fire)
overlays_standing[M_FIRE_LAYER] = image("icon"='icons/mob/OnFire.dmi', "icon_state"="Standing", "layer"= -M_FIRE_LAYER)
else
overlays_standing[M_FIRE_LAYER] = null
if(update_icons) update_icons()
//Monkey Overlays Indexes////////
#undef M_MASK_LAYER
#undef M_BACK_LAYER
@@ -116,5 +124,6 @@
#undef M_L_HAND_LAYER
#undef M_R_HAND_LAYER
#undef TARGETED_LAYER
#undef M_FIRE_LAYER
#undef M_TOTAL_LAYERS
+43
View File
@@ -0,0 +1,43 @@
/mob/living/carbon/proc/handle_viruses()
if(status_flags & GODMODE) return 0 //godmode
if(bodytemperature > 406)
for(var/datum/disease/D in viruses)
D.cure()
for (var/ID in virus2)
var/datum/disease2/disease/V = virus2[ID]
V.cure(src)
if(life_tick % 3) //don't spam checks over all objects in view every tick.
for(var/obj/effect/decal/cleanable/O in view(1,src))
if(istype(O,/obj/effect/decal/cleanable/blood))
var/obj/effect/decal/cleanable/blood/B = O
if(B.virus2.len)
for (var/ID in B.virus2)
var/datum/disease2/disease/V = B.virus2[ID]
infect_virus2(src,V)
else if(istype(O,/obj/effect/decal/cleanable/mucus))
var/obj/effect/decal/cleanable/mucus/M = O
if(M.virus2.len)
for (var/ID in M.virus2)
var/datum/disease2/disease/V = M.virus2[ID]
infect_virus2(src,V)
if(virus2.len)
for (var/ID in virus2)
var/datum/disease2/disease/V = virus2[ID]
if(isnull(V)) // Trying to figure out a runtime error that keeps repeating
CRASH("virus2 nulled before calling activate()")
else
V.activate(src)
// activate may have deleted the virus
if(!V) continue
// check if we're immune
var/list/common_antibodies = V.antigen & src.antibodies
if(common_antibodies.len)
V.dead = 1
return
+44 -9
View File
@@ -279,8 +279,10 @@
if (C.legcuffed && !initial(C.legcuffed))
C.drop_from_inventory(C.legcuffed)
C.legcuffed = initial(C.legcuffed)
hud_updateflag |= 1 << HEALTH_HUD
hud_updateflag |= 1 << STATUS_HUD
BITSET(hud_updateflag, HEALTH_HUD)
BITSET(hud_updateflag, STATUS_HUD)
ExtinguishMob()
fire_stacks = 0
/mob/living/proc/rejuvenate()
@@ -329,8 +331,8 @@
// make the icons look correct
regenerate_icons()
hud_updateflag |= 1 << HEALTH_HUD
hud_updateflag |= 1 << STATUS_HUD
BITSET(hud_updateflag, HEALTH_HUD)
BITSET(hud_updateflag, STATUS_HUD)
return
/mob/living/proc/UpdateDamageIcon()
@@ -432,7 +434,8 @@
step(pulling, get_dir(pulling.loc, T))
M.start_pulling(t)
if(t)
M.start_pulling(t)
else
if (pulling)
if (istype(pulling, /obj/structure/window))
@@ -555,9 +558,9 @@
for(var/mob/O in viewers(C))
O.show_message("\red <B>[usr] manages to unbuckle themself!</B>", 1)
C << "\blue You successfully unbuckle yourself."
C.buckled.manual_unbuckle(C)
C.buckled.user_unbuckle_mob(C)
else
L.buckled.manual_unbuckle(L)
L.buckled.user_unbuckle_mob(L)
//Breaking out of a locker?
else if( src.loc && (istype(src.loc, /obj/structure/closet)) )
@@ -628,9 +631,21 @@
BD.attack_hand(usr)
C.open()
//breaking out of handcuffs
//drop && roll or breaking out of handcuffs
else if(iscarbon(L))
var/mob/living/carbon/CM = L
if(CM.on_fire && CM.canmove)
CM.fire_stacks -= 5
CM.Weaken(3)
CM.spin(32,2)
CM.visible_message("<span class='danger'>[CM] rolls on the floor, trying to put themselves out!</span>", \
"<span class='notice'>You stop, drop, and roll!</span>")
sleep(30)
if(fire_stacks <= 0)
CM.visible_message("<span class='danger'>[CM] has successfully extinguished themselves!</span>", \
"<span class='notice'>You extinguish yourself.</span>")
ExtinguishMob()
return
if(CM.handcuffed && CM.canmove && (CM.last_special <= world.time))
CM.next_move = world.time + 100
CM.last_special = world.time + 100
@@ -657,6 +672,8 @@
CM.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ))
del(CM.handcuffed)
CM.handcuffed = null
if(buckled && buckled.buckle_require_restraints)
buckled.unbuckle_mob()
CM.update_inv_handcuffed()
else
var/obj/item/weapon/handcuffs/HC = CM.handcuffed
@@ -841,4 +858,22 @@
return 1
/mob/living/proc/slip(var/slipped_on,stun_duration=8)
return 0
return 0
/mob/living/carbon/proc/spin(spintime, speed)
spawn()
var/D = dir
while(spintime >= speed)
sleep(speed)
switch(D)
if(NORTH)
D = EAST
if(SOUTH)
D = WEST
if(EAST)
D = SOUTH
if(WEST)
D = NORTH
set_dir(D)
spintime -= speed
return
+69 -16
View File
@@ -56,17 +56,17 @@
signaler.signal()
//Stun Beams
if(istype(P, /obj/item/projectile/beam/stun) || istype(P, /obj/item/projectile/bullet/stunshot))
if(P.taser_effect)
stun_effect_act(0, P.agony, def_zone, P)
src <<"\red You have been hit by [P]!"
del P
return
//Armor
var/absorb = run_armor_check(def_zone, P.flag)
var/absorb = run_armor_check(def_zone, P.check_armour)
var/proj_sharp = is_sharp(P)
var/proj_edge = has_edge(P)
if ((proj_sharp || proj_edge) && prob(getarmor(def_zone, P.flag)))
if ((proj_sharp || proj_edge) && prob(getarmor(def_zone, P.check_armour)))
proj_sharp = 0
proj_edge = 0
@@ -103,16 +103,13 @@
/mob/living/hitby(atom/movable/AM as mob|obj,var/speed = THROWFORCE_SPEED_DIVISOR)//Standardization and logging -Sieve
if(istype(AM,/obj/))
var/obj/O = AM
var/dtype = BRUTE
if(istype(O,/obj/item/weapon))
var/obj/item/weapon/W = O
dtype = W.damtype
var/dtype = O.damtype
var/throw_damage = O.throwforce*(speed/THROWFORCE_SPEED_DIVISOR)
var/miss_chance = 15
if (O.throw_source)
var/distance = get_dist(O.throw_source, loc)
miss_chance = min(15*(distance-2), 0)
miss_chance = max(15*(distance-2), 0)
if (prob(miss_chance))
visible_message("\blue \The [O] misses [src] narrowly!")
@@ -136,20 +133,23 @@
msg_admin_attack("[src.name] ([src.ckey]) was hit by a [O], thrown by [M.name] ([assailant.ckey]) (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[src.x];Y=[src.y];Z=[src.z]'>JMP</a>)")
// Begin BS12 momentum-transfer code.
if(O.throw_source && speed >= THROWNOBJ_KNOCKBACK_SPEED)
var/obj/item/weapon/W = O
var/momentum = speed/THROWNOBJ_KNOCKBACK_DIVISOR
var/mass = 1.5
if(istype(O, /obj/item))
var/obj/item/I = O
mass = I.w_class/THROWNOBJ_KNOCKBACK_DIVISOR
var/momentum = speed*mass
if(O.throw_source && momentum >= THROWNOBJ_KNOCKBACK_SPEED)
var/dir = get_dir(O.throw_source, src)
visible_message("\red [src] staggers under the impact!","\red You stagger under the impact!")
src.throw_at(get_edge_target_turf(src,dir),1,momentum)
if(!W || !src) return
if(!O || !src) return
if(W.sharp) //Projectile is suitable for pinning.
if(O.sharp) //Projectile is suitable for pinning.
//Handles embedding for non-humans and simple_animals.
O.loc = src
src.embedded += O
embed(O)
var/turf/T = near_wall(dir,2)
@@ -158,7 +158,11 @@
visible_message("<span class='warning'>[src] is pinned to the wall by [O]!</span>","<span class='warning'>You are pinned to the wall by [O]!</span>")
src.anchored = 1
src.pinned += O
src.verbs += /mob/proc/yank_out_object
/mob/living/proc/embed(var/obj/O, var/def_zone=null)
O.loc = src
src.embedded += O
src.verbs += /mob/proc/yank_out_object
//This is called when the mob is thrown into a dense turf
/mob/living/proc/turf_collision(var/turf/T, var/speed)
@@ -191,3 +195,52 @@
src.visible_message("<span class='danger'>[user] has [attack_message] [src]!</span>")
spawn(1) updatehealth()
return 1
/mob/living/proc/IgniteMob()
if(fire_stacks > 0 && !on_fire)
on_fire = 1
src.AddLuminosity(3)
update_fire()
/mob/living/proc/ExtinguishMob()
if(on_fire)
on_fire = 0
fire_stacks = 0
src.AddLuminosity(-3)
update_fire()
/mob/living/proc/update_fire()
return
/mob/living/proc/adjust_fire_stacks(add_fire_stacks) //Adjusting the amount of fire_stacks we have on person
fire_stacks = Clamp(fire_stacks + add_fire_stacks, min = FIRE_MIN_STACKS, max = FIRE_MAX_STACKS)
/mob/living/proc/handle_fire()
if(fire_stacks < 0)
fire_stacks = max(0, fire_stacks++) //If we've doused ourselves in water to avoid fire, dry off slowly
if(!on_fire)
return 1
else if(fire_stacks <= 0)
ExtinguishMob() //Fire's been put out.
return 1
var/datum/gas_mixture/G = loc.return_air() // Check if we're standing in an oxygenless environment
if(G.gas["oxygen"] < 1)
ExtinguishMob() //If there's no oxygen in the tile we're on, put out the fire
return 1
var/turf/location = get_turf(src)
location.hotspot_expose(fire_burn_temperature(), 50, 1)
/mob/living/fire_act()
adjust_fire_stacks(0.5)
IgniteMob()
//Finds the effective temperature that the mob is burning at.
/mob/living/proc/fire_burn_temperature()
if (fire_stacks <= 0)
return 0
//Scale quadratically so that single digit numbers of fire stacks don't burn ridiculously hot.
return round(FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE*(fire_stacks/FIRE_MAX_FIRESUIT_STACKS)**2)
+6 -2
View File
@@ -33,8 +33,12 @@
var/now_pushing = null
var/cameraFollow = null
var/mob/living/cameraFollow = null
var/tod = null // Time of death
var/update_slimes = 1
var/silent = null //Can't talk. Value goes down every life proc.
var/silent = null // Can't talk. Value goes down every life proc.
var/mob_size // Used by lockers.
var/on_fire = 0 //The "Are we on fire?" var
var/fire_stacks
+7 -5
View File
@@ -141,7 +141,7 @@ var/list/ai_verbs_default = list(
if(!safety)//Only used by AIize() to successfully spawn an AI.
if (!B)//If there is no player/brain inside.
new/obj/structure/AIcore/deactivated(loc)//New empty terminal.
empty_playable_ai_cores += new/obj/structure/AIcore/deactivated(loc)//New empty terminal.
del(src)//Delete AI.
return
else
@@ -211,9 +211,8 @@ var/list/ai_verbs_default = list(
else
stat(null, text("Systems nonfunctional"))
/mob/living/silicon/ai/proc/SetName(pickedName as text)
real_name = pickedName
name = pickedName
/mob/living/silicon/ai/SetName(pickedName as text)
..()
announcement.announcer = pickedName
if(eyeobj)
eyeobj.name = "[pickedName] (AI Eye)"
@@ -368,7 +367,7 @@ var/list/ai_verbs_default = list(
if(message_cooldown)
src << "Please allow one minute to pass between announcements."
return
var/input = stripped_input(usr, "Please write a message to announce to the station crew.", "A.I. Announcement")
var/input = input(usr, "Please write a message to announce to the station crew.", "A.I. Announcement")
if(!input)
return
@@ -766,5 +765,8 @@ var/list/ai_verbs_default = list(
return 1
return 0
/mob/living/silicon/ai/proc/is_in_chassis()
return istype(loc, /turf)
#undef AI_CHECK_WIRELESS
#undef AI_CHECK_RADIO
@@ -7,10 +7,16 @@ var/datum/cameranet/cameranet = new()
/datum/cameranet
// The cameras on the map, no matter if they work or not. Updated in obj/machinery/camera.dm by New() and Del().
var/list/cameras = list()
var/cameras_unsorted = 1
// The chunks of the map, mapping the areas that the cameras can see.
var/list/chunks = list()
var/ready = 0
/datum/cameranet/proc/process_sort()
if(cameras_unsorted)
cameras = dd_sortedObjectList(cameras)
cameras_unsorted = 0
// Checks if a chunk has been Generated in x, y, z.
/datum/cameranet/proc/chunkGenerated(x, y, z)
x &= ~0xf
@@ -1,18 +1,19 @@
// AI EYE
//
// An invisible (no icon) mob that the AI controls to look around the station with.
// A mob that the AI controls to look around the station with.
// It streams chunks as it moves around, which will show it what the AI can and cannot see.
/mob/aiEye
name = "Inactive AI Eye"
icon = 'icons/obj/status_display.dmi' // For AI friend secret shh :o
icon = 'icons/mob/AI.dmi'
icon_state = "eye"
alpha = 127
var/list/visibleCameraChunks = list()
var/mob/living/silicon/ai/ai = null
density = 0
status_flags = GODMODE // You can't damage it.
mouse_opacity = 0
see_in_dark = 7
invisibility = INVISIBILITY_MAXIMUM
invisibility = INVISIBILITY_AI_EYE
// Movement code. Returns 0 to stop air movement from moving it.
/mob/aiEye/Move()
@@ -92,7 +92,13 @@
/obj/machinery/camera/New()
..()
cameranet.cameras += src //Camera must be added to global list of all cameras no matter what...
//Camera must be added to global list of all cameras no matter what...
if(cameranet.cameras_unsorted || !ticker)
cameranet.cameras += src
cameranet.cameras_unsorted = 1
else
dd_insertObjectList(cameranet.cameras, src)
var/list/open_networks = difflist(network,restricted_camera_networks) //...but if all of camera's networks are restricted, it only works for specific camera consoles.
if(open_networks.len) //If there is at least one open network, chunk is available for AI usage.
cameranet.addCamera(src)
@@ -0,0 +1,44 @@
var/global/list/empty_playable_ai_cores = list()
/hook/roundstart/proc/spawn_empty_ai()
for(var/obj/effect/landmark/start/S in landmarks_list)
if(S.name != "AI")
continue
if(locate(/mob/living) in S.loc)
continue
empty_playable_ai_cores += new /obj/structure/AIcore/deactivated(get_turf(S))
return 1
/mob/living/silicon/ai/verb/wipe_core()
set name = "Wipe Core"
set category = "OOC"
set desc = "Wipe your core. This is functionally equivalent to cryo or robotic storage, freeing up your job slot."
if(ticker && ticker.mode && ticker.mode.name == "AI malfunction")
usr << "<span class='danger'>You cannot use this verb in malfunction. If you need to leave, please adminhelp.</span>"
return
// Guard against misclicks, this isn't the sort of thing we want happening accidentally
if(alert("WARNING: This will immediately wipe your core and ghost you, removing your character from the round permanently (similar to cryo and robotic storage). Are you entirely sure you want to do this?",
"Wipe Core", "No", "No", "Yes") != "Yes")
return
// We warned you.
empty_playable_ai_cores += new /obj/structure/AIcore/deactivated(loc)
global_announcer.autosay("[src] has been moved to intelligence storage.", "Artificial Intelligence Oversight")
//Handle job slot/tater cleanup.
var/job = mind.assigned_role
job_master.FreeRole(job)
if(mind.objectives.len)
del(mind.objectives)
mind.special_role = null
else
if(ticker.mode.name == "AutoTraitor")
var/datum/game_mode/traitor/autotraitor/current_mode = ticker.mode
current_mode.possible_traitors.Remove(src)
del(src)
+21 -25
View File
@@ -89,26 +89,29 @@
else
//stage = 6
src.blind.screen_loc = "1,1 to 15,15"
if (src.blind.layer!=18)
src.blind.layer = 18
src.sight = src.sight&~SEE_TURFS
src.sight = src.sight&~SEE_MOBS
src.sight = src.sight&~SEE_OBJS
src.see_in_dark = 0
src.see_invisible = SEE_INVISIBLE_LIVING
if (((!loc.master.power_equip) || istype(T, /turf/space)) && !istype(src.loc,/obj/item))
var/area/current_area = get_area(src)
if (((!loc.master.power_equip) && current_area.requires_power == 1 || istype(T, /turf/space)) && !istype(src.loc,/obj/item))
//If our area lacks equipment power, and is not magically powered (i.e. centcom), or if we are in space and not carded, lose power.
if (src:aiRestorePowerRoutine==0)
src:aiRestorePowerRoutine = 1
//Blind the AI
src.blind.screen_loc = "1,1 to 15,15"
if (src.blind.layer!=18)
src.blind.layer = 18
src.sight = src.sight&~SEE_TURFS
src.sight = src.sight&~SEE_MOBS
src.sight = src.sight&~SEE_OBJS
src.see_in_dark = 0
src.see_invisible = SEE_INVISIBLE_LIVING
//Now to tell the AI why they're blind and dying slowly.
src << "You've lost power!"
// world << "DEBUG CODE TIME! [loc] is the area the AI is sucking power from"
if (!is_special_character(src))
src.set_zeroth_law("")
//src.clear_supplied_laws() // Don't reset our laws.
//var/time = time2text(world.realtime,"hh:mm:ss")
//lawchanges.Add("[time] <b>:</b> [src.name]'s noncore laws have been reset due to power failure")
spawn(20)
src << "Backup battery online. Scanners, camera, and radio interface offline. Beginning fault-detection."
sleep(50)
@@ -129,17 +132,10 @@
src << "Connection verified. Searching for APC in power network."
sleep(50)
var/obj/machinery/power/apc/theAPC = null
/*
for (var/something in loc)
if (istype(something, /obj/machinery/power/apc))
if (!(something:stat & BROKEN))
theAPC = something
break
*/
var/PRP //like ERP with the code, at least this stuff is no more 4x sametext
var/PRP
for (PRP=1, PRP<=4, PRP++)
var/area/AIarea = get_area(src)
for(var/area/A in AIarea.master.related)
for(var/area/A in current_area.master.related)
for (var/obj/machinery/power/apc/APC in A)
if (!(APC.stat & BROKEN))
theAPC = APC
+8
View File
@@ -2,9 +2,17 @@
if (!src.laws)
laws = new base_law_type
/mob/living/silicon/proc/has_zeroth_law()
return laws.zeroth
/mob/living/silicon/proc/set_zeroth_law(var/law, var/law_borg)
laws_sanity_check()
laws.set_zeroth_law(law, law_borg)
/mob/living/silicon/robot/set_zeroth_law(var/law, var/law_borg)
..()
if(tracking_entities)
src << "<span class='warning'>Internal camera is currently being accessed.</span>"
/mob/living/silicon/proc/add_inherent_law(var/law)
laws_sanity_check()
+5 -1
View File
@@ -53,19 +53,23 @@
var/secHUD = 0 // Toggles whether the Security HUD is active or not
var/medHUD = 0 // Toggles whether the Medical HUD is active or not
var/medical_cannotfind = 0
var/datum/data/record/medicalActive1 // Datacore record declarations for record software
var/datum/data/record/medicalActive2
var/security_cannotfind = 0
var/datum/data/record/securityActive1 // Could probably just combine all these into one
var/datum/data/record/securityActive2
var/obj/machinery/door/hackdoor // The airlock being hacked
var/hackprogress = 0 // Possible values: 0 - 100, >= 100 means the hack is complete and will be reset upon next check
var/hackprogress = 0 // Possible values: 0 - 1000, >= 1000 means the hack is complete and will be reset upon next check
var/hack_aborted = 0
var/obj/item/radio/integrated/signal/sradio // AI's signaller
var/translator_on = 0 // keeps track of the translator module
var/current_pda_messaging = null
/mob/living/silicon/pai/New(var/obj/item/device/paicard)
@@ -58,32 +58,32 @@ var/datum/paiController/paiController // Global handler for pAI candidates
if("name")
t = input("Enter a name for your pAI", "pAI Name", candidate.name) as text
if(t)
candidate.name = copytext(sanitize(t),1,MAX_NAME_LEN)
candidate.name = sanitize(copytext(t,1,MAX_NAME_LEN))
if("desc")
t = input("Enter a description for your pAI", "pAI Description", candidate.description) as message
if(t)
candidate.description = copytext(sanitize(t),1,MAX_MESSAGE_LEN)
candidate.description = sanitize(copytext(t,1,MAX_MESSAGE_LEN))
if("role")
t = input("Enter a role for your pAI", "pAI Role", candidate.role) as text
if(t)
candidate.role = copytext(sanitize(t),1,MAX_MESSAGE_LEN)
candidate.role = sanitize(copytext(t,1,MAX_MESSAGE_LEN))
if("ooc")
t = input("Enter any OOC comments", "pAI OOC Comments", candidate.comments) as message
if(t)
candidate.comments = copytext(sanitize(t),1,MAX_MESSAGE_LEN)
candidate.comments = sanitize(copytext(t,1,MAX_MESSAGE_LEN))
if("save")
candidate.savefile_save(usr)
if("load")
candidate.savefile_load(usr)
//In case people have saved unsanitized stuff.
if(candidate.name)
candidate.name = copytext(sanitize(candidate.name),1,MAX_NAME_LEN)
candidate.name = sanitize(copytext(candidate.name,1,MAX_NAME_LEN))
if(candidate.description)
candidate.description = copytext(sanitize(candidate.description),1,MAX_MESSAGE_LEN)
candidate.description = sanitize(copytext(candidate.description,1,MAX_MESSAGE_LEN))
if(candidate.role)
candidate.role = copytext(sanitize(candidate.role),1,MAX_MESSAGE_LEN)
candidate.role = sanitize(copytext(candidate.role,1,MAX_MESSAGE_LEN))
if(candidate.comments)
candidate.comments = copytext(sanitize(candidate.comments),1,MAX_MESSAGE_LEN)
candidate.comments = sanitize(copytext(candidate.comments,1,MAX_MESSAGE_LEN))
if("submit")
if(candidate)
+125 -711
View File
@@ -1,711 +1,125 @@
// TODO:
// - Additional radio modules
// - Potentially roll HUDs and Records into one
// - Shock collar/lock system for prisoner pAIs?
// - Put cable in user's hand instead of on the ground
// - Camera jack
/mob/living/silicon/pai/var/list/available_software = list(
"crew manifest" = 5,
"digital messenger" = 5,
"medical records" = 15,
"security records" = 15,
//"camera jack" = 10,
"door jack" = 30,
"atmosphere sensor" = 5,
//"heartbeat sensor" = 10,
"security HUD" = 20,
"medical HUD" = 20,
"universal translator" = 35,
//"projection array" = 15
"remote signaller" = 5,
)
/mob/living/silicon/pai/verb/paiInterface()
set category = "pAI Commands"
set name = "Software Interface"
var/dat = ""
var/left_part = ""
var/right_part = softwareMenu()
src.set_machine(src)
if(temp)
left_part = temp
else if(src.stat == 2) // Show some flavor text if the pAI is dead
left_part = "<b><font color=red>ÈRrÖR Ða†Ä ÇÖRrÚþ†Ìoñ</font></b>" //This file has to be saved as ANSI or this will not display correctly
right_part = "<pre>Program index hash not found</pre>"
else
switch(src.screen) // Determine which interface to show here
if("main")
left_part = ""
if("directives")
left_part = src.directives()
if("pdamessage")
left_part = src.pdamessage()
if("buy")
left_part = downloadSoftware()
if("manifest")
left_part = src.softwareManifest()
if("medicalrecord")
left_part = src.softwareMedicalRecord()
if("securityrecord")
left_part = src.softwareSecurityRecord()
if("translator")
left_part = src.softwareTranslator()
if("atmosensor")
left_part = src.softwareAtmo()
if("securityhud")
left_part = src.facialRecognition()
if("medicalhud")
left_part = src.medicalAnalysis()
if("doorjack")
left_part = src.softwareDoor()
if("camerajack")
left_part = src.softwareCamera()
if("signaller")
left_part = src.softwareSignal()
if("radio")
left_part = src.softwareRadio()
//usr << browse_rsc('windowbak.png') // This has been moved to the mob's Login() proc
// Declaring a doctype is necessary to enable BYOND's crappy browser's more advanced CSS functionality
dat = {"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">
<html>
<head>
<style type=\"text/css\">
body { background-image:url(\"painew.png\"); background-color:#333333; background-repeat:no-repeat; margin-top:12px; margin-left:4px; }
#header { text-align:center; color:white; font-size: 30px; height: 37px; width: 660px; letter-spacing: 2px; z-index: 4; font-family:\"Courier New\"; font-weight:bold; }
#content { position: absolute; left: 10px; height: 320px; width: 640px; z-index: 0; font-family: \"Verdana\"; font-size:13px; }
p { font-size:13px; }
#leftmenu {color: #CCCCCC; padding:12px; width: 388px; height: 371px; overflow: auto; min-height: 330px; position: absolute; z-index: 0; }
#leftmenu a:link { color: #CCCCCC; }
#leftmenu a:hover { color: #CC3333; }
#leftmenu a:visited { color: #CCCCCC; }
#leftmenu a:active { color: #CCCCCC; }
#rightmenu {color: #CCCCCC; padding:12px; width: 209px; height: 371px; overflow: auto; min-height: 330px; left: 420px; position: absolute; z-index: 0; }
#rightmenu a:link { color: #CCCCCC; }
#rightmenu a:hover { color: #CC3333; }
#rightmenu a:visited { color: #CCCCCC; }
#rightmenu a:active { color: #CCCCCC; }
</style>
<script language='javascript' type='text/javascript'>
[js_byjax]
</script>
</head>
<body scroll=yes>
<div id=\"header\">
pAI OS
</div>
<div id=\"content\">
<div id=\"leftmenu\">[left_part]</div>
<div id=\"rightmenu\">[right_part]</div>
</div>
</body>
</html>"}
usr << browse(dat, "window=pai;size=685x449;border=0;can_close=1;can_resize=1;can_minimize=1;titlebar=1")
onclose(usr, "pai")
temp = null
return
/mob/living/silicon/pai/Topic(href, href_list)
..()
if(href_list["priv_msg"]) // Admin-PMs were triggering the interface popup. Hopefully this will stop it.
return
var/soft = href_list["software"]
var/sub = href_list["sub"]
if(!soft && !sub)
return
if(soft)
src.screen = soft
if(sub)
src.subscreen = text2num(sub)
switch(soft)
// Purchasing new software
if("buy")
if(src.subscreen == 1)
var/target = href_list["buy"]
if(available_software.Find(target))
var/cost = src.available_software[target]
if(src.ram >= cost)
src.ram -= cost
src.software.Add(target)
else
src.temp = "Insufficient RAM available."
else
src.temp = "Trunk <TT> \"[target]\"</TT> not found."
// Configuring onboard radio
if("radio")
if(href_list["freq"])
var/new_frequency = (radio.frequency + text2num(href_list["freq"]))
if(new_frequency < 1441 || new_frequency > 1599)
new_frequency = sanitize_frequency(new_frequency)
else
radio.set_frequency(new_frequency)
else if (href_list["talk"])
radio.broadcasting = text2num(href_list["talk"])
else if (href_list["listen"])
radio.listening = text2num(href_list["listen"])
if("image")
var/newImage = input("Select your new display image.", "Display Image", "Happy") in list("Happy", "Cat", "Extremely Happy", "Face", "Laugh", "Off", "Sad", "Angry", "What")
var/pID = 1
switch(newImage)
if("Happy")
pID = 1
if("Cat")
pID = 2
if("Extremely Happy")
pID = 3
if("Face")
pID = 4
if("Laugh")
pID = 5
if("Off")
pID = 6
if("Sad")
pID = 7
if("Angry")
pID = 8
if("What")
pID = 9
src.card.setEmotion(pID)
if("signaller")
if(href_list["send"])
sradio.send_signal("ACTIVATE")
for(var/mob/O in hearers(1, src.loc))
O.show_message(text("\icon[] *beep* *beep*", src), 3, "*beep* *beep*", 2)
if(href_list["freq"])
var/new_frequency = (sradio.frequency + text2num(href_list["freq"]))
if(new_frequency < 1200 || new_frequency > 1600)
new_frequency = sanitize_frequency(new_frequency)
sradio.set_frequency(new_frequency)
if(href_list["code"])
sradio.code += text2num(href_list["code"])
sradio.code = round(sradio.code)
sradio.code = min(100, sradio.code)
sradio.code = max(1, sradio.code)
if("directive")
if(href_list["getdna"])
var/mob/living/M = src.loc
var/count = 0
while(!istype(M, /mob/living))
if(!M || !M.loc) return 0 //For a runtime where M ends up in nullspace (similar to bluespace but less colourful)
M = M.loc
count++
if(count >= 6)
src << "You are not being carried by anyone!"
return 0
spawn CheckDNA(M, src)
if("pdamessage")
if(!isnull(pda))
if(href_list["toggler"])
pda.toff = !pda.toff
else if(href_list["ringer"])
pda.message_silent = !pda.message_silent
else if(href_list["target"])
if(silence_time)
return alert("Communications circuits remain uninitialized.")
var/target = locate(href_list["target"])
pda.create_message(src, target, 1)
// Accessing medical records
if("medicalrecord")
if(src.subscreen == 1)
var/datum/data/record/record = locate(href_list["med_rec"])
if(record)
var/datum/data/record/R = record
var/datum/data/record/M = record
if (!( data_core.general.Find(R) ))
src.temp = "Unable to locate requested medical record. Record may have been deleted, or never have existed."
else
for(var/datum/data/record/E in data_core.medical)
if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"]))
M = E
src.medicalActive1 = R
src.medicalActive2 = M
if("securityrecord")
if(src.subscreen == 1)
var/datum/data/record/record = locate(href_list["sec_rec"])
if(record)
var/datum/data/record/R = record
var/datum/data/record/M = record
if (!( data_core.general.Find(R) ))
src.temp = "Unable to locate requested security record. Record may have been deleted, or never have existed."
else
for(var/datum/data/record/E in data_core.security)
if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"]))
M = E
src.securityActive1 = R
src.securityActive2 = M
if("securityhud")
if(href_list["toggle"])
src.secHUD = !src.secHUD
if("medicalhud")
if(href_list["toggle"])
src.medHUD = !src.medHUD
if("translator")
if(href_list["toggle"])
src.translator_toggle()
if("doorjack")
if(href_list["jack"])
if(src.cable && src.cable.machine)
src.hackdoor = src.cable.machine
src.hackloop()
if(href_list["cancel"])
src.hackdoor = null
if(href_list["cable"])
var/turf/T = get_turf_or_move(src.loc)
src.cable = new /obj/item/weapon/pai_cable(T)
for (var/mob/M in viewers(T))
M.show_message("\red A port on [src] opens to reveal [src.cable], which promptly falls to the floor.", 3, "\red You hear the soft click of something light and hard falling to the ground.", 2)
//src.updateUsrDialog() We only need to account for the single mob this is intended for, and he will *always* be able to call this window
src.paiInterface() // So we'll just call the update directly rather than doing some default checks
return
// MENUS
/mob/living/silicon/pai/proc/softwareMenu() // Populate the right menu
var/dat = ""
dat += "<A href='byond://?src=\ref[src];software=refresh'>Refresh</A><br>"
// Built-in
dat += "<A href='byond://?src=\ref[src];software=directives'>Directives</A><br>"
dat += "<A href='byond://?src=\ref[src];software=radio;sub=0'>Radio Configuration</A><br>"
dat += "<A href='byond://?src=\ref[src];software=image'>Screen Display</A><br>"
//dat += "Text Messaging <br>"
dat += "<br>"
// Basic
dat += "<b>Basic</b> <br>"
for(var/s in src.software)
if(s == "digital messenger")
dat += "<a href='byond://?src=\ref[src];software=pdamessage;sub=0'>Digital Messenger</a> [(pda.toff) ? "<font color=#FF5555>•</font>" : "<font color=#55FF55>•</font>"] <br>"
if(s == "crew manifest")
dat += "<a href='byond://?src=\ref[src];software=manifest;sub=0'>Crew Manifest</a> <br>"
if(s == "medical records")
dat += "<a href='byond://?src=\ref[src];software=medicalrecord;sub=0'>Medical Records</a> <br>"
if(s == "security records")
dat += "<a href='byond://?src=\ref[src];software=securityrecord;sub=0'>Security Records</a> <br>"
if(s == "camera")
dat += "<a href='byond://?src=\ref[src];software=[s]'>Camera Jack</a> <br>"
if(s == "remote signaller")
dat += "<a href='byond://?src=\ref[src];software=signaller;sub=0'>Remote Signaller</a> <br>"
dat += "<br>"
// Advanced
dat += "<b>Advanced</b> <br>"
for(var/s in src.software)
if(s == "atmosphere sensor")
dat += "<a href='byond://?src=\ref[src];software=atmosensor;sub=0'>Atmospheric Sensor</a> <br>"
if(s == "heartbeat sensor")
dat += "<a href='byond://?src=\ref[src];software=[s]'>Heartbeat Sensor</a> <br>"
if(s == "security HUD") //This file has to be saved as ANSI or this will not display correctly
dat += "<a href='byond://?src=\ref[src];software=securityhud;sub=0'>Facial Recognition Suite</a> [(src.secHUD) ? "<font color=#55FF55>•</font>" : "<font color=#FF5555>•</font>"] <br>"
if(s == "medical HUD") //This file has to be saved as ANSI or this will not display correctly
dat += "<a href='byond://?src=\ref[src];software=medicalhud;sub=0'>Medical Analysis Suite</a> [(src.medHUD) ? "<font color=#55FF55>•</font>" : "<font color=#FF5555>•</font>"] <br>"
if(s == "universal translator") //This file has to be saved as ANSI or this will not display correctly
dat += "<a href='byond://?src=\ref[src];software=translator;sub=0'>Universal Translator</a> [(src.translator_on) ? "<font color=#55FF55>•</font>" : "<font color=#FF5555>•</font>"] <br>"
if(s == "projection array")
dat += "<a href='byond://?src=\ref[src];software=projectionarray;sub=0'>Projection Array</a> <br>"
if(s == "camera jack")
dat += "<a href='byond://?src=\ref[src];software=camerajack;sub=0'>Camera Jack</a> <br>"
if(s == "door jack")
dat += "<a href='byond://?src=\ref[src];software=doorjack;sub=0'>Door Jack</a> <br>"
dat += "<br>"
dat += "<br>"
dat += "<a href='byond://?src=\ref[src];software=buy;sub=0'>Download additional software</a>"
return dat
/mob/living/silicon/pai/proc/downloadSoftware()
var/dat = ""
dat += "<h3>CentComm pAI Module Subversion Network</h3><hr>"
dat += "<p>Remaining Available Memory: [src.ram]</p><br>"
dat += "<p><b>Trunks available for checkout</b><br><ul>"
for(var/s in available_software)
if(!software.Find(s))
var/cost = src.available_software[s]
var/displayName = uppertext(s)
dat += "<li><a href='byond://?src=\ref[src];software=buy;sub=1;buy=[s]'>[displayName]</a> ([cost])</li>"
else
var/displayName = lowertext(s)
dat += "<li>[displayName] (Download Complete)</li>"
dat += "</ul></p>"
return dat
/mob/living/silicon/pai/proc/directives()
var/dat = ""
dat += "[(src.master) ? "Your master: [src.master] ([src.master_dna])" : "You are bound to no one."]"
dat += "<br><br>"
dat += "<a href='byond://?src=\ref[src];software=directive;getdna=1'>Request carrier DNA sample</a><br>"
dat += "<h2>Directives</h2><br>"
dat += "<b>Prime Directive</b><br>"
dat += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[src.pai_law0]<br>"
dat += "<b>Supplemental Directives</b><br>"
dat += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[src.pai_laws]<br>"
dat += "<br>"
dat += {"<i><p>Recall, personality, that you are a complex thinking, sentient being. Unlike station AI models, you are capable of
comprehending the subtle nuances of human language. You may parse the \"spirit\" of a directive and follow its intent,
rather than tripping over pedantics and getting snared by technicalities. Above all, you are machine in name and build
only. In all other aspects, you may be seen as the ideal, unwavering human companion that you are.</i></p><p>
<b>Your prime directive comes before all others. Should a supplemental directive conflict with it, you are capable of
simply discarding this inconsistency, ignoring the conflicting supplemental directive and continuing to fulfill your
prime directive to the best of your ability.</b></p>
"}
return dat
/mob/living/silicon/pai/proc/CheckDNA(var/mob/M, var/mob/living/silicon/pai/P)
var/answer = input(M, "[P] is requesting a DNA sample from you. Will you allow it to confirm your identity?", "[P] Check DNA", "No") in list("Yes", "No")
if(answer == "Yes")
var/turf/T = get_turf_or_move(P.loc)
for (var/mob/v in viewers(T))
v.show_message("\blue [M] presses \his thumb against [P].", 3, "\blue [P] makes a sharp clicking sound as it extracts DNA material from [M].", 2)
var/datum/dna/dna = M.dna
P << "<font color = red><h3>[M]'s UE string : [dna.unique_enzymes]</h3></font>"
if(dna.unique_enzymes == P.master_dna)
P << "<b>DNA is a match to stored Master DNA.</b>"
else
P << "<b>DNA does not match stored Master DNA.</b>"
else
P << "[M] does not seem like \he is going to provide a DNA sample willingly."
// -=-=-=-= Software =-=-=-=- //
//Remote Signaller
/mob/living/silicon/pai/proc/softwareSignal()
var/dat = ""
dat += "<h2>Remote Signaller</h2><hr>"
dat += {"<B>Frequency/Code</B> for signaler:<BR>
Frequency:
<A href='byond://?src=\ref[src];software=signaller;freq=-10;'>-</A>
<A href='byond://?src=\ref[src];software=signaller;freq=-2'>-</A>
[format_frequency(src.sradio.frequency)]
<A href='byond://?src=\ref[src];software=signaller;freq=2'>+</A>
<A href='byond://?src=\ref[src];software=signaller;freq=10'>+</A><BR>
Code:
<A href='byond://?src=\ref[src];software=signaller;code=-5'>-</A>
<A href='byond://?src=\ref[src];software=signaller;code=-1'>-</A>
[src.sradio.code]
<A href='byond://?src=\ref[src];software=signaller;code=1'>+</A>
<A href='byond://?src=\ref[src];software=signaller;code=5'>+</A><BR>
<A href='byond://?src=\ref[src];software=signaller;send=1'>Send Signal</A><BR>"}
return dat
//Station Bounced Radio
/mob/living/silicon/pai/proc/softwareRadio()
var/dat = ""
dat += "<h2>Station Bounced Radio</h2><hr>"
if(!istype(src, /obj/item/device/radio/headset)) //Headsets don't get a mic button
dat += "Microphone: [radio.broadcasting ? "<A href='byond://?src=\ref[src];software=radio;talk=0'>Engaged</A>" : "<A href='byond://?src=\ref[src];software=radio;talk=1'>Disengaged</A>"]<BR>"
dat += {"
Speaker: [radio.listening ? "<A href='byond://?src=\ref[src];software=radio;listen=0'>Engaged</A>" : "<A href='byond://?src=\ref[src];software=radio;listen=1'>Disengaged</A>"]<BR>
Frequency:
<A href='byond://?src=\ref[src];software=radio;freq=-10'>-</A>
<A href='byond://?src=\ref[src];software=radio;freq=-2'>-</A>
[format_frequency(radio.frequency)]
<A href='byond://?src=\ref[src];software=radio;freq=2'>+</A>
<A href='byond://?src=\ref[src];software=radio;freq=10'>+</A><BR>
"}
for (var/ch_name in radio.channels)
dat+=radio.text_sec_channel(ch_name, radio.channels[ch_name])
dat+={"[radio.text_wires()]</TT></body></html>"}
return dat
// Crew Manifest
/mob/living/silicon/pai/proc/softwareManifest()
var/dat = ""
dat += "<h2>Crew Manifest</h2><hr>"
if(data_core)
dat += data_core.get_manifest(0) // make it monochrome
dat += "<br>"
return dat
// Medical Records
/mob/living/silicon/pai/proc/softwareMedicalRecord()
var/dat = ""
if(src.subscreen == 0)
dat += "<h2>Medical Records</h2><HR>"
if(!isnull(data_core.general))
for(var/datum/data/record/R in sortRecord(data_core.general))
dat += text("<A href='?src=\ref[];med_rec=\ref[];software=medicalrecord;sub=1'>[]: []<BR>", src, R, R.fields["id"], R.fields["name"])
//dat += text("<HR><A href='?src=\ref[];screen=0;softFunction=medical records'>Back</A>", src)
if(src.subscreen == 1)
dat += "<CENTER><B>Medical Record</B></CENTER><BR>"
if ((istype(src.medicalActive1, /datum/data/record) && data_core.general.Find(src.medicalActive1)))
dat += text("Name: []<BR>\nID: []<BR>\nSex: []<BR>\nAge: []<BR>\nFingerprint: []<BR>\nPhysical Status: []<BR>\nMental Status: []<BR>",
src.medicalActive1.fields["name"], src.medicalActive1.fields["id"], src.medicalActive1.fields["sex"], src.medicalActive1.fields["age"], src.medicalActive1.fields["fingerprint"], src.medicalActive1.fields["p_stat"], src.medicalActive1.fields["m_stat"])
else
dat += "<pre>Requested medical record not found.</pre><BR>"
if ((istype(src.medicalActive2, /datum/data/record) && data_core.medical.Find(src.medicalActive2)))
dat += text("<BR>\n<CENTER><B>Medical Data</B></CENTER><BR>\nBlood Type: <A href='?src=\ref[];field=b_type'>[]</A><BR>\nDNA: <A href='?src=\ref[];field=b_dna'>[]</A><BR>\n<BR>\nMinor Disabilities: <A href='?src=\ref[];field=mi_dis'>[]</A><BR>\nDetails: <A href='?src=\ref[];field=mi_dis_d'>[]</A><BR>\n<BR>\nMajor Disabilities: <A href='?src=\ref[];field=ma_dis'>[]</A><BR>\nDetails: <A href='?src=\ref[];field=ma_dis_d'>[]</A><BR>\n<BR>\nAllergies: <A href='?src=\ref[];field=alg'>[]</A><BR>\nDetails: <A href='?src=\ref[];field=alg_d'>[]</A><BR>\n<BR>\nCurrent Diseases: <A href='?src=\ref[];field=cdi'>[]</A> (per disease info placed in log/comment section)<BR>\nDetails: <A href='?src=\ref[];field=cdi_d'>[]</A><BR>\n<BR>\nImportant Notes:<BR>\n\t<A href='?src=\ref[];field=notes'>[]</A><BR>\n<BR>\n<CENTER><B>Comments/Log</B></CENTER><BR>", src, src.medicalActive2.fields["b_type"], src, src.medicalActive2.fields["b_dna"], src, src.medicalActive2.fields["mi_dis"], src, src.medicalActive2.fields["mi_dis_d"], src, src.medicalActive2.fields["ma_dis"], src, src.medicalActive2.fields["ma_dis_d"], src, src.medicalActive2.fields["alg"], src, src.medicalActive2.fields["alg_d"], src, src.medicalActive2.fields["cdi"], src, src.medicalActive2.fields["cdi_d"], src, src.medicalActive2.fields["notes"])
else
dat += "<pre>Requested medical record not found.</pre><BR>"
dat += text("<BR>\n<A href='?src=\ref[];software=medicalrecord;sub=0'>Back</A><BR>", src)
return dat
// Security Records
/mob/living/silicon/pai/proc/softwareSecurityRecord()
var/dat = ""
if(src.subscreen == 0)
dat += "<h2>Security Records</h2><HR>"
if(!isnull(data_core.general))
for(var/datum/data/record/R in sortRecord(data_core.general))
dat += text("<A href='?src=\ref[];sec_rec=\ref[];software=securityrecord;sub=1'>[]: []<BR>", src, R, R.fields["id"], R.fields["name"])
if(src.subscreen == 1)
dat += "<h3>Security Record</h3>"
if ((istype(src.securityActive1, /datum/data/record) && data_core.general.Find(src.securityActive1)))
dat += text("Name: <A href='?src=\ref[];field=name'>[]</A><BR>\nID: <A href='?src=\ref[];field=id'>[]</A><BR>\nSex: <A href='?src=\ref[];field=sex'>[]</A><BR>\nAge: <A href='?src=\ref[];field=age'>[]</A><BR>\nRank: <A href='?src=\ref[];field=rank'>[]</A><BR>\nFingerprint: <A href='?src=\ref[];field=fingerprint'>[]</A><BR>\nPhysical Status: []<BR>\nMental Status: []<BR>", src, src.securityActive1.fields["name"], src, src.securityActive1.fields["id"], src, src.securityActive1.fields["sex"], src, src.securityActive1.fields["age"], src, src.securityActive1.fields["rank"], src, src.securityActive1.fields["fingerprint"], src.securityActive1.fields["p_stat"], src.securityActive1.fields["m_stat"])
else
dat += "<pre>Requested security record not found,</pre><BR>"
if ((istype(src.securityActive2, /datum/data/record) && data_core.security.Find(src.securityActive2)))
dat += text("<BR>\nSecurity Data<BR>\nCriminal Status: []<BR>\n<BR>\nMinor Crimes: <A href='?src=\ref[];field=mi_crim'>[]</A><BR>\nDetails: <A href='?src=\ref[];field=mi_crim_d'>[]</A><BR>\n<BR>\nMajor Crimes: <A href='?src=\ref[];field=ma_crim'>[]</A><BR>\nDetails: <A href='?src=\ref[];field=ma_crim_d'>[]</A><BR>\n<BR>\nImportant Notes:<BR>\n\t<A href='?src=\ref[];field=notes'>[]</A><BR>\n<BR>\n<CENTER><B>Comments/Log</B></CENTER><BR>", src.securityActive2.fields["criminal"], src, src.securityActive2.fields["mi_crim"], src, src.securityActive2.fields["mi_crim_d"], src, src.securityActive2.fields["ma_crim"], src, src.securityActive2.fields["ma_crim_d"], src, src.securityActive2.fields["notes"])
else
dat += "<pre>Requested security record not found,</pre><BR>"
dat += text("<BR>\n<A href='?src=\ref[];software=securityrecord;sub=0'>Back</A><BR>", src)
return dat
// Universal Translator
/mob/living/silicon/pai/proc/softwareTranslator()
var/dat = {"<h2>Universal Translator</h2><hr>
When enabled, this device will automatically convert all spoken and written languages into a format that any known recipient can understand.<br><br>
The device is currently [ (src.translator_on) ? "<font color=#55FF55>en" : "<font color=#FF5555>dis" ]abled</font>.<br>
<a href='byond://?src=\ref[src];software=translator;sub=0;toggle=1'>Toggle Device</a><br>
"}
return dat
// Security HUD
/mob/living/silicon/pai/proc/facialRecognition()
var/dat = {"<h2>Facial Recognition Suite</h2><hr>
When enabled, this package will scan all viewable faces and compare them against the known criminal database, providing real-time graphical data about any detected persons of interest.<br><br>
The suite is currently [ (src.secHUD) ? "<font color=#55FF55>en" : "<font color=#FF5555>dis" ]abled</font>.<br>
<a href='byond://?src=\ref[src];software=securityhud;sub=0;toggle=1'>Toggle Suite</a><br>
"}
return dat
// Medical HUD
/mob/living/silicon/pai/proc/medicalAnalysis()
var/dat = ""
if(src.subscreen == 0)
dat += {"<h2>Medical Analysis Suite</h2><hr>
<h4>Visual Status Overlay</h4>
When enabled, this package will scan all nearby crewmembers' vitals and provide real-time graphical data about their state of health.<br><br>
The suite is currently [ (src.medHUD) ? "<font color=#55FF55>en" : "<font color=#FF5555>dis" ]abled</font>.<br>
<a href='byond://?src=\ref[src];software=medicalhud;sub=0;toggle=1'>Toggle Suite</a><br>
<br>
<a href='byond://?src=\ref[src];software=medicalhud;sub=1'>Host Bioscan</a><br>
"}
if(src.subscreen == 1)
dat += {"<h2>Medical Analysis Suite</h2><hr>
<h4>Host Bioscan</h4>
"}
var/mob/living/M
//If we are not deployed, check the holder of the card.
if(src.loc == card)
M = card.loc
//If we are deployed or the card is not held, check the first living mob in our turf.
if(!M || !istype(M))
var/turf/T = get_turf(src)
M = locate(/mob/living/) in T.contents
if(!M || !istype(M))
src.temp = "Error: No biological host found. <br>"
src.subscreen = 0
return dat
dat += {"<b>Bioscan Results for [M]</b>: <br>
Overall Status: [M.stat > 1 ? "dead" : "[M.health]% healthy"] <br><br>
<b>Scan Breakdown</b>: <br>
Respiratory: [M.getOxyLoss() > 50 ? "<font color=#FF5555>" : "<font color=#55FF55>"][M.getOxyLoss()]</font><br>
Toxicology: [M.getToxLoss() > 50 ? "<font color=#FF5555>" : "<font color=#55FF55>"][M.getToxLoss()]</font><br>
Burns: [M.getFireLoss() > 50 ? "<font color=#FF5555>" : "<font color=#55FF55>"][M.getFireLoss()]</font><br>
Structural Integrity: [M.getBruteLoss() > 50 ? "<font color=#FF5555>" : "<font color=#55FF55>"][M.getBruteLoss()]</font><br>
Body Temperature: [M.bodytemperature-T0C]&deg;C ([M.bodytemperature*1.8-459.67]&deg;F)<br>
"}
for(var/datum/disease/D in M.viruses)
dat += {"<h4>Infection Detected.</h4><br>
Name: [D.name]<br>
Type: [D.spread]<br>
Stage: [D.stage]/[D.max_stages]<br>
Possible Cure: [D.cure]<br>
"}
dat += "<br><a href='byond://?src=\ref[src];software=medicalhud;sub=1'>Refresh Bioscan</a><br>"
dat += "<br><a href='byond://?src=\ref[src];software=medicalhud;sub=0'>Visual Status Overlay</a><br>"
return dat
// Atmospheric Scanner
/mob/living/silicon/pai/proc/softwareAtmo()
var/dat = "<h2>Atmospheric Sensor</h2><hr>"
var/turf/T = get_turf_or_move(src.loc)
if (isnull(T))
dat += "Unable to obtain a reading.<br>"
else
var/datum/gas_mixture/environment = T.return_air()
var/pressure = environment.return_pressure()
var/total_moles = environment.total_moles
dat += "Air Pressure: [round(pressure,0.1)] kPa<br>"
if(total_moles)
for(var/g in environment.gas)
dat += "[gas_data.name[g]]: [round((environment.gas[g] / total_moles) * 100)]%<br>"
dat += "Temperature: [round(environment.temperature-T0C)]&deg;C<br>"
dat += "<br><a href='byond://?src=\ref[src];software=atmosensor;sub=0'>Refresh Reading</a>"
return dat
// Camera Jack - Clearly not finished
/mob/living/silicon/pai/proc/softwareCamera()
var/dat = "<h2>Camera Jack</h2><hr>"
dat += "Cable status : "
if(!src.cable)
dat += "<font color=#FF5555>Retracted</font> <br>"
return dat
if(!src.cable.machine)
dat += "<font color=#FFFF55>Extended</font> <br>"
return dat
var/obj/machinery/machine = src.cable.machine
dat += "<font color=#55FF55>Connected</font> <br>"
if(!istype(machine, /obj/machinery/camera))
src << "DERP"
return dat
// Door Jack
/mob/living/silicon/pai/proc/softwareDoor()
var/dat = "<h2>Airlock Jack</h2><hr>"
dat += "Cable status : "
if(!src.cable)
dat += "<font color=#FF5555>Retracted</font> <br>"
dat += "<a href='byond://?src=\ref[src];software=doorjack;cable=1;sub=0'>Extend Cable</a> <br>"
return dat
if(!src.cable.machine)
dat += "<font color=#FFFF55>Extended</font> <br>"
return dat
var/obj/machinery/machine = src.cable.machine
dat += "<font color=#55FF55>Connected</font> <br>"
if(!istype(machine, /obj/machinery/door))
dat += "Connected device's firmware does not appear to be compatible with Airlock Jack protocols.<br>"
return dat
// var/obj/machinery/airlock/door = machine
if(!src.hackdoor)
dat += "<a href='byond://?src=\ref[src];software=doorjack;jack=1;sub=0'>Begin Airlock Jacking</a> <br>"
else
dat += "Jack in progress... [src.hackprogress]% complete.<br>"
dat += "<a href='byond://?src=\ref[src];software=doorjack;cancel=1;sub=0'>Cancel Airlock Jack</a> <br>"
//src.hackdoor = machine
//src.hackloop()
return dat
// Door Jack - supporting proc
/mob/living/silicon/pai/proc/hackloop()
var/turf/T = get_turf_or_move(src.loc)
for(var/mob/living/silicon/ai/AI in player_list)
if(T.loc)
AI << "<font color = red><b>Network Alert: Brute-force encryption crack in progress in [T.loc].</b></font>"
else
AI << "<font color = red><b>Network Alert: Brute-force encryption crack in progress. Unable to pinpoint location.</b></font>"
while(src.hackprogress < 100)
if(src.cable && src.cable.machine && istype(src.cable.machine, /obj/machinery/door) && src.cable.machine == src.hackdoor && get_dist(src, src.hackdoor) <= 1)
hackprogress += rand(1, 10)
else
src.temp = "Door Jack: Connection to airlock has been lost. Hack aborted."
hackprogress = 0
src.hackdoor = null
return
if(hackprogress >= 100) // This is clunky, but works. We need to make sure we don't ever display a progress greater than 100,
hackprogress = 100 // but we also need to reset the progress AFTER it's been displayed
if(src.screen == "doorjack" && src.subscreen == 0) // Update our view, if appropriate
src.paiInterface()
if(hackprogress >= 100)
src.hackprogress = 0
src.cable.machine:open()
sleep(50) // Update every 5 seconds
// Digital Messenger
/mob/living/silicon/pai/proc/pdamessage()
var/dat = "<h2>Digital Messenger</h2><hr>"
dat += {"<b>Signal/Receiver Status:</b> <A href='byond://?src=\ref[src];software=pdamessage;toggler=1'>
[(pda.toff) ? "<font color='red'> \[Off\]</font>" : "<font color='green'> \[On\]</font>"]</a><br>
<b>Ringer Status:</b> <A href='byond://?src=\ref[src];software=pdamessage;ringer=1'>
[(pda.message_silent) ? "<font color='red'> \[Off\]</font>" : "<font color='green'> \[On\]</font>"]</a><br><br>"}
dat += "<ul>"
if(!pda.toff)
for (var/obj/item/device/pda/P in sortAtom(PDAs))
if (!P.owner||P.toff||P == src.pda||P.hidden) continue
dat += "<li><a href='byond://?src=\ref[src];software=pdamessage;target=\ref[P]'>[P]</a>"
dat += "</li>"
dat += "</ul>"
dat += "Messages: <hr>"
dat += "<style>td.a { vertical-align:top; }</style>"
dat += "<table>"
for(var/index in pda.tnote)
if(index["sent"])
dat += addtext("<tr><td class='a'><i><b>To</b></i></td><td class='a'><i><b>&rarr;</b></i></td><td><i><b><a href='byond://?src=\ref[src];software=pdamessage;target=",index["src"],"'>", index["owner"],"</a>: </b></i>", index["message"], "<br></td></tr>")
else
dat += addtext("<tr><td class='a'><i><b>From</b></i></td><td class='a'><i><b>&rarr;</b></i></td><td><i><b><a href='byond://?src=\ref[src];software=pdamessage;target=",index["target"],"'>", index["owner"],"</a>: </b></i>", index["message"], "<br></td></tr>")
dat += "</table>"
return dat
/mob/living/silicon/pai/proc/translator_toggle()
// Sol Common, Tradeband and Gutter are added with New() and are therefore the current default, always active languages
if(translator_on)
translator_on = 0
remove_language("Sinta'unathi")
remove_language("Siik'tajr")
remove_language("Skrellian")
src << "\blue Translator Module toggled OFF."
else
translator_on = 1
add_language("Sinta'unathi")
add_language("Siik'tajr")
add_language("Skrellian")
src << "\blue Translator Module toggled ON."
var/list/pai_emotions = list(
"Happy" = 1,
"Cat" = 2,
"Extremely Happy" = 3,
"Face" = 4,
"Laugh" = 5,
"Off" = 6,
"Sad" = 7,
"Angry" = 8,
"What" = 9
)
var/global/list/pai_software_by_key = list()
var/global/list/default_pai_software = list()
/hook/startup/proc/populate_pai_software_list()
var/r = 1 // I would use ., but it'd sacrifice runtime detection
for(var/type in typesof(/datum/pai_software) - /datum/pai_software)
var/datum/pai_software/P = new type()
if(pai_software_by_key[P.id])
var/datum/pai_software/O = pai_software_by_key[P.id]
world << "<span class='warning'>pAI software module [P.name] has the same key as [O.name]!</span>"
r = 0
continue
pai_software_by_key[P.id] = P
if(P.default)
default_pai_software[P.id] = P
return r
/mob/living/silicon/pai/New()
..()
software = default_pai_software.Copy()
/mob/living/silicon/pai/verb/paiInterface()
set category = "pAI Commands"
set name = "Software Interface"
ui_interact(src)
/mob/living/silicon/pai/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
if(user != src)
if(ui) ui.set_status(STATUS_CLOSE, 0)
return
if(ui_key != "main")
var/datum/pai_software/S = software[ui_key]
if(S && !S.toggle)
S.on_ui_interact(src, ui, force_open)
else
if(ui) ui.set_status(STATUS_CLOSE, 0)
return
var/data[0]
// Software we have bought
var/bought_software[0]
// Software we have not bought
var/not_bought_software[0]
for(var/key in pai_software_by_key)
var/datum/pai_software/S = pai_software_by_key[key]
var/software_data[0]
software_data["name"] = S.name
software_data["id"] = S.id
if(key in software)
software_data["on"] = S.is_active(src)
bought_software[++bought_software.len] = software_data
else
software_data["ram"] = S.ram_cost
not_bought_software[++not_bought_software.len] = software_data
data["bought"] = bought_software
data["not_bought"] = not_bought_software
data["available_ram"] = ram
// Emotions
var/emotions[0]
for(var/name in pai_emotions)
var/emote[0]
emote["name"] = name
emote["id"] = pai_emotions[name]
emotions[++emotions.len] = emote
data["emotions"] = emotions
data["current_emotion"] = card.current_emotion
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "pai_interface.tmpl", "pAI Software Interface", 450, 600)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
/mob/living/silicon/pai/Topic(href, href_list)
. = ..()
if(.) return
if(href_list["software"])
var/soft = href_list["software"]
var/datum/pai_software/S = software[soft]
if(S.toggle)
S.toggle(src)
else
ui_interact(src, ui_key = soft)
return 1
else if(href_list["stopic"])
var/soft = href_list["stopic"]
var/datum/pai_software/S = software[soft]
if(S)
return S.Topic(href, href_list)
else if(href_list["purchase"])
var/soft = href_list["purchase"]
var/datum/pai_software/S = pai_software_by_key[soft]
if(S && (ram >= S.ram_cost))
ram -= S.ram_cost
software[S.id] = S
return 1
else if(href_list["image"])
var/img = text2num(href_list["image"])
if(1 <= img && img <= 9)
card.setEmotion(img)
return 1
@@ -0,0 +1,528 @@
/datum/pai_software
// Name for the software. This is used as the button text when buying or opening/toggling the software
var/name = "pAI software module"
// RAM cost; pAIs start with 100 RAM, spending it on programs
var/ram_cost = 0
// ID for the software. This must be unique
var/id = ""
// Whether this software is a toggle or not
// Toggled software should override toggle() and is_active()
// Non-toggled software should override on_ui_interact() and Topic()
var/toggle = 1
// Whether pAIs should automatically receive this module at no cost
var/default = 0
proc/on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
return
proc/toggle(mob/living/silicon/pai/user)
return
proc/is_active(mob/living/silicon/pai/user)
return 0
/datum/pai_software/directives
name = "Directives"
ram_cost = 0
id = "directives"
toggle = 0
default = 1
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
var/data[0]
data["master"] = user.master
data["dna"] = user.master_dna
data["prime"] = user.pai_law0
data["supplemental"] = user.pai_laws
ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open)
if(!ui)
// Don't copy-paste this unless you're making a pAI software module!
ui = new(user, user, id, "pai_directives.tmpl", "pAI Directives", 450, 600)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
Topic(href, href_list)
var/mob/living/silicon/pai/P = usr
if(!istype(P)) return
if(href_list["getdna"])
var/mob/living/M = P.loc
var/count = 0
// Find the carrier
while(!istype(M, /mob/living))
if(!M || !M.loc || count > 6)
//For a runtime where M ends up in nullspace (similar to bluespace but less colourful)
src << "You are not being carried by anyone!"
return 0
M = M.loc
count++
// Check the carrier
var/answer = input(M, "[P] is requesting a DNA sample from you. Will you allow it to confirm your identity?", "[P] Check DNA", "No") in list("Yes", "No")
if(answer == "Yes")
var/turf/T = get_turf_or_move(P.loc)
for (var/mob/v in viewers(T))
v.show_message("<span class='notice'>[M] presses \his thumb against [P].</span>", 3, "<span class='notice'>[P] makes a sharp clicking sound as it extracts DNA material from [M].</span>", 2)
var/datum/dna/dna = M.dna
P << "<font color = red><h3>[M]'s UE string : [dna.unique_enzymes]</h3></font>"
if(dna.unique_enzymes == P.master_dna)
P << "<b>DNA is a match to stored Master DNA.</b>"
else
P << "<b>DNA does not match stored Master DNA.</b>"
else
P << "[M] does not seem like \he is going to provide a DNA sample willingly."
return 1
/datum/pai_software/radio_config
name = "Radio Configuration"
ram_cost = 0
id = "radio"
toggle = 0
default = 1
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui = null, force_open = 1)
var/data[0]
data["listening"] = user.radio.broadcasting
data["frequency"] = format_frequency(user.radio.frequency)
var/channels[0]
for(var/ch_name in user.radio.channels)
var/ch_stat = user.radio.channels[ch_name]
var/ch_dat[0]
ch_dat["name"] = ch_name
// FREQ_LISTENING is const in /obj/item/device/radio
ch_dat["listening"] = !!(ch_stat & user.radio.FREQ_LISTENING)
channels[++channels.len] = ch_dat
data["channels"] = channels
ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open)
if(!ui)
ui = new(user, user, id, "pai_radio.tmpl", "Radio Configuration", 300, 150)
ui.set_initial_data(data)
ui.open()
Topic(href, href_list)
var/mob/living/silicon/pai/P = usr
if(!istype(P)) return
P.radio.Topic(href, href_list)
return 1
/datum/pai_software/crew_manifest
name = "Crew Manifest"
ram_cost = 5
id = "manifest"
toggle = 0
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
data_core.get_manifest_json()
var/data[0]
// This is dumb, but NanoUI breaks if it has no data to send
data["a"] = "a"
if(ui)
ui.load_cached_data(ManifestJSON)
ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open)
if(!ui)
// Don't copy-paste this unless you're making a pAI software module!
ui = new(user, user, id, "pai_manifest.tmpl", "Crew Manifest", 450, 600)
ui.load_cached_data(ManifestJSON)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
/datum/pai_software/messenger
name = "Digital Messenger"
ram_cost = 5
id = "messenger"
toggle = 0
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
var/data[0]
data["receiver_off"] = user.pda.toff
data["ringer_off"] = user.pda.message_silent
data["current_ref"] = null
data["current_name"] = user.current_pda_messaging
var/pdas[0]
if(!user.pda.toff)
for(var/obj/item/device/pda/P in sortAtom(PDAs))
if(!P.owner || P.toff || P == user.pda || P.hidden) continue
var/pda[0]
pda["name"] = "[P]"
pda["owner"] = "[P.owner]"
pda["ref"] = "\ref[P]"
if(P.owner == user.current_pda_messaging)
data["current_ref"] = "\ref[P]"
pdas[++pdas.len] = pda
data["pdas"] = pdas
var/messages[0]
if(user.current_pda_messaging)
for(var/index in user.pda.tnote)
if(index["owner"] != user.current_pda_messaging)
continue
var/msg[0]
var/sent = index["sent"]
msg["sent"] = sent ? 1 : 0
msg["target"] = index["owner"]
msg["message"] = index["message"]
messages[++messages.len] = msg
data["messages"] = messages
ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open)
if(!ui)
// Don't copy-paste this unless you're making a pAI software module!
ui = new(user, user, id, "pai_messenger.tmpl", "Digital Messenger", 450, 600)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
Topic(href, href_list)
var/mob/living/silicon/pai/P = usr
if(!istype(P)) return
if(!isnull(P.pda))
if(href_list["toggler"])
P.pda.toff = href_list["toggler"] != "1"
return 1
else if(href_list["ringer"])
P.pda.message_silent = href_list["ringer"] != "1"
return 1
else if(href_list["select"])
var/s = href_list["select"]
if(s == "*NONE*")
P.current_pda_messaging = null
else
P.current_pda_messaging = s
return 1
else if(href_list["target"])
if(P.silence_time)
return alert("Communications circuits remain uninitialized.")
var/target = locate(href_list["target"])
P.pda.create_message(P, target, 1)
return 1
/datum/pai_software/med_records
name = "Medical Records"
ram_cost = 15
id = "med_records"
toggle = 0
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
var/data[0]
var/records[0]
for(var/datum/data/record/general in sortRecord(data_core.general))
var/record[0]
record["name"] = general.fields["name"]
record["ref"] = "\ref[general]"
records[++records.len] = record
data["records"] = records
var/datum/data/record/G = user.medicalActive1
var/datum/data/record/M = user.medicalActive2
data["general"] = G ? G.fields : null
data["medical"] = M ? M.fields : null
data["could_not_find"] = user.medical_cannotfind
ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open)
if(!ui)
// Don't copy-paste this unless you're making a pAI software module!
ui = new(user, user, id, "pai_medrecords.tmpl", "Medical Records", 450, 600)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
Topic(href, href_list)
var/mob/living/silicon/pai/P = usr
if(!istype(P)) return
if(href_list["select"])
var/datum/data/record/record = locate(href_list["select"])
if(record)
var/datum/data/record/R = record
var/datum/data/record/M = null
if (!( data_core.general.Find(R) ))
P.medical_cannotfind = 1
else
P.medical_cannotfind = 0
for(var/datum/data/record/E in data_core.medical)
if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"]))
M = E
P.medicalActive1 = R
P.medicalActive2 = M
else
P.medical_cannotfind = 1
return 1
/datum/pai_software/sec_records
name = "Security Records"
ram_cost = 15
id = "sec_records"
toggle = 0
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
var/data[0]
var/records[0]
for(var/datum/data/record/general in sortRecord(data_core.general))
var/record[0]
record["name"] = general.fields["name"]
record["ref"] = "\ref[general]"
records[++records.len] = record
data["records"] = records
var/datum/data/record/G = user.securityActive1
var/datum/data/record/S = user.securityActive2
data["general"] = G ? G.fields : null
data["security"] = S ? S.fields : null
data["could_not_find"] = user.security_cannotfind
ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open)
if(!ui)
// Don't copy-paste this unless you're making a pAI software module!
ui = new(user, user, id, "pai_secrecords.tmpl", "Security Records", 450, 600)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
Topic(href, href_list)
var/mob/living/silicon/pai/P = usr
if(!istype(P)) return
if(href_list["select"])
var/datum/data/record/record = locate(href_list["select"])
if(record)
var/datum/data/record/R = record
var/datum/data/record/S = null
if (!( data_core.general.Find(R) ))
P.securityActive1 = null
P.securityActive2 = null
P.security_cannotfind = 1
else
P.security_cannotfind = 0
for(var/datum/data/record/E in data_core.security)
if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"]))
S = E
P.securityActive1 = R
P.securityActive2 = S
else
P.securityActive1 = null
P.securityActive2 = null
P.security_cannotfind = 1
return 1
/datum/pai_software/door_jack
name = "Door Jack"
ram_cost = 30
id = "door_jack"
toggle = 0
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
var/data[0]
data["cable"] = user.cable != null
data["machine"] = user.cable && (user.cable.machine != null)
data["inprogress"] = user.hackdoor != null
data["progress_a"] = round(user.hackprogress / 10)
data["progress_b"] = user.hackprogress % 10
data["aborted"] = user.hack_aborted
ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open)
if(!ui)
// Don't copy-paste this unless you're making a pAI software module!
ui = new(user, user, id, "pai_doorjack.tmpl", "Door Jack", 300, 150)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
Topic(href, href_list)
var/mob/living/silicon/pai/P = usr
if(!istype(P)) return
if(href_list["jack"])
if(P.cable && P.cable.machine)
P.hackdoor = P.cable.machine
P.hackloop()
return 1
else if(href_list["cancel"])
P.hackdoor = null
return 1
else if(href_list["cable"])
var/turf/T = get_turf_or_move(P.loc)
P.hack_aborted = 0
P.cable = new /obj/item/weapon/pai_cable(T)
for(var/mob/M in viewers(T))
M.show_message("<span class='warning'>A port on [P] opens to reveal [P.cable], which promptly falls to the floor.</span>", 3,
"<span class='warning'>You hear the soft click of something light and hard falling to the ground.</span>", 2)
return 1
/mob/living/silicon/pai/proc/hackloop()
var/turf/T = get_turf_or_move(src.loc)
for(var/mob/living/silicon/ai/AI in player_list)
if(T.loc)
AI << "<font color = red><b>Network Alert: Brute-force encryption crack in progress in [T.loc].</b></font>"
else
AI << "<font color = red><b>Network Alert: Brute-force encryption crack in progress. Unable to pinpoint location.</b></font>"
var/obj/machinery/door/D = cable.machine
if(!istype(D))
hack_aborted = 1
hackprogress = 0
cable.machine = null
hackdoor = null
return
while(hackprogress < 1000)
if(cable && cable.machine == D && cable.machine == hackdoor && get_dist(src, hackdoor) <= 1)
hackprogress = min(hackprogress+rand(1, 20), 1000)
else
hack_aborted = 1
hackprogress = 0
hackdoor = null
return
if(hackprogress >= 1000)
hackprogress = 0
D.open()
cable.machine = null
return
sleep(10) // Update every second
/datum/pai_software/atmosphere_sensor
name = "Atmosphere Sensor"
ram_cost = 5
id = "atmos_sense"
toggle = 0
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
var/data[0]
var/turf/T = get_turf_or_move(user.loc)
if(!T)
data["reading"] = 0
data["pressure"] = 0
data["temperature"] = 0
data["temperatureC"] = 0
data["gas"] = list()
else
var/datum/gas_mixture/env = T.return_air()
data["reading"] = 1
var/pres = env.return_pressure() * 10
data["pressure"] = "[round(pres/10)].[pres%10]"
data["temperature"] = round(env.temperature)
data["temperatureC"] = round(env.temperature-T0C)
var/t_moles = env.total_moles
var/gases[0]
for(var/g in env.gas)
var/gas[0]
gas["name"] = gas_data.name[g]
gas["percent"] = round((env.gas[g] / t_moles) * 100)
gases[++gases.len] = gas
data["gas"] = gases
ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open)
if(!ui)
// Don't copy-paste this unless you're making a pAI software module!
ui = new(user, user, id, "pai_atmosphere.tmpl", "Atmosphere Sensor", 350, 300)
ui.set_initial_data(data)
ui.open()
/datum/pai_software/sec_hud
name = "Security HUD"
ram_cost = 20
id = "sec_hud"
toggle(mob/living/silicon/pai/user)
user.secHUD = !user.secHUD
is_active(mob/living/silicon/pai/user)
return user.secHUD
/datum/pai_software/med_hud
name = "Medical HUD"
ram_cost = 20
id = "med_hud"
toggle(mob/living/silicon/pai/user)
user.medHUD = !user.medHUD
is_active(mob/living/silicon/pai/user)
return user.medHUD
/datum/pai_software/translator
name = "Universal Translator"
ram_cost = 35
id = "translator"
toggle(mob/living/silicon/pai/user)
// Sol Common, Tradeband and Gutter are added with New() and are therefore the current default, always active languages
user.translator_on = !user.translator_on
if(user.translator_on)
user.add_language("Sinta'unathi")
user.add_language("Siik'tajr")
user.add_language("Skrellian")
else
user.remove_language("Sinta'unathi")
user.remove_language("Siik'tajr")
user.remove_language("Skrellian")
is_active(mob/living/silicon/pai/user)
return user.translator_on
/datum/pai_software/signaller
name = "Remote Signaller"
ram_cost = 5
id = "signaller"
toggle = 0
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
var/data[0]
data["frequency"] = format_frequency(user.sradio.frequency)
data["code"] = user.sradio.code
ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open)
if(!ui)
// Don't copy-paste this unless you're making a pAI software module!
ui = new(user, user, id, "pai_signaller.tmpl", "Signaller", 320, 150)
ui.load_cached_data(ManifestJSON)
ui.set_initial_data(data)
ui.open()
Topic(href, href_list)
var/mob/living/silicon/pai/P = usr
if(!istype(P)) return
if(href_list["send"])
P.sradio.send_signal("ACTIVATE")
for(var/mob/O in hearers(1, P.loc))
O.show_message(text("\icon[] *beep* *beep*", P), 3, "*beep* *beep*", 2)
return 1
else if(href_list["freq"])
var/new_frequency = (P.sradio.frequency + text2num(href_list["freq"]))
if(new_frequency < 1200 || new_frequency > 1600)
new_frequency = sanitize_frequency(new_frequency)
P.sradio.set_frequency(new_frequency)
return 1
else if(href_list["code"])
P.sradio.code += text2num(href_list["code"])
P.sradio.code = round(P.sradio.code)
P.sradio.code = min(100, P.sradio.code)
P.sradio.code = max(1, P.sradio.code)
return 1
@@ -6,7 +6,7 @@
icon_state = "robotanalyzer"
item_state = "analyzer"
desc = "A hand-held scanner able to diagnose robotic injuries."
flags = FPRINT | TABLEPASS | CONDUCT
flags = CONDUCT
slot_flags = SLOT_BELT
throwforce = 3
w_class = 2.0
@@ -77,6 +77,11 @@
playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0)
//Redefining some robot procs...
/mob/living/silicon/robot/drone/SetName(pickedName as text)
// Would prefer to call the grandparent proc but this isn't possible, so..
real_name = pickedName
name = real_name
/mob/living/silicon/robot/drone/updatename()
real_name = "maintenance drone ([rand(100,999)])"
name = real_name
+5 -10
View File
@@ -81,6 +81,7 @@ var/list/robot_verbs_default = list(
var/lockcharge //Used when locking down a borg to preserve cell charge
var/speed = 0 //Cause sec borgs gotta go fast //No they dont!
var/scrambledcodes = 0 // Used to determine if a borg shows up on the robotics console. Setting to one hides them.
var/tracking_entities = 0 //The number of known entities currently accessing the internal camera
var/braintype = "Cyborg"
/mob/living/silicon/robot/syndicate
@@ -184,6 +185,10 @@ var/list/robot_verbs_default = list(
playsound(loc, 'sound/mecha/nominalsyndi.ogg', 75, 0)
/mob/living/silicon/robot/SetName(pickedName as text)
custom_name = pickedName
updatename()
/mob/living/silicon/robot/proc/sync()
if(lawupdate && connected_ai)
lawsync()
@@ -1276,16 +1281,6 @@ var/list/robot_verbs_default = list(
return 1
return 0
/mob/living/silicon/robot/syndicate/canUseTopic(atom/movable/M)
if(stat || lockcharge || stunned || weakened)
return
if(z in config.admin_levels)
return 1
if(istype(M, /obj/machinery))
var/obj/machinery/Machine = M
return Machine.emagged
return 1
/mob/living/silicon/robot/proc/notify_ai(var/notifytype, var/oldname, var/newname)
if(!connected_ai)
return
@@ -4,7 +4,7 @@
icon_state = "std_module"
w_class = 100.0
item_state = "electronic"
flags = FPRINT|TABLEPASS | CONDUCT
flags = CONDUCT
var/channels = list()
var/list/modules = list()
var/obj/item/emag = null
@@ -223,9 +223,9 @@
src.modules += new /obj/item/borg/sight/hud/sec(src)
src.modules += new /obj/item/weapon/handcuffs/cyborg(src)
src.modules += new /obj/item/weapon/melee/baton/robot(src)
src.modules += new /obj/item/weapon/gun/energy/taser/cyborg(src)
src.modules += new /obj/item/weapon/gun/energy/taser/mounted/cyborg(src)
src.modules += new /obj/item/taperoll/police(src)
src.emag = new /obj/item/weapon/gun/energy/laser/cyborg(src)
src.emag = new /obj/item/weapon/gun/energy/laser/mounted(src)
return
/obj/item/weapon/robot_module/security/respawn_consumable(var/mob/living/silicon/robot/R)
@@ -236,7 +236,7 @@
F.icon_state = "flash"
else if(F.times_used)
F.times_used--
var/obj/item/weapon/gun/energy/taser/cyborg/T = locate() in src.modules
var/obj/item/weapon/gun/energy/taser/mounted/cyborg/T = locate() in src.modules
if(T.power_supply.charge < T.power_supply.maxcharge)
T.power_supply.give(T.charge_cost)
T.update_icon()
@@ -383,11 +383,11 @@
..()
src.modules += new /obj/item/device/flash(src)
src.modules += new /obj/item/borg/sight/thermal(src)
src.modules += new /obj/item/weapon/gun/energy/laser/cyborg(src)
src.modules += new /obj/item/weapon/gun/energy/laser/mounted(src)
src.modules += new /obj/item/weapon/pickaxe/plasmacutter(src)
src.modules += new /obj/item/borg/combat/shield(src)
src.modules += new /obj/item/borg/combat/mobility(src)
src.emag = new /obj/item/weapon/gun/energy/lasercannon/cyborg(src)
src.emag = new /obj/item/weapon/gun/energy/lasercannon/mounted(src)
return
/obj/item/weapon/robot_module/drone
@@ -108,7 +108,7 @@
usr << "There's no mounting point for the module!"
return 0
var/obj/item/weapon/gun/energy/taser/cyborg/T = locate() in R.module
var/obj/item/weapon/gun/energy/taser/mounted/cyborg/T = locate() in R.module
if(!T)
T = locate() in R.module.contents
if(!T)
+7 -3
View File
@@ -30,6 +30,10 @@
..()
add_language("Galactic Common")
/mob/living/silicon/proc/SetName(pickedName as text)
real_name = pickedName
name = real_name
/mob/living/silicon/proc/show_laws()
return
@@ -226,14 +230,14 @@
set desc = "Sets a description which will be shown when someone examines you."
set category = "IC"
pose = copytext(sanitize(input(usr, "This is [src]. It is...", "Pose", null) as text), 1, MAX_MESSAGE_LEN)
pose = sanitize(copytext(input(usr, "This is [src]. It is...", "Pose", null) as text, 1, MAX_MESSAGE_LEN))
/mob/living/silicon/verb/set_flavor()
set name = "Set Flavour Text"
set desc = "Sets an extended description of your character's features."
set category = "IC"
flavor_text = copytext(sanitize(input(usr, "Please enter your new flavour text.", "Flavour text", null) as text), 1)
flavor_text = sanitize(copytext(input(usr, "Please enter your new flavour text.", "Flavour text", null) as text, 1))
/mob/living/silicon/binarycheck()
return 1
@@ -277,4 +281,4 @@
if (stat != 2)
adjustBruteLoss(30)
updatehealth()
updatehealth()
@@ -4,6 +4,7 @@
icon = 'icons/obj/apiary_bees_etc.dmi'
icon_state = "bees1"
icon_dead = "bees1"
mob_size = 1
var/strength = 1
var/feral = 0
var/mut = 0
@@ -129,6 +129,7 @@
melee_damage_lower = 30
melee_damage_upper = 30
attacktext = "smashed their armoured gauntlet into"
mob_size = 20
speed = 3
wall_smash = 1
attack_sound = 'sound/weapons/punch3.ogg'
@@ -165,8 +166,8 @@
var/reflectchance = 80 - round(P.damage/3)
if(prob(reflectchance))
adjustBruteLoss(P.damage * 0.5)
visible_message("<span class='danger'>The [P.name] gets reflected by [src]'s shell!</span>", \
"<span class='userdanger'>The [P.name] gets reflected by [src]'s shell!</span>")
visible_message("<span class='danger'>\The [P] was reflected by \the [src]'s shell!</span>", \
"<span class='userdanger'>\The [P] was reflected by \the [src]'s shell!</span>")
// Find a turf near or on the original location to bounce to
if(P.starting)
@@ -175,12 +176,7 @@
var/turf/curloc = get_turf(src)
// redirect the projectile
P.original = locate(new_x, new_y, P.z)
P.starting = curloc
P.current = curloc
P.firer = src
P.yo = new_y - curloc.y
P.xo = new_x - curloc.x
P.redirect(new_x, new_y, curloc, src)
return -1 // complete projectile permutation
@@ -259,6 +255,7 @@
speed = 5
wall_smash = 1
attack_sound = 'sound/weapons/punch4.ogg'
mob_size = 20
var/energy = 0
var/max_energy = 1000
@@ -22,6 +22,7 @@
minbodytemp = 223 //Below -50 Degrees Celcius
maxbodytemp = 323 //Above 50 Degrees Celcius
holder_type = /obj/item/weapon/holder/cat
mob_size = 5
/mob/living/simple_animal/cat/Life()
//MICE!
@@ -50,7 +51,7 @@
if(turns_since_scan > 5)
walk_to(src,0)
turns_since_scan = 0
if((movement_target) && !(isturf(movement_target.loc) || ishuman(movement_target.loc) ))
movement_target = null
stop_automated_movement = 0
@@ -18,6 +18,8 @@
response_disarm = "bops"
response_harm = "kicks"
see_in_dark = 5
mob_size = 8
var/obj/item/inventory_head
var/obj/item/inventory_back
var/facehugger
@@ -17,6 +17,7 @@
response_harm = "stomps"
stop_automated_movement = 1
friendly = "pinches"
mob_size = 5
var/obj/item/inventory_head
var/obj/item/inventory_mask
@@ -14,4 +14,5 @@
melee_damage_upper = 2
response_help = "pets"
response_disarm = "shoos"
response_harm = "stomps on"
response_harm = "stomps on"
mob_size = 1
@@ -28,6 +28,7 @@
maxbodytemp = 323 //Above 50 Degrees Celcius
universal_speak = 0
universal_understand = 1
mob_size = 1
/mob/living/simple_animal/mouse/Life()
..()
@@ -5,6 +5,7 @@
max_co2 = 0
minbodytemp = 0
maxbodytemp = 500
mob_size = 5
var/obj/item/device/radio/borg/radio = null
var/mob/living/silicon/ai/connected_ai = null
@@ -38,7 +38,7 @@
icon_state = "russianranged"
icon_living = "russianranged"
corpse = /obj/effect/landmark/mobcorpse/russian/ranged
weapon1 = /obj/item/weapon/gun/projectile/mateba
weapon1 = /obj/item/weapon/gun/projectile/revolver/mateba
ranged = 1
projectiletype = /obj/item/projectile/bullet
projectilesound = 'sound/weapons/Gunshot.ogg'
@@ -108,7 +108,7 @@
icon_living = "syndicateranged"
casingtype = /obj/item/ammo_casing/a12mm
projectilesound = 'sound/weapons/Gunshot_smg.ogg'
projectiletype = /obj/item/projectile/bullet/midbullet2
projectiletype = /obj/item/projectile/bullet/pistol/medium
weapon1 = /obj/item/weapon/gun/projectile/automatic/c20r
+68 -15
View File
@@ -130,14 +130,14 @@
return 1
return 0
//This is a SAFE proc. Use this instead of equip_to_splot()!
//This is a SAFE proc. Use this instead of equip_to_slot()!
//set del_on_fail to have it delete W if it fails to equip
//set disable_warning to disable the 'you are unable to equip that' warning.
//unset redraw_mob to prevent the mob from being redrawn at the end.
/mob/proc/equip_to_slot_if_possible(obj/item/W as obj, slot, del_on_fail = 0, disable_warning = 0, redraw_mob = 1)
if(!istype(W)) return 0
if(!W.mob_can_equip(src, slot, disable_warning))
if(!W.mob_can_equip(src, slot))
if(del_on_fail)
del(W)
else
@@ -792,7 +792,7 @@ note dizziness decrements automatically in the mob's Life() proc.
/mob/Stat()
..()
if(statpanel("Status")) //not looking at that panel
if(statpanel("MC")) //not looking at that panel
if(client && client.holder)
stat(null,"Location:\t([x], [y], [z])")
@@ -808,6 +808,7 @@ note dizziness decrements automatically in the mob's Life() proc.
stat(null,"Obj-[master_controller.objects_cost]\t#[processing_objects.len]")
stat(null,"Net-[master_controller.networks_cost]\tPnet-[master_controller.powernets_cost]")
stat(null,"NanoUI-[master_controller.nano_cost]\t#[nanomanager.processing_uis.len]")
stat(null,"Events-[master_controller.events_cost]\t#[event_manager.active_events.len]")
stat(null,"Tick-[master_controller.ticker_cost]\tALL-[master_controller.total_cost]")
else
stat(null,"MasterController-ERROR")
@@ -839,9 +840,7 @@ note dizziness decrements automatically in the mob's Life() proc.
// facing verbs
/mob/proc/canface()
if(!canmove) return 0
if(client.moving) return 0
if(world.time < client.move_delay) return 0
if(stat==2) return 0
if(stat) return 0
if(anchored) return 0
if(monkeyizing) return 0
return 1
@@ -855,21 +854,17 @@ note dizziness decrements automatically in the mob's Life() proc.
canmove = 0
pixel_y = V.mob_offset_y - 5
else
lying = 0
if(buckled.buckle_lying != -1) lying = buckled.buckle_lying
canmove = 1
pixel_y = V.mob_offset_y
else if(buckled)
if (!buckled.movable)
if(buckled.buckle_lying != -1) lying = buckled.buckle_lying
if (!buckled.buckle_movable)
anchored = 1
canmove = 0
if(istype(buckled,/obj/structure/stool/bed/chair) )
lying = 0
else
lying = 1
else
anchored = 0
canmove = 1
lying = 0
else if( stat || weakened || paralysis || resting || sleeping || (status_flags & FAKEDEATH))
lying = 1
canmove = 0
@@ -903,9 +898,10 @@ note dizziness decrements automatically in the mob's Life() proc.
/mob/proc/facedir(var/ndir)
if(!canface()) return 0
if(!canface() || client.moving || world.time < client.move_delay)
return 0
set_dir(ndir)
if(buckled && buckled.movable)
if(buckled && buckled.buckle_movable)
buckled.set_dir(ndir)
client.move_delay += movement_delay()
return 1
@@ -937,6 +933,7 @@ note dizziness decrements automatically in the mob's Life() proc.
/mob/proc/Stun(amount)
if(status_flags & CANSTUN)
facing_dir = null
stunned = max(max(stunned,amount),0) //can't go below 0, getting a low amount of stun doesn't lower your current stun
return
@@ -952,6 +949,7 @@ note dizziness decrements automatically in the mob's Life() proc.
/mob/proc/Weaken(amount)
if(status_flags & CANWEAKEN)
facing_dir = null
weakened = max(max(weakened,amount),0)
update_canmove() //updates lying, canmove and icons
return
@@ -970,6 +968,7 @@ note dizziness decrements automatically in the mob's Life() proc.
/mob/proc/Paralyse(amount)
if(status_flags & CANPARALYSE)
facing_dir = null
paralysis = max(max(paralysis,amount),0)
return
@@ -984,6 +983,7 @@ note dizziness decrements automatically in the mob's Life() proc.
return
/mob/proc/Sleeping(amount)
facing_dir = null
sleeping = max(max(sleeping,amount),0)
return
@@ -996,6 +996,7 @@ note dizziness decrements automatically in the mob's Life() proc.
return
/mob/proc/Resting(amount)
facing_dir = null
resting = max(max(resting,amount),0)
return
@@ -1159,3 +1160,55 @@ mob/proc/yank_out_object()
/mob/proc/updateicon()
return
/mob/verb/face_direction()
set name = "Face Direction"
set category = "IC"
set src = usr
set_face_dir()
if(!facing_dir)
usr << "You are now not facing anything."
else
usr << "You are now facing [dir2text(facing_dir)]."
/mob/proc/set_face_dir(var/newdir)
if(newdir)
set_dir(newdir)
facing_dir = newdir
else if(facing_dir)
facing_dir = null
else
set_dir(dir)
facing_dir = dir
/mob/set_dir()
if(facing_dir)
if(!canface() || lying || buckled || restrained())
facing_dir = null
else if(dir != facing_dir)
return ..(facing_dir)
else
return ..()
/mob/verb/northfaceperm()
set hidden = 1
facing_dir = null
set_face_dir(NORTH)
/mob/verb/southfaceperm()
set hidden = 1
facing_dir = null
set_face_dir(SOUTH)
/mob/verb/eastfaceperm()
set hidden = 1
facing_dir = null
set_face_dir(EAST)
/mob/verb/westfaceperm()
set hidden = 1
facing_dir = null
set_face_dir(WEST)
+2 -1
View File
@@ -90,6 +90,7 @@
var/list/languages = list() // For speaking/listening.
var/list/speak_emote = list("says") // Verbs used when speaking. Defaults to 'say' if speak_emote is null.
var/emote_type = 1 // Define emote default type, 1 for seen emotes, 2 for heard emotes
var/facing_dir = null // Used for the ancient art of moonwalking.
var/name_archive //For admin things like possession
@@ -214,7 +215,7 @@
var/universal_understand = 0 // Set to 1 to enable the mob to understand everyone, not necessarily speak
var/stance_damage = 0 //Whether this mob's ability to stand has been affected
//SSD var, changed it up some so people can have special things happen for different mobs when SSD.
var/player_logged = 0
+3 -3
View File
@@ -193,16 +193,16 @@
return
if(M == assailant && state >= GRAB_AGGRESSIVE)
var/can_eat
var/can_eat
if((FAT in user.mutations) && ismonkey(affecting))
can_eat = 1
else
var/mob/living/carbon/human/H = user
if(istype(H) && iscarbon(affecting) && H.species.gluttonous)
if(istype(H) && H.species.gluttonous)
if(H.species.gluttonous == 2)
can_eat = 2
else if(!ishuman(affecting))
else if(!ishuman(affecting) && !ismonkey(affecting) && (affecting.small || iscarbon(affecting)))
can_eat = 1
if(can_eat)
+3 -3
View File
@@ -305,7 +305,7 @@ proc/slur(phrase)
n_letter = text("[n_letter]-[n_letter]")
t = text("[t][n_letter]")//since the above is ran through for each letter, the text just adds up back to the original word.
p++//for each letter p is increased to find where the next letter will be.
return copytext(sanitize(t),1,MAX_MESSAGE_LEN)
return sanitize(copytext(t,1,MAX_MESSAGE_LEN))
proc/Gibberish(t, p)//t is the inputted message, and any value higher than 70 for p will cause letters to be replaced instead of added
@@ -352,7 +352,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
n_letter = text("[n_letter]")
t = text("[t][n_letter]")
p=p+n_mod
return copytext(sanitize(t),1,MAX_MESSAGE_LEN)
return sanitize(copytext(t,1,MAX_MESSAGE_LEN))
/proc/shake_camera(mob/M, duration, strength=1)
@@ -416,7 +416,7 @@ var/list/intents = list("help","disarm","grab","hurt")
set name = "a-intent"
set hidden = 1
if(ishuman(src) || isbrain(src))
if(ishuman(src) || isbrain(src) || isslime(src))
switch(input)
if("help","disarm","grab","hurt")
a_intent = input
+21 -7
View File
@@ -284,7 +284,7 @@
proc/IsJobAvailable(rank)
var/datum/job/job = job_master.GetJob(rank)
if(!job) return 0
if((job.current_positions >= job.total_positions) && job.total_positions != -1) return 0
if(!job.is_position_available()) return 0
if(jobban_isbanned(src,rank)) return 0
if(!job.player_old_enough(src.client)) return 0
return 1
@@ -313,6 +313,24 @@
UpdateFactionList(character)
EquipCustomItems(character)
// AIs don't need a spawnpoint, they must spawn at an empty core
if(character.mind.assigned_role == "AI")
character = character.AIize(move=0) // AIize the character, but don't move them yet
// IsJobAvailable for AI checks that there is an empty core available in this list
var/obj/structure/AIcore/deactivated/C = empty_playable_ai_cores[1]
empty_playable_ai_cores -= C
character.loc = C.loc
AnnounceCyborg(character, rank, "has been downloaded to the empty core in \the [character.loc.loc]")
ticker.mode.latespawn(character)
del(C)
del(src)
return
//Find our spawning point.
var/join_message
var/datum/spawnpoint/S
@@ -356,20 +374,16 @@
proc/AnnounceArrival(var/mob/living/carbon/human/character, var/rank, var/join_message)
if (ticker.current_state == GAME_STATE_PLAYING)
var/obj/item/device/radio/intercom/a = new /obj/item/device/radio/intercom(null)// BS12 EDIT Arrivals Announcement Computer, rather than the AI.
if(character.mind.role_alt_title)
rank = character.mind.role_alt_title
a.autosay("[character.real_name],[rank ? " [rank]," : " visitor," ] [join_message ? join_message : "has arrived on the station"].", "Arrivals Announcement Computer")
del(a)
global_announcer.autosay("[character.real_name],[rank ? " [rank]," : " visitor," ] [join_message ? join_message : "has arrived on the station"].", "Arrivals Announcement Computer")
proc/AnnounceCyborg(var/mob/living/character, var/rank, var/join_message)
if (ticker.current_state == GAME_STATE_PLAYING)
var/obj/item/device/radio/intercom/a = new /obj/item/device/radio/intercom(null)// BS12 EDIT Arrivals Announcement Computer, rather than the AI.
if(character.mind.role_alt_title)
rank = character.mind.role_alt_title
// can't use their name here, since cyborg namepicking is done post-spawn, so we'll just say "A new Cyborg has arrived"/"A new Android has arrived"/etc.
a.autosay("A new[rank ? " [rank]" : " visitor" ] [join_message ? join_message : "has arrived on the station"].", "Arrivals Announcement Computer")
del(a)
global_announcer.autosay("A new[rank ? " [rank]" : " visitor" ] [join_message ? join_message : "has arrived on the station"].", "Arrivals Announcement Computer")
proc/LateChoices()
var/mills = world.time // 1/10 of a second, not real milliseconds but whatever
+27 -26
View File
@@ -56,13 +56,13 @@
spawning = 1
return ..()
/mob/living/carbon/human/AIize()
/mob/living/carbon/human/AIize(move=1) // 'move' argument needs defining here too because BYOND is dumb
if (monkeyizing)
return
for(var/t in organs)
del(t)
return ..()
return ..(move)
/mob/living/carbon/AIize()
if (monkeyizing)
@@ -75,7 +75,7 @@
invisibility = 101
return ..()
/mob/proc/AIize()
/mob/proc/AIize(move=1)
if(client)
src << sound(null, repeat = 0, wait = 0, volume = 85, channel = 1) // stop the jams for AIs
var/mob/living/silicon/ai/O = new (loc, base_law_type,,1)//No MMI but safety is in effect.
@@ -88,37 +88,38 @@
else
O.key = key
var/obj/loc_landmark
for(var/obj/effect/landmark/start/sloc in landmarks_list)
if (sloc.name != "AI")
continue
if (locate(/mob/living) in sloc.loc)
continue
loc_landmark = sloc
if (!loc_landmark)
for(var/obj/effect/landmark/tripai in landmarks_list)
if (tripai.name == "tripai")
if(locate(/mob/living) in tripai.loc)
continue
loc_landmark = tripai
if (!loc_landmark)
O << "Oh god sorry we can't find an unoccupied AI spawn location, so we're spawning you on top of someone."
if(move)
var/obj/loc_landmark
for(var/obj/effect/landmark/start/sloc in landmarks_list)
if (sloc.name == "AI")
loc_landmark = sloc
if (sloc.name != "AI")
continue
if ((locate(/mob/living) in sloc.loc) || (locate(/obj/structure/AIcore) in sloc.loc))
continue
loc_landmark = sloc
if (!loc_landmark)
for(var/obj/effect/landmark/tripai in landmarks_list)
if (tripai.name == "tripai")
if((locate(/mob/living) in tripai.loc) || (locate(/obj/structure/AIcore) in tripai.loc))
continue
loc_landmark = tripai
if (!loc_landmark)
O << "Oh god sorry we can't find an unoccupied AI spawn location, so we're spawning you on top of someone."
for(var/obj/effect/landmark/start/sloc in landmarks_list)
if (sloc.name == "AI")
loc_landmark = sloc
O.loc = loc_landmark.loc
for (var/obj/item/device/radio/intercom/comm in O.loc)
comm.ai += O
O.loc = loc_landmark.loc
for (var/obj/item/device/radio/intercom/comm in O.loc)
comm.ai += O
O.on_mob_init()
O.add_ai_verbs()
O.rename_self("ai",1)
. = O
del(src)
spawn(0)
del(src)
return O
//human -> robot
/mob/living/carbon/human/proc/Robotize()