#include "Spiel.h" #include #include "KartenLeser.h" #include "Statistik.h" #include #ifdef WIN32 #include #else #include #include #include #define Sleep( x ) usleep( (x) * 1000 ) #endif #define TICK 0.03333333 // Inhalt der Spiel Klasse aus Spiel.h // Konstruktor Spiel::Spiel() : ReferenceCounter() { stat = new Statistik(); score = new Bestenliste(); teams = new Array< int >(); teamAnzahl = 0; psqldb = 0; spieler = new RCArray< Spieler >(); spielerAnzahl = 0; spielId = 0; karte = new Karte(); isRunning = 0; sts = 0; InitializeCriticalSection( &cs ); rundenAnzahl = 0; spielZeit = 0; ende = 1; } // Destruktor Spiel::~Spiel() { teams->release(); stat->release(); score->release(); spieler->release(); if( psqldb ) psqldb->release(); karte->release(); if( sts ) sts->release(); DeleteCriticalSection( &cs ); } // nicht constant void Spiel::setPSQLK( SSDatenbankV *psqldb ) { if( this->psqldb ) this->psqldb->release(); this->psqldb = psqldb; stat->setPSQLDB( dynamic_cast( psqldb->getThis() ) ); } void Spiel::setSpielId( int id ) { spielId = id; stat->setSpielId( id ); } void Spiel::setKarteId( int karteId ) { this->karteId = karteId; karte->setKarteId( karteId ); stat->setKarteId( karteId ); } void Spiel::setTempPfad( char *pfad ) { mapPfad = pfad; mapPfad += "/"; } void Spiel::setAccounts( int anzahl, Array< int > *zAccounts ) { spielerAnzahl = anzahl; for( int i = 0; i < anzahl; i++ ) { Spieler *tmp = new Spieler(); tmp->setAccountId( zAccounts->hat( i ) ? zAccounts->get( i ) : 0 ); spieler->set( tmp, i ); } stat->setSpieler( spielerAnzahl, spieler ); } void Spiel::setKlients( int anzahl, RCArray< SSKlientV > *zKlients ) { for( int i = 0; i < anzahl; i++ ) { Spieler *tmp = spieler->z( i ); if( tmp ) tmp->setKlient( new Klient( zKlients->get( i ) ) ); } } void Spiel::setSpielerNummern( int anzahl, Array< int > *spielerNummern ) { if( !sts ) { sts = new SpielerTeamStruktur(); KartenLeser *reader = new KartenLeser( karteId, dynamic_cast( psqldb->getThis() ), mapPfad ); reader->ladeSpielerTeamStruktur( sts ); reader->release(); stat->setTeamNamen( dynamic_cast *>( sts->teamName->getThis() ) ); } for( int i = 0; i < anzahl; i++ ) { Spieler *tmp = spieler->z( i ); if( tmp ) { int sNum = spielerNummern->hat( i ) ? spielerNummern->get( i ) : 0; tmp->setSpielerNummer( sNum ); tmp->setSpielerFarbe( sts->spielerFarbe->hat( sNum ) ? sts->spielerFarbe->get( sNum ) : 0 ); int team = 0; int von = 0; int bis = 0; for( int j = 0; j < sts->teamAnzahl; j++ ) { bis = von + ( sts->teamSize->hat( j ) ? sts->teamSize->get( j ) : 0 ); if( sNum >= von && sNum < bis ) { team = j; break; } von = bis; } tmp->setTeam( team ); tmp->setTeamFarbe( sts->teamFarbe->hat( team ) ? sts->teamFarbe->get( team ) : 0 ); } } } void Spiel::klientOffline( int accountId ) { for( int i = 0; i < spielerAnzahl; i++ ) { if( spieler->z( i )->getAccountId() == accountId ) spieler->z( i )->offline(); } } void Spiel::klientOnline( int accountId, SSKlientV *zKlient ) { for( int i = 0; i < spielerAnzahl; i++ ) { if( spieler->z( i )->getAccountId() == accountId ) { EnterCriticalSection( &cs ); Spieler *s = spieler->z( i ); s->online( zKlient ); Klient *tmp = spieler->z( i )->zKlient(); tmp->sendeSpielerNummer( s->getSpielerNummer(), 0 ); tmp->sendeInitSpieler( spielerAnzahl, spieler, 0 ); tmp->sendeKammeraSize( 400, 400, 0 ); tmp->sendeKartenSize( karte->getBreite(), karte->getHeight(), 0 ); for( int i = 0; i < spielerAnzahl; i++ ) { Spieler *z = spieler->z( i ); if( z ) { tmp->sendeSpielerPosition( z, 0 ); tmp->sendeSpielerGeschwindigkeit( z, 0 ); tmp->sendeSpielerWendigkeit( z, 0 ); } } LeaveCriticalSection( &cs ); } } } void Spiel::nachricht( int accountId, int len, char *bytes ) { if( !isRunning || ende ) return; EnterCriticalSection( &cs ); if( ende ) { LeaveCriticalSection( &cs ); return; } char *msgBeg = bytes; int msgLen = len; int msgAccount = accountId; bool saveMSG = 1; len--; switch( *bytes ) { case 0: // Spieler drückt T_Links for( int i = 0; i < spielerAnzahl; i++ ) { Spieler *tmp = spieler->z( i ); if( tmp && tmp->getAccountId() == accountId ) { if( !tmp->istAmLeben() ) break; if( tmp->machtKurve( 0 ) ) { saveMSG = 0; break; } tmp->setLKurve( 1 ); for( int j = 0; j < spielerAnzahl; j++ ) { Spieler *s = spieler->z( j ); if( s && s->zKlient() ) s->zKlient()->sendeSpielerKurve( tmp->getSpielerNummer(), 1, spielZeit ); } break; } } break; case 1: // Spieler lässt T_Links los for( int i = 0; i < spielerAnzahl; i++ ) { Spieler *tmp = spieler->z( i ); if( tmp && tmp->getAccountId() == accountId ) { if( !tmp->istAmLeben() ) break; if( !tmp->machtKurve( 0 ) ) { saveMSG = 0; break; } tmp->setLKurve( 0 ); for( int j = 0; j < spielerAnzahl; j++ ) { Spieler *s = spieler->z( j ); if( s && s->zKlient() ) s->zKlient()->sendeSpielerKurve( tmp->getSpielerNummer(), 2, spielZeit ); } break; } } break; case 2: // Spieler drückt T_Rechts for( int i = 0; i < spielerAnzahl; i++ ) { Spieler *tmp = spieler->z( i ); if( tmp && tmp->getAccountId() == accountId ) { if( !tmp->istAmLeben() ) break; if( tmp->machtKurve( 1 ) ) { saveMSG = 0; break; } tmp->setRKurve( 1 ); for( int j = 0; j < spielerAnzahl; j++ ) { Spieler *s = spieler->z( j ); if( s && s->zKlient() ) s->zKlient()->sendeSpielerKurve( tmp->getSpielerNummer(), 3, spielZeit ); } break; } } break; case 3: // Spieler lässt T_Rechts los for( int i = 0; i < spielerAnzahl; i++ ) { Spieler *tmp = spieler->z( i ); if( tmp && tmp->getAccountId() == accountId ) { if( !tmp->istAmLeben() ) break; if( !tmp->machtKurve( 1 ) ) { saveMSG = 0; break; } tmp->setRKurve( 0 ); for( int j = 0; j < spielerAnzahl; j++ ) { Spieler *s = spieler->z( j ); if( s && s->zKlient() ) s->zKlient()->sendeSpielerKurve( tmp->getSpielerNummer(), 4, spielZeit ); } break; } } break; case 4: // chat Nachricht if( 1 ) { bytes++; Text *txt = psqldb->getAccountRufName( accountId ); txt->append( ": " ); txt->append( bytes, len ); for( int i = 0; i < spielerAnzahl; i++ ) { Spieler *tmp = spieler->z( i ); if( tmp && tmp->zKlient() ) tmp->zKlient()->sendeChatNachricht( txt->getText(), spielZeit ); } txt->release(); len = 0; } break; default: saveMSG = 0; } if( len ) { // error } if( log && log->istOffen() && saveMSG ) { char c = 1; log->schreibe( &c, 1 ); int spielerNum = 0; for( int i = 0; i < spielerAnzahl; i++ ) { Spieler *tmp = spieler->z( i ); if( tmp && tmp->getAccountId() == msgAccount ) { spielerNum = tmp->getSpielerNummer(); break; } } log->schreibe( (char *)&spielerNum, 4 ); short l = (short)msgLen; log->schreibe( (char *)&l, 2 ); log->schreibe( msgBeg, l ); } LeaveCriticalSection( &cs ); } void Spiel::tick( double zeit ) { for( int i = 0; i < spielerAnzahl; i++ ) { Spieler *tmp = spieler->z( i ); if( tmp ) { bool amLeben = tmp->istAmLeben(); bool lu = tmp->linieIstUnterbrochen(); tmp->tick( karte->zMap(), zeit ); if( amLeben != tmp->istAmLeben() || lu != tmp->linieIstUnterbrochen() ) { if( lu != tmp->linieIstUnterbrochen() ) { char c = 1; log->schreibe( &c, 1 ); int sNum = tmp->getSpielerNummer(); log->schreibe( (char *)&sNum, 4 ); short len = 2; log->schreibe( (char *)&len, 2 ); c = 5; log->schreibe( &c, 1 ); c = (char)tmp->linieIstUnterbrochen(); log->schreibe( &c, 1 ); } for( int j = 0; j < spielerAnzahl; j++ ) { Spieler *s = spieler->z( j ); if( s && s->zKlient() ) { if( amLeben && !tmp->istAmLeben() ) { if( tmp->getKillFarbe() == s->getSpielerFarbe() ) s->addKill(); s->zKlient()->sendeSpielerTod( tmp, spielZeit ); if( s != tmp && s->istAmLeben() ) { score->addSpielerPunkt( s->getSpielerNummer(), 1 ); s->addPunkte( 1 ); } } else if( lu != tmp->linieIstUnterbrochen() ) s->zKlient()->sendeLinienUnterbrechung( tmp->getSpielerNummer(), tmp->linieIstUnterbrochen(), spielZeit ); } } if( amLeben && !tmp->istAmLeben() ) { int team = tmp->getSpielerTeam(); bool teamLebt = 0; for( int k = 0; k < spielerAnzahl; k++ ) { if( spieler->z( k ) && spieler->z( k )->getSpielerTeam() == team ) teamLebt |= spieler->z( k )->istAmLeben(); } if( !teamLebt ) { int teamAmLebenAnzahl = 0; for( int k = 0; k < teamAnzahl; k++ ) { int t = teams->hat( k ) ? teams->get( k ) : 0; bool amLeben = 0; for( int l = 0; l < spielerAnzahl; l++ ) { if( spieler->z( l ) && spieler->z( l )->getSpielerTeam() == t ) amLeben |= spieler->z( l )->istAmLeben(); } if( amLeben ) { teamAmLebenAnzahl++; score->addTeamPunkt( t, 1 ); } else score->addTeamPunkt( t, 0 ); } if( teamAmLebenAnzahl <= 1 ) ende = 1; } } } } } } void Spiel::run() { log = new Datei(); Text *pfad = new Text( "../spiel log/" ); pfad->append( spielId ); pfad->append( "/verlauf.ksggl" ); log->setDatei( pfad ); log->remove(); log->erstellen(); log->open( Datei::Style::schreiben ); time_t t; time( &t ); srand( (unsigned int)t ); log->schreibe( (char *)&spielerAnzahl, 4 ); for( int i = 0; i < spielerAnzahl; i++ ) { Spieler *tmp = spieler->z( i ); if( tmp && tmp->zKlient() ) { log->schreibe( (char *)&i, 4 ); int sNum = tmp->getSpielerNummer(); score->setSpielerPunkte( sNum, 0 ); log->schreibe( (char *)&sNum, 4 ); tmp->zKlient()->sendeSpielerNummer( sNum, 0 ); tmp->zKlient()->sendeInitSpieler( spielerAnzahl, spieler, 0 ); int kg = 400; log->schreibe( (char *)&kg, 4 ); log->schreibe( (char *)&kg, 4 ); int team = tmp->getSpielerTeam(); log->schreibe( (char *)&team, 4 ); int farbe = tmp->getSpielerFarbe(); log->schreibe( (char *)&farbe, 4 ); farbe = tmp->getTeamFarbe(); log->schreibe( (char *)&farbe, 4 ); Text *name = psqldb->getAccountRufName( tmp->getAccountId() ); char len = (char)( name ? name->getLength() : 0 ); log->schreibe( &len, 1 ); if( len ) log->schreibe( name->getText(), len ); if( name ) name->release(); name = sts->teamName->z( tmp->getSpielerTeam() ); len = (char)( name ? name->getLength() : 0 ); log->schreibe( &len, 1 ); if( len ) log->schreibe( name->getText(), len ); tmp->zKlient()->sendeKammeraSize( 400, 400, 0 ); bool gefunden = 0; for( int j = 0; j < teamAnzahl; j++ ) gefunden |= teams->hat( j ) && teams->get( j ) == tmp->getSpielerTeam(); if( !gefunden ) { score->setTeamMaxPunkte( tmp->getSpielerTeam(), teamAnzahl * 3 ); score->setTeamPunkte( tmp->getSpielerTeam(), ( teamAnzahl * 3 ) / 2 ); teams->set( tmp->getSpielerTeam(), teamAnzahl ); teamAnzahl++; } } } for( int i = 0; i < teamAnzahl; i++ ) { score->setTeamMaxPunkte( teams->hat( i ) ? teams->get( i ) : 0, teamAnzahl * 3 ); score->setTeamPunkte( teams->hat( i ) ? teams->get( i ) : 0, ( teamAnzahl * 3 ) / 2 ); } for( int i = 0; i < spielerAnzahl; i++ ) { Spieler *tmp = spieler->z( i ); if( tmp && tmp->zKlient() ) { for( int j = 0; j < teamAnzahl; j++ ) { int team = teams->hat( j ) ? teams->get( j ) : 0; if( i == 0 ) log->schreibe( (char *)&team, 4 ); int p = score->getTeamMaxPunkte( team ); tmp->zKlient()->sendeTeamMaxPunkte( team, p, 0 ); if( i == 0 ) log->schreibe( (char *)&p, 4 ); p = score->getTeamPunkte( team ); tmp->zKlient()->sendeTeamPunkte( team, p, 0 ); if( i == 0 ) log->schreibe( (char *)&p, 4 ); if( sts->teamName->z( team ) ) tmp->zKlient()->sendeTeamName( team, sts->teamName->z( team )->getText() ); } } } Array< char > spielerStatus; int gewinner = -1; while( 1 ) { rundenAnzahl++; int karteBreite = 400 + ( rand() % ( spielerAnzahl * 50 ) ); int karteHeignt = 400 + ( rand() % ( spielerAnzahl * 50 ) ); karte->setSize( karteBreite, karteHeignt ); EnterCriticalSection( &cs ); log->schreibe( (char *)&karteBreite, 4 ); log->schreibe( (char *)&karteHeignt, 4 ); for( int i = 0; i < spielerAnzahl; i++ ) { Spieler *tmp = spieler->z( i ); if( tmp && tmp->zKlient() ) { tmp->zKlient()->sendeKartenSize( karteBreite, karteHeignt, 0 ); double w = 50.0 / 180 * PI; log->schreibe( (char *)&w, 8 ); tmp->setWendigkeit( w ); tmp->setPosition( 100 + ( rand() % ( karteBreite - 200 ) ), 100 + ( rand() % ( karteHeignt - 200 ) ) ); double p = tmp->getX(); log->schreibe( (char *)&p, 8 ); p = tmp->getY(); log->schreibe( (char *)&p, 8 ); int grad = rand() % 180 - 90; double xs = sin( grad / 180.0 * PI ) * 30; log->schreibe( (char *)&xs, 8 ); double ys = sqrt( 30 * 30 - xs * xs ); ys *= ( rand() % 2 > 0 ) ? 1 : -1; log->schreibe( (char *)&ys, 8 ); tmp->setGeschwindigkeit( xs, ys ); } } LeaveCriticalSection( &cs ); for( int i = 0; i < spielerAnzahl; i++ ) { Spieler *tmp = spieler->z( i ); if( tmp ) { for( int j = 0; j < spielerAnzahl; j++ ) { Spieler *s = spieler->z( j ); if( s && s->zKlient() ) { s->zKlient()->sendeSpielerPosition( tmp, 0 ); s->zKlient()->sendeSpielerGeschwindigkeit( tmp, 0 ); s->zKlient()->sendeSpielerWendigkeit( tmp, 0 ); } } } } for( int i = 0; i < teamAnzahl; i++ ) { if( teams->hat( i ) && !score->istTeamAmLeben( teams->get( i ) ) ) { for( int j = 0; j < spielerAnzahl; j++ ) { Spieler *tmp = spieler->z( teams->get( i ) ); if( tmp ) tmp->zKlient()->sendeTeamTod( teams->get( i ), 0 ); } } } ZeitMesser *zeit = new ZeitMesser(); zeit->messungStart(); isRunning = 1; ende = 0; double ausgleich = 0; spielZeit = 0; for( int i = 0; i < spielerAnzahl; i++ ) { Spieler *tmp = spieler->z( i ); if( tmp && tmp->zKlient() ) tmp->zKlient()->sendeStart( 0 ); } double rZeit = 0; while( !ende ) { zeit->messungEnde(); zeit->messungStart(); double z = zeit->getSekunden(); ausgleich += 1.0 / 25 - z; if( ausgleich > 0 ) Sleep( (int)( ausgleich * 1000 ) ); rZeit += z; while( spielZeit + TICK < rZeit && !ende ) { EnterCriticalSection( &cs ); spielZeit += TICK; char c = 0; log->schreibe( &c, 1 ); tick( TICK ); LeaveCriticalSection( &cs ); } } zeit->messungEnde(); zeit->release(); gewinner = -1; for( int i = 0; i < spielerAnzahl; i++ ) { if( spieler->z( i )->istAmLeben() ) { gewinner = spieler->z( i )->getSpielerTeam(); break; } } if( gewinner < 0 ) { double sterbeZeit = 0; for( int i = 0; i < spielerAnzahl; i++ ) { if( spieler->z( i )->getTodesZeit() >= sterbeZeit ) { sterbeZeit = spieler->z( i )->getTodesZeit(); gewinner = spieler->z( i )->getSpielerTeam(); } } } stat->rundenEnde( gewinner, (int)spielZeit, dynamic_cast( karte->zMap()->getThis() ) ); int winTeamAnzahl = 0; Array< int > *winTeams = new Array< int >(); for( int i = 0; i < teamAnzahl; i++ ) { if( score->hatTeamGewonnen( i ) || rundenAnzahl >= 10 ) { winTeams->add( i, winTeamAnzahl ); winTeamAnzahl++; } } if( !winTeamAnzahl ) { int verloren = 0; int team = -1; for( int i = 0; i < teamAnzahl; i++ ) { int t = teams->hat( i ) ? teams->get( i ) : 0; if( !score->getTeamPunkte( t ) ) verloren++; else team = t; } if( verloren == teamAnzahl - 1 ) { winTeams->add( team, winTeamAnzahl ); winTeamAnzahl++; } } if( winTeamAnzahl > 1 ) { int p = -1; for( int i = 0; i < winTeamAnzahl; i++ ) { int t = winTeams->hat( i ) ? winTeams->get( i ) : 0; if( score->getTeamMaxPunkte( t ) - score->getTeamPunkte( t ) < p || p < 0 ) { p = score->getTeamMaxPunkte( t ) - score->getTeamPunkte( t ); for( int j = 0; j < winTeamAnzahl; j++ ) { int tt = winTeams->hat( j ) ? winTeams->get( j ) : 0; if( score->getTeamMaxPunkte( tt ) - score->getTeamPunkte( tt ) > p ) { if( i >= j ) i--; score->setTeamPunkte( tt, 0 ); winTeams->remove( j ); winTeamAnzahl--; j--; } } } } } if( ( !winTeamAnzahl || winTeamAnzahl > 1 ) && teamAnzahl > 1 && rundenAnzahl < 10 ) { winTeams->release(); for( int i = 0; i < spielerAnzahl; i++ ) { if( spieler->z( i ) && spieler->z( i )->zKlient() ) { spieler->z( i )->neuRunde( score->getTeamPunkte( spieler->z( i )->getSpielerTeam() ) != 0 ); spieler->z( i )->zKlient()->sendeRundenEnde( gewinner, 0 ); } } for( int i = 5; i >= 0; i-- ) { for( int k = 0; k < 10; k++ ) { Sleep( 100 ); for( int j = 0; j < spielerAnzahl; j++ ) { if( spieler->z( j ) && spieler->z( j )->zKlient() ) spieler->z( j )->zKlient()->sendeZeitVerbleibend( i, 0 ); } if( !i ) break; } } } else { for( int i = 0; i < spielerAnzahl; i++ ) { if( spieler->z( i ) && spieler->z( i )->zKlient() ) { if( winTeams->getWertIndex( spieler->z( i )->getSpielerTeam() ) < 0 ) { spielerStatus.set( 1, i ); // Datenbank Verloren spieler->z( i )->zKlient()->sendeSpielEnde( 0, 0 ); } else if( winTeamAnzahl > 1 ) { spielerStatus.set( 5, i ); // Datenbank Unentschieden spieler->z( i )->zKlient()->sendeSpielEnde( 2, 0 ); } else { spielerStatus.set( 2, i ); // Datenbank Gewonnen spieler->z( i )->zKlient()->sendeSpielEnde( 1, 0 ); } } if( spieler->z( i ) && ( !spieler->z( i )->zKlient() || !spieler->z( i )->istOnline() ) ) spielerStatus.set( 3, i ); } winTeams->release(); break; } } if( teamAnzahl == 1 ) psqldb->setSpielStatusBeendet( spielId, 6 ); else psqldb->setSpielStatusBeendet( spielId, 5 ); for( int i = 0; i < spielerAnzahl; i++ ) { Spieler *tmp = spieler->z( i ); if( tmp ) { psqldb->setSpielSpielerStatus( spielId, tmp->getAccountId(), tmp->getPunkte(), spielerStatus.get( i ) ); if( teamAnzahl > 1 ) psqldb->addSpielerStatistik( tmp->getAccountId(), spielId ); } } log->close(); log = (Datei *)log->release(); isRunning = 0; } // constant StatistikV *Spiel::getStatistik() const { return dynamic_cast( stat->getThis() ); }