April sync (#360)

* Maps and things no code/icons

* helpers defines globalvars

* Onclick world.dm orphaned_procs

* subsystems

Round vote and shuttle autocall done here too

* datums

* Game folder

* Admin - chatter modules

* clothing - mining

* modular computers - zambies

* client

* mob level 1

* mob stage 2 + simple_animal

* silicons n brains

* mob stage 3 + Alien/Monkey

* human mobs

* icons updated

* some sounds

* emitter y u no commit

* update tgstation.dme

* compile fixes

* travis fixes

Also removes Fast digest mode, because reasons.

* tweaks for travis Mentors are broke again

Also fixes Sizeray guns

* oxygen loss fix for vore code.

* removes unused code

* some code updates

* bulk fixes

* further fixes

* outside things

* whoops.

* Maint bar ported

* GLOBs.
This commit is contained in:
Poojawa
2017-04-13 23:37:00 -05:00
committed by GitHub
parent cdc32c98fa
commit 7e9b96a00f
1322 changed files with 174827 additions and 23888 deletions
+4 -6
View File
@@ -1,5 +1,3 @@
/obj/item/device/mmi
name = "Man-Machine Interface"
desc = "The Warrior's bland acronym, MMI, obscures the true horror of this monstrosity, that nevertheless has become standard-issue on Nanotrasen stations."
@@ -66,8 +64,8 @@
brainmob.container = src
if(!newbrain.damaged_brain) // the brain organ hasn't been beaten to death.
brainmob.stat = CONSCIOUS //we manually revive the brain mob
dead_mob_list -= brainmob
living_mob_list += brainmob
GLOB.dead_mob_list -= brainmob
GLOB.living_mob_list += brainmob
brainmob.reset_perspective()
brain = newbrain
@@ -99,8 +97,8 @@
brainmob.stat = DEAD
brainmob.emp_damage = 0
brainmob.reset_perspective() //so the brainmob follows the brain organ instead of the mmi. And to update our vision
living_mob_list -= brainmob //Get outta here
dead_mob_list += brainmob
GLOB.living_mob_list -= brainmob //Get outta here
GLOB.dead_mob_list += brainmob
brain.brainmob = brainmob //Set the brain to use the brainmob
brainmob = null //Set mmi brainmob var to null
if(user)
+1 -3
View File
@@ -1,8 +1,6 @@
/mob/living/brain
languages_spoken = HUMAN
languages_understood = HUMAN
var/obj/item/device/mmi/container = null
var/timeofhostdeath = 0
var/emp_damage = 0//Handles a type of MMI damage
@@ -64,4 +62,4 @@
/mob/living/brain/fully_replace_character_name(oldname,newname)
..()
if(stored_dna)
stored_dna.real_name = real_name
stored_dna.real_name = real_name
+1 -1
View File
@@ -20,7 +20,7 @@
/datum/emote/brain/flash
key = "flash"
message = "lights' blink."
message = "blinks their lights."
/datum/emote/brain/notice
key = "notice"
+45 -43
View File
@@ -1,4 +1,4 @@
var/global/posibrain_notif_cooldown = 0
GLOBAL_VAR(posibrain_notify_cooldown)
/obj/item/device/mmi/posibrain
name = "positronic brain"
@@ -7,11 +7,11 @@ var/global/posibrain_notif_cooldown = 0
icon_state = "posibrain"
w_class = WEIGHT_CLASS_NORMAL
origin_tech = "biotech=3;programming=3;plasmatech=2"
var/notified = 0
var/next_ask
var/askDelay = 600 //one minute
var/used = 0 //Prevents split personality virus. May be reset if personality deletion code is added.
var/searching = FALSE
brainmob = null
req_access = list(access_robotics)
req_access = list(GLOB.access_robotics)
mecha = null//This does not appear to be used outside of reference in mecha.dm.
braintype = "Android"
var/autoping = TRUE //if it pings on creation immediately
@@ -25,9 +25,8 @@ var/global/posibrain_notif_cooldown = 0
Remember, the purpose of your existence is to serve the crew and the station. Above all else, do no harm.</b>"
var/new_mob_message = "<span class='notice'>The positronic brain chimes quietly.</span>"
var/dead_message = "<span class='deadsay'>It appears to be completely inactive. The reset light is blinking.</span>"
var/list/fluff_names = list("PBU","HIU","SINA","ARMA","OSI","HBL","MSO","RR","CHRI","CDB","HG","XSI","ORNG","GUN","KOR","MET","FRE","XIS","SLI","PKP","HOG","RZH","GOOF","MRPR","JJR","FIRC","INC","PHL","BGB","ANTR","MIW","WJ","JRD","CHOC","ANCL","JLLO","JNLG","KOS","TKRG","XAL","STLP","CBOS","DUNC","FXMC","DRSD")
var/picked_fluff_name //which fluff name we picked
var/list/possible_names //If you leave this blank, it will use the global posibrain names
var/picked_name
/obj/item/device/mmi/posibrain/Topic(href, href_list)
if(href_list["activate"])
@@ -36,42 +35,42 @@ var/global/posibrain_notif_cooldown = 0
activate(ghost)
/obj/item/device/mmi/posibrain/proc/ping_ghosts(msg, newlymade)
if(newlymade || !posibrain_notif_cooldown)
if(newlymade || GLOB.posibrain_notify_cooldown <= world.time)
notify_ghosts("[name] [msg] in [get_area(src)]!", ghost_sound = !newlymade ? 'sound/effects/ghost2.ogg':null, enter_link = "<a href=?src=\ref[src];activate=1>(Click to enter)</a>", source = src, action = NOTIFY_ATTACK, flashwindow = FALSE)
if(!newlymade)
posibrain_notif_cooldown = 1
addtimer(CALLBACK(src, .proc/reset_posibrain_cooldown), askDelay)
/obj/item/device/mmi/posibrain/proc/reset_posibrain_cooldown()
posibrain_notif_cooldown = 0
GLOB.posibrain_notify_cooldown = world.time + askDelay
/obj/item/device/mmi/posibrain/attack_self(mob/user)
if(brainmob && !brainmob.key && !notified)
//Start the process of requesting a new ghost.
to_chat(user, begin_activation_message)
ping_ghosts("requested", FALSE)
notified = 1
used = 0
update_icon()
spawn(askDelay) //Seperate from the global cooldown.
notified = 0
update_icon()
if(brainmob.client)
visible_message(success_message)
else
visible_message(fail_message)
return //Code for deleting personalities recommended here.
if(!brainmob || brainmob.key)
return
if(next_ask > world.time)
return
//Start the process of requesting a new ghost.
to_chat(user, begin_activation_message)
ping_ghosts("requested", FALSE)
next_ask = world.time + askDelay
searching = TRUE
addtimer(CALLBACK(src, .proc/check_success), askDelay)
/obj/item/device/mmi/posibrain/proc/check_success()
searching = FALSE
update_icon()
if(QDELETED(brainmob))
return
if(brainmob.client)
visible_message(success_message)
else
visible_message(fail_message)
/obj/item/device/mmi/posibrain/attack_ghost(mob/user)
activate(user)
//Two ways to activate a positronic brain. A clickable link in the ghost notif, or simply clicking the object itself.
/obj/item/device/mmi/posibrain/proc/activate(mob/user)
if(used || (brainmob && brainmob.key) || jobban_isbanned(user,"posibrain"))
if(QDELETED(brainmob))
return
if(brainmob.key || jobban_isbanned(user,"posibrain"))
return
var/posi_ask = alert("Become a [name]? (Warning, You can no longer be cloned, and all past lives will be forgotten!)","Are you positive?","Yes","No")
if(posi_ask == "No" || QDELETED(src))
return
@@ -97,10 +96,11 @@ var/global/posibrain_notif_cooldown = 0
update_icon()
/obj/item/device/mmi/posibrain/proc/transfer_personality(mob/candidate)
if(used || (brainmob && brainmob.key)) //Prevents hostile takeover if two ghosts get the prompt or link for the same brain.
if(QDELETED(brainmob))
return
if(brainmob.key) //Prevents hostile takeover if two ghosts get the prompt or link for the same brain.
to_chat(candidate, "This brain has already been taken! Please try your possession again later!")
return FALSE
notified = 0
if(candidate.mind && !isobserver(candidate))
candidate.mind.transfer_to(brainmob)
else
@@ -109,12 +109,11 @@ var/global/posibrain_notif_cooldown = 0
to_chat(brainmob, welcome_message)
brainmob.mind.assigned_role = new_role
brainmob.stat = CONSCIOUS
dead_mob_list -= brainmob
living_mob_list += brainmob
GLOB.dead_mob_list -= brainmob
GLOB.living_mob_list += brainmob
visible_message(new_mob_message)
update_icon()
used = 1
return TRUE
@@ -124,7 +123,7 @@ var/global/posibrain_notif_cooldown = 0
if(brainmob && brainmob.key)
switch(brainmob.stat)
if(CONSCIOUS)
if(!src.brainmob.client)
if(!brainmob.client)
msg = "It appears to be in stand-by mode." //afk
if(DEAD)
msg = "<span class='deadsay'>It appears to be completely inactive.</span>"
@@ -133,24 +132,27 @@ var/global/posibrain_notif_cooldown = 0
to_chat(user, msg)
/obj/item/device/mmi/posibrain/New()
/obj/item/device/mmi/posibrain/Initialize()
..()
brainmob = new(src)
picked_fluff_name = pick(fluff_names)
brainmob.name = "[picked_fluff_name]-[rand(100, 999)]"
var/new_name
if(!LAZYLEN(possible_names))
new_name = pick(GLOB.posibrain_names)
else
new_name = pick(possible_names)
brainmob.name = "[new_name]-[rand(100, 999)]"
brainmob.real_name = brainmob.name
brainmob.loc = src
brainmob.container = src
if(autoping)
ping_ghosts("created", TRUE)
..()
/obj/item/device/mmi/posibrain/attackby(obj/item/O, mob/user)
return
/obj/item/device/mmi/posibrain/update_icon()
if(notified)
if(searching)
icon_state = "[initial(icon_state)]-searching"
return
if(brainmob && brainmob.key)
+13 -4
View File
@@ -1,4 +1,4 @@
/mob/living/brain/say(message)
/mob/living/brain/say(message, language)
if(!(container && istype(container, /obj/item/device/mmi)))
return //No MMI, can't speak, bucko./N
else
@@ -7,16 +7,17 @@
return
else
message = Gibberish(message, (emp_damage*6))//scrambles the message, gets worse when emp_damage is higher
..()
/mob/living/brain/get_spans()
return ..() | SPAN_ROBOT
/mob/living/brain/radio(message, message_mode, list/spans)
/mob/living/brain/radio(message, message_mode, list/spans, language)
if(message_mode && istype(container, /obj/item/device/mmi))
var/obj/item/device/mmi/R = container
if(R.radio)
R.radio.talk_into(src, message, , spans)
R.radio.talk_into(src, message, , get_spans(), language)
return ITALICS | REDUCE_RANGE
/mob/living/brain/lingcheck()
@@ -24,4 +25,12 @@
/mob/living/brain/treat_message(message)
message = capitalize(message)
return message
return message
/mob/living/brain/can_speak_in_language(datum/language/dt)
if(HAS_SECONDARY_FLAG(src, OMNITONGUE))
. = has_language(dt)
else if(istype(container, /obj/item/device/mmi/posibrain/soul_vessel))
. = has_language(dt) && ispath(dt, /datum/language/ratvar)
else
. = ..()
@@ -11,15 +11,13 @@
dna = null
faction = list("alien")
ventcrawler = VENTCRAWLER_ALWAYS
languages_spoken = ALIEN
languages_understood = ALIEN
sight = SEE_MOBS
see_in_dark = 4
verb_say = "hisses"
initial_languages = list(/datum/language/xenocommon)
bubble_icon = "alien"
type_of_meat = /obj/item/weapon/reagent_containers/food/snacks/meat/slab/xeno
var/nightvision = 1
devourable = 1
var/obj/item/weapon/card/id/wear_id = null // Fix for station bounced radios -- Skie
var/has_fine_manipulation = 0
@@ -111,7 +109,7 @@ Des: Gives the client of the alien an image on each infected mob.
----------------------------------------*/
/mob/living/carbon/alien/proc/AddInfectionImages()
if (client)
for (var/mob/living/C in mob_list)
for (var/mob/living/C in GLOB.mob_list)
if(C.status_flags & XENO_HOST)
var/obj/item/organ/body_egg/alien_embryo/A = C.getorgan(/obj/item/organ/body_egg/alien_embryo)
if(A)
@@ -74,7 +74,8 @@ In all, this is a lot like the monkey code. /N
/mob/living/carbon/alien/attack_animal(mob/living/simple_animal/M)
if(..())
. = ..()
if(.)
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
switch(M.melee_damage_type)
if(BRUTE)
@@ -89,7 +90,6 @@ In all, this is a lot like the monkey code. /N
adjustCloneLoss(damage)
if(STAMINA)
adjustStaminaLoss(damage)
updatehealth()
/mob/living/carbon/alien/attack_slime(mob/living/simple_animal/slime/M)
if(..()) //successful slime attack
@@ -1,30 +0,0 @@
/datum/emote/living/alien
mob_type_allowed_typecache = list(/mob/living/carbon/alien)
/datum/emote/living/alien/gnarl
key = "gnarl"
key_third_person = "gnarls"
message = "gnarls and shows its teeth..."
/datum/emote/living/alien/hiss
key = "hiss"
key_third_person = "hisses"
message_alien = "hisses."
message_larva = "hisses softly."
/datum/emote/living/alien/hiss/run_emote(mob/user, params)
. = ..()
if(. && isalienadult(user))
playsound(user.loc, "hiss", 40, 1, 1)
/datum/emote/living/alien/roar
key = "roar"
key_third_person = "roars"
message_alien = "roars"
message_larva = "softly roars"
emote_type = EMOTE_AUDIBLE
/datum/emote/living/alien/roar/run_emote(mob/user, params)
. = ..()
if(. && isalienadult(user))
playsound(user.loc, 'sound/voice/hiss5.ogg', 40, 1, 1)
@@ -87,7 +87,7 @@ Doesn't work on other aliens/AI.*/
log_say("AlienWhisper: [key_name(user)]->[M.key] : [msg]")
to_chat(M, "<span class='noticealien'>You hear a strange, alien voice in your head...</span>[msg]")
to_chat(user, "<span class='noticealien'>You said: \"[msg]\" to [M]</span>")
for(var/ded in dead_mob_list)
for(var/ded in GLOB.dead_mob_list)
if(!isobserver(ded))
continue
var/follow_link_user = FOLLOW_LINK(ded, user)
@@ -13,7 +13,7 @@
if(stat == DEAD)
return
for(var/mob/living/carbon/C in living_mob_list)
for(var/mob/living/carbon/C in GLOB.living_mob_list)
if(C == src) //Make sure not to proc it on ourselves.
continue
var/obj/item/organ/alien/hivenode/node = C.getorgan(/obj/item/organ/alien/hivenode)
@@ -108,7 +108,7 @@
//For alien evolution/promotion/queen finder procs. Checks for an active alien of that type
/proc/get_alien_type(var/alienpath)
for(var/mob/living/carbon/alien/humanoid/A in living_mob_list)
for(var/mob/living/carbon/alien/humanoid/A in GLOB.living_mob_list)
if(!istype(A, alienpath))
continue
if(!A.key || A.stat == DEAD) //Only living aliens with a ckey are valid.
@@ -46,7 +46,7 @@
/mob/living/carbon/alien/humanoid/royal/queen/Initialize()
//there should only be one queen
for(var/mob/living/carbon/alien/humanoid/royal/queen/Q in living_mob_list)
for(var/mob/living/carbon/alien/humanoid/royal/queen/Q in GLOB.living_mob_list)
if(Q == src)
continue
if(Q.stat == DEAD)
+2 -2
View File
@@ -5,10 +5,10 @@
var/message_a = say_quote(message, get_spans())
var/rendered = "<i><span class='alien'>Hivemind, <span class='name'>[shown_name]</span> <span class='message'>[message_a]</span></span></i>"
for(var/mob/S in player_list)
for(var/mob/S in GLOB.player_list)
if(!S.stat && S.hivecheck())
to_chat(S, rendered)
if(S in dead_mob_list)
if(S in GLOB.dead_mob_list)
var/link = FOLLOW_LINK(S, src)
to_chat(S, "[link] [rendered]")
@@ -117,7 +117,7 @@ Proc: AddInfectionImages(C)
Des: Adds the infection image to all aliens for this embryo
----------------------------------------*/
/obj/item/organ/body_egg/alien_embryo/AddInfectionImages()
for(var/mob/living/carbon/alien/alien in player_list)
for(var/mob/living/carbon/alien/alien in GLOB.player_list)
if(alien.client)
var/I = image('icons/mob/alien.dmi', loc = owner, icon_state = "infected[stage]")
alien.client.images += I
@@ -127,7 +127,7 @@ Proc: RemoveInfectionImage(C)
Des: Removes all images from the mob infected by this embryo
----------------------------------------*/
/obj/item/organ/body_egg/alien_embryo/RemoveInfectionImages()
for(var/mob/living/carbon/alien/alien in player_list)
for(var/mob/living/carbon/alien/alien in GLOB.player_list)
if(alien.client)
for(var/image/I in alien.client.images)
if(dd_hasprefix_case(I.icon_state, "infected") && I.loc == owner)
@@ -2,11 +2,11 @@
//TODO: Make these simple_animals
var/const/MIN_IMPREGNATION_TIME = 100 //time it takes to impregnate someone
var/const/MAX_IMPREGNATION_TIME = 150
#define MIN_IMPREGNATION_TIME 100 //time it takes to impregnate someone
#define MAX_IMPREGNATION_TIME 150
var/const/MIN_ACTIVE_TIME = 200 //time between being dropped and going idle
var/const/MAX_ACTIVE_TIME = 400
#define MIN_ACTIVE_TIME 200 //time between being dropped and going idle
#define MAX_ACTIVE_TIME 400
/obj/item/clothing/mask/facehugger
name = "alien"
@@ -152,14 +152,6 @@ var/const/MAX_ACTIVE_TIME = 400
// probiscis-blocker handling
if(iscarbon(M))
var/mob/living/carbon/target = M
if(target.wear_mask)
var/obj/item/clothing/W = target.wear_mask
if(W.flags & NODROP)
return FALSE
if(!istype(W,/obj/item/clothing/mask/facehugger))
target.dropItemToGround(W)
target.visible_message("<span class='danger'>[src] tears [W] off of [target]'s face!</span>", \
"<span class='userdanger'>[src] tears [W] off of [target]'s face!</span>")
if(ishuman(M))
var/mob/living/carbon/human/H = M
@@ -168,6 +160,12 @@ var/const/MAX_ACTIVE_TIME = 400
"<span class='userdanger'>[src] smashes against [H]'s [H.head]!</span>")
Die()
return FALSE
if(target.wear_mask)
var/obj/item/clothing/W = target.wear_mask
if(!istype(W,/obj/item/clothing/mask/facehugger) && target.dropItemToGround(W))
target.visible_message("<span class='danger'>[src] tears [W] off of [target]'s face!</span>", \
"<span class='userdanger'>[src] tears [W] off of [target]'s face!</span>")
forceMove(target)
target.equip_to_slot_if_possible(src, slot_wear_mask, 0, 1, 1)
// early returns and validity checks done: attach.
+7 -1
View File
@@ -522,6 +522,7 @@
return
sight = initial(sight)
lighting_alpha = initial(lighting_alpha)
var/obj/item/organ/eyes/E = getorganslot("eye_sight")
if(!E)
update_tint()
@@ -529,6 +530,8 @@
see_invisible = E.see_invisible
see_in_dark = E.see_in_dark
sight |= E.sight_flags
if(!isnull(E.lighting_alpha))
lighting_alpha = E.lighting_alpha
if(client.eye != src)
var/atom/A = client.eye
@@ -543,6 +546,8 @@
see_invisible = G.invis_override
else
see_invisible = min(G.invis_view, see_invisible)
if(!isnull(G.lighting_alpha))
lighting_alpha = min(lighting_alpha, G.lighting_alpha)
if(dna)
for(var/X in dna.mutations)
var/datum/mutation/M = X
@@ -552,11 +557,12 @@
if(see_override)
see_invisible = see_override
. = ..()
//to recalculate and update the mob's total tint from tinted equipment it's wearing.
/mob/living/carbon/proc/update_tint()
if(!tinted_weldhelh)
if(!GLOB.tinted_weldhelh)
return
tinttotal = get_total_tint()
if(tinttotal >= TINT_BLIND)
@@ -44,4 +44,7 @@
/obj/item/bodypart/r_arm, /obj/item/bodypart/r_leg, /obj/item/bodypart/l_leg)
//Gets filled up in create_bodyparts()
var/list/hand_bodyparts = list() //a collection of arms (or actually whatever the fug /bodyparts you monsters use to wreck my systems)
var/list/hand_bodyparts = list() //a collection of arms (or actually whatever the fug /bodyparts you monsters use to wreck my systems)
var/icon_render_key = ""
var/static/list/limb_icon_cache = list()
@@ -19,12 +19,6 @@
if(legcuffed)
. += legcuffed.slowdown
var/const/NO_SLIP_WHEN_WALKING = 1
var/const/SLIDE = 2
var/const/GALOSHES_DONT_HELP = 4
var/const/SLIDE_ICE = 8
/mob/living/carbon/slip(s_amount, w_amount, obj/O, lube)
if(movement_type & FLYING)
return 0
@@ -147,8 +147,8 @@
parts -= picked
if(updating_health)
updatehealth()
if(update)
update_damage_overlays()
if(update)
update_damage_overlays()
// damage MANY bodyparts, in random order
/mob/living/carbon/take_overall_damage(brute, burn, updating_health = 1)
+5 -5
View File
@@ -9,8 +9,8 @@
emote("deathgasp")
. = ..()
if(ticker && ticker.mode)
ticker.mode.check_win() //Calls the rounds wincheck, mainly for wizard, malf, and changeling now
if(SSticker && SSticker.mode)
SSticker.mode.check_win() //Calls the rounds wincheck, mainly for wizard, malf, and changeling now
/mob/living/carbon/gib(no_brain, no_organs, no_bodyparts)
for(var/mob/M in src)
@@ -35,7 +35,7 @@
if(org_zone == "chest")
O.Remove(src)
O.forceMove(get_turf(src))
O.throw_at(get_edge_target_turf(src,pick(alldirs)),rand(1,3),5)
O.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),5)
else
for(var/X in internal_organs)
var/obj/item/organ/I = X
@@ -44,11 +44,11 @@
continue
I.Remove(src)
I.forceMove(get_turf(src))
I.throw_at(get_edge_target_turf(src,pick(alldirs)),rand(1,3),5)
I.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),5)
/mob/living/carbon/spread_bodyparts()
for(var/X in bodyparts)
var/obj/item/bodypart/BP = X
BP.drop_limb()
BP.throw_at(get_edge_target_turf(src,pick(alldirs)),rand(1,3),5)
BP.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),5)
@@ -10,8 +10,11 @@
else
new /obj/effect/gibspawner/humanbodypartless(loc, viruses, dna)
/mob/living/carbon/human/spawn_dust()
new /obj/effect/decal/remains/human(loc)
/mob/living/carbon/human/spawn_dust(just_ash = FALSE)
if(just_ash)
new /obj/effect/decal/cleanable/ash(loc)
else
new /obj/effect/decal/remains/human(loc)
/mob/living/carbon/human/death(gibbed)
if(stat == DEAD)
@@ -29,7 +32,7 @@
dna.species.spec_death(gibbed, src)
if(ticker && ticker.mode)
if(SSticker && SSticker.mode)
sql_report_death(src)
if(mind && mind.devilinfo)
INVOKE_ASYNC(mind.devilinfo, /datum/devilinfo.proc/beginResurrectionCheck, src)
@@ -142,7 +142,7 @@
if(!key)
var/foundghost = 0
if(mind)
for(var/mob/dead/observer/G in player_list)
for(var/mob/dead/observer/G in GLOB.player_list)
if(G.mind == mind)
foundghost = 1
if (G.can_reenter_corpse == 0)
@@ -257,9 +257,6 @@
msg += "[t_He] looks like a drunken mess.\n"
if(91.01 to INFINITY)
msg += "[t_He] [t_is] a shitfaced, slobbering wreck.\n"
for (var/I in src.vore_organs)
var/datum/belly/B = vore_organs[I]
msg += B.get_examine_msg()
msg += "</span>"
@@ -292,7 +289,7 @@
if(istype(H.glasses, /obj/item/clothing/glasses/hud) || CIH)
var/perpname = get_face_name(get_id_name(""))
if(perpname)
var/datum/data/record/R = find_record("name", perpname, data_core.general)
var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.general)
if(R)
msg += "<span class='deptradio'>Rank:</span> [R.fields["rank"]]<br>"
msg += "<a href='?src=\ref[src];hud=1;photo_front=1'>\[Front photo\]</a> "
@@ -310,7 +307,7 @@
msg += "<a href='?src=\ref[src];hud=m;p_stat=1'>\[[health_r]\]</a>"
health_r = R.fields["m_stat"]
msg += "<a href='?src=\ref[src];hud=m;m_stat=1'>\[[health_r]\]</a><br>"
R = find_record("name", perpname, data_core.medical)
R = find_record("name", perpname, GLOB.data_core.medical)
if(R)
msg += "<a href='?src=\ref[src];hud=m;evaluation=1'>\[Medical evaluation\]</a><br>"
@@ -320,7 +317,7 @@
//|| !user.canmove || user.restrained()) Fluff: Sechuds have eye-tracking technology and sets 'arrest' to people that the wearer looks and blinks at.
var/criminal = "None"
R = find_record("name", perpname, data_core.security)
R = find_record("name", perpname, GLOB.data_core.security)
if(R)
criminal = R.fields["criminal"]
@@ -1,54 +0,0 @@
/mob/living/carbon/human/proc/examine_nutrition()
var/message = ""
var/nutrition_examine = round(nutrition)
var/t_He = "It" //capitalised for use at the start of each line.
var/t_His = "Its"
var/t_his = "its"
var/t_is = "is"
var/t_has = "has"
switch(gender)
if(MALE)
t_He = "He"
t_his = "his"
t_His = "His"
if(FEMALE)
t_He = "She"
t_his = "her"
t_His = "Her"
if(PLURAL)
t_He = "They"
t_his = "their"
t_His = "Their"
t_is = "are"
t_has = "have"
if(NEUTER)
t_He = "It"
t_his = "its"
t_His = "Its"
switch(nutrition_examine)
if(0 to 49)
message = "<span class='warning'>[t_He] [t_is] starving! You can hear [t_his] stomach snarling from across the room!</span>\n"
if(50 to 99)
message = "<span class='warning'>[t_He] [t_is] extremely hungry. A deep growl occasionally rumbles from [t_his] empty stomach.</span>\n"
if(100 to 499)
return message //Well that's pretty normal, really.
if(500 to 864) // Fat.
message = "[t_He] [t_has] a stuffed belly, bloated fat and round from eating too much.\n"
if(1200 to 1934) // One person fully digested.
message = "<span class='warning'>[t_He] [t_is] sporting a large, round, sagging stomach. It's contains at least their body weight worth of glorping slush.</span>\n"
if(1935 to 3004) // Two people.
message = "<span class='warning'>[t_He] [t_is] engorged with a huge stomach that sags and wobbles as they move. [t_He] must have consumed at least twice their body weight. It looks incredibly soft.</span>\n"
if(3005 to 4074) // Three people.
message = "<span class='warning'>[t_His] stomach is firmly packed with digesting slop. [t_He] must have eaten at least a few times worth their body weight! It looks hard for them to stand, and [t_his] gut jiggles when they move.</span>\n"
if(4075 to 10000) // Four or more people.
message = "<span class='warning'>[t_He] [t_is] so absolutely stuffed that you aren't sure how it's possible to move. [t_He] can't seem to swell any bigger. The surface of [t_his] belly looks sorely strained!</span>\n"
return message
/mob/living/carbon/human/proc/examine_bellies()
var/message = ""
for (var/I in src.vore_organs)
var/datum/belly/B = vore_organs[I]
message += B.get_examine_msg()
return message
+25 -17
View File
@@ -17,6 +17,9 @@
args[1] = FALSE
Initialize(arglist(args))
/mob/living/carbon/human/dummy/Life()
return
/mob/living/carbon/human/Initialize()
verbs += /mob/living/proc/mob_sleep
verbs += /mob/living/proc/lay_down
@@ -39,6 +42,8 @@
handcrafting = new()
grant_language(/datum/language/common) // ME TARZAN, YOU JANEBOT
..()
/mob/living/carbon/human/create_internal_organs()
@@ -298,7 +303,7 @@
var/mob/living/carbon/human/H = usr
var/perpname = get_face_name(get_id_name(""))
if(istype(H.glasses, /obj/item/clothing/glasses/hud) || istype(H.getorganslot("eye_hud"), /obj/item/organ/cyberimp/eyes/hud))
var/datum/data/record/R = find_record("name", perpname, data_core.general)
var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.general)
if(href_list["photo_front"] || href_list["photo_side"])
if(R)
if(!H.canUseHUD())
@@ -388,7 +393,7 @@
if (!G.emagged)
if(H.wear_id)
var/list/access = H.wear_id.GetAccess()
if(access_sec_doors in access)
if(GLOB.access_sec_doors in access)
allowed_access = H.get_authentification_name()
else
allowed_access = "@%&ERROR_%$*"
@@ -399,7 +404,7 @@
return
if(perpname)
R = find_record("name", perpname, data_core.security)
R = find_record("name", perpname, GLOB.data_core.security)
if(R)
if(href_list["status"])
var/setcriminal = input(usr, "Specify a new criminal status for this person.", "Security HUD", R.fields["criminal"]) in list("None", "*Arrest*", "Incarcerated", "Parolled", "Discharged", "Cancel")
@@ -447,8 +452,8 @@
return
else if(!istype(H.glasses, /obj/item/clothing/glasses/hud/security) && !istype(H.getorganslot("eye_hud"), /obj/item/organ/cyberimp/eyes/hud/security))
return
var/crime = data_core.createCrimeEntry(t1, t2, allowed_access, worldtime2text())
data_core.addMinorCrime(R.fields["id"], crime)
var/crime = GLOB.data_core.createCrimeEntry(t1, t2, allowed_access, worldtime2text())
GLOB.data_core.addMinorCrime(R.fields["id"], crime)
to_chat(usr, "<span class='notice'>Successfully added a minor crime.</span>")
return
if("Major Crime")
@@ -462,8 +467,8 @@
return
else if (!istype(H.glasses, /obj/item/clothing/glasses/hud/security) && !istype(H.getorganslot("eye_hud"), /obj/item/organ/cyberimp/eyes/hud/security))
return
var/crime = data_core.createCrimeEntry(t1, t2, allowed_access, worldtime2text())
data_core.addMajorCrime(R.fields["id"], crime)
var/crime = GLOB.data_core.createCrimeEntry(t1, t2, allowed_access, worldtime2text())
GLOB.data_core.addMajorCrime(R.fields["id"], crime)
to_chat(usr, "<span class='notice'>Successfully added a major crime.</span>")
return
@@ -494,7 +499,7 @@
var/counter = 1
while(R.fields[text("com_[]", counter)])
counter++
R.fields[text("com_[]", counter)] = text("Made by [] on [] [], []<BR>[]", allowed_access, worldtime2text(), time2text(world.realtime, "MMM DD"), year_integer+540, t1)
R.fields[text("com_[]", counter)] = text("Made by [] on [] [], []<BR>[]", allowed_access, worldtime2text(), time2text(world.realtime, "MMM DD"), GLOB.year_integer+540, t1)
to_chat(usr, "<span class='notice'>Successfully added comment.</span>")
return
to_chat(usr, "<span class='warning'>Unable to locate a data core entry for this person.</span>")
@@ -581,7 +586,7 @@
//Check for weapons
if(judgebot.weaponscheck)
if(!idcard || !(access_weapons in idcard.access))
if(!idcard || !(GLOB.access_weapons in idcard.access))
for(var/obj/item/I in held_items)
if(judgebot.check_for_weapons(I))
threatcount += 4
@@ -591,7 +596,7 @@
//Check for arrest warrant
if(judgebot.check_records)
var/perpname = get_face_name(get_id_name())
var/datum/data/record/R = find_record("name", perpname, data_core.security)
var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.security)
if(R && R.fields["criminal"])
switch(R.fields["criminal"])
if("*Arrest*")
@@ -765,7 +770,7 @@
..()
/mob/living/carbon/human/replace_records_name(oldname,newname) // Only humans have records right now, move this up if changed.
for(var/list/L in list(data_core.general,data_core.medical,data_core.security,data_core.locked))
for(var/list/L in list(GLOB.data_core.general,GLOB.data_core.medical,GLOB.data_core.security,GLOB.data_core.locked))
var/datum/data/record/R = find_record("name", oldname, L)
if(R)
R.fields["name"] = newname
@@ -855,7 +860,7 @@
if(7) // Pride
log_game("[src] was influenced by the sin of pride.")
O = new /datum/objective/sintouched/pride
ticker.mode.sintouched += src.mind
SSticker.mode.sintouched += src.mind
src.mind.objectives += O
src.mind.announce_objectives()
@@ -920,12 +925,15 @@
return
if(buckled) //NO INFINITE STACKING!!
return
if(M.incapacitated(FALSE, TRUE) || incapacitated(FALSE, TRUE))
M.visible_message("<span class='boldwarning'>[M] can't hang onto [src]!</span>")
return
if(iscarbon(M) && (!riding_datum.equip_buckle_inhands(M, 2))) //MAKE SURE THIS IS LAST!!
M.visible_message("<span class='boldwarning'>[M] can't climb onto [src] because [M.p_their()] hands are full!</span>")
if(M.stat != CONSCIOUS)
return
if(iscarbon(M))
if(M.incapacitated(FALSE, TRUE) || incapacitated(FALSE, TRUE))
M.visible_message("<span class='boldwarning'>[M] can't hang onto [src]!</span>")
return
if(!riding_datum.equip_buckle_inhands(M, 2)) //MAKE SURE THIS IS LAST!!
M.visible_message("<span class='boldwarning'>[M] can't climb onto [src] because [M.p_their()] hands are full!</span>")
return
. = ..(M, force, check_loc)
stop_pulling()
@@ -160,8 +160,8 @@
return ..()
/mob/living/carbon/human/grabbedby(mob/living/carbon/user, supress_message = 0)
if(user == src && pulling && !pulling.anchored && grab_state >= GRAB_AGGRESSIVE && isliving(pulling))
vore_attack(user, pulling)
if(user == src && pulling && !pulling.anchored && grab_state >= GRAB_AGGRESSIVE && (disabilities & FAT) && ismonkey(pulling))
devour_mob(pulling)
else
..()
@@ -302,13 +302,14 @@
/mob/living/carbon/human/attack_animal(mob/living/simple_animal/M)
if(..())
. = ..()
if(.)
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
if(check_shields(damage, "the [M.name]", null, MELEE_ATTACK, M.armour_penetration))
return 0
return FALSE
var/dam_zone = dismembering_strike(M, pick("chest", "l_hand", "r_hand", "l_leg", "r_leg"))
if(!dam_zone) //Dismemberment successful
return 1
return TRUE
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
if(!affecting)
affecting = get_bodypart("chest")
@@ -1,7 +1,5 @@
var/global/default_martial_art = new/datum/martial_art
/mob/living/carbon/human
languages_spoken = HUMAN
languages_understood = HUMAN
initial_languages = list(/datum/language/common)
hud_possible = list(HEALTH_HUD,STATUS_HUD,ID_HUD,WANTED_HUD,IMPLOYAL_HUD,IMPCHEM_HUD,IMPTRACK_HUD,ANTAG_HUD)
possible_a_intents = list(INTENT_HELP, INTENT_DISARM, INTENT_GRAB, INTENT_HARM)
pressure_resistance = 25
@@ -43,6 +41,7 @@ var/global/default_martial_art = new/datum/martial_art
var/bleedsuppress = 0 //for stopping bloodloss, eventually this will be limb-based like bleeding
var/datum/martial_art/martial_art = null
var/static/default_martial_art = new/datum/martial_art
var/name_override //For temporary visible name changes
@@ -50,4 +49,4 @@ var/global/default_martial_art = new/datum/martial_art
var/datum/personal_crafting/handcrafting
can_buckle = TRUE
buckle_lying = FALSE
can_ride_typecache = list(/mob/living/carbon/human, /mob/living/simple_animal/slime)
can_ride_typecache = list(/mob/living/carbon/human, /mob/living/simple_animal/slime, /mob/living/simple_animal/parrot)
File diff suppressed because it is too large Load Diff
@@ -102,7 +102,7 @@
update_tint()
if(G.vision_correction)
clear_fullscreen("nearsighted")
if(G.vision_flags || G.darkness_view || G.invis_override || G.invis_view)
if(G.vision_flags || G.darkness_view || G.invis_override || G.invis_view || !isnull(G.lighting_alpha))
update_sight()
update_inv_glasses()
if(slot_gloves)
@@ -141,13 +141,13 @@
return not_handled //For future deeper overrides
/mob/living/carbon/human/doUnEquip(obj/item/I, force)
/mob/living/carbon/human/doUnEquip(obj/item/I, force, newloc, no_move, invdrop)
. = ..() //See mob.dm for an explanation on this and some rage about people copypasting instead of calling ..() like they should.
if(!. || !I)
return
if(I == wear_suit)
if(s_store)
if(s_store && invdrop)
dropItemToGround(s_store, TRUE) //It makes no sense for your suit storage to stay on you if you drop your suit.
if(wear_suit.breakouttime) //when unequipping a straightjacket
update_action_buttons_icon() //certain action buttons may be usable again.
@@ -156,17 +156,18 @@
update_inv_w_uniform()
update_inv_wear_suit()
else if(I == w_uniform)
if(r_store)
dropItemToGround(r_store, TRUE) //Again, makes sense for pockets to drop.
if(l_store)
dropItemToGround(l_store, TRUE)
if(wear_id)
dropItemToGround(wear_id)
if(belt)
dropItemToGround(belt)
if(invdrop)
if(r_store)
dropItemToGround(r_store, TRUE) //Again, makes sense for pockets to drop.
if(l_store)
dropItemToGround(l_store, TRUE)
if(wear_id)
dropItemToGround(wear_id)
if(belt)
dropItemToGround(belt)
w_uniform = null
update_suit_sensors()
update_inv_w_uniform()
update_inv_w_uniform(invdrop)
else if(I == gloves)
gloves = null
update_inv_gloves()
@@ -180,7 +181,7 @@
if(G.vision_correction)
if(disabilities & NEARSIGHT)
overlay_fullscreen("nearsighted", /obj/screen/fullscreen/impaired, 1)
if(G.vision_flags || G.darkness_view || G.invis_override || G.invis_view)
if(G.vision_flags || G.darkness_view || G.invis_override || G.invis_view || !isnull(G.lighting_alpha))
update_sight()
update_inv_glasses()
else if(I == ears)
+1 -8
View File
@@ -57,8 +57,6 @@
/mob/living/carbon/human/calculate_affecting_pressure(pressure)
if((wear_suit && (wear_suit.flags & STOPSPRESSUREDMAGE)) && (head && (head.flags & STOPSPRESSUREDMAGE)))
return ONE_ATMOSPHERE
if(ismob(loc))
return ONE_ATMOSPHERE //hopefully won't murderficate people in your guts by going for a spacewalk
else
return pressure
@@ -98,7 +96,7 @@
if(!dna.species.breathe(src))
..()
#define HUMAN_MAX_OXYLOSS 3
#define HUMAN_CRIT_MAX_OXYLOSS (SSmob.wait/30)
#define HUMAN_CRIT_MAX_OXYLOSS (SSmobs.wait/30)
/mob/living/carbon/human/check_breath(datum/gas_mixture/breath)
var/L = getorganslot("lungs")
@@ -141,8 +139,6 @@
/mob/living/carbon/human/proc/get_thermal_protection()
var/thermal_protection = 0 //Simple check to estimate how protected we are against multiple temperatures
if(ismob(loc))
thermal_protection = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT //because lazy and insulated by being inside someone
if(wear_suit)
if(wear_suit.max_heat_protection_temperature >= FIRE_SUIT_MAX_TEMP_PROTECT)
thermal_protection += (wear_suit.max_heat_protection_temperature*0.7)
@@ -252,9 +248,6 @@
if(dna.check_mutation(COLDRES))
return 1 //Fully protected from the cold.
if(ismob(loc))
return 1 //because lazy and being inside somemone insulates you from space
if(dna && (RESISTCOLD in dna.species.species_traits))
return 1
+7 -9
View File
@@ -1,12 +1,10 @@
/mob/living/carbon/human/say_quote(input, spans)
if(!input)
return "says, \"...\"" //not the best solution, but it will stop a large number of runtimes. The cause is somewhere in the Tcomms code
/mob/living/carbon/human/say_quote(input, spans, message_mode)
verb_say = dna.species.say_mod
. = ..()
if(src.slurring)
input = attach_spans(input, spans)
return "slurs, \"[input]\""
return ..()
/mob/living/carbon/human/treat_message(message)
message = dna.species.handle_speech(message,src)
@@ -75,7 +73,7 @@
if(!istype(dongle)) return 0
if(dongle.translate_binary) return 1
/mob/living/carbon/human/radio(message, message_mode, list/spans)
/mob/living/carbon/human/radio(message, message_mode, list/spans, language)
. = ..()
if(. != 0)
return .
@@ -83,17 +81,17 @@
switch(message_mode)
if(MODE_HEADSET)
if (ears)
ears.talk_into(src, message, , spans)
ears.talk_into(src, message, , spans, language)
return ITALICS | REDUCE_RANGE
if(MODE_DEPARTMENT)
if (ears)
ears.talk_into(src, message, message_mode, spans)
ears.talk_into(src, message, message_mode, spans, language)
return ITALICS | REDUCE_RANGE
if(message_mode in radiochannels)
if(message_mode in GLOB.radiochannels)
if(ears)
ears.talk_into(src, message, message_mode, spans)
ears.talk_into(src, message, message_mode, spans, language)
return ITALICS | REDUCE_RANGE
return 0
+58 -49
View File
@@ -17,6 +17,10 @@
var/default_color = "#FFF" // if alien colors are disabled, this is the color that will be used by that race
var/sexes = 1 // whether or not the race has sexual characteristics. at the moment this is only 0 for skeletons and shadows
var/face_y_offset = 0
var/hair_y_offset = 0
var/hair_color = null // this allows races to have specific hair colors... if null, it uses the H's hair/facial hair colors. if "mutcolor", it uses the H's mutant_color
var/hair_alpha = 255 // the alpha used by the hair. 255 is completely solid, 0 is transparent.
var/use_skintones = 0 // does it use skintones or not? (spoiler alert this is only used by humans)
@@ -69,8 +73,6 @@
var/fixed_mut_color3 = ""
var/whitelisted = 0 //Is this species restricted to certain players?
var/whitelist = list() //List the ckeys that can use this species, if it's whitelisted.: list("John Doe", "poopface666", "SeeALiggerPullTheTrigger") Spaces & capitalization can be included or ignored entirely for each key as it checks for both.
var/lang_spoken = HUMAN
var/lang_understood = HUMAN
///////////
// PROCS //
@@ -90,21 +92,21 @@
var/randname
if(gender == MALE)
randname = pick(first_names_male)
randname = pick(GLOB.first_names_male)
else
randname = pick(first_names_female)
randname = pick(GLOB.first_names_female)
if(lastname)
randname += " [lastname]"
else
randname += " [pick(last_names)]"
randname += " [pick(GLOB.last_names)]"
return randname
//Please override this locally if you want to define when what species qualifies for what rank if human authority is enforced.
/datum/species/proc/qualifies_for_rank(rank, list/features)
if(rank in command_positions)
if(rank in GLOB.command_positions)
return 0
return 1
@@ -205,7 +207,7 @@
facialhair_hidden = TRUE
if(H.facial_hair_style && (FACEHAIR in species_traits) && (!facialhair_hidden || dynamic_fhair_suffix))
S = facial_hair_styles_list[H.facial_hair_style]
S = GLOB.facial_hair_styles_list[H.facial_hair_style]
if(S)
//List of all valid dynamic_fhair_suffixes
@@ -262,7 +264,7 @@
standing += image("icon"='icons/mob/human_face.dmi', "icon_state" = "debrained", "layer" = -HAIR_LAYER)
else if(H.hair_style && (HAIR in species_traits))
S = hair_styles_list[H.hair_style]
S = GLOB.hair_styles_list[H.hair_style]
if(S)
//List of all valid dynamic_hair_suffixes
@@ -295,6 +297,7 @@
img_hair.color = forced_colour
img_hair.alpha = hair_alpha
img_hair.pixel_y += hair_y_offset
standing += img_hair
if(standing.len)
@@ -311,33 +314,36 @@
// eyes
var/has_eyes = (H.getorgan(/obj/item/organ/eyes) && HD)
var/has_eyes = TRUE
if(!has_eyes)
if(!H.getorgan(/obj/item/organ/eyes) && HD)
standing += image("icon"='icons/mob/human_face.dmi', "icon_state" = "eyes_missing", "layer" = -BODY_LAYER)
has_eyes = FALSE
if(!HUSK)
if(!(H.disabilities & HUSK))
// lipstick
if(H.lip_style && (LIPS in species_traits) && HD)
var/image/lips = image("icon"='icons/mob/human_face.dmi', "icon_state"="lips_[H.lip_style]", "layer" = -BODY_LAYER)
lips.color = H.lip_color
lips.pixel_y += face_y_offset
standing += lips
// eyes
if((EYECOLOR in species_traits) && HD && has_eyes)
var/image/img_eyes = image("icon" = 'icons/mob/human_face.dmi', "icon_state" = "eyes", "layer" = -BODY_LAYER)
img_eyes.color = "#" + H.eye_color
img_eyes.pixel_y += face_y_offset
standing += img_eyes
//Underwear, Undershirts & Socks
/*This will be refactored at a later date
if(H.underwear)
var/datum/sprite_accessory/underwear/underwear = underwear_list[H.underwear]
var/datum/sprite_accessory/underwear/underwear = GLOB.underwear_list[H.underwear]
if(underwear)
standing += image("icon"=underwear.icon, "icon_state"="[underwear.icon_state]", "layer"=-BODY_LAYER)
if(H.undershirt)
var/datum/sprite_accessory/undershirt/undershirt = undershirt_list[H.undershirt]
var/datum/sprite_accessory/undershirt/undershirt = GLOB.undershirt_list[H.undershirt]
if(undershirt)
if(H.dna.species.sexes && H.gender == FEMALE)
standing += wear_female_version("[undershirt.icon_state]", undershirt.icon, BODY_LAYER)
@@ -345,7 +351,7 @@
standing += image("icon"=undershirt.icon, "icon_state"="[undershirt.icon_state]", "layer"=-BODY_LAYER)
if(H.socks && H.get_num_legs() >= 2 && !(DIGITIGRADE in species_traits))
var/datum/sprite_accessory/socks/socks = socks_list[H.socks]
var/datum/sprite_accessory/socks/socks = GLOB.socks_list[H.socks]
if(socks)
standing += image("icon"=socks.icon, "icon_state"="[socks.icon_state]", "layer"=-BODY_LAYER)
*/
@@ -495,53 +501,53 @@
var/datum/sprite_accessory/S
switch(bodypart)
if("tail_lizard")
S = tails_list_lizard[H.dna.features["tail_lizard"]]
S = GLOB.tails_list_lizard[H.dna.features["tail_lizard"]]
if("waggingtail_lizard")
S.= animated_tails_list_lizard[H.dna.features["tail_lizard"]]
S.= GLOB.animated_tails_list_lizard[H.dna.features["tail_lizard"]]
if("tail_human")
S = tails_list_human[H.dna.features["tail_human"]]
S = GLOB.tails_list_human[H.dna.features["tail_human"]]
if("waggingtail_human")
S.= animated_tails_list_human[H.dna.features["tail_human"]]
S.= GLOB.animated_tails_list_human[H.dna.features["tail_human"]]
if("spines")
S = spines_list[H.dna.features["spines"]]
S = GLOB.spines_list[H.dna.features["spines"]]
if("waggingspines")
S.= animated_spines_list[H.dna.features["spines"]]
S.= GLOB.animated_spines_list[H.dna.features["spines"]]
if("snout")
S = snouts_list[H.dna.features["snout"]]
S = GLOB.snouts_list[H.dna.features["snout"]]
if("frills")
S = frills_list[H.dna.features["frills"]]
S = GLOB.frills_list[H.dna.features["frills"]]
if("horns")
S = horns_list[H.dna.features["horns"]]
S = GLOB.horns_list[H.dna.features["horns"]]
if("ears")
S = ears_list[H.dna.features["ears"]]
S = GLOB.ears_list[H.dna.features["ears"]]
if("body_markings")
S = body_markings_list[H.dna.features["body_markings"]]
S = GLOB.body_markings_list[H.dna.features["body_markings"]]
if("wings")
S = wings_list[H.dna.features["wings"]]
S = GLOB.wings_list[H.dna.features["wings"]]
if("wingsopen")
S = wings_open_list[H.dna.features["wings"]]
S = GLOB.wings_open_list[H.dna.features["wings"]]
if("legs")
S = legs_list[H.dna.features["legs"]]
S = GLOB.legs_list[H.dna.features["legs"]]
//Mammal Bodyparts (Canid/Felid, others maybe in the future)
if("mam_tail")
S = mam_tails_list[H.dna.features["mam_tail"]]
S = GLOB.mam_tails_list[H.dna.features["mam_tail"]]
if("mam_waggingtail")
S.= mam_tails_animated_list[H.dna.features["mam_tail"]]
S.= GLOB.mam_tails_animated_list[H.dna.features["mam_tail"]]
if("mam_body_markings")
S = mam_body_markings_list[H.dna.features["mam_body_markings"]]
S = GLOB.mam_body_markings_list[H.dna.features["mam_body_markings"]]
if("mam_ears")
S = mam_ears_list[H.dna.features["mam_ears"]]
S = GLOB.mam_ears_list[H.dna.features["mam_ears"]]
if("taur")
S = taur_list[H.dna.features["taur"]]
S = GLOB.taur_list[H.dna.features["taur"]]
//Xeno Bodyparts
if("xenodorsal")
S = xeno_dorsal_list[H.dna.features["xenodorsal"]]
S = GLOB.xeno_dorsal_list[H.dna.features["xenodorsal"]]
if("xenohead")
S = xeno_head_list[H.dna.features["xenohead"]]
S = GLOB.xeno_head_list[H.dna.features["xenohead"]]
if("xenotail")
S = xeno_tail_list[H.dna.features["xenotail"]]
S = GLOB.xeno_tail_list[H.dna.features["xenotail"]]
//Slimecoon Bodyparts
/* if("slimecoontail")
@@ -1035,6 +1041,8 @@
return 1
/datum/species/proc/go_bald(mob/living/carbon/human/H)
if(QDELETED(H)) //may be called from a timer
return
H.facial_hair_style = "Shaved"
H.hair_style = "Bald"
H.update_hair()
@@ -1198,9 +1206,9 @@
target.visible_message("<span class='danger'>[user] has weakened [target]!</span>", \
"<span class='userdanger'>[user] has weakened [target]!</span>")
target.apply_effect(4, WEAKEN, armor_block)
target.forcesay(hit_appends)
target.forcesay(GLOB.hit_appends)
else if(target.lying)
target.forcesay(hit_appends)
target.forcesay(GLOB.hit_appends)
@@ -1223,7 +1231,6 @@
return 1
else
user.do_attack_animation(target, ATTACK_EFFECT_DISARM)
add_logs(user, target, "disarmed")
if(target.w_uniform)
target.w_uniform.add_fingerprint(user)
@@ -1234,24 +1241,26 @@
target.visible_message("<span class='danger'>[user] has pushed [target]!</span>",
"<span class='userdanger'>[user] has pushed [target]!</span>", null, COMBAT_MESSAGE_RANGE)
target.apply_effect(2, WEAKEN, target.run_armor_check(affecting, "melee", "Your armor prevents your fall!", "Your armor softens your fall!"))
target.forcesay(hit_appends)
target.forcesay(GLOB.hit_appends)
add_logs(user, target, "disarmed", " pushing them to the ground")
return
var/talked = 0 // BubbleWrap
if(randn <= 60)
//BubbleWrap: Disarming breaks a pull
var/obj/item/I = null
if(target.pulling)
to_chat(target, "<span class='warning'>[user] has broken [target]'s grip on [target.pulling]!</span>")
talked = 1
target.stop_pulling()
//End BubbleWrap
if(!talked) //BubbleWrap
else
I = target.get_active_held_item()
if(target.drop_item())
target.visible_message("<span class='danger'>[user] has disarmed [target]!</span>", \
"<span class='userdanger'>[user] has disarmed [target]!</span>", null, COMBAT_MESSAGE_RANGE)
else
I = null
playsound(target, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
add_logs(user, target, "disarmed", "[I ? " removing \the [I]" : ""]")
return
@@ -1347,7 +1356,7 @@
H.adjust_blurriness(10)
if(prob(I.force + ((100 - H.health)/2)) && H != user)
ticker.mode.remove_revolutionary(H.mind)
SSticker.mode.remove_revolutionary(H.mind)
if(bloody) //Apply blood
if(H.wear_mask)
@@ -1376,7 +1385,7 @@
H.update_inv_w_uniform()
if(Iforce > 10 || Iforce >= 5 && prob(33))
H.forcesay(hit_appends) //forcesay checks stat already.
H.forcesay(GLOB.hit_appends) //forcesay checks stat already.
return TRUE
/datum/species/proc/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H)
@@ -1480,7 +1489,7 @@
H.apply_damage(HEAT_DAMAGE_LEVEL_3*heatmod, BURN)
else
H.apply_damage(HEAT_DAMAGE_LEVEL_2*heatmod, BURN)
else if(H.bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT && !(mutations_list[COLDRES] in H.dna.mutations))
else if(H.bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT && !(GLOB.mutations_list[COLDRES] in H.dna.mutations))
switch(H.bodytemperature)
if(200 to 260)
H.throw_alert("temp", /obj/screen/alert/cold, 1)
@@ -14,6 +14,8 @@ datum/species/mammal
if(H)
H.endTailWag()
/datum/species/mammal/qualifies_for_rank(rank, list/features)
return TRUE
//AVIAN//
/datum/species/avian
@@ -32,6 +34,9 @@ datum/species/mammal
if(H)
H.endTailWag()
/datum/species/avian/qualifies_for_rank(rank, list/features)
return TRUE
//AQUATIC//
/datum/species/aquatic
name = "Aquatic"
@@ -48,6 +53,10 @@ datum/species/mammal
/datum/species/aquatic/spec_death(gibbed, mob/living/carbon/human/H)
if(H)
H.endTailWag()
/datum/species/aquatic/qualifies_for_rank(rank, list/features)
return TRUE
//INSECT//
/datum/species/insect
name = "Insect"
@@ -65,6 +74,8 @@ datum/species/mammal
if(H)
H.endTailWag()
/datum/species/insect/qualifies_for_rank(rank, list/features)
return TRUE
//HERBIVOROUS//
//EXOTIC//
@@ -1,7 +1,7 @@
/datum/species/golem
// Animated beings of stone. They have increased defenses, and do not need to breathe. They're also slow as fuuuck.
name = "Golem"
id = "iron"
id = "iron golem"
species_traits = list(NOBREATH,RESISTHOT,RESISTCOLD,RESISTPRESSURE,NOFIRE,NOGUNS,NOBLOOD,RADIMMUNE,VIRUSIMMUNE,PIERCEIMMUNE,NODISMEMBER,MUTCOLORS)
speedmod = 2
armor = 55
@@ -12,6 +12,7 @@
no_equip = list(slot_wear_mask, slot_wear_suit, slot_gloves, slot_shoes, slot_w_uniform)
nojumpsuit = 1
sexes = 1
damage_overlay_type = ""
meat = /obj/item/weapon/reagent_containers/food/snacks/meat/slab/human/mutant/golem
// To prevent golem subtypes from overwhelming the odds when random species
// changes, only the Random Golem type can be chosen
@@ -21,6 +22,21 @@
fixed_mut_color = "aaa"
var/info_text = "As an <span class='danger'>Iron Golem</span>, you don't have any special traits."
var/prefix = "Iron"
var/list/special_names
/datum/species/golem/random_name(gender,unique,lastname)
var/golem_surname = pick(GLOB.golem_names)
// 3% chance that our golem has a human surname, because
// cultural contamination
if(prob(3))
golem_surname = pick(GLOB.last_names)
else if(special_names && prob(5))
golem_surname = pick(special_names)
var/golem_name = "[prefix] [golem_surname]"
return golem_name
/datum/species/golem/random
name = "Random Golem"
blacklisted = FALSE
@@ -36,21 +52,24 @@
/datum/species/golem/adamantine
name = "Adamantine Golem"
id = "adamantine"
id = "adamantine golem"
meat = /obj/item/weapon/reagent_containers/food/snacks/meat/slab/human/mutant/golem/adamantine
fixed_mut_color = "4ed"
info_text = "As an <span class='danger'>Adamantine Golem</span>, you don't have any special traits."
prefix = "Adamantine"
//Explodes on death
/datum/species/golem/plasma
name = "Plasma Golem"
id = "plasma"
id = "plasma golem"
fixed_mut_color = "a3d"
meat = /obj/item/weapon/ore/plasma
//Can burn and takes damage from heat
species_traits = list(NOBREATH,RESISTCOLD,RESISTPRESSURE,NOGUNS,NOBLOOD,RADIMMUNE,VIRUSIMMUNE,PIERCEIMMUNE,NODISMEMBER,MUTCOLORS)
info_text = "As a <span class='danger'>Plasma Golem</span>, you explode on death!"
burnmod = 1.5
prefix = "Plasma"
special_names = list("Flood","Fire","Bar","Man")
/datum/species/golem/plasma/spec_death(gibbed, mob/living/carbon/human/H)
explosion(get_turf(H),0,1,2,flame_range = 5)
@@ -60,35 +79,40 @@
//Harder to hurt
/datum/species/golem/diamond
name = "Diamond Golem"
id = "diamond"
id = "diamond golem"
fixed_mut_color = "0ff"
armor = 70 //up from 55
meat = /obj/item/weapon/ore/diamond
info_text = "As a <span class='danger'>Diamond Golem</span>, you are more resistant than the average golem."
prefix = "Diamond"
special_names = list("Back")
//Faster but softer and less armoured
/datum/species/golem/gold
name = "Gold Golem"
id = "gold"
id = "gold golem"
fixed_mut_color = "cc0"
speedmod = 1
armor = 25 //down from 55
meat = /obj/item/weapon/ore/gold
info_text = "As a <span class='danger'>Gold Golem</span>, you are faster but less resistant than the average golem."
prefix = "Golden"
//Heavier, thus higher chance of stunning when punching
/datum/species/golem/silver
name = "Silver Golem"
id = "silver"
id = "silver golem"
fixed_mut_color = "ddd"
punchstunthreshold = 9 //60% chance, from 40%
meat = /obj/item/weapon/ore/silver
info_text = "As a <span class='danger'>Silver Golem</span>, your attacks are heavier and have a higher chance of stunning."
prefix = "Silver"
special_names = list("Surfer", "Chariot", "Lining")
//Harder to stun, deals more damage, but it's even slower
/datum/species/golem/plasteel
name = "Plasteel Golem"
id = "plasteel"
id = "plasteel golem"
fixed_mut_color = "bbb"
stunmod = 0.40
punchdamagelow = 12
@@ -99,15 +123,17 @@
info_text = "As a <span class='danger'>Plasteel Golem</span>, you are slower, but harder to stun, and hit very hard when punching."
attack_verb = "smash"
attack_sound = 'sound/effects/meteorimpact.ogg' //hits pretty hard
prefix = "Plasteel"
//Immune to ash storms
/datum/species/golem/titanium
name = "Titanium Golem"
id = "titanium"
id = "titanium golem"
fixed_mut_color = "fff"
meat = /obj/item/weapon/ore/titanium
info_text = "As a <span class='danger'>Titanium Golem</span>, you are immune to ash storms, and slightly more resistant to burn damage."
burnmod = 0.9
prefix = "Titanium"
/datum/species/golem/titanium/on_species_gain(mob/living/carbon/C, datum/species/old_species)
. = ..()
@@ -120,11 +146,12 @@
//Immune to ash storms and lava
/datum/species/golem/plastitanium
name = "Plastitanium Golem"
id = "plastitanium"
id = "plastitanium golem"
fixed_mut_color = "888"
meat = /obj/item/weapon/ore/titanium
info_text = "As a <span class='danger'>Plastitanium Golem</span>, you are immune to both ash storms and lava, and slightly more resistant to burn damage."
burnmod = 0.8
prefix = "Plastitanium"
/datum/species/golem/plastitanium/on_species_gain(mob/living/carbon/C, datum/species/old_species)
. = ..()
@@ -139,12 +166,14 @@
//Fast and regenerates... but can only speak like an abductor
/datum/species/golem/alloy
name = "Alien Alloy Golem"
id = "alloy"
id = "alloy golem"
fixed_mut_color = "333"
meat = /obj/item/stack/sheet/mineral/abductor
mutant_organs = list(/obj/item/organ/tongue/abductor) //abductor tongue
speedmod = 1 //faster
info_text = "As an <span class='danger'>Alloy Golem</span>, you are made of advanced alien materials: you are faster and regenerate over time. You are, however, only able to be heard by other alloy golems."
prefix = "Alien"
special_names = list("Outsider", "Technology", "Watcher", "Stranger") //ominous and unknown
//Regenerates because self-repairing super-advanced alien tech
/datum/species/golem/alloy/spec_life(mob/living/carbon/human/H)
@@ -157,7 +186,7 @@
//Since this will usually be created from a collaboration between podpeople and free golems, wood golems are a mix between the two races
/datum/species/golem/wood
name = "Wood Golem"
id = "wood"
id = "wood golem"
fixed_mut_color = "49311c"
meat = /obj/item/stack/sheet/mineral/wood
//Can burn and take damage from heat
@@ -166,6 +195,13 @@
burnmod = 1.25
heatmod = 1.5
info_text = "As a <span class='danger'>Wooden Golem</span>, you have plant-like traits: you take damage from extreme temperatures, can be set on fire, and have lower armor than a normal golem. You regenerate when in the light and wither in the darkness."
prefix = "Wooden"
/datum/species/golem/wood/random_name(gender,unique,lastname)
var/plant_name = pick("Tomato", "Potato", "Broccoli", "Carrot", "Ambrosia", "Pumpkin", "Ivy", "Kudzu", "Banana", "Moss", "Flower", "Bloom", "Root", "Bark", "Glowshroom", "Petal", "Leaf", \
"Venus", "Sprout","Cocoa", "Strawberry", "Citrus", "Oak", "Cactus", "Pepper", "Juniper")
var/golem_name = "[prefix] [plant_name]"
return golem_name
/datum/species/golem/wood/on_species_gain(mob/living/carbon/C, datum/species/old_species)
. = ..()
@@ -204,13 +240,14 @@
//Radioactive
/datum/species/golem/uranium
name = "Uranium Golem"
id = "uranium"
id = "uranium golem"
fixed_mut_color = "7f0"
meat = /obj/item/weapon/ore/uranium
info_text = "As an <span class='danger'>Uranium Golem</span>, you emit radiation pulses every once in a while. It won't harm fellow golems, but organic lifeforms will be affected."
var/last_event = 0
var/active = null
prefix = "Uranium"
/datum/species/golem/uranium/spec_life(mob/living/carbon/human/H)
if(!active)
@@ -224,7 +261,7 @@
//Immune to physical bullets and resistant to brute, but very vulnerable to burn damage. Dusts on death.
/datum/species/golem/sand
name = "Sand Golem"
id = "sand"
id = "sand golem"
fixed_mut_color = "ffdc8f"
meat = /obj/item/weapon/ore/glass //this is sand
armor = 0
@@ -232,6 +269,7 @@
brutemod = 0.25
info_text = "As a <span class='danger'>Sand Golem</span>, you are immune to physical bullets and take very little brute damage, but are extremely vulnerable to burn damage. You will also turn to sand when dying, preventing any form of recovery."
attack_sound = 'sound/effects/shovel_dig.ogg'
prefix = "Sand"
/datum/species/golem/sand/spec_death(gibbed, mob/living/carbon/human/H)
H.visible_message("<span class='danger'>[H] turns into a pile of sand!</span>")
@@ -253,7 +291,7 @@
//Reflects lasers and resistant to burn damage, but very vulnerable to brute damage. Shatters on death.
/datum/species/golem/glass
name = "Glass Golem"
id = "glass"
id = "glass golem"
fixed_mut_color = "5a96b4aa" //transparent body
meat = /obj/item/weapon/shard
armor = 0
@@ -261,6 +299,7 @@
burnmod = 0.25
info_text = "As a <span class='danger'>Glass Golem</span>, you reflect lasers and energy weapons, and are very resistant to burn damage, but you are extremely vulnerable to brute damage. On death, you'll shatter beyond any hope of recovery."
attack_sound = 'sound/effects/Glassbr2.ogg'
prefix = "Glass"
/datum/species/golem/glass/spec_death(gibbed, mob/living/carbon/human/H)
playsound(H, "shatter", 70, 1)
@@ -295,12 +334,14 @@
//Teleports when hit or when it wants to
/datum/species/golem/bluespace
name = "Bluespace Golem"
id = "bluespace"
id = "bluespace golem"
fixed_mut_color = "33f"
meat = /obj/item/weapon/ore/bluespace_crystal
info_text = "As a <span class='danger'>Bluespace Golem</span>, are spatially unstable: you will teleport when hit, and you can teleport manually at a long distance."
attack_verb = "bluespace punch"
attack_sound = 'sound/effects/phasein.ogg'
prefix = "Bluespace"
special_names = list("Crystal", "Polycrystal")
var/datum/action/innate/unstable_teleport/unstable_teleport
var/teleport_cooldown = 100
@@ -384,7 +425,7 @@
//honk
/datum/species/golem/bananium
name = "Bananium Golem"
id = "bananium"
id = "bananium golem"
fixed_mut_color = "ff0"
say_mod = "honks"
punchdamagelow = 0
@@ -394,6 +435,7 @@
info_text = "As a <span class='danger'>Bananium Golem</span>, you are made for pranking. Your body emits natural honks, and you cannot hurt people when punching them. Your skin also emits bananas when damaged."
attack_verb = "honk"
attack_sound = 'sound/items/AirHorn2.ogg'
prefix = "Bananium"
var/last_honk = 0
var/honkooldown = 0
@@ -401,6 +443,11 @@
var/banana_cooldown = 100
var/active = null
/datum/species/golem/bananium/random_name(gender,unique,lastname)
var/clown_name = pick(GLOB.clown_names)
var/golem_name = "[uppertext(clown_name)]"
return golem_name
/datum/species/golem/bananium/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style = M.martial_art)
..()
if(world.time > last_banana + banana_cooldown && M != H && M.a_intent != INTENT_HELP)
@@ -449,7 +496,7 @@
/datum/species/golem/runic
name = "Runic Golem"
id = "runic"
id = "runic golem"
limbs_id = "cultgolem"
sexes = FALSE
info_text = "As a <span class='danger'>Runic Golem</span>, you possess eldritch powers granted by the Elder God Nar'Sie."
@@ -459,6 +506,12 @@
var/obj/effect/proc_holder/spell/targeted/abyssal_gaze/abyssal_gaze
var/obj/effect/proc_holder/spell/targeted/dominate/dominate
/datum/species/golem/runic/random_name(gender,unique,lastname)
var/edgy_first_name = pick("Razor","Blood","Dark","Evil","Cold","Pale","Black","Silent","Chaos","Deadly")
var/edgy_last_name = pick("Edge","Night","Death","Razor","Blade","Steel","Calamity","Twilight","Shadow","Nightmare") //dammit Razor Razor
var/golem_name = "[edgy_first_name] [edgy_last_name]"
return golem_name
/datum/species/golem/runic/on_species_gain(mob/living/carbon/C, datum/species/old_species)
. = ..()
C.faction |= "cult"
@@ -489,3 +542,100 @@
H.adjustFireLoss(-4)
H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM)
/datum/species/golem/cloth
name = "Cloth Golem"
id = "cloth golem"
limbs_id = "clothgolem"
sexes = FALSE
info_text = "As a <span class='danger'>Cloth Golem</span>, you are able to reform yourself after death, provided your remains aren't burned or destroyed. You are, of course, very flammable."
species_traits = list(NOBREATH,RESISTCOLD,RESISTPRESSURE,NOGUNS,NOBLOOD,RADIMMUNE,VIRUSIMMUNE,PIERCEIMMUNE,NODISMEMBER) //no mutcolors, and can burn
armor = 15 //feels no pain, but not too resistant
burnmod = 2 // don't get burned
speedmod = 1 // not as heavy as stone
punchdamagelow = 4
punchstunthreshold = 7
punchdamagehigh = 8 // not as heavy as stone
prefix = "Cloth"
/datum/species/golem/cloth/random_name(gender,unique,lastname)
var/pharaoh_name = pick("Neferkare", "Hudjefa", "Khufu", "Mentuhotep", "Ahmose", "Amenhotep", "Thutmose", "Hatshepsut", "Tutankhamun", "Ramses", "Seti", \
"Merenptah", "Djer", "Semerkhet", "Nynetjer", "Khafre", "Pepi", "Intef", "Ay") //yes, Ay was an actual pharaoh
var/golem_name = "[pharaoh_name] \Roman[rand(1,99)]"
return golem_name
/datum/species/golem/cloth/spec_life(mob/living/carbon/human/H)
if(H.fire_stacks < 1)
H.adjust_fire_stacks(1) //always prone to burning
..()
/datum/species/golem/cloth/spec_death(gibbed, mob/living/carbon/human/H)
if(gibbed)
return
if(H.on_fire)
H.visible_message("<span class='danger'>[H] burns into ash!</span>")
H.dust(just_ash = TRUE)
return
H.visible_message("<span class='danger'>[H] falls apart into a pile of bandages!</span>")
new /obj/structure/cloth_pile(get_turf(H), H)
..()
/obj/structure/cloth_pile
name = "pile of bandages"
desc = "It emits a strange aura, as if there was still life within it..."
obj_integrity = 50
max_integrity = 50
armor = list(melee = 90, bullet = 90, laser = 25, energy = 80, bomb = 50, bio = 100, fire = -50, acid = -50)
icon = 'icons/obj/items.dmi'
icon_state = "pile_bandages"
resistance_flags = FLAMMABLE
var/revive_time = 900
var/mob/living/carbon/human/cloth_golem
/obj/structure/cloth_pile/Initialize(mapload, mob/living/carbon/human/H)
if(!QDELETED(H) && is_species(H, /datum/species/golem/cloth))
H.unequip_everything()
H.forceMove(src)
cloth_golem = H
to_chat(cloth_golem, "<span class='notice'>You start gathering your life energy, preparing to rise again...</span>")
addtimer(CALLBACK(src, .proc/revive), revive_time)
else
qdel(src)
/obj/structure/cloth_pile/Destroy()
if(cloth_golem)
QDEL_NULL(cloth_golem)
return ..()
/obj/structure/cloth_pile/burn()
visible_message("<span class='danger'>[src] burns into ash!</span>")
new /obj/effect/decal/cleanable/ash(get_turf(src))
..()
/obj/structure/cloth_pile/proc/revive()
if(QDELETED(src) || QDELETED(cloth_golem)) //QDELETED also checks for null, so if no cloth golem is set this won't runtime
return
if(cloth_golem.suiciding || cloth_golem.disabilities & NOCLONE)
QDEL_NULL(cloth_golem)
return
invisibility = INVISIBILITY_MAXIMUM //disappear before the animation
new /obj/effect/overlay/temp/mummy_animation(get_turf(src))
if(cloth_golem.revive(full_heal = TRUE, admin_revive = TRUE))
cloth_golem.grab_ghost() //won't pull if it's a suicide
sleep(20)
cloth_golem.forceMove(get_turf(src))
cloth_golem.visible_message("<span class='danger'>[src] rises and reforms into [cloth_golem]!</span>","<span class='userdanger'>You reform into yourself!</span>")
cloth_golem = null
qdel(src)
/obj/structure/cloth_pile/attackby(obj/item/weapon/P, mob/living/carbon/human/user, params)
. = ..()
if(resistance_flags & ON_FIRE)
return
if(P.is_hot())
visible_message("<span class='danger'>[src] bursts into flames!</span>")
fire_act()
@@ -10,9 +10,7 @@
/datum/species/human/qualifies_for_rank(rank, list/features)
if((!features["tail_human"] || features["tail_human"] == "None") && (!features["ears"] || features["ears"] == "None"))
return TRUE //Pure humans are always allowed in all roles.
return ..()
return TRUE
//Curiosity killed the cat's wagging tail.
/datum/species/human/spec_death(gibbed, mob/living/carbon/human/H)
@@ -7,6 +7,7 @@
species_traits = list(MUTCOLORS,EYECOLOR,NOBLOOD,VIRUSIMMUNE,TOXINLOVER)
meat = /obj/item/weapon/reagent_containers/food/snacks/meat/slab/human/mutant/slime
exotic_blood = "slimejelly"
damage_overlay_type = ""
var/datum/action/innate/regenerate_limbs/regenerate_limbs
/datum/species/jelly/on_species_loss(mob/living/carbon/C)
@@ -226,7 +227,7 @@
else
ui_interact(owner)
/datum/action/innate/swap_body/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = conscious_state)
/datum/action/innate/swap_body/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.conscious_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
@@ -7,6 +7,8 @@
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR,FACEHAIR)
mutant_bodyparts = list("tail_lizard", "snout", "spines", "horns", "frills", "body_markings", "legs", "taur")
mutant_organs = list(/obj/item/organ/tongue/lizard)
coldmod = 1.5
heatmod = 0.67
default_features = list("mcolor" = "0F0","mcolor2" = "0F0","mcolor3" = "0F0", "tail" = "Smooth", "snout" = "Round", "horns" = "None", "frills" = "None", "spines" = "None", "body_markings" = "None", "legs" = "Normal Legs", "taur" = "None")
attack_verb = "slash"
attack_sound = 'sound/weapons/slash.ogg'
@@ -26,6 +28,9 @@
return randname
/datum/species/lizard/qualifies_for_rank(rank, list/features)
return TRUE
//I wag in death
/datum/species/lizard/spec_death(gibbed, mob/living/carbon/human/H)
if(H)
@@ -38,4 +43,4 @@
name = "Ash Walker"
id = "ashlizard"
limbs_id = "lizard"
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,NOBREATH,NOGUNS,DIGITIGRADE)
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,NOBREATH,NOGUNS,DIGITIGRADE)
@@ -1,5 +1,3 @@
var/global/image/plasmaman_on_fire = image("icon"='icons/mob/OnFire.dmi', "icon_state"="plasmaman")
/datum/species/plasmaman
name = "Plasmaman"
id = "plasmaman"
@@ -52,7 +50,7 @@ var/global/image/plasmaman_on_fire = image("icon"='icons/mob/OnFire.dmi', "icon_
return 0
/datum/species/plasmaman/qualifies_for_rank(rank, list/features)
if(rank in security_positions)
if(rank in GLOB.security_positions)
return 0
if(rank == "Clown" || rank == "Mime")//No funny bussiness
return 0
@@ -99,7 +99,7 @@ There are several things that need to be remembered:
/* --------------------------------------- */
//vvvvvv UPDATE_INV PROCS vvvvvv
/mob/living/carbon/human/update_inv_w_uniform()
/mob/living/carbon/human/update_inv_w_uniform(invdrop = TRUE)
remove_overlay(UNIFORM_LAYER)
if(client && hud_used)
@@ -138,7 +138,7 @@ There are several things that need to be remembered:
overlays_standing[UNIFORM_LAYER] = standing
else if(!(dna && dna.species.nojumpsuit))
else if(!(dna && dna.species.nojumpsuit) && invdrop)
// Automatically drop anything in store / id / belt if you're not wearing a uniform. //CHECK IF NECESARRY
for(var/obj/item/thing in list(r_store, l_store, wear_id, belt)) //
dropItemToGround(thing)
@@ -274,7 +274,7 @@ There are several things that need to be remembered:
client.screen += shoes //add it to client's screen
update_observer_view(shoes,1)
var/image/standing = shoes.build_worn_icon(state = shoes.icon_state, default_layer = SHOES_LAYER, default_icon_file = 'icons/mob/feet.dmi')
overlays_standing[SHOES_LAYER] = standing
overlays_standing[SHOES_LAYER] = standing
apply_overlay(SHOES_LAYER)
@@ -392,10 +392,10 @@ There are several things that need to be remembered:
/proc/wear_female_version(t_color, icon, layer, type)
var/index = t_color
var/icon/female_clothing_icon = female_clothing_icons[index]
var/icon/female_clothing_icon = GLOB.female_clothing_icons[index]
if(!female_clothing_icon) //Create standing/laying icons if they don't exist
generate_female_clothing(index,t_color,icon,type)
var/standing = image("icon"=female_clothing_icons["[t_color]"], "layer"=-layer)
var/standing = image("icon"=GLOB.female_clothing_icons["[t_color]"], "layer"=-layer)
return(standing)
/mob/living/carbon/human/proc/get_overlays_copy(list/unwantedLayers)
@@ -1,10 +1,15 @@
/mob/living/carbon/human/whisper(message as text)
/mob/living/carbon/human/whisper_verb(message as text)
whisper(message)
/mob/living/carbon/human/whisper(message, datum/language/language=null)
if(!IsVocal())
return
if(!message)
return
if(!language)
language = get_default_language()
if(say_disabled) //This is here to try to identify lag problems
if(GLOB.say_disabled) //This is here to try to identify lag problems
to_chat(usr, "<span class='danger'>Speech is currently admin-disabled.</span>")
return
@@ -44,9 +49,11 @@
message = Ellipsis(message, 10, 1)
message = treat_message(message)
if(!message)
return
var/list/listening_dead = list()
for(var/mob/M in player_list)
for(var/mob/M in GLOB.player_list)
if(M.stat == DEAD && M.client && ((M.client.prefs.chat_toggles & CHAT_GHOSTWHISPER) || (get_dist(M, src) <= 7)))
listening_dead |= M
@@ -71,14 +78,14 @@
for(var/atom/movable/AM in listening)
if(istype(AM,/obj/item/device/radio))
continue
AM.Hear(rendered, src, languages_spoken, message, , spans)
AM.Hear(rendered, src, language, message, , spans)
message = stars(message)
rendered = "<span class='game say'><span class='name'>[GetVoice()]</span>[alt_name] [whispers], <span class='message'>\"[attach_spans(message, spans)]\"</span></span>"
for(var/atom/movable/AM in eavesdropping)
if(istype(AM,/obj/item/device/radio))
continue
AM.Hear(rendered, src, languages_spoken, message, , spans)
AM.Hear(rendered, src, language, message, , spans)
if(critical) //Dying words.
succumb(1)
+4 -6
View File
@@ -29,7 +29,7 @@
//Start of a breath chain, calls breathe()
/mob/living/carbon/handle_breathing()
if(SSmob.times_fired%4==2 || failed_last_breath)
if(SSmobs.times_fired%4==2 || failed_last_breath)
breathe() //Breathe per 4 ticks, unless suffocating
else
if(istype(loc, /obj/))
@@ -47,8 +47,6 @@
if(loc)
environment = loc.return_air()
if(ismob(loc)) return
var/datum/gas_mixture/breath
if(health <= HEALTH_THRESHOLD_CRIT || (pulledby && pulledby.grab_state >= GRAB_KILL && !getorganslot("breathing_tube")))
@@ -132,7 +130,7 @@
if(prob(20))
emote("gasp")
if(O2_partialpressure > 0)
var/ratio = safe_oxy_min/O2_partialpressure
var/ratio = 1 - O2_partialpressure/safe_oxy_min
adjustOxyLoss(min(5*ratio, 3))
failed_last_breath = 1
oxygen_used = breath_gases["o2"][MOLES]*ratio
@@ -255,7 +253,7 @@
dna.previous.Remove("blood_type")
dna.temporary_mutations.Remove(mut)
continue
HM = mutations_list[mut]
HM = GLOB.mutations_list[mut]
HM.force_lose(src)
dna.temporary_mutations.Remove(mut)
@@ -294,7 +292,7 @@
stomach_contents.Remove(M)
qdel(M)
continue
if(SSmob.times_fired%3==1)
if(SSmobs.times_fired%3==1)
if(!(M.status_flags & GODMODE))
M.adjustBruteLoss(5)
nutrition += 10
@@ -16,6 +16,8 @@
var/pickpocketing = FALSE
var/disposing_body = FALSE
var/obj/machinery/disposal/bodyDisposal = null
var/next_battle_screech = 0
var/battle_screech_cooldown = 50
/mob/living/carbon/monkey/proc/IsStandingStill()
return resisting || pickpocketing || disposing_body
@@ -59,6 +61,12 @@
return 1
return 0
/mob/living/carbon/monkey/proc/battle_screech()
if(next_battle_screech < world.time)
emote(pick("roar","screech"))
for(var/mob/living/carbon/monkey/M in view(7,src))
M.next_battle_screech = world.time + battle_screech_cooldown
/mob/living/carbon/monkey/proc/equip_item(var/obj/item/I)
if(I.loc == src)
@@ -197,7 +205,7 @@
for(var/mob/living/L in around)
if( should_target(L) )
if(L.stat == CONSCIOUS)
emote(pick("roar","screech"))
battle_screech()
retaliate(L)
return TRUE
else if(bodyDisposal)
@@ -241,7 +249,7 @@
var/list/around = view(src, MONKEY_ENEMY_VISION)
for(var/mob/living/carbon/monkey/M in around)
if(M.mode == MONKEY_IDLE && prob(MONKEY_RECRUIT_PROB))
M.emote(pick("roar","screech"))
M.battle_screech()
M.target = target
M.mode = MONKEY_HUNT
@@ -406,7 +414,7 @@
enemies[L] += MONKEY_HATRED_AMOUNT
if(a_intent != INTENT_HARM)
emote(pick("roar","screech"))
battle_screech()
a_intent = INTENT_HARM
/mob/living/carbon/monkey/attack_hand(mob/living/L)
@@ -16,7 +16,7 @@
if(stat == CONSCIOUS)
if(!handle_combat())
if(prob(33) && canmove && isturf(loc) && !pulledby)
step(src, pick(cardinal))
step(src, pick(GLOB.cardinal))
if(prob(1))
emote(pick("scratch","jump","roll","tail"))
else
@@ -2,18 +2,16 @@
name = "monkey"
voice_name = "monkey"
verb_say = "chimpers"
initial_languages = list(/datum/language/monkey)
icon = 'icons/mob/monkey.dmi'
icon_state = ""
gender = NEUTER
pass_flags = PASSTABLE
languages_spoken = MONKEY
languages_understood = MONKEY
ventcrawler = VENTCRAWLER_NUDE
butcher_results = list(/obj/item/weapon/reagent_containers/food/snacks/meat/slab/monkey = 5, /obj/item/stack/sheet/animalhide/monkey = 1)
type_of_meat = /obj/item/weapon/reagent_containers/food/snacks/meat/slab/monkey
gib_type = /obj/effect/decal/cleanable/blood/gibs
unique_name = 1
devourable = 1
bodyparts = list(/obj/item/bodypart/chest/monkey, /obj/item/bodypart/head/monkey, /obj/item/bodypart/l_arm/monkey,
/obj/item/bodypart/r_arm/monkey, /obj/item/bodypart/r_leg/monkey, /obj/item/bodypart/l_leg/monkey)
@@ -160,4 +158,4 @@
if(prob(10))
var/obj/item/clothing/head/helmet/justice/escape/helmet = new(src)
equip_to_slot_or_del(helmet,slot_head)
helmet.attack_self(src) // todo encapsulate toggle
helmet.attack_self(src) // todo encapsulate toggle
@@ -117,26 +117,33 @@
playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1)
visible_message("<span class='danger'>[M] has attempted to lunge at [name]!</span>", \
"<span class='userdanger'>[M] has attempted to lunge at [name]!</span>", null, COMBAT_MESSAGE_RANGE)
if (M.a_intent == INTENT_DISARM)
var/obj/item/I = null
playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
if(prob(95))
Weaken(10)
visible_message("<span class='danger'>[M] has tackled down [name]!</span>", \
"<span class='userdanger'>[M] has tackled down [name]!</span>", null, COMBAT_MESSAGE_RANGE)
else
I = get_active_held_item()
if(drop_item())
visible_message("<span class='danger'>[M] has disarmed [name]!</span>", \
"<span class='userdanger'>[M] has disarmed [name]!</span>", null, COMBAT_MESSAGE_RANGE)
add_logs(M, src, "disarmed")
else
I = null//did not manage to actually disarm the item, gross but no time to refactor
add_logs(M, src, "disarmed", "[I ? " removing \the [I]" : ""]")
updatehealth()
/mob/living/carbon/monkey/attack_animal(mob/living/simple_animal/M)
if(..())
. = ..()
if(.)
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
var/dam_zone = dismembering_strike(M, pick("chest", "l_hand", "r_hand", "l_leg", "r_leg"))
if(!dam_zone) //Dismemberment successful
return 1
return TRUE
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
if(!affecting)
affecting = get_bodypart("chest")
@@ -32,7 +32,7 @@
equip_to_slot_or_del(new relic_mask, slot_wear_mask)
/mob/living/carbon/monkey/punpun/Life()
if(ticker.current_state == GAME_STATE_FINISHED && !memory_saved)
if(SSticker.current_state == GAME_STATE_FINISHED && !memory_saved)
Write_Memory(0)
..()
@@ -68,7 +68,7 @@
//update whether our neck item appears on our hud.
/mob/living/carbon/monkey/update_hud_neck(obj/item/I)
if(client && hud_used && hud_used.hud_shown)
I.screen_loc = ui_monkey_mask
I.screen_loc = ui_monkey_neck
client.screen += I
//update whether our back item appears on our hud.
+12
View File
@@ -28,3 +28,15 @@
var/obj/item/I = get_active_held_item()
if(I)
. |= I.get_held_item_speechspans(src)
/mob/living/carbon/can_speak_in_language(datum/language/dt)
if(HAS_SECONDARY_FLAG(src, OMNITONGUE))
. = has_language(dt)
else if(has_language(dt))
var/obj/item/organ/tongue/T = getorganslot("tongue")
if(T)
. = T.can_speak_in_language(dt)
else
. = initial(dt.flags) & TONGUELESS_SPEECH
else
. = FALSE
@@ -276,12 +276,6 @@
See RemieRichards on irc.rizon.net #coderbus
*/
var/global/list/limb_icon_cache = list()
/mob/living/carbon
var/icon_render_key = ""
//produces a key based on the mob's limbs
/mob/living/carbon/proc/generate_icon_render_key()
+5 -5
View File
@@ -26,20 +26,20 @@
/mob/living/proc/spread_bodyparts()
return
/mob/living/dust()
/mob/living/dust(just_ash = FALSE)
death(1)
if(buckled)
buckled.unbuckle_mob(src,force=1)
dust_animation()
spawn_dust()
spawn_dust(just_ash)
qdel(src)
/mob/living/proc/dust_animation()
return
/mob/living/proc/spawn_dust()
/mob/living/proc/spawn_dust(just_ash = FALSE)
new /obj/effect/decal/cleanable/ash(loc)
@@ -55,9 +55,9 @@
deadchat_broadcast(rendered, follow_target = src, turf_target = T, message_type=DEADCHAT_DEATHRATTLE)
if(mind)
mind.store_memory("Time of death: [tod]", 0)
living_mob_list -= src
GLOB.living_mob_list -= src
if(!gibbed)
dead_mob_list += src
GLOB.dead_mob_list += src
paralysis = 0
stunned = 0
weakened = 0
+5 -2
View File
@@ -7,7 +7,8 @@
param = copytext(act, custom_param + 1, length(act) + 1)
act = copytext(act, 1, custom_param)
var/datum/emote/E = emote_list[act]
var/datum/emote/E
E = E.emote_list[act]
if(!E)
to_chat(src, "<span class='notice'>Unusable emote '[act]'. Say *help for a list.</span>")
return
@@ -426,10 +427,12 @@
var/list/keys = list()
var/list/message = list("Available emotes, you can use them with say \"*emote\": ")
var/datum/emote/E
var/list/emote_list = E.emote_list
for(var/e in emote_list)
if(e in keys)
continue
var/datum/emote/E = emote_list[e]
E = emote_list[e]
if(E.can_run_emote(user, TRUE))
keys += E.key
+2 -5
View File
@@ -9,7 +9,7 @@
return
if(!loc)
if(client)
for(var/obj/effect/landmark/error/E in landmarks_list)
for(var/obj/effect/landmark/error/E in GLOB.landmarks_list)
loc = E.loc
break
message_admins("[key_name_admin(src)] was found to have no .loc with an attached client, if the cause is unknown it would be wise to ask how this was accomplished.")
@@ -40,9 +40,6 @@
//stuff in the stomach
handle_stomach()
// Vore code for belly processes
handle_internal_contents()
update_gravity(mob_has_gravity())
if(machine)
@@ -70,7 +67,7 @@
if(!digitaldisguise)
src.digitaldisguise = image(loc = src)
src.digitaldisguise.override = 1
for(var/mob/living/silicon/ai/AI in player_list)
for(var/mob/living/silicon/ai/AI in GLOB.player_list)
AI.client.images |= src.digitaldisguise
+26 -26
View File
@@ -2,7 +2,7 @@
. = ..()
generateStaticOverlay()
if(staticOverlays.len)
for(var/mob/living/simple_animal/drone/D in player_list)
for(var/mob/living/simple_animal/drone/D in GLOB.player_list)
if(D && D.seeStatic)
if(D.staticChoice in staticOverlays)
D.staticOverlays |= staticOverlays[D.staticChoice]
@@ -13,10 +13,12 @@
if(unique_name)
name = "[name] ([rand(1, 1000)])"
real_name = name
var/datum/atom_hud/data/human/medical/advanced/medhud = huds[DATA_HUD_MEDICAL_ADVANCED]
var/datum/atom_hud/data/human/medical/advanced/medhud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
medhud.add_to_hud(src)
faction += "\ref[src]"
language_menu = new(src)
/mob/living/prepare_huds()
..()
@@ -33,7 +35,7 @@
buckled.unbuckle_mob(src,force=1)
QDEL_NULL(riding_datum)
for(var/mob/living/simple_animal/drone/D in player_list)
for(var/mob/living/simple_animal/drone/D in GLOB.player_list)
for(var/image/I in staticOverlays)
D.staticOverlays.Remove(I)
D.client.images.Remove(I)
@@ -41,6 +43,8 @@
staticOverlays.len = 0
remove_from_all_data_huds()
QDEL_NULL(language_menu)
return ..()
/mob/living/ghostize(can_reenter_corpse = 1)
@@ -342,8 +346,8 @@
if(full_heal)
fully_heal(admin_revive)
if(stat == DEAD && can_be_revived()) //in some cases you can't revive (e.g. no brain)
dead_mob_list -= src
living_mob_list += src
GLOB.dead_mob_list -= src
GLOB.living_mob_list += src
suiciding = 0
stat = UNCONSCIOUS //the mob starts unconscious,
blind_eyes(1)
@@ -480,7 +484,7 @@
newdir = NORTH
else if(newdir == 12) //E + W
newdir = EAST
if((newdir in cardinal) && (prob(50)))
if((newdir in GLOB.cardinal) && (prob(50)))
newdir = turn(get_dir(T, src.loc), 180)
if(!blood_exists)
new /obj/effect/decal/cleanable/trail_holder(src.loc)
@@ -546,9 +550,6 @@
if(buckled && last_special <= world.time)
resist_buckle()
// climbing out of a gut
if(attempt_vr(src,"vore_process_resist",args)) return TRUE
//Breaking out of a container (Locker, sleeper, cryo...)
else if(isobj(loc))
var/obj/C = loc
@@ -598,7 +599,7 @@
return name
/mob/living/update_gravity(has_gravity,override = 0)
if(!ticker || !ticker.mode)
if(!SSticker || !SSticker.mode)
return
if(has_gravity)
clear_alert("weightless")
@@ -668,7 +669,8 @@
if(what && Adjacent(who) && what.mob_can_equip(who, src, final_where, TRUE))
if(temporarilyRemoveItemFromInventory(what))
if(where_list)
who.put_in_hand(what, where_list[2])
if(!who.put_in_hand(what, where_list[2]))
what.forceMove(get_turf(who))
else
who.equip_to_slot(what, where, TRUE)
@@ -725,14 +727,14 @@
..()
if(statpanel("Status"))
if(ticker && ticker.mode)
for(var/datum/gang/G in ticker.mode.gangs)
if(SSticker && SSticker.mode)
for(var/datum/gang/G in SSticker.mode.gangs)
if(G.is_dominating)
stat(null, "[G.name] Gang Takeover: [max(G.domination_time_remaining(), 0)]")
if(istype(ticker.mode, /datum/game_mode/blob))
var/datum/game_mode/blob/B = ticker.mode
if(istype(SSticker.mode, /datum/game_mode/blob))
var/datum/game_mode/blob/B = SSticker.mode
if(B.message_sent)
stat(null, "Blobs to Blob Win: [blobs_legit.len]/[B.blobwincount]")
stat(null, "Blobs to Blob Win: [GLOB.blobs_legit.len]/[B.blobwincount]")
/mob/living/cancel_camera()
..()
@@ -802,9 +804,6 @@
setStaminaLoss(health - 2)
update_health_hud()
/mob/proc/update_sight()
return
/mob/living/proc/owns_soul()
if(mind)
return mind.soulOwner == mind
@@ -910,13 +909,14 @@
// used by secbot and monkeys Crossed
/mob/living/proc/knockOver(var/mob/living/carbon/C)
C.visible_message("<span class='warning'>[pick( \
"[C] dives out of [src]'s way!", \
"[C] stumbles over [src]!", \
"[C] jumps out of [src]'s path!", \
"[C] trips over [src] and falls!", \
"[C] topples over [src]!", \
"[C] leaps out of [src]'s way!")]</span>")
if(C.key) //save us from monkey hordes
C.visible_message("<span class='warning'>[pick( \
"[C] dives out of [src]'s way!", \
"[C] stumbles over [src]!", \
"[C] jumps out of [src]'s path!", \
"[C] trips over [src] and falls!", \
"[C] topples over [src]!", \
"[C] leaps out of [src]'s way!")]</span>")
C.Weaken(2)
/mob/living/post_buckle_mob(mob/living/M)
+2 -6
View File
@@ -122,7 +122,7 @@
IgniteMob()
/mob/living/proc/grabbedby(mob/living/carbon/user, supress_message = 0)
if(user == src || anchored)
if(user == src || anchored || !isturf(user.loc))
return 0
if(!user.pulling || user.pulling != src)
user.start_pulling(src, supress_message)
@@ -172,7 +172,7 @@
/mob/living/attack_slime(mob/living/simple_animal/slime/M)
if(!ticker || !ticker.mode)
if(!SSticker || !SSticker.mode)
to_chat(M, "You cannot attack people before the game has started.")
return
@@ -244,10 +244,6 @@
return 0
/mob/living/attack_alien(mob/living/carbon/alien/humanoid/M)
if(isturf(loc) && istype(loc.loc, /area/start))
to_chat(M, "No attacking people at spawn, you jackass.")
return 0
switch(M.a_intent)
if ("help")
visible_message("<span class='notice'>[M] caresses [src] with its scythe like arm.</span>")
+4 -3
View File
@@ -1,7 +1,5 @@
/mob/living
see_invisible = SEE_INVISIBLE_LIVING
languages_spoken = HUMAN
languages_understood = HUMAN
sight = 0
see_in_dark = 2
hud_possible = list(HEALTH_HUD,STATUS_HUD,ANTAG_HUD)
@@ -74,4 +72,7 @@
var/list/implants = null
var/tesla_ignore = FALSE
var/datum/riding/riding_datum
var/datum/riding/riding_datum
var/datum/language/selected_default_language
var/datum/language_menu/language_menu
+2 -2
View File
@@ -5,8 +5,8 @@
mind.show_memory(src, 0)
//Round specific stuff
if(ticker && ticker.mode)
switch(ticker.mode.name)
if(SSticker && SSticker.mode)
switch(SSticker.mode.name)
if("sandbox")
CanBuild()
+198 -100
View File
@@ -1,70 +1,69 @@
var/list/department_radio_keys = list(
":r" = "right hand", "#r" = "right hand", ".r" = "right hand",
":l" = "left hand", "#l" = "left hand", ".l" = "left hand",
":i" = "intercom", "#i" = "intercom", ".i" = "intercom",
":h" = "department", "#h" = "department", ".h" = "department",
":c" = "Command", "#c" = "Command", ".c" = "Command",
":n" = "Science", "#n" = "Science", ".n" = "Science",
":m" = "Medical", "#m" = "Medical", ".m" = "Medical",
":e" = "Engineering", "#e" = "Engineering", ".e" = "Engineering",
":s" = "Security", "#s" = "Security", ".s" = "Security",
":w" = "whisper", "#w" = "whisper", ".w" = "whisper",
":b" = "binary", "#b" = "binary", ".b" = "binary",
":a" = "alientalk", "#a" = "alientalk", ".a" = "alientalk",
":t" = "Syndicate", "#t" = "Syndicate", ".t" = "Syndicate",
":u" = "Supply", "#u" = "Supply", ".u" = "Supply",
":v" = "Service", "#v" = "Service", ".v" = "Service",
":o" = "AI Private", "#o" = "AI Private", ".o" = "AI Private",
":g" = "changeling", "#g" = "changeling", ".g" = "changeling",
":y" = "Centcom", "#y" = "Centcom", ".y" = "Centcom",
":x" = "cords", "#x" = "cords", ".x" = "cords",
":p" = "admin", "#p" = "admin", ".p" = "admin",
":d" = "deadmin", "#d" = "deadmin", ".d" = "deadmin",
GLOBAL_LIST_INIT(department_radio_keys, list(
":r" = "right hand", ".r" = "right hand",
":l" = "left hand", ".l" = "left hand",
":i" = "intercom", ".i" = "intercom",
":h" = "department", ".h" = "department",
":c" = "Command", ".c" = "Command",
":n" = "Science", ".n" = "Science",
":m" = "Medical", ".m" = "Medical",
":e" = "Engineering", ".e" = "Engineering",
":s" = "Security", ".s" = "Security",
":b" = "binary", ".b" = "binary",
":a" = "alientalk", ".a" = "alientalk",
":t" = "Syndicate", ".t" = "Syndicate",
":u" = "Supply", ".u" = "Supply",
":v" = "Service", ".v" = "Service",
":o" = "AI Private", ".o" = "AI Private",
":g" = "changeling", ".g" = "changeling",
":y" = "Centcom", ".y" = "Centcom",
":x" = "cords", ".x" = "cords",
":p" = "admin", ".p" = "admin",
":d" = "deadmin", ".d" = "deadmin",
":R" = "right hand", "#R" = "right hand", ".R" = "right hand",
":L" = "left hand", "#L" = "left hand", ".L" = "left hand",
":I" = "intercom", "#I" = "intercom", ".I" = "intercom",
":H" = "department", "#H" = "department", ".H" = "department",
":C" = "Command", "#C" = "Command", ".C" = "Command",
":N" = "Science", "#N" = "Science", ".N" = "Science",
":M" = "Medical", "#M" = "Medical", ".M" = "Medical",
":E" = "Engineering", "#E" = "Engineering", ".E" = "Engineering",
":S" = "Security", "#S" = "Security", ".S" = "Security",
":W" = "whisper", "#W" = "whisper", ".W" = "whisper",
":B" = "binary", "#B" = "binary", ".B" = "binary",
":A" = "alientalk", "#A" = "alientalk", ".A" = "alientalk",
":T" = "Syndicate", "#T" = "Syndicate", ".T" = "Syndicate",
":U" = "Supply", "#U" = "Supply", ".U" = "Supply",
":V" = "Service", "#V" = "Service", ".V" = "Service",
":O" = "AI Private", "#O" = "AI Private", ".O" = "AI Private",
":G" = "changeling", "#G" = "changeling", ".G" = "changeling",
":Y" = "Centcom", "#Y" = "Centcom", ".Y" = "Centcom",
":X" = "cords", "#X" = "cords", ".X" = "cords",
":P" = "admin", "#P" = "admin", ".P" = "admin",
":D" = "deadmin", "#D" = "deadmin", ".D" = "deadmin",
":R" = "right hand", ".R" = "right hand",
":L" = "left hand", ".L" = "left hand",
":I" = "intercom", ".I" = "intercom",
":H" = "department", ".H" = "department",
":C" = "Command", ".C" = "Command",
":N" = "Science", ".N" = "Science",
":M" = "Medical", ".M" = "Medical",
":E" = "Engineering", ".E" = "Engineering",
":S" = "Security", ".S" = "Security",
":B" = "binary", ".B" = "binary",
":A" = "alientalk", ".A" = "alientalk",
":T" = "Syndicate", ".T" = "Syndicate",
":U" = "Supply", ".U" = "Supply",
":V" = "Service", ".V" = "Service",
":O" = "AI Private", ".O" = "AI Private",
":G" = "changeling", ".G" = "changeling",
":Y" = "Centcom", ".Y" = "Centcom",
":X" = "cords", ".X" = "cords",
":P" = "admin", ".P" = "admin",
":D" = "deadmin", ".D" = "deadmin",
//kinda localization -- rastaf0
//same keys as above, but on russian keyboard layout. This file uses cp1251 as encoding.
":ê" = "right hand", "#ê" = "right hand", ".ê" = "right hand",
":ä" = "left hand", "#ä" = "left hand", ".ä" = "left hand",
":ø" = "intercom", "#ø" = "intercom", ".ø" = "intercom",
":ð" = "department", "#ð" = "department", ".ð" = "department",
":ñ" = "Command", "#ñ" = "Command", ".ñ" = "Command",
":ò" = "Science", "#ò" = "Science", ".ò" = "Science",
":ü" = "Medical", "#ü" = "Medical", ".ü" = "Medical",
":ó" = "Engineering", "#ó" = "Engineering", ".ó" = "Engineering",
":û" = "Security", "#û" = "Security", ".û" = "Security",
":ö" = "whisper", "#ö" = "whisper", ".ö" = "whisper",
":è" = "binary", "#è" = "binary", ".è" = "binary",
":ô" = "alientalk", "#ô" = "alientalk", ".ô" = "alientalk",
":å" = "Syndicate", "#å" = "Syndicate", ".å" = "Syndicate",
":é" = "Supply", "#é" = "Supply", ".é" = "Supply",
":ï" = "changeling", "#ï" = "changeling", ".ï" = "changeling"
)
":ê" = "right hand", ".ê" = "right hand",
":ä" = "left hand", ".ä" = "left hand",
":ø" = "intercom", ".ø" = "intercom",
":ð" = "department", ".ð" = "department",
":ñ" = "Command", ".ñ" = "Command",
":ò" = "Science", ".ò" = "Science",
":ü" = "Medical", ".ü" = "Medical",
":ó" = "Engineering", ".ó" = "Engineering",
":û" = "Security", ".û" = "Security",
":è" = "binary", ".è" = "binary",
":ô" = "alientalk", ".ô" = "alientalk",
":å" = "Syndicate", ".å" = "Syndicate",
":é" = "Supply", ".é" = "Supply",
":ï" = "changeling", ".ï" = "changeling"))
var/list/crit_allowed_modes = list(MODE_WHISPER,MODE_CHANGELING,MODE_ALIEN)
/mob/living/say(message, bubble_type,var/list/spans = list(), sanitize = TRUE, datum/language/language = null)
var/static/list/crit_allowed_modes = list(MODE_WHISPER = TRUE, MODE_CHANGELING = TRUE, MODE_ALIEN = TRUE)
var/static/list/unconscious_allowed_modes = list(MODE_CHANGELING = TRUE, MODE_ALIEN = TRUE)
var/static/list/one_character_prefix = list(MODE_HEADSET = TRUE, MODE_ROBOT = TRUE, MODE_WHISPER = TRUE)
/mob/living/say(message, bubble_type,var/list/spans = list(), sanitize = TRUE)
if(sanitize)
message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
if(!message || message == "")
@@ -72,8 +71,9 @@ var/list/crit_allowed_modes = list(MODE_WHISPER,MODE_CHANGELING,MODE_ALIEN)
var/message_mode = get_message_mode(message)
var/original_message = message
var/in_critical = InCritical()
if(message_mode == MODE_HEADSET || message_mode == MODE_ROBOT)
if(one_character_prefix[message_mode])
message = copytext(message, 2)
else if(message_mode)
message = copytext(message, 3)
@@ -94,34 +94,79 @@ var/list/crit_allowed_modes = list(MODE_WHISPER,MODE_CHANGELING,MODE_ALIEN)
say_dead(original_message)
return
if(check_emote(original_message))
if(check_emote(original_message) || !can_speak_basic(original_message))
return
if(!can_speak_basic(original_message)) //Stat is seperate so I can handle whispers properly.
return
if(in_critical)
if(!(crit_allowed_modes[message_mode]))
return
else if(stat == UNCONSCIOUS)
if(!(unconscious_allowed_modes[message_mode]))
return
if(stat && !(message_mode in crit_allowed_modes))
return
// language comma detection.
var/datum/language/message_language = get_message_language(message)
if(message_language)
// No, you cannot speak in xenocommon just because you know the key
if(can_speak_in_language(message_language))
language = message_language
message = copytext(message, 3)
if(handle_inherent_channels(message, message_mode)) //Hiveminds, binary chat & holopad.
// Trim the space if they said ",0 I LOVE LANGUAGES"
if(findtext(message, " ", 1, 2))
message = copytext(message, 2)
if(!language)
language = get_default_language()
// Detection of language needs to be before inherent channels, because
// AIs use inherent channels for the holopad. Most inherent channels
// ignore the language argument however.
if(handle_inherent_channels(message, message_mode, language)) //Hiveminds, binary chat & holopad.
return
if(!can_speak_vocal(message))
to_chat(src, "<span class='warning'>You find yourself unable to speak!</span>")
return
if(message_mode != MODE_WHISPER) //whisper() calls treat_message(); double process results in "hisspering"
message = treat_message(message)
var/message_range = 7
var/succumbed = FALSE
if(message_mode == MODE_WHISPER)
message_range = 1
spans |= SPAN_ITALICS
log_whisper("[src.name]/[src.key] : [message]")
if(in_critical)
var/health_diff = round(-HEALTH_THRESHOLD_DEAD + health)
// If we cut our message short, abruptly end it with a-..
var/message_len = length(message)
message = copytext(message, 1, health_diff) + "[message_len > health_diff ? "-.." : "..."]"
message = Ellipsis(message, 10, 1)
message_mode = MODE_WHISPER_CRIT
succumbed = TRUE
else
log_say("[name]/[key] : [message]")
message = treat_message(message)
if(!message)
return
spans += get_spans()
if(language)
var/datum/language/L = GLOB.language_datums[language]
if(!istype(L))
L = new language
GLOB.language_datums[language] = L
spans |= L.spans
//Log what we've said with an associated timestamp, using the list's len for safety/to prevent overwriting messages
log_message(message, INDIVIDUAL_SAY_LOG)
var/message_range = 7
var/radio_return = radio(message, message_mode, spans)
if(radio_return & NOPASS) //There's a whisper() message_mode, no need to continue the proc if that is called
return
if(radio_return & ITALICS)
spans |= SPAN_ITALICS
if(radio_return & REDUCE_RANGE)
@@ -137,12 +182,15 @@ var/list/crit_allowed_modes = list(MODE_WHISPER,MODE_CHANGELING,MODE_ALIEN)
if(pressure < ONE_ATMOSPHERE*0.4) //Thin air, let's italicise the message
spans |= SPAN_ITALICS
send_speech(message, message_range, src, bubble_type, spans)
send_speech(message, message_range, src, bubble_type, spans, language, message_mode)
if(succumbed)
succumb(1)
to_chat(src, compose_message(src, language, message, , spans, message_mode))
log_say("[name]/[key] : [message]")
return 1
/mob/living/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans)
/mob/living/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
if(!client)
return
var/deaf_message
@@ -154,20 +202,38 @@ var/list/crit_allowed_modes = list(MODE_WHISPER,MODE_CHANGELING,MODE_ALIEN)
else
deaf_message = "<span class='notice'>You can't hear yourself!</span>"
deaf_type = 2 // Since you should be able to hear yourself without looking
if(!(message_langs & languages_understood) || force_compose) //force_compose is so AIs don't end up without their hrefs.
message = compose_message(speaker, message_langs, raw_message, radio_freq, spans)
// Recompose message for AI hrefs, language incomprehension.
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode)
show_message(message, 2, deaf_message, deaf_type)
return message
/mob/living/send_speech(message, message_range = 7, obj/source = src, bubble_type = bubble_icon, list/spans)
var/list/listening = get_hearers_in_view(message_range, source)
for(var/mob/M in player_list)
/mob/living/send_speech(message, message_range = 6, obj/source = src, bubble_type = bubble_icon, list/spans, datum/language/message_language=null, message_mode)
var/static/list/eavesdropping_modes = list(MODE_WHISPER = TRUE, MODE_WHISPER_CRIT = TRUE)
var/eavesdrop_range = 0
if(eavesdropping_modes[message_mode])
eavesdrop_range = EAVESDROP_EXTRA_RANGE
var/list/listening = get_hearers_in_view(message_range+eavesdrop_range, source)
var/list/the_dead = list()
for(var/_M in GLOB.player_list)
var/mob/M = _M
if(M.stat == DEAD && M.client && ((M.client.prefs.chat_toggles & CHAT_GHOSTEARS) || (get_dist(M, src) <= 7 && M.z == z)) && client) // client is so that ghosts don't have to listen to mice
listening |= M
the_dead[M] = TRUE
var/rendered = compose_message(src, languages_spoken, message, , spans)
for(var/atom/movable/AM in listening)
AM.Hear(rendered, src, languages_spoken, message, , spans)
var/eavesdropping
var/eavesrendered
if(eavesdrop_range)
eavesdropping = stars(message)
eavesrendered = compose_message(src, message_language, eavesdropping, , spans, message_mode)
var/rendered = compose_message(src, message_language, message, , spans, message_mode)
for(var/_AM in listening)
var/atom/movable/AM = _AM
if(eavesdrop_range && get_dist(source, AM) > message_range && !(the_dead[AM]))
AM.Hear(eavesrendered, src, message_language, eavesdropping, , spans, message_mode)
else
AM.Hear(rendered, src, message_language, message, , spans, message_mode)
//speech bubble
var/list/speech_bubble_recipients = list()
@@ -176,8 +242,7 @@ var/list/crit_allowed_modes = list(MODE_WHISPER,MODE_CHANGELING,MODE_ALIEN)
speech_bubble_recipients.Add(M.client)
var/image/I = image('icons/mob/talk.dmi', src, "[bubble_type][say_test(message)]", FLY_LAYER)
I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
spawn(0)
flick_overlay(I, speech_bubble_recipients, 30)
INVOKE_ASYNC(GLOBAL_PROC, /.proc/flick_overlay, I, speech_bubble_recipients, 30)
/mob/proc/binarycheck()
return 0
@@ -216,16 +281,32 @@ var/list/crit_allowed_modes = list(MODE_WHISPER,MODE_CHANGELING,MODE_ALIEN)
/mob/living/proc/get_message_mode(message)
if(copytext(message, 1, 2) == ";")
return MODE_HEADSET
else if(copytext(message, 1, 2) == "#")
return MODE_WHISPER
else if(length(message) > 2)
return department_radio_keys[copytext(message, 1, 3)]
return GLOB.department_radio_keys[copytext(message, 1, 3)]
/mob/living/proc/get_message_language(message)
var/static/list/langlist
if(!langlist)
langlist = subtypesof(/datum/language)
if(copytext(message, 1, 2) == ",")
var/key = copytext(message, 2, 3)
for(var/ld in langlist)
var/datum/language/LD = ld
if(initial(LD.key) == key)
return LD
return null
/mob/living/proc/handle_inherent_channels(message, message_mode)
if(message_mode == MODE_CHANGELING)
switch(lingcheck())
if(3)
var/msg = "<i><font color=#800040><b>[src.mind]:</b> [message]</font></i>"
for(var/mob/M in mob_list)
if(M in dead_mob_list)
for(var/_M in GLOB.mob_list)
var/mob/M = _M
if(M in GLOB.dead_mob_list)
var/link = FOLLOW_LINK(M, src)
to_chat(M, "[link] [msg]")
else
@@ -240,8 +321,9 @@ var/list/crit_allowed_modes = list(MODE_WHISPER,MODE_CHANGELING,MODE_ALIEN)
if(2)
var/msg = "<i><font color=#800080><b>[mind.changeling.changelingID]:</b> [message]</font></i>"
log_say("[mind.changeling.changelingID]/[src.key] : [message]")
for(var/mob/M in mob_list)
if(M in dead_mob_list)
for(var/_M in GLOB.mob_list)
var/mob/M = _M
if(M in GLOB.dead_mob_list)
var/link = FOLLOW_LINK(M, src)
to_chat(M, "[link] [msg]")
else
@@ -287,32 +369,28 @@ var/list/crit_allowed_modes = list(MODE_WHISPER,MODE_CHANGELING,MODE_ALIEN)
return message
/mob/living/proc/radio(message, message_mode, list/spans)
/mob/living/proc/radio(message, message_mode, list/spans, language)
switch(message_mode)
if(MODE_R_HAND)
for(var/obj/item/r_hand in get_held_items_for_side("r", all = TRUE))
if (r_hand)
return r_hand.talk_into(src, message, , spans)
return r_hand.talk_into(src, message, , spans, language)
return ITALICS | REDUCE_RANGE
if(MODE_L_HAND)
for(var/obj/item/l_hand in get_held_items_for_side("l", all = TRUE))
if (l_hand)
return l_hand.talk_into(src, message, , spans)
return l_hand.talk_into(src, message, , spans, language)
return ITALICS | REDUCE_RANGE
if(MODE_INTERCOM)
for (var/obj/item/device/radio/intercom/I in view(1, null))
I.talk_into(src, message, , spans)
I.talk_into(src, message, , spans, language)
return ITALICS | REDUCE_RANGE
if(MODE_BINARY)
if(binarycheck())
robot_talk(message)
return ITALICS | REDUCE_RANGE //Does not return 0 since this is only reached by humans, not borgs or AIs.
if(MODE_WHISPER)
whisper(message)
return NOPASS
return 0
/mob/living/lingcheck() //1 is ling w/ no hivemind. 2 is ling w/hivemind. 3 is ling victim being linked into hivemind.
@@ -324,10 +402,30 @@ var/list/crit_allowed_modes = list(MODE_WHISPER,MODE_CHANGELING,MODE_ALIEN)
return 3
return 0
/mob/living/say_quote(input, list/spans)
/mob/living/say_quote(input, list/spans, message_mode)
var/tempinput = attach_spans(input, spans)
if(message_mode == MODE_WHISPER)
return "[verb_whisper], \"[tempinput]\""
if(message_mode == MODE_WHISPER_CRIT)
return "[verb_whisper] in [p_their()] last breath, \"[tempinput]\""
if (stuttering)
return "stammers, \"[tempinput]\""
if (getBrainLoss() >= 60)
return "gibbers, \"[tempinput]\""
return ..()
/mob/living/get_default_language()
if(selected_default_language)
if(has_language(selected_default_language))
return selected_default_language
else
selected_default_language = null
. = ..()
/mob/living/proc/open_language_menu(mob/user)
language_menu.ui_interact(user)
/mob/living/whisper(message as text)
say("#[message]")
+98 -27
View File
@@ -1,11 +1,10 @@
#define CALL_BOT_COOLDOWN 900
var/list/ai_list = list()
//Not sure why this is necessary...
/proc/AutoUpdateAI(obj/subject)
var/is_in_use = 0
if (subject!=null)
for(var/A in ai_list)
for(var/A in GLOB.ai_list)
var/mob/living/silicon/ai/M = A
if ((M.client && M.machine == subject))
is_in_use = 1
@@ -22,7 +21,6 @@ var/list/ai_list = list()
canmove = 0
status_flags = CANSTUN|CANPUSH
a_intent = INTENT_HARM //so we always get pushed instead of trying to swap
force_compose = 1 //This ensures that the AI always composes it's own hear message. Needed for hrefs and job display.
sight = SEE_TURFS | SEE_MOBS | SEE_OBJS
see_in_dark = 8
med_hud = DATA_HUD_MEDICAL_BASIC
@@ -84,6 +82,10 @@ var/list/ai_list = list()
var/obj/machinery/camera/portable/builtInCamera
var/obj/structure/AIcore/deactivated/linked_core //For exosuit control
var/mob/living/silicon/robot/deployed_shell = null //For shell control
var/datum/action/innate/deploy_shell/deploy_action = new
var/datum/action/innate/deploy_last_shell/redeploy_action = new
var/chnotify = 0
/mob/living/silicon/ai/Initialize(mapload, datum/ai_laws/L, mob/target_ai)
..()
@@ -138,22 +140,24 @@ var/list/ai_list = list()
radio = new /obj/item/device/radio/headset/ai(src)
aicamera = new/obj/item/device/camera/siliconcam/ai_camera(src)
deploy_action.Grant(src)
if(isturf(loc))
verbs.Add(/mob/living/silicon/ai/proc/ai_network_change, \
/mob/living/silicon/ai/proc/ai_statuschange, /mob/living/silicon/ai/proc/ai_hologram_change, \
/mob/living/silicon/ai/proc/toggle_camera_light, /mob/living/silicon/ai/proc/botcall,\
/mob/living/silicon/ai/proc/control_integrated_radio, /mob/living/silicon/ai/proc/set_automatic_say_channel)
ai_list += src
shuttle_caller_list += src
GLOB.ai_list += src
GLOB.shuttle_caller_list += src
builtInCamera = new /obj/machinery/camera/portable(src)
builtInCamera.network = list("SS13")
/mob/living/silicon/ai/Destroy()
ai_list -= src
shuttle_caller_list -= src
GLOB.ai_list -= src
GLOB.shuttle_caller_list -= src
SSshuttle.autoEvac()
qdel(eyeobj) // No AI, no Eye
malfhack = null
@@ -247,13 +251,16 @@ var/list/ai_list = list()
for(var/mob/living/silicon/robot/R in connected_robots)
borg_area = get_area(R)
var/robot_status = "Nominal"
if(R.stat || !R.client)
if(R.shell)
robot_status = "AI SHELL"
else if(R.stat || !R.client)
robot_status = "OFFLINE"
else if(!R.cell || R.cell.charge <= 0)
robot_status = "DEPOWERED"
//Name, Health, Battery, Module, Area, and Status! Everything an AI wants to know about its borgies!
stat(null, text("[R.name] | S.Integrity: [R.health]% | Cell: [R.cell ? "[R.cell.charge]/[R.cell.maxcharge]" : "Empty"] | \
Module: [R.designation] | Loc: [borg_area.name] | Status: [robot_status]"))
Module: [R.designation] | Loc: [borg_area.name] | Status: [robot_status]"))
stat(null, text("AI shell beacons detected: [LAZYLEN(GLOB.available_ai_shells)]")) //Count of total AI shells
else
stat(null, text("Systems nonfunctional"))
@@ -293,7 +300,7 @@ var/list/ai_list = list()
/mob/living/silicon/ai/proc/ai_roster()
var/dat = "<html><head><title>Crew Roster</title></head><body><b>Crew Roster:</b><br><br>"
dat += data_core.get_manifest()
dat += GLOB.data_core.get_manifest()
dat += "</body></html>"
src << browse(dat, "window=airoster")
@@ -315,7 +322,7 @@ var/list/ai_list = list()
// hack to display shuttle timer
if(!EMERGENCY_IDLE_OR_RECALLED)
var/obj/machinery/computer/communications/C = locate() in machines
var/obj/machinery/computer/communications/C = locate() in GLOB.machines
if(C)
C.post_status("shuttle")
@@ -363,7 +370,7 @@ var/list/ai_list = list()
unset_machine()
src << browse(null, t1)
if (href_list["switchcamera"])
switchCamera(locate(href_list["switchcamera"])) in cameranet.cameras
switchCamera(locate(href_list["switchcamera"])) in GLOB.cameranet.cameras
if (href_list["showalerts"])
ai_alerts()
#ifdef AI_VOX
@@ -403,14 +410,14 @@ var/list/ai_list = list()
if(call_bot_cooldown > world.time)
to_chat(src, "<span class='danger'>Error: Your last call bot command is still processing, please wait for the bot to finish calculating a route.</span>")
return
Bot = locate(href_list["callbot"]) in living_mob_list
Bot = locate(href_list["callbot"]) in GLOB.living_mob_list
if(!Bot || Bot.remote_disabled || src.control_disabled)
return //True if there is no bot found, the bot is manually emagged, or the AI is carded with wireless off.
waypoint_mode = 1
to_chat(src, "<span class='notice'>Set your waypoint by clicking on a valid location free of obstructions.</span>")
return
if(href_list["interface"]) //Remotely connect to a bot!
Bot = locate(href_list["interface"]) in living_mob_list
Bot = locate(href_list["interface"]) in GLOB.living_mob_list
if(!Bot || Bot.remote_disabled || src.control_disabled)
return
Bot.attack_ai(src)
@@ -423,7 +430,7 @@ var/list/ai_list = list()
if(controlled_mech)
to_chat(src, "<span class='warning'>You are already loaded into an onboard computer!</span>")
return
if(!cameranet.checkCameraVis(M))
if(!GLOB.cameranet.checkCameraVis(M))
to_chat(src, "<span class='warning'>Exosuit is no longer near active cameras.</span>")
return
if(lacks_power())
@@ -470,7 +477,7 @@ var/list/ai_list = list()
d += "<A HREF=?src=\ref[src];botrefresh=1>Query network status</A><br>"
d += "<table width='100%'><tr><td width='40%'><h3>Name</h3></td><td width='30%'><h3>Status</h3></td><td width='30%'><h3>Location</h3></td><td width='10%'><h3>Control</h3></td></tr>"
for (Bot in living_mob_list)
for (Bot in GLOB.living_mob_list)
if(Bot.z == ai_Zlevel && !Bot.remote_disabled) //Only non-emagged bots on the same Z-level are detected!
bot_area = get_area(Bot)
var/bot_mode = Bot.get_mode()
@@ -492,7 +499,7 @@ var/list/ai_list = list()
//The target must be in view of a camera or near the core.
if(turf_check in range(get_turf(src)))
call_bot(turf_check)
else if(cameranet && cameranet.checkTurfVis(turf_check))
else if(GLOB.cameranet && GLOB.cameranet.checkTurfVis(turf_check))
call_bot(turf_check)
else
to_chat(src, "<span class='danger'>Selected location is not visible.</span>")
@@ -582,7 +589,7 @@ var/list/ai_list = list()
var/mob/living/silicon/ai/U = usr
for (var/obj/machinery/camera/C in cameranet.cameras)
for (var/obj/machinery/camera/C in GLOB.cameranet.cameras)
if(!C.can_use())
continue
@@ -601,7 +608,7 @@ var/list/ai_list = list()
if(isnull(network))
network = old_network // If nothing is selected
else
for(var/obj/machinery/camera/C in cameranet.cameras)
for(var/obj/machinery/camera/C in GLOB.cameranet.cameras)
if(!C.can_use())
continue
if(network in C.network)
@@ -625,7 +632,7 @@ var/list/ai_list = list()
return //won't work if dead
var/list/ai_emotions = list("Very Happy", "Happy", "Neutral", "Unsure", "Confused", "Sad", "BSOD", "Blank", "Problems?", "Awesome", "Facepalm", "Friend Computer", "Dorfy", "Blue Glow", "Red Glow")
var/emote = input("Please, select a status!", "AI Status", null, null) in ai_emotions
for (var/obj/machinery/M in machines) //change status
for (var/obj/machinery/M in GLOB.machines) //change status
if(istype(M, /obj/machinery/ai_status_display))
var/obj/machinery/ai_status_display/AISD = M
AISD.emotion = emote
@@ -652,7 +659,7 @@ var/list/ai_list = list()
if("Crew Member")
var/list/personnel_list = list()
for(var/datum/data/record/t in data_core.locked)//Look in data core locked.
for(var/datum/data/record/t in GLOB.data_core.locked)//Look in data core locked.
personnel_list["[t.fields["name"]]: [t.fields["rank"]]"] = t.fields["image"]//Pull names, rank, and image.
if(personnel_list.len)
@@ -791,12 +798,13 @@ var/list/ai_list = list()
if(!..())
return
if(interaction == AI_TRANS_TO_CARD)//The only possible interaction. Upload AI mob to a card.
if(!mind)
to_chat(user, "<span class='warning'>No intelligence patterns detected.</span>" )
return
if(!can_be_carded)
to_chat(user, "<span class='boldwarning'>Transfer failed.</span>")
return
disconnect_shell() //If the AI is controlling a borg, force the player back to core!
if(!mind)
to_chat(user, "<span class='warning'>No intelligence patterns detected.</span>" )
return
ShutOffDoomsdayDevice()
new /obj/structure/AIcore/deactivated(loc)//Spawns a deactivated terminal at AI location.
ai_restore_power()//So the AI initially has power.
@@ -818,12 +826,12 @@ var/list/ai_list = list()
//stop AIs from leaving windows open and using then after they lose vision
//apc_override is needed here because AIs use their own APC when powerless
//get_turf_pixel() is because APCs in maint aren't actually in view of the inner camera
if(M && cameranet && !cameranet.checkTurfVis(get_turf_pixel(M)) && !apc_override)
if(M && GLOB.cameranet && !GLOB.cameranet.checkTurfVis(get_turf_pixel(M)) && !apc_override)
return
return 1
/mob/living/silicon/ai/proc/relay_speech(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans)
raw_message = lang_treat(speaker, message_langs, raw_message, spans)
/mob/living/silicon/ai/proc/relay_speech(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
raw_message = lang_treat(speaker, message_language, raw_message, spans, message_mode)
var/name_used = speaker.GetVoice()
var/rendered = "<i><span class='game say'>Relayed Speech: <span class='name'>[name_used]</span> <span class='message'>[raw_message]</span></span></i>"
show_message(rendered, 2)
@@ -907,6 +915,69 @@ var/list/ai_list = list()
to_chat(src, "Hack complete. \The [apc] is now under your exclusive control.")
apc.update_icon()
/mob/living/silicon/ai/verb/deploy_to_shell(var/mob/living/silicon/robot/target)
set category = "AI Commands"
set name = "Deploy to Shell"
if(stat || lacks_power() || control_disabled)
to_chat(src, "<span class='danger'>Wireless networking module is offline.</span>")
return
var/list/possible = list()
for(var/borgie in GLOB.available_ai_shells)
var/mob/living/silicon/robot/R = borgie
if(R.shell && !R.deployed && (R.stat != DEAD) && (!R.connected_ai ||(R.connected_ai == src)))
possible += R
if(!LAZYLEN(possible))
to_chat(src, "No usable AI shell beacons detected.")
if(!target || !(target in possible)) //If the AI is looking for a new shell, or its pre-selected shell is no longer valid
target = input(src, "Which body to control?") as null|anything in possible
if (!target || target.stat == DEAD || target.deployed || !(!target.connected_ai ||(target.connected_ai == src)))
return
else if(mind)
soullink(/datum/soullink/sharedbody, src, target)
deployed_shell = target
target.deploy_init(src)
mind.transfer_to(target)
diag_hud_set_deployed()
/datum/action/innate/deploy_shell
name = "Deploy to AI Shell"
desc = "Wirelessly control a specialized cyborg shell."
button_icon_state = "ai_shell"
/datum/action/innate/deploy_shell/Trigger()
var/mob/living/silicon/ai/AI = owner
if(!AI)
return
AI.deploy_to_shell()
/datum/action/innate/deploy_last_shell
name = "Reconnect to shell"
desc = "Reconnect to the most recently used AI shell."
button_icon_state = "ai_last_shell"
var/mob/living/silicon/robot/last_used_shell
/datum/action/innate/deploy_last_shell/Trigger()
if(!owner)
return
if(last_used_shell)
var/mob/living/silicon/ai/AI = owner
AI.deploy_to_shell(last_used_shell)
else
Remove(owner) //If the last shell is blown, destroy it.
/mob/living/silicon/ai/proc/disconnect_shell()
if(deployed_shell) //Forcibly call back AI in event of things such as damage, EMP or power loss.
to_chat(src, "<span class='danger'>Your remote connection has been reset!</span>")
deployed_shell.undeploy()
diag_hud_set_deployed()
/mob/living/silicon/ai/resist()
return
@@ -6,7 +6,7 @@
/mob/living/silicon/ai/attack_alien(mob/living/carbon/alien/humanoid/M)
if(!ticker || !ticker.mode)
if(!SSticker || !SSticker.mode)
to_chat(M, "You cannot attack people before the game has started.")
return
..()
@@ -22,6 +22,7 @@
return 0
/mob/living/silicon/ai/emp_act(severity)
disconnect_shell()
if (prob(30))
switch(pick(1,2))
if(1)
+2 -2
View File
@@ -16,7 +16,7 @@
if(eyeobj)
eyeobj.setLoc(get_turf(src))
shuttle_caller_list -= src
GLOB.shuttle_caller_list -= src
SSshuttle.autoEvac()
ShutOffDoomsdayDevice()
@@ -35,7 +35,7 @@
if(nuking)
set_security_level("red")
nuking = FALSE
for(var/obj/item/weapon/pinpointer/P in pinpointer_list)
for(var/obj/item/weapon/pinpointer/P in GLOB.pinpointer_list)
P.switch_mode_to(TRACK_NUKE_DISK) //Party's over, back to work, everyone
P.nuke_warning = FALSE
@@ -1,21 +1,23 @@
/mob/living/silicon/ai/examine(mob/user)
var/msg = "<span class='info'>*---------*\nThis is \icon[src] <EM>[src]</EM>!\n"
if (src.stat == DEAD)
if (stat == DEAD)
msg += "<span class='deadsay'>It appears to be powered-down.</span>\n"
else
msg += "<span class='warning'>"
if (src.getBruteLoss())
if (src.getBruteLoss() < 30)
if (getBruteLoss())
if (getBruteLoss() < 30)
msg += "It looks slightly dented.\n"
else
msg += "<B>It looks severely dented!</B>\n"
if (src.getFireLoss())
if (src.getFireLoss() < 30)
if (getFireLoss())
if (getFireLoss() < 30)
msg += "It looks slightly charred.\n"
else
msg += "<B>Its casing is melted and heat-warped!</B>\n"
msg += "</span>"
if (shunted == 0 && !src.client)
if(deployed_shell)
msg += "The wireless networking light is blinking.\n"
else if (!shunted && !client)
msg += "[src]Core.exe has stopped responding! NTOS is searching for a solution to the problem...\n"
msg += "*---------*</span>"
@@ -2,9 +2,9 @@
//
// The datum containing all the chunks.
var/const/CHUNK_SIZE = 16 // Only chunk sizes that are to the power of 2. E.g: 2, 4, 8, 16, etc..
#define CHUNK_SIZE 16 // Only chunk sizes that are to the power of 2. E.g: 2, 4, 8, 16, etc..
var/datum/cameranet/cameranet = new()
GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new)
/datum/cameranet
var/name = "Camera Net" // Name to show for VV and stat()
@@ -66,7 +66,7 @@ var/datum/cameranet/cameranet = new()
/datum/cameranet/proc/updateVisibility(atom/A, opacity_check = 1)
if(!ticker || (opacity_check && !A.opacity))
if(!SSticker || (opacity_check && !A.opacity))
return
majorChunkChange(A, 2)
@@ -151,7 +151,7 @@ var/datum/cameranet/cameranet = new()
if(!statclick)
statclick = new/obj/effect/statclick/debug(null, "Initializing...", src)
stat(name, statclick.update("Cameras: [cameranet.cameras.len] | Chunks: [cameranet.chunks.len]"))
stat(name, statclick.update("Cameras: [GLOB.cameranet.cameras.len] | Chunks: [GLOB.cameranet.chunks.len]"))
// Debug verb for VVing the chunk that the turf is in.
/*
@@ -173,4 +173,5 @@
t.obscured.plane = LIGHTING_PLANE+1
obscured += t.obscured
#undef UPDATE_BUFFER
#undef UPDATE_BUFFER
#undef CHUNK_SIZE
@@ -21,7 +21,7 @@
return
T = get_turf(T)
loc = T
cameranet.visibility(src)
GLOB.cameranet.visibility(src)
if(ai.client)
ai.client.eye = src
update_parallax_contents()
@@ -104,6 +104,6 @@
acceleration = !acceleration
to_chat(usr, "Camera acceleration has been toggled [acceleration ? "on" : "off"].")
/mob/camera/aiEye/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans)
/mob/camera/aiEye/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
if(relay_speech && speaker && ai && !radio_freq && speaker != ai && near_camera(speaker))
ai.relay_speech(message, speaker, message_langs, raw_message, radio_freq, spans)
ai.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans)
+4 -1
View File
@@ -65,6 +65,7 @@
health = maxHealth - getOxyLoss() - getToxLoss() - getBruteLoss() - getFireLoss()
update_stat()
diag_hud_set_health()
disconnect_shell()
/mob/living/silicon/ai/update_stat()
if(status_flags & GODMODE)
@@ -90,6 +91,7 @@
if(see_override)
see_invisible = see_override
sync_lighting_plane_alpha()
/mob/living/silicon/ai/proc/start_RestorePowerRoutine()
@@ -146,7 +148,7 @@
to_chat(src, "Receiving control information from APC.")
sleep(2)
apc_override = 1
theAPC.ui_interact(src, state = conscious_state)
theAPC.ui_interact(src, state = GLOB.conscious_state)
apc_override = 0
aiRestorePowerRoutine = POWER_RESTORATION_APC_FOUND
sleep(50)
@@ -163,6 +165,7 @@
update_sight()
/mob/living/silicon/ai/proc/ai_lose_power()
disconnect_shell()
aiRestorePowerRoutine = POWER_RESTORATION_START
blind_eyes(1)
update_sight()
+1 -1
View File
@@ -6,7 +6,7 @@
client.images += blood
if(stat != DEAD)
for(var/obj/machinery/ai_status_display/O in machines) //change status
for(var/obj/machinery/ai_status_display/O in GLOB.machines) //change status
O.mode = 1
O.emotion = "Neutral"
view_core()
+25 -20
View File
@@ -1,6 +1,6 @@
/mob/living/silicon/ai/say(message)
/mob/living/silicon/ai/say(message, language)
if(parent && istype(parent) && parent.stat != 2) //If there is a defined "parent" AI, it is actually an AI, and it is alive, anything the AI tries to say is said by the parent instead.
parent.say(message)
parent.say(message, language)
return
..(message)
@@ -17,7 +17,7 @@
/mob/living/silicon/ai/IsVocal()
return !config.silent_ai
/mob/living/silicon/ai/radio(message, message_mode, list/spans)
/mob/living/silicon/ai/radio(message, message_mode, list/spans, language)
if(!radio_enabled || aiRestorePowerRoutine || stat) //AI cannot speak if radio is disabled (via intellicard) or depowered.
to_chat(src, "<span class='danger'>Your radio transmitter is offline!</span>")
return 0
@@ -29,17 +29,17 @@
else
return ..()
/mob/living/silicon/ai/handle_inherent_channels(message, message_mode)
/mob/living/silicon/ai/handle_inherent_channels(message, message_mode, language)
. = ..()
if(.)
return .
if(message_mode == MODE_HOLOPAD)
holopad_talk(message)
holopad_talk(message, language)
return 1
//For holopads only. Usable by AI.
/mob/living/silicon/ai/proc/holopad_talk(message)
/mob/living/silicon/ai/proc/holopad_talk(message, language)
log_say("[key_name(src)] : [message]")
message = trim(message)
@@ -49,20 +49,15 @@
var/obj/machinery/holopad/T = current
if(istype(T) && T.masters[src])//If there is a hologram and its master is the user.
send_speech(message, 7, T, "robot", get_spans())
send_speech(message, 7, T, "robot", get_spans(), language)
to_chat(src, "<i><span class='game say'>Holopad transmitted, <span class='name'>[real_name]</span> <span class='message robot'>\"[message]\"</span></span></i>")
else
to_chat(src, "No holopad connected.")
return
// Make sure that the code compiles with AI_VOX undefined
#ifdef AI_VOX
var/announcing_vox = 0 // Stores the time of the last announcement
var/const/VOX_CHANNEL = 200
var/const/VOX_DELAY = 600
#define VOX_DELAY 600
/mob/living/silicon/ai/verb/announcement_help()
set name = "Announcement Help"
@@ -79,10 +74,10 @@ var/const/VOX_DELAY = 600
<font class='bad'>WARNING:</font><BR>Misuse of the announcement system will get you job banned.<HR>"
var/index = 0
for(var/word in vox_sounds)
for(var/word in GLOB.vox_sounds)
index++
dat += "<A href='?src=\ref[src];say_word=[word]'>[capitalize(word)]</A>"
if(index != vox_sounds.len)
if(index != GLOB.vox_sounds.len)
dat += " / "
var/datum/browser/popup = new(src, "announce_help", "Announcement Help", 500, 400)
@@ -91,6 +86,7 @@ var/const/VOX_DELAY = 600
/mob/living/silicon/ai/proc/announcement()
var/static/announcing_vox = 0 // Stores the time of the last announcement
if(announcing_vox > world.time)
to_chat(src, "<span class='notice'>Please wait [round((announcing_vox - world.time) / 10)] seconds.</span>")
return
@@ -120,7 +116,7 @@ var/const/VOX_DELAY = 600
if(!word)
words -= word
continue
if(!vox_sounds[word])
if(!GLOB.vox_sounds[word])
incorrect_words += word
if(incorrect_words.len)
@@ -147,16 +143,16 @@ var/const/VOX_DELAY = 600
word = lowertext(word)
if(vox_sounds[word])
if(GLOB.vox_sounds[word])
var/sound_file = vox_sounds[word]
var/sound/voice = sound(sound_file, wait = 1, channel = VOX_CHANNEL)
var/sound_file = GLOB.vox_sounds[word]
var/sound/voice = sound(sound_file, wait = 1, channel = CHANNEL_VOX)
voice.status = SOUND_STREAM
// If there is no single listener, broadcast to everyone in the same z level
if(!only_listener)
// Play voice for all mobs in the z level
for(var/mob/M in player_list)
for(var/mob/M in GLOB.player_list)
if(M.client && !M.ear_deaf && (M.client.prefs.toggles & SOUND_ANNOUNCEMENTS))
var/turf/T = get_turf(M)
if(T.z == z_level)
@@ -167,3 +163,12 @@ var/const/VOX_DELAY = 600
return 0
#endif
/mob/living/silicon/ai/can_speak_in_language(datum/language/dt)
if(HAS_SECONDARY_FLAG(src, OMNITONGUE))
. = has_language(dt)
else if(is_servant_of_ratvar(src))
// Ratvarian AIs can only speak Ratvarian
. = ispath(dt, /datum/language/ratvar) && has_language(dt)
else
. = ..()
@@ -2,7 +2,7 @@
// Dynamically loading it has bad results with sounds overtaking each other, even with the wait variable.
#ifdef AI_VOX
var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg',
GLOBAL_LIST_INIT(vox_sounds, list("," = 'sound/vox_fem/,.ogg',
"." = 'sound/vox_fem/..ogg',
"a" = 'sound/vox_fem/a.ogg',
"abortions" = 'sound/vox_fem/abortions.ogg',
@@ -713,6 +713,5 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg',
"z" = 'sound/vox_fem/z.ogg',
"zero" = 'sound/vox_fem/zero.ogg',
"zone" = 'sound/vox_fem/zone.ogg',
"zulu" = 'sound/vox_fem/zulu.ogg',
)
"zulu" = 'sound/vox_fem/zulu.ogg'))
#endif
+4 -4
View File
@@ -1,6 +1,6 @@
/mob/living/silicon/Login()
if(mind && ticker && ticker.mode)
ticker.mode.remove_cultist(mind, 0, 0)
ticker.mode.remove_revolutionary(mind, 0)
ticker.mode.remove_gangster(mind, remove_bosses=1)
if(mind && SSticker && SSticker.mode)
SSticker.mode.remove_cultist(mind, 0, 0)
SSticker.mode.remove_revolutionary(mind, 0)
SSticker.mode.remove_gangster(mind, remove_bosses=1)
..()
+3 -1
View File
@@ -4,10 +4,12 @@
stat = DEAD
canmove = 0
card.removePersonality()
if(holoform)
card.forceMove(loc)
update_sight()
clear_fullscreens()
//New pAI's get a brand new mind to prevent meta stuff from their previous life. This new mind causes problems down the line if it's not deleted here.
living_mob_list -= src
GLOB.living_mob_list -= src
ghostize()
qdel(src)
+5 -2
View File
@@ -78,13 +78,13 @@
. += slowdown
/mob/living/silicon/pai/Destroy()
pai_list -= src
GLOB.pai_list -= src
..()
/mob/living/silicon/pai/Initialize()
var/obj/item/device/paicard/P = loc
START_PROCESSING(SSfastprocess, src)
pai_list += src
GLOB.pai_list += src
make_laws()
canmove = 0
if(!istype(P)) //when manually spawning a pai, we create a card to put it into.
@@ -110,10 +110,13 @@
var/datum/action/innate/pai/chassis/AC = new /datum/action/innate/pai/chassis
var/datum/action/innate/pai/rest/AR = new /datum/action/innate/pai/rest
var/datum/action/innate/pai/light/AL = new /datum/action/innate/pai/light
var/datum/action/language_menu/ALM = new
AS.Grant(src)
AC.Grant(src)
AR.Grant(src)
AL.Grant(src)
ALM.Grant(src)
emittersemicd = TRUE
addtimer(CALLBACK(src, .proc/emittercool), 600)
@@ -102,4 +102,4 @@
/mob/living/silicon/pai/movement_delay()
. = ..()
. += 1 //A bit slower than humans, so they're easier to smash
. += 1 //A bit slower than humans, so they're easier to smash
+26 -26
View File
@@ -33,7 +33,7 @@
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>"
left_part = "<b><font color=red>RrR a Rro</font></b>"
right_part = "<pre>Program index hash not found</pre>"
else
@@ -220,18 +220,18 @@
// Accessing medical records
if("medicalrecord")
if(subscreen == 1)
medicalActive1 = find_record("id", href_list["med_rec"], data_core.general)
medicalActive1 = find_record("id", href_list["med_rec"], GLOB.data_core.general)
if(medicalActive1)
medicalActive2 = find_record("id", href_list["med_rec"], data_core.medical)
medicalActive2 = find_record("id", href_list["med_rec"], GLOB.data_core.medical)
if(!medicalActive2)
medicalActive1 = null
temp = "Unable to locate requested security record. Record may have been deleted, or never have existed."
if("securityrecord")
if(subscreen == 1)
securityActive1 = find_record("id", href_list["sec_rec"], data_core.general)
securityActive1 = find_record("id", href_list["sec_rec"], GLOB.data_core.general)
if(securityActive1)
securityActive2 = find_record("id", href_list["sec_rec"], data_core.security)
securityActive2 = find_record("id", href_list["sec_rec"], GLOB.data_core.security)
if(!securityActive2)
securityActive1 = null
temp = "Unable to locate requested security record. Record may have been deleted, or never have existed."
@@ -241,7 +241,7 @@
if(secHUD)
add_sec_hud()
else
var/datum/atom_hud/sec = huds[sec_hud]
var/datum/atom_hud/sec = GLOB.huds[sec_hud]
sec.remove_hud_from(src)
if("medicalhud")
if(href_list["toggle"])
@@ -249,13 +249,13 @@
if(medHUD)
add_med_hud()
else
var/datum/atom_hud/med = huds[med_hud]
var/datum/atom_hud/med = GLOB.huds[med_hud]
med.remove_hud_from(src)
if("translator")
if(href_list["toggle"])
var/on_already = ((languages_understood == ALL) && (languages_spoken == ALL))
languages_spoken = on_already ? (HUMAN | ROBOT) : ALL
languages_understood = on_already ? (HUMAN | ROBOT) : ALL
if(!HAS_SECONDARY_FLAG(src, OMNITONGUE))
grant_all_languages(TRUE)
// this is PERMAMENT.
if("doorjack")
if(href_list["jack"])
if(src.cable && src.cable.machine)
@@ -313,7 +313,8 @@
if(s == "medical HUD")
dat += "<a href='byond://?src=\ref[src];software=medicalhud;sub=0'>Medical Analysis Suite</a>[(src.medHUD) ? "<font color=#55FF55> On</font>" : "<font color=#FF5555> Off</font>"] <br>"
if(s == "universal translator")
dat += "<a href='byond://?src=\ref[src];software=translator;sub=0'>Universal Translator</a>[((languages_spoken == ALL) && (languages_understood == ALL)) ? "<font color=#55FF55> On</font>" : "<font color=#FF5555> Off</font>"] <br>"
var/translator_on = HAS_SECONDARY_FLAG(src, OMNITONGUE)
dat += "<a href='byond://?src=\ref[src];software=translator;sub=0'>Universal Translator</a>[translator_on ? "<font color=#55FF55> On</font>" : "<font color=#FF5555> Off</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")
@@ -413,8 +414,8 @@
// Crew Manifest
/mob/living/silicon/pai/proc/softwareManifest()
. += "<h2>Crew Manifest</h2><br><br>"
if(data_core.general)
for(var/datum/data/record/t in sortRecord(data_core.general))
if(GLOB.data_core.general)
for(var/datum/data/record/t in sortRecord(GLOB.data_core.general))
. += "[t.fields["name"]] - [t.fields["rank"]]<BR>"
. += "</body></html>"
return .
@@ -424,16 +425,16 @@
switch(subscreen)
if(0)
. += "<h3>Medical Records</h3><HR>"
if(data_core.general)
for(var/datum/data/record/R in sortRecord(data_core.general))
if(GLOB.data_core.general)
for(var/datum/data/record/R in sortRecord(GLOB.data_core.general))
. += "<A href='?src=\ref[src];med_rec=[R.fields["id"]];software=medicalrecord;sub=1'>[R.fields["id"]]: [R.fields["name"]]<BR>"
if(1)
. += "<CENTER><B>Medical Record</B></CENTER><BR>"
if(medicalActive1 in data_core.general)
if(medicalActive1 in GLOB.data_core.general)
. += "Name: [medicalActive1.fields["name"]] ID: [medicalActive1.fields["id"]]<BR>\nSex: [medicalActive1.fields["sex"]]<BR>\nAge: [medicalActive1.fields["age"]]<BR>\nFingerprint: [medicalActive1.fields["fingerprint"]]<BR>\nPhysical Status: [medicalActive1.fields["p_stat"]]<BR>\nMental Status: [medicalActive1.fields["m_stat"]]<BR>"
else
. += "<pre>Requested medical record not found.</pre><BR>"
if(medicalActive2 in data_core.medical)
if(medicalActive2 in GLOB.data_core.medical)
. += "<BR>\n<CENTER><B>Medical Data</B></CENTER><BR>\nBlood Type: <A href='?src=\ref[src];field=blood_type'>[medicalActive2.fields["blood_type"]]</A><BR>\nDNA: <A href='?src=\ref[src];field=b_dna'>[medicalActive2.fields["b_dna"]]</A><BR>\n<BR>\nMinor Disabilities: <A href='?src=\ref[src];field=mi_dis'>[medicalActive2.fields["mi_dis"]]</A><BR>\nDetails: <A href='?src=\ref[src];field=mi_dis_d'>[medicalActive2.fields["mi_dis_d"]]</A><BR>\n<BR>\nMajor Disabilities: <A href='?src=\ref[src];field=ma_dis'>[medicalActive2.fields["ma_dis"]]</A><BR>\nDetails: <A href='?src=\ref[src];field=ma_dis_d'>[medicalActive2.fields["ma_dis_d"]]</A><BR>\n<BR>\nAllergies: <A href='?src=\ref[src];field=alg'>[medicalActive2.fields["alg"]]</A><BR>\nDetails: <A href='?src=\ref[src];field=alg_d'>[medicalActive2.fields["alg_d"]]</A><BR>\n<BR>\nCurrent Diseases: <A href='?src=\ref[src];field=cdi'>[medicalActive2.fields["cdi"]]</A> (per disease info placed in log/comment section)<BR>\nDetails: <A href='?src=\ref[src];field=cdi_d'>[medicalActive2.fields["cdi_d"]]</A><BR>\n<BR>\nImportant Notes:<BR>\n\t<A href='?src=\ref[src];field=notes'>[medicalActive2.fields["notes"]]</A><BR>\n<BR>\n<CENTER><B>Comments/Log</B></CENTER><BR>"
else
. += "<pre>Requested medical record not found.</pre><BR>"
@@ -446,16 +447,16 @@
switch(subscreen)
if(0)
. += "<h3>Security Records</h3><HR>"
if(data_core.general)
for(var/datum/data/record/R in sortRecord(data_core.general))
if(GLOB.data_core.general)
for(var/datum/data/record/R in sortRecord(GLOB.data_core.general))
. += "<A href='?src=\ref[src];sec_rec=[R.fields["id"]];software=securityrecord;sub=1'>[R.fields["id"]]: [R.fields["name"]]<BR>"
if(1)
. += "<h3>Security Record</h3>"
if(securityActive1 in data_core.general)
if(securityActive1 in GLOB.data_core.general)
. += "Name: <A href='?src=\ref[src];field=name'>[securityActive1.fields["name"]]</A> ID: <A href='?src=\ref[src];field=id'>[securityActive1.fields["id"]]</A><BR>\nSex: <A href='?src=\ref[src];field=sex'>[securityActive1.fields["sex"]]</A><BR>\nAge: <A href='?src=\ref[src];field=age'>[securityActive1.fields["age"]]</A><BR>\nRank: <A href='?src=\ref[src];field=rank'>[securityActive1.fields["rank"]]</A><BR>\nFingerprint: <A href='?src=\ref[src];field=fingerprint'>[securityActive1.fields["fingerprint"]]</A><BR>\nPhysical Status: [securityActive1.fields["p_stat"]]<BR>\nMental Status: [securityActive1.fields["m_stat"]]<BR>"
else
. += "<pre>Requested security record not found,</pre><BR>"
if(securityActive2 in data_core.security)
if(securityActive2 in GLOB.data_core.security)
. += "<BR>\nSecurity Data<BR>\nCriminal Status: [securityActive2.fields["criminal"]]<BR>\n<BR>\nMinor Crimes: <A href='?src=\ref[src];field=mi_crim'>[securityActive2.fields["mi_crim"]]</A><BR>\nDetails: <A href='?src=\ref[src];field=mi_crim_d'>[securityActive2.fields["mi_crim_d"]]</A><BR>\n<BR>\nMajor Crimes: <A href='?src=\ref[src];field=ma_crim'>[securityActive2.fields["ma_crim"]]</A><BR>\nDetails: <A href='?src=\ref[src];field=ma_crim_d'>[securityActive2.fields["ma_crim_d"]]</A><BR>\n<BR>\nImportant Notes:<BR>\n\t<A href='?src=\ref[src];field=notes'>[securityActive2.fields["notes"]]</A><BR>\n<BR>\n<CENTER><B>Comments/Log</B></CENTER><BR>"
else
. += "<pre>Requested security record not found,</pre><BR>"
@@ -464,11 +465,10 @@
// Universal Translator
/mob/living/silicon/pai/proc/softwareTranslator()
var/translator_on = HAS_SECONDARY_FLAG(src, OMNITONGUE)
. = {"<h3>Universal Translator</h3><br>
When enabled, this device will automatically convert all spoken and written language into a format that any known recipient can understand.<br><br>
The device is currently [ ((languages_spoken == ALL) && (languages_understood == ALL)) ? "<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>
"}
When enabled, this device will permamently be able to speak and understand all known forms of communication.<br><br>
The device is currently [translator_on ? "<font color=#55FF55>en" : "<font color=#FF5555>dis" ]abled.</font><br>[translator_on ? "" : "<a href='byond://?src=\ref[src];software=translator;sub=0;toggle=1'>Activate Translation Module</a><br>"]"}
return .
// Security HUD
@@ -599,7 +599,7 @@
// Door Jack - supporting proc
/mob/living/silicon/pai/proc/hackloop()
var/turf/T = get_turf(src.loc)
for(var/mob/living/silicon/ai/AI in player_list)
for(var/mob/living/silicon/ai/AI in GLOB.player_list)
if(T.loc)
to_chat(AI, "<font color = red><b>Network Alert: Brute-force encryption crack in progress in [T.loc].</b></font>")
else
@@ -36,9 +36,11 @@
if(is_servant_of_ratvar(src) && user.Adjacent(src) && !stat) //To counter pseudo-stealth by using headlamps
msg += "<span class='warning'>Its eyes are glowing a blazing yellow!</span>\n"
switch(src.stat)
switch(stat)
if(CONSCIOUS)
if(!src.client)
if(shell)
msg += "It appears to be an [deployed ? "active" : "empty"] AI shell.\n"
else if(!client)
msg += "It appears to be in stand-by mode.\n" //afk
if(UNCONSCIOUS)
msg += "<span class='warning'>It doesn't seem to be responding.</span>\n"
@@ -32,7 +32,9 @@
to_chat(who, "<b>Obey these laws:</b>")
laws.show_laws(who)
if (is_special_character(src) && connected_ai)
if (shell) //AI shell
to_chat(who, "<b>Remember, you are an AI remotely controlling your shell, other AIs can be ignored.</b>")
else if (is_special_character(src) && connected_ai)
to_chat(who, "<b>Remember, [connected_ai.name] is technically your master, but your objective comes first.</b>")
else if (connected_ai)
to_chat(who, "<b>Remember, [connected_ai.name] is your master, other AIs can be ignored.</b>")
@@ -37,8 +37,8 @@
update_cell_hud_icon()
if(syndicate)
if(ticker.mode.name == "traitor")
for(var/datum/mind/tra in ticker.mode.traitors)
if(SSticker.mode.name == "traitor")
for(var/datum/mind/tra in SSticker.mode.traitors)
if(tra.current)
var/I = image('icons/mob/mob.dmi', loc = tra.current, icon_state = "traitor") //no traitor sprite in that dmi!
src.client.images += I
@@ -48,7 +48,7 @@
if(mind)
if(!mind.special_role)
mind.special_role = "traitor"
ticker.mode.traitors += mind
SSticker.mode.traitors += mind
/mob/living/silicon/robot/update_health_hud()
@@ -4,5 +4,5 @@
regenerate_icons()
show_laws(0)
if(mind)
ticker.mode.remove_revolutionary(mind)
ticker.mode.remove_gangster(mind,1,remove_bosses=1)
SSticker.mode.remove_revolutionary(mind)
SSticker.mode.remove_gangster(mind,1,remove_bosses=1)
+136 -45
View File
@@ -16,6 +16,10 @@
var/obj/item/robot_suit/robot_suit = null //Used for deconstruction to remember what the borg was constructed out of..
var/obj/item/device/mmi/mmi = null
var/shell = FALSE
var/deployed = FALSE
var/mob/living/silicon/ai/mainframe = null
var/datum/action/innate/undeployment/undeployment_action = new
//Hud stuff
@@ -47,7 +51,7 @@
var/ident = 0
var/locked = 1
var/list/req_access = list(access_robotics)
var/list/req_access = list(GLOB.access_robotics)
var/alarms = list("Motion"=list(), "Fire"=list(), "Atmosphere"=list(), "Power"=list(), "Camera"=list(), "Burglar"=list())
@@ -73,7 +77,7 @@
var/sight_mode = 0
var/updating = 0 //portable camera camerachunk update
hud_possible = list(ANTAG_HUD, DIAG_STAT_HUD, DIAG_HUD, DIAG_BATT_HUD)
hud_possible = list(ANTAG_HUD, DIAG_STAT_HUD, DIAG_HUD, DIAG_BATT_HUD, DIAG_TRACK_HUD)
var/list/upgrades = list()
@@ -129,8 +133,12 @@
update_icons()
..()
//If this body is meant to be a borg controlled by the AI player
if(shell)
make_shell()
//MMI stuff. Held togheter by magic. ~Miauw
if(!mmi || !mmi.brainmob)
else if(!mmi || !mmi.brainmob)
mmi = new (src)
mmi.brain = new /obj/item/organ/brain(mmi)
mmi.brain.name = "[real_name]'s brain"
@@ -159,8 +167,8 @@
if(mmi.brainmob)
if(mmi.brainmob.stat == DEAD)
mmi.brainmob.stat = CONSCIOUS
dead_mob_list -= mmi.brainmob
living_mob_list += mmi.brainmob
GLOB.dead_mob_list -= mmi.brainmob
GLOB.living_mob_list += mmi.brainmob
mind.transfer_to(mmi.brainmob)
mmi.update_icon()
else
@@ -170,6 +178,8 @@
mmi = null
if(connected_ai)
connected_ai.connected_robots -= src
if(shell)
GLOB.available_ai_shells -= src
qdel(wires)
qdel(module)
qdel(eye_lights)
@@ -204,6 +214,8 @@
/mob/living/silicon/robot/proc/updatename()
if(shell)
return
var/changed_name = ""
if(custom_name)
changed_name = custom_name
@@ -424,7 +436,9 @@
update_icons()
else if(istype(W, /obj/item/weapon/screwdriver) && opened && cell) // radio
if(radio)
if(shell)
to_chat(user, "You cannot seem to open the radio compartment") //Prevent AI radio key theft
else if(radio)
radio.attackby(W,user)//Push it to the radio to let it handle everything
else
to_chat(user, "<span class='warning'>Unable to locate a radio!</span>")
@@ -453,6 +467,9 @@
if(!cell)
to_chat(user, "<span class='warning'>You need to install a power cell to do that!</span>")
return
if(shell) //AI shells always have the laws of the AI
to_chat(user, "<span class='warning'>[src] is controlled remotely! You cannot upload new laws this way!</span>")
return
if(emagged || (connected_ai && lawupdate)) //Can't be sure which, metagamers
emote("buzz-[user.name]")
return
@@ -594,7 +611,7 @@
/mob/living/silicon/robot/proc/do_camera_update(oldLoc)
if(oldLoc != src.loc)
cameranet.updatePortableCamera(src.camera)
GLOB.cameranet.updatePortableCamera(src.camera)
updating = 0
/mob/living/silicon/robot/Move(a, b, flag)
@@ -606,36 +623,6 @@
updating = 1
addtimer(CALLBACK(src, .proc/do_camera_update, oldLoc), BORG_CAMERA_BUFFER)
if(module)
if(istype(module, /obj/item/weapon/robot_module/janitor))
var/turf/tile = loc
if(isturf(tile))
tile.clean_blood()
for(var/A in tile)
if(is_cleanable(A))
qdel(A)
else if(istype(A, /obj/item))
var/obj/item/cleaned_item = A
cleaned_item.clean_blood()
else if(ishuman(A))
var/mob/living/carbon/human/cleaned_human = A
if(cleaned_human.lying)
if(cleaned_human.head)
cleaned_human.head.clean_blood()
cleaned_human.update_inv_head()
if(cleaned_human.wear_suit)
cleaned_human.wear_suit.clean_blood()
cleaned_human.update_inv_wear_suit()
else if(cleaned_human.w_uniform)
cleaned_human.w_uniform.clean_blood()
cleaned_human.update_inv_w_uniform()
if(cleaned_human.shoes)
cleaned_human.shoes.clean_blood()
cleaned_human.update_inv_shoes()
cleaned_human.clean_blood()
cleaned_human.wash_cream()
to_chat(cleaned_human, "<span class='danger'>[src] cleans your face!</span>")
return
if(istype(module, /obj/item/weapon/robot_module/miner))
if(istype(loc, /turf/open/floor/plating/asteroid))
for(var/obj/item/I in held_items)
@@ -806,7 +793,7 @@
icon_state = "syndie_bloodhound"
faction = list("syndicate")
bubble_icon = "syndibot"
req_access = list(access_syndicate)
req_access = list(GLOB.access_syndicate)
lawupdate = FALSE
scrambledcodes = TRUE // These are rogue borgs.
ionpulse = TRUE
@@ -829,6 +816,9 @@
if(playstyle_string)
to_chat(src, playstyle_string)
/mob/living/silicon/robot/syndicate/ResetModule()
return
/mob/living/silicon/robot/syndicate/medical
icon_state = "syndi-medi"
playstyle_string = "<span class='userdanger'>You are a Syndicate medical cyborg!</span><br>\
@@ -843,12 +833,14 @@
if(!connected_ai)
return
switch(notifytype)
if(1) //New Cyborg
if(NEW_BORG) //New Cyborg
to_chat(connected_ai, "<br><br><span class='notice'>NOTICE - New cyborg connection detected: <a href='?src=\ref[connected_ai];track=[html_encode(name)]'>[name]</a></span><br>")
if(2) //New Module
if(NEW_MODULE) //New Module
to_chat(connected_ai, "<br><br><span class='notice'>NOTICE - Cyborg module change detected: [name] has loaded the [designation] module.</span><br>")
if(3) //New Name
if(RENAME) //New Name
to_chat(connected_ai, "<br><br><span class='notice'>NOTICE - Cyborg reclassification detected: [oldname] is now designated as [newname].</span><br>")
if(AI_SHELL) //New Shell
to_chat(connected_ai, "<br><br><span class='notice'>NOTICE - New cyborg shell detected: <a href='?src=\ref[connected_ai];track=[html_encode(name)]'>[name]</a></span><br>")
/mob/living/silicon/robot/canUseTopic(atom/movable/M, be_close = 0)
if(stat || lockcharge || low_power_mode)
@@ -889,12 +881,12 @@
if(sight_mode & BORGMESON)
sight |= SEE_TURFS
see_invisible = min(see_invisible, SEE_INVISIBLE_MINIMUM)
lighting_alpha = LIGHTING_PLANE_ALPHA_INVISIBLE
see_in_dark = 1
if(sight_mode & BORGMATERIAL)
sight |= SEE_OBJS
see_invisible = min(see_invisible, SEE_INVISIBLE_MINIMUM)
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
see_in_dark = 1
if(sight_mode & BORGXRAY)
@@ -909,6 +901,7 @@
if(see_override)
see_invisible = see_override
sync_lighting_plane_alpha()
/mob/living/silicon/robot/update_stat()
if(status_flags & GODMODE)
@@ -931,6 +924,7 @@
update_headlamp()
diag_hud_set_status()
diag_hud_set_health()
diag_hud_set_aishell()
update_health_hud()
/mob/living/silicon/robot/revive(full_heal = 0, admin_revive = 0)
@@ -940,13 +934,13 @@
update_headlamp()
if(admin_revive)
locked = 1
notify_ai(1)
notify_ai(NEW_BORG)
. = 1
/mob/living/silicon/robot/fully_replace_character_name(oldname, newname)
..()
if(oldname != real_name)
notify_ai(3, oldname, newname)
notify_ai(RENAME, oldname, newname)
if(camera)
camera.c_tag = real_name
custom_name = newname
@@ -967,6 +961,7 @@
speed = 0
ionpulse = FALSE
revert_shell()
return 1
@@ -985,6 +980,11 @@
else
status_flags &= ~CANPUSH
if(module.clean_on_move)
flags |= CLEAN_ON_MOVE
else
flags &= ~CLEAN_ON_MOVE
hat_offset = module.hat_offset
magpulse = module.magpulsing
@@ -998,6 +998,97 @@
new_hat.forceMove(src)
update_icons()
/mob/living/silicon/robot/proc/make_shell(var/obj/item/borg/upgrade/ai/board)
if(!board)
upgrades |= new /obj/item/borg/upgrade/ai(src)
shell = TRUE
braintype = "AI Shell"
name = "[designation] AI Shell [rand(100,999)]"
real_name = name
GLOB.available_ai_shells |= src
if(camera)
camera.c_tag = real_name //update the camera name too
diag_hud_set_aishell()
notify_ai(AI_SHELL)
/mob/living/silicon/robot/proc/revert_shell()
if(!shell)
return
undeploy()
for(var/obj/item/borg/upgrade/ai/boris in src)
//A player forced reset of a borg would drop the module before this is called, so this is for catching edge cases
qdel(boris)
shell = FALSE
GLOB.available_ai_shells -= src
name = "Unformatted Cyborg [rand(100,999)]"
real_name = name
if(camera)
camera.c_tag = real_name
diag_hud_set_aishell()
/mob/living/silicon/robot/proc/deploy_init(var/mob/living/silicon/ai/AI)
real_name = "[AI.real_name] shell [rand(100, 999)] - [designation]" //Randomizing the name so it shows up seperately in the shells list
name = real_name
if(camera)
camera.c_tag = real_name //update the camera name too
mainframe = AI
deployed = TRUE
connected_ai = mainframe
mainframe.connected_robots |= src
lawupdate = TRUE
lawsync()
if(radio && AI.radio) //AI keeps all channels, including Syndie if it is a Traitor
if(AI.radio.syndie)
radio.make_syndie()
radio.subspace_transmission = TRUE
radio.channels = AI.radio.channels
for(var/chan in radio.channels)
radio.secure_radio_connections[chan] = add_radio(radio, GLOB.radiochannels[chan])
diag_hud_set_aishell()
undeployment_action.Grant(src)
/datum/action/innate/undeployment
name = "Disconnect from shell"
desc = "Stop controlling your shell and resume normal core operations."
button_icon_state = "ai_core"
/datum/action/innate/undeployment/Trigger()
if(!..())
return FALSE
var/mob/living/silicon/robot/R = owner
R.undeploy()
return TRUE
/mob/living/silicon/robot/proc/undeploy()
if(!deployed || !mind || !mainframe)
return
mainframe.redeploy_action.Grant(mainframe)
mainframe.redeploy_action.last_used_shell = src
mind.transfer_to(mainframe)
deployed = FALSE
mainframe.deployed_shell = null
undeployment_action.Remove(src)
if(radio) //Return radio to normal
radio.recalculateChannels()
if(camera)
camera.c_tag = real_name //update the camera name too
diag_hud_set_aishell()
mainframe.diag_hud_set_deployed()
mainframe.show_laws() //Always remind the AI when switching
mainframe = null
/mob/living/silicon/robot/attack_ai(mob/user)
if(shell && (!connected_ai || connected_ai == user))
var/mob/living/silicon/ai/AI = user
AI.deploy_to_shell(src)
/mob/living/silicon/robot/shell
shell = TRUE
/mob/living/silicon/robot/MouseDrop_T(mob/living/M, mob/living/user)
. = ..()
if(!(M in buckled_mobs) && isliving(M))
@@ -16,11 +16,12 @@
if (M.a_intent == INTENT_DISARM)
if(!(lying))
M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
if(get_active_held_item())
var/obj/item/I = get_active_held_item()
if(I)
uneq_active()
visible_message("<span class='danger'>[M] disarmed [src]!</span>", \
"<span class='userdanger'>[M] has disabled [src]'s active module!</span>", null, COMBAT_MESSAGE_RANGE)
add_logs(M, src, "disarmed")
add_logs(M, src, "disarmed", "[I ? " removing \the [I]" : ""]")
else
Stun(2)
step(src,get_dir(M,src))
@@ -92,6 +93,8 @@
if(locked)
to_chat(user, "<span class='notice'>You emag the cover lock.</span>")
locked = 0
if(shell) //A warning to Traitors who may not know that emagging AI shells does not slave them.
to_chat(user, "<span class='boldwarning'>[src] seems to be controlled remotely! Emagging the interface may not work as expected.</span>")
else
to_chat(user, "<span class='warning'>The cover is already unlocked!</span>")
return
@@ -125,6 +128,12 @@
log_game("[key_name(user)] attempted to emag cyborg [key_name(src)], but they were slaved to traitor AI [connected_ai].")
return
if(shell) //AI shells cannot be emagged, so we try to make it look like a standard reset. Smart players may see through this, however.
to_chat(user, "<span class='danger'>[src] is remotely controlled! Your emag attempt has triggered a system reset instead!</span>")
log_game("[key_name(user)] attempted to emag an AI shell belonging to [key_name(src) ? key_name(src) : connected_ai]. The shell has been reset as a result.")
ResetModule()
return
SetEmagged(1)
SetStunned(3) //Borgs were getting into trouble because they would attack the emagger before the new laws were shown
lawupdate = 0
@@ -132,7 +141,7 @@
message_admins("[key_name_admin(user)] emagged cyborg [key_name_admin(src)]. Laws overridden.")
log_game("[key_name(user)] emagged cyborg [key_name(src)]. Laws overridden.")
var/time = time2text(world.realtime,"hh:mm:ss")
lawchanges.Add("[time] <B>:</B> [user.name]([user.key]) emagged [name]([key])")
GLOB.lawchanges.Add("[time] <B>:</B> [user.name]([user.key]) emagged [name]([key])")
to_chat(src, "<span class='danger'>ALERT: Foreign software detected.</span>")
sleep(5)
to_chat(src, "<span class='danger'>Initiating diagnostics...</span>")
@@ -20,6 +20,7 @@
var/can_be_pushed = TRUE
var/magpulsing = FALSE
var/clean_on_move = FALSE
var/did_feedback = FALSE
var/feedback_key
@@ -217,7 +218,7 @@
R.SetLockdown(0)
R.anchored = FALSE
R.notransform = FALSE
R.notify_ai(2)
R.notify_ai(NEW_MODULE)
if(R.hud_used)
R.hud_used.update_robot_modules_display()
if(feedback_key && !did_feedback)
@@ -228,8 +229,17 @@
basic_modules = list(
/obj/item/device/assembly/flash/cyborg,
/obj/item/weapon/reagent_containers/borghypo/epi,
/obj/item/device/healthanalyzer,
/obj/item/weapon/weldingtool/largetank/cyborg,
/obj/item/weapon/wrench/cyborg,
/obj/item/weapon/crowbar/cyborg,
/obj/item/stack/sheet/metal/cyborg,
/obj/item/stack/rods/cyborg,
/obj/item/stack/tile/plasteel/cyborg,
/obj/item/weapon/extinguisher,
/obj/item/weapon/pickaxe,
/obj/item/device/t_scanner/adv_mining_scanner,
/obj/item/weapon/restraints/handcuffs/cable/zipties/cyborg,
/obj/item/weapon/soap/nanotrasen,
/obj/item/borg/cyborghug)
emag_modules = list(/obj/item/weapon/melee/energy/sword/cyborg)
@@ -382,6 +392,7 @@
moduleselect_icon = "janitor"
feedback_key = "cyborg_janitor"
hat_offset = -5
clean_on_move = TRUE
/obj/item/weapon/reagent_containers/spray/cyborg_drying
name = "drying agent spray"
+5 -5
View File
@@ -10,7 +10,7 @@
desig = trim_left(S.designation + " " + S.job)
var/message_a = say_quote(message, get_spans())
var/rendered = "<i><span class='game say'>Robotic Talk, <span class='name'>[name]</span> <span class='message'>[message_a]</span></span></i>"
for(var/mob/M in player_list)
for(var/mob/M in GLOB.player_list)
if(M.binarycheck())
if(isAI(M))
var/renderedAI = "<i><span class='game say'>Robotic Talk, <a href='?src=\ref[M];track=[html_encode(name)]'><span class='name'>[name] ([desig])</span></a> <span class='message'>[message_a]</span></span></i>"
@@ -33,19 +33,19 @@
/mob/living/silicon/lingcheck()
return 0 //Borged or AI'd lings can't speak on the ling channel.
/mob/living/silicon/radio(message, message_mode, list/spans)
/mob/living/silicon/radio(message, message_mode, list/spans, language)
. = ..()
if(. != 0)
return .
if(message_mode == "robot")
if (radio)
radio.talk_into(src, message, , spans)
radio.talk_into(src, message, , spans, language)
return REDUCE_RANGE
else if(message_mode in radiochannels)
else if(message_mode in GLOB.radiochannels)
if(radio)
radio.talk_into(src, message, message_mode, spans)
radio.talk_into(src, message, message_mode, spans, language)
return ITALICS | REDUCE_RANGE
return 0
+13 -15
View File
@@ -1,13 +1,12 @@
/mob/living/silicon
gender = NEUTER
voice_name = "synthesized voice"
languages_spoken = ROBOT | HUMAN
languages_understood = ROBOT | HUMAN
has_unlimited_silicon_privilege = 1
verb_say = "states"
verb_ask = "queries"
verb_exclaim = "declares"
verb_yell = "alarms"
initial_languages = list(/datum/language/common, /datum/language/machine)
see_in_dark = 8
bubble_icon = "machine"
weather_immunities = list("ash")
@@ -21,8 +20,7 @@
var/designation = ""
var/radiomod = "" //Radio character used before state laws/arrivals announce to allow department transmissions, default, or none at all.
var/obj/item/device/camera/siliconcam/aicamera = null //photography
//hud_possible = list(DIAG_STAT_HUD, DIAG_HUD, ANTAG_HUD)
hud_possible = list(ANTAG_HUD, DIAG_STAT_HUD, DIAG_HUD)
hud_possible = list(ANTAG_HUD, DIAG_STAT_HUD, DIAG_HUD, DIAG_TRACK_HUD)
var/obj/item/device/radio/borg/radio = null //AIs dont use this but this is at the silicon level to advoid copypasta in say()
@@ -41,8 +39,8 @@
/mob/living/silicon/Initialize()
..()
silicon_mobs += src
var/datum/atom_hud/data/diagnostic/diag_hud = huds[DATA_HUD_DIAGNOSTIC]
GLOB.silicon_mobs += src
var/datum/atom_hud/data/diagnostic/diag_hud = GLOB.huds[DATA_HUD_DIAGNOSTIC]
diag_hud.add_to_hud(src)
diag_hud_set_status()
diag_hud_set_health()
@@ -56,7 +54,7 @@
/mob/living/silicon/Destroy()
radio = null
aicamera = null
silicon_mobs -= src
GLOB.silicon_mobs -= src
return ..()
/mob/living/silicon/contents_explosion(severity, target)
@@ -307,8 +305,8 @@
else if(Autochan == "None") //Prevents use of the radio for automatic annoucements.
radiomod = ""
else //For department channels, if any, given by the internal radio.
for(var/key in department_radio_keys)
if(department_radio_keys[key] == Autochan)
for(var/key in GLOB.department_radio_keys)
if(GLOB.department_radio_keys[key] == Autochan)
radiomod = key
break
@@ -327,23 +325,23 @@
return -10
/mob/living/silicon/proc/remove_med_sec_hud()
var/datum/atom_hud/secsensor = huds[sec_hud]
var/datum/atom_hud/medsensor = huds[med_hud]
var/datum/atom_hud/diagsensor = huds[d_hud]
var/datum/atom_hud/secsensor = GLOB.huds[sec_hud]
var/datum/atom_hud/medsensor = GLOB.huds[med_hud]
var/datum/atom_hud/diagsensor = GLOB.huds[d_hud]
secsensor.remove_hud_from(src)
medsensor.remove_hud_from(src)
diagsensor.remove_hud_from(src)
/mob/living/silicon/proc/add_sec_hud()
var/datum/atom_hud/secsensor = huds[sec_hud]
var/datum/atom_hud/secsensor = GLOB.huds[sec_hud]
secsensor.add_hud_to(src)
/mob/living/silicon/proc/add_med_hud()
var/datum/atom_hud/medsensor = huds[med_hud]
var/datum/atom_hud/medsensor = GLOB.huds[med_hud]
medsensor.add_hud_to(src)
/mob/living/silicon/proc/add_diag_hud()
var/datum/atom_hud/diagsensor = huds[d_hud]
var/datum/atom_hud/diagsensor = GLOB.huds[d_hud]
diagsensor.add_hud_to(src)
/mob/living/silicon/proc/sensor_mode()
@@ -24,7 +24,8 @@
"<span class='userdanger'>[M] took a swipe at [src]!</span>")
/mob/living/silicon/attack_animal(mob/living/simple_animal/M)
if(..())
. = ..()
if(.)
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
if(prob(damage))
for(var/mob/living/N in buckled_mobs)
@@ -44,7 +45,6 @@
adjustCloneLoss(damage)
if(STAMINA)
adjustStaminaLoss(damage)
updatehealth()
/mob/living/silicon/attack_paw(mob/living/user)
return attack_hand(user)
@@ -10,10 +10,7 @@
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
if("grab")
if(grab_state >= GRAB_AGGRESSIVE && isliving(pulling))
vore_attack(M, pulling)
else
grabbedby(M)
grabbedby(M)
if("harm", "disarm")
M.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
@@ -63,25 +60,25 @@
return 1
/mob/living/simple_animal/attack_larva(mob/living/carbon/alien/larva/L)
if(..() && stat != DEAD) //successful larva bite
. = ..()
if(. && stat != DEAD) //successful larva bite
var/damage = rand(5, 10)
L.amount_grown = min(L.amount_grown + damage, L.max_grown)
attack_threshold_check(damage)
return 1
. = attack_threshold_check(damage)
if(.)
L.amount_grown = min(L.amount_grown + damage, L.max_grown)
/mob/living/simple_animal/attack_animal(mob/living/simple_animal/M)
if(..())
. = ..()
if(.)
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
attack_threshold_check(damage, M.melee_damage_type)
return 1
return attack_threshold_check(damage, M.melee_damage_type)
/mob/living/simple_animal/attack_slime(mob/living/simple_animal/slime/M)
if(..()) //successful slime attack
var/damage = rand(15, 25)
if(M.is_adult)
damage = rand(20, 35)
attack_threshold_check(damage)
return 1
return attack_threshold_check(damage)
/mob/living/simple_animal/proc/attack_threshold_check(damage, damagetype = BRUTE, armorcheck = "melee")
var/temp_damage = damage
@@ -92,8 +89,10 @@
if(temp_damage >= 0 && temp_damage <= force_threshold)
visible_message("<span class='warning'>[src] looks unharmed.</span>")
return FALSE
else
apply_damage(damage, damagetype, null, getarmor(null, armorcheck))
return TRUE
/mob/living/simple_animal/bullet_act(obj/item/projectile/Proj)
if(!Proj)
@@ -136,4 +135,4 @@
visual_effect_icon = ATTACK_EFFECT_PUNCH
else
visual_effect_icon = ATTACK_EFFECT_SMASH
..()
..()
@@ -20,6 +20,7 @@
verb_ask = "queries"
verb_exclaim = "declares"
verb_yell = "alarms"
initial_languages = list(/datum/language/common, /datum/language/machine)
bubble_icon = "machine"
faction = list("neutral", "silicon" , "turret")
@@ -118,7 +119,7 @@
..()
access_card = new /obj/item/weapon/card/id(src)
//This access is so bots can be immediately set to patrol and leave Robotics, instead of having to be let out first.
access_card.access += access_robotics
access_card.access += GLOB.access_robotics
set_custom_texts()
Radio = new/obj/item/device/radio(src)
if(radio_key)
@@ -131,7 +132,7 @@
//Adds bot to the diagnostic HUD system
prepare_huds()
var/datum/atom_hud/data/diagnostic/diag_hud = huds[DATA_HUD_DIAGNOSTIC]
var/datum/atom_hud/data/diagnostic/diag_hud = GLOB.huds[DATA_HUD_DIAGNOSTIC]
diag_hud.add_to_hud(src)
diag_hud_set_bothealth()
diag_hud_set_botstat()
@@ -140,6 +141,9 @@
//Gives a HUD view to player bots that use a HUD.
activate_data_hud()
grant_language(/datum/language/common)
grant_language(/datum/language/machine)
/mob/living/simple_animal/bot/update_canmove()
. = ..()
@@ -323,30 +327,29 @@
if((!on) || (!message))
return
if(channel && Radio.channels[channel])// Use radio if we have channel key
Radio.talk_into(src, message, channel, get_spans())
Radio.talk_into(src, message, channel, get_spans(), get_default_language())
else
say(message)
return
/mob/living/simple_animal/bot/get_spans()
return ..() | SPAN_ROBOT
/mob/living/simple_animal/bot/radio(message, message_mode, list/spans)
/mob/living/simple_animal/bot/radio(message, message_mode, list/spans, language)
. = ..()
if(. != 0)
return .
switch(message_mode)
if(MODE_HEADSET)
Radio.talk_into(src, message, , spans)
Radio.talk_into(src, message, , spans, language)
return REDUCE_RANGE
if(MODE_DEPARTMENT)
Radio.talk_into(src, message, message_mode, spans)
Radio.talk_into(src, message, message_mode, spans, language)
return REDUCE_RANGE
if(message_mode in radiochannels)
Radio.talk_into(src, message, message_mode, spans)
if(message_mode in GLOB.radiochannels)
Radio.talk_into(src, message, message_mode, spans, language)
return REDUCE_RANGE
return 0
@@ -607,7 +610,7 @@ Pass a positive integer as an argument to override a bot's default speed.
/mob/living/simple_animal/bot/proc/get_next_patrol_target()
// search the beacon list for the next target in the list.
for(var/obj/machinery/navbeacon/NB in navbeacons["[z]"])
for(var/obj/machinery/navbeacon/NB in GLOB.navbeacons["[z]"])
if(NB.location == next_destination) //Does the Beacon location text match the destination?
destination = new_destination //We now know the name of where we want to go.
patrol_target = NB.loc //Get its location and set it as the target.
@@ -615,7 +618,7 @@ Pass a positive integer as an argument to override a bot's default speed.
return 1
/mob/living/simple_animal/bot/proc/find_nearest_beacon()
for(var/obj/machinery/navbeacon/NB in navbeacons["[z]"])
for(var/obj/machinery/navbeacon/NB in GLOB.navbeacons["[z]"])
var/dist = get_dist(src, NB)
if(nearest_beacon) //Loop though the beacon net to find the true closest beacon.
//Ignore the beacon if were are located on it.
@@ -922,5 +925,5 @@ Pass a positive integer as an argument to override a bot's default speed.
//If a bot has its own HUD (for player bots), provide it.
if(!data_hud_type)
return
var/datum/atom_hud/datahud = huds[data_hud_type]
var/datum/atom_hud/datahud = GLOB.huds[data_hud_type]
datahud.add_hud_to(src)
@@ -265,7 +265,7 @@
..()
/obj/machinery/bot_core/cleanbot
req_one_access = list(access_janitor, access_robotics)
req_one_access = list(GLOB.access_janitor, GLOB.access_robotics)
/mob/living/simple_animal/bot/cleanbot/get_controls(mob/user)
@@ -419,8 +419,7 @@
return
build_step++
to_chat(user, "<span class='notice'>You complete the Securitron! Beep boop.</span>")
var/mob/living/simple_animal/bot/secbot/S = new /mob/living/simple_animal/bot/secbot
S.loc = get_turf(src)
var/mob/living/simple_animal/bot/secbot/S = new /mob/living/simple_animal/bot/secbot(get_turf(src))
S.name = created_name
S.baton_type = I.type
qdel(I)
@@ -59,7 +59,7 @@
shot_delay = 6//Longer shot delay because JESUS CHRIST
check_records = 0//Don't actively target people set to arrest
arrest_type = 1//Don't even try to cuff
bot_core.req_access = list(access_maint_tunnels, access_theatre)
bot_core.req_access = list(GLOB.access_maint_tunnels, GLOB.access_theatre)
arrest_type = 1
if((lasercolor == "b") && (name == "\improper ED-209 Security Robot"))//Picks a name if there isn't already a custome one
name = pick("BLUE BALLER","SANIC","BLUE KILLDEATH MURDERBOT")
@@ -67,7 +67,7 @@
name = pick("RED RAMPAGE","RED ROVER","RED KILLDEATH MURDERBOT")
//SECHUD
var/datum/atom_hud/secsensor = huds[DATA_HUD_SECURITY_ADVANCED]
var/datum/atom_hud/secsensor = GLOB.huds[DATA_HUD_SECURITY_ADVANCED]
secsensor.add_hud_to(src)
/mob/living/simple_animal/bot/ed209/turn_on()
@@ -387,7 +387,7 @@
..()
/obj/machinery/bot_core/floorbot
req_one_access = list(access_construction, access_robotics)
req_one_access = list(GLOB.access_construction, GLOB.access_robotics)
/mob/living/simple_animal/bot/floorbot/UnarmedAttack(atom/A)
if(isturf(A))
@@ -338,7 +338,7 @@
/mob/living/simple_animal/bot/medbot/proc/assess_patient(mob/living/carbon/C)
//Time to see if they need medical help!
if(C.stat == 2)
if(C.stat == DEAD || (C.status_flags & FAKEDEATH))
return 0 //welp too late for them!
if(C.suiciding)
@@ -404,7 +404,7 @@
soft_reset()
return
if(C.stat == 2)
if(C.stat == DEAD || (C.status_flags & FAKEDEATH))
var/list/messagevoice = list("No! Stay with me!" = 'sound/voice/mno.ogg',"Live, damnit! LIVE!" = 'sound/voice/mlive.ogg',"I...I've never lost a patient before. Not today, I mean." = 'sound/voice/mlost.ogg')
var/message = pick(messagevoice)
speak(message)
@@ -496,7 +496,7 @@
return
/mob/living/simple_animal/bot/medbot/proc/check_overdose(mob/living/carbon/patient,reagent_id,injection_amount)
var/datum/reagent/R = chemical_reagents_list[reagent_id]
var/datum/reagent/R = GLOB.chemical_reagents_list[reagent_id]
if(!R.overdose_threshold) //Some chems do not have an OD threshold
return 0
var/current_volume = patient.reagents.get_reagent_amount(reagent_id)
@@ -545,4 +545,4 @@
declare_cooldown = 0
/obj/machinery/bot_core/medbot
req_one_access =list(access_medical, access_robotics)
req_one_access =list(GLOB.access_medical, GLOB.access_robotics)
@@ -4,8 +4,6 @@
// Navigates via floor navbeacons
// Remote Controlled from QM's PDA
var/global/mulebot_count = 0
#define SIGH 0
#define ANNOYED 1
#define DELIGHT 2
@@ -58,10 +56,10 @@ var/global/mulebot_count = 0
cell.charge = 2000
cell.maxcharge = 2000
spawn(10) // must wait for map loading to finish
mulebot_count += 1
if(!suffix)
set_suffix("#[mulebot_count]")
var/static/mulebot_count = 0
mulebot_count += 1
if(!suffix)
set_suffix("#[mulebot_count]")
/mob/living/simple_animal/bot/mulebot/Destroy()
unload(0)
@@ -165,7 +163,7 @@ var/global/mulebot_count = 0
ui_interact(user)
/mob/living/simple_animal/bot/mulebot/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, \
datum/tgui/master_ui = null, datum/ui_state/state = default_state)
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "mulebot", name, 600, 375, master_ui, state)
@@ -231,7 +229,7 @@ var/global/mulebot_count = 0
if(mode == BOT_IDLE || mode == BOT_DELIVER)
start_home()
if("destination")
var/new_dest = input(user, "Enter Destination:", name, destination) as null|anything in deliverybeacontags
var/new_dest = input(user, "Enter Destination:", name, destination) as null|anything in GLOB.deliverybeacontags
if(new_dest)
set_destination(new_dest)
if("setid")
@@ -239,7 +237,7 @@ var/global/mulebot_count = 0
if(new_id)
set_suffix(new_id)
if("sethome")
var/new_home = input(user, "Enter Home:", name, home_destination) as null|anything in deliverybeacontags
var/new_home = input(user, "Enter Home:", name, home_destination) as null|anything in GLOB.deliverybeacontags
if(new_home)
home_destination = new_home
if("unload")
@@ -686,7 +684,7 @@ var/global/mulebot_count = 0
if(!on || wires.is_cut(WIRE_BEACON))
return
for(var/obj/machinery/navbeacon/NB in deliverybeacons)
for(var/obj/machinery/navbeacon/NB in GLOB.deliverybeacons)
if(NB.location == new_destination) // if the beacon location matches the set destination
// the we will navigate there
destination = new_destination
@@ -754,4 +752,4 @@ var/global/mulebot_count = 0
#undef DELIGHT
/obj/machinery/bot_core/mulebot
req_access = list(access_cargo)
req_access = list(GLOB.access_cargo)
@@ -27,18 +27,28 @@
var/target_lastloc //Loc of target when arrested.
var/last_found //There's a delay
var/declare_arrests = 1 //When making an arrest, should it notify everyone on the security channel?
var/idcheck = 1 //If true, arrest people with no IDs
var/weaponscheck = 1 //If true, arrest people for weapons if they lack access
var/idcheck = 0 //If true, arrest people with no IDs
var/weaponscheck = 0 //If true, arrest people for weapons if they lack access
var/check_records = 1 //Does it check security records?
var/arrest_type = 0 //If true, don't handcuff
/mob/living/simple_animal/bot/secbot/beepsky
name = "Officer Beep O'sky"
desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
idcheck = 1
weaponscheck = 1
idcheck = 0
weaponscheck = 0
auto_patrol = 1
/mob/living/simple_animal/bot/secbot/beepsky/jr
name = "Officer Pipsqueak"
desc = "It's Officer Beep O'sky's smaller, just-as aggressive cousin, Pipsqueak."
/mob/living/simple_animal/bot/secbot/beepsky/jr/Initialize()
..()
resize = 0.8
update_transform()
/mob/living/simple_animal/bot/secbot/beepsky/explode()
var/turf/Tsec = get_turf(src)
new /obj/item/weapon/stock_parts/cell/potato(Tsec)
@@ -61,7 +71,7 @@
prev_access = access_card.access
//SECHUD
var/datum/atom_hud/secsensor = huds[DATA_HUD_SECURITY_ADVANCED]
var/datum/atom_hud/secsensor = GLOB.huds[DATA_HUD_SECURITY_ADVANCED]
secsensor.add_hud_to(src)
/mob/living/simple_animal/bot/secbot/turn_on()
@@ -410,4 +420,4 @@ Auto Patrol: []"},
..()
/obj/machinery/bot_core/secbot
req_access = list(access_security)
req_access = list(GLOB.access_security)
@@ -74,7 +74,7 @@
else
to_chat(M, "<span class='cult'>You cannot repair your own dents, as you have none!</span>")
else if(src != M)
..()
return ..()
/mob/living/simple_animal/hostile/construct/Process_Spacemove(movement_dir = 0)
return 1
@@ -20,7 +20,7 @@
back = /obj/item/weapon/storage/backpack
has_id = 1
id_job = "Operative"
id_access_list = list(access_syndicate)
id_access_list = list(GLOB.access_syndicate)
/obj/effect/mob_spawn/human/corpse/syndicatecommando
name = "Syndicate Commando"
@@ -34,7 +34,7 @@
pocket1 = /obj/item/weapon/tank/internals/emergency_oxygen
has_id = 1
id_job = "Operative"
id_access_list = list(access_syndicate)
id_access_list = list(GLOB.access_syndicate)
/obj/effect/mob_spawn/human/corpse/syndicatestormtrooper
name = "Syndicate Stormtrooper"
@@ -47,7 +47,7 @@
back = /obj/item/weapon/tank/jetpack/oxygen/harness
has_id = 1
id_job = "Operative"
id_access_list = list(access_syndicate)
id_access_list = list(GLOB.access_syndicate)
@@ -23,7 +23,6 @@
verb_ask = "flutters inquisitively"
verb_exclaim = "flutters intensely"
verb_yell = "flutters intensely"
devourable = 1
/mob/living/simple_animal/butterfly/Initialize()
..()
@@ -94,9 +94,9 @@
..()
/mob/living/simple_animal/pet/cat/Runtime/Life()
if(!cats_deployed && ticker.current_state >= GAME_STATE_SETTING_UP)
if(!cats_deployed && SSticker.current_state >= GAME_STATE_SETTING_UP)
Deploy_The_Cats()
if(!stat && ticker.current_state == GAME_STATE_FINISHED && !memory_saved)
if(!stat && SSticker.current_state == GAME_STATE_FINISHED && !memory_saved)
Write_Memory()
..()
@@ -27,7 +27,7 @@
del_on_death = 1
/mob/living/simple_animal/cockroach/death(gibbed)
if(ticker.cinematic) //If the nuke is going off, then cockroaches are invincible. Keeps the nuke from killing them, cause cockroaches are immune to nukes.
if(SSticker.cinematic) //If the nuke is going off, then cockroaches are invincible. Keeps the nuke from killing them, cause cockroaches are immune to nukes.
return
..()
@@ -20,7 +20,6 @@
var/obj/item/inventory_head
var/obj/item/inventory_mask
gold_core_spawnable = 2
devourable = 1
/mob/living/simple_animal/crab/Life()
..()
@@ -70,20 +70,25 @@
onclose(user, "mob[real_name]")
return
/mob/living/simple_animal/pet/dog/corgi/attackby(obj/item/O, mob/user, params)
if(inventory_head && inventory_back)
//helmet and armor = 100% protection
if( istype(inventory_head,/obj/item/clothing/head/helmet) && istype(inventory_back,/obj/item/clothing/suit/armor) )
if( O.force )
to_chat(user, "<span class='warning'>[src] is wearing too much armor! You can't cause [p_them()] any damage.</span>")
visible_message("<span class='danger'>[user] hits [src] with [O], however [src] is too armored.</span>")
else
to_chat(user, "<span class='warning'>[src] is wearing too much armor! You can't reach [p_their()] skin.<span>")
visible_message("[user] gently taps [src] with [O].")
if(health>0 && prob(15))
emote("me", 1, "looks at [user] with [pick("an amused","an annoyed","a confused","a resentful", "a happy", "an excited")] expression.")
return
/mob/living/simple_animal/pet/dog/corgi/getarmor(def_zone, type)
var/armorval = 0
if(def_zone)
if(def_zone == "head")
if(inventory_head)
armorval = inventory_head.armor[type]
else
if(inventory_back)
armorval = inventory_back.armor[type]
return armorval
else
if(inventory_head)
armorval += inventory_head.armor[type]
if(inventory_back)
armorval += inventory_back.armor[type]
return armorval*0.5
/mob/living/simple_animal/pet/dog/corgi/attackby(obj/item/O, mob/user, params)
if (istype(O, /obj/item/weapon/razor))
if (shaved)
to_chat(user, "<span class='warning'>You can't shave this corgi, it's already been shaved!</span>")
@@ -304,7 +309,7 @@
turns_per_move = 20
/mob/living/simple_animal/pet/dog/corgi/Ian/Life()
if(ticker.current_state == GAME_STATE_FINISHED && !memory_saved)
if(SSticker.current_state == GAME_STATE_FINISHED && !memory_saved)
Write_Memory(0)
..()
@@ -37,8 +37,8 @@
voice_name = "synthesized chirp"
speak_emote = list("chirps")
bubble_icon = "machine"
languages_spoken = DRONE
languages_understood = DRONE|HUMAN
initial_languages = list(/datum/language/common, /datum/language/machine, /datum/language/drone)
only_speaks_language = /datum/language/drone
mob_size = MOB_SIZE_SMALL
has_unlimited_silicon_privilege = 1
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
@@ -51,6 +51,7 @@
var/staticChoice = "static"
var/list/staticChoices = list("static", "blank", "letter", "animal")
var/picked = FALSE //Have we picked our visual appearence (+ colour if applicable)
var/colour = "grey" //Stored drone color, so we can go back when unhacked.
var/list/drone_overlays[DRONE_TOTAL_LAYERS]
var/laws = \
"1. You may not involve yourself in the matters of another being, even if such matters conflict with Law Two or Law Three, unless the other being is another Drone.\n"+\
@@ -67,6 +68,15 @@
var/visualAppearence = MAINTDRONE //What we appear as
var/hacked = 0 //If we have laws to destroy the station
var/can_be_held = TRUE //if assholes can pick us up
var/flavortext = \
"\n<big><span class='warning'>DO NOT INTERFERE WITH THE ROUND AS A DRONE OR YOU WILL BE DRONE BANNED</span></big>\n"+\
"<span class='notify'>Drones are a ghost role that are allowed to fix the station and build things. Interfering with the round as a drone is against the rules.</span>\n"+\
"<span class='notify'>Actions that constitute interference include, but are not limited to:</span>\n"+\
"<span class='notify'> - Interacting with round critical objects (IDs, weapons, contraband, powersinks, bombs, etc.)</span>\n"+\
"<span class='notify'> - Interacting with living beings (communication, attacking, healing, etc.)</span>\n"+\
"<span class='notify'> - Interacting with non-living beings (dragging bodies, looting bodies, etc.)</span>\n"+\
"<span class='warning'>These rules are at admin discretion and will be heavily enforced.</span>\n"+\
"<span class='warning'><u>If you do not have the regular drone laws, follow your laws to the best of your ability.</u></span>"
/mob/living/simple_animal/drone/Initialize()
. = ..()
@@ -92,7 +102,7 @@
else
verbs -= /mob/living/simple_animal/drone/verb/toggle_statics
var/datum/atom_hud/data/diagnostic/diag_hud = huds[DATA_HUD_DIAGNOSTIC]
var/datum/atom_hud/data/diagnostic/diag_hud = GLOB.huds[DATA_HUD_DIAGNOSTIC]
diag_hud.add_to_hud(src)
@@ -121,6 +131,9 @@
..()
check_laws()
if(flavortext)
to_chat(src, "[flavortext]")
updateSeeStaticMobs()
if(!picked)
@@ -21,10 +21,10 @@
var/area/A = get_area(src)
if(A)
notify_ghosts("A drone shell has been created in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE)
poi_list |= src
GLOB.poi_list |= src
/obj/item/drone_shell/Destroy()
poi_list -= src
GLOB.poi_list -= src
. = ..()
/obj/item/drone_shell/attack_ghost(mob/user)
@@ -36,7 +36,7 @@
if(user.client.player_age < DRONE_MINIMUM_AGE)
to_chat(user, "<span class='danger'>You're too new to play as a drone! Please try again in [DRONE_MINIMUM_AGE - user.client.player_age] days.</span>")
return
if(!ticker.mode)
if(!SSticker.mode)
to_chat(user, "Can't become a drone before the game has started.")
return
var/be_drone = alert("Become a drone? (Warning, You can no longer be cloned!)",,"Yes","No")

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