Skip to content

Commit

Permalink
Bluespace cannon update (#11286)
Browse files Browse the repository at this point in the history
* you are now able to shoot shuttles with BSA

* wip

* remove shooting shuttles

* boom

* more changes

* more changes

* invisible terminal, BSA isn't holographic, qdel terminal on bsa destroyed

* thats not ready yet

* fuck you tgui linters

* pretty blue sparks!

* 60% charging efficiency
  • Loading branch information
Dejaku51 authored Aug 16, 2024
1 parent a0b56d8 commit 86bb519
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 41 deletions.
16 changes: 15 additions & 1 deletion code/game/objects/effects/effect_system/effects_sparks.dm
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
return INITIALIZE_HINT_LATELOAD

/obj/effect/particle_effect/sparks/LateInitialize()
flick("sparks", src) // replay the animation
flick(icon_state, src) // replay the animation
playsound(src, "sparks", 100, TRUE)
var/turf/T = loc
if(isturf(T))
Expand Down Expand Up @@ -59,3 +59,17 @@

/datum/effect_system/lightning_spread
effect_type = /obj/effect/particle_effect/sparks/electricity

// shield sparks
/obj/effect/particle_effect/sparks/shield
name = "shield sparks"
icon_state = "shieldsparkles"

/obj/effect/particle_effect/sparks/shield/Initialize(mapload)
. = ..()
// every particle has a little different color
var/generator/gen_color = generator("color", LIGHT_COLOR_WHITE, LIGHT_COLOR_ELECTRIC_CYAN)
var/rand_color = gen_color.Rand()
color = rand_color
set_light_color(rand_color)

4 changes: 2 additions & 2 deletions code/modules/power/power.dm
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,8 @@
update_appearance()

// connect the machine to a powernet if a node cable is present on the turf
/obj/machinery/power/proc/connect_to_network()
var/turf/T = src.loc
/obj/machinery/power/proc/connect_to_network(var/turf/turf = loc)
var/turf/T = turf
if(!T || !istype(T))
return FALSE

Expand Down
4 changes: 4 additions & 0 deletions code/modules/power/terminal.dm
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,7 @@
/obj/machinery/power/terminal/wirecutter_act(mob/living/user, obj/item/I)
dismantle(user, I)
return TRUE

/obj/machinery/power/terminal/invisible
name = ""
icon_state = ""
155 changes: 120 additions & 35 deletions code/modules/station_goals/bsa.dm
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ GLOBAL_VAR_INIT(bsa_unlock, FALSE)
/datum/station_goal/bluespace_cannon/check_completion()
if(..())
return TRUE
var/obj/machinery/bsa/full/B = locate()
var/obj/machinery/power/bsa/full/B = locate()
if(B && !B.machine_stat)
return TRUE
return FALSE
Expand Down Expand Up @@ -129,68 +129,141 @@ DEFINE_BUFFER_HANDLER(/obj/machinery/bsa/middle)
return WEST


/obj/machinery/bsa/full
/obj/machinery/power/bsa/full
name = "Bluespace Artillery"
desc = "Long range bluespace artillery."
icon = 'icons/obj/lavaland/cannon.dmi'
icon_state = "cannon_west"
var/base_battery_icon_state = "bsa_west_capacitor"
var/static/mutable_appearance/top_layer
var/ex_power = 3
var/power_used_per_shot = 2000000 //enough to kil standard apc - todo : make this use wires instead and scale explosion power with it
var/ready

var/power_used_per_shot = 5000000
var/obj/item/stock_parts/cell/cell
var/obj/machinery/power/terminal/invisible/terminal
use_power = NO_POWER_USE
idle_power_usage = 50 // when idle
active_power_usage = INFINITY // how much you can charge at once
var/charge_efficiency = 0.6 // 60% of power is stored in the cell

pixel_y = -32
pixel_x = -192
bound_width = 352
bound_x = -192
density = TRUE
appearance_flags = NONE //Removes default TILE_BOUND
resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF

/obj/machinery/bsa/full/wrench_act(mob/living/user, obj/item/I)
var/sound/select_sound = 'sound/machines/bsa/bsa_charge.ogg'
var/select_sound_length = 17 SECONDS

var/sound/fire_sound = 'sound/machines/bsa/bsa_fire.ogg'
var/winding_up = FALSE // if true, sparks will be generated in the bullseye

var/last_charge_quarter = 0



/obj/machinery/power/bsa/full/wrench_act(mob/living/user, obj/item/I)
return FALSE

/obj/machinery/bsa/full/proc/get_front_turf()
/obj/machinery/power/bsa/full/Destroy()
. = ..()
QDEL_NULL(cell)
QDEL_NULL(terminal)

/obj/machinery/power/bsa/full/proc/get_front_turf()
switch(dir)
if(WEST)
return locate(x - 7,y,z)
if(EAST)
return locate(x + 4,y,z)
return get_turf(src)

/obj/machinery/bsa/full/proc/get_back_turf()
/obj/machinery/power/bsa/full/proc/get_back_turf()
switch(dir)
if(WEST)
return locate(x + 4,y,z)
if(EAST)
return locate(x - 6,y,z)
return get_turf(src)

/obj/machinery/bsa/full/proc/get_target_turf()
/obj/machinery/power/bsa/full/proc/get_target_turf()
switch(dir)
if(WEST)
return locate(1,y,z)
if(EAST)
return locate(world.maxx,y,z)
return get_turf(src)

/obj/machinery/bsa/full/Initialize(mapload, cannon_direction = WEST)
/obj/machinery/power/bsa/full/proc/make_terminal(turf/T)
// create a terminal object at the same position as original turf loc
// wires will attach to this
terminal = new /obj/machinery/power/terminal/invisible(T)
terminal.master = src

/obj/machinery/power/bsa/full/Initialize(mapload, cannon_direction = WEST)
. = ..()
cell = new /obj/item/stock_parts/cell(src, 5000000)
cell.charge = 0
top_layer = top_layer || mutable_appearance(icon, layer = ABOVE_MOB_LAYER)
switch(cannon_direction)
if(WEST)
setDir(WEST)
pixel_x = -192
top_layer.icon_state = "top_west"
icon_state = "cannon_west"
if(EAST)
setDir(EAST)
top_layer.icon_state = "top_east"
icon_state = "cannon_east"
add_overlay(top_layer)
reload()
update_icon_state()
make_terminal(get_back_turf())


/obj/machinery/power/bsa/full/update_icon_state()
. = ..()
icon_state = "cannon_[dir2text(dir)]"
base_battery_icon_state = "bsa_[dir2text(dir)]_capacitor"

/obj/machinery/bsa/full/proc/fire(mob/user, turf/bullseye)
reload()
/obj/machinery/power/bsa/full/update_overlays()
. = ..()
cut_overlays()
add_overlay(top_layer)
top_layer.icon_state = "top_[dir2text(dir)]"

var/charge_quarter = FLOOR(cell.percent() / 25, 1)
var/charge_sound = 'sound/machines/apc/PowerSwitch_Off.ogg'
if(charge_quarter >= 1)
add_overlay("[base_battery_icon_state]_25")
if(charge_quarter >= 2)
add_overlay("[base_battery_icon_state]_50")
if(charge_quarter >= 3)
add_overlay("[base_battery_icon_state]_75")
if(charge_quarter >= 4)
add_overlay("[base_battery_icon_state]_100")
charge_sound = 'sound/machines/apc/PowerUp_001.ogg'
if(charge_quarter > last_charge_quarter)
playsound(get_turf(src), charge_sound, 25, 1)


/obj/machinery/power/bsa/full/proc/charge_up(mob/user, turf/bullseye)
if(!cell.use(power_used_per_shot))
return FALSE
var/sound/charge_up = sound(select_sound)
playsound(get_turf(src), charge_up, 50, 1)
var/timerid = addtimer(CALLBACK(src, PROC_REF(fire), user, bullseye), select_sound_length, TIMER_STOPPABLE)
winding_up = TRUE
var/list/turfs = spiral_range_turfs(ex_power * 2, bullseye)
var/base_cooldown = 2 SECONDS
var/cooldown = base_cooldown
while(winding_up)
if(QDELETED(src))
break
new /obj/effect/particle_effect/sparks/shield(pick(turfs))
cooldown = base_cooldown * ((timeleft(timerid)) / select_sound_length)
sleep(cooldown)

/obj/machinery/power/bsa/full/proc/fire(mob/user, turf/bullseye)
winding_up = FALSE
playsound(get_turf(src), fire_sound, 50, 1, world.maxx)
var/turf/point = get_front_turf()
var/turf/target = get_target_turf()
var/atom/movable/blocker
Expand Down Expand Up @@ -222,16 +295,26 @@ DEFINE_BUFFER_HANDLER(/obj/machinery/bsa/middle)
log_game("[key_name(user)] has launched an artillery strike targeting [AREACOORD(bullseye)] but it was blocked by [blocker] at [AREACOORD(target)].")


/obj/machinery/bsa/full/proc/reload()
/obj/machinery/power/bsa/full/proc/reload()
ready = FALSE
use_power(power_used_per_shot)
ui_update()
addtimer(CALLBACK(src,"ready_cannon"),600)

/obj/machinery/bsa/full/proc/ready_cannon()
/obj/machinery/power/bsa/full/proc/ready_cannon()
ready = TRUE
ui_update()

/obj/machinery/power/bsa/full/process(delta_time)
if(cell.percent() >= 100 || terminal.surplus() < 1)
return
terminal.add_load(idle_power_usage)
var/charge = clamp(terminal.surplus() * delta_time, 0, active_power_usage)
terminal.add_load(charge)
cell.give(charge * charge_efficiency)
update_appearance(UPDATE_OVERLAYS)
last_charge_quarter = FLOOR(cell.percent() / 25, 1)
ui_update()

/obj/structure/filler
name = "big machinery part"
density = TRUE
Expand All @@ -254,7 +337,6 @@ DEFINE_BUFFER_HANDLER(/obj/machinery/bsa/middle)
canSmoothWith = null



var/datum/weakref/cannon_ref
var/notice
var/target
Expand All @@ -272,12 +354,14 @@ DEFINE_BUFFER_HANDLER(/obj/machinery/bsa/middle)
//Missing updates for: target GPS name changes

/obj/machinery/computer/bsa_control/ui_data()
var/obj/machinery/bsa/full/cannon = cannon_ref?.resolve()
var/obj/machinery/power/bsa/full/cannon = cannon_ref?.resolve()
var/list/data = list()
data["ready"] = cannon ? cannon.ready : FALSE
data["connected"] = cannon
data["notice"] = notice
data["unlocked"] = GLOB.bsa_unlock
data["charge"] = cannon ? cannon.cell.charge : 0
data["max_charge"] = cannon ? cannon.cell.maxcharge : 0
if(target)
data["target"] = get_target_name()
else
Expand All @@ -303,20 +387,20 @@ DEFINE_BUFFER_HANDLER(/obj/machinery/bsa/middle)
/obj/machinery/computer/bsa_control/proc/calibrate(mob/user)
if(!GLOB.bsa_unlock)
return
var/list/gps_locators = list()
for(var/datum/component/gps/G in GLOB.GPS_list) //nulls on the list somehow
var/list/targets = list()
// Find all active GPS
for(var/datum/component/gps/G in GLOB.GPS_list)
if(G.tracking)
gps_locators[G.gpstag] = G
targets[G.gpstag] = G

var/list/options = gps_locators
if(area_aim)
options += GLOB.teleportlocs
var/victim = tgui_input_list(user, "Select target", "Artillery Targeting", options)
targets += GLOB.teleportlocs
var/victim = tgui_input_list(user, "Select target", "Artillery Targeting", targets)
if(isnull(victim))
return
if(isnull(options[victim]))
if(isnull(targets[victim]))
return
target = options[victim]
target = targets[victim]
var/datum/component/gps/log_target = target
log_game("[key_name(user)] has aimed the bluespace artillery strike (BSA) at [get_area_name(log_target.parent)].")

Expand All @@ -335,19 +419,20 @@ DEFINE_BUFFER_HANDLER(/obj/machinery/bsa/middle)
var/datum/component/gps/G = target
return get_turf(G.parent)


/obj/machinery/computer/bsa_control/proc/fire(mob/user)
var/obj/machinery/bsa/full/cannon = cannon_ref?.resolve()
var/obj/machinery/power/bsa/full/cannon = cannon_ref?.resolve()
if(!cannon)
notice = "No Cannon Exists!"
return
if(cannon.machine_stat)
notice = "Cannon unpowered!"
if(cannon.cell.percent() < 100)
notice = "Cannon doesn't have enough charge!"
return
notice = null
cannon.fire(user, get_impact_turf())
cannon.charge_up(user, get_impact_turf())

/obj/machinery/computer/bsa_control/proc/deploy(force=FALSE)
var/obj/machinery/bsa/full/prebuilt = locate() in range(7) //In case of adminspawn
var/obj/machinery/power/bsa/full/prebuilt = locate() in range(7) //In case of adminspawn
if(prebuilt)
return prebuilt

Expand All @@ -362,7 +447,7 @@ DEFINE_BUFFER_HANDLER(/obj/machinery/bsa/middle)
var/datum/effect_system/smoke_spread/s = new
s.set_up(4,get_turf(centerpiece))
s.start()
var/obj/machinery/bsa/full/cannon = new(get_turf(centerpiece),centerpiece.get_cannon_direction())
var/obj/machinery/power/bsa/full/cannon = new(get_turf(centerpiece),centerpiece.get_cannon_direction())
QDEL_NULL(centerpiece.front_ref)
QDEL_NULL(centerpiece.back_ref)
qdel(centerpiece)
Expand Down
Binary file modified icons/obj/lavaland/cannon.dmi
Binary file not shown.
Binary file added sound/machines/bsa/bsa_charge.ogg
Binary file not shown.
Binary file added sound/machines/bsa/bsa_fire.ogg
Binary file not shown.
16 changes: 13 additions & 3 deletions tgui/packages/tgui/interfaces/BluespaceArtillery.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
import { useBackend } from '../backend';
import { Box, Button, LabeledList, NoticeBox, Section } from '../components';
import { Box, Button, LabeledList, NoticeBox, ProgressBar, Section } from '../components';
import { Window } from '../layouts';

export const BluespaceArtillery = (props, context) => {
const { act, data } = useBackend(context);
const { notice, connected, unlocked, target } = data;
const { notice, connected, unlocked, target, charge, max_charge } = data;
return (
<Window width={400} height={220}>
<Window width={400} height={280}>
<Window.Content>
{!!notice && <NoticeBox>{notice}</NoticeBox>}
{connected ? (
<>
<Section title="Charge">
<ProgressBar
ranges={{
good: [1, Infinity],
average: [0.2, 0.99],
bad: [-Infinity, 0.2],
}}
value={charge / max_charge}
/>
</Section>
<Section
title="Target"
buttons={<Button icon="crosshairs" disabled={!unlocked} onClick={() => act('recalibrate')} />}>
Expand Down

0 comments on commit 86bb519

Please sign in to comment.