From 9e71ddd20819fccc00e147594c825c05e817daab Mon Sep 17 00:00:00 2001 From: uraniummeltdown Date: Mon, 30 Oct 2017 20:54:17 +0400 Subject: [PATCH] splits effect_system.dm into multiple files --- code/game/objects/effects/effect_system.dm | 1276 ----------------- .../effects/effect_system/effect_system.dm | 62 + .../effects/effect_system/effects_foam.dm | 257 ++++ .../effects/effect_system/effects_other.dm | 176 +++ .../effects/effect_system/effects_smoke.dm | 489 +++++++ .../effects/effect_system/effects_sparks.dm | 148 ++ .../effects/effect_system/effects_water.dm | 131 ++ paradise.dme | 7 +- 8 files changed, 1269 insertions(+), 1277 deletions(-) delete mode 100644 code/game/objects/effects/effect_system.dm create mode 100644 code/game/objects/effects/effect_system/effect_system.dm create mode 100644 code/game/objects/effects/effect_system/effects_foam.dm create mode 100644 code/game/objects/effects/effect_system/effects_other.dm create mode 100644 code/game/objects/effects/effect_system/effects_smoke.dm create mode 100644 code/game/objects/effects/effect_system/effects_sparks.dm create mode 100644 code/game/objects/effects/effect_system/effects_water.dm diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm deleted file mode 100644 index 6cf11f4f3c8..00000000000 --- a/code/game/objects/effects/effect_system.dm +++ /dev/null @@ -1,1276 +0,0 @@ -/* This is an attempt to make some easily reusable "particle" type effect, to stop the code -constantly having to be rewritten. An item like the jetpack that uses the ion_trail_follow system, just has one -defined, then set up when it is created with New(). Then this same system can just be reused each time -it needs to create more trails.A beaker could have a steam_trail_follow system set up, then the steam -would spawn and follow the beaker, even if it is carried or thrown. -*/ - - -/obj/effect/effect - name = "effect" - icon = 'icons/effects/effects.dmi' - mouse_opacity = 0 - unacidable = 1//So effect are not targeted by alien acid. - -/obj/effect/effect/New() - ..() - if(ticker) - cameranet.updateVisibility(src) - -/obj/effect/effect/Destroy() - if(ticker) - cameranet.updateVisibility(src) - return ..() - -/datum/effect/proc/fadeOut(var/atom/A, var/frames = 16) - if(A.alpha == 0) //Handle already transparent case - return - if(frames == 0) - frames = 1 //We will just assume that by 0 frames, the coder meant "during one frame". - var/step = A.alpha / frames - for(var/i = 0, i < frames, i++) - A.alpha -= step - sleep(world.tick_lag) - return - -/obj/effect/effect/water - name = "water" - icon = 'icons/effects/effects.dmi' - icon_state = "extinguish" - var/life = 15.0 - mouse_opacity = 0 - -/obj/effect/effect/smoke - name = "smoke" - icon = 'icons/effects/water.dmi' - icon_state = "smoke" - opacity = 1 - anchored = 0.0 - mouse_opacity = 0 - var/amount = 8.0 - -/obj/effect/proc/delete() - qdel(src) - - -/obj/effect/effect/water/New() - ..() - //var/turf/T = src.loc - //if(istype(T, /turf)) - // T.firelevel = 0 //TODO: FIX - spawn( 70 ) - delete() - return - return - -/obj/effect/effect/water/Move(turf/newloc) - //var/turf/T = src.loc - //if(istype(T, /turf)) - // T.firelevel = 0 //TODO: FIX - if(--src.life < 1) - //SN src = null - delete() - if(newloc.density) - return 0 - .=..() - -/obj/effect/effect/water/Bump(atom/A) - if(reagents) - reagents.reaction(A) - if(istype(A,/atom/movable)) - var/atom/movable/AM = A - AM.water_act(life, 310.15, src) - return ..() - - -/datum/effect/system - var/number = 3 - var/cardinals = 0 - var/turf/location - var/atom/holder - var/setup = 0 - - Destroy() - holder = null - location = null - return ..() - - proc/set_up(n = 3, c = 0, turf/loc) - if(n > 10) - n = 10 - number = n - cardinals = c - location = loc - setup = 1 - - proc/attach(atom/atom) - holder = atom - - proc/start() - - -///////////////////////////////////////////// -// GENERIC STEAM SPREAD SYSTEM - -//Usage: set_up(number of bits of steam, use North/South/East/West only, spawn location) -// The attach(atom/atom) proc is optional, and can be called to attach the effect -// to something, like a smoking beaker, so then you can just call start() and the steam -// will always spawn at the items location, even if it's moved. - -/* Example: -var/datum/effect/system/steam_spread/steam = new /datum/effect/system/steam_spread() -- creates new system -steam.set_up(5, 0, mob.loc) -- sets up variables -OPTIONAL: steam.attach(mob) -steam.start() -- spawns the effect -*/ -///////////////////////////////////////////// -/obj/effect/effect/steam - name = "steam" - icon = 'icons/effects/effects.dmi' - icon_state = "extinguish" - density = 0 - -/datum/effect/system/steam_spread - - set_up(n = 3, c = 0, turf/loc) - if(n > 10) - n = 10 - number = n - cardinals = c - location = loc - - start() - var/i = 0 - for(i=0, i 10) - n = 10 - number = n - cardinals = c - if(istype(loca, /turf/)) - location = loca - else - location = get_turf(loca) - - start() - var/i = 0 - for(i=0, i 20) - return - spawn(0) - if(holder) - src.location = get_turf(holder) - var/obj/effect/effect/sparks/sparks = new /obj/effect/effect/sparks(src.location) - src.total_sparks++ - var/direction - if(src.cardinals) - direction = pick(cardinal) - else - direction = pick(alldirs) - for(i=0, i 10) - n = 10 - number = n - cardinals = c - if(istype(loca, /turf/)) - location = loca - else - location = get_turf(loca) - if(direct) - direction = direct - - - start() - var/i = 0 - for(i=0, i 20) - return - spawn(0) - if(holder) - src.location = get_turf(holder) - var/obj/effect/effect/harmless_smoke/smoke = new /obj/effect/effect/harmless_smoke(src.location) - src.total_smoke++ - var/direction = src.direction - if(!direction) - if(src.cardinals) - direction = pick(cardinal) - else - direction = pick(alldirs) - for(i=0, i 20) - n = 20 - number = n - cardinals = c - if(istype(loca, /turf/)) - location = loca - else - location = get_turf(loca) - if(direct) - direction = direct - - start() - var/i = 0 - for(i=0, i 20) - return - spawn(0) - if(holder) - src.location = get_turf(holder) - var/obj/effect/effect/bad_smoke/smoke = new /obj/effect/effect/bad_smoke(src.location) - src.total_smoke++ - var/direction = src.direction - if(!direction) - if(src.cardinals) - direction = pick(cardinal) - else - direction = pick(alldirs) - for(i=0, i 20) - n = 20 - number = n - cardinals = c - carry.copy_to(chemholder, carry.total_volume) - - - if(istype(loca, /turf/)) - location = loca - else - location = get_turf(loca) - if(direct) - direction = direct - if(!silent) - var/contained = "" - for(var/reagent in carry.reagent_list) - contained += " [reagent] " - if(contained) - contained = "\[[contained]\]" - var/area/A = get_area(location) - - var/where = "[A.name] | [location.x], [location.y]" - var/whereLink = "[where]" - - if(carry && carry.my_atom) - if(carry.my_atom.fingerprintslast) - var/mob/M = get_mob_by_key(carry.my_atom.fingerprintslast) - var/more = "" - if(M) - more = " " - msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink])[contained]. Last associated key is [carry.my_atom.fingerprintslast][more].", 0, 1) - log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last associated key is [carry.my_atom.fingerprintslast].") - else - msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink]). No associated key.", 0, 1) - log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key.") - else - msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink]). No associated key. CODERS: carry.my_atom may be null.", 0, 1) - log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key. CODERS: carry.my_atom may be null.") - - start(effect_range = 2) - var/i = 0 - - var/color = mix_color_from_reagents(chemholder.reagents.reagent_list) - var/obj/effect/effect/chem_smoke/smokeholder = new /obj/effect/effect/chem_smoke(src.location) - for(var/atom/A in view(effect_range, smokeholder)) - chemholder.reagents.reaction(A) - if(iscarbon(A)) - var/mob/living/carbon/C = A - if(C.can_breathe_gas()) - chemholder.reagents.copy_to(C, chemholder.reagents.total_volume) - qdel(smokeholder) - for(i=0, i 20) - return - spawn(0) - if(holder) - src.location = get_turf(holder) - var/obj/effect/effect/chem_smoke/smoke = new /obj/effect/effect/chem_smoke(src.location) - src.total_smoke++ - var/direction = src.direction - if(!direction) - if(src.cardinals) - direction = pick(cardinal) - else - direction = pick(alldirs) - - if(color) - smoke.icon += color // give the smoke color, if it has any to begin with - else - // if no color, just use the old smoke icon - smoke.icon = 'icons/effects/96x96.dmi' - smoke.icon_state = "smoke" - for(i=0, i 20) - n = 20 - number = n - cardinals = c - if(istype(loca, /turf/)) - location = loca - else - location = get_turf(loca) - if(direct) - direction = direct - - - start() - var/i = 0 - for(i=0, i 20) - return - spawn(0) - if(holder) - src.location = get_turf(holder) - var/obj/effect/effect/sleep_smoke/smoke = new /obj/effect/effect/sleep_smoke(src.location) - src.total_smoke++ - var/direction = src.direction - if(!direction) - if(src.cardinals) - direction = pick(cardinal) - else - direction = pick(alldirs) - for(i=0, i 20) - n = 20 - number = n - cardinals = c - if(istype(loca, /turf/)) - location = loca - else - location = get_turf(loca) - if(direct) - direction = direct - - start() - var/i = 0 - for(i=0, i 20) - return - spawn(0) - if(holder) - src.location = get_turf(holder) - var/obj/effect/effect/mustard_gas/smoke = new /obj/effect/effect/mustard_gas(src.location) - src.total_smoke++ - var/direction = src.direction - if(!direction) - if(src.cardinals) - direction = pick(cardinal) - else - direction = pick(alldirs) - for(i=0, i[user] smashes through \the [src].", "You smash through \the [src].") - qdel(src) - else - to_chat(user, "You hit the metal foam but bounce off it.") - -/obj/structure/foamedmetal/attackby(var/obj/item/I, var/mob/user, params) - user.changeNext_move(CLICK_CD_MELEE) - user.do_attack_animation(src) - if(istype(I, /obj/item/weapon/grab)) - var/obj/item/weapon/grab/G = I - G.affecting.loc = src.loc - user.visible_message("[G.assailant] smashes [G.affecting] through the foamed metal wall.") - qdel(I) - qdel(src) - return - - if(prob(I.force*20 - metal*25)) - user.visible_message("[user] smashes through the foamed metal with \the [I].", "You smash through the foamed metal with \the [I].") - qdel(src) - else - to_chat(user, "You hit the metal foam to no effect.") - -/obj/structure/foamedmetal/attack_animal(mob/living/simple_animal/M) - M.do_attack_animation(src) - if(M.melee_damage_upper == 0) - M.visible_message("[M] nudges \the [src].") - else - if(M.attack_sound) - playsound(loc, M.attack_sound, 50, 1, 1) - M.visible_message("\The [M] [M.attacktext] [src]!") - qdel(src) - -/obj/structure/foamedmetal/attack_alien(mob/living/carbon/alien/humanoid/M) - M.visible_message("[M] tears apart \the [src]!"); - qdel(src) - -/obj/structure/foamedmetal/CanPass(atom/movable/mover, turf/target, height=1.5) - return !density - -/obj/structure/foamedmetal/CanAtmosPass() - return !density - -/datum/effect/system/reagents_explosion - var/amount // TNT equivalent - var/flashing = 0 // does explosion creates flash effect? - var/flashing_factor = 0 // factor of how powerful the flash effect relatively to the explosion - - set_up (amt, loc, flash = 0, flash_fact = 0) - amount = amt - if(istype(loc, /turf/)) - location = loc - else - location = get_turf(loc) - - flashing = flash - flashing_factor = flash_fact - - return - - start() - if(amount <= 2) - var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread - s.set_up(2, 1, location) - s.start() - - for(var/mob/M in viewers(5, location)) - to_chat(M, "The solution violently explodes.") - for(var/mob/M in viewers(1, location)) - if(prob (50 * amount)) - to_chat(M, "The explosion knocks you down.") - M.Weaken(rand(1,5)) - return - else - var/devastation = -1 - var/heavy = -1 - var/light = -1 - var/flash = -1 - - // Clamp all values to MAX_EXPLOSION_RANGE - if(round(amount/12) > 0) - devastation = min (MAX_EX_DEVESTATION_RANGE, devastation + round(amount/12)) - - if(round(amount/6) > 0) - heavy = min (MAX_EX_HEAVY_RANGE, heavy + round(amount/6)) - - if(round(amount/3) > 0) - light = min (MAX_EX_LIGHT_RANGE, light + round(amount/3)) - - if(flash && flashing_factor) - flash += (round(amount/4) * flashing_factor) - - for(var/mob/M in viewers(8, location)) - to_chat(M, "The solution violently explodes.") - - explosion(location, devastation, heavy, light, flash) - - proc/holder_damage(var/atom/holder) - if(holder) - var/dmglevel = 4 - - if(round(amount/8) > 0) - dmglevel = 1 - else if(round(amount/4) > 0) - dmglevel = 2 - else if(round(amount/2) > 0) - dmglevel = 3 - - if(dmglevel<4) holder.ex_act(dmglevel) - - -////////////////////////////////// -//////SPARKLE FIREWORKS -///////////////////////////////// -//////////////////////////// -/obj/effect/sparkles - name = "sparkle" - icon = 'icons/obj/fireworks.dmi'//findback - icon_state = "sparkel" - var/amount = 6.0 - anchored = 1.0 - mouse_opacity = 0 - -/obj/effect/sparkles/New() - ..() - var/icon/I = new(src.icon,src.icon_state) - var/r = rand(0,255) - var/g = rand(0,255) - var/b = rand(0,255) - I.Blend(rgb(r,g,b),ICON_MULTIPLY) - src.icon = I - playsound(src.loc, "sparks", 100, 1) - var/turf/T = src.loc - if(istype(T, /turf)) - T.hotspot_expose(3000,100) - spawn (100) - qdel(src) - return - -/obj/effect/sparkles/Destroy() - var/turf/T = src.loc - if(istype(T, /turf)) - T.hotspot_expose(3000,100) - return ..() - -/obj/effect/sparkles/Move() - ..() - var/turf/T = src.loc - if(istype(T, /turf)) - T.hotspot_expose(3000,100) - return - - -/datum/effect/system/sparkle_spread - var/total_sparks = 0 // To stop it being spammed and lagging! - -/datum/effect/system/sparkle_spread/set_up(n = 3, c = 0, loca) - if(n > 10) - n = 10 - number = n - cardinals = c - if(istype(loca, /turf/)) - location = loca - else - location = get_turf(loca) - -/datum/effect/system/sparkle_spread/start() - var/i = 0 - for(i=0, i 20) - return - spawn(0) - if(holder) - src.location = get_turf(holder) - var/obj/effect/sparkles/sparks = new(src.location) - src.total_sparks++ - var/direction - if(src.cardinals) - direction = pick(cardinal) - else - direction = pick(alldirs) - for(i=0, i 10) + n = 10 + number = n + cardinals = c + location = loc + setup = 1 + + proc/attach(atom/atom) + holder = atom + + proc/start() diff --git a/code/game/objects/effects/effect_system/effects_foam.dm b/code/game/objects/effects/effect_system/effects_foam.dm new file mode 100644 index 00000000000..20eb653c185 --- /dev/null +++ b/code/game/objects/effects/effect_system/effects_foam.dm @@ -0,0 +1,257 @@ +// Foam +// Similar to smoke, but spreads out more +// metal foams leave behind a foamed metal wall + +/obj/structure/foam + name = "foam" + icon = 'icons/effects/effects.dmi' + icon_state = "foam" + opacity = 0 + anchored = 1 + density = 0 + layer = OBJ_LAYER + 0.9 + mouse_opacity = 0 + animate_movement = 0 + var/amount = 3 + var/expand = 1 + var/metal = 0 + + +/obj/structure/foam/New(loc, var/ismetal=0) + ..(loc) + icon_state = "[ismetal ? "m":""]foam" + if(!ismetal && reagents) + color = mix_color_from_reagents(reagents.reagent_list) + metal = ismetal + playsound(src, 'sound/effects/bubbles2.ogg', 80, 1, -3) + spawn(3 + metal*3) + process() + spawn(120) + processing_objects.Remove(src) + sleep(30) + + if(metal) + var/turf/T = get_turf(src) + if(istype(T, /turf/space)) + T.ChangeTurf(/turf/simulated/floor/plating/metalfoam) + var/turf/simulated/floor/plating/metalfoam/MF = get_turf(src) + MF.metal = metal + MF.update_icon() + + var/obj/structure/foamedmetal/M = new(src.loc) + M.metal = metal + M.updateicon() + + flick("[icon_state]-disolve", src) + sleep(5) + qdel(src) + return + +// on delete, transfer any reagents to the floor +/obj/structure/foam/Destroy() + if(!metal && reagents) + reagents.handle_reactions() + for(var/atom/A in oview(1, src)) + if(A == src) + continue + if(reagents.total_volume) + var/fraction = 5 / reagents.total_volume + reagents.reaction(A, TOUCH, fraction) + return ..() + +/obj/structure/foam/process() + if(--amount < 0) + return + + + for(var/direction in cardinal) + + + var/turf/T = get_step(src,direction) + if(!T) + continue + + if(!T.Enter(src)) + continue + + var/obj/structure/foam/F = locate() in T + if(F) + continue + + F = new /obj/structure/foam(T, metal) + F.amount = amount + if(!metal) + F.create_reagents(15) + if(reagents) + for(var/datum/reagent/R in reagents.reagent_list) + F.reagents.add_reagent(R.id, min(R.volume, 3), R.data, reagents.chem_temp) + F.color = mix_color_from_reagents(reagents.reagent_list) + +// foam disolves when heated +// except metal foams +/obj/structure/foam/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(!metal && prob(max(0, exposed_temperature - 475))) + flick("[icon_state]-disolve", src) + + spawn(5) + qdel(src) + + +/obj/structure/foam/Crossed(var/atom/movable/AM) + if(metal) + return + + if(istype(AM, /mob/living/carbon)) + var/mob/living/carbon/M = AM + if(M.slip("foam", 5, 2)) + if(reagents) + for(var/reagent_id in reagents.reagent_list) + var/amount = M.reagents.get_reagent_amount(reagent_id) + if(amount < 25) + M.reagents.add_reagent(reagent_id, min(round(amount / 2), 15)) + if(reagents.total_volume) + var/fraction = 5 / reagents.total_volume + reagents.reaction(M, TOUCH, fraction) + + +/datum/effect/system/foam_spread + var/amount = 5 // the size of the foam spread. + var/list/carried_reagents // the IDs of reagents present when the foam was mixed + var/metal = 0 // 0=foam, 1=metalfoam, 2=ironfoam + var/temperature = T0C + var/list/banned_reagents = list("smoke_powder", "fluorosurfactant", "stimulants") + +/datum/effect/system/foam_spread/set_up(amt=5, loca, var/datum/reagents/carry = null, var/metalfoam = 0) + amount = min(round(amt/5, 1), 7) + if(istype(loca, /turf/)) + location = loca + else + location = get_turf(loca) + + carried_reagents = list() + metal = metalfoam + temperature = carry.chem_temp + + // bit of a hack here. Foam carries along any reagent also present in the glass it is mixed + // with (defaults to water if none is present). Rather than actually transfer the reagents, + // this makes a list of the reagent ids and spawns 1 unit of that reagent when the foam disolves. + + if(carry && !metal) + for(var/datum/reagent/R in carry.reagent_list) + carried_reagents[R.id] = R.volume + +/datum/effect/system/foam_spread/start() + spawn(0) + var/obj/structure/foam/F = locate() in location + if(F) + F.amount += amount + F.amount = min(F.amount, 27) + return + + F = new /obj/structure/foam(location, metal) + F.amount = amount + + if(!metal) // don't carry other chemicals if a metal foam + F.create_reagents(15) + + if(carried_reagents) + for(var/id in carried_reagents) + if(banned_reagents.Find("[id]")) + continue + var/datum/reagent/reagent_volume = carried_reagents[id] + F.reagents.add_reagent(id, min(reagent_volume, 3), null, temperature) + F.color = mix_color_from_reagents(F.reagents.reagent_list) + else + F.reagents.add_reagent("cleaner", 1) + F.color = mix_color_from_reagents(F.reagents.reagent_list) + +// wall formed by metal foams +// dense and opaque, but easy to break + + +/obj/structure/foamedmetal + icon = 'icons/effects/effects.dmi' + icon_state = "metalfoam" + density = 1 + opacity = 1 // changed in New() + anchored = 1 + name = "foamed metal" + desc = "A lightweight foamed metal wall." + var/metal = MFOAM_ALUMINUM + +/obj/structure/foamedmetal/initialize() + ..() + air_update_turf(1) + +/obj/structure/foamedmetal/Destroy() + density = 0 + air_update_turf(1) + return ..() + +/obj/structure/foamedmetal/Move() + var/turf/T = loc + ..() + move_update_air(T) + +/obj/structure/foamedmetal/proc/updateicon() + if(metal == MFOAM_ALUMINUM) + icon_state = "metalfoam" + else + icon_state = "ironfoam" + + +/obj/structure/foamedmetal/ex_act(severity) + qdel(src) + +/obj/structure/foamedmetal/blob_act() + qdel(src) + +/obj/structure/foamedmetal/bullet_act() + if(metal==MFOAM_ALUMINUM || prob(50)) + qdel(src) + +/obj/structure/foamedmetal/attack_hand(var/mob/user) + user.changeNext_move(CLICK_CD_MELEE) + user.do_attack_animation(src) + if((HULK in user.mutations) || (prob(75 - metal*25))) + user.visible_message("[user] smashes through \the [src].", "You smash through \the [src].") + qdel(src) + else + to_chat(user, "You hit the metal foam but bounce off it.") + +/obj/structure/foamedmetal/attackby(var/obj/item/I, var/mob/user, params) + user.changeNext_move(CLICK_CD_MELEE) + user.do_attack_animation(src) + if(istype(I, /obj/item/weapon/grab)) + var/obj/item/weapon/grab/G = I + G.affecting.loc = src.loc + user.visible_message("[G.assailant] smashes [G.affecting] through the foamed metal wall.") + qdel(I) + qdel(src) + return + + if(prob(I.force*20 - metal*25)) + user.visible_message("[user] smashes through the foamed metal with \the [I].", "You smash through the foamed metal with \the [I].") + qdel(src) + else + to_chat(user, "You hit the metal foam to no effect.") + +/obj/structure/foamedmetal/attack_animal(mob/living/simple_animal/M) + M.do_attack_animation(src) + if(M.melee_damage_upper == 0) + M.visible_message("[M] nudges \the [src].") + else + if(M.attack_sound) + playsound(loc, M.attack_sound, 50, 1, 1) + M.visible_message("\The [M] [M.attacktext] [src]!") + qdel(src) + +/obj/structure/foamedmetal/attack_alien(mob/living/carbon/alien/humanoid/M) + M.visible_message("[M] tears apart \the [src]!"); + qdel(src) + +/obj/structure/foamedmetal/CanPass(atom/movable/mover, turf/target, height=1.5) + return !density + +/obj/structure/foamedmetal/CanAtmosPass() + return !density diff --git a/code/game/objects/effects/effect_system/effects_other.dm b/code/game/objects/effects/effect_system/effects_other.dm new file mode 100644 index 00000000000..69246db2859 --- /dev/null +++ b/code/game/objects/effects/effect_system/effects_other.dm @@ -0,0 +1,176 @@ +///////////////////////////////////////////// +//////// Attach an Ion trail to any object, that spawns when it moves (like for the jetpack) +/// just pass in the object to attach it to in set_up +/// Then do start() to start it and stop() to stop it, obviously +/// and don't call start() in a loop that will be repeated otherwise it'll get spammed! +///////////////////////////////////////////// + +/obj/effect/effect/ion_trails + name = "ion trails" + icon_state = "ion_trails" + anchored = 1.0 + +/datum/effect/system/ion_trail_follow + var/turf/oldposition + var/processing = 1 + var/on = 1 + +/datum/effect/system/ion_trail_follow/Destroy() + oldposition = null + return ..() + +/datum/effect/system/ion_trail_follow/set_up(atom/atom) + attach(atom) + +/datum/effect/system/ion_trail_follow/start() //Whoever is responsible for this abomination of code should become an hero + if(!src.on) + src.on = 1 + src.processing = 1 + if(src.processing) + src.processing = 0 + var/turf/T = get_turf(src.holder) + if(T != src.oldposition) + if(!has_gravity(T)) + var/obj/effect/effect/ion_trails/I = new /obj/effect/effect/ion_trails(src.oldposition) + I.dir = src.holder.dir + flick("ion_fade", I) + I.icon_state = "" + spawn( 20 ) + if(I) + I.delete() + src.oldposition = T + spawn(2) + if(src.on) + src.processing = 1 + src.start() + +/datum/effect/system/ion_trail_follow/proc/stop() + src.processing = 0 + src.on = 0 + oldposition = null + +/datum/effect/system/ion_trail_follow/space_trail + var/turf/oldloc // secondary ion trail loc + var/turf/currloc + +/datum/effect/system/ion_trail_follow/space_trail/Destroy() + oldloc = null + currloc = null + return ..() + +/datum/effect/system/ion_trail_follow/space_trail/start() + if(!src.on) + src.on = 1 + src.processing = 1 + if(src.processing) + src.processing = 0 + spawn(0) + var/turf/T = get_turf(src.holder) + if(currloc != T) + switch(holder.dir) + if(NORTH) + src.oldposition = T + src.oldposition = get_step(oldposition, SOUTH) + src.oldloc = get_step(oldposition,EAST) + //src.oldloc = get_step(oldloc, SOUTH) + if(SOUTH) // More difficult, offset to the north! + src.oldposition = get_step(holder,NORTH) + src.oldposition = get_step(oldposition,NORTH) + src.oldloc = get_step(oldposition,EAST) + //src.oldloc = get_step(oldloc,NORTH) + if(EAST) // Just one to the north should suffice + src.oldposition = T + src.oldposition = get_step(oldposition, WEST) + src.oldloc = get_step(oldposition,NORTH) + //src.oldloc = get_step(oldloc,WEST) + if(WEST) // One to the east and north from there + src.oldposition = get_step(holder,EAST) + src.oldposition = get_step(oldposition,EAST) + src.oldloc = get_step(oldposition,NORTH) + //src.oldloc = get_step(oldloc,EAST) + if(istype(T, /turf/space)) + var/obj/effect/effect/ion_trails/I = new /obj/effect/effect/ion_trails(src.oldposition) + var/obj/effect/effect/ion_trails/II = new /obj/effect/effect/ion_trails(src.oldloc) + //src.oldposition = T + I.dir = src.holder.dir + II.dir = src.holder.dir + flick("ion_fade", I) + flick("ion_fade", II) + I.icon_state = "" + II.icon_state = "" + spawn( 20 ) + if(I) I.delete() + if(II) II.delete() + spawn(2) + if(src.on) + src.processing = 1 + src.start() + currloc = T + +//Reagent-based explosion effect +/datum/effect/system/reagents_explosion + var/amount // TNT equivalent + var/flashing = 0 // does explosion creates flash effect? + var/flashing_factor = 0 // factor of how powerful the flash effect relatively to the explosion + + set_up (amt, loc, flash = 0, flash_fact = 0) + amount = amt + if(istype(loc, /turf/)) + location = loc + else + location = get_turf(loc) + + flashing = flash + flashing_factor = flash_fact + + return + + start() + if(amount <= 2) + var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread + s.set_up(2, 1, location) + s.start() + + for(var/mob/M in viewers(5, location)) + to_chat(M, "The solution violently explodes.") + for(var/mob/M in viewers(1, location)) + if(prob (50 * amount)) + to_chat(M, "The explosion knocks you down.") + M.Weaken(rand(1,5)) + return + else + var/devastation = -1 + var/heavy = -1 + var/light = -1 + var/flash = -1 + + // Clamp all values to MAX_EXPLOSION_RANGE + if(round(amount/12) > 0) + devastation = min (MAX_EX_DEVESTATION_RANGE, devastation + round(amount/12)) + + if(round(amount/6) > 0) + heavy = min (MAX_EX_HEAVY_RANGE, heavy + round(amount/6)) + + if(round(amount/3) > 0) + light = min (MAX_EX_LIGHT_RANGE, light + round(amount/3)) + + if(flash && flashing_factor) + flash += (round(amount/4) * flashing_factor) + + for(var/mob/M in viewers(8, location)) + to_chat(M, "The solution violently explodes.") + + explosion(location, devastation, heavy, light, flash) + + proc/holder_damage(var/atom/holder) + if(holder) + var/dmglevel = 4 + + if(round(amount/8) > 0) + dmglevel = 1 + else if(round(amount/4) > 0) + dmglevel = 2 + else if(round(amount/2) > 0) + dmglevel = 3 + + if(dmglevel<4) holder.ex_act(dmglevel) diff --git a/code/game/objects/effects/effect_system/effects_smoke.dm b/code/game/objects/effects/effect_system/effects_smoke.dm new file mode 100644 index 00000000000..6f5ca6d6359 --- /dev/null +++ b/code/game/objects/effects/effect_system/effects_smoke.dm @@ -0,0 +1,489 @@ +///////////////////////////////////////////// +//// SMOKE SYSTEMS +// direct can be optinally added when set_up, to make the smoke always travel in one direction +// in case you wanted a vent to always smoke north for example +///////////////////////////////////////////// + +/obj/effect/effect/smoke + name = "smoke" + icon = 'icons/effects/water.dmi' + icon_state = "smoke" + opacity = 1 + anchored = 0.0 + mouse_opacity = 0 + var/amount = 8.0 + +/obj/effect/effect/harmless_smoke + name = "smoke" + icon_state = "smoke" + opacity = 1 + anchored = 0.0 + mouse_opacity = 0 + var/amount = 6.0 + //Remove this bit to use the old smoke + icon = 'icons/effects/96x96.dmi' + pixel_x = -32 + pixel_y = -32 + +/obj/effect/effect/harmless_smoke/New() + ..() + spawn (100) + delete() + return + +/obj/effect/effect/harmless_smoke/Move() + ..() + return + +/datum/effect/system/harmless_smoke_spread + var/total_smoke = 0 // To stop it being spammed and lagging! + var/direction + + set_up(n = 5, c = 0, loca, direct) + if(n > 10) + n = 10 + number = n + cardinals = c + if(istype(loca, /turf/)) + location = loca + else + location = get_turf(loca) + if(direct) + direction = direct + + + start() + var/i = 0 + for(i=0, i 20) + return + spawn(0) + if(holder) + src.location = get_turf(holder) + var/obj/effect/effect/harmless_smoke/smoke = new /obj/effect/effect/harmless_smoke(src.location) + src.total_smoke++ + var/direction = src.direction + if(!direction) + if(src.cardinals) + direction = pick(cardinal) + else + direction = pick(alldirs) + for(i=0, i 20) + n = 20 + number = n + cardinals = c + if(istype(loca, /turf/)) + location = loca + else + location = get_turf(loca) + if(direct) + direction = direct + + start() + var/i = 0 + for(i=0, i 20) + return + spawn(0) + if(holder) + src.location = get_turf(holder) + var/obj/effect/effect/bad_smoke/smoke = new /obj/effect/effect/bad_smoke(src.location) + src.total_smoke++ + var/direction = src.direction + if(!direction) + if(src.cardinals) + direction = pick(cardinal) + else + direction = pick(alldirs) + for(i=0, i 20) + n = 20 + number = n + cardinals = c + carry.copy_to(chemholder, carry.total_volume) + + + if(istype(loca, /turf/)) + location = loca + else + location = get_turf(loca) + if(direct) + direction = direct + if(!silent) + var/contained = "" + for(var/reagent in carry.reagent_list) + contained += " [reagent] " + if(contained) + contained = "\[[contained]\]" + var/area/A = get_area(location) + + var/where = "[A.name] | [location.x], [location.y]" + var/whereLink = "[where]" + + if(carry && carry.my_atom) + if(carry.my_atom.fingerprintslast) + var/mob/M = get_mob_by_key(carry.my_atom.fingerprintslast) + var/more = "" + if(M) + more = " " + msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink])[contained]. Last associated key is [carry.my_atom.fingerprintslast][more].", 0, 1) + log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last associated key is [carry.my_atom.fingerprintslast].") + else + msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink]). No associated key.", 0, 1) + log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key.") + else + msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink]). No associated key. CODERS: carry.my_atom may be null.", 0, 1) + log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key. CODERS: carry.my_atom may be null.") + + start(effect_range = 2) + var/i = 0 + + var/color = mix_color_from_reagents(chemholder.reagents.reagent_list) + var/obj/effect/effect/chem_smoke/smokeholder = new /obj/effect/effect/chem_smoke(src.location) + for(var/atom/A in view(effect_range, smokeholder)) + chemholder.reagents.reaction(A) + if(iscarbon(A)) + var/mob/living/carbon/C = A + if(C.can_breathe_gas()) + chemholder.reagents.copy_to(C, chemholder.reagents.total_volume) + qdel(smokeholder) + for(i=0, i 20) + return + spawn(0) + if(holder) + src.location = get_turf(holder) + var/obj/effect/effect/chem_smoke/smoke = new /obj/effect/effect/chem_smoke(src.location) + src.total_smoke++ + var/direction = src.direction + if(!direction) + if(src.cardinals) + direction = pick(cardinal) + else + direction = pick(alldirs) + + if(color) + smoke.icon += color // give the smoke color, if it has any to begin with + else + // if no color, just use the old smoke icon + smoke.icon = 'icons/effects/96x96.dmi' + smoke.icon_state = "smoke" + for(i=0, i 20) + n = 20 + number = n + cardinals = c + if(istype(loca, /turf/)) + location = loca + else + location = get_turf(loca) + if(direct) + direction = direct + + + start() + var/i = 0 + for(i=0, i 20) + return + spawn(0) + if(holder) + src.location = get_turf(holder) + var/obj/effect/effect/sleep_smoke/smoke = new /obj/effect/effect/sleep_smoke(src.location) + src.total_smoke++ + var/direction = src.direction + if(!direction) + if(src.cardinals) + direction = pick(cardinal) + else + direction = pick(alldirs) + for(i=0, i 20) + n = 20 + number = n + cardinals = c + if(istype(loca, /turf/)) + location = loca + else + location = get_turf(loca) + if(direct) + direction = direct + + start() + var/i = 0 + for(i=0, i 20) + return + spawn(0) + if(holder) + src.location = get_turf(holder) + var/obj/effect/effect/mustard_gas/smoke = new /obj/effect/effect/mustard_gas(src.location) + src.total_smoke++ + var/direction = src.direction + if(!direction) + if(src.cardinals) + direction = pick(cardinal) + else + direction = pick(alldirs) + for(i=0, i 10) + n = 10 + number = n + cardinals = c + if(istype(loca, /turf/)) + location = loca + else + location = get_turf(loca) + + start() + var/i = 0 + for(i=0, i 20) + return + spawn(0) + if(holder) + src.location = get_turf(holder) + var/obj/effect/effect/sparks/sparks = new /obj/effect/effect/sparks(src.location) + src.total_sparks++ + var/direction + if(src.cardinals) + direction = pick(cardinal) + else + direction = pick(alldirs) + for(i=0, i 10) + n = 10 + number = n + cardinals = c + if(istype(loca, /turf/)) + location = loca + else + location = get_turf(loca) + +/datum/effect/system/sparkle_spread/start() + var/i = 0 + for(i=0, i 20) + return + spawn(0) + if(holder) + src.location = get_turf(holder) + var/obj/effect/sparkles/sparks = new(src.location) + src.total_sparks++ + var/direction + if(src.cardinals) + direction = pick(cardinal) + else + direction = pick(alldirs) + for(i=0, i 10) + n = 10 + number = n + cardinals = c + location = loc + + start() + var/i = 0 + for(i=0, i