mirror of
https://github.com/goonstation/goonstation-2020.git
synced 2026-07-10 22:52:21 +01:00
036a29b765
includes a lot of small things + fixes. big ones are Simple Lights, New Grab stuff, Disorient Eye/Ear protection armor values, access reprogrammer and deconstruction device also added flabo to the list of contributors, we missed her on the first go! check changelog for full list, i merged that too
772 lines
24 KiB
Plaintext
772 lines
24 KiB
Plaintext
///////////////////
|
|
////Fluid Group////
|
|
///////////////////
|
|
|
|
|
|
/datum/reagents/fluid_group
|
|
var/datum/fluid_group/my_group = 0
|
|
var/last_reaction_loc = 0
|
|
var/skip_next_update = 0
|
|
covered_turf()
|
|
.= list()
|
|
if (my_group)
|
|
for (var/fluid in my_group.members)
|
|
var/obj/fluid/F = fluid
|
|
.+= F.loc
|
|
|
|
clear_reagents()
|
|
..()
|
|
if (my_group)
|
|
my_group.evaporate()
|
|
|
|
//Handles reagent reduction -> shrinking puddle
|
|
update_total()
|
|
var/prev_volume = src.total_volume
|
|
..()
|
|
if (skip_next_update) //sometimes we need to change the total without automatically draining the removed amt.
|
|
skip_next_update = 0
|
|
return
|
|
if (my_group)
|
|
my_group.contained_amt = src.total_volume
|
|
|
|
if (src.total_volume <= 0 && prev_volume > 0)
|
|
my_group.evaporate()
|
|
return
|
|
|
|
if (my_group.amt_per_tile >= my_group.required_to_spread) return
|
|
if ((src.total_volume >= prev_volume)) return
|
|
|
|
var/member_dif = (round(src.total_volume / my_group.required_to_spread) - round(prev_volume / my_group.required_to_spread ))
|
|
var/fluids_to_remove = 0
|
|
if (member_dif < 0)
|
|
fluids_to_remove = abs(member_dif)
|
|
|
|
if (fluids_to_remove)
|
|
var/obj/fluid/remove_source = my_group.last_reacted
|
|
if (!remove_source)
|
|
remove_source = my_group.spread_member
|
|
if (!remove_source && my_group.members.len)
|
|
remove_source = pick(my_group.members)
|
|
if (!remove_source)
|
|
my_group.evaporate()
|
|
return
|
|
skip_next_update = 1
|
|
my_group.drain(remove_source, fluids_to_remove)
|
|
|
|
get_reagents_fullness()
|
|
.= "empty"
|
|
if (my_group)
|
|
if(my_group.last_depth_level == 1)
|
|
.= "very shallow"
|
|
else if (my_group.last_depth_level == 2)
|
|
.= "at knee height"
|
|
if(my_group.last_depth_level == 3)
|
|
.= "at chest height"
|
|
if(my_group.last_depth_level == 4)
|
|
.= "very deep"
|
|
|
|
temperature_reagents()
|
|
..()
|
|
src.update_total()
|
|
|
|
play_mix_sound(var/mix_sound) //play sound at random locs
|
|
for (var/i = 0, i < my_group.members.len / 20, i++)
|
|
playsound(pick(my_group.members).loc, mix_sound, 80, 1)
|
|
if (i > 8) break
|
|
|
|
//We use datum/controller/process/fluid_group to do evaporation
|
|
|
|
/datum/fluid_group
|
|
|
|
var/const/group_type = /datum/fluid_group
|
|
//var/const/object_type = /obj/fluid
|
|
|
|
var/base_evaporation_time = 1500
|
|
var/bonus_evaporation_time = 9000 //Ranges from 0 to this value depending on average viscosity
|
|
var/const/max_viscosity = 20
|
|
|
|
var/const/max_alpha = 230
|
|
|
|
var/list/members = list()
|
|
var/obj/fluid/spread_member = 0 //Member that we want to spread from. Should be changed on add amt, displace, etc.
|
|
var/updating = 0 //already updating? block another loop from being started
|
|
|
|
|
|
var/datum/reagents/fluid_group/reagents = 0
|
|
var/contained_amt = 0 //total reagent amt including all members
|
|
var/amt_per_tile = 0 //Don't pull from this value for group calculations without updating it first
|
|
var/required_to_spread = 30
|
|
|
|
var/last_add_time = 0
|
|
var/last_temp_change = 0
|
|
var/last_spread_member = 0
|
|
var/last_contained_amt = -1
|
|
var/last_members_amt = 0
|
|
var/last_depth_level = 0
|
|
var/avg_viscosity = 1
|
|
var/last_update_time = 0
|
|
var/obj/fluid/last_reacted = 0
|
|
|
|
var/datum/color/average_color = 0
|
|
var/master_reagent_name = 0
|
|
var/master_reagent_id = 0
|
|
|
|
var/can_update = 1 //flag is set to 0 temporarily when doing a split operation
|
|
|
|
var/draining = 0
|
|
var/queued_drains = 0 // how many tiles to drain on next update?
|
|
var/turf/last_drain = 0 // tile from which we should try to drain from
|
|
|
|
var/drains_floor = 1
|
|
|
|
disposing()
|
|
can_update = 0
|
|
|
|
for (var/fluid in src.members)
|
|
var/obj/fluid/M = fluid
|
|
M.group = 0
|
|
|
|
//if (src in processing_fluid_groups)
|
|
// processing_fluid_groups.Remove(src)
|
|
//if (src in processing_fluid_spreads)
|
|
// processing_fluid_spreads.Remove(src)
|
|
|
|
processing_fluid_groups -= src
|
|
processing_fluid_spreads -= src
|
|
processing_fluid_drains -= src
|
|
|
|
members = 0
|
|
|
|
reagents.my_group = 0
|
|
reagents = 0
|
|
|
|
spread_member = 0
|
|
updating = 0
|
|
contained_amt = 0
|
|
amt_per_tile = 0
|
|
required_to_spread = initial(required_to_spread)
|
|
last_add_time = world.time //fuck
|
|
last_temp_change = 0
|
|
last_contained_amt = 0
|
|
avg_viscosity = 1
|
|
last_update_time = 0
|
|
last_members_amt = 0
|
|
last_depth_level = 0
|
|
last_reacted = 0
|
|
draining = 0
|
|
queued_drains = 0
|
|
last_drain = 0
|
|
master_reagent_id = 0
|
|
drains_floor = 1
|
|
..()
|
|
|
|
New()
|
|
..()
|
|
src.last_add_time = world.time
|
|
|
|
reagents = new /datum/reagents/fluid_group(90000000) //high number lol.
|
|
reagents.my_group = src
|
|
|
|
if (!(src in processing_fluid_groups))
|
|
processing_fluid_groups.Add(src)
|
|
|
|
proc/update_amt_per_tile()
|
|
contained_amt = src.reagents.total_volume
|
|
amt_per_tile = (members && members.len) ? contained_amt / members.len : 0
|
|
|
|
proc/evaporate()
|
|
//boutput(world,"IM HITTING THE VAPE!!!!!!!!!!")
|
|
if (last_add_time == 0) //this should nOT HAPPEN
|
|
last_add_time = world.time
|
|
return
|
|
|
|
for (var/fluid in src.members)
|
|
var/obj/fluid/F = fluid
|
|
if (!F) continue
|
|
if (F.pooled) continue
|
|
src.remove(F,0,1,1)
|
|
LAGCHECK(LAG_LOW)
|
|
|
|
if (!src.pooled)
|
|
qdel(src)
|
|
|
|
proc/add(var/obj/fluid/F, var/gained_fluid = 0, var/do_update = 1, var/guarantee_is_member = 0)
|
|
if (!F || src.pooled || !members) return
|
|
|
|
if (gained_fluid)
|
|
spread_member = F
|
|
|
|
//if (!members.len) //very first member! do special stuff we should def. have defined before anything else can happen
|
|
// contained_amt = src.reagents.total_volume
|
|
// amt_per_tile = contained_amt
|
|
|
|
LAGCHECK(LAG_MED)
|
|
if (!guarantee_is_member)
|
|
if (!members.len || !(F in members))
|
|
members += F
|
|
F.group = src
|
|
|
|
if (members.len == 1)
|
|
F.update_icon() //update icon of the very first fluid in this group
|
|
|
|
src.last_add_time = world.time
|
|
|
|
if (!do_update) return
|
|
|
|
src.update_loop()
|
|
|
|
//fluid has been removed from its tile. use 'lightweight' in evaporation procedure cause we dont need icon updates / try split / update loop checks at that point
|
|
// if 'lightweight' parameter is 2, invoke an update loop but still ignore icon updates
|
|
proc/remove(var/obj/fluid/F, var/lost_fluid = 1, var/lightweight = 0, var/allow_zero = 0)
|
|
if (!F || F.pooled) return 0
|
|
if (!members || !members.len || !members.Find(F)) return 0
|
|
|
|
if (!lightweight)
|
|
var/turf/t
|
|
for( var/dir in cardinal )
|
|
t = get_step( F, dir )
|
|
if (t && t.active_liquid)
|
|
t.active_liquid.blocked_dirs = 0
|
|
t.active_liquid.update_icon(1)
|
|
else
|
|
var/turf/t
|
|
for( var/dir in cardinal )
|
|
t = get_step( F, dir )
|
|
if (t && t.active_liquid)
|
|
t.active_liquid.blocked_dirs = 0
|
|
|
|
amt_per_tile = (members && members.len) ? contained_amt / members.len : 0
|
|
members -= F //remove after amt per tile ok? otherwise bad thing could happen
|
|
if (lost_fluid)
|
|
src.reagents.skip_next_update = 1
|
|
src.reagents.remove_any(amt_per_tile)
|
|
src.contained_amt = src.reagents.total_volume
|
|
|
|
F.group = 0
|
|
var/turf/removed_loc = F.loc
|
|
if (removed_loc)
|
|
var/turf/T = removed_loc
|
|
T.active_liquid = 0
|
|
|
|
pool(F)
|
|
|
|
if (!lightweight || lightweight == 2)
|
|
if (!src.try_split(removed_loc))
|
|
src.update_loop()
|
|
|
|
if ((!members || src.members.len == 0) && !allow_zero)
|
|
qdel(src)
|
|
|
|
return 1
|
|
|
|
/* identical to remove, except this proc returns the fluids removed
|
|
* vol_max sets upper limit for fluid volume to be removed */
|
|
proc/suck(var/obj/fluid/F, var/vol_max, var/lost_fluid = 1, var/lightweight = 0, var/allow_zero = 1)
|
|
if (!F || F.pooled) return 0
|
|
if (!members || !members.len || !members.Find(F)) return 0
|
|
|
|
var/datum/reagents/R = null
|
|
|
|
if (!lightweight)
|
|
var/turf/t
|
|
for( var/dir in cardinal )
|
|
t = get_step( F, dir )
|
|
if (t && t.active_liquid)
|
|
t.active_liquid.blocked_dirs = 0
|
|
t.active_liquid.update_icon(1)
|
|
else
|
|
var/turf/t
|
|
for( var/dir in cardinal )
|
|
t = get_step( F, dir )
|
|
if (t && t.active_liquid)
|
|
t.active_liquid.blocked_dirs = 0
|
|
|
|
amt_per_tile = (members && members.len) ? contained_amt / members.len : 0
|
|
var/amt_to_remove = min(amt_per_tile, vol_max)
|
|
|
|
if(amt_to_remove == amt_per_tile)
|
|
members -= F //remove after amt per tile ok? otherwise bad thing could happen
|
|
if (lost_fluid)
|
|
src.reagents.skip_next_update = 1
|
|
R = src.reagents.remove_any_to(amt_to_remove)
|
|
src.contained_amt = src.reagents.total_volume
|
|
|
|
F.group = 0
|
|
var/turf/removed_loc = F.loc
|
|
if (removed_loc)
|
|
var/turf/T = removed_loc
|
|
T.active_liquid = 0
|
|
else
|
|
if (lost_fluid)
|
|
src.reagents.skip_next_update = 1
|
|
R = src.reagents.remove_any_to(amt_to_remove)
|
|
src.contained_amt = src.reagents.total_volume
|
|
pool(F)
|
|
|
|
/*if (!lightweight || lightweight == 2)
|
|
if (!src.try_split(removed_loc))
|
|
src.update_loop()*/
|
|
|
|
if ((!members || src.members.len == 0) && !allow_zero)
|
|
qdel(src)
|
|
|
|
return R
|
|
|
|
proc/displace(var/obj/fluid/F) //fluid has been displaced from its tile - delete this object and try to move my contents to adjacent tiles
|
|
LAGCHECK(LAG_LOW)
|
|
if (!members || !F) return
|
|
if (members.len == 1)
|
|
var/turf/T
|
|
for( var/dir in cardinal )
|
|
LAGCHECK(LAG_LOW)
|
|
T = get_step( F, dir )
|
|
if (! (istype(T,/turf/simulated/floor) || istype (T,/turf/unsimulated/floor)) ) continue
|
|
if (T.canpass())
|
|
if (T.active_liquid && T.active_liquid.group)
|
|
T.active_liquid.group.join(src)
|
|
else
|
|
F.loc:active_liquid = 0
|
|
F.loc = T
|
|
T.active_liquid = F
|
|
break
|
|
else
|
|
var/turf/T
|
|
for( var/dir in cardinal )
|
|
LAGCHECK(LAG_LOW)
|
|
T = get_step( F, dir )
|
|
if (T.active_liquid && T.active_liquid.group == src)
|
|
spread_member = T.active_liquid
|
|
break
|
|
src.remove(F,0,2)
|
|
|
|
|
|
proc/displace_channel(var/spread_dir, var/obj/fluid/F, var/obj/channel/channel) // use this to fake height levels. Result can either block a spread or 'jump' the channel by carrying over some fluid
|
|
if (!(channel && F)) return 0
|
|
LAGCHECK(LAG_HIGH)
|
|
var/turf/jump_turf = 0
|
|
var/amt_per_tile_added = (members && members.len) ? (contained_amt+1) / members.len : 0
|
|
|
|
if (amt_per_tile_added <= channel.required_to_pass && spread_dir != channel.dir)
|
|
return 0
|
|
else
|
|
jump_turf = get_step( channel.loc, spread_dir )
|
|
if (spread_dir == channel.dir)
|
|
if (jump_turf.active_liquid && jump_turf.active_liquid.group)
|
|
if (jump_turf.active_liquid.group.amt_per_tile > channel.required_to_pass) //don't flow back in if its 'full'
|
|
return 0
|
|
|
|
|
|
if (!istype(jump_turf)) return 0
|
|
|
|
LAGCHECK(LAG_LOW)
|
|
var/loss = amt_per_tile_added - channel.required_to_pass
|
|
if (jump_turf.active_liquid)
|
|
if (!jump_turf.active_liquid.group)
|
|
var/datum/reagents/R = new /datum/reagents(amt_per_tile_added)
|
|
src.reagents.copy_to(R)
|
|
jump_turf.fluid_react(R,amt_per_tile_added)
|
|
else
|
|
var/datum/reagents/R = new /datum/reagents(amt_per_tile_added)
|
|
src.reagents.copy_to(R)
|
|
jump_turf.fluid_react(R,amt_per_tile_added)
|
|
else
|
|
var/datum/reagents/R = new /datum/reagents(amt_per_tile_added)
|
|
src.reagents.copy_to(R)
|
|
jump_turf.fluid_react(R,amt_per_tile_added)
|
|
|
|
src.reagents.skip_next_update = 1
|
|
src.reagents.remove_any(loss)
|
|
|
|
return 1
|
|
|
|
proc/update_viscosity()
|
|
var/avg = 0
|
|
var/reagents = 0
|
|
|
|
for(var/reagent_id in src.reagents.reagent_list)
|
|
var/datum/reagent/current_reagent = src.reagents.reagent_list[reagent_id]
|
|
|
|
if (isnull(current_reagent))
|
|
continue
|
|
|
|
avg += current_reagent.viscosity
|
|
reagents++
|
|
LAGCHECK(LAG_LOW)
|
|
|
|
if (reagents && avg)
|
|
avg = avg / reagents
|
|
src.avg_viscosity = 1 + (avg * max_viscosity)
|
|
else
|
|
src.avg_viscosity = 1
|
|
|
|
src.avg_viscosity = min(src.avg_viscosity,max_viscosity)
|
|
|
|
proc/add_drain_process()
|
|
if (src.qdeled) return
|
|
|
|
src.draining = 1
|
|
if (!(src in processing_fluid_drains))
|
|
processing_fluid_drains.Add(src)
|
|
|
|
proc/update_loop()
|
|
if (src.qdeled) return
|
|
|
|
src.updating = 1
|
|
if (!(src in processing_fluid_spreads))
|
|
processing_fluid_spreads.Add(src)
|
|
|
|
proc/update_once(force = 0) //this would be called every time the fluid.dm process procs.
|
|
if (src.qdeled || !can_update) return 1
|
|
if (!members || !members.len)
|
|
src.evaporate()
|
|
return 1
|
|
|
|
var/fluids_to_create = 0 //try to create X amount of new tiles (based on how much fluid and tiles we currently hold)
|
|
|
|
src.update_viscosity()
|
|
|
|
if (SPREAD_CHECK(src) || force)
|
|
LAGCHECK(LAG_MED)
|
|
if (src.qdeled) return 1
|
|
src.updating = 1
|
|
|
|
if (src.spread_member != src.last_spread_member)
|
|
if (!src.spread_member)
|
|
src.spread_member = pick(members)
|
|
if (!src.spread_member)
|
|
src.updating = 0
|
|
return 1
|
|
|
|
src.last_spread_member = src.spread_member
|
|
|
|
fluids_to_create = (contained_amt/required_to_spread) - members.len
|
|
|
|
if (force)
|
|
fluids_to_create = force
|
|
|
|
var/list/created = src.spread(fluids_to_create)
|
|
if (created && created.len && !src.qdeled)
|
|
src.members += created
|
|
return
|
|
|
|
LAGCHECK(LAG_MED)
|
|
|
|
if (src.last_contained_amt == src.contained_amt && src.members.len == src.last_members_amt && !force)
|
|
src.updating = 0
|
|
return 1
|
|
|
|
amt_per_tile = (members && members.len) ? contained_amt / members.len : 0
|
|
var/my_depth_level = 0
|
|
for(var/x in depth_levels)
|
|
if (amt_per_tile > x)
|
|
my_depth_level++
|
|
|
|
LAGCHECK(LAG_LOW)
|
|
|
|
var/datum/color/last_color = src.average_color
|
|
src.average_color = src.reagents.get_average_color()
|
|
var/color_dif = 0
|
|
if (!last_color)
|
|
color_dif = 999
|
|
else
|
|
color_dif = abs(average_color.r - last_color.r) + abs(average_color.g - last_color.g) + abs(average_color.b - last_color.b)
|
|
var/color_changed = (color_dif > 10)
|
|
|
|
if (my_depth_level == last_depth_level && !color_changed && src.members.len == src.last_members_amt) //saves cycles for stuff like an ocean flooding into a pretty-much-aready-filled room
|
|
src.updating = 0
|
|
return 1
|
|
|
|
LAGCHECK(LAG_LOW)
|
|
|
|
var/targetalpha = max(25, (src.average_color.a / 255) * src.max_alpha)
|
|
var/targetcolor = rgb(src.average_color.r, src.average_color.g, src.average_color.b)
|
|
|
|
src.master_reagent_name = src.reagents.get_master_reagent_name()
|
|
src.master_reagent_id = src.reagents.get_master_reagent_id()
|
|
|
|
var/master_opacity = !drains_floor && reagents.get_master_reagent_gas_opaque()
|
|
|
|
var/depth_changed = 0 //force icon update later in the proc if fluid member depth changed
|
|
var/last_icon = 0
|
|
|
|
for(var/fluid in src.members)
|
|
var/obj/fluid/F = fluid
|
|
LAGCHECK(LAG_MED)
|
|
if (!F || F.pooled || src.qdeled) continue
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//Set_amt gets called a lot. Let's reduce proc call overhead : by being stupid and pasting the whole thing in this fuckin loop ugh
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
F.amt = src.amt_per_tile
|
|
|
|
if (F.touched_channel)
|
|
src.displace_channel(get_dir(F,F.touched_channel), F, F.touched_channel)
|
|
F.touched_channel = 0
|
|
if (!F || F.pooled || src.qdeled) continue
|
|
|
|
//We update objects manually here because they don't move. A mob that moves around will call HasEntered on its own, so let that case happen naturally
|
|
|
|
depth_changed = 0
|
|
if (F.last_depth_level != my_depth_level)
|
|
F.last_depth_level = my_depth_level
|
|
for(var/obj/O in F.loc)
|
|
LAGCHECK(LAG_MED)
|
|
if (O && O.submerged_images)
|
|
F.HasEntered(O,O.loc)
|
|
|
|
depth_changed = 1
|
|
|
|
if (my_depth_level)
|
|
var/splash_level = max(1,min(my_depth_level, 3))
|
|
F.step_sound = "sound/misc/splash_[splash_level].ogg"
|
|
|
|
F.movement_speed_mod = F.last_depth_level <= 1 ? 0 : (viscosity_SLOW_COMPONENT(F.avg_viscosity,F.max_viscosity,F.max_speed_mod) + DEPTH_SLOW_COMPONENT(F.amt,F.max_reagent_volume,F.max_speed_mod))
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//end
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
if (!F) continue
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//Same shit here with update_icon
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
F.name = src.master_reagent_name //maybe obscure later?
|
|
|
|
F.finalalpha = targetalpha
|
|
F.finalcolor = targetcolor
|
|
|
|
F.color = F.finalcolor
|
|
F.alpha = F.finalalpha
|
|
|
|
|
|
if (F.do_iconstate_updates)
|
|
last_icon = F.icon_state
|
|
|
|
if (F.last_spread_was_blocked || (src.amt_per_tile > src.required_to_spread))
|
|
F.icon_state = "15"
|
|
else
|
|
var/dirs = 0
|
|
for (var/dir in cardinal)
|
|
LAGCHECK(LAG_MED)
|
|
var/turf/simulated/T = get_step(F, dir)
|
|
if (T && T.active_liquid && T.active_liquid.group == F.group)
|
|
dirs |= dir
|
|
F.icon_state = num2text(dirs)
|
|
|
|
if (F.overlay_refs && F.overlay_refs.len)
|
|
LAGCHECK(LAG_MED)
|
|
if (F)
|
|
F.ClearAllOverlays()
|
|
|
|
if (((color_changed || last_icon != F.icon_state) && F.last_spread_was_blocked) || depth_changed)
|
|
F.update_perspective_overlays()
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//end
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//air specific (messy)
|
|
F.opacity = master_opacity
|
|
|
|
|
|
src.last_contained_amt = src.contained_amt
|
|
src.last_members_amt = src.members.len
|
|
src.last_depth_level = my_depth_level
|
|
|
|
src.updating = 0
|
|
return 1
|
|
|
|
proc/spread(var/fluids_to_create) //spread in respect to members
|
|
.= list() //return created fluids
|
|
var/created = 0
|
|
var/obj/fluid/F
|
|
|
|
for (var/i = 1, i <= members.len, i++)
|
|
LAGCHECK(LAG_MED)
|
|
if (src.qdeled) return
|
|
if (i > members.len) continue
|
|
F = members[i]
|
|
if (!F || F.group != src) continue //This can happen if a fluid is deleted/caught with its pants down during an update loop.
|
|
|
|
if (F.blocked_dirs < 4) //skip that update if we were blocked (not an edge tile)
|
|
amt_per_tile = contained_amt / (members.len + created)
|
|
|
|
for(var/fluid in F.update())
|
|
var/obj/fluid/C = fluid
|
|
LAGCHECK(LAG_MED)
|
|
if (!C || C.pooled) continue
|
|
var/turf/T = C.loc
|
|
if (istype(T) && drains_floor)
|
|
T.react_all_cleanables() // bug here regarding fluids doing their whole spread immediately if they're in a patch of cleanables. can't figure it out and its not TERRIBLE, fix later!!!
|
|
C.amt = src.amt_per_tile
|
|
|
|
//copy blood stuff
|
|
if (F.blood_DNA && !C.blood_DNA)
|
|
C.blood_DNA = F.blood_DNA
|
|
if (F.blood_type && !C.blood_type)
|
|
C.blood_type = F.blood_type
|
|
|
|
.+= C
|
|
created++
|
|
|
|
if ((members.len + created)<=0) //this can happen somehow
|
|
continue
|
|
|
|
amt_per_tile = contained_amt / (members.len + created)
|
|
|
|
if (F.touched_other_group && src != F.touched_other_group)
|
|
if (src.join(F.touched_other_group))
|
|
F.touched_other_group = 0
|
|
break
|
|
F.touched_other_group = 0
|
|
|
|
if (created >= fluids_to_create)
|
|
break
|
|
|
|
proc/drain(var/obj/fluid/drain_source, var/fluids_to_remove, var/atom/transfer_to = 0) //basically a reverse spread with drain_source as the center
|
|
if (!drain_source || drain_source.group != src) return
|
|
|
|
//Don't delete tiles if we can just drain existing deep fluid
|
|
amt_per_tile = (members && members.len) ? contained_amt / members.len : 0
|
|
|
|
if (amt_per_tile > required_to_spread)
|
|
if (transfer_to && transfer_to.reagents && src.reagents)
|
|
src.reagents.trans_to_direct(transfer_to.reagents,min(fluids_to_remove * amt_per_tile, src.reagents.total_volume))
|
|
src.contained_amt = src.reagents.total_volume
|
|
else
|
|
src.reagents.remove_any(fluids_to_remove * amt_per_tile)
|
|
|
|
src.update_loop()
|
|
return src.avg_viscosity
|
|
|
|
if (src.members[1] != drain_source)
|
|
if (src.members.len <= 30)
|
|
var/list/L = drain_source.get_connected_fluids()
|
|
if (L.len == members.len)
|
|
src.members = L.Copy()// this is a bit of an ouch, but drains need to be able to finish off smallish puddles properly
|
|
|
|
var/list/fluids_removed = list()
|
|
var/fluids_removed_avg_viscosity = 0
|
|
|
|
for (var/i = members.len, i > 0, i--)
|
|
LAGCHECK(LAG_MED)
|
|
if (src.qdeled) return
|
|
if (i > members.len) continue
|
|
if (!members[i]) continue
|
|
var/obj/fluid/F = members[i] // todo fix error
|
|
if (!F || F.group != src) continue
|
|
|
|
fluids_removed += F
|
|
fluids_removed_avg_viscosity += F.avg_viscosity
|
|
|
|
if (fluids_removed.len >= fluids_to_remove)
|
|
break
|
|
|
|
var/removed_len = fluids_removed.len
|
|
|
|
LAGCHECK(LAG_LOW)
|
|
if (transfer_to && transfer_to.reagents && src.reagents)
|
|
src.reagents.skip_next_update = 1
|
|
src.reagents.trans_to_direct(transfer_to.reagents,src.amt_per_tile * removed_len)
|
|
src.contained_amt = src.reagents.total_volume
|
|
else if (src.reagents)
|
|
src.reagents.skip_next_update = 1
|
|
src.reagents.remove_any(src.amt_per_tile * removed_len)
|
|
src.contained_amt = src.reagents.total_volume
|
|
|
|
for (var/fluid in fluids_removed)
|
|
var/obj/fluid/F = fluid
|
|
src.remove(F,0,src.updating)
|
|
LAGCHECK(LAG_MED)
|
|
|
|
//fluids_removed_avg_viscosity = fluids_removed ? (fluids_removed_avg_viscosity / fluids_removed) : 1
|
|
return src.avg_viscosity
|
|
|
|
proc/join(var/datum/fluid_group/join_with) //join a fluid group into this one
|
|
if (src == join_with || src.qdeled || join_with.qdeled)
|
|
return 0
|
|
|
|
join_with.qdeled = 1 //hacky but stop updating
|
|
|
|
for (var/fluid in join_with.members)
|
|
var/obj/fluid/F = fluid
|
|
LAGCHECK(LAG_MED)
|
|
if (!F) continue
|
|
F.group = src
|
|
src.members += F
|
|
join_with.members -= F
|
|
|
|
join_with.reagents.copy_to(src.reagents)
|
|
|
|
join_with.evaporate()
|
|
join_with = 0
|
|
|
|
src.update_loop() //just in case one wasn't running already
|
|
//src.last_add_time = world.time
|
|
amt_per_tile = (members && members.len) ? contained_amt / members.len : 0
|
|
return 1
|
|
|
|
proc/try_split(var/turf/removed_loc) //called when a fluid is removed. check if the removal causes a split, and proceed from there.
|
|
if (!removed_loc || src.qdeled) return 0
|
|
var/list/connected = 0
|
|
|
|
var/turf/T = 0
|
|
var/obj/fluid/split_liq = 0
|
|
var/removal_key = "[world.time]_[removed_loc.x]_[removed_loc.y]"
|
|
var/adjacent_amt = -1
|
|
for( var/dir in cardinal )
|
|
T = get_step( removed_loc, dir )
|
|
if (T.active_liquid && T.active_liquid.group == src)
|
|
T.active_liquid.temp_removal_key = removal_key
|
|
adjacent_amt++
|
|
split_liq = T.active_liquid
|
|
|
|
if (split_liq && adjacent_amt > 0) //(adjacent_amt > 0) means that we won't even try searching if the removal point is only connected to 1 fluid (could not possibly be a split)
|
|
//pass in adjacent_amt: get_connected will check the removal_key of each fluid, which will trigger an early abort if we determine no split is necessary
|
|
connected = split_liq.get_connected_fluids(adjacent_amt)
|
|
|
|
if (!connected || connected.len == src.members.len)
|
|
return 0
|
|
|
|
if (!removed_loc || src.qdeled || !src.reagents || !src.reagents.total_volume) //trying to stop the weird bug were a bunch of simultaneous splits removes all reagents
|
|
return 0
|
|
contained_amt = src.reagents.total_volume
|
|
|
|
//remove some of contained_amt from src and add it to FG
|
|
src.can_update = 0
|
|
amt_per_tile = (members && members.len) ? contained_amt / members.len : 0
|
|
var/datum/fluid_group/FG = new group_type
|
|
FG.can_update = 0
|
|
//add members to FG, remove them from src
|
|
for (var/fluid in connected)
|
|
var/obj/fluid/F = fluid
|
|
if (!FG) return 0
|
|
FG.members += F
|
|
F.group = FG
|
|
F.last_spread_was_blocked = 0
|
|
LAGCHECK(LAG_HIGH)
|
|
src.members -= FG.members
|
|
|
|
if (FG)
|
|
src.reagents.skip_next_update = 1
|
|
src.reagents.trans_to_direct(FG.reagents, amt_per_tile * connected.len)
|
|
src.contained_amt = src.reagents.total_volume
|
|
|
|
FG.can_update = 1
|
|
FG.last_contained_amt = 0
|
|
FG.last_members_amt = 0
|
|
if (FG.members.len)
|
|
FG.last_spread_member = FG.members[1]
|
|
FG.update_loop()
|
|
|
|
src.can_update = 1
|
|
src.last_contained_amt = 0
|
|
src.last_members_amt = 0
|
|
src.update_loop()
|
|
|
|
//src.last_add_time = world.time
|
|
|
|
return 1 |