Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/bsp_model/src/util/multiplayer_team_deathmatch.cc @ 8372

Last change on this file since 8372 was 8147, checked in by bensch, 18 years ago

orxonox/trunk: merged the network branche back here
merged with command:
svn merge -r8070:HEAD https://svn.orxonox.net/orxonox/branches/network .
no conflicts

File size: 12.3 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11### File Specific:
12   main-programmer: Patrick Boenzli
13*/
14
15#define DEBUG_MODULE_GAME_RULES
16
17#include <map>
18
19#include "multiplayer_team_deathmatch.h"
20
21#include "util/loading/load_param.h"
22#include "util/loading/factory.h"
23
24#include "render2D/image_plane.h"
25#include "state.h"
26#include "class_list.h"
27
28#include "player.h"
29#include "playable.h"
30#include "space_ships/space_ship.h"
31
32
33#include "shared_network_data.h"
34#include "terrain.h"
35#include "class_list.h"
36#include "space_ships/space_ship.h"
37
38#include "network_game_manager.h"
39
40#include "event_handler.h"
41
42#include "glgui.h"
43
44#include "story_entity.h"
45
46
47using namespace std;
48
49
50CREATE_FACTORY(MultiplayerTeamDeathmatch, CL_MULTIPLAYER_TEAM_DEATHMATCH);
51
52
53/**
54 * constructor
55 */
56MultiplayerTeamDeathmatch::MultiplayerTeamDeathmatch(const TiXmlElement* root)
57  : NetworkGameRules(root)
58{
59  this->setClassID(CL_MULTIPLAYER_TEAM_DEATHMATCH, "MultiplayerTeamDeathmatch");
60
61  this->bLocalPlayerDead = false;
62  this->deathTimeout = 10.0f;     // 5 seconds
63  this->timeout = 0.0f;
64  this->numTeams = 2;
65  this->currentGameState = GAMESTATE_PRE_GAME;
66  this->gameStateTimer = 10.0f;
67 
68  this->box = NULL;
69
70  this->deathScreen = new ImagePlane();
71  this->deathScreen->setSize(State::getResX()/4.0, State::getResY()/4.0);
72  this->deathScreen->setAbsCoor2D(State::getResX()/2.0f, State::getResY()/2.0f);
73  this->deathScreen->setVisibility(false);
74
75  this->localPlayer = State::getPlayer();
76
77  if( root != NULL)
78    this->loadParams(root);
79}
80
81/**
82 * decontsructor
83 */
84MultiplayerTeamDeathmatch::~MultiplayerTeamDeathmatch()
85{
86  if( this->deathScreen)
87    delete this->deathScreen;
88}
89
90
91
92void MultiplayerTeamDeathmatch::loadParams(const TiXmlElement* root)
93{
94  GameRules::loadParams(root) ;
95
96  LoadParam(root, "death-penalty-timeout", this, MultiplayerTeamDeathmatch, setDeathPenaltyTimeout)
97      .describe("sets the time in seconds a player has to wait for respawn");
98
99  LoadParam(root, "max-kills", this, MultiplayerTeamDeathmatch, setMaxKills)
100      .describe("sets the maximal kills for winning condition");
101
102  LoadParam(root, "death-screen-image", this, MultiplayerTeamDeathmatch, setDeathScreen)
103      .describe("sets the death screen image");
104 
105  LoadParam(root, "num-teams", this, MultiplayerTeamDeathmatch, setNumTeams)
106      .describe("sets number of teams");
107
108}
109
110
111
112void MultiplayerTeamDeathmatch::setDeathScreen(const std::string& imageName)
113{
114  if( this->deathScreen)
115    this->deathScreen->setTexture(imageName);
116}
117
118
119
120/**
121 * called when the player enters the game
122 * @param player the spawned player
123 */
124void MultiplayerTeamDeathmatch::onPlayerSpawn()
125{
126  this->bLocalPlayerDead = false;
127  this->deathScreen->setVisibility(false);
128}
129
130
131/**
132 * when the player is killed
133 * @param player the killed player
134 */
135void MultiplayerTeamDeathmatch::onPlayerDeath()
136{
137  this->bLocalPlayerDead = true;
138  this->deathScreen->setVisibility(true);
139}
140
141
142/**
143 * time tick
144 * @param dt time
145 */
146void MultiplayerTeamDeathmatch::tick(float dt)
147{
148  //on client side hostId is -1 until hanshake finished
149  if ( SharedNetworkData::getInstance()->getHostID() < 0 )
150    return;
151 
152  if ( currentGameState == GAMESTATE_PRE_GAME )
153  {
154    if ( PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )
155         && PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )->getPreferedTeamId() == TEAM_NOTEAM
156         && box == NULL
157       )
158    {
159      EventHandler::getInstance()->pushState( ES_MENU );
160     
161      OrxGui::GLGuiHandler::getInstance()->activateCursor();
162     
163      box = new OrxGui::GLGuiBox();
164      box->setAbsCoor2D( 300, 100 );
165     
166      OrxGui::GLGuiPushButton * buttonSpectator = new OrxGui::GLGuiPushButton("Spectator");
167      box->pack( buttonSpectator );
168      buttonSpectator->connect(SIGNAL(buttonSpectator, released), this, SLOT(MultiplayerTeamDeathmatch, onButtonSpectator));
169     
170      OrxGui::GLGuiPushButton * buttonRandom = new OrxGui::GLGuiPushButton("Random");
171      box->pack( buttonRandom );
172      buttonRandom->connect(SIGNAL(buttonRandom, released), this, SLOT(MultiplayerTeamDeathmatch, onButtonRandom));
173     
174      OrxGui::GLGuiPushButton * buttonTeam0 = new OrxGui::GLGuiPushButton("Blue Team");
175      box->pack( buttonTeam0 );
176      buttonTeam0->connect(SIGNAL(buttonTeam0, released), this, SLOT(MultiplayerTeamDeathmatch, onButtonTeam0));
177     
178      OrxGui::GLGuiPushButton * buttonTeam1 = new OrxGui::GLGuiPushButton("Red Team");
179      box->pack( buttonTeam1 );
180      buttonTeam1->connect(SIGNAL(buttonTeam1, released), this, SLOT(MultiplayerTeamDeathmatch, onButtonTeam1));
181     
182      OrxGui::GLGuiPushButton * buttonExit = new OrxGui::GLGuiPushButton("Exit");
183      box->pack( buttonExit );
184      buttonExit->connect(SIGNAL(buttonExit, released), this, SLOT(MultiplayerTeamDeathmatch, onButtonExit));
185     
186      box->showAll();
187    }
188  }
189
190  if ( box != NULL
191       && PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )
192       && PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )->getPreferedTeamId() != TEAM_NOTEAM
193     )
194  {
195    delete box;
196    box = NULL;
197     
198    OrxGui::GLGuiHandler::getInstance()->deactivateCursor( true );
199     
200    EventHandler::getInstance()->popState();
201  }
202 
203  if ( box != NULL )
204  {
205    OrxGui::GLGuiHandler::getInstance()->tick( dt );
206  }
207 
208  assignPlayable();
209 
210  if ( !SharedNetworkData::getInstance()->isGameServer() )
211    return;
212 
213  gameStateTimer -= dt;
214  //PRINTF(0)("TICK %f\n", gameStateTimer);
215 
216  if ( currentGameState != GAMESTATE_GAME && gameStateTimer < 0 )
217    nextGameState();
218 
219  this->currentGameState = NetworkGameManager::getInstance()->getGameState();
220 
221  if ( currentGameState == GAMESTATE_GAME )
222  {
223    handleTeamChanges();
224  }
225 
226  this->calculateTeamScore();
227 
228  this->checkGameRules();
229
230  // is the local player dead and inactive
231  if( unlikely(this->bLocalPlayerDead))
232  {
233    this->timeout += dt;
234    PRINTF(0)("TICK DEATH: %f of %f\n", this->timeout, this->deathTimeout);
235    // long enough dead?
236    if( this->timeout >= this->deathTimeout)
237    {
238      this->timeout = 0.0f;
239      // respawn
240      PRINTF(0)("RESPAWN\n");
241      (State::getPlayer())->getPlayable()->respawn();
242    }
243  }
244}
245
246
247/**
248 * draws the stuff
249 */
250void MultiplayerTeamDeathmatch::draw()
251{
252  if( unlikely( this->bLocalPlayerDead))
253  {
254
255  }
256}
257
258
259/**
260 * check the game rules for consistency
261 */
262void MultiplayerTeamDeathmatch::checkGameRules()
263{
264  if ( !SharedNetworkData::getInstance()->isGameServer() )
265    return;
266 
267  // check for max killing count
268  for ( int i = 0; i<numTeams; i++ )
269  {
270    if ( teamScore[i] >= maxKills )
271    {
272      //team i wins
273      //TODO
274    }
275  }
276}
277
278/**
279 * find group for new player
280 * @return group id
281 */
282int MultiplayerTeamDeathmatch::getTeamForNewUser()
283{
284  return TEAM_NOTEAM;
285}
286
287ClassID MultiplayerTeamDeathmatch::getPlayableClassId( int userId, int team )
288{
289  if ( team == TEAM_NOTEAM || team == TEAM_SPECTATOR )
290    return CL_SPECTATOR;
291 
292  if ( team == 0 || team == 1 )
293    return CL_SPACE_SHIP;
294 
295  assert( false );
296}
297
298std::string MultiplayerTeamDeathmatch::getPlayableModelFileName( int userId, int team, ClassID classId )
299{
300  if ( team == 0 )
301    return "models/ships/reap_#.obj";
302  else if ( team == 1 )
303    return "models/ships/fighter.obj";
304  else
305    return "";
306}
307
308/**
309 * calculate team score
310 */
311void MultiplayerTeamDeathmatch::calculateTeamScore( )
312{
313  teamScore.clear();
314 
315  for ( int i = 0; i<numTeams; i++ )
316    teamScore[i] = 0;
317 
318   
319  const std::list<BaseObject*> * list = ClassList::getList( CL_PLAYER_STATS );
320 
321  if ( !list )
322    return;
323 
324  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
325  {
326    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
327
328    if ( stats.getTeamId() >= 0 )
329    {
330      teamScore[stats.getTeamId()] += stats.getScore();
331    }
332  }
333}
334
335/**
336 * get team for player who choose to join random team
337 * @return smallest team
338 */
339int MultiplayerTeamDeathmatch::getRandomTeam( )
340{
341  std::map<int,int> playersInTeam;
342 
343  for ( int i = 0; i<numTeams; i++ )
344    playersInTeam[i] = 0;
345 
346  const std::list<BaseObject*> * list = ClassList::getList( CL_PLAYER_STATS );
347 
348  if ( !list )
349    return 0;
350 
351  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
352  {
353    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
354
355    if ( stats.getTeamId() >= 0 )
356    {
357      playersInTeam[stats.getTeamId()]++;
358    }
359  }
360 
361 
362  int minPlayers = 0xFFFF;
363  int minTeam = -1;
364 
365  for ( int i = 0; i<numTeams; i++ )
366  {
367    if ( playersInTeam[i] < minPlayers )
368    {
369      minTeam = i;
370      minPlayers = playersInTeam[i];
371    }
372  }
373 
374  assert( minTeam != -1 );
375 
376  return minTeam;
377}
378
379void MultiplayerTeamDeathmatch::nextGameState( )
380{
381  if ( currentGameState == GAMESTATE_PRE_GAME )
382  {
383    NetworkGameManager::getInstance()->setGameState( GAMESTATE_GAME );
384   
385    return;
386  }
387 
388  if ( currentGameState == GAMESTATE_GAME )
389  {
390    NetworkGameManager::getInstance()->setGameState( GAMESTATE_POST_GAME );
391   
392    return;
393  }
394 
395  if ( currentGameState == GAMESTATE_POST_GAME )
396  {
397    //TODO end game
398   
399    return;
400  }
401}
402
403void MultiplayerTeamDeathmatch::handleTeamChanges( )
404{
405  const std::list<BaseObject*> * list = ClassList::getList( CL_PLAYER_STATS );
406 
407  if ( !list )
408    return;
409 
410  //first server players with choices
411  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
412  {
413    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
414
415    if ( stats.getTeamId() != stats.getPreferedTeamId() )
416    {
417      if ( stats.getPreferedTeamId() == TEAM_SPECTATOR || ( stats.getPreferedTeamId() >= 0 && stats.getPreferedTeamId() < numTeams ) )
418      {
419        teamChange( stats.getUserId() );
420      }
421    }
422  }
423 
424  //now serve player who want join a random team
425  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
426  {
427    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
428
429    if ( stats.getTeamId() != stats.getPreferedTeamId() )
430    {
431      if ( stats.getPreferedTeamId() == TEAM_RANDOM )
432      {
433        stats.setPreferedTeamId( getRandomTeam() );
434        teamChange( stats.getUserId() );
435      }
436    }
437  }
438}
439
440void MultiplayerTeamDeathmatch::teamChange( int userId )
441{
442  assert( PlayerStats::getStats( userId ) );
443  PlayerStats & stats = *(PlayerStats::getStats( userId ));
444 
445  stats.setTeamId( stats.getPreferedTeamId() );
446 
447  Playable * oldPlayable = stats.getPlayable();
448 
449 
450  ClassID playableClassId = getPlayableClassId( userId, stats.getPreferedTeamId() );
451  std::string playableModel = getPlayableModelFileName( userId, stats.getPreferedTeamId(), playableClassId );
452 
453  BaseObject * bo = Factory::fabricate( playableClassId );
454 
455  assert( bo != NULL );
456  assert( bo->isA( CL_PLAYABLE ) );
457 
458  Playable & playable = *(dynamic_cast<Playable*>(bo));
459 
460  playable.loadModel( playableModel );
461  playable.setOwner( userId );
462  playable.setUniqueID( SharedNetworkData::getInstance()->getNewUniqueID() );
463  playable.setSynchronized( true );
464 
465  stats.setTeamId( stats.getPreferedTeamId() );
466  stats.setPlayableClassId( playableClassId );
467  stats.setPlayableUniqueId( playable.getUniqueID() );
468  stats.setModelFileName( playableModel );
469 
470  if ( oldPlayable )
471  {
472    //if ( userId == SharedNetworkData::getInstance()->getHostID() )
473    //  State::getPlayer()->setPlayable( NULL );
474    delete oldPlayable;
475  }
476}
477
478void MultiplayerTeamDeathmatch::onButtonExit( )
479{
480  State::getCurrentStoryEntity()->stop();
481}
482
483void MultiplayerTeamDeathmatch::onButtonRandom( )
484{
485  NetworkGameManager::getInstance()->prefereTeam( TEAM_RANDOM );
486}
487
488void MultiplayerTeamDeathmatch::onButtonTeam0( )
489{
490  NetworkGameManager::getInstance()->prefereTeam( 0 );
491}
492
493void MultiplayerTeamDeathmatch::onButtonTeam1( )
494{
495  NetworkGameManager::getInstance()->prefereTeam( 1 );
496}
497
498void MultiplayerTeamDeathmatch::onButtonSpectator( )
499{
500  NetworkGameManager::getInstance()->prefereTeam( TEAM_SPECTATOR );
501}
502
503void MultiplayerTeamDeathmatch::assignPlayable( )
504{
505  if ( PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() ) )
506    PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )->getPlayable();
507}
508
509
510
511
512
513
Note: See TracBrowser for help on using the repository browser.