Files
GS13NG/hyperstation/code/mobs/mimic.dm
2024-09-13 01:50:58 -04:00

415 lines
14 KiB
Plaintext

/mob/living/simple_animal/hostile/hs13mimic
name = "Mimic"
icon = 'hyperstation/icons/mobs/mimic.dmi'
desc = "A writhing mass of black flesh, unlikely to be happy to see you."
icon_state = "mimic"
icon_living = "mimic"
icon_dead = "mimic_dead"
gender = NEUTER
speak_chance = 0
maxHealth = 35
health = 35
turns_per_move = 5
move_to_delay = 1
speed = 0
see_in_dark = 8
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
pass_flags = PASSTABLE
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/xeno = 2)
response_help = "prods"
response_disarm = "pushes aside"
response_harm = "smacks"
melee_damage_lower = 8
melee_damage_upper = 12
attacktext = "stings"
attack_sound = 'hyperstation/sound/creatures/mimic/mimic_attack.ogg'
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
ventcrawler = VENTCRAWLER_ALWAYS
blood_volume = 0
faction = list("mimic")
gold_core_spawnable = NO_SPAWN
vision_range = 1
aggro_vision_range = 9
wander = TRUE
minbodytemp = 250 //weak to cold
maxbodytemp = 1500
pressure_resistance = 1200
sight = SEE_MOBS
var/stealthed = TRUE
var/knockdown_people = 1
var/playerTransformCD = 50
var/playerTfTime
var/static/mimic_blacklisted_transform_items = typecacheof(list(
/obj/item/projectile,
/obj/item/radio/intercom,
/mob/living/simple_animal/bot))
var/transformsound = 'hyperstation/sound/creatures/mimic/mimic_transform.ogg'
var/playstyle_string = "<span class='boldannounce'>You are a mimic</span></b>, a tricky creature that can take the form of \
almost any item nearby by shift-clicking it. While morphed, you move slowly and do less damage. \
Finally, you can restore yourself to your original form while morphed by shift-clicking yourself. \
Attacking carbon lifeforms will heal you at the cost of destructuring their DNA. \
You can also change your form to that of simple animals, but be wary that anyone examining you can \
find out.</b>"
/mob/living/simple_animal/hostile/hs13mimic/Initialize(mapload)
. = ..()
trytftorandomobject() // When initialized, make sure they take the form of something.
/mob/living/simple_animal/hostile/hs13mimic/Login()
. = ..()
SEND_SOUND(src, sound('sound/ambience/antag/ling_aler.ogg'))
to_chat(src, src.playstyle_string)
/mob/living/simple_animal/hostile/hs13mimic/attack_hand(mob/living/carbon/human/M)
. = ..()
if(stealthed && stat == CONSCIOUS)
if(M.a_intent == INTENT_HELP)//They're trying to pick us up! We tricked them boys! *plays runescape sea shanty*
target = M
guaranteedknockdown(M)
trigger() // Bring our friends if any!
/mob/living/simple_animal/hostile/hs13mimic/AttackingTarget()
. = ..()
if(iscarbon(target))
var/mob/living/carbon/C = target
if(.)
if(stealthed && knockdown_people) //Guaranteed knockdown if we get the first hit while disguised. Typically, only players can do this since NPC mimics transform first before attacking.
restore()
C.Knockdown(40)
C.visible_message("<span class='danger'>\The [src] knocks down \the [C]!</span>", \
"<span class='userdanger'>\The [src] knocks you down!</span>")
else if(knockdown_people && prob(15))
C.Knockdown(40)
C.visible_message("<span class='danger'>\The [src] knocks down \the [C]!</span>", \
"<span class='userdanger'>\The [src] knocks you down!</span>")
if(C.nutrition >= 15)
C.nutrition -= (rand(7,15)) //They lose 7-15 nutrition
adjustBruteLoss(-3) //We heal 3 damage
C.adjustCloneLoss(rand(2,4)) //They also take a bit of cellular damage.
if(isanimal(target))
var/mob/living/simple_animal/A = target
if(.)
if(stealthed)
restore()
if(A.stat == CONSCIOUS)
adjustBruteLoss(-3) //We heal 3 damage
/mob/living/simple_animal/hostile/hs13mimic/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
trigger()
. = ..()
/mob/living/simple_animal/hostile/hs13mimic/FindTarget()
. = ..()
if(.)
trigger() //We have a target! Trigger!
else if(!target && !stealthed) //Has no target, isn't stealthed, let's search for an object to transform
trytftorandomobject()
/mob/living/simple_animal/hostile/hs13mimic/death(gibbed)
restore() //We died. Restore form.
. = ..()
/mob/living/simple_animal/hostile/hs13mimic/med_hud_set_health()
if(stealthed)
var/image/holder = hud_list[HEALTH_HUD]
holder.icon_state = null
return //we hide medical hud while morphed
..()
/mob/living/simple_animal/hostile/hs13mimic/med_hud_set_status()
if(stealthed)
var/image/holder = hud_list[STATUS_HUD]
holder.icon_state = null
return //we hide medical hud while morphed
..()
/mob/living/simple_animal/hostile/hs13mimic/proc/mimicTransformList() //The list of default things to transform needs to be bigger, consider this in the future.
var/transformitem = rand(1,100)
medhudupdate()
wander = FALSE
vision_range = initial(vision_range)
switch(transformitem)
if(1 to 10)
name = "drinking glass"
icon = 'icons/obj/drinks.dmi'
icon_state = "glass_empty"
desc = "Your standard drinking glass."
if(11 to 20)
name = "insulated gloves"
icon = 'icons/obj/clothing/gloves.dmi'
icon_state = "yellow"
desc = "These gloves will protect the wearer from electric shock."
if(21 to 30)
name = "stunbaton"
desc = "A stun baton for incapacitating people with."
icon = 'icons/obj/items_and_weapons.dmi'
icon_state = "stunbaton"
if(31 to 40)
name = "pen"
icon = 'icons/obj/bureaucracy.dmi'
icon_state = "pen"
desc = "It's a black ink pen, modified for use with both paper and Nanotransen-brand Digital-Readpads™!"
if(41 to 50)
name = "newspaper"
desc = "An issue of The Catpaw, the newspaper circulating aboard GATO stations."
icon = 'icons/obj/bureaucracy.dmi'
icon_state = "newspaper"
if(51 to 60)
name = "stechkin pistol" //greytider bait
desc = "A small, easily concealable 10mm handgun. Has a threaded barrel for suppressors."
icon = 'icons/obj/guns/projectile.dmi'
icon_state = "pistol"
if(61 to 70)
name = "emergency oxygen tank"
desc = "Used for emergencies. Contains very little oxygen, so try to conserve it until you actually need it."
icon = 'icons/obj/tank.dmi'
icon_state = "emergency"
if(71 to 80)
name = "drinking glass"
icon = 'icons/obj/drinks.dmi'
icon_state = "glass_empty"
desc = "Your standard drinking glass."
if(81 to 90)
name = "fleshlight"
icon = 'hyperstation/icons/obj/fleshlight.dmi'
icon_state = "fleshlight_totallynotamimic"
desc = "A sex toy disguised as a flashlight, used to stimulate someones penis, complete with colour changing sleeve."
if(91 to 100)
icon = 'modular_citadel/icons/obj/genitals/dildo.dmi'
switch(rand(1,3)) //switch within a switch hmmmmmmmmmm
if(1)
icon_state = "dildo_knotted_2"
name = "small knotted dildo"
if(2)
icon_state = "dildo_flared_4"
name = "huge flared dildo"
if(3)
icon_state = "dildo_knotted_3"
name = "big knotted dildo"
desc = "Floppy!"
/mob/living/simple_animal/hostile/hs13mimic/proc/guaranteedknockdown(mob/living/carbon/human/M)
M.Knockdown(40)
M.visible_message("<span class='danger'>\The [src] knocks down \the [M]!</span>", \
"<span class='userdanger'>\The [src] tricks you, knocking you down!</span>")
/mob/living/simple_animal/hostile/hs13mimic/proc/medhudupdate()
med_hud_set_health()
med_hud_set_status()
/mob/living/simple_animal/hostile/hs13mimic/proc/restore()
//back to normal mimic sprite
stealthed = FALSE
medhudupdate()
name = initial(name)
icon = 'hyperstation/icons/mobs/mimic.dmi'
icon_state = "mimic"
desc = initial(desc)
speed = initial(speed)
wander = TRUE
vision_range = 9
/mob/living/simple_animal/hostile/hs13mimic/proc/trigger()
if(stealthed && stat == CONSCIOUS)
visible_message("<span class='danger'>The [src] Reveals itself to be a Mimic!</span>")
restore()
playsound(loc, transformsound, 75, TRUE)
triggerOthers(target) // Friends too!
/mob/living/simple_animal/hostile/hs13mimic/proc/triggerOthers(passtarget) //
for(var/mob/living/simple_animal/hostile/hs13mimic/C in oview(5, src.loc))
if(passtarget && C.target == null && !(isdead(target)))
C.target = passtarget
C.trigger()
/mob/living/simple_animal/hostile/hs13mimic/proc/trytftorandomobject()
stealthed = TRUE
medhudupdate()
var/list/obj/item/listItems = list()
for(var/obj/item/I in oview(9,src.loc))
if(allowed(I))
listItems += I
if(LAZYLEN(listItems))
var/obj/item/changedReference = pick(listItems)
wander = FALSE
vision_range = initial(vision_range)
name = changedReference.name
icon = changedReference.icon
icon_state = changedReference.icon_state
desc = changedReference.desc
else
mimicTransformList() //Couldn't find any valid items, let's go for the default list then.
/mob/living/simple_animal/hostile/hs13mimic/proc/allowed(atom/movable/A)
return !is_type_in_typecache(A, mimic_blacklisted_transform_items) && (isitem(A) || isanimal(A))
//One leader mimic spawns per mimic event spawn, they are able to consume and transform themselves into the station's dead pets. Buckle up.
/mob/living/simple_animal/hostile/hs13mimic/leader
var/mob/living/consumptionTarget = null
var/consuming = FALSE
health = 38 //They have a teeeny tiny more health.
maxHealth = 38
/mob/living/simple_animal/hostile/hs13mimic/leader/Life()
. = ..()
if(!consuming)
if(!consumptionTarget)
for(var/mob/living/simple_animal/pet/A in oview(5, src))
if(A.stat == DEAD)
consumptionTarget = A
break
if(!target && consumptionTarget) //Don't try to consume anything if we're currently attacking something.
var/target_distance = get_dist(targets_from, consumptionTarget)
if(target_distance > minimum_distance)
Goto(consumptionTarget,move_to_delay,minimum_distance)
else
tryConsume(consumptionTarget)
/mob/living/simple_animal/hostile/hs13mimic/leader/proc/tryConsume(var/mob/living/simple_animal/pet/A)
src.visible_message("<span class='warning'>[A] is being consumed...</span>",
"<span class='notice'>You start to consume the dead [A]...</span>", "You hear strange fleshy sounds.")
consuming = TRUE
if(do_after(src, 100, target = A))
stealthed = TRUE
speed = 5
wander = TRUE
name = A.name
desc = A.desc
icon = A.icon
icon_state = A.icon_living
desc += "<span class='warning'> But something about it seems wrong...</span>"
qdel(A)
consuming = FALSE
consumptionTarget = FALSE
return TRUE
consuming = FALSE
return FALSE
//Player control code
/mob/living/simple_animal/hostile/hs13mimic/ShiftClickOn(atom/movable/A)
if(playerTfTime <= world.time && stat == CONSCIOUS)
if(A == src)
restore()
playerTfTime = world.time + playerTransformCD
return
if(istype(A) && allowed(A))
stealthed = TRUE
SEND_SOUND(src, sound(transformsound,volume=50))
name = A.name
icon = A.icon
icon_state = A.icon_state
desc = A.desc
speed = 5
playerTfTime = world.time + playerTransformCD
if(isanimal(A))
var/mob/living/simple_animal/animal = A
icon_state = animal.icon_living
desc += "<span class='warning'> But something about it seems wrong...</span>"
else
to_chat(src, "<span class='warning'>You need to wait a little longer before you can shift into something else!</span>")
..()
//Event control
/datum/round_event_control/mimic_infestation
name = "Mimic Infestation"
typepath = /datum/round_event/mimic_infestation
weight = 5
max_occurrences = 1
min_players = 15
/datum/round_event/mimic_infestation
announceWhen = 200
var/static/list/mimic_station_areas_blacklist = typecacheof(/area/space,
/area/shuttle,
/area/mine,
/area/holodeck,
/area/ruin,
/area/hallway,
/area/hallway/primary,
/area/hallway/secondary,
/area/hallway/secondary/entry,
/area/engine/supermatter,
/area/engine/atmospherics_engine,
/area/engine/engineering/reactor_core,
/area/engine/engineering/reactor_control,
/area/ai_monitored/turret_protected,
/area/layenia/cloudlayer,
/area/asteroid/nearstation,
/area/science/server,
/area/science/explab,
/area/science/xenobiology,
/area/security/processing)
var/spawncount = 1
fakeable = FALSE
/datum/round_event/mimic_infestation/setup()
announceWhen = rand(announceWhen, announceWhen + 50)
spawncount = rand(4, 7)
/datum/round_event/mimic_infestation/announce(fake)
priority_announce("Unidentified lifesigns detected aboard [station_name()]. Secure any exterior access, including ducting and ventilation.", "Lifesign Alert", 'sound/ai/aliens.ogg')
/datum/round_event/mimic_infestation/start()
var/list/area/stationAreas = list()
var/list/area/eligible_areas = list()
for(var/area/A in world) // Get the areas in the Z level
if(A.z == SSmapping.station_start)
stationAreas += A
for(var/area/place in stationAreas) // first we check if it's a valid area
if(place.outdoors)
continue
if(place.areasize < 16)
continue
if(is_type_in_typecache(place, mimic_station_areas_blacklist))
continue
eligible_areas += place
for(var/area/place in eligible_areas) // now we check if there are people in that area
var/numOfPeople
for(var/mob/living/carbon/H in place)
numOfPeople++
break
if(numOfPeople > 0)
eligible_areas -= place
var/validFound = FALSE
var/list/turf/validTurfs = list()
var/area/pickedArea
while(!validFound || !eligible_areas.len)
pickedArea = pick_n_take(eligible_areas)
var/list/turf/t = get_area_turfs(pickedArea, SSmapping.station_start)
for(var/turf/thisTurf in t) // now we check if it's a closed turf, cold turf or occupied turf and yeet it
if(isopenturf(thisTurf))
var/turf/open/tempGet = thisTurf
if(tempGet.air.temperature <= T0C)
t -= thisTurf
continue
if(isclosedturf(thisTurf))
t -= thisTurf
else
for(var/obj/O in thisTurf)
if(O.density && !(istype(O, /obj/structure/table)))
t -= thisTurf
break
if(t.len >= spawncount) //Is the number of available turfs equal or bigger than spawncount?
validFound = TRUE
validTurfs = t
if(!eligible_areas.len)
message_admins("No eligible areas for spawning mimics.")
return WAITING_FOR_SOMETHING
notify_ghosts("A group of mimics has spawned in [pickedArea]!", source=pickedArea, action=NOTIFY_ATTACK, flashwindow = FALSE)
while(spawncount > 0 && validTurfs.len)
spawncount--
var/turf/pickedTurf = pick_n_take(validTurfs)
if(spawncount != 0)
var/spawn_type = /mob/living/simple_animal/hostile/hs13mimic
spawn_atom_to_turf(spawn_type, pickedTurf, 1, FALSE)
else
var/spawn_type = /mob/living/simple_animal/hostile/hs13mimic/leader
spawn_atom_to_turf(spawn_type, pickedTurf, 1, FALSE)
return SUCCESSFUL_SPAWN