/* $Id: scorekeeper.cpp,v 1.33.4.1 2006/01/20 11:23:31 chfreund Exp $ */ #include "scorekeeper.hpp" #include "world.hpp" #include "wopsettings.hpp" #include "map.hpp" #include "global.hpp" #include "random.hpp" #include "ball.hpp" #include "rope.hpp" #include "avatar.hpp" #include "color.hpp" #include "serialize.hpp" #include /******************************************************************************/ Mix_Chunk* Scorekeeper::m_cashSample = NULL; /******************************************************************************/ void Scorekeeper::initialize( World* const world ) { WopSettings* settings = WopSettings::getInstance(); m_gameMode = settings->getGameMode(); m_world = world; m_cashSample = Audio::getInstance()->loadSound( "sound/effects/cashreg.wav" ); m_messageSink = &m_defaultMessageSink; // should be redundant because of Scorekeeper::resetScore, but ... for( int p = 0; p < MAX_NUMBER_OF_PLAYERS; p++ ) { m_score[p].nFrags = m_score[p].nKills = m_score[p].nDeaths = m_score[p].nDamage = 0; m_teamScore[p].nFrags = m_teamScore[p].nKills = m_teamScore[p].nDeaths = m_teamScore[p].nDamage = 0; } } /******************************************************************************/ Scorekeeper::~Scorekeeper() { reset(); } /******************************************************************************/ void Scorekeeper::reset() { for( int i = 0; i < MAX_NUMBER_OF_PLAYERS; i++ ) { resetPlayerScore( i ); resetTeamScore( i ); } m_goal.clear(); } /******************************************************************************/ void Scorekeeper::setupGameMode() { WopSettings* settings = WopSettings::getInstance(); for( int g = 0; g < settings->getNumGoals(); g++ ) { Goal* goal = dynamic_cast( m_world->newObject( GOAL_50 )); if( goal->initialize( Vector( 0.5 * m_world->getMap()->getSizeX(), 0.5 * m_world->getMap()->getSizeY() ), localRnd.getVector( 0.1+0.3*localRnd.getNormedReal() ))) { m_goal.push_back( goal ); } } for( int b = 0; b < settings->getNumBalls(); b++ ) { placeNewBall(); } } /******************************************************************************/ void Scorekeeper::playerDamagedPlayer( const Uint8 shooter, const Uint8 victim, const Sint32 damage, const bool killingVictim ) { if( isTeamPlay() ) { if( shooter == victim || m_world->getPlayerByID( shooter )->getTeamID() == m_world->getPlayerByID( victim )->getTeamID()) { if( killingVictim ) { m_score[shooter].nFrags--; m_teamScore[m_world->getPlayerByID( shooter )->getTeamID()].nFrags--; m_score[shooter].nKills++; m_teamScore[m_world->getPlayerByID( shooter )->getTeamID()].nKills++; m_score[victim].nDeaths++; m_teamScore[m_world->getPlayerByID( victim )->getTeamID()].nDeaths++; } m_score[shooter].nDamage -= damage; m_teamScore[m_world->getPlayerByID( shooter )->getTeamID()].nDamage -= damage; } else { if( killingVictim ) { m_score[shooter].nFrags++; m_teamScore[m_world->getPlayerByID( shooter )->getTeamID()].nFrags++; m_score[shooter].nKills++; m_teamScore[m_world->getPlayerByID( shooter )->getTeamID()].nKills++; m_score[victim].nDeaths++; m_teamScore[m_world->getPlayerByID( victim )->getTeamID()].nDeaths++; } m_score[shooter].nDamage += damage; m_teamScore[m_world->getPlayerByID( shooter )->getTeamID()].nDamage += damage; } } else { // deathmatch if( shooter == victim ) { if( killingVictim ) { m_score[shooter].nFrags--; m_score[shooter].nKills++; m_score[victim].nDeaths++; m_score[shooter].nDamage -= damage; } } else { if( killingVictim ) { m_score[shooter].nFrags++; m_score[shooter].nKills++; m_score[victim].nDeaths++; } m_score[shooter].nDamage += damage; } } } /******************************************************************************/ void Scorekeeper::playerScoredGoal( Ball* ball, const Uint8 playerOrTeamID ) { LOG( 1 ) INFO( "Scorekeeper::playerScoredGoal: player/team %i\n", playerOrTeamID ); Audio::getInstance()->playSound( m_cashSample ); if( isTeamPlay() ) { m_teamScore[playerOrTeamID].nFrags += 5; std::ostringstream os; os << "Team " << static_cast( playerOrTeamID ); m_messageSink->addMessage( MessageGenerator::createGoalMessage( os.str().c_str() ) ); } else { Player* scoringPlayer = m_world->getPlayerByID( playerOrTeamID ); if( scoringPlayer != 0 ) { m_score[playerOrTeamID].nFrags += 5; m_messageSink->addMessage( MessageGenerator::createGoalMessage( scoringPlayer->getName() ) ); } } LOG( 5 ) INFO( "Scorekeeper::playerScoredGoal: trying to place new ball\n" ); //placeNewBall(); replaceBall( ball ); LOG( 5 ) INFO( "Scorekeeper::playerScoredGoal: done\n" ); } /******************************************************************************/ void Scorekeeper::replaceBall( Ball* ball ) { const Map* map = m_world->getMap(); // detach from everything but goals for( int a = ball->getNAttachedObjects()-1; a >= 0; a-- ) { if( ! ball->getAttachedObject( a )->isGoal() ) ball->detachFrom( a ); } ball->setVel( Vector( 0.0, 0.0 )); ball->setInitialScoringDelay( 50.0 ); bool ballPlaced = false; while( ! ballPlaced ) { const int x = m_world->getRandom().getUint32Between( 20, map->getSizeX()-20 ), y = m_world->getRandom().getUint32Between( 20, map->getSizeY()-20 ); LOG( 5 ) INFO( "Scorekeeper::replaceBall: trying to place new ball at %4i, %4i\n", x, y ); ball->setPos( Vector( x, y )); ballPlaced = ball->testCollRect(); } LOG( 5 ) INFO( "Scorekeeper::replaceBall: placing done\n" ); } /******************************************************************************/ void Scorekeeper::placeNewBall() { const Map* map = m_world->getMap(); Ball* ball; bool ballPlaced = false; while( ! ballPlaced ) { const int x = m_world->getRandom().getUint32Between( 20, map->getSizeX()-20 ), y = m_world->getRandom().getUint32Between( 20, map->getSizeY()-20 ); LOG( 5 ) INFO( "Scorekeeper::placeNewBall: trying to place new ball at %4i, %4i\n", x, y ); ball = dynamic_cast( m_world->newObject( BALL )); ballPlaced = ball->initialize( Vector( x, y ) , Vector( 0, 0 ), 50.0 ); } LOG( 5 ) INFO( "Scorekeeper::placeNewBall: placing done\n" ); LOG( 5 ) INFO( "Scorekeeper::placeNewBall: attaching new ball to %i goals\n", m_goal.size() ); for( unsigned int g = 0; g < m_goal.size(); g++ ) { ball->attachTo( m_goal[g] ); } LOG( 5 ) INFO( "Scorekeeper::placeNewBall: attaching new ball to goals done\n" ); } /******************************************************************************/ bool Scorekeeper::isTeamPlay() { return (m_gameMode & TEAMPLAY) != 0; } /******************************************************************************/ bool Scorekeeper::setGameMode( const Uint8 gameMode ) { if( gameMode >= NUMBER_OF_GAME_MODES ) { return false; } m_gameMode = gameMode; return true; } /******************************************************************************/ Uint32 Scorekeeper::getSerializeBufferSize() const { return Serialize::sizeOf( m_gameMode ) + 2 * MAX_NUMBER_OF_PLAYERS * sizeof( Score ); } /******************************************************************************/ void Scorekeeper::serialize( Uint8*& bufferPointer ) const { START_SERIALIZED_SIZE_CHECK( bufferPointer ); Serialize::serialize( m_gameMode, bufferPointer ); for( int p = 0; p < MAX_NUMBER_OF_PLAYERS; p++ ) { Serialize::serialize( m_score[p].nFrags, bufferPointer ); Serialize::serialize( m_score[p].nKills, bufferPointer ); Serialize::serialize( m_score[p].nDeaths, bufferPointer ); Serialize::serialize( m_score[p].nDamage, bufferPointer ); } for( int p = 0; p < MAX_NUMBER_OF_PLAYERS; p++ ) { Serialize::serialize( m_teamScore[p].nFrags, bufferPointer ); Serialize::serialize( m_teamScore[p].nKills, bufferPointer ); Serialize::serialize( m_teamScore[p].nDeaths, bufferPointer ); Serialize::serialize( m_teamScore[p].nDamage, bufferPointer ); } DBG( 2 ) INFO( "Scorekeeper::serialize: number of goals is %d\n", m_goal.size() ); END_SERIALIZED_SIZE_CHECK( bufferPointer, Scorekeeper ); } /******************************************************************************/ void Scorekeeper::deserialize( Uint8*& bufferPointer ) { Serialize::deserialize( bufferPointer, m_gameMode ); for( int p = 0; p < MAX_NUMBER_OF_PLAYERS; p++ ) { Serialize::deserialize( bufferPointer, m_score[p].nFrags ); Serialize::deserialize( bufferPointer, m_score[p].nKills ); Serialize::deserialize( bufferPointer, m_score[p].nDeaths ); Serialize::deserialize( bufferPointer, m_score[p].nDamage ); } for( int p = 0; p < MAX_NUMBER_OF_PLAYERS; p++ ) { Serialize::deserialize( bufferPointer, m_teamScore[p].nFrags ); Serialize::deserialize( bufferPointer, m_teamScore[p].nKills ); Serialize::deserialize( bufferPointer, m_teamScore[p].nDeaths ); Serialize::deserialize( bufferPointer, m_teamScore[p].nDamage ); } std::vector& noncollidable = *m_world->getNoncollidables(); m_goal.clear(); // look for ball among collidable objects for( unsigned int i = 0; i < noncollidable.size(); i++ ) { // is it a goal? if( noncollidable[i]->getID() == GOAL_50 ) { m_goal.push_back( dynamic_cast( noncollidable[i] )); } } DBG( 2 ) INFO( "Scorekeeper::deserialize: number of goals is %d\n", m_goal.size() ); } /******************************************************************************/