⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ghost.cpp

📁 VIGASOCO (VIdeo GAmes SOurce COde) Windows port (v0.01)
💻 CPP
字号:
// Ghost.cpp
//
/////////////////////////////////////////////////////////////////////////////

#include "Ghost.h"
#include "GameState.h"
#include "../Operations.h"
#include "Path.h"
#include "GhostAction.h"
#include "Video.h"
#include "Game.h"

/////////////////////////////////////////////////////////////////////////////
// initialization and cleanup
/////////////////////////////////////////////////////////////////////////////

Ghost::Ghost(GhostIDs ghostId)
{
	id = ghostId;
}

Ghost::~Ghost()
{
}

void Ghost::resetState()
{
	Character::resetState();

	prevOrientation = (Orientation)0;
	actualTilePosX = actualTilePosY = 0;
	prevMovOffsX = prevMovOffsY = 0;
	destTilePosX = destTilePosY = 0;

	movNormalPattern = movPanicPattern = movTunnelPattern = 0;
	state = substate = 0;
	panicMode = false;
	hasToChangeOrientation = false;
}

void Ghost::initState(bool special)
{
	sprite = 0x20;
	color = 2*id + 1;

	if (special){
		posX = 0x00;
		posY = 0x94;
		tilePosX = actualTilePosX = 0x1e;
		tilePosY = actualTilePosY = 0x32;
		movOffsX = prevMovOffsX = 0x01;
		movOffsY = prevMovOffsY = 0x00;
		orientation = prevOrientation = LEFT;
	}
}

/////////////////////////////////////////////////////////////////////////////
// movement
/////////////////////////////////////////////////////////////////////////////

void Ghost::run()
{
	// if it's going for pacman and alive, check if we have to move
	if ((state == 0) && (substate == 1)){
		// 0x1b is set at the tunnels
		if (theGame->CRAM[Video::tilePos2ScreenCoord(actualTilePosX, actualTilePosY)] == 0x1b) {
			// check if we have to move according to the movement bit pattern
			movTunnelPattern = Operations::rotateLeft<UINT32, 32>(movTunnelPattern);
			if ((movTunnelPattern & 0x01) == 0) return;
		} else if (panicMode){
			// check if we have to move according to the movement bit pattern
			movPanicPattern = Operations::rotateLeft<UINT32, 32>(movPanicPattern);
			if ((movPanicPattern & 0x01) == 0) return;
		} else {
			// check if we have to move according to the movement bit pattern
			movNormalPattern = Operations::rotateLeft<UINT32, 32>(movNormalPattern);
			if ((movNormalPattern & 0x01) == 0) return;
		}

		// move
		move();
	}
}

void Ghost::move()
{
	// if we are moving in the Y axis
	if (prevMovOffsY != 0){
		// if we are in the middle of a tile in the Y axis
		if ((posY & 0x07) == 0x04){
			moveMiddle();
		} else {
			moveNoMiddle();
		}
	} else {
		// if we are in the middle of a tile in the X axis
		if ((posX & 0x07) == 0x04){
			moveMiddle();
		} else {
			moveNoMiddle();
		}
	}
}

// updates position and tile position if it's in the middle of a tile
void Ghost::moveMiddle()
{
	bool hasToMove = false;

	// if wraparound has happened or it's going to happen, don't search a better move
	if (!checkWrapAround()){
		if (panicMode){
			// if we're in panic mode, move
			hasToMove = true;
		} else {
			// get CRAM data in tile position
			int data = theGame->CRAM[Video::tilePos2ScreenCoord(tilePosX, tilePosY)];
			// 0x1a is set at ghost home and near pacman initial positions
			if (data != 0x1a) {
				hasToMove = true;
			}
		}
	}

	// check if the ghost has to change it's orientation and act accordingly
	checkOrientationChanges();

	// updates tile position
	tilePosX += movOffsX;
	tilePosY += movOffsY;

	prevMovOffsX = movOffsX;
	prevMovOffsY = movOffsY;

	// keep a copy of the current orientation in case we have to
	// change our orientation before the next move in the middle
	prevOrientation = orientation;

	moveNoMiddle();

	// this need to be executed here because the original game moves after
	// the IRQ. If this is executed where hasToMove is set to true, the ghost
	// sometimes can't detect a wall (especially when data != 0x1a)
	if (hasToMove){
		if (panicMode){
			moveInPanicState();
		} else {
			moveInNormalState();
		}
	}
}

// updates position and tile position if it's not in the middle of a tile
void Ghost::moveNoMiddle()
{
	// moves
	posX += prevMovOffsX;
	posY += prevMovOffsY;

	posX &= 0xff;
	posY &= 0xff;

	// sets destination tile position (used in collision detection)
	Video::pos2TilePos(posX, posY, actualTilePosX, actualTilePosY);
}

void Ghost::moveAtHome()
{
	moveAtHomeAction[substate]->run(this);
}

void Ghost::moveWhenKilled()
{
	moveWhenKilledAction[state]->run(this);
}

void Ghost::moveInPanicState()
{
	// if it's alive, moves randomly
	if (state == 0){
		Path::calcRandomPath(tilePosX, tilePosY, orientation, movOffsX, movOffsY, orientation);
	} else {	// otherwise, go home
		Path::calcPath(tilePosX, tilePosY, orientation, 0x2e, 0x2c, movOffsX, movOffsY, orientation);
	}
}

/////////////////////////////////////////////////////////////////////////////
// animation
/////////////////////////////////////////////////////////////////////////////

void Ghost::selectProperAnimation()
{
	// set panic mode sprite
	sprite = 0x1c + theGame->ghostsAnimationFrame;

	// if the ghost is alive and in panic mode, we're done
	if ((state == 0) && (panicMode)) return;

	// otherwise set ghost sprite in normal or dead state
	sprite = 0x20 + 2*((int)orientation) + theGame->ghostsAnimationFrame;
}

void Ghost::draw()
{
	// draw ghost's sprites
	Sprite spr(posX, posY, sprite, color, flipX, flipY, (theGame->collisionObject == id + 1) ? 1 : 0);
	theGame->sprites.push_back(spr);

	// clear sprite attributes
	flipX = flipY = false;
	priority = 0;
}


/////////////////////////////////////////////////////////////////////////////
// orientation methods
/////////////////////////////////////////////////////////////////////////////

// changes ghost orientation
void Ghost::changeOrientation()
{
	// set the opposite orientation and update movement offsets
	orientation = (Orientation) (prevOrientation ^ 0x02);
	movOffsX = movementOffsets[orientation][0];
	movOffsY = movementOffsets[orientation][1];

	// special case in demo mode
	if (theGame->states[DEMO]->substate == 0x22){
		prevMovOffsX = movOffsX;
		prevMovOffsY = movOffsY;
		prevOrientation = orientation;
	}
}

// checks if the ghost has to change it's orientation (because pacman has eaten a big pill)
void Ghost::checkOrientationChanges()
{
	if (hasToChangeOrientation){
		hasToChangeOrientation = false;

		// change orientation
		changeOrientation();
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -