mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-27 10:02:12 +00:00
3591 individual conflicts Update build.js Update install_node.sh Update byond.js oh my fucking god hat slow huh holy shit we all fall down 2 more I missed 2900 individual conflicts 2700 Individual conflicts replaces yarn file with tg version, bumping us down to 2200-ish Down to 2000 individual conflicts 140 down mmm aaaaaaaaaaaaaaaaaaa not yt 575 soon 900 individual conflicts 600 individual conflicts, 121 file conflicts im not okay 160 across 19 files 29 in 4 files 0 conflicts, compiletime fix time some minor incap stuff missed ticks weird dupe definition stuff missed ticks 2 incap fixes undefs and pie fix Radio update and some extra minor stuff returns a single override no more dupe definitions, 175 compiletime errors Unticked file fix sound and emote stuff honk and more radio stuff
370 lines
12 KiB
Plaintext
370 lines
12 KiB
Plaintext
#define TESLA_DEFAULT_ENERGY (695.304 MEGA JOULES)
|
|
#define TESLA_MINI_ENERGY (347.652 MEGA JOULES) // Has a weird scaling thing so this is a lie for now (doesn't generate power anyways).
|
|
//Zap constants, speeds up targeting
|
|
#define BIKE (COIL + 1)
|
|
#define COIL (ROD + 1)
|
|
#define ROD (RIDE + 1)
|
|
#define RIDE (LIVING + 1)
|
|
#define LIVING (MACHINERY + 1)
|
|
#define MACHINERY (BLOB + 1)
|
|
#define BLOB (STRUCTURE + 1)
|
|
#define STRUCTURE (1)
|
|
|
|
/// The Tesla engine
|
|
/obj/energy_ball
|
|
name = "energy ball"
|
|
desc = "An energy ball."
|
|
icon = 'icons/obj/machines/engine/energy_ball.dmi'
|
|
icon_state = "energy_ball"
|
|
anchored = TRUE
|
|
appearance_flags = LONG_GLIDE
|
|
density = TRUE
|
|
plane = MASSIVE_OBJ_PLANE
|
|
plane = ABOVE_LIGHTING_PLANE
|
|
light_range = 6
|
|
move_resist = INFINITY
|
|
obj_flags = CAN_BE_HIT | DANGEROUS_POSSESSION
|
|
pixel_x = -ICON_SIZE_X
|
|
pixel_y = -ICON_SIZE_Y
|
|
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF | FREEZE_PROOF | SHUTTLE_CRUSH_PROOF
|
|
flags_1 = SUPERMATTER_IGNORES_1
|
|
|
|
var/energy
|
|
var/target
|
|
var/list/orbiting_balls = list()
|
|
var/miniball = FALSE
|
|
var/produced_power
|
|
var/energy_to_raise = 32
|
|
var/energy_to_lower = -20
|
|
var/list/shocked_things = list()
|
|
|
|
/obj/energy_ball/Initialize(mapload, starting_energy = 50, is_miniball = FALSE)
|
|
. = ..()
|
|
|
|
energy = starting_energy
|
|
miniball = is_miniball
|
|
START_PROCESSING(SSobj, src)
|
|
|
|
if (!is_miniball)
|
|
set_light(10, 7, "#5e5edd")
|
|
|
|
var/turf/spawned_turf = get_turf(src)
|
|
message_admins("A tesla has been created at [ADMIN_VERBOSEJMP(spawned_turf)].")
|
|
investigate_log("was created at [AREACOORD(spawned_turf)].", INVESTIGATE_ENGINE)
|
|
|
|
/obj/energy_ball/Destroy()
|
|
if(orbiting && istype(orbiting.parent, /obj/energy_ball))
|
|
var/obj/energy_ball/parent_energy_ball = orbiting.parent
|
|
parent_energy_ball.orbiting_balls -= src
|
|
|
|
QDEL_LIST(orbiting_balls)
|
|
STOP_PROCESSING(SSobj, src)
|
|
|
|
return ..()
|
|
|
|
/obj/energy_ball/process()
|
|
if(orbiting)
|
|
energy = 0 // ensure we dont have miniballs of miniballs
|
|
else
|
|
handle_energy()
|
|
|
|
move(4 + orbiting_balls.len * 1.5)
|
|
|
|
playsound(src.loc, 'sound/effects/magic/lightningbolt.ogg', 100, TRUE, extrarange = 30)
|
|
|
|
pixel_x = 0
|
|
pixel_y = 0
|
|
shocked_things.Cut(1, shocked_things.len / 1.3)
|
|
var/list/shocking_info = list()
|
|
tesla_zap(source = src, zap_range = 3, power = TESLA_DEFAULT_ENERGY, shocked_targets = shocking_info)
|
|
|
|
pixel_x = -ICON_SIZE_X
|
|
pixel_y = -ICON_SIZE_Y
|
|
for (var/ball in orbiting_balls)
|
|
var/range = rand(1, clamp(orbiting_balls.len, 2, 3))
|
|
var/list/temp_shock = list()
|
|
//We zap off the main ball instead of ourselves to make things looks proper
|
|
tesla_zap(source = src, zap_range = range, power = TESLA_MINI_ENERGY / 7 * range, shocked_targets = temp_shock)
|
|
shocking_info += temp_shock
|
|
shocked_things += shocking_info
|
|
|
|
/obj/energy_ball/examine(mob/user)
|
|
. = ..()
|
|
if(orbiting_balls.len)
|
|
. += "There are [orbiting_balls.len] mini-balls orbiting it."
|
|
|
|
/obj/energy_ball/proc/move(move_amount)
|
|
var/list/dirs = GLOB.alldirs.Copy()
|
|
if(shocked_things.len)
|
|
for (var/i in 1 to 30)
|
|
var/atom/real_thing = pick(shocked_things)
|
|
dirs += get_dir(src, real_thing) //Carry some momentum yeah? Just a bit tho
|
|
for (var/i in 0 to move_amount)
|
|
var/move_dir = pick(dirs) //ensures teslas don't just sit around
|
|
if (target && prob(10))
|
|
move_dir = get_dir(src, target)
|
|
var/turf/turf_to_move = get_step(src, move_dir)
|
|
if (can_move(turf_to_move))
|
|
forceMove(turf_to_move)
|
|
setDir(move_dir)
|
|
for (var/mob/living/carbon/mob_to_dust in loc)
|
|
dust_mobs(mob_to_dust)
|
|
|
|
/obj/energy_ball/proc/can_move(turf/to_move)
|
|
if (!to_move)
|
|
return FALSE
|
|
|
|
for (var/_thing in to_move)
|
|
var/atom/thing = _thing
|
|
if (SEND_SIGNAL(thing, COMSIG_ATOM_SINGULARITY_TRY_MOVE) & SINGULARITY_TRY_MOVE_BLOCK)
|
|
return FALSE
|
|
|
|
return TRUE
|
|
|
|
/obj/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/effects/magic/lightning_chargeup.ogg', 100, TRUE, extrarange = 30)
|
|
addtimer(CALLBACK(src, PROC_REF(new_mini_ball)), 10 SECONDS)
|
|
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)
|
|
|
|
/obj/energy_ball/proc/new_mini_ball()
|
|
if(!loc)
|
|
return
|
|
|
|
var/obj/energy_ball/miniball = new /obj/energy_ball(
|
|
loc,
|
|
/* starting_energy = */ 0,
|
|
/* is_miniball = */ TRUE
|
|
)
|
|
|
|
miniball.transform *= pick(0.3, 0.4, 0.5, 0.6, 0.7)
|
|
var/list/icon_dimensions = get_icon_dimensions(icon)
|
|
|
|
var/orbitsize = (icon_dimensions["width"] + icon_dimensions["height"]) * pick(0.4, 0.5, 0.6, 0.7, 0.8)
|
|
orbitsize -= (orbitsize / ICON_SIZE_ALL) * (ICON_SIZE_ALL * 0.25)
|
|
miniball.orbit(src, orbitsize, pick(FALSE, TRUE), rand(10, 25), pick(3, 4, 5, 6, 36))
|
|
|
|
/obj/energy_ball/Bump(atom/A)
|
|
dust_mobs(A)
|
|
|
|
/obj/energy_ball/Bumped(atom/movable/AM)
|
|
dust_mobs(AM)
|
|
|
|
/obj/energy_ball/attack_tk(mob/user)
|
|
if(!iscarbon(user))
|
|
return
|
|
var/mob/living/carbon/jedi = user
|
|
to_chat(jedi, span_userdanger("That was a shockingly dumb idea."))
|
|
var/obj/item/organ/internal/brain/rip_u = locate(/obj/item/organ/internal/brain) in jedi.organs
|
|
jedi.ghostize(jedi)
|
|
if(rip_u)
|
|
qdel(rip_u)
|
|
jedi.investigate_log("had [jedi.p_their()] brain dusted by touching [src] with telekinesis.", INVESTIGATE_DEATHS)
|
|
jedi.death()
|
|
return COMPONENT_CANCEL_ATTACK_CHAIN
|
|
|
|
/obj/energy_ball/orbit(obj/energy_ball/target)
|
|
if (istype(target))
|
|
target.orbiting_balls += src
|
|
. = ..()
|
|
|
|
/obj/energy_ball/stop_orbit()
|
|
if (orbiting && istype(orbiting.parent, /obj/energy_ball))
|
|
var/obj/energy_ball/orbitingball = orbiting.parent
|
|
orbitingball.orbiting_balls -= src
|
|
. = ..()
|
|
if (!QDELETED(src))
|
|
qdel(src)
|
|
|
|
|
|
/obj/energy_ball/proc/dust_mobs(atom/A)
|
|
if(isliving(A))
|
|
var/mob/living/living = A
|
|
if(living.incorporeal_move || HAS_TRAIT(living, TRAIT_GODMODE))
|
|
return
|
|
if(!iscarbon(A))
|
|
return
|
|
for(var/obj/machinery/power/energy_accumulator/grounding_rod/GR in orange(src, 2))
|
|
if(GR.anchored)
|
|
return
|
|
var/mob/living/carbon/C = A
|
|
C.investigate_log("has been dusted by an energy ball.", INVESTIGATE_DEATHS)
|
|
C.dust()
|
|
|
|
/proc/tesla_zap(atom/source, zap_range = 3, power, cutoff = 4e5, zap_flags = ZAP_DEFAULT_FLAGS, list/shocked_targets = list())
|
|
if(QDELETED(source))
|
|
return
|
|
if(!(zap_flags & ZAP_ALLOW_DUPLICATES))
|
|
LAZYSET(shocked_targets, source, TRUE) //I don't want no null refs in my list yeah?
|
|
. = source.dir
|
|
if(power < cutoff)
|
|
return
|
|
|
|
/*
|
|
THIS IS SO FUCKING UGLY AND I HATE IT, but I can't make it nice without making it slower, check*N rather then n. So we're stuck with it.
|
|
*/
|
|
var/atom/closest_atom
|
|
var/closest_type = 0
|
|
var/static/list/things_to_shock = zebra_typecacheof(list(
|
|
// Things that we want to shock.
|
|
/obj/machinery = TRUE,
|
|
/mob/living = TRUE,
|
|
/obj/structure = TRUE,
|
|
/obj/vehicle/ridden = TRUE,
|
|
|
|
// Things that we don't want to shock.
|
|
/obj/machinery/atmospherics = FALSE,
|
|
/obj/machinery/portable_atmospherics = FALSE,
|
|
/obj/machinery/power/emitter = FALSE,
|
|
/obj/machinery/field/generator = FALSE,
|
|
/obj/machinery/field/containment = FALSE,
|
|
/obj/machinery/camera = FALSE,
|
|
/obj/machinery/gateway = FALSE,
|
|
/mob/living/simple_animal = FALSE,
|
|
/obj/structure/disposalpipe = FALSE,
|
|
/obj/structure/disposaloutlet = FALSE,
|
|
/obj/machinery/disposal/delivery_chute = FALSE,
|
|
/obj/structure/sign = FALSE,
|
|
/obj/structure/lattice = FALSE,
|
|
/obj/structure/grille = FALSE,
|
|
/obj/structure/frame/machine = FALSE,
|
|
))
|
|
|
|
//Ok so we are making an assumption here. We assume that view() still calculates from the center out.
|
|
//This means that if we find an object we can assume it is the closest one of its type. This is somewhat of a speed increase.
|
|
//This also means we have no need to track distance, as the doview() proc does it all for us.
|
|
|
|
//Darkness fucks oview up hard. I've tried dview() but it doesn't seem to work
|
|
//I hate existance
|
|
for(var/atom/A as anything in typecache_filter_list(oview(zap_range+2, source), things_to_shock))
|
|
if(!(zap_flags & ZAP_ALLOW_DUPLICATES) && LAZYACCESS(shocked_targets, A))
|
|
continue
|
|
// NOTE: these type checks are safe because CURRENTLY the range family of procs returns turfs in least to greatest distance order
|
|
// This is unspecified behavior tho, so if it ever starts acting up just remove these optimizations and include a distance check
|
|
if(closest_type >= BIKE)
|
|
break
|
|
|
|
else if(istype(A, /obj/vehicle/ridden/bicycle))//God's not on our side cause he hates idiots.
|
|
var/obj/vehicle/ridden/bicycle/B = A
|
|
if(!HAS_TRAIT(B, TRAIT_BEING_SHOCKED) && B.can_buckle)//Gee goof thanks for the boolean
|
|
//we use both of these to save on istype and typecasting overhead later on
|
|
//while still allowing common code to run before hand
|
|
closest_type = BIKE
|
|
closest_atom = B
|
|
|
|
else if(closest_type >= COIL)
|
|
continue //no need checking these other things
|
|
|
|
else if(istype(A, /obj/machinery/power/energy_accumulator/tesla_coil))
|
|
if(!HAS_TRAIT(A, TRAIT_BEING_SHOCKED))
|
|
closest_type = COIL
|
|
closest_atom = A
|
|
|
|
else if(closest_type >= ROD)
|
|
continue
|
|
|
|
else if(istype(A, /obj/machinery/power/energy_accumulator/grounding_rod))
|
|
closest_type = ROD
|
|
closest_atom = A
|
|
|
|
else if(closest_type >= RIDE)
|
|
continue
|
|
|
|
else if(istype(A,/obj/vehicle/ridden))
|
|
var/obj/vehicle/ridden/R = A
|
|
if(R.can_buckle && !HAS_TRAIT(R, TRAIT_BEING_SHOCKED))
|
|
closest_type = RIDE
|
|
closest_atom = A
|
|
|
|
else if(closest_type >= LIVING)
|
|
continue
|
|
|
|
else if(isliving(A))
|
|
var/mob/living/L = A
|
|
if(L.stat != DEAD && !HAS_TRAIT(L, TRAIT_TESLA_SHOCKIMMUNE) && !HAS_TRAIT(L, TRAIT_BEING_SHOCKED))
|
|
closest_type = LIVING
|
|
closest_atom = A
|
|
|
|
else if(closest_type >= MACHINERY)
|
|
continue
|
|
|
|
else if(ismachinery(A))
|
|
if(!HAS_TRAIT(A, TRAIT_BEING_SHOCKED))
|
|
closest_type = MACHINERY
|
|
closest_atom = A
|
|
|
|
else if(closest_type >= BLOB)
|
|
continue
|
|
|
|
else if(istype(A, /obj/structure/blob))
|
|
if(!HAS_TRAIT(A, TRAIT_BEING_SHOCKED))
|
|
closest_type = BLOB
|
|
closest_atom = A
|
|
|
|
else if(closest_type >= STRUCTURE)
|
|
continue
|
|
|
|
else if(isstructure(A))
|
|
if(!HAS_TRAIT(A, TRAIT_BEING_SHOCKED))
|
|
closest_type = STRUCTURE
|
|
closest_atom = A
|
|
|
|
//Alright, we've done our loop, now lets see if was anything interesting in range
|
|
if(!closest_atom)
|
|
return
|
|
//common stuff
|
|
source.Beam(closest_atom, icon_state="lightning[rand(1,12)]", time = 5)
|
|
var/zapdir = get_dir(source, closest_atom)
|
|
if(zapdir)
|
|
. = zapdir
|
|
|
|
var/next_range = 2
|
|
if(closest_type == COIL)
|
|
next_range = 5
|
|
|
|
if(closest_type == LIVING)
|
|
var/mob/living/closest_mob = closest_atom
|
|
ADD_TRAIT(closest_mob, TRAIT_BEING_SHOCKED, WAS_SHOCKED)
|
|
addtimer(TRAIT_CALLBACK_REMOVE(closest_mob, TRAIT_BEING_SHOCKED, WAS_SHOCKED), 1 SECONDS)
|
|
var/shock_damage = (zap_flags & ZAP_MOB_DAMAGE) ? (min(round(power / 600), 90) + rand(-5, 5)) : 0
|
|
closest_mob.electrocute_act(shock_damage, source, 1, SHOCK_TESLA | ((zap_flags & ZAP_MOB_STUN) ? NONE : SHOCK_NOSTUN))
|
|
if(issilicon(closest_mob))
|
|
var/mob/living/silicon/S = closest_mob
|
|
if((zap_flags & ZAP_MOB_STUN) && (zap_flags & ZAP_MOB_DAMAGE))
|
|
S.emp_act(EMP_LIGHT)
|
|
next_range = 7 // metallic folks bounce it further
|
|
else
|
|
next_range = 5
|
|
power /= 1.5
|
|
|
|
else
|
|
power = closest_atom.zap_act(power, zap_flags)
|
|
|
|
if(prob(20))//I know I know
|
|
var/list/shocked_copy = shocked_targets.Copy()
|
|
tesla_zap(source = closest_atom, zap_range = next_range, power = power * 0.5, cutoff = cutoff, zap_flags = zap_flags, shocked_targets = shocked_copy)
|
|
tesla_zap(source = closest_atom, zap_range = next_range, power = power * 0.5, cutoff = cutoff, zap_flags = zap_flags, shocked_targets = shocked_targets)
|
|
shocked_targets += shocked_copy
|
|
else
|
|
tesla_zap(source = closest_atom, zap_range = next_range, power = power, cutoff = cutoff, zap_flags = zap_flags, shocked_targets = shocked_targets)
|
|
|
|
#undef BIKE
|
|
#undef COIL
|
|
#undef ROD
|
|
#undef RIDE
|
|
#undef LIVING
|
|
#undef MACHINERY
|
|
#undef BLOB
|
|
#undef STRUCTURE
|
|
|
|
#undef TESLA_DEFAULT_ENERGY
|
|
#undef TESLA_MINI_ENERGY
|