Files
GS13NG/code/modules/mob/living/simple_animal/guardian/guardian.dm
T
2019-12-14 01:01:38 +02:00

689 lines
29 KiB
Plaintext

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 = "<span class='holoparasite bold'>You are a standard Guardian. You shouldn't exist!</span>"
var/magic_fluff_string = "<span class='holoparasite'>You draw the Coder, symbolizing bugs and errors. This shouldn't happen! Submit a bug report!</span>"
var/tech_fluff_string = "<span class='holoparasite'>BOOT SEQUENCE COMPLETE. ERROR MODULE LOADED. THIS SHOULDN'T HAPPEN. Submit a bug report!</span>"
var/carp_fluff_string = "<span class='holoparasite'>CARP CARP CARP SOME SORT OF HORRIFIC BUG BLAME THE CODERS CARP CARP CARP</span>"
/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, "<span class='holoparasite bold'>For some reason, somehow, you have no summoner. Please report this bug immediately.</span>")
return
to_chat(src, "<span class='holoparasite'>You are <font color=\"[namedatum.colour]\"><b>[real_name]</b></font>, bound to serve [summoner.real_name].</span>")
to_chat(src, "<span class='holoparasite'>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.</span>")
to_chat(src, "<span class='holoparasite'>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.</span>")
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, "<span class='danger'>Your summoner has died!</span>")
visible_message("<span class='danger'><B>\The [src] dies along with its user!</B></span>")
summoner.visible_message("<span class='danger'><B>[summoner]'s body is completely consumed by the strain of sustaining [src]!</B></span>")
for(var/obj/item/W in summoner)
if(!summoner.dropItemToGround(W))
qdel(W)
summoner.dust()
death(TRUE)
qdel(src)
else
to_chat(src, "<span class='danger'>Your summoner has died!</span>")
visible_message("<span class='danger'><B>[src] dies along with its user!</B></span>")
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,"<span class='danger'>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, "<span class='holoparasite'>You moved out of range, and were pulled back! You can only move [range] meters from [summoner.real_name]!</span>")
visible_message("<span class='danger'>\The [src] jumps back to its user.</span>")
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, "<span class='danger'><B>You must be manifested to attack!</span></B>")
return FALSE
else
return ..()
/mob/living/simple_animal/hostile/guardian/death()
drop_all_held_items()
..()
if(summoner)
to_chat(summoner, "<span class='danger'><B>Your [name] died somehow!</span></B>")
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 = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#efeeef'>[resulthealth]%</font></div>"
/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, "<span class='danger'><B>Your [name] is under attack! You take damage!</span></B>")
summoner.visible_message("<span class='danger'><B>Blood sprays from [summoner] as [src] takes damage!</B></span>")
if(summoner.stat == UNCONSCIOUS)
to_chat(summoner, "<span class='danger'><B>Your body can't take the strain of sustaining [src] in this condition, it begins to fall apart!</span></B>")
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, "<span class='danger'><B>Your [src] was blown up!</span></B>")
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, "<span class='danger'><B>You don't have another mode!</span></B>")
/mob/living/simple_animal/hostile/guardian/proc/ToggleLight()
if(light_range<3)
to_chat(src, "<span class='notice'>You activate your light.</span>")
set_light(3)
else
to_chat(src, "<span class='notice'>You deactivate your light.</span>")
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 = "<span class='holoparasite bold'>[input]</span>" //apply basic color/bolding
var/my_message = "<font color=\"[namedatum.colour]\"><b><i>[src]:</i></b></font> [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 = "<span class='holoparasite bold'>[input]</span>" //apply basic color/bolding
var/my_message = "<span class='holoparasite bold'><i>[src]:</i> [preliminary_message]</span>" //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, "<font color=\"[G.namedatum.colour]\"><b><i>[src]:</i></b></font> [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, "<span class='holoparasite'>You attempt to reset <font color=\"[G.namedatum.colour]\"><b>[G.real_name]</b></font>'s personality...</span>")
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, "<span class='holoparasite'>Your user reset you, and your body was taken over by a ghost. Looks like they weren't happy with your performance.</span>")
to_chat(src, "<span class='holoparasite bold'>Your <font color=\"[G.namedatum.colour]\">[G.real_name]</font> has been successfully reset.</span>")
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, "<span class='holoparasite'><font color=\"[G.namedatum.colour]\"><b>[G.real_name]</b></font> is now online!</span>")
if("magic")
to_chat(src, "<span class='holoparasite'><font color=\"[G.namedatum.colour]\"><b>[G.real_name]</b></font> has been summoned!</span>")
guardians -= G
if(!guardians.len)
verbs -= /mob/living/proc/guardian_reset
else
to_chat(src, "<span class='holoparasite'>There were no ghosts willing to take control of <font color=\"[G.namedatum.colour]\"><b>[G.real_name]</b></font>. Looks like you're stuck with it for now.</span>")
else
to_chat(src, "<span class='holoparasite'>You decide not to reset [guardians.len > 1 ? "any of your guardians":"your guardian"].</span>")
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 = "<span class='holoparasite'>You shuffle the deck...</span>"
var/used_message = "<span class='holoparasite'>All the cards seem to be blank now.</span>"
var/failure_message = "<span class='holoparasite bold'>..And draw a card! It's...blank? Maybe you should try again later.</span>"
var/ling_failure = "<span class='holoparasite bold'>The deck refuses to respond to a souless creature such as you.</span>"
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, "<span class='holoparasite'>[mob_name] chains are not allowed.</span>")
return
var/list/guardians = user.hasparasites()
if(guardians.len && !allowmultiple)
to_chat(user, "<span class='holoparasite'>You already have a [mob_name]!</span>")
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, "<span class='holoparasite'>You already have a [mob_name]!</span>" )
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, "<span class='holoparasite'><font color=\"[G.namedatum.colour]\"><b>[G.real_name]</b></font> is now online!</span>")
if("magic")
to_chat(user, "[G.magic_fluff_string]")
to_chat(user, "<span class='holoparasite'><font color=\"[G.namedatum.colour]\"><b>[G.real_name]</b></font> has been summoned!</span>")
if("carp")
to_chat(user, "[G.carp_fluff_string]")
to_chat(user, "<span class='holoparasite'><font color=\"[G.namedatum.colour]\"><b>[G.real_name]</b></font> has been caught!</span>")
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 = "<span class='holoparasite'>You start to power on the injector...</span>"
used_message = "<span class='holoparasite'>The injector has already been used.</span>"
failure_message = "<span class='holoparasite bold'>...ERROR. BOOT SEQUENCE ABORTED. AI FAILED TO INTIALIZE. PLEASE CONTACT SUPPORT OR TRY AGAIN LATER.</span>"
ling_failure = "<span class='holoparasite bold'>The holoparasites recoil in horror. They want nothing to do with a creature like you.</span>"
/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 = {"<b>A list of Holoparasite Types</b><br>
<br>
<b>Assassin</b>: 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.<br>
<br>
<b>Chaos</b>: Ignites enemies on touch and causes them to hallucinate all nearby people as the parasite. Automatically extinguishes the user if they catch on fire.<br>
<br>
<b>Charger</b>: 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.<br>
<br>
<b>Explosive</b>: 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.<br>
<br>
<b>Lightning</b>: Attacks apply lightning chains to targets. Has a lightning chain to the user. Lightning chains shock everything near them, doing constant damage.<br>
<br>
<b>Protector</b>: 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.<br>
<br>
<b>Ranged</b>: 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.<br>
<br>
<b>Standard</b>: Devastating close combat attacks and high damage resist. Can smash through weak walls.<br>
<br>
"}
/obj/item/paper/guides/antag/guardian/update_icon()
return
/obj/item/paper/guides/antag/guardian/wizard
name = "Guardian Guide"
info = {"<b>A list of Guardian Types</b><br>
<br>
<b>Assassin</b>: 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.<br>
<br>
<b>Chaos</b>: Ignites enemies on touch and causes them to hallucinate all nearby people as the guardian. Automatically extinguishes the user if they catch on fire.<br>
<br>
<b>Charger</b>: 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.<br>
<br>
<b>Dexterous</b>: 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.<br>
<br>
<b>Explosive</b>: 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.<br>
<br>
<b>Lightning</b>: Attacks apply lightning chains to targets. Has a lightning chain to the user. Lightning chains shock everything near them, doing constant damage.<br>
<br>
<b>Protector</b>: 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.<br>
<br>
<b>Ranged</b>: 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.<br>
<br>
<b>Standard</b>: Devastating close combat attacks and high damage resist. Can smash through weak walls.<br>
<br>
"}
/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 = "<span class='holoparasite'>You put the fishsticks in your mouth...</span>"
used_message = "<span class='holoparasite'>Someone's already taken a bite out of these fishsticks! Ew.</span>"
failure_message = "<span class='holoparasite bold'>You couldn't catch any carp spirits from the seas of Lake Carp. Maybe there are none, maybe you fucked up.</span>"
ling_failure = "<span class='holoparasite bold'>Carp'sie is fine with changelings, so you shouldn't be seeing this message.</span>"
allowmultiple = TRUE
allowling = TRUE
random = TRUE
/obj/item/guardiancreator/carp/choose
random = FALSE