mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-24 05:30:05 +01:00
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:
co-authored by
Fikou
Tastyfish
parent
6dc618e19c
commit
e38eee6dee
@@ -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
|
||||
@@ -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>")
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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 \
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 |
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user