mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-30 16:47:13 +01:00
480 lines
17 KiB
Plaintext
480 lines
17 KiB
Plaintext
#define BOOK_OPEN_RANGE 2
|
|
|
|
/obj/structure/destructible/clockwork/gear_base/technologists_lectern
|
|
name = "technologist's lectern"
|
|
desc = "A small pedestal with a glowing book floating over it.."
|
|
clockwork_desc = "A small pedestal, glowing with a divine energy. Used to research new abilities and objects."
|
|
base_icon_state = "lectern"
|
|
icon_state = "lectern"
|
|
anchored = TRUE
|
|
break_message = "<span class='warning'>The lectern collapses.</span>"
|
|
can_unwrench = FALSE
|
|
max_integrity = 400
|
|
/// If the last process() found a clock cultist in range
|
|
var/mobs_in_range = FALSE
|
|
/// Ref to the effect of the lectern's book
|
|
var/obj/effect/lectern_light/hologram
|
|
/// Ref to the currently selected research
|
|
var/datum/clockwork_research/selected_research
|
|
/// If there is a research ritual already occurring
|
|
var/static/researching = FALSE
|
|
/// If we are the lectern actively doing the researching
|
|
var/primary_researcher = FALSE
|
|
/// The highest tier researched
|
|
var/static/highest_tier_researched = 0
|
|
/// Ref to the research sigil this created
|
|
var/obj/structure/destructible/clockwork/sigil/research/research_sigil
|
|
/// ID of the research timer
|
|
var/research_timer_id
|
|
|
|
|
|
|
|
// Base procs
|
|
/obj/structure/destructible/clockwork/gear_base/technologists_lectern/Initialize(mapload)
|
|
. = ..()
|
|
if(!length(GLOB.clockwork_research))
|
|
GLOB.clockwork_research = setup_clockwork_research()
|
|
|
|
hologram = new(get_turf(src))
|
|
|
|
START_PROCESSING(SSobj, src)
|
|
|
|
selected_research = locate(/datum/clockwork_research/start) in GLOB.clockwork_research
|
|
|
|
set_light(1.5)
|
|
set_light_color(COLOR_THEME_CLOCKWORK)
|
|
|
|
|
|
/obj/structure/destructible/clockwork/gear_base/technologists_lectern/Destroy()
|
|
STOP_PROCESSING(SSobj, src)
|
|
selected_research = null
|
|
|
|
if(research_sigil)
|
|
QDEL_NULL(research_sigil)
|
|
|
|
if(hologram)
|
|
QDEL_NULL(hologram)
|
|
|
|
return ..()
|
|
|
|
|
|
/obj/structure/destructible/clockwork/gear_base/technologists_lectern/atom_deconstruct(disassembled)
|
|
if(primary_researcher)
|
|
deltimer(research_timer_id)
|
|
researching = FALSE
|
|
primary_researcher = FALSE
|
|
log_game("A research ritual of [selected_research] was cancelled by deconstruction of [src].")
|
|
send_clock_message(null, "A research ritual has been disrupted in [get_area(src)]! All research data has been lost.", msg_ghosts = FALSE)
|
|
notify_ghosts("A research ritual was disrupted in [get_area(src)]",
|
|
source = get_turf(src),
|
|
notify_flags = NOTIFY_CATEGORY_NOFLASH,
|
|
header = "Research ritual cancelled",
|
|
)
|
|
|
|
return ..()
|
|
|
|
|
|
/obj/structure/destructible/clockwork/gear_base/technologists_lectern/examine(mob/user)
|
|
. = ..()
|
|
if(researching && IS_CLOCK(user))
|
|
. += span_brass("The researching of [selected_research.name] will take another [DisplayTimeText(timeleft(research_timer_id))].")
|
|
|
|
|
|
/obj/structure/destructible/clockwork/gear_base/technologists_lectern/process(seconds_per_tick)
|
|
if(researching)
|
|
if(SPT_PROB(5, seconds_per_tick))
|
|
new /obj/effect/temp_visual/steam_release(get_turf(src))
|
|
|
|
if(SPT_PROB(2, seconds_per_tick))
|
|
var/text = pick("[src]'s book flips a page as it hums away.", "[src] makes a creaking noise.", "[src] whirrs lightly.", "A faint clank is heard from inside [src].")
|
|
visible_message(span_brass(text))
|
|
|
|
var/mob_nearby = FALSE
|
|
for(var/mob/living/person in viewers(BOOK_OPEN_RANGE, get_turf(src)))
|
|
if(IS_CLOCK(person))
|
|
mob_nearby = TRUE
|
|
break
|
|
|
|
if(mob_nearby && !mobs_in_range)
|
|
hologram.open()
|
|
mobs_in_range = TRUE
|
|
|
|
else if(!mob_nearby && mobs_in_range)
|
|
hologram.close()
|
|
mobs_in_range = FALSE
|
|
|
|
|
|
/obj/structure/destructible/clockwork/gear_base/technologists_lectern/attack_hand(mob/living/user, list/modifiers)
|
|
if(!IS_CLOCK(user))
|
|
return
|
|
|
|
if(!anchored)
|
|
balloon_alert(user, "not fastened!")
|
|
return
|
|
|
|
ui_interact(user)
|
|
|
|
|
|
// UI code
|
|
/obj/structure/destructible/clockwork/gear_base/technologists_lectern/ui_interact(mob/user, datum/tgui/ui)
|
|
ui = SStgui.try_update_ui(user, src, ui)
|
|
if (!ui)
|
|
ui = new(user, src, "ClockworkResearch")
|
|
ui.open()
|
|
|
|
/obj/structure/destructible/clockwork/gear_base/technologists_lectern/ui_assets(mob/user)
|
|
return list(
|
|
get_asset_datum(/datum/asset/spritesheet_batched/research_designs),
|
|
)
|
|
|
|
/obj/structure/destructible/clockwork/gear_base/technologists_lectern/ui_data(mob/user)
|
|
var/list/data = list()
|
|
|
|
data["focused_research"] = list(
|
|
"name" = selected_research.name,
|
|
"desc" = selected_research.desc,
|
|
"lore" = selected_research.lore,
|
|
"researched" = selected_research.researched,
|
|
"starting" = selected_research.starting,
|
|
"can_research" = can_research(selected_research.tier),
|
|
"research_location" = initial(selected_research.selected_area.name),
|
|
"research_designs" = assemble_research_designs(selected_research),
|
|
"research_scriptures" = assemble_research_scriptures(selected_research),
|
|
"type" = selected_research.type,
|
|
)
|
|
|
|
data["in_area"] = (istype(get_area(src), selected_research.selected_area))
|
|
|
|
return data
|
|
|
|
/obj/structure/destructible/clockwork/gear_base/technologists_lectern/ui_static_data(mob/user)
|
|
var/list/data = list()
|
|
|
|
data["research_tiers"] = list()
|
|
data["starting_research"] = null
|
|
|
|
var/highest_tier = 0
|
|
for(var/datum/clockwork_research/research as anything in GLOB.clockwork_research)
|
|
if(research.tier > highest_tier)
|
|
highest_tier = research.tier
|
|
|
|
if(research.starting)
|
|
data["starting_research"] = list(
|
|
"name" = research.name,
|
|
"desc" = research.desc,
|
|
"lore" = research.lore,
|
|
"researched" = research.researched,
|
|
"starting" = research.starting,
|
|
"can_research" = TRUE,
|
|
"research_location" = initial(research.selected_area.name),
|
|
"research_designs" = assemble_research_designs(research),
|
|
"research_scriptures" = assemble_research_scriptures(research),
|
|
"type" = research.type,
|
|
)
|
|
|
|
for(var/i in 1 to highest_tier)
|
|
data["research_tiers"] += list(list())
|
|
|
|
for(var/datum/clockwork_research/research as anything in GLOB.clockwork_research)
|
|
if(research.starting)
|
|
continue
|
|
|
|
data["research_tiers"][research.tier] += list(list(
|
|
"name" = research.name,
|
|
"desc" = research.desc,
|
|
"lore" = research.lore,
|
|
"researched" = research.researched,
|
|
"starting" = research.starting,
|
|
"can_research" = can_research(research.tier),
|
|
"research_location" = initial(research.selected_area.name),
|
|
"research_designs" = assemble_research_designs(research),
|
|
"research_scriptures" = assemble_research_scriptures(research),
|
|
"type" = research.type,
|
|
))
|
|
|
|
|
|
return data
|
|
|
|
|
|
/obj/structure/destructible/clockwork/gear_base/technologists_lectern/ui_act(action, params)
|
|
. = ..()
|
|
if (.)
|
|
return
|
|
|
|
switch(action)
|
|
if("select_research")
|
|
var/path = text2path(params["path"])
|
|
|
|
if(!ispath(path, /datum/clockwork_research))
|
|
return FALSE
|
|
|
|
var/datum/clockwork_research/research_datum = locate(path) in GLOB.clockwork_research
|
|
if(!research_datum || !can_research(research_datum.tier))
|
|
return FALSE
|
|
|
|
selected_research = research_datum
|
|
return TRUE
|
|
|
|
if("start_research")
|
|
if(!selected_research || !can_research(selected_research.tier))
|
|
return FALSE
|
|
|
|
if(!selected_research.check_is_place_good(src))
|
|
return FALSE
|
|
|
|
check_room(usr)
|
|
|
|
return TRUE
|
|
|
|
/// Provided a research datum, returns a list of icon states from tinker cache designs for use in the UI
|
|
/obj/structure/destructible/clockwork/gear_base/technologists_lectern/proc/assemble_research_designs(datum/clockwork_research/selected_research)
|
|
RETURN_TYPE(/list)
|
|
|
|
. = list()
|
|
|
|
for(var/datum/tinker_cache_item/type as anything in selected_research.unlocked_recipes)
|
|
var/atom/path = initial(type.item_path)
|
|
|
|
. += list(list(
|
|
"name" = initial(path.name),
|
|
"icon" = sanitize_css_class_name(initial(type.research_icon_state) || initial(path.icon_state)),
|
|
"icon2" = sanitize_css_class_name("[initial(type.research_icon) || initial(path.icon)][initial(type.research_icon_state) || initial(path.icon_state)]"),
|
|
))
|
|
|
|
return .
|
|
|
|
/// Provided a research datum, returns a list of icon states from scriptures for use in the UI
|
|
/obj/structure/destructible/clockwork/gear_base/technologists_lectern/proc/assemble_research_scriptures(datum/clockwork_research/selected_research)
|
|
RETURN_TYPE(/list)
|
|
|
|
. = list()
|
|
|
|
for(var/datum/scripture/type as anything in selected_research.unlocked_scriptures)
|
|
|
|
. += list(list(
|
|
"name" = initial(type.name),
|
|
"icon" = sanitize_css_class_name(initial(type.button_icon_state)),
|
|
"icon2" = sanitize_css_class_name("modular_skyrat/modules/clock_cult/icons/actions_clock.dmi[initial(type.button_icon_state)]"),
|
|
))
|
|
|
|
return .
|
|
|
|
|
|
/// Helper to see if any given tier is researchable
|
|
/obj/structure/destructible/clockwork/gear_base/technologists_lectern/proc/can_research(tier)
|
|
return (tier <= (highest_tier_researched + 1))
|
|
|
|
|
|
// Custom procs
|
|
|
|
|
|
/// Check to see if there's enough room to ritual-ize, and invoke the ritual if so
|
|
/obj/structure/destructible/clockwork/gear_base/technologists_lectern/proc/check_room(mob/owner)
|
|
var/turf/target_turf = get_turf(src)
|
|
for(var/turf/nearby_turf as anything in RANGE_TURFS(1, target_turf))
|
|
if(istype(nearby_turf, /turf/open/floor))
|
|
continue
|
|
|
|
owner.balloon_alert(owner, "not enough room!")
|
|
return
|
|
|
|
if(researching)
|
|
owner.balloon_alert(owner, "already researching!")
|
|
return
|
|
|
|
INVOKE_ASYNC(src, PROC_REF(begin_research), owner, target_turf)
|
|
|
|
|
|
/// Begin the research after a delay, announcing it and starting everything
|
|
/obj/structure/destructible/clockwork/gear_base/technologists_lectern/proc/begin_research(mob/owner, turf/target_turf)
|
|
if(!do_after(owner, 10 SECONDS, src))
|
|
return FALSE
|
|
|
|
researching = TRUE
|
|
primary_researcher = TRUE
|
|
|
|
AddComponent(/datum/component/brass_spreader, range = 6)
|
|
|
|
playsound(target_turf, 'sound/machines/clockcult/ark_deathrattle.ogg', 80, FALSE, pressure_affected = FALSE)
|
|
research_sigil = new(target_turf)
|
|
send_clock_message(null, "A research ritual has begun in [get_area(src)], ensure nobody stops it until it is completed in [DisplayTimeText(selected_research.time_to_research)]!", msg_ghosts = FALSE)
|
|
notify_ghosts("[owner] has begun a research ritual in [get_area(src)]",
|
|
source = src,
|
|
notify_flags = NOTIFY_CATEGORY_NOFLASH,
|
|
header = "Research ritual"
|
|
)
|
|
log_game("[owner] began a research ritual of [selected_research.name] in [get_area(src)].")
|
|
|
|
research_timer_id = addtimer(CALLBACK(src, PROC_REF(finish_research), owner), selected_research.time_to_research, TIMER_STOPPABLE)
|
|
|
|
sleep(10 SECONDS)
|
|
|
|
send_message("You hear the echoing of cogs ")
|
|
|
|
addtimer(CALLBACK(src, PROC_REF(send_message), "The echoing of cogs returns, even louder, "), (selected_research.time_to_research / 2), 9 SECONDS)
|
|
|
|
/// Send a message to everyone on the Z level with directions to the lectern
|
|
/obj/structure/destructible/clockwork/gear_base/technologists_lectern/proc/send_message(initial_message = "You hear the echoing of cogs ", volume = 70)
|
|
for(var/mob/living/living_mob as anything in GLOB.mob_living_list)
|
|
if((living_mob.z != z) || IS_CLOCK(living_mob) || !HAS_TRAIT(living_mob, TRAIT_DEAF))
|
|
continue
|
|
|
|
|
|
var/turf/mob_turf = get_turf(living_mob)
|
|
var/dist = get_dist(mob_turf, src)
|
|
var/dir = get_dir(mob_turf, src)
|
|
var/message = initial_message
|
|
switch(dist)
|
|
if (0 to 15)
|
|
message += "very nearby, to your [dir2text(dir)]!"
|
|
if (16 to 31)
|
|
message += "nearby, to your [dir2text(dir)]!"
|
|
if (32 to 127)
|
|
message += "far away, to your [dir2text(dir)]!"
|
|
else
|
|
message += "very far, to your [dir2text(dir)]!"
|
|
|
|
living_mob.playsound_local(get_turf(src), 'modular_skyrat/modules/clock_cult/sound/machinery/research_notice.ogg', volume, FALSE, pressure_affected = FALSE)
|
|
to_chat(living_mob, span_brass(message))
|
|
|
|
|
|
/// Called when the research finishes, cleaning up everything and triggering the appropriate effects
|
|
/obj/structure/destructible/clockwork/gear_base/technologists_lectern/proc/finish_research(mob/owner)
|
|
if(QDELETED(src) || QDELETED(research_sigil))
|
|
return
|
|
|
|
send_clock_message(null, "The research ritual in [get_area(src)] has completed, rejoice!", msg_ghosts = FALSE)
|
|
notify_ghosts("A research ritual in [get_area(src)] has been completed",
|
|
source = src,
|
|
notify_flags = NOTIFY_CATEGORY_NOFLASH,
|
|
header = "Research ritual completed",
|
|
)
|
|
log_game("Finished a research ritual of [selected_research.name] in [get_area(src)].")
|
|
|
|
researching = FALSE
|
|
primary_researcher = FALSE
|
|
|
|
var/datum/component/spreader = GetComponent(/datum/component/brass_spreader)
|
|
if(spreader)
|
|
qdel(spreader)
|
|
|
|
selected_research.on_research()
|
|
|
|
if(selected_research.tier > highest_tier_researched)
|
|
highest_tier_researched = selected_research.tier
|
|
|
|
selected_research = locate(/datum/clockwork_research/start) in GLOB.clockwork_research
|
|
|
|
|
|
research_sigil.finish_research()
|
|
|
|
priority_announce("An outburst of anomalous energy has been detected at [get_area(src)]. Please ensure the safety of any nearby crew.")
|
|
|
|
addtimer(CALLBACK(src, PROC_REF(side_effect)), 10 SECONDS)
|
|
|
|
|
|
/// Called after research completes, making one of a few bad things happen to the station
|
|
/obj/structure/destructible/clockwork/gear_base/technologists_lectern/proc/side_effect(force_rand)
|
|
var/side_effect_num = force_rand || rand(1, 40)
|
|
|
|
switch(side_effect_num)
|
|
if(1 to 10) // Cult-ify everything nearby
|
|
playsound(src, 'modular_skyrat/modules/clock_cult/sound/machinery/ark_scream.ogg', 100, FALSE, pressure_affected = FALSE)
|
|
for(var/atom/nearby_atom in range(8))
|
|
if(istype(nearby_atom, /turf/open/floor))
|
|
var/turf/floor_tile = nearby_atom
|
|
floor_tile.ChangeTurf(/turf/open/floor/bronze)
|
|
new /obj/effect/temp_visual/ratvar/floor(floor_tile)
|
|
new /obj/effect/temp_visual/ratvar/beam(floor_tile)
|
|
|
|
else if(istype(nearby_atom, /turf/closed/wall))
|
|
var/turf/wall = nearby_atom
|
|
wall.ChangeTurf(/turf/closed/wall/mineral/bronze)
|
|
new /obj/effect/temp_visual/ratvar/wall(wall)
|
|
new /obj/effect/temp_visual/ratvar/beam(wall)
|
|
|
|
else if(istype(nearby_atom, /obj/structure/window))
|
|
new /obj/structure/window/bronze/fulltile(nearby_atom.loc)
|
|
new /obj/effect/temp_visual/ratvar/window(nearby_atom.loc)
|
|
new /obj/effect/temp_visual/ratvar/beam(nearby_atom.loc)
|
|
qdel(nearby_atom)
|
|
|
|
else if(istype(nearby_atom, /obj/machinery/door/airlock/glass))
|
|
new /obj/machinery/door/airlock/bronze/clock/glass(nearby_atom.loc)
|
|
new /obj/effect/temp_visual/ratvar/door(nearby_atom.loc)
|
|
new /obj/effect/temp_visual/ratvar/beam(nearby_atom.loc)
|
|
qdel(nearby_atom)
|
|
|
|
else if(istype(nearby_atom, /obj/machinery/door/airlock))
|
|
new /obj/machinery/door/airlock/bronze/clock(nearby_atom.loc)
|
|
new /obj/effect/temp_visual/ratvar/door(nearby_atom.loc)
|
|
new /obj/effect/temp_visual/ratvar/beam(nearby_atom.loc)
|
|
qdel(nearby_atom)
|
|
|
|
if(11 to 20) // Spawn 4 ai-controlled marauders to fuck shit up
|
|
visible_message(span_warning("A group of clockwork marauders appear, before being obscured by a cloud of smoke!"))
|
|
|
|
for(var/direction in list(NORTH, SOUTH, EAST, WEST))
|
|
var/turf/tile = get_step(src, direction)
|
|
new /mob/living/basic/clockwork_marauder(tile)
|
|
|
|
do_smoke(4, holder = src, location = src)
|
|
|
|
if(21 to 30) // Fuck up the power
|
|
priority_announce("A fatal power outage has occurred. Please ensure that all on-board devices are connected to an appropriate power generator.")
|
|
|
|
apc_loop:
|
|
for(var/obj/machinery/power/apc/controller as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/power/apc))
|
|
var/area/apc_area = get_area(controller) // make sure that no "critical" APCs lose their power (SM, namely)
|
|
for(var/list/zlevel_turfs as anything in apc_area.get_zlevel_turf_lists())
|
|
for(var/turf/area_turf as anything in zlevel_turfs)
|
|
for(var/obj/machinery/depowered_machinery in area_turf)
|
|
if(depowered_machinery.critical_machine)
|
|
continue apc_loop
|
|
|
|
controller.cell?.charge = 0
|
|
|
|
for(var/obj/machinery/power/smes/battery_pack as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/power/smes))
|
|
battery_pack.charge = 0
|
|
|
|
GLOB.max_clock_power += 1500 // Extra bonus
|
|
GLOB.clock_power = GLOB.max_clock_power // for stealing the entire station's power
|
|
|
|
for(var/mob/living/living_mob as anything in GLOB.mob_living_list)
|
|
if(!is_station_level(living_mob.z))
|
|
continue
|
|
|
|
if(IS_CLOCK(living_mob))
|
|
to_chat(living_mob, span_brass("You feel as if something powerful is watching over you, as you feel the power in your Clockwork Slab increase."))
|
|
else
|
|
to_chat(living_mob, span_brass("You feel as if something powerful is watching over you as a low hum of machinery fills your mind."))
|
|
|
|
|
|
if(31 to 40) // Fuck up the power, but in the other way instead
|
|
priority_announce("An extreme power surge has been detected in on-board APCs. Surge will subside in [rand(3, 8)] minutes.") // Not always accurate, are we?
|
|
|
|
force_apc_arcing(TRUE)
|
|
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(force_apc_arcing), FALSE), 4 MINUTES)
|
|
|
|
|
|
/obj/effect/lectern_light
|
|
icon = 'modular_skyrat/modules/clock_cult/icons/clockwork_objects.dmi'
|
|
icon_state = "lectern_closed"
|
|
pixel_y = 10
|
|
layer = FLY_LAYER
|
|
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
|
alpha = 160
|
|
anchored = TRUE
|
|
|
|
/// Open the book
|
|
/obj/effect/lectern_light/proc/open()
|
|
icon_state = "lectern_open"
|
|
flick("lectern_opening", src)
|
|
|
|
/// Close the book
|
|
/obj/effect/lectern_light/proc/close()
|
|
icon_state = "lectern_closed"
|
|
flick("lectern_closing", src)
|
|
|
|
#undef BOOK_OPEN_RANGE
|