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