mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-07-22 05:17:38 +01:00
cca0dfe7b6
Part one of our nefarious plans to destroy lag forever, and also accomplish some cool shit. This replaces our renderer system with plane masters, this will also be used to turn skyboxes into backdrops and thus totally remove skybox updating lag. Additionally, this will let us manipulate entire planes very easily to do all sorts of zany shit. All credit goes to the original coders, this is some seriously cool stuff. Also fixes some bizarre smoothing behaviour, reduces updateoverlays calls since now not every single structure in the game tries smoothing with nothing. <img width="1349" height="1349" alt="image" src="https://github.com/user-attachments/assets/9b7cecd7-3c47-448b-9dd8-9b904640bf82" /> <img width="1349" height="1349" alt="image" src="https://github.com/user-attachments/assets/647d75a2-1bff-45ca-ab92-0aea10631afd" /> --------- Co-authored-by: Matt Atlas <liermattia@gmail.com>
444 lines
13 KiB
Plaintext
444 lines
13 KiB
Plaintext
#define TESLA_DEFAULT_POWER 1738260
|
|
#define TESLA_MINI_POWER 156250
|
|
|
|
/obj/singularity/energy_ball
|
|
name = "energy ball"
|
|
desc = "An energy ball."
|
|
icon = 'icons/obj/tesla_engine/energy_ball.dmi'
|
|
icon_state = "energy_ball"
|
|
pixel_x = -32
|
|
pixel_y = -32
|
|
current_size = STAGE_TWO
|
|
move_self = 1
|
|
grav_pull = 0
|
|
contained = 0
|
|
density = 1
|
|
energy = 0
|
|
dissipate = 1
|
|
dissipate_delay = 10
|
|
dissipate_strength = 1
|
|
plane = ABOVE_LIGHTING_PLANE
|
|
blend_mode = BLEND_ADD
|
|
var/failed_direction = 0
|
|
var/list/orbiting_balls = list()
|
|
var/produced_power
|
|
var/energy_to_raise = 32
|
|
var/energy_to_lower = -20
|
|
var/list/immune_things = list(/obj/effect/projectile/muzzle/emitter, /obj/effect/ebeam, /obj/effect/decal/cleanable/ash, /obj/singularity)
|
|
|
|
/obj/singularity/energy_ball/feedback_hints(mob/user, distance, is_adjacent)
|
|
. += ..()
|
|
if(orbiting_balls.len)
|
|
. += "There are <b>[orbiting_balls.len] energy balls</b> orbiting \the [src]."
|
|
|
|
/obj/singularity/energy_ball/ex_act(severity, target)
|
|
return
|
|
|
|
/obj/singularity/energy_ball/Destroy()
|
|
walk(src, 0) // Stop walking
|
|
|
|
for(var/ball in orbiting_balls)
|
|
var/obj/singularity/energy_ball/EB = ball
|
|
qdel(EB)
|
|
|
|
. = ..()
|
|
|
|
/obj/singularity/energy_ball/process()
|
|
if(!orbiting)
|
|
handle_energy()
|
|
|
|
move_the_basket_ball(rand(1, 6) - orbiting_balls.len * 0.25)
|
|
|
|
playsound(src.loc, 'sound/magic/lightningbolt.ogg', 100, 1, extrarange = 30)
|
|
|
|
pixel_x = 0
|
|
pixel_y = 0
|
|
|
|
// Instead of miniballs shooting stuff, decided to make it just count the power produced.
|
|
dir = tesla_zap(src, 10, TESLA_DEFAULT_POWER + orbiting_balls.len * TESLA_MINI_POWER, TRUE)
|
|
|
|
pixel_x = -32
|
|
pixel_y = -32
|
|
|
|
else
|
|
energy = 0 // ensure we dont have miniballs of miniballs
|
|
if(energy < 0)
|
|
qdel(src)
|
|
|
|
/obj/singularity/energy_ball/admin_investigate_setup()
|
|
if(orbiting)
|
|
return
|
|
else
|
|
..()
|
|
|
|
/obj/singularity/energy_ball/proc/move_the_basket_ball(var/move_amount)
|
|
|
|
var/list/valid_directions = GLOB.alldirs.Copy()
|
|
|
|
var/can_zmove = !(locate(/obj/machinery/containment_field) in view(12,src))
|
|
if(can_zmove && prob(10))
|
|
valid_directions.Add(UP)
|
|
valid_directions.Add(DOWN)
|
|
|
|
valid_directions.Remove(failed_direction)
|
|
|
|
var/move_dir = 0
|
|
if(target && prob(75))
|
|
move_dir = get_dir(src, target)
|
|
else
|
|
valid_directions.Remove(dir)
|
|
move_dir = (prob(50) && (dir != failed_direction)) ? dir : pick(valid_directions)
|
|
|
|
if(move_dir & (UP | DOWN) )
|
|
move_amount = 0
|
|
|
|
var/move_tesla = !move_amount ? 0.1 : move_amount
|
|
for(var/i in 0 to move_amount)
|
|
do_single_move(move_dir)
|
|
sleep(1 SECOND / move_tesla)
|
|
|
|
/obj/singularity/energy_ball/proc/do_single_move(var/move_dir)
|
|
var/z_move = 0
|
|
var/turf/T
|
|
switch(move_dir)
|
|
if(UP)
|
|
var/turf/current_turf = get_turf(src)
|
|
T = GET_TURF_ABOVE(current_turf)
|
|
z_move = 1
|
|
if(DOWN)
|
|
var/turf/current_turf = get_turf(src)
|
|
T = GET_TURF_BELOW(current_turf)
|
|
z_move = -1
|
|
else
|
|
T = get_step(src, move_dir)
|
|
|
|
if(can_move(T) && can_dunk(get_turf(src),T,move_dir))
|
|
switch(z_move)
|
|
if(1)
|
|
visible_message(SPAN_DANGER("\The [src] gravitates upwards!"))
|
|
zMove(UP)
|
|
visible_message(SPAN_DANGER("\The [src] gravitates from below!"))
|
|
if(0)
|
|
Move(T)
|
|
if(-1)
|
|
visible_message(SPAN_DANGER("\The [src] gravitates downwards!"))
|
|
zMove(DOWN)
|
|
visible_message(SPAN_DANGER("\The [src] gravitates from above!"))
|
|
|
|
if(dir in GLOB.alldirs)
|
|
dir = move_dir
|
|
else
|
|
dir = pick(GLOB.alldirs)
|
|
|
|
for(var/mob/living/carbon/C in loc)
|
|
dust_mobs(C)
|
|
failed_direction = 0
|
|
else
|
|
failed_direction = move_dir
|
|
|
|
/obj/singularity/energy_ball/proc/can_dunk(var/turf/old_turf,var/turf/new_turf,var/move_direction)
|
|
|
|
if(istype(new_turf,/turf/simulated/wall/r_wall))
|
|
return FALSE
|
|
|
|
if(istype(old_turf,/turf/simulated/floor/reinforced) && (move_direction & DOWN))
|
|
return FALSE
|
|
|
|
if(istype(new_turf,/turf/simulated/floor/reinforced) && (move_direction & UP))
|
|
return FALSE
|
|
|
|
return TRUE
|
|
|
|
/obj/singularity/energy_ball/proc/handle_energy()
|
|
if(energy >= energy_to_raise)
|
|
energy_to_lower = energy_to_raise - 20
|
|
energy_to_raise = energy_to_raise * 1.25
|
|
|
|
playsound(src.loc, 'sound/magic/lightning_chargeup.ogg', 100, 1, extrarange = 30)
|
|
addtimer(CALLBACK(src, PROC_REF(new_mini_ball)), 100)
|
|
|
|
else if(energy < energy_to_lower && orbiting_balls.len)
|
|
energy_to_raise = energy_to_raise / 1.25
|
|
energy_to_lower = (energy_to_raise / 1.25) - 20
|
|
energy = energy_to_raise - 5
|
|
|
|
var/Orchiectomy_target = pick(orbiting_balls)
|
|
qdel(Orchiectomy_target)
|
|
|
|
else if(orbiting_balls.len)
|
|
|
|
// Basically the more balls we have the faster Tesla looses energy.
|
|
if(orbiting_balls.len > 16)
|
|
dissipate_delay = 1.5
|
|
dissipate_strength = 5
|
|
if(orbiting_balls.len > 12)
|
|
dissipate_delay = 2.5
|
|
dissipate_strength = 2
|
|
if(orbiting_balls.len <= 12)
|
|
dissipate_delay = 5
|
|
dissipate_strength = 1
|
|
|
|
dissipate() //sing code has a much better system.
|
|
else // that is when we have no balls but our energy is less
|
|
energy_to_raise = energy_to_raise / 1.25
|
|
energy_to_lower = (energy_to_raise / 1.25) - 20
|
|
|
|
/obj/singularity/energy_ball/proc/new_mini_ball()
|
|
if(!loc)
|
|
return
|
|
var/obj/singularity/energy_ball/EB = new(loc, 0, FALSE, FALSE)
|
|
|
|
EB.transform *= pick(0.3, 0.4, 0.5, 0.6, 0.7)
|
|
var/icon/I = icon(icon,icon_state,dir)
|
|
|
|
var/orbitsize = (I.Width() + I.Height()) * pick(0.4, 0.5, 0.6, 0.7, 0.8)
|
|
orbitsize -= (orbitsize / world.icon_size) * (world.icon_size * 0.25)
|
|
|
|
EB.orbit(src, orbitsize, rand(10, 25))
|
|
|
|
|
|
/obj/singularity/energy_ball/Collide(atom/A)
|
|
if(check_for_immune(A))
|
|
return
|
|
if(isliving(A))
|
|
dust_mobs(A)
|
|
else if(isobj(A))
|
|
if(istype(A, /obj/effect/accelerated_particle))
|
|
consume(A)
|
|
return
|
|
var/obj/O = A
|
|
O.tesla_act(0, TRUE)
|
|
|
|
/obj/singularity/energy_ball/CollidedWith(atom/bumped_atom)
|
|
//Fucking snowflake code
|
|
SHOULD_CALL_PARENT(FALSE)
|
|
SEND_SIGNAL(src, COMSIG_ATOM_BUMPED, bumped_atom)
|
|
|
|
if(check_for_immune(bumped_atom))
|
|
return
|
|
if(isliving(bumped_atom))
|
|
dust_mobs(bumped_atom)
|
|
else if(isobj(bumped_atom))
|
|
if(istype(bumped_atom, /obj/effect/accelerated_particle))
|
|
consume(bumped_atom)
|
|
return
|
|
var/obj/O = bumped_atom
|
|
O.tesla_act(0, TRUE)
|
|
|
|
/obj/singularity/energy_ball/proc/check_for_immune(var/O)
|
|
if(!O)
|
|
return FALSE
|
|
for(var/v in immune_things)
|
|
if(istype(O, v))
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/obj/singularity/energy_ball/Move(NewLoc, Dir)
|
|
. = ..()
|
|
for(var/v in view(0, loc))
|
|
if(istype(v, /obj/singularity))
|
|
continue
|
|
|
|
if(isliving(v))
|
|
dust_mobs(v)
|
|
else if(isobj(v))
|
|
var/obj/O = v
|
|
O.tesla_act(0, TRUE)
|
|
|
|
/obj/singularity/energy_ball/orbit(obj/singularity/energy_ball/target)
|
|
if (istype(target))
|
|
target.orbiting_balls += src
|
|
target.dissipate_strength = target.orbiting_balls.len
|
|
|
|
. = ..()
|
|
|
|
/obj/singularity/energy_ball/stop_orbit()
|
|
. = ..()
|
|
if (!loc && !QDELETED(src))
|
|
qdel(src)
|
|
|
|
/obj/singularity/energy_ball/proc/dust_mobs(atom/A)
|
|
if(!iscarbon(A))
|
|
return
|
|
for(var/obj/machinery/power/grounding_rod/GR in orange(src, 2))
|
|
if(GR.anchored)
|
|
return
|
|
var/mob/living/carbon/C = A
|
|
C.dust()
|
|
|
|
/obj/singularity/energy_ball/tesla_act()
|
|
return
|
|
|
|
/proc/tesla_zap(atom/source, zap_range = 3, power, explosive = FALSE, stun_mobs = TRUE)
|
|
. = source.dir
|
|
if(power < 1000)
|
|
return
|
|
|
|
var/closest_dist = 0
|
|
var/closest_atom
|
|
var/obj/machinery/power/tesla_coil/closest_tesla_coil
|
|
var/obj/machinery/power/grounding_rod/closest_grounding_rod
|
|
var/mob/living/closest_mob
|
|
var/obj/machinery/closest_machine
|
|
var/obj/structure/closest_structure
|
|
var/obj/machinery/power/emitter/closest_emitter // Use only if Tesla is too grown. Will escape.
|
|
var/static/list/blacklisted_types = typecacheof(list(
|
|
/obj/machinery/atmospherics,
|
|
/obj/machinery/field_generator,
|
|
/mob/living/simple_animal,
|
|
/obj/machinery/particle_accelerator/control_box,
|
|
/obj/structure/particle_accelerator/fuel_chamber,
|
|
/obj/structure/particle_accelerator/particle_emitter/center,
|
|
/obj/structure/particle_accelerator/particle_emitter/left,
|
|
/obj/structure/particle_accelerator/particle_emitter/right,
|
|
/obj/structure/particle_accelerator/power_box,
|
|
/obj/structure/particle_accelerator/end_cap,
|
|
/obj/machinery/containment_field,
|
|
/obj/structure/disposalpipe,
|
|
/obj/structure/sign,
|
|
/obj/machinery/gateway,
|
|
/obj/structure/lattice,
|
|
/obj/structure/grille,
|
|
/obj/machinery/the_singularitygen/tesla,
|
|
/obj/machinery/atmospherics/pipe
|
|
))
|
|
var/static/list/things_to_shock = typecacheof(list(
|
|
/obj/machinery,
|
|
/mob/living,
|
|
/obj/structure
|
|
))
|
|
|
|
var/rods_count = 0
|
|
var/beam_range = zap_range + 2
|
|
for(var/A in typecache_filter_multi_list_exclusion(oview(source, beam_range), things_to_shock, blacklisted_types))
|
|
|
|
if(istype(source, /obj/singularity/energy_ball) && istype(A, /obj/machinery/power/tesla_beacon))
|
|
var/obj/machinery/power/tesla_beacon/E = A
|
|
var/obj/singularity/energy_ball/B = source
|
|
if(!E.active)
|
|
return
|
|
B.visible_message("\The [B] discharges entirely at [A] until it dissapears and [A] melts down")
|
|
B.Beam(E, icon_state="lightning[rand(1,12)]", icon = 'icons/effects/effects.dmi', time=2, maxdistance=beam_range)
|
|
E.tesla_act(0, TRUE)
|
|
qdel(B)
|
|
return
|
|
|
|
else if(istype(A, /obj/machinery/power/tesla_coil))
|
|
var/dist = get_dist(source, A)
|
|
var/obj/machinery/power/tesla_coil/C = A
|
|
if(dist <= zap_range && (dist < closest_dist || !closest_tesla_coil) && !C.being_shocked)
|
|
closest_dist = dist
|
|
|
|
//we use both of these to save on istype and typecasting overhead later on
|
|
//while still allowing common code to run before hand
|
|
closest_tesla_coil = C
|
|
closest_atom = C
|
|
|
|
else if(closest_tesla_coil)
|
|
if(istype(A, /obj/machinery/power/grounding_rod)) // to count number of rods
|
|
rods_count += 1
|
|
continue //no need checking these other things
|
|
|
|
else if(istype(A, /obj/machinery/power/grounding_rod))
|
|
rods_count += 1
|
|
var/dist = get_dist(source, A)-2
|
|
if(dist <= zap_range && (dist < closest_dist || !closest_grounding_rod))
|
|
closest_grounding_rod = A
|
|
closest_atom = A
|
|
closest_dist = dist
|
|
|
|
else if(closest_grounding_rod)
|
|
continue
|
|
|
|
else if(istype(A, /obj/machinery/power/emitter))
|
|
var/obj/machinery/power/emitter/e = A
|
|
closest_emitter = e
|
|
|
|
else if(closest_emitter)
|
|
continue
|
|
|
|
else if(isliving(A))
|
|
var/dist = get_dist(source, A)
|
|
var/mob/living/L = A
|
|
if(dist <= zap_range && (dist < closest_dist || !closest_mob) && L.stat != DEAD && !L.tesla_ignore)
|
|
closest_mob = L
|
|
closest_atom = A
|
|
closest_dist = dist
|
|
|
|
else if(closest_mob)
|
|
continue
|
|
|
|
else if(istype(A, /obj/machinery))
|
|
var/obj/machinery/M = A
|
|
var/dist = get_dist(source, A)
|
|
if(dist <= zap_range && (dist < closest_dist || !closest_machine) && !M.being_shocked)
|
|
closest_machine = M
|
|
closest_atom = A
|
|
closest_dist = dist
|
|
|
|
else if(closest_mob)
|
|
continue
|
|
|
|
else if(istype(A, /obj/structure))
|
|
var/obj/structure/S = A
|
|
var/dist = get_dist(source, A)
|
|
if(dist <= zap_range && (dist < closest_dist || !closest_tesla_coil) && !S.being_shocked)
|
|
closest_structure = S
|
|
closest_atom = A
|
|
closest_dist = dist
|
|
|
|
var/melt = FALSE
|
|
if(istype(source, /obj/singularity/energy_ball))
|
|
var/obj/singularity/energy_ball/E = source
|
|
if(E.energy && (E.orbiting_balls.len > rods_count * 4)) // so that miniballs don't fry stuff.
|
|
melt = TRUE // 1 grounding rod can handle max 4 balls
|
|
E.visible_message(SPAN_DANGER("All [E.orbiting_balls.len] energize for a second, sending their energy to the main ball, which redirects it at the nearest object! Sacrificing one of its miniballs!"))
|
|
for(var/obj/singularity/energy_ball/mini in E.orbiting_balls)
|
|
mini.Beam(source, icon_state="lightning[rand(1,12)]", icon = 'icons/effects/effects.dmi', time=2)
|
|
playsound(source.loc, 'sound/magic/lightning_chargeup.ogg', 100, 1, extrarange = 30)
|
|
E.energy_to_raise = E.energy_to_raise / 1.25
|
|
E.energy_to_lower = (E.energy_to_raise / 1.25) - 20
|
|
E.energy = E.energy_to_raise - 5
|
|
|
|
var/Orchiectomy_target = pick(E.orbiting_balls)
|
|
qdel(Orchiectomy_target)
|
|
E.dissipate()
|
|
|
|
//Alright, we've done our loop, now lets see if was anything interesting in range
|
|
if(closest_atom)
|
|
//common stuff
|
|
source.Beam(closest_atom, icon_state="lightning[rand(1,12)]", icon = 'icons/effects/effects.dmi', time= 5)
|
|
var/zapdir = get_dir(source, closest_atom)
|
|
if(zapdir)
|
|
. = zapdir
|
|
|
|
//per type stuff:
|
|
if(closest_tesla_coil)
|
|
closest_tesla_coil.tesla_act(power, melt)
|
|
|
|
else if(closest_grounding_rod)
|
|
closest_grounding_rod.tesla_act(power, melt)
|
|
|
|
else if(closest_emitter)
|
|
closest_emitter.tesla_act(power, melt)
|
|
|
|
else if(closest_mob)
|
|
var/shock_damage = clamp(round(power/400), 10, 90) + rand(-5, 5)
|
|
closest_mob.electrocute_act(shock_damage, source, 1, tesla_shock = 1)
|
|
if(issilicon(closest_mob))
|
|
var/mob/living/silicon/S = closest_mob
|
|
if(stun_mobs)
|
|
S.emp_act(EMP_LIGHT)
|
|
tesla_zap(S, 7, power / 1.5, explosive, stun_mobs) // metallic folks bounce it further
|
|
else
|
|
tesla_zap(closest_mob, 5, power / 1.5, explosive, stun_mobs)
|
|
|
|
else if(closest_machine)
|
|
closest_machine.tesla_act(power, melt)
|
|
|
|
else if(closest_structure)
|
|
closest_structure.tesla_act(power, melt)
|
|
|
|
#undef TESLA_DEFAULT_POWER
|
|
#undef TESLA_MINI_POWER
|