28#include "ObjectsGhost.h"
30#include "ResourceManager.h"
31#include "MapSearchAStar.h"
32#include "BrainsFactory.h"
35Ghost::Ghost(Sint32 iObjID, Sint32 iMX, Sint32 iMY, GameField* GF) : Actor(iObjID, iMX, iMY, GF)
38 if(iObjID == PME_OBJECT_GHOST_RED)
40 iSpeed = PME_GHOST_START_SPEED;
42 pointScatteringTarget.iX = 25;
43 pointScatteringTarget.iY = -3;
45 else if(iObjID == PME_OBJECT_GHOST_PINK)
47 iSpeed = PME_GHOST_START_SPEED;
48 iGoingOutTrigger = 10;
49 pointScatteringTarget.iX = 2;
50 pointScatteringTarget.iY = -3;
52 else if(iObjID == PME_OBJECT_GHOST_BLUE)
54 iSpeed = PME_GHOST_START_SPEED;
55 iGoingOutTrigger = 20;
56 pointScatteringTarget.iX = 25;
57 pointScatteringTarget.iY = 32;
59 else if(iObjID == PME_OBJECT_GHOST_ORANGE)
61 iSpeed = PME_GHOST_START_SPEED;
62 iGoingOutTrigger = 30;
63 pointScatteringTarget.iX = 0;
64 pointScatteringTarget.iY = 32;
68 Main::Instance().ILogMgr().get()->msg(LML_CRITICAL,
" [Ghost] Ghost ID '%d' unknown, unexpected results!\n", iID);
69 iGoingOutTrigger = -1;
73 pStateInit =
new(std::nothrow) GhostStateInit(
"Init");
74 pStateEvading =
new(std::nothrow) GhostStateEvading(
"Evading");
75 pStateChasing =
new(std::nothrow) GhostStateChasing(
"Chasing");
76 pStateScattering =
new(std::nothrow) GhostStateScattering(
"Scattering");
77 pStateDeath =
new(std::nothrow) GhostStateDeath(
"Death");
80 Main::Instance().ILogMgr().get()->msg(LML_LOW,
" [Ghost] Ghost ID '%d' created.\n", iID);
90 pStateEvading =
nullptr;
92 pStateChasing =
nullptr;
93 delete pStateScattering;
94 pStateScattering =
nullptr;
96 pStateDeath =
nullptr;
98 Main::Instance().ILogMgr().get()->msg(LML_LOW,
" [Ghost] Ghost ID '%d' deleted.\n", iID);
104Sint32 Ghost::execute()
108 if(pCurrentState) pCurrentState->execute(
this);
117#define PME_DEBUG_NUM_GHOST_ATTRIBUTES 6
118Sint32 Ghost::debug(Sint32 iMode)
120 Main &mC64 = Main::Instance();
122 Font* pFont = Main::Instance().IFontMgr().get(ResourceManager::Instance().get(RM_FONT_CONSOLE));
128 Sint32 iDebugStartY = 0;
131 case PME_OBJECT_GHOST_RED:
132 iDebugStartY = PME_DEBUG_PANEL_GHOST_Y + iMazeRenderingY;
134 case PME_OBJECT_GHOST_BLUE:
135 iDebugStartY = PME_DEBUG_PANEL_GHOST_Y + iMazeRenderingY + 1 * ((PME_DEBUG_NUM_GHOST_ATTRIBUTES * 16) + 16);
137 case PME_OBJECT_GHOST_PINK:
138 iDebugStartY = PME_DEBUG_PANEL_GHOST_Y + iMazeRenderingY + 2 * ((PME_DEBUG_NUM_GHOST_ATTRIBUTES * 16) + 16);
140 case PME_OBJECT_GHOST_ORANGE:
141 iDebugStartY = PME_DEBUG_PANEL_GHOST_Y + iMazeRenderingY + 3 * ((PME_DEBUG_NUM_GHOST_ATTRIBUTES * 16) + 16);
146 pFont->setPosition(PME_DEBUG_PANEL_GHOST_X, iDebugStartY);
149 pFont->render(sDebug);
152 mC64.ITool().intToStrDec(iMazeX, sTmp);
153 sDebug =
"Position: [";
156 mC64.ITool().intToStrDec(iMazeY, sTmp);
159 mC64.ITool().intToStrDec(iPositionX, sTmp);
162 mC64.ITool().intToStrDec(iPositionY, sTmp);
165 pFont->setPosition(PME_DEBUG_PANEL_GHOST_X, iDebugStartY + 16);
166 pFont->render(sDebug);
170 mC64.ITool().intToStrDec(iSpeed, sTmp);
171 sDebug += sTmp; sDebug +=
" - GoingOut: ";
172 mC64.ITool().intToStrDec(iGoingOutTrigger, sTmp);
174 pFont->setPosition(PME_DEBUG_PANEL_GHOST_X, iDebugStartY + 32);
175 pFont->render(sDebug);
178 mC64.ITool().intToStrDec(pointTarget.iX, sTmp);
179 sDebug =
"Target: [";
182 mC64.ITool().intToStrDec(pointTarget.iY, sTmp);
185 pFont->setPosition(PME_DEBUG_PANEL_GHOST_X, iDebugStartY + 48);
186 pFont->render(sDebug);
189 pCurrentState->getName(sDebug);
190 sDebug =
"State: " + sDebug;
191 pFont->setPosition(PME_DEBUG_PANEL_GHOST_X, iDebugStartY + 64);
192 pFont->render(sDebug);
195 if(BrainsFactory::Instance().getName(idBrain, sDebug) == -1) sDebug =
"Empty";
196 sDebug =
"Brain: " + sDebug;
197 pFont->setPosition(PME_DEBUG_PANEL_GHOST_X, iDebugStartY + 80);
198 pFont->render(sDebug);
204Sint32 Ghost::msgGoInit()
208 stateChange(pStateInit);
213Sint32 Ghost::msgPelletPowerEaten(Sint32 iX, Sint32 iY)
217 pointEvadingTarget.iX = iX;
218 pointEvadingTarget.iY = iY;
221 if(!stateCurrentCheck(*pStateInit) && !stateCurrentCheck(*pStateDeath)) stateChange(pStateEvading);
230Sint32 Ghost::msgGhostCollision()
233 if(stateCurrentCheck(*pStateDeath))
return 2;
236 if(stateCurrentCheck(*pStateEvading))
238 stateChange(pStateDeath);
247Sint32 Ghost::getScatteringTarget(Sint32& iX, Sint32& iY)
249 iX = pointScatteringTarget.iX;
250 iY = pointScatteringTarget.iY;
259Sint32 Ghost::applyMovementRules(Sint32 iTX, Sint32 iTY)
261 Sint32 i, iSelected = 0;
262 double dLowest = 1000.0f;
263 vector<MazePoint> vMovementOptions;
266 pGameField->getMovementOptions(iMazeX, iMazeY, vMovementOptions);
269 for(i = 0; i < vMovementOptions.size();)
271 if((vMovementOptions[i].iX == iMazePrevX) && (vMovementOptions[i].iY == iMazePrevY))
273 vMovementOptions.erase(vMovementOptions.begin() + i);
279 if(vMovementOptions.size() == 1) iSelected = 0;
285 for(i = 0; i < vMovementOptions.size(); ++i) euclideanDistance(iTX, iTY, vMovementOptions[i]);
286 for(i = 0; i < vMovementOptions.size(); ++i)
288 if(dLowest > vMovementOptions[i].dDistance)
290 dLowest = vMovementOptions[i].dDistance;
297 vPath.push_back(vMovementOptions[iSelected]);
303GhostStateInit::GhostStateInit(
const string& sN) : State(sN) { iTime = 0; }
304void GhostStateInit::enter(Actor* pAct)
306 Ghost* pGhost =
reinterpret_cast<Ghost*
>(pAct);
312 pGhost->eAM = Actor::eActorMoving::AM_NEXT_STEP;
313 pGhost->vPath.clear();
316 iTime = Main::Instance().ITimer().getTicksNow();
317 if(pGhost->statePreviousCheck(*pGhost->pStateDeath)) iTime = iTime - (pGhost->pGameField->messageGetReady(-1) / 4);
319void GhostStateInit::execute(Actor* pAct)
321 Ghost* pGhost =
reinterpret_cast<Ghost*
>(pAct);
325 if(pGhost->eAM == Actor::eActorMoving::AM_DISABLED)
return;
328 if(Main::Instance().ITimer().getTicksNow() < (iTime + pGhost->pGameField->messageGetReady(-1)))
return;
331 if(pGhost->pGameField->getEatenPelletsPercent() < pGhost->iGoingOutTrigger)
334 if(pGhost->vPath.size() == 0)
336 if(pGhost->iMazeX == 11) iTmp = 16;
338 pGhost->pGameField->mapSearch().findPath(pGhost->iMazeX, pGhost->iMazeY, iTmp, 14, pGhost->vPath, PME_STATE_WALKABLE_GHOST);
339 pGhost->pointTarget.iX = iTmp;
340 pGhost->pointTarget.iY = 14;
346 if(pGhost->vPath.size() == 0)
348 pGhost->pGameField->mapSearch().findPath(pGhost->iMazeX, pGhost->iMazeY, 13, 11, pGhost->vPath, PME_STATE_WALKABLE_GHOST);
349 pGhost->pointTarget.iX = 13;
350 pGhost->pointTarget.iY = 11;
354 if(pGhost->iMazeX == 13 && pGhost->iMazeY == 11)
356 pGhost->stateChange(pGhost->pStateChasing);
361GhostStateEvading::GhostStateEvading(
const string& sN) : State(sN) { }
362void GhostStateEvading::enter(Actor* pAct)
364 Ghost* pGhost =
reinterpret_cast<Ghost*
>(pAct);
370 pGhost->iSpeed -= PME_GHOST_SPEED_VARIATION;
373 pGhost->eSS = Actor::eSpriteState::SS_EVADE_FIRST_STAGE;
375void GhostStateEvading::execute(Actor* pAct)
377 Ghost* pGhost =
reinterpret_cast<Ghost*
>(pAct);
378 Sint32 iX, iY, iWaveMode;
381 iWaveMode = pGhost->pGameField->getWaveMode();
382 if((iWaveMode != PME_GLOBAL_WAVE_EVADING) && (iWaveMode != PME_GLOBAL_WAVE_EVADING_END))
385 pGhost->statePrevious();
390 if(iWaveMode == PME_GLOBAL_WAVE_EVADING_END)
393 pGhost->eSS = Actor::eSpriteState::SS_EVADE_SECOND_STAGE;
397 if(pGhost->vPath.size() == 0)
400 iX = Main::Instance().ITool().randWELL() % 6;
401 iX = MAZE_WIDTH - pGhost->pointEvadingTarget.iX + iX - 3;
402 iY = Main::Instance().ITool().randWELL() % 6;
403 iY = MAZE_HEIGHT - pGhost->pointEvadingTarget.iY + iY - 3;
404 pGhost->pGameField->validateMazePosition(iX, iY);
405 pGhost->pGameField->mapSearch().findPath(pGhost->iMazeX, pGhost->iMazeY, iX, iY, pGhost->vPath, PME_STATE_WALKABLE);
406 pGhost->pointTarget.iX = iX;
407 pGhost->pointTarget.iY = iY;
410void GhostStateEvading::exit(Actor* pAct)
412 Ghost* pGhost =
reinterpret_cast<Ghost*
>(pAct);
418 pGhost->iSpeed += PME_GHOST_SPEED_VARIATION;
421 pGhost->eSS = Actor::eSpriteState::SS_DEFAULT;
424 pGhost->eAM = Actor::eActorMoving::AM_NEXT_STEP;
425 pGhost->vPath.clear();
429GhostStateChasing::GhostStateChasing(
const string& sN) : State(sN) { iTX = iTY = iITX = iITY = 0; bGetNewTarget =
true; }
430void GhostStateChasing::enter(Actor* pAct)
435void GhostStateChasing::execute(Actor* pAct)
437 vector<MazePoint> vIntersection;
438 Ghost* pGhost =
reinterpret_cast<Ghost*
>(pAct);
442 if(pGhost->eAM == Actor::eActorMoving::AM_DISABLED)
return;
445 iWaveMode = pGhost->pGameField->getWaveMode();
446 if(iWaveMode == PME_GLOBAL_WAVE_SCATTERING)
448 pGhost->stateChange(pGhost->pStateScattering);
451 else if(iWaveMode == PME_GLOBAL_WAVE_EVADING)
453 pGhost->stateChange(pGhost->pStateEvading);
458 if((pGhost->iMazeX == iTX) && (pGhost->iMazeY == iTY)) bGetNewTarget =
true;
461 pGhost->pGameField->getMovementOptions(pGhost->iMazeX, pGhost->iMazeY, vIntersection);
462 if((vIntersection.size() > 2) && ((pGhost->iMazeX != iITX) || (pGhost->iMazeY != iITY)))
464 iITX = pGhost->iMazeX;
465 iITY = pGhost->iMazeY;
466 bGetNewTarget =
true;
472 pGhost->think(iTX, iTY);
473 pGhost->pointTarget.iX = iTX;
474 pGhost->pointTarget.iY = iTY;
475 bGetNewTarget =
false;
479 if(pGhost->vPath.size() == 0)
481 pGhost->applyMovementRules(iTX, iTY);
484void GhostStateChasing::exit(Actor* pAct)
486 Ghost* pGhost =
reinterpret_cast<Ghost*
>(pAct);
492 pGhost->eAM = Actor::eActorMoving::AM_NEXT_STEP;
493 pGhost->vPath.clear();
497GhostStateScattering::GhostStateScattering(
const string& sN) : State(sN) {}
498void GhostStateScattering::enter(Actor* pAct)
503void GhostStateScattering::execute(Actor* pAct)
506 Ghost* pGhost =
reinterpret_cast<Ghost*
>(pAct);
509 if(pGhost->eAM == Actor::eActorMoving::AM_DISABLED)
return;
512 iWaveMode = pGhost->pGameField->getWaveMode();
513 if(iWaveMode == PME_GLOBAL_WAVE_CHASING)
515 pGhost->stateChange(pGhost->pStateChasing);
518 else if(iWaveMode == PME_GLOBAL_WAVE_EVADING)
520 pGhost->stateChange(pGhost->pStateEvading);
525 if(pGhost->vPath.size() == 0)
527 pGhost->pointTarget = pGhost->pointScatteringTarget;
528 pGhost->applyMovementRules(pGhost->pointScatteringTarget.iX, pGhost->pointScatteringTarget.iY);
531void GhostStateScattering::exit(Actor* pAct)
533 Ghost* pGhost =
reinterpret_cast<Ghost*
>(pAct);
539 pGhost->eAM = Actor::eActorMoving::AM_NEXT_STEP;
540 pGhost->vPath.clear();
544GhostStateDeath::GhostStateDeath(
const string& sN) : State(sN) {}
545void GhostStateDeath::enter(Actor* pAct)
547 Ghost* pGhost =
reinterpret_cast<Ghost*
>(pAct);
553 pGhost->iSpeed = PME_PACMAN_START_SPEED;
556 pGhost->eSS = Actor::eSpriteState::SS_DEATH;
558void GhostStateDeath::execute(Actor* pAct)
560 Ghost* pGhost =
reinterpret_cast<Ghost*
>(pAct);
563 if(pGhost->eAM == Actor::eActorMoving::AM_DISABLED)
return;
566 if(pGhost->vPath.size() == 0)
569 if(pGhost->iMazeX == (pGhost->iStartingPositionX / MAZE_TILE_SIZE) && pGhost->iMazeY == (pGhost->iStartingPositionY / MAZE_TILE_SIZE))
570 pGhost->stateChange(pGhost->pStateInit);
575 pGhost->pointTarget.iX = pGhost->iStartingPositionX / MAZE_TILE_SIZE;
576 pGhost->pointTarget.iY = pGhost->iStartingPositionY / MAZE_TILE_SIZE;
577 pGhost->pGameField->mapSearch().findPath(pGhost->iMazeX, pGhost->iMazeY, pGhost->pointTarget.iX, pGhost->pointTarget.iY, pGhost->vPath, PME_STATE_WALKABLE_GHOST);
581void GhostStateDeath::exit(Actor* pAct)
583 Ghost* pGhost =
reinterpret_cast<Ghost*
>(pAct);
589 pGhost->iSpeed = PME_GHOST_START_SPEED;
592 pGhost->eSS = Actor::eSpriteState::SS_DEFAULT;