diff options
| author | manuel <manuel@mausz.at> | 2011-05-05 00:57:07 +0200 |
|---|---|---|
| committer | manuel <manuel@mausz.at> | 2011-05-05 00:57:07 +0200 |
| commit | ce48af53646cd9e7ec762fc1ac176b3aa620b11d (patch) | |
| tree | f8fbf2cae8c7d0cbac2696a8f4cf94410bfb4928 /pacman-c++/common | |
| parent | e54ccad07e256ba877bd41d70bd358bd0085bd1e (diff) | |
| download | foop-ce48af53646cd9e7ec762fc1ac176b3aa620b11d.tar.gz foop-ce48af53646cd9e7ec762fc1ac176b3aa620b11d.tar.bz2 foop-ce48af53646cd9e7ec762fc1ac176b3aa620b11d.zip | |
- refactorized the whole project and made a few subprojects
- replaced tcp with enet
- added connect dialog
- some smaller bugfixes
Diffstat (limited to 'pacman-c++/common')
48 files changed, 2411 insertions, 0 deletions
diff --git a/pacman-c++/common/actor.cpp b/pacman-c++/common/actor.cpp new file mode 100644 index 0000000..de8d77e --- /dev/null +++ b/pacman-c++/common/actor.cpp | |||
| @@ -0,0 +1,375 @@ | |||
| 1 | #include "actor.h" | ||
| 2 | #include "util.h" | ||
| 3 | #include <QtCore/QPropertyAnimation> | ||
| 4 | #include <QtCore/QVariantAnimation> | ||
| 5 | #include <QDebug> | ||
| 6 | |||
| 7 | static QVariant myBooleanInterpolator(const bool &start, const bool &end, qreal progress) | ||
| 8 | { | ||
| 9 | return (progress == 1.0) ? end : start; | ||
| 10 | } | ||
| 11 | |||
| 12 | Actor::Actor(Color::Color color, bool local, QGraphicsItem *parent) | ||
| 13 | : GameEntity(color, parent), m_direction(Actor::None), m_local(local), m_reset(true), | ||
| 14 | m_wakaPlayer(NULL), m_roundPoints(0), m_gamePoints(0) | ||
| 15 | { | ||
| 16 | m_type = Type; | ||
| 17 | |||
| 18 | /* DON'T set any pixmap here. we've a pixmap in the animation | ||
| 19 | * but we need a sprite for the collision detection | ||
| 20 | */ | ||
| 21 | setSprite(Constants::sprite_margin, Constants::sprite_margin, Constants::field_size.width, Constants::field_size.height); | ||
| 22 | /* higher player "over" lower player */ | ||
| 23 | setZValue(m_color * 10); | ||
| 24 | |||
| 25 | /* rest of the ctor is only for clients */ | ||
| 26 | if (Constants::server) | ||
| 27 | return; | ||
| 28 | |||
| 29 | /* our actor pixmap. created after server part */ | ||
| 30 | m_pix = ":/" + QString("actor%1").arg(Util::floorLog2(color) + 1); | ||
| 31 | |||
| 32 | /* setup icon for player */ | ||
| 33 | m_icon.setPixmap(m_pix); | ||
| 34 | m_icon.setSprite(Constants::sprite_margin, Constants::sprite_margin, Constants::field_size.width, Constants::field_size.height); | ||
| 35 | |||
| 36 | /* setup static images first | ||
| 37 | * they are visible if no animation is running | ||
| 38 | * and will be the first in m_images | ||
| 39 | */ | ||
| 40 | for (int i = 0; i < 5; i++) | ||
| 41 | { | ||
| 42 | PixmapItem *img = new PixmapItem(m_pix, this); | ||
| 43 | m_images.append(img); | ||
| 44 | int x = i * Constants::sprite_offset + Constants::sprite_margin; | ||
| 45 | int y = Actor::None * Constants::sprite_offset + Constants::sprite_margin; | ||
| 46 | img->setSprite(x, y, Constants::field_size.width, Constants::field_size.height); | ||
| 47 | img->setVisible(false); | ||
| 48 | } | ||
| 49 | |||
| 50 | /* setup animation stuff */ | ||
| 51 | qRegisterAnimationInterpolator<bool>(myBooleanInterpolator); | ||
| 52 | m_moving = new QParallelAnimationGroup(this); | ||
| 53 | m_eating.append(NULL); // Actor::None | ||
| 54 | m_eating.append(setupEatingAnimation(Actor::Left)); | ||
| 55 | m_eating.append(setupEatingAnimation(Actor::Right)); | ||
| 56 | m_eating.append(setupEatingAnimation(Actor::Up)); | ||
| 57 | m_eating.append(setupEatingAnimation(Actor::Down)); | ||
| 58 | |||
| 59 | /* dieing animation */ | ||
| 60 | m_dieing = new QSequentialAnimationGroup(this); | ||
| 61 | for (int i = 0; i < 11; i++) | ||
| 62 | { | ||
| 63 | PixmapItem *img = new PixmapItem(m_pix, this); | ||
| 64 | m_images.append(img); | ||
| 65 | int x = i * Constants::sprite_offset + Constants::sprite_margin; | ||
| 66 | int y = 5 * Constants::sprite_offset + Constants::sprite_margin; | ||
| 67 | img->setSprite(x, y, Constants::field_size.width, Constants::field_size.height); | ||
| 68 | img->setVisible(false); | ||
| 69 | |||
| 70 | QPropertyAnimation *fadein = new QPropertyAnimation(img, "visible", m_dieing); | ||
| 71 | fadein->setDuration(0); | ||
| 72 | fadein->setEndValue(true); | ||
| 73 | |||
| 74 | m_dieing->addPause(130); | ||
| 75 | |||
| 76 | QPropertyAnimation *fadeout = new QPropertyAnimation(img, "visible", m_dieing); | ||
| 77 | fadeout->setDuration(0); | ||
| 78 | fadeout->setEndValue(false); | ||
| 79 | } | ||
| 80 | |||
| 81 | /* setup waka sound */ | ||
| 82 | if (local) | ||
| 83 | m_wakaPlayer = new GaplessAudioPlayer(Sound::WakaWaka, 100, this); | ||
| 84 | |||
| 85 | /* make the picture showing the current direction visible */ | ||
| 86 | m_images[m_direction]->setVisible(true); | ||
| 87 | } | ||
| 88 | |||
| 89 | QSequentialAnimationGroup *Actor::setupEatingAnimation(Actor::Movement direction) | ||
| 90 | { | ||
| 91 | QSequentialAnimationGroup *eating = new QSequentialAnimationGroup(this); | ||
| 92 | eating->setLoopCount(-1); | ||
| 93 | for (int i = 0; i < 4; i++) | ||
| 94 | { | ||
| 95 | PixmapItem *img = new PixmapItem(m_pix, this); | ||
| 96 | m_images.append(img); | ||
| 97 | int x = i * Constants::sprite_offset + Constants::sprite_margin; | ||
| 98 | int y = direction * Constants::sprite_offset + Constants::sprite_margin; | ||
| 99 | img->setSprite(x, y, Constants::field_size.width, Constants::field_size.height); | ||
| 100 | img->setVisible(false); | ||
| 101 | |||
| 102 | QPropertyAnimation *fadein = new QPropertyAnimation(img, "visible", eating); | ||
| 103 | fadein->setDuration(0); | ||
| 104 | fadein->setEndValue(true); | ||
| 105 | |||
| 106 | eating->addPause(100); | ||
| 107 | |||
| 108 | QPropertyAnimation *fadeout = new QPropertyAnimation(img, "visible", eating); | ||
| 109 | fadeout->setDuration(0); | ||
| 110 | fadeout->setEndValue(false); | ||
| 111 | |||
| 112 | QPropertyAnimation *move = new QPropertyAnimation(img, "pos", m_moving); | ||
| 113 | move->setDuration(Constants::tick - 30); | ||
| 114 | move->setEndValue(QPoint(0, 0)); | ||
| 115 | } | ||
| 116 | |||
| 117 | return eating; | ||
| 118 | } | ||
| 119 | |||
| 120 | PixmapItem &Actor::icon() | ||
| 121 | { | ||
| 122 | return m_icon; | ||
| 123 | } | ||
| 124 | |||
| 125 | const QString Actor::iconStr() | ||
| 126 | { | ||
| 127 | return QString(":/actor%1icon").arg(Util::floorLog2(m_color) + 1); | ||
| 128 | } | ||
| 129 | |||
| 130 | Actor::Movement Actor::direction() | ||
| 131 | { | ||
| 132 | return m_direction; | ||
| 133 | } | ||
| 134 | |||
| 135 | |||
| 136 | void Actor::setDirection(Movement direction) | ||
| 137 | { | ||
| 138 | m_direction = direction; | ||
| 139 | } | ||
| 140 | |||
| 141 | bool Actor::isLocal() | ||
| 142 | { | ||
| 143 | return m_local; | ||
| 144 | } | ||
| 145 | |||
| 146 | bool Actor::hadReset() | ||
| 147 | { | ||
| 148 | if (!m_reset) | ||
| 149 | return false; | ||
| 150 | m_reset = false; | ||
| 151 | return true; | ||
| 152 | } | ||
| 153 | |||
| 154 | void Actor::reset() | ||
| 155 | { | ||
| 156 | m_reset = true; | ||
| 157 | if (Constants::server) | ||
| 158 | { | ||
| 159 | m_direction = Actor::None; | ||
| 160 | return; | ||
| 161 | } | ||
| 162 | |||
| 163 | stopEating(); | ||
| 164 | m_moving->stop(); | ||
| 165 | setZValue(m_color * 10); | ||
| 166 | m_dieing->stop(); | ||
| 167 | /* hide all pictures */ | ||
| 168 | for (int i = 0; i < m_images.size(); ++i) | ||
| 169 | m_images.at(i)->setVisible(false); | ||
| 170 | |||
| 171 | if (m_eating[m_direction] != NULL) | ||
| 172 | m_eating[m_direction]->stop(); | ||
| 173 | |||
| 174 | m_direction = Actor::None; | ||
| 175 | m_images[m_direction]->setVisible(true); | ||
| 176 | } | ||
| 177 | |||
| 178 | void Actor::move(QPoint newpos) | ||
| 179 | { | ||
| 180 | QPoint oldpos = pos().toPoint(); | ||
| 181 | Actor::Movement direction = Actor::None; | ||
| 182 | if (oldpos.x() - newpos.x() < 0) | ||
| 183 | direction = Actor::Right; | ||
| 184 | else if (oldpos.x() - newpos.x() > 0) | ||
| 185 | direction = Actor::Left; | ||
| 186 | else if (oldpos.y() - newpos.y() < 0) | ||
| 187 | direction = Actor::Down; | ||
| 188 | else if (oldpos.y() - newpos.y() > 0) | ||
| 189 | direction = Actor::Up; | ||
| 190 | move(direction); | ||
| 191 | } | ||
| 192 | |||
| 193 | void Actor::move(Actor::Movement direction) | ||
| 194 | { | ||
| 195 | if (Constants::server) | ||
| 196 | return moveByServer(direction); | ||
| 197 | |||
| 198 | /* stop current animation if direction changed */ | ||
| 199 | if (direction != m_direction) | ||
| 200 | { | ||
| 201 | /* hide all pictures */ | ||
| 202 | for (int i = 0; i < m_images.size(); ++i) | ||
| 203 | m_images.at(i)->setVisible(false); | ||
| 204 | |||
| 205 | if (m_eating[m_direction] != NULL) | ||
| 206 | m_eating[m_direction]->stop(); | ||
| 207 | } | ||
| 208 | |||
| 209 | QPointF endpos = movementToPoint(direction); | ||
| 210 | switch(direction) | ||
| 211 | { | ||
| 212 | case Actor::Left: | ||
| 213 | case Actor::Right: | ||
| 214 | endpos *= Constants::field_size.width; | ||
| 215 | break; | ||
| 216 | case Actor::Up: | ||
| 217 | case Actor::Down: | ||
| 218 | endpos *= Constants::field_size.height; | ||
| 219 | break; | ||
| 220 | case Actor::None: | ||
| 221 | default: | ||
| 222 | break; | ||
| 223 | } | ||
| 224 | |||
| 225 | for(int i = 0; i < m_moving->animationCount(); ++i) | ||
| 226 | { | ||
| 227 | QPropertyAnimation *move = dynamic_cast<QPropertyAnimation *>(m_moving->animationAt(i)); | ||
| 228 | move->setStartValue(QPoint(0, 0) - endpos); | ||
| 229 | } | ||
| 230 | setPos(pos() + endpos); | ||
| 231 | |||
| 232 | /* start new animation if direction changed */ | ||
| 233 | if (direction != m_direction) | ||
| 234 | { | ||
| 235 | if (direction == Actor::None) | ||
| 236 | m_images[m_direction]->setVisible(true); | ||
| 237 | else | ||
| 238 | m_eating[direction]->start(); | ||
| 239 | } | ||
| 240 | |||
| 241 | /* start moving animation */ | ||
| 242 | if (direction != Actor::None) | ||
| 243 | m_moving->start(); | ||
| 244 | |||
| 245 | m_direction = direction; | ||
| 246 | } | ||
| 247 | |||
| 248 | void Actor::moveByServer(Actor::Movement direction) | ||
| 249 | { | ||
| 250 | QPointF endpos = movementToPoint(direction); | ||
| 251 | switch(direction) | ||
| 252 | { | ||
| 253 | case Actor::Left: | ||
| 254 | case Actor::Right: | ||
| 255 | endpos *= Constants::field_size.width; | ||
| 256 | break; | ||
| 257 | case Actor::Up: | ||
| 258 | case Actor::Down: | ||
| 259 | endpos *= Constants::field_size.height; | ||
| 260 | break; | ||
| 261 | case Actor::None: | ||
| 262 | default: | ||
| 263 | break; | ||
| 264 | } | ||
| 265 | setPos(pos() + endpos); | ||
| 266 | m_direction = direction; | ||
| 267 | } | ||
| 268 | |||
| 269 | bool Actor::isMoving() | ||
| 270 | { | ||
| 271 | return (m_moving->state() == QAbstractAnimation::Running); | ||
| 272 | } | ||
| 273 | |||
| 274 | bool Actor::canEat(Actor *other, const QList<Color::Color> &order) | ||
| 275 | { | ||
| 276 | if (other == NULL || order.empty() || m_color == other->color()) | ||
| 277 | return false; | ||
| 278 | |||
| 279 | int idx = order.indexOf(m_color); | ||
| 280 | return (order.at(idx + 1) == other->color()); | ||
| 281 | } | ||
| 282 | |||
| 283 | void Actor::onDie(Actor *other) | ||
| 284 | { | ||
| 285 | other->eatingPacman(); | ||
| 286 | die(); | ||
| 287 | } | ||
| 288 | |||
| 289 | void Actor::die() | ||
| 290 | { | ||
| 291 | if (Constants::server) | ||
| 292 | return; | ||
| 293 | |||
| 294 | reset(); | ||
| 295 | m_images[m_direction]->setVisible(false); | ||
| 296 | setZValue(zValue() * 10); | ||
| 297 | m_dieing->start(); | ||
| 298 | if (m_local) | ||
| 299 | AudioManager::self()->play(Sound::Die); | ||
| 300 | } | ||
| 301 | |||
| 302 | void Actor::eatingFruit() | ||
| 303 | { | ||
| 304 | if (!m_local) | ||
| 305 | return; | ||
| 306 | AudioManager::self()->play(Sound::EatingFruit); | ||
| 307 | } | ||
| 308 | |||
| 309 | void Actor::eatingPacman() | ||
| 310 | { | ||
| 311 | if (!m_local) | ||
| 312 | return; | ||
| 313 | AudioManager::self()->play(Sound::EatingGhost); | ||
| 314 | } | ||
| 315 | |||
| 316 | void Actor::startEating() | ||
| 317 | { | ||
| 318 | if (!m_local || !m_wakaPlayer->isWorking()) | ||
| 319 | return; | ||
| 320 | m_wakaPlayer->play(); | ||
| 321 | } | ||
| 322 | |||
| 323 | void Actor::stopEating() | ||
| 324 | { | ||
| 325 | if (!m_local || !m_wakaPlayer->isWorking()) | ||
| 326 | return; | ||
| 327 | m_wakaPlayer->pause(); | ||
| 328 | } | ||
| 329 | |||
| 330 | unsigned int Actor::getRoundPoints() | ||
| 331 | { | ||
| 332 | return m_roundPoints; | ||
| 333 | } | ||
| 334 | |||
| 335 | unsigned int Actor::getGamePoints() | ||
| 336 | { | ||
| 337 | return m_gamePoints; | ||
| 338 | } | ||
| 339 | |||
| 340 | void Actor::addRoundPoints(unsigned int amount) | ||
| 341 | { | ||
| 342 | m_roundPoints += amount; | ||
| 343 | } | ||
| 344 | |||
| 345 | void Actor::finishRound(bool died) | ||
| 346 | { | ||
| 347 | if (!died) | ||
| 348 | m_gamePoints += m_roundPoints; | ||
| 349 | m_roundPoints = 0; | ||
| 350 | } | ||
| 351 | |||
| 352 | QPoint Actor::movementToPoint(const Actor::Movement direction) | ||
| 353 | { | ||
| 354 | QPoint endpos(0,0); | ||
| 355 | switch (direction) | ||
| 356 | { | ||
| 357 | case Actor::Up: | ||
| 358 | endpos = QPoint(0, -1); | ||
| 359 | break; | ||
| 360 | case Actor::Down: | ||
| 361 | endpos = QPoint(0, 1); | ||
| 362 | break; | ||
| 363 | case Actor::Left: | ||
| 364 | endpos = QPoint(-1, 0); | ||
| 365 | break; | ||
| 366 | case Actor::Right: | ||
| 367 | endpos = QPoint(1, 0); | ||
| 368 | break; | ||
| 369 | case Actor::None: | ||
| 370 | break; | ||
| 371 | default: | ||
| 372 | Q_ASSERT(false); | ||
| 373 | } | ||
| 374 | return endpos; | ||
| 375 | } | ||
diff --git a/pacman-c++/common/actor.h b/pacman-c++/common/actor.h new file mode 100644 index 0000000..c30c62a --- /dev/null +++ b/pacman-c++/common/actor.h | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | #ifndef ACTOR_H | ||
| 2 | #define ACTOR_H | ||
| 3 | |||
| 4 | #include "gameentity.h" | ||
| 5 | #include "constants.h" | ||
| 6 | #include "audio.h" | ||
| 7 | #include <QtCore/QSequentialAnimationGroup> | ||
| 8 | #include <QtCore/QParallelAnimationGroup> | ||
| 9 | #include <QList> | ||
| 10 | |||
| 11 | class Actor | ||
| 12 | : public GameEntity | ||
| 13 | { | ||
| 14 | Q_OBJECT | ||
| 15 | |||
| 16 | public: | ||
| 17 | enum Movement | ||
| 18 | { | ||
| 19 | None = 0, | ||
| 20 | Left, | ||
| 21 | Right, | ||
| 22 | Up, | ||
| 23 | Down, | ||
| 24 | }; | ||
| 25 | |||
| 26 | enum | ||
| 27 | { | ||
| 28 | Type = UserType + Transmission::pacman | ||
| 29 | }; | ||
| 30 | |||
| 31 | Actor(Color::Color color, bool local = false, QGraphicsItem *parent = 0); | ||
| 32 | virtual ~Actor() | ||
| 33 | {}; | ||
| 34 | |||
| 35 | PixmapItem &icon(); | ||
| 36 | const QString iconStr(); | ||
| 37 | Movement direction(); | ||
| 38 | void setDirection(Movement direction); | ||
| 39 | void reset(); | ||
| 40 | bool hadReset(); | ||
| 41 | bool isLocal(); | ||
| 42 | void move(Movement direction); | ||
| 43 | void move(QPoint newpos); | ||
| 44 | bool isMoving(); | ||
| 45 | void die(); | ||
| 46 | void eatingFruit(); | ||
| 47 | void eatingPacman(); | ||
| 48 | void startEating(); | ||
| 49 | void stopEating(); | ||
| 50 | bool canEat(Actor *other, const QList<Color::Color> &order); | ||
| 51 | virtual void onDie(Actor *); | ||
| 52 | |||
| 53 | unsigned int getRoundPoints(); | ||
| 54 | unsigned int getGamePoints(); | ||
| 55 | void addRoundPoints(unsigned int amount); | ||
| 56 | void finishRound(bool died = false); | ||
| 57 | |||
| 58 | static QPoint movementToPoint(const Movement direction); | ||
| 59 | |||
| 60 | private: | ||
| 61 | void moveByServer(Movement direction); | ||
| 62 | QSequentialAnimationGroup *setupEatingAnimation(Actor::Movement direction); | ||
| 63 | |||
| 64 | private: | ||
| 65 | QPixmap m_pix; | ||
| 66 | Movement m_direction; | ||
| 67 | PixmapItem m_icon; | ||
| 68 | bool m_local; | ||
| 69 | bool m_reset; | ||
| 70 | GaplessAudioPlayer *m_wakaPlayer; | ||
| 71 | |||
| 72 | unsigned int m_roundPoints; | ||
| 73 | unsigned int m_gamePoints; | ||
| 74 | |||
| 75 | QList<PixmapItem *> m_images; | ||
| 76 | QList<QSequentialAnimationGroup *> m_eating; | ||
| 77 | QParallelAnimationGroup *m_moving; | ||
| 78 | QSequentialAnimationGroup *m_dieing; | ||
| 79 | }; | ||
| 80 | |||
| 81 | #endif // ACTOR_H | ||
diff --git a/pacman-c++/common/audio.cpp b/pacman-c++/common/audio.cpp new file mode 100644 index 0000000..70cd37e --- /dev/null +++ b/pacman-c++/common/audio.cpp | |||
| @@ -0,0 +1,355 @@ | |||
| 1 | #include "audio.h" | ||
| 2 | #include "constants.h" | ||
| 3 | #include <phonon/AudioOutput> | ||
| 4 | #include <QCoreApplication> | ||
| 5 | #include <QTimer> | ||
| 6 | #include <QFile> | ||
| 7 | #include <QDir> | ||
| 8 | #include <QDebug> | ||
| 9 | |||
| 10 | /* the universe's only audio manager */ | ||
| 11 | AudioManager *AudioManager::m_instance = NULL; | ||
| 12 | bool AudioManager::m_working = false; | ||
| 13 | |||
| 14 | AudioManager::AudioManager() | ||
| 15 | : m_muted(true) | ||
| 16 | { | ||
| 17 | if (Constants::server) | ||
| 18 | { | ||
| 19 | qDebug() << "Server has no sound"; | ||
| 20 | m_players.append(new AudioPlayer(this)); | ||
| 21 | } | ||
| 22 | else | ||
| 23 | { | ||
| 24 | preload(); | ||
| 25 | AudioPlayer *firstplayer = new AudioPlayer(this); | ||
| 26 | firstplayer->test(m_sounds[Sound::WakaWaka]); | ||
| 27 | m_working = firstplayer->m_working; | ||
| 28 | m_players.append(firstplayer); | ||
| 29 | } | ||
| 30 | m_muted = false; | ||
| 31 | } | ||
| 32 | |||
| 33 | AudioManager *AudioManager::self() | ||
| 34 | { | ||
| 35 | if (m_instance == NULL) | ||
| 36 | m_instance = new AudioManager(); | ||
| 37 | return m_instance; | ||
| 38 | } | ||
| 39 | |||
| 40 | bool AudioManager::isWorking() const | ||
| 41 | { | ||
| 42 | return m_working; | ||
| 43 | } | ||
| 44 | |||
| 45 | void AudioManager::setMuted(bool mute) | ||
| 46 | { | ||
| 47 | if (!isWorking()) | ||
| 48 | return; | ||
| 49 | |||
| 50 | if (mute == m_muted) | ||
| 51 | return; | ||
| 52 | |||
| 53 | for(int i = 0; i < m_players.count(); ++i) | ||
| 54 | m_players.at(i)->setMuted(mute); | ||
| 55 | m_muted = mute; | ||
| 56 | emit mutedChanged(mute); | ||
| 57 | } | ||
| 58 | |||
| 59 | bool AudioManager::isMuted() const | ||
| 60 | { | ||
| 61 | return m_muted; | ||
| 62 | } | ||
| 63 | |||
| 64 | void AudioManager::pause() | ||
| 65 | { | ||
| 66 | if (!isWorking()) | ||
| 67 | return; | ||
| 68 | for(int i = 0; i < m_players.count(); ++i) | ||
| 69 | m_players.at(i)->pause(); | ||
| 70 | } | ||
| 71 | |||
| 72 | void AudioManager::stop() | ||
| 73 | { | ||
| 74 | if (!isWorking()) | ||
| 75 | return; | ||
| 76 | for(int i = 0; i < m_players.count(); ++i) | ||
| 77 | m_players.at(i)->stop(); | ||
| 78 | } | ||
| 79 | |||
| 80 | void AudioManager::clear() | ||
| 81 | { | ||
| 82 | if (!isWorking()) | ||
| 83 | return; | ||
| 84 | for(int i = 0; i < m_players.count(); ++i) | ||
| 85 | m_players.at(i)->clear(); | ||
| 86 | } | ||
| 87 | |||
| 88 | void AudioManager::clearQueue() const | ||
| 89 | { | ||
| 90 | if (!isWorking()) | ||
| 91 | return; | ||
| 92 | for(int i = 0; i < m_players.count(); ++i) | ||
| 93 | m_players.at(i)->clearQueue(); | ||
| 94 | } | ||
| 95 | |||
| 96 | AudioPlayer *AudioManager::audioPlayer() | ||
| 97 | { | ||
| 98 | return m_players.at(0); | ||
| 99 | } | ||
| 100 | |||
| 101 | void AudioManager::play(Sound::Type sound, bool wait) | ||
| 102 | { | ||
| 103 | audioPlayer()->play(sound, wait); | ||
| 104 | } | ||
| 105 | |||
| 106 | void AudioManager::enqueue(Sound::Type sound) | ||
| 107 | { | ||
| 108 | if (!isWorking()) | ||
| 109 | return; | ||
| 110 | audioPlayer()->enqueue(Phonon::MediaSource(m_sounds[sound])); | ||
| 111 | } | ||
| 112 | |||
| 113 | void AudioManager::registerAudioPlayer(AudioPlayer *player) | ||
| 114 | { | ||
| 115 | player->setMuted(m_muted); | ||
| 116 | connect(player, SIGNAL(destroyed(QObject *)), this, SLOT(unregisterAudioPlayer_helper(QObject *))); | ||
| 117 | m_players.append(player); | ||
| 118 | } | ||
| 119 | |||
| 120 | void AudioManager::unregisterAudioPlayer(AudioPlayer *player) | ||
| 121 | { | ||
| 122 | disconnect(player, SIGNAL(destroyed(QObject *)), this, SLOT(unregisterAudioPlayer_helper(QObject *))); | ||
| 123 | m_players.removeAll(player); | ||
| 124 | } | ||
| 125 | |||
| 126 | void AudioManager::unregisterAudioPlayer_helper(QObject *player) | ||
| 127 | { | ||
| 128 | unregisterAudioPlayer(static_cast<AudioPlayer *>(player)); | ||
| 129 | } | ||
| 130 | |||
| 131 | void AudioManager::preload() | ||
| 132 | { | ||
| 133 | m_sounds.clear(); | ||
| 134 | QDir sounds(":/sound"); | ||
| 135 | for(unsigned i = 1; i <= sounds.count(); ++i) | ||
| 136 | m_sounds.append(new QFile(QString(":/sound/sound%1").arg(i), this)); | ||
| 137 | } | ||
| 138 | |||
| 139 | QFile *AudioManager::sound(Sound::Type sound) | ||
| 140 | { | ||
| 141 | if (!isWorking()) | ||
| 142 | return NULL; | ||
| 143 | return m_sounds.at(sound); | ||
| 144 | } | ||
| 145 | |||
| 146 | /* --------------------------------------------------------------- */ | ||
| 147 | |||
| 148 | AudioPlayer::AudioPlayer(QObject *parent) | ||
| 149 | : Phonon::MediaObject(parent), m_working(false) | ||
| 150 | { | ||
| 151 | if (!Constants::server) | ||
| 152 | { | ||
| 153 | m_working = AudioManager::m_working; | ||
| 154 | m_output = new Phonon::AudioOutput(Phonon::MusicCategory, this); | ||
| 155 | Phonon::createPath(this, m_output); | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | bool AudioPlayer::isWorking() const | ||
| 160 | { | ||
| 161 | return m_working; | ||
| 162 | } | ||
| 163 | |||
| 164 | void AudioPlayer::setMuted(bool mute) | ||
| 165 | { | ||
| 166 | m_output->setMuted(mute); | ||
| 167 | } | ||
| 168 | |||
| 169 | bool AudioPlayer::isMuted() const | ||
| 170 | { | ||
| 171 | return m_output->isMuted(); | ||
| 172 | } | ||
| 173 | |||
| 174 | void AudioPlayer::setLoop(QFile *sound) | ||
| 175 | { | ||
| 176 | if (!isWorking()) | ||
| 177 | return; | ||
| 178 | |||
| 179 | if (sound == NULL) | ||
| 180 | { | ||
| 181 | disconnect(this, SIGNAL(aboutToFinish()), this, SLOT(loopEnqueue())); | ||
| 182 | return; | ||
| 183 | } | ||
| 184 | |||
| 185 | m_loopsound = sound; | ||
| 186 | connect(this, SIGNAL(aboutToFinish()), this, SLOT(loopEnqueue())); | ||
| 187 | setCurrentSource(Phonon::MediaSource(m_loopsound)); | ||
| 188 | enqueue(Phonon::MediaSource(m_loopsound)); | ||
| 189 | } | ||
| 190 | |||
| 191 | void AudioPlayer::setLoop(Sound::Type sound) | ||
| 192 | { | ||
| 193 | setLoop(AudioManager::self()->sound(sound)); | ||
| 194 | } | ||
| 195 | |||
| 196 | void AudioPlayer::play() | ||
| 197 | { | ||
| 198 | Phonon::MediaObject::play(); | ||
| 199 | } | ||
| 200 | |||
| 201 | void AudioPlayer::play(Sound::Type sound, bool wait) | ||
| 202 | { | ||
| 203 | if (m_working) | ||
| 204 | { | ||
| 205 | setCurrentSource(Phonon::MediaSource(AudioManager::self()->sound(sound))); | ||
| 206 | play(); | ||
| 207 | } | ||
| 208 | else if (wait) | ||
| 209 | { | ||
| 210 | QTimer *timer = new QTimer(this); | ||
| 211 | timer->setSingleShot(true); | ||
| 212 | unsigned int interval = Sound::length[sound]; | ||
| 213 | /* add a small delay server side only */ | ||
| 214 | if (Constants::server) | ||
| 215 | interval += Constants::tick; | ||
| 216 | timer->setInterval(interval); | ||
| 217 | connect(timer, SIGNAL(timeout()), this, SLOT(finished_ex())); | ||
| 218 | timer->start(); | ||
| 219 | } | ||
| 220 | } | ||
| 221 | |||
| 222 | /* this is a simple hack to check if phonon can actually play sounds.. */ | ||
| 223 | void AudioPlayer::test(QFile *testsound) | ||
| 224 | { | ||
| 225 | stop(); | ||
| 226 | m_output->setVolume(0); | ||
| 227 | setCurrentSource(Phonon::MediaSource(testsound)); | ||
| 228 | connect(this, SIGNAL(stateChanged(Phonon::State,Phonon::State)), this, SLOT(stateChanged_ex(Phonon::State,Phonon::State))); | ||
| 229 | play(); | ||
| 230 | |||
| 231 | QTimer timer; | ||
| 232 | timer.setSingleShot(true); | ||
| 233 | connect(&timer, SIGNAL(timeout()), this, SLOT(testFinished())); | ||
| 234 | timer.start(500); | ||
| 235 | while(timer.isActive()) | ||
| 236 | { | ||
| 237 | qApp->processEvents(); | ||
| 238 | Sleeper::msleep(1); | ||
| 239 | } | ||
| 240 | clear(); | ||
| 241 | } | ||
| 242 | |||
| 243 | void AudioPlayer::finished_ex() | ||
| 244 | { | ||
| 245 | emit finished(); | ||
| 246 | } | ||
| 247 | |||
| 248 | void AudioPlayer::stateChanged_ex(Phonon::State newstate, Phonon::State /* oldstate */) | ||
| 249 | { | ||
| 250 | if (newstate != Phonon::ErrorState) | ||
| 251 | { | ||
| 252 | m_working = true; | ||
| 253 | m_output->setVolume(1); | ||
| 254 | qDebug() << "Sound is working for you!"; | ||
| 255 | } | ||
| 256 | disconnect(this, SIGNAL(stateChanged(Phonon::State, Phonon::State)), this, SLOT(stateChanged_ex(Phonon::State, Phonon::State))); | ||
| 257 | stop(); | ||
| 258 | } | ||
| 259 | |||
| 260 | void AudioPlayer::testFinished() | ||
| 261 | { | ||
| 262 | if (!m_working) | ||
| 263 | qWarning() << "There's no sound for you :("; | ||
| 264 | disconnect(this, SIGNAL(stateChanged(Phonon::State, Phonon::State)), this, SLOT(stateChanged_ex(Phonon::State, Phonon::State))); | ||
| 265 | } | ||
| 266 | |||
| 267 | void AudioPlayer::loopEnqueue() | ||
| 268 | { | ||
| 269 | enqueue(Phonon::MediaSource(m_loopsound)); | ||
| 270 | } | ||
| 271 | |||
| 272 | /* --------------------------------------------------------------- */ | ||
| 273 | |||
| 274 | GaplessAudioPlayer::GaplessAudioPlayer(Sound::Type sound, qint32 mark, QObject *parent) | ||
| 275 | : QObject(parent), m_sound(sound) | ||
| 276 | { | ||
| 277 | m_working = AudioManager::m_working; | ||
| 278 | if (!m_working) | ||
| 279 | return; | ||
| 280 | |||
| 281 | m_player1 = new AudioPlayer(this); | ||
| 282 | m_player2 = new AudioPlayer(this); | ||
| 283 | |||
| 284 | m_player2->setPrefinishMark(mark); | ||
| 285 | m_player1->setPrefinishMark(mark); | ||
| 286 | |||
| 287 | connect(m_player1, SIGNAL(prefinishMarkReached(qint32)), this, SLOT(startPlayer2())); | ||
| 288 | connect(m_player2, SIGNAL(prefinishMarkReached(qint32)), this, SLOT(startPlayer1())); | ||
| 289 | |||
| 290 | AudioManager::self()->registerAudioPlayer(m_player1); | ||
| 291 | AudioManager::self()->registerAudioPlayer(m_player2); | ||
| 292 | } | ||
| 293 | |||
| 294 | bool GaplessAudioPlayer::isWorking() const | ||
| 295 | { | ||
| 296 | return m_working; | ||
| 297 | } | ||
| 298 | |||
| 299 | void GaplessAudioPlayer::setMuted(bool mute) | ||
| 300 | { | ||
| 301 | if (!m_working) | ||
| 302 | return; | ||
| 303 | m_player1->setMuted(mute); | ||
| 304 | m_player2->setMuted(mute); | ||
| 305 | } | ||
| 306 | |||
| 307 | bool GaplessAudioPlayer::isMuted() const | ||
| 308 | { | ||
| 309 | return m_player1->isMuted() && m_player2->isMuted(); | ||
| 310 | } | ||
| 311 | |||
| 312 | void GaplessAudioPlayer::play() | ||
| 313 | { | ||
| 314 | if (!m_working) | ||
| 315 | return; | ||
| 316 | if (m_player1->state() != Phonon::PlayingState && m_player2->state() != Phonon::PlayingState) | ||
| 317 | startPlayer1(); | ||
| 318 | } | ||
| 319 | |||
| 320 | void GaplessAudioPlayer::pause() | ||
| 321 | { | ||
| 322 | if (!m_working) | ||
| 323 | return; | ||
| 324 | if (m_player1->state() != Phonon::PausedState) | ||
| 325 | m_player1->pause(); | ||
| 326 | if (m_player2->state() != Phonon::PausedState) | ||
| 327 | m_player2->pause(); | ||
| 328 | } | ||
| 329 | |||
| 330 | void GaplessAudioPlayer::startPlayer1() | ||
| 331 | { | ||
| 332 | m_player1->play(m_sound); | ||
| 333 | } | ||
| 334 | |||
| 335 | void GaplessAudioPlayer::startPlayer2() | ||
| 336 | { | ||
| 337 | m_player2->play(m_sound); | ||
| 338 | } | ||
| 339 | |||
| 340 | /* --------------------------------------------------------------- */ | ||
| 341 | |||
| 342 | void AudioPlayer::Sleeper::sleep(unsigned long secs) | ||
| 343 | { | ||
| 344 | QThread::sleep(secs); | ||
| 345 | } | ||
| 346 | |||
| 347 | void AudioPlayer::Sleeper::msleep(unsigned long msecs) | ||
| 348 | { | ||
| 349 | QThread::msleep(msecs); | ||
| 350 | } | ||
| 351 | |||
| 352 | void AudioPlayer::Sleeper::usleep(unsigned long usecs) | ||
| 353 | { | ||
| 354 | QThread::usleep(usecs); | ||
| 355 | } | ||
diff --git a/pacman-c++/common/audio.h b/pacman-c++/common/audio.h new file mode 100644 index 0000000..6aec42d --- /dev/null +++ b/pacman-c++/common/audio.h | |||
| @@ -0,0 +1,148 @@ | |||
| 1 | #ifndef AUDIO_H | ||
| 2 | #define AUDIO_H | ||
| 3 | |||
| 4 | #include <QObject> | ||
| 5 | #include <QList> | ||
| 6 | #include <QFile> | ||
| 7 | #include <QThread> | ||
| 8 | #include <phonon/MediaObject> | ||
| 9 | |||
| 10 | namespace Phonon | ||
| 11 | { | ||
| 12 | class AudioOutput; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Sound | ||
| 16 | { | ||
| 17 | enum Type | ||
| 18 | { | ||
| 19 | Intro = 0, | ||
| 20 | WakaWaka, | ||
| 21 | EatingFruit, | ||
| 22 | EatingGhost, | ||
| 23 | Die, | ||
| 24 | Ambient | ||
| 25 | }; | ||
| 26 | |||
| 27 | const unsigned int length[] = { | ||
| 28 | 4310, 2090, 570, 570, 1720, | ||
| 29 | }; | ||
| 30 | }; | ||
| 31 | |||
| 32 | /* --------------------------------------------------------------- */ | ||
| 33 | |||
| 34 | class AudioPlayer | ||
| 35 | : public Phonon::MediaObject | ||
| 36 | { | ||
| 37 | Q_OBJECT | ||
| 38 | friend class AudioManager; | ||
| 39 | |||
| 40 | private: | ||
| 41 | class Sleeper | ||
| 42 | : public QThread | ||
| 43 | { | ||
| 44 | public: | ||
| 45 | static void sleep(unsigned long secs); | ||
| 46 | static void msleep(unsigned long msecs); | ||
| 47 | static void usleep(unsigned long usecs); | ||
| 48 | }; | ||
| 49 | |||
| 50 | public: | ||
| 51 | AudioPlayer(QObject *parent = 0); | ||
| 52 | bool isWorking() const; | ||
| 53 | void setMuted(bool mute = true); | ||
| 54 | bool isMuted() const; | ||
| 55 | void setLoop(Sound::Type sound); | ||
| 56 | void play(); | ||
| 57 | void play(Sound::Type sound, bool wait = false); | ||
| 58 | |||
| 59 | protected: | ||
| 60 | void test(QFile *testsound); | ||
| 61 | void setLoop(QFile *sound); | ||
| 62 | |||
| 63 | public slots: | ||
| 64 | void loopEnqueue(); | ||
| 65 | |||
| 66 | protected slots: | ||
| 67 | void finished_ex(); | ||
| 68 | void testFinished(); | ||
| 69 | void stateChanged_ex(Phonon::State newstate, Phonon::State oldstate); | ||
| 70 | |||
| 71 | protected: | ||
| 72 | bool m_working; | ||
| 73 | QFile *m_loopsound; | ||
| 74 | Phonon::AudioOutput *m_output; | ||
| 75 | }; | ||
| 76 | |||
| 77 | /* --------------------------------------------------------------- */ | ||
| 78 | |||
| 79 | class GaplessAudioPlayer | ||
| 80 | : public QObject | ||
| 81 | { | ||
| 82 | Q_OBJECT | ||
| 83 | |||
| 84 | public: | ||
| 85 | GaplessAudioPlayer(Sound::Type sound, qint32 mark, QObject *parent = 0); | ||
| 86 | bool isWorking() const; | ||
| 87 | void setMuted(bool mute = true); | ||
| 88 | bool isMuted() const; | ||
| 89 | void play(); | ||
| 90 | void pause(); | ||
| 91 | |||
| 92 | protected slots: | ||
| 93 | void startPlayer1(); | ||
| 94 | void startPlayer2(); | ||
| 95 | |||
| 96 | protected: | ||
| 97 | bool m_working; | ||
| 98 | Sound::Type m_sound; | ||
| 99 | AudioPlayer *m_player1; | ||
| 100 | AudioPlayer *m_player2; | ||
| 101 | }; | ||
| 102 | |||
| 103 | /* --------------------------------------------------------------- */ | ||
| 104 | |||
| 105 | class AudioManager | ||
| 106 | : public QObject | ||
| 107 | { | ||
| 108 | Q_OBJECT | ||
| 109 | friend class AudioPlayer; | ||
| 110 | friend class GaplessAudioPlayer; | ||
| 111 | |||
| 112 | public: | ||
| 113 | AudioManager(); | ||
| 114 | static AudioManager *self(); | ||
| 115 | bool isWorking() const; | ||
| 116 | void setMuted(bool mute = true); | ||
| 117 | bool isMuted() const; | ||
| 118 | void pause(); | ||
| 119 | void stop(); | ||
| 120 | void clear(); | ||
| 121 | void clearQueue() const; | ||
| 122 | |||
| 123 | AudioPlayer *audioPlayer(); | ||
| 124 | void play(Sound::Type sound, bool wait = false); | ||
| 125 | void enqueue(Sound::Type sound); | ||
| 126 | |||
| 127 | void registerAudioPlayer(AudioPlayer *player); | ||
| 128 | void unregisterAudioPlayer(AudioPlayer *player); | ||
| 129 | |||
| 130 | signals: | ||
| 131 | void mutedChanged(bool muted); | ||
| 132 | |||
| 133 | private slots: | ||
| 134 | void unregisterAudioPlayer_helper(QObject *player); | ||
| 135 | |||
| 136 | private: | ||
| 137 | void preload(); | ||
| 138 | QFile *sound(Sound::Type sound); | ||
| 139 | |||
| 140 | private: | ||
| 141 | bool m_muted; | ||
| 142 | static bool m_working; | ||
| 143 | static AudioManager *m_instance; | ||
| 144 | QList<QFile *> m_sounds; | ||
| 145 | QList<AudioPlayer *> m_players; | ||
| 146 | }; | ||
| 147 | |||
| 148 | #endif // AUDIOPLAYER_H | ||
diff --git a/pacman-c++/common/block.cpp b/pacman-c++/common/block.cpp new file mode 100644 index 0000000..7f9dd14 --- /dev/null +++ b/pacman-c++/common/block.cpp | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | #include "block.h" | ||
| 2 | #include "constants.h" | ||
| 3 | #include "actor.h" | ||
| 4 | #include "util.h" | ||
| 5 | #include <QtDebug> | ||
| 6 | |||
| 7 | QMap<Color::Color, QPixmap> Block::m_pixmaps; | ||
| 8 | |||
| 9 | Block::Block(Color::Color color, unsigned int neighbours, QGraphicsItem *parent) | ||
| 10 | : GameEntity(color, parent), m_neighbours(neighbours) | ||
| 11 | { | ||
| 12 | m_type = Type; | ||
| 13 | |||
| 14 | /* empty object for servers */ | ||
| 15 | if (Constants::server) | ||
| 16 | return; | ||
| 17 | |||
| 18 | if (m_pixmaps.find(color) == m_pixmaps.end()) | ||
| 19 | { | ||
| 20 | unsigned int colid = (color == Color::none) ? 0 : Util::floorLog2(color) + 1; | ||
| 21 | QString pixmapName = ":/" + QString("block%1").arg(colid); | ||
| 22 | m_pixmaps[color] = QPixmap(pixmapName); | ||
| 23 | } | ||
| 24 | setPixmap(m_pixmaps.find(color).value()); | ||
| 25 | setNeighbours(m_neighbours); | ||
| 26 | } | ||
| 27 | |||
| 28 | unsigned int Block::neighbours() | ||
| 29 | { | ||
| 30 | return m_neighbours; | ||
| 31 | } | ||
| 32 | |||
| 33 | void Block::setNeighbours(unsigned int neighbours) | ||
| 34 | { | ||
| 35 | m_neighbours = neighbours; | ||
| 36 | setSprite(neighbours * Constants::sprite_offset, 0, Constants::field_size.width, Constants::field_size.height); | ||
| 37 | } | ||
| 38 | |||
| 39 | bool Block::checkEnter(Actor * /* actor */) | ||
| 40 | { | ||
| 41 | if (m_color == Color::none) | ||
| 42 | return false; | ||
| 43 | return true; | ||
| 44 | } | ||
| 45 | |||
| 46 | GameEntity::EnteredState Block::enter(Actor *actor) | ||
| 47 | { | ||
| 48 | if (m_color != Color::none && m_color != actor->color()) | ||
| 49 | return DestroyedActor; | ||
| 50 | return Nothing; | ||
| 51 | } | ||
| 52 | |||
| 53 | void Block::onDie(Actor *actor) | ||
| 54 | { | ||
| 55 | actor->die(); | ||
| 56 | } | ||
diff --git a/pacman-c++/common/block.h b/pacman-c++/common/block.h new file mode 100644 index 0000000..abfbc5a --- /dev/null +++ b/pacman-c++/common/block.h | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | #ifndef BLOCK_H | ||
| 2 | #define BLOCK_H | ||
| 3 | |||
| 4 | #include "gameentity.h" | ||
| 5 | #include "constants.h" | ||
| 6 | #include <QMap> | ||
| 7 | |||
| 8 | class Block | ||
| 9 | : public GameEntity | ||
| 10 | { | ||
| 11 | public: | ||
| 12 | enum Neighbour | ||
| 13 | { | ||
| 14 | None = 0, | ||
| 15 | Left = (1 << 0), | ||
| 16 | Right = (1 << 1), | ||
| 17 | Up = (1 << 2), | ||
| 18 | Down = (1 << 3) | ||
| 19 | }; | ||
| 20 | |||
| 21 | enum | ||
| 22 | { | ||
| 23 | Type = UserType + Transmission::block | ||
| 24 | }; | ||
| 25 | |||
| 26 | public: | ||
| 27 | Block(Color::Color color, unsigned int neighbours = None, QGraphicsItem *parent = 0); | ||
| 28 | virtual ~Block() | ||
| 29 | {}; | ||
| 30 | |||
| 31 | unsigned int neighbours(); | ||
| 32 | void setNeighbours(unsigned int neighbours); | ||
| 33 | virtual bool checkEnter(Actor *actor); | ||
| 34 | virtual EnteredState enter(Actor *actor); | ||
| 35 | virtual void onDie(Actor *); | ||
| 36 | |||
| 37 | private: | ||
| 38 | // map for saving QPixmaps for reuse | ||
| 39 | static QMap<Color::Color, QPixmap> m_pixmaps; | ||
| 40 | unsigned int m_neighbours; | ||
| 41 | }; | ||
| 42 | |||
| 43 | #endif // BLOCK_H | ||
diff --git a/pacman-c++/common/bonuspoint.cpp b/pacman-c++/common/bonuspoint.cpp new file mode 100644 index 0000000..033b7c8 --- /dev/null +++ b/pacman-c++/common/bonuspoint.cpp | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | #include "bonuspoint.h" | ||
| 2 | #include "constants.h" | ||
| 3 | #include "actor.h" | ||
| 4 | |||
| 5 | #define BONUSPOINTS_NUM_SPRITES 4 | ||
| 6 | |||
| 7 | namespace | ||
| 8 | { | ||
| 9 | QPixmap *pixmap = NULL; | ||
| 10 | } | ||
| 11 | |||
| 12 | BonusPoint::BonusPoint(QGraphicsItem *parent) | ||
| 13 | : GameEntity(parent) | ||
| 14 | { | ||
| 15 | m_type = Type; | ||
| 16 | |||
| 17 | /* empty object for servers */ | ||
| 18 | if (Constants::server) | ||
| 19 | return; | ||
| 20 | |||
| 21 | if (pixmap == NULL) | ||
| 22 | pixmap = new QPixmap(":/bonuspoints"); | ||
| 23 | setPixmap(*pixmap); | ||
| 24 | |||
| 25 | int rand = (int) (BONUSPOINTS_NUM_SPRITES * (qrand() / (RAND_MAX + 1.0))); | ||
| 26 | setSprite(rand * 20 + Constants::sprite_margin, Constants::sprite_margin, Constants::field_size.width, Constants::field_size.height); | ||
| 27 | } | ||
| 28 | |||
| 29 | GameEntity::EnteredState BonusPoint::enter(Actor *actor) | ||
| 30 | { | ||
| 31 | actor->addRoundPoints(Constants::Game::bonus_point_value); | ||
| 32 | return DestroyedEntity; | ||
| 33 | } | ||
| 34 | |||
| 35 | void BonusPoint::onDie(Actor *actor) | ||
| 36 | { | ||
| 37 | actor->eatingFruit(); | ||
| 38 | } | ||
diff --git a/pacman-c++/common/bonuspoint.h b/pacman-c++/common/bonuspoint.h new file mode 100644 index 0000000..a72a4db --- /dev/null +++ b/pacman-c++/common/bonuspoint.h | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | #ifndef BONUSPOINT_H | ||
| 2 | #define BONUSPOINT_H | ||
| 3 | |||
| 4 | #include "gameentity.h" | ||
| 5 | |||
| 6 | class BonusPoint | ||
| 7 | : public GameEntity | ||
| 8 | { | ||
| 9 | public: | ||
| 10 | enum | ||
| 11 | { | ||
| 12 | Type = UserType + Transmission::bonuspoint | ||
| 13 | }; | ||
| 14 | |||
| 15 | public: | ||
| 16 | BonusPoint(QGraphicsItem *parent=0); | ||
| 17 | virtual ~BonusPoint() | ||
| 18 | {}; | ||
| 19 | |||
| 20 | virtual EnteredState enter(Actor *actor); | ||
| 21 | virtual void onDie(Actor *actor); | ||
| 22 | }; | ||
| 23 | |||
| 24 | #endif // BONUSPOINT_H | ||
diff --git a/pacman-c++/common/common.pro b/pacman-c++/common/common.pro new file mode 100644 index 0000000..5903f9d --- /dev/null +++ b/pacman-c++/common/common.pro | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | TEMPLATE = lib | ||
| 2 | CONFIG += staticlib | ||
| 3 | |||
| 4 | include(../common.pri) | ||
| 5 | |||
| 6 | SOURCES += pixmapitem.cpp \ | ||
| 7 | actor.cpp \ | ||
| 8 | block.cpp \ | ||
| 9 | bonuspoint.cpp \ | ||
| 10 | point.cpp \ | ||
| 11 | audio.cpp \ | ||
| 12 | sceneholder.cpp \ | ||
| 13 | util.cpp \ | ||
| 14 | gameentity.cpp | ||
| 15 | HEADERS += pixmapitem.h \ | ||
| 16 | actor.h \ | ||
| 17 | block.h \ | ||
| 18 | bonuspoint.h \ | ||
| 19 | constants.h \ | ||
| 20 | point.h \ | ||
| 21 | audio.h \ | ||
| 22 | sceneholder.h \ | ||
| 23 | util.h \ | ||
| 24 | gameentity.h | ||
| 25 | |||
| 26 | OTHER_FILES += style.qss \ | ||
| 27 | pacman.rc | ||
| 28 | |||
| 29 | RESOURCES += pacman.qrc | ||
| 30 | RC_FILE = pacman.rc | ||
diff --git a/pacman-c++/common/constants.h b/pacman-c++/common/constants.h new file mode 100644 index 0000000..d40c39e --- /dev/null +++ b/pacman-c++/common/constants.h | |||
| @@ -0,0 +1,102 @@ | |||
| 1 | #ifndef CONSTANTS_H | ||
| 2 | #define CONSTANTS_H | ||
| 3 | #include <sys/types.h> | ||
| 4 | |||
| 5 | namespace Constants { | ||
| 6 | const struct | ||
| 7 | { | ||
| 8 | const unsigned int width; | ||
| 9 | const unsigned int height; | ||
| 10 | } | ||
| 11 | field_size = { 16, 16 }, | ||
| 12 | map_size = { 35, 17 }, | ||
| 13 | map_size_pixel = { field_size.width * map_size.width, | ||
| 14 | field_size.height * map_size.height }; | ||
| 15 | const unsigned int sprite_margin = 2; | ||
| 16 | const unsigned int sprite_offset = 20; | ||
| 17 | const unsigned int tick = 250; // ms | ||
| 18 | extern bool server; | ||
| 19 | |||
| 20 | namespace Networking | ||
| 21 | { | ||
| 22 | const unsigned int port = 7321; | ||
| 23 | const unsigned int connection_timeout = 3000; | ||
| 24 | const unsigned int packet_timeout = 3000; | ||
| 25 | } | ||
| 26 | |||
| 27 | namespace Game | ||
| 28 | { | ||
| 29 | const unsigned int bonus_point_value = 100; | ||
| 30 | const unsigned int point_value = 10; | ||
| 31 | /* players will be placed with this minimum manhattan distance */ | ||
| 32 | const unsigned int player_minimum_distance = 5; | ||
| 33 | /* if the distance above isn't possible, decrease the distance by this value */ | ||
| 34 | const unsigned int player_distance_decr = 2; | ||
| 35 | /* there's a chance of 1:30 that a bonus point will be added (with one actor) */ | ||
| 36 | const unsigned int bouns_point_chance = 30; | ||
| 37 | /* every additional player will raise the chance of a bonus point by that factor */ | ||
| 38 | const unsigned int bouns_point_chance_playerfactor = 3; | ||
| 39 | /* there's a chance of 1:5 that a block will be colorized */ | ||
| 40 | const unsigned int colorize_block_chance = 5; | ||
| 41 | /* how long colorized blocks will stay colorized */ | ||
| 42 | const unsigned int colorize_block_tickcount_min = 50; | ||
| 43 | const unsigned int colorize_block_tickcount_max = 100; | ||
| 44 | } | ||
| 45 | |||
| 46 | namespace AI | ||
| 47 | { | ||
| 48 | /* bots minimum manhatten distance before other players will be recognized */ | ||
| 49 | const unsigned int player_minimum_distance = 4; | ||
| 50 | /* weight values used to determine new direction of bot */ | ||
| 51 | const unsigned int weight_afraid = 50; | ||
| 52 | const unsigned int weight_hunt = 10; | ||
| 53 | const unsigned int weight_bonus_point = 3; | ||
| 54 | const unsigned int weight_point = 1; | ||
| 55 | const unsigned int weight_colorblock = 5; | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | namespace Color | ||
| 60 | { | ||
| 61 | enum Color | ||
| 62 | { | ||
| 63 | none = 0, | ||
| 64 | red = (1 << 0), | ||
| 65 | blue = (1 << 1), | ||
| 66 | green = (1 << 2), | ||
| 67 | yellow = (1 << 3) | ||
| 68 | }; | ||
| 69 | |||
| 70 | /* colororder used in protocol and gui */ | ||
| 71 | const Color order[] = | ||
| 72 | { Color::red, Color::blue, Color::green, Color::yellow, Color::none }; | ||
| 73 | } | ||
| 74 | |||
| 75 | // constants for data transmission to client | ||
| 76 | namespace Transmission | ||
| 77 | { | ||
| 78 | typedef unsigned int field_t; | ||
| 79 | typedef unsigned int mask_t; | ||
| 80 | |||
| 81 | const field_t none = 0; | ||
| 82 | const field_t block = (1 << 4); | ||
| 83 | const field_t point = (1 << 5); | ||
| 84 | const field_t bonuspoint = (1 << 6); | ||
| 85 | const field_t pacman = (1 << 7); | ||
| 86 | const field_t empty = (1 << 8); // explicit empty for update | ||
| 87 | const field_t death = (1 << 9); | ||
| 88 | |||
| 89 | const field_t direction_none = 0; | ||
| 90 | const field_t direction_left = (1 << 10); | ||
| 91 | const field_t direction_right = (1 << 11); | ||
| 92 | const field_t direction_up = (1 << 12); | ||
| 93 | const field_t direction_down = (1 << 13); | ||
| 94 | |||
| 95 | const mask_t color_mask = Color::none | Color::red | Color::blue | Color::green | Color::yellow; | ||
| 96 | const mask_t type_mask = block | bonuspoint; | ||
| 97 | const mask_t direction_mask = direction_none | direction_left | direction_right | direction_up | direction_down; | ||
| 98 | |||
| 99 | typedef field_t** map_t; | ||
| 100 | } | ||
| 101 | |||
| 102 | #endif // CONSTANTS_H | ||
diff --git a/pacman-c++/common/gameentity.cpp b/pacman-c++/common/gameentity.cpp new file mode 100644 index 0000000..e73e759 --- /dev/null +++ b/pacman-c++/common/gameentity.cpp | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | #include "gameentity.h" | ||
| 2 | |||
| 3 | GameEntity::GameEntity(Color::Color color, QGraphicsItem *parent) | ||
| 4 | : PixmapItem(parent), m_type(Type), m_color(color) | ||
| 5 | {} | ||
| 6 | |||
| 7 | GameEntity::GameEntity(QGraphicsItem *parent) | ||
| 8 | : PixmapItem(parent), m_type(Type), m_color(Color::none) | ||
| 9 | {} | ||
diff --git a/pacman-c++/common/gameentity.h b/pacman-c++/common/gameentity.h new file mode 100644 index 0000000..116fae5 --- /dev/null +++ b/pacman-c++/common/gameentity.h | |||
| @@ -0,0 +1,72 @@ | |||
| 1 | #ifndef GAMEENTITY_H | ||
| 2 | #define GAMEENTITY_H | ||
| 3 | |||
| 4 | #include "constants.h" | ||
| 5 | #include "pixmapitem.h" | ||
| 6 | #include <QtGlobal> | ||
| 7 | #include <QDebug> | ||
| 8 | |||
| 9 | class Actor; | ||
| 10 | |||
| 11 | /** | ||
| 12 | * Base class for entities that interact in the game | ||
| 13 | */ | ||
| 14 | class GameEntity | ||
| 15 | : public PixmapItem | ||
| 16 | { | ||
| 17 | public: | ||
| 18 | enum | ||
| 19 | { | ||
| 20 | Type = UserType + 1 | ||
| 21 | }; | ||
| 22 | |||
| 23 | enum EnteredState | ||
| 24 | { | ||
| 25 | Nothing, | ||
| 26 | DestroyedEntity, | ||
| 27 | DestroyedActor | ||
| 28 | }; | ||
| 29 | |||
| 30 | public: | ||
| 31 | GameEntity(Color::Color color = Color::none, QGraphicsItem *parent = 0); | ||
| 32 | GameEntity(QGraphicsItem *parent); | ||
| 33 | virtual ~GameEntity() | ||
| 34 | {}; | ||
| 35 | |||
| 36 | /* color of entity */ | ||
| 37 | virtual Color::Color color() | ||
| 38 | { | ||
| 39 | return m_color; | ||
| 40 | } | ||
| 41 | |||
| 42 | /* returns whether the actor may enter this field */ | ||
| 43 | virtual bool checkEnter(Actor *) | ||
| 44 | { | ||
| 45 | return true; | ||
| 46 | } | ||
| 47 | |||
| 48 | /* performs action when this actor acctually enters | ||
| 49 | * returns whether this entity survives the entering | ||
| 50 | */ | ||
| 51 | virtual EnteredState enter(Actor *) | ||
| 52 | { | ||
| 53 | /* default to no action/survive */ | ||
| 54 | return Nothing; | ||
| 55 | } | ||
| 56 | |||
| 57 | /* called when an instance acctually dies for creating effects */ | ||
| 58 | virtual void onDie(Actor *) | ||
| 59 | {}; | ||
| 60 | |||
| 61 | /* enable the use of qgraphicsitem_cast with this item */ | ||
| 62 | int type() const | ||
| 63 | { | ||
| 64 | return m_type; | ||
| 65 | } | ||
| 66 | |||
| 67 | protected: | ||
| 68 | int m_type; | ||
| 69 | Color::Color m_color; | ||
| 70 | }; | ||
| 71 | |||
| 72 | #endif // GAMEENTITY_H | ||
diff --git a/pacman-c++/common/pacman.qrc b/pacman-c++/common/pacman.qrc new file mode 100644 index 0000000..6654fd1 --- /dev/null +++ b/pacman-c++/common/pacman.qrc | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | <RCC> | ||
| 2 | <qresource prefix="/"> | ||
| 3 | <file alias="actor1">pics/actor1.png</file> | ||
| 4 | <file alias="actor2">pics/actor2.png</file> | ||
| 5 | <file alias="actor3">pics/actor3.png</file> | ||
| 6 | <file alias="actor4">pics/actor4.png</file> | ||
| 7 | <file alias="block0">pics/block0.png</file> | ||
| 8 | <file alias="block1">pics/block1.png</file> | ||
| 9 | <file alias="block2">pics/block2.png</file> | ||
| 10 | <file alias="block3">pics/block3.png</file> | ||
| 11 | <file alias="block4">pics/block4.png</file> | ||
| 12 | <file alias="bonuspoints">pics/bonuspoints.png</file> | ||
| 13 | <file alias="points">pics/points.png</file> | ||
| 14 | <file alias="stylesheet">style.qss</file> | ||
| 15 | <file alias="appicon">pics/app.ico</file> | ||
| 16 | <file alias="actor1icon">pics/actor1icon.png</file> | ||
| 17 | <file alias="actor2icon">pics/actor2icon.png</file> | ||
| 18 | <file alias="actor3icon">pics/actor3icon.png</file> | ||
| 19 | <file alias="actor4icon">pics/actor4icon.png</file> | ||
| 20 | <file alias="soundon">pics/soundon.xpm</file> | ||
| 21 | <file alias="soundoff">pics/soundoff.xpm</file> | ||
| 22 | </qresource> | ||
| 23 | <qresource prefix="/sound"> | ||
| 24 | <file alias="sound1">sound/intro.ogg</file> | ||
| 25 | <file alias="sound2">sound/waka_waka.ogg</file> | ||
| 26 | <file alias="sound3">sound/eating_fruit.ogg</file> | ||
| 27 | <file alias="sound4">sound/eating_ghost.ogg</file> | ||
| 28 | <file alias="sound5">sound/die.ogg</file> | ||
| 29 | <file alias="sound6">sound/ambient.ogg</file> | ||
| 30 | </qresource> | ||
| 31 | </RCC> | ||
diff --git a/pacman-c++/common/pacman.rc b/pacman-c++/common/pacman.rc new file mode 100644 index 0000000..8c9f03b --- /dev/null +++ b/pacman-c++/common/pacman.rc | |||
| @@ -0,0 +1 @@ | |||
| IDI_ICON1 ICON DISCARDABLE "pics/app.ico" | |||
diff --git a/pacman-c++/common/pics/actor1.png b/pacman-c++/common/pics/actor1.png new file mode 100644 index 0000000..5a37b4f --- /dev/null +++ b/pacman-c++/common/pics/actor1.png | |||
| Binary files differ | |||
diff --git a/pacman-c++/common/pics/actor1icon.png b/pacman-c++/common/pics/actor1icon.png new file mode 100644 index 0000000..4407cef --- /dev/null +++ b/pacman-c++/common/pics/actor1icon.png | |||
| Binary files differ | |||
diff --git a/pacman-c++/common/pics/actor2.png b/pacman-c++/common/pics/actor2.png new file mode 100644 index 0000000..736a6e7 --- /dev/null +++ b/pacman-c++/common/pics/actor2.png | |||
| Binary files differ | |||
diff --git a/pacman-c++/common/pics/actor2icon.png b/pacman-c++/common/pics/actor2icon.png new file mode 100644 index 0000000..eaf2a4c --- /dev/null +++ b/pacman-c++/common/pics/actor2icon.png | |||
| Binary files differ | |||
diff --git a/pacman-c++/common/pics/actor3.png b/pacman-c++/common/pics/actor3.png new file mode 100644 index 0000000..f963cff --- /dev/null +++ b/pacman-c++/common/pics/actor3.png | |||
| Binary files differ | |||
diff --git a/pacman-c++/common/pics/actor3icon.png b/pacman-c++/common/pics/actor3icon.png new file mode 100644 index 0000000..2558cbc --- /dev/null +++ b/pacman-c++/common/pics/actor3icon.png | |||
| Binary files differ | |||
diff --git a/pacman-c++/common/pics/actor4.png b/pacman-c++/common/pics/actor4.png new file mode 100644 index 0000000..e500dc5 --- /dev/null +++ b/pacman-c++/common/pics/actor4.png | |||
| Binary files differ | |||
diff --git a/pacman-c++/common/pics/actor4icon.png b/pacman-c++/common/pics/actor4icon.png new file mode 100644 index 0000000..82bf637 --- /dev/null +++ b/pacman-c++/common/pics/actor4icon.png | |||
| Binary files differ | |||
diff --git a/pacman-c++/common/pics/app.ico b/pacman-c++/common/pics/app.ico new file mode 100644 index 0000000..4a73cd4 --- /dev/null +++ b/pacman-c++/common/pics/app.ico | |||
| Binary files differ | |||
diff --git a/pacman-c++/common/pics/block0.png b/pacman-c++/common/pics/block0.png new file mode 100644 index 0000000..76bc4b7 --- /dev/null +++ b/pacman-c++/common/pics/block0.png | |||
| Binary files differ | |||
diff --git a/pacman-c++/common/pics/block1.png b/pacman-c++/common/pics/block1.png new file mode 100644 index 0000000..99e8633 --- /dev/null +++ b/pacman-c++/common/pics/block1.png | |||
| Binary files differ | |||
diff --git a/pacman-c++/common/pics/block2.png b/pacman-c++/common/pics/block2.png new file mode 100644 index 0000000..963207e --- /dev/null +++ b/pacman-c++/common/pics/block2.png | |||
| Binary files differ | |||
diff --git a/pacman-c++/common/pics/block3.png b/pacman-c++/common/pics/block3.png new file mode 100644 index 0000000..6662de4 --- /dev/null +++ b/pacman-c++/common/pics/block3.png | |||
| Binary files differ | |||
diff --git a/pacman-c++/common/pics/block4.png b/pacman-c++/common/pics/block4.png new file mode 100644 index 0000000..00fbd74 --- /dev/null +++ b/pacman-c++/common/pics/block4.png | |||
| Binary files differ | |||
diff --git a/pacman-c++/common/pics/bonuspoints.png b/pacman-c++/common/pics/bonuspoints.png new file mode 100644 index 0000000..b5714c9 --- /dev/null +++ b/pacman-c++/common/pics/bonuspoints.png | |||
| Binary files differ | |||
diff --git a/pacman-c++/common/pics/pacman10-hp-sprite-2.png b/pacman-c++/common/pics/pacman10-hp-sprite-2.png new file mode 100644 index 0000000..7354b9d --- /dev/null +++ b/pacman-c++/common/pics/pacman10-hp-sprite-2.png | |||
| Binary files differ | |||
diff --git a/pacman-c++/common/pics/points.png b/pacman-c++/common/pics/points.png new file mode 100644 index 0000000..6ba4496 --- /dev/null +++ b/pacman-c++/common/pics/points.png | |||
| Binary files differ | |||
diff --git a/pacman-c++/common/pics/soundoff.xpm b/pacman-c++/common/pics/soundoff.xpm new file mode 100644 index 0000000..ba33f5f --- /dev/null +++ b/pacman-c++/common/pics/soundoff.xpm | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | /* XPM */ | ||
| 2 | static char * soundoff_xpm[] = { | ||
| 3 | "12 10 2 1", | ||
| 4 | " c None", | ||
| 5 | ". c #000000", | ||
| 6 | " ", | ||
| 7 | " . ", | ||
| 8 | " .. . .", | ||
| 9 | ".... . . ", | ||
| 10 | ".... .. ", | ||
| 11 | ".... .. ", | ||
| 12 | ".... . . ", | ||
| 13 | " .. . .", | ||
| 14 | " . ", | ||
| 15 | " "}; | ||
diff --git a/pacman-c++/common/pics/soundon.xpm b/pacman-c++/common/pics/soundon.xpm new file mode 100644 index 0000000..e6ca41e --- /dev/null +++ b/pacman-c++/common/pics/soundon.xpm | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | /* XPM */ | ||
| 2 | static char * soundoff_xpm[] = { | ||
| 3 | "12 10 2 1", | ||
| 4 | " c None", | ||
| 5 | ". c #000000", | ||
| 6 | " . ", | ||
| 7 | " . . ", | ||
| 8 | " .. . . ", | ||
| 9 | ".... . . ", | ||
| 10 | ".... . . ", | ||
| 11 | ".... . . ", | ||
| 12 | ".... . . ", | ||
| 13 | " .. . . ", | ||
| 14 | " . . ", | ||
| 15 | " . "}; | ||
diff --git a/pacman-c++/common/pixmapitem.cpp b/pacman-c++/common/pixmapitem.cpp new file mode 100644 index 0000000..1ceeec1 --- /dev/null +++ b/pacman-c++/common/pixmapitem.cpp | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | #include "pixmapitem.h" | ||
| 2 | #include <QPainter> | ||
| 3 | |||
| 4 | PixmapItem::PixmapItem(QGraphicsItem *parent) | ||
| 5 | : QGraphicsObject(parent), m_x(0), m_y(0) | ||
| 6 | { | ||
| 7 | } | ||
| 8 | |||
| 9 | PixmapItem::PixmapItem(const QString &fileName, QGraphicsItem *parent) | ||
| 10 | : QGraphicsObject(parent), m_x(0), m_y(0) | ||
| 11 | { | ||
| 12 | m_pix = ":/" + fileName; | ||
| 13 | m_width = m_pix.width(); | ||
| 14 | m_height = m_pix.height(); | ||
| 15 | } | ||
| 16 | |||
| 17 | PixmapItem::PixmapItem(const QString &fileName, QGraphicsScene *scene) | ||
| 18 | : QGraphicsObject(), m_x(0), m_y(0) | ||
| 19 | { | ||
| 20 | m_pix = ":/" + fileName; | ||
| 21 | m_width = m_pix.width(); | ||
| 22 | m_height = m_pix.height(); | ||
| 23 | scene->addItem(this); | ||
| 24 | } | ||
| 25 | |||
| 26 | PixmapItem::PixmapItem(const QPixmap &pix, QGraphicsItem *parent) | ||
| 27 | : QGraphicsObject(parent), m_pix(pix), m_x(0), m_y(0) | ||
| 28 | { | ||
| 29 | m_width = m_pix.width(); | ||
| 30 | m_height = m_pix.height(); | ||
| 31 | } | ||
| 32 | |||
| 33 | PixmapItem::PixmapItem(const QPixmap &pix, QGraphicsScene *scene) | ||
| 34 | : QGraphicsObject(), m_pix(pix), m_x(0), m_y(0) | ||
| 35 | { | ||
| 36 | m_width = m_pix.width(); | ||
| 37 | m_height = m_pix.height(); | ||
| 38 | scene->addItem(this); | ||
| 39 | } | ||
| 40 | |||
| 41 | void PixmapItem::setPixmap(const QPixmap &pix) | ||
| 42 | { | ||
| 43 | m_pix = pix; | ||
| 44 | m_width = m_pix.width(); | ||
| 45 | m_height = m_pix.height(); | ||
| 46 | } | ||
| 47 | |||
| 48 | void PixmapItem::setSprite(int x, int y, int width, int height) | ||
| 49 | { | ||
| 50 | m_x = x; | ||
| 51 | m_y = y; | ||
| 52 | m_width = width; | ||
| 53 | m_height = height; | ||
| 54 | } | ||
| 55 | |||
| 56 | QSizeF PixmapItem::size() const | ||
| 57 | { | ||
| 58 | return QSizeF(m_width, m_height); | ||
| 59 | } | ||
| 60 | |||
| 61 | QRectF PixmapItem::boundingRect() const | ||
| 62 | { | ||
| 63 | return QRectF(QPointF(0, 0), size()); | ||
| 64 | } | ||
| 65 | |||
| 66 | QPainterPath PixmapItem::shape() const | ||
| 67 | { | ||
| 68 | QPainterPath path; | ||
| 69 | path.addRect(boundingRect()); | ||
| 70 | return path; | ||
| 71 | } | ||
| 72 | |||
| 73 | void PixmapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) | ||
| 74 | { | ||
| 75 | painter->drawPixmap(QPoint(0, 0), m_pix, QRect(m_x, m_y, m_width, m_height)); | ||
| 76 | } | ||
| 77 | |||
diff --git a/pacman-c++/common/pixmapitem.h b/pacman-c++/common/pixmapitem.h new file mode 100644 index 0000000..f57c22a --- /dev/null +++ b/pacman-c++/common/pixmapitem.h | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | #ifndef PIXMAPITEM__H | ||
| 2 | #define PIXMAPITEM__H | ||
| 3 | |||
| 4 | #include <QtGui/QGraphicsObject> | ||
| 5 | #include <QtGui/QGraphicsScene> | ||
| 6 | |||
| 7 | class PixmapItem | ||
| 8 | : public QGraphicsObject | ||
| 9 | { | ||
| 10 | public: | ||
| 11 | PixmapItem(QGraphicsItem *parent = 0); | ||
| 12 | PixmapItem(const QString &fileName, QGraphicsItem *parent = 0); | ||
| 13 | PixmapItem(const QString &fileName, QGraphicsScene *scene); | ||
| 14 | PixmapItem(const QPixmap &pix, QGraphicsItem *parent = 0); | ||
| 15 | PixmapItem(const QPixmap &pix, QGraphicsScene *scene); | ||
| 16 | virtual ~PixmapItem() | ||
| 17 | {}; | ||
| 18 | |||
| 19 | void setPixmap(const QPixmap &pix); | ||
| 20 | void setSprite(int x, int y, int width, int height); | ||
| 21 | QSizeF size() const; | ||
| 22 | QRectF boundingRect() const; | ||
| 23 | QPainterPath shape() const; | ||
| 24 | void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); | ||
| 25 | |||
| 26 | private: | ||
| 27 | QPixmap m_pix; | ||
| 28 | int m_x, m_y; | ||
| 29 | int m_width, m_height; | ||
| 30 | }; | ||
| 31 | |||
| 32 | #endif | ||
diff --git a/pacman-c++/common/point.cpp b/pacman-c++/common/point.cpp new file mode 100644 index 0000000..d7ebdb1 --- /dev/null +++ b/pacman-c++/common/point.cpp | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | #include "point.h" | ||
| 2 | #include "constants.h" | ||
| 3 | #include "actor.h" | ||
| 4 | |||
| 5 | namespace | ||
| 6 | { | ||
| 7 | QPixmap *pixmap = NULL; | ||
| 8 | } | ||
| 9 | |||
| 10 | Point::Point(QGraphicsItem *parent) | ||
| 11 | : GameEntity(parent) | ||
| 12 | { | ||
| 13 | m_type = Type; | ||
| 14 | |||
| 15 | /* empty object for servers */ | ||
| 16 | if (Constants::server) | ||
| 17 | return; | ||
| 18 | |||
| 19 | if (pixmap == NULL) | ||
| 20 | pixmap = new QPixmap(":/points"); | ||
| 21 | setPixmap(*pixmap); | ||
| 22 | } | ||
| 23 | |||
| 24 | GameEntity::EnteredState Point::enter(Actor *actor) | ||
| 25 | { | ||
| 26 | actor->addRoundPoints(Constants::Game::point_value); | ||
| 27 | return DestroyedEntity; | ||
| 28 | } | ||
| 29 | |||
| 30 | void Point::onDie(Actor *actor) | ||
| 31 | { | ||
| 32 | actor->startEating(); | ||
| 33 | } | ||
diff --git a/pacman-c++/common/point.h b/pacman-c++/common/point.h new file mode 100644 index 0000000..7739554 --- /dev/null +++ b/pacman-c++/common/point.h | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | #ifndef POINT_H | ||
| 2 | #define POINT_H | ||
| 3 | |||
| 4 | #include "gameentity.h" | ||
| 5 | |||
| 6 | class Point | ||
| 7 | : public GameEntity | ||
| 8 | { | ||
| 9 | public: | ||
| 10 | enum | ||
| 11 | { | ||
| 12 | Type = UserType + Transmission::point | ||
| 13 | }; | ||
| 14 | |||
| 15 | public: | ||
| 16 | Point(QGraphicsItem *parent=0); | ||
| 17 | virtual ~Point() | ||
| 18 | {}; | ||
| 19 | |||
| 20 | virtual EnteredState enter(Actor *actor); | ||
| 21 | virtual void onDie(Actor *actor); | ||
| 22 | }; | ||
| 23 | |||
| 24 | #endif // POINT_H | ||
diff --git a/pacman-c++/common/sceneholder.cpp b/pacman-c++/common/sceneholder.cpp new file mode 100644 index 0000000..bd9b01b --- /dev/null +++ b/pacman-c++/common/sceneholder.cpp | |||
| @@ -0,0 +1,364 @@ | |||
| 1 | #include "sceneholder.h" | ||
| 2 | #include "constants.h" | ||
| 3 | #include "gameentity.h" | ||
| 4 | #include "block.h" | ||
| 5 | #include "actor.h" | ||
| 6 | #include "bonuspoint.h" | ||
| 7 | #include "point.h" | ||
| 8 | #include "util.h" | ||
| 9 | |||
| 10 | SceneHolder::SceneHolder(QObject *parent) | ||
| 11 | : QGraphicsScene(parent), m_color(Color::none), m_pointsLeft(0) | ||
| 12 | { | ||
| 13 | setSceneRect(0, 0, Constants::map_size_pixel.width, Constants::map_size_pixel.height); | ||
| 14 | setBackgroundBrush(Qt::black); | ||
| 15 | |||
| 16 | m_overlayText = new QGraphicsTextItem(); | ||
| 17 | |||
| 18 | visualMap.resize(Constants::map_size.width); | ||
| 19 | for (int i = 0; i < visualMap.size(); ++i) | ||
| 20 | visualMap[i].resize(Constants::map_size.height); | ||
| 21 | } | ||
| 22 | |||
| 23 | void SceneHolder::reset() | ||
| 24 | { | ||
| 25 | processDelayedItems(); | ||
| 26 | showEatingText(false); | ||
| 27 | |||
| 28 | /* remove actors from scene so they don't get deleted during clear */ | ||
| 29 | foreach(Actor *actor, m_actors) | ||
| 30 | { | ||
| 31 | actor->reset(); | ||
| 32 | removeItem(actor); | ||
| 33 | } | ||
| 34 | |||
| 35 | /* clear our stuff */ | ||
| 36 | clear(); | ||
| 37 | m_pointsLeft = 0; | ||
| 38 | for (int i = 0; i < visualMap.size(); ++i) | ||
| 39 | { | ||
| 40 | visualMap[i].clear(); | ||
| 41 | visualMap[i].resize(Constants::map_size.height); | ||
| 42 | } | ||
| 43 | |||
| 44 | /* add actors again */ | ||
| 45 | foreach(Actor *actor, m_actors) | ||
| 46 | addItem(actor); | ||
| 47 | } | ||
| 48 | |||
| 49 | void SceneHolder::processDelayedItems() | ||
| 50 | { | ||
| 51 | /* remove items that got marked for removal from scene */ | ||
| 52 | foreach(GameEntity *item, m_oldItems) | ||
| 53 | { | ||
| 54 | removeItem(item); | ||
| 55 | delete item; | ||
| 56 | } | ||
| 57 | m_oldItems.clear(); | ||
| 58 | |||
| 59 | /* process death */ | ||
| 60 | foreach(const Color::Color color, m_death.keys()) | ||
| 61 | { | ||
| 62 | Q_ASSERT(m_death[color] != NULL); | ||
| 63 | m_death[color]->onDie(m_actors[color]); | ||
| 64 | } | ||
| 65 | m_death.clear(); | ||
| 66 | } | ||
| 67 | |||
| 68 | void SceneHolder::updateMap(const Transmission::map_t& map) | ||
| 69 | { | ||
| 70 | processDelayedItems(); | ||
| 71 | |||
| 72 | /* process update */ | ||
| 73 | for (unsigned int x = 0; x < Constants::map_size.width; ++x) | ||
| 74 | { | ||
| 75 | for (unsigned int y = 0; y < Constants::map_size.height; ++y) | ||
| 76 | { | ||
| 77 | const Transmission::field_t &cur = map[x][y]; | ||
| 78 | if (cur == Transmission::none) | ||
| 79 | continue; | ||
| 80 | updateMap(map, x, y); | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | if (m_pointsLeft == 0) | ||
| 85 | emit allPointsRemoved(); | ||
| 86 | } | ||
| 87 | |||
| 88 | void SceneHolder::updateMap(const Transmission::map_t& map, const unsigned int x, unsigned int y) | ||
| 89 | { | ||
| 90 | const Transmission::field_t &cur = map[x][y]; | ||
| 91 | if (cur == Transmission::none) | ||
| 92 | return; | ||
| 93 | |||
| 94 | /* we may have multiple colors in one position (e.g during eating another pacman) */ | ||
| 95 | Color::Color color = static_cast<Color::Color>(cur & Transmission::color_mask); | ||
| 96 | QList<Color::Color> colors; | ||
| 97 | if (color == Color::none) | ||
| 98 | colors.append(Color::none); | ||
| 99 | foreach(Color::Color col, m_eatingorder.toSet()) | ||
| 100 | { | ||
| 101 | if (color & col) | ||
| 102 | colors.append(col); | ||
| 103 | } | ||
| 104 | Q_ASSERT(colors.count() > 0); | ||
| 105 | |||
| 106 | /* for now complain if there are more colors or it's a Transmission::death packet */ | ||
| 107 | Q_ASSERT(colors.count() == 1 || cur & Transmission::death); | ||
| 108 | |||
| 109 | if (cur & Transmission::empty) | ||
| 110 | { | ||
| 111 | GameEntity *oldItem = visualMap[x][y]; | ||
| 112 | /* special handling for purging field */ | ||
| 113 | if (oldItem != NULL) | ||
| 114 | { | ||
| 115 | /* remove item from visualmap and register item for removal in next update */ | ||
| 116 | visualMap[x][y] = NULL; | ||
| 117 | m_oldItems.append(oldItem); | ||
| 118 | |||
| 119 | /* an item must be removed by an actor */ | ||
| 120 | Actor *actor = m_actors[colors.at(0)]; | ||
| 121 | Q_ASSERT(actor != NULL); | ||
| 122 | oldItem->onDie(actor); | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | GameEntity *item = NULL; | ||
| 127 | if (cur == Transmission::none) | ||
| 128 | { | ||
| 129 | /* no update */ | ||
| 130 | } | ||
| 131 | else | ||
| 132 | { | ||
| 133 | if (cur & Transmission::block) | ||
| 134 | { | ||
| 135 | unsigned int neighbours = Block::None; | ||
| 136 | /* check for old block first */ | ||
| 137 | if (visualMap[x][y] != NULL) | ||
| 138 | { | ||
| 139 | Block *oldItem = qgraphicsitem_cast<Block *>(visualMap[x][y]); | ||
| 140 | if (oldItem != NULL) | ||
| 141 | neighbours = oldItem->neighbours(); | ||
| 142 | } | ||
| 143 | /* check left side */ | ||
| 144 | if (x > 0 && map[x - 1][y] & Transmission::block) | ||
| 145 | neighbours |= Block::Left; | ||
| 146 | /* check right side */ | ||
| 147 | if (x < Constants::map_size.width && map[x + 1][y] & Transmission::block) | ||
| 148 | neighbours |= Block::Right; | ||
| 149 | /* check upside */ | ||
| 150 | if (y > 0 && map[x][y - 1] & Transmission::block) | ||
| 151 | neighbours |= Block::Up; | ||
| 152 | /* check down side */ | ||
| 153 | if (y < Constants::map_size.height && map[x][y + 1] & Transmission::block) | ||
| 154 | neighbours |= Block::Down; | ||
| 155 | item = new Block(colors.at(0), neighbours); | ||
| 156 | } | ||
| 157 | |||
| 158 | if (cur & Transmission::bonuspoint) | ||
| 159 | item = new BonusPoint(); | ||
| 160 | |||
| 161 | if (cur & Transmission::point) | ||
| 162 | { | ||
| 163 | item = new Point(); | ||
| 164 | connect(item, SIGNAL(destroyed()), this, SLOT(decrementPoints())); | ||
| 165 | ++m_pointsLeft; | ||
| 166 | } | ||
| 167 | |||
| 168 | if (cur & Transmission::pacman) | ||
| 169 | { | ||
| 170 | foreach(color, colors) | ||
| 171 | { | ||
| 172 | /* WARNING: do NOT add actor to visualMap as visualMap-items may | ||
| 173 | * get deleted during update and actors are referenced in_mactors too | ||
| 174 | * if you REALLY need that you need to changed updateMap so that all actors | ||
| 175 | * will be moved before any new items get allocated (totally untested) | ||
| 176 | */ | ||
| 177 | Actor *actor = m_actors.value(color, NULL); | ||
| 178 | if (actor == NULL) | ||
| 179 | { | ||
| 180 | actor = new Actor(color, (color == m_color)); | ||
| 181 | m_actors[color] = actor; | ||
| 182 | addItem(actor); | ||
| 183 | actor->setPos(mapPositionToCoord(x, y)); | ||
| 184 | actor->hadReset(); | ||
| 185 | } | ||
| 186 | else | ||
| 187 | { | ||
| 188 | /* check for death */ | ||
| 189 | if (cur & Transmission::death) | ||
| 190 | { | ||
| 191 | foreach(Color::Color col, colors) | ||
| 192 | { | ||
| 193 | if (color == col) | ||
| 194 | continue; | ||
| 195 | if (m_actors[col]->canEat(actor, m_eatingorder)) | ||
| 196 | { | ||
| 197 | m_death[col] = actor; | ||
| 198 | break; | ||
| 199 | } | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 203 | /* move actor */ | ||
| 204 | if (actor->hadReset()) | ||
| 205 | actor->setPos(mapPositionToCoord(x, y)); | ||
| 206 | else | ||
| 207 | actor->move(mapPositionToCoord(x, y)); | ||
| 208 | |||
| 209 | /* that's kind a hack but working right now */ | ||
| 210 | if (!(cur & Transmission::empty)) | ||
| 211 | actor->stopEating(); | ||
| 212 | qDebug() << "[SceneUpdate] actor moves: color=" << color | ||
| 213 | << "newpos=" << QPoint(x, y); | ||
| 214 | } | ||
| 215 | |||
| 216 | if ((cur & Transmission::death) && visualMap[x][y] != NULL) | ||
| 217 | m_death[color] = visualMap[x][y]; | ||
| 218 | } | ||
| 219 | } | ||
| 220 | |||
| 221 | if (cur & Transmission::empty) | ||
| 222 | { | ||
| 223 | /* already handled */ | ||
| 224 | } | ||
| 225 | } | ||
| 226 | |||
| 227 | /* add new created item to scene | ||
| 228 | * remove old item on that location if there's one | ||
| 229 | */ | ||
| 230 | if (item != NULL) | ||
| 231 | { | ||
| 232 | GameEntity *oldItem = visualMap[x][y]; | ||
| 233 | if (oldItem != NULL) | ||
| 234 | { | ||
| 235 | removeItem(oldItem); | ||
| 236 | delete oldItem; | ||
| 237 | } | ||
| 238 | |||
| 239 | addItem(item); | ||
| 240 | item->setPos(mapPositionToCoord(x, y)); | ||
| 241 | visualMap[x][y] = item; | ||
| 242 | } | ||
| 243 | } | ||
| 244 | |||
| 245 | void SceneHolder::setColor(Color::Color color) | ||
| 246 | { | ||
| 247 | m_color = color; | ||
| 248 | } | ||
| 249 | |||
| 250 | Color::Color SceneHolder::color() | ||
| 251 | { | ||
| 252 | return m_color; | ||
| 253 | } | ||
| 254 | |||
| 255 | unsigned int SceneHolder::pointsLeft() | ||
| 256 | { | ||
| 257 | return m_pointsLeft; | ||
| 258 | } | ||
| 259 | |||
| 260 | void SceneHolder::decrementPoints() | ||
| 261 | { | ||
| 262 | --m_pointsLeft; | ||
| 263 | } | ||
| 264 | |||
| 265 | void SceneHolder::setEatingOrder(QList<Color::Color> &order) | ||
| 266 | { | ||
| 267 | m_eatingorder = order; | ||
| 268 | } | ||
| 269 | |||
| 270 | QList<Color::Color> &SceneHolder::eatingOrder() | ||
| 271 | { | ||
| 272 | return m_eatingorder; | ||
| 273 | } | ||
| 274 | |||
| 275 | void SceneHolder::showEatingText(bool show) | ||
| 276 | { | ||
| 277 | if (!show) | ||
| 278 | { | ||
| 279 | if (m_overlayText->scene() == this) | ||
| 280 | removeItem(m_overlayText); | ||
| 281 | return; | ||
| 282 | } | ||
| 283 | |||
| 284 | m_overlayText->setDefaultTextColor(Qt::black); | ||
| 285 | QString text = QString( | ||
| 286 | "<div style=\"background-color: gray;\" align=\"center\">" | ||
| 287 | "<br />" | ||
| 288 | ); | ||
| 289 | unsigned int lines = 1; | ||
| 290 | |||
| 291 | text = text % QString("<b>Your Pacman: <img src=\"%1\"/></b><br /><br />") | ||
| 292 | .arg(m_actors[m_color]->iconStr()); | ||
| 293 | lines += 2; | ||
| 294 | |||
| 295 | foreach(Actor *actor, m_actors) | ||
| 296 | { | ||
| 297 | foreach(Actor *other, m_actors) | ||
| 298 | { | ||
| 299 | if (!actor->canEat(other, m_eatingorder)) | ||
| 300 | continue; | ||
| 301 | text = text % QString("<img src=\"%1\"/> can eat <img src=\"%2\"/><br />") | ||
| 302 | .arg(actor->iconStr(), other->iconStr()); | ||
| 303 | ++lines; | ||
| 304 | } | ||
| 305 | } | ||
| 306 | text = text % "</div>"; | ||
| 307 | m_overlayText->setHtml(text); | ||
| 308 | m_overlayText->setTextWidth(150); | ||
| 309 | m_overlayText->setOpacity(0.9); | ||
| 310 | |||
| 311 | QFontMetrics metrics(m_overlayText->font()); | ||
| 312 | m_overlayText->setPos((width() - m_overlayText->textWidth()) / 2, (height() - metrics.height() * lines) / 2); | ||
| 313 | m_overlayText->setZValue(100); | ||
| 314 | |||
| 315 | addItem(m_overlayText); | ||
| 316 | } | ||
| 317 | |||
| 318 | void SceneHolder::showWaitingForPlayers(bool show) | ||
| 319 | { | ||
| 320 | if (!show) | ||
| 321 | { | ||
| 322 | if (m_overlayText->scene() == this) | ||
| 323 | removeItem(m_overlayText); | ||
| 324 | return; | ||
| 325 | } | ||
| 326 | |||
| 327 | m_overlayText->setDefaultTextColor(Qt::black); | ||
| 328 | QString text = QString( | ||
| 329 | "<div style=\"background-color: gray;\" align=\"center\">" | ||
| 330 | "<br />" | ||
| 331 | "Waiting for other Players...<br />" | ||
| 332 | "</div>" | ||
| 333 | ); | ||
| 334 | unsigned int lines = 3; | ||
| 335 | m_overlayText->setHtml(text); | ||
| 336 | m_overlayText->setTextWidth(150); | ||
| 337 | m_overlayText->setOpacity(0.9); | ||
| 338 | |||
| 339 | QFontMetrics metrics(m_overlayText->font()); | ||
| 340 | m_overlayText->setPos((width() - m_overlayText->textWidth()) / 2, (height() - metrics.height() * lines) / 2); | ||
| 341 | m_overlayText->setZValue(100); | ||
| 342 | |||
| 343 | addItem(m_overlayText); | ||
| 344 | } | ||
| 345 | |||
| 346 | QPoint SceneHolder::mapPositionToCoord(unsigned int x, unsigned int y) | ||
| 347 | { | ||
| 348 | return QPoint(x * Constants::field_size.width, y * Constants::field_size.height); | ||
| 349 | } | ||
| 350 | |||
| 351 | QPoint SceneHolder::mapPositionToCoord(QPoint point) | ||
| 352 | { | ||
| 353 | return mapPositionToCoord(point.x(), point.y()); | ||
| 354 | } | ||
| 355 | |||
| 356 | QPoint SceneHolder::CoordToMapPosition(unsigned int x, unsigned int y) | ||
| 357 | { | ||
| 358 | return QPoint(x / Constants::field_size.width, y / Constants::field_size.height); | ||
| 359 | } | ||
| 360 | |||
| 361 | QPoint SceneHolder::CoordToMapPosition(QPoint point) | ||
| 362 | { | ||
| 363 | return CoordToMapPosition(point.x(), point.y()); | ||
| 364 | } | ||
diff --git a/pacman-c++/common/sceneholder.h b/pacman-c++/common/sceneholder.h new file mode 100644 index 0000000..0872837 --- /dev/null +++ b/pacman-c++/common/sceneholder.h | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | #ifndef SCENEHOLDER_H | ||
| 2 | #define SCENEHOLDER_H | ||
| 3 | |||
| 4 | #include "constants.h" | ||
| 5 | #include <QtGui> | ||
| 6 | |||
| 7 | class GameEntity; | ||
| 8 | class Actor; | ||
| 9 | |||
| 10 | class SceneHolder | ||
| 11 | : public QGraphicsScene | ||
| 12 | { | ||
| 13 | Q_OBJECT | ||
| 14 | |||
| 15 | public: | ||
| 16 | SceneHolder(QObject *parent = 0); | ||
| 17 | virtual ~SceneHolder() | ||
| 18 | {}; | ||
| 19 | void reset(); | ||
| 20 | unsigned int pointsLeft(); | ||
| 21 | void updateMap(const Transmission::map_t& map); | ||
| 22 | void updateMap(const Transmission::map_t& map, const unsigned int x, const unsigned int y); | ||
| 23 | void setColor(Color::Color color = Color::none); | ||
| 24 | Color::Color color(); | ||
| 25 | void setEatingOrder(QList<Color::Color> &order); | ||
| 26 | QList<Color::Color> &eatingOrder(); | ||
| 27 | void showEatingText(bool show = true); | ||
| 28 | void showWaitingForPlayers(bool show = true); | ||
| 29 | |||
| 30 | signals: | ||
| 31 | void allPointsRemoved(); | ||
| 32 | |||
| 33 | private slots: | ||
| 34 | void decrementPoints(); | ||
| 35 | |||
| 36 | protected: | ||
| 37 | /* process items that got delayed by one tick */ | ||
| 38 | void processDelayedItems(); | ||
| 39 | /* data conversion */ | ||
| 40 | QPoint mapPositionToCoord(unsigned int x, unsigned int y); | ||
| 41 | QPoint mapPositionToCoord(QPoint point); | ||
| 42 | QPoint CoordToMapPosition(unsigned int x, unsigned int y); | ||
| 43 | QPoint CoordToMapPosition(QPoint point); | ||
| 44 | |||
| 45 | protected: | ||
| 46 | /* map of all pixmap instances */ | ||
| 47 | QVector< QVector<GameEntity *> > visualMap; | ||
| 48 | |||
| 49 | /* map of actors in order to keep track of those instances */ | ||
| 50 | QMap<Color::Color, Actor *> m_actors; | ||
| 51 | |||
| 52 | /* items that got removed/has been eaten | ||
| 53 | * must be remove one tick later | ||
| 54 | */ | ||
| 55 | QList<GameEntity *> m_oldItems; | ||
| 56 | /* we need to store items that killed an actor too (e.g. colored blocks) */ | ||
| 57 | QMap<Color::Color, GameEntity *> m_death; | ||
| 58 | |||
| 59 | /* my local color */ | ||
| 60 | Color::Color m_color; | ||
| 61 | |||
| 62 | /* a actor can only eat his upper neighbour | ||
| 63 | * the order of the neighbours is determined by the colors order (sent from server) | ||
| 64 | * please note that !pl1.canEat(pl2, ...) doesn't necessarily mean that pl2 can eat pl1 | ||
| 65 | * order MUST be in this format: [col1, [col2 ... colN], col1] | ||
| 66 | */ | ||
| 67 | QList<Color::Color> m_eatingorder; | ||
| 68 | |||
| 69 | /* points left before round ends */ | ||
| 70 | unsigned int m_pointsLeft; | ||
| 71 | QGraphicsTextItem *m_overlayText; | ||
| 72 | }; | ||
| 73 | |||
| 74 | #endif // SCENEHOLDER_H | ||
diff --git a/pacman-c++/common/sound/ambient.ogg b/pacman-c++/common/sound/ambient.ogg new file mode 100644 index 0000000..2919513 --- /dev/null +++ b/pacman-c++/common/sound/ambient.ogg | |||
| Binary files differ | |||
diff --git a/pacman-c++/common/sound/die.ogg b/pacman-c++/common/sound/die.ogg new file mode 100644 index 0000000..f6af2e0 --- /dev/null +++ b/pacman-c++/common/sound/die.ogg | |||
| Binary files differ | |||
diff --git a/pacman-c++/common/sound/eating_fruit.ogg b/pacman-c++/common/sound/eating_fruit.ogg new file mode 100644 index 0000000..752864a --- /dev/null +++ b/pacman-c++/common/sound/eating_fruit.ogg | |||
| Binary files differ | |||
diff --git a/pacman-c++/common/sound/eating_ghost.ogg b/pacman-c++/common/sound/eating_ghost.ogg new file mode 100644 index 0000000..a204a2c --- /dev/null +++ b/pacman-c++/common/sound/eating_ghost.ogg | |||
| Binary files differ | |||
diff --git a/pacman-c++/common/sound/intro.ogg b/pacman-c++/common/sound/intro.ogg new file mode 100644 index 0000000..d38f16b --- /dev/null +++ b/pacman-c++/common/sound/intro.ogg | |||
| Binary files differ | |||
diff --git a/pacman-c++/common/sound/waka_waka.ogg b/pacman-c++/common/sound/waka_waka.ogg new file mode 100644 index 0000000..def0d96 --- /dev/null +++ b/pacman-c++/common/sound/waka_waka.ogg | |||
| Binary files differ | |||
diff --git a/pacman-c++/common/style.qss b/pacman-c++/common/style.qss new file mode 100644 index 0000000..1a24459 --- /dev/null +++ b/pacman-c++/common/style.qss | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | QGroupBox#actor1::indicator { | ||
| 2 | background-image: url(:/actor1icon); | ||
| 3 | background-position: top left; | ||
| 4 | background-repeat: no-repeat; | ||
| 5 | width: 16px; | ||
| 6 | height: 14px; | ||
| 7 | } | ||
| 8 | |||
| 9 | QGroupBox#actor2::indicator { | ||
| 10 | background-image: url(:/actor2icon); | ||
| 11 | background-position: top left; | ||
| 12 | background-repeat: no-repeat; | ||
| 13 | width: 16px; | ||
| 14 | height: 14px; | ||
| 15 | } | ||
| 16 | |||
| 17 | QGroupBox#actor3::indicator { | ||
| 18 | background-image: url(:/actor3icon); | ||
| 19 | background-position: top left; | ||
| 20 | background-repeat: no-repeat; | ||
| 21 | width: 16px; | ||
| 22 | height: 14px; | ||
| 23 | } | ||
| 24 | |||
| 25 | QGroupBox#actor4::indicator { | ||
| 26 | background-image: url(:/actor4icon); | ||
| 27 | background-position: top left; | ||
| 28 | background-repeat: no-repeat; | ||
| 29 | width: 16px; | ||
| 30 | height: 14px; | ||
| 31 | } | ||
diff --git a/pacman-c++/common/util.cpp b/pacman-c++/common/util.cpp new file mode 100644 index 0000000..a3426b6 --- /dev/null +++ b/pacman-c++/common/util.cpp | |||
| @@ -0,0 +1,342 @@ | |||
| 1 | #include "util.h" | ||
| 2 | |||
| 3 | namespace Util | ||
| 4 | { | ||
| 5 | Transmission::map_t createUninitialisedMap() | ||
| 6 | { | ||
| 7 | Transmission::map_t map; | ||
| 8 | map = new Transmission::field_t*[Constants::map_size.width]; | ||
| 9 | for (unsigned int i = 0; i < Constants::map_size.width; ++i) | ||
| 10 | map[i] = new Transmission::field_t[Constants::map_size.height]; | ||
| 11 | return map; | ||
| 12 | } | ||
| 13 | |||
| 14 | Transmission::map_t createEmptyMap() | ||
| 15 | { | ||
| 16 | Transmission::map_t map = createUninitialisedMap(); | ||
| 17 | for (unsigned int x = 0; x < Constants::map_size.width; ++x) | ||
| 18 | { | ||
| 19 | for (unsigned int y = 0; y < Constants::map_size.height; ++y) | ||
| 20 | { | ||
| 21 | Transmission::field_t &cur = map[x][y]; | ||
| 22 | cur = Transmission::none; | ||
| 23 | } | ||
| 24 | } | ||
| 25 | return map; | ||
| 26 | } | ||
| 27 | |||
| 28 | void deleteMap(Transmission::map_t map) | ||
| 29 | { | ||
| 30 | for (unsigned int x = 0; x < Constants::map_size.width; ++x) | ||
| 31 | delete[] map[x]; | ||
| 32 | delete[] map; | ||
| 33 | } | ||
| 34 | |||
| 35 | Transmission::map_t createDemoMap() | ||
| 36 | { | ||
| 37 | Transmission::map_t map = createEmptyMap(); | ||
| 38 | |||
| 39 | const char *tmpl[] = { | ||
| 40 | " # # ", | ||
| 41 | " #### ###### # #### # # ###### ### ", | ||
| 42 | " # # ", | ||
| 43 | " # ##### # # # # # ### # # # ", | ||
| 44 | " # # # # # # # # # # ## # # ", | ||
| 45 | " # # # # # # # # ### # # # # ", | ||
| 46 | " # # # # # # # # # # # # ## # ", | ||
| 47 | " # # ### ##### # ### # # # ", | ||
| 48 | " ### # ", | ||
| 49 | " # # ### #### #### #### ##### ", | ||
| 50 | " #### # #..# #..# #..# # # ", | ||
| 51 | " # # ### #..# #..# #### # # # # ", | ||
| 52 | " # # # #..# #..# # # ", | ||
| 53 | " # #### # #### #### # # ##### # ", | ||
| 54 | " # # ", | ||
| 55 | " #### ###### # ##### # ####### ### ", | ||
| 56 | " # # " | ||
| 57 | }; | ||
| 58 | |||
| 59 | for (unsigned int x = 0; x < Constants::map_size.width; ++x) | ||
| 60 | { | ||
| 61 | for (unsigned int y = 0; y < Constants::map_size.height; ++y) | ||
| 62 | { | ||
| 63 | Transmission::field_t &cur = map[x][y]; | ||
| 64 | cur = Transmission::none; | ||
| 65 | if (tmpl[y][x] == '#') | ||
| 66 | cur |= Color::none | Transmission::block; | ||
| 67 | /* this is a simple hack to create areas where no | ||
| 68 | * autoplaced points/actors will be placed (see makePoints) | ||
| 69 | */ | ||
| 70 | else if (tmpl[y][x] == '.') | ||
| 71 | cur |= Transmission::point; | ||
| 72 | } | ||
| 73 | } | ||
| 74 | return map; | ||
| 75 | } | ||
| 76 | |||
| 77 | void placeActors(Transmission::map_t map, unsigned int players, const Color::Color *colors) | ||
| 78 | { | ||
| 79 | #if 0 | ||
| 80 | for(unsigned int i = 0; i < players; ++i) | ||
| 81 | map[i][0] = colors[i] | Transmission::pacman; | ||
| 82 | return; | ||
| 83 | #endif | ||
| 84 | |||
| 85 | int mindistance = Constants::Game::player_minimum_distance; | ||
| 86 | /* this outer loop is used if there are no more valid places left | ||
| 87 | * so we can change mindistance | ||
| 88 | */ | ||
| 89 | QList<QPoint> actors; | ||
| 90 | for(unsigned int i = 0; i < players; ++i) | ||
| 91 | { | ||
| 92 | /* first remove formerly placed actors from map */ | ||
| 93 | foreach(QPoint pos, actors) | ||
| 94 | map[pos.x()][pos.y()] = Transmission::none; | ||
| 95 | actors.clear(); | ||
| 96 | |||
| 97 | /* get list of valid positions */ | ||
| 98 | QList<QPoint> validpos; | ||
| 99 | for (unsigned int x = 0; x < Constants::map_size.width; ++x) | ||
| 100 | { | ||
| 101 | for (unsigned int y = 0; y < Constants::map_size.height; ++y) | ||
| 102 | { | ||
| 103 | Transmission::field_t &cur = map[x][y]; | ||
| 104 | if (cur == Transmission::none) | ||
| 105 | validpos.append(QPoint(x, y)); | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | /* place actors at map */ | ||
| 110 | for(i = 0; i < players; ++i) | ||
| 111 | { | ||
| 112 | int rand = (int) (validpos.size() * (qrand() / (RAND_MAX + 1.0))); | ||
| 113 | QPoint newpos = validpos.at(rand); | ||
| 114 | map[newpos.x()][newpos.y()] = colors[i] | Transmission::pacman; | ||
| 115 | qDebug() << "[Place] Actor" << i << "at" << newpos; | ||
| 116 | actors.append(newpos); | ||
| 117 | validpos.removeAt(rand); | ||
| 118 | |||
| 119 | QMutableListIterator<QPoint> j(validpos); | ||
| 120 | while(j.hasNext()) | ||
| 121 | { | ||
| 122 | j.next(); | ||
| 123 | QPoint tmp = j.value() - newpos; | ||
| 124 | if (tmp.manhattanLength() < mindistance) | ||
| 125 | j.remove(); | ||
| 126 | } | ||
| 127 | |||
| 128 | if (validpos.empty()) | ||
| 129 | { | ||
| 130 | qWarning() << "There are no more valid positions for actors left on the map"; | ||
| 131 | mindistance -= Constants::Game::player_distance_decr; | ||
| 132 | break; | ||
| 133 | } | ||
| 134 | } | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | void fillPoints(Transmission::map_t map, Transmission::field_t type) | ||
| 139 | { | ||
| 140 | /* auto place normal points*/ | ||
| 141 | for (unsigned int x = 0; x < Constants::map_size.width; ++x) | ||
| 142 | { | ||
| 143 | for (unsigned int y = 0; y < Constants::map_size.height; ++y) | ||
| 144 | { | ||
| 145 | Transmission::field_t &cur = map[x][y]; | ||
| 146 | if (cur == Transmission::none) | ||
| 147 | { | ||
| 148 | #if 0 | ||
| 149 | /* use for endround testing */ | ||
| 150 | if (x > 0) | ||
| 151 | continue; | ||
| 152 | #endif | ||
| 153 | cur = type; | ||
| 154 | } | ||
| 155 | else if (cur == Transmission::point) | ||
| 156 | cur = Transmission::none; | ||
| 157 | } | ||
| 158 | } | ||
| 159 | } | ||
| 160 | |||
| 161 | Transmission::field_t actorMovementToTransmission(Actor::Movement mov, Transmission::field_t def) | ||
| 162 | { | ||
| 163 | switch (mov) | ||
| 164 | { | ||
| 165 | case Actor::None: | ||
| 166 | return Transmission::direction_none; | ||
| 167 | break; | ||
| 168 | case Actor::Left: | ||
| 169 | return Transmission::direction_left; | ||
| 170 | break; | ||
| 171 | case Actor::Right: | ||
| 172 | return Transmission::direction_right; | ||
| 173 | break; | ||
| 174 | case Actor::Up: | ||
| 175 | return Transmission::direction_up; | ||
| 176 | break; | ||
| 177 | case Actor::Down: | ||
| 178 | return Transmission::direction_down; | ||
| 179 | break; | ||
| 180 | default: | ||
| 181 | return def; | ||
| 182 | break; | ||
| 183 | } | ||
| 184 | return def; | ||
| 185 | } | ||
| 186 | |||
| 187 | Actor::Movement transmissionMovementToActor(Transmission::field_t field, Actor::Movement def) | ||
| 188 | { | ||
| 189 | switch (field) | ||
| 190 | { | ||
| 191 | case Transmission::direction_none: | ||
| 192 | return Actor::None; | ||
| 193 | break; | ||
| 194 | case Transmission::direction_left: | ||
| 195 | return Actor::Left; | ||
| 196 | break; | ||
| 197 | case Transmission::direction_right: | ||
| 198 | return Actor::Right; | ||
| 199 | break; | ||
| 200 | case Transmission::direction_up: | ||
| 201 | return Actor::Up; | ||
| 202 | break; | ||
| 203 | case Transmission::direction_down: | ||
| 204 | return Actor::Down; | ||
| 205 | break; | ||
| 206 | default: | ||
| 207 | return def; | ||
| 208 | break; | ||
| 209 | } | ||
| 210 | return def; | ||
| 211 | } | ||
| 212 | |||
| 213 | const QString colorToString(Color::Color color) | ||
| 214 | { | ||
| 215 | switch(color) | ||
| 216 | { | ||
| 217 | case Color::none: | ||
| 218 | return "none"; | ||
| 219 | break; | ||
| 220 | case Color::red: | ||
| 221 | return "red"; | ||
| 222 | break; | ||
| 223 | case Color::blue: | ||
| 224 | return "blue"; | ||
| 225 | break; | ||
| 226 | case Color::green: | ||
| 227 | return "green"; | ||
| 228 | break; | ||
| 229 | case Color::yellow: | ||
| 230 | return "yellow"; | ||
| 231 | break; | ||
| 232 | default: | ||
| 233 | return "unknown"; | ||
| 234 | break; | ||
| 235 | } | ||
| 236 | } | ||
| 237 | |||
| 238 | QSharedPointer<QByteArray> createPacket(const ::google::protobuf::MessageLite& packet) | ||
| 239 | { | ||
| 240 | qint64 packetlen = packet.ByteSize(); | ||
| 241 | QSharedPointer<QByteArray> data = QSharedPointer<QByteArray>(new QByteArray); | ||
| 242 | data->resize(packetlen); | ||
| 243 | |||
| 244 | /* use protobuf.SerializeWithCachedSizesToArray() to avoid calling protobuf.ByteSize() again */ | ||
| 245 | ::google::protobuf::uint8 *dataptr = reinterpret_cast<google::protobuf::uint8 *>(data->data()); | ||
| 246 | packet.SerializeWithCachedSizesToArray(dataptr); | ||
| 247 | return data; | ||
| 248 | } | ||
| 249 | |||
| 250 | bool sendPacket(QByteArray *data, ENetPeer *peer, ENetHost *host) | ||
| 251 | { | ||
| 252 | ENetPacket *packet = enet_packet_create(data->data(), data->length(), ENET_PACKET_FLAG_RELIABLE); | ||
| 253 | if (enet_peer_send(peer, 0, packet) < 0) | ||
| 254 | { | ||
| 255 | qDebug() << "[sendPacket] Error while sending packet"; | ||
| 256 | return false; | ||
| 257 | } | ||
| 258 | enet_host_flush(host); | ||
| 259 | return true; | ||
| 260 | } | ||
| 261 | |||
| 262 | bool sendPacket(const ::google::protobuf::MessageLite& packet, ENetPeer *peer, ENetHost *host) | ||
| 263 | { | ||
| 264 | return sendPacket(createPacket(packet).data(), peer, host); | ||
| 265 | } | ||
| 266 | |||
| 267 | QSharedPointer<QByteArray> receivePacket(ENetPacket *packet) | ||
| 268 | { | ||
| 269 | const char *pdata = reinterpret_cast<const char *>(packet->data); | ||
| 270 | QSharedPointer<QByteArray> data = QSharedPointer<QByteArray>(new QByteArray(pdata, packet->dataLength)); | ||
| 271 | return data; | ||
| 272 | } | ||
| 273 | |||
| 274 | int floorLog2(unsigned int n) | ||
| 275 | { | ||
| 276 | if (n == 0) | ||
| 277 | return -1; | ||
| 278 | |||
| 279 | int pos = 0; | ||
| 280 | if (n >= 1<<16) { n >>= 16; pos += 16; } | ||
| 281 | if (n >= 1<< 8) { n >>= 8; pos += 8; } | ||
| 282 | if (n >= 1<< 4) { n >>= 4; pos += 4; } | ||
| 283 | if (n >= 1<< 2) { n >>= 2; pos += 2; } | ||
| 284 | if (n >= 1<< 1) { pos += 1; } | ||
| 285 | return pos; | ||
| 286 | } | ||
| 287 | |||
| 288 | #if 0 | ||
| 289 | void hexdump(void *pAddressIn, long lSize) | ||
| 290 | { | ||
| 291 | char szBuf[100]; | ||
| 292 | long lIndent = 1; | ||
| 293 | long lOutLen, lIndex, lIndex2, lOutLen2; | ||
| 294 | long lRelPos; | ||
| 295 | struct { char *pData; unsigned long lSize; } buf; | ||
| 296 | unsigned char *pTmp,ucTmp; | ||
| 297 | unsigned char *pAddress = (unsigned char *)pAddressIn; | ||
| 298 | |||
| 299 | buf.pData = (char *)pAddress; | ||
| 300 | buf.lSize = lSize; | ||
| 301 | |||
| 302 | while (buf.lSize > 0) | ||
| 303 | { | ||
| 304 | pTmp = (unsigned char *)buf.pData; | ||
| 305 | lOutLen = (int)buf.lSize; | ||
| 306 | if (lOutLen > 16) | ||
| 307 | lOutLen = 16; | ||
| 308 | |||
| 309 | // create a 64-character formatted output line: | ||
| 310 | sprintf(szBuf, " > " | ||
| 311 | " " | ||
| 312 | " %08lX", pTmp-pAddress); | ||
| 313 | lOutLen2 = lOutLen; | ||
| 314 | |||
| 315 | for(lIndex = 1+lIndent, lIndex2 = 53-15+lIndent, lRelPos = 0; | ||
| 316 | lOutLen2; | ||
| 317 | lOutLen2--, lIndex += 2, lIndex2++ | ||
| 318 | ) | ||
| 319 | { | ||
| 320 | ucTmp = *pTmp++; | ||
| 321 | |||
| 322 | sprintf(szBuf + lIndex, "%02X ", (unsigned short)ucTmp); | ||
| 323 | if(!isprint(ucTmp)) ucTmp = '.'; // nonprintable char | ||
| 324 | szBuf[lIndex2] = ucTmp; | ||
| 325 | |||
| 326 | if (!(++lRelPos & 3)) // extra blank after 4 bytes | ||
| 327 | { lIndex++; szBuf[lIndex+2] = ' '; } | ||
| 328 | } | ||
| 329 | |||
| 330 | if (!(lRelPos & 3)) lIndex--; | ||
| 331 | |||
| 332 | szBuf[lIndex ] = '<'; | ||
| 333 | szBuf[lIndex+1] = ' '; | ||
| 334 | |||
| 335 | printf("%s\n", szBuf); | ||
| 336 | |||
| 337 | buf.pData += lOutLen; | ||
| 338 | buf.lSize -= lOutLen; | ||
| 339 | } | ||
| 340 | } | ||
| 341 | #endif | ||
| 342 | } | ||
diff --git a/pacman-c++/common/util.h b/pacman-c++/common/util.h new file mode 100644 index 0000000..1ec82b3 --- /dev/null +++ b/pacman-c++/common/util.h | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | #ifndef UTIL_H | ||
| 2 | #define UTIL_H | ||
| 3 | |||
| 4 | #include "constants.h" | ||
| 5 | #include "actor.h" | ||
| 6 | #include "pacman.pb.h" | ||
| 7 | |||
| 8 | extern "C" { | ||
| 9 | #include "enet/enet.h" | ||
| 10 | } | ||
| 11 | |||
| 12 | namespace Util | ||
| 13 | { | ||
| 14 | Transmission::map_t createUninitialisedMap(); | ||
| 15 | Transmission::map_t createDemoMap(); | ||
| 16 | void placeActors(Transmission::map_t map, unsigned int players, const Color::Color *colors); | ||
| 17 | void fillPoints(Transmission::map_t map, Transmission::field_t type = Transmission::point); | ||
| 18 | Transmission::map_t createEmptyMap(); | ||
| 19 | void deleteMap(Transmission::map_t map); | ||
| 20 | |||
| 21 | Transmission::field_t actorMovementToTransmission(Actor::Movement mov, | ||
| 22 | Transmission::field_t def = Transmission::none); | ||
| 23 | Actor::Movement transmissionMovementToActor(Transmission::field_t field, | ||
| 24 | Actor::Movement def = Actor::None); | ||
| 25 | const QString colorToString(Color::Color color); | ||
| 26 | |||
| 27 | /* send packet with error check and flush */ | ||
| 28 | QSharedPointer<QByteArray> createPacket(const ::google::protobuf::MessageLite& packet); | ||
| 29 | bool sendPacket(QByteArray *data, ENetPeer *peer, ENetHost *host); | ||
| 30 | bool sendPacket(const ::google::protobuf::MessageLite& packet, ENetPeer *peer, ENetHost *host); | ||
| 31 | QSharedPointer<QByteArray> receivePacket(ENetPacket *packet); | ||
| 32 | |||
| 33 | int floorLog2(unsigned int n); | ||
| 34 | |||
| 35 | #if 0 | ||
| 36 | void hexdump(void *pAddressIn, long lSize); | ||
| 37 | #endif | ||
| 38 | } | ||
| 39 | #endif // UTIL_H | ||
