1 /* This file is part of KsirK.
2    Copyright (C) 2001-2007 Gael de Chalendar <kleag@free.fr>
3 
4    KsirK is free software; you can redistribute it and/or
5    modify it under the terms of the GNU General Public
6    License as published by the Free Software Foundation, either version 2
7    of the License, or (at your option) any later version.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17    02110-1301, USA
18 */
19 
20 /*  begin                : Wed Jul 18 2001  */
21 
22 
23 #ifndef ANIMSPRITE_H
24 #define ANIMSPRITE_H
25 
26 #include "KsirkGlobalDefinitions.h"
27 #include "animspritespool.h"
28 
29 #include <QGraphicsItem>
30 #include <QTimer>
31 
32 #include <limits>
33 #include <QTextStream>
34 
35 class QSvgRenderer;
36 
37 namespace Ksirk
38 {
39 
40 class BackGnd;
41 namespace GameLogic
42 {
43   class Country;
44 }
45 
46 /**
47  * The AnimSprite objects are the animated images used for all individual
48  * moving objects in KsirK. It is based on QGraphicsPixmapItem that handle
49  * all sprite specific behavior (sequence of images...). The individual
50  * images are taken from an SVG image that stores all the versions of the sprite.
51  * A sprite also have a direction (that allows to select the images looking
52  * toward left or right) and a destination point allowing to handle sprite
53  * movement.
54  *
55  */
56 class AnimSprite : public QObject, public QGraphicsPixmapItem
57 {
58   Q_OBJECT
59 public:
60   /**
61   * When used for fight display, the sprites can be attacker or
62   * defendant. In the other cases, they are nothing particular (NONE)
63   * This state is only used for explosion animation
64   */
65   enum State {NONE, ATTACKER, DEFENDANT};
66 
67   enum TDir {state, right, left, up, down, N, S, E, O, NO, SO, SE, NE};
68 
69   /**
70     * This constructor allows to create a new @ref AnimSprite whose images are
71     * taken from the given file name with the given number of frames and
72     * number of look directions
73     * @param svgid The id of the SVG element from which to load images
74     * @param aBackGnd The background giving info about the world geometry and
75     * access to the underlying QGraphicsScene
76     * @param nbFrames The number of different frames in this sprite animation,
77     * thus the number of columns in the sprite image
78     * @param nbDirs The number of different views on the sprite,
79     * thus the number of rows in the sprite image
80     * @param visibility Measures how much this sprite is visible. It gives its
81     * Z value on the graphics scene.
82     */
83   AnimSprite(const QString &svgid,
84               unsigned int width,
85               unsigned int height,
86               unsigned int nbFrames, unsigned int nbDirs,
87               double zoom,
88               BackGnd* aBackGnd,
89               unsigned int visibility = 100);
90 
91   /** The default destructor */
92   ~AnimSprite() override;
93 
94   /**
95     * Moves the sprite by one step towards its destinationPoint.
96     */
97   void moveIt();
98 
99   /**
100     * Hides and shows the sprite. Causes it to be repainted.
101     */
102   void repaint();
103 
104   /**
105     * Return true if the current frame is the last one. False otherwise.
106     */
107   bool isLastFrame() const;
108 
109   //@{
110   /**
111     * Accessors to some variables
112     */
113   void setDestination(GameLogic::Country *);
114   GameLogic::Country *getDestination();
115   void setDestinationPoint(const QPointF &);
116   const QPointF& getDestinationPoint() const;
117   bool isAttacker() const;
118   void setAttacker();
119   bool isDefendant() const;
120   void setDefendant();
121   bool isNone() const;
122   void setNone();
getBackGnd()123   inline BackGnd* getBackGnd() {return backGnd;}
124   //@}
125 
126   /**
127     * Bit to bit comparison
128     */
129   int operator==(const AnimSprite& Arg1) const;
130 
131   /**
132     * executes setLook towards left or right according to the relative
133     * abscissa of the current position point and the destination point
134     */
135   void turnTowardDestination();
136 
137   /**
138     * Simplified changing of the images sequence of the sprite. Use default
139     * values built from the given id
140     * @param id The base id from which skin data is accessed
141     */
142   void changeSequence(const QString &id);
143 
144   /**
145     * Change the images sequence of the sprite.
146     * @param imgPath The path to the SVG file containing the sprite's new images
147     * @param newNbFrames The number of frames of the sprite in the new image
148     * @param nbDirs The number of directions of the sprite in the new image
149     */
150   void changeSequence(const QString &imgPath,
151                        unsigned int width,
152                        unsigned int height,
153                        unsigned int newNbFrames, unsigned int nbDirs);
154 
155   /** Turns the sprite towards left */
156   void setLookLeft();
157 
158   /** Turns the sprite towards right */
159   void setLookRight();
160 
161   /**
162     * Test if the sprites looks to left
163     * @return true if the sprite is directed towards left and false otherwise
164     */
165   bool looksToLeft() const;
166 
167   /**
168     * Test if the sprites looks to right
169     * @return true if the sprite is directed towards right and true otherwise
170     */
171   bool looksToRight() const;
172 
173   /** Write property of bool approachDestByRight. */
174   void setApproachDestByRight( const bool& _newVal);
175   /** Read property of bool approachDestByRight. */
176   bool getApproachDestByRight() const;
177 
178   /** Write property of bool approachDestByLeft . */
179   void setApproachDestByLeft ( const bool& _newVal);
180   /** Read property of bool approachDestByLeft . */
181   bool getApproachDestByLeft () const;
182 
183   /** Write property of bool approachDestByTop. */
184   void setApproachDestByTop( const bool& _newVal);
185   /** Read property of bool approachDestByTop. */
186   bool getApproachDestByTop() const;
187 
188   /** Write property of bool approachDestByBottom . */
189   void setApproachDestByBottom ( const bool& _newVal);
190   /** Read property of bool approachDestByBottom . */
191   bool getApproachDestByBottom () const;
192 
193   /**
194     * Return the maximum value for x for this sprite by looking to its
195     * including background. Necessary for directed approaches.
196     */
197   qreal getMaxX() const;
198 
199   /**
200     * Return the maximum value for y for this sprite by looking to its
201     * including background. Necessary for directed approaches.
202     */
203   qreal getMaxY() const;
204 
205   /** returns the current state of the sprite */
206   State getState() const;
207 
208   /** Return true if the state of the game is the argument; false otherwise */
209   bool isMyState(State state) const;
210 
211   /** sets the new state of the game */
212   void setState(State newState);
213 
214   /**
215     * This function chooses the approach mode of a sprite towards its destination:
216     * if the distance between the origin and the destination is higher than half
217     * the size of the map and if the origin and destination countries comunicate,
218     * then the sprite should choose an approach by left or right, through the
219     * edge of the map.
220     * This protected method will be called by three public functions specialized
221     * using as source point, respectivly, the infantryman point, the cavalryman
222     * point and the cannon point.
223     */
224   void setupTravel(GameLogic::Country* src, GameLogic::Country* dest,
225     const QPointF& srcPoint, const QPointF& destPoint);
226 
227   /**
228     * This virtual function chooses the approach mode of a sprite towards its
229     * destination. It will be overloaded by subclasses:
230     * if the distance between the origin and the destination is higher than half
231     * the size of the map and if the origin and destination countries comunicate,
232     * then the sprite should choose an approach by left or right, through the
233     * edge of the map.
234     */
235   virtual void setupTravel(GameLogic::Country* src, GameLogic::Country* dest,
236     const QPointF* dpi=0);
237 
238   /**
239     * Saves a XML representation of the sprite for game saving purpose
240     * @param xmlStream The stream to write on
241     */
242   virtual void saveXml(QTextStream& xmlStream);
243 
244   /**
245     * Retrieves the numFrame's frame image of this sprite in its current
246     * direction
247     * @param numFrame The index of the image to retrieve
248     * @return a copy of the numFrame's image of this sprite in its current
249     * direction
250     */
251   QPixmap image(unsigned int numFrame) const;
252 
253   void arrival();
254 
255   void setAnimated(unsigned int numberOfShots = std::numeric_limits<unsigned int>::max());
256 
257   void setStatic();
258 
259   void applyZoomFactor(qreal zoomFactor);
260 
261   void addDecoration(const QString& svgid, const QRectF& geometry);
262 
263 public slots:
264   void animate();
265 
266 signals:
267 
268   /**
269     * emitted when the coordinates of the sprite become equal to those of its
270     * destination point
271     */
272   void atDestination(AnimSprite* sprite);
273 
274   void animationFinished(AnimSprite* sprite);
275 
276 protected:
sceneEvent(QEvent *)277   bool sceneEvent ( QEvent *  ) override {return false;}
278 
279   /**
280     * Set this sprite to display its numFrame's frame. If numFrame is greater
281     * than the number of frames of the sprite, do nothing
282     * @param numFrame The number of the frame to display
283     */
284   void setFrame(unsigned int numFrame);
285 
286   /**
287     * Builds the sequence of images of this sprite using the SVG renderer and
288     * data about zoom factor, look direction, etc.
289     */
290   void sequenceConstruction();
291 
292   /**
293     * changes the direction of this sprite's look
294     */
295   void setLook(TDir);
296 
297   bool m_animated;
298 
299   /**
300    * Zoom factor
301    */
302   double m_zoom;
303 
304   private:
305   QString m_svgid;
306 
307   /**
308     * Change the active frame to the next one in the list. Use the first one
309     * if the current frame was the last one
310     *
311     */
312   void nextFrame();
313 
314   /**
315   * Direction of the look of the sprite (left or right) ;
316   * Allows to select the good image sequence
317   */
318   TDir look;
319 
320   /**
321     * The number of versions of the sprite
322     */
323   unsigned int nbVersions;
324 
325   /**
326     * The background onto which the sprite will be displayed
327     */
328   BackGnd *backGnd;
329 
330   /**
331     * For a sprite moving from one country to another, the destination one ;
332     * NULL otherwise.
333     */
334   GameLogic::Country *destination;
335 
336   /**
337     * The coordinates of the destination (gun point or flag point for example)
338     */
339   QPointF destinationPoint;
340 
341   /**
342     * the number of images in a version of the sprite
343     */
344   unsigned int frames;
345 
346   /**
347     * the number of the current image in the current version of the sprite
348     */
349   unsigned int actFrame;
350 
351   /**
352     * The attacking state of the sprite
353     */
354   State myState;
355 
356   /**
357     * Position information needed to load graphics from the pool
358     */
359   double m_height, m_width;
360 
361   /** If this member is true, the sprite should approach its destination by
362     * the left. So, if it is at the right side of its dest, it will continue
363     * towards right up to the right side of the world. There, it will jump at
364     * the left side and continue directly towards its destination.
365     * When this member is set to true, the sprite should set
366     * approachDestByRight to false. If both are false, the sprite will go
367     * directly towards its destination.
368     */
369   bool approachDestByLeft ;
370 
371   /** If this member is true, the sprite should approach its destination by
372     * the right. So, if it is at the left side of its dest, it will continue
373     * towards left up to the left side of the world. There, it will jump at
374     * the right side and continue directly towards its destination.
375     * When this member is set to true, the sprite should set
376     * approachDestByLeft to false. If both are false, the sprite will go
377     * directly towards its destination.
378     */
379   bool approachDestByRight;
380 
381   /** If this member is true, the sprite should approach its destination by
382     * the top. So, if it is under its dest, it will continue
383     * towards the bottom down to the bottom side of the world. There, it will
384     *  jump at the top side and continue directly towards its destination.
385     * When this member is set to true, the sprite should set
386     * approachDestByBottom to false. If both are false, the sprite will go
387     * directly towards its destination.
388     */
389   bool approachDestByTop ;
390 
391   /** If this member is true, the sprite should approach its destination by
392     * the bottom. So, if it is upper its dest, it will continue
393     * towards the top up to the top side of the world. There, it will jump at
394     * the bottom side and continue directly towards its destination.
395     * When this member is set to true, the sprite should set
396     * approachDestByTop to false. If both are false, the sprite will go
397     * directly towards its destination.
398     */
399   bool approachDestByBottom;
400 
401 
402   /**
403     * Stores the images of this sprite for all its directions with the current
404     * SVG file and zoom factor.
405     */
406   QList<QPixmap> m_frames;
407 
408   /**
409     * This SVG renderer stores the SVG file of this sprite, renders it at the
410     * desired zoom factor and the result is used to fill the frames list
411     */
412   QSvgRenderer* m_renderer;
413 
414   unsigned int m_numberOfShots;
415 
416   QTimer m_timer;
417 
418   QString m_skin;
419 };
420 
421 } // closing namespace Ksirk
422 
423 #endif // ANIMSPRITE_H
424