/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 = "You are a mimic, 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." /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("\The [src] knocks down \the [C]!", \ "\The [src] knocks you down!") else if(knockdown_people && prob(15)) C.Knockdown(40) C.visible_message("\The [src] knocks down \the [C]!", \ "\The [src] knocks you down!") 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("\The [src] knocks down \the [M]!", \ "\The [src] tricks you, knocking you down!") /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("The [src] Reveals itself to be a Mimic!") 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("[A] is being consumed...", "You start to consume the dead [A]...", "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 += " But something about it seems wrong..." 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 += " But something about it seems wrong..." else to_chat(src, "You need to wait a little longer before you can shift into something else!") ..() //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