CPlayerWM.cpp 28.9 KB
Newer Older
1
/*
2
 * CPlayerWM.cpp
3 4 5
 *
 *  Created on: 14.07.2010
 *      Author: gerstrong
6 7
 *
 *  The code for the player when he is shown on the map...
8 9 10
 */

#include "CPlayerWM.h"
11
#include "engine/galaxy/common/ai/CFlag.h"
Gerhard Stein's avatar
Gerhard Stein committed
12
#include <engine/galaxy/ep6/ai/CRope.h>
13
#include "common/CBehaviorEngine.h"
Gerhard Stein's avatar
Gerhard Stein committed
14
#include <base/CInput.h>
15
#include "sdl/sound/CSound.h"
16
#include "CVec.h"
17

18 19
const int TIME_TO_WAVE = 400;

20 21
namespace galaxy {

22
CPlayerWM::CPlayerWM(CMap *pmap,
23 24 25 26 27 28 29
        const Uint16 foeID,
        Uint32 x,
        Uint32 y,
        CInventory &l_Inventory,
        stCheat &Cheatmode,
        const unsigned int actionoffset,
        const int playerID):
30
CPlayerBase(pmap, foeID, x, y,
31 32
		    LEFT,
		    l_Inventory,
33 34
            Cheatmode,
            playerID),
Gerhard Stein's avatar
Gerhard Stein committed
35
m_basesprite(0),
36
m_teleportanibasetile(0),
37
  m_teleportoldtile(0),
Gerhard Stein's avatar
Gerhard Stein committed
38
walkBaseFrame(0),
39 40 41
m_looking_dir(LEFT),
m_animation(0),
m_animation_time(1),
Gerstrong's avatar
Gerstrong committed
42
m_animation_ticker(0),
43
m_cantswim(false),
44
waveTimer(0),
Gerhard Stein's avatar
Gerhard Stein committed
45
swimming(false),
46 47
mUsedGrapplingHook(false),
mounted(false)
48
{
Gerhard Stein's avatar
Gerhard Stein committed
49
	m_ActionBaseOffset = actionoffset;
gerstrong's avatar
gerstrong committed
50

Gerhard Stein's avatar
Gerhard Stein committed
51 52
	CGalaxySpriteObject::setActionForce(0);
	setActionSprite();
Gerhard Stein's avatar
Gerhard Stein committed
53 54

	walkBaseFrame = sprite;
55
	wavingBaseFrame = walkBaseFrame + 22;
gerstrong's avatar
gerstrong committed
56
	swimBaseFrame = walkBaseFrame + 24;
Gerhard Stein's avatar
Gerhard Stein committed
57
	climbBaseFrame = walkBaseFrame + 37;
Gerhard Stein's avatar
Gerhard Stein committed
58
	m_basesprite = walkBaseFrame;
Gerhard Stein's avatar
Gerhard Stein committed
59

Gerhard Stein's avatar
Gerhard Stein committed
60
	performCollisions();
Gerhard Stein's avatar
Gerhard Stein committed
61
	mProcessPtr = &CPlayerWM::processMoving;
62 63
}

64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119

/**
 * Before Keen rides on the foot we get the location where to ride
 */
VectorD2<int> CPlayerWM::fetchFootDestCoord()
{
	VectorD2<int> location1;
	VectorD2<int> location2;
	int coordData;

	const byte *dataPtr = g_pBehaviorEngine->m_ExeFile.getRawData();
	//const byte *dataPtr = g_pBehaviorEngine->m_ExeFile.getDSegPtr(); // only Zeros here!
	//const byte *dataPtr = (byte*) g_pBehaviorEngine->m_ExeFile.getHeaderData();

	memcpy(&coordData, dataPtr+0xDE43, sizeof(int));
	location1.x = coordData & 0xFF;
	memcpy(&coordData, dataPtr+0xDE58, sizeof(int));
	location1.y = coordData & 0xFF;

	memcpy(&coordData, dataPtr+0xDE78, sizeof(int));
	location2.x = coordData & 0xFF;
	memcpy(&coordData, dataPtr+0xDE8C, sizeof(int));
	location2.y = coordData & 0xFF;


	// Check for the first location
	VectorD2<int> vec1;
	VectorD2<int> vec2;

	VectorD2<int> levelCoord;

	levelCoord = getPosition();

	levelCoord.x >>= CSF;
	levelCoord.y >>= CSF;

	vec1.x = levelCoord.x - location1.x;
	vec1.y = levelCoord.y - location1.y;
	vec2.x = levelCoord.x - location2.x;
	vec2.y = levelCoord.y - location2.y;

	const int dist1 = vec1.GetLength2();
	const int dist2 = vec2.GetLength2();

	VectorD2<int> newCoord;

	if(dist2 > dist1)
		newCoord = location2;
	else
		newCoord = location1;

	newCoord.x <<= CSF;
	newCoord.y <<= CSF;
	return newCoord;
}

120 121


Gerhard Stein's avatar
Gerhard Stein committed
122
void CPlayerWM::pumpEvent(const CEvent *evPtr)
123
{
Gerhard Stein's avatar
Gerhard Stein committed
124
    CSpriteObject::pumpEvent(evPtr);
Gerhard Stein's avatar
Gerhard Stein committed
125

126
    // Events for the Player are processed here.
Gerhard Stein's avatar
Gerhard Stein committed
127
    if( const EventPlayerEndLevel* ev = dynamic_cast<const EventPlayerEndLevel*>(evPtr) )
128
    {
129
        gEventManager.flush();
130
        if(ev->who == mSprVar)
131
        {            
132
            if(ev->sucess)
133
            {                
134 135 136 137 138 139
                finishLevel(ev->levelObject);

                if(g_pBehaviorEngine->getEpisode() == 5)
                {
                    // enough fuses broken, in fact of all the fuses levels, except the secret one.
                    // then open the elevator door for the last level!
140 141
                    // NOTE: I'm not sure, if there is a better way to do it.
                    // if you know one, go ahead and improve this!
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
                    if(m_Inventory.Item.fuse_levels_completed >= 4)
                    {
                        // Must happen only once!
                        m_Inventory.Item.fuse_levels_completed = 0;

                        int x = (0x1A)<<CSF; // upper left corner of that elevator
                        int y = (0x37)<<CSF; // on the map

                        // I only will change the closed elevator tiles!
                        const int tileID = mp_Map->getPlaneDataAt(1, x, y);

                        // I only will change the closed elevator tiles!
                        if(tileID == 0x072C)
                        {
                            const int t_ul = tileID+10;
                            const int t_ur = mp_Map->getPlaneDataAt(1, x+(1<<CSF), y) + 10;
                            const int t_ll = mp_Map->getPlaneDataAt(1, x, y+(1<<CSF)) + 10;
                            const int t_lr = mp_Map->getPlaneDataAt(1, x+(1<<CSF), y+(1<<CSF)) + 10;

                            x >>= CSF; y >>= CSF;

                            mp_Map->setTile(x, y, t_ul, true);
                            mp_Map->setTile(x+1, y, t_ur, true);
                            mp_Map->setTile(x, y+1, t_ll, true);
                            mp_Map->setTile(x+1, y+1, t_lr, true);
                        }
                    }
                }
            }
        }
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188

        if(ev->teleport)
        {
            // Find the spot of the teleportation destination
            // TODO: This part is only meant for Episode 5. We should catch exception
            // Whenever another episode tries to trigger this call.
            int x,y;
            mp_Map->findTile( 0x1A, &x, &y, 2);

            const int newX = x<<CSF;
            const int newY = y<<CSF;

            m_Pos.x = newX;
            m_Pos.y = newY;

            m_camera.setPosition(m_Pos);
        }
Gerhard Stein's avatar
Gerhard Stein committed
189
    }
190

191
    else if( const EventPlayerRideFoot* ev = dynamic_cast<const EventPlayerRideFoot*>(evPtr) )
Gerhard Stein's avatar
Gerhard Stein committed
192
    {
193
        gEventManager.flush();
Gerhard Stein's avatar
Gerhard Stein committed
194 195
        finishLevel(ev->levelObject);
        solid = false;
196

Gerhard Stein's avatar
Gerhard Stein committed
197 198
        // Here we need to set the coordinates calculated to where Keen has to go.
        target = fetchFootDestCoord();
199

Gerhard Stein's avatar
Gerhard Stein committed
200 201 202 203 204 205
        // Make Keen ride on the foot
        m_Action.setActionFormat(0x1492);
        setActionSprite();
        mProcessPtr = &CPlayerWM::processRiding;
    }
}
gerstrong's avatar
gerstrong committed
206 207 208



Gerhard Stein's avatar
Gerhard Stein committed
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
/**
 * The main process cycle for the player itself only on the map
 */
void CPlayerWM::process()
{
    if(mp_Map->locked())
        return;

    processInput();

	// Perform animation cycle
	if(m_animation_ticker >= m_animation_time)
	{
		m_animation++;
		m_animation_ticker = 0;
224
	}
Gerhard Stein's avatar
Gerhard Stein committed
225 226 227 228
	else m_animation_ticker++;

	(this->*mProcessPtr)();

229

230
    processCamera();
231 232
}

233 234 235 236 237 238

/*
 * Processes the waving of the player on map here
 */
void CPlayerWM::processWaving()
{
239 240
    if(mounted)
    {
241 242 243 244
        mProcessPtr = &CPlayerWM::processMoving;
        m_basesprite = walkBaseFrame;
        waveTimer = 0;
        return;
245 246
    }
    
247
    waveTimer++;
248 249 250 251


    if( m_playcontrol[PA_Y] != 0 || m_playcontrol[PA_X] != 0 ||
            m_playcontrol[PA_JUMP] || waveTimer >= (TIME_TO_WAVE/4) )
252
    {
253 254 255 256
        mProcessPtr = &CPlayerWM::processMoving;
        m_basesprite = walkBaseFrame;
        waveTimer = 0;
        return;
257
    }
gerstrong's avatar
gerstrong committed
258

259 260
    m_animation_time = 10;
    sprite = m_basesprite;
gerstrong's avatar
gerstrong committed
261
    sprite +=  m_animation%2;
262 263 264 265 266
}




267 268 269
/*
 * Processes the walking of the player on map here
 */
270
void CPlayerWM::processMoving()
271
{
272 273 274
    // Only happens in Keen6 when keening is hanging on the satelite
    if(mounted)
    {
275 276
        sprite = 181;
        return;
277 278 279
    }
    
    
Gerhard Stein's avatar
Gerhard Stein committed
280 281 282
    // Check if the player is swimming or walking and setup the proper speed
    int movespeed;
    if(m_basesprite == swimBaseFrame)
283
        movespeed = 25;
Gerhard Stein's avatar
Gerhard Stein committed
284
    else if(m_basesprite == walkBaseFrame)
285
        movespeed = 50;
Gerhard Stein's avatar
Gerhard Stein committed
286
    else
287
        movespeed = 0;
Gerhard Stein's avatar
Gerhard Stein committed
288 289 290 291 292 293 294
    
    bool walking=false;
    
    bool bleft, bright, bup, bdown;
    
    // This will trigger between swim and walkmode
    checkforSwimming(bleft, bright, bup, bdown);
295 296

    // This will make Keen climb in
Gerhard Stein's avatar
Gerhard Stein committed
297 298
    direction_t climbDir;
    if( checkforClimbing(climbDir) )
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
    {
        // Check if Keen has a hook, but
        if(!mUsedGrapplingHook)
        {
            if(m_Inventory.Item.m_special.ep6.hook > 0)
            {
                m_Inventory.Item.m_special.ep6.hook--;
                mUsedGrapplingHook = true;

                int x = getXMidPos();
                int y = getYMidPos();

                x = x>>CSF; y = y>>CSF;
                x = x<<CSF; y = (y+climbDir)<<CSF;

314
                spawnObj(new CRope(mp_Map, x, y));
315 316 317 318 319
                playSound(SOUND_ROPE_THROW);
            }
            else
            {
                // Tell the player he cannot climb yet
320
                CEventContainer& EventContainer = gEventManager;
321
                EventContainer.add( new EventSendBitmapDialogMsg(
322
                                        gGraphics.getBitmapFromId(29),
Gerhard Stein's avatar
Gerhard Stein committed
323
                                        g_pBehaviorEngine->getString("KEEN_ROPE_REQUIRED"), RIGHT) );
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338

                moveYDir(-(climbDir<<CSF)/2);
            }
        }

        if(mUsedGrapplingHook)
        {
            xDirection = CENTER;
            yDirection = climbDir;
            solid = false;
            mProcessPtr = &CPlayerWM::processClimbing;
            m_basesprite = climbBaseFrame;
            waveTimer = 0;
            return;
        }
Gerhard Stein's avatar
Gerhard Stein committed
339 340 341 342
    }
    
    // In Episode 5 and 6 there are teleporters. Verify those teleporters and elevators
    if(g_pBehaviorEngine->getEpisode() >= 5)
343
        verifyTeleportation();
Gerhard Stein's avatar
Gerhard Stein committed
344 345
    
    // Normal walking
346 347

    if( m_playcontrol[PA_X]<0 && !bleft)
Gerhard Stein's avatar
Gerhard Stein committed
348
    {
349
        if( m_playcontrol[PA_Y] == 0 )
350
            yDirection = 0;
Gerhard Stein's avatar
Gerhard Stein committed
351
	
352 353 354 355
        moveLeft(movespeed);
        walking = true;
        xDirection = LEFT;
        waveTimer = 0;
Gerhard Stein's avatar
Gerhard Stein committed
356
    }
357 358 359
    else if( m_playcontrol[PA_X]>0 && !bright)
    {
        if(m_playcontrol[PA_Y]==0)
360
            yDirection = 0;
Gerhard Stein's avatar
Gerhard Stein committed
361
	
362 363 364 365
        moveRight(movespeed);
        walking = true;
        xDirection = RIGHT;
        waveTimer = 0;
Gerhard Stein's avatar
Gerhard Stein committed
366
    }
367 368
        
    if(m_playcontrol[PA_Y]<0 && !bup)
Gerhard Stein's avatar
Gerhard Stein committed
369
    {
370 371 372 373 374 375 376
        if(m_playcontrol[PA_X]==0)
            xDirection = 0;

        moveUp(movespeed);
        walking = true;
        yDirection = UP;
        waveTimer = 0;
Gerhard Stein's avatar
Gerhard Stein committed
377
    }
378
    else if(m_playcontrol[PA_Y]>0 && !bdown)
Gerhard Stein's avatar
Gerhard Stein committed
379
    {
380 381 382 383 384 385 386
        if(m_playcontrol[PA_X]==0)
            xDirection = 0;

        moveDown(movespeed);
        walking = true;
        yDirection = DOWN;
        waveTimer = 0;
Gerhard Stein's avatar
Gerhard Stein committed
387 388 389 390 391
    }
    
    // In case noclipping was triggered, make it solid, or remove it...
    if(m_Cheatmode.noclipping)
    {
392 393
        solid = !solid;
        m_Cheatmode.noclipping = false;
Gerhard Stein's avatar
Gerhard Stein committed
394 395 396
    }
    
    // perform actions depending on if the jump button was pressed
397
    if( m_playcontrol[PA_JUMP] )
Gerhard Stein's avatar
Gerhard Stein committed
398
    {
399 400 401 402 403 404
        // Get the object
        Uint16 object = mp_Map->getPlaneDataAt(2, getXMidPos(), getYMidPos());
        if(object) // if we found an object
        {
            // start the level
            startLevel(object);
Gerhard Stein's avatar
Gerhard Stein committed
405
            gInput.flushCommands();
406
        }
Gerhard Stein's avatar
Gerhard Stein committed
407 408 409 410 411
    }
    
    // If keen is just walking on the map or swimming in the sea. Do the proper animation for it.
    if(m_basesprite == walkBaseFrame)
    {
412 413 414 415 416 417 418 419 420 421 422
        performWalkingAnimation(walking);
        m_cantswim = false;

        waveTimer++;
        if( waveTimer >= TIME_TO_WAVE)
        {
            mProcessPtr = &CPlayerWM::processWaving;
            m_basesprite = wavingBaseFrame;
            waveTimer = 0;
            return;
        }
Gerhard Stein's avatar
Gerhard Stein committed
423
    }
424
    else if( isSwimming() )
Gerhard Stein's avatar
Gerhard Stein committed
425
    {
426 427 428 429 430 431 432 433
        if(m_Inventory.Item.m_special.ep4.swimsuit)
        {
            performSwimmingAnimation();
        }
        else
        {
            if( !m_cantswim )
            {
434
                CEventContainer& EventContainer = gEventManager;
435 436

                g_pSound->playSound( SOUND_CANT_DO, PLAY_PAUSEALL );
437
                EventContainer.add( new EventSendBitmapDialogMsg(gGraphics.getBitmapFromId(105),
438 439 440 441 442 443
                                                                 g_pBehaviorEngine->getString("CANT_SWIM_TEXT"), LEFT) );

                m_cantswim = true;
            }

        }
Gerhard Stein's avatar
Gerhard Stein committed
444
    }
445 446
}

Gerhard Stein's avatar
Gerhard Stein committed
447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463


void CPlayerWM::processClimbing()
{
    moveYDir(yDirection*30);
    
    sprite = m_basesprite + m_animation%2;

    direction_t climbDir;
    
    if( checkforClimbing(climbDir) )
    {	    	    
	if(yDirection != climbDir)
	{	    
	    mProcessPtr = &CPlayerWM::processMoving;
	    m_basesprite = walkBaseFrame;
	    waveTimer = 0;
Gerhard Stein's avatar
Gerhard Stein committed
464
	    solid = true;
Gerhard Stein's avatar
Gerhard Stein committed
465 466 467 468 469 470 471 472 473
	    moveYDir(-climbDir<<CSF);
	    return;
	}
    }
    
}



474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503
const int RIDE_SPEED = 32;

void CPlayerWM::processRiding()
{
	// Ride while trying to reach the destination coords
	// Move the player to the target
	VectorD2<int> pos(getXPosition(), getYPosition());
	VectorD2<int> vec = target-pos;

	VectorD2<int> vec_norm = vec;

	const int dist_x = abs(vec.x);
	const int dist_y = abs(vec.y);

	if(dist_x != 0)
		vec_norm.x = vec.x/dist_x;
	if(dist_y != 0)
		vec_norm.y = vec.y/dist_y;

	if( dist_x < RIDE_SPEED &&	dist_y < RIDE_SPEED)
	{
		// When he reaches the target. make him visible and start opening the elevator
		moveDir(vec);
		setAction(0);
		mProcessPtr = &CPlayerWM::processMoving;
		solid = true;
	}
	else
	{
		moveDir(vec_norm*RIDE_SPEED);
504
		processActionRoutine();
505 506 507
	}
}

Gerhard Stein's avatar
Gerhard Stein committed
508 509 510 511

void CPlayerWM::verifyTeleportation()
{
	//target -> change it when the touched tile is known
512 513
	int x = getXMidPos();
	int y = getYUpPos();
Gerhard Stein's avatar
Gerhard Stein committed
514 515 516 517 518

	// Check if Keen touches a teleporter or elevator
	const Uint16 object = mp_Map->getPlaneDataAt( 2, x, y );
	if(object < 0xC000 && object > 0x100)
	{
519 520
		x = (x >> CSF);
		y = (y >> CSF);
Gerhard Stein's avatar
Gerhard Stein committed
521 522

		bool isElevator = false;
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538
		
		std::vector<CTileProperties> &Tile = g_pBehaviorEngine->getTileProperties(1);
		Uint16 behav = Tile[mp_Map->at( x, y, 1)].behaviour;
			
		// Elevator are double the size. Check that! Else it must be an teleporter		
		if( behav==33 || behav==34 )
		{		
		  if(object == mp_Map->getPlaneDataAt( 2, (x-1) << CSF, y << CSF ))
		  {
		    isElevator |= true;
		  }
		  if(object == mp_Map->getPlaneDataAt( 2, (x+1) << CSF, y << CSF ))
		  {
		    x = x + 1;
		    isElevator |= true;
		  }
539
		}
Gerhard Stein's avatar
Gerhard Stein committed
540

541 542 543 544 545 546
		x = (x << CSF);
		y = (y << CSF);

		target.x = x;
		target.y = y;

547
		// In that case get the tile where to go and make him move or ...
Gerhard Stein's avatar
Gerhard Stein committed
548
		if(isElevator)
549
		{
Gerhard Stein's avatar
Gerhard Stein committed
550
			mProcessPtr = &CPlayerWM::processEnteringElevator;
551
		}
552 553 554
        else // ... make him move until teleporter hides him.
        {
            mProcessPtr = &CPlayerWM::processEnteringTeleporter;
555

556
            setupTeleportAnimation(false, target);
gerstrong's avatar
gerstrong committed
557

558
            playSound(SOUND_TELEPORT);
559

560 561 562
            solid = false;
        }
    }
Gerhard Stein's avatar
Gerhard Stein committed
563 564 565 566

}


567 568 569 570
// Elevators
const int SLOW_TELEPORT_WALK_SPEED = 8;
const int ELEVATOR_SPEED = 128;
const int ELEVATOR_CLOSE_TIME = 5;
Gerhard Stein's avatar
Gerhard Stein committed
571

Gerhard Stein's avatar
Gerhard Stein committed
572 573
void CPlayerWM::processEnteringElevator()
{
574
	// Move him to the target
575
	VectorD2<int> pos(getXPosition(), getYPosition());
576
	VectorD2<int> vec = target-pos;
577 578 579


	VectorD2<int> vec_norm = vec;
Gerhard Stein's avatar
Gerhard Stein committed
580 581 582 583

	const int dist_x = abs(vec.x);
	const int dist_y = abs(vec.y);

584 585 586 587
	if(dist_x != 0)
		vec_norm.x = vec.x/dist_x;
	if(dist_y != 0)
		vec_norm.y = vec.y/dist_y;
588

589 590 591
	yDirection = vec_norm.y;


Gerhard Stein's avatar
Gerhard Stein committed
592 593 594 595 596
	if( dist_x < SLOW_TELEPORT_WALK_SPEED &&
		dist_y < SLOW_TELEPORT_WALK_SPEED)
	{
		moveDir(vec);
		mProcessPtr = &CPlayerWM::processClosingElevator;
597
		performWalkingAnimation(false);
598 599
		elevator_frames = 5;
		elevator_close_timer = 0;
Gerhard Stein's avatar
Gerhard Stein committed
600
	}
601 602 603 604
	else
	{
		moveDir(vec_norm*SLOW_TELEPORT_WALK_SPEED);
	}
605

Gerhard Stein's avatar
Gerhard Stein committed
606 607 608 609
	performWalkingAnimation(true);
}

void CPlayerWM::processClosingElevator()
610
{
611 612
	const int x = getXMidPos() >> CSF;
	const int y = getYMidPos() >> CSF;
613 614 615 616
	const Uint16 tile1 = mp_Map->getPlaneDataAt( 1, x<<CSF, y<<CSF );
	const Uint16 tile2 = mp_Map->getPlaneDataAt( 1, (x-1)<<CSF, y<<CSF );
	const Uint16 tile3 = mp_Map->getPlaneDataAt( 1, (x-1)<<CSF, (y-1)<<CSF );
	const Uint16 tile4 = mp_Map->getPlaneDataAt( 1, x<<CSF, (y-1)<<CSF );
617 618

	elevator_close_timer++;
619
	if(elevator_close_timer >= ELEVATOR_CLOSE_TIME)
620 621 622 623
	{
		elevator_close_timer = 0;

		// Make the player close the elevator
624 625 626 627
		mp_Map->setTile(x, y, tile1-2, true);
		mp_Map->setTile(x-1, y, tile2-2, true);
		mp_Map->setTile(x-1, y-1, tile3-2, true);
		mp_Map->setTile(x, y-1, tile4-2, true);
gerstrong's avatar
gerstrong committed
628

Gerhard Stein's avatar
Gerhard Stein committed
629
		playSound(SOUND_ELEVATOR_OPEN);
630 631

		elevator_frames--;
632

633 634 635
		if(elevator_frames == 0)
		{
			// If done make him invisible and transport him through the level. !solid
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655

			//target -> change it when the touched tile is known
			const int x = getXMidPos();
			const int y = getYMidPos();

			// Check if Keen touches a teleporter or elevator
			const Uint16 object = mp_Map->getPlaneDataAt( 2, x, y );
			const Uint32 filter = object & 0xFFFF;
			const Uint32 newPosX = (filter & 0xFF00) >> 8;
			const Uint32 newPosY = (filter & 0x00FF);

			// Set new target
			target.x = ((newPosX+1)<<CSF);
			target.y = (newPosY<<CSF);

			// make him invisible
			solid = false;
			dontdraw = true;

			// change process
656 657 658
			mProcessPtr = &CPlayerWM::processElevating;
		}
	}
659
}
Gerhard Stein's avatar
Gerhard Stein committed
660 661

void CPlayerWM::processElevating()
662
{
663 664 665 666 667 668 669 670 671 672 673 674 675 676
	// Move the player to the target
	VectorD2<int> pos(getXPosition(), getYPosition());
	VectorD2<int> vec = target-pos;


	VectorD2<int> vec_norm = vec;

	const int dist_x = abs(vec.x);
	const int dist_y = abs(vec.y);

	if(dist_x != 0)
		vec_norm.x = vec.x/dist_x;
	if(dist_y != 0)
		vec_norm.y = vec.y/dist_y;
677

678 679 680 681 682 683 684 685 686 687 688 689
	if( dist_x < SLOW_TELEPORT_WALK_SPEED &&
		dist_y < SLOW_TELEPORT_WALK_SPEED)
	{
		moveDir(vec);
		mProcessPtr = &CPlayerWM::processOpeningElevator;
		performWalkingAnimation(false);
		elevator_frames = 5;
		elevator_close_timer = 0;
	}
	else
	{
		moveDir(vec_norm*ELEVATOR_SPEED);
Gerhard Stein's avatar
Gerhard Stein committed
690
		playSound(SOUND_ELEVATING);
691
	}
692
}
Gerhard Stein's avatar
Gerhard Stein committed
693 694

void CPlayerWM::processOpeningElevator()
695
{
696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713
	// Open until it's wide open
	const int x = getXMidPos() >> CSF;
	const int y = getYMidPos() >> CSF;
	const Uint16 tile1 = mp_Map->getPlaneDataAt( 1, x<<CSF, y<<CSF );
	const Uint16 tile2 = mp_Map->getPlaneDataAt( 1, (x-1)<<CSF, y<<CSF );
	const Uint16 tile3 = mp_Map->getPlaneDataAt( 1, (x-1)<<CSF, (y-1)<<CSF );
	const Uint16 tile4 = mp_Map->getPlaneDataAt( 1, x<<CSF, (y-1)<<CSF );

	elevator_close_timer++;
	if(elevator_close_timer >= ELEVATOR_CLOSE_TIME)
	{
		elevator_close_timer = 0;

		// Make the player close the elevator
		mp_Map->setTile(x, y, tile1+2, true);
		mp_Map->setTile(x-1, y, tile2+2, true);
		mp_Map->setTile(x-1, y-1, tile3+2, true);
		mp_Map->setTile(x, y-1, tile4+2, true);
gerstrong's avatar
gerstrong committed
714

Gerhard Stein's avatar
Gerhard Stein committed
715
		playSound(SOUND_ELEVATOR_OPEN);
716 717 718 719 720 721 722

		elevator_frames--;

		if(elevator_frames == 0)
		{
			// make him visible
			dontdraw = false;
723

724 725 726 727 728 729
			target.y += (1<<CSF);

			// and walk out
			mProcessPtr = &CPlayerWM::processLeavingElevator;
		}
	}
730
}
Gerhard Stein's avatar
Gerhard Stein committed
731 732

void CPlayerWM::processLeavingElevator()
733
{
734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763
	// Move him to the target
	VectorD2<int> pos(getXPosition(), getYPosition());
	VectorD2<int> vec = target-pos;

	VectorD2<int> vec_norm = vec;

	const int dist_x = abs(vec.x);
	const int dist_y = abs(vec.y);

	if(dist_x != 0)
		vec_norm.x = vec.x/dist_x;
	if(dist_y != 0)
		vec_norm.y = vec.y/dist_y;

	yDirection = vec_norm.y;

	if( dist_x < SLOW_TELEPORT_WALK_SPEED &&
		dist_y < SLOW_TELEPORT_WALK_SPEED)
	{
		// When done set him solid
		solid = true;
		moveDir(vec);
		mProcessPtr = &CPlayerWM::processMoving;
	}
	else
	{
		moveDir(vec_norm*SLOW_TELEPORT_WALK_SPEED);
	}

	performWalkingAnimation(true);
764 765
}

Gerhard Stein's avatar
Gerhard Stein committed
766

767
// Teleporter
Gerhard Stein's avatar
Gerhard Stein committed
768

769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791
void CPlayerWM::setupTeleportAnimation(const bool unset, const VectorD2<int> &pos)
{
    const int x = pos.x;
    const int y = pos.y;
    const int ep = g_pBehaviorEngine->getEpisode();

    if(!unset)
        m_teleportoldtile = mp_Map->getPlaneDataAt( 1, x, y );

    // Depending on having Keen 6 or 5 the animation tiles are a bit different
    if( ep==5 )
    {
        m_teleportanibasetile = unset ? m_teleportoldtile : 0xA7F;
    }
    if( ep==6 )
    {
        m_teleportanibasetile = unset ? m_teleportoldtile : 0xA35;
    }

    mp_Map->setTile(x>>CSF, y>>CSF, m_teleportanibasetile, true);
}


Gerhard Stein's avatar
Gerhard Stein committed
792
void CPlayerWM::processEnteringTeleporter()
gerstrong's avatar
gerstrong committed
793
{
794 795 796 797 798 799 800 801 802 803 804 805 806 807
	// Move him to the target
	VectorD2<int> pos(getXPosition(), getYPosition());
	VectorD2<int> vec = target-pos;


	VectorD2<int> vec_norm = vec;

	const int dist_x = abs(vec.x);
	const int dist_y = abs(vec.y);

	if(dist_x != 0)
		vec_norm.x = vec.x/dist_x;
	if(dist_y != 0)
		vec_norm.y = vec.y/dist_y;
Gerhard Stein's avatar
Gerhard Stein committed
808

809
	yDirection = vec_norm.y;
gerstrong's avatar
gerstrong committed
810

811
    // if Keen reached target
812 813 814 815
	if( dist_x < SLOW_TELEPORT_WALK_SPEED &&
		dist_y < SLOW_TELEPORT_WALK_SPEED)
	{
		moveDir(vec);
gerstrong's avatar
gerstrong committed
816

817
        // If done make him invisible and transport him through the map. !solid
818 819 820 821 822

		//target -> change it when the touched tile is known
		const int x = getXMidPos();
		const int y = getYMidPos();

823 824
        setupTeleportAnimation(true, target);

825 826 827 828
		// Get the destination
		const Uint16 object = mp_Map->getPlaneDataAt( 2, x, y );
		const Uint32 filter = object & 0xFFFF;
		const Uint32 newPosX = (filter & 0xFF00) >> 8;
829
		const Uint32 newPosY = (filter & 0x00FF);                
830 831 832

		// Set new target
		target.x = (newPosX<<CSF);
833
		target.y = (newPosY<<CSF);       
gerstrong's avatar
gerstrong committed
834

835 836 837
		// make him invisible
		solid = false;
		dontdraw = true;
838
		mProcessPtr = &CPlayerWM::processWarpInTeleporter;		
839 840 841 842 843 844 845
		performWalkingAnimation(false);
	}
	else
	{
	  const int x = target.x;
	  const int y = target.y;

846 847 848 849 850
      const int ep = g_pBehaviorEngine->getEpisode();

      // Amount of animation tiles.
      const int teleportAnimTiles = (ep==5) ? 1 : 3;

851
	  Uint16 aniTile = mp_Map->getPlaneDataAt( 1, x, y ) + 1;
gerstrong's avatar
gerstrong committed
852

853
      if(m_teleportanibasetile + teleportAnimTiles < aniTile)
854 855 856
	  {
	    aniTile = m_teleportanibasetile;
	  }
gerstrong's avatar
gerstrong committed
857 858 859

	  mp_Map->setTile(x>>CSF, y>>CSF, aniTile, true);

860 861 862 863
	  moveDir(vec_norm*SLOW_TELEPORT_WALK_SPEED);
	}

	performWalkingAnimation(true);
gerstrong's avatar
gerstrong committed
864

865 866 867 868 869
}


void CPlayerWM::processWarpInTeleporter()
{
870 871 872 873 874
	// Move the player to the target directly
	VectorD2<int> new_pos(target);
	moveToForce(target);
	new_pos.x += ((m_BBox.x2-m_BBox.x1)/2);
	new_pos.y += ((m_BBox.y2-m_BBox.y1)/2);
gerstrong's avatar
gerstrong committed
875 876
	m_camera.setPosition(new_pos);

877 878 879 880
    mp_Map->mGamePlayPos = new_pos;
    mp_Map->calcVisibleArea();
    mp_Map->refreshVisibleArea();

881
	mProcessPtr = &CPlayerWM::processLeavingTeleporter;
882
	playSound(SOUND_TELEPORT);
gerstrong's avatar
gerstrong committed
883

884 885
    setupTeleportAnimation(false, new_pos);

886 887
	target.y += (1<<CSF);
	dontdraw = false;
888 889 890 891
}

void CPlayerWM::processLeavingTeleporter()
{
892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913
	// Move him to the target
	VectorD2<int> pos(getXPosition(), getYPosition());
	VectorD2<int> vec = target-pos;

	VectorD2<int> vec_norm = vec;

	const int dist_x = abs(vec.x);
	const int dist_y = abs(vec.y);

	if(dist_x != 0)
		vec_norm.x = vec.x/dist_x;
	if(dist_y != 0)
		vec_norm.y = vec.y/dist_y;

	yDirection = vec_norm.y;

	if( dist_x < SLOW_TELEPORT_WALK_SPEED &&
		dist_y < SLOW_TELEPORT_WALK_SPEED)
	{
		// When done set him solid
		solid = true;
		moveDir(vec);
gerstrong's avatar
gerstrong committed
914

915 916 917
        VectorD2<int> animTilePos = target;
        animTilePos.y -= (1<<CSF);
        setupTeleportAnimation(true, animTilePos);
918 919 920
		mProcessPtr = &CPlayerWM::processMoving;
	}
	else
921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938
	{        
        const int x = pos.x;
        const int y = pos.y;

        const int ep = g_pBehaviorEngine->getEpisode();

        // Amount of animation tiles.
        const int teleportAnimTiles = (ep==5) ? 1 : 3;

        Uint16 aniTile = mp_Map->getPlaneDataAt( 1, x, y ) + 1;

        if(m_teleportanibasetile + teleportAnimTiles < aniTile)
        {
          aniTile = m_teleportanibasetile;
        }

        mp_Map->setTile(x>>CSF, y>>CSF, aniTile, true);

939 940
		moveDir(vec_norm*SLOW_TELEPORT_WALK_SPEED);
	}
941

gerstrong's avatar
gerstrong committed
942
	performWalkingAnimation(true);
943
}
Gerhard Stein's avatar
Gerhard Stein committed
944 945 946 947




948 949
/**
 * This function will help starting the level for Commander Keen
950
 */
951
void CPlayerWM::startLevel(Uint16 object)
952
{
953 954 955
    int x, y;
    int level = object - 0xC000;
    Uint16 flag_dest = level + 0xF000;
gerstrong's avatar
gerstrong committed
956

957 958 959 960
    const int ep = g_pBehaviorEngine->getEpisode();
    const int shipLevel = (ep < 6) ? 18 : 17;

    if(mp_Map->findTile(flag_dest, &x, &y, 2) || g_pBehaviorEngine->m_option[OPT_LVLREPLAYABILITY].value || level >= shipLevel)
961
    {
962
        gEventManager.add(new EventEnterLevel(object));
963
    }
964 965
}

966 967 968
/*
 *	makes the player finish the level
 */
969
bool CPlayerWM::finishLevel(const int object)
gerstrong's avatar
gerstrong committed
970
{
971 972
	// if a door or other blocker was found remove it
	int x, y;
973
	Uint16 door = object + 0xD000;
974 975 976 977 978 979 980 981
	while(mp_Map->findTile(door, &x, &y, 2))
	{
		// Open blocks in case there are
		mp_Map->setTile( x, y, 0, true, 1);
		mp_Map->setTile( x, y, 0, true, 2);
		mp_Map->redrawAt( x, y);
	}

982
	Uint16 flag_dest = object + 0xF000;
983 984 985
	if(mp_Map->findTile(flag_dest, &x, &y, 2))
	{
		// spawn the flag
986
		const auto episode = g_pBehaviorEngine->getEpisode();
987
		VectorD2<Uint32> src(getXPosition(), getYPosition());
988 989

		// Here we move the coordinates in order get it positioned correctly in the pole
990
        GsSprite &FlagSprite = gGraphics.getSprite(mSprVar,WAVING_BASEFRAME);
991 992 993 994 995

		unsigned int csfX = (x<<CSF);
		unsigned int csfY = (y<<CSF);

		csfX += (6<<STC);
gerstrong's avatar
gerstrong committed
996
		if(episode != 5)
997
		    csfY -= FlagSprite.m_bboxY2;
gerstrong's avatar
gerstrong committed
998

Gerhard Stein's avatar
Gerhard Stein committed
999
		csfY += (2<<STC);
gerstrong's avatar
gerstrong committed
1000

1001
		if(episode == 5)
1002 1003
		{
		    csfX -= (14<<STC);
1004
		    csfY -= (1<<CSF);
1005 1006 1007
		}
		else
		{
gerstrong's avatar
gerstrong committed
1008
		    g_pSound->playSound( SOUND_FLAG_APPEAR );
1009
		}
1010 1011 1012 1013 1014 1015 1016
		
		if(episode == 6)
		{
		    csfX += (1<<STC);
		    csfY += (2<<STC);
		}
		
gerstrong's avatar
gerstrong committed
1017

1018 1019
		VectorD2<Uint32> dst(csfX, csfY);

1020

Gerhard Stein's avatar
Gerhard Stein committed
1021
        CFlag *pFlag = new CFlag(mp_Map, src, dst, mSprVar, true, true);
1022
		spawnObj(pFlag);
gerstrong's avatar
gerstrong committed
1023

1024

1025
		// Mark the tileinfo on the map as level finished!! So player cannot just re-enter. Exception is if replayability is on.
1026
		mp_Map->setTile( x, y, 0, true, 2);
1027 1028

        return true;
gerstrong's avatar
gerstrong committed
1029
	}
1030 1031

    return false;
1032
}
1033

1034 1035 1036 1037
/**
 * This is the function will switch between swim and walk mode
 * Those are the tileproperties to check for
 * 11      Enter water from top	Keen 4
Gerhard Stein's avatar
Gerhard Stein committed
1038
 * 12      Enter water from right Keen 4
1039
 * 13      Enter water from bottom Keen 4
Gerhard Stein's avatar
Gerhard Stein committed
1040
 * 14      Enter water from left Keen 4
1041
 */
Gerstrong's avatar
Gerstrong committed
1042
void CPlayerWM::checkforSwimming(bool &bleft, bool &bright, bool &bup, bool &bdown)
1043 1044 1045 1046
{
	Uint16 left, right, up, down;
	std::vector<CTileProperties> &Tile = g_pBehaviorEngine->getTileProperties(1);

Gerstrong's avatar
Gerstrong committed
1047 1048
	bleft = bright = bup = bdown = false;

1049 1050 1051 1052 1053 1054 1055
	left = Tile[mp_Map->at( getXLeftPos()>>CSF, getYMidPos()>>CSF, 1)].behaviour;
	right = Tile[mp_Map->at( getXRightPos()>>CSF, getYMidPos()>>CSF, 1)].behaviour;
	up = Tile[mp_Map->at( getXMidPos()>>CSF, getYUpPos()>>CSF, 1)].behaviour;
	down = Tile[mp_Map->at( getXMidPos()>>CSF, getYDownPos()>>CSF, 1)].behaviour;

	// from top
	if(up == 11)
Gerstrong's avatar
Gerstrong committed
1056 1057
	{
		bdown = true;
1058
        makeHimSwim(true);
Gerstrong's avatar
Gerstrong committed
1059
	}
1060
	else if(down == 11)
1061
	{
1062
        makeHimSwim(false);
1063
	}
1064 1065 1066

	// from right
	if(right == 12)
Gerstrong's avatar
Gerstrong committed
1067 1068
	{
		bleft = true;
1069
        makeHimSwim(true);
Gerstrong's avatar
Gerstrong committed
1070
	}
1071
	else if(left == 12)
1072
	{
1073
        makeHimSwim(false);
1074
	}
1075 1076 1077

	// from bottom
	if(down == 13)
Gerstrong's avatar
Gerstrong committed
1078 1079
	{
		bup = true;
1080
        makeHimSwim(true);
Gerstrong's avatar
Gerstrong committed
1081
	}
1082
	else if(up == 13)
1083
	{
1084
        makeHimSwim(false);
1085
	}
1086 1087 1088

	// from left
	if(left == 14)
Gerstrong's avatar
Gerstrong committed
1089 1090
	{
		bright = true;
1091
        makeHimSwim(true);
Gerstrong's avatar
Gerstrong committed
1092
	}
1093
	else if(right == 14)
1094
	{
1095
        makeHimSwim(false);
1096
	}
Gerstrong's avatar
Gerstrong committed
1097 1098

	if(m_Inventory.Item.m_special.ep4.swimsuit)
1099
	{
Gerstrong's avatar
Gerstrong committed
1100
		bleft = bright = bup = bdown = false;
1101
	}
1102 1103
}

Gerhard Stein's avatar
Gerhard Stein committed
1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126
bool CPlayerWM::checkforClimbing(direction_t &climbDir)
{
	const int y = getYMidPos();
	const int x = getXMidPos();
	
	const int info = mp_Map->getPlaneDataAt(2, x, y);

	// from top
	if(info == 0x0F)
	{
		climbDir = UP;
		return true;
	}
	else if(info == 0x10)
	{
		climbDir = DOWN;
		return true;
	}
	
	return false;
}


1127 1128 1129 1130 1131
/**
 * This performs the animation when player is walking on the map
 */
void CPlayerWM::performWalkingAnimation(bool walking)
{
1132
	if(xDirection == RIGHT && yDirection == 0)
Gerhard Stein's avatar
Gerhard Stein committed
1133
		sprite = m_basesprite + 1;
1134
	else if(xDirection == 0 && yDirection == UP)
Gerhard Stein's avatar
Gerhard Stein committed
1135
		sprite = m_basesprite + 4;
1136
	else if(xDirection == 0 && yDirection == DOWN)
Gerhard Stein's avatar
Gerhard Stein committed
1137
		sprite = m_basesprite + 7;
Gerhard Stein's avatar
Gerhard Stein committed
1138
	else if(xDirection == RIGHT && yDirection == DOWN)
Gerhard Stein's avatar
Gerhard Stein committed
1139
		sprite = m_basesprite + 10;
Gerhard Stein's avatar
Gerhard Stein committed
1140
	else if(xDirection == LEFT && yDirection == DOWN)
Gerhard Stein's avatar
Gerhard Stein committed
1141
		sprite = m_basesprite + 13;
Gerhard Stein's avatar
Gerhard Stein committed
1142
	else if(xDirection == LEFT && yDirection == UP)
Gerhard Stein's avatar
Gerhard Stein committed
1143
		sprite = m_basesprite + 16;
Gerhard Stein's avatar
Gerhard Stein committed
1144
	else if(xDirection == RIGHT && yDirection == UP)
Gerhard Stein's avatar
Gerhard Stein committed
1145
		sprite = m_basesprite + 19;
1146
	else
Gerhard Stein's avatar
Gerhard Stein committed
1147
		sprite = m_basesprite - 2;
1148 1149 1150 1151

	if(walking)
	{
		m_animation_time = 5;
1152
		sprite +=  m_animation%3;
Gerhard Stein's avatar
Gerhard Stein committed
1153
		playWalkSound();
1154 1155 1156
	}
	else
		sprite +=  2;
gerstrong's avatar
gerstrong committed
1157

1158 1159 1160 1161 1162 1163
	if(swimming)
	{
	    playSound(SOUND_KEEN_SWIM_TO_LAND);
	    swimming = false;
	}

1164 1165
}

1166 1167 1168
/**
 * This performs the animation when player is swimming in water on the map
 */
1169 1170
void CPlayerWM::performSwimmingAnimation()
{
1171
	if(xDirection == RIGHT && yDirection == 0)
1172
		sprite = m_basesprite + 2;
1173
	else if(xDirection == 0 && yDirection == DOWN)
1174
		sprite = m_basesprite + 4;
1175
	else if(xDirection == LEFT && yDirection == 0)
1176
		sprite = m_basesprite + 6;
Gerhard Stein's avatar
Gerhard Stein committed
1177
	else if(xDirection == RIGHT && yDirection == UP)
1178
		sprite = m_basesprite + 8;
Gerhard Stein's avatar
Gerhard Stein committed
1179
	else if(xDirection == RIGHT && yDirection == DOWN)
1180
		sprite = m_basesprite + 10;
Gerhard Stein's avatar
Gerhard Stein committed
1181
	else if(xDirection == LEFT && yDirection == DOWN)
1182
		sprite = m_basesprite + 12;
Gerhard Stein's avatar
Gerhard Stein committed
1183
	else if(xDirection == LEFT && yDirection == UP)
1184
		sprite = m_basesprite + 14;
1185 1186
	else
		sprite = m_basesprite;
gerstrong's avatar
gerstrong committed
1187

1188 1189 1190 1191 1192
	if(!swimming)
	{
	    playSound(SOUND_KEEN_SWIM_TO_LAND);
	    swimming = true;
	}
1193 1194 1195

	m_animation_time = 5;
	sprite +=  m_animation%2;
Gerstrong's avatar
Gerstrong committed
1196

Gerhard Stein's avatar
Gerhard Stein committed
1197
	playSwimSound();
1198 1199
}

1200 1201 1202 1203 1204
void CPlayerWM::setMounted(const bool value)
{
    mounted = value;
}

Gerhard Stein's avatar
Gerhard Stein committed
1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232
void CPlayerWM::processMoveBitDown()
{
    /// Now check the neighboring tile to the down
    const unsigned int x1 = getXPosition()+m_BBox.x1;
    const unsigned int x2 = getXPosition()+m_BBox.x2;
    const unsigned int y2 = getYPosition()+m_BBox.y2;

    if( ( blockedd = checkSolidD(x1, x2, y2) ) == true )
    {
        // additionally if there is a narrow space and the object might fit in, try to move it into that space
        const int xMid = (x1+x2)/2;
        if(checkSolidD(x1, xMid, y2) == false)
        {
            processMoveBitLeft();
        }
        else if(checkSolidD(xMid, x2, y2) == false)
        {
            processMoveBitRight();
        }

        return;
    }

    // if we are here, the tiles aren't blocking us.
    m_Pos.y++;
}


1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247
bool CPlayerWM::isSwimming()
{
    return (m_basesprite == swimBaseFrame);
}

void CPlayerWM::makeHimSwim(const bool value)
{
    if(value)
        m_basesprite = swimBaseFrame;
    else
        m_basesprite = walkBaseFrame;
}



1248

1249
}