2 * Copyright 2007-2008 Thomas Gallinari <tg8187@yahoo.fr>
3 * Copyright 2007-2008 Alexandre Galinier <alex.galinier@hotmail.com>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include <KGameDifficulty>
26 const qreal
Ghost::MAX_SPEED_RATIO
= 2.0;
28 Ghost::Ghost(qreal p_x
, qreal p_y
, const QString
& p_imageId
, Maze
* p_maze
) : Character(p_x
, p_y
, p_maze
) {
29 // Initialize the ghost attributes
30 m_imageId
= p_imageId
;
32 m_type
= Element::GHOST
;
33 m_state
= Ghost::HUNTER
;
34 m_maxSpeed
= m_normalSpeed
* MAX_SPEED_RATIO
;
35 // Initialize the random-number generator
37 // Makes the ghost move as soon as the game is created
50 void Ghost::goDown() {
55 void Ghost::goRight() {
60 void Ghost::goLeft() {
65 void Ghost::updateMove() {
66 // Get the current cell coordinates from the character coordinates
67 int curCellRow
= m_maze
->getRowFromY(m_y
);
68 int curCellCol
= m_maze
->getColFromX(m_x
);
69 // Flag to know when the ghost has no choice but go back
70 bool halfTurnRequired
= true;
71 // Contains the different directions a ghost can choose when on a cell center
72 QList
<QPointF
> directionsList
;
75 // If the ghost is not "eaten"
76 if (m_state
!= Ghost::EATEN
) {
77 // If the ghost gets on a Cell center
79 // We retrieve all the directions the ghost can choose (save the turnning back)
80 if (m_maze
->getCell(curCellRow
, curCellCol
+ 1).getType() == Cell::CORRIDOR
||
81 (m_maze
->getCell(curCellRow
, curCellCol
).getType() == Cell::GHOSTCAMP
&&
82 m_maze
->getCell(curCellRow
, curCellCol
+ 1).getType() == Cell::GHOSTCAMP
)) {
84 directionsList
.append(QPointF(m_speed
, 0.0));
85 halfTurnRequired
= false;
88 if (m_maze
->getCell(curCellRow
+ 1, curCellCol
).getType() == Cell::CORRIDOR
||
89 (m_maze
->getCell(curCellRow
, curCellCol
).getType() == Cell::GHOSTCAMP
&&
90 m_maze
->getCell(curCellRow
+ 1, curCellCol
).getType() == Cell::GHOSTCAMP
)) {
92 directionsList
.append(QPointF(0.0, m_speed
));
93 halfTurnRequired
= false;
96 if (m_maze
->getCell(curCellRow
- 1, curCellCol
).getType() == Cell::CORRIDOR
||
97 (m_maze
->getCell(curCellRow
, curCellCol
).getType() == Cell::GHOSTCAMP
&&
98 m_maze
->getCell(curCellRow
- 1, curCellCol
).getType() == Cell::GHOSTCAMP
)) {
100 directionsList
.append(QPointF(0.0, -m_speed
));
101 halfTurnRequired
= false;
104 if (m_maze
->getCell(curCellRow
, curCellCol
- 1).getType() == Cell::CORRIDOR
||
105 (m_maze
->getCell(curCellRow
, curCellCol
).getType() == Cell::GHOSTCAMP
&&
106 m_maze
->getCell(curCellRow
, curCellCol
- 1).getType() == Cell::GHOSTCAMP
)) {
108 directionsList
.append(QPointF(-m_speed
, 0.0));
109 halfTurnRequired
= false;
112 // Random number generation to choose one of the directions
113 nb
= int(double(rand()) / (double(RAND_MAX
) + 1) * directionsList
.size());
114 // If there is no directions in the list, the character goes backward
115 if (directionsList
.size() == 0) {
116 m_xSpeed
= -m_xSpeed
;
117 m_ySpeed
= -m_ySpeed
;
118 } else if ((m_xSpeed
!= 0 && m_xSpeed
!= directionsList
[nb
].x()) ||
119 (m_ySpeed
!= 0 && m_ySpeed
!= directionsList
[nb
].y())) { // If the chosen direction isn't forward
120 // We move the ghost on the center of the cell and update the directions
122 m_xSpeed
= directionsList
[nb
].x();
123 m_ySpeed
= directionsList
[nb
].y();
128 } else { // If the ghost has been eaten
130 // If the ghost has not reached the camp yet
131 if (m_pathToCamp
.size() != 0) {
132 // Go to the next cell to the camp
133 updateMove(m_pathToCamp
.first().y(), m_pathToCamp
.first().x());
134 // Remove the cell the ghost has reached from the path
135 m_pathToCamp
.removeFirst();
137 // If the ghost is not at home (that means it has just been eaten)
138 if (curCellRow
!= m_maze
->getResurrectionCell().y() || curCellCol
!= m_maze
->getResurrectionCell().x()) {
139 // Compute the path to go back to the camp
140 m_pathToCamp
= m_maze
->getPathToGhostCamp(curCellRow
, curCellCol
);
141 if (!m_pathToCamp
.isEmpty()) {
142 updateMove(m_pathToCamp
.first().y(), m_pathToCamp
.first().x());
144 // Set the ghost at home
145 m_x
= m_maze
->getResurrectionCell().x() * Cell::SIZE
+ Cell::SIZE
/ 2;
146 m_y
= m_maze
->getResurrectionCell().y() * Cell::SIZE
+ Cell::SIZE
/ 2;
147 setState(Ghost::HUNTER
);
149 } else { // The ghost has reached the ghost camp
150 setState(Ghost::HUNTER
);
158 void Ghost::updateMove(int p_row
, int p_col
) {
159 // Get the current cell coordinates from the ghost coordinates
160 int curGhostRow
= m_maze
->getRowFromY(m_y
);
161 int curGhostCol
= m_maze
->getColFromX(m_x
);
164 if (curGhostRow
== p_row
) {
165 if (p_col
> curGhostCol
) {
173 if (p_row
> curGhostRow
) {
186 QString
Ghost::getImageId() const {
190 Ghost::State
Ghost::getState() const {
194 void Ghost::setState(Ghost::State p_state
) {
199 m_speed
= m_normalSpeed
/ 2;
203 m_speed
= m_normalSpeed
;
206 emit(stateChanged());
209 void Ghost::doActionOnCollision(Kapman
*) {
215 emit(ghostEaten(this));
223 void Ghost::initSpeedInc() {
224 // Ghosts speed increase when level up
225 if(KGameDifficulty::level() == KGameDifficulty::Easy
) {
226 m_speedIncrease
= Character::LOW_SPEED_INC
;
228 if(KGameDifficulty::level() == KGameDifficulty::Medium
) {
229 m_speedIncrease
= Character::MEDIUM_SPEED_INC
;
231 if(KGameDifficulty::level() == KGameDifficulty::Hard
) {
232 m_speedIncrease
= Character::HIGH_SPEED_INC
;