mirror of
https://github.com/vgstation-coders/vgstation13.git
synced 2025-12-10 10:21:11 +00:00
* SNOWPLANES? * snow map #2 * it sort of works (not really) * we'll call this a prototype * committing so I can remove other changes later * snowmap prototype 2/11/2016 - practically ready for an open beta edition * more stuff, more sprites, more items, we're getting there * before I uncheck the error handler * AAAAAAAAAAAAAAAAA * it works now * Edits the map to be more terrestrial: Added paramedic stations/security stations/EVA stations to each map. Removed grilles from taxi. Still a bunch of shite to do eg belt hell but we're getting there Also tweaked spawn chance because reasons * snowboot * Coats (#2) * Take these, good luck * oops * According to all known laws of aviation, there is no way a bee should be able to fly. Its wings are too small to get its fat little body off the ground. The bee, of course, flies anyway because bees don’t care what humans think is impossible. Yellow, black. Yellow, black. Yellow, black. Yellow, black. Ooh, black and yellow! Let’s shake it up a little. Barry! Breakfast is ready! Coming! Hang on a second. Hello? - Barry? - Adam? - Oan you believe this is happening? - I can’t. I’ll pick you up. Looking sharp. Use the stairs. Your father paid good money for those. Sorry. I’m excited. Here’s the graduate. We’re very proud of you, son. A perfect report card, all B’s. Very proud. Ma! I got a thing going here. - You got lint on your fuzz. - Ow! That’s me! - Wave to us! We’ll be in row 118,000. - Bye! Barry, I told you, stop flying in the house! - Hey, Adam. - Hey, Barry. - Is that fuzz gel? - A little. Special day, graduation. Never thought I’d make it. Three days grade school, three days high school. Those were awkward. * define * bugfixes * fixes conflicts * fixed bugs and made hoods work better * do ah look lahk ah know what "ay-tomic" is? * bugfixes shadowfixes added like seven different coats, ian now can wear scarves * mapchanges - snaxi is now united * wolves, and point handling (#3) * wolves, and point handling * wolf pointing, removes hitler * Removes nonsense * ice ice baby procedural generation is the best buzzword new snow map doors map now has proper z level names not working right now ice smoothing is being a !!bitch!! * glaciers now smooth glaciers no longer eat up the pipes between stations (this will cause some fuck ups with smoothing but uh yeah) you now slip on rivers todo - skis - snowshoes - spiked boots * Moves ores to overlays, adds snow roid sprites (#5) * Moves ores to overlays, adds snow roid sprites * Fixes gibtonite, re-approaches some mine surprises * Wendigos added, skifree yeti added, wendigo meat and transformation added (#4) * DEER, and leather stuff * Adds xeno spears, xenohide, fixes bugs * alright dragonbro over to you for tonight I'm going to sleep * Fixes wendigos, and wolves * if it works it works who cares why * snowmap bugfixes and optimisations * zzz * Revamp in working state no work in progress saving wip Most issues fixed. Fishing half way through overhaul to include minigame Turned spaces into tabs. fucking atom REEEEEEEEEE Clownfish and clownburger added. All fishing code done. Carp and normal fish recipes updated and ready. Carpmeat changed to subtype of fish_fillet. WIP. Rods mostly done. Basic fish and bait added. * removes bluespace ponds to be atomic * fixes issues - bluespace pond back in the code but not able to be got anywhere * does the easy things * renames it taxi outpost adds map cleaning things * OK THIS WILL FIX IT FOR REAL * fixes EVERYTHING but it's not ready to merge because I reckon we can squeeze some last minute features in * whoops forgot to fix this * underground mining stuff * adds lobby music courtesy of aceedex * bugfixes mining underground optimisations (now it actually runs instead of grinding to a halt) there are runtimes aaaa oh well will fix tomorrow * fixes so that JSG can host it some missing features
855 lines
27 KiB
Plaintext
855 lines
27 KiB
Plaintext
#define NO_TRANSIT 0 //Don't use transit areas
|
|
#define TRANSIT_ACROSS_Z_LEVELS 1 //Only use transit areas if moving to another z-level
|
|
#define TRANSIT_ALWAYS 2 //Always use transit areas
|
|
|
|
//Whether this shuttle can be linked to a shuttle control console.
|
|
#define LINK_FREE 0
|
|
#define LINK_PASSWORD_ONLY 1
|
|
#define LINK_FORBIDDEN 2
|
|
|
|
//Whether the shuttle destroys stuff it collides with, or displaces it
|
|
#define COLLISION_DESTROY 0
|
|
#define COLLISION_DISPLACE 1 //this is same as COLLISION_DISPLACE as for now
|
|
|
|
//One of these values is returned at initialize()
|
|
#define INIT_SUCCESS 1 //everything is good
|
|
#define INIT_NO_AREA 2 //can't find starting area
|
|
#define INIT_NO_PORT 3 //can't find shuttle's docking port
|
|
#define INIT_NO_START 4 //shuttle's docking port isn't connected to a destination port
|
|
|
|
/datum/shuttle
|
|
var/name = "shuttle"
|
|
|
|
//List of ALL docking ports the shuttle can move to
|
|
var/list/docking_ports = list()
|
|
|
|
//The shuttle's main area - it contains the linked_port
|
|
var/area/linked_area
|
|
|
|
//The shuttle's linked shuttle docking port - essential
|
|
var/obj/docking_port/shuttle/linked_port
|
|
|
|
//The shuttle's current location
|
|
var/obj/docking_port/destination/current_port
|
|
|
|
//The shuttle's transit location
|
|
var/obj/docking_port/destination/transit_port
|
|
|
|
//The shuttle's destination
|
|
var/obj/docking_port/destination/destination_port
|
|
|
|
//List of ALL docking ports on the shuttle. Setup at initialize(), the shuttle can only move docking ports in this list
|
|
//(which means those which are placed in the shuttle's area on the map). This exists to prevent shuttles from moving on top
|
|
//of another docking port and then moving it away
|
|
var/list/docking_ports_aboard = list()
|
|
|
|
var/use_transit = TRANSIT_ACROSS_Z_LEVELS
|
|
|
|
var/dir = NORTH
|
|
|
|
var/can_rotate = 1
|
|
|
|
//This is the time it takes for the shuttle to depart (if there's a transit area) or to travel (if there are no transit areas)
|
|
var/pre_flight_delay = 50
|
|
|
|
//If there is a transit port, this is the time the shuttle spends in it
|
|
//If there isn't a transit port, this has no effect. Use the pre_flight_delay var instead
|
|
var/transit_delay = 100
|
|
|
|
//If the shuttle is currently moving
|
|
var/moving = 0
|
|
|
|
var/list/cant_leave_zlevel = list(
|
|
/obj/item/weapon/disk/nuclear = "The nuclear authentication disk can't be transported on a shuttle.",
|
|
)
|
|
|
|
//This list is transferred to all linked shuttle control consoles
|
|
var/list/req_access = list()
|
|
|
|
var/last_moved = 0
|
|
var/cooldown = 100
|
|
|
|
//When the shuttle moves, coordinates of its final location will be offset by rand(-innacuracy, innacuracy)
|
|
var/innacuracy = 0
|
|
|
|
//When the shuttle moves, if stable is 0 then all unbuckled mobs will be stunned
|
|
var/stable = 0
|
|
|
|
var/password = 28011
|
|
var/can_link_to_computer = LINK_FORBIDDEN
|
|
|
|
//Whether the shuttle gibs or displaces stuff. Change this to COLLISION_DISPLACE to make all shuttles displace stuff by default
|
|
var/collision_type = COLLISION_DESTROY
|
|
|
|
var/list/control_consoles = list()
|
|
|
|
var/lockdown = 0
|
|
|
|
var/destroy_everything = 0
|
|
|
|
var/disable_mesons = 0
|
|
|
|
/datum/shuttle/New(var/area/starting_area)
|
|
.=..()
|
|
|
|
if(starting_area)
|
|
if(ispath(starting_area))
|
|
linked_area = locate(starting_area)
|
|
else if(isarea(starting_area))
|
|
linked_area = starting_area
|
|
else
|
|
linked_area = starting_area
|
|
warning("Unable to find area [starting_area] in world - [src.type] ([src.name]) won't be able to function properly.")
|
|
|
|
if(istype(linked_area) && linked_area.contents.len) //Only add the shuttle to the list if its area exists and it has something in it
|
|
shuttles |= src
|
|
|
|
password = rand(10000,99999)
|
|
|
|
//initialize() proc - called automatically in proc/setup_shuttles() below.
|
|
//Returns INIT_SUCCESS, INIT_NO_AREA, INIT_NO_START or INIT_NO_PORT, depending on whether there were any errors
|
|
/datum/shuttle/proc/initialize()
|
|
. = INIT_SUCCESS
|
|
src.docking_ports = list()
|
|
src.docking_ports_aboard = list()
|
|
src.transit_port = null
|
|
|
|
if(!linked_area || !istype(linked_area))
|
|
//No linked area - the shuttle doesn't exist (very bad)
|
|
return INIT_NO_AREA
|
|
|
|
//This line below used to cause weird bugs with some maps (https://github.com/d3athrow/vgstation13/issues/6773)
|
|
|
|
//var/obj/docking_port/shuttle/shuttle_docking_port = locate() in linked_area.contents.Copy()
|
|
|
|
//I have no idea what was causing it, but after replacing it with the following five lines everything started working as intended
|
|
var/obj/docking_port/shuttle/shuttle_docking_port
|
|
|
|
for(var/obj/docking_port/shuttle/S in linked_area)
|
|
shuttle_docking_port = S
|
|
break
|
|
//
|
|
|
|
if(shuttle_docking_port)
|
|
//In case this shuttle already has a shuttle docking port, unlink it
|
|
if(linked_port)
|
|
linked_port.unlink_from_shuttle(src)
|
|
|
|
shuttle_docking_port.link_to_shuttle(src)
|
|
|
|
//The following few lines ensure that if there's a docking port at the shuttle's starting location, the shuttle is docked to it
|
|
var/turf/check_turf = shuttle_docking_port.get_docking_turf()
|
|
if(check_turf)
|
|
for(var/obj/docking_port/P in check_turf.contents)
|
|
shuttle_docking_port.dock(P)
|
|
src.current_port = shuttle_docking_port.docked_with
|
|
break
|
|
|
|
if(!src.current_port)
|
|
//This isn't really a problem, but if the shuttle moves somewhere it won't be able to return to its starting location
|
|
. = INIT_NO_START
|
|
|
|
src.dir = turn(linked_port.dir, 180)
|
|
else
|
|
//No docking port - the shuttle can't be moved (bad but fixable with admin intervention)
|
|
. = INIT_NO_PORT
|
|
|
|
|
|
for(var/obj/docking_port/D in linked_area)
|
|
docking_ports_aboard |= D
|
|
|
|
return
|
|
|
|
/datum/shuttle/Destroy()
|
|
shuttles -= src
|
|
..()
|
|
|
|
/datum/shuttle/proc/get_transit_delay()
|
|
return transit_delay
|
|
|
|
/datum/shuttle/proc/get_pre_flight_delay()
|
|
return pre_flight_delay
|
|
|
|
/datum/shuttle/proc/get_cooldown()
|
|
return cooldown
|
|
|
|
//Shuttles like the emergency shuttle (which moves to pre-defined locations) and vox shuttle (which ends the round once moved to a pre-defined location)
|
|
//should have this proc return 1, so they can't be deleted.
|
|
/datum/shuttle/proc/is_special()
|
|
return 0
|
|
|
|
//Adds a docking port to list of travel destinations, accepts path or the port itself
|
|
/datum/shuttle/proc/add_dock(var/D)
|
|
if(ispath(D))
|
|
for(var/obj/docking_port/destination/dock in all_docking_ports)
|
|
if(istype(dock,D))
|
|
dock.link_to_shuttle(src)
|
|
return dock
|
|
else if(istype(D,/obj/docking_port/destination))
|
|
var/obj/docking_port/destination/dock = D
|
|
dock.link_to_shuttle(src)
|
|
return dock
|
|
|
|
return D
|
|
|
|
//Adds a docking port as a transit area, accepts path or the port itself
|
|
/datum/shuttle/proc/set_transit_dock(var/D)
|
|
if(ispath(D))
|
|
for(var/obj/docking_port/destination/dock in all_docking_ports)
|
|
if(istype(dock,D))
|
|
transit_port = dock
|
|
return dock
|
|
else if(istype(D,/obj/docking_port/destination))
|
|
transit_port = D
|
|
return D
|
|
|
|
/datum/shuttle/proc/can_move()
|
|
if(lockdown)
|
|
return 0
|
|
if(last_moved + cooldown < world.time)
|
|
return 1
|
|
|
|
//Checks the shuttle for any offending atoms
|
|
/datum/shuttle/proc/forbid_movement()
|
|
var/atom/A = linked_area.contains_atom_from_list(cant_leave_zlevel) //code/game/atoms.dm, 243
|
|
if(A)
|
|
return A
|
|
return 0
|
|
|
|
//This is the proc you generally want to use when moving a shuttle. Runs all sorts of checks (cooldown, if already moving, etc)
|
|
//If you want to bypass it, set destination_port to something and call pre_flight()
|
|
//Alternatively, call move_to_dock(destination)
|
|
/datum/shuttle/proc/travel_to(var/obj/docking_port/D, var/obj/machinery/computer/shuttle_control/broadcast = null, var/mob/user)
|
|
if(!D)
|
|
return 0 //no docking port
|
|
if(!linked_port)
|
|
return 0 //no shuttle port
|
|
|
|
if(destination_port)
|
|
if(broadcast)
|
|
broadcast.announce( "The shuttle is currently in process of moving." )
|
|
else if(user)
|
|
to_chat(user, "The shuttle is currently moving")
|
|
return 0 //shuttle already travelling
|
|
|
|
if(lockdown)
|
|
if(broadcast)
|
|
broadcast.announce( "This shuttle is locked down." )
|
|
else if(user)
|
|
to_chat(user, "The shuttle can't move (locked down)")
|
|
return 0
|
|
|
|
if(!can_move())
|
|
if(broadcast)
|
|
broadcast.announce( "The engines are still cooling down from the previous trip." )
|
|
else if(user)
|
|
to_chat(user, "The shuttle can't move (on cooldown)")
|
|
return 0
|
|
|
|
if(D.docked_with)
|
|
if(broadcast)
|
|
broadcast.announce( "[capitalize(D.areaname)] is currently used by another shuttle. Please wait until the docking port is free, or select another destination." )
|
|
else if(user)
|
|
to_chat(user, "The shuttle can't move ([D.areaname] is used by another shuttle)")
|
|
return 0
|
|
|
|
//Handle the message
|
|
var/time = "as soon as possible"
|
|
switch(pre_flight_delay)
|
|
if(0)
|
|
time = "immediately"
|
|
if(1 to 30)
|
|
time = "in a few seconds"
|
|
if(31 to 50)
|
|
time = "shortly"
|
|
if(51 to 80)
|
|
time = "after a short delay"
|
|
if(81 to INFINITY)
|
|
time = "in [max(round((pre_flight_delay) / 10, 1), 0)] seconds"
|
|
if(broadcast)
|
|
broadcast.announce("The shuttle has received your message and will be sent [time].")
|
|
|
|
destination_port = D
|
|
last_moved = world.time
|
|
moving = 1
|
|
|
|
log_game("[usr ? key_name(usr) : "Something"] sent [name] ([type]) to [D.areaname]")
|
|
|
|
if(get_pre_flight_delay())
|
|
spawn(max(1,get_pre_flight_delay()-5))
|
|
for(var/obj/structure/shuttle/engine/propulsion/P in linked_area)
|
|
spawn()
|
|
P.shoot_exhaust()
|
|
|
|
spawn(get_pre_flight_delay())
|
|
//If moving to another zlevel, check for items which can't leave the zlevel (nuke disk, primarily)
|
|
if(linked_port.z != D.z)
|
|
var/atom/A = forbid_movement()
|
|
if( A )
|
|
if(cant_leave_zlevel[A.type])
|
|
if(broadcast)
|
|
broadcast.announce("ERROR: [cant_leave_zlevel[A.type]]")
|
|
else if(user)
|
|
to_chat(user, cant_leave_zlevel[A.type])
|
|
else
|
|
if(broadcast)
|
|
broadcast.announce("ERROR: [A.name] is preventing the shuttle from departing.")
|
|
else if(user)
|
|
to_chat(user, "[A.name] is preventing the shuttle from departing.")
|
|
moving = 0
|
|
destination_port = null
|
|
return 0
|
|
|
|
if(transit_port && get_transit_delay())
|
|
if(broadcast)
|
|
broadcast.announce( "The shuttle has departed and is now moving towards [D.areaname]." )
|
|
else if(user)
|
|
to_chat(user, "The shuttle has departed towards [D.areaname]")
|
|
else
|
|
if(broadcast)
|
|
broadcast.announce( "The shuttle has arrived at [D.areaname]." )
|
|
else if(user)
|
|
to_chat(user, "The shuttle has arrived at [D.areaname]")
|
|
|
|
pre_flight()
|
|
|
|
return 1
|
|
|
|
/datum/shuttle/proc/pre_flight()
|
|
if(!destination_port)
|
|
return
|
|
|
|
if(transit_port && get_transit_delay())
|
|
if(use_transit == TRANSIT_ALWAYS || (use_transit == TRANSIT_ACROSS_Z_LEVELS && (linked_area.z != destination_port.z)))
|
|
move_to_dock(transit_port)
|
|
spawn(max(1,get_transit_delay()-5))
|
|
for(var/obj/structure/shuttle/engine/propulsion/P in linked_area)
|
|
spawn()
|
|
P.shoot_exhaust()
|
|
sleep(get_transit_delay())
|
|
|
|
if(destination_port)
|
|
move_to_dock(destination_port)
|
|
destination_port = null
|
|
|
|
moving = 0
|
|
|
|
//This is the proc you want to use to FORCE a shuttle to move. It always moves it, unless the shuttle or its area don't exist. Transit is skipped, after_flight() is called
|
|
/datum/shuttle/proc/move_to_dock(var/obj/docking_port/D, var/ignore_innacuracy = 0) //A direct proc with no bullshit
|
|
if(!D)
|
|
return
|
|
if(!linked_port)
|
|
return
|
|
|
|
//List of all shuttles docked to this shuttle. They will be moved together with their parent.
|
|
//In the list, shuttles are associated with the docking port they are docked to
|
|
var/list/docked_shuttles = list()
|
|
|
|
//To prevent two shuttles that are docked to each other from potentially breaking everything, all moved shuttles are added to this list
|
|
var/list/moved_shuttles = list()
|
|
|
|
moved_shuttles += src
|
|
|
|
//See all destination ports in current area
|
|
for(var/obj/docking_port/destination/dock in linked_area)
|
|
//If somebody is docked to it (and it isn't us (that would be weird but better be sure))
|
|
if(dock.docked_with && !(dock.docked_with == linked_port))
|
|
//Get the docking port that's docked to it, and then its shuttle
|
|
var/obj/docking_port/shuttle/S = dock.docked_with
|
|
if(!S || !S.linked_shuttle)
|
|
continue
|
|
|
|
docked_shuttles |= S.linked_shuttle
|
|
docked_shuttles[S.linked_shuttle]=dock
|
|
|
|
//******Handle rotation*********
|
|
var/rotate = 0
|
|
if(src.can_rotate)
|
|
|
|
if(linked_port.dir != turn(D.dir,180))
|
|
|
|
rotate = dir2angle(turn(D.dir,180)) - dir2angle(linked_port.dir)
|
|
|
|
if(rotate < 0)
|
|
rotate += 360
|
|
else if(rotate >= 360)
|
|
rotate -= 360
|
|
|
|
//******Get the turf to move to**
|
|
var/turf/target_turf = D.get_docking_turf()
|
|
|
|
if(!ignore_innacuracy && innacuracy) //Handle innacuracy
|
|
var/list/turf_list = list()
|
|
|
|
for(var/turf/T in orange(innacuracy,D.get_docking_turf()))
|
|
turf_list|=T
|
|
|
|
target_turf = pick(turf_list)
|
|
|
|
//****Finally, move the area***
|
|
if(move_area_to(get_turf(linked_port), target_turf, rotate))
|
|
|
|
linked_port.dock(D) //Dock our docking port with the destination
|
|
|
|
//****Move shuttles docked to us**
|
|
if(docked_shuttles.len)
|
|
for(var/datum/shuttle/S in docked_shuttles)
|
|
if(S in moved_shuttles)
|
|
continue
|
|
var/obj/docking_port/destination/our_moved_dock = docked_shuttles[S]
|
|
if(!our_moved_dock)
|
|
continue
|
|
|
|
moved_shuttles |= S
|
|
S.move_to_dock(our_moved_dock, ignore_innacuracy = 1)
|
|
|
|
log_game("[name] ([type]) moved to [D.areaname]")
|
|
|
|
current_port = D
|
|
|
|
after_flight() //Shake the shuttle, weaken unbuckled mobs, etc.
|
|
|
|
return 1
|
|
|
|
return
|
|
|
|
/datum/shuttle/proc/close_all_doors()
|
|
for(var/obj/machinery/door/unpowered/shuttle/D in linked_area)
|
|
spawn(0)
|
|
D.close()
|
|
|
|
/datum/shuttle/proc/open_all_doors()
|
|
for(var/obj/machinery/door/unpowered/shuttle/D in linked_area)
|
|
spawn(0)
|
|
D.open()
|
|
|
|
//Shakes cameras for mobs
|
|
/datum/shuttle/proc/after_flight()
|
|
for(var/atom/movable/AM in linked_area)
|
|
if(AM.anchored)
|
|
continue
|
|
|
|
if(istype(AM,/mob/living))
|
|
var/mob/living/M = AM
|
|
|
|
if(istype(AM,/mob/living/carbon/human) && disable_mesons)
|
|
var/mob/living/carbon/human/H = AM
|
|
if(istype(H.glasses,/obj/item/clothing/glasses/scanner/meson))
|
|
var/obj/item/clothing/glasses/scanner/meson/mesons = H.glasses
|
|
mesons.disable(H)
|
|
|
|
if(!M.locked_to)
|
|
shake_camera(M, 10, 1) // unbuckled, HOLY SHIT SHAKE THE ROOM
|
|
|
|
if(!src.stable)
|
|
if(istype(M, /mob/living/carbon))
|
|
M.Knockdown(3)
|
|
else
|
|
shake_camera(M, 3, 1) // buckled, not a lot of shaking
|
|
|
|
//Gibs or moves mobs and stuff
|
|
/datum/shuttle/proc/collide(var/atom/movable/AM as mob|obj)
|
|
AM.shuttle_act(src)
|
|
|
|
//This is awful
|
|
/datum/shuttle/proc/supercharge()
|
|
cooldown = 0
|
|
pre_flight_delay = 0
|
|
transit_delay = 0
|
|
|
|
//Like (input() in shuttles), but better
|
|
/proc/select_shuttle_from_all(var/mob/user, var/message = "Select a shuttle", var/title = "Shuttle selection", var/list/omit_shuttles = null, var/show_lockdown = 0, var/show_cooldown = 0)
|
|
if(!user)
|
|
return
|
|
|
|
var/list/shuttle_list = list()
|
|
for(var/datum/shuttle/S in shuttles)
|
|
if(omit_shuttles)
|
|
if(S.type in omit_shuttles)
|
|
continue
|
|
if(S in omit_shuttles)
|
|
continue
|
|
if(S.name in omit_shuttles)
|
|
continue
|
|
var/name = S.name
|
|
if(show_lockdown && S.lockdown)
|
|
name = "[name] (LOCKDOWN)"
|
|
else
|
|
if(show_cooldown && !S.can_move())
|
|
name = "[name] (ON COOLDOWN)"
|
|
shuttle_list += name
|
|
shuttle_list[name]=S
|
|
|
|
var/my_shuttle = input(usr, message, title) in shuttle_list as text|null
|
|
|
|
if( my_shuttle && shuttle_list[my_shuttle] && istype(shuttle_list[my_shuttle], /datum/shuttle) )
|
|
return shuttle_list[my_shuttle]
|
|
|
|
/datum/shuttle/proc/move(var/mob/user) //a very simple proc which selects a random area and sends the shuttle there
|
|
var/list/possible_locations = list()
|
|
for(var/obj/docking_port/destination/S in src.docking_ports)
|
|
if(S == current_port)
|
|
continue
|
|
if(S.docked_with)
|
|
continue
|
|
|
|
possible_locations += S
|
|
|
|
if(!possible_locations.len)
|
|
return
|
|
var/obj/docking_port/destination/target = pick(possible_locations)
|
|
|
|
travel_to(target,,user)
|
|
|
|
//The proc that does most of the work
|
|
//RETURNS: 1 if everything is good, 0 if everything is bad
|
|
/datum/shuttle/proc/move_area_to(var/turf/our_center, var/turf/new_center, var/rotate = 0)
|
|
if(!our_center)
|
|
return
|
|
if(!new_center)
|
|
return
|
|
if((rotate % 90) != 0) //If not divisible by 90, make it
|
|
rotate += (rotate % 90)
|
|
|
|
var/datum/coords/our_center_coords = new(our_center.x,our_center.y)
|
|
var/datum/coords/new_center_coords = new(new_center.x,new_center.y)
|
|
|
|
var/datum/coords/offset = new_center_coords.subtract(our_center_coords)
|
|
|
|
//For displacing
|
|
var/throwy = world.maxy
|
|
|
|
var/area/space
|
|
|
|
space = get_space_area()
|
|
if(!space)
|
|
warning("Unable to find space area for shuttle [src.type]")
|
|
|
|
//Make a list of coordinates of turfs to move, and associate the coordinates with the turfs they represent
|
|
var/list/turfs_to_move = list()
|
|
|
|
//Now here's the dumb part - since there's no fast way I know to check if a coord datum has a coord datum with the same values in a list,
|
|
//this coordinates list stores every coordinate of a moved turf as a string (example: "52;61").
|
|
var/list/our_own_turfs = list()
|
|
|
|
//Go through all turfs in our area
|
|
for(var/turf/T in linked_area.get_turfs())
|
|
var/datum/coords/C = new(T.x,T.y)
|
|
turfs_to_move += C
|
|
turfs_to_move[C] = T
|
|
|
|
our_own_turfs += "[T.x];[T.y];[T.z]"
|
|
|
|
var/cosine = cos(rotate)
|
|
var/sine = sin(rotate)
|
|
|
|
//Calculate new coordinates
|
|
var/list/new_turfs = list() //Coordinates of turfs that WILL be created
|
|
for(var/datum/coords/C in turfs_to_move)
|
|
var/datum/coords/new_coords = C.add(offset) //Get the coordinates of new turfs by adding offset
|
|
|
|
new_turfs += new_coords
|
|
new_turfs[new_coords] = C //Associate the old coordinates with the new ones for an easier time
|
|
|
|
if(rotate != 0)
|
|
//Oh god this works
|
|
|
|
var/newX = (cosine * (new_coords.x_pos - new_center.x)) + (sine * (new_coords.y_pos - new_center.y)) + new_center.x
|
|
var/newY = -(sine * (new_coords.x_pos - new_center.x)) + (cosine * (new_coords.y_pos - new_center.y)) + new_center.y
|
|
|
|
new_coords.x_pos = newX
|
|
new_coords.y_pos = newY
|
|
|
|
if(new_coords.y_pos < throwy)
|
|
throwy = new_coords.y_pos
|
|
|
|
var/area/A = get_area( locate(new_coords.x_pos, new_coords.y_pos, new_center.z) )
|
|
|
|
if(!A)
|
|
message_admins("<span class='notice'>WARNING: Unable to find an area at [new_coords.x_pos];[new_coords.y_pos];[new_center.z]. [src.name] ([src.type]) will not be moved.")
|
|
return
|
|
if(!destroy_everything && !A.shuttle_can_crush) //Breaking blueprint areas and space is fine, breaking the station is not. Breaking randomly generated vaults is fine, in case they spawn in a bad spot!
|
|
message_admins("<span class='notice'>WARNING: [src.name] ([src.type]) attempted to destroy [A] ([A.type]).</span> If you want [src.name] to be able to move freely and destroy areas, change its \"destroy_everything\" variable to 1.")
|
|
return
|
|
//If any of the new turfs are in the moved shuttle's current area, EMERGENCY ABORT (this leads to the shuttle destroying itself & potentially gibbing everybody inside)
|
|
if("[new_coords.x_pos];[new_coords.y_pos];[new_center.z]" in our_own_turfs)
|
|
warning("Shuttle ([src.name]; [src.type]) has attempted to move to a location which overlaps with its current position. Offending turf: [new_coords.x_pos];[new_coords.y_pos];[new_center.z]")
|
|
message_admins("WARNING: A shuttle ([src.name]; [src.type]) has attempted to move to a location which overlaps with its current position. The shuttle will not be moved.")
|
|
return
|
|
|
|
|
|
var/list/turfs_to_update = list()
|
|
|
|
//Move turfs
|
|
for(var/datum/coords/C in new_turfs)
|
|
//Get old turf type
|
|
var/datum/coords/old_C = new_turfs[C]
|
|
var/turf/old_turf = turfs_to_move[old_C]
|
|
var/turf/new_turf = locate(C.x_pos,C.y_pos,new_center.z)
|
|
var/add_underlay = 0
|
|
|
|
if(!old_turf)
|
|
message_admins("ERROR when moving [src.name] ([src.type]) - failed to get original turf at [old_C.x_pos];[old_C.y_pos];[our_center.z]")
|
|
continue
|
|
else if(old_turf.preserve_underlay == 0 && istype(old_turf,/turf/simulated/shuttle/wall)) //Varediting a turf's "preserve_underlay" to 1 will protect its underlay from being changed
|
|
if(old_turf.icon_state in transparent_icons)
|
|
add_underlay = 1
|
|
if(old_turf.underlays.len) //this list is in code/game/area/areas.dm
|
|
var/image/I = locate(/image) in old_turf.underlays //bandaid
|
|
if(I.icon == 'icons/turf/shuttle.dmi') //Don't change underlay to space if CURRENT underlay is a shuttle floor!
|
|
add_underlay = 0
|
|
|
|
if(!new_turf)
|
|
message_admins("ERROR when moving [src.name] ([src.type]) - failed to get new turf at [C.x_pos];[C.y_pos];[new_center.z]")
|
|
continue
|
|
|
|
var/turf/displace_to = locate(C.x_pos,throwy,new_center.z)
|
|
for(var/atom/movable/AM as mob|obj in new_turf.contents)
|
|
if(AM.anchored || src.collision_type == COLLISION_DESTROY)
|
|
src.collide(AM)
|
|
else
|
|
AM.forceMove(displace_to)
|
|
|
|
var/area/old_area = get_area(new_turf)
|
|
if(!old_area)
|
|
old_area = space
|
|
|
|
//Get the turf's image before it's gone!
|
|
var/image/undlay
|
|
if(add_underlay)
|
|
undlay = image("icon"=new_turf.icon,"icon_state"=new_turf.icon_state,"dir"=new_turf.dir)
|
|
undlay.overlays = new_turf.overlays
|
|
|
|
//****Add the new turf to shuttle's area****
|
|
|
|
linked_area.contents.Add(new_turf)
|
|
new_turf.change_area(old_area,linked_area)
|
|
new_turf.ChangeTurf(old_turf.type, allow = 1)
|
|
new_turfs[C] = new_turf
|
|
|
|
//***Remove old turf from shuttle's area****
|
|
|
|
space.contents.Add(old_turf)
|
|
old_turf.change_area(linked_area,space)
|
|
|
|
//All objects which can't be moved by the shuttle have their area changed to space!
|
|
for(var/atom/movable/AM in old_turf.contents)
|
|
if(!AM.can_shuttle_move(src))
|
|
AM.change_area(linked_area,space)
|
|
|
|
//****Move all variables from the old turf over to the new turf****
|
|
|
|
for(var/key in old_turf.vars)
|
|
if(key in ignored_keys)
|
|
continue
|
|
//ignored_keys: code/game/area/areas.dm, 526 (above the move_contents_to proc)
|
|
//as of 06/08/2015: list("loc", "locs", "parent_type", "vars", "verbs", "type", "x", "y", "z","group","contents","air","light","areaMaster","underlays","lighting_overlay")
|
|
if(istype(old_turf.vars[key],/list))
|
|
var/list/L = old_turf.vars[key]
|
|
new_turf.vars[key] = L.Copy()
|
|
else if(old_turf.vars)
|
|
new_turf.vars[key] = old_turf.vars[key]
|
|
if(old_turf.transform)
|
|
new_turf.transform = old_turf.transform
|
|
|
|
//****Prepare underlays**** (only do this if add_underlay is 1 -> see above)
|
|
if(add_underlay && undlay)
|
|
new_turf.underlays = list(undlay) //Remove all old underlays, add space
|
|
else
|
|
new_turf.underlays = old_turf.underlays
|
|
/*
|
|
if(ispath(replaced_turf_type,/turf/space))//including the transit hyperspace turfs
|
|
if(old_turf.underlays.len)
|
|
new_turf.underlays = old_turf.underlays
|
|
else
|
|
new_turf.underlays += undlay
|
|
else
|
|
new_turf.underlays += undlay*/
|
|
|
|
new_turf.dir = old_turf.dir
|
|
new_turf.icon_state = old_turf.icon_state
|
|
new_turf.icon = old_turf.icon
|
|
if(rotate)
|
|
new_turf.shuttle_rotate(rotate)
|
|
|
|
//*****Move air*****
|
|
|
|
var/turf/simulated/S_OLD = old_turf
|
|
|
|
if(istype(S_OLD) && S_OLD.zone)
|
|
var/turf/simulated/S_NEW = new_turf
|
|
|
|
if(!S_NEW.air)
|
|
S_NEW.make_air()
|
|
|
|
S_NEW.air.copy_from(S_OLD.zone.air)
|
|
S_OLD.zone.remove(S_OLD)
|
|
|
|
//*****Move objects and mobs*****
|
|
for(var/atom/movable/AM in old_turf)
|
|
if(!AM.can_shuttle_move(src))
|
|
continue
|
|
|
|
if(AM.bound_width > WORLD_ICON_SIZE || AM.bound_height > WORLD_ICON_SIZE) //If the moved object's bounding box is more than the default, move it after everything else (using spawn())
|
|
AM.forceMove(null) //Without this, ALL neighbouring turfs attempt to move this object too, resulting in the object getting shifted to north/east
|
|
|
|
spawn()
|
|
AM.forceMove(new_turf)
|
|
|
|
//TODO: Make this compactible with bound_x and bound_y.
|
|
else
|
|
AM.forceMove(new_turf)
|
|
|
|
if(rotate)
|
|
AM.shuttle_rotate(rotate)
|
|
|
|
//Move landmarks - for moving the arrivals shuttle
|
|
for(var/list/L in moved_landmarks) //moved_landmarks: code/game/area/areas.dm, 527 (above the move_contents_to proc)
|
|
if(old_turf in L)
|
|
L -= old_turf
|
|
L += new_turf
|
|
|
|
//Add the new turf to the list of turfs to update
|
|
turfs_to_update += new_turf
|
|
|
|
//Delete the old turf
|
|
var/replacing_turf_type = old_turf.get_underlying_turf()
|
|
var/obj/docking_port/destination/D = linked_port.docked_with
|
|
|
|
if(D && istype(D))
|
|
replacing_turf_type = D.base_turf_type
|
|
|
|
old_turf.ChangeTurf(replacing_turf_type, allow = 1)
|
|
|
|
if(D && istype(D))
|
|
if(D.base_turf_icon)
|
|
old_turf.icon = D.base_turf_icon
|
|
if(D.base_turf_icon_state)
|
|
old_turf.icon_state = D.base_turf_icon_state
|
|
|
|
if(istype(old_turf,/turf/space))
|
|
old_turf.lighting_clear_overlay() //A horrible band-aid fix for lighting overlays appearing over space
|
|
|
|
//Update doors
|
|
if(turfs_to_update.len)
|
|
for(var/turf/simulated/T1 in turfs_to_update)
|
|
for(var/obj/machinery/door/D2 in T1)
|
|
D2.update_nearby_tiles()
|
|
|
|
return 1
|
|
|
|
/proc/setup_shuttles()
|
|
world.log << "Setting up all shuttles..."
|
|
|
|
var/all_count = 0
|
|
var/count = 0
|
|
for(var/datum/shuttle/S in shuttles)
|
|
switch(S.initialize())
|
|
if(INIT_NO_AREA)
|
|
if(S.is_special())
|
|
var/msg = S.linked_area ? "- \"[S.linked_area]\" was given as a starting area." : ""
|
|
warning("Invalid or missing starting area for [S.name] ([S.type]) [msg]")
|
|
else
|
|
var/msg = S.linked_area ? "- \"[S.linked_area]\" was given as a starting area." : ""
|
|
world.log << "Invalid or missing starting area for [S.name] ([S.type]) [msg]"
|
|
if(INIT_NO_PORT)
|
|
if(S.is_special())
|
|
warning("Couldn't find a shuttle docking port for [S.name] ([S.type]).")
|
|
else
|
|
world.log << "Couldn't find a shuttle docking port for [S.name] ([S.type])."
|
|
if(INIT_NO_START)
|
|
if(S.is_special())
|
|
warning("[S.name] ([S.type]) couldn't connect to a destination port on init - unless this is intended, there might be problems.")
|
|
else
|
|
world.log << "[S.name] ([S.type]) couldn't connect to a destination port on init - unless this is intended, there might be problems."
|
|
else
|
|
count++
|
|
all_count++
|
|
|
|
world.log << "[all_count] shuttles initialized, of them [count] were initialized properly."
|
|
|
|
//THE MOST IMPORTANT PIECE OF CODE HERE
|
|
emergency_shuttle.shuttle = escape_shuttle
|
|
|
|
if(!emergency_shuttle || !emergency_shuttle.shuttle)
|
|
warning("Emergency shuttle is broken.")
|
|
else
|
|
world.log << "Emergency shuttle has been successfully set up."
|
|
|
|
//Custom shuttles
|
|
/datum/shuttle/custom
|
|
name = "custom shuttle"
|
|
|
|
/datum/shuttle/proc/show_outline(var/mob/user, var/turf/centered_at)
|
|
if(!user)
|
|
return
|
|
|
|
if(!centered_at)
|
|
var/turf/user_turf = get_turf(user)
|
|
if(!user_turf)
|
|
to_chat(user, "You must be standing on a turf!")
|
|
return
|
|
|
|
centered_at = get_step(user_turf,usr.dir)
|
|
|
|
var/turf/original_center = get_turf(linked_port)
|
|
|
|
if(!centered_at)
|
|
to_chat(user, "ERROR: Unable to find center turf!")
|
|
return
|
|
|
|
var/offsetX = centered_at.x - original_center.x
|
|
var/offsetY = centered_at.y - original_center.y
|
|
var/datum/coords/offset = new(offsetX,offsetY)
|
|
|
|
var/rotate = dir2angle(turn(user.dir,180)) - dir2angle(linked_port.dir)
|
|
|
|
var/list/original_coords = list()
|
|
for(var/turf/T in linked_area.get_turfs())
|
|
var/datum/coords/C = new(T.x,T.y)
|
|
original_coords += C
|
|
|
|
var/list/new_coords = list()
|
|
|
|
var/cosine = cos(rotate)
|
|
var/sine = sin(rotate)
|
|
|
|
for(var/datum/coords/C in original_coords)
|
|
var/datum/coords/NC = C.add(offset)
|
|
new_coords += NC
|
|
|
|
if(rotate)
|
|
var/newX = (cosine * (NC.x_pos - centered_at.x)) + (sine * (NC.y_pos - centered_at.y)) + centered_at.x
|
|
var/newY = -(sine * (NC.x_pos - centered_at.x)) + (cosine * (NC.y_pos - centered_at.y)) + centered_at.y
|
|
|
|
NC.x_pos = newX
|
|
NC.y_pos = newY
|
|
|
|
var/list/images = list()
|
|
for(var/datum/coords/C in new_coords)
|
|
var/turf/T = locate(C.x_pos,C.y_pos,centered_at.z)
|
|
if(!T)
|
|
continue
|
|
|
|
var/image/I = image('icons/turf/areas.dmi', icon_state="bluenew")
|
|
I.loc = T
|
|
images += I
|
|
user << I
|
|
|
|
var/image/center_img = image('icons/turf/areas.dmi', icon_state="blue") //This is actually RED, honk
|
|
center_img.loc = centered_at
|
|
images += center_img
|
|
user << center_img
|
|
|
|
alert(usr,"Press \"Ok\" to remove the images","Magic","Ok")
|
|
|
|
if(usr.client)
|
|
for(var/image/I in images)
|
|
usr.client.images -= I
|
|
return
|
|
|
|
#undef INIT_SUCCESS
|
|
#undef INIT_NO_AREA
|
|
#undef INIT_NO_PORT
|
|
#undef INIT_NO_START
|