1 /******************************************************************************
2  *  Warmux is a convivial mass murder game.
3  *  Copyright (C) 2001-2011 Warmux Team.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18  ******************************************************************************
19  * Abstract class used for physical object (object with a size, mass,
20  * etc.). This object can have differents state : ready, is moving, or ghost
21  * (is outside of the world).
22  *
23  * You can : make the object move (with collision test), change state, etc.
24  * If the object go outside of the world, it become a ghost.
25  *****************************************************************************/
26 
27 #ifndef PHYSICAL_OBJECT_H
28 #define PHYSICAL_OBJECT_H
29 
30 #include "physics.h"
31 #include <WARMUX_point.h>
32 #include <WARMUX_rectangle.h>
33 
34 // Alive state
35 typedef enum
36 {
37   ALIVE,
38   DEAD,
39   GHOST,
40   DROWNED
41 } alive_t;
42 
43 // Forward declaration
44 class Action;
45 class Character;
46 
47 #define PIXEL_PER_METER 40
48 static const Double METER_PER_PIXEL(1.0/PIXEL_PER_METER);
49 
50 class PhysicalObj : public Physics
51 {
52   // collision management
53   bool m_collides_with_ground;
54   bool m_collides_with_characters;
55   bool m_collides_with_objects;
56   // Special meaning, SignalObjectCollision is called but trajectory continues
57   // until out of map
58   bool m_go_through_objects;
59   PhysicalObj *m_last_collided_object;
60 
61   Point2i m_rebound_position;
62 
63   // Rectangle used for collision tests
64   int m_test_left, m_test_right, m_test_top, m_test_bottom;
65 
66   // Object size and position.
67   int m_width, m_height;
68 
69   bool can_be_ghost;
70 
71 protected:
72   PhysicalObj* m_overlapping_object;
73   uint m_minimum_overlapse_time;
74   bool m_ignore_movements;
75   bool m_is_character;
76   bool m_is_fire;
77 
78   virtual void CheckOverlapping();
79 
80   std::string m_name;
81   std::string m_unique_id;
82 
83   std::string m_rebound_sound;
84 
85   alive_t m_alive;
86   int m_energy;
87 
88   bool m_allow_negative_y;
89 
StartMoving()90   void StartMoving()
91   {
92     m_last_collided_object = NULL;
93     Physics::StartMoving();
94   }
95 
96 public:
97   PhysicalObj(const std::string &name, const std::string &xml_config="");
98   /* Note : The copy constructor is not implemented (and this is not a bug)
99    * because we can copy directly the pointer m_overlapping_object whereas this
100    * object does not own it.
101    * FIXME what happen if the object is deleted meanwhile ???*/
102   virtual ~PhysicalObj();
103 
104   //-------- Set position and size -------
105 
CanBeGhost(bool state)106   void CanBeGhost(bool state) { can_be_ghost = state; }
107 
108   // Set/Get position - notice how we don't introduce rounding of the other coordinate
SetX(Double x)109   void SetX(Double x) { SetXY( Point2d(x, GetPhysY() * PIXEL_PER_METER) ); };
SetY(Double y)110   void SetY(Double y) { SetXY( Point2d(GetPhysX() * PIXEL_PER_METER, y) ); };
SetXY(const Point2i & position)111   void SetXY(const Point2i &position) { SetXY(Point2d(position.x, position.y)); };
112   void SetXY(const Point2d &position);
113   // GetX/GetY use a hack assuming the coordinates are always positive!
GetX()114   int GetX() const { return uround(GetPhysX() * PIXEL_PER_METER); };
GetY()115   int GetY() const { return uround(GetPhysY() * PIXEL_PER_METER); };
116   // Get{X,Y} used to depend on Get{X,Y}Double, but this seems unnecessary Double roundtrips
GetXDouble()117   Double GetXDouble() const { return GetX(); };
GetYDouble()118   Double GetYDouble() const { return GetY(); };
GetPosition()119   const Point2d GetPosition() const { return Point2d(GetXDouble(), GetYDouble()) ;};
120 
121   // Set/Get size
122   void SetSize(const Point2i &newSize);
GetWidth()123   int GetWidth() const { return m_width; };
GetHeight()124   int GetHeight() const { return m_height; };
GetSize()125   Point2i GetSize() const { return Point2i(m_width, m_height); };
126 
127   // Set/Get test rectangles
128   void SetTestRect (uint left, uint right, uint top, uint bottom);
129   // Optimized intersection test
130   inline bool Intersect(const Rectanglei & position) const;
GetTestRect()131   const Rectanglei GetTestRect() const
132   {
133     int width = m_width - m_test_right - m_test_left;
134     int height = m_height - m_test_bottom - m_test_top;
135     width  =  width ?  width : 1;
136     height = height ? height : 1;
137     return Rectanglei(GetX() + m_test_left, GetY() + m_test_top, width, height);
138   }
GetTestWidth()139   int GetTestWidth() const { return m_width -m_test_left -m_test_right; };
GetTestHeight()140   int GetTestHeight() const { return m_height -m_test_top -m_test_bottom; };
141 
142   //----------- Access to datas (read only) ----------
GetName()143   virtual const std::string &GetName() const { return m_name; }
144 
GetUniqueId()145   const std::string &GetUniqueId() const { return m_unique_id; }
SetUniqueId(const std::string & s)146   void SetUniqueId(const std::string& s) { m_unique_id = s; }
147 
GetCenterX()148   int GetCenterX() const { return GetX() +m_test_left +GetTestWidth()/2; };
GetCenterY()149   int GetCenterY() const { return GetY() +m_test_top +GetTestHeight()/2; };
GetCenter()150   const Point2i GetCenter() const { return Point2i(GetCenterX(), GetCenterY()); };
GetRect()151   const Rectanglei GetRect() const { return Rectanglei( GetX(), GetY(), m_width, m_height); };
CollidesWithGround()152   bool CollidesWithGround() const { return m_collides_with_ground; }
153   // This is a hack
CanBeBlasted()154   bool CanBeBlasted() const { return m_collides_with_ground && !m_go_through_objects; }
IsCharacter()155   bool IsCharacter() const { return m_is_character; }
156 
157   //----------- Physics related function ----------
158 
159   // Update position (and state) with current time
160   void UpdatePosition();
161 
162   // Move the character until he gets out of the ground
163   bool PutOutOfGround();
164 
165   // Where direction is the angle of the direction where the object is moved
166   // and max_distance is max distance allowed when putting out
167   bool PutOutOfGround(Double direction, Double max_distance=30);
168 
169   // Collision management
170   void SetCollisionModel(bool collides_with_ground,
171                          bool collides_with_characters,
172                          bool collides_with_objects,
173                          bool go_through_objects = false);
174   void SetOverlappingObject(PhysicalObj* obj, int timeout = 0);
GetOverlappingObject()175   const PhysicalObj* GetOverlappingObject() const { return m_overlapping_object; };
IsOverlapping(const PhysicalObj * obj)176   virtual bool IsOverlapping(const PhysicalObj* obj) const { return m_overlapping_object == obj; };
177 
178   bool IsInVacuumXY(const Point2i &position, bool check_objects = true) const;
179   // Relative to current position
180   bool IsInVacuum(const Point2i &offset, bool check_objects = true) const { return IsInVacuumXY(GetPosition() + offset, check_objects); };
181   PhysicalObj* CollidedObjectXY(const Point2i & position) const;
182   // Relative to current position
183   PhysicalObj* CollidedObject(const Point2i & offset = Point2i(0,0)) const { return CollidedObjectXY(GetPosition() + offset); };
184   bool FootsInVacuumXY(const Point2i & position) const;
FootsInVacuum()185   bool FootsInVacuum() const { return FootsInVacuumXY(GetPosition()); };
186 
187   bool IsInWater() const;
188 
189   // The object is outside of the world
190   bool IsOutsideWorldXY(const Point2i& position) const;
191   // Relative to current position
192   bool IsOutsideWorld(const Point2i &offset = Point2i(0,0)) const { return IsOutsideWorldXY( GetPosition() + offset ); };
193 
194   // Refresh datas
195   virtual void Refresh() = 0;
196 
197   // Draw the object
198   virtual void Draw() = 0;
199 
200   // Damage handling
201   virtual void SetEnergyDelta(int delta, Character* dealer);
202 
203   //-------- state ----
204   void Init();
205   void Ghost();
206   void Drown();
207   void GoOutOfWater(); // usefull for supertux.
208 
IsImmobile()209   virtual bool IsImmobile() const { return IsSleeping() || m_ignore_movements ||(!IsMoving() && !FootsInVacuum())||(m_alive == GHOST); };
210 
IsGhost()211   bool IsGhost() const { return m_alive == GHOST; };
IsDrowned()212   bool IsDrowned() const { return m_alive == DROWNED; };
IsDead()213   bool IsDead() const { return IsGhost() || IsDrowned() || m_alive==DEAD; };
IsFire()214   bool IsFire() const { return m_is_fire; }
215 
216   // Are the two object in contact ? (uses test rectangles)
Overlapse(const PhysicalObj & b)217   bool Overlapse(const PhysicalObj &b) const { return GetTestRect().Intersect( b.GetTestRect() ); };
218 
219   // Do the point p touch the object ?
Contain(const Point2i & p)220   bool Contain(const Point2i &p) const { return  GetTestRect().Contains( p ); };
221 
222   bool PutRandomly(bool on_top_of_world, Double min_dst_with_characters, bool net_sync = true);
223 
224   collision_t NotifyMove(Point2d oldPos, Point2d newPos);
225 
226 protected:
227   virtual void SignalRebound();
SignalGroundCollision(const Point2d &,const Double &)228   virtual void SignalGroundCollision(const Point2d& /* my_speed_before */, const Double& /*contactAngle*/) { };
SignalObjectCollision(const Point2d &,PhysicalObj *,const Point2d &)229   virtual void SignalObjectCollision(const Point2d& /* my_speed_before */,
230                                      PhysicalObj * /* collided/ing object */,
231                                      const Point2d& /* object speed_before */) { };
SignalOutOfMap()232   virtual void SignalOutOfMap() { };
233 
234 private:
235   //Retrun the position of the point of contact of the obj on the ground
236   bool ContactPoint(int &x, int &y) const;
237 
238 
239   // The object fall directly to the ground (or become a ghost)
240   void DirectFall();
241 
242   // Directly after a rebound, if we are stuck in a wall, we stop moving
243   void CheckRebound();
244 
245   void Collide(collision_t collision, PhysicalObj* collided_obj, const Point2d& position);
246 
247   void ContactPointAngleOnGround(const Point2d& oldPos,
248                                  Point2d& contactPos,
249                                  Double& contactAngle) const;
250 };
251 
252 #endif
253