Ports TG Icemoon framework and map (#49680) (#12002)

* ports all the tg junk for icemoon, not yet changed to make it all compile

* fixes

* fixes

* fixes

* fixes

* fixes

* new stuff

* whew

* fixes

* it compiles, now to fix the maps

* fixes the maps

* fixes solars + removes the space tiles in the toxins burn chamber

* nukes the SpawnTerrain proc used for tg geysers

* linter fix

* fix

* fixes the non matching turf atmos (hopefully)

* more mapping fixes

* dmm2tgm

* unfucks changeturf for the more_caves

* fixes the volanic subtypes of the other thing

* fixes the stupid fucking tile placing list

* some map fixes, fixes the station_ruin loader shitting out errors this commit took 2 hours of my fucking life

* fixes a bunch of mismatch atmos in ruins

* fixes wendigo cave having no air

* backwards couch backwards couch

* fixes the SM up

* wendigos can't runtime when butchering if you can't butcher them 😎

* makes the wendigo fight have the same atmos as the surrounding icemoon

* Tweaks atmos mixture from o2=22;n2=82;TEMP=180 to o2=18;n2=63;TEMP=180, making lavaland weapons actually work

* makes the wendigo screech shake not completely aids

* fixes snowlegion portals dropping proper legions instead of skeles

* brings the engioutpost ruin over as well

* whoopps

* empty commit to reroll bots

* Fixes pirates, ops, the mining base, and gives pirates and ops drills

* fixes lone ops and ninjas

* fixes the snowed plating getting fucked when tiles are placed on it

* removes some OP junk from the wabbajack pool (aka removes non-antag headslugs again)

* more bug fixes

* empty commit to reroll bots

* hopefully finally kills the active turfs on the library ruin

Co-authored-by: kevinz000 <2003111+kevinz000@users.noreply.github.com>
This commit is contained in:
Detective-Google
2020-05-07 07:46:16 -05:00
committed by GitHub
parent e24bda9a9f
commit bd37d45334
123 changed files with 277438 additions and 220 deletions
+19 -2
View File
@@ -1,13 +1,18 @@
/datum/component/knockback
/// distance the atom will be thrown
var/throw_distance
/// whether this can throw anchored targets (tables, etc)
var/throw_anchored
/// whether this is a gentle throw (default false means people thrown into walls are stunned / take damage)
var/throw_gentle
/datum/component/knockback/Initialize(throw_distance=1)
/datum/component/knockback/Initialize(throw_distance=1, throw_gentle=FALSE)
if(!isitem(parent) && !ishostile(parent) && !isgun(parent) && !ismachinery(parent) && !isstructure(parent))
return COMPONENT_INCOMPATIBLE
src.throw_distance = throw_distance
src.throw_anchored = throw_anchored
src.throw_gentle = throw_gentle
/datum/component/knockback/RegisterWithParent()
. = ..()
@@ -22,17 +27,29 @@
. = ..()
UnregisterSignal(parent, list(COMSIG_ITEM_AFTERATTACK, COMSIG_HOSTILE_ATTACKINGTARGET, COMSIG_PROJECTILE_ON_HIT))
/// triggered after an item attacks something
/datum/component/knockback/proc/item_afterattack(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters)
if(!proximity_flag)
return
do_knockback(target, user, get_dir(source, target))
/// triggered after a hostile simplemob attacks something
/datum/component/knockback/proc/hostile_attackingtarget(mob/living/simple_animal/hostile/attacker, atom/target)
do_knockback(target, attacker, get_dir(attacker, target))
/// triggered after a projectile hits something
/datum/component/knockback/proc/projectile_hit(atom/fired_from, atom/movable/firer, atom/target, Angle)
do_knockback(target, null, angle2dir(Angle))
/**
* Throw a target in a direction
*
* Arguments:
* * target - Target atom to throw
* * thrower - Thing that caused this atom to be thrown
* * throw_dir - Direction to throw the atom
*/
/datum/component/knockback/proc/do_knockback(atom/target, mob/thrower, throw_dir)
if(!ismovable(target) || throw_dir == null)
return
@@ -43,4 +60,4 @@
throw_dir = turn(throw_dir, 180)
throw_distance *= -1
var/atom/throw_target = get_edge_target_turf(throwee, throw_dir)
throwee.safe_throw_at(throw_target, throw_distance, 1, thrower)
throwee.safe_throw_at(throw_target, throw_distance, 1, thrower) //, gentle = throw_gentle)
+31
View File
@@ -0,0 +1,31 @@
/datum/element/snailcrawl
element_flags = ELEMENT_DETACH
/datum/element/snailcrawl/Attach(datum/target)
. = ..()
if(!ismovable(target))
return ELEMENT_INCOMPATIBLE
var/P
if(iscarbon(target))
P = .proc/snail_crawl
else
P = .proc/lubricate
RegisterSignal(target, COMSIG_MOVABLE_MOVED, P)
/datum/element/snailcrawl/Detach(mob/living/carbon/target)
. = ..()
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
if(istype(target))
target.remove_movespeed_modifier(/datum/movespeed_modifier/snail_crawl)
/datum/element/snailcrawl/proc/snail_crawl(mob/living/carbon/snail)
if(snail.resting && !snail.buckled && lubricate(snail))
snail.add_movespeed_modifier(/datum/movespeed_modifier/snail_crawl)
else
snail.remove_movespeed_modifier(/datum/movespeed_modifier/snail_crawl)
/datum/element/snailcrawl/proc/lubricate(atom/movable/snail)
var/turf/open/OT = get_turf(snail)
if(istype(OT))
OT.MakeSlippery(TURF_WET_LUBE, 20)
return TRUE
+112
View File
@@ -0,0 +1,112 @@
// Hey! Listen! Update \config\iceruinblacklist.txt with your new ruins!
/datum/map_template/ruin/icemoon
prefix = "_maps/RandomRuins/IceRuins/"
allow_duplicates = FALSE
cost = 5
// above ground only
/datum/map_template/ruin/icemoon/lust
name = "Ruin of Lust"
id = "lust"
description = "Not exactly what you expected."
suffix = "icemoon_surface_lust.dmm"
/datum/map_template/ruin/icemoon/asteroid
name = "Asteroid Site"
id = "asteroidsite"
description = "Surprised to see us here?"
suffix = "icemoon_surface_asteroid.dmm"
/datum/map_template/ruin/icemoon/hotsprings
name = "Hot Springs"
id = "hotsprings"
description = "Just relax and take a dip, nothing will go wrong, I swear!"
suffix = "icemoon_surface_hotsprings.dmm"
/datum/map_template/ruin/icemoon/engioutpost
name = "Engineer Outpost"
id = "engioutpost"
description = "Blown up by an unfortunate accident."
suffix = "icemoon_surface_engioutpost.dmm"
/datum/map_template/ruin/icemoon/fountain
name = "Fountain Hall"
id = "fountain"
description = "The fountain has a warning on the side. DANGER: May have undeclared side effects that only become obvious when implemented."
prefix = "_maps/RandomRuins/AnywhereRuins/"
suffix = "fountain_hall.dmm"
// above and below ground together
/datum/map_template/ruin/icemoon/mining_site
name = "Mining Site"
id = "miningsite"
description = "Ruins of a site where people once mined with primitive tools for ore."
suffix = "icemoon_surface_mining_site.dmm"
always_place = TRUE
always_spawn_with = list(/datum/map_template/ruin/icemoon/underground/mining_site_below = PLACE_BELOW)
/datum/map_template/ruin/icemoon/underground/mining_site_below
name = "Mining Site Underground"
id = "miningsite-underground"
description = "Who knew ladders could be so useful?"
suffix = "icemoon_underground_mining_site.dmm"
unpickable = TRUE
// below ground only
/datum/map_template/ruin/icemoon/underground
name = "underground ruin"
/datum/map_template/ruin/icemoon/underground/abandonedvillage
name = "Abandoned Village"
id = "abandonedvillage"
description = "Who knows what lies within?"
suffix = "icemoon_underground_abandoned_village.dmm"
/datum/map_template/ruin/icemoon/underground/library
name = "Buried Library"
id = "buriedlibrary"
description = "A once grand library, now lost to the confines of the Ice Moon."
suffix = "icemoon_underground_library.dmm"
/datum/map_template/ruin/icemoon/underground/wrath
name = "Ruin of Wrath"
id = "wrath"
description = "You'll fight and fight and just keep fighting."
suffix = "icemoon_underground_wrath.dmm"
/datum/map_template/ruin/icemoon/underground/lavaland
name = "Lavaland Site"
id = "lavalandsite"
description = "I guess we never really left you huh?"
suffix = "icemoon_underground_lavaland.dmm"
/datum/map_template/ruin/icemoon/underground/puzzle
name = "Ancient Puzzle"
id = "puzzle"
description = "Mystery to be solved."
suffix = "icemoon_underground_puzzle.dmm"
/datum/map_template/ruin/icemoon/underground/bathhouse
name = "Bath House"
id = "bathhouse"
description = "A taste of paradise, locked in the hell of the Ice Moon."
suffix = "icemoon_underground_bathhouse.dmm"
/datum/map_template/ruin/icemoon/underground/wendigo_cave
name = "Wendigo Cave"
id = "wendigocave"
description = "Into the jaws of the beast."
suffix = "icemoon_underground_wendigo_cave.dmm"
/datum/map_template/ruin/icemoon/underground/free_golem
name = "Free Golem Ship"
id = "golem-ship"
description = "Lumbering humanoids, made out of precious metals, move inside this ship. They frequently leave to mine more minerals, which they somehow turn into more of them. \
Seem very intent on research and individual liberty, and also geology-based naming?"
prefix = "_maps/RandomRuins/AnywhereRuins/"
suffix = "golem_ship.dmm"
allow_duplicates = FALSE
+4 -2
View File
@@ -67,7 +67,8 @@
description = "Lumbering humanoids, made out of precious metals, move inside this ship. They frequently leave to mine more minerals, which they somehow turn into more of them. \
Seem very intent on research and individual liberty, and also geology based naming?"
cost = 20
suffix = "lavaland_surface_golem_ship.dmm"
prefix = "_maps/RandomRuins/AnywhereRuins/"
suffix = "golem_ship.dmm"
allow_duplicates = FALSE
/datum/map_template/ruin/lavaland/animal_hospital
@@ -175,7 +176,8 @@
name = "Fountain Hall"
id = "fountain"
description = "The fountain has a warning on the side. DANGER: May have undeclared side effects that only become obvious when implemented."
suffix = "lavaland_surface_fountain_hall.dmm"
prefix = "_maps/RandomRuins/AnywhereRuins/"
suffix = "fountain_hall.dmm"
cost = 5
allow_duplicates = FALSE
+22 -66
View File
@@ -391,78 +391,34 @@
owner.underlays -= marked_underlay //if this is being called, we should have an owner at this point.
..()
/datum/status_effect/saw_bleed
/datum/status_effect/stacking/saw_bleed
id = "saw_bleed"
duration = -1 //removed under specific conditions
tick_interval = 6
alert_type = null
var/mutable_appearance/bleed_overlay
var/mutable_appearance/bleed_underlay
var/bleed_amount = 3
var/bleed_buildup = 3
var/delay_before_decay = 5
delay_before_decay = 5
stack_threshold = 10
max_stacks = 10
overlay_file = 'icons/effects/bleed.dmi'
underlay_file = 'icons/effects/bleed.dmi'
overlay_state = "bleed"
underlay_state = "bleed"
var/bleed_damage = 200
var/needs_to_bleed = FALSE
/datum/status_effect/saw_bleed/Destroy()
if(owner)
owner.cut_overlay(bleed_overlay)
owner.underlays -= bleed_underlay
QDEL_NULL(bleed_overlay)
return ..()
/datum/status_effect/stacking/saw_bleed/fadeout_effect()
new /obj/effect/temp_visual/bleed(get_turf(owner))
/datum/status_effect/saw_bleed/on_apply()
if(owner.stat == DEAD)
return FALSE
bleed_overlay = mutable_appearance('icons/effects/bleed.dmi', "bleed[bleed_amount]")
bleed_underlay = mutable_appearance('icons/effects/bleed.dmi', "bleed[bleed_amount]")
var/icon/I = icon(owner.icon, owner.icon_state, owner.dir)
var/icon_height = I.Height()
bleed_overlay.pixel_x = -owner.pixel_x
bleed_overlay.pixel_y = FLOOR(icon_height * 0.25, 1)
bleed_overlay.transform = matrix() * (icon_height/world.icon_size) //scale the bleed overlay's size based on the target's icon size
bleed_underlay.pixel_x = -owner.pixel_x
bleed_underlay.transform = matrix() * (icon_height/world.icon_size) * 3
bleed_underlay.alpha = 40
owner.add_overlay(bleed_overlay)
owner.underlays += bleed_underlay
return ..()
/datum/status_effect/stacking/saw_bleed/threshold_cross_effect()
owner.adjustBruteLoss(bleed_damage)
var/turf/T = get_turf(owner)
new /obj/effect/temp_visual/bleed/explode(T)
for(var/d in GLOB.alldirs)
new /obj/effect/temp_visual/dir_setting/bloodsplatter(T, d)
playsound(T, "desceration", 100, TRUE, -1)
/datum/status_effect/saw_bleed/tick()
if(owner.stat == DEAD)
qdel(src)
else
add_bleed(-1)
/datum/status_effect/saw_bleed/proc/add_bleed(amount)
owner.cut_overlay(bleed_overlay)
owner.underlays -= bleed_underlay
bleed_amount += amount
if(bleed_amount)
if(bleed_amount >= 10)
needs_to_bleed = TRUE
qdel(src)
else
if(amount > 0)
tick_interval += delay_before_decay
bleed_overlay.icon_state = "bleed[bleed_amount]"
bleed_underlay.icon_state = "bleed[bleed_amount]"
owner.add_overlay(bleed_overlay)
owner.underlays += bleed_underlay
else
qdel(src)
/datum/status_effect/saw_bleed/on_remove()
. = ..()
if(needs_to_bleed)
var/turf/T = get_turf(owner)
new /obj/effect/temp_visual/bleed/explode(T)
for(var/d in GLOB.alldirs)
new /obj/effect/temp_visual/dir_setting/bloodsplatter(T, d)
playsound(T, "desceration", 200, 1, -1)
owner.adjustBruteLoss(bleed_damage)
else
new /obj/effect/temp_visual/bleed(get_turf(owner))
/datum/status_effect/stacking/saw_bleed/bloodletting
id = "bloodletting"
stack_threshold = 7
max_stacks = 7
bleed_damage = 20
/datum/status_effect/neck_slice
id = "neck_slice"
+134 -3
View File
@@ -7,7 +7,6 @@
var/duration = -1 //How long the status effect lasts in DECISECONDS. Enter -1 for an effect that never ends unless removed through some means.
var/tick_interval = 10 //How many deciseconds between ticks, approximately. Leave at 10 for every second.
var/mob/living/owner //The mob affected by the status effect.
var/status_type = STATUS_EFFECT_UNIQUE //How many of the effect can be on one mob, and what happens when you try to add another
var/on_remove_on_mob_delete = FALSE //if we call on_remove() when the mob is deleted
var/examine_text //If defined, this text will appear when the mob is examined - to use he, she etc. use "SUBJECTPRONOUN" and replace it in the examines themselves
var/alert_type = /obj/screen/alert/status_effect //the alert thrown by the status effect, contains name and description
@@ -16,6 +15,8 @@
/// If this is TRUE, the user will have sprint forcefully disabled while this is active.
var/blocks_sprint = FALSE
var/obj/screen/alert/status_effect/linked_alert = null //the alert itself, if it exists
/// How many of the effect can be on one mob, and what happens when you try to add another
var/status_type = STATUS_EFFECT_UNIQUE
/datum/status_effect/New(list/arguments)
on_creation(arglist(arguments))
@@ -67,6 +68,9 @@
/datum/status_effect/proc/tick() //Called every tick.
/datum/status_effect/proc/before_remove() //! Called before being removed; returning FALSE will cancel removal
return TRUE
/datum/status_effect/proc/on_remove() //Called whenever the buff expires or is removed; do note that at the point this is called, it is out of the owner's status_effects but owner is not yet null
SHOULD_CALL_PARENT(TRUE)
REMOVE_TRAIT(owner, TRAIT_COMBAT_MODE_LOCKED, src)
@@ -123,12 +127,13 @@
S1 = new effect(arguments)
. = S1
/mob/living/proc/remove_status_effect(effect) //removes all of a given status effect from this mob, returning TRUE if at least one was removed
/mob/living/proc/remove_status_effect(effect, ...) //removes all of a given status effect from this mob, returning TRUE if at least one was removed
. = FALSE
var/list/arguments = args.Copy(2)
if(status_effects)
var/datum/status_effect/S1 = effect
for(var/datum/status_effect/S in status_effects)
if(initial(S1.id) == S.id)
if(initial(S1.id) == S.id && S.before_remove(arguments))
qdel(S)
. = TRUE
@@ -147,3 +152,129 @@
for(var/datum/status_effect/S in status_effects)
if(initial(S1.id) == S.id)
. += S
//////////////////////
// STACKING EFFECTS //
//////////////////////
/datum/status_effect/stacking
id = "stacking_base"
duration = -1 //removed under specific conditions
alert_type = null
var/stacks = 0 //how many stacks are accumulated, also is # of stacks that target will have when first applied
var/delay_before_decay //deciseconds until ticks start occuring, which removes stacks (first stack will be removed at this time plus tick_interval)
tick_interval = 10 //deciseconds between decays once decay starts
var/stack_decay = 1 //how many stacks are lost per tick (decay trigger)
var/stack_threshold //special effects trigger when stacks reach this amount
var/max_stacks //stacks cannot exceed this amount
var/consumed_on_threshold = TRUE //if status should be removed once threshold is crossed
var/threshold_crossed = FALSE //set to true once the threshold is crossed, false once it falls back below
var/overlay_file
var/underlay_file
var/overlay_state // states in .dmi must be given a name followed by a number which corresponds to a number of stacks. put the state name without the number in these state vars
var/underlay_state // the number is concatonated onto the string based on the number of stacks to get the correct state name
var/mutable_appearance/status_overlay
var/mutable_appearance/status_underlay
/datum/status_effect/stacking/proc/threshold_cross_effect() //what happens when threshold is crossed
/datum/status_effect/stacking/proc/stacks_consumed_effect() //runs if status is deleted due to threshold being crossed
/datum/status_effect/stacking/proc/fadeout_effect() //runs if status is deleted due to being under one stack
/datum/status_effect/stacking/proc/stack_decay_effect() //runs every time tick() causes stacks to decay
/datum/status_effect/stacking/proc/on_threshold_cross()
threshold_cross_effect()
if(consumed_on_threshold)
stacks_consumed_effect()
qdel(src)
/datum/status_effect/stacking/proc/on_threshold_drop()
/datum/status_effect/stacking/proc/can_have_status()
return owner.stat != DEAD
/datum/status_effect/stacking/proc/can_gain_stacks()
return owner.stat != DEAD
/datum/status_effect/stacking/tick()
if(!can_have_status())
qdel(src)
else
add_stacks(-stack_decay)
stack_decay_effect()
/datum/status_effect/stacking/proc/add_stacks(stacks_added)
if(stacks_added > 0 && !can_gain_stacks())
return FALSE
owner.cut_overlay(status_overlay)
owner.underlays -= status_underlay
stacks += stacks_added
if(stacks > 0)
if(stacks >= stack_threshold && !threshold_crossed) //threshold_crossed check prevents threshold effect from occuring if changing from above threshold to still above threshold
threshold_crossed = TRUE
on_threshold_cross()
if(consumed_on_threshold)
return
else if(stacks < stack_threshold && threshold_crossed)
threshold_crossed = FALSE //resets threshold effect if we fall below threshold so threshold effect can trigger again
on_threshold_drop()
if(stacks_added > 0)
tick_interval += delay_before_decay //refreshes time until decay
stacks = min(stacks, max_stacks)
status_overlay.icon_state = "[overlay_state][stacks]"
status_underlay.icon_state = "[underlay_state][stacks]"
owner.add_overlay(status_overlay)
owner.underlays += status_underlay
else
fadeout_effect()
qdel(src) //deletes status if stacks fall under one
/datum/status_effect/stacking/on_creation(mob/living/new_owner, stacks_to_apply)
. = ..()
if(.)
add_stacks(stacks_to_apply)
/datum/status_effect/stacking/on_apply()
if(!can_have_status())
return FALSE
status_overlay = mutable_appearance(overlay_file, "[overlay_state][stacks]")
status_underlay = mutable_appearance(underlay_file, "[underlay_state][stacks]")
var/icon/I = icon(owner.icon, owner.icon_state, owner.dir)
var/icon_height = I.Height()
status_overlay.pixel_x = -owner.pixel_x
status_overlay.pixel_y = FLOOR(icon_height * 0.25, 1)
status_overlay.transform = matrix() * (icon_height/world.icon_size) //scale the status's overlay size based on the target's icon size
status_underlay.pixel_x = -owner.pixel_x
status_underlay.transform = matrix() * (icon_height/world.icon_size) * 3
status_underlay.alpha = 40
owner.add_overlay(status_overlay)
owner.underlays += status_underlay
return ..()
/datum/status_effect/stacking/Destroy()
if(owner)
owner.cut_overlay(status_overlay)
owner.underlays -= status_underlay
QDEL_NULL(status_overlay)
return ..()
/// Status effect from multiple sources, when all sources are removed, so is the effect
/datum/status_effect/grouped
status_type = STATUS_EFFECT_MULTIPLE //! Adds itself to sources and destroys itself if one exists already, there are never multiple
var/list/sources = list()
/datum/status_effect/grouped/on_creation(mob/living/new_owner, source)
var/datum/status_effect/grouped/existing = new_owner.has_status_effect(type)
if(existing)
existing.sources |= source
qdel(src)
return FALSE
else
sources |= source
return ..()
/datum/status_effect/grouped/before_remove(source)
sources -= source
return !length(sources)
+108 -26
View File
@@ -1,49 +1,96 @@
//The effects of weather occur across an entire z-level. For instance, lavaland has periodic ash storms that scorch most unprotected creatures.
/**
* Causes weather to occur on a z level in certain area types
*
* The effects of weather occur across an entire z-level. For instance, lavaland has periodic ash storms that scorch most unprotected creatures.
* Weather always occurs on different z levels at different times, regardless of weather type.
* Can have custom durations, targets, and can automatically protect indoor areas.
*
*/
/datum/weather
/// name of weather
var/name = "space wind"
/// description of weather
var/desc = "Heavy gusts of wind blanket the area, periodically knocking down anyone caught in the open."
var/telegraph_message = "<span class='warning'>The wind begins to pick up.</span>" //The message displayed in chat to foreshadow the weather's beginning
var/telegraph_duration = 300 //In deciseconds, how long from the beginning of the telegraph until the weather begins
var/telegraph_sound //The sound file played to everyone on an affected z-level
var/telegraph_overlay //The overlay applied to all tiles on the z-level
/// The message displayed in chat to foreshadow the weather's beginning
var/telegraph_message = "<span class='warning'>The wind begins to pick up.</span>"
var/weather_message = "<span class='userdanger'>The wind begins to blow ferociously!</span>" //Displayed in chat once the weather begins in earnest
var/weather_duration = 1200 //In deciseconds, how long the weather lasts once it begins
var/weather_duration_lower = 1200 //See above - this is the lowest possible duration
var/weather_duration_upper = 1500 //See above - this is the highest possible duration
/// In deciseconds, how long from the beginning of the telegraph until the weather begins
var/telegraph_duration = 300
/// The sound file played to everyone on an affected z-level
var/telegraph_sound
/// The overlay applied to all tiles on the z-level
var/telegraph_overlay
/// Displayed in chat once the weather begins in earnest
var/weather_message = "<span class='userdanger'>The wind begins to blow ferociously!</span>"
///In deciseconds, how long the weather lasts once it begins
var/weather_duration = 1200
///See above - this is the lowest possible duration
var/weather_duration_lower = 1200
///See above - this is the highest possible duration
var/weather_duration_upper = 1500
/// Looping sound while weather is occuring
var/weather_sound
/// Area overlay while the weather is occuring
var/weather_overlay
/// Color to apply to the area while weather is occuring
var/weather_color = null
var/end_message = "<span class='danger'>The wind relents its assault.</span>" //Displayed once the weather is over
var/end_duration = 300 //In deciseconds, how long the "wind-down" graphic will appear before vanishing entirely
/// Displayed once the weather is over
var/end_message = "<span class='danger'>The wind relents its assault.</span>"
/// In deciseconds, how long the "wind-down" graphic will appear before vanishing entirely
var/end_duration = 300
/// Sound that plays while weather is ending
var/end_sound
/// Area overlay while weather is ending
var/end_overlay
var/area_type = /area/space //Types of area to affect
var/list/impacted_areas = list() //Areas to be affected by the weather, calculated when the weather begins
var/list/protected_areas = list()//Areas that are protected and excluded from the affected areas.
var/impacted_z_levels // The list of z-levels that this weather is actively affecting
/// Types of area to affect
var/area_type = /area/space
/// TRUE value protects areas with outdoors marked as false, regardless of area type
var/protect_indoors = FALSE
/// Areas to be affected by the weather, calculated when the weather begins
var/list/impacted_areas = list()
var/overlay_layer = AREA_LAYER //Since it's above everything else, this is the layer used by default. TURF_LAYER is below mobs and walls if you need to use that.
var/aesthetic = FALSE //If the weather has no purpose other than looks
var/immunity_type = "storm" //Used by mobs to prevent them from being affected by the weather
/// Areas that are protected and excluded from the affected areas.
var/list/protected_areas = list()
/// The list of z-levels that this weather is actively affecting
var/impacted_z_levels
var/stage = END_STAGE //The stage of the weather, from 1-4
/// Since it's above everything else, this is the layer used by default. TURF_LAYER is below mobs and walls if you need to use that.
var/overlay_layer = AREA_LAYER
/// Plane for the overlay
var/overlay_plane = BLACKNESS_PLANE
/// If the weather has no purpose but aesthetics.
var/aesthetic = FALSE
/// Used by mobs to prevent them from being affected by the weather
var/immunity_type = "storm"
// These are read by the weather subsystem and used to determine when and where to run the weather.
var/probability = 0 // Weight amongst other eligible weather. If zero, will never happen randomly.
var/target_trait = ZTRAIT_STATION // The z-level trait to affect when run randomly or when not overridden.
/// The stage of the weather, from 1-4
var/stage = END_STAGE
/// Weight amongst other eligible weather. if zero, will never happen randomly.
var/probability = 0
/// The z-level trait to affect when run randomly or when not overridden.
var/target_trait = ZTRAIT_STATION
/// Whether a barometer can predict when the weather will happen
var/barometer_predictable = FALSE
var/next_hit_time = 0 //For barometers to know when the next storm will hit
/// For barometers to know when the next storm will hit
var/next_hit_time = 0
/datum/weather/New(z_levels)
..()
impacted_z_levels = z_levels
/**
* Telegraphs the beginning of the weather on the impacted z levels
*
* Sends sounds and details to mobs in the area
* Calculates duration and hit areas, and makes a callback for the actual weather to start
*
*/
/datum/weather/proc/telegraph()
if(stage == STARTUP_STAGE)
return
@@ -58,6 +105,8 @@
affectareas -= get_areas(V)
for(var/V in affectareas)
var/area/A = V
if(protect_indoors && !A.outdoors)
continue
if(A.z in impacted_z_levels)
impacted_areas |= A
weather_duration = rand(weather_duration_lower, weather_duration_upper)
@@ -72,6 +121,13 @@
SEND_SOUND(M, sound(telegraph_sound))
addtimer(CALLBACK(src, .proc/start), telegraph_duration)
/**
* Starts the actual weather and effects from it
*
* Updates area overlays and sends sounds and messages to mobs to notify them
* Begins dealing effects from weather to mobs in the area
*
*/
/datum/weather/proc/start()
if(stage >= MAIN_STAGE)
return
@@ -86,6 +142,13 @@
SEND_SOUND(M, sound(weather_sound))
addtimer(CALLBACK(src, .proc/wind_down), weather_duration)
/**
* Weather enters the winding down phase, stops effects
*
* Updates areas to be in the winding down phase
* Sends sounds and messages to mobs to notify them
*
*/
/datum/weather/proc/wind_down()
if(stage >= WIND_DOWN_STAGE)
return
@@ -100,6 +163,13 @@
SEND_SOUND(M, sound(end_sound))
addtimer(CALLBACK(src, .proc/end), end_duration)
/**
* Fully ends the weather
*
* Effects no longer occur and area overlays are removed
* Removes weather from processing completely
*
*/
/datum/weather/proc/end()
if(stage == END_STAGE)
return 1
@@ -115,7 +185,11 @@
if(can_weather_act(L))
weather_act(L)
/datum/weather/proc/can_weather_act(mob/living/L) //Can this weather impact a mob?
/**
* Returns TRUE if the living mob can be affected by the weather
*
*/
/datum/weather/proc/can_weather_act(mob/living/L)
var/turf/mob_turf = get_turf(L)
if(mob_turf && !(mob_turf.z in impacted_z_levels))
return
@@ -123,11 +197,19 @@
return
if(!(get_area(L) in impacted_areas))
return
return 1
return TRUE
/datum/weather/proc/weather_act(mob/living/L) //What effect does this weather have on the hapless mob?
/**
* Affects the mob with whatever the weather does
*
*/
/datum/weather/proc/weather_act(mob/living/L)
return
/**
* Updates the overlays on impacted areas
*
*/
/datum/weather/proc/update_areas()
for(var/V in impacted_areas)
var/area/N = V
@@ -17,8 +17,9 @@
end_message = "<span class='boldannounce'>The downpour gradually slows to a light shower. It should be safe outside now.</span>"
end_sound = 'sound/ambience/acidrain_end.ogg'
area_type = /area/lavaland/surface/outdoors
target_trait = ZTRAIT_MINING
area_type = /area
protect_indoors = TRUE
target_trait = ZTRAIT_ACIDRAIN
immunity_type = "acid" // temp
@@ -16,8 +16,9 @@
end_duration = 300
end_overlay = "light_ash"
area_type = /area/lavaland/surface/outdoors
target_trait = ZTRAIT_MINING
area_type = /area
protect_indoors = TRUE
target_trait = ZTRAIT_ASHSTORM
immunity_type = "ash"
@@ -15,8 +15,9 @@
end_duration = 100
end_message = "<span class='boldannounce'>The snowfall dies down, it should be safe to go outside again.</span>"
area_type = /area/awaymission/snowdin/outside
target_trait = ZTRAIT_AWAY
area_type = /area
protect_indoors = TRUE
target_trait = ZTRAIT_SNOWSTORM
immunity_type = "snow"