Skip to content

Commit

Permalink
Genericises multi-dock prevention (#2358)
Browse files Browse the repository at this point in the history
## About The Pull Request

Expands docking ticket functionality to include validation based on if
another docking ticket has been created for a specific port, hopefully
preventing multiple ships attempting to dock at the same port
simultaneously.

Also a freebie of ensuring planets which are generating can't be
interacted with and caused to load a second time, since that's icky.

## Why It's Good For The Game

Bugs from multiple people docking to an overmap object at once are bad.

## Changelog

:cl:
add: There's a few more descriptive docking errors now.
/:cl:

<!-- Both :cl:'s are required for the changelog to work! You can put
your name to the right of the first :cl: if you want to overwrite your
GitHub username as author ingame. -->
<!-- You can use multiple of the same prefix (they're only used for the
icon ingame) and delete the unneeded ones. Despite some of the tags,
changelogs should generally represent how a player might be affected by
the changes rather than a summary of the PR's contents. -->
  • Loading branch information
MarkSuckerberg authored Nov 9, 2023
1 parent a104294 commit 68f0457
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 19 deletions.
10 changes: 5 additions & 5 deletions code/controllers/subsystem/overmap.dm
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ SUBSYSTEM_DEF(overmap)
var/datum/map_template/ruin/used_ruin = ispath(ruin_type) ? (new ruin_type) : ruin_type

// name is random but PROBABLY unique
var/encounter_name = dynamic_datum.planet_name || "Dynamic Overmap Encounter #[rand(1111,9999)]-[rand(1111,9999)]"
var/encounter_name = dynamic_datum.planet_name || "\improper Uncharted Space [dynamic_datum.x]/[dynamic_datum.y]-[rand(1111, 9999)]"
var/datum/map_zone/mapzone = SSmapping.create_map_zone(encounter_name)
var/datum/virtual_level/vlevel = SSmapping.create_virtual_level(
encounter_name,
Expand Down Expand Up @@ -318,7 +318,7 @@ SUBSYSTEM_DEF(overmap)

var/obj/docking_port/stationary/primary_dock = new(primary_docking_turf)
primary_dock.dir = NORTH
primary_dock.name = "\improper Uncharted Space"
primary_dock.name = "[encounter_name] docking location #1"
primary_dock.height = RESERVE_DOCK_MAX_SIZE_SHORT
primary_dock.width = RESERVE_DOCK_MAX_SIZE_LONG
primary_dock.dheight = 0
Expand All @@ -327,7 +327,7 @@ SUBSYSTEM_DEF(overmap)

var/obj/docking_port/stationary/secondary_dock = new(secondary_docking_turf)
secondary_dock.dir = NORTH
secondary_dock.name = "\improper Uncharted Space"
secondary_dock.name = "[encounter_name] docking location #2"
secondary_dock.height = RESERVE_DOCK_MAX_SIZE_SHORT
secondary_dock.width = RESERVE_DOCK_MAX_SIZE_LONG
secondary_dock.dheight = 0
Expand All @@ -350,7 +350,7 @@ SUBSYSTEM_DEF(overmap)

var/obj/docking_port/stationary/tertiary_dock = new(tertiary_docking_turf)
tertiary_dock.dir = NORTH
tertiary_dock.name = "\improper Uncharted Space"
tertiary_dock.name = "[encounter_name] docking location #3"
tertiary_dock.height = RESERVE_DOCK_MAX_SIZE_SHORT
tertiary_dock.width = RESERVE_DOCK_MAX_SIZE_LONG
tertiary_dock.dheight = 0
Expand All @@ -359,7 +359,7 @@ SUBSYSTEM_DEF(overmap)

var/obj/docking_port/stationary/quaternary_dock = new(quaternary_docking_turf)
quaternary_dock.dir = NORTH
quaternary_dock.name = "\improper Uncharted Space"
quaternary_dock.name = "[encounter_name] docking location #4"
quaternary_dock.height = RESERVE_DOCK_MAX_SIZE_SHORT
quaternary_dock.width = RESERVE_DOCK_MAX_SIZE_LONG
quaternary_dock.dheight = 0
Expand Down
21 changes: 16 additions & 5 deletions code/modules/overmap/_overmap_datum.dm
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
/// The icon state the token will be set to on init.
var/token_icon_state = "object"

/// The current docking ticket of this object, if any
var/datum/docking_ticket/current_docking_ticket

/datum/overmap/New(position, ...)
SHOULD_NOT_OVERRIDE(TRUE) // Use [/datum/overmap/proc/Initialize] instead.
if(!position)
Expand All @@ -64,6 +67,8 @@

/datum/overmap/Destroy(force, ...)
SSovermap.overmap_objects -= src
if(current_docking_ticket)
QDEL_NULL(current_docking_ticket)
if(docked_to)
docked_to.post_undocked()
docked_to.contents -= src
Expand Down Expand Up @@ -219,17 +224,20 @@
if(docked_to)
CRASH("Overmap datum [src] tried to dock to [docked_to] when it is already docked to another overmap datum.")

if(docking)
return
if(docking || current_docking_ticket)
return "Already docking!"
docking = TRUE

var/datum/docking_ticket/ticket = dock_target.pre_docked(src)
if(!ticket || ticket.docking_error)
var/ticket_error = ticket?.docking_error
if(!ticket || ticket_error)
qdel(ticket)
docking = FALSE
return ticket?.docking_error || "Unknown docking error!"
return ticket_error || "Unknown docking error!"
if(!pre_dock(dock_target, ticket))
qdel(ticket)
docking = FALSE
return
return ticket_error

start_dock(dock_target, ticket)

Expand Down Expand Up @@ -289,6 +297,9 @@
dock_target.post_docked(src)
docking = FALSE

//Clears the docking ticket from both sides
qdel(current_docking_ticket)

SEND_SIGNAL(src, COMSIG_OVERMAP_DOCK, dock_target)

/**
Expand Down
35 changes: 34 additions & 1 deletion code/modules/overmap/docking_ticket.dm
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,40 @@
var/docking_error

/datum/docking_ticket/New(_target_port, _issuer, _target, _docking_error)
docking_error = _docking_error
if(docking_error)
return

if(!_target_port)
docking_error = "No target port specified!"
return
target_port = _target_port
if(target_port.current_docking_ticket)
docking_error = "[target_port] is already being docked to!"
return
target_port.current_docking_ticket = src

if(!_issuer)
docking_error = "No issuer overmap datum specified!"
return
issuer = _issuer

if(!_target)
docking_error = "No target overmap datum specified!"
return
target = _target
docking_error = _docking_error
if(target.current_docking_ticket)
docking_error = "[target] is already docking!"
return
target.current_docking_ticket = src


/datum/docking_ticket/Destroy(force, ...)
if(target)
target.current_docking_ticket = null
target = null
if(target_port)
target_port.current_docking_ticket = null
target_port = null

return ..()
10 changes: 10 additions & 0 deletions code/modules/overmap/objects/dynamic_datum.dm
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
var/ruin_type
/// list of ruins and their target turf, indexed by name
var/list/ruin_turfs
/// Whether or not the level is currently loading.
var/loading = FALSE

/// The mapgenerator itself. SHOULD NOT BE NULL if the datum ever creates an encounter
var/datum/map_generator/mapgen = /datum/map_generator/single_turf/space
Expand Down Expand Up @@ -68,6 +70,8 @@
return get_turf(pick(reserve_docks))

/datum/overmap/dynamic/pre_docked(datum/overmap/ship/controlled/dock_requester)
if(loading)
return new /datum/docking_ticket(_docking_error = "[src] is currently being scanned for suitable docking locations by another ship. Please wait.")
if(!load_level())
return new /datum/docking_ticket(_docking_error = "[src] cannot be docked to.")
else
Expand Down Expand Up @@ -177,15 +181,21 @@
return FALSE
if(mapzone)
return TRUE

loading = TRUE
log_shuttle("[src] [REF(src)] LEVEL_INIT")

// use the ruin type in template if it exists, or pick from ruin list if IT exists; otherwise null
var/selected_ruin = template || (ruin_type ? pickweightAllowZero(SSmapping.ruin_types_probabilities[ruin_type]) : null)
var/list/dynamic_encounter_values = SSovermap.spawn_dynamic_encounter(src, selected_ruin)
if(!length(dynamic_encounter_values))
return FALSE

mapzone = dynamic_encounter_values[1]
reserve_docks = dynamic_encounter_values[2]
ruin_turfs = dynamic_encounter_values[3]

loading = FALSE
return TRUE

/datum/overmap/dynamic/empty
Expand Down
9 changes: 1 addition & 8 deletions code/modules/overmap/objects/outpost/outpost.dm
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@
/// The mapzone used by the outpost level and hangars. Using a single mapzone means networked radio messages.
var/datum/map_zone/mapzone
var/list/datum/hangar_shaft/shaft_datums = list()
/// A list keeping track of the docks that're currently being landed at. Helps to prevent SGTs,
/// as at time of writing there's no protection against a ship docking with a port that's already being docked to.
var/list/landing_in_progress_docks = list() // TODO: generalize this approach to prevent simultaneous-dock ship-overlap SGTs

/// The maximum number of missions that may be offered by the outpost at one time.
/// Missions which have been accepted do not count against this limit.
Expand Down Expand Up @@ -214,14 +211,10 @@
)
return FALSE

landing_in_progress_docks += h_dock
adjust_dock_to_shuttle(h_dock, dock_requester.shuttle_port)
return new /datum/docking_ticket(h_dock, src, dock_requester)

/datum/overmap/outpost/post_docked(datum/overmap/ship/controlled/dock_requester)
// removes the stationary dock from the list, so that we don't have to worry about it causing merge SGTs
landing_in_progress_docks -= dock_requester.shuttle_port.docked

for(var/mob/M as anything in GLOB.player_list)
if(dock_requester.shuttle_port.is_in_shuttle_bounds(M))
M.play_screen_text("<span class='maptext' style=font-size:24pt;text-align:center valign='top'><u>[name]</u></span><br>[station_time_timestamp_fancy("hh:mm")]")
Expand Down Expand Up @@ -288,7 +281,7 @@
// a dock/undock cycle may leave the stationary port w/ flipped width and height,
// due to adjust_dock_to_shuttle(). so we need to check both orderings of the list.
if( \
!(h_dock in landing_in_progress_docks) && !h_dock.docked && \
!h_dock.current_docking_ticket && !h_dock.docked && \
( \
(h_dock.width == h_template.dock_width && h_dock.height == h_template.dock_height) || \
(h_dock.width == h_template.dock_height && h_dock.height == h_template.dock_width) \
Expand Down
2 changes: 2 additions & 0 deletions code/modules/overmap/ships/controlled_ship_datum.dm
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,10 @@

/datum/overmap/ship/controlled/pre_dock(datum/overmap/to_dock, datum/docking_ticket/ticket)
if(ticket.target != src || ticket.issuer != to_dock)
ticket.docking_error = "Invalid target."
return FALSE
if(!shuttle_port.check_dock(ticket.target_port))
ticket.docking_error = "Targeted docking port invalid."
return FALSE
return TRUE

Expand Down
2 changes: 2 additions & 0 deletions code/modules/shuttle/shuttle.dm
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,8 @@
var/json_key
//Setting this to false will prevent the roundstart_template from being loaded on Initiallize(). You should set this to false if this loads a subship on a ship map template
var/load_template_on_initialize = TRUE
/// The docking ticket of the ship docking to this port.
var/datum/docking_ticket/current_docking_ticket

/obj/docking_port/stationary/Initialize(mapload)
. = ..()
Expand Down

0 comments on commit 68f0457

Please sign in to comment.