-
Notifications
You must be signed in to change notification settings - Fork 6
/
pulp.lua
2121 lines (1876 loc) · 64.2 KB
/
pulp.lua
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
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
assert(___pulp, "___pulp object must be defined before import")
-- scale audio by this amount
-- (we need to declare this before importing pulp-audio)
SOUNDSCALE = {
[0] = 0.320, -- sine
[1] = 0.412, -- square
[2] = 0.300, -- sawtooth
[3] = 0.440, -- triangle
[4] = 0.160 -- noise
}
import "CoreLibs/utilities/sampler"
import "pulp-audio.lua"
local pulp <const> = ___pulp
local floor <const> = math.floor
local ceil <const> = math.ceil
local max <const> = math.max
local min <const> = math.min
local substr <const> = string.sub
local random <const> = math.random
local string_char <const> = string.char
local string_byte <const> = string.byte
local abs <const> = math.abs
local TTYPE_WORLD <const> = 0
local TTYPE_PLAYER <const> = 1
local TTYPE_SPRITE <const> = 2
local TTYPE_ITEM <const> = 3
local ACTOR_TYPE_GLOBAL <const> = 0
local ACTOR_TYPE_ROOM <const> = 1
local ACTOR_TYPE_TILE <const> = 2
local __exits = {}
pulp.scripts = {}
pulp.tiles = pulp.tiles or {}
pulp.sounds = pulp.sounds or {}
pulp.tiles_by_name = {}
pulp.rooms_by_name = {}
pulp.sounds_by_name = {}
pulp.song_names_by_id = {}
pulp.roomtiles = {}
pulp.store = {}
pulp.store_dirty = false
local roomtiles = pulp.roomtiles
pulp.rooms = pulp.rooms or {}
pulp.game = {
script = EMPTY,
name = "",
type = ACTOR_TYPE_GLOBAL,
__tostring = function(...)
return pulp.gamename
end
}
pulp.player = {
is_player = true,
frame = 0,
x = 0,
y = 0,
-- used if PTLE_SMOOTH_MOVEMENT_SPEED > 0
smooth_x = 0,
smooth_y = 0
}
pulp.invert = false
pulp.listen = true
pulp.shake = 0
pulp.hideplayer = false -- (resets to false every frame.)
pulp.roomQueued = nil
pulp.frame = 0
pulp.tilemap = playdate.graphics.tilemap.new()
local tilemap <const> = pulp.tilemap
pulp.game_is_loaded = false
pulp.timers = {}
pulp.shakex = 2
pulp.shakey = 2
pulp.exits = nil
pulp.message = nil
pulp.optattachmessage = nil
local disabled_exit_x = nil
local disabled_exit_y = nil
local pulp_tile_fps_lookup_floor = {}
local pulp_tile_fps_lookup_floor_lookup = {}
-- we scale down the sound to reduce saturation and match playback in Firefox
pulp.soundscale = SOUNDSCALE
local EMPTY <const> = {
any = function (...) end
}
pulp.EMPTY = {
any = EMPTY.any
}
pulp.EMPTY.script = pulp.EMPTY
pulp.gameScript = EMPTY
local FPS <const> = 20
local SPF <const> = 1/FPS
local alphabet =
" !\"#$%&'()*+,-./0123"
.. "456789:;<=>?@ABCDEFG"
.. "HIJKLMNOPQRSTUVWXYZ["
.."\\]^_`abcdefghijklmno"
.. "pqrstuvwxyz<|>~"
-- NOT local -- shared with pulpscript!
config = {
autoAct = 1,
inputRepeat=1,
inputRepeatBetween=0.2,
inputRepeatDelay=0.4,
follow = 0,
followCenterX=12,
followCenterY=7,
followOverflowTile = 1,
allowDismissRootMenu = 0,
sayAdvanceDelay = 0.2,
textSpeed = 20,
_pulp_to_lua = pulp.tiles[1],
}
-- TODO: only start if accelerometer is used in this game.
playdate.startAccelerometer()
playdate.display.setRefreshRate(FPS)
local tile_img = pulp.tile_img
local font_img = pulp.font_img
local GRIDX <const>, GRIDY <const> = pulp.tile_img[1]:getSize()
if GRIDX == 8 then
playdate.display.setScale(2)
end
if GRIDX == 4 then
playdate.display.setScale(4)
end
if GRIDX == 2 then
playdate.display.setScale(8)
end
if GRIDX == 1 then
playdate.display.setScale(16)
end
local PIX8SCALE <const> = GRIDX / 8
pulp.gridx = GRIDX
pulp.gridy = GRIDY
pulp.pix8scale = PIX8SCALE
local HALFWIDTH_SRCRECT = nil
if pulp.halfwidth then
HALFWIDTH_SRCRECT = playdate.geometry.rect.new(0, 0, GRIDX/2, GRIDY)
end
playdate.graphics.setBackgroundColor(playdate.graphics.kColorBlack)
local TILESW <const> = 25
local TILESH <const> = 15
local cropl = 0
local cropr = TILESW-1
local cropu = 0
local cropd = TILESH-1
local iscropped = false
tilemap:setImageTable(tile_img)
tilemap:setSize(TILESW, TILESH)
for y = 0,TILESH-1 do
pulp.roomtiles[y] = {}
end
-- sounds
local SOUND_CHANNELS <const> = 5
local wavetypes <const> = {
[0] = playdate.sound.kWaveSine,
[1] = playdate.sound.kWaveSquare,
[2] = playdate.sound.kWaveSawtooth,
[3] = playdate.sound.kWaveTriangle,
[4] = playdate.sound.kWaveNoise,
}
-- tweens x toward y by adding/subtracting at most c
local function tween(x, y, c)
if abs(x - y) <= c then
return y
elseif x < y then
return x + c
else
return x - c
end
end
------------------------------------------------ API ---------------------------------------------------------
local function copytable(t)
local t2 = {}
for k,v in pairs(t) do
t2[k] = v
end
return t2
end
local function trimLineEnd(s)
return string.gsub(s, "%s*$", "")
end
-- input: a string, height and width
-- output: a list of strings, one for each 'page', each of which is word-wrapped to fit in w-by-h rectangle (as rendered with pulp.__fn_label)
local function paginate(text, w, h)
-- virtal cursor position
local x = 0
local y = 0
-- return value
local pages = {""}
-- the index of the first character to include in this line.
local startidx = 1
-- the index of the first character in the currently-processing word (or startidx if larger)
local wordidx = 1
local wordx = 0
-- skip this many characters
local multichar = 0
-- waiting to find start of word.
local hook_word = true
-- waiting to find start of line.
local hook_line = true
for i = 1,#text+1 do
if i == #text+1 then
-- finish with text[startidx:]
pages[#pages] = pages[#pages] .. trimLineEnd(substr(text, startidx, #text))
else
if multichar > 0 then
multichar -= 1
goto continue
end
local char = substr(text, i, i)
if char == '\f' then
pages[#pages] = pages[#pages] .. trimLineEnd(substr(text, startidx, i - 1))
pages[#pages+1] = ""
x = 0
y = 0
startidx = i
wordidx = i
wordx = 0
hook_line = true
hook_word = true
elseif char == '\n' then
pages[#pages] = pages[#pages] .. trimLineEnd(substr(text, startidx, i - 1)) .. "\n"
x = 0
y += 1
startidx = i
wordidx = i
wordx = 0
hook_line = true
hook_word = true
else
local chbyte = string_byte(text, i, i)
local isspace = (char == ' ' or char == '\t')
--[[print(
tostring(x) .. "/" .. tostring(w),
tostring(y) .. "/" .. tostring(h), char
)]]
if x >= w then
local cut_point = i
if wordidx > startidx then
cut_point = wordidx
x -= wordx - 1
else
x = 0
end
local cutline = trimLineEnd(substr(text, startidx, cut_point - 1))
pages[#pages] = pages[#pages] .. cutline .. "\n"
startidx = cut_point
wordidx = cut_point
wordx = 0
y += 1
if y >= h then
y = 0
pages[#pages+1] = ""
end
else
x += 1
end
if hook_line then
startidx = i
end
if hook_word then
wordidx = i
wordx = x
end
if not isspace then
hook_line = false
hook_word = false
else
hook_word = true
end
-- read embeds
if chbyte >= 0x80 then
multichar = chbyte - 0x80
end
end
::continue::
end
end
-- remove empty final page
if pages[#pages] == "" then
pages[#pages] = nil
end
if #pages == 0 then
pages[1] = ""
end
return pages
end
-- https://stackoverflow.com/q/49979017
local function getStackDepth()
local depth = 0
while true do
if not debug.getinfo(3 + depth) then
break
end
depth = depth + 1
end
return depth
end
-- slow, so don't call it except sometimes
local stackdepth = 0
local function preventStackOverflow()
if stackdepth > 300 then
print("WARNING: stack overflow detected.")
return true
end
return false
end
local event_persist = {
aa = playdate.getCrankPosition() or 0,
ra = 0,
ax = 0,
ay = 1,
az = 0,
dx = 0,
dy = 0,
orientation = "standing up"
}
function event_persist:new()
return {
aa = self.aa,
ra = self.ra,
ax = self.ax,
ay = self.ay,
az = self.az,
dx = self.dx,
dy = self.dy,
tx = self.tx,
ty = self.ty,
px = pulp.player.x,
py = pulp.player.y,
game = pulp.game,
room = self.room,
orientation = self.orientation,
frame = pulp.frame
}
end
function pulp:newScript(name)
local script = {}
pulp.scripts[name] = script
return script
end
function pulp:associateScript(name, t, id)
local script = type(name) == "string" and pulp.scripts[name] or name
assert(script, "no script found with name '" .. tostring(name) .. "'")
if t == "tile" then
assert(pulp.tiles[id], "script \"" .. name .. "\" for tile " .. tostring(id) .. ", but tile does not exist")
pulp.tiles[id].script = script
elseif t == "room" then
assert(pulp.rooms[id], "associate room script with unknown room id " .. tostring(id))
pulp.rooms[id].script = script
elseif t == "global" and id == 0 then
pulp.gameScript = script
pulp.game.script = script
else
assert(false, "unrecognized script type " .. tostring(t))
end
end
function pulp:getScriptEventByName(id, evname)
local script = pulp:getScript(id) or EMPTY
return script[evname] or script.any or EMPTY.any
end
function pulp:getScript(id)
if type(id) == "string" then
return pulp.scripts[id] or EMPTY
elseif type(id) == "number" then
return (pulp.tiles[id] or EMPTY).script or EMPTY
elseif type(id) == "table" then
return id
else
-- oops. :(
assert(false)
return {}
end
end
function pulp:getCurrentRoom()
return pulp.rooms[pulp.current_room_idx]
end
function pulp:getPlayerScript()
return pulp.player.script or EMPTY
end
function pulp:getTile(tid)
if type(tid) == "number" then
return pulp.tiles[tid]
else
return pulp.tiles_by_name[tid]
end
end
function pulp:getSongName(sid)
if type(sid) == "number" then
return pulp.song_names_by_id[sid]
else
return sid
end
end
function pulp:getSound(sid)
if type(sid) == "number" then
return pulp.sounds[sid]
else
return pulp.sounds_by_name[sid]
end
end
function pulp:getTileAt(x, y)
return (roomtiles[y] or EMPTY)[x]
end
local function default_event_interact(tilei, event, evname)
if tilei.tile.says and #tilei.tile.says > 0 then
pulp.__fn_say(nil, nil, nil, nil, tilei, event, evname, nil, tilei.tile.says)
end
end
local function default_event_collect(tilei, event, evname)
local says = tilei.tile.says
pulp.setvariable(tilei.name .. "s", (pulp.getvariable(tilei.name .. "s") or 0) + 1)
pulp.__fn_swap(tilei, 0)
if says and #says > 0 then
pulp.__fn_say(nil, nil, nil, nil, tilei, event, evname, nil, says)
end
end
function playdate.cranked(change, acceleratedChange)
local script = pulp:getPlayerScript()
event_persist.aa = playdate.getCrankPosition()
event_persist.ra = change
if script then
(script.crank or script.any)(pulp.player, event_persist:new(), "crank")
end
end
function playdate.crankDocked()
local script = pulp:getPlayerScript()
if script then
(script.dock or script.any)(pulp.player, event_persist:new(), "dock")
end
end
function playdate.crankUndocked()
local script = pulp:getPlayerScript()
if script then
(script.undock or script.any)(pulp.player, event_persist:new(), "undock")
end
end
local function readAccelerometer()
local ax, ay, az = playdate.readAccelerometer()
if ax and ay and ay then
event_persist.ax = ax
event_persist.ay = ay
event_persist.az = az
event_persist.ax = event_persist.ax or 0
event_persist.ay = event_persist.ay or 0
event_persist.az = event_persist.az or 0
if ay >= 0.70 then
event_persist.orientation = "standing up"
elseif ay <= -0.70 then
event_persist.orientation = "upside down"
elseif az >= 0.70 then
event_persist.orientation = "on back"
elseif az <= -0.70 then
event_persist.orientation = "on front"
elseif ax >= 0.70 then
event_persist.orientation = "on right"
elseif ax <= -0.70 then
event_persist.orientation = "on left"
else
-- (hysteresis)
end
end
end
local prev_a = false
local prev_b = false
local prev_up = false
local prev_down = false
local prev_left = false
local prev_right = false
local a_press_time = false
local b_press_time = false
local up_press_time = false
local down_press_time = false
local left_press_time = false
local right_press_time = false
local function updateMessage(up, down, left, right, confirm, cancel)
-- FIXME: yes, this is pretty messy.
local message = pulp.message
local text = (message.text or EMPTY)[message.page]
-- TODO: crank can also dismiss
local skiptext = up or down or confirm or cancel or left or right
if message.dismiss then
pulp.message = pulp.message.previous
return
end
if message.sayAdvanceDelay > 0 then
message.sayAdvanceDelay -= SPF
end
if not message.showoptions and not message.text then
if message.block then
pulp.optattachmessage = message
message.block(message.actor, message.event, message.evname)
pulp.optattachmessage = nil
message.showoptions = true
message.optselect = 1
if message.options and #message.options > 0 then
pulp:emit("change", event_persist:new())
end
end
if #message.options == 0 then
-- dismiss menu
print("warning: opened a menu with 0 valid options")
pulp.message = pulp.message.previous
return
end
end
if message.showoptions then
if message.sayAdvanceDelay > 0 then return end
local prevoptsel = message.optselect
if up then
message.optselect -= 1
elseif down then
message.optselect += 1
end
if message.opth then
if left and message.firstopt ~= 1 then
message.firstopt -= message.opth
message.optselect -= message.opth
end
if right and message.firstopt + message.opth <= #message.options then
message.firstopt += message.opth
message.optselect += message.opth
end
if message.firstopt <= 1 then
message.firstopt = 1
elseif message.firstopt > #message.options then
message.firstopt -= message.opth
end
end
if up or down then
if message.opth then
if message.optselect < message.firstopt then
message.optselect = message.firstopt + message.opth
elseif message.optselect > message.firstopt + message.opth - 1 or message.optselect > #message.options then
message.optselect = message.firstopt
end
else
if message.optselect < 1 then
message.optselect = #message.options
elseif message.optselect > #message.options then
message.optselect = 1
end
end
end
if message.opth then
message.optselect = max(min(message.optselect, message.firstopt + message.opth - 1), message.firstopt)
end
message.optselect = max(min(message.optselect, #message.options), 1) -- paranoia
if prevoptsel ~= message.optselect then
pulp:emit("change", event_persist:new())
end
if confirm then
local option = message.options[message.optselect]
-- dismiss message
if option and option.block then
assert(option.event)
option.block(option.actor, option.event, option.evname, option)
-- dismiss ALL menus if no submenu opened in option block
if pulp.message == message then
pulp.message = nil
elseif pulp.message.text then
message.dismiss = true
end
(pulp.gameScript.select or pulp.gameScript.any)(pulp.game, event_persist:new(), "select")
end
elseif cancel then
if pulp.message.previous or config.allowDismissRootMenu ~= 0 then
pulp.message = pulp.message.previous
;(pulp.gameScript.select or pulp.gameScript.any)(pulp.game, event_persist:new(), "dismiss")
else
(pulp.gameScript.select or pulp.gameScript.any)(pulp.game, event_persist:new(), "invalid")
end
end
elseif message.textidx < #text and skiptext and message.sayAdvanceDelay <= 0 then
message.textidx = #text
elseif message.textidx < #text then
message.textidx += (message.textSpeed or FPS) / FPS
if message.textidx >= #text then
message.textids = #text
end
elseif skiptext and message.sayAdvanceDelay <= 0 then
-- proceed to next page or close if last page.
if message.page == #message.text then
-- close the final page.
if message.block then
pulp.optattachmessage = message
message.block(message.actor, message.event, message.evname)
pulp.optattachmessage = nil
message.block = nil
end
if message.options and #message.options then
message.showoptions = true
message.optselect = 1
if message.options and #message.options > 0 then
pulp:emit("change", event_persist:new())
end
else
-- dismiss message if no menus opened up
message.dismiss = true
if message == pulp.message then
pulp.message = nil
end
end
else
-- go to next page
message.page += 1
message.prompt_timer = -1
message.textidx = 0
end
else
-- wait to proceed
message.prompt_timer += 1
end
end
local function drawMessage(message, submenu)
if not message or message.dismiss then
return
end
if not submenu then
if message.clear then
playdate.graphics.clear(playdate.graphics.kColorBlack)
end
if message.text and message.page and message.text[message.page] then
pulp.__fn_window(message.x-1, message.y-1, message.w+2, message.h+2)
local text = substr(message.text[message.page], 1, floor(message.textidx))
pulp.__fn_label(message.x, message.y, nil, nil, text)
-- prompt to advance
if message.prompt_timer >= 0 and not message.showoptions then
local prompt_idx = 10 + floor((message.prompt_timer % FPS) * SPF * 2)
pulp.pipe_img[prompt_idx]:draw(GRIDX * (message.x + message.w - 1), GRIDY * (message.y + message.h))
end
end
end
-- recursively draw options for previous menu
drawMessage(message.previous, true)
-- options
if message.options and message.showoptions then
local optw = message.optw or min(message.options_width, 8)
local opth = message.opth or #message.options
local optx = message.optx or message.x + message.w - 1 - optw
local opty = message.opty or message.y + message.h
pulp.__fn_window(optx - 2, opty - 1, optw + 3, opth + 2)
local y = 0
for i = message.firstopt,#message.options do
if y >= opth then
break
end
local option = message.options[i]
local text = option.text
if not pulp.halfwidth and #text > optw then
text = substr(text, 1, optw)
elseif pulp.halfwidth and #text > optw * 2 then
text = substr(text, 1, optw * 2)
end
pulp.__fn_label(optx, opty + y, nil, nil, text)
y += 1
end
-- cursor
pulp.pipe_img[submenu and 13 or 12]:draw((optx - 1) * GRIDX, (opty + message.optselect - message.firstopt) * GRIDY)
if #message.options > opth then
-- page icon
pulp.pipe_img[14]:draw(GRIDX * (optx + optw - 1), GRIDY * (opty + opth))
end
end
end
local function readInput()
local a = playdate.buttonIsPressed( playdate.kButtonA )
local b = playdate.buttonIsPressed( playdate.kButtonB )
local up = playdate.buttonIsPressed( playdate.kButtonUp )
local down = playdate.buttonIsPressed( playdate.kButtonDown )
local left = playdate.buttonIsPressed( playdate.kButtonLeft )
local right = playdate.buttonIsPressed( playdate.kButtonRight )
-- FIXME: ensure this is correct
if up and down then
up = false
down = false
end
if left and right then
left = false
right = false
end
pulp.PTLE_CONFIRM_DAS = -1
pulp.PTLE_CANCEL_DAS = -1
pulp.PTLE_V_DAS = -1
pulp.PTLE_H_DAS = -1
local a_pressed = a and not prev_a
local b_pressed = b and not prev_b
local up_pressed = up and not prev_up
local down_pressed = down and not prev_down
local left_pressed = left and not prev_left
local right_pressed = right and not prev_right
if config.inputRepeat == 1 then
local now = playdate.getCurrentTimeMilliseconds()
local next_first = now + config.inputRepeatDelay * 1000
local next_repeat = now + config.inputRepeatBetween * 1000
if a_pressed then
a_press_time = next_first
end
if b_pressed then
b_press_time = next_first
end
if up_pressed then
up_press_time = next_first
end
if down_pressed then
down_press_time = next_first
end
if left_pressed then
left_press_time = next_first
end
if right_pressed then
right_press_time = next_first
end
if a and a_press_time and now >= a_press_time then
a_press_time = next_repeat
a_pressed = true
pulp.PTLE_CONFIRM_DAS = 1
end
if b and b_press_time and now >= b_press_time then
b_press_time = next_repeat
b_pressed = true
pulp.PTLE_CANCEL_DAS = 1
end
if up and up_press_time and now >= up_press_time then
up_press_time = next_repeat
up_pressed = true
pulp.PTLE_V_DAS = 1
end
if down and down_press_time and now >= down_press_time then
down_press_time = next_repeat
down_pressed = true
pulp.PTLE_V_DAS = 1
end
if left and left_press_time and now >= left_press_time then
left_press_time = next_repeat
left_pressed = true
pulp.PTLE_H_DAS = 1
end
if right and right_press_time and now >= right_press_time then
right_press_time = next_repeat
right_pressed = true
pulp.PTLE_H_DAS = 1
end
else
a_press_time = false
b_press_time = false
up_press_time = false
down_press_time = false
left_press_time = false
right_press_time = false
end
if pulp.message then
updateMessage(up_pressed, down_pressed, left_pressed, right_pressed, a_pressed, b_pressed)
else
local player = pulp.player
if up_pressed or down_pressed or left_pressed or right_pressed then
event_persist.dx = 0
event_persist.dy = 0
if up_pressed then
event_persist.dy = -1
elseif down_pressed then
event_persist.dy = 1
elseif left_pressed then
event_persist.dx = -1
elseif right_pressed then
event_persist.dx = 1
end
end
local tx = max(0, min(player.x + event_persist.dx, TILESW-1))
local ty = max(0, min(player.y + event_persist.dy, TILESH-1))
event_persist.tx = tx
event_persist.ty = ty
local playerScript = pulp:getPlayerScript()
if pulp.listen and (pulp.PTLE_SMOOTH_MOVEMENT_SPEED <= 0 or (pulp.player.smooth_x == pulp.player.x and pulp.player.smooth_y == pulp.player.y)) then
if a_pressed and playerScript then
(playerScript.confirm or playerScript.any)(pulp.player, event_persist:new(), "confirm")
end
if b_pressed and playerScript then
(playerScript.cancel or playerScript.any)(pulp.player, event_persist:new(), "cancel")
end
local do_exit = false
if pulp.listen then
-- check for exits
-- TODO: only do this if player has moved since previous frame
local x = player.x
local y = player.y
if x ~= disabled_exit_x or y ~= disabled_exit_y then
disabled_exit_x = nil
disabled_exit_y = nil
end
for i = 1,#__exits do
local exit = __exits[i]
if exit.edge == nil and (x ~= disabled_exit_x or y ~= disabled_exit_y) then
do_exit = x == exit.x and y == exit.y
elseif exit.edge == 1 then
do_exit = x == exit.x and event_persist.dx > 0
elseif exit.edge == 2 then
do_exit = y == exit.y and event_persist.dy > 0
elseif exit.edge == 3 then
do_exit = x == exit.x and event_persist.dx < 0
elseif exit.edge == 0 or exit.edge == 4 then
do_exit = y == exit.y and event_persist.dy < 0
end
if do_exit then
if exit.fin then
pulp.__fn_fin(exit.fin)
else
if exit.edge == nil then
pulp.__fn_goto(exit.tx, exit.ty, exit.room)
elseif exit.edge == 1 or exit.edge == 3 then
pulp.__fn_goto(exit.tx, y, exit.room)
elseif exit.edge == 2 or exit.edge == 4 or exit.edge == 0 then
pulp.__fn_goto(x, exit.ty, exit.room)
end
end
break
end
end
-- move, and check for interactions and collections
if (up_pressed or down_pressed or left_pressed or right_pressed) then
if not do_exit then
local ttile = roomtiles[ty][tx]
if ttile then -- paranoia
if not ttile.solid then
player.x = tx
player.y = ty
if pulp.PTLE_SMOOTH_MOVEMENT_SPEED <= 0 then
player.smooth_x = player.x
player.smooth_y = player.y
end
else
if playerScript then
(playerScript.bump or playerScript.any)(player, event_persist:new(), "bump")
end
end
local _type = ttile.ttype
local _script = ttile.script or EMPTY
-- _script_any <- script.any, or if that's NOT SET BY USER (i.e. is EMPTY) then nil.
-- bad code. :|
local _script_any = _script.any
if _script_any == EMPTY.any then
_script_any = nil
end
if _type == TTYPE_SPRITE and config.autoAct then
(_script.interact or _script_any or default_event_interact)(ttile, event_persist:new(), "interact")
elseif _type == TTYPE_ITEM then
(_script.collect or _script_any or default_event_collect)(ttile, event_persist:new(), "collect")
end
end
end
if playerScript then
(playerScript.update or playerScript.any)(player, event_persist:new(), "update")
end
end
end
end
end
prev_a = a
prev_b = b
prev_up = up
prev_down = down
prev_left = left
prev_right = right
end
local function smoothMovementBegin()
local player = pulp.player
pulp.smooth_true_x = player.x
pulp.smooth_true_y = player.y
if pulp.PTLE_SMOOTH_MOVEMENT_SPEED > 0 then
player.smooth_x = tween(player.smooth_x, player.x, pulp.PTLE_SMOOTH_MOVEMENT_SPEED)
player.smooth_y = tween(player.smooth_y, player.y, pulp.PTLE_SMOOTH_MOVEMENT_SPEED)
pulp.PTLE_SMOOTH_OFFSET_X = player.smooth_x - player.x
pulp.PTLE_SMOOTH_OFFSET_Y = player.smooth_y - player.y
else
player.smooth_x = player.x
player.smooth_y = player.y
pulp.PTLE_SMOOTH_OFFSET_X = 0
pulp.PTLE_SMOOTH_OFFSET_Y = 0
end
end
local function smoothMovementEnd()
local player = pulp.player
player.x = pulp.smooth_true_x
player.y = pulp.smooth_true_y