7
7
if (! apply_parallax_pref(viewmob)) // don't want shit computers to crash when specing someone with insane parallax, so use the viewer's pref
8
8
return
9
9
10
+ if (isnull(C. parallax_master))
11
+ C. parallax_master = new (null , src )
12
+
13
+ C. screen |= C. parallax_master
14
+
10
15
if (! length(C. parallax_layers_cached))
11
16
C. parallax_layers_cached = list ()
12
17
C. parallax_layers_cached += new / atom/movable / screen/ parallax_layer/ layer_1(null , src )
17
22
if (length(C. parallax_layers) > C. parallax_layers_max)
18
23
C. parallax_layers. len = C. parallax_layers_max
19
24
20
- C. screen |= (C. parallax_layers)
25
+ C. parallax_master. vis_contents = C. parallax_layers
26
+
21
27
var /atom/movable /screen/plane_master/PM = screenmob. hud_used. plane_masters[" [ PLANE_SPACE ] " ]
22
28
if (screenmob != mymob)
23
29
C. screen -= locate (/ atom/movable / screen/ plane_master/ parallax_white) in C. screen
24
30
C. screen += PM
31
+
25
32
PM . color = list (
26
33
0 , 0 , 0 , 0 ,
27
34
0 , 0 , 0 , 0 ,
34
41
/ datum / hud/ proc / remove_parallax( mob / viewmob)
35
42
var /mob /screenmob = viewmob || mymob
36
43
var /client /C = screenmob. client
37
- C. screen -= (C. parallax_layers_cached)
44
+ C. screen -= C. parallax_master
45
+
38
46
var /atom/movable /screen/plane_master/PM = screenmob. hud_used. plane_masters[" [ PLANE_SPACE ] " ]
39
47
if (screenmob != mymob)
40
48
C. screen -= locate (/ atom/movable / screen/ plane_master/ parallax_white) in C. screen
41
49
C. screen += PM
50
+
42
51
PM . color = initial(PM . color)
43
52
C. parallax_layers = null
44
53
92
101
var /client /C = screenmob. client
93
102
if (new_parallax_movedir == C. parallax_movedir)
94
103
return
95
- var /animatedir = new_parallax_movedir
96
- if (new_parallax_movedir == FALSE )
97
- var /animate_time = 0
98
- for (var /atom/movable /screen/parallax_layer/L as anything in C. parallax_layers)
99
- L. icon_state = initial(L. icon_state)
100
- L. update_o(C. view)
101
- var /T = PARALLAX_LOOP_TIME / L. speed
102
- if (T > animate_time)
103
- animate_time = T
104
- C. dont_animate_parallax = world . time + min(animate_time, PARALLAX_LOOP_TIME )
105
- animatedir = C. parallax_movedir
106
-
107
- var /matrix /newtransform
108
- switch (animatedir)
104
+
105
+ var /animation_dir = new_parallax_movedir || C. parallax_movedir
106
+ var /matrix /new_transform
107
+ switch (animation_dir)
109
108
if (NORTH )
110
- newtransform = matrix(1 , 0 , 0 , 0 , 1 , PARALLAX_ICON_SIZE )
109
+ new_transform = matrix(1 , 0 , 0 , 0 , 1 , PARALLAX_ICON_SIZE )
111
110
if (SOUTH )
112
- newtransform = matrix(1 , 0 , 0 , 0 , 1 ,- PARALLAX_ICON_SIZE )
111
+ new_transform = matrix(1 , 0 , 0 , 0 , 1 ,- PARALLAX_ICON_SIZE )
113
112
if (EAST )
114
- newtransform = matrix(1 , 0 , PARALLAX_ICON_SIZE , 0 , 1 , 0 )
113
+ new_transform = matrix(1 , 0 , PARALLAX_ICON_SIZE , 0 , 1 , 0 )
115
114
if (WEST )
116
- newtransform = matrix(1 , 0 ,- PARALLAX_ICON_SIZE , 0 , 1 , 0 )
117
-
118
- var /shortesttimer
119
- if (! skip_windups)
120
- for (var /atom/movable /screen/parallax_layer/L as anything in C. parallax_layers)
121
- var /T = PARALLAX_LOOP_TIME / L. speed
122
- if (isnull(shortesttimer))
123
- shortesttimer = T
124
- if (T < shortesttimer)
125
- shortesttimer = T
126
- L. transform = newtransform
127
- animate (L, transform = matrix(), time = T, easing = QUAD_EASING | (new_parallax_movedir ? EASE_IN : EASE_OUT ), flags = ANIMATION_END_NOW )
128
- if (new_parallax_movedir)
129
- L. transform = newtransform
130
- animate (transform = matrix(), time = T) // queue up another animate so lag doesn't create a shutter
115
+ new_transform = matrix(1 , 0 ,- PARALLAX_ICON_SIZE , 0 , 1 , 0 )
131
116
132
- C. parallax_movedir = new_parallax_movedir
133
- if (C. parallax_animate_timer)
134
- deltimer (C. parallax_animate_timer)
135
- var /datum /callback/CB = CALLBACK (src , PROC_REF (update_parallax_motionblur), C, animatedir, new_parallax_movedir, newtransform)
136
- if (skip_windups)
137
- CB . Invoke()
138
- else
139
- C. parallax_animate_timer = addtimer(CB , min(shortesttimer, PARALLAX_LOOP_TIME ), TIMER_CLIENT_TIME | TIMER_STOPPABLE )
117
+ var /longest_timer = 0
118
+ for (var /key in C. parallax_animate_timers)
119
+ deltimer (C. parallax_animate_timers[key])
120
+ C. parallax_animate_timers = list ()
140
121
122
+ for (var /atom/movable /screen/parallax_layer/layer as anything in C. parallax_layers)
123
+ var /scaled_time = PARALLAX_LOOP_TIME / layer. speed
124
+ if (new_parallax_movedir == NONE ) // If we're stopping, we need to stop on the same dime, yeah?
125
+ scaled_time = PARALLAX_LOOP_TIME
126
+ longest_timer = max(longest_timer, scaled_time)
141
127
142
- / datum / hud/ proc / update_parallax_motionblur( client / C, animatedir, new_parallax_movedir, matrix / newtransform)
143
- if (! C)
144
- return
145
- C. parallax_animate_timer = FALSE
146
- for (var /thing in C. parallax_layers)
147
- var /atom/movable /screen/parallax_layer/L = thing
148
- if (! new_parallax_movedir)
149
- animate (L)
128
+ if (skip_windups)
129
+ update_parallax_motionblur (C, layer, new_parallax_movedir, new_transform)
150
130
continue
151
131
152
- var /newstate = initial(L. icon_state)
153
- var /T = PARALLAX_LOOP_TIME / L. speed
132
+ layer. transform = new_transform
133
+ animate (layer, transform = matrix(), time = scaled_time, easing = QUAD_EASING | (new_parallax_movedir ? EASE_IN : EASE_OUT ))
134
+ if (new_parallax_movedir == NONE )
135
+ continue
154
136
155
- if (newstate in icon_states (L. icon))
156
- L. icon_state = newstate
157
- L. update_o(C. view)
137
+ // queue up another animate so lag doesn't create a shutter
138
+ animate (transform = new_transform, time = 0 )
139
+ animate (transform = matrix(), time = scaled_time / 2 )
140
+ C. parallax_animate_timers[layer] = addtimer(CALLBACK (src , PROC_REF (update_parallax_motionblur), C, layer, new_parallax_movedir, new_transform), scaled_time, TIMER_CLIENT_TIME | TIMER_STOPPABLE )
158
141
159
- L. transform = newtransform
142
+ C. dont_animate_parallax = world . time + min(longest_timer, PARALLAX_LOOP_TIME )
143
+ C. parallax_movedir = new_parallax_movedir
144
+
145
+ / datum / hud/ proc / update_parallax_motionblur( client / C, atom/movable / screen/ parallax_layer/ layer, new_parallax_movedir, matrix / new_transform)
146
+ if (! C)
147
+ return
160
148
161
- animate (L, transform = L. transform, time = 0 , loop = - 1 , flags = ANIMATION_END_NOW )
162
- animate (transform = matrix(), time = T)
149
+ C. parallax_animate_timers -= layer
150
+
151
+ // If we are moving in a direction, we used the QUAD_EASING function with EASE_IN
152
+ // This means our position function is x^2. This is always LESS then the linear we're using here
153
+ // But if we just used the same time delay, our rate of change would mismatch. f'(1) = 2x for quad easing, rather then the 1 we get for linear
154
+ // (This is because of how derivatives work right?)
155
+ // Because of this, while our actual rate of change from before was PARALLAX_LOOP_TIME, our perceived rate of change was PARALLAX_LOOP_TIME / 2 (lower == faster).
156
+ // Let's account for that here
157
+ var /scaled_time = (PARALLAX_LOOP_TIME / layer. speed) / 2
158
+ animate (layer, transform = new_transform, time = 0 , loop = - 1 , flags = ANIMATION_END_NOW )
159
+ animate (transform = matrix(), time = scaled_time)
163
160
164
161
/ datum / hud/ proc / update_parallax( mob / viewmob)
165
162
var /mob /screenmob = viewmob || mymob
196
193
var /our_speed = parallax_layer. speed
197
194
var /change_x
198
195
var /change_y
196
+ var /old_x = parallax_layer. offset_x
197
+ var /old_y = parallax_layer. offset_y
198
+
199
199
if (parallax_layer. absolute)
200
200
// We use change here so the typically large absolute objects don't jitter so much
201
- change_x = (posobj. x - SSparallax. planet_x_offset) * our_speed + parallax_layer . offset_x
202
- change_y = (posobj. y - SSparallax. planet_y_offset) * our_speed + parallax_layer . offset_y
201
+ change_x = (posobj. x - SSparallax. planet_x_offset) * our_speed + old_x
202
+ change_y = (posobj. y - SSparallax. planet_y_offset) * our_speed + old_y
203
203
else
204
204
change_x = offset_x * our_speed
205
205
change_y = offset_y * our_speed
206
206
207
207
// This is how we tile parralax sprites
208
208
// It doesn't use change because we really don't want to animate this
209
- if (parallax_layer . offset_x - change_x > PARALLAX_ICON_SIZE / 2 )
209
+ if (old_x - change_x > PARALLAX_ICON_SIZE / 2 )
210
210
parallax_layer. offset_x -= PARALLAX_ICON_SIZE
211
- else if (parallax_layer . offset_x - change_x < - (PARALLAX_ICON_SIZE / 2 ))
211
+ else if (old_x - change_x < - (PARALLAX_ICON_SIZE / 2 ))
212
212
parallax_layer. offset_x += PARALLAX_ICON_SIZE
213
- if (parallax_layer . offset_y - change_y > PARALLAX_ICON_SIZE / 2 )
213
+ if (old_y - change_y > PARALLAX_ICON_SIZE / 2 )
214
214
parallax_layer. offset_y -= PARALLAX_ICON_SIZE
215
- else if (parallax_layer . offset_y - change_y < - (PARALLAX_ICON_SIZE / 2 ))
215
+ else if (old_y - change_y < - (PARALLAX_ICON_SIZE / 2 ))
216
216
parallax_layer. offset_y += PARALLAX_ICON_SIZE
217
217
218
- // Now that we have our offsets, let's do our positioning
219
218
parallax_layer. offset_x -= change_x
220
219
parallax_layer. offset_y -= change_y
221
220
222
- parallax_layer. screen_loc = " CENTER-7:[ round(parallax_layer. offset_x, 1 )] ,CENTER-7: [ round(parallax_layer. offset_y, 1 )] "
223
-
224
- // We're going to use a transform to "glide" that last movement out, so it looks nicer
221
+ // Now that we have our offsets, let's do our positioning
222
+ // We're going to use an animate to "glide" that last movement out, so it looks nicer
225
223
// Don't do any animates if we're not actually moving enough distance yeah? thanks lad
226
224
if (run_parralax && (largest_change * our_speed > 1 ))
227
- parallax_layer. transform = matrix(1 ,0 ,change_x, 0 ,1 ,change_y)
228
- animate (parallax_layer, transform= matrix(), time = glide_rate)
225
+ animate (parallax_layer, pixel_x = round(parallax_layer. offset_x, 1 ), pixel_y = round(parallax_layer. offset_y, 1 ), time = glide_rate)
226
+ else
227
+ parallax_layer. pixel_x = round(parallax_layer. offset_x, 1 )
228
+ parallax_layer. pixel_y = round(parallax_layer. offset_y, 1 )
229
229
230
230
/ atom/movable / proc / update_parallax_contents()
231
231
for (var /mob /client_mob as anything in client_mobs_in_contents)
237
237
var /area /areaobj = get_area(client. eye)
238
238
hud_used. set_parallax_movedir(areaobj. parallax_movedir, TRUE )
239
239
240
+ // Root object for parallax, all parallax layers are drawn onto this
241
+ INITIALIZE_IMMEDIATE (/ atom/movable / screen/ parallax_root)
242
+ / atom/movable / screen/ parallax_root
243
+ icon = null
244
+ blend_mode = BLEND_ADD
245
+ plane = PLANE_SPACE_PARALLAX
246
+ screen_loc = " CENTER-7,CENTER-7"
247
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
248
+
240
249
// We need parallax to always pass its args down into initialize, so we immediate init it
241
250
INITIALIZE_IMMEDIATE (/ atom/movable / screen/ parallax_layer)
242
251
/ atom/movable / screen/ parallax_layer
@@ -246,17 +255,16 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/parallax_layer)
246
255
var /offset_y = 0
247
256
var /view_sized
248
257
var /absolute = FALSE
249
- appearance_flags = APPEARANCE_UI | TILE_BOUND
258
+ appearance_flags = APPEARANCE_UI | TILE_BOUND | KEEP_TOGETHER
250
259
blend_mode = BLEND_ADD
251
260
plane = PLANE_SPACE_PARALLAX
252
- screen_loc = " CENTER-7,CENTER-7"
253
261
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
254
262
255
263
/ atom/movable / screen/ parallax_layer/ Initialize(mapload, datum / hud/ hud_owner)
256
264
. = .. ()
257
265
// Parallax layers are independant of hud, they care about client
258
266
// Not doing this will just create a bunch of hard deletes
259
- hud = null
267
+ set_new_hud ( null )
260
268
261
269
var /client /boss = hud_owner?. mymob?. canon_client
262
270
@@ -280,16 +288,20 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/parallax_layer)
280
288
281
289
// Turn the view size into a grid of correctly scaled overlays
282
290
var /list /viewscales = getviewsize(view)
291
+ // This could be half the size but we need to provide space for parallax movement on mob movement, and movement on scroll from shuttles, so like this instead
283
292
var /countx = CEILING ((viewscales[1 ] / 2 ) * parallax_scaler, 1 ) + 1
284
293
var /county = CEILING ((viewscales[2 ] / 2 ) * parallax_scaler, 1 ) + 1
285
294
var /list /new_overlays = new
286
295
for (var /x in - countx to countx)
287
296
for (var /y in - county to county)
288
297
if (x == 0 && y == 0 )
289
298
continue
299
+
290
300
var /mutable_appearance /texture_overlay = mutable_appearance(icon, icon_state)
291
- texture_overlay. transform = matrix(1 , 0 , x* PARALLAX_ICON_SIZE , 0 , 1 , y* PARALLAX_ICON_SIZE )
301
+ texture_overlay. pixel_x += PARALLAX_ICON_SIZE * x
302
+ texture_overlay. pixel_y += PARALLAX_ICON_SIZE * y
292
303
new_overlays += texture_overlay
304
+
293
305
cut_overlays ()
294
306
add_overlay (new_overlays)
295
307
view_sized = view
0 commit comments