mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-21 20:13:45 +01:00
Merge branch 'master' into robotic_arms_bots
This commit is contained in:
@@ -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>"
|
||||
|
||||
|
||||
@@ -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"
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user