Voidwalker Rework | Basic Mob Edition + Bonus Antag (#91646)
## About The Pull Request Reworks the Voidwalker into a basic mob, including a lot of the balance and mechanics! Old (left), new (right)  https://github.com/user-attachments/assets/22d6138f-11aa-4f7a-8600-2565e6578bcf (little outdated) https://youtu.be/cp1E3qPJGX4 (high res mirror) **🟨Voidwalker mob changes🟨** No longer a human species and no more void eater. Instead deals damage by simple unarmed attacks. Instead of dealing brute, the voidwalker does oxygen damage (4-5 hits to knock out) with left-click, and slight brute on right click. Non-human mobs automatically take brute damage instead of oxygen damage. 150 HP 33% burn armor Yes it has hands, but it can only pick up and drop stuff **🟨Window phase🟨**  Instead of needing to smash a window with the void eater, moving through windows simply leaves them passable for 5 seconds. Makes kidnapping a lot easier, but also makes it easier for people to chase you People who used the voided skull also leave windows passable for a short bit. **🟩Cosmic Charge🟩** Standard charge ability, but only lets you charge towards space and works while dragging people **🟩The Vomitwalker🟩** People you kidnapped now occasionally do the nebula vomit, which voidwalkers can use to dive from and into  Diving into it is very fast but also removes the nebula vomit. You can also kidnap people into the vomit (this doesn't remove the vomit). There is also a little UI for tracking this. Clicking it while in space dive teleports you to the next nebula vomit, if there are any.  **🟨Voided people changes🟨** Kidnapped people and people that used the cosmic skull are no longer muted, but take 10% extra brute and occasionally leave behind glass shards when taking a lot of damage. Are no longer obliterated on a second encounter with voidwalkers. Voidwalkers can't hurt people they've already voided (unless they really want to), but instead just knock them out for 30s Also the kidnapped do space vomit as I said earlier. **🟩Sunwalker🟩** Voidwalker variant made for pure murderbone. Has no camo and kindap mechanics, but has a fiery charge, loads of damage and area igniting and people ignition. It's admin, but I might change this later once I've had some more time to think about it.  Other changes: - Voidwindows no longer need to be space adjacent - Unsettle works faster but can't be used in combat anymore - Space camo now grants complete space invisibility - Makes a lot of aspects easily moddable, so we can easily mod it into a moistwalker in-game - Taking a cosmic skull when you already used one gives you the old voidwalker void eater arm. Additional uses just gives you more void eater arms until you run out of hands - I definitely forgot a lot more - I made a cool voidwalker hud! It even has a unique space camo toggle ## Why It's Good For The Game <details> <summary>Lot of text</summary> Voidwalker was basically a snowflaked toghether human species because I didn't know how to sprite, but I was able to work with species and visual effects. Then I realized I can just commission sprites! This also let me just cut out a lot of the snowflake code, because it's no longer a human so half the things I didn't want them to be able to do, they just literally cannot do. Voidwalkers were in a bit of strange spot with kidnapping? There was essentially no incentive, other than "smash spaceman = funny". They also had issues doing, anything? There's surprisingly little space on a space station, especially maps such as tram. Making the voided victims have nebula vomit gives the voidwalker a reason to WANT to kidnap, by giving them a way to appear basically anywhere on the station. I don't think it's too overpowered. Voided people don't vomit that much, it's easily cleanable and diving into it removes them, so they're limited usability. Replacing the brute damage with oxygen damage also kinda... just makes sense? I seriously contemplated letting them do stamina damage for the first iteration, but opted not to do it because stamina damage has so many hooks attached. Oxygen damage doesn't! It's also just incredibly thematic, let's them bypass most armor and makes them more suited to non-letha kidnappings. Space camo making them completely invisible was also long overdue. It was literally just urging people to turn up their gamma and turn down their parallax settings. I thought it was an interesting mechanic, but it's just straight up unfair and doesn't belong in a multiplayer game. They now more frequently leave behind little glass shards, leave particles from nebula vomit they leave from and have more unique sound effects, so attentive (and lucky) people can still deduce if an area is safe-ish. I removed being able to shatter voided people because the mechanic was deeply misunderstood. It was intended to give them a means of removing people if they kept incessently bothering the voidwalker, but people went out of their way to use this to roundremove people they had already voided. The 30s sleep conveys my intention a lot better, and fits better now that the voidwalker benefits from having as many voided people vomitting all over the place. The cosmic charge gives them some much needed survivability. My experiences (in observing voidwalkers, I can never get the roll ;_;) is that they're constantly one mistake away from complete obliteration. The cosmic charge let's them get out quick despite their slow movement speed in gravity. It also makes them stronger when fighting in space. They got 33% burn armor so it's a tiny bit harder to wipe them away in a single laser salvo, while still giving people ample opportunity to fight them off . Also they're like glass or something so it fits thematically. I gave them hands because I thought it was cool, might be a mistake idk </details> ## Changelog 🆑 Time-Green, INFRARED_BACON add: Voidwalker has been throughly reworked! Now you are even less safe! admin: Adds admin-only Sunwalker mob fix: Unsettle doesnt work on yourself anymore fix: Space camo doesnt stop bobbing anymore fix: Voidwalker windows now recharge on kidnap runtime: Fixes healthanalyzers runtiming when scanning mobs without reagent holders /🆑
@@ -114,6 +114,7 @@
|
||||
#define COLOR_TRAM_LIGHT_BLUE "#A8A7DA"
|
||||
#define COLOR_AMETHYST "#822BFF"
|
||||
#define COLOR_BLUE_LIGHT "#33CCFF"
|
||||
#define COLOR_BLUE_VERY_LIGHT "#ccecff"
|
||||
#define COLOR_NAVY "#000080"
|
||||
#define COLOR_BLUE_GRAY "#75A2BB"
|
||||
|
||||
|
||||
@@ -156,6 +156,7 @@ DEFINE_BITFIELD(status_flags, list(
|
||||
#define ATTACK_EFFECT_MECHFIRE "mech_fire"
|
||||
#define ATTACK_EFFECT_MECHTOXIN "mech_toxin"
|
||||
#define ATTACK_EFFECT_BOOP "boop" //Honk
|
||||
#define ATTACK_EFFECT_VOID "void"
|
||||
|
||||
/// Attack animation for sharp items
|
||||
#define ATTACK_ANIMATION_SLASH "slash"
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
/// Called from /datum/component/space_kidnap/successful_kidnap() : (mob/living/carbon/human/voidwalker, mob/living/carbon/human/victim)
|
||||
#define COMSIG_VOIDWALKER_SUCCESSFUL_KIDNAP "voidwalker_successful_kidnap"
|
||||
@@ -39,6 +39,7 @@
|
||||
#define ROLE_SPIDER "Spider"
|
||||
#define ROLE_WIZARD_MIDROUND "Wizard (Midround)"
|
||||
#define ROLE_VOIDWALKER "Voidwalker"
|
||||
#define ROLE_SUNWALKER "Sunwalker"
|
||||
|
||||
// Latejoin roles
|
||||
#define ROLE_HERETIC_SMUGGLER "Heretic Smuggler"
|
||||
|
||||
@@ -1525,7 +1525,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
|
||||
/// Trait given to colorblind mobs
|
||||
#define TRAIT_COLORBLIND "colorblind"
|
||||
|
||||
/// Trait that blocks invisibility (uh as of writing only the space camo but might expand later idk)
|
||||
#define TRAIT_INVISIBILITY_BLOCKED "invisibility_blocked"
|
||||
|
||||
/// Trait that signals to objects on this turf that its open (has UNDERFLOOR_INTERACTIBLE) but still covers them
|
||||
#define TRAIT_UNCOVERED_TURF "uncovered_turf"
|
||||
|
||||
// END TRAIT DEFINES
|
||||
|
||||
@@ -108,6 +108,7 @@ GLOBAL_LIST_INIT(phobia_mobs, list(
|
||||
)),
|
||||
"skeletons" = typecacheof(list(/mob/living/basic/skeleton)),
|
||||
"snakes" = typecacheof(list(/mob/living/basic/snake)),
|
||||
"space" = typecacheof(list(/mob/living/basic/voidwalker)),
|
||||
"the supernatural" = typecacheof(list(
|
||||
/mob/dead/observer,
|
||||
/mob/living/basic/bat,
|
||||
@@ -123,6 +124,7 @@ GLOBAL_LIST_INIT(phobia_mobs, list(
|
||||
/mob/living/basic/wizard,
|
||||
/mob/living/basic/zombie,
|
||||
/mob/living/simple_animal/bot/mulebot/paranormal,
|
||||
/mob/living/basic/voidwalker,
|
||||
)),
|
||||
))
|
||||
|
||||
@@ -577,8 +579,6 @@ GLOBAL_LIST_INIT(phobia_species, list(
|
||||
/datum/species/plasmaman,
|
||||
/datum/species/skeleton,
|
||||
)),
|
||||
"space" = typecacheof(list(/datum/species/voidwalker)),
|
||||
"supernatural" = typecacheof(list(/datum/species/voidwalker))
|
||||
))
|
||||
|
||||
/// Creates a regular expression to match against the given phobia
|
||||
|
||||
@@ -339,6 +339,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
|
||||
"TRAIT_IMMUNODEFICIENCY" = TRAIT_IMMUNODEFICIENCY,
|
||||
"TRAIT_INCAPACITATED" = TRAIT_INCAPACITATED,
|
||||
"TRAIT_INTROVERT" = TRAIT_INTROVERT,
|
||||
"TRAIT_INVISIBILITY_BLOCKED" = TRAIT_INVISIBILITY_BLOCKED,
|
||||
"TRAIT_INVISIBLE_MAN" = TRAIT_INVISIBLE_MAN,
|
||||
"TRAIT_INVISIMIN" = TRAIT_INVISIMIN,
|
||||
"TRAIT_IN_CALL" = TRAIT_IN_CALL,
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/datum/hud/dextrous/voidwalker
|
||||
ui_style = 'icons/hud/screen_voidwalker.dmi'
|
||||
|
||||
/datum/hud/dextrous/voidwalker/New(mob/living/owner)
|
||||
. = ..()
|
||||
|
||||
floor_change.icon = ui_style
|
||||
floor_change.screen_loc = ui_rest
|
||||
static_inventory += floor_change
|
||||
|
||||
action_intent = new /atom/movable/screen/combattoggle/flashy/voidwalker(null, src)
|
||||
action_intent.icon = ui_style
|
||||
static_inventory += action_intent
|
||||
|
||||
var/atom/movable/screen/space_camo_toggle = new /atom/movable/screen/space_camo(null, src)
|
||||
space_camo_toggle.screen_loc = ui_above_movement
|
||||
static_inventory += space_camo_toggle
|
||||
|
||||
var/atom/movable/screen/vomit_jump/vomit = new /atom/movable/screen/vomit_jump(null, src)
|
||||
vomit.screen_loc = ui_mood
|
||||
static_inventory += vomit
|
||||
|
||||
/// This exists because for some reason only the combat indicator screen_loc is constantly set to initial
|
||||
/atom/movable/screen/combattoggle/flashy/voidwalker
|
||||
screen_loc = ui_movi
|
||||
|
||||
/atom/movable/screen/space_camo
|
||||
name = "space camouflage toggle"
|
||||
icon = 'icons/hud/screen_voidwalker.dmi'
|
||||
icon_state = "camo_toggle"
|
||||
|
||||
/// Wheter or not we're toggled on or off
|
||||
var/invisibility_toggle = TRUE
|
||||
|
||||
/atom/movable/screen/space_camo/Click()
|
||||
if(!isliving(usr))
|
||||
return
|
||||
|
||||
invisibility_toggle = !invisibility_toggle
|
||||
update_appearance()
|
||||
|
||||
if(invisibility_toggle)
|
||||
REMOVE_TRAIT(usr, TRAIT_INVISIBILITY_BLOCKED, type)
|
||||
else
|
||||
ADD_TRAIT(usr, TRAIT_INVISIBILITY_BLOCKED, type)
|
||||
|
||||
/atom/movable/screen/space_camo/update_icon_state()
|
||||
icon_state = initial(icon_state) + (invisibility_toggle ? "" : "_off")
|
||||
return ..()
|
||||
|
||||
/atom/movable/screen/vomit_jump
|
||||
name = "vomit tracker"
|
||||
icon = 'icons/hud/screen_voidwalker.dmi'
|
||||
icon_state = "vomitjump"
|
||||
/// So we can sort of loop through it
|
||||
var/index = 1
|
||||
|
||||
/atom/movable/screen/vomit_jump/Initialize(mapload, datum/hud/hud_owner)
|
||||
. = ..()
|
||||
|
||||
var/icon/vomit_overlay = icon(/obj/effect/decal/cleanable/vomit/nebula::icon, pick(/obj/effect/decal/cleanable/vomit/nebula::random_icon_states))
|
||||
add_overlay(vomit_overlay)
|
||||
|
||||
/atom/movable/screen/vomit_jump/examine(mob/user)
|
||||
. = ..()
|
||||
|
||||
var/list/vomits = get_valid_vomits()
|
||||
|
||||
. += span_notice("Tracks all of the nebula vomits generated by the people you have touched.")
|
||||
. += span_notice("Left-click while in space dive to move to a nebula vomit, if there are any.")
|
||||
. += span_notice("Current nebula vomits: [vomits.len]")
|
||||
|
||||
|
||||
/atom/movable/screen/vomit_jump/proc/get_valid_vomits()
|
||||
var/list/valid_vomits = list()
|
||||
|
||||
for(var/atom/movable/vomit as anything in GLOB.nebula_vomits)
|
||||
if(!is_station_level(vomit.z))
|
||||
return
|
||||
|
||||
valid_vomits += vomit
|
||||
return valid_vomits
|
||||
|
||||
/atom/movable/screen/vomit_jump/Click(location, control, params)
|
||||
var/list/modifiers = params2list(params)
|
||||
if(LAZYACCESS(modifiers, RIGHT_CLICK) || LAZYACCESS(modifiers, SHIFT_CLICK))
|
||||
usr.examinate(src)
|
||||
return
|
||||
|
||||
if(!isliving(usr))
|
||||
return
|
||||
|
||||
if(!istype(usr.loc, /obj/effect/dummy/phased_mob/space_dive))
|
||||
usr.balloon_alert(usr, "must be space diving!")
|
||||
return
|
||||
|
||||
var/list/vomits = get_valid_vomits()
|
||||
|
||||
if(!vomits.len)
|
||||
usr.balloon_alert(usr, "no nebula vomits!")
|
||||
return
|
||||
|
||||
var/obj/effect/dummy/phased_mob/space_dive/holder = usr.loc
|
||||
|
||||
index = (index % vomits.len) + 1
|
||||
|
||||
holder.forceMove(get_step(vomits[index], pick(GLOB.alldirs)))
|
||||
usr.playsound_local(usr, 'sound/effects/phasein.ogg', 50, FALSE)
|
||||
@@ -715,11 +715,13 @@
|
||||
name = "Voidwalker"
|
||||
config_tag = "Voidwalker"
|
||||
preview_antag_datum = /datum/antagonist/voidwalker
|
||||
|
||||
midround_type = LIGHT_MIDROUND
|
||||
pref_flag = ROLE_VOIDWALKER
|
||||
ruleset_flags = RULESET_INVADER
|
||||
|
||||
weight = 5
|
||||
min_pop = 30 // Ensures there's a lot of people near windows
|
||||
min_pop = 40 // Ensures there's a lot of people near windows
|
||||
max_antag_cap = 1
|
||||
ruleset_lazy_templates = list(LAZY_TEMPLATE_KEY_VOIDWALKER_VOID)
|
||||
signup_atom_appearance = /obj/item/clothing/head/helmet/skull/cosmic
|
||||
@@ -727,9 +729,11 @@
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/voidwalker/can_be_selected()
|
||||
return ..() && !SSmapping.is_planetary() && !isnull(find_space_spawn())
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/voidwalker/create_ruleset_body()
|
||||
return new /mob/living/basic/voidwalker
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/voidwalker/assign_role(datum/mind/candidate)
|
||||
candidate.add_antag_datum(/datum/antagonist/voidwalker)
|
||||
candidate.current.set_species(/datum/species/voidwalker)
|
||||
candidate.current.forceMove(find_space_spawn())
|
||||
playsound(candidate.current, 'sound/effects/magic/ethereal_exit.ogg', 50, TRUE, -1)
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/// Drop debris when taking damage
|
||||
/datum/component/debris_bleeder
|
||||
/// The type of debrees to spawn at a certain damage threshold. First threshold to hit in the list wins, so usually you'd want to construct from descending damage
|
||||
/// list(/obj/item/toolbox = 30, /obj/item/wire = 20, etc)
|
||||
var/list/debris_to_damage
|
||||
/// Which type of damage to respond to
|
||||
var/damage_type
|
||||
/// The sound to play on hit
|
||||
var/sound
|
||||
/// Minimal damage at which we can play the sound
|
||||
var/sound_threshold
|
||||
|
||||
/datum/component/debris_bleeder/Initialize(list/debris_to_damage, damage_type = BRUTE, sound = null, sound_threshold = 0)
|
||||
if(!isliving(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
src.debris_to_damage = debris_to_damage
|
||||
src.damage_type = damage_type
|
||||
src.sound = sound
|
||||
src.sound_threshold = sound_threshold
|
||||
|
||||
RegisterSignal(parent, COMSIG_MOB_APPLY_DAMAGE, PROC_REF(on_apply_damage))
|
||||
|
||||
/datum/component/debris_bleeder/proc/on_apply_damage(mob/living/liver, amount, damage_type)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(src.damage_type != damage_type)
|
||||
return
|
||||
|
||||
for(var/key in debris_to_damage)
|
||||
var/value = debris_to_damage[key]
|
||||
|
||||
if(value < amount)
|
||||
new key ((get_turf(liver)))
|
||||
if(sound && sound_threshold < amount)
|
||||
playsound(liver, sound, 60)
|
||||
@@ -2,13 +2,17 @@
|
||||
/datum/component/glass_passer
|
||||
/// How long does it take us to move into glass?
|
||||
var/pass_time = 0 SECONDS
|
||||
/// How long does the window stay deformed and passable for others?
|
||||
var/deform_glass = 0 SECONDS
|
||||
|
||||
/datum/component/glass_passer/Initialize(pass_time)
|
||||
/datum/component/glass_passer/Initialize(pass_time, deform_glass)
|
||||
if(!ismob(parent)) //if its not a mob then just directly use passwindow
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
src.pass_time = pass_time
|
||||
src.deform_glass = deform_glass
|
||||
|
||||
/datum/component/glass_passer/RegisterWithParent()
|
||||
if(!pass_time)
|
||||
passwindow_on(parent, type)
|
||||
else
|
||||
@@ -16,14 +20,16 @@
|
||||
|
||||
var/mob/mobbers = parent
|
||||
mobbers.generic_canpass = FALSE
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_CROSS_OVER, PROC_REF(cross_over))
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_CROSS_OVER, PROC_REF(on_cross_over))
|
||||
|
||||
/datum/component/glass_passer/Destroy()
|
||||
. = ..()
|
||||
if(deform_glass)
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved))
|
||||
|
||||
/datum/component/glass_passer/UnregisterFromParent()
|
||||
if(parent)
|
||||
passwindow_off(parent, type)
|
||||
|
||||
/datum/component/glass_passer/proc/cross_over(mob/passer, atom/crosser)
|
||||
/datum/component/glass_passer/proc/on_cross_over(mob/passer, atom/crosser)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(istype(crosser, /obj/structure/grille))
|
||||
@@ -34,6 +40,27 @@
|
||||
|
||||
return null
|
||||
|
||||
/datum/component/glass_passer/proc/on_moved(mob/living/phaser, atom/old_loc, dir, forced, list/old_locs)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
for(var/obj/structure/structure as anything in old_loc)
|
||||
if(!structure.density || !istype(structure, /obj/structure/window) && !istype(structure, /obj/structure/grille))
|
||||
continue
|
||||
|
||||
blomperize(structure)
|
||||
|
||||
/// Make the window temporarily passable
|
||||
/datum/component/glass_passer/proc/blomperize(obj/structure/structure)
|
||||
structure.density = FALSE
|
||||
apply_wibbly_filters(structure)
|
||||
|
||||
addtimer(CALLBACK(src, PROC_REF(unblomperize), structure), deform_glass)
|
||||
|
||||
/// Reset the windows passability
|
||||
/datum/component/glass_passer/proc/unblomperize(obj/structure/structure)
|
||||
structure.density = initial(structure.density)
|
||||
remove_wibbly_filters(structure, 0.5 SECONDS)
|
||||
|
||||
/datum/component/glass_passer/proc/bumped(mob/living/owner, atom/bumpee)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
var/fire_type
|
||||
|
||||
/datum/component/igniter/Initialize(fire_stacks = 1, fire_type = /datum/status_effect/fire_handler/fire_stacks)
|
||||
if(!isitem(parent) && !ishostile(parent) && !isgun(parent) && !ismachinery(parent) && !isstructure(parent) && !isprojectilespell(parent))
|
||||
if(!isitem(parent) && !ishostile(parent) && !isgun(parent) && !ismachinery(parent) && !isstructure(parent) && !isprojectilespell(parent) && !isbasicmob(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
src.fire_stacks = fire_stacks
|
||||
@@ -14,8 +14,8 @@
|
||||
RegisterSignal(parent, COMSIG_PROJECTILE_ON_HIT, PROC_REF(projectile_hit))
|
||||
else if(isitem(parent))
|
||||
RegisterSignal(parent, COMSIG_ITEM_AFTERATTACK, PROC_REF(item_afterattack))
|
||||
else if(ishostile(parent))
|
||||
RegisterSignal(parent, COMSIG_HOSTILE_POST_ATTACKINGTARGET, PROC_REF(hostile_attackingtarget))
|
||||
else if(isbasicmob(parent))
|
||||
RegisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(unarmed_attack))
|
||||
|
||||
/datum/component/igniter/UnregisterFromParent()
|
||||
UnregisterSignal(parent, list(COMSIG_ITEM_AFTERATTACK, COMSIG_HOSTILE_POST_ATTACKINGTARGET, COMSIG_PROJECTILE_ON_HIT))
|
||||
@@ -25,11 +25,9 @@
|
||||
|
||||
do_igniter(target)
|
||||
|
||||
/datum/component/igniter/proc/hostile_attackingtarget(mob/living/simple_animal/hostile/attacker, atom/target, success)
|
||||
/datum/component/igniter/proc/unarmed_attack(mob/living/source, atom/target, proximity, modifiers)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!success)
|
||||
return
|
||||
do_igniter(target)
|
||||
|
||||
/datum/component/igniter/proc/projectile_hit(datum/fired_from, atom/movable/firer, atom/target, Angle)
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
var/outline_colour
|
||||
/// When this timer completes we start restoring health, it is a timer rather than a cooldown so we can do something on its completion
|
||||
var/regeneration_start_timer
|
||||
/// Callback for adding special checks for whether or not we can start regenning
|
||||
var/datum/callback/regen_check = null
|
||||
|
||||
/datum/component/regenerator/Initialize(
|
||||
regeneration_delay = 6 SECONDS,
|
||||
@@ -35,6 +37,7 @@
|
||||
heals_wounds = FALSE,
|
||||
ignore_damage_types = list(STAMINA),
|
||||
outline_colour = COLOR_PALE_GREEN,
|
||||
regen_check = null,
|
||||
)
|
||||
if (!isliving(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
@@ -47,6 +50,7 @@
|
||||
src.heals_wounds = heals_wounds
|
||||
src.ignore_damage_types = ignore_damage_types
|
||||
src.outline_colour = outline_colour
|
||||
src.regen_check = regen_check
|
||||
|
||||
/datum/component/regenerator/RegisterWithParent()
|
||||
. = ..()
|
||||
@@ -71,6 +75,10 @@
|
||||
|
||||
if (damagetype in ignore_damage_types)
|
||||
return
|
||||
|
||||
reset_regeneration_timer()
|
||||
|
||||
/datum/component/regenerator/proc/reset_regeneration_timer()
|
||||
stop_regenerating()
|
||||
regeneration_start_timer = addtimer(CALLBACK(src, PROC_REF(start_regenerating)), regeneration_delay, TIMER_UNIQUE|TIMER_OVERRIDE|TIMER_STOPPABLE)
|
||||
|
||||
@@ -129,6 +137,11 @@
|
||||
/datum/component/regenerator/proc/should_be_regenning(mob/living/who)
|
||||
if(who.stat == DEAD)
|
||||
return FALSE
|
||||
|
||||
if(regen_check && !regen_check.Invoke(who))
|
||||
reset_regeneration_timer()
|
||||
return FALSE
|
||||
|
||||
if(heals_wounds && iscarbon(who))
|
||||
var/mob/living/carbon/carbon_who = who
|
||||
if(length(carbon_who.all_wounds) > 0)
|
||||
|
||||
@@ -6,22 +6,28 @@
|
||||
var/non_space_alpha
|
||||
/// How long we can't enter camo after hitting or being hit
|
||||
var/reveal_after_combat
|
||||
/// Icon override for our camouflage
|
||||
var/image/camo_icon
|
||||
/// The world time after we can camo again
|
||||
VAR_PRIVATE/next_camo
|
||||
/// Image we show to our jaunter so they can see where they are
|
||||
var/image/position_indicator
|
||||
/// Icon we draw our position indicator from
|
||||
var/phased_mob_icon = 'icons/obj/weapons/guns/projectiles.dmi'
|
||||
/// Icon state we use for our position indicator
|
||||
var/phased_mob_icon_state = "solarflare"
|
||||
/// The alpha we see ourselves at when in camo
|
||||
var/alpha_to_self
|
||||
/// Are we currently camouflaged?
|
||||
var/is_camouflaged = FALSE
|
||||
/// What is the type for the space tile? For easy admin modding
|
||||
var/turf/open/camo_tile = /turf/open/space
|
||||
|
||||
/datum/component/space_camo/Initialize(space_alpha, non_space_alpha, reveal_after_combat)
|
||||
/datum/component/space_camo/Initialize(space_alpha, non_space_alpha, alpha_to_self = 120, reveal_after_combat, camo_icon)
|
||||
if(!ismovable(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
src.space_alpha = space_alpha
|
||||
src.non_space_alpha = non_space_alpha
|
||||
src.reveal_after_combat = reveal_after_combat
|
||||
src.camo_icon = camo_icon
|
||||
src.alpha_to_self = alpha_to_self
|
||||
|
||||
/datum/component/space_camo/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_ATOM_ENTERING, PROC_REF(on_atom_entering))
|
||||
@@ -29,11 +35,18 @@
|
||||
return
|
||||
|
||||
var/mob/living/living_parent = parent
|
||||
position_indicator = image(phased_mob_icon, living_parent, phased_mob_icon_state, ABOVE_LIGHTING_PLANE)
|
||||
|
||||
position_indicator = camo_icon ? camo_icon : image(living_parent, ABOVE_LIGHTING_PLANE)
|
||||
|
||||
position_indicator.loc = living_parent
|
||||
|
||||
SET_PLANE_EXPLICIT(position_indicator, ABOVE_LIGHTING_PLANE, living_parent)
|
||||
position_indicator.appearance_flags |= RESET_ALPHA
|
||||
position_indicator.alpha = 0
|
||||
|
||||
RegisterSignal(parent, SIGNAL_ADDTRAIT(TRAIT_INVISIBILITY_BLOCKED), PROC_REF(added_invisibility_block))
|
||||
RegisterSignal(parent, SIGNAL_REMOVETRAIT(TRAIT_INVISIBILITY_BLOCKED), PROC_REF(removed_invisibility_block))
|
||||
|
||||
RegisterSignals(parent, list(COMSIG_ATOM_WAS_ATTACKED, COMSIG_MOB_ITEM_ATTACK, COMSIG_LIVING_UNARMED_ATTACK, COMSIG_ATOM_BULLET_ACT, COMSIG_ATOM_REVEAL), PROC_REF(force_exit_camo))
|
||||
RegisterSignal(parent, COMSIG_MOB_LOGIN, PROC_REF(show_client_image))
|
||||
show_client_image(parent)
|
||||
@@ -61,10 +74,12 @@
|
||||
exit_camo(parent)
|
||||
|
||||
/datum/component/space_camo/proc/attempt_enter_camo()
|
||||
if(!isspaceturf(get_turf(parent)) || next_camo > world.time)
|
||||
if(!istype(get_turf(parent), camo_tile) || next_camo > world.time || HAS_TRAIT(parent, TRAIT_INVISIBILITY_BLOCKED))
|
||||
return FALSE
|
||||
|
||||
enter_camo(parent)
|
||||
if(!is_camouflaged)
|
||||
enter_camo(parent)
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/component/space_camo/proc/force_exit_camo()
|
||||
@@ -78,16 +93,20 @@
|
||||
if(parent.alpha != space_alpha)
|
||||
animate(parent, alpha = space_alpha, time = 0.5 SECONDS)
|
||||
if (position_indicator)
|
||||
animate(position_indicator, alpha = 255, time = 0.5 SECONDS)
|
||||
animate(position_indicator, alpha = alpha_to_self, time = 0.5 SECONDS)
|
||||
parent.remove_from_all_data_huds()
|
||||
parent.add_atom_colour(SSparallax.get_parallax_color(), TEMPORARY_COLOUR_PRIORITY)
|
||||
is_camouflaged = TRUE
|
||||
|
||||
/datum/component/space_camo/proc/exit_camo(atom/movable/parent)
|
||||
if(!is_camouflaged)
|
||||
return
|
||||
|
||||
animate(parent, alpha = non_space_alpha, time = 0.5 SECONDS)
|
||||
if (position_indicator)
|
||||
animate(position_indicator, alpha = 0, time = 0.5 SECONDS)
|
||||
parent.add_to_all_human_data_huds()
|
||||
parent.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY)
|
||||
DO_FLOATING_ANIM(parent)
|
||||
is_camouflaged = FALSE
|
||||
|
||||
/datum/component/space_camo/proc/show_client_image(mob/show_to)
|
||||
SIGNAL_HANDLER
|
||||
@@ -96,3 +115,13 @@
|
||||
/datum/component/space_camo/proc/remove_client_image(mob/remove_from)
|
||||
SIGNAL_HANDLER
|
||||
remove_from.client?.images -= position_indicator
|
||||
|
||||
/datum/component/space_camo/proc/added_invisibility_block(atom/movable/parent)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
exit_camo(parent)
|
||||
|
||||
/datum/component/space_camo/proc/removed_invisibility_block(atom/movable/parent)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
attempt_enter_camo()
|
||||
|
||||
@@ -8,17 +8,24 @@
|
||||
var/surface_time = 1 SECONDS
|
||||
/// Traits added during phasing (and removed after)
|
||||
var/static/phase_traits = list(TRAIT_MAGICALLY_PHASED, TRAIT_RUNECHAT_HIDDEN, TRAIT_WEATHER_IMMUNE)
|
||||
/// Type of turf that is divable
|
||||
var/diveable_turf = /turf/open/space
|
||||
/// A decal we can dive from, and escape into (but only one enter)
|
||||
var/diveable_decal = /obj/effect/decal/cleanable/vomit/nebula
|
||||
|
||||
/datum/component/space_dive/Initialize(...)
|
||||
/datum/component/space_dive/Initialize(jaunt_type)
|
||||
if(!isliving(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
src.jaunt_type = jaunt_type
|
||||
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_BUMP, PROC_REF(bump))
|
||||
RegisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_unarmed_attack))
|
||||
|
||||
/datum/component/space_dive/proc/bump(mob/living/parent, atom/bumped)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!isspaceturf(get_turf(parent)))
|
||||
if(!istype(get_turf(parent), diveable_turf))
|
||||
return
|
||||
|
||||
if(ismovable(bumped))
|
||||
@@ -40,6 +47,9 @@
|
||||
/datum/component/space_dive/proc/dive(atom/bumped)
|
||||
var/obj/effect/dummy/phased_mob/jaunt = new jaunt_type(get_turf(bumped), parent)
|
||||
|
||||
var/mob/living/diver = parent
|
||||
diver.drop_all_held_items()
|
||||
|
||||
RegisterSignal(jaunt, COMSIG_MOB_EJECTED_FROM_JAUNT, PROC_REF(surface))
|
||||
RegisterSignal(jaunt, COMSIG_MOB_PHASED_CHECK, PROC_REF(move_check))
|
||||
parent.add_traits(phase_traits, REF(src))
|
||||
@@ -50,7 +60,7 @@
|
||||
/datum/component/space_dive/proc/move_check(obj/effect/dummy/phased_mob/jaunt, mob/living/parent, turf/new_turf)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!isspaceturf(new_turf))
|
||||
if(!istype(new_turf, diveable_turf) && !(locate(diveable_decal) in new_turf))
|
||||
return
|
||||
|
||||
INVOKE_ASYNC(src, PROC_REF(attempt_surface), parent, new_turf)
|
||||
@@ -59,6 +69,12 @@
|
||||
/// try and surface by doing a do_after
|
||||
/datum/component/space_dive/proc/attempt_surface(mob/living/parent, turf/new_turf)
|
||||
if(do_after(parent, surface_time, new_turf, extra_checks = CALLBACK(src, PROC_REF(check_if_moved), parent, get_turf(parent))))
|
||||
var/decal = locate(diveable_decal) in new_turf
|
||||
|
||||
if(decal)
|
||||
var/obj/particles = new /obj/effect/abstract/particle_holder (decal, /particles/void_vomit)
|
||||
QDEL_IN(particles, 60 SECONDS)
|
||||
|
||||
surface(null, parent, new_turf)
|
||||
|
||||
// we check if we moved for the do_after, since relayed movements arent caught that well by the do_after
|
||||
@@ -80,6 +96,29 @@
|
||||
// This needs to happen at the end, after all the traits and stuff is handled
|
||||
SEND_SIGNAL(parent, COMSIG_MOB_AFTER_EXIT_JAUNT, src)
|
||||
|
||||
/datum/component/space_dive/proc/on_unarmed_attack(mob/living/source, atom/target, proximity, modifiers)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(istype(target, diveable_decal))
|
||||
INVOKE_ASYNC(src, PROC_REF(try_enter), source, target)
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/datum/component/space_dive/proc/try_enter(mob/living/source, atom/movable/decal)
|
||||
if(!do_after(source, 1 SECONDS, decal))
|
||||
return
|
||||
|
||||
dive(decal)
|
||||
new /obj/effect/temp_visual/circle_wave/unsettle(get_turf(decal))
|
||||
qdel(decal)
|
||||
|
||||
/obj/effect/dummy/phased_mob/space_dive
|
||||
movespeed = 1
|
||||
phased_mob_icon_state = "solarflare"
|
||||
|
||||
/obj/effect/dummy/phased_mob/space_dive/voidwalker
|
||||
phased_mob_icon = /mob/living/basic/voidwalker::icon
|
||||
phased_mob_icon_state = /mob/living/basic/voidwalker::icon_state + "_stealthed"
|
||||
|
||||
/obj/effect/dummy/phased_mob/space_dive/sunwalker
|
||||
phased_mob_icon = /mob/living/basic/voidwalker/sunwalker::icon
|
||||
phased_mob_icon_state = /mob/living/basic/voidwalker/sunwalker::icon_state + "_stealthed"
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
/// Component that lets us space kidnap people as the voidwalker with our HAAAADS
|
||||
/datum/component/space_kidnap
|
||||
/// How long does it take to kidnap them?
|
||||
var/kidnap_time = 6 SECONDS
|
||||
/// Are we kidnapping right now?
|
||||
var/kidnapping = FALSE
|
||||
|
||||
/datum/component/space_kidnap/Initialize(...)
|
||||
if(!ishuman(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
RegisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(try_kidnap))
|
||||
|
||||
/datum/component/space_kidnap/proc/try_kidnap(mob/living/parent, atom/target)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!isliving(target))
|
||||
return
|
||||
|
||||
var/mob/living/victim = target
|
||||
|
||||
if(victim.stat == DEAD)
|
||||
target.balloon_alert(parent, "is dead!")
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
if(!victim.incapacitated)
|
||||
return
|
||||
|
||||
if(!isspaceturf(get_turf(target)))
|
||||
target.balloon_alert(parent, "not in space!")
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
if(!kidnapping)
|
||||
INVOKE_ASYNC(src, PROC_REF(kidnap), parent, target)
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/datum/component/space_kidnap/proc/kidnap(mob/living/parent, mob/living/victim)
|
||||
victim.Paralyze(kidnap_time) //so they don't get up if we already got em
|
||||
var/obj/particles = new /obj/effect/abstract/particle_holder (victim, /particles/void_kidnap)
|
||||
kidnapping = TRUE
|
||||
|
||||
if(do_after(parent, kidnap_time, victim, extra_checks = CALLBACK(src, PROC_REF(check_incapacitated), victim)))
|
||||
take_them(victim)
|
||||
|
||||
qdel(particles)
|
||||
kidnapping = FALSE
|
||||
|
||||
/datum/component/space_kidnap/proc/take_them(mob/living/victim)
|
||||
if(ishuman(victim))
|
||||
var/mob/living/carbon/human/hewmon = victim
|
||||
hewmon.gain_trauma(/datum/brain_trauma/voided)
|
||||
|
||||
victim.flash_act(INFINITY, override_blindness_check = TRUE, visual = TRUE, type = /atom/movable/screen/fullscreen/flash/black)
|
||||
new /obj/effect/temp_visual/circle_wave/unsettle(get_turf(victim))
|
||||
|
||||
if(!SSmapping.lazy_load_template(LAZY_TEMPLATE_KEY_VOIDWALKER_VOID) || !GLOB.voidwalker_void.len)
|
||||
victim.forceMove(get_random_station_turf())
|
||||
victim.heal_overall_damage(brute = 80, burn = 20)
|
||||
CRASH("[victim] was instantly dumped after being voidwalker kidnapped due to a missing landmark!")
|
||||
else
|
||||
victim.heal_and_revive(90)
|
||||
victim.adjustOxyLoss(-100, FALSE)
|
||||
|
||||
var/obj/wisp = new /obj/effect/wisp_mobile (get_turf(pick(GLOB.voidwalker_void)))
|
||||
victim.forceMove(wisp)
|
||||
successfully_kidnapped()
|
||||
|
||||
/datum/component/space_kidnap/proc/successfully_kidnapped(mob/living/carbon/human/kidnappee)
|
||||
SEND_SIGNAL(parent, COMSIG_VOIDWALKER_SUCCESSFUL_KIDNAP, kidnappee)
|
||||
|
||||
/datum/component/space_kidnap/proc/check_incapacitated(mob/living/carbon/human/kidnappee)
|
||||
return kidnappee.incapacitated
|
||||
@@ -2,13 +2,16 @@
|
||||
/datum/component/vision_hurting
|
||||
var/damage_per_second
|
||||
var/message
|
||||
/// Do people looking at us make a fuss?
|
||||
var/silent
|
||||
|
||||
/datum/component/vision_hurting/Initialize(damage_per_second=1, message="Your eyes burn as you look at")
|
||||
/datum/component/vision_hurting/Initialize(damage_per_second=1, message="Your eyes burn as you look at", silent = FALSE)
|
||||
if(!isatom(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
src.damage_per_second = damage_per_second
|
||||
src.message = message
|
||||
src.silent = silent
|
||||
|
||||
START_PROCESSING(SSdcs, src)
|
||||
|
||||
@@ -20,6 +23,8 @@
|
||||
if(!burning_orbs)
|
||||
continue
|
||||
burning_orbs.apply_organ_damage(damage_per_second * seconds_per_tick)
|
||||
if(silent)
|
||||
return
|
||||
if(SPT_PROB(50, seconds_per_tick))
|
||||
to_chat(viewer, span_userdanger("[message] [parent]!"))
|
||||
if(SPT_PROB(20, seconds_per_tick))
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
if(!isliving(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
|
||||
RegisterSignal(target, COMSIG_LIVING_ATTACK_ATOM, PROC_REF(check_if_glass))
|
||||
RegisterSignals(target, list(COMSIG_LIVING_ATTACK_ATOM, COMSIG_LIVING_UNARMED_ATTACK), PROC_REF(check_if_glass))
|
||||
|
||||
/datum/element/glass_pacifist/proc/check_if_glass(mob/living/owner, atom/hit)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/// Give to a human or other dextrous mob to have them only be able to pick up and drop items, and not use them on anything
|
||||
/datum/element/pick_and_drop_only
|
||||
element_flags = ELEMENT_DETACH_ON_HOST_DESTROY
|
||||
|
||||
/datum/element/pick_and_drop_only/Attach(datum/target)
|
||||
. = ..()
|
||||
|
||||
if(!isliving(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
|
||||
RegisterSignal(target, COMSIG_LIVING_PICKED_UP_ITEM, PROC_REF(on_picked_up))
|
||||
|
||||
/datum/element/pick_and_drop_only/proc/on_picked_up(mob/living/liver, obj/item/item)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
RegisterSignal(item, COMSIG_ITEM_DROPPED, PROC_REF(on_dropped))
|
||||
|
||||
RegisterSignals(item, list(COMSIG_ITEM_ATTACK,
|
||||
COMSIG_ITEM_ATTACK_SECONDARY,
|
||||
COMSIG_ITEM_ATTACK_ATOM,
|
||||
COMSIG_ITEM_ATTACK_SELF,
|
||||
COMSIG_ITEM_ATTACK_SELF_SECONDARY,
|
||||
COMSIG_ITEM_INTERACTING_WITH_ATOM,
|
||||
COMSIG_ITEM_INTERACTING_WITH_ATOM_SECONDARY,
|
||||
), \
|
||||
PROC_REF(on_item_use))
|
||||
|
||||
/datum/element/pick_and_drop_only/proc/on_dropped(obj/item/item, mob/user)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
UnregisterSignal(item, list(
|
||||
COMSIG_ITEM_DROPPED,
|
||||
COMSIG_ITEM_ATTACK,
|
||||
COMSIG_ITEM_ATTACK_SECONDARY,
|
||||
COMSIG_ITEM_ATTACK_ATOM,
|
||||
COMSIG_ITEM_ATTACK_SELF,
|
||||
COMSIG_ITEM_ATTACK_SELF_SECONDARY,
|
||||
COMSIG_ITEM_INTERACTING_WITH_ATOM,
|
||||
COMSIG_ITEM_INTERACTING_WITH_ATOM_SECONDARY,
|
||||
))
|
||||
|
||||
/datum/element/pick_and_drop_only/proc/on_item_use()
|
||||
SIGNAL_HANDLER
|
||||
// CANCEL EVERYTHING, WAHAHAHA!!
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
@@ -215,6 +215,9 @@
|
||||
icon_state = "vomitnanite_1"
|
||||
random_icon_states = list("vomitnanite_1", "vomitnanite_2", "vomitnanite_3", "vomitnanite_4")
|
||||
|
||||
/// Tracked for voidwalkers to jump to and from
|
||||
GLOBAL_LIST_EMPTY(nebula_vomits)
|
||||
|
||||
/obj/effect/decal/cleanable/vomit/nebula
|
||||
name = "nebula vomit"
|
||||
desc = "Gosh, how... beautiful."
|
||||
@@ -225,11 +228,17 @@
|
||||
/obj/effect/decal/cleanable/vomit/nebula/Initialize(mapload, list/datum/disease/diseases)
|
||||
. = ..()
|
||||
update_appearance(UPDATE_OVERLAYS)
|
||||
GLOB.nebula_vomits += src
|
||||
|
||||
/obj/effect/decal/cleanable/vomit/nebula/update_overlays()
|
||||
. = ..()
|
||||
. += emissive_appearance(icon, icon_state, src, alpha = src.alpha)
|
||||
|
||||
/obj/effect/decal/cleanable/vomit/nebula/Destroy()
|
||||
. = ..()
|
||||
|
||||
GLOB.nebula_vomits -= src
|
||||
|
||||
/// Nebula vomit with extra guests
|
||||
/obj/effect/decal/cleanable/vomit/nebula/worms
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/// Voidwalker murderbone variant focused around the sun (wow yet another fire element antag!!)
|
||||
/mob/living/basic/voidwalker/sunwalker
|
||||
name = "Heliarch"
|
||||
desc = "A cosmic entity covered in stellar corona. You DEFINITELY shouldn't stare."
|
||||
|
||||
icon_state = "sunwalker"
|
||||
|
||||
melee_damage_type = BURN
|
||||
melee_damage_lower = 25
|
||||
melee_damage_upper = 25
|
||||
|
||||
health = 200
|
||||
maxHealth = 200
|
||||
|
||||
obj_damage = 50
|
||||
speed = 0.2
|
||||
|
||||
maximum_survivable_temperature = INFINITY
|
||||
pressure_resistance = INFINITY
|
||||
|
||||
charge = /datum/action/cooldown/mob_cooldown/charge/sunwalker
|
||||
telepathy = /datum/action/cooldown/spell/list_target/telepathy/voidwalker/sunwalker
|
||||
can_do_abductions = FALSE
|
||||
|
||||
regenerate_colour = COLOR_BLUE
|
||||
light_range = 7
|
||||
|
||||
/// Temperature we move our surroundings towards
|
||||
var/hotspot_temperature = 1000
|
||||
/// Gas volume passively exposed to our temperature
|
||||
var/hotspot_volume = 100
|
||||
|
||||
/// Water damage we take on any exposure
|
||||
var/water_damage = 10
|
||||
/// Below this health threshold, we dont take water damage
|
||||
var/water_damage_cutoff = 10
|
||||
|
||||
/mob/living/basic/voidwalker/sunwalker/unique_setup()
|
||||
AddComponent(/datum/component/igniter)
|
||||
AddComponent(/datum/component/vision_hurting, damage_per_second = 0.1, message = null, silent = TRUE)
|
||||
AddComponent(/datum/component/space_dive, /obj/effect/dummy/phased_mob/space_dive/sunwalker)
|
||||
|
||||
create_reagents(1) // Needed for the water reagent interactions to work
|
||||
|
||||
var/static/list/ray_filter = list(type = "rays", size = 32, color = COLOR_BLUE_VERY_LIGHT)
|
||||
add_filter("sunwalker_rays", 3, ray_filter)
|
||||
animate(get_filter("sunwalker_rays"), offset = 1, time = 3 SECONDS, loop = -1, flags = ANIMATION_PARALLEL)
|
||||
|
||||
/mob/living/basic/voidwalker/sunwalker/examine(mob/user)
|
||||
. = ..()
|
||||
|
||||
if(!iscarbon(user))
|
||||
return
|
||||
|
||||
// MY EYEESSS!!!
|
||||
var/mob/living/carbon/carbon = user
|
||||
if(carbon.get_eye_protection() < 1)
|
||||
var/obj/item/organ/eyes/burning_orbs = locate() in carbon.organs
|
||||
burning_orbs?.apply_organ_damage(5)
|
||||
|
||||
/mob/living/basic/voidwalker/sunwalker/UnarmedAttack(atom/target, proximity_flag, list/modifiers)
|
||||
. = ..()
|
||||
|
||||
do_sparks(rand(1, 4), source = target)
|
||||
|
||||
/mob/living/basic/voidwalker/sunwalker/process(seconds_per_tick)
|
||||
. = ..()
|
||||
if(isopenturf(loc))
|
||||
var/turf/location = loc
|
||||
location.hotspot_expose(hotspot_temperature, hotspot_volume)
|
||||
|
||||
if(prob(2))
|
||||
new /obj/effect/hotspot(location)
|
||||
|
||||
/mob/living/basic/voidwalker/sunwalker/reagent_expose(datum/reagent/chem, methods, reac_volume, show_message, touch_protection)
|
||||
. = ..()
|
||||
|
||||
if(istype(chem, /datum/reagent/water) && health > water_damage_cutoff)
|
||||
take_overall_damage(water_damage)
|
||||
playsound(src, 'sound/items/tools/welder.ogg', 80, TRUE, 1)
|
||||
do_sparks(rand(4, 8), source = src)
|
||||
@@ -0,0 +1,41 @@
|
||||
/// Space antagonist that murders everyone in space and nearby it using the power of loads of fire
|
||||
/datum/antagonist/sunwalker
|
||||
name = "\improper Sunwalker"
|
||||
antagpanel_category = ANTAG_GROUP_ABOMINATIONS
|
||||
pref_flag = ROLE_SUNWALKER
|
||||
|
||||
show_in_antagpanel = TRUE
|
||||
antagpanel_category = "Voidwalker"
|
||||
show_name_in_check_antagonists = TRUE
|
||||
show_to_ghosts = TRUE
|
||||
ui_name = "AntagInfoSunwalker"
|
||||
suicide_cry = "FOR THE SUN!!"
|
||||
|
||||
/datum/antagonist/sunwalker/greet()
|
||||
. = ..()
|
||||
owner.announce_objectives()
|
||||
|
||||
/datum/antagonist/sunwalker/on_gain()
|
||||
. = ..()
|
||||
|
||||
forge_objectives()
|
||||
|
||||
/datum/antagonist/sunwalker/forge_objectives()
|
||||
var/datum/objective/sunwalker/objective = new
|
||||
objective.owner = owner
|
||||
objectives += objective
|
||||
|
||||
/datum/objective/sunwalker
|
||||
|
||||
/datum/objective/sunwalker/New()
|
||||
var/list/explanation_texts = list(
|
||||
"Teach them to fear the void. Overhwelm them with your brilliance, then impart the truth of immolation. Seek to destroy, not enlighten.",
|
||||
)
|
||||
explanation_text = pick(explanation_texts)
|
||||
|
||||
if(prob(5))
|
||||
explanation_text = "Man I fucking love glass."
|
||||
..()
|
||||
|
||||
/datum/objective/sunwalker/check_completion()
|
||||
return owner.current.stat != DEAD
|
||||
@@ -3,13 +3,13 @@
|
||||
name = "\improper Voidwalker"
|
||||
antagpanel_category = ANTAG_GROUP_ABOMINATIONS
|
||||
pref_flag = ROLE_VOIDWALKER
|
||||
|
||||
show_in_antagpanel = TRUE
|
||||
antagpanel_category = "Voidwalker"
|
||||
show_name_in_check_antagonists = TRUE
|
||||
show_to_ghosts = TRUE
|
||||
ui_name = "AntagInfoVoidwalker"
|
||||
suicide_cry = "FOR THE VOID!!"
|
||||
preview_outfit = /datum/outfit/voidwalker
|
||||
|
||||
/datum/antagonist/voidwalker/greet()
|
||||
. = ..()
|
||||
@@ -18,30 +18,19 @@
|
||||
/datum/antagonist/voidwalker/on_gain()
|
||||
. = ..()
|
||||
|
||||
var/mob/living/carbon/human/body = owner.current
|
||||
if(ishuman(body))
|
||||
body.set_species(/datum/species/voidwalker)
|
||||
|
||||
forge_objectives()
|
||||
|
||||
/datum/antagonist/voidwalker/on_removal()
|
||||
var/mob/living/carbon/human/body = owner.current
|
||||
if(ishuman(body))
|
||||
body.set_species(/datum/species/human)
|
||||
|
||||
return ..()
|
||||
/datum/antagonist/voidwalker/get_preview_icon()
|
||||
var/mob/living/basic/voidwalker/walker_type = /mob/living/basic/voidwalker
|
||||
var/icon/icon = icon(walker_type::icon, walker_type::icon_state)
|
||||
icon.Crop(5, 18, 30, 44)
|
||||
return finish_preview_icon(icon)
|
||||
|
||||
/datum/antagonist/voidwalker/forge_objectives()
|
||||
var/datum/objective/voidwalker_objective/objective = new
|
||||
objective.owner = owner
|
||||
objectives += objective
|
||||
|
||||
/datum/outfit/voidwalker
|
||||
name = "Voidwalker (Preview only)"
|
||||
|
||||
/datum/outfit/voidwalker/post_equip(mob/living/carbon/human/human, visuals_only)
|
||||
human.set_species(/datum/species/voidwalker)
|
||||
|
||||
/datum/objective/voidwalker_objective
|
||||
|
||||
/datum/objective/voidwalker_objective/New()
|
||||
|
||||
@@ -4,18 +4,22 @@
|
||||
desc = "Stare directly into someone who doesn't see you. Remain in their view for a bit to stun them for 2 seconds and announce your presence to them. "
|
||||
button_icon_state = "terrify"
|
||||
background_icon_state = "bg_void"
|
||||
overlay_icon_state = null
|
||||
panel = null
|
||||
spell_requirements = NONE
|
||||
cooldown_time = 12 SECONDS
|
||||
cast_range = 9
|
||||
active_msg = "You prepare to stare down a target..."
|
||||
deactive_msg = "You refocus your eyes..."
|
||||
|
||||
/// how long we need to stare at someone to unsettle them (woooooh)
|
||||
var/stare_time = 8 SECONDS
|
||||
var/stare_time = 6 SECONDS
|
||||
/// how long we stun someone on successful cast
|
||||
var/stun_time = 2 SECONDS
|
||||
/// stamina damage we doooo
|
||||
var/stamina_damage = 80
|
||||
/// Used briefly for checking if we comitted a combat during our staredown
|
||||
VAR_PRIVATE/in_combat = FALSE
|
||||
|
||||
/datum/action/cooldown/spell/pointed/unsettle/is_valid_target(atom/cast_on)
|
||||
. = ..()
|
||||
@@ -24,26 +28,34 @@
|
||||
cast_on.balloon_alert(owner, "cannot be targeted!")
|
||||
return FALSE
|
||||
|
||||
if(!check_if_in_view(cast_on))
|
||||
if(!check_if_staring(cast_on))
|
||||
owner.balloon_alert(owner, "cannot see you!")
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
return .
|
||||
|
||||
/datum/action/cooldown/spell/pointed/unsettle/cast(mob/living/carbon/human/cast_on)
|
||||
. = ..()
|
||||
|
||||
if(do_after(owner, stare_time, cast_on, IGNORE_TARGET_LOC_CHANGE | IGNORE_USER_LOC_CHANGE, extra_checks = CALLBACK(src, PROC_REF(check_if_in_view), cast_on), hidden = TRUE))
|
||||
spookify(cast_on)
|
||||
return
|
||||
owner.balloon_alert(owner, "line of sight broken!")
|
||||
return SPELL_NO_IMMEDIATE_COOLDOWN
|
||||
RegisterSignals(owner, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_LIVING_ATTACK_ATOM), PROC_REF(is_combatting))
|
||||
|
||||
/datum/action/cooldown/spell/pointed/unsettle/proc/check_if_in_view(mob/living/carbon/human/target)
|
||||
if(do_after(owner, stare_time, cast_on, IGNORE_TARGET_LOC_CHANGE | IGNORE_USER_LOC_CHANGE, extra_checks = CALLBACK(src, PROC_REF(check_if_staring), cast_on), hidden = TRUE))
|
||||
spookify(cast_on)
|
||||
|
||||
else
|
||||
. = SPELL_NO_IMMEDIATE_COOLDOWN
|
||||
|
||||
UnregisterSignal(owner, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_LIVING_ATTACK_ATOM))
|
||||
|
||||
/datum/action/cooldown/spell/pointed/unsettle/proc/check_if_staring(mob/living/carbon/human/target)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(target.is_blind() || !(owner in view(target, world.view)))
|
||||
owner.balloon_alert(owner, "line of sight broken!")
|
||||
return FALSE
|
||||
if(in_combat)
|
||||
owner.balloon_alert(owner, "interrupted by combat!")
|
||||
in_combat = FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/action/cooldown/spell/pointed/unsettle/proc/spookify(mob/living/carbon/human/target)
|
||||
@@ -56,12 +68,70 @@
|
||||
new /obj/effect/temp_visual/circle_wave/unsettle(get_turf(target))
|
||||
SEND_SIGNAL(owner, COMSIG_ATOM_REVEAL)
|
||||
|
||||
/datum/action/cooldown/spell/pointed/unsettle/proc/is_combatting()
|
||||
SIGNAL_HANDLER
|
||||
|
||||
in_combat = TRUE
|
||||
|
||||
/obj/effect/temp_visual/circle_wave/unsettle
|
||||
color = COLOR_PURPLE
|
||||
|
||||
/datum/action/cooldown/spell/list_target/telepathy/voidwalker
|
||||
name = "Transmit"
|
||||
name = "Cosmic Transmit"
|
||||
background_icon_state = "bg_void"
|
||||
button_icon = 'icons/mob/actions/actions_voidwalker.dmi'
|
||||
button_icon_state = "voidwalker_telepathy"
|
||||
panel = null
|
||||
overlay_icon_state = null
|
||||
|
||||
/datum/action/cooldown/spell/list_target/telepathy/voidwalker/sunwalker
|
||||
name = "Stellar Transmit"
|
||||
background_icon_state = "bg_star"
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/charge/sunwalker
|
||||
name = "Stellar Charge"
|
||||
background_icon_state = "bg_star"
|
||||
charge_past = 1
|
||||
charge_damage = 30
|
||||
cooldown_time = 8 SECONDS
|
||||
destroy_objects = FALSE
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/charge/sunwalker/on_move(atom/source, atom/new_loc, atom/target)
|
||||
. = ..()
|
||||
|
||||
new /obj/effect/hotspot(get_turf(owner))
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/charge/sunwalker/charge_end(datum/source)
|
||||
. = ..()
|
||||
|
||||
for(var/turf/open/tile in range(1, owner))
|
||||
new /obj/effect/hotspot(tile)
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/charge/sunwalker/do_charge_indicator(atom/charger, atom/charge_target)
|
||||
return
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/charge/voidwalker
|
||||
name = "Cosmic Dash"
|
||||
button_icon_state = "void_dash"
|
||||
charge_past = 0
|
||||
charge_damage = 20
|
||||
cooldown_time = 8 SECONDS
|
||||
destroy_objects = FALSE
|
||||
charge_distance = 40
|
||||
|
||||
/// Turfs that are valid to target
|
||||
var/turf/valid_target_turf = /turf/open/space
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/charge/voidwalker/do_charge_indicator(atom/charger, atom/charge_target)
|
||||
playsound(owner, 'sound/effects/curse/curse1.ogg', 100)
|
||||
return
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/charge/voidwalker/on_moved(atom/source)
|
||||
return
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/charge/voidwalker/PreActivate(atom/target)
|
||||
if(istype(get_turf(target), valid_target_turf))
|
||||
return ..()
|
||||
|
||||
owner.balloon_alert(owner, "must target [initial(valid_target_turf.name)]!")
|
||||
return FALSE
|
||||
|
||||
@@ -1,147 +0,0 @@
|
||||
///Turn the damage overlays glassy
|
||||
#define GLASSY_OVERLAY_MATRIX list(\
|
||||
1, 2, 2, 0, \
|
||||
0, 1, 0, 0, \
|
||||
0, 0, 1, 0, \
|
||||
0, 0, 0, 1, \
|
||||
0, 0, 0, 0)
|
||||
|
||||
/obj/item/bodypart/head/voidwalker
|
||||
texture_bodypart_overlay = /datum/bodypart_overlay/texture/spacey
|
||||
icon_greyscale = 'icons/mob/human/species/voidwalker.dmi'
|
||||
limb_id = SPECIES_VOIDWALKER
|
||||
is_dimorphic = FALSE
|
||||
bodypart_traits = list(TRAIT_MUTE)
|
||||
head_flags = NONE
|
||||
blocks_emissive = EMISSIVE_BLOCK_NONE
|
||||
|
||||
damage_overlay_color = GLASSY_OVERLAY_MATRIX
|
||||
|
||||
light_brute_msg = "splintered"
|
||||
medium_brute_msg = "cracked"
|
||||
heavy_brute_msg = "shattered"
|
||||
|
||||
light_burn_msg = "bent"
|
||||
medium_burn_msg = "deformed"
|
||||
heavy_burn_msg = "warped"
|
||||
|
||||
damage_examines = list(
|
||||
BRUTE = GLASSY_BRUTE_EXAMINE_TEXT,
|
||||
BURN = GLASSY_BURN_EXAMINE_TEXT,
|
||||
)
|
||||
|
||||
/obj/item/bodypart/chest/voidwalker
|
||||
texture_bodypart_overlay = /datum/bodypart_overlay/texture/spacey
|
||||
icon_greyscale = 'icons/mob/human/species/voidwalker.dmi'
|
||||
limb_id = SPECIES_VOIDWALKER
|
||||
is_dimorphic = FALSE
|
||||
blocks_emissive = EMISSIVE_BLOCK_NONE
|
||||
|
||||
damage_overlay_color = GLASSY_OVERLAY_MATRIX
|
||||
|
||||
light_brute_msg = "splintered"
|
||||
medium_brute_msg = "cracked"
|
||||
heavy_brute_msg = "shattered"
|
||||
|
||||
light_burn_msg = "bent"
|
||||
medium_burn_msg = "deformed"
|
||||
heavy_burn_msg = "warped"
|
||||
|
||||
damage_examines = list(
|
||||
BRUTE = GLASSY_BRUTE_EXAMINE_TEXT,
|
||||
BURN = GLASSY_BURN_EXAMINE_TEXT,
|
||||
)
|
||||
|
||||
/obj/item/bodypart/arm/left/voidwalker
|
||||
texture_bodypart_overlay = /datum/bodypart_overlay/texture/spacey
|
||||
icon_greyscale = 'icons/mob/human/species/voidwalker.dmi'
|
||||
limb_id = SPECIES_VOIDWALKER
|
||||
is_dimorphic = FALSE
|
||||
blocks_emissive = EMISSIVE_BLOCK_NONE
|
||||
|
||||
bodypart_traits = list(TRAIT_CHUNKYFINGERS)
|
||||
|
||||
damage_overlay_color = GLASSY_OVERLAY_MATRIX
|
||||
|
||||
light_brute_msg = "splintered"
|
||||
medium_brute_msg = "cracked"
|
||||
heavy_brute_msg = "shattered"
|
||||
|
||||
light_burn_msg = "bent"
|
||||
medium_burn_msg = "deformed"
|
||||
heavy_burn_msg = "warped"
|
||||
|
||||
damage_examines = list(
|
||||
BRUTE = GLASSY_BRUTE_EXAMINE_TEXT,
|
||||
BURN = GLASSY_BURN_EXAMINE_TEXT,
|
||||
)
|
||||
|
||||
/obj/item/bodypart/arm/right/voidwalker
|
||||
texture_bodypart_overlay = /datum/bodypart_overlay/texture/spacey
|
||||
icon_greyscale = 'icons/mob/human/species/voidwalker.dmi'
|
||||
limb_id = SPECIES_VOIDWALKER
|
||||
is_dimorphic = FALSE
|
||||
blocks_emissive = EMISSIVE_BLOCK_NONE
|
||||
|
||||
bodypart_traits = list(TRAIT_CHUNKYFINGERS)
|
||||
|
||||
damage_overlay_color = GLASSY_OVERLAY_MATRIX
|
||||
|
||||
light_brute_msg = "splintered"
|
||||
medium_brute_msg = "cracked"
|
||||
heavy_brute_msg = "shattered"
|
||||
|
||||
light_burn_msg = "bent"
|
||||
medium_burn_msg = "deformed"
|
||||
heavy_burn_msg = "warped"
|
||||
|
||||
damage_examines = list(
|
||||
BRUTE = GLASSY_BRUTE_EXAMINE_TEXT,
|
||||
BURN = GLASSY_BURN_EXAMINE_TEXT,
|
||||
)
|
||||
|
||||
/obj/item/bodypart/leg/left/voidwalker
|
||||
texture_bodypart_overlay = /datum/bodypart_overlay/texture/spacey
|
||||
icon_greyscale = 'icons/mob/human/species/voidwalker.dmi'
|
||||
limb_id = SPECIES_VOIDWALKER
|
||||
is_dimorphic = FALSE
|
||||
blocks_emissive = EMISSIVE_BLOCK_NONE
|
||||
|
||||
damage_overlay_color = GLASSY_OVERLAY_MATRIX
|
||||
|
||||
light_brute_msg = "splintered"
|
||||
medium_brute_msg = "cracked"
|
||||
heavy_brute_msg = "shattered"
|
||||
|
||||
light_burn_msg = "bent"
|
||||
medium_burn_msg = "deformed"
|
||||
heavy_burn_msg = "warped"
|
||||
|
||||
damage_examines = list(
|
||||
BRUTE = GLASSY_BRUTE_EXAMINE_TEXT,
|
||||
BURN = GLASSY_BURN_EXAMINE_TEXT,
|
||||
)
|
||||
|
||||
/obj/item/bodypart/leg/right/voidwalker
|
||||
texture_bodypart_overlay = /datum/bodypart_overlay/texture/spacey
|
||||
icon_greyscale = 'icons/mob/human/species/voidwalker.dmi'
|
||||
limb_id = SPECIES_VOIDWALKER
|
||||
is_dimorphic = FALSE
|
||||
blocks_emissive = EMISSIVE_BLOCK_NONE
|
||||
|
||||
damage_overlay_color = GLASSY_OVERLAY_MATRIX
|
||||
|
||||
light_brute_msg = "splintered"
|
||||
medium_brute_msg = "cracked"
|
||||
heavy_brute_msg = "shattered"
|
||||
|
||||
light_burn_msg = "bent"
|
||||
medium_burn_msg = "deformed"
|
||||
heavy_burn_msg = "warped"
|
||||
|
||||
damage_examines = list(
|
||||
BRUTE = GLASSY_BRUTE_EXAMINE_TEXT,
|
||||
BURN = GLASSY_BURN_EXAMINE_TEXT,
|
||||
)
|
||||
|
||||
#undef GLASSY_OVERLAY_MATRIX
|
||||
@@ -93,7 +93,7 @@ GLOBAL_LIST_EMPTY(voidwalker_void)
|
||||
. = ..()
|
||||
|
||||
gone.remove_traits(wisp_driver_traits, REF(src))
|
||||
to_chat(gone, span_boldwarning("You feel it would be very bad to get caught again."))
|
||||
to_chat(gone, span_boldwarning("You feel watched."))
|
||||
qdel(src)
|
||||
|
||||
/// Loop us around, maybe, if we're going to bump into a wall
|
||||
|
||||
@@ -16,12 +16,11 @@
|
||||
/obj/item/clothing/head/helmet/skull/cosmic/attack_self(mob/user, modifiers)
|
||||
. = ..()
|
||||
|
||||
if(!uses || !ishuman(user))
|
||||
if(istype(user, /mob/living/basic/voidwalker))
|
||||
to_chat(user, span_bolddanger("OH GOD NOO!!!! WHYYYYYYYYY??!!! WHO WOULD DO THIS?!!"))
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/hewmon = user
|
||||
if(is_species(hewmon, /datum/species/voidwalker))
|
||||
to_chat(user, span_bolddanger("OH GOD NOO!!!! WHYYYYYYYYY!!!!! WHO WOULD DO THIS?!!"))
|
||||
if(!uses || !ishuman(user))
|
||||
return
|
||||
|
||||
to_chat(user, span_purple("You begin staring into \the [src]..."))
|
||||
@@ -29,14 +28,75 @@
|
||||
if(!do_after(user, 10 SECONDS, src))
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/starer = user
|
||||
starer.cure_trauma_type(/datum/brain_trauma/voided) //this wouldn't make much sense to have anymore
|
||||
|
||||
starer.gain_trauma(/datum/brain_trauma/voided/stable)
|
||||
to_chat(user, span_purple("And a whole world opens up to you."))
|
||||
playsound(get_turf(user), 'sound/effects/curse/curse5.ogg', 60)
|
||||
|
||||
uses--
|
||||
if(uses <= 0)
|
||||
icon_state = drained_icon_state
|
||||
light_on = FALSE
|
||||
|
||||
var/mob/living/carbon/human/starer = user
|
||||
|
||||
if(starer.has_trauma_type(/datum/brain_trauma/voided/stable))
|
||||
starer.put_in_hands(new /obj/item/void_eater(), TRUE, forced = TRUE)
|
||||
playsound(starer, 'sound/effects/blob/blobattack.ogg', 60, TRUE)
|
||||
else
|
||||
starer.cure_trauma_type(/datum/brain_trauma/voided) //this wouldn't make much sense to have anymore
|
||||
starer.gain_trauma(/datum/brain_trauma/voided/stable)
|
||||
|
||||
to_chat(user, span_purple("And a whole world opens up to you."))
|
||||
playsound(get_turf(user), 'sound/effects/curse/curse5.ogg', 60)
|
||||
|
||||
/**
|
||||
* An armblade that pops windows
|
||||
*/
|
||||
/obj/item/void_eater
|
||||
name = "void eater" //as opposed to full eater
|
||||
desc = "A deformed appendage, capable of shattering any glass and any flesh."
|
||||
icon = 'icons/obj/weapons/voidwalker_items.dmi'
|
||||
icon_state = "tentacle"
|
||||
inhand_icon_state = "tentacle"
|
||||
icon_angle = 180
|
||||
force = 25
|
||||
armour_penetration = 35
|
||||
lefthand_file = 'icons/mob/inhands/antag/voidwalker_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/antag/voidwalker_righthand.dmi'
|
||||
blocks_emissive = EMISSIVE_BLOCK_NONE
|
||||
item_flags = ABSTRACT | DROPDEL
|
||||
resistance_flags = INDESTRUCTIBLE | ACID_PROOF | FIRE_PROOF | LAVA_PROOF | UNACIDABLE
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
tool_behaviour = TOOL_MINING
|
||||
hitsound = 'sound/items/weapons/bladeslice.ogg'
|
||||
wound_bonus = -30
|
||||
exposed_wound_bonus = 20
|
||||
|
||||
/obj/item/void_eater/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
ADD_TRAIT(src, TRAIT_NODROP, HAND_REPLACEMENT_TRAIT)
|
||||
AddComponent(/datum/component/temporary_glass_shatterer)
|
||||
|
||||
/obj/effect/spawner/random/glass_shards
|
||||
loot = list(/obj/item/shard = 2, /obj/item/shard/plasma = 1, /obj/item/shard/titanium = 1, /obj/item/shard/plastitanium = 1)
|
||||
spawn_random_offset = TRUE
|
||||
|
||||
/// Min shards we generate
|
||||
var/min_spawn = 4
|
||||
/// Max shards we generate
|
||||
var/max_spawn = 6
|
||||
|
||||
/obj/effect/spawner/random/glass_shards/Initialize(mapload)
|
||||
spawn_loot_count = rand(min_spawn, max_spawn)
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/effect/spawner/random/glass_shards/mini
|
||||
min_spawn = 1
|
||||
max_spawn = 2
|
||||
|
||||
/obj/effect/spawner/random/glass_debris
|
||||
/// Weighted list for the debris we spawn
|
||||
loot = list(
|
||||
/obj/effect/decal/cleanable/glass = 2,
|
||||
/obj/effect/decal/cleanable/glass/plasma = 1,
|
||||
/obj/effect/decal/cleanable/glass/titanium = 1,
|
||||
/obj/effect/decal/cleanable/glass/plastitanium = 1,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,347 @@
|
||||
//Minimum strength to convert a wall into a void window.
|
||||
#define WALL_CONVERT_STRENGTH 40
|
||||
|
||||
/// Voidwalker mob to void all over the place
|
||||
/mob/living/basic/voidwalker
|
||||
name = "voidwalker"
|
||||
desc = "A glass-like entity from the void between stars. You probably shouldn't stare."
|
||||
icon = 'icons/mob/simple/voidwalker.dmi'
|
||||
icon_state = "voidwalker"
|
||||
|
||||
mob_biotypes = MOB_SPECIAL
|
||||
maxHealth = 150
|
||||
health = 150
|
||||
damage_coeff = list(BRUTE = 1, BURN = 0.66, TOX = 1, STAMINA = 1, OXY = 0)
|
||||
|
||||
pressure_resistance = 200
|
||||
combat_mode = TRUE
|
||||
|
||||
obj_damage = 15
|
||||
|
||||
melee_damage_lower = 12
|
||||
melee_damage_upper = 15
|
||||
melee_attack_cooldown = CLICK_CD_MELEE
|
||||
|
||||
melee_damage_type = OXY
|
||||
|
||||
attack_sound = 'sound/items/weapons/shrink_hit.ogg'
|
||||
attack_vis_effect = ATTACK_EFFECT_VOID
|
||||
|
||||
faction = list(FACTION_CARP)
|
||||
|
||||
habitable_atmos = null
|
||||
minimum_survivable_temperature = 0
|
||||
maximum_survivable_temperature = 1500
|
||||
|
||||
basic_mob_flags = DEL_ON_DEATH
|
||||
speed = 0
|
||||
|
||||
hud_type = /datum/hud/dextrous/voidwalker
|
||||
hud_possible = list(ANTAG_HUD)
|
||||
sight = SEE_TURFS | SEE_MOBS
|
||||
|
||||
/// Color of our regen outline
|
||||
var/regenerate_colour = COLOR_GRAY
|
||||
|
||||
/// How long does it take to kidnap them?
|
||||
var/kidnap_time = 6 SECONDS
|
||||
/// Are we kidnapping right now?
|
||||
var/kidnapping = FALSE
|
||||
|
||||
/// Our stare/stun ability
|
||||
var/datum/action/cooldown/spell/pointed/unsettle/unsettle
|
||||
/// Our means of communicating with the world
|
||||
var/datum/action/cooldown/spell/list_target/telepathy/voidwalker/telepathy = /datum/action/cooldown/spell/list_target/telepathy/voidwalker
|
||||
/// Our cool charge ability
|
||||
var/datum/action/cooldown/mob_cooldown/charge/charge = /datum/action/cooldown/mob_cooldown/charge/voidwalker
|
||||
|
||||
/// Alpha we have in space
|
||||
var/space_alpha = 0
|
||||
/// Alpha we have elsewhere
|
||||
var/non_space_alpha = 255
|
||||
|
||||
/// Speed modifier given when in gravity
|
||||
var/datum/movespeed_modifier/speed_modifier = /datum/movespeed_modifier/grounded_voidwalker
|
||||
|
||||
/// Cooldown for converting walls to void windows
|
||||
COOLDOWN_DECLARE(wall_conversion)
|
||||
/// How many wall conversions can we perform before we have to refresh?
|
||||
var/conversions_remaining = 2
|
||||
|
||||
/// Damage type we do for rightclicks
|
||||
var/rclick_damage_type = BRUTE
|
||||
/// Can we speak?
|
||||
var/can_speak = FALSE
|
||||
/// Turf that our abilities rely on. VVing this automatically sets all the components and removes space dependency stuff if the new tile isnt space
|
||||
var/home_turf = /turf/open/space
|
||||
/// Decal that we can kidnap on
|
||||
var/kidnapping_decal = /obj/effect/decal/cleanable/vomit/nebula
|
||||
/// Toggle for abduction interactions, in-case we have non-kidnap subtypes ()
|
||||
var/can_do_abductions = TRUE
|
||||
|
||||
/mob/living/basic/voidwalker/Initialize(mapload, mob/tamer)
|
||||
ADD_TRAIT(src, TRAIT_FREE_HYPERSPACE_MOVEMENT, INNATE_TRAIT) //Need to set before init cause if we init in hyperspace we get dragged before the trait can be added
|
||||
. = ..()
|
||||
|
||||
AddElement(/datum/element/simple_flying)
|
||||
AddElement(/datum/element/glass_pacifist)
|
||||
|
||||
AddComponent(/datum/component/regenerator, brute_per_second = 2, burn_per_second = 2, outline_colour = regenerate_colour, regen_check = CALLBACK(src, PROC_REF(can_regen)))
|
||||
AddComponent(/datum/component/glass_passer, deform_glass = 5 SECONDS)
|
||||
AddComponent(/datum/component/planet_allergy)
|
||||
|
||||
AddElement(/datum/element/dextrous, hud_type = hud_type)
|
||||
AddComponent(/datum/component/basic_inhands, x_offset = -2)
|
||||
|
||||
AddElement(/datum/element/pick_and_drop_only)
|
||||
|
||||
AddComponent(/datum/component/debris_bleeder, \
|
||||
list(/obj/effect/spawner/random/glass_shards = 20, /obj/effect/spawner/random/glass_debris = 0), \
|
||||
BRUTE, SFX_SHATTER, sound_threshold = 20)
|
||||
|
||||
charge = new charge(src)
|
||||
charge.Grant(src)
|
||||
|
||||
// Glass passing is handled by the glass passer component
|
||||
passtable_on(src, type)
|
||||
|
||||
// Voidwalker lore is that radio's actually attracted them, so they should be able to listen to it
|
||||
var/obj/item/radio/internal_radio = new /obj/item/radio(src)
|
||||
internal_radio.keyslot = /obj/item/encryptionkey/heads/captain
|
||||
internal_radio.subspace_transmission = TRUE
|
||||
internal_radio.canhear_range = 0 // anything higher and people in the area will hear it too
|
||||
internal_radio.recalculateChannels()
|
||||
|
||||
telepathy = new telepathy(src)
|
||||
telepathy.Grant(src)
|
||||
|
||||
unique_setup()
|
||||
|
||||
/// Stuff you might want different on subtypes
|
||||
/mob/living/basic/voidwalker/proc/unique_setup()
|
||||
AddComponent(/datum/component/space_camo, space_alpha, non_space_alpha, 255, 5 SECONDS, image(icon, icon_state + "_stealthed", ABOVE_LIGHTING_PLANE))
|
||||
AddComponent(/datum/component/space_dive, /obj/effect/dummy/phased_mob/space_dive/voidwalker)
|
||||
|
||||
unsettle = new(src)
|
||||
unsettle.Grant(src)
|
||||
|
||||
fully_replace_character_name(null, pick(GLOB.voidwalker_names))
|
||||
|
||||
/mob/living/basic/voidwalker/Destroy()
|
||||
QDEL_NULL(unsettle)
|
||||
QDEL_NULL(telepathy)
|
||||
QDEL_NULL(charge)
|
||||
|
||||
return ..()
|
||||
|
||||
/// Called on COMSIG_LIVING_UNARMED_ATTACK
|
||||
/mob/living/basic/voidwalker/early_melee_attack(atom/target, list/modifiers, ignore_cooldown)
|
||||
. = ..()
|
||||
|
||||
if(!. || !can_do_abductions)
|
||||
return
|
||||
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/hewmon = target
|
||||
|
||||
var/should_attack = try_kidnap(hewmon)
|
||||
|
||||
if(!should_attack)
|
||||
return FALSE
|
||||
|
||||
if(hewmon.stat == HARD_CRIT && !hewmon.has_trauma_type(/datum/brain_trauma/voided))
|
||||
hewmon.balloon_alert(src, "is in crit!")
|
||||
hewmon.Stun(5 SECONDS) // blocks some crit movement mechanics from a bunch of sources
|
||||
return FALSE
|
||||
|
||||
// left click
|
||||
if(LAZYACCESS(modifiers, LEFT_CLICK))
|
||||
melee_damage_type = ishuman(target) ? initial(melee_damage_type) : rclick_damage_type
|
||||
|
||||
// Right click
|
||||
else
|
||||
melee_damage_type = rclick_damage_type
|
||||
|
||||
if(!istype(target, /turf/closed/wall))
|
||||
return
|
||||
INVOKE_ASYNC(src, PROC_REF(try_convert_wall), target)
|
||||
return TRUE
|
||||
|
||||
/// Called by the regenerator component so we only regen in space
|
||||
/mob/living/basic/voidwalker/proc/can_regen()
|
||||
if(istype(get_turf(src), home_turf))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/basic/voidwalker/can_speak(allow_mimes)
|
||||
return can_speak && ..()
|
||||
|
||||
/mob/living/basic/voidwalker/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change)
|
||||
. = ..()
|
||||
|
||||
if(!isturf(loc) || !speed_modifier)
|
||||
return
|
||||
|
||||
var/turf/new_turf = loc
|
||||
|
||||
//apply debufs for being in gravity
|
||||
var/area/local_area = get_area(new_turf)
|
||||
if(new_turf.has_gravity() && !is_area_nearby_station(local_area))
|
||||
add_movespeed_modifier(speed_modifier)
|
||||
//remove debufs for not being in gravity
|
||||
else
|
||||
remove_movespeed_modifier(speed_modifier)
|
||||
|
||||
/mob/living/basic/voidwalker/death()
|
||||
var/turf/spawn_loc = get_turf(src)
|
||||
new /obj/effect/spawner/random/glass_shards(spawn_loc)
|
||||
new /obj/item/clothing/head/helmet/skull/cosmic(spawn_loc)
|
||||
playsound(get_turf(src), SFX_SHATTER, 100)
|
||||
|
||||
return ..()
|
||||
|
||||
///
|
||||
/// Kidnapping
|
||||
///
|
||||
|
||||
/// Start the kidnap interactions, including surprises for those who are already voided
|
||||
/mob/living/basic/voidwalker/proc/try_kidnap(mob/living/carbon/human/victim)
|
||||
if(victim.has_trauma_type(/datum/brain_trauma/voided))
|
||||
victim.balloon_alert(src, "already voided!")
|
||||
new /obj/effect/temp_visual/circle_wave/unsettle(get_turf(victim))
|
||||
victim.SetSleeping(30 SECONDS)
|
||||
return FALSE
|
||||
|
||||
if(victim.stat == DEAD)
|
||||
victim.balloon_alert(src, "is dead!")
|
||||
return FALSE
|
||||
|
||||
if(victim.stat == CONSCIOUS) //we're still beating them up!!
|
||||
return TRUE
|
||||
|
||||
if(!istype(get_turf(victim), home_turf) && !(locate(kidnapping_decal) in get_turf(victim)))
|
||||
victim.balloon_alert(src, "not in space!")
|
||||
return FALSE
|
||||
|
||||
if(!kidnapping)
|
||||
INVOKE_ASYNC(src, PROC_REF(kidnap), src, victim)
|
||||
return FALSE
|
||||
|
||||
/// Start kidnapping the victim
|
||||
/mob/living/basic/voidwalker/proc/kidnap(mob/living/parent, mob/living/victim)
|
||||
victim.Paralyze(kidnap_time) //so they don't get up if we already got em
|
||||
|
||||
var/static/list/wave_filter = list(type = "wave", x = 2, size = 4)
|
||||
victim.add_filter("wave_filter_kidnap", 3, wave_filter)
|
||||
animate(victim.get_filter("wave_filter_kidnap"), offset = 32, time = kidnap_time)
|
||||
|
||||
kidnapping = TRUE
|
||||
|
||||
if(do_after(parent, kidnap_time, victim, extra_checks = CALLBACK(src, PROC_REF(check_incapacitated), victim)))
|
||||
take_them(victim)
|
||||
|
||||
victim.remove_filter("wave_filter_kidnap")
|
||||
|
||||
kidnapping = FALSE
|
||||
|
||||
/// Woosh! You got takened
|
||||
/mob/living/basic/voidwalker/proc/take_them(mob/living/victim)
|
||||
if(ishuman(victim))
|
||||
var/mob/living/carbon/human/hewmon = victim
|
||||
hewmon.gain_trauma(/datum/brain_trauma/voided)
|
||||
|
||||
victim.flash_act(INFINITY, override_blindness_check = TRUE, visual = TRUE, type = /atom/movable/screen/fullscreen/flash/black)
|
||||
new /obj/effect/temp_visual/circle_wave/unsettle(get_turf(victim))
|
||||
|
||||
if(!SSmapping.lazy_load_template(LAZY_TEMPLATE_KEY_VOIDWALKER_VOID) || !GLOB.voidwalker_void.len)
|
||||
victim.forceMove(get_random_station_turf())
|
||||
victim.heal_overall_damage(brute = 80, burn = 20)
|
||||
CRASH("[victim] was instantly dumped after being voidwalker kidnapped due to a missing landmark!")
|
||||
else
|
||||
victim.heal_and_revive(90)
|
||||
victim.adjustOxyLoss(-100, FALSE)
|
||||
|
||||
conversions_remaining++
|
||||
|
||||
var/obj/wisp = new /obj/effect/wisp_mobile (get_turf(pick(GLOB.voidwalker_void)))
|
||||
victim.forceMove(wisp)
|
||||
|
||||
/// Check if theyre still incapacitated for the kidnap do_after
|
||||
/mob/living/basic/voidwalker/proc/check_incapacitated(mob/living/carbon/human/kidnappee)
|
||||
return kidnappee.incapacitated
|
||||
|
||||
/// Modding the voidwalker is funny, so setting the home_turf sets everything right for easy of modding
|
||||
/mob/living/basic/voidwalker/vv_edit_var(vname, vval)
|
||||
. = ..()
|
||||
// This is all very snowflakey code but like, it's supposed to be. It's just for helping admins mod it
|
||||
if(vname == NAMEOF(src, home_turf))
|
||||
var/datum/component/space_camo/camo = GetComponent(/datum/component/space_camo)
|
||||
var/datum/component/space_dive/dive = GetComponent(/datum/component/space_dive)
|
||||
|
||||
camo.camo_tile = vval
|
||||
dive.diveable_turf = vval
|
||||
if(istype(charge, /datum/action/cooldown/mob_cooldown/charge/voidwalker))
|
||||
var/datum/action/cooldown/mob_cooldown/charge/voidwalker/charge_voidwalker = charge
|
||||
charge_voidwalker.valid_target_turf = vval
|
||||
|
||||
if(!isspaceturf(vval))
|
||||
qdel(GetComponent(/datum/component/planet_allergy))
|
||||
remove_movespeed_modifier(speed_modifier)
|
||||
speed_modifier = null
|
||||
|
||||
///
|
||||
/// Wall Conversion
|
||||
///
|
||||
|
||||
/// Attempt to convert a wall into passable voidwalker windows
|
||||
/mob/living/basic/voidwalker/proc/try_convert_wall(turf/closed/wall/our_wall)
|
||||
if(!conversions_remaining)
|
||||
balloon_alert(src, "need more kidnaps!")
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
if(!COOLDOWN_FINISHED(src, wall_conversion))
|
||||
balloon_alert(src, "must wait [DisplayTimeText(COOLDOWN_TIMELEFT(src, wall_conversion))]!")
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
if(!check_wall_validity(our_wall, src, silent = FALSE))
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
playsound(our_wall, 'sound/effects/magic/blind.ogg', 100, TRUE)
|
||||
new /obj/effect/temp_visual/transmute_tile_flash(our_wall)
|
||||
|
||||
var/obj/particles = new /obj/effect/abstract/particle_holder (our_wall, /particles/void_wall)
|
||||
|
||||
balloon_alert(src, "opening window...")
|
||||
if(!do_after(src, 8 SECONDS, our_wall, hidden = TRUE))
|
||||
qdel(particles)
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
if(!conversions_remaining)
|
||||
qdel(particles)
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
qdel(particles)
|
||||
|
||||
var/list/target_walls = list()
|
||||
target_walls += our_wall
|
||||
for(var/turf/closed/wall/adjacent_wall in orange(1, our_wall))
|
||||
if(check_wall_validity(adjacent_wall))
|
||||
target_walls += adjacent_wall
|
||||
|
||||
playsound(our_wall, 'sound/effects/magic/blind.ogg', 100, TRUE)
|
||||
|
||||
for(var/turf/closed/wall/targeted_wall in target_walls)
|
||||
new /obj/effect/temp_visual/transmute_tile_flash(targeted_wall)
|
||||
targeted_wall.ScrapeAway()
|
||||
new /obj/structure/window/fulltile/voidwalker(targeted_wall)
|
||||
new /obj/structure/grille(targeted_wall)
|
||||
|
||||
conversions_remaining--
|
||||
COOLDOWN_START(src, wall_conversion, 60 SECONDS)
|
||||
|
||||
/// Check if the wall is valid for conversion
|
||||
/mob/living/basic/voidwalker/proc/check_wall_validity(turf/closed/wall/wall_to_check, silent = TRUE)
|
||||
if(wall_to_check.hardness < WALL_CONVERT_STRENGTH)
|
||||
if(!silent)
|
||||
balloon_alert(src, "too strong!")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
#undef WALL_CONVERT_STRENGTH
|
||||
@@ -1,135 +0,0 @@
|
||||
/// Voidwalker eyes with nightvision and thermals
|
||||
/obj/item/organ/eyes/voidwalker
|
||||
name = "blackened orbs"
|
||||
desc = "These orbs will withstand the light of the sun, yet still see within the darkest voids."
|
||||
icon_state = "eyes_voidwalker"
|
||||
eye_icon_state = null
|
||||
blink_animation = FALSE
|
||||
iris_overlay = null
|
||||
pepperspray_protect = TRUE
|
||||
flash_protect = FLASH_PROTECTION_WELDER
|
||||
color_cutoffs = list(20, 10, 40)
|
||||
sight_flags = SEE_MOBS
|
||||
|
||||
/// Voidwalker brain stacked with a lot of the abilities
|
||||
/obj/item/organ/brain/voidwalker
|
||||
name = "cosmic brain"
|
||||
desc = "A mind fully integrated into the cosmic thread."
|
||||
icon = 'icons/obj/medical/organs/shadow_organs.dmi'
|
||||
can_smoothen_out = FALSE
|
||||
|
||||
/// Alpha we have in space
|
||||
var/space_alpha = 15
|
||||
/// Alpha we have elsewhere
|
||||
var/non_space_alpha = 255
|
||||
/// We settle the un
|
||||
var/datum/action/unsettle = /datum/action/cooldown/spell/pointed/unsettle
|
||||
/// Regen effect we have in space
|
||||
var/datum/status_effect/regen = /datum/status_effect/space_regeneration
|
||||
/// Speed modifier given when in gravity
|
||||
var/datum/movespeed_modifier/speed_modifier = /datum/movespeed_modifier/grounded_voidwalker
|
||||
/// The void eater weapon
|
||||
var/obj/item/glass_breaker
|
||||
/// Our brain transmit telepathy spell
|
||||
var/datum/action/transmit = /datum/action/cooldown/spell/list_target/telepathy/voidwalker
|
||||
|
||||
/obj/item/organ/brain/voidwalker/on_mob_insert(mob/living/carbon/organ_owner, special, movement_flags)
|
||||
. = ..()
|
||||
|
||||
RegisterSignal(organ_owner, COMSIG_ATOM_ENTERING, PROC_REF(on_atom_entering))
|
||||
|
||||
organ_owner.AddComponent(/datum/component/space_camo, space_alpha, non_space_alpha, 5 SECONDS)
|
||||
|
||||
organ_owner.AddElement(/datum/element/only_pull_living)
|
||||
organ_owner.AddElement(/datum/element/glass_pacifist)
|
||||
organ_owner.AddElement(/datum/element/no_crit_hitting)
|
||||
|
||||
organ_owner.apply_status_effect(regen)
|
||||
|
||||
unsettle = new unsettle(organ_owner)
|
||||
unsettle.Grant(organ_owner)
|
||||
|
||||
transmit = new transmit(organ_owner)
|
||||
transmit.Grant(organ_owner)
|
||||
|
||||
glass_breaker = new/obj/item/void_eater
|
||||
organ_owner.put_in_hands(glass_breaker)
|
||||
|
||||
/obj/item/organ/brain/voidwalker/on_mob_remove(mob/living/carbon/organ_owner, special, movement_flags)
|
||||
. = ..()
|
||||
|
||||
UnregisterSignal(organ_owner, COMSIG_ENTER_AREA)
|
||||
alpha = 255
|
||||
|
||||
qdel(organ_owner.GetComponent(/datum/component/space_camo))
|
||||
|
||||
organ_owner.RemoveElement(/datum/element/only_pull_living)
|
||||
organ_owner.RemoveElement(/datum/element/glass_pacifist)
|
||||
organ_owner.RemoveElement(/datum/element/no_crit_hitting)
|
||||
|
||||
organ_owner.remove_status_effect(regen)
|
||||
|
||||
unsettle.Remove(organ_owner)
|
||||
unsettle = initial(unsettle)
|
||||
|
||||
transmit.Remove(organ_owner)
|
||||
transmit = initial(transmit)
|
||||
|
||||
QDEL_NULL(glass_breaker)
|
||||
|
||||
/obj/item/organ/brain/voidwalker/proc/on_atom_entering(mob/living/carbon/organ_owner, atom/entering)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!isturf(entering))
|
||||
return
|
||||
|
||||
var/turf/new_turf = entering
|
||||
|
||||
//apply debufs for being in gravity
|
||||
var/area/local_area = get_area(new_turf)
|
||||
if(new_turf.has_gravity() && !is_area_nearby_station(local_area))
|
||||
organ_owner.add_movespeed_modifier(speed_modifier)
|
||||
//remove debufs for not being in gravity
|
||||
else
|
||||
organ_owner.remove_movespeed_modifier(speed_modifier)
|
||||
|
||||
/obj/item/organ/brain/voidwalker/on_death()
|
||||
. = ..()
|
||||
|
||||
var/turf/spawn_loc = get_turf(owner)
|
||||
new /obj/effect/spawner/random/glass_shards(spawn_loc)
|
||||
new /obj/item/clothing/head/helmet/skull/cosmic(spawn_loc)
|
||||
playsound(get_turf(owner), SFX_SHATTER, 100)
|
||||
|
||||
qdel(owner)
|
||||
|
||||
/obj/item/implant/radio/voidwalker
|
||||
radio_key = /obj/item/encryptionkey/heads/captain
|
||||
actions_types = null
|
||||
|
||||
/obj/effect/spawner/random/glass_shards
|
||||
loot = list(/obj/item/shard = 2, /obj/item/shard/plasma = 1, /obj/item/shard/titanium = 1, /obj/item/shard/plastitanium = 1)
|
||||
spawn_random_offset = TRUE
|
||||
|
||||
/// Min shards we generate
|
||||
var/min_spawn = 4
|
||||
/// Max shards we generate
|
||||
var/max_spawn = 6
|
||||
|
||||
/obj/effect/spawner/random/glass_shards/Initialize(mapload)
|
||||
spawn_loot_count = rand(min_spawn, max_spawn)
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/effect/spawner/random/glass_shards/mini
|
||||
min_spawn = 1
|
||||
max_spawn = 2
|
||||
|
||||
/obj/effect/spawner/random/glass_debris
|
||||
/// Weighted list for the debris we spawn
|
||||
loot = list(
|
||||
/obj/effect/decal/cleanable/glass = 2,
|
||||
/obj/effect/decal/cleanable/glass/plasma = 1,
|
||||
/obj/effect/decal/cleanable/glass/titanium = 1,
|
||||
/obj/effect/decal/cleanable/glass/plastitanium = 1,
|
||||
)
|
||||
@@ -1,15 +1,30 @@
|
||||
/particles/void_kidnap
|
||||
/particles/void_wall
|
||||
icon = 'icons/effects/particles/voidwalker.dmi'
|
||||
icon_state = list("kidnap_1" = 1, "kidnap_2" = 1, "kidnap_3" = 2)
|
||||
width = 100
|
||||
height = 300
|
||||
count = 1000
|
||||
spawning = 20
|
||||
spawning = 3
|
||||
lifespan = 1.5 SECONDS
|
||||
fade = 1 SECONDS
|
||||
velocity = list(0, 0.4, 0)
|
||||
position = generator(GEN_SPHERE, 12, 12, NORMAL_RAND)
|
||||
drift = generator(GEN_SPHERE, 0, 1, NORMAL_RAND)
|
||||
friction = 0.2
|
||||
gravity = list(0.95, 0)
|
||||
gravity = list(0, 0.1)
|
||||
grow = 0.05
|
||||
|
||||
/particles/void_vomit
|
||||
icon = 'icons/effects/particles/voidwalker.dmi'
|
||||
icon_state = list("void_1" = 1, "void_2" = 5)
|
||||
width = 100
|
||||
height = 300
|
||||
count = 100
|
||||
spawning = 1
|
||||
lifespan = 3 SECONDS
|
||||
fade = 2 SECONDS
|
||||
velocity = list(0, 0.1, 0)
|
||||
position = generator(GEN_SPHERE, 6, 6, NORMAL_RAND)
|
||||
drift = generator(GEN_SPHERE, 0, 0.05, NORMAL_RAND)
|
||||
friction = 0.1
|
||||
gravity = list(0, 0.50)
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
/// Species for the voidwalker antagonist
|
||||
/datum/species/voidwalker
|
||||
name = "\improper Voidling"
|
||||
id = SPECIES_VOIDWALKER
|
||||
sexes = FALSE
|
||||
inherent_traits = list(
|
||||
TRAIT_NOBREATH,
|
||||
TRAIT_NO_UNDERWEAR,
|
||||
TRAIT_RADIMMUNE,
|
||||
TRAIT_VIRUSIMMUNE,
|
||||
TRAIT_NOBLOOD,
|
||||
TRAIT_NODISMEMBER,
|
||||
TRAIT_NEVER_WOUNDED,
|
||||
TRAIT_MOVE_FLYING,
|
||||
TRAIT_RESISTCOLD,
|
||||
TRAIT_RESISTHIGHPRESSURE,
|
||||
TRAIT_RESISTLOWPRESSURE,
|
||||
TRAIT_NOHUNGER,
|
||||
TRAIT_FREE_HYPERSPACE_MOVEMENT,
|
||||
TRAIT_ADVANCEDTOOLUSER,
|
||||
TRAIT_NO_BLOOD_OVERLAY,
|
||||
TRAIT_NO_THROWING,
|
||||
TRAIT_GENELESS,
|
||||
)
|
||||
changesource_flags = MIRROR_BADMIN
|
||||
|
||||
bodypart_overrides = list(
|
||||
BODY_ZONE_HEAD = /obj/item/bodypart/head/voidwalker,
|
||||
BODY_ZONE_CHEST = /obj/item/bodypart/chest/voidwalker,
|
||||
BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/voidwalker,
|
||||
BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/voidwalker,
|
||||
BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/voidwalker,
|
||||
BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/voidwalker,
|
||||
)
|
||||
|
||||
no_equip_flags = ITEM_SLOT_OCLOTHING | ITEM_SLOT_ICLOTHING | ITEM_SLOT_GLOVES | ITEM_SLOT_MASK | ITEM_SLOT_HEAD | ITEM_SLOT_FEET | ITEM_SLOT_BACK | ITEM_SLOT_EARS | ITEM_SLOT_EYES
|
||||
|
||||
mutantbrain = /obj/item/organ/brain/voidwalker
|
||||
mutanteyes = /obj/item/organ/eyes/voidwalker
|
||||
mutantheart = null
|
||||
mutantlungs = null
|
||||
mutanttongue = null
|
||||
|
||||
siemens_coeff = 0
|
||||
|
||||
/datum/species/voidwalker/on_species_gain(mob/living/carbon/human/human_who_gained_species, datum/species/old_species, pref_load, regenerate_icons)
|
||||
. = ..()
|
||||
|
||||
human_who_gained_species.AddComponent(/datum/component/glass_passer)
|
||||
human_who_gained_species.AddComponent(/datum/component/space_dive)
|
||||
human_who_gained_species.AddComponent(/datum/component/space_kidnap)
|
||||
|
||||
var/obj/item/implant/radio = new /obj/item/implant/radio/voidwalker (human_who_gained_species)
|
||||
radio.implant(human_who_gained_species, null, TRUE, TRUE)
|
||||
|
||||
human_who_gained_species.AddComponent(/datum/component/planet_allergy)
|
||||
|
||||
human_who_gained_species.fully_replace_character_name(null, pick(GLOB.voidwalker_names))
|
||||
|
||||
/datum/species/voidwalker/on_species_loss(mob/living/carbon/human/human, datum/species/new_species, pref_load)
|
||||
. = ..()
|
||||
|
||||
qdel(human.GetComponent(/datum/component/glass_passer))
|
||||
qdel(human.GetComponent(/datum/component/space_dive))
|
||||
qdel(human.GetComponent(/datum/component/space_kidnap))
|
||||
|
||||
var/obj/item/implant/radio = locate(/obj/item/implant/radio/voidwalker) in human
|
||||
if(radio)
|
||||
qdel(radio)
|
||||
|
||||
qdel(human.GetComponent(/datum/component/planet_allergy))
|
||||
|
||||
/datum/species/voidwalker/check_roundstart_eligible()
|
||||
return FALSE
|
||||
@@ -2,22 +2,6 @@
|
||||
/datum/movespeed_modifier/grounded_voidwalker
|
||||
multiplicative_slowdown = 1.1
|
||||
|
||||
/// Regenerate in space
|
||||
/datum/status_effect/space_regeneration
|
||||
id = "space_regeneration"
|
||||
duration = STATUS_EFFECT_PERMANENT
|
||||
alert_type = null
|
||||
// How much do we heal per tick?
|
||||
var/healing = 1.5
|
||||
|
||||
/datum/status_effect/space_regeneration/tick(effect)
|
||||
heal_owner()
|
||||
|
||||
/// Regenerate health whenever this status effect is applied or reapplied
|
||||
/datum/status_effect/space_regeneration/proc/heal_owner()
|
||||
if(isspaceturf(get_turf(owner)))
|
||||
owner.heal_ordered_damage(healing, list(BRUTE, BURN, OXY, STAMINA, TOX, BRAIN))
|
||||
|
||||
/datum/status_effect/planet_allergy
|
||||
id = "planet_allergy"
|
||||
duration = STATUS_EFFECT_PERMANENT
|
||||
|
||||
@@ -12,25 +12,45 @@
|
||||
/// Color in which we paint the space texture
|
||||
var/space_color = COLOR_WHITE
|
||||
///traits we give on gain
|
||||
var/list/traits_to_apply = list(TRAIT_MUTE, TRAIT_PACIFISM)
|
||||
var/list/traits_to_apply = list(TRAIT_PACIFISM)
|
||||
/// Do we ban the person from entering space?
|
||||
var/ban_from_space = TRUE
|
||||
/// Chance we'll get a color from space_colors
|
||||
var/coloring_chance = 50
|
||||
/// Statis list of all possible space colors
|
||||
var/static/list/space_colors = list("#ffffff", "#00ccff","#b12bff","#ff7f3a","#ff1c55","#ff7597","#28ff94","#0fcfff","#ff8b4c","#ffc425","#2dff96","#1770ff","#ff3f31","#ffba3b")
|
||||
var/static/list/space_colors = list("#00ccff","#b12bff","#ff7f3a","#ff1c55","#ff7597","#28ff94","#0fcfff","#ff8b4c","#ffc425","#2dff96","#1770ff","#ff3f31","#ffba3b")
|
||||
/// Frequency at which we do a space vomit
|
||||
var/vomit_frequency = 2
|
||||
/// We take a little extra damage, cause we're like glass or something
|
||||
var/brute_mod = 1.1
|
||||
|
||||
/datum/brain_trauma/voided/on_gain()
|
||||
. = ..()
|
||||
space_color = pick(space_colors)
|
||||
|
||||
if(prob(coloring_chance))
|
||||
space_color = pick(space_colors)
|
||||
|
||||
owner.add_traits(traits_to_apply, REF(src))
|
||||
if(ban_from_space)
|
||||
owner.AddComponent(/datum/component/banned_from_space)
|
||||
owner.AddComponent(/datum/component/planet_allergy)
|
||||
|
||||
if(!is_on_a_planet(owner))
|
||||
owner.AddComponent(/datum/component/planet_allergy)
|
||||
|
||||
owner.AddComponent(/datum/component/debris_bleeder, \
|
||||
list(/obj/effect/spawner/random/glass_shards = 20, /obj/effect/spawner/random/glass_debris = 0), \
|
||||
BRUTE, SFX_SHATTER, sound_threshold = 20)
|
||||
|
||||
RegisterSignal(owner, COMSIG_CARBON_ATTACH_LIMB, PROC_REF(texture_limb)) //also catch new limbs being attached
|
||||
RegisterSignal(owner, COMSIG_CARBON_REMOVE_LIMB, PROC_REF(untexture_limb)) //and remove it from limbs if they go away
|
||||
|
||||
for(var/obj/item/bodypart as anything in owner.bodyparts)
|
||||
texture_limb(owner, bodypart)
|
||||
|
||||
if(ishuman(owner))
|
||||
var/mob/living/carbon/human/human = owner
|
||||
human.physiology.brute_mod *= brute_mod
|
||||
|
||||
//your underwear is belong to us
|
||||
if(ishuman(owner))
|
||||
var/mob/living/carbon/human/human = owner //CARBON WILL NEVER BE REAL!!!!!
|
||||
@@ -48,11 +68,22 @@
|
||||
if(ban_from_space)
|
||||
qdel(owner.GetComponent(/datum/component/banned_from_space))
|
||||
qdel(owner.GetComponent(/datum/component/planet_allergy))
|
||||
qdel(owner.GetComponent(/datum/component/debris_bleeder))
|
||||
|
||||
if(ishuman(owner))
|
||||
var/mob/living/carbon/human/human = owner
|
||||
human.physiology.brute_mod /= brute_mod
|
||||
|
||||
for(var/obj/item/bodypart/bodypart as anything in owner.bodyparts)
|
||||
untexture_limb(owner, bodypart)
|
||||
owner.update_body()
|
||||
|
||||
/datum/brain_trauma/voided/on_life(seconds_per_tick, times_fired)
|
||||
. = ..()
|
||||
|
||||
if(prob(vomit_frequency))
|
||||
owner.vomit(MOB_VOMIT_KNOCKDOWN, vomit_type = /obj/effect/decal/cleanable/vomit/nebula, distance = 0)
|
||||
|
||||
/// Apply the space texture
|
||||
/datum/brain_trauma/voided/proc/texture_limb(atom/source, obj/item/bodypart/limb)
|
||||
SIGNAL_HANDLER
|
||||
@@ -85,13 +116,14 @@
|
||||
/// Positive version of the previous. Get space immunity and the ability to slowly move through glass (but you still get muted)
|
||||
/datum/brain_trauma/voided/stable
|
||||
scan_desc = "stable cosmic neural pattern"
|
||||
traits_to_apply = list(TRAIT_MUTE, TRAIT_RESISTLOWPRESSURE, TRAIT_RESISTCOLD)
|
||||
traits_to_apply = list(TRAIT_RESISTLOWPRESSURE, TRAIT_RESISTCOLD)
|
||||
ban_from_space = FALSE
|
||||
vomit_frequency = 0
|
||||
|
||||
/datum/brain_trauma/voided/stable/on_gain()
|
||||
. = ..()
|
||||
|
||||
owner.AddComponent(/datum/component/glass_passer, 2 SECONDS)
|
||||
owner.AddComponent(/datum/component/glass_passer, 2 SECONDS, 2 SECONDS)
|
||||
|
||||
/datum/brain_trauma/voided/stable/on_lose()
|
||||
. = ..()
|
||||
|
||||
@@ -1,167 +0,0 @@
|
||||
//Minimum strength to convert a wall into a void window.
|
||||
#define WALL_CONVERT_STRENGTH 40
|
||||
|
||||
/**
|
||||
* An armblade that pops windows
|
||||
*/
|
||||
/obj/item/void_eater
|
||||
name = "void eater" //as opposed to full eater
|
||||
desc = "A deformed appendage, capable of shattering any glass and any flesh."
|
||||
icon = 'icons/obj/weapons/voidwalker_items.dmi'
|
||||
icon_state = "tentacle"
|
||||
inhand_icon_state = "tentacle"
|
||||
icon_angle = 180
|
||||
force = 25
|
||||
armour_penetration = 35
|
||||
lefthand_file = 'icons/mob/inhands/antag/voidwalker_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/antag/voidwalker_righthand.dmi'
|
||||
blocks_emissive = EMISSIVE_BLOCK_NONE
|
||||
item_flags = ABSTRACT | DROPDEL
|
||||
resistance_flags = INDESTRUCTIBLE | ACID_PROOF | FIRE_PROOF | LAVA_PROOF | UNACIDABLE
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
tool_behaviour = TOOL_MINING
|
||||
hitsound = 'sound/items/weapons/bladeslice.ogg'
|
||||
wound_bonus = -30
|
||||
exposed_wound_bonus = 20
|
||||
|
||||
/// Damage we loss per hit
|
||||
var/damage_loss_per_hit = 0.5
|
||||
/// The minimal damage we can reach
|
||||
var/damage_minimum = 15
|
||||
/// Cooldown for converting walls to void windows
|
||||
COOLDOWN_DECLARE(wall_conversion)
|
||||
///How many wall conversions can we perform before we have to refresh?
|
||||
var/conversions_remaining = 2
|
||||
|
||||
/obj/item/void_eater/Initialize(mapload)
|
||||
. = ..()
|
||||
ADD_TRAIT(src, TRAIT_NODROP, HAND_REPLACEMENT_TRAIT)
|
||||
|
||||
AddComponent(/datum/component/temporary_glass_shatterer)
|
||||
|
||||
/obj/item/void_eater/equipped(mob/user)
|
||||
. = ..()
|
||||
|
||||
RegisterSignal(user, COMSIG_VOIDWALKER_SUCCESSFUL_KIDNAP, PROC_REF(refresh))
|
||||
|
||||
/obj/item/void_eater/dropped(mob/user, silent)
|
||||
. = ..()
|
||||
UnregisterSignal(user, COMSIG_VOIDWALKER_SUCCESSFUL_KIDNAP)
|
||||
|
||||
/obj/item/void_eater/examine(mob/user)
|
||||
. = ..()
|
||||
. += span_notice("The [name] weakens each hit, recharge it by kidnapping someone!")
|
||||
. += span_notice("Sharpness: [round(force)]/[initial(force)]")
|
||||
. += span_notice("Wall Conversions remaining: [conversions_remaining ? conversions_remaining : "None! You must resharpen your blade!"]")
|
||||
|
||||
/obj/item/void_eater/attack(mob/living/target_mob, mob/living/user, list/modifiers, list/attack_modifiers)
|
||||
if(!ishuman(target_mob))
|
||||
return ..()
|
||||
|
||||
var/mob/living/carbon/human/hewmon = target_mob
|
||||
|
||||
if(hewmon.has_trauma_type(/datum/brain_trauma/voided))
|
||||
var/turf/spawnloc = get_turf(hewmon)
|
||||
|
||||
if(hewmon.stat != DEAD)
|
||||
hewmon.balloon_alert(user, "already voided!")
|
||||
playsound(hewmon, SFX_SHATTER, 60)
|
||||
new /obj/effect/spawner/random/glass_shards/mini (spawnloc)
|
||||
hewmon.adjustBruteLoss(10) // BONUS DAMAGE
|
||||
else
|
||||
hewmon.balloon_alert(user, "shattering...")
|
||||
if(do_after(user, 4 SECONDS, hewmon))
|
||||
new /obj/effect/spawner/random/glass_shards (spawnloc)
|
||||
var/obj/item/organ/brain = hewmon.get_organ_by_type(/obj/item/organ/brain)
|
||||
if(brain)
|
||||
brain.Remove(hewmon)
|
||||
brain.forceMove(spawnloc)
|
||||
brain.balloon_alert(user, "shattered!")
|
||||
playsound(hewmon, SFX_SHATTER, 100)
|
||||
qdel(hewmon)
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
if(hewmon.stat == HARD_CRIT && !hewmon.has_trauma_type(/datum/brain_trauma/voided))
|
||||
target_mob.balloon_alert(user, "is in crit!")
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
target_mob.apply_status_effect(/datum/status_effect/void_eatered)
|
||||
|
||||
if(force == damage_minimum + damage_loss_per_hit)
|
||||
user.balloon_alert(user, "void eater blunted!")
|
||||
|
||||
force = max(force - damage_loss_per_hit, damage_minimum)
|
||||
|
||||
if(prob(5))
|
||||
new /obj/effect/spawner/random/glass_debris (get_turf(user))
|
||||
return ..()
|
||||
|
||||
/obj/item/void_eater/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
|
||||
if(!istype(interacting_with, /turf/closed/wall))
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(!conversions_remaining)
|
||||
balloon_alert(user, "must refresh void eater!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(!COOLDOWN_FINISHED(src, wall_conversion))
|
||||
balloon_alert(user, "must wait [DisplayTimeText(COOLDOWN_TIMELEFT(src, wall_conversion))]!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
var/turf/closed/wall/our_wall = interacting_with
|
||||
if(!check_wall_validity(our_wall, user, silent = FALSE))
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
playsound(interacting_with, 'sound/effects/magic/blind.ogg', 100, TRUE)
|
||||
new /obj/effect/temp_visual/transmute_tile_flash(interacting_with)
|
||||
balloon_alert(user, "opening window...")
|
||||
if(!do_after(user, 8 SECONDS, interacting_with, hidden = TRUE))
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
if(!conversions_remaining)
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
var/list/target_walls = list()
|
||||
target_walls += our_wall
|
||||
for(var/turf/closed/wall/adjacent_wall in orange(1, interacting_with))
|
||||
if(check_wall_validity(adjacent_wall, user))
|
||||
target_walls += adjacent_wall
|
||||
|
||||
for(var/turf/closed/wall/targeted_wall in target_walls)
|
||||
playsound(targeted_wall, 'sound/effects/magic/blind.ogg', 100, TRUE)
|
||||
new /obj/effect/temp_visual/transmute_tile_flash(targeted_wall)
|
||||
targeted_wall.ScrapeAway()
|
||||
new /obj/structure/window/fulltile/voidwalker(targeted_wall)
|
||||
new /obj/structure/grille(targeted_wall)
|
||||
conversions_remaining--
|
||||
COOLDOWN_START(src, wall_conversion, 60 SECONDS)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/// Called when the voidwalker kidnapped someone
|
||||
/obj/item/void_eater/proc/refresh(mob/living/carbon/human/voidwalker)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
force = initial(force)
|
||||
|
||||
color = "#000000"
|
||||
animate(src, color = null, time = 1 SECONDS)//do a color flashy woosh
|
||||
|
||||
to_chat(voidwalker, span_boldnotice("Your [name] refreshes!"))
|
||||
|
||||
/obj/item/void_eater/proc/check_wall_validity(turf/closed/wall/wall_to_check, mob/living/user, silent = TRUE)
|
||||
if(wall_to_check.hardness < WALL_CONVERT_STRENGTH)
|
||||
if(!silent)
|
||||
balloon_alert(user, "too strong!")
|
||||
return FALSE
|
||||
|
||||
for(var/turf/nearby_turf in orange(1, wall_to_check))
|
||||
var/area/nearby_area = get_area(nearby_turf)
|
||||
if(is_area_nearby_station(nearby_area))
|
||||
return TRUE
|
||||
|
||||
if(!silent)
|
||||
balloon_alert(user, "not near space!")
|
||||
|
||||
return FALSE
|
||||
|
||||
|
||||
|
||||
#undef WALL_CONVERT_STRENGTH
|
||||
@@ -1157,6 +1157,3 @@
|
||||
|
||||
/mob/living/carbon/human/species/zombie/infectious
|
||||
race = /datum/species/zombie/infectious
|
||||
|
||||
/mob/living/carbon/human/species/voidwalker
|
||||
race = /datum/species/voidwalker
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
* * needs_metabolizing (bool) takes into consideration if the chemical is matabolizing when it's checked.
|
||||
*/
|
||||
/mob/living/proc/has_reagent(reagent, amount = -1, needs_metabolizing = FALSE)
|
||||
return reagents.has_reagent(reagent, amount, needs_metabolizing)
|
||||
return reagents?.has_reagent(reagent, amount, needs_metabolizing)
|
||||
|
||||
/mob/living/proc/update_damage_hud()
|
||||
return
|
||||
|
||||
|
Before Width: | Height: | Size: 696 B After Width: | Height: | Size: 345 B |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 919 KiB After Width: | Height: | Size: 918 KiB |
|
Before Width: | Height: | Size: 326 B After Width: | Height: | Size: 353 B |
|
After Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 16 KiB |
@@ -382,7 +382,6 @@
|
||||
#include "code\__DEFINES\dcs\signals\signals_turf.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_twohand.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_vehicle.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_voidwalker.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_wash.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_wizard.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_xeno_control.dm"
|
||||
@@ -623,6 +622,7 @@
|
||||
#include "code\_onclick\hud\screen_objects.dm"
|
||||
#include "code\_onclick\hud\screentip.dm"
|
||||
#include "code\_onclick\hud\soulscythe.dm"
|
||||
#include "code\_onclick\hud\voidwalkerhud.dm"
|
||||
#include "code\_onclick\hud\parallax\parallax.dm"
|
||||
#include "code\_onclick\hud\parallax\random_layer.dm"
|
||||
#include "code\_onclick\hud\rendering\plane_master_controller.dm"
|
||||
@@ -1133,6 +1133,7 @@
|
||||
#include "code\datums\components\dart_insert.dm"
|
||||
#include "code\datums\components\deadchat_control.dm"
|
||||
#include "code\datums\components\death_linked.dm"
|
||||
#include "code\datums\components\debris_bleeder.dm"
|
||||
#include "code\datums\components\dejavu.dm"
|
||||
#include "code\datums\components\deployable.dm"
|
||||
#include "code\datums\components\direct_explosive_trap.dm"
|
||||
@@ -1279,7 +1280,6 @@
|
||||
#include "code\datums\components\space_allergy.dm"
|
||||
#include "code\datums\components\space_camo.dm"
|
||||
#include "code\datums\components\space_dive.dm"
|
||||
#include "code\datums\components\space_kidnap.dm"
|
||||
#include "code\datums\components\spawner.dm"
|
||||
#include "code\datums\components\speechmod.dm"
|
||||
#include "code\datums\components\spill.dm"
|
||||
@@ -1586,6 +1586,7 @@
|
||||
#include "code\datums\elements\pet_bonus.dm"
|
||||
#include "code\datums\elements\pet_collar.dm"
|
||||
#include "code\datums\elements\pet_cult.dm"
|
||||
#include "code\datums\elements\pick_and_drop_only.dm"
|
||||
#include "code\datums\elements\plant_backfire.dm"
|
||||
#include "code\datums\elements\point_of_interest.dm"
|
||||
#include "code\datums\elements\poster_tearer.dm"
|
||||
@@ -3456,17 +3457,16 @@
|
||||
#include "code\modules\antagonists\valentines\heartbreaker.dm"
|
||||
#include "code\modules\antagonists\valentines\valentine.dm"
|
||||
#include "code\modules\antagonists\venus_human_trap\venus_human_trap.dm"
|
||||
#include "code\modules\antagonists\voidwalker\sunwalker_mob.dm"
|
||||
#include "code\modules\antagonists\voidwalker\sunwalkers.dm"
|
||||
#include "code\modules\antagonists\voidwalker\voidwalker.dm"
|
||||
#include "code\modules\antagonists\voidwalker\voidwalker_abilities.dm"
|
||||
#include "code\modules\antagonists\voidwalker\voidwalker_bodyparts.dm"
|
||||
#include "code\modules\antagonists\voidwalker\voidwalker_kidnap.dm"
|
||||
#include "code\modules\antagonists\voidwalker\voidwalker_loot.dm"
|
||||
#include "code\modules\antagonists\voidwalker\voidwalker_organs.dm"
|
||||
#include "code\modules\antagonists\voidwalker\voidwalker_mob.dm"
|
||||
#include "code\modules\antagonists\voidwalker\voidwalker_particles.dm"
|
||||
#include "code\modules\antagonists\voidwalker\voidwalker_species.dm"
|
||||
#include "code\modules\antagonists\voidwalker\voidwalker_status_effects.dm"
|
||||
#include "code\modules\antagonists\voidwalker\voidwalker_traumas.dm"
|
||||
#include "code\modules\antagonists\voidwalker\voidwalker_void_eater.dm"
|
||||
#include "code\modules\antagonists\voidwalker\voidwalker_window.dm"
|
||||
#include "code\modules\antagonists\wishgranter\wishgranter.dm"
|
||||
#include "code\modules\antagonists\wizard\imp_antag.dm"
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import { BlockQuote, LabeledList, Section, Stack } from 'tgui-core/components';
|
||||
|
||||
import { Window } from '../layouts';
|
||||
|
||||
const tipstyle = {
|
||||
color: 'white',
|
||||
};
|
||||
|
||||
const noticestyle = {
|
||||
color: 'lightblue',
|
||||
};
|
||||
|
||||
export const AntagInfoSunwalker = (props) => {
|
||||
return (
|
||||
<Window width={660} height={300}>
|
||||
<Window.Content backgroundColor="#0d0d0d">
|
||||
<Stack fill>
|
||||
<Stack.Item width="40%">
|
||||
<Section fill>
|
||||
<Stack vertical fill>
|
||||
<Stack.Item fontSize="25px">You are the Sunwalker</Stack.Item>
|
||||
<Stack.Item>
|
||||
<BlockQuote>
|
||||
You are an ancient voidwalker, having been caught in a
|
||||
supernova. You are altered, and hateful.
|
||||
</BlockQuote>
|
||||
<BlockQuote>
|
||||
There will be no lessons or enlightenment, they wont survive
|
||||
to learn from it.
|
||||
</BlockQuote>
|
||||
</Stack.Item>
|
||||
<Stack.Divider />
|
||||
</Stack>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
<Stack.Item width="60%">
|
||||
<Section fill title="Powers">
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Space Dive">
|
||||
You can move under the station from space, use this to hunt
|
||||
and get to isolated sections of space.
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Burning Slash">
|
||||
Your attacks deal great burn damage and ignite those hit.
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Burning Physiology">
|
||||
Your very skin heats the air around you, while the vacuum of
|
||||
space mends any wounds your body might have sustained. You can
|
||||
move through glass freely, but are slowed in gravity.
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Stellar Charge">
|
||||
With an exploding burning speed, charge forwards, dealing
|
||||
damage and burning the surroundings.
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
@@ -12,13 +12,13 @@ const noticestyle = {
|
||||
|
||||
export const AntagInfoVoidwalker = (props) => {
|
||||
return (
|
||||
<Window width={620} height={470}>
|
||||
<Window width={660} height={660}>
|
||||
<Window.Content backgroundColor="#0d0d0d">
|
||||
<Stack fill>
|
||||
<Stack.Item width="46.2%">
|
||||
<Stack.Item width="50%">
|
||||
<Section fill>
|
||||
<Stack vertical fill>
|
||||
<Stack.Item fontSize="25px">You are a Voidwalker.</Stack.Item>
|
||||
<Stack.Item fontSize="25px">You are the Voidwalker</Stack.Item>
|
||||
<Stack.Item>
|
||||
<BlockQuote>
|
||||
You are a creature from the void between stars. You were
|
||||
@@ -33,39 +33,57 @@ export const AntagInfoVoidwalker = (props) => {
|
||||
stop you. You can move through windows, so stay near them to
|
||||
always have a way out.
|
||||
<br />
|
||||
<br />
|
||||
<span style={tipstyle}>Hunt: </span>
|
||||
Pick unfair fights. Look for inattentive targets and strike at
|
||||
them when they don't expect you.
|
||||
<br />
|
||||
<br />
|
||||
<span style={tipstyle}>Abduct: </span>
|
||||
Your Unsettle ability stuns and drains your targets. Finish
|
||||
them with your void window and use it to pop a window, drag
|
||||
them into space and use an empty hand to kidnap them.
|
||||
Your Unsettle ability stuns and drains your targets. Knock
|
||||
them out with your draining slash, take them to space (or
|
||||
nebula vomit) and enlighten them.
|
||||
<br />
|
||||
<br />
|
||||
<span style={tipstyle}>Reap: </span>
|
||||
Our students expell our essence regularly. We can use this to
|
||||
go where we could otherwise not, but we reabsorb this when we
|
||||
use it to leave. (You can dive in space vomit.)
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
<Stack.Item width="53%">
|
||||
<Stack.Item width="50%">
|
||||
<Section fill title="Powers">
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Space Dive">
|
||||
You can move under the station from space, use this to hunt
|
||||
and get to isolated sections of space.
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Void Eater">
|
||||
Your divine appendage; it allows you to incapacitate the loud
|
||||
ones and instantly break windows, or convert soft walls into
|
||||
windows for you to pass through.
|
||||
<LabeledList.Item label="Draining Slash">
|
||||
You take the breath right from their lungs and quickly take
|
||||
down even the strongest opponents. Should they resist,
|
||||
right-click allows you to do some raw damage. Your arms are
|
||||
otherwise not very sophisticated, and are not good for much
|
||||
more than just grabbing things.
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Cosmic Physiology">
|
||||
Your natural camouflage makes you nearly invisible in space,
|
||||
as well as mending any wounds your body might have sustained.
|
||||
You can move through glass freely, but are slowed in gravity.
|
||||
Your natural camouflage makes you invisible in space, as well
|
||||
as mending any wounds your body might have sustained. You can
|
||||
move through glass freely, but are slowed in gravity.
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Unsettle">
|
||||
Target a victim while remaining only partially in their view
|
||||
to stun and weaken them, but also announce them your presence.
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Cosmic Dash">
|
||||
With a short range and negligible damage, it makes for a poor
|
||||
offensive tool, but great for quick escapes and repositions.
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Expand">
|
||||
For every lesson we teach, we grow in power. We can convert
|
||||
walls into glass to allow us to reach even further.
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
|
||||