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"