holopara qol update (#72042) (#18438)

holoparasite types have improved code
admins can now give someone a holoparasite through a new menu in vv
dropdown
alt click holopara abilities were moved to right click (support's beacon
wasn't, but support's heal mode was)
holoparas have less hardcoded stuff so admins can edit them easier
holoparasites now get their light color from their guardian color
holoparasites no longer have the hostile faction, things will attack
them
holoparasites now have a damage overlay, so you can see how much your
summoner is damaged
holoparasite health updating is now event based rather than running on
life, so you'll see health changes everytime they happen, rather than
every 2 seconds
holoparasites fly properly again (they cant spacewalk, but count as
flying for stuff like chasms)
holoparasite creation now uses a radial menu with tooltips for each
subtype. it also shows ghosts which type you picked
holoparasites can no longer be fugu'd
adds support for ownerless holoparasites
fixes mildly related bugs along the way

Co-authored-by: Fikou <23585223+Fikou@users.noreply.github.com>
Co-authored-by: Tastyfish <crazychris32@gmail.com>
This commit is contained in:
Zonespace
2023-01-09 05:39:54 -05:00
committed by GitHub
co-authored by Fikou Tastyfish
parent 6dc618e19c
commit e38eee6dee
32 changed files with 1142 additions and 975 deletions
+8
View File
@@ -0,0 +1,8 @@
#define GUARDIAN_THEME_TECH "tech"
#define GUARDIAN_THEME_MAGIC "magic"
#define GUARDIAN_THEME_CARP "carp"
#define GUARDIAN_THEME_MINER "miner"
#define GUARDIAN_COLOR_LAYER 2
#define GUARDIAN_HANDS_LAYER 1
#define GUARDIAN_TOTAL_LAYERS 2
+1
View File
@@ -55,6 +55,7 @@
#define span_highlight(str) ("<span class='highlight'>" + str + "</span>")
#define span_his_grace(str) ("<span class='his_grace'>" + str + "</span>")
#define span_holoparasite(str) ("<span class='holoparasite'>" + str + "</span>")
#define span_boldholoparasite(str) ("<span class='holoparasite bold'>" + str + "</span>")
#define span_hypnophrase(str) ("<span class='hypnophrase'>" + str + "</span>")
#define span_icon(str) ("<span class='icon'>" + str + "</span>")
#define span_info(str) ("<span class='info'>" + str + "</span>")
+1
View File
@@ -130,6 +130,7 @@
#define VV_HK_REMOVE_MOOD "removemood"
#define VV_HK_GIVE_HALLUCINATION "give_hallucination"
#define VV_HK_GIVE_DELUSION_HALLUCINATION "give_hallucination_delusion"
#define VV_HK_GIVE_GUARDIAN_SPIRIT "give_guardian_spirit"
// /mob/living/carbon
#define VV_HK_MAKE_AI "aiify"
+17 -17
View File
@@ -69,7 +69,7 @@
static_inventory += using
pull_icon = new /atom/movable/screen/pull()
pull_icon.icon = 'icons/hud/guardian.dmi'
pull_icon.icon = ui_style
pull_icon.update_appearance()
pull_icon.screen_loc = ui_living_pull
pull_icon.hud = src
@@ -103,15 +103,15 @@
if(!mymob)
return
if(istype(mymob, /mob/living/simple_animal/hostile/guardian/dextrous))
var/mob/living/simple_animal/hostile/guardian/dextrous/D = mymob
var/mob/living/simple_animal/hostile/guardian/dextrous/dex_guardian = mymob
if(hud_shown)
if(D.internal_storage)
D.internal_storage.screen_loc = ui_id
D.client.screen += D.internal_storage
if(dex_guardian.internal_storage)
dex_guardian.internal_storage.screen_loc = ui_id
dex_guardian.client.screen += dex_guardian.internal_storage
else
if(D.internal_storage)
D.internal_storage.screen_loc = null
if(dex_guardian.internal_storage)
dex_guardian.internal_storage.screen_loc = null
..()
@@ -125,8 +125,8 @@
/atom/movable/screen/guardian/manifest/Click()
if(isguardian(usr))
var/mob/living/simple_animal/hostile/guardian/G = usr
G.Manifest()
var/mob/living/simple_animal/hostile/guardian/user = usr
user.manifest()
/atom/movable/screen/guardian/recall
@@ -136,8 +136,8 @@
/atom/movable/screen/guardian/recall/Click()
if(isguardian(usr))
var/mob/living/simple_animal/hostile/guardian/G = usr
G.Recall()
var/mob/living/simple_animal/hostile/guardian/user = usr
user.recall()
/atom/movable/screen/guardian/toggle_mode
icon_state = "toggle"
@@ -146,8 +146,8 @@
/atom/movable/screen/guardian/toggle_mode/Click()
if(isguardian(usr))
var/mob/living/simple_animal/hostile/guardian/G = usr
G.ToggleMode()
var/mob/living/simple_animal/hostile/guardian/user = usr
user.toggle_modes()
/atom/movable/screen/guardian/toggle_mode/inactive
icon_state = "notoggle" //greyed out so it doesn't look like it'll work
@@ -169,8 +169,8 @@
/atom/movable/screen/guardian/communicate/Click()
if(isguardian(usr))
var/mob/living/simple_animal/hostile/guardian/G = usr
G.Communicate()
var/mob/living/simple_animal/hostile/guardian/user = usr
user.communicate()
/atom/movable/screen/guardian/toggle_light
@@ -180,5 +180,5 @@
/atom/movable/screen/guardian/toggle_light/Click()
if(isguardian(usr))
var/mob/living/simple_animal/hostile/guardian/G = usr
G.ToggleLight()
var/mob/living/simple_animal/hostile/guardian/user = usr
user.toggle_light()
+1
View File
@@ -200,6 +200,7 @@ GLOBAL_LIST_EMPTY(radial_menus)
/datum/radial_menu/proc/HideElement(atom/movable/screen/radial/slice/E)
E.cut_overlays()
E.vis_contents.Cut()
E.alpha = 0
E.name = "None"
E.maptext = null
+1 -1
View File
@@ -581,7 +581,7 @@
/atom/movable/screen/healths/guardian
name = "summoner health"
icon = 'icons/mob/nonhuman-player/guardian.dmi'
icon = 'icons/hud/guardian.dmi'
icon_state = "base"
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
@@ -136,6 +136,7 @@
clean_old_turfs()
UnregisterSignal(parent, list(
COMSIG_MOVABLE_MOVED,
COMSIG_MOVABLE_Z_CHANGED,
COMSIG_ATOM_UPDATE_LIGHT_RANGE,
COMSIG_ATOM_UPDATE_LIGHT_POWER,
COMSIG_ATOM_UPDATE_LIGHT_COLOR,
@@ -277,6 +278,8 @@
///Called when the current_holder is qdeleted, to remove the light effect.
/datum/component/overlay_lighting/proc/on_holder_qdel(atom/movable/source, force)
SIGNAL_HANDLER
if(QDELETED(current_holder))
return
UnregisterSignal(current_holder, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED))
if(directional)
UnregisterSignal(current_holder, COMSIG_ATOM_DIR_CHANGE)
+1 -1
View File
@@ -203,7 +203,7 @@
current.faction |= creator.faction
creator.faction |= current.faction
if(creator.mind.special_role)
if(creator.mind?.special_role)
message_admins("[ADMIN_LOOKUPFLW(current)] has been created by [ADMIN_LOOKUPFLW(creator)], an antagonist.")
to_chat(current, span_userdanger("Despite your creator's current allegiances, your true master remains [creator.real_name]. If their loyalties change, so do yours. This will never change unless your creator's body is destroyed."))
+5 -8
View File
@@ -1901,18 +1901,15 @@
return 0
var/list/forced_gravity = list()
if(SEND_SIGNAL(src, COMSIG_ATOM_HAS_GRAVITY, gravity_turf, forced_gravity))
if(!length(forced_gravity))
SEND_SIGNAL(gravity_turf, COMSIG_TURF_HAS_GRAVITY, src, forced_gravity)
SEND_SIGNAL(src, COMSIG_ATOM_HAS_GRAVITY, gravity_turf, forced_gravity)
SEND_SIGNAL(gravity_turf, COMSIG_TURF_HAS_GRAVITY, src, forced_gravity)
if(length(forced_gravity))
var/positive_grav = max(forced_gravity)
var/negative_grav = min(min(forced_gravity), 0) //negative grav needs to be below or equal to 0
var/positive_grav = 0
var/negative_grav = 0
//our gravity is sum of the most massive positive and negative numbers returned by the signal
//so that adding two forced_gravity elements with an effect size of 1 each doesnt add to 2 gravity
//but negative force gravity effects can cancel out positive ones
for(var/gravity_influence in forced_gravity)
positive_grav = max(positive_grav, gravity_influence)
negative_grav = min(negative_grav, gravity_influence)
return (positive_grav + negative_grav)
@@ -72,14 +72,6 @@
item_path = /obj/item/guardiancreator/choose/wizard
category = "Assistance"
/datum/spellbook_entry/item/guardian/buy_spell(mob/living/carbon/human/user, obj/item/spellbook/book)
. = ..()
if(!.)
return
new /obj/item/paper/guides/antag/guardian/wizard(get_turf(user))
to_chat(user, span_notice("If you are not experienced in the ways of wizardly guardians, a guide has been summoned at your feet."))
/datum/spellbook_entry/item/bloodbottle
name = "Bottle of Blood"
desc = "A bottle of magically infused blood, the smell of which will \
+1 -1
View File
@@ -209,7 +209,7 @@
/obj/item/clothing/neck/necklace/memento_mori/proc/regurgitate_guardian(mob/living/simple_animal/hostile/guardian/guardian)
guardian.locked = FALSE
guardian.Recall(TRUE)
guardian.recall(forced = TRUE)
to_chat(guardian, span_notice("You have been returned back from your summoner's pendant!"))
guardian.playsound_local(get_turf(guardian), 'sound/magic/repulse.ogg', 50, TRUE)
+57
View File
@@ -1857,6 +1857,7 @@ GLOBAL_LIST_EMPTY(fire_appearances)
VV_DROPDOWN_OPTION(VV_HK_REMOVE_MOOD, "Remove Mood Event")
VV_DROPDOWN_OPTION(VV_HK_GIVE_HALLUCINATION, "Give Hallucination")
VV_DROPDOWN_OPTION(VV_HK_GIVE_DELUSION_HALLUCINATION, "Give Delusion Hallucination")
VV_DROPDOWN_OPTION(VV_HK_GIVE_GUARDIAN_SPIRIT, "Give Guardian Spirit")
/mob/living/vv_do_topic(list/href_list)
. = ..()
@@ -1879,6 +1880,10 @@ GLOBAL_LIST_EMPTY(fire_appearances)
if(!check_rights(NONE))
return
admin_give_delusion(usr)
if(href_list[VV_HK_GIVE_GUARDIAN_SPIRIT])
if(!check_rights(NONE))
return
admin_give_guardian(usr)
/mob/living/proc/move_to_error_room()
var/obj/effect/landmark/error/error_landmark = locate(/obj/effect/landmark/error) in GLOB.landmarks_list
@@ -2512,3 +2517,55 @@ GLOBAL_LIST_EMPTY(fire_appearances)
log_admin("[key_name(admin)] gave [src] a delusion hallucination. (Type: [delusion_args[1]])")
// Not using the wrapper here because we already have a list / arglist
_cause_hallucination(delusion_args)
/mob/living/proc/admin_give_guardian(mob/admin)
if(!admin || !check_rights(NONE))
return
var/del_mob = FALSE
var/mob/old_mob
var/ai_control = FALSE
var/list/possible_players = list("None", "Poll Ghosts") + sort_list(GLOB.clients)
var/client/guardian_client = tgui_input_list(admin, "Pick the player to put in control.", "Guardian Controller", possible_players)
if(!guardian_client)
return
else if(guardian_client == "None")
guardian_client = null
ai_control = (tgui_alert(admin, "Do you want to give the spirit AI control?", "Guardian Controller", list("Yes", "No")) == "Yes")
else if(guardian_client == "Poll Ghosts")
var/list/candidates = poll_ghost_candidates("Do you want to play as an admin created Guardian Spirit of [real_name]?", ROLE_PAI, FALSE, 100, POLL_IGNORE_HOLOPARASITE)
if(LAZYLEN(candidates))
var/mob/dead/observer/candidate = pick(candidates)
guardian_client = candidate.client
else
tgui_alert(admin, "No ghost candidates.", "Guardian Controller")
return
else
old_mob = guardian_client.mob
if(isobserver(old_mob) || tgui_alert(admin, "Do you want to delete [guardian_client]'s old mob?", "Guardian Controller", list("Yes"," No")) == "Yes")
del_mob = TRUE
var/picked_type = tgui_input_list(admin, "Pick the guardian type.", "Guardian Controller", subtypesof(/mob/living/simple_animal/hostile/guardian))
var/picked_theme = tgui_input_list(admin, "Pick the guardian theme.", "Guardian Controller", list(GUARDIAN_THEME_TECH, GUARDIAN_THEME_MAGIC, GUARDIAN_THEME_CARP, GUARDIAN_THEME_MINER, "Random"))
if(picked_theme == "Random")
picked_theme = null //holopara code handles not having a theme by giving a random one
var/picked_name = tgui_input_text(admin, "Name the guardian, leave empty to let player name it.", "Guardian Controller")
var/picked_color = input(admin, "Set the guardian's color, cancel to let player set it.", "Guardian Controller", "#ffffff") as color|null
if(tgui_alert(admin, "Confirm creation.", "Guardian Controller", list("Yes", "No")) != "Yes")
return
var/mob/living/simple_animal/hostile/guardian/summoned_guardian = new picked_type(src, picked_theme)
summoned_guardian.set_summoner(src, different_person = TRUE)
if(picked_name)
summoned_guardian.fully_replace_character_name(null, picked_name)
if(picked_color)
summoned_guardian.set_guardian_color(picked_color)
summoned_guardian.key = guardian_client?.key
guardian_client?.init_verbs()
if(del_mob)
qdel(old_mob)
if(ai_control)
summoned_guardian.can_have_ai = TRUE
summoned_guardian.toggle_ai(AI_ON)
summoned_guardian.manifest()
message_admins(span_adminnotice("[key_name_admin(admin)] gave a guardian spirit controlled by [guardian_client || "AI"] to [src]."))
log_admin("[key_name(admin)] gave a guardian spirit controlled by [guardian_client] to [src].")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Give Guardian Spirit")
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,211 @@
GLOBAL_LIST_INIT(guardian_radial_images, setup_guardian_radial())
/proc/setup_guardian_radial()
. = list()
for(var/mob/living/simple_animal/hostile/guardian/guardian_path as anything in subtypesof(/mob/living/simple_animal/hostile/guardian))
var/datum/radial_menu_choice/option = new()
option.name = initial(guardian_path.creator_name)
option.image = image(icon = 'icons/hud/guardian.dmi', icon_state = initial(guardian_path.creator_icon))
option.info = span_boldnotice(initial(guardian_path.creator_desc))
.[guardian_path] = option
/obj/item/guardiancreator
name = "enchanted deck of tarot cards"
desc = "An enchanted deck of tarot cards, rumored to be a source of unimaginable power."
icon = 'icons/obj/toys/playing_cards.dmi'
icon_state = "deck_tarot_full"
/// Are we used or in the process of being used? If yes, then we can't be used.
var/used = FALSE
/// The visuals we give to the guardian we spawn.
var/theme = GUARDIAN_THEME_MAGIC
/// The name of the guardian, for UI/message stuff.
var/mob_name = "Guardian Spirit"
/// Message sent when you use it.
var/use_message = span_holoparasite("You shuffle the deck...")
/// Message sent when it's already used.
var/used_message = span_holoparasite("All the cards seem to be blank now.")
/// Failure message if no ghost picks the holopara.
var/failure_message = span_boldholoparasite("..And draw a card! It's... blank? Maybe you should try again later.")
/// Failure message if we don't allow lings.
var/ling_failure = span_boldholoparasite("The deck refuses to respond to a souless creature such as you.")
/// Message sent if we successfully get a guardian.
var/success_message = span_holoparasite("<b>%GUARDIAN</b> has been summoned!")
/// If true, you are given a random guardian rather than picking from a selection.
var/random = TRUE
/// If true, you can have multiple guardians at the same time.
var/allowmultiple = FALSE
/// If true, lings can get guardians from this.
var/allowling = TRUE
/// If true, a dextrous guardian can get their own guardian, infinite chain!
var/allowguardian = FALSE
/// List of all the guardians this type can spawn.
var/list/possible_guardians = list( //default, has everything but dextrous
/mob/living/simple_animal/hostile/guardian/assassin,
/mob/living/simple_animal/hostile/guardian/charger,
/mob/living/simple_animal/hostile/guardian/explosive,
/mob/living/simple_animal/hostile/guardian/gaseous,
/mob/living/simple_animal/hostile/guardian/gravitokinetic,
/mob/living/simple_animal/hostile/guardian/lightning,
/mob/living/simple_animal/hostile/guardian/protector,
/mob/living/simple_animal/hostile/guardian/ranged,
/mob/living/simple_animal/hostile/guardian/standard,
/mob/living/simple_animal/hostile/guardian/support,
)
/obj/item/guardiancreator/attack_self(mob/living/user)
if(isguardian(user) && !allowguardian)
to_chat(user, span_holoparasite("[mob_name] chains are not allowed."))
return
var/list/guardians = user.get_all_linked_holoparasites()
if(length(guardians) && !allowmultiple)
to_chat(user, span_holoparasite("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)
to_chat(user, used_message)
return
var/list/radial_options = GLOB.guardian_radial_images.Copy()
for(var/possible_guardian in radial_options)
if(possible_guardian in possible_guardians)
continue
radial_options -= possible_guardian
var/mob/living/simple_animal/hostile/guardian/guardian_path
if(random)
guardian_path = pick(possible_guardians)
else
guardian_path = show_radial_menu(user, src, radial_options, custom_check = CALLBACK(src, PROC_REF(check_menu), user), radius = 42, require_near = TRUE)
if(!guardian_path)
return
used = TRUE
to_chat(user, use_message)
var/guardian_type_name = "a random"
if(!random)
guardian_type_name = "the " + lowertext(initial(guardian_path.creator_name))
var/list/mob/dead/observer/candidates = poll_ghost_candidates("Do you want to play as [guardian_type_name] [mob_name] of [user.real_name]?", ROLE_PAI, FALSE, 100, POLL_IGNORE_HOLOPARASITE)
if(LAZYLEN(candidates))
var/mob/dead/observer/candidate = pick(candidates)
spawn_guardian(user, candidate, guardian_path)
else
to_chat(user, failure_message)
used = FALSE
/obj/item/guardiancreator/proc/spawn_guardian(mob/living/user, mob/dead/candidate, guardian_path)
var/list/guardians = user.get_all_linked_holoparasites()
if(length(guardians) && !allowmultiple)
to_chat(user, span_holoparasite("You already have a [mob_name]!") )
used = FALSE
return
var/mob/living/simple_animal/hostile/guardian/summoned_guardian = new guardian_path(user, theme)
summoned_guardian.set_summoner(user, different_person = TRUE)
summoned_guardian.key = candidate.key
user.log_message("has summoned [key_name(summoned_guardian)], a [summoned_guardian.creator_name] holoparasite.", LOG_GAME)
summoned_guardian.log_message("was summoned as a [summoned_guardian.creator_name] holoparasite.", LOG_GAME)
to_chat(user, summoned_guardian.used_fluff_string)
to_chat(user, replacetext(success_message, "%GUARDIAN", mob_name))
summoned_guardian.client?.init_verbs()
return summoned_guardian
/obj/item/guardiancreator/proc/check_menu(mob/living/user)
if(!istype(user))
return FALSE
if(user.incapacitated() || !user.is_holding(src) || used)
return FALSE
return TRUE
/obj/item/guardiancreator/choose
random = FALSE
/obj/item/guardiancreator/choose/all/Initialize(mapload)
. = ..()
possible_guardians = subtypesof(/mob/living/simple_animal/hostile/guardian)
/obj/item/guardiancreator/choose/wizard
allowmultiple = TRUE
possible_guardians = list( //no support, but dextrous
/mob/living/simple_animal/hostile/guardian/assassin,
/mob/living/simple_animal/hostile/guardian/charger,
/mob/living/simple_animal/hostile/guardian/dextrous,
/mob/living/simple_animal/hostile/guardian/explosive,
/mob/living/simple_animal/hostile/guardian/gaseous,
/mob/living/simple_animal/hostile/guardian/gravitokinetic,
/mob/living/simple_animal/hostile/guardian/lightning,
/mob/living/simple_animal/hostile/guardian/protector,
/mob/living/simple_animal/hostile/guardian/ranged,
/mob/living/simple_animal/hostile/guardian/standard,
)
/obj/item/guardiancreator/choose/wizard/spawn_guardian(mob/living/user, mob/dead/candidate)
. = ..()
var/mob/guardian = .
if(!guardian)
return
var/datum/antagonist/wizard/antag_datum = user.mind.has_antag_datum(/datum/antagonist/wizard)
if(antag_datum)
if(!antag_datum.wiz_team)
antag_datum.create_wiz_team()
guardian.mind.add_antag_datum(/datum/antagonist/wizard_minion, antag_datum.wiz_team)
/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/medical/syringe.dmi'
icon_state = "combat_hypo"
theme = GUARDIAN_THEME_TECH
mob_name = "Holoparasite"
use_message = span_holoparasite("You start to power on the injector...")
used_message = span_holoparasite("The injector has already been used.")
failure_message = span_boldholoparasite("...ERROR. BOOT SEQUENCE ABORTED. AI FAILED TO INTIALIZE. PLEASE CONTACT SUPPORT OR TRY AGAIN LATER.")
ling_failure = span_boldholoparasite("The holoparasites recoil in horror. They want nothing to do with a creature like you.")
success_message = span_holoparasite("<b>%GUARDIAN</b> is now online!")
/obj/item/guardiancreator/tech/choose
random = FALSE
/obj/item/guardiancreator/tech/choose/all/Initialize(mapload)
. = ..()
possible_guardians = subtypesof(/mob/living/simple_animal/hostile/guardian)
/obj/item/guardiancreator/tech/choose/traitor
allowling = FALSE
/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/meat.dmi'
icon_state = "fishfingers"
theme = GUARDIAN_THEME_CARP
mob_name = "Holocarp"
use_message = span_holoparasite("You put the fishsticks in your mouth...")
used_message = span_holoparasite("Someone's already taken a bite out of these fishsticks! Ew.")
failure_message = span_boldholoparasite("You couldn't catch any carp spirits from the seas of Lake Carp. Maybe there are none, maybe you fucked up.")
ling_failure = span_boldholoparasite("Carp'sie seems to not have taken you as the chosen one. Maybe it's because of your horrifying origin.")
success_message = span_holoparasite("<b>%GUARDIAN</b> has been caught!")
allowmultiple = TRUE
/obj/item/guardiancreator/carp/choose
random = FALSE
/obj/item/guardiancreator/miner
name = "dusty shard"
desc = "Seems to be a very old rock, may have originated from a strange meteor."
icon = 'icons/obj/lavaland/artefacts.dmi'
icon_state = "dustyshard"
theme = GUARDIAN_THEME_MINER
mob_name = "Power Miner"
use_message = span_holoparasite("You pierce your skin with the shard...")
used_message = span_holoparasite("This shard seems to have lost all its power...")
failure_message = span_boldholoparasite("The shard hasn't reacted at all. Maybe try again later...")
ling_failure = span_boldholoparasite("The power of the shard seems to not react with your horrifying, mutated body.")
success_message = span_holoparasite("<b>%GUARDIAN</b> has appeared!")
possible_guardians = list( //limited to ones useful on lavaland
/mob/living/simple_animal/hostile/guardian/charger,
/mob/living/simple_animal/hostile/guardian/protector,
/mob/living/simple_animal/hostile/guardian/ranged,
/mob/living/simple_animal/hostile/guardian/standard,
/mob/living/simple_animal/hostile/guardian/support,
)
/obj/item/guardiancreator/miner/choose
random = FALSE
@@ -7,95 +7,99 @@
attack_sound = 'sound/weapons/bladeslice.ogg'
attack_vis_effect = ATTACK_EFFECT_SLASH
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
playstyle_string = "<span class='holoparasite'>As an <b>assassin</b> type you do medium damage and have no damage resistance, but can enter stealth, massively increasing the damage of your next attack and causing it to ignore armor. Stealth is broken when you attack or take damage.</span>"
magic_fluff_string = "<span class='holoparasite'>..And draw the Space Ninja, a lethal, invisible assassin.</span>"
tech_fluff_string = "<span class='holoparasite'>Boot sequence complete. Assassin modules loaded. Holoparasite swarm online.</span>"
carp_fluff_string = "<span class='holoparasite'>CARP CARP CARP! Caught one! It's an assassin carp! Just when you thought it was safe to go back to the water... which is unhelpful, because we're in space.</span>"
miner_fluff_string = "<span class='holoparasite'>You encounter... Glass, a sharp, fragile attacker.</span>"
playstyle_string = span_holoparasite("As an <b>assassin</b> type you do medium damage and have no damage resistance, but can enter stealth, massively increasing the damage of your next attack and causing it to ignore armor. Stealth is broken when you attack or take damage.")
magic_fluff_string = span_holoparasite("..And draw the Space Ninja, a lethal, invisible assassin.")
tech_fluff_string = span_holoparasite("Boot sequence complete. Assassin modules loaded. Holoparasite swarm online.")
carp_fluff_string = span_holoparasite("CARP CARP CARP! Caught one! It's an assassin carp! Just when you thought it was safe to go back to the water... which is unhelpful, because we're in space.")
miner_fluff_string = span_holoparasite("You encounter... Glass, a sharp, fragile attacker.")
creator_name = "Assassin"
creator_desc = "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."
creator_icon = "assassin"
toggle_button_type = /atom/movable/screen/guardian/toggle_mode/assassin
/// Is it in stealth mode?
var/toggle = FALSE
var/stealthcooldown = 160
/// Time between going in stealth.
var/stealth_cooldown_time = 16 SECONDS
/// Damage added in stealth mode.
var/damage_bonus = 35
/// Screen alert given when we are able to stealth.
var/atom/movable/screen/alert/canstealthalert
/// Screen alert given when we are in stealth.
var/atom/movable/screen/alert/instealthalert
/mob/living/simple_animal/hostile/guardian/assassin/Initialize(mapload)
. = ..()
stealthcooldown = 0
/// Cooldown for the stealth toggle.
COOLDOWN_DECLARE(stealth_cooldown)
/mob/living/simple_animal/hostile/guardian/assassin/Life(delta_time = SSMOBS_DT, times_fired)
. = ..()
updatestealthalert()
if(loc == summoner && toggle)
ToggleMode(0)
/mob/living/simple_animal/hostile/guardian/assassin/get_status_tab_items()
. = ..()
if(stealthcooldown >= world.time)
. += "Stealth Cooldown Remaining: [DisplayTimeText(stealthcooldown - world.time)]"
if(!COOLDOWN_FINISHED(src, stealth_cooldown))
. += "Stealth Cooldown Remaining: [DisplayTimeText(COOLDOWN_TIMELEFT(src, stealth_cooldown))]"
/mob/living/simple_animal/hostile/guardian/assassin/AttackingTarget()
/mob/living/simple_animal/hostile/guardian/assassin/AttackingTarget(atom/attacked_target)
. = ..()
if(.)
if(toggle && (isliving(target) || istype(target, /obj/structure/window) || istype(target, /obj/structure/grille)))
ToggleMode(1)
toggle_modes(forced = TRUE)
/mob/living/simple_animal/hostile/guardian/assassin/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
. = ..()
if(. > 0 && toggle)
ToggleMode(1)
toggle_modes(forced = TRUE)
/mob/living/simple_animal/hostile/guardian/assassin/Recall()
if(..() && toggle)
ToggleMode(0)
/mob/living/simple_animal/hostile/guardian/assassin/ToggleMode(forced = 0)
/mob/living/simple_animal/hostile/guardian/assassin/recall_effects()
if(toggle)
melee_damage_lower = initial(melee_damage_lower)
melee_damage_upper = initial(melee_damage_upper)
toggle_modes(forced = TRUE)
/mob/living/simple_animal/hostile/guardian/assassin/toggle_modes(forced = FALSE)
if(toggle)
melee_damage_lower -= damage_bonus
melee_damage_upper -= damage_bonus
armour_penetration = initial(armour_penetration)
obj_damage = initial(obj_damage)
environment_smash = initial(environment_smash)
alpha = initial(alpha)
if(!forced)
to_chat(src, "[span_danger("<B>You exit stealth.")]</B>")
to_chat(src, span_bolddanger("You exit stealth."))
else
visible_message(span_danger("\The [src] suddenly appears!"))
stealthcooldown = world.time + initial(stealthcooldown) //we were forced out of stealth and go on cooldown
cooldown = world.time + 40 //can't recall for 4 seconds
COOLDOWN_START(src, stealth_cooldown, stealth_cooldown_time) //we were forced out of stealth and go on cooldown
COOLDOWN_START(src, manifest_cooldown, 4 SECONDS) //can't recall for 4 seconds
updatestealthalert()
toggle = FALSE
else if(stealthcooldown <= world.time)
if(src.loc == summoner)
to_chat(src, "[span_danger("<B>You have to be manifested to enter stealth!")]</B>")
else if(COOLDOWN_FINISHED(src, stealth_cooldown))
if(!is_deployed())
to_chat(src, span_bolddanger("You have to be manifested to enter stealth!"))
return
melee_damage_lower = 50
melee_damage_upper = 50
melee_damage_lower += damage_bonus
melee_damage_upper += damage_bonus
armour_penetration = 100
obj_damage = 0
environment_smash = ENVIRONMENT_SMASH_NONE
new /obj/effect/temp_visual/guardian/phase/out(get_turf(src))
alpha = 15
if(!forced)
to_chat(src, "[span_danger("<B>You enter stealth, empowering your next attack.")]</B>")
to_chat(src, span_bolddanger("You enter stealth, empowering your next attack."))
updatestealthalert()
toggle = TRUE
else if(!forced)
to_chat(src, "[span_danger("<B>You cannot yet enter stealth, wait another [DisplayTimeText(stealthcooldown - world.time)]!")]</B>")
to_chat(src, span_bolddanger("You cannot yet enter stealth, wait another [DisplayTimeText(COOLDOWN_TIMELEFT(src, stealth_cooldown))]!"))
/mob/living/simple_animal/hostile/guardian/assassin/proc/updatestealthalert()
if(stealthcooldown <= world.time)
if(toggle)
if(!instealthalert)
instealthalert = throw_alert("instealth", /atom/movable/screen/alert/instealth)
clear_alert("canstealth")
canstealthalert = null
else
if(!canstealthalert)
canstealthalert = throw_alert("canstealth", /atom/movable/screen/alert/canstealth)
clear_alert("instealth")
instealthalert = null
else
if(!COOLDOWN_FINISHED(src, stealth_cooldown))
clear_alert("instealth")
instealthalert = null
clear_alert("canstealth")
canstealthalert = null
return
if(toggle && !instealthalert)
instealthalert = throw_alert("instealth", /atom/movable/screen/alert/instealth)
clear_alert("canstealth")
canstealthalert = null
else if(!toggle && !canstealthalert)
canstealthalert = throw_alert("canstealth", /atom/movable/screen/alert/canstealth)
clear_alert("instealth")
instealthalert = null
@@ -2,73 +2,70 @@
/mob/living/simple_animal/hostile/guardian/charger
melee_damage_lower = 15
melee_damage_upper = 15
ranged = 1 //technically
ranged = TRUE //technically
ranged_message = "charges"
ranged_cooldown_time = 40
ranged_cooldown_time = 4 SECONDS
speed = -1
damage_coeff = list(BRUTE = 0.6, BURN = 0.6, TOX = 0.6, CLONE = 0.6, STAMINA = 0, OXY = 0.6)
playstyle_string = "<span class='holoparasite'>As a <b>charger</b> type you do medium damage, have medium damage resistance, move very fast, and can charge at a location, damaging any target hit and forcing them to drop any items they are holding.</span>"
magic_fluff_string = "<span class='holoparasite'>..And draw the Hunter, an alien master of rapid assault.</span>"
tech_fluff_string = "<span class='holoparasite'>Boot sequence complete. Charge modules loaded. Holoparasite swarm online.</span>"
carp_fluff_string = "<span class='holoparasite'>CARP CARP CARP! Caught one! It's a charger carp, that likes running at people. But it doesn't have any legs...</span>"
miner_fluff_string = "<span class='holoparasite'>You encounter... Titanium, a lightweight, agile fighter.</span>"
var/charging = 0
playstyle_string = span_holoparasite("As a <b>charger</b> type you do medium damage, have medium damage resistance, move very fast, and can charge at a location, damaging any target hit and forcing them to drop any items they are holding.")
magic_fluff_string = span_holoparasite("..And draw the Hunter, an alien master of rapid assault.")
tech_fluff_string = span_holoparasite("Boot sequence complete. Charge modules loaded. Holoparasite swarm online.")
carp_fluff_string = span_holoparasite("CARP CARP CARP! Caught one! It's a charger carp, that likes running at people. But it doesn't have any legs...")
miner_fluff_string = span_holoparasite("You encounter... Titanium, a lightweight, agile fighter.")
creator_name = "Charger"
creator_desc = "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."
creator_icon = "charger"
var/charging = FALSE
var/atom/movable/screen/alert/chargealert
/mob/living/simple_animal/hostile/guardian/charger/Life(delta_time = SSMOBS_DT, times_fired)
. = ..()
if(ranged_cooldown <= world.time)
if(!COOLDOWN_FINISHED(src, ranged_cooldown))
if(!chargealert)
chargealert = throw_alert(ALERT_CHARGE, /atom/movable/screen/alert/cancharge)
else
clear_alert(ALERT_CHARGE)
chargealert = null
/mob/living/simple_animal/hostile/guardian/charger/OpenFire(atom/A)
if(!charging)
visible_message(span_danger("<b>[src]</b> [ranged_message] at [A]!"))
ranged_cooldown = world.time + ranged_cooldown_time
clear_alert(ALERT_CHARGE)
chargealert = null
Shoot(A)
/mob/living/simple_animal/hostile/guardian/charger/OpenFire(atom/target)
if(charging)
return
visible_message(span_danger("<b>[src]</b> [ranged_message] at [target]!"))
COOLDOWN_START(src, ranged_cooldown, ranged_cooldown_time)
clear_alert(ALERT_CHARGE)
chargealert = null
Shoot(target)
/mob/living/simple_animal/hostile/guardian/charger/Shoot(atom/targeted_atom)
charging = 1
charging = TRUE
throw_at(targeted_atom, range, 1, src, FALSE, TRUE, callback = CALLBACK(src, PROC_REF(charging_end)))
/mob/living/simple_animal/hostile/guardian/charger/proc/charging_end()
charging = 0
charging = FALSE
/mob/living/simple_animal/hostile/guardian/charger/Move()
if(charging)
new /obj/effect/temp_visual/decoy/fading(loc,src)
. = ..()
new /obj/effect/temp_visual/decoy/fading(loc, src)
return ..()
/mob/living/simple_animal/hostile/guardian/charger/snapback()
/mob/living/simple_animal/hostile/guardian/charger/check_distance()
if(!charging)
..()
/mob/living/simple_animal/hostile/guardian/charger/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
if(!charging)
return ..()
else if(hit_atom)
if(isliving(hit_atom) && hit_atom != summoner)
var/mob/living/L = hit_atom
var/blocked = FALSE
if(hasmatchingsummoner(hit_atom)) //if the summoner matches don't hurt them
blocked = TRUE
if(ishuman(hit_atom))
var/mob/living/carbon/human/H = hit_atom
if(H.check_shields(src, 90, "[name]", attack_type = THROWN_PROJECTILE_ATTACK))
blocked = TRUE
if(!blocked)
L.drop_all_held_items()
L.visible_message(span_danger("[src] slams into [L]!"), span_userdanger("[src] slams into you!"))
L.apply_damage(20, BRUTE)
playsound(get_turf(L), 'sound/effects/meteorimpact.ogg', 100, TRUE)
shake_camera(L, 4, 3)
shake_camera(src, 2, 3)
charging = 0
if(!isliving(hit_atom) || hit_atom == summoner || hasmatchingsummoner(hit_atom))
return
var/mob/living/hit_mob = hit_atom
if(ishuman(hit_mob))
var/mob/living/carbon/human/hit_human = hit_mob
if(hit_human.check_shields(src, 90, name, attack_type = THROWN_PROJECTILE_ATTACK))
return
hit_mob.drop_all_held_items()
hit_mob.visible_message(span_danger("[src] slams into [hit_mob]!"), span_userdanger("[src] slams into you!"))
hit_mob.apply_damage(20, BRUTE)
playsound(hit_mob, 'sound/effects/meteorimpact.ogg', 100, TRUE)
shake_camera(hit_mob, 4, 3)
shake_camera(src, 2, 3)
@@ -3,54 +3,55 @@
melee_damage_lower = 10
melee_damage_upper = 10
damage_coeff = list(BRUTE = 0.75, BURN = 0.75, TOX = 0.75, CLONE = 0.75, STAMINA = 0, OXY = 0.75)
playstyle_string = "<span class='holoparasite'>As a <b>dextrous</b> type you can hold items, store an item within yourself, and have medium damage resistance, but do low damage on attacks. Recalling and leashing will force you to drop unstored items!</span>"
magic_fluff_string = "<span class='holoparasite'>..And draw the Drone, a dextrous master of construction and repair.</span>"
tech_fluff_string = "<span class='holoparasite'>Boot sequence complete. Dextrous combat modules loaded. Holoparasite swarm online.</span>"
carp_fluff_string = "<span class='holoparasite'>CARP CARP CARP! You caught one! It can hold stuff in its fins, sort of.</span>"
miner_fluff_string = "<span class='holoparasite'>You encounter... Gold, a malleable constructor.</span>"
playstyle_string = span_holoparasite("As a <b>dextrous</b> type you can hold items, store an item within yourself, and have medium damage resistance, but do low damage on attacks. Recalling and leashing will force you to drop unstored items!")
magic_fluff_string = span_holoparasite("..And draw the Drone, a dextrous master of construction and repair.")
tech_fluff_string = span_holoparasite("Boot sequence complete. Dextrous combat modules loaded. Holoparasite swarm online.")
carp_fluff_string = span_holoparasite("CARP CARP CARP! You caught one! It can hold stuff in its fins, sort of.")
miner_fluff_string = span_holoparasite("You encounter... Gold, a malleable constructor.")
creator_name = "Dextrous"
creator_desc = "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."
creator_icon = "dextrous"
dextrous = TRUE
held_items = list(null, null)
var/obj/item/internal_storage //what we're storing within ourself
/mob/living/simple_animal/hostile/guardian/dextrous/death(gibbed)
..()
. = ..()
if(internal_storage)
dropItemToGround(internal_storage)
/mob/living/simple_animal/hostile/guardian/dextrous/examine(mob/user)
if(dextrous)
. = list("<span class='info'>This is [icon2html(src)] \a <b>[src]</b>!\n[desc]", EXAMINE_SECTION_BREAK) //SKYRAT EDIT CHANGE
for(var/obj/item/I in held_items)
if(!(I.item_flags & ABSTRACT))
. += "It has [I.get_examine_string(user)] in its [get_held_index_name(get_held_index_of_item(I))]."
for(var/obj/item/held_item in held_items)
if(!(held_item.item_flags & ABSTRACT))
. += "It has [held_item.get_examine_string(user)] in its [get_held_index_name(get_held_index_of_item(held_item))]."
if(internal_storage && !(internal_storage.item_flags & ABSTRACT))
. += "It is holding [internal_storage.get_examine_string(user)] in its internal storage."
. += "</span>"
else
return ..()
/mob/living/simple_animal/hostile/guardian/dextrous/Recall(forced)
if(!summoner || loc == summoner || (cooldown > world.time && !forced))
return FALSE
/mob/living/simple_animal/hostile/guardian/dextrous/recall_effects()
drop_all_held_items()
return ..() //lose items, then return
/mob/living/simple_animal/hostile/guardian/dextrous/snapback()
if(summoner && !(get_dist(get_turf(summoner),get_turf(src)) <= range))
drop_all_held_items()
..() //lose items, then return
/mob/living/simple_animal/hostile/guardian/dextrous/check_distance()
if(!summoner || get_dist(get_turf(summoner), get_turf(src)) <= range)
return
drop_all_held_items()
..() //lose items, then return
//SLOT HANDLING BULLSHIT FOR INTERNAL STORAGE
/mob/living/simple_animal/hostile/guardian/dextrous/doUnEquip(obj/item/I, force, newloc, no_move, invdrop = TRUE, silent = FALSE)
/mob/living/simple_animal/hostile/guardian/dextrous/doUnEquip(obj/item/equipped_item, force, newloc, no_move, invdrop = TRUE, silent = FALSE)
if(..())
update_held_items()
if(I == internal_storage)
if(equipped_item == internal_storage)
internal_storage = null
update_inv_internal_storage()
return TRUE
return FALSE
/mob/living/simple_animal/hostile/guardian/dextrous/can_equip(obj/item/I, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE)
/mob/living/simple_animal/hostile/guardian/dextrous/can_equip(obj/item/equipped_item, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE)
switch(slot)
if(ITEM_SLOT_DEX_STORAGE)
if(internal_storage)
@@ -68,13 +69,13 @@
return ITEM_SLOT_DEX_STORAGE
return ..()
/mob/living/simple_animal/hostile/guardian/dextrous/equip_to_slot(obj/item/I, slot)
/mob/living/simple_animal/hostile/guardian/dextrous/equip_to_slot(obj/item/equipped_item, slot)
if(!..())
return
switch(slot)
if(ITEM_SLOT_DEX_STORAGE)
internal_storage = I
internal_storage = equipped_item
update_inv_internal_storage()
else
to_chat(src, span_danger("You are trying to equip this item to an unsupported inventory slot. Report this to a coder!"))
@@ -4,61 +4,69 @@
UnregisterSignal(A, COMSIG_PARENT_EXAMINE); \
} while (0)
//Bomb
/mob/living/simple_animal/hostile/guardian/bomb
//Explosive
/mob/living/simple_animal/hostile/guardian/explosive
melee_damage_lower = 15
melee_damage_upper = 15
damage_coeff = list(BRUTE = 0.6, BURN = 0.6, TOX = 0.6, CLONE = 0.6, STAMINA = 0, OXY = 0.6)
range = 13
playstyle_string = "<span class='holoparasite'>As an <b>explosive</b> type, you have moderate close combat abilities and are capable of converting nearby items and objects into disguised bombs via alt click.</span>"
magic_fluff_string = "<span class='holoparasite'>..And draw the Scientist, master of explosive death.</span>"
tech_fluff_string = "<span class='holoparasite'>Boot sequence complete. Explosive modules active. Holoparasite swarm online.</span>"
carp_fluff_string = "<span class='holoparasite'>CARP CARP CARP! Caught one! It's an explosive carp! Boom goes the fishy.</span>"
miner_fluff_string = "<span class='holoparasite'>You encounter... Gibtonite, an explosive fighter.</span>"
var/bomb_cooldown = 0
playstyle_string = span_holoparasite("As an <b>explosive</b> type, you have moderate close combat abilities and are capable of converting nearby items and objects into disguised bombs via right-click.")
magic_fluff_string = span_holoparasite("..And draw the Scientist, master of explosive death.")
tech_fluff_string = span_holoparasite("Boot sequence complete. Explosive modules active. Holoparasite swarm online.")
carp_fluff_string = span_holoparasite("CARP CARP CARP! Caught one! It's an explosive carp! Boom goes the fishy.")
miner_fluff_string = span_holoparasite("You encounter... Gibtonite, an explosive fighter.")
creator_name = "Explosive"
creator_desc = "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."
creator_icon = "explosive"
/// Static list of signals that activate the boom.
var/static/list/boom_signals = list(COMSIG_PARENT_ATTACKBY, COMSIG_ATOM_BUMPED, COMSIG_ATOM_ATTACK_HAND)
/// After this amount of time passses, boom deactivates.
var/decay_time = 1 MINUTES
/// Time between bombs.
var/bomb_cooldown_time = 20 SECONDS
/// The cooldown timer between bombs.
COOLDOWN_DECLARE(bomb_cooldown)
/mob/living/simple_animal/hostile/guardian/bomb/get_status_tab_items()
/mob/living/simple_animal/hostile/guardian/explosive/get_status_tab_items()
. = ..()
if(bomb_cooldown >= world.time)
. += "Bomb Cooldown Remaining: [DisplayTimeText(bomb_cooldown - world.time)]"
if(!COOLDOWN_FINISHED(src, bomb_cooldown))
. += "Bomb Cooldown Remaining: [DisplayTimeText(COOLDOWN_TIMELEFT(src, bomb_cooldown))]"
/mob/living/simple_animal/hostile/guardian/bomb/AltClickOn(atom/movable/A)
if(!istype(A))
/mob/living/simple_animal/hostile/guardian/explosive/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers)
if(LAZYACCESS(modifiers, RIGHT_CLICK) && proximity_flag && isobj(attack_target))
plant_bomb(attack_target)
return
if(loc == summoner)
to_chat(src, span_danger("<B>You must be manifested to create bombs!</B>"))
return
if(isobj(A) && Adjacent(A))
if(bomb_cooldown <= world.time && !stat)
to_chat(src, span_danger("<B>Success! Bomb armed!</B>"))
bomb_cooldown = world.time + 200
RegisterSignal(A, COMSIG_PARENT_EXAMINE, PROC_REF(display_examine))
RegisterSignal(A, boom_signals, PROC_REF(kaboom))
addtimer(CALLBACK(src, PROC_REF(disable), A), 600, TIMER_UNIQUE|TIMER_OVERRIDE)
else
to_chat(src, span_danger("<B>Your powers are on cooldown! You must wait 20 seconds between bombs.</B>"))
return ..()
/mob/living/simple_animal/hostile/guardian/bomb/proc/kaboom(atom/source, mob/living/explodee)
/mob/living/simple_animal/hostile/guardian/explosive/proc/plant_bomb(obj/planting_on)
if(!COOLDOWN_FINISHED(src, bomb_cooldown))
to_chat(src, span_bolddanger("Your powers are on cooldown! You must wait [DisplayTimeText(COOLDOWN_TIMELEFT(src, bomb_cooldown))] between bombs."))
return
to_chat(src, span_bolddanger("Success! Bomb armed!"))
COOLDOWN_START(src, bomb_cooldown, bomb_cooldown_time)
RegisterSignal(planting_on, COMSIG_PARENT_EXAMINE, PROC_REF(display_examine))
RegisterSignal(planting_on, boom_signals, PROC_REF(kaboom))
addtimer(CALLBACK(src, PROC_REF(disable), planting_on), decay_time, TIMER_UNIQUE|TIMER_OVERRIDE)
/mob/living/simple_animal/hostile/guardian/explosive/proc/kaboom(atom/source, mob/living/explodee)
SIGNAL_HANDLER
if(!istype(explodee))
return
if(explodee == src || explodee == summoner || hasmatchingsummoner(explodee))
return
to_chat(explodee, span_danger("<B>[source] was boobytrapped!</B>"))
to_chat(src, span_danger("<B>Success! Your trap caught [explodee]</B>"))
var/turf/T = get_turf(source)
playsound(T,'sound/effects/explosion2.ogg', 200, TRUE)
new /obj/effect/temp_visual/explosion(T)
to_chat(explodee, span_bolddanger("[source] was boobytrapped!"))
to_chat(src, span_bolddanger("Success! Your trap caught [explodee]"))
playsound(source, 'sound/effects/explosion2.ogg', 200, TRUE)
new /obj/effect/temp_visual/explosion(get_turf(source))
EX_ACT(explodee, EXPLODE_HEAVY)
UNREGISTER_BOMB_SIGNALS(source)
/mob/living/simple_animal/hostile/guardian/bomb/proc/disable(atom/A)
to_chat(src, span_danger("<B>Failure! Your trap didn't catch anyone this time.</B>"))
UNREGISTER_BOMB_SIGNALS(A)
/mob/living/simple_animal/hostile/guardian/explosive/proc/disable(obj/rigged_obj)
to_chat(src, span_bolddanger("Failure! Your trap didn't catch anyone this time."))
UNREGISTER_BOMB_SIGNALS(rigged_obj)
/mob/living/simple_animal/hostile/guardian/bomb/proc/display_examine(datum/source, mob/user, text)
/mob/living/simple_animal/hostile/guardian/explosive/proc/display_examine(datum/source, mob/user, text)
SIGNAL_HANDLER
text += span_holoparasite("It glows with a strange <font color=\"[guardiancolor]\">light</font>!")
text += span_holoparasite("It glows with a strange <font color=\"[guardian_color]\">light</font>!")
#undef UNREGISTER_BOMB_SIGNALS
@@ -9,20 +9,23 @@
tech_fluff_string = span_holoparasite("Boot sequence complete. Atmospheric modules activated. Holoparasite swarm online.")
carp_fluff_string = span_holoparasite("CARP CARP CARP! You caught one! OH GOD, EVERYTHING'S ON FIRE. Except you and the fish.")
miner_fluff_string = span_holoparasite("You encounter... Plasma, the bringer of fire.")
creator_name = "Gaseous"
creator_desc = "Creates sparks on touch and continuously expels a gas of its choice. Automatically extinguishes the user if they catch on fire."
creator_icon = "gaseous"
toggle_button_type = /atom/movable/screen/guardian/toggle_mode/gases
/// Gas being expelled.
var/expelled_gas = null
/// How much gas we expel per second.
var/gas_rate = 10
/// Possible gases to expel, with their expelling multiplier.
/// Rate of temperature stabilization per second.
var/temp_stabilization_rate = 0.1
/// Possible gases to expel, with how much moles they create.
var/static/list/possible_gases = list(
/datum/gas/oxygen = 5,
/datum/gas/nitrogen = 75, //yes 75 times. overpressurizing is hard!.
/datum/gas/water_vapor = 0.1, //you need incredibly little water vapor for the effects to kick in
/datum/gas/nitrous_oxide = 1.5,
/datum/gas/carbon_dioxide = 5,
/datum/gas/plasma = 0.25,
/datum/gas/bz = 1,
/datum/gas/oxygen = 50,
/datum/gas/nitrogen = 750, //overpressurizing is hard!.
/datum/gas/water_vapor = 1, //you need incredibly little water vapor for the effects to kick in
/datum/gas/nitrous_oxide = 15,
/datum/gas/carbon_dioxide = 50,
/datum/gas/plasma = 3,
/datum/gas/bz = 10,
)
/// Gas colors, used for the particles.
var/static/list/gas_colors = list(
@@ -45,33 +48,34 @@
return
do_sparks(1, TRUE, target)
/mob/living/simple_animal/hostile/guardian/gaseous/Recall(forced)
/mob/living/simple_animal/hostile/guardian/gaseous/recall(forced)
expelled_gas = null
QDEL_NULL(particles) //need to delete before putting in another object
. = ..()
if(.)
if(. && summoner)
UnregisterSignal(summoner, COMSIG_ATOM_PRE_PRESSURE_PUSH)
/mob/living/simple_animal/hostile/guardian/gaseous/Manifest(forced)
/mob/living/simple_animal/hostile/guardian/gaseous/manifest(forced)
. = ..()
if(.)
if(. && summoner)
RegisterSignal(summoner, COMSIG_ATOM_PRE_PRESSURE_PUSH, PROC_REF(stop_pressure))
/mob/living/simple_animal/hostile/guardian/gaseous/Life(delta_time, times_fired)
. = ..()
summoner.extinguish_mob()
summoner.adjust_fire_stacks(-10 * delta_time)
summoner.adjust_bodytemperature(get_temp_change_amount((summoner.get_body_temp_normal() - summoner.bodytemperature), 0.1 * delta_time))
if(summoner)
summoner.extinguish_mob()
summoner.set_fire_stacks(0, remove_wet_stacks = FALSE)
summoner.adjust_bodytemperature(get_temp_change_amount((summoner.get_body_temp_normal() - summoner.bodytemperature), temp_stabilization_rate * delta_time))
if(!expelled_gas)
return
var/datum/gas_mixture/mix_to_spawn = new()
mix_to_spawn.add_gas(expelled_gas)
mix_to_spawn.gases[expelled_gas][MOLES] = gas_rate * possible_gases[expelled_gas] * delta_time
mix_to_spawn.gases[expelled_gas][MOLES] = possible_gases[expelled_gas] * delta_time
mix_to_spawn.temperature = T20C
var/turf/open/our_turf = get_turf(src)
our_turf.assume_air(mix_to_spawn)
/mob/living/simple_animal/hostile/guardian/gaseous/ToggleMode()
/mob/living/simple_animal/hostile/guardian/gaseous/toggle_modes()
var/list/gases = list("None")
for(var/datum/gas/gas as anything in possible_gases)
gases[initial(gas.name)] = gas
@@ -3,73 +3,89 @@
melee_damage_lower = 15
melee_damage_upper = 15
damage_coeff = list(BRUTE = 0.75, BURN = 0.75, TOX = 0.75, CLONE = 0.75, STAMINA = 0, OXY = 0.75)
playstyle_string = "<span class='holoparasite'>As a <b>gravitokinetic</b> type, you can alt click to make the gravity on the ground stronger, and punching applies this effect to a target.</span>"
magic_fluff_string = "<span class='holoparasite'>..And draw the Singularity, an anomalous force of terror.</span>"
tech_fluff_string = "<span class='holoparasite'>Boot sequence complete. Gravitokinetic modules loaded. Holoparasite swarm online.</span>"
carp_fluff_string = "<span class='holoparasite'>CARP CARP CARP! Caught one! It's a gravitokinetic carp! Now do you understand the gravity of the situation?</span>"
miner_fluff_string = "<span class='holoparasite'>You encounter... Bananium, a master of gravity business.</span>"
var/list/gravito_targets = list()
var/gravity_power_range = 10 //how close the stand must stay to the target to keep the heavy gravity
playstyle_string = span_holoparasite("As a <b>gravitokinetic</b> type, you can right-click to make the gravity on the ground stronger, and punching applies this effect to a target.")
magic_fluff_string = span_holoparasite("..And draw the Singularity, an anomalous force of terror.")
tech_fluff_string = span_holoparasite("Boot sequence complete. Gravitokinetic modules loaded. Holoparasite swarm online.")
carp_fluff_string = span_holoparasite("CARP CARP CARP! Caught one! It's a gravitokinetic carp! Now do you understand the gravity of the situation?")
miner_fluff_string = span_holoparasite("You encounter... Bananium, a master of gravity business.")
creator_name = "Gravitokinetic"
creator_desc = "Attacks will apply crushing gravity to the target. Can target the ground as well to slow targets advancing on you, but this will affect the user."
creator_icon = "gravitokinetic"
/// Targets we have applied our effects on.
var/list/gravity_targets = list()
/// Distance in which our ability works
var/gravity_power_range = 10
/// Gravity added on punches.
var/punch_gravity = 5
/// Gravity added to turfs.
var/turf_gravity = 3
/mob/living/simple_animal/hostile/guardian/gravitokinetic/Initialize(mapload, theme)
. = ..()
AddElement(/datum/element/forced_gravity, 1)
/mob/living/simple_animal/hostile/guardian/gravitokinetic/set_summoner(mob/to_who, different_person)
. = ..()
to_who.AddElement(/datum/element/forced_gravity, 1)
/mob/living/simple_animal/hostile/guardian/gravitokinetic/cut_summoner(different_person)
summoner.RemoveElement(/datum/element/forced_gravity, 1)
return ..()
///Removes gravity from affected mobs upon guardian death to prevent permanent effects
/mob/living/simple_animal/hostile/guardian/gravitokinetic/death()
. = ..()
for(var/i in gravito_targets)
remove_gravity(i)
for(var/gravity_target in gravity_targets)
remove_gravity(gravity_target)
/mob/living/simple_animal/hostile/guardian/gravitokinetic/AttackingTarget()
/mob/living/simple_animal/hostile/guardian/gravitokinetic/AttackingTarget(atom/attacked_target)
. = ..()
if(isliving(target) && target != src && target != summoner)
to_chat(src, "[span_danger("<B>Your punch has applied heavy gravity to [target]!")]</B>")
add_gravity(target, 5)
if(isliving(target) && !hasmatchingsummoner(attacked_target) && target != src && target != summoner && !gravity_targets[target])
to_chat(src, span_bolddanger("Your punch has applied heavy gravity to [target]!"))
add_gravity(target, punch_gravity)
to_chat(target, span_userdanger("Everything feels really heavy!"))
/mob/living/simple_animal/hostile/guardian/gravitokinetic/AltClickOn(atom/A)
if(isopenturf(A) && is_deployed() && stat != DEAD && in_range(src, A) && !incapacitated())
var/turf/T = A
if(isspaceturf(T))
to_chat(src, span_warning("You cannot add gravity to space!"))
return
visible_message(span_danger("[src] slams their fist into the [T]!"), span_notice("You modify the gravity of the [T]."))
do_attack_animation(T)
add_gravity(T, 3)
/mob/living/simple_animal/hostile/guardian/gravitokinetic/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers)
if(LAZYACCESS(modifiers, RIGHT_CLICK) && proximity_flag && !gravity_targets[target])
slam_turf(attack_target)
return
return ..()
/mob/living/simple_animal/hostile/guardian/gravitokinetic/Recall(forced)
. = ..()
to_chat(src, "[span_danger("<B>You have released your gravitokinetic powers!")]</B>")
for(var/i in gravito_targets)
remove_gravity(i)
/mob/living/simple_animal/hostile/guardian/gravitokinetic/proc/slam_turf(turf/open/slammed)
if(!isopenturf(slammed) || isgroundlessturf(slammed))
to_chat(src, span_warning("You cannot add gravity to this!"))
return
visible_message(span_danger("[src] slams their fist into the [slammed]!"), span_notice("You modify the gravity of the [slammed]."))
do_attack_animation(slammed)
add_gravity(slammed, turf_gravity)
/mob/living/simple_animal/hostile/guardian/gravitokinetic/Manifest(forced)
. = ..()
//just make sure to reapply a gravity immunity wherever you summon. it can be overridden but not by you at least
summoner.AddElement(/datum/element/forced_gravity, 1)
AddElement(/datum/element/forced_gravity, 1)
/mob/living/simple_animal/hostile/guardian/gravitokinetic/recall_effects()
to_chat(src, span_bolddanger("You have released your gravitokinetic powers!"))
for(var/gravity_target in gravity_targets)
remove_gravity(gravity_target)
/mob/living/simple_animal/hostile/guardian/gravitokinetic/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE)
. = ..()
for(var/i in gravito_targets)
if(get_dist(src, i) > gravity_power_range)
remove_gravity(i)
for(var/gravity_target in gravity_targets)
if(get_dist(src, gravity_target) > gravity_power_range)
remove_gravity(gravity_target)
/mob/living/simple_animal/hostile/guardian/gravitokinetic/proc/add_gravity(atom/A, new_gravity = 3)
if(gravito_targets[A])
/mob/living/simple_animal/hostile/guardian/gravitokinetic/proc/add_gravity(atom/target, new_gravity = 3)
if(gravity_targets[target])
return
A.AddElement(/datum/element/forced_gravity, new_gravity)
gravito_targets[A] = new_gravity
RegisterSignal(A, COMSIG_MOVABLE_MOVED, PROC_REF(__distance_check))
target.AddElement(/datum/element/forced_gravity, new_gravity)
gravity_targets[target] = new_gravity
RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(distance_check))
playsound(src, 'sound/effects/gravhit.ogg', 100, TRUE)
/mob/living/simple_animal/hostile/guardian/gravitokinetic/proc/remove_gravity(atom/target)
if(isnull(gravito_targets[target]))
if(isnull(gravity_targets[target]))
return
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
target.RemoveElement(/datum/element/forced_gravity, gravito_targets[target])
gravito_targets -= target
target.RemoveElement(/datum/element/forced_gravity, gravity_targets[target])
gravity_targets -= target
/mob/living/simple_animal/hostile/guardian/gravitokinetic/proc/__distance_check(atom/movable/AM, OldLoc, Dir, Forced)
/mob/living/simple_animal/hostile/guardian/gravitokinetic/proc/distance_check(atom/movable/moving_target, old_loc, dir, forced)
SIGNAL_HANDLER
if(get_dist(src, AM) > gravity_power_range)
remove_gravity(AM)
if(get_dist(src, moving_target) > gravity_power_range)
remove_gravity(moving_target)
@@ -1,10 +1,10 @@
//Beam
/obj/effect/ebeam/chain
name = "lightning chain"
layer = LYING_MOB_LAYER
plane = GAME_PLANE_FOV_HIDDEN
/mob/living/simple_animal/hostile/guardian/beam
//Lightning
/mob/living/simple_animal/hostile/guardian/lightning
melee_damage_lower = 7
melee_damage_upper = 7
attack_verb_continuous = "shocks"
@@ -13,16 +13,19 @@
attack_sound = 'sound/machines/defib_zap.ogg'
damage_coeff = list(BRUTE = 0.7, BURN = 0.7, TOX = 0.7, CLONE = 0.7, STAMINA = 0, OXY = 0.7)
range = 7
playstyle_string = "<span class='holoparasite'>As a <b>lightning</b> type, you will apply lightning chains to targets on attack and have a lightning chain to your summoner. Lightning chains will shock anyone near them.</span>"
magic_fluff_string = "<span class='holoparasite'>..And draw the Tesla, a shocking, lethal source of power.</span>"
tech_fluff_string = "<span class='holoparasite'>Boot sequence complete. Lightning modules active. Holoparasite swarm online.</span>"
carp_fluff_string = "<span class='holoparasite'>CARP CARP CARP! Caught one! It's a lightning carp! Everyone else goes zap zap.</span>"
miner_fluff_string = "<span class='holoparasite'>You encounter... Iron, a conductive master of lightning.</span>"
playstyle_string = span_holoparasite("As a <b>lightning</b> type, you will apply lightning chains to targets on attack and have a lightning chain to your summoner. Lightning chains will shock anyone near them.")
magic_fluff_string = span_holoparasite("..And draw the Tesla, a shocking, lethal source of power.")
tech_fluff_string = span_holoparasite("Boot sequence complete. Lightning modules active. Holoparasite swarm online.")
carp_fluff_string = span_holoparasite("CARP CARP CARP! Caught one! It's a lightning carp! Everyone else goes zap zap.")
miner_fluff_string = span_holoparasite("You encounter... Iron, a conductive master of lightning.")
creator_name = "Lightning"
creator_desc = "Attacks apply lightning chains to targets. Has a lightning chain to the user. Lightning chains shock everything near them, doing constant damage."
creator_icon = "lightning"
var/datum/beam/summonerchain
var/list/enemychains = list()
var/successfulshocks = 0
/mob/living/simple_animal/hostile/guardian/beam/AttackingTarget()
/mob/living/simple_animal/hostile/guardian/lightning/AttackingTarget(atom/attacked_target)
. = ..()
if(. && isliving(target) && target != src && target != summoner)
cleardeletedchains()
@@ -36,28 +39,19 @@
enemychains -= C
enemychains += Beam(target, "lightning[rand(1,12)]", maxdistance=7, beam_type=/obj/effect/ebeam/chain)
/mob/living/simple_animal/hostile/guardian/beam/Destroy()
/mob/living/simple_animal/hostile/guardian/lightning/manifest_effects()
summonerchain = Beam(summoner, "lightning[rand(1,12)]", beam_type=/obj/effect/ebeam/chain)
while(loc != summoner)
if(successfulshocks > 5)
successfulshocks = 0
if(shockallchains())
successfulshocks++
SLEEP_CHECK_DEATH(3, src)
/mob/living/simple_animal/hostile/guardian/lightning/recall_effects()
removechains()
return ..()
/mob/living/simple_animal/hostile/guardian/beam/Manifest()
. = ..()
if(.)
if(summoner)
summonerchain = Beam(summoner, "lightning[rand(1,12)]", beam_type=/obj/effect/ebeam/chain)
while(loc != summoner)
if(successfulshocks > 5)
successfulshocks = 0
if(shockallchains())
successfulshocks++
SLEEP_CHECK_DEATH(3, src)
/mob/living/simple_animal/hostile/guardian/beam/Recall()
. = ..()
if(.)
removechains()
/mob/living/simple_animal/hostile/guardian/beam/proc/cleardeletedchains()
/mob/living/simple_animal/hostile/guardian/lightning/proc/cleardeletedchains()
if(summonerchain && QDELETED(summonerchain))
summonerchain = null
if(enemychains.len)
@@ -66,7 +60,7 @@
if(!chain || QDELETED(cd))
enemychains -= chain
/mob/living/simple_animal/hostile/guardian/beam/proc/shockallchains()
/mob/living/simple_animal/hostile/guardian/lightning/proc/shockallchains()
. = 0
cleardeletedchains()
if(summoner)
@@ -77,7 +71,7 @@
for(var/chain in enemychains)
. += chainshock(chain)
/mob/living/simple_animal/hostile/guardian/beam/proc/removechains()
/mob/living/simple_animal/hostile/guardian/lightning/proc/removechains()
if(summonerchain)
qdel(summonerchain)
summonerchain = null
@@ -86,7 +80,7 @@
qdel(chain)
enemychains = list()
/mob/living/simple_animal/hostile/guardian/beam/proc/chainshock(datum/beam/B)
/mob/living/simple_animal/hostile/guardian/lightning/proc/chainshock(datum/beam/B) //fuck you, fuck this
. = 0
var/list/turfs = list()
for(var/E in B.elements)
@@ -4,13 +4,20 @@
melee_damage_upper = 15
range = 15 //worse for it due to how it leashes
damage_coeff = list(BRUTE = 0.4, BURN = 0.4, TOX = 0.4, CLONE = 0.4, STAMINA = 0, OXY = 0.4)
playstyle_string = "<span class='holoparasite'>As a <b>protector</b> type you cause your summoner to leash to you instead of you leashing to them and have two modes; Combat Mode, where you do and take medium damage, and Protection Mode, where you do and take almost no damage, but move slightly slower.</span>"
magic_fluff_string = "<span class='holoparasite'>..And draw the Guardian, a stalwart protector that never leaves the side of its charge.</span>"
tech_fluff_string = "<span class='holoparasite'>Boot sequence complete. Protector modules loaded. Holoparasite swarm online.</span>"
carp_fluff_string = "<span class='holoparasite'>CARP CARP CARP! You caught one! Wait, no... it caught you! The fisher has become the fishy.</span>"
miner_fluff_string = "<span class='holoparasite'>You encounter... Uranium, a very resistant guardian.</span>"
playstyle_string = span_holoparasite("As a <b>protector</b> type you cause your summoner to leash to you instead of you leashing to them and have two modes; Combat Mode, where you do and take medium damage, and Protection Mode, where you do and take almost no damage, but move slightly slower.")
magic_fluff_string = span_holoparasite("..And draw the Guardian, a stalwart protector that never leaves the side of its charge.")
tech_fluff_string = span_holoparasite("Boot sequence complete. Protector modules loaded. Holoparasite swarm online.")
carp_fluff_string = span_holoparasite("CARP CARP CARP! You caught one! Wait, no... it caught you! The fisher has become the fishy.")
miner_fluff_string = span_holoparasite("You encounter... Uranium, a very resistant guardian.")
creator_name = "Protector"
creator_desc = "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."
creator_icon = "protector"
toggle_button_type = /atom/movable/screen/guardian/toggle_mode
/// Damage removed in protecting mode.
var/damage_penalty = 13
/// Is it in protecting mode?
var/toggle = FALSE
/// Overlay of our protection shield.
var/mutable_appearance/shield_overlay
/mob/living/simple_animal/hostile/guardian/protector/ex_act(severity)
@@ -26,48 +33,44 @@
/mob/living/simple_animal/hostile/guardian/protector/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
. = ..()
if(. > 0 && toggle)
var/image/I = new('icons/effects/effects.dmi', src, "shield-flash", MOB_LAYER+0.01, dir = pick(GLOB.cardinals))
if(guardiancolor)
I.color = guardiancolor
flick_overlay_view(I, 5)
var/image/flash_overlay = new('icons/effects/effects.dmi', src, "shield-flash", layer+0.01, dir = pick(GLOB.cardinals))
flash_overlay.color = guardian_color
flick_overlay_view(flash_overlay, 0.5 SECONDS)
/mob/living/simple_animal/hostile/guardian/protector/ToggleMode()
if(cooldown > world.time)
return 0
cooldown = world.time + 10
/mob/living/simple_animal/hostile/guardian/protector/toggle_modes()
if(COOLDOWN_FINISHED(src, manifest_cooldown))
return
COOLDOWN_START(src, manifest_cooldown, 1 SECONDS)
if(toggle)
cut_overlay(shield_overlay)
melee_damage_lower = initial(melee_damage_lower)
melee_damage_upper = initial(melee_damage_upper)
melee_damage_lower += damage_penalty
melee_damage_upper += damage_penalty
speed = initial(speed)
damage_coeff = list(BRUTE = 0.4, BURN = 0.4, TOX = 0.4, CLONE = 0.4, STAMINA = 0, OXY = 0.4)
to_chat(src, "[span_danger("<B>You switch to combat mode.")]</B>")
to_chat(src, span_bolddanger("You switch to combat mode."))
toggle = FALSE
else
if(!shield_overlay)
shield_overlay = mutable_appearance('icons/effects/effects.dmi', "shield-grey")
if(guardiancolor)
shield_overlay.color = guardiancolor
shield_overlay.color = guardian_color
add_overlay(shield_overlay)
melee_damage_lower = 2
melee_damage_upper = 2
melee_damage_lower -= damage_penalty
melee_damage_upper -= damage_penalty
speed = 1
damage_coeff = list(BRUTE = 0.05, BURN = 0.05, TOX = 0.05, CLONE = 0.05, STAMINA = 0, OXY = 0.05) //damage? what's damage?
to_chat(src, "[span_danger("<B>You switch to protection mode.")]</B>")
to_chat(src, span_bolddanger("You switch to protection mode."))
toggle = TRUE
/mob/living/simple_animal/hostile/guardian/protector/snapback() //snap to what? snap to the guardian!
if(summoner)
if(get_dist(get_turf(summoner),get_turf(src)) <= range)
return
else
if(istype(summoner.loc, /obj/effect))
to_chat(src, span_holoparasite("You moved out of range, and were pulled back! You can only move [range] meters from [summoner.real_name]!"))
visible_message(span_danger("\The [src] jumps back to its user."))
Recall(TRUE)
else
to_chat(summoner, span_holoparasite("You moved out of range, and were pulled back! You can only move [range] meters from <font color=\"[guardiancolor]\"><b>[real_name]</b></font>!"))
summoner.visible_message(span_danger("\The [summoner] jumps back to [summoner.p_their()] protector."))
new /obj/effect/temp_visual/guardian/phase/out(get_turf(summoner))
summoner.forceMove(get_turf(src))
new /obj/effect/temp_visual/guardian/phase(get_turf(summoner))
/mob/living/simple_animal/hostile/guardian/protector/check_distance() //snap to what? snap to the guardian!
if(!summoner || get_dist(summoner, src) <= range)
return
if(istype(summoner.loc, /obj/effect))
to_chat(src, span_holoparasite("You moved out of range, and were pulled back! You can only move [range] meters from [summoner.real_name]!"))
visible_message(span_danger("\The [src] jumps back to its user."))
recall(forced = TRUE)
return
to_chat(summoner, span_holoparasite("You moved out of range, and were pulled back! You can only move [range] meters from <font color=\"[guardian_color]\"><b>[real_name]</b></font>!"))
summoner.visible_message(span_danger("\The [summoner] jumps back to [summoner.p_their()] protector."))
new /obj/effect/temp_visual/guardian/phase/out(get_turf(summoner))
summoner.forceMove(get_turf(src))
new /obj/effect/temp_visual/guardian/phase(get_turf(summoner))
@@ -18,50 +18,66 @@
projectilesound = 'sound/effects/hit_on_shattered_glass.ogg'
ranged = 1
range = 13
playstyle_string = "<span class='holoparasite'>As a <b>ranged</b> type, you have only light damage resistance, but are capable of spraying shards of crystal at incredibly high speed. You can also deploy surveillance snares to monitor enemy movement. Finally, you can switch to scout mode, in which you can't attack, but can move without limit.</span>"
magic_fluff_string = "<span class='holoparasite'>..And draw the Sentinel, an alien master of ranged combat.</span>"
tech_fluff_string = "<span class='holoparasite'>Boot sequence complete. Ranged combat modules active. Holoparasite swarm online.</span>"
carp_fluff_string = "<span class='holoparasite'>CARP CARP CARP! Caught one, it's a ranged carp. This fishy can watch people pee in the ocean.</span>"
miner_fluff_string = "<span class='holoparasite'>You encounter... Diamond, a powerful projectile thrower.</span>"
playstyle_string = span_holoparasite("As a <b>ranged</b> type, you have only light damage resistance, but are capable of spraying shards of crystal at incredibly high speed. You can also deploy surveillance snares to monitor enemy movement. Finally, you can switch to scout mode, in which you can't attack, but can move without limit.")
magic_fluff_string = span_holoparasite("..And draw the Sentinel, an alien master of ranged combat.")
tech_fluff_string = span_holoparasite("Boot sequence complete. Ranged combat modules active. Holoparasite swarm online.")
carp_fluff_string = span_holoparasite("CARP CARP CARP! Caught one, it's a ranged carp. This fishy can watch people pee in the ocean.")
miner_fluff_string = span_holoparasite("You encounter... Diamond, a powerful projectile thrower.")
creator_name = "Ranged"
creator_desc = "Has two modes. Ranged; which fires a constant stream of weak, armor-ignoring projectiles. Scout; where it 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."
creator_icon = "ranged"
see_invisible = SEE_INVISIBLE_LIVING
see_in_dark = NIGHTVISION_FOV_RANGE
toggle_button_type = /atom/movable/screen/guardian/toggle_mode
/// List of all deployed snares.
var/list/snares = list()
/// Is it in scouting mode?
var/toggle = FALSE
/// Maximum snares deployed at once.
var/max_snares = 6
/// Lower damage before scouting.
var/previous_lower_damage = 0
/// Upper damage before scouting.
var/previous_upper_damage = 0
/mob/living/simple_animal/hostile/guardian/ranged/ToggleMode()
if(loc == summoner)
if(toggle)
ranged = initial(ranged)
melee_damage_lower = initial(melee_damage_lower)
melee_damage_upper = initial(melee_damage_upper)
obj_damage = initial(obj_damage)
environment_smash = initial(environment_smash)
alpha = 255
range = initial(range)
to_chat(src, "[span_danger("<B>You switch to combat mode.")]</B>")
toggle = FALSE
else
ranged = 0
melee_damage_lower = 0
melee_damage_upper = 0
obj_damage = 0
environment_smash = ENVIRONMENT_SMASH_NONE
alpha = 45
range = 255
to_chat(src, "[span_danger("<B>You switch to scout mode.")]</B>")
toggle = TRUE
/mob/living/simple_animal/hostile/guardian/ranged/toggle_modes()
if(is_deployed() && summoner)
to_chat(src, span_bolddanger("You have to be recalled to toggle modes!"))
return
if(toggle)
ranged = initial(ranged)
melee_damage_lower = previous_lower_damage
melee_damage_upper = previous_upper_damage
previous_lower_damage = 0
previous_upper_damage = 0
obj_damage = initial(obj_damage)
environment_smash = initial(environment_smash)
alpha = 255
range = initial(range)
to_chat(src, span_bolddanger("You switch to combat mode."))
toggle = FALSE
else
to_chat(src, "[span_danger("<B>You have to be recalled to toggle modes!")]</B>")
ranged = 0
previous_lower_damage = melee_damage_lower
melee_damage_lower = 0
previous_upper_damage = melee_damage_upper
melee_damage_upper = 0
obj_damage = 0
environment_smash = ENVIRONMENT_SMASH_NONE
alpha = 45
range = 255
to_chat(src, span_bolddanger("You switch to scout mode."))
toggle = TRUE
/mob/living/simple_animal/hostile/guardian/ranged/Shoot(atom/targeted_atom)
. = ..()
if(istype(., /obj/projectile))
var/obj/projectile/P = .
if(guardiancolor)
P.color = guardiancolor
if(!istype(., /obj/projectile))
return
var/obj/projectile/shot_projectile = .
shot_projectile.color = guardian_color
/mob/living/simple_animal/hostile/guardian/ranged/ToggleLight()
/mob/living/simple_animal/hostile/guardian/ranged/toggle_light()
var/msg
switch(lighting_alpha)
if (LIGHTING_PLANE_ALPHA_VISIBLE)
@@ -76,55 +92,68 @@
else
lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE
msg = "You deactivate your night vision."
to_chat(src, span_notice("[msg]"))
sync_lighting_plane_alpha()
to_chat(src, span_notice(msg))
/mob/living/simple_animal/hostile/guardian/ranged/verb/Snare()
set name = "Set Surveillance Snare"
set category = "Guardian"
set desc = "Set an invisible snare that will alert you when living creatures walk over it. Max of 5"
if(length(snares) < 6)
var/turf/snare_loc = get_turf(loc)
var/obj/effect/snare/S = new /obj/effect/snare(snare_loc)
S.spawner = src
S.name = "[get_area(snare_loc)] snare ([rand(1, 1000)])"
snares |= S
to_chat(src, "[span_danger("<B>Surveillance snare deployed!")]</B>")
if(length(snares) < max_snares)
var/turf/snare_loc = get_turf(src)
var/obj/effect/snare/new_snare = new /obj/effect/snare(snare_loc, src)
new_snare.name = "[get_area(snare_loc)] snare ([rand(1, 1000)])"
snares += new_snare
to_chat(src, span_bolddanger("Surveillance snare deployed!"))
else
to_chat(src, "[span_danger("<B>You have too many snares deployed. Remove some first.")]</B>")
to_chat(src, span_bolddanger("You have too many snares deployed. Remove some first."))
/mob/living/simple_animal/hostile/guardian/ranged/verb/DisarmSnare()
set name = "Remove Surveillance Snare"
set category = "Guardian"
set desc = "Disarm unwanted surveillance snares."
var/picked_snare = tgui_input_list(src, "Pick which snare to remove", "Remove Snare", sort_names(snares))
var/picked_snare = tgui_input_list(src, "Pick which snare to remove.", "Remove Snare", sort_names(snares))
if(isnull(picked_snare))
return
snares -= picked_snare
qdel(picked_snare)
to_chat(src, "[span_danger("<B>Snare disarmed.")]</B>")
to_chat(src, span_bolddanger("Snare disarmed."))
/obj/effect/snare
name = "snare"
desc = "You shouldn't be seeing this!"
var/mob/living/simple_animal/hostile/guardian/spawner
invisibility = INVISIBILITY_ABSTRACT
var/datum/weakref/guardian_ref
/obj/effect/snare/Initialize(mapload)
/obj/effect/snare/Initialize(mapload, spawning_guardian)
. = ..()
guardian_ref = WEAKREF(spawning_guardian)
var/static/list/loc_connections = list(
COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
)
AddElement(/datum/element/connect_loc, loc_connections)
/obj/effect/snare/proc/on_entered(datum/source, AM as mob|obj)
/obj/effect/snare/Destroy(force)
var/mob/living/simple_animal/hostile/guardian/ranged/spawning_guardian = guardian_ref?.resolve()
if(spawning_guardian)
spawning_guardian.snares -= src
return ..()
/obj/effect/snare/proc/on_entered(datum/source, crossed_object)
SIGNAL_HANDLER
if(isliving(AM) && spawner && spawner.summoner && AM != spawner && !spawner.hasmatchingsummoner(AM))
to_chat(spawner.summoner, "[span_danger("<B>[AM] has crossed surveillance snare, [name].")]</B>")
var/list/guardians = spawner.summoner.get_all_linked_holoparasites()
for(var/para in guardians)
to_chat(para, "[span_danger("<B>[AM] has crossed surveillance snare, [name].")]</B>")
var/mob/living/simple_animal/hostile/guardian/ranged/spawning_guardian = guardian_ref?.resolve()
if(!spawning_guardian)
qdel(src)
return
if(!isliving(crossed_object) || crossed_object == spawning_guardian || spawning_guardian.hasmatchingsummoner(crossed_object))
return
send_message(spawning_guardian.summoner || spawning_guardian, crossed_object)
/obj/effect/snare/proc/send_message(mob/living/recipient, crossed_object)
to_chat(recipient, span_bolddanger("[crossed_object] has crossed [name]."))
var/list/guardians = recipient.get_all_linked_holoparasites()
for(var/guardian in guardians)
send_message(guardian, crossed_object)
/obj/effect/snare/singularity_act()
return
@@ -132,17 +161,15 @@
/obj/effect/snare/singularity_pull()
return
/mob/living/simple_animal/hostile/guardian/ranged/Manifest(forced)
if (toggle)
/mob/living/simple_animal/hostile/guardian/ranged/manifest_effects()
if(toggle)
incorporeal_move = INCORPOREAL_MOVE_BASIC
. = ..()
/mob/living/simple_animal/hostile/guardian/ranged/Recall(forced)
/mob/living/simple_animal/hostile/guardian/ranged/recall_effects()
// To stop scout mode from moving when recalled
incorporeal_move = FALSE
. = ..()
/mob/living/simple_animal/hostile/guardian/ranged/AttackingTarget()
/mob/living/simple_animal/hostile/guardian/ranged/AttackingTarget(atom/attacked_target)
if(toggle)
return
..()
return ..()
@@ -1,18 +1,23 @@
//Standard
/mob/living/simple_animal/hostile/guardian/punch
/mob/living/simple_animal/hostile/guardian/standard
damage_coeff = list(BRUTE = 0.5, BURN = 0.5, TOX = 0.5, CLONE = 0.5, STAMINA = 0, OXY = 0.5)
melee_damage_lower = 20
melee_damage_upper = 20
obj_damage = 80
next_move_modifier = 0.8 //attacks 20% faster
environment_smash = ENVIRONMENT_SMASH_WALLS
playstyle_string = "<span class='holoparasite'>As a <b>standard</b> type you have no special abilities, but have a high damage resistance and a powerful attack capable of smashing through walls.</span>"
magic_fluff_string = "<span class='holoparasite'>..And draw the Assistant, faceless and generic, but never to be underestimated.</span>"
tech_fluff_string = "<span class='holoparasite'>Boot sequence complete. Standard combat modules loaded. Holoparasite swarm online.</span>"
carp_fluff_string = "<span class='holoparasite'>CARP CARP CARP! You caught one! It's really boring and standard. Better punch some walls to ease the tension.</span>"
miner_fluff_string = "<span class='holoparasite'>You encounter... Adamantine, a powerful attacker.</span>"
playstyle_string = span_holoparasite("As a <b>standard</b> type you have no special abilities, but have a high damage resistance and a powerful attack capable of smashing through walls.")
magic_fluff_string = span_holoparasite("..And draw the Assistant, faceless and generic, but never to be underestimated.")
tech_fluff_string = span_holoparasite("Boot sequence complete. Standard combat modules loaded. Holoparasite swarm online.")
carp_fluff_string = span_holoparasite("CARP CARP CARP! You caught one! It's really boring and standard. Better punch some walls to ease the tension.")
miner_fluff_string = span_holoparasite("You encounter... Adamantine, a powerful attacker.")
creator_name = "Standard"
creator_desc = "Devastating close combat attacks and high damage resistance. Can smash through weak walls."
creator_icon = "standard"
/// The text we shout when attacking.
var/battlecry = "AT"
/mob/living/simple_animal/hostile/guardian/punch/verb/Battlecry()
/mob/living/simple_animal/hostile/guardian/standard/verb/Battlecry()
set name = "Set Battlecry"
set category = "Guardian"
set desc = "Choose what you shout as you punch people."
@@ -20,13 +25,16 @@
if(input)
battlecry = input
/mob/living/simple_animal/hostile/guardian/punch/AttackingTarget()
/mob/living/simple_animal/hostile/guardian/standard/AttackingTarget(atom/attacked_target)
. = ..()
if(isliving(target))
say("[battlecry][battlecry][battlecry][battlecry][battlecry][battlecry][battlecry][battlecry][battlecry][battlecry]!!", ignore_spam = TRUE)
playsound(loc, src.attack_sound, 50, TRUE, TRUE)
playsound(loc, src.attack_sound, 50, TRUE, TRUE)
playsound(loc, src.attack_sound, 50, TRUE, TRUE)
playsound(loc, src.attack_sound, 50, TRUE, TRUE)
if(!isliving(target) || attacked_target == src)
return
var/msg = ""
for(var/i in 1 to 9)
msg += battlecry
say("[msg]!!", ignore_spam = TRUE)
for(var/j in 1 to 4)
addtimer(CALLBACK(src, PROC_REF(do_attack_sound), target.loc), j)
/mob/living/simple_animal/hostile/guardian/standard/proc/do_attack_sound(atom/playing_from)
playsound(playing_from, attack_sound, 50, TRUE, TRUE)
@@ -1,77 +1,66 @@
//Healer
/mob/living/simple_animal/hostile/guardian/healer
combat_mode = TRUE
friendly_verb_continuous = "heals"
friendly_verb_simple = "heal"
//Support
/mob/living/simple_animal/hostile/guardian/support
speed = 0
damage_coeff = list(BRUTE = 0.7, BURN = 0.7, TOX = 0.7, CLONE = 0.7, STAMINA = 0, OXY = 0.7)
melee_damage_lower = 15
melee_damage_upper = 15
playstyle_string = "<span class='holoparasite'>As a <b>support</b> type, you may toggle your basic attacks to a healing mode. In addition, Alt-Clicking on an adjacent object or mob will warp them to your bluespace beacon after a short delay.</span>"
magic_fluff_string = "<span class='holoparasite'>..And draw the CMO, a potent force of life... and death.</span>"
carp_fluff_string = "<span class='holoparasite'>CARP CARP CARP! You caught a support carp. It's a kleptocarp!</span>"
tech_fluff_string = "<span class='holoparasite'>Boot sequence complete. Support modules active. Holoparasite swarm online.</span>"
miner_fluff_string = "<span class='holoparasite'>You encounter... Bluespace, the master of support.</span>"
toggle_button_type = /atom/movable/screen/guardian/toggle_mode
var/obj/structure/receiving_pad/beacon
var/beacon_cooldown = 0
playstyle_string = span_holoparasite("As a <b>support</b> type, you may right-click to heal targets. In addition, alt-clicking on an adjacent object or mob will warp them to your bluespace beacon after a short delay.")
magic_fluff_string = span_holoparasite("..And draw the Chief Medical Officer, a potent force of life... and death.")
carp_fluff_string = span_holoparasite("CARP CARP CARP! You caught a support carp. It's a kleptocarp!")
tech_fluff_string = span_holoparasite("Boot sequence complete. Support modules active. Holoparasite swarm online.")
miner_fluff_string = span_holoparasite("You encounter... Bluespace, the master of support.")
creator_name = "Support"
creator_desc = "Does medium damage, but can heal its targets and create beacons to teleport people and things to."
creator_icon = "support"
/// Is it in healing mode?
var/toggle = FALSE
/// How much we heal per hit.
var/healing_amount = 5
/// Our teleportation beacon.
var/obj/structure/receiving_pad/beacon
/// Time it takes to teleport.
var/teleporting_time = 6 SECONDS
/// Time between creating beacons.
var/beacon_cooldown_time = 5 MINUTES
/// Cooldown between creating beacons.
COOLDOWN_DECLARE(beacon_cooldown)
/mob/living/simple_animal/hostile/guardian/healer/Initialize(mapload)
/mob/living/simple_animal/hostile/guardian/support/Initialize(mapload)
. = ..()
var/datum/atom_hud/medsensor = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
medsensor.show_to(src)
/mob/living/simple_animal/hostile/guardian/healer/get_status_tab_items()
/mob/living/simple_animal/hostile/guardian/support/get_status_tab_items()
. = ..()
if(beacon_cooldown >= world.time)
. += "Beacon Cooldown Remaining: [DisplayTimeText(beacon_cooldown - world.time)]"
if(!COOLDOWN_FINISHED(src, beacon_cooldown))
. += "Beacon Cooldown Remaining: [DisplayTimeText(COOLDOWN_TIMELEFT(src, beacon_cooldown))]"
/mob/living/simple_animal/hostile/guardian/healer/AttackingTarget()
. = ..()
if(is_deployed() && toggle && iscarbon(target))
var/mob/living/carbon/C = target
C.adjustBruteLoss(-5)
C.adjustFireLoss(-5)
C.adjustOxyLoss(-5)
C.adjustToxLoss(-5)
var/obj/effect/temp_visual/heal/H = new /obj/effect/temp_visual/heal(get_turf(C))
if(guardiancolor)
H.color = guardiancolor
if(C == summoner)
update_health_hud()
med_hud_set_health()
med_hud_set_status()
/mob/living/simple_animal/hostile/guardian/support/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers)
if(LAZYACCESS(modifiers, RIGHT_CLICK) && proximity_flag && isliving(attack_target))
heal_target(attack_target)
return
return ..()
/mob/living/simple_animal/hostile/guardian/healer/ToggleMode()
if(src.loc == summoner)
if(toggle)
set_combat_mode(TRUE)
speed = 0
damage_coeff = list(BRUTE = 0.7, BURN = 0.7, TOX = 0.7, CLONE = 0.7, STAMINA = 0, OXY = 0.7)
melee_damage_lower = 15
melee_damage_upper = 15
to_chat(src, "[span_danger("<B>You switch to combat mode.")]</B>")
toggle = FALSE
else
set_combat_mode(FALSE)
speed = 1
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
melee_damage_lower = 0
melee_damage_upper = 0
to_chat(src, "[span_danger("<B>You switch to healing mode.")]</B>")
toggle = TRUE
else
to_chat(src, "[span_danger("<B>You have to be recalled to toggle modes!")]</B>")
/mob/living/simple_animal/hostile/guardian/support/proc/heal_target(mob/living/target)
do_attack_animation(target, ATTACK_EFFECT_PUNCH)
target.visible_message(span_notice("[src] heals [target]!"),\
span_userdanger("[src] heals you!"), null, COMBAT_MESSAGE_RANGE, src)
to_chat(src, span_notice("You heal [target]!"))
playsound(target, attack_sound, 50, TRUE, TRUE, frequency = -1) //play punch in REVERSE
target.adjustBruteLoss(-healing_amount)
target.adjustFireLoss(-healing_amount)
target.adjustOxyLoss(-healing_amount)
target.adjustToxLoss(-healing_amount)
var/obj/effect/temp_visual/heal/heal_effect = new /obj/effect/temp_visual/heal(get_turf(target))
heal_effect.color = guardian_color
/mob/living/simple_animal/hostile/guardian/healer/verb/Beacon()
/mob/living/simple_animal/hostile/guardian/support/verb/Beacon()
set name = "Place Bluespace Beacon"
set category = "Guardian"
set desc = "Mark a floor as your beacon point, allowing you to warp targets to it. Your beacon will not work at extreme distances."
if(beacon_cooldown >= world.time)
to_chat(src, "[span_danger("<B>Your power is on cooldown. You must wait five minutes between placing beacons.")]</B>")
if(!COOLDOWN_FINISHED(src, beacon_cooldown))
to_chat(src, span_bolddanger("Your power is on cooldown. You must wait five minutes between placing beacons."))
return
var/turf/beacon_loc = get_turf(src.loc)
@@ -84,9 +73,9 @@
beacon = new(beacon_loc, src)
to_chat(src, "[span_danger("<B>Beacon placed! You may now warp targets and objects to it, including your user, via Alt+Click.")]</B>")
to_chat(src, span_bolddanger("Beacon placed! You may now warp targets and objects to it, including your user, via Alt+Click."))
beacon_cooldown = world.time + 3000
COOLDOWN_START(src, beacon_cooldown, beacon_cooldown_time)
/obj/structure/receiving_pad
name = "bluespace receiving pad"
@@ -99,50 +88,51 @@
plane = FLOOR_PLANE
layer = ABOVE_OPEN_TURF_LAYER
/obj/structure/receiving_pad/New(loc, mob/living/simple_animal/hostile/guardian/healer/G)
/obj/structure/receiving_pad/New(loc, mob/living/simple_animal/hostile/guardian/spawning_guardian)
. = ..()
if(G?.guardiancolor)
add_atom_colour(G.guardiancolor, FIXED_COLOUR_PRIORITY)
add_atom_colour(spawning_guardian?.guardian_color, FIXED_COLOUR_PRIORITY)
/obj/structure/receiving_pad/proc/disappear()
visible_message(span_notice("[src] vanishes!"))
qdel(src)
/mob/living/simple_animal/hostile/guardian/healer/AltClickOn(atom/movable/A)
if(!istype(A))
return
if(src.loc == summoner)
to_chat(src, "[span_danger("<B>You must be manifested to warp a target!")]</B>")
/mob/living/simple_animal/hostile/guardian/support/AltClickOn(atom/movable/target)
teleport_to_beacon(target)
/mob/living/simple_animal/hostile/guardian/support/proc/teleport_to_beacon(atom/movable/teleport_target)
if(!istype(teleport_target))
return
if(!beacon)
to_chat(src, "[span_danger("<B>You need a beacon placed to warp things!")]</B>")
to_chat(src, span_bolddanger("You need a beacon placed to warp things!"))
return
if(!Adjacent(A))
to_chat(src, "[span_danger("<B>You must be adjacent to your target!")]</B>")
if(!is_deployed())
to_chat(src, span_bolddanger("You must be manifested to warp a target!"))
return
if(A.anchored)
to_chat(src, "[span_danger("<B>Your target cannot be anchored!")]</B>")
if(!Adjacent(teleport_target))
to_chat(src, span_bolddanger("You must be adjacent to your target!"))
return
var/turf/T = get_turf(A)
if(beacon.z != T.z)
to_chat(src, "[span_danger("<B>The beacon is too far away to warp to!")]</B>")
if(teleport_target.anchored)
to_chat(src, span_bolddanger("Your target is anchored!"))
return
to_chat(src, "[span_danger("<B>You begin to warp [A].")]</B>")
A.visible_message(span_danger("[A] starts to glow faintly!"), \
var/turf/target_turf = get_turf(teleport_target)
if(beacon.z != target_turf.z)
to_chat(src, span_bolddanger("The beacon is too far away to warp to!"))
return
to_chat(src, span_bolddanger("You begin to warp [teleport_target]."))
teleport_target.visible_message(span_danger("[teleport_target] starts to glow faintly!"), \
span_userdanger("You start to faintly glow, and you feel strangely weightless!"))
do_attack_animation(A)
if(!do_mob(src, A, 60)) //now start the channel
to_chat(src, "[span_danger("<B>You need to hold still!")]</B>")
do_attack_animation(teleport_target)
playsound(teleport_target, attack_sound, 50, TRUE, TRUE, frequency = -1) //play punch in REVERSE
if(!do_mob(src, teleport_target, teleporting_time)) //now start the channel
to_chat(src, span_bolddanger("You need to hold still!"))
return
new /obj/effect/temp_visual/guardian/phase/out(T)
if(isliving(A))
var/mob/living/L = A
L.flash_act()
A.visible_message(span_danger("[A] disappears in a flash of light!"), \
span_userdanger("Your vision is obscured by a flash of light!"))
do_teleport(A, beacon, 0, channel = TELEPORT_CHANNEL_BLUESPACE)
new /obj/effect/temp_visual/guardian/phase(get_turf(A))
new /obj/effect/temp_visual/guardian/phase/out(target_turf)
if(isliving(teleport_target))
var/mob/living/living_target = teleport_target
living_target.flash_act()
teleport_target.visible_message(
span_danger("[teleport_target] disappears in a flash of light!"), \
span_userdanger("Your vision is obscured by a flash of light!"), \
)
do_teleport(teleport_target, beacon, 0, channel = TELEPORT_CHANNEL_BLUESPACE)
new /obj/effect/temp_visual/guardian/phase(get_turf(teleport_target))
@@ -141,12 +141,20 @@
item_flags = NOBLUDGEON
w_class = WEIGHT_CLASS_NORMAL
layer = MOB_LAYER
var/static/list/fugu_blacklist
/obj/item/fugu_gland/Initialize(mapload)
. = ..()
if(!fugu_blacklist)
fugu_blacklist = typecacheof(list(
/mob/living/simple_animal/hostile/guardian,
))
/obj/item/fugu_gland/afterattack(atom/target, mob/user, proximity_flag)
. = ..()
if(!proximity_flag)
return
if(!isanimal(target))
if(!isanimal(target) || fugu_blacklist[target.type])
return
var/mob/living/simple_animal/animal = target
+8
View File
@@ -473,3 +473,11 @@
if(!istype(player, /client))
return
return player
/proc/health_percentage(mob/living/mob)
var/divided_health = mob.health / mob.maxHealth
if(iscyborg(mob) || islarva(mob))
divided_health = (mob.health + mob.maxHealth) / (mob.maxHealth * 2)
else if(iscarbon(mob) || isAI(mob) || isbrain(mob))
divided_health = abs(HEALTH_THRESHOLD_DEAD - mob.health) / abs(HEALTH_THRESHOLD_DEAD - mob.maxHealth)
return divided_health * 100
@@ -177,16 +177,16 @@
/mob/living/simple_animal/hostile/gorilla/cargo_domestic,
/mob/living/simple_animal/hostile/guardian,
/mob/living/simple_animal/hostile/guardian/assassin,
/mob/living/simple_animal/hostile/guardian/beam,
/mob/living/simple_animal/hostile/guardian/bomb,
/mob/living/simple_animal/hostile/guardian/charger,
/mob/living/simple_animal/hostile/guardian/dextrous,
/mob/living/simple_animal/hostile/guardian/explosive,
/mob/living/simple_animal/hostile/guardian/gaseous,
/mob/living/simple_animal/hostile/guardian/gravitokinetic,
/mob/living/simple_animal/hostile/guardian/healer,
/mob/living/simple_animal/hostile/guardian/lightning,
/mob/living/simple_animal/hostile/guardian/protector,
/mob/living/simple_animal/hostile/guardian/punch,
/mob/living/simple_animal/hostile/guardian/ranged,
/mob/living/simple_animal/hostile/guardian/standard,
/mob/living/simple_animal/hostile/guardian/support,
/mob/living/simple_animal/hostile/headcrab,
/mob/living/simple_animal/hostile/heretic_summon,
/mob/living/simple_animal/hostile/heretic_summon/armsy,
@@ -87,7 +87,7 @@
desc = "Though capable of near sorcerous feats via use of hardlight holograms and nanomachines, they require an \
organic host as a home base and source of fuel. Holoparasites come in various types and share damage with their host."
progression_minimum = 30 MINUTES
item = /obj/item/storage/box/syndie_kit/guardian
item = /obj/item/guardiancreator/tech/choose/traitor
cost = 18
surplus = 0
purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

+2
View File
@@ -94,6 +94,7 @@
#include "code\__DEFINES\generators.dm"
#include "code\__DEFINES\ghost.dm"
#include "code\__DEFINES\gravity.dm"
#include "code\__DEFINES\guardian_defines.dm"
#include "code\__DEFINES\hud.dm"
#include "code\__DEFINES\icon_smoothing.dm"
#include "code\__DEFINES\id_cards.dm"
@@ -3915,6 +3916,7 @@
#include "code\modules\mob\living\simple_animal\friendly\drone\verbs.dm"
#include "code\modules\mob\living\simple_animal\friendly\drone\visuals_icons.dm"
#include "code\modules\mob\living\simple_animal\guardian\guardian.dm"
#include "code\modules\mob\living\simple_animal\guardian\guardian_creator.dm"
#include "code\modules\mob\living\simple_animal\guardian\types\assassin.dm"
#include "code\modules\mob\living\simple_animal\guardian\types\charger.dm"
#include "code\modules\mob\living\simple_animal\guardian\types\dextrous.dm"