GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians #define GUARDIAN_HANDS_LAYER 1 #define GUARDIAN_TOTAL_LAYERS 1 /mob/living/simple_animal/hostile/guardian name = "Guardian Spirit" real_name = "Guardian Spirit" desc = "A mysterious being that stands by its charge, ever vigilant." speak_emote = list("hisses") gender = NEUTER mob_biotypes = list(MOB_INORGANIC) bubble_icon = "guardian" response_help = "passes through" response_disarm = "flails at" response_harm = "punches" icon = 'icons/mob/guardian.dmi' icon_state = "magicOrange" icon_living = "magicOrange" icon_dead = "magicOrange" speed = 0 blood_volume = 0 a_intent = INTENT_HARM stop_automated_movement = 1 movement_type = FLYING // Immunity to chasms and landmines, etc. attack_sound = 'sound/weapons/punch1.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) minbodytemp = 0 maxbodytemp = INFINITY attacktext = "punches" maxHealth = INFINITY //The spirit itself is invincible health = INFINITY healable = FALSE //don't brusepack the guardian damage_coeff = list(BRUTE = 0.5, BURN = 0.5, TOX = 0.5, CLONE = 0.5, STAMINA = 0, OXY = 0.5) //how much damage from each damage type we transfer to the owner environment_smash = ENVIRONMENT_SMASH_STRUCTURES obj_damage = 40 melee_damage_lower = 15 melee_damage_upper = 15 butcher_results = list(/obj/item/ectoplasm = 1) AIStatus = AI_OFF hud_type = /datum/hud/guardian dextrous_hud_type = /datum/hud/dextrous/guardian //if we're set to dextrous, account for it. var/list/guardian_overlays[GUARDIAN_TOTAL_LAYERS] var/reset = 0 //if the summoner has reset the guardian already var/cooldown = 0 var/mob/living/carbon/summoner var/range = 13 //how far from the user the spirit can be var/toggle_button_type = /obj/screen/guardian/ToggleMode/Inactive //what sort of toggle button the hud uses var/datum/guardianname/namedatum = new/datum/guardianname() var/playstyle_string = "You are a standard Guardian. You shouldn't exist!" var/magic_fluff_string = "You draw the Coder, symbolizing bugs and errors. This shouldn't happen! Submit a bug report!" var/tech_fluff_string = "BOOT SEQUENCE COMPLETE. ERROR MODULE LOADED. THIS SHOULDN'T HAPPEN. Submit a bug report!" var/carp_fluff_string = "CARP CARP CARP SOME SORT OF HORRIFIC BUG BLAME THE CODERS CARP CARP CARP" /mob/living/simple_animal/hostile/guardian/Initialize(mapload, theme) GLOB.parasites += src setthemename(theme) . = ..() /mob/living/simple_animal/hostile/guardian/med_hud_set_health() if(summoner) var/image/holder = hud_list[HEALTH_HUD] holder.icon_state = "hud[RoundHealth(summoner)]" /mob/living/simple_animal/hostile/guardian/med_hud_set_status() if(summoner) var/image/holder = hud_list[STATUS_HUD] var/icon/I = icon(icon, icon_state, dir) holder.pixel_y = I.Height() - world.icon_size if(summoner.stat == DEAD) holder.icon_state = "huddead" else holder.icon_state = "hudhealthy" /mob/living/simple_animal/hostile/guardian/Destroy() GLOB.parasites -= src return ..() /mob/living/simple_animal/hostile/guardian/proc/setthemename(pickedtheme) //set the guardian's theme to something cool! if(!pickedtheme) pickedtheme = pick("magic", "tech", "carp") var/list/possible_names = list() switch(pickedtheme) if("magic") for(var/type in (subtypesof(/datum/guardianname/magic) - namedatum.type)) possible_names += new type if("tech") for(var/type in (subtypesof(/datum/guardianname/tech) - namedatum.type)) possible_names += new type if("carp") for(var/type in (subtypesof(/datum/guardianname/carp) - namedatum.type)) possible_names += new type namedatum = pick(possible_names) updatetheme(pickedtheme) /mob/living/simple_animal/hostile/guardian/proc/updatetheme(theme) //update the guardian's theme to whatever its datum is; proc for adminfuckery name = "[namedatum.prefixname] [namedatum.suffixcolour]" real_name = "[name]" icon_living = "[namedatum.parasiteicon]" icon_state = "[namedatum.parasiteicon]" icon_dead = "[namedatum.parasiteicon]" bubble_icon = "[namedatum.bubbleicon]" if (namedatum.stainself) add_atom_colour(namedatum.colour, FIXED_COLOUR_PRIORITY) //Special case holocarp, because #snowflake code if(theme == "carp") speak_emote = list("gnashes") desc = "A mysterious fish that stands by its charge, ever vigilant." attacktext = "bites" attack_sound = 'sound/weapons/bite.ogg' /mob/living/simple_animal/hostile/guardian/Login() //if we have a mind, set its name to ours when it logs in ..() if(mind) mind.name = "[real_name]" if(!summoner) to_chat(src, "For some reason, somehow, you have no summoner. Please report this bug immediately.") return to_chat(src, "You are [real_name], bound to serve [summoner.real_name].") to_chat(src, "You are capable of manifesting or recalling to your master with the buttons on your HUD. You will also find a button to communicate with [summoner.p_them()] privately there.") to_chat(src, "While personally invincible, you will die if [summoner.real_name] does, and any damage dealt to you will have a portion passed on to [summoner.p_them()] as you feed upon [summoner.p_them()] to sustain yourself.") to_chat(src, playstyle_string) /mob/living/simple_animal/hostile/guardian/Life() //Dies if the summoner dies . = ..() update_health_hud() //we need to update all of our health displays to match our summoner and we can't practically give the summoner a hook to do it med_hud_set_health() med_hud_set_status() if(!QDELETED(summoner)) if(summoner.stat == DEAD) forceMove(summoner.loc) to_chat(src, "Your summoner has died!") visible_message("\The [src] dies along with its user!") summoner.visible_message("[summoner]'s body is completely consumed by the strain of sustaining [src]!") for(var/obj/item/W in summoner) if(!summoner.dropItemToGround(W)) qdel(W) summoner.dust() death(TRUE) qdel(src) else to_chat(src, "Your summoner has died!") visible_message("[src] dies along with its user!") death(TRUE) qdel(src) snapback() if(HAS_TRAIT(summoner, TRAIT_NODEATH) && (istype(summoner.wear_neck, /obj/item/clothing/neck/necklace/memento_mori))) REMOVE_TRAIT(summoner, TRAIT_NODEATH, "memento_mori") to_chat(summoner,"You feel incredibly vulnerable as the memento mori pulls your life force in one too many directions!") /mob/living/simple_animal/hostile/guardian/Stat() ..() if(statpanel("Status")) if(summoner) var/resulthealth if(iscarbon(summoner)) resulthealth = round((abs(HEALTH_THRESHOLD_DEAD - summoner.health) / abs(HEALTH_THRESHOLD_DEAD - summoner.maxHealth)) * 100) else resulthealth = round((summoner.health / summoner.maxHealth) * 100, 0.5) stat(null, "Summoner Health: [resulthealth]%") if(cooldown >= world.time) stat(null, "Manifest/Recall Cooldown Remaining: [DisplayTimeText(cooldown - world.time)]") /mob/living/simple_animal/hostile/guardian/Move() //Returns to summoner if they move out of range . = ..() snapback() /mob/living/simple_animal/hostile/guardian/proc/snapback() if(summoner) if(get_dist(get_turf(summoner),get_turf(src)) <= range) return else to_chat(src, "You moved out of range, and were pulled back! You can only move [range] meters from [summoner.real_name]!") visible_message("\The [src] jumps back to its user.") if(istype(summoner.loc, /obj/effect)) Recall(TRUE) else new /obj/effect/temp_visual/guardian/phase/out(loc) forceMove(summoner.loc) new /obj/effect/temp_visual/guardian/phase(loc) /mob/living/simple_animal/hostile/guardian/canSuicide() return FALSE /mob/living/simple_animal/hostile/guardian/proc/is_deployed() return loc != summoner /mob/living/simple_animal/hostile/guardian/AttackingTarget() if(!is_deployed()) to_chat(src, "You must be manifested to attack!") return FALSE else return ..() /mob/living/simple_animal/hostile/guardian/death() drop_all_held_items() ..() if(summoner) to_chat(summoner, "Your [name] died somehow!") summoner.death() /mob/living/simple_animal/hostile/guardian/update_health_hud() if(summoner && hud_used && hud_used.healths) var/resulthealth if(iscarbon(summoner)) resulthealth = round((abs(HEALTH_THRESHOLD_DEAD - summoner.health) / abs(HEALTH_THRESHOLD_DEAD - summoner.maxHealth)) * 100) else resulthealth = round((summoner.health / summoner.maxHealth) * 100, 0.5) hud_used.healths.maptext = "
[resulthealth]%
" /mob/living/simple_animal/hostile/guardian/adjustHealth(amount, updating_health = TRUE, forced = FALSE) //The spirit is invincible, but passes on damage to the summoner . = amount if(summoner) if(loc == summoner) return FALSE summoner.adjustBruteLoss(amount) if(amount > 0) to_chat(summoner, "Your [name] is under attack! You take damage!") summoner.visible_message("Blood sprays from [summoner] as [src] takes damage!") if(summoner.stat == UNCONSCIOUS) to_chat(summoner, "Your body can't take the strain of sustaining [src] in this condition, it begins to fall apart!") summoner.adjustCloneLoss(amount * 0.5) //dying hosts take 50% bonus damage as cloneloss update_health_hud() /mob/living/simple_animal/hostile/guardian/ex_act(severity, target) switch(severity) if(1) gib() return if(2) adjustBruteLoss(60) if(3) adjustBruteLoss(30) /mob/living/simple_animal/hostile/guardian/gib() if(summoner) to_chat(summoner, "Your [src] was blown up!") summoner.gib() ghostize() qdel(src) //HAND HANDLING /mob/living/simple_animal/hostile/guardian/equip_to_slot(obj/item/I, slot) if(!slot) return FALSE if(!istype(I)) return FALSE . = TRUE var/index = get_held_index_of_item(I) if(index) held_items[index] = null update_inv_hands() if(I.pulledby) I.pulledby.stop_pulling() I.screen_loc = null // will get moved if inventory is visible I.forceMove(src) I.equipped(src, slot) I.layer = ABOVE_HUD_LAYER I.plane = ABOVE_HUD_PLANE /mob/living/simple_animal/hostile/guardian/proc/apply_overlay(cache_index) if((. = guardian_overlays[cache_index])) add_overlay(.) /mob/living/simple_animal/hostile/guardian/proc/remove_overlay(cache_index) var/I = guardian_overlays[cache_index] if(I) cut_overlay(I) guardian_overlays[cache_index] = null /mob/living/simple_animal/hostile/guardian/update_inv_hands() remove_overlay(GUARDIAN_HANDS_LAYER) var/list/hands_overlays = list() var/obj/item/l_hand = get_item_for_held_index(1) var/obj/item/r_hand = get_item_for_held_index(2) if(r_hand) var/r_state = r_hand.item_state if(!r_state) r_state = r_hand.icon_state hands_overlays += r_hand.build_worn_icon(state = r_state, default_layer = GUARDIAN_HANDS_LAYER, default_icon_file = r_hand.righthand_file, isinhands = TRUE) if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD) r_hand.layer = ABOVE_HUD_LAYER r_hand.plane = ABOVE_HUD_PLANE r_hand.screen_loc = ui_hand_position(get_held_index_of_item(r_hand)) client.screen |= r_hand if(l_hand) var/l_state = l_hand.item_state if(!l_state) l_state = l_hand.icon_state hands_overlays += l_hand.build_worn_icon(state = l_state, default_layer = GUARDIAN_HANDS_LAYER, default_icon_file = l_hand.lefthand_file, isinhands = TRUE) if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD) l_hand.layer = ABOVE_HUD_LAYER l_hand.plane = ABOVE_HUD_PLANE l_hand.screen_loc = ui_hand_position(get_held_index_of_item(l_hand)) client.screen |= l_hand if(hands_overlays.len) guardian_overlays[GUARDIAN_HANDS_LAYER] = hands_overlays apply_overlay(GUARDIAN_HANDS_LAYER) /mob/living/simple_animal/hostile/guardian/regenerate_icons() update_inv_hands() //MANIFEST, RECALL, TOGGLE MODE/LIGHT, SHOW TYPE /mob/living/simple_animal/hostile/guardian/proc/Manifest(forced) if(istype(summoner.loc, /obj/effect) || (cooldown > world.time && !forced)) return FALSE if(loc == summoner) forceMove(summoner.loc) new /obj/effect/temp_visual/guardian/phase(loc) cooldown = world.time + 10 reset_perspective() return TRUE return FALSE /mob/living/simple_animal/hostile/guardian/proc/Recall(forced) if(!summoner || loc == summoner || (cooldown > world.time && !forced)) return FALSE new /obj/effect/temp_visual/guardian/phase/out(loc) forceMove(summoner) cooldown = world.time + 10 return TRUE /mob/living/simple_animal/hostile/guardian/proc/ToggleMode() to_chat(src, "You don't have another mode!") /mob/living/simple_animal/hostile/guardian/proc/ToggleLight() if(light_range<3) to_chat(src, "You activate your light.") set_light(3) else to_chat(src, "You deactivate your light.") set_light(0) /mob/living/simple_animal/hostile/guardian/verb/ShowType() set name = "Check Guardian Type" set category = "Guardian" set desc = "Check what type you are." to_chat(src, playstyle_string) //COMMUNICATION /mob/living/simple_animal/hostile/guardian/proc/Communicate() if(summoner) var/input = stripped_input(src, "Please enter a message to tell your summoner.", "Guardian", "") if(!input) return var/preliminary_message = "[input]" //apply basic color/bolding var/my_message = "[src]: [preliminary_message]" //add source, color source with the guardian's color to_chat(summoner, my_message) var/list/guardians = summoner.hasparasites() for(var/para in guardians) to_chat(para, my_message) for(var/M in GLOB.dead_mob_list) var/link = FOLLOW_LINK(M, src) to_chat(M, "[link] [my_message]") src.log_talk(input, LOG_SAY, tag="guardian") /mob/living/proc/guardian_comm() set name = "Communicate" set category = "Guardian" set desc = "Communicate telepathically with your guardian." var/input = stripped_input(src, "Please enter a message to tell your guardian.", "Message", "") if(!input) return var/preliminary_message = "[input]" //apply basic color/bolding var/my_message = "[src]: [preliminary_message]" //add source, color source with default grey... to_chat(src, my_message) var/list/guardians = hasparasites() for(var/para in guardians) var/mob/living/simple_animal/hostile/guardian/G = para to_chat(G, "[src]: [preliminary_message]" ) for(var/M in GLOB.dead_mob_list) var/link = FOLLOW_LINK(M, src) to_chat(M, "[link] [my_message]") src.log_talk(input, LOG_SAY, tag="guardian") //FORCE RECALL/RESET /mob/living/proc/guardian_recall() set name = "Recall Guardian" set category = "Guardian" set desc = "Forcibly recall your guardian." var/list/guardians = hasparasites() for(var/para in guardians) var/mob/living/simple_animal/hostile/guardian/G = para G.Recall() /mob/living/proc/guardian_reset() set name = "Reset Guardian Player (One Use)" set category = "Guardian" set desc = "Re-rolls which ghost will control your Guardian. One use per Guardian." var/list/guardians = hasparasites() for(var/para in guardians) var/mob/living/simple_animal/hostile/guardian/P = para if(P.reset) guardians -= P //clear out guardians that are already reset if(guardians.len) var/mob/living/simple_animal/hostile/guardian/G = input(src, "Pick the guardian you wish to reset", "Guardian Reset") as null|anything in guardians if(G) to_chat(src, "You attempt to reset [G.real_name]'s personality...") var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as [src.real_name]'s [G.real_name]?", ROLE_PAI, null, FALSE, 100) if(LAZYLEN(candidates)) var/mob/dead/observer/C = pick(candidates) to_chat(G, "Your user reset you, and your body was taken over by a ghost. Looks like they weren't happy with your performance.") to_chat(src, "Your [G.real_name] has been successfully reset.") message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(G)])") G.ghostize(FALSE) G.setthemename(G.namedatum.theme) //give it a new color, to show it's a new person C.transfer_ckey(G) G.reset = 1 switch(G.namedatum.theme) if("tech") to_chat(src, "[G.real_name] is now online!") if("magic") to_chat(src, "[G.real_name] has been summoned!") guardians -= G if(!guardians.len) verbs -= /mob/living/proc/guardian_reset else to_chat(src, "There were no ghosts willing to take control of [G.real_name]. Looks like you're stuck with it for now.") else to_chat(src, "You decide not to reset [guardians.len > 1 ? "any of your guardians":"your guardian"].") else verbs -= /mob/living/proc/guardian_reset ////////parasite tracking/finding procs /mob/living/proc/hasparasites() //returns a list of guardians the mob is a summoner for . = list() for(var/P in GLOB.parasites) var/mob/living/simple_animal/hostile/guardian/G = P if(G.summoner == src) . += G /mob/living/simple_animal/hostile/guardian/proc/hasmatchingsummoner(mob/living/simple_animal/hostile/guardian/G) //returns 1 if the summoner matches the target's summoner return (istype(G) && G.summoner == summoner) ////////Creation /obj/item/guardiancreator name = "deck of tarot cards" desc = "An enchanted deck of tarot cards, rumored to be a source of unimaginable power." icon = 'icons/obj/toy.dmi' icon_state = "deck_syndicate_full" var/used = FALSE var/theme = "magic" var/mob_name = "Guardian Spirit" var/use_message = "You shuffle the deck..." var/used_message = "All the cards seem to be blank now." var/failure_message = "..And draw a card! It's...blank? Maybe you should try again later." var/ling_failure = "The deck refuses to respond to a souless creature such as you." var/list/possible_guardians = list("Assassin", "Chaos", "Charger", "Explosive", "Lightning", "Protector", "Ranged", "Standard", "Support") var/random = TRUE var/allowmultiple = FALSE var/allowling = TRUE var/allowguardian = FALSE /obj/item/guardiancreator/attack_self(mob/living/user) if(isguardian(user) && !allowguardian) to_chat(user, "[mob_name] chains are not allowed.") return var/list/guardians = user.hasparasites() if(guardians.len && !allowmultiple) to_chat(user, "You already have a [mob_name]!") return if(user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling) && !allowling) to_chat(user, "[ling_failure]") return if(used == TRUE) to_chat(user, "[used_message]") return used = TRUE to_chat(user, "[use_message]") var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as the [mob_name] of [user.real_name]?", ROLE_PAI, null, FALSE, 100, POLL_IGNORE_HOLOPARASITE) if(LAZYLEN(candidates)) var/mob/dead/observer/C = pick(candidates) spawn_guardian(user, C.key) else to_chat(user, "[failure_message]") used = FALSE /obj/item/guardiancreator/proc/spawn_guardian(var/mob/living/user, var/key) var/guardiantype = "Standard" if(random) guardiantype = pick(possible_guardians) else guardiantype = input(user, "Pick the type of [mob_name]", "[mob_name] Creation") as null|anything in possible_guardians if(!guardiantype) to_chat(user, "[failure_message]" ) used = FALSE return var/pickedtype = /mob/living/simple_animal/hostile/guardian/punch switch(guardiantype) if("Chaos") pickedtype = /mob/living/simple_animal/hostile/guardian/fire if("Standard") pickedtype = /mob/living/simple_animal/hostile/guardian/punch if("Ranged") pickedtype = /mob/living/simple_animal/hostile/guardian/ranged if("Support") pickedtype = /mob/living/simple_animal/hostile/guardian/healer if("Explosive") pickedtype = /mob/living/simple_animal/hostile/guardian/bomb if("Lightning") pickedtype = /mob/living/simple_animal/hostile/guardian/beam if("Protector") pickedtype = /mob/living/simple_animal/hostile/guardian/protector if("Charger") pickedtype = /mob/living/simple_animal/hostile/guardian/charger if("Assassin") pickedtype = /mob/living/simple_animal/hostile/guardian/assassin if("Dextrous") pickedtype = /mob/living/simple_animal/hostile/guardian/dextrous var/list/guardians = user.hasparasites() if(guardians.len && !allowmultiple) to_chat(user, "You already have a [mob_name]!" ) used = FALSE return var/mob/living/simple_animal/hostile/guardian/G = new pickedtype(user, theme) G.summoner = user G.key = key G.mind.enslave_mind_to_creator(user) log_game("[key_name(user)] has summoned [key_name(G)], a [guardiantype] holoparasite.") switch(theme) if("tech") to_chat(user, "[G.tech_fluff_string]") to_chat(user, "[G.real_name] is now online!") if("magic") to_chat(user, "[G.magic_fluff_string]") to_chat(user, "[G.real_name] has been summoned!") if("carp") to_chat(user, "[G.carp_fluff_string]") to_chat(user, "[G.real_name] has been caught!") user.verbs += /mob/living/proc/guardian_comm user.verbs += /mob/living/proc/guardian_recall user.verbs += /mob/living/proc/guardian_reset /obj/item/guardiancreator/choose random = FALSE /obj/item/guardiancreator/choose/dextrous possible_guardians = list("Assassin", "Chaos", "Charger", "Dextrous", "Explosive", "Lightning", "Protector", "Ranged", "Standard", "Support") /obj/item/guardiancreator/choose/wizard possible_guardians = list("Assassin", "Chaos", "Charger", "Dextrous", "Explosive", "Lightning", "Protector", "Ranged", "Standard") allowmultiple = TRUE /obj/item/guardiancreator/tech name = "holoparasite injector" desc = "It contains an alien nanoswarm of unknown origin. Though capable of near sorcerous feats via use of hardlight holograms and nanomachines, it requires an organic host as a home base and source of fuel." icon = 'icons/obj/syringe.dmi' icon_state = "combat_hypo" theme = "tech" mob_name = "Holoparasite" use_message = "You start to power on the injector..." used_message = "The injector has already been used." failure_message = "...ERROR. BOOT SEQUENCE ABORTED. AI FAILED TO INTIALIZE. PLEASE CONTACT SUPPORT OR TRY AGAIN LATER." ling_failure = "The holoparasites recoil in horror. They want nothing to do with a creature like you." /obj/item/guardiancreator/tech/choose/traitor possible_guardians = list("Assassin", "Chaos", "Charger", "Explosive", "Lightning", "Protector", "Ranged", "Standard", "Support") /obj/item/guardiancreator/tech/choose/traitor/check_uplink_validity() return !used /obj/item/guardiancreator/tech/choose random = FALSE /obj/item/guardiancreator/tech/choose/dextrous possible_guardians = list("Assassin", "Chaos", "Charger", "Dextrous", "Explosive", "Lightning", "Protector", "Ranged", "Standard", "Support") /obj/item/paper/guides/antag/guardian name = "Holoparasite Guide" icon_state = "paper_words" info = {"A list of Holoparasite Types

Assassin: Does medium damage and takes full damage, but can enter stealth, causing its next attack to do massive damage and ignore armor. However, it becomes briefly unable to recall after attacking from stealth.

Chaos: Ignites enemies on touch and causes them to hallucinate all nearby people as the parasite. Automatically extinguishes the user if they catch on fire.

Charger: Moves extremely fast, does medium damage on attack, and can charge at targets, damaging the first target hit and forcing them to drop any items they are holding.

Explosive: High damage resist and medium power attack that may explosively teleport targets. Can turn any object, including objects too large to pick up, into a bomb, dealing explosive damage to the next person to touch it. The object will return to normal after the trap is triggered or after a delay.

Lightning: Attacks apply lightning chains to targets. Has a lightning chain to the user. Lightning chains shock everything near them, doing constant damage.

Protector: Causes you to teleport to it when out of range, unlike other parasites. Has two modes; Combat, where it does and takes medium damage, and Protection, where it does and takes almost no damage but moves slightly slower.

Ranged: Has two modes. Ranged; which fires a constant stream of weak, armor-ignoring projectiles. Scout; Cannot attack, but can move through walls and is quite hard to see. Can lay surveillance snares, which alert it when crossed, in either mode.

Standard: Devastating close combat attacks and high damage resist. Can smash through weak walls.

"} /obj/item/paper/guides/antag/guardian/update_icon() return /obj/item/paper/guides/antag/guardian/wizard name = "Guardian Guide" info = {"A list of Guardian Types

Assassin: Does medium damage and takes full damage, but can enter stealth, causing its next attack to do massive damage and ignore armor. However, it becomes briefly unable to recall after attacking from stealth.

Chaos: Ignites enemies on touch and causes them to hallucinate all nearby people as the guardian. Automatically extinguishes the user if they catch on fire.

Charger: Moves extremely fast, does medium damage on attack, and can charge at targets, damaging the first target hit and forcing them to drop any items they are holding.

Dexterous: Does low damage on attack, but is capable of holding items and storing a single item within it. It will drop items held in its hands when it recalls, but it will retain the stored item.

Explosive: High damage resist and medium power attack that may explosively teleport targets. Can turn any object, including objects too large to pick up, into a bomb, dealing explosive damage to the next person to touch it. The object will return to normal after the trap is triggered or after a delay.

Lightning: Attacks apply lightning chains to targets. Has a lightning chain to the user. Lightning chains shock everything near them, doing constant damage.

Protector: Causes you to teleport to it when out of range, unlike other parasites. Has two modes; Combat, where it does and takes medium damage, and Protection, where it does and takes almost no damage but moves slightly slower.

Ranged: Has two modes. Ranged; which fires a constant stream of weak, armor-ignoring projectiles. Scout; Cannot attack, but can move through walls and is quite hard to see. Can lay surveillance snares, which alert it when crossed, in either mode.

Standard: Devastating close combat attacks and high damage resist. Can smash through weak walls.

"} /obj/item/storage/box/syndie_kit/guardian name = "holoparasite injector kit" /obj/item/storage/box/syndie_kit/guardian/PopulateContents() new /obj/item/guardiancreator/tech/choose/traitor(src) new /obj/item/paper/guides/antag/guardian(src) /obj/item/guardiancreator/carp name = "holocarp fishsticks" desc = "Using the power of Carp'sie, you can catch a carp from byond the veil of Carpthulu, and bind it to your fleshy flesh form." icon = 'icons/obj/food/food.dmi' icon_state = "fishfingers" theme = "carp" mob_name = "Holocarp" use_message = "You put the fishsticks in your mouth..." used_message = "Someone's already taken a bite out of these fishsticks! Ew." failure_message = "You couldn't catch any carp spirits from the seas of Lake Carp. Maybe there are none, maybe you fucked up." ling_failure = "Carp'sie is fine with changelings, so you shouldn't be seeing this message." allowmultiple = TRUE allowling = TRUE random = TRUE /obj/item/guardiancreator/carp/choose random = FALSE