mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-14 16:44:33 +01:00
Merge remote-tracking branch 'upstream/master' into refactor-spawning-from-vents
This commit is contained in:
@@ -53,7 +53,6 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
|
||||
if(ismob(body))
|
||||
T = get_turf(body) //Where is the body located?
|
||||
attack_log_old = body.attack_log_old //preserve our attack logs by copying them to our ghost
|
||||
logs = body.logs.Copy()
|
||||
|
||||
var/mutable_appearance/MA = copy_appearance(body)
|
||||
if(body.mind && body.mind.name)
|
||||
@@ -577,7 +576,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
|
||||
var/dat
|
||||
dat += "<h4>Crew Manifest</h4>"
|
||||
dat += GLOB.data_core.get_manifest()
|
||||
dat += GLOB.data_core.get_manifest(OOC = TRUE)
|
||||
|
||||
src << browse(dat, "window=manifest;size=370x420;can_close=1")
|
||||
|
||||
@@ -781,4 +780,4 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
set category = "Ghost"
|
||||
|
||||
var/datum/spawners_menu/menu = new /datum/spawners_menu(src)
|
||||
menu.ui_interact(src)
|
||||
menu.tgui_interact(src)
|
||||
|
||||
@@ -1,20 +1,10 @@
|
||||
/mob/dead/observer/say(var/message)
|
||||
/mob/dead/observer/say(message)
|
||||
message = sanitize(copytext(message, 1, MAX_MESSAGE_LEN))
|
||||
|
||||
if(!message)
|
||||
return
|
||||
|
||||
log_ghostsay(message, src)
|
||||
|
||||
if(src.client)
|
||||
if(src.client.prefs.muted & MUTE_DEADCHAT)
|
||||
to_chat(src, "<span class='warning'>You cannot talk in deadchat (muted).</span>")
|
||||
return
|
||||
|
||||
if(src.client.handle_spam_prevention(message,MUTE_DEADCHAT))
|
||||
return
|
||||
|
||||
. = src.say_dead(message)
|
||||
return say_dead(message)
|
||||
|
||||
|
||||
/mob/dead/observer/emote(act, type, message, force)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
return FALSE
|
||||
|
||||
/mob/proc/death(gibbed)
|
||||
SEND_SIGNAL(src, COMSIG_MOB_DEATH, gibbed)
|
||||
return FALSE
|
||||
|
||||
/mob/proc/dust_animation()
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
. = trim(. + trim(msg))
|
||||
. += "\""
|
||||
|
||||
/mob/proc/hear_say(list/message_pieces, verb = "says", italics = 0, mob/speaker = null, sound/speech_sound, sound_vol, sound_frequency)
|
||||
/mob/proc/hear_say(list/message_pieces, verb = "says", italics = 0, mob/speaker = null, sound/speech_sound, sound_vol, sound_frequency, use_voice = TRUE)
|
||||
if(!client)
|
||||
return 0
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
return 0
|
||||
|
||||
var/speaker_name = speaker.name
|
||||
if(ishuman(speaker))
|
||||
if(use_voice && ishuman(speaker))
|
||||
var/mob/living/carbon/human/H = speaker
|
||||
speaker_name = H.GetVoice()
|
||||
|
||||
@@ -99,9 +99,9 @@
|
||||
if(speaker == src)
|
||||
to_chat(src, "<span class='warning'>You cannot hear yourself speak!</span>")
|
||||
else
|
||||
to_chat(src, "<span class='name'>[speaker_name]</span>[speaker.GetAltName()] talks but you cannot hear [speaker.p_them()].")
|
||||
to_chat(src, "<span class='name'>[speaker.name]</span> talks but you cannot hear [speaker.p_them()].")
|
||||
else
|
||||
to_chat(src, "<span class='game say'><span class='name'>[speaker_name]</span>[speaker.GetAltName()] [track][message]</span>")
|
||||
to_chat(src, "<span class='game say'><span class='name'>[speaker_name]</span>[use_voice ? speaker.GetAltName() : ""] [track][message]</span>")
|
||||
if(speech_sound && (get_dist(speaker, src) <= world.view && src.z == speaker.z))
|
||||
var/turf/source = speaker? get_turf(speaker) : get_turf(src)
|
||||
playsound_local(source, speech_sound, sound_vol, 1, sound_frequency)
|
||||
@@ -171,7 +171,14 @@
|
||||
|
||||
to_chat(src, heard)
|
||||
|
||||
/mob/proc/hear_holopad_talk(list/message_pieces, var/verb = "says", var/mob/speaker = null)
|
||||
/mob/proc/hear_holopad_talk(list/message_pieces, verb = "says", mob/speaker = null)
|
||||
if(sleeping || stat == UNCONSCIOUS)
|
||||
hear_sleep(multilingual_to_message(message_pieces))
|
||||
return
|
||||
|
||||
if(!can_hear())
|
||||
return
|
||||
|
||||
var/message = combine_message(message_pieces, verb, speaker)
|
||||
|
||||
var/name = speaker.name
|
||||
|
||||
@@ -186,7 +186,7 @@
|
||||
if(prob(80))
|
||||
new_name += " [pick(list("Hadii","Kaytam","Zhan-Khazan","Hharar","Njarir'Akhan"))]"
|
||||
else
|
||||
new_name += ..(gender,1)
|
||||
new_name += " [..(gender,1)]"
|
||||
return new_name
|
||||
|
||||
/datum/language/vulpkanin
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
/mob/living/carbon/alien/larva/show_inv(mob/user as mob)
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/larva/start_pulling(atom/movable/AM, state, force = move_force, supress_message = FALSE)
|
||||
/mob/living/carbon/alien/larva/start_pulling(atom/movable/AM, state, force = pull_force, show_message = FALSE)
|
||||
return FALSE
|
||||
|
||||
/* Commented out because it's duplicated in life.dm
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
return
|
||||
polling = 1
|
||||
spawn()
|
||||
var/list/candidates = pollCandidates("Do you want to play as an alien?", ROLE_ALIEN, 0)
|
||||
var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as an alien?", ROLE_ALIEN, FALSE, source = /mob/living/carbon/alien/larva)
|
||||
var/mob/C = null
|
||||
|
||||
// To stop clientless larva, we will check that our host has a client
|
||||
|
||||
@@ -28,6 +28,10 @@
|
||||
|
||||
var/attached = 0
|
||||
|
||||
/obj/item/clothing/mask/facehugger/ComponentInitialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/proximity_monitor)
|
||||
|
||||
/obj/item/clothing/mask/facehugger/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
|
||||
..()
|
||||
if(obj_integrity < 90)
|
||||
@@ -78,7 +82,7 @@
|
||||
return HasProximity(finder)
|
||||
return 0
|
||||
|
||||
/obj/item/clothing/mask/facehugger/HasProximity(atom/movable/AM as mob|obj)
|
||||
/obj/item/clothing/mask/facehugger/HasProximity(atom/movable/AM)
|
||||
if(CanHug(AM) && Adjacent(AM))
|
||||
return Attach(AM)
|
||||
return 0
|
||||
@@ -210,6 +214,7 @@
|
||||
icon_state = "[initial(icon_state)]_dead"
|
||||
item_state = "facehugger_inactive"
|
||||
stat = DEAD
|
||||
qdel(GetComponent(/datum/component/proximity_monitor))
|
||||
|
||||
visible_message("<span class='danger'>[src] curls up into a ball!</span>")
|
||||
|
||||
|
||||
@@ -226,13 +226,6 @@
|
||||
brainmob.emp_damage += rand(0,10)
|
||||
..()
|
||||
|
||||
/obj/item/mmi/relaymove(var/mob/user, var/direction)
|
||||
if(user.stat || user.stunned)
|
||||
return
|
||||
var/obj/item/rig/rig = src.get_rig()
|
||||
if(rig)
|
||||
rig.forced_move(direction, user)
|
||||
|
||||
/obj/item/mmi/Destroy()
|
||||
if(isrobot(loc))
|
||||
var/mob/living/silicon/robot/borg = loc
|
||||
|
||||
@@ -514,10 +514,10 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, list(/obj/machinery/atmospherics/unary/ven
|
||||
|
||||
/mob/living/update_pipe_vision()
|
||||
if(pipes_shown.len)
|
||||
if(!istype(loc, /obj/machinery/atmospherics))
|
||||
if(!is_ventcrawling(src))
|
||||
remove_ventcrawl()
|
||||
else
|
||||
if(istype(loc, /obj/machinery/atmospherics))
|
||||
if(is_ventcrawling(src))
|
||||
add_ventcrawl(loc)
|
||||
|
||||
|
||||
@@ -538,6 +538,8 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, list(/obj/machinery/atmospherics/unary/ven
|
||||
take_organ_damage(10)
|
||||
if(iscarbon(hit_atom) && hit_atom != src)
|
||||
var/mob/living/carbon/victim = hit_atom
|
||||
if(victim.flying)
|
||||
return
|
||||
if(hurt)
|
||||
victim.take_organ_damage(10)
|
||||
take_organ_damage(10)
|
||||
|
||||
@@ -109,9 +109,6 @@
|
||||
// log_world("k")
|
||||
sql_report_death(src)
|
||||
|
||||
if(wearing_rig)
|
||||
wearing_rig.notify_ai("<span class='danger'>Warning: user death event. Mobility control passed to integrated intelligence system.</span>")
|
||||
|
||||
/mob/living/carbon/human/update_revive()
|
||||
. = ..()
|
||||
if(. && healthdoll)
|
||||
|
||||
@@ -30,8 +30,15 @@
|
||||
//handle_emote_CD() located in [code\modules\mob\emote.dm]
|
||||
var/on_CD = FALSE
|
||||
act = lowertext(act)
|
||||
switch(act)
|
||||
//Cooldown-inducing emotes
|
||||
|
||||
switch(act) //This switch makes sure you have air in your lungs before you scream
|
||||
if("growl", "growls", "howl", "howls", "hiss", "hisses", "scream", "screams", "sneeze", "sneezes")
|
||||
if(getOxyLoss() > 35) //no screaming if you don't have enough breath to scream
|
||||
on_CD = handle_emote_CD()
|
||||
emote("gasp")
|
||||
return
|
||||
|
||||
switch(act) //This switch adds cooldowns to some emotes
|
||||
if("ping", "pings", "buzz", "buzzes", "beep", "beeps", "yes", "no", "buzz2")
|
||||
var/found_machine_head = FALSE
|
||||
if(ismachineperson(src)) //Only Machines can beep, ping, and buzz, yes, no, and make a silly sad trombone noise.
|
||||
@@ -44,7 +51,7 @@
|
||||
found_machine_head = TRUE
|
||||
|
||||
if(!found_machine_head) //Everyone else fails, skip the emote attempt
|
||||
return //Everyone else fails, skip the emote attempt
|
||||
return //Everyone else fails, skip the emote attempt
|
||||
if("drone","drones","hum","hums","rumble","rumbles")
|
||||
if(isdrask(src)) //Only Drask can make whale noises
|
||||
on_CD = handle_emote_CD() //proc located in code\modules\mob\emote.dm
|
||||
@@ -133,7 +140,7 @@
|
||||
if(!force && on_CD == 1) // Check if we need to suppress the emote attempt.
|
||||
return // Suppress emote, you're still cooling off.
|
||||
|
||||
switch(act)
|
||||
switch(act) //This is for actually making the emotes happen
|
||||
if("me") //OKAY SO RANT TIME, THIS FUCKING HAS TO BE HERE OR A SHITLOAD OF THINGS BREAK
|
||||
return custom_emote(m_type, message) //DO YOU KNOW WHY SHIT BREAKS? BECAUSE SO MUCH OLDCODE CALLS mob.emote("me",1,"whatever_the_fuck_it_wants_to_emote")
|
||||
//WHO THE FUCK THOUGHT THAT WAS A GOOD FUCKING IDEA!?!?
|
||||
@@ -308,14 +315,14 @@
|
||||
m_type = 1
|
||||
|
||||
if("bow", "bows")
|
||||
if(!buckled)
|
||||
if(!restrained())
|
||||
var/M = handle_emote_param(param)
|
||||
|
||||
message = "<B>[src]</B> bows[M ? " to [M]" : ""]."
|
||||
m_type = 1
|
||||
|
||||
if("salute", "salutes")
|
||||
if(!buckled)
|
||||
if(!restrained())
|
||||
var/M = handle_emote_param(param)
|
||||
|
||||
message = "<B>[src]</B> salutes[M ? " to [M]" : ""]."
|
||||
@@ -592,7 +599,7 @@
|
||||
message = "<B>[src]</B> sighs[M ? " at [M]" : ""]."
|
||||
m_type = 2
|
||||
else
|
||||
message = "<B>[src]</B> makes a weak noise"
|
||||
message = "<B>[src]</B> makes a weak noise."
|
||||
m_type = 2
|
||||
|
||||
if("hsigh", "hsighs")
|
||||
@@ -600,7 +607,7 @@
|
||||
message = "<B>[src]</B> sighs contentedly."
|
||||
m_type = 2
|
||||
else
|
||||
message = "<B>[src]</B> makes a [pick("chill", "relaxed")] noise"
|
||||
message = "<B>[src]</B> makes a [pick("chill", "relaxed")] noise."
|
||||
m_type = 2
|
||||
|
||||
if("laugh", "laughs")
|
||||
|
||||
@@ -301,14 +301,13 @@
|
||||
else if(nutrition >= NUTRITION_LEVEL_FAT)
|
||||
msg += "[p_they(TRUE)] [p_are()] quite chubby.\n"
|
||||
|
||||
if(!ismachineperson(src) && blood_volume < BLOOD_VOLUME_SAFE)
|
||||
if(blood_volume < BLOOD_VOLUME_SAFE)
|
||||
msg += "[p_they(TRUE)] [p_have()] pale skin.\n"
|
||||
|
||||
if(bleedsuppress)
|
||||
msg += "[p_they(TRUE)] [p_are()] bandaged with something.\n"
|
||||
else if(bleed_rate)
|
||||
var/bleed_message = !ismachineperson(src) ? "bleeding" : "leaking"
|
||||
msg += "<B>[p_they(TRUE)] [p_are()] [bleed_message]!</B>\n"
|
||||
msg += "<B>[p_they(TRUE)] [p_are()] bleeding!</B>\n"
|
||||
|
||||
if(reagents.has_reagent("teslium"))
|
||||
msg += "[p_they(TRUE)] [p_are()] emitting a gentle blue glow!\n"
|
||||
@@ -341,7 +340,7 @@
|
||||
if(decaylevel == 3)
|
||||
msg += "[p_they(TRUE)] [p_are()] rotting and blackened, the skin sloughing off. The smell is indescribably foul.\n"
|
||||
if(decaylevel == 4)
|
||||
msg += "[p_they(TRUE)] [p_are()] mostly dessicated now, with only bones remaining of what used to be a person.\n"
|
||||
msg += "[p_they(TRUE)] [p_are()] mostly desiccated now, with only bones remaining of what used to be a person.\n"
|
||||
|
||||
if(hasHUD(user,"security"))
|
||||
var/perpname = get_visible_name(TRUE)
|
||||
@@ -365,6 +364,17 @@
|
||||
msg += "<span class = 'deptradio'>Security records:</span> <a href='?src=[UID()];secrecordComment=`'>\[View comment log\]</a> <a href='?src=[UID()];secrecordadd=`'>\[Add comment\]</a>\n"
|
||||
msg += "<span class = 'deptradio'>Latest entry:</span> [commentLatest]\n"
|
||||
|
||||
if(hasHUD(user, "skills"))
|
||||
var/perpname = get_visible_name(TRUE)
|
||||
var/skills
|
||||
|
||||
if(perpname)
|
||||
for(var/datum/data/record/E in GLOB.data_core.general)
|
||||
if(E.fields["name"] == perpname)
|
||||
skills = E.fields["notes"]
|
||||
if(skills)
|
||||
msg += "<span class='deptradio'>Employment records:</span> [skills]\n"
|
||||
|
||||
if(hasHUD(user,"medical"))
|
||||
var/perpname = get_visible_name(TRUE)
|
||||
var/medical = "None"
|
||||
@@ -405,8 +415,11 @@
|
||||
return !istype(CIH,/obj/item/organ/internal/cyberimp/eyes/hud/security) && S && S.read_only
|
||||
if("medical")
|
||||
return istype(H.glasses, /obj/item/clothing/glasses/hud/health) || istype(CIH,/obj/item/organ/internal/cyberimp/eyes/hud/medical)
|
||||
if("skills")
|
||||
return istype(H.glasses, /obj/item/clothing/glasses/hud/skills)
|
||||
else
|
||||
return FALSE
|
||||
|
||||
else if(isrobot(M) || isAI(M)) //Stand-in/Stopgap to prevent pAIs from freely altering records, pending a more advanced Records system
|
||||
switch(hudtype)
|
||||
if("security")
|
||||
@@ -421,6 +434,8 @@
|
||||
switch(hudtype)
|
||||
if("security")
|
||||
return TRUE
|
||||
if("skills")
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
else
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
icon = 'icons/mob/human.dmi'
|
||||
icon_state = "body_m_s"
|
||||
deathgasp_on_death = TRUE
|
||||
var/obj/item/rig/wearing_rig // This is very not good, but it's much much better than calling get_rig() every update_canmove() call.
|
||||
|
||||
/mob/living/carbon/human/New(loc)
|
||||
icon = null // This is now handled by overlays -- we just keep an icon for the sake of the map editor.
|
||||
@@ -30,8 +29,6 @@
|
||||
|
||||
create_reagents(330)
|
||||
|
||||
martial_art = GLOB.default_martial_art
|
||||
|
||||
handcrafting = new()
|
||||
|
||||
// Set up DNA.
|
||||
@@ -182,13 +179,6 @@
|
||||
stat("Tank Pressure", internal.air_contents.return_pressure())
|
||||
stat("Distribution Pressure", internal.distribute_pressure)
|
||||
|
||||
if(istype(back, /obj/item/rig))
|
||||
var/obj/item/rig/suit = back
|
||||
var/cell_status = "ERROR"
|
||||
if(suit.cell)
|
||||
cell_status = "[suit.cell.charge]/[suit.cell.maxcharge]"
|
||||
stat(null, "Suit charge: [cell_status]")
|
||||
|
||||
// I REALLY need to split up status panel things into datums
|
||||
var/mob/living/simple_animal/borer/B = has_brain_worms()
|
||||
if(B && B.controlling)
|
||||
@@ -264,7 +254,7 @@
|
||||
limbs_affected -= 1
|
||||
else valid_limbs -= processing_dismember
|
||||
|
||||
if(!istype(l_ear, /obj/item/clothing/ears/earmuffs) && !istype(r_ear, /obj/item/clothing/ears/earmuffs))
|
||||
if(check_ear_prot() < HEARING_PROTECTION_TOTAL)
|
||||
AdjustEarDamage(30, 120)
|
||||
if(prob(70) && !shielded)
|
||||
Paralyse(10)
|
||||
@@ -288,7 +278,7 @@
|
||||
limbs_affected -= 1
|
||||
else valid_limbs -= processing_dismember
|
||||
|
||||
if(!istype(l_ear, /obj/item/clothing/ears/earmuffs) && !istype(r_ear, /obj/item/clothing/ears/earmuffs))
|
||||
if(check_ear_prot() < HEARING_PROTECTION_TOTAL)
|
||||
AdjustEarDamage(15, 60)
|
||||
if(prob(50) && !shielded)
|
||||
Paralyse(10)
|
||||
@@ -306,8 +296,8 @@
|
||||
apply_damage(5, BRUTE, affecting, run_armor_check(affecting, "melee"))
|
||||
|
||||
/mob/living/carbon/human/bullet_act()
|
||||
if(martial_art && martial_art.deflection_chance) //Some martial arts users can deflect projectiles!
|
||||
if(!prob(martial_art.deflection_chance))
|
||||
if(mind && mind.martial_art && mind.martial_art.deflection_chance) //Some martial arts users can deflect projectiles!
|
||||
if(!prob(mind.martial_art.deflection_chance))
|
||||
return ..()
|
||||
if(!src.lying && !(HULK in mutations)) //But only if they're not lying down, and hulks can't do it
|
||||
visible_message("<span class='danger'>[src] deflects the projectile; [p_they()] can't be hit with ranged weapons!</span>", "<span class='userdanger'>You deflect the projectile!</span>")
|
||||
@@ -941,12 +931,18 @@
|
||||
return number
|
||||
|
||||
/mob/living/carbon/human/check_ear_prot()
|
||||
if(!can_hear())
|
||||
return HEARING_PROTECTION_TOTAL
|
||||
if(istype(l_ear, /obj/item/clothing/ears/earmuffs))
|
||||
return HEARING_PROTECTION_TOTAL
|
||||
if(istype(r_ear, /obj/item/clothing/ears/earmuffs))
|
||||
return HEARING_PROTECTION_TOTAL
|
||||
if(head && (head.flags & HEADBANGPROTECT))
|
||||
return 1
|
||||
return HEARING_PROTECTION_MINOR
|
||||
if(l_ear && (l_ear.flags & EARBANGPROTECT))
|
||||
return 1
|
||||
return HEARING_PROTECTION_MINOR
|
||||
if(r_ear && (r_ear.flags & EARBANGPROTECT))
|
||||
return 1
|
||||
return HEARING_PROTECTION_MINOR
|
||||
|
||||
///tintcheck()
|
||||
///Checks eye covering items for visually impairing tinting, such as welding masks
|
||||
@@ -963,16 +959,6 @@
|
||||
var/obj/item/clothing/mask/MT = src.wear_mask
|
||||
tinted += MT.tint
|
||||
|
||||
//god help me
|
||||
if(istype(back, /obj/item/rig))
|
||||
var/obj/item/rig/O = back
|
||||
if(O.helmet && O.helmet == head && (O.helmet.body_parts_covered & HEAD))
|
||||
if((O.offline && O.offline_vision_restriction == 1) || (!O.offline && O.vision_restriction == 1))
|
||||
tinted = 2
|
||||
if((O.offline && O.offline_vision_restriction == 2) || (!O.offline && O.vision_restriction == 2))
|
||||
tinted = 3
|
||||
//im so sorry
|
||||
|
||||
return tinted
|
||||
|
||||
|
||||
@@ -1193,7 +1179,7 @@
|
||||
set src in view(1)
|
||||
var/self = 0
|
||||
|
||||
if(usr.stat == 1 || usr.restrained() || !isliving(usr)) return
|
||||
if(usr.stat == 1 || usr.restrained() || !isliving(usr) || usr.is_dead()) return
|
||||
|
||||
if(usr == src)
|
||||
self = 1
|
||||
@@ -1465,12 +1451,13 @@
|
||||
var/obj/item/organ/internal/eyes/eyes = get_int_organ(/obj/item/organ/internal/eyes)
|
||||
var/obj/item/organ/internal/cyberimp/eyes/eye_implant = get_int_organ(/obj/item/organ/internal/cyberimp/eyes)
|
||||
if(istype(dna.species) && dna.species.eyes)
|
||||
var/icon/eyes_icon = new /icon('icons/mob/human_face.dmi', dna.species.eyes)
|
||||
var/icon/eyes_icon
|
||||
if(eye_implant) //Eye implants override native DNA eye colo(u)r
|
||||
eyes_icon = eye_implant.generate_icon()
|
||||
else if(eyes)
|
||||
eyes_icon = eyes.generate_icon()
|
||||
else //Error 404: Eyes not found!
|
||||
eyes_icon = new('icons/mob/human_face.dmi', dna.species.eyes)
|
||||
eyes_icon.Blend("#800000", ICON_ADD)
|
||||
|
||||
return eyes_icon
|
||||
@@ -1748,16 +1735,14 @@ Eyes need to have significantly high darksight to shine unless the mob has the X
|
||||
if(G.trigger_guard == TRIGGER_GUARD_NORMAL)
|
||||
if(HULK in mutations)
|
||||
to_chat(src, "<span class='warning'>Your meaty finger is much too large for the trigger guard!</span>")
|
||||
return 0
|
||||
return FALSE
|
||||
if(NOGUNS in dna.species.species_traits)
|
||||
to_chat(src, "<span class='warning'>Your fingers don't fit in the trigger guard!</span>")
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if(martial_art && martial_art.no_guns) //great dishonor to famiry
|
||||
to_chat(src, "<span class='warning'>[martial_art.no_guns_message]</span>")
|
||||
return 0
|
||||
|
||||
return .
|
||||
if(mind && mind.martial_art && mind.martial_art.no_guns) //great dishonor to famiry
|
||||
to_chat(src, "<span class='warning'>[mind.martial_art.no_guns_message]</span>")
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/human/proc/change_icobase(var/new_icobase, var/new_deform, var/owner_sensitive)
|
||||
for(var/obj/item/organ/external/O in bodyparts)
|
||||
|
||||
@@ -129,13 +129,6 @@
|
||||
O.heal_damage(0, -amount, internal = 0, robo_repair = O.is_robotic(), updating_health = updating_health)
|
||||
return STATUS_UPDATE_HEALTH
|
||||
|
||||
|
||||
/mob/living/carbon/human/Paralyse(amount)
|
||||
// Notify our AI if they can now control the suit.
|
||||
if(wearing_rig && !stat && paralysis < amount) //We are passing out right this second.
|
||||
wearing_rig.notify_ai("<span class='danger'>Warning: user consciousness failure. Mobility control passed to integrated intelligence system.</span>")
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/adjustCloneLoss(amount)
|
||||
if(dna.species && amount > 0)
|
||||
amount = amount * dna.species.clone_mod
|
||||
@@ -342,7 +335,5 @@ This function restores all organs.
|
||||
..(damage, damagetype, def_zone, blocked)
|
||||
return 1
|
||||
|
||||
//Handle BRUTE and BURN damage
|
||||
handle_suit_punctures(damagetype, damage)
|
||||
//Handle species apply_damage procs
|
||||
return dna.species.apply_damage(damage, damagetype, def_zone, blocked, src, sharp, used_weapon)
|
||||
|
||||
@@ -13,14 +13,22 @@ emp_act
|
||||
if(!dna.species.bullet_act(P, src))
|
||||
return FALSE
|
||||
if(P.is_reflectable)
|
||||
if(check_reflect(def_zone)) // Checks if you've passed a reflection% check
|
||||
var/can_reflect = check_reflect(def_zone)
|
||||
if(can_reflect == 1) // proper reflection
|
||||
visible_message("<span class='danger'>The [P.name] gets reflected by [src]!</span>", \
|
||||
"<span class='userdanger'>The [P.name] gets reflected by [src]!</span>")
|
||||
|
||||
"<span class='userdanger'>The [P.name] gets reflected by [src]!</span>")
|
||||
P.reflect_back(src)
|
||||
|
||||
return -1 // complete projectile permutation
|
||||
|
||||
else if(can_reflect == 2) //If target is holding a toy sword
|
||||
var/list/safe_list = list(/obj/item/projectile/beam/lasertag, /obj/item/projectile/beam/practice)
|
||||
if(is_type_in_list(P, safe_list)) //And it's safe
|
||||
visible_message("<span class='danger'>The [P.name] gets reflected by [src]!</span>", \
|
||||
"<span class='userdanger'>The [P.name] gets reflected by [src]!</span>")
|
||||
P.reflect_back(src)
|
||||
return -1 // complete projectile permutation
|
||||
|
||||
|
||||
//Shields
|
||||
if(check_shields(P, P.damage, "the [P.name]", PROJECTILE_ATTACK, P.armour_penetration))
|
||||
P.on_hit(src, 100, def_zone)
|
||||
@@ -172,10 +180,14 @@ emp_act
|
||||
var/obj/item/I = l_hand
|
||||
if(I.IsReflect(def_zone) == 1)
|
||||
return 1
|
||||
if(I.IsReflect(def_zone) == 2) //Toy swords
|
||||
return 2
|
||||
if(r_hand && istype(r_hand, /obj/item/))
|
||||
var/obj/item/I = r_hand
|
||||
if(I.IsReflect(def_zone) == 1)
|
||||
return 1
|
||||
if(I.IsReflect(def_zone) == 2) //Toy swords
|
||||
return 2
|
||||
return 0
|
||||
|
||||
|
||||
@@ -203,7 +215,7 @@ emp_act
|
||||
return 0
|
||||
|
||||
/mob/living/carbon/human/proc/check_block()
|
||||
if(martial_art && prob(martial_art.block_chance) && martial_art.can_use(src) && in_throw_mode && !incapacitated(FALSE, TRUE))
|
||||
if(mind && mind.martial_art && prob(mind.martial_art.block_chance) && mind.martial_art.can_use(src) && in_throw_mode && !incapacitated(FALSE, TRUE))
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/human/acid_act(acidpwr, acid_volume, bodyzone_hit) //todo: update this to utilize check_obscured_slots() //and make sure it's check_obscured_slots(TRUE) to stop aciding through visors etc
|
||||
@@ -531,17 +543,6 @@ emp_act
|
||||
w_uniform.add_mob_blood(source)
|
||||
update_inv_w_uniform()
|
||||
|
||||
/mob/living/carbon/human/proc/handle_suit_punctures(var/damtype, var/damage)
|
||||
|
||||
if(!wear_suit) return
|
||||
if(!istype(wear_suit,/obj/item/clothing/suit/space)) return
|
||||
if(damtype != BURN && damtype != BRUTE) return
|
||||
|
||||
var/obj/item/clothing/suit/space/SS = wear_suit
|
||||
var/penetrated_dam = max(0,(damage - max(0,(SS.breach_threshold - SS.damage))))
|
||||
|
||||
if(penetrated_dam) SS.create_breaches(damtype, penetrated_dam)
|
||||
|
||||
/mob/living/carbon/human/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
|
||||
if(user.a_intent == INTENT_HARM)
|
||||
if(HAS_TRAIT(user, TRAIT_PACIFISM))
|
||||
@@ -583,41 +584,34 @@ emp_act
|
||||
if(M.a_intent == INTENT_HARM)
|
||||
if(w_uniform)
|
||||
w_uniform.add_fingerprint(M)
|
||||
var/damage = rand(15, 30)
|
||||
var/damage = prob(90) ? 20 : 0
|
||||
if(!damage)
|
||||
playsound(loc, 'sound/weapons/slashmiss.ogg', 50, 1, -1)
|
||||
playsound(loc, 'sound/weapons/slashmiss.ogg', 50, TRUE, -1)
|
||||
visible_message("<span class='danger'>[M] has lunged at [src]!</span>")
|
||||
return 0
|
||||
var/obj/item/organ/external/affecting = get_organ(ran_zone(M.zone_selected))
|
||||
var/armor_block = run_armor_check(affecting, "melee")
|
||||
var/armor_block = run_armor_check(affecting, "melee", armour_penetration = 10)
|
||||
|
||||
playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
|
||||
playsound(loc, 'sound/weapons/slice.ogg', 25, TRUE, -1)
|
||||
visible_message("<span class='danger'>[M] has slashed at [src]!</span>", \
|
||||
"<span class='userdanger'>[M] has slashed at [src]!</span>")
|
||||
|
||||
apply_damage(damage, BRUTE, affecting, armor_block)
|
||||
if(damage >= 25)
|
||||
visible_message("<span class='danger'>[M] has wounded [src]!</span>", \
|
||||
"<span class='userdanger'>[M] has wounded [src]!</span>")
|
||||
apply_effect(4, WEAKEN, armor_block)
|
||||
add_attack_logs(M, src, "Alien attacked")
|
||||
add_attack_logs(M, src, "Alien attacked")
|
||||
updatehealth("alien attack")
|
||||
|
||||
if(M.a_intent == INTENT_DISARM)
|
||||
if(prob(80))
|
||||
if(M.a_intent == INTENT_DISARM) //Always drop item in hand, if no item, get stun instead.
|
||||
var/obj/item/I = get_active_hand()
|
||||
if(I && unEquip(I))
|
||||
playsound(loc, 'sound/weapons/slash.ogg', 25, TRUE, -1)
|
||||
visible_message("<span class='danger'>[M] disarms [src]!</span>", "<span class='userdanger'>[M] disarms you!</span>", "<span class='hear'>You hear aggressive shuffling!</span>")
|
||||
to_chat(M, "<span class='danger'>You disarm [src]!</span>")
|
||||
else
|
||||
var/obj/item/organ/external/affecting = get_organ(ran_zone(M.zone_selected))
|
||||
playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
|
||||
apply_effect(5, WEAKEN, run_armor_check(affecting, "melee"))
|
||||
add_attack_logs(M, src, "Alien tackled")
|
||||
visible_message("<span class='danger'>[M] has tackled down [src]!</span>")
|
||||
else
|
||||
if(prob(99)) //this looks fucking stupid but it was previously 'var/randn = rand(1, 100); if(randn <= 99)'
|
||||
playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1)
|
||||
drop_item()
|
||||
visible_message("<span class='danger'>[M] disarmed [src]!</span>")
|
||||
else
|
||||
playsound(loc, 'sound/weapons/slashmiss.ogg', 50, 1, -1)
|
||||
visible_message("<span class='danger'>[M] has tried to disarm [src]!</span>")
|
||||
|
||||
/mob/living/carbon/human/attack_animal(mob/living/simple_animal/M)
|
||||
. = ..()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
GLOBAL_DATUM_INIT(default_martial_art, /datum/martial_art, new())
|
||||
/mob/living/carbon/human
|
||||
|
||||
hud_possible = list(HEALTH_HUD,STATUS_HUD,ID_HUD,WANTED_HUD,IMPMINDSHIELD_HUD,IMPCHEM_HUD,IMPTRACK_HUD,SPECIALROLE_HUD,GLAND_HUD)
|
||||
@@ -42,8 +41,6 @@ GLOBAL_DATUM_INIT(default_martial_art, /datum/martial_art, new())
|
||||
|
||||
var/datum/personal_crafting/handcrafting
|
||||
|
||||
var/datum/martial_art/martial_art = null
|
||||
|
||||
var/special_voice = "" // For changing our voice. Used by a symptom.
|
||||
|
||||
var/hand_blood_color
|
||||
|
||||
@@ -16,12 +16,6 @@
|
||||
else if(istype(wear_suit, /obj/item/clothing/suit/space/hardsuit))
|
||||
var/obj/item/clothing/suit/space/hardsuit/C = wear_suit
|
||||
thrust = C.jetpack
|
||||
else if(istype(back,/obj/item/rig))
|
||||
var/obj/item/rig/rig = back
|
||||
for(var/obj/item/rig_module/maneuvering_jets/module in rig.installed_modules)
|
||||
thrust = module.jets
|
||||
break
|
||||
|
||||
if(thrust)
|
||||
if((movement_dir || thrust.stabilizers) && thrust.allow_thrust(0.01, src))
|
||||
return 1
|
||||
|
||||
@@ -66,9 +66,7 @@
|
||||
if(!is_station_level(T.z))
|
||||
return
|
||||
var/area/A = get_area(src)
|
||||
if(cryo_ssd(src))
|
||||
var/obj/effect/portal/P = new /obj/effect/portal(T, null, null, 40)
|
||||
P.name = "NT SSD Teleportation Portal"
|
||||
cryo_ssd(src)
|
||||
if(A.fast_despawn)
|
||||
force_cryo_human(src)
|
||||
|
||||
@@ -302,14 +300,6 @@
|
||||
if(!(head && head.flags & AIRTIGHT)) //if NOT (head AND head.flags CONTAIN AIRTIGHT)
|
||||
null_internals = 1 //not wearing a mask or suitable helmet
|
||||
|
||||
if(istype(back, /obj/item/rig)) //wearing a rigsuit
|
||||
var/obj/item/rig/rig = back //needs to be typecasted because this doesn't use get_rig() for some reason
|
||||
if(rig.offline && (rig.air_supply && internal == rig.air_supply)) //if rig IS offline AND (rig HAS air_supply AND internal IS air_supply)
|
||||
null_internals = 1 //offline suits do not breath
|
||||
|
||||
else if(rig.air_supply && internal == rig.air_supply) //if rig HAS air_supply AND internal IS rig air_supply
|
||||
skip_contents_check = 1 //skip contents.Find() check, the oxygen is valid even being outside of the mob
|
||||
|
||||
if(!contents.Find(internal) && (!skip_contents_check)) //if internal NOT IN contents AND skip_contents_check IS false
|
||||
null_internals = 1 //not a rigsuit and your oxygen is gone
|
||||
|
||||
@@ -706,13 +696,14 @@
|
||||
|
||||
if(alcohol_strength >= slur_start) //slurring
|
||||
Slur(drunk)
|
||||
if(alcohol_strength >= brawl_start) //the drunken martial art
|
||||
if(!istype(martial_art, /datum/martial_art/drunk_brawling))
|
||||
var/datum/martial_art/drunk_brawling/F = new
|
||||
F.teach(src, 1)
|
||||
if(alcohol_strength < brawl_start) //removing the art
|
||||
if(istype(martial_art, /datum/martial_art/drunk_brawling))
|
||||
martial_art.remove(src)
|
||||
if(mind)
|
||||
if(alcohol_strength >= brawl_start) //the drunken martial art
|
||||
if(!istype(mind.martial_art, /datum/martial_art/drunk_brawling))
|
||||
var/datum/martial_art/drunk_brawling/F = new
|
||||
F.teach(src, TRUE)
|
||||
else if(alcohol_strength < brawl_start) //removing the art
|
||||
if(istype(mind.martial_art, /datum/martial_art/drunk_brawling))
|
||||
mind.martial_art.remove(src)
|
||||
if(alcohol_strength >= confused_start && prob(33)) //confused walking
|
||||
if(!confused)
|
||||
Confused(1)
|
||||
|
||||
@@ -6,4 +6,5 @@
|
||||
if(ventcrawler)
|
||||
to_chat(src, "<span class='notice'>You can ventcrawl! Use alt+click on vents to quickly travel about the station.</span>")
|
||||
update_pipe_vision()
|
||||
regenerate_icons()
|
||||
return
|
||||
|
||||
@@ -62,11 +62,6 @@
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/proc/HasVoiceChanger()
|
||||
if(istype(back, /obj/item/rig))
|
||||
var/obj/item/rig/rig = back
|
||||
if(rig.speech && rig.speech.voice_holder && rig.speech.voice_holder.active && rig.speech.voice_holder.voice)
|
||||
return rig.speech.voice_holder.voice
|
||||
|
||||
for(var/obj/item/gear in list(wear_mask, wear_suit, head))
|
||||
if(!gear)
|
||||
continue
|
||||
|
||||
@@ -371,7 +371,7 @@
|
||||
return
|
||||
|
||||
/datum/species/proc/help(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
|
||||
if(attacker_style && attacker_style.help_act(user, target))//adminfu only...
|
||||
if(attacker_style && attacker_style.help_act(user, target) == TRUE)//adminfu only...
|
||||
return TRUE
|
||||
if(target.health >= HEALTH_THRESHOLD_CRIT && !(target.status_flags & FAKEDEATH))
|
||||
target.help_shake_act(user)
|
||||
@@ -383,7 +383,7 @@
|
||||
if(target.check_block())
|
||||
target.visible_message("<span class='warning'>[target] blocks [user]'s grab attempt!</span>")
|
||||
return FALSE
|
||||
if(attacker_style && attacker_style.grab_act(user, target))
|
||||
if(attacker_style && attacker_style.grab_act(user, target) == TRUE)
|
||||
return TRUE
|
||||
else
|
||||
target.grabbedby(user)
|
||||
@@ -412,7 +412,7 @@
|
||||
if(target.check_block())
|
||||
target.visible_message("<span class='warning'>[target] blocks [user]'s attack!</span>")
|
||||
return FALSE
|
||||
if(attacker_style && attacker_style.harm_act(user, target))
|
||||
if(attacker_style && attacker_style.harm_act(user, target) == TRUE)
|
||||
return TRUE
|
||||
else
|
||||
var/datum/unarmed_attack/attack = user.dna.species.unarmed
|
||||
@@ -460,7 +460,7 @@
|
||||
if(target.check_block())
|
||||
target.visible_message("<span class='warning'>[target] blocks [user]'s disarm attempt!</span>")
|
||||
return FALSE
|
||||
if(attacker_style && attacker_style.disarm_act(user, target))
|
||||
if(attacker_style && attacker_style.disarm_act(user, target) == TRUE)
|
||||
return TRUE
|
||||
else
|
||||
add_attack_logs(user, target, "Disarmed", ATKLOG_ALL)
|
||||
@@ -516,12 +516,9 @@
|
||||
playsound(target.loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
|
||||
target.visible_message("<span class='danger'>[user] attempted to disarm [target]!</span>")
|
||||
|
||||
/datum/species/proc/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style = M.martial_art) //Handles any species-specific attackhand events.
|
||||
/datum/species/proc/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style) //Handles any species-specific attackhand events.
|
||||
if(!istype(M))
|
||||
return
|
||||
if(H.frozen)
|
||||
to_chat(M, "<span class='warning'>Do not touch Admin-Frozen people.</span>")
|
||||
return
|
||||
|
||||
if(istype(M))
|
||||
var/obj/item/organ/external/temp = M.bodyparts_by_name["r_hand"]
|
||||
@@ -531,6 +528,9 @@
|
||||
to_chat(M, "<span class='warning'>You can't use your hand.</span>")
|
||||
return
|
||||
|
||||
if(M.mind)
|
||||
attacker_style = M.mind.martial_art
|
||||
|
||||
if((M != H) && M.a_intent != INTENT_HELP && H.check_shields(M, 0, M.name, attack_type = UNARMED_ATTACK))
|
||||
add_attack_logs(M, H, "Melee attacked with fists (miss/block)")
|
||||
H.visible_message("<span class='warning'>[M] attempted to touch [H]!</span>")
|
||||
@@ -817,20 +817,6 @@ It'll return null if the organ doesn't correspond, so include null checks when u
|
||||
if(!isnull(hat.lighting_alpha))
|
||||
H.lighting_alpha = min(hat.lighting_alpha, H.lighting_alpha)
|
||||
|
||||
if(istype(H.back, /obj/item/rig)) ///aghhh so snowflakey
|
||||
var/obj/item/rig/rig = H.back
|
||||
if(rig.visor)
|
||||
if(!rig.helmet || (H.head && rig.helmet == H.head))
|
||||
if(rig.visor && rig.visor.vision && rig.visor.active && rig.visor.vision.glasses)
|
||||
var/obj/item/clothing/glasses/G = rig.visor.vision.glasses
|
||||
if(istype(G))
|
||||
H.sight |= G.vision_flags
|
||||
H.see_in_dark = max(G.see_in_dark, H.see_in_dark)
|
||||
H.see_invisible = min(G.invis_view, H.see_invisible)
|
||||
|
||||
if(!isnull(G.lighting_alpha))
|
||||
H.lighting_alpha = min(G.lighting_alpha, H.lighting_alpha)
|
||||
|
||||
if(H.vision_type)
|
||||
H.sight |= H.vision_type.sight_flags
|
||||
H.see_in_dark = max(H.see_in_dark, H.vision_type.see_in_dark)
|
||||
|
||||
@@ -74,6 +74,10 @@
|
||||
..()
|
||||
H.gender = NEUTER
|
||||
|
||||
/datum/species/diona/on_species_loss(mob/living/carbon/human/H)
|
||||
. = ..()
|
||||
H.clear_alert("nolight")
|
||||
|
||||
/datum/species/diona/handle_reagents(mob/living/carbon/human/H, datum/reagent/R)
|
||||
if(R.id == "glyphosate" || R.id == "atrazine")
|
||||
H.adjustToxLoss(3) //Deal aditional damage
|
||||
@@ -81,9 +85,8 @@
|
||||
return ..()
|
||||
|
||||
/datum/species/diona/handle_life(mob/living/carbon/human/H)
|
||||
if(H.stat == DEAD)
|
||||
return
|
||||
var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing
|
||||
var/is_vamp = H.mind?.vampire != null
|
||||
if(isturf(H.loc)) //else, there's considered to be no light
|
||||
var/turf/T = H.loc
|
||||
light_amount = min(1, T.get_lumcount()) - 0.5
|
||||
@@ -91,9 +94,12 @@
|
||||
H.clear_alert("nolight")
|
||||
else
|
||||
H.throw_alert("nolight", /obj/screen/alert/nolight)
|
||||
H.adjust_nutrition(light_amount * 10)
|
||||
if(H.nutrition > NUTRITION_LEVEL_ALMOST_FULL)
|
||||
H.set_nutrition(NUTRITION_LEVEL_ALMOST_FULL)
|
||||
|
||||
if(!is_vamp)
|
||||
H.adjust_nutrition(light_amount * 10)
|
||||
if(H.nutrition > NUTRITION_LEVEL_ALMOST_FULL)
|
||||
H.set_nutrition(NUTRITION_LEVEL_ALMOST_FULL)
|
||||
|
||||
if(light_amount > 0.2 && !H.suiciding) //if there's enough light, heal
|
||||
if(!pod && H.health <= 0)
|
||||
return
|
||||
@@ -102,7 +108,7 @@
|
||||
H.adjustToxLoss(-1)
|
||||
H.adjustOxyLoss(-1)
|
||||
|
||||
if(H.nutrition < NUTRITION_LEVEL_STARVING + 50)
|
||||
if(!is_vamp && H.nutrition < NUTRITION_LEVEL_STARVING + 50)
|
||||
H.adjustBruteLoss(2)
|
||||
..()
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
death_message = "gives a short series of shrill beeps, their chassis shuddering before falling limp, nonfunctional."
|
||||
death_sounds = list('sound/voice/borg_deathsound.ogg') //I've made this a list in the event we add more sounds for dead robots.
|
||||
|
||||
species_traits = list(IS_WHITELISTED, NO_BREATHE, NO_SCAN, NO_INTORGANS, NO_PAIN, NO_DNA, RADIMMUNE, VIRUSIMMUNE, NO_GERMS, NO_DECAY, NOTRANSSTING) //Computers that don't decay? What a lie!
|
||||
species_traits = list(IS_WHITELISTED, NO_BREATHE, NO_BLOOD, NO_SCAN, NO_INTORGANS, NO_PAIN, NO_DNA, RADIMMUNE, VIRUSIMMUNE, NO_GERMS, NO_DECAY, NOTRANSSTING) //Computers that don't decay? What a lie!
|
||||
clothing_flags = HAS_UNDERWEAR | HAS_UNDERSHIRT | HAS_SOCKS
|
||||
bodyflags = HAS_SKIN_COLOR | HAS_HEAD_MARKINGS | HAS_HEAD_ACCESSORY | ALL_RPARTS
|
||||
dietflags = 0 //IPCs can't eat, so no diet
|
||||
@@ -30,10 +30,6 @@
|
||||
blood_color = "#1F181F"
|
||||
flesh_color = "#AAAAAA"
|
||||
|
||||
blood_color = "#3C3C3C"
|
||||
exotic_blood = "oil"
|
||||
blood_damage_type = STAMINA
|
||||
|
||||
//Default styles for created mobs.
|
||||
default_hair = "Blue IPC Screen"
|
||||
dies_at_threshold = TRUE
|
||||
|
||||
@@ -35,8 +35,9 @@
|
||||
"antennae" = /obj/item/organ/internal/wryn/hivenode
|
||||
)
|
||||
|
||||
species_traits = list(IS_WHITELISTED, NO_BREATHE, HAS_SKIN_COLOR, NO_SCAN, HIVEMIND)
|
||||
species_traits = list(LIPS, IS_WHITELISTED, NO_BREATHE, NO_SCAN, HIVEMIND)
|
||||
clothing_flags = HAS_UNDERWEAR | HAS_UNDERSHIRT | HAS_SOCKS
|
||||
bodyflags = HAS_SKIN_COLOR
|
||||
dietflags = DIET_HERB //bees feed off nectar, so bee people feed off plants too
|
||||
|
||||
dies_at_threshold = TRUE
|
||||
|
||||
@@ -273,11 +273,6 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
overlays_standing[UNDERWEAR_LAYER] = mutable_appearance(underwear_standing, layer = -UNDERWEAR_LAYER)
|
||||
apply_overlay(UNDERWEAR_LAYER)
|
||||
|
||||
if(lip_style && (LIPS in dna.species.species_traits))
|
||||
var/icon/lips = icon("icon" = 'icons/mob/human_face.dmi', "icon_state" = "lips_[lip_style]_s")
|
||||
lips.Blend(lip_color, ICON_ADD)
|
||||
standing += mutable_appearance(lips, layer = -BODY_LAYER)
|
||||
|
||||
overlays_standing[BODY_LAYER] = standing
|
||||
apply_overlay(BODY_LAYER)
|
||||
//tail
|
||||
@@ -964,10 +959,6 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
var/mutable_appearance/standing
|
||||
if(back.icon_override)
|
||||
standing = mutable_appearance(back.icon_override, "[back.icon_state]", layer = -BACK_LAYER)
|
||||
else if(istype(back, /obj/item/rig))
|
||||
//If this is a rig and a mob_icon is set, it will take species into account in the rig update_icon() proc.
|
||||
var/obj/item/rig/rig = back
|
||||
standing = rig.mob_icon
|
||||
else if(back.sprite_sheets && back.sprite_sheets[dna.species.name])
|
||||
standing = mutable_appearance(back.sprite_sheets[dna.species.name], "[back.icon_state]", layer = -BACK_LAYER)
|
||||
else
|
||||
@@ -1307,6 +1298,11 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
else
|
||||
. += "#000000"
|
||||
|
||||
if(lip_color && (LIPS in dna.species.species_traits))
|
||||
. += "[lip_color]"
|
||||
else
|
||||
. += "#000000"
|
||||
|
||||
for(var/organ_tag in dna.species.has_limbs)
|
||||
var/obj/item/organ/external/part = bodyparts_by_name[organ_tag]
|
||||
if(isnull(part))
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
var/list/default_genes = list(REGEN, BREATHLESS, COLDRES)
|
||||
var/list/default_spells = list()
|
||||
var/activated = FALSE //for wishgranters to not give an option if someone already has it.
|
||||
|
||||
|
||||
/datum/superheroes/proc/create(var/mob/living/carbon/human/H)
|
||||
assign_genes(H)
|
||||
assign_spells(H)
|
||||
@@ -84,7 +84,7 @@
|
||||
|
||||
/datum/superheroes/griffin
|
||||
name = "The Griffin"
|
||||
default_spells = list(/obj/effect/proc_holder/spell/targeted/recruit)
|
||||
default_spells = list(/obj/effect/proc_holder/spell/targeted/click/recruit)
|
||||
class = "Supervillain"
|
||||
desc = "You are The Griffin, the ultimate supervillain. You thrive on chaos and have no respect for the supposed authority \
|
||||
of the command staff of this station. Along with your gang of dim-witted yet trusty henchmen, you will be able to execute \
|
||||
@@ -145,100 +145,102 @@
|
||||
|
||||
|
||||
//The Griffin's special recruit abilitiy
|
||||
/obj/effect/proc_holder/spell/targeted/recruit
|
||||
/obj/effect/proc_holder/spell/targeted/click/recruit
|
||||
name = "Recruit Greyshirt"
|
||||
desc = "Allows you to recruit a conscious, non-braindead, non-catatonic human to be part of the Greyshirts, your personal henchmen. This works on Civilians only and you can recruit a maximum of 3!."
|
||||
charge_max = 450
|
||||
clothes_req = 0
|
||||
clothes_req = FALSE
|
||||
range = 1 //Adjacent to user
|
||||
action_icon_state = "spell_greytide"
|
||||
var/recruiting = 0
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/recruit/cast(list/targets,mob/living/user = usr)
|
||||
for(var/mob/living/carbon/human/target in targets)
|
||||
var/obj/item/organ/external/head/head_organ = target.get_organ("head")
|
||||
if(SSticker.mode.greyshirts.len >= 3)
|
||||
click_radius = -1
|
||||
selection_activated_message = "<span class='notice'>You start preparing a mindblowing monologue. <B>Left-click to cast at a target!</B></span>"
|
||||
selection_deactivated_message = "<span class='notice'>You decide to save your brilliance for another day.</span>"
|
||||
allowed_type = /mob/living/carbon/human
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/recruit/can_cast(mob/user = usr, charge_check = TRUE, show_message = FALSE)
|
||||
if(SSticker.mode.greyshirts.len >= 3)
|
||||
if(show_message)
|
||||
to_chat(user, "<span class='warning'>You have already recruited the maximum number of henchmen.</span>")
|
||||
if(!in_range(user, target))
|
||||
to_chat(user, "<span class='warning'>You need to be closer to enthrall [target].</span>")
|
||||
charge_counter = charge_max
|
||||
return
|
||||
if(!target.ckey)
|
||||
to_chat(user, "<span class='warning'>The target has no mind.</span>")
|
||||
charge_counter = charge_max
|
||||
return
|
||||
if(target.stat)
|
||||
to_chat(user, "<span class='warning'>The target must be conscious.</span>")
|
||||
charge_counter = charge_max
|
||||
return
|
||||
if(!ishuman(target))
|
||||
to_chat(user, "<span class='warning'>You can only recruit humans.</span>")
|
||||
charge_counter = charge_max
|
||||
return
|
||||
if(target.mind.assigned_role != "Civilian")
|
||||
to_chat(user, "<span class='warning'>You can only recruit Civilians.</span>")
|
||||
return
|
||||
if(recruiting)
|
||||
return FALSE
|
||||
if(recruiting)
|
||||
if(show_message)
|
||||
to_chat(user, "<span class='danger'>You are already recruiting!</span>")
|
||||
charge_counter = charge_max
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/recruit/valid_target(mob/living/carbon/human/target, user)
|
||||
if(!..())
|
||||
return FALSE
|
||||
|
||||
return target.ckey && !target.stat
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/recruit/cast(list/targets,mob/living/user = usr)
|
||||
var/mob/living/carbon/human/target = targets[1]
|
||||
if(target.mind.assigned_role != "Civilian")
|
||||
to_chat(user, "<span class='warning'>You can only recruit Civilians.</span>")
|
||||
revert_cast(user)
|
||||
return
|
||||
recruiting = TRUE
|
||||
to_chat(user, "<span class='danger'>This target is valid. You begin the recruiting process.</span>")
|
||||
to_chat(target, "<span class='userdanger'>[user] focuses in concentration. Your head begins to ache.</span>")
|
||||
|
||||
for(var/progress = 0, progress <= 3, progress++)
|
||||
switch(progress)
|
||||
if(1)
|
||||
to_chat(user, "<span class='notice'>You begin by introducing yourself and explaining what you're about.</span>")
|
||||
user.visible_message("<span class='danger'>[user] introduces [user.p_them()]self and explains [user.p_their()] plans.</span>")
|
||||
if(2)
|
||||
to_chat(user, "<span class='notice'>You begin the recruitment of [target].</span>")
|
||||
user.visible_message("<span class='danger'>[user] leans over towards [target], whispering excitedly as [user.p_they()] give[user.p_s()] a speech.</span>")
|
||||
to_chat(target, "<span class='danger'>You feel yourself agreeing with [user], and a surge of loyalty begins building.</span>")
|
||||
target.Weaken(12)
|
||||
sleep(20)
|
||||
if(ismindshielded(target))
|
||||
to_chat(user, "<span class='notice'>[target.p_they(TRUE)] are enslaved by Nanotrasen. You feel [target.p_their()] interest in your cause wane and disappear.</span>")
|
||||
user.visible_message("<span class='danger'>[user] stops talking for a moment, then moves back away from [target].</span>")
|
||||
to_chat(target, "<span class='danger'>Your mindshield implant activates, protecting you from conversion.</span>")
|
||||
return
|
||||
if(3)
|
||||
to_chat(user, "<span class='notice'>You begin filling out the application form with [target].</span>")
|
||||
user.visible_message("<span class='danger'>[user] pulls out a pen and paper and begins filling an application form with [target].</span>")
|
||||
to_chat(target, "<span class='danger'>You are being convinced by [user] to fill out an application form to become a henchman.</span>")//Ow the edge
|
||||
|
||||
if(!do_mob(user, target, 100)) //around 30 seconds total for enthralling, 45 for someone with a mindshield implant
|
||||
to_chat(user, "<span class='danger'>The enrollment process has been interrupted - you have lost the attention of [target].</span>")
|
||||
to_chat(target, "<span class='warning'>You move away and are no longer under the charm of [user]. The application form is null and void.</span>")
|
||||
recruiting = FALSE
|
||||
return
|
||||
recruiting = 1
|
||||
to_chat(user, "<span class='danger'>This target is valid. You begin the recruiting process.</span>")
|
||||
to_chat(target, "<span class='userdanger'>[user] focuses in concentration. Your head begins to ache.</span>")
|
||||
|
||||
for(var/progress = 0, progress <= 3, progress++)
|
||||
switch(progress)
|
||||
if(1)
|
||||
to_chat(user, "<span class='notice'>You begin by introducing yourself and explaining what you're about.</span>")
|
||||
user.visible_message("<span class='danger'>[user] introduces [user.p_them()]self and explains [user.p_their()] plans.</span>")
|
||||
if(2)
|
||||
to_chat(user, "<span class='notice'>You begin the recruitment of [target].</span>")
|
||||
user.visible_message("<span class='danger'>[user] leans over towards [target], whispering excitedly as [user.p_they()] give[user.p_s()] a speech.</span>")
|
||||
to_chat(target, "<span class='danger'>You feel yourself agreeing with [user], and a surge of loyalty begins building.</span>")
|
||||
target.Weaken(12)
|
||||
sleep(20)
|
||||
if(ismindshielded(target))
|
||||
to_chat(user, "<span class='notice'>[target.p_they(TRUE)] are enslaved by Nanotrasen. You feel [target.p_their()] interest in your cause wane and disappear.</span>")
|
||||
user.visible_message("<span class='danger'>[user] stops talking for a moment, then moves back away from [target].</span>")
|
||||
to_chat(target, "<span class='danger'>Your mindshield implant activates, protecting you from conversion.</span>")
|
||||
return
|
||||
if(3)
|
||||
to_chat(user, "<span class='notice'>You begin filling out the application form with [target].</span>")
|
||||
user.visible_message("<span class='danger'>[user] pulls out a pen and paper and begins filling an application form with [target].</span>")
|
||||
to_chat(target, "<span class='danger'>You are being convinced by [user] to fill out an application form to become a henchman.</span>")//Ow the edge
|
||||
|
||||
if(!do_mob(user, target, 100)) //around 30 seconds total for enthralling, 45 for someone with a mindshield implant
|
||||
to_chat(user, "<span class='danger'>The enrollment process has been interrupted - you have lost the attention of [target].</span>")
|
||||
to_chat(target, "<span class='warning'>You move away and are no longer under the charm of [user]. The application form is null and void.</span>")
|
||||
recruiting = 0
|
||||
return
|
||||
|
||||
recruiting = 0
|
||||
to_chat(user, "<span class='notice'>You have recruited <b>[target]</b> as your henchman!</span>")
|
||||
to_chat(target, "<span class='deadsay'><b>You have decided to enroll as a henchman for [user]. You are now part of the feared 'Greyshirts'.</b></span>")
|
||||
to_chat(target, "<span class='deadsay'><b>You must follow the orders of [user], and help [user.p_them()] succeed in [user.p_their()] dastardly schemes.</span>")
|
||||
to_chat(target, "<span class='deadsay'>You may not harm other Greyshirt or [user]. However, you do not need to obey other Greyshirts.</span>")
|
||||
SSticker.mode.greyshirts += target.mind
|
||||
target.set_species(/datum/species/human)
|
||||
recruiting = FALSE
|
||||
to_chat(user, "<span class='notice'>You have recruited <b>[target]</b> as your henchman!</span>")
|
||||
to_chat(target, "<span class='deadsay'><b>You have decided to enroll as a henchman for [user]. You are now part of the feared 'Greyshirts'.</b></span>")
|
||||
to_chat(target, "<span class='deadsay'><b>You must follow the orders of [user], and help [user.p_them()] succeed in [user.p_their()] dastardly schemes.</span>")
|
||||
to_chat(target, "<span class='deadsay'>You may not harm other Greyshirt or [user]. However, you do not need to obey other Greyshirts.</span>")
|
||||
SSticker.mode.greyshirts += target.mind
|
||||
target.set_species(/datum/species/human)
|
||||
var/obj/item/organ/external/head/head_organ = target.get_organ("head")
|
||||
if(head_organ)
|
||||
head_organ.h_style = "Bald"
|
||||
head_organ.f_style = "Shaved"
|
||||
target.s_tone = 35
|
||||
// No `update_dna=0` here because the character is being over-written
|
||||
target.change_eye_color(1,1,1)
|
||||
for(var/obj/item/W in target.get_all_slots())
|
||||
target.unEquip(W)
|
||||
target.rename_character(target.real_name, "Generic Henchman ([rand(1, 1000)])")
|
||||
target.equip_to_slot_or_del(new /obj/item/clothing/under/color/grey/greytide(target), slot_w_uniform)
|
||||
target.equip_to_slot_or_del(new /obj/item/clothing/shoes/black/greytide(target), slot_shoes)
|
||||
target.equip_to_slot_or_del(new /obj/item/storage/toolbox/mechanical/greytide(target), slot_l_hand)
|
||||
target.equip_to_slot_or_del(new /obj/item/radio/headset(target), slot_l_ear)
|
||||
var/obj/item/card/id/syndicate/W = new(target)
|
||||
W.icon_state = "lifetimeid"
|
||||
W.access = list(ACCESS_MAINT_TUNNELS)
|
||||
W.assignment = "Greyshirt"
|
||||
W.rank = "Greyshirt"
|
||||
W.flags |= NODROP
|
||||
W.SetOwnerInfo(target)
|
||||
W.UpdateName()
|
||||
target.equip_to_slot_or_del(W, slot_wear_id)
|
||||
target.regenerate_icons()
|
||||
target.s_tone = 35
|
||||
// No `update_dna=0` here because the character is being over-written
|
||||
target.change_eye_color(1,1,1)
|
||||
for(var/obj/item/W in target.get_all_slots())
|
||||
target.unEquip(W)
|
||||
target.rename_character(target.real_name, "Generic Henchman ([rand(1, 1000)])")
|
||||
target.equip_to_slot_or_del(new /obj/item/clothing/under/color/grey/greytide(target), slot_w_uniform)
|
||||
target.equip_to_slot_or_del(new /obj/item/clothing/shoes/black/greytide(target), slot_shoes)
|
||||
target.equip_to_slot_or_del(new /obj/item/storage/toolbox/mechanical/greytide(target), slot_l_hand)
|
||||
target.equip_to_slot_or_del(new /obj/item/radio/headset(target), slot_l_ear)
|
||||
var/obj/item/card/id/syndicate/W = new(target)
|
||||
W.icon_state = "lifetimeid"
|
||||
W.access = list(ACCESS_MAINT_TUNNELS)
|
||||
W.assignment = "Greyshirt"
|
||||
W.rank = "Greyshirt"
|
||||
W.flags |= NODROP
|
||||
W.SetOwnerInfo(target)
|
||||
W.UpdateName()
|
||||
target.equip_to_slot_or_del(W, slot_wear_id)
|
||||
target.regenerate_icons()
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
if(changed)
|
||||
animate(src, transform = ntransform, time = 2, pixel_y = final_pixel_y, dir = final_dir, easing = EASE_IN|EASE_OUT)
|
||||
handle_transform_change()
|
||||
floating = 0 // If we were without gravity, the bouncing animation got stopped, so we make sure we restart it in next life().
|
||||
floating = FALSE // If we were without gravity, the bouncing animation got stopped, so we make sure we restart it in next life().
|
||||
|
||||
/mob/living/carbon/proc/handle_transform_change()
|
||||
return
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
// Whew! Good thing I'm indestructible! (or already dead)
|
||||
return FALSE
|
||||
|
||||
..()
|
||||
stat = DEAD
|
||||
SetDizzy(0)
|
||||
SetJitter(0)
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
set waitfor = FALSE
|
||||
set invisibility = 0
|
||||
|
||||
if(flying) //TODO: Better floating
|
||||
animate(src, pixel_y = pixel_y + 5 , time = 10, loop = 1, easing = SINE_EASING)
|
||||
animate(pixel_y = pixel_y - 5, time = 10, loop = 1, easing = SINE_EASING)
|
||||
if(flying && !floating) //TODO: Better floating
|
||||
float(TRUE)
|
||||
|
||||
if(client || registered_z) // This is a temporary error tracker to make sure we've caught everything
|
||||
var/turf/T = get_turf(src)
|
||||
|
||||
@@ -3,8 +3,29 @@
|
||||
var/datum/atom_hud/data/human/medical/advanced/medhud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
|
||||
medhud.add_to_hud(src)
|
||||
faction += "\ref[src]"
|
||||
determine_move_and_pull_forces()
|
||||
GLOB.mob_living_list += src
|
||||
|
||||
// Used to determine the forces dependend on the mob size
|
||||
// Will only change the force if the force was not set in the mob type itself
|
||||
/mob/living/proc/determine_move_and_pull_forces()
|
||||
var/value
|
||||
switch(mob_size)
|
||||
if(MOB_SIZE_TINY)
|
||||
value = MOVE_FORCE_EXTREMELY_WEAK
|
||||
if(MOB_SIZE_SMALL)
|
||||
value = MOVE_FORCE_WEAK
|
||||
if(MOB_SIZE_HUMAN)
|
||||
value = MOVE_FORCE_NORMAL
|
||||
if(MOB_SIZE_LARGE)
|
||||
value = MOVE_FORCE_NORMAL // For now
|
||||
if(!move_force)
|
||||
move_force = value
|
||||
if(!pull_force)
|
||||
pull_force = value
|
||||
if(!move_resist)
|
||||
move_resist = value
|
||||
|
||||
/mob/living/prepare_huds()
|
||||
..()
|
||||
prepare_data_huds()
|
||||
@@ -59,8 +80,9 @@
|
||||
//Even if we don't push/swap places, we "touched" them, so spread fire
|
||||
spreadFire(M)
|
||||
|
||||
if(now_pushing)
|
||||
return 1
|
||||
// No pushing if we're already pushing past something, or if the mob we're pushing into is anchored.
|
||||
if(now_pushing || M.anchored)
|
||||
return TRUE
|
||||
|
||||
//Should stop you pushing a restrained person out of the way
|
||||
if(isliving(M))
|
||||
@@ -68,7 +90,7 @@
|
||||
if(L.pulledby && L.pulledby != src && L.restrained())
|
||||
if(!(world.time % 5))
|
||||
to_chat(src, "<span class='warning'>[L] is restrained, you cannot push past.</span>")
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
if(L.pulling)
|
||||
if(ismob(L.pulling))
|
||||
@@ -76,28 +98,28 @@
|
||||
if(P.restrained())
|
||||
if(!(world.time % 5))
|
||||
to_chat(src, "<span class='warning'>[L] is restrained, you cannot push past.</span>")
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
if(moving_diagonally) //no mob swap during diagonal moves.
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
if(a_intent == INTENT_HELP) // Help intent doesn't mob swap a mob pulling a structure
|
||||
if(isstructure(M.pulling) || isstructure(pulling))
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
if(!M.buckled && !M.has_buckled_mobs())
|
||||
var/mob_swap
|
||||
//the puller can always swap with it's victim if on grab intent
|
||||
if(M.pulledby == src && a_intent == INTENT_GRAB)
|
||||
mob_swap = 1
|
||||
mob_swap = TRUE
|
||||
//restrained people act if they were on 'help' intent to prevent a person being pulled from being seperated from their puller
|
||||
else if((M.restrained() || M.a_intent == INTENT_HELP) && (restrained() || a_intent == INTENT_HELP))
|
||||
mob_swap = 1
|
||||
mob_swap = TRUE
|
||||
if(mob_swap)
|
||||
//switch our position with M
|
||||
if(loc && !loc.Adjacent(M.loc))
|
||||
return 1
|
||||
now_pushing = 1
|
||||
return TRUE
|
||||
now_pushing = TRUE
|
||||
var/oldloc = loc
|
||||
var/oldMloc = M.loc
|
||||
|
||||
@@ -114,18 +136,18 @@
|
||||
if(!M_passmob)
|
||||
M.pass_flags &= ~PASSMOB
|
||||
|
||||
now_pushing = 0
|
||||
return 1
|
||||
now_pushing = FALSE
|
||||
return TRUE
|
||||
|
||||
// okay, so we didn't switch. but should we push?
|
||||
// not if he's not CANPUSH of course
|
||||
if(!(M.status_flags & CANPUSH))
|
||||
return 1
|
||||
return TRUE
|
||||
//anti-riot equipment is also anti-push
|
||||
if(M.r_hand && (prob(M.r_hand.block_chance * 2)) && !istype(M.r_hand, /obj/item/clothing))
|
||||
return 1
|
||||
return TRUE
|
||||
if(M.l_hand && (prob(M.l_hand.block_chance * 2)) && !istype(M.l_hand, /obj/item/clothing))
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
//Called when we bump into an obj
|
||||
/mob/living/proc/ObjBump(obj/O)
|
||||
@@ -175,13 +197,6 @@
|
||||
AM.setDir(current_dir)
|
||||
now_pushing = FALSE
|
||||
|
||||
/mob/living/Stat()
|
||||
. = ..()
|
||||
if(. && get_rig_stats)
|
||||
var/obj/item/rig/rig = get_rig()
|
||||
if(rig)
|
||||
SetupStat(rig)
|
||||
|
||||
/mob/living/proc/can_track(mob/living/user)
|
||||
//basic fast checks go first. When overriding this proc, I recommend calling ..() at the end.
|
||||
var/turf/T = get_turf(src)
|
||||
@@ -209,7 +224,7 @@
|
||||
set category = "Object"
|
||||
|
||||
if(istype(AM) && Adjacent(AM))
|
||||
start_pulling(AM)
|
||||
start_pulling(AM, show_message = TRUE)
|
||||
else
|
||||
stop_pulling()
|
||||
|
||||
@@ -743,16 +758,17 @@
|
||||
/mob/living/proc/float(on)
|
||||
if(throwing)
|
||||
return
|
||||
var/fixed = 0
|
||||
var/fixed = FALSE
|
||||
if(anchored || (buckled && buckled.anchored))
|
||||
fixed = 1
|
||||
fixed = TRUE
|
||||
if(on && !floating && !fixed)
|
||||
animate(src, pixel_y = pixel_y + 2, time = 10, loop = -1)
|
||||
floating = 1
|
||||
sleep(10)
|
||||
animate(src, pixel_y = pixel_y - 2, time = 10, loop = -1)
|
||||
floating = TRUE
|
||||
else if(((!on || fixed) && floating))
|
||||
var/final_pixel_y = get_standard_pixel_y_offset(lying)
|
||||
animate(src, pixel_y = final_pixel_y, time = 10)
|
||||
floating = 0
|
||||
animate(src, pixel_y = get_standard_pixel_y_offset(lying), time = 10)
|
||||
floating = FALSE
|
||||
|
||||
/mob/living/proc/can_use_vents()
|
||||
return "You can't fit into that vent."
|
||||
@@ -827,15 +843,17 @@
|
||||
if(!used_item)
|
||||
used_item = get_active_hand()
|
||||
..()
|
||||
floating = 0 // If we were without gravity, the bouncing animation got stopped, so we make sure we restart the bouncing after the next movement.
|
||||
floating = FALSE // If we were without gravity, the bouncing animation got stopped, so we make sure we restart the bouncing after the next movement.
|
||||
|
||||
/mob/living/proc/do_jitter_animation(jitteriness, loop_amount = 6)
|
||||
var/amplitude = min(4, (jitteriness/100) + 1)
|
||||
var/amplitude = min(4, (jitteriness / 100) + 1)
|
||||
var/pixel_x_diff = rand(-amplitude, amplitude)
|
||||
var/pixel_y_diff = rand(-amplitude/3, amplitude/3)
|
||||
var/pixel_y_diff = rand(-amplitude / 3, amplitude / 3)
|
||||
var/final_pixel_x = get_standard_pixel_x_offset(lying)
|
||||
var/final_pixel_y = get_standard_pixel_y_offset(lying)
|
||||
animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff , time = 2, loop = loop_amount)
|
||||
animate(pixel_x = initial(pixel_x) , pixel_y = initial(pixel_y) , time = 2)
|
||||
floating = 0 // If we were without gravity, the bouncing animation got stopped, so we make sure we restart the bouncing after the next movement.
|
||||
animate(pixel_x = final_pixel_x , pixel_y = final_pixel_y , time = 2)
|
||||
floating = FALSE // If we were without gravity, the bouncing animation got stopped, so we make sure we restart the bouncing after the next movement.
|
||||
|
||||
|
||||
/mob/living/proc/get_temperature(datum/gas_mixture/environment)
|
||||
@@ -909,6 +927,8 @@
|
||||
. += T.slowdown
|
||||
if(slowed)
|
||||
. += 10
|
||||
if(forced_look)
|
||||
. += 3
|
||||
if(ignorewalk)
|
||||
. += config.run_speed
|
||||
else
|
||||
@@ -927,10 +947,10 @@
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/mob/living/start_pulling(atom/movable/AM, state, force = pull_force, supress_message = FALSE)
|
||||
/mob/living/start_pulling(atom/movable/AM, state, force = pull_force, show_message = FALSE)
|
||||
if(!AM || !src)
|
||||
return FALSE
|
||||
if(!(AM.can_be_pulled(src, state, force)))
|
||||
if(!(AM.can_be_pulled(src, state, force, show_message)))
|
||||
return FALSE
|
||||
if(incapacitated())
|
||||
return
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
var/armor = run_armor_check(zone, "melee", "Your armor has protected your [parse_zone(zone)].", "Your armor has softened hit to your [parse_zone(zone)].", I.armour_penetration)
|
||||
apply_damage(I.throwforce, dtype, zone, armor, is_sharp(I), I)
|
||||
if(I.thrownby)
|
||||
add_attack_logs(I.thrownby, src, "Hit with thrown [I]")
|
||||
add_attack_logs(I.thrownby, src, "Hit with thrown [I]", !I.throwforce ? ATKLOG_ALMOSTALL : null) // Only message if the person gets damages
|
||||
else
|
||||
return 1
|
||||
else
|
||||
@@ -186,6 +186,8 @@
|
||||
return 1
|
||||
if(fire_stacks > 0)
|
||||
adjust_fire_stacks(-0.1) //the fire is slowly consumed
|
||||
for(var/obj/item/clothing/C in contents)
|
||||
C.catch_fire()
|
||||
else
|
||||
ExtinguishMob()
|
||||
return
|
||||
@@ -219,7 +221,7 @@
|
||||
fire_stacks += L.fire_stacks
|
||||
IgniteMob()
|
||||
|
||||
/mob/living/can_be_pulled(user, grab_state, force)
|
||||
/mob/living/can_be_pulled(user, grab_state, force, show_message = FALSE)
|
||||
return ..() && !(buckled && buckled.buckle_prevents_pull)
|
||||
|
||||
/mob/living/water_act(volume, temperature, source, method = REAGENT_TOUCH)
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
see_invisible = SEE_INVISIBLE_LIVING
|
||||
pressure_resistance = 10
|
||||
|
||||
// Will be determined based on mob size if left null. Done in living/proc/determine_move_and_pull_forces()
|
||||
move_resist = null
|
||||
move_force = null
|
||||
pull_force = null
|
||||
|
||||
//Health and life related vars
|
||||
var/maxHealth = 100 //Maximum health that should be possible.
|
||||
var/health = 100 //A mob's health
|
||||
@@ -28,7 +33,7 @@
|
||||
var/on_fire = 0 //The "Are we on fire?" var
|
||||
var/fire_stacks = 0 //Tracks how many stacks of fire we have on, max is usually 20
|
||||
|
||||
var/floating = 0
|
||||
var/floating = FALSE
|
||||
var/mob_size = MOB_SIZE_HUMAN
|
||||
var/metabolism_efficiency = 1 //more or less efficiency to metabolize helpful/harmful reagents and regulate body temperature..
|
||||
var/digestion_ratio = 1 //controls how quickly reagents metabolize; largely governered by species attributes.
|
||||
|
||||
@@ -38,7 +38,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
|
||||
|
||||
GLOBAL_LIST_EMPTY(channel_to_radio_key)
|
||||
|
||||
proc/get_radio_key_from_channel(var/channel)
|
||||
/proc/get_radio_key_from_channel(var/channel)
|
||||
var/key = GLOB.channel_to_radio_key[channel]
|
||||
if(!key)
|
||||
for(var/radio_key in GLOB.department_radio_keys)
|
||||
@@ -351,8 +351,6 @@ proc/get_radio_key_from_channel(var/channel)
|
||||
return
|
||||
|
||||
if(stat)
|
||||
if(stat == DEAD)
|
||||
return say_dead(message_pieces)
|
||||
return
|
||||
|
||||
if(is_muzzled())
|
||||
@@ -451,14 +449,14 @@ proc/get_radio_key_from_channel(var/channel)
|
||||
var/speech_bubble_test = say_test(message)
|
||||
|
||||
for(var/mob/M in listening)
|
||||
M.hear_say(message_pieces, verb, italics, src)
|
||||
M.hear_say(message_pieces, verb, italics, src, use_voice = FALSE)
|
||||
if(M.client)
|
||||
speech_bubble_recipients.Add(M.client)
|
||||
|
||||
if(eavesdropping.len)
|
||||
stars_all(message_pieces) //hopefully passing the message twice through stars() won't hurt... I guess if you already don't understand the language, when they speak it too quietly to hear normally you would be able to catch even less.
|
||||
for(var/mob/M in eavesdropping)
|
||||
M.hear_say(message_pieces, verb, italics, src)
|
||||
M.hear_say(message_pieces, verb, italics, src, use_voice = FALSE)
|
||||
if(M.client)
|
||||
speech_bubble_recipients.Add(M.client)
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
var/list/connected_robots = list()
|
||||
var/aiRestorePowerRoutine = 0
|
||||
//var/list/laws = list()
|
||||
var/alarms = list("Motion" = list(), "Fire" = list(), "Atmosphere" = list(), "Power" = list(), "Camera" = list())
|
||||
alarms_listend_for = list("Motion", "Fire", "Atmosphere", "Power", "Camera", "Burglar")
|
||||
var/viewalerts = 0
|
||||
var/icon/holo_icon//Default is assigned when AI is created.
|
||||
var/obj/mecha/controlled_mech //For controlled_mech a mech, to determine whether to relaymove or use the AI eye.
|
||||
@@ -63,6 +63,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
|
||||
//MALFUNCTION
|
||||
var/datum/module_picker/malf_picker
|
||||
var/datum/action/innate/ai/choose_modules/modules_action
|
||||
var/list/datum/AI_Module/current_modules = list()
|
||||
var/can_dominate_mechs = 0
|
||||
var/shunted = 0 //1 if the AI is currently shunted. Used to differentiate between shunted and ghosted/braindead
|
||||
@@ -172,19 +173,19 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
add_language("Galactic Common", 1)
|
||||
add_language("Sol Common", 1)
|
||||
add_language("Tradeband", 1)
|
||||
add_language("Neo-Russkiya", 0)
|
||||
add_language("Gutter", 0)
|
||||
add_language("Sinta'unathi", 0)
|
||||
add_language("Siik'tajr", 0)
|
||||
add_language("Canilunzt", 0)
|
||||
add_language("Skrellian", 0)
|
||||
add_language("Vox-pidgin", 0)
|
||||
add_language("Orluum", 0)
|
||||
add_language("Rootspeak", 0)
|
||||
add_language("Neo-Russkiya", 1)
|
||||
add_language("Gutter", 1)
|
||||
add_language("Sinta'unathi", 1)
|
||||
add_language("Siik'tajr", 1)
|
||||
add_language("Canilunzt", 1)
|
||||
add_language("Skrellian", 1)
|
||||
add_language("Vox-pidgin", 1)
|
||||
add_language("Orluum", 1)
|
||||
add_language("Rootspeak", 1)
|
||||
add_language("Trinary", 1)
|
||||
add_language("Chittin", 0)
|
||||
add_language("Bubblish", 0)
|
||||
add_language("Clownish", 0)
|
||||
add_language("Chittin", 1)
|
||||
add_language("Bubblish", 1)
|
||||
add_language("Clownish", 1)
|
||||
|
||||
if(!safety)//Only used by AIize() to successfully spawn an AI.
|
||||
if(!B)//If there is no player/brain inside.
|
||||
@@ -241,6 +242,46 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
return
|
||||
show_borg_info()
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_alerts()
|
||||
var/list/dat = list("<HEAD><TITLE>Current Station Alerts</TITLE><META HTTP-EQUIV='Refresh' CONTENT='10'></HEAD><BODY>\n")
|
||||
dat += "<A HREF='?src=[UID()];mach_close=aialerts'>Close</A><BR><BR>"
|
||||
var/list/list/temp_alarm_list = SSalarm.alarms.Copy()
|
||||
for(var/cat in temp_alarm_list)
|
||||
if(!(cat in alarms_listend_for))
|
||||
continue
|
||||
dat += text("<B>[]</B><BR>\n", cat)
|
||||
var/list/list/L = temp_alarm_list[cat].Copy()
|
||||
for(var/alarm in L)
|
||||
var/list/list/alm = L[alarm].Copy()
|
||||
var/area_name = alm[1]
|
||||
var/C = alm[2]
|
||||
var/list/list/sources = alm[3].Copy()
|
||||
for(var/thing in sources)
|
||||
var/atom/A = locateUID(thing)
|
||||
if(A && A.z != z)
|
||||
L -= alarm
|
||||
continue
|
||||
dat += "<NOBR>"
|
||||
if(C && islist(C))
|
||||
var/dat2 = ""
|
||||
for(var/cam in C)
|
||||
var/obj/machinery/camera/I = locateUID(cam)
|
||||
if(!QDELETED(I))
|
||||
dat2 += text("[]<A HREF=?src=[UID()];switchcamera=[cam]>[]</A>", (dat2 == "") ? "" : " | ", I.c_tag)
|
||||
dat += text("-- [] ([])", area_name, (dat2 != "") ? dat2 : "No Camera")
|
||||
else
|
||||
dat += text("-- [] (No Camera)", area_name)
|
||||
if(sources.len > 1)
|
||||
dat += text("- [] sources", sources.len)
|
||||
dat += "</NOBR><BR>\n"
|
||||
if(!L.len)
|
||||
dat += "-- All Systems Nominal<BR>\n"
|
||||
dat += "<BR>\n"
|
||||
|
||||
viewalerts = TRUE
|
||||
var/dat_text = dat.Join("")
|
||||
src << browse(dat_text, "window=aialerts&can_close=0")
|
||||
|
||||
/mob/living/silicon/ai/proc/show_borg_info()
|
||||
stat(null, text("Connected cyborgs: [connected_robots.len]"))
|
||||
for(var/thing in connected_robots)
|
||||
@@ -611,7 +652,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
if(href_list["switchcamera"])
|
||||
switchCamera(locate(href_list["switchcamera"])) in GLOB.cameranet.cameras
|
||||
if(href_list["showalerts"])
|
||||
subsystem_alarm_monitor()
|
||||
ai_alerts()
|
||||
if(href_list["show_paper"])
|
||||
if(last_paper_seen)
|
||||
src << browse(last_paper_seen, "window=show_paper")
|
||||
@@ -786,12 +827,49 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
|
||||
Bot.call_bot(src, waypoint)
|
||||
|
||||
/mob/living/silicon/ai/alarm_triggered(src, class, area/A, list/O, obj/alarmsource)
|
||||
if(!(class in alarms_listend_for))
|
||||
return
|
||||
if(alarmsource.z != z)
|
||||
return
|
||||
if(stat == DEAD)
|
||||
return TRUE
|
||||
if(O)
|
||||
var/obj/machinery/camera/C = locateUID(O[1])
|
||||
if(O.len == 1 && !QDELETED(C) && C.can_use())
|
||||
queueAlarm("--- [class] alarm detected in [A.name]! (<A HREF=?src=[UID()];switchcamera=[O[1]]>[C.c_tag]</A>)", class)
|
||||
else if(O && O.len)
|
||||
var/foo = 0
|
||||
var/dat2 = ""
|
||||
for(var/thing in O)
|
||||
var/obj/machinery/camera/I = locateUID(thing)
|
||||
if(!QDELETED(I))
|
||||
dat2 += text("[]<A HREF=?src=[UID()];switchcamera=[thing]>[]</A>", (!foo) ? "" : " | ", I.c_tag) //I'm not fixing this shit...
|
||||
foo = 1
|
||||
queueAlarm(text ("--- [] alarm detected in []! ([])", class, A.name, dat2), class)
|
||||
else
|
||||
queueAlarm(text("--- [] alarm detected in []! (No Camera)", class, A.name), class)
|
||||
else
|
||||
queueAlarm(text("--- [] alarm detected in []! (No Camera)", class, A.name), class)
|
||||
if(viewalerts)
|
||||
ai_alerts()
|
||||
|
||||
/mob/living/silicon/ai/alarm_cancelled(src, class, area/A, obj/origin, cleared)
|
||||
if(cleared)
|
||||
if(!(class in alarms_listend_for))
|
||||
return
|
||||
if(origin.z != z)
|
||||
return
|
||||
queueAlarm("--- [class] alarm in [A.name] has been cleared.", class, 0)
|
||||
if(viewalerts)
|
||||
ai_alerts()
|
||||
|
||||
/mob/living/silicon/ai/proc/switchCamera(obj/machinery/camera/C)
|
||||
|
||||
if(!tracking)
|
||||
cameraFollow = null
|
||||
|
||||
if(!C || stat == DEAD) //C.can_use())
|
||||
if(QDELETED(C) || stat == DEAD) //C.can_use())
|
||||
return FALSE
|
||||
|
||||
if(!eyeobj)
|
||||
@@ -851,13 +929,6 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
to_chat(src, "<span class='notice'>Switched to [network] camera network.</span>")
|
||||
//End of code by Mord_Sith
|
||||
|
||||
|
||||
/mob/living/silicon/ai/proc/choose_modules()
|
||||
set category = "Malfunction"
|
||||
set name = "Choose Module"
|
||||
|
||||
malf_picker.use(src)
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_statuschange()
|
||||
set category = "AI Commands"
|
||||
set name = "AI Status"
|
||||
@@ -1028,15 +1099,6 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
|
||||
return
|
||||
|
||||
/mob/living/silicon/ai/proc/corereturn()
|
||||
set category = "Malfunction"
|
||||
set name = "Return to Main Core"
|
||||
|
||||
var/obj/machinery/power/apc/apc = loc
|
||||
if(!istype(apc))
|
||||
to_chat(src, "<span class='notice'>You are already in your Main Core.</span>")
|
||||
return
|
||||
apc.malfvacate()
|
||||
|
||||
//Toggles the luminosity and applies it by re-entereing the camera.
|
||||
/mob/living/silicon/ai/proc/toggle_camera_light()
|
||||
@@ -1181,16 +1243,6 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
/mob/living/silicon/ai/can_buckle()
|
||||
return FALSE
|
||||
|
||||
// Pass lying down or getting up to our pet human, if we're in a rig.
|
||||
/mob/living/silicon/ai/lay_down()
|
||||
set name = "Rest"
|
||||
set category = "IC"
|
||||
|
||||
resting = 0
|
||||
var/obj/item/rig/rig = get_rig()
|
||||
if(rig)
|
||||
rig.force_rest(src)
|
||||
|
||||
/mob/living/silicon/ai/switch_to_camera(obj/machinery/camera/C)
|
||||
if(!C.can_use() || !is_in_chassis())
|
||||
return FALSE
|
||||
@@ -1244,8 +1296,17 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
to_chat(src, "In the top right corner of the screen you will find the Malfunctions tab, where you can purchase various abilities, from upgraded surveillance to station ending doomsday devices.")
|
||||
to_chat(src, "You are also capable of hacking APCs, which grants you more points to spend on your Malfunction powers. The drawback is that a hacked APC will give you away if spotted by the crew. Hacking an APC takes 60 seconds.")
|
||||
view_core() //A BYOND bug requires you to be viewing your core before your verbs update
|
||||
verbs += /mob/living/silicon/ai/proc/choose_modules
|
||||
malf_picker = new /datum/module_picker
|
||||
modules_action = new(malf_picker)
|
||||
modules_action.Grant(src)
|
||||
|
||||
///Removes all malfunction-related /datum/action's from the target AI.
|
||||
/mob/living/silicon/ai/proc/remove_malf_abilities()
|
||||
QDEL_NULL(modules_action)
|
||||
for(var/datum/AI_Module/AM in current_modules)
|
||||
for(var/datum/action/A in actions)
|
||||
if(istype(A, initial(AM.power_type)))
|
||||
qdel(A)
|
||||
|
||||
/mob/living/silicon/ai/proc/open_nearest_door(mob/living/target)
|
||||
if(!istype(target))
|
||||
@@ -1271,8 +1332,10 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
if(istype(A))
|
||||
switch(alert(src, "Do you want to open \the [A] for [target]?", "Doorknob_v2a.exe", "Yes", "No"))
|
||||
if("Yes")
|
||||
A.AIShiftClick()
|
||||
to_chat(src, "<span class='notice'>You open \the [A] for [target].</span>")
|
||||
if(!A.density)
|
||||
to_chat(src, "<span class='notice'>[A] was already opened.</span>")
|
||||
else if(A.open_close(src))
|
||||
to_chat(src, "<span class='notice'>You open \the [A] for [target].</span>")
|
||||
else
|
||||
to_chat(src, "<span class='warning'>You deny the request.</span>")
|
||||
else
|
||||
|
||||
@@ -142,7 +142,7 @@
|
||||
acceleration = !acceleration
|
||||
to_chat(usr, "Camera acceleration has been toggled [acceleration ? "on" : "off"].")
|
||||
|
||||
/mob/camera/aiEye/hear_say(list/message_pieces, verb = "says", italics = 0, mob/speaker = null, sound/speech_sound, sound_vol, sound_frequency)
|
||||
/mob/camera/aiEye/hear_say(list/message_pieces, verb = "says", italics = 0, mob/speaker = null, sound/speech_sound, sound_vol, sound_frequency, use_voice = TRUE)
|
||||
if(relay_speech)
|
||||
if(istype(ai))
|
||||
ai.relay_speech(speaker, message_pieces, verb)
|
||||
|
||||
@@ -132,8 +132,6 @@
|
||||
sleep(50)
|
||||
theAPC = null
|
||||
|
||||
process_queued_alarms()
|
||||
|
||||
/mob/living/silicon/ai/updatehealth(reason = "none given")
|
||||
if(status_flags & GODMODE)
|
||||
health = 100
|
||||
|
||||
@@ -80,17 +80,26 @@ GLOBAL_VAR_INIT(announcing_vox, 0) // Stores the time of the last announcement
|
||||
<LI>Do not use punctuation as you would normally, if you want a pause you can use the full stop and comma characters by separating them with spaces, like so: 'Alpha . Test , Bravo'.</LI></UL>\
|
||||
<font class='bad'>WARNING:</font><BR>Misuse of the announcement system will get you job banned.<HR>"
|
||||
|
||||
var/index = 0
|
||||
for(var/word in GLOB.vox_sounds)
|
||||
index++
|
||||
dat += "<A href='?src=[UID()];say_word=[word]'>[capitalize(word)]</A>"
|
||||
if(index != GLOB.vox_sounds.len)
|
||||
dat += " / "
|
||||
// Show alert and voice sounds separately
|
||||
var/vox_words = GLOB.vox_sounds - GLOB.vox_alerts
|
||||
dat = help_format(GLOB.vox_alerts, dat)
|
||||
dat = help_format(vox_words, dat)
|
||||
|
||||
var/datum/browser/popup = new(src, "announce_help", "Announcement Help", 500, 400)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
/mob/living/silicon/ai/proc/help_format(word_list, dat)
|
||||
var/index = 0
|
||||
for(var/word in word_list)
|
||||
index++
|
||||
dat += "<A href='?src=[UID()];say_word=[word]'>[capitalize(word)]</A>"
|
||||
if(index != length(word_list))
|
||||
dat += " / "
|
||||
else
|
||||
dat += "<HR>"
|
||||
return dat
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_announcement()
|
||||
if(check_unable(AI_CHECK_WIRELESS | AI_CHECK_RADIO))
|
||||
return
|
||||
|
||||
@@ -435,9 +435,6 @@
|
||||
// Pass lying down or getting up to our pet human, if we're in a rig.
|
||||
if(stat == CONSCIOUS && istype(loc,/obj/item/paicard))
|
||||
resting = 0
|
||||
var/obj/item/rig/rig = get_rig()
|
||||
if(istype(rig))
|
||||
rig.force_rest(src)
|
||||
else
|
||||
resting = !resting
|
||||
to_chat(src, "<span class='notice'>You are now [resting ? "resting" : "getting up"]</span>")
|
||||
@@ -520,7 +517,7 @@
|
||||
/mob/living/silicon/pai/Bumped()
|
||||
return
|
||||
|
||||
/mob/living/silicon/pai/start_pulling(atom/movable/AM, state, force = move_force, supress_message = FALSE)
|
||||
/mob/living/silicon/pai/start_pulling(atom/movable/AM, state, force = pull_force, show_message = FALSE)
|
||||
return FALSE
|
||||
|
||||
/mob/living/silicon/pai/update_canmove(delay_action_updates = 0)
|
||||
@@ -566,6 +563,10 @@
|
||||
var/obj/item/holder/H = ..()
|
||||
if(!istype(H))
|
||||
return
|
||||
if(stat == DEAD)
|
||||
H.icon = 'icons/mob/pai.dmi'
|
||||
H.icon_state = "[chassis]_dead"
|
||||
return
|
||||
if(resting)
|
||||
icon_state = "[chassis]"
|
||||
resting = 0
|
||||
|
||||
@@ -243,7 +243,7 @@
|
||||
add_fingerprint(user)
|
||||
|
||||
|
||||
proc/robot_healthscan(mob/user, mob/living/M)
|
||||
/proc/robot_healthscan(mob/user, mob/living/M)
|
||||
var/scan_type
|
||||
if(istype(M, /mob/living/silicon/robot))
|
||||
scan_type = "robot"
|
||||
@@ -312,8 +312,3 @@ proc/robot_healthscan(mob/user, mob/living/M)
|
||||
to_chat(user, "[capitalize(O.name)]: <font color='red'>[O.damage]</font>")
|
||||
if(!organ_found)
|
||||
to_chat(user, "<span class='warning'>No prosthetics located.</span>")
|
||||
|
||||
if(ismachineperson(H))
|
||||
to_chat(user, "<span class='notice'>Internal Fluid Level:[H.blood_volume]/[H.max_blood]</span>")
|
||||
if(H.bleed_rate)
|
||||
to_chat(user, "<span class='warning'>Warning:External component leak detected!</span>")
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
emote("deathgasp", force = TRUE)
|
||||
|
||||
if(module)
|
||||
module.handle_death(gibbed)
|
||||
module.handle_death(src, gibbed)
|
||||
|
||||
// Only execute the below if we successfully died
|
||||
. = ..(gibbed)
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
ventcrawler = 2
|
||||
magpulse = 1
|
||||
mob_size = MOB_SIZE_SMALL
|
||||
pull_force = MOVE_FORCE_VERY_WEAK // Can only drag small items
|
||||
|
||||
modules_break = FALSE
|
||||
|
||||
@@ -34,7 +35,14 @@
|
||||
var/mail_destination = 0
|
||||
var/reboot_cooldown = 60 // one minute
|
||||
var/last_reboot
|
||||
var/emagged_time
|
||||
var/list/pullable_drone_items = list(
|
||||
/obj/item/pipe,
|
||||
/obj/structure/disposalconstruct,
|
||||
/obj/item/stack/cable_coil,
|
||||
/obj/item/stack/rods,
|
||||
/obj/item/stack/sheet,
|
||||
/obj/item/stack/tile
|
||||
)
|
||||
|
||||
holder_type = /obj/item/holder/drone
|
||||
// var/sprite[0]
|
||||
@@ -50,7 +58,7 @@
|
||||
|
||||
// Disable the microphone wire on Drones
|
||||
if(radio)
|
||||
radio.wires.CutWireIndex(RADIO_WIRE_TRANSMIT)
|
||||
radio.wires.cut(WIRE_RADIO_TRANSMIT)
|
||||
|
||||
if(camera && ("Robots" in camera.network))
|
||||
camera.network.Add("Engineering")
|
||||
@@ -69,6 +77,10 @@
|
||||
verbs -= /mob/living/silicon/robot/verb/Namepick
|
||||
module = new /obj/item/robot_module/drone(src)
|
||||
|
||||
//Allows Drones to hear the Engineering channel.
|
||||
module.channels = list("Engineering" = 1)
|
||||
radio.recalculateChannels()
|
||||
|
||||
//Grab stacks.
|
||||
stack_metal = locate(/obj/item/stack/sheet/metal/cyborg) in src.module
|
||||
stack_wood = locate(/obj/item/stack/sheet/wood) in src.module
|
||||
@@ -114,6 +126,11 @@
|
||||
/mob/living/silicon/robot/drone/pick_module()
|
||||
return
|
||||
|
||||
/mob/living/silicon/robot/drone/can_be_revived()
|
||||
. = ..()
|
||||
if(emagged)
|
||||
return FALSE
|
||||
|
||||
//Drones cannot be upgraded with borg modules so we need to catch some items before they get used in ..().
|
||||
/mob/living/silicon/robot/drone/attackby(obj/item/W as obj, mob/user as mob, params)
|
||||
|
||||
@@ -154,15 +171,17 @@
|
||||
return
|
||||
|
||||
else
|
||||
user.visible_message("<span class='warning'>\the [user] swipes [user.p_their()] ID card through [src], attempting to shut it down.</span>", "<span class='warning'>You swipe your ID card through \the [src], attempting to shut it down.</span>")
|
||||
var/confirm = alert("Using your ID on a Maintenance Drone will shut it down, are you sure you want to do this?", "Disable Drone", "Yes", "No")
|
||||
if(confirm == ("Yes") && (user in range(3, src)))
|
||||
user.visible_message("<span class='warning'>\the [user] swipes [user.p_their()] ID card through [src], attempting to shut it down.</span>", "<span class='warning'>You swipe your ID card through \the [src], attempting to shut it down.</span>")
|
||||
|
||||
if(emagged)
|
||||
return
|
||||
if(emagged)
|
||||
return
|
||||
|
||||
if(allowed(W))
|
||||
shut_down()
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Access denied.</span>")
|
||||
if(allowed(W))
|
||||
shut_down()
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Access denied.</span>")
|
||||
|
||||
return
|
||||
|
||||
@@ -193,8 +212,8 @@
|
||||
log_game("[key_name(user)] emagged drone [key_name(src)]. Laws overridden.")
|
||||
var/time = time2text(world.realtime,"hh:mm:ss")
|
||||
GLOB.lawchanges.Add("[time] <B>:</B> [H.name]([H.key]) emagged [name]([key])")
|
||||
addtimer(CALLBACK(src, .proc/shut_down, TRUE), EMAG_TIMER)
|
||||
|
||||
emagged_time = world.time
|
||||
emagged = 1
|
||||
density = 1
|
||||
pass_flags = 0
|
||||
@@ -321,20 +340,22 @@
|
||||
/mob/living/silicon/robot/drone/Bumped(atom/movable/AM)
|
||||
return
|
||||
|
||||
/mob/living/silicon/robot/drone/start_pulling(var/atom/movable/AM)
|
||||
/mob/living/silicon/robot/drone/start_pulling(atom/movable/AM, state, force = pull_force, show_message = FALSE)
|
||||
|
||||
if(is_type_in_list(AM, pullable_drone_items))
|
||||
..(AM, force = INFINITY) // Drone power! Makes them able to drag pipes and such
|
||||
|
||||
if(istype(AM,/obj/item/pipe) || istype(AM,/obj/structure/disposalconstruct))
|
||||
..()
|
||||
else if(istype(AM,/obj/item))
|
||||
var/obj/item/O = AM
|
||||
if(O.w_class > WEIGHT_CLASS_SMALL)
|
||||
to_chat(src, "<span class='warning'>You are too small to pull that.</span>")
|
||||
if(show_message)
|
||||
to_chat(src, "<span class='warning'>You are too small to pull that.</span>")
|
||||
return
|
||||
else
|
||||
..()
|
||||
else
|
||||
to_chat(src, "<span class='warning'>You are too small to pull that.</span>")
|
||||
return
|
||||
if(show_message)
|
||||
to_chat(src, "<span class='warning'>You are too small to pull that.</span>")
|
||||
|
||||
/mob/living/silicon/robot/drone/add_robot_verbs()
|
||||
src.verbs |= silicon_subsystems
|
||||
@@ -344,13 +365,25 @@
|
||||
|
||||
/mob/living/silicon/robot/drone/update_canmove(delay_action_updates = 0)
|
||||
. = ..()
|
||||
if(emagged)
|
||||
density = 1
|
||||
if(world.time - emagged_time > EMAG_TIMER)
|
||||
shut_down(TRUE)
|
||||
return
|
||||
density = 0 //this is reset every canmove update otherwise
|
||||
density = emagged //this is reset every canmove update otherwise
|
||||
|
||||
/mob/living/simple_animal/drone/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0)
|
||||
if(affect_silicon)
|
||||
return ..()
|
||||
|
||||
/mob/living/silicon/robot/drone/decompile_act(obj/item/matter_decompiler/C, mob/user)
|
||||
if(!client && istype(user, /mob/living/silicon/robot/drone))
|
||||
to_chat(user, "<span class='warning'>You begin decompiling the other drone.</span>")
|
||||
if(!do_after(user, 5 SECONDS, target = loc))
|
||||
to_chat(user, "<span class='warning'>You need to remain still while decompiling such a large object.</span>")
|
||||
return
|
||||
if(QDELETED(src) || QDELETED(user))
|
||||
return ..()
|
||||
to_chat(user, "<span class='warning'>You carefully and thoroughly decompile your downed fellow, storing as much of its resources as you can within yourself.</span>")
|
||||
new/obj/effect/decal/cleanable/blood/oil(get_turf(src))
|
||||
C.stored_comms["metal"] += 15
|
||||
C.stored_comms["glass"] += 15
|
||||
C.stored_comms["wood"] += 5
|
||||
qdel(src)
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
//Has a list of items that it can hold.
|
||||
var/list/can_hold = list(
|
||||
/obj/item/stock_parts/cell,
|
||||
/obj/item/firealarm_electronics,
|
||||
/obj/item/airalarm_electronics,
|
||||
/obj/item/airlock_electronics,
|
||||
@@ -24,6 +23,8 @@
|
||||
/obj/item/mounted/frame/firealarm,
|
||||
/obj/item/mounted/frame/newscaster_frame,
|
||||
/obj/item/mounted/frame/intercom,
|
||||
/obj/item/mounted/frame/extinguisher,
|
||||
/obj/item/mounted/frame/light_switch,
|
||||
/obj/item/rack_parts,
|
||||
/obj/item/camera_assembly,
|
||||
/obj/item/tank,
|
||||
@@ -151,15 +152,13 @@
|
||||
var/list/stored_comms = list(
|
||||
"metal" = 0,
|
||||
"glass" = 0,
|
||||
"wood" = 0,
|
||||
"plastic" = 0
|
||||
"wood" = 0
|
||||
)
|
||||
|
||||
/obj/item/matter_decompiler/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
|
||||
return
|
||||
|
||||
/obj/item/matter_decompiler/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, proximity, params)
|
||||
|
||||
/obj/item/matter_decompiler/afterattack(atom/target, mob/living/user, proximity, params)
|
||||
if(!proximity) return //Not adjacent.
|
||||
|
||||
//We only want to deal with using this on turfs. Specific items aren't important.
|
||||
@@ -168,101 +167,11 @@
|
||||
return
|
||||
|
||||
//Used to give the right message.
|
||||
var/grabbed_something = 0
|
||||
var/grabbed_something = FALSE
|
||||
|
||||
for(var/mob/M in T)
|
||||
if(istype(M,/mob/living/simple_animal/lizard) || istype(M,/mob/living/simple_animal/mouse))
|
||||
src.loc.visible_message("<span class='notice'>[src.loc] sucks [M] into its decompiler. There's a horrible crunching noise.</span>","<span class='warning'>It's a bit of a struggle, but you manage to suck [M] into your decompiler. It makes a series of visceral crunching noises.</span>")
|
||||
new/obj/effect/decal/cleanable/blood/splatter(get_turf(src))
|
||||
qdel(M)
|
||||
stored_comms["wood"]++
|
||||
stored_comms["wood"]++
|
||||
stored_comms["plastic"]++
|
||||
stored_comms["plastic"]++
|
||||
return
|
||||
|
||||
else if(istype(M,/mob/living/silicon/robot/drone) && !M.client)
|
||||
|
||||
var/mob/living/silicon/robot/drone/D = src.loc
|
||||
|
||||
if(!istype(D))
|
||||
return
|
||||
|
||||
to_chat(D, "<span class='warning'>You begin decompiling the other drone.</span>")
|
||||
|
||||
if(!do_after(D, 50, target = target))
|
||||
to_chat(D, "<span class='warning'>You need to remain still while decompiling such a large object.</span>")
|
||||
return
|
||||
|
||||
if(!M || !D) return
|
||||
|
||||
to_chat(D, "<span class='warning'>You carefully and thoroughly decompile your downed fellow, storing as much of its resources as you can within yourself.</span>")
|
||||
|
||||
qdel(M)
|
||||
new/obj/effect/decal/cleanable/blood/oil(get_turf(src))
|
||||
|
||||
stored_comms["metal"] += 15
|
||||
stored_comms["glass"] += 15
|
||||
stored_comms["wood"] += 5
|
||||
stored_comms["plastic"] += 5
|
||||
|
||||
return
|
||||
else
|
||||
continue
|
||||
|
||||
for(var/obj/W in T)
|
||||
//Different classes of items give different commodities.
|
||||
if(istype(W,/obj/item/cigbutt))
|
||||
stored_comms["plastic"]++
|
||||
else if(istype(W,/obj/structure/spider/spiderling))
|
||||
stored_comms["wood"]++
|
||||
stored_comms["wood"]++
|
||||
stored_comms["plastic"]++
|
||||
stored_comms["plastic"]++
|
||||
else if(istype(W,/obj/item/light))
|
||||
var/obj/item/light/L = W
|
||||
if(L.status >= 2) //In before someone changes the inexplicably local defines. ~ Z
|
||||
stored_comms["metal"]++
|
||||
stored_comms["glass"]++
|
||||
else
|
||||
continue
|
||||
else if(istype(W,/obj/effect/decal/remains/robot))
|
||||
stored_comms["metal"]++
|
||||
stored_comms["metal"]++
|
||||
stored_comms["plastic"]++
|
||||
stored_comms["plastic"]++
|
||||
stored_comms["glass"]++
|
||||
else if(istype(W,/obj/item/trash))
|
||||
stored_comms["metal"]++
|
||||
stored_comms["plastic"]++
|
||||
stored_comms["plastic"]++
|
||||
else if(istype(W,/obj/effect/decal/cleanable/blood/gibs/robot))
|
||||
stored_comms["metal"]++
|
||||
stored_comms["metal"]++
|
||||
stored_comms["glass"]++
|
||||
stored_comms["glass"]++
|
||||
else if(istype(W,/obj/item/ammo_casing))
|
||||
stored_comms["metal"]++
|
||||
else if(istype(W,/obj/item/shard))
|
||||
stored_comms["glass"]++
|
||||
stored_comms["glass"]++
|
||||
stored_comms["glass"]++
|
||||
else if(istype(W,/obj/item/reagent_containers/food/snacks/grown))
|
||||
stored_comms["wood"]++
|
||||
stored_comms["wood"]++
|
||||
stored_comms["wood"]++
|
||||
stored_comms["wood"]++
|
||||
else if(istype(W,/obj/item/broken_bottle))
|
||||
stored_comms["glass"]++
|
||||
stored_comms["glass"]++
|
||||
stored_comms["glass"]++
|
||||
else if(istype(W,/obj/item/light/tube) || istype(W,/obj/item/light/bulb))
|
||||
stored_comms["glass"]++
|
||||
else
|
||||
continue
|
||||
|
||||
qdel(W)
|
||||
grabbed_something = 1
|
||||
for(var/atom/movable/A in T)
|
||||
if(A.decompile_act(src, user)) // Each decompileable mob or obj needs to have this defined
|
||||
grabbed_something = TRUE
|
||||
|
||||
if(grabbed_something)
|
||||
to_chat(user, "<span class='notice'>You deploy your decompiler and clear out the contents of \the [T].</span>")
|
||||
@@ -353,11 +262,5 @@
|
||||
stack_wood = new /obj/item/stack/sheet/wood(src.module)
|
||||
stack_wood.amount = 1
|
||||
stack = stack_wood
|
||||
if("plastic")
|
||||
if(!stack_plastic)
|
||||
stack_plastic = new /obj/item/stack/sheet/plastic(src.module)
|
||||
stack_plastic.amount = 1
|
||||
stack = stack_plastic
|
||||
|
||||
stack.amount++
|
||||
decompiler.stored_comms[type]--
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
handle_robot_cell()
|
||||
process_locks()
|
||||
update_items()
|
||||
process_queued_alarms()
|
||||
|
||||
|
||||
/mob/living/silicon/robot/proc/handle_robot_cell()
|
||||
@@ -46,7 +45,7 @@
|
||||
|
||||
/mob/living/silicon/robot/proc/handle_equipment()
|
||||
if(camera && !scrambledcodes)
|
||||
if(stat == DEAD || wires.IsCameraCut())
|
||||
if(stat == DEAD || wires.is_cut(WIRE_BORG_CAMERA))
|
||||
camera.status = 0
|
||||
else
|
||||
camera.status = 1
|
||||
|
||||
@@ -59,7 +59,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
var/ear_protection = 0
|
||||
var/damage_protection = 0
|
||||
var/emp_protection = FALSE
|
||||
var/xeno_disarm_chance = 85
|
||||
|
||||
var/list/force_modules = list()
|
||||
var/allow_rename = TRUE
|
||||
@@ -72,11 +71,10 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
var/list/req_access
|
||||
var/ident = 0
|
||||
//var/list/laws = list()
|
||||
var/alarms = list("Motion"=list(), "Fire"=list(), "Atmosphere"=list(), "Power"=list(), "Camera"=list())
|
||||
var/viewalerts = 0
|
||||
var/modtype = "Default"
|
||||
var/lower_mod = 0
|
||||
var/datum/effect_system/spark_spread/spark_system//So they can initialize sparks whenever/N
|
||||
var/datum/effect_system/spark_spread/spark_system //So they can initialize sparks whenever/N
|
||||
var/jeton = 0
|
||||
var/low_power_mode = 0 //whether the robot has no charge left.
|
||||
var/weapon_lock = 0
|
||||
@@ -85,6 +83,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
var/lockcharge //Used when locking down a borg to preserve cell charge
|
||||
var/speed = 0 //Cause sec borgs gotta go fast //No they dont!
|
||||
var/scrambledcodes = 0 // Used to determine if a borg shows up on the robotics console. Setting to one hides them.
|
||||
var/can_lock_cover = FALSE //Used to set if a borg can re-lock its cover.
|
||||
var/has_camera = TRUE
|
||||
var/pdahide = 0 //Used to hide the borg from the messenger list
|
||||
var/tracking_entities = 0 //The number of known entities currently accessing the internal camera
|
||||
@@ -112,7 +111,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
/mob/living/silicon/robot/get_cell()
|
||||
return cell
|
||||
|
||||
/mob/living/silicon/robot/New(loc, syndie = FALSE, unfinished = FALSE, alien = FALSE, mob/living/silicon/ai/ai_to_sync_to = null)
|
||||
/mob/living/silicon/robot/New(loc, syndie = FALSE, unfinished = FALSE, alien = FALSE, connect_to_AI = TRUE, mob/living/silicon/ai/ai_to_sync_to = null)
|
||||
spark_system = new /datum/effect_system/spark_spread()
|
||||
spark_system.set_up(5, 0, src)
|
||||
spark_system.attach(src)
|
||||
@@ -134,13 +133,13 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
radio = new /obj/item/radio/borg(src)
|
||||
common_radio = radio
|
||||
|
||||
init(ai_to_sync_to = ai_to_sync_to)
|
||||
init(alien, connect_to_AI, ai_to_sync_to)
|
||||
|
||||
if(has_camera && !camera)
|
||||
camera = new /obj/machinery/camera(src)
|
||||
camera.c_tag = real_name
|
||||
camera.network = list("SS13","Robots")
|
||||
if(wires.IsCameraCut()) // 5 = BORG CAMERA
|
||||
if(wires.is_cut(WIRE_BORG_CAMERA)) // 5 = BORG CAMERA
|
||||
camera.status = 0
|
||||
|
||||
if(mmi == null)
|
||||
@@ -172,18 +171,20 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
scanner = new(src)
|
||||
scanner.Grant(src)
|
||||
|
||||
/mob/living/silicon/robot/proc/init(alien = FALSE, mob/living/silicon/ai/ai_to_sync_to = null)
|
||||
/mob/living/silicon/robot/proc/init(alien, connect_to_AI = TRUE, mob/living/silicon/ai/ai_to_sync_to = null)
|
||||
aiCamera = new/obj/item/camera/siliconcam/robot_camera(src)
|
||||
make_laws()
|
||||
additional_law_channels["Binary"] = ":b "
|
||||
if(!connect_to_AI)
|
||||
return
|
||||
var/found_ai = ai_to_sync_to
|
||||
if(!found_ai)
|
||||
found_ai = select_active_ai_with_fewest_borgs()
|
||||
if(found_ai)
|
||||
lawupdate = 1
|
||||
lawupdate = TRUE
|
||||
connect_to_ai(found_ai)
|
||||
else
|
||||
lawupdate = 0
|
||||
lawupdate = FALSE
|
||||
|
||||
playsound(loc, 'sound/voice/liveagain.ogg', 75, 1)
|
||||
|
||||
@@ -270,6 +271,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
//If there's an MMI in the robot, have it ejected when the mob goes away. --NEO
|
||||
//Improved /N
|
||||
/mob/living/silicon/robot/Destroy()
|
||||
SStgui.close_uis(wires)
|
||||
if(mmi && mind)//Safety for when a cyborg gets dust()ed. Or there is no MMI inside.
|
||||
var/turf/T = get_turf(loc)//To hopefully prevent run time errors.
|
||||
if(T) mmi.loc = T
|
||||
@@ -445,7 +447,10 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
notify_ai(2)
|
||||
|
||||
uneq_all()
|
||||
SSnanoui.close_user_uis(src)
|
||||
SStgui.close_user_uis(src)
|
||||
sight_mode = null
|
||||
update_sight()
|
||||
hands.icon_state = "nomod"
|
||||
icon_state = "robot"
|
||||
module.remove_subsystems_and_actions(src)
|
||||
@@ -543,6 +548,43 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
src.verbs -= GLOB.robot_verbs_default
|
||||
src.verbs -= silicon_subsystems
|
||||
|
||||
/mob/living/silicon/robot/verb/cmd_robot_alerts()
|
||||
set category = "Robot Commands"
|
||||
set name = "Show Alerts"
|
||||
if(usr.stat == DEAD)
|
||||
to_chat(src, "<span class='userdanger'>Alert: You are dead.</span>")
|
||||
return //won't work if dead
|
||||
robot_alerts()
|
||||
|
||||
/mob/living/silicon/robot/proc/robot_alerts()
|
||||
var/list/dat = list()
|
||||
var/list/list/temp_alarm_list = SSalarm.alarms.Copy()
|
||||
for(var/cat in temp_alarm_list)
|
||||
if(!(cat in alarms_listend_for))
|
||||
continue
|
||||
dat += text("<B>[cat]</B><BR>\n")
|
||||
var/list/list/L = temp_alarm_list[cat].Copy()
|
||||
for(var/alarm in L)
|
||||
var/list/list/alm = L[alarm].Copy()
|
||||
var/list/list/sources = alm[3].Copy()
|
||||
var/area_name = alm[1]
|
||||
for(var/thing in sources)
|
||||
var/atom/A = locateUID(thing)
|
||||
if(A && A.z != z)
|
||||
L -= alarm
|
||||
continue
|
||||
dat += "<NOBR>"
|
||||
dat += text("-- [area_name]")
|
||||
dat += "</NOBR><BR>\n"
|
||||
if(!L.len)
|
||||
dat += "-- All Systems Nominal<BR>\n"
|
||||
dat += "<BR>\n"
|
||||
|
||||
var/datum/browser/alerts = new(usr, "robotalerts", "Current Station Alerts", 400, 410)
|
||||
var/dat_text = dat.Join("")
|
||||
alerts.set_content(dat_text)
|
||||
alerts.open()
|
||||
|
||||
/mob/living/silicon/robot/proc/ionpulse()
|
||||
if(!ionpulse_on)
|
||||
return
|
||||
@@ -604,6 +646,23 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
/mob/living/silicon/robot/InCritical()
|
||||
return low_power_mode
|
||||
|
||||
/mob/living/silicon/robot/alarm_triggered(src, class, area/A, list/O, obj/alarmsource)
|
||||
if(!(class in alarms_listend_for))
|
||||
return
|
||||
if(alarmsource.z != z)
|
||||
return
|
||||
if(stat == DEAD)
|
||||
return
|
||||
queueAlarm(text("--- [class] alarm detected in [A.name]!"), class)
|
||||
|
||||
/mob/living/silicon/robot/alarm_cancelled(src, class, area/A, obj/origin, cleared)
|
||||
if(cleared)
|
||||
if(!(class in alarms_listend_for))
|
||||
return
|
||||
if(origin.z != z)
|
||||
return
|
||||
queueAlarm("--- [class] alarm in [A.name] has been cleared.", class, 0)
|
||||
|
||||
/mob/living/silicon/robot/ex_act(severity)
|
||||
switch(severity)
|
||||
if(1.0)
|
||||
@@ -697,6 +756,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
if(allowed(W))
|
||||
locked = !locked
|
||||
to_chat(user, "You [ locked ? "lock" : "unlock"] [src]'s interface.")
|
||||
to_chat(src, "<span class='notice'>[user] [ locked ? "locked" : "unlocked"] your interface.</span>")
|
||||
update_icons()
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Access denied.</span>")
|
||||
@@ -713,7 +773,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
if(!user.drop_item())
|
||||
return
|
||||
if(U.action(src))
|
||||
to_chat(user, "<span class='notice'>You apply the upgrade to [src].</span>")
|
||||
user.visible_message("<span class = 'notice'>[user] applied [U] to [src].</span>", "<span class='notice'>You apply [U] to [src].</span>")
|
||||
U.forceMove(src)
|
||||
else
|
||||
to_chat(user, "<span class='danger'>Upgrade error.</span>")
|
||||
@@ -795,7 +855,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
opened = FALSE
|
||||
update_icons()
|
||||
return
|
||||
else if(wiresexposed && wires.IsAllCut())
|
||||
else if(wiresexposed && wires.is_all_cut())
|
||||
//Cell is out, wires are exposed, remove MMI, produce damaged chassis, baleet original mob.
|
||||
if(!mmi)
|
||||
to_chat(user, "[src] has no brain to remove.")
|
||||
@@ -909,16 +969,24 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
update_icons()
|
||||
return
|
||||
|
||||
/mob/living/silicon/robot/verb/unlock_own_cover()
|
||||
/mob/living/silicon/robot/verb/toggle_own_cover()
|
||||
set category = "Robot Commands"
|
||||
set name = "Unlock Cover"
|
||||
set desc = "Unlocks your own cover if it is locked. You can not lock it again. A human will have to lock it for you."
|
||||
if(locked)
|
||||
switch(alert("You can not lock your cover again, are you sure?\n (You can still ask for a human to lock it)", "Unlock Own Cover", "Yes", "No"))
|
||||
if("Yes")
|
||||
locked = 0
|
||||
update_icons()
|
||||
to_chat(usr, "You unlock your cover.")
|
||||
set name = "Toggle Cover"
|
||||
set desc = "Toggles the lock on your cover."
|
||||
|
||||
if(can_lock_cover)
|
||||
if(alert("Are you sure?", locked ? "Unlock Cover" : "Lock Cover", "Yes", "No") == "Yes")
|
||||
locked = !locked
|
||||
update_icons()
|
||||
to_chat(usr, "<span class='notice'>You [locked ? "lock" : "unlock"] your cover.</span>")
|
||||
return
|
||||
if(!locked)
|
||||
to_chat(usr, "<span class='warning'>You cannot lock your cover yourself. Find a robotocist.</span>")
|
||||
return
|
||||
if(alert("You cannnot lock your own cover again. Are you sure?\n You will need a robotocist to re-lock you.", "Unlock Own Cover", "Yes", "No") == "Yes")
|
||||
locked = !locked
|
||||
update_icons()
|
||||
to_chat(usr, "<span class='notice'>You unlock your cover.</span>")
|
||||
|
||||
/mob/living/silicon/robot/attack_ghost(mob/user)
|
||||
if(wiresexposed)
|
||||
@@ -1023,10 +1091,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
src << browse(null, t1)
|
||||
return 1
|
||||
|
||||
if(href_list["showalerts"])
|
||||
subsystem_alarm_monitor()
|
||||
return 1
|
||||
|
||||
if(href_list["mod"])
|
||||
var/obj/item/O = locate(href_list["mod"])
|
||||
if(istype(O) && (O.loc == src))
|
||||
@@ -1041,6 +1105,11 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
activate_module(O)
|
||||
installed_modules()
|
||||
|
||||
//Show alerts window if user clicked on "Show alerts" in chat
|
||||
if(href_list["showalerts"])
|
||||
robot_alerts()
|
||||
return TRUE
|
||||
|
||||
if(href_list["deact"])
|
||||
var/obj/item/O = locate(href_list["deact"])
|
||||
if(activated(O))
|
||||
@@ -1063,7 +1132,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
return 1
|
||||
|
||||
/mob/living/silicon/robot/proc/radio_menu()
|
||||
radio.interact(src)//Just use the radio's Topic() instead of bullshit special-snowflake code
|
||||
radio.interact(src)
|
||||
|
||||
/mob/living/silicon/robot/proc/control_headlamp()
|
||||
if(stat || lamp_recharging || low_power_mode)
|
||||
@@ -1233,7 +1302,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
|
||||
/mob/living/silicon/robot/proc/SetLockdown(var/state = 1)
|
||||
// They stay locked down if their wire is cut.
|
||||
if(wires.LockedCut())
|
||||
if(wires.is_cut(WIRE_BORG_LOCKED))
|
||||
state = 1
|
||||
if(state)
|
||||
throw_alert("locked", /obj/screen/alert/locked)
|
||||
@@ -1343,14 +1412,14 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
eye_protection = 2 // Immunity to flashes and the visual part of flashbangs
|
||||
ear_protection = 1 // Immunity to the audio part of flashbangs
|
||||
damage_protection = 10 // Reduce all incoming damage by this number
|
||||
xeno_disarm_chance = 20
|
||||
allow_rename = FALSE
|
||||
modtype = "Commando"
|
||||
faction = list("nanotrasen")
|
||||
is_emaggable = FALSE
|
||||
can_lock_cover = TRUE
|
||||
default_cell_type = /obj/item/stock_parts/cell/bluespace
|
||||
|
||||
/mob/living/silicon/robot/deathsquad/init(alien = FALSE, mob/living/silicon/ai/ai_to_sync_to = null)
|
||||
/mob/living/silicon/robot/deathsquad/init(alien = FALSE, connect_to_AI = TRUE, mob/living/silicon/ai/ai_to_sync_to = null)
|
||||
laws = new /datum/ai_laws/deathsquad
|
||||
module = new /obj/item/robot_module/deathsquad(src)
|
||||
aiCamera = new/obj/item/camera/siliconcam/robot_camera(src)
|
||||
@@ -1376,11 +1445,12 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
static_radio_channels = 1
|
||||
allow_rename = FALSE
|
||||
weapons_unlock = TRUE
|
||||
can_lock_cover = TRUE
|
||||
default_cell_type = /obj/item/stock_parts/cell/super
|
||||
var/eprefix = "Amber"
|
||||
|
||||
|
||||
/mob/living/silicon/robot/ert/init(alien = FALSE, mob/living/silicon/ai/ai_to_sync_to = null)
|
||||
/mob/living/silicon/robot/ert/init(alien = FALSE, connect_to_AI = TRUE, mob/living/silicon/ai/ai_to_sync_to = null)
|
||||
laws = new /datum/ai_laws/ert_override
|
||||
radio = new /obj/item/radio/borg/ert(src)
|
||||
radio.recalculateChannels()
|
||||
@@ -1413,7 +1483,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
damage_protection = 5 // Reduce all incoming damage by this number
|
||||
eprefix = "Gamma"
|
||||
magpulse = 1
|
||||
xeno_disarm_chance = 40
|
||||
|
||||
|
||||
/mob/living/silicon/robot/destroyer
|
||||
@@ -1433,11 +1502,13 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
ear_protection = 1 // Immunity to the audio part of flashbangs
|
||||
emp_protection = TRUE // Immunity to EMP, due to heavy shielding
|
||||
damage_protection = 20 // Reduce all incoming damage by this number. Very high in the case of /destroyer borgs, since it is an admin-only borg.
|
||||
xeno_disarm_chance = 10
|
||||
can_lock_cover = TRUE
|
||||
default_cell_type = /obj/item/stock_parts/cell/bluespace
|
||||
|
||||
/mob/living/silicon/robot/destroyer/init(alien = FALSE, mob/living/silicon/ai/ai_to_sync_to = null)
|
||||
..()
|
||||
/mob/living/silicon/robot/destroyer/init(alien = FALSE, connect_to_AI = TRUE, mob/living/silicon/ai/ai_to_sync_to = null)
|
||||
aiCamera = new/obj/item/camera/siliconcam/robot_camera(src)
|
||||
additional_law_channels["Binary"] = ":b "
|
||||
laws = new /datum/ai_laws/deathsquad
|
||||
module = new /obj/item/robot_module/destroyer(src)
|
||||
module.add_languages(src)
|
||||
module.add_subsystems_and_actions(src)
|
||||
@@ -1446,6 +1517,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
qdel(radio)
|
||||
radio = new /obj/item/radio/borg/ert/specops(src)
|
||||
radio.recalculateChannels()
|
||||
playsound(loc, 'sound/mecha/nominalsyndi.ogg', 75, 0)
|
||||
|
||||
/mob/living/silicon/robot/destroyer/borg_icons()
|
||||
if(base_icon == "")
|
||||
|
||||
@@ -2,19 +2,17 @@
|
||||
if(M.a_intent == INTENT_DISARM)
|
||||
if(!lying)
|
||||
M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
|
||||
if(prob(xeno_disarm_chance))
|
||||
Stun(7)
|
||||
step(src, get_dir(M,src))
|
||||
spawn(5)
|
||||
step(src, get_dir(M,src))
|
||||
add_attack_logs(M, src, "Alien pushed over")
|
||||
playsound(loc, 'sound/weapons/pierce.ogg', 50, 1, -1)
|
||||
visible_message("<span class='danger'>[M] has forced back [src]!</span>",\
|
||||
"<span class='userdanger'>[M] has forced back [src]!</span>")
|
||||
var/obj/item/I = get_active_hand()
|
||||
if(I)
|
||||
uneq_active()
|
||||
visible_message("<span class='danger'>[M] disarmed [src]!</span>", "<span class='userdanger'>[M] has disabled [src]'s active module!</span>")
|
||||
add_attack_logs(M, src, "alien disarmed")
|
||||
else
|
||||
playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1)
|
||||
visible_message("<span class='danger'>[M] took a swipe at [src]!</span>",\
|
||||
"<span class='userdanger'>[M] took a swipe at [src]!</span>")
|
||||
Stun(2)
|
||||
step(src, get_dir(M,src))
|
||||
add_attack_logs(M, src, "Alien pushed over")
|
||||
visible_message("<span class='danger'>[M] forces back [src]!</span>", "<span class='userdanger'>[M] forces back [src]!</span>")
|
||||
playsound(loc, 'sound/weapons/pierce.ogg', 50, TRUE, -1)
|
||||
else
|
||||
..()
|
||||
return
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
var/list/temp_list = modules
|
||||
modules = list()
|
||||
for(var/obj/O in temp_list)
|
||||
if(O)
|
||||
if(!QDELETED(O)) //so items getting deleted don't stay in module list and haunt you
|
||||
modules += O
|
||||
|
||||
/obj/item/robot_module/proc/add_languages(mob/living/silicon/robot/R)
|
||||
@@ -114,7 +114,7 @@
|
||||
/obj/item/robot_module/proc/handle_custom_removal(component_id, mob/living/user, obj/item/W)
|
||||
return FALSE
|
||||
|
||||
/obj/item/robot_module/proc/handle_death(gibbed)
|
||||
/obj/item/robot_module/proc/handle_death(mob/living/silicon/robot/R, gibbed)
|
||||
return
|
||||
|
||||
/obj/item/robot_module/standard
|
||||
@@ -255,7 +255,7 @@
|
||||
|
||||
fix_modules()
|
||||
|
||||
/obj/item/robot_module/engineering/handle_death()
|
||||
/obj/item/robot_module/engineering/handle_death(mob/living/silicon/robot/R, gibbed)
|
||||
var/obj/item/gripper/G = locate(/obj/item/gripper) in modules
|
||||
if(G)
|
||||
G.drop_gripped_item(silent = TRUE)
|
||||
@@ -368,6 +368,11 @@
|
||||
R.add_language("Clownish",1)
|
||||
R.add_language("Neo-Russkiya", 1)
|
||||
|
||||
/obj/item/robot_module/butler/handle_death(mob/living/silicon/robot/R, gibbed)
|
||||
var/obj/item/storage/bag/tray/cyborg/T = locate(/obj/item/storage/bag/tray/cyborg) in modules
|
||||
if(istype(T))
|
||||
T.drop_inventory(R)
|
||||
|
||||
|
||||
/obj/item/robot_module/miner
|
||||
name = "miner robot module"
|
||||
@@ -623,7 +628,7 @@
|
||||
..()
|
||||
|
||||
|
||||
/obj/item/robot_module/drone/handle_death()
|
||||
/obj/item/robot_module/drone/handle_death(mob/living/silicon/robot/R, gibbed)
|
||||
var/obj/item/gripper/G = locate(/obj/item/gripper) in modules
|
||||
if(G)
|
||||
G.drop_gripped_item(silent = TRUE)
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
modtype = "Syndicate"
|
||||
req_access = list(ACCESS_SYNDICATE)
|
||||
ionpulse = 1
|
||||
can_lock_cover = TRUE
|
||||
lawchannel = "State"
|
||||
var/playstyle_string = "<span class='userdanger'>You are a Syndicate assault cyborg!</span><br>\
|
||||
<b>You are armed with powerful offensive tools to aid you in your mission: help the operatives secure the nuclear authentication disk. \
|
||||
|
||||
@@ -11,9 +11,11 @@
|
||||
var/list/stating_laws = list()// Channels laws are currently being stated on
|
||||
var/list/alarms_to_show = list()
|
||||
var/list/alarms_to_clear = list()
|
||||
var/list/alarm_types_show = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0, "Camera" = 0)
|
||||
var/list/alarm_types_clear = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0, "Camera" = 0)
|
||||
var/list/alarms_listend_for = list("Motion", "Fire", "Atmosphere", "Power", "Camera")
|
||||
//var/list/hud_list[10]
|
||||
var/list/speech_synthesizer_langs = list() //which languages can be vocalized by the speech synthesizer
|
||||
var/list/alarm_handlers = list() // List of alarm handlers this silicon is registered to
|
||||
var/designation = ""
|
||||
var/obj/item/camera/siliconcam/aiCamera = null //photography
|
||||
//Used in say.dm, allows for pAIs to have different say flavor text, as well as silicons, although the latter is not implemented.
|
||||
@@ -25,9 +27,6 @@
|
||||
|
||||
//var/sensor_mode = 0 //Determines the current HUD.
|
||||
|
||||
var/next_alarm_notice
|
||||
var/list/datum/alarm/queued_alarms = new()
|
||||
|
||||
hud_possible = list(SPECIALROLE_HUD, DIAG_STAT_HUD, DIAG_HUD)
|
||||
|
||||
|
||||
@@ -46,6 +45,8 @@
|
||||
diag_hud_set_health()
|
||||
add_language("Galactic Common")
|
||||
init_subsystems()
|
||||
RegisterSignal(SSalarm, COMSIG_TRIGGERED_ALARM, .proc/alarm_triggered)
|
||||
RegisterSignal(SSalarm, COMSIG_CANCELLED_ALARM, .proc/alarm_cancelled)
|
||||
|
||||
/mob/living/silicon/med_hud_set_health()
|
||||
return //we use a different hud
|
||||
@@ -55,10 +56,93 @@
|
||||
|
||||
/mob/living/silicon/Destroy()
|
||||
GLOB.silicon_mob_list -= src
|
||||
for(var/datum/alarm_handler/AH in alarm_handlers)
|
||||
AH.unregister(src)
|
||||
return ..()
|
||||
|
||||
/mob/living/silicon/proc/alarm_triggered(src, class, area/A, list/O, obj/alarmsource)
|
||||
return
|
||||
|
||||
/mob/living/silicon/proc/alarm_cancelled(src, class, area/A, obj/origin, cleared)
|
||||
return
|
||||
|
||||
/mob/living/silicon/proc/queueAlarm(message, type, incoming = TRUE)
|
||||
var/in_cooldown = (alarms_to_show.len > 0 || alarms_to_clear.len > 0)
|
||||
if(incoming)
|
||||
alarms_to_show += message
|
||||
alarm_types_show[type] += 1
|
||||
else
|
||||
alarms_to_clear += message
|
||||
alarm_types_clear[type] += 1
|
||||
|
||||
if(in_cooldown)
|
||||
return
|
||||
|
||||
addtimer(CALLBACK(src, .proc/show_alarms), 3 SECONDS)
|
||||
|
||||
/mob/living/silicon/proc/show_alarms()
|
||||
if(alarms_to_show.len < 5)
|
||||
for(var/msg in alarms_to_show)
|
||||
to_chat(src, msg)
|
||||
else if(length(alarms_to_show))
|
||||
|
||||
var/list/msg = list("--- ")
|
||||
|
||||
if(alarm_types_show["Burglar"])
|
||||
msg += "BURGLAR: [alarm_types_show["Burglar"]] alarms detected. - "
|
||||
|
||||
if(alarm_types_show["Motion"])
|
||||
msg += "MOTION: [alarm_types_show["Motion"]] alarms detected. - "
|
||||
|
||||
if(alarm_types_show["Fire"])
|
||||
msg += "FIRE: [alarm_types_show["Fire"]] alarms detected. - "
|
||||
|
||||
if(alarm_types_show["Atmosphere"])
|
||||
msg += "ATMOSPHERE: [alarm_types_show["Atmosphere"]] alarms detected. - "
|
||||
|
||||
if(alarm_types_show["Power"])
|
||||
msg += "POWER: [alarm_types_show["Power"]] alarms detected. - "
|
||||
|
||||
if(alarm_types_show["Camera"])
|
||||
msg += "CAMERA: [alarm_types_show["Camera"]] alarms detected. - "
|
||||
|
||||
msg += "<A href=?src=[UID()];showalerts=1'>\[Show Alerts\]</a>"
|
||||
var/msg_text = msg.Join("")
|
||||
to_chat(src, msg_text)
|
||||
|
||||
if(alarms_to_clear.len < 3)
|
||||
for(var/msg in alarms_to_clear)
|
||||
to_chat(src, msg)
|
||||
|
||||
else if(alarms_to_clear.len)
|
||||
var/list/msg = list("--- ")
|
||||
|
||||
if(alarm_types_clear["Motion"])
|
||||
msg += "MOTION: [alarm_types_clear["Motion"]] alarms cleared. - "
|
||||
|
||||
if(alarm_types_clear["Fire"])
|
||||
msg += "FIRE: [alarm_types_clear["Fire"]] alarms cleared. - "
|
||||
|
||||
if(alarm_types_clear["Atmosphere"])
|
||||
msg += "ATMOSPHERE: [alarm_types_clear["Atmosphere"]] alarms cleared. - "
|
||||
|
||||
if(alarm_types_clear["Power"])
|
||||
msg += "POWER: [alarm_types_clear["Power"]] alarms cleared. - "
|
||||
|
||||
if(alarm_types_show["Camera"])
|
||||
msg += "CAMERA: [alarm_types_clear["Camera"]] alarms cleared. - "
|
||||
|
||||
msg += "<A href=?src=[UID()];showalerts=1'>\[Show Alerts\]</a>"
|
||||
|
||||
var/msg_text = msg.Join("")
|
||||
to_chat(src, msg_text)
|
||||
|
||||
|
||||
alarms_to_show.Cut()
|
||||
alarms_to_clear.Cut()
|
||||
for(var/key in alarm_types_show)
|
||||
alarm_types_show[key] = 0
|
||||
for(var/key in alarm_types_clear)
|
||||
alarm_types_clear[key] = 0
|
||||
|
||||
/mob/living/silicon/rename_character(oldname, newname)
|
||||
// we actually don't want it changing minds and stuff
|
||||
if(!newname)
|
||||
@@ -283,63 +367,6 @@
|
||||
if("Disable")
|
||||
to_chat(src, "Sensor augmentations disabled.")
|
||||
|
||||
/mob/living/silicon/proc/receive_alarm(var/datum/alarm_handler/alarm_handler, var/datum/alarm/alarm, was_raised)
|
||||
if(!next_alarm_notice)
|
||||
next_alarm_notice = world.time + 10 SECONDS
|
||||
|
||||
var/list/alarms = queued_alarms[alarm_handler]
|
||||
if(was_raised)
|
||||
// Raised alarms are always set
|
||||
alarms[alarm] = 1
|
||||
else
|
||||
// Alarms that were raised but then cleared before the next notice are instead removed
|
||||
if(alarm in alarms)
|
||||
alarms -= alarm
|
||||
// And alarms that have only been cleared thus far are set as such
|
||||
else
|
||||
alarms[alarm] = -1
|
||||
|
||||
/mob/living/silicon/proc/process_queued_alarms()
|
||||
if(next_alarm_notice && (world.time > next_alarm_notice))
|
||||
next_alarm_notice = 0
|
||||
|
||||
var/alarm_raised = 0
|
||||
for(var/datum/alarm_handler/AH in queued_alarms)
|
||||
var/list/alarms = queued_alarms[AH]
|
||||
var/reported = 0
|
||||
for(var/datum/alarm/A in alarms)
|
||||
if(alarms[A] == 1)
|
||||
if(!reported)
|
||||
reported = 1
|
||||
to_chat(src, "<span class='warning'>--- [AH.category] Detected ---</span>")
|
||||
raised_alarm(A)
|
||||
|
||||
for(var/datum/alarm_handler/AH in queued_alarms)
|
||||
var/list/alarms = queued_alarms[AH]
|
||||
var/reported = 0
|
||||
for(var/datum/alarm/A in alarms)
|
||||
if(alarms[A] == -1)
|
||||
if(!reported)
|
||||
reported = 1
|
||||
to_chat(src, "<span class='notice'>--- [AH.category] Cleared ---</span>")
|
||||
to_chat(src, "\The [A.alarm_name()].")
|
||||
|
||||
if(alarm_raised)
|
||||
to_chat(src, "<A HREF=?src=[UID()];showalerts=1>\[Show Alerts\]</A>")
|
||||
|
||||
for(var/datum/alarm_handler/AH in queued_alarms)
|
||||
var/list/alarms = queued_alarms[AH]
|
||||
alarms.Cut()
|
||||
|
||||
/mob/living/silicon/proc/raised_alarm(var/datum/alarm/A)
|
||||
to_chat(src, "[A.alarm_name()]!")
|
||||
|
||||
/mob/living/silicon/ai/raised_alarm(var/datum/alarm/A)
|
||||
var/cameratext = ""
|
||||
for(var/obj/machinery/camera/C in A.cameras())
|
||||
cameratext += "[(cameratext == "")? "" : "|"]<A HREF=?src=[UID()];switchcamera=\ref[C]>[C.c_tag]</A>"
|
||||
to_chat(src, "[A.alarm_name()]! ([(cameratext)? cameratext : "No Camera"])")
|
||||
|
||||
/mob/living/silicon/adjustToxLoss(var/amount)
|
||||
return STATUS_UPDATE_NONE
|
||||
|
||||
|
||||
@@ -3,11 +3,10 @@
|
||||
|
||||
/mob/living/silicon/attack_alien(mob/living/carbon/alien/humanoid/M)
|
||||
if(..()) //if harm or disarm intent
|
||||
var/damage = rand(10, 20)
|
||||
var/damage = 20
|
||||
if(prob(90))
|
||||
playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1)
|
||||
visible_message("<span class='danger'>[M] has slashed at [src]!</span>", \
|
||||
"<span class='userdanger'>[M] has slashed at [src]!</span>")
|
||||
visible_message("<span class='danger'>[M] has slashed at [src]!</span>", "<span class='userdanger'>[M] has slashed at [src]!</span>")
|
||||
if(prob(8))
|
||||
flash_eyes(affect_silicon = 1)
|
||||
add_attack_logs(M, src, "Alien attacked")
|
||||
@@ -59,11 +58,12 @@
|
||||
if(INTENT_HELP)
|
||||
M.visible_message("<span class='notice'>[M] pets [src]!</span>", \
|
||||
"<span class='notice'>You pet [src]!</span>")
|
||||
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
|
||||
if("grab")
|
||||
grabbedby(M)
|
||||
else
|
||||
M.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
|
||||
playsound(loc, 'sound/effects/bang.ogg', 10, 1)
|
||||
visible_message("<span class='danger'>[M] punches [src], but doesn't leave a dent.</span>", \
|
||||
"<span class='userdanger'>[M] punches [src], but doesn't leave a dent.!</span>")
|
||||
visible_message("<span class='notice'>[M] punches [src], but doesn't leave a dent.</span>", \
|
||||
"<span class='notice'>[M] punches [src], but doesn't leave a dent.</span>")
|
||||
return FALSE
|
||||
|
||||
@@ -4,17 +4,15 @@
|
||||
var/datum/nano_module/atmos_control/atmos_control
|
||||
var/datum/tgui_module/crew_monitor/crew_monitor
|
||||
var/datum/nano_module/law_manager/law_manager
|
||||
var/datum/nano_module/power_monitor/silicon/power_monitor
|
||||
var/datum/tgui_module/power_monitor/digital/power_monitor
|
||||
|
||||
/mob/living/silicon
|
||||
var/list/silicon_subsystems = list(
|
||||
/mob/living/silicon/proc/subsystem_alarm_monitor,
|
||||
/mob/living/silicon/proc/subsystem_law_manager
|
||||
)
|
||||
|
||||
/mob/living/silicon/ai
|
||||
silicon_subsystems = list(
|
||||
/mob/living/silicon/proc/subsystem_alarm_monitor,
|
||||
/mob/living/silicon/proc/subsystem_atmos_control,
|
||||
/mob/living/silicon/proc/subsystem_crew_monitor,
|
||||
/mob/living/silicon/proc/subsystem_law_manager,
|
||||
@@ -23,7 +21,6 @@
|
||||
|
||||
/mob/living/silicon/robot/drone
|
||||
silicon_subsystems = list(
|
||||
/mob/living/silicon/proc/subsystem_alarm_monitor,
|
||||
/mob/living/silicon/proc/subsystem_law_manager,
|
||||
/mob/living/silicon/proc/subsystem_power_monitor
|
||||
)
|
||||
@@ -32,30 +29,11 @@
|
||||
register_alarms = 0
|
||||
|
||||
/mob/living/silicon/proc/init_subsystems()
|
||||
alarm_monitor = new(src)
|
||||
atmos_control = new(src)
|
||||
crew_monitor = new(src)
|
||||
law_manager = new(src)
|
||||
power_monitor = new(src)
|
||||
|
||||
if(!register_alarms)
|
||||
return
|
||||
|
||||
var/list/register_to = list(SSalarms.atmosphere_alarm, SSalarms.burglar_alarm, SSalarms.camera_alarm, SSalarms.fire_alarm, SSalarms.motion_alarm, SSalarms.power_alarm)
|
||||
for(var/datum/alarm_handler/AH in register_to)
|
||||
AH.register(src, /mob/living/silicon/proc/receive_alarm)
|
||||
queued_alarms[AH] = list() // Makes sure alarms remain listed in consistent order
|
||||
alarm_handlers |= AH
|
||||
|
||||
/********************
|
||||
* Alarm Monitor *
|
||||
********************/
|
||||
/mob/living/silicon/proc/subsystem_alarm_monitor()
|
||||
set name = "Alarm Monitor"
|
||||
set category = "Subsystems"
|
||||
|
||||
alarm_monitor.ui_interact(usr, state = GLOB.self_state)
|
||||
|
||||
/********************
|
||||
* Atmos Control *
|
||||
********************/
|
||||
@@ -89,5 +67,5 @@
|
||||
set category = "Subsystems"
|
||||
set name = "Power Monitor"
|
||||
|
||||
power_monitor.ui_interact(usr, state = GLOB.self_state)
|
||||
power_monitor.tgui_interact(usr, state = GLOB.self_state)
|
||||
|
||||
|
||||
@@ -42,13 +42,18 @@
|
||||
|
||||
/mob/living/simple_animal/attack_alien(mob/living/carbon/alien/humanoid/M)
|
||||
if(..()) //if harm or disarm intent.
|
||||
var/damage = rand(15, 30)
|
||||
visible_message("<span class='danger'>[M] has slashed at [src]!</span>", \
|
||||
"<span class='userdanger'>[M] has slashed at [src]!</span>")
|
||||
playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
|
||||
add_attack_logs(M, src, "Alien attacked")
|
||||
attack_threshold_check(damage)
|
||||
return
|
||||
if(M.a_intent == INTENT_DISARM)
|
||||
playsound(loc, 'sound/weapons/pierce.ogg', 25, TRUE, -1)
|
||||
visible_message("<span class='danger'>[M] [response_disarm] [name]!</span>", "<span class='userdanger'>[M] [response_disarm] you!</span>")
|
||||
add_attack_logs(M, src, "Alien disarmed")
|
||||
else
|
||||
var/damage = rand(15, 30)
|
||||
visible_message("<span class='danger'>[M] has slashed at [src]!</span>", \
|
||||
"<span class='userdanger'>[M] has slashed at [src]!</span>")
|
||||
playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
|
||||
add_attack_logs(M, src, "Alien attacked")
|
||||
attack_threshold_check(damage)
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/attack_larva(mob/living/carbon/alien/larva/L)
|
||||
if(..()) //successful larva bite
|
||||
|
||||
@@ -94,7 +94,6 @@
|
||||
hud_possible = list(DIAG_STAT_HUD, DIAG_BOT_HUD, DIAG_HUD, DIAG_PATH_HUD = HUD_LIST_LIST)//Diagnostic HUD views
|
||||
|
||||
/obj/item/radio/headset/bot
|
||||
subspace_transmission = 1
|
||||
requires_tcomms = FALSE
|
||||
canhear_range = 0
|
||||
|
||||
@@ -756,7 +755,7 @@ Pass a positive integer as an argument to override a bot's default speed.
|
||||
|
||||
// send a radio signal with multiple data key/values
|
||||
/mob/living/simple_animal/bot/proc/post_signal_multiple(var/freq, var/list/keyval)
|
||||
if(z != 1) //Bot control will only work on station.
|
||||
if(!is_station_level(z)) //Bot control will only work on station.
|
||||
return
|
||||
var/datum/radio_frequency/frequency = SSradio.return_frequency(freq)
|
||||
if(!frequency)
|
||||
|
||||
@@ -474,8 +474,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.forceMove(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.robot_arm = robot_arm
|
||||
qdel(I)
|
||||
@@ -512,7 +511,7 @@
|
||||
//General Griefsky
|
||||
|
||||
else if((istype(I, /obj/item/wrench)) && (build_step == 3))
|
||||
var/obj/item/griefsky_assembly/A = new /obj/item/griefsky_assembly
|
||||
var/obj/item/griefsky_assembly/A = new /obj/item/griefsky_assembly(get_turf(src))
|
||||
user.put_in_hands(A)
|
||||
to_chat(user, "<span class='notice'>You adjust the arm slots for extra weapons!.</span>")
|
||||
user.unEquip(src, 1)
|
||||
@@ -540,8 +539,7 @@
|
||||
if(!user.unEquip(I))
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You complete General Griefsky!.</span>")
|
||||
var/mob/living/simple_animal/bot/secbot/griefsky/S = new /mob/living/simple_animal/bot/secbot/griefsky
|
||||
S.forceMove(get_turf(src))
|
||||
new /mob/living/simple_animal/bot/secbot/griefsky(get_turf(src))
|
||||
qdel(I)
|
||||
qdel(src)
|
||||
|
||||
@@ -556,8 +554,7 @@
|
||||
if(!user.unEquip(I))
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You complete Genewul Giftskee!.</span>")
|
||||
var/mob/living/simple_animal/bot/secbot/griefsky/toy/S = new /mob/living/simple_animal/bot/secbot/griefsky/toy
|
||||
S.forceMove(get_turf(src))
|
||||
new /mob/living/simple_animal/bot/secbot/griefsky/toy(get_turf(src))
|
||||
qdel(I)
|
||||
qdel(src)
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
RegisterSignal(src, COMSIG_CROSSED_MOVABLE, .proc/human_squish_check)
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/Destroy()
|
||||
SStgui.close_uis(wires)
|
||||
unload(0)
|
||||
QDEL_NULL(wires)
|
||||
QDEL_NULL(cell)
|
||||
@@ -142,7 +143,7 @@
|
||||
if(open)
|
||||
icon_state="mulebot-hatch"
|
||||
else
|
||||
icon_state = "mulebot[!wires.MobAvoid()]"
|
||||
icon_state = "mulebot[wires.is_cut(WIRE_MOB_AVOIDANCE)]"
|
||||
overlays.Cut()
|
||||
if(load && !ismob(load))//buckling handles the mob offsets
|
||||
load.pixel_y = initial(load.pixel_y) + 9
|
||||
@@ -158,9 +159,9 @@
|
||||
qdel(src)
|
||||
if(2)
|
||||
for(var/i = 1; i < 3; i++)
|
||||
wires.RandomCut()
|
||||
wires.cut_random()
|
||||
if(3)
|
||||
wires.RandomCut()
|
||||
wires.cut_random()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/bullet_act(obj/item/projectile/Proj)
|
||||
@@ -169,7 +170,7 @@
|
||||
unload(0)
|
||||
if(prob(25))
|
||||
visible_message("<span class='danger'>Something shorts out inside [src]!</span>")
|
||||
wires.RandomCut()
|
||||
wires.cut_random()
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/Topic(href, list/href_list)
|
||||
if(..())
|
||||
@@ -318,7 +319,7 @@
|
||||
|
||||
// returns true if the bot has power
|
||||
/mob/living/simple_animal/bot/mulebot/proc/has_power()
|
||||
return !open && cell && cell.charge > 0 && wires.HasPower()
|
||||
return !open && cell && cell.charge > 0 && !wires.is_cut(WIRE_MAIN_POWER1) && !wires.is_cut(WIRE_MAIN_POWER2)
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/proc/buzz(type)
|
||||
switch(type)
|
||||
@@ -362,7 +363,7 @@
|
||||
if(istype(AM,/obj/structure/closet/crate))
|
||||
CRATE = AM
|
||||
else
|
||||
if(wires.LoadCheck())
|
||||
if(!wires.is_cut(WIRE_LOADCHECK))
|
||||
buzz(SIGH)
|
||||
return // if not hacked, only allow crates to be loaded
|
||||
|
||||
@@ -459,8 +460,7 @@
|
||||
on = 0
|
||||
return
|
||||
if(on)
|
||||
var/speed = (wires.Motor1() ? 1 : 0) + (wires.Motor2() ? 2 : 0)
|
||||
// to_chat(world, "speed: [speed]")
|
||||
var/speed = (!wires.is_cut(WIRE_MOTOR1) ? 1 : 0) + (!wires.is_cut(WIRE_MOTOR2) ? 2 : 0)
|
||||
var/num_steps = 0
|
||||
switch(speed)
|
||||
if(0)
|
||||
@@ -624,7 +624,7 @@
|
||||
// not loaded
|
||||
if(auto_pickup) // find a crate
|
||||
var/atom/movable/AM
|
||||
if(wires.LoadCheck()) // if hacked, load first unanchored thing we find
|
||||
if(wires.is_cut(WIRE_LOADCHECK)) // if hacked, load first unanchored thing we find
|
||||
for(var/atom/movable/A in get_step(loc, loaddir))
|
||||
if(!A.anchored)
|
||||
AM = A
|
||||
@@ -672,7 +672,7 @@
|
||||
|
||||
// called when bot bumps into anything
|
||||
/mob/living/simple_animal/bot/mulebot/Bump(atom/obs)
|
||||
if(!wires.MobAvoid()) // usually just bumps, but if avoidance disabled knock over mobs
|
||||
if(wires.is_cut(WIRE_MOB_AVOIDANCE)) // usually just bumps, but if avoidance disabled knock over mobs
|
||||
var/mob/M = obs
|
||||
if(ismob(M))
|
||||
if(istype(M,/mob/living/silicon/robot))
|
||||
@@ -736,8 +736,8 @@
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/receive_signal(datum/signal/signal)
|
||||
if(!wires.RemoteRX() || ..())
|
||||
return 1
|
||||
if(wires.is_cut(WIRE_REMOTE_RX) || ..())
|
||||
return TRUE
|
||||
|
||||
var/recv = signal.data["command"]
|
||||
|
||||
@@ -772,7 +772,7 @@
|
||||
|
||||
// send a radio signal with multiple data key/values
|
||||
/mob/living/simple_animal/bot/mulebot/post_signal_multiple(var/freq, var/list/keyval)
|
||||
if(!wires.RemoteTX())
|
||||
if(wires.is_cut(WIRE_REMOTE_TX))
|
||||
return
|
||||
|
||||
..()
|
||||
@@ -803,7 +803,7 @@
|
||||
|
||||
//Update navigation data. Called when commanded to deliver, return home, or a route update is needed...
|
||||
/mob/living/simple_animal/bot/mulebot/proc/get_nav()
|
||||
if(!on || !wires.BeaconRX())
|
||||
if(!on || wires.is_cut(WIRE_BEACON_RX))
|
||||
return
|
||||
|
||||
for(var/obj/machinery/navbeacon/NB in GLOB.deliverybeacons)
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
minbodytemp = 0
|
||||
faction = list("cult")
|
||||
flying = 1
|
||||
flying = TRUE
|
||||
pressure_resistance = 100
|
||||
universal_speak = 1
|
||||
AIStatus = AI_OFF //normal constructs don't have AI
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
harm_intent_damage = 1
|
||||
friendly = "nudges"
|
||||
density = 0
|
||||
flying = TRUE
|
||||
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
|
||||
ventcrawler = 2
|
||||
mob_size = MOB_SIZE_TINY
|
||||
|
||||
@@ -123,6 +123,7 @@
|
||||
for(var/mob/living/simple_animal/mouse/M in view(1, src))
|
||||
if(!M.stat && Adjacent(M))
|
||||
custom_emote(1, "splats \the [M]!")
|
||||
M.death()
|
||||
M.splat()
|
||||
movement_target = null
|
||||
stop_automated_movement = 0
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
response_disarm = "bops"
|
||||
response_harm = "kicks"
|
||||
speak = list("YAP", "Woof!", "Bark!", "AUUUUUU")
|
||||
speak_emote = list("barks", "woofs")
|
||||
speak_emote = list("barks.", "woofs.")
|
||||
emote_hear = list("barks!", "woofs!", "yaps.","pants.")
|
||||
emote_see = list("shakes its head.", "chases its tail.","shivers.")
|
||||
faction = list("neutral")
|
||||
|
||||
@@ -126,6 +126,7 @@
|
||||
gold_core_spawnable = FRIENDLY_SPAWN
|
||||
blood_volume = BLOOD_VOLUME_NORMAL
|
||||
var/obj/item/udder/udder = null
|
||||
gender = FEMALE
|
||||
|
||||
/mob/living/simple_animal/cow/Initialize()
|
||||
udder = new()
|
||||
|
||||
@@ -23,3 +23,14 @@
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat = 1)
|
||||
can_collar = 1
|
||||
gold_core_spawnable = FRIENDLY_SPAWN
|
||||
|
||||
/mob/living/simple_animal/lizard/decompile_act(obj/item/matter_decompiler/C, mob/user)
|
||||
if(!istype(user, /mob/living/silicon/robot/drone))
|
||||
user.visible_message("<span class='notice'>[user] sucks [src] into its decompiler. There's a horrible crunching noise.</span>", \
|
||||
"<span class='warning'>It's a bit of a struggle, but you manage to suck [src] into your decompiler. It makes a series of visceral crunching noises.</span>")
|
||||
new/obj/effect/decal/cleanable/blood/splatter(get_turf(src))
|
||||
C.stored_comms["wood"] += 2
|
||||
C.stored_comms["glass"] += 2
|
||||
qdel(src)
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
@@ -80,22 +80,16 @@
|
||||
icon_resting = "mouse_[mouse_color]_sleep"
|
||||
desc = "It's a small [mouse_color] rodent, often seen hiding in maintenance areas and making a nuisance of itself."
|
||||
|
||||
/mob/living/simple_animal/mouse/proc/splat()
|
||||
src.health = 0
|
||||
src.stat = DEAD
|
||||
src.icon_dead = "mouse_[mouse_color]_splat"
|
||||
src.icon_state = "mouse_[mouse_color]_splat"
|
||||
layer = MOB_LAYER
|
||||
if(client)
|
||||
client.time_died_as_mouse = world.time
|
||||
|
||||
/mob/living/simple_animal/mouse/attack_hand(mob/living/carbon/human/M as mob)
|
||||
if(M.a_intent == INTENT_HELP)
|
||||
get_scooped(M)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/mouse/start_pulling(var/atom/movable/AM)//Prevents mouse from pulling things
|
||||
to_chat(src, "<span class='warning'>You are too small to pull anything.</span>")
|
||||
/mob/living/simple_animal/mouse/start_pulling(atom/movable/AM, state, force = pull_force, show_message = FALSE)//Prevents mouse from pulling things
|
||||
if(istype(AM, /obj/item/reagent_containers/food/snacks/cheesewedge))
|
||||
return ..() // Get dem
|
||||
if(show_message)
|
||||
to_chat(src, "<span class='warning'>You are too small to pull anything except cheese.</span>")
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/mouse/Crossed(AM as mob|obj, oldloc)
|
||||
@@ -110,6 +104,10 @@
|
||||
desc = "It's toast."
|
||||
death()
|
||||
|
||||
/mob/living/simple_animal/mouse/proc/splat()
|
||||
icon_dead = "mouse_[mouse_color]_splat"
|
||||
icon_state = "mouse_[mouse_color]_splat"
|
||||
|
||||
/mob/living/simple_animal/mouse/death(gibbed)
|
||||
// Only execute the below if we successfully died
|
||||
playsound(src, squeak_sound, 40, 1)
|
||||
@@ -234,3 +232,14 @@
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
can_collar = 0
|
||||
butcher_results = list(/obj/item/stack/sheet/metal = 1)
|
||||
|
||||
/mob/living/simple_animal/mouse/decompile_act(obj/item/matter_decompiler/C, mob/user)
|
||||
if(!(istype(user, /mob/living/silicon/robot/drone)))
|
||||
user.visible_message("<span class='notice'>[user] sucks [src] into its decompiler. There's a horrible crunching noise.</span>", \
|
||||
"<span class='warning'>It's a bit of a struggle, but you manage to suck [src] into your decompiler. It makes a series of visceral crunching noises.</span>")
|
||||
new/obj/effect/decal/cleanable/blood/splatter(get_turf(src))
|
||||
C.stored_comms["wood"] += 2
|
||||
C.stored_comms["glass"] += 2
|
||||
qdel(src)
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
maxHealth = 20
|
||||
health = 20
|
||||
mob_size = MOB_SIZE_TINY
|
||||
flying = TRUE
|
||||
harm_intent_damage = 8
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 10
|
||||
|
||||
@@ -95,6 +95,10 @@
|
||||
for(var/mob/A in searched_for)
|
||||
. += A
|
||||
|
||||
// All bee sprites are made up of overlays. They do not have any special sprite overlays for items placed on them, such as collars, so this proc is unneeded.
|
||||
/mob/living/simple_animal/hostile/poison/bees/regenerate_icons()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/bees/proc/generate_bee_visuals()
|
||||
overlays.Cut()
|
||||
|
||||
|
||||
@@ -47,6 +47,13 @@
|
||||
if(C.can_inject(null, FALSE, inject_target, FALSE))
|
||||
C.reagents.add_reagent("spidertoxin", venom_per_bite)
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/giant_spider/get_spacemove_backup()
|
||||
. = ..()
|
||||
// If we don't find any normal thing to use, attempt to use any nearby spider structure instead.
|
||||
if(!.)
|
||||
for(var/obj/structure/spider/S in range(1, get_turf(src)))
|
||||
return S
|
||||
|
||||
//nursemaids - these create webs and eggs
|
||||
/mob/living/simple_animal/hostile/poison/giant_spider/nurse
|
||||
desc = "Furry and black, it makes you shudder to look at it. This one has brilliant green eyes."
|
||||
@@ -164,15 +171,27 @@
|
||||
|
||||
if(!cocoon_target)
|
||||
var/list/choices = list()
|
||||
for(var/mob/living/L in view(1,src))
|
||||
for(var/mob/living/L in view(1, src))
|
||||
if(L == src)
|
||||
continue
|
||||
if(L.stat != DEAD)
|
||||
continue
|
||||
if(istype(L, /mob/living/simple_animal/hostile/poison/giant_spider))
|
||||
continue
|
||||
if(Adjacent(L))
|
||||
choices += L
|
||||
for(var/obj/O in src.loc)
|
||||
for(var/obj/O in get_turf(src))
|
||||
if(O.anchored)
|
||||
continue
|
||||
if(!(isitem(O) || isstructure(O) || ismachinery(O)))
|
||||
continue
|
||||
if(Adjacent(O))
|
||||
choices += O
|
||||
cocoon_target = input(src,"What do you wish to cocoon?") in null|choices
|
||||
if(length(choices))
|
||||
cocoon_target = input(src,"What do you wish to cocoon?") in null|choices
|
||||
else
|
||||
to_chat(src, "<span class='warning'>No suitable dead prey or wrappable objects found nearby.")
|
||||
return
|
||||
|
||||
if(cocoon_target && busy != SPINNING_COCOON)
|
||||
busy = SPINNING_COCOON
|
||||
@@ -199,6 +218,8 @@
|
||||
for(var/mob/living/L in C.loc)
|
||||
if(istype(L, /mob/living/simple_animal/hostile/poison/giant_spider))
|
||||
continue
|
||||
if(L.stat != DEAD)
|
||||
continue
|
||||
large_cocoon = 1
|
||||
L.loc = C
|
||||
C.pixel_x = L.pixel_x
|
||||
|
||||
@@ -71,9 +71,6 @@
|
||||
var/spawn_delay = 600
|
||||
var/turn_on = 0
|
||||
var/auto_spawn = 1
|
||||
proc
|
||||
warpbots()
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/hivebot/tele/New()
|
||||
..()
|
||||
@@ -83,7 +80,7 @@
|
||||
visible_message("<span class='danger'>The [src] warps in!</span>")
|
||||
playsound(src.loc, 'sound/effects/empulse.ogg', 25, 1)
|
||||
|
||||
/mob/living/simple_animal/hostile/hivebot/tele/warpbots()
|
||||
/mob/living/simple_animal/hostile/hivebot/tele/proc/warpbots()
|
||||
icon_state = "def_radar"
|
||||
visible_message("<span class='warning'>The [src] turns on!</span>")
|
||||
while(bot_amt > 0)
|
||||
|
||||
@@ -122,8 +122,8 @@ Difficulty: Very Hard
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/enrage(mob/living/L)
|
||||
if(ishuman(L))
|
||||
var/mob/living/carbon/human/H = L
|
||||
if(H.martial_art && prob(H.martial_art.deflection_chance))
|
||||
. = TRUE
|
||||
if(H.mind && H.mind.martial_art && prob(H.mind.martial_art.deflection_chance))
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/alternating_dir_shots()
|
||||
ranged_cooldown = world.time + 40
|
||||
@@ -241,6 +241,14 @@ Difficulty: Very Hard
|
||||
AT.pixel_y += random_y
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/float(on) //we don't want this guy to float, messes up his animations
|
||||
if(throwing)
|
||||
return
|
||||
if(on && !floating)
|
||||
floating = TRUE
|
||||
else if(!on && floating)
|
||||
floating = FALSE
|
||||
|
||||
/obj/item/projectile/colossus
|
||||
name ="death bolt"
|
||||
icon_state= "chronobolt"
|
||||
|
||||
@@ -524,7 +524,7 @@ Difficulty: Medium
|
||||
else
|
||||
animate(src, pixel_x = -16, pixel_z = 0, time = 5)
|
||||
|
||||
obj/effect/temp_visual/fireball
|
||||
/obj/effect/temp_visual/fireball
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "fireball"
|
||||
name = "fireball"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
//malfunctioning combat drones
|
||||
/mob/living/simple_animal/hostile/retaliate/malf_drone
|
||||
/mob/living/simple_animal/hostile/malf_drone
|
||||
name = "combat drone"
|
||||
desc = "An automated combat drone armed with state of the art weaponry and shielding."
|
||||
icon_state = "drone3"
|
||||
@@ -8,254 +8,175 @@
|
||||
icon_dead = "drone_dead"
|
||||
ranged = 1
|
||||
rapid = 3
|
||||
retreat_distance = 3
|
||||
minimum_distance = 3
|
||||
speak_chance = 5
|
||||
turns_per_move = 3
|
||||
response_help = "pokes the"
|
||||
response_disarm = "gently pushes aside the"
|
||||
response_harm = "hits the"
|
||||
speak = list("ALERT.","Hostile-ile-ile entities dee-twhoooo-wected.","Threat parameterszzzz- szzet.","Bring sub-sub-sub-systems uuuup to combat alert alpha-a-a.")
|
||||
emote_see = list("beeps menacingly","whirrs threateningly","scans its immediate vicinity")
|
||||
speak = list("ALERT.", "Hostile-ile-ile entities dee-twhoooo-wected.", "Threat parameterszzzz- szzet.", "Bring sub-sub-sub-systems uuuup to combat alert alpha-a-a.")
|
||||
emote_see = list("beeps menacingly.", "whirrs threateningly.", "scans for targets.")
|
||||
a_intent = INTENT_HARM
|
||||
stop_automated_movement_when_pulled = 0
|
||||
health = 300
|
||||
maxHealth = 300
|
||||
stop_automated_movement_when_pulled = FALSE
|
||||
health = 200
|
||||
maxHealth = 200
|
||||
speed = 8
|
||||
projectiletype = /obj/item/projectile/beam/drone
|
||||
projectiletype = /obj/item/projectile/beam/immolator/weak
|
||||
projectilesound = 'sound/weapons/laser3.ogg'
|
||||
var/datum/effect_system/trail_follow/ion/ion_trail
|
||||
|
||||
//the drone randomly switches between these states because it's malfunctioning
|
||||
var/hostile_drone = 0
|
||||
//0 - retaliate, only attack enemies that attack it
|
||||
//1 - hostile, attack everything that comes near
|
||||
|
||||
var/turf/patrol_target
|
||||
var/explode_chance = 1
|
||||
var/disabled = 0
|
||||
var/exploding = 0
|
||||
|
||||
//Drones aren't affected by atmos.
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
minbodytemp = 0
|
||||
|
||||
var/has_loot = 1
|
||||
faction = list("malf_drone")
|
||||
deathmessage = "suddenly breaks apart."
|
||||
del_on_death = 1
|
||||
var/datum/effect_system/trail_follow/ion/ion_trail
|
||||
var/passive_mode = TRUE // if true, don't target anything.
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/malf_drone/New()
|
||||
..()
|
||||
if(prob(5))
|
||||
projectiletype = /obj/item/projectile/beam/pulse/drone
|
||||
projectilesound = 'sound/weapons/pulse2.ogg'
|
||||
/mob/living/simple_animal/hostile/malf_drone/Initialize(mapload)
|
||||
. = ..()
|
||||
ion_trail = new
|
||||
ion_trail.set_up(src)
|
||||
ion_trail.start()
|
||||
update_icons()
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/malf_drone/Process_Spacemove(var/check_drift = 0)
|
||||
/mob/living/simple_animal/hostile/malf_drone/Process_Spacemove(check_drift = 0)
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/malf_drone/ListTargets()
|
||||
if(hostile_drone)
|
||||
return view(src, 10)
|
||||
else
|
||||
return ..()
|
||||
|
||||
//self repair systems have a chance to bring the drone back to life
|
||||
/mob/living/simple_animal/hostile/retaliate/malf_drone/Life(seconds, times_fired)
|
||||
|
||||
//emps and lots of damage can temporarily shut us down
|
||||
if(disabled > 0)
|
||||
stat = UNCONSCIOUS
|
||||
icon_state = "drone_dead"
|
||||
disabled--
|
||||
wander = 0
|
||||
speak_chance = 0
|
||||
if(disabled <= 0)
|
||||
stat = CONSCIOUS
|
||||
icon_state = "drone0"
|
||||
wander = 1
|
||||
speak_chance = 5
|
||||
|
||||
//repair a bit of damage
|
||||
if(prob(1))
|
||||
src.visible_message("<span class='warning'>[bicon(src)] [src] shudders and shakes as some of it's damaged systems come back online.</span>")
|
||||
do_sparks(3, 1, src)
|
||||
health += rand(25,100)
|
||||
|
||||
//spark for no reason
|
||||
if(prob(5))
|
||||
do_sparks(3, 1, src)
|
||||
|
||||
//sometimes our targetting sensors malfunction, and we attack anyone nearby
|
||||
if(prob(disabled ? 0 : 1))
|
||||
if(hostile_drone)
|
||||
src.visible_message("<span class='notice'>[bicon(src)] [src] retracts several targetting vanes, and dulls it's running lights.</span>")
|
||||
hostile_drone = 0
|
||||
else
|
||||
src.visible_message("<span class='warning'>[bicon(src)] [src] suddenly lights up, and additional targetting vanes slide into place.</span>")
|
||||
hostile_drone = 1
|
||||
|
||||
if(health / maxHealth > 0.9)
|
||||
icon_state = "drone3"
|
||||
explode_chance = 0
|
||||
else if(health / maxHealth > 0.7)
|
||||
icon_state = "drone2"
|
||||
explode_chance = 0
|
||||
else if(health / maxHealth > 0.5)
|
||||
icon_state = "drone1"
|
||||
explode_chance = 0.5
|
||||
else if(health / maxHealth > 0.3)
|
||||
icon_state = "drone0"
|
||||
explode_chance = 5
|
||||
else if(health > 0)
|
||||
//if health gets too low, shut down
|
||||
icon_state = "drone_dead"
|
||||
exploding = 0
|
||||
if(!disabled)
|
||||
if(prob(50))
|
||||
src.visible_message("<span class='notice'>[bicon(src)] [src] suddenly shuts down!</span>")
|
||||
else
|
||||
src.visible_message("<span class='notice'>[bicon(src)] [src] suddenly lies still and quiet.</span>")
|
||||
disabled = rand(150, 600)
|
||||
walk(src,0)
|
||||
|
||||
if(exploding && prob(20))
|
||||
if(prob(50))
|
||||
src.visible_message("<span class='warning'>[bicon(src)] [src] begins to spark and shake violenty!</span>")
|
||||
else
|
||||
src.visible_message("<span class='warning'>[bicon(src)] [src] sparks and shakes like it's about to explode!</span>")
|
||||
do_sparks(3, 1, src)
|
||||
|
||||
if(!exploding && !disabled && prob(explode_chance))
|
||||
exploding = 1
|
||||
stat = UNCONSCIOUS
|
||||
wander = 1
|
||||
walk(src,0)
|
||||
spawn(rand(50,150))
|
||||
if(!disabled && exploding)
|
||||
explosion(get_turf(src), 0, 1, 4, 7)
|
||||
//proc/explosion(turf/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog = 1)
|
||||
..()
|
||||
|
||||
//ion rifle!
|
||||
/mob/living/simple_animal/hostile/retaliate/malf_drone/emp_act(severity)
|
||||
health -= rand(3,15) * (severity + 1)
|
||||
disabled = rand(150, 600)
|
||||
hostile_drone = 0
|
||||
walk(src,0)
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/malf_drone/Destroy() //Seriously, what the actual hell.
|
||||
//some random debris left behind
|
||||
if(has_loot)
|
||||
do_sparks(3, 1, src)
|
||||
var/obj/O
|
||||
|
||||
//shards
|
||||
O = new /obj/item/shard(loc)
|
||||
step_to(O, get_turf(pick(view(7, src))))
|
||||
if(prob(75))
|
||||
O = new /obj/item/shard(loc)
|
||||
step_to(O, get_turf(pick(view(7, src))))
|
||||
if(prob(50))
|
||||
O = new /obj/item/shard(loc)
|
||||
step_to(O, get_turf(pick(view(7, src))))
|
||||
if(prob(25))
|
||||
O = new /obj/item/shard(loc)
|
||||
step_to(O, get_turf(pick(view(7, src))))
|
||||
|
||||
//rods
|
||||
O = new /obj/item/stack/rods(src.loc)
|
||||
step_to(O, get_turf(pick(view(7, src))))
|
||||
if(prob(75))
|
||||
O = new /obj/item/stack/rods(src.loc)
|
||||
step_to(O, get_turf(pick(view(7, src))))
|
||||
if(prob(50))
|
||||
O = new /obj/item/stack/rods(src.loc)
|
||||
step_to(O, get_turf(pick(view(7, src))))
|
||||
if(prob(25))
|
||||
O = new /obj/item/stack/rods(src.loc)
|
||||
step_to(O, get_turf(pick(view(7, src))))
|
||||
|
||||
//plasteel
|
||||
O = new /obj/item/stack/sheet/plasteel(src.loc)
|
||||
step_to(O, get_turf(pick(view(7, src))))
|
||||
if(prob(75))
|
||||
O = new /obj/item/stack/sheet/plasteel(src.loc)
|
||||
step_to(O, get_turf(pick(view(7, src))))
|
||||
if(prob(50))
|
||||
O = new /obj/item/stack/sheet/plasteel(src.loc)
|
||||
step_to(O, get_turf(pick(view(7, src))))
|
||||
if(prob(25))
|
||||
O = new /obj/item/stack/sheet/plasteel(src.loc)
|
||||
step_to(O, get_turf(pick(view(7, src))))
|
||||
|
||||
//also drop dummy circuit boards deconstructable for research (loot)
|
||||
var/obj/item/circuitboard/C
|
||||
|
||||
//spawn 1-4 boards of a random type
|
||||
var/spawnees = 0
|
||||
var/num_boards = rand(1,4)
|
||||
var/list/options = list(1,2,4,8,16,32,64,128,256, 512)
|
||||
for(var/i=0, i<num_boards, i++)
|
||||
var/chosen = pick(options)
|
||||
options.Remove(options.Find(chosen))
|
||||
spawnees |= chosen
|
||||
|
||||
if(spawnees & 1)
|
||||
C = new(src.loc)
|
||||
C.name = "Drone CPU motherboard"
|
||||
C.origin_tech = "programming=[rand(3,6)]"
|
||||
|
||||
if(spawnees & 2)
|
||||
C = new(src.loc)
|
||||
C.name = "Drone neural interface"
|
||||
C.origin_tech = "biotech=[rand(3,6)]"
|
||||
|
||||
if(spawnees & 4)
|
||||
C = new(src.loc)
|
||||
C.name = "Drone suspension processor"
|
||||
C.origin_tech = "magnets=[rand(3,6)]"
|
||||
|
||||
if(spawnees & 8)
|
||||
C = new(src.loc)
|
||||
C.name = "Drone shielding controller"
|
||||
C.origin_tech = "bluespace=[rand(3,6)]"
|
||||
|
||||
if(spawnees & 16)
|
||||
C = new(src.loc)
|
||||
C.name = "Drone power capacitor"
|
||||
C.origin_tech = "powerstorage=[rand(3,6)]"
|
||||
|
||||
if(spawnees & 32)
|
||||
C = new(src.loc)
|
||||
C.name = "Drone hull reinforcer"
|
||||
C.origin_tech = "materials=[rand(3,6)]"
|
||||
|
||||
if(spawnees & 64)
|
||||
C = new(src.loc)
|
||||
C.name = "Drone auto-repair system"
|
||||
C.origin_tech = "engineering=[rand(3,6)]"
|
||||
|
||||
if(spawnees & 128)
|
||||
C = new(src.loc)
|
||||
C.name = "Drone plasma overcharge counter"
|
||||
C.origin_tech = "plasmatech=[rand(3,6)]"
|
||||
|
||||
if(spawnees & 256)
|
||||
C = new(src.loc)
|
||||
C.name = "Drone targetting circuitboard"
|
||||
C.origin_tech = "combat=[rand(3,6)]"
|
||||
|
||||
if(spawnees & 512)
|
||||
C = new(src.loc)
|
||||
C.name = "Corrupted drone morality core"
|
||||
C.origin_tech = "syndicate=[rand(3,6)]"
|
||||
|
||||
/mob/living/simple_animal/hostile/malf_drone/ListTargets()
|
||||
if(passive_mode)
|
||||
return list()
|
||||
return ..()
|
||||
|
||||
/obj/item/projectile/beam/drone
|
||||
damage = 15
|
||||
/mob/living/simple_animal/hostile/malf_drone/AttackingTarget()
|
||||
OpenFire(target) // prevents it pointlessly nuzzling its target in melee if its cornered
|
||||
|
||||
/obj/item/projectile/beam/pulse/drone
|
||||
damage = 10
|
||||
/mob/living/simple_animal/hostile/malf_drone/update_icons()
|
||||
if(passive_mode)
|
||||
icon_state = "drone_dead"
|
||||
else if(health / maxHealth > 0.9)
|
||||
icon_state = "drone3"
|
||||
else if(health / maxHealth > 0.7)
|
||||
icon_state = "drone2"
|
||||
else if(health / maxHealth > 0.5)
|
||||
icon_state = "drone1"
|
||||
else
|
||||
icon_state = "drone0"
|
||||
|
||||
/mob/living/simple_animal/hostile/malf_drone/adjustHealth(damage, updating_health)
|
||||
do_sparks(3, 1, src)
|
||||
passive_mode = FALSE
|
||||
update_icons()
|
||||
. = ..() // this will handle finding a target if there is a valid one nearby
|
||||
|
||||
/mob/living/simple_animal/hostile/malf_drone/Life(seconds, times_fired)
|
||||
. = ..()
|
||||
if(.) // mob is alive. We check this just in case Life() can fire for qdel'ed mobs.
|
||||
if(times_fired % 15 == 0) // every 15 cycles, aka 30 seconds, 50% chance to switch between modes
|
||||
scramble_settings()
|
||||
|
||||
/mob/living/simple_animal/hostile/malf_drone/proc/scramble_settings()
|
||||
if(prob(50))
|
||||
do_sparks(3, 1, src)
|
||||
passive_mode = !passive_mode
|
||||
if(passive_mode)
|
||||
visible_message("<span class='notice'>[src] retracts several targetting vanes.</span>")
|
||||
if(target)
|
||||
LoseTarget()
|
||||
else
|
||||
visible_message("<span class='warning'>[src] suddenly lights up, and additional targetting vanes slide into place.</span>")
|
||||
update_icons()
|
||||
|
||||
/mob/living/simple_animal/hostile/malf_drone/emp_act(severity)
|
||||
adjustHealth(100 / severity) // takes the same damage as a mining drone from emp
|
||||
|
||||
/mob/living/simple_animal/hostile/malf_drone/drop_loot()
|
||||
do_sparks(3, 1, src)
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
|
||||
//shards
|
||||
var/obj/O = new /obj/item/shard(T)
|
||||
step_to(O, get_turf(pick(view(7, src))))
|
||||
if(prob(75))
|
||||
O = new /obj/item/shard(T)
|
||||
step_to(O, get_turf(pick(view(7, src))))
|
||||
if(prob(50))
|
||||
O = new /obj/item/shard(T)
|
||||
step_to(O, get_turf(pick(view(7, src))))
|
||||
if(prob(25))
|
||||
O = new /obj/item/shard(T)
|
||||
step_to(O, get_turf(pick(view(7, src))))
|
||||
|
||||
//rods
|
||||
var/obj/item/stack/K = new /obj/item/stack/rods(T)
|
||||
step_to(K, get_turf(pick(view(7, src))))
|
||||
K.amount = pick(1, 2, 3, 4)
|
||||
K.update_icon()
|
||||
|
||||
//plasteel
|
||||
K = new /obj/item/stack/sheet/plasteel(T)
|
||||
step_to(K, get_turf(pick(view(7, src))))
|
||||
K.amount = pick(1, 2, 3, 4)
|
||||
K.update_icon()
|
||||
|
||||
//also drop dummy circuit boards deconstructable for research (loot)
|
||||
var/obj/item/circuitboard/C
|
||||
|
||||
//spawn 1-4 boards of a random type
|
||||
var/spawnees = 0
|
||||
var/num_boards = rand(1, 4)
|
||||
var/list/options = list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512)
|
||||
for(var/i=0, i<num_boards, i++)
|
||||
var/chosen = pick(options)
|
||||
options.Remove(options.Find(chosen))
|
||||
spawnees |= chosen
|
||||
|
||||
if(spawnees & 1)
|
||||
C = new(T)
|
||||
C.name = "Drone CPU motherboard"
|
||||
C.origin_tech = "programming=[rand(3, 6)]"
|
||||
|
||||
if(spawnees & 2)
|
||||
C = new(T)
|
||||
C.name = "Drone neural interface"
|
||||
C.origin_tech = "biotech=[rand(3, 6)]"
|
||||
|
||||
if(spawnees & 4)
|
||||
C = new(T)
|
||||
C.name = "Drone suspension processor"
|
||||
C.origin_tech = "magnets=[rand(3, 6)]"
|
||||
|
||||
if(spawnees & 8)
|
||||
C = new(T)
|
||||
C.name = "Drone shielding controller"
|
||||
C.origin_tech = "bluespace=[rand(3, 6)]"
|
||||
|
||||
if(spawnees & 16)
|
||||
C = new(T)
|
||||
C.name = "Drone power capacitor"
|
||||
C.origin_tech = "powerstorage=[rand(3, 6)]"
|
||||
|
||||
if(spawnees & 32)
|
||||
C = new(T)
|
||||
C.name = "Drone hull reinforcer"
|
||||
C.origin_tech = "materials=[rand(3, 6)]"
|
||||
|
||||
if(spawnees & 64)
|
||||
C = new(T)
|
||||
C.name = "Drone auto-repair system"
|
||||
C.origin_tech = "engineering=[rand(3, 6)]"
|
||||
|
||||
if(spawnees & 128)
|
||||
C = new(T)
|
||||
C.name = "Drone plasma overcharge counter"
|
||||
C.origin_tech = "plasmatech=[rand(3, 6)]"
|
||||
|
||||
if(spawnees & 256)
|
||||
C = new(T)
|
||||
C.name = "Drone targetting circuitboard"
|
||||
C.origin_tech = "combat=[rand(3, 6)]"
|
||||
|
||||
if(spawnees & 512)
|
||||
C = new(T)
|
||||
C.name = "Corrupted drone morality core"
|
||||
C.origin_tech = "syndicate=[rand(3, 6)]"
|
||||
|
||||
@@ -26,21 +26,34 @@
|
||||
flying = 1
|
||||
|
||||
var/carp_color = "carp" //holder for icon set
|
||||
var/list/icon_sets = list("carp", "blue", "yellow", "grape", "rust", "teal", "purple")
|
||||
var/static/list/carp_colors = list(\
|
||||
"lightpurple" = "#c3b9f1", \
|
||||
"lightpink" = "#da77a8", \
|
||||
"green" = "#70ff25", \
|
||||
"grape" = "#df0afb", \
|
||||
"swamp" = "#e5e75a", \
|
||||
"turquoise" = "#04e1ed", \
|
||||
"brown" = "#ca805a", \
|
||||
"teal" = "#20e28e", \
|
||||
"lightblue" = "#4d88cc", \
|
||||
"rusty" = "#dd5f34", \
|
||||
"beige" = "#bbaeaf", \
|
||||
"yellow" = "#f3ca4a", \
|
||||
"blue" = "#09bae1", \
|
||||
"palegreen" = "#7ef099", \
|
||||
)
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/carp/Initialize(mapload)
|
||||
. = ..()
|
||||
carp_randomify()
|
||||
update_icons()
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/carp/proc/carp_randomify()
|
||||
if(prob(1))
|
||||
carp_color = pick("white", "black")
|
||||
else
|
||||
carp_color = pick(icon_sets)
|
||||
icon_state = "[carp_color]"
|
||||
icon_living = "[carp_color]"
|
||||
icon_dead = "[carp_color]_dead"
|
||||
/mob/living/simple_animal/hostile/retaliate/carp/proc/carp_randomify(rarechance)
|
||||
// Simplified version of: /mob/living/simple_animal/hostile/carp/proc/carp_randomify(rarechance)
|
||||
var/our_color
|
||||
our_color = pick(carp_colors)
|
||||
add_atom_colour(carp_colors[our_color], FIXED_COLOUR_PRIORITY)
|
||||
regenerate_icons()
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/carp/koi
|
||||
name = "space koi"
|
||||
@@ -61,13 +74,15 @@
|
||||
maxbodytemp = 1500
|
||||
|
||||
gold_core_spawnable = HOSTILE_SPAWN
|
||||
var/randomize_icon = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/carp/koi/Initialize(mapload)
|
||||
. = ..()
|
||||
var/koinum = rand(1, 4)
|
||||
icon_state = "koi[koinum]"
|
||||
icon_living = "koi[koinum]"
|
||||
icon_dead = "koi[koinum]-dead"
|
||||
if(randomize_icon)
|
||||
var/koinum = rand(1, 4)
|
||||
icon_state = "koi[koinum]"
|
||||
icon_living = "koi[koinum]"
|
||||
icon_dead = "koi[koinum]-dead"
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/carp/koi/Process_Spacemove(var/movement_dir)
|
||||
return TRUE
|
||||
@@ -76,3 +91,4 @@
|
||||
icon_state = "koi5"
|
||||
icon_living = "koi5"
|
||||
icon_dead = "koi5-dead"
|
||||
randomize_icon = FALSE
|
||||
|
||||
@@ -18,3 +18,5 @@
|
||||
melee_damage_upper = 20
|
||||
unique_pet = TRUE
|
||||
atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 2, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0)
|
||||
gender = FEMALE
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
minbodytemp = 0
|
||||
flying = TRUE
|
||||
pressure_resistance = 300
|
||||
gold_core_spawnable = NO_SPAWN //too spooky for science
|
||||
faction = list("undead") // did I mention ghost
|
||||
|
||||
@@ -362,7 +362,7 @@
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
minbodytemp = 0
|
||||
mob_size = MOB_SIZE_TINY
|
||||
flying = 1
|
||||
flying = TRUE
|
||||
bubble_icon = "syndibot"
|
||||
gold_core_spawnable = HOSTILE_SPAWN
|
||||
del_on_death = 1
|
||||
|
||||
@@ -42,27 +42,6 @@
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/user = owner
|
||||
user.DoVentSmash()
|
||||
|
||||
// ---------- PRINCESS ACTIONS
|
||||
|
||||
/datum/action/innate/terrorspider/evolvequeen
|
||||
name = "Evolve Queen"
|
||||
icon_icon = 'icons/mob/terrorspider.dmi'
|
||||
button_icon_state = "terror_queen"
|
||||
|
||||
/datum/action/innate/terrorspider/evolvequeen/Activate()
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/princess/user = owner
|
||||
if(!istype(user))
|
||||
to_chat(user, "<span class='warning'>ERROR: attempt to use evolve queen ability on a non-princess</span>")
|
||||
return
|
||||
var/feedings_left = user.feedings_to_evolve - user.fed
|
||||
if(feedings_left > 0)
|
||||
to_chat(user, "<span class='warning'>You must wrap [feedings_left] more humanoid prey before you can do this!</span>")
|
||||
return
|
||||
for(var/mob/living/simple_animal/hostile/poison/terror_spider/queen/Q in GLOB.ts_spiderlist)
|
||||
if(Q.spider_awaymission == user.spider_awaymission)
|
||||
to_chat(user, "<span class='warning'>The presence of another Queen in the area is preventing you from maturing.")
|
||||
return
|
||||
user.evolve_to_queen()
|
||||
|
||||
// ---------- QUEEN ACTIONS
|
||||
|
||||
@@ -93,19 +72,11 @@
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/queen/user = owner
|
||||
user.LayQueenEggs()
|
||||
|
||||
/datum/action/innate/terrorspider/queen/queenfakelings
|
||||
name = "Fake Spiderlings"
|
||||
icon_icon = 'icons/effects/effects.dmi'
|
||||
button_icon_state = "spiderling"
|
||||
|
||||
/datum/action/innate/terrorspider/queen/queenfakelings/Activate()
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/queen/user = owner
|
||||
user.QueenFakeLings()
|
||||
|
||||
// ---------- EMPRESS
|
||||
|
||||
/datum/action/innate/terrorspider/queen/empress/empresserase
|
||||
name = "Erase Brood"
|
||||
name = "Empress Erase Brood"
|
||||
icon_icon = 'icons/effects/blood.dmi'
|
||||
button_icon_state = "mgibbl1"
|
||||
|
||||
@@ -113,6 +84,16 @@
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/user = owner
|
||||
user.EraseBrood()
|
||||
|
||||
/datum/action/innate/terrorspider/queen/empress/empresslings
|
||||
name = "Empresss Spiderlings"
|
||||
icon_icon = 'icons/effects/effects.dmi'
|
||||
button_icon_state = "spiderling"
|
||||
|
||||
/datum/action/innate/terrorspider/queen/empress/empresslings/Activate()
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/user = owner
|
||||
user.EmpressLings()
|
||||
|
||||
|
||||
// ---------- WEB
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/Web()
|
||||
@@ -186,13 +167,26 @@
|
||||
|
||||
// ---------- WRAP
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/mobIsWrappable(mob/living/M)
|
||||
if(!istype(M))
|
||||
return FALSE
|
||||
if(M.stat != DEAD)
|
||||
return FALSE
|
||||
if(M.anchored)
|
||||
return FALSE
|
||||
if(!Adjacent(M))
|
||||
return FALSE
|
||||
if(isterrorspider(M))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/FindWrapTarget()
|
||||
if(!cocoon_target)
|
||||
var/list/choices = list()
|
||||
for(var/mob/living/L in oview(1,src))
|
||||
if(Adjacent(L) && !L.anchored)
|
||||
if(L.stat == DEAD)
|
||||
choices += L
|
||||
if(!mobIsWrappable(L))
|
||||
continue
|
||||
choices += L
|
||||
for(var/obj/O in oview(1,src))
|
||||
if(Adjacent(O) && !O.anchored)
|
||||
if(!istype(O, /obj/structure/spider/terrorweb) && !istype(O, /obj/structure/spider/cocoon) && !istype(O, /obj/structure/spider/spiderling/terror_spiderling))
|
||||
@@ -226,9 +220,7 @@
|
||||
O.loc = C
|
||||
large_cocoon = 1
|
||||
for(var/mob/living/L in C.loc)
|
||||
if(istype(L, /mob/living/simple_animal/hostile/poison/terror_spider))
|
||||
continue
|
||||
if(L.stat != DEAD)
|
||||
if(!mobIsWrappable(L))
|
||||
continue
|
||||
if(iscarbon(L))
|
||||
regen_points += regen_points_per_kill
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
else if(volume < 90)
|
||||
// bitten thrice, die quickly, severe muscle cramps make movement very difficult. Even calling for help probably won't save you.
|
||||
// total damage: 4, human health 150 until crit, = 37.5 ticks, = 75s = 1m15s until death
|
||||
update_flags |= M.adjustToxLoss(4, FALSE) // a bit worse than coiine
|
||||
update_flags |= M.adjustToxLoss(4, FALSE)
|
||||
update_flags |= M.EyeBlurry(6, FALSE)
|
||||
M.Confused(6)
|
||||
else
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
ventcrawler = 1
|
||||
idle_ventcrawl_chance = 0
|
||||
ai_playercontrol_allowtype = 0
|
||||
rapid = 3
|
||||
canlay = 1000
|
||||
spider_tier = TS_TIER_5
|
||||
projectiletype = /obj/item/projectile/terrorqueenspit/empress
|
||||
@@ -35,6 +34,8 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/New()
|
||||
..()
|
||||
empresslings_action = new()
|
||||
empresslings_action.Grant(src)
|
||||
empresserase_action = new()
|
||||
empresserase_action.Grant(src)
|
||||
|
||||
@@ -44,7 +45,6 @@
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/NestMode()
|
||||
..()
|
||||
queeneggs_action.button.name = "Empress Eggs"
|
||||
queenfakelings_action.button.name = "Empress Lings"
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/LayQueenEggs()
|
||||
var/eggtype = input("What kind of eggs?") as null|anything in list(TS_DESC_QUEEN, TS_DESC_MOTHER, TS_DESC_PRINCE, TS_DESC_PRINCESS, TS_DESC_RED, TS_DESC_GRAY, TS_DESC_GREEN, TS_DESC_BLACK, TS_DESC_PURPLE, TS_DESC_WHITE, TS_DESC_BROWN)
|
||||
@@ -70,7 +70,7 @@
|
||||
if(TS_DESC_PRINCE)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/prince, numlings)
|
||||
if(TS_DESC_PRINCESS)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/princess, numlings)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess, numlings)
|
||||
if(TS_DESC_MOTHER)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/mother, numlings)
|
||||
if(TS_DESC_QUEEN)
|
||||
@@ -78,7 +78,7 @@
|
||||
else
|
||||
to_chat(src, "<span class='danger'>Unrecognized egg type.</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/QueenFakeLings()
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/proc/EmpressLings()
|
||||
var/numlings = input("How many?") as null|anything in list(10, 20, 30, 40, 50)
|
||||
var/sbpc = input("%chance to be stillborn?") as null|anything in list(0, 25, 50, 75, 100)
|
||||
for(var/i=0, i<numlings, i++)
|
||||
@@ -96,7 +96,8 @@
|
||||
S.amount_grown = 250
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/proc/EraseBrood()
|
||||
for(var/mob/living/simple_animal/hostile/poison/terror_spider/T in GLOB.ts_spiderlist)
|
||||
for(var/thing in GLOB.ts_spiderlist)
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/T = thing
|
||||
if(T.spider_tier < spider_tier)
|
||||
T.degenerate = 1
|
||||
to_chat(T, "<span class='userdanger'>Through the hivemind, the raw power of [src] floods into your body, burning it from the inside out!</span>")
|
||||
@@ -106,8 +107,6 @@
|
||||
qdel(T)
|
||||
to_chat(src, "<span class='userdanger'>All Terror Spiders, except yourself, will die off shortly.</span>")
|
||||
|
||||
|
||||
/obj/item/projectile/terrorqueenspit/empress
|
||||
damage_type = BURN
|
||||
damage = 30
|
||||
bonus_tox = 0
|
||||
damage = 90
|
||||
|
||||
|
||||
@@ -39,11 +39,10 @@
|
||||
to_chat(src, "<span class='warning'>You must wrap more humanoid prey before you can do this!</span>")
|
||||
return
|
||||
var/list/eggtypes = list(TS_DESC_RED, TS_DESC_GRAY, TS_DESC_GREEN)
|
||||
var/num_brown = CountSpidersType(/mob/living/simple_animal/hostile/poison/terror_spider/brown)
|
||||
if(num_brown < 2)
|
||||
var/list/spider_array = CountSpidersDetailed(FALSE)
|
||||
if(spider_array[/mob/living/simple_animal/hostile/poison/terror_spider/brown] < 2)
|
||||
eggtypes += TS_DESC_BROWN
|
||||
var/num_black = CountSpidersType(/mob/living/simple_animal/hostile/poison/terror_spider/black)
|
||||
if(num_black < 2)
|
||||
if(spider_array[/mob/living/simple_animal/hostile/poison/terror_spider/black] < 2)
|
||||
eggtypes += TS_DESC_BLACK
|
||||
var/eggtype = pick(eggtypes)
|
||||
if(client)
|
||||
@@ -51,6 +50,10 @@
|
||||
if(!(eggtype in eggtypes))
|
||||
to_chat(src, "<span class='danger'>Unrecognized egg type.</span>")
|
||||
return 0
|
||||
if(fed < feedings_to_lay)
|
||||
// We have to check this again after the popup, to account for people spam-clicking the button, then doing all the popups at once.
|
||||
to_chat(src, "<span class='warning'>You must wrap more humanoid prey before you can do this!</span>")
|
||||
return
|
||||
visible_message("<span class='notice'>[src] lays a cluster of eggs.</span>")
|
||||
if(eggtype == TS_DESC_RED)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/red, 1)
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/DoHiveSense()
|
||||
var/hsline = ""
|
||||
to_chat(src, "Your Brood: ")
|
||||
for(var/mob/living/simple_animal/hostile/poison/terror_spider/T in GLOB.ts_spiderlist)
|
||||
for(var/thing in GLOB.ts_spiderlist)
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/T = thing
|
||||
if(T.spider_awaymission != spider_awaymission)
|
||||
continue
|
||||
hsline = "* [T] in [get_area(T)], "
|
||||
@@ -20,21 +21,55 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/CountSpiders()
|
||||
var/numspiders = 0
|
||||
for(var/mob/living/simple_animal/hostile/poison/terror_spider/T in GLOB.ts_spiderlist)
|
||||
for(var/thing in GLOB.ts_spiderlist)
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/T = thing
|
||||
if(T.stat != DEAD && !T.spider_placed && spider_awaymission == T.spider_awaymission)
|
||||
numspiders += 1
|
||||
return numspiders
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/CountSpidersType(specific_type)
|
||||
var/numspiders = 0
|
||||
for(var/mob/living/simple_animal/hostile/poison/terror_spider/T in GLOB.ts_spiderlist)
|
||||
if(T.stat != DEAD && !T.spider_placed && spider_awaymission == T.spider_awaymission)
|
||||
if(T.type == specific_type)
|
||||
numspiders += 1
|
||||
for(var/obj/structure/spider/eggcluster/terror_eggcluster/E in GLOB.ts_egg_list)
|
||||
if(E.spiderling_type == specific_type && E.z == z)
|
||||
numspiders += E.spiderling_number
|
||||
for(var/obj/structure/spider/spiderling/terror_spiderling/L in GLOB.ts_spiderling_list)
|
||||
if(!L.stillborn && L.grow_as == specific_type && L.z == z)
|
||||
numspiders += 1
|
||||
return numspiders
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/CountSpidersDetailed(check_mine = FALSE, list/mytypes = list())
|
||||
var/list/spider_totals = list("all" = 0)
|
||||
var/check_list = length(mytypes) > 0
|
||||
for(var/thistype in mytypes)
|
||||
spider_totals[thistype] = 0
|
||||
for(var/thing in GLOB.ts_spiderlist)
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/T = thing
|
||||
if(T.stat == DEAD || T.spider_placed || spider_awaymission != T.spider_awaymission)
|
||||
continue
|
||||
if(check_mine && T.spider_myqueen != src)
|
||||
continue
|
||||
if(check_list && !(T.type in mytypes))
|
||||
continue
|
||||
if(T == src)
|
||||
continue
|
||||
if(spider_totals[T.type])
|
||||
spider_totals[T.type]++
|
||||
else
|
||||
spider_totals[T.type] = 1
|
||||
spider_totals["all"]++
|
||||
for(var/thing in GLOB.ts_egg_list)
|
||||
var/obj/structure/spider/eggcluster/terror_eggcluster/E = thing
|
||||
if(check_mine && E.spider_myqueen != src)
|
||||
continue
|
||||
if(check_list && E.spiderling_type && !(E.spiderling_type in mytypes))
|
||||
continue
|
||||
if(spider_totals[E.spiderling_type])
|
||||
spider_totals[E.spiderling_type] += E.spiderling_number
|
||||
else
|
||||
spider_totals[E.spiderling_type] = E.spiderling_number
|
||||
spider_totals["all"] += E.spiderling_number
|
||||
for(var/thing in GLOB.ts_spiderling_list)
|
||||
var/obj/structure/spider/spiderling/terror_spiderling/L = thing
|
||||
if(L.stillborn)
|
||||
continue
|
||||
if(check_mine && L.spider_myqueen != src)
|
||||
continue
|
||||
if(check_list && L.grow_as && !(L.grow_as in mytypes))
|
||||
continue
|
||||
if(spider_totals[L.grow_as])
|
||||
spider_totals[L.grow_as]++
|
||||
else
|
||||
spider_totals[L.grow_as] = 1
|
||||
spider_totals["all"]++
|
||||
return spider_totals
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
spider_opens_doors = 2
|
||||
web_type = /obj/structure/spider/terrorweb/purple
|
||||
ai_spins_webs = FALSE
|
||||
gender = MALE
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/prince/death(gibbed)
|
||||
if(can_die() && !hasdied && spider_uo71)
|
||||
|
||||
@@ -2,58 +2,80 @@
|
||||
// --------------------------------------------------------------------------------
|
||||
// ----------------- TERROR SPIDERS: T3 PRINCESS OF TERROR --------------------------
|
||||
// --------------------------------------------------------------------------------
|
||||
// -------------: ROLE: cutesy
|
||||
// -------------: AI: as green, but will evolve to queen when it can
|
||||
// -------------: SPECIAL: can evolve into a queen, if fed enough
|
||||
// -------------: TO FIGHT IT: kill it before it evolves
|
||||
// -------------: ROLE: mini-queen, maintains a smaller nest, but also more expendable
|
||||
// -------------: AI: maintains a small group of spiders. Small fraction of a queen's nest.
|
||||
// -------------: SPECIAL: lays eggs over time, like a queen
|
||||
// -------------: TO FIGHT IT: hunt it before it lays eggs
|
||||
// -------------: SPRITES FROM: FoS, https://www.paradisestation.org/forum/profile/335-fos
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/princess
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess
|
||||
name = "Princess of Terror spider"
|
||||
desc = "An enormous spider. It looks strangely cute and fluffy."
|
||||
spider_role_summary = "Future Queen"
|
||||
spider_role_summary = "Mini-Queen"
|
||||
ai_target_method = TS_DAMAGE_SIMPLE
|
||||
icon_state = "terror_princess1"
|
||||
icon_living = "terror_princess1"
|
||||
icon_dead = "terror_princess_dead1"
|
||||
icon_dead = "terror_princess1_dead"
|
||||
maxHealth = 150
|
||||
health = 150
|
||||
regen_points_per_hp = 1 // always regens very fast
|
||||
force_threshold = 18 // outright immune to anything of force under 18, same as queen
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 20
|
||||
idle_ventcrawl_chance = 5
|
||||
spider_tier = TS_TIER_3
|
||||
spider_opens_doors = 2
|
||||
web_type = /obj/structure/spider/terrorweb/queen
|
||||
var/feedings_to_evolve = 3
|
||||
var/datum/action/innate/terrorspider/ventsmash/ventsmash_action
|
||||
var/datum/action/innate/terrorspider/evolvequeen/evolvequeen_action
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/princess/New()
|
||||
..()
|
||||
ventsmash_action = new()
|
||||
ventsmash_action.Grant(src)
|
||||
evolvequeen_action = new()
|
||||
evolvequeen_action.Grant(src)
|
||||
// Unlike queens, no ranged attack.
|
||||
ranged = 0
|
||||
retreat_distance = 0
|
||||
minimum_distance = 0
|
||||
projectilesound = null
|
||||
projectiletype = null
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/princess/proc/evolve_to_queen()
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/queen/Q = new(loc)
|
||||
if(mind)
|
||||
mind.transfer_to(Q)
|
||||
// Calling `transfer_to()` removes our new body (the Queen's) ability to see the med hud, so we have to re-add the queen here.
|
||||
var/datum/atom_hud/U = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
|
||||
U.add_hud_to(Q)
|
||||
qdel(src)
|
||||
canlay = 0
|
||||
hasnested = TRUE
|
||||
spider_spawnfrequency = 300 // 30 seconds
|
||||
var/grant_prob = 25 // 25% chance every spider_spawnfrequency seconds to gain 1 egg
|
||||
var/spider_max_children = 8
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/princess/DoWrap()
|
||||
. = ..()
|
||||
if(fed == 0)
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess/grant_queen_subtype_abilities()
|
||||
// Queens start in movement mode, where they can ventcrawl but not lay eggs. Then they move to NestMode() where they can wallsmash and egglay, but not ventcrawl.
|
||||
// Princesses are simpler, and can always lay eggs, always vent crawl, but never smash walls. Unlike queens, they don't have a "nesting" transformation.
|
||||
queeneggs_action = new()
|
||||
queeneggs_action.Grant(src)
|
||||
queensense_action = new()
|
||||
queensense_action.Grant(src)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess/ListAvailableEggTypes()
|
||||
var/list/valid_types = list(TS_DESC_RED, TS_DESC_GRAY, TS_DESC_GREEN)
|
||||
|
||||
// Each princess can also have ONE black/purple/brown. If it dies, they can pick a new spider from the 3 advanced types to lay.
|
||||
var/list/spider_array = CountSpidersDetailed(TRUE, list(/mob/living/simple_animal/hostile/poison/terror_spider/black, /mob/living/simple_animal/hostile/poison/terror_spider/purple, /mob/living/simple_animal/hostile/poison/terror_spider/brown))
|
||||
if(spider_array["all"] < 1)
|
||||
valid_types |= TS_DESC_BLACK
|
||||
valid_types |= TS_DESC_PURPLE
|
||||
valid_types |= TS_DESC_BROWN
|
||||
|
||||
return valid_types
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess/grant_eggs()
|
||||
spider_lastspawn = world.time
|
||||
|
||||
if(!isturf(loc))
|
||||
to_chat(src, "<span class='danger'>You cannot generate eggs while hiding in [loc].</span>")
|
||||
return
|
||||
|
||||
if(!prob(grant_prob))
|
||||
return
|
||||
|
||||
var/list/spider_array = CountSpidersDetailed(TRUE)
|
||||
var/brood_count = spider_array["all"]
|
||||
|
||||
// Color shifts depending on how much of their brood capacity they have used.
|
||||
if(brood_count == 0)
|
||||
icon_state = "terror_princess1"
|
||||
icon_living = "terror_princess1"
|
||||
icon_dead = "terror_princess_dead1"
|
||||
icon_dead = "terror_princess1_dead"
|
||||
desc = "An enormous spider. It looks strangely cute and fluffy, with soft pink fur covering most of its body."
|
||||
else if(fed == 1)
|
||||
else if(brood_count < (spider_max_children /2))
|
||||
icon_state = "terror_princess2"
|
||||
icon_living = "terror_princess2"
|
||||
icon_dead = "terror_princess2_dead"
|
||||
@@ -62,13 +84,44 @@
|
||||
icon_state = "terror_princess3"
|
||||
icon_living = "terror_princess3"
|
||||
icon_dead = "terror_princess3_dead"
|
||||
desc = "An enormous spider. Its entire body has turned an ominous blood red color, with actual blood dripping from its jaws. It stares around, hungrily."
|
||||
desc = "An enormous spider. Its entire body looks to be the color of dried blood."
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/princess/spider_special_action()
|
||||
if(cocoon_target)
|
||||
handle_cocoon_target()
|
||||
else if(fed >= feedings_to_evolve)
|
||||
evolve_to_queen()
|
||||
else if(world.time > (last_cocoon_object + freq_cocoon_object))
|
||||
seek_cocoon_target()
|
||||
if((brood_count + canlay) >= spider_max_children)
|
||||
return
|
||||
canlay++
|
||||
if(canlay == 1)
|
||||
to_chat(src, "<span class='notice'>You have an egg available to lay.</span>")
|
||||
else
|
||||
to_chat(src, "<span class='notice'>You have [canlay] eggs available to lay.</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess/show_egg_timer()
|
||||
var/average_timer = (1 / (grant_prob / 100)) * (spider_spawnfrequency / 10)
|
||||
to_chat(src, "<span class='danger'>Too soon to attempt that again. You generate a new egg every [average_timer] seconds, on average.</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess/NestMode()
|
||||
// Princesses don't nest. However, we still need to override this in case an AI princess calls it.
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess/spider_special_action()
|
||||
// Princess AI routine. GREATLY simplified version of queen routine.
|
||||
if(!stat && !ckey)
|
||||
// Utilize normal queen AI for finding a nest site (neststep=0), and activating NestMode() (neststep=1)
|
||||
if(neststep != 2)
|
||||
return ..()
|
||||
// After that, simply lay an egg once per nestfrequency, until we have the max.
|
||||
if(world.time < (lastnestsetup + nestfrequency))
|
||||
return
|
||||
lastnestsetup = world.time
|
||||
if(ai_nest_is_full())
|
||||
return
|
||||
spider_lastspawn = world.time
|
||||
DoLayTerrorEggs(pick(spider_types_standard), 1)
|
||||
// Yes, this means NPC princesses won't create T2 spiders.
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess/ai_nest_is_full()
|
||||
var/list/spider_array = CountSpidersDetailed(TRUE)
|
||||
if(spider_array["all"] >= spider_max_children)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/purple/Life(seconds, times_fired)
|
||||
. = ..()
|
||||
if(.) // if mob is NOT dead
|
||||
if(stat != DEAD) // Can't use if(.) for this due to the fact it can sometimes return FALSE even when mob is alive.
|
||||
if(!degenerate && spider_myqueen)
|
||||
if(dcheck_counter >= 10)
|
||||
dcheck_counter = 0
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
// -------------: ROLE: gamma-level threat to the whole station, like a blob
|
||||
// -------------: AI: builds a nest, lays many eggs, attempts to take over the station
|
||||
// -------------: SPECIAL: spins webs, breaks lights, breaks cameras, webs objects, lays eggs, commands other spiders...
|
||||
// -------------: TO FIGHT IT: bring an army, and take no prisoners. Mechs and/or decloner guns are a very good idea.
|
||||
// -------------: TO FIGHT IT: bring an army, and take no prisoners. Mechs are a very good idea.
|
||||
// -------------: SPRITES FROM: IK3I
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen
|
||||
@@ -43,69 +43,94 @@
|
||||
var/neststep = 0
|
||||
var/hasnested = FALSE
|
||||
var/spider_max_per_nest = 35 // above this, AI queens become stable
|
||||
var/canlay = 4 // main counter for egg-laying ability! # = num uses, incremented at intervals
|
||||
var/canlay = 5 // main counter for egg-laying ability! # = num uses, incremented at intervals
|
||||
var/eggslaid = 0
|
||||
var/spider_can_fakelings = 3 // spawns defective spiderlings that don't grow up, used to freak out crew, atmosphere
|
||||
var/list/spider_types_standard = list(/mob/living/simple_animal/hostile/poison/terror_spider/red, /mob/living/simple_animal/hostile/poison/terror_spider/gray, /mob/living/simple_animal/hostile/poison/terror_spider/green, /mob/living/simple_animal/hostile/poison/terror_spider/black)
|
||||
var/datum/action/innate/terrorspider/queen/queennest/queennest_action
|
||||
var/datum/action/innate/terrorspider/queen/queensense/queensense_action
|
||||
var/datum/action/innate/terrorspider/queen/queeneggs/queeneggs_action
|
||||
var/datum/action/innate/terrorspider/queen/queenfakelings/queenfakelings_action
|
||||
var/datum/action/innate/terrorspider/ventsmash/ventsmash_action
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/New()
|
||||
..()
|
||||
queennest_action = new()
|
||||
queennest_action.Grant(src)
|
||||
ventsmash_action = new()
|
||||
ventsmash_action.Grant(src)
|
||||
grant_queen_subtype_abilities()
|
||||
spider_myqueen = src
|
||||
if(spider_awaymission)
|
||||
spider_growinstantly = 1
|
||||
spider_growinstantly = TRUE
|
||||
spider_spawnfrequency = 150
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/grant_queen_subtype_abilities()
|
||||
queennest_action = new()
|
||||
queennest_action.Grant(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/Life(seconds, times_fired)
|
||||
. = ..()
|
||||
if(.) // if mob is NOT dead
|
||||
if(ckey && canlay < 12 && hasnested) // max 12 eggs worth stored at any one time, realistically that's tons.
|
||||
if(stat != DEAD) // Can't use if(.) for this due to the fact it can sometimes return FALSE even when mob is alive.
|
||||
if(ckey && hasnested)
|
||||
if(world.time > (spider_lastspawn + spider_spawnfrequency))
|
||||
if(eggslaid >= 20)
|
||||
canlay += 3
|
||||
else if(eggslaid >= 10)
|
||||
canlay += 2
|
||||
else
|
||||
canlay++
|
||||
spider_lastspawn = world.time
|
||||
if(canlay == 1)
|
||||
to_chat(src, "<span class='notice'>You have an egg available to lay.</span>")
|
||||
else if(canlay == 12)
|
||||
to_chat(src, "<span class='notice'>You have [canlay] eggs available to lay. You won't grow any more eggs until you lay some of your existing ones.</span>")
|
||||
else
|
||||
to_chat(src, "<span class='notice'>You have [canlay] eggs available to lay.</span>")
|
||||
grant_eggs()
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/grant_eggs()
|
||||
spider_lastspawn = world.time
|
||||
canlay += getSpiderLevel()
|
||||
if(canlay == 1)
|
||||
to_chat(src, "<span class='notice'>You have an egg available to lay.</span>")
|
||||
else if(canlay > 1)
|
||||
to_chat(src, "<span class='notice'>You have [canlay] eggs available to lay.</span>")
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/getSpiderLevel()
|
||||
return 1 + round(MinutesAlive() / 10)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/MinutesAlive()
|
||||
return round((world.time - spider_creation_time) / 600)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/death(gibbed)
|
||||
if(can_die() && !hasdied)
|
||||
if(spider_uo71)
|
||||
UnlockBlastDoors("UO71_Caves")
|
||||
// When a queen dies, so do her player-controlled purple-type guardians. Intended as a motivator for purples to ensure they guard her.
|
||||
for(var/mob/living/simple_animal/hostile/poison/terror_spider/purple/P in GLOB.ts_spiderlist)
|
||||
if(ckey)
|
||||
P.visible_message("<span class='danger'>\The [src] writhes in pain!</span>")
|
||||
to_chat(P,"<span class='userdanger'>\The [src] has died. Without her hivemind link, purple terrors like yourself cannot survive more than a few minutes!</span>")
|
||||
P.degenerate = 1
|
||||
// When a queen (or subtype!) dies, so do all of her spiderlings, and half of all her fully grown offspring
|
||||
// This feature is intended to provide a way for crew to still win even if the queen has overwhelming numbers - by sniping the queen.
|
||||
for(var/thing in GLOB.ts_spiderlist)
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/T = thing
|
||||
if(!T.spider_myqueen)
|
||||
continue
|
||||
if(T.spider_myqueen != src)
|
||||
continue
|
||||
if(prob(50) || T.spider_tier >= spider_tier)
|
||||
to_chat(T, "<span class='userdanger'>\The psychic backlash from the death of [src] crashes into your mind! Somehow... you find a way to keep going!</span>")
|
||||
continue
|
||||
T.visible_message("<span class='danger'>[T] writhes in pain!</span>")
|
||||
to_chat(T, "<span class='userdanger'>\The psychic backlash from the death of [src] overwhelms you! You feel the life start to drain out of you...</span>")
|
||||
T.degenerate = TRUE
|
||||
for(var/thing in GLOB.ts_spiderling_list)
|
||||
var/obj/structure/spider/spiderling/terror_spiderling/T = thing
|
||||
if(T.spider_myqueen && T.spider_myqueen == src)
|
||||
qdel(T)
|
||||
return ..()
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/Retaliate()
|
||||
..()
|
||||
for(var/mob/living/simple_animal/hostile/poison/terror_spider/T in GLOB.ts_spiderlist)
|
||||
for(var/thing in GLOB.ts_spiderlist)
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/T = thing
|
||||
T.enemies |= enemies
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/ai_nest_is_full()
|
||||
var/numspiders = CountSpiders()
|
||||
if(numspiders >= spider_max_per_nest)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/spider_special_action()
|
||||
if(!stat && !ckey)
|
||||
switch(neststep)
|
||||
@@ -152,11 +177,13 @@
|
||||
neststep = 2
|
||||
NestMode()
|
||||
if(2)
|
||||
// Create initial four purple nest guards.
|
||||
// Create initial T2 spiders.
|
||||
if(world.time > (lastnestsetup + nestfrequency))
|
||||
lastnestsetup = world.time
|
||||
spider_lastspawn = world.time
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/purple, 4)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/purple, 2)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/white, 2)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/brown, 2)
|
||||
neststep = 3
|
||||
if(3)
|
||||
// Create spiders (random types) until nest is full.
|
||||
@@ -183,28 +210,26 @@
|
||||
neststep = 4
|
||||
else
|
||||
spider_lastspawn = world.time
|
||||
var/num_purple = CountSpidersType(/mob/living/simple_animal/hostile/poison/terror_spider/purple)
|
||||
var/num_white = CountSpidersType(/mob/living/simple_animal/hostile/poison/terror_spider/white)
|
||||
var/num_brown = CountSpidersType(/mob/living/simple_animal/hostile/poison/terror_spider/brown)
|
||||
if(num_purple < 4)
|
||||
var/list/spider_array = CountSpidersDetailed(FALSE)
|
||||
if(spider_array[/mob/living/simple_animal/hostile/poison/terror_spider/purple] < 4)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/purple, 2)
|
||||
else if(num_white < 2)
|
||||
else if(spider_array[/mob/living/simple_animal/hostile/poison/terror_spider/white] < 2)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/white, 2)
|
||||
else if(num_brown < 4)
|
||||
else if(spider_array[/mob/living/simple_animal/hostile/poison/terror_spider/brown] < 4)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/brown, 4)
|
||||
else
|
||||
DoLayTerrorEggs(pick(spider_types_standard), 5)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/NestPrompt()
|
||||
var/confirm = alert(src, "Are you sure you want to nest? You will be able to lay eggs, and smash walls, but not ventcrawl.","Nest?","Yes","No")
|
||||
if(confirm == "Yes")
|
||||
NestMode()
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/NestMode()
|
||||
queeneggs_action = new()
|
||||
queeneggs_action.Grant(src)
|
||||
queenfakelings_action = new()
|
||||
queenfakelings_action.Grant(src)
|
||||
queensense_action = new()
|
||||
queensense_action.Grant(src)
|
||||
queennest_action.Remove(src)
|
||||
@@ -213,21 +238,8 @@
|
||||
ai_ventcrawls = FALSE
|
||||
environment_smash = ENVIRONMENT_SMASH_RWALLS
|
||||
DoQueenScreech(8, 100, 8, 100)
|
||||
MassFlicker()
|
||||
to_chat(src, "<span class='notice'>You have matured to your egglaying stage. You can now smash through walls, and lay eggs, but can no longer ventcrawl.</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/MassFlicker()
|
||||
var/list/target_lights = list()
|
||||
for(var/mob/living/carbon/human/H in GLOB.player_list)
|
||||
if(H.z != z)
|
||||
continue
|
||||
if(H.stat == DEAD)
|
||||
continue
|
||||
for(var/obj/machinery/light/L in orange(7, H))
|
||||
if(L.on && prob(25))
|
||||
target_lights += L
|
||||
for(var/obj/machinery/light/I in target_lights)
|
||||
I.flicker()
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/LayQueenEggs()
|
||||
if(stat == DEAD)
|
||||
@@ -236,48 +248,23 @@
|
||||
to_chat(src, "<span class='danger'>You must nest before doing this.</span>")
|
||||
return
|
||||
if(canlay < 1)
|
||||
var/remainingtime = round(((spider_lastspawn + spider_spawnfrequency) - world.time) / 10, 1)
|
||||
if(remainingtime > 0)
|
||||
to_chat(src, "<span class='danger'>Too soon to attempt that again. Wait another [num2text(remainingtime)] seconds.</span>")
|
||||
else
|
||||
to_chat(src, "<span class='danger'>Too soon to attempt that again. Wait just a few more seconds...</span>")
|
||||
show_egg_timer()
|
||||
return
|
||||
var/list/eggtypes = list(TS_DESC_RED, TS_DESC_GRAY, TS_DESC_GREEN, TS_DESC_BLACK, TS_DESC_PURPLE)
|
||||
if(canlay >= 4)
|
||||
eggtypes |= TS_DESC_BROWN
|
||||
if(canlay >= 12)
|
||||
eggtypes |= TS_DESC_MOTHER
|
||||
eggtypes |= TS_DESC_PRINCE
|
||||
var/num_purples = CountSpidersType(/mob/living/simple_animal/hostile/poison/terror_spider/purple)
|
||||
if(num_purples >= 2)
|
||||
eggtypes -= TS_DESC_PURPLE
|
||||
var/num_blacks = CountSpidersType(/mob/living/simple_animal/hostile/poison/terror_spider/black)
|
||||
if(num_blacks >= 2)
|
||||
eggtypes -= TS_DESC_BLACK
|
||||
var/list/eggtypes = ListAvailableEggTypes()
|
||||
var/list/eggtypes_uncapped = list(TS_DESC_RED, TS_DESC_GRAY, TS_DESC_GREEN)
|
||||
|
||||
var/eggtype = input("What kind of eggs?") as null|anything in eggtypes
|
||||
if(canlay < 1)
|
||||
// this was checked before input() but we have to check again to prevent them spam-clicking the popup.
|
||||
to_chat(src, "<span class='danger'>Too soon to lay another egg.</span>")
|
||||
return
|
||||
if(!(eggtype in eggtypes))
|
||||
to_chat(src, "<span class='danger'>Unrecognized egg type.</span>")
|
||||
return 0
|
||||
if(eggtype == TS_DESC_MOTHER || eggtype == TS_DESC_PRINCE)
|
||||
if(canlay < 12)
|
||||
to_chat(src, "<span class='danger'>Insufficient strength. It takes as much effort to lay one of those as it does to lay 12 normal eggs.</span>")
|
||||
else
|
||||
if(eggtype == TS_DESC_MOTHER)
|
||||
canlay -= 12
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/mother, 1)
|
||||
else if(eggtype == TS_DESC_PRINCE)
|
||||
canlay -= 12
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/prince, 1)
|
||||
return
|
||||
else if(eggtype == TS_DESC_BROWN)
|
||||
if(canlay < 4)
|
||||
to_chat(src, "<span class='danger'>Insufficient strength. It takes as much effort to lay one of those as it does to lay 4 normal eggs.</span>")
|
||||
else
|
||||
canlay -= 4
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/brown, 1)
|
||||
return
|
||||
|
||||
// Multiple of eggtypes_uncapped can be laid at once. Other types must be laid one at a time (to prevent exploits)
|
||||
var/numlings = 1
|
||||
if(eggtype != TS_DESC_PURPLE)
|
||||
if(eggtype in eggtypes_uncapped)
|
||||
if(canlay >= 5)
|
||||
numlings = input("How many in the batch?") as null|anything in list(1, 2, 3, 4, 5)
|
||||
else if(canlay >= 3)
|
||||
@@ -287,23 +274,61 @@
|
||||
if(eggtype == null || numlings == null)
|
||||
to_chat(src, "<span class='danger'>Cancelled.</span>")
|
||||
return
|
||||
// Actually lay the eggs.
|
||||
if(canlay < numlings)
|
||||
// We have to check this again after the popups, to account for people spam-clicking the button, then doing all the popups at once.
|
||||
to_chat(src, "<span class='warning'>Too soon to do this again!</span>")
|
||||
return
|
||||
canlay -= numlings
|
||||
eggslaid += numlings
|
||||
if(eggtype == TS_DESC_RED)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/red, numlings)
|
||||
else if(eggtype == TS_DESC_GRAY)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/gray, numlings)
|
||||
else if(eggtype == TS_DESC_GREEN)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/green, numlings)
|
||||
else if(eggtype == TS_DESC_BLACK)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/black, numlings)
|
||||
else if(eggtype == TS_DESC_PURPLE)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/purple, numlings)
|
||||
switch(eggtype)
|
||||
if(TS_DESC_RED)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/red, numlings)
|
||||
if(TS_DESC_GRAY)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/gray, numlings)
|
||||
if(TS_DESC_GREEN)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/green, numlings)
|
||||
if(TS_DESC_BLACK)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/black, numlings)
|
||||
if(TS_DESC_PURPLE)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/purple, numlings)
|
||||
if(TS_DESC_BROWN)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/brown, numlings)
|
||||
if(TS_DESC_MOTHER)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/mother, numlings)
|
||||
if(TS_DESC_PRINCE)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/prince, numlings)
|
||||
if(TS_DESC_PRINCESS)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess, numlings)
|
||||
else
|
||||
to_chat(src, "<span class='danger'>Unrecognized egg type.</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/show_egg_timer()
|
||||
var/remainingtime = round(((spider_lastspawn + spider_spawnfrequency) - world.time) / 10, 1)
|
||||
if(remainingtime > 0)
|
||||
to_chat(src, "<span class='danger'>Too soon to attempt that again. Wait another [num2text(remainingtime)] seconds.</span>")
|
||||
else
|
||||
to_chat(src, "<span class='danger'>Unrecognized egg type.</span>")
|
||||
to_chat(src, "<span class='danger'>Too soon to attempt that again. Wait just a few more seconds...</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/ListAvailableEggTypes()
|
||||
if(MinutesAlive() >= 20)
|
||||
var/list/spider_array = CountSpidersDetailed(TRUE, list(/mob/living/simple_animal/hostile/poison/terror_spider/mother, /mob/living/simple_animal/hostile/poison/terror_spider/prince, /mob/living/simple_animal/hostile/poison/terror_spider/queen/princess))
|
||||
if(spider_array["all"] == 0)
|
||||
return list(TS_DESC_PRINCE, TS_DESC_PRINCESS) // Mother will be added to this list.... AFTER mothers are reworked.
|
||||
|
||||
var/list/valid_types = list(TS_DESC_RED, TS_DESC_GRAY, TS_DESC_GREEN)
|
||||
var/list/spider_array = CountSpidersDetailed(FALSE, list(/mob/living/simple_animal/hostile/poison/terror_spider/brown, /mob/living/simple_animal/hostile/poison/terror_spider/purple, /mob/living/simple_animal/hostile/poison/terror_spider/black))
|
||||
if(spider_array[/mob/living/simple_animal/hostile/poison/terror_spider/brown] < 2)
|
||||
valid_types += TS_DESC_BROWN
|
||||
if(spider_array[/mob/living/simple_animal/hostile/poison/terror_spider/purple] < 2)
|
||||
valid_types += TS_DESC_PURPLE
|
||||
if(spider_array[/mob/living/simple_animal/hostile/poison/terror_spider/black] < 2)
|
||||
valid_types += TS_DESC_BLACK
|
||||
return valid_types
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/DoQueenScreech(light_range, light_chance, camera_range, camera_chance)
|
||||
visible_message("<span class='userdanger'>\The [src] emits a bone-chilling shriek!</span>")
|
||||
visible_message("<span class='userdanger'>[src] emits a bone-chilling shriek!</span>")
|
||||
for(var/obj/machinery/light/L in orange(light_range, src))
|
||||
if(L.on && prob(light_chance))
|
||||
L.break_light_tube()
|
||||
@@ -311,46 +336,37 @@
|
||||
if(C.status && prob(camera_chance))
|
||||
C.toggle_cam(src, 0)
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/QueenFakeLings()
|
||||
if(eggslaid < 10)
|
||||
to_chat(src, "<span class='danger'>You must lay at least 10 eggs before doing this.</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/examine(mob/user)
|
||||
. = ..()
|
||||
if(!key || stat == DEAD)
|
||||
return
|
||||
if(spider_can_fakelings)
|
||||
spider_can_fakelings--
|
||||
var/numlings = 25
|
||||
for(var/i in 1 to numlings)
|
||||
var/obj/structure/spider/spiderling/terror_spiderling/S = new /obj/structure/spider/spiderling/terror_spiderling(get_turf(src))
|
||||
S.grow_as = /mob/living/simple_animal/hostile/poison/terror_spider/red
|
||||
S.stillborn = 1
|
||||
S.spider_mymother = src
|
||||
if(!spider_can_fakelings)
|
||||
queenfakelings_action.Remove(src)
|
||||
else
|
||||
to_chat(src, "<span class='danger'>You have run out of uses of this ability.</span>")
|
||||
if(!isobserver(user) && !isterrorspider(user))
|
||||
return
|
||||
. += "<span class='notice'>[p_they(TRUE)] has laid [eggslaid] egg[eggslaid != 1 ? "s" : ""].</span>"
|
||||
. += "<span class='notice'>[p_they(TRUE)] has lived for [MinutesAlive()] minutes.</span>"
|
||||
|
||||
|
||||
/obj/item/projectile/terrorqueenspit
|
||||
name = "poisonous spit"
|
||||
damage = 0
|
||||
name = "acid spit"
|
||||
damage = 40
|
||||
icon_state = "toxin"
|
||||
damage_type = TOX
|
||||
var/bonus_tox = 30
|
||||
damage_type = BURN
|
||||
|
||||
/obj/item/projectile/terrorqueenspit/on_hit(mob/living/carbon/target, blocked = 0, hit_zone)
|
||||
if(ismob(target) && blocked < 100)
|
||||
var/mob/living/L = target
|
||||
if(L.reagents)
|
||||
if(L.can_inject(null, FALSE, "chest", FALSE))
|
||||
L.Hallucinate(400)
|
||||
if(!isterrorspider(L))
|
||||
L.adjustToxLoss(bonus_tox)
|
||||
|
||||
/obj/structure/spider/terrorweb/queen
|
||||
name = "shimmering web"
|
||||
desc = "This web seems to shimmer all different colors in the light."
|
||||
name = "airtight web"
|
||||
desc = "This multi-layered web seems to be able to resist air pressure."
|
||||
|
||||
/obj/structure/spider/terrorweb/queen/web_special_ability(mob/living/carbon/C)
|
||||
if(istype(C))
|
||||
var/inject_target = pick("chest","head")
|
||||
if(C.can_inject(null, FALSE, inject_target, FALSE))
|
||||
C.Hallucinate(400)
|
||||
C.adjustToxLoss(30)
|
||||
|
||||
/obj/structure/spider/terrorweb/queen/New()
|
||||
. = ..()
|
||||
air_update_turf(TRUE)
|
||||
|
||||
/obj/structure/spider/terrorweb/queen/CanAtmosPass(turf/T)
|
||||
return FALSE
|
||||
|
||||
/obj/structure/spider/terrorweb/queen/Destroy()
|
||||
var/turf/T = get_turf(src)
|
||||
. = ..()
|
||||
T.air_update_turf(TRUE)
|
||||
|
||||
@@ -188,7 +188,7 @@
|
||||
C.enemies = enemies
|
||||
if(spider_growinstantly)
|
||||
C.amount_grown = 250
|
||||
C.spider_growinstantly = 1
|
||||
C.spider_growinstantly = TRUE
|
||||
spawn(10)
|
||||
stop_automated_movement = 0
|
||||
|
||||
@@ -196,7 +196,7 @@
|
||||
name = "terror egg cluster"
|
||||
desc = "A cluster of tiny spider eggs. They pulse with a strong inner life, and appear to have sharp thorns on the sides."
|
||||
icon_state = "eggs"
|
||||
var/spider_growinstantly = 0
|
||||
var/spider_growinstantly = FALSE
|
||||
var/spider_myqueen = null
|
||||
var/spider_mymother = null
|
||||
var/spiderling_type = null
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
spider_steps_taken++
|
||||
CreatePath(entry_vent)
|
||||
step_to(src,entry_vent)
|
||||
if(spider_debug > 0)
|
||||
if(spider_debug)
|
||||
visible_message("<span class='notice'>[src] moves towards the vent [entry_vent].</span>")
|
||||
else
|
||||
path_to_vent = 0
|
||||
|
||||
@@ -17,6 +17,7 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
|
||||
// Name / Description
|
||||
name = "terror spider"
|
||||
desc = "The generic parent of all other terror spider types. If you see this in-game, it is a bug."
|
||||
gender = FEMALE
|
||||
|
||||
// Icons
|
||||
icon = 'icons/mob/terrorspider.dmi'
|
||||
@@ -141,29 +142,33 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
|
||||
var/mylocation = null
|
||||
var/chasecycles = 0
|
||||
var/web_infects = 0
|
||||
var/spider_creation_time = 0
|
||||
|
||||
var/datum/action/innate/terrorspider/web/web_action
|
||||
var/web_type = /obj/structure/spider/terrorweb
|
||||
var/datum/action/innate/terrorspider/wrap/wrap_action
|
||||
|
||||
// Breathing - require some oxygen, and no toxins, but take little damage from this requirement not being met (they can hold their breath)
|
||||
// Breathing - require some oxygen, and no toxins
|
||||
atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 1, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
unsuitable_atmos_damage = 1
|
||||
|
||||
// Temperature - can freeze in space and cook in plasma, but it takes extreme temperatures to do this.
|
||||
minbodytemp = 100
|
||||
maxbodytemp = 500
|
||||
heat_damage_per_tick = 3
|
||||
// Temperature
|
||||
heat_damage_per_tick = 5 // Takes 250% normal damage from being in a hot environment ("kill it with fire!")
|
||||
|
||||
// DEBUG OPTIONS & COMMANDS
|
||||
var/spider_growinstantly = 0 // DEBUG OPTION, DO NOT ENABLE THIS ON LIVE. IT IS USED TO TEST NEST GROWTH/SETUP AI.
|
||||
var/spider_debug = 0
|
||||
var/spider_growinstantly = FALSE // DEBUG OPTION, DO NOT ENABLE THIS ON LIVE. IT IS USED TO TEST NEST GROWTH/SETUP AI.
|
||||
var/spider_debug = FALSE
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// --------------------- TERROR SPIDERS: SHARED ATTACK CODE -----------------------
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
|
||||
// Forces terrors to use the 'bite' graphic when attacking something. Same as code/modules/mob/living/carbon/alien/larva/larva_defense.dm#L34
|
||||
if(!no_effect && !visual_effect_icon)
|
||||
visual_effect_icon = ATTACK_EFFECT_BITE
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/AttackingTarget()
|
||||
if(isterrorspider(target))
|
||||
if(target in enemies)
|
||||
@@ -187,14 +192,13 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
|
||||
if(F.welded)
|
||||
to_chat(src, "The fire door is welded shut.")
|
||||
else
|
||||
visible_message("<span class='danger'>\The [src] pries open the firedoor!</span>")
|
||||
visible_message("<span class='danger'>[src] pries open the firedoor!</span>")
|
||||
F.open()
|
||||
else
|
||||
to_chat(src, "Closing fire doors does not help.")
|
||||
else if(istype(target, /obj/machinery/door/airlock))
|
||||
var/obj/machinery/door/airlock/A = target
|
||||
if(A.density)
|
||||
try_open_airlock(A)
|
||||
try_open_airlock(A)
|
||||
else if(isliving(target) && (!client || a_intent == INTENT_HARM))
|
||||
var/mob/living/G = target
|
||||
if(issilicon(G))
|
||||
@@ -221,27 +225,23 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/examine(mob/user)
|
||||
. = ..()
|
||||
var/list/msgs = list()
|
||||
if(stat == DEAD)
|
||||
msgs += "<span class='notice'>It appears to be dead.</span>\n"
|
||||
else
|
||||
if(stat != DEAD)
|
||||
if(key)
|
||||
msgs += "<span class='warning'>Its eyes regard you with a curious intelligence.</span>"
|
||||
. += "<span class='warning'>[p_they(TRUE)] regards [p_their()] surroundings with a curious intelligence.</span>"
|
||||
if(health > (maxHealth*0.95))
|
||||
msgs += "<span class='notice'>It is in excellent health.</span>"
|
||||
. += "<span class='notice'>[p_they(TRUE)] is in excellent health.</span>"
|
||||
else if(health > (maxHealth*0.75))
|
||||
msgs += "<span class='notice'>It has a few injuries.</span>"
|
||||
. += "<span class='notice'>[p_they(TRUE)] has a few injuries.</span>"
|
||||
else if(health > (maxHealth*0.55))
|
||||
msgs += "<span class='warning'>It has many injuries.</span>"
|
||||
. += "<span class='warning'>[p_they(TRUE)] has many injuries.</span>"
|
||||
else if(health > (maxHealth*0.25))
|
||||
msgs += "<span class='warning'>It is barely clinging on to life!</span>"
|
||||
. += "<span class='warning'>[p_they(TRUE)] is barely clinging on to life!</span>"
|
||||
if(degenerate)
|
||||
msgs += "<span class='warning'>It appears to be dying.</span>"
|
||||
. += "<span class='warning'>[p_they(TRUE)] appears to be dying.</span>"
|
||||
else if(health < maxHealth && regen_points > regen_points_per_kill)
|
||||
msgs += "<span class='notice'>It appears to be regenerating quickly.</span>"
|
||||
. += "<span class='notice'>[p_they(TRUE)] appears to be regenerating quickly.</span>"
|
||||
if(killcount >= 1)
|
||||
msgs += "<span class='warning'>It has blood dribbling from its mouth.</span>"
|
||||
. += msgs.Join("<BR>")
|
||||
. += "<span class='warning'>[p_they(TRUE)] has blood dribbling from [p_their()] mouth.</span>"
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/New()
|
||||
..()
|
||||
@@ -254,9 +254,10 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
|
||||
if(web_type)
|
||||
web_action = new()
|
||||
web_action.Grant(src)
|
||||
wrap_action = new()
|
||||
wrap_action.Grant(src)
|
||||
|
||||
if(regen_points_per_tick < regen_points_per_hp)
|
||||
// Only grant the Wrap action button to spiders who need to use it to regenerate their health
|
||||
wrap_action = new()
|
||||
wrap_action.Grant(src)
|
||||
name += " ([rand(1, 1000)])"
|
||||
real_name = name
|
||||
msg_terrorspiders("[src] has grown in [get_area(src)].")
|
||||
@@ -278,6 +279,7 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
|
||||
addtimer(CALLBACK(src, .proc/announcetoghosts), 30)
|
||||
var/datum/atom_hud/U = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
|
||||
U.add_hud_to(src)
|
||||
spider_creation_time = world.time
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/announcetoghosts()
|
||||
if(spider_awaymission)
|
||||
@@ -285,8 +287,7 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
|
||||
if(stat == DEAD)
|
||||
return
|
||||
if(ckey)
|
||||
var/image/alert_overlay = image('icons/mob/terrorspider.dmi', icon_state)
|
||||
notify_ghosts("[src] has appeared in [get_area(src)]. (already player-controlled)", source = src, alert_overlay = alert_overlay)
|
||||
notify_ghosts("[src] (player controlled) has appeared in [get_area(src)].")
|
||||
else if(ai_playercontrol_allowtype)
|
||||
var/image/alert_overlay = image('icons/mob/terrorspider.dmi', icon_state)
|
||||
notify_ghosts("[src] has appeared in [get_area(src)].", enter_link = "<a href=?src=[UID()];activate=1>(Click to control)</a>", source = src, alert_overlay = alert_overlay, action = NOTIFY_ATTACK)
|
||||
@@ -298,7 +299,7 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/Life(seconds, times_fired)
|
||||
. = ..()
|
||||
if(!.) // if mob is dead
|
||||
if(stat == DEAD) // Can't use if(.) for this due to the fact it can sometimes return FALSE even when mob is alive.
|
||||
if(prob(2))
|
||||
// 2% chance every cycle to decompose
|
||||
visible_message("<span class='notice'>\The dead body of the [src] decomposes!</span>")
|
||||
@@ -342,7 +343,7 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/ObjBump(obj/O)
|
||||
if(istype(O, /obj/machinery/door/airlock))
|
||||
var/obj/machinery/door/airlock/L = O
|
||||
if(L.density)
|
||||
if(L.density) // must check density here, to avoid rapid bumping of an airlock that is in the process of opening, instantly forcing it closed
|
||||
return try_open_airlock(L)
|
||||
if(istype(O, /obj/machinery/door/firedoor))
|
||||
var/obj/machinery/door/firedoor/F = O
|
||||
@@ -352,7 +353,8 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/msg_terrorspiders(msgtext)
|
||||
for(var/mob/living/simple_animal/hostile/poison/terror_spider/T in GLOB.ts_spiderlist)
|
||||
for(var/thing in GLOB.ts_spiderlist)
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/T = thing
|
||||
if(T.stat != DEAD)
|
||||
to_chat(T, "<span class='terrorspider'>TerrorSense: [msgtext]</span>")
|
||||
|
||||
@@ -365,21 +367,61 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/try_open_airlock(obj/machinery/door/airlock/D)
|
||||
if(D.operating)
|
||||
return
|
||||
if(!D.density)
|
||||
to_chat(src, "<span class='warning'>Closing doors does not help us.</span>")
|
||||
else if(D.welded)
|
||||
to_chat(src, "<span class='warning'>The door is welded shut.</span>")
|
||||
if(D.welded)
|
||||
to_chat(src, "<span class='warning'>The door is welded.</span>")
|
||||
else if(D.locked)
|
||||
to_chat(src, "<span class='warning'>The door is bolted shut.</span>")
|
||||
to_chat(src, "<span class='warning'>The door is bolted.</span>")
|
||||
else if(D.allowed(src))
|
||||
D.open(1)
|
||||
return 1
|
||||
if(D.density)
|
||||
D.open(TRUE)
|
||||
else
|
||||
D.close(TRUE)
|
||||
return TRUE
|
||||
else if(D.arePowerSystemsOn() && (spider_opens_doors != 2))
|
||||
to_chat(src, "<span class='warning'>The door's motors resist your efforts to force it.</span>")
|
||||
else if(!spider_opens_doors)
|
||||
to_chat(src, "<span class='warning'>Your type of spider is not strong enough to force open doors.</span>")
|
||||
else
|
||||
visible_message("<span class='danger'>[src] pries open the door!</span>")
|
||||
visible_message("<span class='danger'>[src] forces the door!</span>")
|
||||
playsound(src.loc, "sparks", 100, 1)
|
||||
D.open(1)
|
||||
return 1
|
||||
if(D.density)
|
||||
D.open(TRUE)
|
||||
else
|
||||
D.close(TRUE)
|
||||
return TRUE
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/get_spacemove_backup()
|
||||
. = ..()
|
||||
// If we don't find any normal thing to use, attempt to use any nearby spider structure instead.
|
||||
if(!.)
|
||||
for(var/obj/structure/spider/S in range(1, get_turf(src)))
|
||||
return S
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/Stat()
|
||||
..()
|
||||
// Determines what shows in the "Status" tab for player-controlled spiders. Used to help players understand spider health regeneration mechanics.
|
||||
// Uses <font color='#X'> because the status panel does NOT accept <span class='X'>.
|
||||
if(statpanel("Status") && ckey && stat == CONSCIOUS)
|
||||
if(degenerate)
|
||||
stat(null, "<font color='#eb4034'>Hivemind Connection Severed! Dying...</font>") // color=red
|
||||
return
|
||||
if(health != maxHealth)
|
||||
var/hp_points_per_second = 0
|
||||
var/ltext = "FAST"
|
||||
var/lcolor = "#fcba03" // orange
|
||||
var/secs_per_tick = (SSmobs.wait / 10) // This uses SSmobs.wait because it must use the same frequency as mobs are processed
|
||||
if(regen_points < (regen_points_per_hp * 2))
|
||||
// Slow regen speed: using regen_points as we get them. Figure out regen_points/sec, then convert that to hp/sec.
|
||||
var/regen_points_per_second = (regen_points_per_tick / secs_per_tick)
|
||||
hp_points_per_second = (regen_points_per_second / regen_points_per_hp)
|
||||
ltext = "SLOW (HUNGRY!)"
|
||||
lcolor = "#eb4034" // red
|
||||
else
|
||||
// Fast regen speed: healing at full 1 hp / tick rate. Just divide 1hp/tick by seconds/tick to get healing/sec.
|
||||
hp_points_per_second = 1 / secs_per_tick
|
||||
if(hp_points_per_second > 0)
|
||||
var/pc_of_max_per_second = round(((hp_points_per_second / maxHealth) * 100), 0.1)
|
||||
stat(null, "Regeneration: [ltext]: <font color='[lcolor]'>[num2text(pc_of_max_per_second)]% of health per second</font>")
|
||||
|
||||
|
||||
|
||||
@@ -86,6 +86,7 @@
|
||||
|
||||
//Parrots are kleptomaniacs. This variable ... stores the item a parrot is holding.
|
||||
var/obj/item/held_item = null
|
||||
flying = TRUE
|
||||
gold_core_spawnable = FRIENDLY_SPAWN
|
||||
|
||||
|
||||
@@ -710,7 +711,7 @@
|
||||
ears.talk_into(src, message_pieces, message_mode, verb)
|
||||
used_radios += ears
|
||||
|
||||
/mob/living/simple_animal/parrot/hear_say(list/message_pieces, verb = "says", italics = 0, mob/speaker = null, sound/speech_sound, sound_vol, sound_frequency)
|
||||
/mob/living/simple_animal/parrot/hear_say(list/message_pieces, verb = "says", italics = 0, mob/speaker = null, sound/speech_sound, sound_vol, sound_frequency, use_voice = TRUE)
|
||||
if(speaker != src && prob(50))
|
||||
parrot_hear(html_decode(multilingual_to_message(message_pieces)))
|
||||
..()
|
||||
|
||||
@@ -32,8 +32,9 @@
|
||||
animate_ghostly_presence(src, -1, 20, 1) // Restart the floating animation after the attack animation, as it will be cancelled.
|
||||
|
||||
|
||||
/mob/living/simple_animal/possessed_object/start_pulling(var/atom/movable/AM) // Silly motherfuckers think they can pull things.
|
||||
to_chat(src, "<span class='warning'>You are unable to pull [AM]!</span>")
|
||||
/mob/living/simple_animal/possessed_object/start_pulling(atom/movable/AM, state, force = pull_force, show_message = FALSE) // Silly motherfuckers think they can pull things.
|
||||
if(show_message)
|
||||
to_chat(src, "<span class='warning'>You are unable to pull [AM]!</span>")
|
||||
|
||||
|
||||
/mob/living/simple_animal/possessed_object/ghost() // Ghosting will return the object to normal, and will not disqualify the ghoster from various mid-round antag positions.
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
status_flags = 0
|
||||
faction = list("cult")
|
||||
status_flags = CANPUSH
|
||||
flying = TRUE
|
||||
loot = list(/obj/item/reagent_containers/food/snacks/ectoplasm)
|
||||
del_on_death = 1
|
||||
deathmessage = "lets out a contented sigh as their form unwinds."
|
||||
|
||||
@@ -319,10 +319,9 @@
|
||||
return verb
|
||||
|
||||
/mob/living/simple_animal/movement_delay()
|
||||
. = ..()
|
||||
|
||||
. = speed
|
||||
|
||||
if(forced_look)
|
||||
. += 3
|
||||
. += config.animal_delay
|
||||
|
||||
/mob/living/simple_animal/Stat()
|
||||
@@ -615,3 +614,8 @@
|
||||
if(pcollar && collar_type)
|
||||
add_overlay("[collar_type]collar")
|
||||
add_overlay("[collar_type]tag")
|
||||
|
||||
/mob/living/simple_animal/Login()
|
||||
..()
|
||||
walk(src, 0) // if mob is moving under ai control, then stop AI movement
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
return verb
|
||||
|
||||
/mob/living/simple_animal/slime/hear_say(list/message_pieces, verb = "says", italics = 0, mob/speaker = null, sound/speech_sound, sound_vol, sound_frequency)
|
||||
/mob/living/simple_animal/slime/hear_say(list/message_pieces, verb = "says", italics = 0, mob/speaker = null, sound/speech_sound, sound_vol, sound_frequency, use_voice = TRUE)
|
||||
if(speaker != src && !stat)
|
||||
if(speaker in Friends)
|
||||
speech_buffer = list()
|
||||
|
||||
@@ -265,7 +265,7 @@
|
||||
/mob/living/simple_animal/slime/unEquip(obj/item/I, force)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/slime/start_pulling(atom/movable/AM, state, force = move_force, supress_message = FALSE)
|
||||
/mob/living/simple_animal/slime/start_pulling(atom/movable/AM, state, force = pull_force, show_message = FALSE)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/slime/attack_ui(slot)
|
||||
|
||||
@@ -141,18 +141,6 @@
|
||||
if(updating && val_change)
|
||||
update_canmove()
|
||||
|
||||
/mob/living/proc/StartFlying()
|
||||
var/val_change = !flying
|
||||
flying = TRUE
|
||||
if(val_change)
|
||||
update_animations()
|
||||
|
||||
/mob/living/proc/StopFlying()
|
||||
var/val_change = !!flying
|
||||
flying = FALSE
|
||||
if(val_change)
|
||||
update_animations()
|
||||
|
||||
|
||||
// SCALAR STATUS EFFECTS
|
||||
|
||||
|
||||
@@ -20,14 +20,15 @@
|
||||
spawn() alert("You have logged in already with another key this round, please log out of this one NOW or risk being banned!")
|
||||
if(matches)
|
||||
if(M.client)
|
||||
message_admins("<font color='red'><B>Notice: </B><font color='blue'><A href='?src=[usr.UID()];priv_msg=[src.client.UID()]'>[key_name_admin(src)]</A> has the same [matches] as <A href='?src=[usr.UID()];priv_msg=[M.client.UID()]'>[key_name_admin(M)]</A>.</font>", 1)
|
||||
message_admins("<font color='red'><B>Notice: </B><font color='blue'><A href='?src=[usr.UID()];priv_msg=[src.client.ckey]'>[key_name_admin(src)]</A> has the same [matches] as <A href='?src=[usr.UID()];priv_msg=[M.client.ckey]'>[key_name_admin(M)]</A>.</font>", 1)
|
||||
log_adminwarn("Notice: [key_name(src)] has the same [matches] as [key_name(M)].")
|
||||
else
|
||||
message_admins("<font color='red'><B>Notice: </B><font color='blue'><A href='?src=[usr.UID()];priv_msg=[src.client.UID()]'>[key_name_admin(src)]</A> has the same [matches] as [key_name_admin(M)] (no longer logged in). </font>", 1)
|
||||
message_admins("<font color='red'><B>Notice: </B><font color='blue'><A href='?src=[usr.UID()];priv_msg=[src.client.ckey]'>[key_name_admin(src)]</A> has the same [matches] as [key_name_admin(M)] (no longer logged in). </font>", 1)
|
||||
log_adminwarn("Notice: [key_name(src)] has the same [matches] as [key_name(M)] (no longer logged in).")
|
||||
|
||||
/mob/Login()
|
||||
GLOB.player_list |= src
|
||||
last_known_ckey = ckey
|
||||
update_Login_details()
|
||||
world.update_status()
|
||||
|
||||
|
||||
+46
-4
@@ -19,7 +19,6 @@
|
||||
for(var/datum/alternate_appearance/AA in viewing_alternate_appearances)
|
||||
AA.viewers -= src
|
||||
viewing_alternate_appearances = null
|
||||
logs.Cut()
|
||||
LAssailant = null
|
||||
return ..()
|
||||
|
||||
@@ -479,6 +478,41 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \
|
||||
return 0 //Unsupported slot
|
||||
//END HUMAN
|
||||
|
||||
/mob/proc/get_visible_mobs()
|
||||
var/list/seen_mobs = list()
|
||||
for(var/mob/M in view(src))
|
||||
seen_mobs += M
|
||||
|
||||
return seen_mobs
|
||||
|
||||
/**
|
||||
* Returns an assoc list which contains the mobs in range and their "visible" name.
|
||||
* Mobs out of view but in range will be listed as unknown. Else they will have their visible name
|
||||
*/
|
||||
/mob/proc/get_telepathic_targets()
|
||||
var/list/validtargets = new /list()
|
||||
var/turf/T = get_turf(src)
|
||||
var/list/mobs_in_view = get_visible_mobs()
|
||||
|
||||
for(var/mob/living/M in range(14, T))
|
||||
if(M && M.mind)
|
||||
if(M == src)
|
||||
continue
|
||||
var/mob_name
|
||||
if(M in mobs_in_view)
|
||||
mob_name = M.name
|
||||
else
|
||||
mob_name = "Unknown entity"
|
||||
var/i = 0
|
||||
var/result_name
|
||||
do
|
||||
result_name = mob_name
|
||||
if(i++)
|
||||
result_name += " ([i])" // Avoid dupes
|
||||
while(validtargets[result_name])
|
||||
validtargets[result_name] = M
|
||||
return validtargets
|
||||
|
||||
// If you're looking for `reset_perspective`, that's a synonym for this proc.
|
||||
/mob/proc/reset_perspective(atom/A)
|
||||
if(client)
|
||||
@@ -578,6 +612,8 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \
|
||||
changeNext_move(CLICK_CD_POINT)
|
||||
var/obj/P = new /obj/effect/temp_visual/point(tile)
|
||||
P.invisibility = invisibility
|
||||
P.pixel_x = A.pixel_x
|
||||
P.pixel_y = A.pixel_y
|
||||
return 1
|
||||
|
||||
/mob/proc/ret_grab(obj/effect/list_container/mobl/L as obj, flag)
|
||||
@@ -880,6 +916,9 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \
|
||||
return
|
||||
if(!Adjacent(usr))
|
||||
return
|
||||
if(IsFrozen(src) && !is_admin(usr))
|
||||
to_chat(usr, "<span class='boldannounce'>Interacting with admin-frozen players is not permitted.</span>")
|
||||
return
|
||||
if(isLivingSSD(src) && M.client && M.client.send_ssd_warning(src))
|
||||
return
|
||||
show_inv(usr)
|
||||
@@ -1228,10 +1267,13 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \
|
||||
create_log_in_list(debug_log, text, collapse, world.timeofday)
|
||||
|
||||
/mob/proc/create_log(log_type, what, target = null, turf/where = get_turf(src))
|
||||
LAZYINITLIST(logs[log_type])
|
||||
var/list/log_list = logs[log_type]
|
||||
if(!ckey)
|
||||
return
|
||||
var/real_ckey = ckey
|
||||
if(ckey[1] == "@") // Admin aghosting will do this
|
||||
real_ckey = copytext(ckey, 2)
|
||||
var/datum/log_record/record = new(log_type, src, what, target, where, world.time)
|
||||
log_list.Add(record)
|
||||
GLOB.logging.add_log(real_ckey, record)
|
||||
|
||||
/proc/create_log_in_list(list/target, text, collapse = TRUE, last_log)//forgive me code gods for this shitcode proc
|
||||
//this proc enables lovely stuff like an attack log that looks like this: "[18:20:29-18:20:45]21x John Smith attacked Andrew Jackson with a crowbar."
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
var/list/attack_log_old = list( )
|
||||
var/list/debug_log = null
|
||||
|
||||
var/list/logs = list() // Logs for each log type defined in __DEFINES/logs.dm
|
||||
var/last_known_ckey = null // Used in logging
|
||||
|
||||
var/last_log = 0
|
||||
var/obj/machinery/machine = null
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
var/question = "Do you want to play as [M.real_name ? M.real_name : M.name][M.job ? " ([M.job])" : ""]"
|
||||
if(alert("Do you want to show the antag status?","Show antag status","Yes","No") == "Yes")
|
||||
question += ", [M.mind?.special_role ? M.mind?.special_role : "No special role"]"
|
||||
var/list/mob/dead/observer/candidates = pollCandidates("[question]?", poll_time = 100, min_hours = minhours)
|
||||
var/list/mob/dead/observer/candidates = SSghost_spawns.poll_candidates("[question]?", poll_time = 10 SECONDS, min_hours = minhours, source = M)
|
||||
var/mob/dead/observer/theghost = null
|
||||
|
||||
if(LAZYLEN(candidates))
|
||||
@@ -288,7 +288,7 @@
|
||||
S.message = Gibberish(S.message, p)
|
||||
|
||||
|
||||
proc/muffledspeech(phrase)
|
||||
/proc/muffledspeech(phrase)
|
||||
phrase = html_decode(phrase)
|
||||
var/leng=length(phrase)
|
||||
var/counter=length(phrase)
|
||||
@@ -675,4 +675,3 @@ GLOBAL_LIST_INIT(intents, list(INTENT_HELP,INTENT_DISARM,INTENT_GRAB,INTENT_HARM
|
||||
return FALSE //This is the only case someone should actually be completely blocked from antag rolling as well
|
||||
return TRUE
|
||||
|
||||
#define isterrorspider(A) (istype((A), /mob/living/simple_animal/hostile/poison/terror_spider))
|
||||
|
||||
@@ -369,8 +369,9 @@
|
||||
step(pulling, get_dir(pulling.loc, A))
|
||||
return
|
||||
|
||||
/mob/proc/update_gravity()
|
||||
/mob/proc/update_gravity(has_gravity)
|
||||
return
|
||||
|
||||
/client/proc/check_has_body_select()
|
||||
return mob && mob.hud_used && mob.hud_used.zone_select && istype(mob.hud_used.zone_select, /obj/screen/zone_sel)
|
||||
|
||||
|
||||
@@ -77,7 +77,10 @@
|
||||
else output += "<p><a href='byond://?src=[UID()];skip_antag=2'>Global Antag Candidacy</A>"
|
||||
output += "<br /><small>You are <b>[client.skip_antag ? "ineligible" : "eligible"]</b> for all antag roles.</small></p>"
|
||||
|
||||
output += "<p><a href='byond://?src=[UID()];observe=1'>Observe</A></p>"
|
||||
if(!SSticker || SSticker.current_state == GAME_STATE_STARTUP)
|
||||
output += "<p>Observe (Please wait...)</p>"
|
||||
else
|
||||
output += "<p><a href='byond://?src=[UID()];observe=1'>Observe</A></p>"
|
||||
|
||||
if(GLOB.join_tos)
|
||||
output += "<p><a href='byond://?src=[UID()];tos=1'>Terms of Service</A></p>"
|
||||
@@ -103,7 +106,7 @@
|
||||
|
||||
output += "</center>"
|
||||
|
||||
var/datum/browser/popup = new(src, "playersetup", "<div align='center'>New Player Options</div>", 220, 290)
|
||||
var/datum/browser/popup = new(src, "playersetup", "<div align='center'>New Player Options</div>", 240, 330)
|
||||
popup.set_window_options("can_close=0")
|
||||
popup.set_content(output)
|
||||
popup.open(0)
|
||||
@@ -144,7 +147,8 @@
|
||||
|
||||
|
||||
/mob/new_player/Topic(href, href_list[])
|
||||
if(!client) return 0
|
||||
if(!client)
|
||||
return FALSE
|
||||
|
||||
if(href_list["consent_signed"])
|
||||
var/sqltime = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")
|
||||
@@ -162,12 +166,12 @@
|
||||
|
||||
if(href_list["show_preferences"])
|
||||
client.prefs.ShowChoices(src)
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
if(href_list["ready"])
|
||||
if(!tos_consent)
|
||||
to_chat(usr, "<span class='warning'>You must consent to the terms of service before you can join!</span>")
|
||||
return 0
|
||||
return FALSE
|
||||
ready = !ready
|
||||
new_player_panel_proc()
|
||||
|
||||
@@ -182,7 +186,11 @@
|
||||
if(href_list["observe"])
|
||||
if(!tos_consent)
|
||||
to_chat(usr, "<span class='warning'>You must consent to the terms of service before you can join!</span>")
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if(!SSticker || SSticker.current_state == GAME_STATE_STARTUP)
|
||||
to_chat(usr, "<span class='warning'>You must wait for the server to finish starting before you can join!</span>")
|
||||
return FALSE
|
||||
|
||||
if(alert(src,"Are you sure you wish to observe? You cannot normally join the round after doing this!","Player Setup","Yes","No") == "Yes")
|
||||
if(!client)
|
||||
@@ -216,12 +224,12 @@
|
||||
return 1
|
||||
if(href_list["tos"])
|
||||
privacy_consent()
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if(href_list["late_join"])
|
||||
if(!tos_consent)
|
||||
to_chat(usr, "<span class='warning'>You must consent to the terms of service before you can join!</span>")
|
||||
return 0
|
||||
return FALSE
|
||||
if(!SSticker || SSticker.current_state != GAME_STATE_PLAYING)
|
||||
to_chat(usr, "<span class='warning'>The round is either not ready, or has already finished...</span>")
|
||||
return
|
||||
@@ -229,7 +237,7 @@
|
||||
|
||||
if(!is_alien_whitelisted(src, client.prefs.species) && config.usealienwhitelist)
|
||||
to_chat(src, alert("You are currently not whitelisted to play [client.prefs.species]."))
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
LateChoices()
|
||||
|
||||
@@ -248,7 +256,7 @@
|
||||
if(client.prefs.species in GLOB.whitelisted_species)
|
||||
if(!is_alien_whitelisted(src, client.prefs.species) && config.usealienwhitelist)
|
||||
to_chat(src, alert("You are currently not whitelisted to play [client.prefs.species]."))
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
AttemptLateSpawn(href_list["SelectedJob"],client.prefs.spawnpoint)
|
||||
return
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
if(adminonly)
|
||||
question = "(<font color='#997700'>Admin only poll</font>) " + question
|
||||
|
||||
var output = "<!DOCTYPE html><html><body>"
|
||||
var/output = "<!DOCTYPE html><html><body>"
|
||||
if(polltype == POLLTYPE_MULTI || polltype == POLLTYPE_OPTION)
|
||||
select_query = GLOB.dbcon.NewQuery("SELECT text, percentagecalc, (SELECT COUNT(optionid) FROM [format_table_name("poll_vote")] WHERE optionid = poll_option.id GROUP BY optionid) AS votecount FROM [format_table_name("poll_option")] WHERE pollid = [pollid]")
|
||||
select_query.Execute()
|
||||
|
||||
@@ -513,16 +513,16 @@
|
||||
if(4)
|
||||
clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
|
||||
if(JOB_MINER)
|
||||
clothes_s = new /icon(uniform_dmi, "miner_s")
|
||||
clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
|
||||
clothes_s = new /icon(uniform_dmi, "explorer_s")
|
||||
clothes_s.Blend(new /icon('icons/mob/feet.dmi', "explorer"), ICON_UNDERLAY)
|
||||
clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY)
|
||||
if(prob(1))
|
||||
clothes_s.Blend(new /icon('icons/mob/head.dmi', "bearpelt"), ICON_OVERLAY)
|
||||
switch(backbag)
|
||||
if(2)
|
||||
clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
|
||||
clothes_s.Blend(new /icon('icons/mob/back.dmi', "explorerpack"), ICON_OVERLAY)
|
||||
if(3)
|
||||
clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-eng"), ICON_OVERLAY)
|
||||
clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-explorer"), ICON_OVERLAY)
|
||||
if(4)
|
||||
clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
|
||||
if(JOB_LAWYER)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user