1// MIT License
2
3// Copyright (c) 2017 Vadim Grigoruk @nesbox // grigoruk@gmail.com
4
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11
12// The above copyright notice and this permission notice shall be included in all
13// copies or substantial portions of the Software.
14
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21// SOFTWARE.
22
23#include "core/core.h"
24
25#if defined(TIC_BUILD_WITH_LUA)
26
27#include <stdlib.h>
28#include <string.h>
29#include <lua.h>
30#include <lauxlib.h>
31#include <lualib.h>
32#include <ctype.h>
33
34s32 luaopen_lpeg(lua_State *lua);
35
36static inline s32 getLuaNumber(lua_State* lua, s32 index)
37{
38 return (s32)lua_tonumber(lua, index);
39}
40
41static void registerLuaFunction(tic_core* core, lua_CFunction func, const char *name)
42{
43 lua_pushlightuserdata(core->currentVM, core);
44 lua_pushcclosure(core->currentVM, func, 1);
45 lua_setglobal(core->currentVM, name);
46}
47
48static tic_core* getLuaCore(lua_State* lua)
49{
50 tic_core* core = lua_touserdata(lua, lua_upvalueindex(1));
51 return core;
52}
53
54static s32 lua_peek(lua_State* lua)
55{
56 s32 top = lua_gettop(lua);
57 tic_mem* tic = (tic_mem*)getLuaCore(lua);
58
59 if(top >= 1)
60 {
61 s32 address = getLuaNumber(lua, 1);
62 s32 bits = BITS_IN_BYTE;
63
64 if(top == 2)
65 bits = getLuaNumber(lua, 2);
66
67 lua_pushinteger(lua, tic_api_peek(tic, address, bits));
68 return 1;
69 }
70 else luaL_error(lua, "invalid parameters, peek(addr,bits)\n");
71
72 return 0;
73}
74
75static s32 lua_poke(lua_State* lua)
76{
77 s32 top = lua_gettop(lua);
78 tic_mem* tic = (tic_mem*)getLuaCore(lua);
79
80 if(top >= 2)
81 {
82 s32 address = getLuaNumber(lua, 1);
83 u8 value = getLuaNumber(lua, 2);
84 s32 bits = BITS_IN_BYTE;
85
86 if(top == 3)
87 bits = getLuaNumber(lua, 3);
88
89 tic_api_poke(tic, address, value, bits);
90 }
91 else luaL_error(lua, "invalid parameters, poke(addr,val,bits)\n");
92
93 return 0;
94}
95
96static s32 lua_peek1(lua_State* lua)
97{
98 s32 top = lua_gettop(lua);
99 tic_mem* tic = (tic_mem*)getLuaCore(lua);
100
101 if(top == 1)
102 {
103 s32 address = getLuaNumber(lua, 1);
104 lua_pushinteger(lua, tic_api_peek1(tic, address));
105 return 1;
106 }
107 else luaL_error(lua, "invalid parameters, peek1(addr)\n");
108
109 return 0;
110}
111
112static s32 lua_poke1(lua_State* lua)
113{
114 s32 top = lua_gettop(lua);
115 tic_mem* tic = (tic_mem*)getLuaCore(lua);
116
117 if(top == 2)
118 {
119 s32 address = getLuaNumber(lua, 1);
120 u8 value = getLuaNumber(lua, 2);
121
122 tic_api_poke1(tic, address, value);
123 }
124 else luaL_error(lua, "invalid parameters, poke1(addr,val)\n");
125
126 return 0;
127}
128
129static s32 lua_peek2(lua_State* lua)
130{
131 s32 top = lua_gettop(lua);
132 tic_mem* tic = (tic_mem*)getLuaCore(lua);
133
134 if(top == 1)
135 {
136 s32 address = getLuaNumber(lua, 1);
137 lua_pushinteger(lua, tic_api_peek2(tic, address));
138 return 1;
139 }
140 else luaL_error(lua, "invalid parameters, peek2(addr)\n");
141
142 return 0;
143}
144
145static s32 lua_poke2(lua_State* lua)
146{
147 s32 top = lua_gettop(lua);
148 tic_mem* tic = (tic_mem*)getLuaCore(lua);
149
150 if(top == 2)
151 {
152 s32 address = getLuaNumber(lua, 1);
153 u8 value = getLuaNumber(lua, 2);
154
155 tic_api_poke2(tic, address, value);
156 }
157 else luaL_error(lua, "invalid parameters, poke2(addr,val)\n");
158
159 return 0;
160}
161
162static s32 lua_peek4(lua_State* lua)
163{
164 s32 top = lua_gettop(lua);
165 tic_mem* tic = (tic_mem*)getLuaCore(lua);
166
167 if(top == 1)
168 {
169 s32 address = getLuaNumber(lua, 1);
170 lua_pushinteger(lua, tic_api_peek4(tic, address));
171 return 1;
172 }
173 else luaL_error(lua, "invalid parameters, peek4(addr)\n");
174
175 return 0;
176}
177
178static s32 lua_poke4(lua_State* lua)
179{
180 s32 top = lua_gettop(lua);
181 tic_mem* tic = (tic_mem*)getLuaCore(lua);
182
183 if(top == 2)
184 {
185 s32 address = getLuaNumber(lua, 1);
186 u8 value = getLuaNumber(lua, 2);
187
188 tic_api_poke4(tic, address, value);
189 }
190 else luaL_error(lua, "invalid parameters, poke4(addr,val)\n");
191
192 return 0;
193}
194
195static s32 lua_cls(lua_State* lua)
196{
197 s32 top = lua_gettop(lua);
198
199 tic_mem* tic = (tic_mem*)getLuaCore(lua);
200
201 tic_api_cls(tic, top == 1 ? getLuaNumber(lua, 1) : 0);
202
203 return 0;
204}
205
206static s32 lua_pix(lua_State* lua)
207{
208 s32 top = lua_gettop(lua);
209
210 if(top >= 2)
211 {
212 s32 x = getLuaNumber(lua, 1);
213 s32 y = getLuaNumber(lua, 2);
214
215 tic_mem* tic = (tic_mem*)getLuaCore(lua);
216
217 if(top >= 3)
218 {
219 s32 color = getLuaNumber(lua, 3);
220 tic_api_pix(tic, x, y, color, false);
221 }
222 else
223 {
224 lua_pushinteger(lua, tic_api_pix(tic, x, y, 0, true));
225 return 1;
226 }
227
228 }
229 else luaL_error(lua, "invalid parameters, pix(x y [color])\n");
230
231 return 0;
232}
233
234static s32 lua_line(lua_State* lua)
235{
236 s32 top = lua_gettop(lua);
237
238 if(top == 5)
239 {
240 float x0 = lua_tonumber(lua, 1);
241 float y0 = lua_tonumber(lua, 2);
242 float x1 = lua_tonumber(lua, 3);
243 float y1 = lua_tonumber(lua, 4);
244 s32 color = getLuaNumber(lua, 5);
245
246 tic_mem* tic = (tic_mem*)getLuaCore(lua);
247
248 tic_api_line(tic, x0, y0, x1, y1, color);
249 }
250 else luaL_error(lua, "invalid parameters, line(x0,y0,x1,y1,color)\n");
251
252 return 0;
253}
254
255static s32 lua_rect(lua_State* lua)
256{
257 s32 top = lua_gettop(lua);
258
259 if(top == 5)
260 {
261 s32 x = getLuaNumber(lua, 1);
262 s32 y = getLuaNumber(lua, 2);
263 s32 w = getLuaNumber(lua, 3);
264 s32 h = getLuaNumber(lua, 4);
265 s32 color = getLuaNumber(lua, 5);
266
267 tic_mem* tic = (tic_mem*)getLuaCore(lua);
268
269 tic_api_rect(tic, x, y, w, h, color);
270 }
271 else luaL_error(lua, "invalid parameters, rect(x,y,w,h,color)\n");
272
273 return 0;
274}
275
276static s32 lua_rectb(lua_State* lua)
277{
278 s32 top = lua_gettop(lua);
279
280 if(top == 5)
281 {
282 s32 x = getLuaNumber(lua, 1);
283 s32 y = getLuaNumber(lua, 2);
284 s32 w = getLuaNumber(lua, 3);
285 s32 h = getLuaNumber(lua, 4);
286 s32 color = getLuaNumber(lua, 5);
287
288 tic_mem* tic = (tic_mem*)getLuaCore(lua);
289
290 tic_api_rectb(tic, x, y, w, h, color);
291 }
292 else luaL_error(lua, "invalid parameters, rectb(x,y,w,h,color)\n");
293
294 return 0;
295}
296
297static s32 lua_circ(lua_State* lua)
298{
299 s32 top = lua_gettop(lua);
300
301 if(top == 4)
302 {
303 tic_mem* tic = (tic_mem*)getLuaCore(lua);
304
305 s32 x = getLuaNumber(lua, 1);
306 s32 y = getLuaNumber(lua, 2);
307 s32 radius = getLuaNumber(lua, 3);
308 s32 color = getLuaNumber(lua, 4);
309
310 tic_api_circ(tic, x, y, radius, color);
311 }
312 else luaL_error(lua, "invalid parameters, circ(x,y,radius,color)\n");
313
314 return 0;
315}
316
317static s32 lua_circb(lua_State* lua)
318{
319 s32 top = lua_gettop(lua);
320
321 if(top == 4)
322 {
323 tic_mem* tic = (tic_mem*)getLuaCore(lua);
324
325 s32 x = getLuaNumber(lua, 1);
326 s32 y = getLuaNumber(lua, 2);
327 s32 radius = getLuaNumber(lua, 3);
328 s32 color = getLuaNumber(lua, 4);
329
330 tic_api_circb(tic, x, y, radius, color);
331 }
332 else luaL_error(lua, "invalid parameters, circb(x,y,radius,color)\n");
333
334 return 0;
335}
336
337static s32 lua_elli(lua_State* lua)
338{
339 s32 top = lua_gettop(lua);
340
341 if(top == 5)
342 {
343 tic_mem* tic = (tic_mem*)getLuaCore(lua);
344
345 s32 x = getLuaNumber(lua, 1);
346 s32 y = getLuaNumber(lua, 2);
347 s32 a = getLuaNumber(lua, 3);
348 s32 b = getLuaNumber(lua, 4);
349 s32 color = getLuaNumber(lua, 5);
350
351 tic_api_elli(tic, x, y, a, b, color);
352 }
353 else luaL_error(lua, "invalid parameters, elli(x,y,a,b,color)\n");
354
355 return 0;
356}
357
358static s32 lua_ellib(lua_State* lua)
359{
360 s32 top = lua_gettop(lua);
361
362 if(top == 5)
363 {
364 tic_mem* tic = (tic_mem*)getLuaCore(lua);
365
366 s32 x = getLuaNumber(lua, 1);
367 s32 y = getLuaNumber(lua, 2);
368 s32 a = getLuaNumber(lua, 3);
369 s32 b = getLuaNumber(lua, 4);
370 s32 color = getLuaNumber(lua, 5);
371
372 tic_api_ellib(tic, x, y, a, b, color);
373 }
374 else luaL_error(lua, "invalid parameters, ellib(x,y,a,b,color)\n");
375
376 return 0;
377}
378
379static s32 lua_tri(lua_State* lua)
380{
381 s32 top = lua_gettop(lua);
382
383 if(top == 7)
384 {
385 float pt[6];
386
387 for(s32 i = 0; i < COUNT_OF(pt); i++)
388 pt[i] = lua_tonumber(lua, i+1);
389
390 s32 color = getLuaNumber(lua, 7);
391
392 tic_mem* tic = (tic_mem*)getLuaCore(lua);
393
394 tic_api_tri(tic, pt[0], pt[1], pt[2], pt[3], pt[4], pt[5], color);
395 }
396 else luaL_error(lua, "invalid parameters, tri(x1,y1,x2,y2,x3,y3,color)\n");
397
398 return 0;
399}
400
401static s32 lua_trib(lua_State* lua)
402{
403 s32 top = lua_gettop(lua);
404
405 if(top == 7)
406 {
407 float pt[6];
408
409 for(s32 i = 0; i < COUNT_OF(pt); i++)
410 pt[i] = lua_tonumber(lua, i+1);
411
412 s32 color = getLuaNumber(lua, 7);
413
414 tic_mem* tic = (tic_mem*)getLuaCore(lua);
415
416 tic_api_trib(tic, pt[0], pt[1], pt[2], pt[3], pt[4], pt[5], color);
417 }
418 else luaL_error(lua, "invalid parameters, trib(x1,y1,x2,y2,x3,y3,color)\n");
419
420 return 0;
421}
422
423#if defined(BUILD_DEPRECATED)
424
425void drawTexturedTriangleDep(tic_core* core, float x1, float y1, float x2, float y2, float x3, float y3, float u1, float v1, float u2, float v2, float u3, float v3, bool use_map, u8* colors, s32 count);
426
427static s32 lua_textri(lua_State* lua)
428{
429 s32 top = lua_gettop(lua);
430
431 if (top >= 12)
432 {
433 float pt[12];
434
435 for (s32 i = 0; i < COUNT_OF(pt); i++)
436 pt[i] = (float)lua_tonumber(lua, i + 1);
437
438 tic_mem* tic = (tic_mem*)getLuaCore(lua);
439 static u8 colors[TIC_PALETTE_SIZE];
440 s32 count = 0;
441 bool use_map = false;
442
443 // check for use map
444 if (top >= 13)
445 use_map = lua_toboolean(lua, 13);
446
447 // check for chroma
448 if(top >= 14)
449 {
450 if(lua_istable(lua, 14))
451 {
452 for(s32 i = 1; i <= TIC_PALETTE_SIZE; i++)
453 {
454 lua_rawgeti(lua, 14, i);
455 if(lua_isnumber(lua, -1))
456 {
457 colors[i-1] = getLuaNumber(lua, -1);
458 count++;
459 lua_pop(lua, 1);
460 }
461 else
462 {
463 lua_pop(lua, 1);
464 break;
465 }
466 }
467 }
468 else
469 {
470 colors[0] = getLuaNumber(lua, 14);
471 count = 1;
472 }
473 }
474
475 drawTexturedTriangleDep(getLuaCore(lua),
476 pt[0], pt[1], // xy 1
477 pt[2], pt[3], // xy 2
478 pt[4], pt[5], // xy 3
479 pt[6], pt[7], // uv 1
480 pt[8], pt[9], // uv 2
481 pt[10], pt[11], // uv 3
482 use_map, // use map
483 colors, count); // chroma
484 }
485
486 return 0;
487}
488
489#endif
490
491static s32 lua_ttri(lua_State* lua)
492{
493 s32 top = lua_gettop(lua);
494
495 if (top >= 12)
496 {
497 float pt[12];
498
499 for (s32 i = 0; i < COUNT_OF(pt); i++)
500 pt[i] = (float)lua_tonumber(lua, i + 1);
501
502 tic_mem* tic = (tic_mem*)getLuaCore(lua);
503 static u8 colors[TIC_PALETTE_SIZE];
504 s32 count = 0;
505 tic_texture_src src = tic_tiles_texture;
506
507 // check for texture src
508 if (top >= 13)
509 {
510 src = lua_isboolean(lua, 13)
511 ? (lua_toboolean(lua, 13) ? tic_map_texture : tic_tiles_texture)
512 : lua_tointeger(lua, 13);
513 }
514 // check for chroma
515 if(top >= 14)
516 {
517 if(lua_istable(lua, 14))
518 {
519 for(s32 i = 1; i <= TIC_PALETTE_SIZE; i++)
520 {
521 lua_rawgeti(lua, 14, i);
522 if(lua_isnumber(lua, -1))
523 {
524 colors[i-1] = getLuaNumber(lua, -1);
525 count++;
526 lua_pop(lua, 1);
527 }
528 else
529 {
530 lua_pop(lua, 1);
531 break;
532 }
533 }
534 }
535 else
536 {
537 colors[0] = getLuaNumber(lua, 14);
538 count = 1;
539 }
540 }
541
542 float z[3];
543 bool depth = false;
544
545 if(top == 17)
546 {
547 for (s32 i = 0; i < COUNT_OF(z); i++)
548 z[i] = (float)lua_tonumber(lua, i + 15);
549
550 depth = true;
551 }
552
553 tic_api_ttri(tic, pt[0], pt[1], // xy 1
554 pt[2], pt[3], // xy 2
555 pt[4], pt[5], // xy 3
556 pt[6], pt[7], // uv 1
557 pt[8], pt[9], // uv 2
558 pt[10], pt[11], // uv 3
559 src, // texture source
560 colors, count, // chroma
561 z[0], z[1], z[2], depth); // depth
562 }
563 else luaL_error(lua, "invalid parameters, ttri(x1,y1,x2,y2,x3,y3,u1,v1,u2,v2,u3,v3,[src=0],[chroma=off],[z1=0],[z2=0],[z3=0])\n");
564 return 0;
565}
566
567
568static s32 lua_clip(lua_State* lua)
569{
570 s32 top = lua_gettop(lua);
571
572 if(top == 0)
573 {
574 tic_mem* tic = (tic_mem*)getLuaCore(lua);
575
576 tic_api_clip(tic, 0, 0, TIC80_WIDTH, TIC80_HEIGHT);
577 }
578 else if(top == 4)
579 {
580 s32 x = getLuaNumber(lua, 1);
581 s32 y = getLuaNumber(lua, 2);
582 s32 w = getLuaNumber(lua, 3);
583 s32 h = getLuaNumber(lua, 4);
584
585 tic_mem* tic = (tic_mem*)getLuaCore(lua);
586
587 tic_api_clip((tic_mem*)getLuaCore(lua), x, y, w, h);
588 }
589 else luaL_error(lua, "invalid parameters, use clip(x,y,w,h) or clip()\n");
590
591 return 0;
592}
593
594static s32 lua_btnp(lua_State* lua)
595{
596 tic_core* core = getLuaCore(lua);
597 tic_mem* tic = (tic_mem*)core;
598
599 s32 top = lua_gettop(lua);
600
601 if (top == 0)
602 {
603 lua_pushinteger(lua, tic_api_btnp(tic, -1, -1, -1));
604 }
605 else if(top == 1)
606 {
607 s32 index = getLuaNumber(lua, 1) & 0x1f;
608
609 lua_pushboolean(lua, tic_api_btnp(tic, index, -1, -1));
610 }
611 else if (top == 3)
612 {
613 s32 index = getLuaNumber(lua, 1) & 0x1f;
614 u32 hold = getLuaNumber(lua, 2);
615 u32 period = getLuaNumber(lua, 3);
616
617 lua_pushboolean(lua, tic_api_btnp(tic, index, hold, period));
618 }
619 else
620 {
621 luaL_error(lua, "invalid params, btnp [ id [ hold period ] ]\n");
622 return 0;
623 }
624
625 return 1;
626}
627
628static s32 lua_btn(lua_State* lua)
629{
630 tic_core* core = getLuaCore(lua);
631 tic_mem* tic = (tic_mem*)core;
632
633 s32 top = lua_gettop(lua);
634
635 if (top == 0)
636 {
637 lua_pushinteger(lua, tic_api_btn(tic, -1));
638 }
639 else if (top == 1)
640 {
641 bool pressed = tic_api_btn(tic, getLuaNumber(lua, 1) & 0x1f);
642 lua_pushboolean(lua, pressed);
643 }
644 else
645 {
646 luaL_error(lua, "invalid params, btn [ id ]\n");
647 return 0;
648 }
649
650 return 1;
651}
652
653static s32 lua_spr(lua_State* lua)
654{
655 s32 top = lua_gettop(lua);
656
657 s32 index = 0;
658 s32 x = 0;
659 s32 y = 0;
660 s32 w = 1;
661 s32 h = 1;
662 s32 scale = 1;
663 tic_flip flip = tic_no_flip;
664 tic_rotate rotate = tic_no_rotate;
665 static u8 colors[TIC_PALETTE_SIZE];
666 s32 count = 0;
667
668 if(top >= 1)
669 {
670 index = getLuaNumber(lua, 1);
671
672 if(top >= 3)
673 {
674 x = getLuaNumber(lua, 2);
675 y = getLuaNumber(lua, 3);
676
677 if(top >= 4)
678 {
679 if(lua_istable(lua, 4))
680 {
681 for(s32 i = 1; i <= TIC_PALETTE_SIZE; i++)
682 {
683 lua_rawgeti(lua, 4, i);
684 if(lua_isnumber(lua, -1))
685 {
686 colors[i-1] = getLuaNumber(lua, -1);
687 count++;
688 lua_pop(lua, 1);
689 }
690 else
691 {
692 lua_pop(lua, 1);
693 break;
694 }
695 }
696 }
697 else
698 {
699 colors[0] = getLuaNumber(lua, 4);
700 count = 1;
701 }
702
703 if(top >= 5)
704 {
705 scale = getLuaNumber(lua, 5);
706
707 if(top >= 6)
708 {
709 flip = getLuaNumber(lua, 6);
710
711 if(top >= 7)
712 {
713 rotate = getLuaNumber(lua, 7);
714
715 if(top >= 9)
716 {
717 w = getLuaNumber(lua, 8);
718 h = getLuaNumber(lua, 9);
719 }
720 }
721 }
722 }
723 }
724 }
725 }
726
727 tic_mem* tic = (tic_mem*)getLuaCore(lua);
728
729 tic_api_spr(tic, index, x, y, w, h, colors, count, scale, flip, rotate);
730
731 return 0;
732}
733
734static s32 lua_mget(lua_State* lua)
735{
736 s32 top = lua_gettop(lua);
737
738 if(top == 2)
739 {
740 s32 x = getLuaNumber(lua, 1);
741 s32 y = getLuaNumber(lua, 2);
742
743 tic_mem* tic = (tic_mem*)getLuaCore(lua);
744
745 u8 value = tic_api_mget(tic, x, y);
746 lua_pushinteger(lua, value);
747 return 1;
748 }
749 else luaL_error(lua, "invalid params, mget(x,y)\n");
750
751 return 0;
752}
753
754static s32 lua_mset(lua_State* lua)
755{
756 s32 top = lua_gettop(lua);
757
758 if(top == 3)
759 {
760 s32 x = getLuaNumber(lua, 1);
761 s32 y = getLuaNumber(lua, 2);
762 u8 val = getLuaNumber(lua, 3);
763
764 tic_mem* tic = (tic_mem*)getLuaCore(lua);
765
766 tic_api_mset(tic, x, y, val);
767 }
768 else luaL_error(lua, "invalid params, mget(x,y)\n");
769
770 return 0;
771}
772
773typedef struct
774{
775 lua_State* lua;
776 s32 reg;
777} RemapData;
778
779static void remapCallback(void* data, s32 x, s32 y, RemapResult* result)
780{
781 RemapData* remap = (RemapData*)data;
782 lua_State* lua = remap->lua;
783
784 lua_rawgeti(lua, LUA_REGISTRYINDEX, remap->reg);
785 lua_pushinteger(lua, result->index);
786 lua_pushinteger(lua, x);
787 lua_pushinteger(lua, y);
788 lua_pcall(lua, 3, 3, 0);
789
790 result->index = getLuaNumber(lua, -3);
791 result->flip = getLuaNumber(lua, -2);
792 result->rotate = getLuaNumber(lua, -1);
793}
794
795static s32 lua_map(lua_State* lua)
796{
797 s32 x = 0;
798 s32 y = 0;
799 s32 w = TIC_MAP_SCREEN_WIDTH;
800 s32 h = TIC_MAP_SCREEN_HEIGHT;
801 s32 sx = 0;
802 s32 sy = 0;
803 s32 scale = 1;
804 static u8 colors[TIC_PALETTE_SIZE];
805 s32 count = 0;
806
807 s32 top = lua_gettop(lua);
808
809 if(top >= 2)
810 {
811 x = getLuaNumber(lua, 1);
812 y = getLuaNumber(lua, 2);
813
814 if(top >= 4)
815 {
816 w = getLuaNumber(lua, 3);
817 h = getLuaNumber(lua, 4);
818
819 if(top >= 6)
820 {
821 sx = getLuaNumber(lua, 5);
822 sy = getLuaNumber(lua, 6);
823
824 if(top >= 7)
825 {
826 if(lua_istable(lua, 7))
827 {
828 for(s32 i = 1; i <= TIC_PALETTE_SIZE; i++)
829 {
830 lua_rawgeti(lua, 7, i);
831 if(lua_isnumber(lua, -1))
832 {
833 colors[i-1] = getLuaNumber(lua, -1);
834 count++;
835 lua_pop(lua, 1);
836 }
837 else
838 {
839 lua_pop(lua, 1);
840 break;
841 }
842 }
843 }
844 else
845 {
846 colors[0] = getLuaNumber(lua, 7);
847 count = 1;
848 }
849
850 if(top >= 8)
851 {
852 scale = getLuaNumber(lua, 8);
853
854 if(top >= 9)
855 {
856 if (lua_isfunction(lua, 9))
857 {
858 s32 remap = luaL_ref(lua, LUA_REGISTRYINDEX);
859
860 RemapData data = {lua, remap};
861
862 tic_mem* tic = (tic_mem*)getLuaCore(lua);
863
864 tic_api_map(tic, x, y, w, h, sx, sy, colors, count, scale, remapCallback, &data);
865
866 luaL_unref(lua, LUA_REGISTRYINDEX, data.reg);
867
868 return 0;
869 }
870 }
871 }
872 }
873 }
874 }
875 }
876
877 tic_mem* tic = (tic_mem*)getLuaCore(lua);
878
879 tic_api_map((tic_mem*)getLuaCore(lua), x, y, w, h, sx, sy, colors, count, scale, NULL, NULL);
880
881 return 0;
882}
883
884static s32 lua_music(lua_State* lua)
885{
886 s32 top = lua_gettop(lua);
887 tic_mem* tic = (tic_mem*)getLuaCore(lua);
888
889 if(top == 0) tic_api_music(tic, -1, 0, 0, false, false, -1, -1);
890 else if(top >= 1)
891 {
892 s32 track = getLuaNumber(lua, 1);
893
894 if(track > MUSIC_TRACKS - 1)
895 {
896 luaL_error(lua, "invalid music track index");
897 return 0;
898 }
899
900 tic_api_music(tic, -1, 0, 0, false, false, -1, -1);
901
902 s32 frame = -1;
903 s32 row = -1;
904 bool loop = true;
905 bool sustain = false;
906 s32 tempo = -1;
907 s32 speed = -1;
908
909 if(top >= 2)
910 {
911 frame = getLuaNumber(lua, 2);
912
913 if(top >= 3)
914 {
915 row = getLuaNumber(lua, 3);
916
917 if(top >= 4)
918 {
919 loop = lua_toboolean(lua, 4);
920
921 if (top >= 5)
922 {
923 sustain = lua_toboolean(lua, 5);
924
925 if (top >= 6)
926 {
927 tempo = getLuaNumber(lua, 6);
928
929 if (top >= 7)
930 {
931 speed = getLuaNumber(lua, 7);
932 }
933 }
934 }
935
936 }
937 }
938 }
939
940 tic_api_music(tic, track, frame, row, loop, sustain, tempo, speed);
941 }
942 else luaL_error(lua, "invalid params, use music(track)\n");
943
944 return 0;
945}
946
947static s32 lua_sfx(lua_State* lua)
948{
949 s32 top = lua_gettop(lua);
950
951 if(top >= 1)
952 {
953 tic_mem* tic = (tic_mem*)getLuaCore(lua);
954
955 s32 note = -1;
956 s32 octave = -1;
957 s32 duration = -1;
958 s32 channel = 0;
959 s32 volumes[TIC80_SAMPLE_CHANNELS] = {MAX_VOLUME, MAX_VOLUME};
960 s32 speed = SFX_DEF_SPEED;
961
962 s32 index = getLuaNumber(lua, 1);
963
964 if(index < SFX_COUNT)
965 {
966 if (index >= 0)
967 {
968 tic_sample* effect = tic->ram->sfx.samples.data + index;
969
970 note = effect->note;
971 octave = effect->octave;
972 speed = effect->speed;
973 }
974
975 if(top >= 2)
976 {
977 if(lua_isinteger(lua, 2))
978 {
979 s32 id = getLuaNumber(lua, 2);
980 note = id % NOTES;
981 octave = id / NOTES;
982 }
983 else if(lua_isstring(lua, 2))
984 {
985 const char* noteStr = lua_tostring(lua, 2);
986
987 if(!tic_tool_parse_note(noteStr, &note, &octave))
988 {
989 luaL_error(lua, "invalid note, should be like C#4\n");
990 return 0;
991 }
992 }
993
994 if(top >= 3)
995 {
996 duration = getLuaNumber(lua, 3);
997
998 if(top >= 4)
999 {
1000 channel = getLuaNumber(lua, 4);
1001
1002 if(top >= 5)
1003 {
1004 if(lua_istable(lua, 5))
1005 {
1006 for(s32 i = 0; i < COUNT_OF(volumes); i++)
1007 {
1008 volumes[i] = lua_rawgeti(lua, 5, i + 1);
1009 lua_pop(lua, 1);
1010 }
1011 }
1012 else volumes[0] = volumes[1] = getLuaNumber(lua, 5);
1013
1014 if(top >= 6)
1015 {
1016 speed = getLuaNumber(lua, 6);
1017 }
1018 }
1019 }
1020 }
1021 }
1022
1023 if (channel >= 0 && channel < TIC_SOUND_CHANNELS)
1024 {
1025 tic_api_sfx(tic, index, note, octave, duration, channel, volumes[0] & 0xf, volumes[1] & 0xf, speed);
1026 }
1027 else luaL_error(lua, "unknown channel\n");
1028 }
1029 else luaL_error(lua, "unknown sfx index\n");
1030 }
1031 else luaL_error(lua, "invalid sfx params\n");
1032
1033 return 0;
1034}
1035
1036static s32 lua_vbank(lua_State* lua)
1037{
1038 tic_core* core = getLuaCore(lua);
1039 tic_mem* tic = (tic_mem*)core;
1040
1041 s32 prev = core->state.vbank.id;
1042
1043 if(lua_gettop(lua) == 1)
1044 tic_api_vbank(tic, getLuaNumber(lua, 1));
1045
1046 lua_pushinteger(lua, prev);
1047 return 1;
1048}
1049
1050static s32 lua_sync(lua_State* lua)
1051{
1052 tic_mem* tic = (tic_mem*)getLuaCore(lua);
1053
1054 bool toCart = false;
1055 u32 mask = 0;
1056 s32 bank = 0;
1057
1058 if(lua_gettop(lua) >= 1)
1059 {
1060 mask = getLuaNumber(lua, 1);
1061
1062 if(lua_gettop(lua) >= 2)
1063 {
1064 bank = getLuaNumber(lua, 2);
1065
1066 if(lua_gettop(lua) >= 3)
1067 {
1068 toCart = lua_toboolean(lua, 3);
1069 }
1070 }
1071 }
1072
1073 if(bank >= 0 && bank < TIC_BANKS)
1074 tic_api_sync(tic, mask, bank, toCart);
1075 else
1076 luaL_error(lua, "sync() error, invalid bank");
1077
1078 return 0;
1079}
1080
1081static s32 lua_reset(lua_State* lua)
1082{
1083 tic_core* core = getLuaCore(lua);
1084
1085 core->state.initialized = false;
1086
1087 return 0;
1088}
1089
1090static s32 lua_key(lua_State* lua)
1091{
1092 tic_core* core = getLuaCore(lua);
1093 tic_mem* tic = &core->memory;
1094
1095 s32 top = lua_gettop(lua);
1096
1097 if (top == 0)
1098 {
1099 lua_pushboolean(lua, tic_api_key(tic, tic_key_unknown));
1100 }
1101 else if (top == 1)
1102 {
1103 tic_key key = getLuaNumber(lua, 1);
1104
1105 if(key < tic_keys_count)
1106 lua_pushboolean(lua, tic_api_key(tic, key));
1107 else
1108 {
1109 luaL_error(lua, "unknown keyboard code\n");
1110 return 0;
1111 }
1112 }
1113 else
1114 {
1115 luaL_error(lua, "invalid params, key [code]\n");
1116 return 0;
1117 }
1118
1119 return 1;
1120}
1121
1122static s32 lua_keyp(lua_State* lua)
1123{
1124 tic_core* core = getLuaCore(lua);
1125 tic_mem* tic = &core->memory;
1126
1127 s32 top = lua_gettop(lua);
1128
1129 if (top == 0)
1130 {
1131 lua_pushboolean(lua, tic_api_keyp(tic, tic_key_unknown, -1, -1));
1132 }
1133 else
1134 {
1135 tic_key key = getLuaNumber(lua, 1);
1136
1137 if(key >= tic_keys_count)
1138 {
1139 luaL_error(lua, "unknown keyboard code\n");
1140 }
1141 else
1142 {
1143 if(top == 1)
1144 {
1145 lua_pushboolean(lua, tic_api_keyp(tic, key, -1, -1));
1146 }
1147 else if(top == 3)
1148 {
1149 u32 hold = getLuaNumber(lua, 2);
1150 u32 period = getLuaNumber(lua, 3);
1151
1152 lua_pushboolean(lua, tic_api_keyp(tic, key, hold, period));
1153 }
1154 else
1155 {
1156 luaL_error(lua, "invalid params, keyp [ code [ hold period ] ]\n");
1157 return 0;
1158 }
1159 }
1160 }
1161
1162 return 1;
1163}
1164
1165static s32 lua_memcpy(lua_State* lua)
1166{
1167 s32 top = lua_gettop(lua);
1168
1169 if(top == 3)
1170 {
1171 s32 dest = getLuaNumber(lua, 1);
1172 s32 src = getLuaNumber(lua, 2);
1173 s32 size = getLuaNumber(lua, 3);
1174
1175 tic_mem* tic = (tic_mem*)getLuaCore(lua);
1176 tic_api_memcpy(tic, dest, src, size);
1177 }
1178 else luaL_error(lua, "invalid params, memcpy(dest,src,size)\n");
1179
1180 return 0;
1181}
1182
1183static s32 lua_memset(lua_State* lua)
1184{
1185 s32 top = lua_gettop(lua);
1186
1187 if(top == 3)
1188 {
1189 s32 dest = getLuaNumber(lua, 1);
1190 u8 value = getLuaNumber(lua, 2);
1191 s32 size = getLuaNumber(lua, 3);
1192
1193 tic_mem* tic = (tic_mem*)getLuaCore(lua);
1194 tic_api_memset(tic, dest, value, size);
1195 }
1196 else luaL_error(lua, "invalid params, memset(dest,val,size)\n");
1197
1198 return 0;
1199}
1200
1201static const char* printString(lua_State* lua, s32 index)
1202{
1203 lua_getglobal(lua, "tostring");
1204 lua_pushvalue(lua, -1);
1205 lua_pushvalue(lua, index);
1206 lua_call(lua, 1, 1);
1207
1208 const char* text = lua_tostring(lua, -1);
1209
1210 lua_pop(lua, 2);
1211
1212 return text;
1213}
1214
1215static s32 lua_font(lua_State* lua)
1216{
1217 tic_mem* tic = (tic_mem*)getLuaCore(lua);
1218 s32 top = lua_gettop(lua);
1219
1220 if(top >= 1)
1221 {
1222 const char* text = printString(lua, 1);
1223 s32 x = 0;
1224 s32 y = 0;
1225 s32 width = TIC_SPRITESIZE;
1226 s32 height = TIC_SPRITESIZE;
1227 u8 chromakey = 0;
1228 bool fixed = false;
1229 s32 scale = 1;
1230 bool alt = false;
1231
1232 if(top >= 3)
1233 {
1234 x = getLuaNumber(lua, 2);
1235 y = getLuaNumber(lua, 3);
1236
1237 if(top >= 4)
1238 {
1239 chromakey = getLuaNumber(lua, 4);
1240
1241 if(top >= 6)
1242 {
1243 width = getLuaNumber(lua, 5);
1244 height = getLuaNumber(lua, 6);
1245
1246 if(top >= 7)
1247 {
1248 fixed = lua_toboolean(lua, 7);
1249
1250 if(top >= 8)
1251 {
1252 scale = getLuaNumber(lua, 8);
1253
1254 if(top >= 9)
1255 {
1256 alt = lua_toboolean(lua, 9);
1257 }
1258 }
1259 }
1260 }
1261 }
1262 }
1263
1264 if(scale == 0)
1265 {
1266 lua_pushinteger(lua, 0);
1267 return 1;
1268 }
1269
1270 s32 size = tic_api_font(tic, text, x, y, &chromakey, 1, width, height, fixed, scale, alt);
1271
1272 lua_pushinteger(lua, size);
1273
1274 return 1;
1275 }
1276
1277 return 0;
1278}
1279
1280static s32 lua_print(lua_State* lua)
1281{
1282 s32 top = lua_gettop(lua);
1283
1284 if(top >= 1)
1285 {
1286 tic_mem* tic = (tic_mem*)getLuaCore(lua);
1287
1288 s32 x = 0;
1289 s32 y = 0;
1290 s32 color = TIC_DEFAULT_COLOR;
1291 bool fixed = false;
1292 s32 scale = 1;
1293 bool alt = false;
1294
1295 const char* text = printString(lua, 1);
1296
1297 if(top >= 3)
1298 {
1299 x = getLuaNumber(lua, 2);
1300 y = getLuaNumber(lua, 3);
1301
1302 if(top >= 4)
1303 {
1304 color = getLuaNumber(lua, 4) % TIC_PALETTE_SIZE;
1305
1306 if(top >= 5)
1307 {
1308 fixed = lua_toboolean(lua, 5);
1309
1310 if(top >= 6)
1311 {
1312 scale = getLuaNumber(lua, 6);
1313
1314 if(top >= 7)
1315 {
1316 alt = lua_toboolean(lua, 7);
1317 }
1318 }
1319 }
1320 }
1321 }
1322
1323 if(scale == 0)
1324 {
1325 lua_pushinteger(lua, 0);
1326 return 1;
1327 }
1328
1329 s32 size = tic_api_print(tic, text ? text : "nil", x, y, color, fixed, scale, alt);
1330
1331 lua_pushinteger(lua, size);
1332
1333 return 1;
1334 }
1335
1336 return 0;
1337}
1338
1339static s32 lua_trace(lua_State *lua)
1340{
1341 s32 top = lua_gettop(lua);
1342 tic_mem* tic = (tic_mem*)getLuaCore(lua);
1343
1344 if(top >= 1)
1345 {
1346 const char* text = printString(lua, 1);
1347 u8 color = TIC_DEFAULT_COLOR;
1348
1349 if(top >= 2)
1350 {
1351 color = getLuaNumber(lua, 2);
1352 }
1353
1354 tic_api_trace(tic, text, color);
1355 }
1356 else luaL_error(lua, "invalid params, trace(text,[color])\n");
1357
1358 return 0;
1359}
1360
1361static s32 lua_pmem(lua_State *lua)
1362{
1363 s32 top = lua_gettop(lua);
1364 tic_core* core = getLuaCore(lua);
1365 tic_mem* tic = &core->memory;
1366
1367 if(top >= 1)
1368 {
1369 u32 index = getLuaNumber(lua, 1);
1370
1371 if(index < TIC_PERSISTENT_SIZE)
1372 {
1373 u32 val = tic_api_pmem(tic, index, 0, false);
1374
1375 if(top >= 2)
1376 {
1377 tic_api_pmem(tic, index, (u32)lua_tointeger(lua, 2), true);
1378 }
1379
1380 lua_pushinteger(lua, val);
1381
1382 return 1;
1383 }
1384
1385 luaL_error(lua, "invalid persistent tic index\n");
1386 }
1387 else luaL_error(lua, "invalid params, pmem(index [val]) -> val\n");
1388
1389 return 0;
1390}
1391
1392static s32 lua_time(lua_State *lua)
1393{
1394 tic_mem* tic = (tic_mem*)getLuaCore(lua);
1395
1396 lua_pushnumber(lua, tic_api_time(tic));
1397
1398 return 1;
1399}
1400
1401static s32 lua_tstamp(lua_State *lua)
1402{
1403 tic_mem* tic = (tic_mem*)getLuaCore(lua);
1404
1405 lua_pushnumber(lua, tic_api_tstamp(tic));
1406
1407 return 1;
1408}
1409
1410static s32 lua_exit(lua_State *lua)
1411{
1412 tic_api_exit((tic_mem*)getLuaCore(lua));
1413
1414 return 0;
1415}
1416
1417static s32 lua_mouse(lua_State *lua)
1418{
1419 tic_core* core = getLuaCore(lua);
1420
1421 {
1422 tic_point pos = tic_api_mouse((tic_mem*)core);
1423
1424 lua_pushinteger(lua, pos.x);
1425 lua_pushinteger(lua, pos.y);
1426 }
1427
1428 const tic80_mouse* mouse = &core->memory.ram->input.mouse;
1429
1430 lua_pushboolean(lua, mouse->left);
1431 lua_pushboolean(lua, mouse->middle);
1432 lua_pushboolean(lua, mouse->right);
1433 lua_pushinteger(lua, mouse->scrollx);
1434 lua_pushinteger(lua, mouse->scrolly);
1435
1436 return 7;
1437}
1438
1439static s32 lua_fget(lua_State* lua)
1440{
1441 tic_mem* tic = (tic_mem*)getLuaCore(lua);
1442 s32 top = lua_gettop(lua);
1443
1444 if(top >= 1)
1445 {
1446 u32 index = getLuaNumber(lua, 1);
1447
1448 if(top >= 2)
1449 {
1450 u32 flag = getLuaNumber(lua, 2);
1451 lua_pushboolean(lua, tic_api_fget(tic, index, flag));
1452 return 1;
1453 }
1454 }
1455
1456 luaL_error(lua, "invalid params, fget(sprite,flag)\n");
1457
1458 return 0;
1459}
1460
1461static s32 lua_fset(lua_State* lua)
1462{
1463 tic_mem* tic = (tic_mem*)getLuaCore(lua);
1464 s32 top = lua_gettop(lua);
1465
1466 if(top >= 1)
1467 {
1468 u32 index = getLuaNumber(lua, 1);
1469
1470 if(top >= 2)
1471 {
1472 u32 flag = getLuaNumber(lua, 2);
1473
1474 if(top >= 3)
1475 {
1476 bool value = lua_toboolean(lua, 3);
1477 tic_api_fset(tic, index, flag, value);
1478 return 0;
1479 }
1480 }
1481 }
1482
1483 luaL_error(lua, "invalid params, fset(sprite,flag,value)\n");
1484
1485 return 0;
1486}
1487
1488static s32 lua_dofile(lua_State *lua)
1489{
1490 luaL_error(lua, "unknown method: \"dofile\"\n");
1491
1492 return 0;
1493}
1494
1495static s32 lua_loadfile(lua_State *lua)
1496{
1497 luaL_error(lua, "unknown method: \"loadfile\"\n");
1498
1499 return 0;
1500}
1501
1502void lua_open_builtins(lua_State *lua)
1503{
1504 static const luaL_Reg loadedlibs[] =
1505 {
1506 { "_G", luaopen_base },
1507 { LUA_LOADLIBNAME, luaopen_package },
1508 { LUA_COLIBNAME, luaopen_coroutine },
1509 { LUA_TABLIBNAME, luaopen_table },
1510 { LUA_STRLIBNAME, luaopen_string },
1511 { LUA_MATHLIBNAME, luaopen_math },
1512 { LUA_DBLIBNAME, luaopen_debug },
1513 { NULL, NULL }
1514 };
1515
1516 for (const luaL_Reg *lib = loadedlibs; lib->func; lib++)
1517 {
1518 luaL_requiref(lua, lib->name, lib->func, 1);
1519 lua_pop(lua, 1);
1520 }
1521}
1522
1523void initLuaAPI(tic_core* core)
1524{
1525 static const struct{lua_CFunction func; const char* name;} ApiItems[] =
1526 {
1527#define API_FUNC_DEF(name, ...) {lua_ ## name, #name},
1528 TIC_API_LIST(API_FUNC_DEF)
1529#undef API_FUNC_DEF
1530
1531#if defined(BUILD_DEPRECATED)
1532 {lua_textri, "textri"},
1533#endif
1534 };
1535
1536 for (s32 i = 0; i < COUNT_OF(ApiItems); i++)
1537 registerLuaFunction(core, ApiItems[i].func, ApiItems[i].name);
1538
1539 registerLuaFunction(core, lua_dofile, "dofile");
1540 registerLuaFunction(core, lua_loadfile, "loadfile");
1541}
1542
1543void closeLua(tic_mem* tic)
1544{
1545 tic_core* core = (tic_core*)tic;
1546
1547 if(core->currentVM)
1548 {
1549 lua_close(core->currentVM);
1550 core->currentVM = NULL;
1551 }
1552}
1553
1554static bool initLua(tic_mem* tic, const char* code)
1555{
1556 tic_core* core = (tic_core*)tic;
1557
1558 closeLua(tic);
1559
1560 lua_State* lua = core->currentVM = luaL_newstate();
1561 lua_open_builtins(lua);
1562
1563 initLuaAPI(core);
1564
1565 {
1566 lua_State* lua = core->currentVM;
1567
1568 lua_settop(lua, 0);
1569
1570 if(luaL_loadstring(lua, code) != LUA_OK || lua_pcall(lua, 0, LUA_MULTRET, 0) != LUA_OK)
1571 {
1572 core->data->error(core->data->data, lua_tostring(lua, -1));
1573 return false;
1574 }
1575 }
1576
1577 return true;
1578}
1579
1580/*
1581** Message handler which appends stract trace to exceptions.
1582** This function was extractred from lua.c.
1583*/
1584static s32 msghandler (lua_State *lua)
1585{
1586 const char *msg = lua_tostring(lua, 1);
1587 if (msg == NULL) /* is error object not a string? */
1588 {
1589 if (luaL_callmeta(lua, 1, "__tostring") && /* does it have a metamethod */
1590 lua_type(lua, -1) == LUA_TSTRING) /* that produces a string? */
1591 return 1; /* that is the message */
1592 else
1593 msg = lua_pushfstring(lua, "(error object is a %s value)", luaL_typename(lua, 1));
1594 }
1595 luaL_traceback(lua, lua, msg, 1); /* append a standard traceback */
1596 return 1; /* return the traceback */
1597}
1598
1599/*
1600** Interface to 'lua_pcall', which sets appropriate message handler function.
1601** Please use this function for all top level lua functions.
1602** This function was extractred from lua.c (and stripped of signal handling)
1603*/
1604static s32 docall (lua_State *lua, s32 narg, s32 nres)
1605{
1606 s32 status = 0;
1607 s32 base = lua_gettop(lua) - narg; /* function index */
1608 lua_pushcfunction(lua, msghandler); /* push message handler */
1609 lua_insert(lua, base); /* put it under function and args */
1610 status = lua_pcall(lua, narg, nres, base);
1611 lua_remove(lua, base); /* remove message handler from the stack */
1612 return status;
1613}
1614
1615void callLuaTick(tic_mem* tic)
1616{
1617 tic_core* core = (tic_core*)tic;
1618
1619 lua_State* lua = core->currentVM;
1620
1621 if(lua)
1622 {
1623 lua_getglobal(lua, TIC_FN);
1624 if(lua_isfunction(lua, -1))
1625 {
1626 if(docall(lua, 0, 0) != LUA_OK)
1627 {
1628 core->data->error(core->data->data, lua_tostring(lua, -1));
1629 return;
1630 }
1631
1632 // call OVR() callback for backward compatibility
1633 {
1634 lua_getglobal(lua, OVR_FN);
1635 if(lua_isfunction(lua, -1))
1636 {
1637 OVR(core)
1638 {
1639 if(docall(lua, 0, 0) != LUA_OK)
1640 core->data->error(core->data->data, lua_tostring(lua, -1));
1641 }
1642 }
1643 else lua_pop(lua, 1);
1644 }
1645 }
1646 else
1647 {
1648 lua_pop(lua, 1);
1649 core->data->error(core->data->data, "'function TIC()...' isn't found :(");
1650 }
1651 }
1652}
1653
1654void callLuaIntCallback(tic_mem* tic, s32 value, void* data, const char* name)
1655{
1656 tic_core* core = (tic_core*)tic;
1657 lua_State* lua = core->currentVM;
1658
1659 if (lua)
1660 {
1661 lua_getglobal(lua, name);
1662 if(lua_isfunction(lua, -1))
1663 {
1664 lua_pushinteger(lua, value);
1665 if(docall(lua, 1, 0) != LUA_OK)
1666 core->data->error(core->data->data, lua_tostring(lua, -1));
1667 }
1668 else lua_pop(lua, 1);
1669 }
1670}
1671
1672void callLuaScanline(tic_mem* tic, s32 row, void* data)
1673{
1674 callLuaIntCallback(tic, row, data, SCN_FN);
1675
1676 // try to call old scanline
1677 callLuaIntCallback(tic, row, data, "scanline");
1678}
1679
1680void callLuaBorder(tic_mem* tic, s32 row, void* data)
1681{
1682 callLuaIntCallback(tic, row, data, BDR_FN);
1683}
1684
1685void callLuaMenu(tic_mem* tic, s32 index, void* data)
1686{
1687 callLuaIntCallback(tic, index, data, MENU_FN);
1688}
1689
1690void callLuaBoot(tic_mem* tic)
1691{
1692 tic_core* core = (tic_core*)tic;
1693 lua_State* lua = core->currentVM;
1694
1695 if (lua)
1696 {
1697 lua_getglobal(lua, BOOT_FN);
1698 if(lua_isfunction(lua, -1))
1699 {
1700 if(docall(lua, 0, 0) != LUA_OK)
1701 core->data->error(core->data->data, lua_tostring(lua, -1));
1702 }
1703 else lua_pop(lua, 1);
1704 }
1705}
1706
1707static const char* const LuaKeywords [] =
1708{
1709 "and", "break", "do", "else", "elseif",
1710 "end", "false", "for", "function", "goto", "if",
1711 "in", "local", "nil", "not", "or", "repeat",
1712 "return", "then", "true", "until", "while"
1713};
1714
1715static inline bool isalnum_(char c) {return isalnum(c) || c == '_';}
1716
1717static const tic_outline_item* getLuaOutline(const char* code, s32* size)
1718{
1719 enum{Size = sizeof(tic_outline_item)};
1720
1721 *size = 0;
1722
1723 static tic_outline_item* items = NULL;
1724
1725 if(items)
1726 {
1727 free(items);
1728 items = NULL;
1729 }
1730
1731 const char* ptr = code;
1732
1733 while(true)
1734 {
1735 static const char FuncString[] = "function ";
1736
1737 ptr = strstr(ptr, FuncString);
1738
1739 if(ptr)
1740 {
1741 ptr += sizeof FuncString - 1;
1742
1743 const char* start = ptr;
1744 const char* end = start;
1745
1746 while(*ptr)
1747 {
1748 char c = *ptr;
1749
1750 if(isalnum_(c) || c == ':');
1751 else if(c == '(')
1752 {
1753 end = ptr;
1754 break;
1755 }
1756 else break;
1757
1758 ptr++;
1759 }
1760
1761 if(end > start)
1762 {
1763 items = realloc(items, (*size + 1) * Size);
1764
1765 items[*size].pos = start;
1766 items[*size].size = (s32)(end - start);
1767
1768 (*size)++;
1769 }
1770 }
1771 else break;
1772 }
1773
1774 return items;
1775}
1776
1777static void evalLua(tic_mem* tic, const char* code) {
1778 tic_core* core = (tic_core*)tic;
1779 lua_State* lua = core->currentVM;
1780
1781 if (!lua) return;
1782
1783 lua_settop(lua, 0);
1784
1785 if(luaL_loadstring(lua, code) != LUA_OK || lua_pcall(lua, 0, LUA_MULTRET, 0) != LUA_OK)
1786 {
1787 core->data->error(core->data->data, lua_tostring(lua, -1));
1788 }
1789}
1790
1791tic_script_config LuaSyntaxConfig =
1792{
1793 .id = 10,
1794 .name = "lua",
1795 .fileExtension = ".lua",
1796 .projectComment = "--",
1797 {
1798 .init = initLua,
1799 .close = closeLua,
1800 .tick = callLuaTick,
1801 .boot = callLuaBoot,
1802
1803 .callback =
1804 {
1805 .scanline = callLuaScanline,
1806 .border = callLuaBorder,
1807 .menu = callLuaMenu,
1808 },
1809 },
1810
1811 .getOutline = getLuaOutline,
1812 .eval = evalLua,
1813
1814 .blockCommentStart = "--[[",
1815 .blockCommentEnd = "]]",
1816 .blockCommentStart2 = NULL,
1817 .blockCommentEnd2 = NULL,
1818 .singleComment = "--",
1819 .blockStringStart = "[[",
1820 .blockStringEnd = "]]",
1821 .blockEnd = "end",
1822
1823 .keywords = LuaKeywords,
1824 .keywordsCount = COUNT_OF(LuaKeywords),
1825};
1826
1827#endif /* defined(TIC_BUILD_WITH_LUA) */
1828