Merge remote-tracking branch 'ParadiseSS13/master' into skills_rework

This commit is contained in:
Kyep
2020-09-19 06:39:38 -07:00
534 changed files with 9837 additions and 16102 deletions
+1 -1
View File
@@ -780,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)
@@ -592,7 +592,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 +600,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")
+7 -11
View File
@@ -29,8 +29,6 @@
create_reagents(330)
martial_art = GLOB.default_martial_art
handcrafting = new()
// Set up DNA.
@@ -298,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>")
@@ -1731,16 +1729,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)
@@ -13,13 +13,20 @@ 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
visible_message("<span class='danger'>The [P.name] gets reflected by [src]!</span>", \
"<span class='userdanger'>The [P.name] gets reflected by [src]!</span>")
var/can_reflect = check_reflect(def_zone)
if(!can_reflect)
return (..(P , def_zone)) //Bad luck
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 not safe
return (..(P , def_zone)) //Bad luck
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)
P.reflect_back(src)
return -1 // complete projectile permutation
return -1 // complete projectile permutation
//Shields
if(check_shields(P, P.damage, "the [P.name]", PROJECTILE_ATTACK, P.armour_penetration))
@@ -172,10 +179,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 +214,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
@@ -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
+9 -10
View File
@@ -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)
@@ -698,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)
@@ -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,7 +516,7 @@
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
@@ -528,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>")
+88 -86
View File
@@ -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()
+2
View File
@@ -927,6 +927,8 @@
. += T.slowdown
if(slowed)
. += 10
if(forced_look)
. += 3
if(ignorewalk)
. += config.run_speed
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
+1 -1
View File
@@ -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)
@@ -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"
@@ -35,7 +35,6 @@
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,
@@ -127,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)
@@ -208,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
@@ -361,12 +365,7 @@
/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)
+23 -10
View File
@@ -83,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
@@ -752,6 +753,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>")
@@ -768,7 +770,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>")
@@ -964,16 +966,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)
@@ -1403,6 +1413,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
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, connect_to_AI = TRUE, mob/living/silicon/ai/ai_to_sync_to = null)
@@ -1431,6 +1442,7 @@ 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"
@@ -1487,6 +1499,7 @@ 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.
can_lock_cover = TRUE
default_cell_type = /obj/item/stock_parts/cell/bluespace
/mob/living/silicon/robot/destroyer/init(alien = FALSE, connect_to_AI = TRUE, mob/living/silicon/ai/ai_to_sync_to = null)
@@ -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. \
@@ -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")
@@ -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
@@ -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)]"
@@ -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
@@ -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)
@@ -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_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_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
@@ -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(stat != DEAD) // Can't use if(.) for this due to the fact it can sometimes return FALSE even when mob is alive.
if(ckey && canlay < 12 && hasnested) // max 12 eggs worth stored at any one time, realistically that's tons.
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,27 +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()
@@ -315,46 +336,33 @@
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/New()
. = ..()
air_update_turf(TRUE)
/obj/structure/spider/terrorweb/queen/CanAtmosPass(turf/T)
return FALSE
/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)
@@ -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)
@@ -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,54 @@ 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/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>")
@@ -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()
+35
View File
@@ -478,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)
+1 -2
View File
@@ -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))
+6 -16
View File
@@ -38,8 +38,7 @@
O.rename_self("AI",1)
spawn()
qdel(src)
INVOKE_ASYNC(GLOBAL_PROC, .proc/qdel, src) // To prevent the proc from returning null.
return O
@@ -102,8 +101,7 @@
O.Namepick()
spawn(0)//To prevent the proc from returning null.
qdel(src)
INVOKE_ASYNC(GLOBAL_PROC, .proc/qdel, src) // To prevent the proc from returning null.
return O
//human -> alien
@@ -135,9 +133,7 @@
to_chat(new_xeno, "<B>You are now an alien.</B>")
new_xeno.update_pipe_vision()
spawn(0)//To prevent the proc from returning null.
qdel(src)
return
qdel(src)
/mob/living/carbon/human/proc/slimeize(reproduce as num)
if(notransform)
@@ -190,9 +186,7 @@
to_chat(new_corgi, "<B>You are now a Corgi. Yap Yap!</B>")
new_corgi.update_pipe_vision()
spawn(0)//To prevent the proc from returning null.
qdel(src)
return
qdel(src)
/mob/living/carbon/human/Animalize()
@@ -221,9 +215,7 @@
to_chat(new_mob, "You suddenly feel more... animalistic.")
new_mob.update_pipe_vision()
spawn()
qdel(src)
return
qdel(src)
/mob/proc/Animalize()
@@ -264,9 +256,7 @@
to_chat(pai, "<B>You have become a pAI! Your name is [pai.name].</B>")
pai.update_pipe_vision()
spawn(0)//To prevent the proc from returning null.
qdel(src)
return
qdel(src)
/mob/proc/safe_respawn(var/MP)
if(!MP)