/
shuttle.dm
296 lines (248 loc) · 10.7 KB
/
shuttle.dm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
//shuttle moving state defines are in setup.dm
/datum/shuttle
var/name = ""
var/warmup_time = 0
var/moving_status = SHUTTLE_IDLE
var/list/shuttle_area //can be both single area type or a list of areas
var/obj/shuttle_landmark/current_location //This variable is type-abused initially: specify the landmark_tag, not the actual landmark.
var/arrive_time = 0 //the time at which the shuttle arrives when long jumping
var/flags = 0
var/process_state = IDLE_STATE //Used with SHUTTLE_FLAGS_PROCESS, as well as to store current state.
var/category = /datum/shuttle
var/multiz = 0 //how many multiz levels, starts at 0
var/ceiling_type = /turf/unsimulated/floor/shuttle_ceiling
var/sound_takeoff = 'sound/effects/shuttle_takeoff.ogg'
var/sound_landing = 'sound/effects/shuttle_landing.ogg'
var/knockdown = 1 //whether shuttle downs non-buckled people when it moves
var/defer_initialisation = FALSE //this shuttle will/won't be initialised automatically. If set to true, you are responsible for initialzing the shuttle manually.
//Useful for shuttles that are initialed by map_template loading, or shuttles that are created in-game or not used.
var/logging_home_tag //Whether in-game logs will be generated whenever the shuttle leaves/returns to the landmark with this landmark_tag.
var/logging_access //Controls who has write access to log-related stuff; should correlate with pilot access.
var/mothershuttle //tag of mothershuttle
var/motherdock //tag of mothershuttle landmark, defaults to starting location
/datum/shuttle/New(_name, obj/shuttle_landmark/initial_location)
..()
if(_name)
src.name = _name
var/list/areas = list()
if(!islist(shuttle_area))
shuttle_area = list(shuttle_area)
for(var/T in shuttle_area)
var/area/A = locate(T)
if(!istype(A))
CRASH("Shuttle \"[name]\" couldn't locate area [T].")
areas += A
shuttle_area = areas
if(initial_location)
current_location = initial_location
else
current_location = SSshuttle.get_landmark(current_location)
if(!istype(current_location))
CRASH("Shuttle \"[name]\" could not find its starting location.")
if(src.name in SSshuttle.shuttles)
CRASH("A shuttle with the name '[name]' is already defined.")
SSshuttle.shuttles[src.name] = src
if(logging_home_tag)
new /datum/shuttle_log(src)
if(flags & SHUTTLE_FLAGS_PROCESS)
SSshuttle.process_shuttles += src
if(flags & SHUTTLE_FLAGS_SUPPLY)
if(SSsupply.shuttle)
CRASH("A supply shuttle is already defined.")
SSsupply.shuttle = src
/datum/shuttle/Destroy()
current_location = null
SSshuttle.shuttles -= src.name
SSshuttle.process_shuttles -= src
SSshuttle.shuttle_logs -= src
if(SSsupply.shuttle == src)
SSsupply.shuttle = null
. = ..()
/datum/shuttle/proc/short_jump(obj/shuttle_landmark/destination)
if(moving_status != SHUTTLE_IDLE) return
moving_status = SHUTTLE_WARMUP
if(sound_takeoff)
playsound(current_location, sound_takeoff, 100, 20, 0.2)
spawn(warmup_time*10)
if (moving_status == SHUTTLE_IDLE)
return //someone cancelled the launch
if(!fuel_check()) //fuel error (probably out of fuel) occured, so cancel the launch
var/datum/shuttle/autodock/S = src
if(istype(S))
S.cancel_launch(null)
return
moving_status = SHUTTLE_INTRANSIT //shouldn't matter but just to be safe
attempt_move(destination)
moving_status = SHUTTLE_IDLE
/datum/shuttle/proc/long_jump(obj/shuttle_landmark/destination, obj/shuttle_landmark/interim, travel_time)
if(moving_status != SHUTTLE_IDLE) return
var/obj/shuttle_landmark/start_location = current_location
moving_status = SHUTTLE_WARMUP
if(sound_takeoff)
playsound(current_location, sound_takeoff, 100, 20, 0.2)
if (!istype(start_location.base_area, /area/space))
var/area/A = get_area(start_location)
for (var/mob/M in GLOB.player_list)
if (M.client && M.z == A.z && !istype(get_turf(M), /turf/space) && !(get_area(M) in src.shuttle_area))
to_chat(M, SPAN_NOTICE("The rumble of engines are heard as a shuttle lifts off."))
spawn(warmup_time*10)
if(moving_status == SHUTTLE_IDLE)
return //someone cancelled the launch
if(!fuel_check()) //fuel error (probably out of fuel) occured, so cancel the launch
var/datum/shuttle/autodock/S = src
if(istype(S))
S.cancel_launch(null)
return
arrive_time = world.time + travel_time*10
moving_status = SHUTTLE_INTRANSIT
if(attempt_move(interim))
var/fwooshed = 0
while (world.time < arrive_time)
if(!fwooshed && (arrive_time - world.time) < 100)
fwooshed = 1
playsound(destination, sound_landing, 100, 0, 7)
if (!istype(destination.base_area, /area/space))
var/area/A = get_area(destination)
for (var/mob/M in GLOB.player_list)
if (M.client && M.z == A.z && !istype(get_turf(M), /turf/space) && !(get_area(M) in src.shuttle_area))
to_chat(M, SPAN_NOTICE("The rumble of a shuttle's engines fill the area as a ship manuevers in for a landing."))
sleep(5)
if(!attempt_move(destination))
attempt_move(start_location) //try to go back to where we started. If that fails, I guess we're stuck in the interim location
moving_status = SHUTTLE_IDLE
/datum/shuttle/proc/fuel_check()
return 1 //fuel check should always pass in non-overmap shuttles (they have magic engines)
/*****************
* Shuttle Moved Handling * (Observer Pattern Implementation: Shuttle Moved)
* Shuttle Pre Move Handling * (Observer Pattern Implementation: Shuttle Pre Move)
*****************/
/datum/shuttle/proc/attempt_move(obj/shuttle_landmark/destination)
if(current_location == destination)
return FALSE
if(!destination.is_valid(src))
return FALSE
if(current_location.cannot_depart(src))
return FALSE
testing("[src] moving to [destination]. Areas are [english_list(shuttle_area)]")
var/list/translation = list()
for(var/area/A in shuttle_area)
testing("Moving [A]")
translation += get_turf_translation(get_turf(current_location), get_turf(destination), A.contents)
var/old_location = current_location
GLOB.shuttle_pre_move_event.raise_event(src, old_location, destination)
shuttle_moved(destination, translation)
GLOB.shuttle_moved_event.raise_event(src, old_location, destination)
destination.shuttle_arrived(src)
// + BANDAID
// /obj/machinery/proc/area_changed and /proc/translate_turfs cause problems with power cost duplication.
var/list/area/retally_areas
if (isarea(shuttle_area))
retally_areas = list(shuttle_area)
else if (islist(shuttle_area))
retally_areas = shuttle_area
for (var/area/area as anything in retally_areas)
area.retally_power()
// - BANDAID
return TRUE
//just moves the shuttle from A to B, if it can be moved
//A note to anyone overriding move in a subtype. shuttle_moved() must absolutely not, under any circumstances, fail to move the shuttle.
//If you want to conditionally cancel shuttle launches, that logic must go in short_jump(), long_jump() or attempt_move()
/datum/shuttle/proc/shuttle_moved(obj/shuttle_landmark/destination, list/turf_translation)
// log_debug("move_shuttle() called for [shuttle_tag] leaving [origin] en route to [destination].")
// log_degug("area_coming_from: [origin]")
// log_debug("destination: [destination]")
if((flags & SHUTTLE_FLAGS_ZERO_G))
var/new_grav = 1
if(destination.flags & SLANDMARK_FLAG_ZERO_G)
var/area/new_area = get_area(destination)
new_grav = new_area.has_gravity
for(var/area/our_area in shuttle_area)
if(our_area.has_gravity != new_grav)
our_area.gravitychange(new_grav)
for(var/turf/src_turf in turf_translation)
var/turf/dst_turf = turf_translation[src_turf]
if(src_turf.is_solid_structure()) //in case someone put a hole in the shuttle and you were lucky enough to be under it
for(var/atom/movable/AM in dst_turf)
if(!AM.simulated)
continue
AM.shuttle_land_on()
var/list/powernets = list()
for(var/area/A in shuttle_area)
// if there was a zlevel above our origin, erase our ceiling now we're leaving
if(HasAbove(current_location.z))
for(var/turf/TO in A.contents)
var/turf/TA = GetAbove(TO)
if(istype(TA, ceiling_type))
TA.ChangeTurf(get_base_turf_by_area(TA), 1, 1)
if(knockdown)
for(var/mob/M in A)
spawn(0)
if(istype(M, /mob/living/carbon))
if(M.buckled)
to_chat(M, SPAN_WARNING("Sudden acceleration presses you into your chair!"))
shake_camera(M, 3, 1)
else
to_chat(M, SPAN_WARNING("The floor lurches beneath you!"))
shake_camera(M, 10, 1)
M.visible_message(SPAN_WARNING("[M.name] is tossed around by the sudden acceleration!"))
M.throw_at_random(FALSE, 4, 1)
for(var/obj/structure/cable/C in A)
powernets |= C.powernet
if(logging_home_tag)
var/datum/shuttle_log/s_log = SSshuttle.shuttle_logs[src]
s_log.handle_move(current_location, destination)
translate_turfs(turf_translation, current_location.base_area, current_location.base_turf)
current_location = destination
// if there's a zlevel above our destination, paint in a ceiling on it so we retain our air
if(HasAbove(current_location.z))
for(var/area/A in shuttle_area)
for(var/turf/TD in A.contents)
var/turf/TA = GetAbove(TD)
if(istype(TA, get_base_turf_by_area(TA)) || istype(TA, /turf/simulated/open))
if(get_area(TA) in shuttle_area)
continue
TA.ChangeTurf(ceiling_type, TRUE, TRUE, TRUE)
// Remove all powernets that were affected, and rebuild them.
var/list/cables = list()
for(var/datum/powernet/P in powernets)
cables |= P.cables
qdel(P)
for(var/obj/structure/cable/C in cables)
if(!C.powernet)
var/datum/powernet/NewPN = new()
NewPN.add_cable(C)
propagate_network(C,C.powernet)
if(mothershuttle)
var/datum/shuttle/mothership = SSshuttle.shuttles[mothershuttle]
if(mothership)
if(current_location.landmark_tag == motherdock)
mothership.shuttle_area |= shuttle_area
else
mothership.shuttle_area -= shuttle_area
/// Handler for shuttles landing on atoms. Called by `shuttle_moved()`.
/atom/movable/proc/shuttle_land_on()
qdel(src)
/mob/living/shuttle_land_on()
gib()
//returns 1 if the shuttle has a valid arrive time
/datum/shuttle/proc/has_arrive_time()
return (moving_status == SHUTTLE_INTRANSIT)
/datum/shuttle/proc/find_children()
. = list()
for(var/shuttle_name in SSshuttle.shuttles)
var/datum/shuttle/shuttle = SSshuttle.shuttles[shuttle_name]
if(shuttle.mothershuttle == name)
. += shuttle
//Returns those areas that are not actually child shuttles.
/datum/shuttle/proc/find_childfree_areas()
. = shuttle_area.Copy()
for(var/datum/shuttle/child in find_children())
. -= child.shuttle_area
/datum/shuttle/autodock/proc/get_location_name()
if(moving_status == SHUTTLE_INTRANSIT)
return "In transit"
return current_location.name
/datum/shuttle/autodock/proc/get_destination_name()
if(!next_location)
return "None"
return next_location.name