1 #include "World.h"
2
3
4 #include "common.h"
5 #include "map.h"
6
7
8 #include "minorGems/graphics/Image.h"
9 #include "minorGems/util/SimpleVector.h"
10
11
12
13
14
15 class GraphicContainer {
16
17 public:
18
GraphicContainer(const char * inTGAFileName)19 GraphicContainer( const char *inTGAFileName ) {
20
21 Image *image = readTGA( inTGAFileName );
22
23 mW = image->getWidth();
24 mH = image->getHeight();
25 int imagePixelCount = mW * mH;
26
27 mRed = new double[ imagePixelCount ];
28 mGreen = new double[ imagePixelCount ];
29 mBlue = new double[ imagePixelCount ];
30
31 for( int i=0; i<imagePixelCount; i++ ) {
32 mRed[i] = 255 * image->getChannel(0)[ i ];
33 mGreen[i] = 255 * image->getChannel(1)[ i ];
34 mBlue[i] = 255 * image->getChannel(2)[ i ];
35 }
36 delete image;
37 }
38
39
~GraphicContainer()40 ~GraphicContainer() {
41 delete [] mRed;
42 delete [] mGreen;
43 delete [] mBlue;
44 }
45
46
47 double *mRed;
48 double *mGreen;
49 double *mBlue;
50
51 int mW;
52 int mH;
53
54
55 };
56
57
58
59
60
61
62
63
64 GraphicContainer *tileContainer;
65 GraphicContainer *chestContainer;
66
67 GraphicContainer *spriteContainer;
68 GraphicContainer *spriteSadContainer;
69 GraphicContainer *spouseContainer;
70
71 GraphicContainer *prizeAnimationContainer;
72 GraphicContainer *dustAnimationContainer;
73 GraphicContainer *heartAnimationContainer;
74
75
76 // dimensions of one tile. TileImage contains 13 tiles, stacked vertically,
77 // with blank lines between tiles
78 int tileW = 8;
79 int tileH = 8;
80
81 int tileImageW;
82 int tileImageH;
83
84
85 int numTileSets;
86
87 // how wide the swath of a world is that uses a given tile set
88 int tileSetWorldSpan = 200;
89 // overlap during tile set transition
90 int tileSetWorldOverlap = 50;
91
92 // for testing
93 int tileSetSkip = 0;
94
95 int tileSetOrder[18] = { 0, 2, 10, 1, 8, 3, 5, 6, 4, 7, 13, 9, 15,
96 14, 16, 12, 11, 17 };
97
98
99
mapTileSet(int inSetNumber)100 int mapTileSet( int inSetNumber ) {
101 // stay in bounds of tileSetOrder
102 inSetNumber = inSetNumber % 18;
103
104 int mappedSetNumber = tileSetOrder[ inSetNumber ];
105
106 // stay in bounds of tile set collection
107 return mappedSetNumber % numTileSets;
108 }
109
110
111
112
113
114 int chestW = 8;
115 int chestH = 8;
116
117 int numGems = 6;
118 int gemLocations[6] = { 41, 42, 43, 44, 45, 46 };
119 //int gemLocations[4] = { 10, 11, 12, 13 };
120 double gemColors[6][3] = { { 255, 0, 0 },
121 { 0, 255, 0 },
122 { 255, 160, 0 },
123 { 0, 0, 255 },
124 { 255, 255, 0 },
125 { 255, 0, 255 } };
126
127
128
129
130 class Animation {
131 public:
132
Animation(int inX,int inY,int inFrameW,int inFrameH,char inAutoStep,char inRemoveAtEnd,GraphicContainer * inGraphics)133 Animation( int inX, int inY, int inFrameW, int inFrameH,
134 char inAutoStep,
135 char inRemoveAtEnd, GraphicContainer *inGraphics )
136 : mX( inX ), mY( inY ),
137 mFrameW( inFrameW ), mFrameH( inFrameH ),
138 mPageNumber( 0 ),
139 mFrameNumber( 0 ),
140 mAutoStep( inAutoStep ),
141 mRemoveAtEnd( inRemoveAtEnd ),
142 mGraphics( inGraphics ) {
143
144 mImageW = mGraphics->mW;
145
146 mNumFrames = ( mGraphics->mH - mFrameH ) / mFrameH + 1;
147 mNumPages = ( mGraphics->mW - mFrameW ) / mFrameW + 1;
148 }
149
150 // default constructor so that we can build a vector
151 // of Animations
Animation()152 Animation() {
153 }
154
155
156 // replaces graphics of animation
swapGraphics(GraphicContainer * inNewGraphics)157 void swapGraphics( GraphicContainer *inNewGraphics ) {
158
159 mGraphics = inNewGraphics;
160
161 mImageW = mGraphics->mW;
162
163 mNumFrames = ( mGraphics->mH - mFrameH ) / mFrameH + 1;
164 mNumPages = ( mGraphics->mW - mFrameW ) / mFrameW + 1;
165
166 if( mPageNumber >= mNumPages ) {
167 mPageNumber = mNumPages - 1;
168 }
169 if( mFrameNumber >= mNumFrames ) {
170 mFrameNumber = mNumFrames - 1;
171 }
172 }
173
174
175
176 int mX, mY;
177
178
179 int mFrameW, mFrameH;
180 int mImageW;
181
182 // can blend between pages
183 double mPageNumber;
184
185 int mNumPages;
186
187 int mFrameNumber;
188 int mNumFrames;
189 char mAutoStep;
190 char mRemoveAtEnd;
191
192
193 GraphicContainer *mGraphics;
194
195 };
196
197
198
199 SimpleVector<Animation> animationList;
200
201
202
203
204 // pointers into vectors are unsafe
205 //Animation *spriteAnimation;
206 //Animation *spouseAnimation;
207
208 int spriteAnimationIndex;
209 int spouseAnimationIndex;
210
211
212
213 char playerDead = false;
214 char spouseDead = false;
215 char metSpouse = false;
216
217
218
219 void resetSampleHashTable();
220
221
222
initWorld()223 void initWorld() {
224 resetMap();
225 resetSampleHashTable();
226
227 playerDead = false;
228 spouseDead = false;
229 metSpouse = false;
230
231 animationList.deleteAll();
232
233
234 tileImageW = tileContainer->mW;
235 tileImageH = tileContainer->mH;
236
237 numTileSets = (tileImageW + 1) / (tileW + 1);
238
239 Animation character( 0, 0, 8, 8, false, false, spriteContainer );
240
241
242 animationList.push_back( character );
243
244 // unsafe
245 // get pointer to animation in vector
246 //spriteAnimation = animationList.getElement( animationList.size() - 1 );
247 spriteAnimationIndex = animationList.size() - 1;
248
249 Animation spouse( 100, 7, 8, 8, false, false, spouseContainer );
250 spouse.mFrameNumber = 7;
251
252
253 animationList.push_back( spouse );
254
255 // unsafe!
256 // get pointer to animation in vector
257 //spouseAnimation = animationList.getElement( animationList.size() - 1 );
258 spouseAnimationIndex = animationList.size() - 1;
259 }
260
261
262
263
264
265
266
267
isSpriteTransparent(GraphicContainer * inContainer,int inSpriteIndex)268 char isSpriteTransparent( GraphicContainer *inContainer, int inSpriteIndex ) {
269
270 // take transparent color from corner
271 return
272 inContainer->mRed[ inSpriteIndex ] ==
273 inContainer->mRed[ 0 ]
274 &&
275 inContainer->mGreen[ inSpriteIndex ] ==
276 inContainer->mGreen[ 0 ]
277 &&
278 inContainer->mBlue[ inSpriteIndex ] ==
279 inContainer->mBlue[ 0 ];
280 }
281
282
283
284 struct rgbColorStruct {
285 double r;
286 double g;
287 double b;
288 };
289 typedef struct rgbColorStruct rgbColor;
290
291
292
293 // outTransient set to true if sample returned is part of a transient
294 // world feature (character sprite, chest, etc.)
295 rgbColor sampleFromWorldNoWeight( int inX, int inY, char *outTransient );
296
297 // same, but wrapped in a hash table to store non-transient results
298 rgbColor sampleFromWorldNoWeightHash( int inX, int inY );
299
300
301
sampleFromWorld(int inX,int inY,double inWeight)302 Uint32 sampleFromWorld( int inX, int inY, double inWeight ) {
303 rgbColor c = sampleFromWorldNoWeightHash( inX, inY );
304
305 unsigned char r = (unsigned char)( inWeight * c.r );
306 unsigned char g = (unsigned char)( inWeight * c.g );
307 unsigned char b = (unsigned char)( inWeight * c.b );
308
309
310 return r << 16 | g << 8 | b;
311 }
312
313
314
isSpritePresent(int inX,int inY)315 char isSpritePresent( int inX, int inY ) {
316 // look at animations
317 for( int i=0; i<animationList.size(); i++ ) {
318 Animation a = *( animationList.getElement( i ) );
319
320 int animW = a.mFrameW;
321 int animH = a.mFrameH;
322
323
324 // pixel position relative to animation center
325 // player position centered on sprint left-to-right
326 int animX = (int)( inX - a.mX + a.mFrameW / 2 );
327 int animY = (int)( inY - a.mY + a.mFrameH / 2 );
328
329 if( animX >= 0 && animX < animW
330 &&
331 animY >= 0 && animY < animH ) {
332 return true;
333 }
334
335 }
336
337
338 return false;
339 }
340
341
342
343 #include "HashTable.h"
344
345 HashTable<rgbColor> worldSampleHashTable( 30000 );
346
347
resetSampleHashTable()348 void resetSampleHashTable() {
349 worldSampleHashTable.clear();
350 }
351
352
353
sampleFromWorldNoWeightHash(int inX,int inY)354 rgbColor sampleFromWorldNoWeightHash( int inX, int inY ) {
355
356 char found;
357
358 rgbColor sample = worldSampleHashTable.lookup( inX, inY, &found );
359
360 if( isSpritePresent( inX, inY ) ) {
361 // don't consider cached result if a sprite is present
362 found = false;
363 }
364
365
366 if( found ) {
367 return sample;
368 }
369
370 // else not found
371
372 // call real function to get result
373 char transient;
374 sample = sampleFromWorldNoWeight( inX, inY, &transient );
375
376 // insert, but only if not transient
377 if( !transient ) {
378 worldSampleHashTable.insert( inX, inY, sample );
379 }
380
381 return sample;
382 }
383
384
385
sampleFromWorldNoWeight(int inX,int inY,char * outTransient)386 rgbColor sampleFromWorldNoWeight( int inX, int inY, char *outTransient ) {
387 *outTransient = false;
388
389 rgbColor returnColor;
390
391 char isSampleAnim = false;
392
393 // consider sampling from an animation
394 // draw them in reverse order so that oldest sprites are drawn on top
395 for( int i=animationList.size() - 1; i>=0; i-- ) {
396
397 Animation a = *( animationList.getElement( i ) );
398
399 int animW = a.mFrameW;
400 int animH = a.mFrameH;
401
402
403 // pixel position relative to animation center
404 // player position centered on sprint left-to-right
405 int animX = (int)( inX - a.mX + a.mFrameW / 2 );
406 int animY = (int)( inY - a.mY + a.mFrameH / 2 );
407
408 if( animX >= 0 && animX < animW
409 &&
410 animY >= 0 && animY < animH ) {
411
412 // pixel is in animation frame
413
414 int animIndex = animY * a.mImageW + animX;
415
416 // skip to appropriate anim page
417 animIndex += (int)a.mPageNumber * (animW + 1);
418
419
420 // skip to appropriate anim frame
421 animIndex +=
422 a.mFrameNumber *
423 a.mImageW *
424 ( animH + 1 );
425
426 // page to blend with
427 int animBlendIndex = animIndex + animW + 1;
428
429 double blendWeight = a.mPageNumber - (int)a.mPageNumber;
430
431
432 if( !isSpriteTransparent( a.mGraphics, animIndex ) ) {
433
434 // in non-transparent part
435
436 if( blendWeight != 0 ) {
437 returnColor.r =
438 ( 1 - blendWeight ) * a.mGraphics->mRed[ animIndex ]
439 +
440 blendWeight * a.mGraphics->mRed[ animBlendIndex ];
441 returnColor.g =
442 ( 1 - blendWeight ) * a.mGraphics->mGreen[ animIndex ]
443 +
444 blendWeight * a.mGraphics->mGreen[ animBlendIndex ];
445 returnColor.b =
446 ( 1 - blendWeight ) * a.mGraphics->mBlue[ animIndex ]
447 +
448 blendWeight * a.mGraphics->mBlue[ animBlendIndex ];
449 }
450 else {
451 // no blend
452 returnColor.r = a.mGraphics->mRed[ animIndex ];
453 returnColor.g = a.mGraphics->mGreen[ animIndex ];
454 returnColor.b = a.mGraphics->mBlue[ animIndex ];
455 }
456
457 *outTransient = true;
458 // don't return here, because there might be other
459 // animations and sprites that are on top of
460 // this one
461 isSampleAnim = true;
462 }
463 }
464 }
465
466 if( isSampleAnim ) {
467 // we have already found an animation here that is on top
468 // of whatever map graphics we might sample below
469
470 // thus, we can return now
471 return returnColor;
472 }
473
474
475
476 int tileIndex;
477
478 char blocked = isBlocked( inX, inY );
479
480 if( !blocked ) {
481 // empty tile
482 tileIndex = 0;
483 }
484 else {
485
486 int neighborsBlockedBinary = 0;
487
488 if( isBlocked( inX, inY - tileH ) ) {
489 // top
490 neighborsBlockedBinary = neighborsBlockedBinary | 1;
491 }
492 if( isBlocked( inX + tileW, inY ) ) {
493 // right
494 neighborsBlockedBinary = neighborsBlockedBinary | 1 << 1;
495 }
496 if( isBlocked( inX, inY + tileH ) ) {
497 // bottom
498 neighborsBlockedBinary = neighborsBlockedBinary | 1 << 2;
499 }
500 if( isBlocked( inX - tileW, inY ) ) {
501 // left
502 neighborsBlockedBinary = neighborsBlockedBinary | 1 << 3;
503 }
504
505 // skip empty tile, treat as tile index
506 neighborsBlockedBinary += 1;
507
508 tileIndex = neighborsBlockedBinary;
509 }
510
511
512
513 // pick a tile set
514 int netWorldSpan = tileSetWorldSpan + tileSetWorldOverlap;
515
516 int tileSet = inX / netWorldSpan + tileSetSkip;
517 int overhang = inX % netWorldSpan;
518 if( inX < 0 ) {
519 // fix to a constant tile set below 0
520 overhang = 0;
521 tileSet = 0;
522 }
523
524 // is there blending with next tile set?
525 int blendTileSet = tileSet + 1;
526 double blendWeight = 0;
527
528 if( overhang > tileSetWorldSpan ) {
529 blendWeight = ( overhang - tileSetWorldSpan ) /
530 (double) tileSetWorldOverlap;
531 }
532 // else 100% blend of our first tile set
533
534
535 tileSet = tileSet % numTileSets;
536 blendTileSet = blendTileSet % numTileSets;
537
538 // make sure not negative
539 if( tileSet < 0 ) {
540 tileSet += numTileSets;
541 }
542 if( blendTileSet < 0 ) {
543 blendTileSet += numTileSets;
544 }
545
546
547 // apply mapping
548 tileSet = mapTileSet( tileSet );
549 blendTileSet = mapTileSet( blendTileSet );
550
551
552 // sample from tile image
553 int imageY = inY % tileH;
554 int imageX = inX % tileW;
555
556
557 if( imageX < 0 ) {
558 imageX += tileW;
559 }
560 if( imageY < 0 ) {
561 imageY += tileH;
562 }
563
564 // offset to top left corner of tile
565 int tileImageOffset = tileIndex * ( tileH + 1 ) * tileImageW
566 + tileSet * (tileW + 1);
567 int blendTileImageOffset = tileIndex * ( tileH + 1 ) * tileImageW
568 + blendTileSet * (tileW + 1);
569
570
571 int imageIndex = tileImageOffset + imageY * tileImageW + imageX;
572 int blendImageIndex = blendTileImageOffset + imageY * tileImageW + imageX;
573
574 returnColor.r =
575 (1-blendWeight) * tileContainer->mRed[ imageIndex ] +
576 blendWeight * tileContainer->mRed[ blendImageIndex ];
577
578 returnColor.g =
579 (1-blendWeight) * tileContainer->mGreen[ imageIndex ] +
580 blendWeight * tileContainer->mGreen[ blendImageIndex ];
581
582 returnColor.b =
583 (1-blendWeight) * tileContainer->mBlue[ imageIndex ] +
584 blendWeight * tileContainer->mBlue[ blendImageIndex ];
585
586
587 // only consider drawing chests in empty spots
588 if( !blocked && isChest( inX, inY ) ) {
589 // draw chest here
590
591 char chestType = isChest( inX, inY );
592
593
594 // sample from chest image
595 int imageY = inY % chestH;
596 int imageX = inX % chestW;
597
598
599 if( imageX < 0 ) {
600 imageX += chestW;
601 }
602 if( imageY < 0 ) {
603 imageY += chestH;
604 }
605
606 int spriteIndex = 0;
607
608 if( chestType == CHEST_OPEN ) {
609 spriteIndex = 1;
610 }
611
612 // skip to sub-sprite
613 int spriteOffset =
614 spriteIndex *
615 chestW *
616 ( chestH + 1 );
617
618 int subSpriteIndex = imageY * chestW + imageX;
619
620 int imageIndex = spriteOffset + subSpriteIndex;
621
622 if( !isSpriteTransparent( chestContainer, imageIndex ) ) {
623
624 if( chestType == CHEST_CLOSED ) {
625 *outTransient = true;
626 }
627
628 // check if this is one of the gem locations
629 char isGem = false;
630 int gemNumber = 0;
631
632 for( int i=0; i<numGems && !isGem; i++ ) {
633 if( subSpriteIndex == gemLocations[ i ] ) {
634 isGem = true;
635 gemNumber = i;
636 }
637 }
638
639 char gemColorUsed = false;
640
641 if( isGem ) {
642 // check if our gem is turned on for this chest
643 unsigned char code = getChestCode( inX, inY );
644
645 if( code & 0x01 << gemNumber ) {
646
647 gemColorUsed = true;
648
649 returnColor.r = gemColors[ gemNumber ][ 0 ];
650 returnColor.g = gemColors[ gemNumber ][ 1 ];
651 returnColor.b = gemColors[ gemNumber ][ 2 ];
652
653 }
654
655 }
656
657
658 if( !gemColorUsed ) {
659 // use underlying chest color
660 returnColor.r = chestContainer->mRed[ imageIndex ];
661 returnColor.g = chestContainer->mGreen[ imageIndex ];
662 returnColor.b = chestContainer->mBlue[ imageIndex ];
663 }
664
665 }
666
667 }
668
669
670 return returnColor;
671 }
672
673
674
675
676
677
getTileWidth()678 int getTileWidth() {
679 return tileW;
680 }
681
682
683
getTileHeight()684 int getTileHeight() {
685 return tileH;
686 }
687
688
689
destroyWorld()690 void destroyWorld() {
691 /*
692 printf( "%d hits, %d misses, %f hit ratio\n",
693 hitCount, missCount, hitCount / (double)( hitCount + missCount ) );
694 */
695 }
696
697
698
stepAnimations()699 void stepAnimations() {
700
701
702 for( int i=0; i<animationList.size(); i++ ) {
703 Animation *a = animationList.getElement( i );
704 if( a->mAutoStep ) {
705 if( a->mFrameNumber < a->mNumFrames - 1 ) {
706 a->mFrameNumber ++;
707 }
708 else if( a->mRemoveAtEnd ) {
709 // remove it
710 animationList.deleteElement( i );
711 // back up in list for next loop iteration
712 i--;
713 }
714 }
715
716 }
717 }
718
719
720
startPrizeAnimation(int inX,int inY)721 void startPrizeAnimation( int inX, int inY ) {
722
723 Animation a( inX, inY, 16, 16, true, true, prizeAnimationContainer );
724
725 animationList.push_back( a );
726 }
727
728
729
startDustAnimation(int inX,int inY)730 void startDustAnimation( int inX, int inY ) {
731
732 Animation a( inX, inY, 16, 16, true, true, dustAnimationContainer );
733
734 animationList.push_back( a );
735 }
736
737
738
startHeartAnimation(int inX,int inY)739 void startHeartAnimation( int inX, int inY ) {
740
741 Animation a( inX, inY, 16, 16, true, true, heartAnimationContainer );
742
743 animationList.push_back( a );
744 }
745
746
747
748
749
750 #include <math.h>
751
752
setPlayerPosition(int inX,int inY)753 void setPlayerPosition( int inX, int inY ) {
754
755 Animation *spriteAnimation =
756 animationList.getElement( spriteAnimationIndex );
757
758 char moving = false;
759
760 if( inX != spriteAnimation->mX ) {
761 moving = true;
762 }
763
764
765 spriteAnimation->mX = inX;
766 // player position centered at sprite's feet
767 int newSpriteY = inY - spriteAnimation->mFrameH / 2 + 1;
768
769
770 if( newSpriteY != spriteAnimation->mY ) {
771 moving = true;
772 }
773
774 spriteAnimation->mY = newSpriteY;
775
776 if( metSpouse && ! spouseDead ) {
777 Animation *spouseAnimation =
778 animationList.getElement( spouseAnimationIndex );
779
780 // spouse stands immediately in front of player
781 int desiredSpouseX = inX + spouseAnimation->mFrameH;
782 int desiredSpouseY = spriteAnimation->mY;
783
784 // gravitates there gradually one pixel at a time in each x and y
785 int dX = desiredSpouseX - spouseAnimation->mX;
786 int dY = desiredSpouseY - spouseAnimation->mY;
787
788 // convert to -1, 0, or +1
789 if( dX != 0 ) {
790 dX = (int)( dX / fabs( dX ) );
791 }
792 if( dY != 0 ) {
793 dY = (int)( dY / fabs( dY ) );
794 }
795
796 if( moving ) {
797 // only execute this transition when player is moving
798 spouseAnimation->mX += dX;
799 spouseAnimation->mY += dY;
800 }
801
802
803 // check for heart animation and have it track moving couple
804 for( int i=0; i<animationList.size(); i++ ) {
805 Animation *a = animationList.getElement( i );
806
807 if( a->mGraphics == heartAnimationContainer ) {
808
809 // move it halfway between player and spouse
810 a->mX = ( spouseAnimation->mX - spriteAnimation->mX ) / 2 +
811 spriteAnimation->mX;
812 a->mY = ( spouseAnimation->mY - spriteAnimation->mY ) / 2 +
813 spriteAnimation->mY + 1;
814 }
815 }
816
817
818 }
819
820 }
821
822
823
setPlayerSpriteFrame(int inFrame)824 void setPlayerSpriteFrame( int inFrame ) {
825 Animation *spriteAnimation =
826 animationList.getElement( spriteAnimationIndex );
827
828 spriteAnimation->mFrameNumber = inFrame;
829
830 if( metSpouse && ! spouseDead ) {
831 Animation *spouseAnimation =
832 animationList.getElement( spouseAnimationIndex );
833
834 // spouse follows player
835 spouseAnimation->mFrameNumber = inFrame;
836 }
837 }
838
839
840
setCharacterAges(double inAge)841 void setCharacterAges( double inAge ) {
842 Animation *spriteAnimation =
843 animationList.getElement( spriteAnimationIndex );
844 Animation *spouseAnimation =
845 animationList.getElement( spouseAnimationIndex );
846
847 // 0 -> 0.25, constant page 0
848 if( inAge <= 0.25 ) {
849 spriteAnimation->mPageNumber = 0;
850 spouseAnimation->mPageNumber = 0;
851 }
852 // 0.75 - 1.0, constant last page
853 else if( inAge >= 0.75 ) {
854 spriteAnimation->mPageNumber = spriteAnimation->mNumPages - 1;
855 spouseAnimation->mPageNumber = spouseAnimation->mNumPages - 1;
856 }
857 else {
858 // blend of pages in between
859 double blendingAge = ( inAge - 0.25 ) / 0.5;
860
861 spriteAnimation->mPageNumber =
862 blendingAge * ( spriteAnimation->mNumPages - 1 );
863
864 spouseAnimation->mPageNumber =
865 blendingAge * ( spouseAnimation->mNumPages - 1 );
866 }
867 }
868
869
870
getSpousePosition(int * outX,int * outY)871 void getSpousePosition( int *outX, int *outY ) {
872 Animation *spouseAnimation =
873 animationList.getElement( spouseAnimationIndex );
874
875 *outX = spouseAnimation->mX;
876 *outY = spouseAnimation->mY + spouseAnimation->mFrameH / 2 - 1;
877 }
878
879
880
haveMetSpouse()881 char haveMetSpouse() {
882 return metSpouse && ! spouseDead;
883 }
884
885
886
meetSpouse()887 void meetSpouse() {
888 metSpouse = true;
889 }
890
891
892
diePlayer()893 void diePlayer() {
894 Animation *spriteAnimation =
895 animationList.getElement( spriteAnimationIndex );
896
897 playerDead = true;
898
899 // tombstone
900 spriteAnimation->mFrameNumber = 8;
901 }
902
903
904
dieSpouse()905 void dieSpouse() {
906 Animation *spriteAnimation =
907 animationList.getElement( spriteAnimationIndex );
908 Animation *spouseAnimation =
909 animationList.getElement( spouseAnimationIndex );
910
911 spouseDead = true;
912
913 // tombstone
914 spouseAnimation->mFrameNumber = 8;
915
916 if( metSpouse ) {
917 // swap player sprite with sad sprite
918 spriteAnimation->swapGraphics( spriteSadContainer );
919 }
920 }
921
922
923
isPlayerDead()924 char isPlayerDead() {
925 return playerDead;
926 }
927
928
929
isSpouseDead()930 char isSpouseDead() {
931 return spouseDead;
932 }
933
934
935
loadWorldGraphics()936 void loadWorldGraphics() {
937 tileContainer = new GraphicContainer( "tileSet.tga" );
938 chestContainer = new GraphicContainer( "chest.tga" );
939
940 spriteContainer = new GraphicContainer( "characterSprite.tga" );
941 spriteSadContainer = new GraphicContainer( "characterSpriteSad.tga" );
942 spouseContainer = new GraphicContainer( "spouseSprite.tga" );
943
944 prizeAnimationContainer = new GraphicContainer( "chestPrize.tga" );
945 dustAnimationContainer = new GraphicContainer( "chestDust.tga" );
946 heartAnimationContainer = new GraphicContainer( "heart.tga" );
947 }
948
949
950
destroyWorldGraphics()951 void destroyWorldGraphics() {
952 delete tileContainer;
953 delete chestContainer;
954
955 delete spriteContainer;
956 delete spriteSadContainer;
957 delete spouseContainer;
958
959 delete prizeAnimationContainer;
960 delete dustAnimationContainer;
961 delete heartAnimationContainer;
962 }
963
964