Merge branch 'master' into robotic_arms_bots

This commit is contained in:
Nicaragua
2019-02-19 19:30:08 -03:00
committed by GitHub
612 changed files with 11854 additions and 6627 deletions
+12 -10
View File
@@ -70,7 +70,7 @@
sound_vol *= 0.5
if(sleeping || stat == UNCONSCIOUS)
hear_sleep(message_pieces)
hear_sleep(multilingual_to_message(message_pieces))
return 0
var/speaker_name = speaker.name
@@ -97,7 +97,7 @@
if(!can_hear())
// INNATE is the flag for audible-emote-language, so we don't want to show an "x talks but you cannot hear them" message if it's set
// if(!language || !(language.flags & INNATE))
// if(!language || !(language.flags & INNATE))
if(speaker == src)
to_chat(src, "<span class='warning'>You cannot hear yourself speak!</span>")
else
@@ -158,14 +158,16 @@
message = strip_html_properly(message)
var/list/punctuation = list(",", "!", ".", ";", "?")
var/list/messages = splittext(message, " ")
var/R = rand(1, messages.len)
var/heardword = messages[R]
if(copytext(heardword,1, 1) in punctuation)
heardword = copytext(heardword,2)
if(copytext(heardword,-1) in punctuation)
heardword = copytext(heardword,1,lentext(heardword))
heard = "<span class='game say'>...<i>You hear something about<i>... '[heardword]'...</span>"
if(messages.len > 0)
var/R = rand(1, messages.len)
var/heardword = messages[R]
if(copytext(heardword,1, 1) in punctuation)
heardword = copytext(heardword,2)
if(copytext(heardword,-1) in punctuation)
heardword = copytext(heardword,1,lentext(heardword))
heard = "<span class='game say'>...<i>You hear something about<i>... '[heardword]'...</span>"
else
heard = "<span class='game say'>...<i>You almost hear something...</i>...</span>"
else
heard = "<span class='game say'>...<i>You almost hear someone talking</i>...</span>"
+7
View File
@@ -529,6 +529,13 @@
return TRUE
return FALSE
/datum/language/abductor/golem
name = "Golem Mindlink"
desc = "Communicate with other alien alloy golems through a psychic link."
/datum/language/abductor/golem/check_special_condition(mob/living/carbon/human/other, mob/living/carbon/human/speaker)
return TRUE
/datum/language/corticalborer
name = "Cortical Link"
desc = "Cortical borers possess a strange link between their tiny minds."
@@ -19,6 +19,10 @@
var/obj/item/radio/radio = null // For use with the radio MMI upgrade
var/datum/action/generic/configure_mmi_radio/radio_action = null
// Used for cases when mmi or one of it's children commits suicide.
// Needed to fix a rather insane bug when a posibrain/robotic brain commits suicide
var/dead_icon = "mmi_dead"
/obj/item/mmi/attackby(var/obj/item/O as obj, var/mob/user as mob, params)
if(istype(O, /obj/item/organ/internal/brain/crystal ))
to_chat(user, "<span class='warning'> This brain is too malformed to be able to use with the [src].</span>")
@@ -4,8 +4,9 @@
if(!.)
return FALSE
if(!gibbed && container && istype(container, /obj/item/mmi))//If not gibbed but in a container.
var/obj/item/mmi/mmi = container
visible_message("<span class='danger'>[src]'s MMI flatlines!</span>", "<span class='warning'>You hear something flatline.</span>")
container.icon_state = "mmi_dead"
mmi.icon_state = mmi.dead_icon
/mob/living/carbon/brain/gib()
// can we muster a parent call here?
@@ -21,6 +21,8 @@
var/mob/living/carbon/human/imprinted_master = null
var/ejected_flavor_text = "circuit"
dead_icon = "boris_blank"
/obj/item/mmi/robotic_brain/Destroy()
imprinted_master = null
return ..()
@@ -228,4 +230,5 @@
desc = "A cube of shining metal, four inches to a side and covered in shallow grooves."
silenced = TRUE
requires_master = FALSE
ejected_flavor_text = "metal cube"
ejected_flavor_text = "metal cube"
dead_icon = "posibrain"
+2
View File
@@ -451,6 +451,8 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump,
continue
if(istype(I, /obj/item/organ))
continue
if(I.flags & ABSTRACT)
continue
else
failed++
@@ -172,7 +172,7 @@
var/M = handle_emote_param(param)
message = "<B>[src]</B> [M ? "drones at [M]" : "rumbles"]."
playsound(loc, 'sound/voice/DraskTalk.ogg', 50, 0)
playsound(loc, 'sound/voice/drasktalk.ogg', 50, 0)
m_type = 2
if("squish", "squishes")
@@ -1992,3 +1992,12 @@ Eyes need to have significantly high darksight to shine unless the mob has the X
dna.SetSEState(block, FALSE, TRUE)
genemutcheck(src, block, null, MUTCHK_FORCED)
dna.UpdateSE()
/mob/living/carbon/human/extinguish_light()
// Parent function handles stuff the human may be holding
..()
var/obj/item/organ/internal/lantern/O = get_int_organ(/obj/item/organ/internal/lantern)
if(O && O.glowing)
O.toggle_biolum(TRUE)
visible_message("<span class='danger'>[src] is engulfed in shadows and fades into the darkness.</span>", "<span class='danger'>A sense of dread washes over you as you suddenly dim dark.</span>")
@@ -10,7 +10,8 @@ emp_act
/mob/living/carbon/human/bullet_act(obj/item/projectile/P, def_zone)
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>", \
@@ -295,6 +296,8 @@ emp_act
if(Iforce > 10 || Iforce >= 5 && prob(33))
forcesay(GLOB.hit_appends) //forcesay checks stat already
dna.species.spec_attacked_by(I, user, affecting, user.a_intent, src)
//this proc handles being hit by a thrown atom
/mob/living/carbon/human/hitby(atom/movable/AM, skipcatch = 0, hitpush = 1, blocked = 0)
var/obj/item/I
@@ -321,6 +324,8 @@ emp_act
visible_message("<span class='danger'>[I] embeds itself in [src]'s [L.name]!</span>","<span class='userdanger'>[I] embeds itself in your [L.name]!</span>")
hitpush = 0
skipcatch = 1 //can't catch the now embedded item
if(!blocked)
dna.species.spec_hitby(AM, src)
return ..()
/mob/living/carbon/human/proc/bloody_hands(var/mob/living/source, var/amount = 2)
@@ -473,7 +478,7 @@ emp_act
playsound(src, 'sound/weapons/punch4.ogg', 50, 1)
if("fire")
update |= affecting.receive_damage(0, rand(M.force/2, M.force))
playsound(src, 'sound/items/Welder.ogg', 50, 1)
playsound(src, 'sound/items/welder.ogg', 50, 1)
if("tox")
M.mech_toxin_damage(src)
else
+5 -1
View File
@@ -91,6 +91,9 @@
var/obj/item/organ/internal/L = get_organ_slot("lungs")
if((breathes && !L) || breathes && L && (L.status & ORGAN_DEAD))
return FALSE
if(oxyloss > 10 || losebreath >= 4)
emote("gasp")
return FALSE
if(mind)
return !mind.miming
return TRUE
@@ -121,7 +124,8 @@
span = mind.speech_span
if((COMIC in mutations) \
|| (locate(/obj/item/organ/internal/cyberimp/brain/clown_voice) in internal_organs) \
|| istype(get_item_by_slot(slot_wear_mask), /obj/item/clothing/mask/gas/voice/clown))
|| istype(get_item_by_slot(slot_wear_mask), /obj/item/clothing/mask/gas/voice/clown) \
|| GetComponent(/datum/component/jestosterone))
span = "sans"
if(WINGDINGS in mutations)
@@ -360,6 +360,10 @@
var/datum/unarmed_attack/attack = user.dna.species.unarmed
user.do_attack_animation(target, attack.animation_type)
if(attack.harmless)
playsound(target.loc, attack.attack_sound, 25, 1, -1)
target.visible_message("<span class='danger'>[user] [pick(attack.attack_verb)]ed [target]!</span>")
return FALSE
add_attack_logs(user, target, "Melee attacked with fists", target.ckey ? null : ATKLOG_ALL)
if(!iscarbon(user))
@@ -381,7 +385,6 @@
playsound(target.loc, attack.attack_sound, 25, 1, -1)
target.visible_message("<span class='danger'>[user] [pick(attack.attack_verb)]ed [target]!</span>")
target.apply_damage(damage, BRUTE, affecting, armor_block, sharp = attack.sharp) //moving this back here means Armalis are going to knock you down 70% of the time, but they're pure adminbus anyway.
if((target.stat != DEAD) && damage >= user.dna.species.punchstunthreshold)
target.visible_message("<span class='danger'>[user] has weakened [target]!</span>", \
@@ -390,6 +393,7 @@
target.forcesay(GLOB.hit_appends)
else if(target.lying)
target.forcesay(GLOB.hit_appends)
SEND_SIGNAL(target, COMSIG_PARENT_ATTACKBY)
/datum/species/proc/disarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
if(target.check_block()) //cqc
@@ -509,6 +513,7 @@
var/miss_sound = 'sound/weapons/punchmiss.ogg'
var/sharp = FALSE
var/animation_type = ATTACK_EFFECT_PUNCH
var/harmless = FALSE //if set to true, attacks won't be admin logged and punches will "hit" for no damage
/datum/unarmed_attack/diona
attack_verb = list("lash", "bludgeon")
@@ -709,8 +714,6 @@ It'll return null if the organ doesn't correspond, so include null checks when u
if(XRAY in H.mutations)
H.sight |= (SEE_TURFS|SEE_MOBS|SEE_OBJS)
H.see_in_dark = max(H.see_in_dark, 8)
H.see_invisible = SEE_INVISIBLE_MINIMUM
if(H.see_override) //Override all
H.see_invisible = H.see_override
@@ -719,6 +722,13 @@ It'll return null if the organ doesn't correspond, so include null checks when u
if(abs(temperature - M.bodytemperature) > 10) //If our water and mob temperature varies by more than 10K, cool or/ heat them appropriately
M.bodytemperature = (temperature + M.bodytemperature) * 0.5 //Approximation for gradual heating or cooling
/datum/species/proc/bullet_act(obj/item/projectile/P, mob/living/carbon/human/H) //return TRUE if hit, FALSE if stopped/reflected/etc
return TRUE
/datum/species/proc/spec_hitby(atom/movable/AM, mob/living/carbon/human/H)
/datum/species/proc/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H)
/proc/get_random_species(species_name = FALSE) // Returns a random non black-listed or hazardous species, either as a string or datum
var/static/list/random_species = list()
if(!random_species.len)
@@ -10,7 +10,7 @@
"heart" = /obj/item/organ/internal/heart,
"liver" = /obj/item/organ/internal/liver,
"kidneys" = /obj/item/organ/internal/kidneys,
"brain" = /obj/item/organ/internal/brain,
"brain" = /obj/item/organ/internal/brain/abductor,
"appendix" = /obj/item/organ/internal/appendix,
"eyes" = /obj/item/organ/internal/eyes/abductor //3 darksight.
)
@@ -6,14 +6,14 @@
language = "Orluum"
eyes = "drask_eyes_s"
speech_sounds = list('sound/voice/DraskTalk.ogg')
speech_sounds = list('sound/voice/drasktalk.ogg')
speech_chance = 20
male_scream_sound = 'sound/voice/DraskTalk2.ogg'
female_scream_sound = 'sound/voice/DraskTalk2.ogg'
male_cough_sounds = 'sound/voice/DraskCough.ogg'
female_cough_sounds = 'sound/voice/DraskCough.ogg'
male_sneeze_sound = 'sound/voice/DraskSneeze.ogg'
female_sneeze_sound = 'sound/voice/DraskSneeze.ogg'
male_scream_sound = 'sound/voice/drasktalk2.ogg'
female_scream_sound = 'sound/voice/drasktalk2.ogg'
male_cough_sounds = 'sound/voice/draskcough.ogg'
female_cough_sounds = 'sound/voice/draskcough.ogg'
male_sneeze_sound = 'sound/voice/drasksneeze.ogg'
female_sneeze_sound = 'sound/voice/drasksneeze.ogg'
burn_mod = 2
//exotic_blood = "cryoxadone"
@@ -5,8 +5,10 @@
icobase = 'icons/mob/human_races/r_golem.dmi'
deform = 'icons/mob/human_races/r_golem.dmi'
species_traits = list(NO_BREATHE, NO_BLOOD, RADIMMUNE, VIRUSIMMUNE, NOGUNS)
species_traits = list(NO_BREATHE, NO_BLOOD, NO_PAIN, RADIMMUNE, VIRUSIMMUNE, NOGUNS)
brute_mod = 0.45 //55% damage reduction
burn_mod = 0.45
tox_mod = 0.45
oxy_mod = 0
dietflags = DIET_OMNI //golems can eat anything because they are magic or something
@@ -31,35 +33,654 @@
blood_color = "#515573"
flesh_color = "#137E8F"
skinned_type = /obj/item/stack/sheet/metal
slowdown = 3
siemens_coeff = 0
blacklisted = TRUE // To prevent golem subtypes from overwhelming the odds when random species changes, only the Random Golem type can be chosen
dangerous_existence = TRUE
has_organ = list(
"brain" = /obj/item/organ/internal/brain/golem
"brain" = /obj/item/organ/internal/brain/golem,
"adamantine_resonator" = /obj/item/organ/internal/adamantine_resonator
) //Has standard darksight of 2.
suicide_messages = list(
"is crumbling into dust!",
"is smashing their body apart!")
var/golem_colour = rgb(170, 170, 170)
var/info_text = "As an <span class='danger'>Iron Golem</span>, you don't have any special traits."
var/random_eligible = TRUE
var/prefix = "Iron"
var/list/special_names = list("Tarkus")
var/human_surname_chance = 3
var/special_name_chance = 5
var/owner //dobby is a free golem
/datum/species/golem/get_random_name()
var/golem_surname = pick(GLOB.golem_names)
// 3% chance that our golem has a human surname, because cultural contamination
if(prob(human_surname_chance))
golem_surname = pick(GLOB.last_names)
else if(special_names && special_names.len && prob(special_name_chance))
golem_surname = pick(special_names)
var/golem_name = "[prefix] [golem_surname]"
return golem_name
/datum/species/golem/on_species_gain(mob/living/carbon/human/H)
..()
if(H.mind)
H.mind.assigned_role = "Golem"
H.mind.special_role = SPECIAL_ROLE_GOLEM
H.real_name = "adamantine golem ([rand(1, 1000)])"
if(owner)
H.mind.special_role = SPECIAL_ROLE_GOLEM
else
H.mind.special_role = SPECIAL_ROLE_FREE_GOLEM
H.real_name = get_random_name()
H.name = H.real_name
H.equip_to_slot_or_del(new /obj/item/clothing/under/golem(H), slot_w_uniform)
H.equip_to_slot_or_del(new /obj/item/clothing/suit/golem(H), slot_wear_suit)
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/golem(H), slot_shoes)
H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/golem(H), slot_wear_mask)
H.equip_to_slot_or_del(new /obj/item/clothing/gloves/golem(H), slot_gloves)
H.regenerate_icons()
to_chat(H, info_text)
//Random Golem
////////Adamantine Golem stuff I dunno where else to put it
/datum/species/golem/random
name = "Random Golem"
blacklisted = FALSE
dangerous_existence = FALSE
var/static/list/random_golem_types
/datum/species/golem/random/on_species_gain(mob/living/carbon/C, datum/species/old_species)
..()
if(!random_golem_types)
random_golem_types = subtypesof(/datum/species/golem) - type
for(var/V in random_golem_types)
var/datum/species/golem/G = V
if(!initial(G.random_eligible))
random_golem_types -= G
var/datum/species/golem/golem_type = pick(random_golem_types)
var/mob/living/carbon/human/H = C
H.set_species(golem_type)
//Golem subtypes
//Leader golems, can resonate to communicate with all other golems
/datum/species/golem/adamantine
name = "Adamantine Golem"
skinned_type = /obj/item/stack/sheet/mineral/adamantine
has_organ = list(
"brain" = /obj/item/organ/internal/brain/golem,
"adamantine_resonator" = /obj/item/organ/internal/adamantine_resonator,
"vocal_cords" = /obj/item/organ/internal/vocal_cords/adamantine
)
golem_colour = rgb(68, 238, 221)
info_text = "As an <span class='danger'>Adamantine Golem</span>, you possess special vocal cords allowing you to \"resonate\" messages to all golems."
prefix = "Adamantine"
special_names = null
//The suicide bombers of golemkind
/datum/species/golem/plasma
name = "Plasma Golem"
skinned_type = /obj/item/stack/ore/plasma
golem_colour = rgb(170, 51, 221)
heat_level_1 = 360
heat_level_2 = 400
heat_level_3 = 460
info_text = "As a <span class='danger'>Plasma Golem</span>, you burn easily. Be careful, if you get hot enough while burning, you'll blow up!"
heatmod = 0 //fine until they blow up
prefix = "Plasma"
special_names = list("Flood", "Fire", "Bar", "Man")
var/boom_warning = FALSE
var/datum/action/innate/ignite/ignite
/datum/species/golem/plasma/handle_life(mob/living/carbon/human/H)
if(H.bodytemperature > 750)
if(!boom_warning && H.on_fire)
to_chat(H, "<span class='userdanger'>You feel like you could blow up at any moment!</span>")
boom_warning = TRUE
else
if(boom_warning)
to_chat(H, "<span class='notice'>You feel more stable.</span>")
boom_warning = FALSE
if(H.bodytemperature > 850 && H.on_fire && prob(25))
explosion(get_turf(H), 1, 2, 4, flame_range = 5)
if(H)
H.gib()
if(H.fire_stacks < 2) //flammable
H.adjust_fire_stacks(1)
..()
/datum/species/golem/plasma/on_species_gain(mob/living/carbon/C, datum/species/old_species)
..()
if(ishuman(C))
ignite = new
ignite.Grant(C)
/datum/species/golem/plasma/on_species_loss(mob/living/carbon/C)
if(ignite)
ignite.Remove(C)
..()
/datum/action/innate/ignite
name = "Ignite"
desc = "Set yourself aflame, bringing yourself closer to exploding!"
check_flags = AB_CHECK_CONSCIOUS
button_icon_state = "sacredflame"
/datum/action/innate/ignite/Activate()
if(ishuman(owner))
var/mob/living/carbon/human/H = owner
if(H.fire_stacks)
to_chat(owner, "<span class='notice'>You ignite yourself!</span>")
else
to_chat(owner, "<span class='warning'>You try to ignite yourself, but fail!</span>")
H.IgniteMob() //firestacks are already there passively
//Harder to hurt
/datum/species/golem/diamond
name = "Diamond Golem"
golem_colour = rgb(0, 255, 255)
brute_mod = 0.3 //70% damage reduction up from 55%
burn_mod = 0.3
tox_mod = 0.3
skinned_type = /obj/item/stack/ore/diamond
info_text = "As a <span class='danger'>Diamond Golem</span>, you are more resistant than the average golem."
prefix = "Diamond"
special_names = list("Back")
//Faster but softer and less armoured
/datum/species/golem/gold
name = "Gold Golem"
golem_colour = rgb(204, 204, 0)
slowdown = 2
brute_mod = 0.75 //25% damage reduction down from 55%
burn_mod = 0.75
tox_mod = 0.75
skinned_type = /obj/item/stack/ore/gold
info_text = "As a <span class='danger'>Gold Golem</span>, you are faster but less resistant than the average golem."
prefix = "Golden"
special_names = list("Boy")
//Heavier, thus higher chance of stunning when punching
/datum/species/golem/silver
name = "Silver Golem"
golem_colour = rgb(221, 221, 221)
punchstunthreshold = 9 //60% chance, from 40%
skinned_type = /obj/item/stack/ore/silver
info_text = "As a <span class='danger'>Silver Golem</span>, your attacks have a higher chance of stunning."
prefix = "Silver"
special_names = list("Surfer", "Chariot", "Lining")
//Harder to stun, deals more damage, but it's even slower
/datum/species/golem/plasteel
name = "Plasteel Golem"
golem_colour = rgb(187, 187, 187)
stun_mod = 0.4
punchdamagelow = 12
punchdamagehigh = 21
punchstunthreshold = 18 //still 40% stun chance
slowdown = 5 //diona speed
skinned_type = /obj/item/stack/ore/iron
info_text = "As a <span class='danger'>Plasteel Golem</span>, you are slower, but harder to stun, and hit very hard when punching."
prefix = "Plasteel"
special_names = null
unarmed_type = /datum/unarmed_attack/golem/plasteel
/datum/unarmed_attack/golem/plasteel
attack_verb = list("smash")
attack_sound = 'sound/effects/meteorimpact.ogg'
//More resistant to burn damage
//Add ashstorm resistance if we ever port lavaland
/datum/species/golem/titanium
name = "Titanium Golem"
golem_colour = rgb(255, 255, 255)
skinned_type = /obj/item/stack/ore/titanium
info_text = "As a <span class='danger'>Titanium Golem</span>, you are resistant to burn damage."
burn_mod = 0.3
prefix = "Titanium"
special_names = list("Dioxide")
//Even more resistant to burn damage
//Add ashstorm and lava resistance if we ever port lavaland
/datum/species/golem/plastitanium
name = "Plastitanium Golem"
golem_colour = rgb(136, 136, 136)
skinned_type = /obj/item/stack/ore/titanium
info_text = "As a <span class='danger'>Plastitanium Golem</span>, you are very resistant to burn damage."
burn_mod = 0.15
prefix = "Plastitanium"
special_names = null
//Fast and regenerates... but can only speak like an abductor
/datum/species/golem/alloy
name = "Alien Alloy Golem"
golem_colour = rgb(51, 51, 51)
skinned_type = /obj/item/stack/sheet/mineral/abductor
language = "Golem Mindlink"
default_language = "Golem Mindlink"
slowdown = 2 //faster
info_text = "As an <span class='danger'>Alloy Golem</span>, you are made of advanced alien materials: you are faster and regenerate over time. You are, however, only able to speak telepathically to other alloy golems."
prefix = "Alien"
special_names = list("Outsider", "Technology", "Watcher", "Stranger") //ominous and unknown
//Regenerates because self-repairing super-advanced alien tech
/datum/species/golem/alloy/handle_life(mob/living/carbon/human/H)
if(H.stat == DEAD)
return
H.adjustBruteLoss(-2)
H.adjustFireLoss(-2)
H.adjustToxLoss(-2)
H.adjustOxyLoss(-2)
/datum/species/golem/alloy/can_understand(mob/other) //Can understand everyone, but they can only speak over their mindlink
return TRUE
/datum/species/golem/alloy/on_species_gain(mob/living/carbon/human/H)
..()
H.languages.Cut()
H.add_language("Golem Mindlink")
//Regenerates like dionas, less resistant
/datum/species/golem/wood
name = "Wood Golem"
golem_colour = rgb(158, 112, 75)
skinned_type = /obj/item/stack/sheet/wood
species_traits = list(NO_BREATHE, NO_BLOOD, NO_PAIN, RADIMMUNE, VIRUSIMMUNE, NOGUNS, IS_PLANT)
//Can burn and take damage from heat
brute_mod = 0.7 //30% damage reduction down from 55%
burn_mod = 1
heatmod = 1.5
heat_level_1 = 300
heat_level_2 = 340
heat_level_3 = 400
dietflags = 0 //Regenerate nutrition in light, no diet necessary
taste_sensitivity = TASTE_SENSITIVITY_NO_TASTE
info_text = "As a <span class='danger'>Wooden Golem</span>, you have plant-like traits: you take damage from extreme temperatures, can be set on fire, and have lower armor than a normal golem. You regenerate when in the light and wither in the darkness."
prefix = "Wooden"
special_names = list("Bark", "Willow", "Catalpa", "Oak", "Sap", "Twig", "Branch", "Maple", "Birch", "Elm", "Basswood", "Cottonwood", "Larch", "Aspen", "Ash", "Beech", "Buckeye", "Cedar", "Chestnut", "Cypress", "Fir", "Hawthorn", "Hazel", "Hickory", "Ironwood", "Juniper", "Leaf", "Mangrove", "Palm", "Pawpaw", "Pine", "Poplar", "Redwood", "Redbud", "Sassafras", "Spruce", "Sumac", "Trunk", "Walnut", "Yew")
human_surname_chance = 0
special_name_chance = 100
/datum/species/golem/wood/handle_life(mob/living/carbon/human/H)
var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing
if(isturf(H.loc)) //else, there's considered to be no light
var/turf/T = H.loc
light_amount = min(T.get_lumcount() * 10, 5) //hardcapped so it's not abused by having a ton of flashlights
H.nutrition = min(H.nutrition+light_amount, NUTRITION_LEVEL_WELL_FED+10)
if(light_amount > 0)
H.clear_alert("nolight")
else
H.throw_alert("nolight", /obj/screen/alert/nolight)
if((light_amount >= 5) && !H.suiciding) //if there's enough light, heal
H.adjustBruteLoss(-(light_amount/2))
H.adjustFireLoss(-(light_amount/4))
if(H.nutrition < NUTRITION_LEVEL_STARVING+50)
H.take_overall_damage(10,0)
..()
//Radioactive
/datum/species/golem/uranium
name = "Uranium Golem"
golem_colour = rgb(119, 255, 0)
skinned_type = /obj/item/stack/ore/uranium
info_text = "As an <span class='danger'>Uranium Golem</span>, you emit radiation. It won't harm fellow golems, but organic lifeforms will be affected."
prefix = "Uranium"
special_names = list("Oxide", "Rod", "Meltdown")
/datum/species/golem/uranium/handle_life(mob/living/carbon/human/H)
for(var/mob/living/L in range(2, H))
if(isgolem(H))
continue
to_chat(L, "<span class='danger'>You are enveloped by a soft green glow emanating from [H].</span>")
L.apply_effect(10, IRRADIATE)
..()
//Ventcrawler
/datum/species/golem/plastic
name = "Plastic Golem"
prefix = "Plastic"
special_names = null
golem_colour = rgb(255, 255, 255)
skinned_type = /obj/item/stack/sheet/plastic
info_text = "As a <span class='danger'>Plastic Golem</span>, you are capable of ventcrawling if you're naked."
/datum/species/golem/plastic/on_species_gain(mob/living/carbon/C, datum/species/old_species)
. = ..()
C.ventcrawler = 1
/datum/species/golem/plastic/on_species_loss(mob/living/carbon/C)
. = ..()
C.ventcrawler = initial(C.ventcrawler)
//Immune to physical bullets and resistant to brute, but very vulnerable to burn damage. Dusts on death.
/datum/species/golem/sand
name = "Sand Golem"
golem_colour = rgb(255, 220, 143)
skinned_type = /obj/item/stack/ore/glass //this is sand
brute_mod = 0.25
burn_mod = 3
info_text = "As a <span class='danger'>Sand Golem</span>, you are immune to physical bullets and take very little brute damage, but are extremely vulnerable to burn damage and energy weapons. You will also turn to sand when dying, preventing any form of recovery."
unarmed_type = /datum/unarmed_attack/golem/sand
prefix = "Sand"
special_names = list("Castle", "Bag", "Dune", "Worm", "Storm")
/datum/species/golem/sand/handle_death(mob/living/carbon/human/H)
H.visible_message("<span class='danger'>[H] turns into a pile of sand!</span>")
for(var/obj/item/W in H)
H.unEquip(W)
for(var/i=1, i <= rand(3, 5), i++)
new /obj/item/stack/ore/glass(get_turf(H))
qdel(H)
/datum/species/golem/sand/bullet_act(obj/item/projectile/P, mob/living/carbon/human/H)
if(!(P.original == H && P.firer == H))
if(P.flag == "bullet" || P.flag == "bomb")
playsound(H, 'sound/effects/shovel_dig.ogg', 70, 1)
H.visible_message("<span class='danger'>The [P.name] sinks harmlessly in [H]'s sandy body!</span>", \
"<span class='userdanger'>The [P.name] sinks harmlessly in [H]'s sandy body!</span>")
return FALSE
return TRUE
/datum/unarmed_attack/golem/sand
attack_sound = 'sound/effects/shovel_dig.ogg'
//Reflects lasers and resistant to burn damage, but very vulnerable to brute damage. Shatters on death.
/datum/species/golem/glass
name = "Glass Golem"
golem_colour = rgb(90, 150, 180)
skinned_type = /obj/item/shard
brute_mod = 3 //very fragile
burn_mod = 0.25
info_text = "As a <span class='danger'>Glass Golem</span>, you reflect lasers and energy weapons, and are very resistant to burn damage. However, you are extremely vulnerable to brute damage. On death, you'll shatter beyond any hope of recovery."
unarmed_type = /datum/unarmed_attack/golem/glass
prefix = "Glass"
special_names = list("Lens", "Prism", "Fiber", "Bead")
/datum/species/golem/glass/handle_death(mob/living/carbon/human/H)
playsound(H, "shatter", 70, 1)
H.visible_message("<span class='danger'>[H] shatters!</span>")
for(var/obj/item/W in H)
H.unEquip(W)
for(var/i=1, i <= rand(3, 5), i++)
new /obj/item/shard(get_turf(H))
qdel(H)
/datum/species/golem/glass/bullet_act(obj/item/projectile/P, mob/living/carbon/human/H)
if(!(P.original == H && P.firer == H)) //self-shots don't reflect
if(P.is_reflectable)
H.visible_message("<span class='danger'>The [P.name] gets reflected by [H]'s glass skin!</span>", \
"<span class='userdanger'>The [P.name] gets reflected by [H]'s glass skin!</span>")
if(P.starting)
var/new_x = P.starting.x + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
var/new_y = P.starting.y + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
var/turf/curloc = get_turf(H)
// redirect the projectile
P.firer = src
P.original = locate(new_x, new_y, P.z)
P.starting = curloc
P.current = curloc
P.yo = new_y - curloc.y
P.xo = new_x - curloc.x
P.Angle = null
return FALSE
return TRUE
/datum/unarmed_attack/golem/glass
attack_sound = 'sound/effects/glassbr2.ogg'
//Teleports when hit or when it wants to
/datum/species/golem/bluespace
name = "Bluespace Golem"
golem_colour = rgb(51, 51, 255)
skinned_type = /obj/item/stack/ore/bluespace_crystal
info_text = "As a <span class='danger'>Bluespace Golem</span>, you are spatially unstable: You will teleport when hit, and you can teleport manually at a long distance."
prefix = "Bluespace"
special_names = list("Crystal", "Polycrystal")
unarmed_type = /datum/unarmed_attack/golem/bluespace
var/datum/action/innate/unstable_teleport/unstable_teleport
var/teleport_cooldown = 100
var/last_teleport = 0
var/tele_range = 6
/datum/species/golem/bluespace/proc/reactive_teleport(mob/living/carbon/human/H)
H.visible_message("<span class='warning'>[H] teleports!</span>", "<span class='danger'>You destabilize and teleport!</span>")
var/list/turfs = new/list()
for(var/turf/T in orange(tele_range, H))
if(T.density)
continue
if(T.x>world.maxx-tele_range || T.x<tele_range)
continue
if(T.y>world.maxy-tele_range || T.y<tele_range)
continue
turfs += T
if(!turfs.len)
turfs += pick(/turf in orange(tele_range, H))
var/turf/picked = pick(turfs)
if(!isturf(picked))
return
if(H.buckled)
H.buckled.unbuckle_mob()
do_teleport(H, picked)
return TRUE
/datum/species/golem/bluespace/spec_hitby(atom/movable/AM, mob/living/carbon/human/H)
..()
var/obj/item/I
if(istype(AM, /obj/item))
I = AM
if(I.thrownby == H) //No throwing stuff at yourself to trigger the teleport
return 0
else
reactive_teleport(H)
/datum/species/golem/bluespace/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
..()
if(world.time > last_teleport + teleport_cooldown && M != H && M.a_intent != INTENT_HELP)
reactive_teleport(H)
/datum/species/golem/bluespace/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H)
..()
if(world.time > last_teleport + teleport_cooldown && user != H)
reactive_teleport(H)
/datum/species/golem/bluespace/bullet_act(obj/item/projectile/P, mob/living/carbon/human/H)
if(world.time > last_teleport + teleport_cooldown)
reactive_teleport(H)
return TRUE
/datum/species/golem/bluespace/on_species_gain(mob/living/carbon/C, datum/species/old_species)
..()
if(ishuman(C))
unstable_teleport = new
unstable_teleport.Grant(C)
last_teleport = world.time
/datum/species/golem/bluespace/on_species_loss(mob/living/carbon/C)
if(unstable_teleport)
unstable_teleport.Remove(C)
..()
/datum/action/innate/unstable_teleport
name = "Unstable Teleport"
check_flags = AB_CHECK_CONSCIOUS
button_icon_state = "blink"
icon_icon = 'icons/mob/actions/actions.dmi'
var/cooldown = 150
var/last_teleport = 0
var/tele_range = 6
/datum/action/innate/unstable_teleport/IsAvailable()
if(..())
if(world.time > last_teleport + cooldown)
return 1
return 0
/datum/action/innate/unstable_teleport/Activate()
var/mob/living/carbon/human/H = owner
H.visible_message("<span class='warning'>[H] starts vibrating!</span>", "<span class='danger'>You start charging your bluespace core...</span>")
playsound(get_turf(H), 'sound/weapons/flash.ogg', 25, 1)
addtimer(CALLBACK(src, .proc/teleport, H), 15)
/datum/action/innate/unstable_teleport/proc/teleport(mob/living/carbon/human/H)
H.visible_message("<span class='warning'>[H] teleports!</span>", "<span class='danger'>You teleport!</span>")
var/list/turfs = new/list()
for(var/turf/T in orange(tele_range, H))
if(istype(T, /turf/space))
continue
if(T.density)
continue
if(T.x>world.maxx-tele_range || T.x<tele_range)
continue
if(T.y>world.maxy-tele_range || T.y<tele_range)
continue
turfs += T
if(!turfs.len)
turfs += pick(/turf in orange(tele_range, H))
var/turf/picked = pick(turfs)
if(!isturf(picked))
return
if(H.buckled)
H.buckled.unbuckle_mob()
do_teleport(H, picked)
last_teleport = world.time
UpdateButtonIcon() //action icon looks unavailable
sleep(cooldown + 5)
UpdateButtonIcon() //action icon looks available again
/datum/unarmed_attack/golem/bluespace
attack_verb = "bluespace punch"
attack_sound = 'sound/effects/phasein.ogg'
//honk
/datum/species/golem/bananium
name = "Bananium Golem"
golem_colour = rgb(255, 255, 0)
punchdamagelow = 0
punchdamagehigh = 0
punchstunthreshold = 1 //Harmless and can't stun
skinned_type = /obj/item/stack/ore/bananium
info_text = "As a <span class='danger'>Bananium Golem</span>, you are made for pranking. Your body emits natural honks, and you can barely even hurt people when punching them. Your skin also bleeds banana peels when damaged."
prefix = "Bananium"
special_names = null
unarmed_type = /datum/unarmed_attack/golem/bananium
var/last_honk = 0
var/honkooldown = 0
var/last_banana = 0
var/banana_cooldown = 100
var/active = null
/datum/species/golem/bananium/on_species_gain(mob/living/carbon/human/H)
..()
last_banana = world.time
last_honk = world.time
H.job = "Clown"
H.mutations.Add(COMIC)
H.equip_to_slot_or_del(new /obj/item/reagent_containers/food/drinks/bottle/bottleofbanana(H), slot_r_store)
H.equip_to_slot_or_del(new /obj/item/bikehorn(H), slot_l_store)
/datum/species/golem/bananium/get_random_name()
var/clown_name = pick(GLOB.clown_names)
var/golem_name = "[prefix] [clown_name]"
return golem_name
/datum/species/golem/bananium/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
..()
if(world.time > last_banana + banana_cooldown && M != H && M.a_intent != INTENT_HELP)
new/obj/item/grown/bananapeel/specialpeel(get_turf(H))
last_banana = world.time
/datum/species/golem/bananium/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H)
..()
if(world.time > last_banana + banana_cooldown && user != H)
new/obj/item/grown/bananapeel/specialpeel(get_turf(H))
last_banana = world.time
/datum/species/golem/bananium/bullet_act(obj/item/projectile/P, mob/living/carbon/human/H)
if(world.time > last_banana + banana_cooldown)
new/obj/item/grown/bananapeel/specialpeel(get_turf(H))
last_banana = world.time
return TRUE
/datum/species/golem/bananium/spec_hitby(atom/movable/AM, mob/living/carbon/human/H)
..()
var/obj/item/I
if(istype(AM, /obj/item))
I = AM
if(I.thrownby == H) //No throwing stuff at yourself to make bananas
return 0
else
new/obj/item/grown/bananapeel/specialpeel(get_turf(H))
last_banana = world.time
/datum/species/golem/bananium/handle_life(mob/living/carbon/human/H)
if(!active)
if(world.time > last_honk + honkooldown)
active = 1
playsound(get_turf(H), 'sound/items/bikehorn.ogg', 50, 1)
last_honk = world.time
honkooldown = rand(20, 80)
active = null
..()
/datum/species/golem/bananium/handle_death(mob/living/carbon/human/H)
playsound(get_turf(H), 'sound/misc/sadtrombone.ogg', 70, 0)
/datum/unarmed_attack/golem/bananium
attack_verb = list("HONK")
attack_sound = 'sound/items/airhorn2.ogg'
animation_type = ATTACK_EFFECT_DISARM
harmless = TRUE
//...
/datum/species/golem/tranquillite
name = "Tranquillite Golem"
prefix = "Tranquillite"
special_names = null
golem_colour = rgb(255, 255, 255)
skinned_type = /obj/item/stack/ore/tranquillite
info_text = "As a <span class='danger'>Tranquillite Golem</span>, you are capable of creating invisible walls, and can regenerate by drinking your bottle of Nothing."
unarmed_type = /datum/unarmed_attack/golem/tranquillite
/datum/species/golem/tranquillite/get_random_name()
var/mime_name = pick(GLOB.mime_names)
var/golem_name = "[prefix] [mime_name]"
return golem_name
/datum/species/golem/tranquillite/on_species_gain(mob/living/carbon/human/H)
..()
H.job = "Mime"
H.equip_to_slot_or_del(new /obj/item/clothing/head/beret(H), slot_head)
H.equip_to_slot_or_del(new /obj/item/reagent_containers/food/drinks/bottle/bottleofnothing(H), slot_r_store)
H.equip_to_slot_or_del(new /obj/item/cane(H), slot_l_hand)
if(H.mind)
H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall(null))
H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mime/speak(null))
H.mind.miming = TRUE
/datum/unarmed_attack/golem/tranquillite
attack_sound = null
miss_sound = null
//Golem abstract items
/obj/item/clothing/under/golem
name = "adamantine skin"
name = "golem skin"
desc = "a golem's skin"
icon_state = "golem"
item_state = "golem"
@@ -69,34 +690,39 @@
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0)
/obj/item/clothing/suit/golem
name = "adamantine shell"
name = "golem shell"
desc = "a golem's thick outter shell"
icon_state = "golem"
item_state = "golem"
body_parts_covered = HEAD|UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS
flags_inv = HIDEGLOVES|HIDESHOES
flags = ABSTRACT | NODROP | THICKMATERIAL
gas_transfer_coefficient = 0.01
permeability_coefficient = 0.02
body_parts_covered = HEAD | UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS | HANDS
flags_inv = HIDEGLOVES | HIDESHOES
flags = STOPSPRESSUREDMAGE | ABSTRACT | NODROP | THICKMATERIAL
flags_size = ONESIZEFITSALL
armor = list(melee = 55, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0)
cold_protection = HEAD | UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS | HANDS
min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 100, rad = 0)
/obj/item/clothing/shoes/golem
name = "golem's feet"
desc = "sturdy adamantine feet"
desc = "sturdy golem feet"
icon_state = "golem"
item_state = "golem"
flags = ABSTRACT | NODROP
/obj/item/clothing/mask/gas/golem
name = "golem's face"
desc = "the imposing face of an adamantine golem"
desc = "the imposing face of a golem"
icon_state = "golem"
item_state = "golem"
unacidable = 1
flags = ABSTRACT | NODROP
flags_inv = HIDEEARS | HIDEEYES
/obj/item/clothing/gloves/golem
name = "golem's hands"
desc = "strong adamantine hands"
desc = "strong golem hands"
icon_state = "golem"
item_state = null
flags = ABSTRACT | NODROP
@@ -222,6 +222,10 @@ var/global/list/damage_icon_parts = list()
base_icon.Blend(temp, ICON_OVERLAY)
if(!skeleton)
if(isgolem(src))
var/datum/species/golem/G = src.dna.species
if(G.golem_colour)
base_icon.ColorTone(G.golem_colour)
if(husk)
base_icon.ColorTone(husk_color_mod)
else if(hulk)
@@ -239,6 +243,7 @@ var/global/list/damage_icon_parts = list()
var/mutable_appearance/new_base = mutable_appearance(base_icon, layer = -LIMBS_LAYER)
human_icon_cache[icon_key] = new_base
standing += new_base
//END CACHED ICON GENERATION.
overlays_standing[LIMBS_LAYER] = standing
@@ -92,7 +92,7 @@
to_chat(src, "<span class='notice'>Unusable emote '[act]'. Say *help for a list.</span>")
if((message && stat == CONSCIOUS))
if(client)
log_emote("[name]/[key] : [message]")
log_emote("[name]/[key] : [message]", src)
if(m_type & 1)
visible_message(message)
else
+2
View File
@@ -67,6 +67,8 @@
med_hud_set_health()
med_hud_set_status()
if(!gibbed && !QDELETED(src))
addtimer(CALLBACK(src, .proc/med_hud_set_status), (DEFIB_TIME_LIMIT * 10) + 1)
callHook("death", list(src, gibbed))
for(var/s in ownedSoullinks)
+19 -2
View File
@@ -80,6 +80,10 @@
if(moving_diagonally) //no mob swap during diagonal moves.
return 1
if(a_intent == INTENT_HELP) // Help intent doesn't mob swap a mob pulling a structure
if(isstructure(M.pulling) || isstructure(pulling))
return 1
if(!M.buckled && !M.has_buckled_mobs())
var/mob_swap
//the puller can always swap with it's victim if on grab intent
@@ -128,6 +132,13 @@
//Called when we want to push an atom/movable
/mob/living/proc/PushAM(atom/movable/AM, force = move_force)
if(isstructure(AM) && AM.pulledby)
if(a_intent == INTENT_HELP && AM.pulledby != src) // Help intent doesn't push other peoples pulled structures
return FALSE
if(get_dist(get_step(AM, get_dir(src, AM)), AM.pulledby)>1)//Release pulled structures beyond 1 distance
AM.pulledby.stop_pulling()
if(now_pushing)
return TRUE
if(moving_diagonally) // no pushing during diagonal moves
@@ -226,7 +237,7 @@
return TRUE
A.visible_message("<span class='danger'>[src] points [hand_item] at [A]!</span>",
"<span class='userdanger'>[src] points [hand_item] at you!</span>")
A << 'sound/weapons/TargetOn.ogg'
A << 'sound/weapons/targeton.ogg'
return TRUE
visible_message("<b>[src]</b> points to [A]")
return TRUE
@@ -508,6 +519,7 @@
var/turf/T = loc
. = ..()
if(.)
SEND_SIGNAL(src, COMSIG_MOVABLE_MOVED)
handle_footstep(loc)
step_count++
@@ -882,7 +894,7 @@
// If we're pulling something then drop what we're currently pulling and pull this instead.
AM.add_fingerprint(src)
if(pulling)
if(AM == pulling)// Are we trying to pull something we are already pulling? Then just stop here, no need to continue.
if(AM == pulling)// Are we trying to pull something we are already pulling? Then just stop here, no need to continue.
return
stop_pulling()
if(AM.pulledby)
@@ -975,3 +987,8 @@
/mob/living/proc/fakefire()
return
/mob/living/extinguish_light()
for(var/atom/A in src)
if(A.light_range > 0)
A.extinguish_light()
+1 -1
View File
@@ -117,7 +117,7 @@
playsound(src, 'sound/weapons/punch4.ogg', 50, 1)
if("fire")
take_overall_damage(0, rand(M.force/2, M.force))
playsound(src, 'sound/items/Welder.ogg', 50, 1)
playsound(src, 'sound/items/welder.ogg', 50, 1)
if("tox")
M.mech_toxin_damage(src)
else
+3 -2
View File
@@ -190,7 +190,7 @@ proc/get_radio_key_from_channel(var/channel)
message_range = 1
if(first_piece.speaking)
message_range = first_piece.speaking.get_talkinto_msg_range(message)
var/msg
if(!first_piece.speaking || !(first_piece.speaking.flags & NO_TALK_MSG))
msg = "<span class='notice'>[src] talks into [used_radios[1]]</span>"
@@ -343,6 +343,8 @@ proc/get_radio_key_from_channel(var/channel)
to_chat(src, "<span class='danger'>You're muzzled and cannot speak!</span>")
return
log_whisper(multilingual_to_message(message_pieces), src)
var/message_range = 1
var/eavesdropping_range = 2
var/watching_range = 5
@@ -445,7 +447,6 @@ proc/get_radio_key_from_channel(var/channel)
for(var/mob/M in watching)
M.show_message(rendered, 2)
log_whisper(multilingual_to_message(message_pieces), src)
return 1
/mob/living/speech_bubble(var/bubble_state = "",var/bubble_loc = src, var/list/bubble_recipients = list())
+8 -8
View File
@@ -36,7 +36,7 @@ var/list/ai_verbs_default = list(
/mob/living/silicon/ai
name = "AI"
icon = 'icons/mob/AI.dmi'//
icon = 'icons/mob/ai.dmi'//
icon_state = "ai"
move_resist = MOVE_FORCE_VERY_STRONG
density = 1
@@ -143,7 +143,7 @@ var/list/ai_verbs_default = list(
density = 1
loc = loc
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo1"))
holo_icon = getHologramIcon(icon('icons/mob/ai.dmi',"holo1"))
proc_holder_list = new()
@@ -379,7 +379,7 @@ var/list/ai_verbs_default = list(
//if(icon_state == initial(icon_state))
var/icontype = ""
icontype = input("Select an icon!", "AI", null, null) in display_choices
icon = 'icons/mob/AI.dmi' //reset this in case we were on a custom sprite and want to change to a standard one
icon = 'icons/mob/ai.dmi' //reset this in case we were on a custom sprite and want to change to a standard one
switch(icontype)
if("Custom")
icon = 'icons/mob/custom_synthetic/custom-synthetic.dmi' //set this here so we can use the custom_sprite
@@ -1007,13 +1007,13 @@ var/list/ai_verbs_default = list(
qdel(holo_icon)
switch(input)
if("default")
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo1"))
holo_icon = getHologramIcon(icon('icons/mob/ai.dmi',"holo1"))
if("floating face")
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo2"))
holo_icon = getHologramIcon(icon('icons/mob/ai.dmi',"holo2"))
if("xeno queen")
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo3"))
holo_icon = getHologramIcon(icon('icons/mob/ai.dmi',"holo3"))
if("eldritch")
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo4"))
holo_icon = getHologramIcon(icon('icons/mob/ai.dmi',"holo4"))
if("ancient machine")
holo_icon = getHologramIcon(icon('icons/mob/ancient_machine.dmi', "ancient_machine"))
if("custom")
@@ -1022,7 +1022,7 @@ var/list/ai_verbs_default = list(
else if("[ckey]-ai-holo" in icon_states('icons/mob/custom_synthetic/custom-synthetic64.dmi'))
holo_icon = getHologramIcon(icon('icons/mob/custom_synthetic/custom-synthetic64.dmi', "[ckey]-ai-holo"))
else
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo1"))
holo_icon = getHologramIcon(icon('icons/mob/ai.dmi',"holo1"))
return
@@ -6,7 +6,7 @@
/mob/camera/aiEye
name = "Inactive AI Eye"
icon = 'icons/mob/AI.dmi' //Allows ghosts to see what the AI is looking at.
icon = 'icons/mob/ai.dmi' //Allows ghosts to see what the AI is looking at.
icon_state = "eye"
alpha = 127
invisibility = SEE_INVISIBLE_OBSERVER
@@ -37,6 +37,9 @@ var/global/list/empty_playable_ai_cores = list()
var/datum/game_mode/traitor/autotraitor/current_mode = ticker.mode
current_mode.possible_traitors.Remove(src)
// Ghost the current player and disallow them to return to the body
ghostize(FALSE)
// Delete the old AI shell
qdel(src)
// TODO: Move away from the insane name-based landmark system
@@ -1,13 +1,13 @@
/mob/living/silicon/decoy
name = "AI"
icon = 'icons/mob/AI.dmi'//
icon = 'icons/mob/ai.dmi'//
icon_state = "ai"
anchored = 1 // -- TLE
canmove = 0
a_intent = INTENT_HARM // This is apparently the only thing that stops other mobs walking through them as if they were thin air.
/mob/living/silicon/decoy/New()
src.icon = 'icons/mob/AI.dmi'
src.icon = 'icons/mob/ai.dmi'
src.icon_state = "ai"
src.anchored = 1
src.canmove = 0
@@ -79,6 +79,7 @@
var/obj/item/integrated_radio/signal/sradio // AI's signaller
var/translator_on = 0 // keeps track of the translator module
var/flashlight_on = FALSE //keeps track of the flashlight module
var/current_pda_messaging = null
var/custom_sprite = 0
@@ -607,3 +608,8 @@
else //something went very wrong.
CRASH("pAI without card")
loc = card
/mob/living/silicon/pai/extinguish_light()
flashlight_on = FALSE
set_light(0)
card.set_light(0)
@@ -609,3 +609,20 @@
data["holder"] = 0
return data
/datum/pai_software/flashlight
name = "Flashlight"
ram_cost = 5
id = "flashlight"
/datum/pai_software/flashlight/toggle(mob/living/silicon/pai/user)
var/atom/movable/actual_location = istype(user.loc, /obj/item/paicard) ? user.loc : user
if(user.flashlight_on)
actual_location.set_light(2)
user.card.set_light(2)
return
actual_location.set_light(2)
user.card.set_light(0)
/datum/pai_software/flashlight/is_active(mob/living/silicon/pai/user)
return user.flashlight_on
@@ -99,7 +99,7 @@
/mob/living/silicon/robot/drone/update_icons()
overlays.Cut()
if(stat == 0)
if(stat == CONSCIOUS)
overlays += "eyes-[icon_state]"
else
overlays -= "eyes"
@@ -124,7 +124,7 @@
else if(istype(W, /obj/item/card/id)||istype(W, /obj/item/pda))
if(stat == 2)
if(stat == DEAD)
if(!config.allow_drone_spawn || emagged || health < -35) //It's dead, Dave.
to_chat(user, "<span class='warning'>The interface is fried, and a distressing burned smell wafts from the robot's interior. You're not rebooting this one.</span>")
@@ -166,7 +166,7 @@
..()
/mob/living/silicon/robot/drone/emag_act(user as mob)
if(!client || stat == 2)
if(!client || stat == DEAD)
to_chat(user, "<span class='warning'>There's not much point subverting this heap of junk.</span>")
return
@@ -223,12 +223,12 @@
/mob/living/silicon/robot/drone/death(gibbed)
. = ..(gibbed)
ghostize(can_reenter_corpse = 0)
adjustBruteLoss(health)
//CONSOLE PROCS
/mob/living/silicon/robot/drone/proc/law_resync()
if(stat != 2)
if(stat != DEAD)
if(emagged)
to_chat(src, "<span class='warning'>You feel something attempting to modify your programming, but your hacked subroutines are unaffected.</span>")
else
@@ -237,7 +237,7 @@
show_laws()
/mob/living/silicon/robot/drone/proc/shut_down(force=FALSE)
if(stat == 2)
if(stat == DEAD)
return
if(emagged && !force)
@@ -38,16 +38,35 @@
/obj/item/gripper/paperwork
name = "paperwork gripper"
desc = "A simple grasping tool for clerical work."
icon = 'icons/obj/device.dmi'
icon_state = "gripper"
can_hold = list(
/obj/item/clipboard,
/obj/item/paper,
// /obj/item/paper_bundle,
/obj/item/card/id
)
/obj/item/gripper/medical
name = "medical gripper"
desc = "A grasping tool used to help patients up once surgery is complete."
can_hold = list()
/obj/item/gripper/medical/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, proximity, params)
var/mob/living/carbon/human/H
if(!wrapped && proximity && target && ishuman(target))
H = target
if(H.lying)
H.AdjustSleeping(-5)
if(H.sleeping == 0)
H.StopResting()
H.AdjustParalysis(-3)
H.AdjustStunned(-3)
H.AdjustWeakened(-3)
playsound(user.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
user.visible_message( \
"<span class='notice'>[user] shakes [H] trying to wake [H.p_them()] up!</span>",\
"<span class='notice'>You shake [H] trying to wake [H.p_them()] up!</span>",\
)
/obj/item/gripper/New()
..()
can_hold = typecacheof(can_hold)
@@ -1382,6 +1382,9 @@ var/list/robot_verbs_default = list(
if(2)
disable_component("comms", 60)
/mob/living/silicon/robot/extinguish_light()
update_headlamp(1, 150)
/mob/living/silicon/robot/rejuvenate()
..()
var/brute = 1000
@@ -153,15 +153,15 @@
modules += new /obj/item/stack/medical/ointment/advanced(src)
modules += new /obj/item/stack/medical/splint(src)
modules += new /obj/item/stack/nanopaste(src)
modules += new /obj/item/scalpel(src)
modules += new /obj/item/scalpel/laser/laser1(src)
modules += new /obj/item/hemostat(src)
modules += new /obj/item/retractor(src)
modules += new /obj/item/cautery(src)
modules += new /obj/item/bonegel(src)
modules += new /obj/item/FixOVein(src)
modules += new /obj/item/bonesetter(src)
modules += new /obj/item/circular_saw(src)
modules += new /obj/item/surgicaldrill(src)
modules += new /obj/item/gripper/medical(src)
emag = new /obj/item/reagent_containers/spray(src)
@@ -408,6 +408,7 @@
..()
modules += new /obj/item/healthanalyzer/advanced(src)
modules += new /obj/item/reagent_scanner/adv(src)
modules += new /obj/item/bodyanalyzer/borg/syndicate(src)
modules += new /obj/item/borg_defib(src)
modules += new /obj/item/roller_holder(src)
modules += new /obj/item/reagent_containers/borghypo/syndicate(src)
@@ -416,14 +417,14 @@
modules += new /obj/item/stack/medical/ointment/advanced(src)
modules += new /obj/item/stack/medical/splint(src)
modules += new /obj/item/stack/nanopaste(src)
modules += new /obj/item/scalpel(src)
modules += new /obj/item/scalpel/laser/laser1(src)
modules += new /obj/item/hemostat(src)
modules += new /obj/item/retractor(src)
modules += new /obj/item/cautery(src)
modules += new /obj/item/bonegel(src)
modules += new /obj/item/FixOVein(src)
modules += new /obj/item/bonesetter(src)
modules += new /obj/item/surgicaldrill(src)
modules += new /obj/item/gripper/medical(src)
modules += new /obj/item/melee/energy/sword/cyborg/saw(src) //Energy saw -- primary weapon
modules += new /obj/item/card/emag(src)
modules += new /obj/item/crowbar/cyborg(src)
@@ -13,7 +13,7 @@
if(INTENT_HARM, INTENT_DISARM)
M.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
visible_message("<span class='danger'>[M] [response_harm] [src]!</span>")
playsound(loc, "punch", 25, 1, -1)
playsound(loc, attacked_sound, 25, 1, -1)
attack_threshold_check(harm_intent_damage)
add_attack_logs(M, src, "Melee attacked with fists")
updatehealth()
@@ -396,8 +396,8 @@ var/robot_arm = /obj/item/robot_parts/l_arm
icon = 'icons/obj/aibots.dmi'
icon_state = "helmet_signaler"
item_state = "helmet"
var/build_step = 0
var/created_name = "Securitron" //To preserve the name if it's a unique securitron I guess
var/build_step = 0
/obj/item/clothing/head/helmet/attackby(obj/item/assembly/signaler/S, mob/user, params)
..()
@@ -490,6 +490,68 @@ var/robot_arm = /obj/item/robot_parts/l_arm
to_chat(user, "<span class='notice'>You remove the robot arm from [src].</span>")
build_step--
//General Griefsky
else if((istype(I, /obj/item/wrench)) && (build_step == 3))
var/obj/item/griefsky_assembly/A = new /obj/item/griefsky_assembly
user.put_in_hands(A)
to_chat(user, "<span class='notice'>You adjust the arm slots for extra weapons!.</span>")
user.unEquip(src, 1)
qdel(src)
/obj/item/griefsky_assembly
name = "\improper Griefsky assembly"
desc = "Some sort of bizarre assembly."
icon = 'icons/obj/aibots.dmi'
icon_state = "griefsky_assembly"
item_state = "griefsky_assembly"
var/build_step = 0
var/toy_step = 0
/obj/item/griefsky_assembly/attackby(obj/item/I, mob/user, params)
..()
if((istype(I, /obj/item/melee/energy/sword)) && (build_step < 3 ))
if(!user.unEquip(I))
return
build_step++
to_chat(user, "<span class='notice'>You add an energy sword to [src]!.</span>")
qdel(I)
else if((istype(I, /obj/item/melee/energy/sword)) && (build_step == 3))
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))
qdel(I)
qdel(src)
else if((istype(I, /obj/item/toy/sword)) && (toy_step < 3 ))
if(!user.unEquip(I))
return
toy_step++
to_chat(user, "<span class='notice'>You add a toy sword to [src]!.</span>")
qdel(I)
else if((istype(I, /obj/item/toy/sword)) && (toy_step == 3))
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))
qdel(I)
qdel(src)
else if(istype(I, /obj/item/screwdriver))
if((build_step == 1) || (build_step == 2) || (build_step == 3) || (build_step == 4))
new /obj/item/melee/energy/sword(get_turf(src))
to_chat(user, "<span class='notice'>You detach the energy sword from [src].</span>")
build_step--
else if((toy_step == 1) || (toy_step == 2) || (toy_step == 3) || (toy_step == 4))
new /obj/item/toy/sword(get_turf(src))
to_chat(user, "<span class='notice'>You detach the toy sword from [src].</span>")
toy_step--
//Honkbot Assembly
/obj/item/storage/box/clown/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/robot_parts/l_arm) && !istype(W, /obj/item/robot_parts/r_arm))
@@ -41,7 +41,7 @@
var/check_records = 1 //Does it check security records?
var/arrest_type = 0 //If true, don't handcuff
var/projectile = /obj/item/projectile/energy/electrode //Holder for projectile type
var/shoot_sound = 'sound/weapons/Taser.ogg'
var/shoot_sound = 'sound/weapons/taser.ogg'
/mob/living/simple_animal/bot/ed209/New(loc, created_name, created_lasercolor)
@@ -357,7 +357,7 @@
target = C
oldtarget_name = C.name
speak("Level [threatlevel] infraction alert!")
playsound(loc, pick('sound/voice/ed209_20sec.ogg', 'sound/voice/EDPlaceholder.ogg'), 50, 0)
playsound(loc, pick('sound/voice/ed209_20sec.ogg', 'sound/voice/edplaceholder.ogg'), 50, 0)
visible_message("<b>[src]</b> points at [C.name]!")
mode = BOT_HUNT
spawn(0)
@@ -416,7 +416,7 @@
..()
/mob/living/simple_animal/bot/ed209/proc/set_weapon() //used to update the projectile type and firing sound
shoot_sound = 'sound/weapons/Laser.ogg'
shoot_sound = 'sound/weapons/laser.ogg'
if(emagged == 2)
if(lasercolor)
projectile = /obj/item/projectile/beam/disabler
@@ -424,7 +424,7 @@
projectile = /obj/item/projectile/beam
else
if(!lasercolor)
shoot_sound = 'sound/weapons/Taser.ogg'
shoot_sound = 'sound/weapons/taser.ogg'
projectile = /obj/item/projectile/energy/electrode
else if(lasercolor == "b")
projectile = /obj/item/projectile/beam/lasertag/bluetag
@@ -0,0 +1,231 @@
/mob/living/simple_animal/bot/secbot/griefsky //This bot is powerful. If you managed to get 4 eswords somehow, you deserve this horror. Emag him for best results.
name = "\improper General Griefsky"
desc = "Is that a secbot with four eswords in its arms...?"
icon_state = "griefsky0"
health = 100
maxHealth = 100
base_icon = "griefsky"
window_name = "Automatic Security Unit v3.0"
var/spin_icon = "griefsky-c" // griefsky and griefsky junior have dif icons
var/weapon = /obj/item/melee/energy/sword
var/block_chance = 50 //block attacks
var/reflect_chance = 80 // chance to reflect projectiles
var/dmg = 30 //esword dmg
var/block_chance_melee = 50
var/block_chance_ranged = 90
var/stun_chance = 50
var/spam_flag = 0
/mob/living/simple_animal/bot/secbot/griefsky/toy //A toy version of general griefsky!
name = "Genewul Giftskee"
desc = "An adorable looking secbot with four toy swords taped to its arms"
spin_icon = "griefskyj-c"
health = 50
maxHealth = 50
radio_channel = "Service" //we dont report sec anymore!
dmg = 0
block_chance_melee = 1
block_chance_ranged = 1
stun_chance = 0
bot_core_type = /obj/machinery/bot_core/toy
weapon = /obj/item/toy/sword
/obj/machinery/bot_core/toy
req_access = list(access_maint_tunnels, access_theatre, access_robotics)
/mob/living/simple_animal/bot/secbot/griefsky/proc/spam_flag_false() //used for addtimer to not spam comms
spam_flag = 0
/mob/living/simple_animal/bot/secbot/griefsky/back_to_idle()
..()
playsound(loc, 'sound/weapons/saberoff.ogg', 50, 1, -1)
/mob/living/simple_animal/bot/secbot/griefsky/emag_act(mob/user)
..()
light_color = LIGHT_COLOR_PURE_RED //if you see a red one. RUN!!
/mob/living/simple_animal/bot/secbot/griefsky/Crossed(atom/movable/AM)
..()
if(ismob(AM) && AM == target)
var/mob/living/carbon/C = AM
visible_message("[src] flails his swords and pushes [C] out of it's way!" )
C.Weaken(2)
/mob/living/simple_animal/bot/secbot/griefsky/New()
..()
/mob/living/simple_animal/bot/secbot/griefsky/Destroy()
QDEL_NULL(weapon)
return ..()
/mob/living/simple_animal/bot/secbot/griefsky/UnarmedAttack(atom/A) //like secbots its only possible with admin intervention
if(!on)
return
if(iscarbon(A))
var/mob/living/carbon/C = A
sword_attack(C)
/mob/living/simple_animal/bot/secbot/griefsky/bullet_act(obj/item/projectile/P) //so uncivilized
retaliate(P.firer)
if((icon_state == spin_icon) && (prob(block_chance_ranged))) //only when the eswords are on
visible_message("[src] deflects [P] with its energy swords!")
playsound(loc, 'sound/weapons/blade1.ogg', 50, 1, 0)
else
..()
/mob/living/simple_animal/bot/secbot/griefsky/proc/sword_attack(mob/living/carbon/C) // esword attack
src.do_attack_animation(C)
playsound(loc, 'sound/weapons/blade1.ogg', 50, 1, -1)
spawn(2)
icon_state = spin_icon
var/threat = C.assess_threat(src)
if(ishuman(C))
C.apply_damage(dmg, BRUTE)
if(prob(stun_chance))
C.Weaken(5)
add_attack_logs(src, C, "sliced")
if(declare_arrests)
var/area/location = get_area(src)
if(!spam_flag)
speak("Back away! I will deal with this level [threat] swine <b>[C]</b> in [location] myself!.", radio_channel)
spam_flag = 1
addtimer(CALLBACK(src, .proc/spam_flag_false), 100) //to avoid spamming comms of sec for each hit
visible_message("[src] flails his swords and cuts [C]!")
/mob/living/simple_animal/bot/secbot/griefsky/handle_automated_action()
if(!on)
return
switch(mode)
if(BOT_IDLE) // idle
icon_state = "griefsky1"
walk_to(src,0)
look_for_perp() // see if any criminals are in range
if(!mode && auto_patrol) // still idle, and set to patrol
mode = BOT_START_PATROL // switch to patrol mode
if(BOT_HUNT) // hunting for perp
icon_state = spin_icon
playsound(loc,'sound/effects/spinsabre.ogg',100,1,-1)
if(frustration >= 15) // general beepsky doesn't give up so easily, jedi scum
walk_to(src,0)
back_to_idle()
return
if(target) // make sure target exists
if(target.stat == !DEAD)
if(Adjacent(target) && isturf(target.loc)) // if right next to perp
target_lastloc = target.loc
sword_attack(target)
anchored = TRUE
frustration++
return
else // not next to perp
var/turf/olddist = get_dist(src, target)
walk_to(src, target,1,3) //he's a fast fucker
if((get_dist(src, target)) >= (olddist))
frustration++
else
frustration = 0
else
back_to_idle()
speak("You fool")
else
back_to_idle()
if(BOT_START_PATROL)
look_for_perp()
start_patrol()
if(BOT_PATROL)
icon_state = "griefsky1"
look_for_perp()
bot_patrol()
return
/mob/living/simple_animal/bot/secbot/griefsky/look_for_perp()
anchored = 0
for (var/mob/living/carbon/C in view(7,src)) //Let's find us a criminal
if((C.stat) || (C.handcuffed))
continue
if((C.name == oldtarget_name) && (world.time < last_found + 100))
continue
threatlevel = C.assess_threat(src)
if(!threatlevel)
continue
else if(threatlevel >= 4)
target = C
oldtarget_name = C.name
speak("You are a bold one")
playsound(src,'sound/weapons/saberon.ogg',50,TRUE,-1)
visible_message("[src] ignites his energy swords!")
icon_state = "griefsky-c"
visible_message("<b>[src]</b> points at [C.name]!")
mode = BOT_HUNT
INVOKE_ASYNC(src, .proc/handle_automated_action)
break
else
continue
/mob/living/simple_animal/bot/secbot/griefsky/explode()
walk_to(src,0)
visible_message("<span class='boldannounce'>[src] lets out a huge cough as it blows apart!</span>")
var/turf/Tsec = get_turf(src)
new /obj/item/assembly/prox_sensor(Tsec)
if(prob(50))
new /obj/item/robot_parts/r_arm(Tsec)
if(prob(50)) //most of the time weapon will be destroyed
new weapon(Tsec)
if(prob(25))
new weapon(Tsec)
if(prob(10))
new weapon(Tsec)
if(prob(5))
new weapon(Tsec)
do_sparks(3, 1, src)
new /obj/effect/decal/cleanable/blood/oil(loc)
..()
//this section is blocking attack
/mob/living/simple_animal/bot/secbot/griefsky/bullet_act(obj/item/projectile/P) //so uncivilized
retaliate(P.firer)
if((icon_state == spin_icon) && (prob(block_chance_ranged))) //only when the eswords are on
visible_message("[src] deflects [P] with its energy swords!")
playsound(loc, 'sound/weapons/blade1.ogg', 50, 1, 0)
else
..()
/mob/living/simple_animal/bot/secbot/griefsky/proc/special_retaliate_after_attack(mob/user) //allows special actions to take place after being attacked.
return
/mob/living/simple_animal/bot/secbot/griefsky/special_retaliate_after_attack(mob/user)
if(icon_state != spin_icon)
return
if(prob(block_chance_melee))
visible_message("[src] deflects [user]'s attack with his energy swords!")
playsound(loc, 'sound/weapons/blade1.ogg', 50, TRUE, -1)
return TRUE
/mob/living/simple_animal/bot/secbot/griefsky/attack_hand(mob/living/carbon/human/H)
if((H.a_intent == INTENT_HARM) || (H.a_intent == INTENT_DISARM))
retaliate(H)
if(special_retaliate_after_attack(H))
return
return ..()
/mob/living/simple_animal/bot/secbot/griefsky/attackby(obj/item/W, mob/user, params) //cant touch or attack him while spinning
if(src.icon_state == spin_icon)
if(prob(block_chance_melee))
user.changeNext_move(CLICK_CD_MELEE)
user.do_attack_animation(src)
visible_message("[src] deflects [user]'s move with his energy swords!")
playsound(loc, 'sound/weapons/blade1.ogg', 50, TRUE, -1)
else
return ..()
else
return ..()
@@ -286,6 +286,7 @@
new /obj/item/assembly/prox_sensor(Tsec)
if(prob(50))
drop_part(robot_arm, Tsec)
new /obj/effect/decal/cleanable/blood/oil(loc)
var/datum/effect_system/spark_spread/s = new
s.set_up(3, 1, src)
s.start()
@@ -121,7 +121,7 @@
dat += hack(user)
dat += showpai(user)
dat += text({"
<TT><B>Securitron v1.6 controls</B></TT><BR><BR>
<TT><B>[window_name]</B></TT><BR><BR>
Status: []<BR>
Behaviour controls are [locked ? "locked" : "unlocked"]<BR>
Maintenance panel panel is [open ? "opened" : "closed"]"},
@@ -177,3 +177,57 @@
minbodytemp = 0
melee_damage_lower = 5
melee_damage_upper = 15
/mob/living/simple_animal/pet/cat/cak
name = "Keeki"
desc = "It's a cat made out of cake."
icon_state = "cak"
icon_living = "cak"
icon_resting = "cak_rest"
icon_dead = "cak_dead"
health = 50
maxHealth = 50
harm_intent_damage = 10
butcher_results = list(
/obj/item/organ/internal/brain = 1,
/obj/item/organ/internal/heart = 1,
/obj/item/reagent_containers/food/snacks/birthdaycakeslice = 3,
/obj/item/reagent_containers/food/snacks/meat/slab = 2
)
response_harm = "takes a bite out of"
attacked_sound = "sound/items/eatfood.ogg"
deathmessage = "loses its false life and collapses!"
death_sound = "bodyfall"
/mob/living/simple_animal/pet/cat/cak/Life()
..()
if(stat)
return
if(health < maxHealth)
adjustBruteLoss(-4)
for(var/obj/item/reagent_containers/food/snacks/donut/D in range(1, src))
if(D.icon_state != "donut2")
D.name = "frosted donut"
D.icon_state = "donut2"
D.reagents.add_reagent("sprinkles", 2)
D.filling_color = "#FF69B4"
/mob/living/simple_animal/pet/cat/cak/attack_hand(mob/living/L)
..()
if(L.a_intent == INTENT_HARM && L.reagents && !stat)
L.reagents.add_reagent("nutriment", 0.4)
L.reagents.add_reagent("vitamin", 0.4)
/mob/living/simple_animal/pet/cat/cak/CheckParts(list/parts)
..()
var/obj/item/organ/internal/brain/B = locate(/obj/item/organ/internal/brain) in contents
if(!B || !B.brainmob || !B.brainmob.mind)
return
B.brainmob.mind.transfer_to(src)
to_chat(src, "<span class='big bold'>You are a cak!</span><b> You're a harmless cat/cake hybrid that everyone loves. People can take bites out of you if they're hungry, but you regenerate health \
so quickly that it generally doesn't matter. You're remarkably resilient to any damage besides this and it's hard for you to really die at all. You should go around and bring happiness and \
free cake to the station!</b>")
var/new_name = stripped_input(src, "Enter your name, or press \"Cancel\" to stick with Keeki.", "Name Change")
if(new_name)
to_chat(src, "<span class='notice'>Your name is now <b>\"[new_name]\"</b>!</span>")
name = new_name
@@ -5,6 +5,7 @@
icon_state = "mouse_gray"
icon_living = "mouse_gray"
icon_dead = "mouse_gray_dead"
icon_resting = "mouse_gray_sleep"
speak = list("Squeek!","SQUEEK!","Squeek?")
speak_emote = list("squeeks","squeaks","squiks")
emote_hear = list("squeeks","squeaks","squiks")
@@ -69,6 +70,7 @@
icon_state = "mouse_[mouse_color]"
icon_living = "mouse_[mouse_color]"
icon_dead = "mouse_[mouse_color]_dead"
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()
@@ -121,7 +123,7 @@
if(on_CD == 1)
return
switch(act)
if("squeak")
message = "<B>\The [src]</B> squeaks!"
@@ -207,4 +209,16 @@
/mob/living/simple_animal/mouse/blobinfected/get_scooped(mob/living/carbon/grabber)
to_chat(grabber, "<span class='warning'>You try to pick up [src], but they slip out of your grasp!</span>")
to_chat(src, "<span class='warning'>[src] tries to pick you up, but you wriggle free of their grasp!</span>")
to_chat(src, "<span class='warning'>[src] tries to pick you up, but you wriggle free of their grasp!</span>")
/mob/living/simple_animal/mouse/fluff/clockwork
name = "Chip"
real_name = "Chip"
mouse_color = "clockwork"
icon_state = "mouse_clockwork"
response_help = "pets"
response_disarm = "gently pushes aside"
response_harm = "stamps on"
gold_core_spawnable = CHEM_MOB_SPAWN_INVALID
can_collar = 0
butcher_results = list(/obj/item/stack/sheet/metal = 1)
@@ -74,4 +74,5 @@
a_intent = INTENT_HARM
pass_flags = PASSTABLE
universal_speak = 1
universal_understand = 1
universal_understand = 1
gold_core_spawnable = CHEM_MOB_SPAWN_INVALID //badmin only
@@ -2,7 +2,7 @@
/mob/living/simple_animal/hostile/hellhound
// Sprites by FoS: http://nanotrasen.se/phpBB3/memberlist.php?mode=viewprofile&u=386
name = "Lesser Hellhound"
desc = "A horrifying, black canine monster, with glowing red eyes and vicious-looking teeth. A firey, lava-like substance drips from it."
desc = "A demonic-looking black canine monster with glowing red eyes and sharp teeth. A firey, lava-like substance drips from it."
icon_state = "hellhound"
icon_living = "hellhound"
icon_dead = "hellhound_dead"
@@ -97,7 +97,7 @@
/mob/living/simple_animal/hostile/hellhound/AttackingTarget()
. = ..()
if(ishuman(target))
if(ishuman(target) && (!client || a_intent == INTENT_HARM))
special_aoe()
/mob/living/simple_animal/hostile/hellhound/attackby(obj/item/C, mob/user, params)
@@ -117,6 +117,7 @@
/mob/living/simple_animal/hostile/hellhound/greater
name = "Greater Hellhound"
desc = "A demonic-looking black canine monster with glowing red eyes and sharp teeth. Greater hounds are far stronger than their lesser kin, and typically employed by powerful bluespace entities."
icon_state = "hellhoundgreater"
icon_living = "hellhoundgreater"
icon_resting = "hellhoundgreater_sit"
@@ -15,7 +15,7 @@
melee_damage_upper = 3
attacktext = "claws"
attack_sound = 'sound/weapons/bladeslice.ogg'
projectilesound = 'sound/weapons/Gunshot.ogg'
projectilesound = 'sound/weapons/gunshots/gunshot.ogg'
projectiletype = /obj/item/projectile/hivebotbullet
faction = list("hivebot")
check_friendly_fire = 1
@@ -80,7 +80,7 @@
smoke.set_up(5, 0, src.loc)
smoke.start()
visible_message("<span class='danger'>The [src] warps in!</span>")
playsound(src.loc, 'sound/effects/EMPulse.ogg', 25, 1)
playsound(src.loc, 'sound/effects/empulse.ogg', 25, 1)
/mob/living/simple_animal/hostile/hivebot/tele/warpbots()
icon_state = "def_radar"
@@ -128,7 +128,7 @@ Difficulty: Medium
/obj/effect/temp_visual/target/proc/fall()
var/turf/T = get_turf(src)
playsound(T,'sound/magic/Fireball.ogg', 200, 1)
playsound(T,'sound/magic/fireball.ogg', 200, 1)
new /obj/effect/temp_visual/fireball(T)
sleep(12)
explosion(T, 0, 0, 1, 0, 0, 0, 1)
@@ -164,7 +164,7 @@ Difficulty: Medium
new /obj/effect/temp_visual/target(turf)
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_walls()
playsound(get_turf(src),'sound/magic/Fireball.ogg', 200, 1)
playsound(get_turf(src),'sound/magic/fireball.ogg', 200, 1)
for(var/d in cardinal)
spawn(0)
@@ -69,7 +69,7 @@ Difficulty: Hard
medal_type = MEDAL_PREFIX
score_type = BIRD_SCORE
del_on_death = TRUE
death_sound = 'sound/magic/Repulse.ogg'
death_sound = 'sound/magic/repulse.ogg'
/mob/living/simple_animal/hostile/megafauna/hierophant/New()
..()
@@ -342,7 +342,7 @@ Difficulty: Hard
new /obj/effect/temp_visual/hierophant/telegraph(T, src)
new /obj/effect/temp_visual/hierophant/telegraph(source, src)
playsound(T,'sound/magic/blink.ogg', 200, 1)
//playsound(T,'sound/magic/Wand_Teleport.ogg', 200, 1)
//playsound(T,'sound/magic/wand_teleport.ogg', 200, 1)
playsound(source,'sound/magic/blink.ogg', 200, 1)
//playsound(source,'sound/machines/AirlockOpen.ogg', 200, 1)
blinking = TRUE
@@ -520,7 +520,7 @@ Difficulty: Hard
var/turf/T = get_turf(src)
if(!T)
return
playsound(T,'sound/magic/Blind.ogg', 125, 1, -5) //make a sound
playsound(T,'sound/magic/blind.ogg', 125, 1, -5) //make a sound
sleep(6) //wait a little
bursting = TRUE
do_damage(T) //do damage and mark us as bursting
@@ -572,7 +572,7 @@ Difficulty: Hard
to_chat(user, "<span class='notice'>You start removing your hierophant rune...</span>")
H.timer = world.time + 51
if(do_after(user, 50, target = src))
playsound(src,'sound/magic/Blind.ogg', 200, 1, -4)
playsound(src,'sound/magic/blind.ogg', 200, 1, -4)
new /obj/effect/temp_visual/hierophant/telegraph/teleport(get_turf(src), user)
to_chat(user, "<span class='hierophant_warning'>You touch the rune with the staff, dispelling it!</span>")
H.rune = null
@@ -34,7 +34,7 @@
icon_state = "pirateranged"
icon_living = "pirateranged"
icon_dead = "piratemelee_dead"
projectilesound = 'sound/weapons/Laser.ogg'
projectilesound = 'sound/weapons/laser.ogg'
ranged = 1
rapid = 1
retreat_distance = 5
@@ -19,6 +19,7 @@
#define TS_DESC_PURPLE "Purple - Guard"
#define TS_DESC_BROWN "Brown - Breacher"
#define TS_DESC_PRINCE "Prince - WAR"
#define TS_DESC_PRINCESS "Princess - HORDE"
#define TS_DESC_MOTHER "Mother - HORROR"
#define TS_DESC_QUEEN "Queen - LEADER"
@@ -7,7 +7,7 @@
/datum/action/innate/terrorspider/web/Activate()
var/mob/living/simple_animal/hostile/poison/terror_spider/user = owner
user.Web(0)
user.Web()
/datum/action/innate/terrorspider/wrap
name = "Wrap"
@@ -30,16 +30,6 @@
var/mob/living/simple_animal/hostile/poison/terror_spider/green/user = owner
user.DoLayGreenEggs()
// ---------- PRINCE ACTIONS
/datum/action/innate/terrorspider/thickweb
name = "Thick Web"
icon_icon = 'icons/effects/effects.dmi'
button_icon_state = "stickyweb2"
/datum/action/innate/terrorspider/thickweb/Activate()
var/mob/living/simple_animal/hostile/poison/terror_spider/user = owner
user.Web(1)
// ---------- BOSS ACTIONS
@@ -52,6 +42,28 @@
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 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
/datum/action/innate/terrorspider/queen/queennest
@@ -103,7 +115,9 @@
// ---------- WEB
/mob/living/simple_animal/hostile/poison/terror_spider/proc/Web(var/thick = 0)
/mob/living/simple_animal/hostile/poison/terror_spider/proc/Web()
if(!web_type)
return
var/turf/mylocation = loc
visible_message("<span class='notice'>[src] begins to secrete a sticky substance.</span>")
if(do_after(src, delay_web, target = loc))
@@ -116,15 +130,8 @@
if(T)
to_chat(src, "<span class='danger'>There is already a web here.</span>")
else
var/obj/structure/spider/terrorweb/W = new /obj/structure/spider/terrorweb(loc)
var/obj/structure/spider/terrorweb/W = new web_type(loc)
W.creator_ckey = ckey
if(thick)
W.opacity = 1
W.name = "thick terror web"
W.health = W.health * 2
if(web_infects)
W.infectious = 1
W.name = "sharp terror web"
/obj/structure/spider/terrorweb
name = "terror web"
@@ -135,7 +142,6 @@
health = 20 // two welders, or one laser shot (15 for the normal spider webs)
icon_state = "stickyweb1"
var/creator_ckey = null
var/infectious = 0
/obj/structure/spider/terrorweb/New()
..()
@@ -164,11 +170,7 @@
DeCloakNearby()
if(iscarbon(mover))
var/mob/living/carbon/C = mover
if(!IsTSInfected(C) && infectious)
var/inject_target = pick("chest","head")
if(C.can_inject(null, 0, inject_target, 0))
to_chat(C, "<span class='danger'>[src] slices into you!</span>")
new /obj/item/organ/internal/body_egg/terror_eggs(C)
web_special_ability(C)
spawn(70)
if(C.loc == loc)
qdel(src)
@@ -186,6 +188,9 @@
return
..()
/obj/structure/spider/terrorweb/proc/web_special_ability(mob/living/carbon/C)
return
// ---------- WRAP
/mob/living/simple_animal/hostile/poison/terror_spider/proc/FindWrapTarget()
@@ -21,7 +21,7 @@
health = 120
melee_damage_lower = 5
melee_damage_upper = 10
move_to_delay = 5
web_type = /obj/structure/spider/terrorweb/black
stat_attack = 1 // ensures they will target people in crit, too!
spider_tier = TS_TIER_2
@@ -43,4 +43,17 @@
step_away(src, L)
LoseTarget()
step_away(src, L)
visible_message("<span class='notice'>[src] jumps away from [L]!</span>")
visible_message("<span class='notice'>[src] jumps away from [L]!</span>")
/obj/structure/spider/terrorweb/black
name = "sinister web"
desc = "This web has beads of a dark fluid on its strands."
/obj/structure/spider/terrorweb/black/web_special_ability(mob/living/carbon/C)
if(istype(C))
if(!C.reagents.has_reagent("terror_black_toxin", 60))
var/inject_target = pick("chest","head")
if(C.can_inject(null, 0, inject_target, 0))
to_chat(C, "<span class='danger'>[src] slices into you!</span>")
C.reagents.add_reagent("terror_black_toxin", 30)
@@ -26,6 +26,7 @@
ai_ventbreaker = 1
freq_ventcrawl_combat = 600 // Ventcrawls very frequently, breaking open vents as it goes.
freq_ventcrawl_idle = 1800
web_type = null
var/datum/action/innate/terrorspider/ventsmash/ventsmash_action
/mob/living/simple_animal/hostile/poison/terror_spider/brown/New()
@@ -16,7 +16,6 @@
health = 1000
melee_damage_lower = 30
melee_damage_upper = 60
move_to_delay = 5
ventcrawler = 1
idle_ventcrawl_chance = 0
ai_playercontrol_allowtype = 0
@@ -43,30 +42,32 @@
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_RED, TS_DESC_GRAY, TS_DESC_GREEN, TS_DESC_BLACK, TS_DESC_PURPLE, TS_DESC_WHITE)
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)
var/numlings = input("How many in the batch?") as null|anything in list(1, 2, 3, 4, 5, 10, 15, 20, 30, 40, 50)
if(eggtype == null || numlings == null)
to_chat(src, "<span class='danger'>Cancelled.</span>")
return
switch(eggtype)
if(TS_DESC_RED)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/red,numlings,1)
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,1)
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,1)
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,1)
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,0)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/purple, numlings)
if(TS_DESC_WHITE)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/white,numlings,0)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/white, numlings)
if(TS_DESC_PRINCE)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/prince,numlings,1)
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)
if(TS_DESC_MOTHER)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/mother,numlings,1)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/mother, numlings)
if(TS_DESC_QUEEN)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/queen,numlings,1)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/queen, numlings)
else
to_chat(src, "<span class='danger'>Unrecognized egg type.</span>")
@@ -81,6 +82,7 @@
/mob/living/simple_animal/hostile/poison/terror_spider/white, \
/mob/living/simple_animal/hostile/poison/terror_spider/black)
S.spider_myqueen = spider_myqueen
S.spider_mymother = src
if(prob(sbpc))
S.stillborn = TRUE
if(spider_growinstantly)
@@ -94,7 +96,7 @@
for(var/obj/structure/spider/eggcluster/terror_eggcluster/T in ts_egg_list)
qdel(T)
for(var/obj/structure/spider/spiderling/terror_spiderling/T in ts_spiderling_list)
T.stillborn = TRUE
qdel(T)
to_chat(src, "<span class='userdanger'>All Terror Spiders, except yourself, will die off shortly.</span>")
@@ -4,7 +4,7 @@
// --------------------------------------------------------------------------------
// -------------: ROLE: ambusher
// -------------: AI: hides in vents, emerges when prey is near to kill it, then hides again. Intended to scare normal crew.
// -------------: SPECIAL: invisible when on top of a vent, emerges when prey approaches or gets trapped in webs. Bite silences targets.
// -------------: SPECIAL: invisible when on top of a vent, emerges when prey approaches or gets trapped in webs.
// -------------: TO FIGHT IT: shoot it through a window, or make it regret ambushing you
// -------------: SPRITES FROM: FoS, http://nanotrasen.se/phpBB3/memberlist.php?mode=viewprofile&u=386
@@ -21,11 +21,11 @@
melee_damage_lower = 10
melee_damage_upper = 20
regen_points_per_hp = 2 // 50% higher regen speed
move_to_delay = 5 // slightly faster than normal
stat_attack = 1 // ensures they will target people in crit, too!
wander = 0 // wandering defeats the purpose of stealth
idle_vision_range = 3 // very low idle vision range
delay_web = 20 // double speed
web_type = /obj/structure/spider/terrorweb/gray
/mob/living/simple_animal/hostile/poison/terror_spider/gray/spider_specialattack(mob/living/carbon/human/L, poisonable)
@@ -137,3 +137,8 @@
if(get_dist(src,temp_vent) > 0 && get_dist(src,temp_vent) < 5)
step_to(src,temp_vent)
// if you're bumped off your vent, try to get back to it
/obj/structure/spider/terrorweb/gray
alpha = 100
name = "transparent web"
desc = "This web is partly transparent, making it harder to see, and easier to get caught by."
@@ -16,10 +16,11 @@
icon_state = "terror_green"
icon_living = "terror_green"
icon_dead = "terror_green_dead"
maxHealth = 120
health = 120
maxHealth = 150
health = 150
melee_damage_lower = 10
melee_damage_upper = 20
web_type = /obj/structure/spider/terrorweb/green
var/feedings_to_lay = 2
var/datum/action/innate/terrorspider/greeneggs/greeneggs_action
@@ -33,54 +34,46 @@
var/obj/structure/spider/eggcluster/E = locate() in get_turf(src)
if(E)
to_chat(src, "<span class='notice'>There is already a cluster of eggs here!</span>")
else if(fed < feedings_to_lay)
return
if(fed < feedings_to_lay)
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)
eggtypes += TS_DESC_BROWN
var/num_black = CountSpidersType(/mob/living/simple_animal/hostile/poison/terror_spider/black)
if(num_black < 2)
eggtypes += TS_DESC_BLACK
var/eggtype = pick(eggtypes)
if(client)
eggtype = input("What kind of eggs?") as null|anything in eggtypes
if(!(eggtype in eggtypes))
to_chat(src, "<span class='danger'>Unrecognized egg type.</span>")
return 0
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)
else if(eggtype == TS_DESC_GRAY)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/gray, 1)
else if(eggtype == TS_DESC_GREEN)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/green, 1)
else if(eggtype == TS_DESC_BLACK)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/black, 1)
else if(eggtype == TS_DESC_BROWN)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/brown, 1)
else
visible_message("<span class='notice'>[src] begins to lay a cluster of eggs.</span>")
if(prob(33))
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/red, 1, 1)
else if(prob(50))
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/gray, 1, 1)
else
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/green, 1, 1)
fed -= feedings_to_lay
to_chat(src, "<span class='warning'>Unrecognized egg type!</span>")
fed += feedings_to_lay
fed -= feedings_to_lay
/mob/living/simple_animal/hostile/poison/terror_spider/green/spider_special_action()
if(cocoon_target)
if(get_dist(src, cocoon_target) <= 1)
spider_steps_taken = 0
DoWrap()
else
if(spider_steps_taken > spider_max_steps)
spider_steps_taken = 0
cocoon_target = null
busy = 0
stop_automated_movement = 0
else
spider_steps_taken++
CreatePath(cocoon_target)
step_to(src,cocoon_target)
if(spider_debug)
visible_message("<span class='notice'>[src] moves towards [cocoon_target] to cocoon it.</span>")
handle_cocoon_target()
else if(fed >= feedings_to_lay)
DoLayGreenEggs()
else if(world.time > (last_cocoon_object + freq_cocoon_object))
last_cocoon_object = world.time
var/list/can_see = view(src, 10)
for(var/mob/living/C in can_see)
if(C.stat == DEAD && !isterrorspider(C) && !C.anchored)
spider_steps_taken = 0
cocoon_target = C
return
for(var/obj/O in can_see)
if(O.anchored)
continue
if(istype(O, /obj/item) || istype(O, /obj/structure) || istype(O, /obj/machinery))
if(!istype(O, /obj/item/paper))
cocoon_target = O
stop_automated_movement = 1
spider_steps_taken = 0
return
seek_cocoon_target()
/mob/living/simple_animal/hostile/poison/terror_spider/green/spider_specialattack(mob/living/carbon/human/L, poisonable)
if(!poisonable)
@@ -94,4 +87,14 @@
visible_message("<span class='danger'>[src] buries its fangs deep into the [inject_target] of [target]!</span>")
else
visible_message("<span class='danger'>[src] bites [target], but cannot inject venom into [target.p_their()] [inject_target]!</span>")
L.attack_animal(src)
L.attack_animal(src)
/obj/structure/spider/terrorweb/green
name = "slimy web"
desc = "This web is partly composed of strands of green slime."
/obj/structure/spider/terrorweb/green/web_special_ability(mob/living/carbon/C)
if(istype(C))
if(C.eye_blurry < 60)
C.AdjustEyeBlurry(30)
@@ -13,18 +13,20 @@
desc = "An enormous spider. Hundreds of tiny spiderlings are crawling all over it. Their beady little eyes all stare at you. The horror!"
spider_role_summary = "Schmuck bait. Extremely weak in combat, but spawns many spiderlings when it dies."
ai_target_method = TS_DAMAGE_SIMPLE
icon_state = "terror_gray2"
icon_living = "terror_gray2"
icon_dead = "terror_gray2_dead"
icon_state = "terror_mother"
icon_living = "terror_mother"
icon_dead = "terror_mother_dead"
maxHealth = 50
health = 50
melee_damage_lower = 10
melee_damage_upper = 20
move_to_delay = 5
idle_ventcrawl_chance = 5
spider_tier = TS_TIER_3
spider_opens_doors = 2
var/canspawn = 1
web_type = null
var/canspawn = TRUE
var/spawn_count = 30
var/spawn_pc_stillborn = 50
var/datum/action/innate/terrorspider/ventsmash/ventsmash_action
/mob/living/simple_animal/hostile/poison/terror_spider/mother/New()
@@ -34,24 +36,20 @@
/mob/living/simple_animal/hostile/poison/terror_spider/mother/death(gibbed)
if(can_die())
var/always_stillborn = FALSE
if(spider_awaymission && !is_away_level(z))
always_stillborn = TRUE
canspawn = FALSE
if(canspawn)
canspawn = 0
for(var/i in 0 to 30)
canspawn = FALSE
for(var/i in 0 to spawn_count)
var/obj/structure/spider/spiderling/terror_spiderling/S = new /obj/structure/spider/spiderling/terror_spiderling(get_turf(src))
S.grow_as = pick(/mob/living/simple_animal/hostile/poison/terror_spider/red, /mob/living/simple_animal/hostile/poison/terror_spider/gray)
if(always_stillborn || prob(66))
if(prob(spawn_pc_stillborn))
S.stillborn = 1
else if(prob(10))
S.grow_as = pick(/mob/living/simple_animal/hostile/poison/terror_spider/black, /mob/living/simple_animal/hostile/poison/terror_spider/green)
S.grow_as = pick(/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)
S.amount_grown = 50 // double speed growth
S.immediate_ventcrawl = 1
visible_message("<span class='userdanger'>[src] breaks apart, the many spiders on its back scurrying everywhere!</span>")
degenerate = 1
return ..()
/mob/living/simple_animal/hostile/poison/terror_spider/mother/Destroy()
canspawn = 0
canspawn = FALSE
return ..()
@@ -21,19 +21,14 @@
regen_points_per_hp = 6 // double the normal - IE halved regen speed
melee_damage_lower = 30
melee_damage_upper = 40
move_to_delay = 4 // faster than normal
ventcrawler = 0
ai_ventcrawls = 0
environment_smash = ENVIRONMENT_SMASH_RWALLS
idle_ventcrawl_chance = 0
spider_tier = TS_TIER_3
spider_opens_doors = 2
var/datum/action/innate/terrorspider/thickweb/thickweb_action
/mob/living/simple_animal/hostile/poison/terror_spider/prince/New()
..()
thickweb_action = new()
thickweb_action.Grant(src)
web_type = /obj/structure/spider/terrorweb/purple
ai_spins_webs = FALSE
/mob/living/simple_animal/hostile/poison/terror_spider/prince/death(gibbed)
if(can_die() && !hasdied && spider_uo71)
@@ -0,0 +1,68 @@
// --------------------------------------------------------------------------------
// ----------------- 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
// -------------: SPRITES FROM: FoS, http://nanotrasen.se/phpBB3/memberlist.php?mode=viewprofile&u=386
/mob/living/simple_animal/hostile/poison/terror_spider/princess
name = "Princess of Terror spider"
desc = "An enormous spider. It looks strangely cute and fluffy."
spider_role_summary = "Future Queen"
ai_target_method = TS_DAMAGE_SIMPLE
icon_state = "terror_princess1"
icon_living = "terror_princess1"
icon_dead = "terror_princess_dead1"
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)
/mob/living/simple_animal/hostile/poison/terror_spider/princess/proc/evolve_to_queen()
change_mob_type(/mob/living/simple_animal/hostile/poison/terror_spider/queen, null, null, 1, 1)
/mob/living/simple_animal/hostile/poison/terror_spider/princess/DoWrap()
. = ..()
if(fed == 0)
icon_state = "terror_princess1"
icon_living = "terror_princess1"
icon_dead = "terror_princess_dead1"
desc = "An enormous spider. It looks strangely cute and fluffy, with soft pink fur covering most of its body."
else if(fed == 1)
icon_state = "terror_princess2"
icon_living = "terror_princess2"
icon_dead = "terror_princess2_dead"
desc = "An enormous spider. It used to look strangely cute and fluffy, but now the effect is spoiled by parts of its fur, which have turned an ominous blood red in color."
else
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."
/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()
@@ -20,22 +20,19 @@
health = 200
melee_damage_lower = 15
melee_damage_upper = 25
move_to_delay = 4
spider_tier = TS_TIER_2
move_to_delay = 5 // at 20ticks/sec, this is 4 tile/sec movespeed, same as a human. Faster than a normal spider, so it can intercept attacks on queen.
speed = 0 // '0' (also the default for human mobs) converts to 2.5 total delay, or 4 tiles/sec.
spider_opens_doors = 2
ventcrawler = 0
ai_ventcrawls = 0
environment_smash = ENVIRONMENT_SMASH_RWALLS
idle_ventcrawl_chance = 0 // stick to the queen!
web_type = /obj/structure/spider/terrorweb/purple
ai_spins_webs = FALSE
var/dcheck_counter = 0
var/queen_visible = 1
var/cycles_noqueen = 0
var/datum/action/innate/terrorspider/thickweb/thickweb_action
/mob/living/simple_animal/hostile/poison/terror_spider/purple/New()
..()
thickweb_action = new()
thickweb_action.Grant(src)
/mob/living/simple_animal/hostile/poison/terror_spider/purple/death(gibbed)
if(can_die() && spider_myqueen)
@@ -44,7 +41,7 @@
if(get_dist(src,Q) > 20)
if(!degenerate && !Q.degenerate)
degenerate = 1
Q.DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/purple,1,0)
Q.DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/purple, 1)
visible_message("<span class='notice'>[src] chitters in the direction of [Q]!</span>")
return ..()
@@ -92,3 +89,9 @@
to_chat(src,"<span class='userdanger'>Your link to your Queen has been broken! Your life force starts to drain away!</span>")
melee_damage_lower = 5
melee_damage_upper = 10
/obj/structure/spider/terrorweb/purple
name = "thick web"
desc = "This web is so thick, most cannot see beyond it."
opacity = 1
health = 40
@@ -21,7 +21,6 @@
regen_points_per_tick = 3
melee_damage_lower = 10
melee_damage_upper = 20
move_to_delay = 15 // yeah, this is very slow, but
ventcrawler = 1
idle_ventcrawl_chance = 0
force_threshold = 18 // outright immune to anything of force under 18, this means welders can't hurt it, only guns can
@@ -32,6 +31,7 @@
projectiletype = /obj/item/projectile/terrorqueenspit
spider_tier = TS_TIER_4
spider_opens_doors = 2
web_type = /obj/structure/spider/terrorweb/queen
var/spider_spawnfrequency = 1200 // 120 seconds
var/spider_spawnfrequency_stable = 1200 // 120 seconds. Spawnfrequency is set to this on ai spiders once nest setup is complete.
var/spider_lastspawn = 0
@@ -156,7 +156,7 @@
if(world.time > (lastnestsetup + nestfrequency))
lastnestsetup = world.time
spider_lastspawn = world.time
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/purple, 2, 0)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/purple, 2)
neststep = 3
if(3)
// Create spiders (random T1 types) until nest is full.
@@ -170,7 +170,7 @@
var/obj/structure/spider/eggcluster/terror_eggcluster/N = locate() in get_turf(src)
if(!N)
spider_lastspawn = world.time
DoLayTerrorEggs(pick(spider_types_standard), 2, 0)
DoLayTerrorEggs(pick(spider_types_standard), 2)
if(4)
// Nest should be full. If so, pulse attack command. Otherwise, start replenishing nest (stage 5).
if(world.time > (spider_lastspawn + spider_spawnfrequency))
@@ -193,13 +193,13 @@
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)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/purple, 2, 0)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/purple, 2)
else if(num_white < 2)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/white, 2, 0)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/white, 2)
else if(num_brown < 2)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/brown, 2, 0)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/brown, 2)
else
DoLayTerrorEggs(pick(spider_types_standard), 2, 0)
DoLayTerrorEggs(pick(spider_types_standard), 2)
/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")
@@ -270,17 +270,17 @@
else
if(eggtype == TS_DESC_MOTHER)
canlay -= 12
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/mother, 1, 0)
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, 0)
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, 0)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/brown, 1)
return
var/numlings = 1
if(eggtype != TS_DESC_PURPLE)
@@ -296,15 +296,15 @@
canlay -= numlings
eggslaid += numlings
if(eggtype == TS_DESC_RED)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/red, numlings, 1)
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, 1)
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, 1)
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, 1)
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, 0)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/purple, numlings)
else
to_chat(src, "<span class='danger'>Unrecognized egg type.</span>")
@@ -323,11 +323,12 @@
return
if(spider_can_fakelings)
spider_can_fakelings--
var/numlings = 15
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
@@ -348,3 +349,14 @@
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."
/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, 0, inject_target, 0))
C.Hallucinate(400)
C.adjustToxLoss(30)
@@ -21,8 +21,10 @@
health = 200
melee_damage_lower = 15
melee_damage_upper = 20
move_to_delay = 20
move_to_delay = 10 // at 20ticks/sec, this is 2 tile/sec movespeed
speed = 2 // movement_delay() gives 4.5, or 0.45s between steps, which = about 2.2 tiles/second. Player is slightly faster than AI, but cannot move on diagonals.
spider_opens_doors = 2
web_type = /obj/structure/spider/terrorweb/red
var/enrage = 0
var/melee_damage_lower_rage0 = 15
var/melee_damage_upper_rage0 = 20
@@ -56,4 +58,10 @@
visible_message("<span class='notice'>[src] retracts its fangs a little.</span>")
melee_damage_lower = melee_damage_lower_rage1
melee_damage_upper = melee_damage_upper_rage1
..()
..()
/obj/structure/spider/terrorweb/red
health = 30
name = "reinforced web"
desc = "This web is reinforced with extra strands, for added strength."
@@ -13,10 +13,14 @@
var/stillborn = FALSE
faction = list("terrorspiders")
var/spider_myqueen = null
var/use_vents = 1
var/spider_mymother = null
var/goto_mother = FALSE
var/ventcrawl_chance = 30 // 30% every process(), assuming 33% wander does not trigger
var/immediate_ventcrawl = TRUE
var/list/enemies = list()
var/immediate_ventcrawl = 0
var/spider_awaymission = FALSE
var/frustration = 0
var/debug_ai_choices = FALSE
/obj/structure/spider/spiderling/terror_spiderling/New()
..()
@@ -35,6 +39,48 @@
qdel(src)
. = ..()
/obj/structure/spider/spiderling/terror_spiderling/die()
for(var/obj/structure/spider/spiderling/terror_spiderling/S in view(7, src))
S.immediate_ventcrawl = TRUE
. = ..()
/obj/structure/spider/spiderling/terror_spiderling/proc/score_surroundings(atom/A = src)
var/safety_score = 0
var/turf/T = get_turf(A)
for(var/mob/living/L in viewers(T))
if(isterrorspider(L))
if(L.stat == DEAD)
safety_score--
else
safety_score++
if(spider_mymother && L == spider_mymother)
safety_score++
else if(L.stat != DEAD)
safety_score--
if(debug_ai_choices)
debug_visual(T, safety_score, A)
return safety_score
/obj/structure/spider/spiderling/terror_spiderling/proc/debug_visual(turf/T, score, atom/A)
// This proc exists to help debug why spiderlings are making the ventcrawl AI choices they do.
// It won't be called unless you set the spiderling's debug_ai_choices to true.
if(debug_ai_choices && istype(T))
if(A == src)
if(score > 0)
new /obj/effect/temp_visual/heart(T) // heart symbol, I am safe here, protected by a friendly spider
else if (score == 0)
new /obj/effect/temp_visual/heal(T) // white "+" symbol, I am neutral here
else
new /obj/effect/temp_visual/at_shield(T) // octagon symbol, I am unsafe here, I need to flee
else
if(score > 0)
new /obj/effect/temp_visual/telekinesis(T) // blue sparks, this is a safe area, I want to go here
else if (score == 0)
new /obj/effect/temp_visual/revenant(T) // purple sparks, this is a neutral area, an acceptable choice
else
new /obj/effect/temp_visual/cult/sparks(T) // red sparks, this is an unsafe area, I won't go here unless fleeing something worse
/obj/structure/spider/spiderling/terror_spiderling/process()
if(travelling_in_vent)
if(isturf(loc))
@@ -42,6 +88,7 @@
entry_vent = null
else if(entry_vent)
if(get_dist(src, entry_vent) <= 1)
frustration = 0
var/list/vents = list()
for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in entry_vent.parent.other_atmosmch)
vents.Add(temp_vent)
@@ -49,8 +96,22 @@
entry_vent = null
return
var/obj/machinery/atmospherics/unary/vent_pump/exit_vent = pick(vents)
if(prob(50))
visible_message("<B>[src] scrambles into the ventillation ducts!</B>", "<span class='notice'>You hear something squeezing through the ventilation ducts.</span>")
if(spider_mymother && (goto_mother || prob(10)))
for(var/obj/machinery/atmospherics/unary/vent_pump/v in view(5, spider_mymother))
if(!v.welded)
exit_vent = v
goto_mother = FALSE
if(!stillborn)
var/current_safety_score = score_surroundings(src)
var/new_safety_score = score_surroundings(exit_vent)
if(new_safety_score < current_safety_score)
// Try to find an alternative.
exit_vent = pick(vents)
new_safety_score = score_surroundings(exit_vent)
if(new_safety_score < current_safety_score)
// No alternative safe vent could be found. Abort.
entry_vent = null
return
var/original_location = loc
spawn(rand(20,60))
forceMove(exit_vent)
@@ -72,14 +133,24 @@
var/area/new_area = get_area(loc)
if(new_area)
new_area.Entered(src)
else
frustration++
walk_to(src, entry_vent, 1)
if(frustration > 2)
entry_vent = null
else if(prob(33))
var/list/nearby = oview(10, src)
if(nearby.len)
var/target_atom = pick(nearby)
if(!istype(get_turf(target_atom),/turf/space))
walk_to(src, target_atom)
else if(immediate_ventcrawl || (prob(10) && use_vents))
immediate_ventcrawl = 0
else if(immediate_ventcrawl || prob(ventcrawl_chance))
immediate_ventcrawl = FALSE
if(!stillborn && !goto_mother)
var/safety_score = score_surroundings(src)
if(safety_score > 0)
// This area seems safe (friendly spiders present). Do not leave this area.
return
for(var/obj/machinery/atmospherics/unary/vent_pump/v in view(7,src))
if(!v.welded)
entry_vent = v
@@ -91,29 +162,33 @@
if(spider_awaymission && !is_away_level(z))
stillborn = TRUE
if(stillborn)
die()
if(amount_grown >= 300)
// Fake spiderlings stick around for awhile, just to be spooky.
die()
else
if(!grow_as)
grow_as = pick(/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)
var/mob/living/simple_animal/hostile/poison/terror_spider/S = new grow_as(loc)
S.faction = faction
S.spider_myqueen = spider_myqueen
S.spider_mymother = spider_mymother
S.master_commander = master_commander
S.enemies = enemies
qdel(src)
// --------------------------------------------------------------------------------
// ----------------- TERROR SPIDERS: EGGS (USED BY NURSE AND QUEEN TYPES) ---------
// --------------------------------------------------------------------------------
/mob/living/simple_animal/hostile/poison/terror_spider/proc/DoLayTerrorEggs(lay_type, lay_number, lay_crawl)
/mob/living/simple_animal/hostile/poison/terror_spider/proc/DoLayTerrorEggs(lay_type, lay_number)
stop_automated_movement = 1
var/obj/structure/spider/eggcluster/terror_eggcluster/C = new /obj/structure/spider/eggcluster/terror_eggcluster(get_turf(src))
C.spiderling_type = lay_type
C.spiderling_number = lay_number
C.spiderling_ventcrawl = lay_crawl
C.faction = faction
C.spider_myqueen = spider_myqueen
C.spider_mymother = src
C.master_commander = master_commander
C.enemies = enemies
if(spider_growinstantly)
@@ -129,9 +204,9 @@
var/spider_growinstantly = 0
faction = list("terrorspiders")
var/spider_myqueen = null
var/spider_mymother = null
var/spiderling_type = null
var/spiderling_number = 1
var/spiderling_ventcrawl = 1
var/list/enemies = list()
/obj/structure/spider/eggcluster/terror_eggcluster/New()
@@ -169,16 +244,11 @@
var/obj/structure/spider/spiderling/terror_spiderling/S = new /obj/structure/spider/spiderling/terror_spiderling(get_turf(src))
if(spiderling_type)
S.grow_as = spiderling_type
S.use_vents = spiderling_ventcrawl
S.faction = faction
S.spider_myqueen = spider_myqueen
S.spider_mymother = spider_mymother
S.master_commander = master_commander
S.enemies = enemies
if(spider_growinstantly)
S.amount_grown = 250
var/rnum = 5 - spiderling_number
for(var/i=0, i<rnum, i++)
var/obj/structure/spider/spiderling/terror_spiderling/S = new /obj/structure/spider/spiderling/terror_spiderling(get_turf(src))
S.stillborn = TRUE
// every set of eggs always spawn 5 spiderlings, but most are decoys
qdel(src)
@@ -134,14 +134,11 @@
L.do_attack_animation(src)
visible_message("<span class='danger'>[src] smashes the [L.name].</span>")
break
else if(ai_spins_webs && world.time > (last_spins_webs + freq_spins_webs))
else if(web_type && ai_spins_webs && world.time > (last_spins_webs + freq_spins_webs))
last_spins_webs = world.time
var/obj/structure/spider/terrorweb/T = locate() in get_turf(src)
if(!T)
var/obj/structure/spider/terrorweb/W = new /obj/structure/spider/terrorweb(loc)
if(web_infects)
W.infectious = 1
W.name = "sharp terror web"
new web_type(loc)
visible_message("<span class='notice'>[src] puts up some spider webs.</span>")
else if(ai_ventcrawls && world.time > (last_ventcrawl_time + my_ventcrawl_freq))
if(prob(idle_ventcrawl_chance))
@@ -202,6 +199,42 @@
H.enemies |= enemies
return 0
/mob/living/simple_animal/hostile/poison/terror_spider/proc/handle_cocoon_target()
if(cocoon_target)
if(get_dist(src, cocoon_target) <= 1)
spider_steps_taken = 0
DoWrap()
else
if(spider_steps_taken > spider_max_steps)
spider_steps_taken = 0
cocoon_target = null
busy = 0
stop_automated_movement = 0
else
spider_steps_taken++
CreatePath(cocoon_target)
step_to(src,cocoon_target)
if(spider_debug)
visible_message("<span class='notice'>[src] moves towards [cocoon_target] to cocoon it.</span>")
/mob/living/simple_animal/hostile/poison/terror_spider/proc/seek_cocoon_target()
last_cocoon_object = world.time
var/list/can_see = view(src, 10)
for(var/mob/living/C in can_see)
if(C.stat == DEAD && !isterrorspider(C) && !C.anchored)
spider_steps_taken = 0
cocoon_target = C
return
for(var/obj/O in can_see)
if(O.anchored)
continue
if(istype(O, /obj/item) || istype(O, /obj/structure) || istype(O, /obj/machinery))
if(!istype(O, /obj/item/paper))
cocoon_target = O
stop_automated_movement = 1
spider_steps_taken = 0
return
// --------------------------------------------------------------------------------
// --------------------- TERROR SPIDERS: PATHING CODE -----------------------------
// --------------------------------------------------------------------------------
@@ -34,13 +34,25 @@ var/global/list/ts_spiderling_list = list()
attacktext = "bites"
attack_sound = 'sound/weapons/bite.ogg'
poison_type = "" // we do not use that silly system.
a_intent = INTENT_HARM
// Movement
pass_flags = PASSTABLE
turns_per_move = 5 // number of turns before AI-controlled spiders wander around. No effect on actual player or AI movement speed!
move_to_delay = 6
turns_per_move = 5
// AI spider speed at chasing down targets. Higher numbers mean slower speed. Divide 20 (server tick rate / second) by this to get tiles/sec.
// 5 = 4 tiles/sec, 6 = 3.3 tiles/sec. 3 = 6.6 tiles/sec.
// Player spider movement speed is controlled by the 'speed' var.
// Higher numbers mean slower speed. Can be negative for major speed increase. Call movement_delay() on mob to convert this var to into a step delay.
// '-1' (default for fast humans) converts to 1.5 or 6.6 tiles/sec
// '0' (default for human mobs) converts to 2.5, or 4 tiles/sec.
// '1' (default for most simple_mobs, including terror spiders) converts to 3.5, or 2.8 tiles/sec.
// '2' converts to 4.5, or 2.2 tiles/sec.
// Atmos
pressure_resistance = 50 //50 kPa difference required to push
throw_pressure_limit = 100 //100 kPa difference required to throw
pass_flags = PASSTABLE
// Ventcrawling
ventcrawler = 1 // allows player ventcrawling
@@ -131,11 +143,13 @@ var/global/list/ts_spiderling_list = list()
var/attackstep = 0
var/attackcycles = 0
var/spider_myqueen = null
var/spider_mymother = null
var/mylocation = null
var/chasecycles = 0
var/web_infects = 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)
@@ -243,8 +257,9 @@ var/global/list/ts_spiderling_list = list()
add_language("Galactic Common")
default_language = GLOB.all_languages["Spider Hivemind"]
web_action = new()
web_action.Grant(src)
if(web_type)
web_action = new()
web_action.Grant(src)
wrap_action = new()
wrap_action.Grant(src)
@@ -264,9 +279,9 @@ var/global/list/ts_spiderling_list = list()
spider_placed = 1
else
ts_count_alive_station++
// after 30 seconds, assuming nobody took control of it yet, offer it to ghosts.
addtimer(CALLBACK(src, .proc/CheckFaction), 150)
addtimer(CALLBACK(src, .proc/announcetoghosts), 300)
// after 3 seconds, assuming nobody took control of it yet, offer it to ghosts.
addtimer(CALLBACK(src, .proc/CheckFaction), 20)
addtimer(CALLBACK(src, .proc/announcetoghosts), 30)
var/datum/atom_hud/U = huds[DATA_HUD_MEDICAL_ADVANCED]
U.add_hud_to(src)
@@ -349,9 +364,9 @@ var/global/list/ts_spiderling_list = list()
/mob/living/simple_animal/hostile/poison/terror_spider/proc/CheckFaction()
if(faction.len != 1 || (!("terrorspiders" in faction)) || master_commander != null)
visible_message("<span class='danger'>[src] writhes in pain!</span>")
log_runtime(EXCEPTION("Terror spider created with incorrect faction list at: [atom_loc_line(src)]"))
death()
to_chat(src, "<span class='userdanger'>Your connection to the hive mind has been severed!</span>")
log_runtime(EXCEPTION("Terror spider with incorrect faction list at: [atom_loc_line(src)]"))
gib()
/mob/living/simple_animal/hostile/poison/terror_spider/proc/try_open_airlock(obj/machinery/door/airlock/D)
if(D.operating)
@@ -19,9 +19,8 @@
health = 200
melee_damage_lower = 5
melee_damage_upper = 15
move_to_delay = 4
spider_tier = TS_TIER_2
web_infects = 1
web_type = /obj/structure/spider/terrorweb/white
/mob/living/simple_animal/hostile/poison/terror_spider/white/LoseTarget()
@@ -57,3 +56,16 @@
if(C.get_int_organ(/obj/item/organ/internal/body_egg))
return 1
return 0
/obj/structure/spider/terrorweb/white
name = "infested web"
desc = "This web is covered in hundreds of tiny, biting spiders - and their eggs."
/obj/structure/spider/terrorweb/white/web_special_ability(mob/living/carbon/C)
if(istype(C))
if(!IsTSInfected(C))
var/inject_target = pick("chest","head")
if(C.can_inject(null, 0, inject_target, 0))
to_chat(C, "<span class='danger'>[src] slices into you!</span>")
new /obj/item/organ/internal/body_egg/terror_eggs(C)
@@ -76,6 +76,7 @@
var/sentience_type = SENTIENCE_ORGANIC // Sentience type, for slime potions
var/list/loot = list() //list of things spawned at mob's loc when it dies
var/del_on_death = 0 //causes mob to be deleted on death, useful for mobs that spawn lootable corpses
var/attacked_sound = "punch"
var/deathmessage = ""
var/death_sound = null //The sound played on death
@@ -176,7 +176,7 @@ var/global/totaltribbles = 0 //global variable so it updates for all tribbles,
playsound(src, "shatter", 70, 1)
Break()
else
playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1)
playsound(src.loc, 'sound/effects/glasshit.ogg', 75, 1)
return
/obj/structure/tribble_cage/update_icon()
+1
View File
@@ -3,6 +3,7 @@
layer = 4.0
animate_movement = 2
pressure_resistance = 8
dont_save = TRUE //to avoid it messing up in buildmode saving
var/datum/mind/mind
var/stat = 0 //Whether a mob is alive or dead. TODO: Move this to living - Nodrak
+1
View File
@@ -536,6 +536,7 @@ var/list/intents = list(INTENT_HELP,INTENT_DISARM,INTENT_GRAB,INTENT_HARM)
if(ID.registered_name == oldname)
ID.registered_name = newname
ID.name = "[newname]'s ID Card ([ID.assignment])"
ID.RebuildHTML()
if(!search_pda) break
search_id = 0