mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-01 04:21:42 +00:00
Converts most spans into span procs. Mostly used regex for this and sorted out any compile time errors afterwards so there could be some bugs. Was initially going to do defines, but ninja said to make it into a proc, and if there's any overhead, they can easily be changed to defines. Makes it easier to control the formatting and prevents typos when creating spans as it'll runtime if you misspell instead of silently failing. Reduces the code you need to write when writing spans, as you don't need to close the span as that's automatically handled by the proc. (Note from Lemon: This should be converted to defines once we update the minimum version to 514. Didn't do it now because byond pain and such)
457 lines
15 KiB
Plaintext
457 lines
15 KiB
Plaintext
/// How many lines of log we keep
|
|
#define EXODRONE_LOG_SIZE 15
|
|
/// Size of drone storage shared between loot and tools.
|
|
#define EXODRONE_CARGO_SLOTS 6
|
|
|
|
// Fuel types and travel time per unit of distance on that fuel.
|
|
#define FUEL_BASIC "basic"
|
|
#define BASIC_FUEL_TIME_COST 300
|
|
|
|
#define FUEL_ADVANCED "advanced"
|
|
#define ADVANCED_FUEL_TIME_COST 200
|
|
|
|
#define FUEL_EXOTIC "exotic"
|
|
#define EXOTIC_FUEL_TIME_COST 100
|
|
|
|
/// All exodrones.
|
|
GLOBAL_LIST_EMPTY(exodrones)
|
|
/// All exodrone launchers.
|
|
GLOBAL_LIST_EMPTY(exodrone_launchers)
|
|
|
|
/// Exploration drone
|
|
/obj/item/exodrone
|
|
name = "exploration drone"
|
|
desc = "long range semi-autonomous exploration drone"
|
|
icon = 'icons/obj/exploration.dmi'
|
|
icon_state = "drone"
|
|
w_class = WEIGHT_CLASS_BULKY
|
|
|
|
/// Current drone status, see code\__DEFINES\adventure.dm
|
|
var/drone_status = EXODRONE_IDLE
|
|
/// Are we currently controlled by remote terminal, blocks other terminals from interacting with this drone.
|
|
var/controlled = FALSE
|
|
/// Site we're currently at, null means station.
|
|
var/datum/exploration_site/location
|
|
/// Site we're currently travelling to, null means going back to station - check drone status if you want to check if traveling or idle
|
|
var/datum/exploration_site/travel_target
|
|
/// Total travel time to our current target
|
|
var/travel_time
|
|
/// Id of travel timer
|
|
var/travel_timer_id
|
|
/// Message that will show up on busy screen
|
|
var/busy_message = "Doing something..."
|
|
/// When we entered busy state
|
|
var/busy_start_time
|
|
/// How long will busy state last
|
|
var/busy_duration
|
|
// Our current adventure if any.
|
|
var/datum/adventure/current_adventure
|
|
// Our current simple event ui data if any
|
|
var/list/current_event_ui_data
|
|
/// Pad we've launched from, we'll try to land on this one first when coming back if it still exists.
|
|
var/datum/weakref/last_pad
|
|
/// Log of recent events
|
|
var/list/drone_log = list()
|
|
/// List of tools, EXODRONE_TOOL_WELDER etc
|
|
var/list/tools = list()
|
|
// Current travel cost per 1 distance in deciseconds
|
|
var/travel_cost_coeff = BASIC_FUEL_TIME_COST
|
|
/// Repeated drone name counter
|
|
var/static/name_counter = list()
|
|
/// Used to provide source to the regex replacement function. DO NOT MODIFY DIRECTLY
|
|
var/static/obj/item/exodrone/_regex_context
|
|
|
|
/obj/item/exodrone/Initialize()
|
|
. = ..()
|
|
name = pick(strings(EXODRONE_FILE,"probe_names"))
|
|
if(name_counter[name])
|
|
name_counter[name]++
|
|
name = "[name] \Roman[name_counter[name]]"
|
|
else
|
|
name_counter[name] = 1
|
|
GLOB.exodrones += src
|
|
/// Cargo storage
|
|
var/datum/component/storage/storage = AddComponent(/datum/component/storage/concrete)
|
|
storage.cant_hold = GLOB.blacklisted_cargo_types
|
|
storage.max_w_class = WEIGHT_CLASS_NORMAL
|
|
storage.max_items = EXODRONE_CARGO_SLOTS
|
|
|
|
/obj/item/exodrone/Destroy()
|
|
. = ..()
|
|
GLOB.exodrones -= src
|
|
|
|
/// Description for drone listing, describes location and current status
|
|
/obj/item/exodrone/proc/ui_description()
|
|
if(location)
|
|
switch(drone_status)
|
|
if(EXODRONE_TRAVEL)
|
|
return "Traveling back to station."
|
|
else
|
|
return "Exploring [location.display_name()]"
|
|
else
|
|
switch(drone_status)
|
|
if(EXODRONE_TRAVEL)
|
|
return "Traveling to exploration site."
|
|
else
|
|
return "Idle."
|
|
|
|
/// Starts travel for site, does not validate if it's possible
|
|
/obj/item/exodrone/proc/launch_for(datum/exploration_site/target_site)
|
|
if(!location) //We're launching from station, fuel up
|
|
var/obj/machinery/exodrone_launcher/pad = locate() in loc
|
|
pad.fuel_up(src)
|
|
pad.launch_effect()
|
|
last_pad = WEAKREF(pad)
|
|
drone_log("Launched from [pad.name] and set course for [target_site.display_name()]")
|
|
else
|
|
drone_log("Launched from [location.display_name()] and set course for [target_site ? target_site.display_name() : station_name()]")
|
|
set_status(EXODRONE_TRAVEL)
|
|
moveToNullspace()
|
|
var/distance_to_travel = target_site ? target_site.distance : location.distance //If we're going home distance is distance of our current location
|
|
if(location && target_site) //Traveling site to site is faster (don't think too hard on 3d space logistics here)
|
|
distance_to_travel = max(abs(target_site.distance - location.distance),1)
|
|
travel_target = target_site
|
|
travel_time = travel_cost_coeff*distance_to_travel
|
|
travel_timer_id = addtimer(CALLBACK(src,.proc/finish_travel),travel_time,TIMER_STOPPABLE)
|
|
|
|
/// Travel cleanup
|
|
/obj/item/exodrone/proc/finish_travel()
|
|
location = travel_target
|
|
travel_timer_id = null
|
|
travel_time = null
|
|
if(location)//We're arriving at exploration site
|
|
location.on_drone_arrival(src)
|
|
set_status(EXODRONE_EXPLORATION)
|
|
else
|
|
var/obj/machinery/exodrone_launcher = find_landing_pad()
|
|
if(exodrone_launcher)
|
|
forceMove(get_turf(exodrone_launcher))
|
|
drone_log("Arrived at [station_name()]. Landing at [exodrone_launcher].")
|
|
else
|
|
var/turf/drop_zone = drop_somewhere_on_station()
|
|
drone_log("Arrived at [station_name()]. Emergency landing at [drop_zone.loc.name].")
|
|
set_status(EXODRONE_IDLE)
|
|
|
|
/obj/item/exodrone/proc/set_status(new_status)
|
|
SEND_SIGNAL(src,COMSIG_EXODRONE_STATUS_CHANGED)
|
|
drone_status = new_status
|
|
|
|
/// Cargo space left
|
|
/obj/item/exodrone/proc/space_left()
|
|
return EXODRONE_CARGO_SLOTS - length(contents) - length(tools)
|
|
|
|
/// Adds drone tool and resizes storage.
|
|
/obj/item/exodrone/proc/add_tool(tool_type)
|
|
if(space_left() > 0 && (tool_type in GLOB.exodrone_tool_metadata))
|
|
tools += tool_type
|
|
update_storage_size()
|
|
|
|
/// Removes drone tool and resizes storage.
|
|
/obj/item/exodrone/proc/remove_tool(tool_type)
|
|
tools -= tool_type
|
|
update_storage_size()
|
|
|
|
/// Resizes storage component depending on slots used by tools.
|
|
/obj/item/exodrone/proc/update_storage_size()
|
|
var/datum/component/storage/storage = GetComponent(/datum/component/storage/concrete)
|
|
storage.max_items = EXODRONE_CARGO_SLOTS - length(tools)
|
|
|
|
/// Builds ui data for drone storage.
|
|
/obj/item/exodrone/proc/get_cargo_data()
|
|
. = list()
|
|
for(var/tool in tools)
|
|
. += list(list("type"="tool","name"=tool))
|
|
for(var/obj/cargo in contents)
|
|
. += list(list("type"="cargo","name"=cargo.name, "ref"=ref(cargo)))
|
|
for(var/_ in 1 to space_left())
|
|
. += list(list("type"="empty","name"="Free space"))
|
|
|
|
/// Tries to add loot to drone cargo while respecting space left
|
|
/obj/item/exodrone/proc/try_transfer(obj/loot, delete_on_failure=TRUE)
|
|
if(space_left() > 1)
|
|
loot.forceMove(src)
|
|
drone_log("Acquired [loot.name].")
|
|
else
|
|
drone_log("Abandoned [loot.name] due to lack of space.")
|
|
if(delete_on_failure)
|
|
qdel(loot)
|
|
|
|
/// Crashes the drone somewhere random if there's no launchpad to be found.
|
|
/obj/item/exodrone/proc/drop_somewhere_on_station()
|
|
var/turf/random_spot = get_safe_random_station_turf()
|
|
|
|
var/obj/structure/closet/supplypod/pod = podspawn(list(
|
|
"target" = random_spot,
|
|
))
|
|
forceMove(pod)
|
|
return random_spot
|
|
|
|
/// Tries to find landing pad, starting with the one we launched from.
|
|
/obj/item/exodrone/proc/find_landing_pad()
|
|
var/obj/machinery/exodrone_launcher/landing_pad = last_pad?.resolve()
|
|
if(landing_pad)
|
|
return landing_pad
|
|
for(var/obj/machinery/exodrone_launcher/other_pad in GLOB.exodrone_launchers)
|
|
return other_pad
|
|
|
|
/// encounters random or specificed event for the current site.
|
|
/obj/item/exodrone/proc/explore_site(datum/exploration_event/specific_event)
|
|
if(!specific_event) //encounter random event
|
|
var/list/events_to_encounter = list()
|
|
for(var/datum/exploration_event/event in location.events)
|
|
if(event.visited)
|
|
continue
|
|
events_to_encounter += event
|
|
if(!length(events_to_encounter))
|
|
drone_log("It seems there's nothing interesting left around [location.name].")
|
|
return
|
|
var/datum/exploration_event/encountered_event = pick(events_to_encounter)
|
|
encountered_event.encounter(src)
|
|
else if(specific_event.is_targetable())
|
|
specific_event.encounter(src)
|
|
|
|
/obj/item/exodrone/proc/get_adventure_data()
|
|
var/list/data = current_adventure?.ui_data()
|
|
data["description"] = updateKeywords(data["description"])
|
|
var/list/choices = data["choices"]
|
|
for(var/list/choice in choices)
|
|
choice["text"] = updateKeywords(choice["text"])
|
|
return data
|
|
|
|
///Replaces $$SITE_NAME with site name and $$QualityName with quality values
|
|
/obj/item/exodrone/proc/updateKeywords(text)
|
|
_regex_context = src
|
|
var/static/regex/keywordRegex = regex(@"\$\$(\S*)","g")
|
|
. = keywordRegex.Replace(text,/obj/item/exodrone/proc/replace_keyword)
|
|
_regex_context = null
|
|
|
|
/// This is called with src = regex datum, so don't try to access any instance variables directly here.
|
|
/obj/item/exodrone/proc/replace_keyword(match,g1)
|
|
switch(g1)
|
|
if("SITE_NAME")
|
|
return _regex_context.location.display_name()
|
|
else
|
|
if(_regex_context.current_adventure.qualities[g1])
|
|
return "[_regex_context.current_adventure.qualities[g1]]"
|
|
else
|
|
return ""
|
|
|
|
/obj/item/exodrone/proc/start_adventure(datum/adventure/adventure)
|
|
current_adventure = adventure
|
|
RegisterSignal(current_adventure,COMSIG_ADVENTURE_FINISHED,.proc/resolve_adventure)
|
|
RegisterSignal(current_adventure,COMSIG_ADVENTURE_QUALITY_INIT,.proc/add_tool_qualities)
|
|
RegisterSignal(current_adventure,COMSIG_ADVENTURE_DELAY_START,.proc/adventure_delay_start)
|
|
RegisterSignal(current_adventure,COMSIG_ADVENTURE_DELAY_END,.proc/adventure_delay_end)
|
|
set_status(EXODRONE_ADVENTURE)
|
|
current_adventure.start_adventure()
|
|
|
|
/// Handles finishing adventure
|
|
/obj/item/exodrone/proc/resolve_adventure(datum/source,result)
|
|
SIGNAL_HANDLER
|
|
switch(result)
|
|
if(ADVENTURE_RESULT_SUCCESS)
|
|
award_adventure_loot()
|
|
UnregisterSignal(current_adventure,list(COMSIG_ADVENTURE_FINISHED,COMSIG_ADVENTURE_QUALITY_INIT,COMSIG_ADVENTURE_DELAY_START,COMSIG_ADVENTURE_DELAY_END))
|
|
current_adventure = null
|
|
set_status(EXODRONE_EXPLORATION)
|
|
return
|
|
if(ADVENTURE_RESULT_DAMAGE)
|
|
damage(max_integrity*0.5) //Half health lost
|
|
if(!QDELETED(src)) // Don't bother if we just blown up from the damage
|
|
UnregisterSignal(current_adventure,list(COMSIG_ADVENTURE_FINISHED,COMSIG_ADVENTURE_QUALITY_INIT,COMSIG_ADVENTURE_DELAY_START,COMSIG_ADVENTURE_DELAY_END))
|
|
current_adventure = null
|
|
set_status(EXODRONE_EXPLORATION)
|
|
return
|
|
if(ADVENTURE_RESULT_DEATH)
|
|
qdel(src)
|
|
|
|
/// Adds loot from current adventure to the drone
|
|
/obj/item/exodrone/proc/award_adventure_loot()
|
|
if(length(current_adventure.loot_categories))
|
|
var/generator_type = GLOB.adventure_loot_generator_index[pick(current_adventure.loot_categories)]
|
|
if(!generator_type)
|
|
return //Could probably warn but i suppose this is up to adventure creator.
|
|
var/datum/adventure_loot_generator/generator = new generator_type
|
|
generator.transfer_loot(src)
|
|
|
|
/// Applies adventure qualities based on our tools
|
|
/obj/item/exodrone/proc/add_tool_qualities(datum/source,list/quality_list)
|
|
SIGNAL_HANDLER
|
|
for(var/tool in tools)
|
|
quality_list[tool] = 1
|
|
|
|
/obj/item/exodrone/proc/adventure_delay_start(datum/source, delay_time,delay_message)
|
|
SIGNAL_HANDLER
|
|
set_busy(delay_message,delay_time)
|
|
|
|
/obj/item/exodrone/proc/adventure_delay_end(datum/source)
|
|
SIGNAL_HANDLER
|
|
unset_busy(EXODRONE_ADVENTURE)
|
|
|
|
/// Enters busy mode for a given duration.
|
|
/obj/item/exodrone/proc/set_busy(message,duration)
|
|
if(message)
|
|
busy_message = message
|
|
busy_start_time = world.time
|
|
busy_duration = duration
|
|
set_status(EXODRONE_BUSY)
|
|
|
|
/// Resets busy status
|
|
/obj/item/exodrone/proc/unset_busy(new_status)
|
|
busy_message = initial(busy_message)
|
|
busy_start_time = null
|
|
busy_duration = null
|
|
set_status(new_status)
|
|
|
|
/obj/item/exodrone/proc/busy_time_left()
|
|
return busy_duration - (world.time - busy_start_time)
|
|
|
|
/// Returns failure message or FALSE if we're ready to travel
|
|
/obj/item/exodrone/proc/travel_error()
|
|
/// We're home and on ready pad or exploring and out of any events/adventures
|
|
switch(drone_status)
|
|
if(EXODRONE_IDLE)
|
|
var/obj/machinery/exodrone_launcher/pad = locate() in loc
|
|
if(!pad)
|
|
return "No launcher"
|
|
if(!pad.fuel_canister)
|
|
return "No fuel in launcher"
|
|
if(pad.fuel_canister.uses <= 0)
|
|
return "Launcher fuel used up"
|
|
return FALSE
|
|
if(EXODRONE_EXPLORATION)
|
|
if(current_event_ui_data)
|
|
return "Busy"
|
|
return FALSE
|
|
else
|
|
return ""
|
|
|
|
/// Deals damage in adventures/events.
|
|
/obj/item/exodrone/proc/damage(amount)
|
|
take_damage(amount)
|
|
drone_log("Sustained [amount] damage.")
|
|
|
|
/obj/item/exodrone/proc/drone_log(message)
|
|
drone_log.Insert(1,message)
|
|
if(length(drone_log) > EXODRONE_LOG_SIZE)
|
|
drone_log.Cut(EXODRONE_LOG_SIZE)
|
|
|
|
/obj/item/exodrone/proc/has_tool(tool_type)
|
|
return tools.Find(tool_type)
|
|
|
|
/// Exploration drone launcher
|
|
/obj/machinery/exodrone_launcher
|
|
name = "exploration drone launcher"
|
|
icon = 'icons/obj/exploration.dmi'
|
|
icon_state = "launcher"
|
|
/// Loaded fuel pellet.
|
|
var/obj/item/fuel_pellet/fuel_canister
|
|
|
|
/obj/machinery/exodrone_launcher/Initialize()
|
|
. = ..()
|
|
GLOB.exodrone_launchers += src
|
|
|
|
/obj/machinery/exodrone_launcher/attackby(obj/item/I, mob/living/user, params)
|
|
if(istype(I, /obj/item/fuel_pellet))
|
|
if(fuel_canister)
|
|
to_chat(user, span_warning("There's already a fuel tank inside [src]!"))
|
|
return TRUE
|
|
if(!user.transferItemToLoc(I, src))
|
|
return
|
|
fuel_canister = I
|
|
update_icon()
|
|
return TRUE
|
|
else if(istype(I,/obj/item/exodrone) && user.transferItemToLoc(I, drop_location()))
|
|
return TRUE
|
|
else
|
|
return ..()
|
|
|
|
/obj/machinery/exodrone_launcher/crowbar_act(mob/living/user, obj/item/I)
|
|
. = ..()
|
|
if(fuel_canister)
|
|
to_chat(user, span_notice("You remove the fuel tank from [src]."))
|
|
fuel_canister.forceMove(drop_location())
|
|
fuel_canister = null
|
|
|
|
/obj/machinery/exodrone_launcher/Destroy()
|
|
. = ..()
|
|
GLOB.exodrone_launchers -= src
|
|
|
|
/obj/machinery/exodrone_launcher/update_overlays()
|
|
. = ..()
|
|
if(fuel_canister && fuel_canister.uses > 0)
|
|
switch(fuel_canister.fuel_type)
|
|
if(FUEL_BASIC)
|
|
. += "launchpad_fuel_basic"
|
|
if(FUEL_ADVANCED)
|
|
. += "launchpad_fuel_advanced"
|
|
if(FUEL_EXOTIC)
|
|
. += "launchpad_fuel_exotic"
|
|
|
|
/obj/machinery/exodrone_launcher/proc/get_fuel_coefficent()
|
|
if(!fuel_canister)
|
|
return
|
|
switch(fuel_canister.fuel_type)
|
|
if(FUEL_BASIC)
|
|
return BASIC_FUEL_TIME_COST
|
|
if(FUEL_ADVANCED)
|
|
return ADVANCED_FUEL_TIME_COST
|
|
if(FUEL_EXOTIC)
|
|
return EXOTIC_FUEL_TIME_COST
|
|
|
|
/obj/machinery/exodrone_launcher/proc/fuel_up(obj/item/exodrone/drone)
|
|
drone.travel_cost_coeff = get_fuel_coefficent()
|
|
fuel_canister.use()
|
|
|
|
/obj/machinery/exodrone_launcher/proc/launch_effect()
|
|
playsound(src,'sound/effects/podwoosh.ogg',50, FALSE)
|
|
do_smoke(1,get_turf(src))
|
|
|
|
/obj/machinery/exodrone_launcher/handle_atom_del(atom/A)
|
|
if(A == fuel_canister)
|
|
fuel_canister = null
|
|
update_icon()
|
|
|
|
/obj/item/exodrone/proc/get_travel_coeff()
|
|
switch(drone_status)
|
|
if(EXODRONE_IDLE)
|
|
var/obj/machinery/exodrone_launcher/pad = locate() in loc
|
|
if(pad && pad.fuel_canister)
|
|
return pad.get_fuel_coefficent()
|
|
else
|
|
return travel_cost_coeff
|
|
else
|
|
return travel_cost_coeff
|
|
|
|
/obj/item/fuel_pellet
|
|
name = "standard fuel pellet"
|
|
desc = "compressed fuel pellet for long-distance flight"
|
|
icon = 'icons/obj/exploration.dmi'
|
|
icon_state = "fuel_basic"
|
|
var/fuel_type = FUEL_BASIC
|
|
var/uses = 5
|
|
|
|
/obj/item/fuel_pellet/use()
|
|
uses--
|
|
if(uses < 0)
|
|
qdel(src)
|
|
|
|
/obj/item/fuel_pellet/advanced
|
|
name = "advanced fuel pellet"
|
|
fuel_type = FUEL_ADVANCED
|
|
icon_state = "fuel_advanced"
|
|
|
|
/obj/item/fuel_pellet/exotic
|
|
name = "exotic fuel pellet"
|
|
fuel_type = FUEL_EXOTIC
|
|
icon_state = "fuel_exotic"
|
|
|
|
#undef EXODRONE_LOG_SIZE
|
|
#undef EXODRONE_CARGO_SLOTS
|
|
#undef FUEL_BASIC
|
|
#undef BASIC_FUEL_TIME_COST
|
|
#undef FUEL_ADVANCED
|
|
#undef ADVANCED_FUEL_TIME_COST
|
|
#undef FUEL_EXOTIC
|
|
#undef EXOTIC_FUEL_TIME_COST
|