/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. ### File Specific: main-programmer: Patrick Boenzli */ #define DEBUG_MODULE_GAME_RULES #include #include "multiplayer_team_deathmatch.h" #include "util/loading/load_param.h" #include "util/loading/factory.h" #include "render2D/image_plane.h" #include "state.h" #include "class_list.h" #include "player.h" #include "playable.h" #include "space_ships/space_ship.h" #include "shared_network_data.h" #include "terrain.h" #include "class_list.h" #include "space_ships/space_ship.h" #include "network_game_manager.h" using namespace std; CREATE_FACTORY(MultiplayerTeamDeathmatch, CL_MULTIPLAYER_TEAM_DEATHMATCH); /** * constructor */ MultiplayerTeamDeathmatch::MultiplayerTeamDeathmatch(const TiXmlElement* root) : NetworkGameRules(root) { this->setClassID(CL_MULTIPLAYER_TEAM_DEATHMATCH, "MultiplayerTeamDeathmatch"); this->bLocalPlayerDead = false; this->deathTimeout = 10.0f; // 5 seconds this->timeout = 0.0f; this->numTeams = 2; this->currentGameState = GAMESTATE_PRE_GAME; this->gameStateTimer = 10.0f; this->deathScreen = new ImagePlane(); this->deathScreen->setSize(State::getResX()/4.0, State::getResY()/4.0); this->deathScreen->setAbsCoor2D(State::getResX()/2.0f, State::getResY()/2.0f); this->deathScreen->setVisibility(false); this->localPlayer = State::getPlayer(); if( root != NULL) this->loadParams(root); } /** * decontsructor */ MultiplayerTeamDeathmatch::~MultiplayerTeamDeathmatch() { if( this->deathScreen) delete this->deathScreen; } void MultiplayerTeamDeathmatch::loadParams(const TiXmlElement* root) { GameRules::loadParams(root) ; LoadParam(root, "death-penalty-timeout", this, MultiplayerTeamDeathmatch, setDeathPenaltyTimeout) .describe("sets the time in seconds a player has to wait for respawn"); LoadParam(root, "max-kills", this, MultiplayerTeamDeathmatch, setMaxKills) .describe("sets the maximal kills for winning condition"); LoadParam(root, "death-screen-image", this, MultiplayerTeamDeathmatch, setDeathScreen) .describe("sets the death screen image"); LoadParam(root, "num-teams", this, MultiplayerTeamDeathmatch, setNumTeams) .describe("sets number of teams"); } void MultiplayerTeamDeathmatch::setDeathScreen(const std::string& imageName) { if( this->deathScreen) this->deathScreen->setTexture(imageName); } /** * called when the player enters the game * @param player the spawned player */ void MultiplayerTeamDeathmatch::onPlayerSpawn() { this->bLocalPlayerDead = false; this->deathScreen->setVisibility(false); } /** * when the player is killed * @param player the killed player */ void MultiplayerTeamDeathmatch::onPlayerDeath() { this->bLocalPlayerDead = true; this->deathScreen->setVisibility(true); } /** * time tick * @param dt time */ void MultiplayerTeamDeathmatch::tick(float dt) { if ( !SharedNetworkData::getInstance()->isGameServer() ) return; gameStateTimer -= dt; PRINTF(0)("TICK %f\n", gameStateTimer); if ( currentGameState != GAMESTATE_GAME && gameStateTimer < 0 ) nextGameState(); this->currentGameState = NetworkGameManager::getInstance()->getGameState(); if ( currentGameState == GAMESTATE_GAME ) { handleTeamChanges(); } this->calculateTeamScore(); this->checkGameRules(); // is the local player dead and inactive if( unlikely(this->bLocalPlayerDead)) { this->timeout += dt; PRINTF(0)("TICK DEATH: %f of %f\n", this->timeout, this->deathTimeout); // long enough dead? if( this->timeout >= this->deathTimeout) { this->timeout = 0.0f; // respawn PRINTF(0)("RESPAWN\n"); (State::getPlayer())->getPlayable()->respawn(); } } } /** * draws the stuff */ void MultiplayerTeamDeathmatch::draw() { if( unlikely( this->bLocalPlayerDead)) { } } /** * check the game rules for consistency */ void MultiplayerTeamDeathmatch::checkGameRules() { if ( !SharedNetworkData::getInstance()->isGameServer() ) return; // check for max killing count for ( int i = 0; i= maxKills ) { //team i wins //TODO } } } /** * find group for new player * @return group id */ int MultiplayerTeamDeathmatch::getTeamForNewUser( ) { return TEAM_NOTEAM; } ClassID MultiplayerTeamDeathmatch::getPlayableClassId( int team ) { return CL_SPECTATOR; } std::string MultiplayerTeamDeathmatch::getPlayableModelFileName( int team, ClassID classId ) { return ""; } /** * calculate team score */ void MultiplayerTeamDeathmatch::calculateTeamScore( ) { teamScore.clear(); for ( int i = 0; i * list = ClassList::getList( CL_PLAYER_STATS ); if ( !list ) return; for ( std::list::const_iterator it = list->begin(); it != list->end(); it++ ) { PlayerStats & stats = *dynamic_cast(*it); if ( stats.getTeamId() >= 0 ) { teamScore[stats.getTeamId()] += stats.getScore(); } } } /** * get team for player who choose to join random team * @return smallest team */ int MultiplayerTeamDeathmatch::getRandomTeam( ) { std::map playersInTeam; for ( int i = 0; i * list = ClassList::getList( CL_PLAYER_STATS ); if ( !list ) return 0; for ( std::list::const_iterator it = list->begin(); it != list->end(); it++ ) { PlayerStats & stats = *dynamic_cast(*it); if ( stats.getTeamId() >= 0 ) { playersInTeam[stats.getTeamId()]++; } } int minPlayers = 0xFFFF; int minTeam = -1; for ( int i = 0; isetGameState( GAMESTATE_GAME ); return; } if ( currentGameState == GAMESTATE_GAME ) { NetworkGameManager::getInstance()->setGameState( GAMESTATE_POST_GAME ); return; } if ( currentGameState == GAMESTATE_POST_GAME ) { //TODO end game return; } } void MultiplayerTeamDeathmatch::handleTeamChanges( ) { const std::list * list = ClassList::getList( CL_PLAYER_STATS ); if ( !list ) return; //first server players with choices for ( std::list::const_iterator it = list->begin(); it != list->end(); it++ ) { PlayerStats & stats = *dynamic_cast(*it); if ( stats.getTeamId() != stats.getPreferedTeamId() ) { if ( stats.getPreferedTeamId() == TEAM_SPECTATOR || ( stats.getPreferedTeamId() <= 0 && stats.getPreferedTeamId() < numTeams ) ) { teamChange( stats.getUserId() ); } } } //now serve player who want join a random team for ( std::list::const_iterator it = list->begin(); it != list->end(); it++ ) { PlayerStats & stats = *dynamic_cast(*it); if ( stats.getTeamId() != stats.getPreferedTeamId() ) { if ( stats.getPreferedTeamId() == TEAM_RANDOM ) { stats.setPreferedTeamId( getTeamForNewUser() ); teamChange( stats.getUserId() ); } } } } void MultiplayerTeamDeathmatch::teamChange( int userId ) { assert( PlayerStats::getStats( userId ) ); PlayerStats & stats = *(PlayerStats::getStats( userId )); assert(false); }