mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-21 12:02:31 +01:00
Ported the various matrix procs and defines from TG. Updated our snowflake procs with the Bay's current version. Refactor of our orbit proc to align with the updated procs, tesla energy ball too.
446 lines
13 KiB
Plaintext
446 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 = EFFECTS_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/ex_act(severity, target)
|
|
return
|
|
|
|
/obj/singularity/energy_ball/Destroy()
|
|
walk(src, 0) // Stop walking
|
|
if(orbiting && istype(orbiting.orbiting, /obj/singularity/energy_ball))
|
|
var/obj/singularity/energy_ball/EB = orbiting.orbiting
|
|
EB.orbiting_balls -= src
|
|
|
|
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/get_examine_text(mob/user, distance, is_adjacent, infix, suffix)
|
|
. = ..()
|
|
if(orbiting_balls.len)
|
|
. += "There are [orbiting_balls.len] energy balls orbiting \the [src]."
|
|
|
|
|
|
/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)
|
|
T = GetAbove(src)
|
|
z_move = 1
|
|
if(DOWN)
|
|
T = GetBelow(src)
|
|
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/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/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 (orbiting && istype(orbiting.orbiting, /obj/singularity/energy_ball))
|
|
var/obj/singularity/energy_ball/orbitingball = orbiting.orbiting
|
|
orbitingball.orbiting_balls -= src
|
|
orbitingball.dissipate_strength = orbitingball.orbiting_balls.len
|
|
. = ..()
|
|
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
|