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)

![image](https://github.com/user-attachments/assets/5583db66-6025-4874-95dd-938aa828634c)![image](https://github.com/user-attachments/assets/2785c5cc-ccda-4ffd-bc1c-5bb278873d9b)


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🟨**

![image](https://github.com/user-attachments/assets/82a330ee-16f8-46e4-a325-c894fc8931d6)
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

![image](https://github.com/user-attachments/assets/e483a0d2-a418-479e-89e5-1dcd71165140)
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.


![image](https://github.com/user-attachments/assets/8907f261-6395-44fb-86ea-0ed548aca3ab)

**🟨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.

![image](https://github.com/user-attachments/assets/2383dc6e-2173-4449-b71b-367e81c55f88)

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
/🆑
This commit is contained in:
Time-Green
2025-07-01 12:55:31 +01:00
committed by GitHub
parent b3bee1441d
commit 39a2434c06
48 changed files with 1135 additions and 717 deletions
+1
View File
@@ -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"
+1
View File
@@ -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"
+1
View File
@@ -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"
+3 -1
View File
@@ -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
+2 -2
View File
@@ -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
+1
View File
@@ -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,
+108
View File
@@ -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)
+36
View File
@@ -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)
+32 -5
View File
@@ -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
+4 -6
View File
@@ -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)
+13
View File
@@ -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)
+40 -11
View File
@@ -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()
+42 -3
View File
@@ -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"
-72
View File
@@ -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
+6 -1
View File
@@ -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))
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
Binary file not shown.

Before

Width:  |  Height:  |  Size: 696 B

After

Width:  |  Height:  |  Size: 345 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 919 KiB

After

Width:  |  Height:  |  Size: 918 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 326 B

After

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

+6 -6
View File
@@ -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:&ensp;</span>
Pick unfair fights. Look for inattentive targets and strike at
them when they don&apos;t expect you.
<br />
<br />
<span style={tipstyle}>Abduct:&ensp;</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:&ensp;</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>