From fdafaf39b5085dca628f08c746e28eff8a538d3d Mon Sep 17 00:00:00 2001 From: LordFowl Date: Wed, 4 Jan 2017 17:06:44 -0500 Subject: [PATCH] BayMerge DLC Pack (#1355) Ports totally; https://github.com/Baystation12/Baystation12/pull/12389/files Baystation12#14599 Ports partially; Baystation12#14216 (only blob-related functions) All the failure messages have been replaced with failure events in industrial drills, that range from probably lethal to certainly lethal and in one case just moderately annoying. --- .../objects/effects/spawners/gibspawner.dm | 78 +++++-- .../circuitboards/machinery/mining_drill.dm | 11 +- .../items/weapons/grenades/fragmentation.dm | 60 +++-- code/modules/blob/blob.dm | 209 +++++++++++++----- code/modules/clothing/clothing.dm | 7 +- code/modules/events/event.dm | 3 + code/modules/events/false_alarm.dm | 7 +- code/modules/events/radiation_storm.dm | 1 + code/modules/mining/drilling/drill.dm | 131 +++++++++-- code/modules/mob/hear_say.dm | 10 +- .../modules/mob/living/silicon/robot/robot.dm | 18 +- .../projectiles/guns/energy/special.dm | 10 +- code/modules/research/designs.dm | 14 ++ html/changelogs/LordFowl - PR 3113912125.yml | 38 ++++ icons/turf/flooring/asteroid.dmi | Bin 4945 -> 6225 bytes 15 files changed, 439 insertions(+), 158 deletions(-) create mode 100644 html/changelogs/LordFowl - PR 3113912125.yml diff --git a/code/game/objects/effects/spawners/gibspawner.dm b/code/game/objects/effects/spawners/gibspawner.dm index b145b77ed2e..3984c272384 100644 --- a/code/game/objects/effects/spawners/gibspawner.dm +++ b/code/game/objects/effects/spawners/gibspawner.dm @@ -1,27 +1,61 @@ -/obj/effect/gibspawner - generic - gibtypes = list(/obj/effect/decal/cleanable/blood/gibs,/obj/effect/decal/cleanable/blood/gibs,/obj/effect/decal/cleanable/blood/gibs/core) - gibamounts = list(2,2,1) +/obj/effect/gibspawner/generic + gibtypes = list( + /obj/effect/decal/cleanable/blood/gibs, + /obj/effect/decal/cleanable/blood/gibs, + /obj/effect/decal/cleanable/blood/gibs/core + ) + gibamounts = list(2,2,1) - New() - gibdirections = list(list(WEST, NORTHWEST, SOUTHWEST, NORTH),list(EAST, NORTHEAST, SOUTHEAST, SOUTH), list()) - ..() +/obj/effect/gibspawner/generic/New() + gibdirections = list(list(WEST, NORTHWEST, SOUTHWEST, NORTH),list(EAST, NORTHEAST, SOUTHEAST, SOUTH), list()) + ..() - human - gibtypes = list(/obj/effect/decal/cleanable/blood/gibs,/obj/effect/decal/cleanable/blood/gibs/down,/obj/effect/decal/cleanable/blood/gibs,/obj/effect/decal/cleanable/blood/gibs,/obj/effect/decal/cleanable/blood/gibs,/obj/effect/decal/cleanable/blood/gibs,/obj/effect/decal/cleanable/blood/gibs/core) - gibamounts = list(1,1,1,1,1,1,1) +/obj/effect/gibspawner/human + gibtypes = list( + /obj/effect/decal/cleanable/blood/gibs, + /obj/effect/decal/cleanable/blood/gibs/down, + /obj/effect/decal/cleanable/blood/gibs, + /obj/effect/decal/cleanable/blood/gibs, + /obj/effect/decal/cleanable/blood/gibs, + /obj/effect/decal/cleanable/blood/gibs, + /obj/effect/decal/cleanable/blood/gibs/core) + gibamounts = list(1,1,1,1,1,1,1) - New() - gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), alldirs, alldirs, list()) - gibamounts[6] = pick(0,1,2) - ..() +/obj/effect/gibspawner/human/New() + gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), alldirs, alldirs, list()) + gibamounts[6] = pick(0,1,2) + ..() - robot - sparks = 1 - gibtypes = list(/obj/effect/decal/cleanable/blood/gibs/robot/up,/obj/effect/decal/cleanable/blood/gibs/robot/down,/obj/effect/decal/cleanable/blood/gibs/robot,/obj/effect/decal/cleanable/blood/gibs/robot,/obj/effect/decal/cleanable/blood/gibs/robot,/obj/effect/decal/cleanable/blood/gibs/robot/limb) - gibamounts = list(1,1,1,1,1,1) +/obj/effect/gibspawner/robot + sparks = 1 + gibtypes = list( + /obj/effect/decal/cleanable/blood/gibs/robot/up, + /obj/effect/decal/cleanable/blood/gibs/robot/down, + /obj/effect/decal/cleanable/blood/gibs/robot, + /obj/effect/decal/cleanable/blood/gibs/robot, + /obj/effect/decal/cleanable/blood/gibs/robot, + /obj/effect/decal/cleanable/blood/gibs/robot/limb + ) + gibamounts = list(1,1,1,1,1,1) - New() - gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), alldirs, alldirs) - gibamounts[6] = pick(0,1,2) - ..() \ No newline at end of file +/obj/effect/gibspawner/robot/New() + gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), alldirs, alldirs) + gibamounts[6] = pick(0,1,2) + ..() + +/obj/effect/gibspawner/xeno + gibtypes = list( + /obj/effect/decal/cleanable/blood/gibs/xeno, + /obj/effect/decal/cleanable/blood/gibs/xeno/up, + /obj/effect/decal/cleanable/blood/gibs/xeno, + /obj/effect/decal/cleanable/blood/gibs/xeno, + /obj/effect/decal/cleanable/blood/gibs/xeno, + /obj/effect/decal/cleanable/blood/gibs/xeno, + /obj/effect/decal/cleanable/blood/gibs/xeno/core + ) + gibamounts = list(1,1,1,1,1,1,1) + +/obj/effect/gibspawner/xeno/New() + gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), alldirs, alldirs, list()) + gibamounts[6] = pick(0,1,2) + ..() \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/machinery/mining_drill.dm b/code/game/objects/items/weapons/circuitboards/machinery/mining_drill.dm index 426ced89da6..c3c6147734b 100644 --- a/code/game/objects/items/weapons/circuitboards/machinery/mining_drill.dm +++ b/code/game/objects/items/weapons/circuitboards/machinery/mining_drill.dm @@ -1,5 +1,5 @@ #ifndef T_BOARD -#error T_BOARD macro is not defined but we need it! +#error T_BOARD macro is not defined but we need it! #endif /obj/item/weapon/circuitboard/miningdrill @@ -11,4 +11,11 @@ "/obj/item/weapon/stock_parts/capacitor" = 1, "/obj/item/weapon/cell" = 1, "/obj/item/weapon/stock_parts/matter_bin" = 1, - "/obj/item/weapon/stock_parts/micro_laser" = 1) \ No newline at end of file + "/obj/item/weapon/stock_parts/micro_laser" = 1) + +/obj/item/weapon/circuitboard/miningdrillbrace + name = T_BOARD("mining drill brace") + build_path = "/obj/machinery/mining/brace" + board_type = "machine" + origin_tech = list(TECH_DATA = 1, TECH_ENGINEERING = 1) + req_components = list() \ No newline at end of file diff --git a/code/game/objects/items/weapons/grenades/fragmentation.dm b/code/game/objects/items/weapons/grenades/fragmentation.dm index 930093ef37b..7ffc48c5ee1 100644 --- a/code/game/objects/items/weapons/grenades/fragmentation.dm +++ b/code/game/objects/items/weapons/grenades/fragmentation.dm @@ -1,3 +1,31 @@ +proc/fragem(var/source,var/fragx,var/fragy,var/light_dam,var/flash_dam,var/p_dam,var/p_range,var/can_cover=1) + var/turf/O = get_turf(source) + var/fragger = rand(fragx,fragy) + explosion(O, -1, -1, light_dam, flash_dam) + var/list/target_turfs = getcircle(O, 7) + var/fragments_per_projectile = round(fragger/target_turfs.len) + + for(var/turf/T in target_turfs) + sleep(0) + var/obj/item/projectile/bullet/pellet/fragment/P = new (O) + + P.damage = p_dam + P.pellets = fragments_per_projectile + P.range_step = p_range + P.shot_from = source + P.name = "[source]'s shrapnel" + + P.launch(T) + + if(can_cover) + for(var/mob/living/M in O) + //lying on a frag grenade while the grenade is on the ground causes you to absorb most of the shrapnel. + //you will most likely be dead, but others nearby will be spared the fragments that hit you instead. + if(M.lying && isturf(get_turf(source))) + P.attack_mob(M, 0, 0) + else + P.attack_mob(M, 0, 100) //otherwise, allow a decent amount of fragments to pass + //Fragmentation grenade projectile /obj/item/projectile/bullet/pellet/fragment damage = 15 @@ -27,36 +55,6 @@ set waitfor = 0 ..() - var/turf/O = get_turf(src) - if(!O) return - - if(explosion_size) - explosion(O, -1, -1, explosion_size, explosion_size+1) - - var/list/target_turfs = getcircle(O, spread_range) - var/fragments_per_projectile = round(num_fragments/target_turfs.len) - - for(var/turf/T in target_turfs) - sleep(0) - var/obj/item/projectile/bullet/pellet/fragment/P = new (O) - - P.damage = fragment_damage - P.pellets = fragments_per_projectile - P.range_step = damage_step - P.shot_from = src.name - - P.launch(T) - - //var/cone = new /obj/item/weapon/caution/cone (T) - //spawn(100) qdel(cone) - - //Make sure to hit any mobs in the source turf - for(var/mob/living/M in O) - //lying on a frag grenade while the grenade is on the ground causes you to absorb most of the shrapnel. - //you will most likely be dead, but others nearby will be spared the fragments that hit you instead. - if(M.lying && isturf(src.loc)) - P.attack_mob(M, 0, 0) - else - P.attack_mob(M, 0, 100) //otherwise, allow a decent amount of fragments to pass + fragem(src,num_fragments,num_fragments,explosion_size,explosion_size+1,fragment_damage,damage_step,1) qdel(src) diff --git a/code/modules/blob/blob.dm b/code/modules/blob/blob.dm index ee7f89d5256..397b051c341 100644 --- a/code/modules/blob/blob.dm +++ b/code/modules/blob/blob.dm @@ -4,23 +4,87 @@ icon = 'icons/mob/blob.dmi' icon_state = "blob" light_range = 3 + light_color = "#b5ff5b" desc = "Some blob creature thingy" density = 1 opacity = 0 anchored = 1 mouse_opacity = 2 + layer = 4 var/maxHealth = 30 var/health + var/regen_rate = 5 var/brute_resist = 4 + var/laser_resist = 4 // Special resist for laser based weapons - Emitters or handheld energy weaponry. Damage is divided by this and THEN by fire_resist. var/fire_resist = 1 + var/secondary_core_growth_chance = 10.0 //% chance to grow a secondary blob core instead of whatever was suposed to grown. Secondary cores are considerably weaker, but still nasty. var/expandType = /obj/effect/blob + var/obj/effect/blob/core/parent_core = null + var/growth_range = 0 + var/blob_may_process = 1 + var/hangry = 0 //if the blob will attack or not. /obj/effect/blob/New(loc) + processing_objects.Add(src) health = maxHealth update_icon() return ..(loc) +/obj/effect/blob/Destroy() + processing_objects.Remove(src) + ..() + +/obj/effect/blob/process() + if(!parent_core) + src.take_damage(5) + src.regen_rate = -5 + src.growth_range = 0 + playsound(loc, 'sound/effects/splat.ogg', 50, 1) + return + + if(prob(70)) + for(var/mob/living/L in src.loc) + if(L.stat == DEAD) + if(prob(10)) + L.gib() + if(health < maxHealth) + health += rand(10,30) + if(health > maxHealth) + health = maxHealth + continue + L.visible_message("The blob absorbs \the [L]!", "The blob absorbs you!") + playsound(loc, 'sound/effects/attackblob.ogg', 50, 1) + L.take_organ_damage(rand(5, 10)) + if(health < maxHealth) + health += rand(1,10) + if(health > maxHealth) + health = maxHealth + hangry += 16 + + for(var/mob/living/L in range(src,"3x3")) + if(!hangry) + if(L.stat == DEAD) + continue + if(prob(40)) + L.visible_message("The blob sucks \the [L] into itself!", "The blob sucks you in!") + playsound(loc, 'sound/effects/attackblob.ogg', 50, 1) + L.take_organ_damage(rand(5, 10)) + L.forceMove(src.loc) + else + L.visible_message("The blob glomps \the [L]!", "The blob glomps you!") + playsound(loc, 'sound/effects/attackblob.ogg', 50, 1) + L.take_organ_damage(rand(5, 20)) + if(health < maxHealth) + health += rand(1,10) + if(health > maxHealth) + health = maxHealth + hangry += 4 + + hangry -= 1 + if(hangry < 0) + hangry = 0 + /obj/effect/blob/CanPass(var/atom/movable/mover, vra/turf/target, var/height = 0, var/air_group = 0) if(air_group || height == 0) return 1 @@ -50,7 +114,7 @@ update_icon() /obj/effect/blob/proc/regen() - health = min(health + 1, maxHealth) + health = min(health + regen_rate, maxHealth) update_icon() /obj/effect/blob/proc/expand(var/turf/T) @@ -58,66 +122,51 @@ return if(istype(T, /turf/simulated/wall)) var/turf/simulated/wall/SW = T - SW.take_damage(80) - return - var/obj/structure/girder/G = locate() in T - if(G) - if(prob(40)) - G.dismantle() - return - var/obj/structure/window/W = locate() in T - if(W) - W.shatter() - return - var/obj/structure/grille/GR = locate() in T - if(GR) - qdel(GR) - return - for(var/obj/machinery/door/D in T) // There can be several - and some of them can be open, locate() is not suitable - if(D.density) - D.ex_act(2) - return - var/obj/structure/foamedmetal/F = locate() in T - if(F) - qdel(F) - return - var/obj/structure/inflatable/I = locate() in T - if(I) - I.deflate(1) + SW.ex_act(2) return - var/obj/vehicle/V = locate() in T - if(V) - V.ex_act(2) - return - var/obj/machinery/bot/B = locate() in T - if(B) - B.ex_act(2) - return - var/obj/mecha/M = locate() in T - if(M) - M.visible_message("The blob attacks \the [M]!") - M.take_damage(40) - return + for(var/obj/O in T) + if(O.density) + O.ex_act(2) + return // Above things, we destroy completely and thus can use locate. Mobs are different. for(var/mob/living/L in T) if(L.stat == DEAD) continue - L.visible_message("The blob attacks \the [L]!", "The blob attacks you!") - playsound(loc, 'sound/effects/attackblob.ogg', 50, 1) - L.take_organ_damage(rand(30, 40)) + if(prob(30)) + L.visible_message("The blob sucks \the [L] into itself!", "The blob sucks you in!") + playsound(loc, 'sound/effects/attackblob.ogg', 50, 1) + L.take_organ_damage(rand(5, 10)) + L.forceMove(src.loc) + else + L.visible_message("The blob pulverizes \the [L]!", "The blob pulverizes you!") + playsound(loc, 'sound/effects/attackblob.ogg', 50, 1) + L.take_organ_damage(rand(30, 40)) + if(health < maxHealth) + health += rand(1,10) + if(health > maxHealth) + health = maxHealth return - new expandType(T, min(health, 30)) + + if(parent_core) + if(get_dist(T,src) <= parent_core.growth_range) + if(!(locate(/obj/effect/blob/core/) in range(T, 2)) && prob(secondary_core_growth_chance) && (parent_core.core_count < parent_core.core_limit)) + var/obj/effect/blob/core/secondary/S = new /obj/effect/blob/core/secondary(T) + S.parent_core = src.parent_core + src.parent_core.core_count += 1 + else + var/obj/effect/blob/C = new expandType(T) + C.parent_core = src.parent_core /obj/effect/blob/proc/pulse(var/forceLeft, var/list/dirs) regen() - sleep(5) + sleep(4) var/pushDir = pick(dirs) var/turf/T = get_step(src, pushDir) var/obj/effect/blob/B = (locate() in T) if(!B) - if(prob(health)) + if(prob(health+60)) expand(T) return if(forceLeft) @@ -131,11 +180,12 @@ if(BRUTE) take_damage(Proj.damage / brute_resist) if(BURN) - take_damage(Proj.damage / fire_resist) + take_damage((Proj.damage / laser_resist) / fire_resist) return 0 /obj/effect/blob/attackby(var/obj/item/weapon/W, var/mob/user) user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.do_attack_animation(src) playsound(loc, 'sound/effects/attackblob.ogg', 50, 1) visible_message("\The [src] has been attacked with \the [W][(user ? " by [user]." : ".")]") var/damage = 0 @@ -145,6 +195,11 @@ if(istype(W, /obj/item/weapon/weldingtool)) playsound(loc, 'sound/items/Welder.ogg', 100, 1) if("brute") + if(prob(30)) + visible_message("\The [W] gets caught in the gelatinous folds of \the [src]") + user.drop_from_inventory(W) + W.forceMove(src.loc) + return damage = (W.force / brute_resist) take_damage(damage) @@ -154,26 +209,38 @@ name = "blob core" icon = 'icons/mob/blob.dmi' icon_state = "blob_core" + light_range = 1 + light_power = 2 + light_color = "#F3D203" maxHealth = 200 brute_resist = 2 + laser_resist = 7 + regen_rate = 2 fire_resist = 2 + var/core_count //amount of secondary cores + var/core_limit = 4 //for if a badmin ever wants the station to die, they can set this higher expandType = /obj/effect/blob/shield - var/blob_may_process = 1 + growth_range = 10 // Maximal distance for new blob pieces from this core. + +/obj/effect/blob/core/New() + if(!parent_core) + parent_core = src + ..() /obj/effect/blob/core/update_icon() - return - -/obj/effect/blob/core/New(loc) - processing_objects.Add(src) - return ..(loc) - -/obj/effect/blob/core/Destroy() - processing_objects.Remove(src) - return ..() + var/health_percent = (health / maxHealth) * 100 + switch(health_percent) + if(66 to INFINITY) + icon_state = "blob_core" + if(33 to 66) + icon_state = "blob_node" + if(-INFINITY to 33) + icon_state = "blob_factory" /obj/effect/blob/core/process() set waitfor = 0 + ..() if(!blob_may_process) return blob_may_process = 0 @@ -184,18 +251,42 @@ pulse(20, list(SOUTH, WEST)) blob_may_process = 1 +// Half the stats of a normal core. Blob has a very small probability of growing these when spreading. These will spread the blob further. +/obj/effect/blob/core/secondary + name = "small blob core" + icon = 'icons/mob/blob.dmi' + icon_state = "blob_core" + maxHealth = 100 + brute_resist = 1 + fire_resist = 1 + laser_resist = 4 + regen_rate = 1 + growth_range = 3 + +/obj/effect/blob/core/secondary/New() + processing_objects.Add(src) + health = maxHealth + update_icon() + return ..(loc) + +/obj/effect/blob/core/secondary/Destroy() + if(parent_core) + parent_core.core_count -= 1 + ..() + /obj/effect/blob/shield name = "strong blob" icon = 'icons/mob/blob.dmi' icon_state = "blob_idle" - desc = "Some blob creature thingy" + opacity = 1 maxHealth = 60 brute_resist = 1 fire_resist = 2 + laser_resist = 5 /obj/effect/blob/shield/New() - ..() update_nearby_tiles() + ..() /obj/effect/blob/shield/Destroy() density = 0 diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 6e253ca9d21..42299d181cc 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -580,7 +580,7 @@ BLIND // can't see anything else rolled_down = -1 if(H) update_clothing_icon() - + /obj/item/clothing/under/proc/update_rollsleeves_status() var/mob/living/carbon/human/H if(istype(src.loc, /mob/living/carbon/human)) @@ -624,8 +624,9 @@ BLIND // can't see anything /obj/item/clothing/under/proc/set_sensors(mob/usr as mob) var/mob/M = usr - if (istype(M, /mob/dead/)) return - if (usr.stat || usr.restrained()) return + if(M.stat || M.paralysis || M.stunned || M.weakened || M.restrained()) + usr << "You cannot reach your suit sensors like this..." + return if(has_sensor >= 2) usr << "The controls are locked." return 0 diff --git a/code/modules/events/event.dm b/code/modules/events/event.dm index aba539f5829..9e837b4091b 100644 --- a/code/modules/events/event.dm +++ b/code/modules/events/event.dm @@ -69,6 +69,9 @@ var/dummy = 0 //If 1, this event is a dummy instance used for retrieving values, it should not run or add/remove itself from any lists + var/two_part = 0 + //used for events that run secondary announcements, like releasing maint access. + /datum/event/nothing no_fake = 1 diff --git a/code/modules/events/false_alarm.dm b/code/modules/events/false_alarm.dm index d57f8629667..a24cc275b18 100644 --- a/code/modules/events/false_alarm.dm +++ b/code/modules/events/false_alarm.dm @@ -8,10 +8,13 @@ endWhen = 90 var/datum/event_meta/EM var/eventname + var/datum/event/E = null /datum/event/false_alarm/end() command_announcement.Announce("Error, It appears our previous announcement about [eventname] was a sensor glitch. There is no cause for alarm, please return to your stations.", "False Alarm") + if(two_part) + E.end() if (EM) qdel(EM) EM = null @@ -25,7 +28,6 @@ //Don't pick events that are excluded from faking. EM = pick(EC.available_events) - var/datum/event/E = null var/fake_allowed = 0 while (!fake_allowed) if (E) @@ -40,6 +42,9 @@ eventname = E.ic_name else eventname = EM.name + if(E.two_part) + two_part = 1 + E.start() E.kill() E.announce() diff --git a/code/modules/events/radiation_storm.dm b/code/modules/events/radiation_storm.dm index f1a99a4d727..b4c212e73ac 100644 --- a/code/modules/events/radiation_storm.dm +++ b/code/modules/events/radiation_storm.dm @@ -7,6 +7,7 @@ announceWhen = 1 endWhen = revokeAccess var/postStartTicks = 0 + two_part = 1 ic_name = "radiation" /datum/event/radiation_storm/announce() diff --git a/code/modules/mining/drilling/drill.dm b/code/modules/mining/drilling/drill.dm index 0f78a2785ae..6caf64bdd0b 100644 --- a/code/modules/mining/drilling/drill.dm +++ b/code/modules/mining/drilling/drill.dm @@ -141,14 +141,22 @@ return src.attack_hand(user) /obj/machinery/mining/drill/attackby(obj/item/O as obj, mob/user as mob) - if(!active) + if(!active && !panel_open) if(default_deconstruction_screwdriver(user, O)) return if(default_deconstruction_crowbar(user, O)) return if(default_part_replacement(user, O)) return - if(!panel_open || active) return ..() + if(active) return ..() + + if(istype(O, /obj/item/weapon/crowbar)) + if (panel_open && cell) + user << "You wrench out \the [cell]." + cell.forceMove(get_turf(user)) + component_parts -= cell + cell = null + return if(istype(O, /obj/item/weapon/cell)) if(cell) @@ -165,13 +173,7 @@ /obj/machinery/mining/drill/attack_hand(mob/user as mob) check_supports() - if (panel_open && cell) - user << "You take out \the [cell]." - cell.loc = get_turf(user) - component_parts -= cell - cell = null - return - else if(need_player_check) + if(need_player_check) user << "You hit the manual override and reset the drill's error checking." need_player_check = 0 if(anchored) @@ -189,8 +191,46 @@ else user << "The drill is unpowered." else - user << "Turning on a piece of industrial machinery without sufficient bracing or wires exposed is a bad idea." - + if(use_cell_power()) + if(!supported && !panel_open) + system_error("unbraced drill error") + sleep(30) + if(!supported) //if you can resolve it manually in three seconds then power to you good-sir. + if(prob(50)) + visible_message("\icon[src] [src.name] beeps, \"Unbraced drill error automatically corrected. Please brace your drill.\"") + else + visible_message("\The [src] explodes!") + fragem(src,10,35,2,1,5,1,0) + qdel(src) + else + visible_message("\icon[src] [src.name] beeps, \"Unbraced drill error manually resolved. Operations may resume normally.\"") + if(supported && panel_open) + if(cell) + system_error("unsealed cell fitting error") + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src.loc) + s.start() + sleep(20) + s.set_up(3, 1, src.loc) + s.start() + sleep(10) + s.set_up(3, 1, src.loc) + s.start() + sleep(10) + if(panel_open) + if(prob(70)) + visible_message("\The [src]'s cell shorts out!") + cell.use(cell.charge) + else + visible_message("\The [src]'s cell detonates!") + explosion(src.loc, -1, -1, 2, 1) + qdel(cell) + component_parts -= cell + cell = null + else + visible_message("\icon[src] [src.name] beeps, \"Unsealed cell fitting error manually resolved. Operations may resume normally.\"") + else + user << "The drill is unpowered." update_icon() /obj/machinery/mining/drill/update_icon() @@ -238,7 +278,8 @@ /obj/machinery/mining/drill/proc/system_error(var/error) if(error) - src.visible_message("\The [src] flashes a '[error]' warning.") + visible_message("\icon[src] [src.name] flashes a system warning: [error].") + playsound(src.loc, 'sound/machines/warning-buzzer.ogg', 100, 1) need_player_check = 1 active = 0 update_icon() @@ -283,7 +324,9 @@ O.loc = B usr << "You unload the drill's storage cache into the ore box." else - usr << "You must move an ore box up to the drill before you can unload it." + for(var/obj/item/weapon/ore/O in contents) + O.forceMove(src.loc) + usr << "You spill the content's of the drill's storage box all over the ground. Idiot." /obj/machinery/mining/brace @@ -292,16 +335,70 @@ icon_state = "mining_brace" var/obj/machinery/mining/drill/connected +/obj/machinery/mining/brace/New() + ..() + + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/miningdrillbrace(src) + /obj/machinery/mining/brace/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(connected && connected.active) + user << "You know you ought not work with the brace of a running drill, but you do anyways." + sleep(5) + if(istype(user, /mob/living/carbon/human)) + //Save the users active hand + var/mob/living/carbon/human/H = user + var/obj/item/organ/external/LA = H.get_organ("l_hand") + var/obj/item/organ/external/RA = H.get_organ("r_hand") + var/active_hand = H.hand + if(prob(20)) + if(active_hand) + LA.droplimb(0,DROPLIMB_BLUNT) + else + RA.droplimb(0,DROPLIMB_BLUNT) + connected.system_error("unexpected user interface error") + return + else + H.apply_damage(25,BRUTE, sharp=1, edge=1) + connected.system_error("unexpected user interface error") + return + else + var/mob/living/M = user + M.apply_damage(25,BRUTE, sharp=1, edge=1) + + if(default_deconstruction_screwdriver(user, W)) + return + if(default_deconstruction_crowbar(user, W)) + return + if(istype(W,/obj/item/weapon/wrench)) if(istype(get_turf(src), /turf/space)) - user << "You can't anchor something to empty space. Idiot." + user << "You send the [src] careening into space. Idiot." + var/inertia = rand(10,30) + for(var/i in 1 to inertia) + step_away(src,user,15,8) + if(!(istype(get_turf(src), /turf/space))) + break + sleep(1) return if(connected && connected.active) - user << "You can't unanchor the brace of a running drill!" - return + if(prob(50)) + sleep(10) + connected.system_error("unbraced drill error") + sleep(30) + if(connected && connected.active) //if you can resolve it manually in three seconds then power to you good-sir. + if(prob(50)) + visible_message("\icon[src] [src.name] beeps, \"Unbraced drill error automatically corrected. Please brace your drill.\"") + else + visible_message("\The [src] explodes!") + fragem(src,10,35,2,1,5,1,0) + qdel(src) + return + else + connected.system_error("unexpected user interface error") + return playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) user << "You [anchored ? "un" : ""]anchor the brace." @@ -356,4 +453,4 @@ return 0 src.set_dir(turn(src.dir, 90)) - return 1 \ No newline at end of file + return 1 diff --git a/code/modules/mob/hear_say.dm b/code/modules/mob/hear_say.dm index 57648d57c97..c88aa5841f2 100644 --- a/code/modules/mob/hear_say.dm +++ b/code/modules/mob/hear_say.dm @@ -217,7 +217,15 @@ if(say_understands(speaker, language)) message = "[speaker] [verb], \"[message]\"" else - message = "[speaker] [verb]." + var/adverb + var/length = length(message) * pick(0.8, 0.9, 1.0, 1.1, 1.2) //Inserts a little fuzziness. + switch(length) + if(0 to 12) adverb = " briefly" + if(12 to 30) adverb = " a short message" + if(30 to 48) adverb = " a message" + if(48 to 90) adverb = " a lengthy message" + else adverb = " a very lengthy message" + message = "[speaker] [verb][adverb]." if(src.status_flags & PASSEMOTES) for(var/obj/item/weapon/holder/H in src.contents) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index e9cdb29aad1..7e751c5250b 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -908,24 +908,8 @@ sleep(20) playsound(loc, 'sound/effects/alert.ogg', 125, 1) sleep(10) - var/turf/O = get_turf(src) - var/fragger = rand(50,100) density = 0 - explosion(O, -1, -1, 2) - var/list/target_turfs = getcircle(O, 7) - var/fragments_per_projectile = round(fragger/target_turfs.len) - - for(var/turf/T in target_turfs) - sleep(0) - var/obj/item/projectile/bullet/pellet/fragment/P = new (O) - - P.damage = 5 - P.pellets = fragments_per_projectile - P.range_step = 1 - P.shot_from = src.name - P.name = "[src]'s shrapnel" - - P.launch(T) + fragem(src,50,100,2,1,5,1,0) gib() return diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index 3ffa1ce1802..f22b8c0328e 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -500,15 +500,15 @@ obj/item/weapon/gun/energy/staff/special_check(var/mob/user) LL.droplimb(0,DROPLIMB_BLUNT) RL.droplimb(0,DROPLIMB_BLUNT) playsound(user, 'sound/effects/splat.ogg', 50, 1) - user.show_message("\red With a sickening series of crunches, [user]'s body shrinks, and they begin to sprout feathers!") - user.show_message("[user] screams!",2) + user.visible_message(" With a sickening series of crunches, [user]'s body shrinks, and they begin to sprout feathers!") + user.visible_message("[user] screams!",2) new_mob = new /mob/living/simple_animal/parrot(H.loc) new_mob.universal_speak = 1 new_mob.key = H.key new_mob.a_intent = "harm" qdel(H) sleep(20) - new_mob.show_message("[new_mob] squawks, 'Poly wanna cracker!'",2) + new_mob.say("Poly wanna cracker!") return 0 return 1 @@ -537,8 +537,8 @@ obj/item/weapon/gun/energy/staff/animate/special_check(var/mob/user) var/obj/item/organ/external/RA = H.get_organ("r_hand") var/active_hand = H.hand playsound(user, 'sound/effects/blobattack.ogg', 40, 1) - user.visible_message("\red With a sickening crunch, [user]'s hand rips itself off, and begins crawling away!") - user.show_message("[user] screams!",2) + user.visible_message(" With a sickening crunch, [user]'s hand rips itself off, and begins crawling away!") + user.visible_message("[user] screams!",2) user.drop_item() if(active_hand) LA.droplimb(0,DROPLIMB_EDGE) diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm index 35324403430..bbee306f86d 100644 --- a/code/modules/research/designs.dm +++ b/code/modules/research/designs.dm @@ -1341,6 +1341,20 @@ CIRCUITS BELOW build_path = /obj/item/weapon/circuitboard/biogenerator sort_string = "KBAAA" +/datum/design/circuit/miningdrill + name = "mining drill head" + id = "mining drill head" + req_tech = list(TECH_DATA = 1, TECH_ENGINEERING = 1) + build_path = /obj/item/weapon/circuitboard/miningdrill + sort_string = "KCAAA" + +/datum/design/circuit/miningdrillbrace + name = "mining drill brace" + id = "mining drill brace" + req_tech = list(TECH_DATA = 1, TECH_ENGINEERING = 1) + build_path = /obj/item/weapon/circuitboard/miningdrillbrace + sort_string = "KCAAB" + /datum/design/circuit/comconsole name = "communications console" id = "comconsole" diff --git a/html/changelogs/LordFowl - PR 3113912125.yml b/html/changelogs/LordFowl - PR 3113912125.yml new file mode 100644 index 00000000000..b6b4822890f --- /dev/null +++ b/html/changelogs/LordFowl - PR 3113912125.yml @@ -0,0 +1,38 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +################################# + +# Your name. +author: LordFowl + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - tweak: "Removing cells from industrial mining drills now requires a crowbar." + - rscadd: "Industrial mining drills have been made more dangerous." + - rscadd: "Blobs have been made more dangerous." \ No newline at end of file diff --git a/icons/turf/flooring/asteroid.dmi b/icons/turf/flooring/asteroid.dmi index b064d7f377e7bcfd362bb020862366d70dde06b2..293c991c173007442b185be78692c1edb81d14da 100644 GIT binary patch delta 6154 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 delta 4864 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 md@p?04Rrm$)q3&V{{I63Nqr0B&ligT0000