Files
Bubberstation/code/modules/research/ordnance/doppler_array.dm
LemonInTheDark ef714c1c34 Overlay Lighting Color/Intensity Pass (#81425)
## About The Pull Request

I was looking at screenshots of the game and realized we had a lot of
light sources that were really... flat.

Medium intensity, not colored at all, cringe.

So I went over all the uses of overlay styled lighting (since I've done
matrix lighting already) and gave them more unique features. Colors that
match the sprite they're used with, intensity to produce vibes, that
sort of thing.

It's kinda impossible to go one by one cause there's a LOT.

I may have gone a bit overboard with a few, I'm messing around with some
things like giving bots colors based off their department, etc. We'll
see how this all turns out.

Oh also I tweaked how the cone of overlay lighting is drawn. It seemed a
bit too present to me so I dropped the alpha down from like 200 to 120
at max (so it's roughly half of the mask's alpha so it's less
overwhelming

## Why It's Good For The Game

Lighting should be impactful, subtle and colorful

<details>
<summary>
Old Lights
</summary>


![dreamseeker_QJ5bFZxd63](https://github.com/tgstation/tgstation/assets/58055496/8ae74a95-32cb-473f-830a-ab4e1073a581)

![dreamseeker_DPVgI8wOoN](https://github.com/tgstation/tgstation/assets/58055496/149095af-a08a-4038-bf18-9e3401327452)

![dreamseeker_pyEmTAb37x](https://github.com/tgstation/tgstation/assets/58055496/6dbb6cf8-2ed7-4bc0-9d19-c64849088a33)

![dreamseeker_aDfvnea6YD](https://github.com/tgstation/tgstation/assets/58055496/4ed983e1-6be3-4513-ba3b-cecde08ccd38)

![dreamseeker_RnkQSwmxmc](https://github.com/tgstation/tgstation/assets/58055496/63e0210e-e1b1-42f0-be64-53d67c43f689)

![dreamseeker_G8NSC3lzAk](https://github.com/tgstation/tgstation/assets/58055496/93001925-904d-4061-8874-1d17bb225a90)

![dreamseeker_yASfxtbHDR](https://github.com/tgstation/tgstation/assets/58055496/ce0ae9ad-9067-44e0-9491-3ef331bbbb84)

![dreamseeker_4ecBbG5urI](https://github.com/tgstation/tgstation/assets/58055496/ce82f471-15c7-40ce-bc08-be4f5dc8a3b7)

![dreamseeker_udYlv8uAce](https://github.com/tgstation/tgstation/assets/58055496/c516a278-852b-44b8-ba7c-1203cea3f845)

![dreamseeker_bc2120Fnmr](https://github.com/tgstation/tgstation/assets/58055496/87a1429a-2329-4dd5-8c7b-ff44f54a08bb)

</details>

<details>
<summary>
New Lights
</summary>


![dreamseeker_0H11TyhGgx](https://github.com/tgstation/tgstation/assets/58055496/75b68a25-055e-488c-af82-b062dbe7413e)

![dreamseeker_2B9AENHsfl](https://github.com/tgstation/tgstation/assets/58055496/b52d441c-6ed3-495b-9ebd-9b0c9f924f30)

![dreamseeker_3vOVRRMTSP](https://github.com/tgstation/tgstation/assets/58055496/b265578f-34cc-4a0a-80ea-3237fb83df33)

![dreamseeker_5bTLup65rx](https://github.com/tgstation/tgstation/assets/58055496/6fcd3dc0-5927-458a-9f77-5582ad57a954)

![dreamseeker_iZzxZv4nfW](https://github.com/tgstation/tgstation/assets/58055496/67c3af13-2305-4130-936b-19ded08ccc4e)

![dreamseeker_Lhe9TSA0Av](https://github.com/tgstation/tgstation/assets/58055496/a5310e58-0ff1-45ac-bb81-b4a0212eb0ce)

![dreamseeker_ngQJUv0tV4](https://github.com/tgstation/tgstation/assets/58055496/c3d7423a-ab32-4401-9ffa-c4c3b7811334)

![dreamseeker_PL0z6sU7by](https://github.com/tgstation/tgstation/assets/58055496/2947d828-3aee-48c2-903f-2bf0db9077d2)

![dreamseeker_xineFZDzPA](https://github.com/tgstation/tgstation/assets/58055496/095ff8b0-51cf-4f7c-a2ee-752d9d7e87bd)

![dreamseeker_zpXxbZZakS](https://github.com/tgstation/tgstation/assets/58055496/c4200d35-a2fa-4c3f-8e88-1fd87f44cd46)

</details>

## Changelog
🆑
add: Tweaked the saturation, color and intensity of a bunch of lights
/🆑
2024-03-09 23:57:19 +00:00

315 lines
12 KiB
Plaintext

/obj/machinery/doppler_array
name = "tachyon-doppler array"
desc = "A highly precise directional sensor array which measures the release of quants from decaying tachyons. The doppler shifting of the mirror-image formed by these quants can reveal the size, location and temporal affects of energetic disturbances within a large radius ahead of the array.\n"
circuit = /obj/item/circuitboard/machine/doppler_array
icon = 'icons/obj/machines/research.dmi'
icon_state = "tdoppler"
base_icon_state = "tdoppler"
density = TRUE
verb_say = "states coldly"
var/cooldown = 10
var/next_announce = 0
var/max_dist = 150
/// Number which will be part of the name of the next record, increased by one for each already created record
var/record_number = 1
/// List of all explosion records in the form of /datum/data/tachyon_record
var/list/records = list()
/// Reference to a disk we are going to print to.
var/obj/item/computer_disk/inserted_disk
// Lighting system to better communicate the directions.
light_system = OVERLAY_LIGHT_DIRECTIONAL
light_range = 4
light_power = 1.5
light_color = COLOR_RED
/obj/machinery/doppler_array/Initialize(mapload)
. = ..()
RegisterSignal(SSdcs, COMSIG_GLOB_EXPLOSION, PROC_REF(sense_explosion))
RegisterSignal(src, COMSIG_MACHINERY_POWER_LOST, PROC_REF(update_doppler_light))
RegisterSignal(src, COMSIG_MACHINERY_POWER_RESTORED, PROC_REF(update_doppler_light))
update_doppler_light()
// Rotation determines the detectable direction.
AddComponent(/datum/component/simple_rotation)
/datum/data/tachyon_record
name = "Log Recording"
var/timestamp
var/coordinates = ""
var/displacement = 0
var/factual_radius = list()
var/theory_radius = list()
/// Indexed to length 3 if filled properly. Should be an empty list otherwise.
var/reaction_results = list()
var/explosion_identifier
/obj/machinery/doppler_array/examine(mob/user)
. = ..()
. += span_notice("It is currently facing [dir2text(dir)]")
/obj/machinery/doppler_array/attackby(obj/item/item, mob/user, params)
if(istype(item, /obj/item/computer_disk))
var/obj/item/computer_disk/disk = item
eject_disk(user)
if(user.transferItemToLoc(disk, src))
inserted_disk = disk
return
else
balloon_alert(user, "it's stuck to your hand!")
return ..()
return ..()
/obj/machinery/doppler_array/wrench_act(mob/living/user, obj/item/tool)
default_unfasten_wrench(user, tool)
return ITEM_INTERACT_SUCCESS
/obj/machinery/doppler_array/screwdriver_act(mob/living/user, obj/item/tool)
if(!default_deconstruction_screwdriver(user, "[base_icon_state]", "[base_icon_state]", tool))
return FALSE
power_change()
update_appearance()
return TRUE
/obj/machinery/doppler_array/crowbar_act(mob/living/user, obj/item/tool)
if(!default_deconstruction_crowbar(tool))
return FALSE
return TRUE
/// Printing of a record into a disk.
/obj/machinery/doppler_array/proc/print(mob/user, datum/data/tachyon_record/record)
if(!record || !inserted_disk)
return
var/datum/computer_file/data/ordnance/explosive/record_data = new
record_data.filename = "Doppler Array " + record.name //Doppler Array Log Recording #x
record_data.explosion_record = record
record_data.possible_experiments = apply_experiments(record)
if(inserted_disk.add_file(record_data))
playsound(src, 'sound/machines/ping.ogg', 25)
else
playsound(src, 'sound/machines/terminal_error.ogg', 25)
/**
* Checks a specified tachyon record for fitting reactions, then returns a list with
* the experiment typepath as key and score as value.
* The score is the same for all explosive experiments (light radius).
*/
/obj/machinery/doppler_array/proc/apply_experiments(datum/data/tachyon_record/record)
var/list/passed_experiments = list()
var/list/record_reactions = record.reaction_results
var/list/radius_used = length(record.theory_radius) ? record.theory_radius : record.factual_radius
var/explosion_score = radius_used["shockwave_radius"]
if(!explosion_score) // Dont even bother.
return passed_experiments
/// Early return for explosions without proper reaction_results. We will append experiments that are always fair game.
if(!record_reactions.len)
for (var/datum/experiment/ordnance/explosive/experiment in SSresearch.ordnance_experiments)
if(experiment.allow_any_source)
passed_experiments += list(experiment.type = explosion_score)
return passed_experiments
for (var/datum/experiment/ordnance/explosive/experiment in SSresearch.ordnance_experiments)
var/list/experiment_reactions = experiment.required_reactions
/// The reactions in record.reaction_results that corresponds to the required_reactions list.
var/list/fitting_reactions = list()
/// The reactions in required_reactions list that are missing in record.reaction_results.
var/list/missing_reactions = list()
/// The reactions in record.reaction_results that are not present in required_reactions list.
var/list/extra_reactions = list()
for(var/reaction in experiment_reactions)
if(reaction in record_reactions[TANK_RESULTS_REACTION])
fitting_reactions += reaction
else
missing_reactions += reaction
for(var/reaction in record_reactions[TANK_RESULTS_REACTION])
if(!(reaction in fitting_reactions))
extra_reactions += reaction
// Check for extra reactions.
if(experiment.sanitized_reactions && extra_reactions.len)
continue
// Check for misc properties
if(experiment.sanitized_misc && length(record_reactions[TANK_RESULTS_MISC]))
continue
// Check for missing reactions for those who require all.
if(experiment.require_all && missing_reactions.len)
continue
// For those who only need one, check if there is actually one.
if(!experiment.require_all && experiment_reactions.len)
if(!fitting_reactions.len)
continue
// Suceeded all check, append to the returned list.
passed_experiments += list(experiment.type = explosion_score)
return passed_experiments
/// Sensing, recording, and broadcasting of explosion
/obj/machinery/doppler_array/proc/sense_explosion(datum/source, turf/epicenter, devastation_range, heavy_impact_range, light_impact_range,
took, orig_dev_range, orig_heavy_range, orig_light_range, explosion_cause, explosion_index)
SIGNAL_HANDLER
var/list/fetched_reaction_results = list()
if(istype(explosion_cause, /obj/item/tank))
var/obj/item/tank/exploding_tank = explosion_cause
fetched_reaction_results = exploding_tank.explosion_information()
if(machine_stat & NOPOWER)
return FALSE
var/turf/zone = get_turf(src)
if(!is_valid_z_level(zone, epicenter))
return FALSE
if(next_announce > world.time)
return FALSE
next_announce = world.time + cooldown
if((get_dist(epicenter, zone) > max_dist) || !(get_dir(zone, epicenter) & dir))
return FALSE
var/datum/data/tachyon_record/new_record = new /datum/data/tachyon_record()
new_record.name = "Log Recording #[record_number]"
new_record.timestamp = station_time_timestamp()
new_record.coordinates = "[epicenter.x], [epicenter.y]"
new_record.displacement = took
new_record.factual_radius["epicenter_radius"] = devastation_range
new_record.factual_radius["outer_radius"] = heavy_impact_range
new_record.factual_radius["shockwave_radius"] = light_impact_range
new_record.reaction_results = fetched_reaction_results
new_record.explosion_identifier = explosion_index
var/list/messages = list("Explosive disturbance detected.",
"Epicenter at: grid ([epicenter.x], [epicenter.y]). Temporal displacement of tachyons: [took] seconds.",
"Factual: Epicenter radius: [devastation_range]. Outer radius: [heavy_impact_range]. Shockwave radius: [light_impact_range].",
)
// If the bomb was capped, say its theoretical size.
if(devastation_range < orig_dev_range || heavy_impact_range < orig_heavy_range || light_impact_range < orig_light_range)
messages += "Theoretical: Epicenter radius: [orig_dev_range]. Outer radius: [orig_heavy_range]. Shockwave radius: [orig_light_range]."
new_record.theory_radius["epicenter_radius"] = orig_dev_range
new_record.theory_radius["outer_radius"] = orig_heavy_range
new_record.theory_radius["shockwave_radius"] = orig_light_range
for(var/message in messages)
say(message)
record_number++
records += new_record
return TRUE
/obj/machinery/doppler_array/proc/eject_disk(mob/user)
if(!inserted_disk)
return FALSE
if(user)
user.put_in_hands(inserted_disk)
else
inserted_disk.forceMove(drop_location())
playsound(src, 'sound/machines/card_slide.ogg', 50)
return TRUE
/// We rely on exited to clear references.
/obj/machinery/doppler_array/Exited(atom/movable/gone, direction)
if(gone == inserted_disk)
inserted_disk = null
return ..()
/obj/machinery/doppler_array/powered()
if(panel_open)
return FALSE
return ..()
/obj/machinery/doppler_array/update_overlays()
. = ..()
if(panel_open)
. += mutable_appearance(icon, "[base_icon_state]_open")
else
. += mutable_appearance(icon,"[base_icon_state]_cable")
if(machine_stat & BROKEN) // Probably meant to be used on an indestructible doppler, but this is not implemented.
. += mutable_appearance(icon, "[base_icon_state]_screen-broken")
else if (machine_stat & NOPOWER)
. += mutable_appearance(icon, "[base_icon_state]_screen-off")
/obj/machinery/doppler_array/on_deconstruction(disassembled)
eject_disk()
. = ..()
/obj/machinery/doppler_array/Destroy()
inserted_disk = null
QDEL_NULL(records) //We only want the list nuked, not the contents.
. = ..()
/obj/machinery/doppler_array/proc/update_doppler_light()
SIGNAL_HANDLER
set_light_on(!(machine_stat & NOPOWER))
/obj/machinery/doppler_array/AltClick(mob/user)
return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation
/obj/machinery/doppler_array/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "DopplerArray", name)
ui.open()
/obj/machinery/doppler_array/ui_data(mob/user)
var/list/data = list()
data["records"] = list()
data["disk"] = inserted_disk?.name
data["storage"] = "[inserted_disk?.used_capacity] / [inserted_disk?.max_capacity] GQ"
for(var/datum/data/tachyon_record/singular_record in records)
var/list/record_data = list(
"name" = singular_record.name,
"timestamp" = singular_record.timestamp,
"coordinates" = singular_record.coordinates,
"displacement" = singular_record.displacement,
"factual_epicenter_radius" = singular_record.factual_radius["epicenter_radius"],
"factual_outer_radius" = singular_record.factual_radius["outer_radius"],
"factual_shockwave_radius" = singular_record.factual_radius["shockwave_radius"],
"theory_epicenter_radius" = singular_record.theory_radius["epicenter_radius"],
"theory_outer_radius" = singular_record.theory_radius["outer_radius"],
"theory_shockwave_radius" = singular_record.theory_radius["shockwave_radius"],
"reaction_results" = list(),
"ref" = REF(singular_record)
)
var/list/reaction_data = singular_record.reaction_results
// Make sure the list is indexed first.
if(reaction_data.len)
for (var/path in reaction_data[TANK_RESULTS_REACTION])
var/datum/gas_reaction/reaction_path = path
record_data["reaction_results"] += initial(reaction_path.name)
if(TANK_MERGE_OVERPRESSURE in reaction_data[TANK_RESULTS_MISC])
record_data["reaction_results"] += "Tank overpressurized before reaction"
data["records"] += list(record_data)
return data
/obj/machinery/doppler_array/ui_act(action, list/params)
. = ..()
if(.)
return
switch(action)
if("delete_record")
var/datum/data/tachyon_record/record = locate(params["ref"]) in records
if(!records || !(record in records))
return
records -= record
return TRUE
if("save_record")
var/datum/data/tachyon_record/record = locate(params["ref"]) in records
if(!records || !(record in records))
return
print(usr, record)
return TRUE
if("eject_disk")
eject_disk(usr)