From 432724a38840dd23bde7e0145fd941a80caa7b2d Mon Sep 17 00:00:00 2001 From: kevinz000 <2003111+kevinz000@users.noreply.github.com> Date: Thu, 30 Apr 2020 00:58:59 -0700 Subject: [PATCH] fixes --- code/__DEFINES/mobs.dm | 4 +- code/__DEFINES/mobs/slowdowns.dm | 6 + code/datums/status_effects/status_effect.dm | 129 +++++++++++++++++- .../hostile/megafauna/demonic_frost_miner.dm | 25 ++-- .../simple_animal/hostile/megafauna/drake.dm | 23 ++++ .../hostile/mining_mobs/ice_demon.dm | 2 +- .../hostile/mining_mobs/ice_whelp.dm | 6 +- .../hostile/mining_mobs/polarbear.dm | 6 +- tgstation.dme | 1 + 9 files changed, 176 insertions(+), 26 deletions(-) create mode 100644 code/__DEFINES/mobs/slowdowns.dm diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 47b7330f07..de35be080e 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -289,6 +289,4 @@ #define HUMAN_FIRE_STACK_ICON_NUM 3 -#define PULL_PRONE_SLOWDOWN 0.6 -#define FIREMAN_CARRY_SLOWDOWN 0 -#define PIGGYBACK_CARRY_SLOWDOWN 1 +#define SLEEP_CHECK_DEATH(X) sleep(X); if(QDELETED(src) || stat == DEAD) return; diff --git a/code/__DEFINES/mobs/slowdowns.dm b/code/__DEFINES/mobs/slowdowns.dm new file mode 100644 index 0000000000..e532da0066 --- /dev/null +++ b/code/__DEFINES/mobs/slowdowns.dm @@ -0,0 +1,6 @@ +/// How much someone is slowed from pulling a prone human +#define PULL_PRONE_SLOWDOWN 0.6 +/// How much someone is slowed from fireman carrying a human +#define FIREMAN_CARRY_SLOWDOWN 0 +/// How much someone is slowed by piggybacking a human +#define PIGGYBACK_CARRY_SLOWDOWN 1 diff --git a/code/datums/status_effects/status_effect.dm b/code/datums/status_effects/status_effect.dm index e2114f0778..d3c2f44abb 100644 --- a/code/datums/status_effects/status_effect.dm +++ b/code/datums/status_effects/status_effect.dm @@ -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)) @@ -147,3 +148,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) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm index e258f958b1..88f2cfb132 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm @@ -10,8 +10,7 @@ Difficulty: Extremely Hard icon_state = "demonic_miner" icon_living = "demonic_miner" icon = 'icons/mob/icemoon/icemoon_monsters.dmi' - attack_verb_continuous = "pummels" - attack_verb_simple = "pummels" + attack_text = "pummels" attack_sound = 'sound/weapons/sonic_jackhammer.ogg' mob_biotypes = MOB_ORGANIC|MOB_HUMANOID light_color = "#E4C7C5" @@ -105,7 +104,7 @@ Difficulty: Extremely Hard else ice_shotgun(5, list(list(0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330), list(-30, -15, 0, 15, 30))) -/obj/projectile/frost_orb +/obj/item/projectile/frost_orb name = "frost orb" icon_state = "ice_1" damage = 20 @@ -114,12 +113,12 @@ Difficulty: Extremely Hard homing_turn_speed = 30 damage_type = BURN -/obj/projectile/frost_orb/on_hit(atom/target, blocked = FALSE) +/obj/item/projectile/frost_orb/on_hit(atom/target, blocked = FALSE) . = ..() if(isturf(target) || isobj(target)) target.ex_act(EXPLODE_HEAVY) -/obj/projectile/snowball +/obj/item/projectile/snowball name = "machine-gun snowball" icon_state = "nuclear_particle" damage = 5 @@ -127,7 +126,7 @@ Difficulty: Extremely Hard speed = 4 damage_type = BRUTE -/obj/projectile/ice_blast +/obj/item/projectile/ice_blast name = "ice blast" icon_state = "ice_2" damage = 15 @@ -135,7 +134,7 @@ Difficulty: Extremely Hard speed = 4 damage_type = BRUTE -/obj/projectile/ice_blast/on_hit(atom/target, blocked = FALSE) +/obj/item/projectile/ice_blast/on_hit(atom/target, blocked = FALSE) . = ..() if(isturf(target) || isobj(target)) target.ex_act(EXPLODE_HEAVY) @@ -166,26 +165,26 @@ Difficulty: Extremely Hard var/turf/endloc = get_turf(target) if(!endloc) break - var/obj/projectile/frost_orb/P = new(startloc) + var/obj/item/projectile/frost_orb/P = new(startloc) P.preparePixelProjectile(endloc, startloc) P.firer = src if(target) P.original = target P.set_homing_target(target) P.fire(rand(0, 360)) - addtimer(CALLBACK(P, /obj/projectile/frost_orb/proc/orb_explosion, projectile_speed_multiplier), 20) // make the orbs home in after a second + addtimer(CALLBACK(P, /obj/item/projectile/frost_orb/proc/orb_explosion, projectile_speed_multiplier), 20) // make the orbs home in after a second SLEEP_CHECK_DEATH(added_delay) SetRecoveryTime(40, 60) /// Called when the orb is exploding, shoots out projectiles -/obj/projectile/frost_orb/proc/orb_explosion(projectile_speed_multiplier) +/obj/item/projectile/frost_orb/proc/orb_explosion(projectile_speed_multiplier) for(var/i in 0 to 5) var/angle = i * 60 var/turf/startloc = get_turf(src) var/turf/endloc = get_turf(original) if(!startloc || !endloc) break - var/obj/projectile/ice_blast/P = new(startloc) + var/obj/item/projectile/ice_blast/P = new(startloc) P.speed *= projectile_speed_multiplier P.preparePixelProjectile(endloc, startloc, null, angle + rand(-10, 10)) P.firer = firer @@ -201,7 +200,7 @@ Difficulty: Extremely Hard var/turf/endloc = get_turf(target) if(!endloc) break - var/obj/projectile/P = new /obj/projectile/snowball(startloc) + var/obj/item/projectile/P = new /obj/item/projectile/snowball(startloc) P.speed *= projectile_speed_multiplier P.preparePixelProjectile(endloc, startloc, null, rand(-spread, spread)) P.firer = src @@ -220,7 +219,7 @@ Difficulty: Extremely Hard var/turf/endloc = get_turf(target) if(!endloc) break - var/obj/projectile/P = new /obj/projectile/ice_blast(startloc) + var/obj/item/projectile/P = new /obj/item/projectile/ice_blast(startloc) P.speed *= projectile_speed_multiplier P.preparePixelProjectile(endloc, startloc, null, spread) P.firer = src diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm index 4644992ad0..4a349f9385 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm @@ -394,3 +394,26 @@ Difficulty: Medium /mob/living/simple_animal/hostile/megafauna/dragon/lesser/grant_achievement(medaltype,scoretype) return + +//fire line keeps going even if dragon is deleted +/proc/dragon_fire_line(source, list/turfs) + var/list/hit_list = list() + for(var/turf/T in turfs) + if(istype(T, /turf/closed)) + break + new /obj/effect/hotspot(T) + T.hotspot_expose(700,50,1) + for(var/mob/living/L in T.contents) + if(L in hit_list || L == source) + continue + hit_list += L + L.adjustFireLoss(20) + to_chat(L, "You're hit by [source]'s fire breath!") + + // deals damage to mechs + for(var/obj/mecha/M in T.contents) + if(M in hit_list) + continue + hit_list += M + M.take_damage(45, BRUTE, "melee", 1) + sleep(1.5) diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/ice_demon.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/ice_demon.dm index 560043a624..8f01584a8e 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/ice_demon.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/ice_demon.dm @@ -43,7 +43,7 @@ /// Distance the demon will teleport from the target var/teleport_distance = 3 -/obj/projectile/temp/basilisk/ice +/obj/item/projectile/temp/basilisk/ice name = "ice blast" damage = 5 nodamage = FALSE diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/ice_whelp.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/ice_whelp.dm index 95e5a42eae..8c56390b0b 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/ice_whelp.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/ice_whelp.dm @@ -7,8 +7,7 @@ icon_dead = "ice_whelp_dead" mob_biotypes = MOB_ORGANIC|MOB_BEAST mouse_opacity = MOUSE_OPACITY_ICON - friendly_verb_continuous = "stares down" - friendly_verb_simple = "stare down" + friendly = "stares down" speak_emote = list("roars") speed = 30 move_to_delay = 30 @@ -20,8 +19,7 @@ armour_penetration = 20 melee_damage_lower = 20 melee_damage_upper = 20 - attack_verb_continuous = "chomps" - attack_verb_simple = "chomp" + attack_text = "chomps" attack_sound = 'sound/magic/demon_attack1.ogg' vision_range = 9 aggro_vision_range = 9 diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/polarbear.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/polarbear.dm index 0a30a30701..03a168440b 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/polarbear.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/polarbear.dm @@ -7,8 +7,7 @@ icon_dead = "polarbear_dead" mob_biotypes = MOB_ORGANIC|MOB_BEAST mouse_opacity = MOUSE_OPACITY_ICON - friendly_verb_continuous = "growls at" - friendly_verb_simple = "growl at" + friendly = "growls at" speak_emote = list("growls") speed = 12 move_to_delay = 12 @@ -17,8 +16,7 @@ obj_damage = 40 melee_damage_lower = 25 melee_damage_upper = 25 - attack_verb_continuous = "claws" - attack_verb_simple = "claw" + attack_text = "claws" attack_sound = 'sound/weapons/bladeslice.ogg' vision_range = 2 // don't aggro unless you basically antagonize it, though they will kill you worse than a goliath will aggro_vision_range = 9 diff --git a/tgstation.dme b/tgstation.dme index ae64f85e18..92e9f84459 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -125,6 +125,7 @@ #include "code\__DEFINES\dcs\helpers.dm" #include "code\__DEFINES\dcs\signals.dm" #include "code\__DEFINES\flags\shields.dm" +#include "code\__DEFINES\mobs\slowdowns.dm" #include "code\__HELPERS\_cit_helpers.dm" #include "code\__HELPERS\_lists.dm" #include "code\__HELPERS\_logging.dm"