Initial source commit
This commit is contained in:
commit
f1384c11ee
335 changed files with 52715 additions and 0 deletions
963
gamma256/gameSource/World.cpp
Normal file
963
gamma256/gameSource/World.cpp
Normal file
|
@ -0,0 +1,963 @@
|
|||
#include "World.h"
|
||||
|
||||
|
||||
#include "common.h"
|
||||
#include "map.h"
|
||||
|
||||
|
||||
#include "minorGems/graphics/Image.h"
|
||||
#include "minorGems/util/SimpleVector.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class GraphicContainer {
|
||||
|
||||
public:
|
||||
|
||||
GraphicContainer( const char *inTGAFileName ) {
|
||||
|
||||
Image *image = readTGA( inTGAFileName );
|
||||
|
||||
mW = image->getWidth();
|
||||
mH = image->getHeight();
|
||||
int imagePixelCount = mW * mH;
|
||||
|
||||
mRed = new double[ imagePixelCount ];
|
||||
mGreen = new double[ imagePixelCount ];
|
||||
mBlue = new double[ imagePixelCount ];
|
||||
|
||||
for( int i=0; i<imagePixelCount; i++ ) {
|
||||
mRed[i] = 255 * image->getChannel(0)[ i ];
|
||||
mGreen[i] = 255 * image->getChannel(1)[ i ];
|
||||
mBlue[i] = 255 * image->getChannel(2)[ i ];
|
||||
}
|
||||
delete image;
|
||||
}
|
||||
|
||||
|
||||
~GraphicContainer() {
|
||||
delete [] mRed;
|
||||
delete [] mGreen;
|
||||
delete [] mBlue;
|
||||
}
|
||||
|
||||
|
||||
double *mRed;
|
||||
double *mGreen;
|
||||
double *mBlue;
|
||||
|
||||
int mW;
|
||||
int mH;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
GraphicContainer *tileContainer;
|
||||
GraphicContainer *chestContainer;
|
||||
|
||||
GraphicContainer *spriteContainer;
|
||||
GraphicContainer *spriteSadContainer;
|
||||
GraphicContainer *spouseContainer;
|
||||
|
||||
GraphicContainer *prizeAnimationContainer;
|
||||
GraphicContainer *dustAnimationContainer;
|
||||
GraphicContainer *heartAnimationContainer;
|
||||
|
||||
|
||||
// dimensions of one tile. TileImage contains 13 tiles, stacked vertically,
|
||||
// with blank lines between tiles
|
||||
int tileW = 8;
|
||||
int tileH = 8;
|
||||
|
||||
int tileImageW;
|
||||
int tileImageH;
|
||||
|
||||
|
||||
int numTileSets;
|
||||
|
||||
// how wide the swath of a world is that uses a given tile set
|
||||
int tileSetWorldSpan = 200;
|
||||
// overlap during tile set transition
|
||||
int tileSetWorldOverlap = 50;
|
||||
|
||||
// for testing
|
||||
int tileSetSkip = 0;
|
||||
|
||||
int tileSetOrder[18] = { 0, 2, 10, 1, 8, 3, 5, 6, 4, 7, 13, 9, 15,
|
||||
14, 16, 12, 11, 17 };
|
||||
|
||||
|
||||
|
||||
int mapTileSet( int inSetNumber ) {
|
||||
// stay in bounds of tileSetOrder
|
||||
inSetNumber = inSetNumber % 18;
|
||||
|
||||
int mappedSetNumber = tileSetOrder[ inSetNumber ];
|
||||
|
||||
// stay in bounds of tile set collection
|
||||
return mappedSetNumber % numTileSets;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int chestW = 8;
|
||||
int chestH = 8;
|
||||
|
||||
int numGems = 6;
|
||||
int gemLocations[6] = { 41, 42, 43, 44, 45, 46 };
|
||||
//int gemLocations[4] = { 10, 11, 12, 13 };
|
||||
double gemColors[6][3] = { { 255, 0, 0 },
|
||||
{ 0, 255, 0 },
|
||||
{ 255, 160, 0 },
|
||||
{ 0, 0, 255 },
|
||||
{ 255, 255, 0 },
|
||||
{ 255, 0, 255 } };
|
||||
|
||||
|
||||
|
||||
|
||||
class Animation {
|
||||
public:
|
||||
|
||||
Animation( int inX, int inY, int inFrameW, int inFrameH,
|
||||
char inAutoStep,
|
||||
char inRemoveAtEnd, GraphicContainer *inGraphics )
|
||||
: mX( inX ), mY( inY ),
|
||||
mFrameW( inFrameW ), mFrameH( inFrameH ),
|
||||
mPageNumber( 0 ),
|
||||
mFrameNumber( 0 ),
|
||||
mAutoStep( inAutoStep ),
|
||||
mRemoveAtEnd( inRemoveAtEnd ),
|
||||
mGraphics( inGraphics ) {
|
||||
|
||||
mImageW = mGraphics->mW;
|
||||
|
||||
mNumFrames = ( mGraphics->mH - mFrameH ) / mFrameH + 1;
|
||||
mNumPages = ( mGraphics->mW - mFrameW ) / mFrameW + 1;
|
||||
}
|
||||
|
||||
// default constructor so that we can build a vector
|
||||
// of Animations
|
||||
Animation() {
|
||||
}
|
||||
|
||||
|
||||
// replaces graphics of animation
|
||||
void swapGraphics( GraphicContainer *inNewGraphics ) {
|
||||
|
||||
mGraphics = inNewGraphics;
|
||||
|
||||
mImageW = mGraphics->mW;
|
||||
|
||||
mNumFrames = ( mGraphics->mH - mFrameH ) / mFrameH + 1;
|
||||
mNumPages = ( mGraphics->mW - mFrameW ) / mFrameW + 1;
|
||||
|
||||
if( mPageNumber >= mNumPages ) {
|
||||
mPageNumber = mNumPages - 1;
|
||||
}
|
||||
if( mFrameNumber >= mNumFrames ) {
|
||||
mFrameNumber = mNumFrames - 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int mX, mY;
|
||||
|
||||
|
||||
int mFrameW, mFrameH;
|
||||
int mImageW;
|
||||
|
||||
// can blend between pages
|
||||
double mPageNumber;
|
||||
|
||||
int mNumPages;
|
||||
|
||||
int mFrameNumber;
|
||||
int mNumFrames;
|
||||
char mAutoStep;
|
||||
char mRemoveAtEnd;
|
||||
|
||||
|
||||
GraphicContainer *mGraphics;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
SimpleVector<Animation> animationList;
|
||||
|
||||
|
||||
|
||||
|
||||
// pointers into vectors are unsafe
|
||||
//Animation *spriteAnimation;
|
||||
//Animation *spouseAnimation;
|
||||
|
||||
int spriteAnimationIndex;
|
||||
int spouseAnimationIndex;
|
||||
|
||||
|
||||
|
||||
char playerDead = false;
|
||||
char spouseDead = false;
|
||||
char metSpouse = false;
|
||||
|
||||
|
||||
|
||||
void resetSampleHashTable();
|
||||
|
||||
|
||||
|
||||
void initWorld() {
|
||||
resetMap();
|
||||
resetSampleHashTable();
|
||||
|
||||
playerDead = false;
|
||||
spouseDead = false;
|
||||
metSpouse = false;
|
||||
|
||||
animationList.deleteAll();
|
||||
|
||||
|
||||
tileImageW = tileContainer->mW;
|
||||
tileImageH = tileContainer->mH;
|
||||
|
||||
numTileSets = (tileImageW + 1) / (tileW + 1);
|
||||
|
||||
Animation character( 0, 0, 8, 8, false, false, spriteContainer );
|
||||
|
||||
|
||||
animationList.push_back( character );
|
||||
|
||||
// unsafe
|
||||
// get pointer to animation in vector
|
||||
//spriteAnimation = animationList.getElement( animationList.size() - 1 );
|
||||
spriteAnimationIndex = animationList.size() - 1;
|
||||
|
||||
Animation spouse( 100, 7, 8, 8, false, false, spouseContainer );
|
||||
spouse.mFrameNumber = 7;
|
||||
|
||||
|
||||
animationList.push_back( spouse );
|
||||
|
||||
// unsafe!
|
||||
// get pointer to animation in vector
|
||||
//spouseAnimation = animationList.getElement( animationList.size() - 1 );
|
||||
spouseAnimationIndex = animationList.size() - 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
char isSpriteTransparent( GraphicContainer *inContainer, int inSpriteIndex ) {
|
||||
|
||||
// take transparent color from corner
|
||||
return
|
||||
inContainer->mRed[ inSpriteIndex ] ==
|
||||
inContainer->mRed[ 0 ]
|
||||
&&
|
||||
inContainer->mGreen[ inSpriteIndex ] ==
|
||||
inContainer->mGreen[ 0 ]
|
||||
&&
|
||||
inContainer->mBlue[ inSpriteIndex ] ==
|
||||
inContainer->mBlue[ 0 ];
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct rgbColorStruct {
|
||||
double r;
|
||||
double g;
|
||||
double b;
|
||||
};
|
||||
typedef struct rgbColorStruct rgbColor;
|
||||
|
||||
|
||||
|
||||
// outTransient set to true if sample returned is part of a transient
|
||||
// world feature (character sprite, chest, etc.)
|
||||
rgbColor sampleFromWorldNoWeight( int inX, int inY, char *outTransient );
|
||||
|
||||
// same, but wrapped in a hash table to store non-transient results
|
||||
rgbColor sampleFromWorldNoWeightHash( int inX, int inY );
|
||||
|
||||
|
||||
|
||||
Uint32 sampleFromWorld( int inX, int inY, double inWeight ) {
|
||||
rgbColor c = sampleFromWorldNoWeightHash( inX, inY );
|
||||
|
||||
unsigned char r = (unsigned char)( inWeight * c.r );
|
||||
unsigned char g = (unsigned char)( inWeight * c.g );
|
||||
unsigned char b = (unsigned char)( inWeight * c.b );
|
||||
|
||||
|
||||
return r << 16 | g << 8 | b;
|
||||
}
|
||||
|
||||
|
||||
|
||||
char isSpritePresent( int inX, int inY ) {
|
||||
// look at animations
|
||||
for( int i=0; i<animationList.size(); i++ ) {
|
||||
Animation a = *( animationList.getElement( i ) );
|
||||
|
||||
int animW = a.mFrameW;
|
||||
int animH = a.mFrameH;
|
||||
|
||||
|
||||
// pixel position relative to animation center
|
||||
// player position centered on sprint left-to-right
|
||||
int animX = (int)( inX - a.mX + a.mFrameW / 2 );
|
||||
int animY = (int)( inY - a.mY + a.mFrameH / 2 );
|
||||
|
||||
if( animX >= 0 && animX < animW
|
||||
&&
|
||||
animY >= 0 && animY < animH ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#include "HashTable.h"
|
||||
|
||||
HashTable<rgbColor> worldSampleHashTable( 30000 );
|
||||
|
||||
|
||||
void resetSampleHashTable() {
|
||||
worldSampleHashTable.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
rgbColor sampleFromWorldNoWeightHash( int inX, int inY ) {
|
||||
|
||||
char found;
|
||||
|
||||
rgbColor sample = worldSampleHashTable.lookup( inX, inY, &found );
|
||||
|
||||
if( isSpritePresent( inX, inY ) ) {
|
||||
// don't consider cached result if a sprite is present
|
||||
found = false;
|
||||
}
|
||||
|
||||
|
||||
if( found ) {
|
||||
return sample;
|
||||
}
|
||||
|
||||
// else not found
|
||||
|
||||
// call real function to get result
|
||||
char transient;
|
||||
sample = sampleFromWorldNoWeight( inX, inY, &transient );
|
||||
|
||||
// insert, but only if not transient
|
||||
if( !transient ) {
|
||||
worldSampleHashTable.insert( inX, inY, sample );
|
||||
}
|
||||
|
||||
return sample;
|
||||
}
|
||||
|
||||
|
||||
|
||||
rgbColor sampleFromWorldNoWeight( int inX, int inY, char *outTransient ) {
|
||||
*outTransient = false;
|
||||
|
||||
rgbColor returnColor;
|
||||
|
||||
char isSampleAnim = false;
|
||||
|
||||
// consider sampling from an animation
|
||||
// draw them in reverse order so that oldest sprites are drawn on top
|
||||
for( int i=animationList.size() - 1; i>=0; i-- ) {
|
||||
|
||||
Animation a = *( animationList.getElement( i ) );
|
||||
|
||||
int animW = a.mFrameW;
|
||||
int animH = a.mFrameH;
|
||||
|
||||
|
||||
// pixel position relative to animation center
|
||||
// player position centered on sprint left-to-right
|
||||
int animX = (int)( inX - a.mX + a.mFrameW / 2 );
|
||||
int animY = (int)( inY - a.mY + a.mFrameH / 2 );
|
||||
|
||||
if( animX >= 0 && animX < animW
|
||||
&&
|
||||
animY >= 0 && animY < animH ) {
|
||||
|
||||
// pixel is in animation frame
|
||||
|
||||
int animIndex = animY * a.mImageW + animX;
|
||||
|
||||
// skip to appropriate anim page
|
||||
animIndex += (int)a.mPageNumber * (animW + 1);
|
||||
|
||||
|
||||
// skip to appropriate anim frame
|
||||
animIndex +=
|
||||
a.mFrameNumber *
|
||||
a.mImageW *
|
||||
( animH + 1 );
|
||||
|
||||
// page to blend with
|
||||
int animBlendIndex = animIndex + animW + 1;
|
||||
|
||||
double blendWeight = a.mPageNumber - (int)a.mPageNumber;
|
||||
|
||||
|
||||
if( !isSpriteTransparent( a.mGraphics, animIndex ) ) {
|
||||
|
||||
// in non-transparent part
|
||||
|
||||
if( blendWeight != 0 ) {
|
||||
returnColor.r =
|
||||
( 1 - blendWeight ) * a.mGraphics->mRed[ animIndex ]
|
||||
+
|
||||
blendWeight * a.mGraphics->mRed[ animBlendIndex ];
|
||||
returnColor.g =
|
||||
( 1 - blendWeight ) * a.mGraphics->mGreen[ animIndex ]
|
||||
+
|
||||
blendWeight * a.mGraphics->mGreen[ animBlendIndex ];
|
||||
returnColor.b =
|
||||
( 1 - blendWeight ) * a.mGraphics->mBlue[ animIndex ]
|
||||
+
|
||||
blendWeight * a.mGraphics->mBlue[ animBlendIndex ];
|
||||
}
|
||||
else {
|
||||
// no blend
|
||||
returnColor.r = a.mGraphics->mRed[ animIndex ];
|
||||
returnColor.g = a.mGraphics->mGreen[ animIndex ];
|
||||
returnColor.b = a.mGraphics->mBlue[ animIndex ];
|
||||
}
|
||||
|
||||
*outTransient = true;
|
||||
// don't return here, because there might be other
|
||||
// animations and sprites that are on top of
|
||||
// this one
|
||||
isSampleAnim = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( isSampleAnim ) {
|
||||
// we have already found an animation here that is on top
|
||||
// of whatever map graphics we might sample below
|
||||
|
||||
// thus, we can return now
|
||||
return returnColor;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int tileIndex;
|
||||
|
||||
char blocked = isBlocked( inX, inY );
|
||||
|
||||
if( !blocked ) {
|
||||
// empty tile
|
||||
tileIndex = 0;
|
||||
}
|
||||
else {
|
||||
|
||||
int neighborsBlockedBinary = 0;
|
||||
|
||||
if( isBlocked( inX, inY - tileH ) ) {
|
||||
// top
|
||||
neighborsBlockedBinary = neighborsBlockedBinary | 1;
|
||||
}
|
||||
if( isBlocked( inX + tileW, inY ) ) {
|
||||
// right
|
||||
neighborsBlockedBinary = neighborsBlockedBinary | 1 << 1;
|
||||
}
|
||||
if( isBlocked( inX, inY + tileH ) ) {
|
||||
// bottom
|
||||
neighborsBlockedBinary = neighborsBlockedBinary | 1 << 2;
|
||||
}
|
||||
if( isBlocked( inX - tileW, inY ) ) {
|
||||
// left
|
||||
neighborsBlockedBinary = neighborsBlockedBinary | 1 << 3;
|
||||
}
|
||||
|
||||
// skip empty tile, treat as tile index
|
||||
neighborsBlockedBinary += 1;
|
||||
|
||||
tileIndex = neighborsBlockedBinary;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// pick a tile set
|
||||
int netWorldSpan = tileSetWorldSpan + tileSetWorldOverlap;
|
||||
|
||||
int tileSet = inX / netWorldSpan + tileSetSkip;
|
||||
int overhang = inX % netWorldSpan;
|
||||
if( inX < 0 ) {
|
||||
// fix to a constant tile set below 0
|
||||
overhang = 0;
|
||||
tileSet = 0;
|
||||
}
|
||||
|
||||
// is there blending with next tile set?
|
||||
int blendTileSet = tileSet + 1;
|
||||
double blendWeight = 0;
|
||||
|
||||
if( overhang > tileSetWorldSpan ) {
|
||||
blendWeight = ( overhang - tileSetWorldSpan ) /
|
||||
(double) tileSetWorldOverlap;
|
||||
}
|
||||
// else 100% blend of our first tile set
|
||||
|
||||
|
||||
tileSet = tileSet % numTileSets;
|
||||
blendTileSet = blendTileSet % numTileSets;
|
||||
|
||||
// make sure not negative
|
||||
if( tileSet < 0 ) {
|
||||
tileSet += numTileSets;
|
||||
}
|
||||
if( blendTileSet < 0 ) {
|
||||
blendTileSet += numTileSets;
|
||||
}
|
||||
|
||||
|
||||
// apply mapping
|
||||
tileSet = mapTileSet( tileSet );
|
||||
blendTileSet = mapTileSet( blendTileSet );
|
||||
|
||||
|
||||
// sample from tile image
|
||||
int imageY = inY % tileH;
|
||||
int imageX = inX % tileW;
|
||||
|
||||
|
||||
if( imageX < 0 ) {
|
||||
imageX += tileW;
|
||||
}
|
||||
if( imageY < 0 ) {
|
||||
imageY += tileH;
|
||||
}
|
||||
|
||||
// offset to top left corner of tile
|
||||
int tileImageOffset = tileIndex * ( tileH + 1 ) * tileImageW
|
||||
+ tileSet * (tileW + 1);
|
||||
int blendTileImageOffset = tileIndex * ( tileH + 1 ) * tileImageW
|
||||
+ blendTileSet * (tileW + 1);
|
||||
|
||||
|
||||
int imageIndex = tileImageOffset + imageY * tileImageW + imageX;
|
||||
int blendImageIndex = blendTileImageOffset + imageY * tileImageW + imageX;
|
||||
|
||||
returnColor.r =
|
||||
(1-blendWeight) * tileContainer->mRed[ imageIndex ] +
|
||||
blendWeight * tileContainer->mRed[ blendImageIndex ];
|
||||
|
||||
returnColor.g =
|
||||
(1-blendWeight) * tileContainer->mGreen[ imageIndex ] +
|
||||
blendWeight * tileContainer->mGreen[ blendImageIndex ];
|
||||
|
||||
returnColor.b =
|
||||
(1-blendWeight) * tileContainer->mBlue[ imageIndex ] +
|
||||
blendWeight * tileContainer->mBlue[ blendImageIndex ];
|
||||
|
||||
|
||||
// only consider drawing chests in empty spots
|
||||
if( !blocked && isChest( inX, inY ) ) {
|
||||
// draw chest here
|
||||
|
||||
char chestType = isChest( inX, inY );
|
||||
|
||||
|
||||
// sample from chest image
|
||||
int imageY = inY % chestH;
|
||||
int imageX = inX % chestW;
|
||||
|
||||
|
||||
if( imageX < 0 ) {
|
||||
imageX += chestW;
|
||||
}
|
||||
if( imageY < 0 ) {
|
||||
imageY += chestH;
|
||||
}
|
||||
|
||||
int spriteIndex = 0;
|
||||
|
||||
if( chestType == CHEST_OPEN ) {
|
||||
spriteIndex = 1;
|
||||
}
|
||||
|
||||
// skip to sub-sprite
|
||||
int spriteOffset =
|
||||
spriteIndex *
|
||||
chestW *
|
||||
( chestH + 1 );
|
||||
|
||||
int subSpriteIndex = imageY * chestW + imageX;
|
||||
|
||||
int imageIndex = spriteOffset + subSpriteIndex;
|
||||
|
||||
if( !isSpriteTransparent( chestContainer, imageIndex ) ) {
|
||||
|
||||
if( chestType == CHEST_CLOSED ) {
|
||||
*outTransient = true;
|
||||
}
|
||||
|
||||
// check if this is one of the gem locations
|
||||
char isGem = false;
|
||||
int gemNumber = 0;
|
||||
|
||||
for( int i=0; i<numGems && !isGem; i++ ) {
|
||||
if( subSpriteIndex == gemLocations[ i ] ) {
|
||||
isGem = true;
|
||||
gemNumber = i;
|
||||
}
|
||||
}
|
||||
|
||||
char gemColorUsed = false;
|
||||
|
||||
if( isGem ) {
|
||||
// check if our gem is turned on for this chest
|
||||
unsigned char code = getChestCode( inX, inY );
|
||||
|
||||
if( code & 0x01 << gemNumber ) {
|
||||
|
||||
gemColorUsed = true;
|
||||
|
||||
returnColor.r = gemColors[ gemNumber ][ 0 ];
|
||||
returnColor.g = gemColors[ gemNumber ][ 1 ];
|
||||
returnColor.b = gemColors[ gemNumber ][ 2 ];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if( !gemColorUsed ) {
|
||||
// use underlying chest color
|
||||
returnColor.r = chestContainer->mRed[ imageIndex ];
|
||||
returnColor.g = chestContainer->mGreen[ imageIndex ];
|
||||
returnColor.b = chestContainer->mBlue[ imageIndex ];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
return returnColor;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int getTileWidth() {
|
||||
return tileW;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int getTileHeight() {
|
||||
return tileH;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void destroyWorld() {
|
||||
/*
|
||||
printf( "%d hits, %d misses, %f hit ratio\n",
|
||||
hitCount, missCount, hitCount / (double)( hitCount + missCount ) );
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
void stepAnimations() {
|
||||
|
||||
|
||||
for( int i=0; i<animationList.size(); i++ ) {
|
||||
Animation *a = animationList.getElement( i );
|
||||
if( a->mAutoStep ) {
|
||||
if( a->mFrameNumber < a->mNumFrames - 1 ) {
|
||||
a->mFrameNumber ++;
|
||||
}
|
||||
else if( a->mRemoveAtEnd ) {
|
||||
// remove it
|
||||
animationList.deleteElement( i );
|
||||
// back up in list for next loop iteration
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void startPrizeAnimation( int inX, int inY ) {
|
||||
|
||||
Animation a( inX, inY, 16, 16, true, true, prizeAnimationContainer );
|
||||
|
||||
animationList.push_back( a );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void startDustAnimation( int inX, int inY ) {
|
||||
|
||||
Animation a( inX, inY, 16, 16, true, true, dustAnimationContainer );
|
||||
|
||||
animationList.push_back( a );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void startHeartAnimation( int inX, int inY ) {
|
||||
|
||||
Animation a( inX, inY, 16, 16, true, true, heartAnimationContainer );
|
||||
|
||||
animationList.push_back( a );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include <math.h>
|
||||
|
||||
|
||||
void setPlayerPosition( int inX, int inY ) {
|
||||
|
||||
Animation *spriteAnimation =
|
||||
animationList.getElement( spriteAnimationIndex );
|
||||
|
||||
char moving = false;
|
||||
|
||||
if( inX != spriteAnimation->mX ) {
|
||||
moving = true;
|
||||
}
|
||||
|
||||
|
||||
spriteAnimation->mX = inX;
|
||||
// player position centered at sprite's feet
|
||||
int newSpriteY = inY - spriteAnimation->mFrameH / 2 + 1;
|
||||
|
||||
|
||||
if( newSpriteY != spriteAnimation->mY ) {
|
||||
moving = true;
|
||||
}
|
||||
|
||||
spriteAnimation->mY = newSpriteY;
|
||||
|
||||
if( metSpouse && ! spouseDead ) {
|
||||
Animation *spouseAnimation =
|
||||
animationList.getElement( spouseAnimationIndex );
|
||||
|
||||
// spouse stands immediately in front of player
|
||||
int desiredSpouseX = inX + spouseAnimation->mFrameH;
|
||||
int desiredSpouseY = spriteAnimation->mY;
|
||||
|
||||
// gravitates there gradually one pixel at a time in each x and y
|
||||
int dX = desiredSpouseX - spouseAnimation->mX;
|
||||
int dY = desiredSpouseY - spouseAnimation->mY;
|
||||
|
||||
// convert to -1, 0, or +1
|
||||
if( dX != 0 ) {
|
||||
dX = (int)( dX / fabs( dX ) );
|
||||
}
|
||||
if( dY != 0 ) {
|
||||
dY = (int)( dY / fabs( dY ) );
|
||||
}
|
||||
|
||||
if( moving ) {
|
||||
// only execute this transition when player is moving
|
||||
spouseAnimation->mX += dX;
|
||||
spouseAnimation->mY += dY;
|
||||
}
|
||||
|
||||
|
||||
// check for heart animation and have it track moving couple
|
||||
for( int i=0; i<animationList.size(); i++ ) {
|
||||
Animation *a = animationList.getElement( i );
|
||||
|
||||
if( a->mGraphics == heartAnimationContainer ) {
|
||||
|
||||
// move it halfway between player and spouse
|
||||
a->mX = ( spouseAnimation->mX - spriteAnimation->mX ) / 2 +
|
||||
spriteAnimation->mX;
|
||||
a->mY = ( spouseAnimation->mY - spriteAnimation->mY ) / 2 +
|
||||
spriteAnimation->mY + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void setPlayerSpriteFrame( int inFrame ) {
|
||||
Animation *spriteAnimation =
|
||||
animationList.getElement( spriteAnimationIndex );
|
||||
|
||||
spriteAnimation->mFrameNumber = inFrame;
|
||||
|
||||
if( metSpouse && ! spouseDead ) {
|
||||
Animation *spouseAnimation =
|
||||
animationList.getElement( spouseAnimationIndex );
|
||||
|
||||
// spouse follows player
|
||||
spouseAnimation->mFrameNumber = inFrame;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void setCharacterAges( double inAge ) {
|
||||
Animation *spriteAnimation =
|
||||
animationList.getElement( spriteAnimationIndex );
|
||||
Animation *spouseAnimation =
|
||||
animationList.getElement( spouseAnimationIndex );
|
||||
|
||||
// 0 -> 0.25, constant page 0
|
||||
if( inAge <= 0.25 ) {
|
||||
spriteAnimation->mPageNumber = 0;
|
||||
spouseAnimation->mPageNumber = 0;
|
||||
}
|
||||
// 0.75 - 1.0, constant last page
|
||||
else if( inAge >= 0.75 ) {
|
||||
spriteAnimation->mPageNumber = spriteAnimation->mNumPages - 1;
|
||||
spouseAnimation->mPageNumber = spouseAnimation->mNumPages - 1;
|
||||
}
|
||||
else {
|
||||
// blend of pages in between
|
||||
double blendingAge = ( inAge - 0.25 ) / 0.5;
|
||||
|
||||
spriteAnimation->mPageNumber =
|
||||
blendingAge * ( spriteAnimation->mNumPages - 1 );
|
||||
|
||||
spouseAnimation->mPageNumber =
|
||||
blendingAge * ( spouseAnimation->mNumPages - 1 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void getSpousePosition( int *outX, int *outY ) {
|
||||
Animation *spouseAnimation =
|
||||
animationList.getElement( spouseAnimationIndex );
|
||||
|
||||
*outX = spouseAnimation->mX;
|
||||
*outY = spouseAnimation->mY + spouseAnimation->mFrameH / 2 - 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
char haveMetSpouse() {
|
||||
return metSpouse && ! spouseDead;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void meetSpouse() {
|
||||
metSpouse = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void diePlayer() {
|
||||
Animation *spriteAnimation =
|
||||
animationList.getElement( spriteAnimationIndex );
|
||||
|
||||
playerDead = true;
|
||||
|
||||
// tombstone
|
||||
spriteAnimation->mFrameNumber = 8;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void dieSpouse() {
|
||||
Animation *spriteAnimation =
|
||||
animationList.getElement( spriteAnimationIndex );
|
||||
Animation *spouseAnimation =
|
||||
animationList.getElement( spouseAnimationIndex );
|
||||
|
||||
spouseDead = true;
|
||||
|
||||
// tombstone
|
||||
spouseAnimation->mFrameNumber = 8;
|
||||
|
||||
if( metSpouse ) {
|
||||
// swap player sprite with sad sprite
|
||||
spriteAnimation->swapGraphics( spriteSadContainer );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
char isPlayerDead() {
|
||||
return playerDead;
|
||||
}
|
||||
|
||||
|
||||
|
||||
char isSpouseDead() {
|
||||
return spouseDead;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void loadWorldGraphics() {
|
||||
tileContainer = new GraphicContainer( "tileSet.tga" );
|
||||
chestContainer = new GraphicContainer( "chest.tga" );
|
||||
|
||||
spriteContainer = new GraphicContainer( "characterSprite.tga" );
|
||||
spriteSadContainer = new GraphicContainer( "characterSpriteSad.tga" );
|
||||
spouseContainer = new GraphicContainer( "spouseSprite.tga" );
|
||||
|
||||
prizeAnimationContainer = new GraphicContainer( "chestPrize.tga" );
|
||||
dustAnimationContainer = new GraphicContainer( "chestDust.tga" );
|
||||
heartAnimationContainer = new GraphicContainer( "heart.tga" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void destroyWorldGraphics() {
|
||||
delete tileContainer;
|
||||
delete chestContainer;
|
||||
|
||||
delete spriteContainer;
|
||||
delete spriteSadContainer;
|
||||
delete spouseContainer;
|
||||
|
||||
delete prizeAnimationContainer;
|
||||
delete dustAnimationContainer;
|
||||
delete heartAnimationContainer;
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue