diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 3dc9223bb57..f1f2b8e461a 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -117,6 +117,15 @@ locate(min(CENTER.x+(RADIUS),world.maxx), min(CENTER.y+(RADIUS),world.maxy), CENTER.z) \ ) +/// Returns the turfs on the edge of a square with CENTER in the middle and with the given RADIUS. If used near the edge of the map, will still work fine. +// order of the additions: top edge + bottom edge + left edge + right edge +#define RANGE_EDGE_TURFS(RADIUS, CENTER)\ + (CENTER.y + RADIUS < world.maxy ? block(locate(max(CENTER.x - RADIUS, 1), min(CENTER.y + RADIUS, world.maxy), CENTER.z), locate(min(CENTER.x + RADIUS, world.maxx), min(CENTER.y + RADIUS, world.maxy), CENTER.z)) : list()) +\ + (CENTER.y - RADIUS > 1 ? block(locate(max(CENTER.x - RADIUS, 1), max(CENTER.y - RADIUS, 1), CENTER.z), locate(min(CENTER.x + RADIUS, world.maxx), max(CENTER.y - RADIUS, 1), CENTER.z)) : list()) +\ + (CENTER.x - RADIUS > 1 ? block(locate(max(CENTER.x - RADIUS, 1), min(CENTER.y + RADIUS - 1, world.maxy), CENTER.z), locate(max(CENTER.x - RADIUS, 1), max(CENTER.y - RADIUS + 1, 1), CENTER.z)) : list()) +\ + (CENTER.x + RADIUS < world.maxx ? block(locate(min(CENTER.x + RADIUS, world.maxx), min(CENTER.y + RADIUS - 1, world.maxy), CENTER.z), locate(min(CENTER.x + RADIUS, world.maxx), max(CENTER.y - RADIUS + 1, 1), CENTER.z)) : list()) + + #define FOR_DVIEW(type, range, center, invis_flags) \ GLOB.dview_mob.loc = center; \ GLOB.dview_mob.see_invisible = invis_flags; \ diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm index 5d26805365d..3bdce223b70 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm @@ -297,10 +297,9 @@ Difficulty: Hard arena_cooldown = world.time + initial(arena_cooldown) for(var/d in GLOB.cardinal) INVOKE_ASYNC(src, .proc/arena_squares, T, d) - for(var/t in RANGE_TURFS(11, T)) - if(t && get_dist(t, T) == 11) - new /obj/effect/temp_visual/hierophant/wall(t, src) - new /obj/effect/temp_visual/hierophant/blast(t, src, FALSE) + for(var/t in RANGE_EDGE_TURFS(11, T)) + new /obj/effect/temp_visual/hierophant/wall(t, src) + new /obj/effect/temp_visual/hierophant/blast(t, src, FALSE) if(get_dist(src, T) >= 11) //hey you're out of range I need to get closer to you! INVOKE_ASYNC(src, .proc/blink, T) 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 3143196499f..f4e18f0b690 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 @@ -1,6 +1,7 @@ #define TUMOR_INACTIVE 0 #define TUMOR_ACTIVE 1 #define TUMOR_PASSIVE 2 +#define ARENA_RADIUS 12 //Elite mining mobs /mob/living/simple_animal/hostile/asteroid/elite @@ -174,6 +175,9 @@ While using this makes the system rely on OnFire, it still gives options for tim /mob/living/simple_animal/hostile/asteroid/elite/herald, ) + ///List of invaders that have teleportes into the arena *multiple times*. They will be suffering. + var/list/invaders = list() + /obj/structure/elite_tumor/attack_hand(mob/user, list/modifiers) . = ..() if(!ishuman(user)) @@ -234,6 +238,7 @@ While using this makes the system rely on OnFire, it still gives options for tim icon_state = "tumor_popped" RegisterSignal(mychild, COMSIG_PARENT_QDELETING, .proc/onEliteLoss) INVOKE_ASYNC(src, .proc/arena_checks) + AddComponent(/datum/component/proximity_monitor, ARENA_RADIUS) //Boots out humanoid invaders. Minebots / random fauna / that colossus you forgot to clear away allowed. /obj/structure/elite_tumor/proc/return_elite() mychild.forceMove(loc) @@ -246,6 +251,7 @@ While using this makes the system rely on OnFire, it still gives options for tim mychild.grab_ghost() notify_ghosts("\A [mychild] has been challenged in \the [get_area(src)]!", enter_link="(Click to help)", source = mychild, action = NOTIFY_FOLLOW) INVOKE_ASYNC(src, .proc/arena_checks) + AddComponent(/datum/component/proximity_monitor, ARENA_RADIUS) /obj/structure/elite_tumor/Initialize(mapload) . = ..() @@ -255,6 +261,7 @@ While using this makes the system rely on OnFire, it still gives options for tim /obj/structure/elite_tumor/Destroy() STOP_PROCESSING(SSobj, src) QDEL_NULL(gps) + invaders.Cut() if(activator) clear_activator(activator) if(mychild) @@ -322,23 +329,40 @@ While using this makes the system rely on OnFire, it still gives options for tim var/turf/tumor_turf = get_turf(src) if(loc == null) return - for(var/tumor_range_turfs in RANGE_TURFS(12, tumor_turf)) - if(get_dist(tumor_range_turfs, tumor_turf) == 12) - 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 + 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 /obj/structure/elite_tumor/proc/border_check() - if(activator != null && get_dist(src, activator) >= 12) + if(activator != null && get_dist(src, activator) >= ARENA_RADIUS) activator.forceMove(loc) visible_message("[activator] suddenly reappears above [src]!") playsound(loc,'sound/effects/phasein.ogg', 200, 0, 50, TRUE, TRUE) - if(mychild != null && get_dist(src, mychild) >= 12) + if(mychild != null && get_dist(src, mychild) >= ARENA_RADIUS) mychild.forceMove(loc) visible_message("[mychild] suddenly reappears above [src]!") playsound(loc,'sound/effects/phasein.ogg', 200, 0, 50, TRUE, TRUE) +/obj/structure/elite_tumor/HasProximity(atom/movable/AM) + if(!ishuman(AM) && !isrobot(AM)) + return + var/mob/living/M = AM + if(M == activator) + return + if(M in invaders) + to_chat(M, "You dare to try to break the sanctity of our arena? SUFFER...") + for(var/i in 1 to 4) + M.apply_status_effect(STATUS_EFFECT_VOID_PRICE) /// Hey kids, want 60 brute damage, increased by 40 each time you do it? Well, here you go! + else + to_chat(M, "Only spectators are allowed, while the arena is in combat...") + invaders += M + var/list/valid_turfs = RANGE_EDGE_TURFS(ARENA_RADIUS + 1, src) + M.forceMove(pick(valid_turfs)) //Doesn't check for lava. Don't cheese it. + playsound(M, 'sound/effects/phasein.ogg', 200, 0, 50, TRUE, TRUE) + + /obj/structure/elite_tumor/proc/onEliteLoss() playsound(loc,'sound/effects/tendril_destroyed.ogg', 200, 0, 50, TRUE, TRUE) visible_message("[src] begins to convulse violently before beginning to dissipate.") @@ -382,6 +406,7 @@ While using this makes the system rely on OnFire, it still gives options for tim Bear in mind, if anyone interacts with your tumor, you'll be resummoned here to carry out another fight. In such a case, you will regain your full max health.\n\ Also, be weary of your fellow inhabitants, they likely won't be happy to see you!") to_chat(mychild, "Note that you are a lavaland monster, and thus not allied to the station. You should not cooperate or act friendly with any station crew unless under extreme circumstances!") + qdel(GetComponent(/datum/component/proximity_monitor)) /obj/item/tumor_shard name = "tumor shard" @@ -405,7 +430,7 @@ While using this makes the system rely on OnFire, it still gives options for tim E.revive() user.visible_message("[user] stabs [E] with [src], reviving it.") SEND_SOUND(E, 'sound/magic/cult_spell.ogg') - to_chat(E, "You have been revived by [user]. While you can't speak to them, you owe [user] a great debt. Assist [user.p_them()] in achieving [user.p_their()] goals, regardless of risk.") + to_chat(E, "You have been revived by [user], and you owe [user] a great debt. Assist [user.p_them()] in achieving [user.p_their()] goals, regardless of risk.") to_chat(E, "Note that you now share the loyalties of [user]. You are expected not to intentionally sabotage their faction unless commanded to!") if(user.mind.special_role) E.maxHealth = 300 @@ -450,7 +475,7 @@ While using this makes the system rely on OnFire, it still gives options for tim /obj/effect/temp_visual/elite_tumor_wall/CanPass(atom/movable/mover, border_dir) . = ..() - if(mover == ourelite || mover == activator) + if(isliving(mover)) return FALSE /obj/item/gps/internal/tumor @@ -458,3 +483,8 @@ While using this makes the system rely on OnFire, it still gives options for tim gpstag = "Cancerous Signal" desc = "Ghosts in a fauna? That's cancerous!" invisibility = 100 + +#undef TUMOR_INACTIVE +#undef TUMOR_ACTIVE +#undef TUMOR_PASSIVE +#undef ARENA_RADIUS diff --git a/code/modules/mob/living/simple_animal/hostile/mining/elites/goliath_broodmother.dm b/code/modules/mob/living/simple_animal/hostile/mining/elites/goliath_broodmother.dm index f8d09d06e60..f82a321a34b 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining/elites/goliath_broodmother.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining/elites/goliath_broodmother.dm @@ -143,7 +143,7 @@ color = "#FF0000" speed = 0 move_to_delay = 3 - addtimer(CALLBACK(src, .proc/reset_rage), 65) + addtimer(CALLBACK(src, .proc/reset_rage), 5 SECONDS) /mob/living/simple_animal/hostile/asteroid/elite/broodmother/proc/reset_rage() color = "#FFFFFF" @@ -159,7 +159,7 @@ var/turf/T = get_step(src, spawndir) if(T) child.forceMove(T) - child.revive() // at most this is a 29 hp heal. + child.revive() // at most this is a 49 hp heal. playsound(src, 'sound/effects/bamf.ogg', 100, 1) //The goliath's children. Pretty weak, simple mobs which are able to put a single tentacle under their target when at range. @@ -172,10 +172,11 @@ icon_aggro = "goliath_baby" icon_dead = "goliath_baby_dead" icon_gib = "syndicate_gib" - maxHealth = 30 - health = 30 - melee_damage_lower = 5 - melee_damage_upper = 5 + maxHealth = 50 + health = 50 + melee_damage_lower = 12.5 + melee_damage_upper = 12.5 + armour_penetration_percentage = 50 attacktext = "bashes against" attack_sound = 'sound/weapons/punch1.ogg' throw_message = "does nothing to the rocky hide of the" @@ -221,6 +222,7 @@ continue visible_message("[src] grabs hold of [L]!") L.Stun(1 SECONDS) + L.KnockDown(2.5 SECONDS) L.adjustBruteLoss(rand(20,25)) latched = TRUE if(!latched) diff --git a/code/modules/mob/living/simple_animal/hostile/mining/elites/herald.dm b/code/modules/mob/living/simple_animal/hostile/mining/elites/herald.dm index acbc2d139f8..82b2628b88c 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining/elites/herald.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining/elites/herald.dm @@ -28,6 +28,7 @@ health = 1000 melee_damage_lower = 20 melee_damage_upper = 20 + armour_penetration_percentage = 50 light_power = 5 light_range = 2 light_color = "#FF0000" @@ -151,7 +152,7 @@ var/target_turf = get_turf(target) var/angle_to_target = get_angle(src, target_turf) say("Pray") - SLEEP_CHECK_DEATH(0.75 SECONDS)// no point blank instant shotgun. + SLEEP_CHECK_DEATH(0.5 SECONDS)// no point blank instant shotgun. shoot_projectile(target_turf, angle_to_target, FALSE, TRUE) addtimer(CALLBACK(src, .proc/shoot_projectile, target_turf, angle_to_target, FALSE, TRUE), 0.2 SECONDS) if(health < maxHealth * 0.5 && !is_mirror) diff --git a/code/modules/mob/living/simple_animal/hostile/mining/elites/legionnaire.dm b/code/modules/mob/living/simple_animal/hostile/mining/elites/legionnaire.dm index 3b2ca1dcd62..705a720390c 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining/elites/legionnaire.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining/elites/legionnaire.dm @@ -28,6 +28,7 @@ health = 1000 melee_damage_lower = 35 melee_damage_upper = 35 + armour_penetration_percentage = 50 attacktext = "slashes its arms at" attack_sound = 'sound/weapons/bladeslice.ogg' throw_message = "doesn't affect the sturdiness of" @@ -66,7 +67,7 @@ /datum/action/innate/elite_attack/bonfire_teleport name = "Bonfire Teleport" button_icon_state = "bonfire_teleport" - chosen_message = "You will leave a bonfire. Second use will let you swap positions with it indefintiely. Using this move on the same tile as your active bonfire removes it." + chosen_message = "You will leave a bonfire. Second use will let you swap positions with it indefintiely. Using this move on the same tile as your active bonfire removes it." chosen_attack_num = BONFIRE_TELEPORT /datum/action/innate/elite_attack/spew_smoke @@ -129,7 +130,7 @@ visible_message("[src] prepares to charge!") addtimer(CALLBACK(src, .proc/legionnaire_charge_to, dir_to_target, 0), 4) -/mob/living/simple_animal/hostile/asteroid/elite/legionnaire/proc/legionnaire_charge_to(move_dir, times_ran) +/mob/living/simple_animal/hostile/asteroid/elite/legionnaire/proc/legionnaire_charge_to(move_dir, times_ran, list/hit_targets = list()) if(times_ran >= 6) charging = FALSE return @@ -147,21 +148,30 @@ if(D.density) charging = FALSE return + if(T.x > world.maxx - 2 || T.x < 2) //Keep them from runtiming + charging = FALSE + return + if(T.y > world.maxy - 2 || T.y < 2) + charging = FALSE + return forceMove(T) playsound(src,'sound/effects/bang.ogg', 200, 1) - var/list/hit_things = list() var/throwtarget = get_edge_target_turf(src, move_dir) - for(var/mob/living/L in T.contents - hit_things - src) + for(var/mob/living/L in T.contents - src) if(faction_check_mob(L)) charging = FALSE return - hit_things += L visible_message("[src] tramples and kicks [L]!") to_chat(L, "[src] tramples you and kicks you away!") L.throw_at(throwtarget, 10, 1, src) - L.KnockDown(1 SECONDS) - L.adjustBruteLoss(25) - addtimer(CALLBACK(src, .proc/legionnaire_charge_to, move_dir, (times_ran + 1)), 0.7) + L.Weaken(1 SECONDS) //Pain Train has no breaks. + if(L in hit_targets) + L.adjustBruteLoss(15) + else + hit_targets += L + L.adjustBruteLoss(25) + + addtimer(CALLBACK(src, .proc/legionnaire_charge_to, move_dir, (times_ran + 1), hit_targets), 0.7) /mob/living/simple_animal/hostile/asteroid/elite/legionnaire/proc/head_detach(target) ranged_cooldown = world.time + 1 SECONDS * revive_multiplier() @@ -222,7 +232,7 @@ mypile.forceMove(legionturf) /mob/living/simple_animal/hostile/asteroid/elite/legionnaire/proc/spew_smoke() - ranged_cooldown = world.time + 3 SECONDS * revive_multiplier() + ranged_cooldown = world.time + 2.5 SECONDS * revive_multiplier() var/smoke_location = null if(isnull(myhead)) smoke_location = src diff --git a/code/modules/mob/living/simple_animal/hostile/mining/elites/pandora.dm b/code/modules/mob/living/simple_animal/hostile/mining/elites/pandora.dm index 1ce5b17f993..8128d5b2fc1 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining/elites/pandora.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining/elites/pandora.dm @@ -30,6 +30,7 @@ health = 1000 melee_damage_lower = 15 melee_damage_upper = 15 + armour_penetration_percentage = 50 attacktext = "smashes into the side of" attack_sound = 'sound/weapons/sonic_jackhammer.ogg' throw_message = "merely dinks off of the"