1 /*
2 Copyright (c) 2010 Peter "Corsix" Cawley
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy of
5 this software and associated documentation files (the "Software"), to deal in
6 the Software without restriction, including without limitation the rights to
7 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8 of the Software, and to permit persons to whom the Software is furnished to do
9 so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 SOFTWARE.
21 */
22
23 #include "th_gfx.h"
24 #include "th_lua_internal.h"
25 #include "th_map.h"
26
27 namespace {
28
29 /* this variable is used to determine the layer of the animation, it should be
30 rewritten at some
31 point so that the it is passed as an argument in the function l_anim_set_tile
32 */
33 int last_layer = 2;
34
l_anims_new(lua_State * L)35 int l_anims_new(lua_State* L) {
36 luaT_stdnew<animation_manager>(L, luaT_environindex, true);
37 return 1;
38 }
39
l_anims_set_spritesheet(lua_State * L)40 int l_anims_set_spritesheet(lua_State* L) {
41 animation_manager* pAnims = luaT_testuserdata<animation_manager>(L);
42 sprite_sheet* pSheet = luaT_testuserdata<sprite_sheet>(L, 2);
43 lua_settop(L, 2);
44
45 pAnims->set_sprite_sheet(pSheet);
46 luaT_setenvfield(L, 1, "sprites");
47 return 1;
48 }
49
50 //! Set the video target for the sprites.
51 /*!
52 setCanvas(<video-surface>)
53 */
l_anims_set_canvas(lua_State * L)54 int l_anims_set_canvas(lua_State* L) {
55 animation_manager* pAnims = luaT_testuserdata<animation_manager>(L);
56 render_target* pCanvas = luaT_testuserdata<render_target>(L, 2);
57 lua_settop(L, 2);
58
59 pAnims->set_canvas(pCanvas);
60 luaT_setenvfield(L, 1, "target");
61 return 1;
62 }
63
l_anims_load(lua_State * L)64 int l_anims_load(lua_State* L) {
65 animation_manager* pAnims = luaT_testuserdata<animation_manager>(L);
66 size_t iStartDataLength, iFrameDataLength, iListDataLength,
67 iElementDataLength;
68 const uint8_t* pStartData = luaT_checkfile(L, 2, &iStartDataLength);
69 const uint8_t* pFrameData = luaT_checkfile(L, 3, &iFrameDataLength);
70 const uint8_t* pListData = luaT_checkfile(L, 4, &iListDataLength);
71 const uint8_t* pElementData = luaT_checkfile(L, 5, &iElementDataLength);
72
73 if (pAnims->load_from_th_file(pStartData, iStartDataLength, pFrameData,
74 iFrameDataLength, pListData, iListDataLength,
75 pElementData, iElementDataLength)) {
76 lua_pushboolean(L, 1);
77 } else {
78 lua_pushboolean(L, 0);
79 }
80
81 return 1;
82 }
83
84 //! Load custom animations.
85 /*!
86 loadCustom(<data-of-an-animation-file>) -> true/false
87 */
l_anims_loadcustom(lua_State * L)88 int l_anims_loadcustom(lua_State* L) {
89 animation_manager* pAnims = luaT_testuserdata<animation_manager>(L);
90 size_t iDataLength;
91 const uint8_t* pData = luaT_checkfile(L, 2, &iDataLength);
92
93 if (pAnims->load_custom_animations(pData, iDataLength)) {
94 lua_pushboolean(L, 1);
95 } else {
96 lua_pushboolean(L, 0);
97 }
98
99 return 1;
100 }
101
102 //! Lua interface for getting a set of animations by name and tile size (one for
103 //! each view direction, 'nil' if no animation is available for a direction).
104 /*!
105 getAnimations(<tile-size>, <animation-name>) -> (<anim-north>, <anim-east>,
106 <anim-south>, <anim-west>)
107 */
l_anims_getanims(lua_State * L)108 int l_anims_getanims(lua_State* L) {
109 animation_manager* pAnims = luaT_testuserdata<animation_manager>(L);
110 int iTileSize = static_cast<int>(luaL_checkinteger(L, 2));
111 const char* pName = luaL_checkstring(L, 3);
112
113 const animation_start_frames& oFrames =
114 pAnims->get_named_animations(pName, iTileSize);
115 if (oFrames.north < 0) {
116 lua_pushnil(L);
117 } else {
118 lua_pushnumber(L, static_cast<double>(oFrames.north));
119 }
120 if (oFrames.east < 0) {
121 lua_pushnil(L);
122 } else {
123 lua_pushnumber(L, static_cast<double>(oFrames.east));
124 }
125 if (oFrames.south < 0) {
126 lua_pushnil(L);
127 } else {
128 lua_pushnumber(L, static_cast<double>(oFrames.south));
129 }
130 if (oFrames.west < 0) {
131 lua_pushnil(L);
132 } else {
133 lua_pushnumber(L, static_cast<double>(oFrames.west));
134 }
135 return 4;
136 }
137
l_anims_getfirst(lua_State * L)138 int l_anims_getfirst(lua_State* L) {
139 animation_manager* pAnims = luaT_testuserdata<animation_manager>(L);
140 int iAnim = static_cast<int>(luaL_checkinteger(L, 2));
141
142 lua_pushinteger(L, pAnims->get_first_frame(iAnim));
143 return 1;
144 }
145
l_anims_getnext(lua_State * L)146 int l_anims_getnext(lua_State* L) {
147 animation_manager* pAnims = luaT_testuserdata<animation_manager>(L);
148 int iFrame = static_cast<int>(luaL_checkinteger(L, 2));
149
150 lua_pushinteger(L, pAnims->get_next_frame(iFrame));
151 return 1;
152 }
153
l_anims_set_alt_pal(lua_State * L)154 int l_anims_set_alt_pal(lua_State* L) {
155 animation_manager* pAnims = luaT_testuserdata<animation_manager>(L);
156 size_t iAnimation = luaL_checkinteger(L, 2);
157 size_t iPalLen;
158 const uint8_t* pPal = luaT_checkfile(L, 3, &iPalLen);
159 if (iPalLen != 256) {
160 return luaL_argerror(L, 3, "GhostPalette string is not a valid palette");
161 }
162 uint32_t iAlt32 = static_cast<uint32_t>(luaL_checkinteger(L, 4));
163
164 pAnims->set_animation_alt_palette_map(iAnimation, pPal, iAlt32);
165
166 lua_getfenv(L, 1);
167 lua_insert(L, 2);
168 lua_settop(L, 4);
169 lua_settable(L, 2);
170 lua_settop(L, 1);
171 return 1;
172 }
173
l_anims_set_marker(lua_State * L)174 int l_anims_set_marker(lua_State* L) {
175 animation_manager* pAnims = luaT_testuserdata<animation_manager>(L);
176 lua_pushboolean(
177 L, pAnims->set_frame_marker(luaL_checkinteger(L, 2),
178 static_cast<int>(luaL_checkinteger(L, 3)),
179 static_cast<int>(luaL_checkinteger(L, 4)))
180 ? 1
181 : 0);
182 return 1;
183 }
184
l_anims_set_secondary_marker(lua_State * L)185 int l_anims_set_secondary_marker(lua_State* L) {
186 animation_manager* pAnims = luaT_testuserdata<animation_manager>(L);
187 lua_pushboolean(
188 L, pAnims->set_frame_secondary_marker(
189 luaL_checkinteger(L, 2), static_cast<int>(luaL_checkinteger(L, 3)),
190 static_cast<int>(luaL_checkinteger(L, 4)))
191 ? 1
192 : 0);
193 return 1;
194 }
195
l_anims_draw(lua_State * L)196 int l_anims_draw(lua_State* L) {
197 animation_manager* pAnims = luaT_testuserdata<animation_manager>(L);
198 render_target* pCanvas = luaT_testuserdata<render_target>(L, 2);
199 size_t iFrame = luaL_checkinteger(L, 3);
200 layers* pLayers = luaT_testuserdata<layers>(L, 4, luaT_upvalueindex(2));
201 int iX = static_cast<int>(luaL_checkinteger(L, 5));
202 int iY = static_cast<int>(luaL_checkinteger(L, 6));
203 int iFlags = static_cast<int>(luaL_optinteger(L, 7, 0));
204
205 pAnims->draw_frame(pCanvas, iFrame, *pLayers, iX, iY, iFlags);
206
207 lua_settop(L, 1);
208 return 1;
209 }
210
211 template <typename T>
l_anim_new(lua_State * L)212 int l_anim_new(lua_State* L) {
213 T* pAnimation = luaT_stdnew<T>(L, luaT_environindex, true);
214 lua_rawgeti(L, luaT_environindex, 2);
215 lua_pushlightuserdata(L, pAnimation);
216 lua_pushvalue(L, -3);
217 lua_rawset(L, -3);
218 lua_pop(L, 1);
219 return 1;
220 }
221
222 template <typename T>
l_anim_persist(lua_State * L)223 int l_anim_persist(lua_State* L) {
224 T* pAnimation;
225 if (lua_gettop(L) == 3) {
226 pAnimation = luaT_testuserdata<T>(L, 1, luaT_environindex, false);
227 luaT_rotate(L, 1, -1);
228 } else {
229 // Fast __persist call
230 pAnimation = (T*)lua_touserdata(L, -1);
231 }
232 lua_persist_writer* pWriter = (lua_persist_writer*)lua_touserdata(L, 1);
233
234 pAnimation->persist(pWriter);
235 lua_rawgeti(L, luaT_environindex, 1);
236 lua_pushlightuserdata(L, pAnimation);
237 lua_gettable(L, -2);
238 pWriter->write_stack_object(-1);
239 lua_pop(L, 2);
240 return 0;
241 }
242
243 template <typename T>
l_anim_pre_depersist(lua_State * L)244 int l_anim_pre_depersist(lua_State* L) {
245 // Note that anims and the map have nice reference cycles between them
246 // and hence we cannot be sure which is depersisted first. To ensure that
247 // things work nicely, we initialise all the fields of a THAnimation as
248 // soon as possible, thus preventing issues like an anim -> map -> anim
249 // reference chain whereby l_anim_depersist is called after l_map_depersist
250 // (as anim references map in its environment table) causing the prev
251 // field to be set during map depersistence, then cleared to nullptr by the
252 // constructor during l_anim_depersist.
253 T* pAnimation = luaT_testuserdata<T>(L);
254 new (pAnimation) T; // Call constructor
255 return 0;
256 }
257
258 template <typename T>
l_anim_depersist(lua_State * L)259 int l_anim_depersist(lua_State* L) {
260 T* pAnimation = luaT_testuserdata<T>(L);
261 lua_settop(L, 2);
262 lua_insert(L, 1);
263 lua_persist_reader* pReader = (lua_persist_reader*)lua_touserdata(L, 1);
264
265 lua_rawgeti(L, luaT_environindex, 2);
266 lua_pushlightuserdata(L, pAnimation);
267 lua_pushvalue(L, 2);
268 lua_settable(L, -3);
269 lua_pop(L, 1);
270 pAnimation->depersist(pReader);
271 lua_rawgeti(L, luaT_environindex, 1);
272 lua_pushlightuserdata(L, pAnimation);
273 if (!pReader->read_stack_object()) return 0;
274 lua_settable(L, -3);
275 lua_pop(L, 1);
276 return 0;
277 }
278
l_anim_set_hitresult(lua_State * L)279 int l_anim_set_hitresult(lua_State* L) {
280 luaL_checktype(L, 1, LUA_TUSERDATA);
281 lua_settop(L, 2);
282 lua_rawgeti(L, luaT_environindex, 1);
283 lua_pushlightuserdata(L, lua_touserdata(L, 1));
284 lua_pushvalue(L, 2);
285 lua_settable(L, 3);
286 lua_settop(L, 1);
287 return 1;
288 }
289
l_anim_set_frame(lua_State * L)290 int l_anim_set_frame(lua_State* L) {
291 animation* pAnimation = luaT_testuserdata<animation>(L);
292 pAnimation->set_frame(luaL_checkinteger(L, 2));
293 lua_settop(L, 1);
294 return 1;
295 }
296
l_anim_get_frame(lua_State * L)297 int l_anim_get_frame(lua_State* L) {
298 animation* pAnimation = luaT_testuserdata<animation>(L);
299 lua_pushinteger(L, pAnimation->get_frame());
300 return 1;
301 }
302
l_anim_set_crop(lua_State * L)303 int l_anim_set_crop(lua_State* L) {
304 animation* pAnimation = luaT_testuserdata<animation>(L);
305 pAnimation->set_crop_column(static_cast<int>(luaL_checkinteger(L, 2)));
306 lua_settop(L, 1);
307 return 1;
308 }
309
l_anim_get_crop(lua_State * L)310 int l_anim_get_crop(lua_State* L) {
311 animation* pAnimation = luaT_testuserdata<animation>(L);
312 lua_pushinteger(L, pAnimation->get_crop_column());
313 return 1;
314 }
315
l_anim_set_anim(lua_State * L)316 int l_anim_set_anim(lua_State* L) {
317 animation* pAnimation = luaT_testuserdata<animation>(L);
318 animation_manager* pManager = luaT_testuserdata<animation_manager>(L, 2);
319 lua_Integer iAnim = luaL_checkinteger(L, 3);
320 if (iAnim < 0 ||
321 iAnim >= static_cast<lua_Integer>(pManager->get_animation_count()))
322 luaL_argerror(L, 3, "Animation index out of bounds");
323
324 if (lua_isnoneornil(L, 4)) {
325 pAnimation->set_flags(0);
326 } else {
327 pAnimation->set_flags(static_cast<uint32_t>(luaL_checkinteger(L, 4)));
328 }
329
330 pAnimation->set_animation(pManager, static_cast<size_t>(iAnim));
331 lua_settop(L, 2);
332 luaT_setenvfield(L, 1, "animator");
333 lua_pushnil(L);
334 luaT_setenvfield(L, 1, "morph_target");
335
336 return 1;
337 }
338
l_anim_set_morph(lua_State * L)339 int l_anim_set_morph(lua_State* L) {
340 animation* pAnimation = luaT_testuserdata<animation>(L);
341 animation* pMorphTarget =
342 luaT_testuserdata<animation>(L, 2, luaT_environindex);
343
344 int iDurationFactor = 1;
345 if (!lua_isnoneornil(L, 3) && luaL_checkinteger(L, 3) > 0) {
346 iDurationFactor = static_cast<int>(luaL_checkinteger(L, 3));
347 }
348
349 pAnimation->set_morph_target(pMorphTarget, iDurationFactor);
350 lua_settop(L, 2);
351 luaT_setenvfield(L, 1, "morph_target");
352
353 return 1;
354 }
355
l_anim_set_drawable_layer(lua_State * L)356 int l_anim_set_drawable_layer(lua_State* L) {
357 last_layer = static_cast<int>(luaL_checkinteger(L, 2));
358 return 1;
359 }
360
l_anim_get_anim(lua_State * L)361 int l_anim_get_anim(lua_State* L) {
362 animation* pAnimation = luaT_testuserdata<animation>(L);
363 lua_pushinteger(L, pAnimation->get_animation());
364
365 return 1;
366 }
367
368 template <typename T>
l_anim_set_tile(lua_State * L)369 int l_anim_set_tile(lua_State* L) {
370 T* pAnimation = luaT_testuserdata<T>(L);
371 if (lua_isnoneornil(L, 2)) {
372 pAnimation->remove_from_tile();
373 lua_pushnil(L);
374 luaT_setenvfield(L, 1, "map");
375 lua_settop(L, 1);
376 } else {
377 level_map* pMap = luaT_testuserdata<level_map>(L, 2);
378 map_tile* pNode =
379 pMap->get_tile(static_cast<int>(luaL_checkinteger(L, 3) - 1),
380 static_cast<int>(luaL_checkinteger(L, 4) - 1));
381 if (pNode) {
382 pAnimation->attach_to_tile(pNode, last_layer);
383 } else {
384 luaL_argerror(L, 3,
385 lua_pushfstring(L,
386 "Map index out of bounds (" LUA_NUMBER_FMT
387 "," LUA_NUMBER_FMT ")",
388 lua_tonumber(L, 3), lua_tonumber(L, 4)));
389 }
390
391 lua_settop(L, 2);
392 luaT_setenvfield(L, 1, "map");
393 }
394
395 return 1;
396 }
397
l_anim_get_tile(lua_State * L)398 int l_anim_get_tile(lua_State* L) {
399 animation* pAnimation = luaT_testuserdata<animation>(L);
400 lua_settop(L, 1);
401 lua_getfenv(L, 1);
402 lua_getfield(L, 2, "map");
403 lua_replace(L, 2);
404 if (lua_isnil(L, 2)) {
405 return 0;
406 }
407 level_map* pMap = (level_map*)lua_touserdata(L, 2);
408 const link_list* pListNode = pAnimation->get_previous();
409 while (pListNode->prev) {
410 pListNode = pListNode->prev;
411 }
412 // Casting pListNode to a map_tile* is slightly dubious, but it should
413 // work. If on the normal list, then pListNode will be a map_tile*, and
414 // all is fine. However, if on the early list, pListNode will be pointing
415 // to a member of a map_tile, so we're relying on pointer arithmetic
416 // being a subtract and integer divide by sizeof(map_tile) to yield the
417 // correct map_tile.
418 const map_tile* pRootNode = pMap->get_tile_unchecked(0, 0);
419 uintptr_t iDiff = reinterpret_cast<const char*>(pListNode) -
420 reinterpret_cast<const char*>(pRootNode);
421 int iIndex = (int)(iDiff / sizeof(map_tile));
422 int iY = iIndex / pMap->get_width();
423 int iX = iIndex - (iY * pMap->get_width());
424 lua_pushinteger(L, iX + 1);
425 lua_pushinteger(L, iY + 1);
426 return 3; // map, x, y
427 }
428
l_anim_set_parent(lua_State * L)429 int l_anim_set_parent(lua_State* L) {
430 animation* pAnimation = luaT_testuserdata<animation>(L);
431 animation* pParent =
432 luaT_testuserdata<animation>(L, 2, luaT_environindex, false);
433 pAnimation->set_parent(pParent);
434 lua_settop(L, 1);
435 return 1;
436 }
437
438 template <typename T>
l_anim_set_flag(lua_State * L)439 int l_anim_set_flag(lua_State* L) {
440 T* pAnimation = luaT_testuserdata<T>(L);
441 pAnimation->set_flags(static_cast<uint32_t>(luaL_checkinteger(L, 2)));
442
443 lua_settop(L, 1);
444 return 1;
445 }
446
447 template <typename T>
l_anim_set_flag_partial(lua_State * L)448 int l_anim_set_flag_partial(lua_State* L) {
449 T* pAnimation = luaT_testuserdata<T>(L);
450 uint32_t iFlags = static_cast<uint32_t>(luaL_checkinteger(L, 2));
451 if (lua_isnone(L, 3) || lua_toboolean(L, 3)) {
452 pAnimation->set_flags(pAnimation->get_flags() | iFlags);
453 } else {
454 pAnimation->set_flags(pAnimation->get_flags() & ~iFlags);
455 }
456 lua_settop(L, 1);
457 return 1;
458 }
459
460 template <typename T>
l_anim_make_visible(lua_State * L)461 int l_anim_make_visible(lua_State* L) {
462 T* pAnimation = luaT_testuserdata<T>(L);
463 pAnimation->set_flags(pAnimation->get_flags() &
464 ~static_cast<uint32_t>(thdf_alpha_50 | thdf_alpha_75));
465
466 lua_settop(L, 1);
467 return 1;
468 }
469
470 template <typename T>
l_anim_make_invisible(lua_State * L)471 int l_anim_make_invisible(lua_State* L) {
472 T* pAnimation = luaT_testuserdata<T>(L);
473 pAnimation->set_flags(pAnimation->get_flags() |
474 static_cast<uint32_t>(thdf_alpha_50 | thdf_alpha_75));
475
476 lua_settop(L, 1);
477 return 1;
478 }
479
480 template <typename T>
l_anim_get_flag(lua_State * L)481 int l_anim_get_flag(lua_State* L) {
482 T* pAnimation = luaT_testuserdata<T>(L);
483 lua_pushinteger(L, pAnimation->get_flags());
484
485 return 1;
486 }
487
488 template <typename T>
l_anim_set_position(lua_State * L)489 int l_anim_set_position(lua_State* L) {
490 T* pAnimation = luaT_testuserdata<T>(L);
491
492 pAnimation->set_position(static_cast<int>(luaL_checkinteger(L, 2)),
493 static_cast<int>(luaL_checkinteger(L, 3)));
494
495 lua_settop(L, 1);
496 return 1;
497 }
498
l_anim_get_position(lua_State * L)499 int l_anim_get_position(lua_State* L) {
500 animation* pAnimation = luaT_testuserdata<animation>(L);
501
502 lua_pushinteger(L, pAnimation->get_x());
503 lua_pushinteger(L, pAnimation->get_y());
504
505 return 2;
506 }
507
508 template <typename T>
l_anim_set_speed(lua_State * L)509 int l_anim_set_speed(lua_State* L) {
510 T* pAnimation = luaT_testuserdata<T>(L);
511
512 pAnimation->set_speed(static_cast<int>(luaL_optinteger(L, 2, 0)),
513 static_cast<int>(luaL_optinteger(L, 3, 0)));
514
515 lua_settop(L, 1);
516 return 1;
517 }
518
519 template <typename T>
l_anim_set_layer(lua_State * L)520 int l_anim_set_layer(lua_State* L) {
521 T* pAnimation = luaT_testuserdata<T>(L);
522
523 pAnimation->set_layer(static_cast<int>(luaL_checkinteger(L, 2)),
524 static_cast<int>(luaL_optinteger(L, 3, 0)));
525
526 lua_settop(L, 1);
527 return 1;
528 }
529
l_anim_set_layers_from(lua_State * L)530 int l_anim_set_layers_from(lua_State* L) {
531 animation* pAnimation = luaT_testuserdata<animation>(L);
532 const animation* pAnimationSrc =
533 luaT_testuserdata<animation>(L, 2, luaT_environindex);
534
535 pAnimation->set_layers_from(pAnimationSrc);
536
537 lua_settop(L, 1);
538 return 1;
539 }
540
l_anim_set_tag(lua_State * L)541 int l_anim_set_tag(lua_State* L) {
542 luaT_testuserdata<animation>(L);
543 lua_settop(L, 2);
544 luaT_setenvfield(L, 1, "tag");
545 return 1;
546 }
547
l_anim_get_tag(lua_State * L)548 int l_anim_get_tag(lua_State* L) {
549 luaT_testuserdata<animation>(L);
550 lua_settop(L, 1);
551 lua_getfenv(L, 1);
552 lua_getfield(L, 2, "tag");
553 return 1;
554 }
555
l_anim_get_marker(lua_State * L)556 int l_anim_get_marker(lua_State* L) {
557 animation* pAnimation = luaT_testuserdata<animation>(L);
558 int iX = 0;
559 int iY = 0;
560 pAnimation->get_marker(&iX, &iY);
561 lua_pushinteger(L, iX);
562 lua_pushinteger(L, iY);
563 return 2;
564 }
565
l_anim_get_secondary_marker(lua_State * L)566 int l_anim_get_secondary_marker(lua_State* L) {
567 animation* pAnimation = luaT_testuserdata<animation>(L);
568 int iX = 0;
569 int iY = 0;
570 pAnimation->get_secondary_marker(&iX, &iY);
571 lua_pushinteger(L, iX);
572 lua_pushinteger(L, iY);
573 return 2;
574 }
575
576 template <typename T>
l_anim_tick(lua_State * L)577 int l_anim_tick(lua_State* L) {
578 T* pAnimation = luaT_testuserdata<T>(L);
579 pAnimation->tick();
580 lua_settop(L, 1);
581 return 1;
582 }
583
584 template <typename T>
l_anim_draw(lua_State * L)585 int l_anim_draw(lua_State* L) {
586 T* pAnimation = luaT_testuserdata<T>(L);
587 render_target* pCanvas = luaT_testuserdata<render_target>(L, 2);
588 pAnimation->draw(pCanvas, static_cast<int>(luaL_checkinteger(L, 3)),
589 static_cast<int>(luaL_checkinteger(L, 4)));
590 lua_settop(L, 1);
591 return 1;
592 }
593
l_srl_set_sheet(lua_State * L)594 int l_srl_set_sheet(lua_State* L) {
595 sprite_render_list* pSrl = luaT_testuserdata<sprite_render_list>(L);
596 sprite_sheet* pSheet = luaT_testuserdata<sprite_sheet>(L, 2);
597 pSrl->set_sheet(pSheet);
598
599 lua_settop(L, 2);
600 luaT_setenvfield(L, 1, "sheet");
601 return 1;
602 }
603
l_srl_append(lua_State * L)604 int l_srl_append(lua_State* L) {
605 sprite_render_list* pSrl = luaT_testuserdata<sprite_render_list>(L);
606 pSrl->append_sprite(luaL_checkinteger(L, 2),
607 static_cast<int>(luaL_checkinteger(L, 3)),
608 static_cast<int>(luaL_checkinteger(L, 4)));
609 lua_settop(L, 1);
610 return 1;
611 }
612
l_srl_set_lifetime(lua_State * L)613 int l_srl_set_lifetime(lua_State* L) {
614 sprite_render_list* pSrl = luaT_testuserdata<sprite_render_list>(L);
615 pSrl->set_lifetime(static_cast<int>(luaL_checkinteger(L, 2)));
616 lua_settop(L, 1);
617 return 1;
618 }
619
l_srl_is_dead(lua_State * L)620 int l_srl_is_dead(lua_State* L) {
621 sprite_render_list* pSrl = luaT_testuserdata<sprite_render_list>(L);
622 lua_pushboolean(L, pSrl->is_dead() ? 1 : 0);
623 return 1;
624 }
625
626 } // namespace
627
lua_register_anims(const lua_register_state * pState)628 void lua_register_anims(const lua_register_state* pState) {
629 // Anims
630 {
631 lua_class_binding<animation_manager> lcb(pState, "anims", l_anims_new,
632 lua_metatable::anims);
633 lcb.add_function(l_anims_load, "load");
634 lcb.add_function(l_anims_loadcustom, "loadCustom");
635 lcb.add_function(l_anims_set_spritesheet, "setSheet", lua_metatable::sheet);
636 lcb.add_function(l_anims_set_canvas, "setCanvas", lua_metatable::surface);
637 lcb.add_function(l_anims_getanims, "getAnimations");
638 lcb.add_function(l_anims_getfirst, "getFirstFrame");
639 lcb.add_function(l_anims_getnext, "getNextFrame");
640 lcb.add_function(l_anims_set_alt_pal, "setAnimationGhostPalette");
641 lcb.add_function(l_anims_set_marker, "setFrameMarker");
642 lcb.add_function(l_anims_set_secondary_marker, "setFrameSecondaryMarker");
643 lcb.add_function(l_anims_draw, "draw", lua_metatable::surface,
644 lua_metatable::layers);
645 lcb.add_constant("Alt32_GreyScale", thdf_alt32_grey_scale);
646 lcb.add_constant("Alt32_BlueRedSwap", thdf_alt32_blue_red_swap);
647 }
648
649 // Weak table at AnimMetatable[1] for light UD -> object lookup
650 // For hitTest / setHitTestResult
651 lua_newtable(pState->L);
652 lua_createtable(pState->L, 0, 1);
653 lua_pushliteral(pState->L, "v");
654 lua_setfield(pState->L, -2, "__mode");
655 lua_setmetatable(pState->L, -2);
656 lua_rawseti(pState->L,
657 pState->metatables[static_cast<size_t>(lua_metatable::anim)], 1);
658
659 // Weak table at AnimMetatable[2] for light UD -> full UD lookup
660 // For persisting Map
661 lua_newtable(pState->L);
662 lua_createtable(pState->L, 0, 1);
663 lua_pushliteral(pState->L, "v");
664 lua_setfield(pState->L, -2, "__mode");
665 lua_setmetatable(pState->L, -2);
666 lua_rawseti(pState->L,
667 pState->metatables[static_cast<size_t>(lua_metatable::anim)], 2);
668
669 // Anim
670 {
671 lua_class_binding<animation> lcb(pState, "animation", l_anim_new<animation>,
672 lua_metatable::anim);
673 lcb.add_metamethod(l_anim_persist<animation>, "persist");
674 lcb.add_metamethod(l_anim_pre_depersist<animation>, "pre_depersist");
675 lcb.add_metamethod(l_anim_depersist<animation>, "depersist");
676 lcb.add_function(l_anim_set_anim, "setAnimation", lua_metatable::anims);
677 lcb.add_function(l_anim_set_crop, "setCrop");
678 lcb.add_function(l_anim_get_crop, "getCrop");
679 lcb.add_function(l_anim_set_morph, "setMorph");
680 lcb.add_function(l_anim_set_frame, "setFrame");
681 lcb.add_function(l_anim_get_frame, "getFrame");
682 lcb.add_function(l_anim_get_anim, "getAnimation");
683 lcb.add_function(l_anim_set_tile<animation>, "setTile", lua_metatable::map);
684 lcb.add_function(l_anim_get_tile, "getTile");
685 lcb.add_function(l_anim_set_parent, "setParent");
686 lcb.add_function(l_anim_set_flag<animation>, "setFlag");
687 lcb.add_function(l_anim_set_flag_partial<animation>, "setPartialFlag");
688 lcb.add_function(l_anim_get_flag<animation>, "getFlag");
689 lcb.add_function(l_anim_make_visible<animation>, "makeVisible");
690 lcb.add_function(l_anim_make_invisible<animation>, "makeInvisible");
691 lcb.add_function(l_anim_set_tag, "setTag");
692 lcb.add_function(l_anim_get_tag, "getTag");
693 lcb.add_function(l_anim_set_position<animation>, "setPosition");
694 lcb.add_function(l_anim_get_position, "getPosition");
695 lcb.add_function(l_anim_set_speed<animation>, "setSpeed");
696 lcb.add_function(l_anim_set_layer<animation>, "setLayer");
697 lcb.add_function(l_anim_set_layers_from, "setLayersFrom");
698 lcb.add_function(l_anim_set_hitresult, "setHitTestResult");
699 lcb.add_function(l_anim_get_marker, "getMarker");
700 lcb.add_function(l_anim_get_secondary_marker, "getSecondaryMarker");
701 lcb.add_function(l_anim_tick<animation>, "tick");
702 lcb.add_function(l_anim_draw<animation>, "draw", lua_metatable::surface);
703 lcb.add_function(l_anim_set_drawable_layer, "setDrawingLayer");
704 }
705
706 // Duplicate AnimMetatable[1,2] to SpriteListMetatable[1,2]
707 lua_rawgeti(pState->L,
708 pState->metatables[static_cast<size_t>(lua_metatable::anim)], 1);
709 lua_rawseti(
710 pState->L,
711 pState->metatables[static_cast<size_t>(lua_metatable::sprite_list)], 1);
712 lua_rawgeti(pState->L,
713 pState->metatables[static_cast<size_t>(lua_metatable::anim)], 2);
714 lua_rawseti(
715 pState->L,
716 pState->metatables[static_cast<size_t>(lua_metatable::sprite_list)], 2);
717
718 // SpriteList
719 {
720 lua_class_binding<sprite_render_list> lcb(pState, "spriteList",
721 l_anim_new<sprite_render_list>,
722 lua_metatable::sprite_list);
723 lcb.add_metamethod(l_anim_persist<sprite_render_list>, "persist");
724 lcb.add_metamethod(l_anim_pre_depersist<sprite_render_list>,
725 "pre_depersist");
726 lcb.add_metamethod(l_anim_depersist<sprite_render_list>, "depersist");
727 lcb.add_function(l_srl_set_sheet, "setSheet", lua_metatable::sheet);
728 lcb.add_function(l_srl_append, "append");
729 lcb.add_function(l_srl_set_lifetime, "setLifetime");
730 lcb.add_function(l_srl_is_dead, "isDead");
731 lcb.add_function(l_anim_set_tile<sprite_render_list>, "setTile",
732 lua_metatable::map);
733 lcb.add_function(l_anim_set_flag<sprite_render_list>, "setFlag");
734 lcb.add_function(l_anim_set_flag_partial<sprite_render_list>,
735 "setPartialFlag");
736 lcb.add_function(l_anim_get_flag<sprite_render_list>, "getFlag");
737 lcb.add_function(l_anim_make_visible<sprite_render_list>, "makeVisible");
738 lcb.add_function(l_anim_make_invisible<sprite_render_list>,
739 "makeInvisible");
740 lcb.add_function(l_anim_set_position<sprite_render_list>, "setPosition");
741 lcb.add_function(l_anim_set_speed<sprite_render_list>, "setSpeed");
742 lcb.add_function(l_anim_set_layer<sprite_render_list>, "setLayer");
743 lcb.add_function(l_anim_tick<sprite_render_list>, "tick");
744 lcb.add_function(l_anim_draw<sprite_render_list>, "draw",
745 lua_metatable::surface);
746 }
747 }
748