From b0cec39d840d66a4d51e90258a07f5ab4506d7a5 Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sun, 14 Jul 2024 20:20:27 -0400 Subject: [PATCH] overmaps 1 - generation & spatial (#6550) here we go gamers --- citadel.dme | 7 +- .../controllers/subsystem/mapping/_mapping.dm | 4 - .../subsystem/mapping/obfuscation.dm | 3 + code/controllers/subsystem/overmap.dm | 122 ++++++++++++- code/controllers/subsystem/spatial_grids.dm | 5 +- .../components/turfs/reservation_border.dm | 1 + code/game/atoms/movable/movable.dm | 46 ----- code/game/gamemodes/events/dust.dm | 3 - code/game/machinery/nuclear_bomb.dm | 3 - code/game/mecha/combat/fighter.dm | 71 -------- code/game/turfs/space/space.dm | 21 --- code/modules/admin/admin_verbs.dm | 1 + code/modules/mapping/map.dm | 1 - code/modules/mapping/turf_reservation.dm | 64 +++++-- code/modules/media/mediamanager.dm | 3 +- code/modules/overmap/entity/entity.dm | 30 +++- code/modules/overmap/entity/physics.dm | 52 +++++- code/modules/overmap/events/event_handler.dm | 60 ------- code/modules/overmap/legacy/sectors.dm | 79 ++++----- .../overmap/legacy/ships/computers/helm.dm | 18 +- code/modules/overmap/legacy/spacetravel.dm | 157 ----------------- code/modules/overmap/map/area.dm | 34 +++- code/modules/overmap/map/overmap.dm | 94 ++++++++++ code/modules/overmap/map/overmap_template.dm | 67 +++++++ .../overmap/map/overmap_template_layer.dm | 17 ++ .../map/template_layers/legacy_events.dm | 78 +++++++++ code/modules/overmap/map/turf.dm | 165 +++++++++++------- code/modules/overmap/{map => }/object.dm | 0 code/modules/power/supermatter/supermatter.dm | 10 -- code/modules/tgui/modules/overmap.dm | 16 +- .../{numbers.dmi => numbers_unused.dmi} | Bin icons/modules/overmap/area.dmi | Bin 0 -> 229 bytes icons/modules/overmap/turf.dmi | Bin 0 -> 1199 bytes 33 files changed, 707 insertions(+), 525 deletions(-) delete mode 100644 code/modules/overmap/legacy/spacetravel.dm create mode 100644 code/modules/overmap/map/overmap.dm create mode 100644 code/modules/overmap/map/overmap_template.dm create mode 100644 code/modules/overmap/map/overmap_template_layer.dm create mode 100644 code/modules/overmap/map/template_layers/legacy_events.dm rename code/modules/overmap/{map => }/object.dm (100%) rename icons/effects/{numbers.dmi => numbers_unused.dmi} (100%) create mode 100644 icons/modules/overmap/area.dmi create mode 100644 icons/modules/overmap/turf.dmi diff --git a/citadel.dme b/citadel.dme index 6add89d2cc5..6ad6d866c6f 100644 --- a/citadel.dme +++ b/citadel.dme @@ -4172,6 +4172,7 @@ #include "code\modules\organs\subtypes\nano.dm" #include "code\modules\organs\subtypes\unbreakable.dm" #include "code\modules\organs\subtypes\unseverable.dm" +#include "code\modules\overmap\object.dm" #include "code\modules\overmap\public.dm" #include "code\modules\overmap\entity\entity.dm" #include "code\modules\overmap\entity\physics.dm" @@ -4186,7 +4187,6 @@ #include "code\modules\overmap\legacy\overmap_planet.dm" #include "code\modules\overmap\legacy\overmap_shuttle.dm" #include "code\modules\overmap\legacy\sectors.dm" -#include "code\modules\overmap\legacy\spacetravel.dm" #include "code\modules\overmap\legacy\disperser\disperser.dm" #include "code\modules\overmap\legacy\disperser\disperser_charge.dm" #include "code\modules\overmap\legacy\disperser\disperser_circuit.dm" @@ -4206,8 +4206,11 @@ #include "code\modules\overmap\legacy\ships\engines\gas_thruster_vr.dm" #include "code\modules\overmap\legacy\ships\engines\ion_thruster.dm" #include "code\modules\overmap\map\area.dm" -#include "code\modules\overmap\map\object.dm" +#include "code\modules\overmap\map\overmap.dm" +#include "code\modules\overmap\map\overmap_template.dm" +#include "code\modules\overmap\map\overmap_template_layer.dm" #include "code\modules\overmap\map\turf.dm" +#include "code\modules\overmap\map\template_layers\legacy_events.dm" #include "code\modules\overmap\tiled\tiled.dm" #include "code\modules\paperwork\adminpaper.dm" #include "code\modules\paperwork\carbonpaper.dm" diff --git a/code/controllers/subsystem/mapping/_mapping.dm b/code/controllers/subsystem/mapping/_mapping.dm index c6cbd9b305f..eabccb9b489 100644 --- a/code/controllers/subsystem/mapping/_mapping.dm +++ b/code/controllers/subsystem/mapping/_mapping.dm @@ -35,10 +35,6 @@ SUBSYSTEM_DEF(mapping) // load world - this also initializes our first reserved level, which is compiled in. load_station() - // perform snowflake legacy init stuff - // todo: refactor - if(!(LEGACY_MAP_DATUM).overmap_z) - build_overmap() // todo: refactor - Set up antagonists. populate_antag_type_list() // todo: refactor - Set up spawn points. diff --git a/code/controllers/subsystem/mapping/obfuscation.dm b/code/controllers/subsystem/mapping/obfuscation.dm index 84117b1bc8b..192d67ada01 100644 --- a/code/controllers/subsystem/mapping/obfuscation.dm +++ b/code/controllers/subsystem/mapping/obfuscation.dm @@ -4,6 +4,8 @@ /** * Obfuscation module * + * todo: should this be mapping? this is a lot more important than just mapping + * * * Generates **mangled** IDs; these are either persistently-unique or round-local IDs that are separate per map / map template. * * Generates **obfuscated** IDs; these are mangled and obfuscated IDs that are safe to reveal to players. * @@ -14,6 +16,7 @@ */ /datum/controller/subsystem/mapping /// used to ensure global-ness + // todo: should this be here? this is used literally everywhere var/static/round_global_descriptor /// round-local hash storage for specific map ids var/static/round_local_mangling_cache = list() diff --git a/code/controllers/subsystem/overmap.dm b/code/controllers/subsystem/overmap.dm index 63ef976132b..6a49061cc46 100644 --- a/code/controllers/subsystem/overmap.dm +++ b/code/controllers/subsystem/overmap.dm @@ -3,12 +3,21 @@ SUBSYSTEM_DEF(overmaps) subsystem_flags = SS_NO_FIRE init_order = INIT_ORDER_OVERMAPS + /// overmap by id + // todo: recover + var/static/list/datum/overmap/overmap_by_id = list() + + /// im so sorry bros dont hurt me please-- + /// (eventually we'll have proper bindings but for now, uh, this is how it is!) + var/const/default_overmap_id = "main" + /datum/controller/subsystem/overmaps/Initialize() - if((LEGACY_MAP_DATUM).use_overmap) - GLOB.overmap_event_handler.create_events((LEGACY_MAP_DATUM).overmap_z, (LEGACY_MAP_DATUM).overmap_size, (LEGACY_MAP_DATUM).overmap_event_areas) + make_default_overmap() rebuild_helm_computers() return ..() +//! legacy code below + /datum/controller/subsystem/overmaps/proc/rebuild_helm_computers() for(var/obj/machinery/computer/ship/helm/H in GLOB.machines) H.get_known_sectors() @@ -17,3 +26,112 @@ SUBSYSTEM_DEF(overmaps) if(!initialized) return addtimer(CALLBACK(src, PROC_REF(rebuild_helm_computers)), 0, TIMER_UNIQUE) + +/* +/client/proc/overmap_upload() + set name = "Instantiate Overmap" + set category = "Debug" + + var/are_you_sure = alert( + src, + "Instantiating overmaps is an advanced feature. \ + The uploaded file is placed and instantiated as an overmap; only overmap tiles, overmap entities, and overmap tile entities \ + should exist in the file, or you may have funny things happen and the server explode. \ + Are you sure you know what you are doing?", + "Upload Overmap", + "No", + "Yes", + ) + if(are_you_sure != "Yes") + return + + var/map = input(src, "Select overmap .dmm", "Instantiate Overmap") as file|null + if(!map) + return + + var/datum/dmm_parsed/parsed_map = parse_map(map) + + if(!parsed_map.parsed) + alert(src, "Failed to parse map.", "Parse Error") + return + + var/max_x = world.maxx - TURF_CHUNK_RESOLUTION * 2 + var/max_y = world.maxy - TURF_CHUNK_RESOLUTION * 2 + + if(parsed_map.width >= max_x || parsed_map.height >= max_y) + alert(src, "Your map is too big for the current world size. Maximum: [max_x]x[max_y]", "Improper Dimensions") + return + + // welcome to hell + // allocate turf reservation and load at offset + // from this point on, if we crash, we don't warn the user, because it shouldn't be possible to crash + var/datum/overmap_template/template = new + template.width = parsed_map.width + template.height = parsed_map.height + var/datum/overmap/creating = new("loaded-[rand(1, 1000000)]", template) + creating.initialize() + // loaded, load the map template in there + var/datum/dmm_context/loaded_context = parsed_map.load( + creating.reservation.bottom_left_coords[1], + creating.reservation.bottom_left_coords[2], + creating.reservation.bottom_left_coords[3], + ) + // initialize + SSatoms.init_map_bounds(loaded_context) + var/llx = loaded_context.loaded_bounds[MAP_MINX] + var/lly = loaded_context.loaded_bounds[MAP_MINY] + var/llz = loaded_context.loaded_bounds[MAP_MINZ] + // announce + log_and_message_admins("overmap [creating.id] with dimensions [creating.width]x[creating.height] loaded at LL-bounds [llx], [lly], [llz]") +*/ + +//! end + +//* Overmap Management *// + +/** + * i don't know what to put here + * this isn't a good long-term proc but for now it's fine + */ +/datum/controller/subsystem/overmaps/proc/get_or_load_default_overmap() + if(overmap_by_id[default_overmap_id]) + return overmap_by_id[default_overmap_id] + make_default_overmap() + return overmap_by_id[default_overmap_id] + + +/datum/controller/subsystem/overmaps/proc/make_default_overmap() + if(overmap_by_id[default_overmap_id]) + return + var/datum/map/station/map_datum = SSmapping.loaded_station + if(!map_datum.use_overmap) + return + var/datum/overmap_template/legacy_default/using_default_template = new(map_datum.overmap_size, map_datum.overmap_size, event_clouds = map_datum.overmap_event_areas) + create_overmap_from_template(using_default_template, default_overmap_id) + +/datum/controller/subsystem/overmaps/proc/create_overmap_from_template(datum/overmap_template/templatelike, use_id) + if(ispath(templatelike)) + templatelike = new templatelike + // make sure template is valid + ASSERT(istype(templatelike)) + // get template into another var + var/datum/overmap_template/template = templatelike + // get id or generate + var/id = use_id || generate_overmap_id() + ASSERT(!overmap_by_id[id]) + // make overmap + var/datum/overmap/creating = new(id, template) + // instantiation + creating.initialize() + // done + return creating + +/datum/controller/subsystem/overmaps/proc/generate_overmap_id() + var/potential + var/safety = 1000 + do + if(safety-- <= 0) + CRASH("failed to generate overmap id - too many loops") + potential = "[SSmapping.round_global_descriptor && "[SSmapping.round_global_descriptor]-"][copytext(md5("[rand(1, 1000000)]"), 1, 5)]" + while(overmap_by_id[potential]) + return potential diff --git a/code/controllers/subsystem/spatial_grids.dm b/code/controllers/subsystem/spatial_grids.dm index 89793acb3e4..660724af43e 100644 --- a/code/controllers/subsystem/spatial_grids.dm +++ b/code/controllers/subsystem/spatial_grids.dm @@ -12,13 +12,16 @@ SUBSYSTEM_DEF(spatial_grids) /// /living mobs. they don't have to be alive, just a subtype of /living. var/datum/spatial_grid/living + /// /obj/overmap/entity's + var/datum/spatial_grid/overmap_entities /datum/controller/subsystem/spatial_grids/Initialize() make_grids() return ..() /datum/controller/subsystem/spatial_grids/proc/make_grids() - living = new /datum/spatial_grid(/mob/living, 16) + living = new /datum/spatial_grid(/mob/living) + overmap_entities = new /datum/spatial_grid(/obj/overmap/entity) /datum/controller/subsystem/spatial_grids/on_max_z_changed(old_z_count, new_z_count) . = ..() diff --git a/code/datums/components/turfs/reservation_border.dm b/code/datums/components/turfs/reservation_border.dm index 5132dc924c5..e0c45e377b1 100644 --- a/code/datums/components/turfs/reservation_border.dm +++ b/code/datums/components/turfs/reservation_border.dm @@ -8,6 +8,7 @@ * todo: allow simulation of specific atmos instead of just RESERVED_TURF_TYPe */ /datum/component/reservation_border + can_transfer = TRUE var/atom/movable/mirage_border/holder1 var/atom/movable/mirage_border/holder2 var/atom/movable/mirage_border/holder3 diff --git a/code/game/atoms/movable/movable.dm b/code/game/atoms/movable/movable.dm index ef9da3be942..8efb1632f1e 100644 --- a/code/game/atoms/movable/movable.dm +++ b/code/game/atoms/movable/movable.dm @@ -231,52 +231,6 @@ if(mover.loc in locs) . = TRUE -/atom/movable/proc/touch_map_edge() - if(z in (LEGACY_MAP_DATUM).sealed_levels) - return - - if((LEGACY_MAP_DATUM).use_overmap) - overmap_spacetravel(get_turf(src), src) - return - - var/move_to_z = src.get_transit_zlevel() - if(move_to_z) - var/new_z = move_to_z - var/new_x - var/new_y - - if(x <= TRANSITIONEDGE) - new_x = world.maxx - TRANSITIONEDGE - 2 - new_y = rand(TRANSITIONEDGE + 2, world.maxy - TRANSITIONEDGE - 2) - - else if (x >= (world.maxx - TRANSITIONEDGE + 1)) - new_x = TRANSITIONEDGE + 1 - new_y = rand(TRANSITIONEDGE + 2, world.maxy - TRANSITIONEDGE - 2) - - else if (y <= TRANSITIONEDGE) - new_y = world.maxy - TRANSITIONEDGE -2 - new_x = rand(TRANSITIONEDGE + 2, world.maxx - TRANSITIONEDGE - 2) - - else if (y >= (world.maxy - TRANSITIONEDGE + 1)) - new_y = TRANSITIONEDGE + 1 - new_x = rand(TRANSITIONEDGE + 2, world.maxx - TRANSITIONEDGE - 2) - - if(SSticker && istype(SSticker.mode, /datum/game_mode/nuclear)) // Only really care if the game mode is nuclear - var/datum/game_mode/nuclear/G = SSticker.mode - G.check_nuke_disks() - - var/turf/T = locate(new_x, new_y, new_z) - if(istype(T)) - forceMove(T) - -//by default, transition randomly to another zlevel -/atom/movable/proc/get_transit_zlevel() - var/list/candidates = SSmapping.crosslinked_levels() - candidates -= z - if(!length(candidates)) - return - return pick(candidates) - // Returns the current scaling of the sprite. // Note this DOES NOT measure the height or width of the icon, but returns what number is being multiplied with to scale the icons, if any. /atom/movable/proc/get_icon_scale_x() diff --git a/code/game/gamemodes/events/dust.dm b/code/game/gamemodes/events/dust.dm index 4cc3660bdef..0b6aa3cb0e1 100644 --- a/code/game/gamemodes/events/dust.dm +++ b/code/game/gamemodes/events/dust.dm @@ -84,9 +84,6 @@ The "dust" will damage the hull of the station causin minor hull breaches. walk(src, 0) // Because we might have called walk_towards, we must stop the walk loop or BYOND keeps an internal reference to us forever. return ..() -/obj/effect/space_dust/touch_map_edge() - qdel(src) - /obj/effect/space_dust/Bump(atom/A) . = ..() hit(A) diff --git a/code/game/machinery/nuclear_bomb.dm b/code/game/machinery/nuclear_bomb.dm index 2cd56489cbd..d7f7a571d1d 100644 --- a/code/game/machinery/nuclear_bomb.dm +++ b/code/game/machinery/nuclear_bomb.dm @@ -423,6 +423,3 @@ var/bomb_set log_game("[src], the last authentication disk, has been destroyed. Spawning [D] at ([D.x], [D.y], [D.z]).") nuke_disks -= src return ..() - -/obj/item/disk/nuclear/touch_map_edge() - qdel(src) diff --git a/code/game/mecha/combat/fighter.dm b/code/game/mecha/combat/fighter.dm index 8080722b351..dcfe0d5392d 100644 --- a/code/game/mecha/combat/fighter.dm +++ b/code/game/mecha/combat/fighter.dm @@ -61,77 +61,6 @@ . = ..() consider_gravity() -//We don't get lost quite as easy. -/obj/mecha/combat/fighter/touch_map_edge() - //No overmap enabled or no driver to choose - if(!(LEGACY_MAP_DATUM).use_overmap || !occupant || !can_ztravel()) - return ..() - - var/obj/overmap/entity/visitable/our_ship = get_overmap_sector(z) - - //We're not on the overmap - if(!our_ship) - return ..() - - //Stored for safety checking after user input - var/this_x = x - var/this_y = y - var/this_z = z - var/this_occupant = occupant - - var/what_edge - - var/new_x - var/new_y - var/new_z - - if(x <= TRANSITIONEDGE) - what_edge = WEST - new_x = world.maxx - TRANSITIONEDGE - 2 - new_y = rand(TRANSITIONEDGE + 2, world.maxy - TRANSITIONEDGE - 2) - - else if (x >= (world.maxx - TRANSITIONEDGE + 1)) - what_edge = EAST - new_x = TRANSITIONEDGE + 1 - new_y = rand(TRANSITIONEDGE + 2, world.maxy - TRANSITIONEDGE - 2) - - else if (y <= TRANSITIONEDGE) - what_edge = SOUTH - new_y = world.maxy - TRANSITIONEDGE -2 - new_x = rand(TRANSITIONEDGE + 2, world.maxx - TRANSITIONEDGE - 2) - - else if (y >= (world.maxy - TRANSITIONEDGE + 1)) - what_edge = NORTH - new_y = TRANSITIONEDGE + 1 - new_x = rand(TRANSITIONEDGE + 2, world.maxx - TRANSITIONEDGE - 2) - - var/list/choices = list() - for(var/obj/overmap/entity/visitable/V in range(1, our_ship)) - choices[V.name] = V - - var/choice = input("Choose an overmap destination:", "Destination", null) as null|anything in choices - if(!choice) - var/backwards = turn(what_edge, 180) - forceMove(get_step(src,backwards)) //Move them back a step, then. - setDir(backwards) - return - else - var/obj/overmap/entity/visitable/V = choices[choice] - if(occupant != this_occupant || this_x != x || this_y != y || this_z != z || get_dist(V,our_ship) > 1) //Sanity after user input - to_chat(occupant, "You or they appear to have moved!") - return - var/list/levels = V.get_space_zlevels() - if(!levels.len) - to_chat(occupant, "You don't appear to be able to get there from here!") - return - new_z = pick(levels) - var/turf/destination = locate(new_x, new_y, new_z) - if(!destination || destination.density) - to_chat(occupant, "You don't appear to be able to get there from here! Is it blocked?") - return - else - forceMove(destination) - //Modified phazon code /obj/mecha/combat/fighter/Topic(href, href_list) ..() diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm index 88fa14d618b..1b2459a30cb 100644 --- a/code/game/turfs/space/space.dm +++ b/code/game/turfs/space/space.dm @@ -36,17 +36,6 @@ // we have parallax and don't need this anymore // icon_state = SPACE_ICON_STATE(x, y, z) - // We might be an edge - if(y == world.maxy || forced_dirs & NORTH) - edge |= NORTH - else if(y == 1 || forced_dirs & SOUTH) - edge |= SOUTH - - if(x == 1 || forced_dirs & WEST) - edge |= WEST - else if(x == world.maxx || forced_dirs & EAST) - edge |= EAST - if (CONFIG_GET(flag/starlight)) update_starlight() @@ -163,16 +152,6 @@ // If that's changed, then you'll want to swipe the rest of the roofing code from code/game/turfs/simulated/floor_attackby.dm return -/turf/space/Entered(var/atom/movable/A) - . = ..() - - if(edge) - addtimer(CALLBACK(src, PROC_REF(on_atom_edge_touch), A), 0) - -/turf/space/proc/on_atom_edge_touch(atom/movable/AM) - if(!QDELETED(AM) && (AM.loc == src)) - AM.touch_map_edge() - //// Special variants used in various maps //// diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index cb878a2e71b..363d9c100b0 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -155,6 +155,7 @@ var/list/admin_verbs_spawn = list( /client/proc/virus2_editor, /client/proc/map_template_load, /client/proc/map_template_upload, + // /client/proc/overmap_upload, /client/proc/map_template_load_on_new_z ) diff --git a/code/modules/mapping/map.dm b/code/modules/mapping/map.dm index 256ef2e647e..4d0afdb101a 100644 --- a/code/modules/mapping/map.dm +++ b/code/modules/mapping/map.dm @@ -252,7 +252,6 @@ var/use_overmap = 0 // If overmap should be used (including overmap space travel override) var/overmap_size = 20 // Dimensions of overmap zlevel if overmap is used. - var/overmap_z = 0 // If 0 will generate overmap zlevel on init. Otherwise will populate the zlevel provided. var/overmap_event_areas = 0 // How many event "clouds" will be generated /// list of title cutscreens by path to display. for legacy support, tuples of list(icon, state) work too. associate to % chance, defaulting to 1. diff --git a/code/modules/mapping/turf_reservation.dm b/code/modules/mapping/turf_reservation.dm index cf626310bad..5404480cfd0 100644 --- a/code/modules/mapping/turf_reservation.dm +++ b/code/modules/mapping/turf_reservation.dm @@ -10,9 +10,12 @@ /datum/turf_reservation /// are we allocated? var/tmp/allocated = FALSE - /// reserved turfs - set when allocated - var/list/turf/reserved_turfs /// border turfs - just the first layer / the immediate border + /// + /// todo: this shouldn't be a var, make it a proc + /// + /// * does not include the rest of the border + /// * you shouldn't need to initialize more than one layer of turfs. var/list/turf/border_turfs /// width @@ -33,6 +36,7 @@ /// callback to use when something crosses border /// + /// * called with (turf/border) /// * only used if border is custom-initalized, otherwise we use selflooping transition borders /// * specifying this makes us put a reservation border component on the turfs as needed. var/datum/callback/border_handler @@ -40,6 +44,7 @@ var/border_mirage_anyways = FALSE /// border initializer to call with every turf on the border to init them /// + /// * called with (turf/border, datum/turf_reservation/reservation) /// * if border is specified but initializer isn't, we just make them transition borders. var/datum/callback/border_initializer @@ -50,6 +55,8 @@ /// our border area instance if needed var/area/reservation_border/border_area + /// our area instance + var/area/reservation_area //* spatial lookup *// var/spatial_bl_x @@ -81,7 +88,6 @@ ), locate( top_right_coords[1], top_right_coords[2], top_right_coords[3]) )) - reserved_turfs = null allocated = FALSE if(border_area) QDEL_NULL(border_area) @@ -100,6 +106,10 @@ spatial_bl_x = spatial_tr_x = spatial_bl_y = spatial_tr_y = spatial_z = null + if(!reservation_area.unique) + qdel(reservation_area) + reservation_area = null + return TRUE /datum/turf_reservation/proc/reserve(width, height, border, z_override) @@ -170,7 +180,7 @@ // calculate non-bordered BL = locate(1 + TURF_CHUNK_RESOLUTION * (outer_x - 1) + border, 1 + TURF_CHUNK_RESOLUTION * (outer_y - 1) + border, level_index) - TR = locate(BL.x + real_width - 1 - border, BL.y + real_height - 1 - border, BL.z) + TR = locate(BL.x + width - 1, BL.y + height - 1, level_index) final = block(BL, TR) // calculate border @@ -261,7 +271,7 @@ locate(bottom_left_coords[1] - 1, top_right_coords[2], bottom_left_coords[3]), ) for(var/turf/T as anything in immediate_left) - border_initializer?.Invoke(T) + border_initializer?.Invoke(T, src) if(needs_component) T.AddComponent(/datum/component/reservation_border, mirage_range, WEST, should_mirage, locate(top_right_coords[1], T.y, T.z), border_handler) // right @@ -270,7 +280,7 @@ locate(top_right_coords[1] + 1, top_right_coords[2], bottom_left_coords[3]), ) for(var/turf/T as anything in immediate_right) - border_initializer?.Invoke(T) + border_initializer?.Invoke(T, src) if(needs_component) T.AddComponent(/datum/component/reservation_border, mirage_range, EAST, should_mirage, locate(bottom_left_coords[1], T.y, T.z), border_handler) // up @@ -279,7 +289,7 @@ locate(top_right_coords[1], top_right_coords[2] + 1, bottom_left_coords[3]), ) for(var/turf/T as anything in immediate_up) - border_initializer?.Invoke(T) + border_initializer?.Invoke(T, src) if(needs_component) T.AddComponent(/datum/component/reservation_border, mirage_range, NORTH, should_mirage, locate(T.x, bottom_left_coords[2], T.z), border_handler) // down @@ -288,7 +298,7 @@ locate(top_right_coords[1], bottom_left_coords[2] - 1, bottom_left_coords[3]), ) for(var/turf/T as anything in immediate_down) - border_initializer?.Invoke(T) + border_initializer?.Invoke(T, src) if(needs_component) T.AddComponent(/datum/component/reservation_border, mirage_range, SOUTH, should_mirage, locate(T.x, top_right_coords[2], T.z), border_handler) @@ -296,25 +306,25 @@ var/turf/corner // top left corner = locate(bottom_left_coords[1] - 1, top_right_coords[2] + 1, bottom_left_coords[3]) - border_initializer?.Invoke(corner) + border_initializer?.Invoke(corner, src) if(needs_component) corner.AddComponent(/datum/component/reservation_border, mirage_range, NORTHWEST, should_mirage, locate(top_right_coords[1], bottom_left_coords[2], bottom_left_coords[3]), border_handler) immediate_corners += corner // top right corner = locate(top_right_coords[1] + 1, top_right_coords[2] + 1, bottom_left_coords[3]) - border_initializer?.Invoke(corner) + border_initializer?.Invoke(corner, src) if(needs_component) corner.AddComponent(/datum/component/reservation_border, mirage_range, NORTHEAST, should_mirage, locate(bottom_left_coords[1], bottom_left_coords[2], bottom_left_coords[3]), border_handler) immediate_corners += corner // bottom left corner = locate(bottom_left_coords[1] - 1, bottom_left_coords[2] - 1, bottom_left_coords[3]) - border_initializer?.Invoke(corner) + border_initializer?.Invoke(corner, src) if(needs_component) corner.AddComponent(/datum/component/reservation_border, mirage_range, SOUTHWEST, should_mirage, locate(top_right_coords[1], top_right_coords[2], bottom_left_coords[3]), border_handler) immediate_corners += corner // bottom right corner = locate(top_right_coords[1] + 1, bottom_left_coords[2] - 1, bottom_left_coords[3]) - border_initializer?.Invoke(corner) + border_initializer?.Invoke(corner, src) if(needs_component) corner.AddComponent(/datum/component/reservation_border, mirage_range, SOUTHEAST, should_mirage, locate(bottom_left_coords[1], top_right_coords[2], bottom_left_coords[3]), border_handler) immediate_corners += corner @@ -329,7 +339,7 @@ // todo: area.assimilate_turfs? area_instance.contents.Add(final) - src.reserved_turfs = final.Copy() + src.reservation_area = area_instance src.width = width src.height = height src.border = border @@ -356,6 +366,34 @@ return TRUE +/** + * gets an unordered list of all inner (non-border) turfs + */ +/datum/turf_reservation/proc/unordered_inner_turfs() + return block( + locate(bottom_left_coords[1], bottom_left_coords[2], bottom_left_coords[3]), + locate(top_right_coords[1], top_right_coords[2], top_right_coords[3]), + ) + +/** + * gets an unordered list of all outer (border) turfs + */ +/datum/turf_reservation/proc/unordered_border_turfs() + if(!border) + return list() + return border_turfs.Copy() + +/** + * gets an unordered list of all immediate (1-outside) turfs + */ +/datum/turf_reservation/proc/unordered_immediate_border_turfs() + if(!border) + return list() + // todo: implement this + CRASH("unimplemented") + +//* Reservation Border Area *// + /area/reservation_border name = "Reservation Border Area" unique = FALSE diff --git a/code/modules/media/mediamanager.dm b/code/modules/media/mediamanager.dm index edc2ed313d1..2d16ae5348c 100644 --- a/code/modules/media/mediamanager.dm +++ b/code/modules/media/mediamanager.dm @@ -35,7 +35,8 @@ // Update when moving between areas. // TODO - While this direct override might technically be faster, probably better code to use observer or hooks ~Leshana -/area/Entered(var/mob/living/M) +/area/Entered(atom/movable/AM, atom/oldLoc) + var/mob/M = AM // Note, we cannot call ..() first, because it would update lastarea. if(!istype(M)) return ..() diff --git a/code/modules/overmap/entity/entity.dm b/code/modules/overmap/entity/entity.dm index 6e34bc6ec61..77b8fa97fec 100644 --- a/code/modules/overmap/entity/entity.dm +++ b/code/modules/overmap/entity/entity.dm @@ -4,13 +4,17 @@ * overmap objects capable of motion */ /obj/overmap/entity - //* identity + //* identity *// /// id var/id /// next id var/static/id_next = 0 - //* physics + //* overmap *// + /// if we're currently in an overmap; if so, which? + var/datum/overmap/overmap + + //* physics *// /// velocity x in overmap units per second var/vel_x /// velocity y in overmap units per second @@ -23,6 +27,10 @@ var/max_speed = OVERMAP_DISTANCE_TILE /// is moving var/tmp/is_moving = FALSE + /// is forced moving + /// + /// todo: reevaluate if this is the right way to perform forced movements like wrapping. + var/tmp/is_forced_moving = FALSE /obj/overmap/entity/New() // assign id immediately @@ -31,16 +39,20 @@ /obj/overmap/entity/Initialize(mapload) . = ..() + // init physics initialize_physics() update_velocity_ticking() + // add to spatial grid + AddComponent(/datum/component/spatial_grid, SSspatial_grids.overmap_entities) /obj/overmap/entity/Destroy() + // stop physics deactivate_physics() return ..() /obj/overmap/entity/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change) . = ..() - if(!isturf(old_loc) || forced) + if(!isturf(old_loc) || (forced && !is_forced_moving)) initialize_physics() /obj/overmap/entity/vv_edit_var(var_name, var_value, mass_edit, raw_edit) @@ -52,3 +64,15 @@ set_velocity(vy = var_value) return TRUE return ..() + +/** + * called when we join an overmap + */ +/obj/overmap/entity/proc/on_overmap_join(datum/overmap/map) + src.overmap = map + +/** + * called when we leave an overmap + */ +/obj/overmap/entity/proc/on_overmap_leave(datum/overmap/map) + src.overmap = map diff --git a/code/modules/overmap/entity/physics.dm b/code/modules/overmap/entity/physics.dm index 208d0160b28..adbd1e2b429 100644 --- a/code/modules/overmap/entity/physics.dm +++ b/code/modules/overmap/entity/physics.dm @@ -1,5 +1,7 @@ /** * (re)initialize physics + * + * always sets us back to a non-ticking state */ /obj/overmap/entity/proc/initialize_physics() deactivate_physics() @@ -16,6 +18,8 @@ physics_tick(delta_time) /obj/overmap/entity/proc/physics_tick(dt) + if(!overmap) + return // what are we doing // todo: proper overmaps physics, take diff from overmap south/west var/new_position_x = pos_x + vel_x * dt var/new_position_y = pos_y + vel_y * dt @@ -37,9 +41,25 @@ if(new_loc != loc) var/turf/old_loc = loc - if(!Move(new_loc, NORTH, dt * 10)) - initialize_physics() // for athena's event - return + var/jumping = FALSE + if(istype(new_loc, /turf/overmap/edge)) + var/turf/overmap/edge/edge = new_loc + new_loc = edge.get_wrap_counterpart() + jumping = TRUE + pos_x += edge.wrap_sign_x * OVERMAP_DISTANCE_TILE * overmap.width + pos_y += edge.wrap_sign_y * OVERMAP_DISTANCE_TILE * overmap.height + if(jumping) + is_forced_moving = TRUE + forceMove(new_loc) + is_forced_moving = FALSE + else if(get_dist(loc, new_loc) == 1) + if(!Move(new_loc, NORTH, dt * 10)) + initialize_physics() + return + else + message_admins(SPAN_DANGER("overmap entity attempted to perform an illegal move ([src]); please check logs. halting movement of affected entity.")) + initialize_physics() + CRASH("attempted to move not one tile but also while not jumping") if(get_dist(old_loc, loc) > 1) pixel_x = new_pixel_x pixel_y = new_pixel_y @@ -59,7 +79,7 @@ /obj/overmap/entity/proc/set_velocity(vx, vy) if(!isnull(vx)) vel_x = vx - if(isnull(vy)) + if(!isnull(vy)) vel_y = vy if(!is_moving && (QUANTIZE_OVERMAP_DISTANCE(vel_x) || QUANTIZE_OVERMAP_DISTANCE(vel_y))) @@ -92,8 +112,30 @@ /obj/overmap/entity/proc/is_moving() return QUANTIZE_OVERMAP_DISTANCE(vel_x) || QUANTIZE_OVERMAP_DISTANCE(vel_y) +//* Getters *// + +/** + * gets our tile X on overmap + * + * @return 0 if not on overmap + */ +/obj/overmap/entity/proc/get_tile_x() + if(!overmap) + return 0 + return x - overmap.lower_left_x + 1 + +/** + * gets our tile Y on overmap + * + * @return 0 if not on overmap + */ +/obj/overmap/entity/proc/get_tile_y() + if(!overmap) + return 0 + return y - overmap.lower_left_y + 1 + /** - * gets our movement (non-angular) speed + * gets our movement (non-angular) speed in overmaps units per second */ /obj/overmap/entity/proc/get_speed() return sqrt(vel_x ** 2 + vel_y ** 2) diff --git a/code/modules/overmap/events/event_handler.dm b/code/modules/overmap/events/event_handler.dm index d629abe683e..d153de1d413 100644 --- a/code/modules/overmap/events/event_handler.dm +++ b/code/modules/overmap/events/event_handler.dm @@ -9,66 +9,6 @@ GLOBAL_DATUM_INIT(overmap_event_handler, /singleton/overmap_event_handler, new) hazard_by_turf = list() ship_events = list() -// Populates overmap with random events! Should be called once at startup at some point. -/singleton/overmap_event_handler/proc/create_events(var/z_level, var/overmap_size, var/number_of_events) - // Acquire the list of not-yet utilized overmap turfs on this Z-level - var/list/overmap_turfs = block(locate(OVERMAP_EDGE, OVERMAP_EDGE, z_level), locate(overmap_size - OVERMAP_EDGE, overmap_size - OVERMAP_EDGE, z_level)) - var/list/candidate_turfs = list() - for(var/Trf in overmap_turfs) - var/turf/T = Trf - if(!(locate(/obj/overmap/entity/visitable) in T)) - candidate_turfs += T - - for(var/i = 1 to number_of_events) - if(!candidate_turfs.len) - break - var/overmap_event_type = pick(subtypesof(/datum/overmap_event)) - var/datum/overmap_event/datum_spawn = new overmap_event_type - log_debug(SPAN_DEBUGINFO("Generating cloud of [datum_spawn.count] [datum_spawn] overmap event hazards")) - - var/list/event_turfs = acquire_event_turfs(datum_spawn.count, datum_spawn.radius, candidate_turfs, datum_spawn.continuous) - candidate_turfs -= event_turfs - - for(var/event_turf in event_turfs) - var/type = pick(datum_spawn.hazards) - new type(event_turf) - - qdel(datum_spawn) // IDK help how do I do this better? - -/singleton/overmap_event_handler/proc/acquire_event_turfs(var/number_of_turfs, var/distance_from_origin, var/list/candidate_turfs, var/continuous = TRUE) - number_of_turfs = min(number_of_turfs, candidate_turfs.len) - candidate_turfs = candidate_turfs.Copy() // Not this proc's responsibility to adjust the given lists - - var/origin_turf = pick(candidate_turfs) - var/list/selected_turfs = list(origin_turf) - var/list/selection_turfs = list(origin_turf) - candidate_turfs -= origin_turf - - while(selection_turfs.len && selected_turfs.len < number_of_turfs) - var/selection_turf = pick(selection_turfs) - var/random_neighbour = get_random_neighbour(selection_turf, candidate_turfs, continuous, distance_from_origin) - - if(random_neighbour) - candidate_turfs -= random_neighbour - selected_turfs += random_neighbour - if(get_dist(origin_turf, random_neighbour) < distance_from_origin) - selection_turfs += random_neighbour - else - selection_turfs -= selection_turf - - return selected_turfs - -/singleton/overmap_event_handler/proc/get_random_neighbour(var/turf/origin_turf, var/list/candidate_turfs, var/continuous = TRUE, var/range) - var/fitting_turfs - if(continuous) - fitting_turfs = origin_turf.CardinalTurfs(FALSE) - else - fitting_turfs = trange(range, origin_turf) - fitting_turfs = shuffle(fitting_turfs) - for(var/turf/T in fitting_turfs) - if(T in candidate_turfs) - return T - /singleton/overmap_event_handler/proc/start_hazard(var/obj/overmap/entity/visitable/ship/ship, var/obj/overmap/tiled/hazard/hazard) // Make these accept both hazards or events if(!(ship in ship_events)) ship_events += ship diff --git a/code/modules/overmap/legacy/sectors.dm b/code/modules/overmap/legacy/sectors.dm index 608619913ac..a963b4d77b4 100644 --- a/code/modules/overmap/legacy/sectors.dm +++ b/code/modules/overmap/legacy/sectors.dm @@ -44,32 +44,32 @@ find_z_levels() // This populates map_z and assigns z levels to the ship. register_z_levels() // This makes external calls to update global z level information. - ASSERT((LEGACY_MAP_DATUM).overmap_z) - - start_x = start_x || rand(OVERMAP_EDGE, (LEGACY_MAP_DATUM).overmap_size - OVERMAP_EDGE) - start_y = start_y || rand(OVERMAP_EDGE, (LEGACY_MAP_DATUM).overmap_size - OVERMAP_EDGE) - - forceMove(locate(start_x, start_y, (LEGACY_MAP_DATUM).overmap_z)) - docking_codes = "[ascii2text(rand(65,90))][ascii2text(rand(65,90))][ascii2text(rand(65,90))][ascii2text(rand(65,90))]" - testing("Located sector \"[name]\" at [start_x],[start_y], containing Z [english_list(map_z)]") + // todo: This is shitcode but sue me tbh we gotta refactor this shit anyways to be overmap_initializer's + spawn(-1) + var/datum/overmap/legacy_bind_overmap = SSovermaps.get_or_load_default_overmap() + var/turf/where_to_go = free_overmap_space(legacy_bind_overmap) + start_x = where_to_go.x + start_y = where_to_go.y - LAZYADD(SSshuttle.sectors_to_initialize, src) //Queued for further init. Will populate the waypoint lists; waypoints not spawned yet will be added in as they spawn. - SSshuttle.process_init_queues() + forceMove(where_to_go) + testing("Located sector \"[name]\" at [start_x],[start_y], containing Z [english_list(map_z)]") - if(known) - plane = ABOVE_LIGHTING_PLANE - for(var/obj/machinery/computer/ship/helm/H in GLOB.machines) - H.get_known_sectors() - else - real_appearance = image(icon, src, icon_state) - real_appearance.override = TRUE - name = unknown_name - icon_state = unknown_state - color = null - desc = "Scan this to find out more information." + if(known) + plane = ABOVE_LIGHTING_PLANE + for(var/obj/machinery/computer/ship/helm/H in GLOB.machines) + H.get_known_sectors() + else + real_appearance = image(icon, src, icon_state) + real_appearance.override = TRUE + name = unknown_name + icon_state = unknown_state + color = null + desc = "Scan this to find out more information." + LAZYADD(SSshuttle.sectors_to_initialize, src) //Queued for further init. Will populate the waypoint lists; waypoints not spawned yet will be added in as they spawn. + SSshuttle.process_init_queues() // You generally shouldn't destroy these. /obj/overmap/entity/visitable/Destroy() @@ -222,25 +222,18 @@ priority_announcement.Announce(message, new_title = "Automated Distress Signal", new_sound = 'sound/AI/sos.ogg', zlevel = -1) -/proc/build_overmap() - if(!(LEGACY_MAP_DATUM).use_overmap) - return 1 - - ASSERT(!(LEGACY_MAP_DATUM).overmap_z) - testing("Building overmap...") - (LEGACY_MAP_DATUM).overmap_z = SSmapping.allocate_level().z_index - - testing("Putting overmap on [(LEGACY_MAP_DATUM).overmap_z]") - var/area/overmap/A = new - for (var/square in block(locate(1,1,(LEGACY_MAP_DATUM).overmap_z), locate((LEGACY_MAP_DATUM).overmap_size,(LEGACY_MAP_DATUM).overmap_size,(LEGACY_MAP_DATUM).overmap_z))) - var/turf/T = square - if(T.x == 1 || T.y == 1 || T.x == (LEGACY_MAP_DATUM).overmap_size || T.y == (LEGACY_MAP_DATUM).overmap_size) - T = T.ChangeTurf(/turf/overmap/edge) - else - T = T.ChangeTurf(/turf/overmap) - ChangeArea(T, A) - - (LEGACY_MAP_DATUM).sealed_levels |= (LEGACY_MAP_DATUM).overmap_z - - testing("Overmap build complete.") - return 1 +/obj/overmap/entity/visitable/proc/free_overmap_space(datum/overmap/map) + var/list/turf/potential_turfs = map.reservation.unordered_inner_turfs() + var/safety = 1000 + var/turf/potential + while((potential = pick_n_take(potential_turfs))) + if(length(potential.contents)) + // something already here + continue + if(safety-- < 0) + stack_trace("safety ran out, that shouldn't really happen but okay") + break + break + if(!potential) + potential = locate(map.lower_left_x, map.lower_left_y, map.reservation.bottom_left_coords[3]) + return potential diff --git a/code/modules/overmap/legacy/ships/computers/helm.dm b/code/modules/overmap/legacy/ships/computers/helm.dm index cbd8d4cfaa1..c7ccf8a01be 100644 --- a/code/modules/overmap/legacy/ships/computers/helm.dm +++ b/code/modules/overmap/legacy/ships/computers/helm.dm @@ -54,14 +54,14 @@ GLOBAL_LIST_EMPTY(all_waypoints) if (S.known) var/datum/computer_file/data/waypoint/R = new() R.fields["name"] = S.name - R.fields["x"] = S.x - R.fields["y"] = S.y + R.fields["x"] = S.get_tile_x() + R.fields["y"] = S.get_tile_y() known_sectors[S.name] = R /obj/machinery/computer/ship/helm/process(delta_time) ..() if(autopilot && dx && dy && !autopilot_disabled) - var/turf/T = locate(dx,dy,(LEGACY_MAP_DATUM).overmap_z) + var/turf/T = locate(dx, dy, linked.z) if(linked.loc == T) if(!linked.is_moving()) autopilot = 0 @@ -104,8 +104,8 @@ GLOBAL_LIST_EMPTY(all_waypoints) data["sector"] = current_sector ? current_sector.name : "Deep Space" data["sector_info"] = current_sector ? current_sector.desc : "Not Available" data["landed"] = linked.get_landed_info() - data["s_x"] = linked.x - data["s_y"] = linked.y + data["s_x"] = linked.get_tile_x() + data["s_y"] = linked.get_tile_y() data["dest"] = dy && dx data["d_x"] = dx data["d_y"] = dy @@ -166,13 +166,13 @@ GLOBAL_LIST_EMPTY(all_waypoints) return TRUE switch(params["add"]) if("current") - R.fields["x"] = linked.x - R.fields["y"] = linked.y + R.fields["x"] = linked.get_tile_x() + R.fields["y"] = linked.get_tile_y() if("new") - var/newx = input("Input new entry x coordinate", "Coordinate input", linked.x) as num + var/newx = input("Input new entry x coordinate", "Coordinate input", linked.get_tile_x()) as num if(ui_status(usr, ui.state) != UI_INTERACTIVE) return TRUE - var/newy = input("Input new entry y coordinate", "Coordinate input", linked.y) as num + var/newy = input("Input new entry y coordinate", "Coordinate input", linked.get_tile_y()) as num if(ui_status(usr, ui.state) != UI_INTERACTIVE) return FALSE R.fields["x"] = clamp(newx, 1, world.maxx) diff --git a/code/modules/overmap/legacy/spacetravel.dm b/code/modules/overmap/legacy/spacetravel.dm deleted file mode 100644 index e28e4a88668..00000000000 --- a/code/modules/overmap/legacy/spacetravel.dm +++ /dev/null @@ -1,157 +0,0 @@ -// List used to cache empty zlevels to avoid nedless map bloat -var/list/cached_space = list() - -// Space stragglers go here - -/obj/overmap/entity/visitable/sector/temporary - name = "Deep Space" - invisibility = 101 - known = 0 - -/obj/overmap/entity/visitable/sector/temporary/New(var/nx, var/ny, var/nz) - loc = locate(nx, ny, (LEGACY_MAP_DATUM).overmap_z) - x = nx - y = ny - map_z += nz - map_sectors["[nz]"] = src - testing("Temporary sector at [x],[y] was created, corresponding zlevel is [nz].") - -/obj/overmap/entity/visitable/sector/temporary/Destroy() - map_sectors["[map_z]"] = null - testing("Temporary sector at [x],[y] was deleted.") - return ..() - -/obj/overmap/entity/visitable/sector/temporary/proc/can_die(var/mob/observer) - testing("Checking if sector at [map_z[1]] can die.") - for(var/mob/M in global.GLOB.player_list) - if(M != observer && (M.z in map_z)) - testing("There are people on it.") - return 0 - return 1 - -/proc/get_deepspace(x, y) - var/turf/overmap/overmap_turf = locate(x,y,(LEGACY_MAP_DATUM).overmap_z) - if(!istype(overmap_turf)) - CRASH("Attempt to get deepspace at ([x],[y]) which is not on overmap: [overmap_turf]") - var/obj/overmap/entity/visitable/sector/temporary/res = locate() in overmap_turf - if(istype(res)) - return res - else if(cached_space.len) - res = cached_space[cached_space.len] - cached_space -= res - res.forceMove(overmap_turf) - return res - else - return new /obj/overmap/entity/visitable/sector/temporary(x, y, (LEGACY_MAP_DATUM).get_empty_zlevel()) - -/atom/movable/proc/lost_in_space() - for(var/atom/movable/AM in contents) - if(!AM.lost_in_space()) - return FALSE - if(has_buckled_mobs()) - for(var/mob/M in buckled_mobs) - if(!M.lost_in_space()) - return FALSE - - return TRUE - -/* -/obj/item/uav/lost_in_space() - if(state == 1) - return FALSE - return ..() -*/ - -/obj/machinery/power/supermatter/lost_in_space() - return FALSE - -/obj/singularity/lost_in_space() - return FALSE - -/obj/vehicle_old/lost_in_space() - if(load && !load.lost_in_space()) - return FALSE - return ..() - -/mob/lost_in_space() - return isnull(client) - -/mob/observer/lost_in_space() // heeyyyyyy buddy can we not :) - return FALSE - -/mob/living/carbon/human/lost_in_space() - return FALSE - // return isnull(client) && !key && stat == DEAD // Allows bodies that players have ghosted from to be deleted - Ater - -/proc/overmap_spacetravel(turf/space/T, atom/movable/A) - if (!T || !A) - return - - var/obj/overmap/entity/visitable/M = get_overmap_sector(T.z) - if (!M) - return - - // Is the landmark still on the map. - if(!isturf(M.loc)) - return - - // Don't let AI eyes yeet themselves off the map - if(istype(A, /mob/observer/eye)) - return - - if(A.lost_in_space()) - if(!QDELETED(A)) - qdel(A) - return - - var/nx = 1 - var/ny = 1 - var/nz = 1 - - if(T.x <= TRANSITIONEDGE) - nx = world.maxx - TRANSITIONEDGE - 2 - ny = rand(TRANSITIONEDGE + 2, world.maxy - TRANSITIONEDGE - 2) - - else if (A.x >= (world.maxx - TRANSITIONEDGE - 1)) - nx = TRANSITIONEDGE + 2 - ny = rand(TRANSITIONEDGE + 2, world.maxy - TRANSITIONEDGE - 2) - - else if (T.y <= TRANSITIONEDGE) - ny = world.maxy - TRANSITIONEDGE -2 - nx = rand(TRANSITIONEDGE + 2, world.maxx - TRANSITIONEDGE - 2) - - else if (A.y >= (world.maxy - TRANSITIONEDGE - 1)) - ny = TRANSITIONEDGE + 2 - nx = rand(TRANSITIONEDGE + 2, world.maxx - TRANSITIONEDGE - 2) - - nz = SAFEPICK(M.map_z) - if(!isnull(nz)) - A.forceMove(locate(nx, ny, nz)) - return - - testing("[A] spacemoving from [M] ([M.x], [M.y]).") - - var/turf/map = locate(M.x,M.y,(LEGACY_MAP_DATUM).overmap_z) - var/obj/overmap/entity/visitable/TM - for(var/obj/overmap/entity/visitable/O in map) - if(O != M && O.in_space && prob(50)) - TM = O - break - if(!TM) - TM = get_deepspace(M.x,M.y) - nz = pick(TM.get_space_zlevels()) - - var/turf/dest = locate(nx,ny,nz) - if(istype(dest)) - A.forceMove(dest) - if(ismob(A)) - var/mob/D = A - if(D.pulling) - D.pulling.forceMove(dest) - - if(istype(M, /obj/overmap/entity/visitable/sector/temporary)) - var/obj/overmap/entity/visitable/sector/temporary/source = M - if (source.can_die()) - testing("Caching [M] for future use") - source.moveToNullspace() - cached_space += source diff --git a/code/modules/overmap/map/area.dm b/code/modules/overmap/map/area.dm index a69cf68a0ee..1861976dd8d 100644 --- a/code/modules/overmap/map/area.dm +++ b/code/modules/overmap/map/area.dm @@ -1,5 +1,35 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 silicons *// + +/** + * this is only on the turfs inside the overmap, + * not the turfs outside of it + */ /area/overmap - name = "System Map" + name = "Overmap Zone" + icon = 'icons/modules/overmap/area.dmi' + icon_state = "map" icon_state = "start" - requires_power = FALSE + // todo: sensor update dynamic_lighting = DYNAMIC_LIGHTING_FORCED + + /// our overmap + var/datum/overmap/overmap + +/area/overmap/Destroy() + overmap = null + return ..() + +/area/overmap/Entered(atom/movable/AM, atom/oldLoc) + . = ..() + if(!istype(AM, /obj/overmap/entity)) + return + var/obj/overmap/entity/entity = AM + entity.on_overmap_join(overmap) + +/area/overmap/Exited(atom/movable/AM, atom/oldLoc) + . = ..() + if(!istype(AM, /obj/overmap/entity)) + return + var/obj/overmap/entity/entity = AM + entity.on_overmap_leave(overmap) diff --git a/code/modules/overmap/map/overmap.dm b/code/modules/overmap/map/overmap.dm new file mode 100644 index 00000000000..86012125629 --- /dev/null +++ b/code/modules/overmap/map/overmap.dm @@ -0,0 +1,94 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 silicons *// + +/datum/overmap + /// friendly name, if any; generated if not + var/name + /// unique id + var/id + /// width in tiles + var/width + /// height in tiles + var/height + /// cached for speed + var/lower_left_x + /// cached for speed + var/lower_left_y + /// cached for speed + var/upper_right_x + /// cached for speed + var/upper_right_y + /// our turf reservation + var/datum/turf_reservation/reservation + /// our template + var/datum/overmap_template/template + +/datum/overmap/New(id, datum/overmap_template/template) + src.id = id + src.template = template + +/** + * initializes an overmap from a template + */ +/datum/overmap/proc/initialize(datum/overmap_template/template = src.template) + ASSERT(!SSovermaps.overmap_by_id[id]) + + if(!template.initialized) + template.initialize() + + construct(template) + + allocate() + template.on_allocation(src) + + build(template) + template.on_allocation_initialized(src) + + SSovermaps.overmap_by_id[id] = src + return TRUE + +/** + * allocates our reservation block + */ +/datum/overmap/proc/allocate() + if(reservation) + CRASH("has reservation already") + // alloc a 1 tile border + reservation = SSmapping.request_block_reservation( + width, + height, + area_override = /area/overmap, + border = 1, + border_initializer = CALLBACK(src, PROC_REF(reservation_border_initializer)), + ) + lower_left_x = reservation.bottom_left_coords[1] + lower_left_y = reservation.bottom_left_coords[2] + upper_right_x = reservation.top_right_coords[1] + upper_right_y = reservation.top_right_coords[2] + var/area/overmap/created_area = reservation.reservation_area + created_area.overmap = src + return reservation + +/** + * constructs our parameters from template + */ +/datum/overmap/proc/construct(datum/overmap_template/template) + src.width = template.width + src.height = template.height + +/** + * builds and initializes our map, which is usually blank unless a template put stuff in. + */ +/datum/overmap/proc/build() + var/list/turf/map_turfs = reservation.unordered_inner_turfs() + for(var/turf/turf as anything in map_turfs) + var/turf/overmap/map/map_tile = turf.ChangeTurf(/turf/overmap/map) + map_tile.initialize_overmap(src) + + +/** + * makes a border turf + */ +/datum/overmap/proc/reservation_border_initializer(turf/border, datum/turf_reservation/reservation) + var/turf/overmap/edge/edge = border.ChangeTurf(/turf/overmap/edge) + edge.initialize_border(src, reservation) diff --git a/code/modules/overmap/map/overmap_template.dm b/code/modules/overmap/map/overmap_template.dm new file mode 100644 index 00000000000..62fe8789c6c --- /dev/null +++ b/code/modules/overmap/map/overmap_template.dm @@ -0,0 +1,67 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 silicons *// + +/** + * a template used to construct an overmap + */ +/datum/overmap_template + /// are we initialized? + var/initialized = FALSE + /// our width + var/width + /// our height + var/height + /// our layers + /// typepath to init + /// applied in order + var/list/layers = list() + +/datum/overmap_template/New(width, height, list/additional_layers) + src.width = width + src.height = height + if(additional_layers) + src.layers += additional_layers + +/** + * should be idempotent! + */ +/datum/overmap_template/proc/initialize() + for(var/index in 1 to length(layers)) + var/datum/overmap_template_layer/maybe_layer = layers[index] + if(istype(maybe_layer)) + continue + maybe_layer = new maybe_layer + layers[index] = maybe_layer + + initialized = TRUE + +/** + * called right after the turf reservation is allocated and initialized + */ +/datum/overmap_template/proc/on_allocation_initialized(datum/overmap/map) + for(var/datum/overmap_template_layer/layer as anything in layers) + layer.apply_to(map) + +/** + * called right after the turf reservation is allocated, but not initialized + */ +/datum/overmap_template/proc/on_allocation(datum/overmap/map) + return + +/** + * default + */ +/datum/overmap_template/legacy_default + width = 20 + height = 20 + + /// event clouds to spawn + var/event_clouds = 2 + +/datum/overmap_template/legacy_default/New(width, height, list/additional_layers, event_clouds) + ..() + src.event_clouds = event_clouds + +/datum/overmap_template/legacy_default/initialize() + layers += new /datum/overmap_template_layer/legacy_events(event_clouds) + return ..() diff --git a/code/modules/overmap/map/overmap_template_layer.dm b/code/modules/overmap/map/overmap_template_layer.dm new file mode 100644 index 00000000000..17ed788b15b --- /dev/null +++ b/code/modules/overmap/map/overmap_template_layer.dm @@ -0,0 +1,17 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 silicons *// + +/** + * generation layers + */ +/datum/overmap_template_layer + +/** + * apply to overmap + * + * * this doesn't have to be idempotent as of right now + * * this is called after the overmap is instanced, so this can't be previewed properly + * * this is called before anything is put on the overmap / build_map() is done + */ +/datum/overmap_template_layer/proc/apply_to(datum/overmap/map) + return TRUE diff --git a/code/modules/overmap/map/template_layers/legacy_events.dm b/code/modules/overmap/map/template_layers/legacy_events.dm new file mode 100644 index 00000000000..b113ccadf03 --- /dev/null +++ b/code/modules/overmap/map/template_layers/legacy_events.dm @@ -0,0 +1,78 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 silicons *// + +/** + * legacy seeded events + */ +/datum/overmap_template_layer/legacy_events + /// number of clouds + var/number_of_clouds = 2 + +/datum/overmap_template_layer/legacy_events/New(number_of_clouds) + if(!isnull(number_of_clouds)) + src.number_of_clouds = number_of_clouds + return ..() + +/datum/overmap_template_layer/legacy_events/apply_to(datum/overmap/map) + . = ..() + if(!.) + return + + var/list/turf/overmap_turfs = map.reservation.unordered_inner_turfs() + var/list/turf/candidate_turfs = list() + + for(var/turf/candidate as anything in overmap_turfs) + if(length(candidate.contents)) + continue + candidate_turfs += candidate + + for(var/i in 1 to number_of_clouds) + if(!length(candidate_turfs)) + break + var/event_type = pick(subtypesof(/datum/overmap_event)) + var/datum/overmap_event/datum_spawn = new event_type + + var/list/turf/event_turfs = get_cloud_turfs(datum_spawn.count, datum_spawn.radius, candidate_turfs, datum_spawn.continuous) + candidate_turfs -= event_turfs + + for(var/turf/event_turf as anything in event_turfs) + var/event_spawn_type = pick(datum_spawn.hazards) + new event_spawn_type(event_turf) + + qdel(datum_spawn) + +/datum/overmap_template_layer/legacy_events/proc/get_cloud_turfs(amount, radius, list/turf/candidates, continuous) + // don't modify original list + candidates = candidates.Copy() + // clamp + amount = min(amount, length(candidates)) + + var/turf/origin = pick(candidates) + var/list/turf/selected = list(origin) + var/list/turf/expanding = list(origin) + + candidates -= origin + + while(length(expanding) && length(selected) < amount) + var/turf/checking = pick(expanding) + var/turf/neighbor = get_random_neighbor(checking, candidates, continuous, radius) + + if(neighbor) + candidates -= neighbor + selected += neighbor + if(get_dist(origin, neighbor) < radius) + expanding += neighbor + else + expanding -= expanding + + return selected + +/datum/overmap_template_layer/legacy_events/proc/get_random_neighbor(turf/origin, list/turf/candidates, continuous, range) + var/list/turf/potential + if(continuous) + potential = origin.CardinalTurfs(FALSE) + else + potential = trange(range, origin) + for(var/turf/checking in potential) + if(checking in candidates) + return checking diff --git a/code/modules/overmap/map/turf.dm b/code/modules/overmap/map/turf.dm index f9666f923a0..37e32b95e62 100644 --- a/code/modules/overmap/map/turf.dm +++ b/code/modules/overmap/map/turf.dm @@ -1,74 +1,117 @@ /turf/overmap - icon = 'icons/turf/space.dmi' + name = "--init--" + desc = "If you see this, it means coders didn't update the description but did allow perspective-relayed examine. Yell at them." + icon = 'icons/modules/overmap/turf.dmi' icon_state = "map" permit_ao = FALSE -// initialized = FALSE // TODO - Fix unsimulated turf initialization so this override is not necessary! + + maptext_height = 32 + maptext_width = 32 + maptext_x = 0 + maptext_y = 12 + +/turf/overmap/proc/initialize_overmap(datum/overmap/map) + return TRUE + +/turf/overmap/map + opacity = FALSE + density = FALSE + +/turf/overmap/map/initialize_overmap(datum/overmap/map) + var/calculated_x = x - map.lower_left_x + var/calculated_y = y - map.lower_left_y + name = "[calculated_x]-[calculated_y]" + return ..() /turf/overmap/edge opacity = TRUE density = TRUE - var/map_is_to_my - var/turf/overmap/edge/wrap_buddy -/turf/overmap/edge/Initialize(mapload) - ..() - return INITIALIZE_HINT_LATELOAD - -/turf/overmap/edge/LateInitialize() - //This could be done by using the (LEGACY_MAP_DATUM).overmap_size much faster, HOWEVER, doing it programatically to 'find' - // the edges this way allows for 'sub overmaps' elsewhere and whatnot. - for(var/side in GLOB.alldirs) //The order of this list is relevant: It should definitely break on finding a cardinal FIRST. - var/turf/T = get_step(src, side) - if(T?.type == /turf/overmap) //Not a wall, not something else, EXACTLY a flat map turf. - map_is_to_my = side - break - - if(map_is_to_my) - var/turf/T = get_step(src, map_is_to_my) // Should be a normal map turf - while(istype(T, /turf/overmap)) - T = get_step(T, map_is_to_my) // Could be a wall if the map is only 1 turf big - if(istype(T, /turf/overmap/edge)) - wrap_buddy = T - break - -/turf/overmap/edge/Destroy() - wrap_buddy = null + /// stores a reference to our overmap for wrap purposes + /// + /// todo: is this a good method? it works for now but i hate storing turf vars... + var/datum/overmap/overmap + /// sign of wrap, x + var/wrap_sign_x + /// sign of wrap, y + var/wrap_sign_y + +/turf/overmap/edge/initialize_overmap(datum/overmap/map) + name = "border (warp-enabled)" + overmap = map return ..() -/turf/overmap/edge/Bumped(var/atom/movable/AM) - if(wrap_buddy?.map_is_to_my) - AM.forceMove(get_step(wrap_buddy, wrap_buddy.map_is_to_my)) - else - . = ..() - -/turf/overmap/Initialize(mapload) - . = ..() - name = "[x]-[y]" - var/list/numbers = list() - - if(x == 1 || x == (LEGACY_MAP_DATUM).overmap_size) - numbers += list("[round(y/10)]","[round(y%10)]") - if(y == 1 || y == (LEGACY_MAP_DATUM).overmap_size) - numbers += "-" - if(y == 1 || y == (LEGACY_MAP_DATUM).overmap_size) - numbers += list("[round(x/10)]","[round(x%10)]") - - for(var/i = 1 to numbers.len) - var/image/I = image('icons/effects/numbers.dmi',numbers[i]) - I.pixel_x = 5*i - 2 - I.pixel_y = world.icon_size/2 - 3 - if(y == 1) - I.pixel_y = 3 - I.pixel_x = 5*i + 4 - if(y == (LEGACY_MAP_DATUM).overmap_size) - I.pixel_y = world.icon_size - 9 - I.pixel_x = 5*i + 4 - if(x == 1) - I.pixel_x = 5*i - 2 - if(x == (LEGACY_MAP_DATUM).overmap_size) - I.pixel_x = 5*i + 2 - add_overlay(I) +/** + * initializes our locality + * + * remember: at this point, overmap hasn't been set, because we're currently being called from a /datum/turf_reservation! + */ +/turf/overmap/edge/proc/initialize_border(datum/overmap/map, datum/turf_reservation/reservation) + var/lower_left_x = reservation.bottom_left_coords[1] + var/lower_left_y = reservation.bottom_left_coords[2] + var/upper_right_x = reservation.top_right_coords[1] + var/upper_right_y = reservation.top_right_coords[2] + + var/number + if((x == lower_left_x - 1) || (x == upper_right_x + 1)) + // left or right borders + if((y == lower_left_y - 1) || (y == upper_right_y + 1)) + else + number = y - lower_left_y + 1 + else if((y == lower_left_y - 1) || (y == upper_right_y + 1)) + // top or bottom borders + if((x == lower_left_x - 1) || (x == upper_right_x + 1)) + else + number = x - lower_left_x + 1 + + wrap_sign_x = 0 + wrap_sign_y = 0 + + if(x == lower_left_x - 1) + if(y == lower_left_y - 1) + wrap_sign_y = 1 + wrap_sign_x = 1 + else if(x == upper_right_x + 1) + if(y == upper_right_y + 1) + wrap_sign_y = -1 + wrap_sign_x = -1 + if(y == lower_left_y - 1) + if(x == upper_right_x + 1) + wrap_sign_x = -1 + wrap_sign_y = 1 + else if(y == upper_right_y + 1) + if(x == lower_left_x - 1) + wrap_sign_x = 1 + wrap_sign_y = -1 + + if(number) + maptext = MAPTEXT_CENTER("[number]") + +/** + * get where a ship wraps to when it touches us + * + * supports diagonals. + */ +/turf/overmap/edge/proc/get_wrap_counterpart() + if(x == overmap.lower_left_x - 1) + if(y == overmap.lower_left_y - 1) + return locate(overmap.upper_right_x, overmap.upper_right_y, z) + return locate(overmap.upper_right_x, y, z) + else if(x == overmap.upper_right_x + 1) + if(y == overmap.upper_right_y + 1) + return locate(overmap.lower_left_x, overmap.lower_left_y, z) + return locate(overmap.lower_left_x, y, z) + if(y == overmap.lower_left_y - 1) + if(x == overmap.upper_right_x + 1) + return locate(overmap.lower_left_x, overmap.upper_right_y, z) + return locate(x, overmap.upper_right_y, z) + else if(y == overmap.upper_right_y + 1) + if(x == overmap.lower_left_x - 1) + return locate(overmap.upper_right_x, overmap.lower_left_y, z) + return locate(x, overmap.lower_left_y, z) + +//! LEGACY BELOW /turf/overmap/Entered(var/atom/movable/O, var/atom/oldloc) ..() @@ -79,3 +122,5 @@ ..() if(istype(O, /obj/overmap/entity/visitable/ship)) GLOB.overmap_event_handler.on_turf_exited(src, O, newloc) + +//! END diff --git a/code/modules/overmap/map/object.dm b/code/modules/overmap/object.dm similarity index 100% rename from code/modules/overmap/map/object.dm rename to code/modules/overmap/object.dm diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index 7c6186aaf15..599a8ed31d9 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -240,16 +240,6 @@ GLOB.global_announcer.autosay(alert_msg, "Supermatter Monitor") public_alert = 0 - -/obj/machinery/power/supermatter/get_transit_zlevel() - //don't send it back to the station -- most of the time - if(prob(99)) - var/list/candidates = SSmapping.crosslinked_levels() - (LEGACY_MAP_DATUM).station_levels - . = SAFEPICK(candidates) - if(.) - return - return ..() - /obj/machinery/power/supermatter/process(delta_time) var/turf/L = loc diff --git a/code/modules/tgui/modules/overmap.dm b/code/modules/tgui/modules/overmap.dm index 89b71e86644..4a6149f409a 100644 --- a/code/modules/tgui/modules/overmap.dm +++ b/code/modules/tgui/modules/overmap.dm @@ -110,8 +110,8 @@ data["sector"] = current_sector ? current_sector.name : "Deep Space" data["sector_info"] = current_sector ? current_sector.desc : "Not Available" - data["s_x"] = linked.x - data["s_y"] = linked.y + data["s_x"] = linked.get_tile_x() + data["s_y"] = linked.get_tile_y() data["speed"] = round(linked.get_speed_legacy()*1000, 0.01) data["accel"] = round(linked.get_acceleration_legacy()*1000, 0.01) data["heading"] = linked.get_heading() @@ -188,8 +188,8 @@ data["sector"] = current_sector ? current_sector.name : "Deep Space" data["sector_info"] = current_sector ? current_sector.desc : "Not Available" data["landed"] = linked.get_landed_info() - data["s_x"] = linked.x - data["s_y"] = linked.y + data["s_x"] = linked.get_tile_x() + data["s_y"] = linked.get_tile_y() data["dest"] = dy && dx data["d_x"] = dx data["d_y"] = dy @@ -311,11 +311,11 @@ return TRUE switch(params["add"]) if("current") - R.fields["x"] = linked.x - R.fields["y"] = linked.y + R.fields["x"] = linked.get_tile_x() + R.fields["y"] = linked.get_tile_y() if("new") - var/newx = input("Input new entry x coordinate", "Coordinate input", linked.x) as num - var/newy = input("Input new entry y coordinate", "Coordinate input", linked.y) as num + var/newx = input("Input new entry x coordinate", "Coordinate input", linked.get_tile_x()) as num + var/newy = input("Input new entry y coordinate", "Coordinate input", linked.get_tile_y()) as num R.fields["x"] = clamp(newx, 1, world.maxx) R.fields["y"] = clamp(newy, 1, world.maxy) known_sectors[sec_name] = R diff --git a/icons/effects/numbers.dmi b/icons/effects/numbers_unused.dmi similarity index 100% rename from icons/effects/numbers.dmi rename to icons/effects/numbers_unused.dmi diff --git a/icons/modules/overmap/area.dmi b/icons/modules/overmap/area.dmi new file mode 100644 index 0000000000000000000000000000000000000000..c107bcc6475ae68c3194f1cef117fdecdf808ea4 GIT binary patch literal 229 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJ?5dE65|`BCklFziD-R$&XJM9faA!9WTWM2S_a0&Cmu|e%6RpyKJrb@IYyv5Brqw3f%OYhwmJP zK}keTk6WHeqyrm$-k5(SDe^Ibwu5Xn=#4!Z>Gqb%e$*TzPALyDVCD zVtBADU2$7`n`?ZzVRfx7UU6Q1m@ZXuDpPDLS7adVEXCsAluZ=rOMuxW^Sad{X zb7OL8aCB*JZU6vyoKseCa&`CgQ*iP1gNKs6#&p*Aw@yiHuwMl0~|?2K~z|Uwbofv>Oc^N;RFbaBKs25APE6M zk$nk@ApieQou26o#i^pdTv+xMGtb3)LrurBY%><>Ncb}EfM<6tlJuv;9EoddGdw`nSsx~HktTCLVI5B;ju)FoLu zlgSiIrHUTUqm$?Hp;Ri;$;oC54{90>*L~q}-9|&-6|xja^VI9@>#5h{`?TZa^W}0? z&11LgI8K)j)pFTUlgr)dX*N4gJe^Lb*;H4(UM`ok5BvaoKg2#5ChP-0z}^qBUj=Ue zU;S6?{So%@Tf#ngf5ko-VgE1z!EFwI3Ri)kbSr&Tg>2V|#jQ{VUBX_m|FcKgjkzm`jN zNfz|`{mFDX*K<75>3HPBbUL9^I2epS)U4N0^urTH>$Scc4=4}>uWDAS-R_fTN3&Yd zU7#imN2A$nq2}v!3d8WkhsA6bsu>R7^lUc!1J8cH-)z*?`8*sR{sG;#XjP9t*Qx*j N002ovPDHLkV1kVNFY^EZ literal 0 HcmV?d00001