CMessie.cpp 7.67 KB
Newer Older
1
#include "CMessie.h"
Gerhard Stein's avatar
Gerhard Stein committed
2
#include <base/CInput.h>
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

// Nessie (in ep3) (on the world map)
enum nessie_actions{
	NESSIE_SWIMNORMAL, NESSIE_PAUSE
};

#define NESSIE_PAUSE_TIME       250

#define NESSIE_ANIM_RATE        4

#define NESSIE_DOWNLEFT_FRAME   130
#define NESSIE_DOWNRIGHT_FRAME  132
#define NESSIE_UPRIGHT_FRAME    134
#define NESSIE_UPLEFT_FRAME     136

#define NESSIE_SPEED            32

void nessie_find_next_checkpoint(int o);

22 23 24
CMessie::CMessie(CMap *p_map, Uint32 x, Uint32 y) :
CVorticonSpriteObject(p_map, x, y, OBJ_MESSIE),
mounted(nullptr)
25
{
Gerhard Stein's avatar
Gerhard Stein committed
26
	xDirection = LEFT, yDirection = DOWN;
27 28
	onscreen = true;
	solid = false;
29

30
	baseframe = NESSIE_DOWNLEFT_FRAME;
31

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
	animframe = 0;
	animtimer = 0;
	state = NESSIE_SWIMNORMAL;
	pausetimer = 0;
	mortimer_swim_amt = 0;
	destx = 0;
	desty = 0;
	inhibitfall = 1;
	canbezapped = 0;

	for(size_t i=0;i<=NESSIETRAILLEN;i++)
	{
		tiletrailX[i] = 0;
		tiletrailY[i] = 0;
	}
	// kick nessie into going counter-clockwise
	// (otherwise she'll go clockwise)
	int mx, my;
	mx = getXPosition()>>CSF;
	my = getYPosition()>>CSF;
	tiletrailX[0] = mx;
	tiletrailY[0] = my;
	tiletrailX[1] = mx+1;
	tiletrailY[1] = my;
	tiletrailhead = 2;
57 58 59 60 61 62 63 64 65 66 67 68
}


void CMessie::getTouchedBy(CVorticonSpriteObject &theObject)
{
    // This is not valid. Only if nessie is mounted or unmounted
    if(CPlayer *Player = dynamic_cast<CPlayer*>(&theObject))
    {
	if (mounted)
	    Player->moveTo(m_Pos);
    }
}
69

70 71
bool CMessie::tryMounting(CPlayer &player)
{
Gerhard Stein's avatar
Gerhard Stein committed
72
    const int dist = 2<<CSF;
73 74 75 76 77 78 79
	const int nessie_x = getXPosition();
	const int nessie_y = getYPosition();
	
	// Look if Messie is nearby
	const int x = player.getXPosition();
	const int y = player.getYPosition();
	
Gerhard Stein's avatar
Gerhard Stein committed
80 81 82 83 84 85 86 87 88 89
    if( x >= nessie_x-dist+m_BBox.x1 and x <= nessie_x+dist+m_BBox.x2 )
    {
        if( y >= nessie_y-dist+m_BBox.y1 and y <= nessie_y+dist+m_BBox.y2 )
        {
            player.solid = false;
            player.beingteleported = true;
            mounted = &player;
            return true;
        }
    }
90
	return false;
91 92
}

93
bool CMessie::tryToUnmount()
94
{
95 96 97 98
    // Unmount part!
    // Check if a NESSIE_LAND_OBJ is nearby the player. Only then he can unmount
    const int x = mounted->getXPosition()>>CSF;
    const int y = mounted->getYPosition()>>CSF;
Gerhard Stein's avatar
Gerhard Stein committed
99
    for(int dy=-2 ; dy <= 2 ; dy++)
100
    {
Gerhard Stein's avatar
Gerhard Stein committed
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
        for(int dx=-2 ; dx <= 2 ; dx++)
        {
            // If NESSIE_LAND_OBJ was found, than put the player there!
            const int infotile = mp_Map->getObjectat(x+dx, y+dy);

            if(infotile == NESSIE_LAND)
            {
                // Look for the Nessie object
                std::vector<CTileProperties> &TileProperty = g_pBehaviorEngine->getTileProperties();
                CTileProperties &Tile = TileProperty[mp_Map->at(x+dx, y+dy)];
                if( !Tile.bdown and !Tile.bup and
                        !Tile.bleft and !Tile.bright )
                {
                    // unmount Messie!
                    mounted->solid = !mounted->godmode;
                    mounted->beingteleported = false;

                    mounted->moveToForce((x+dx)<<CSF, (y+dy)<<CSF);

                    mounted = nullptr;
Gerhard Stein's avatar
Gerhard Stein committed
121
                    gInput.flushAll();
Gerhard Stein's avatar
Gerhard Stein committed
122 123 124 125
                    return true;
                }
            }
        }
126 127 128
    }
    return false;
}
129

130 131
void CMessie::process()
{    
132
    auto &evList = gEventManager;
133
    
Gerhard Stein's avatar
Gerhard Stein committed
134 135
    // TODO: Pump should happens to this object as well.

136
    if( CPlayer::Mount *ev = evList.occurredEvent<CPlayer::Mount>() )
137 138 139 140 141 142 143 144 145 146 147
    {
        // Let's see if he can do that...
        if(tryMounting( const_cast<CPlayer&>(ev->player) ))
        {
            evList.pop_Event();
            // TODO: Create an Event here that hides all the Players
        }
        else
        {
            evList.pop_Event();
        }
148 149 150 151 152 153 154 155 156
    }
    
    // Search for the next where Messie has to swim
    if(destx == 0 && desty == 0)
    {
	nessie_find_next_checkpoint();
    }
    
    // animation
157
	sprite = baseframe + animframe;
158 159 160 161 162 163 164 165 166
	
	// Did player try to mount Messie?
	if (mounted)
	{
	    // Move mounted object with Messie. It still should be hidden at this point.
	    mounted->moveTo(m_Pos);
	    sprite += 8;
	    
	    // If first Player pushes the first button, unmount!
Gerhard Stein's avatar
Gerhard Stein committed
167
        if(gInput.getPressedCommand(IC_JUMP))
168
	    {
Gerhard Stein's avatar
Gerhard Stein committed
169
            tryToUnmount();
Gerhard Stein's avatar
Gerhard Stein committed
170
            gInput.flushAll();
171 172 173
	    }	    
	}
	
174
	if (animtimer > NESSIE_ANIM_RATE)
175
	{
176 177
	    animframe ^= 1;
	    animtimer = 0;
178
	}
179
	else animtimer++;
180
	
181
	switch(state)
182
	{
183
	    case NESSIE_SWIMNORMAL:
184
		// arrived at destination?
185
		if ( getXPosition() > (destx-NESSIE_SPEED/2)  &&
186
		    getXPosition() < (destx+NESSIE_SPEED/2) )
187
		{
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
		    if ( getYPosition() > (desty-NESSIE_SPEED/2)  &&
			getYPosition() < (desty+NESSIE_SPEED/2) )
		    {
			nessie_find_next_checkpoint();
			
			// set up/down and left/right direction flags for frame selection
			bool goleft = (destx < getXPosition());
			bool godown = (desty > getYPosition());
			
			if(goleft && !godown)
			    xDirection = LEFT, yDirection = UP;
			else if(goleft && godown)
			    xDirection = LEFT, yDirection = DOWN;
			else if(!goleft && !godown)
			    xDirection = RIGHT, yDirection = UP;
			else if(!goleft && godown)
			    xDirection = RIGHT, yDirection = DOWN;
		    }
206
		}
207
		move_nessie();
208
		break;
209
	    case NESSIE_PAUSE:
210
		if(pausetimer)
211
		{
212
		    pausetimer--;
213 214 215
		}
		else
		{
216 217
		    state = NESSIE_SWIMNORMAL;
		    move_nessie();
218 219 220 221 222
		}
		break;
	}
}

223
void CMessie::move_nessie()
224 225
{
	// select proper frame based on up/down and left/right direction flags
Gerhard Stein's avatar
Gerhard Stein committed
226
	if (xDirection == LEFT && yDirection == DOWN)
227
		baseframe = NESSIE_DOWNLEFT_FRAME;
Gerhard Stein's avatar
Gerhard Stein committed
228
	else if (xDirection == RIGHT && yDirection == DOWN)
229
		baseframe = NESSIE_DOWNRIGHT_FRAME;
Gerhard Stein's avatar
Gerhard Stein committed
230
	else if (xDirection == LEFT && yDirection == UP)
231
		baseframe = NESSIE_UPLEFT_FRAME;
Gerhard Stein's avatar
Gerhard Stein committed
232
	else if (xDirection == RIGHT && yDirection == UP)
233
		baseframe = NESSIE_UPRIGHT_FRAME;
234 235

	// head to destination
236
	if (getXPosition() < destx)
237
		moveRight(NESSIE_SPEED);
238
	else if (getXPosition() > destx)
239 240
		moveLeft(NESSIE_SPEED);

241
	if (getYPosition() < desty)
242
		moveDown(NESSIE_SPEED);
243
	else if (getYPosition() > desty)
244
		moveUp(NESSIE_SPEED);
245 246
}

247
void CMessie::nessie_find_next_checkpoint()
248
{
249
	int x,y;
250 251 252 253 254 255
	int xa,ya;
	unsigned int destx, desty;

	// search in the 8 surrounding tiles and head to the first pathtile
	// we find that's not one of the last 5 we've been to

256 257
	x = ((getXPosition())>>CSF)-1;
	y = ((getYPosition()+(8<<STC))>>CSF)-1;
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272

	destx = desty = 0;

	for(ya=0;ya<3;ya++)
	{
		for(xa=0;xa<3;xa++)
		{
			destx = x+xa;
			desty = y+ya;

			int obj = mp_Map->getObjectat(destx, desty);
			if (obj==NESSIE_PATH || obj==NESSIE_WEED)
			{
				// find out if this is one of the last tiles we've been to
				bool oneoflasttiles = false;
273
				for(size_t i=0;i<NESSIETRAILLEN;i++)
274
				{
275 276
					if (tiletrailX[i]==destx &&
							tiletrailY[i]==desty)
277 278 279 280 281 282 283 284
					{
						oneoflasttiles = true;
						break;
					}
				}

				if (!oneoflasttiles)
				{
285 286 287 288
					tiletrailX[tiletrailhead] = destx;
					tiletrailY[tiletrailhead] = desty;
					tiletrailhead++;
					if (tiletrailhead>=NESSIETRAILLEN)
289
					{
290
						tiletrailhead = 0;
291 292 293 294 295 296 297 298 299
					}
					goto foundtile;
				} // end if (!oneoflasttiles)
			}  // end if(obj==8192 ...

		} // end for(xa...
	} // end for(ya...

	// If Nessie went to an dead end. Go back!
300
	tiletrailhead = 0;
301 302 303 304
	return;

	foundtile: ;

305 306
	this->destx = (destx<<CSF);
	this->desty = (desty<<CSF)-(8<<STC);
307 308 309 310

	int obj = mp_Map->getObjectat(destx, desty);
	if(obj == NESSIE_WEED || obj == NESSIE_LAND)
	{
311 312
		state = NESSIE_PAUSE;
		pausetimer = NESSIE_PAUSE_TIME;
313 314
	}
}