diff --git a/code/controllers/subsystem/acid.dm b/code/controllers/subsystem/acid.dm new file mode 100644 index 00000000000..f86c8540af5 --- /dev/null +++ b/code/controllers/subsystem/acid.dm @@ -0,0 +1,36 @@ +SUBSYSTEM_DEF(acid) + name = "Acid" + priority = FIRE_PRIORITY_ACID + flags = SS_NO_INIT|SS_BACKGROUND + runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME + + var/list/currentrun = list() + var/list/processing = list() + +/datum/controller/subsystem/acid/stat_entry() + ..("P:[processing.len]") + + +/datum/controller/subsystem/acid/fire(resumed = 0) + if(!resumed) + src.currentrun = processing.Copy() + + //cache for sanic speed (lists are references anyways) + var/list/currentrun = src.currentrun + + while(currentrun.len) + var/obj/O = currentrun[currentrun.len] + currentrun.len-- + if(!O || QDELETED(O)) + processing -= O + if(MC_TICK_CHECK) + return + continue + + if(O.acid_level && O.acid_processing()) + else + O.cut_overlay(GLOB.acid_overlay, TRUE) + processing -= O + + if(MC_TICK_CHECK) + return \ No newline at end of file diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 37f5c521f9f..bbc41892a32 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -719,6 +719,14 @@ var/list/blood_splatter_icons = list() /atom/proc/singularity_pull() return +/** + * Respond to acid being used on our atom + * + * Default behaviour is to send COMSIG_ATOM_ACID_ACT and return + */ +/atom/proc/acid_act(acidpwr, acid_volume) + SEND_SIGNAL(src, COMSIG_ATOM_ACID_ACT, acidpwr, acid_volume) + /atom/proc/narsie_act() return diff --git a/code/game/objects/effects/alien_acid.dm b/code/game/objects/effects/alien_acid.dm index 118d3efcc2c..8f383fd518c 100644 --- a/code/game/objects/effects/alien_acid.dm +++ b/code/game/objects/effects/alien_acid.dm @@ -1,88 +1,92 @@ -/* Alien shit! - * Contains: - * effect/acid - */ - - -/* - * Acid - */ /obj/effect/acid gender = PLURAL name = "acid" - desc = "Burbling corrossive stuff." - icon = 'icons/effects/effects.dmi' + desc = "Burbling corrosive stuff." icon_state = "acid" - density = 0 + density = FALSE opacity = 0 - anchored = 1 - unacidable = 1 - var/atom/target - var/ticks = 0 - var/target_strength = 0 + anchored = TRUE + resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF + layer = ABOVE_NORMAL_TURF_LAYER + var/turf/target -/obj/effect/acid/New(loc, targ) - ..(loc) - target = targ +/obj/effect/acid/Initialize(mapload, acid_pwr, acid_amt) + . = ..() + + target = get_turf(src) + + if(acid_amt) + acid_level = min(acid_amt * acid_pwr, 12000) //capped so the acid effect doesn't last a half hour on the floor. //handle APCs and newscasters and stuff nicely - pixel_x = target.pixel_x - pixel_y = target.pixel_y + pixel_x = target.pixel_x + rand(-4,4) + pixel_y = target.pixel_y + rand(-4,4) - if(isturf(target)) //Turfs take twice as long to take down. - target_strength = 640 - else - target_strength = 320 - tick() + START_PROCESSING(SSobj, src) -/obj/effect/acid/proc/tick() +/obj/effect/acid/Destroy() + STOP_PROCESSING(SSobj, src) + target = null + return ..() + +/obj/effect/acid/process() + . = 1 if(!target) qdel(src) + return 0 - ticks++ + if(prob(5)) + playsound(loc, 'sound/items/welder.ogg', 100, TRUE) - if(ticks >= target_strength) - target.visible_message("[target] collapses under its own weight into a puddle of goop and undigested debris!") - - if(istype(target, /obj/structure/closet)) - var/obj/structure/closet/T = target - T.dump_contents() - qdel(target) - - if(istype(target, /turf/simulated/mineral)) - var/turf/simulated/mineral/M = target - M.ChangeTurf(/turf/simulated/floor/plating/asteroid/airless) - - if(istype(target, /turf/simulated/floor)) - var/turf/simulated/floor/F = target - F.ChangeTurf(F.baseturf) - - if(istype(target, /turf/simulated/wall)) - var/turf/simulated/wall/W = target - W.dismantle_wall(1) - - else - qdel(target) + for(var/obj/O in target) + if(prob(20) && !(resistance_flags & UNACIDABLE)) + if(O.acid_level < acid_level * 0.3) + var/acid_used = min(acid_level * 0.05, 20) + O.acid_act(10, acid_used) + acid_level = max(0, acid_level - acid_used * 10) + acid_level = max(acid_level - (5 + 2 * round(sqrt(acid_level))), 0) + if(acid_level <= 0) qdel(src) - return + return 0 - x = target.x - y = target.y - z = target.z +/obj/effect/acid/Crossed(AM as mob|obj) + if(isliving(AM)) + var/mob/living/L = AM + if(L.flying) + return + if(L.m_intent != MOVE_INTENT_WALK && prob(40)) + var/acid_used = min(acid_level * 0.05, 20) + if(L.acid_act(10, acid_used, "feet")) + acid_level = max(0, acid_level - acid_used * 10) + playsound(L, 'sound/weapons/sear.ogg', 50, TRUE) + to_chat(L, "[src] burns you!") - switch(target_strength - ticks) - if(480) - visible_message("[target] is holding up against the acid!") - if(320) - visible_message("[target] is being melted by the acid!") - if(160) - visible_message("[target] is struggling to withstand the acid!") - if(80) - visible_message("[target] begins to crumble under the acid!") +//xenomorph corrosive acid +/obj/effect/acid/alien + var/target_strength = 30 - spawn(1) - if(src) - tick() + +/obj/effect/acid/alien/process() + . = ..() + if(.) + if(prob(45)) + playsound(loc, 'sound/items/welder.ogg', 100, TRUE) + target_strength-- + if(target_strength <= 0) + target.visible_message("[target] collapses under its own weight into a puddle of goop and undigested debris!") + target.acid_melt() + qdel(src) + else + + switch(target_strength) + if(24) + visible_message("[target] is holding up against the acid!") + if(16) + visible_message("[target] is being melted by the acid!") + if(8) + visible_message("[target] is struggling to withstand the acid!") + if(4) + visible_message("[target] begins to crumble under the acid!") \ No newline at end of file diff --git a/code/game/objects/effects/decals/remains.dm b/code/game/objects/effects/decals/remains.dm index 77a51b4d975..d69b8cad25a 100644 --- a/code/game/objects/effects/decals/remains.dm +++ b/code/game/objects/effects/decals/remains.dm @@ -1,6 +1,12 @@ /obj/effect/decal/remains gender = PLURAL +/obj/effect/decal/remains/acid_act() + visible_message("[src] dissolve[gender==PLURAL?"":"s"] into a puddle of sizzling goop!") + playsound(src, 'sound/items/welder.ogg', 150, TRUE) + new /obj/effect/decal/cleanable/greenglow(drop_location()) + qdel(src) + /obj/effect/decal/remains/human name = "remains" desc = "They look like human remains. They have a strange aura about them." diff --git a/code/game/objects/effects/effects.dm b/code/game/objects/effects/effects.dm index 8bf451be5b8..356928029b2 100644 --- a/code/game/objects/effects/effects.dm +++ b/code/game/objects/effects/effects.dm @@ -15,6 +15,12 @@ /obj/effect/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE) return FALSE +/obj/effect/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume, global_overlay = TRUE) + return + +/obj/effect/acid_act() + return + /obj/effect/decal plane = FLOOR_PLANE var/no_scoop = FALSE //if it has this, don't let it be scooped up diff --git a/code/game/objects/effects/glowshroom.dm b/code/game/objects/effects/glowshroom.dm index 464d5c277fd..a75090183dc 100644 --- a/code/game/objects/effects/glowshroom.dm +++ b/code/game/objects/effects/glowshroom.dm @@ -188,3 +188,10 @@ /obj/structure/glowshroom/proc/CheckEndurance() if(endurance <= 0) qdel(src) + +/obj/structure/glowshroom/acid_act(acidpwr, acid_volume) + . = 1 + visible_message("[src] melts away!") + var/obj/effect/decal/cleanable/molten_object/I = new (get_turf(src)) + I.desc = "Looks like this was \an [src] some time ago." + qdel(src) \ No newline at end of file diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 316ae48bc74..92afffc6698 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -218,6 +218,15 @@ var/global/image/fire_overlay = image("icon" = 'icons/goonstation/effects/fire.d A.desc += "\nLooks like this used to be \an [name] some time ago." ..() +/obj/item/acid_melt() + if(!QDELETED(src)) + var/turf/T = get_turf(src) + var/obj/effect/decal/cleanable/molten_object/MO = new(T) + MO.pixel_x = rand(-16,16) + MO.pixel_y = rand(-16,16) + MO.desc = "Looks like this was \an [src] some time ago." + ..() + /obj/item/afterattack(atom/target, mob/user, proximity, params) SEND_SIGNAL(src, COMSIG_ITEM_AFTERATTACK, target, user, proximity, params) ..() @@ -251,6 +260,15 @@ var/global/image/fire_overlay = image("icon" = 'icons/goonstation/effects/fire.d else extinguish() + if(acid_level > 20 && !ismob(loc))// so we can still remove the clothes on us that have acid. + var/mob/living/carbon/human/H = user + if(istype(H)) + if(!H.gloves || (!(H.gloves.resistance_flags & (UNACIDABLE|ACID_PROOF)))) + to_chat(user, "The acid on [src] burns your hand!") + var/obj/item/organ/external/affecting = H.get_organ("[user.hand ? "l" : "r" ]_arm") + if(affecting && affecting.receive_damage( 0, 5 )) // 5 burn damage + H.UpdateDamageIcon() + if(istype(src.loc, /obj/item/storage)) //If the item is in a storage item, take it out var/obj/item/storage/S = src.loc @@ -578,6 +596,7 @@ var/global/image/fire_overlay = image("icon" = 'icons/goonstation/effects/fire.d if(!do_after(user, 40, target = source)) return clean_blood() + acid_level = 0 user.visible_message("[user] washes [src] using [source].", \ "You wash [src] using [source].") return 1 diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index 0bac4aeb848..432f2e6a958 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -158,6 +158,42 @@ qdel(src) return 2 +///// ACID + +GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/effects/effects.dmi', "acid")) + +///the obj's reaction when touched by acid +/obj/acid_act(acidpwr, acid_volume) + if(!(resistance_flags & UNACIDABLE) && acid_volume) + + if(!acid_level) + SSacid.processing[src] = src + add_overlay(GLOB.acid_overlay, TRUE) + var/acid_cap = acidpwr * 300 //so we cannot use huge amounts of weak acids to do as well as strong acids. + if(acid_level < acid_cap) + acid_level = min(acid_level + acidpwr * acid_volume, acid_cap) + return 1 + +///the proc called by the acid subsystem to process the acid that's on the obj +/obj/proc/acid_processing() + . = 1 + if(!(resistance_flags & ACID_PROOF)) + for(var/armour_value in armor) + if(armour_value != "acid" && armour_value != "fire") + armor[armour_value] = max(armor[armour_value] - round(sqrt(acid_level) * 0.1), 0) + if(prob(33)) + playsound(loc, 'sound/items/welder.ogg', 150, TRUE) + take_damage(min(1 + round(sqrt(acid_level) * 0.3), 300), BURN, "acid", 0) + + acid_level = max(acid_level - (5 + 3 * round(sqrt(acid_level))), 0) + if(!acid_level) + return 0 + +///called when the obj is destroyed by acid. +/obj/proc/acid_melt() + SSacid.processing -= src + deconstruct(FALSE) + //// FIRE /obj/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume, global_overlay = TRUE) @@ -202,9 +238,11 @@ /obj/proc/obj_break(damage_flag) return -//what happens when the obj's integrity reaches zero. +///what happens when the obj's integrity reaches zero. /obj/proc/obj_destruction(damage_flag) - if(damage_flag == BURN) + if(damage_flag == "acid") + acid_melt() + else if(damage_flag == "fire") burn() else deconstruct(FALSE) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 569ca8250b7..affa17117b8 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -2,7 +2,6 @@ //var/datum/module/mod //not used var/origin_tech = null //Used by R&D to determine what research bonuses it grants. var/crit_fail = 0 - var/unacidable = 0 //universal "unacidabliness" var, here so you can use it in any obj. animate_movement = 2 var/throwforce = 1 var/list/attack_verb = list() //Used in attackby() to say how something was attacked "[x] has been [z.attack_verb] by [y] with [z]" @@ -15,6 +14,7 @@ var/obj_integrity //defaults to max_integrity var/max_integrity = INFINITY var/integrity_failure = 0 //0 if we have no special broken behavior + var/acid_level = 0 //how much acid is on that obj var/resistance_flags = NONE // INDESTRUCTIBLE var/can_be_hit = TRUE //can this be bludgeoned by items? diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm index e6c0bdea081..1f6718da713 100644 --- a/code/game/turfs/simulated/floor.dm +++ b/code/game/turfs/simulated/floor.dm @@ -241,5 +241,8 @@ var/list/icons_to_ignore_at_floor_init = list("damaged1","damaged2","damaged3"," if(.) ChangeTurf(/turf/simulated/floor/clockwork) +/turf/simulated/floor/acid_melt() + ChangeTurf(baseturf) + /turf/simulated/floor/can_have_cabling() return !burnt && !broken diff --git a/code/game/turfs/simulated/floor/lava.dm b/code/game/turfs/simulated/floor/lava.dm index b2c29a5ee01..e2d45ff17e7 100644 --- a/code/game/turfs/simulated/floor/lava.dm +++ b/code/game/turfs/simulated/floor/lava.dm @@ -14,6 +14,9 @@ /turf/simulated/floor/plating/lava/ex_act() return +/turf/simulated/floor/plating/lava/acid_act(acidpwr, acid_volume) + return + /turf/simulated/floor/plating/lava/airless temperature = TCMB diff --git a/code/game/turfs/simulated/floor/plating.dm b/code/game/turfs/simulated/floor/plating.dm index 7fabcb0b957..a901e402ef0 100644 --- a/code/game/turfs/simulated/floor/plating.dm +++ b/code/game/turfs/simulated/floor/plating.dm @@ -150,6 +150,10 @@ /turf/simulated/floor/engine/pry_tile(obj/item/C, mob/user, silent = FALSE) return +/turf/simulated/floor/engine/acid_act(acidpwr, acid_volume) + acidpwr = min(acidpwr, 50) //we reduce the power so reinf floor never get melted. + . = ..() + /turf/simulated/floor/engine/attackby(obj/item/C as obj, mob/user as mob, params) if(!C || !user) return diff --git a/code/game/turfs/simulated/minerals.dm b/code/game/turfs/simulated/minerals.dm index 2109c8c62e5..8131c791ad4 100644 --- a/code/game/turfs/simulated/minerals.dm +++ b/code/game/turfs/simulated/minerals.dm @@ -132,6 +132,9 @@ if(istype(M.selected,/obj/item/mecha_parts/mecha_equipment/drill)) M.selected.action(src) +/turf/simulated/mineral/acid_melt() + ChangeTurf(baseturf) + /turf/simulated/mineral/ex_act(severity, target) ..() switch(severity) diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index 26b79c9e9f4..188136057da 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -446,6 +446,14 @@ if(prob(20)) ChangeTurf(/turf/simulated/wall/cult) +/turf/simulated/wall/acid_act(acidpwr, acid_volume) + if(explosion_block >= 2) + acidpwr = min(acidpwr, 50) //we reduce the power so strong walls never get melted. + . = ..() + +/turf/simulated/wall/acid_melt() + dismantle_wall(1) + /turf/simulated/wall/proc/add_dent(denttype, x=rand(-8, 8), y=rand(-8, 8)) if(LAZYLEN(dent_decals) >= MAX_DENT_DECALS) return diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm index 40c0d83272e..1c0bfb167d6 100644 --- a/code/game/turfs/space/space.dm +++ b/code/game/turfs/space/space.dm @@ -25,7 +25,7 @@ var/area/A = loc if(!IS_DYNAMIC_LIGHTING(src) && IS_DYNAMIC_LIGHTING(A)) add_overlay(/obj/effect/fullbright) - + if (light_power && light_range) update_light() @@ -265,6 +265,9 @@ var/turf/T = locate(destination_x, destination_y, destination_z) user.forceMove(T) +/turf/space/acid_act(acidpwr, acid_volume) + return 0 + /turf/space/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir) underlay_appearance.icon = 'icons/turf/space.dmi' underlay_appearance.icon_state = SPACE_ICON_STATE diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 0ab9ccbef15..28d730e79d4 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -43,7 +43,7 @@ /turf/Initialize(mapload) . = ..() - + var/area/A = loc if(!IS_DYNAMIC_LIGHTING(src) && IS_DYNAMIC_LIGHTING(A)) add_overlay(/obj/effect/fullbright) @@ -206,7 +206,7 @@ var/old_baseturf = baseturf var/turf/W = new path(src) W.baseturf = old_baseturf - + if(!defer_change) W.AfterChange(ignore_air) W.blueprint_data = old_blueprint_data @@ -412,6 +412,27 @@ //////////////////////////////////////////////////// +/turf/acid_act(acidpwr, acid_volume) + . = 1 + var/acid_type = /obj/effect/acid + if(acidpwr >= 200) //alien acid power + acid_type = /obj/effect/acid/alien + var/has_acid_effect = FALSE + for(var/obj/O in src) + if(intact && O.level == 1) //hidden under the floor + continue + if(istype(O, acid_type)) + var/obj/effect/acid/A = O + A.acid_level = min(A.level + acid_volume * acidpwr, 12000)//capping acid level to limit power of the acid + has_acid_effect = 1 + continue + O.acid_act(acidpwr, acid_volume) + if(!has_acid_effect) + new acid_type(src, acidpwr, acid_volume) + +/turf/proc/acid_melt() + return + /turf/handle_fall(mob/faller, forced) faller.lying = pick(90, 270) if(!forced) @@ -516,5 +537,5 @@ /turf/AllowDrop() return TRUE -/turf/proc/water_act(volume, temperature, source) +/turf/proc/water_act(volume, temperature, source) return FALSE diff --git a/code/game/turfs/unsimulated.dm b/code/game/turfs/unsimulated.dm index 8ae608a0af6..537cfdc8d57 100644 --- a/code/game/turfs/unsimulated.dm +++ b/code/game/turfs/unsimulated.dm @@ -10,6 +10,9 @@ /turf/unsimulated/rpd_act() return +/turf/unsimulated/acid_act(acidpwr, acid_volume, acid_id) + return 0 + /turf/unsimulated/floor/plating/vox icon_state = "plating" name = "plating" diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm index 126e9f30b31..cbf11d23d99 100644 --- a/code/modules/crafting/recipes.dm +++ b/code/modules/crafting/recipes.dm @@ -184,8 +184,8 @@ result = /obj/item/ammo_casing/shotgun/frag12 reqs = list(/obj/item/ammo_casing/shotgun/techshell = 1, /datum/reagent/glycerol = 5, - /datum/reagent/sacid = 5, - /datum/reagent/facid = 5,) + /datum/reagent/acid = 5, + /datum/reagent/acid/facid = 5,) tools = list(/obj/item/screwdriver) time = 5 category = CAT_WEAPONRY diff --git a/code/modules/mob/living/carbon/alien/alien_defense.dm b/code/modules/mob/living/carbon/alien/alien_defense.dm index 5eb8f5766e4..0182f169b9a 100644 --- a/code/modules/mob/living/carbon/alien/alien_defense.dm +++ b/code/modules/mob/living/carbon/alien/alien_defense.dm @@ -74,3 +74,6 @@ In all, this is a lot like the monkey code. /N adjustCloneLoss(damage) if(STAMINA) adjustStaminaLoss(damage) + +/mob/living/carbon/alien/acid_act(acidpwr, acid_volume) + return 0//aliens are immune to acid. \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm index fd8d4445717..9ec48c51bb1 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm @@ -70,34 +70,20 @@ Doesn't work on other aliens/AI.*/ return -/mob/living/carbon/alien/humanoid/proc/corrosive_acid(O as obj|turf in oview(1)) //If they right click to corrode, an error will flash if its an invalid target./N +/mob/living/carbon/alien/humanoid/proc/corrosive_acid(atom/target) //If they right click to corrode, an error will flash if its an invalid target./N set name = "Corrossive Acid (200)" set desc = "Drench an object in acid, destroying it over time." set category = "Alien" if(powerc(200)) - if(O in oview(1)) - // OBJ CHECK - if(isobj(O)) - var/obj/I = O - if(I.unacidable) //So the aliens don't destroy energy fields/singularies/other aliens/etc with their acid. - to_chat(src, "You cannot dissolve this object.") - return - // TURF CHECK - else if(istype(O, /turf/simulated)) - var/turf/simulated/T = O - if(T.unacidable) - to_chat(src, "You cannot dissolve this object.") - return - else// Not a type we can acid. - return - - adjustPlasma(-200) - new /obj/effect/acid(get_turf(O), O) - visible_message("[src] vomits globs of vile stuff all over [O]. It begins to sizzle and melt under the bubbling mess of acid!") + if(target in oview(1)) + if(target.acid_act(200, 100)) + visible_message("[src] vomits globs of vile stuff all over [target]. It begins to sizzle and melt under the bubbling mess of acid!") + adjustPlasma(-200) + else + to_chat(src, "You cannot dissolve this object.") else - to_chat(src, "Target is too far away.") - return + to_chat(src, "[target] is too far away.") /mob/living/carbon/alien/humanoid/proc/neurotoxin() // ok set name = "Spit Neurotoxin (50)" diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 21662714653..00de5dfd550 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1171,3 +1171,10 @@ so that different stomachs can handle things in different ways VB*/ SEND_SIGNAL(src, COMSIG_MOB_UPDATE_SIGHT) sync_lighting_plane_alpha() + +/mob/living/carbon/ExtinguishMob() + for(var/X in get_equipped_items()) + var/obj/item/I = X + I.acid_level = 0 //washes off the acid on our clothes + I.extinguish() //extinguishes our clothes + ..() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index d172fabef00..de7da52218c 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -167,6 +167,152 @@ emp_act O.emp_act(severity) ..() +/mob/living/carbon/human/acid_act(acidpwr, acid_volume, bodyzone_hit) //todo: update this to utilize check_obscured_slots() //and make sure it's check_obscured_slots(TRUE) to stop aciding through visors etc + var/list/damaged = list() + var/list/inventory_items_to_kill = list() + var/acidity = acidpwr * min(acid_volume * 0.005, 0.1) + //HEAD// + if(!bodyzone_hit || bodyzone_hit == "head") //only if we didn't specify a zone or if that zone is the head. + var/obj/item/clothing/head_clothes = null + if(glasses) + head_clothes = glasses + if(wear_mask) + head_clothes = wear_mask + if(head) + head_clothes = head + if(head_clothes) + if(!(head_clothes.resistance_flags & UNACIDABLE)) + head_clothes.acid_act(acidpwr, acid_volume) + update_inv_glasses() + update_inv_wear_mask() + update_inv_head() + else + to_chat(src, "Your [head_clothes.name] protects your head and face from the acid!") + else + . = get_organ("head") + if(.) + damaged += . + if(l_ear) + inventory_items_to_kill += l_ear + if(r_ear) + inventory_items_to_kill += r_ear + + //CHEST// + if(!bodyzone_hit || bodyzone_hit == "chest") + var/obj/item/clothing/chest_clothes = null + if(w_uniform) + chest_clothes = w_uniform + if(wear_suit) + chest_clothes = wear_suit + if(chest_clothes) + if(!(chest_clothes.resistance_flags & UNACIDABLE)) + chest_clothes.acid_act(acidpwr, acid_volume) + update_inv_w_uniform() + update_inv_wear_suit() + else + to_chat(src, "Your [chest_clothes.name] protects your body from the acid!") + else + . = get_organ("chest") + if(.) + damaged += . + if(wear_id) + inventory_items_to_kill += wear_id + if(wear_pda) + inventory_items_to_kill += wear_pda + if(r_store) + inventory_items_to_kill += r_store + if(l_store) + inventory_items_to_kill += l_store + if(s_store) + inventory_items_to_kill += s_store + + + //ARMS & HANDS// + if(!bodyzone_hit || bodyzone_hit == "l_arm" || bodyzone_hit == "r_arm") + var/obj/item/clothing/arm_clothes = null + if(gloves) + arm_clothes = gloves + if(w_uniform && ((w_uniform.body_parts_covered & HANDS) || (w_uniform.body_parts_covered & ARMS))) + arm_clothes = w_uniform + if(wear_suit && ((wear_suit.body_parts_covered & HANDS) || (wear_suit.body_parts_covered & ARMS))) + arm_clothes = wear_suit + + if(arm_clothes) + if(!(arm_clothes.resistance_flags & UNACIDABLE)) + arm_clothes.acid_act(acidpwr, acid_volume) + update_inv_gloves() + update_inv_w_uniform() + update_inv_wear_suit() + else + to_chat(src, "Your [arm_clothes.name] protects your arms and hands from the acid!") + else + . = get_organ("r_arm") + if(.) + damaged += . + . = get_organ("l_arm") + if(.) + damaged += . + + + //LEGS & FEET// + if(!bodyzone_hit || bodyzone_hit == "l_leg" || bodyzone_hit =="r_leg" || bodyzone_hit == "feet") + var/obj/item/clothing/leg_clothes = null + if(shoes) + leg_clothes = shoes + if(w_uniform && ((w_uniform.body_parts_covered & FEET) || (bodyzone_hit != "feet" && (w_uniform.body_parts_covered & LEGS)))) + leg_clothes = w_uniform + if(wear_suit && ((wear_suit.body_parts_covered & FEET) || (bodyzone_hit != "feet" && (wear_suit.body_parts_covered & LEGS)))) + leg_clothes = wear_suit + if(leg_clothes) + if(!(leg_clothes.resistance_flags & UNACIDABLE)) + leg_clothes.acid_act(acidpwr, acid_volume) + update_inv_shoes() + update_inv_w_uniform() + update_inv_wear_suit() + else + to_chat(src, "Your [leg_clothes.name] protects your legs and feet from the acid!") + else + . = get_organ("r_leg") + if(.) + damaged += . + . = get_organ("l_leg") + if(.) + damaged += . + + + //DAMAGE// + for(var/obj/item/organ/external/affecting in damaged) + affecting.receive_damage(acidity, 2 * acidity) + + if(istype(affecting, /obj/item/organ/external/head)) + var/obj/item/organ/external/head/head_organ = affecting + if(prob(min(acidpwr * acid_volume / 10, 90))) //Applies disfigurement + head_organ.receive_damage(acidity, 2 * acidity) + emote("scream") + head_organ.h_style = "Bald" + head_organ.f_style = "Shaved" + update_hair() + update_fhair() + head_organ.disfigure() + + UpdateDamageIcon() + + //MELTING INVENTORY ITEMS// + //these items are all outside of armour visually, so melt regardless. + if(!bodyzone_hit) + if(back) + inventory_items_to_kill += back + if(belt) + inventory_items_to_kill += belt + if(l_hand) + inventory_items_to_kill += l_hand + if(r_hand) + inventory_items_to_kill += r_hand + + for(var/obj/item/I in inventory_items_to_kill) + I.acid_act(acidpwr, acid_volume) + return 1 + /mob/living/carbon/human/emag_act(user as mob, var/obj/item/organ/external/affecting) if(!istype(affecting)) return diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index cd20656254f..5d275173e93 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -266,6 +266,10 @@ ..() flash_eyes() +/mob/living/acid_act(acidpwr, acid_volume) + take_organ_damage(acidpwr * min(1, acid_volume * 0.1)) + return 1 + /mob/living/proc/updatehealth(reason = "none given") if(status_flags & GODMODE) health = maxHealth diff --git a/code/modules/reagents/chemistry/reagents/toxins.dm b/code/modules/reagents/chemistry/reagents/toxins.dm index 43278d135e5..7f0890a0c37 100644 --- a/code/modules/reagents/chemistry/reagents/toxins.dm +++ b/code/modules/reagents/chemistry/reagents/toxins.dm @@ -275,7 +275,7 @@ return ..() | update_flags -/datum/reagent/sacid +/datum/reagent/acid name = "Sulphuric acid" id = "sacid" description = "A strong mineral acid with the molecular formula H2SO4." @@ -283,13 +283,14 @@ color = "#00FF32" process_flags = ORGANIC | SYNTHETIC taste_description = "ACID" + var/acidpwr = 10 //the amount of protection removed from the armour -/datum/reagent/sacid/on_mob_life(mob/living/M) +/datum/reagent/acid/on_mob_life(mob/living/M) var/update_flags = STATUS_UPDATE_NONE update_flags |= M.adjustFireLoss(1, FALSE) return ..() | update_flags -/datum/reagent/sacid/reaction_mob(mob/living/M, method = TOUCH, volume) +/datum/reagent/acid/reaction_mob(mob/living/M, method = TOUCH, volume) if(ishuman(M) && !isgrey(M)) var/mob/living/carbon/human/H = M if(method == TOUCH) @@ -318,13 +319,62 @@ H.adjustFireLoss(min(max(4, (volume - 10) * 2), 20)) H.emote("scream") -/datum/reagent/sacid/reaction_obj(obj/O, volume) - if((istype(O,/obj/item) || istype(O,/obj/structure/glowshroom)) && prob(40)) - if(!O.unacidable) - var/obj/effect/decal/cleanable/molten_object/I = new/obj/effect/decal/cleanable/molten_object(O.loc) - I.desc = "Looks like this was \an [O] some time ago." - O.visible_message("[O] melts.") - qdel(O) +/datum/reagent/acid/reaction_obj(obj/O, volume) + if(ismob(O.loc)) //handled in human acid_act() + return + volume = round(volume, 0.1) + O.acid_act(acidpwr, volume) + +/datum/reagent/acid/reaction_turf(turf/T, volume) + if(!istype(T)) + return + volume = round(volume, 0.1) + T.acid_act(acidpwr, volume) + +/datum/reagent/acid/facid + name = "Fluorosulfuric Acid" + id = "facid" + description = "Fluorosulfuric acid is a an extremely corrosive super-acid." + color = "#5050FF" + acidpwr = 42 + +/datum/reagent/acid/facid/on_mob_life(mob/living/M) + var/update_flags = STATUS_UPDATE_NONE + update_flags |= M.adjustToxLoss(1*REAGENTS_EFFECT_MULTIPLIER, FALSE) + return ..() | update_flags + +/datum/reagent/acid/facid/reaction_mob(mob/living/M, method = TOUCH, volume) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(method == TOUCH) + if(volume > 9) + if(!H.wear_mask && !H.head) + var/obj/item/organ/external/affecting = H.get_organ("head") + if(affecting) + affecting.disfigure() + H.adjustFireLoss(min(max(8, (volume - 5) * 3), 75)) + H.emote("scream") + return + else + var/melted_something = FALSE + if(H.wear_mask && !H.wear_mask.unacidable) + qdel(H.wear_mask) + H.update_inv_wear_mask() + to_chat(H, "Your [H.wear_mask] melts away!") + melted_something = TRUE + + if(H.head && !H.head.unacidable) + qdel(H.head) + H.update_inv_head() + to_chat(H, "Your [H.head] melts away!") + melted_something = TRUE + if(melted_something) + return + + if(volume >= 5) + H.emote("scream") + H.adjustFireLoss(min(max(8, (volume - 5) * 3), 75)) + to_chat(H, "The blueish acidic substance stings[volume < 5 ? " you, but isn't concentrated enough to harm you" : null]!") /datum/reagent/carpotoxin name = "Carpotoxin" @@ -620,62 +670,6 @@ M.emote("scream") return ..() | update_flags -/datum/reagent/facid - name = "Fluorosulfuric Acid" - id = "facid" - description = "Fluorosulfuric acid is a an extremely corrosive super-acid." - reagent_state = LIQUID - color = "#5050FF" - process_flags = ORGANIC | SYNTHETIC - taste_description = "ACID" - -/datum/reagent/facid/on_mob_life(mob/living/M) - var/update_flags = STATUS_UPDATE_NONE - update_flags |= M.adjustToxLoss(1*REAGENTS_EFFECT_MULTIPLIER, FALSE) - update_flags |= M.adjustFireLoss(1, FALSE) - return ..() | update_flags - -/datum/reagent/facid/reaction_mob(mob/living/M, method = TOUCH, volume) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(method == TOUCH) - if(volume > 9) - if(!H.wear_mask && !H.head) - var/obj/item/organ/external/affecting = H.get_organ("head") - if(affecting) - affecting.disfigure() - H.adjustFireLoss(min(max(8, (volume - 5) * 3), 75)) - H.emote("scream") - return - else - var/melted_something = FALSE - if(H.wear_mask && !H.wear_mask.unacidable) - qdel(H.wear_mask) - H.update_inv_wear_mask() - to_chat(H, "Your [H.wear_mask] melts away!") - melted_something = TRUE - - if(H.head && !H.head.unacidable) - qdel(H.head) - H.update_inv_head() - to_chat(H, "Your [H.head] melts away!") - melted_something = TRUE - if(melted_something) - return - - if(volume >= 5) - H.emote("scream") - H.adjustFireLoss(min(max(8, (volume - 5) * 3), 75)) - to_chat(H, "The blueish acidic substance stings[volume < 5 ? " you, but isn't concentrated enough to harm you" : null]!") - -/datum/reagent/facid/reaction_obj(obj/O, volume) - if((istype(O, /obj/item) || istype(O, /obj/structure/glowshroom))) - if(!O.unacidable) - var/obj/effect/decal/cleanable/molten_object/I = new/obj/effect/decal/cleanable/molten_object(O.loc) - I.desc = "Looks like this was \an [O] some time ago." - O.visible_message("[O] melts.") - qdel(O) - /datum/reagent/initropidril name = "Initropidril" id = "initropidril" diff --git a/code/modules/reagents/chemistry/reagents/water.dm b/code/modules/reagents/chemistry/reagents/water.dm index 64156a7cadd..c3f63083b2b 100644 --- a/code/modules/reagents/chemistry/reagents/water.dm +++ b/code/modules/reagents/chemistry/reagents/water.dm @@ -24,10 +24,14 @@ /datum/reagent/water/reaction_mob(mob/living/M, method = TOUCH, volume) M.water_act(volume, water_temperature, src, method) -/datum/reagent/water/reaction_turf(turf/simulated/T, volume) +/datum/reagent/water/reaction_turf(turf/T, volume) T.water_act(volume, water_temperature, src) + var/obj/effect/acid/A = (locate(/obj/effect/acid) in T) + if(A) + A.acid_level = max(A.acid_level - volume* 50, 0) /datum/reagent/water/reaction_obj(obj/O, volume) + O.acid_level = 0 O.water_act(volume, water_temperature, src) /datum/reagent/lube diff --git a/paradise.dme b/paradise.dme index cda0cebff3e..0f4bd815d39 100644 --- a/paradise.dme +++ b/paradise.dme @@ -200,6 +200,7 @@ #include "code\controllers\master.dm" #include "code\controllers\subsystem.dm" #include "code\controllers\verbs.dm" +#include "code\controllers\subsystem\acid.dm" #include "code\controllers\subsystem\afk.dm" #include "code\controllers\subsystem\air.dm" #include "code\controllers\subsystem\alarm.dm"