From ce48af53646cd9e7ec762fc1ac176b3aa620b11d Mon Sep 17 00:00:00 2001 From: manuel Date: Thu, 5 May 2011 00:57:07 +0200 Subject: - refactorized the whole project and made a few subprojects - replaced tcp with enet - added connect dialog - some smaller bugfixes --- pacman-c++/common/actor.cpp | 375 ++++++++++++++++++++++++ pacman-c++/common/actor.h | 81 +++++ pacman-c++/common/audio.cpp | 355 ++++++++++++++++++++++ pacman-c++/common/audio.h | 148 ++++++++++ pacman-c++/common/block.cpp | 56 ++++ pacman-c++/common/block.h | 43 +++ pacman-c++/common/bonuspoint.cpp | 38 +++ pacman-c++/common/bonuspoint.h | 24 ++ pacman-c++/common/common.pro | 30 ++ pacman-c++/common/constants.h | 102 +++++++ pacman-c++/common/gameentity.cpp | 9 + pacman-c++/common/gameentity.h | 72 +++++ pacman-c++/common/pacman.qrc | 31 ++ pacman-c++/common/pacman.rc | 1 + pacman-c++/common/pics/actor1.png | Bin 0 -> 1231 bytes pacman-c++/common/pics/actor1icon.png | Bin 0 -> 232 bytes pacman-c++/common/pics/actor2.png | Bin 0 -> 1257 bytes pacman-c++/common/pics/actor2icon.png | Bin 0 -> 233 bytes pacman-c++/common/pics/actor3.png | Bin 0 -> 1226 bytes pacman-c++/common/pics/actor3icon.png | Bin 0 -> 231 bytes pacman-c++/common/pics/actor4.png | Bin 0 -> 1536 bytes pacman-c++/common/pics/actor4icon.png | Bin 0 -> 233 bytes pacman-c++/common/pics/app.ico | Bin 0 -> 174 bytes pacman-c++/common/pics/block0.png | Bin 0 -> 479 bytes pacman-c++/common/pics/block1.png | Bin 0 -> 453 bytes pacman-c++/common/pics/block2.png | Bin 0 -> 476 bytes pacman-c++/common/pics/block3.png | Bin 0 -> 452 bytes pacman-c++/common/pics/block4.png | Bin 0 -> 471 bytes pacman-c++/common/pics/bonuspoints.png | Bin 0 -> 642 bytes pacman-c++/common/pics/pacman10-hp-sprite-2.png | Bin 0 -> 6857 bytes pacman-c++/common/pics/points.png | Bin 0 -> 188 bytes pacman-c++/common/pics/soundoff.xpm | 15 + pacman-c++/common/pics/soundon.xpm | 15 + pacman-c++/common/pixmapitem.cpp | 77 +++++ pacman-c++/common/pixmapitem.h | 32 ++ pacman-c++/common/point.cpp | 33 +++ pacman-c++/common/point.h | 24 ++ pacman-c++/common/sceneholder.cpp | 364 +++++++++++++++++++++++ pacman-c++/common/sceneholder.h | 74 +++++ pacman-c++/common/sound/ambient.ogg | Bin 0 -> 23243 bytes pacman-c++/common/sound/die.ogg | Bin 0 -> 20271 bytes pacman-c++/common/sound/eating_fruit.ogg | Bin 0 -> 8774 bytes pacman-c++/common/sound/eating_ghost.ogg | Bin 0 -> 9238 bytes pacman-c++/common/sound/intro.ogg | Bin 0 -> 45705 bytes pacman-c++/common/sound/waka_waka.ogg | Bin 0 -> 25855 bytes pacman-c++/common/style.qss | 31 ++ pacman-c++/common/util.cpp | 342 +++++++++++++++++++++ pacman-c++/common/util.h | 39 +++ 48 files changed, 2411 insertions(+) create mode 100644 pacman-c++/common/actor.cpp create mode 100644 pacman-c++/common/actor.h create mode 100644 pacman-c++/common/audio.cpp create mode 100644 pacman-c++/common/audio.h create mode 100644 pacman-c++/common/block.cpp create mode 100644 pacman-c++/common/block.h create mode 100644 pacman-c++/common/bonuspoint.cpp create mode 100644 pacman-c++/common/bonuspoint.h create mode 100644 pacman-c++/common/common.pro create mode 100644 pacman-c++/common/constants.h create mode 100644 pacman-c++/common/gameentity.cpp create mode 100644 pacman-c++/common/gameentity.h create mode 100644 pacman-c++/common/pacman.qrc create mode 100644 pacman-c++/common/pacman.rc create mode 100644 pacman-c++/common/pics/actor1.png create mode 100644 pacman-c++/common/pics/actor1icon.png create mode 100644 pacman-c++/common/pics/actor2.png create mode 100644 pacman-c++/common/pics/actor2icon.png create mode 100644 pacman-c++/common/pics/actor3.png create mode 100644 pacman-c++/common/pics/actor3icon.png create mode 100644 pacman-c++/common/pics/actor4.png create mode 100644 pacman-c++/common/pics/actor4icon.png create mode 100644 pacman-c++/common/pics/app.ico create mode 100644 pacman-c++/common/pics/block0.png create mode 100644 pacman-c++/common/pics/block1.png create mode 100644 pacman-c++/common/pics/block2.png create mode 100644 pacman-c++/common/pics/block3.png create mode 100644 pacman-c++/common/pics/block4.png create mode 100644 pacman-c++/common/pics/bonuspoints.png create mode 100644 pacman-c++/common/pics/pacman10-hp-sprite-2.png create mode 100644 pacman-c++/common/pics/points.png create mode 100644 pacman-c++/common/pics/soundoff.xpm create mode 100644 pacman-c++/common/pics/soundon.xpm create mode 100644 pacman-c++/common/pixmapitem.cpp create mode 100644 pacman-c++/common/pixmapitem.h create mode 100644 pacman-c++/common/point.cpp create mode 100644 pacman-c++/common/point.h create mode 100644 pacman-c++/common/sceneholder.cpp create mode 100644 pacman-c++/common/sceneholder.h create mode 100644 pacman-c++/common/sound/ambient.ogg create mode 100644 pacman-c++/common/sound/die.ogg create mode 100644 pacman-c++/common/sound/eating_fruit.ogg create mode 100644 pacman-c++/common/sound/eating_ghost.ogg create mode 100644 pacman-c++/common/sound/intro.ogg create mode 100644 pacman-c++/common/sound/waka_waka.ogg create mode 100644 pacman-c++/common/style.qss create mode 100644 pacman-c++/common/util.cpp create mode 100644 pacman-c++/common/util.h (limited to 'pacman-c++/common') 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 @@ +#include "actor.h" +#include "util.h" +#include +#include +#include + +static QVariant myBooleanInterpolator(const bool &start, const bool &end, qreal progress) +{ + return (progress == 1.0) ? end : start; +} + +Actor::Actor(Color::Color color, bool local, QGraphicsItem *parent) + : GameEntity(color, parent), m_direction(Actor::None), m_local(local), m_reset(true), + m_wakaPlayer(NULL), m_roundPoints(0), m_gamePoints(0) +{ + m_type = Type; + + /* DON'T set any pixmap here. we've a pixmap in the animation + * but we need a sprite for the collision detection + */ + setSprite(Constants::sprite_margin, Constants::sprite_margin, Constants::field_size.width, Constants::field_size.height); + /* higher player "over" lower player */ + setZValue(m_color * 10); + + /* rest of the ctor is only for clients */ + if (Constants::server) + return; + + /* our actor pixmap. created after server part */ + m_pix = ":/" + QString("actor%1").arg(Util::floorLog2(color) + 1); + + /* setup icon for player */ + m_icon.setPixmap(m_pix); + m_icon.setSprite(Constants::sprite_margin, Constants::sprite_margin, Constants::field_size.width, Constants::field_size.height); + + /* setup static images first + * they are visible if no animation is running + * and will be the first in m_images + */ + for (int i = 0; i < 5; i++) + { + PixmapItem *img = new PixmapItem(m_pix, this); + m_images.append(img); + int x = i * Constants::sprite_offset + Constants::sprite_margin; + int y = Actor::None * Constants::sprite_offset + Constants::sprite_margin; + img->setSprite(x, y, Constants::field_size.width, Constants::field_size.height); + img->setVisible(false); + } + + /* setup animation stuff */ + qRegisterAnimationInterpolator(myBooleanInterpolator); + m_moving = new QParallelAnimationGroup(this); + m_eating.append(NULL); // Actor::None + m_eating.append(setupEatingAnimation(Actor::Left)); + m_eating.append(setupEatingAnimation(Actor::Right)); + m_eating.append(setupEatingAnimation(Actor::Up)); + m_eating.append(setupEatingAnimation(Actor::Down)); + + /* dieing animation */ + m_dieing = new QSequentialAnimationGroup(this); + for (int i = 0; i < 11; i++) + { + PixmapItem *img = new PixmapItem(m_pix, this); + m_images.append(img); + int x = i * Constants::sprite_offset + Constants::sprite_margin; + int y = 5 * Constants::sprite_offset + Constants::sprite_margin; + img->setSprite(x, y, Constants::field_size.width, Constants::field_size.height); + img->setVisible(false); + + QPropertyAnimation *fadein = new QPropertyAnimation(img, "visible", m_dieing); + fadein->setDuration(0); + fadein->setEndValue(true); + + m_dieing->addPause(130); + + QPropertyAnimation *fadeout = new QPropertyAnimation(img, "visible", m_dieing); + fadeout->setDuration(0); + fadeout->setEndValue(false); + } + + /* setup waka sound */ + if (local) + m_wakaPlayer = new GaplessAudioPlayer(Sound::WakaWaka, 100, this); + + /* make the picture showing the current direction visible */ + m_images[m_direction]->setVisible(true); +} + +QSequentialAnimationGroup *Actor::setupEatingAnimation(Actor::Movement direction) +{ + QSequentialAnimationGroup *eating = new QSequentialAnimationGroup(this); + eating->setLoopCount(-1); + for (int i = 0; i < 4; i++) + { + PixmapItem *img = new PixmapItem(m_pix, this); + m_images.append(img); + int x = i * Constants::sprite_offset + Constants::sprite_margin; + int y = direction * Constants::sprite_offset + Constants::sprite_margin; + img->setSprite(x, y, Constants::field_size.width, Constants::field_size.height); + img->setVisible(false); + + QPropertyAnimation *fadein = new QPropertyAnimation(img, "visible", eating); + fadein->setDuration(0); + fadein->setEndValue(true); + + eating->addPause(100); + + QPropertyAnimation *fadeout = new QPropertyAnimation(img, "visible", eating); + fadeout->setDuration(0); + fadeout->setEndValue(false); + + QPropertyAnimation *move = new QPropertyAnimation(img, "pos", m_moving); + move->setDuration(Constants::tick - 30); + move->setEndValue(QPoint(0, 0)); + } + + return eating; +} + +PixmapItem &Actor::icon() +{ + return m_icon; +} + +const QString Actor::iconStr() +{ + return QString(":/actor%1icon").arg(Util::floorLog2(m_color) + 1); +} + +Actor::Movement Actor::direction() +{ + return m_direction; +} + + +void Actor::setDirection(Movement direction) +{ + m_direction = direction; +} + +bool Actor::isLocal() +{ + return m_local; +} + +bool Actor::hadReset() +{ + if (!m_reset) + return false; + m_reset = false; + return true; +} + +void Actor::reset() +{ + m_reset = true; + if (Constants::server) + { + m_direction = Actor::None; + return; + } + + stopEating(); + m_moving->stop(); + setZValue(m_color * 10); + m_dieing->stop(); + /* hide all pictures */ + for (int i = 0; i < m_images.size(); ++i) + m_images.at(i)->setVisible(false); + + if (m_eating[m_direction] != NULL) + m_eating[m_direction]->stop(); + + m_direction = Actor::None; + m_images[m_direction]->setVisible(true); +} + +void Actor::move(QPoint newpos) +{ + QPoint oldpos = pos().toPoint(); + Actor::Movement direction = Actor::None; + if (oldpos.x() - newpos.x() < 0) + direction = Actor::Right; + else if (oldpos.x() - newpos.x() > 0) + direction = Actor::Left; + else if (oldpos.y() - newpos.y() < 0) + direction = Actor::Down; + else if (oldpos.y() - newpos.y() > 0) + direction = Actor::Up; + move(direction); +} + +void Actor::move(Actor::Movement direction) +{ + if (Constants::server) + return moveByServer(direction); + + /* stop current animation if direction changed */ + if (direction != m_direction) + { + /* hide all pictures */ + for (int i = 0; i < m_images.size(); ++i) + m_images.at(i)->setVisible(false); + + if (m_eating[m_direction] != NULL) + m_eating[m_direction]->stop(); + } + + QPointF endpos = movementToPoint(direction); + switch(direction) + { + case Actor::Left: + case Actor::Right: + endpos *= Constants::field_size.width; + break; + case Actor::Up: + case Actor::Down: + endpos *= Constants::field_size.height; + break; + case Actor::None: + default: + break; + } + + for(int i = 0; i < m_moving->animationCount(); ++i) + { + QPropertyAnimation *move = dynamic_cast(m_moving->animationAt(i)); + move->setStartValue(QPoint(0, 0) - endpos); + } + setPos(pos() + endpos); + + /* start new animation if direction changed */ + if (direction != m_direction) + { + if (direction == Actor::None) + m_images[m_direction]->setVisible(true); + else + m_eating[direction]->start(); + } + + /* start moving animation */ + if (direction != Actor::None) + m_moving->start(); + + m_direction = direction; +} + +void Actor::moveByServer(Actor::Movement direction) +{ + QPointF endpos = movementToPoint(direction); + switch(direction) + { + case Actor::Left: + case Actor::Right: + endpos *= Constants::field_size.width; + break; + case Actor::Up: + case Actor::Down: + endpos *= Constants::field_size.height; + break; + case Actor::None: + default: + break; + } + setPos(pos() + endpos); + m_direction = direction; +} + +bool Actor::isMoving() +{ + return (m_moving->state() == QAbstractAnimation::Running); +} + +bool Actor::canEat(Actor *other, const QList &order) +{ + if (other == NULL || order.empty() || m_color == other->color()) + return false; + + int idx = order.indexOf(m_color); + return (order.at(idx + 1) == other->color()); +} + +void Actor::onDie(Actor *other) +{ + other->eatingPacman(); + die(); +} + +void Actor::die() +{ + if (Constants::server) + return; + + reset(); + m_images[m_direction]->setVisible(false); + setZValue(zValue() * 10); + m_dieing->start(); + if (m_local) + AudioManager::self()->play(Sound::Die); +} + +void Actor::eatingFruit() +{ + if (!m_local) + return; + AudioManager::self()->play(Sound::EatingFruit); +} + +void Actor::eatingPacman() +{ + if (!m_local) + return; + AudioManager::self()->play(Sound::EatingGhost); +} + +void Actor::startEating() +{ + if (!m_local || !m_wakaPlayer->isWorking()) + return; + m_wakaPlayer->play(); +} + +void Actor::stopEating() +{ + if (!m_local || !m_wakaPlayer->isWorking()) + return; + m_wakaPlayer->pause(); +} + +unsigned int Actor::getRoundPoints() +{ + return m_roundPoints; +} + +unsigned int Actor::getGamePoints() +{ + return m_gamePoints; +} + +void Actor::addRoundPoints(unsigned int amount) +{ + m_roundPoints += amount; +} + +void Actor::finishRound(bool died) +{ + if (!died) + m_gamePoints += m_roundPoints; + m_roundPoints = 0; +} + +QPoint Actor::movementToPoint(const Actor::Movement direction) +{ + QPoint endpos(0,0); + switch (direction) + { + case Actor::Up: + endpos = QPoint(0, -1); + break; + case Actor::Down: + endpos = QPoint(0, 1); + break; + case Actor::Left: + endpos = QPoint(-1, 0); + break; + case Actor::Right: + endpos = QPoint(1, 0); + break; + case Actor::None: + break; + default: + Q_ASSERT(false); + } + return endpos; +} 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 @@ +#ifndef ACTOR_H +#define ACTOR_H + +#include "gameentity.h" +#include "constants.h" +#include "audio.h" +#include +#include +#include + +class Actor + : public GameEntity +{ +Q_OBJECT + +public: + enum Movement + { + None = 0, + Left, + Right, + Up, + Down, + }; + + enum + { + Type = UserType + Transmission::pacman + }; + + Actor(Color::Color color, bool local = false, QGraphicsItem *parent = 0); + virtual ~Actor() + {}; + + PixmapItem &icon(); + const QString iconStr(); + Movement direction(); + void setDirection(Movement direction); + void reset(); + bool hadReset(); + bool isLocal(); + void move(Movement direction); + void move(QPoint newpos); + bool isMoving(); + void die(); + void eatingFruit(); + void eatingPacman(); + void startEating(); + void stopEating(); + bool canEat(Actor *other, const QList &order); + virtual void onDie(Actor *); + + unsigned int getRoundPoints(); + unsigned int getGamePoints(); + void addRoundPoints(unsigned int amount); + void finishRound(bool died = false); + + static QPoint movementToPoint(const Movement direction); + +private: + void moveByServer(Movement direction); + QSequentialAnimationGroup *setupEatingAnimation(Actor::Movement direction); + +private: + QPixmap m_pix; + Movement m_direction; + PixmapItem m_icon; + bool m_local; + bool m_reset; + GaplessAudioPlayer *m_wakaPlayer; + + unsigned int m_roundPoints; + unsigned int m_gamePoints; + + QList m_images; + QList m_eating; + QParallelAnimationGroup *m_moving; + QSequentialAnimationGroup *m_dieing; +}; + +#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 @@ +#include "audio.h" +#include "constants.h" +#include +#include +#include +#include +#include +#include + +/* the universe's only audio manager */ +AudioManager *AudioManager::m_instance = NULL; +bool AudioManager::m_working = false; + +AudioManager::AudioManager() + : m_muted(true) +{ + if (Constants::server) + { + qDebug() << "Server has no sound"; + m_players.append(new AudioPlayer(this)); + } + else + { + preload(); + AudioPlayer *firstplayer = new AudioPlayer(this); + firstplayer->test(m_sounds[Sound::WakaWaka]); + m_working = firstplayer->m_working; + m_players.append(firstplayer); + } + m_muted = false; +} + +AudioManager *AudioManager::self() +{ + if (m_instance == NULL) + m_instance = new AudioManager(); + return m_instance; +} + +bool AudioManager::isWorking() const +{ + return m_working; +} + +void AudioManager::setMuted(bool mute) +{ + if (!isWorking()) + return; + + if (mute == m_muted) + return; + + for(int i = 0; i < m_players.count(); ++i) + m_players.at(i)->setMuted(mute); + m_muted = mute; + emit mutedChanged(mute); +} + +bool AudioManager::isMuted() const +{ + return m_muted; +} + +void AudioManager::pause() +{ + if (!isWorking()) + return; + for(int i = 0; i < m_players.count(); ++i) + m_players.at(i)->pause(); +} + +void AudioManager::stop() +{ + if (!isWorking()) + return; + for(int i = 0; i < m_players.count(); ++i) + m_players.at(i)->stop(); +} + +void AudioManager::clear() +{ + if (!isWorking()) + return; + for(int i = 0; i < m_players.count(); ++i) + m_players.at(i)->clear(); +} + +void AudioManager::clearQueue() const +{ + if (!isWorking()) + return; + for(int i = 0; i < m_players.count(); ++i) + m_players.at(i)->clearQueue(); +} + +AudioPlayer *AudioManager::audioPlayer() +{ + return m_players.at(0); +} + +void AudioManager::play(Sound::Type sound, bool wait) +{ + audioPlayer()->play(sound, wait); +} + +void AudioManager::enqueue(Sound::Type sound) +{ + if (!isWorking()) + return; + audioPlayer()->enqueue(Phonon::MediaSource(m_sounds[sound])); +} + +void AudioManager::registerAudioPlayer(AudioPlayer *player) +{ + player->setMuted(m_muted); + connect(player, SIGNAL(destroyed(QObject *)), this, SLOT(unregisterAudioPlayer_helper(QObject *))); + m_players.append(player); +} + +void AudioManager::unregisterAudioPlayer(AudioPlayer *player) +{ + disconnect(player, SIGNAL(destroyed(QObject *)), this, SLOT(unregisterAudioPlayer_helper(QObject *))); + m_players.removeAll(player); +} + +void AudioManager::unregisterAudioPlayer_helper(QObject *player) +{ + unregisterAudioPlayer(static_cast(player)); +} + +void AudioManager::preload() +{ + m_sounds.clear(); + QDir sounds(":/sound"); + for(unsigned i = 1; i <= sounds.count(); ++i) + m_sounds.append(new QFile(QString(":/sound/sound%1").arg(i), this)); +} + +QFile *AudioManager::sound(Sound::Type sound) +{ + if (!isWorking()) + return NULL; + return m_sounds.at(sound); +} + +/* --------------------------------------------------------------- */ + +AudioPlayer::AudioPlayer(QObject *parent) + : Phonon::MediaObject(parent), m_working(false) +{ + if (!Constants::server) + { + m_working = AudioManager::m_working; + m_output = new Phonon::AudioOutput(Phonon::MusicCategory, this); + Phonon::createPath(this, m_output); + } +} + +bool AudioPlayer::isWorking() const +{ + return m_working; +} + +void AudioPlayer::setMuted(bool mute) +{ + m_output->setMuted(mute); +} + +bool AudioPlayer::isMuted() const +{ + return m_output->isMuted(); +} + +void AudioPlayer::setLoop(QFile *sound) +{ + if (!isWorking()) + return; + + if (sound == NULL) + { + disconnect(this, SIGNAL(aboutToFinish()), this, SLOT(loopEnqueue())); + return; + } + + m_loopsound = sound; + connect(this, SIGNAL(aboutToFinish()), this, SLOT(loopEnqueue())); + setCurrentSource(Phonon::MediaSource(m_loopsound)); + enqueue(Phonon::MediaSource(m_loopsound)); +} + +void AudioPlayer::setLoop(Sound::Type sound) +{ + setLoop(AudioManager::self()->sound(sound)); +} + +void AudioPlayer::play() +{ + Phonon::MediaObject::play(); +} + +void AudioPlayer::play(Sound::Type sound, bool wait) +{ + if (m_working) + { + setCurrentSource(Phonon::MediaSource(AudioManager::self()->sound(sound))); + play(); + } + else if (wait) + { + QTimer *timer = new QTimer(this); + timer->setSingleShot(true); + unsigned int interval = Sound::length[sound]; + /* add a small delay server side only */ + if (Constants::server) + interval += Constants::tick; + timer->setInterval(interval); + connect(timer, SIGNAL(timeout()), this, SLOT(finished_ex())); + timer->start(); + } +} + +/* this is a simple hack to check if phonon can actually play sounds.. */ +void AudioPlayer::test(QFile *testsound) +{ + stop(); + m_output->setVolume(0); + setCurrentSource(Phonon::MediaSource(testsound)); + connect(this, SIGNAL(stateChanged(Phonon::State,Phonon::State)), this, SLOT(stateChanged_ex(Phonon::State,Phonon::State))); + play(); + + QTimer timer; + timer.setSingleShot(true); + connect(&timer, SIGNAL(timeout()), this, SLOT(testFinished())); + timer.start(500); + while(timer.isActive()) + { + qApp->processEvents(); + Sleeper::msleep(1); + } + clear(); +} + +void AudioPlayer::finished_ex() +{ + emit finished(); +} + +void AudioPlayer::stateChanged_ex(Phonon::State newstate, Phonon::State /* oldstate */) +{ + if (newstate != Phonon::ErrorState) + { + m_working = true; + m_output->setVolume(1); + qDebug() << "Sound is working for you!"; + } + disconnect(this, SIGNAL(stateChanged(Phonon::State, Phonon::State)), this, SLOT(stateChanged_ex(Phonon::State, Phonon::State))); + stop(); +} + +void AudioPlayer::testFinished() +{ + if (!m_working) + qWarning() << "There's no sound for you :("; + disconnect(this, SIGNAL(stateChanged(Phonon::State, Phonon::State)), this, SLOT(stateChanged_ex(Phonon::State, Phonon::State))); +} + +void AudioPlayer::loopEnqueue() +{ + enqueue(Phonon::MediaSource(m_loopsound)); +} + +/* --------------------------------------------------------------- */ + +GaplessAudioPlayer::GaplessAudioPlayer(Sound::Type sound, qint32 mark, QObject *parent) + : QObject(parent), m_sound(sound) +{ + m_working = AudioManager::m_working; + if (!m_working) + return; + + m_player1 = new AudioPlayer(this); + m_player2 = new AudioPlayer(this); + + m_player2->setPrefinishMark(mark); + m_player1->setPrefinishMark(mark); + + connect(m_player1, SIGNAL(prefinishMarkReached(qint32)), this, SLOT(startPlayer2())); + connect(m_player2, SIGNAL(prefinishMarkReached(qint32)), this, SLOT(startPlayer1())); + + AudioManager::self()->registerAudioPlayer(m_player1); + AudioManager::self()->registerAudioPlayer(m_player2); +} + +bool GaplessAudioPlayer::isWorking() const +{ + return m_working; +} + +void GaplessAudioPlayer::setMuted(bool mute) +{ + if (!m_working) + return; + m_player1->setMuted(mute); + m_player2->setMuted(mute); +} + +bool GaplessAudioPlayer::isMuted() const +{ + return m_player1->isMuted() && m_player2->isMuted(); +} + +void GaplessAudioPlayer::play() +{ + if (!m_working) + return; + if (m_player1->state() != Phonon::PlayingState && m_player2->state() != Phonon::PlayingState) + startPlayer1(); +} + +void GaplessAudioPlayer::pause() +{ + if (!m_working) + return; + if (m_player1->state() != Phonon::PausedState) + m_player1->pause(); + if (m_player2->state() != Phonon::PausedState) + m_player2->pause(); +} + +void GaplessAudioPlayer::startPlayer1() +{ + m_player1->play(m_sound); +} + +void GaplessAudioPlayer::startPlayer2() +{ + m_player2->play(m_sound); +} + +/* --------------------------------------------------------------- */ + +void AudioPlayer::Sleeper::sleep(unsigned long secs) +{ + QThread::sleep(secs); +} + +void AudioPlayer::Sleeper::msleep(unsigned long msecs) +{ + QThread::msleep(msecs); +} + +void AudioPlayer::Sleeper::usleep(unsigned long usecs) +{ + QThread::usleep(usecs); +} 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 @@ +#ifndef AUDIO_H +#define AUDIO_H + +#include +#include +#include +#include +#include + +namespace Phonon +{ + class AudioOutput; +} + +namespace Sound +{ + enum Type + { + Intro = 0, + WakaWaka, + EatingFruit, + EatingGhost, + Die, + Ambient + }; + + const unsigned int length[] = { + 4310, 2090, 570, 570, 1720, + }; +}; + +/* --------------------------------------------------------------- */ + +class AudioPlayer + : public Phonon::MediaObject +{ + Q_OBJECT + friend class AudioManager; + +private: + class Sleeper + : public QThread + { + public: + static void sleep(unsigned long secs); + static void msleep(unsigned long msecs); + static void usleep(unsigned long usecs); + }; + +public: + AudioPlayer(QObject *parent = 0); + bool isWorking() const; + void setMuted(bool mute = true); + bool isMuted() const; + void setLoop(Sound::Type sound); + void play(); + void play(Sound::Type sound, bool wait = false); + +protected: + void test(QFile *testsound); + void setLoop(QFile *sound); + +public slots: + void loopEnqueue(); + +protected slots: + void finished_ex(); + void testFinished(); + void stateChanged_ex(Phonon::State newstate, Phonon::State oldstate); + +protected: + bool m_working; + QFile *m_loopsound; + Phonon::AudioOutput *m_output; +}; + +/* --------------------------------------------------------------- */ + +class GaplessAudioPlayer + : public QObject +{ + Q_OBJECT + +public: + GaplessAudioPlayer(Sound::Type sound, qint32 mark, QObject *parent = 0); + bool isWorking() const; + void setMuted(bool mute = true); + bool isMuted() const; + void play(); + void pause(); + +protected slots: + void startPlayer1(); + void startPlayer2(); + +protected: + bool m_working; + Sound::Type m_sound; + AudioPlayer *m_player1; + AudioPlayer *m_player2; +}; + +/* --------------------------------------------------------------- */ + +class AudioManager + : public QObject +{ + Q_OBJECT + friend class AudioPlayer; + friend class GaplessAudioPlayer; + +public: + AudioManager(); + static AudioManager *self(); + bool isWorking() const; + void setMuted(bool mute = true); + bool isMuted() const; + void pause(); + void stop(); + void clear(); + void clearQueue() const; + + AudioPlayer *audioPlayer(); + void play(Sound::Type sound, bool wait = false); + void enqueue(Sound::Type sound); + + void registerAudioPlayer(AudioPlayer *player); + void unregisterAudioPlayer(AudioPlayer *player); + +signals: + void mutedChanged(bool muted); + +private slots: + void unregisterAudioPlayer_helper(QObject *player); + +private: + void preload(); + QFile *sound(Sound::Type sound); + +private: + bool m_muted; + static bool m_working; + static AudioManager *m_instance; + QList m_sounds; + QList m_players; +}; + +#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 @@ +#include "block.h" +#include "constants.h" +#include "actor.h" +#include "util.h" +#include + +QMap Block::m_pixmaps; + +Block::Block(Color::Color color, unsigned int neighbours, QGraphicsItem *parent) + : GameEntity(color, parent), m_neighbours(neighbours) +{ + m_type = Type; + + /* empty object for servers */ + if (Constants::server) + return; + + if (m_pixmaps.find(color) == m_pixmaps.end()) + { + unsigned int colid = (color == Color::none) ? 0 : Util::floorLog2(color) + 1; + QString pixmapName = ":/" + QString("block%1").arg(colid); + m_pixmaps[color] = QPixmap(pixmapName); + } + setPixmap(m_pixmaps.find(color).value()); + setNeighbours(m_neighbours); +} + +unsigned int Block::neighbours() +{ + return m_neighbours; +} + +void Block::setNeighbours(unsigned int neighbours) +{ + m_neighbours = neighbours; + setSprite(neighbours * Constants::sprite_offset, 0, Constants::field_size.width, Constants::field_size.height); +} + +bool Block::checkEnter(Actor * /* actor */) +{ + if (m_color == Color::none) + return false; + return true; +} + +GameEntity::EnteredState Block::enter(Actor *actor) +{ + if (m_color != Color::none && m_color != actor->color()) + return DestroyedActor; + return Nothing; +} + +void Block::onDie(Actor *actor) +{ + actor->die(); +} 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 @@ +#ifndef BLOCK_H +#define BLOCK_H + +#include "gameentity.h" +#include "constants.h" +#include + +class Block + : public GameEntity +{ +public: + enum Neighbour + { + None = 0, + Left = (1 << 0), + Right = (1 << 1), + Up = (1 << 2), + Down = (1 << 3) + }; + + enum + { + Type = UserType + Transmission::block + }; + +public: + Block(Color::Color color, unsigned int neighbours = None, QGraphicsItem *parent = 0); + virtual ~Block() + {}; + + unsigned int neighbours(); + void setNeighbours(unsigned int neighbours); + virtual bool checkEnter(Actor *actor); + virtual EnteredState enter(Actor *actor); + virtual void onDie(Actor *); + +private: + // map for saving QPixmaps for reuse + static QMap m_pixmaps; + unsigned int m_neighbours; +}; + +#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 @@ +#include "bonuspoint.h" +#include "constants.h" +#include "actor.h" + +#define BONUSPOINTS_NUM_SPRITES 4 + +namespace +{ + QPixmap *pixmap = NULL; +} + +BonusPoint::BonusPoint(QGraphicsItem *parent) + : GameEntity(parent) +{ + m_type = Type; + + /* empty object for servers */ + if (Constants::server) + return; + + if (pixmap == NULL) + pixmap = new QPixmap(":/bonuspoints"); + setPixmap(*pixmap); + + int rand = (int) (BONUSPOINTS_NUM_SPRITES * (qrand() / (RAND_MAX + 1.0))); + setSprite(rand * 20 + Constants::sprite_margin, Constants::sprite_margin, Constants::field_size.width, Constants::field_size.height); +} + +GameEntity::EnteredState BonusPoint::enter(Actor *actor) +{ + actor->addRoundPoints(Constants::Game::bonus_point_value); + return DestroyedEntity; +} + +void BonusPoint::onDie(Actor *actor) +{ + actor->eatingFruit(); +} 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 @@ +#ifndef BONUSPOINT_H +#define BONUSPOINT_H + +#include "gameentity.h" + +class BonusPoint + : public GameEntity +{ +public: + enum + { + Type = UserType + Transmission::bonuspoint + }; + +public: + BonusPoint(QGraphicsItem *parent=0); + virtual ~BonusPoint() + {}; + + virtual EnteredState enter(Actor *actor); + virtual void onDie(Actor *actor); +}; + +#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 @@ +TEMPLATE = lib +CONFIG += staticlib + +include(../common.pri) + +SOURCES += pixmapitem.cpp \ + actor.cpp \ + block.cpp \ + bonuspoint.cpp \ + point.cpp \ + audio.cpp \ + sceneholder.cpp \ + util.cpp \ + gameentity.cpp +HEADERS += pixmapitem.h \ + actor.h \ + block.h \ + bonuspoint.h \ + constants.h \ + point.h \ + audio.h \ + sceneholder.h \ + util.h \ + gameentity.h + +OTHER_FILES += style.qss \ + pacman.rc + +RESOURCES += pacman.qrc +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 @@ +#ifndef CONSTANTS_H +#define CONSTANTS_H +#include + +namespace Constants { + const struct + { + const unsigned int width; + const unsigned int height; + } + field_size = { 16, 16 }, + map_size = { 35, 17 }, + map_size_pixel = { field_size.width * map_size.width, + field_size.height * map_size.height }; + const unsigned int sprite_margin = 2; + const unsigned int sprite_offset = 20; + const unsigned int tick = 250; // ms + extern bool server; + + namespace Networking + { + const unsigned int port = 7321; + const unsigned int connection_timeout = 3000; + const unsigned int packet_timeout = 3000; + } + + namespace Game + { + const unsigned int bonus_point_value = 100; + const unsigned int point_value = 10; + /* players will be placed with this minimum manhattan distance */ + const unsigned int player_minimum_distance = 5; + /* if the distance above isn't possible, decrease the distance by this value */ + const unsigned int player_distance_decr = 2; + /* there's a chance of 1:30 that a bonus point will be added (with one actor) */ + const unsigned int bouns_point_chance = 30; + /* every additional player will raise the chance of a bonus point by that factor */ + const unsigned int bouns_point_chance_playerfactor = 3; + /* there's a chance of 1:5 that a block will be colorized */ + const unsigned int colorize_block_chance = 5; + /* how long colorized blocks will stay colorized */ + const unsigned int colorize_block_tickcount_min = 50; + const unsigned int colorize_block_tickcount_max = 100; + } + + namespace AI + { + /* bots minimum manhatten distance before other players will be recognized */ + const unsigned int player_minimum_distance = 4; + /* weight values used to determine new direction of bot */ + const unsigned int weight_afraid = 50; + const unsigned int weight_hunt = 10; + const unsigned int weight_bonus_point = 3; + const unsigned int weight_point = 1; + const unsigned int weight_colorblock = 5; + } +} + +namespace Color +{ + enum Color + { + none = 0, + red = (1 << 0), + blue = (1 << 1), + green = (1 << 2), + yellow = (1 << 3) + }; + + /* colororder used in protocol and gui */ + const Color order[] = + { Color::red, Color::blue, Color::green, Color::yellow, Color::none }; +} + +// constants for data transmission to client +namespace Transmission +{ + typedef unsigned int field_t; + typedef unsigned int mask_t; + + const field_t none = 0; + const field_t block = (1 << 4); + const field_t point = (1 << 5); + const field_t bonuspoint = (1 << 6); + const field_t pacman = (1 << 7); + const field_t empty = (1 << 8); // explicit empty for update + const field_t death = (1 << 9); + + const field_t direction_none = 0; + const field_t direction_left = (1 << 10); + const field_t direction_right = (1 << 11); + const field_t direction_up = (1 << 12); + const field_t direction_down = (1 << 13); + + const mask_t color_mask = Color::none | Color::red | Color::blue | Color::green | Color::yellow; + const mask_t type_mask = block | bonuspoint; + const mask_t direction_mask = direction_none | direction_left | direction_right | direction_up | direction_down; + + typedef field_t** map_t; +} + +#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 @@ +#include "gameentity.h" + +GameEntity::GameEntity(Color::Color color, QGraphicsItem *parent) + : PixmapItem(parent), m_type(Type), m_color(color) +{} + +GameEntity::GameEntity(QGraphicsItem *parent) + : PixmapItem(parent), m_type(Type), m_color(Color::none) +{} 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 @@ +#ifndef GAMEENTITY_H +#define GAMEENTITY_H + +#include "constants.h" +#include "pixmapitem.h" +#include +#include + +class Actor; + +/** + * Base class for entities that interact in the game + */ +class GameEntity + : public PixmapItem +{ +public: + enum + { + Type = UserType + 1 + }; + + enum EnteredState + { + Nothing, + DestroyedEntity, + DestroyedActor + }; + +public: + GameEntity(Color::Color color = Color::none, QGraphicsItem *parent = 0); + GameEntity(QGraphicsItem *parent); + virtual ~GameEntity() + {}; + + /* color of entity */ + virtual Color::Color color() + { + return m_color; + } + + /* returns whether the actor may enter this field */ + virtual bool checkEnter(Actor *) + { + return true; + } + + /* performs action when this actor acctually enters + * returns whether this entity survives the entering + */ + virtual EnteredState enter(Actor *) + { + /* default to no action/survive */ + return Nothing; + } + + /* called when an instance acctually dies for creating effects */ + virtual void onDie(Actor *) + {}; + + /* enable the use of qgraphicsitem_cast with this item */ + int type() const + { + return m_type; + } + +protected: + int m_type; + Color::Color m_color; +}; + +#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 @@ + + + pics/actor1.png + pics/actor2.png + pics/actor3.png + pics/actor4.png + pics/block0.png + pics/block1.png + pics/block2.png + pics/block3.png + pics/block4.png + pics/bonuspoints.png + pics/points.png + style.qss + pics/app.ico + pics/actor1icon.png + pics/actor2icon.png + pics/actor3icon.png + pics/actor4icon.png + pics/soundon.xpm + pics/soundoff.xpm + + + sound/intro.ogg + sound/waka_waka.ogg + sound/eating_fruit.ogg + sound/eating_ghost.ogg + sound/die.ogg + sound/ambient.ogg + + 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 Binary files /dev/null and b/pacman-c++/common/pics/actor1.png differ diff --git a/pacman-c++/common/pics/actor1icon.png b/pacman-c++/common/pics/actor1icon.png new file mode 100644 index 0000000..4407cef Binary files /dev/null and b/pacman-c++/common/pics/actor1icon.png differ diff --git a/pacman-c++/common/pics/actor2.png b/pacman-c++/common/pics/actor2.png new file mode 100644 index 0000000..736a6e7 Binary files /dev/null and b/pacman-c++/common/pics/actor2.png differ diff --git a/pacman-c++/common/pics/actor2icon.png b/pacman-c++/common/pics/actor2icon.png new file mode 100644 index 0000000..eaf2a4c Binary files /dev/null and b/pacman-c++/common/pics/actor2icon.png differ diff --git a/pacman-c++/common/pics/actor3.png b/pacman-c++/common/pics/actor3.png new file mode 100644 index 0000000..f963cff Binary files /dev/null and b/pacman-c++/common/pics/actor3.png differ diff --git a/pacman-c++/common/pics/actor3icon.png b/pacman-c++/common/pics/actor3icon.png new file mode 100644 index 0000000..2558cbc Binary files /dev/null and b/pacman-c++/common/pics/actor3icon.png differ diff --git a/pacman-c++/common/pics/actor4.png b/pacman-c++/common/pics/actor4.png new file mode 100644 index 0000000..e500dc5 Binary files /dev/null and b/pacman-c++/common/pics/actor4.png differ diff --git a/pacman-c++/common/pics/actor4icon.png b/pacman-c++/common/pics/actor4icon.png new file mode 100644 index 0000000..82bf637 Binary files /dev/null and b/pacman-c++/common/pics/actor4icon.png differ diff --git a/pacman-c++/common/pics/app.ico b/pacman-c++/common/pics/app.ico new file mode 100644 index 0000000..4a73cd4 Binary files /dev/null and b/pacman-c++/common/pics/app.ico differ diff --git a/pacman-c++/common/pics/block0.png b/pacman-c++/common/pics/block0.png new file mode 100644 index 0000000..76bc4b7 Binary files /dev/null and b/pacman-c++/common/pics/block0.png differ diff --git a/pacman-c++/common/pics/block1.png b/pacman-c++/common/pics/block1.png new file mode 100644 index 0000000..99e8633 Binary files /dev/null and b/pacman-c++/common/pics/block1.png differ diff --git a/pacman-c++/common/pics/block2.png b/pacman-c++/common/pics/block2.png new file mode 100644 index 0000000..963207e Binary files /dev/null and b/pacman-c++/common/pics/block2.png differ diff --git a/pacman-c++/common/pics/block3.png b/pacman-c++/common/pics/block3.png new file mode 100644 index 0000000..6662de4 Binary files /dev/null and b/pacman-c++/common/pics/block3.png differ diff --git a/pacman-c++/common/pics/block4.png b/pacman-c++/common/pics/block4.png new file mode 100644 index 0000000..00fbd74 Binary files /dev/null and b/pacman-c++/common/pics/block4.png differ diff --git a/pacman-c++/common/pics/bonuspoints.png b/pacman-c++/common/pics/bonuspoints.png new file mode 100644 index 0000000..b5714c9 Binary files /dev/null and b/pacman-c++/common/pics/bonuspoints.png 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 Binary files /dev/null and b/pacman-c++/common/pics/pacman10-hp-sprite-2.png differ diff --git a/pacman-c++/common/pics/points.png b/pacman-c++/common/pics/points.png new file mode 100644 index 0000000..6ba4496 Binary files /dev/null and b/pacman-c++/common/pics/points.png 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 @@ +/* XPM */ +static char * soundoff_xpm[] = { +"12 10 2 1", +" c None", +". c #000000", +" ", +" . ", +" .. . .", +".... . . ", +".... .. ", +".... .. ", +".... . . ", +" .. . .", +" . ", +" "}; 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 @@ +/* XPM */ +static char * soundoff_xpm[] = { +"12 10 2 1", +" c None", +". c #000000", +" . ", +" . . ", +" .. . . ", +".... . . ", +".... . . ", +".... . . ", +".... . . ", +" .. . . ", +" . . ", +" . "}; 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 @@ +#include "pixmapitem.h" +#include + +PixmapItem::PixmapItem(QGraphicsItem *parent) + : QGraphicsObject(parent), m_x(0), m_y(0) +{ +} + +PixmapItem::PixmapItem(const QString &fileName, QGraphicsItem *parent) + : QGraphicsObject(parent), m_x(0), m_y(0) +{ + m_pix = ":/" + fileName; + m_width = m_pix.width(); + m_height = m_pix.height(); +} + +PixmapItem::PixmapItem(const QString &fileName, QGraphicsScene *scene) + : QGraphicsObject(), m_x(0), m_y(0) +{ + m_pix = ":/" + fileName; + m_width = m_pix.width(); + m_height = m_pix.height(); + scene->addItem(this); +} + +PixmapItem::PixmapItem(const QPixmap &pix, QGraphicsItem *parent) + : QGraphicsObject(parent), m_pix(pix), m_x(0), m_y(0) +{ + m_width = m_pix.width(); + m_height = m_pix.height(); +} + +PixmapItem::PixmapItem(const QPixmap &pix, QGraphicsScene *scene) + : QGraphicsObject(), m_pix(pix), m_x(0), m_y(0) +{ + m_width = m_pix.width(); + m_height = m_pix.height(); + scene->addItem(this); +} + +void PixmapItem::setPixmap(const QPixmap &pix) +{ + m_pix = pix; + m_width = m_pix.width(); + m_height = m_pix.height(); +} + +void PixmapItem::setSprite(int x, int y, int width, int height) +{ + m_x = x; + m_y = y; + m_width = width; + m_height = height; +} + +QSizeF PixmapItem::size() const +{ + return QSizeF(m_width, m_height); +} + +QRectF PixmapItem::boundingRect() const +{ + return QRectF(QPointF(0, 0), size()); +} + +QPainterPath PixmapItem::shape() const +{ + QPainterPath path; + path.addRect(boundingRect()); + return path; +} + +void PixmapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) +{ + painter->drawPixmap(QPoint(0, 0), m_pix, QRect(m_x, m_y, m_width, m_height)); +} + 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 @@ +#ifndef PIXMAPITEM__H +#define PIXMAPITEM__H + +#include +#include + +class PixmapItem + : public QGraphicsObject +{ +public: + PixmapItem(QGraphicsItem *parent = 0); + PixmapItem(const QString &fileName, QGraphicsItem *parent = 0); + PixmapItem(const QString &fileName, QGraphicsScene *scene); + PixmapItem(const QPixmap &pix, QGraphicsItem *parent = 0); + PixmapItem(const QPixmap &pix, QGraphicsScene *scene); + virtual ~PixmapItem() + {}; + + void setPixmap(const QPixmap &pix); + void setSprite(int x, int y, int width, int height); + QSizeF size() const; + QRectF boundingRect() const; + QPainterPath shape() const; + void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); + +private: + QPixmap m_pix; + int m_x, m_y; + int m_width, m_height; +}; + +#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 @@ +#include "point.h" +#include "constants.h" +#include "actor.h" + +namespace +{ + QPixmap *pixmap = NULL; +} + +Point::Point(QGraphicsItem *parent) + : GameEntity(parent) +{ + m_type = Type; + + /* empty object for servers */ + if (Constants::server) + return; + + if (pixmap == NULL) + pixmap = new QPixmap(":/points"); + setPixmap(*pixmap); +} + +GameEntity::EnteredState Point::enter(Actor *actor) +{ + actor->addRoundPoints(Constants::Game::point_value); + return DestroyedEntity; +} + +void Point::onDie(Actor *actor) +{ + actor->startEating(); +} 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 @@ +#ifndef POINT_H +#define POINT_H + +#include "gameentity.h" + +class Point + : public GameEntity +{ +public: + enum + { + Type = UserType + Transmission::point + }; + +public: + Point(QGraphicsItem *parent=0); + virtual ~Point() + {}; + + virtual EnteredState enter(Actor *actor); + virtual void onDie(Actor *actor); +}; + +#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 @@ +#include "sceneholder.h" +#include "constants.h" +#include "gameentity.h" +#include "block.h" +#include "actor.h" +#include "bonuspoint.h" +#include "point.h" +#include "util.h" + +SceneHolder::SceneHolder(QObject *parent) + : QGraphicsScene(parent), m_color(Color::none), m_pointsLeft(0) +{ + setSceneRect(0, 0, Constants::map_size_pixel.width, Constants::map_size_pixel.height); + setBackgroundBrush(Qt::black); + + m_overlayText = new QGraphicsTextItem(); + + visualMap.resize(Constants::map_size.width); + for (int i = 0; i < visualMap.size(); ++i) + visualMap[i].resize(Constants::map_size.height); +} + +void SceneHolder::reset() +{ + processDelayedItems(); + showEatingText(false); + + /* remove actors from scene so they don't get deleted during clear */ + foreach(Actor *actor, m_actors) + { + actor->reset(); + removeItem(actor); + } + + /* clear our stuff */ + clear(); + m_pointsLeft = 0; + for (int i = 0; i < visualMap.size(); ++i) + { + visualMap[i].clear(); + visualMap[i].resize(Constants::map_size.height); + } + + /* add actors again */ + foreach(Actor *actor, m_actors) + addItem(actor); +} + +void SceneHolder::processDelayedItems() +{ + /* remove items that got marked for removal from scene */ + foreach(GameEntity *item, m_oldItems) + { + removeItem(item); + delete item; + } + m_oldItems.clear(); + + /* process death */ + foreach(const Color::Color color, m_death.keys()) + { + Q_ASSERT(m_death[color] != NULL); + m_death[color]->onDie(m_actors[color]); + } + m_death.clear(); +} + +void SceneHolder::updateMap(const Transmission::map_t& map) +{ + processDelayedItems(); + + /* process update */ + for (unsigned int x = 0; x < Constants::map_size.width; ++x) + { + for (unsigned int y = 0; y < Constants::map_size.height; ++y) + { + const Transmission::field_t &cur = map[x][y]; + if (cur == Transmission::none) + continue; + updateMap(map, x, y); + } + } + + if (m_pointsLeft == 0) + emit allPointsRemoved(); +} + +void SceneHolder::updateMap(const Transmission::map_t& map, const unsigned int x, unsigned int y) +{ + const Transmission::field_t &cur = map[x][y]; + if (cur == Transmission::none) + return; + + /* we may have multiple colors in one position (e.g during eating another pacman) */ + Color::Color color = static_cast(cur & Transmission::color_mask); + QList colors; + if (color == Color::none) + colors.append(Color::none); + foreach(Color::Color col, m_eatingorder.toSet()) + { + if (color & col) + colors.append(col); + } + Q_ASSERT(colors.count() > 0); + + /* for now complain if there are more colors or it's a Transmission::death packet */ + Q_ASSERT(colors.count() == 1 || cur & Transmission::death); + + if (cur & Transmission::empty) + { + GameEntity *oldItem = visualMap[x][y]; + /* special handling for purging field */ + if (oldItem != NULL) + { + /* remove item from visualmap and register item for removal in next update */ + visualMap[x][y] = NULL; + m_oldItems.append(oldItem); + + /* an item must be removed by an actor */ + Actor *actor = m_actors[colors.at(0)]; + Q_ASSERT(actor != NULL); + oldItem->onDie(actor); + } + } + + GameEntity *item = NULL; + if (cur == Transmission::none) + { + /* no update */ + } + else + { + if (cur & Transmission::block) + { + unsigned int neighbours = Block::None; + /* check for old block first */ + if (visualMap[x][y] != NULL) + { + Block *oldItem = qgraphicsitem_cast(visualMap[x][y]); + if (oldItem != NULL) + neighbours = oldItem->neighbours(); + } + /* check left side */ + if (x > 0 && map[x - 1][y] & Transmission::block) + neighbours |= Block::Left; + /* check right side */ + if (x < Constants::map_size.width && map[x + 1][y] & Transmission::block) + neighbours |= Block::Right; + /* check upside */ + if (y > 0 && map[x][y - 1] & Transmission::block) + neighbours |= Block::Up; + /* check down side */ + if (y < Constants::map_size.height && map[x][y + 1] & Transmission::block) + neighbours |= Block::Down; + item = new Block(colors.at(0), neighbours); + } + + if (cur & Transmission::bonuspoint) + item = new BonusPoint(); + + if (cur & Transmission::point) + { + item = new Point(); + connect(item, SIGNAL(destroyed()), this, SLOT(decrementPoints())); + ++m_pointsLeft; + } + + if (cur & Transmission::pacman) + { + foreach(color, colors) + { + /* WARNING: do NOT add actor to visualMap as visualMap-items may + * get deleted during update and actors are referenced in_mactors too + * if you REALLY need that you need to changed updateMap so that all actors + * will be moved before any new items get allocated (totally untested) + */ + Actor *actor = m_actors.value(color, NULL); + if (actor == NULL) + { + actor = new Actor(color, (color == m_color)); + m_actors[color] = actor; + addItem(actor); + actor->setPos(mapPositionToCoord(x, y)); + actor->hadReset(); + } + else + { + /* check for death */ + if (cur & Transmission::death) + { + foreach(Color::Color col, colors) + { + if (color == col) + continue; + if (m_actors[col]->canEat(actor, m_eatingorder)) + { + m_death[col] = actor; + break; + } + } + } + + /* move actor */ + if (actor->hadReset()) + actor->setPos(mapPositionToCoord(x, y)); + else + actor->move(mapPositionToCoord(x, y)); + + /* that's kind a hack but working right now */ + if (!(cur & Transmission::empty)) + actor->stopEating(); + qDebug() << "[SceneUpdate] actor moves: color=" << color + << "newpos=" << QPoint(x, y); + } + + if ((cur & Transmission::death) && visualMap[x][y] != NULL) + m_death[color] = visualMap[x][y]; + } + } + + if (cur & Transmission::empty) + { + /* already handled */ + } + } + + /* add new created item to scene + * remove old item on that location if there's one + */ + if (item != NULL) + { + GameEntity *oldItem = visualMap[x][y]; + if (oldItem != NULL) + { + removeItem(oldItem); + delete oldItem; + } + + addItem(item); + item->setPos(mapPositionToCoord(x, y)); + visualMap[x][y] = item; + } +} + +void SceneHolder::setColor(Color::Color color) +{ + m_color = color; +} + +Color::Color SceneHolder::color() +{ + return m_color; +} + +unsigned int SceneHolder::pointsLeft() +{ + return m_pointsLeft; +} + +void SceneHolder::decrementPoints() +{ + --m_pointsLeft; +} + +void SceneHolder::setEatingOrder(QList &order) +{ + m_eatingorder = order; +} + +QList &SceneHolder::eatingOrder() +{ + return m_eatingorder; +} + +void SceneHolder::showEatingText(bool show) +{ + if (!show) + { + if (m_overlayText->scene() == this) + removeItem(m_overlayText); + return; + } + + m_overlayText->setDefaultTextColor(Qt::black); + QString text = QString( + "
" + "
" + ); + unsigned int lines = 1; + + text = text % QString("Your Pacman:

") + .arg(m_actors[m_color]->iconStr()); + lines += 2; + + foreach(Actor *actor, m_actors) + { + foreach(Actor *other, m_actors) + { + if (!actor->canEat(other, m_eatingorder)) + continue; + text = text % QString("  can eat
") + .arg(actor->iconStr(), other->iconStr()); + ++lines; + } + } + text = text % "
"; + m_overlayText->setHtml(text); + m_overlayText->setTextWidth(150); + m_overlayText->setOpacity(0.9); + + QFontMetrics metrics(m_overlayText->font()); + m_overlayText->setPos((width() - m_overlayText->textWidth()) / 2, (height() - metrics.height() * lines) / 2); + m_overlayText->setZValue(100); + + addItem(m_overlayText); +} + +void SceneHolder::showWaitingForPlayers(bool show) +{ + if (!show) + { + if (m_overlayText->scene() == this) + removeItem(m_overlayText); + return; + } + + m_overlayText->setDefaultTextColor(Qt::black); + QString text = QString( + "
" + "
" + "Waiting for other Players...
" + "
" + ); + unsigned int lines = 3; + m_overlayText->setHtml(text); + m_overlayText->setTextWidth(150); + m_overlayText->setOpacity(0.9); + + QFontMetrics metrics(m_overlayText->font()); + m_overlayText->setPos((width() - m_overlayText->textWidth()) / 2, (height() - metrics.height() * lines) / 2); + m_overlayText->setZValue(100); + + addItem(m_overlayText); +} + +QPoint SceneHolder::mapPositionToCoord(unsigned int x, unsigned int y) +{ + return QPoint(x * Constants::field_size.width, y * Constants::field_size.height); +} + +QPoint SceneHolder::mapPositionToCoord(QPoint point) +{ + return mapPositionToCoord(point.x(), point.y()); +} + +QPoint SceneHolder::CoordToMapPosition(unsigned int x, unsigned int y) +{ + return QPoint(x / Constants::field_size.width, y / Constants::field_size.height); +} + +QPoint SceneHolder::CoordToMapPosition(QPoint point) +{ + return CoordToMapPosition(point.x(), point.y()); +} 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 @@ +#ifndef SCENEHOLDER_H +#define SCENEHOLDER_H + +#include "constants.h" +#include + +class GameEntity; +class Actor; + +class SceneHolder + : public QGraphicsScene +{ + Q_OBJECT + +public: + SceneHolder(QObject *parent = 0); + virtual ~SceneHolder() + {}; + void reset(); + unsigned int pointsLeft(); + void updateMap(const Transmission::map_t& map); + void updateMap(const Transmission::map_t& map, const unsigned int x, const unsigned int y); + void setColor(Color::Color color = Color::none); + Color::Color color(); + void setEatingOrder(QList &order); + QList &eatingOrder(); + void showEatingText(bool show = true); + void showWaitingForPlayers(bool show = true); + +signals: + void allPointsRemoved(); + +private slots: + void decrementPoints(); + +protected: + /* process items that got delayed by one tick */ + void processDelayedItems(); + /* data conversion */ + QPoint mapPositionToCoord(unsigned int x, unsigned int y); + QPoint mapPositionToCoord(QPoint point); + QPoint CoordToMapPosition(unsigned int x, unsigned int y); + QPoint CoordToMapPosition(QPoint point); + +protected: + /* map of all pixmap instances */ + QVector< QVector > visualMap; + + /* map of actors in order to keep track of those instances */ + QMap m_actors; + + /* items that got removed/has been eaten + * must be remove one tick later + */ + QList m_oldItems; + /* we need to store items that killed an actor too (e.g. colored blocks) */ + QMap m_death; + + /* my local color */ + Color::Color m_color; + + /* a actor can only eat his upper neighbour + * the order of the neighbours is determined by the colors order (sent from server) + * please note that !pl1.canEat(pl2, ...) doesn't necessarily mean that pl2 can eat pl1 + * order MUST be in this format: [col1, [col2 ... colN], col1] + */ + QList m_eatingorder; + + /* points left before round ends */ + unsigned int m_pointsLeft; + QGraphicsTextItem *m_overlayText; +}; + +#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 Binary files /dev/null and b/pacman-c++/common/sound/ambient.ogg differ diff --git a/pacman-c++/common/sound/die.ogg b/pacman-c++/common/sound/die.ogg new file mode 100644 index 0000000..f6af2e0 Binary files /dev/null and b/pacman-c++/common/sound/die.ogg 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 Binary files /dev/null and b/pacman-c++/common/sound/eating_fruit.ogg 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 Binary files /dev/null and b/pacman-c++/common/sound/eating_ghost.ogg differ diff --git a/pacman-c++/common/sound/intro.ogg b/pacman-c++/common/sound/intro.ogg new file mode 100644 index 0000000..d38f16b Binary files /dev/null and b/pacman-c++/common/sound/intro.ogg 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 Binary files /dev/null and b/pacman-c++/common/sound/waka_waka.ogg 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 @@ +QGroupBox#actor1::indicator { + background-image: url(:/actor1icon); + background-position: top left; + background-repeat: no-repeat; + width: 16px; + height: 14px; +} + +QGroupBox#actor2::indicator { + background-image: url(:/actor2icon); + background-position: top left; + background-repeat: no-repeat; + width: 16px; + height: 14px; +} + +QGroupBox#actor3::indicator { + background-image: url(:/actor3icon); + background-position: top left; + background-repeat: no-repeat; + width: 16px; + height: 14px; +} + +QGroupBox#actor4::indicator { + background-image: url(:/actor4icon); + background-position: top left; + background-repeat: no-repeat; + width: 16px; + height: 14px; +} 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 @@ +#include "util.h" + +namespace Util +{ + Transmission::map_t createUninitialisedMap() + { + Transmission::map_t map; + map = new Transmission::field_t*[Constants::map_size.width]; + for (unsigned int i = 0; i < Constants::map_size.width; ++i) + map[i] = new Transmission::field_t[Constants::map_size.height]; + return map; + } + + Transmission::map_t createEmptyMap() + { + Transmission::map_t map = createUninitialisedMap(); + for (unsigned int x = 0; x < Constants::map_size.width; ++x) + { + for (unsigned int y = 0; y < Constants::map_size.height; ++y) + { + Transmission::field_t &cur = map[x][y]; + cur = Transmission::none; + } + } + return map; + } + + void deleteMap(Transmission::map_t map) + { + for (unsigned int x = 0; x < Constants::map_size.width; ++x) + delete[] map[x]; + delete[] map; + } + + Transmission::map_t createDemoMap() + { + Transmission::map_t map = createEmptyMap(); + + const char *tmpl[] = { + " # # ", + " #### ###### # #### # # ###### ### ", + " # # ", + " # ##### # # # # # ### # # # ", + " # # # # # # # # # # ## # # ", + " # # # # # # # # ### # # # # ", + " # # # # # # # # # # # # ## # ", + " # # ### ##### # ### # # # ", + " ### # ", + " # # ### #### #### #### ##### ", + " #### # #..# #..# #..# # # ", + " # # ### #..# #..# #### # # # # ", + " # # # #..# #..# # # ", + " # #### # #### #### # # ##### # ", + " # # ", + " #### ###### # ##### # ####### ### ", + " # # " + }; + + for (unsigned int x = 0; x < Constants::map_size.width; ++x) + { + for (unsigned int y = 0; y < Constants::map_size.height; ++y) + { + Transmission::field_t &cur = map[x][y]; + cur = Transmission::none; + if (tmpl[y][x] == '#') + cur |= Color::none | Transmission::block; + /* this is a simple hack to create areas where no + * autoplaced points/actors will be placed (see makePoints) + */ + else if (tmpl[y][x] == '.') + cur |= Transmission::point; + } + } + return map; + } + + void placeActors(Transmission::map_t map, unsigned int players, const Color::Color *colors) + { +#if 0 + for(unsigned int i = 0; i < players; ++i) + map[i][0] = colors[i] | Transmission::pacman; + return; +#endif + + int mindistance = Constants::Game::player_minimum_distance; + /* this outer loop is used if there are no more valid places left + * so we can change mindistance + */ + QList actors; + for(unsigned int i = 0; i < players; ++i) + { + /* first remove formerly placed actors from map */ + foreach(QPoint pos, actors) + map[pos.x()][pos.y()] = Transmission::none; + actors.clear(); + + /* get list of valid positions */ + QList validpos; + for (unsigned int x = 0; x < Constants::map_size.width; ++x) + { + for (unsigned int y = 0; y < Constants::map_size.height; ++y) + { + Transmission::field_t &cur = map[x][y]; + if (cur == Transmission::none) + validpos.append(QPoint(x, y)); + } + } + + /* place actors at map */ + for(i = 0; i < players; ++i) + { + int rand = (int) (validpos.size() * (qrand() / (RAND_MAX + 1.0))); + QPoint newpos = validpos.at(rand); + map[newpos.x()][newpos.y()] = colors[i] | Transmission::pacman; + qDebug() << "[Place] Actor" << i << "at" << newpos; + actors.append(newpos); + validpos.removeAt(rand); + + QMutableListIterator j(validpos); + while(j.hasNext()) + { + j.next(); + QPoint tmp = j.value() - newpos; + if (tmp.manhattanLength() < mindistance) + j.remove(); + } + + if (validpos.empty()) + { + qWarning() << "There are no more valid positions for actors left on the map"; + mindistance -= Constants::Game::player_distance_decr; + break; + } + } + } + } + + void fillPoints(Transmission::map_t map, Transmission::field_t type) + { + /* auto place normal points*/ + for (unsigned int x = 0; x < Constants::map_size.width; ++x) + { + for (unsigned int y = 0; y < Constants::map_size.height; ++y) + { + Transmission::field_t &cur = map[x][y]; + if (cur == Transmission::none) + { +#if 0 + /* use for endround testing */ + if (x > 0) + continue; +#endif + cur = type; + } + else if (cur == Transmission::point) + cur = Transmission::none; + } + } + } + + Transmission::field_t actorMovementToTransmission(Actor::Movement mov, Transmission::field_t def) + { + switch (mov) + { + case Actor::None: + return Transmission::direction_none; + break; + case Actor::Left: + return Transmission::direction_left; + break; + case Actor::Right: + return Transmission::direction_right; + break; + case Actor::Up: + return Transmission::direction_up; + break; + case Actor::Down: + return Transmission::direction_down; + break; + default: + return def; + break; + } + return def; + } + + Actor::Movement transmissionMovementToActor(Transmission::field_t field, Actor::Movement def) + { + switch (field) + { + case Transmission::direction_none: + return Actor::None; + break; + case Transmission::direction_left: + return Actor::Left; + break; + case Transmission::direction_right: + return Actor::Right; + break; + case Transmission::direction_up: + return Actor::Up; + break; + case Transmission::direction_down: + return Actor::Down; + break; + default: + return def; + break; + } + return def; + } + + const QString colorToString(Color::Color color) + { + switch(color) + { + case Color::none: + return "none"; + break; + case Color::red: + return "red"; + break; + case Color::blue: + return "blue"; + break; + case Color::green: + return "green"; + break; + case Color::yellow: + return "yellow"; + break; + default: + return "unknown"; + break; + } + } + + QSharedPointer createPacket(const ::google::protobuf::MessageLite& packet) + { + qint64 packetlen = packet.ByteSize(); + QSharedPointer data = QSharedPointer(new QByteArray); + data->resize(packetlen); + + /* use protobuf.SerializeWithCachedSizesToArray() to avoid calling protobuf.ByteSize() again */ + ::google::protobuf::uint8 *dataptr = reinterpret_cast(data->data()); + packet.SerializeWithCachedSizesToArray(dataptr); + return data; + } + + bool sendPacket(QByteArray *data, ENetPeer *peer, ENetHost *host) + { + ENetPacket *packet = enet_packet_create(data->data(), data->length(), ENET_PACKET_FLAG_RELIABLE); + if (enet_peer_send(peer, 0, packet) < 0) + { + qDebug() << "[sendPacket] Error while sending packet"; + return false; + } + enet_host_flush(host); + return true; + } + + bool sendPacket(const ::google::protobuf::MessageLite& packet, ENetPeer *peer, ENetHost *host) + { + return sendPacket(createPacket(packet).data(), peer, host); + } + + QSharedPointer receivePacket(ENetPacket *packet) + { + const char *pdata = reinterpret_cast(packet->data); + QSharedPointer data = QSharedPointer(new QByteArray(pdata, packet->dataLength)); + return data; + } + + int floorLog2(unsigned int n) + { + if (n == 0) + return -1; + + int pos = 0; + if (n >= 1<<16) { n >>= 16; pos += 16; } + if (n >= 1<< 8) { n >>= 8; pos += 8; } + if (n >= 1<< 4) { n >>= 4; pos += 4; } + if (n >= 1<< 2) { n >>= 2; pos += 2; } + if (n >= 1<< 1) { pos += 1; } + return pos; + } + +#if 0 + void hexdump(void *pAddressIn, long lSize) + { + char szBuf[100]; + long lIndent = 1; + long lOutLen, lIndex, lIndex2, lOutLen2; + long lRelPos; + struct { char *pData; unsigned long lSize; } buf; + unsigned char *pTmp,ucTmp; + unsigned char *pAddress = (unsigned char *)pAddressIn; + + buf.pData = (char *)pAddress; + buf.lSize = lSize; + + while (buf.lSize > 0) + { + pTmp = (unsigned char *)buf.pData; + lOutLen = (int)buf.lSize; + if (lOutLen > 16) + lOutLen = 16; + + // create a 64-character formatted output line: + sprintf(szBuf, " > " + " " + " %08lX", pTmp-pAddress); + lOutLen2 = lOutLen; + + for(lIndex = 1+lIndent, lIndex2 = 53-15+lIndent, lRelPos = 0; + lOutLen2; + lOutLen2--, lIndex += 2, lIndex2++ + ) + { + ucTmp = *pTmp++; + + sprintf(szBuf + lIndex, "%02X ", (unsigned short)ucTmp); + if(!isprint(ucTmp)) ucTmp = '.'; // nonprintable char + szBuf[lIndex2] = ucTmp; + + if (!(++lRelPos & 3)) // extra blank after 4 bytes + { lIndex++; szBuf[lIndex+2] = ' '; } + } + + if (!(lRelPos & 3)) lIndex--; + + szBuf[lIndex ] = '<'; + szBuf[lIndex+1] = ' '; + + printf("%s\n", szBuf); + + buf.pData += lOutLen; + buf.lSize -= lOutLen; + } + } +#endif +} 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 @@ +#ifndef UTIL_H +#define UTIL_H + +#include "constants.h" +#include "actor.h" +#include "pacman.pb.h" + +extern "C" { +#include "enet/enet.h" +} + +namespace Util +{ + Transmission::map_t createUninitialisedMap(); + Transmission::map_t createDemoMap(); + void placeActors(Transmission::map_t map, unsigned int players, const Color::Color *colors); + void fillPoints(Transmission::map_t map, Transmission::field_t type = Transmission::point); + Transmission::map_t createEmptyMap(); + void deleteMap(Transmission::map_t map); + + Transmission::field_t actorMovementToTransmission(Actor::Movement mov, + Transmission::field_t def = Transmission::none); + Actor::Movement transmissionMovementToActor(Transmission::field_t field, + Actor::Movement def = Actor::None); + const QString colorToString(Color::Color color); + + /* send packet with error check and flush */ + QSharedPointer createPacket(const ::google::protobuf::MessageLite& packet); + bool sendPacket(QByteArray *data, ENetPeer *peer, ENetHost *host); + bool sendPacket(const ::google::protobuf::MessageLite& packet, ENetPeer *peer, ENetHost *host); + QSharedPointer receivePacket(ENetPacket *packet); + + int floorLog2(unsigned int n); + +#if 0 + void hexdump(void *pAddressIn, long lSize); +#endif +} +#endif // UTIL_H -- cgit v1.2.3