mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-07-11 23:23:55 +01:00
Merge remote-tracking branch 'upstream/dev' into sprites
Conflicts: icons/mob/items_lefthand.dmi icons/mob/items_righthand.dmi
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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]")
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
..()
|
||||
*/
|
||||
@@ -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
|
||||
@@ -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
|
||||
..()
|
||||
*/
|
||||
..()
|
||||
@@ -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]")
|
||||
..()
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
Executable → Regular
+5
-1
@@ -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)
|
||||
|
||||
Executable → Regular
+125
-711
@@ -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 += " [src.pai_law0]<br>"
|
||||
dat += "<b>Supplemental Directives</b><br>"
|
||||
dat += " [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]°C ([M.bodytemperature*1.8-459.67]°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)]°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>→</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>→</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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user