1 /*
2 Copyright (c) 2009 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
25 #include "config.h"
26
27 #include <algorithm>
28 #include <cassert>
29 #include <climits>
30 #include <cstring>
31 #include <new>
32
33 #include "persist_lua.h"
34 #include "th_map.h"
35 #include "th_sound.h"
36
37 /** Data retrieval class, simulating sequential access to the data, keeping
38 * track of available length. */
39 class memory_reader {
40 public:
memory_reader(const uint8_t * pData,size_t iLength)41 memory_reader(const uint8_t* pData, size_t iLength) {
42 data = pData;
43 remaining_bytes = iLength;
44 }
45
46 const uint8_t* data; ///< Pointer to the remaining data.
47 size_t remaining_bytes; ///< Remaining number of bytes.
48
49 //! Can \a iSize bytes be read from the file?
50 /*!
51 @param iSize Number of bytes that are queried.
52 @return Whether the requested number of bytes is still available.
53 */
are_bytes_available(size_t iSize)54 bool are_bytes_available(size_t iSize) { return iSize <= remaining_bytes; }
55
56 //! Is EOF reached?
57 /*!
58 @return Whether EOF has been reached.
59 */
is_at_end_of_file()60 bool is_at_end_of_file() { return remaining_bytes == 0; }
61
62 //! Get an 8 bit value from the file.
63 /*!
64 @return Read 8 bit value.
65 @pre There should be at least a byte available for reading.
66 */
read_uint8()67 uint8_t read_uint8() {
68 assert(remaining_bytes > 0);
69
70 uint8_t iVal = *data;
71 data++;
72 remaining_bytes--;
73 return iVal;
74 }
75
76 //! Get a 16 bit value from the file.
77 /*!
78 @return Read 16 bit value.
79 @pre There should be at least 2 bytes available for reading.
80 */
read_uint16()81 uint16_t read_uint16() {
82 uint16_t iVal = read_uint8();
83 uint16_t iVal2 = read_uint8();
84 return static_cast<uint16_t>(iVal | (iVal2 << 8));
85 }
86
87 //! Get a signed 16 bit value from the file.
88 /*!
89 @return The read signed 16 bit value.
90 @pre There should be at least 2 bytes available for reading.
91 */
read_int16()92 int read_int16() {
93 int val = read_uint16();
94 if (val < 0x7FFF) return val;
95
96 int ret = -1;
97 return (ret & ~0xFFFF) | val;
98 }
99
100 //! Get a 32 bit value from the file.
101 /*!
102 @return Read 32 bit value.
103 @pre There should be at least 4 bytes available for reading.
104 */
read_uint32()105 uint32_t read_uint32() {
106 uint32_t iVal = read_uint16();
107 uint32_t iVal2 = read_uint16();
108 return iVal | (iVal2 << 16);
109 }
110
111 //! Load string from the memory_reader.
112 /*!
113 @param [out] pStr String to load.
114 @return Whether the string could be loaded.
115 */
read_string(std::string * pStr)116 bool read_string(std::string* pStr) {
117 char buff[256];
118
119 if (is_at_end_of_file()) {
120 return false;
121 }
122
123 size_t iLength = read_uint8();
124 if (!are_bytes_available(iLength)) {
125 return false;
126 }
127
128 size_t idx;
129 for (idx = 0; idx < iLength; idx++) {
130 buff[idx] = read_uint8();
131 }
132 buff[idx] = '\0';
133 *pStr = std::string(buff);
134
135 return true;
136 }
137 };
138
animation_manager()139 animation_manager::animation_manager() {
140 first_frames.clear();
141 frames.clear();
142 element_list.clear();
143 elements.clear();
144 custom_sheets.clear();
145
146 sheet = nullptr;
147
148 animation_count = 0;
149 frame_count = 0;
150 element_list_count = 0;
151 element_count = 0;
152 }
153
~animation_manager()154 animation_manager::~animation_manager() {
155 for (size_t i = 0; i < custom_sheets.size(); i++) {
156 delete custom_sheets[i];
157 }
158 }
159
set_sprite_sheet(sprite_sheet * pSpriteSheet)160 void animation_manager::set_sprite_sheet(sprite_sheet* pSpriteSheet) {
161 sheet = pSpriteSheet;
162 }
163
load_from_th_file(const uint8_t * pStartData,size_t iStartDataLength,const uint8_t * pFrameData,size_t iFrameDataLength,const uint8_t * pListData,size_t iListDataLength,const uint8_t * pElementData,size_t iElementDataLength)164 bool animation_manager::load_from_th_file(
165 const uint8_t* pStartData, size_t iStartDataLength,
166 const uint8_t* pFrameData, size_t iFrameDataLength,
167 const uint8_t* pListData, size_t iListDataLength,
168 const uint8_t* pElementData, size_t iElementDataLength) {
169 size_t iAnimationCount = iStartDataLength / sizeof(th_animation_properties);
170 size_t iFrameCount = iFrameDataLength / sizeof(th_frame_properties);
171 size_t iListCount = iListDataLength / 2;
172 size_t iElementCount = iElementDataLength / sizeof(th_element_properties);
173
174 if (iAnimationCount == 0 || iFrameCount == 0 || iListCount == 0 ||
175 iElementCount == 0) {
176 return false;
177 }
178
179 // Start offset of the file data into the vectors.
180 size_t iAnimationStart = animation_count;
181 size_t iFrameStart = frame_count;
182 size_t iListStart = element_list_count;
183 size_t iElementStart = element_count;
184
185 // Original data file must start at offset 0 due to the hard-coded animation
186 // numbers in the Lua code.
187 if (iAnimationStart > 0 || iFrameStart > 0 || iListStart > 0 ||
188 iElementStart > 0) {
189 return false;
190 }
191
192 // Overflow of list elements.
193 if (iElementStart + iElementCount >= 0xFFFF) {
194 return false;
195 }
196
197 // Create new space for the data.
198 first_frames.reserve(iAnimationStart + iAnimationCount);
199 frames.reserve(iFrameStart + iFrameCount);
200 element_list.reserve(iListStart + iListCount + 1);
201 elements.reserve(iElementStart + iElementCount);
202
203 // Read animations.
204 for (size_t i = 0; i < iAnimationCount; ++i) {
205 size_t iFirstFrame =
206 reinterpret_cast<const th_animation_properties*>(pStartData)[i]
207 .first_frame;
208 if (iFirstFrame > iFrameCount) {
209 iFirstFrame = 0;
210 }
211
212 iFirstFrame += iFrameStart;
213 first_frames.push_back(iFirstFrame);
214 }
215
216 // Read frames.
217 for (size_t i = 0; i < iFrameCount; ++i) {
218 const th_frame_properties* pFrame =
219 reinterpret_cast<const th_frame_properties*>(pFrameData) + i;
220
221 frame oFrame;
222 oFrame.list_index =
223 iListStart + (pFrame->list_index < iListCount ? pFrame->list_index : 0);
224 oFrame.next_frame =
225 iFrameStart + (pFrame->next < iFrameCount ? pFrame->next : 0);
226 oFrame.sound = pFrame->sound;
227 oFrame.flags = pFrame->flags;
228 // Bounding box fields initialised later
229 oFrame.marker_x = 0;
230 oFrame.marker_y = 0;
231 oFrame.secondary_marker_x = 0;
232 oFrame.secondary_marker_y = 0;
233
234 frames.push_back(oFrame);
235 }
236
237 // Read element list.
238 for (size_t i = 0; i < iListCount; ++i) {
239 uint16_t iElmNumber = *(reinterpret_cast<const uint16_t*>(pListData) + i);
240 if (iElmNumber >= iElementCount) {
241 iElmNumber = 0xFFFF;
242 } else {
243 iElmNumber = static_cast<uint16_t>(iElmNumber + iElementStart);
244 }
245
246 element_list.push_back(iElmNumber);
247 }
248 element_list.push_back(0xFFFF);
249
250 // Read elements.
251 size_t iSpriteCount = sheet->get_sprite_count();
252 for (size_t i = 0; i < iElementCount; ++i) {
253 const th_element_properties* pTHElement =
254 reinterpret_cast<const th_element_properties*>(pElementData) + i;
255
256 element oElement;
257 oElement.sprite = pTHElement->table_position / 6;
258 oElement.flags = pTHElement->flags & 0xF;
259 oElement.x = static_cast<int>(pTHElement->offx) - 141;
260 oElement.y = static_cast<int>(pTHElement->offy) - 186;
261 oElement.layer = static_cast<uint8_t>(
262 pTHElement->flags >> 4); // High nibble, layer of the element.
263 if (oElement.layer > 12) {
264 // Nothing lives on layer 6
265 oElement.layer = 6;
266 }
267 oElement.layer_id = pTHElement->layerid;
268 if (oElement.sprite < iSpriteCount) {
269 oElement.element_sprite_sheet = sheet;
270 } else {
271 oElement.element_sprite_sheet = nullptr;
272 }
273
274 elements.push_back(oElement);
275 }
276
277 // Compute bounding box of the animations using the sprite sheet.
278 for (size_t i = 0; i < iFrameCount; ++i) {
279 set_bounding_box(frames[iFrameStart + i]);
280 }
281
282 animation_count += iAnimationCount;
283 frame_count += iFrameCount;
284 element_list_count += iListCount + 1;
285 element_count += iElementCount;
286
287 assert(first_frames.size() == animation_count);
288 assert(frames.size() == frame_count);
289 assert(element_list.size() == element_list_count);
290 assert(elements.size() == element_count);
291
292 return true;
293 }
294
295 namespace {
296
297 //! Update \a iLeft with the smallest of both values.
298 /*!
299 @param [inout] iLeft Left value to check and update.
300 @param iRight Second value to check.
301 */
set_left_to_min(int & iLeft,int iRight)302 void set_left_to_min(int& iLeft, int iRight) {
303 if (iRight < iLeft) iLeft = iRight;
304 }
305
306 //! Update \a iLeft with the biggest of both values.
307 /*!
308 @param [inout] iLeft Left value to check and update.
309 @param iRight Second value to check.
310 */
set_left_to_max(int & iLeft,int iRight)311 void set_left_to_max(int& iLeft, int iRight) {
312 if (iRight > iLeft) iLeft = iRight;
313 }
314
315 } // namespace
316
set_bounding_box(frame & oFrame)317 void animation_manager::set_bounding_box(frame& oFrame) {
318 oFrame.bounding_left = INT_MAX;
319 oFrame.bounding_right = INT_MIN;
320 oFrame.bounding_top = INT_MAX;
321 oFrame.bounding_bottom = INT_MIN;
322
323 size_t iListIndex = oFrame.list_index;
324 for (;; ++iListIndex) {
325 uint16_t iElement = element_list[iListIndex];
326 if (iElement >= elements.size()) {
327 break;
328 }
329
330 element& oElement = elements[iElement];
331 if (oElement.element_sprite_sheet == nullptr) {
332 continue;
333 }
334
335 int iWidth;
336 int iHeight;
337 oElement.element_sprite_sheet->get_sprite_size_unchecked(oElement.sprite,
338 &iWidth, &iHeight);
339 set_left_to_min(oFrame.bounding_left, oElement.x);
340 set_left_to_min(oFrame.bounding_top, oElement.y);
341 set_left_to_max(oFrame.bounding_right, oElement.x - 1 + (int)iWidth);
342 set_left_to_max(oFrame.bounding_bottom, oElement.y - 1 + (int)iHeight);
343 }
344 }
345
set_canvas(render_target * pCanvas)346 void animation_manager::set_canvas(render_target* pCanvas) { canvas = pCanvas; }
347
348 namespace {
349
350 //! Load the header.
351 /*!
352 @param [inout] input Data to read.
353 @return Number of consumed bytes, a negative number indicates an error.
354 */
load_header(memory_reader & input)355 int load_header(memory_reader& input) {
356 static const uint8_t aHdr[] = {'C', 'T', 'H', 'G', 1, 2};
357
358 if (!input.are_bytes_available(6)) {
359 return false;
360 }
361
362 for (int i = 0; i < 6; i++) {
363 if (input.read_uint8() != aHdr[i]) {
364 return false;
365 }
366 }
367 return true;
368 }
369
370 } // namespace
371
load_elements(memory_reader & input,sprite_sheet * pSpriteSheet,size_t iNumElements,size_t & iLoadedElements,size_t iElementStart,size_t iElementCount)372 size_t animation_manager::load_elements(
373 memory_reader& input, sprite_sheet* pSpriteSheet, size_t iNumElements,
374 size_t& iLoadedElements, size_t iElementStart, size_t iElementCount) {
375 size_t iFirst = iLoadedElements + iElementStart;
376
377 size_t iSpriteCount = pSpriteSheet->get_sprite_count();
378 while (iNumElements > 0) {
379 if (iLoadedElements >= iElementCount || !input.are_bytes_available(12)) {
380 return SIZE_MAX;
381 }
382
383 size_t iSprite = input.read_uint32();
384 int iX = input.read_int16();
385 int iY = input.read_int16();
386 uint8_t iLayerClass = input.read_uint8();
387 uint8_t iLayerId = input.read_uint8();
388 uint32_t iFlags = input.read_uint16();
389
390 if (iLayerClass > 12) {
391 // Nothing lives on layer 6
392 iLayerClass = 6;
393 }
394
395 element oElement;
396 oElement.sprite = iSprite;
397 oElement.flags = iFlags;
398 oElement.x = iX;
399 oElement.y = iY;
400 oElement.layer = iLayerClass;
401 oElement.layer_id = iLayerId;
402 if (oElement.sprite >= iSpriteCount)
403 oElement.element_sprite_sheet = nullptr;
404 else
405 oElement.element_sprite_sheet = pSpriteSheet;
406
407 elements.push_back(oElement);
408 iLoadedElements++;
409 iNumElements--;
410 }
411 return iFirst;
412 }
413
make_list_elements(size_t iFirstElement,size_t iNumElements,size_t & iLoadedListElements,size_t iListStart,size_t iListCount)414 size_t animation_manager::make_list_elements(size_t iFirstElement,
415 size_t iNumElements,
416 size_t& iLoadedListElements,
417 size_t iListStart,
418 size_t iListCount) {
419 size_t iFirst = iLoadedListElements + iListStart;
420
421 // Verify there is enough room for all list elements + 0xFFFF
422 if (iLoadedListElements + iNumElements + 1 > iListCount) {
423 return SIZE_MAX;
424 }
425
426 // Overflow for list elements.
427 assert(iFirstElement + iNumElements < 0xFFFF);
428
429 while (iNumElements > 0) {
430 element_list.push_back(static_cast<uint16_t>(iFirstElement));
431 iLoadedListElements++;
432 iFirstElement++;
433 iNumElements--;
434 }
435 // Add 0xFFFF.
436 element_list.push_back(0xFFFF);
437 iLoadedListElements++;
438
439 return iFirst;
440 }
441
442 namespace {
443
444 //! Shift the first frame if all frames are available.
445 /*!
446 @param iFirst First frame number, or 0xFFFFFFFFu if no animation.
447 @param iLength Number of frames in the animation.
448 @param iStart Start of the frames for this file.
449 @param iLoaded Number of loaded frames.
450 @return The shifted first frame, or 0xFFFFFFFFu.
451 */
shift_first(uint32_t iFirst,size_t iLength,size_t iStart,size_t iLoaded)452 uint32_t shift_first(uint32_t iFirst, size_t iLength, size_t iStart,
453 size_t iLoaded) {
454 if (iFirst == 0xFFFFFFFFu || iFirst + iLength > iLoaded) {
455 return 0xFFFFFFFFu;
456 }
457 return iFirst + static_cast<uint32_t>(iStart);
458 }
459
460 } // namespace
461
fix_next_frame(uint32_t iFirst,size_t iLength)462 void animation_manager::fix_next_frame(uint32_t iFirst, size_t iLength) {
463 if (iFirst == 0xFFFFFFFFu) {
464 return;
465 }
466
467 frame& oFirst = frames[iFirst];
468 oFirst.flags |= 0x1; // Start of animation flag.
469
470 frame& oLast = frames[iFirst + iLength - 1];
471 oLast.next_frame = iFirst; // Loop last frame back to the first.
472 }
473
load_custom_animations(const uint8_t * pData,size_t iDataLength)474 bool animation_manager::load_custom_animations(const uint8_t* pData,
475 size_t iDataLength) {
476 memory_reader input(pData, iDataLength);
477
478 if (!load_header(input)) {
479 return false;
480 }
481
482 if (!input.are_bytes_available(5 * 4)) {
483 return false;
484 }
485
486 size_t iAnimationCount = input.read_uint32();
487 size_t iFrameCount = input.read_uint32();
488 size_t iElementCount = input.read_uint32();
489 size_t iSpriteCount = input.read_uint32();
490 input.read_uint32(); // Total number of bytes sprite data is not used.
491
492 // Every element is referenced once, and one 0xFFFF for every frame.
493 size_t iListCount = iElementCount + iFrameCount;
494
495 size_t iFrameStart = frame_count;
496 size_t iListStart = element_list_count;
497 size_t iElementStart = element_count;
498
499 if (iAnimationCount == 0 || iFrameCount == 0 || iElementCount == 0 ||
500 iSpriteCount == 0) {
501 return false;
502 }
503
504 // Overflow of list elements.
505 if (iElementStart + iElementCount >= 0xFFFF) {
506 return false;
507 }
508
509 // Create new space for the elements.
510 // Be optimistic in reservation.
511 first_frames.reserve(first_frames.size() + iAnimationCount * 4);
512 frames.reserve(iFrameStart + iFrameCount);
513 element_list.reserve(iListStart + iListCount);
514 elements.reserve(iElementStart + iElementCount);
515
516 // Construct a sprite sheet for the sprites to be loaded.
517 sprite_sheet* pSheet = new sprite_sheet;
518 pSheet->set_sprite_count(iSpriteCount, canvas);
519 custom_sheets.push_back(pSheet);
520
521 size_t iLoadedFrames = 0;
522 size_t iLoadedListElements = 0;
523 size_t iLoadedElements = 0;
524 size_t iLoadedSprites = 0;
525
526 // Read the blocks of the file, until hitting EOF.
527 for (;;) {
528 if (input.is_at_end_of_file()) break;
529
530 // Read identification bytes at the start of each block, and dispatch
531 // loading.
532 if (!input.are_bytes_available(2)) return false;
533 int first = input.read_uint8();
534 int second = input.read_uint8();
535
536 // Recognized a grouped animation block, load it.
537 if (first == 'C' && second == 'A') {
538 animation_key oKey;
539
540 if (!input.are_bytes_available(2 + 4)) {
541 return false;
542 }
543
544 oKey.tile_size = input.read_uint16();
545 size_t iNumFrames = input.read_uint32();
546 if (iNumFrames == 0) {
547 return false;
548 }
549
550 if (!input.read_string(&oKey.name)) {
551 return false;
552 }
553
554 if (!input.are_bytes_available(4 * 4)) {
555 return false;
556 }
557
558 uint32_t iNorthFirst = input.read_uint32();
559 uint32_t iEastFirst = input.read_uint32();
560 uint32_t iSouthFirst = input.read_uint32();
561 uint32_t iWestFirst = input.read_uint32();
562
563 iNorthFirst =
564 shift_first(iNorthFirst, iNumFrames, iFrameStart, iLoadedFrames);
565 iEastFirst =
566 shift_first(iEastFirst, iNumFrames, iFrameStart, iLoadedFrames);
567 iSouthFirst =
568 shift_first(iSouthFirst, iNumFrames, iFrameStart, iLoadedFrames);
569 iWestFirst =
570 shift_first(iWestFirst, iNumFrames, iFrameStart, iLoadedFrames);
571
572 animation_start_frames oFrames;
573 oFrames.north = -1;
574 oFrames.east = -1;
575 oFrames.south = -1;
576 oFrames.west = -1;
577
578 if (iNorthFirst != 0xFFFFFFFFu) {
579 fix_next_frame(iNorthFirst, iNumFrames);
580 oFrames.north = static_cast<long>(first_frames.size());
581 first_frames.push_back(iNorthFirst);
582 }
583 if (iEastFirst != 0xFFFFFFFFu) {
584 fix_next_frame(iEastFirst, iNumFrames);
585 oFrames.east = static_cast<long>(first_frames.size());
586 first_frames.push_back(iEastFirst);
587 }
588 if (iSouthFirst != 0xFFFFFFFFu) {
589 fix_next_frame(iSouthFirst, iNumFrames);
590 oFrames.south = static_cast<long>(first_frames.size());
591 first_frames.push_back(iSouthFirst);
592 }
593 if (iWestFirst != 0xFFFFFFFFu) {
594 fix_next_frame(iWestFirst, iNumFrames);
595 oFrames.west = static_cast<long>(first_frames.size());
596 first_frames.push_back(iWestFirst);
597 }
598
599 named_animation_pair p(oKey, oFrames);
600 named_animations.insert(p);
601 continue;
602 } else if (first == 'F' && second == 'R') {
603 // Recognized a frame block, load it.
604
605 if (iLoadedFrames >= iFrameCount) {
606 return false;
607 }
608
609 if (!input.are_bytes_available(2 + 2)) {
610 return false;
611 }
612
613 int iSound = input.read_uint16();
614 size_t iNumElements = input.read_uint16();
615
616 size_t iElm = load_elements(input, pSheet, iNumElements, iLoadedElements,
617 iElementStart, iElementCount);
618 if (iElm == SIZE_MAX) {
619 return false;
620 }
621
622 size_t iListElm = make_list_elements(
623 iElm, iNumElements, iLoadedListElements, iListStart, iListCount);
624 if (iListElm == SIZE_MAX) {
625 return false;
626 }
627
628 frame oFrame;
629 oFrame.list_index = iListElm;
630
631 // Point to next frame.
632 // Last frame of each animation corrected later.
633 oFrame.next_frame = iFrameStart + iLoadedFrames + 1;
634
635 oFrame.sound = iSound;
636
637 // Set later
638 oFrame.flags = 0;
639 oFrame.marker_x = 0;
640 oFrame.marker_y = 0;
641 oFrame.secondary_marker_x = 0;
642 oFrame.secondary_marker_y = 0;
643
644 set_bounding_box(oFrame);
645
646 frames.push_back(oFrame);
647 iLoadedFrames++;
648 continue;
649 } else if (first == 'S' && second == 'P') {
650 // Recognized a Sprite block, load it.
651
652 if (iLoadedSprites >= iSpriteCount) {
653 return false;
654 }
655
656 if (!input.are_bytes_available(2 + 2 + 4)) {
657 return false;
658 }
659
660 int iWidth = input.read_uint16();
661 int iHeight = input.read_uint16();
662 uint32_t iSize = input.read_uint32();
663
664 // Check it is safe to use as 'int'
665 if (iSize > INT_MAX) {
666 return false;
667 }
668
669 // Load data.
670 uint8_t* pData = new (std::nothrow) uint8_t[iSize];
671 if (pData == nullptr) {
672 return false;
673 }
674
675 if (!input.are_bytes_available(iSize)) {
676 delete[] pData;
677 return false;
678 }
679
680 for (uint32_t i = 0; i < iSize; i++) {
681 pData[i] = input.read_uint8();
682 }
683
684 if (!pSheet->set_sprite_data(iLoadedSprites, pData, true, iSize, iWidth,
685 iHeight)) {
686 return false;
687 }
688
689 iLoadedSprites++;
690 continue;
691 } else {
692 // Unrecognized block, fail.
693 return false;
694 }
695 }
696
697 assert(iLoadedFrames == iFrameCount);
698 assert(iLoadedListElements == iListCount);
699 assert(iLoadedElements == iElementCount);
700 assert(iLoadedSprites == iSpriteCount);
701
702 // Fix the next pointer of the last frame in case it points to non-existing
703 // frames.
704 frame& oFrame = frames[iFrameStart + iFrameCount - 1];
705 if (iFrameCount > 0 && oFrame.next_frame >= iFrameStart + iFrameCount) {
706 // Useless, but maybe less crashy.
707 oFrame.next_frame = iFrameStart;
708 }
709
710 animation_count = first_frames.size();
711 frame_count += iFrameCount;
712 element_list_count += iListCount;
713 element_count += iElementCount;
714 assert(frames.size() == frame_count);
715 assert(element_list.size() == element_list_count);
716 assert(elements.size() == element_count);
717
718 return true;
719 }
720
get_named_animations(const std::string & sName,int iTilesize) const721 const animation_start_frames& animation_manager::get_named_animations(
722 const std::string& sName, int iTilesize) const {
723 static const animation_start_frames oNoneAnimations = {-1, -1, -1, -1};
724
725 animation_key oKey;
726 oKey.name = sName;
727 oKey.tile_size = iTilesize;
728
729 named_animations_map::const_iterator iter = named_animations.find(oKey);
730 if (iter == named_animations.end()) {
731 return oNoneAnimations;
732 }
733 return (*iter).second;
734 }
735
get_animation_count() const736 size_t animation_manager::get_animation_count() const {
737 return animation_count;
738 }
739
get_frame_count() const740 size_t animation_manager::get_frame_count() const { return frame_count; }
741
get_first_frame(size_t iAnimation) const742 size_t animation_manager::get_first_frame(size_t iAnimation) const {
743 if (iAnimation < animation_count) {
744 return first_frames[iAnimation];
745 } else {
746 return 0;
747 }
748 }
749
get_next_frame(size_t iFrame) const750 size_t animation_manager::get_next_frame(size_t iFrame) const {
751 if (iFrame < frame_count) {
752 return frames[iFrame].next_frame;
753 } else {
754 return iFrame;
755 }
756 }
757
set_animation_alt_palette_map(size_t iAnimation,const uint8_t * pMap,uint32_t iAlt32)758 void animation_manager::set_animation_alt_palette_map(size_t iAnimation,
759 const uint8_t* pMap,
760 uint32_t iAlt32) {
761 if (iAnimation >= animation_count) {
762 return;
763 }
764
765 size_t iFrame = first_frames[iAnimation];
766 size_t iFirstFrame = iFrame;
767 do {
768 size_t iListIndex = frames[iFrame].list_index;
769 for (;; ++iListIndex) {
770 uint16_t iElement = element_list[iListIndex];
771 if (iElement >= element_count) {
772 break;
773 }
774
775 element& oElement = elements[iElement];
776 if (oElement.element_sprite_sheet != nullptr) {
777 oElement.element_sprite_sheet->set_sprite_alt_palette_map(
778 oElement.sprite, pMap, iAlt32);
779 }
780 }
781 iFrame = frames[iFrame].next_frame;
782 } while (iFrame != iFirstFrame);
783 }
784
set_frame_marker(size_t iFrame,int iX,int iY)785 bool animation_manager::set_frame_marker(size_t iFrame, int iX, int iY) {
786 if (iFrame >= frame_count) {
787 return false;
788 }
789
790 frames[iFrame].marker_x = iX;
791 frames[iFrame].marker_y = iY;
792 return true;
793 }
794
set_frame_secondary_marker(size_t iFrame,int iX,int iY)795 bool animation_manager::set_frame_secondary_marker(size_t iFrame, int iX,
796 int iY) {
797 if (iFrame >= frame_count) {
798 return false;
799 }
800
801 frames[iFrame].secondary_marker_x = iX;
802 frames[iFrame].secondary_marker_y = iY;
803 return true;
804 }
805
get_frame_marker(size_t iFrame,int * pX,int * pY)806 bool animation_manager::get_frame_marker(size_t iFrame, int* pX, int* pY) {
807 if (iFrame >= frame_count) {
808 return false;
809 }
810
811 *pX = frames[iFrame].marker_x;
812 *pY = frames[iFrame].marker_y;
813 return true;
814 }
815
get_frame_secondary_marker(size_t iFrame,int * pX,int * pY)816 bool animation_manager::get_frame_secondary_marker(size_t iFrame, int* pX,
817 int* pY) {
818 if (iFrame >= frame_count) {
819 return false;
820 }
821
822 *pX = frames[iFrame].secondary_marker_x;
823 *pY = frames[iFrame].secondary_marker_y;
824 return true;
825 }
826
hit_test(size_t iFrame,const::layers & oLayers,int iX,int iY,uint32_t iFlags,int iTestX,int iTestY) const827 bool animation_manager::hit_test(size_t iFrame, const ::layers& oLayers, int iX,
828 int iY, uint32_t iFlags, int iTestX,
829 int iTestY) const {
830 if (iFrame >= frame_count) {
831 return false;
832 }
833
834 const frame& oFrame = frames[iFrame];
835 iTestX -= iX;
836 iTestY -= iY;
837
838 if (iFlags & thdf_flip_horizontal) {
839 iTestX = -iTestX;
840 }
841
842 if (iTestX < oFrame.bounding_left || iTestX > oFrame.bounding_right) {
843 return false;
844 }
845
846 if (iFlags & thdf_flip_vertical) {
847 if (-iTestY < oFrame.bounding_top || -iTestY > oFrame.bounding_bottom) {
848 return false;
849 }
850 } else {
851 if (iTestY < oFrame.bounding_top || iTestY > oFrame.bounding_bottom) {
852 return false;
853 }
854 }
855
856 if (iFlags & thdf_bound_box_hit_test) {
857 return true;
858 }
859
860 size_t iListIndex = oFrame.list_index;
861 for (;; ++iListIndex) {
862 uint16_t iElement = element_list[iListIndex];
863 if (iElement >= element_count) {
864 break;
865 }
866
867 const element& oElement = elements[iElement];
868 if ((oElement.layer_id != 0 &&
869 oLayers.layer_contents[oElement.layer] != oElement.layer_id) ||
870 oElement.element_sprite_sheet == nullptr) {
871 continue;
872 }
873
874 if (iFlags & thdf_flip_horizontal) {
875 int iWidth;
876 int iHeight;
877 oElement.element_sprite_sheet->get_sprite_size_unchecked(
878 oElement.sprite, &iWidth, &iHeight);
879 if (oElement.element_sprite_sheet->hit_test_sprite(
880 oElement.sprite, oElement.x + iWidth - iTestX,
881 iTestY - oElement.y, oElement.flags ^ thdf_flip_horizontal)) {
882 return true;
883 }
884 } else {
885 if (oElement.element_sprite_sheet->hit_test_sprite(
886 oElement.sprite, iTestX - oElement.x, iTestY - oElement.y,
887 oElement.flags)) {
888 return true;
889 }
890 }
891 }
892
893 return false;
894 }
895
draw_frame(render_target * pCanvas,size_t iFrame,const::layers & oLayers,int iX,int iY,uint32_t iFlags) const896 void animation_manager::draw_frame(render_target* pCanvas, size_t iFrame,
897 const ::layers& oLayers, int iX, int iY,
898 uint32_t iFlags) const {
899 if (iFrame >= frame_count) {
900 return;
901 }
902
903 uint32_t iPassOnFlags = iFlags & thdf_alt_palette;
904
905 size_t iListIndex = frames[iFrame].list_index;
906 for (;; ++iListIndex) {
907 uint16_t iElement = element_list[iListIndex];
908 if (iElement >= element_count) {
909 break;
910 }
911
912 const element& oElement = elements[iElement];
913 if (oElement.element_sprite_sheet == nullptr) {
914 continue;
915 }
916
917 if (oElement.layer_id != 0 &&
918 oLayers.layer_contents[oElement.layer] != oElement.layer_id) {
919 // Some animations involving doctors (i.e. #72, #74, maybe others)
920 // only provide versions for heads W1 and B1, not W2 and B2. The
921 // quickest way to fix this is this dirty hack here, which draws
922 // the W1 layer as well as W2 if W2 is being used, and similarly
923 // for B1 / B2. A better fix would be to go into each animation
924 // which needs it, and duplicate the W1 / B1 layers to W2 / B2.
925 if (oElement.layer == 5 &&
926 oLayers.layer_contents[5] - 4 == oElement.layer_id) {
927 /* don't skip */;
928 } else {
929 continue;
930 }
931 }
932
933 if (iFlags & thdf_flip_horizontal) {
934 int iWidth;
935 int iHeight;
936 oElement.element_sprite_sheet->get_sprite_size_unchecked(
937 oElement.sprite, &iWidth, &iHeight);
938
939 oElement.element_sprite_sheet->draw_sprite(
940 pCanvas, oElement.sprite, iX - oElement.x - iWidth, iY + oElement.y,
941 iPassOnFlags | (oElement.flags ^ thdf_flip_horizontal));
942 } else {
943 oElement.element_sprite_sheet->draw_sprite(
944 pCanvas, oElement.sprite, iX + oElement.x, iY + oElement.y,
945 iPassOnFlags | oElement.flags);
946 }
947 }
948 }
949
get_frame_sound(size_t iFrame)950 size_t animation_manager::get_frame_sound(size_t iFrame) {
951 if (iFrame < frame_count) {
952 return frames[iFrame].sound;
953 } else {
954 return 0;
955 }
956 }
957
get_frame_extent(size_t iFrame,const::layers & oLayers,int * pMinX,int * pMaxX,int * pMinY,int * pMaxY,uint32_t iFlags) const958 void animation_manager::get_frame_extent(size_t iFrame, const ::layers& oLayers,
959 int* pMinX, int* pMaxX, int* pMinY,
960 int* pMaxY, uint32_t iFlags) const {
961 int iMinX = INT_MAX;
962 int iMaxX = INT_MIN;
963 int iMinY = INT_MAX;
964 int iMaxY = INT_MIN;
965 if (iFrame < frame_count) {
966 size_t iListIndex = frames[iFrame].list_index;
967
968 for (;; ++iListIndex) {
969 uint16_t iElement = element_list[iListIndex];
970 if (iElement >= element_count) {
971 break;
972 }
973
974 const element& oElement = elements[iElement];
975 if ((oElement.layer_id != 0 &&
976 oLayers.layer_contents[oElement.layer] != oElement.layer_id) ||
977 oElement.element_sprite_sheet == nullptr) {
978 continue;
979 }
980
981 int iX = oElement.x;
982 int iY = oElement.y;
983 int iWidth;
984 int iHeight;
985 oElement.element_sprite_sheet->get_sprite_size_unchecked(
986 oElement.sprite, &iWidth, &iHeight);
987 if (iFlags & thdf_flip_horizontal) iX = -(iX + iWidth);
988 if (iX < iMinX) iMinX = iX;
989 if (iY < iMinY) iMinY = iY;
990 if (iX + iWidth + 1 > iMaxX) iMaxX = iX + iWidth + 1;
991 if (iY + iHeight + 1 > iMaxY) iMaxY = iY + iHeight + 1;
992 }
993 }
994 if (pMinX) *pMinX = iMinX;
995 if (pMaxX) *pMaxX = iMaxX;
996 if (pMinY) *pMinY = iMinY;
997 if (pMaxY) *pMaxY = iMaxY;
998 }
999
chunk_renderer(int width,int height,uint8_t * buffer)1000 chunk_renderer::chunk_renderer(int width, int height, uint8_t* buffer) {
1001 data = buffer ? buffer : new uint8_t[width * height];
1002 ptr = data;
1003 end = data + width * height;
1004 x = 0;
1005 y = 0;
1006 this->width = width;
1007 this->height = height;
1008 skip_eol = false;
1009 }
1010
~chunk_renderer()1011 chunk_renderer::~chunk_renderer() { delete[] data; }
1012
take_data()1013 uint8_t* chunk_renderer::take_data() {
1014 uint8_t* buffer = data;
1015 data = nullptr;
1016 return buffer;
1017 }
1018
chunk_fill_to_end_of_line(uint8_t value)1019 void chunk_renderer::chunk_fill_to_end_of_line(uint8_t value) {
1020 if (x != 0 || !skip_eol) {
1021 chunk_fill(width - x, value);
1022 }
1023 skip_eol = false;
1024 }
1025
chunk_finish(uint8_t value)1026 void chunk_renderer::chunk_finish(uint8_t value) {
1027 chunk_fill(static_cast<int>(end - ptr), value);
1028 }
1029
chunk_fill(int npixels,uint8_t value)1030 void chunk_renderer::chunk_fill(int npixels, uint8_t value) {
1031 fix_n_pixels(npixels);
1032 if (npixels > 0) {
1033 std::memset(ptr, value, npixels);
1034 increment_position(npixels);
1035 }
1036 }
1037
chunk_copy(int npixels,const uint8_t * in_data)1038 void chunk_renderer::chunk_copy(int npixels, const uint8_t* in_data) {
1039 fix_n_pixels(npixels);
1040 if (npixels > 0) {
1041 std::memcpy(ptr, in_data, npixels);
1042 increment_position(npixels);
1043 }
1044 }
1045
fix_n_pixels(int & npixels) const1046 void chunk_renderer::fix_n_pixels(int& npixels) const {
1047 if (ptr + npixels > end) {
1048 npixels = static_cast<int>(end - ptr);
1049 }
1050 }
1051
increment_position(int npixels)1052 void chunk_renderer::increment_position(int npixels) {
1053 ptr += npixels;
1054 x += npixels;
1055 y += x / width;
1056 x = x % width;
1057 skip_eol = true;
1058 }
1059
decode_chunks(const uint8_t * data,int datalen,bool complex)1060 void chunk_renderer::decode_chunks(const uint8_t* data, int datalen,
1061 bool complex) {
1062 if (complex) {
1063 while (!is_done() && datalen > 0) {
1064 uint8_t b = *data;
1065 --datalen;
1066 ++data;
1067 if (b == 0) {
1068 chunk_fill_to_end_of_line(0xFF);
1069 } else if (b < 0x40) {
1070 int amt = b;
1071 if (datalen < amt) amt = datalen;
1072 chunk_copy(amt, data);
1073 data += amt;
1074 datalen -= amt;
1075 } else if ((b & 0xC0) == 0x80) {
1076 chunk_fill(b - 0x80, 0xFF);
1077 } else {
1078 int amt;
1079 uint8_t colour = 0;
1080 if (b == 0xFF) {
1081 if (datalen < 2) {
1082 break;
1083 }
1084 amt = (int)data[0];
1085 colour = data[1];
1086 data += 2;
1087 datalen -= 2;
1088 } else {
1089 amt = b - 60 - (b & 0x80) / 2;
1090 if (datalen > 0) {
1091 colour = *data;
1092 ++data;
1093 --datalen;
1094 }
1095 }
1096 chunk_fill(amt, colour);
1097 }
1098 }
1099 } else {
1100 while (!is_done() && datalen > 0) {
1101 uint8_t b = *data;
1102 --datalen;
1103 ++data;
1104 if (b == 0) {
1105 chunk_fill_to_end_of_line(0xFF);
1106 } else if (b < 0x80) {
1107 int amt = b;
1108 if (datalen < amt) amt = datalen;
1109 chunk_copy(amt, data);
1110 data += amt;
1111 datalen -= amt;
1112 } else {
1113 chunk_fill(0x100 - b, 0xFF);
1114 }
1115 }
1116 }
1117 chunk_finish(0xFF);
1118 }
1119
1120 namespace {
1121
are_flags_set(uint32_t val,uint32_t flags)1122 bool are_flags_set(uint32_t val, uint32_t flags) {
1123 return (val & flags) == flags;
1124 }
1125
1126 } // namespace
1127
draw(render_target * pCanvas,int iDestX,int iDestY)1128 void animation::draw(render_target* pCanvas, int iDestX, int iDestY) {
1129 if (are_flags_set(flags, thdf_alpha_50 | thdf_alpha_75)) return;
1130
1131 iDestX += x_relative_to_tile;
1132 iDestY += y_relative_to_tile;
1133 if (sound_to_play) {
1134 sound_player* pSounds = sound_player::get_singleton();
1135 if (pSounds) pSounds->play_at(sound_to_play, iDestX, iDestY);
1136 sound_to_play = 0;
1137 }
1138 if (manager) {
1139 if (flags & thdf_crop) {
1140 clip_rect rcOld, rcNew;
1141 pCanvas->get_clip_rect(&rcOld);
1142 rcNew.y = rcOld.y;
1143 rcNew.h = rcOld.h;
1144 rcNew.x = iDestX + (crop_column - 1) * 32;
1145 rcNew.w = 64;
1146 clip_rect_intersection(rcNew, rcOld);
1147 pCanvas->set_clip_rect(&rcNew);
1148 manager->draw_frame(pCanvas, frame_index, layers, iDestX, iDestY, flags);
1149 pCanvas->set_clip_rect(&rcOld);
1150 } else
1151 manager->draw_frame(pCanvas, frame_index, layers, iDestX, iDestY, flags);
1152 }
1153 }
1154
draw_child(render_target * pCanvas,int iDestX,int iDestY)1155 void animation::draw_child(render_target* pCanvas, int iDestX, int iDestY) {
1156 if (are_flags_set(flags, thdf_alpha_50 | thdf_alpha_75)) return;
1157 if (are_flags_set(parent->flags, thdf_alpha_50 | thdf_alpha_75)) return;
1158 int iX = 0, iY = 0;
1159 parent->get_marker(&iX, &iY);
1160 iX += x_relative_to_tile + iDestX;
1161 iY += y_relative_to_tile + iDestY;
1162 if (sound_to_play) {
1163 sound_player* pSounds = sound_player::get_singleton();
1164 if (pSounds) pSounds->play_at(sound_to_play, iX, iY);
1165 sound_to_play = 0;
1166 }
1167 if (manager) manager->draw_frame(pCanvas, frame_index, layers, iX, iY, flags);
1168 }
1169
hit_test_child(int iDestX,int iDestY,int iTestX,int iTestY)1170 bool animation::hit_test_child(int iDestX, int iDestY, int iTestX, int iTestY) {
1171 // TODO
1172 return false;
1173 }
1174
1175 namespace {
1176
CalculateMorphRect(const clip_rect & rcOriginal,clip_rect & rcMorph,int iYLow,int iYHigh)1177 void CalculateMorphRect(const clip_rect& rcOriginal, clip_rect& rcMorph,
1178 int iYLow, int iYHigh) {
1179 rcMorph = rcOriginal;
1180 if (rcMorph.y < iYLow) {
1181 rcMorph.h += rcMorph.y - iYLow;
1182 rcMorph.y = iYLow;
1183 }
1184 if (rcMorph.y + rcMorph.h >= iYHigh) {
1185 rcMorph.h = iYHigh - rcMorph.y - 1;
1186 }
1187 }
1188
1189 } // namespace
1190
draw_morph(render_target * pCanvas,int iDestX,int iDestY)1191 void animation::draw_morph(render_target* pCanvas, int iDestX, int iDestY) {
1192 if (are_flags_set(flags, thdf_alpha_50 | thdf_alpha_75)) return;
1193
1194 if (!manager) return;
1195
1196 iDestX += x_relative_to_tile;
1197 iDestY += y_relative_to_tile;
1198 if (sound_to_play) {
1199 sound_player* pSounds = sound_player::get_singleton();
1200 if (pSounds) pSounds->play_at(sound_to_play, iDestX, iDestY);
1201 sound_to_play = 0;
1202 }
1203
1204 clip_rect oClipRect;
1205 pCanvas->get_clip_rect(&oClipRect);
1206 clip_rect oMorphRect;
1207 CalculateMorphRect(oClipRect, oMorphRect,
1208 iDestY + morph_target->x_relative_to_tile,
1209 iDestY + morph_target->y_relative_to_tile + 1);
1210 pCanvas->set_clip_rect(&oMorphRect);
1211 manager->draw_frame(pCanvas, frame_index, layers, iDestX, iDestY, flags);
1212 CalculateMorphRect(oClipRect, oMorphRect,
1213 iDestY + morph_target->y_relative_to_tile,
1214 iDestY + morph_target->speed.dx);
1215 pCanvas->set_clip_rect(&oMorphRect);
1216 manager->draw_frame(pCanvas, morph_target->frame_index, morph_target->layers,
1217 iDestX, iDestY, morph_target->flags);
1218 pCanvas->set_clip_rect(&oClipRect);
1219 }
1220
hit_test(int iDestX,int iDestY,int iTestX,int iTestY)1221 bool animation::hit_test(int iDestX, int iDestY, int iTestX, int iTestY) {
1222 if (are_flags_set(flags, thdf_alpha_50 | thdf_alpha_75)) {
1223 return false;
1224 }
1225
1226 if (manager == nullptr) {
1227 return false;
1228 }
1229
1230 return manager->hit_test(frame_index, layers, x_relative_to_tile + iDestX,
1231 y_relative_to_tile + iDestY, flags, iTestX, iTestY);
1232 }
1233
hit_test_morph(int iDestX,int iDestY,int iTestX,int iTestY)1234 bool animation::hit_test_morph(int iDestX, int iDestY, int iTestX, int iTestY) {
1235 if (are_flags_set(flags, thdf_alpha_50 | thdf_alpha_75)) {
1236 return false;
1237 }
1238
1239 if (manager == nullptr) {
1240 return false;
1241 }
1242
1243 return manager->hit_test(frame_index, layers, x_relative_to_tile + iDestX,
1244 y_relative_to_tile + iDestY, flags, iTestX,
1245 iTestY) ||
1246 morph_target->hit_test(iDestX, iDestY, iTestX, iTestY);
1247 }
1248
1249 namespace {
THAnimation_hit_test_child(drawable * pSelf,int iDestX,int iDestY,int iTestX,int iTestY)1250 bool THAnimation_hit_test_child(drawable* pSelf, int iDestX, int iDestY,
1251 int iTestX, int iTestY) {
1252 return reinterpret_cast<animation*>(pSelf)->hit_test_child(iDestX, iDestY,
1253 iTestX, iTestY);
1254 }
1255
THAnimation_draw_child(drawable * pSelf,render_target * pCanvas,int iDestX,int iDestY)1256 void THAnimation_draw_child(drawable* pSelf, render_target* pCanvas, int iDestX,
1257 int iDestY) {
1258 reinterpret_cast<animation*>(pSelf)->draw_child(pCanvas, iDestX, iDestY);
1259 }
1260
THAnimation_hit_test_morph(drawable * pSelf,int iDestX,int iDestY,int iTestX,int iTestY)1261 bool THAnimation_hit_test_morph(drawable* pSelf, int iDestX, int iDestY,
1262 int iTestX, int iTestY) {
1263 return reinterpret_cast<animation*>(pSelf)->hit_test_morph(iDestX, iDestY,
1264 iTestX, iTestY);
1265 }
1266
THAnimation_draw_morph(drawable * pSelf,render_target * pCanvas,int iDestX,int iDestY)1267 void THAnimation_draw_morph(drawable* pSelf, render_target* pCanvas, int iDestX,
1268 int iDestY) {
1269 reinterpret_cast<animation*>(pSelf)->draw_morph(pCanvas, iDestX, iDestY);
1270 }
1271
THAnimation_hit_test(drawable * pSelf,int iDestX,int iDestY,int iTestX,int iTestY)1272 bool THAnimation_hit_test(drawable* pSelf, int iDestX, int iDestY, int iTestX,
1273 int iTestY) {
1274 return reinterpret_cast<animation*>(pSelf)->hit_test(iDestX, iDestY, iTestX,
1275 iTestY);
1276 }
1277
THAnimation_draw(drawable * pSelf,render_target * pCanvas,int iDestX,int iDestY)1278 void THAnimation_draw(drawable* pSelf, render_target* pCanvas, int iDestX,
1279 int iDestY) {
1280 reinterpret_cast<animation*>(pSelf)->draw(pCanvas, iDestX, iDestY);
1281 }
1282
THAnimation_is_multiple_frame_animation(drawable * pSelf)1283 bool THAnimation_is_multiple_frame_animation(drawable* pSelf) {
1284 animation* pAnimation = reinterpret_cast<animation*>(pSelf);
1285 if (pAnimation) {
1286 size_t firstFrame = pAnimation->get_animation_manager()->get_first_frame(
1287 pAnimation->get_animation());
1288 size_t nextFrame =
1289 pAnimation->get_animation_manager()->get_next_frame(firstFrame);
1290 return nextFrame != firstFrame;
1291 } else {
1292 return false;
1293 }
1294 }
1295
1296 } // namespace
1297
animation_base()1298 animation_base::animation_base() : drawable() {
1299 x_relative_to_tile = 0;
1300 y_relative_to_tile = 0;
1301 for (int i = 0; i < 13; ++i) {
1302 layers.layer_contents[i] = 0;
1303 }
1304 flags = 0;
1305 }
1306
animation()1307 animation::animation()
1308 : animation_base(),
1309 manager(nullptr),
1310 morph_target(nullptr),
1311 animation_index(0),
1312 frame_index(0),
1313 speed({0, 0}),
1314 sound_to_play(0),
1315 crop_column(0) {
1316 draw_fn = THAnimation_draw;
1317 hit_test_fn = THAnimation_hit_test;
1318 is_multiple_frame_animation_fn = THAnimation_is_multiple_frame_animation;
1319 }
1320
persist(lua_persist_writer * pWriter) const1321 void animation::persist(lua_persist_writer* pWriter) const {
1322 lua_State* L = pWriter->get_stack();
1323
1324 // Write the next chained thing
1325 lua_rawgeti(L, luaT_environindex, 2);
1326 lua_pushlightuserdata(L, next);
1327 lua_rawget(L, -2);
1328 pWriter->fast_write_stack_object(-1);
1329 lua_pop(L, 2);
1330
1331 // Write the drawable fields
1332 pWriter->write_uint(flags);
1333
1334 if (draw_fn == THAnimation_draw && hit_test_fn == THAnimation_hit_test) {
1335 pWriter->write_uint(1);
1336 } else if (draw_fn == THAnimation_draw_child &&
1337 hit_test_fn == THAnimation_hit_test_child) {
1338 pWriter->write_uint(2);
1339 } else if (draw_fn == THAnimation_draw_morph &&
1340 hit_test_fn == THAnimation_hit_test_morph) {
1341 // NB: Prior version of code used the number 3 here, and forgot
1342 // to persist the morph target.
1343 pWriter->write_uint(4);
1344 lua_rawgeti(L, luaT_environindex, 2);
1345 lua_pushlightuserdata(L, morph_target);
1346 lua_rawget(L, -2);
1347 pWriter->write_stack_object(-1);
1348 lua_pop(L, 2);
1349 } else {
1350 pWriter->write_uint(0);
1351 }
1352
1353 // Write the simple fields
1354 pWriter->write_uint(animation_index);
1355 pWriter->write_uint(frame_index);
1356 pWriter->write_int(x_relative_to_tile);
1357 pWriter->write_int(y_relative_to_tile);
1358
1359 // Not a uint, for compatibility
1360 pWriter->write_int((int)sound_to_play);
1361
1362 // For compatibility
1363 pWriter->write_int(0);
1364
1365 if (flags & thdf_crop) {
1366 pWriter->write_int(crop_column);
1367 }
1368
1369 // Write the unioned fields
1370 if (draw_fn != THAnimation_draw_child) {
1371 pWriter->write_int(speed.dx);
1372 pWriter->write_int(speed.dy);
1373 } else {
1374 lua_rawgeti(L, luaT_environindex, 2);
1375 lua_pushlightuserdata(L, parent);
1376 lua_rawget(L, -2);
1377 pWriter->write_stack_object(-1);
1378 lua_pop(L, 2);
1379 }
1380
1381 // Write the layers
1382 int iNumLayers = 13;
1383 for (; iNumLayers >= 1; --iNumLayers) {
1384 if (layers.layer_contents[iNumLayers - 1] != 0) break;
1385 }
1386 pWriter->write_uint(iNumLayers);
1387 pWriter->write_byte_stream(layers.layer_contents, iNumLayers);
1388 }
1389
depersist(lua_persist_reader * pReader)1390 void animation::depersist(lua_persist_reader* pReader) {
1391 lua_State* L = pReader->get_stack();
1392
1393 do {
1394 // Read the chain
1395 if (!pReader->read_stack_object()) break;
1396 next = reinterpret_cast<link_list*>(lua_touserdata(L, -1));
1397 if (next) next->prev = this;
1398 lua_pop(L, 1);
1399
1400 // Read drawable fields
1401 if (!pReader->read_uint(flags)) break;
1402 int iFunctionSet;
1403 if (!pReader->read_uint(iFunctionSet)) break;
1404 switch (iFunctionSet) {
1405 case 3:
1406 // 3 should be the morph set, but the actual morph target is
1407 // missing, so settle for a graphical bug rather than a segfault
1408 // by reverting to the normal function set.
1409 case 1:
1410 draw_fn = THAnimation_draw;
1411 hit_test_fn = THAnimation_hit_test;
1412 break;
1413 case 2:
1414 draw_fn = THAnimation_draw_child;
1415 hit_test_fn = THAnimation_hit_test_child;
1416 break;
1417 case 4:
1418 draw_fn = THAnimation_draw_morph;
1419 hit_test_fn = THAnimation_hit_test_morph;
1420 pReader->read_stack_object();
1421 morph_target = reinterpret_cast<animation*>(lua_touserdata(L, -1));
1422 lua_pop(L, 1);
1423 break;
1424 default:
1425 pReader->set_error(lua_pushfstring(
1426 L, "Unknown animation function set #%i", iFunctionSet));
1427 return;
1428 }
1429
1430 // Read the simple fields
1431 if (!pReader->read_uint(animation_index)) break;
1432 if (!pReader->read_uint(frame_index)) break;
1433 if (!pReader->read_int(x_relative_to_tile)) break;
1434 if (!pReader->read_int(y_relative_to_tile)) break;
1435 int iDummy;
1436 if (!pReader->read_int(iDummy)) break;
1437 if (iDummy >= 0) sound_to_play = (unsigned int)iDummy;
1438 if (!pReader->read_int(iDummy)) break;
1439 if (flags & thdf_crop) {
1440 if (!pReader->read_int(crop_column)) {
1441 break;
1442 }
1443 } else {
1444 crop_column = 0;
1445 }
1446
1447 // Read the unioned fields
1448 if (draw_fn != THAnimation_draw_child) {
1449 if (!pReader->read_int(speed.dx)) break;
1450 if (!pReader->read_int(speed.dy)) break;
1451 } else {
1452 if (!pReader->read_stack_object()) break;
1453 parent = static_cast<animation*>(lua_touserdata(L, -1));
1454 lua_pop(L, 1);
1455 }
1456
1457 // Read the layers
1458 std::memset(layers.layer_contents, 0, sizeof(layers.layer_contents));
1459 int iNumLayers;
1460 if (!pReader->read_uint(iNumLayers)) {
1461 break;
1462 }
1463
1464 if (iNumLayers > 13) {
1465 if (!pReader->read_byte_stream(layers.layer_contents, 13)) break;
1466 if (!pReader->read_byte_stream(nullptr, iNumLayers - 13)) break;
1467 } else {
1468 if (!pReader->read_byte_stream(layers.layer_contents, iNumLayers)) break;
1469 }
1470
1471 // Fix the m_pAnimator field
1472 luaT_getenvfield(L, 2, "animator");
1473 manager = static_cast<animation_manager*>(lua_touserdata(L, -1));
1474 lua_pop(L, 1);
1475
1476 return;
1477 } while (false);
1478
1479 pReader->set_error("Cannot depersist animation instance");
1480 }
1481
tick()1482 void animation::tick() {
1483 frame_index = manager->get_next_frame(frame_index);
1484 if (draw_fn != THAnimation_draw_child) {
1485 x_relative_to_tile += speed.dx;
1486 y_relative_to_tile += speed.dy;
1487 }
1488
1489 if (morph_target) {
1490 morph_target->y_relative_to_tile += morph_target->speed.dy;
1491 if (morph_target->y_relative_to_tile < morph_target->x_relative_to_tile) {
1492 morph_target->y_relative_to_tile = morph_target->x_relative_to_tile;
1493 }
1494 }
1495
1496 // Female flying to heaven sound fix:
1497 if (frame_index == 6987) {
1498 sound_to_play = 123;
1499 } else {
1500 sound_to_play = manager->get_frame_sound(frame_index);
1501 }
1502 }
1503
remove_from_tile()1504 void animation_base::remove_from_tile() { link_list::remove_from_list(); }
1505
attach_to_tile(map_tile * pMapNode,int layer)1506 void animation_base::attach_to_tile(map_tile* pMapNode, int layer) {
1507 remove_from_tile();
1508 link_list* pList;
1509 if (flags & thdf_early_list) {
1510 pList = &pMapNode->oEarlyEntities;
1511 } else {
1512 pList = &pMapNode->entities;
1513 }
1514
1515 this->set_drawing_layer(layer);
1516
1517 while (pList->next &&
1518 static_cast<drawable*>(pList->next)->get_drawing_layer() < layer) {
1519 pList = pList->next;
1520 }
1521
1522 prev = pList;
1523 if (pList->next != nullptr) {
1524 pList->next->prev = this;
1525 this->next = pList->next;
1526 } else {
1527 next = nullptr;
1528 }
1529 pList->next = this;
1530 }
1531
set_parent(animation * pParent)1532 void animation::set_parent(animation* pParent) {
1533 remove_from_tile();
1534 if (pParent == nullptr) {
1535 draw_fn = THAnimation_draw;
1536 hit_test_fn = THAnimation_hit_test;
1537 speed = {0, 0};
1538 } else {
1539 draw_fn = THAnimation_draw_child;
1540 hit_test_fn = THAnimation_hit_test_child;
1541 parent = pParent;
1542 next = parent->next;
1543 if (next) next->prev = this;
1544 prev = parent;
1545 parent->next = this;
1546 }
1547 }
1548
set_animation(animation_manager * pManager,size_t iAnimation)1549 void animation::set_animation(animation_manager* pManager, size_t iAnimation) {
1550 manager = pManager;
1551 animation_index = iAnimation;
1552 frame_index = pManager->get_first_frame(iAnimation);
1553 if (morph_target) {
1554 morph_target = nullptr;
1555 draw_fn = THAnimation_draw;
1556 hit_test_fn = THAnimation_hit_test;
1557 }
1558 }
1559
get_marker(int * pX,int * pY)1560 bool animation::get_marker(int* pX, int* pY) {
1561 if (!manager || !manager->get_frame_marker(frame_index, pX, pY)) {
1562 return false;
1563 }
1564
1565 if (flags & thdf_flip_horizontal) {
1566 *pX = -*pX;
1567 }
1568
1569 *pX += x_relative_to_tile;
1570 *pY += y_relative_to_tile + 16;
1571 return true;
1572 }
1573
get_secondary_marker(int * pX,int * pY)1574 bool animation::get_secondary_marker(int* pX, int* pY) {
1575 if (!manager || !manager->get_frame_secondary_marker(frame_index, pX, pY)) {
1576 return false;
1577 }
1578
1579 if (flags & thdf_flip_horizontal) {
1580 *pX = -*pX;
1581 }
1582
1583 *pX += x_relative_to_tile;
1584 *pY += y_relative_to_tile + 16;
1585 return true;
1586 }
1587
1588 namespace {
1589
GetAnimationDurationAndExtent(animation_manager * pManager,size_t iFrame,const::layers & oLayers,int * pMinY,int * pMaxY,uint32_t iFlags)1590 int GetAnimationDurationAndExtent(animation_manager* pManager, size_t iFrame,
1591 const ::layers& oLayers, int* pMinY,
1592 int* pMaxY, uint32_t iFlags) {
1593 int iMinY = INT_MAX;
1594 int iMaxY = INT_MIN;
1595 int iDuration = 0;
1596 size_t iCurFrame = iFrame;
1597 do {
1598 int iFrameMinY;
1599 int iFrameMaxY;
1600 pManager->get_frame_extent(iCurFrame, oLayers, nullptr, nullptr,
1601 &iFrameMinY, &iFrameMaxY, iFlags);
1602 if (iFrameMinY < iMinY) iMinY = iFrameMinY;
1603 if (iFrameMaxY > iMaxY) iMaxY = iFrameMaxY;
1604 iCurFrame = pManager->get_next_frame(iCurFrame);
1605 ++iDuration;
1606 } while (iCurFrame != iFrame);
1607 if (pMinY) {
1608 *pMinY = iMinY;
1609 }
1610 if (pMaxY) {
1611 *pMaxY = iMaxY;
1612 }
1613 return iDuration;
1614 }
1615
1616 } // namespace
1617
set_morph_target(animation * pMorphTarget,int iDurationFactor)1618 void animation::set_morph_target(animation* pMorphTarget, int iDurationFactor) {
1619 morph_target = pMorphTarget;
1620 draw_fn = THAnimation_draw_morph;
1621 hit_test_fn = THAnimation_hit_test_morph;
1622
1623 /* Morphing is the process by which two animations are combined to give a
1624 single animation of one animation turning into another. At the moment,
1625 morphing is done by having a y value, above which the original animation is
1626 rendered, and below which the new animation is rendered, and having the y
1627 value move upward a bit each frame.
1628 One example of where this is used is when transparent or invisible patients
1629 are cured at the pharmacy cabinet.
1630 The process of morphing requires four state variables, which are stored in
1631 the morph target animation:
1632 * The y value top limit - morph_target->x
1633 * The y value threshold - morph_target->y
1634 * The y value bottom limit - morph_target->speed.dx
1635 * The y value increment per frame - morph_target->speed.dy
1636 This obviously means that the morph target should not be ticked or rendered
1637 as it's position and speed contain other values.
1638 */
1639
1640 int iOrigMinY, iOrigMaxY;
1641 int iMorphMinY, iMorphMaxY;
1642
1643 int iOriginalDuration = GetAnimationDurationAndExtent(
1644 manager, frame_index, layers, &iOrigMinY, &iOrigMaxY, flags);
1645 int iMorphDuration = GetAnimationDurationAndExtent(
1646 morph_target->manager, morph_target->frame_index, morph_target->layers,
1647 &iMorphMinY, &iMorphMaxY, morph_target->flags);
1648 if (iMorphDuration > iOriginalDuration) {
1649 iMorphDuration = iOriginalDuration;
1650 }
1651
1652 iMorphDuration *= iDurationFactor;
1653 if (iOrigMinY < iMorphMinY) {
1654 morph_target->x_relative_to_tile = iOrigMinY;
1655 } else {
1656 morph_target->x_relative_to_tile = iMorphMinY;
1657 }
1658
1659 if (iOrigMaxY > iMorphMaxY) {
1660 morph_target->speed.dx = iOrigMaxY;
1661 } else {
1662 morph_target->speed.dx = iMorphMaxY;
1663 }
1664
1665 int iDist = morph_target->x_relative_to_tile - morph_target->speed.dx;
1666 morph_target->speed.dy = (iDist - iMorphDuration + 1) / iMorphDuration;
1667 morph_target->y_relative_to_tile = morph_target->speed.dx;
1668 }
1669
set_frame(size_t iFrame)1670 void animation::set_frame(size_t iFrame) { frame_index = iFrame; }
1671
set_layer(int iLayer,int iId)1672 void animation_base::set_layer(int iLayer, int iId) {
1673 if (0 <= iLayer && iLayer <= 12) {
1674 layers.layer_contents[iLayer] = static_cast<uint8_t>(iId);
1675 }
1676 }
1677
1678 namespace {
1679
THSpriteRenderList_hit_test(drawable * pSelf,int iDestX,int iDestY,int iTestX,int iTestY)1680 bool THSpriteRenderList_hit_test(drawable* pSelf, int iDestX, int iDestY,
1681 int iTestX, int iTestY) {
1682 return reinterpret_cast<sprite_render_list*>(pSelf)->hit_test(iDestX, iDestY,
1683 iTestX, iTestY);
1684 }
1685
THSpriteRenderList_draw(drawable * pSelf,render_target * pCanvas,int iDestX,int iDestY)1686 void THSpriteRenderList_draw(drawable* pSelf, render_target* pCanvas,
1687 int iDestX, int iDestY) {
1688 reinterpret_cast<sprite_render_list*>(pSelf)->draw(pCanvas, iDestX, iDestY);
1689 }
1690
THSpriteRenderList_is_multiple_frame_animation(drawable * pSelf)1691 bool THSpriteRenderList_is_multiple_frame_animation(drawable* pSelf) {
1692 return false;
1693 }
1694
1695 } // namespace
1696
sprite_render_list()1697 sprite_render_list::sprite_render_list() : animation_base() {
1698 draw_fn = THSpriteRenderList_draw;
1699 hit_test_fn = THSpriteRenderList_hit_test;
1700 is_multiple_frame_animation_fn =
1701 THSpriteRenderList_is_multiple_frame_animation;
1702 buffer_size = 0;
1703 sprite_count = 0;
1704 sheet = nullptr;
1705 sprites = nullptr;
1706 dx_per_tick = 0;
1707 dy_per_tick = 0;
1708 lifetime = -1;
1709 }
1710
~sprite_render_list()1711 sprite_render_list::~sprite_render_list() { delete[] sprites; }
1712
tick()1713 void sprite_render_list::tick() {
1714 x_relative_to_tile += dx_per_tick;
1715 y_relative_to_tile += dy_per_tick;
1716 if (lifetime > 0) {
1717 --lifetime;
1718 }
1719 }
1720
draw(render_target * pCanvas,int iDestX,int iDestY)1721 void sprite_render_list::draw(render_target* pCanvas, int iDestX, int iDestY) {
1722 if (!sheet) {
1723 return;
1724 }
1725
1726 iDestX += x_relative_to_tile;
1727 iDestY += y_relative_to_tile;
1728
1729 sprite* pLast = sprites + sprite_count;
1730 for (sprite* pSprite = sprites; pSprite != pLast; ++pSprite) {
1731 sheet->draw_sprite(pCanvas, pSprite->index, iDestX + pSprite->x,
1732 iDestY + pSprite->y, flags);
1733 }
1734 }
1735
hit_test(int iDestX,int iDestY,int iTestX,int iTestY)1736 bool sprite_render_list::hit_test(int iDestX, int iDestY, int iTestX,
1737 int iTestY) {
1738 // TODO
1739 return false;
1740 }
1741
set_lifetime(int iLifetime)1742 void sprite_render_list::set_lifetime(int iLifetime) {
1743 if (iLifetime < 0) {
1744 iLifetime = -1;
1745 }
1746 lifetime = iLifetime;
1747 }
1748
append_sprite(size_t iSprite,int iX,int iY)1749 void sprite_render_list::append_sprite(size_t iSprite, int iX, int iY) {
1750 if (buffer_size == sprite_count) {
1751 int iNewSize = buffer_size * 2;
1752 if (iNewSize == 0) {
1753 iNewSize = 4;
1754 }
1755 sprite* pNewSprites = new sprite[iNewSize];
1756 #ifdef _MSC_VER
1757 #pragma warning(disable : 4996)
1758 #endif
1759 std::copy(sprites, sprites + sprite_count, pNewSprites);
1760 #ifdef _MSC_VER
1761 #pragma warning(default : 4996)
1762 #endif
1763 delete[] sprites;
1764 sprites = pNewSprites;
1765 buffer_size = iNewSize;
1766 }
1767 sprites[sprite_count].index = iSprite;
1768 sprites[sprite_count].x = iX;
1769 sprites[sprite_count].y = iY;
1770 ++sprite_count;
1771 }
1772
persist(lua_persist_writer * pWriter) const1773 void sprite_render_list::persist(lua_persist_writer* pWriter) const {
1774 lua_State* L = pWriter->get_stack();
1775
1776 pWriter->write_uint(sprite_count);
1777 pWriter->write_uint(flags);
1778 pWriter->write_int(x_relative_to_tile);
1779 pWriter->write_int(y_relative_to_tile);
1780 pWriter->write_int(dx_per_tick);
1781 pWriter->write_int(dy_per_tick);
1782 pWriter->write_int(lifetime);
1783
1784 sprite* pLast = sprites + sprite_count;
1785 for (sprite* pSprite = sprites; pSprite != pLast; ++pSprite) {
1786 pWriter->write_uint(pSprite->index);
1787 pWriter->write_int(pSprite->x);
1788 pWriter->write_int(pSprite->y);
1789 }
1790
1791 // Write the layers
1792 int iNumLayers = 13;
1793 for (; iNumLayers >= 1; --iNumLayers) {
1794 if (layers.layer_contents[iNumLayers - 1] != 0) {
1795 break;
1796 }
1797 }
1798 pWriter->write_uint(iNumLayers);
1799 pWriter->write_byte_stream(layers.layer_contents, iNumLayers);
1800
1801 // Write the next chained thing
1802 lua_rawgeti(L, luaT_environindex, 2);
1803 lua_pushlightuserdata(L, next);
1804 lua_rawget(L, -2);
1805 pWriter->fast_write_stack_object(-1);
1806 lua_pop(L, 2);
1807 }
1808
depersist(lua_persist_reader * pReader)1809 void sprite_render_list::depersist(lua_persist_reader* pReader) {
1810 lua_State* L = pReader->get_stack();
1811
1812 if (!pReader->read_uint(sprite_count)) return;
1813 buffer_size = sprite_count;
1814 delete[] sprites;
1815 sprites = new sprite[buffer_size];
1816
1817 if (!pReader->read_uint(flags)) return;
1818 if (!pReader->read_int(x_relative_to_tile)) return;
1819 if (!pReader->read_int(y_relative_to_tile)) return;
1820 if (!pReader->read_int(dx_per_tick)) return;
1821 if (!pReader->read_int(dy_per_tick)) return;
1822 if (!pReader->read_int(lifetime)) return;
1823 for (sprite *pSprite = sprites, *pLast = sprites + sprite_count;
1824 pSprite != pLast; ++pSprite) {
1825 if (!pReader->read_uint(pSprite->index)) return;
1826 if (!pReader->read_int(pSprite->x)) return;
1827 if (!pReader->read_int(pSprite->y)) return;
1828 }
1829
1830 // Read the layers
1831 std::memset(layers.layer_contents, 0, sizeof(layers.layer_contents));
1832 int iNumLayers;
1833 if (!pReader->read_uint(iNumLayers)) {
1834 return;
1835 }
1836
1837 if (iNumLayers > 13) {
1838 if (!pReader->read_byte_stream(layers.layer_contents, 13)) {
1839 return;
1840 }
1841
1842 if (!pReader->read_byte_stream(nullptr, iNumLayers - 13)) {
1843 return;
1844 }
1845 } else {
1846 if (!pReader->read_byte_stream(layers.layer_contents, iNumLayers)) {
1847 return;
1848 }
1849 }
1850
1851 // Read the chain
1852 if (!pReader->read_stack_object()) {
1853 return;
1854 }
1855
1856 next = reinterpret_cast<link_list*>(lua_touserdata(L, -1));
1857 if (next) {
1858 next->prev = this;
1859 }
1860 lua_pop(L, 1);
1861
1862 // Fix the sheet field
1863 luaT_getenvfield(L, 2, "sheet");
1864 sheet = static_cast<sprite_sheet*>(lua_touserdata(L, -1));
1865 lua_pop(L, 1);
1866 }
1867