SuperTuxKart
soccer_world.hpp
1 //
2 // SuperTuxKart - a fun racing game with go-kart
3 // Copyright (C) 2004-2015 SuperTuxKart-Team
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 3
8 // of the License, or (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 #ifndef SOCCER_WORLD_HPP
20 #define SOCCER_WORLD_HPP
21 
22 #include "modes/world_with_rank.hpp"
23 #include "states_screens/race_gui_base.hpp"
24 #include "karts/abstract_kart.hpp"
25 #include "tracks/check_goal.hpp"
26 #include "tracks/check_manager.hpp"
27 
28 #include <IMesh.h>
29 #include <string>
30 
31 class AbstractKart;
32 class Controller;
33 class NetworkString;
34 class TrackObject;
35 class TrackSector;
36 
41 class SoccerWorld : public WorldWithRank
42 {
43 public:
44  struct ScorerData
45  {
47  unsigned int m_id;
51  float m_time;
53  std::string m_kart;
55  core::stringw m_player;
57  std::string m_country_code;
60  }; // ScorerData
61 
62 private:
64  {
65  public:
67  unsigned int m_kart_id;
69  float m_distance;
70 
71  bool operator < (const KartDistanceMap& r) const
72  {
73  return m_distance < r.m_distance;
74  }
75  KartDistanceMap(unsigned int kart_id = 0, float distance = 0.0f)
76  {
77  m_kart_id = kart_id;
78  m_distance = distance;
79  }
80  }; // KartDistanceMap
81 
83  {
84  // These data are used by AI to determine ball aiming angle
85  private:
86  // Radius of the ball
87  float m_radius;
88 
89  // Slope of the line from ball to the center point of goals
90  float m_red_goal_slope;
91  float m_blue_goal_slope;
92 
93  // The transform only takes the ball heading into account,
94  // ie no hpr of ball which allowing setting aim point easier
95  btTransform m_trans;
96 
97  // Two goals
98  CheckGoal* m_blue_check_goal;
99  CheckGoal* m_red_check_goal;
100 
101  // Location to red/blue goal points from the ball heading point of view
102  Vec3 m_red_goal_1;
103  Vec3 m_red_goal_2;
104  Vec3 m_red_goal_3;
105  Vec3 m_blue_goal_1;
106  Vec3 m_blue_goal_2;
107  Vec3 m_blue_goal_3;
108  public:
109  void reset()
110  {
111  m_red_goal_1 = Vec3(0, 0, 0);
112  m_red_goal_2 = Vec3(0, 0, 0);
113  m_red_goal_3 = Vec3(0, 0, 0);
114  m_blue_goal_1 = Vec3(0, 0, 0);
115  m_blue_goal_2 = Vec3(0, 0, 0);
116  m_blue_goal_3 = Vec3(0, 0, 0);
117  m_red_goal_slope = 1.0f;
118  m_blue_goal_slope = 1.0f;
119  m_trans = btTransform(btQuaternion(0, 0, 0, 1), Vec3(0, 0, 0));
120  } // reset
121 
122  float getDiameter() const
123  {
124  return m_radius * 2;
125  } // getDiameter
126 
127  void init(float ball_radius)
128  {
129  m_radius = ball_radius;
130  assert(m_radius > 0.0f);
131 
132  // Save two goals
133  unsigned int n = CheckManager::get()->getCheckStructureCount();
134  for (unsigned int i = 0; i < n; i++)
135  {
136  CheckGoal* goal = dynamic_cast<CheckGoal*>
137  (CheckManager::get()->getCheckStructure(i));
138  if (goal)
139  {
140  if (goal->getTeam())
141  m_blue_check_goal = goal;
142  else
143  m_red_check_goal = goal;
144  }
145  }
146  if (m_blue_check_goal == NULL || m_red_check_goal == NULL)
147  {
148  Log::error("SoccerWorld", "Goal(s) is missing!");
149  }
150  } // init
151 
152  void updateBallAndGoal(const Vec3& ball_pos, float heading)
153  {
154  btQuaternion quat(Vec3(0, 1, 0), -heading);
155  m_trans = btTransform(btQuaternion(Vec3(0, 1, 0), heading),
156  ball_pos);
157 
158  // Red goal
159  m_red_goal_1 = quatRotate(quat, m_red_check_goal
160  ->getPoint(CheckGoal::POINT_FIRST) - ball_pos);
161  m_red_goal_2 = quatRotate(quat, m_red_check_goal
162  ->getPoint(CheckGoal::POINT_CENTER) - ball_pos);
163  m_red_goal_3 = quatRotate(quat, m_red_check_goal
164  ->getPoint(CheckGoal::POINT_LAST) - ball_pos);
165 
166  // Blue goal
167  m_blue_goal_1 = quatRotate(quat, m_blue_check_goal
168  ->getPoint(CheckGoal::POINT_FIRST) - ball_pos);
169  m_blue_goal_2 = quatRotate(quat, m_blue_check_goal
170  ->getPoint(CheckGoal::POINT_CENTER) - ball_pos);
171  m_blue_goal_3 = quatRotate(quat, m_blue_check_goal
172  ->getPoint(CheckGoal::POINT_LAST) - ball_pos);
173 
174  // Update the slope:
175  // Use y = mx + c as an equation from goal center to ball
176  // As the line always intercept in (0,0) which is the ball location,
177  // so y(z)/x is the slope , it is used for determine aiming position
178  // of ball later
179  m_red_goal_slope = m_red_goal_2.z() / m_red_goal_2.x();
180  m_blue_goal_slope = m_blue_goal_2.z() / m_blue_goal_2.x();
181  } // updateBallAndGoal
182 
183  bool isApproachingGoal(KartTeam team) const
184  {
185  // If the ball lies between the first and last pos, and faces
186  // in front of either of them, (inside angular size of goal)
187  // than it's likely to goal
188  if (team == KART_TEAM_BLUE)
189  {
190  if ((m_blue_goal_1.z() > 0.0f || m_blue_goal_3.z() > 0.0f) &&
191  ((m_blue_goal_1.x() < 0.0f && m_blue_goal_3.x() > 0.0f) ||
192  (m_blue_goal_3.x() < 0.0f && m_blue_goal_1.x() > 0.0f)))
193  return true;
194  }
195  else
196  {
197  if ((m_red_goal_1.z() > 0.0f || m_red_goal_3.z() > 0.0f) &&
198  ((m_red_goal_1.x() < 0.0f && m_red_goal_3.x() > 0.0f) ||
199  (m_red_goal_3.x() < 0.0f && m_red_goal_1.x() > 0.0f)))
200  return true;
201  }
202  return false;
203  } // isApproachingGoal
204 
205  Vec3 getAimPosition(KartTeam team, bool reverse) const
206  {
207  // If it's likely to goal already, aim the ball straight behind
208  // should do the job
209  if (isApproachingGoal(team))
210  return m_trans(Vec3(0, 0, reverse ? m_radius*2 : -m_radius*2));
211 
212  // Otherwise do the below:
213  // This is done by using Pythagorean Theorem and solving the
214  // equation from ball to goal center (y = (m_***_goal_slope) x)
215 
216  // We aim behind the ball from the center of the ball to its
217  // diameter, so 2*m_radius = sqrt (x2 + y2),
218  // which is next x = sqrt (2*m_radius - y2)
219  // And than we have x = y / m(m_***_goal_slope)
220  // After put that in the slope equation, we have
221  // y = sqrt(2*m_radius*m2 / (1+m2))
222  float x = 0.0f;
223  float y = 0.0f;
224  if (team == KART_TEAM_BLUE)
225  {
226  y = sqrt((m_blue_goal_slope * m_blue_goal_slope * m_radius*2) /
227  (1 + (m_blue_goal_slope * m_blue_goal_slope)));
228  if (m_blue_goal_2.x() == 0.0f ||
229  (m_blue_goal_2.x() > 0.0f && m_blue_goal_2.z() > 0.0f) ||
230  (m_blue_goal_2.x() < 0.0f && m_blue_goal_2.z() > 0.0f))
231  {
232  // Determine when y should be negative
233  y = -y;
234  }
235  x = y / m_blue_goal_slope;
236  }
237  else
238  {
239  y = sqrt((m_red_goal_slope * m_red_goal_slope * m_radius*2) /
240  (1 + (m_red_goal_slope * m_red_goal_slope)));
241  if (m_red_goal_2.x() == 0.0f ||
242  (m_red_goal_2.x() > 0.0f && m_red_goal_2.z() > 0.0f) ||
243  (m_red_goal_2.x() < 0.0f && m_red_goal_2.z() > 0.0f))
244  {
245  y = -y;
246  }
247  x = y / m_red_goal_slope;
248  }
249  assert (!std::isnan(x));
250  assert (!std::isnan(y));
251  // Return the world coordinates
252  return (reverse ? m_trans(Vec3(-x, 0, -y)) :
253  m_trans(Vec3(x, 0, y)));
254  } // getAimPosition
255  void resetCheckGoal(const Track* t)
256  {
257  m_red_check_goal->reset(*t);
258  m_blue_check_goal->reset(*t);
259  }
260  }; // BallGoalData
261 
262  std::vector<KartDistanceMap> m_red_kdm;
263  std::vector<KartDistanceMap> m_blue_kdm;
264  BallGoalData m_bgd;
265 
268  btRigidBody* m_ball_body;
269 
272  bool m_count_down_reached_zero;
273 
274  SFXBase *m_goal_sound;
275 
279  int m_ball_hitter;
280 
282  std::vector<ScorerData> m_red_scorers;
283  std::vector<ScorerData> m_blue_scorers;
284 
287 
288  float m_ball_heading;
289 
290  std::vector<btTransform> m_goal_transforms;
292  void updateBallPosition(int ticks);
294  void updateAIData();
296  int getTeamNum(KartTeam team) const;
297 
300  std::vector<int> m_goal_frame;
301 
302  int m_reset_ball_ticks;
303  int m_ticks_back_to_own_goal;
304 
305  void resetKartsToSelfGoals();
306 
307 public:
308 
309  SoccerWorld();
310  virtual ~SoccerWorld();
311 
312  virtual void init() OVERRIDE;
313  virtual void onGo() OVERRIDE;
314 
315  // clock events
316  virtual bool isRaceOver() OVERRIDE;
317  virtual void countdownReachedZero() OVERRIDE;
318  virtual void terminateRace() OVERRIDE;
319 
320  // overriding World methods
321  virtual void reset(bool restart=false) OVERRIDE;
322 
323  virtual unsigned int getRescuePositionIndex(AbstractKart *kart) OVERRIDE;
324  virtual btTransform getRescueTransform(unsigned int rescue_pos) const
325  OVERRIDE;
326  virtual bool useFastMusicNearEnd() const OVERRIDE { return false; }
327  virtual void getKartsDisplayInfo(
328  std::vector<RaceGUIBase::KartIconDisplayInfo> *info) OVERRIDE {}
329 
330  virtual bool raceHasLaps() OVERRIDE { return false; }
331 
332  virtual void enterRaceOverState() OVERRIDE;
333 
334  virtual const std::string& getIdent() const OVERRIDE;
335 
336  virtual void update(int ticks) OVERRIDE;
337 
338  bool shouldDrawTimer() const OVERRIDE { return !isStartPhase(); }
339  // ------------------------------------------------------------------------
340  void onCheckGoalTriggered(bool first_goal);
341  // ------------------------------------------------------------------------
342  void setBallHitter(unsigned int kart_id);
343  // ------------------------------------------------------------------------
345  bool getKartSoccerResult(unsigned int kart_id) const;
346  // ------------------------------------------------------------------------
347  int getScore(KartTeam team) const
348  {
349  return (int)(team == KART_TEAM_BLUE ? m_blue_scorers.size()
350  : m_red_scorers.size());
351  }
352  // ------------------------------------------------------------------------
353  const std::vector<ScorerData>& getScorers(KartTeam team) const
354  { return (team == KART_TEAM_BLUE ? m_blue_scorers : m_red_scorers); }
355  // ------------------------------------------------------------------------
356  int getBallNode() const;
357  // ------------------------------------------------------------------------
358  const Vec3& getBallPosition() const
359  { return (Vec3&)m_ball_body->getCenterOfMassTransform().getOrigin(); }
360  // ------------------------------------------------------------------------
361  bool ballNotMoving() const
362  {
363  return (m_ball_body->getLinearVelocity().x() == 0.0f ||
364  m_ball_body->getLinearVelocity().z() == 0.0f);
365  }
366  // ------------------------------------------------------------------------
367  float getBallHeading() const
368  { return m_ball_heading; }
369  // ------------------------------------------------------------------------
370  float getBallDiameter() const
371  { return m_bgd.getDiameter(); }
372  // ------------------------------------------------------------------------
373  bool ballApproachingGoal(KartTeam team) const
374  { return m_bgd.isApproachingGoal(team); }
375  // ------------------------------------------------------------------------
376  Vec3 getBallAimPosition(KartTeam team, bool reverse = false) const
377  { return m_bgd.getAimPosition(team, reverse); }
378  // ------------------------------------------------------------------------
379  bool isCorrectGoal(unsigned int kart_id, bool first_goal) const;
380  // ------------------------------------------------------------------------
381  int getBallChaser(KartTeam team) const
382  {
383  // Only AI call this function, so each team should have at least a kart
384  assert(m_blue_kdm.size() > 0 && m_red_kdm.size() > 0);
385  return (team == KART_TEAM_BLUE ? m_blue_kdm[0].m_kart_id :
386  m_red_kdm[0].m_kart_id);
387  }
388  // ------------------------------------------------------------------------
390  int getAttacker(KartTeam team) const;
391  // ------------------------------------------------------------------------
392  void handlePlayerGoalFromServer(const NetworkString& ns);
393  // ------------------------------------------------------------------------
394  void handleResetBallFromServer(const NetworkString& ns);
395  // ------------------------------------------------------------------------
396  virtual bool hasTeam() const OVERRIDE { return true; }
397  // ------------------------------------------------------------------------
398  virtual std::pair<uint32_t, uint32_t> getGameStartedProgress() const
399  OVERRIDE
400  {
401  std::pair<uint32_t, uint32_t> progress(
402  std::numeric_limits<uint32_t>::max(),
403  std::numeric_limits<uint32_t>::max());
404  if (race_manager->hasTimeTarget())
405  {
406  progress.first = (uint32_t)m_time;
407  }
408  else if (m_red_scorers.size() > m_blue_scorers.size())
409  {
410  progress.second = (uint32_t)((float)m_red_scorers.size() /
411  (float)race_manager->getMaxGoal() * 100.0f);
412  }
413  else
414  {
415  progress.second = (uint32_t)((float)m_blue_scorers.size() /
416  (float)race_manager->getMaxGoal() * 100.0f);
417  }
418  return progress;
419  }
420  // ------------------------------------------------------------------------
421  virtual void saveCompleteState(BareNetworkString* bns,
422  STKPeer* peer) OVERRIDE;
423  // ------------------------------------------------------------------------
424  virtual void restoreCompleteState(const BareNetworkString& b) OVERRIDE;
425  // ------------------------------------------------------------------------
426  virtual bool isGoalPhase() const OVERRIDE
427  {
428  int diff = m_ticks_back_to_own_goal - getTicksSinceStart();
429  return diff > 0 && diff < stk_config->time2Ticks(3.0f);
430  }
431 }; // SoccerWorld
432 
433 
434 #endif
double m_time
Elasped/remaining time in seconds.
Definition: world_status.hpp:93
HandicapLevel
Handicap per player.
Definition: remote_kart_info.hpp:39
This is the base class for kart controller - that can be a player or a a robot.
Definition: controller.hpp:45
A wrapper around bullets btVector3 to include conventient conversion functions (e....
Definition: vec3.hpp:34
int getTeamNum(KartTeam team) const
Get number of teammates in a team, used by starting position assign.
This object keeps track of which sector an object is on.
Definition: track_sector.hpp:38
virtual const std::string & getIdent() const OVERRIDE
Returns the internal identifier for this race.
Definition: soccer_world.cpp:199
TrackObject * m_ball
Keep a pointer to the track object of soccer ball.
Definition: soccer_world.hpp:267
core::stringw m_player
Player name which scores.
Definition: soccer_world.hpp:55
TrackSector * m_ball_track_sector
Data generated from navmesh.
Definition: soccer_world.hpp:286
virtual void enterRaceOverState() OVERRIDE
Called when the race is finished, but it still leaves some time for an end of race animation,...
Definition: soccer_world.cpp:701
unsigned int getCheckStructureCount() const
Returns the number of check structures defined.
Definition: check_manager.hpp:74
Definition: soccer_world.hpp:44
virtual void reset(bool restart=false) OVERRIDE
Called when a soccer game is restarted.
Definition: soccer_world.cpp:128
virtual ~SoccerWorld()
The destructor frees all data structures.
Definition: soccer_world.cpp:74
A WorldWithRank is a world where the karts are ranked.
Definition: world_with_rank.hpp:38
int getTicksSinceStart() const
Get the ticks since start regardless of which way the clock counts.
Definition: world_status.hpp:215
virtual unsigned int getRescuePositionIndex(AbstractKart *kart) OVERRIDE
Determines the rescue position for a kart.
Definition: soccer_world.cpp:672
virtual void terminateRace() OVERRIDE
Called at the end of a race.
Definition: soccer_world.cpp:184
int getAttacker(KartTeam team) const
Get the AI who will attack the other team ball chaser.
Definition: soccer_world.cpp:643
void updateAIData()
Function to update data for AI usage.
Definition: soccer_world.cpp:608
static CheckManager * get()
Returns the instance of the check manager.
Definition: check_manager.hpp:68
virtual btTransform getRescueTransform(unsigned int rescue_pos) const OVERRIDE
Returns the bullet transformation for the specified rescue index.
Definition: soccer_world.cpp:686
virtual void reset(const Track &track) OVERRIDE
Initialises the 'previous positions' of all karts with the start position defined for this track.
Definition: check_goal.cpp:102
std::string m_country_code
Country code of player.
Definition: soccer_world.hpp:57
virtual bool isRaceOver() OVERRIDE
The soccer game is over if time up or either team wins.
Definition: soccer_world.cpp:475
int m_frame_count
Profiling usage.
Definition: soccer_world.hpp:299
std::vector< ScorerData > m_red_scorers
Goals data of each team scored.
Definition: soccer_world.hpp:282
Implements a simple checkline that will score a point when the soccer ball crosses it.
Definition: check_goal.hpp:37
int m_ball_invalid_timer
Counts ticks when the ball is off track, so a reset can be triggered if the ball is off for more than...
Definition: soccer_world.hpp:278
virtual void onGo() OVERRIDE
Called when 'go' is being displayed for the first time.
Definition: soccer_world.cpp:176
bool m_correct_goal
Whether this goal is socred correctly (identify for own goal).
Definition: soccer_world.hpp:49
void updateBallPosition(int ticks)
Function to update the location the ball on the polygon map.
Definition: soccer_world.cpp:523
Describes a chain of 8-bit unsigned integers.
Definition: network_string.hpp:52
int m_goal_target
Number of goals needed to win.
Definition: soccer_world.hpp:271
virtual void init() OVERRIDE
Initializes the soccer world.
Definition: soccer_world.cpp:86
Definition: soccer_world.hpp:82
unsigned int m_id
World ID of kart which scores.
Definition: soccer_world.hpp:47
An implementation of WorldWithRank, to provide the soccer game mode Notice: In soccer world,...
Definition: soccer_world.hpp:41
virtual bool raceHasLaps() OVERRIDE
Called when it is needed to know whether this kind of race involves counting laps.
Definition: soccer_world.hpp:330
unsigned int m_kart_id
World ID of kart.
Definition: soccer_world.hpp:67
Represents a peer. This class is used to interface the ENetPeer structure.
Definition: stk_peer.hpp:69
float m_distance
Distance to ball from kart.
Definition: soccer_world.hpp:69
Definition: soccer_world.hpp:63
virtual void update(int ticks) OVERRIDE
Update the world and the track.
Definition: soccer_world.cpp:208
float m_time
Time goal.
Definition: soccer_world.hpp:51
bool shouldDrawTimer() const OVERRIDE
The code that draws the timer should call this first to know whether the game mode wants a timer draw...
Definition: soccer_world.hpp:338
std::string m_kart
Kart ident which scores.
Definition: soccer_world.hpp:53
The base class for sound effects.
Definition: sfx_base.hpp:42
virtual void getKartsDisplayInfo(std::vector< RaceGUIBase::KartIconDisplayInfo > *info) OVERRIDE
Called by the code that draws the list of karts on the race GUI to know what needs to be drawn in the...
Definition: soccer_world.hpp:327
SoccerWorld()
Constructor.
Definition: soccer_world.cpp:52
virtual bool useFastMusicNearEnd() const OVERRIDE
Returns if this mode should use fast music (if available).
Definition: soccer_world.hpp:326
int time2Ticks(float t)
Converts a time value into ticks (of physics time steps).
Definition: stk_config.hpp:280
virtual std::pair< uint32_t, uint32_t > getGameStartedProgress() const OVERRIDE
Used by server to get the current started game progress in either or both remaining time or progress ...
Definition: soccer_world.hpp:398
bool getKartSoccerResult(unsigned int kart_id) const
Get the soccer result of kart in soccer world (including AIs)
Definition: soccer_world.cpp:505
An abstract interface for the actual karts.
Definition: abstract_kart.hpp:61
This is a base object for any separate object on the track, which might also have a skeletal animatio...
Definition: track_object.hpp:46
A new implementation of NetworkString, which has a fixed format: Byte 0: The type of the message,...
Definition: network_string.hpp:421
HandicapLevel m_handicap_level
Handicap of player.
Definition: soccer_world.hpp:59
Definition: track.hpp:96
void setBallHitter(unsigned int kart_id)
Sets the last kart that hit the ball, to be able to identify the scorer later.
Definition: soccer_world.cpp:467
virtual void countdownReachedZero() OVERRIDE
Called when the match time ends.
Definition: soccer_world.cpp:496