From 924356965bff67b9dbc0f3397c7a473c94e4e140 Mon Sep 17 00:00:00 2001 From: atermonera Date: Wed, 7 Dec 2022 23:46:12 -0800 Subject: [PATCH 1/4] Turrets target mechs --- code/game/machinery/portable_turret.dm | 128 ++++++++++++++++++------- 1 file changed, 95 insertions(+), 33 deletions(-) diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm index 84e8edbc8e..4101f720e9 100644 --- a/code/game/machinery/portable_turret.dm +++ b/code/game/machinery/portable_turret.dm @@ -93,6 +93,7 @@ var/timeout = 10 // When a turret pops up, then finds nothing to shoot at, this number decrements until 0, when it pops down. var/can_salvage = TRUE // If false, salvaging doesn't give you anything. + /obj/machinery/porta_turret/crescent req_one_access = list(access_cent_specops) enabled = FALSE @@ -106,23 +107,27 @@ check_all = FALSE check_down = TRUE + /obj/machinery/porta_turret/can_catalogue(mob/user) // Dead turrets can't be scanned. if(stat & BROKEN) to_chat(user, span("warning", "\The [src] was destroyed, so it cannot be scanned.")) return FALSE return ..() + /obj/machinery/porta_turret/stationary ailock = TRUE lethal = TRUE installation = /obj/item/gun/energy/laser + /obj/machinery/porta_turret/stationary/syndie // Generic turrets for POIs that need to not shoot their buddies. req_one_access = list(access_syndicate) enabled = TRUE check_all = TRUE faction = "syndicate" // Make sure this equals the faction that the mobs in the POI have or they will fight each other. + /obj/machinery/porta_turret/ai_defense name = "defense turret" desc = "This variant appears to be much more durable." @@ -131,6 +136,7 @@ health = 250 // Since lasers do 40 each. maxhealth = 250 + /datum/category_item/catalogue/anomalous/precursor_a/alien_turret name = "Precursor Alpha Object - Turrets" desc = "An autonomous defense turret created by unknown ancient aliens. It utilizes an \ @@ -143,6 +149,7 @@ quirk of how they designed their electronics." value = CATALOGUER_REWARD_MEDIUM + /obj/machinery/porta_turret/alien // The kind used on the UFO submap. name = "interior anti-boarding turret" desc = "A very tough looking turret made by alien hands." @@ -158,6 +165,7 @@ maxhealth = 250 turret_type = "alien" + /obj/machinery/porta_turret/alien/destroyed // Turrets that are already dead, to act as a warning of what the rest of the submap contains. name = "broken interior anti-boarding turret" desc = "A very tough looking turret made by alien hands. This one looks destroyed, thankfully." @@ -165,6 +173,7 @@ stat = BROKEN can_salvage = FALSE // So you need to actually kill a turret to get the alien gun. + /obj/machinery/porta_turret/industrial name = "industrial turret" desc = "This variant appears to be much more rugged." @@ -175,6 +184,7 @@ maxhealth = 200 turret_type = "industrial" + /obj/machinery/porta_turret/industrial/bullet_act(obj/item/projectile/Proj) var/damage = round(Proj.get_structure_damage() * 1.33) @@ -190,9 +200,11 @@ take_damage(damage) + /obj/machinery/porta_turret/industrial/attack_generic(mob/living/L, damage) return ..(L, damage * 0.8) + /obj/machinery/porta_turret/industrial/teleport_defense name = "defense turret" desc = "This variant appears to be much more durable, with a rugged outer coating." @@ -201,6 +213,7 @@ health = 250 maxhealth = 250 + /obj/machinery/porta_turret/poi //These are always angry enabled = TRUE lethal = TRUE @@ -208,6 +221,7 @@ check_all = TRUE can_salvage = FALSE // So you can't just twoshot a turret and get a fancy gun + /obj/machinery/porta_turret/lasertag name = "lasertag turret" turret_type = "normal" @@ -228,16 +242,19 @@ check_all = FALSE check_down = FALSE + /obj/machinery/porta_turret/lasertag/red turret_type = "red" installation = /obj/item/gun/energy/lasertag/red check_weapons = TRUE // Used to target blue players + /obj/machinery/porta_turret/lasertag/blue turret_type = "blue" installation = /obj/item/gun/energy/lasertag/blue check_synth = TRUE // Used to target red players + /obj/machinery/porta_turret/lasertag/assess_living(var/mob/living/L) if(!ishuman(L)) return TURRET_NOT_TARGET @@ -262,6 +279,7 @@ if(istype(M.wear_suit, /obj/item/clothing/suit/bluetag) && check_weapons) // Checks if they are a blue player return TURRET_PRIORITY_TARGET + /obj/machinery/porta_turret/lasertag/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) var/data[0] data["access"] = !isLocked(user) @@ -283,6 +301,7 @@ ui.open() ui.set_auto_update(1) + /obj/machinery/porta_turret/lasertag/Topic(href, href_list) if(..()) return 1 @@ -300,6 +319,7 @@ return 1 + /obj/machinery/porta_turret/Initialize() //Sets up a spark system spark_system = new /datum/effect_system/spark_spread @@ -314,11 +334,13 @@ add_overlay(turret_opened_overlay) return ..() + /obj/machinery/porta_turret/Destroy() qdel(spark_system) spark_system = null return ..() + /obj/machinery/porta_turret/update_icon() if(stat & BROKEN) // Turret is dead. icon_state = "destroyed_target_prism_[turret_type]" @@ -370,6 +392,7 @@ weapon_setup(installation) + /obj/machinery/porta_turret/proc/weapon_setup(var/guntype) switch(guntype) if(/obj/item/gun/energy/gun/burst) @@ -401,6 +424,7 @@ lethal_shot_sound = 'sound/weapons/eluger.ogg' shot_sound = 'sound/weapons/Taser.ogg' + /obj/machinery/porta_turret/proc/isLocked(mob/user) if(ailock && issilicon(user)) to_chat(user, "There seems to be a firewall preventing you from accessing this device.") @@ -412,18 +436,21 @@ return 0 + /obj/machinery/porta_turret/attack_ai(mob/user) if(isLocked(user)) return ui_interact(user) + /obj/machinery/porta_turret/attack_hand(mob/user) if(isLocked(user)) return ui_interact(user) + /obj/machinery/porta_turret/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) var/data[0] data["access"] = !isLocked(user) @@ -451,10 +478,12 @@ ui.open() ui.set_auto_update(1) + /obj/machinery/porta_turret/proc/HasController() var/area/A = get_area(src) return A && A.turret_controls.len > 0 + /obj/machinery/porta_turret/CanUseTopic(var/mob/user) if(HasController()) to_chat(user, "Turrets can only be controlled using the assigned turret controller.") @@ -469,6 +498,7 @@ return ..() + /obj/machinery/porta_turret/Topic(href, href_list) if(..()) return 1 @@ -498,6 +528,7 @@ return 1 + /obj/machinery/porta_turret/power_change() if(powered()) stat &= ~NOPOWER @@ -581,6 +612,7 @@ attacked = 0 ..() + /obj/machinery/porta_turret/attack_generic(mob/living/L, damage) if(isanimal(L)) var/mob/living/simple_mob/S = L @@ -593,6 +625,7 @@ visible_message("\The [L] bonks \the [src]'s casing!") return ..() + /obj/machinery/porta_turret/emag_act(var/remaining_charges, var/mob/user) if(!emagged) //Emagging the turret makes it go bonkers and stun everyone. It also makes @@ -606,6 +639,7 @@ enabled = TRUE //turns it back on. The cover popUp() popDown() are automatically called in process(), no need to define it here return 1 + /obj/machinery/porta_turret/take_damage(var/force) if(!raised && !raising) force = force / 8 @@ -618,6 +652,7 @@ if(health <= 0) die() //the death process :( + /obj/machinery/porta_turret/bullet_act(obj/item/projectile/Proj) var/damage = Proj.get_structure_damage() @@ -635,6 +670,7 @@ take_damage(damage) + /obj/machinery/porta_turret/emp_act(severity) if(enabled) //if the turret is on, the EMP no matter how severe disables the turret for a while @@ -654,11 +690,13 @@ ..() + /obj/machinery/porta_turret/ai_defense/emp_act(severity) if(prob(33)) // One in three chance to resist an EMP. This is significant if an AoE EMP is involved against multiple turrets. return ..() + /obj/machinery/porta_turret/alien/emp_act(severity) // This is overrided to give an EMP resistance as well as avoid scambling the turret settings. if(prob(75)) // Superior alien technology, I guess. return @@ -667,6 +705,7 @@ if(!enabled) enabled = TRUE + /obj/machinery/porta_turret/ex_act(severity) switch (severity) if(1) @@ -679,12 +718,14 @@ if(3) take_damage(initial(health) * 8 / 3) //Level 4 is too weak to bother turrets + /obj/machinery/porta_turret/proc/die() //called when the turret dies, ie, health <= 0 health = 0 stat |= BROKEN //enables the BROKEN bit spark_system.start() //creates some sparks because they look cool update_icon() + /obj/machinery/porta_turret/process() //the main machinery process @@ -707,33 +748,32 @@ for(var/mob in living_mob_list) var/mob/M = mob - if(M.z != z) //Skip + if(M.z != z || !(get_turf(M) in seenturfs)) // Skip continue - if(get_turf(M) in seenturfs) - assess_and_assign(mob, targets, secondarytargets) + switch(assess_living(L)) + if(TURRET_PRIORITY_TARGET) + targets += L + if(TURRET_SECONDARY_TARGET) + secondarytargets += L - /* This was dumb. Why do this and then check line of sight later? - for(var/mob/M in mobs_in_xray_view(world.view, src)) - assess_and_assign(M, targets, secondarytargets) - */ + for(var/obj/mecha/M as anything in mechas_list) + if(M.z != z || !(get_turf(M) in seenturfs)) // Skip + continue + switch(assess_mecha(M)) + if(TURRET_PRIORITY_TARGET) + targets += L + if(TURRET_SECONDARY_TARGET) + secondarytargets += L - if(!tryToShootAt(targets)) - if(!tryToShootAt(secondarytargets)) // if no valid targets, go for secondary targets - timeout-- - if(timeout <= 0) - spawn() - popDown() // no valid targets, close the cover + if(!tryToShootAt(targets) && + !tryToShootAt(secondarytargets) && + --timeout <= 0) + popDown() // no valid targets, close the cover if(auto_repair && (health < maxhealth)) use_power(20000) health = min(health+1, maxhealth) // 1HP for 20kJ -/obj/machinery/porta_turret/proc/assess_and_assign(var/mob/living/L, var/list/targets, var/list/secondarytargets) - switch(assess_living(L)) - if(TURRET_PRIORITY_TARGET) - targets += L - if(TURRET_SECONDARY_TARGET) - secondarytargets += L /obj/machinery/porta_turret/proc/assess_living(var/mob/living/L) if(!istype(L)) @@ -742,9 +782,6 @@ if(L.invisibility >= INVISIBILITY_LEVEL_ONE) // Cannot see him. see_invisible is a mob-var return TURRET_NOT_TARGET - if(!L) - return TURRET_NOT_TARGET - if(faction && L.faction == faction) return TURRET_NOT_TARGET @@ -789,6 +826,17 @@ return TURRET_PRIORITY_TARGET //if the perp has passed all previous tests, congrats, it is now a "shoot-me!" nominee + +/obj/machinery/porta_turret/proc/assess_mecha(var/obj/mecha/M) + if(!istype(M)) + return TURRENT_NOT_TARGET + + if(!M.occupant) + return check_all ? TURRET_SECONDARY_TARGET : TURRET_NOT_TARGET + + return assess_living(M.occupant) + + /obj/machinery/porta_turret/proc/assess_perp(var/mob/living/carbon/human/H) if(!H || !istype(H)) return 0 @@ -798,6 +846,7 @@ return H.assess_perp(src, check_access, check_weapons, check_records, check_arrest) + /obj/machinery/porta_turret/proc/tryToShootAt(var/list/mob/living/targets) if(targets.len && last_target && (last_target in targets) && target(last_target)) return 1 @@ -810,6 +859,7 @@ /obj/machinery/porta_turret/proc/popUp() //pops the turret up + set waitfor = FALSE if(disabled) return if(raising || raised) @@ -830,7 +880,9 @@ update_icon() timeout = 10 + /obj/machinery/porta_turret/proc/popDown() //pops the turret down + set waitfor = FALSE last_target = null if(disabled) return @@ -852,24 +904,26 @@ update_icon() timeout = 10 + /obj/machinery/porta_turret/proc/set_raised_raising(var/incoming_raised, var/incoming_raising) raised = incoming_raised raising = incoming_raising density = raised || raising + /obj/machinery/porta_turret/proc/target(var/mob/living/target) if(disabled) - return + return FALSE if(target) last_target = target - spawn() - popUp() //pop the turret up if it's not already up. + popUp() //pop the turret up if it's not already up. set_dir(get_dir(src, target)) //even if you can't shoot, follow the target playsound(src, 'sound/machines/turrets/turret_rotate.ogg', 100, 1) // Play rotating sound spawn() shootAt(target) - return 1 - return + return TRUE + return FALSE + /obj/machinery/porta_turret/proc/shootAt(var/mob/living/target) //any emagged turrets will shoot extremely fast! This not only is deadly, but drains a lot power! @@ -881,9 +935,7 @@ sleep(shot_delay) last_fired = FALSE - var/turf/T = get_turf(src) - var/turf/U = get_turf(target) - if(!istype(T) || !istype(U)) + if(!isturf(get_turf(src)) || !isturf(get_turf(target))) return if(!raised) //the turret has to be raised in order to fire - makes sense, right? @@ -898,9 +950,12 @@ A = new projectile(loc) playsound(src, shot_sound, 75, 1) - // Lethal/emagged turrets use twice the power due to higher energy beams - // Emagged turrets again use twice as much power due to higher firing rates - use_power(reqpower * (2 * (emagged || lethal)) * (2 * emagged)) + var/power_mult = 1 + if(emagged) + power_mult = 4 // Lethal beams + higher rate of fire + else if(lethal) + power_mult = 2 // Lethal beams + use_power(reqpower * power_mult) //Turrets aim for the center of mass by default. //If the target is grabbing someone then the turret smartly aims for extremities @@ -919,6 +974,7 @@ // Reset the time needed to go back down, since we just tried to shoot at someone. timeout = 10 + /datum/turret_checks var/enabled var/lethal @@ -931,6 +987,7 @@ var/check_all var/ailock + /obj/machinery/porta_turret/proc/setState(var/datum/turret_checks/TC) if(controllock) return @@ -953,6 +1010,7 @@ Known as "turret frame"s */ + /obj/machinery/porta_turret_construct name = "turret frame" icon = 'icons/obj/turrets.dmi' @@ -964,6 +1022,7 @@ var/installation = null //the gun type installed var/gun_charge = 0 //the gun charge of the gun type installed + /obj/machinery/porta_turret_construct/attackby(obj/item/I, mob/user) //this is a bit unwieldy but self-explanatory switch(build_step) @@ -1127,6 +1186,7 @@ ..() + /obj/machinery/porta_turret_construct/attack_hand(mob/user) switch(build_step) if(4) @@ -1146,9 +1206,11 @@ new /obj/item/assembly/prox_sensor(loc) build_step = 4 + /obj/machinery/porta_turret_construct/attack_ai() return + /atom/movable/porta_turret_cover icon = 'icons/obj/turrets.dmi' From 9635a687f3019d9722467d427be87ed7ce82a081 Mon Sep 17 00:00:00 2001 From: atermonera Date: Thu, 8 Dec 2022 00:16:51 -0800 Subject: [PATCH 2/4] Blobs will try to attack mechs --- code/modules/blob2/overmind/powers.dm | 36 ++++++++++++++++----------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/code/modules/blob2/overmind/powers.dm b/code/modules/blob2/overmind/powers.dm index 9356645bbb..c958868de8 100644 --- a/code/modules/blob2/overmind/powers.dm +++ b/code/modules/blob2/overmind/powers.dm @@ -219,23 +219,31 @@ for(var/mob/living/L in view(src)) if(L.stat == DEAD) continue // Already dying or dead. - if(L.faction == blob_type.faction) - continue // No friendly fire. - if(locate(/obj/structure/blob) in L.loc) - continue // Already has a blob over them. + if(can_attack(L)) + potential_targets += L - var/obj/structure/blob/B = null - for(var/direction in cardinal) - var/turf/T = get_step(L, direction) - B = locate(/obj/structure/blob) in T - if(B && B.overmind == src) - break - if(!B) - continue - - potential_targets += L + for(var/obj/mecha/M in view(src)) + if(!M.occupant) + continue // Just a hunk of metal + if(can_attack(M.occupant)) + potential_targets += L if(potential_targets.len) var/mob/living/victim = pick(potential_targets) var/turf/T = get_turf(victim) expand_blob(T) + +/mob/observer/blob/proc/can_attack(var/mob/living/L) + if(!istype(L)) + return FALSE + if(L.faction == blob_type.faction) + return FALSE // No friendly fire. + if(locate(/obj/structure/blob) in get_turf(L)) + return FALSE // Already has a blob over them. + + for(var/direction in cardinal) + var/turf/T = get_step(L, direction) + var/obj/structure/blob/BB = locate(/obj/structure/blob) in T + if(B && B.overmind == src) + return TRUE + return FALSE From 9245b45bc2ca3f2ca7a54eb7ed8c31418cd5b8ee Mon Sep 17 00:00:00 2001 From: atermonera Date: Thu, 8 Dec 2022 21:11:50 -0800 Subject: [PATCH 3/4] B --- code/modules/blob2/overmind/powers.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/blob2/overmind/powers.dm b/code/modules/blob2/overmind/powers.dm index c958868de8..405910c810 100644 --- a/code/modules/blob2/overmind/powers.dm +++ b/code/modules/blob2/overmind/powers.dm @@ -243,7 +243,7 @@ for(var/direction in cardinal) var/turf/T = get_step(L, direction) - var/obj/structure/blob/BB = locate(/obj/structure/blob) in T + var/obj/structure/blob/B = locate(/obj/structure/blob) in T if(B && B.overmind == src) return TRUE return FALSE From 76c9ec8581b1ccad606c80a5c32196dfd5e54eb8 Mon Sep 17 00:00:00 2001 From: atermonera Date: Thu, 8 Dec 2022 22:02:50 -0800 Subject: [PATCH 4/4] compile errors --- code/game/machinery/portable_turret.dm | 19 +++++++++---------- code/modules/blob2/overmind/powers.dm | 2 +- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm index 4101f720e9..1c9dbcaceb 100644 --- a/code/game/machinery/portable_turret.dm +++ b/code/game/machinery/portable_turret.dm @@ -746,27 +746,26 @@ for(var/turf/T in oview(world.view, src)) seenturfs += T - for(var/mob in living_mob_list) - var/mob/M = mob + for(var/mob/M as anything in living_mob_list) if(M.z != z || !(get_turf(M) in seenturfs)) // Skip continue - switch(assess_living(L)) + switch(assess_living(M)) if(TURRET_PRIORITY_TARGET) - targets += L + targets += M if(TURRET_SECONDARY_TARGET) - secondarytargets += L + secondarytargets += M for(var/obj/mecha/M as anything in mechas_list) if(M.z != z || !(get_turf(M) in seenturfs)) // Skip continue switch(assess_mecha(M)) if(TURRET_PRIORITY_TARGET) - targets += L + targets += M if(TURRET_SECONDARY_TARGET) - secondarytargets += L + secondarytargets += M - if(!tryToShootAt(targets) && - !tryToShootAt(secondarytargets) && + if(!tryToShootAt(targets) && \ + !tryToShootAt(secondarytargets) && \ --timeout <= 0) popDown() // no valid targets, close the cover @@ -829,7 +828,7 @@ /obj/machinery/porta_turret/proc/assess_mecha(var/obj/mecha/M) if(!istype(M)) - return TURRENT_NOT_TARGET + return TURRET_NOT_TARGET if(!M.occupant) return check_all ? TURRET_SECONDARY_TARGET : TURRET_NOT_TARGET diff --git a/code/modules/blob2/overmind/powers.dm b/code/modules/blob2/overmind/powers.dm index 405910c810..ee7e2a884f 100644 --- a/code/modules/blob2/overmind/powers.dm +++ b/code/modules/blob2/overmind/powers.dm @@ -226,7 +226,7 @@ if(!M.occupant) continue // Just a hunk of metal if(can_attack(M.occupant)) - potential_targets += L + potential_targets += M if(potential_targets.len) var/mob/living/victim = pick(potential_targets)