Changeling Morph (#10010)

This commit is contained in:
Geeves
2020-09-23 12:16:30 +02:00
committed by GitHub
parent df857171d0
commit ded43af1d7
11 changed files with 327 additions and 57 deletions
@@ -205,6 +205,10 @@ mob/living/simple_animal/hostile/hitby(atom/movable/AM as mob|obj,var/speed = TH
/mob/living/simple_animal/hostile/think()
..()
if(stop_thinking)
return
switch(stance)
if(HOSTILE_STANCE_IDLE)
targets = ListTargets(10)
@@ -0,0 +1,205 @@
#define MORPH_COOLDOWN 50
/mob/living/simple_animal/hostile/morph
name = "morph"
desc = "A revolting, pulsating pile of flesh."
speak_emote = list("gurgles")
emote_hear = list("gurgles")
icon = 'icons/mob/npc/animal.dmi'
icon_state = "morph"
icon_living = "morph"
icon_dead = "morph_dead"
speed = 2.5
stop_automated_movement = TRUE
response_help = "pets"
response_disarm = "shoves"
response_harm = "harmlessly punches"
mob_size = 15
universal_speak = TRUE
universal_understand = TRUE
tameable = FALSE
status_flags = CANPUSH
pass_flags = PASSTABLE
maxHealth = 125
health = 125
melee_damage_lower = 12
melee_damage_upper = 16
see_in_dark = 8
see_invisible = SEE_INVISIBLE_NOLIGHTING
minbodytemp = 0
maxbodytemp = 350
min_oxy = 0
max_co2 = 0
max_tox = 0
wander = FALSE
attacktext = "glomped"
attack_sound = 'sound/effects/blobattack.ogg'
var/morphed = FALSE
var/melee_damage_disguised = 0
var/eat_while_disguised = FALSE
var/atom/movable/form = null
var/morph_time = 0
var/static/list/blacklist_typecache = typecacheof(list(/obj/screen, /obj/singularity, /mob/living/simple_animal/hostile/morph, /obj/effect))
/mob/living/simple_animal/hostile/morph/Initialize()
. = ..()
verbs += /mob/living/proc/ventcrawl
/mob/living/simple_animal/hostile/morph/examine(mob/user)
if(morphed)
. = form.examine(user)
if(get_dist(src, user) > 2)
return
to_chat(user, SPAN_WARNING("It doesn't look quite right..."))
else
return ..()
/mob/living/simple_animal/hostile/morph/proc/allowed(atom/movable/A)
return !is_type_in_typecache(A, blacklist_typecache) && (isobj(A) || ismob(A))
/mob/living/simple_animal/hostile/morph/proc/eat(var/atom/movable/A, var/delay = 20)
if(morphed && !eat_while_disguised)
to_chat(src, SPAN_WARNING("You can't eat anything while you are disguised!"))
return FALSE
if(A?.loc == src)
return FALSE
visible_message(SPAN_WARNING("\The [src] begins swallowing \the [A] whole!"), SPAN_NOTICE("You begin swallowing \the [A] whole."))
if(do_after(src, delay, act_target = A))
visible_message(SPAN_WARNING("\The [src] swallows \the [A] whole!"), SPAN_NOTICE("You swallow \the [A] whole."))
A.forceMove(src)
return TRUE
/mob/living/simple_animal/hostile/morph/AltClickOn(atom/movable/A)
if(morph_time <= world.time && !stat)
if(A == src)
restore()
else if(istype(A) && allowed(A))
assume(A)
else
to_chat(src, SPAN_WARNING("Your chameleon skin is still repairing itself!"))
/mob/living/simple_animal/hostile/morph/proc/assume(atom/movable/target)
if(morphed)
to_chat(src, SPAN_WARNING("You must restore to your original form first!"))
return
morphed = TRUE
form = target
visible_message(SPAN_WARNING("\The [src] suddenly twists and changes shape, becoming a copy of \the [target]!"), SPAN_NOTICE("You twist your body and assume the form of \the [target]."))
appearance = target.appearance
alpha = max(alpha, 150) //fucking chameleons
transform = initial(transform)
pixel_y = initial(pixel_y)
pixel_x = initial(pixel_x)
//Morphed is weaker
melee_damage_lower = melee_damage_disguised
melee_damage_upper = melee_damage_disguised
speed = 1
mob_size = MOB_MINISCULE
morph_time = world.time + MORPH_COOLDOWN
return
/mob/living/simple_animal/hostile/morph/proc/restore()
if(!morphed)
to_chat(src, SPAN_WARNING("You're already in your normal form!"))
return
morphed = FALSE
form = null
alpha = initial(alpha)
color = initial(color)
desc = initial(desc)
animate_movement = SLIDE_STEPS
maptext = null
visible_message(SPAN_WARNING("\The [src] suddenly collapses in on itself, dissolving into a pile of green flesh!"), SPAN_NOTICE("You reform to your normal body."))
name = initial(name)
icon = initial(icon)
icon_state = initial(icon_state)
cut_overlays()
overlays = null
//Baseline stats
melee_damage_lower = initial(melee_damage_lower)
melee_damage_upper = initial(melee_damage_upper)
speed = 2.5
mob_size = 15
morph_time = world.time + MORPH_COOLDOWN
/mob/living/simple_animal/hostile/morph/death(gibbed)
if(morphed)
visible_message(SPAN_WARNING("\The [src] twists and dissolves into a pile of green flesh!"), SPAN_DANGER("Your skin ruptures! Your flesh breaks apart! No disguise can ward off de--"))
restore()
barf_contents()
..()
/mob/living/simple_animal/hostile/morph/proc/barf_contents()
for(var/atom/movable/AM in src)
AM.forceMove(loc)
if(prob(90))
step(AM, pick(global.alldirs))
/mob/living/simple_animal/hostile/morph/UnarmedAttack(atom/A, proximity)
if(morphed && !melee_damage_disguised)
to_chat(src, SPAN_WARNING("You can't attack while disguised!"))
return
if(isliving(A)) //Eat Corpses to regen health
var/mob/living/L = A
if(L.stat == DEAD)
if(eat(L, 30))
adjustBruteLoss(-50)
return
else if(istype(A, /obj/item)) //Eat items just to be annoying
var/obj/item/I = A
if(!I.anchored)
eat(I, 20)
return
return ..()
/mob/living/simple_animal/hostile/bullet_act(obj/item/projectile/P, def_zone)
..()
if (ismob(P.firer) && target_mob != P.firer)
target_mob = P.firer
stance = HOSTILE_STANCE_ATTACK
/mob/living/simple_animal/hostile/morph/attackby(obj/item/O, mob/user)
..()
if(morphed && user != src)
restore()
/mob/living/simple_animal/hostile/morph/hitby(atom/movable/AM, speed)
..()
if(morphed)
restore()
/mob/living/simple_animal/hostile/morph/attack_generic(mob/user, damage, attack_message)
..()
if(morphed)
restore()
/mob/living/simple_animal/hostile/morph/attack_hand(mob/living/carbon/human/M)
..()
if(morphed && M != src)
restore()
/mob/living/simple_animal/hostile/morph/start_ventcrawl()
if(morphed)
to_chat(src, SPAN_WARNING("You can't ventcrawl while disguised!"))
return
return ..()
/mob/living/simple_animal/hostile/morph/do_animate_chat(var/message, var/datum/language/language, var/small, var/list/show_to, var/duration, var/list/message_override)
INVOKE_ASYNC(src, /atom/movable/proc/animate_chat, message, language, small, show_to, duration)
@@ -27,6 +27,7 @@
universal_speak = 0 //No, just no.
var/meat_amount = 0
var/meat_type
var/stop_thinking = FALSE // prevents them from doing any AI stuff whatsoever
var/stop_automated_movement = 0 //Use this to temporarely stop random movement or to if you write special movement code for animals.
var/wander = 1 // Does the mob wander around when idle?
var/stop_automated_movement_when_pulled = 1 //When set to 1 this stops the animal from moving when someone is pulling it.
@@ -239,6 +240,10 @@
/mob/living/simple_animal/think()
..()
if(stop_thinking)
return
if(!stop_automated_movement && wander && !anchored)
if(isturf(loc) && !resting && !buckled && canmove) //This is so it only moves if it's not inside a closet, gentics machine, etc.
if(turns_since_move >= turns_per_move && !(stop_automated_movement_when_pulled && pulledby)) //Some animals don't move when pulled
+6 -3
View File
@@ -58,9 +58,12 @@ var/global/list/can_enter_vent_with = list(
/mob/living/proc/ventcrawl_carry()
for(var/atom/A in src.contents)
if(!is_allowed_vent_crawl_item(A))
to_chat(src, "<span class='warning'>You can't be carrying that when vent crawling!</span>")
return 0
return 1
to_chat(src, SPAN_WARNING("You can't be carrying that when vent crawling!"))
return FALSE
return TRUE
/mob/living/simple_animal/hostile/morph/ventcrawl_carry()
return TRUE
/obj/machinery/atmospherics/AltClick(mob/living/user)
if(is_type_in_list(src, ventcrawl_machinery) && user.can_ventcrawl())