The Paint & Linen Update [Splinter 2]: Splashplosions (#35528)

* Soft Reset

* gotta set up the FLAXOIL define

* test_reach

* deprecated comment has left the building
This commit is contained in:
DeityLink
2023-12-11 00:01:20 +01:00
committed by GitHub
parent 00e584b333
commit f90d45fb46
16 changed files with 368 additions and 108 deletions

View File

@@ -236,6 +236,8 @@
#define isfloor(A) (istype(A, /turf/simulated/floor) || istype(A, /turf/unsimulated/floor) || istype(A, /turf/simulated/floor/shuttle) || istype(A, /turf/simulated/floor/shuttle/brig))
#define iswall(A) (istype(A, /turf/simulated/wall) || istype(A, /turf/unsimulated/wall))
#define isshuttleturf(A) (istype(A, /turf/simulated/wall/shuttle) || istype(A, /turf/simulated/floor/shuttle))
#define issilent(A) (A.silent || (ishuman(A) && (A.mind && A.mind.miming || A:species:flags & SPECIES_NO_MOUTH))) //Remember that silent is not the same as miming. Miming you can emote, silent you can't gesticulate at all

View File

@@ -524,6 +524,8 @@
#define MIMOSA "mimosa"
#define LEMONDROP "lemondrop"
#define FLAXOIL "flax_oil"
// How many units of reagent are consumed per tick, by default.
#define REAGENTS_METABOLISM 0.2

View File

@@ -201,3 +201,14 @@ var/static/list/counterclockwise_perpendicular_dirs = list(EAST,WEST,EAST|WEST,S
return "↙"
if(NORTHWEST)
return "↖"
/proc/splitdiagonals(var/dir)
switch(dir)
if(NORTHEAST)
return list(NORTH,EAST)
if(SOUTHEAST)
return list(SOUTH,EAST)
if(SOUTHWEST)
return list(SOUTH,WEST)
if(NORTHWEST)
return list(NORTH,WEST)

View File

@@ -22,6 +22,8 @@
var/vector/origin_floored //the floored origin vector
var/vector/direction //direction of the ray
var/original_damage //original damage of the ray when applicable
var/turf/final_turf
var/turf/previous_turf
/ray/proc/toString()
return "\[Ray\](\n- origin = " + origin.toString() + "\n- origin_floored = "+ origin_floored.toString() + "\n- direction = " + direction.toString() + "\n- z-level = " + num2text(z) + "\n)"
@@ -112,6 +114,10 @@
//our result
var/list/rayCastHit/hits = list()
var/turf/T = vector2turf(origin.floored(), z)
previous_turf = T
final_turf = T
while(distance < max_distance)
//moving one step further
pointer += a_step
@@ -134,7 +140,10 @@
continue
//getting the turf at our current (floored) vector
var/turf/T = vector2turf(new_position, z)
T = vector2turf(new_position, z)
if (!T.density)
previous_turf = final_turf
final_turf = T
//trying hit at turf
var/rayCastHitInfo/info = new /rayCastHitInfo(src, makeweakref(T), new_position, new_position_unfloored, distance)

View File

@@ -0,0 +1,128 @@
//test_reach(), by Deity Link
//Basically sends a cheap projectile that moves from a turf A to a turf B in a "straight" line. Returns true if it reaches turf B without hitting anything on the way there (other than turf B itself)
//Useful for instance to check if an item thrown/projectile fired from a A to B would reach its target
/proc/test_reach(var/turf/origin,var/turf/destination,var/_pass_flags=0)
if (!origin || !destination)
return FALSE
if (origin.z != destination.z)
return FALSE
if (origin == destination)
return TRUE
var/obj/test_reach/test = new(origin,destination,_pass_flags)
var/result = test.main()
qdel(test)
return result
//////////////////////////////////////////////////////////////////////////////////////////////
/obj/test_reach
invisibility = 101
pass_flags = 0
var/dist_x
var/dist_y
var/dx = 0
var/dy = 0
var/error = 0
var/target_angle = 0
var/bumped = 0
var/max_range = 100
var/turf/starting
var/turf/target
var/result = FALSE
var/finished = FALSE
/obj/test_reach/New(var/turf/loc,var/turf/destination,var/_pass_flags)
..()
starting = loc
target = destination
pass_flags = _pass_flags
/obj/test_reach/proc/main()
//let's do our first movement by carefully going around any adjacent wall if another cardinal direction toward our destination is possible
//this fixes a quirk with bresenham paths where it may decide to run into adjacent walls on its first step even when it doesn't make "sense"
var/orientation = get_dir(loc,target)
if (orientation in diagonal)
var/turf/gotta_move = null
for (var/direction in splitdiagonals(orientation))
var/turf/T = get_step(loc,direction)
if (!T.density && T.Adjacent(src))
if (!gotta_move)
gotta_move = T
else
gotta_move = null
if (gotta_move)
loc = gotta_move
starting = loc
if (starting == target)
return TRUE
//init
dist_x = abs(target.x - starting.x)
dist_y = abs(target.y - starting.y)
if (target.x > starting.x)
dx = EAST
else
dx = WEST
if (target.y > starting.y)
dy = NORTH
else
dy = SOUTH
if(dist_x > dist_y)
error = dist_x/2 - dist_y
else
error = dist_y/2 - dist_x
//main loop
while(loc && !finished)
loop()
return result
/obj/test_reach/proc/loop()
if(loc && !finished)
if(dist_x > dist_y)
bresenham_step(dist_x,dist_y,dx,dy)
else
bresenham_step(dist_y,dist_x,dy,dx)
bumped = 0
/obj/test_reach/proc/bresenham_step(var/distA, var/distB, var/dA, var/dB)//based on the code I wrote forever ago in projectiles.dm
if(max_range < 1)
finished = TRUE
return
max_range--
if(error < 0)
var/atom/step = get_step(src, dB)
if(!step)
finished = TRUE
return
Move(step)
error += distA
if (loc == target)
result = TRUE
finished = TRUE
else
var/atom/step = get_step(src, dA)
if(!step)
finished = TRUE
return
Move(step)
error -= distB
dir = dA
if(error < 0)
dir = dA + dB
if (loc == target)
result = TRUE
finished = TRUE
/obj/test_reach/to_bump(var/atom/A)
if (A == target)
result = TRUE
finished = TRUE
else
finished = TRUE

View File

@@ -451,6 +451,12 @@
return TRUE
if(locate(/obj/effect/unwall_field) in loc) //Annoying workaround for this -kanef
return TRUE
if(istype(mover, /obj/item/projectile/beam))
var/obj/item/projectile/beam/B = mover
var/returns = bounds_dist(src, B.previous_turf) >= 0
if (returns && B.previous_turf)
B.final_turf = B.previous_turf
return returns
return bounds_dist(src, mover) >= 0
// harderforce is for things like lighting overlays which should only be moved in EXTREMELY specific sitations.

View File

@@ -110,12 +110,16 @@ steam.start() -- spawns the effect
icon_state = "extinguish"
density = 0
/datum/effect/system/steam_spread/set_up(n = 3, c = 0, turf/loc)
/datum/effect/system/steam_spread
var/color
/datum/effect/system/steam_spread/set_up(n = 3, c = 0, turf/loc, var/_color = null)
if(n > 10)
n = 10
number = n
cardinals = c
location = loc
color = _color
/datum/effect/system/steam_spread/start()
var/i = 0
@@ -124,6 +128,9 @@ steam.start() -- spawns the effect
if(holder)
src.location = get_turf(holder)
var/obj/effect/steam/steam = new /obj/effect/steam(src.location)
if (color)
steam.icon_state = "extinguish_gray"
steam.color = color
var/direction
if(src.cardinals)
direction = pick(cardinal)

View File

@@ -297,16 +297,8 @@
reservoir.reagents.trans_to(src, reservoir.reagents.total_volume)
if(src.reagents.total_volume) //The possible reactions didnt use up all reagents.
var/datum/effect/system/steam_spread/steam = new /datum/effect/system/steam_spread()
steam.set_up(10, 0, get_turf(src))
steam.attach(src)
steam.start()
for(var/atom/A in view(affected_area, get_turf(src)))
if( A == src )
continue
src.reagents.reaction(A, 1, 10)
if(reagents.total_volume) //The possible reactions didnt use up all reagents.
reagents.splashplosion(affected_area)
invisibility = INVISIBILITY_MAXIMUM //Why am i doing this?
spawn(50) //To make sure all reagents can work

View File

@@ -223,7 +223,10 @@ var/list/one_way_windows
return TRUE
if(!density)
return TRUE
if(istype(mover))
if(istype(mover, /obj/item/projectile/beam))
var/obj/item/projectile/beam/B = mover
return bounds_dist(border_dummy, B.previous_turf) >= 0
else if(istype(mover))
return bounds_dist(border_dummy, mover) >= 0
else if(get_dir(loc, target) == dir)
return FALSE

View File

@@ -12,10 +12,16 @@
w_class = W_CLASS_MEDIUM
fire_delay = 1
fire_sound = 'sound/weapons/shotgun.ogg'
empty_sound = 'sound/weapons/magazine_load_click.ogg'
conventional_firearm = 0
var/hard = 1 //When toggled on, the gun's shots will deal damage. When off, they deal no damage, but deliver five times the reagents.
var/max_reagents = 50
var/obj/item/projectile/projectile_type = /obj/item/projectile/bullet/liquid_blob
var/mixed_color = null
var/mixed_alpha = 255
var/radius = 0
/obj/item/weapon/gun/siren/isHandgun()
return FALSE
@@ -24,6 +30,15 @@
create_reagents(max_reagents)
reagents.add_reagent(WATER, max_reagents)
/obj/item/weapon/gun/siren/click_empty(mob/user = null)
if (user)
if(empty_sound)
to_chat(user, "<span class='warning'>No liquid left inside \the [src]</span>")
playsound(user, empty_sound, 100, 1)
else
if(empty_sound)
playsound(src, empty_sound, 100, 1)
/obj/item/weapon/gun/siren/verb/flush_reagents()
set name = "Flush contents"
set category = "Object"
@@ -38,9 +53,13 @@
if(in_chamber)
QDEL_NULL(in_chamber)
/obj/item/weapon/gun/siren/on_reagent_change()
mixed_color = mix_color_from_reagents(reagents.reagent_list)
mixed_alpha = mix_alpha_from_reagents(reagents.reagent_list)
/obj/item/weapon/gun/siren/examine(mob/user)
..()
to_chat(user, "<span class='info'>It has [round(reagents.total_volume/10)] round\s remaining.</span>")
to_chat(user, "<span class='info'>It has [round(reagents.total_volume/5)] round\s remaining.</span>")
if(hard >= 0)
if(hard)
to_chat(user, "<span class='info'>It is set to \"hard liquid\".</span>")
@@ -54,11 +73,13 @@
desc = initial(desc)
fire_sound = initial(fire_sound)
recoil = 1
radius = 0
else
to_chat(user, "<span class='info'>You set \the [src] to fire soft liquid.</span>")
desc = "The most efficient ranged mass reagent delivery system there is."
fire_sound = 'sound/items/egg_squash.ogg'
recoil = 0
radius = 1
/obj/item/weapon/gun/siren/afterattack(atom/A, mob/living/user, flag, params, struggle = 0)
if(flag)
@@ -67,7 +88,7 @@
to_chat(user, "<span class='warning'>A label sticks the trigger to the trigger guard!</span>")//Such a new feature, the player might not know what's wrong if it doesn't tell them.
return
if(reagents.total_volume < 10)
if(reagents.total_volume < 5)
return click_empty(user)
if(in_chamber)
if(in_chamber.reagents && in_chamber.reagents.total_volume)
@@ -78,18 +99,18 @@
in_chamber.reagents.remove_reagent(R.id, reagents.get_reagent_amount(R.id)*4)
in_chamber.reagents.trans_to(src, in_chamber.reagents.total_volume)
QDEL_NULL(in_chamber)
in_chamber = new projectile_type(src, hard)
reagents.trans_to(in_chamber, 10)
if(!hard) //When set to no-damage mode, each shot has five times the reagents.
in_chamber = new projectile_type(src, hard, mixed_color, mixed_alpha, radius)
reagents.trans_to(in_chamber, 5)
if(!hard) //When set to no-damage mode, each shot has ten times the reagents.
for(var/datum/reagent/R in in_chamber.reagents.reagent_list)
in_chamber.reagents.add_reagent(R.id, reagents.get_reagent_amount(R.id)*4)
R.volume *= 10
Fire(A,user,params, "struggle" = struggle)
/obj/item/weapon/gun/siren/process_chambered()
return in_chamber
/obj/item/weapon/gun/siren/can_discharge()
if(reagents.total_volume < 10)
if(reagents.total_volume < 5)
return 1
/obj/item/weapon/gun/siren/caduceus
@@ -118,7 +139,7 @@
/obj/item/weapon/gun/siren/supersoaker
name = "super soaker"
desc = "For ages 10 and up."
desc = "For ages 10 and up. Pump it to shoot further."
icon_state = "super_soaker"
item_state = "super_soaker"
inhand_states = list("left_hand" = 'icons/mob/in-hand/left/guns.dmi', "right_hand" = 'icons/mob/in-hand/right/guns.dmi')
@@ -139,16 +160,18 @@
if(harm_labeled >= min_harm_label)
to_chat(user, "<span class='warning'>A label sticks the trigger to the trigger guard!</span>")//Such a new feature, the player might not know what's wrong if it doesn't tell them.
return
if(reagents.total_volume < 10 && !in_chamber)
if(reagents.total_volume < 5 && !in_chamber)
return click_empty(user)
if(!in_chamber)
in_chamber = new projectile_type(src, max(3+(round(pumps/2)),15))
reagents.trans_to(in_chamber, 10)
in_chamber = new projectile_type(src, min(3+(round(pumps/2)),15), mixed_color, mixed_alpha)
reagents.trans_to(in_chamber, 5)
for(var/datum/reagent/R in in_chamber.reagents.reagent_list)
R.volume *= 4//so here we're just doubling our quantity of reagents from 10 to 20//moved from projectile code
in_chamber.firer = user
Fire(A,user,params, struggle = struggle)
if(reagents.total_volume >= 10)
in_chamber = new projectile_type(src)
reagents.trans_to(in_chamber, 10)
if(pumps > 0)
pumps--
QDEL_NULL(in_chamber)
/obj/item/weapon/gun/siren/supersoaker/attack_self(mob/user)
if(world.time - last_pump >= 1)

View File

@@ -46,7 +46,8 @@ var/list/beam_master = list()
var/turf/T = vector2turf(info.point, z)
T.last_beam_damage = fired_beam.damage
fired_beam.final_turf = final_turf
fired_beam.previous_turf = previous_turf
if(!A.Cross(fired_beam, T) || (!isturf(fired_beam.original) && A == fired_beam.original))
var/ret = fired_beam.to_bump(A)
if(ret)
@@ -82,6 +83,8 @@ var/list/beam_master = list()
var/beam_color = null
var/beam_shift = null// the beam will animate() toward this color after being fired
var/list/ray/past_rays = list() //full of rays
var/turf/final_turf = null
var/turf/previous_turf = null
/obj/item/projectile/beam/Destroy()
QDEL_LIST_NULL(past_rays)
@@ -100,7 +103,8 @@ var/list/beam_master = list()
hits = shot_ray.cast(travel_range)
else
hits = shot_ray.cast(MAX_BEAM_DISTANCE)
final_turf = shot_ray.final_turf
previous_turf = shot_ray.previous_turf
if(!gcDestroyed)
past_rays += shot_ray
else
@@ -118,11 +122,13 @@ var/list/beam_master = list()
shot_ray.draw(last_hit.distance, icon, icon_state, color_override = beam_color, color_shift = beam_shift)
if(last_hit.hit_type == RAY_CAST_REBOUND)
final_turf=null
ASSERT(!gcDestroyed)
spawn()
rebound(last_hit.hit_atom)
if(last_hit.hit_type == RAY_CAST_PORTAL)
final_turf=null
ASSERT(!gcDestroyed)
spawn()
portal(last_hit.hit_atom)
@@ -1156,50 +1162,62 @@ var/list/laser_tag_vests = list(/obj/item/clothing/suit/tag/redtag, /obj/item/cl
penetration = 0
pass_flags = PASSTABLE
var/has_splashed = FALSE
var/atom/splashed_atom = null
/obj/item/projectile/beam/liquid_stream/New(atom/A, var/t_range)
/obj/item/projectile/beam/liquid_stream/New(atom/A, var/t_range=3, var/m_color, var/m_alpha=255)
..(A)
create_reagents(20)
if(t_range)
travel_range = t_range
else
travel_range = 0
/obj/item/projectile/beam/liquid_stream/OnFired()
beam_color = mix_color_from_reagents(reagents.reagent_list)
alpha = mix_alpha_from_reagents(reagents.reagent_list)
..()
travel_range = t_range
beam_color = m_color
alpha = m_alpha
/obj/item/projectile/beam/liquid_stream/on_hit(var/atom/A, var/blocked = 0)
if(reagents.total_volume)
for(var/datum/reagent/R in reagents.reagent_list)
reagents.add_reagent(R.id, reagents.get_reagent_amount(R.id))//so here we're just doubling our quantity of reagents from 10 to 20
if(istype(A, /mob))
if(firer.zone_sel.selecting == TARGET_MOUTH && def_zone == LIMB_HEAD && ishuman(A)) //if aiming at head and is humanoid
var/mob/living/carbon/human/victim = A
if(!victim.check_body_part_coverage(MOUTH)) //if not covered with mask or something
victim.visible_message("<span class='warning'>[A] swallows \the [src]!</span>",
"<span class='warning'>You swallow \the [src]!</span>")
reagents.trans_to(A, reagents.total_volume) //20% chance to get in mouth and in system, if mouth targeting was possible at all with projectiles this chance should be scrapped
has_splashed = TRUE //guess we arent stacking with the splash
return 1
else
A.visible_message("<span class='warning'>\The [src] gets blocked from [A]'s mouth!</span>",
"<span class='warning'>\The [src] gets blocked from your mouth!</span>")//just block mouth, no turf splash
if(reagents.total_volume && istype(A, /mob))
if(firer.zone_sel.selecting == TARGET_MOUTH && def_zone == LIMB_HEAD && ishuman(A)) //if aiming at head and is humanoid
var/mob/living/carbon/human/victim = A
if(!victim.check_body_part_coverage(MOUTH)) //if not covered with mask or something
victim.visible_message("<span class='warning'>[A] swallows \the [src]!</span>",
"<span class='warning'>You swallow \the [src]!</span>")
reagents.trans_to(A, reagents.total_volume)
has_splashed = TRUE //guess we arent stacking with the splash
qdel(src)
return 1
else
var/splash_verb = pick("douses","completely soaks","drenches","splashes")
A.visible_message("<span class='warning'>\The [src] [splash_verb] [A]!</span>",
"<span class='warning'>\The [src] [splash_verb] you!</span>")
splash_sub(reagents, get_turf(A), reagents.total_volume/2, firer)//then we splash 10 of those on the turf in front (or under in case of mobs) of the hit atom
A.visible_message("<span class='warning'>\The [src] gets blocked from [A]'s mouth!</span>",
"<span class='warning'>\The [src] gets blocked from your mouth!</span>")//just block mouth, no turf splash
else
splash_sub(reagents, get_turf(src), reagents.total_volume/2, firer)
splash_sub(reagents, A, reagents.total_volume, firer)//and 10 more on the atom itself
has_splashed = TRUE
return 1
var/splash_verb = pick("douses","completely soaks","drenches","splashes")
A.visible_message("<span class='warning'>\The [src] [splash_verb] [A]!</span>",
"<span class='warning'>\The [src] [splash_verb] you!</span>")
/obj/item/projectile/beam/liquid_stream/to_bump(var/atom/A)
splashed_atom = A//doesn't matter if it's actually the atom we end up splashing since we only use that var on bullet_die()
. = ..()
/obj/item/projectile/beam/liquid_stream/bullet_die()//splashes reagents on the hit atom, or in front of it in case of turfs and border objects
if(reagents && reagents.total_volume && !has_splashed && ((bumped && splashed_atom) || final_turf))
if (splashed_atom && !isturf(splashed_atom) && (previous_turf && previous_turf.Adjacent(splashed_atom)))
if (splashed_atom.flow_flags & ON_BORDER)
loc = previous_turf
else
loc = get_turf(splashed_atom)
else if (isturf(splashed_atom))
loc = final_turf
else
loc = previous_turf
playsound(loc, 'sound/effects/slosh.ogg', 20, 1)
reagents.splashplosion(0)
has_splashed = TRUE
..()
//I never want to deal wity ray casts ever again
/obj/item/projectile/beam/liquid_stream/fireto(var/vector/origin, var/vector/direction)//splashes reagents on the turf if the projectile ran out
..()
if (reagents && reagents.total_volume && final_turf && !has_splashed)
loc = final_turf
reagents.splashplosion(0)
has_splashed = TRUE
qdel(src)
/obj/item/projectile/beam/liquid_stream/OnDeath()
if(!has_splashed && loc)
splash_sub(reagents, get_turf(src), reagents.total_volume)
/obj/item/projectile/beam/liquid_stream/proc/adjust_strength(var/t_range)
if(t_range)

View File

@@ -904,8 +904,10 @@
custom_impact = 1
rotate = 0
var/hard = 0
var/radius = 1//big glob of liquid, splashes a bit on surroundings
var/atom/splashed_atom = null
/obj/item/projectile/bullet/liquid_blob/New(atom/T, var/hardness = null)
/obj/item/projectile/bullet/liquid_blob/New(atom/T, var/hardness = null, var/mixed_color=null, var/mixed_alpha=255, var/_rad=1)
..(T)
hard = hardness
if(hard)
@@ -913,37 +915,34 @@
create_reagents(10)
else
create_reagents(50)
icon += mixed_color
alpha = mixed_alpha
radius = _rad
/obj/item/projectile/bullet/liquid_blob/OnFired()
src.icon += mix_color_from_reagents(reagents.reagent_list)
src.alpha = mix_alpha_from_reagents(reagents.reagent_list)
..()
/obj/item/projectile/bullet/liquid_blob/to_bump(var/atom/A)
splashed_atom = A//doesn't matter if it's actually the atom we end up splashing since we only use that var on bullet_die()
. = ..()
if (. && A)
if ((special_collision == PROJECTILE_COLLISION_DEFAULT) || (special_collision == PROJECTILE_COLLISION_BLOCKED))
if(istype(A, /mob))
if(hard)
var/splash_verb = pick("dousing","completely soaking","drenching","splashing")
A.visible_message("<span class='warning'>\The [src] smashes into [A], [splash_verb] \him!</span>",
"<span class='warning'>\The [src] smashes into you, [splash_verb] you!</span>")
else
var/splash_verb = pick("douses","completely soaks","drenches","splashes")
A.visible_message("<span class='warning'>\The [src] [splash_verb] [A]!</span>",
"<span class='warning'>\The [src] [splash_verb] you!</span>")
/obj/item/projectile/bullet/liquid_blob/on_hit(atom/A as mob|obj|turf|area)
if(!A)
return
..()
/obj/item/projectile/bullet/liquid_blob/bullet_die()
if(reagents.total_volume)
for(var/datum/reagent/R in reagents.reagent_list)
reagents.add_reagent(R.id, reagents.get_reagent_amount(R.id))
if(istype(A, /mob))
if(hard)
var/splash_verb = pick("dousing","completely soaking","drenching","splashing")
A.visible_message("<span class='warning'>\The [src] smashes into [A], [splash_verb] \him!</span>",
"<span class='warning'>\The [src] smashes into you, [splash_verb] you!</span>")
else
var/splash_verb = pick("douses","completely soaks","drenches","splashes")
A.visible_message("<span class='warning'>\The [src] [splash_verb] [A]!</span>",
"<span class='warning'>\The [src] [splash_verb] you!</span>")
splash_sub(reagents, get_turf(A), reagents.total_volume/2)
else
splash_sub(reagents, get_turf(src), reagents.total_volume/2)
splash_sub(reagents, A, reagents.total_volume)
return 1
/obj/item/projectile/bullet/liquid_blob/OnDeath()
if(get_turf(src))
playsound(src, 'sound/effects/slosh.ogg', 20, 1)
var/turf/T = get_turf(splashed_atom)
if (!T.density && T.Adjacent(src))
loc = T
playsound(loc, 'sound/effects/slosh.ogg', 20, 1)
reagents.splashplosion(radius)
..()
/obj/item/projectile/bullet/pellet
name = "buckshot pellet"

View File

@@ -1989,10 +1989,7 @@
user?.attack_log += text("\[[time_stamp()]\] <span class='danger'>Threw a [lit ? "lit" : "unlit"] molotov to \the [hit_atom], containing [reagents.get_reagent_ids()]</span>")
log_attack("[lit ? "Lit" : "Unlit"] molotov shattered at [formatJumpTo(get_turf(hit_atom))], thrown by [key_name(user)] and containing [reagents.get_reagent_ids()]")
message_admins("[lit ? "Lit" : "Unlit"] molotov shattered at [formatJumpTo(get_turf(hit_atom))], thrown by [key_name_admin(user)] and containing [reagents.get_reagent_ids()]")
reagents.reaction(get_turf(src), TOUCH) //splat the floor AND the thing we hit, otherwise fuel wouldn't ignite when hitting anything that wasn't a floor
if(hit_atom != get_turf(src)) //prevent spilling on the floor twice though
var/list/hit_zone = user && user.zone_sel ? list(user.zone_sel.selecting) : ALL_LIMBS
reagents.reaction(hit_atom, TOUCH, zone_sels = hit_zone) //maybe this could be improved?
reagents.splashplosion(reagents.total_volume >= (reagents.maximum_volume/2))//splashing everything on the tile hit, and the surrounding ones if we're over half full.
invisibility = INVISIBILITY_MAXIMUM //so it stays a while to ignite any fuel
if(molotov == 1) //for molotovs
@@ -2000,7 +1997,6 @@
new /obj/effect/decal/cleanable/ash(get_turf(src))
var/turf/loca = get_turf(src)
if(loca)
// to_chat(world, "<span class='warning'>Burning...</span>")
loca.hotspot_expose(700, 1000,surfaces=istype(loc,/turf))
else
new /obj/item/weapon/reagent_containers/glass/rag(get_turf(src))

View File

@@ -0,0 +1,44 @@
//Hits every turfs in view and their content with our reagents (provided they are not blocked by windows or other turfs)
//Can be set to inject hit mob with some of the reagents based on their permeability. False by default.
/datum/reagents/proc/splashplosion(var/range=3,var/allow_permeability=FALSE)
if (reagent_list.len <= 0)
return
var/list/hit_turfs = list()
var/turf/epicenter = get_turf(my_atom)
var/datum/effect/system/steam_spread/steam = new /datum/effect/system/steam_spread()
steam.set_up(max(range,1)*3, 0, epicenter, mix_color_from_reagents(reagent_list))
steam.start()
playsound(epicenter, 'sound/effects/bamf.ogg', max(10,15*range), 0, range-4)
if (!range)
hit_turfs = list(epicenter)
else
for(var/turf/T in dview(range, epicenter, INVISIBILITY_MAXIMUM))
if (cheap_pythag(T.x - epicenter.x,T.y - epicenter.y) <= range + 0.5)
if (test_reach(epicenter,T,PASSTABLE|PASSGRILLE|PASSMOB|PASSMACHINE|PASSGIRDER))
hit_turfs += T
for(var/datum/reagent/R in reagent_list)
var/min_volume_per_tile = max(1,R.volume/hit_turfs.len)
//the volume is affected by the number of turfs hit. The less turfs hit, the more concentrated the splashing.
//and the closer to the epicenter, the more splashing as well
for (var/turf/T in hit_turfs)
var/volume_for_this_tile = round((R.volume - min_volume_per_tile) / max(1,get_dist(epicenter,T))) + min_volume_per_tile
if (!T.density)
for (var/atom/movable/AM in T.contents)
if (ismob(AM))
if (isanimal(AM))
R.reaction_animal(AM, TOUCH, volume_for_this_tile,hit_turfs)
else
R.reaction_mob(AM, TOUCH, volume_for_this_tile, ALL_LIMBS, allow_permeability, hit_turfs)
else if (isobj(AM) && !istype(AM,/atom/movable/lighting_overlay))
R.reaction_obj(AM, volume_for_this_tile,hit_turfs)
R.reaction_turf(T, volume_for_this_tile,hit_turfs)
clear_reagents()

View File

@@ -539,20 +539,38 @@
else
to_chat(mob, "<span class = 'notice'>Your pupils dilate further.</span>")
/datum/disease2/effect/colorsmoke
/datum/disease2/effect/colorsplash
name = "Colorful Syndrome"
desc = "Causes the infected to synthesize smoke & rainbow colourant."
desc = "Causes the infected to expulse bursts of paint from their pores."
encyclopedia = "The paint can be washed off items, and removed from floors and walls using bleach or acetone. The infected's own skin color will match the color of their last paint burst, but they can recover their original color with a shower, or exposure to space cleaner."
stage = 3
badness = EFFECT_DANGER_HINDRANCE
var/list/random_color_list = list("#00aedb","#a200ff","#f47835","#d41243","#d11141","#00b159","#00aedb","#f37735","#ffc425","#008744","#0057e7","#d62d20","#ffa700")
max_multiplier = 3
/datum/disease2/effect/colorsmoke/activate(var/mob/living/mob)
if (ismouse(mob))//people don't like infected mice ruining maint
var/mob/living/simple_animal/mouse/M = mob
if (!initial(M.infectable))
return
/datum/disease2/effect/colorsplash/activate(var/mob/living/mob)
var/obj/item/weapon/reagent_containers/R = new(get_turf(mob))
R.invisibility = 101
var/list/colors_to_use = random_color_list.Copy()
var/range = 2 + round(max(1,multiplier))
var/color_count = round(max(1,multiplier))
if (ismouse(mob))
range = 0
color_count = 1
var/color_to_use = ""
for(var/i = 1 to color_count)
color_to_use = pick(colors_to_use)
colors_to_use -= color_to_use
R.reagents.add_reagent(FLAXOIL, 10 * max(1,range), list("color" = color_to_use, "alpha" = 255))
R.reagents.splashplosion(range)
range--
qdel(R)
to_chat(mob, "<span class='notice'>You feel colorful!</span>")
mob.reagents.add_reagent(COLORFUL_REAGENT, 5)
mob.reagents.add_reagent(PAISMOKE, 5)
mob.color = color_to_use
/datum/disease2/effect/cleansmoke
name = "Cleaning Syndrome"

View File

@@ -110,6 +110,7 @@
#include "code\__HELPERS\path.dm"
#include "code\__HELPERS\priority_queue.dm"
#include "code\__HELPERS\sanitize_values.dm"
#include "code\__HELPERS\test_reach.dm"
#include "code\__HELPERS\text.dm"
#include "code\__HELPERS\time.dm"
#include "code\__HELPERS\timed_alerts.dm"
@@ -2423,6 +2424,7 @@
#include "code\modules\reagents\randomized_reagent.dm"
#include "code\modules\reagents\reagent_containers.dm"
#include "code\modules\reagents\reagent_dispenser.dm"
#include "code\modules\reagents\splashplosion.dm"
#include "code\modules\reagents\syringe_gun.dm"
#include "code\modules\reagents\machinery\centrifuge.dm"
#include "code\modules\reagents\machinery\chem_dispenser.dm"