Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/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
RevLine 
[7034]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
[8068]17#include <map>
18
[7034]19#include "multiplayer_team_deathmatch.h"
20
[7193]21#include "util/loading/load_param.h"
22#include "util/loading/factory.h"
[7034]23
[7810]24#include "render2D/image_plane.h"
[7039]25#include "state.h"
[7101]26#include "class_list.h"
[7034]27
[7044]28#include "player.h"
29#include "playable.h"
[7101]30#include "space_ships/space_ship.h"
[7039]31
[7116]32
[7101]33#include "shared_network_data.h"
[7116]34#include "terrain.h"
35#include "class_list.h"
36#include "space_ships/space_ship.h"
[7044]37
[8068]38#include "network_game_manager.h"
[7101]39
[8147]40#include "event_handler.h"
[8068]41
[8147]42#include "glgui.h"
43
44#include "story_entity.h"
45
46
[7034]47using namespace std;
48
49
[7035]50CREATE_FACTORY(MultiplayerTeamDeathmatch, CL_MULTIPLAYER_TEAM_DEATHMATCH);
51
52
[7034]53/**
54 * constructor
55 */
[7035]56MultiplayerTeamDeathmatch::MultiplayerTeamDeathmatch(const TiXmlElement* root)
[8068]57  : NetworkGameRules(root)
[7035]58{
59  this->setClassID(CL_MULTIPLAYER_TEAM_DEATHMATCH, "MultiplayerTeamDeathmatch");
[7034]60
[7037]61  this->bLocalPlayerDead = false;
62  this->deathTimeout = 10.0f;     // 5 seconds
[7082]63  this->timeout = 0.0f;
[8068]64  this->numTeams = 2;
65  this->currentGameState = GAMESTATE_PRE_GAME;
66  this->gameStateTimer = 10.0f;
[8147]67 
68  this->box = NULL;
[7040]69
[7810]70  this->deathScreen = new ImagePlane();
[7044]71  this->deathScreen->setSize(State::getResX()/4.0, State::getResY()/4.0);
[7040]72  this->deathScreen->setAbsCoor2D(State::getResX()/2.0f, State::getResY()/2.0f);
[7044]73  this->deathScreen->setVisibility(false);
[7037]74
[7044]75  this->localPlayer = State::getPlayer();
76
[7035]77  if( root != NULL)
78    this->loadParams(root);
79}
80
[7034]81/**
82 * decontsructor
83 */
84MultiplayerTeamDeathmatch::~MultiplayerTeamDeathmatch()
[7044]85{
86  if( this->deathScreen)
87    delete this->deathScreen;
88}
[7034]89
90
91
92void MultiplayerTeamDeathmatch::loadParams(const TiXmlElement* root)
[7035]93{
[7040]94  GameRules::loadParams(root) ;
[7037]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");
[7039]101
102  LoadParam(root, "death-screen-image", this, MultiplayerTeamDeathmatch, setDeathScreen)
103      .describe("sets the death screen image");
[8068]104 
105  LoadParam(root, "num-teams", this, MultiplayerTeamDeathmatch, setNumTeams)
106      .describe("sets number of teams");
[7039]107
[7035]108}
109
110
[7039]111
[7221]112void MultiplayerTeamDeathmatch::setDeathScreen(const std::string& imageName)
[7039]113{
114  if( this->deathScreen)
115    this->deathScreen->setTexture(imageName);
116}
117
118
119
[7035]120/**
121 * called when the player enters the game
122 * @param player the spawned player
123 */
[7044]124void MultiplayerTeamDeathmatch::onPlayerSpawn()
[7039]125{
[7044]126  this->bLocalPlayerDead = false;
127  this->deathScreen->setVisibility(false);
[7039]128}
[7034]129
[7035]130
131/**
132 * when the player is killed
133 * @param player the killed player
134 */
[7044]135void MultiplayerTeamDeathmatch::onPlayerDeath()
[7039]136{
137  this->bLocalPlayerDead = true;
[7044]138  this->deathScreen->setVisibility(true);
[7039]139}
[7035]140
141
142/**
143 * time tick
144 * @param dt time
145 */
146void MultiplayerTeamDeathmatch::tick(float dt)
[7037]147{
[8147]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 
[8068]210  if ( !SharedNetworkData::getInstance()->isGameServer() )
211    return;
212 
213  gameStateTimer -= dt;
[8147]214  //PRINTF(0)("TICK %f\n", gameStateTimer);
[8068]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 
[7039]228  this->checkGameRules();
[7035]229
[7039]230  // is the local player dead and inactive
231  if( unlikely(this->bLocalPlayerDead))
232  {
233    this->timeout += dt;
[7088]234    PRINTF(0)("TICK DEATH: %f of %f\n", this->timeout, this->deathTimeout);
[7039]235    // long enough dead?
[7044]236    if( this->timeout >= this->deathTimeout)
[7039]237    {
238      this->timeout = 0.0f;
239      // respawn
[7079]240      PRINTF(0)("RESPAWN\n");
[7044]241      (State::getPlayer())->getPlayable()->respawn();
[7039]242    }
243  }
[7037]244}
[7035]245
[7037]246
[7035]247/**
248 * draws the stuff
249 */
250void MultiplayerTeamDeathmatch::draw()
[7039]251{
252  if( unlikely( this->bLocalPlayerDead))
253  {
[7035]254
[7039]255  }
256}
[7035]257
[7039]258
[7035]259/**
260 * check the game rules for consistency
261 */
262void MultiplayerTeamDeathmatch::checkGameRules()
[7039]263{
[8068]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}
[7101]277
[8068]278/**
279 * find group for new player
280 * @return group id
281 */
[8147]282int MultiplayerTeamDeathmatch::getTeamForNewUser()
[8068]283{
284  return TEAM_NOTEAM;
285}
[7101]286
[8147]287ClassID MultiplayerTeamDeathmatch::getPlayableClassId( int userId, int team )
[8068]288{
[8147]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 );
[8068]296}
[7101]297
[8147]298std::string MultiplayerTeamDeathmatch::getPlayableModelFileName( int userId, int team, ClassID classId )
[8068]299{
[8147]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 "";
[8068]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++ )
[7039]325  {
[8068]326    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
327
328    if ( stats.getTeamId() >= 0 )
329    {
330      teamScore[stats.getTeamId()] += stats.getScore();
331    }
[7039]332  }
[8068]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++ )
[7039]352  {
[8068]353    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
354
355    if ( stats.getTeamId() >= 0 )
356    {
357      playersInTeam[stats.getTeamId()]++;
358    }
[7039]359  }
[8068]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}
[7101]378
[8068]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}
[7118]402
[8068]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++ )
[7116]412  {
[8068]413    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
[7118]414
[8068]415    if ( stats.getTeamId() != stats.getPreferedTeamId() )
[7116]416    {
[8147]417      if ( stats.getPreferedTeamId() == TEAM_SPECTATOR || ( stats.getPreferedTeamId() >= 0 && stats.getPreferedTeamId() < numTeams ) )
[7116]418      {
[8068]419        teamChange( stats.getUserId() );
[7116]420      }
421    }
422  }
[8068]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);
[7101]428
[8068]429    if ( stats.getTeamId() != stats.getPreferedTeamId() )
[7101]430    {
[8068]431      if ( stats.getPreferedTeamId() == TEAM_RANDOM )
[7101]432      {
[8147]433        stats.setPreferedTeamId( getRandomTeam() );
[8068]434        teamChange( stats.getUserId() );
[7101]435      }
436    }
437  }
[8068]438}
[7101]439
[8068]440void MultiplayerTeamDeathmatch::teamChange( int userId )
441{
442  assert( PlayerStats::getStats( userId ) );
443  PlayerStats & stats = *(PlayerStats::getStats( userId ));
444 
[8147]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  }
[7039]476}
[7035]477
[8147]478void MultiplayerTeamDeathmatch::onButtonExit( )
479{
480  State::getCurrentStoryEntity()->stop();
481}
[7035]482
[8147]483void MultiplayerTeamDeathmatch::onButtonRandom( )
484{
485  NetworkGameManager::getInstance()->prefereTeam( TEAM_RANDOM );
486}
[7035]487
[8147]488void MultiplayerTeamDeathmatch::onButtonTeam0( )
489{
490  NetworkGameManager::getInstance()->prefereTeam( 0 );
491}
[7035]492
[8147]493void MultiplayerTeamDeathmatch::onButtonTeam1( )
494{
495  NetworkGameManager::getInstance()->prefereTeam( 1 );
496}
[7035]497
[8147]498void MultiplayerTeamDeathmatch::onButtonSpectator( )
499{
500  NetworkGameManager::getInstance()->prefereTeam( TEAM_SPECTATOR );
501}
[7035]502
[8147]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.