summaryrefslogtreecommitdiffstats
path: root/pacman-c++/common
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2011-05-05 00:57:07 +0200
committermanuel <manuel@mausz.at>2011-05-05 00:57:07 +0200
commitce48af53646cd9e7ec762fc1ac176b3aa620b11d (patch)
treef8fbf2cae8c7d0cbac2696a8f4cf94410bfb4928 /pacman-c++/common
parente54ccad07e256ba877bd41d70bd358bd0085bd1e (diff)
downloadfoop-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')
-rw-r--r--pacman-c++/common/actor.cpp375
-rw-r--r--pacman-c++/common/actor.h81
-rw-r--r--pacman-c++/common/audio.cpp355
-rw-r--r--pacman-c++/common/audio.h148
-rw-r--r--pacman-c++/common/block.cpp56
-rw-r--r--pacman-c++/common/block.h43
-rw-r--r--pacman-c++/common/bonuspoint.cpp38
-rw-r--r--pacman-c++/common/bonuspoint.h24
-rw-r--r--pacman-c++/common/common.pro30
-rw-r--r--pacman-c++/common/constants.h102
-rw-r--r--pacman-c++/common/gameentity.cpp9
-rw-r--r--pacman-c++/common/gameentity.h72
-rw-r--r--pacman-c++/common/pacman.qrc31
-rw-r--r--pacman-c++/common/pacman.rc1
-rw-r--r--pacman-c++/common/pics/actor1.pngbin0 -> 1231 bytes
-rw-r--r--pacman-c++/common/pics/actor1icon.pngbin0 -> 232 bytes
-rw-r--r--pacman-c++/common/pics/actor2.pngbin0 -> 1257 bytes
-rw-r--r--pacman-c++/common/pics/actor2icon.pngbin0 -> 233 bytes
-rw-r--r--pacman-c++/common/pics/actor3.pngbin0 -> 1226 bytes
-rw-r--r--pacman-c++/common/pics/actor3icon.pngbin0 -> 231 bytes
-rw-r--r--pacman-c++/common/pics/actor4.pngbin0 -> 1536 bytes
-rw-r--r--pacman-c++/common/pics/actor4icon.pngbin0 -> 233 bytes
-rw-r--r--pacman-c++/common/pics/app.icobin0 -> 174 bytes
-rw-r--r--pacman-c++/common/pics/block0.pngbin0 -> 479 bytes
-rw-r--r--pacman-c++/common/pics/block1.pngbin0 -> 453 bytes
-rw-r--r--pacman-c++/common/pics/block2.pngbin0 -> 476 bytes
-rw-r--r--pacman-c++/common/pics/block3.pngbin0 -> 452 bytes
-rw-r--r--pacman-c++/common/pics/block4.pngbin0 -> 471 bytes
-rw-r--r--pacman-c++/common/pics/bonuspoints.pngbin0 -> 642 bytes
-rw-r--r--pacman-c++/common/pics/pacman10-hp-sprite-2.pngbin0 -> 6857 bytes
-rw-r--r--pacman-c++/common/pics/points.pngbin0 -> 188 bytes
-rw-r--r--pacman-c++/common/pics/soundoff.xpm15
-rw-r--r--pacman-c++/common/pics/soundon.xpm15
-rw-r--r--pacman-c++/common/pixmapitem.cpp77
-rw-r--r--pacman-c++/common/pixmapitem.h32
-rw-r--r--pacman-c++/common/point.cpp33
-rw-r--r--pacman-c++/common/point.h24
-rw-r--r--pacman-c++/common/sceneholder.cpp364
-rw-r--r--pacman-c++/common/sceneholder.h74
-rw-r--r--pacman-c++/common/sound/ambient.oggbin0 -> 23243 bytes
-rw-r--r--pacman-c++/common/sound/die.oggbin0 -> 20271 bytes
-rw-r--r--pacman-c++/common/sound/eating_fruit.oggbin0 -> 8774 bytes
-rw-r--r--pacman-c++/common/sound/eating_ghost.oggbin0 -> 9238 bytes
-rw-r--r--pacman-c++/common/sound/intro.oggbin0 -> 45705 bytes
-rw-r--r--pacman-c++/common/sound/waka_waka.oggbin0 -> 25855 bytes
-rw-r--r--pacman-c++/common/style.qss31
-rw-r--r--pacman-c++/common/util.cpp342
-rw-r--r--pacman-c++/common/util.h39
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
7static QVariant myBooleanInterpolator(const bool &start, const bool &end, qreal progress)
8{
9 return (progress == 1.0) ? end : start;
10}
11
12Actor::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
89QSequentialAnimationGroup *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
120PixmapItem &Actor::icon()
121{
122 return m_icon;
123}
124
125const QString Actor::iconStr()
126{
127 return QString(":/actor%1icon").arg(Util::floorLog2(m_color) + 1);
128}
129
130Actor::Movement Actor::direction()
131{
132 return m_direction;
133}
134
135
136void Actor::setDirection(Movement direction)
137{
138 m_direction = direction;
139}
140
141bool Actor::isLocal()
142{
143 return m_local;
144}
145
146bool Actor::hadReset()
147{
148 if (!m_reset)
149 return false;
150 m_reset = false;
151 return true;
152}
153
154void 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
178void 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
193void 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
248void 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
269bool Actor::isMoving()
270{
271 return (m_moving->state() == QAbstractAnimation::Running);
272}
273
274bool 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
283void Actor::onDie(Actor *other)
284{
285 other->eatingPacman();
286 die();
287}
288
289void 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
302void Actor::eatingFruit()
303{
304 if (!m_local)
305 return;
306 AudioManager::self()->play(Sound::EatingFruit);
307}
308
309void Actor::eatingPacman()
310{
311 if (!m_local)
312 return;
313 AudioManager::self()->play(Sound::EatingGhost);
314}
315
316void Actor::startEating()
317{
318 if (!m_local || !m_wakaPlayer->isWorking())
319 return;
320 m_wakaPlayer->play();
321}
322
323void Actor::stopEating()
324{
325 if (!m_local || !m_wakaPlayer->isWorking())
326 return;
327 m_wakaPlayer->pause();
328}
329
330unsigned int Actor::getRoundPoints()
331{
332 return m_roundPoints;
333}
334
335unsigned int Actor::getGamePoints()
336{
337 return m_gamePoints;
338}
339
340void Actor::addRoundPoints(unsigned int amount)
341{
342 m_roundPoints += amount;
343}
344
345void Actor::finishRound(bool died)
346{
347 if (!died)
348 m_gamePoints += m_roundPoints;
349 m_roundPoints = 0;
350}
351
352QPoint 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
11class Actor
12 : public GameEntity
13{
14Q_OBJECT
15
16public:
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
60private:
61 void moveByServer(Movement direction);
62 QSequentialAnimationGroup *setupEatingAnimation(Actor::Movement direction);
63
64private:
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 */
11AudioManager *AudioManager::m_instance = NULL;
12bool AudioManager::m_working = false;
13
14AudioManager::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
33AudioManager *AudioManager::self()
34{
35 if (m_instance == NULL)
36 m_instance = new AudioManager();
37 return m_instance;
38}
39
40bool AudioManager::isWorking() const
41{
42 return m_working;
43}
44
45void 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
59bool AudioManager::isMuted() const
60{
61 return m_muted;
62}
63
64void 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
72void 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
80void 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
88void 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
96AudioPlayer *AudioManager::audioPlayer()
97{
98 return m_players.at(0);
99}
100
101void AudioManager::play(Sound::Type sound, bool wait)
102{
103 audioPlayer()->play(sound, wait);
104}
105
106void AudioManager::enqueue(Sound::Type sound)
107{
108 if (!isWorking())
109 return;
110 audioPlayer()->enqueue(Phonon::MediaSource(m_sounds[sound]));
111}
112
113void 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
120void AudioManager::unregisterAudioPlayer(AudioPlayer *player)
121{
122 disconnect(player, SIGNAL(destroyed(QObject *)), this, SLOT(unregisterAudioPlayer_helper(QObject *)));
123 m_players.removeAll(player);
124}
125
126void AudioManager::unregisterAudioPlayer_helper(QObject *player)
127{
128 unregisterAudioPlayer(static_cast<AudioPlayer *>(player));
129}
130
131void 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
139QFile *AudioManager::sound(Sound::Type sound)
140{
141 if (!isWorking())
142 return NULL;
143 return m_sounds.at(sound);
144}
145
146/* --------------------------------------------------------------- */
147
148AudioPlayer::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
159bool AudioPlayer::isWorking() const
160{
161 return m_working;
162}
163
164void AudioPlayer::setMuted(bool mute)
165{
166 m_output->setMuted(mute);
167}
168
169bool AudioPlayer::isMuted() const
170{
171 return m_output->isMuted();
172}
173
174void 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
191void AudioPlayer::setLoop(Sound::Type sound)
192{
193 setLoop(AudioManager::self()->sound(sound));
194}
195
196void AudioPlayer::play()
197{
198 Phonon::MediaObject::play();
199}
200
201void 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.. */
223void 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
243void AudioPlayer::finished_ex()
244{
245 emit finished();
246}
247
248void 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
260void 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
267void AudioPlayer::loopEnqueue()
268{
269 enqueue(Phonon::MediaSource(m_loopsound));
270}
271
272/* --------------------------------------------------------------- */
273
274GaplessAudioPlayer::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
294bool GaplessAudioPlayer::isWorking() const
295{
296 return m_working;
297}
298
299void GaplessAudioPlayer::setMuted(bool mute)
300{
301 if (!m_working)
302 return;
303 m_player1->setMuted(mute);
304 m_player2->setMuted(mute);
305}
306
307bool GaplessAudioPlayer::isMuted() const
308{
309 return m_player1->isMuted() && m_player2->isMuted();
310}
311
312void 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
320void 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
330void GaplessAudioPlayer::startPlayer1()
331{
332 m_player1->play(m_sound);
333}
334
335void GaplessAudioPlayer::startPlayer2()
336{
337 m_player2->play(m_sound);
338}
339
340/* --------------------------------------------------------------- */
341
342void AudioPlayer::Sleeper::sleep(unsigned long secs)
343{
344 QThread::sleep(secs);
345}
346
347void AudioPlayer::Sleeper::msleep(unsigned long msecs)
348{
349 QThread::msleep(msecs);
350}
351
352void 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
10namespace Phonon
11{
12 class AudioOutput;
13}
14
15namespace 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
34class AudioPlayer
35 : public Phonon::MediaObject
36{
37 Q_OBJECT
38 friend class AudioManager;
39
40private:
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
50public:
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
59protected:
60 void test(QFile *testsound);
61 void setLoop(QFile *sound);
62
63public slots:
64 void loopEnqueue();
65
66protected slots:
67 void finished_ex();
68 void testFinished();
69 void stateChanged_ex(Phonon::State newstate, Phonon::State oldstate);
70
71protected:
72 bool m_working;
73 QFile *m_loopsound;
74 Phonon::AudioOutput *m_output;
75};
76
77/* --------------------------------------------------------------- */
78
79class GaplessAudioPlayer
80 : public QObject
81{
82 Q_OBJECT
83
84public:
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
92protected slots:
93 void startPlayer1();
94 void startPlayer2();
95
96protected:
97 bool m_working;
98 Sound::Type m_sound;
99 AudioPlayer *m_player1;
100 AudioPlayer *m_player2;
101};
102
103/* --------------------------------------------------------------- */
104
105class AudioManager
106 : public QObject
107{
108 Q_OBJECT
109 friend class AudioPlayer;
110 friend class GaplessAudioPlayer;
111
112public:
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
130signals:
131 void mutedChanged(bool muted);
132
133private slots:
134 void unregisterAudioPlayer_helper(QObject *player);
135
136private:
137 void preload();
138 QFile *sound(Sound::Type sound);
139
140private:
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
7QMap<Color::Color, QPixmap> Block::m_pixmaps;
8
9Block::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
28unsigned int Block::neighbours()
29{
30 return m_neighbours;
31}
32
33void 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
39bool Block::checkEnter(Actor * /* actor */)
40{
41 if (m_color == Color::none)
42 return false;
43 return true;
44}
45
46GameEntity::EnteredState Block::enter(Actor *actor)
47{
48 if (m_color != Color::none && m_color != actor->color())
49 return DestroyedActor;
50 return Nothing;
51}
52
53void 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
8class Block
9 : public GameEntity
10{
11public:
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
26public:
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
37private:
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
7namespace
8{
9 QPixmap *pixmap = NULL;
10}
11
12BonusPoint::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
29GameEntity::EnteredState BonusPoint::enter(Actor *actor)
30{
31 actor->addRoundPoints(Constants::Game::bonus_point_value);
32 return DestroyedEntity;
33}
34
35void 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
6class BonusPoint
7 : public GameEntity
8{
9public:
10 enum
11 {
12 Type = UserType + Transmission::bonuspoint
13 };
14
15public:
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 @@
1TEMPLATE = lib
2CONFIG += staticlib
3
4include(../common.pri)
5
6SOURCES += 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
15HEADERS += 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
26OTHER_FILES += style.qss \
27 pacman.rc
28
29RESOURCES += pacman.qrc
30RC_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
5namespace 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
59namespace 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
76namespace 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
3GameEntity::GameEntity(Color::Color color, QGraphicsItem *parent)
4 : PixmapItem(parent), m_type(Type), m_color(color)
5{}
6
7GameEntity::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
9class Actor;
10
11/**
12 * Base class for entities that interact in the game
13 */
14class GameEntity
15 : public PixmapItem
16{
17public:
18 enum
19 {
20 Type = UserType + 1
21 };
22
23 enum EnteredState
24 {
25 Nothing,
26 DestroyedEntity,
27 DestroyedActor
28 };
29
30public:
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
67protected:
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 */
2static 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 */
2static 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
4PixmapItem::PixmapItem(QGraphicsItem *parent)
5 : QGraphicsObject(parent), m_x(0), m_y(0)
6{
7}
8
9PixmapItem::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
17PixmapItem::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
26PixmapItem::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
33PixmapItem::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
41void PixmapItem::setPixmap(const QPixmap &pix)
42{
43 m_pix = pix;
44 m_width = m_pix.width();
45 m_height = m_pix.height();
46}
47
48void 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
56QSizeF PixmapItem::size() const
57{
58 return QSizeF(m_width, m_height);
59}
60
61QRectF PixmapItem::boundingRect() const
62{
63 return QRectF(QPointF(0, 0), size());
64}
65
66QPainterPath PixmapItem::shape() const
67{
68 QPainterPath path;
69 path.addRect(boundingRect());
70 return path;
71}
72
73void 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
7class PixmapItem
8 : public QGraphicsObject
9{
10public:
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
26private:
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
5namespace
6{
7 QPixmap *pixmap = NULL;
8}
9
10Point::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
24GameEntity::EnteredState Point::enter(Actor *actor)
25{
26 actor->addRoundPoints(Constants::Game::point_value);
27 return DestroyedEntity;
28}
29
30void 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
6class Point
7 : public GameEntity
8{
9public:
10 enum
11 {
12 Type = UserType + Transmission::point
13 };
14
15public:
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
10SceneHolder::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
23void 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
49void 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
68void 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
88void 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
245void SceneHolder::setColor(Color::Color color)
246{
247 m_color = color;
248}
249
250Color::Color SceneHolder::color()
251{
252 return m_color;
253}
254
255unsigned int SceneHolder::pointsLeft()
256{
257 return m_pointsLeft;
258}
259
260void SceneHolder::decrementPoints()
261{
262 --m_pointsLeft;
263}
264
265void SceneHolder::setEatingOrder(QList<Color::Color> &order)
266{
267 m_eatingorder = order;
268}
269
270QList<Color::Color> &SceneHolder::eatingOrder()
271{
272 return m_eatingorder;
273}
274
275void 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\"/> &nbsp;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
318void 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
346QPoint SceneHolder::mapPositionToCoord(unsigned int x, unsigned int y)
347{
348 return QPoint(x * Constants::field_size.width, y * Constants::field_size.height);
349}
350
351QPoint SceneHolder::mapPositionToCoord(QPoint point)
352{
353 return mapPositionToCoord(point.x(), point.y());
354}
355
356QPoint SceneHolder::CoordToMapPosition(unsigned int x, unsigned int y)
357{
358 return QPoint(x / Constants::field_size.width, y / Constants::field_size.height);
359}
360
361QPoint 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
7class GameEntity;
8class Actor;
9
10class SceneHolder
11 : public QGraphicsScene
12{
13 Q_OBJECT
14
15public:
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
30signals:
31 void allPointsRemoved();
32
33private slots:
34 void decrementPoints();
35
36protected:
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
45protected:
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 @@
1QGroupBox#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
9QGroupBox#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
17QGroupBox#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
25QGroupBox#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
3namespace 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
8extern "C" {
9#include "enet/enet.h"
10}
11
12namespace 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