mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-12 03:02:54 +00:00
Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com> Co-authored-by: Kashargul <KashL@t-online.de>
320 lines
10 KiB
Plaintext
320 lines
10 KiB
Plaintext
#define TESLA_DEFAULT_POWER 1738260
|
|
#define TESLA_MINI_POWER 869130
|
|
|
|
/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 = TRUE
|
|
energy = 0
|
|
dissipate = 1
|
|
dissipate_delay = 5
|
|
dissipate_strength = 1
|
|
var/list/orbiting_balls = list()
|
|
var/miniball = FALSE
|
|
var/produced_power
|
|
var/energy_to_raise = 32
|
|
var/energy_to_lower = -20
|
|
|
|
/obj/singularity/energy_ball/New(loc, starting_energy = 50, is_miniball = FALSE)
|
|
..()
|
|
miniball = is_miniball
|
|
|
|
/obj/singularity/energy_ball/Initialize()
|
|
. = ..()
|
|
if(!miniball)
|
|
set_light(10, 7, "#EEEEFF")
|
|
|
|
/obj/singularity/energy_ball/ex_act(severity, target)
|
|
return
|
|
|
|
/obj/singularity/energy_ball/Destroy()
|
|
if(orbiting && istype(orbiting.parent, /obj/singularity/energy_ball)) //CHOMPEdit
|
|
var/obj/singularity/energy_ball/EB = orbiting.parent //CHOMPEdit
|
|
EB.orbiting_balls -= src
|
|
|
|
for(var/obj/singularity/energy_ball/EB as anything in orbiting_balls)
|
|
qdel(EB)
|
|
|
|
. = ..()
|
|
|
|
/obj/singularity/energy_ball/admin_investigate_setup()
|
|
if(miniball)
|
|
return //don't annnounce miniballs
|
|
..()
|
|
|
|
|
|
/obj/singularity/energy_ball/process(var/wait = 20)
|
|
set waitfor = FALSE
|
|
if(!orbiting)
|
|
if (handle_energy())
|
|
return
|
|
|
|
move_the_basket_ball(max(wait - 5, 4 + orbiting_balls.len * 1.5))
|
|
|
|
playsound(src, 'sound/effects/lightningbolt.ogg', 100, 1, extrarange = 30)
|
|
|
|
set_dir(tesla_zap(src, 7, TESLA_DEFAULT_POWER, TRUE))
|
|
|
|
for (var/ball in orbiting_balls)
|
|
var/range = rand(1, CLAMP(orbiting_balls.len, 3, 7))
|
|
tesla_zap(ball, range, TESLA_MINI_POWER/7*range, TRUE)
|
|
else
|
|
energy = 0 // ensure we dont have miniballs of miniballs
|
|
|
|
/obj/singularity/energy_ball/examine(mob/user)
|
|
. = ..()
|
|
if(orbiting_balls.len)
|
|
. += "The amount of orbiting mini-balls is [orbiting_balls.len]."
|
|
|
|
/obj/singularity/energy_ball/proc/move_the_basket_ball(var/move_amount)
|
|
//we face the last thing we zapped, so this lets us favor that direction a bit
|
|
var/move_bias = dir
|
|
for(var/i in 0 to move_amount)
|
|
var/move_dir = pick(global.alldirs + move_bias) //ensures large-ball teslas don't just sit around
|
|
if(target && prob(10))
|
|
move_dir = get_dir(src,target)
|
|
var/turf/T = get_step(src, move_dir)
|
|
if(can_move(T))
|
|
forceMove(T)
|
|
set_dir(move_dir)
|
|
for(var/mob/living/carbon/C in loc)
|
|
dust_mob(C)
|
|
sleep(1) // So movement is smooth
|
|
|
|
/obj/singularity/energy_ball/proc/handle_energy()
|
|
if (energy <= 0)
|
|
log_game("TESLA([x],[y],[z]) Collapsed entirely.")
|
|
investigate_log("collapsed.", I_SINGULO)
|
|
qdel(src)
|
|
return TRUE
|
|
|
|
if(energy >= energy_to_raise)
|
|
energy_to_lower = energy_to_raise - 20
|
|
energy_to_raise = energy_to_raise * 1.25
|
|
|
|
playsound(src, 'sound/effects/lightning_chargeup.ogg', 100, 1, extrarange = 30)
|
|
//addtimer(CALLBACK(src, PROC_REF(new_mini_ball)), 100)
|
|
spawn(100) new_mini_ball()
|
|
|
|
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
|
|
|
|
var/Orchiectomy_target = pick(orbiting_balls)
|
|
qdel(Orchiectomy_target)
|
|
|
|
else
|
|
dissipate() //sing code has a much better system.
|
|
|
|
/obj/singularity/energy_ball/proc/new_mini_ball()
|
|
if(!loc)
|
|
return
|
|
var/obj/singularity/energy_ball/EB = new(loc, 0, TRUE)
|
|
GLOB.all_singularities -= EB //why are these miniballs even singularities in the first place, they don't do anything
|
|
|
|
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, pick(FALSE, TRUE), rand(10, 25), pick(3, 4, 5, 6, 36))
|
|
|
|
/obj/singularity/energy_ball/attack_hand(mob/user)
|
|
dust_mob(user)
|
|
return 1
|
|
|
|
/obj/singularity/energy_ball/Bump(atom/A)
|
|
dust_mob(A)
|
|
|
|
/obj/singularity/energy_ball/Bumped(atom/movable/AM)
|
|
dust_mob(AM)
|
|
|
|
/obj/singularity/energy_ball/orbit(obj/singularity/energy_ball/target)
|
|
if (istype(target))
|
|
target.orbiting_balls += src
|
|
//TODO-LESH-DEL global.poi_list -= src
|
|
target.dissipate_strength = target.orbiting_balls.len + 1
|
|
|
|
. = ..()
|
|
/obj/singularity/energy_ball/stop_orbit()
|
|
if (orbiting && istype(orbiting.parent, /obj/singularity/energy_ball)) //CHOMPEdit
|
|
var/obj/singularity/energy_ball/orbitingball = orbiting.parent //CHOMPEdit
|
|
orbitingball.orbiting_balls -= src
|
|
orbitingball.dissipate_strength = orbitingball.orbiting_balls.len + 1
|
|
..()
|
|
if (!loc && !QDELETED(src))
|
|
qdel(src)
|
|
|
|
|
|
/obj/singularity/energy_ball/proc/dust_mob(mob/living/L)
|
|
if(!istype(L) || L.incorporeal_move)
|
|
return
|
|
// L.dust() - Changing to do fatal elecrocution instead
|
|
L.electrocute_act(500, src, def_zone = BP_TORSO)
|
|
|
|
/proc/tesla_zap(atom/source, zap_range = 3, power, explosive = FALSE, stun_mobs = TRUE)
|
|
if(!source) // Some mobs and maybe some objects delete themselves when they die.
|
|
return
|
|
. = 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/structure/blob/closest_blob
|
|
var/static/things_to_shock = typecacheof(list(/obj/machinery, /mob/living, /obj/structure))
|
|
var/static/blacklisted_tesla_types = typecacheof(list(
|
|
/obj/machinery/atmospherics,
|
|
/obj/machinery/power/emitter,
|
|
/obj/machinery/field_generator,
|
|
/obj/machinery/door/blast,
|
|
/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))
|
|
|
|
for(var/A in typecache_filter_multi_list_exclusion(oview(source, zap_range+2), things_to_shock, blacklisted_tesla_types))
|
|
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)
|
|
continue //no need checking these other things
|
|
|
|
else if(istype(A, /obj/machinery/power/grounding_rod))
|
|
var/obj/machinery/power/grounding_rod/G = A
|
|
var/dist = get_dist(source, A) - (G.anchored ? 2 : 0)
|
|
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(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.status_flags & GODMODE))
|
|
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_machine)
|
|
continue
|
|
|
|
else if(istype(A, /obj/structure/blob))
|
|
var/obj/structure/blob/B = A
|
|
var/dist = get_dist(source, A)
|
|
if(dist <= zap_range && (dist < closest_dist || !closest_tesla_coil) && !B.being_shocked)
|
|
closest_blob = B
|
|
closest_atom = A
|
|
closest_dist = dist
|
|
|
|
else if(closest_blob)
|
|
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
|
|
|
|
//Alright, we've done our loop, now lets see if was anything interesting in range
|
|
if(closest_atom)
|
|
//common stuff
|
|
var/atom/srcLoc = get_turf(source) // VOREStation Edit - Makes beams look nicer
|
|
srcLoc.Beam(closest_atom, icon_state="lightning[rand(1,12)]", time=5, maxdistance = INFINITY) // VOREStation Edit - Makes beams look nicer
|
|
var/zapdir = get_dir(source, closest_atom)
|
|
if(zapdir)
|
|
. = zapdir
|
|
|
|
var/drain_energy = FALSE // VOREStation Edit - Safety First! Drain Tesla fast when its loose
|
|
|
|
//per type stuff:
|
|
if(closest_tesla_coil)
|
|
closest_tesla_coil.tesla_act(power, explosive, stun_mobs)
|
|
|
|
else if(closest_grounding_rod)
|
|
closest_grounding_rod.tesla_act(power, explosive, stun_mobs)
|
|
|
|
else if(closest_mob)
|
|
var/shock_damage = CLAMP(round(power/400), 10, 90) + rand(-5, 5)
|
|
closest_mob.electrocute_act(shock_damage, source, 1 - closest_mob.get_shock_protection(), ran_zone())
|
|
log_game("TESLA([source.x],[source.y],[source.z]) Shocked [key_name(closest_mob)] for [shock_damage]dmg.")
|
|
message_admins("Tesla zapped [key_name_admin(closest_mob)]!")
|
|
if(issilicon(closest_mob))
|
|
var/mob/living/silicon/S = closest_mob
|
|
if(stun_mobs)
|
|
S.emp_act(3 /*EMP_LIGHT*/)
|
|
tesla_zap(closest_mob, 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)
|
|
drain_energy = TRUE // VOREStation Edit - Safety First! Drain Tesla fast when its loose
|
|
closest_machine.tesla_act(power, explosive, stun_mobs)
|
|
|
|
else if(closest_blob)
|
|
drain_energy = TRUE // VOREStation Edit - Safety First! Drain Tesla fast when its loose
|
|
closest_blob.tesla_act(power, explosive, stun_mobs)
|
|
|
|
else if(closest_structure)
|
|
drain_energy = TRUE // VOREStation Edit - Safety First! Drain Tesla fast when its loose
|
|
closest_structure.tesla_act(power, explosive, stun_mobs)
|
|
|
|
// VOREStation Edit Start - Safety First! Drain Tesla fast when its loose
|
|
if(drain_energy && istype(source, /obj/singularity/energy_ball))
|
|
var/obj/singularity/energy_ball/EB = source
|
|
if (EB.energy > 0)
|
|
EB.energy -= min(EB.energy, max(10, round(EB.energy * 0.05)))
|
|
// VOREStation Edit End
|
|
|
|
#undef TESLA_DEFAULT_POWER
|
|
#undef TESLA_MINI_POWER
|