1 | /* |
2 | Copyright (C) 2002-2005, Jason Katz-Brown <jasonkb@mit.edu> |
3 | Copyright 2010 Stefan Majewsky <majewsky@gmx.net> |
4 | |
5 | This program is free software; you can redistribute it and/or modify |
6 | it under the terms of the GNU General Public License as published by |
7 | the Free Software Foundation; either version 2 of the License, or |
8 | (at your option) any later version. |
9 | |
10 | This program is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | GNU General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU General Public License |
16 | along with this program; if not, write to the Free Software |
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
18 | */ |
19 | |
20 | #ifndef GAME_H |
21 | #define GAME_H |
22 | |
23 | //#define SOUND |
24 | |
25 | #include <kolflib_export.h> |
26 | #include "ball.h" |
27 | |
28 | #include "tagaro/scene.h" |
29 | |
30 | #include <QGraphicsView> |
31 | #include <KLocale> |
32 | #include <KConfigGroup> |
33 | |
34 | class QLabel; |
35 | class QSlider; |
36 | class QCheckBox; |
37 | class QVBoxLayout; |
38 | class KolfGame; |
39 | class KGameRenderer; |
40 | |
41 | namespace Kolf |
42 | { |
43 | class Wall; |
44 | } |
45 | namespace Tagaro |
46 | { |
47 | class Board; |
48 | } |
49 | namespace Phonon |
50 | { |
51 | class MediaObject; |
52 | } |
53 | namespace Kolf |
54 | { |
55 | class ItemFactory; |
56 | KGameRenderer* renderer(); |
57 | Tagaro::Board* findBoard(QGraphicsItem* item); //TODO: temporary HACK |
58 | b2World* world(); //TODO: temporary HACK (should be inside KolfGame, but various places outside the game need to create CanvasItems) |
59 | } |
60 | |
61 | enum Direction { D_Left, D_Right, Forwards, Backwards }; |
62 | enum Amount { Amount_Less, Amount_Normal, Amount_More }; |
63 | |
64 | class BallStateInfo |
65 | { |
66 | public: |
67 | void saveState(KConfigGroup *cfgGroup); |
68 | void loadState(KConfigGroup *cfgGroup); |
69 | |
70 | int id; |
71 | QPoint spot; |
72 | BallState state; |
73 | bool beginningOfHole; |
74 | int score; |
75 | }; |
76 | class BallStateList : public QList<BallStateInfo> |
77 | { |
78 | public: |
79 | int hole; |
80 | int player; |
81 | bool canUndo; |
82 | Vector vector; |
83 | }; |
84 | |
85 | class Player |
86 | { |
87 | public: |
88 | Player() : m_ball(new Ball(0, Kolf::world())) {} |
89 | Ball *ball() const { return m_ball; } |
90 | void setBall(Ball *ball) { m_ball = ball; } |
91 | BallStateInfo stateInfo(int hole) const { BallStateInfo ret; ret.spot = m_ball->pos().toPoint(); ret.state = m_ball->curState(); ret.score = score(hole); ret.beginningOfHole = m_ball->beginningOfHole(); ret.id = m_id; return ret; } |
92 | |
93 | QList<int> scores() const { return m_scores; } |
94 | void setScores(const QList<int> &newScores) { m_scores = newScores; } |
95 | int score(int hole) const { return m_scores.at(hole - 1); } |
96 | int lastScore() const { return m_scores.last(); } |
97 | int firstScore() const { return m_scores.first(); } |
98 | |
99 | void addStrokeToHole(int hole) { (*(m_scores.begin() + (hole -1)))++; } |
100 | void setScoreForHole(int score, int hole) { (*(m_scores.begin() + (hole - 1))) = score; } |
101 | void subtractStrokeFromHole(int hole) { (*(m_scores.begin() + (hole -1))--); } |
102 | void resetScore(int hole) { (*(m_scores.begin() + (hole - 1))) = 0; } |
103 | void addHole() { m_scores.append(0); } |
104 | unsigned int numHoles() const { return m_scores.count(); } |
105 | |
106 | QString name() const { return m_name; } |
107 | void setName(const QString &name) { m_name = name; m_ball->setName(name); } |
108 | |
109 | void setId(int id) { m_id = id; } |
110 | int id() const { return m_id; } |
111 | |
112 | private: |
113 | Ball *m_ball; |
114 | QList<int> m_scores; |
115 | QString m_name; |
116 | int m_id; |
117 | }; |
118 | |
119 | typedef QList<Player> PlayerList; |
120 | |
121 | class Putter : public QGraphicsLineItem, public CanvasItem |
122 | { |
123 | public: |
124 | Putter(QGraphicsItem* parent, b2World* world); |
125 | |
126 | void go(Direction, Amount amount = Amount_Normal); |
127 | void setOrigin(double x, double y); |
128 | double curLen() const { return guideLineLength; } |
129 | double curAngle() const { return angle; } |
130 | int curDeg() const { return rad2deg(angle); } |
131 | virtual void showInfo(); |
132 | virtual void hideInfo(); |
133 | void setAngle(double news) { angle = news; finishMe(); } |
134 | void setDeg(int news) { angle = deg2rad(news); finishMe(); } |
135 | double curMaxAngle() const { return maxAngle; } |
136 | virtual void setVisible(bool yes); |
137 | void saveAngle(Ball *ball) { angleMap[ball] = angle; } |
138 | void setAngle(Ball *ball); |
139 | void resetAngles() { angleMap.clear(); setZValue(999999); } |
140 | virtual void moveBy(double dx, double dy); |
141 | void setShowGuideLine(bool yes); |
142 | |
143 | virtual QPointF getPosition() const { return QGraphicsItem::pos(); } |
144 | private: |
145 | QPointF midPoint; |
146 | double maxAngle; |
147 | double angle; |
148 | double oneDegree; |
149 | QMap<Ball *, double> angleMap; |
150 | double guideLineLength, putterWidth; |
151 | void finishMe(); |
152 | QGraphicsLineItem *guideLine; |
153 | bool m_showGuideLine; |
154 | }; |
155 | |
156 | class HoleInfo; |
157 | class HoleConfig : public Config |
158 | { |
159 | Q_OBJECT |
160 | |
161 | public: |
162 | HoleConfig(HoleInfo *holeInfo, QWidget *); |
163 | |
164 | private slots: |
165 | void authorChanged(const QString &); |
166 | void parChanged(int); |
167 | void maxStrokesChanged(int); |
168 | void nameChanged(const QString &); |
169 | void borderWallsChanged(bool); |
170 | |
171 | private: |
172 | HoleInfo *holeInfo; |
173 | }; |
174 | class HoleInfo : public CanvasItem |
175 | { |
176 | public: |
177 | HoleInfo(b2World* world) : CanvasItem(world) { setSimulationType(CanvasItem::NoSimulation); m_lowestMaxStrokes = 4; } |
178 | virtual ~HoleInfo() {} |
179 | void setPar(int newpar) { m_par = newpar; } |
180 | int par() const { return m_par; } |
181 | void setMaxStrokes(int newMaxStrokes) { m_maxStrokes = newMaxStrokes; } |
182 | int lowestMaxStrokes() const { return m_lowestMaxStrokes; } |
183 | int maxStrokes() const { return m_maxStrokes; } |
184 | bool hasMaxStrokes() const { return m_maxStrokes != m_lowestMaxStrokes; } |
185 | void setAuthor(QString newauthor) { m_author = newauthor; } |
186 | QString author() const { return m_author; } |
187 | |
188 | void setName(QString newname) { m_name = newname; } |
189 | void setUntranslatedName(QString newname) { m_untranslatedName = newname; } |
190 | QString name() const { return m_name; } |
191 | QString untranslatedName() const { return m_untranslatedName; } |
192 | |
193 | virtual Config *config(QWidget *parent) { return new HoleConfig(this, parent); } |
194 | void borderWallsChanged(bool yes); |
195 | bool borderWalls() const { return m_borderWalls; } |
196 | |
197 | virtual QPointF getPosition() const { return QPointF(); } |
198 | private: |
199 | QString m_author; |
200 | QString m_name; |
201 | QString m_untranslatedName; |
202 | bool m_borderWalls; |
203 | int m_par; |
204 | int m_maxStrokes; |
205 | int m_lowestMaxStrokes; |
206 | }; |
207 | |
208 | class StrokeCircle : public QGraphicsItem |
209 | { |
210 | public: |
211 | StrokeCircle(QGraphicsItem *parent); |
212 | |
213 | void setValue(double v); |
214 | double value(); |
215 | void setMaxValue(double m); |
216 | void setSize(const QSizeF& size); |
217 | void setThickness(double t); |
218 | double thickness() const; |
219 | double width() const; |
220 | double height() const; |
221 | virtual void paint (QPainter *, const QStyleOptionGraphicsItem *, QWidget *); |
222 | virtual QRectF boundingRect() const; |
223 | virtual bool collidesWithItem(const QGraphicsItem*, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const; |
224 | |
225 | private: |
226 | double dvalue, dmax; |
227 | double ithickness, iwidth, iheight; |
228 | }; |
229 | |
230 | struct KOLFLIB_EXPORT CourseInfo |
231 | { |
232 | CourseInfo(const QString &_name, const QString &_untranslatedName, const QString &_author, unsigned int _holes, unsigned int _par) { name = _name; untranslatedName = _untranslatedName, author = _author; holes = _holes; par = _par; } |
233 | CourseInfo(); |
234 | |
235 | QString name; |
236 | QString untranslatedName; |
237 | QString author; |
238 | unsigned int holes; |
239 | unsigned int par; |
240 | }; |
241 | |
242 | class KOLFLIB_EXPORT KolfGame : public QGraphicsView |
243 | { |
244 | Q_OBJECT |
245 | |
246 | public: |
247 | KolfGame(const Kolf::ItemFactory& factory, PlayerList *players, const QString &filename, QWidget *parent=0); |
248 | ~KolfGame(); |
249 | void setFilename(const QString &filename); |
250 | QString curFilename() const { return filename; } |
251 | void emitLargestHole() { emit largestHole(highestHole); } |
252 | QGraphicsScene *scene() const { return course; } |
253 | void removeItem(QGraphicsItem *item) { m_topLevelQItems.removeAll(item); } |
254 | bool askSave(bool); |
255 | bool isEditing() const { return editing; } |
256 | int currentHole() { return curHole; } |
257 | void setStrict(bool yes) { strict = yes; } |
258 | // returns true when you shouldn't do anything |
259 | bool isPaused() const { return paused; } |
260 | Ball *curBall() const { return (*curPlayer).ball(); } |
261 | void updateMouse(); |
262 | void ballMoved(); |
263 | void setBorderWalls(bool); |
264 | void setInPlay(bool yes) { inPlay = yes; } |
265 | bool isInPlay() { return inPlay; } |
266 | bool isInfoShowing() { return m_showInfo; } |
267 | void stoppedBall(); |
268 | QString courseName() const { return holeInfo.name(); } |
269 | void hidePutter() { putter->setVisible(false); } |
270 | void ignoreEvents(bool ignore) { m_ignoreEvents = ignore; } |
271 | |
272 | void setSelectedItem(CanvasItem* citem); |
273 | |
274 | static void scoresFromSaved(KConfig*, PlayerList &players); |
275 | static void courseInfo(CourseInfo &info, const QString &filename); |
276 | |
277 | public slots: |
278 | void pause(); |
279 | void unPause(); |
280 | void save(); |
281 | void toggleEditMode(); |
282 | void setModified(bool mod = true); |
283 | void addNewObject(const QString& identifier); |
284 | void addNewHole(); |
285 | void switchHole(int); |
286 | void switchHole(const QString &); |
287 | void nextHole(); |
288 | void prevHole(); |
289 | void firstHole(); |
290 | void lastHole(); |
291 | void randHole(); |
292 | void playSound(const QString &file, float vol = 1); |
293 | void showInfoDlg(bool = false); |
294 | void resetHole(); |
295 | void clearHole(); |
296 | void setShowInfo(bool yes); |
297 | void toggleShowInfo(); |
298 | void updateShowInfo(); |
299 | void setUseMouse(bool yes) { m_useMouse = yes; } |
300 | void setUseAdvancedPutting(bool yes); |
301 | void setShowGuideLine(bool yes); |
302 | void setSound(bool yes); |
303 | void undoShot(); |
304 | void timeout(); |
305 | void saveScores(KConfig *); |
306 | void startFirstHole(int hole); |
307 | void sayWhosGoing(); |
308 | |
309 | signals: |
310 | void holesDone(); |
311 | void newHole(int); |
312 | void parChanged(int, int); |
313 | void titleChanged(const QString &); |
314 | void largestHole(int); |
315 | void scoreChanged(int, int, int); |
316 | void newPlayersTurn(Player *); |
317 | void newSelectedItem(CanvasItem *); |
318 | void checkEditing(); |
319 | void editingStarted(); |
320 | void editingEnded(); |
321 | void inPlayStart(); |
322 | void inPlayEnd(); |
323 | void maxStrokesReached(const QString &); |
324 | void currentHole(int); |
325 | void modifiedChanged(bool); |
326 | void newStatusText(const QString &); |
327 | |
328 | private slots: |
329 | void shotDone(); |
330 | void holeDone(); |
331 | void startNextHole(); |
332 | void fastTimeout(); |
333 | void putterTimeout(); |
334 | void autoSaveTimeout(); |
335 | |
336 | void emitMax(); |
337 | |
338 | protected: |
339 | void mouseMoveEvent(QMouseEvent *e); |
340 | void mousePressEvent(QMouseEvent *e); |
341 | void mouseReleaseEvent(QMouseEvent *e); |
342 | void mouseDoubleClickEvent(QMouseEvent *e); |
343 | |
344 | void handleMousePressEvent(QMouseEvent *e); |
345 | void handleMouseDoubleClickEvent(QMouseEvent *e); |
346 | void handleMouseMoveEvent(QMouseEvent *e); |
347 | void handleMouseReleaseEvent(QMouseEvent *e); |
348 | void keyPressEvent(QKeyEvent *e); |
349 | void keyReleaseEvent(QKeyEvent *e); |
350 | |
351 | //resizes view to make sure it is square and calls resizeAllItems |
352 | void resizeEvent(QResizeEvent *); |
353 | |
354 | QPoint viewportToViewport(const QPoint &p); |
355 | |
356 | private: |
357 | Tagaro::Scene *course; |
358 | Tagaro::Board *courseBoard; |
359 | Putter *putter; |
360 | PlayerList *players; |
361 | PlayerList::Iterator curPlayer; |
362 | Ball *whiteBall; |
363 | StrokeCircle *strokeCircle; |
364 | |
365 | QTimer *timer; |
366 | QTimer *autoSaveTimer; |
367 | QTimer *fastTimer; |
368 | QTimer *putterTimer; |
369 | bool regAdv; |
370 | |
371 | const Kolf::ItemFactory& m_factory; |
372 | QList<QGraphicsItem*> m_topLevelQItems; //includes balls, but not putter |
373 | QList<QGraphicsItem*> m_moveableQItems; |
374 | |
375 | QList<Kolf::Wall *> borderWalls; |
376 | |
377 | int timerMsec; |
378 | int autoSaveMsec; |
379 | int fastTimerMsec; |
380 | int putterTimerMsec; |
381 | |
382 | void puttPress(); |
383 | void puttRelease(); |
384 | bool inPlay; |
385 | bool putting; |
386 | bool stroking; |
387 | bool finishStroking; |
388 | double strength; |
389 | double maxStrength; |
390 | int puttCount; |
391 | bool puttReverse; |
392 | |
393 | int curHole; |
394 | int highestHole; |
395 | int curPar; |
396 | |
397 | int wallWidth; |
398 | int height; |
399 | int width; |
400 | int margin; |
401 | |
402 | int advancePeriod; |
403 | |
404 | int lastDelId; |
405 | |
406 | bool paused; |
407 | |
408 | QString filename; |
409 | bool recalcHighestHole; |
410 | void openFile(); |
411 | |
412 | bool strict; |
413 | |
414 | bool editing; |
415 | QGraphicsItem *selectedItem; |
416 | |
417 | //For intro banner |
418 | Tagaro::SpriteObjectItem *banner; |
419 | |
420 | #ifdef SOUND |
421 | Phonon::MediaObject *m_player; |
422 | #endif |
423 | bool m_sound; |
424 | QString soundDir; |
425 | |
426 | bool m_ignoreEvents; |
427 | |
428 | HoleInfo holeInfo; |
429 | QMap<QString, QPointF> savedState; |
430 | |
431 | BallStateList ballStateList; |
432 | void loadStateList(); |
433 | void recreateStateList(); |
434 | void addHoleInfo(BallStateList &list); |
435 | |
436 | bool dontAddStroke; |
437 | |
438 | bool addingNewHole; |
439 | int scoreboardHoles; |
440 | inline void resetHoleScores(); |
441 | |
442 | bool m_showInfo; |
443 | |
444 | bool infoShown; |
445 | |
446 | KConfig *cfg; |
447 | KConfigGroup cfgGroup; |
448 | |
449 | inline void addBorderWall(const QPoint &start, const QPoint &end); |
450 | void shotStart(); |
451 | void startBall(const Vector &vector); |
452 | |
453 | bool modified; |
454 | |
455 | inline bool allPlayersDone(); |
456 | |
457 | bool m_useMouse; |
458 | bool m_useAdvancedPutting; |
459 | |
460 | QString playerWhoMaxed; |
461 | }; |
462 | |
463 | #endif |
464 | |