diff --git a/citadel.dme b/citadel.dme index b9817bccebb..2de7b72c79c 100644 --- a/citadel.dme +++ b/citadel.dme @@ -67,7 +67,6 @@ #include "code\__DEFINES\movement.dm" #include "code\__DEFINES\movespeed_modification.dm" #include "code\__DEFINES\objects.dm" -#include "code\__DEFINES\overmap.dm" #include "code\__DEFINES\parameters_world.dm" #include "code\__DEFINES\persistence.dm" #include "code\__DEFINES\planets.dm" @@ -199,6 +198,8 @@ #include "code\__DEFINES\mobs\organs.dm" #include "code\__DEFINES\mobs\silicon_privileges.dm" #include "code\__DEFINES\mobs\sprite_accessories.dm" +#include "code\__DEFINES\overmaps\misc.dm" +#include "code\__DEFINES\overmaps\overmap.dm" #include "code\__DEFINES\power\power.dm" #include "code\__DEFINES\preferences\data_keys_character.dm" #include "code\__DEFINES\preferences\data_keys_global.dm" @@ -3478,6 +3479,7 @@ #include "code\modules\overmap\disperser\disperser_circuit.dm" #include "code\modules\overmap\disperser\disperser_console.dm" #include "code\modules\overmap\disperser\disperser_fire.dm" +#include "code\modules\overmap\entity\physics.dm" #include "code\modules\overmap\events\event_handler.dm" #include "code\modules\overmap\events\generation.dm" #include "code\modules\overmap\events\overmap_event.dm" diff --git a/code/__DEFINES/overmap.dm b/code/__DEFINES/overmaps/misc.dm similarity index 100% rename from code/__DEFINES/overmap.dm rename to code/__DEFINES/overmaps/misc.dm diff --git a/code/__DEFINES/overmaps/overmap.dm b/code/__DEFINES/overmaps/overmap.dm new file mode 100644 index 00000000000..17bf28ea34f --- /dev/null +++ b/code/__DEFINES/overmaps/overmap.dm @@ -0,0 +1,30 @@ +// debug +#ifdef ENABLE_OVERMAP_AGGRESSIVE_ASSERT + #define OVERMAP_AGGRESSIVE_ASSERT(statement) ASSERT(statement) +#else + #define OVERMAP_AGGRESSIVE_ASSERT(statement) +#endif + +/** + * distances + * everything's real distance is pixels for obvious reasons (like us using byond pixel movement) + */ + +/// units of overmap distance +#define OVERMAP_DISTANCE_UNIT "l-s" +/// overmap distance units per pixel +#define OVERMAP_DISTANCE_PIXEL 3 +/// overmap distance quantization +#define OVERMAP_DISTANCE_ACCURACY 0.0001 +/// duplicate of world icon size. don't lie to yourself, we aren't getting 64x64 ss13. +#define OVERMAP_WORLD_ICON_SIZE 32 +/// overmap coordinate distance in a tile +#define OVERMAP_DISTANCE_TILE (OVERMAP_WORLD_ICON_SIZE * OVERMAP_DISTANCE_PIXEL) +/// overmap distance quantize helper +#define QUANTIZE_OVERMAP_DISTANCE(d) round(d, OVERMAP_DISTANCE_ACCURACY) +/// render overmap distance +#define OVERMAP_DISTANCE_RENDER(distance) "[QUANTIZE_OVERMAP_DISTANCE(distance)] l-s" +/// overmap dist to pixels +#define OVERMAP_DIST_TO_PIXEL(d) (d / OVERMAP_DISTANCE_PIXEL) +/// pixels to overmap dist +#define OVERMAP_PIXEL_TO_DIST(p) (p * OVERMAP_DISTANCE_PIXEL) diff --git a/code/controllers/subsystem/parallax.dm b/code/controllers/subsystem/parallax.dm index edda655cd96..21d472d5d3b 100644 --- a/code/controllers/subsystem/parallax.dm +++ b/code/controllers/subsystem/parallax.dm @@ -92,7 +92,7 @@ SUBSYSTEM_DEF(parallax) var/obj/effect/overmap/visitable/ship/V = get_overmap_sector(z) if(!istype(V)) return - if(V.is_still()) + if(!V.is_moving()) return return list( 60, diff --git a/code/modules/events/meteors.dm b/code/modules/events/meteors.dm index 63448462c58..fef2bb72452 100644 --- a/code/modules/events/meteors.dm +++ b/code/modules/events/meteors.dm @@ -83,7 +83,7 @@ return /datum/event/meteor_wave/overmap/tick() - if(victim && !victim.is_still()) // Meteors mostly fly in your face + if(victim && !!victim.is_moving()) // Meteors mostly fly in your face start_side = prob(90) ? victim.fore_dir : pick(GLOB.cardinal) else // Unless you're standing still start_side = pick(GLOB.cardinal) @@ -94,10 +94,10 @@ if(!victim) return var/skill = victim.get_helm_skill() - var/speed = victim.get_speed() + var/speed = victim.get_speed_legacy() if(skill >= SKILL_PROF) . = round(. * 0.5) - if(victim.is_still()) // Standing still means less shit flies your way + if(!victim.is_moving()) // Standing still means less shit flies your way . = round(. * 0.1) if(speed < SHIP_SPEED_SLOW) // Slow and steady . = round(. * 0.5) diff --git a/code/modules/overmap/entity/physics.dm b/code/modules/overmap/entity/physics.dm new file mode 100644 index 00000000000..4d4198c0c46 --- /dev/null +++ b/code/modules/overmap/entity/physics.dm @@ -0,0 +1,7 @@ +// obviously this file is wip for ship --> entity conversion huh + +/** + * check if we're moving, used to determine if we need to start ticking + */ +/obj/effect/overmap/visitable/ship/proc/is_moving() + return QUANTIZE_OVERMAP_DISTANCE(vel_x) || QUANTIZE_OVERMAP_DISTANCE(vel_y) diff --git a/code/modules/overmap/ships/computers/helm.dm b/code/modules/overmap/ships/computers/helm.dm index 6c1ce0eccb8..63a6c9cd761 100644 --- a/code/modules/overmap/ships/computers/helm.dm +++ b/code/modules/overmap/ships/computers/helm.dm @@ -63,15 +63,15 @@ GLOBAL_LIST_EMPTY(all_waypoints) if(autopilot && dx && dy && !autopilot_disabled) var/turf/T = locate(dx,dy,GLOB.using_map.overmap_z) if(linked.loc == T) - if(linked.is_still()) + if(!linked.is_moving()) autopilot = 0 else linked.decelerate() else var/brake_path = linked.get_brake_path() var/direction = get_dir(linked.loc, T) - var/acceleration = min(linked.get_acceleration(), accellimit) - var/speed = linked.get_speed() + var/acceleration = min(linked.get_acceleration_legacy(), accellimit) + var/speed = linked.get_speed_legacy() var/heading = linked.get_heading() // Destination is current grid or speedlimit is exceeded @@ -111,7 +111,7 @@ GLOBAL_LIST_EMPTY(all_waypoints) data["d_x"] = dx data["d_y"] = dy data["speedlimit"] = speedlimit ? speedlimit*1000 : "Halted" - data["accel"] = min(round(linked.get_acceleration()*1000, 0.01),accellimit*1000) + data["accel"] = min(round(linked.get_acceleration_legacy()*1000, 0.01),accellimit*1000) data["heading"] = linked.get_heading_degrees() data["autopilot_disabled"] = autopilot_disabled data["autopilot"] = autopilot @@ -119,16 +119,16 @@ GLOBAL_LIST_EMPTY(all_waypoints) data["canburn"] = linked.can_burn() data["accellimit"] = accellimit*1000 - var/speed = round(linked.get_speed()*1000, 0.01) + var/speed = round(linked.get_speed_legacy()*1000, 0.01) var/speed_color = null - if(linked.get_speed() < SHIP_SPEED_SLOW) + if(linked.get_speed_legacy() < SHIP_SPEED_SLOW) speed_color = "good" - if(linked.get_speed() > SHIP_SPEED_FAST) + if(linked.get_speed_legacy() > SHIP_SPEED_FAST) speed_color = "average" data["speed"] = speed data["speed_color"] = speed_color - if(linked.get_speed()) + if(linked.get_speed_legacy()) data["ETAnext"] = "[round(linked.ETA()/10)] seconds" else data["ETAnext"] = "N/A" diff --git a/code/modules/overmap/ships/ship.dm b/code/modules/overmap/ships/ship.dm index 620474d3bf8..2622fec68c7 100644 --- a/code/modules/overmap/ships/ship.dm +++ b/code/modules/overmap/ships/ship.dm @@ -1,14 +1,13 @@ -#define SHIP_MOVE_RESOLUTION 0.00001 -#define MOVING(speed) abs(speed) >= min_speed -#define SANITIZE_SPEED(speed) SIGN(speed) * clamp(abs(speed), 0, max_speed) -#define CHANGE_SPEED_BY(speed_var, v_diff) \ - v_diff = SANITIZE_SPEED(v_diff);\ - if(!MOVING(speed_var + v_diff)) \ +// renamed because why the hell did you name it CHANGE_SPEED_BY +#define PENALIZED_SPEED_CHANGE(speed_var, v_diff) \ + v_diff = QUANTIZE_OVERMAP_DISTANCE(v_diff);\ + if(!QUANTIZE_OVERMAP_DISTANCE(speed_var + v_diff)) \ {speed_var = 0};\ else \ - {speed_var = SANITIZE_SPEED((speed_var + v_diff)/(1 + speed_var*v_diff/(max_speed ** 2)))} + {speed_var = QUANTIZE_OVERMAP_DISTANCE((speed_var + v_diff)/(1 + speed_var*v_diff/(max_speed ** 2)))} // Uses Lorentzian dynamics to avoid going too fast. +// todo: /obj/overmap/entity /obj/effect/overmap/visitable/ship name = "spacecraft" desc = "This marker represents a spaceship. Scan it for more information." @@ -16,23 +15,31 @@ dir = NORTH icon_state = "ship" appearance_flags = TILE_BOUND|KEEP_TOGETHER|LONG_GLIDE + glide_size = 8 var/moving_state = "ship_moving" + //! identity + /// id + var/id + /// next id + var/static/id_next = 0 + + /// Tonnes, arbitrary number, affects acceleration provided by engines. var/vessel_mass = 10000 /// Arbitrary number, affects how likely are we to evade meteors. var/vessel_size = SHIP_SIZE_LARGE - /// "Speed of light" for the ship, in turfs/decisecond. - var/max_speed = 1/(1 SECOND) - /// Below this, we round speed to 0 to avoid math errors. - var/min_speed = 1/(2 MINUTES) /// Pixel coordinates in the world. var/position_x /// Pixel coordinates in the world. var/position_y - /// Speed in x,y direction. - var/list/speed = list(0,0) + /// velocity x in overmap units per second + var/vel_x + /// velocity y in overmap units per second + var/vel_y + /// max speed in overmap units per second + var/max_speed = OVERMAP_DISTANCE_TILE /// Worldtime when ship last acceleated. var/last_burn = 0 /// How often ship can do burns. @@ -52,10 +59,13 @@ var/skill_needed = SKILL_NONE //We don't like skills. var/operator_skill +/obj/effect/overmap/visitable/ship/New() + // assign id immediately + id = "[++id_next]" + return ..() + /obj/effect/overmap/visitable/ship/Initialize(mapload) . = ..() - min_speed = round(min_speed, SHIP_MOVE_RESOLUTION) - max_speed = round(max_speed, SHIP_MOVE_RESOLUTION) SSshuttle.ships += src position_x = ((loc.x - 1) * WORLD_ICON_SIZE) + (WORLD_ICON_SIZE/2) + pixel_x + 1 position_y = ((loc.y - 1) * WORLD_ICON_SIZE) + (WORLD_ICON_SIZE/2) + pixel_y + 1 @@ -70,14 +80,11 @@ accelerate(direction, accel_limit) operator_skill = user.get_skill_value(/datum/skill/pilot) -/obj/effect/overmap/visitable/ship/proc/is_still() - return !MOVING(speed[1]) && !MOVING(speed[2]) - /obj/effect/overmap/visitable/ship/get_scan_data(mob/user) . = ..() - if(!is_still()) - . += {"\n\[i\]Heading\[/i\]: [get_heading_degrees()]\n\[i\]Velocity\[/i\]: [get_speed() * 1000]"} + if(!!is_moving()) + . += {"\n\[i\]Heading\[/i\]: [get_heading_degrees()]\n\[i\]Velocity\[/i\]: [get_speed_legacy() * 1000]"} else . += {"\n\[i\]Vessel was stationary at time of scan.\[/i\]\n"} @@ -90,31 +97,37 @@ . += {"\[i\]Life Signs\[/i\]: [life ? life : "None"]"} // Projected acceleration based on information from engines -/obj/effect/overmap/visitable/ship/proc/get_acceleration() - return round(get_total_thrust()/get_vessel_mass(), SHIP_MOVE_RESOLUTION) +/obj/effect/overmap/visitable/ship/proc/get_acceleration_legacy() + return round(get_total_thrust()/get_vessel_mass(), OVERMAP_DISTANCE_ACCURACY) // Does actual burn and returns the resulting acceleration -/obj/effect/overmap/visitable/ship/proc/get_burn_acceleration() - return round(burn() / get_vessel_mass(), SHIP_MOVE_RESOLUTION) +/obj/effect/overmap/visitable/ship/proc/get_burn_acceleration_legacy() + return round(burn() / get_vessel_mass(), OVERMAP_DISTANCE_ACCURACY) /obj/effect/overmap/visitable/ship/proc/get_vessel_mass() . = vessel_mass for(var/obj/effect/overmap/visitable/ship/ship in src) . += ship.get_vessel_mass() -/obj/effect/overmap/visitable/ship/proc/get_speed() - return round(sqrt(speed[1] ** 2 + speed[2] ** 2), SHIP_MOVE_RESOLUTION) +/** + * ! legacy + * + * get speed in tiles / decisecond + */ +/obj/effect/overmap/visitable/ship/proc/get_speed_legacy() + . = QUANTIZE_OVERMAP_DISTANCE(sqrt(vel_x ** 2 + vel_y ** 2)) + . = OVERMAP_DIST_TO_PIXEL(.) / WORLD_ICON_SIZE / 10 // Get heading in BYOND dir bits /obj/effect/overmap/visitable/ship/proc/get_heading() - var/res = 0 - if(MOVING(speed[1])) - if(speed[1] > 0) + var/res = NONE + if(vel_x) + if(vel_x > 0) res |= EAST else res |= WEST - if(MOVING(speed[2])) - if(speed[2] > 0) + if(vel_y) + if(vel_y > 0) res |= NORTH else res |= SOUTH @@ -122,14 +135,14 @@ // Get heading in degrees (like a compass heading) /obj/effect/overmap/visitable/ship/proc/get_heading_degrees() - return (arctan(speed[2], speed[1]) + 360) % 360 // Yes ATAN2(y, x) is correct to get clockwise degrees + return (arctan(vel_y, vel_x) + 360) % 360 // Yes ATAN2(y, x) is correct to get clockwise degrees /obj/effect/overmap/visitable/ship/proc/adjust_speed(n_x, n_y) - var/old_still = is_still() - CHANGE_SPEED_BY(speed[1], n_x) - CHANGE_SPEED_BY(speed[2], n_y) + var/old_still = !is_moving() + PENALIZED_SPEED_CHANGE(vel_x, n_x) + PENALIZED_SPEED_CHANGE(vel_y, n_y) update_icon() - var/still = is_still() + var/still = !is_moving() if(still == old_still) return else if(still) @@ -146,30 +159,35 @@ SSmapping.throw_movables_on_z_turfs_of_type(zz, /turf/space, REVERSE_DIR(fore_dir)) /obj/effect/overmap/visitable/ship/proc/get_brake_path() - if(!get_acceleration()) + if(!get_acceleration_legacy()) return INFINITY - if(is_still()) + if(!is_moving()) return 0 if(!burn_delay) return 0 - if(!get_speed()) + if(!get_speed_legacy()) return 0 - var/num_burns = get_speed()/get_acceleration() + 2 // Some padding in case acceleration drops form fuel usage - var/burns_per_grid = 1/ (burn_delay * get_speed()) + var/num_burns = get_speed_legacy()/get_acceleration_legacy() + 2 // Some padding in case acceleration drops form fuel usage + var/burns_per_grid = 1/ (burn_delay * get_speed_legacy()) return round(num_burns/burns_per_grid) /obj/effect/overmap/visitable/ship/proc/decelerate() - if(((speed[1]) || (speed[2])) && can_burn()) - if (speed[1]) - adjust_speed(-SIGN(speed[1]) * min(get_burn_acceleration(),abs(speed[1])), 0) - if (speed[2]) - adjust_speed(0, -SIGN(speed[2]) * min(get_burn_acceleration(),abs(speed[2]))) + if(is_moving() && can_burn()) + var/deceleration = get_burn_acceleration_legacy() + //? shim: convert to new overmaps units from old + //? old was, for some stupid reason, "turfs per decosecond". + deceleration = deceleration * OVERMAP_DISTANCE_TILE * 10 + adjust_speed(-SIGN(vel_x) * min(deceleration,abs(vel_x)), -SIGN(vel_y) * min(deceleration,abs(vel_y))) last_burn = world.time /obj/effect/overmap/visitable/ship/proc/accelerate(direction, accel_limit) if(can_burn()) last_burn = world.time - var/acceleration = min(get_burn_acceleration(), accel_limit) + var/acceleration = min(get_burn_acceleration_legacy(), accel_limit) + //? shim: convert to new overmaps units from old + //? old was, for some stupid reason, "turfs per decosecond". + acceleration = acceleration * OVERMAP_DISTANCE_TILE * 10 + if(direction & EAST) adjust_speed(acceleration, 0) if(direction & WEST) @@ -180,8 +198,8 @@ adjust_speed(0, -acceleration) /obj/effect/overmap/visitable/ship/process(delta_time) - var/new_position_x = position_x + (speed[1] * WORLD_ICON_SIZE * delta_time * 10) - var/new_position_y = position_y + (speed[2] * WORLD_ICON_SIZE * delta_time * 10) + var/new_position_x = position_x + (OVERMAP_DIST_TO_PIXEL(vel_x) * delta_time) + var/new_position_y = position_y + (OVERMAP_DIST_TO_PIXEL(vel_y) * delta_time) // For simplicity we assume that you can't travel more than one turf per tick. That would be hella-fast. var/new_turf_x = CEILING(new_position_x / WORLD_ICON_SIZE, 1) @@ -202,7 +220,8 @@ pixel_x = new_pixel_x pixel_y = new_pixel_y return - animate(src, pixel_x = new_pixel_x, pixel_y = new_pixel_y, time = delta_time * 10, flags = ANIMATION_END_NOW) + // todo: actual animations + animate(src, pixel_x = new_pixel_x, pixel_y = new_pixel_y, time = 8, flags = ANIMATION_END_NOW) // If we get moved, update our internal tracking to account for it /obj/effect/overmap/visitable/ship/Moved(atom/old_loc, direction, forced = FALSE) @@ -218,7 +237,7 @@ /obj/effect/overmap/visitable/ship/update_icon() - if(!is_still()) + if(!!is_moving()) icon_state = moving_state transform = matrix().Turn(get_heading_degrees()) else @@ -248,18 +267,18 @@ // Deciseconds to next step /obj/effect/overmap/visitable/ship/proc/ETA() . = INFINITY - if(MOVING(speed[1])) + if(vel_x) var/offset = MODULUS(position_x, WORLD_ICON_SIZE) - var/dist_to_go = (speed[1] > 0) ? (WORLD_ICON_SIZE - offset) : offset - . = min(., (dist_to_go / abs(speed[1])) * (1/WORLD_ICON_SIZE)) - if(MOVING(speed[2])) + var/dist_to_go = (vel_x > 0) ? (WORLD_ICON_SIZE - offset) : offset + . = min(., (dist_to_go / OVERMAP_DIST_TO_PIXEL(abs(vel_x))) * 10) + if(vel_y) var/offset = MODULUS(position_y, WORLD_ICON_SIZE) - var/dist_to_go = (speed[2] > 0) ? (WORLD_ICON_SIZE - offset) : offset - . = min(., (dist_to_go / abs(speed[2])) * (1/WORLD_ICON_SIZE)) + var/dist_to_go = (vel_y > 0) ? (WORLD_ICON_SIZE - offset) : offset + . = min(., (dist_to_go / OVERMAP_DIST_TO_PIXEL(abs(vel_y))) * 10) . = max(., 0) /obj/effect/overmap/visitable/ship/proc/halt() - adjust_speed(-speed[1], -speed[2]) + adjust_speed(-vel_x, -vel_y) halted = 1 /obj/effect/overmap/visitable/ship/proc/unhalt() @@ -284,8 +303,7 @@ var/turf/T = get_turf(src) // Usually we're on the turf, but sometimes we might be landed or something. var/x_to_use = T?.x || "UNK" var/y_to_use = T?.y || "UNK" - return "\[X:[x_to_use], Y:[y_to_use], VEL:[get_speed() * 1000], HDG:[get_heading_degrees()]\]" + return "\[X:[x_to_use], Y:[y_to_use], VEL:[get_speed_legacy() * 1000], HDG:[get_heading_degrees()]\]" -#undef MOVING -#undef SANITIZE_SPEED -#undef CHANGE_SPEED_BY +/obj/effect/overmap/visitable/ship/set_glide_size(new_glide_size, recursive) + return // *no*. diff --git a/code/modules/tgui/modules/overmap.dm b/code/modules/tgui/modules/overmap.dm index 75a4107b129..e3600d2355d 100644 --- a/code/modules/tgui/modules/overmap.dm +++ b/code/modules/tgui/modules/overmap.dm @@ -110,12 +110,12 @@ data["sector_info"] = current_sector ? current_sector.desc : "Not Available" data["s_x"] = linked.x data["s_y"] = linked.y - data["speed"] = round(linked.get_speed()*1000, 0.01) - data["accel"] = round(linked.get_acceleration()*1000, 0.01) + 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_degrees() data["viewing"] = viewing_overmap(user) - if(linked.get_speed()) + if(linked.get_speed_legacy()) data["ETAnext"] = "[round(linked.ETA()/10)] seconds" else data["ETAnext"] = "N/A" @@ -192,7 +192,7 @@ data["d_x"] = dx data["d_y"] = dy data["speedlimit"] = speedlimit ? speedlimit*1000 : "Halted" - data["accel"] = min(round(linked.get_acceleration()*1000, 0.01),accellimit*1000) + data["accel"] = min(round(linked.get_acceleration_legacy()*1000, 0.01),accellimit*1000) data["heading"] = linked.get_heading_degrees() data["autopilot_disabled"] = autopilot_disabled data["autopilot"] = autopilot @@ -200,16 +200,16 @@ data["canburn"] = linked.can_burn() data["accellimit"] = accellimit*1000 - var/speed = round(linked.get_speed()*1000, 0.01) + var/speed = round(linked.get_speed_legacy()*1000, 0.01) var/speed_color = null - if(linked.get_speed() < SHIP_SPEED_SLOW) + if(linked.get_speed_legacy() < SHIP_SPEED_SLOW) speed_color = "good" - if(linked.get_speed() > SHIP_SPEED_FAST) + if(linked.get_speed_legacy() > SHIP_SPEED_FAST) speed_color = "average" data["speed"] = speed data["speed_color"] = speed_color - if(linked.get_speed()) + if(linked.get_speed_legacy()) data["ETAnext"] = "[round(linked.ETA()/10)] seconds" else data["ETAnext"] = "N/A"