diff --git a/code/__DEFINES/mob_defines.dm b/code/__DEFINES/mob_defines.dm index 1ca22c92883..b7599881e39 100644 --- a/code/__DEFINES/mob_defines.dm +++ b/code/__DEFINES/mob_defines.dm @@ -15,6 +15,7 @@ #define CANNOT_BREAK (1 << 0) #define CANNOT_DISMEMBER (1 << 1) #define CANNOT_BURN (1 << 2) +#define CANNOT_INT_BLEED (1 << 3) #define PROCESS_ACCURACY 10 diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index dfe30135dd6..9bafd69f603 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -48,6 +48,8 @@ #define STATUS_EFFECT_BLOOD_SWELL /datum/status_effect/bloodswell //stun resistance and halved damage for gargantua vampires +#define STATUS_EFFECT_VAMPIRE_GLADIATOR /datum/status_effect/vampire_gladiator // Bonebreak, IB and burn wound immunity for garg vampires and healing. + #define STATUS_EFFECT_BLOOD_RUSH /datum/status_effect/blood_rush // speed boost for gargantua vampires #define STATUS_EFFECT_CHAINSAW_SLAYING /datum/status_effect/chainsaw_slaying // Stun immunity, very slight damage resistance diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 179f2e33975..548877ea656 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -111,7 +111,7 @@ return dist -/proc/circlerangeturfs(center=usr,radius=3) +/proc/circle_edge_turfs(center = usr, radius = 3) // Get the turfs on the edge of a circle. Currently only works for radius 3 var/turf/centerturf = get_turf(center) var/list/turfs = new/list() @@ -120,11 +120,13 @@ for(var/turf/T in range(radius, centerturf)) var/dx = T.x - centerturf.x var/dy = T.y - centerturf.y - if(dx*dx + dy*dy <= rsq) + if(dx * dx + dy * dy <= (rsq - radius)) + continue + if(dx * dx + dy * dy <= rsq) turfs += T return turfs -/proc/circleviewturfs(center=usr,radius=3) //Is there even a diffrence between this proc and circlerangeturfs()? +/proc/circleviewturfs(center = usr, radius = 3) // All the turfs in a circle of the radius var/turf/centerturf = get_turf(center) var/list/turfs = new/list() @@ -133,7 +135,7 @@ for(var/turf/T in view(radius, centerturf)) var/dx = T.x - centerturf.x var/dy = T.y - centerturf.y - if(dx*dx + dy*dy <= rsq) + if(dx * dx + dy * dy <= rsq) turfs += T return turfs diff --git a/code/__HELPERS/trait_helpers.dm b/code/__HELPERS/trait_helpers.dm index efbad457f7a..3c36fd0986b 100644 --- a/code/__HELPERS/trait_helpers.dm +++ b/code/__HELPERS/trait_helpers.dm @@ -181,6 +181,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_NO_BONES "no_bones" #define TRAIT_STURDY_LIMBS "sturdy_limbs" #define TRAIT_BURN_WOUND_IMMUNE "burn_immune" +#define TRAIT_IB_IMMUNE "ib_immune" #define TRAIT_COMIC_SANS "comic_sans" #define TRAIT_CHAV "chav" @@ -275,6 +276,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define MODSUIT_TRAIT "modsuit_trait" #define ENFORCER_GLOVES "enforcer_gloves" #define HOLO_CIGAR "holo_cigar" +#define GLADIATOR "gladiator" //quirk traits #define TRAIT_ALCOHOL_TOLERANCE "alcohol_tolerance" diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm index 4e57df1548e..940f2561442 100644 --- a/code/datums/status_effects/buffs.dm +++ b/code/datums/status_effects/buffs.dm @@ -173,8 +173,8 @@ return FALSE ADD_TRAIT(owner, TRAIT_CHUNKYFINGERS, VAMPIRE_TRAIT) var/mob/living/carbon/human/H = owner - H.physiology.brute_mod *= 0.5 - H.physiology.burn_mod *= 0.8 + H.physiology.brute_mod *= 0.4 + H.physiology.burn_mod *= 0.5 H.physiology.stamina_mod *= 0.5 H.physiology.stun_mod *= 0.5 var/datum/antagonist/vampire/V = owner.mind.has_antag_datum(/datum/antagonist/vampire) @@ -188,8 +188,8 @@ return REMOVE_TRAIT(owner, TRAIT_CHUNKYFINGERS, VAMPIRE_TRAIT) var/mob/living/carbon/human/H = owner - H.physiology.brute_mod /= 0.5 - H.physiology.burn_mod /= 0.8 + H.physiology.brute_mod /= 0.4 + H.physiology.burn_mod /= 0.5 H.physiology.stamina_mod /= 0.5 H.physiology.stun_mod /= 0.5 if(bonus_damage_applied) @@ -197,6 +197,48 @@ H.physiology.melee_bonus -= 10 H.dna.species.punchstunthreshold -= 8 +/datum/status_effect/vampire_gladiator + id = "vampire_gladiator" + duration = 30 SECONDS + tick_interval = 1 SECONDS + alert_type = /obj/screen/alert/status_effect/vampire_gladiator + +/obj/screen/alert/status_effect/vampire_gladiator + name = "Gladiatorial Resilience" + desc = "Roused by the thrill of the fight, your body has become more resistant to breaking!" + icon = 'icons/mob/actions/actions.dmi' + icon_state = "mech_damtype_brute" + +/datum/status_effect/vampire_gladiator/on_apply() + . = ..() + var/mob/living/carbon/human/H = owner + if(!istype(H)) + return + ADD_TRAIT(H, TRAIT_NO_BONES, GLADIATOR) + ADD_TRAIT(H, TRAIT_STURDY_LIMBS, GLADIATOR) + ADD_TRAIT(H, TRAIT_BURN_WOUND_IMMUNE, GLADIATOR) + ADD_TRAIT(H, TRAIT_IB_IMMUNE, GLADIATOR) + for(var/obj/item/organ/external/limb in H.bodyparts) + limb.add_limb_flags() + + +/datum/status_effect/vampire_gladiator/on_remove() + var/mob/living/carbon/human/H = owner + if(!istype(H)) + return + REMOVE_TRAIT(H, TRAIT_NO_BONES, GLADIATOR) + REMOVE_TRAIT(H, TRAIT_STURDY_LIMBS, GLADIATOR) + REMOVE_TRAIT(H, TRAIT_BURN_WOUND_IMMUNE, GLADIATOR) + REMOVE_TRAIT(H, TRAIT_IB_IMMUNE, GLADIATOR) + for(var/obj/item/organ/external/limb in H.bodyparts) + limb.remove_limb_flags() + + +/datum/status_effect/vampire_gladiator/tick() + owner.adjustStaminaLoss(-20) + owner.adjustBruteLoss(-5) + owner.adjustFireLoss(-5) + /datum/status_effect/blood_rush alert_type = null duration = 10 SECONDS diff --git a/code/game/turfs/simulated/floor/asteroid_floors.dm b/code/game/turfs/simulated/floor/asteroid_floors.dm index e89da58ed60..1e0d0a21d6b 100644 --- a/code/game/turfs/simulated/floor/asteroid_floors.dm +++ b/code/game/turfs/simulated/floor/asteroid_floors.dm @@ -292,7 +292,7 @@ GLOBAL_LIST_INIT(megafauna_spawn_list, list(/mob/living/simple_animal/hostile/me if(DEADLY_DEEPROCK) var/tempradius = rand(10, 15) var/probmodifer = 43 * tempradius //Yes this is a magic number, it is a magic number that works well. - for(var/turf/NT in circlerangeturfs(T, tempradius)) + for(var/turf/NT in circleviewturfs(T, tempradius)) var/distance = (max(get_dist(T, NT), 1)) //Get dist throws -1 if same turf if(prob(min(probmodifer / distance, 100))) if(ismineralturf(NT) || istype(NT, /turf/simulated/floor/plating/asteroid)) //No spawning on lava / other ruins @@ -302,7 +302,7 @@ GLOBAL_LIST_INIT(megafauna_spawn_list, list(/mob/living/simple_animal/hostile/me var/turf/oasis_lake = pickweight(list(/turf/simulated/floor/plating/lava/smooth/lava_land_surface = 4, /turf/simulated/floor/plating/lava/smooth/lava_land_surface/plasma = 4, /turf/simulated/floor/chasm/straight_down/lava_land_surface = 4, /turf/simulated/floor/plating/lava/smooth/mapping_lava = 6, /turf/simulated/floor/beach/away/water = 1, /turf/simulated/floor/plating/asteroid = 1)) if(oasis_lake == /turf/simulated/floor/plating/asteroid) new /obj/effect/spawner/oasisrock(T, tempradius) - for(var/turf/oasis in circlerangeturfs(T, tempradius)) + for(var/turf/oasis in circleviewturfs(T, tempradius)) oasis.ChangeTurf(oasis_lake, ignore_air = TRUE) /obj/effect/spawner/oasisrock @@ -314,7 +314,7 @@ GLOBAL_LIST_INIT(megafauna_spawn_list, list(/mob/living/simple_animal/hostile/me addtimer(CALLBACK(src, PROC_REF(make_rock), radius), 5 SECONDS) /obj/effect/spawner/oasisrock/proc/make_rock(radius) - for(var/turf/oasis in circlerangeturfs(get_turf(src), radius)) + for(var/turf/oasis in circleviewturfs(get_turf(src), radius)) oasis.ChangeTurf(/turf/simulated/mineral/random/high_chance/volcanic, ignore_air = TRUE) var/list/valid_turfs = RANGE_EDGE_TURFS(radius + 2, src) for(var/mob/M in range(src, radius)) //We don't want mobs inside the ore rock diff --git a/code/modules/antagonists/vampire/vampire_powers/gargantua_powers.dm b/code/modules/antagonists/vampire/vampire_powers/gargantua_powers.dm index c76b25bb2f8..bc09d51b8c5 100644 --- a/code/modules/antagonists/vampire/vampire_powers/gargantua_powers.dm +++ b/code/modules/antagonists/vampire/vampire_powers/gargantua_powers.dm @@ -201,3 +201,92 @@ var/mob/living/L = user L.apply_status_effect(STATUS_EFFECT_CHARGING) L.throw_at(target, targeting.range, 1, L, FALSE, callback = CALLBACK(L, TYPE_PROC_REF(/mob/living, remove_status_effect), STATUS_EFFECT_CHARGING)) + +#define ARENA_SIZE 3 + +/obj/effect/proc_holder/spell/vampire/arena + name = "Desecrated Duel (150)" + desc = "You leap towards someone. Upon landing, you conjure an arena, and within it you will heal brute and burn damage, recover from fatigue faster, and be strengthened against lasting damages. Can be recasted to end the spell early." + gain_desc = "You can now leap to a target and trap them in a conjured arena." + required_blood = 150 + base_cooldown = 30 SECONDS + action_icon_state = "duel" + should_recharge_after_cast = FALSE + var/spell_active = FALSE + /// Holds a reference to the timer until either the spell runs out or we recast it + var/timer + /// Holds a reference to all arena walls so we can qdel them easily with dispel() + var/list/all_temp_walls = list() + +/obj/effect/proc_holder/spell/vampire/arena/create_new_targeting() + var/datum/spell_targeting/click/T = new + T.click_radius = 0 + T.allowed_type = /mob/living/carbon/human + return T + +/obj/effect/proc_holder/spell/vampire/arena/cast(list/targets, mob/living/user) + var/target = targets[1] // We only want to dash towards the first mob in our targeting list, if somehow multiple ended up in there + if(!targets) + return + + if(timer) // Recast to dispel the wall and buff early + dispel(user) + return + + // First we leap towards the enemy target + user.add_stun_absorption("gargantua", INFINITY, 2) // We temporarily make the gargantua immune to stuns to stop any matrix fuckery from happening + animate(user, 1 SECONDS, pixel_z = 64, flags = ANIMATION_RELATIVE, easing = SINE_EASING|EASE_OUT) + addtimer(CALLBACK(user, user.spin(12, 1), 3, 2), 0.3 SECONDS) + var/angle = get_angle(user, target) + 180 + user.transform = user.transform.Turn(angle) + for(var/i in 1 to 10) + var/move_dir = get_dir(user, target) + user.forceMove(get_step(user, move_dir)) + if(get_turf(user) == get_turf(target)) + user.remove_stun_absorption("gargantua") + user.set_body_position(STANDING_UP) + user.transform = matrix() + break + sleep(1) + animate(user, 0.2 SECONDS, pixel_z = -64, flags = ANIMATION_RELATIVE, easing = SINE_EASING|EASE_IN) + // They get a cool soundeffect and a visual, as a treat + + playsound(get_turf(user), 'sound/effects/meteorimpact.ogg', 100, TRUE) + new /obj/effect/temp_visual/stomp(get_turf(user)) + + // Now we build the arena and give the caster the buff + + user.apply_status_effect(STATUS_EFFECT_VAMPIRE_GLADIATOR) + spell_active = TRUE + timer = addtimer(CALLBACK(src, PROC_REF(dispel), user, TRUE), 30 SECONDS, TIMER_STOPPABLE) + RegisterSignal(user, COMSIG_PARENT_QDELETING, PROC_REF(dispel)) + arena_checks(get_turf(target), user) + +/obj/effect/proc_holder/spell/vampire/arena/proc/arena_checks(turf/target_turf, mob/living/user) + if(!spell_active || QDELETED(src)) + return + INVOKE_ASYNC(src, PROC_REF(fighters_check), user) //Checks to see if our fighters died. + INVOKE_ASYNC(src, PROC_REF(arena_trap), target_turf) //Gets another arena trap queued up for when this one runs out. + addtimer(CALLBACK(src, PROC_REF(arena_checks), target_turf, user), 5 SECONDS) + +/obj/effect/proc_holder/spell/vampire/arena/proc/arena_trap(turf/target_turf) + for(var/tumor_range_turfs in circle_edge_turfs(target_turf, ARENA_SIZE)) + tumor_range_turfs = new /obj/effect/temp_visual/elite_tumor_wall(tumor_range_turfs, src) + all_temp_walls += tumor_range_turfs + +/obj/effect/proc_holder/spell/vampire/arena/proc/fighters_check(mob/living/user) + if(QDELETED(user) || user.stat == DEAD) + dispel(user) + return + +/obj/effect/proc_holder/spell/vampire/arena/proc/dispel(mob/living/user) + spell_active = FALSE + if(timer) + deltimer(timer) + timer = null + QDEL_LIST_CONTENTS(all_temp_walls) + cooldown_handler.start_recharge() + user.remove_status_effect(STATUS_EFFECT_VAMPIRE_GLADIATOR) + user.visible_message("The arena begins to dissipate.") + +#undef ARENA_SIZE diff --git a/code/modules/antagonists/vampire/vampire_subclasses.dm b/code/modules/antagonists/vampire/vampire_subclasses.dm index 9d9282f1cc7..25028792746 100644 --- a/code/modules/antagonists/vampire/vampire_subclasses.dm +++ b/code/modules/antagonists/vampire/vampire_subclasses.dm @@ -53,10 +53,11 @@ /obj/effect/proc_holder/spell/vampire/self/stomp = 250, /datum/vampire_passive/blood_swell_upgrade = 400, /obj/effect/proc_holder/spell/vampire/self/overwhelming_force = 600, + /obj/effect/proc_holder/spell/vampire/charge = 800, /obj/effect/proc_holder/spell/fireball/demonic_grasp = 800) fully_powered_abilities = list(/datum/vampire_passive/full, /datum/vampire_passive/vision/full, - /obj/effect/proc_holder/spell/vampire/charge) + /obj/effect/proc_holder/spell/vampire/arena) improved_rejuv_healing = TRUE /datum/vampire_subclass/dantalion @@ -87,6 +88,7 @@ /obj/effect/proc_holder/spell/vampire/blood_barrier, /obj/effect/proc_holder/spell/vampire/self/blood_rush, /obj/effect/proc_holder/spell/vampire/self/stomp, + /obj/effect/proc_holder/spell/vampire/charge, /obj/effect/proc_holder/spell/vampire/shadow_snare, /obj/effect/proc_holder/spell/vampire/soul_anchor, /obj/effect/proc_holder/spell/vampire/pacify, @@ -106,7 +108,7 @@ /datum/vampire_passive/full, /datum/vampire_passive/vision/full, /obj/effect/proc_holder/spell/vampire/self/blood_spill, - /obj/effect/proc_holder/spell/vampire/charge, + /obj/effect/proc_holder/spell/vampire/arena, /obj/effect/proc_holder/spell/vampire/self/eternal_darkness, /obj/effect/proc_holder/spell/vampire/hysteria, /obj/effect/proc_holder/spell/vampire/raise_vampires, diff --git a/code/modules/mob/living/simple_animal/hostile/mining/elites/elite.dm b/code/modules/mob/living/simple_animal/hostile/mining/elites/elite.dm index 50c290a8009..5535c33af11 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining/elites/elite.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining/elites/elite.dm @@ -330,10 +330,7 @@ While using this makes the system rely on OnFire, it still gives options for tim if(loc == null) return for(var/tumor_range_turfs in RANGE_EDGE_TURFS(ARENA_RADIUS, tumor_turf)) - var/obj/effect/temp_visual/elite_tumor_wall/newwall - newwall = new /obj/effect/temp_visual/elite_tumor_wall(tumor_range_turfs, src) - newwall.activator = activator - newwall.ourelite = mychild + new /obj/effect/temp_visual/elite_tumor_wall(tumor_range_turfs, src) /obj/structure/elite_tumor/proc/border_check() if(activator != null && get_dist(src, activator) >= ARENA_RADIUS) @@ -453,14 +450,12 @@ While using this makes the system rely on OnFire, it still gives options for tim smoothing_flags = SMOOTH_BITMASK smoothing_groups = list(SMOOTH_GROUP_HIERO_WALL) canSmoothWith = list(SMOOTH_GROUP_HIERO_WALL) - duration = 50 + duration = 5 SECONDS layer = BELOW_MOB_LAYER plane = GAME_PLANE color = rgb(255,0,0) light_range = MINIMUM_USEFUL_LIGHT_RANGE light_color = LIGHT_COLOR_PURE_RED - var/activator - var/ourelite /obj/effect/temp_visual/elite_tumor_wall/Initialize(mapload, new_caster) . = ..() diff --git a/code/modules/mod/modules/modules_supply.dm b/code/modules/mod/modules/modules_supply.dm index 85f2c2f3fe8..87e0912107b 100644 --- a/code/modules/mod/modules/modules_supply.dm +++ b/code/modules/mod/modules/modules_supply.dm @@ -526,7 +526,7 @@ /obj/structure/mining_bomb/proc/boom(atom/movable/firer) visible_message("[src] explodes!") playsound(src, 'sound/magic/magic_missile.ogg', 200, vary = TRUE) - for(var/turf/T in circlerangeturfs(src, 2)) + for(var/turf/T in circleviewturfs(src, 2)) if(ismineralturf(T)) var/turf/simulated/mineral/mineral_turf = T mineral_turf.gets_drilled(firer) diff --git a/code/modules/surgery/organs/organ_external.dm b/code/modules/surgery/organs/organ_external.dm index c62115cc810..4a5e028e7ba 100644 --- a/code/modules/surgery/organs/organ_external.dm +++ b/code/modules/surgery/organs/organ_external.dm @@ -148,6 +148,21 @@ if(HAS_TRAIT(owner, TRAIT_BURN_WOUND_IMMUNE)) limb_flags |= CANNOT_BURN + if(HAS_TRAIT(owner, TRAIT_IB_IMMUNE)) + limb_flags |= CANNOT_INT_BLEED + +/obj/item/organ/external/proc/remove_limb_flags() + if(!HAS_TRAIT(owner, TRAIT_NO_BONES)) + limb_flags &= ~CANNOT_BREAK + encased = initial(encased) + + if(!HAS_TRAIT(owner, TRAIT_STURDY_LIMBS)) + limb_flags &= ~CANNOT_DISMEMBER + + if(!HAS_TRAIT(owner, TRAIT_BURN_WOUND_IMMUNE)) + limb_flags &= ~CANNOT_BURN + if(!HAS_TRAIT(owner, TRAIT_IB_IMMUNE)) + limb_flags &= ~CANNOT_INT_BLEED /obj/item/organ/external/replaced(mob/living/carbon/human/target) owner = target @@ -697,6 +712,8 @@ Note that amputating the affected organ does in fact remove the infection from t return if(NO_BLOOD in owner.dna.species.species_traits) return + if(limb_flags & CANNOT_INT_BLEED) + return status |= ORGAN_INT_BLEEDING owner.custom_pain("You feel something rip in your [name]!") diff --git a/icons/mob/actions/actions.dmi b/icons/mob/actions/actions.dmi index e9a28c73026..43ace519395 100644 Binary files a/icons/mob/actions/actions.dmi and b/icons/mob/actions/actions.dmi differ diff --git a/tgui/packages/tgui/interfaces/SpecMenu.js b/tgui/packages/tgui/interfaces/SpecMenu.js index 92a49f3ab4f..aa2316ae119 100644 --- a/tgui/packages/tgui/interfaces/SpecMenu.js +++ b/tgui/packages/tgui/interfaces/SpecMenu.js @@ -157,11 +157,16 @@ const GarMenu = (props, context) => { demonic hand to snare someone. If you are on disarm/grab intent you will push/pull the target, respectively.

+

+ Charge: Unlocked at 800 blood, you gain the ability to charge at a target. Destroying + and knocking back pretty much anything you collide with. +

Full Power - Charge: You gain the ability to charge at a target. Destroying - and knocking back pretty much anything you collide with. + Desecrated Duel: Leap towards a visible enemy, creating an + arena upon landing, infusing you with increased regeneration, and granting + you resistance to internal damages.