diff --git a/aurorastation.dme b/aurorastation.dme index 213fb2d53a9..3de0e2d6bba 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -2110,6 +2110,7 @@ #include "code\modules\mob\living\simple_animal\hostile\giant_spider.dm" #include "code\modules\mob\living\simple_animal\hostile\hivebot.dm" #include "code\modules\mob\living\simple_animal\hostile\hostile.dm" +#include "code\modules\mob\living\simple_animal\hostile\icarus_drone.dm" #include "code\modules\mob\living\simple_animal\hostile\krampus.dm" #include "code\modules\mob\living\simple_animal\hostile\mimic.dm" #include "code\modules\mob\living\simple_animal\hostile\moghesfauna.dm" @@ -2129,7 +2130,6 @@ #include "code\modules\mob\living\simple_animal\hostile\commanded\ives.dm" #include "code\modules\mob\living\simple_animal\hostile\retaliate\cavern.dm" #include "code\modules\mob\living\simple_animal\hostile\retaliate\clown.dm" -#include "code\modules\mob\living\simple_animal\hostile\retaliate\drone.dm" #include "code\modules\mob\living\simple_animal\hostile\retaliate\retaliate.dm" #include "code\modules\modular_computers\laptop_vendor.dm" #include "code\modules\modular_computers\computers\modular_computer\core.dm" diff --git a/code/_helpers/areas.dm b/code/_helpers/areas.dm index fb6a515d7fa..20a0648ba06 100644 --- a/code/_helpers/areas.dm +++ b/code/_helpers/areas.dm @@ -81,7 +81,9 @@ . = (A.z in z_levels) /proc/is_station_area(var/area/A) - . = isStationLevel(A.z) + if(A.station_area) + return TRUE + return FALSE /proc/is_contact_area(var/area/A) . = isContactLevel(A.z) diff --git a/code/controllers/subsystems/mob.dm b/code/controllers/subsystems/mob.dm index 9f4c44b6600..82eed7035c4 100644 --- a/code/controllers/subsystems/mob.dm +++ b/code/controllers/subsystems/mob.dm @@ -46,7 +46,7 @@ /datum/controller/subsystem/mobs/Initialize() // Some setup work for the eat-types lists. mtl_synthetic = typecacheof(mtl_synthetic) + list( - /mob/living/simple_animal/hostile/retaliate/malf_drone = TRUE, + /mob/living/simple_animal/hostile/icarus_drone = TRUE, /mob/living/simple_animal/hostile/viscerator = TRUE, /mob/living/simple_animal/spiderbot = TRUE ) diff --git a/code/controllers/subsystems/traumas.dm b/code/controllers/subsystems/traumas.dm index 164006442d8..bd3743930b7 100644 --- a/code/controllers/subsystems/traumas.dm +++ b/code/controllers/subsystems/traumas.dm @@ -41,7 +41,7 @@ var/datum/controller/subsystem/traumas/SStraumas "security" = typecacheof(list(/mob/living/bot/secbot)), "lizards" = typecacheof(list(/mob/living/simple_animal/lizard)), "cats" = typecacheof(list(/mob/living/simple_animal/cat, /mob/living/simple_animal/familiar/pet/cat, /mob/living/simple_animal/cat/kitten)), - "robots" = typecacheof(list(/mob/living/silicon,/mob/living/bot, /mob/living/simple_animal/hostile/retaliate/malf_drone)), + "robots" = typecacheof(list(/mob/living/silicon,/mob/living/bot, /mob/living/simple_animal/hostile/icarus_drone)), "pests" = typecacheof(list(/mob/living/simple_animal/hostile/carp, /mob/living/simple_animal/rat, /mob/living/carbon/alien/diona)), "paranormals" = typecacheof(list(/mob/living/simple_animal/hostile/scarybat, /mob/living/simple_animal/hostile/true_changeling, /mob/living/simple_animal/hostile/mimic, /mob/living/simple_animal/hostile/faithless, diff --git a/code/datums/outfits/ert/deathsquad.dm b/code/datums/outfits/ert/deathsquad.dm index e01bcc220a2..01d0c44a1c5 100644 --- a/code/datums/outfits/ert/deathsquad.dm +++ b/code/datums/outfits/ert/deathsquad.dm @@ -29,6 +29,7 @@ name = "Asset Protection Lead" l_pocket = /obj/item/pinpointer + r_hand = /obj/item/device/orbital_dropper/icarus_drones /datum/outfit/admin/deathsquad/get_id_access() return get_all_accesses() diff --git a/code/datums/outfits/event/outfit_nanotrasen.dm b/code/datums/outfits/event/outfit_nanotrasen.dm index a47f0158d75..6719b02e691 100644 --- a/code/datums/outfits/event/outfit_nanotrasen.dm +++ b/code/datums/outfits/event/outfit_nanotrasen.dm @@ -25,7 +25,7 @@ uniform = /obj/item/clothing/under/rank/centcom_officer l_ear = /obj/item/device/radio/headset/heads/captain head = /obj/item/clothing/head/beret/centcom/officer - + l_pocket = /obj/item/device/orbital_dropper/icarus_drones /datum/outfit/admin/nt/captain name = "NanoTrasen Navy Captain" @@ -33,7 +33,7 @@ uniform = /obj/item/clothing/under/rank/centcom_captain l_ear = /obj/item/device/radio/headset/heads/captain head = /obj/item/clothing/head/beret/centcom/captain - + l_pocket = /obj/item/device/orbital_dropper/icarus_drones /datum/outfit/admin/nt/protection_detail name = "ERT Protection Detail" @@ -93,7 +93,8 @@ backpack_contents = list( /obj/item/storage/box/fancy/cigarettes/cigar = 1, - /obj/item/flame/lighter/zippo = 1 + /obj/item/flame/lighter/zippo = 1, + /obj/item/device/orbital_dropper/icarus_drones = 1 ) implants = list( diff --git a/code/game/jobs/access.dm b/code/game/jobs/access.dm index ddd511b5673..1a55e838f19 100644 --- a/code/game/jobs/access.dm +++ b/code/game/jobs/access.dm @@ -239,9 +239,9 @@ var/obj/item/card/id/all_access/ghost_all_access /mob/living/simple_animal/spiderbot/GetIdCard() return internal_id -/mob/living/carbon/human/GetIdCard() +/mob/living/carbon/human/GetIdCard(var/ignore_hand = FALSE) var/obj/item/I = get_active_hand() - if(I) + if(I && !ignore_hand) var/id = I.GetID() if(id) return id diff --git a/code/game/objects/items/devices/drop_targeter/_droptargeter.dm b/code/game/objects/items/devices/drop_targeter/_droptargeter.dm index fc7b57a073e..82b17b9a612 100644 --- a/code/game/objects/items/devices/drop_targeter/_droptargeter.dm +++ b/code/game/objects/items/devices/drop_targeter/_droptargeter.dm @@ -14,6 +14,7 @@ var/paint_distance = 14 // From how far away can you paint a target? + var/does_explosion = TRUE var/emagged = FALSE // If emagged, things can be dropped in on station areas var/drop_message = "Orbital package inbound, clear the targetted area immediately!" @@ -77,7 +78,8 @@ announcer.autosay(drop_message_emagged, announcer_name, "Common") has_dropped++ - addtimer(CALLBACK(GLOBAL_PROC, /proc/explosion, targloc, 1, 2, 4, 6), 100) //YEEHAW + if(does_explosion) + addtimer(CALLBACK(GLOBAL_PROC, /proc/explosion, targloc, 1, 2, 4, 6), 100) //YEEHAW addtimer(CALLBACK(src, .proc/orbital_drop, targloc, user), 105) flick_overlay(I, showto, 20) //2 seconds of the red dot appearing @@ -86,7 +88,7 @@ /obj/item/device/orbital_dropper/proc/orbital_drop(var/turf/target, var/user) if(!map) return - log_and_message_admins("[key_name_admin(src)] has used a [src] at JMP.") + log_and_message_admins("[key_name_admin(user)] has used a [src] at JMP.") map.load(target, TRUE) //Target must be the center! diff --git a/code/game/objects/items/devices/drop_targeter/orbital_drops.dm b/code/game/objects/items/devices/drop_targeter/orbital_drops.dm index 5bc9b9f0d30..e8af8cd020c 100644 --- a/code/game/objects/items/devices/drop_targeter/orbital_drops.dm +++ b/code/game/objects/items/devices/drop_targeter/orbital_drops.dm @@ -46,3 +46,23 @@ desc_antag = "This is a stealthy variant of the standard armory orbital drop. It will not report itself dropping on common, unless emagged." announcer_name = "Syndicate Autodrone" announcer_channel = "Mercenary" + +/obj/item/device/orbital_dropper/icarus_drones + name = "icarus painter" + desc = "A device used to paint a target, which will then promptly orbitally drop the requested items. This one has been modified to call in Icarus Drones." + + var/num_of_drones = 2 + drop_amount = 1 + does_explosion = FALSE + + emagged = TRUE // to let people drop it in the station + + drop_message_emagged = "NanoTrasen combat drones coming your way! Happy hunting!" + announcer_name = "NDV Icarus" + + map = null + +/obj/item/device/orbital_dropper/icarus_drones/orbital_drop(var/turf/target, var/user) + log_and_message_admins("[key_name_admin(user)] has used a [src] at JMP.") + for(var/i = 1, i <= num_of_drones, i++) + new /mob/living/simple_animal/hostile/icarus_drone(get_random_turf_in_range(target, 4, 2, TRUE)) \ No newline at end of file diff --git a/code/modules/events/carp_migration.dm b/code/modules/events/carp_migration.dm index 95c10e679dc..76aaaf6ebe5 100644 --- a/code/modules/events/carp_migration.dm +++ b/code/modules/events/carp_migration.dm @@ -15,29 +15,30 @@ /datum/event/carp_migration/setup() announceWhen = rand(40, 60) - endWhen = rand(600,1200) + endWhen = rand(600, 1200) despawn_turfs = typecacheof(despawn_turfs) /datum/event/carp_migration/announce() var/announcement = "" + var/soundfile = 'sound/AI/spacecarp.ogg' if(severity == EVENT_LEVEL_MAJOR) - announcement = "Massive migration of unknown biological entities has been detected near [station_name()], please stand-by." - command_announcement.Announce(announcement, "Lifesign Alert", new_sound = 'sound/AI/massivespacecarp.ogg') + announcement = "Massive migration of unknown biological entities has been detected near [station_name()], please stand-by. The NDV Icarus has dispatched combat drones to assist." + soundfile = 'sound/AI/massivespacecarp.ogg' else - announcement = "Unknown biological [spawned_carp.len == 1 ? "entity has" : "entities have"] been detected near [station_name()], please stand-by." - command_announcement.Announce(announcement, "Lifesign Alert", new_sound = 'sound/AI/spacecarp.ogg') + announcement = "Unknown biological [length(spawned_carp) == 1 ? "entity has" : "entities have"] been detected near [station_name()], please stand-by.[severity == EVENT_LEVEL_MODERATE ? " The NDV Icarus has dispatched combat drones to assist." : ""]" + command_announcement.Announce(announcement, "Lifesign Alert", new_sound = soundfile) /datum/event/carp_migration/start() if(severity == EVENT_LEVEL_MAJOR) - spawn_fish(landmarks_list.len) - spawn_caverndweller(landmarks_list.len) + spawn_fish(length(landmarks_list), spawn_drones = TRUE) + spawn_caverndweller(length(landmarks_list), spawn_drones = TRUE) else if(severity == EVENT_LEVEL_MODERATE) - spawn_fish(rand(4, 6)) //12 to 30 carp, in small groups - spawn_caverndweller(rand(1, 2)) //less of those, also don't happen in the regular event + spawn_fish(rand(4, 6), spawn_drones = TRUE) //12 to 30 carp, in small groups + spawn_caverndweller(rand(1, 2), spawn_drones = TRUE) //less of those, also don't happen in the regular event else spawn_fish(rand(1, 3), 1, 2) //1 to 6 carp, alone or in pairs -/datum/event/carp_migration/proc/spawn_fish(var/num_groups, var/group_size_min=3, var/group_size_max=5) +/datum/event/carp_migration/proc/spawn_fish(var/num_groups, var/group_size_min = 3, var/group_size_max = 5, var/spawn_drones = FALSE) set waitfor = FALSE var/list/spawn_locations = list() @@ -50,7 +51,11 @@ var/i = 1 while (i <= num_groups) var/group_size = rand(group_size_min, group_size_max) - for (var/j = 1, j <= group_size, j++) + if(spawn_drones && prob(25)) + var/drone_num = rand(1, 2) + for(var/d = 1, d <= drone_num, d++) + new /mob/living/simple_animal/hostile/icarus_drone(get_random_turf_in_range(spawn_locations[i], 10, 6, TRUE)) + for(var/j = 1, j <= group_size, j++) if(prob(95)) var/mob/living/simple_animal/hostile/carp/carp = new(spawn_locations[i]) spawned_carp += WEAKREF(carp) @@ -63,7 +68,7 @@ CHECK_TICK i++ -/datum/event/carp_migration/proc/spawn_caverndweller(var/num_groups, var/group_size_min=2, var/group_size_max=3) +/datum/event/carp_migration/proc/spawn_caverndweller(var/num_groups, var/group_size_min=2, var/group_size_max=3, var/spawn_drones = FALSE) set waitfor = FALSE var/list/spawn_locations = list() @@ -76,6 +81,10 @@ var/i = 1 while (i <= num_groups) var/group_size = rand(group_size_min, group_size_max) + if(spawn_drones && prob(25)) + var/drone_num = rand(1, 2) + for(var/d = 1, d <= drone_num, d++) + new /mob/living/simple_animal/hostile/icarus_drone(get_random_turf_in_range(spawn_locations[i], 10, 6, TRUE)) for (var/j in 1 to group_size) new /mob/living/simple_animal/hostile/retaliate/cavern_dweller(spawn_locations[i]) CHECK_TICK diff --git a/code/modules/events/false_alarm.dm b/code/modules/events/false_alarm.dm index d0951482d82..94e049e808b 100644 --- a/code/modules/events/false_alarm.dm +++ b/code/modules/events/false_alarm.dm @@ -47,7 +47,4 @@ E.start() E.kill() - E.announce() - - - + E.announce() \ No newline at end of file diff --git a/code/modules/events/rogue_drones.dm b/code/modules/events/rogue_drones.dm index 5ba18a589d1..16f4afc9d27 100644 --- a/code/modules/events/rogue_drones.dm +++ b/code/modules/events/rogue_drones.dm @@ -12,7 +12,7 @@ var/num = rand(2,10) for(var/i=0, i drones_list.len * 0.75) + if(num_recovered > length(drones_list) * 0.75) command_announcement.Announce("Icarus drone control reports the malfunctioning wing has been recovered safely.", "Rogue drone alert") else command_announcement.Announce("Icarus drone control registers disappointment at the loss of the drones, but the survivors have been recovered.", "Rogue drone alert") diff --git a/code/modules/mob/living/simple_animal/hostile/commanded/bear_companion.dm b/code/modules/mob/living/simple_animal/hostile/commanded/bear_companion.dm index 03518651095..50a3706b1eb 100644 --- a/code/modules/mob/living/simple_animal/hostile/commanded/bear_companion.dm +++ b/code/modules/mob/living/simple_animal/hostile/commanded/bear_companion.dm @@ -10,7 +10,8 @@ health = 100 maxHealth = 100 - density = 1 + density = TRUE + belongs_to_station = FALSE attacktext = "swatted" melee_damage_lower = 25 diff --git a/code/modules/mob/living/simple_animal/hostile/commanded/commanded.dm b/code/modules/mob/living/simple_animal/hostile/commanded/commanded.dm index 14974579ae0..93a7e069b36 100644 --- a/code/modules/mob/living/simple_animal/hostile/commanded/commanded.dm +++ b/code/modules/mob/living/simple_animal/hostile/commanded/commanded.dm @@ -3,7 +3,8 @@ stance = COMMANDED_STOP melee_damage_lower = 0 melee_damage_upper = 0 - density = 0 + density = FALSE + belongs_to_station = TRUE var/short_name = null var/list/command_buffer = list() var/list/known_commands = list("stay", "stop", "attack", "follow") diff --git a/code/modules/mob/living/simple_animal/hostile/commanded/ives.dm b/code/modules/mob/living/simple_animal/hostile/commanded/ives.dm index 119822afea2..b412bbebb62 100644 --- a/code/modules/mob/living/simple_animal/hostile/commanded/ives.dm +++ b/code/modules/mob/living/simple_animal/hostile/commanded/ives.dm @@ -10,6 +10,7 @@ health = 70 maxHealth = 70 + belongs_to_station = TRUE stop_automated_movement_when_pulled = TRUE density = TRUE diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index ab2e6725dd5..92399a1abdf 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -2,6 +2,7 @@ faction = "hostile" var/stance = HOSTILE_STANCE_IDLE //Used to determine behavior var/mob/living/target_mob + var/belongs_to_station = FALSE var/attack_same = 0 var/ranged = 0 var/rapid = 0 diff --git a/code/modules/mob/living/simple_animal/hostile/icarus_drone.dm b/code/modules/mob/living/simple_animal/hostile/icarus_drone.dm new file mode 100644 index 00000000000..23a965bb31c --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/icarus_drone.dm @@ -0,0 +1,358 @@ +/mob/living/simple_animal/hostile/icarus_drone + name = "combat drone" + desc = "An automated combat drone armed with state of the art weaponry and shielding. This one has the markings of the NDV Icarus on the side." + desc_fluff = "Produced by NanoTrasen, these combat drones are often carried and deployed by NDV Drone Carriers to protect local assets." + icon_state = "drone3" + icon_living = "drone3" + icon_dead = "drone_dead" + ranged = TRUE + rapid = TRUE + speak_chance = 5 + turns_per_move = 3 + response_help = "pokes" + response_disarm = "gently pushes aside" + response_harm = "hits" + speak = list("ALERT, Icarus Drone active and patrolling!", "Hostile entities in the area!", "Threat parameters nominal.", "Subsystems stable at combat level theta.") + emote_see = list("beeps menacingly", "whirrs threateningly", "scans its immediate vicinity") + attack_emote = "shifts its targetting vanes towards" + a_intent = I_HURT + stop_automated_movement_when_pulled = FALSE + health = 300 + maxHealth = 300 + speed = 8 + projectiletype = /obj/item/projectile/beam/drone + projectilesound = 'sound/weapons/laser3.ogg' + destroy_surroundings = 0 + var/datum/effect_system/ion_trail/ion_trail + belongs_to_station = TRUE + + //the drone randomly switches between these states when it's malfunctioning + var/hostile_drone = FALSE + // FALSE - retaliate, only attack enemies that attack it + // TRUE - hostile, attack everything that comes near + + var/turf/patrol_target + var/explode_chance = 1 + var/malfunctioning = FALSE + var/disabled = FALSE + var/exploding = FALSE + + //Drones aren't affected by atmos. + min_oxy = 0 + max_oxy = 0 + min_tox = 0 + max_tox = 0 + min_co2 = 0 + max_co2 = 0 + min_n2 = 0 + max_n2 = 0 + minbodytemp = 0 + + var/has_loot = TRUE + faction = "neutral" + + tameable = FALSE + + flying = TRUE + +/mob/living/simple_animal/hostile/icarus_drone/Initialize() + . = ..() + if(prob(5)) + projectiletype = /obj/item/projectile/beam/pulse/drone + projectilesound = 'sound/weapons/pulse2.ogg' + ion_trail = new(src) + ion_trail.start() + if(!malfunctioning) + addtimer(CALLBACK(src, .proc/beam_out), 15 MINUTES) + + // warp in effect + var/matrix/M = matrix() + M.Scale(0.1, 0.1) + animate(src, transform = M, time = 0.1, easing = LINEAR_EASING) + + spark(src, 3, alldirs) + + var/matrix/N = matrix() + N.Scale(1, 1) + animate(src, transform = N, time = 2, easing = SINE_EASING) + +/mob/living/simple_animal/hostile/icarus_drone/proc/beam_out() + if(malfunctioning) // if we somehow start malfunctioning after init, don't beam out + return + visible_message(SPAN_WARNING("\The [src] warps into nothingness!")) + + spark(src, 3, alldirs) + + var/matrix/M = matrix() + M.Scale(0.1, 0.1) + animate(src, transform = M, time = 2, easing = LINEAR_EASING) + + has_loot = FALSE + qdel(src) + +/mob/living/simple_animal/hostile/icarus_drone/examine(mob/user) + ..() + if(malfunctioning) + if(hostile_drone) + to_chat(user, SPAN_WARNING("It's completely lit up, and its targetting vanes are deployed.")) + else + to_chat(user, SPAN_WARNING("Most of its lights are off, and its targetting vanes are retracted.")) + +/mob/living/simple_animal/hostile/icarus_drone/do_animate_chat(var/message, var/datum/language/language, var/small, var/list/show_to, var/duration, var/list/message_override) + INVOKE_ASYNC(src, /atom/movable/proc/animate_chat, message, language, small, show_to, duration) + +/mob/living/simple_animal/hostile/icarus_drone/Allow_Spacemove(var/check_drift = 0) + return TRUE + +/mob/living/simple_animal/hostile/icarus_drone/validator_living(var/mob/living/L, var/atom/current) + if(malfunctioning) + return ..() + if(L.stat == DEAD) + return FALSE + if(ishuman(L)) + var/mob/living/carbon/human/H = L + var/obj/item/card/id/ID = H.GetIdCard(TRUE) + if(!ID) // can't identify, too risky, don't shoot + return FALSE + if(!H.handcuffed) // don't shoot cuffed people + var/datum/record/general/R = SSrecords.find_record("name", ID.registered_name) + if(istype(R) && istype(R.security) && R.security.criminal == "*Arrest*") // blast free criminals + return TRUE + return FALSE // generally, don't shoot humans + if(istype(L, /mob/living/simple_animal/hostile)) + var/mob/living/simple_animal/hostile/SA = L + if(SA.belongs_to_station) + return FALSE + return TRUE + return FALSE + +/mob/living/simple_animal/hostile/icarus_drone/validator_bot(var/obj/machinery/bot/B, var/atom/current) + if(malfunctioning) + return ..() + return FALSE + +/mob/living/simple_animal/hostile/icarus_drone/validator_turret(var/obj/machinery/porta_turret/T, var/atom/current) + if(malfunctioning) + return ..() + if(is_station_area(get_area(T))) // any turrets not on station turf is probably hostile + return FALSE + return TRUE + +/mob/living/simple_animal/hostile/icarus_drone/validator_e_field(var/obj/effect/energy_field/E, var/atom/current) + if(malfunctioning) + return ..() + return FALSE + +/mob/living/simple_animal/hostile/icarus_drone/isSynthetic() + return TRUE + +//self repair systems have a chance to bring the drone back to life +/mob/living/simple_animal/hostile/icarus_drone/Life() + //emps and lots of damage can temporarily shut us down + if(disabled > 0) + stat = UNCONSCIOUS + icon_state = "drone_dead" + disabled-- + wander = FALSE + speak_chance = 0 + else + stat = CONSCIOUS + icon_state = "drone0" + wander = TRUE + speak_chance = 5 + + //repair a bit of damage + if(prob(1) && health < maxHealth) + visible_message(SPAN_NOTICE("\The [src] shudders and shakes as some of its damaged systems come back online.")) + spark(src, 3, alldirs) + health += rand(25, 100) + + //spark for no reason + if(malfunctioning && prob(5)) + spark(src, 3, alldirs) + + //sometimes our targetting sensors malfunction, and we attack anyone nearby + if(malfunctioning && prob(disabled ? 0 : 1)) + if(hostile_drone) + src.visible_message(SPAN_NOTICE("\The [src] retracts several targetting vanes, and dulls its running lights.")) + hostile_drone = FALSE + else + src.visible_message(SPAN_ALERT("\The [src] suddenly lights up, and additional targetting vanes slide into place.")) + hostile_drone = TRUE + + if(health / maxHealth > 0.9) + icon_state = "drone3" + explode_chance = 0 + else if(health / maxHealth > 0.7) + icon_state = "drone2" + explode_chance = 0 + else if(health / maxHealth > 0.5) + icon_state = "drone1" + explode_chance = 0.5 + else if(health / maxHealth > 0.3) + icon_state = "drone0" + explode_chance = 5 + else if(health > 0) + //if health gets too low, shut down + icon_state = "drone_dead" + exploding = FALSE + if(!disabled) + if(prob(50)) + visible_message(SPAN_NOTICE("\The [src] suddenly shuts down!")) + else + visible_message(SPAN_NOTICE("\The [src] suddenly lies still and quiet.")) + disabled = rand(150, 600) + walk(src, 0) + + if(exploding && prob(20)) + if(prob(50)) + visible_message(SPAN_ALERT("\The [src] begins to spark and shake violently!")) + else + visible_message(SPAN_ALERT("\The [src] sparks and shakes like it's about to explode!")) + spark(src, 3, alldirs) + + if(!exploding && !disabled && prob(explode_chance)) + exploding = TRUE + stat = UNCONSCIOUS + wander = 1 + walk(src, 0) + spawn(rand(50, 150)) + if(!disabled && exploding) + explosion(get_turf(src), 0, 1, 4, 7) + ..() + +//ion rifle! +/mob/living/simple_animal/hostile/icarus_drone/emp_act(severity) + health -= rand(3, 15) * (severity + 1) + disabled = rand(150, 600) + hostile_drone = FALSE + walk(src, 0) + +/mob/living/simple_animal/hostile/icarus_drone/death() + ..(null, "suddenly breaks apart.") + qdel(src) + +/mob/living/simple_animal/hostile/icarus_drone/Destroy() + QDEL_NULL(ion_trail) + //some random debris left behind + if(has_loot) + spark(src, 3, alldirs) + var/obj/O + + //shards + O = new /obj/item/material/shard(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(75)) + O = new /obj/item/material/shard(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(50)) + O = new /obj/item/material/shard(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(25)) + O = new /obj/item/material/shard(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + + //rods + O = new /obj/item/stack/rods(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(75)) + O = new /obj/item/stack/rods(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(50)) + O = new /obj/item/stack/rods(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(25)) + O = new /obj/item/stack/rods(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + + //plasteel + O = new /obj/item/stack/material/plasteel(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(75)) + O = new /obj/item/stack/material/plasteel(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(50)) + O = new /obj/item/stack/material/plasteel(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(25)) + O = new /obj/item/stack/material/plasteel(src.loc) + step_to(O, get_turf(pick(view(7, src)))) + + //also drop dummy circuit boards deconstructable for research (loot) + var/obj/item/circuitboard/C + + //spawn 1-4 boards of a random type + var/spawnees = 0 + var/num_boards = rand(1, 4) + var/list/options = list(1, 2, 4, 8, 16, 32, 64, 128, 256) + if(malfunctioning) + options += 512 + for(var/i = 0, i < num_boards, i++) + var/chosen = pick(options) + options.Remove(options.Find(chosen)) + spawnees |= chosen + + if(spawnees & 1) + C = new(src.loc) + C.name = "drone CPU motherboard" + C.origin_tech = list(TECH_DATA = rand(3, 6)) + + if(spawnees & 2) + C = new(src.loc) + C.name = "drone neural interface" + C.origin_tech = list(TECH_BIO = rand(3,6)) + + if(spawnees & 4) + C = new(src.loc) + C.name = "drone suspension processor" + C.origin_tech = list(TECH_MAGNET = rand(3,6)) + + if(spawnees & 8) + C = new(src.loc) + C.name = "drone shielding controller" + C.origin_tech = list(TECH_BLUESPACE = rand(3,6)) + + if(spawnees & 16) + C = new(src.loc) + C.name = "drone power capacitor" + C.origin_tech = list(TECH_POWER = rand(3,6)) + + if(spawnees & 32) + C = new(src.loc) + C.name = "drone hull reinforcer" + C.origin_tech = list(TECH_MATERIAL = rand(3,6)) + + if(spawnees & 64) + C = new(src.loc) + C.name = "Drone auto-repair system" + C.origin_tech = list(TECH_ENGINEERING = rand(3,6)) + + if(spawnees & 128) + C = new(src.loc) + C.name = "drone phoron overcharge counter" + C.origin_tech = list(TECH_PHORON = rand(3,6)) + + if(spawnees & 256) + C = new(src.loc) + C.name = "drone targetting circuitboard" + C.origin_tech = list(TECH_COMBAT = rand(3,6)) + + if(spawnees & 512) + C = new(src.loc) + C.name = "corrupted drone morality core" + C.origin_tech = list(TECH_ILLEGAL = rand(3,6)) + + return ..() + +/obj/item/projectile/beam/drone + damage = 15 + +/obj/item/projectile/beam/pulse/drone + damage = 10 + +/mob/living/simple_animal/hostile/icarus_drone/malf + speak = list("ALERT.", "Hostile-ile-ile entities dee-twhoooo-wected.", "Threat parameterszzzz- szzet.", "Bring sub-sub-sub-systems uuuup to combat alert alpha-a-a.") + emote_see = list("beeps menacingly", "whirrs threateningly", "scans its immediate vicinity") + belongs_to_station = FALSE + malfunctioning = TRUE + faction = "malf_drone" \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm deleted file mode 100644 index 484117b99af..00000000000 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm +++ /dev/null @@ -1,283 +0,0 @@ - -//malfunctioning combat drones -/mob/living/simple_animal/hostile/retaliate/malf_drone - name = "combat drone" - desc = "An automated combat drone armed with state of the art weaponry and shielding." - icon_state = "drone3" - icon_living = "drone3" - icon_dead = "drone_dead" - ranged = 1 - rapid = 1 - speak_chance = 5 - turns_per_move = 3 - response_help = "pokes" - response_disarm = "gently pushes aside" - response_harm = "hits" - speak = list("ALERT.","Hostile-ile-ile entities dee-twhoooo-wected.","Threat parameterszzzz- szzet.","Bring sub-sub-sub-systems uuuup to combat alert alpha-a-a.") - emote_see = list("beeps menacingly","whirrs threateningly","scans its immediate vicinity") - a_intent = I_HURT - stop_automated_movement_when_pulled = 0 - health = 300 - maxHealth = 300 - speed = 8 - projectiletype = /obj/item/projectile/beam/drone - projectilesound = 'sound/weapons/laser3.ogg' - destroy_surroundings = 0 - var/datum/effect_system/ion_trail/ion_trail - - //the drone randomly switches between these states because it's malfunctioning - var/hostile_drone = 0 - //0 - retaliate, only attack enemies that attack it - //1 - hostile, attack everything that comes near - - var/turf/patrol_target - var/explode_chance = 1 - var/disabled = 0 - var/exploding = 0 - - //Drones aren't affected by atmos. - min_oxy = 0 - max_oxy = 0 - min_tox = 0 - max_tox = 0 - min_co2 = 0 - max_co2 = 0 - min_n2 = 0 - max_n2 = 0 - minbodytemp = 0 - - var/has_loot = 1 - faction = "malf_drone" - - tameable = FALSE - - flying = TRUE - smart = TRUE - -/mob/living/simple_animal/hostile/retaliate/malf_drone/Initialize() - . = ..() - if(prob(5)) - projectiletype = /obj/item/projectile/beam/pulse/drone - projectilesound = 'sound/weapons/pulse2.ogg' - ion_trail = new(src) - ion_trail.start() - -/mob/living/simple_animal/hostile/retaliate/malf_drone/do_animate_chat(var/message, var/datum/language/language, var/small, var/list/show_to, var/duration, var/list/message_override) - INVOKE_ASYNC(src, /atom/movable/proc/animate_chat, message, language, small, show_to, duration) - -/mob/living/simple_animal/hostile/retaliate/malf_drone/Allow_Spacemove(var/check_drift = 0) - return 1 - -/mob/living/simple_animal/hostile/retaliate/malf_drone/ListTargets() - if(hostile_drone) - return view(src, 10) - else - return ..() - -/mob/living/simple_animal/hostile/retaliate/malf_drone/isSynthetic() - return TRUE - -//self repair systems have a chance to bring the drone back to life -/mob/living/simple_animal/hostile/retaliate/malf_drone/Life() - - //emps and lots of damage can temporarily shut us down - if(disabled > 0) - stat = UNCONSCIOUS - icon_state = "drone_dead" - disabled-- - wander = 0 - speak_chance = 0 - if(disabled <= 0) - stat = CONSCIOUS - icon_state = "drone0" - wander = 1 - speak_chance = 5 - - //repair a bit of damage - if(prob(1)) - src.visible_message(SPAN_WARNING("\The [src] shudders and shakes as some of its damaged systems come back online.")) - spark(src, 3, alldirs) - health += rand(25,100) - - //spark for no reason - if(prob(5)) - spark(src, 3, alldirs) - - //sometimes our targetting sensors malfunction, and we attack anyone nearby - if(prob(disabled ? 0 : 1)) - if(hostile_drone) - src.visible_message(SPAN_NOTICE("\The [src] retracts several targetting vanes, and dulls its running lights.")) - hostile_drone = 0 - else - src.visible_message(SPAN_WARNING("\The [src] suddenly lights up, and additional targetting vanes slide into place.")) - hostile_drone = 1 - - if(health / maxHealth > 0.9) - icon_state = "drone3" - explode_chance = 0 - else if(health / maxHealth > 0.7) - icon_state = "drone2" - explode_chance = 0 - else if(health / maxHealth > 0.5) - icon_state = "drone1" - explode_chance = 0.5 - else if(health / maxHealth > 0.3) - icon_state = "drone0" - explode_chance = 5 - else if(health > 0) - //if health gets too low, shut down - icon_state = "drone_dead" - exploding = 0 - if(!disabled) - if(prob(50)) - src.visible_message(SPAN_NOTICE("\The [src] suddenly shuts down!")) - else - src.visible_message(SPAN_NOTICE("\The [src] suddenly lies still and quiet.")) - disabled = rand(150, 600) - walk(src,0) - - if(exploding && prob(20)) - if(prob(50)) - src.visible_message(SPAN_WARNING("\The [src] begins to spark and shake violenty!")) - else - src.visible_message(SPAN_WARNING("\The [src] sparks and shakes like it's about to explode!")) - - spark(src, 3, alldirs) - - if(!exploding && !disabled && prob(explode_chance)) - exploding = 1 - stat = UNCONSCIOUS - wander = 1 - walk(src,0) - spawn(rand(50,150)) - if(!disabled && exploding) - explosion(get_turf(src), 0, 1, 4, 7) - //proc/explosion(turf/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog = 1) - ..() - -//ion rifle! -/mob/living/simple_animal/hostile/retaliate/malf_drone/emp_act(severity) - health -= rand(3,15) * (severity + 1) - disabled = rand(150, 600) - hostile_drone = 0 - walk(src,0) - -/mob/living/simple_animal/hostile/retaliate/malf_drone/death() - ..(null,"suddenly breaks apart.") - qdel(src) - -/mob/living/simple_animal/hostile/retaliate/malf_drone/Destroy() - QDEL_NULL(ion_trail) - //some random debris left behind - if(has_loot) - spark(src, 3, alldirs) - var/obj/O - - //shards - O = new /obj/item/material/shard(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(75)) - O = new /obj/item/material/shard(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(50)) - O = new /obj/item/material/shard(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(25)) - O = new /obj/item/material/shard(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - - //rods - O = new /obj/item/stack/rods(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(75)) - O = new /obj/item/stack/rods(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(50)) - O = new /obj/item/stack/rods(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(25)) - O = new /obj/item/stack/rods(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - - //plasteel - O = new /obj/item/stack/material/plasteel(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(75)) - O = new /obj/item/stack/material/plasteel(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(50)) - O = new /obj/item/stack/material/plasteel(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(25)) - O = new /obj/item/stack/material/plasteel(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - - //also drop dummy circuit boards deconstructable for research (loot) - var/obj/item/circuitboard/C - - //spawn 1-4 boards of a random type - var/spawnees = 0 - var/num_boards = rand(1,4) - var/list/options = list(1,2,4,8,16,32,64,128,256,512) - for(var/i=0, i